閱讀難度:★★★★☆
技能要求:機器學習基礎、Keras、numpy、matplotlib
字數:960字
閱讀時長:5分鐘
本文接上一期,補充一些MDN的代碼練習。本教程開發環境是python+jupyter,引用了一個用keras寫的mdn包,目标是拟合反正弦函數曲線:
y=7.0sin(0.85x)+0.5x+r
該函數在每個點都有多個解,是以要求ANN模型需要有能力處理它的損失函數。 MDN是預測這些多輸出值的好方法。
1
引入相關依賴
import keras
import mdn
import numpy as np
import matplotlib.pyplot as plt
複制
2
生成模拟資料
#y=7.0sin(0.85x)+0.5x+r
#r标準的高斯随機噪聲
NSAMPLE = 3000
y_data = np.float32(np.random.uniform(-10.5, 10.5, NSAMPLE))
r_data = np.random.normal(size=NSAMPLE)
x_data = np.sin(0.85 * y_data) * 7.0 + y_data * 0.5 + r_data * 1.0
x_data = x_data.reshape((NSAMPLE, 1))
plt.figure(figsize=(4, 4))
plt.plot(x_data,y_data,'ro', alpha=0.3,markersize = 1)
plt.show()
複制

3
模組化
接下來,我們在Keras中建構MDN模型。 使用了Keras中的Sequential模型,其中MDN層位于一個或多個Dense層之後。 您需要為MDN定義輸出次元和混合狀态的數量,比如:
MDN(output_dimension,number_mixtures)
對于本教程的問題,我們隻需要定義輸出次元為1,因為我們預測的y值次元為1。 添加更多的混合狀态數量會增加更多參數(模型更複雜,需要更長時間訓練),但可能有助于使預測結果更好。 你可以從訓練資料中看到曲線評估混合狀态的數量有5個,是以設定混合狀态的數量N_MIXES = 5是比較好的方式。
對于MDN,我們需定義适合的損失函數,使其可以處理混合狀态參數,損失函數必須考慮輸出維數和混合狀态的數量。
N_HIDDEN = 12
N_MIXES = 6
model = keras.Sequential()
model.add(keras.layers.Dense(N_HIDDEN, batch_input_shape=(None, 1), activation='relu'))
model.add(keras.layers.Dense(N_HIDDEN, activation='relu'))
model.add(mdn.MDN(1, N_MIXES))
model.compile(loss=mdn.get_mixture_loss_func(1,N_MIXES), optimizer=keras.optimizers.Adam())
model.summary()
複制
網絡結果如下圖所示:
4
訓練模型
history = model.fit(x=x_data, y=y_data, batch_size=128, epochs=500, validation_split=0.2)
複制
5
可視化
我們通過圖表的方式檢視模型是如何訓練的。 從下圖,我們可以看到,經過一定的訓練後,訓練效果的提升相當緩慢。對于本教程,1.5左右的損失值産生了相當好的結果。
代碼如下:
plt.figure(figsize=(10, 5))
plt.ylim([0,9])
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.show()
複制
6
預測
現在我們可以通過在x軸上産生3000個均勻間隔點來預測y軸的數值,測試下訓練好的模型。注意,y_test包含分布的參數,而不是圖上的實際點。要在圖上找到點,我們需要從每個分布中進行采樣,采樣後的結果為y_samples。
x_test = np.float32(np.arange(-15,15,0.01))
NTEST = x_test.size
print("Testing:", NTEST, "samples.")
x_test = x_test.reshape(NTEST,1)
y_test = model.predict(x_test)
y_samples = np.apply_along_axis(mdn.sample_from_output, 1, y_test, 1, N_MIXES,temp=1.0)
複制
對比下預測結果:
plt.figure(figsize=(4, 4))
plt.plot(x_data,y_data,'ro',x_test, y_samples[:,:,0], 'bo',alpha=0.3,markersize = 1)
plt.show()
複制
附上keras實作的MDN:
https://github.com/cpmpercussion/keras-mdn-layer