*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

+ Recent posts