2.代码实现梯度下降
2.1 批量梯度下降BGD
2.1.1 一元一次线性回归
import numpy as np # 创建数据 X = np.random.rand(100, 1) w, b = np.random.randint(1, 10, size = 2) # 增加噪声,也被称为"加盐" y = w * X + b + np.random.rand(100, 1) # 把b作为偏置项,截距对应系数 x_0 = 1, 更新 X X = np.concatenate([X, np.full(shape = (100, 1), fill_value = 1)], axis = 1) # 循环次数 epoches = 10000 # 学习率 eta = 0.01 # 要求解的系数,"瞎蒙的" theta = np.random.randn(2, 1) for i in range(epoches): # 批量梯度下降,X为矩阵,包含所有的数据 g = X.T.dot(X.dot(theta) - y) # 根据公式计算的梯度 theta = theta - eta * g print('真实的斜率、截距:', w, b) print('使用BGD求的斜率、截距:', theta[0], theta[1])
可以看出,我们求出的数据和真实的数据还是有一定的差距的,这就是加了 噪声(加盐) 的作用结果,但这样的计算数据才是更加真实的,因为现实生活中的数据是不可能完美的。
下图是梯度下降的示意图:
import numpy as np # 创建数据 X = np.random.rand(100, 1) w, b = np.random.randint(1, 10, size = 2) # 增加噪声,也被称为"加盐" y = w * X + b + np.random.rand(100, 1) # 把b作为偏置项,截距对应系数 x_0 = 1, 更新 X X = np.concatenate([X, np.full(shape = (100, 1), fill_value = 1)], axis = 1) # 循环次数 epoches = 10000 # 学习率 t0, t1 = 5, 1000 # t 是梯度下降的次数,逆时衰减,随着梯度下降次数增加,学习率变小 def learning_rate_shedule(t): return t0 / (t + t1) # 要求解的系数,"瞎蒙的" theta = np.random.randn(2, 1) for i in range(epoches): # 批量梯度下降,X为矩阵,包含所有的数据 g = X.T.dot(X.dot(theta) - y) # 根据公式计算的梯度 eta = learning_rate_shedule(i) theta = theta - eta * g print('真实的斜率、截距:', w, b) print('使用BGD求的斜率、截距:', theta[0], theta[1])
2.1.2 八元一次线性回归
import numpy as np # 创建数据 X = np.random.rand(100, 8) w = np.random.randint(1, 10, size = (8, 1)) b = np.random.randint(1, 10, size = 1) # 增加噪声,也被称为"加盐" y = X.dot(w) + b + np.random.rand(100, 1) # 把b作为偏置项,截距对应系数 x_0 = 1, 更新 X X = np.concatenate([X, np.full(shape = (100, 1), fill_value = 1)], axis = 1) # 循环次数 epoches = 10000 # 学习率 t0, t1 = 5, 1000 # t 是梯度下降的次数,逆时衰减,随着梯度下降次数增加,学习率变小 def learning_rate_shedule(t): return t0 / (t + t1) # 要求解的系数,"瞎蒙的" theta = np.random.randn(9, 1) for i in range(epoches): # 批量梯度下降,X为矩阵,包含所有的数据 g = X.T.dot(X.dot(theta) - y) # 根据公式计算的梯度 eta = learning_rate_shedule(i) theta = theta - eta * g print('真实的斜率、截距:', w, b) print('使用BGD求的斜率、截距:', theta)
2.2 随机梯度下降SGD
2.2.1 一元一次线性回归
import numpy as np # 创建数据 X = np.random.rand(100, 1) w, b = np.random.randint(1, 10, size = 2) # 增加噪声,也被称为"加盐" y = w * X + b + np.random.rand(100, 1) # 把b作为偏置项,截距对应系数 x_0 = 1, 更新 X X = np.concatenate([X, np.full_like(X, fill_value = 1)], axis = 1) # 循环次数 epoches = 100 # 学习率 t0, t1 = 5, 1000 # t 是梯度下降的次数,逆时衰减,随着梯度下降次数增加,学习率变小 def learning_rate_shedule(t): return t0 / (t + t1) theta = np.random.randn(2, 1) cnt = 0 # 表示训练的次数 for t in range(epoches): index = np.arange(100) np.random.shuffle(index) # 洗牌,打乱顺序 # NumPy 花式索引 X = X[index] y = y[index] for i in range(100): X_i = X[[i]] y_i = y[[i]] # 根据这一个样本,进行计算梯度 g = X_i.T.dot(X_i.dot(theta) - y_i) eta = learning_rate_shedule(cnt) cnt += 1 theta -= eta * g print('真实的斜率、截距:', w, b) print('使用SGD求的斜率、截距:', theta[0], theta[1])
2.2.2 五元一次线性回归
import numpy as np # 创建数据 X = np.random.rand(100, 5) w = np.random.randint(1, 10, size = (5, 1)) b = np.random.randint(1, 10, size = 1) # 增加噪声,也被称为"加盐" y = X.dot(w) + b + np.random.rand(100, 1) # 把b作为偏置项,截距对应系数 x_0 = 1, 更新 X X = np.concatenate([X, np.full(shape = (100, 1), fill_value = 1)], axis = 1) # 循环次数 epoches = 100 # 学习率 t0, t1 = 5, 1000 # t 是梯度下降的次数,逆时衰减,随着梯度下降次数增加,学习率变小 def learning_rate_shedule(t): return t0 / (t + t1) theta = np.random.randn(6, 1) cnt = 0 # 表示训练的次数 for t in range(epoches): index = np.arange(100) np.random.shuffle(index) # 洗牌,打乱顺序 # NumPy 花式索引 X = X[index] y = y[index] for i in range(100): X_i = X[[i]] # 两个[]:可以进行矩阵运算 y_i = y[[i]] # 根据这一个样本,进行计算梯度 g = X_i.T.dot(X_i.dot(theta) - y_i) eta = learning_rate_shedule(cnt) cnt += 1 theta -= eta * g print('真实的斜率、截距:', w, b) print('使用SGD求的斜率、截距:', theta)
2.3 小批量梯度下降MBGD
2.3.1 一元一次线性回归
import numpy as np # 1、创建数据集X,y X = np.random.rand(100, 1) w,b = np.random.randint(1, 10,size = 2) y = w * X + b + np.random.randn(100, 1) # 2、使用偏置项x_0 = 1,更新X X = np.c_[X, np.ones((100, 1))] # 3、定义一个函数来调整学习率 t0, t1 = 5, 500 def learning_rate_schedule(t): return t0/(t + t1) # 4、创建超参数轮次、样本数量、小批量数量 epochs = 100 n = 100 batch_size = 16 num_batches = int(n / batch_size) # 5、初始化 W0...Wn,标准正太分布创建W θ = np.random.randn(2, 1) # 6、多次for循环实现梯度下降,最终结果收敛 for epoch in range(epochs): # 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序 index = np.arange(n) np.random.shuffle(index) X = X[index] y = y[index] for i in range(num_batches): # 一次取一批数据16个样本 X_batch = X[i * batch_size : (i + 1) * batch_size] y_batch = y[i * batch_size : (i + 1) * batch_size] g = X_batch.T.dot(X_batch.dot(θ) - y_batch) learning_rate = learning_rate_schedule(epoch * n + i) θ = θ - learning_rate * g print('真实斜率和截距是:', w, b) print('梯度下降计算斜率和截距是:',θ)
2.3.2 三元一次线性回归
import numpy as np # 1、创建数据集X,y X = np.random.rand(100, 3) w = np.random.randint(1,10,size = (3, 1)) b = np.random.randint(1,10,size = 1) y = X.dot(w) + b + np.random.randn(100, 1) # 2、使用偏置项 X_0 = 1,更新X X = np.c_[X, np.ones((100, 1))] # 3、定义一个函数来调整学习率 t0, t1 = 5, 500 def learning_rate_schedule(t): return t0/(t + t1) # 4、创建超参数轮次、样本数量、小批量数量 epochs = 10000 n = 100 batch_size = 16 num_batches = int(n / batch_size) # 5、初始化 W0...Wn,标准正太分布创建W θ = np.random.randn(4, 1) # 6、多次for循环实现梯度下降,最终结果收敛 for epoch in range(epochs): # 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序 index = np.arange(n) np.random.shuffle(index) X = X[index] y = y[index] for i in range(num_batches): # 一次取一批数据16个样本 X_batch = X[i * batch_size : (i + 1) * batch_size] y_batch = y[i * batch_size : (i + 1) * batch_size] g = X_batch.T.dot(X_batch.dot(θ) - y_batch) learning_rate = learning_rate_schedule(epoch * n + i) θ = θ - learning_rate * g print('真实斜率和截距是:', w, b) print('梯度下降计算斜率和截距是:',θ)