react网站开发实战,泉州网站设计平台,云南建设学校网站,做网站用html好还是vue好1.线性方程和向量乘法
深度学习的基础就是从线性回归方程的理论进入的。简单的线性回归方程为 比如大家日常中买房子#xff0c;价格受到哪些因素影响呢#xff1f;
比如房龄、交通、是否是学区、有无配套超市、公园#xff0c;这些基本是外部条件#xff0c;内部条件诸如…1.线性方程和向量乘法
深度学习的基础就是从线性回归方程的理论进入的。简单的线性回归方程为 比如大家日常中买房子价格受到哪些因素影响呢
比如房龄、交通、是否是学区、有无配套超市、公园这些基本是外部条件内部条件诸如几梯几户、层高、容积率、面积、朝向等这些这样一看如果使用上面的模型构建一个房屋价格预测的神经网络模型参数非常多这么多个参数影响了房屋的价格。所谓线性回归(regression)是能为一个或者多个自变量与因变量之间关系建模的一类方法。回归在数学中经常用来表示输入和输出之间的关系。
所以上面的房屋价格如果只考虑面积和房龄的话预测模型就变成了 称为偏执或者截距预测值所依据的自变量称为特征或者协变量把试图预测的目标称为标签或者目标。。所以整体的预测值就可以描述为 我们用矩阵表示出来就是 向量是对于单个数据样本特征。使用符号表示的矩阵就是。就可以很方便的引用整个数据集的个样本。其中的每一行就是一个样本每一列就是一种特征。对于特征集合预测值通过矩阵-向量乘法表示为 2.正态分布和平方损失
正态分布和线性回归之间的关系很密切。 正态分布normal distribution也称为高斯分布Gaussian distribution 最早由德国数学家高斯Gauss应用于天文学研究。 我们定义正态分布的时候就是有一个随机变量具有均值和方差标准差其正态分布概率密度函数如下 在后面的方程中我们假设噪声服从正态分布。
如果使用函数来实现
def normal(x, mu, sigma):p 1/ math.sqrt(2 * math.pi * sigma**2)return p* np.exp(-0.5 / sigma**2 * (x-mu)**2)# 注意torch.normal定义中
torch.normal(mean: _float, std: _float, size: Sequence[Union[_int, SymInt]]...)
mean: 正态分布的均值可以是一个数值也可以是一个张量
std: 正态分布的标准差可以是一个数值也可以是一个张量
size:输出随机数的形状可以是一个整数用于生成size大小的一维张量也可以是一个元组用于生成相应形状的多维张量
3.样本刷选
现在我们从市场上获取了一批输入数据即有一批特征值。因为我们最终是寻找参数。所以虽然开始不知道最终具体的是多少但是可以根据经验值填写一个 所以使用参数模型.其中 作为噪声项服从均值为0的正态分布。这就是我们第一章节中的 import random # 导入random用于需要随机化初始的权重以及随机梯度下降
import torch
from d2l import torch as d2ldef synthetic_data(w, b, num_examples):生成yxW b噪声:param w::param b::param num_examples: 指定生成样本的数量:return:X torch.normal(0, 1, (num_examples, len(w))) # 生成均值为0方差为1的是num个样本列数是wy torch.matmul(X, w) b # Matrix Multiplication 两个相乘y torch.normal(0, 0.01, y.shape) # 加入一个随机噪音均值为0方差为1return X, y.reshape((-1, 1)) # 做成一个列向量返回 注意features中的每一行都包含一个二维数据样本 labels中的每一行都包含一维标签值一个标量 x torch.arange(12).reshape(2,6)print(x)y x.reshape((-1,1))print(y) 这里还有一个就是之前很多时候我们使用的时候都是
torch.arange(24).reshape(2,3,4)
reshape的参数都是整数但是上面的y.reshape((-1,1))是什么意思呢
-1作为一个维度参数时表示该维度的大小由数组的实际大小和其它维度决定。换句话说NumPy会自动计算这个维度的大小以保持数组元素总数不变。1表示新形状中的另一个维度大小为1。因此当你对一个数组或矩阵调用.reshape((-1, 1))时你实际上是在告诉NumPy将原数组重塑为一个列向量即每列只有一个元素的二维数组。也就是说无论输入数组有多少个元素结果都将是一个两维数组其中每个原始元素占据一行且仅有一列。参考 x torch.arange(12).reshape(2,6)print(x)y x.reshape((-1,1))print(y)
输出如下所示 我们调用上面的函数 true_w torch.tensor([2, -3.4])true_b 4.2features, labels synthetic_data(true_w, true_b, 1000)print(output features:, features)print(foutput labels: {labels})
输出如下所示和上面的理解是一致的 即features特征值是一个每一行都包含一个二维数组的样本labels即预测值每一行都包含一个一维标签值 。
我们看看特征值和标签之间的散点分布图。 d2l.set_figsize()# 这里的detach是从pytorch detach出来之后才能转到numpy中d2l.plt.scatter(features[:, 0].detach().numpy(), labels.detach().numpy(), 1);d2l.plt.show() 现在我们的基础数据已经构造完成。接下来一个重要的事情需要定义个函数每次读取一个小批量。
4.小批量数据构造
为什么要使用小批量而不是使用全部的样本呢因为每次计算梯度需要对损失函数求导损失函数是对我们样本平均损失所以求解一次梯度函数需要把所有样本重新计算一遍这个训练过程太贵了所以在神经网络实际训练几乎不用全部的样本。同样一个神经网络模型的训练过程可能需要数分钟数个小时甚至更久。因为要计算几百步甚至几千步才能求解出最终的结果。所以我们定义损失函数之后只要能求解得到一个“差不多”的解就可以而且在多维复杂的模型中很少能得到准确解。所以我们损失函数就是多个采样数据各自损失最后求平均得到最终的损失函数。所以我们采样个样本来求解近似。 所以这里的采样的个样本如果 很大则计算出的结果相对比较精确但是计算复杂度很高如果比较小计算比较容易但是精确度可能会很差。毕竟梯度的计算复杂度是和样本的个数线性相关的。
def data_iter(batch_size, features, labels)::param batch_size::param features::param labels::return:num_examples len(features)indices list(range(num_examples))# shuffle这些样本是随机读取的没有特定的顺序random.shuffle(indices) # 把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]
测试下这个函数 batch_size 10for X, y in data_iter(batch_size, features, labels):print(小批量数据:, X, \n, y)break 5.定义模型 def linreg(X, w, b):线性规划模型:param X::param w::param b::return:return torch.matmul(X, w) b
w torch.normal(0, 0.01, size(2, 1), requires_gradTrue)
b torch.zeros(1, requires_gradTrue)
这是一个均值为零方差为0.01的正太分布函数。我们需要计算梯度requires_gradTrue.对于偏差来说。我们直接给出一个0当然也需要不断地调整所以需要计算梯度。
6.定义损失函数
def squared_loss(y_hat, y):定义损失函数就是均方误差:param y_hat: 预测值:param y: 真实值:return:# y.reshape(y_hat.shape) 确保两者大小一样return (y_hat - y.reshape(y_hat.shape)) **2 / 2
其中是预测值是我们的真实值。原则上两个个数是一样的但是计算中可能是一个行向量一个是列向量。所以使用.shape函数统一下。 7.定义优化算法
def sgd(params, lr, batch_size):小批量随机梯度下降:param params: params 包含了w和b:param lr:学习率:param batch_size::return:with torch.no_grad(): # 更新的时候不要更新梯度for param in params:param - lr * param.grad / batch_sizeparam.grad.zero_() # 把梯度设置为0下次计算梯度的时候就和上次不会相关了
with*作用torch.no_grad() 是一个上下文管理器context manager它告诉 PyTorch 在这个块内不需要计算梯度。这意味着任何在此块内的操作都不会被加入到自动求导图中即不会跟踪这些操作以进行反向传播从而节省内存和计算资源。 原因当确定某些操作如参数更新不需要参与梯度计算时使用 torch.no_grad() 可以提高效率。特别是在推理阶段或手动更新参数时我们通常不需要追踪这些操作的梯度。
将param.grad.zero_()的原因主要有
将当前参数的梯度设置为零。这是因为在默认情况下PyTorch 的反向传播会累加梯度而不是覆盖它们。如果不重置梯度那么在下一次反向传播时新计算出的梯度会被加到旧的梯度上导致不正确的更新。为什么需要这样做每次参数更新后我们应该清除之前的梯度信息以便于下一轮迭代中正确地计算新的梯度并进行更新。
8.训练 现在结合上面的过程进行训练
if __name__ __main__:true_w torch.tensor([2, -3.4])true_b 4.2features, labels synthetic_data(true_w, true_b, 1000)# print(output features:, features)# print(foutput labels: {labels})## d2l.set_figsize()# # 这里的detach是从pytorch detach出来之后才能转到numpy中# d2l.plt.scatter(features[:, 0].detach().numpy(), labels.detach().numpy(), 1);## # d2l.plt.show()## # features就是自变量输入值;labels是标签这个就是因变量输出值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_gradTrue)b torch.zeros(1, requires_gradTrue)# 训练的过程lr 0.03 # 学习率num_epochs 3 # 把数据扫3遍net linreg # 模型就是我们linreg之所以这样写就是后续可以快速替换为其他模型loss squared_loss # 均方损失for epoch in range(num_epochs):for X, y in data_iter(batch_size, features, labels):l loss(net(X, w, b), y)l.sum().backward() # 求和之后计算梯度sgd([w,b], lr, batch_size)with torch.no_grad():train_l loss(net(features, w, b), labels)print(fepoch {epoch 1}, loss {float(train_l.mean()):f})print(fw的估计误差: {true_w - w.reshape(true_w.shape)})print(fb的估计误差: {true_b - b})
输出如下所示