딥러닝_CNN_합성곱연산(Covnet)_2. 사전훈련된 모델 활용한 이미지 분류

주지윤·2022년 12월 7일
0

딥러닝

목록 보기
15/21
post-custom-banner

합성곱연산_사전훈련된 모델 활용

  • 사전 훈련된 모델(pretrained model): 대규모 이미지 분류 문제를 위해 대량의 데이터셋에서 미리 훈련된 모델

  • keras에서 사용할 수 있는 사전훈련모델

    • Xception, ResNet, MobileNet, EfficientNet, DenseNet ...



1. 사전 훈련 모델을 사용한 특성 추출: feature extraction

  • 특성추출: 사전에 학습된 모델의 표현을 사용하여 새로운 샘플에서 흥미로운 특성을 뽑아내는 것
  • 특성맵: 이미지에 대한 일반적인 콘셉트의 존재 여부를 기록한 맵
  • 밀집 연결층에서는 더이상 이미지에 있는 객체의 위치정보를 가지고 있지 않음(Flatten)
  • 합성곱에서는 객체의 위치를 고려, 층에 깊이에 따라 일반성의 수준이 다름
    • 하위층: 매우 일반적 특성(에지,색깔, 질감 등)
    • 상위층: 좀 더 추상적 (고양이의 귀, 눈 등)

🔸 사용모델: VGG16

conv_base = applications.vgg16.VGG16(
    weights="imagenet",
    include_top=False,
    input_shape=(180, 180, 3))
  • weight: 가중치 체크포인트 지정
  • include_top: 밀집 연결 분류기 포함 여부[True,False]
  • input_shape: 이미지 텐서의 크기
conv_base.summary()

🔸 밀집 연결층을 연결하는 방법 2가지

  • 합성곱 기반층을 실행하고, 디스크에 저장 → 독립된 밀집 연결 분류기에 입력
    • 합성곱 기반층을 한번만 사용: 데이터 증식 X
  • 준비된 모델에 밀집 연결층을 쌓아 확장
    • 모든 입력 이미지가 매번 합성곱 기반 통과: 데이터 증식 O



1) 빠른 특성 추출: 데이터증식X

🔸 vgg16 특성추출 함수 적용

  • 참고
import numpy as np
  
def get_features_and_labels(dataset):
    all_features = []
    all_labels = []
    
    for images, labels in dataset:
        preprocessed_images = keras.applications.vgg16.preprocess_input(images)
        features = conv_base.predict(preprocessed_images)
        
        all_features.append(features)
        all_labels.append(labels)
        
    return np.concatenate(all_features), np.concatenate(all_labels)
  
train_features, train_labels =  get_features_and_labels(train_dataset)
val_features, val_labels =  get_features_and_labels(validation_dataset)
test_features, test_labels =  get_features_and_labels(test_dataset)

  • 이미지 데이터 전처리

    • keras.applications.vgg16.preprocess_input(images)
    • 적절한 범위로 픽셀 값 조정
  • conv_base.predict()를 사용하여 특성 추출(넘파이 배열)

  • train_features.shape >>>(2000,5,5,512)



🔸 밀집 연결 분류기 정의 및 훈련

inputs = keras.Input(shape=(5, 5, 512))
x = layers.Flatten()(inputs)
x = layers.Dense(256)(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(1, activation="sigmoid")(x)

model = keras.Model(inputs, outputs)
model.compile(loss="binary_crossentropy",
              optimizer="rmsprop",
              metrics=["accuracy"])
  
  
callbacks = [keras.callbacks.ModelCheckpoint(
                filepath="feature_extraction.keras",
                save_best_only=True,
                monitor="val_loss")]

history = model.fit(train_features, train_labels,
                    epochs=20,
                    validation_data=(val_features, val_labels),
                    callbacks=callbacks)
  • Dense층 전에 Flatten
  • 규제를 위한 Dropout사용

🔸 그래프

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(1, len(acc) + 1)
plt.plot(epochs, acc, "bo", label="Training accuracy")
plt.plot(epochs, val_acc, "b", label="Validation accuracy")
plt.title("Training and validation accuracy")
plt.legend()
plt.figure()
plt.plot(epochs, loss, "bo", label="Training loss")
plt.plot(epochs, val_loss, "b", label="Validation loss")
plt.title("Training and validation loss")
plt.legend()
plt.show()


🔸 테스트 평가: feature_extraction.keras

test_model = keras.models.load_model('feature_extraction.keras')
test_loss, test_acc = test_model.evaluate(test_features, test_labels)
print(f'정확도: {test_acc:.3f}')

정확도: 0.974



2) 데이터증식을 사용한 특성추출

  1. 데이터 증식
  2. 합성곱 기반층 동결
  3. 밀집 분류기
  • 합성곱 기반층 동결을 하는 이유:
    • Dense층은 랜덤한 초기화 → 매우 큰 가중치 업데이트 값 전파
    • == 합성곱으로 사전 훈련된 표현 훼손

🔸 데이터 증식

data_augmentation = keras.Sequential([
        layers.RandomFlip("horizontal"),
        layers.RandomRotation(0.1),
        layers.RandomZoom(0.2),])

🔸 합성곱 기반층 동결

conv_base.trainable = False

훈련가능한 가중치 참고:

  • conv_base.trainable = True일 경우
    • len(conv_base.trainable_weights)>>>26
  • conv_base.trainable = False일 경우
    • len(conv_base.trainable_weights)>>>0

🔸 데이터 증식과 밀집 분류기를 합성곱 층에 연결

inputs = keras.Input(shape=(180, 180, 3))

x = data_augmentation(inputs)   # 데이터증식
x = keras.applications.vgg16.preprocess_input(x)   # 이미지데이터 전처리
x = conv_base(x)   # 합성곱연산

x = layers.Flatten()(x)   
x = layers.Dense(256)(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model = keras.Model(inputs, outputs)
model.compile(loss="binary_crossentropy",
              optimizer="rmsprop",
              metrics=["accuracy"])
callbacks = [
    keras.callbacks.ModelCheckpoint(
        filepath="feature_extraction_with_data_augmentation.keras",
        save_best_only=True,
        monitor="val_loss")
]
history = model.fit(
    train_dataset,
    epochs=50,
    validation_data=validation_dataset,
    callbacks=callbacks)

🔸 그래프

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(1, len(acc) + 1)
plt.plot(epochs, acc, "bo", label="Training accuracy")
plt.plot(epochs, val_acc, "b", label="Validation accuracy")
plt.title("Training and validation accuracy")
plt.legend()
plt.figure()
plt.plot(epochs, loss, "bo", label="Training loss")
plt.plot(epochs, val_loss, "b", label="Validation loss")
plt.title("Training and validation loss")
plt.legend()
plt.show()


🔸 테스트 평가: feature_extraction_with_data_augmentation.keras

test_model = keras.models.load_model(
    "feature_extraction_with_data_augmentation.keras")
test_loss, test_acc = test_model.evaluate(test_dataset)
print(f"Test accuracy: {test_acc:.3f}")

Test accuracy: 0.976



2. 사전 훈련 모델 미세조정

  • 특성추출 보완
  • 상위 층 몇 개를 동결에서 해제하고 모델에 새로 추가한 층(지금은 밀집연결층)과 함께 훈련
  • 단, 맨위의 분류기(밀집연결층)가 훈련된 후 합성곱 기반의 상위층을 미세조정할 수 있다.
    • 분류기가 미리 훈련되지 않을 경우 훈련되는 동안 너무 큰 오차신호가 전파


1. 사전 훈련된 기반 네트워크위에 새로운 네트워크 추가
2. 기반 네트워크 동결
3. 새로 추가한 네트워크 훈련
4. 기반 네트워크에서 일부 층 동결 해제
5. 동결을 해제한 층과 새로 추가한 층을 함께 훈련

🔸 1~3까지 '데이터증식을 사용한 특성추출'에서 이미 완료

🔸 4. 일부층 동결 해제

conv_base.trainable = True
for layer in conv_base.laters[:-4]:
	layer.trainable = False

🔸 5. 동결을 해제한 층과 새로 추가한 층을 함께 훈련

model.compile(loss="binary_crossentropy",
              optimizer=keras.optimizers.RMSprop(learning_rate=1e-5),
              metrics=["accuracy"])
  
callbacks = [
    keras.callbacks.ModelCheckpoint(
        filepath="fine_tuning.keras",
        save_best_only=True,
        monitor="val_loss")
]

history = model.fit(
    train_dataset,
    epochs=30,
    validation_data=validation_dataset,
    callbacks=callbacks)
  • 학습률을 낮춘 RMSProp옵티마이저 사용: 변경량이 너무 크면 학습된 표현에 나쁜영향을 줄 수 있다.

🔸 6. 테스트 평가:fine_tuning.keras

model = keras.models.load_model("fine_tuning.keras")
test_loss, test_acc = model.evaluate(test_dataset) 
print(f"Test accuracy: {test_acc:.3f}")

Test accuracy: 0.979




합성곱(CNN/Convnet) 요약

  • 컴퓨터 비전 작업에서 가장 뛰어남
  • 패턴과 개념의 계층구조를 학습
  • 작은 데이터 셋의 과대적합을 피하기 위한 방법: 데이터 증식
  • 특성추출방식으로 기존 컨브넷을 쉽게 재사용 가능
  • 특성추출을 보완: 미세조정



** 이미지출처

post-custom-banner

0개의 댓글