손글씨 숫자 이미지 분류(MNIST)
MNIST 데이터셋에서 숫자 이미지를 불러와 해당 이미지의 숫자를 분류해보자.
우선 데이터셋을 로드하고 데이터들을 분류한 뒤 시각화 해보자.
import matplotlib.pyplot as plt
import tensorflow as tf
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()
print(train_images.shape) # (60000, 28, 28)
print(train_labels.shape) # (60000,)
print(test_images.shape) # (10000, 28, 28)
print(test_labels.shape) # (10000,)
print(28 * 28) # 784
plt.imshow(train_images[0], cmap="Greys")
plt.show()
print(train_labels[8])
이미지 데이터를 파악하기 위해 학습 데이터와 테스트 데이터의 형태를 출력해보았다.
또한 8번째 이미지의 실제 숫자 레이블을 출력해보았다.
그 결과 6만개의 28x28 픽셀 이미지를 가지고 있음을 알 수 있으며, 8번째 이미지의 실제 숫자 레이블이 1임을 알 수 있다.
이제 모델을 구축해야 한다.
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(512, activation='relu', input_shape=(784,), name='Layer1'))
model.add(tf.keras.layers.Dense(10, activation='sigmoid', name='OUTPUT'))
model.summary()
Sequential 모델을 생성하고 두개의 층을 추가했다.
은닉층에는 512개의 뉴런을 배치했고, 활성화 함수로는 relu를 사용하였으며, 입력의 갯수는 784(28*28)개로 설정하였다.
또한, 출력층에는 10개의 뉴런을 배치하였는데 이는 0~9까지의 입력 이미지 중 예측값이 가장 큰 값을 가진 뉴런이 최종 예측 클래스가 되므로 총 10개의 뉴런이 필요하다.
그렇게 구축한 모델 구조를 확인해보자.
정상적으로 레이어가 생성되었다.
이제 모델을 구축했으니 컴파일을 할 차례이다.
컴파일 과정에서 손실 함수로 MSE을 사용하고, 최적화 알고리즘으로 RMSprop을 사용하였다.
추가로, 정확도를 파악하기 위해 정확도 평가 지표를 사용하였다.
# 모델 컴파일
model.compile(optimizer='rmsprop', loss='mse', metrics=['accuracy'])
컴파일 이후에 할 과정은 각 데이터의 전처리 과정을 거쳐야 한다.
전처리 과정을 거쳐야 하는 이유는 아래 사진으로 확인해보자.
학습 데이터는 2차원 텐서로 설정하는게 좋다.
그러나 해당 데이터에서는 28*28 픽셀을 나타내기 위해 28, 28이 이차원 배열로 설정되어 있다.
그러므로 28 28을 1차원 배열로 변경하여 총 학습 데이터의 텐서를 2차원으로 맞춰주는 과정이 필요하다.
해당 과정은 reshape() 함수를 사용한다.
그리고 정규화를 통해 경사하강법의 수렴 속도를 올려 학습 속도를 올려주어야 한다.
MNIST의 픽셀은 0부터 255 사이의 정수로 표현된다.
그럼 255을 255.0으로 실수형으로 바꾸고 나누게 되면 어떻게 될까?
0~1 사이의 실수로 표현이 가능해진다.
위 같은 과정을 정규화 라고 한다.
또한 MNIST 데이터셋의 레이블은 0~9까지의 숫자이다.
그러므로 해당 숫자에 맞는 레이블을 벡터로 표현하기 위해 원-핫 인코딩을 사용하였다.
원-핫 인코딩은 3이라는 레이블을 [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]로 변환한다.
그 전에는 일일이 수작업으로 라벨링 작업을 수행했지만, 원-핫 인코딩을 통한 라벨링은 굉장히 간단하다.
# 원-핫 인코딩
변수명 = tf.keras.utils.to_categorical(데이터)
위 방식으로 코드를 작성하여 데이터를 원-핫 인코딩으로 라벨링 할 수 있다.
이제 방식을 알았으니 코드를 작성해보자.
# 훈련 데이터 2차원 텐서로 변환
train_images = train_images.reshape((60000, 784))
train_images = train_images.astype('float32') / 255.0
test_images = test_images.reshape((10000, 784))
test_images = test_images.astype('float32') / 255.0
# 데이터 라벨링을 위한 원-핫 인코딩
train_labels = tf.keras.utils.to_categorical(train_labels)
test_labels = tf.keras.utils.to_categorical(test_labels)
학습을 위한 준비작업을 모두 마쳤다.
이제 본격적으로 데이터를 학습시켜보자.
에포크 수는 5, 배치 크기는 128로 설정하였다.
학습 조건을 설정할 때는 가장 효율적인 환경을 알지 못한다.
그렇기에 다양한 시도를 통해 가장 맞는 환경을 설정해 주어야 한다.
# 모델 훈련
model.fit(train_images, train_labels, epochs=5, batch_size=128)
이제 훈련 결과를 확인해보자.
훈련 결과를 확인하는 방법도 존재한다.
# 훈련 결과 평가
변수명 = 모델명.evaluate(데이터)
여기서 어떤 데이터를 평가 하느냐에 따라 평가 값이 달라진다.
테스트 데이터를 평가하면 손실률이, 정답 테스트 데이터를 평가하면 정확도를 측정할 수 있다.
평가코드는 아래와 같다.
# 모델 평가 측정
test_loss, test_acc = model.evaluate(test_images, test_labels)
print('테스트 정확도:', test_acc)
이제는 모델의 손실률과 정확도를 시각화 해볼 예정이다.
더 정확한 측정을 하기 위해서 모델을 다시 한번 학습시켜 시각화를 진행하였다.
# 모델 재훈련
history = model.fit(train_images, train_labels, epochs=5, batch_size=128)
# 손실률 및 정확도 저장
loss = history.history['loss']
acc = history.history['accuracy']
epochs = range(1, len(loss) + 1)
# 데이터 시각화
plt.plot(epochs, loss, 'b', label='Training Loss')
plt.plot(epochs, acc, 'r', label='Accuracy')
plt.xlabel('epochs')
plt.ylabel('loss/acc')
plt.show()
높은 정확도와 낮은 손실률을 기록했다.
에포크가 점점 커질때마다 미세하지만 정확도가 올라감을 확인할 수 있다.
내가 쓴 글씨 예측하기
이제 학습한 모델을 가지고 내가 그린 숫자를 맞춰보려고 한다.
위 사진을 모델에 의해 평가하기 전 마찬가지로 전처리 과정을 거쳐야 한다.
파일 불러오고, 크기 줄이고, 정규화를 수행해야 한다는 말이다.
import cv2
# 사진 불러오기
image = cv2.imread(filename='/Users/ansejun/Desktop/Python3/ABC/4주차/number.png', flags=cv2.IMREAD_GRAYSCALE)
# 크기 조절하기
image = cv2.resize(src=image, dsize=(28, 28))
# 정규화
image = image.astype('float')
image = image.reshape(1, 28 * 28)
image = 255 - image
image /= 255.0
# 전처리 한 사진 시각화
plt.imshow(image.reshape(28, 28), cmap='Grays')
plt.show()
# 데이터 예측
pred = model.predict(image.reshape(1, 28 * 28), batch_size=1)
print(f'추정된 숫자 : {pred.argmax()}')
위 코드로 데이터를 시각화 하였을 때 과연 어떤 출력이 나올까?
전처리 후에 위와 같은 사진이 나오게 되었다.
이제 위 데이터를 예측한 결과는 어떻게 나올까?
놀랍게도 틀렸다.
내가 학습을 잘못한건지, 아니면 쟤가 멍청한건지 모르겠다.
비록 틀렸지만, 그래도 5랑 2랑 비슷하니까 컴퓨터도 헷갈릴 수 있겠지요.
Keras 기본 개념
딥러닝에 대해 다시 한번 개념을 적립하고 다음 단계로 넘어가려고 한다.
간단하게 Keras에서 사용하는 메서드들에 대해 알아보자.
Sequential 모델의 주요 메소드
1. compile(optimizer, loss=None, metrics=None)
- 모델을 훈련시키기 위한 구성 메서드
- optimizer : 최적화 알고리즘 (Ex. adam, sgd...)
- loss : 손실함수 (Ex. mse, binary_crossentropy...)
- metrics : 성능 평가 기준 (Ex. ['accuracy'])
2. fit(x=None, y=None, batch_size=None, epochs=1, verbose=1)
- 모델을 훈련하는 메서드
- x : 입력 데이터
- y : 정답 데이터
- batch_size : 배치 크기
- epochs : 훈련 반복 횟수
- verbose : 훈련 과정의 출력 모드
3. evaluate(x=None, y=None)
- 테스트 데이터로 모델의 성능을 평가하는 메서드
- x : 테스트 입력 데이터
- y : 테스트 정답 데이터
4. predict(x, batch_size=None)
- 입력 샘플에 대한 예측값을 생성하는 메서드
- x : 입력 데이터
- batch_size : 배치 사이즈
5. add(layer)
- 모델에 레이어를 추가하는 메서드
- layer : 추가할 레이어 객체
레이어 클래스
1. Input(shape, batch_size, name)
- 입력을 받아서 Keras 텐서를 생성하는 객체
- shape : 입력 데이터의 형태
- batch_size : 배치 크기
- name : 이름
2. Dense(units, activation=None, use_bias=True, input_shape)
- 유닛들이 전부 연결된 레이어
- units : 뉴런의 수
- activation : 활성화 함수 (Ex. relu, sigmoid)
- use_bias : 바이어스 항 사용여부
- input_shape : 입력 데이터의 형태(첫 레이어에서만 사용)
비선형 회귀 모델
비선형 데이터를 모델에 학습시켜 비선형 실제 데이터와 예측 데이터를 시각화 해보려고 한다.
데이터 불러오기
데이터가 담긴 csv파일을 불러오려고 한다.
import pandas as pd
df = pd.read_csv(filepath_or_buffer='nonlinear.csv')
print(df.head())
csv 파일의 상단 데이터를 확인해보자.
CSV 확인 결과 데이터가 해당 형태로 들어있음을 확인할 수 있다.
위 데이터들을 시각화하여 확인해보자.
plt.scatter(df['x'], df['y'], )
plt.show()
한눈에 봐도 비선형으로 선형이 나올것 같은 불친절한 데이터처럼 보인다.
이제 해당 데이터를 잘 활용해보자.
데이터 전처리
이제 해당 데이터셋에 담긴 데이터들을 뽑아와 리스트에 담아야 한다.
X = df.iloc[:, 0]
y = df.iloc[:, 1]
그러나 여기서 알아야 할 점은 해당 변수의 자료형은 리스트가 아니라는 것이다.
# 자료형 확인
print(type(X))
print(type(y))
type()함수를 사용하여 자료형을 확인하면 <class 'pandas.core.series.Series'> 형태의 자료형으로 선언되어 있음을 확인할 수 있다.
그렇기에 해당 자료형을 numpy 형태로 변경해주어야 한다.
# 자료형 변경
X = X.to_numpy() # pandas -> ndarray
y = y.to_numpy() # pandas -> numpy
# 데이터 재배열
tf_X = X.reshape(1000, 1)
위 코드를 사용하여 자료형을 변경해주었다.
모델에서 훈련 시 입력데이터는 텐서를 2로 설정해주어 한다.
그렇기에 reshape() 메서드를 사용해서 차원을 한개 더 늘리는 과정을 수행하였다.
모델 생성 및 컴파일
이제 학습시킬 모델을 생성해보자.
모델은 Sequential 모델을 사용했으며 각 층들 및 컴파일 환경은 아래와 같이 설정하였다.
# 라이브러리 호출
import tensorflow as tf
# 모델 생성
model = tf.keras.models.Sequential([], name="ML")
input_layer = tf.keras.layers.Input(shape=(1,), name='Input')
dense_layer1 = tf.keras.layers.Dense(units=6, activation='sigmoid', name='Layer1')
dense_layer2 = tf.keras.layers.Dense(units=5, activation='sigmoid', name='Layer2')
dense_layer3 = tf.keras.layers.Dense(units=4, activation='sigmoid', name='Layer3')
dense_layer4 = tf.keras.layers.Dense(units=1, activation='sigmoid', name='Output')
# 각 층을 설정
model.add(layer=input_layer)
model.add(layer=dense_layer1)
model.add(layer=dense_layer2)
model.add(layer=dense_layer3)
model.add(layer=dense_layer4)
model.summary()
모델 훈련
모델도 생성하고, 데이터들의 전처리 과정도 마쳤으니 모델을 훈련시켜야 한다.
# 모델 훈련
model.fit(x=tf_X, y=y, epochs=2000)
입력 데이터들을 넣고 2000번의 에포크 만큼 학습을 수행하였다.
예측 및 시각화
이제 훈련을 마친 모델을 가지고 데이터를 예측 및 시각화 해보자.
# 데이터 예측
predict_result = model.predict(x=X)
# 시각화
plt.scatter(X, y, color='g')
plt.scatter(X, predict_result, color='r')
plt.show()
데이터를 예측한 결과를 확인해보면 0.6 이후로부터는 예측값의 정확도가 떨어짐을 확인할 수 있다.
이는 다양한 이유 중 하나일 것이다.
1. 과적합 또는 과소적합
2. 학습률 문제
3. 모델의 복잡성 부족
위 3가지가 가장 높은 이유일 것이라고 예측된다.
'Python > 데이터분석(ABC 부트캠프)' 카테고리의 다른 글
[24일차] ABC 부트캠프 / OpenCV 실습 (0) | 2024.07.28 |
---|---|
[23일차] ABC 부트캠프 / CNN 모델 (0) | 2024.07.28 |
[21일차] ABC 부트캠프 / 머신러닝 퀴즈 해결 및 신경망 (0) | 2024.07.26 |
[20일차] ABC 부트캠프 / 제 2회 ESG Day (2) | 2024.07.21 |
[19일차] ABC 부트캠프 / sklearn의 datasets 모듈 예제 (0) | 2024.07.21 |