本周课程主要内容为线性回归,BP网络与性能优化。
线性回归
线性回归是利用数理统计中回归分析,来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法,运用十分广泛。其表达形式为 其中,e为误差服从均值为0的正态分布。
1.线性回归的基本元素
为了解释线性回归,举一个实际的例子:我们希望根据房屋的面积(平方英尺)和房龄(年)来估算房屋价格(美元)。为了开发一个能预测房价的模型,我们需要收集一个真实的数据集。这个数据集包括了房屋的销售价格、面积和房龄。
在机器学习的术语中,该数据集称为训练数据集(training data set)或训练集(training set)。每行数据(比如一次房屋交易相对应的数据)称为样本(sample),也可以称为数据点(data point)或数据样本(data instance)。我们把试图预测的目标(比如预测房屋价格)称为标签(label)或目标(target)。预测所依据的自变量(面积和房龄)称为特征(feature)或协变量(covariate)。
线性回归的基本模型为
我们要做的是在该模型的基础上,找到模型的权重w和偏置e,在寻找之前,我们需要两个工具:
1):模型的度量方式:损失函数
2):更新模型提高质量的方法:随机梯度下降
通过不断地梯度下降,去寻找令损失函数最小的一组参数w与e。
2.线性回归的神经网络图
我们将线性回归模型描述为一个神经网络。该图只显示连接模式,隐去了权重和偏置。
如图所示的神经网络中,输入为x1, . . . , xd,因此输入层中的输入数(或称为特征维度,feature dimen‐ sionality)为d。网络的输出为o1,因此输出层中的输出数是1。需要注意的是,输入值都是已经给定的,并且只有一个计算神经元。由于模型重点在发生计算的地方,所以通常我们在计算层数时不考虑输入层。也就是说,图中神经网络的层数为1。我们可以将线性回归模型视为仅由单个人工神经元组成的神经网络,称为单层神经网络。 对于线性回归,每个输入都与每个输出相连,我们将这种为全连接层(fully‐connected layer)或称为稠密层(dense layer)。
3.线性回归的基本实现
import random import torch import numpy from d2l import torch as d2l def synthetic_data(w, b, num_examples): """生成线性数据集 y = wx + b + c""" """torch.normal(means, std, out=None) 返回一个张量,包含从给定参数means,std的离散正态分布中抽取随机数。 均值means是一个张量,包含每个输出元素相关的正态分布的均值。 std是一个张量,包含每个输出元素相关的正态分布的标准差。 均值和标准差的形状不须匹配,但每个张量的元素个数须相同。""" X = torch.normal(0, 1, (num_examples, len(w))) """torch.matmul(input, other) → Tensor 计算两个张量input和other的矩阵乘积 matmul函数没有强制规定维度和大小,可以用利用广播机制进行不同维度的相乘操作。""" y = torch.matmul(X, w) + b y += torch.normal(0, 0.01, y.shape) return X, y.reshape((-1, 1)) def data_iter(batch_size, features, labels): """该函数用来接收批量大小,特征矩阵,标签向量,生成batch_size小批量""" num_examples = len(features) """list(range(num))返回的对象是range而不是list""" indices = list(range(num_examples)) """随机读取""" random.shuffle(indices) for i in range(0, num_examples, batch_size): batch_indices = torch.tensor(indices[i: min(i + batch_size, num_examples)]) yield features[batch_indices],labels[batch_indices] """yield在返回数据的同时,还保存了当前的执行内容,当你再一次调用这个函数时,他会找到你在此函数中的yield关键字,然后从yield的下一句开始执行。""" def linreg(X, w, b): """线性回归模型""" return torch.matmul(X, w) + b def squard_loss(y_hat, y): return (y_hat - y.reshape(y_hat.shape)) ** 2 / 2 def sgd(params, lr, batch_size): """小批量随机梯度下降 lr为学习率""" """torch.no_grad() 是一个上下文管理器,用于暂时关闭自动求导功能,即关闭梯度计算。 用于不需要计算梯度,或想要评估模型时""" with torch.no_grad(): for param in params: param -= lr * param.grad / batch_size param.grad.zero_() if __name__ == '__main__': true_w = torch.tensor([2, -3.4]) true_b = 4.2 features, labels = synthetic_data(true_w, true_b, 1000) print('features:', features[0],'\nlabels:', labels[0]) """detach是一种分离的方法,numpy转化为数组""" #point1 = features[:, (1)].detach().numpy() #point2 = labels.detach().numpy() #d2l.set_figsize() #d2l.plt.scatter(point1, point2,1) #d2l.plt.show() 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) lr = 0.03 num_epochs = 3 net = linreg loss = squard_loss for epoch in range(num_epochs): for X, y in data_iter(batch_size, features, labels): l = loss(net(X, w, b), y) """.sum().backward() 通常用于对张量(Tensor)进行反向传播以计算梯度。 .sum() 是一个聚合操作,用于将张量中的所有元素相加得到一个标量(scalar)。 .backward() 用于根据这个标量进行反向传播,计算并存储张量中每个元素的梯度。""" l.sum().backward() sgd([w, b], lr, batch_size) with torch.no_grad(): train_l = loss(net(features, w, b), labels) print(f'epoch{epoch+1}, loss{float(train_l.mean())}') print(f'w的估计误差:{true_w - w.reshape(true_w.shape)}') print(f'w的估计误差:{true_b - b}')
4.实现时候遇到的问题
1.实现时想在双系统那边实现,但是Ubuntu突然进不去了,一直在弹bios.error,通过进入bios将混显模式改为独显模式解决。
2..detach().numpy()在d2l.plt.scatter(point1, point2,1)中一直报错,一直说没有引用numpy,提出来在外面用point表示能正常使用,不知道为什么。