본문 바로가기
Deep Learning/Hands On Machine Learning

12.2 넘파이처럼 텐서플로 사용하기

by 대소기 2021. 9. 29.
  • Tensorflow : tensor가 한 연산에서 다른 연산으로 흐르기 때문에 tensor + flow 가 되었다.
  • Tensor : ndarray와 매우 비슷하고 기본적으로 다차원 배열을 다룬다. 스칼라 값을 가질 수도 있다.

12.2.1 텐서와 연산

텐서 생성

import tensorflow as tf

tf.constant([[1,2,3], [4,5,6]]) #matrix

# <tf.Tensor: shape=(2, 3), dtype=int32, numpy=
# array([[1, 2, 3],
#        [4, 5, 6]], dtype=int32)>
  • tf.constant()를 통해 tensor를 생성할 수 있다.
  • 텐서는 ndarray와 같이 shape와 dtype을 가진다.

인덱스 참조

t=tf.constant([[1.,2.,3.],[4.,5.,6.]])
t.shape
t[:, 1:]

# <tf.Tensor: shape=(2, 2), dtype=float32, numpy=
# array([[2., 3.],
#        [5., 6.]], dtype=float32)>
  • 인덱스 참조 또한 가능하다.

텐서 연산

t=tf.constant([[1.,2.,3.],[4.,5.,6.]])

plus = t + 10
sqaure = tf.sqaure(t)
matrix_multiplication = t @ tf.transpose(t)
  • 위의 @ 연산자는 tf.matmul() 함수를 호출하는 것과 동일한 역할을 한다.
  • 위의 기본적인 연산 외에도 tf.add(), tf.multiply(), tf.square(), tf.exp(), tf.sqrt() 등이 가능하다.
  • tf.reshape(), tf.sqeeeze(), tf.tile()은 numpy 메소드와 이름이 같고 기능도 같다.
  • 하지만, tf.reduce_mean()np.mean(), tf.reduce_sum()은 np.sum(), tf.reduce_max()np.max(), tf.math.log()np.max() 와 동일하다. 이처럼 기능은 같지만 tensorlfow와 numpy의 이름이 다른 경우도 있다.
  • 텐서 연산에서 넘파이와 기능은 같지만 이름이 다른 함수들의 경우엔 특별한 이유가 있다.
  • tf.transpose()의 경우 전치된 데이터의 복사본으로 새로운 데이터가 만들어지지만, t.T는(numpy 연산) 동일한 데이터의 view일 뿐이다.
  • tf.reduce_sum()의 경우 GPU커널이 reduce알고리즘을 사용하여 연산을 수행하기 때문에 np.sum()과 다르다.
  • tf.reduce_sum()tf.reduce_mean()의 경우 부동소수점 연산의 어쩔수 없는 오차로 인해 결과값이 호출시마다 조금씩 달라진다.
  • 이러한 이유로 numpy와 tensorflow 연산 함수 간에는 이름과 작동 '과정'의 차이가 존재한다('결과적으로는 같은 연산을 수행한다').

케라스의 저수준 API

from tensorflow import keras
K=keras.backend
K.sqaure(K.transpose(t))+10
  • 다른 케라스 구현에 적용할 수 있는 코드를 사용할 떄는 keras.backend의 자체 저수준 API를 사용하여야 한다.
  • 하지만, tensorflow가 제공하는 함수의 일부만이 사용 가능하다는 점이 단점이다.

12.2.2 텐서와 넘파이

t=tf.constant([[1.,2.,3.],[4.,5.,6.]])
a=np.array([2.,4.,5.])
a=tf.constant(a)
t=t.numpy() # or np.array(t)
  • tensor와 numpy간의 변환은 자유롭다.
  • numpy는 기본으로 64비트 정밀도를 사용하지만, 신경망은 32비트 정밀도로 충분하고 메모리도 적게 사용하기 때문에 32비트를 사용한다.
  • 이러한 이유로 numpy를 tensorflow로 변환하기 위해 numpy array를 생성할 떄 dtype=tf.float32로 지정해야 한다.

12.2.3 타입 변환

  • tensor 연산에서 타입 변환은 자동으로 이뤄지지 않는다. 즉 다른 타입끼리의 연산이 불가능하다.
  • 때문에 만약 다른 타입끼리의 연산이 필요하다면 tf.cast(tensor, dtype)을 사용해 수동으로 dtype을 변경해줘야 한다.

12.2.4 변수

  • 앞서 살펴본 tf.constant()를 통해 생성되는 tf.Tensor 객체는 내용의 변경이 불가능한 객체이다.
  • 하지만 deep learning 과정에서 backpropagation을 통해 weight을 update하기 위해서는 tensor가 변경 가능해야 한다.
  • 이럴 때 tf.Variable()을 통해 변경 가능한 객체를 만들어야 한다.
v = tf.Variable([[1.,2.,3.],[4.,5.,6.]])
v

# <tf.Variable 'Variable:0' shape=(2, 3) dtype=float32, numpy=
# array([[1., 2., 3.],
#        [4., 5., 6.]], dtype=float32)>
  • tf.Variable 객체는 tf.Tensor 객체와 동일한 연산이 가능하고 넘파이 호환도 역시 가능하다.
v = tf.Variable([[1.,2.,3.],[4.,5.,6.]])
v

v.assign(2*v)
v[0,1].assign(42)
v[:,2].assign([0.,1.])
v.scatter_nd_update(indices=[[0,0],[1,2]], updates=[100., 200.])
  • assing() 메소드를 이용해 변숫값을 바꿀 수 있다. 또한 assign_add()assign_sub() 메소드를 사용하여 주어진 값만큼 변수를 증가시키거나 감소시킬 수 있다.
  • scatter_update(), scatter_nd_update()를 통해 개별 원소를 변경할 수 있고, assign() 메소드를 사용해서도 가능하다.