JS,一门从浏览器兴起,却不止于浏览器的脚本,个人一直认为其是最有潜力的脚本语言。不只是因为ES6优雅的语法,更重要的是其易上手,跨平台的优点。

Node将JS从browser带去了client是革命性的,使得常常被冠以“浏览器脚本”的JS成为一门足以和PHP,PY匹敌的通用性脚本。

关于tensorflow,这里就不多做介绍,简而言之就是一个深度学习的框架,而为众人所知的是他对python的支持性非常高,几乎可以说到tf,那就是python的天下,以至于说到深度学习,众人都会联想到py,Google也是首推python在深度学习领域的使用,这和python早期与Google的渊源有关。不过,笔者多次和py的交手后,对py的这种偏自然的语法及其不适应,很难接受这么“优秀的语言”(宁愿ruby,亦不python),这样的感受始于笔者最早一次使用深度学习做金融数据分析的毕业设计,python可把我害苦了。那时的我对JS爱不释手,曾企图使用JS自己构建神经网络。

终于,tfjs还是来了(在做毕设那会我就预言了要深度学习可以完全用JS开发),然而,Google最早对tfjs的态度(其实是在Google大脑工作的开源开发者)似乎还是停留在“JS要在浏览器上跑”的这种观念,所以笔者使用0.0.x版本都是基于浏览器开发的,@tensorflow/tfjs这个项目,其实在vue或者react等项目上非常的合适,但是对于client的node来说就不是那么友好,很多接口是不支持的。

下面来说说,这两个项目的区别,打开 npmjs.com,搜索tfjs



可以看到,tfjs和tfjs-node,下面来说说这个两个项目有什么不同,tfjs是为浏览器端而设计的,而tfjs-node是为node端设计的。

存储

个人认为,这两个项目最大的区别就是存储model的差别,早期的tfjs是基于浏览器的,故而可以将训练后的model存储在localstorage,indexedb,当然还可以通过formdata上传至http服务器。下面我来测试一下:

localStorage存储Model

浏览器代码

<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js"> </script>
<script>
(async ()=>{
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'});
const xs = tf.tensor2d([1, 2, 3, 4], [4, 1]);
const ys = tf.tensor2d([1, 3, 5, 7], [4, 1]);
model.fit(xs, ys).then(() => {
model.predict(tf.tensor2d([5], [1, 1])).print();
});
let save = await model.save('localstorage://model-1')
})()
</script>
</head>
<body>
</body>
</html>

在chrome的浏览器application中可以看到已经存储的localstorage,tfjs一共存储了5个key-value,目前不懂里面的意义是什么

indexdb存储Model

事实上我之前做为前端也没有使用过indexdb,主要还是因为indexdb相对于webstorage过于庞大复杂,复杂的数据一般都丢给了后端用MySQL,笔者非常喜欢使用localstorage。以下尝试使用indexdb存储训练模型

浏览器代码

<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js"> </script>
<script>
(async ()=>{
let model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'});
//目标y=2x-1
const xs = tf.tensor2d([1, 2, 3, 4], [4, 1]);
const ys = tf.tensor2d([1, 3, 5, 7], [4, 1]);
console.log('开始训练')
for(let i=0;i<2000;i++) await model.fit(xs, ys)
console.log('训练完毕')
let save = await model.save('indexeddb://model-1')
model = await tf.loadLayersModel('indexeddb://model-1');
model.predict(tf.tensor2d([10],[1,1])).print();
})()
</script>
</head> <body>
</body>
</html>

可以看到训练模型被存储再indexdb数据库中

Model上传至服务器

前端代码,训练的过程是一毛一样的,上述所有浏览器的深度学习法唯独就是最后一步存储不太一样,这里需要用到browserHTTPRequest的request请求,特别注意browserHTTPRequest不可以再node下跑,会提示要求再浏览器中使用,传输的文件形式应该是通过form-data到达服务器的。

前端代码

<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js"> </script>
<script>
(async ()=>{
let model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'});
//目标y=2x-1
const xs = tf.tensor2d([1, 2, 3, 4], [4, 1]);
const ys = tf.tensor2d([1, 3, 5, 7], [4, 1]);
console.log('开始训练')
for(let i=0;i<2000;i++) await model.fit(xs, ys)
console.log('训练完毕')
let save = await model.save(tf.io.browserHTTPRequest('http://localhost:3000/Upload/test', {method: 'PUT'}))
})()
</script>
</head>
<body>
</body>
</html>

后端node实现文件接受,转储

	static async test(req,res){
let json = req.files.model.weights.bin.path
let path = req.files.model.json.path
const r = fs.createReadStream(json)
const w = fs.createWriteStream('./test.json')
r.pipe(w)
}

上述代码是一个代码块,由于我用到了自己构建的一个node框架,是根据TP的MVC模式设计的,关键代码如上,从req的files中取出文件,用fs模块转储到特定目录中。

以上所述均是tfjs框架的存储方式,有很大的缺点,那就是在浏览器端训练,训练后的模型只能存储在浏览器中,无法做大数据的收集,即使可以上传到服务器,训练的模型依然不能得到安全,可持续化,完整的保证,当然也有其一些优点,节省了大量服务器的资源,毕竟深度学习训练如果涉及到图形,音频,语言文字的话是相当复杂和消耗资源的,将训练过程合理的分压到客户端,最后再收集到服务器却是一种很“鸡贼”的手法,在这里我只能说妙啊妙啊,不过这满足不了程序员的控制欲,下面介绍一下tfjs-node的存储,由于tfjs-node的安装比tfjs复杂一些,如何安装tfjs-node请查看笔者上一篇博客。

Node的文件系统fs存储方式

欲用文件系统,请先安装tfjs-node。

node代码

const tf = require("@tensorflow/tfjs-node");
const model = tf.sequential(); //定义网络结构,层数,单元数,输入
model.add(tf.layers.dense({units: 1, inputShape: [1]})); //定义优化器
model.compile({loss: 'meanSquaredError', optimizer: 'sgd'}); //目标:y=2x+1;
const xs = tf.tensor2d([1,2,3,5], [4,1]);
const ys = tf.tensor2d([3,5,7,11], [4,1]); //使用async是因为训练中有异步操作,需要用到await
(async ()=>{
//训练1000次
for(let i=0;i<1000;i++) {
await model.fit(xs,ys);//等待训练的异步操作
console.log(`第${i}次`);
}
model.predict(tf.tensor2d([5,3,99], [3, 1])).print();
let save = await model.save('file://./model')
})();

上述代码中,其实训练过程和存储过程与browser大同小异,且存储的API都是model的save方法。

使用上述代码后,js所在的当前目录会产生一个model目录,并多出两个记忆文件模型。

至此,tfjs-node了却了我半年的顾虑,为js做深度学习保存模型寻找一个文件系统的方式,这样才能完全使用js进行深度学习的开发了。

tfjs-node初体验:训练模型的存储的更多相关文章

  1. node初体验(一)

    1.node.js是一个构建在chrome V8引擎上的javascript运行环境 2.node.js特点:单线程.事件驱动.非阻塞IO模型.轻量 3.node.js是单线程的(多个请求都是一个线程 ...

  2. Blazor初体验之寻找存储client-side jwt token的方法

    https://www.cnblogs.com/chen8854/p/securing-your-blazor-apps-authentication-with-clientside-blazor-u ...

  3. node初体验(二)

    1.静态资源访问,需要设置路由和响应标头 2.url模块.path模块.querystring模块 Url { protocol: null, slashes: null, auth: null, h ...

  4. Node.js 网页瘸腿爬虫初体验

    延续上一篇,想把自己博客的文档标题利用Node.js的request全提取出来,于是有了下面的初哥爬虫,水平有限,这只爬虫目前还有点瘸腿,请看官你指正了. // 内置http模块,提供了http服务器 ...

  5. node.js 初体验

    node.js 初体验 2011-10-31 22:56 by 聂微东, 174545 阅读, 118 评论, 收藏, 编辑 PS: ~ 此篇文章的进阶内容在为<Nodejs初阶之express ...

  6. Microsoft IoT Starter Kit 开发初体验-反馈控制与数据存储

    在上一篇文章<Microsoft IoT Starter Kit 开发初体验>中,讲述了微软中国发布的Microsoft IoT Starter Kit所包含的硬件介绍.开发环境搭建.硬件 ...

  7. node.js + express 初体验【hello world】

    [node.js]  一个神奇的XX 呵呵 :) 不知道怎么形容他才好! [express] 是node.js 开发web应用程序的框架 开发环境:XP 大家共同进步吧 :) 一:前期准备: 1:下载 ...

  8. (数据科学学习手札35)tensorflow初体验

    一.简介 TensorFlow时谷歌于2015年11月宣布在Github上开源的第二代分布式机器学习系统,目前仍处于快速开发迭代中,有大量的新功能新特性在陆续研发中: TensorFlow既是一个实现 ...

  9. Flume日志采集系统——初体验(Logstash对比版)

    这两天看了一下Flume的开发文档,并且体验了下Flume的使用. 本文就从如下的几个方面讲述下我的使用心得: 初体验--与Logstash的对比 安装部署 启动教程 参数与实例分析 Flume初体验 ...

随机推荐

  1. 基于ssh开发彩票购买系统的设计与实现毕业设计

    开发环境: Windows操作系统开发工具: MyEclipse+Jdk+Tomcat+MYSQL数据库 运行效果图: 源码及原文地址:http://javadao.xyz/forum.php?mod ...

  2. 为什么常用 Map<> map = new HashMap()

    在初学Java的时候,经常能看到教材上的写法,使用了接口Map来引用一个map,而不是它的具体实现,那么这样做的好处是什么呢? <Effective Java>第52条:通过接口引用对象 ...

  3. JAVA初学者——逻辑运算符

    Hello!大家好,我是浩宇大熊猫~ 加油~充实每一天~ java里面的逻辑运算符有与(&).或(|).异或(^).非(!) 其实这些初高中数学课都学过哈,很简单~ public class ...

  4. 微信获得access_token

    <?php //获取access_token $appid = 'wx47a6fc3c1187e60d'; //测试账号appid $appsecret = '525f76d57c7bd7200 ...

  5. CodeForces 1294D MEX maximizing(思维)

    http://codeforces.com/contest/1294/problem/D 大致题意: 刚开始有一个空集合,会往里添加q次数,每次加一个值,而且你可以让这个数任意加减x若干次 每次添加后 ...

  6. IOC 本质是为了实现 AOP|火影鸣人

    @JFinal 波总在 JFinal 4.8 发布新闻的评论 中给出了下面的表述: IOC 本质是为了实现 AOP 我有点吃惊, 没想到 Java 界的大佬对这两个概念有和我完全不一致的认识. 所以写 ...

  7. 吴裕雄--天生自然ShellX学习笔记:Shell printf 命令

    printf 命令模仿 C 程序库(library)里的 printf() 程序. printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好. printf ...

  8. 吴裕雄--天生自然 JAVA开发学习:修饰符

    public class InstanceCounter { private static int numInstances = 0; protected static int getCount() ...

  9. 从西班牙、英国出租车与Uber之争,看共享打车未来发展趋势

    一种新事物.新服务的崛起,必然会损害传统事物和服务的既得利益.比如在电灯泡发明之初,煤油灯企业就将电灯泡专利收购并"雪藏"以维护自己的利益.而电商的崛起,也让传统的线下实体店受到严 ...

  10. JavaScript详解(三)

    JavaScript的数组 JavaScript中的数组具有相当的灵活性,除了能存储数据外,还提供了一系列的属性和方法.因为JavaScript本身是一个弱类型语言,故其数组不会限制存放数据的类型. ...