종속 변수가 연속적인 숫자값.
학습데이터의 상태(종속변수)가 변한다.
=> 학습데이터의 상태(종속변수)가 다시 변한다.
BMI지수 학습
class별 확률값
ex. (0.6, 0.3, 0.1)
정형데이터를 대상으로 했다.
이제는 비정형데이터를 대상으로 하려 한다. 인지와 관련된 데이터. 소리, 그림, ...
Artificial 은 생략하는 경우가 많음.
keras Model을 기본으로 생각하면 쉽다.
Layer를 추가한다. input 레이어와 output 레이어 사이에 hidden layer를 추가하는 것.
계층을 많이 주어 깊은 신경망을 만든다고 해서 지은 이름.
이게 곧 Deep Learning이다. 이름만 바꿨다기보단, 이때부터 러닝 기술이 확실히 좋아졌다고 생각하면 된다.
ex. 알파고
Image 데이터는? Image를 DNN을 이용해서 학습하면 좋겠네?
컴퓨터에게는 공간지각능력이 없기 때문에, 이에 대한 데이터를 다 넣어줘야 한다.
이미지는 가로, 세로 pixel의 집합. 2차원이다. 그리고 이미지의 입력은 기본적으로 3차원이다. DNN은 입력이 2차원이라서 차원 수를 맞춰줘야 해.
그래서 이미지 데이터를 2차원에서 1차원으로 바꿔. 가로 세로 데이터를 그냥 한 줄로 쭉 나열하는 거야. 이렇게 하면 1차원 데이터가 되긴 하는데, 공간 데이터가 사라지지? 그래서 이미지 학습에 한계가 있었어.
DNN은 입력이 2차원이라서 이미지 학습에 한계가 있었다. 이를 해결하고자 개발된 게 CNN 알고리즘이다.
여기부터는 Local에서 하지 않고, 구글 colab에서 학습한다.
- 구글 드라이브
- 전에 만들었던 폴더 들어가기 (파이썬 실습)
- 우클릭 - 더보기 - Google Colaboratory (설치 안 되어 있으면 설치부터 하자)
- 왼쪽 메뉴에서 폴더 모양 클릭
- 오른쪽에서는 역삼각형 눌러서
리소스 보기
클릭
- 우측 하단에 '런타임 유형 변경'
기본값으로 'Noun' 이 되어 있다. 이거 느림. GPU로 바꾸자.- 리소스를 다시 계산해준다.
세팅 끝!
일반적인 좌표계. 위쪽 방향이 y축, 오른쪽 방향이 x축이다.
(x, y) 로 표현한다.
이미지는 전용 좌표계가 따로 있다. 오른쪽이 x축인 건 동일한데, 아래가 y축인 게 차이점이다.
(y, x) 으로 표현한다. y축부터 먼저 표시하는 것.
모든 이미지는 3차원이라고 생각하자.
각 픽셀 당 R, G, B 세 개의 데이터가 있다. 각 데이터마다 0~255 즉 2^8 값을 가진다. 24bit로 표현되는데, 이걸 True Color
라고 한다.
그럼 픽셀 당 가로 좌표, 세로 좌표, color데이터 세 개를 모아서 3차원이 되는 것.
R, G, B 값의 평균을 내서 동일한 값을 넣는다.
ex. [10, 150, 20] -> [60, 60, 60]
이 흑백 3차원 데이터를 2차원으로 표현하려면?
가로, 세로 좌표계 안에 color 데이터를 값 하나로 표현하는 것
# from google.colab import drive
# drive.mount('/content/drive')
import numpy as np
from PIL import Image # 이미지처리하기 편한 라이브러리
import matplotlib.pyplot as plt
color_img = Image.open('/content/drive/MyDrive/한국SW산업협회 교육-Java 과정/파이썬 실습/fruits.jpg')
plt.imshow(color_img)
plt.show()
# 우리가 필요한 건 ndarray다.
# numpy를 이용해서 데이터를 뽑아내자.
color_pixel = np.array(color_img)
# pixel 데이터를 이용해도 그림을 그리는 게 가능하다.
plt.imshow(color_pixel)
plt.show()
print('shape : {}'.format(color_pixel.shape))
# 출력
# shape : (426, 640, 3)
# (세로 픽셀 수, 가로 픽셀 수, 차원 수)
# 위의 그림을 흑백으로 바꿔보자.
# 각 pixel의 RGB값을 평균내서 RGB칸에 설정하면 흑백처리된다.
gray_pixel = color_pixel.copy()
for y in range(gray_pixel.shape[0]):
for x in range(gray_pixel.shape[1]):
gray_pixel[y, x] = np.mean(gray_pixel[y,x])
# gray_pixel[y,x] 데이터가 r, g, b 세 개의 데이터이므로 평균을 얻을 수 있다.
plt.imshow(gray_pixel)
plt.show()
print(gray_pixel.shape)
# 흑백 3차원 이미지를 2차원으로 변경
# 3차원이 아니라 2차원 흑백 이미지로 만들어보자.
# 사이즈를 더 줄일 수 있음.
# 이미지 데이터 2차원으로 변경
gray_2d_pixel = gray_pixel[:,:,0]
print(gray_2d_pixel.shape)
# 이미지 출력
plt.imshow(gray_2d_pixel, cmap='gray')
plt.show()
비정형 데이터의 가장 대표적인 데이터 image. 이를 학습하려면 어떻게 하면 좋다?
-> CNN(Convolutional Neural Network)
합성곱
이라고도 부르고, Convnet(컨브넷)
이라고도 부른다.
convolution 연산. conv 연산. 합성곱 연산
f, g 2개의 함수가 있다.
f를 반전, 전이시켜서 g와 곱한 다음, 그 결과를 적분한다.
이거..? 몰라도 돼.
Filter를 한 번 거치면, 보통은 원본 이미지 데이터의 크기가 줄어든다. 대신 filter를 여러 개 사용하여, 합성곱의 결과 데이터들을 여러 개 얻을 수 있다. 이렇게 만들어진 여러 데이터들을 활용하면, 학습의 결과가 좋아지게 되는 것.
# module 불러오기
import numpy as np # numpy 기능
import tensorflow as tf # tensorflow 기능
import matplotlib.pyplot as plt # 그림그리기
import matplotlib.image as img # image 불러오기 위함
없음
# 그림 그리기
# 도화지 준비
fig = plt.figure(figsize=(10,10)) # 가로세로 크기는 inch단위
# 도화지를 위 아래 두 부분으로 나누기
ax1 = fig.add_subplot(1,2,1) # 행 1, 열 2, 순서 1번째
ax2 = fig.add_subplot(1,2,2) # 행 1, 열 2, 순서 2번째
# 이미지 불러오기
ori_image = img.imread('/content/drive/MyDrive/한국SW산업협회 교육-Java 과정/파이썬 실습/girl-teddy.jpg')
ax1.imshow(ori_image)
# 이미지 준비
print(ori_image.shape)
# 출력
# (429, 640, 3)
# 가로pixel, 세로pixel, 채널수
# 입력이미지의 형태
# Conv 연산 함수는 4차원 데이터를 요구한다.
# 따라서 3차원이었던 데이터를 4차원으로 변경해야 한다.
# (1, 429, 640, 3) => (이미지 개수, height, width, color)
input_image = ori_image.reshape((1,) + ori_image.shape)
input_image = input_image.astype(np.float32)
print('Convolution input image.shape : {}'.format(input_image.shape))
# 입력이미지 channel 변경
# (1, 429, 640, 1) => (이미지 개수, height, width, color)
# slicing을 이용하여 첫번째 R(Red) 값만 이용
channel_1_input_image = input_image[:,:,:,0:1] # numpy의 slicing 활용
print('Channel 변경 input_image.shape : {}'.format(channel_1_input_image.shape))
# filter 준비
# filter
# (3,3,1,1) => (filter height, filter width, filter channel, filter 개수)
# filter의 채널은 원본 이미지의 채널과 항상 동일해야 한다.
# 따라서 세 번째 값이 1이 되도록 만든다.
weight = np.array([[[[-1]],[[0]],[[1]]],
[[[-1]],[[0]],[[1]]],
[[[-1]],[[0]],[[1]]]])
# -1 값은 크게 의미 없음.
print('적용할 filter shape : {}'.format(weight.shape))
# Convolution(합성곱) 결과
conv2d = tf.nn.conv2d(channel_1_input_image,
weight,
strides=[1,1,1,1],
padding='VALID').numpy()
print('Convolution 결과 shape : {}'.format(conv2d.shape))
# 출력
# Convolution 결과 shape : (1, 427, 638, 1)
# 원본에 비해 2픽셀씩 줄어들었다.
# 출력하기
# 도화지 준비
fig = plt.figure(figsize=(10,10)) # 가로세로 크기는 inch단위
# 도화지를 위 아래 두 부분으로 나누기
ax1 = fig.add_subplot(1,2,1) # 행 1, 열 2, 순서 1번째
ax2 = fig.add_subplot(1,2,2) # 행 1, 열 2, 순서 2번째
# 이미지 불러오기
ori_image = img.imread('/content/drive/MyDrive/한국SW산업협회 교육-Java 과정/파이썬 실습/girl-teddy.jpg')
t_img = conv2d[0,:,:,:]
ax1.imshow(ori_image)
ax2.imshow(t_img)
fig.tight_layout()
plt.show()
이미지의 특징을 뽑아내서 학습에 좋은 이미지를 만드는 것!
이 때, Filter(kernel 이라고도 함)
에 따라 달라지고, 여러 개의 Filter를 사용하게 되면, 이미지 원본 1개에서 특징만 추출한 이미지 여러 개를 만들 수 있다.
다만, 잘못하면 너무 많은 양의 데이터가 생성된다. (이미지 사이즈가 약간 줄어들긴 하지만...)
-> 이 문제를 해결하기 위해 Image Size를 줄인다.
그리고 이 역할을 담당하는 게 바로 Pooling Layer
다.
CNN에서 가장 많이 사용하는 것은 MAX pooling
이다.
filter가 좋아서, 특징을 잘 뽑아내는 filter를 사용할 경우 더 좋은 결과값을 얻을 것이다. 따라서 가장 좋은 결과값을 얻기 위해 filter를 끊임없이 변경시킨다.
loss계산을 마치고 다시 반복하려 할 때, filter값을 변경시킨다.
우리가 학습을 통해서 갱신시키고, 우리가 얻으려고 하는 값이 바로 filter의 weight 값이다
weight = np.array([[[[-1]],[[0]],[[1]]],
[[[-1]],[[0]],[[1]]],
[[[-1]],[[0]],[[1]]]])
feature map : image에서 filter를 거쳐서, 특징을 뽑아낸 이미지
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib.image as img
fig = plt.figure(figsize=(10,10)) # 가로세로 크기 inch단위
ax1 = fig.add_subplot(1,3,1)
ax2 = fig.add_subplot(1,3,2)
ax3 = fig.add_subplot(1,3,3)
ori_image = img.imread('/content/drive/MyDrive/한국SW산업협회 교육-Java 과정/파이썬 실습/girl-teddy.jpg')
# 첫 번째 그림판에는 이미지 원본 출력
ax1.imshow(ori_image)
# 입력이미지의 형태
# (1, 429, 640, 3) => (이미지 개수, height, width, color)
input_image = ori_image.reshape((1,) + ori_image.shape)
input_image = input_image.astype(np.float32)
print('Convolution input image.shape : {}'.format(input_image.shape))
# 입력이미지 channel 변경
# (1, 429, 640, 1) => (이미지 개수, height, width, color)
# slicing을 이용하여 첫번째 R(Red) 값만 이용
channel_1_input_image = input_image[:,:,:,0:1]
print('Channel 변경 input_image.shape : {}'.format(channel_1_input_image.shape))
# filter
# (3,3,1,1) => (filter height, filter width, filter channel, filter 개수)
# weight = np.random.rand(3,3,1,1)
weight = np.array([[[[-1]],[[0]],[[1]]],
[[[-1]],[[0]],[[1]]],
[[[-1]],[[0]],[[1]]]])
print('적용할 filter shape : {}'.format(weight.shape))
# stride : 1 (가로1, 세로1)
# padding = 'VALID'
conv2d = tf.nn.conv2d(channel_1_input_image,
weight,
strides=[1,1,1,1],
padding='VALID').numpy()
t_img = conv2d[0,:,:,:]
# 2번째 그림판에 convolution한 이미지(특징을 뽑아낸) 출력
ax2.imshow(t_img)
## pooling 처리 ##
# ksize = pooling filter의 크기
pool = tf.nn.max_pool(conv2d,
ksize=[1,3,3,1],
strides=[1,3,3,1],
padding='VALID').numpy()
t_img = pool[0,:,:,:]
# 3번째 그림판에 pooling한 이미지(크기를 줄인) 출력
ax3.imshow(t_img)
fig.tight_layout()
plt.show()
# 여기서 나온 conv2d, pool 설정 코드들은 실제로는 사용되지 않는다.
# 설명을 위해서 명시해본 것.
### 공통 코드 - 데이터 만들기
# module 불러오기
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split # train 데이터와 test 데이터를 분리하기 위함
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Flatten, Dense
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping # 작업 도중 조기 종료시키기
# Raw Data Loading
df = pd.read_csv('/content/drive/MyDrive/한국SW산업협회 교육-Java 과정/파이썬 실습/mnist-train.csv')
display(df.head(), df.shape)
# 출력
# data frame 5 rows × 785 columns
# (42000, 785)
# 우리 데이터는 샘플로 제공된 거라서 결측치, 이상치가 없다.
# 실제로 할 때는 결측치, 이상치 처리를 반드시 해야 한다.
# 데이터 나누기
x_data_train, x_data_test, t_data_train, t_data_test = \
train_test_split(df.drop('label', axis=1, inplace=False),
df['label'],
test_size=0.3)
# 정규화 진행
scaler = MinMaxScaler()
scaler.fit(x_data_train)
x_data_train_norm = scaler.transform(x_data_train)
x_data_test_norm = scaler.transform(x_data_test)
### 첫 번째 Model : Multinomial Classification(머신러닝)
model_1 = Sequential()
model_1.add(Flatten(input_shape=(784,)))
model_1.add(Dense(10, activation='softmax'))
model_1.compile(optimizer=Adam(learning_rate=1e-4),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']) # 정확도를 근간으로 우리 모델을 평가
early_stopping = EarlyStopping(monitor='val_loss',
patience=3, # loss값이 떨어지지 않는 경우 몇 번이나 참을지 설정
verbose=1, # 중간 결과값 화면에 출력
mode='auto', # 정해져있는 값이니 그냥 auto
restore_best_weights=True) # 최적의 값을 얻었을 때 그 값 저장해두기
model_1.fit(x_data_train_norm,
t_data_train,
epochs=2000,
validation_split=0.2,
verbose=1,
batch_size=100,
callbacks=[early_stopping]) # early_stopping값 적용시키기
# 출력
# Epoch 153/2000
# 217/236 [==========================>...] - ETA: 0s - loss: 0.2379 - accuracy: 0.9323Restoring model weights from the end of the best epoch: 150.
# 236/236 [==============================] - 1s 3ms/step - loss: 0.2351 - accuracy: 0.9334 - val_loss: 0.2908 - val_accuracy: 0.9189
# Epoch 153: early stopping
# <keras.callbacks.History at 0x7f51fa9201f0>
### 첫 번째 Model => Multinomial Classification(머신러닝)
# 평가
print(model_1.evaluate(x_data_test_norm, t_data_test))
# 출력
# 394/394 [==============================] - 1s 2ms/step - loss: 0.2813 - accuracy: 0.9222
# [0.28126806020736694, 0.9222221970558167]
### 두 번째 Model : DNN(딥러닝)
model_2 = Sequential()
# input layer
model_2.add(Flatten(input_shape=(784,)))
# hidden layer 추가
# node의 개수는 아무거나 적음. 물론, 더 효과적인 개수에 대해 정리된 것도 있음.
model_2.add(Dense(64, activation='relu'))
model_2.add(Dense(128, activation='relu'))
model_2.add(Dense(32, activation='relu'))
# output layer
model_2.add(Dense(10, activation='softmax'))
model_2.compile(optimizer=Adam(learning_rate=1e-4),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']) # 정확도를 근간으로 우리 모델을 평가
early_stopping = EarlyStopping(monitor='val_loss',
patience=3, # loss값이 떨어지지 않는 경우 몇 번이나 참을지 설정
verbose=1, # 중간 결과값 화면에 출력
mode='auto', # 정해져있는 값이니 그냥 auto
restore_best_weights=True) # 최적의 값을 얻었을 때 그 값 저장해두기
model_2.fit(x_data_train_norm,
t_data_train,
epochs=2000,
validation_split=0.2,
verbose=1,
batch_size=100,
callbacks=[early_stopping]) # early_stopping값 적용시키기
# 출력
# Epoch 49/2000
# 231/236 [============================>.] - ETA: 0s - loss: 0.0462 - accuracy: 0.9884Restoring model weights from the end of the best epoch: 46.
# 236/236 [==============================] - 1s 4ms/step - loss: 0.0464 - accuracy: 0.9884 - val_loss: 0.1412 - val_accuracy: 0.9597
# Epoch 49: early stopping
# <keras.callbacks.History at 0x7f5244a2c4f0>
### 두 번째 Model : DNN(딥러닝)
# 평가
print(model_2.evaluate(x_data_test_norm, t_data_test))
# 출력
# 394/394 [==============================] - 1s 2ms/step - loss: 0.1410 - accuracy: 0.9592
# [0.14098674058914185, 0.9592063426971436]
# 결과 비교
# 첫 번째 : 0.922
# 두 번째 : 0.959
### 세 번째 Model : CNN(딥러닝)
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout
# Conv2D : conv 계산 후 relu 돌리는 레이어
# MaxPooling2D : Max Pooling
# Dropout : 과적합을 피할 수 있게 해주는 것
model_3 = Sequential()
## Feature Extraction(Convolution 처리)
# convolution
model_3.add(Conv2D(filters=32,
kernel_size=(3, 3),
activation='relu',
input_shape=(28, 28, 1)))
# filters=32 : filter의 개수
# 이를 통해, 원본 데이터 1개 당 32개의 변형 데이터를 얻을 수 있다.
# kernel_size=(3,3) : filter(kernel)의 행렬 크기
# input_shape=(28, 28, 1)
# 첫 번째 input은 ㅁ 와 ㅁㅁㅁㅁ 가 합쳐진다.
# 이미지 한 개의 shape을 적으면 된다.
# 28 x 28 사이즈, 채널은 1개짜리
# pooling
model_3.add(MaxPooling2D(pool_size=(2, 2)))
# pool_size=(2, 2) : pooling하는 필터 크기
# 위 내용(conv, pooling)을 원하는 대로 반복
# convolution
model_3.add(Conv2D(filters=64,
kernel_size=(3, 3),
activation='relu'))
# pooling
model_3.add(MaxPooling2D(pool_size=(2, 2)))
# convolution
model_3.add(Conv2D(filters=64,
kernel_size=(3, 3),
activation='relu'))
# input layer
# 이번에는 input_shape을 고정적으로 잡지 않는다.
# 앞단계 설정에 따라 몇 개의 input이 들어올 지 알 수 없기 때문
model_3.add(Flatten())
# hidden layer 추가
# node의 개수는 아무거나 적음. 물론, 더 효과적인 개수에 대해 정리된 것도 있음.
model_3.add(Dense(128, activation='relu'))
# output layer
model_3.add(Dense(10, activation='softmax'))
model_3.compile(optimizer=Adam(learning_rate=1e-4),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']) # 정확도를 근간으로 우리 모델을 평가
early_stopping = EarlyStopping(monitor='val_loss',
patience=3, # loss값이 떨어지지 않는 경우 몇 번이나 참을지 설정
verbose=1, # 중간 결과값 화면에 출력
mode='auto', # 정해져있는 값이니 그냥 auto
restore_best_weights=True) # 최적의 값을 얻었을 때 그 값 저장해두기
# CNN에는 여러 장의 이미지가 들어가기 때문에, 반드시 4차원 데이터를 넣어줘야 한다.
# 따라서 기존에 2차원이었던 데이터 x_data_train_norm 를 4차원으로 바꿔서 사용해야 한다.
model_3.fit(x_data_train_norm.reshape(-1, 28, 28, 1),
t_data_train,
epochs=2000,
validation_split=0.2,
verbose=1,
batch_size=100,
callbacks=[early_stopping]) # early_stopping값 적용시키기
# 출력
# Epoch 27/2000
# 236/236 [==============================] - ETA: 0s - loss: 0.0291 - accuracy: 0.9905Restoring model weights from the end of the best epoch: 24.
# 236/236 [==============================] - 1s 6ms/step - loss: 0.0291 - accuracy: 0.9905 - val_loss: 0.0551 - val_accuracy: 0.9827
# Epoch 27: early stopping
# <keras.callbacks.History at 0x7f5244b457c0>
### 세 번째 Model : CNN(딥러닝)
# 평가
print(model_3.evaluate(x_data_test_norm.reshape(-1, 28, 28, 1),
t_data_test))
# 출력
# 394/394 [==============================] - 1s 3ms/step - loss: 0.0534 - accuracy: 0.9836
# [0.05337640270590782, 0.9835714101791382]
# 결과 비교
# 첫 번째 : 0.922
# 두 번째 : 0.959
# 세 번째 : 0.984
CNN을 이용해서 Model을 학습하면, Image 학습, 예측에 좋은 결과를 얻을 수 있다.
우리가 배운 내용
데이터는 어떠한 형태로 입력해야 할까?
Model은 어떻게 만들까?
-> keras 이용하기
Model 학습, 평가하기
-> keras 이용하기
그러면, 실사 데이터를 이용해서 학습 & 예측하려면 어떻게 해야할까?
많은 양의 실사 이미지 모으기 / 라벨링 / 사이즈 균일하게 리사이징
이러한 번거로움을 줄이기 위한 방법이 전이학습
이다.