반응형
이미지 크롤링
# !pip install selenium
from selenium import webdriver as wb # 브라우저를 조작하는 도구
from selenium.webdriver.common.keys import Keys # 키 입력을 도와주는 도구(키보드)
from bs4 import BeautifulSoup as bs # 문서를 파싱해서 선택자 활용을 도와주는 도구
from tqdm import tqdm # 반복문 진행 정도를 시각화해주는 도구
from urllib.request import urlretrieve # 이미지 다운로드를 도와주는 도구
import time # 시간제어 도구
import os # 폴더 생성,삭제,이동 등을 도와주는 도구
keyword = "수달"
# 이미지가 저장될 폴더 생성
# 해당 폴더가 있는지 확인
if os.path.isdir('./{}'.format(keyword)) == False :
os.mkdir('./{}'.format(keyword)) # 폴더 생성
url = 'https://www.google.com/search?q={}&source=lnms&tbm=isch&sa=X&ved=2ahUKEwjs85-GsN7vAhX4xYsBHR6aBg0Q_AUoAXoECAEQAw&biw=1745&bih=852'.format(keyword)
driver = wb.Chrome() # 브라우져 생성
driver.get(url) # url 요청
time.sleep(5) # 페이지 로딩까지 5초 대기
cnt = 0
pre_img_src = [] # 이전에 다운로드된 경로
for j in range(10) :
img_html = bs(driver.page_source,'html.parser')
# 이미지 태그 수집
images = img_html.select('img.rg_i.Q4LuWd')
# 이미지 태그의 src 속성 값 추출
img_src = []
for img in images :
src = img.get('src')
if src != None : # img 태그에 src 속성이 없는 경우
if src not in pre_img_src : # 이전에 다운로드한 경로에 있는지 검사
img_src.append(src)
else : # img 태그에 src 속성이 있는 경우
src = img.get('data-src')
if src not in pre_img_src :
img_src.append(src)
# 파일 다운로드
# img_src를 반복문으로 돌면서 저장, tqdm 사용
for src in tqdm(img_src) :
cnt += 1
try :
urlretrieve(src,'./{}/{}.png'.format(keyword,cnt))
except :
print("수집불가")
continue
pre_img_src += img_src # 다운로드한 경로를 이전 리스트에 추가
# 화면 스크롤
for i in range(6):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# driver.find_element_by_css_selector('body').send_keys(Keys.PAGE_DOWN)
time.sleep(1)
이미지 데이터 전처리
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from PIL import Image
# os : 파일 및 폴더 처리에 관련된 라이버르리
import os
# 각 폴더별 경로 지정
procyonoides_dir = '너구리/'
suricatta_dir = '미어캣/'
otter_dir = '수달/'
# os.listdir : 해당 경로에 있는 파일명들을 리스트로 순서대로 저장
procyonoides_fnames = os.listdir(Nyctereutes_dir)
suricatta_fnames = os.listdir(suricatta_dir)
otter_fnames = os.listdir(otter_dir)
otter_fnames
#os.path.join : 폴더 경로와 파일명을 결합
test_path = os.path.join(procyonoides_dir,procyonoides_fnames[50] )
test_path
'너구리/144.png'
# 이미지를 로딩하는 함수(데이터로드, 파일 오픈 및 사이즈 조정, 배열로 변경)
def load_images(folder_path, file_names, img_size_shape=(224,224)):
images = []
for i in file_names:
# 폴더 경로 + 파일명 합치기
path = os.path.join(folder_path, i)
# 파일 오픈 및 크기 조정(resize: 파일 형태(사이즈)를 변경)
img = Image.open(path).resize(img_size_shape).convert('RGB')
# numpy배열로 변경후에 리스트에 저장
images.append(np.array(img))

# 리스트 자체도 numpy배열로 변경해서 반환
return np.array(images)
train_procyonoides = load_images(procyonoides_dir,procyonoides_fnames)
train_suricatta = load_images(suricatta_dir, suricatta_fnames)
train_otter = load_images(otter_dir, otter_fnames)
print(train_procyonoides.shape)
print(train_suricatta.shape)
print(train_otter.shape)
(400, 224, 224, 3)
(400, 224, 224, 3)
(400, 224, 224, 3)
X = np.concatenate([train_procyonoides, train_suricatta, train_otter])
y = np.array([0]*400+[1]*400+[2]*400)
print(X.shape)
print(y.shape)
(1200, 224, 224, 3)
(1200,)
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=11)
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)
(960, 224, 224, 3)
(240, 224, 224, 3)
(960,)
(240,)
NPZ파일로 변환(Numpy Zip)
- 압축된 배열 파일로 데이터를 변환
np.savez_compressed('animals.npz', # 저장될 폴더 경로 및 파일명 설정
X_train = X_train,
X_test = X_test,
y_train = y_train,
y_test = y_test)
목표
- 크롤링한 3종류의 이미지 데이터를 분류하는 신경망 모델을 만들어보자
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import fashion_mnist
data = np.load("/content/drive/MyDrive/Colab Notebooks/빅데이터 13차(딥러닝)/Data/animals.npz")
X_train = data['X_train']
X_test = data['X_test']
y_train = data['y_train']
y_test = data['y_test']
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(y_test.shape)
(960, 224, 224, 3)
(240, 224, 224, 3)
(960,)
(240,)
MLP로 신경망 모델 만들기
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Flatten
model = Sequential()
model.add(Flatten(input_shape=(224,224,3)))
model.add(Dense(300, activation="relu"))
model.add(Dense(150, activation="relu"))
model.add(Dense(50, activation="relu"))
model.add(Dense(3, activation="softmax"))
# 기존 categorical_crossentropy에 레이블들의 원핫인코딩까지 sparse_를 쓰면 자동으로 지원
model.compile(loss="sparse_categorical_crossentropy",
optimizer="Adam",
metrics=['acc']
)
from sklearn.utils import validation
from sklearn.model_selection import train_test_split
h = model.fit(X_train,y_train,
batch_size=128,
epochs=50,
validation_split=0.2
)
Epoch 1/50
6/6 [==============================] - 3s 72ms/step - loss: 17426.5371 - acc: 0.2930 - val_loss: 7392.8706 - val_acc: 0.3281
Epoch 2/50
6/6 [==============================] - 0s 36ms/step - loss: 6421.2710 - acc: 0.3255 - val_loss: 6963.2598 - val_acc: 0.2812
Epoch 3/50
6/6 [==============================] - 0s 34ms/step - loss: 6894.0620 - acc: 0.3464 - val_loss: 7319.2251 - val_acc: 0.3906
Epoch 4/50
6/6 [==============================] - 0s 31ms/step - loss: 5149.3687 - acc: 0.3333 - val_loss: 4044.2434 - val_acc: 0.3854
Epoch 5/50
6/6 [==============================] - 0s 28ms/step - loss: 5796.9009 - acc: 0.3724 - val_loss: 7200.7622 - val_acc: 0.3906
Epoch 6/50
6/6 [==============================] - 0s 29ms/step - loss: 6574.7090 - acc: 0.3333 - val_loss: 9707.5273 - val_acc: 0.3021
...............................................................................................
Epoch 50/50
6/6 [==============================] - 0s 28ms/step - loss: 90.8250 - acc: 0.6862 - val_loss: 250.8062 - val_acc: 0.4323
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()

다양한 이미지를 가지고 왔기 때문에 정확도가 높지 않다
pre = model.predict(X_test)
pre
# 정확도 외에도 정밀도, 재현율, F-score 까지 확인해보자
from sklearn.metrics import classification_report
# np.argmax : 출력된 확률값 중 가장 큰 수치값의 인덱스를 반환
# axis=1 : pre가 2차원 배열이므로 내부 배열들만(1차원) 보겠다는 뜻
np.argmax(pre, axis=1)
array([2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
#classification_report(평가용정답, 예측한 정답)
print(classification_report(y_test,np.argmax(pre, axis=1)))
# precision(정밀도) : 모델이 True라고 분류한 것 중에서 실제 True인 것의 비율
# recall(재현율) : 실제 True인 것들 중에서 모델이 True라고 예측한 것의 비율
# support : 레이블의 개수
# -> 결국은 pre값이 각 레이블에 대한 확률 값으로 나오기 때문에 그 중 가장 높은 수치의 인덱스를 반환하여 y_test랑 비교하는 방식
precision recall f1-score support
0 0.00 0.00 0.00 87
1 0.00 0.00 0.00 79
2 0.31 1.00 0.47 74
accuracy 0.31 240
macro avg 0.10 0.33 0.16 240
weighted avg 0.10 0.31 0.15 240
- 기존 MLP로는 3채널이고 배경이 다양한 이미지 데이터들을 분류하는데 어려움이 있다
CNN을 적용하여 신경망을 모델링해보자
from tensorflow.keras.layers import Conv2D, MaxPool2D, Flatten, Dropout
cnn_model = Sequential()
# 1. 특성추출부(Conv - 특징이 되는 정보를 부각시켜 추출함)
cnn_model.add(Conv2D(input_shape=(224,224,3),
# 필터(돋보기)의 개수 -> 추출하는 특징의 개수를 설정
filters=128,
# 필터의 크기 설정(행,열)
kernel_size=(3,3),
# same : 원본 데이터의 크기에 맞게 알아서 패딩을 적용('valid' -> 패딩적용X)
padding='same',
activation='relu'
))
# 2. 특성추출부(Pooling - 불필요한 정보 삭제)
# pool_size : 디폴트 값이 2(필터 크기가 2x2)
cnn_model.add(MaxPool2D())
cnn_model.add(Conv2D(filters=256,
kernel_size=(3,3),
padding='same',
activation='relu'
))
cnn_model.add(MaxPool2D())
# Dropout : 신경망의 전체 뉴런중 일부(20%)를 학습이 불가하도록 만들어주는 명령
# -> 신경망의 복잡도를 낮춰서 좀 더 가볍게 동작시키고 과대적합을 해소하는데 도움을 줌
cnn_model.add(Dropout(0.2))
cnn_model.add(Conv2D(filters=128,
kernel_size=(3,3),
padding='same',
activation='relu'
))
cnn_model.add(MaxPool2D())
cnn_model.add(Conv2D(filters=64,
kernel_size=(3,3),
padding='same',
activation='relu'
))
cnn_model.add(MaxPool2D())
# 분류기(MLP : 다층퍼셉트론)
cnn_model.add(Flatten())
cnn_model.add(Dense(128, activation='relu'))
cnn_model.add(Dense(64, activation='relu'))
cnn_model.add(Dense(32, activation='relu'))
cnn_model.add(Dense(3, activation='softmax'))
cnn_model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 224, 224, 128) 3584
max_pooling2d (MaxPooling2D (None, 112, 112, 128) 0
)
conv2d_1 (Conv2D) (None, 112, 112, 256) 295168
max_pooling2d_1 (MaxPooling (None, 56, 56, 256) 0
2D)
dropout (Dropout) (None, 56, 56, 256) 0
conv2d_2 (Conv2D) (None, 56, 56, 128) 295040
max_pooling2d_2 (MaxPooling (None, 28, 28, 128) 0
2D)
conv2d_3 (Conv2D) (None, 28, 28, 64) 73792
max_pooling2d_3 (MaxPooling (None, 14, 14, 64) 0
2D)
flatten_1 (Flatten) (None, 12544) 0
dense_4 (Dense) (None, 128) 1605760
dense_5 (Dense) (None, 64) 8256
dense_6 (Dense) (None, 32) 2080
dense_7 (Dense) (None, 3) 99
=================================================================
Total params: 2,283,779
Trainable params: 2,283,779
Non-trainable params: 0
cnn_model.compile(loss='sparse_categorical_crossentropy',
optimizer='Adam',
metrics=['acc'])
h= cnn_model.fit(X_train,y_train,
validation_split=0.2,
batch_size=128,
epochs=50)
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()

pre = cnn_model.predict(X_test)
from sklearn.metrics import classification_report
print(classification_report(y_test, np.argmax(pre, axis=1)))
precision recall f1-score support
0 0.48 0.51 0.49 87
1 0.53 0.49 0.51 79
2 0.45 0.46 0.46 74
accuracy 0.49 240
macro avg 0.49 0.49 0.49 240
weighted avg 0.49 0.49 0.49 240
직접 만든 CNN 모델로는 한번에 좋은 결과를 보긴 힘들다
CNN 전이학습 모델 활용하기(VGG160)
- ImageNet challenge 대회에서 2014년도 준우승한 VGG16모델을 활용해보자
from tensorflow.keras.applications import VGG16
pre_trained_model = VGG16(input_shape=(224,224,3),
include_top=False,
weights='imagenet'
)
# include_top=False : 불러온 모델의 MLP층을 사용하지 않고 특성추출부만 사용(특성추출방식)
# False : 상단부(MLP)를 쓰지 않겠다는 뜻
# -> 기존 이미지넷 대회에서는 1000가지의 이미지를 분류했으나 우리는 3가지 동물로만 분류하기 때문에
# MPL층을 우리에게 맞게 설정해줘야 함
# weights='imagenet' : 이미지넷 대회에서 학습된 가중치(w)를 그대로 가져와서 사용
pre_trained_model.summary()
Model: "vgg16"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 224, 224, 3)] 0
block1_conv1 (Conv2D) (None, 224, 224, 64) 1792
block1_conv2 (Conv2D) (None, 224, 224, 64) 36928
block1_pool (MaxPooling2D) (None, 112, 112, 64) 0
block2_conv1 (Conv2D) (None, 112, 112, 128) 73856
block2_conv2 (Conv2D) (None, 112, 112, 128) 147584
block2_pool (MaxPooling2D) (None, 56, 56, 128) 0
block3_conv1 (Conv2D) (None, 56, 56, 256) 295168
block3_conv2 (Conv2D) (None, 56, 56, 256) 590080
block3_conv3 (Conv2D) (None, 56, 56, 256) 590080
block3_pool (MaxPooling2D) (None, 28, 28, 256) 0
block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160
block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808
block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808
block4_pool (MaxPooling2D) (None, 14, 14, 512) 0
block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808
block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808
block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808
block5_pool (MaxPooling2D) (None, 7, 7, 512) 0
=================================================================
Total params: 14,714,688
Trainable params: 14,714,688
Non-trainable params: 0
_________________________________________________________________
cnn_model2 = Sequential()
#특성추출부
cnn_model2.add(pre_trained_model)
# MLP층
cnn_model2.add(Flatten())
cnn_model2.add(Dense(128, activation='relu'))
cnn_model2.add(Dense(64, activation='relu'))
cnn_model2.add(Dense(32, activation='relu'))
cnn_model2.add(Dense(3, activation='softmax'))
cnn_model2.summary()
Model: "sequential_4"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
vgg16 (Functional) (None, 7, 7, 512) 14714688
flatten_2 (Flatten) (None, 25088) 0
dense_8 (Dense) (None, 128) 3211392
dense_9 (Dense) (None, 64) 8256
dense_10 (Dense) (None, 32) 2080
dense_11 (Dense) (None, 3) 99
=================================================================
Total params: 17,936,515
Trainable params: 17,936,515 #학습 시킬수 있는 parameter
Non-trainable params: 0 #학습 시킬수 없는 parameter
_________________________________________________________________
MLP층만 수정하고 특성추출부는 학습이 잘 된것을 가져왔는데
역전파로 학습시키고 이를 토대로 w,b값을 다시 바꾸면 잘 학습된 특성추출부를 가져온 의미가 없다.
# 사전에 학습된 vgg16모델을 불러와서 재학습이 불가능하도록 동결(잘 학습된 w,b값을 그대로 사용하기 위해서)
# -> 동결을 시키지 않게 되면 새롭게 만들어준 MLP층과 재학습하게 되므로 잘 학습된 w,b값이 뒤틀려 버린다
pre_trained_model.trainable = False
pre_trained_model.summary()
Model: "vgg16"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 224, 224, 3)] 0
.................................................................
=================================================================
Total params: 14,714,688
Trainable params: 0
Non-trainable params: 14,714,688 # non trainalbe params로 바뀜
_________________________________________________________________
cnn_model2.compile(loss='sparse_categorical_crossentropy',
optimizer='Adam',
metrics=['acc'])
h2 = cnn_model2.fit(X_train, y_train,
validation_split=0.2,
batch_size=128,
epochs=50)
plt.figure(figsize=(15,5))
# train 데이터
plt.plot(h2.history['acc'], label=['acc'],
c='blue', marker='.')
# val 데이터
plt.plot(h2.history['val_acc'], label=['val_acc'],
c='red', marker='.')
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.legend()
plt.show()

pre = cnn_model2.predict(X_test)
print(classification_report(y_test, np.argmax(pre, axis=1)))
precision recall f1-score support
0 0.76 0.78 0.77 87
1 0.90 0.70 0.79 79
2 0.71 0.85 0.77 74
accuracy 0.78 240
macro avg 0.79 0.78 0.78 240
weighted avg 0.79 0.78 0.78 240
- 결과는 기존보다 좋아졌지만 조금 더 튜닝해보자(미세조정방식 적용)
pre_trained_model = VGG16(input_shape=(224,224,3),
include_top=False,
weights='imagenet')
pre_trained_model.summary()
Model: "vgg16"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_2 (InputLayer) [(None, 224, 224, 3)] 0
block1_conv1 (Conv2D) (None, 224, 224, 64) 1792
block1_conv2 (Conv2D) (None, 224, 224, 64) 36928
block1_pool (MaxPooling2D) (None, 112, 112, 64) 0
block2_conv1 (Conv2D) (None, 112, 112, 128) 73856
block2_conv2 (Conv2D) (None, 112, 112, 128) 147584
block2_pool (MaxPooling2D) (None, 56, 56, 128) 0
block3_conv1 (Conv2D) (None, 56, 56, 256) 295168
block3_conv2 (Conv2D) (None, 56, 56, 256) 590080
block3_conv3 (Conv2D) (None, 56, 56, 256) 590080
block3_pool (MaxPooling2D) (None, 28, 28, 256) 0
block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160
block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808
block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808
block4_pool (MaxPooling2D) (None, 14, 14, 512) 0
block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808
block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808
block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808
block5_pool (MaxPooling2D) (None, 7, 7, 512) 0
=================================================================
Total params: 14,714,688
Trainable params: 14,714,688
Non-trainable params: 0
_________________________________________________________________
# VGG16 모델의 각 층별 이름을 출력
for layer in pre_trained_model.layers :
print(layer.name)
input_2
block1_conv1
block1_conv2
block1_pool
block2_conv1
block2_conv2
block2_pool
block3_conv1
block3_conv2
block3_conv3
block3_pool
block4_conv1
block4_conv2
block4_conv3
block4_pool
block5_conv1
block5_conv2
block5_conv3
block5_pool
for layer in pre_trained_model.layers:
if layer.name == 'block5_conv3' :
layer.trainable = True # 마지막층만 학습 가능하게
else :
layer.trainable = False
pre_trained_model.summary()
Model: "vgg16"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_2 (InputLayer) [(None, 224, 224, 3)] 0
block1_conv1 (Conv2D) (None, 224, 224, 64) 1792
block1_conv2 (Conv2D) (None, 224, 224, 64) 36928
block1_pool (MaxPooling2D) (None, 112, 112, 64) 0
block2_conv1 (Conv2D) (None, 112, 112, 128) 73856
block2_conv2 (Conv2D) (None, 112, 112, 128) 147584
block2_pool (MaxPooling2D) (None, 56, 56, 128) 0
block3_conv1 (Conv2D) (None, 56, 56, 256) 295168
block3_conv2 (Conv2D) (None, 56, 56, 256) 590080
block3_conv3 (Conv2D) (None, 56, 56, 256) 590080
..............................................................
=================================================================
Total params: 14,714,688
Trainable params: 2,359,808
Non-trainable params: 12,354,880
_________________________________________________________________
cnn_model3 = Sequential()
cnn_model3.add(pre_trained_model)
cnn_model3.add(Flatten())
cnn_model3.add(Dense(128, activation='relu'))
cnn_model3.add(Dense(64, activation='relu'))
cnn_model3.add(Dense(32, activation='relu'))
cnn_model3.add(Dense(3, activation='softmax'))
cnn_model3.summary()
Model: "sequential_5"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
vgg16 (Functional) (None, 7, 7, 512) 14714688
flatten_3 (Flatten) (None, 25088) 0
dense_12 (Dense) (None, 128) 3211392
dense_13 (Dense) (None, 64) 8256
dense_14 (Dense) (None, 32) 2080
dense_15 (Dense) (None, 3) 99
=================================================================
Total params: 17,936,515
Trainable params: 5,581,635
Non-trainable params: 12,354,880
_________________________________________________________________
cnn_model3.compile(loss='sparse_categorical_crossentropy',
optimizer='Adam',
metrics=['acc'])
h3 = cnn_model3.fit(X_train,y_train,
validation_split=0.2,
batch_size=128,
epochs=50)
plt.figure(figsize=(15,5))
# train 데이터
plt.plot(h3.history['acc'], label=['acc'],
c='blue', marker='.')
# val 데이터
plt.plot(h3.history['val_acc'], label=['val_acc'],
c='red', marker='.')
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.legend()
plt.show()

pre = cnn_model3.predict(X_test)
print(classification_report(y_test, np.argmax(pre, axis=1)))
precision recall f1-score support
0 0.78 0.82 0.80 87
1 0.82 0.82 0.82 79
2 0.87 0.82 0.85 74
accuracy 0.82 240
macro avg 0.82 0.82 0.82 240
weighted avg 0.82 0.82 0.82 240
데이터 증강(이미지 증식)
- 모델의 과대적합을 방지하기 위한 기법 중 하나
- 유사한 이미지를 생성하여 학습에 용이하게 만들어주고 학습 데이터의 양 자체를 늘려주는 효과
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# ImageDataGenerator : 이미지 데이터를 생성하기 위한 조건을 설정하는 함수
aug = ImageDataGenerator(rotation_range=30, # 이미지 회전 각도
width_shift_range=0.2, # 20% 내외 수평이동
height_shift_range=0.2, # 20% 내외 수직이동
zoom_range=0.2, # 0.8 ~ 1.2배로 축소/확대
horizontal_flip=True, # 수평방향으로 뒤집기
fill_mode='nearest' # 이미지가 변형되면서 비는 공간에 가장 가까운 픽셀값으로 채워줌
)
for layer in pre_trained_model2.layers:
if layer.name == 'block5_conv3' :
layer.trainable = True # 마지막층만 학습 가능하게
else :
layer.trainable = False
cnn_model4 = Sequential()
cnn_model4.add(pre_trained_model2)
cnn_model4.add(Flatten())
cnn_model4.add(Dense(128, activation='relu'))
cnn_model4.add(Dense(64, activation='relu'))
cnn_model4.add(Dense(32, activation='relu'))
cnn_model4.add(Dense(3, activation='softmax'))
cnn_model4.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
vgg16 (Functional) (None, 7, 7, 512) 14714688
flatten_2 (Flatten) (None, 25088) 0
dense_8 (Dense) (None, 128) 3211392
dense_9 (Dense) (None, 64) 8256
dense_10 (Dense) (None, 32) 2080
dense_11 (Dense) (None, 3) 99
=================================================================
Total params: 17,936,515
Trainable params: 5,581,635
Non-trainable params: 12,354,880
_________________________________________________________________
cnn_model4.compile(loss='sparse_categorical_crossentropy',
optimizer='Adam',
metrics=['acc'])
len(X_train)
960
# flow : ImageDataGenerator로 설정한 조건을 통해 이미지를 생성하여 학습에 적용시켜주는 함수
cnn_model4.fit(aug.flow(X_train,y_train, batch_size=128),
# 한 epoch 당 7.5번 돌고 끝나게 됨(128*7.5로 총 960개의 새로운 이미지를 생성)
steps_per_epoch=len(X_train) / 128,
epochs=50
)
# 1epoch 때 증식된 이미지 960개로 학습, 2epoch 때 960개가 추가되어서 총 1920개로 학습 .... 이렇게 반복
pre = cnn_model4.predict(X_test)
print(classification_report(y_test, np.argmax(pre, axis=1)))
precision recall f1-score support
0 0.78 0.79 0.79 87
1 0.87 0.85 0.86 79
2 0.85 0.86 0.86 74
accuracy 0.83 240
macro avg 0.84 0.84 0.84 240
weighted avg 0.83 0.83 0.83 240
반응형
'빅데이터 서비스 교육 > 딥러닝' 카테고리의 다른 글
RNN모델 (0) | 2022.07.26 |
---|---|
전이학습 & 데이터 확장 (0) | 2022.07.25 |
CNN (0) | 2022.07.21 |
활성화함수, 최적화함수 비교 및 최적화 모델 찾기 (0) | 2022.07.21 |
활성화함수, 최적화 함수 (0) | 2022.07.19 |