一、导数复习
1、正切 tan
定义:tanθ=y/x 如下图
2、导数
3、偏导数
偏导数:当有多元函数是,针对于不同的自变量,描述函数变化率的公式。
二、梯度下降的几个问题
1、梯度下降
梯度下降是一种非常通用的优化算法,能够为大范围的问题找到最优解。梯度下降的中心思想就是迭代的调整参数从而使损失函数最小化。
假设你迷失在山上的浓雾之中,你能感觉到的只有你脚下路面的坡度。快速到达山脚的一个策略就是沿着最陡的方向下坡。这就是梯度下降的做法:通过测量参数向量θ相关的误差函数的局部梯度,并不断沿着降低梯度的方向调整,直到梯度降为0,到达最小值。
具体来说,首先使用一个随机的θ值(这被称为随机初始化),然后逐步改良,每次踏出一步,每一步都尝试降低一点损失函数(如MSE),直到算法收敛出一个最小值。
2、梯度下降的方向
- 梯度下降的方向1:只要对损失函数求导,θ的变化方向永远趋近于损失函数的最小值。
- 梯度下降的方向2: 如果θ已经在最低点,那么梯度将不会发生变化。
3、梯度下降的步长
- 梯度下降的步长1:梯度下降中一个重要参数是每一步的步长,这取决于超参数的学习率。
- 梯度下降的步长2:梯度下降的步长会逐渐变小。
3、如何应对梯度下降的局部最小值问题
- 对于MSE来说,因为损失函数是个凸函数,所以不存在局部最小值,只有一个全局最小值。
- 通过随机初始化θ,可以避开局部最小值。
- 对于多变量,高维度的值,就算在某个维度上陷入和局部最小值,但是还能从别的维度跳出。
三、多变量线性回归
1、多变量线性回归引入
模型:
之前: hθ(x) = θ0 + θ1x
现在: hθ(x) = θ0 + θ1x1 + θ2x2 + … + θnxn
为了保证模型的统一性,我们给模型加上x0 ,并使 x0 = 1。
多项型回归代码案例:
"""
多项式回归
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
m = 100
X = 6 * np.random.rand(m, 1) - 3
y = 0.5 * X ** 2 + X + 2 + np.random.randn(m, 1)
plt.plot(X, y, 'b.')
# plt.show()
d = {1: 'g-', 2: 'r+', 10: 'y*'}
for i in d:
# include_bias 可以理解为w0 =False 意思就是不要w0
poly_features = PolynomialFeatures(degree=i, include_bias=False)
"""
fit 和 fit_transform的区别
fit: 简单来说,就是求得训练集X的均值,方差,最大值,最小值这些训练集X固有的属性
fit_transform: 首先fit,然后在此基础上,进行标准化,降维,归一化等操作
"""
X_poly = poly_features.fit_transform(X)
print(X[0])
print(X_poly[0])
# print(X_poly[:, 0])
lin_reg = LinearRegression()
lin_reg.fit(X_poly, y)
# print(lin_reg.intercept_, lin_reg.coef_)
y_predict = lin_reg.predict(X_poly)
plt.plot(X_poly[:, 0], y_predict, d[i])
plt.show()
2、多元梯度下降方法
模型: hθ(x) = θT x = θ0x0 + θ1x1 + θ2x2 + … + θnxn
参数: θ0 θ1…θn
损失函数:
梯度下降公式:
一元与多元梯度下降对比:
3、特征缩放(归一化)
一般情况下我们我们使用特征缩放,把特征值会缩放到接近 -1 ≤ xi ≤ 1的区域。
左图的梯度下降算法直接走向最小值,可以快速到达。而在右图中,先是沿着与全局最小值方向近乎垂直的方向前进,接下来是一段几乎平坦的长长的山谷。最终还是会抵达最小值,但是这需要花费大量的时间。
特征缩放是为了确保i特征在一个数量级上。
4、学习率
我们通常通过损失u函数来确保梯度下降在正常工作。
4.1、如果损失函数下降的幅度小于10-3,那我们就说损失函数已经收敛了
或者使用自动收敛测试。
4.2、当损失函数上升的时候,证明梯度下降方法没有正常工作,这时候可以使用小一点的学习率α
对于足够小的学习率α而言,损失函数应该每次都下降
但是如果学习率α太小,收敛的速度将会很慢。
5、随机梯度下降
代码案例:
"""
随机梯度下降
"""
import numpy as np
import random
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# print(X_b)
n_epochs = 500
a0 = 0.1
decay_rate = 1
m = 100
num = [i for i in range(100)]
def learning_schedule(epoch_num):
return (1 / (decay_rate * epoch_num + 1)) * a0
theta = np.random.randn(2, 1)
# epoch 是轮次的意思,意思是用m个样本做一轮迭代
for epoch in range(n_epochs):
# 生成100个不重复的随机数
rand = random.sample(num, 100)
for i in range(m):
random_index = rand[i]
xi = X_b[random_index:random_index+1]
yi = y[random_index:random_index+1]
gradients = xi.T.dot(xi.dot(theta)-yi)
learning_rate = learning_schedule(epoch+1)
theta = theta - learning_rate * gradients
print(theta)
6、“Batch” Gradient Descent 批梯度下降
代码案例:
"""
线性回归实现梯度下降的批处理(batch_gradient_descent )
"""
import numpy as np
X1 = 2 * np.random.rand(100, 1)
X2 = 4 * np.random.rand(100, 1)
X3 = 6 * np.random.rand(100, 1)
y = 4 + 3 * X1 + 4 * X2 + 5 * X3 + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X1, X2, X3]
learning_rate = 0.01
# 通常在做机器学习的时候,一般不会等到他收敛,因为太浪费时间,所以会设置一个收敛次数
n_iterations = 1000
m = 100
# 1.初始化theta, w0...wn
theta = np.random.randn(4, 1)
# print(theta)
count = 0
num = [i for i in range(100)]
for epoch in range(100):
# 生成了100个不重复的随机数
import random
rand = random.sample(num, 100)
for i in range(m):
random_index = rand[i]
xi = X_b[random_index:random_index+1]
yi = y[random_index:random_index+1]
print(xi, yi)
gradients = xi.T.dot(xi.dot(theta)-yi)
theta = theta - learning_rate * gradients
# 利用损失函数监控模型
loss = 1/(2 * m) * np.sum((X_b.dot(theta)-y) ** 2)
count += 1
# print(count, loss)
#4. 不会设置阈值,之间设置超参数,迭代次数,迭代次数到了,我们就认为收敛了
for iteration in range(n_iterations):
count += 1
# 2. 接着求梯度gradient
gradients = 1/m * X_b.T.dot(X_b.dot(theta)-y)
# print(gradients)
# 3. 应用公式调整theta值, theta_t + 1 = theta_t - grad * learning_rate
theta = theta - learning_rate * gradients
# # 利用损失函数监控模型
loss = 1/(2 * m) * np.sum((X_b.dot(theta)-y) ** 2)
print(count, loss)
# print(count)
print(theta)
7、‘Mini-batch’梯度下降
- 如果 mini-batch 大小 = m : 那他就是批梯度下降。
- 如果 mini-batch 大小 = 1 : 那他就是随机梯度下降。(代码在上第六点随机下降)。
- 如果 mini-batch 1 < 大小 < m :那他就是‘Mini-batch’随机梯度下降。
当:mini-batch= m
代码案例:
"""
随机梯度下降
"""
import numpy as np
import random
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# print(X_b)
n_epochs = 500
t0, t1 = 5, 50
m = 100
num = [i for i in range(100)]
def learning_schedule(t):
return t0 / (t + t1)
theta = np.random.randn(2, 1)
batch_num = 5
batch_size = m // 5
# epoch 是轮次的意思,意思是用m个样本做一轮迭代
for epoch in range(n_epochs):
# 生成100个不重复的随机数
for i in range(batch_num):
start = i*batch_size
end = (i+1)*batch_size
xi = X_b[start:end]
yi = y[start:end]
gradients = 1/batch_size * xi.T.dot(xi.dot(theta)-yi)
learning_rate = learning_schedule(epoch*m + i)
theta = theta - learning_rate * gradients
print(theta)
三中梯度下降的总结:
随机梯度下降会丧失向量带来的加速,所以我们不会太用随机梯度下降。
如何选择:
- 训练集比较小: 使用批梯度下降(小于2000个)。
- 训练集比较大:使用Mini-bitch梯度下降 一般的Mini-batch size 是64,128,256, 512,1024
Mini-batch size要适用CPU/GPU的内存。
8、Lass 回归
Lasso回归和岭回归类似,不同的是,Lasso可以理解为在线性回归基础上加入一个L1正则项,同样来限制W不要过大。其中λ>0,通过确定λ的值可以使得模型在偏差和方差之间达到平衡,随着λ的增大,模型的方差减小,偏差增大。
"""
Lasso 回归
Lasso用的是l1的正则化
"""
import numpy as np
from sklearn.linear_model import Lasso
from sklearn.linear_model import SGDRegressor
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
lasso_reg = Lasso(alpha=0.15)
lasso_reg.fit(X, y)
print(lasso_reg.predict([[1.5]]))
print(lasso_reg.coef_)
sgd_reg = SGDRegressor(penalty='l1', n_iter=1000)
sgd_reg.fit(X, y.ravel())
print(sgd_reg.predict([[1.5]]))
print(sgd_reg.coef_)
9、岭回归
针对高方差,即过拟合的模型,解决办法之一就是对模型进行正则化:限制参数大小(由于本篇博客所提到的岭回归和Lasso都是正则化的特征选择方法,所以对于其他解决过拟合的方法不多赘述)当线性回归过拟合时,权重系数wj就会非常的大,岭回归就是要解决这样的问题。岭回归(Ridge Regression)可以理解为在线性回归的损失函数的基础上,加,入一个L2正则项,来限制W不要过大。其中λ>0,通过确定λ的值可以使得模型在偏差和方差之间达到平衡,随着λ的增大,模型的方差减小,偏差增大。
代码案例:
"""
岭回归
岭回归运用了L2正则化
"""
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.linear_model import SGDRegressor
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
# alpha是惩罚项里的alpha, solver处理数据的方法,auto是根据数据自动选择,svd是解析解,sag就是随机梯度下降
ridge_reg = Ridge(alpha=1, solver='auto')
# 学习过程
ridge_reg.fit(X, y)
# 预测
print(ridge_reg.predict([[1.5], [2], [2.5]]))
# 打印截距
print(ridge_reg.intercept_)
# 打印系数
print(ridge_reg.coef_)
"""
岭回归和sgd & penalty=2是等价的
"""
sgd_reg = SGDRegressor(penalty='l2')
sgd_reg.fit(X, y.ravel())
print(sgd_reg.predict([[1.5], [2], [2.5]]))
# 打印截距
print("W0=", sgd_reg.intercept_)
# 打印系数
print("W1=", sgd_reg.coef_)
10、学习率衰减
在做Mini-batch的时候,因为噪声的原因,可能训练结果不是收敛的,而是在最低点周围晃动,如果我们要解决这个问题,那我们就需要减少学习率,让他在尽量小的范围内晃动。
1 epoch = 1 次遍历所有的数据。