앞선 게시글에서는 이미지의 모든 픽셀을 신경망으로 보내는 실습을 했는데 이번 게시글에서는 이미지의 특성을 추출해 신경망으로 보내는 실습을 하고자 한다.
즉 Feature extractor 생성이 가장 큰 특징이라고 볼 수 있다.
데이터는 앞선 게시글과 같은 캐릭터 이미지를 활용했다.
먼저 필요한 라이브러리를 임포트
import cv2
import numpy as np
import os
import zipfile
from google.colab.patches import cv2_imshow
import tensorflow as tf
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt #그래프
다음은 전체 이미지에서 픽셀을 추출한다.
구글 드라이브에 마운트해 데이터를 가져온다.
#구글 드라이브 연결
from google.colab import drive
drive.mount('/content/drive')
path = '/content/drive/MyDrive/데이터파일.zip'
zip_object = zipfile.ZipFile(file = path, mode = 'r') #read모드
zip_object.extractall('./')
zip_object.close()
directory = '/content/homer_bart_1'
files = [os.path.join(directory, f) for f in sorted(os.listdir(directory))]
print(files)
새로운 변수를 생성해 각 특성의 이름을 입력한다. (해당 특성들은 파일의 헤더가 됨)
export = 'mouth,pants,shoes,tshirt,shorts,sneakers,class\n'
색상과 관련한 숫자를 입력할 features 변수를 생성한다.
show_images = False
features = []
각각의 이미지 확인
for image_path in files:
#각 이미지 로드
try:
original_image = cv2.imread(image_path)
(H, W) = original_image.shape[:2] #높이, 너비까지만 사용 채널X
except:
continue
image = original_image.copy()
image_features = []
mouth = pants = shoes = 0
tshirt = shorts = sneakers = 0
image_name = os.path.basename(os.path.normpath(image_path))
#클래스 정의
if image_name.startswith('b'):
class_name = 0
else:
class_name = 1
#각각의 픽셀 살펴보기
for height in range(0, H):
for width in range(0, W):
#세가지 색 채널 BGR
blue = image.item(height, width, 0)
green = image.item(height, width, 1)
red = image.item(height, width, 2)
# Homer - brown mouth 첫번째 특성
if (blue >= 95 and blue <= 140 and green >= 160 and green <= 185 and red >= 175 and red <= 200):
image[height, width] = [0, 255, 255] #brown mouth를 노란색으로 변경
mouth += 1
# Homer - blue pants 두번째 특성
if (blue >= 150 and blue <= 180 and green >= 98 and green <= 120 and red >= 0 and red <= 90):
image[height, width] = [0, 255, 255]
pants += 1
# Homer - gray shoes 세번째 특성
if height > (H / 2): #이미지 하단부분만 활용
if (blue >= 25 and blue <= 45 and green >= 25 and green <= 45 and red >= 25 and red <= 45):
image[height, width] = [0, 255, 255]
shoes += 1
# Bart - orange t-shirt 첫번째 특성
if (blue >= 11 and blue <= 22 and green >= 85 and green <= 105 and red >= 240 and red <= 255):
image[height, width] = [0, 255, 128]
tshirt += 1
# Bart - blue shorts 두번째 특성
if (blue >= 125 and blue <= 170 and green >= 0 and green <= 12 and red >= 0 and red <= 20):
image[height, width] = [0, 255, 128]
shorts += 1
# Bart - blue sneakers 세번째 특성
if height > (H / 2): #이미지 하단부분만 활용
if (blue >= 125 and blue <= 170 and green >= 0 and green <= 12 and red >= 0 and red <= 20):
image[height, width] = [0, 255, 128]
sneakers += 1
#이미지의 총 픽셀 수로 특성을 정규화
mouth = round((mouth / (H * W)) * 100, 9)
pants = round((pants / (H * W)) * 100, 9)
shoes = round((shoes / (H * W)) * 100, 9)
tshirt = round((tshirt / (H * W)) * 100, 9)
shorts = round((shorts / (H * W)) * 100, 9)
sneakers = round((sneakers / (H * W)) * 100, 9)
image_features.append(mouth)
image_features.append(pants)
image_features.append(shoes)
image_features.append(tshirt)
image_features.append(shorts)
image_features.append(sneakers)
#클래스 추가
image_features.append(class_name)
#특성목록에 추가
features.append(image_features)
#print('Homer mouth: %s - Homer pants: %s - Homer shoes: %s' % (image_features[0], image_features[1], image_features[2]))
#print('Bart t-shirt: %s - Bart shorts: %s - Bart sneakers: %s' % (image_features[3], image_features[4], image_features[5]))
#string으로 연결
f = (",".join([str(item) for item in image_features]))
export += f + '\n'
if show_images == True:
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) #opencv의 채널은 BGR 순서기때문에 이미지를 보려면 RGB로 변환해야한다.
original_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2RGB)
fig, im = plt.subplots(1, 2)
im[0].axis('off')
im[0].imshow(original_image)
im[1].axis('off')
im[1].imshow(image)
plt.show()
모든 특성 확인하기.
export
특성 결과 csv 로 저장하기.
with open('features.csv', 'w') as file:
for l in export:
file.write(l)
#파일이 제대로 생성되고 닫혔는지 확인
file.closed
결과가 참이면 True 가 리턴 되고 features.csv 가 생성된다 (해당 경우는 구글 드라이브에 데이터 마운트 해두었어서 거기 경로에 생성됨)
데이터셋 변수를 생성해 해당 데이터 파일을 확인한다.
dataset = pd.read_csv('features.csv')
dataset
다음으로 학습셋과 검증셋을 만들어준다.
#8:2 비율로 사용
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 1)
학습, 검증 데이터의 shape 확인
X_train.shape, y_train.shape
결과로 ((215,6) (215,)) 를 확인 할 수 있다.
X_test.shape, y_test.shape
결과로 ((54,6) (54,)) 를 확인 할 수 있다.
다음으로 신경망을 구현한다.
# 뉴런 수 : 6 -> 4 -> 4 -> 4 -> 1
network2 = tf.keras.models.Sequential()
#Bart 특성 세개, Homer 특성 세개 = 6
network2.add(tf.keras.layers.Dense(input_shape = (6,), units = 4, activation='relu'))
#입력값 6 + 출력값 2(클래스개수) / 2 = 4
network2.add(tf.keras.layers.Dense(units = 4, activation='relu'))
network2.add(tf.keras.layers.Dense(units = 4, activation='relu'))
network2.add(tf.keras.layers.Dense(units = 1, activation='sigmoid'))
신경망(네트워크) 확인하기.
network2.summary()
모델 컴파일 진행.
network2.compile(optimizer='Adam', loss='binary_crossentropy', metrics = ['accuracy'])
history = network2.fit(X_train, y_train, epochs = 50)
history.history.keys()
리턴 값으로 dict_keys(['loss', 'accuracy']) 를 확인할 수 있다.
먼저 손실값을 시각화해본다.
plt.plot(history.history['loss']);
에포크 수에 비례해서 손실이 줄어듦을 볼 수 있다.
다음으로는 정확도를 시각화한다.
plt.plot(history.history['accuracy']);
에포크 수에 비례해서 정확도가 증가함을 볼 수 있다.
모델학습이 완료되었으니 X 검증 데이터셋을 이용해 모델을 평가한다.
predictions = network2.predict(X_test)
predictions
각 확률값으로 리턴 되므로 임계값을 정의해서 클래스로 변환 시켜준다.
predictions = (predictions > 0.5)
predictions
해당 결과를 기대출력과 비교해본다.
y_test
sklearn 을 이용해 비교값의 정확도를 확인해본다.
from sklearn.metrics import accuracy_score
accuracy_score(y_test, predictions)
이전 게시글에서 전체 픽셀로 비교했을때는 0.68을 기록했었는데 특성만 추출해서 진행하는 이번 실습이 약 20%정도 성능이 좋음을 볼 수 있다!
오차행렬 생성을 위해 변수를 생성해준다.
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, predictions)
히트맵으로 시각화를 진행한다.
sns.heatmap(cm, annot=True);
클래스 0은 Bart를 의미하고, 22개 이미지들이 정확하게 Bart로 분류되었고 6개가 Homer로 잘못분류되었음을 의미한다.
클래스 1은 Homer를 의미하고, 26개 이미지들이 정확하게 Homer로 분류되었고 0개가 Bart로 잘못분류되었음을 의미한다.(다맞았네)
다음으로 각 클래스별로 분석해본다.
from sklearn.metrics import classification_report
print(classification_report(y_test, predictions))
분석결과로는
클래스 0인 Bart 이미지에 대해 recall 0.79 로 신경망이 79%를 식별해내면서, 그에 대한 정확도 precision은 100%를 기록했고,
클래스 1인 Homer 이미지에 대해 recall 1.0 으로 신경망이 100%를 식별해내면서, 그에 대한 정확도 precision은 81%를 기록하였다.
이후 모델을 저장하고 필요 시 로드하면서 사용하면 된다.
먼저 위 모델을 저장한다.
model_json = network2.to_json()
with open('network2.json','w') as json_file:
json_file.write(model_json)
from keras.models import save_model
network2_saved = save_model(network2, '/content/weights2.hdf5')
로드한다.
with open('network2.json', 'r') as json_file:
json_saved_model = json_file.read()
json_saved_model
network2_loaded = tf.keras.models.model_from_json(json_saved_model)
network2_loaded.load_weights('weights2.hdf5')
network2_loaded.compile(loss = 'binary_crossentropy', optimizer='Adam', metrics=['accuracy'])
로드한 모델을 확인한다.
network2_loaded.summary()
테스트 데이터 구조를 확인한다.
test_image = X_test[0]
test_image.shape
(6,) 결과를 확인할 수 있는데, 벡터의 크기와 동일하지만 배치 형식에 맞추기 위해 이미지를 재구성해줘야한다.
test_image = test_image.reshape(1,-1)
test_image.shape
(1,6) 결과를 확인할 수 있다.
모델 예측(predict)진행.
#network2_loaded.predict(test_image) 행렬 형식이므로 [0][0]으로 출력값 확인
network2_loaded.predict(test_image)[0][0]
#클래스 따라 분류되어 출력되도록 분기
if network2_loaded.predict(test_image)[0][0] < 0.5:
print('Bart')
else:
print('Homer')
.
'스터디 > AI' 카테고리의 다른 글
[이론/Imple] Variational autoencoder, VAE 변이형 오토인코더 2 (0) | 2024.04.30 |
---|---|
[이론/Imple] Variational autoencoder, VAE 변이형 오토인코더 1 (1) | 2024.04.28 |
[Imple] 캐릭터 분류를 위한 컴퓨터비전 신경망 예제(Neural network for image classification) (0) | 2023.05.25 |
[이론/Imple] Object Tracking 객체 트래킹 (0) | 2023.05.03 |
[이론/Imple] Face Recognition 얼굴 인식 (1) | 2023.05.03 |