딥러닝

[딥러닝] 사람 얼굴 이진 분류 모델 만들기

퓨어맨 2022. 7. 19. 13:43
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from PIL import Image # PIL : 이미지를 불러오게끔 해주는 라이브러리

# convert -> L : 흑백, RGB : 컬러
img = Image.open("/content/drive/MyDrive/Colab Notebooks/빅데이터 13차(딥러닝)/data/Class 1-samples/0.jpg").convert('L')

# numpy 배열로 이미지 데이터를 변환(기계가 인식할 수 있도록 데이터를 수치화 시켜줌)
# 이미지의 크기에 맞게 가로, 세로 픽셀수로 수치화가 됨

img_array = np.array(img)
img_array.shape
(224, 224)

 

# 반복문 실행시 어느정도 실행되고 있는지 %로 알려주는 라이브러리
from tqdm import tqdm

# 학습 데이터셋 구성하기!
class1_list = []   # 첫번째 데이터가 들어갈 자리
class2_list = []   # 두번째 데이터가 들어갈 자리

for i in tqdm(range(0, 200, 1)):
  # 1. 첫번째 데이터 작업
  # 경로와 이름에 맞게 이미지를 가져와서 흑백으로 변환한 후 img1 변수에 담아주기
  img1 = Image.open("/content/drive/MyDrive/Colab Notebooks/빅데이터 13차(딥러닝)/data/Class 1-samples/"+str(i)+".jpg").convert("L")
  # 이미지 데이터가 저장된 img1을 numpy배열로 변환
  img_array1 = np.array(img1)
  # numpy 배열 데이터를 빈 리스트에 하나씩 추가해주기
  class1_list.append(img_array1)

  # 1. 두번째 데이터 작업
  img2 = Image.open("/content/drive/MyDrive/Colab Notebooks/빅데이터 13차(딥러닝)/data/Class 2-samples/"+str(i)+".jpg").convert("L")
  img_array2 = np.array(img2)
  class2_list.append(img_array2)
  
# 리스트 자체도 numpy 배열로 변환
# 사진 하나하나도 numpy배열로, 이를 담은 리스트도 numpy배열로 변환시켜줘야 함(신경망에 들어갈 수 있는 형태로 변경시켜주기 위함!)
class1_numpy = np.array(class1_list)
class2_numpy = np.array(class2_list)

# concatenate : 두 배열을 순서대로 붙여주는 명령
data = np.concatenate((class1_numpy, class2_numpy))

class1_numpy.shape, data.shape # 문제 데이터 생성완료!
((200, 224, 224), (400, 224, 224))

 

# 정답 데이터 만들기(문제와 정답의 순서를 일정하게 맞춰줄 것!)
# 0 : 첫번째 데이터의 정답, 1: 두번째 데이터의 정답
target = np.array([0]*200 + [1]*200)
target
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1])

 

data.shape, target.shape
((400, 224, 224), (400,))

 

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(data, target,
                                                    test_size=0.2,
                                                    random_state=1
                                                    )
                                                    
print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)
(320, 224, 224)
(320,)
(80, 224, 224)
(80,)

 

from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Flatten

# 신경망 구조 설계
model = Sequential()

model.add(Flatten(input_shape=(224,224)))

# input_dim : 입력되는 데이터의 특성 개수를 설정
# activation : 활성화 함수를 설정(들어온 자극(데이터)에 대한 응답여부(예측결과)를 결정하는 함수)
# 입력층(input_dim) + 중간 1개층(Dense)
model.add(Dense(500, input_dim=2, activation='relu'))

# 중간층
model.add(Dense(300, activation='relu'))
model.add(Dense(100, activation='relu'))
model.add(Dense(50, activation='relu'))

# 출력층
model.add(Dense(1, activation='sigmoid'))

model.summary()
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten (Flatten)           (None, 50176)             0         
                                                                 
 dense (Dense)               (None, 500)               25088500  
                                                                 
 dense_1 (Dense)             (None, 300)               150300    
                                                                 
 dense_2 (Dense)             (None, 100)               30100     
                                                                 
 dense_3 (Dense)             (None, 50)                5050      
                                                                 
 dense_4 (Dense)             (None, 1)                 51        
                                                                 
=================================================================
Total params: 25,274,001
Trainable params: 25,274,001
Non-trainable params: 0
_________________________________________________________________

 

 

# 학습 및 평가방법 설정
# binary_crossentropy : 2진분류에 사용하는 손실함수
#  -> 오차의 평균을 구하는 것은 mse와 같지만 0~1사이의 값으로 반환한 후에 평균오차를 구함(그래야 0또는1로 분류하기 편하니까!)
model.compile(loss='binary_crossentropy',
              optimizer='Adam',   # 최적화함수 : 확률적 경사하강법
              metrics=['acc']    # metrics : 평가방법을 설정(분류문제이기 때문에 정확도를 넣어줌)
              )
              
# 학습
h = model.fit(X_train, y_train, 
              validation_split = 0.2, # 위에서 random_state 로 순서를 섞어줌
              epochs=100,
              batch_size=128          # default 값이 32인데 속도를 빠르게 하기위해 128로 설정
              )

# validation_split : 자동으로 train 데이터에서 검증 데이터를 분리시켜주는 명령
# 주의점 : 분리시켜줄 때 뒤에서부터 20%를 잘라줌
#          일정한 값으로 정렬돼 있는 데이터에는 사용할 수 없음
plt.figure(figsize=(15,5))

plt.plot(h.history['acc'], label='acc')

plt.legend()
plt.show

 

plt.figure(figsize=(15,5))

# train 데이터
plt.plot(h.history['acc'],
         label='acc',
         c = 'blue',
         marker='.'
         )

# val 데이터
plt.plot(h.history['val_acc'],
         label='val_acc',
         c = 'red',
         marker='.'
         )

plt.xlabel("epochs")
plt.ylabel("accuracy")

plt.legend()
plt.show()

 

model.evaluate(X_test, y_test)
3/3 [==============================] - 0s 6ms/step - loss: 0.0000e+00 - acc: 1.0000
[0.0, 1.0]