• 前言
  • Java代码中如何更改激活函数
  1. 更改前向传播forward()中卷积层激活函数。
  2. 更改输出层梯度计算公式
  3. 反向传播求激活函数微分
  • 激活函数与标签值的修改

 

 

一、前言:

 

本文探讨在卷积神经网络结构中,如何去处理激活函数的问题。

1、如何在前向传播的时候更改卷积层的激活函数。

2、对输出层损失函数梯度求解时,因输出层激活函数选择不同,梯度会产生变化,并如何正确修改。

3、对于反向传播的时候,根据激活函数的不同,对应反向传播的梯度公式会发生变化。

 

 

cnn的激活函数意义 cnn的激活函数在哪使用_Java

图片 1

 

java代码为例,一个神经网络 包含一个输入层、两个卷积层,两个池化层、一个全连接层。

LayerBuilder builder = new LayerBuilder();
builder.addLayer(Layer.buildInputLayer(new Size(28,28)));
builder.addLayer(Layer.buildConvLayer(6, new Size(5, 5)));
builder.addLayer(Layer.buildSampLayer(new Size(2, 2)));
builder.addLayer(Layer.buildConvLayer(12, new Size(5, 5)));
builder.addLayer(Layer.buildSampLayer(new Size(2, 2)));
builder.addLayer(Layer.buildOutputLayer(10));//输出层;
CNN cnn = new CNN(builder, 10);
 
Learningrate = 0.85, batchSize = 10。采用mnist数据集测试

 

首先对两个卷积层设置激活函数为sigmoid激活函数     

// 设置激活函数

layer.setActivation(new Sigmoid());

再设置输出层激活函数为tanh激活函数

// 设置激活函数

layer.setActivation(new Tanh());

 

这里注意最后一层tanh激活函数取值范围为 -1~1;(而我们之前用的是sigmoid,取值范围为0~1)

 

 

 

 

 

 

 

 

二、Java代码中如何更改激活函数

 

1、更改前向传播forward()中卷积层激活函数。

 

首先是输出层第L层。注意到输出层的W,b满足下式:

 

aL = σ(zL) = σ(WLaL-1 + bL)

 

注:σ表示当前层激活函数、W为权值、b为偏置。

 

``Java
final double bias = layer.getBias(j);
sum = Util.matrixOp(sum, new Operator() {
  private static final long serialVersionUID = 2469461972825890810L;
                  
@Override
  public double process(double value) {
      return layer.getActivation().active(value + bias);
  }
                  
});
``

这里卷积层我们采用了sigmoid激活函数,这里激活公式为:

 

  1. / (1 + Math.pow(Math.E, -x))

 

 

2、更改输出层梯度计算公式

 

这里我们采用的是均方差计算公式。

 

Lost = ||a-y||2/2;

 

a = σ(z);

 

这里均方差代价函数求导得到

 

F‘(x) = (a-y)σ’(z);

 

根据求导结果,我们只要知道激活函数的导数,我们就能求出输出层的梯度了。

而这里的梯度是我预先设定好的。

 

``Java

double gradient = outputLayer.getActivation().gradient(outmaps[m]);
            
outputLayer.setError(m, 0, 0, gradient*(target[m] - outmaps[m])); //sigmoid
 
``

 

 

3、反向传播求激活函数微分

 

只是更改前向传播是不够的。反向传播求梯度时,会因激活函数选择不同,梯度公式也会产生变化。

   

    Output = f……(g(z));

 

 

前向传播通过复杂的函数映射计算出最后的output,而我们采用梯度下降法,去寻找合适的那个映射,所以我们根据这个复杂的映射求微分。

 

Gradient = F’g’(z);

 

而这里采用最大值池化以及sigmoid激活函数;

所以求导结果应该是

 

Gradient = σ‘(x)*Max’∑1nai
 
也就是激活函数的与最大池化导数Hadamard乘积。
 
``Java
outMatrix = Util.matrixOp(map, new Operator() {
                        
    private static final long serialVersionUID = 1L;
 
@Override
    public double process(double value) {
        return layer.getActivation().gradient(value);
    }
                        
});

//这里的输出结果应该除以scale(卷积核面积)

outMatrix = Util.matrixOp(outMatrix,
    Util.kronecker(nextError, scale, sampPos), null, null, Util.multiply);
``

 

 

  • 激活函数与标签值的修改

 

这里最后一层选取激活函数的时候需要注意一个点。

因为sigmoid取值范围为0~1,我们标签值也是1.所以能契合sigmoid函数。

但是当我们改为tanh激活函数的时候,tanh取值范围为-1~1.所以为了契合标签值,我将tanh函数,以及它的梯度做了个变化。 à 0.5x + 0.5;梯度变为原先的1/2,然后发现也是能正确运行的。

 

待解决:

Q:如果我不对激活函数但是我更改标签值的时候发现,我将标签改为2.然后我发现无法得到正确结果。