好久没发博客了,最近一直在忙于毕设…
说到毕设,最近在用神经网络做一些东西,用的是MATLAB自带的神经网络工具箱去训练,毕竟和其他平台相比比较熟悉。MATLAB用工具箱训练出来的神经网络是一个network类型,里面包含了这个网络的所有参数。出于研究需要,我需要将神经网络的隐含层的输出提取出来,但是发现并没有直接提取的办法。查了一些资料,算是搞懂了,写一篇东西记录一下,也顺便分享给有需要的人。
其实这个操作并不难,只是因为MATLAB自动帮我们完成了一些数据处理操作,所以导致我们无法直接通过节点输出计算公式算得隐含层的输出。
众所周知,神经元节点的输出由下式计算可得
其中向量x为上一层节点的输出,也就是当前神经元的输入,w为权值矩阵,b是偏置,z为输出的加权和,σ为激活函数,a为神经元的输出。
所以可以看到,只要确定好了输入、权值、偏置以及激活函数,就可以算出任意一层的输出。下面分别介绍怎么获取这些属性。
介绍之前先生成一个单隐层的前向全连接网络作为后面的素材。
net1 = feedforwardnet(10);
上述语句生成了一个隐层节点数为10的BP网络
首先是激活函数,MATLAB中network对象有一个layers属性,是一个cell数组,数组的元素数量等于网络的层数(输入不算一层),因此本文的net1网络的layers对象应有2个元素,利用
length(net1.layers)
命令可查看其元素数量
可以看到元素数量为2,而激活函数则在layers数组的元素的transferFcn成员里面,使用命令
net1.layers{1}.transferFcn
可查看第一层的激活函数,在单隐层BP网络中第一层即为隐层
可以看到本隐层的激活函数为tansig函数,顺便附上tansig函数的图像
接下来是权值矩阵,对于network类型的网络对象,有专门的IW和LW成员来存放矩阵,其中IW(input weight)存放的是从输入节点到各层的权值矩阵,而LW(layers weight)存放的是层与层之间的权值矩阵。因此,要获取BP网络从输入节点到隐层的权值,可查看成员
net1.IW{1, 1}
可以看到,它是一个10x0的矩阵,行数10是因为隐层有10个节点,列数为0是因为我们还没给这个网络配置输入。
而要查看隐层到输出层的权值,可查看成员
net1.LW{2, 1}
network对象有一个b成员,也是一个cell数组,存放的就是各层的偏置(当然输入也不算一层)。
最后是输入的获取,相比于前三个要素,输入的获取要稍微复杂一点,因为利用MATLAB训练神经网络时,它会自动地对训练集施加归一化,也就是将实际的输入到输出的映射变为n维的[-1, 1]到m维的[-1, 1]的映射,其中n,m分别为输入输出维数,并且将归一化的操作参数存储在一个结构中。训练完后,所有的输入在输入之前需要进行归一化,而输出则需要反归一化。因此,要自己计算网络的输出,我们首先要把归一化的操作给自己完成了。
首先我们模拟MATLAB对输入的归一化,我们可以通过
[trainSetInput_nml, NmlInput] = mapminmax(trainSetInput, -1, 1)
来将原始训练集的输入数据trainSetInput归一化为范围在[-1, 1]的trainSetInput_nml,而归一化的相关参数则存储在NmlInput中。同样,通过
[trainSetOutput_nml, NmlOutput] = mapminmax(trainSetOutput, -1, 1)
来将原始训练集的输入数据trainSetOutput归一化为范围在[-1, 1]的trainSetOutput_nml,而归一化的相关参数则存储在NmlOutput中。
经过前面的操作,我们就分别获得了计算节点输出所需的四要素,接下来就是按照公式进行计算了
trainHidden = zeros(10, num); % 假设训练集中有num个样本,则就有对应num个隐层输出
for m = 1: num
trainHidden( : , m) = net1.IW{1, 1} * trainSetInput_nml( : , m) + net1.b{1}; % 计算加权和
end
trainHidden = tansig(trainHidden); % 经过激活函数得到最后输出
这样,我们就可以把训练集trainSetInput所对应的隐层输出给求出来了。
本文中使用单隐层BP网络来举例,所以只有输入到隐层以及隐层到输出的权值。对于其他结构的网络,IW和LW的具体元素需要各位读者自行探索。