일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 스파르타코딩클럽
- Phrase Sets
- 4주차
- 모델적응
- jquery
- html
- AWS
- model
- KoBERT
- mnist
- KoBART
- 우분투2004
- ubuntu
- Transfer_Learning
- Google Speech To Text
- 서버
- Flask
- Linux
- keras
- Django
- ajax
- Custom Classes
- FastAPI
- 과일종류예측
- EC2
- UbuntuServer
- Ubuntu2004
- Kaggle
- 가장쉽게배우는머신러닝
- Model Adaptations
- Today
- Total
영웅은 죽지 않는다
딥러닝 때려 부수기 - 전이 학습(TL), 캐글 데이터를 이용한 과일 종류 예측 모델 본문
딥러닝 때려 부수기 - 전이 학습(TL), 캐글 데이터를 이용한 과일 종류 예측 모델
YoungWoong Park 2021. 8. 19. 15:52전이 학습 (Transfer Learning, TL)이란
사람이 영어를 완벽하게 구사할 수 있다면, 프랑스어를 배울 때 영어를 배웠던 과정과 유사하게 지식을 습득하는 것과 같은 개념입니다. 과거에 문제를 해결하면서 축적된 경험을 토대로 그것과 유사한 신경망을 학습시키는 방법을 전이 학습(Transfer Learning)이라고 합니다. 이는 학습 속도가 비교적 빠르고, 더 정확하고, 상대적으로 적은 데이터셋으로 좋은 결과를 낼 수 있기 때문에 실무에서 자주 사용하는 방법입니다.
전이 학습은 미리 학습시킨 모델(pretrained models)을 가져와 새로운 데이터셋에 다시 학습시키는 방법입니다. 이는 다른 형태의 데이터셋에 대해서도 효과를 보이는데, 예를 들어 1,000개의 동물/사물을 분류하는 ImageNet이라는 대회에서 학습한 모델들을 가져와 얼굴 인식 데이터셋에 학습시켜도 좋은 결과를 얻을 수 있습니다. 이런 특징 때문에 전이 학습은 딥러닝에서 중요한 부분을 차지하게 되었습니다.
TL을 이용한 과일 종류 예측 모델
- 데이터셋 다운로드 : https://www.kaggle.com/moltean/fruits
캐글에 로그인 후 내 프로필 -> Account -> API -> Create New API Token 에서 kaggle.json을 다운로드하여 username과 key값을 입력합니다.
import os
os.environ['KAGGLE_USERNAME'] = 'username' # username
os.environ['KAGGLE_KEY'] = 'key' # key
그 후 데이터셋의 API Command를 Copy하여 데이터셋을 불러온 후 압축을 풉니다.
-q는 데이터 수가 많을 때 출력을 나오지 않게 하는 메소드입니다.
!kaggle datasets download -d moltean/fruits
!unzip -q fruits.zip
- 필요한 패키지 Import
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense, Conv2D, MaxPooling2D, Flatten, Dropout
from tensorflow.keras.optimizers import Adam, SGD
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import OneHotEncoder
- 전처리 : 이미지 증강 기법 이용
train_datagen = ImageDataGenerator(
rescale=1./255, # 일반화
rotation_range=10, # 랜덤하게 이미지를 회전 (단위: 도, 0-180)
zoom_range=0.1, # 랜덤하게 이미지 확대 (%)
width_shift_range=0.1, # 랜덤하게 이미지를 수평으로 이동 (%)
height_shift_range=0.1, # 랜덤하게 이미지를 수직으로 이동 (%)
horizontal_flip=True # 랜덤하게 이미지를 수평으로 뒤집기
)
test_datagen = ImageDataGenerator(
rescale=1./255 # 일반화
)
train_gen = train_datagen.flow_from_directory(
'fruits-360/Training',
target_size=(224, 224), # (height, width)
batch_size=32,
seed=2021,
class_mode='categorical',
shuffle=True
)
test_gen = test_datagen.flow_from_directory(
'fruits-360/Test',
target_size=(224, 224), # (height, width)
batch_size=32,
seed=2021,
class_mode='categorical',
shuffle=False
)
여기서도 증강기법 값들을 넣어준 이후, flow_from_directory 메소드를 이용해 폴더 내부에 있는 데이터를 직접 읽어와 label별로 class를 분류해주는 작업을 추가하며 train값에 랜덤성을 넣어주기 위해 shuffle값을 True로 설정해줍니다.
train 폴더에는 67,692개의 이미지가 있고 이를 131개의 클래스로 분류했고, test 폴더에는 22,688개의 이미지가 있고 이 또한 131개의 클래스로 분류했다는 것을 출력해줍니다.
- 데이터 확인하기
from pprint import pprint
pprint(train_gen.class_indices)
각 데이터들이 번호로 매칭되어 있는 것을 확인합니다. 데이터는 131개의 클래스가 존재하기에, 130번 'Watermelon'까지 존재하는 것을 알 수 있습니다.
preview_batch = train_gen.__getitem__(0)
preview_imgs, preview_labels = preview_batch
plt.title(str(preview_labels[0]))
plt.imshow(preview_imgs[0])
train_gen의 0번째 item을 가져오는 메소드를 입력하여 batch의 preview를 확인합니다. preview_batch는 image와 label로 나뉠 수 있고, 각각을 title과 image로 나타낸 결과입니다.
augmentation을 진행해서 그런지, 이미지가 조금 뒤틀린 형태로 보입니다.
전이 학습 시키기
https://keras.io/api/applications/
전이 학습을 시킬 때에는 이미 학습이 된 pre-trained model을 다운로드 받아서 사용하게 되는데, 이 때 Inception V3 모듈을 이용하여 진행해보겠습니다.
from tensorflow.keras.applications.inception_v3 import InceptionV3
input = Input(shape=(224, 224, 3))
base_model = InceptionV3(weights='imagenet', include_top=False, input_tensor=input, pooling='max')
x = base_model.output
x = Dropout(rate=0.25)(x)
x = Dense(256, activation='relu')(x)
output = Dense(131, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=output)
model.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=0.001), metrics=['acc'])
model.summary()
weight는 imagenet을 학습시킨 모델을 사용하며, include_top을 False로 설정하여 마지막 출력 layer에 있는 것을 우리의 입맛대로 쓰기 위해 버리게 됩니다. 처음에 설정한 input값을 넣어준 뒤, max pooling으로 설정합니다.
출력 layer를 직접 설정해야 하기에, output 설정을 한 후 Dropout, Dense를 설정하여 모델의 네트워크를 구성합니다.
Inception V3는 굉장히 복잡한 형태로 되어있습니다. 많은 양의 layer가 출력된 것을 볼 수 있는데, 여기서 주목해야 할 점은 마지막 출력 layer 부분입니다.
위에서 출력 layer을 버린다고 설정하였기에, 우리가 직접 정의한 dropout과 dense는 따로 출력된 것을 볼 수 있습니다. 이 부분이 전이학습의 큰 장점입니다. imagenet의 weight를 쓴다고 해서 그 weight와 bias를 그대로 두는 것이 아닌 initial weight를 imagenet에서 학습시킨 데이터의 weight를 쓴다는 의미입니다. 그리고 fit을 하게 되면 그 weight와 bias가 완전히 바뀌게 될 것입니다. 그렇기에 initial weight가 굉장히 유리한 위치에서 시작한다고 이해하면 되겠습니다.
- 학습시키기
from tensorflow.keras.callbacks import ModelCheckpoint
# 저장했다가 나중에 씀
history = model.fit(
train_gen,
validation_data=test_gen, # 검증 데이터를 넣어주면 한 epoch이 끝날때마다 자동으로 검증
epochs=20, # epochs 복수형으로 쓰기!
callbacks=[
ModelCheckpoint('model.h5', monitor='val_acc', verbose=1, save_best_only=True)
]
여기서는 학습시킨 모델을 저장했다가 다시 불러오는, keras에서 정의한 callback을 사용하였습니다. ModelCheckpoint에 model.h5라는 파일로 모델의 weight랑 네트워크 구조를 저장하게 되고, save_best_only를 True로 주어 val_acc값 중 가장 높은 값 하나만을 저장하게 됩니다. verbose = 1은 저장하게 되면 출력하라는 의미입니다.
이 부분은 시간이 정말 오래 걸리는 학습입니다. 한 epoch을 도는 데에 15분정도가 걸린 것 같은데, epoch을 20번 돌아야 해서 총 4~5시간 정도가 걸렸네요. 학습시켜놓고 낮잠 자고 오세요.
- 학습 결과 그래프
fig, axes = plt.subplots(1, 2, figsize=(20, 6))
axes[0].plot(history.history['loss'])
axes[0].plot(history.history['val_loss'])
axes[1].plot(history.history['acc'])
axes[1].plot(history.history['val_acc'])
학습 과정을 거친 후 결과 그래프를 보게 되면, loss값은 급격히 떨어지게 되고 acc값은 높은 수치로 증가하는 형태를 볼 수 있습니다. 우리는 이 학습된 모델을 model.h5로 저장을 하였기 때문에, 위와 같은 성능을 보이는 학습된 모델이 local storage에 보이게 될 것입니다. 시간이 많이 소요되는 모델이기에, 이 모델을 따로 저장하여 필요할 때 이를 응용할 수 있게끔 load하는 과정이 필요합니다.
- 학습된 모델 Load
from tensorflow.keras.models import load_model
model = load_model('model.h5')
print('Model loaded!')
Load가 잘 되었다면 'Model loaded!' 라고 출력이 되겠네요.
- 테스트하기
test_imgs, test_labels = test_gen.__getitem__(100)
y_pred = model.predict(test_imgs)
classes = dict((v, k) for k, v in test_gen.class_indices.items())
fig, axes = plt.subplots(4, 8, figsize=(20, 12))
for img, test_label, pred_label, ax in zip(test_imgs, test_labels, y_pred, axes.flatten()):
test_label = classes[np.argmax(test_label)]
pred_label = classes[np.argmax(pred_label)]
ax.set_title('GT:%s\nPR:%s' % (test_label, pred_label))
ax.imshow(img)
위 과정과 유사하게 100번째 item을 불러온 후 이미지 데이터를 predict 한 후, One-Hot-Encoding 되어있는 값들을 다시 class값으로 되돌립니다. 그렇기에 nunmpy의 argmax 메소드를 이용하여 값들을 지정합니다. 인덱스값으로 다시 돌려 놓은 후 클래스의 이름을 뽑아내어 우리가 알 수 있는 영어 용어로 되돌리게 됩니다.
GT는 Ground Truth의 약자인데, 정답값을 의미하고 PR은 Predict, 예측값을 의미합니다. 위 출력값에서 보면 정답값과 예측값이 일치하는 것도 있지만 그렇지 않은 것도 중간중간 존재합니다. 딥러닝 모델이라고 해서 무조건 100%의 정확도가 나오는 것은 아니기 때문입니다.
Transfer Learning을 응용하기 위해서는 batch index를 다양한 값을 넣어주며 테스트하는 과정이 필요합니다. 또한 위에서 사용한 Imagenet V3 뿐만 아니라 ResNet50 model 등 다양한 전이학습 모델이 있기에 여러가지 모델을 사용하여 네트워크를 구성해 보는 것도 방법일 것입니다.
어렵네요.
'Programming > Machine Learning' 카테고리의 다른 글
[Google Cloud] Speech-To-Text의 모델 적응 기능 활용해 STT 성능 높이기 (0) | 2022.10.27 |
---|---|
딥러닝 때려 부수기 - 합성곱 신경망(CNN), 캐글 데이터를 이용한 수화 알파벳(MNIST) 분류 모델 (0) | 2021.08.18 |
딥러닝 때려 부수기 - 신경망 개념&스킬, 캐글 데이터를 이용한 XOR문제 해결 (0) | 2021.08.14 |
머신러닝 때려 부수기 - 캐글 데이터를 이용한 논리 회귀(Logistic Regression), 전처리(Preprocessing) (0) | 2021.08.01 |
머신러닝 때려 부수기 - 캐글 데이터를 이용한 선형 회귀 (Linear Regression) (0) | 2021.07.23 |