내용
이 글은 "Deep Learning with Python"의 3.4 절의 내용입니다.
신경망의 구성과 binary classification
신경망 훈련은 다음 객체를 중심으로 이루어집니다.
- Layers: 네트워크(또는 모델)로 결합되는 계층
- 입력 데이터 및 해당 대상
- 학습에 사용되는 피드백 신호를 정의하는 손실 함수
- 학습 진행 방법을 결정하는 옵티마이저
다음과 같이 상호 작용을 시각화할 수 있습니다. 함께 연결된 레이어로 구성된 네트워크는 입력 데이터를 예측에 매핑합니다. 그런 다음 손실 함수는 이러한 예측을 목표와 비교하여 손실 값을 생성합니다. 네트워크의 예측이 예상과 얼마나 잘 일치하는지 측정합니다. 옵티마이저는 이 손실 값을 사용하여 네트워크의 가중치를 업데이트합니다.
layers: the building blocks of deep learning
from keras import layers layer=layers.Dense(32, input_shape=(784,)) layer
<keras.layers.core.dense.Dense at 0x7f9f7ed824d0>
첫 번째 차원이 784인 입력 2D 텐서로만 받아들이는 레이어(배치 차원인 축 0은 지정되지 않았으므로 모든 값이 허용됨)로 이 레이어는 첫 번째 차원이 32로 변환된 텐서를 반환합니다.
그러므로 다음 레이어의 입력 단위는 32 차원이어야 합니다. Keras를 사용할 때 모델에 추가하는 레이어가 들어오는 레이어의 모양과 일치하도록 동적으로 만들어지기 때문에 호환성에 대해 걱정할 필요가 없습니다. 예를 들어 다음을 작성한다고 가정합니다.
from keras import models from keras import layers
model=models.Sequential() model.add(layers.Dense(32, input_shape=(784, ))) model.add(layers.Dense(32)) model.summary()
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_1 (Dense) (None, 32) 25120 dense_2 (Dense) (None, 32) 1056 ================================================================= Total params: 26,176 Trainable params: 26,176 Non-trainable params: 0 _________________________________________________________________
두 번째 레이어는 입력 모양 인수를 받지 않고 대신 자동으로 입력 모양을 이전 레이어의 출력 모양으로 유추했습니다.
Binary classification example: IMDB
이진 분류 즉 두 그룹으로 분류(classification)를 예로 많이 사용되는 데이터셋은 영화의 평을 positive와 negative로 분류한 IMDB임
50000개 데이터 중 25000개는 학습, 25000개는 테스트를 위한 것으로 각각 50%의 positive와 50%dml negative로 구성
import tensorflow as tf from tensorflow.keras import utils from keras.datasets import imdb import numpy as np
(xtr, ytr),(xte, yte)=imdb.load_data(num_words=10000)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz 17465344/17464789 [==============================] - 0s 0us/step 17473536/17464789 [==============================] - 0s 0us/step
num_words=10000 인수는 훈련 데이터에서 가장 자주 발생하는 상위 10,000개의 단어만 유지한다는 것을 의미합니다. 희귀 단어는 폐기됩니다. 이를 통해 관리 가능한 크기의 벡터 데이터로 작업할 수 있습니다.
변수 xtr, ytr은 리뷰 목록입니다. 각 리뷰는 단어 색인(단어 시퀀스 인코딩)의 목록입니다. ytr 및 yte는 0과 1의 목록입니다. 여기서 0은 음수를 나타내고 1은 양수를 나타냅니다.
print(xtr[0])
[1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65, 458, 4468, 66, 3941, 4, 173, 36, 256, 5, 25, 100, 43, 838, 112, 50, 670, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 4536, 1111, 17, 546, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2025, 19, 14, 22, 4, 1920, 4613, 469, 4, 22, 71, 87, 12, 16, 43, 530, 38, 76, 15, 13, 1247, 4, 22, 17, 515, 17, 12, 16, 626, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2223, 5244, 16, 480, 66, 3785, 33, 4, 130, 12, 16, 38, 619, 5, 25, 124, 51, 36, 135, 48, 25, 1415, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 5952, 15, 256, 4, 2, 7, 3766, 5, 723, 36, 71, 43, 530, 476, 26, 400, 317, 46, 7, 4, 2, 1029, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2071, 56, 26, 141, 6, 194, 7486, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 5535, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 1334, 88, 12, 16, 283, 5, 16, 4472, 113, 103, 32, 15, 16, 5345, 19, 178, 32]
ytr[0]
1
# 가장 빈번한 단어 10000개를 지정 단어 인덱스는 10000 이상이 될 수 없습니다. max([max(i) for i in xtr])
9999
다음은 이러한 리뷰 중 하나를 영어 단어로 빠르게 해독하는 방법입니다.
word_index=imdb.get_word_index() reverse_word_index=dict([(value, key) for (key, value) in word_index.items()]) decoded_review=' '.join([reverse_word_index.get(i - 3, '?') for i in xtr[0]]) decoded_review
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb_word_index.json 1646592/1641221 [==============================] - 0s 0us/step 1654784/1641221 [==============================] - 0s 0us/step "? this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert ? is an amazing actor and now the same being director ? father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for ? and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also ? to the two little boy's that played the ? of norman and paul they were just brilliant children are often left out of the ? list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all"
데이터 준비
신경망에는 정수 목록을 신경망에 공급할 수 없습니다. 목록을 텐서로 바꿔야 합니다. 그렇게 하는 두 가지 방법이 있습니다.
목록을 0과 1의 벡터로 변환하기 위해 목록을 원-핫 인코딩합니다. 이것은 예를 들어 시퀀스 [3, 5]를 1인 인덱스 3과 5를 제외하고 모두 0인 10,000차원 벡터로 바꾸는 것을 의미합니다. 그런 다음 부동 소수점 벡터 데이터를 처리할 수 있는 고밀도 계층을 네트워크의 첫 번째 계층으로 사용할 수 있습니다. 데이터를 벡터화하기 위해 후자의 솔루션을 사용해 보겠습니다. 이 작업은 최대 명확성을 위해 수동으로 수행합니다.
다음과 같이 .to_categorical()
메소드를 사용할 수 있습니다.
이 함수보다 다음과 같이 사용자 정의 함수를 작성하여 사용할 수 있습니다.
xtr.shape
(25000,)
def vectorize(seq, dims=10000): result=np.zeros((len(seq), dims)) for i, j in enumerate(seq): result[i, j]=1 return(result)
xtr1=vectorize(xtr) xtr1[0]
array([0., 1., 1., ..., 0., 0., 0.])
xte1=vectorize(xte) xte1[-1]
array([0., 1., 1., ..., 0., 0., 0.])
feature를 원-핫 벡터로 변환하였읍니다. 라벨은 float32 형으로 전환하여야 합니다.
ytr1=np.asarray(ytr).astype("float32") yte1=np.asarray(yte).astype("float32") ytr1[0]
1.0
신경망 구축
입력 데이터는 벡터이고 레이블은 스칼라(1과 0)입니다. 이러한 문제에서 잘 수행되는 네트워크 유형은 relu 활성화가 있는 완전 연결(밀도) 계층으로 Dense(16, activation='relu')
와 같이 layer를 설정합니다. 이 설정에서 Dense()에 전달되는 인수 16는 레이어의 은닉(hidden layer) 유닛 수입니다. 은닉 유닛은 레이어의 표현 공간에 있는 차원입니다. 이 층으로 부터의 출력은 다음 과정의 결과입니다.
16개의 은닉 유닛이 있다는 것은 가중치 행렬 W가 모양(input_dimension, 16)을 갖는다는 것을 의미합니다. W가 있는 내적은 입력 데이터를 16차원 표현 공간에 투영합니다. 그런 다음 편향 벡터 b를 추가한 것입니다. 표현 공간의 차원을 "내부 표현을 학습할 때 네트워크에 얼마나 많은 자유를 허용하는지"로 직관적으로 이해할 수 있습니다. 더 많은 은닉 유닛(고차원 표현 공간)을 사용하면 네트워크가 더 복잡한 표현을 학습할 수 있지만, 고비용, 과적합 등의 문제가 발생할 수 있습니다.
from tensorflow.keras import models, layers
model=models.Sequential() model.add(layers.Dense(16, activation="relu", input_shape=(10000,))) model.add(layers.Dense(16, activation="relu")) model.add(layers.Dense(1, activation='sigmoid')) model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
위 코드에서 최적화를 위해 'rmsprop', 'binary_crossentropy', 'accuracy'를 문자열로 전달하였습니다. 이는 keras의 일부로서 패키지화되어 있기 때문에 가능한 것입니다. 다른 방법으로는 optimizer, loss, metrics 클래스 인스턴스를 적용하여 다음과 같이 전달할 수 있습니다.
from tensorflow.keras import optimizers, losses, metrics model.compile(optimizer=optimizers.RMSprop(learning_rate=0.001), loss=losses.binary_crossentropy, metrics=[metrics.binary_accuracy])
학습시 모델 검증고 예측
이전에 본 적이 없는 데이터에 대한 모델의 정확도를 훈련하는 동안 모니터링하기 위해 원본 훈련 데이터에서 10,000개의 샘플을 분리하여 검증 세트를 생성합니다.
xtr_val=xtr1[:10000] xtr_part=xtr1[10000:] ytr_val=ytr1[:10000] ytr_part=ytr1[10000:]
이제 512개 샘플의 미니 배치에서 20개의 에포크(xtr및 ytr 텐서의 모든 샘플에 대해 20회 반복) 동안 모델을 훈련합니다. 동시에 분리한 10,000개 샘플의 손실과 정확도를 모니터링합니다. 유효성 검사 데이터를 validation_data 인수로 전달하면 됩니다.
history=model.fit(xtr_part, ytr_part, epochs=20, batch_size=512, validation_data=(xtr_val, ytr_val))
Epoch 1/20 30/30 [==============================] - 1s 39ms/step - loss: 0.3165 - binary_accuracy: 0.8998 - val_loss: 0.3071 - val_binary_accuracy: 0.8846 Epoch 2/20 30/30 [==============================] - 1s 20ms/step - loss: 0.2285 - binary_accuracy: 0.9264 - val_loss: 0.2793 - val_binary_accuracy: 0.8903 Epoch 3/20 … Epoch 19/20 30/30 [==============================] - 1s 19ms/step - loss: 0.0067 - binary_accuracy: 0.9995 - val_loss: 0.6789 - val_binary_accuracy: 0.8650 Epoch 20/20 30/30 [==============================] - 1s 19ms/step - loss: 0.0076 - binary_accuracy: 0.9989 - val_loss: 0.7106 - val_binary_accuracy: 0.8657
model.fit()
에 대한 호출은 History 객체를 반환합니다. 이 개체에는 학습 중에 발생한 모든 것에 대한 데이터가 포함된 사전인 구성원 기록이 있습니다.
hist_dict=history.history hist_dict.keys()
dict_keys(['loss', 'binary_accuracy', 'val_loss', 'val_binary_accuracy'])
partLoss=hist_dict['loss'] partAcc=hist_dict["binary_accuracy"] valLoss=hist_dict['val_loss'] valAcc=hist_dict["val_binary_accuracy"] epoch=range(1, len(valAcc)+1)
import matplotlib.pyplot as plt
plt.figure(dpi=100) plt.subplot(1,2,1) plt.plot(epoch, partLoss, label="loss") plt.plot(epoch, valLoss, label="val_loss") plt.legend(loc='best') plt.xlabel('Epoch', weight="bold") plt.ylabel('LOSS', weight="bold") plt.subplot(1,2,2) plt.plot(epoch, partAcc, label="Acc") plt.plot(epoch, valAcc, label="val_Acc") plt.legend(loc='best') plt.xlabel('Epoch', weight="bold") plt.ylabel('acc', weight="bold") plt.show()
보시다시피 훈련 손실은 모든 Epoch에 따라 감소하고 훈련 정확도는 모든 Epoch에 따라 증가합니다. 이것이 경사하강법 최적화를 실행할 때 기대할 수 있는 것입니다. 최소화하려는 양은 반복할 때마다 적어야 합니다. 그러나 유효성 검사 손실 및 정확도의 경우는 그렇지 않습니다. 네 번째 에포크에서 정점에 도달하는 것 같습니다. 이것은 앞서 경고한 내용의 한 예입니다. 훈련 데이터에서 더 나은 성능을 보이는 모델이 이전에 본 적이 없는 데이터에서 더 나은 성능을 보일 필요는 없습니다. 정확한 용어로, 여러분이 보고 있는 것은 과적합입니다. 두 번째 에포크 이후에는 훈련 데이터에 대해 과도하게 최적화되고, 결국 훈련 데이터에 특정한 표현을 학습하고 훈련 외부의 데이터로 일반화하지 않는 표현을 얻게 됩니다. 세트. 이 경우 과적합을 방지하기 위해 세 epoch 후에 훈련을 중지할 수 있습니다. 일반적으로 4장에서 다룰 과적합을 완화하기 위해 다양한 기술을 사용할 수 있습니다. 4개의 에포크 동안 새 네트워크를 처음부터 훈련한 다음 테스트 데이터에서 평가해 보겠습니다.
model.fit(xtr1, ytr1, epochs=4, batch_size=512) result=model.evaluate(xte1, yte1) result
Epoch 1/4 49/49 [==============================] - 1s 13ms/step - loss: 0.2296 - binary_accuracy: 0.9470 Epoch 2/4 49/49 [==============================] - 1s 12ms/step - loss: 0.1383 - binary_accuracy: 0.9589 Epoch 3/4 49/49 [==============================] - 1s 12ms/step - loss: 0.1103 - binary_accuracy: 0.9662 Epoch 4/4 49/49 [==============================] - 1s 12ms/step - loss: 0.0890 - binary_accuracy: 0.9721 782/782 [==============================] - 2s 3ms/step - loss: 0.4906 - binary_accuracy: 0.8591 [0.4905923008918762, 0.8590800166130066]
model.predict(xte1)
array([[0.01625119], [0.99998116], [0.9388633 ], ..., [0.0638714 ], [0.0514787 ], [0.88493717]], dtype=float32)
yte1
array([0., 1., 1., ..., 0., 0., 0.], dtype=float32)
댓글
댓글 쓰기