题目要求
题目给出了5000张像素为400的图片,都为手写的1到10,要求用这些图片作为训练集,能识别其他的手写数字。用逻辑回归实现多分类和神经网络实现。
刚开始听到用像素点做识别还觉得挺不可思议的,以为识别用的都是先用梯度识别轮廓然后归类这种。但看完代码的实现过程,是把每个像素作为特征。想想实际上写数字,同样的图片大小,基本写的区域也差不多,有笔迹的区域应该也差不多,做回归预测理论上也可行,却没想到可以达到95%这么高的正确率。
有个疑问是所给数据中X矩阵存的像素数据是【-1,1】的值,是把灰度值归一到这个区间上吗,而且具体值的意义不大?只要知道这个区域有没有笔迹不就好了?或许这个值和落笔轻重也有关系?不管怎么说,带进去回归能出来就是了
一、多类logistic回归实现
总体思路
首先利用公式给出J(seita)和梯度的表达式,调用fmincg函数直接用高级优化给出训练的结构。注意在调整seita参数的值时,是用一个for循环,对1到10十个数分别进行识别(0或1),优化出10组seita集合,即 是n的时候有一组对应的seita集合使输出为1(n为1到10任意值)。
预测的过程就是把输入和10各seita集相乘,找出其中输出最大的一个seita集对应的数字即可(也就是对应概率最大的,sigmoid函数的输出就是概率)
关于公式使用
要注意sigmoid函数和线性回归虽然J(seita)求偏导的表达式相同(推出来相同而已,可认为是偶然),但其中h函数不一样,J(seita)不一样。
二、神经网络实现(前馈传播)
是一个3层神经网络,要求使用所给权重进行预测
由于图像大小为20×20,因此我们有400个输入层单元(不包括总是输出+1的额外偏置单元),第二层有25个单元和10个输出单元(对应于10个数字类别)
题目中已经给出了seita,所以关键的调seita矩阵的工作就不需要我们做了,只需要根据他们的关系一层层往后变换就可以了,所以J,grad也不用求,算是学反向传播前的代码铺垫。
其实就是逐步映射将特征逐渐减少,最后变成10个输出,然后给任何一个图片就可以根据它的401个特征输出10个特征,看
X = [ones(m,1) X];
a2 = sigmoid(X*Theta1');%5000x401乘以401x25得到5000x25。即把401个feature映射到25
a2 = [ones(size(a2,1),1) a2];
a3 = (sigmoid(a2*Theta2'));%5000x26乘以26x10得到5000x10。即把26个feature映射到10
[c, p] = max(a3, [], 2);
三、反馈神经网络的整体实现
关于代码的一些记录
1、图片数据是存储在ex3data1.mat中的,运行如下代码之后会生成X和y两个变量
load('ex3data1.mat'); % training data stored in arrays X, y
有5000张图,每张图有400个像素点,也就是400个特征,X中存储图片的灰度强度(但是不知道为什么值好像都是-1到1的值,归一化到-1,1?);y中是图片对应的数值1到10
matlab批量图片导出图片大小,MATLAB实例:将批量的图片保存为.mat文件.
MATLAB将批量的图片保存为mat文件.
2、随机显示所有图片中的100张
randperm(m)函数把1到m的m个数打乱顺序
% Randomly select 100 data points to display
rand_indices = randperm(m);%把1到m这些数随机打乱得到的一个数字序列
sel = X(rand_indices(1:100), :);
displayData(sel);
3、关于矩阵运算
3.1为了运算生成的新y
h = eye(10);%10*10
y = h(y,:);%y原来是5000*1 !!!.y矩阵中的数是对应的行数
最后生成的y是5000*10,前500行为第十列全1,第二个500行为第1列全为1,第三个500行为第2列全为1
3.2算代价函数J的时候用了矩阵的点乘(两个矩阵维度相同时可用)
J = sum(sum(-y.*log(a3) - (1-y).*log(1-a3)))/m;
注意sum是按列求和
注意之前的J是直接矩阵相乘即可,而这里神经网络的公式中有两层求和,需要使用 “矩阵点乘,sum,再sum” 的方式计算。 如果使用矩阵相乘省略一层sum,结果会出错。
3.3矩阵求和
补:上面举例的sum(A)是对列求和,但是当sum中的矩阵是一个向量时就是其中的数相加。如sum([4,2])=6,所以最后J求出来才是一个数值
3.4矩阵操作
参考ch2 Matlab矩阵的生成与运算.内容很全
data = rand(4,4) %初始化1个[0,1]的4*4的随机矩阵
a = data(:,1) %取data的所有行,第1列
b = data(:,[1,3]) %取所有行,第1,3列
c = data([2,3],[1,2]) %%取第2,3行,以及1,2列
data(:) 就是把矩阵的元素按列的顺序变为一列,矩阵转化为向量
矩阵的删除
4、求准确率的方法
注意其中pred 和 y是两个矩阵,通过计算矩阵中有多少对应元素相等来算准确率。
fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100);%求准确率的方法
5、关于出现的“…",是换行用的
%以下两种函数表达方式相同,加...是因为换行,对应中文的句号“。”
% function [J grad] = nnCostFunction(nn_params, ...
% input_layer_size, ...
% hidden_layer_size, ...
% num_labels, ...
% X, y, lambda)
function [J grad] = nnCostFunction(nn_params, input_layer_size,hidden_layer_size, num_labels,X, y, lambda)
6、randperm
将一列序号随机打乱,序号必须是整数。
sel = randperm(m);% 是把1到n这些数随机打乱得到的一个数字序列。
randperm(100,5)
ans =
91 37 11 76 38
这个意思是将前100个数中,随机选择5个。所以randperm(n,m)中,n一定大于等于m。