人工神经网络ANN的算法总结
用笔记,记录自己的点滴进步;用行动,驱赶心中的彷徨
——杰
前言
人工神经网络(Artificial Neural Network,ANN),也简称神经网络,是众多机器学 习算法中比较接近生物神经网络特性的数学模型。人工神经网络通过模拟生物神经网络 (大脑)的结构和功能,由大量的节点(或称“神经元”,或“单元”)和之间相互联接构 成,可以用来对数据之间的复杂关系进行建模。
深度学习(deep neural network)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。
--wiki
神经网络:一种可以通过观测数据使计算机学习的仿生语言范例
深度学习:一组强大的神经网络学习技术
最初的最简单的神经网络是神经元(感知机),之后由寒冬开始复苏,出现了卷积神经网络CNN,图神经网络RNN,反向传播算法BP。
大多数学习过机器学习的人,特别是初学者来说,很难理解神经元和感知机的关系。这里我做一个简单的解释。
|
|
|
上图神经元和感知机的原理大概。我们可以看到单个神经元在树突上收集其他神经元传递过来的信息,在信息量到达一个阈值之后,便会产生一个脉冲信号,经过轴突传送到突触,进而传递给下一个神经元。感知机正是模仿这一神经元的运行过程进行的设计。最初的感知机模型也是一种二元表示法,也就是要么有信号产生,要么没有信号产生。
我们把感知机的模型进行分解,可以分为:输入权值、**函数、输出。
-
输入权值:每个输入都有一个权值,另外还有一个W0表示偏置,偏置的作用是让后面的阶跃函数位于原点。
-
**函数:这里采用阶跃函数作为**函数,实际应用的还有很多**函数,诸如Sigmoid函数,Relu等等。
-
输出:该感知器的输出由下面这个公式来计算
关于**函数和神经元的描述,有兴趣的可以继续了解,这里便不做详细的解析。总之,感知机的缺陷,就在于仅适用于线性条件,并且对于大规模的数据集,显得极为吃力,准确率不足。
这里我重点介绍CNN,卷积神经网络算法
卷积神经网络
卷积神经网络(Convolutional Neural Networks, CNN)是一类包含卷积计算且具有深度结构的前馈神经网络(Feedforward Neural Networks),是深度学习(deep learning)的代表算法之一。卷积神经网络具有表征学习(representation learning)能力,能够按其阶层结构对输入信息进行平移不变分类(shift-invariant classification),因此也被称为“平移不变人工神经网络(Shift-Invariant Artificial Neural Networks, SIANN)”
——来自比较多的网络说法
卷积神经网络(Convolutional Neural Networks / CNNs / ConvNets)与普通神经网络非常相似,它们都由具有可学习的权重和偏置常量(biases)的神经元组成。每个神经元都接收一些输入,并做一些点积计算,输出是每个分类的分数,普通神经网络里的一些计算技巧到这里依旧适用。
所以哪里不同呢?卷积神经网络默认输入是图像,可以让我们把特定的性质编码入网络结构,使是我们的前馈函数更加有效率,并减少了大量参数。
多个神经元组织在一起,就是神经网络。
上图中最左边的原始输入信息称之为输入层,最右边的神经元称之为输出层(上图中输出层只有一个神经元),中间的叫隐藏层。
啥叫输入层、输出层、隐藏层呢?
输入层(Input layer),众多神经元(Neuron)接受大量非线形输入讯息。输入的讯息称为输入向量。
输出层(Output layer),讯息在神经元链接中传输、分析、权衡,形成输出结果。输出的讯息称为输出向量。
隐藏层(Hidden layer),简称“隐层”,是输入层和输出层之间众多神经元和链接组成的各个层面。如果有多个隐藏层,则意味着多个**函数。
它们如何计算和联系起来的呢?举个小列子:
此外,上文中讲的都是一层隐藏层,但实际中也有多层隐藏层的,即输入层和输出层中间夹着数层隐藏层,层和层之间是全连接的结构,同一层的神经元之间没有连接。
关于隐藏层的密码,是整个算法区别其他算法的关键。
相关名词解释
卷积神经网络通常包含以下几种层:
- 卷积层(Convolutional layer),卷积神经网路中每层卷积层由若干卷积单元组成,每个卷积单元的参数都是通过反向传播算法优化得到的。卷积运算的目的是提取输入的不同特征,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网络能从低级特征中迭代提取更复杂的特征。
- 线性整流层(Rectified Linear Units layer, ReLU layer),这一层神经的活性化函数(Activation function)使用线性整流(Rectified Linear Units, ReLU)f(x)=max(0,x)。也有地方成为这是激励层
- 池化层(Pooling layer),通常在卷积层之后会得到维度很大的特征,将特征切成几个区域,取其最大值或平均值,得到新的、维度较小的特征。
- 全连接层( Fully-Connected layer), 把所有局部特征结合变成全局特征,用来计算最后每一类的得分。
最左边是数据输入层,对数据做一些处理,比如去均值(把输入数据各个维度都中心化为0,避免数据过多偏差,影响训练效果)、归一化(把所有的数据都归一到同样的范围)、PCA/白化等等。CNN只对训练集做“去均值”这一步。
中间是
CONV:卷积计算层,线性乘积 求和。
RELU:激励层,上文2.2节中有提到:ReLU是**函数的一种。
POOL:池化层,简言之,即取区域平均或最大。
最右边是
FC:全连接层
卷积计算层是CNN的核心
卷积层
最初的CNN,它的优势就在于对图像的处理,详细的卷积层操作,可以参照这里。(对于这里,我存在盗用的嫌疑)。卷积层的操作对象,主要可以分为对静态图片和动态图像的处理。它们的共同特征就在,对原图像进行特征的提取处理,也就是我们常说的卷积。
非严格意义上来讲,下图中红框框起来的部分便可以理解为一个滤波器,即带着一组固定权重的神经元。多个滤波器叠加便成了卷积层。
对图像(不同的数据窗口数据)和滤波矩阵(一组固定的权重:因为每个神经元的多个权重固定,所以又可以看做一个恒定的滤波器filter)做内积(逐个元素相乘再求和)的操作就是所谓的『卷积』。
如下图,中间的部分就是我们的滤波器filter,左边是输入的二维表,右边是输出的二维表。
中间滤波器filter与数据窗口做内积,其具体计算过程则是:40 + 00 + 00 + 00 + 01 + 01 + 00 + 01 + -4*2 = -8
对于动图,需要考虑的参数也会更多,比如:深度、步长、填充字。
后记:
普通神经网络把输入层和隐含层进行“全连接(Full Connected)“的设计。但是对于复杂的神经网络,则我们需要消耗更多的性能来提取特征,故而提出了局部感知的概念,对隐含单元和输入单元间的连接加以限制:每个隐含单元仅仅只能连接输入单元的一部分。每个隐含单元连接的输入区域大小叫r神经元的感受野(receptive field)。
这里请参考:详解卷积神经网络(CNN)
激励层
常用的激励函数,有sigmoid,Tanh,ReLU,Leaky ReLU,Maxout。
sigmoid函数,功能是把一个实数压缩至0到1之间。输入的数字非常大的时候,结果会接近1,而非常大的负数作为输入,则会得到接近0的结果。数学形式很简单,是
def sigmoid(x):
return 1. / (1 + np.exp(-x))
def plot_sigmoid():
x = np.arange(-10, 10, 0.1)
y = sigmoid(x)
fig = plt.figure()
# ax = fig.add_subplot(111)
ax = axisartist.Subplot(fig, 111)
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# ax.spines['bottom'].set_color('none')
# ax.spines['left'].set_color('none')
ax.axis['bottom'].set_axisline_style("-|>", size=1.5)
ax.spines['left'].set_position(('data', 0))
ax.plot(x, y)
plt.xlim([-10.05, 10.05])
plt.ylim([-0.02, 1.02])
plt.tight_layout()
plt.savefig("sigmoid.png")
plt.show()
图像是:
缺点:
- sigmoid函数在实际梯度下降中,容易饱和和终止梯度传递。
- sigmoid函数的输出没有0中心化,这是一个比较闹心的事情,因为每一层的输出都要作为下一层的输入,而未0中心化会直接影响梯度下降,
Tanh函数,它会将输入值压缩至-1到1之间,当然,它同样也有sigmoid函数里说到的第一个缺点,在很大或者很小的输入值下,神经元很容易饱和。但是它缓解了第二个缺点,它的输出是0中心化的。如下图像。
代码实现:
def tanh(x):
return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))
def plot_tanh():
x = np.arange(-10, 10, 0.1)
y = tanh(x)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# ax.spines['bottom'].set_color('none')
# ax.spines['left'].set_color('none')
ax.spines['left'].set_position(('data', 0))
ax.spines['bottom'].set_position(('data', 0))
ax.plot(x, y)
plt.xlim([-10.05, 10.05])
plt.ylim([-1.02, 1.02])
ax.set_yticks([-1.0, -0.5, 0.5, 1.0])
ax.set_xticks([-10, -5, 5, 10])
plt.tight_layout()
plt.savefig("tanh.png")
plt.show()
ReLU函数,ReLU是修正线性单元(The Rectified Linear Unit)的简称。它对于输入x计算f(x)=max(0,x)。换言之,以0为分界线,左侧都为0,右侧是y=x这条直线。
代码实现:
def relu(x):
return np.where(x < 0, 0, x)
def plot_relu():
x = np.arange(-10, 10, 0.1)
y = relu(x)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# ax.spines['bottom'].set_color('none')
# ax.spines['left'].set_color('none')
ax.spines['left'].set_position(('data', 0))
ax.plot(x, y)
plt.xlim([-10.05, 10.05])
plt.ylim([0, 10.02])
ax.set_yticks([2, 4, 6, 8, 10])
plt.tight_layout()
plt.savefig("relu.png")
plt.show()
优点:实验表明,它的使用,相对于sigmoid和tanh,可以非常大程度地提升随机梯度下降的收敛速度。此外求梯度,变得更加简单。
缺点:ReLU单元也有它的缺点,在训练过程中,它其实挺脆弱的,有时候甚至会挂掉。举个例子说吧,如果一个很大的梯度流经ReLU单元,那权重的更新结果可能是,在此之后任何的数据点都没有办法再**它了。一旦这种情况发生,那本应经这个ReLU回传的梯度,将永远变为0。
Leaky ReLU函数,它是相对与ReLU函数的缺点而言的,有所改进。这里他讲下x<0的情况,变成发f(x)=ax,a为一个无限小的数。
代码实现如下:
def prelu(x):
return np.where(x < 0, 0.5 * x, x)
def plot_prelu():
x = np.arange(-10, 10, 0.1)
y = prelu(x)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# ax.spines['bottom'].set_color('none')
# ax.spines['left'].set_color('none')
ax.spines['left'].set_position(('data', 0))
ax.spines['bottom'].set_position(('data', 0))
ax.plot(x, y)
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.savefig("prelu.png")
plt.show()
池化层
池化(pool)即下采样(downsamples).
池化层进行的运算一般有以下几种:
- 最大池化(Max Pooling)。取4个点的最大值。这是最常用的池化方法。
- 均值池化(Mean Pooling)。取4个点的均值。
- 高斯池化。借鉴高斯模糊的方法。不常用。
- 可训练池化。训练函数 ff ,接受4个点为输入,出入1个点。不常用。
如果池化层的输入单元大小不是二的整数倍,一般采取边缘补零(zero-padding)的方式补成2的倍数,然后再池化。
全连接层
全连接层和卷积层可以相互转换:
- 对于任意一个卷积层,要把它变成全连接层只需要把权重变成一个巨大的矩阵,其中大部分都是0 除了一些特定区块(因为局部感知),而且好多区块的权值还相同(由于权重共享)。
- 相反地,对于任何一个全连接层也可以变为卷积层。比如,一个K=4096 的全连接层,输入层大小为 7∗7∗512,它可以等效为一个 F=7, P=0, S=1, K=4096 的卷积层。换言之,我们把 filter size 正好设置为整个输入层大小。
补充
通常情况下,我们工程中发现,3层神经网络效果优于2层神经网络,但是如果把层数再不断增加(4,5,6层),对最后结果的帮助就没有那么大的跳变了。不过在卷积神经网上还是不一样的,深层的网络结构对于它的准确率有很大的帮助,直观理解的方式是,图像是一种深层的结构化数据,因此深层的卷积神经网络能够更准确地把这些层级信息表达出来。
当我们加大层数以及每一层的神经元个数的时候,我们的神经网络容量变大了。更通俗一点说,神经网络的空间表达能力变得更丰富了。这就会产生过拟合。同样的,永远不要用减少层数和神经元的方法来缓解过拟合!!!这会极大影响神经网络的表达能力!!!我们有其他的方法,比如说之前一直提到的正则化来缓解这个问题。
参考资料与原文
下一篇: 熏腊肉用什么熏,来做一份传统熏腊肉吧