js空格占位符_在浏览器中进行深度学习:TensorFlow.js (七)递归神经网络

上一篇我们讨论了CNN,卷积神经网络。CNN广泛应用于图像相关的深度学习场景中。然而CNN也有一些限制:

  • 很难应用于序列数据
  • 输入数据和输出数据都是固定长度
  • 不理解上下文

这些问题就可以由RNN来处理了。

神经网络除了CNN之外的另一个常见的类别是RNN,递归/循环神经网络。这里的R其实是两种神经网络,Recurrent:时间递归 , Recusive:结构递归。时间递归神经网络的神经元间连接构成有向图,而结构递归神经网络利用相似的神经网络结构递归构造更为复杂的深度网络。我们大部分时间讲的RNN指的是前一种,时间递归神经网络。

6200b3eb241e813222065797812240e2.png

RNN的结构如上图所示,为了解决上下文的问题,RNN网路中,输入Xt,输出ht,而且输出ht回反馈回处理单元A。上图右边是随时间展开的序列图。tn时间的输出hn反馈成为tn+1时间的输入,hn和Xn+1一起成为tn+1时间的输入。这样也就保留了上下文对模型的影响,以更好的针对时间序列建模。

如下图所示,RNN可以支持不同的输入输出序列。

f819efc128a711c21f808674ae19842b.png

RNN有一些变体,常见的是LSTM和GRU

LSTM即Long Short Memory Network,长短时记忆网络。它其实是属于RNN的一种变种,可以说它是为了克服RNN无法很好处理远距离依赖而提出的。

GRU即Gated Recurrent Unit,是LSTM的一个变体。GRU保持了LSTM的效果同时又使结构更加简单,所以它也非常流行。

a69d9641b4d504ac68c20fc35f6a2cfe.png

RNN可以有效的应用在以下的领域中:

  • 音乐作曲
  • 图像捕捉
  • 语音识别
  • 时序异常处理
  • 股价预测
  • 文本翻译

例子:用RNN实现加法运算

我们这里介绍一个利用RNN来实现加法运算的例子,源代码在这里,或者去我的Codepen运行我的例子。这个例子最早源自keras。

科学世界的论证(reasoning)方式有两种,演绎(deduction)和归纳(induction)。

所谓的演绎就是根据已有的理论,通过逻辑推导,得出结论。经典的就是欧几里得的几何原理,利用基本的公设和公理演绎出了整个欧氏几何的大厦。而机器学习则是典型的归纳法,数据先行,现有观测数据,然后利用数学建模,找到最能够解释当前观察数据的公式。这就像是理论物理学家和实验物理学家,理论物理学家利用演绎,根据理论推出万物运行的道理,实验物理学家通过实验数据,反推理论,证实或者否定理论。当然两种方法是相辅相成的,都是科学的利器。

好了我们回到加法的例子,这里我们要用机器学习的方法来教会计算机加法,记得用归纳而不是演绎。因为计算机是很擅长演绎的,加法的演绎是所有计算的基础之一,定义0,1,2=1+1,然后演绎出所有的加法。这里用归纳,然计算机算法通过已有的加法例子数据找到如何计算加法。这样做当然不是最有效的,但是很有趣。

我们来看例子吧。

首先是一个需要一个字符表的类来管理字符到张量的映射:

class CharacterTable { /** * Constructor of CharacterTable. * @param chars A string that contains the characters that can appear * in the input. */ constructor(chars) { this.chars = chars; this.charIndices = {}; this.indicesChar = {}; this.size = this.chars.length; for (let i = 0; i < this.size; ++i) { const char = this.chars[i]; if (this.charIndices[char] != null) { throw new Error(`Duplicate character '${char}'`); } this.charIndices[this.chars[i]] = i; this.indicesChar[i] = this.chars[i]; } } /** * Convert a string into a one-hot encoded tensor. * * @param str The input string. * @param numRows Number of rows of the output tensor. * @returns The one-hot encoded 2D tensor. * @throws If `str` contains any characters outside the `CharacterTable`'s * vocabulary. */ encode(str, numRows) { const buf = tf.buffer([numRows, this.size]); for (let i = 0; i < str.length; ++i) { const char = str[i]; if (this.charIndices[char] == null) { throw new Error(`Unknown character: '${char}'`); } buf.set(1, i, this.charIndices[char]); } return buf.toTensor().as2D(numRows, this.size); } encodeBatch(strings, numRows) { const numExamples = strings.length; const buf = tf.buffer([numExamples, numRows, this.size]); for (let n = 0; n < numExamples; ++n) { const str = strings[n]; for (let i = 0; i < str.length; ++i) { const char = str[i]; if (this.charIndices[char] == null) { throw new Error(`Unknown character: '${char}'`); } buf.set(1, n, i, this.charIndices[char]); } } return buf.toTensor().as3D(numExamples, numRows, this.size); } /** * Convert a 2D tensor into a string with the CharacterTable's vocabulary. * * @param x Input 2D tensor. * @param calcArgmax Whether to perform `argMax` operation on `x` before * indexing into the `CharacterTable`'s vocabulary. * @returns The decoded string. */ decode(x, calcArgmax = true) { return tf.tidy(() => { if (calcArgmax) { x = x.argMax(1); } const xData = x.dataSync(); // TODO(cais): Performance implication? let output = ""; for (const index of Array.from(xData)) { output += this.indicesChar[index]; } return output; }); }}

这个类存储了加法运算所能用到的所有字符,“0123456789+ ”,其中空格是占位符,两位数的2会变成“ 2”。

为了实现字符到索引的双向映射, 这个类保存了两个表,charIndices是字符到索引,indicesChar是索引到字符。

encode方法把一个加法字符串映射为一个one hot的tensor:

this.charTable.encode("1+2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值