Python 练习题 --- 梯度下降

  • 题目要求
  • 思路讲解
  • 第一题
  • 第二题
  • 第一步
  • 第二步
  • 第三步
  • 第四步
  • 第五步
  • 改进

  • 题目来源:在校课程老师布置的作业

题目要求

已知某系统模型可由 用Python画一个训练数据梯度与均方误差之间的关系图_sklearn

对该系统实际采样得到 4 个样本:(0,3.1)(1,4.9)(2,7.2)(3,8.9)

根据采样数据使用一维线性回归算法估计该模型:用Python画一个训练数据梯度与均方误差之间的关系图_sklearn_02

选取损失函数:用Python画一个训练数据梯度与均方误差之间的关系图_sklearn_03

基于 梯度下降算法 估计参数 wb

提示:
用Python画一个训练数据梯度与均方误差之间的关系图_sklearn_04

用Python画一个训练数据梯度与均方误差之间的关系图_机器学习_05

其中:

  • n 是样本数,(用Python画一个训练数据梯度与均方误差之间的关系图_机器学习_06用Python画一个训练数据梯度与均方误差之间的关系图_迭代_07)是样本点,用Python画一个训练数据梯度与均方误差之间的关系图_迭代_08

问题:

  1. 假设初始值 w = 0b = 0,学习率 η= 0.01,根据已采集的 4 个样本,基于 梯度下降算法 估计 wb,请计算 第1次第3次 迭代的结果,要求 给出计算过程每次迭代后的平均误差
  • 假设初始值 w = 0b = 0,请用 python 编程计算学习率为 η= 0.01η= 0.001 时迭代 100 次的结果。

思路讲解

这道题就是简单的 梯度下降 ,公式已经给出来了,我们就直接按照公式实现即可。

第一题

第一题要求手写,有了初始条件 用Python画一个训练数据梯度与均方误差之间的关系图_sklearn_09 ,很容易写出来梯度下降的过程。
我写了个程序输出,代码如下:

w = 0
b = 0
eta = 0.01

def process():
    
    global w, b
    
    x = x_train.reshape(1, -1)[0]
    y_hat = x * w + b
    y = y_train.reshape(1, -1)[0]
    diff = y - y_hat
    
    print('(' + '+'.join(map(lambda x:str(round(x, 4)), diff**2)) + f')/{2*x.shape[0]} =', round((diff**2 / (2*x.shape[0])).sum(), 4))
    
    grad_w = -diff * x
    print('(' + '+'.join(map(lambda x:f'({round(x, 4)})', grad_w)) + f')/{x.shape[0]} =', round(grad_w.sum() / x.shape[0], 4))
    w -= eta * grad_w.sum() / x.shape[0]
    print('w =', w)
    grad_b = -diff
    print('(' + '+'.join(map(lambda x:f'({round(x, 4)})', grad_b)) + f')/{x.shape[0]} =', round(grad_b.sum() / x.shape[0], 4))
    b -= eta * grad_b.sum() / x.shape[0]
    print('b =', b)

for i in range(1, 4):
    print('Epoch', i)
    process()
    print()
  • Epoch 1
    用Python画一个训练数据梯度与均方误差之间的关系图_机器学习_10
  • Epoch 2
    用Python画一个训练数据梯度与均方误差之间的关系图_梯度下降_11
  • Epoch 3
    用Python画一个训练数据梯度与均方误差之间的关系图_迭代_12

第二题

要计算 η= 0.01η= 0.001 时的结果,我们可以把能复用的地方封装成函数,以简化我们的代码。

第一步

首先要 初始化数据

w = 0
b = 0
X = [0., 1., 2., 3.]
Y = [3.1, 4.9, 7.2, 8.9]
  • 学习率我们可以作为参数传递给函数
第二步

计算 用Python画一个训练数据梯度与均方误差之间的关系图_迭代_13

def forward(w, X, b):
	result = []
	for x in X:
		result.append(w*x+b)
	return result
第三步

计算 损失 loss

def get_loss(X, Y, Y_PRED):
	result = []
	for i, y in enumerate(Y):
		result.append((y - Y_PRED[i])**2)
	return sum(result) / (2 * len(X))
第四步

迭代 计算损失 ,并 更新 wb ,传入参数 学习率 η

  • 将初始化数据加入函数中,这样每次更改学习率进行训练就不需要再初始化数据。
def train(eta):
    
    global w, b
    x_train = [0., 1., 2., 3.]
    y_train = [3.1, 4.9, 7.2, 8.9]
    
    for step in range(1, 101):
        y_pred = forward(w, x_train, b)
        loss = get_loss(x_train, y_train, y_pred)
        print('Epoch {}: loss = {}'.format(step, loss))
        
        w -= -eta * sum([x * (y - y_hat) for x, y, y_hat in zip(x_train, y_train, y_pred)]) / len(x_train)
        b -= -eta * sum([y - y_hat for y, y_hat in zip(y_train, y_pred)]) / len(x_train)
第五步

传参 。调用 train 函数。

  • η= 0.01
train(0.01)
print('w=', w, 'b=', b)

用Python画一个训练数据梯度与均方误差之间的关系图_机器学习_14

  • η= 0.001
train(0.001)
print('w=', w, 'b=', b)

用Python画一个训练数据梯度与均方误差之间的关系图_梯度下降_15

改进
  • 使用 numpy 数组进行计算操作会更简便。
  • 封装成类 会更好看。
  • (当然,我的作业包括以上两点)