动手学深度学习----线性回归(从0开始实现)

基础概念

线性回归的过程是已知数据点,需要通过一条直线来拟合这些点,这条直线对应的参数 都是通过线性回归求得
例子:假设y = X × w + b y是一个房子的价格 X是一个向量[X1,X2],X1是面积,X2是位置,是影响y的因素,w是X中对应的权重[w1,w2]T, b 是偏差
y=w1 × X1+ w2 × X2+b 通过梯度下降寻找不断更新参数以得到最优解

从0实现线性回归

代码是指定w为 [2, 3.4]T b为4.2 构造一个随机数据集
通过梯度下降 线性回归去用一条直线近似生成的点集 在最后查看近似求得的w b与真实的w b的差距

#线性回归
import torch
import random
from d2l import torch as d2l
from matplotlib import pyplot as plt


def synthetic_data(w, b, num_expamples):   # 构建人造数据集 w=[2 ,-3.4]T  b=4.2     以及一个噪声项d  y= Xw + b + d
    X = torch.normal(0, 1, (num_expamples, len(w)))  # 生成均值为0 方差为1的随机数 num_expamples个样本  len(w) 列数
    y = torch.matmul(X, w) + b  # y = X * w + b     matmul矩阵乘法
    y += torch.normal(0, 0.01, y.shape)  # 噪声
    return X, y.reshape((-1, 1))  # reshape(-1,1)转换成1个列向量


true_w = torch.tensor([2, -3.4])
true_b = 4.2
features, labels = synthetic_data(true_w, true_b, 1000)  # 生成 1000个样本 每个样本两列

d2l.set_figsize()
d2l.plt.scatter(features[:, 1].detach().numpy(), labels.detach().numpy(), 1)  # 将X的第一列与lable画散点图 可看出二者之间存在线性关系
plt.show()

# 随机获得一组 features[] labels[]
def data_iter(batch_size, features, labels):
    num_emamples = len(features)  # 获取样本数量
    indices = list(range(num_emamples))    # 生成每个样本的index range(n)--- 0到n-1
    random.shuffle(indices)  # 将index 随机打乱 shuffle只能用于list
    for i in range(0, num_emamples, batch_size):
        batch_indices = torch.tensor(indices[i:min(i + batch_size, num_emamples)])  # 避免超出list的范围所以用了min()
        yield features[batch_indices], labels[batch_indices]


batch_size = 10
for X, y in data_iter(batch_size, features, labels):
    print(X, '\n', y)
    break


w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)  # 需要更新 所以要计算梯度
b = torch.zeros(1, requires_grad=True)


def linear_regression(X, w, b):  # 定义模型
    return torch.matmul(X, w) + b


def square_loss(y_hat, y):
    # 均方损失
    return (y_hat - y.reshape(y_hat.shape))**2 / 2


def sgd(params, lr, batch_size):  # params是一个list 给定所以参数 lr 学习率
    # 小批量随机梯度下降
    with torch.no_grad():  # 不需要计算梯度, 更新值时 才需要计算
        for param in params:
            param -= lr * param.grad / batch_size  # param.grad 参数梯度值  /batch_size 损失函数中未求均值 在这边除以batch_size
            param.grad.zero_()  # 不会自动设0 手动将梯度设置为0


lr = 0.03  # 给定超参数
num_epochs = 10
net = linear_regression
loss = square_loss
# 训练模型
for epoch in range(num_epochs):
    for X, y in data_iter(batch_size, features, labels):  # 将一个batch_size大小features和labels赋给  X 和 y
        l = loss(net(X, w, b), y)   # net(X, w, b)相当于linear_regression(X, w, b)  计算小批量损失
        # l 形状是 [batch_size, 1]
        l.sum().backward()  # 求和算梯度
        sgd([w, b], lr, batch_size)  # 使用上面计算的梯度对w b进行更新
    with torch.no_grad():
        train_l = loss(net(features, w, b), labels)  # 计算整个features和整个labels的loss
        print(f'epoch {epoch +1}, loss {float(train_l.mean()):f}')

print(f'w的估计误差:{true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差:{true_b - b}')

你可能感兴趣的:(#,深度学习,深度学习,python,线性回归)