Tensorflow 개발자 자격증 준비하기(3)

Tensorflow 개발자 자격증 준비하기(3)

Image Classification

가위바위보 손 사진을 갖고 가위/바위/보자기로 이미지를 분류하는 classification 문제를 풀어보자. 이전과 마찬가지로 이미지 분류 문제입니다.

1. 문제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def solution_model():
url = 'https://storage.googleapis.com/download.tensorflow.org/data/rps.zip'
urllib.request.urlretrieve(url, 'rps.zip')
local_zip = 'rps.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('tmp/')
zip_ref.close()


TRAINING_DIR = "tmp/rps/"
training_datagen = ImageDataGenerator(
# YOUR CODE HERE)

train_generator = # YOUR CODE HERE


model = tf.keras.models.Sequential([
# YOUR CODE HERE, BUT END WITH A 3 Neuron Dense, activated by softmax
tf.keras.layers.Dense(3, activation='softmax')
])

return model

2. 기본 CNN모델 사용

: 케라스 책에 있는 고양이 vs 강아지 기본 분류모델을 사용했다.

[ 데이터 전처리 ]

: 단계는 다음과 같다. ImageGenerator 클래스를 사용한다.

  1. 사진 파일을 읽는다
  2. jpg컨텐츠를 rgb픽셀로 디코딩
  3. 부동소수점 타입의 텐서로 변환
  4. 0 - 255의 픽셀값을 [0, 1] 사이로 조정한다.
    : 신경망은 작은 입력값을 선호한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
training_datagen = ImageDataGenerator(
rescale=1. / 255,
validation_split=0.2
)

train_generator = training_datagen.flow_from_directory(TRAINING_DIR,
target_size=(150, 150),
batch_size=20,
class_mode='categorical',
subset='training',
)

validation_generator = training_datagen.flow_from_directory(TRAINING_DIR,
target_size=(150, 150),
batch_size=20,
class_mode='categorical',
subset='validation',
)
  • rescale=1. / 255 : 모든 이미지를 1/255로 스케일 조정
  • target_size=(150, 150) : 모든 이미지 크기를 150 x 150으로 바꾼다
  • class_mode='categorical' : 다중분류일 경우 categorical, 혹은 sparse 사용. 이진분류는 binary사용.
1
2
3
4
5
6
7
8
model.fit(
train_generator,
steps_per_epoch=len(train_generator),
epochs=30,
validation_data=(validation_generator),
validation_steps=len(validation_generator),
callbacks=[es, mc],
)
  • fit() : 첫번째 매개변수로 python generator를 받는다(ImageGenerator로 생성).
  • steps_per_epoch : 하나의 에포크를 정의하기위해 사용할 배치의 수. 이 값만큼 경사하강법을 실시한다.
    • 여기서 20개의 샘플이 하나의 배치이므로 에포크 하나에서 샘플 2016개가 모두 처리되려면 101개의 배치가 필요하다.
    • 이는 그냥 간단하게 len(train_generator)의 값이다.
  • validation_data : python data generator, 혹은 numpy tuple을 인자로 넘길 수 있다.

![샘플개수와_배치데이터_python_generator_크기](/image/스크린샷 2020-06-22 오전 12.00.50.png)

[ 사용한 모델 ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
model = tf.keras.models.Sequential([
Conv2D(32, (3, 3), padding='same', activation='relu', input_shape=(150, 150, 3)),
MaxPooling2D(2, 2),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D(2, 2),
Conv2D(128, (3, 3), activation='relu'),
MaxPooling2D(2, 2),
Conv2D(128, (3, 3), activation='relu'),
MaxPooling2D(2, 2),
Flatten(),
Dense(512, activation='relu'),
Dense(3, activation='softmax'),
])

model.compile(optimizer=keras.optimizers.RMSprop(lr=1e-4), loss='categorical_crossentropy', metrics=['acc'])

: 결과는 책에서 나온대로 70%대 초반정도의 정확도를 보여줬다. 이때 훈련 정확도와 검증 정확도, 훈련 손실과 검증 손실의 양상은 아래의 이미지와 비슷했다.

훈련정확도와_검증정확도

훈련손실과_검증손실

  • 위의 두 그래프는 과대적합되는 모델의 양상을 보여준다.
    • 훈련 정확도는 선형적으로 증가하여 100%까지 이르렀지만, 검증 정확도는 어느 지점에서 멈춰있다.
    • 훈련 손실은 선형적으로 감소하여 0%까지 이르렀지만, 검증 손실은 선형적으로 증가/변화가 없다.

이러한 Overfitting문제를 컴퓨터 비전분야에서 해결하기 위해 일반적으로 사용하는 Data augumentation(데이터 증식) 방법을 사용해보도록 하자.

3. 데이터 증식 사용

데이터 증식 : 기존 훈련샘플들을 변환함으로서 더 많은 훈련데이터를 생성하여 학습을 위한 샘플의 개수를 늘리는 방법

케라스에서는 ImageDataGenerator에서 이미지를 읽어들일때 여러 랜덤변환을 적용하도록 설정할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
ImageDataGenerator(
rescale=1. / 255,
validation_split=0.2
rotation_range=40, # 랜덤하게 사진을 회전시킬 각도 범위(1-180도)
width_shift_range=0.2, # 사진을 수평으로 랜덤하게 평행이동시킬 범위
height_shift_range=0.2, # 사진을 수직으로 랜덤하게 평행이동시킬 범위
shear_range=0.2, # 랜덤하게 전단변환을 적용할 각도 범위
zoom_range=0.2, # 랜덤하게 사진을 확대할 범위
horizontal_flip=True, # 랜덤하게 이미지를 수평으로 뒤집을지 여부
fill_mode='nearest', # 회전/이동 등으로 새롭게 생성되는 픽셀을 채울 방법
)
  1. 회전각의 범위는 -rotation_range ~ +rotation_range이다
  2. height/width_shift_range는 전체 너비와 높이에 대한 비율값이다.
  3. 전단변환은 rotation_range로 회전할 때 y축 방향으로 각도를 증가시켜 이미지를 변형한다.
  4. horizontal_flip은 수평대칭을 가정할 수 있는 풍경이나 인물사진의 학습에 사용한다. 도로 표지판과 같이 뒤집힌 글씨를 학습시키는건 노노.
  5. fill_mode의 기본값인 nearest인접한 픽셀을 사용한다. 그밖에 constant, reflect, wrap등이 있다.

또한 모델에는 Dense layer직전에 Dropout을 추가한다.

4. 사전 훈련된 컨브넷 사용

완전 사기다 이건ㅋㅋ. 나쁜뜻이 아니라 성능이 너무 극적으로 좋아져서 사기라는 의미다. 실제 시험때 써도 될지 모르겠다.

방법은 그냥 간단하다. 사전 훈련된 합성곱 신경망을 가져와서 내 Dense layer classifier 앞에 넣어준다.

1
2
3
4
5
6
7
from keras.applications.vgg16 import VGG16

conv_base = VGG16(weights='imagenet',
include_top=False,
input_shape=(150, 150, 3))

conv_base.trainable = False # 사전학습된 가중치는 학습하지 않는다.

모델은 아래처럼 간단해진다.

1
2
3
4
5
model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(3, activation='softmax'))
1
2
3
4
Epoch 30/30
101/101 [==============================] - 549s 5s/step - loss: 2.8820e-04 - acc: 1.0000 - val_loss: 1.3292e-05 - val_acc: 0.9881

Epoch 00030: val_acc did not improve from 0.99603

근데 학습시간이 어ㅓㅓ어어ㅓㅓ엄청나게 오래걸린다. 실제로는 못쓸듯…

댓글