您的位置 首页 > 数码极客

【logspace】神经算术逻辑单元(NALU)简单指南:解释,直觉和代码

在这篇文章中,我解释了纳鲁、其结构、其组成部分和传统神经网络的含义。

这篇文章的主要目的是提供简单直观的NALU解释(包括概念和代码)。

神经网络在哪里失败?

神经网络,从理论上讲,都是很不错的函数逼近。他们几乎总能学习输入(数据或特征)和输出(标签或目标)之间的任何有意义的关系。因此,它们被用于各种各样的应用,从物体检测和分类到语音到文本转换,再到可以击败人类世界冠军球员的智能游戏代理。有许多有效的神经网络模型满足了诸如卷积神经网络(CNN),递归神经网络(RNN),自动编码器等应用的各种需求。深度学习和神经网络模型的进步本身就是另一个主题。

然而,根据论文作者的说法,它们缺乏非常基本的能力,这对人类甚至蜜蜂来说都是微不足道的!这是一种计算/操作数字的能力,也可以从可观察的数字模式推断出数字关系。结果表明,标准的神经网络甚至连学习一个恒等函数(输入和输出相同的函数;f(x) = x,这是最直接的数值关系。下面的图片显示了学习这种恒等函数的各种神经网络的均方误差(MSE)。

图像显示了标准神经网络的MSE,其具有在隐藏层中使用不同激活函数(非线性)训练的完全相同的体系结构

他们为什么失败?

NN无法学习这种数值表示的主要原因是在网络的隐层中使用了非线性激活函数。这些激活函数对于了解输入和标签之间的抽象非线性关系是至关重要的,但当涉及到将数字表示简化到超出训练数据中所看到的数字范围时,它们就会失败得很惨。因此,这样的网络对于记住在训练集中看到的数值模式是非常好的,但是不能很好地推断这种表示。

这就像是在不理解考试的基本概念的情况下记住答案或主题。这样做,如果在考试中提出类似的问题,则可以很好地执行,但是,如果要求的问题被设计为测试知识而不是记忆能力,则会失败。

该故障的严重程度直接对应于所选激活函数内的非线性程度。从上面的图像可以清楚地看出,诸如Tanh和Sigmoid之类的硬约束非线性函数比诸如PReLU和ELU的软约束非线性函数具有非常小的推广能力。

解决方案:Neural Accumulator(NAC)

Neural Accumulator(NAC)是NALU模型的基础。NAC是一种简单而有效的神经网络模型(unit),它支持学习加法和减法的能力,这是学习线性函数的理想属性。

NAC是一种特殊的线性层,其权重参数受限于只有1,0或-1的限制。通过以这种方式约束权重值,可以防止层改变输入数据的规模,并且它们在newtwork中保持一致,不管有多少层被堆叠在一起。因此,输出将是输入向量的线性组合,可以很容易地表示加减运算。

直觉:为了理解这个事实,让我们考虑下面的NN层的例子,它对输入执行线性算术运算。

图解说明没有偏差且权重值为-1,0或1的神经网络层可以学习线性外推。

如上面的NN层所示,网络可以通过将权重参数限制为-1,0和1来学习外推简单的算术函数,如加法和减法(y = x1 + x2和y = x1 - x2)。

注意:如上面的网络图所示,NAC不包含bias参数(b),并且没有应用于隐藏层单元输出的非线性。

由于标准神经网络很难学习NAC中权重参数的约束,因此作者描述了使用标准(无约束)参数W_hat和M_hat来学习这种受限参数值的非常有用的公式。这些参数类似于任何标准NN权重参数,可以随机初始化并且可以在训练过程中学习。根据W_hat和M_hat获得W的公式如下:

公式表示两个矩阵之间的元素乘积

使用上述公式来计算网络中的权重参数,保证这种参数的值将在范围[-1,1]与更倾向于朝-1,0和1。另外,这个方程是可微方程(其导数可以根据权重参数计算)。因此,它会更容易为NAC学习W¯¯使用梯度下降和反向传播。下面是NAC单元的架构图。

NAC架构学习简单(线性)数字函数

使用Tensorflow在python中实现NAC

可以想象,NAC是一个简单的NN模型,几乎没有什么调整。下面我展示了使用Tensorflow和Numpy库在python中简单实现单个NAC层。

import numpy as np

import tensorflow as tf

# Define a Neural Accumulator (NAC) for addition/subtraction -> Useful to learn the addition/subtraction operation

def nac_simple_single_layer(x_in, out_units):

'''

Attributes:

x_in -> Input tensor

out_units -> number of output units

Return:

y_out -> Output tensor of mentioned shape

W -> Weight matrix of the layer

'''

# Get the number of input features (numbers)

in_features = x_in.shape[1]

# define W_hat and M_hat

W_hat = (shape=[in_shape, out_units],

initializer= (minval=-2,maxval=2),

trainable=True, name="W_hat")

M_hat = (shape=[in_shape, out_units],

initializer= (minval=-2,maxval=2),

trainable=True, name="M_hat")

# Get W using the formula

W = (W_hat) * (M_hat)

y_out = (x_in, W)

return y_out,W

在上面的代码中,我使用了可训练参数W_hat和M_hat的随机统一初始化,但是可以对这些参数使用任何推荐的权重初始化技术。

超越加法和减法:NAC用于复杂的数字函数

尽管上述简单神经网络模型能够学习诸如加法和减法之类的基本算术函数,但是希望能够学习更复杂的算术运算,例如乘法,除法和幂函数。

下面是NAC的修改架构,它能够使用log space(对数值和指数)为其权重参数学习更复杂的数字函数。观察这个NAC与帖子中首先提到的NAC有何不同。

NAC架构学习更复杂的数字函数

如上图所示,该单元格在与权重矩阵W进行矩阵乘法之前将对数函数应用于输入数据,然后在结果矩阵上应用指数函数。获得输出的公式在下面的等式中给出。

上面显示的复数NAC的输出方程。这里的Epsilon是一个非常小的值,可以避免训练期间的log(0)情况

因此,就简单NAC和复杂NAC的基本机制而言,一切都是相同的,包括W_hat和M_hat的受限权重W的公式。唯一的区别是复杂的NAC在层的输入和输出上应用log space。

复杂NAC的Python实现:

与两个NAC的体系结构一样,复杂NAC的python实现几乎相同,只是输出张量公式中提到的变化。以下是此类NAC的代码。

# define a complex NAC in log space -> for more complex arithmetic functions such as multiplication, division and power

def nac_complex_single_layer(x_in, out_units, epsilon = 0.000001):

'''

:param x_in: input feature vector

:param out_units: number of output units of the cell

:param epsilon: small value to avoid log(0) in the output result

:return m: output tensor

:return W: associated weight matrix

'''

in_features = x_in.shape[1]

W_hat = (shape=[in_shape, out_units],

initializer= (minval=-2,maxval=2),

trainable=True, name="W_hat")

M_hat = (shape=[in_shape, out_units],

initializer= (minval=-2,maxval=2),

trainable=True, name="M_hat")

#Get Unrestricted parameter matrix W

W = (W_hat) * (M_hat)

# Express Input feature in log space to learn complex functions

x_modified = (x_in) + epsilon)

m = ( (x_modified, W) )

return m, W

总结:神经算术逻辑单元(NALU)

到目前为止可以想象,将两个NAC模型组合在一起可以学习几乎所有的算术运算。这是NALU背后的关键思想,它包括由学习的门信号控制的上述简单NAC和复杂NAC 的加权组合。因此,NAC构成了NALU的基本构建块。所以,如果你已经正确理解了NAC,NALU很容易掌握。如果还没有,请花点时间再次阅读NAC的两个解释。下图描述了NALU的架构。

NALU的注释图

如上图所示,在NALU中,两个NAC(紫色单元)由学习的S形门控(橙色单元)内插(组合),使得NAC的输出可以基于数值函数由门激活或去激活。正在努力训练网络。

如上所述,简单的NAC计算累加函数,因此它负责存储NALU的线性(加法和减法)运算。虽然复杂的NAC负责执行更复杂的数字函数,例如乘法,除法和幂函数。NALU中底层单元的输出可以用数学表示如下:

Simple NAC : a = W X

Complex NAC: m = exp ( W log (|X| + e) )

Where, W = tanh(W_hat) * sigmoid(M_hat)

Gate cell: g = sigmoid(GX) # Where G is standard trainable parameter matrix

# And finally the output of the NALU

NALU: y = g * a + (1-g) * m # Where * is the element wise product

在NALU的上述公式中,我们可以说如果门输出g = 0,那么网络将只学习复杂的函数而不是简单的函数。相反,如果g = 1,那么网络将只学习加法函数而不是复杂函数。因此,总的来说,NALU可以学习任何由乘法,加法,减法,除法和幂函数组成的数字函数,这样可以很好地推断出在训练期间看到的数字范围之外的数字。

NALU的Python实现:

在NALU的实现中,我们将使用前面代码片段中定义的简单和复杂NAC。

def nalu(x_in, out_units, epsilon=0.000001, get_weights=False):

'''

:param x_in: input feature vector

:param out_units: number of output units of the cell

:param epsilon: small value to avoid log(0) in the output result

:param get_weights: True if want to get the weights of the model

in return

:return: output tensor

:return: Gate weight matrix

:return: NAC1 (simple NAC) weight matrix

:return: NAC2 (complex NAC) weight matrix

'''

in_features = x_in.shape[1]

# Get the output tensor from simple NAC

a, W_simple = nac_simple_single_layer(x_in, out_units)

# Get the output tensor from complex NAC

m, W_complex = nac_complex_single_layer(x_in, out_units, epsilon= epsilon)

# Gate signal layer

G = (shape=[in_shape, out_units],

initializer= (stddev=1.0),

trainable=True, name="Gate_weights")

g = ( (x_in, G) )

y_out = g * a + (1 - g) * m

if(get_weights):

return y_out, G, W_simple, W_complex

else:

return y_out

同样,在上面的代码中,我对门参数G使用了随机正常初始化,但是可以使用任何推荐的权重初始化技术。

我相信NALU是人工智能的一个现代突破,特别是神经网络,似乎非常有前景。它们可以为许多应用打开大门,这些应用对于标准NN来说似乎很难处理。

Authors显示各种不同的实验结果中的纸从简单的算术函数的学习任务中提供一系列MNIST图像计数的手写数字位数神经网络应用的不同区域实施NALU使网络学习评估计算机程序!

结果令人惊讶,并证明NALU 在几乎所有涉及数字表示的任务中都优于标准NN模型。我建议读者了解这些实验及其结果,以深入了解NALU如何在一些有趣的数字任务中发挥作用。

但是,NAC或NALU不太可能成为完成每项任务的完美解决方案。相反,它们展示了用于创建旨在用于数值函数的目标类的模型的一般设计策略。

代码地址:

原始论文地址:

关于作者: admin

无忧经验小编鲁达,内容侵删请Email至wohenlihai#qq.com(#改为@)

热门推荐