어느덧 2주차에 접어들었다.

13기에서 아직 공부하던 습관이 남아있어서 1주차 부터 우수혼공족에 당차게 뽑혔다.

(정말로 기쁘기 그지없습니다.)

1주차에 일벌리기 좋아한다는 나의 성향에 족장님이 대차게 오해를 해버리셨다.

족장님 말에서 서운함이 가득 묻어 나오신다. 걱정마요 혼공학습단이 그만큼 매력적이라 끊지 못해 온겁니다.

내가 말했던 것은 그만큼 혼공학습단이 얻어가는 것이 너무 많아 열심히 할 자신이 없다는 나의 의도가 왜곡이 되어버렸다.

역시 이래서 한국말은 'ㅏ'다르고 'ㅓ'다르다는 말이 이래서 나온게 아닌가 싶다.

 

 

1. 패션 상품 이미지 분류하기

저번주에는 딥러닝 모델 중 합성곱신경망의 구조에 대해 알아보았다. 이제는 그 합성곱 신경망을 활용하여 해당 모델의 주특기인 이미지 분류를 해보도록 하자.

 

(1) 활성화함수

 우선 모델을 만들기 전에, 활성화 함수라는 것에 대해 짚고 넘어가자. 활성화 함수란, 뉴런의 출력값을 결정하는 함수이다. 해당 함수를 입력값이 통과하면, 입력된 값에 비선형성을 부여하게 되는데 이는 복잡한 분류/회귀 문제를 해결할 수 있는 장점이 있다.


"선형, 비선형 그게 도대체 뭔데"

선형, 비선형 말은 많이 들어봤지만 이야기가 조금 모호해서 힘들수 있다. 선형/비선형은 수학에서 등장한 개념인데, 선형이라는 것은 영어로 "Linear"라는 단어로, 말 그대로 '직선'이라는 뜻이다. 그럼 반대로 비선형성은 직선이 아닌 것, 쉽게 생각하면 곡선이라는 것이다. 우리는 데이터가 존재하면 그것을 좌표평면상에 점으로 표현할 수 있는데. 그 데이터가 분포한 패턴을 하나의 그래프인 '선'으로 그릴 수 있지 않은가? 수학에서는 이를 수식으로 표현 할 수 있는 소리가 된다. 이때, 만약 데이터를 하나의 '직선' 으로 표현할 수 있다면 '선형'성을 갖고 있다하고, 직선으로 표현이 안되고 곡선으로 표현할 수 있다면 '비선형성'이라고 생각하면된다.

[출처] https://aeir.tistory.com/entry/%EC%84%A0%ED%98%95%EC%84%B1%EA%B3%BC-%EB%B9%84%EC%84%A0%ED%98%95%EC%84%B1

그림을 통해 보면 왼쪽은 직선으로 데이터의 분포를 잘 나타낼 수 있다.  이것이 바로 선형성이다. 그러면 자동으로 오른쪽은 비선형성을 갖는다고 볼 수 있다.


자 다시 딥러닝으로 돌아와서, 세상의 모든 데이터가 직선으로 표현할 수 있다면 좋겠다만, 현실을 비선형성을 지닌 패턴이 더 많다. 그렇기 때문에 이를 제대로 학습하기 위해서는 비선형성을 부여할 수 있는 활성화함수가 도움을 줄 수 있다는 것이다. 모델이 잘 학습이 되었다면, 즉 수식이 잘 만들어졌다면 우리는 데이터를 집어넣는 '딸깍' 한번에 모든 현상을 분류하고 예측할 수 있다는 것이다.

 

대표적인 활성화 함수로는 sigmoid, ReLU, tanh, softmax 함수 등이 있다.

 

(2) LeNet-5 만들기

이제 활성화 함수에 대해 알아 보았으니 본격적으로 LeNet-5 모델을 만들어보자. 우리는 파이썬 Keras 라이브러리를 통해 쉽게 만들수 있으므로 이를 활용하여 만들어 보겠다.

import keras
from keras import layers

lenet5= keras.Sequential()
lenet5.add(layers.Input(shape=(28, 28, 1)))
lenet5.add(layers.Conv2D(filters=6, kernel_size=5, activation='sigmoid', padding='same'))
lenet5.add(layers.AveragePooling2D(pool_size=2))
lenet5.add(layers.Conv2D(filters=16, kernel_size=5, activation='sigmoid'))
lenet5.add(layers.AveragePooling2D(pool_size=2))
lenet5.add(layers.Flatten())

lenet5.add(layers.Dense(units=120, activation='sigmoid'))
lenet5.add(layers.Dense(units=84, activation='sigmoid'))
lenet5.add(layers.Dense(units=10, activation='softmax'))

모델이 잘 만들어졌으니, 요약을 통해 어떻게 구조가 되어있는지 확인해보자.

conv2d_4 🟦 합성곱층 3×3 필터 6개 사용, 특징 추출
average_pooling2d_4 🟩 풀링층 2×2 평균 풀링
conv2d_5 🟦 합성곱층 5×5 필터 16개 사용
average_pooling2d_5 🟩 풀링층 2×2 평균 풀링
flatten_2 - (전처리) 2D → 1D 변환
dense_6 🟨 밀집층 400 → 120
dense_7 🟨 밀집층 120 → 84
dense_8 🟨 밀집층 84 → 10 (출력층)

라고 보면 된다. 각 파라미터는 전시간에 학습을 했으니 코드를 보면 알 수 있다.

 

2. 훈련 데이터 준비하기

(1) MNIST 데이터셋

우리는 만들어진 모델을 MNIST 데이터 셋을 통해 시험해보려고 한다. 해당 데이터 셋은 딥러닝을 처음 배우는 사람들이 자주쓰는 데이터 셋으로 유명한 데이터셋이다. 데이터 크기 및 개수가 동일하나 여러 종류의 옷 이미지들이 있어 활용하기 쉽다는 장점이 있다. 해당 데이터셋은 Keras 라이브러리에 datasets 모듈 아래에 이를 부를 수 있는 함수가 내장되어 있어 이를 활용하자.

(train_input, train_target), (test_input, test_target)= keras.datasets.fashion_mnist.load_data()
print(train_input.shape, train_target.shape) #불러온 데이터셋의 개수를 알수 있다.

#해당 데이터셋에 어떤 이미지가 있는지 확인하기
import matplotlib.pyplot as plt

fig, axs = plt.subplots(1, 10, figsize=(20, 3))
for i in range(10):
    axs[i].imshow(train_input[i], cmap='gray_r')
plt.show()

데이터셋에 어떤 이미지들이 있는지 파악이 됐다. 이제 훈련을 시켜서 모델을 시험해봐야하는데, 들어가기전에 우리는 몇가지 작업이 있다. 바로 타겟이 원-핫 인코딩이 적용되어있는지, 그리고 해당 데이터 마지막 차원에 1을 추가해야한다. 마지막으로는 모델의 최적화를 위해 검증세트가 필요하므로 이를 만들어야한다.

 

일단 먼저 넘파이배열의 reshape() 함수를 이용하여, 마지막 차원에 1을 추가하고 모든 데이터 값을 -1과 1사이의 값으로 변환해주자. 왜냐하면 보통 신경망 모델의 경우 -1과 1사이에서 더 잘 작동하기 때문에 그렇다.

train_input= train_input.reshape(-1, 28, 28, 1)/255.0

이제 검증세트가 필요한데, 이를 만들어보자.

from sklearn.model_selection import train_test_split

train_scaled, val_scaled, train_target, val_target 
	= train_test_split(train_input, train_target, test_size=0.2, random_state=42)

 

(2) 모델 훈련하기

이제 본격적으로 모델을 훈련시켜보자. 이때, 우리는 '콜백' 이라는 것을 먼저 정의하고 훈련을 할 것이다. 콜백은 훈련 과정에서 최상의 모델을 지정하고, 검증세트에 대한 손실이 증가하기전에 조기 종료할 수 있는 장점이 있어 과적합을 방지할 수 있다.

checkpoint_cb= keras.callbacks.ModelCheckpoint('lenet5-model.keras', save_best_only=True)

early_stopping_cb= keras.callbacks.EarlyStopping(patience=2, restore_best_weights=True)

이제 훈련을 시켜보자 이때, 해당 모델에서의 타겟은 정수값이고 다중분류 이므로 손실함수를 'sparse_categorical_crossentropy'를 사용한다. 만약 원핫 인코딩이 되어있다면 'categorical_crossentropy'를 사용하면 된다.

lenet5.compile(loss='sparse_categorical_crossentropy', metrics=['accuracy'])
hist=lenet5.fit(train_scaled, train_target, epochs=20, 
	validation_data=(val_scaled, val_target), callbacks=[checkpoint_cb, early_stopping_cb])

14번째 epoch에서 제일 높은 정확도가 나왔다. 나름 잘 학습한 듯 하다.

(3) 모델 성능 확인하기_기본숙제

이제 모델도 만들었으니 정확하게 모델에 대한 손실과 정확도를 그림으로 그려 성능을 알아보도록 하자.

epochs = range(1, len(hist.history['loss']) + 1)

fig, axs = plt.subplots(1, 2, figsize=(12, 5))
axs[0].plot(epochs, hist.history['loss'])
axs[0].plot(epochs, hist.history['val_loss'])
axs[0].set_xticks(epochs)
axs[0].set_xlabel('Epochs')
axs[0].set_ylabel('Loss')

axs[1].plot(epochs, hist.history['accuracy'])
axs[1].plot(epochs, hist.history['val_accuracy'])
axs[1].set_xticks(epochs)
axs[1].set_xlabel('Epochs')
axs[1].set_ylabel('Accuracy')

plt.show()

 

(4) 추가숙제_예측이 실패한 이유

예측 결과를 조금 살펴봤는데 몇몇은 예측이 실패했다.

이유는 여러가지로 추측할수 있을 듯 하다.

 

1. 모델 구조

-> 우리는 LeNet-5 라는 단순한 모델을 사용했기 때문에, 기울기 소실 문제가 발생하여 예측에 문제가 생길 수 있다.

2. 데이터간 유사성

-> 데이터 이미지 자체가 비슷한 디자인들이 있다. 하여 이러한 부분에서 예측이 실패할 가능성이 있다.

3. 학습 부족 또는 과적합

우리는 콜백으로 EarlyStopping을 지정했는데, 오히려 이것이 학습을 충분하게 하지 못한 원인이 되었거나, 검증은 좋았으나 일반화에 어려움이 있어 테스트에서는 실패했을 수도 잇다.

4. 입력값의 왜곡

만약 입력값이 몇몇이 제대로 된것이 아닌 잘린 이미지 등이 들어가 있다면 예측이 조금 어려웠을 수도 있다.

 

13기 혼공학습단을 끝내면서 과거의 ENTP적 기질로 일벌리는 걸 잘하는 나는 6개월 동안 변한 것이 없는 것 같다.

이렇게 여름 방학을 맞아 14기를 지원하는 것을 보면...

그래도 뭐 어쩌겠나 이미 신청한 것을 하다 보면 또 얻어가는 것과 성취감도 많겠지라는 생각을 하며,

14기 혼공단도 열심히 한번 해보도록 하자.

 

1. 최초의 CNN 모델

합성곱 신경망. 이름을 들으면 참 와닿지 않는다, 아무래도 전공자가 아니라면 해당 이름을 들어본적이 없을 것이다.

그렇다면 요즘 우리가 스마트폰에 없으면 아쉬운 기능인 FaceID 기능은 쉽게 알것이다. 바로 그 기능을 구현시켜주는 것이 CNN, 즉 합성곱 신경망(CNN) 이다.


(1) 최초의 CNN

CNN이 개발되기 전, 초기 형태는 페이스북의 얀 르쿤이 개발한 'LeNet' 이라는 것에 출발했다. 우편서비스에서 우편번호를 자동으로 인식하기 위해 이를 개발한 것인데, 이것이 지금까지 발전되어 우리는 현재 FaceID 등의 기술로 사용하고 있는 것이다.

 

(2) 인공신경망과 합성곱신경망

신경망이라는 단어는 사람의 뇌구조에서 한번쯤 들어 보았을 것이다. 즉, OO신경망 이라는 기술을 사람의 뇌구조를 그대로 본따 만든 기술이라 생각하면 된다. 우리는 일련의 사고과정을 통해 물체를 인식하고, 판단하고, 행동하는 것을 그대로 컴퓨터에서 할 수 있도록 했다는 말이다. 하지만 컴퓨터는 복잡한 인간의 사고과정을 이해할 수는 없으니, 용도와 목적에 따라 따로따로 분리하여 구조화 해두었는데 그 중, 우리가 한번쯤 들어본 '인공신경망(ANN)', 과 '합성곱신경망(CNN)'의 차이를 조금 알아보자.

 


- 인공신경망(Artificial Neural Network)

똑같은 신경망의 구조이지만 인공신경망은 텍스트 분류, 금융데이터 예측에 사용되는 신경망으로써 '입력층-은닉층-출력층' 구조를 거쳐 데이터를 처리한다. 

 

- 합성곱신경망(Convolutional Neural Network)

 이미지 처리를 위해 조금 더 특화한 인공신경망. '입력층-합성곱층-풀링층-밀집층' 의 세분화 된 층들을 거쳐 이미지를 분석하고 패턴을 학습할 수 있다. 

 

[합성곱 신경망 각 층의 역할]

합성곱층 : 이미지의 작은 부분을 스캔하여 핵심 특성을 추출하는 층이며, 합성곱계산을 통해 얻은 출력을 특성 맵이라 한다.

풀링층 : 특성 맵을 축소하여 처리 속도를 높이고 조금 더 중요한 특성에 집중하도록 하는 층

밀집증 : 추출된 특성을 바탕으로 최종 결과 도출하는 층. 추출된 이미지 패턴을 바탕으로 분류 작업 수행


 

2. 합성곱신경망의 층 만들기_[추가숙제]

(1) 합성곱층

파이썬의 Keras 라이브러리를 통해 우리는 쉽게 합성곱신경망의 레이어들을 만들어볼 수 있다. 합성곱레이어는 이미지를 입력으로 받았을 때, 돋보기로 하나하나 살펴보며 패턴을 찾아내는 층이라고 생각하면 된다. 합성곱레이어에서는 대표적인 매개변수를 이해해야한다. '필터 수', '필터 크기', '스트라이드', '패딩' 에 대해 하나씩 살펴보자.

 

- Filter(필터)

필터는 돋보기의 역할에 해당하는 것이라고 보면 쉽다. 그러면 우리는 돋보기를 통해 몇개의 특징을 추출할 것인지, 어떤 크기의 돋보기로 볼 것 인지에 대한 정의를 해주어야하는데, 그것이 바로 필터 수와 필터 크기에 대한 파라미터이다. 

 

- Stride(스트라이드)

스트라이드는 필터가 이동하는 칸 수를 말한다. 말그대로 돋보기가 차례차례 이미지를 훑고 지나갈건데, 하나하나씩 볼건지 몇개씩 건너 뛰면서 볼것인지를 결정해준다. 이때, 적절한 스트라이드를 설정하면 계산량을 줄이면서 중요한 정보를 추출 할 수 있다. 그러나 너무 작거나 크면 계산량이 너무 많아지거나 중요한 정보가 손실될 수 있다.

 

- Padding(패딩)

패딩이라는 것은 필터가 이미지를 훑으면서 가장자리의 정보는 완전히 덮을 수 없다. 이러한 문제로 출력 크기가 작아지고 가장자리에 해당하는 정보가 점점 소실되는데 이러한 점을 보완하는 파라미터이다. 기본적으로 Valid, Same 패딩이 있다.

 

import keras
from keras import layers
import numpy as np

#합성곱층 만들기
conv1= layers.Conv2D(filters=10, kernel_size=(3,3))

#합성곱층의 처리 과정
x = np.random.normal(size=(10, 28, 28, 1))
conv_out = conv1(x)
print(conv_out.shape)

#합성곱층의 파라미터 값에 따른 출력
conv2 = layers.Conv2D(filters=10, kernel_size=(3,3), strides=(2,2))
print(conv2(x).shape)

conv3 = layers.Conv2D(filters=10, kernel_size=(3,3), strides=(2,2), padding='same')
print(conv3(x).shape)

conv4 = layers.Conv2D(filters=10, kernel_size=(3,3), padding='same' )
print(conv4(x).shape)

 

 

(2) 풀링층

풀링레이어는 합성곱레이어에서 만들어진 특징맵을 받아 특징은 그대로 유지하면서 크기를 줄이는 층이다. 컴퓨터에서는 처리해야하는 데이터의 크기가 클수록 비효율적이고 복잡한데 이는 과적합의 위험이 있다. 하여 풀링층은 데이터의 크기를 줄여 계산을 감소시키고 과적합을 방지시킨다. 풀링 방법에는 평균과 최대 풀링 두가지가 있다. 이때 풀링층은 학습되는 가중치가 없어 새로운 특성맵을 만들지 않는다. 즉, 요약과 압충에 집중하는 레이어이다.

 

- 평균 풀링(Average Pooling)

평균 풀링은 지정된 크기의 영역에 있는 평균값을 사용한다.

 

- 최대 풀링(Max Pooling)

평균 풀링은 지정된 크기의 영역에 있는 최댓값을 사용한다.

 

 

(3) 밀집층

밀집층은  추출된 특징을 바탕으로 최종적으로 분류나 회귀등의 예측을 수행한다. 전형적으로 인공신경망처럼 작동하는 층이며 입력과 가중치의 dot product(내적)에 편향을 더하는 방식으로 값을 계산한다. 그리고 해당 값은 활성화 함수를 통해 결과를 마지막으로 조정하여 분류와 회귀를 수행한다.

 

3. 합성곱 연산

필자의 전공은 수학교육과 이므로, 조금 더 합성곱신경망에 대한 자세한 연산방식을 소개하려고 한다.  합성곱은 영어로 Convolution 라 하는데, 이는 수학에서 유용한 연산 방식이다. 합성곱은 다음과 같이 정의된다. 이때 함수 f를 우리가 입력하는 이미지의 값이라 생각하고, g를 커널이라고 생각하면 된다.

 

이때 t는 함수의 입력과 출력의 기준을 의미하는 것의 변수이며, 타우는 입출력을 이어주는 매개변수이다. 이러한 연산방식은 기본적으로 연속적인 값들이 입력(f)으로 주어졌을 때 우리가 적절한 함수 g를 잘 선택하여 컨볼루션 하게 되면 원하는 형태의 연속되는 신호를 출력값을 얻게 된다. 이러한 연산 특징을 이용하여 입력 값에 대하여 원하는 정보만을 추출할 수 있다.

4. [기본숙제] _keras/tensorflow 설치 하기 및 LeNet 그림그리기

+ Recent posts