어느덧 2주차에 접어들었다.
13기에서 아직 공부하던 습관이 남아있어서 1주차 부터 우수혼공족에 당차게 뽑혔다.
(정말로 기쁘기 그지없습니다.)
1주차에 일벌리기 좋아한다는 나의 성향에 족장님이 대차게 오해를 해버리셨다.
내가 말했던 것은 그만큼 혼공학습단이 얻어가는 것이 너무 많아 열심히 할 자신이 없다는 나의 의도가 왜곡이 되어버렸다.
역시 이래서 한국말은 'ㅏ'다르고 'ㅓ'다르다는 말이 이래서 나온게 아닌가 싶다.
1. 패션 상품 이미지 분류하기
저번주에는 딥러닝 모델 중 합성곱신경망의 구조에 대해 알아보았다. 이제는 그 합성곱 신경망을 활용하여 해당 모델의 주특기인 이미지 분류를 해보도록 하자.
(1) 활성화함수
우선 모델을 만들기 전에, 활성화 함수라는 것에 대해 짚고 넘어가자. 활성화 함수란, 뉴런의 출력값을 결정하는 함수이다. 해당 함수를 입력값이 통과하면, 입력된 값에 비선형성을 부여하게 되는데 이는 복잡한 분류/회귀 문제를 해결할 수 있는 장점이 있다.
"선형, 비선형 그게 도대체 뭔데"
선형, 비선형 말은 많이 들어봤지만 이야기가 조금 모호해서 힘들수 있다. 선형/비선형은 수학에서 등장한 개념인데, 선형이라는 것은 영어로 "Linear"라는 단어로, 말 그대로 '직선'이라는 뜻이다. 그럼 반대로 비선형성은 직선이 아닌 것, 쉽게 생각하면 곡선이라는 것이다. 우리는 데이터가 존재하면 그것을 좌표평면상에 점으로 표현할 수 있는데. 그 데이터가 분포한 패턴을 하나의 그래프인 '선'으로 그릴 수 있지 않은가? 수학에서는 이를 수식으로 표현 할 수 있는 소리가 된다. 이때, 만약 데이터를 하나의 '직선' 으로 표현할 수 있다면 '선형'성을 갖고 있다하고, 직선으로 표현이 안되고 곡선으로 표현할 수 있다면 '비선형성'이라고 생각하면된다.
그림을 통해 보면 왼쪽은 직선으로 데이터의 분포를 잘 나타낼 수 있다. 이것이 바로 선형성이다. 그러면 자동으로 오른쪽은 비선형성을 갖는다고 볼 수 있다.
자 다시 딥러닝으로 돌아와서, 세상의 모든 데이터가 직선으로 표현할 수 있다면 좋겠다만, 현실을 비선형성을 지닌 패턴이 더 많다. 그렇기 때문에 이를 제대로 학습하기 위해서는 비선형성을 부여할 수 있는 활성화함수가 도움을 줄 수 있다는 것이다. 모델이 잘 학습이 되었다면, 즉 수식이 잘 만들어졌다면 우리는 데이터를 집어넣는 '딸깍' 한번에 모든 현상을 분류하고 예측할 수 있다는 것이다.
대표적인 활성화 함수로는 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])
(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. 입력값의 왜곡
만약 입력값이 몇몇이 제대로 된것이 아닌 잘린 이미지 등이 들어가 있다면 예측이 조금 어려웠을 수도 있다.
'혼자 공부하는 > 딥러닝' 카테고리의 다른 글
[혼만딥] 1주차_합성곱 신경망으로 패션 상품 이미지 분류하기(1) (2) | 2025.07.06 |
---|