* 본 포스팅은 머신러닝교과서를 참조하여 작성되었습니다.
* https://github.com/rickiepark/python-machine-learning-book-3rd-edition
GitHub - rickiepark/python-machine-learning-book-3rd-edition: <머신 러닝 교과서 3판>의 코드 저장소
<머신 러닝 교과서 3판>의 코드 저장소. Contribute to rickiepark/python-machine-learning-book-3rd-edition development by creating an account on GitHub.
github.com
데이터를 생성하고 훈련 데이터셋과 검증 데이터셋으로 나눈다.
tf.random.set_seed(1)
np.random.seed(1)
x = np.random.uniform(low=-1, high=1, size=(200, 2))
y = np.ones(len(x))
y[x[:, 0] * x[:, 1]<0] = 0
x_train = x[:100, :]
y_train = y[:100]
x_valid = x[100:, :]
y_valid = y[100:]
fig = plt.figure(figsize=(6, 6))
plt.plot(x[y==0, 0],
x[y==0, 1], 'o', alpha=0.75, markersize=10)
plt.plot(x[y==1, 0],
x[y==1, 1], '<', alpha=0.75, markersize=10)
plt.xlabel(r'$x_1$', size=15)
plt.ylabel(r'$x_2$', size=15)
# plt.savefig('images/14_1.png', dpi=300)
plt.show()
이제 이 문제와 데이터셋에서 어떤 구조를 사용할지 결정해야 한다. 경험적으로 층이 많을수록 각 층에 뉴런 개수가 많을수록 모델의 수용 능력이 크다. 여기서 모델의 수용 능력은 모델이 얼마나 복잡한 함수를 근사할 수 있을지를 측정한 것으로 생각할 수 있다. 많은 파라미터를 가지고 있으면 모델이 복잡한 함수를 근사할 수 있지만 모델이 클수록 훈련하기 힘들다(그리고 과대적합되기 쉽다). 실제로는 로지스틱 회귀, 즉 간단한 단일층 신경망처럼 간단한 기본 모델로 시작하는 것이 좋다.
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(units=1,
input_shape=(2, ),
activation='sigmoid'))
model.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_4 (Dense) (None, 1) 3
=================================================================
Total params: 3
Trainable params: 3
Non-trainable params: 0
_________________________________________________________________
모델을 정의한 후 컴파일하고 배치 크기 2로 200에포크 동안 훈련한다.
model.compile(optimizer=tf.keras.optimizers.SGD(),
loss=tf.keras.losses.BinaryCrossentropy(),
metrics=[tf.keras.metrics.BinaryAccuracy()])
hist = model.fit(x_train, y_train, validation_data=(x_valid, y_valid), epochs=200, batch_size=2, verbose=0)
from mlxtend.plotting import plot_decision_regions
history = hist.history
fig = plt.figure(figsize=(16, 4))
ax = fig.add_subplot(1, 3, 1)
plt.plot(history['loss'], lw=4)
plt.plot(history['val_loss'], lw=4)
plt.legend(['Train loss', 'Validation loss'], fontsize=15)
ax.set_xlabel('Epochs', size=15)
ax = fig.add_subplot(1, 3, 2)
plt.plot(history['binary_accuracy'], lw=4)
plt.plot(history['val_binary_accuracy'], lw=4)
plt.legend(['Train Acc.', 'Validation Acc.'], fontsize=15)
ax.set_xlabel('Epochs', size=15)
ax = fig.add_subplot(1, 3, 3)
plot_decision_regions(X=x_valid, y=y_valid.astype(np.integer),
clf=model)
ax.set_xlabel(r'$x_1$', size=15)
ax.xaxis.set_label_coords(1, -0.025)
ax.set_ylabel(r'$x_2$', size=15)
ax.yaxis.set_label_coords(-0.025, 1)
plt.show()
여기서 볼 수 있듯 은닉층이 없는 간단한 모델은 선형 결정 경계만 찾을 수 있다. 따라서 XOR 문제를 풀 수 없다. 이로 인해 훈련 데이터셋과 검증 데이터셋의 손실이 매우 높고 분류 정확도는 매우 낮다.
비선형 결정 경계를 찾기 위해 비선형 활성화 함수를 사용한 한 개 이상의 은닉층을 추가할 수 있다.
tf.random.set_seed(1)
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(units=4, input_shape=(2, ), activation='relu'))
model.add(tf.keras.layers.Dense(units=4, activation='relu'))
model.add(tf.keras.layers.Dense(units=4, activation='relu'))
model.add(tf.keras.layers.Dense(units=1, activation='sigmoid'))
model.summary()
Model: "sequential_4"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_5 (Dense) (None, 4) 12
dense_6 (Dense) (None, 4) 20
dense_7 (Dense) (None, 4) 20
dense_8 (Dense) (None, 1) 5
=================================================================
Total params: 57
Trainable params: 57
Non-trainable params: 0
_________________________________________________________________
## 컴파일:
model.compile(optimizer=tf.keras.optimizers.SGD(),
loss=tf.keras.losses.BinaryCrossentropy(),
metrics=[tf.keras.metrics.BinaryAccuracy()])
## 훈련:
hist = model.fit(x_train, y_train,
validation_data=(x_valid, y_valid),
epochs=200, batch_size=2, verbose=0)
history = hist.history
fig = plt.figure(figsize=(16, 4))
ax = fig.add_subplot(1, 3, 1)
plt.plot(history['loss'], lw=4)
plt.plot(history['val_loss'], lw=4)
plt.legend(['Train loss', 'Validation loss'], fontsize=15)
ax.set_xlabel('Epochs', size=15)
ax = fig.add_subplot(1, 3, 2)
plt.plot(history['binary_accuracy'], lw=4)
plt.plot(history['val_binary_accuracy'], lw=4)
plt.legend(['Train Acc.', 'Validation Acc.'], fontsize=15)
ax.set_xlabel('Epochs', size=15)
ax = fig.add_subplot(1, 3, 3)
plot_decision_regions(X=x_valid, y=y_valid.astype(np.integer),
clf=model)
ax.set_xlabel(r'$x_1$', size=15)
ax.xaxis.set_label_coords(1, -0.025)
ax.set_ylabel(r'$x_2$', size=15)
ax.yaxis.set_label_coords(-0.025, 1)
plt.show()
모델이 이 데이터에서 비선형 결정 경계를 찾은 것을 볼 수 있다. 이 모델은 훈련 데이터셋에서 100% 정확도를 달성했다. 검증 데이터셋의 정확도는 95%로 모델이 약간 과대적합된 것으로 보인다.
'소소하지만 소소하지 않은 개발 공부 > 머신 러닝 교과서' 카테고리의 다른 글
[머신러닝교과서] RNN을 사용한 영화 리뷰 감성 분석(1) (2) | 2023.01.31 |
---|---|
[머신러닝교과서] 순차 데이터 모델링의 개념 (0) | 2023.01.31 |
[머신러닝교과서] 사이킷런을 사용한 k-평균 군집, KMeans, python (0) | 2023.01.06 |
10.4 RANSAC을 사용하여 안정된 회귀 모델 훈련, python (0) | 2022.12.23 |
10.1 선형회귀, 머신러닝교과서, python (1) | 2022.12.22 |