前段時間,我作了個RNN預測金融數據的畢業設計(華爾街),當時TensorFlow.js尚未發佈,我不得已使用了keras對數據進行了訓練,而且擬合好了不一樣期貨的模型,由於當時畢設的網站是用node.js寫的,爲了能夠在網站中預測,我採起的方案是:用python進行訓練和預測,而後使用node.js運行python命令,最終在瀏覽器上可視化出來,這也算的上是黑科技了!javascript
不過這樣經過一個解釋器調用另外一個解釋器,語言之間互相通訊其實不是什麼好的設計方式,且不說維護兩門語言的困難,調用其餘語言過程會產生的錯誤和性能問題較多,並且顯得整個項目很混亂,強迫症受不了。css
現在,Google開始官推TensorFlow的JS API又是前端福音。但根據官網的介紹,TensorFlow.js目前尚不成熟,JS方面還沒有實現像Python那麼豐富的學習API。因此各類基於TF的深度學習項目若是須要使用JS重構也須要慢慢過渡。html
更多關於TensorFlow.js的目前支持情況請參閱:https://www.linpx.com/p/you-want-to-know-that-everything-about-tensorflowjs-is-here.html前端
如上所述,TensorFlow.js尚不能導出訓練文件,但能夠導入訓練文件,今天根據官網提供的文檔,將我畢設項目的預測功能重構爲純JS實現。方法是經過導入python訓練好的文件,依靠TensorFlow.js調用進行預測。java
本文是對TensorFlow官網文檔的學習和實用,記錄了筆者用tfjs導入模型進行預測的過程,參考資料:https://js.tensorflow.org/tutorials/import-keras.htmlnode
接下來就開始翻譯~~哦不,是上手coding。python
如tfjs官方所述,咱們一般在keras中訓練後導出的是H5格式的文件,tfjs不能直接理解h5文件,故須要先將h5轉換格式。git
安裝tensorflowjs:程序員
pip install tensorflowjs
能夠看到tensorflowjs版本還很年幼,看來發布不久。github
注意下面這些操做依然是基於python作的,咱們先嚐試手動轉換文件格式。
pip安裝完tensorflowjs後,進入cmd嘗試轉換H5文件
tensorflowjs_converter --input_format keras D:\pro\WallStreet\tf_modules\models\20.h5 D:\pro\WallStreet\tf_modules\models\20
對上面的命令進行一下解釋:
input_format這個option後面跟着的是原始文件格式來源(keras),而後緊跟着h5文件的地址,而後是轉化後保存的目標目錄。
這裏注意一下,h5最終會被轉化爲多個文件,因此目標是個目錄而不是文件,目錄裏有:
其中model.json是js中須要調用的文件,另外兩個是訓練後的二進制文件。
The target TensorFlow.js Layers format is a directory containing a model.json file and a set of sharded weight files in binary format. The model.json file contains both the model topology (aka "architecture" or "graph": a description of the layers and how they are connected) and a manifest of the weight files.
這是Google的原文,翻譯過來是tensorflowjs最終格式是個目錄 ,包含了一個model.json,還有一些碎片的權重(神經網絡中的名詞:訓練過程優化所得的w值)文件(二進制格式)。json文件則記錄神經網絡的拓撲結構,一種對神經網絡不一樣層,不一樣神經元之間鏈接的狀態的記錄。大意就是保存了訓練後的模型結構!
這段話比較玄學,以我多年對計算機各類理論的融匯貫通後的理解是,神經網絡成型後的模型(也就是訓練事後的文件),由兩部分組成,一個是神經元自己的內部權重(一些數據),還有事神經元之間鏈接的橋樑(一些結構),綜合起來仍是——「數據結構」,這個數據結構相似圖,有節點和鏈接,節點仍是一些多維的權值。
因而可知,一個真正的程序員應當好好學習基本的專業課包括數學知識,而不是停留在語言層面,不然涉及到高深的技術時,終將也會茫然。
廢話多了,在實際項目中,咱們不可能手動轉換,考慮直接在keras訓練後生成tensorflowjs文件,這應是自動化的過程
以下:
import tensorflowjs as tfjs ... # 建立RNN,並訓練 model = Sequential() model.add(LSTM(128, input_shape=(1, window))) model.add(Dense(1)) model.compile(loss='mean_squared_error', optimizer='adam') model.fit(trainX, trainY, epochs=100, batch_size=100, verbose=2) #保存訓練模型 #model.save('tf_modules/models/%s.h5'%g_id) tfjs.converters.save_keras_model(model,'tf_modules/models/%s'%g_id)
這只是我改進項目中的python訓練代碼的片斷,能夠看到原來的model.save是保存爲h5,被我註釋後改爲了保存爲tensorflowjs文件集,使用的是tensorflowjs下的 converters.save_keras_model
方法。
萬事俱備,只欠東風,能夠經過JavaScript導入模型預測了。
當到達這一步時,覺得要大功告成了,too young!
你可能會說很簡單啊,tfjs必定提供了讀取模型的方法,沒錯,確實提供了,不過很惋惜不支持node.js,筆者在寫篇博客期間,不停翻閱各類國外文檔,耗費了整整一下午,官方給出的例子太過簡單了:
import * as tf from '@tensorflow/tfjs'; const model = await tf.loadModel('https://foo.bar/tfjs_artifacts/model.json'); const example = tf.fromPixels(webcamElement); // for example const prediction = model.predict(example);
就這麼短短几行,一個例子,意思是:「你用loadmodel+predict方法就好了!」
這對於tensorflow新手來講無疑又是巨大災難。
最關鍵的是,筆者注意到loadModel()方法傳入的是一個http地址,而研究了一下午,在嘗試了node.js下各類文件讀取,http訪問後發現原來這貨也只支持瀏覽器端的實現,一句話歸納就是目前的tfjs導入模型不支持node.js!
如下就是結論的由來,若是有成功使用Node.js讀取model的請留言幫助我,感激涕零。
那怎麼辦呢,硬着頭皮在瀏覽器下運行咯。具體以下:
第一步:保存模型到靜態目錄下
爲了browser端能夠訪問到model.json以及另外兩個權重的二進制文件,在python代碼訓練完成後保存模型到靜態可訪問目錄下,這對於node.js來講十分重要,由於node.js經過express中間件能夠給定一個靜態資源目錄(就是存放css,js,img的目錄)
例如:
//配置靜態文件爲assets目錄 app.use(express.static(__dirname + "/assets"))
這是指定的靜態文件的根目錄,訓練後的模型也放到這個目錄中,瀏覽器才能訪問到。
個人方法是在這個目錄下新建一個models目錄專門存放model,而且不一樣商品訓練出來的模型都是一個獨立目錄(前面說了,tensorflowjs轉化後造成的是一個目錄),目錄名字是商品在數據庫的主鍵ID。
這樣保存模型的代碼就變成這樣了
tfjs.converters.save_keras_model(model,'assets/tf_models/%s'%g_id
第二步:瀏覽器script引入tfjs
script(src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.11.4",type="text/javascript")
以上是筆者使用了jade引擎,能夠自行轉化爲html的script標籤
第三步:預測
如下的JavaScript代碼都是在瀏覽器中運行的:
async function get_predict_data(g_id){ //預測 let model = await tf.loadModel(`/tf_models/${g_id}/model.json`) let response = await fetch(`/futures/data/${g_id}/30`); let data = (await response.json()).data; let max_price = []; for(let i in data){ max_price.push(data[i].max_price); } scaler = new min_max_scale(max_price); max_price = scaler.fit(max_price); let tf_price = tf.tensor3d(max_price,[1,1,30]); let prediction = model.predict(tf_price); let a = (await prediction.data())[0]; a = scaler.inverse(a); } //數據歸一化 function min_max_scale(data){ this.max = Math.max(...data); this.min = Math.min(...data); this.fit = function(){ for(i in data){ data[i] = (data[i]-this.min)/(this.max-this.min); } return data; } this.inverse = (to_inverse) => to_inverse*(this.max-this.min)+this.min }
最後這個a即爲瀏覽器下跑模型預測的值。
別看代碼很簡短,大體用了兩個方法,一個是預測方法,另外一個歸一化數據方法,這裏面坑坑可多了。
數據標準化,這裏使用的是歸一化,在python下使用的是sklearn的MinMaxScaler對象,而npm庫中翻遍了也找不到類似的功能模塊,只好我本身實現了。
什麼是歸一化,算法是什麼?請參考:https://blog.csdn.net/Jiaach/article/details/79484990
能夠看到,get_predict_data(預測函數)中除了官方給出的loadModel和predict函數外還有許多陌生的函數(均來自於tensorflow),這些函數的API對於新手來講十分陌生,官網給的也不是很明確,並且仍是英文的,今天先不介紹,這些函數留給從此《JS作深度學習博客系列》一個個介紹。
tensorflow.js導入模型到此告一段落。
完整代碼參考個人github項目:https://github.com/devilyouwei/WallStreet