Tensorflow 이미지 분류 - CNN (python)
다음은 머신러닝 야학에서 텐서플로우 심화 강의인 <Tensorflow 이미지 분류 - CNN (python)>을 학습하고 요약정리한 내용입니다. 강의 내용을 기반으로 요약하되, 보충 설명이 필요한 경우 <밑바닥부터 시작하는 딥러닝>이라는 책과 Stanford 대학의 <CS231n 2017> 강의를 참고했습니다.
오리엔테이션
이전 기초 수업에서는 "표" 형태의 데이터를 다뤘다면
이번 심화 수업에서는 "이미지" 형태의 데이터를 다룰 예정입니다.
데이터와 차원
데이터에 대해 차원은 두 가지 의미를 가집니다.
• "차원 수"의 의미
- 데이터 공간의 맥락: 변수의 개수
- 데이터 형태의 맥락: 배열의 깊이
이미지 데이터 이해
이미지 데이터를 이해하기 위해 MNIST와 CIFAR10 데이터를 가지고 실습을 진행해봅니다.
• MNIST 이미지 데이터 하나의 "차원 수"
- 데이터 공간의 맥락: 변수의 개수 = 28 * 28 = 784개
- 데이터 형태의 맥락: 배열의 깊이 = (28, 28)로 2차원 형태
# MNIST
(독립, 종속) = tf.keras.datasets.mnist.load_data()
print(독립.shape, 종속.shape) # (60000, 28, 28) (60000,)
• CIFAR10 이미지 데이터 하나의 "차원 수"
- 데이터 공간의 맥락: 변수의 개수 = 32 * 32 * 3 = 3072개
- 데이터 형태의 맥락: 배열의 깊이 = (32, 32, 3)로 3차원 형태
# CIFAR10
(독립, 종속) = tf.keras.datasets.cifar10.load_data()
print(독립.shpae, 종속.shape) # (50000, 32, 32, 3) (50000, 1)
다섯 번째 딥러닝 1 - Flatten
"이미지" 데이터를 "표" 형태의 데이터로 변형해서 학습하는 방법과 딥러닝 모델의 별명이 "특징 자동 추출기"인 이유를 배웁니다.
• 이미지 데이터를 표 형태의 데이터로 변형해서 학습하는 방법
1. 독립변수에 대해 reshape 해주거나
① 과거의 데이터를 준비합니다.
(독립, 종속), _ = tf.keras.datasets.mnist.load_data()
독립 = 독립.reshape(60000, 784)
종속 = pd.get_dummies(종속)
print(독립.shape, 종속.shape)
② 모델의 구조를 만듭니다.
X = tf.keras.layers.Input(shape=[784])
H = tf.keras.layers.Dense(84, activation='swish')(X)
Y = tf.keras.layers.Dense(10, activation='softmax')(H)
model = tf.keras.models.Model(X, Y)
model.compile(loss='categorical_crossentropy', metrics='accuracy')
③ 데이터로 모델을 학습(fit)합니다.
model.fit(독립, 종속, epochs=10)
④ 모델을 이용합니다.
print("Predictions: ", model.predict(독립[0:5]))
2. 아예 flatten layer 쌓기
① 과거의 데이터를 준비합니다.
(독립, 종속), _ = tf.keras.datasets.mnist.load_data()
종속 = pd.get_dummies(종속)
print(독립.shape, 종속.shape)
② 모델의 구조를 만듭니다.
X = tf.keras.layers.Input(shape=[28, 28])
H = tf.keras.layers.Flatten()(X)
H = tf.keras.layers.Dense(84, activation='swish')(H)
Y = tf.keras.layers.Dense(10, activation='softmax')(H)
model = tf.keras.models.Model(X, Y)
model.compile(loss='categorical_crossentropy', metrics='accuracy')
③ 데이터로 모델을 학습(fit)합니다.
model.fit(독립, 종속, epochs=10)
④ 모델을 이용합니다.
print("Predictions: ", model.predict(독립[0:5]))
• 딥러닝 모델의 별명이 "특징 자동 추출기"인 이유
위 슬라이드에서 입력층은 (60000, 784), 은닉층은 (60000, 84), 출력층은 (60000, 10)의 형태입니다. 이때 컴퓨터에게 출력층에서 0~9, 즉 10개의 카테고리로 이미지를 분류하기 위해서 입력층에서 784개의 픽셀 중 가장 좋은 특징을 84개만 찾아달라는 것과 같습니다. 이로 인해 딥러닝이 "특징 자동 추출기"라는 별명을 갖게 되었습니다.
다섯 번째 딥러닝 2 - Conv2D
컨볼루션을 이해하고, 필터를 이해하고, 컨볼루션 연산을 직접 해봅니다.
• 컨볼루션의 이해
1. convolution(합성곱)
특정한 패턴의 특징이 어디서 나타나는지 확인하는 도구
2. feature map(특징맵)
대상 이미지로부터 필터를 통해 특징을 잡아낸 컨볼루션의 결과
특징에 대한 위치 정보가 포함된 지도
★ 컨볼루션 필터 하나가 특징맵 이미지 하나를 만든다!
3. 코드
① 과거의 데이터를 준비합니다.
(독립, 종속), _ = tf.keras.datasets.mnist.load_data()
독립 = 독립.reshape(60000, 28, 28, 1)
종속 = pd.get_dummies(종속)
print(독립.shape, 종속.shape)
② 모델의 구조를 만듭니다.
X = tf.keras.layers.Input(shape=[28, 28, 1])
H = tf.keras.layers.Conv2D(3, kernel_size=5, activation='swish')(X) # 사이즈가 5인 필터 셋 3개 사용
H = tf.keras.layers.Conv2D(6, kernel_size=5, activation='swish')(H) # 사이즈가 5인 필터셋 6개 사용
H = tf.keras.layers.Flatten()(H)
H = tf.keras.layers.Dense(84, activation='swish')(H)
Y = tf.keras.layers.Dense(10, activation='softmax')(H)
model = tf.keras.models.Model(X, Y)
model.compile(loss='categorical_crossentropy', metrics='accuracy')
- 컨볼루션 필터 3개 → 3개의 특징맵 생성 = 3 채널의 특징맵
- 컨볼루션 필터 6개 → 6개의 특징맵 생성 = 6 채널의 특징맵
Tip) "채널"이라는 표현 기억해두기!
③~④ 이하 동일
• 필터의 이해
1. 필터셋은 3차원 형태로 된 가중치의 모음
2. 필터셋 하나는 앞선 레이어의 결과인 "특징맵" 전체를 본다.
3. 필터셋 개수만큼 특징맵을 만든다.
• 컨볼루션 연산
참고로 컨볼루션 연산 시 output size를 결정하는 식은 $\frac{N + 2*P - F}{stride} + 1$
N - input size, P - padding size, F - filter size
여기서는 padding에 대한 정보가 없으니 padding=0, stride=1이므로 output size가 $\frac{8 + 2*0 - 3}{1} + 1 = 6$이다.
다섯 번째 딥러닝 3 - MaxPool2D
pooling의 목적과 pooling 중에서도 max pooling의 연산 방식을 살펴보고 코드로 실습해봅니다.
• pooling
1. 목적
flatten layer 이후에 사용되는 가중치의 수를 작게 유지하기 위해 입력으로 사용할 column 수를 조정하는 것
즉, 학습해야 할 파라미터 수를 줄이기 위해 풀링 사용!
2. 연산 방식(max pooling)
위 슬라이드에서 2x2 필터가 6x6 특징맵을 돌면서 가장 큰 값(max)만 가져옴
Tip) 특징맵에서 값이 클수록 특징이 많이 나타나므로 average pooling보다 max pooling을 사용
3. 코드
① 과거의 데이터를 준비합니다.
(독립, 종속), _ = tf.keras.datasets.mnist.load_data()
독립 = 독립.reshape(60000, 28, 28, 1)
종속 = pd.get_dummies(종속)
print(독립.shape, 종속.shape)
② 모델의 구조를 만듭니다.
X = tf.keras.layers.Input(shape=[28, 28, 1])
H = tf.keras.layers.Conv2D(3, kernel_size=5, activation='swish')(X)
H = tf.keras.layers.MaxPool2D()(H)
H = tf.keras.layers.Conv2D(6, kernel_size=5, activation='swish')(H)
H = tf.keras.layers.MaxPool2D()(H)
H = tf.keras.layers.Flatten()(H)
H = tf.keras.layers.Dense(84, activation='swish')(H)
Y = tf.keras.layers.Dense(10, activation='softmax')(H)
model = tf.keras.models.Model(X, Y)
model.compile(loss='categorical_crossentropy', metrics='accuracy')
③~④ 이하 동일
다섯 번째 딥러닝 완성 - LeNet
지금까지 배운 내용을 바탕으로 MNIST와 Cifar10 dataset에 대해 LeNet을 만들어봅니다.
• MNIST
1. 과거의 데이터를 준비합니다.
(독립, 종속), _ = tf.keras.datasets.mnist.load_data()
독립 = 독립.reshape(60000, 28, 28, 1)
종속 = pd.get_dummies(종속)
print(독립.shape, 종속.shape)
2. 모델의 구조를 만듭니다.
# INPUT 32x32
X = tf.keras.layers.Input(shape=[28, 28, 1])
# C1: feature maps 6@28x28
# MNIST 데이터의 경우 input 자체가 28x28이므로 이를 유지해주기 위해 padding='same'
H = tf.keras.layers.Conv2D(6, kernel_size=5, padding='same', activation='swish')(X)
# S2: f. maps 6@14x14
H = tf.keras.layers.MaxPool2D()(H)
# C2: f. maps 16@10x10
# output size = (input size + 2*padding - filter)/stride + 1 = (14 + 2*0 - 5)/1 + 1 = 10
H = tf.keras.layers.Conv2D(16, kernel_size=5, activation='swish')(H)
# S4: f.maps 16@5x5
H = tf.keras.layers.MaxPool2D()(H)
H = tf.keras.layers.Flatten()(H)
# C5: layer 120
H = tf.keras.layers.Dense(120, activation='swish')(H)
# F6: layer 84
H = tf.keras.layers.Dense(84, activation='swish')(H)
# OUTPUT 10
Y = tf.keras.layers.Dense(10, activation='softmax')(H)
model = tf.keras.models.Model(X, Y)
model.compile(loss='categorical_crossentropy', metrics='accuracy')
3~4. 이하 동일
• Cifar10
1. 과거의 데이터를 준비합니다.
(독립, 종속), _ = tf.keras.datasets.cifar10.load_data()
종속 = pd.get_dummies(종속.reshape(50000))
print(독립.shape, 종속.shape)
2. 모델의 구조를 만듭니다.
# INPUT 32x32
X = tf.keras.layers.Input(shape=[32, 32, 3])
# C1: feature maps 6@28x28
# output size = (input size + 2*padding - filter)/stride + 1 = (32 + 2*0 - 5)/1 + 1 = 28
H = tf.keras.layers.Conv2D(6, kernel_size=5, activation='swish')(X)
# S2: f. maps 6@14x14
H = tf.keras.layers.MaxPool2D()(H)
# C2: f. maps 16@10x10
# output size = (input size + 2*padding - filter)/stride + 1 = (14 + 2*0 - 5)/1 + 1 = 10
H = tf.keras.layers.Conv2D(16, kernel_size=5, activation='swish')(H)
# S4: f.maps 16@5x5
H = tf.keras.layers.MaxPool2D()(H)
H = tf.keras.layers.Flatten()(H)
# C5: layer 120
H = tf.keras.layers.Dense(120, activation='swish')(H)
# F6: layer 84
H = tf.keras.layers.Dense(84, activation='swish')(H)
# OUTPUT 10
Y = tf.keras.layers.Dense(10, activation='softmax')(H)
model = tf.keras.models.Model(X, Y)
model.compile(loss='categorical_crossentropy', metrics='accuracy')
3~4. 이하 동일
내 이미지 사용하기
내 이미지를 사용하여 LeNet을 구성해봅니다.
• 이미지 데이터를 구성하는 방법
• 이미지 데이터를 읽어 들이는 코드의 사용법
1. 과거의 데이터를 내 로컬로부터 이미지를 읽어 들여 준비합니다.
# 라이브러리 로딩
import glob
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
# 이미지 읽어서 데이터 준비하기
paths = glob.glob('./notMNIST_small/*/*.png')
paths = np.random.permutation(paths)
독립 = np.array([plt.imread(paths[i]) for i in range(len(paths))])
종속 = np.array([paths[i].split('/')[-2] for i in range(len(paths))])
print(독립.shape, 종속.shape)
독립 = 독립.reshape(18724, 28, 28, 1)
종속 = pd.get_dummies(종속)
print(독립.shape, 종속.shape)
2~4. 이하 동일
수업을 마치며
수업을 마치며 차원, 특징 자동 추출기, LeNet에 대해 정리해봅니다.
'Deep Learning > Tensorflow' 카테고리의 다른 글
[머신러닝 야학/2기] Tensorflow (python) 수업 정리 (0) | 2021.01.18 |
---|