C++實現神經網路之五—模型的保存和載入以及畫出實時輸出曲線

模型的保存和載入

在我們完成對神經網路的訓練之後,一般要把模型保存起來。不然每次使用模型之前都需要先訓練模型,對於data hungry的神經網路來說,視數據多寡和精度要求高低,訓練一次的時間從幾分鐘到數百個小時不等,這是任何人都耗不起的。把訓練好的模型保存下來,當需要使用它的時候,只需要載入就行了。

現在需要考慮的一個問題是,保存模型的時候,我們到底要保存哪些東西?

之前有提到,可以簡單的認為權值矩陣就是所謂模型。所以權值矩陣一定要保存。除此之外呢?不能忘記的一點是,我們保存模型是為了載入後能使用模型。顯然要求載入模型之後,輸入一個或一組樣本就能開始前向運算和反向傳播。這也就是說,之前實現的時候,forward()之前需要的,這裡也都需要,只是權值不是隨意初始化了,而是用訓練好的權值矩陣代替。基於以上考慮,最終決定要保存的內容如下4個:

  1. layer_neuron_num,各層神經元數目,這是生成神經網路需要的唯一參數。
  2. weights,神經網路初始化之後需要用訓練好的權值矩陣去初始化權值。
  3. activation_function,使用神經網路的過程其實就是前向計算的過程,顯然需要知道激活函數是什麼。
  4. learning_rate,如果要在現有模型的基礎上繼續訓練以得到更好的模型,更新權值的時候需要用到這個函數。

再決定了需要保存的內容之後,接下來就是實現了,仍然是保存為xml格式,上一篇已經提到了保存和載入xml是多麼的方便:

//Save model;n void Net::save(std::string filename)n {n cv::FileStorage model(filename, cv::FileStorage::WRITE);n model << "layer_neuron_num" << layer_neuron_num;n model << "learning_rate" << learning_rate;n model << "activation_function" << activation_function;nn for (int i = 0; i < weights.size(); i++)n {n std::string weight_name = "weight_" + std::to_string(i);n model << weight_name << weights[i];n }n model.release();n }nn //Load model;n void Net::load(std::string filename)n {n cv::FileStorage fs;n fs.open(filename, cv::FileStorage::READ);n cv::Mat input_, target_;nn fs["layer_neuron_num"] >> layer_neuron_num;n initNet(layer_neuron_num);nn for (int i = 0; i < weights.size(); i++)n {n std::string weight_name = "weight_" + std::to_string(i);n fs[weight_name] >> weights[i];n }nn fs["learning_rate"] >> learning_rate;n fs["activation_function"] >> activation_function;nn fs.release();n }n

實時畫出輸出曲線

有時候我們為了有一個直觀的觀察,我們希望能夠是實時的用一個曲線來表示輸出誤差。但是沒有找到滿意的程序可用,於是自己就寫了一個非常簡單的函數,用來實時輸出訓練時的loss。理想的輸出大概像下面這樣:

為什麼說是理想的輸出呢,因為一般來說誤差很小,可能曲線直接就是從左下角開始的,上面一大片都沒有用到。不過已經能夠看出loss的大致走向了。

這個函數的實現其實就是先畫倆個作為坐標用的直線,然後把相鄰點用直線連接起來:

//Draw loss curven void draw_curve(cv::Mat& board, std::vector<double> points)n {n cv::Mat board_(620, 1000, CV_8UC3, cv::Scalar::all(200));n board = board_;n cv::line(board, cv::Point(0, 550), cv::Point(1000, 550), cv::Scalar(0, 0, 0), 2);n cv::line(board, cv::Point(50, 0), cv::Point(50, 1000), cv::Scalar(0, 0, 0), 2);nn for (size_t i = 0; i < points.size() - 1; i++)n {n cv::Point pt1(50 + i * 2, (int)(548 - points[i]));n cv::Point pt2(50 + i * 2 + 1, (int)(548 - points[i + 1]));n cv::line(board, pt1, pt2, cv::Scalar(0, 0, 255), 2);n if (i >= 1000)n {n return;n }n }n cv::imshow("Loss", board);n cv::waitKey(10);n }n

至此,神經網路已經實現完成了。完整的代碼可以在Github上找到。

下一步,就是要用編寫的神經網路,用實際樣本開始訓練了。下一篇,用MNIST數據訓練神經網路。

源碼鏈接

LiuXiaolong19920720/simple_netgithub.com圖標
推薦閱讀:

1.26【OpenCV圖像處理】模板匹配

TAG:OpenCV | C | 神经网络 |