학습 모델의 재사용 (Transfer Learning)


DNN 모델을 스케치 단계서 부터 전부 다시 학습하는 것은 어려운 일이다. 정말 많은 데이터를 필요로 하기 때문에 학습이 거의 대부분 실패 한다.

여러 방법이 있을 수 있지만 여기서는 Transfer Learning을 다룬다. 잘알려진pretrainted model을 이용해서 마지막 final layer만 수정해서 본인의 목적에 맞게 다시 학습 시키는 방법이다.
혹자는 Fine tuning이라 부르기도 한다.

본인 보유한 데이터 양에 따라 어느 정도 레이어들을 수정할지가 결정된다. 보통 앞부분 layer는 추상적인 feature를 extraction하는 레이어이므로 건들지 않고 마지막 레이러들을 수정한다.

하지만 pretrained model이 현재 수행하려고 하는 작업에 전혀 관련이 없다면Transfer Learning이 의미가 퇴색 된다.
이 경우 unsupervised pre-training방법으로 RBM 또는 Autoencoder방법을 사용하거나 실제로 labeling 데이터를 왕창 모아서 학습을 해야한다.
하지만 scarth부터 random initialization 상태에서 학습하는 것은 매우 도전적인 일이므로 추천 하진 않는다.

결국 아무 때나 Deep Learning을 쓰기엔 무리가 있다.

개념설명

아래와 같이 ImageNet모델이 있다고 가정한다. 1000개를 classify할 수 있다.

이것을 가지고 고양이 Tigger, Misty, Neither 세개를 구분하는 모델을 만든다. 당연히 이런 특정 고양이 이미지는 많이 없다. 따라서 pre-trained 모델을 사용 한다.

이 때 학습할 때 마지막 softmax layer만 학습하게 된다.
이전 데이터는 freeze하게 된다. 이것은 deep learning framework에 따라 구현코드가 달라진다. 이후에는 TensorFlow를 이용해서 이 방법을 다룬다.

  • trainablePrameter =0, freeze = 1

그리고 이러한 freeze레이어의 숫자는 training data의 양에 따라서 다르게 적용할 수 있다.

Tensorflow 구현 (개념 설명)

전부다 저장하고 restore하는 코드

[...] # construct the original model

with tf.Session() as sess:
	saver.restore(sess, "./my_original_model.ckpt")
	[...] # Train it on your new task

부분적으로 복구하는 방법

init = tf.global_variables_initializer()
reuse_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="hidden[123]")
reuse_vars_dict = dict([(var.name, var.name) for var in reuse_vars])
original_saver = tf.Saver(reuse_vars_dict) # saver to restore the original model

new_saver = tf.Saver() # saver to save the new model

with tf.Session() as sess:
	sess.run(init)
	original_saver.restore("./my_original_model.ckpt") # restore layers 1 to 3
	[...] # train the new model
	new_saver.save("./my_new_model.ckpt") # save the whole model

좀 더 상세한 내용은 이전 포스트를 참조한다.

실제코드

MNIST 데이터를 가지고 fully connected DNN의 pre-trained model을 로드해서 fine-tuning 하는 방법을 다룬다.
전체 구현코드는 Github Link에 있다.

  • 모델 학습
  • 전체 로드
  • 일부분 로드
  • 앞부분 레이어 고정후 뒷 부분만 학습
  • 고정레이어 cache후 뒷 부분만 학습 (트레이닝 속도 향상)

기본 라이브러리 로딩

import tensorflow as tf
# Common imports
import numpy as np
import os
from tensorflow.examples.tutorials.mnist import input_data

def reset_graph(seed=42):
    tf.reset_default_graph()
    tf.set_random_seed(seed)
    np.random.seed(seed)
def leaky_relu(z, name=None):
    return tf.maximum(0.01 * z, z, name=name)

mnist = input_data.read_data_sets("./")
Extracting ./train-images-idx3-ubyte.gz
Extracting ./train-labels-idx1-ubyte.gz
Extracting ./t10k-images-idx3-ubyte.gz
Extracting ./t10k-labels-idx1-ubyte.gz

모델 생성

하이퍼파라메터 설정

reset_graph()

n_inputs = 28 * 28  # MNIST
n_hidden1 = 300
n_hidden2 = 50
n_hidden3 = 50
n_hidden4 = 50
n_hidden5 = 50
n_outputs = 10

n_epochs = 20
batch_size = 50

모델 생성

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(hidden1, n_hidden2, activation=tf.nn.relu, name="hidden2")
    hidden3 = tf.layers.dense(hidden2, n_hidden3, activation=tf.nn.relu, name="hidden3")
    hidden4 = tf.layers.dense(hidden3, n_hidden4, activation=tf.nn.relu, name="hidden4")
    hidden5 = tf.layers.dense(hidden4, n_hidden5, activation=tf.nn.relu, name="hidden5")
    logits = tf.layers.dense(hidden5, n_outputs, 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")

learning_rate = 0.01
threshold = 1.0

optimizer = tf.train.GradientDescentOptimizer(learning_rate)
grads_and_vars = optimizer.compute_gradients(loss)
capped_gvs = [(tf.clip_by_value(grad, -threshold, threshold), var)
              for grad, var in grads_and_vars]
training_op = optimizer.apply_gradients(capped_gvs)

init = tf.global_variables_initializer()
saver = tf.train.Saver()

학습

with tf.Session() as sess:
    init.run()
    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})
        if epoch % 5 == 0:
            acc_train = accuracy.eval(feed_dict={X: X_batch, y: y_batch})
            acc_test = accuracy.eval(feed_dict={X: mnist.validation.images, y: mnist.validation.labels})
            print(epoch, "Batch accuracy:", acc_train, "Validation accuracy:", acc_test)

    save_path = saver.save(sess, "./my_model_final.ckpt")
0 Batch accuracy: 0.94 Validation accuracy: 0.9006
5 Batch accuracy: 1.0 Validation accuracy: 0.9642
10 Batch accuracy: 0.96 Validation accuracy: 0.9712
15 Batch accuracy: 0.98 Validation accuracy: 0.9772
20 Batch accuracy: 1.0 Validation accuracy: 0.9774
25 Batch accuracy: 1.0 Validation accuracy: 0.9786
30 Batch accuracy: 1.0 Validation accuracy: 0.9778
35 Batch accuracy: 1.0 Validation accuracy: 0.9776

모델 로딩후 재학습

여기서 부터 모델을 불러와서 다시 fine-tuning 하는 부분을 구현 한다.

reset_graph()
saver = tf.train.import_meta_graph("./my_model_final.ckpt.meta")

로딩가능한 operation이 무엇인지 확인한다.

for op in tf.get_default_graph().get_operations():
    print(op.name)
X
y
hidden1/kernel/Initializer/random_uniform/shape
hidden1/kernel/Initializer/random_uniform/min
hidden1/kernel/Initializer/random_uniform/max
[생략]
[생략]
save/RestoreV2_11/tensor_names
save/RestoreV2_11/shape_and_slices
save/RestoreV2_11
save/Assign_11
save/restore_all

파라메터가 너무 많기 때문에 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")

다른 사람의 편의를 위해서 import operation collection으로 미리 정의해 줄수도 있다.

for op in (X, y, accuracy, 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, "./my_model_final.ckpt")
    # continue training the model...
INFO:tensorflow:Restoring parameters from ./my_model_final.ckpt

아니면 모델을 로드에서 Testing만 가능하다.

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, "./my_new_model_final.ckpt")    
INFO:tensorflow:Restoring parameters from ./my_model_final.ckpt
0 Test accuracy: 0.9743
1 Test accuracy: 0.9744
2 Test accuracy: 0.9756
3 Test accuracy: 0.9743
4 Test accuracy: 0.9751
5 Test accuracy: 0.975
6 Test accuracy: 0.9741
7 Test accuracy: 0.9742
8 Test accuracy: 0.9751
9 Test accuracy: 0.9748
10 Test accuracy: 0.9744
11 Test accuracy: 0.9747
12 Test accuracy: 0.9746
13 Test accuracy: 0.9747
14 Test accuracy: 0.9746
15 Test accuracy: 0.9747
16 Test accuracy: 0.9742
17 Test accuracy: 0.9749
18 Test accuracy: 0.9746
19 Test accuracy: 0.9748
20 Test accuracy: 0.975
21 Test accuracy: 0.9746
22 Test accuracy: 0.9745
23 Test accuracy: 0.975
24 Test accuracy: 0.9744
25 Test accuracy: 0.9743
26 Test accuracy: 0.9743
27 Test accuracy: 0.9745
28 Test accuracy: 0.9746
29 Test accuracy: 0.9749
30 Test accuracy: 0.9746
31 Test accuracy: 0.9747
32 Test accuracy: 0.9747
33 Test accuracy: 0.9743
34 Test accuracy: 0.9746
35 Test accuracy: 0.9746
36 Test accuracy: 0.9749
37 Test accuracy: 0.9751
38 Test accuracy: 0.9748
39 Test accuracy: 0.9743

다른 방법은 그냥 원래 모델에 대한 code가 있다면 그것을 로딩해도 된다. 그렇게 하면import_meta_graph()를 호출하지 않아도 된다.

마지막 4번째 레어어만 수정해서 재학습하기 (not freezing the lower layers)

  • import_meta_graph()로 전체 graph를 모두 불러온다음 4번째 Layer를 무시한다.
  • 즉 3번째 레이어 까지만 재사용한다.
  • 그리고 output 레이어도 재설정한다.
  • 그리고 이것으로 optimizer를 이용해서 최적화한다.
  • 이렇게 생성된 결과를 새로운 파일에 저장한다.
reset_graph()

n_hidden4 = 20  # new layer
n_outputs = 10  # new layer

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.GradientDescentOptimizer(learning_rate)
    training_op = optimizer.minimize(loss)

init = tf.global_variables_initializer()
new_saver = tf.train.Saver()

새로운 레이어를 정의하고 loss namesapce를 다르게 정의 했기 때문에saver.restore()후에 값이 중복 되지 않는다.

with tf.Session() as sess:
    init.run()
    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 = new_saver.save(sess, "./my_new_model_final.ckpt")
INFO:tensorflow:Restoring parameters from ./my_model_final.ckpt
0 Test accuracy: 0.9665
...
...
39 Test accuracy: 0.9751

마지막 4번째 레어어만 수정해서 재학습하기 (freezing the lower layers)

구현을 위해서는 2가지 방법이 존재한다.

  • tf.GraphKeys.TRAINABLE_VARIABLES, scope="outputs")을 이용한 방법
  • tf.stop_gradient를 이용한방법

tf.GraphKeys.TRAINABLE_VARIABLES 이용

reset_graph()

n_inputs = 28 * 28  # MNIST
n_hidden1 = 300 # reused
n_hidden2 = 50  # reused
n_hidden3 = 50  # reused
n_hidden4 = 20  # new!
n_outputs = 10  # new!

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")       # reused
    hidden2 = tf.layers.dense(hidden1, n_hidden2, activation=tf.nn.relu, name="hidden2") # reused
    hidden3 = tf.layers.dense(hidden2, n_hidden3, activation=tf.nn.relu, name="hidden3") # reused
    hidden4 = tf.layers.dense(hidden3, n_hidden4, activation=tf.nn.relu, name="hidden4") # new!
    logits = tf.layers.dense(hidden4, n_outputs, name="outputs")                         # new!

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")

학습할 대상을 정규식에 의해서 scope을 정해서 불러온다.
결과는 아래와 같다.

tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
                                   scope="outputs")
[<tf.Variable 'outputs/kernel:0' shape=(20, 10) dtype=float32_ref>,
<tf.Variable 'outputs/bias:0' shape=(10,) dtype=float32_ref>]
with tf.name_scope("train"):                                         # not shown in the book
    optimizer = tf.train.GradientDescentOptimizer(learning_rate)     # not shown
    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()

따로 새롭게 namesapce를 정의하지 않고 load할 때 정규식을 이용해서 일부분만 불러온다.
이렇게 하면 name을 변경할 필요 없다.

tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES,
                               scope="hidden[123]|outputs") # regular expression
[<tf.Variable 'hidden1/kernel:0' shape=(784, 300) dtype=float32_ref>,
 <tf.Variable 'hidden1/bias:0' shape=(300,) dtype=float32_ref>,
 <tf.Variable 'hidden2/kernel:0' shape=(300, 50) dtype=float32_ref>,
 <tf.Variable 'hidden2/bias:0' shape=(50,) dtype=float32_ref>,
 <tf.Variable 'hidden3/kernel:0' shape=(50, 50) dtype=float32_ref>,
 <tf.Variable 'hidden3/bias:0' shape=(50,) dtype=float32_ref>,
 <tf.Variable 'outputs/kernel:0' shape=(20, 10) dtype=float32_ref>,
 <tf.Variable 'outputs/bias:0' shape=(10,) dtype=float32_ref>]
reuse_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES,
                               scope="hidden[123]|outputs]") # regular expression
reuse_vars_dict = dict([(var.op.name, var) for var in reuse_vars])
restore_saver = tf.train.Saver(reuse_vars_dict) # to restore layers 1-3

init = tf.global_variables_initializer()
saver = tf.train.Saver()

with tf.Session() as sess:
    init.run()
    restore_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, "./my_new_model_final.ckpt")
INFO:tensorflow:Restoring parameters from ./my_model_final.ckpt
0 Test accuracy: 0.9221
...
...
39 Test accuracy: 0.9556

tf.stop_gradient 이용

reset_graph()

n_inputs = 28 * 28  # MNIST
n_hidden1 = 300 # reused
n_hidden2 = 50  # reused
n_hidden3 = 50  # reused
n_hidden4 = 20  # new!
n_outputs = 10  # new!

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") # reused frozen
    hidden2 = tf.layers.dense(hidden1, n_hidden2, activation=tf.nn.relu,
                              name="hidden2") # reused frozen
    hidden2_stop = tf.stop_gradient(hidden2)
    hidden3 = tf.layers.dense(hidden2_stop, n_hidden3, activation=tf.nn.relu,
                              name="hidden3") # reused, not frozen
    hidden4 = tf.layers.dense(hidden3, n_hidden4, activation=tf.nn.relu,
                              name="hidden4") # new!
    logits = tf.layers.dense(hidden4, n_outputs, name="outputs") # new!
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)

위와 같이 hidden2_stop = tf.stop_gradient(hidden2)을 사용해서 중간 레이어를 만든다.
그 이후에는 트레이닝 코드는 위 방식과 정확히 일치한다.

%%time
reuse_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES,
                               scope="hidden[123]") # regular expression
reuse_vars_dict = dict([(var.op.name, var) for var in reuse_vars])
restore_saver = tf.train.Saver(reuse_vars_dict) # to restore layers 1-3

init = tf.global_variables_initializer()
saver = tf.train.Saver()

with tf.Session() as sess:
    init.run()
    restore_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, "./my_new_model_final.ckpt")
INFO:tensorflow:Restoring parameters from ./my_model_final.ckpt
0 Test accuracy: 0.9654
...
...
19 Test accuracy: 0.9738
CPU times: user 23.1 s, sys: 852 ms, total: 23.9 s
Wall time: 13.5 s

Fronzen Layer를 cache해서 학습속도를 올리는 방법

Frozen 레이어는 변화하지 않기 때문에 이것은 cache해서 재사용 할 수 있다.

reset_graph()

n_inputs = 28 * 28  # MNIST
n_hidden1 = 300 # reused
n_hidden2 = 50  # reused
n_hidden3 = 50  # reused
n_hidden4 = 20  # new!
n_outputs = 10  # new!

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") # reused frozen
    hidden2 = tf.layers.dense(hidden1, n_hidden2, activation=tf.nn.relu,
                              name="hidden2") # reused frozen & cached
    hidden2_stop = tf.stop_gradient(hidden2)
    hidden3 = tf.layers.dense(hidden2_stop, n_hidden3, activation=tf.nn.relu,
                              name="hidden3") # reused, not frozen
    hidden4 = tf.layers.dense(hidden3, n_hidden4, activation=tf.nn.relu,
                              name="hidden4") # new!
    logits = tf.layers.dense(hidden4, n_outputs, name="outputs") # new!

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]") # regular expression
reuse_vars_dict = dict([(var.op.name, var) for var in reuse_vars])
restore_saver = tf.train.Saver(reuse_vars_dict) # to restore layers 1-3

init = tf.global_variables_initializer()
saver = tf.train.Saver()

핵심 방법은 1번만 트레이닝해서 h2_cache를 만든다음 이것을 suffling한 index를 가지고 epoch을 돌면서 training하는 것이다.
메모리가 충분하다면 이러한 방법이 가능하다.
뒷 부분을 계산하지 않기 때문에 training속도를 증가 시킬 수 있다.13.5초에서9.63초로 속도가 빨라진 것을 알 수 있다.

%%time
import numpy as np

n_batches = mnist.train.num_examples // batch_size

with tf.Session() as sess:
    init.run()
    restore_saver.restore(sess, "./my_model_final.ckpt")
    
    h2_cache = sess.run(hidden2, feed_dict={X: mnist.train.images})
    h2_cache_test = sess.run(hidden2, feed_dict={X: mnist.test.images}) # not shown in the book

    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)
        for hidden2_batch, y_batch in zip(hidden2_batches, y_batches):
            sess.run(training_op, feed_dict={hidden2:hidden2_batch, y:y_batch})

        accuracy_val = accuracy.eval(feed_dict={hidden2: h2_cache_test, # not shown
                                                y: mnist.test.labels})  # not shown
        print(epoch, "Test accuracy:", accuracy_val)                    # not shown

    save_path = saver.save(sess, "./my_new_model_final.ckpt")
INFO:tensorflow:Restoring parameters from ./my_model_final.ckpt
0 Test accuracy: 0.9648
...
...
19 Test accuracy: 0.9736
CPU times: user 20.7 s, sys: 428 ms, total: 21.1 s
Wall time: 9.63 s

참고문헌

Coursera deep learning ai, Andrew Ng.
Hands-On Machine Learning with Scikit-Learn and Tensorflow, Aureien Geron


+ Recent posts