이번 포스팅에서는 캔, 페트병, 종이컵의 custom data를 이용한
전이 학습 transfer learning을 진행해 보려고 합니다
transfer learning에 대해서는 정말 좋은글이 많기 때문에...
https://jeinalog.tistory.com/m/13
Transfer Learning|학습된 모델을 새로운 프로젝트에 적용하기
#Transfer Learning #전이학습 #CNN #합성곱 신경망 #Image Classification #이미지 분류 이 글은 원작자의 허락 하에 번역한 글입니다! 중간 중간 자연스러운 흐름을 위해 의역한 부분들이 있습니다. 원 의미
jeinalog.tistory.com
개인적으로 가장 잘 정리되어있는 글이었습니다
전이학습의 포인트는 기존에 학습되어 있는 모델을 가지고 자신의 모델을 학습 키시는 것인데
여기서 원래 학습되어있는 부분을 무너트리지 않는 선에서 미세조정을 해야한다는 것입니다
저의 경우 데이터는 적지만 모델이 어느정도 유사성이 있다고 판단하였고
특징을 추출하는 convolution base 부분은 전부 동결시키고
이미지 분류를 실시하는 Classifier 부분만 학습을 진행할 예정입니다
진행을 위해 224*224의 gray scale 이미지 1860장을 수집하였고
1650 장을 training + validation data
210 장을 test data로 이용하였습니다
모든 이미지를 물체가 중앙에 오도록 전처리하였습니다
전처리를 진행할 때 생각해 두셔야 하는 것이
이 모델을 실제로 써야 할 때 역시 같은 방법으로 전처리를 해야 한다는 것입니다
전처리 과정은 이 쪽
pre-trained model로는 DenseNet201
가중치는 imagenet을 이용하였습니다
사용한 버전
- tensorflow = 2.2.0
import tensorflow as tf
size = (224, 224, 3)
base_model = tf.keras.applications.DenseNet201(
include_top=False,
pooling='None',
weights='imagenet',
input_shape=size,
)
# base_model.summary()
pre-trained model 가져오기
summary() 이용해서 모델 구성 확인 가능 (너무 길다)
import tensorflow as tf
from tensorflow.keras import models, layers
model = models.Sequential()
model.add(base_model)
model.add(layers.Flatten(name='Flatten'))
model.add(layers.Dense(256, activation='relu', name='Dense_1'))
model.add(layers.Dropout(0.5, name='Dropout'))
model.add(layers.Dense(3, activation='softmax', name='Dense_2'))
model.summary()
print(len(model.trainable_weights))
base_model.trainable = False
print(len(model.trainable_weights))
606
4
pre-trained model 부분만 동결시키기
직접 추가한 Fully Conected layer 만 남은 것을 알 수 있습니다
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import os
import numpy as np
Path = "경로설정"
imageGenerator = ImageDataGenerator(
rescale=1./255,
validation_split=0.2,
rotation_range=30,
zoom_range=[1.0,1.4],
shear_range=0.1,
brightness_range=[0.9,1.2],
horizontal_flip=True,
vertical_flip=True,
fill_mode='nearest',
)
trainGen = imageGenerator.flow_from_directory(
os.path.join(Path, 'training_set'),
target_size=size[0:1],
shuffle=False,
subset='training'
)
validationGen = imageGenerator.flow_from_directory(
os.path.join(Path, 'training_set'),
target_size=size[0:1],
shuffle=False,
subset='validation'
)
x_train=np.concatenate([trainGen.next()[0] for i in range(trainGen.__len__())])
y_train=np.concatenate([trainGen.next()[1] for i in range(trainGen.__len__())])
x_val=np.concatenate([validationGen.next()[0] for i in range(validationGen.__len__())])
y_val=np.concatenate([validationGen.next()[1] for i in range(validationGen.__len__())])
import matplotlib.pyplot as plt
num_sample = 3
random_idxs = np.random.randint(trainGen.samples, size=num_sample)
def Trash(label):
if label == 0: trash = 'can'
elif label == 1: trash = 'paper'
else: trash = 'plastic'
return trash
plt.figure(figsize=(num_sample*3, num_sample*2))
for i, idx in enumerate(random_idxs):
img = x_train[idx, :]
label = y_train[idx]
plt.subplot(1, len(random_idxs), i+1)
plt.imshow(img)
label_num = np.argmax(label)
trash = Trash(label_num)
plt.title("Index: {}, Label: {}".format(idx, trash))
training data 에서 랜덤 하게 3가지를 확인할 수 있습니다
셀을 반복 실행하면 다른 값도 볼 수 있어요
from tensorflow.keras import optimizers
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
model.compile(loss='categorical_crossentropy',
optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
metrics=['acc'])
early_stopping = EarlyStopping(patience=3, monitor='val_loss',
restore_best_weights=True)
optimizer는 안정적인 학습을 위해 SGD를 사용하였고
이미 학습이 되어있는 부분을 망치지 않기 위해 작은 learning rate를 사용하였습니다
또한 과적합이 되는 것을 방지하기 위해 EarlyStopping을 이용하여 val_loss가 3번 이상 나아지지 않으면 학습을 중단시키도록 하였습니다
베스트 모델을 저장시키는 ModelCheckpoint를 사용하셔도 좋습니다
epochs = 20
history = model.fit(x_train, y_train,epochs=epochs,
validation_data=(x_val, y_val),
callbacks=[early_stopping]
)
...
13 epoch 째 이후 3번 이상 더 나아지지 않아 학습이 중단되었습니다
history.history.keys()
dict_keys(['loss', 'acc', 'val_loss', 'val_acc'])
import matplotlib.pyplot as plt
history_dict = history.history
loss = history_dict['loss']
val_loss = history_dict['val_loss']
epochs = range(1, len(loss)+1)
fig = plt.figure(figsize=(12, 6))
ax1 = fig.add_subplot(1, 2, 1)
ax1.plot(epochs, loss, color='blue', label='train_loss')
ax1.plot(epochs, val_loss, color='red', label='val_loss')
ax1.set_title('Train ans Validation loss')
ax1.set_xlabel('Epochs')
ax1.set_ylabel('loss')
ax1.grid()
ax1.legend()
accuracy = history_dict['acc']
val_accuracy = history_dict['val_acc']
ax2 = fig.add_subplot(1, 2, 2)
ax2.plot(epochs, accuracy, color='blue', label='train_accuracy')
ax2.plot(epochs, val_accuracy, color='red', label='val_accuracy')
ax2.set_title('Train ans Validation Accuracy')
ax2.set_xlabel('Epochs')
ax2.set_ylabel('Accuracy')
ax2.grid()
ax2.legend()
plt.show()
확실히 transfer learning을 이용하니 초반부터 높은 정확도와 낮은 손실이 나옴을 볼 수 있습니다
testGenerator = ImageDataGenerator(
rescale=1./255
)
testGen = testGenerator.flow_from_directory(
os.path.join(Path, 'test_set'),
target_size=size[0:1],
shuffle=False,
)
x_test=np.concatenate([testGen.next()[0] for i in range(testGen.__len__())])
y_test=np.concatenate([testGen.next()[1] for i in range(testGen.__len__())])
test data 가져오기
model.evaluate(x_test, y_test)
7/7 [==============================] - 19s 3s/step - loss: 0.0778 - acc: 0.9619
[0.07779338210821152, 0.961904764175415]
96%의 정확도가 나왔습니다 와!
num_sample = 3
random_idxs = np.random.randint(teatGen.samples, size=num_sample)
plt.figure(figsize=(num_sample*3, num_sample*2))
for i, idx in enumerate(random_idxs):
img = x_test[idx, :]
label = y_test[idx]
pred_ysi = model.predict(x_test[random_idxs])
arg_pred_yi = np.argmax(pred_ysi, axis=1)
lab_trash = Trash(np.argmax(label))
pred_trash = Trash(arg_pred_yi[i])
plt.subplot(1, len(random_idxs), i+1)
plt.imshow(img)
plt.title("Label: {}, pred: {}".format(lab_trash, pred_trash))
test data 에서 랜덤 하게 3가지를 예측하고 정답과 함께 출력합니다
셀을 반복 실행하면 다른 값을 볼 수 있습니다
우측과 같이 틀린 예측도 있음을 볼 수 있습니다
y_true = np.argmax(y_test, axis=-1)
pred_ys = model.predict(x_test)
y_pred = np.argmax(pred_ys, axis=-1)
def Labels(num_list):
label_list = []
for num in num_list:
if num==0:
label_list.append('can')
elif num==1:
label_list.append('paper')
else:
label_list.append('plastic')
return label_list
y_true = Labels(y_true)
y_pred = Labels(y_pred)
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
plt.figure(figsize=(9, 9))
cm = confusion_matrix(y_true, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.xlabel('predicted Label')
plt.ylabel('True Label')
plt.show()
0 == can
1 == paper
2 == plastic
confusion matrix는 다음과 같이 그려졌습니다
클래스당 70개의 test data 이니
캔은 모두 정확히 판단 하였는데
페트병을 캔으로 인식한 error가 많네요
model.save('recycling_model.h5')
모델 저장하기~
'딥러닝 > tensorflow' 카테고리의 다른 글
predict? predict_classes? 단일이미지 예측 하기 (0) | 2021.08.13 |
---|---|
tensorflow 모델과 webcam을 이용한 Classification (0) | 2021.08.12 |
이미지 전처리, 증폭에 사용하는 ImageDataGenerator (0) | 2021.07.31 |
개와 고양이 데이터를 이용한 CNN Classification (0) | 2021.07.31 |
MNIST손글씨 데이터를 이용한 Classification (0) | 2021.07.30 |