机器学习的三要素
1.1. 模型
首先明确机器学习的主要任务:确定样本空间的输入x和输出y,及x和y之间找到一个f(x,) -> y。 的模型f(x,) ,且尽可能与输出y相匹配。一开始不知道这样的函数是什么样的,所以我们要g根据经验,假设有一个函数集合(f1,f2,f3,f4,f5……,fn),这样的假设函数集合有时候也成为假设空间,我们通过观察,这一系列函数,在训练集中的表现,来选取一个fi在训练集D中最理想,那么fi就是最适合的,或者说是最理想的假设。
我们常说的模型有:
- 线性模型: ,是一个参数化的线性函数族。
- 广义线性方法: ,其中 为可学习的非线性基函数,就等价于神经网络。
线性模型:w是一个权重向量,x是一个特征向量,w的转置与X相乘,得到一个值再与b相加即为当前模型下的预期值y^。
非线性模型:x经过一个非线性的函数,可以得到一个非线性的特征向量,而又是一个可以学习的非线性基函数,则可以再套一层非线性基函数。依次类推。
经过多层学习基函数后得到的向量,又可以作为新的输入x继续重新进行训练,这与全连接神经网络有异曲同工之妙。
1.2.1. 学习准则-损失函数。
我们有,训练集D,模型。现在将测试集放入模型 中得到一个结果y^,再拿预测值y^与真实值y作比较。而作比较的手段即学习准则。
通常思路是:得到所有预测值y^ 与 真实值y之间 的差值绝对值之和,我们要尽可能使这个和小于一定值,则满足要求。若是概率也是类似。
所以说我们要度量一个模型的好坏,需要引入一个期望风险(expected risk)的概念。期望的风险是一个数学期望。即 ,我们求的数学期望是Loss函数(损失函数)的期望。
损失函数有很多种类,如:
- 0-1损失函数:
数学性质不太好(倒数 = 0),所以我们需要一个连续可微的损失函数。如平方差损失函数
- 平方差损失函数:
平方损失函数一般用在结果为实值上,即连续的值,但不适合分类,即离散的值。一般会使用交叉熵损失函数(又称为负的对数似然函数 ,将实值之间的比较转换成概率值之间的比较)。
还有一种二分类损失函数Hinge:L= max(0 , 1 - y * y^),若y与y^相近则正负性相同,相乘为正,1 减去一个大于0 的数则 loss值相对较小。
1.2.2. 学习准则-参数学习
由以上可以得出,我们在寻找一个适合的模型,评判标准就是这个模型在数据集上有一个比较小的期望风险。期望风险是在训练集和测试集上共同的得到的风险加到一起。而我们只能在训练集上做这些预测,测试集的东西是未知的,因此期望风险是未知的,一般通过在一部分数据集上预测的结果即经验风险,来近似。
利用经验风险,在局部上逐步取得最优化:
经验风险最小化
- 在选择合适的风险函数后,我们寻找一个参数,使得经验风险最小化。
- 机器学习转化为一个最优化问题:
当在训练集上通过更新参数,不断最小化经验风险的方法,是一个不断拟合的过程。
- 过拟合:模型过于复杂,在训练集上训练的还行,在测试集不一定可以。一般由于数据少或者噪声的影响。
- 欠拟合: 在训练集上表现得不好,在测试集上也可能表现得不好。
因此我们需要找到一个中间的状态,如下图中的第二张图片。
增强泛化能力:
正则化后,模型适合更多数据,且降低模型复杂度,何为正则化,所有损害优化的操作都是正则化!有1.增强约束,如增加L1/L2约束,2.干扰优化过程,如提前终止优化。
梯度下降法
2.1. 原理及种类
我们之前提及,机器学习是一个最优化的问题,那最优化有何种途径呢?一个很直接的方法就是梯度下降法,逐步找到最小值。
图中曲线是一个凸函数(这里的凸函数与国内考研教材凸函数定义相反):,我们如何更新参数使得风险函数最小呢?
假设曲线中某一点的斜率(导数或偏导)为负数,那原来的就会减去一个负数,从而向右移动,即向使得风险函数更小的方向移动。相同的,假如该点斜率为正数,那么就会减去一个负数,就会往左移动。其中的是学习率。
学习率的取值也是一个很关键的因素,以下图片总结:
上面提到的是一个通过样本可学习的参数,不是我们定义的,通常模型的性质中会包含。而是我们定义的,这里是指一次学习速度的快慢,我们把这种自己定义的,与模型无关,但是在训练过程中又能对模型的训练起到至关重要作用的参数成为超参,像这样的参数还有网络的层数,聚类的个数,分类的个数等。
梯度下降法分为:
- 批量随机下降法(BGD):每个样本都要进行更新。
- 随机梯度下降法(SGD):每次都是取随机的对一个样本更新,对那种不完全是凸函数的模型有时会找到相对于批量随机下降法更好的参数。但不利于利用计算机的并行能力。
- 小批量的随机梯度下降法:随机取出其中的一堆,进行更新。
2.2. 随机梯度下降法(实战)
图片来源于网课截图。
import numpy as np
X = np.arange(0,50)
# RandomArray是 [-5,5)的噪声值
np.random.seed(1)#让每次取到的随机值都是一样的。
RandomArray = (np.random.random(50)*2-1)*5
y = 2 * X + RandomArray
import matplotlib.pyplot as plt
plt.scatter(X,y)
X = X.reshape(50,1)
y = y.reshape(50,1)
#把X,y连接起来,第一个值是特征值,第二个值是标签
All_date = np.concatenate((X,y),axis = 1)#默认的是第一个维度即按行,这里要按列
All_date #此时数据集完成!
np.random.shuffle(All_date)
train_date = All_date[:40]
test_date = All_date[40:]
np.sum(All_date[:,0] * 2 - All_date[:,1]) # 所有 x - y 值的和 后面的0,1 是维度。
# 超参初始化
lr = 0.001 #学习率
N = 100
epsilon = 195
randint = np.random.randint(0,40)#随机的一个索引。
rand_x = train_date[randint][0] # x值是第一个值,因此取 0
rand_y = train_date[randint][1] # y是第二个值,同理
#要学习的参数
theta = np.random.rand()
theta
#开始训练(核心代码)
Num = 1
theta_list = []
loss_list=[]
while True:
#重新排序
np.random.shuffle(train_date)
for n in range(N):
randint = np.random.randint(0,40)#随机的一个索引。
rand_x = train_date[randint][0] # x值是第一个值,因此取 0
rand_y = train_date[randint][1] # y是第二个值,同理
#先要计算梯度,在此基础上更新参数,
# 1.计算梯度
grad = rand_x * (rand_x *theta -rand_y)
# 2.更新参数theta
theta = theta - lr * grad
#计算更新theta后的错误率
X = train_date[:,0]#同下。
y = train_date[:,1] # 是不是应该用测试集??
loss = np.sum(0.5*(theta*X -y)**2)
print("Number: %d,theta %f loss: %f"%(Num,theta,loss))
Num = Num + 1
theta_list.append((theta))
loss_list.append(loss)
if loss < epsilon :
break
# 画图
plt.plot(range(len(theta_list)),theta_list)
plt.plot(range(len(loss_list)),loss_list)
线性回归
之前的模型x即特征只有一种,但一般情况肯定不会只有一种,当样本维度为1时,我们成为简单回归(左图);当特征有很多个的时候,即x有很多维度时,我们就说他是多元回归(右图)。
- 模型:
- 增广权重向量:
- 增广特征向量:
( 2和3共同组成了 。)
优化方法:
- 实值:经验风险最小化,结构风险最小化。
- 概率值: 最大似然估计值,最大后验估计。
3.1. 经验风险最小化-最小二乘法:
- 模型:
- 学习准则:损失函数可以用平方差函数。只在训练集上训练,即经验风险,经验风险最小化经验风险最小化,即希望预测值与真实值尽可能最小化。即希望最小,经验风险也可以转换为范数形式:
(范数:向量空间种度量一个向量的长度或大小。如1范数是所有向量绝对值之和。2范数是所有向量平方和再开根号,也叫欧几里得范数。)
- 优化:,
以上提到的优化方法是最小二乘法,需要存在逆矩阵,即保证每个数据是独立的。但是不能保证每个数据特征是独立的,因此最小二乘法有很多约束。
3.2. 经验风险最小化-岭回归
为了解决最小二乘法造成的影响,我们引入了岭回归的概念,给的对角线加上一个常数,这样就保证其满秩,即相互独立。原来:,变为:, 其中I是一个单位矩阵。经过整理最后风险函数变为:。我们也可以理解为,对影响最大的权重进行正则化。
3.3. 从概率的角度看待线性回归
此部分已经在另一板块花了好几天总结,在此省略。
值得一提的是,之前最小二乘法用梯度下降法求参数是寻找经验风险最小值,而类似于正态分布这种凹函数,用梯度下降法最后求得的是极大值!也正好符合我们需要求参数取何值时下,样本在某模型上表现得更好的需求!
3.4. 最小二乘法求二元线性回归回归(实战)
import numpy as np;
np.random.seed(1)
X = np.random.normal(size = (1000,2),scale = 1) # X1,X2
X
RandomArray =(np.random.random(1000)*2 - 1)*5
y = 2 * X[:,0] + (-3)*X[:,1] + 4 + RandomArray
import matplotlib.pyplot as plt
plt.scatter(X[:,0],y)
plt.scatter(X[:,1],y)
from mpl_toolkits import mplot3d
ax = plt.axes(projection = '3d')
ax.scatter3D(X[:,0],X[:,1],y)
All_date = np.concatenate((X,y.reshape(1000,1)),axis = 1)
All_date
#构造训练集和测试集
np.random.shuffle(All_date)
train_date = All_date[:700,:]
test_date = All_date[700:,:]
train_date.shape,test_date.shape
W = np.random.normal(size = (2))
b = np.random.rand()
W[0],W[1],b
loss = 0.5 * np.sum( (y - (2*X[:,0] + (-3)*X[:,1] + 4)) ** 2)
#计算当前模型的损失值
loss = 0.5*np.sum( (y -(W[0]*X[:,0]+ W[1]*X[:,1] + b))**2 )
X = train_date[:,:2]
X = X.reshape(2,700)
y = train_date[:,-1]
X.shape
#构建增广矩阵
W_hat = np.concatenate((W,np.array([b]))).reshape(3,1)
X_hat = np.concatenate((X,np.ones((1,700))),axis = 0)
W_hat.shape,X_hat.shape
W_hat,X_hat
np.sum((y.reshape(700,1) - np.dot(X_hat.T,W_hat))**2)/700
lr = 0.0001 # 学习率
Num = 1
w0_list = []
w1_list = []
b_list = []
loss_list = []
while True:
#训练集上更新参数
W_hat = W_hat + lr * np.dot(X_hat,(y.reshape(700,1) - np.dot(X_hat.T,W_hat)))
#记录参数
w0_list.append(W_hat[0])
w1_list.append(W_hat[1])
b_list.append(W_hat[2])
# 训练集上计算总错误
loss = np.sum((y.reshape(700,1) - np.dot(X_hat.T,W_hat))**2)/2
loss_list.append(loss)
if Num % 10 == 1 :
print("Number: %d, loss: %f"%(Num,loss))
Num = Num + 1
if loss < 1000 or Num >1000:
break
plt.plot(range(len(loss_list)),loss_list)
plt.plot(range(len(w0_list)),w0_list)
plt.plot(range(len(w1_list)),w1_list)
plt.plot(range(len(b_list)),b_list)