-
2020-06-27 21:08:21
BP神经网络原理
经典的BP神经网络通常由三层组成: 输入层, 隐含层与输出层.通常输入层神经元的个数与特征数相关,输出层的个数与类别数相同, 隐含层的层数与神经元数均可以自定义.
每个神经元代表对数据的一次处理:
每个隐含层和输出层神经元输出与输入的函数关系为:其中Wij表示神经元i与神经元j之间连接的权重,Oj代表神经元j的输出, sigmod是一个特殊的函数用于将任意实数映射到(0,1)区间.
上文中的sigmod函数称为神经元的激励函数(activation function), 除了sigmod函数1/1+e^-IL外, 常用还有tanh和ReLU函数.
我们用一个完成训练的神经网络处理回归问题, 每个样本拥有n个输入.相应地,神经网络拥有n个输入神经元和1个输出神经元.
实际应用中我们通常在输入层额外增加一个偏置神经元, 提供一个可控的输入修正;或者为每个隐含层神经元设置一个偏置参数.
我们将n个特征依次送入输入神经元, 隐含层神经元获得输入层的输出并计算自己输出值, 输出层的神经元根据隐含层输出计算出回归值.
上述过程一般称为前馈(Feed-Forward)过程, 该过程中神经网络的输入输出与多维函数无异.
现在我们的问题是如何训练这个神经网络.
作为监督学习算法,BP神经网络的训练过程即是根据前馈得到的预测值和参考值比较, 根据误差调整连接权重Wij的过程.
训练过程称为反向传播过程(BackPropagation), 数据流正好与前馈过程相反.
首先我们随机初始化连接权重Wij, 对某一训练样本进行一次前馈过程得到各神经元的输出.
首先计算输出层的误差:
Ej=sigmod′(Oj)∗(Tj−Oj)=Oj(1−Oj)(Tj−Oj)
其中Ej代表神经元j的误差,Oj表示神经元j的输出, Tj表示当前训练样本的参考输出, sigmod′(x)是上文sigmod函数的一阶导数.
计算隐含层误差:Ej=sigmod′(Oj)∗∑kEkWjk=Oj(1−Oj)∑kEkWjk
隐含层输出不存在参考值, 使用下一层误差的加权和代替(Tj−Oj).
计算完误差后就可以更新Wij和θj:
Wij=Wij+λEjOi
其中λ是一个称为学习率的参数,一般在(0,0.1)区间上取值.
实际上为了加快学习的效率我们引入称为矫正矩阵的机制, 矫正矩阵记录上一次反向传播过程中的EjOi值, 这样Wj更新公式变为:
Wij=Wij+λEjOi+μCij
μ是一个称为矫正率的参数.随后更新矫正矩阵:
Cij=EjOi
每一个训练样本都会更新一次整个网络的参数.我们需要额外设置训练终止的条件.
最简单的训练终止条件为设置最大迭代次数, 如将数据集迭代1000次后终止训练.
单纯的设置最大迭代次数不能保证训练结果的精确度, 更好的办法是使用损失函数(loss function)作为终止训练的依据.
损失函数可以选用输出层各节点的方差:
L=∑j(Tj−Oj)2
为了避免神经网络进行无意义的迭代, 我们通常在训练数据集中抽出一部分用作校验.当预测误差高于阈值时提前终止训练.
Python实现BP神经网络
首先实现几个工具函数:
def rand(a, b): return (b - a) * random.random() + a def make_matrix(m, n, fill=0.0): # 创造一个指定大小的矩阵 mat = [] for i in range(m): mat.append([fill] * n) return mat
定义sigmod函数和它的导数:
def sigmoid(x): return 1.0 / (1.0 + math.exp(-x)) def sigmod_derivate(x): return x * (1 - x)
定义BPNeuralNetwork类, 使用三个列表维护输入层,隐含层和输出层神经元, 列表中的元素代表对应神经元当前的输出值.使用两个二维列表以邻接矩阵的形式维护输入层与隐含层, 隐含层与输出层之间的连接权值, 通过同样的形式保存矫正矩阵.
定义setup方法初始化神经网络:
def setup(self, ni, nh, no): self.input_n = ni + 1 # 因为需要多加一个偏置神经元,提供一个可控的输入修正 self.hidden_n = nh self.output_n = no # 初始化神经元 self.input_cells = self.input_n * [1.0] self.hidden_cells = self.hidden_n * [1.0] self.output_cells = self.output_n * [1.0] # 初始化权重矩阵 self.input_weights = make_matrix(self.input_n, self.hidden_n) self.output_weights = make_matrix(self.hidden_n, self.output_n) # 权重矩阵随机激活 for i in range(self.input_n): for h in range(self.hidden_n): self.input_weights[i][h] = rand(-0.2, 0.2) for h in range(self.hidden_n): for o in range(self.output_n): self.output_weights[h][o] = rand(-0.2, 0.2) # 初始化矫正矩阵 self.input_correction = make_matrix(self.input_n, self.hidden_n) self.output_correction = make_matrix(self.hidden_n, self.output_n)
定义predict方法进行一次前馈, 并返回输出:
def predict(self, inputs): # 激活输入层 for i in range(self.input_n - 1): self.input_cells[i] = inputs[i] # 激活隐藏层 for j in range(self.hidden_n): total = 0.0 for i in range(self.input_n): total += self.input_cells[i] * self.input_weights[i][j] self.hidden_cells[j] = sigmoid(total) for k in range(self.output_n): total = 0.0 for j in range(self.hidden_n): total += self.hidden_cells[j] * self.output_weights[j][k] self.output_cells[k] = sigmoid(total) return self.output_cells[:]
定义back_propagate方法定义一次反向传播和更新权值的过程, 并返回最终预测误差:
def back_propagate(self, case, label, learn, correct): # 前馈 self.predict(case) # 获取输出层误差 output_deltas = [0.0] * self.output_n for o in range(self.output_n): error = label[o] - self.output_cells[o] output_deltas[o] = sigmod_derivate(self.output_cells[o]) * error # 获取隐藏层误差 hidden_deltas = [0.0] * self.hidden_n for h in range(self.hidden_n): error = 0.0 for o in range(self.output_n): error += output_deltas[o] * self.output_weights[h][o] hidden_deltas[h] = sigmod_derivate(self.hidden_cells[h]) * error # 更新输出权重 for h in range(self.hidden_n): for o in range(self.output_n): # Wij=Wij+λEjOi+μCij change = output_deltas[o] * self.hidden_cells[h] self.output_weights[h][o] += learn * change + correct * self.output_correction[h][o] # 更新输入权重 for i in range(self.input_n): for h in range(self.hidden_n): # Wij=Wij+λEjOi+μCij change = hidden_deltas[h] * self.input_cells[i] self.input_weights[i][h] += learn * change + correct * self.input_correction[i][h] self.input_correction[i][h] = change # 获取全局误差 error = 0.0 for o in range(len(label)): error += 0.5 * (label[o] - self.output_cells[o]) ** 2 return error
定义train方法控制迭代, 该方法可以修改最大迭代次数, 学习率λ, 矫正率μ三个参数.
def train(self, cases, labels, limit=10000, learn=0.05, correct=0.1): for i in range(limit): error = 0.0 for i in range(len(cases)): label = labels[i] case = cases[i] error += self.back_propagate(case, label, learn, correct)
编写test方法,演示如何使用神经网络学习异或逻辑:
def test(self): cases = [ [0, 0], [0, 1], [1, 0], [1, 1], ] labels = [[0], [1], [1], [0]] self.setup(2, 5, 1) # 设置各层的神经元数量 self.train(cases, labels, 10000, 0.5, 0.1) for case in cases: print(self.predict(case))
运行结果:
总结
BP神经网络的理解主要难点在于各层误差和权重的更新上面,涉及到一系列数学公式,只要把数学公式弄懂就会理解代码为什么这样做.
更多相关内容 -
神经网络原理
2018-12-04 21:59:02神经网络原理_Simon.Haykin_编——神经网络书籍中最经典的一本 -
[M] 人工神经网络原理及应用.pdf
2019-06-19 10:20:34人工神经网络原理及应用(高清带目录).pdf 朱大奇 史慧 编著,一共10章,198页。 《人工神经网络原理及应用》由朱大奇、史慧编著,科学出版社出版。该书是现代计算机科学技术精品教材之一,介绍了人工神经网络的... -
MATLAB神经网络原理与实例精解pdf
2019-01-03 14:37:57MATLAB神经网络原理与实例精解,含有深度学习中的所有模型及文档及程序说明,深度学习入门必备! -
MATLAB神经网络原理与实例精解源代码文件.zip
2019-07-21 20:36:32关于MATLAB神经网络原理与实例精解的源代码文件,有想要学习的可以下载看看 -
神经网络原理(S.Haykin).rar
2019-07-22 04:30:47神经网络原理(S.Haykin).rar -
神经网络原理+Simon.Haykin
2018-07-19 12:45:42神经网络原理+Simon.Haykin——神经网络书籍中最经典的一本 -
卷积神经网络原理与视觉实践
2021-08-31 15:04:36卷积神经网络原理与视觉实践 -
【深度学习】卷积神经网络原理 深度学习原理.pdf
2022-04-13 11:01:10【深度学习】卷积神经网络原理 深度学习原理.pdf -
深度学习(神经网络) —— BP神经网络原理推导及python实现
2020-12-20 16:41:03深度学习(神经网络) —— BP神经网络原理推导及python实现摘要(一)BP神经网络简介1、神经网络权值调整的一般形式为:2、BP神经网络中关于学习信号的求取方法:(二)BP神经网络原理推导1、变量说明2、BP算法推导... -
卷积神经网络原理详解
2018-06-07 14:25:13本ppt详细介绍了卷积神经网络的起源背景、算法原理、算法的执行过程、以及CNN的应用场景 -
神经网络原理,全书签,simon著
2018-06-05 14:44:01神经网络原理,全书签,simon著,pdf格式,很清晰,书签很全。 -
MATLAB神经网络原理与实例精解(pdf+源码)
2019-05-23 10:32:31本资源包含《matlab神经网络原理与实例精解》pdf与代码,方便了解matlab如何构建神经网络 -
神经网络源码_神经网络原理与实例源码_;matlab源码_神经网络原理_
2021-09-29 07:27:13书本神经网络原理与实例中matlab算法与例子源码 -
MATLAB神经网络原理与实例精解
2018-07-24 10:48:31MATLAB神经网络原理与实例精解,系统深入学习MATLAB神经网络 -
神经网络原理(S.Haykin).pdf
2018-04-21 08:46:34神经网络原理 Simon.Haykin 编着——神经网络书籍中最经典的一本,对于刚学习神经网络的朋友还是不错的。 -
BP神经网络原理
2018-06-04 21:07:38BP神经网络原理,BP神经网络原理,BP神经网络原理,BP神经网络原理 -
《人工神经网络原理与应用》试题.doc
2019-08-20 14:17:30《人工神经网络原理与应用》试题.doc -
卷积神经网络原理
2022-03-23 12:33:42简单快速了解卷积神经网络(CNN)原理Convolutional Neural Network(CNN)
- 卷积层
- 池化层(Pooling)
- 归一化
- 全连接
- 把全连接层转化成卷积层
ConvNets
卷积神经网络的结构基于一个假设,即输入数据是图像,基于该假设,我们就向结构中添加了一些特有的性质。这些特有属性使得前向传播函数实现起来更高效,并且大幅度降低了网络中参数的数量。
常规神经网络
常规神经网络,神经网络的输入是一个向量,然后在一系列的隐层中对它做变换。每个隐层都是由若干的神经元组成,每个神经元都与前一层中的所有神经元连接。
举例说来,一个尺寸为200x200x3的图像,会让神经元包含200x200x3=120,000个权重值。而网络中肯定不止一个神经元,那么参数的量就会快速增加!显而易见,这种全连接方式效率低下,大量的参数也很快会导致网络过拟合。
ConvNets
计算机认识的图片:一个有长宽的矩阵,再加上一个通道数;在RGB图片里有3个通道,R\G\B.
一个简单的卷积神经网络是由各种层按照顺序排列组成,网络中的每个层使用一个可以微分的函数将激活数据从一个层传递到另一个层。卷积神经网络主要由三种类型的层构成:卷积层,池化(Pooling)层和全连接层(全连接层和常规神经网络中的一样)。通过将这些层叠加起来,就可以构建一个完整的卷积神经网络。
卷积层
卷积层是构建卷积神经网络的核心层,它产生了网络中大部分的计算量。
如何简化计算?
- 让不同的神经元守备不同区域
- 共享参数
input
4 1 0 0 8 1 0 2 4 1 0 1 8 0 0 2 4 1 0 0 8 1 0 2 4 0 0 1 8 2 0 2 4 0 0 0 8 0 0 2 4 1 0 1 8 1 0 2 filter
0 1 0 0 1 0 0 1 0 在前向传播的时候,让每个filter都在输入数据的宽度和高度上滑动(更精确地说是卷积),然后计算整个filter和输入数据任一处的内积。当filter沿着输入数据的宽度和高度滑过后,会生成一个2维的激活图(activation map),激活图给出了在每个空间位置处Receptive field的反应。直观地来说,网络会让filter学习到当它看到某些类型的视觉特征时就激活,具体的视觉特征可能是某些方位上的边界,或者在第一层上某些颜色的斑点.
一个channel的卷积
在每个卷积层上,我们会有一排的filter(比如16个、32、64个,需要多少个,自己定,你开心就好),每个都会生成一个不同的二维激活图。将这些激活映射在深度方向上层叠起来就生成了输出数据。
例如,在100 * 100 * 3的输入下,我定了第一层的 filter 为64个,stride=1,那么输出将是 98 * 98 * 64的矩阵
一个filter就是一个神经元,当它滑向下一区域时,就相当于切换到下一区域的神经元,这些神经元共享同一组参数也就是filter里的参数,你定了64个filter那么将有64组filter分别扫过一整张图片.
动画演示
https://cs231n.github.io/assets/conv-demo/index.html
例1:假设输入数据体尺寸为[32x32x3](比如CIFAR-10的RGB图像),如果Receptive field是5x5,那么卷积层中的每个神经元会有输入数据体中[5x5x3]区域的权重,共5x5x3=75个权重(还要加一个偏差参数)。注意这个连接在深度维度上的大小必须为3,和输入数据体的深度一致。
例2:假设输入数据体的尺寸是[16x16x20],filter尺寸是3x3,那么卷积层中每个神经元和输入数据体就有3x3x20=180个连接。再次提示:在空间上连接是局部的(3x3),但是在深度上是和输入数据体一致的(20)。
怎么控制输出数据?
3个超参数控制着输出数据体的尺寸:深度(depth),步长(stride)和填充(padding)。
- 首先,输出数据体的深度是一个超参数:它和使用的filter的数量一致,而每个filter在输入数据中寻找一些不同的东西。举例来说,如果第一个卷积层的输入是原始图像,那么在深度维度上的不同神经元将可能被不同方向的边界,或者是颜色斑点激活。我们将这些沿着深度方向排列、filter相同的神经元集合称为深度列(depth column),也有人使用纤维(fibre)来称呼它们。
- 其次,在滑动filter的时候,必须指定步长。当步长为1,滤波器每次移动1个像素。当步长为2(或者不常用的3,或者更多,这些在实际中很少使用),filter滑动时每次移动2个像素。这个操作会让输出数据体在空间上变小。
- 在下文可以看到,有时候将输入数据体用0在边缘处进行填充是很方便的。这个零填充(zero-padding)的尺寸是一个超参数。零填充有一个良好性质,即可以控制输出数据体的空间尺寸(最常用的是用来保持输入数据体在空间上的尺寸,这样输入和输出的宽高都相等)(你可以用0填充,也可以用均值填充,根据需求,你喜欢就好)。
如何抓取特征
当图片上出现与filter相似的特征时,输出的值会有明显变化,训练时根据这种变化,网络会调整参数,让filter记住这个特征.
池化层
为了控制数据体的大小,通常,在连续的卷积层之间会周期性地插入一个池化层。这样的话就能减少网络中参数的数量,使得计算资源耗费变少,也能有效控制过拟合。池化层使用MAX操作(不一定非要MAX Pooling也可以mean等等,你喜欢),对输入数据体的每一个深度切片独立进行操作,改变它的空间尺寸。最常见的形式是池化层使用尺寸2x2的filter,以步长为2来对每个深度切片进行降采样,将其中75%的激活信息都丢掉。每个MAX操作是从4个数字中取最大值(也就是在深度切片中某个2x2的区域)。深度保持不变。
是不是一定非要用池化层?
答案是否定的。不是非得用池化,我用池化就一定好。举个栗子,Alpha Go论文中有提到,网络是19 * 19的输入,而恰巧围棋棋盘就是19*19路,Alpha Go设计者就把每一步棋子在棋盘的位置当成一张图片,那么网络就可以用CNN,而确实是用的CNN,那么在这上面使用池化的话会发生什么?会丢了棋子信息,因为每一个棋子都会影响棋局的走势,所有不能丢失任一处的棋子信息。
归一化层
在卷积神经网络的结构中,提出了很多不同类型的归一化层,有时候是为了实现在生物大脑中观测到的抑制机制。但是这些层渐渐都不再流行,因为实践证明它们的效果即使存在,也是极其有限的。
全连接层
在全连接层中,神经元对于前一层中的所有激活数据是全部连接的,这个常规神经网络中一样。
网络结构
卷积神经网络通常是由三种层构成:卷积层,池化层(除非特别说明,一般就是最大值池化)和全连接层(简称FC)。ReLU激活函数也应该算是是一层,它逐元素地进行激活函数操作。在本节中将讨论在卷积神经网络中这些层通常是如何组合在一起的。
层的排列规律
卷积神经网络最常见的形式就是将一些卷积层和ReLU层放在一起,其后紧跟池化层,然后重复如此直到图像在空间上被缩小到一个足够小的尺寸,在某个地方过渡成成全连接层也较为常见。最后的全连接层得到输出,比如分类评分等。
- INPUT -> FC,实现一个线性分类器,此处N = M = K = 0。
- INPUT -> CONV -> RELU -> FC
- INPUT -> [CONV -> RELU -> POOL]*2 -> FC -> RELU -> FC。此处在每个汇聚层之间有一个卷积层。
- INPUT -> [CONV -> RELU -> CONV -> RELU -> POOL]*3 -> [FC -> RELU]*2 -> FC。此处每个汇聚层前有两个卷积层,这个思路适用于更大更深的网络,因为在执行具有破坏性的池化操作前,多重的卷积层可以从输入数据中学习到更多的复杂特征。
层的尺寸设置规律
- 输入层(包含图像的)应该能被2整除很多次。常用数字包括32(比如CIFAR-10),64,96(比如STL-10)或224(比如ImageNet卷积神经网络),384和512。
- 卷积层 应该使用小尺寸滤波器(比如3x3或最多5x5),使用步长1 。还有一点非常重要,就是对输入数据进行零填充,这样卷积层就不会改变输入数据在空间维度上的尺寸。
- 池化层 负责对输入数据的空间维度进行降采样。最常用的设置是用用2x2Receptive field的最大值池化,步长为2。注意这一操作将会把输入数据中75%的激活数据丢弃(因为对宽度和高度都进行了2的降采样)。 另一个不那么常用的设置是使用3x3的Receptive field,步长为2。最大值池化的Receptive field尺寸很少有超过3的,因为池化操作过于激烈,易造成数据信息丢失,这通常会导致算法性能变差。
减少尺寸设置的问题:上文中展示的两种设置是很好的,因为所有的卷积层都能保持其输入数据的空间尺寸,汇聚层只负责对数据体从空间维度进行降采样。如果使用的步长大于1并且不对卷积层的输入数据使用零填充,那么就必须非常仔细地监督输入数据体通过整个卷积神经网络结构的过程,确认所有的步长和滤波器都尺寸互相吻合
为什么在卷积层使用1的步长? 在实际应用中,更小的步长效果更好。上文也已经提过,步长为1可以让空间维度的降采样全部由汇聚层负责,卷积层只负责对输入数据体的深度进行变换。
为何使用零填充? 使用零填充除了前面提到的可以让卷积层的输出数据保持和输入数据在空间维度的不变,还可以提高算法性能。如果卷积层值进行卷积而不进行零填充,那么数据体的尺寸就会略微减小,那么图像边缘的信息就会过快地损失掉。网络结构例子:
一个用于CIFAR-10图像数据分类的卷积神经网络的结构可以是[输入层-卷积层-ReLU层-汇聚层-全连接层]。细节如下:
- 输入[32x32x3]存有图像的原始像素值,本例中图像宽高均为32,有3个颜色通道。
- 卷积层中,神经元与输入层中的一个局部区域相连,每个神经元都计算自己与输入层相连的小区域与自己权重的内积。卷积层会计算所有神经元的输出。如果我们使用12个滤波器(也叫作核),得到的输出数据体的维度就是[32x32x12]。
- ReLU层将会逐个元素地进行激活函数操作,比如使用以0为阈值的 作为激活函数。该层对数据尺寸没有改变,还是[32x32x12]。
- 池化层在在空间维度(宽度和高度)上进行降采样(downsampling)操作,数据尺寸变为[16x16x12]。
- 全连接层将会计算分类评分,数据尺寸变为[1x1x10],其中10个数字对应的就是CIFAR-10中10个类别的分类评分值。正如其名,全连接层与常规神经网络一样,其中每个神经元都与前一层中所有神经元相连接。
由此看来,卷积神经网络一层一层地将图像从原始像素值变换成最终的分类评分值。其中有的层含有参数,有的没有。具体说来,卷积层和全连接层(CONV/FC)对输入执行变换操作的时候,不仅会用到激活函数,还会用到很多参数(神经元的突触权值和偏差)。而ReLU层和汇聚层则是进行一个固定不变的函数操作。卷积层和全连接层中的参数会随着梯度下降被训练,这样卷积神经网络计算出的分类评分就能和训练集中的每个图像的标签吻合了。
小结:
- 简单案例中卷积神经网络的结构,就是一系列的层将输入数据变换为输出数据(比如分类评分)。
- 卷积神经网络结构中有几种不同类型的层(目前最流行的有卷积层、全连接层、ReLU层和汇聚层)。
- 每个层的输入是3D数据,然后使用一个可导的函数将其变换为3D的输出数据。
- 有的层有参数,有的没有(卷积层和全连接层有,ReLU层和汇聚层没有)。
案例学习
下面是卷积神经网络领域中比较有名的几种结构:
- LeNet: 第一个成功的卷积神经网络应用,是Yann LeCun在上世纪90年代实现的。当然,最著名还是被应用在识别数字和邮政编码等的LeNet结构。
- AlexNet: AlexNet卷积神经网络在计算机视觉领域中受到欢迎,它由Alex Krizhevsky,Ilya Sutskever和Geoff Hinton实现。AlexNet在2012年的ImageNet ILSVRC 竞赛中夺冠,性能远远超出第二名(16%的top5错误率,第二名是26%的top5错误率)。这个网络的结构和LeNet非常类似,但是更深更大,并且使用了层叠的卷积层来获取特征(之前通常是只用一个卷积层并且在其后马上跟着一个汇聚层)。
- ZF Net: Matthew Zeiler和Rob Fergus发明的网络在ILSVRC 2013比赛中夺冠,它被称为ZFNet(Zeiler &Fergus Net的简称)。它通过修改结构中的超参数来实现对AlexNet的改良,具体说来就是增加了中间卷积层的尺寸,让第一层的步长和滤波器尺寸更小。
- GoogLeNet: ILSVRC 2014的胜利者是谷歌的Szeged等实现的卷积神经网络。它主要的贡献就是实现了一个奠基模块,它能够显著地减少网络中参数的数量(AlexNet中有60M,该网络中只有4M)。还有,这个论文中没有使用卷积神经网络顶部使用全连接层,而是使用了一个平均汇聚,把大量不是很重要的参数都去除掉了。GooLeNet还有几种改进的版本,最新的一个是Inception-v4。
- VGGNet: ILSVRC 2014的第二名是Karen Simonyan和 Andrew Zisserman实现的卷积神经网络,现在称其为VGGNet。它主要的贡献是展示出网络的深度是算法优良性能的关键部分。他们最好的网络包含了16个卷积/全连接层。网络的结构非常一致,从头到尾全部使用的是3x3的卷积和2x2的汇聚。他们的预训练模型是可以在网络上获得并在Caffe中使用的。VGGNet不好的一点是它耗费更多计算资源,并且使用了更多的参数,导致更多的内存占用(140M)。其中绝大多数的参数都是来自于第一个全连接层。后来发现这些全连接层即使被去除,对于性能也没有什么影响,这样就显著降低了参数数量。
- ResNet: 残差网络(Residual Network)是ILSVRC2015的胜利者,由何恺明等实现。它使用了特殊的跳跃链接,大量使用了批量归一化(batch normalization)。这个结构同样在最后没有使用全连接层。读者可以查看何恺明的的演讲(视频,PPT),以及一些使用Torch重现网络的实验。ResNet当前最好的卷积神经网络模型(2016年五月)。何开明等最近的工作是对原始结构做一些优化,可以看论文 Identity Mappings in Deep Residual Networks,2016年3月发表。
把全连接层转化成卷积层(摘自CS231n课程笔记翻译:卷积神经网络笔记)
全连接层和卷积层之间唯一的不同就是卷积层中的神经元只与输入数据中的一个局部区域连接,并且在卷积列中的神经元共享参数。然而在两类层中,神经元都是计算点积,所以它们的函数形式是一样的。因此,将此两者相互转化是可能的:
- 对于任一个卷积层,都存在一个能实现和它一样的前向传播函数的全连接层。权重矩阵是一个巨大的矩阵,除了某些特定块(这是因为有局部连接),其余部分都是零。而在其中大部分块中,元素都是相等的(因为参数共享)。
- 相反,任何全连接层都可以被转化为卷积层。比如,一个 的全连接层,输入数据体的尺寸是,这个全连接层可以被等效地看做一个的 卷积层。换句话说,就是将滤波器的尺寸设置为和输入数据体的尺寸一致了。因为只有一个单独的深度列覆盖并滑过输入数据体,所以输出将变成 ,这个结果就和使用初始的那个全连接层一样了。
全连接层转化为卷积层:在两种变换中,将全连接层转化为卷积层在实际运用中更加有用。假设一个卷积神经网络的输入是224x224x3的图像,一系列的卷积层和汇聚层将图像数据变为尺寸为7x7x512的激活数据体(在AlexNet中就是这样,通过使用5个汇聚层来对输入数据进行空间上的降采样,每次尺寸下降一半,所以最终空间尺寸为224/2/2/2/2/2=7)。从这里可以看到,AlexNet使用了两个尺寸为4096的全连接层,最后一个有1000个神经元的全连接层用于计算分类评分。我们可以将这3个全连接层中的任意一个转化为卷积层:
- 针对第一个连接区域是[7x7x512]的全连接层,令其滤波器尺寸为 ,这样输出数据体就为[1x1x4096]了。
- 针对第二个全连接层,令其滤波器尺寸为 ,这样输出数据体为[1x1x4096]。
- 对最后一个全连接层也做类似的,令其 ,最终输出为[1x1x1000]
实际操作中,每次这样的变换都需要把全连接层的权重W重塑成卷积层的滤波器。那么这样的转化有什么作用呢?
它在下面的情况下可以更高效:让卷积网络在一张更大的输入图片上滑动(译者注:即把一张更大的图片的不同区域都分别带入到卷积网络,得到每个区域的得分),得到多个输出,这样的转化可以让我们在单个向前传播的过程中完成上述的操作。举个例子,如果我们想让224x224尺寸的浮窗,以步长为32在384x384的图片上滑动,把每个经停的位置都带入卷积网络,最后得到6x6个位置的类别得分。上述的把全连接层转换成卷积层的做法会更简便。如果224x224的输入图片经过卷积层和汇聚层之后得到了[7x7x512]的数组,那么,384x384的大图片直接经过同样的卷积层和汇聚层之后会得到[12x12x512]的数组(因为途径5个汇聚层,尺寸变为384/2/2/2/2/2 = 12)。然后再经过上面由3个全连接层转化得到的3个卷积层,最终得到[6x6x1000]的输出(因为(12 - 7)/1 + 1 = 6)。这个结果正是浮窗在原图经停的6x6个位置的得分!(译者注:这一段的翻译与原文不同,经过了译者较多的修改,使更容易理解)
面对384x384的图像,让(含全连接层)的初始卷积神经网络以32像素的步长独立对图像中的224x224块进行多次评价,其效果和使用把全连接层变换为卷积层后的卷积神经网络进行一次前向传播是一样的。
自然,相较于使用被转化前的原始卷积神经网络对所有36个位置进行迭代计算,使用转化后的卷积神经网络进行一次前向传播计算要高效得多,因为36次计算都在共享计算资源。这一技巧在实践中经常使用,一次来获得更好的结果。比如,通常将一张图像尺寸变得更大,然后使用变换后的卷积神经网络来对空间上很多不同位置进行评价得到
分类评分,然后在求这些分值的平均值。最后,如果我们想用步长小于32的浮窗怎么办?用多次的向前传播就可以解决。比如我们想用步长为16的浮窗。那么先使用原图在转化后的卷积网络执行向前传播,然后分别沿宽度,沿高度,最后同时沿宽度和高度,把原始图片分别平移16个像素,然后把这些平移之后的图分别带入卷积网络。(译者注:这一段的翻译与原文不同,经过了译者较多的修改,使更容易理解)
参考台湾大学李宏毅老师的机器学习课程 参考由杜客和猴子翻译,堃堃和李艺颖进行校对修改的cs231n笔记。来自网址:https://zhuanlan.zhihu.com/p/22038289 图片分别平移16个像素,然后把这些平移之后的图分别带入卷积网络。(译者注:这一段的翻译与原文不同,经过了译者较多的修改,使更容易理解)
参考台湾大学李宏毅老师的机器学习课程
参考由杜客和猴子翻译,堃堃和李艺颖进行校对修改的cs231n笔记。来自网址:https://zhuanlan.zhihu.com/p/220382892021-6-15
-
人工神经网络原理及应用
2015-11-19 16:50:45《人工神经网络原理及应用》由朱大奇、史慧编著,科学出版社出版。该书是现代计算机科学技术精品教材之一,介绍了人工神经网络的基本原理及其应用。重点阐述了9种常见神经网络的结构组成、工作原理、设计方法及应用... -
Elman神经网络原理
2021-07-30 11:12:16Elman神经网络 近期开题,阅读到了一篇文章关于故障诊断的,其中用到了Elman神经网络,具体是结合EMD、PCA-SOM的Elman的性能评估/预测故障诊断,对Elman神经网络有点陌生,网上资源也讲的特别杂,来做个汇总...Elman神经网络
近期开题,阅读到了一篇文章关于故障诊断的,其中用到了Elman神经网络,具体是结合EMD、PCA-SOM的Elman的性能评估/预测故障诊断,对Elman神经网络有点陌生,网上资源也讲的特别杂,来做个汇总Introduction吧!
介绍
Elman神经网络 是 J. L. Elman于1990年首先针对语音处理问题而提出来的,是一种典型的局部回归网络( global feed forward local recurrent)。Elman网络可以看作是一个具有局部记忆单元和局部反馈连接的递归神经网络。
Elman网络具有与多层前向网络相似的多层结构。
它的主要结构是前馈连接, 包括输入层、 隐含层、 输出层, 其连接权可以进行学习修正;反馈连接由一组“结构 ” 单元构成,用来记忆前一时刻的输出值, 其连接权值是固定的。在这种网络中, 除了普通的隐含层外, 还有一个特别的隐含层,称为关联层 (或联系单元层 ) ;该层从隐含层接收反馈信号, 每一个隐含层节点都有一个与之对应的关联层节点连接。关联层的作用是通过联接记忆将上一个时刻的隐层状态连同当前时刻的网络输入一起作为隐层的输入, 相当于状态反馈。隐层的传递函数仍为某种非线性函数, 一般为 Sigmoid函数, 输出层为线性函数, 关联层也为线性函数。
----词条来自于百度百科
Elman组成
Elman神经网络是一种典型的动态神经网络,通常有四层:输入层、中间层(隐含层)、 承接层和输出层。
-
输入层、隐含层和输出层的连接类似于前馈网络。
-
输入层的单元只传输信号,输出层的单元具有线性加权的功能。
-
隐层细胞的传递函数可以是线性函数,也可以是非线性函数。
-
承接层又称为上下文层或状态层,用于记忆隐层的前一个时间步长输出,因此可以看作是一步时间延迟算子。
-
Elman网络结构
带反馈的的BP网络
行程迟滞具有短期记忆功能(Figure来自于网络)
Elman神经网络的特点是通过受体层的延迟和存储,隐层的输出与隐层的输入本身相连。这种自连接对其历史状态的数据非常敏感,内部反馈网络也增加了动态信息处理的能力,从而达到动态建模的目的。
选择用历史训练的Elman神经网络同步预测,数据流程图如下图所示。
- Elman网络学习算法
用BP算法进行权值修正,指标函数为误差平方和
Matlab实例代码
本实例是引用的《Matlab神经网络30个案例分析》中的一个,觉得很不错,就更新一下下!~
内容较为古老,直接附上了,请多担待。
电力负荷预测概述
模型建立
电力系统负荷数据
具体数据及其源代码在我的GitHub上可下载:
https://github.com/YurBro/Project-Code/tree/main/ElmanNNMatlab Code:
%% 基于Elman神经网络的电力负荷预测模型研究 % % % <html> % <table border="0" width="600px" id="table1"> <tr> <td><b><font size="2">该案例作者申明:</font></b></td> </tr> <tr> <td><span class="comment"><font size="2">1:本人长期驻扎在此<a target="_blank" href="http://www.ilovematlab.cn/forum-158-1.html"><font color="#0000FF">板块</font></a>里,对<a target="_blank" href="http://www.ilovematlab.cn/thread-48362-1-1.html"><font color="#0000FF">该案例</font></a>提问,做到有问必答。</font></span></td></tr><tr> <td><span class="comment"><font size="2">2:此案例有配套的教学视频,配套的完整可运行Matlab程序。</font></span></td> </tr> <tr> <td><span class="comment"><font size="2"> 3:以下内容为该案例的部分内容(约占该案例完整内容的1/10)。</font></span></td> </tr> <tr> <td><span class="comment"><font size="2"> 4:此案例为原创案例,转载请注明出处(<a target="_blank" href="http://www.ilovematlab.cn/">Matlab中文论坛</a>,<a target="_blank" href="http://www.ilovematlab.cn/forum-158-1.html">《Matlab神经网络30个案例分析》</a>)。</font></span></td> </tr> <tr> <td><span class="comment"><font size="2"> 5:若此案例碰巧与您的研究有关联,我们欢迎您提意见,要求等,我们考虑后可以加在案例里。</font></span></td> </tr> <tr> <td><span class="comment"><font size="2"> 6:您看到的以下内容为初稿,书籍的实际内容可能有少许出入,以书籍实际发行内容为准。</font></span></td> </tr><tr> <td><span class="comment"><font size="2"> 7:此书其他常见问题、预定方式等,<a target="_blank" href="http://www.ilovematlab.cn/thread-47939-1-1.html">请点击这里</a>。</font></span></td> </tr></table> % </html> % %% 清空环境变量 clc; clear all close all nntwarn off; %% 数据载入 load data; a=data; %% 选取训练数据和测试数据 for i=1:6 p(i,:)=[a(i,:),a(i+1,:),a(i+2,:)]; end % 训练数据输入 p_train=p(1:5,:); % 训练数据输出 t_train=a(4:8,:); % 测试数据输入 p_test=p(6,:); % 测试数据输出 t_test=a(9,:); % 为适应网络结构 做转置 p_train=p_train'; t_train=t_train'; p_test=p_test'; %% 网络的建立和训练 % 利用循环,设置不同的隐藏层神经元个数 nn=[7 11 14 18]; for i=1:4 threshold=[0 1;0 1;0 1;0 1;0 1;0 1;0 1;0 1;0 1]; % 建立Elman神经网络 隐藏层为nn(i)个神经元 net=newelm(threshold,[nn(i),3],{'tansig','purelin'}); % 设置网络训练参数 net.trainparam.epochs=1000; net.trainparam.show=20; % 初始化网络 net=init(net); % Elman网络训练 net=train(net,p_train,t_train); % 预测数据 y=sim(net,p_test); % 计算误差 error(i,:)=y'-t_test; end %% 通过作图 观察不同隐藏层神经元个数时,网络的预测效果 plot(1:1:3,error(1,:),'-ro','linewidth',2); hold on; plot(1:1:3,error(2,:),'b:x','linewidth',2); hold on; plot(1:1:3,error(3,:),'k-.s','linewidth',2); hold on; plot(1:1:3,error(4,:),'c--d','linewidth',2); title('Elman预测误差图') set(gca,'Xtick',[1:3]) legend('7','11','14','18','location','best') xlabel('时间点') ylabel('误差') hold off; web browser http://www.ilovematlab.cn/viewthread.php?tid=63640 %% % % <html> % <table align="center" > <tr> <td align="center"><font size="2">版权所有:</font><a % href="http://www.ilovematlab.cn/">Matlab中文论坛</a> <script % src="http://s3.cnzz.com/stat.php?id=971931&web_id=971931&show=pic" language="JavaScript" ></script> </td> </tr></table> % </html> %
目前知道的关于Elman神经网络的内容就这么多,还需要再多读读Paper。
~
有新的相关内容知识,⚡必更新⚡!
~
待研究透彻之后,定给出⚡Python代码⚡!
-更新日志-
(2021.8.19只更新了个MATLAB的程序,着实丢人!!!)
~
❤坚持读Paper,坚持做笔记写Blog!❤ღ( ´・ᴗ・` )
❤
『
我相信所有被我遗忘的美好,一定还在这世上的某个角落,也相信总有一天,走过很长的生命,遇见美好,春暖花开!
』 -
-
神经网络学习笔记1——BP神经网络原理到编程实现(matlab,python)
2022-01-13 22:10:46神经网络学习笔记1——BP神经网络原理到编程实现(matlab,python)先表达一下歉意吧
不好意思拖了这么久才整理,弄完考试的事情就在研究老师给安排的新任务,一时间还有点摸不到头脑,就直接把百度网盘链接放在视频下面了但是最近才发现那个链接发出来了看不到,所以现在有时间了就来重新整理一下!
(发了之后看好多人管我要,我还奇怪,原来是没法出去o(╥﹏╥)o)
目录
下面是视频地址和代码数据
BP神经网络原理及编程实现
BP神经网络原理及编程实现_哔哩哔哩_bilibili
python,matlab代码,还有数据集放在这里了
链接:https://pan.baidu.com/s/1-onLcVrPR7csFWJkxhIMsg
提取码:j3z6感觉有帮助的话,可以点个赞支持一下,真的每次被赞的时候还是挺开心的哈哈(*^▽^*)
1.bp神经网络原理
bp神经网络主要由三部分组成,分别是前向传播,反向传播,测试模型。其中前向传播主要是计算模型当前的预测结果,反向传播是对模型进行修正得到能达到预测效果的模型,测试模型是看我们最后通过反向传播得到的模型能否识别出我们想要的分类,好下面我来分别介绍他们的原理~
1.1前向传播
我就拿一个三层的网络来举例说明,同时也是我后面讲得第一个项目,这样理论实践相结合,比较方便理解。
这是一个基础的三层神经网络,按顺序分别是输入层,隐藏层,输出层,我们先按照一个节点来看,这样方便理解,我把传播的公式放在下面
其中a1作为输入的一个特征,在这里我们把特征数字化表示成一个数字
w代表权重,其实按我理解,就是a1占多少分量,这个特征对我们识别目标帮助有多大
b是一个偏差,方便我们对a2也就是下一个节点的值进行调整
z代表节点激活,这里用到了归激活函数sigmoid,对节点进行激活,按照我的理解sigmoid是一个归一化函数他要把归一化到0-1之间,方便收敛和标签值比较,判断误差,这样通过缩小误差来达到模型的预测功能。
最后的得到的z3是前向传播的结果也就是我们模型预测结果分类标签。
1.2反向传播
得到了前向传播的结果,相当于是一组用来训练的数据,我们要通过这次前向传播得到的结果和我们的分类标签相减得到误差。
我们希望缩小误差让我们的模型有更好的训练效果,这时候就要用到反向传播们这里用的是梯度下降法,让误差按照梯度的方向减小,最后训练打到我们预期的效果。
还是用我们刚才的神经网络
这里是做的一个链式求导,可以左右对应着看,因为E对b直接进行求导得不到结果,通过链式展开,配合着左边的公式,其中每一部都是可以求出来的,结果如红字表示,这里感觉文字不太方便表述,要是实在还不清楚,就看一下最前面分享的视频,里面讲解的还是比较细致的
然后求w1,w2同理
这样我们就能通过反向传播的到,b1,b2,w1,w2的变化率,然后和最开始随机得到的w和b进行运算就得到了我们通过这一组数据训练后的结果,在这里最重要的就是权重和偏差的数值了!
1.3 测试模型
理解了前面两个测试模型其实就很好理解了,这里其实主要也是前向传播,我们用训练好的模型对测试集进行目标分类,在通过
正确预测/训练集总数 * 100% = 模型的准确率
2.两个项目的matlab实现和python实现
对于这个程序要是看不懂的地方我记得在视频中有逐行对应的讲解,这里我们就大致标注一下
2.1语音数据分类预测
matlab实现如下
%% 清空环境变量 clc clear %% 训练数据预测数据提取及归一化 %1.下载四类语音信号 load data1 c1 load data2 c2 load data3 c3 load data4 c4 %2.四个特征信号矩阵合成一个矩阵 data(1:500,:)=c1(1:500,:); data(501:1000,:)=c2(1:500,:); data(1001:1500,:)=c3(1:500,:); data(1501:2000,:)=c4(1:500,:); %3.从1到2000间随机排序 k=rand(1,2000);%生成0-1之中2000个随机数 [m,n]=sort(k);%对k进行从从小到大的排序,序结果放入m(1*2000)向量,n(1*2000)为原数据对应的索引号 %4.输入输出数据 input=data(:,2:25);%取出data中2到25列数据构成新矩阵input output1 =data(:,1);%取出data中第一列数据构成矩阵output1 %5.把输出从1维变成4维 for i=1:2000 switch output1(i) case 1 output(i,:)=[1 0 0 0]; case 2 output(i,:)=[0 1 0 0]; case 3 output(i,:)=[0 0 1 0]; case 4 output(i,:)=[0 0 0 1]; end end %6.随机提取1500个样本为训练样本,500个样本为预测样本 input_train=input(n(1:1500),:)'; output_train=output(n(1:1500),:)'; input_test=input(n(1501:2000),:)'; output_test=output(n(1501:2000),:)'; %7.输入数据归一化 [inputn,inputps]=mapminmax(input_train);%归一化到[-1,1]之间,inputps用来作下一次同样的归一化 %%8.网络结构初始化,设置节点输入层,隐藏层,输出层 innum=24; midnum=25;%选择多少个节点才比较好? outnum=4; %9.权值初始化 w1=rands(midnum,innum);%随机给定隐藏层和是输入层间的初始神经元权重 W1= net. iw{1, 1}; b1=rands(midnum,1);%中间各层神经元阈值 B1 = net.b{1}; w2=rands(midnum,outnum);%中间层到输出层的权值 W2 = net.lw{2,1}; b2=rands(outnum,1);%输出层各神经元阈值 B2 = net. b{2} %10.权重,偏差重新赋值 w2_1=w2;w2_2=w2_1;%把w2中的值分别配给w1w2 w1_1=w1;w1_2=w1_1; b1_1=b1;b1_2=b1_1; b2_1=b2;b2_2=b2_1; %11.学习率 xite=0.1 %权值阈值更新 alfa=0.01; %学习速率,这里设置为0.01 %%12 网络训练 %(1)大循环 for ii=1:10 E(ii)=0; for i=1:1:1500 %% (2)网络预测输出 x=inputn(:,i); % (3)隐含层输出 for j=1:1:midnum I(j)=inputn(:,i)'*w1(j,:)'+b1(j); Iout(j)=1/(1+exp(-I(j))); end % (4)输出层输出 yn=w2'*Iout'+b2; %%(5) 权值阀值修正 %计算误差 e=output_train(:,i)-yn; E(ii)=E(ii)+sum(abs(e)); %计算权值变化率 dw2=e*Iout; db2=e'; for j=1:1:midnum S=1/(1+exp(-I(j))); FI(j)=S*(1-S); end for k=1:1:innum for j=1:1:midnum dw1(k,j)=FI(j)*x(k)*(e(1)*w2(j,1)+e(2)*w2(j,2)+e(3)*w2(j,3)+e(4)*w2(j,4)); db1(j)=FI(j)*(e(1)*w2(j,1)+e(2)*w2(j,2)+e(3)*w2(j,3)+e(4)*w2(j,4)); end end %(6)权值阈值更新,学习率在这用 w1=w1_1+xite*dw1'; b1=b1_1+xite*db1'; w2=w2_1+xite*dw2'; b2=b2_1+xite*db2'; w1_2=w1_1;w1_1=w1; w2_2=w2_1;w2_1=w2; b1_2=b1_1;b1_1=b1; b2_2=b2_1;b2_1=b2; end end %%13 语音特征信号分类 inputn_test=mapminmax('apply',input_test,inputps); for ii=1:1 for i=1:500%1500 %隐含层输出 for j=1:1:midnum I(j)=inputn_test(:,i)'*w1(j,:)'+b1(j); Iout(j)=1/(1+exp(-I(j))); end fore(:,i)=w2'*Iout'+b2; end end %% 14结果分析 %(1)根据网络输出找出数据属于哪类 for i=1:500 output_fore(i)=find(fore(:,i)==max(fore(:,i))); end %(2)BP网络预测误差 error=output_fore-output1(n(1501:2000))'; %画出预测语音种类和实际语音种类的分类图 figure(1) plot(output_fore,'r') hold on plot(output1(n(1501:2000))','b') legend('预测语音类别','实际语音类别') %画出误差图 figure(2) plot(error) title('BP网络分类误差','fontsize',12) xlabel('语音信号','fontsize',12) ylabel('分类误差','fontsize',12) %print -dtiff -r600 1-4 k=zeros(1,4); %找出判断错误的分类属于哪一类 for i=1:500 if error(i)~=0 %~表示非也就是error不等于0是 [b,c]=max(output_test(:,i)); switch c case 1 k(1)=k(1)+1; case 2 k(2)=k(2)+1; case 3 k(3)=k(3)+1; case 4 k(4)=k(4)+1; end end end %找出每类的个体和 kk=zeros(1,4); for i=1:500 [b,c]=max(output_test(:,i)); switch c case 1 kk(1)=kk(1)+1; case 2 kk(2)=kk(2)+1; case 3 kk(3)=kk(3)+1; case 4 kk(4)=kk(4)+1; end end %正确率 rightridio=(kk-k)./kk
这个我在程序中进行了比较详细的备注,数据集在前面网盘链接中可以获取,这个项目的python文件是我完全仿照matlab中写了,流程基本一样,不太具有再利用价值,所以可以看下视频中的思路和讲解。
2.2 蝴蝶花分类预测
这里需要注意的是这里数据集是已经打乱好的数据,python中不在是墨守成规的仿照matlab文件,而是写好了一个框架,虽然是打乱的数据集,但是也配备了随机抽取数据的函数,方便大家拿了就用!!
这里用的改进的bp神经网路,动量下降法进行加速收敛大致步骤原理公式如下
Step 1 :初始化数据,设定各层节点数和学习效率等值。Step 2 :输入层 FA 输入样品,计算出隐层 FB 活动。b(ki)=logsig(a*V(:,ki)+Pi(ki))Step 3 :计算出输出层 FC 活动。c(kj)=logsig(b*W(:,kj)+Tau(kj))Step 4 :网络输出和期望输出相比较,计算出输出层 FC 的错误。d=c.*(1-c).*(ck-c)Step 5 :反传,计算出隐层 FB 的错误。e=b.*(1-b).*(d*W')Step 6 :修改 FC 层和 FB 之间的权值 wij 。DeltaW(ki,kj)=Alpha*b(ki)*d(kj)+Gamma*DeltaWOld(ki,kj)W=W+DeltaWStep 7 :修改 FA 层和 FB 之间的权值 vhj 。DeltaV(kh,ki)=Beta*a(kh)*e(ki)V=V+DeltaVStep 8 :修改偏差。重复 Step 2 ~ Step 8 ,直到输出层 FC 的错误足够小。2.2.1matlab程序如下
clc %清屏 clear all; %删除 workplace 变量 close all; %关掉显示图形窗口 format long % Initial % parameters for the NN structure h=4; i=3; j=3; Alpha=0.9; Beta=0.5; Gamma=0.85; Tor=0.0005; Maxepoch=2000; Accuracy=0; Ntrain=115; Ntest=35; %随机赋值 [-1, +1] V=2*(rand(h,i)-0.5); W=2*(rand(i,j)-0.5); Pi=2*(rand(1,i)-0.5); Tau=2*(rand(1,j)-0.5); DeltaWOld(i,j)=0; DeltaVOld(h,i)=0; DeltaPiOld(i)=0; DeltaTauOld(j)=0; % the learning process Epoch=1; Error=10; %加载数据 load data.dat Odesired=data(:,2); % normalize the input data to rang [-1 +1] datanew=data(:,3:6); maxv=max(max(datanew)); minv=min(min(datanew)); datanorm=2*((datanew-minv)/(maxv-minv)-0.5); while Error>Tor Err(Epoch)=0; for k=1:Ntrain % k = the index of tranning set a=datanorm(k,:); % set the desired output ck[j] if data(k,2)==0 ck=[1 0 0]; elseif data(k,2)==1 ck=[0 1 0]; else ck=[0 0 1]; end; % calculate the hidden nodes activation for ki=1:i b(ki)=logsig(a*V(:,ki)+Pi(ki)); end; % calculate the output nodes activation for kj=1:j c(kj)=logsig(b*W(:,kj)+Tau(kj)); end; % calculate error in output Layer FC d=c.*(1-c).*(ck-c); % calculate error in hidden layer FB e=b.*(1-b).*(d*W'); % adjust weights Wij between FB and FC for ki=1:i for kj=1:j DeltaW(ki,kj)=Alpha*b(ki)*d(kj)+Gamma*DeltaWOld(ki,kj); end end; W=W+DeltaW; DeltaWOld=DeltaW; % adjust weights Vij between FA and FB for kh=1:h for ki=1:i DeltaV(kh,ki)=Beta*a(kh)*e(ki); end end; V=V+DeltaV; DeltaVold=DeltaV; % adjust thresholds Pi and Tau DeltaPi=Beta*e+Gamma*DeltaPiOld; Pi=Pi+DeltaPi; DeltaPiold=DeltaPi; DeltaTau=Alpha*d+Gamma*DeltaTauOld; Tau=Tau+DeltaTau; DeltaTauold=DeltaTau; % the error is the max of d(1),d(2),d(3) Err(Epoch)=Err(Epoch)+0.5*(d(1)*d(1)+d(2)*d(2)+d(3)*d(3)); end %for k=1:Ntrain Err(Epoch)=Err(Epoch)/Ntrain; Error=Err(Epoch); % the training stops when iterate is too much if Epoch > Maxepoch break; end Epoch = Epoch +1; % update the iterate number end % test data for k=1:Ntest % k = the index of test set a=datanorm(Ntrain+k,:); % calculate the hidden nodes activation for ki=1:i b(ki)=logsig(a*V(:,ki)+Pi(ki)); end; % calculate the output of test sets for kj=1:j c(kj)=logsig(b*W(:,kj)+Tau(kj)); end; % transfer the output to one field format if (c(1)> 0.9) Otest(k)=0; elseif (c(2)> 0.9) Otest(k)=1; elseif (c(3)> 0.9) Otest(k)=2; else Otest(k)=3; end; % calculate the accuracy of test sets if Otest(k)==Odesired(Ntrain+k) Accuracy=Accuracy+1; end; end; % k=1:Ntest % plot the error plot(Err); % plot the NN output and desired output during test N=1:Ntest; figure; plot(N,Otest,'b-',N,Odesired(116:150),'r-'); % display the accuracy Accuracy = 100*Accuracy/Ntest; t=['正确率: ' num2str(Accuracy) '%' ]; disp(t);
2.2.2 python实现和框架如下
每一部分具体的功能都进行了标注
import math import random import numpy from sklearn import preprocessing import time import xlwt import matplotlib.pyplot as plt random.seed(0) def read_data(dir_str): ''' 读取txt文件中的数据 数据内容:科学计数法保存的多行多列数据 输入:txt文件的路径 输出:小数格式的数组,行列与txt文件中相同 ''' data_temp = [] with open(dir_str) as fdata: while True: line=fdata.readline() if not line: break data_temp.append([float(i) for i in line.split()]) return numpy.array(data_temp) def randome_init_train_test(data, n_tr): ''' 随机划分训练集和测试集 ''' # sklearn提供一个将数据集切分成训练集和测试集的函数train_test_split train_index = numpy.random.choice(data.shape[0], size=n_tr, replace=False, p=None) train_data = data[train_index] test_index = numpy.delete(numpy.arange(data.shape[0]),train_index) # 删除train_index对应索引的行数 test_data = data[test_index] return train_data, test_data def min_max_normalization(np_array): ''' 离差标准化,(Xi-min(X))/(max(X)-min(X)) ''' min_max_scaler = preprocessing.MinMaxScaler() ret = min_max_scaler.fit_transform(np_array) return ret def label_to_value(label): ''' 标签转换为对应输出值 (由于输出层结构,需要修改输出数据结构)''' switch = { 0.0: [1,0,0], 1.0: [0,1,0], 2.0: [0,0,1] } return switch[label] def value_to_label(value): ''' 神经网络输出值转换为对应标签 ''' return value.index(max(value)) def rand(min, max): ''' 随机取[a, b]范围内的值 ''' return (max - min) * random.random() + min def make_matrix(m, n, fill=0.0): # 生成多维矩阵 mat = [] for i in range(m): mat.append([fill] * n) return mat def sigmoid(x): return 1.0 / (1.0 + math.exp(-x)) def sigmoid_derivative(x): return x * (1 - x) class BPNeuralNetwork: def __init__(self): # 设置在BP神经网络中用到的参数 self.input_n = 0 self.hidden_n = 0 self.output_n = 0 self.input_values = [] # [1.0] * self.input_n self.hidden_values = [] # [1.0] * self.hidden_n self.output_values = [] # [1.0] * self.output_n self.input_weights = [] self.output_weights = [] self.input_correction = [] # dw1 self.output_correction = [] # dw2 self.input_bias = [] self.output_bias = [] def setup(self, ni, nh, no): # 参数设置 self.input_n = ni self.hidden_n = nh self.output_n = no # init self.input_values = [1.0] * self.input_n # 输入层神经元输出(输入特征) self.hidden_values = [1.0] * self.hidden_n # 中间层神经元输出 self.output_values = [1.0] * self.output_n # 隐藏层神经元输出(预测结果) self.input_weights = make_matrix(self.input_n, self.hidden_n) self.output_weights = make_matrix(self.hidden_n, self.output_n) # 初始随机赋值,在范围[-1, +1]内 for i in range(self.input_n): for h in range(self.hidden_n): self.input_weights[i][h] = rand(-1, 1) for h in range(self.hidden_n): for o in range(self.output_n): self.output_weights[h][o] = rand(-1, 1) self.input_correction = make_matrix(self.input_n, self.hidden_n) self.output_correction = make_matrix(self.hidden_n, self.output_n) self.input_bias = [0.0] * self.input_n self.output_bias = [0.0] * self.output_n def predict(self, inputs): # 前向传播(在train中套在反向传播的train前面) # 输入层计算 for i in range(self.input_n - 1): self.input_values[i] = inputs[i] # 隐藏层计算 for j in range(self.hidden_n): total = 0.0 for i in range(self.input_n): total += self.input_values[i] * self.input_weights[i][j] self.hidden_values[j] = sigmoid(total + self.input_bias[i]) # 输出层计算 for k in range(self.output_n): total = 0.0 for j in range(self.hidden_n): total += self.hidden_values[j] * self.output_weights[j][k] self.output_values[k] = sigmoid(total + self.output_bias[j]) return self.output_values[:] def back_propagate(self, case, label, learn, correct): # 前向预测 self.predict(case) # 计算输出层的误差 w2 output_deltas = [0.0] * self.output_n for o in range(self.output_n): error = label[o] - self.output_values[o] output_deltas[o] = sigmoid_derivative(self.output_values[o]) * error # 计算隐藏层的误差 w1 hidden_deltas = [0.0] * self.hidden_n for h in range(self.hidden_n): error = 0.0 for o in range(self.output_n): error += output_deltas[o] * self.output_weights[h][o] hidden_deltas[h] = sigmoid_derivative(self.hidden_values[h]) * error # 更新隐藏-输出层权重 b2 for h in range(self.hidden_n): for o in range(self.output_n): change = output_deltas[o] * self.hidden_values[h] self.output_weights[h][o] += learn * change + correct * self.output_correction[h][o] self.output_correction[h][o] = change self.output_bias[o] += learn * change # 更新输入-隐藏层权重 b1 for i in range(self.input_n): for h in range(self.hidden_n): change = hidden_deltas[h] * self.input_values[i] self.input_weights[i][h] += learn * change + correct * self.input_correction[i][h] self.input_correction[i][h] = change self.input_bias[h] += learn * change # 计算样本的均方误差 error = 0.0 for o in range(len(label)): error += 0.5 * (label[o] - self.output_values[o]) ** 2 return error def train(self, datas, labels, epochs=5000, learn=0.05, correct=0.1, stop_error=0.001): for j in range(epochs): error = 0.0 for i in range(len(datas)): label = labels[i] data = datas[i] error += self.back_propagate(data, label, learn, correct) if error <= stop_error: return j+1 return epochs def save_excel(datas, output_file): # 将数据保存到新的excel表格里 # 因为xls文件支持最大数据行数为65536,所以大文件输出成几个小文件,每个小文件有MAX_EXCEL_ROWS行数据 MAX_EXCEL_ROWS = 60000 for no in range(0, datas.__len__()//MAX_EXCEL_ROWS + 1): sheet_name = 'sheet' + str(no+1) output_file_name = output_file.split('.')[0] + str(no+1) + '.' + output_file.split('.')[-1] print('输出文件:', output_file_name) excel = xlwt.Workbook() sh = excel.add_sheet(sheet_name) for i, data in enumerate(datas[no*MAX_EXCEL_ROWS:(no+1)*MAX_EXCEL_ROWS]): for j, d in enumerate(data): sh.write(i, j, d) try: excel.save(output_file_name) except: xxx = input('输出异常!!请检查输出路径是否异常或文件是否已存在(需删除已存在文件)。然后输入任意键即可...') no = no - 1 print('结束gool luck') if __name__ == '__main__': n_tr = 115 input_nodes = 4 hidden_nodes = 3 # output_nodes = 3 epochs = 1000 learn_rate = 0.5 # 学习率 momentum_rate = 0.09 # 动量参数 correct_rate = 0.1 # 矫正率 data = read_data(r"D:\优化大作业\BPNN_Butterfly classification\data.txt") normal_data = min_max_normalization(data[:, 2:]) # 变量归一化 data = numpy.concatenate((data[:, 1:2],normal_data),axis=1) # 取出输出的结果和标准化的数据拼接在一起 tr, te = randome_init_train_test(data, n_tr) # 随机划分训练集和测试集 tr_in = tr[:, 1:] tr_out = [label_to_value(v[0]) for v in tr[:, :1]] # 由于输出层使用3个节点,需要修改输出数据结构 n_true = 0 # 统计正确预测数量 nn = BPNeuralNetwork() nn.setup(input_nodes, hidden_nodes, output_nodes) # 设置BP神经网络框架 st = time.perf_counter() epoch = nn.train(tr_in, tr_out, epochs, learn_rate, correct_rate) # train(self, datas, labels, epochs=5000, learn=0.05, correct=0.1, stop_error=0.001) print('epoch:', epoch, '\nTrain_time:', time.perf_counter() - st) pre = [] for t in te: t_in = t[1:] label = value_to_label(nn.predict(t_in)) if label == t[0]: n_true += 1 # print(t, label) pre.append([label]) # 输出统计结果 accuracy = n_true/(data.shape[0]-n_tr) print('accuracy:', accuracy) print(nn.input_bias, nn.output_bias) # numpy.savetxt(r'bpnn_param\input_weights.txt', (nn.input_weights), fmt='%s') # numpy.savetxt(r'bpnn_param\output_weights.txt', (nn.output_weights), fmt='%s') # numpy.savetxt(r'bpnn_param\input_correction.txt', (nn.input_correction), fmt='%s') # numpy.savetxt(r'bpnn_param\output_correction.txt', (nn.output_correction), fmt='%s') # 将数据保存到新的excel表格里 te_pre = numpy.concatenate((te, numpy.array(pre)), axis=1) save_excel(te_pre, 'test_result.xls') # 绘制准确率曲线 x_axis_data = [i for i in range(35)] y_axis_data1 = te[:, :1] # 真实结果 y_axis_data2 = pre # 预测结果 plt.xlabel('测试集数', fontproperties='SimHei') plt.ylabel('预测分类', fontproperties='SimHei') plt.plot(x_axis_data, y_axis_data1, color='blue', label='真实结果' ) plt.plot(x_axis_data, y_axis_data2, color='red', label='预测结果') plt.show()
3.心得分享
经过自己的学习和研究,感觉可以先看懂公式,然后把程序导进去,用好断点,一步一步步进或者调试模式,看看得到的程序的结果和应该得出的结果得维数是不是相同,数据是否合理,研究透之后可以多自己写一写练一练,基本就没啥问题啦~
up也是刚开始学习,有什么问题可以多多交流,互相学习~
-
BP神经网络基本原理简介
2018-08-15 15:11:57BP神经网络的详细介绍,包括基本算法及理论,方便初学者学习掌握 -
《MATLAB神经网络30个案例分析》(全书和源代码)/《MATLAB神经网络原理与实例精解》
2018-05-17 14:50:13包括: 《MATLAB神经网络30个案例分析》(全书和源代码) 《MATLAB神经网络原理与实例精解》 对于初学者有很大帮助,讲解很透彻! -
CNN卷积神经网络原理详解(上)
2019-10-18 23:59:17CNN卷积神经网络原理详解(上)前言卷积神经网络的生物背景我们要让计算机做什么?卷积网络第一层全连接层训练 前言 卷积网络(convolutional network),也叫作卷积神经网络(convolutional neural network,CNN),是...