기본 콘텐츠로 건너뛰기

[ML] 결정트리(Decision Tree) 모델

신경망의 구성과 binary classification

내용

이 글은 "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()메소드를 사용할 수 있습니다.

[utils.to_categorical(xtr[i]) for i in range(len(xtr))]

이 함수보다 다음과 같이 사용자 정의 함수를 작성하여 사용할 수 있습니다.

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) 유닛 수입니다. 은닉 유닛은 레이어의 표현 공간에 있는 차원입니다. 이 층으로 부터의 출력은 다음 과정의 결과입니다.

output = relu(dot(W, input)+b)

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)

댓글

이 블로그의 인기 게시물

[Linear Algebra] 유사변환(Similarity transformation)

유사변환(Similarity transformation) n×n 차원의 정방 행렬 A, B 그리고 가역 행렬 P 사이에 식 1의 관계가 성립하면 행렬 A와 B는 유사행렬(similarity matrix)이 되며 행렬 A를 가역행렬 P와 B로 분해하는 것을 유사 변환(similarity transformation) 이라고 합니다. $$\tag{1} A = PBP^{-1} \Leftrightarrow P^{-1}AP = B $$ 식 2는 식 1의 양변에 B의 고유값을 고려한 것입니다. \begin{align}\tag{식 2} B - \lambda I &= P^{-1}AP – \lambda P^{-1}P\\ &= P^{-1}(AP – \lambda P)\\ &= P^{-1}(A - \lambda I)P \end{align} 식 2의 행렬식은 식 3과 같이 정리됩니다. \begin{align} &\begin{aligned}\textsf{det}(B - \lambda I ) & = \textsf{det}(P^{-1}(AP – \lambda P))\\ &= \textsf{det}(P^{-1}) \textsf{det}((A – \lambda I)) \textsf{det}(P)\\ &= \textsf{det}(P^{-1}) \textsf{det}(P) \textsf{det}((A – \lambda I))\\ &= \textsf{det}(A – \lambda I)\end{aligned}\\ &\begin{aligned}\because \; \textsf{det}(P^{-1}) \textsf{det}(P) &= \textsf{det}(P^{-1}P)\\ &= \textsf{det}(I)\end{aligned}\end{align} 유사행렬의 특성 유사행렬인 두 정방행렬 A와 B는 'A ~ B' 와 같

[matplotlib] 히스토그램(Histogram)

히스토그램(Histogram) 히스토그램은 확률분포의 그래픽적인 표현이며 막대그래프의 종류입니다. 이 그래프가 확률분포와 관계가 있으므로 통계적 요소를 나타내기 위해 많이 사용됩니다. plt.hist(X, bins=10)함수를 사용합니다. x=np.random.randn(1000) plt.hist(x, 10) plt.show() 위 그래프의 y축은 각 구간에 해당하는 갯수이다. 빈도수 대신 확률밀도를 나타내기 위해서는 위 함수의 매개변수 normed=True로 조정하여 나타낼 수 있다. 또한 매개변수 bins의 인수를 숫자로 전달할 수 있지만 리스트 객체로 지정할 수 있다. 막대그래프의 경우와 마찬가지로 각 막대의 폭은 매개변수 width에 의해 조정된다. y=np.linspace(min(x)-1, max(x)+1, 10) y array([-4.48810153, -3.54351935, -2.59893717, -1.65435499, -0.70977282, 0.23480936, 1.17939154, 2.12397372, 3.0685559 , 4.01313807]) plt.hist(x, y, normed=True) plt.show()

R 미분과 적분

내용 expression 미분 2차 미분 mosaic를 사용한 미분 적분 미분과 적분 R에서의 미분과 적분 함수는 expression()함수에 의해 생성된 표현식을 대상으로 합니다. expression expression(문자, 또는 식) 이 표현식의 평가는 eval() 함수에 의해 실행됩니다. > ex1<-expression(1+0:9) > ex1 expression(1 + 0:9) > eval(ex1) [1] 1 2 3 4 5 6 7 8 9 10 > ex2<-expression(u, 2, u+0:9) > ex2 expression(u, 2, u + 0:9) > ex2[1] expression(u) > ex2[2] expression(2) > ex2[3] expression(u + 0:9) > u<-0.9 > eval(ex2[3]) [1] 0.9 1.9 2.9 3.9 4.9 5.9 6.9 7.9 8.9 9.9 미분 D(표현식, 미분 변수) 함수로 미분을 실행합니다. 이 함수의 표현식은 expression() 함수로 생성된 객체이며 미분 변수는 다음 식의 분모의 변수를 의미합니다. $$\frac{d}{d \text{변수}}\text{표현식}$$ 이 함수는 어떤 함수의 미분의 결과를 표현식으로 반환합니다. > D(expression(2*x^3), "x") 2 * (3 * x^2) > eq<-expression(log(x)) > eq expression(log(x)) > D(eq, "x") 1/x > eq2<-expression(a/(1+b*exp(-d*x))); eq2 expression(a/(1 + b * exp(-d * x))) > D(eq2, "x") a * (b * (exp(-d * x) * d))/(1 + b