๋™์•„๋ฆฌ,ํ•™ํšŒ/GDGoC

[AI ์Šคํ„ฐ๋””] Section 8 : CNN & LeNet5

egahyun 2024. 12. 27. 02:03

CNN (Convolutional Neural Network) ์†Œ๊ฐœ

์ด๋ฏธ์ง€ ํ•™์Šต ๊ณผ์ •

1. Pixel ์ •๋ณด ์ธ์‹

  • pixel : 0 ~ 255 ์‚ฌ์ด์˜ ์ •์ˆ˜๊ฐ’์œผ๋กœ ๋น›์˜ ๊ฐ•๋„๋ฅผ ๋‚˜ํƒ€๋ƒ„ (black : 0)
  • ์ปฌ๋Ÿฌ์ด๋ฏธ์ง€ : ํ‘๋ฐฑ ์ด๋ฏธ์ง€ 3์žฅ์œผ๋กœ RGB๋กœ ๊ฒน์ณ์„œ ์ƒ‰์„ ํ‘œํ˜„ํ•˜๊ฒŒ ๋จ

< NN (neural network)๋ฅผ ๊ฑฐ์น˜๋ฉด์„œ ์ด๋ฏธ์ง€์˜ ํŠน์„ฑ์ด ํ•™์Šต๋จ>

 

2. Edge/Simple Shape ํŠน์„ฑ ํ•™์Šต
  ⇒ ์€๋‹‰์ธต์„ ๊ฑฐ์นจ : ๋‹จ์ˆœํ•œ ํŠน์„ฑ(์‚ฌ์„ , ์ˆ˜์ง์„  ๋“ฑ์˜ ํ…Œ๋‘๋ฆฌ ๋“ฑ์„ ํ•™์Šต)

 

3. Complex Shape ํŠน์„ฑ ํ•™์Šต
  ⇒ ์€๋‹‰์ธต ๋‹จ๊ณ„๊ฐ€ ๊นŠ์–ด์ง : ๋‹จ์ˆœํ•œ ํŠน์„ฑ์„ ์กฐํ•ฉํ•œ ๋ณต์žกํ•œ ์‰์ž…์ด ํ•™์Šต๋จ

 

4. ์–ผ๊ตด์ธ์‹์— ํ•„์š”ํ•œ ํŠน์„ฑ ํ•™์Šต

  ⇒ ์ตœ์ข… : ์ „์ฒด ์ธ์‹์— ํ•„์š”ํ•œ ํŠน์„ฑ์„ ํ•™์Šต

 

5. ์–ผ๊ตด์„ ๋ณด๊ณ  ๋ˆ„๊ตฌ์ธ์ง€ ๋ถ„๋ฅ˜ ๊ฐ€๋Šฅ

 

CNN ์ด์ „์˜ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ : 2์ฐจ์› ์ด๋ฏธ์ง€๋ฅผ 1์ฐจ์› ๋ฒกํ„ฐ conversion

  1. reshape(60000, 784) : 60000์žฅ์˜ ์‚ฌ์ง„์„ reshape
  2. ๋ฌธ์ œ์ 
    • ์ด๋ฏธ์ง€์˜ ๊ณต๊ฐ„์ , ์ง€์—ญ์  ํŠน์„ฑ ์ƒ์‹ค
    • fully connected์ด๋ฏ€๋กœ ๊ณ„์‚ฐ๋Ÿ‰ ๊ธ‰์ฆ
      100๋งŒ ํ”ฝ์…€์˜ ๊ฒฝ์šฐ, 1000 x 1000 ์‚ฌ์ง„
      ⇒ ์ปฌ๋Ÿฌ๋ฉด, 3 x 1000 x 1000
      ⇒ ์ด ๊ณ„์‚ฐ : 300๋งŒ ์ฐจ์› x Layer ์ˆ˜ x ๊ฐ Layer์˜ Neuron ์ˆ˜
    • ํ•ด๊ฒฐ : ์ด๋ฏธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํŠน๋ณ„ํ•œ ๊ตฌ์กฐ์˜ NN์ด ํ•„์š” ⇒ CNN

 

CNN์˜ ํŠน๋ณ„ํ•œ ๋ ˆ์ด์–ด

 

Convolutional Layer (ํ•ฉ์„ฑ๊ณฑ์ธต)

01. ํŠน์ง•

  • Image ์ •๋ณด์˜ ๊ณต๊ฐ„์  ์ง€์—ญ ํŠน์„ฑ (Locality) ๋ณด์กด
    ⇒ ์ปค๋„ ์‚ฌ์ด์ฆˆ ๋งŒํผ์˜ patch์˜ ์ธ์ ‘ ํ”ฝ์…€๋“ค์— ๋Œ€ํ•œ ์ƒ๊ด€๊ด€๊ณ„๋ฅผ ๋น„์„ ํ˜• ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•ด Locality ์ถ”์ถœ
    ⇒ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ•„ํ„ฐ ์ ์šฉ์‹œ, ๋‹ค์–‘ํ•œ locality ์ถ”์ถœ ๊ฐ€๋Šฅ
         ( ํ•„ํ„ฐ ๊ฐ๊ฐ์— ํŠน์ง•์„ ์ง์ ‘ ๋ถ€์—ฌํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์—ญ์ „ํŒŒ์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์ตœ์ ํ™”๋จ)
  • Filter (Kernel) ์„ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ํŠน์„ฑ ์ถ”์ถœ
  • Parameter Sharing
    : ์ด๋ฏธ์ง€์˜ ๋ชจ๋“ ํŒจ์น˜๊ฐ€ ๋™์ผํ•œ ์ปค๋„์„ ์ ์šฉํ•˜์—ฌ ๋‹ค์Œ ๋ ˆ์ด์–ด์˜ output ์ถœ๋ ฅํ•œ๋‹ค.
    ⇒ ์žฅ์  : ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ํš๊ธฐ์ ์œผ๋กœ ๊ฐ์†Œ (ํ•™์Šต๋˜๋Š”๊ฒƒ์€ ์ปค๋„๋ฐ–์— ์—†๊ธฐ ๋•Œ๋ฌธ)

02. Kernel : ์Šค์Šค๋กœ ํ•™์Šตํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ, Neural Network์˜ ๊ฒฝ์‚ฌํ•˜๊ฐ•๋ฒ•๊ณผ ์˜ค์ฐจ์—ญ์ „ํŒŒ๋กœ ํ•™์Šต๋œ๋‹ค

03. Convolution (ํ•ฉ์„ฑ๊ณฑ)

  (1) ๋ฐฉ๋ฒ•

  • ์ฒซ๋ฒˆ์งธ image patch ์ƒ์„ฑ
    → kernel ์‚ฌ์ด์ฆˆ์— ๋งž๊ฒŒ input ์ด๋ฏธ์ง€๋ฅผ ์ด๋ฏธ์ง€ ํŒจ์น˜๋กœ ๋งŒ๋“  ๊ฒƒ
    → ๊ฒฐ๊ณผ : 5 = 1x1 + 0x2 + 0x3 + 1x4 (ํŒŒ๋ž‘์ƒ‰ )
  • ํ•œ ํ”ฝ์…€ ์˜ฎ๊ฒจ์„œ, 2๋ฒˆ์งธ ์ด๋ฏธ์ง€ ํŒจ์น˜ ์ƒ์„ฑ
  • ๋๊นŒ์ง€ ๋„๋‹ฌ์‹œ, ํ•œํ”ฝ์…€ ๋‚ด๋ ค๊ฐ€์„œ ๋‹ค์‹œ ์ง„ํ–‰
  • ๋๊นŒ์ง€ ์ง„ํ–‰

 (2)  Padding

     : ํ•ฉ์„ฑ๊ณฑ ์ง„ํ–‰์‹œ, ์ธํ’‹์‚ฌ์ด์ฆˆ๊ฐ€ ์ค„์–ด๋“ค๊ฒŒ ๋˜๋Š”๋ฐ ์ด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•

  • default = no padding
    ⇒ ์ด์œ  : ์ด๋ฏธ์ง€์˜ ๋Œ€๋ถ€๋ถ„์€ ๊ฐ€์šด๋ฐ๊ฐ€ ์ค‘์š”ํ•œ ๊ฒƒ
  • padding์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ (= padding = ”same”) : ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ท€ํ‰์ด์— ์žˆ์–ด ์ •๋ณด์†์‹ค์„ ๋ง‰์•„์•ผํ•˜๋Š” ๊ฒฝ์šฐ
  • ๋ฐฉ๋ฒ• : 4x4 ์ธํ’‹์˜ ๊ฐ€์žฅ์ž๋ฆฌ์— 0 ํ”ฝ์…€์„ ๋„ฃ์–ด 5x5๋กœ ๋งŒ๋“  ํ›„, ํ•ฉ์„ฑ๊ณฑ์„ ์ง„ํ–‰

 (3) Striding

  : ์ด๋ฏธ์ง€ ํŒจ์น˜๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, ์›€์ง์ด๋Š” ์ •๋„ (= ํ•„ํ„ฐ๋ฅผ ์ธํ’‹์—์„œ ์›€์ง์ด๋Š” ๊ฐ„๊ฒฉ์˜ ์ •๋„)

  • ํŠน์ง• : stride๊ฐ€ ํด์ˆ˜๋ก ๊ณ„์‚ฐ์ด ์ค„๊ณ , ์†๋„๊ฐ€ ๋นจ๋ผ์ง€๋‚˜, ์ •๋ณด๊ฐ€ ๋งŽ์ด ์†์‹ค๋˜์–ด ์ •ํ™•๋„๊ฐ€ ๋–จ์–ด์ง
  • ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ : ์ •ํ™•๋„ ๋ณด๋‹จ, ์†๋„๋ฅผ ์ค‘์š”์‹œ ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ / ์ด๋ฏธ์ง€๊ฐ€ ๋„ˆ๋ฌด ํฐ ๊ฒฝ์šฐ
  • ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” 1๋กœ ๋งŽ์ด ํ•จ

(4) ์ปฌ๋Ÿฌ ์ด๋ฏธ์ง€์—์„œ์˜ ํ•ฉ์„ฑ๊ณฑ

  • R, G, B 3๊ฐœ์˜ ์ฑ„๋„๋กœ ๊ตฌ์„ฑ๋œ ์‚ฌ์ง„์˜ ์ฑ„๋„ ๊ฐ๊ฐ์— ํ•„ํ„ฐ๋ฅผ ์ ์šฉ
  • 3๊ฐœ์˜ ํ•ฉ์„ฑ๊ณฑ ๊ฒฐ๊ณผ๋ฅผ ๋”ํ•˜์—ฌ ํ•˜๋‚˜์˜ matrix๋กœ ๋งŒ๋“ญ
  • ๋น„์„ ํ˜• ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๋Š” ๋‹จ๊ณ„๋กœ, relu(matrix + b)๋ฅผ ๊ฑฐ์ณ, output์„ ์ƒ์„ฑํ•œ๋‹ค.

 

Pooling Layer (ํ’€๋ง์ธต)

01. ํŠน์ง•

 - Image data ์˜ ์ •๋ณด ์†์‹ค ์—†๋Š” ์••์ถ• (์ •๋ณด ์†์‹ค์„ ์ตœ์†Œํ™”!) : ์‚ฌ์ด์ฆˆ ์ถ•์†Œ๋จ

   โž” ๊ณ„์‚ฐ๋Ÿ‰ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ถ•์†Œ, ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์ˆ˜ ๊ฐ์†Œ (๊ณผ์ ํ•ฉ ๋ฐฉ์ง€ → ์ผ๋ฐ˜ํ™” ๋Šฅ๋ ฅ์— ๋„์›€๋จ)

 - ๋‰ด๋Ÿฐ์˜ ๊ฐ€์ค‘์น˜๊ฐ€ ์—†์Œ

 - positional Invariance : ํŠน์ • ํ”ฝ์…€์˜ ์ •ํ™•ํ•œ ํฌ์ง€์…˜์— ๋ฏผ๊ฐ๋„๊ฐ€ ์ ์Œ

   โž” ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ’€๋ง์„ ๊ฑฐ์น˜๋ฉด, ๋„“์€ ์˜์—ญ์— ๊ฑธ์ณ์„œ ๊ฐ™์€ ํšจ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•จ

   โž”  ์ด์œ  : ํ’€๋ง์„ ๊ฑฐ์น˜๋ฉด์„œ ์›๋ž˜ ์ด๋ฏธ์ง€์˜ ์—ฌ๋Ÿฌ ๊ฐœ ํ”ฝ์…€์˜ ํŠน์„ฑ์„ 1ํ”ฝ์…€์— ๋‹ด๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ

 

02. ์—ญํ•  : image subsampling

  โž” ์ด๋ฏธ์ง€ ์‚ฌ์ด์ฆˆ๋ฅผ ์ค„์—ฌ๋„, ์ •๋ณด ์†์‹ค์ด ์–ผ๋งˆ ๋˜์ง€ ์•Š์Œ์„ ์ด์šฉํ•œ ๊ฒƒ

 

03. ์ข…๋ฅ˜

 - Average Pooling : ํ‰๊ท ๊ฐ’์„ ๋‚ด, ๊ทธ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ 

 - Max Pooling : ์ตœ๋Œ€๊ฐ’์„ ๊ฐ€์ ธ์˜จ ๊ฒƒ

  โž” ex) 2x2 max pooling with stride 2 : 2x2 ํ”ฝ์…€์„ ์ด๋ฏธ์ง€์— ์ ์šฉํ•ด, 4๊ฐœ์˜ ํ”ฝ์…€ ์ค‘ ์ตœ๋Œ€๊ฐ’ 1๊ฐœ์”ฉ ๋ฝ‘์Œ

 

04. Flattening

 (1) ํ•„์š”ํ•œ ์ด์œ  : ๋งˆ์ง€๋ง‰์—” ๊ผญ fully connected layer/Dense ๋ ˆ์ด์–ด๋ฅผ ๊ฑฐ์ณ์•ผํ•˜๋Š”๋ฐ, ์ด๋“ค์€ ์ž…๋ ฅ์„ 1์ฐจ์›์œผ๋กœ๋งŒ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์—

 (2) ๊ณผ์ •

  • ์ด๋ฏธ์ง€๋ฅผ Flattening ์„ ํ†ตํ•ด 1์ฐจ์›์œผ๋กœ ๋งŒ๋“ฌ
  • fully connected ๋ ˆ์ด์–ด๋กœ ์—ฐ๊ฒฐ๋œ ํžˆ๋“ ๋ ˆ์ด์–ด๋ฅผ ์ง€๋‚จ
  • softmax ํ•จ์ˆ˜๋ฅผ ์ง€๋‚˜, ์ด ์‚ฌ์ง„์ด ์–ด๋–ค ์‚ฌ์ง„์ผ ํ™•๋ฅ ์„ ์ถœ๋ ฅ
  • ๋ถ„๋ฅ˜๋จ

 

๋Œ€ํ‘œ์ ์ธ CNN ๋ชจ๋ธ

AlexNet - 2012 ๋…„ ILSVRC ๋Œ€ํšŒ ์šฐ์Šน
- LeNet์˜ ํ™•์žฅํŒ
GoogleLeNet(Inception Net) - 2014 ๋…„ ILSVRC ๋Œ€ํšŒ ์šฐ์Šน
ResNet - 2015 ๋…„ ILSVRC ๋Œ€ํšŒ ์šฐ์Šน
- 152๊ฐœ์˜ ์ธต : ResNet ๋ถ€ํ„ฐ ๋”ฅํ•ด์ง€๊ธฐ ์‹œ์ž‘
- skip connection์„ ํ†ตํ•ด ์›๋ž˜์˜ ์ •๋ณด๋ฅผ ์žŠ์ง€ ์•Š๊ณ , ํ•™์Šต์„ ์ด์–ด๋‚˜๊ฐˆ ์ˆ˜ ์žˆ์Œ
MobileNet - 1000๊ฐ€์ง€ ํด๋ž˜์Šค๋ฅผ ๋ถ„๋ฅ˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋ฒผ์šด ๋ชจ๋ธ
- mobile device ์šฉ pre-trained model ⇒ ์ „์ดํ•™์Šต ๋ชจ๋ธ ⇒ ํŒŒ์ธํŠœ๋‹ํ•ด์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
VGG-16 - Keras ๋‚ด์žฅ ์‚ฌ์ „ ํ•™์Šต ๋ชจ๋ธ - (2014 ๋…„, 16 layers)

์‹ค์Šต - Deeper CNN์„ ์ด์šฉํ•œ CIFAR-10 ๋ถ„๋ฅ˜

๋ชจ๋ธ

GPU๊ฐ€ ์—ฐ๊ฒฐ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ + ํ…์„œํ”Œ๋กœ์šฐ ๋ฒ„์ „

# GPU ์—ฐ๊ฒฐ ํ™•์ธ
from tensorflow.python.client import device_lib
device_lib.list_local_devices()

# ํ…์„œํ”Œ๋กœ์šฐ ๋ฒ„์ „
import tensorflow as tf
tf.__version__

๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

import numpy as np
from tensorflow.keras.datasets import cifar10

# train, test split
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
# (50000, 32, 32, 3)
# (10000, 32, 32, 3)
# (50000, 1)
# (10000, 1)

# ํด๋ž˜์Šค๋ณ„ ์ด๋ฆ„
cifa10_classes = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']

# ํด๋ž˜์Šค๋ณ„ ์‚ฌ์ง„ ์‹œ๊ฐํ™”
fig, axes = plt.subplots(2, 8, figsize=(15, 4))
axes = axes.ravel()
for i in range(16):
    idx = np.random.randint(0, len(y_train))
    axes[i].imshow(X_train[idx, :])
    axes[i].set_xticks([])
    axes[i].set_yticks([])
    axes[i].set_title(cifa10_classes[y_train[idx, 0]])

# data normalization
X_train_scaled = X_train / 255.
X_test_scaled  = X_test / 255.

# one-hot encoding of class labels
# categorical cross entryopy๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•จ
y_train_onehot = utils.to_categorical(y_train)
y_test_onehot  = utils.to_categorical(y_test)
print(y_train_onehot.shape)
print(y_test_onehot.shape)

# tf.data ๋ฅผ ์ด์šฉํ•œ shuffling and batch ๊ตฌ์„ฑ
# gpu์— ํšจ์œจ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์˜ฌ๋ฆฌ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ (์•ˆํ•ด๋„ ๋‚˜์ค‘์— ๋ณ€ํ™˜๊ณผ์ •์„ ๊ฑฐ์ณ์ง
# ์ด๊ฑฐ ํ•˜๊ธฐ ์ „์€ numpy ๋ฐ์ดํ„ฐ (GPU์—์„œ๋Š” ๋ชป๋Œ์•„๊ฐ€๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…)
# ๊ทธ๋ƒฅ ์ถœ๋ ฅํ•˜๋ฉด ๋ญ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š์Œ
train_ds = tf.data.Dataset.from_tensor_slices((X_train_scaled, y_train_onehot)).shuffle(10000).batch(64)
test_ds  = tf.data.Dataset.from_tensor_slices((X_test_scaled, y_test_onehot)).batch(64)

๋ชจ๋ธ ๊ตฌ์„ฑ

from tensorflow.keras import utils
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Activation, Dropout
from tensorflow.keras.optimizers import Adam
import matplotlib.pyplot as plt

# model build
model = Sequential()

model.add(Conv2D(16, (3, 3), padding='same', input_shape=(32, 32, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D((2,2))) # strides ์ง€์ •์ด ์ƒ๋žต๋จ => pool ์‚ฌ์ด์ฆˆ์™€ ๋™์ผํ•˜๊ฒŒ
model.add(Dropout(0.2)) # 20 % ๋‰ด๋Ÿฐ deactivate

# ์•ž ๋ณด๋‹ค ํ•„ํ„ฐ ์‚ฌ์ด์ฆˆ ๋Š˜๋ ค๊ฐ-> ๊ณ„์† ๋Š˜๋ ค๊ฐ -> ์‚ฌ์ง„ ์‚ฌ์ด์ง€๋Š” maxpooling ๋˜๋ฉฐ ์ž‘์•„์ง€์ง€๋งŒ, ๊ฐœ์ˆ˜๋Š” ๋Š˜์–ด๋‚˜๋„๋ก
model.add(Conv2D(32, (3, 3), padding='same')) 
model.add(Activation('relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Dropout(0.2))

model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D((2,2)))
model.add(Dropout(0.2))

model.add(Flatten()) # Dense ๋ ˆ์ด์–ด์™€ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax')) # ์•„์›ƒํ’‹ ๋ ˆ์ด์–ด์™€ ๋ฐ”๋กœ ์—ด๊ฒฐ / ๋‹ค์ค‘๋ถ„๋ฅ˜์—ฌ์„œ softmax

# ๋ชจ๋ธ ์š”์•ฝ
model.summary()

๋ชจ๋ธ ํ•™์Šต

# model compile : ๋‹ค์ค‘๋ถ„๋ฅ˜์—ฌ์„œ categorical_crossentropy
# Adam์„ ํ•จ์ˆ˜๋กœ ๋ถ€๋ฅด๊ฒŒ ๋˜๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ•™์Šต๋ฅ ๋“ฑ์„ ์ง€์ • ๊ฐ€๋Šฅ
model.compile(loss='categorical_crossentropy', optimizer=Adam(learning_rate=0.001), metrics=['accuracy'])

# ๋ชจ๋ธ ํ•™์Šต
model.fit(train_ds, epochs=5, validation_data=test_ds, verbose=1, shuffle=True)

๋ชจ๋ธ ์˜ˆ์ธก

# [0.9354581832885742, 0.6686000227928162]
model.evaluate(test_ds, verbose=0)

# ํ™•๋ฅ  ๋ถ„ํฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ argmax๋ฅผ ์ด์šฉํ•ด, ๊ฐ€์žฅ ํ™•๋ฅ ์ด ๋†’์€ ์ธ๋ฑ์Šค๊ฐ’ ๋ฐ˜ํ™˜ํ•˜๋„๋ก
# => y_test์™€ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์Œ
y_pred = model.predict(X_test_scaled).argmax(axis=-1)

# y_test๋ฅผ flatten : (10000,1) => (10000,)
y_true = y_test.ravel()

ํ‰๊ฐ€ ์ง€ํ‘œ

cm = confusion_matrix(y_true, y_pred)

array([[734,  25,  51,  21,   5,   6,  10,   8,  93,  47],
       [ 13, 830,   3,   6,   4,   2,   8,   2,  23, 109],
       [ 99,   5, 536,  81,  74,  68,  77,  25,  27,   8],
       [ 41,  14,  79, 478,  46, 162,  94,  29,  27,  30],
       [ 38,   5, 137,  71, 509,  42,  93,  82,  16,   7],
       [ 24,   7,  80, 215,  30, 527,  30,  56,  17,  14],
       [ 10,   7,  50,  64,  34,  14, 797,   3,   9,  12],
       [ 17,   1,  41,  48,  59,  79,  12, 707,   9,  27],
       [ 72,  46,  14,  14,   3,   6,   5,   5, 807,  28],
       [ 32, 118,   6,  14,   7,   3,   7,  15,  37, 761]], dtype=int64)

์ž˜ ๋‚˜์™”๋Š”์ง€ ํ™•์ธ ์‹œ๊ฐํ™” : ๋ญ˜๋กœ ์˜ˆ์ธกํ–ˆ๋Š”์ง€ ํ™•์ธ ๊ฐ€๋Šฅ

fig, axes = plt.subplots(2, 8, figsize=(15, 4))
axes = axes.ravel()

# 16๊ฐœ์˜ ๋ฌด์ž‘์œ„ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•˜์—ฌ ํ‘œ์‹œ
for i in range(16):
    idx = np.random.randint(0, len(y_test))  # ๋ฌด์ž‘์œ„ ์ธ๋ฑ์Šค ์ƒ์„ฑ
    axes[i].imshow(X_test[idx, :])      # ์ด๋ฏธ์ง€ ํ‘œ์‹œ
    axes[i].set_xticks([])                    # x์ถ• ๋ˆˆ๊ธˆ ์ œ๊ฑฐ
    axes[i].set_yticks([])                    # y์ถ• ๋ˆˆ๊ธˆ ์ œ๊ฑฐ
    # ์‹ค์ œ ๋ผ๋ฒจ๊ณผ ์˜ˆ์ธก๋œ ๋ผ๋ฒจ๋กœ ์ œ๋ชฉ ์„ค์ •
    axes[i].set_title("true={} \\npredicted={}".
                      format(cifa10_classes[y_true[idx]], cifa10_classes[y_pred[idx]]))

plt.tight_layout() # ์„œ๋ธŒํ”Œ๋กฏ๋“ค์ด ๊ฒน์น˜์ง€ ์•Š๋„๋ก ๋ ˆ์ด์•„์›ƒ ์กฐ์ •
plt.show() 

Heat Map

plt.figure(figsize=(10,8))

sns.heatmap(cm, annot=True)

plt.xticks(np.arange(10), cifa10_classes, rotation=45, fontsize=12)
plt.yticks(np.arange(10), cifa10_classes, rotation=45, fontsize=12)
plt.xlabel("true class")
plt.ylabel("predicted class")
plt.title('Confusion Matrix')
print('Test Accuracy :', accuracy_score(y_true, y_pred))

 


LesNet 5

01. ์†Œ๊ฐœ

 - 1998๋…„ Yan LeCunn์ด ์ œ์•ˆํ•œ ์ตœ์ดˆ์˜ CNN ๋ชจ๋ธ

 

02. ๊ตฌ์กฐ

- 2, 4, 7, 8, 9 : 5๊ฐœ์˜ ์ธต์„ ๊ฐ€์ง (ํ•™์Šต๋˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์žˆ๋Š” ์ธต) 

  1. input image : 32x32์˜ ํ‘๋ฐฑ ์ด๋ฏธ์ง€
  2. convolution filter : 5x5์˜ 6์žฅ์˜ ํ•„ํ„ฐ ⇒ ๊ฒฐ๊ณผ : 28x28x6
  3. pooling : average pooling (2x2 / stride 2) ⇒ ๊ฒฐ๊ณผ : 14x14x6
  4. convolution filter : 5x5์˜ 16์žฅ์˜ ํ•„ํ„ฐ ⇒ ๊ฒฐ๊ณผ : 10x10x16
  5. pooling : average pooling (2x2 / stride 2) ⇒ ๊ฒฐ๊ณผ : 5x5x16 (5x5 ์‚ฌ์ด์ฆˆ์˜ ์‚ฌ์ง„ 16)
  6. flattening : 400x1 ๋ฒก(1655=400)
  7. Dense layer : 120๊ฐœ์˜ ๋‰ด๋Ÿฐ ⇒ ๊ฒฐ๊ณผ : fully connected ๋ ˆ์ด์–ด ์ƒ์„ฑ
  8. Dense layer : 84๊ฐœ์˜ ๋‰ด๋Ÿฐ
  9. output layer : 10๊ฐœ์˜ ๋‰ด๋Ÿฐ ⇒ ๊ฒฐ๊ณผ : 10๊ฐœ ์ค‘ ํ•˜๋‚˜๋กœ ๋ถ„๋ฅ˜ํ•˜๋Š” ๋ชจ๋ธ

03. ์‹ค์Šต : MNIST ๋ฐ์ดํ„ฐ์…‹์„ ์ด์šฉํ•œ ๋ชจ๋ธ ๊ตฌ์ถ•

๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋ฐ ์ •์ œ

from tensorflow.keras.datasets import mnist

# ์ž๋™์œผ๋กœ ํŒŒ์ด์ฌ์˜ ํŠœํ”Œ ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚˜๋ˆ 
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# ํด๋ž˜์Šค ๋ณ„ ๊ทธ๋ฆผ
plt.figure(figsize=(5,5))
for i in range(9):
    plt.subplot(3, 3, i+1)
    plt.imshow(X_train[i], cmap='gray', interpolation='none') # default : color
    plt.title("Class {}".format(y_train[i]))
    plt.xticks([])
    plt.yticks([])
plt.tight_layout()
plt.show()

# simple scailing : ์ตœ๋Œ€๊ฐ’์œผ๋กœ ๋‚˜๋ˆ  0 ~ 1 ์‚ฌ์ด๋กœ pixel ๊ฐ’์„ scale
X_train_scaled = X_train / 255.
X_test_scaled = X_test / 255.
X_train_scaled.shape, X_test_scaled.shape # ((60000, 28, 28), (10000, 28, 28))

# Conv2D layer ์˜ ์ž…๋ ฅ ์‚ฌ์–‘์— ๋งž์ถ”์–ด 3 dimension ์œผ๋กœ ์ฐจ์› ์ฆ๊ฐ€ : ํ‘๋ฐฑ์ด๋ฏ€๋กœ 1 (์ปฌ๋Ÿฌ๋ฉด 3)
X_train_scaled = np.expand_dims(X_train_scaled, axis=3)
X_test_scaled = np.expand_dims(X_test_scaled, axis=3)
X_train_scaled.shape, X_test_scaled.shape # ((60000, 28, 28, 1), (10000, 28, 28, 1))

# ๋ ˆ์ด๋ธ”์„ one hot encoding ํ•ด์คŒ -> categorical cross entryopy๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•จ
# (60000, 10) (10000, 10)
y_train_onehot = tf.keras.utils.to_categorical(y_train)
y_test_onehot = tf.keras.utils.to_categorical(y_test)

# tf.data ๋ฅผ ์ด์šฉํ•œ shuffling and batch ๊ตฌ์„ฑ
# gpu์— ํšจ์œจ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์˜ฌ๋ฆฌ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ (์•ˆํ•ด๋„ ๋‚˜์ค‘์— ๋ณ€ํ™˜๊ณผ์ •์„ ๊ฑฐ์ณ์ง
# ์ด๊ฑฐ ํ•˜๊ธฐ ์ „์€ numpy ๋ฐ์ดํ„ฐ (GPU์—์„œ๋Š” ๋ชป๋Œ์•„๊ฐ€๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…)
# ๊ทธ๋ƒฅ ์ถœ๋ ฅํ•˜๋ฉด ๋ญ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š์Œ
train_ds = tf.data.Dataset.from_tensor_slices((X_train_scaled, y_train_onehot)).shuffle(10000).batch(128) # ํŠœํ”Œ ํ˜•ํƒœ๋กœ ์ž…๋ ฅํ”ผ์ฒ˜, ๋ ˆ์ด๋ธ” ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์Œ 
test_ds  = tf.data.Dataset.from_tensor_slices((X_test_scaled, y_test_onehot)).batch(128) # shuffle ํ•„์š” ์—†์Œ -> test์— ๊ตณ์ด,,,,!

# ์ถœ๋ ฅ ๋ฐฉ๋ฒ• : for๋ฌธ ์‚ฌ์šฉ
for x, y in train_ds :
	print(X)

LeNet ๊ตฌ์„ฑ

model = tf.keras.Sequential()

model.add(Conv2D(6, kernel_size=5, padding="same", input_shape=(28, 28, 1))) # ํŒจ๋”ฉ ์ ์šฉ
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

model.add(Conv2D(16, kernel_size=5, padding="valid"))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

model.add(Flatten())
model.add(Dense(120))
model.add(Activation ('relu'))

model.add(Dense(84))
model.add(Activation ('relu'))

model.add(Dense(10))
model.add(Activation ('softmax')) # ๋‹ค์ค‘๋ถ„๋ฅ˜์ด๋ฏ€๋กœ softmax

model.summary()
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                      Output Shape              Param #   
=================================================================
 conv2d_4 (Conv2D)                (None, 28, 28, 6)         156                                                                 
 activation_4 (Activation)        (None, 28, 28, 6)         0                                                                        
 max_pooling2d_2 (MaxPooling 2D)  (None, 14, 14, 6)         0                                                                                                                                       
 conv2d_5 (Conv2D)                (None, 10, 10, 16)        2416                                                                      
 activation_5 (Activation)        (None, 10, 10, 16)        0                                                                          
 max_pooling2d_3 (MaxPooling 2D)  (None, 5, 5, 16)          0                                                                                                                                       
 flatten_1 (Flatten)              (None, 400)               0                                                                          
 dense_2 (Dense)                  (None, 120)               48120                                                                     
 activation_6 (Activation)        (None, 120)               0                                                                         
 dense_3 (Dense)                  (None, 84)                10164                                                                     
 activation_7 (Activation)        (None, 84)                0                                                                         
 dense_4 (Dense)                  (None, 10)                850                                                                       
 activation_8 (Activation)        (None, 10)                0                                                                         
=================================================================
Total params: 61,706
Trainable params: 61,706
Non-trainable params: 0

# ๋ชจ๋ธ ์ปดํŒŒ์ผ
model.compile(loss="categorical_crossentropy", optimizer='adam', metrics=['accuracy'])

๋ชจ๋ธ ํ›ˆ๋ จ ๋ฐ ์˜ˆ์ธก

# ์œ„์—์„œ train_ds๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉฐ ๋ฐฐ์น˜์‚ฌ์ด์ฆˆ ๋“ฑ์„ ๋งž์ถฐ๋†“์•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•„์š”์—†์Œ
history = model.fit(train_ds, epochs=5, validation_data=test_ds)
                    
score = model.evaluate(test_ds, verbose=0)
print("Test loss ", score[0]) # Test loss  0.037596870213747025
print("Test Accuracy ", score[1]) # Test Accuracy  0.9873999953269958

y_pred = model.predict(X_test_scaled).argmax(axis=1)

# ๋ชจ๋ธ ํ›ˆ๋ จ ๊ฒฐ๊ณผ ์‹œ๊ฐํ™” : ๊ณผ์ ํ•ฉ์ด ์ผ์–ด๋‚ฌ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•จ
plt.figure(figsize=(12,4))
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('model accuracy')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.legend(['train', 'test'])

plt.subplot(1, 2, 2)
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'test']

์˜ˆ์ธก ๊ฒฐ๊ณผ ํ™•์ธ ๋ฐ ์‹œ๊ฐํ™”

from sklearn.metrics import confusion_matrix, accuracy_score

# Test Accuracy : 0.985
print('Test Accuracy :', accuracy_score(y_test, y_pred))

# ํ˜ผ๋™ํ–‰๋ ฌ ๊ทธ๋ƒฅ ์ถœ๋ ฅ
print(confusion_matrix(y_test, y_pred))

# ํ˜ผ๋™ํ–‰๋ ฌ ์‹œ๊ฐํ™”
plt.figure(figsize=(7,6))
sns.heatmap(confusion_matrix(y_test, y_pred), annot=True, fmt='d')
plt.xticks(np.arange(10), list(range(10)), rotation=45, fontsize=12)
plt.yticks(np.arange(10), list(range(10)), rotation=45, fontsize=12)
plt.xlabel("predicted class")
plt.ylabel("true class")
plt.title('Confusion Matrix')

 

04. ์‹ค์Šต : Fashion MNIST ๋ฐ์ดํ„ฐ์…‹์„ ์ด์šฉํ•œ ๋ชจ๋ธ ๊ตฌ์ถ•

๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋ฐ ์ •์ œ

(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.fashion_mnist.load_data()

class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 
               'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

# ๋ฐ์ดํ„ฐ ์˜ˆ์‹œ ์‹œ๊ฐํ™”
plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    plt.xlabel(class_names[train_labels[i]])
    plt.xticks([])
    plt.yticks([])

X_train = train_images / 255.0
X_test  = test_images / 255.0

# Conv2D layer ์˜ ์ž…๋ ฅ ์‚ฌ์–‘์— ๋งž์ถ”์–ด 3 dimension ์œผ๋กœ ์ฐจ์› ์ฆ๊ฐ€
X_train_scaled = np.expand_dims(X_train_scaled, axis=3)
X_test_scaled = np.expand_dims(X_test_scaled, axis=3)
X_train_scaled.shape, X_test_scaled.shape # ((60000, 28, 28, 1), (10000, 28, 28, 1))

# ๋ ˆ์ด๋ธ”์„ one hot encoding : (60000, 10) (10000, 10)
y_train_onehot = tf.keras.utils.to_categorical(y_train)
y_test_onehot = tf.keras.utils.to_categorical(y_test)

# tf.data ๋ฅผ ์ด์šฉํ•œ shuffling and batch ๊ตฌ์„ฑ
train_ds = tf.data.Dataset.from_tensor_slices((X_train_scaled, y_train_onehot)).shuffle(10000).batch(128) # ํŠœํ”Œ ํ˜•ํƒœ๋กœ ์ž…๋ ฅํ”ผ์ฒ˜, ๋ ˆ์ด๋ธ” ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์Œ 
test_ds  = tf.data.Dataset.from_tensor_slices((X_test_scaled, y_test_onehot)).batch(128) # shuffle ํ•„์š” ์—†์Œ -> test์— ๊ตณ์ด,,,,!

๋ชจ๋ธ ๊ตฌ์„ฑ

# LeNet model ๊ตฌ์„ฑ
# kernel ์‚ฌ์ด์ฆˆ๋ฅผ ์ค„์ด๊ณ  convolution ์ธต ํ•œ๋ฒˆ ๋” ๋Š˜๋ฆผ
model = tf.keras.Sequential()

model.add(Conv2D(6, kernel_size=3, padding="same", input_shape=(28, 28, 1))) # ํŒจ๋”ฉ ์ ์šฉ
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

model.add(Conv2D(16, kernel_size=3, padding="valid"))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

model.add(Conv2D(32, kernel_size=3, padding="valid"))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

model.add(Flatten())
model.add(Dense(120))
model.add(Activation ('relu'))

model.add(Dense(84))
model.add(Activation ('relu'))

model.add(Dense(10))
model.add(Activation ('softmax')) # ๋‹ค์ค‘๋ถ„๋ฅ˜์ด๋ฏ€๋กœ softmax

model.summary()
Model: "sequential_1"
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ Layer (type)                         โ”ƒ Output Shape                โ”ƒ         Param # โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ conv2d (Conv2D)                      โ”‚ (None, 28, 28, 6)           โ”‚              60 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ activation (Activation)              โ”‚ (None, 28, 28, 6)           โ”‚               0 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ max_pooling2d (MaxPooling2D)         โ”‚ (None, 14, 14, 6)           โ”‚               0 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ conv2d_1 (Conv2D)                    โ”‚ (None, 12, 12, 16)          โ”‚             880 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ activation_1 (Activation)            โ”‚ (None, 12, 12, 16)          โ”‚               0 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ max_pooling2d_1 (MaxPooling2D)       โ”‚ (None, 6, 6, 16)            โ”‚               0 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ conv2d_2 (Conv2D)                    โ”‚ (None, 4, 4, 32)            โ”‚           4,640 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ activation_2 (Activation)            โ”‚ (None, 4, 4, 32)            โ”‚               0 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ max_pooling2d_2 (MaxPooling2D)       โ”‚ (None, 2, 2, 32)            โ”‚               0 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ flatten (Flatten)                    โ”‚ (None, 128)                 โ”‚               0 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ dense (Dense)                        โ”‚ (None, 120)                 โ”‚          15,480 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ activation_3 (Activation)            โ”‚ (None, 120)                 โ”‚               0 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ dense_1 (Dense)                      โ”‚ (None, 84)                  โ”‚          10,164 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ activation_4 (Activation)            โ”‚ (None, 84)                  โ”‚               0 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ dense_2 (Dense)                      โ”‚ (None, 10)                  โ”‚             850 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ activation_5 (Activation)            โ”‚ (None, 10)                  โ”‚               0 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
 Total params: 32,074 (125.29 KB)
 Trainable params: 32,074 (125.29 KB)
 Non-trainable params: 0 (0.00 B)
 
# model compile 
model.compile(loss="categorical_crossentropy", optimizer='adam', metrics=['accuracy'])

๋ชจ๋ธ ํ›ˆ๋ จ ๋ฐ ์˜ˆ์ธก ๋ฐ ๊ฒฐ๊ณผ

# ๋ชจ๋ธ ํ•™์Šต
history = model.fit(train_ds, epochs=5, validation_data=test_ds)
                    
score = model.evaluate(test_ds, verbose=0)
print("Test loss ", score[0]) # Test loss 
print("Test Accuracy ", score[1]) # Test Accuracy

y_pred = model.predict(X_test_scaled).argmax(axis=1)

# ๋ชจ๋ธ ํ›ˆ๋ จ ๊ฒฐ๊ณผ ์‹œ๊ฐํ™”
plt.figure(figsize=(12,4))
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('model accuracy')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.legend(['train', 'test'])

plt.subplot(1, 2, 2)
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'test']

ํ˜ผ๋™ํ–‰๋ ฌ ์‹œ๊ฐํ™”

# confusion matrix ์‹œ๊ฐํ™”
cm = confusion_matrix(y_test, y_pred)
ax = sns.heatmap(cm, annot=True, fmt='d')
plt.figure(figsize=(7,6))
ax.set_xticklabels(class_names,  rotation=45, fontsize=12)
ax.set_yticklabels(class_names,  rotation=45, fontsize=12)
ax.set_xlabel("predicted class")
ax.set_ylabel("true class")