监督学习模型描述
学习算法通过训练集得到一个假设函数h,h接收输入可以得到一个输出。
列如:
已知房子大小与对应的价格,通过学习算法驯良可以得到一个假设函数
h
h
h:
h
=
θ
0
+
θ
1
x
h=\theta_0+\theta_1x
h=θ0+θ1x
设x为房子大小,
h
h
h所得到值即为房价。通过训练集的学习确定假设h的两个系数。
代价函数
对于我们的假设函数h,需要定义一个标准来表明假设所得值与真实值之间的误差,通常我们用平方误差来表明误差,这个我们记为代价函数
J
J
J
代价函数是所有样本误差的平均。
J
(
θ
0
,
θ
1
)
=
1
2
m
∑
i
=
1
m
(
h
(
x
i
)
−
y
i
)
2
J(\theta_0,\theta_1)=\cfrac{1}{2m}\sum_{i=1}^m(h(x^i)-y^i)^2
J(θ0,θ1)=2m1i=1∑m(h(xi)−yi)2
综上,我们要找到一对系数
θ
0
,
θ
1
\theta_0,\theta_1
θ0,θ1来使得代价函数
J
J
J最小
梯度下降(Bath梯度下降)
- 给定 θ 0 , θ 1 \theta_0,\theta_1 θ0,θ1初始值,一般都直接设为0
- 更改 θ 0 , θ 1 \theta_0,\theta_1 θ0,θ1以减小 J ( θ 0 , θ 1 ) J(\theta_0,\theta_1) J(θ0,θ1)
(注意:梯度下降可能会使得代价函数位于局部最低值,而不是最小值)
更改系数的方法是利用偏导数来进行。
重复直至收敛{
θ
j
=
θ
j
−
α
∂
∂
θ
j
J
(
θ
0
,
θ
1
)
\theta_j=\theta_j-\alpha\cfrac{\partial}{\partial\theta_j}J(\theta_0,\theta_1)
θj=θj−α∂θj∂J(θ0,θ1)}
其中
θ
j
\theta_j
θj为各个系数,这个问题中的
j
=
0
,
1
j=0,1
j=0,1,
α
\alpha
α为学习率,控制梯度下降的速度,如果
α
\alpha
α过小,会导致迭代速度慢,
α
\alpha
α过大会导致无法收敛,因为学习率太大,每次都会越过最低点。
如上图,横坐标相当是系数
θ
0
,
θ
1
\theta_0,\theta_1
θ0,θ1的综合效应,纵坐标为代价函数
J
(
θ
0
,
θ
1
)
J(\theta_0,\theta_1)
J(θ0,θ1)。当前为A点,原本应该会被下降到B点,可是由于学习率过大导致越过了B点到达了C点。
学习率适当不是说取0.5(刚开始时我选择了0.5)正常情况下为0.1,0.03,0.01,0.003,0.001…
数据拟合
我们先将老师提供的数据画出来
clear;
clc;
data=load('ex1data1.txt');
size=data(:,1)';
price=data(:,2)';
figure(1);
plot(size,price,'o');
title('训练集');
xlabel('房子大小');
ylabel('房价')
通过拟合获取函数
clear;
clc;
%%
%画出原始图像
data=load('ex1data1.txt');
size=data(:,1)';
price=data(:,2)';
figure(1);
plot(size,price,'o');
title('训练集');
xlabel('房子大小');
ylabel('房价')
%%
%拟合函数
syms h J k0 k1 f0 f1;%定义变量
h=k0+k1*size;%定义假设函数h
J=sum((h-price).^2)/(2*length(size));%定义代价函数J
f0=diff(J,k0);%求得代价函数对k0的偏导
f1=diff(J,k1);%求得代价函数对k1的偏导
%初始化k0,k1
k0=0;
k1=0;
nowJ=subs(J);%记录当前代价
lastJ=2*nowJ;%记录之前代价
a=0.01;%学习率
while (lastJ-nowJ)/lastJ>=0.00001%当代价变动不大时即为收敛,退出循环
%获取新的k0,k1值
temp0=vpa(subs(k0-a*f0));
temp1=vpa(subs(k1-a*f1));
k0=temp0;
k1=temp1;
lastJ=nowJ;
nowJ=subs(J);%计算新的代价函数
end
disp([k0,k1])
x=(5:0.1:25);
y=k0+k1*x;
hold on;
plot(x,y,'-');
其中需要注意的是
θ
0
,
θ
1
\theta_0,\theta_1
θ0,θ1要同时改变,所以先用temp变量记录变换后的值,等到计算结束之后一起更改系数。
特征缩放
在多变量线性回归中,由于不同特征之间的数量级差别可能很大(比如说房子的大小和房间数)会导致代价函数h收敛较慢,所以需要对特征进行处理后使用
- 方法一 除以最大值
所有特征都除以他的最大值,这个方法在特征数据都是同号的时候能够将所有数据都缩放到[0,1]之间,方便收敛。 - 方法二 均值归一化
对于特征向量 x i x_i xi,由于有 θ 0 \theta_0 θ0的原因, x 0 x_0 x0要永远为1,而对于其他特征:
x i = x i − μ i s i x_i=\frac{x_i-\mu_i}{s_i} xi=sixi−μi
其中, μ i \mu_i μi是特征向量 x i x_i xi的平均值, s i s_i si是 x i x_i xi的范围, s i = m a x ( x i ) − m i n ( x i ) s_i=max(x_i)-min(x_i) si=max(xi)−min(xi)
学习率的选择与代价函数收敛的判断
学习率的选择
虽然学习率可以选择0.01,0.003,0.001…但是他们之间的差距任然很大,就上述数据而言,我选择的学习率为0.012,通过观察代价函数值与迭代次数的关系,我们可以选择学习率。
clear;
clc;
%%
data=load('ex1data1.txt');
size=data(:,1)';
price=data(:,2)';
%%
%拟合函数
syms h J k0 k1 f0 f1;%定义变量
h=k0+k1*size;%定义假设函数h
J=sum((h-price).^2)/(2*length(size));%定义代价函数J
f0=diff(J,k0);%求得代价函数对k0的偏导
f1=diff(J,k1);%求得代价函数对k1的偏导
%初始化k0,k1
k0=0;
k1=0;
nowJ=subs(J);%记录当前代价
lastJ=2*nowJ;%记录之前代价
a=0.012;%学习率
number=0;
J_va=zeros(1,1500);
while number~=1500%当代价变动不大时即为收敛,退出循环
%获取新的k0,k1值
temp0=vpa(subs(k0-a*f0));
temp1=vpa(subs(k1-a*f1));
k0=temp0;
k1=temp1;
lastJ=nowJ;
nowJ=subs(J);%计算新的代价函数
number=number+1;
J_va(number)=nowJ;
end
figure(2);
plot(1:number,J_va);
xlabel('迭代次数')
ylabel('代价')
title('代价随迭代次数而减小')
可以看出曲线非常平滑,这是一个比较好的学习率的结果,如果我们选择一个稍微小一点的,比如0.01
这个曲线很畸形,所以这个学习率并不是太好
代价函数收敛判断
方法一 代价函数变化率小
我们可以记录前一次代价函数的值,然后当前代价进行比较,当变化率小于某个值时退出循环
nowJ=subs(J);
lastJ=2*nowJ+1;
while (lastJ-nowJ)/lastJ>=0.0001%当变化率小于0.0001时退出循环
temp0=subs(k0-a*f0);
temp1=subs(k1-a*f1);
k0=temp0;
k1=temp1;
%更改记录的代价函数值
lastJ=nowJ;
nowJ=subs(J);
end
这种方法容易实现,但是却不一定准确。收到学习率的影响,变化率可能会一直大于某个数,这个阙值很难找到。
方法二
在上述我们确定学习率的时候,我们得到了学习率和迭代次数的关系图:
我们可以从这个图中可以得到代价函数在迭代多少次之后趋于收敛。如上图我们可以得知,当迭代次数大于约1200次时,函数趋于收敛。我们可以事先确定好迭代次数来进行数据分析。