반응형
Transfer Learning (전이 학습)
- 하나의 문제를 해결하고 새로운 유사한 문제에 적용하면서 얻은 지식을 저장하는데 초점을 맞춘 것
- 예시) 자동차를 인식하는 하는 법을 학습하면서 학습을 토대로 트럭을 인식하려고 할 때 적용
- 인공지능에서의 전이 학습은 사전학습모델(Pre-trained Model)을 이용하는 것을 의미
- 개념 알기 : https://luvris2.tistory.com/176
데이터 준비
이미지 데이터셋 다운로드
!wget --no-check-certificate \
https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip \
-O ./cats_and_dogs_filtered.zip
다운로드 파일 압축 해제
- 압축 해제 후 파일 디렉토리 변수로 저장
import zipfile
zipfile.ZipFile('cats_and_dogs_filtered.zip').extractall('/tmp/')
train_dir = ('/tmp/cats_and_dogs_filtered/train')
validation_dir = ('/tmp/cats_and_dogs_filtered/validation')
내 환경에 맞게 데이터셋 설정
학습시킬 데이터셋 호출
- X_train, y_train : 학습을 위한 데이터로 학습 데이터와 결과가 있음
- train_label : 학습을 위한 데이터의 클래스 분류를 사용자가 알아보기 쉽게 한 데이터
- X_test, y_test : 성능 테스트를 위한 데이터와 예측 결과가 있음
- test_label : 성능 테스트를 위한 데이터의 클래스 분류를 사용자가 알아보기 쉽게 한 데이터
- X_val, y_val : 검증을 위한 데이터와 검증하기 위한 결과 데이터가 있음
- val_label : 검증을 위한 데이터의 클래스 분류를 사용자가 알아보기 쉽게 한 데이터
# 데이터셋을 분리하는 함수
def load_dataset_from_hdf5_file(hdf_file_path):
hf = h5py.File(hdf_file_path, 'r')
X_train = np.array(hf['trainX'])
y_train = np.array(hf['trainY'])
train_label = np.array(hf['trainLabels'])
X_test = np.array(hf['testX'])
y_test = np.array(hf['testY'])
test_label = np.array(hf['testLabels'])
X_val = np.array(hf['devX'])
y_val = np.array(hf['devY'])
val_label = np.array(hf['devLabels'])
return X_train, y_train, train_label, X_test, y_test, test_label, X_val, y_val, val_label
X_train, y_train, train_label, X_test, y_test, test_label, X_val, y_val, val_label\
= load_dataset_from_hdf5_file('/vehicle_datasets/vehicle-type-dataset-SIZE224-train-dev-test-v2.hdf5')
내가 학습시킬 이미지 데이터셋 확인
# 학습 데이터가 이미 전처리가 되어있음
X_train[0]
>>> array([[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.], ...
X_train.max()
>>> 1.0
X_train.min()
>>> 0.0
# 가로 224, 세로 224, RGB컬러의 이미지 데이터
X_train[0].shape
>>> (224, 224, 3)
# 클래스가 7개로 분류 되는 결과 데이터, 원핫 인코딩이 되어 있음
y_train[0]
>>> ([0, 0, 0, 0, 0, 1, 0])
# 사람이 이해하기 쉽게 정리 한 데이터로 확인, 즉 첫번째 이미지 파일은 오토바이임
train_label[0]
>>> b'motocycle-motorbike-chopper'
# ImageDataGenerator를 위한 이미지의 크기와 채널의 정보를 변수로 저장
IMG_SHAPE = (224, 224, 3)
이미지 데이터셋 전처리 및 이미지 증강 작업
X_train[0]
>>> array([[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.], ...
# 데이터를 보니 이미 전처리가 되어있음
# 학습의 효율을 높이기 위해 이미지 증강만 진행
from tensorflow.keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator( rotation_range=20, width_shift_range=0.2,\
height_shift_range=0.2, zoom_range=0.2, horizontal_flip=True)
train_generator = train_datagen.flow(X_train, y_train)
MobileNetV2 기반 모델 생성 (Input Layer)
- base_model = tf.keras.applications.MobileNetV2 : 사전학습모델을 호출하여 새로운 모델로 정의
- input_shape : 이미지의 가로, 세로, 채널의 정보
- include_top : True/False로 구분, 네트워크의 최상단에 완전 연결 레이어를 넣을지의 여부
- trainable : 학습 여부(True/False), False일 경우 해당 모델의 학습을 하지 않음
- base_model(MobileNetV2)은 사전학습 된 모델이며, 학습 된 데이터로 특징을 잡아내는 역할
# IMG_SHAPE : 내가 학습시킬 이미지 데이터셋의 정보를 저장한 변수 이름
base_model = tf.keras.applications.MobileNetV2(input_shape = IMG_SHAPE, include_top = False)
# 학습여부 : 학습하지 않음
base_model.trainable = False
분류 작업을 할 모델 생성 후 모델링 (Output Layer (=Fully-connected Layer))
- output : 모델의 출력층(output layer)의 연결 여부
- head_model = base_model.output : 특징이 추출된 출력 데이터를 새 모델의 입력 데이터로 사용
- GlobalAveragePooling2D : 풀링 작업을 하고 1차원의 배열로 변경 (Convert FC Layer)
- Dense(7, 'softmax') : 분류 할 클래스가 7개이며, 3개 이상의 분류 모델은 softmax output
# new_model = model.output : 출력층을 새로운 계층(head_model)과 연결
head_model = base_model.output
# 분류를 위한 함수형 모델링
head_model = tf.keras.layers.GlobalAveragePooling2D()(head_model)
head_model = tf.keras.layers.Dense(128, 'relu')(head_model)
head_model = tf.keras.layers.Dense(7, 'softmax')(head_model)
모델 병합
- model = base model + head model
- input layer : 특징을 추츨해내는 역할을 하는 base_model(MobileNetV2기반)
- output layer : 분류 작업을 하는 head_model
# 모델 병합
model = tf.keras.models.Model(inputs = base_model.input, outputs = head_model)
모델 컴파일
- 최적화 설정 : RMSporp 사용
- 손실함수 설정 : 원핫 인코딩 처리가 되어 있기 때문에 'categorical_crossentropy' 사용
- 손실함수 분류에 따른 처리를 자세히 알고 싶다면? https://luvris2.tistory.com/163
- metrics(결과지표 설정) : 정확도 표시
# 컴파일
model.compile(tf.keras.optimizers.RMSprop(0.0001), 'categorical_crossentropy', ['accuracy'])
모델 학습
- train_generator : 이미지 증강 처리하고 학습결과까지 포함 (X_train+y_train)
- epochs : 학습의 반복 정도
- validation_data : 학습과 별개로 다른 데이터로 검증 여부, 과적합 방지 용도
epoch_history = model.fit( train_generator, epochs=5, validation_data= (X_val, y_val))
>>> Epoch 1/5
19/19 [==============================] - 19s 821ms/step - loss: 1.6215 - accuracy: 0.4146 - val_loss: 1.2126 - val_accuracy: 0.6533
Epoch 2/5
19/19 [==============================] - 13s 689ms/step - loss: 1.0424 - accuracy: 0.6816 - val_loss: 0.8264 - val_accuracy: 0.8533
Epoch 3/5
19/19 [==============================] - 13s 687ms/step - loss: 0.7184 - accuracy: 0.8159 - val_loss: 0.6115 - val_accuracy: 0.8400
Epoch 4/5
19/19 [==============================] - 14s 724ms/step - loss: 0.5368 - accuracy: 0.8590 - val_loss: 0.4643 - val_accuracy: 0.8800
Epoch 5/5
19/19 [==============================] - 15s 762ms/step - loss: 0.4376 - accuracy: 0.8740 - val_loss: 0.3856 - val_accuracy: 0.8933
Fine Tuning (미세 조정)
- base_model.trainable=True : 동결 해제
- 모델 특성 조정
- 참조하여 생성한 모델의 크기 확인, 적정 크기를 학습용으로 분배
- 모델 크기 확인 : base_model.shape
- 모델의 동결해제 적정 범위 설정 : base_model [ 0 : N ]
- 동결 해제 설정 : 반복문을 이용하여 설정한 범위 동결 해제
# Fine tuning
# 학습 가능 상태로 변경
base_model.trainable=True
# 참조해온 모델 레이어 확인
len(base_model.layers)
>>> 154
# 학습 범위 설정 121 ~ 154
end_layer = 120 # setting N (int)
for layer in base_model.layers[ 0 : end_layer+1 ]:
layer.trainable = False
# 컴파일
model.compile(tf.keras.optimizers.RMSprop(0.0001), 'categorical_crossentropy', ['accuracy'])
# 학습
epoch_history1 = model.fit( train_generator, epochs=5, validation_data= (X_val, y_val))
반응형