使用one-vs-all初始手写字母识别
数据特点
- 每一个图片都是20 x 20的像素矩阵,但是在输入的样本中是一个1 x 400的向量,标签y在{0, 1, 2, ..., 9}之间取值
- 共有5000个训练样本
可视化数据
- 从5000个样本中随机的挑选出100个训练样本进行可视化
- 得到的100个样本中,每一个样本都是一个向量,要想对其可视化,需要将其从向量还原为原始的矩阵
- 首先确定矩阵的高和宽(单位是像素pixel)
- 创建一个displayArray矩阵,用来保存100个样本转换为矩阵的像素数据,形象地讲,就是将100个图片放到一个大的面板上,这样才能做到可视化数据
- 初始完毕displayArray矩阵之后,使用matlib中的imagesc函数将其显示出来
- 代码如下:
- myDisplayData.m
function [h, displayArray] = myDisplayData(X)
% 获取一张图片的高和宽
exampleHeight = round(sqrt(size(X(1, :), 2)));
exampleWidth = round(size(X(1, :), 2) / exampleHeight);
% 计算整个面板的高和宽(但是是图片的个数)
[m, n] = size(X);
displayRows = round(sqrt(m));
displayCols = round(m / displayRows);
% 先创建出displayRows * exampleHeight, displayCols * exampleWidth的面板
displayArray = ones(displayRows * exampleHeight, displayCols * exampleWidth);
% 将图片放到面板对应的位置上
% 下面的式子就和数学有一些关系,如何确定现在填充的矩阵在displayArray中的位置
currExample = 1;
for i = 1:displayRows
for j = 1:displayCols
displayArray(...
(i - 1) * exampleWidth + 1:exampleWidth + (i - 1) * exampleWidth, ...
(j - 1) * exampleHeight + 1:exampleHeight + (j - 1) * exampleHeight ...
) = ...
reshape(X(currExample, :), ...
exampleHeight, exampleWidth);
currExample = currExample + 1;
end
end
colormap(gray);
h = imagesc(display_array);
axis image off;
end
数据预处理
- 为X添加bias(偏移量): X = [ones(m, 1), X]; % m表示样本的数量
- m: 训练样本的数量
- n: 特征的数量,不包括bias(偏移)特征
- y: 标签,{0, 1, 2, ..., 9}
- numLabel: y可以取的值的个数,这里为10
确定假设函数
- 由题目可知,这是一个典型的Multi-Class Logistic Regression问题,因此使用逻辑回归模型
- 模型函数: $$h( heta)=g( heta{T}x)={{1}over{1+e{- heta^{T}x}}}$$
- 因为这个一个10分类的问题,所以需要拟合出10个假设函数才行,也就是要最小化出10个( heta)向量,我们调用oneVsAll函数返回的参数应该是一个矩阵,每一个行向量是一个类别的假设函数的参数
计算损失函数(cost function)和梯度
- 损失函数公式: $$J( heta)={{1}over{m}}sum_{i=1}m(-y{(i)}log(h_{ heta}(x^{(i)})) - (1-y{(i)})log(1-h_{ heta}(x{(i)})))+{{lambda}over{2m}}sum_{j=1}m{ heta_{j}2}$$其中( heta), (y^{(i)}), (x^{(i)})为向量或者矩阵,后一项是对非偏差项的正则化
- 梯度公式: j >= 1 $${{partial}over{partial} heta_{j}}J( heta)={{1}over{m}}sum_{i=1}m{(h_{ heta}(x{(i)})-y{(i)})x{(i)}} + {{lambda}over{m}} heta_{j}$$ j = 0 $${{partial}over{partial} heta_{0}}J( heta)={{1}over{m}}sum_{i=1}m{(h_{ heta}(x{(i)})-y{(i)})x{(i)}}$$
- 注意,上面的(h_{ heta}(x^{(i)}))是sigmoid函数,自己在实现的时候总是将其写成线性回归函数
在oneVsAll.m文件中实现(minimize_{ heta}J( heta))
-
每一个类都进行梯度下降,计算出这一类的参数,也就是写一个循环,在每一个循环中都有可以得到最终的这个类别对应的参数,循环的次数为numLabels
-
核心代码
for index = 1:numLabels initialTheta = zeros(n + 1, 1); options = optimset('GradObj', 'on', 'MaxIter', 50); % fmincg会自动选择最优的学习率alpha allTheta(index, :) = fmincg(@(t)(lrCostFunction(t, X, (y == index), lambda)), ... initialTheta, options);
end
## 预测
+ 输入的一个样本,需要为其添加bias值,在将样本分别输入到10个假设函数中,计算出最大的值,那个值对应的就是类别。
+ 核心代码
```matlib
tmp = zeros(m, num_labels);
for i = 1:num_labels
tmp(:, i) = sigmoid(X * allTheta(i, :)');
end
[val, p] = max(tmp, [], 2);