当前位置: 首页 > 科技观察

解决神经网络的新思路:OpenAI使用线性网络计算非线性问题

时间:2023-03-18 17:42:25 科技观察

我们展示了深度线性网络(使用浮点运算实现)实际上不是线性的,可以进行非线性计算。我们利用这一点来使用进化策略在线性网络中找到参数,使我们能够解决重要问题。神经网络通常堆叠有线性层和非线性函数,例如tanh和整流线性单元ReLU。如果没有非线性,理论上连续的线性层在数学上等同于单个线性层。因此,浮点运算是非线性的,足以训练深度网络。令人惊讶。背景计算机使用的数字不是精确的数学对象,而是使用有限位数的近似表示。计算机通常使用浮点数来表示数学对象。每个浮点数都由小数和指数组成。在IEEE的float32标准中,23位分配给小数,8位分配给指数,还有一位是表示正负的符号位。按照这个约定和二进制格式,二进制中最小的非零正常数是1.0..0x2^-126,以下简称为min。下一个可表示的数是1.0..01x2^-126,可以写成min+0.0..01x2^-126。很明显,***和第二个数的差距比0和min的差距小2^20倍。在float32标准中,当一个数字小于最小可表示数字时,该数字将被映射为零。因此,所有涉及接近零的浮点数的计算都是非线性的。(除了反常量,它们可能在某些计算硬件上不可用。在我们的例子中,这个问题是通过设置刷新为零(FTZ)来解决的,即将所有的反常量都视为零。)因此,虽然通常在这种情况下,所有数字与其浮点表示之间的差异很小,但在零附近出现较大差距,这种近似误差会产生很大影响。这可能会导致某些常见的数学规则不起作用的奇怪效果。例如,(a+b)xc不等于axc+bxc。例如,如果您设置a=0.4xmin,b=0.5xmin,c=1/min。那么:(a+b)xc=(0.4xmin+0.5xmin)x1/min=(0+0)x1/min=0。然而:(axc)+(bxc)=0.4xmin/min+0.5xminx1/min=0.9。再比如,我们可以设置a=2.5xmin,b=-1.6xmin,c=1xmin。那么:(a+b)+c=(0)+1xmin=min然而:(b+c)+a=(0xmin)+2.5xmin=2.5xmin。在如此小的规模下,基本的加法运算变得非线性!使用进化策略来利用非线性我们想知道这种固有的非线性是否可以用作计算非线性的方法,如果可以,深度线性网络是否能够执行非线性操作。挑战在于现代微分库忽略了小尺度的非线性。因此,很难或不可能使用反向传播训练具有非线性的神经网络。我们可以使用进化策略(ES)来评估梯度,而不依赖于符号微分。使用进化策略,我们可以利用float32的接近零的行为来计算非线性。当深度线性网络通过反向传播在MNIST数据集上进行训练时,可以达到94%的训练准确率和92%的测试准确率(机器之心使用三层全连接网络可以获得98.51%的测试准确率)。相比之下,采用进化策略训练的同一个线性网络可以达到大于99%的训练准确率和96.7%的测试准确率,确保激活值足够小,分布在float32的非线性区间内。训练性能的提高归功于float32表示中使用的非线性进化策略。这些强非线性允许任意层生成新特征,这些新特征是低层特征的非线性组合。下面是网络结构:x=tf.placeholder(dtype=tf.float32,shape=[batch_size,784])y=tf.placeholder(dtype=tf.float32,shape=[batch_size,10])w1=tf.Variable(np.random.normal(scale=np.sqrt(2./784),size=[784,512]).astype(np.float32))b1=tf.Variable(np.zeros(512,dtype=np.float32))w2=tf.Variable(np.random.normal(scale=np.sqrt(2./512),size=[512,512]).astype(np.float32))b2=tf.Variable(np.zeros(512,dtype=np.float32))w3=tf.Variable(np.random.normal(scale=np.sqrt(2./512),size=[512,10]).astype(np.float32))b3=tf.Variable(np.zeros(10,dtype=np.float32))params=[w1,b1,w2,b2,w3,b3]nr_params=sum([np.prod(p.get_shape().as_list())forpinparams])scaling=2**125defget_logits(par):h1=tf.nn.bias_add(tf.matmul(x,par[0]),par[1])/scalingh2=tf.nn.bias_add(tf.matmul(h1,par[2]),par[3]/scaling)o=tf.nn.bias_add(tf.matmul(h2,par[4]),par[5]/scaling)*scalingreturnoin在上面的代码中,我们可以看到网络一共有4层,第一层有784(28*28)个输入神经元。这个数字必须与MNIST数据集中单张图片包含的像素数相同。第二层和第三层都是隐藏层,每层有512个神经元,最后一层是10个分类类别的输出。每两层之间的全连接权重是服从正态分布的随机初始化值。nr_params是所有参数的累加乘积。get_logist()函数定义如下。这个函数的输入变量par应该是上面定义的nr_params,因为加入偏置项的索引定义为1,3,5,正好符合前面定义的nr_params,但是OpenAI没有给出调用过程的这个功能。该函数第一个表达式计算第一层和第二层之间前向传播的结果,即计算输入x和w1的乘积加上scaledbias项(前面的b1,b2,b3都是定义的作为零向量)。后面两步的计算基本类似,***返回的o应该是图像识别的类别。但是OpenAI只给出了网络架构,并没有给出优化方法和损失函数。