딥러닝 소개 - 텐서플로 기본

Page content

강의 홍보

공지

  • 본 Tutorial은 교재 핸즈온 머신러닝 2판를 활용하여 본 강사로부터 국비교육 강의를 듣는 사람들에게 자료 제공을 목적으로 제작하였습니다.

  • 강사의 주관적인 판단으로 압축해서 자료를 정리하였기 때문에, 자세하게 공부를 하고 싶은 분은 반드시 교재를 구매하실 것을 권해드립니다.

책 정말 좋습니다! 꼭 구매하세요!

개요

  • 인경 신경망은(Artificial Neural Network)을 촉발시킨 근원임
    • 뇌에 있는 생물학적 뉴런의 네트워크에서 영감을 받은 머신러닝 모델
  • 활용예제
    • 수백만개의 이미지 분류
    • 수백만개의 비디어 추천
    • 매우 복잡한 문제를 풀 때 유용한 머신러닝 모델
  • Keras API
    • 케라스는 신경망 구축, 훈련, 평가, 실행을 목적으로 설계된 API이자, 프레임워크

(1) 주요 환경 설정

  • 주요 환경 설정은 아래와 같이 정의합니다.
# 파이썬 ≥3.5 필수
import sys
assert sys.version_info >= (3, 5)

# 사이킷런 ≥0.20 필수
import sklearn
assert sklearn.__version__ >= "0.20"

# 텐서플로 ≥2.0 필수
import tensorflow as tf
assert tf.__version__ >= "2.0"
from tensorflow import keras

# 공통 모듈 임포트
import numpy as np
import pandas as pd
import os

# 노트북 실행 결과를 동일하게 유지하기 위해
np.random.seed(42)

# 깔끔한 그래프 출력을 위해
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rc('axes', labelsize=14)
mpl.rc('xtick', labelsize=12)
mpl.rc('ytick', labelsize=12)

# 그림을 저장할 위치
PROJECT_ROOT_DIR = "."
CHAPTER_ID = "ann"
IMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, "images", CHAPTER_ID)
os.makedirs(IMAGES_PATH, exist_ok=True)

def save_fig(fig_id, tight_layout=True, fig_extension="png", resolution=300):
    path = os.path.join(IMAGES_PATH, fig_id + "." + fig_extension)
    print("그림 저장:", fig_id)
    if tight_layout:
        plt.tight_layout()
    plt.savefig(path, format=fig_extension, dpi=resolution)

# 불필요한 경고를 무시합니다 (사이파이 이슈 #5998 참조)
import warnings
warnings.filterwarnings(action="ignore", message="^internal gelsd")

I. 텐서플로의 전체적인 개요

  • 지금까지는 케라스를 활용한 인공신경망의 개요에 대해 확인하였다.
  • 딥러닝 작업의 95%tf.keras외에 다른 것은 필요하지 않다.
  • 그러나, 텐서플로를 조금 더 자세히 들여다 본다.

II. 텐서플로의 역사 및 기능 개요

  • 텐서플로는 2015년 11월 오픈 소스로 공개
    • 그 전에 구글 포토, 구글 검색, 구글 클라우드 스피치에서 이미 사용됨
    • 텐서플로를 활용하여 이미지 분류, 자연어 처리, 추천 시스템, 시계열 예측 등과 같은 머신러닝 작업을 수행
  • 그 외 딥러닝 프레임워크에 관한 비교글은 다음 글 참조

(1) 텐서플로의 주요 기능

  • NumPy와 비슷하지만, GPU 지원
    • 병렬처리 가능 및 연산속도 향상
  • 분산 컴퓨팅 지원
  • JIT 컴파일러 포함, 메모리 사용량을 줄이기 위해 계산 최적화
  • 텐서플로 API의 주요 기능은 다음 그림 참조
  • 가장 저수준의 텐서플로 연산은 매우 효율적인 C++코드로 구현되어 있음

(2) 텐서플로의 그 외 기능

  • 윈도우, 리눅스, 맥OS, iOS, 안드로이드에서 사용 가능
  • C++, 자바, Go, 스위프트 API에서도 사용 가능
  • 텐서보드 (시각화), 텐서플로 제품화를 위한 TFX

III. 텐서플로 사용

  • 텐서플로의 기초적인 사용법에 대해 다시 확인한다.
    • 텐서는 한 연산에서 다른 연상르ㅗ 흐름
    • 텐서는 넘파이의 ndarray와 비슷
    • 다차원 배열

(1) 텐서와 연산

  • 두 개의 행과 세계의 열을 가진 실수 행렬을 만든다.
tf.constant([[1., 2., 3.], [4., 5., 6.]]) # 행렬
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[1., 2., 3.],
       [4., 5., 6.]], dtype=float32)>
tf.constant(42) # 단순값 스칼라도 확인 가능
<tf.Tensor: shape=(), dtype=int32, numpy=42>
  • ndarray와 마찬가지로 tf.Tensor는 크기와 데이터 타입(dtype)을 가진다.
t = tf.constant([[1., 2., 3.], [4., 5., 6.]])
print(t.shape)
print(t.dtype)
(2, 3)
<dtype: 'float32'>
  • 인덱스 참조도 넘파이와 매우 비슷하게 작동함
t[:, 1:]
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[2., 3.],
       [5., 6.]], dtype=float32)>
t[..., 1, tf.newaxis]
<tf.Tensor: shape=(2, 1), dtype=float32, numpy=
array([[2.],
       [5.]], dtype=float32)>
  • 모든 종류의 텐서 연산이 가능하다.
t+10
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[11., 12., 13.],
       [14., 15., 16.]], dtype=float32)>
tf.square(t)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[ 1.,  4.,  9.],
       [16., 25., 36.]], dtype=float32)>
tf.transpose(t)
<tf.Tensor: shape=(3, 2), dtype=float32, numpy=
array([[1., 4.],
       [2., 5.],
       [3., 6.]], dtype=float32)>
t @ tf.transpose(t)
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[14., 32.],
       [32., 77.]], dtype=float32)>
  • @ 연산은 행렬 곱셈을 위해 파이썬 3.5에 추가된 것.
  • 위 행렬곱셈은 (2 x 3) x (3 x 2) = (2 x 2) 방식을 따른 것이다.

(2) 텐서와 넘파이

  • 텐서는 넘파이와 함께 사용이 가능함
  • 텐서와 넘파이는 서로 쉽게 변환이 가능함
a = np.array([2., 4., 5.])
tf.constant(a)
<tf.Tensor: shape=(3,), dtype=float64, numpy=array([2., 4., 5.])>
t.numpy()
array([[1., 2., 3.],
       [4., 5., 6.]], dtype=float32)
tf.square(a)
<tf.Tensor: shape=(3,), dtype=float64, numpy=array([ 4., 16., 25.])>
np.square(t)
array([[ 1.,  4.,  9.],
       [16., 25., 36.]], dtype=float32)
  • 단 한가지 주의점이 있다.
    • NumPy는 기본으로 64비트 정밀도를 사용하지만, 텐서플로는 32비트 정밀도를 사용함. 따라서, 넘파이 배열로 텐서를 만들 때 dtype=tf.float32로 지정한다.

(3) 타입 변환

  • 호환되지 않는 타입의 예를 확인한다.
  • 먼저 정수텐서와 실수 텐서는 더할 수 없다.
tf.constant(2.) + tf.constant(40)
---------------------------------------------------------------------------

InvalidArgumentError                      Traceback (most recent call last)

<ipython-input-16-1026a7e18cf4> in <module>()
----> 1 tf.constant(2.) + tf.constant(40)


/usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_ops.py in binary_op_wrapper(x, y)
    982     with ops.name_scope(None, op_name, [x, y]) as name:
    983       if isinstance(x, ops.Tensor) and isinstance(y, ops.Tensor):
--> 984         return func(x, y, name=name)
    985       elif not isinstance(y, sparse_tensor.SparseTensor):
    986         try:


/usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_ops.py in _add_dispatch(x, y, name)
   1274     return gen_math_ops.add(x, y, name=name)
   1275   else:
-> 1276     return gen_math_ops.add_v2(x, y, name=name)
   1277 
   1278 


/usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/gen_math_ops.py in add_v2(x, y, name)
    478         pass  # Add nodes to the TensorFlow graph.
    479     except _core._NotOkStatusException as e:
--> 480       _ops.raise_from_not_ok_status(e, name)
    481   # Add nodes to the TensorFlow graph.
    482   _, _, _op, _outputs = _op_def_library._apply_op_helper(


/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/ops.py in raise_from_not_ok_status(e, name)
   6651   message = e.message + (" name: " + name if name is not None else "")
   6652   # pylint: disable=protected-access
-> 6653   six.raise_from(core._status_to_exception(e.code, message), None)
   6654   # pylint: enable=protected-access
   6655 


/usr/local/lib/python3.6/dist-packages/six.py in raise_from(value, from_value)


InvalidArgumentError: cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a int32 tensor [Op:AddV2]
  • 32비트 실수와 64비트 실수도 더할 수 없다.
tf.constant(2.) + tf.constant(40., dtype=tf.float64)
---------------------------------------------------------------------------

InvalidArgumentError                      Traceback (most recent call last)

<ipython-input-22-11603e4e2c5e> in <module>()
----> 1 tf.constant(2.) + tf.constant(40., dtype=tf.float64)


/usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_ops.py in binary_op_wrapper(x, y)
    982     with ops.name_scope(None, op_name, [x, y]) as name:
    983       if isinstance(x, ops.Tensor) and isinstance(y, ops.Tensor):
--> 984         return func(x, y, name=name)
    985       elif not isinstance(y, sparse_tensor.SparseTensor):
    986         try:


/usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_ops.py in _add_dispatch(x, y, name)
   1274     return gen_math_ops.add(x, y, name=name)
   1275   else:
-> 1276     return gen_math_ops.add_v2(x, y, name=name)
   1277 
   1278 


/usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/gen_math_ops.py in add_v2(x, y, name)
    478         pass  # Add nodes to the TensorFlow graph.
    479     except _core._NotOkStatusException as e:
--> 480       _ops.raise_from_not_ok_status(e, name)
    481   # Add nodes to the TensorFlow graph.
    482   _, _, _op, _outputs = _op_def_library._apply_op_helper(


/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/ops.py in raise_from_not_ok_status(e, name)
   6651   message = e.message + (" name: " + name if name is not None else "")
   6652   # pylint: disable=protected-access
-> 6653   six.raise_from(core._status_to_exception(e.code, message), None)
   6654   # pylint: enable=protected-access
   6655 


/usr/local/lib/python3.6/dist-packages/six.py in raise_from(value, from_value)


InvalidArgumentError: cannot compute AddV2 as input #1(zero-based) was expected to be a float tensor but is a double tensor [Op:AddV2]
  • 만약 타입 변환이 필요할 경우에는 tf.cast() 함수를 사용한다.
t2 = tf.constant(40., dtype=tf.float64)
tf.constant(2.0) + tf.cast(t2, tf.float32)
<tf.Tensor: shape=(), dtype=float32, numpy=42.0>

(4) 변수

  • 기본적으로 tf.tensor는 변경 불가능함
  • 즉, 텐서의 내용을 바꿀 수 없음.
    • 이는, 역전파로 변경되어야 하는 신경망의 가중치를 구현할 수 없음
  • 그래서, 필요한 것이 tf.Variable
tf_v = tf.Variable([[1., 2., 3.], [4., 5., 6.]])
tf_v
<tf.Variable 'Variable:0' shape=(2, 3) dtype=float32, numpy=
array([[1., 2., 3.],
       [4., 5., 6.]], dtype=float32)>
  • 이제 특정 또는 전체의 값을 변경한다.
tf_v[0, 1].assign(42)
<tf.Variable 'UnreadVariable' shape=(2, 3) dtype=float32, numpy=
array([[ 1., 42.,  3.],
       [ 4.,  5.,  6.]], dtype=float32)>
tf_v[0, 0:2].assign([3., 2.])
<tf.Variable 'UnreadVariable' shape=(2, 3) dtype=float32, numpy=
array([[3., 2., 3.],
       [4., 5., 6.]], dtype=float32)>
  • 변수를 직접 만드는 일은 매우 드물다.

(5) 그 외 다른 데이터 구조

  • 그 외헤, 희소 텐서, 텐서 배열, 래그트 텐서, 문자열 텐서, 집합, 등이 있는데, 교재 470 페이지를 참고한다.

IV. What’s Next

  • 다음 시간에는 사용자 정의 모델과 훈련 알고리즘에 대해 실습을 진행하도록 한다.