学习进度:【18/73】
实战:房价预测
李沐【动手学深度学习】15实战kaggle房价预测_李沐深度学习kaggle实战-CSDN博客
李沐15学习笔记详解:kaggle竞赛房价预测_kaggle房价预测 + 课程竞赛-CSDN博客
一上来就错。。。所以我转战去了飞桨,主要是理解过程
导入包
回归模型可以理解为:存在一个点集,用一条曲线去拟合它分布的过程。如果拟合曲线是一条直线,则称为线性回归。如果是一条二次曲线,则被称为二次回归。线性回归是回归模型中最简单的一种。
假设函数
假设函数是指,用数学的方法描述自变量和因变量之间的关系,它们之间可以是一个线性函数或非线性函数。 在本次线性回顾模型中,我们的假设函数为 Y^=aX1+bY^=aX1+b ,其中,Y^Y^表示模型的预测结果(预测房价),用来和真实的Y区分。模型要学习的参数即:a,b。
损失函数
损失函数是指,用数学的方法衡量假设函数预测结果与真实值之间的误差。这个差距越小预测越准确,而算法的任务就是使这个差距越来越小。
建立模型后,我们需要给模型一个优化目标,使得学到的参数能够让预测值Y^尽可能地接近真实值Y。输入任意一个数据样本的目标值yi和模型给出的预测值Yi^,损失函数输出一个非负的实值。这个实值通常用来反映模型误差的大小。
对于线性模型来讲,最常用的损失函数就是均方误差(Mean Squared Error, MSE)。即对于一个大小为n的测试集,MSE是n个数据预测结果误差平方的均值。
优化算法
在模型训练中优化算法也是至关重要的,它决定了一个模型的精度和运算速度。这个的线性回归实例中主要使用了梯度下降法进行优化。
梯度下降是深度学习中非常重要的概念,值得庆幸的是它也十分容易理解。损失函数J(w,b)可以理解为变量w和b的函数。观察下图,垂直轴表示损失函数的值,两个水平轴分别表示变量w和b。实际上,可能是更高维的向量,但是为了方便说明,在这里假设w和b都是一个实数。算法的最终目标是找到损失函数的最小值。而这个寻找过程就是不断地微调变量w和b的值,一步一步地试出这个最小值。而试的方法就是沿着梯度方向逐步移动。本例中让图中的圆点表示损失函数的某个值,那么梯度下降就是让圆点沿着曲面下降,直到取到最小值或逼近最小值。
因为是凸函数,所以无论初始化在曲面上的哪一点,最终都会收敛到同一点或者相近的点。
深度学习计算
层和块
chapter_deep-learning-computation/model-construction.ipynb
块
块(block)可以描述单个层、由多个层组成的组件或整个模型本身。 使用块进行抽象的一个好处是可以将一些块组合成更大的组件, 这一过程通常是递归的。
从编程的角度来看,块由类(class)表示。 它的任何子类都必须定义一个将其输入转换为输出的前向传播函数, 并且必须存储任何必需的参数。 注意,有些块不需要任何参数。 最后,为了计算梯度,块必须具有反向传播函数。 在定义我们自己的块时,由于自动微分提供了一些后端实现,我们只需要考虑前向传播函数和必需的参数。
块需要提供的基本功能
①将输入数据作为其前向传播函数的参数。
②通过前向传播函数来生成输出。注:输出的形状可能与输入的形状不同。
③计算其输出关于输入的梯度,可通过其反向传播函数进行访问。通常这是自动发生的。
④存储和访问前向传播计算所需的参数。
⑤根据需要初始化模型参数。
自定义块
它包含一个多层感知机,其具有256个隐藏单元的隐藏层和一个10维输出层。 注意,下面的MLP类继承了表示块的类。我们的实现只需要提供我们自己的构造函数(Python中的__init__函数)和前向传播函数。
__init__函数通过super().init() 调用父类的__init__函数, 省去了重复编写模版代码的痛苦。 然后,实例化两个全连接层, 分别为self.hidden和self.out。 注意,除非我们实现一个新的运算符, 否则我们不必担心反向传播函数或参数初始化, 系统将自动生成这些。
顺序块
Sequential的设计是为了把其他模块串起来。 为了构建我们自己的简化的MySequential, 我们只需要定义两个关键函数:
①一种将块逐个追加到列表中的函数。
②一种前向传播函数,用于将输入按追加块的顺序传递给块组成的“链条”。
_modules:__init__函数将每个模块逐个添加到有序字典_modules中,_modules的主要优点是: 在模块的参数初始化过程中, 系统知道在_modules字典中查找需要初始化参数的子块。
参数管理
chapter_deep-learning-computation/parameters.ipynb
从已有模型中访问参数。 当通过Sequential类定义模型时, 可以通过索引来访问模型的任意层。 这就像模型是一个列表一样,每层的参数都在其属性中。 如下所示,我们可以检查第二个全连接层的参数。
print(net[2].state_dict())来查看
提取目标参数
从第二个全连接层(即第三个神经网络层)提取偏置, 提取后返回的是一个参数类实例,并进一步访问该参数的值:
参数是复合的对象,包含值、梯度和额外信息。 这就是我们需要显式参数值的原因。 除了值之外,我们还可以访问每个参数的梯度。 在上面这个网络中,由于我们还没有调用反向传播,所以参数的梯度处于初始状态
一次性访问所有参数
当我们需要对所有参数执行操作时,逐个访问它们可能会很麻烦。 当我们处理更复杂的块(例如,嵌套块)时,情况可能会变得特别复杂, 因为我们需要递归整个树来提取每个子块的参数。 下面,我们将通过演示来比较访问第一个全连接层的参数和访问所有层
另一种访问网络参数的方式
从嵌套块收集参数
定义一个生成块的函数(可以说是“块工厂”),然后将这些块组合到更大的块中。
参数初始化
深度学习框架提供默认随机初始化, 也允许我们创建自定义初始化方法, 满足我们通过其他规则实现初始化权重。默认情况下,PyTorch会根据一个范围均匀地初始化权重和偏置矩阵, 这个范围是根据输入和输出维度计算出的。 PyTorch的nn.init模块提供了多种预置初始化方法。
①内置初始化
下面的代码将所有权重参数初始化为标准差为0.01的高斯随机变量, 且将偏置参数设置为0
还可以将所有参数初始化为给定的常数,比如初始化为1:
我们还可以对某些块应用不同的初始化方法。 例如,下面我们使用Xavier初始化方法初始化第一个神经网络层, 然后将第三个神经网络层初始化为常量值42:
②自定义初始化
使用以下的分布为任意权重参数 𝑤 定义初始化方法
可以直接设置参数
参数绑定
在多个层间共享参数: 我们可以定义一个稠密层,然后使用它的参数来设置另一个层的参数。
第三个和第五个神经网络层的参数是绑定的。 它们不仅值相等,而且由相同的张量表示。 因此,如果我们改变其中一个参数,另一个参数也会改变。 你可能会思考:当参数绑定时,梯度会发生什么情况? 答案是由于模型参数包含梯度,因此在反向传播期间第二个隐藏层 (即第三个神经网络层)和第三个隐藏层(即第五个神经网络层)的梯度会加在一起。
自定义层
chapter_deep-learning-computation/custom-layer.ipynb
不带参数的层
带参数的层
定义具有参数的层, 这些参数可以通过训练进行调整。 我们可以使用内置函数来创建参数,这些函数提供一些基本的管理功能。 比如管理访问、初始化、共享、保存和加载模型参数。 这样做的好处之一是:我们不需要为每个自定义层编写自定义的序列化程序。
现在,让我们实现自定义版本的全连接层。该层需要两个参数,一个用于表示权重,另一个用于表示偏置项。 在此实现中,我们使用修正线性单元作为激活函数。该层需要输入参数:in_units和units,分别表示输入数(输入维度)和输出数(输出维度)。
卷积神经网络
从全连接层到卷积
chapter_convolutional-neural-networks/why-conv.ipynb