Matlab - 神经网络训练

5
我正在创建一个具有反向传播的两层神经网络。NN应该从一个20001x17向量中获取数据,该向量在每行中包含以下信息:
-前16个单元格包含范围从0到15的整数,它们充当变量以帮助我们确定我们想要表达的26个字母中的哪一个。例如,以下16个值系列表示字母A:[2 8 4 5 2 7 5 3 1 6 0 8 2 7 2 7]。
-第17个单元格包含范围从1到26的数字,表示我们想要的字母。1代表A,2代表B等。
NN的输出层由26个输出组成。每次向NN提供如上所述的输入时,它应该输出一个1x26向量,除了对应于输入值意味着代表的字母的一个单元格外,所有单元格都包含零。例如,输出[1 0 0 ... 0]将表示字母A,而[0 0 0 ... 1]将表示字母Z。
在我展示代码之前,有些重要的事情需要说明:我需要使用traingdm函数,并且隐藏层数目(暂时)固定为21。
尝试创建上述概念,我编写了以下MATLAB代码:
%%%%%%%%
%Start of code%
%%%%%%%%

%
%Initialize the input and target vectors
%
p = zeros(16,20001);
t = zeros(26,20001);

%
%Fill the input and training vectors from the dataset provided
%
for i=2:20001
    for k=1:16
        p(k,i-1) = data(i,k);
    end
    t(data(i,17),i-1) = 1;
end

net = newff(minmax(p),[21 26],{'logsig' 'logsig'},'traingdm');

y1 = sim(net,p);

net.trainParam.epochs = 200;
net.trainParam.show = 1;
net.trainParam.goal = 0.1;
net.trainParam.lr = 0.8;
net.trainParam.mc = 0.2;
net.divideFcn = 'dividerand';
net.divideParam.trainRatio = 0.7;
net.divideParam.testRatio = 0.2;
net.divideParam.valRatio = 0.1;

%[pn,ps] = mapminmax(p);
%[tn,ts] = mapminmax(t);

net = init(net);
[net,tr] = train(net,p,t);

y2 = sim(net,pn);

%%%%%%%%
%End of code%
%%%%%%%%

现在来说我的问题:我希望我的输出如描述一样,即例如y2向量的每个列应该是一个字母的表示。然而我的代码并没有做到这一点。相反,它产生了在0和1之间大幅变化的结果,值从0.1到0.9不等。
我的问题是:我需要进行某些转换吗?也就是说,我是否需要将我的输入和/或输出数据转换为一种形式,以便我可以实际上看到我的神经网络是否正在正确地学习?
任何意见都将不胜感激。
4个回答

2

这是正常现象。你的输出层使用了一个log-sigmoid转换函数,它总会给你一些介于0和1之间的中间输出。

通常情况下,你需要寻找具有最大值的输出,也就是最可能的字符。

这意味着,对于y2中的每一列,你需要查找包含该行中最大值的行的索引。可以按以下方式计算:

[dummy, I]=max(y2);

I 是一个向量,包含每一行中最大值的索引。


Martin,感谢您的回复。使用max(y2),我现在至少可以获得有关网络正确识别字母的次数的一些信息。然而,在提供数据之前,我所做的是将其缩小,以便0<=p(x)<=1。由于p的最小值为0,最大值为15,因此我制作了一个新的输入向量scaledp = p/15。 - sp.
你不应该使用max作为活动函数,因为你的误差函数应该定义在活动上而不是激活上,而且max是不可微分的,这意味着你不能使用反向传播。你需要使用softmax,见下面我的答案。 - Ben Allison

1

你可以将y2视为每个输入是26个字母字符之一的输出概率分布,例如如果y2的一列如下所示:

.2
.5
.15
.15

如果我们假设只有4种可能的输出,那么这个字符是B的概率为50%。



==备注==

NN的输出层由26个输出组成。每次NN接收到像上面描述的输入时,它应该输出一个1x26向量,其中除了对应于输入值所代表的字母的那个单元格之外,其他所有单元格都包含零。例如,输出[1 0 0 ... 0]将是字母A,而[0 0 0 ... 1]将是字母Z。

最好避免使用目标值0和1来编码网络的输出。
避免使用0和1作为目标值的原因是,'logsig' Sigmoid转移函数不能在有限权重下产生这些输出值。如果您尝试训练网络以完全匹配目标值0和1,则梯度下降将强制权重无限增长。
因此,不要使用0和1值,而是尝试使用例如0.04和0.9的值,使得[0.9,0.04,...,0.04]是字母A的目标输出向量。


参考资料:
Thomas M. Mitchell, Machine Learning, McGraw-Hill Higher Education, 1997, p114-115


我认为那不正确。输出向量的每个元素将具有在0.00和1.00之间变化的值,但任何列的总和(或该列中的任何元素)实际上都不会表示百分比。 - sp.
y2Normalized = y2 ./ repmat(sum(y2), 26, 1) - Amro
或者,您可以使用y2中最高值与次高值之间的差异作为预测置信度的度量。 - Amro
除非您使用概率神经网络,否则它绝对不是概率分布。根据您使用的算法以及训练方式,它甚至不是置信度值。 - markwatson

1
  1. 在输出层中使用 hardlin fcn
    1. 使用 trainlmtrainrp 训练网络。
    2. 为了学习您的网络,使用一个 for 循环和一个条件来比较输出和目标。当它是最好的时候,使用 break 退出学习循环。
    3. 使用除 mapminmax 之外的另一种方式对数据集进行预处理。

0

我不知道这是否构成了一个真正的回答:但是这里有一些评论。

  • 我不理解你的编码方案。如何将“A”表示为那组数字?看起来你陷入了一个常见的陷阱,使用任意数字来编码分类值。不要这样做:例如,如果'a'是1,'b'是2,'c'是3,那么你的编码隐含地表明'a'更像'b'而不是'c'(因为网络具有实值输入,序数属性很重要)。正确的方法是将每个字母表示为26个二进制值的输入之一,只有一个处于活动状态,表示该字母。
  • 你的输出是正确的,输出层的激活永远不会是0或1,而是实数。你可以将最大值作为你的活动函数,但这是有问题的,因为它不可微分,所以你不能使用反向传播。你应该将输出与softmax函数相结合,使它们的总和为1。然后,你可以将输出视为给定输入的条件概率,如果你愿意的话。虽然网络并不是显式概率的,但是通过正确的活动和激活函数,它的结构将与对数线性模型完全相同(可能具有对应于隐藏层的潜在变量),人们经常这样做。

请参考David Mackay的教科书,了解神经网络的简介及其与概率之间的联系。同时,也可以看一下Geoff Hinton小组的这篇论文,详细了解关于正确表示和激活/活跃函数的预测下一个字符的任务(但要注意他们的方法非常复杂,并且使用了不同的训练方法来实现递归网络)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接