11. 플러터 : 개와 고양이 사진 분류 (케라스) (2)

이전 글에서 정리한 순서대로
하나씩 하나씩 진행해 보도록 한다.


첫 번째로 개와 고양이를 구분하는 케라스 모델을 만든다.
이번 글에서 사용하는 코드는
"케라스 창시자에게 배우는 딥러닝"에서 가져왔다.
내가 할 수도 있겠지만
그런 정도의 정확도로 어찌 블로그에 올릴 수 있겠는가!
"케라스 창시자" 정말 좋은 책이니까
아직 보지 않았다면 꼭 구매하도록 하자.


깃헙에 가면 참고로 했던 소스 코드와 설명을 볼 수 있다.
여러 가지 버전이 있지만,
여기서는 정확도가 중요한 것이 아니기 때문에 첫 번째 버전을 사용하도록 한다.

5.2 - 소규모 데이터셋에서 컨브넷 사용하기
5.3 - 사전 훈련된 컨브넷 사용하기


(음.. 앞의 말은 취소다.
정확도가 안 나오는 걸로 했다가 무지막지하게 고생했다.
가장 좋은 버전을 사용하도록 하겠다.)


학습하고 검사할 개와 고양이 사진이 필요하다.
깃헙에 있는 데이터셋은
2천개의 사진을 같은 폴더에 두었고
이들을 3개의 폴더로 구분해서 저장하는 것부터 시작한다.
굳이 따라할 필요가 없어서
해당 파일을 각각의 폴더에 나누어서 저장한 압축 파일을 사용한다.
압축을 풀어서 파이썬 소스 파일이 있는 폴더로 붙여넣는다.

실패.
파일을 첨부하려고 했더니 용량 제한이 10mb.
압축 파일은 90mb.
할 수 없다. 직접 폴더를 만들고 파일을 복사해야겠다.

깃헙 프로젝트를 다운로드 받는다.
datasets 안에 들어가면 cats_and_dogs/train 폴더가 보인다.

  1. train 폴더와 같은 위치에 small 폴더 생성
  2. small 폴더 안에 train, valid, test 폴더 생성
  3. train, valid, test 폴더 각각에 cats와 dogs 폴더 생성
  4. 원본 파일이 있는 train 폴더의 고양이 사진 처음 1,000개를 small/train/cats 폴더로 복사
  5. 원본 파일이 있는 train 폴더의 개 사진 처음 1,000개를 small/train/dogs 폴더로 복사
  6. valid와 test 폴더에는 각각 500개씩 복사
  7. 파이썬 소프 파일이 있는 폴더로 cats_and_dogs 폴더 붙여넣기

폴더 생성 및 복사가 끝나면 아래와 같은 모습이 되어야 한다.
사진이 큼지막한게 보기가 아주 좋다. 시원하다.


여기서부터 이전 글에서 언급했던 순서대로 시작이다.


1번
먼저 모델을 생성해서 파일로 저장하는 코드다.
이번 코드에는 주석을 붙이지 않았다.
프로젝트의 목적이 플러터에서 이미 분류 모델을 구동하는 것이지
모델 자체를 설명하는 것이 아니니까.
설명이 필요하면 앞에서 언급한 깃헙 파일을 보도록 한다.


def save_model(model_path, train_path, valid_path):
# 이미지넷에서 가져온 사전 학습한 가중치는 수정하면 안됨
conv_base = tf.keras.applications.VGG16(weights='imagenet', include_top=False, input_shape=[150, 150, 3])

model = tf.keras.models.Sequential()
model.add(conv_base) # 기존 모델 연결
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(512, activation='relu'))
model.add(tf.keras.layers.Dropout(rate=0.5))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))

# 전체 동결. 이미지넷에서 가져온 사전 학습한 가중치는 수정하면 안됨
conv_base.trainable = False

model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=0.0001),
loss='binary_crossentropy',
metrics=['acc'])

# 학습 데이터 증강
train_img_generator = tf.keras.preprocessing.image.ImageDataGenerator(
rescale=1/255,
rotation_range=20,
width_shift_range=0.1,
height_shift_range=0.1,
shear_range=0.1,
zoom_range=0.1,
horizontal_flip=True)
# 검증 제너레이터는 이미지 증강하면 안됨.
valid_img_generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1/255)

batch_size = 32
train_generator = train_img_generator.flow_from_directory(
train_path,
target_size=[150, 150],
batch_size=batch_size,
class_mode='binary')
valid_generator = valid_img_generator.flow_from_directory(
valid_path,
target_size=[150, 150],
batch_size=batch_size,
class_mode='binary')

# 20회 에포크만큼 학습
model.fit_generator(train_generator,
steps_per_epoch=1000 // batch_size,
epochs=20,
validation_data=valid_generator,
validation_steps=50)

# hdf5 형식 : Hierarchical Data Format version 5
model.save(model_path)


model_path = 'models/cats_and_dogs_small.h5'
save_model(model_path, 'cats_and_dogs/small/train', 'cats_and_dogs/small/valid')


데스크탑을 우재와 서진이가 사용하고 있는 관계로
맥북에서 돌리고 있는데.. 4시간은 걸리는 것 같다.
그래서, 내가 만든 모델 파일을 첨부하려고 했다.
10mb 용량 제한에 걸렸다.
우재야 미안하다. 직접 만들어야겠다.


모델을 저장했다면 잘 동작하는지 확인할 차례다.
모델을 로딩해서 정확도를 확인해 본다.


def load_model(model_path, test_path):
model = tf.keras.models.load_model(model_path)

generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1/255)

test_gen = generator.flow_from_directory(test_path,
target_size=[150, 150],
batch_size=500,
class_mode='binary')

# 첫 번째 배치 읽기. batch_size가 500이니까 500개 가져옴
x, y = next(test_gen)
print('acc :', model.evaluate(x, y))


load_model(model_path, 'cats_and_dogs/small/test')


아쉽지만, 정확도는 그리 잘나오는 편은 아니다.
여러 가지 버전 중에서 첫 번째 버전을 선택했으니까.
손실 값은 0.58, 정확도는 72.8% 나왔다.

acc : [0.5835418028831482, 0.728]


2번
마지막으로 저장한 모델 파일을 텐서플로 라이트 버전으로 변환한다.
변환은 늘 그렇듯이 이전 글에 나왔던 코드를 붙여넣어서 사용한다.


# 저장한 파일로부터 모델 변환 후 다시 저장
def convert_model(model_path, tflite_path):
converter = tf.lite.TFLiteConverter.from_keras_model_file(model_path)
flat_data = converter.convert()

with open(tflite_path, 'wb') as f:
f.write(flat_data)


convert_model('models/cats_and_dogs_small.h5', 'models/cats_and_dogs.tflite')


이걸로 파이썬 기반으로 작업할 내용은 모두 끝났고
여기서 만든 모델 파일을 안드로이드에서 사용할 것이다.