0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

谷歌在TensorFlow开发者峰会上发布TensorFlow的JavaScript版本

zhKF_jqr_AI 来源:未知 作者:李倩 2018-07-12 08:47 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

编者按:今年4月,谷歌在TensorFlow开发者峰会上发布TensorFlow的JavaScript版本,引起开发者广泛关注。如今3个月过去了,大家学会使用这个机器学习新框架了吗?在这篇文章中,我们将用一个初级项目Neural Titanic来演示如何使用TensorFlow.js,联系到最近发生在泰国的事故,这次我们选用的数据集是“泰坦尼克号”,目标是分析哪些人更能从悲剧中幸免于难(二元分类)。

Demo

注:本文适合对前端JavaScript开发有基本了解的读者。

神经网络

经过Geoffrey Hinton、Yoshua Bengio、Andrew Ng和Yann LeCun等人的不懈努力,如今神经网络终于可以正大光明地站在阳光下,并在现实中有了用武之地。众所周知,传统统计模型可以处理结构化的数据,但对非结构化的数据,如图像、音频和自然语言却无可奈何。现在,通过往神经网络中添加更多层神经元,也就是我们常说的深度学习研究,对非结构化数据建模已经不再是难事。

以图像建模为例,图像中最简单的特征是边缘,这些边缘是形成纹理的基础,纹理是形成简单对象的基础,而简单对象又是形成复杂对象的基础。这种关系正好契合深层神经网络的多层结构,因此我们也能学习这些可组合的特征。(考虑到文章的目的是介绍TensorFlow.js,我们对深度学习的介绍就此打住。)

如需要以上PPT,欢迎私信哦

在过去这几十年中,随着计算机算力和可用数据的急剧增加,神经网络已经成为解决诸多现实世界问题的可行方案。与此同时,像TensorFlow这样的机器学习库也在快速崛起,鼓励开发者尝试用神经网络解决问题。虽然完全搞懂神经网络不是一时半会儿就能做到的,但我们希望这篇文章能激发开发者兴趣,鼓励他们去创建自己的的神经网络程序。

项目概述

如上所述,神经网络非常适合对非结构化数据进行建模,而本文的示例数据集是泰坦尼克号,它只包含表格数据。这里我们先澄清一个误区,看完之前的介绍,一些人可能会认为神经网络是万能的,它比传统统计模型更好,但事实上,对于简单数据,模型结构越简单,它的性能就越好,因为那样越不容易出现过拟合。

例如泰坦尼克号数据集,或者其他几乎所有类型的表格数据,神经网络在处理它们时需要用到的超参数有batch-size、激活函数和神经元数量等,但像决策树这样的常规算法只需调整更少超参数,最后性能也差不多。所以虽然鼓励新手多多尝试,但当我们建模时,真的没有必要事事都用神经网络。

在这个项目中,因为神经网络处理的是简单数据集的二元分类任务,我们会结合可视化技术,具体介绍最后的单隐藏层神经网络。如果你已经精通前端JavaScript开发,也能熟练使用像React这样的前端框架,你可以在读完本文后再去学习官方文档,相信它会让你对TensorFlow.js产生更多兴趣:js.tensorflow.org/tutorials/mnist.html

数据集和建模概述

泰坦尼克号数据集适合初学者,由于比较小,影响输出结果的各项特征也比较好找。我们的任务是根据表格数据预测乘客的生存概率,因此可以被用来辅助预测的列是X,预测的目标列则是Y。下面是数据集中的部分数据:

对应X和Y,我们可以获得:

预测特征(X)

pClass:船票等级(1等、2等、3等)

name:乘客的姓名

sex:乘客的性别

age:乘客的年龄

sibsp:船上和乘客相关的兄弟姐妹、配偶人数

parch:船上与乘客相关的父母和孩子人数

ticket:乘客的票号

fare:乘客为船票支付的金额

cabin:乘客所在船舱

Embarked:登船港口(C=Cherbourg, Q=Queenstown, S=Southampton)

目标标签(Y)

survived:乘客幸存为1,死亡为0

原数据集中包含超过1000名乘客的信息,这里为了简洁直观,我们假装上表就是我们的数据集,X和y的映射关系如下所示:

从技术意义上讲,神经网络为非线性函数拟合提供了一个强大的框架。如果把上图转换成函数形式,它就是:

对于神经网络,如果我们要模型学会其中的映射关系,这个学习过程被称为训练。最后得到的结果必定是个近似值,而不是精确函数,因为如果是后者,这个神经网络就过拟合了,它强行记住了数据集的所有结果,这样的模型是没法用在其他数据上的,泛化(通用化)水平太低。作为深度学习实践者,我们的目标是构建近似上述函数的神经网络体系结构,让它不仅在训练集上表现出色,也能被推广到从未见过的数据上。

项目设置

为了防止每次开发都要重新绑定源代码,这里我们先用webpack bundler把JavaScript源代码和webpack dev服务器捆绑起来。

在开始项目前,我们先做一些设置:

安装Node.js

到github上下载这个repo:github.com/Andrewnetwork/NeuralTitanic

打开终端,再打开下载的repo

设置终端类型:npm install

键入以下命令启动dev服务器:npm run dev

单击终端中显示的URL,或在Web浏览器中输入:localhost:8080/

在步骤4中,用npm来安装package.json中列出的项目依赖项。在步骤5中,启动开发服务器,上面会显示步骤6中需要点击的URL。这之后,每当我们保存对源代码的修改时,网页上会实时刷新内容,并显示更改。

如果需要捆绑源代码,只需运行npm run build,它会自动生成文件放进./dist/文件夹中。

代码

虽然文章开头我们展示了一个比较美观的Demo,但这里我们没有介绍index.html、index.js、ui.js等内容,一方面是因为本文假设读者已经熟悉现代前端JavaScript开发,另一方面是这些细枝末节介绍起来太复杂,容易讲不清楚。如果确实有需要,可以直接用步骤2中提到的repo,或者Python了解下?学起来很快的!:stuckouttongue:

preprocessing.js

function prepTitanicRow(row){

var sex = [0,0];

var embarked = [0,0,0];

var pclass = [0,0,0];

var age = row["age"];

var sibsp = row["sibsp"];

var parch = row["parch"];

var fare = row["fare"];

// Process Categorical Variables

if(row["sex"] == "male"){

sex = [0,1];

}elseif(row["sex"] == "female"){

sex = [1,0];

}

if(row["embarked"] == "S"){

embarked = [0,0,1];

}

elseif(row["embarked"] == "C"){

embarked = [0,1,0];

}

elseif(row["embarked"] == "Q"){

embarked = [1,0,0];

}

if(row["Pclass"] == 1){

pclass = [0,0,1];

}

elseif(row["Pclass"] == 2){

pclass = [0,1,0];

}

elseif(row["Pclass"] == 3){

pclass = [1,0,0];

}

// Process Quantitative Variables

if(parseFloat(age) == NaN){

age = 0;

}

if(parseFloat(sibsp) == NaN){

sibsp = 0;

}

if(parseFloat(parch) == NaN){

parch = 0;

}

if(parseFloat(fare) == NaN){

fare = 0;

}

return pclass.concat(sex).concat([age,sibsp,parch,fare]).concat(embarked);

}

对于任何数据分析工作,数据预处理是非常重要的,也是十分有必要的,上面的代码就在进行预处理:把分类变量转换为one-hot编码,并用0替代缺失值(NaN)。因为这是个简单数据集,事实上我们还可以更优雅一点,用算法来填补缺失值,但考虑到篇幅因素,这里我们都做简化处理。

}

exportfunction titanicPreprocess(data){

const X = _.map(_.map(data,(x)=>x.d),prepTitanicRow);

const y = _.map(data,(x)=>x.d["survived"]);

return [X,y];

}

在这里,我们把预处理函数prepTitanicRow映射到数据的每一行,这个函数的输出是特征变量X和目标向量y。

modeling.js

exportfunction createModel(actFn,nNeurons){

const initStrat = "leCunNormal";

const model = tf.sequential();

model.add(tf.layers.dense({units:nNeurons,activation:actFn,kernelInitializer:initStrat,inputShape:[12]}));

model.add(tf.layers.dense({units:1,activation:"sigmoid",kernelInitializer:initStrat}));

model.compile({optimizer: "adam", loss: tf.losses.logLoss});

return model;

}

现在我们就可以创建单隐藏层神经网络了,它已经被actFn和nNeurons两个变量参数化。可以发现,我们要近似的函数有多个输入,却只有一个输出,这是因为我们在上面的预处理步骤中扩展了特征空间的维度;也就是说,我们现在有一个步长为3的one-hot输入,而不是只有一个输入端口,如下图所示:

const initStrat = "leCunNormal";

上图中这些带箭头的线被称为“边”,它们自带权重,我们训练神经网络的最终目标就是把这些权重调整到最佳值。在刚开始训练的时候,因为对情况一无所知,这些边会被随机分配一个初始值,我们把它称为初始化策略。

一般情况下,这个初始化不用你自己声明,TensorFlow提供了通用性较强的默认初始化策略,在大多数情况下都表现良好。但就事论事,这个策略确实会影响神经网络性能,尤其是我们这次用到的数据集太小了,权重的初始值会对训练过程造成明显影响。所以这里我们自选一种初始化策略。

const model = tf.sequential();

这个序列模型对象就是我们用来构建神经网络的东西。它意味着当我们往里面添加神经网络层时,它们会按顺序堆叠,先输入层,再隐藏层,最后是输出层。

model.add(tf.layers.dense({units:nNeurons,activation:actFn,kernelInitializer:initStrat,inputShape:[12]}));

在这里,我们添加了一个输入层(大小为12),并在它后面又加了个密集连接的隐藏层。密集连接表示这一层的所有神经元都与上一层的每个神经元相连,在图中,神经元被表示为圆,但需要注意的是,它是个存储单位,我们的输入不是神经元。

隐藏层会继承定义图层的参数词典:我们定义了多少参数,它就接收多少参数。除了我们提供的参数,它还有一些默认参数:

units:神经元个数,这是个可调整的超参数。

activation:该层中应用于每个神经元的激活函数,对于本文已超纲,请自学选择。

kernelInitializer:初始化。

inputShape:输入空间大小,在我们的例子里是12。

model.add(tf.layers.dense({units:1,activation:"sigmoid",kernelInitializer:initStrat}));

这是我们整个神经网络的最后一层,它只是一个密集连接到隐藏层的单个输出神经元。我们用sigmoid函数作为该神经元的激活函数,因为函数的范围是[0,1],刚好适合二元分类问题。如果你还要深究“为什么这个函数能用于预测概率”,我只能简单告诉你,它和逻辑回归息息相关。

model.compile({optimizer: "adam", loss: tf.losses.logLoss});

截至目前,我们已经完成网络的搭建工作,最后就只剩下TensorFlow编译了。在编译过程中,我们会遇到两个新参数:

optimizer:这是我们在训练期间使用的优化算法。如果是新手,用Adam;如果很要求高,梯度下降会是你的最爱。

loss:这个参数的选择要多加注意,因为不同的建模问题需要不同的损失函数,它决定了我们会如何测量神经网络预测结果和实际结果之间的差异。这个误差会结合优化算法、反向传播算法进一步训练模型,一般情况下,我们用交叉熵。

最后就是神经网络模型的实际训练:

export async function trainModel(data,trainState){

// Disable Form Inputs

d3.select("#modelParameters").selectAll(".form-control").attr('disabled', 'disabled');

d3.select("#tableControls").selectAll(".form-control").attr('disabled', 'disabled');

// Create Model

const model = createModel(d3.select("#activationFunction").property("value"),

parseInt(d3.select("#nNeurons").property("value")));

// Preprocess Data

const cleanedData = titanicPreprocess(data);

const X = cleanedData[0];

const y = cleanedData[1];

// Train Model

const lossValues = [];

var lastBatchLoss = null;

// Get Hyperparameter Settings

const epochs = d3.select("#epochs").property("value");

const batchSize = d3.select("#batchSize").property("value")

// Init training curve plotting.

initPlot();

for(let epoch = 0; epoch < epochs && trainState.s; epoch++ ){

try{

var i = 0;

while(trainState.s){

// Select Batch

const [xs,ys] = tf.tidy(() => {

const xs = tf.tensor(X.slice(i*batchSize,(i+1)*batchSize))

const ys = tf.tensor(y.slice(i*batchSize,(i+1)*batchSize))

return [xs,ys];

});

const history = await model.fit(xs, ys, {batchSize: batchSize, epochs: 1});

lastBatchLoss = history.history.loss[0];

tf.dispose([xs, ys]);

await tf.nextFrame();

i++;

}

}catch(err){

// End of epoch.

//console.log("Epoch "+epoch+"/"+epochs+" ended.");

const xs = tf.tensor(X);

const pred = model.predict(xs).dataSync();

updatePredictions(pred);

const accuracy = _.sum(_.map(_.zip(pred,y),(x)=> (Math.round(x[0]) == x[1]) ? 1 : 0))/pred.length;

lossValues.push(lastBatchLoss);

plotLoss(lossValues,accuracy);

}

}

trainState.s = true;

createTrainBttn("train",data);

console.log("End Training");

// Enable Form Controls

d3.select("#modelParameters").selectAll(".form-control").attr('disabled', null);

d3.select("#tableControls").selectAll(".form-control").attr('disabled', null);

}

在具体介绍前,我们先看看一些常用的术语:

Epoch:在整个数据集上训练一次被称为一个epoch。

Mini-Batch:完整训练数据的子集。对于每个epoch,我们会把训练数据分成较小的子集一批批进行训练,通过对比,想必你也应该理解上一个术语的含义了。

如果还是觉得有困难,这里是完整版:

创建神经网络

预处理数据

Epoch Loop:我们手动设置的迭代次数

Mini-Batch Loop:我们还没有完成一个epoch,还有剩余数据,训练也没有停止——在Mini-Batch上训练模型。

End of epoch:已经进一步训练了模型,并让它对数据做了预测,而且已经用函数updatePredictions更新了预测结果。

什么是“async”和“await”?

ES6允许我们定义异步函数,常见的有async函数,这里应该没问题。当我们训练模型时,用await,它也是个异步函数,这样我们就能让模型在进入下一个epoch前先完成训练。

tf.tidy和tf.dispose?

这些函数涉及所创建的张量。你可以在张量或变量上调用dispose来清除它并释放其GPU内存;或者用tf.tidy执行一个函数并清除所有创建的中间张量,释放它们的GPU内存(它不清除内部函数的返回值)。

await tf.nextFrame();

如果没有这个,模型训练会冻结你的浏览器。其实查遍资料,关于它的记录非常少,这大概是TensorFlow.js早起开发时的产物。

tf.tensor()和dataSync();

因为我们的数据存储在标准JavaScript数组中,所以我们需要用tf.tensor()将它们转换为TensorFlow的张量格式。反之,如果要从张量转回数组,用dataSync()。

小结

如果你下载了repo,而且准确无误地理解了上述内容,你会得到之前动图的演示结果,其中红色表示死亡,绿色表示幸存,亮绿色表示幸存几率更高。

本文探讨了一个完整的现代JavaScript项目,该项目使用TensorFlow.js可视化单层神经网络的演化预测,使用的数据集是泰坦尼克号,问题类型是二元分类。希望读者能根据这篇文章开始理解如何使用TensorFlow.js。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 谷歌
    +关注

    关注

    27

    文章

    6246

    浏览量

    110285
  • 神经网络
    +关注

    关注

    42

    文章

    4829

    浏览量

    106828
  • 数据集
    +关注

    关注

    4

    文章

    1232

    浏览量

    26055

原文标题:海难幸存者:基于项目的TensorFlow.js简介

文章出处:【微信号:jqr_AI,微信公众号:论智】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    谷歌发布基于机器学习框架TensorFlow模块 改善AI模型的隐私保护

    物联网和AI时代,数据成为重要的决策和生产工具,但是如何保护个人数据不被滥用,是许多机构和公民担心的问题。谷歌公司基于机器学习框架TensorFlow
    发表于 03-07 08:52 1603次阅读

    TF下载量已超4600万!首届TensorFlow World大会,谷歌大牛Jeff Dean激情演讲

    TensorFlow 2.0正式版发布不久,全球开发者和开源用户迎来了首届TensorFlow World大会。谷歌大牛Jeff Dean登
    的头像 发表于 10-31 09:47 6417次阅读

    关于 TensorFlow

    。学生、研究员、爱好、极客、工程师、开发者、发明家、创业者等等都可以Apache 2.0 开源协议下使用TensorflowTensorflo
    发表于 03-30 19:57

    谷歌深度学习插件tensorflow

    前段时间忙着研究Zedboard,这几天穿插着加入Python的深度学习的研究,最近使用谷歌tensorflow比较多,而且官方出了中文教程,比较给力,下面Windows10下安装一下
    发表于 07-04 13:46

    TensorFlow是什么

    Google Brain 团队为深度神经网络(DNN)开发的功能强大的开源软件库,于 2015 年 11 月首次发布 Apache 2.x 协议许可下可用。截至今天,短短的两年内,其 GitHub 库
    发表于 07-22 10:14

    TensorFlow的特点和基本的操作方式

    2015年11月GitHub上开源,2016年4月补充了分布式版本,最新版本为1.10,2018年下半年将发布
    发表于 11-23 09:56

    TensorFlow最新版本

    TensorFlow 版本 1.10.0 已经正式发布啦!
    的头像 发表于 08-11 08:24 5194次阅读

    TensorFlow的2.0 版本将来临

    TensorFlow 的 contrib 模块已经超越了单个存储库中可以维护和支持的模块。较大的项目最好分开维护,我们将在 TensorFlow 的主代码里添加一些规模较小的扩展。因此,作为发布
    的头像 发表于 08-15 09:01 5902次阅读

    TensorFlow2.0终于问世,Alpha版可以抢先体验

    之前开发者反馈,希望TensorFlow能够简化API、减少冗余并改进文档和示例。这次2.0发布,听取了开发者的建议,因此新版本有以下三大特
    的头像 发表于 03-08 09:30 4059次阅读
    <b class='flag-5'>TensorFlow</b>2.0终于问世,Alpha版可以抢先体验

    谷歌发布TensorFlow用于人工智能模型的隐私保护

    近日,谷歌发布了隐私保护TensorFlow工具包,可以评估各种机器学习分类器的隐私属性。谷歌表示,它旨在成为一个隐私测试套件的基础,不管AI开发者
    发表于 07-20 11:06 1075次阅读

    TensorFlow 2:专为性能和易用性而设计

    今年早些时候举行的 TensorFlow 开发者峰会上,我们着重介绍了 TensorFlow 2 将注重易用性和实际性能。为争取赢得基准测
    的头像 发表于 09-08 16:02 2081次阅读

    如何基于 ES6 的 JavaScript 进行 TensorFlow.js 的开发

    TensorFlow.js 是 TensorFlowJavaScript 版本,支持 GPU 硬件加速,可以运行在 Node.js 或浏览器环境中。它不但支持完全基于
    的头像 发表于 10-31 11:16 3823次阅读

    谷歌TensorFlow 2.4 Mac M1优化版发布

    谷歌表示,借助 TensorFlow 2,可在跨平台、设备和硬件上实现一流的训练性能,从而使开发者、工程师和研究人员能够在他们喜欢的平台上工作。IT之家获悉,现在,TensorFlow
    的头像 发表于 12-04 10:11 1821次阅读

    谷歌正式发布TensorFlow 图神经网络

    日前,我们很高兴发布TensorFlow 图神经网络 (Graph Neural Networks, GNNs),此库可以帮助开发者利用 TensorFlow 轻松处理图结构化数据
    的头像 发表于 01-05 13:44 1982次阅读

    TensorFlow的衰落与PyTorch的崛起

    采访开发者、硬件专家、云提供商以及熟悉谷歌机器学习工作的人士时,他们的观点也是相同的。TensorFlow 争夺
    的头像 发表于 11-04 14:23 2386次阅读