前段时间,我作了个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