如果说线性分类器使用直线作为分类的边界,那么神经网络则是在使用线性分类的基础上加了非线性的分类,也就是曲线。直接说就是,比如在svm上是权重w与输入x相乘之后就是计算损失函数(直接使用w权重矩阵对输入x进行分类,而神经网络是在使用w权重对输入x进行分类之前,先用激活函数计算输入x的值,),而神经网络里则不是,它是在权重矩阵w与输入x相乘之后,再将这个结果输入到一个名为激活函数里面,这个激活函数就好比生物神经元里面的激励函数,当输入信号达到一定阈值后触发信号输出。经过激活函数计算后再计算损失函数。

W权重矩阵,对一幅图像而言,可以说是这幅图像的特征表达,w权重的每行数据代表了一个图像特征,w权重的列数则表示该图像有多少个特征需要去分类。普通的线性分类器比如支持向量机SVM就是使用w特征矩阵与输入x矩阵相乘,然后根据损失函数对输入进行分类,这是直接使用特征矩阵对输入去分类。而神经网络则不同。首先需要明白一件事,就是w特征矩阵与输入x相乘的结果是表达了什么?w是这幅图像的特征矩阵,每一行表示了一个特征,有多少列就有多少个特征,那w与x矩阵乘法的结果是一个矩阵,这个矩阵的每一行数则表示这幅图像的某特征其突出的程度,也就是说某一行的结果越大则这一行所代表的图像特征在图像中占的比重就越大。而对于一些相似特征那么他们的结果也就越相近,这时再使用线性分类器则不好分别,那么就需要使用一些函数对这些特征进行抑制或者放大,突出我们想要的特征。这些函数就是神经网络里的激活函数。这些激活函数往往是在输入层后面,输出层前面,对于一个两层的神经网络来说就是,x->f(w1*x)->w2->loss,其输入层是x,输出层是w2->loss。中间隐含层是w1特征矩阵。
对一个两层神经网络的代码如下

import numpy as np
from numpy.random import randn
import matplotlib.pyplot as plt
# 定义输入和神经元大小,并初始化
N, D_in, H, D_out = 64,1000,100,10
x, y = randn(N,D_in), randn(N,D_out) # x(64,1000),y(64,10)
w1, w2 = randn(D_in, H), randn(H, D_out) # w1(1000,100),w2(100,10)
# 进行训练
lossK = []
for t in range(2000):
    # 前向传播
    h = 1 / (1 + np.exp(np.dot(-x,w1))) # 激活函数,h(64,100)
    y_pred = np.dot(h, w2) # y_pred(64,10)
    loss = np.square(y_pred - y).sum() 
    if(t%100==0):
        print(t, loss)
    lossK.append(loss)
    # 反向传播
    grad_y_pred = 2 * (y_pred - y) # (64,10)
    grad_w2 = np.dot(h.T, grad_y_pred) # (100,10)
    grad_h = np.dot(grad_y_pred,w2.T) # (64,100)
    grad_w1 = np.dot(x.T,grad_h * h * (np.ones(h.shape) - h)) # (1000,100)
    # 更新w
    w1 -= 1e-4 * grad_w1
    w2 -= 1e-4 * grad_w2
x = np.arange(2000)
y = lossK
plt.plot(x, y)
plt.show()

结果:

神经网络算权重 神经网络的权重矩阵_权重


可以看见损失函数是在逐渐减少的

神经网络算权重 神经网络的权重矩阵_权重_02


纵轴表示损失函数,横轴表示训练次数。

当然相比于规范的神经网络训练步骤,这段代码有几处不足。

(1)对于输入x没有做标准化处理,虽然这里的x和w均是随机生成的呈正态分布的数据。所谓标准化处理就是将输入数据处理呈均值为0,方差为1呈标准正态分布的数据。

(2)没有增加偏置项b,如果没有设置偏置项b,对于y=wx分类器一定会经过原点,影响分类效果,如果加了偏置项,b可以大于0可以等于0可以小于0,这样这个分类器就会更加好用。

常用的激活函数有Sigmoid, tanh, ReLU,Leaky-ReLU,ELU.

神经网络算权重 神经网络的权重矩阵_权重_03


缺点:

(1)饱和性会使得梯度消失,就是x过大或者过小时,梯度接近于0;

(2)函数输出永远在0-1之间,每个神经元的偏导同号,其梯度值更新的方向都是一样的,也就是梯度值会出现同时增加或者同时减小的现象,即容易出现锯齿现象;

(3)涉及指数运算,会占用较大的计算资源。

神经网络算权重 神经网络的权重矩阵_激活函数_04


双曲正切函数作为激活函数,会使得函数输出有正有负,范围在[-1,1],其梯度值的变化是可以有正有负的,不会出现锯齿现象,但是其饱和性的问题依然存在。

神经网络算权重 神经网络的权重矩阵_权重_05

ReLU函数可以理解为整流函数,只对输入大于0的项做出反应,小于0的项则全部置零。这样会使得一些神经元出现死亡的现象,也就是梯度不会发生更新,对外界输入没有反映,往往加一些偏置项(常取0.01)可以缓解这种情况。总体而言,ReLU激活函数其梯度收敛速度远远大于Sigmoid和双曲正切函数,而且计算简单不会出现饱和现象,因此ReLU激活函数用的更多。

4.Leaky ReLU:f(x)=max(0.01x,x)

Leaky ReLU函数是为了解决死亡神经元问题而设计的,继承了ReLU函数的优点。

5.Maxout ELU:f(x)=max(w1x+b1,w2x+b2)

对输出使用神经元再进行选择一次,继承了ReLU和leaky ReLU的优点,但是参数却增加了一倍。

面对这几个激活函数,斯坦福课程给出的推荐是:

(1)不要轻易使用Sigmoid函数;

(2)可以使用ReLU函数,但是要注意学习率不能太大;

(3)可以使用tanh,但是效果不如leaky ReLU或者maxout

(4)可以使用leaky ReLU或者Maxout eLU。

总结自:斯坦福cs231n课程和B站up主同济子豪兄
推荐一个不错的B站up主添加链接描述