上一篇文章我們介紹的線性模型的求解,但有很多模型是非線性的,比如:
這裡表示有兩個輸入,一個輸出。
現在我們已經不能採用y=ax+b的形式去定義一個函式了,我們只能知道輸入變數的數量,但不知道某個變數存在幾次方的分量,所以我們採用一個神經網路去定義一個函式。
我們假設只有一個輸入、一個輸出,神經網路模型結構類似上圖,其中藍色的路徑仍為線性模型,紅色路徑為階躍函式,是非線性模型。
以上模型只有三個神經元,設輸入為x,隱藏層為h,啟用函式輸出為a,最終輸出為y,整個資料計算流情況如下:
以上共有6+3+1個變數,整個訓練的過程就是要解出這些變數。官方教程內有自定義神經網路模型的求解程式碼,和解線性模型的流程一致,大致以下幾個步驟:
1、預設所有k=1,b=0;
2、將x代入模型,求得pred_y,通過pred_y和y計算損失函式,在通過損失函式來計算梯度;
3、通過梯度調整k、b的值
4、重複上述2、3過程,直到損失函式足夠小。
具體程式碼請參看官方示例程式碼。
我們這篇文章將採用Keras封裝好的方法來進行神經網路的訓練和應用。
整個程式包括:建立模型、訓練模型和應用模型三個過程。
主執行緒程式碼:
public void Run() { //1、建立模型 Model model = BuildModel(); model.compile(loss: keras.losses.MeanSquaredError(), optimizer: keras.optimizers.SGD(0.02f), metrics: new[] { "mae" }); model.summary(); //2、訓練模型 (NDArray train_x, NDArray train_y) = PrepareData(1000); model.fit(train_x, train_y, batch_size: 64, epochs: 100); //3、應用模型(消費) test(model); }
1、建立模型
BuildModel方法定義如下:
/// <summary> /// 構建網路模型 /// </summary> private Model BuildModel() { // 網路引數 int num_features = 1; // data features int n_hidden_1 = 16; // 1st layer number of neurons. int num_out = 1; // total output . var model = keras.Sequential(); model.add(keras.Input(num_features)); model.add(keras.layers.Dense(n_hidden_1)); model.add(keras.layers.LeakyReLU(0.2f)); model.add(keras.layers.Dense(num_out)); return model; }
以上:Input為輸入層,Dense為全連線層,啟用函式可選包括:Sigmod、ReLu、LeakyReLu、tanh
model.compile方法定義該模型的訓練方式:
loss: keras.losses.MeanSquaredError()表示損失函式採用均方差公式(MSE),這個公式上一篇文章介紹過
optimizer: keras.optimizers.SGD(0.02f)表示引數更新採用隨機梯度下降法(SGD),學習率為0.02
metrics: new[] { "mae" }表示要顯示的模型評價方法為平均絕對誤差(Mean absolute Error),另外此處還有一個選項為acc,表示準確性( accuracy),後面在進行分類學習時將採用這種評價方法。
model.summary()方法將列印出該模型的摘要資訊。
2、訓練模型
(NDArray train_x, NDArray train_y) = PrepareData(1000);
model.fit(train_x, train_y, batch_size: 64, epochs: 100);
首先要載入學習資料,然後將學習資料提供給fit方法進行學習,batch_size 表示每次運算取的資料量,epochs表示迴圈迭代的次數。所有學習資料用完一次就表示一個epoch,1000除以64等於15.625,所以每計算16次就表示一個epoch。
整個訓練過程中將列印出下列資訊:
PrepareData方法:
/// <summary> /// 載入訓練資料 /// </summary> /// <param name="total_size"></param> private (NDArray, NDArray) PrepareData(int total_size) { float[,] arrx = new float[total_size, 1]; float[] arry = new float[total_size]; for (int i = 0; i < total_size; i++) { float x = (float)random.Next(-400, 400) / 100; float y = x * x; arrx[i, 0] = x; arry[i] = y; } NDArray train_X = np.array(arrx); NDArray train_Y = np.array(arry); return (train_X, train_Y); }
該方法生成1000個符合y=x*x的標準資料。
3、應用模型
學習完成以後,該模型就可以用於實際應用了。我們隨機生成一下資料,將模型計算的結果和理論實際的數值進行比較,可以判斷模型是否有效。
/// <summary> /// 消費模型 /// </summary> private void test(Model model) { int test_size = 10; for (int i = 0; i < test_size; i++) { float x = (float)random.Next(-300, 300) / 100; float y = x * x; var test_x = np.array(new float[1, 1] { { x } }); var pred_y = model.Apply(test_x); Console.WriteLine($"{i}:x={(float)test_x:0.00}\ty={y:0.0000} Pred:{(float)pred_y[0].numpy():0.0000}"); } }
執行結果如下:
看結果情況,基本像那麼一回事。
【相關資源】
原始碼:Git: https://gitee.com/seabluescn/tf_not.git
專案名稱:NonlinearRegressionWithKeras