from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam
model = Sequential()
model.add(Dense(100,input_shape=(1,)))
model.add(Dense(100))
model.add(Dense(1, activation="sigmoid"))
adam = Adam(learning_rate=0.001)
model.compile(optimizer=adam, loss="binary_crossentropy", metrics=['accuracy'])
import numpy as np
nps = np.array([[1],[2],[3],[4],[5]])
nps2 = np.array([[0],[0],[0],[1],[1]])
model.fit(nps,nps2,epochs=50)
위 예시는 임의 층을 만들고, Adam 옵티마이저로 binary_crossentropy 손실함수를 통해 모델을 학습 시키는 예시입니다. 이렇게 학습을 하게 되면 1~3에 대해서는 임계값 0.5기준 0으로 나오고, 4~5는 1로 예측하게끔 학습할 수 있습니다.
model.predict(np.array([[0]]))
1/1 [==============================] - 0s 19ms/step
array([[0.08920556]], dtype=float32)
이 과정에서는 모델을 만든 뒤 fit함수가 모든 것을 알아서 처리하고 있습니다. 하지만 직접 원하는 경사 하강을 수행하기 위해서는 1. 자동 미분을 하고 2. 그 미분값으로 weights에 지정한 learning_rate 만큼 반영하는 작업이 필요합니다.
GradientTape를 통한 자동 미분 그리고 수동 적용
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam
from keras.losses import binary_crossentropy
import tensorflow as tf
model = Sequential()
model.add(Dense(100,input_shape=(1,)))
model.add(Dense(100))
model.add(Dense(1, activation="sigmoid"))
adam = Adam(learning_rate=0.001)
import numpy as np
nps = np.array([[1],[2],[3],[4],[5]])
nps2 = np.array([[0],[0],[0],[1],[1]])
for epoch in range(100):
with tf.GradientTape() as tape:
predicted = model(nps)
calculated = binary_crossentropy(nps2, predicted)
gradients = tape.gradient(calculated,model.trainable_variables)
adam.apply_gradients(zip(gradients, model.trainable_variables))
print("Loss ", np.mean(calculated))
위 코드는 이진 분류를 하되, 직접 binary_crossentropy에 실제 데이터와 예측 데이터를 넘겨서 각 loss 정도를 구합니다. 이 계산 과정에서 모든 내용은 GradientTape에 의해 기록되기 때문에 추후 미분을 할 수 있게 됩니다. 모든 연산이 끝나면 밖에 나와서 처리한 목적 값에 대하여 미분을 합니다. 단, model.trainable_variables 값, 즉 모델 층에 존재하는 각각의 가중치 값으로 편미분을 한다는 사실에 유의해야 합니다. 이렇게 미분된 값은 Adam Optimizer을 통해 learning rate 0.001 로 적용하여 각 가중치에 반영합니다.