zoukankan      html  css  js  c++  java
  • tfjs-node初体验:训练模型的存储

    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进行深度学习的开发了。

  • 相关阅读:
    关于总线的总结
    我已经理解了并发和并行的区别
    关于CPU的一些基本知识总结
    shell生成指定长度的随机数
    进程、线程、协程、例程、过程的区别是什么?
    Perl输出带颜色行号或普通输出行
    Ruby数组(2):数组方法详细整理
    Linux find常用用法示例
    MariaDB官方手册翻译
    Ruby中to_s和to_str、to_i和to_int、to_a和to_ary、to_h和to_hash的解释说明
  • 原文地址:https://www.cnblogs.com/devilyouwei/p/10632112.html
Copyright © 2011-2022 走看看