Main Content

字符识别

此示例说明如何训练神经网络以执行简单的字符识别。

定义问题

脚本 prprob 定义了一个包含 26 列的矩阵 X,每列对应一个字母。每列有 35 个值,值可能是 1,也可能是 0。每列(包含 35 个值)定义一个字母的 5×7 位图。

矩阵 T 是一个 26×26 的单位矩阵,它将 26 个输入向量映射到 26 个类。

[X,T] = prprob;

以下命令将第一个字母 A 绘制为一个位图。

plotchar(X(:,1))

创建第一个神经网络

为求解此问题,我们将使用针对模式识别建立的具有 25 个隐藏神经元的前馈神经网络。

由于神经网络以随机初始权重进行初始化,因此每次运行该示例进行训练后的结果都略有不同。为了避免这种随机性,请设置随机种子以便每次都重现相同的结果。这对于您自己的应用情形不是必需的。

setdemorandstream(pi);

net1 = feedforwardnet(25);
view(net1)

训练第一个神经网络

函数 train 将数据划分为训练集、验证集和测试集。训练集用于更新网络,验证集用于在网络过拟合训练数据之前停止网络,从而保持良好的泛化。测试集用作完全独立的测量手段,用于衡量网络针对新样本的预期表现。

当网络针对训练集或验证集不再可能有改善时,训练停止。

net1.divideFcn = '';
net1 = train(net1,X,T,nnMATLAB);
 
Computing Resources:
MATLAB on GLNXA64
 

训练第二个神经网络

我们希望网络不仅可以识别形状标准的字母,还可以识别含噪的字母。因此,我们将尝试针对含噪数据训练第二个网络,并将其泛化能力与第一个网络进行比较。

以下命令为每个字母 Xn 创建 30 个含噪副本。值由 minmax 限制在 0 和 1 之间。还定义了相应的目标 Tn

numNoise = 30;
Xn = min(max(repmat(X,1,numNoise)+randn(35,26*numNoise)*0.2,0),1);
Tn = repmat(T,1,numNoise);

以下是 A 的含噪版本。

figure
plotchar(Xn(:,1))

以下命令将创建并训练第二个网络。

net2 = feedforwardnet(25);
net2 = train(net2,Xn,Tn,nnMATLAB);
 
Computing Resources:
MATLAB on GLNXA64
 

测试两个神经网络

noiseLevels = 0:.05:1;
numLevels = length(noiseLevels);
percError1 = zeros(1,numLevels);
percError2 = zeros(1,numLevels);
for i = 1:numLevels
  Xtest = min(max(repmat(X,1,numNoise)+randn(35,26*numNoise)*noiseLevels(i),0),1);
  Y1 = net1(Xtest);
  percError1(i) = sum(sum(abs(Tn-compet(Y1))))/(26*numNoise*2);
  Y2 = net2(Xtest);
  percError2(i) = sum(sum(abs(Tn-compet(Y2))))/(26*numNoise*2);
end

figure
plot(noiseLevels,percError1*100,'--',noiseLevels,percError2*100);
title('Percentage of Recognition Errors');
xlabel('Noise Level');
ylabel('Errors');
legend('Network 1','Network 2','Location','NorthWest')

由于存在噪声,在无噪声情况下训练的网络 1 的错误数多于在有噪声情况下训练的网络 2。