본문 바로가기
기계학습/이미지 머신러닝

남자 여자 판독기 - CNN 모델

by tryotto 2020. 2. 25.

이번에는 남녀 판독기를 만들어보았다.

정확도 부분에서 좀 아쉽다.

왜 실제 이미지에서는 제대로 힘을 발휘하지 못하는지.. 아쉽다


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 데이터를 담을 list 선언
 
train_data = []
 
 
# trainning data set 을 만드는 함수 정의
import cv2 
import numpy as np
 
def make_train_set(sex, root, file_type, num_img):  
  for idx in range(1, num_img):
    if idx<10:
      idx = '00'+str(idx)
    elif idx<100:
      idx = '0'+str(idx)
    else:
      idx = str(idx)
 
    path = root+idx+file_type
    img = cv2.imread(path)
 
    if img is not None:
      train_data.append([img[:224,:224,:], np.array(sex)])
 
cs

- 훈련 데이터 셋을 만들어주는 함수를 선언했다.

- 이전 프로젝트와는 달리, 이미지 크기 조절을 받자마자 해줬기 때문에 코드 길이가 줄어들었다.
또한, 함수로 만들어줘서 가독성을 좋게 만들어주었다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 여자 연예인 사진 가져오기 (1) - 로제, 여자 라벨=0
make_train_set(0, '/content/drive/My Drive/로제___Google_검색/pic_', '.jpg', 100)
 
# 여자 연예인 사진 가져오기 (2) - 지수, 여자 라벨=0
make_train_set(0, '/content/drive/My Drive/지수_블랙핑크___Google_검색/pic_', '.jpg', 100)
 
# 여자 연예인 사진 가져오기 (2) - 여자 연예인, 여자 라벨=0
make_train_set(0, '/content/drive/My Drive/cat-and-dog/여자_연예인___Google_검색/pic_', '.jpg', 100)
 
 
# 남자 연예인 사진 가져오기 (1) - 임시완, 남자 라벨=1
make_train_set(1, '/content/drive/My Drive/임시완_얼굴___Google_검색/pic_', '.jpg', 200)
 
# 남자 연예인 사진 가져오기 (2) - 강동원, 남자 라벨=1
make_train_set(1, '/content/drive/My Drive/강동원_얼굴___Google_검색/pic_', '.jpg', 40)
 
# 남자 연예인 사진 가져오기 (3) - 정우성, 남자 라벨=1
make_train_set(1, '/content/drive/My Drive/정우성_얼굴___Google_검색/pic_', '.jpg', 130)
 
 
cs

- 이런식으로 해서, 훈련 데이터를 만들어주었다.

- 이 부분에서 잘못 훈련된 것 같다.
훈련 데이터들이 괜찮아야지 테스트 데이터에서도 제대로 작동하는데,
훈련 데이터에서는 성능이 좋음에도 불구하고 테스트 데이터에서는 잘못 작동했다.
오버피팅이 일어나지 않았나 싶다.

- 훈련 데이터 양을 늘리고싶지만, 더 이상의 노동은 별로 하고싶지 않고,
별 다른 방법이 없다.

- 다른 블로그에서 봤던 내용처럼, 아무래도 사진의 배경이 뚜렸한 경우에는 잘 못 훈련되도록 유도하는 것 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 섞기
import random
 
train_data = np.array(train_data)
random.shuffle(train_data)
train_data = train_data.tolist()
 
 
 
# train_X, train_Y 따로 만들어주기
 
train_X, train_Y = zip(*train_data)
 
train_X = np.array(train_X)
train_Y = np.array(train_Y)
 
cs

- 데이터를 섞어주었다.

- 이전 프로젝트와는 달리, 이번에는 y 데이터를 원핫 처리 하지 않았다.
그 이유는 다음 코드를 보면서 설명하겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 모델 설계하기
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten, Conv2D
 
model = Sequential()
model.add(Conv2D(filters=64, kernel_size=3, activation='relu', input_shape=(224,224,3)))
model.add(Conv2D(filters=32, kernel_size=3, activation='relu'))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
 
 
 
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
model.fit(x=train_X, y=train_Y, batch_size=50, epochs=5)
 
cs

- 맨 마지막 layer 에서, 출력값이 1차원이며 활성화 함수를 시그모이드로 설정했다.
따라서, 남자인지 여자인지를 확률적으로 계산해 출력하겠다는 것이다.

- 원핫 처리를 할 경우엔, 각 값이 너무 작게 나와서 눈에 보기 쉽지 않았기에 이런 선택을 했다.


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
# 테스트 케이스 실험해보기 함수 정의
import matplotlib.pyplot as plt
 
def test_case(sex, path):
  img = cv2.imread(path)
  photo_img = img
 
  img = np.array(img[:224, :224, :])
  img = img.reshape(-12242243)
 
  probability = model.predict(x=img)
  
  if probability < 0.5:
    print("predict : 여자다!")
  else:
    print("predict : 남자다!")
  print("accuracy : ", probability[0][0]*100,"%")
 
  if sex == 0:
    print("real value : 여자임")
  else:
    print("real value : 남자임")
  
  plt.imshow(cv2.cvtColor(photo_img, cv2.COLOR_BGR2RGB))
 
 
 
 
cs

- 테스트 케이스에도 제대로 작동하는지를 판별하기 위한 함수다.

- 확률 값이 1/2보다 작으면 여자, 크면 남자라고 설정했다.

- 원본 사진을 색상 문제 없이 출력해주기 위해 cv2.cvtColor() 함수를 사용해 주었다.






>> 이 두 사진만 봤을때는 엄청 잘 훈련된 모델이라고 생각했는데...
다른 사진들에 적용해보니 정확도가 너무 낮았다.
훈련이 잘 안 된 것 같다.......




# 총평

- 이진 분류 문제는 이 코드를 그대로 사용만 해도 풀리는 것 같다.
다른 실습을 할때도 이 코드를 활용하도록 하자

- 문제는, 제대로 된 훈련 데이터를 얻는 것이다.
어디서 그런 데이터를 얻어야 하는 것일까
대가리 아프다 


'기계학습 > 이미지 머신러닝' 카테고리의 다른 글

MNIST 실습 - GAN  (0) 2020.02.11
MNIST 실습 - CNN 모델  (0) 2020.02.10
MNIST - 일반 딥러닝 모델  (0) 2020.02.09
MNIST - 기본 1 layer 머신러닝  (0) 2020.02.08