*transfer learning
*CNN 2가지 파트
- Convolutional base : 이미지로부터 특징을 효과적으로 추출하는 것 (feature extraction)
- Classifier : 주로 fully connected layer, 모든 계층의 뉴런이 이전 층의 출력 노드와 하나도 빠짐없이 모두 연결되어 있는 층, 추출된 특징을 잘 학습해서 이미지를 알맞은 카테고리로 분류하는 것
*"계층적인 특징"을 "스스로" 학습한다.
- 모델의 첫 번째 층은 "일반적인(general)" 특징을 추출
- 모델의 마지막 층에 가까워질수록 특정 데이터셋 또는 특정 문제에서만 나타날 수 있는 "구체적인(specific)" 특징을 추출
- 앞단의 계층들은 다른 데이터셋의 이미지들을 학습할 때도 재사용될 수 있지만, 뒷단의 계층들은 새로운 문제를 맞이할 때마다 새로 학습이 필요
*전략
- 전략 1 : 전체 모델을 새로 학습시키기
- 전략 2 : Convolutional base의 일부분은 고정시킨 상태로, 나머지 계층과 classifier를 새로 학습시키기
- 전략 3 : Convolutional base는 고정시키고, classifier만 새로 학습시키기
*전략2
- 데이터셋이 작고 모델의 파라미터가 많다면, 오버피팅될 위험이 있으므로, 더 많은 계층을 건들지 않고 그대로 둔다.
- 데이터셋이 크고 그에 비해 모델이 작아서 파라미터가 적다면, 오버피팅에 대한 걱정을 할 필요가 없으므로 더 많은 계층을 학습시킨다.
*전략3
- convolutional base는 건들지 않고, feature extraction mechanism으로 활용하고, classifier만 재학습시키는 방법
- 컴퓨팅 연산 능력이 부족하거나, 데이터셋이 너무 작을 때, 그리고 풀고자 하는 문제가 pre-trained model의 학습 데이터셋과 매우 유사할 때
*learning rate
- 전략 1과 전략 2는 learning rate에 대해서 조심해야 한다.
- learning rate는 신경망에서 parameter를 얼마나 재조정할 것인지를 결정하는 hyper-parameter.
- CNN base일 때는 작은 learning rate를 사용하는 것이 바람직
- 작은 learning rate으로 학습을 시킨다면 CNN 모델의 parameter들을 너무 빠르게, 혹은 너무 많이 왜곡시키지 않고 원래 학습되어 있던 지식을 잘 보존하면서 추가로 학습 가능
*전이학습 전체 과정
- (1) 사전학습 모델 선택하기
- (2) 내 문제가 "데이터크기 - 유사성" 그래프에서 어떤 부분에 속하는지 알아보기
- (3) 내 모델을 Fine-tuning 하기
*"데이터크기 - 유사성" 그래프의 4가지 상황
- (1) 크기가 크고, 유사성이 작은 데이터셋 : 전략 1, 유사성이 거의 없는 데이터로 새로 학습을 시켜야 한다고 해도, 사전 학습 모델의 구조와 파라미터들을 가지고 시작하는 것이 아예 처음 시작하는 것보다 유용할 것임
- (2) 크기가 크고, 유사성이 높은 데이터셋 : 전략 2, 데이터셋의 크기가 커서 오버피팅은 문제가 안 될 것이기에, 원하는 만큼 학습 시켜도 됨. 데이터셋이 유사하다는 이점이 있으므로 모델이 이전에 학습한 지식을 활용하지 않을 이유가 없음
- (3) 크기가 작고, 유사성이 작은 데이터셋 : 전략 2 밖에 방법이 없음. convolutional base 계층 중 몇 개의 계층을 학습시키고, 몇 개를 그대로 두어야 하는지를 알아내는 것은 어려움. 너무 많은 계층을 새로 학습시키면 작은 데이터셋에 모델이 over-fitting 될 우려가 있고, 너무 적은 계층만을 학습시키면 제대로 학습되지 않을 것임. (2) 케이스보다는 좀 더 깊은 계층까지 새로 학습을 시킬 필요가 있음. 그리고 작은 크기의 데이터셋을 보완하기 위해 data augmentaion 같은 테크닉에 대해 알아봐야 함.
- (4) 크기가 작고, 유사성이 높은 데이터셋 : 전략 3, pre-trained model 의 마지막 classifier만 삭제하고, 기존의 convolutional base는 feature extractor로 사용하고, extracted 된 feature를 새 classifier에 넣어서 분류할 수 있도록 학습시킨다. 즉 새 classifier만 학습시킨다.
*classifier, 분류기
(1) Fully-connected layers
: Fully-connected layers 를 쌓은 후, 마지막에 softmax activated layer 를 놓는 것, softmax layer는 주어진 카테고리 각각에 대해 그 카테고리일 확률값을 출력
(2) Global average pooling
: Convolutional base의 끝에 Fully-connected layer 대신에 average pooling layer를 추가하고, 그 결과값을 바로 softmax layer와 연결하는 방식
(3) Linear support vector machines
: Convolutional base에서 추출된 특징을 Linear support vector machines 분류기로 분류함으로써 정확도를 더 높일 수 있다고 함.
(0) CNN 구조 끝에서 학습되는 여러가지 classifier들의 성능을 비교해보는 것은 많은 탐구가 필요한 작업
*test
features_batch = conv_base.predict(inputs_batch)
(1) Fully-connected layers : Adam 사용
(2) Global average pooling : average pooling 에 넣은 후 sigmoid 활성화 함수에 넣는다. 이진분류인 경우에는 활성화 함수로 sigmoid function을 loss function으로는 binary cross-entropy를 사용
(3) Linear support vector machines : K-fold cross-validation 방법을 이용해서 모델을 평가
*모델 로딩 후 재학습
reset_graph()
saver = tf.train.import_meta_graph("./model_completed.ckpt.meta")
로딩 가능한 operation 확인
for op in tf.get_default_graph().get_operations():
print(op.name)
parameter가 너무 많기 때문에 TensorBoard로 확인
get_tensor_by_name, get_operation_by_name으로 로드
x = tf.get_default_graph().get_tensor_by_name("X:0")
y = tf.get_default_graph().get_tensor_by_name("y:0")
accuracy = tf.get_default_graph().get_tensor_by_name("eval/accuracy:0")
training_op = tf.get_default_graph().get_operation_by_name("GradientDescent")
for op in (X, y, accuary, training_op):
tf.add_to_collection("my_important_ops", op)
X, y, accuracy, training_op = tf.get_collection("my_important_ops")
with tf.Session() as sess:
saver.restore(sess, "./model_completed.ckpt")
with tf.Session() as sess:
saver.restore(sess, "./my_model_final.ckpt")
for epoch in range(n_epochs):
for iteration in range(mnist.train.num_examples // batch_size):
X_batch, y_batch = mnist.train.next_batch(batch_size)
sess.run(training_op, feed_dict = {X: X_batch, y: y_batch})
accuracy_val = accuracy.eval(feed_dict={X: mnist.test.images, y: mnist.test.labels})
print(epoch, "Test accuracy:", accuracy_val)
save_path = saver.save(sess, "./model_completed.ckpt")
*마지막 4번째 layer만 수정해서 재학습하기 (not freezing the lower layers)
- import_meta_graph() 로 전체 graph를 모두 불러온 다음 4번째 layer를 무시한다.
- 3번째 layer 까지만 재사용한다.
- output layer 도 재설정한다.
- 이것으로 optimizer를 이용해서 최적화한다.
- 이렇게 생성된 결과를 새로운 파일에 저장
reset_graph()
n_hidden4 = 20
n_outputs = 10
saver = tf.train.import_meta_graph("./my_model_final.ckpt.meta")
X = tf.get_default_graph().get_tensor_by_name("X:0")
y = tf.get_default_graph().get_tensor_by_name("y:0")
hidden3 = tf.get_default_graph().get_tensor_by_name("dnn/hidden4/Relu:0")
new_hidden4= tf.layers.dense(hidden3, n_hidden4, activation = tf.nn.relu, name = "new_hidden4")
new_logits = tf.layers.dense(new_hidden4, n_outputs, name = "new_outputs")
with tf.name_scope("new_loss"):
xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=new_logits)
loss = tf.reduce_mean(xentropy, name = "loss")
with tf.name_scope("new_eval"):
correct = tf.nn.in_top_k(new_logits, y, 1)
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32), name = "accuracy")
with tf.name_scope("new_train"):
optimizer = tf.train.GradientDescentOpimizer(learning_rate)
training_op = optimizer.minimize(loss)
init = tf.global_variables_initialiaer()
new_saver = tf.train.Saver()
with tf.Session() as sess:
init.run()
saver.restore(sess, "./model_completed.ckpt")
for eopch in range(n_epochs):
for iteration in range(mnist.train.num_examples // batch_size):
X_batch, y_batch = mnist.train.next_batch(batch_size)
sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
accuracy_val = accuracy.eval(feed_dict={X: mnist.test.images, y: mnist.test.labels})
print(epoch, "Test accuracy:", accuracy_val)
save_path = new_saver.save(sess, "./model_completed.ckpt")
*마지막 4번째 layer만 수정해서 재학습하기 (freezing the lower layers)
tf.GraphKeys.TRAINABLE_VARIABLES, scope="outputs" 을 이용한 방법
tf.stop_gradient를 이용한 방법
[tf.GraphKeys.TRAINABLE_VARIABLES 이용]
reset_graph()
n_inputs = 28 * 28
n_hidden1 = 300
n_hidden2 = 50
n_hidden3 = 50
n_hidden4 = 20
n_outputs = 10
X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")
y = tf.placeholder(tf.int64, shape=(None), name="y")
with tf.name_scope("dnn"):
hidden1 = tf.layers.dense(X, n_hidden1, activation = tf.nn.relu, name="hidden1")
hidden2 = tf.layers.dense(n_hidden1, n_hidden2, activation = tf.nn.relu, name="hidden2")
hidden3 = tf.layers.dense(n_hidden2, n_hidden3, activation = tf.nn.relu, name="hidden3")
hidden4 = tf.layers.dense(n_hidden3, n_hidden4, activation = tf.nn.relu, name="hidden4")
logits = tf.layers.dense(n_hidden4, n_outputs, name="outputs")
with tf.name_scope("loss"):
xentropy = tf.nn.sparse_softmax_cross_entropy_wth_logits(labels=y, logits=logits)
loss = tf.reduce_mean(xentropy, name = "loss")
with tf.name_scope("eval"):
correct = tf.nn.in_top_k(logits, y, 1)
loss = tf.reduce_mean(tf.cast(correct, tf.float32), name = "accuracy")
학습할 대상을 정규식에 의해서 scope를 정해서 불러온다.
tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="outputs")
with tf.name_scope("train"):
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope = "outputs")
training_op = optimizer.minimize(loss, var_list = train_vars)
init= tf.global_variables_initializer()
new_saver = tf.train.Saver()
tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope="hidden[123]|outputs")
reuse_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope="hidden[123]|outputs]")
reuse_vars_dict = dict( [ (var.op.name, var) for var in reuse_vars ] )
restore_saver = tf.train.Saver(reuse_vars_dict)
init = tf.global_variables_initializer()
saver = tf.train.Saver()
with tf.Session() as sess:
init.run()
restore_saver.restore(sess, "./model_completed.ckpt")
for epoch in range(n_epochs):
for iteration in range(mnist.train.num_examples // batch_size):
X_batch, y_batch = mnist.train.next_batch(batch_size)
sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
accuracy_val = accuracy.eval(feed_dict={X: mnist.test.images, y: mnist.test.labels})
print(epoch, "Test accuracy:", accuracy_val)
save_path = saver.save(sess, "./model_completed.ckpt")
[tf.stop_gradient 이용]
reset_graph()
n_inputs = 28 * 28
n_hidden1 = 300
n_hidden2 = 50
n_hidden3 = 50
n_hidden4 = 20
n_outputs = 10
X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X")
y = tf.placeholder(tf.int64, shape=(None), name="y")
with tf.name_scope("dnn"):
hidden1 = tf.layers.dense(X, n_hidden1, activation=tf.nn.relu, name="hidden1")
hidden2 = tf.layers.dense(n_hidden1, n_hidden2, activation=tf.nn.relu, name="hidden2")
hidden2_stop = tf.stop_gradient(hidden2)
hidden3 = tf.layers.dense(hidden2_stop, n_hidden3, activation=tf.nn.relu, name="hidden3")
hidden4 = tf.layers.dense(n_hidden3, n_hidden4, activation=tf.nn.relu, name="hidden4")
logits = tf.layers.dense(n_hidden4, n_outputs, activation=tf.nn.relu, name="outputs")
with tf.name_scope("loss"):
xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits)
loss = tf.reduce_mean(xentropy, name="loss")
with tf.name_scope("eval"):
correct = tf.nn.in_top_k(logits, y, 1)
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32), name="accuracy")
with tf.name_scope("train"):
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
training_op = optimizer.minimize(loss)
reuse_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope="hidden[123]")
reuse_vars_dict = dict ( [ (var.op.name, var) for var in reuse_vars] )
restore_saver = tf.train.Saver(reuse_vars_dict)
init = tf.global_variables_initializer()
saver = tf.train.Saver()
with tf.Session() as sess:
init.run()
restore_saver.restore(sess, "./model_completed.ckpt")
for epoch in range(n_epochs):
for iteration in range(mnist.train.num_examples // batch_size):
X_batch, y_batch = mnist.train.next_batch(batch_size)
sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
accuracy_val = accuracy.eval(feed_dict={X: mnist.test.images, y: mnist.test.labels})
print(epoch, "Test accuracy:", accuacy_val)
save_path = saver.save(sess, "./model_completed.ckpt")
*Fronzen Layer를 cache 해서 학습속도를 올리는 방법
- Frozen layer는 변하지 않기 때문에 cache 해서 재사용 가능
- 한 번만 트레이닝해서 h2_cache를 만든 다음 이것을 shuffling 한 index를 가지고 epoch을 돌면서 training 하는 것
- 메모리가 충분하다면 가능
- 뒷 부분을 계산하지 않기 때문에 training 속도를 증가시킬 수 있음
n_batches = mnist.train.num_examples // batch_size
with tf.Session() as sess:
init.run()
restore_saver.restore(sess, "./model_completed.ckpt")
h2_cache = sess.run(hidden2, feed_dict={X: mnist.train.images})
h2_cache_test = sess.run(hidden2, feed_dict={X: mnist.test.images})
for epoch in range(n_epochs):
shuffled_idx = np.random.permutation(mnist.train.num_examples)
hidden2_batches = np.array_split(h2_cache[shuffled_idx], n_batches)
y_batches = np.array_split(mnist.train.labels[shuffled_idx], n_batches)
'스타트업 > AI' 카테고리의 다른 글
[AI] mmdetection transfer learning (0) | 2020.07.06 |
---|---|
[AI] Adaptive Transfer Learning (0) | 2020.07.02 |
[AI] ICDAR SROIE (0) | 2020.06.19 |
[AI] VIA tool 사용법 정리 (0) | 2020.06.18 |
[AI] Fraud Detection (0) | 2020.06.17 |