其他博客的优秀分享:编程作业(python)| 吴恩达 机器学习(3)多分类与神经网络
2020/03/23
总结:
- 逻辑回归的多分类:0~9。对每一类和标签,计算最优的参数,计算得到10组最优参数θn*10
- 采用的模型仍然是简单的线性模型:
计算得到的该样本为正样本的概率,因此从10个模型
中选择概率最大的那个,就完成了识别
- 系统引入非线性可以大大提高性能,但是前述的简单线性模型虽然可以通过多项式引入非线性,其非线性的形式有限,且两两的二次多项式特征太多,计算量太大,冗余也会很多,因此需要更加强大的非线性分类器——神经网络
- 神经网络的代价函数:前向传播 forward propagation
- 神经网络的偏导数:反向传播 Backpropagation
- 误差的反向传播理解
- 向量化代码的书写
- 随机初始化的重要性,打破对称性
- 梯度检验
for c = 1:num_labels
all_theta(c,:) = fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), ...
initial_theta, options);
end
% all_theta的每行为训练好的向量,sigmoid为样本为1的概率,因此取所有中概率最大的那个
[a,p] = max(sigmoid( X * all_theta'),[],2) ; % 返回每行最大值的索引位置,也就是预测的数字
mean(double(p == y)) * 100
1、多分类
在本练习中,您将实现一个one-vs-all Logistic回归和神经网络来识别手写数字。 在开始编程练习之前,我们强烈建议大家观看 视频讲座和完成相关主题的复习问题。 对于这项练习,您将使用Logistic回归和神经网络来识别手写数字(从0到9)。 自动手写数字识别在今天被广泛使用-从识别开始邮政编码(邮政编码)在邮件信封上确认金额写在银行支票上。 本练习将向您展示您所学到的方法如何用于此分类任务。 在练习的第一部分中,您将扩展您先前对Logistic回归的实现,并将其应用于单vs-all分类。
在ex3data1.mat中给您一个数据集,其中包含5000个手写数字的训练示例(MNIST)。 在ex3data1.mat中有5000个训练示例,其中每个训练示例都是数字的20像素乘20像素灰度图像。 20×20的像素网格被“展开”成一个400维向量。 这些训练示例中的每一个都成为我们数据矩阵X中的一行。 这就是我们一个5000乘400矩阵X,其中每一行都是手写数字图像的训练示例。
训练集的第二部分是包含训练集标签的5000维向量y. 因此,“0”数字被标记为“10”,而数字“1”到“9”则按其自然顺序标记为“1”到“9”。
randperm(m)生成m个[1,m]的随机数
注意display_array的索引的书写:经常用到的二维矩阵的索引。
% 可视化数据的代码
load('ex3data1.mat'); % training data stored in arrays X, y
m = size(X, 1);
% Randomly select 100 data points to display
rand_indices = randperm(m); % change the order -jin
sel = X(rand_indices(1:100), :); % 选取随机的100个样本
% Gray Image
colormap(gray);
example_width = round(sqrt(size(X, 2)));% 获取图像长/宽 默认相等
% Compute rows, cols
[m n] = size(X);
example_height = (n / example_width);
% Compute number of items to display
display_rows = floor(sqrt(m));
display_cols = ceil(m / display_rows);
% Between images padding
pad = 1;
% Setup blank display 用黑色的线分割开来:每行height行pad 1,每个width列pad 1
display_array = - ones(pad + display_rows * (example_height + pad), ...
pad + display_cols * (example_width + pad));
% Copy each example into a patch on the display array 把样本放进display矩阵中
curr_ex = 1;
for j = 1:display_rows
for i = 1:display_cols
if curr_ex > m,
break;
end
% Copy the patch
% Get the max value of the patch 获取最大值,并将每个样本归一化
max_val = max(abs(X(curr_ex, :)));
display_array(pad + (j - 1) * (example_height + pad) + (1:example_height), ...
pad + (i - 1) * (example_width + pad) + (1:example_width)) = ...
reshape(X(curr_ex, :), example_height, example_width) / max_val;
curr_ex = curr_ex + 1;
end
if curr_ex > m,
break;
end
end
% Display Image
h = imagesc(display_array, [-1 1]);
axis image off
drawnow;
1.1 矢量化的一对多逻辑回归
-
计算代价函数和导数,跟前面的逻辑回归是一样的。而且用的模型是简单的线性模型:
,且加入正则化。
- 如果我们有非常多的特征,通过学习后的假设可能很好的适应了训练集,但可能无法推广到新的数据。如果存在过拟合,该如何处理?
- 丢弃一些不重要的特征,不利于正确预测的特征。如PCA
- 正则化,保留所有的特征,但是减小参数的magnitude大小,减小它的重要程度。
- θ的正则化参数λ越小,对模型的惩罚越小,限制就越小,模型将更复杂。
- θ的正则化参数λ越大,对模型的惩罚越大小,限制就越多,模型将更简单,更平滑,就不易过拟合。
- 我们有非常多的特征,但是不知道该惩罚哪一个,因此全都惩罚,并让最优化算法来选择惩罚的程度 即 λ
- 为什么增加一项后可以使得θ的值减小呢?
- 因为令λ的很大的话,要减小cost fuction,就只能减小θ的值
- 加入正则化后:
temp=[0;theta(2:end)]; % 先把theta(1)拿掉,不参与正则化
J= -1 * sum( y .* log( sigmoid(X*theta) ) + (1 - y ) .* log( (1 - sigmoid(X*theta)) ) ) / m + lambda/(2*m) * temp' * temp ;
grad = ( X' * (sigmoid(X*theta) - y ) )/ m + lambda/m * temp ;
- 对每一类数字0-9分别进行训练,那么给出的y为0~9的标签就是 y==k,这样给出0/1的标签。 对每一类计算最优的线性逻辑回归参数θ,就是我们训练出的模型。
%% Setup the parameters you will use for this part of the exercise
input_layer_size = 400; % 20x20 Input Images of Digits
num_labels = 10; % 10 labels, from 1 to 10
% (note that we have mapped "0" to label 10)
lambda = 0.1;
m = size(X, 1);
n = size(X, 2);
% You need to return the following variables correctly
all_theta = zeros(num_labels, n + 1);
% Add ones to the X data matrix
X = [ones(m, 1) X];
options = optimset('GradObj', 'on', 'MaxIter', 50);
initial_theta = zeros(n + 1, 1);
for c = 1:num_labels
all_theta(c,:) = fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), ...
initial_theta, options);
end
- 利用训练出的模型(参数θ)去计算训练集中的准确率
m = size(X, 1);
num_labels = size(all_theta, 1);
% You need to return the following variables correctly
p = zeros(size(X, 1), 1);
% Add ones to the X data matrix
X = [ones(m, 1) X];
% all_theta的每行为训练好的向量,sigmoid为样本为1的概率,因此取所有中概率最大的那个
[a,p] = max(sigmoid( X * all_theta'),[],2) ; % 返回每行最大值的索引位置,也就是预测的数字
mean(double(p == y)) * 100
Training Set Accuracy: 94.960000
2、神经网络
线性回归和逻辑回归大多数都是线性分类器,但是在实际应用中,非线性才是最重要的,虽然线性回归和逻辑回归都可以通过构造多项式的方法来引入非线性,但是必定有限。下面引入更加强大的非线性分类器学习算法。
2.1 非线性假设
非线性引入系统十分重要,能够大大提高系统的性能。如果特征非常多,eg:100,想要构造非线性,如多项式,仅仅构造100个特征的二次多项式,两两的乘积,就会有5000个特征,这在计算时计算量非常大。此时,我们用神经网络来构造非线性,并快速求解。
Coursera吴恩达机器学习课程 总结笔记及作业代码——第4周神经网络
-
上层是一个三层神经网络,第一层为输入层,第二层为隐藏层,第三层为输出层。每条边上有一个权值θ,则第二层表示为:
,这只是个对一个样本
的表示,对整个样本集X进行表示,则如下:
设X样本集表示如下,每行为一个样本,则。
- 其实神经网络就像是逻辑回归,
,只是输入变成了
,这个是与样本X有关的更高级的特征/进化体。
- 这些更高级的特征比多项式厉害,也就能更好的预测新数据,这就是神经网络比逻辑回归和线性回归的优势。
- 优势:引入更好的非线性!
- 第二层就是神经网络通过对输入X学习后自己得到的新特征
2.2 Examples and intuitions
利用sigmoid函数和{0,1}输入,实现与逻辑和或逻辑。与:,或:
,非:
同或:x1 XNOR x2 = (x1 & x2) | (~x1 & ~x2)
通过这样的方法可以逐渐构造出越来越复杂的函数,得到原来越厉害的特征值,这就是神经网络的厉害之处。
2.3 多类分类
输出有四个维度,表示人、汽车、摩托车、卡车。
2.4 神经网络的代价函数
- 有m个样本,L层神经网络,每一层有sl个神经元,输出可以是二分类或者多分类。逻辑回归中只有一个输出变量,而神经网络是维度为K的向量。
- 对于每行的特征,给出K个预测,然后选择一个可能性最高的,与y做比较。
- 正则化项是除去每层的θ0后,每一层的θ矩阵的和。l-每一层,j-下一层的神经元个数,i-上一层的神经元个数
2.5 反向传播——为了计算代价函数的偏导数
这部分理解起来比较困难:吴恩达机器学习:神经网络 | 反向传播算法
前面我们有了神经网络的代价函数J(θ),我们需要计算J(θ)的偏导数才能进行最优化计算出所有的参数θ。
- 为了计算出偏导数,我们需要搭建一个跳板,就是误差
- 同时对这个误差进行反向传播,就可以得到J(θ)的偏导数
- 中间变量Z很重要,必不可少
我们定义误差函数为:,对于输出层的误差计算: 对于其它层的误差计算:
- 误差的跳板已经有了,下面推导和计算J(θ)的偏导数
- 理解神经网络的误差和反向传播
2.6 展开参数
由于fminunc需要的导数和初始参数θ都是向量,而此处神经网络由于是一对多的多输出模型,因此θ和偏导数都是n*10(特征个数*分类类数)的矩阵,不再是向量。此时,如何取出这些矩阵并展开成向量?
先把所有的θ首尾相连成一个列向量,,然后送入fminunc中进行优化,然后再从θ中重构出,θ1,θ2...同样的将梯度矩阵D也变成一个很长的向量DVec。从向量表达转回为矩阵表达,就是reshape即可。
如何应用于学习算法呢?将这个长向量θ作为初始initialTheta输入fminunc,同时也将这个长向量thetaVec输入代价函数。由于fminunc需要长向量,而costFunction需要参数矩阵,因此需要reshape回参数矩阵,再进行前向传播和反向传播,计算导数和代价函数。并且代价函数要和θ一样展开成同顺序的长向量。
-
fminunc高级优化需要导数gradient和参数矩阵都是列向量
-
而costFunction的计算需要是参数矩阵,因此需要从矩阵到向量的一个转换。
在使用复杂模型如神经网络时,计算导数和反向传播都是具有很多细节的算法,在实现的时候会有点复杂;同时,实现反向传播时会遇到很多细小的错误。优化时看起来每次迭代代价函数都在减小,即使遇到一些小错误,看起来J(θ)都在减小,但最后得到的神经网络误差总是高于无误差的网络。
-
需要梯度检验这个工具:帮助确定前向传播和反向传播时100%正确的,代码可能会出错
-
即利用左右差分近似估计该点处的导数:并对所有的θ都估计,我们计算出的DVev应该与该值近似
-
就是正向传播的方式计算导数,但是这样会比较慢,所以我们使用反向传播的方式更高效地求解导数。但可以用来验证反向传播是否写对了。
2.7 随机初始化
如果所有初始化参数θ都是0,即所有的权重都是0。打破梯度对称性!
-
这样来自于前一层的所有权重都是零,得到的a(2)1=a(2)2,因为权重都是一样的,那么对于每一层而言,其输入都是相同的。
-
由于权重都是相同的,且输入都是相同的,当误差在反向传播时,其权重也是相同的,由误差公式可能,误差也是相同的。
-
由导数公式可得,偏导数也是相同的,所以对于θ的更新,也是相同的。然后再次迭代。
-
这就意味着所有的隐藏单元都在计算相同的特征,所有的隐藏单元都使用相同的输入函数,就造成了高度冗余。最后的逻辑单元只会得到一个结果,因为所有的10个逻辑单元的结果都一样。
-
所以随机化为接近0的
内的随机数,然后再进行反向传播,再进行梯度检验。
2.8 总结
- 搭建神经网络:总共多少层,每层多少个单元?
- 输入层由特征个数决定,输出层由分类类数决定
- 隐藏层的层数和单元数该怎么确定呢?一般只选择一个隐藏层,也是最常见的。若使用多个隐藏层,一般每层的单元数是一样的,如3 5 5 4的结构,
- 虽然隐藏层的单元数越多越好,但是计算量也会很大。
训练神经网络的步骤:
这里最好是对每一个样本进行循环计算,计算出误差项delta(l)和激活值activations(a(l))。
神经网络的代价函数J(θ)是一个非凸函数,因此理论上是能够停留在局部最小值的位置。实际上 梯度下降算法和其他一些高级优化方法理论上都能收敛于局部最小值。但一般来讲,这个问题并不要紧,尽管我们不能保证这些优化算法一定能得到全局最优,但通常梯度下降这类算法在最小化代价函数J(θ)的过程中还是表现得很不错的,通常能够得到一个很小的局部最小值。
反向传播算法能够很好的让更复杂,维度更大,非线性的函数模型更高的拟合我们的数据。因此是最为高效的学习算法。
%% Setup the parameters you will use for this exercise
input_layer_size = 400; % 20x20 Input Images of Digits
hidden_layer_size = 25; % 25 hidden units
num_labels = 10; % 10 labels, from 1 to 10
% 假定已经求出了最优参数 Theta1, Theta2.
X = [ones(m, 1) X];
a2 = sigmoid(X * Theta1'); % 第二层激活函数输出
a2 = [ones(m, 1) a2]; % 第二层加入b,偏置
a3 = sigmoid(a2 * Theta2');
[aa,p] = max(a3,[],2); % 返回每行最大值的索引位置,也就是预测的数字
Training Set Accuracy: 97.520000
代码原理:
样本集矩阵如下,每行为一个新样本。
,
,
因此,,右侧的列向量为一个样本,由于样本集X为行向量,所以θ参数矩阵需要转置!