반응형

source: tensorflow.org

오늘은 딥러닝 모델을 생성할 때 많이 사용하는 Python 라이브러리 중 Tensorflow의 기본 동작 원리와 코드, Tensorflow 2.0에서는 어떻게 변화하였는지에 대해 살펴보도록 하겠습니다!

 

텐서플로 1 코드를 텐서플로 2로 바꿔보자

여전히 텐서플로 1.X 버전의 코드를 수정하지 않고 텐서플로 2.0에서 실행할 수 있습니다(contrib 모듈은 제외):

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

→ contrib 모듈의 경우 각 함수에 맞게 대체 가능한 모듈 찾아서 변경하기 (이 부분이 조금 귀찮음)

 

텐서플로 1 vs 2 동작원리 살펴보기

1. 텐서플로 1.x 코드

import tensorflow as tf  # v1

# 1. tf.placeholder를 사용하여 그래프에 입력할 값의 형태를 미리 지정한다.
in_a = tf.placeholder(dtype=tf.float32, shape=(2))
in_b = tf.placeholder(dtype=tf.float32, shape=(2))

# 2. 그래프 생성
def forward(x):
    # tf.get_variable을 사용하여 변수를 생성하고 tf.variable scope로 그 범위를 지정한다.
    with tf.variable_scope("matmul", reuse=tf.AUTO_REUSE):
        W = tf.get_variable("W", initializer=tf.ones(shape=(2,2)),
                            regularizer=tf.contrib.layers.l2_regularizer(0.04))
        b = tf.get_variable("b", initializer=tf.zeros(shape=(2)))
        return W * x + b

out_a = forward(in_a)
out_b = forward(in_b)

reg_loss = tf.losses.get_regularization_loss(scope="matmul")

# 3. tf.Session.run을 이용하여 그래프를 실행한다.
# The value returned by run() has the same shape as the fetches argument.
# feed_dict을 이용하여 placeholder의 실제 입력값을 넣는다.
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    outs = sess.run([out_a, out_b, reg_loss],  # fetches
                    feed_dict={in_a: [1, 0], in_b: [0, 1]})

 

 

2. 텐서플로 2.x 코드로 변경

import tensorflow as tf  # v2

# tf.variable_scope 사용하지 않음
W = tf.Variable(tf.ones(shape=(2,2)), name="W")
b = tf.Variable(tf.zeros(shape=(2)), name="b")

@tf.function
def forward(x):	
    return W * x + b

# tf.placeholder & tf.Session.run를 사용하지 않음
# Session.run 대신 실제 입력값의 단순 함수 호출로 변경(즉시 실행가능)
out_a = forward([1,0])
out_b = forward([0,1])

regularizer = tf.keras.regularizers.l2(0.04)
reg_loss = regularizer(W)

: TensorFlow 2 패키지에는 pip 버전 >19.0이 필요합니다. (https://www.tensorflow.org/install)

 

결론

source: https://www.tensorflow.org/guide/migrate#결론

전체적인 과정은 다음과 같습니다:

  1. 업그레이드 스크립트를 실행하세요.
  2. contrib 모듈을 삭제하세요.
  3. 모델을 객체 지향 스타일(케라스)로 바꾸세요.
  4. 가능한 **[tf.keras](<https://www.tensorflow.org/api_docs/python/tf/keras>)**나 **[tf.estimator](<https://www.tensorflow.org/api_docs/python/tf/estimator>)**의 훈련과 평가 루프를 사용하세요.
  5. 그렇지 않으면 사용자 정의 루프를 사용하세요. 세션과 컬렉션은 사용하지 말아야 합니다.

텐서플로 2.0 스타일로 코드를 바꾸려면 약간의 작업이 필요하지만 다음과 같은 장점을 얻을 수 있습니다:

  • 코드 라인이 줄어 듭니다.
  • 명료하고 단순해집니다.
  • 디버깅이 쉬워집니다.

 


텐서플로 2 | Basic Model 만들어보자

→ tensorflow2라고 쓰고 tf.keras 라고 읽는다.

참고: https://www.tensorflow.org/guide/keras

  • 아래의 tensorflow2 모델은 이미지 분류를 예시로 작성하였습니다.

 

1. dataset 생성하기

  • 여러 방법이 있지만 2가지만 소개합니다.
import tensorflow as tf

# Case 1
## ex, 
## x_train = [train_data_dir/file1.jpg, train_data_dir/file2.jpg, train_data_dir/file3.jpg, ...]
## y_train = [class1, class1, class2, ...]

train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))

# 필요에 따라 map_func 사용할 수 있음 (ex, 이미지 read, resize, ...)
train_dataset = train_dataset.map(lambda item1, item2: tf.numpy_function(
                                      map_func, [item1, item2], [tf.float32, tf.float32]))

# Shuffle and batch
train_dataset = train_dataset.shuffle(BUFFER_SIZE, seed=2021).batch(BATCH_SIZE)
train_dataset = train_dataset.prefetch(BUFFER_SIZE//2)
# Case 2
## ex, train_data_dir/class1/file1.jpg, train_data_dir/class1/file2.jpg, train_data_dir/class2/file3.jpg, ...
train_dataset = tf.keras.preprocessing.image_dataset_from_directory(train_data_dir,
                                                                    seed=2021,
                                                                    image_size=(img_height, img_width),
                                                                    batch_size=batch_size)

# class name 찾을 수 있음
class_names = train_dataset.class_names

train_dataset = train_dataset.cache().prefetch(BUFFER_SIZE//2)

 

2. model 생성하기

2.1 함수형

import tensorflow as tf
class_num = 5

def create_image_classification_model(input_shape):
    # 아래의 구조의 경우, tf.keras.Model 대신 tf.keras.models.Sequential 사용 가능
    # 다만, 다중 입력 및 출력, residual connection, attention 등 Model function이 활용성이 더 높음
    model_input = tf.keras.Input(shape=input_shape)

    embedding = tf.keras.layers.Conv2D(2, 3, padding='same', activation='relu')(model_input)

    embedding = tf.keras.layers.GlobalAveragePooling2D()(embedding)

    embedding = tf.keras.layers.Dense(128, activation='relu')(embedding)
    embedding = tf.keras.layers.Dropout(0.2)(embedding)
    
    embedding = tf.keras.layers.Dense(class_num, activation='softmax', name='output')(embedding)
    
    return tf.keras.Model(model_input, embedding, name='image_classification_model')

input_shape = (256, 256, 3)
classification_model = create_image_classification_model(input_shape)

## sample test
temp_input = tf.random.uniform(input_shape, dtype=tf.float32, minval=0, maxval=256)
output = classification_model.predict(tf.expand_dims(temp_input, 0))
output.shape  # (1, 5)

# model architecture(shape) & params 확인
classification_model.summary()

## (구조가 더 복잡한 경우,) model architecture(shape) ploting하여 확인 가능
# tf.keras.utils.plot_model(classification_model, "image_classification_model.png", show_shapes=True)

 

2.2 클래스 상속

import tensorflow as tf
class_num = 5

class ClassificationModel(tf.keras.Model):
    def __init__(self, class_num, dim=128, rate=0.1):
        super(ClassificationModel, self).__init__()
        self.conv2d = tf.keras.layers.Conv2D(2, 3, padding='same', activation='relu')
        
        self.dense1 = tf.keras.layers.Dense(dim, activation='relu')
        self.dense2 = tf.keras.layers.Dense(class_num, activation='softmax', name='output')
        
        self.gapooling = tf.keras.layers.GlobalAveragePooling2D()
        self.dropout = tf.keras.layers.Dropout(rate)
        

    def call(self, inputs):

        embedding = self.conv2d(inputs)

        embedding = self.gapooling(embedding)

        embedding = self.dense1(embedding)
        embedding = self.dropout(embedding)

        embedding = self.dense2(embedding)

        return embedding


input_shape = (256, 256, 3)
classification_model = ClassificationModel(class_num=class_num, rate=0.2)

## sample test
temp_input = tf.random.uniform(input_shape, dtype=tf.float32, minval=0, maxval=256)
output = classification_model(tf.expand_dims(temp_input, 0))

output.shape # TensorShape([1, 5])

# model architecture & params 확인
classification_model.build((None, 256, 256, 3))
classification_model.summary()

 

3. model 훈련하기

classification_model.compile(optimizer='adam',
                             loss=tf.keras.losses.CategoricalCrossentropy(from_logits=False),
                             metrics=['categorical_accuracy'])

history = classification_model.fit(train_dataset,
                                   epochs=EPOCHS,
                                   validation_data=val_dataset,
                                   callbacks=[modelcheck],)  # callbacks: modelcheckpoint, etc

 

  • 시각화하기
    import matplotlib.pyplot as plt
    
    acc = history.history['accuracy']
    val_acc = history.history['val_accuracy']
    
    loss=history.history['loss']
    val_loss=history.history['val_loss']
    
    epochs_range = range(EPOCHS)
    
    plt.figure(figsize=(8, 8))
    plt.subplot(1, 2, 1)
    plt.plot(epochs_range, acc, label='Training Accuracy')
    plt.plot(epochs_range, val_acc, label='Validation Accuracy')
    plt.legend(loc='lower right')
    plt.title('Training and Validation Accuracy')
    
    plt.subplot(1, 2, 2)
    plt.plot(epochs_range, loss, label='Training Loss')
    plt.plot(epochs_range, val_loss, label='Validation Loss')
    plt.legend(loc='upper right')
    plt.title('Training and Validation Loss')
    plt.show()​
    source: https://www.tensorflow.org/tutorials/images/classification

 

4. model save & load, predict 하기

model_save_path = 'image_classification_model'

# model architecture & weight 저장
classification_model.save(model_save_path)

# model architecture & weight 불러오기
new_model = tf.keras.models.load_model(model_save_path)
# new_model.trainable = False  # transfer learning시 pre-trained model을 freezing할 때 사용, layer별로 설정 가능

# 불러온 모델 predict
y_pred = new_model.predict(test_dataset,
                           steps=STEP_SIZE_TEST
                           )

 

 

반응형

+ Recent posts