티스토리 뷰

[딥러닝 express]의 연습문제 7장 풀이입니다. (개인적인 풀이기에 오답이 있을 수 있습니다!)

 

 

 

 

 

 

08. 케라스를 이용하여, 우리가 5장에서 학습한 초기 신경망인 퍼셉트론을 구현할 수 있을까?

 

케라스를 이용해서는 구현할 수 없다. 퍼셉트론의 경우 활성화 함수로 계단 함수를 사용하기 때문이다. 계단함수는 0값 에 대한 미분이 불가능해 미분 함수가 정의되지 않는다. 때문에 Keras가 사용하는 경사 하강법과 동시에 사용할 수 없다.

 

계단함수를 사용하고자 한다면 상위에서 작동하는 텐서플로우에서 활성화 함수에 대한 그래디언트를 따로 정의해 사용해야 한다. (tf.custom_gradient)

 

 

 

 

 

 

 

 

09. 케라스를 이용하여, 은닉층이 2개인 MLP를 생성해보자. 은닉층이 2개인 MLP를 이용하여, MNIST 숫자들을 처리해본다. 은닉층이 하나일때와 차이가 있는가?

 

 

import tensorflow as tf

# 숫자데이터 가져오기
(train_images, train_labels), (test_images, test_labels)= tf.keras.datasets.mnist.load_data()

# 순차모델 생성
model = tf.keras.models.Sequential()

# 레이어 생성
model.add(tf.keras.layers.Dense(512, activation='relu', input_shape=(784,))) # 은닉층1
#model.add(tf.keras.layers.Dense(512, activation='relu')) # 은닉층2
model.add(tf.keras.layers.Dense(10, activation='sigmoid')) # 출력층

print(model.summary())

model.compile(optimizer='rmsprop',
                loss='mse',
                metrics=['accuracy'])

# 데이터 평탄화, 정규화
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)

# 모델 학습
model.fit(train_images, train_labels, epochs=5, batch_size=128)

# 테스트
test_loss, test_acc = model.evaluate(test_images, test_labels)
print('테스트 정확도:', test_acc)

 

 

 

기존 코드에 512개의 유닛으로 이루어진 은닉층을 추가하여 학습을 진행시킨 후 테스트 해보았습니다. 여러번 실행해본 결과 근소하나 은닉층을 추가한 쪽의 정확도가 더 높아진 것을 확인해 볼 수 있었습니다.

 

 

 

 

 

 

 

 


10. 본문에는 MNIST 데이터 세트를 분류하는 소스가 포함되어있다. 이 소스에서 최적화 방법을 “Adam”, “RMSprop”, “Adadelta”, “Adagrad”으로 변경하면서 성능을 측정하여 보자. MNIST 데이터 세트의 경우, 어떤 방법이 가장 좋은 성능을 보이는가?

 

 

- Adam : RMSprop + 모멘텀

model.compile(optimizer='Adam',
                loss='mse',
                metrics=['accuracy'])

테스트 정확도: 0.9779000282287598

 

- RMSprop : Adagrad의 수정판

model.compile(optimizer='RMSprop',
                loss='mse',
                metrics=['accuracy'])

테스트 정확도: 0.9804999828338623

 

 

- Adadelta : 모멘텀을 이용하여 감소하는 학습률 문제를 처리한 Adagrad의 변형

model.compile(optimizer='Adadelta',
                loss='mse',
                metrics=['accuracy'])

테스트 정확도: 0.15809999406337738

 

- Adagrad: 가변 학습률 사용

model.compile(optimizer='Adagrad',
                loss='mse',
                metrics=['accuracy'])

테스트 정확도: 0.37529999017715454

 

본문 코드에서 모델 컴파일시에 optimizer 옵션을 바꾸어 가며, 정확도를 확인해 보았습니다. MNIST 데이터 세트의 경우, RMSprop을 최적화 방법으로 선택하는 것이 가장 좋은 성능을 보였습니다.

 

 

 

 

 

 

 

 

 

 

11. 케라스에서 유닛의 활성화 함수를 “linear”로 설정하면 선형회귀도 구현할 수 있다. 기울기가 3인 직선을 만들고 여기에 노이즈를 추가하여 입력데이터를 만들고 케라스 모델로 선형회귀를 실행해보자.

 

다음과 같은 넘파이 배열을 입력 데이터로 사용하였습니다.

X = np.linspace(0, 10, 100)
y = 3.0 * X + np.random.randn(X.shape)*0.3

 

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf

# X : 0부터 10사이에서 100개의 숫자
X = np.linspace(0, 10, 100)

# y : 기울기가 3에 노이즈(랜덤 y절편)를 추가한 데이터
y = 3.0 * X + np.random.randn(*X.shape)*0.3

# 입력데이터 확인
plt.plot(X)
plt.plot(y)
plt.xlabel('x') 
plt.ylabel('y')
plt.show()

 

 

# 순차모델 생성
model = tf.keras.models.Sequential()

# 레이어 생성
model.add(tf.keras.layers.Dense(1, input_shape = (1,), activation='linear'))

# 활성화 함수 설정
sgd = tf.keras.optimizers.SGD(learning_rate = 0.01)

model.compile(optimizer=sgd,
                loss='mse',
                metrics=['accuracy'])

# 모델 학습
history = model.fit(X, y, epochs=5, batch_size=1)

# 오차 변화 그래프
plt.plot(history.history['loss'])
plt.legend(['Loss'], loc='upper right')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')

# 화면에 그래프 출력
plt.show()

 

순차적 모델을 생성해 유닛의 개수는 1개 입력데이터는 1차원 배열로 활성화 함수로 linear를 가진 레이어를 추가하여 모델을 학습시키고 오차가 어떻게 변화하는지 matplotlib으로 그래프를 그려 확인해 보았습니다. 에포크에 따라 오차가 줄어들며 선형회귀가 잘 구현되었음을 알 수 있습니다.

 

 

 

 

 

 

 

 

 

12. 주택 특징값을 받아서 주택 가격을 예측하는 모델을 구축해보자. 미국 보스톤 지역의 집값 데이터를 저장한 “Boston Housing” 데이터 세트를 사용해보자(예전 자료이다). 이 데이터 세트는 케라스에 포함되어있다. 이 데이터 세트는 비교적 크기가 작으며 506개의 샘플을 가지고 있다. 이데이터 세트에서는 14가지 특징을 사용한다. 유닛의 활성화 함수를 “ReLU”로 하여도 회귀가 가능하다.

 

from keras.datasets import boston_housing

(X_train, y_train), (X_test, y_test)= boston_housing.load_data()

 

import matplotlib.pyplot as plt
import tensorflow as tf
from keras.datasets import boston_housing

# 보스톤 집값 데이터 가져오기
(X_train, y_train), (X_test, y_test)= boston_housing.load_data()

# 데이터 정규화
mean = X_train.mean(axis = 0)
std = X_train.std(axis = 0)
X_train = (X_train - mean)/std
X_test = (X_test - mean)/std


# 순차모델 생성
model = tf.keras.models.Sequential()

# 레이어 생성
model.add(tf.keras.layers.Dense(32, input_shape = (13,), activation='relu')) # 입력 + 은닉층
model.add(tf.keras.layers.Dense(1)) # 출력층

# 컴파일
model.compile(optimizer='rmsprop', loss='mse', metrics=['accuracy'])

# 모델 학습
model.fit(X_train, y_train, epochs=20, batch_size=10)

# 테스트
y_pred = model.predict(X_test)

# 테스트 결과 그리기
plt.figure(figsize=(5, 5))
plt.scatter(y_test, y_pred, c = 'red')
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], c = 
'blue')
plt.xlabel('y_test')
plt.ylabel('y_pred')

# 그래프 보이기
plt.show()

 

 

 

은닉층 유닛에 렐루 활성화 함수를 사용해 구현하였습니다. 정답은 x축으로 예측값은 y축으로 두어 예측값 점분포도를 그린 결과는 오른쪽과 같습니다. 기준선인 파란색 선에 가까울수록 정확하게 예측한 것으로 어느정도 회귀가 학습된 것을 확인할 수 있습니다.

 

 

 

 

 

 

 

 

 

 

13. Kaggle 사이트에 가보면 “pima-indians-diabetes.csv” 데이터 파일을 찾을 수 있다. 이 데이터 세트에는 Pima 인디언의 의료 기록과 각 환자가 5년 이내에 당뇨병 발병 여부가 저장되어있다. 처음부터 8개의 특성만을 입력으로 하고, 인덱스 8에 저장된 값(1: 당뇨병 양성, 0: 당뇨병 음성)을 레이블로 한다. 이 데이터를 가지고 케라스의 MLP를 이용하여 학습시켜 보자.’

 

 

dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',')
X = dataset[:,0:8]
y = dataset[:,8]

 

import numpy as np
import tensorflow as tf

# 같은 폴더내에 csv파일 읽어오기
dataset = np.loadtxt('pima-indians-diabetes.csv', delimiter=',') 

# 입력데이터
X = dataset[:,0:8] 
y = dataset[:,8] 

# 모델 생성
model = tf.keras.models.Sequential() 
model.add(tf.keras.layers.Dense(32, input_shape = (8,), activation = 'relu')) 
model.add(tf.keras.layers.Dense(32, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid')) 

# 컴파일
model.compile(optimizer='rmsprop',
                loss='mse',
                metrics=['accuracy'])

# 학습
model.fit(X, y, epochs = 500, batch_size = 32)

 

...

Epoch 494/500
24/24 [==============================] - 0s 522us/step - loss: 0.1003 - accuracy: 0.8633
Epoch 495/500
24/24 [==============================] - 0s 565us/step - loss: 0.1072 - accuracy: 0.8594
Epoch 496/500
24/24 [==============================] - 0s 522us/step - loss: 0.1020 - accuracy: 0.8698
Epoch 497/500
24/24 [==============================] - 0s 565us/step - loss: 0.1013 - accuracy: 0.8711
Epoch 498/500
24/24 [==============================] - 0s 522us/step - loss: 0.1057 - accuracy: 0.8568
Epoch 499/500
24/24 [==============================] - 0s 565us/step - loss: 0.1018 - accuracy: 0.8789
Epoch 500/500
24/24 [==============================] - 0s 609us/step - loss: 0.1005 - accuracy: 0.8815

 

먼저 Kaggle에서 파일을 다운받아 코드와 같은 디렉토리에 저장하였습니다. 32개의 유닛을 가지고 활성화 함수로 ReLu를 사용하는 은닉층 2개를 포함한 MLP 모델을 사용하였으며, 배치사이즈를 32로 500 에포크를 학습한 결과 마지막 에포크에 대해 정확도가 약 0.88인 것을 볼 수 있습니다.

 

 

 

 

 

14. 사이킷런에서 기본으로 제공하는 데이터 중에 붓꽃 데이터 세트가 있다. 이 데이터 세트는 세가지 붗꽃 종류 (lris setosa, lris virginica, lris versicolor)의 150개 샘플로 구성된다. 각 샘플에서 꽃받침 길이와 너비, 꽃잎의 길이와 너비의 4가지 특징이 측정되었다. 이 4가지 특징의 조합을 기반으로 로날드 피셔는 종을 서로 구별하는 선형 판별 모델을 개발했다. 우리는 알려진 붓꽃들을 대상으로 학습시킨 후에, 미지의 붓꽃에 대한 꽃받침 크기와 꽃잎 크기를 입력하여서 이것이 어떤 붓꽃인지를 예측할 것이다. 케라스로 구현된 MLP로 이것을 시도해보자. 다음의 코드를 참조한다.

 

iris = datasets.load_iris()
X = iris.data[:,(0,1)]  # 꽃의 너비와 높이만을 입력으로 한다
y = (iris.target == 0).astype(np.int) # 출력은 Iris Setosa인가 아닌가 이다.

 

 

from sklearn import datasets
from sklearn.model_selection import train_test_split
import tensorflow as tf

classes = {0:'setosa', 1:'versicolor', 2:'virginica'}

# 붗꽃데이터 가져오기
iris = datasets.load_iris()

# 입력데이터
#X = iris.data[:,(0,1)]  # 꽃의 너비와 높이 추출
#y = (iris.target == 0).astype(np.int) # 출력 : Iris Setosa인가 아닌가
X = iris.data
y = iris.target
y = tf.keras.utils.to_categorical(y) # 원핫 엔코딩

# 훈련, 테스트 데이터(80:20)로 분할한다.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state = 1)


# 모델 생성
model = tf.keras.models.Sequential() 

# 레이어 추가
model.add(tf.keras.layers.Dense(32, input_shape = (4,), activation = 'relu')) 
model.add(tf.keras.layers.Dense(32, activation='relu'))
model.add(tf.keras.layers.Dense(3, activation='sigmoid')) 

# 컴파일
model.compile(optimizer='rmsprop',
                loss='mse',
                metrics=['accuracy'])

# 학습
model.fit(X_train, y_train, epochs = 20, batch_size = 1)

# 테스트 데이터에 대해 테스트
loss, accuracy = model.evaluate(X_test, y_test)
print('테스트 정확도:', accuracy)

# 임의의 데이터에 대해 테스트
y_pred = model.predict([[3, 2, 1.5, 2]])
print('추정되는 종: ', classes[y_pred.argmax()])

 

...
120/120 [==============================] - 0s 530us/step - loss: 0.0257 - accuracy: 0.9667
Epoch 16/20
120/120 [==============================] - 0s 530us/step - loss: 0.0237 - accuracy: 0.9750
Epoch 17/20
120/120 [==============================] - 0s 521us/step - loss: 0.0211 - accuracy: 0.9583
Epoch 18/20
120/120 [==============================] - 0s 530us/step - loss: 0.0257 - accuracy: 0.9583
Epoch 19/20
120/120 [==============================] - 0s 504us/step - loss: 0.0223 - accuracy: 0.9583
Epoch 20/20
120/120 [==============================] - 0s 530us/step - loss: 0.0228 - accuracy: 0.9417
1/1 [==============================] - 0s 77ms/step - loss: 0.0201 - accuracy: 0.9667

테스트 정확도: 0.9666666388511658
추정되는 종:  versicolor

 

sklearn에서 제공하는 iris 데이터를 이용해 훈련데이터와 테스트 데이터로 분할해 학습과 테스트를 진행해 보았습니다. 32개의 유닛과 relu 활성화 함수를 사용하는 은닉층 2개가 포함된 모델을 사용하였으며, 배치사이즈는 1로, 20 에포크를 진행하니 테스트 데이터에 대해 약 0.96의 정확도를 얻을 수 있었습니다. 임의의 데이터를 주어 predict 메소드로 y_pred를 얻고, argmax를 통한 종의 추정도 해보았습니다. 위는 [3, 2, 1.5, 2]를 입력하니 versicolor로 추정된 결과입니다.

 

 

 

감사합니다.

 


공부한 내용을 복습/기록하기 위해 작성한 글이므로 내용에 오류가 있을 수 있습니다.

댓글
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Total
Today
Yesterday