Ch 8. 컨볼루션 신경망

wonnie1224·2023년 4월 27일
0

8.1 발상과 전개

📌 발상

Untitled

  • 다층 퍼셉트론에 입력하기 위해 1차원으로 펼치면 삼각형 모양은 사라짐
  • 다층 퍼셉트론 - 픽셀의 연결성 못 씀 → 개별 화소를 보고 분류

⇒ 작은 데이터셋에서도 정확도가 낮고 ImageNet이나 COCO와 같은 큰 데이터셋은 거의 인식 못하는 근본 원인

📌 간략 역사

Untitled

📌 딥러닝의 성공 요인

  • 데이터셋이 커짐
  • GPU 병렬 처리로 학습 시간이 대폭 빨라짐
  • 좋은 학습 알고리즘 개발; 활성 함수, 규제 기법, 손실 함수, 옵티마이저 발전

8.2 컨볼루션 신경망의 구조

8.2.1 컨볼루션층 & 풀링층

📌 컨볼루션층

: 입력 특징 맵 (feature map)에 컨볼루션을 적용해서 얻은 피쳐 맵을 출력함

  • 입력 피쳐 맵 : k개 채널로 구성 → 깊이가 k인 m x n 맵, 즉 m x n x k 모양의 3차원 텐서

  • 필터의 깊이 = 입력 피쳐 맵의 깊이 =k

  • 필터의 크기 = h x h (h : 보통 3 or 5)

  • 필터 - bias 값 1개 추가로 가짐

➡️ 필터는 kh2+1kh^2+1개의 가중치 가짐 (가중치 때문에 +1)

  • 필터는 깊이 방향으론 이동 X, 좌우 & 상하 방향으로 이동하며 곱의 합(= 로짓 logit)을 구하는 컨볼루션 수
  • 출력 피쳐 맵 : 로짓에 활성화 함수(보통 ReLU or ReLU의 변종) 적용한 결과

Untitled

  • 필터 개수 k’ : 보통 16, 32, 64, 128, 256 사용
  • 필터 1개 당 피처 맵 1개 생성
  • 출력 피처 맵 : 필터의 개수인 k’ 깊이의 m’ x n’ x k’ 모양의 텐서

Padding

🌿 필요한 이유

맵의 경계에 필터를 대면 일부 픽셀이 밖으로 나가서 적용 불가능

but 경계를 제외하면 층이 깊어질수록 맵의 크기 점점 작아짐

정리하자면,

⇒ ouput 맵의 크기를 유지하기 위해

⇒ edge 쪽 픽셀 정보를 더 잘 이용하기 위해

🌿 종류

  • 0 padding : 경계 바깥에 0 덧댐
  • copy padding : 경계 픽셀의 값을 복사해 덧댐

Untitled

선생님, Padding은 뭔가요? 밸리드 패딩 / 풀 패딩 / 세임 패딩

Stride

  • 출력 맵의 크기를 줄이는 효과

stride = s 이면

  • s개 픽셀 씩 건너 필터 적용
  • m x n 맵이 (m/s) x (n/s)로 축소

Untitled

컨볼루션층의 연산

5x5x3 입력 피쳐 맵 - 3x3x3 필터 2개 적용 → 3x3x2 출력 피쳐 맵

0 padding, stride=2

Untitled

Untitled

conv 층의 특성

  1. 가중치 공유(weight sharing)
    • 필터 값 = 가중치
    • 입력 피쳐 맵의 모든 화소가 같은 필터 사용 ⇒ 가중치 공유함!
  2. 부분 연결성(partial connection)
    • 해당 픽셀 주위로 국한하여 연산함

⇒ 학습 알고리즘이 최적화해야 할 가중치 개수 대폭 줄여줌

컨볼루션층 : kk'개의 h x h x k 필터 ⇒ 최적화할 가중치 k(kh2+1)k'(kh^2+1)개 (bias 노드 땜에 +1함)

conv 층의 연산량

Untitled

📌 풀링층 pooling layer

  1. max pooling : 필터 안의 픽셀 중 max값을 취하는 연산

Untitled

  • stride = 2 → 1개 픽셀 건너서 필터 적용함 ➡️ 피쳐 맵 크 1/2로 줄어듦
  1. average pooling : 필터 안의 픽셀값의 평균 취하는 연산

+) 보통 max pooling 많이 사용

8.2.2 빌딩블록을 쌓아 만드는 컨볼루션 신경망

빌딩블록 쌓기

Untitled

피쳐 맵의 크기 mxn은 컨볼루션층과 풀링층의 stride에 따라 바뀜

깊이 k 는 컨볼루션층에서는 필터 개수에 따라 바뀌지만, 풀링층에서는 그대로 유지

🌿 컨볼루션 신경망의 구조

1) 신경망의 앞부분 : 컨볼루션층 & 풀링층 번갈아 쌓음 - 피쳐 추출하는 역할

2) 중간부분 : Flatten 연산 - 컨볼루션층의 다차원 구조 → 1차원 구조로 변환해 FC층에 입력

3) 신경망 뒷부분 : FC층을 쌓아 분류 수행

4) 출력층 : 부류 개수 만큼 노드 배치

📌 LeNet-5 사례

[그림 8-11(a)]

필기 숫자 인식 목적 → 출력층에 10개 노드

*) 6@28x28 : 28 x 28 피처맵이 6장이라는 뜻

입력층 : MNIST의 28 x 28맵의 상하좌우에 2픽셀씩 padding → 32 x 32맵 입력

숫자 맵 - 명암(채널 1개) → 입력 피처 맵의 깊이 = 1

Untitled

[그림 8-11(b)]

  • LeNet-5의 구조 : C-P-C-P-C-FC-FC

    가중치 : conv층 & FC층에만 있음

    • 1번째 conv층 : (5x5x1+1)x6
    • 2번째 conv층 : (5x5x6+1)x16
    • 3번째 conv층 : (5x5x16+1)x120
    • 1번째 fc층 : (120+1)x84
    • 2번째 fc층 : (84+1)x10
  • 연산단계

    1) 입력은 28×28×1 맵

    1번째 conv층 : 5x5 필터 6개, stride=1, 0 padding 적용

    2) 32×32 맵에 컨볼루션 적용 → 28×28×6 피쳐 맵이 만들어지고 풀링층을 통과하면 14×14×6 특징 맵이 됨

    3) 2번째 conv층은 5×5 필터 16개를 쓰고 stride=1, padding 적용X

    ⇒ 10×10×16 특징 맵을 얻는데 풀링층을 통과하여 5×5×16 피처 맵

    4) 3번째 conv층에서 5×5 필터를 120개 적용하여 1×1×120 피처 맵 얻음

    5) Flatten 연산을 통해 1차원 구조로 변환하여 FC층에 입력

    6) 1번째 FC층의 특징 벡터는 84개 노드를 가진 은닉층을 통과하여 10개 노드를 가진 출력층에 도달

📌 유연한 구조

conv층, pooling층, FC층을 쌓아 만들어서 다양한 모양으로 조립 가능

🌿 오토인코더(auto-encoder) : 입력 영상을 그대로 출력으로 내놓는 컨볼루션 신경망

  1. 인코더 : 피쳐 맵을 점점 작게 함
  2. 디코더 : 피쳐 맵 다시 키워 원래 영상 복원함
  • 보통 인코더 & 디코더 대칭 이루도록 설계함
  • 신경망의 가운데 층 : 원래 영상보다 크기가 훨씬 축소된 피쳐 맵 생성
    • 디코더 통해 원래 영상 복원 가능할 정도의 핵심 정보 모두 가지고 있음

🌿영상 분할을 위한 컨볼루션 신경망 : fc층 제거 후 마지막 conv 층에 레이블된 분할 맵 배치

Untitled

8.3 컨볼루션 신경망의 학습

📌 컨볼루션 신경망을 위한 역전파 알고리즘

Untitled

  1. 전방 계산 : conv 층, pooling층, FC층 거쳐 출력 벡터 oo 출력
  2. 손실 함수 : oo 와 참값 벡터 yy의 오류를 계산
  3. 역전파 : 오류를 줄이는 방향으로 가중치 갱신
    1. 가중치 : conv층에 있는 필터들, FC층에 있는 값들
    2. 아래의 알고리즘 흐름 그대로 적용(수식은 다름)

Untitled

Untitled

📌 특징 학습과 통째 학습

  • 특징 학습 (feature learning) : 특징 추출을 담당하는 필터를 학습
    • 주어진 데이터셋을 인식하는 데 최적인 필터를 찾아냄
  • 특징 학습을 다른 관점에서 바라보면 통째 학습(end-to-end learning)

고전적 컴퓨터 비전 - 특징을 사람이 설계한 방법으로 추출

ex) LBP, SIFT, HOG 등

  1. 고전 패러다임

수작업 특징으로 분류 모델을 학습 → 특징 추출 프로그램 + 분류기 프로그램 결합 → 인식기 완성

  1. 딥러닝 패러다임

통합된 신경망에서 특징 학습 & 분류기 학습을 통째로 진행

Untitled

📌 컨볼루션 신경망이 우수한 이유

  1. 데이터의 원래 구조 유지
  2. 특징 학습
  3. 신경망 깊이 깊게 가능

8.4 컨볼루션 신경망 구현

📌 LeNet-5의 재현

import numpy as np
import tensorflow as tf
import tensorflow.keras.datasets as ds

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D,MaxPooling2D,Flatten,Dropout,Dense
from tensorflow.keras.optimizers import Adam

# 데이터 준비; MNIST 데이터셋 읽어오고 형태 변환
(x_train,y_train),(x_test,y_test)=ds.mnist.load_data()
x_train=x_train.reshape(60000,28,28,1)
x_test=x_test.reshape(10000,28,28,1)
x_train=x_train.astype(np.float32)/255.0
x_test=x_test.astype(np.float32)/255.0
y_train=tf.keras.utils.to_categorical(y_train,10)
y_test=tf.keras.utils.to_categorical(y_test,10)

# 모델 선택
cnn=Sequential()
cnn.add(Conv2D(6,(5,5),padding='same',activation='relu',input_shape=(28,28,1))) # conv층(필터개수, 크기, 패딩 종류, 활성화함수 종류, 신경망에 최초로 입력되는 텐서 모양)
cnn.add(MaxPooling2D(pool_size=(2,2),strides=2)) # 풀링층
cnn.add(Conv2D(16,(5,5),padding='valid',activation='relu'))
cnn.add(MaxPooling2D(pool_size=(2,2),strides=2))
cnn.add(Conv2D(120,(5,5),padding='valid',activation='relu'))
cnn.add(Flatten()) # 텐서 1차원 구조로 변환하여 FC층에 입력
cnn.add(Dense(units=84,activation='relu')) # FC층
cnn.add(Dense(units=10,activation='softmax')) # 출력층

# 학습
cnn.compile(loss='categorical_crossentropy',optimizer=Adam(learning_rate=0.001),metrics=['accuracy']) # 정확률을 사용하여 성능 조사하라
cnn.fit(x_train,y_train,batch_size=128,epochs=30,validation_data=(x_test,y_test),verbose=2) # 매 epoch마다 validation 인수로 성능 평가

# 예측 ; 성능 측정                                
res=cnn.evaluate(x_test,y_test,verbose=0) # 테스트 집합으로 성능 측정
print('정확률=',res[1]*100) # 퍼센트로 산

8.4.2 자연 영상 인식

import numpy as np
import tensorflow as tf
import tensorflow.keras.datasets as ds

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D,MaxPooling2D,Flatten,Dense,Dropout
from tensorflow.keras.optimizers import Adam

(x_train,y_train),(x_test,y_test)=ds.cifar10.load_data()
x_train=x_train.astype(np.float32)/255.0
x_test=x_test.astype(np.float32)/255.0
y_train=tf.keras.utils.to_categorical(y_train,10)
y_test=tf.keras.utils.to_categorical(y_test,10)

cnn=Sequential()
cnn.add(Conv2D(32,(3,3),activation='relu',input_shape=(32,32,3)))
cnn.add(Conv2D(32,(3,3),activation='relu'))
cnn.add(MaxPooling2D(pool_size=(2,2)))
cnn.add(Dropout(0.25))
cnn.add(Conv2D(64,(3,3),activation='relu'))
cnn.add(Conv2D(64,(3,3),activation='relu'))
cnn.add(MaxPooling2D(pool_size=(2,2)))
cnn.add(Dropout(0.25))
cnn.add(Flatten())
cnn.add(Dense(units=512,activation='relu'))
cnn.add(Dropout(0.5))
cnn.add(Dense(units=10,activation='softmax'))

cnn.compile(loss='categorical_crossentropy',optimizer=Adam(learning_rate=0.001),metrics=['accuracy'])
hist=cnn.fit(x_train,y_train,batch_size=128,epochs=100,validation_data=(x_test,y_test),verbose=2)

res=cnn.evaluate(x_test,y_test,verbose=0)
print('정확률=',res[1]*100)

import matplotlib.pyplot as plt

plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Accuracy graph')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train','Validation'])
plt.grid()
plt.show()

plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Loss graph')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train','Validation'])
plt.grid()
plt.show()

8.4.3 텐서플로 프로그래밍

📌 models 모듈 : Sequential, Function API

: 모델 생성 시 사용

  • Sequential : 한 갈래 텐서가 끝까지 흐름 Untitled
  • Function API : 중간에 여러 갈래로 나뉨
    • 층을 흐르는 텐서 중간에 접근하여 값 읽거나, 2갈래로 나눠 다른 처리하는 경우 사용

      Untitled

📌 layers 모듈: Dense, Conv2D, MaxPooling2D, Flatten, Dropout 등

: 신경망 구성하는 층 제공

  • Dense : FC층
  • Conv2D : 컨볼루션층 (컨볼루션 연산에서 필터가 깊이 방향으론 이동 X, 수평&수직 방향으로만 이동해서 2D임)
  • MaxPooling2D : max 풀링
  • Flatten : 피처맵을 1차원 구조로 펼침
  • Dropout : 드롭아웃 규제 기법

📌 losses 모듈: MSE, categorical_crossentropy 등

: 손실 함수

📌 optimizers 모듈: SGD, Adam, AdaGrad, RMSprop 등

: 8종류 옵티마이저 제공

8.5 [비전 에이전트 6] 우편번호 인식기 v.2

  • 데이터셋 시프트 (dataset shift) : 학습에 사용한 data와 실제 현장에서 발생한 data의 분포가 다른 상황 → 성능 저하 발생

8.6 딥러닝의 학습 알고리즘 향상

8.6.1 손실 함수

  • 초기 신경망 - 분류 문제 : 주로 평균제곱오차 MSE 사용
  • 딥러닝 - 주로 교차 엔트로피 사용

📌 교차 엔트로피 (cross entropy)

두 확률 분포가 얼마나 다른지 측정

한 샘플에 대한 cross entropy

Untitled

c : 부류 개수

  • 손실 함수로 쓸 땐 미니 배치에 대해 평균
  • 손실 함수의 값이 클수록 단계 3에서 가중치를 갱신하는 양이 커져 학습이 원만
  • 평균제곱오차는 손실 함수의 값이 더 큰데 미분값이 더 작아 가중치 갱신이 더 작은 불공정한 상황이 발생

⇒ 교차 엔트로피는 평균제곱오차의 불공정성 문제를 해결

📌 Focal 손실 함수

  • 부류 불균형이 심한 경우에 주로 사용

ex) 부류가 2개인 경우; 물체 분할 - 물체 & 배경을 구분

oo=(물체일 확률, 배경일 확률) : 신경망이 출력한 예측 벡터
y : 참값

Untitled

Untitled

영역 분할 - 보통 물체가 점유한 영역보다 배경 영역이 훨씬 넓음 ➡️ 부류 불균형이 심함

손실 함수 계산; 모든 화소의 e를 평균함 → 배경 픽셀만 분류를 잘하면 물체 픽셀를 못하더라도 교차 엔트로피가 낮아지는 부작용이 발생

➡️이런 부작용 방지 방법 : p_t가 커지면 빠르게 0에 가깝게 만드는 것

식 (8.4)의 Focal 손실 함수는 이런 조건을 만족

  • γ : 하이퍼 파라미터, 클수록 곡선이 0에 더욱 빠르게 가까워짐
  • γ = 0 ; cross entropy와 같음
  • γ = 2에서 최고 성능 보임

Untitled

8.6.2 옵티마이저

🌿 SGD

신경망 학습의 목적은 손실 함수의 값을 가능한 한 낮추는 매개변수를 찾는 것이다. 이는 매개변수의 최적값을 찾는 문제이며, 이러한 문제를 푸는 것을 최적화(optimization)라고 한다.

우리는 지금까지 매개변수의 기울기(미분)을 이용해 기울어진 방향으로 매개변수 값을 갱신하는 일을 반복해 최적화를 진행했다. 이것이 확률적 경사 하강법(SGD)이라는 방법

⇒ SGD의 단점은 비등방성(anisotropy) 함수(방향에 따라 성질, 즉 여기에서는 기울기가 달라지는 함수)에서는 탐색 경로가 비효율적

SGD 옵티마이저의 한계를 모멘텀 & 적응적 학습률로 극복

📌 모멘텀

모멘텀(momentum) : 이전 운동량을 현재에 반영할 때 사용

속도 V 갱신 후 V로 가중치 W 갱신

α : 오래된 운동량의 영향력을 줄여주는 인자

Untitled

Untitled

Untitled

Untitled

Untitled

  • [그림 8-19(a)]
    • 검은색 화살표 ; 이전 단계에서 누적된 속도 벡터 V

    • 검은 점으로 표시한 W가 현재 점

      SGD ; 그레이디언트 방향(빨강) 따라 이동한 빨간색 점이 새로운 W

      모멘텀을 적용한 SGD ; 그레이디언트 방향과 속도 벡터를 더한 방향(파랑)을 따라 이동한 파란색 점이 새로운 W

  • 텐서플로의 SGD 클래스의 선언 Untitled
    • momentum 매개변수 : 식 (8.5)의 α에 해당 한다.
    • momentum 기본값이 0.0 → 생략하면 모멘텀을 적용X 고전적인 SGD를 사용하는 셈

📌 적응적 학습률

식 (8.5)의 가중치 갱신 규칙은 고정된 학습률 ρ를 사용

그레이디언트 - 손실 함수가 작아지는 방향을 지시, but 얼만큼 이동해야 최소점에 도달하는지에 대한 정보 X

⇒ 0.01 또는 0.001과 같이 작은 학습률을 곱해 조금씩 보수적으로 이동

Untitled

학습률이 너무 크면 최저점을 중심으로 왔다갔다하는 현상 나타남
너무 작으면 학습 시간이 과다함

🌿 적응적 학습률 (adaptive learning rate) : 세대 & 그레이디언트에 따라 적응적으로 학습률 정함

  • 적응적 학습률을 적용한 옵티마이저
    • AdaGrad: 이전 그레이디언트를 누적한 정보를 이용해 학습률을 적응적으로 결정
    • RMSprop: 이전 그레이디언트를 누적할 때 오래될수록 영향력을 줄여가는 방식으로AdaGrad를 개선
    • Adam: RMSprop에 모멘텀 적용

8.6.3 규제

딥러닝은 신경망 모델의 용량을 크게 유지하면서 여러 규제 기법을 적용해 과잉 적합을 방지하는 전략 사용

📌 과잉 적합

과잉 적합 (over fitting) : 훈련에 참여하지 않은 새로운 데이터에 대해 아주 낮은 성능 보임

Untitled

📌 데이터 증강

📌 드롭아웃

: 피쳐 맵 구성하는 요소 중 일부를 랜덤 선택하여 0으로 설정

  • 드롭아웃 비율 r : 0으로 만들 요소의 비율
  • 피쳐 맵의 모든 요소의 합을 대략 유지 위해 살아남은 요소에 x 1/1r1/1-r

📌 조기 멈춤

Untitled

Untitled

  • EarlyStopping 클래스 매개변수 monitor : 어떤 측정치를 기준으로 삼을지 min_delta : 그것보다 작은 개선은 개선으로 여기지 마삼 patience : 그 값에 해당하는 epoch 동안 개선이 없으면 지정한 epoch에 도달하지 않았더라도 조기에 학습 stop restore_best_weights : False - 멈추는 순간의 가중치 / True - 가장 좋았던 세대의 가중치 취

8.7 전이 학습

전이 학습 (transfer learning) : 어떤 도메인의 데이터로 학습한 모델을 다른 도메인에 적용해 성능 높이는 방법

8.7.1 백본 모델

사전 학습 모델(pre-trained model) : 대용량 데이터로 미리 학습돼 있어 전이 학습에 활용할 수 있는 모델

  • pretrained 모델을 특정 응용에 전이 학습하면 백본 모델(backbone model)로 사용했다고 표현

Keras documentation: Keras Applications

Untitled

8.7.2 사전 학습 모델로 자연 영상 인식

  • ImageNet ; 1000부류

ResNet50 사용

import cv2 as cv 
import numpy as np
from tensorflow.keras.applications.resnet50 import ResNet50,preprocess_input,decode_predictions

model=ResNet50(weights='imagenet') # ResNet50 클래스로 사전 학습 모델을 읽어 model 객체에 저장, ImageNet으로 학습된 가중치

## 테스트 영상을 읽고 신경망에 입력할 수 있는 형태로 변환
img=cv.imread('rabbit.jpg') 
x=np.reshape(cv.resize(img,(224,224)),(1,224,224,3)) # 224×224×3 텐서를 1×224×224×3 텐서로 변환, predict 함수는 여러 장으로 구성된 미니 배치 단위로 입력 받기 때문  
x=preprocess_input(x)

preds=model.predict(x) # predict 함수로 예측을 수행하고 결과를 preds에 저장, preds 객체는 1×1000 배열
top5=decode_predictions(preds,top=5)[0] # 1,000개 확률 중에 가장 큰 5개 확률을 취하고 그들의 부류 이름을 같이 제공
print('예측 결과:',top5)

for i in range(5):
    cv.putText(img,top5[i][1]+':'+str(top5[i][2]),(10,20+i*20),cv.FONT_HERSHEY_SIMPLEX,0.5,(255,255,255),1)

cv.imshow('Recognition result',img)

cv.waitKey()
cv.destroyAllWindows()

Untitled

8.7.3 사전 학습 모델로 견종 인식

  • Stanford dogs 데이터셋; 부류 120개

Stanford Dogs dataset for Fine-Grained Visual Categorization

  • 미세 조정 (fine-tuning) : 사전 학습된 모델 뒤에 새로운 층 붙여 신경망 구성하고 학습률 낮게 설정해 다시 학습하는 방식
  • ImageNet으로 학습된 모델을 Stanford dogs 데이터로 전이 학습!
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Flatten,Dense,Dropout,Rescaling
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.applications.densenet import DenseNet121
from tensorflow.keras.utils import image_dataset_from_directory
import pathlib

data_path=pathlib.Path('datasets/stanford_dogs/images/images')

train_ds=image_dataset_from_directory(data_path,validation_split=0.2,subset='training',seed=123,image_size=(224,224),batch_size=16)
test_ds=image_dataset_from_directory(data_path,validation_split=0.2,subset='validation',seed=123,image_size=(224,224),batch_size=16)

base_model=DenseNet121(weights='imagenet',include_top=False,input_shape=(224,224,3))
cnn=Sequential()
cnn.add(Rescaling(1.0/255.0)) # 입력 텐서를 255로 나누어 [0.1] 범위로 변환
cnn.add(base_model)
cnn.add(Flatten())
cnn.add(Dense(1024,activation='relu'))
cnn.add(Dropout(0.75))
cnn.add(Dense(units=120,activation='softmax'))

# 학습
cnn.compile(loss='sparse_categorical_crossentropy',optimizer=Adam(learning_rate=0.000001),metrics=['accuracy']) # 
hist=cnn.fit(train_ds,epochs=200,validation_data=test_ds,verbose=2)

print('정확률=',cnn.evaluate(test_ds,verbose=0)[1]*100)

cnn.save('cnn_for_stanford_dogs.h5')	# 미세 조정된 모델을 파일에 저장

import pickle
f=open('dog_species_names.txt','wb')
pickle.dump(train_ds.class_names,f)
f.close()

import matplotlib.pyplot as plt

plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Accuracy graph')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train','Validation'])
plt.grid()
plt.show()

plt.plot(hist.history['loss'])
plt.plot(hist.history['val_loss'])
plt.title('Loss graph')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train','Validation'])
plt.grid()
plt.show()
  • code train_ds=image_dataset_from_directory(data_path,validation_split=0.2,subset='training',seed=123,image_size=(224,224),batch_size=16) test_ds=image_dataset_from_directory(data_path,validation_split=0.2,subset='validation',seed=123,image_size=(224,224),batch_size=16) 인수1 : 데이터가 저장되어 있는 폴더의 경로를 지정 인수2 : validation_split=0.2는 훈련 집합과 검증 집합을 8:2로 분할 인수3 : subset 훈련 집합을 취하라 인수4 : 다시 실행해도 같은 결과를 얻기 위해 난수 씨앗을 123으로 고정 인수5 : 영상을 읽으면서 224×224 크기로 변환 미니 배치 크기를 16으로 설정 sparse_categorical_crossentropy : 부류 정보를 원핫 코드가 아니라 정수로 표현

Untitled

8.8 견종 인식 프로그램

💡 프로그램 패턴

  1. GUI 제작 지원하는 클래스 선언
    1. 생성자 함수 __init__ 설정 : 윈도우 제목&위치&크기 설정, 위젯(버튼,레이블 등) 생성, 버튼 클릭 시 수행할 콜백함수 지정
    2. 호출되는 콜백함수들 선언
  2. 프로그램의 메인 : PyOt 실행에 필요한 객체 생성
import cv2 as cv 
import numpy as np
import tensorflow as tf
import winsound       
import pickle
import sys
from PyQt5.QtWidgets import *

cnn=tf.keras.models.load_model('cnn_for_stanford_dogs.h5')	# 모델 읽기
dog_species=pickle.load(open('dog_species_names.txt','rb'))	# 견종 이름
         
class DogSpeciesRecognition(QMainWindow):
    def __init__(self) :
        super().__init__()
        self.setWindowTitle('견종 인식')
        self.setGeometry(200,200,700,100)
       
        fileButton=QPushButton('강아지 사진 열기',self) 
        recognitionButton=QPushButton('품종 인식',self)
        quitButton=QPushButton('나가기',self) 
        
        fileButton.setGeometry(10,10,100,30)
        recognitionButton.setGeometry(110,10,100,30)
        quitButton.setGeometry(510,10,100,30)
        
        fileButton.clicked.connect(self.pictureOpenFunction)
        recognitionButton.clicked.connect(self.recognitionFunction)                         
        quitButton.clicked.connect(self.quitFunction)
        
    def pictureOpenFunction(self):
        fname=QFileDialog.getOpenFileName(self,'강아지 사진 읽기','./')           
        self.img=cv.imread(fname[0])
        if self.img is None: sys.exit('파일을 찾을 수 없습니다.')  
        
        cv.imshow('Dog image',self.img)          
        
    def recognitionFunction(self):
        x=np.reshape(cv.resize(self.img,(224,224)),(1,224,224,3))    
        res=cnn.predict(x)[0]		# 예측
        top5=np.argsort(-res)[:5]
        top5_dog_species_names=[dog_species[i] for i in top5]
        for i in range(5):
            prob='('+str(res[top5[i]])+')'
            name=str(top5_dog_species_names[i]).split('-')[1]
            cv.putText(self.img,prob+name,(10,100+i*30),cv.FONT_HERSHEY_SIMPLEX,0.7,(255,255,255),2)
        cv.imshow('Dog image',self.img)   
        winsound.Beep(1000,500)
                
    def quitFunction(self):
        cv.destroyAllWindows()        
        self.close()
              
app=QApplication(sys.argv) 
win=DogSpeciesRecognition() 
win.show()
app.exec_()

Untitled

Ch9. 인식

profile
안녕하세요😊 컴퓨터비전을 공부하고 있습니다 🙌

0개의 댓글