독서 리마인더/텐서플로 2와 케라스로 구현하는 딥러닝

[텐서플로2와 케라스로 구현하는 딥러닝] 2장

hwijin97 2021. 5. 19. 20:34

2장 텐서플로 1.x 2.x

텐서플로 1.x

import tensorflow.compat.v1 as tf

with tf.Session() as sess:
  message = tf.constant("hello world")
  print(sess.run(message))
  print(sess.run(message).decode())

계산그래프 :

node와 edge를 가진 네트워크로서, 텐서 객체(상수,변수, placeholder) , 모든 계산를 포함한 연산 객체가 정의된다.

각 노드는 0개 이상의 입력, 1개의 출력을 가진다. 노드는 tensors, operations를 나타내고

edge는 연산 간에 흐르는 텐서를 나타낸다.

그래프 실행 :

tensors와 operations 객체가 평가되는 환경을 캡슐화하는 session 객체를 사용해 수행된다.

session객체는 한계층에서 다른 계층으로 정보의 실제 계산과 전송이 이루어진다.

그래프를 사용하는 이유 :

1. 네트워크를 설명해 줄수 있는 자연스러운 비유가 된다.

2. 공통 하위 표현식, 커널, 중복 표현식을 제거해 자동으로 최적화 할 수 있다.

3. 그래프를 훈련 중 쉽게 배포해서, cpu, gpu, tpu, cloud, iot, mobile, 등과 같은 다양한 환경에 배포 가능하다.

import tensorflow.compat.v1 as tf

with tf.Session() as sess:
  v_1 = tf.constant([1,2,3,4])
  v_2 = tf.constant([2,1,5,3])
  v_add = tf.add(v_1,v_2)
  print(sess.run(v_add))

run (fetches, feed_dict=None, options=None, run_metadata) 메소드를 사용해 실행한다.

fetches 매개변수에서 텐서를 계산한다, fetch에 v_add 텐서가 있고, v_add로 이어지는 그래프 내의 모든 덴서와 연산을 수행한다.

fetches는 여러개의 tensor 객체 혹은 연산 객체를 가질 수 있다.

 

상수, 변수, placeholder와 작업

텐서 : n 차원 배열

스칼라 - 0차원 텐서 - []

벡터 - 1차원 텐서 - [D0]

행렬matrix - 2차원 텐서 - [D0, D1]

텐서 - n차원 텐서 - [D0, D1, D2, D3, ... ,Dn-1]

상수 : 텐서이며 값을 변경할 수 없음

변수 : 세션 내에서 값을 갱신 해야할때 사용한다.

placeholder : 텐서플로 그래프에 값을 넣는데 사용된다.

 

예시

  t_1 = tf.constant(4)
  t_2 = tf.constant([4,3,2])
  zero_t = tf.zeros([5,4],tf.float32)
  one_t = tf.ones_like(zero_t)
  t = tf.Variable([[1,2,3],[3,4,5],[5,6,7]])
  range_t = tf.linespace(2.0,5.0,5) ==> 균등 분포
  range_t = tf.range(10,15,5) ==> 균일히 증가
  t_random = tf.random_normal([2,3], mean=2.0, stddev=4, seed=12) ==> 정규분포
  t_random = tf.truncated_normal([1,5],mean=0,stddev=2,seed=12) ==>잘려진 정규분포
  t_random = tf.random_uniform([2,3],minval=0,maxval=4,seed=12) ==> minval, maxval 범위
  tf.random_crop(t_random,[2,5],seed=12) ==> 특정 크기로 절단
  tf.random_suffle(t_random)
  tf.set_random_seed(45) ==> 모든 세션의 랜덤 텐서의 시드를 설정한다.
  

변수 :

  rand_t = tf.random_uniform([50,50], 0, 10, seed=0)
  t_a = tf.Variable(rand_t)
  t_b = tf.Variable(rand_t) #균등분포 랜덤 값으로 초기화
  weights = tf.Variable(tf.random_normal([100,100],mean=0.0,stddev=2))
  bias = tf.Variable(tf.zeros([100]), name='biases')
  weight2 = tf.Variable(weights.initialized_value(), name='w2') #위의 가중치로 변수 w2를 초기화한다.
  initial_op = tf.global_variables_initializer() #연산 객체를 초기화 해주는 객체
  bias = tf.Variable(tf.zeros([100,100]))
  sess.run(bias.initializer) #변수 개별적 초기화
  
  saver = tf.train.Saver() #모든 변수저장 Saver class
  x = tf.placeholder('float',shape=None,name=None)
  y = x * 2
  data = tf.random_uniform([3,2],10)
  x_data = sess.run(data)
  print(sess.run(y,feed_dict={x:x_data})) # [[16.338106   8.4631815] [ 6.279848  15.92954  ] [14.346416   5.494562 ]]
  #값을 알려면 명시적으로 run을 원하는 텐서값과 실행해야한다.

텐서플로 2.x 에서 텐서플로 1.x 예제 수행 방법 :

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

실행 예시 :

tf.reset_default_graph() #그래프 변수 초기화
in_a = tf.placeholder(dtype=tf.float32,shape=(2))

def model(x):
  with tf.variable_scope('matmul'):
    w = tf.get_variable("W", initializer=tf.ones(shape=(2,2)))
    b = tf.get_variable("b", initializer=tf.zeros(shape=(2)))
    return x * w + b
  
out_a = model(in_a)

with tf.Session() as sess:
  sess.run(tf.global_variables_initializer())
  outs = sess.run([out_a],feed_dict={in_a:[1,0]})
  writer = tf.summary.FileWriter("/logs",sess.graph)

텐서보드tensorboard 시각화 애플리케이션

tensorboard --logdir=./logs/
#http://localhost:6006/

텐서플로 2.x

즉시 실행 eager execution :

특별한 session interface, placeholder 없이, node를 정의, 변경, 실행이 가능하다.

텐서플로 1.x 는 모델 구현 세부사항을 변경하고 싶을때, 그래프와 세션을 조정한다.

 

Chainer

프레임워크

#https://chainer.org/ 참고

 

오토그래프 :

eager execution 파이썬 코드를 가져와서, 자동으로 그래프 생성 코드로 변환한다.

사용법 : 특정 데코레이터 decorator tf.function을 어노테이션annotation처럼 써주면된다.

import tensorflow as tf
def linear_layer(x):
  return 3 * x + 2

@tf.function
def simple_nn(x):
  return tf.nn.relu(linear_layer(x))

def simple_function(x):
  return 3 * x

simple_nn #<tensorflow.python.eager.def_function.Function at 0x7f9736390ad0>
simple_function #<function __main__.simple_function>

simple_nn은 텐서플로 내부와 상호작용하는 특수 핸들러handler이다.

 

오토그래프를 사용한 코드와, 없는 동일한 코드의 속도차이 :

cell = tf.keras.layers.LSTMCell(100)

@tf.function
def fn(input, state):
  return cell(input,state)

input = tf.zeros([100,100])
state = [tf.zeros([100,100])] * 2
#워밍업
cell(input,state)
fn(input,state)

graph_time = timeit.timeit(lambda: cell(input,state), number=100)
auto_graph_time = timeit.timeit(lambda: fn(input,state), number=100)
print('graph time :', graph_time) #graph time : 0.12537865199999487
print('auto graph time :', auto_graph_time) #auto graph time : 0.10789341600002444

파이썬 함수는 tf.function으로 decoration이 가능하다. tf.function은 모든 최적화를 동원해 동등한 정적 그래프로 변환한다.

 

케라스 API : 3가지 프로그래밍 모델

순차적Sequential API :

순차적 API는 90%의 사례에 적합한 직관적이며 간결한 모델이다.

1장에서 MNIST 코드로 다뤘다.

함수적functional API :

다중 입력, 다중 출력, 비순차 흐름과의 잔존 연결, 공유, 재사용 가능 계층을 포함해 좀 더 복잡한 비선형 위상topology으로 모델을 구축하려는 경우 유용하다. 네트워크가 비선형으로 입력과 출력을 전달한다는 점이 다르다.

모델 서브클래싱 model subclassing API :

일반적으로 자신이 계층을 정의해야 할때 사용한다. 복잡도 측면에서 높은 비용이 들기 때문에 필요할 때만 사용해야 한다. tf.keras.layers.Layer을 상속받아 재정의 class를 만든다.

 

 

CallBack 콜백 :

훈련중에 동작을 확장 혹은 수정의 내용을 모델로 전달하는 객체이다.

 

tf.keras.callbacks.ModelCheckPoint :

모델의 체크포인트를 저장하고 문제가 발생했을 때 복구하는데 사용한다.

tf.keras.callbacks.LearningRateScheduler :

모델의 learningRate 를 동적으로 변경할 때 사용한다.

tf.keras.callbacks.EarlyStopping : 

검증 성능이 한동안 개선되지 않을때 훈련을 중단한다.

tf.keras.callbacks.TensorBoard :

텐서보드를 통해 모델의 행동을 모니터링할 때 사용한다.

 

모델과 가중치 저장 : 

모델을 훈련한 후, 가중치를 지속적으로 저장하면 유용하다.

#checkpoint 파일로 저장

model.save_weight('./weights/my_model')

#모델 상태 복원

model.load_weights(file_path)

#가중치 이외의 모델을 json 파일로 저장, 복원

json_string = model.to_json()

model = tf.keras.models.model_from_json(json_string)

#YAML로 저장,복원

#모델을 가중치와 최적화 매개변수와 함께 저장, 복원

model.save('my_model.h5')

model = tf.keras.models.load_model('my_model.h5')

 

tf.data.datasets로 훈련 :

데이터셋 연산 :

1. 생성 

from_tensor_slices() :

개별(or 다중) 넘파이(or tensor)를 받고 배치를 지원한다.

from_tensors() :

배치를 지원하지 않는 from_tensor_slices()

from_generator() :

생성자 함수에서 입력을 취한다.

 

2. 변환

batch() : 순차적으로 데이터셋을 지정한 크기로 분할

repeat() : 데이터를 복제

shuffle() : 데이터를 무작위로 셔플

map() : 데이터에 함수를 적용

filter() : 데이터를 거르는 함수 적용

 

3. 반복자iterator

next_batch = iterator.get_next() : 다음 데이터 호출

추정기Estimators

tf.keras 와 같이 상위 API로서 계산 그래프나 세션을 대신 처리해준다. 대규모 양산production-ready 환경에 적합한 고효율 학습 모델이다.

#two hidden layers, 10 nodes in each hidden layer, using DNN
classifier = tf.estimator.DNNClassifier(feature_columns = feature_columns, hidden_units=[10,10],
n_classes =3)
#feature_columns : 모델에서 사용하려는 단일 특징을 설명하는 feature 열의 목록
#tf.feature_columns 로 정의된다.

효율 추정기Efficient Estimators : tf.Datasets형식을 입력으로 받고, tf.estimator.train_and_evaluate()으로 훈련되고 평가된다.

 

비정형 텐서ragged tensor

균일하지 않은 형태를 가진 특수 유형의 고밀도 텐서를 의미한다. 텍스트 문장 및 계층적 데이터 처럼 배치마다 차원이 다른 시퀀스들을 처리하는데 유용하다.

ragged = tf.ragged.constant([1,2,3],[3,4],[5,6,7,8])
#<tf.RaggedTensor [[1,2,3], [3,4], [5,6,7,8]]>

맞춤형 훈련

gradient계산의 최적화를 좀 더 세밀하게 제어하려는 경우 맞춤형 훈련을 사용한다.

tf.GradientTape(): 자동 미분을 위한 연산을 기록한다.

tf.gradient_function() : 입력 함수의 각 매개변수의 도함수를 인수에 대해 계산하는 함수를 반환한다.

tf.value_and_gradients_function() : 입력 함수의 인수에 대한 도함수 목록과, 입력 함수 값을 반환한다.

tf.implicit_gradients() : 이 출력이 종속된 훈련 가능한 모든 인수에 대해 입력 함수 출력의 그래디언트를 계산한다.

 

텐서플로 2.x에서 분산 훈련

다중 GPU

MultiWorkerMirroredStrategy

TPUStrategy

ParameterServerStrategy

책 참고.

 

텐서플로 2.x의 효율적인 사용

tf.keras와 같은 하이레벨API를 우선적으로 사용한다.

@tf.function 를 추가해 auto graph로 그래프 모드에서 효율적으로 수행되도록 한다.

파이썬 객체를 사용해 변수와 손실을 추적한다. tf.get_variable 대신 tf.Variable을 사용한다.

데이터입력에는 tf.data.Dataset을 이용해라.

가능하면 tf.keras.layers를 순차적, 함수적 API로 사전 정의된 레고 블럭을 사용해라.

양산production-ready모델이 필요한경우 추정기estimator을 사용하고, 필요한경우 모델을 추정기로 변환해라.

GPU, CPU, 여러 플랫폼으로 분산 전략 사용을 고려해라.