[텐서플로2와 케라스로 구현하는 딥러닝] 2장
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, 여러 플랫폼으로 분산 전략 사용을 고려해라.