## Pytorch神经网络基础

### 层和块

在之前的内容中，我们认识了一些神经网络，比如：线性回归，Softmax回归，多层感知机；他们有的是整个模型，有的是一层神经网络，有的甚至只是一个单元，他们的功能以及复杂程度也各不相同，但他们都有着如下三个特征：

* 接受一些输入
* 产生对应的输出
* 由一组可调整参数描述

对于一些复杂的网络，研究讨论比层大但比整个模型小的部分很有意义，因为复杂的网络中经常有重复出现的部分，每个部分也常常有自己的功能。考虑到上面的三个特征，这就使得我们思考是否可以对这些部分进行一个抽象，这就得到了块的概念：块指单个层，多个层组成的部分，或者整个模型本身。使用块对整个模型进行描述就简便许多，这一过程是递归的，块的内部还可以划分为多个块，直至满足需要为止。

PyTorch帮我们实现了块的大部分所需功能，包括自动求导，我们只需从nn.Module继承并改写其中的一部分就能得到我们需要的块以及模型，具体做法和细节见代码中的注释

### 参数管理

在选择了架构并设置了超参数后，我们就进入了训练阶段。此时，我们的目标是找到使损失函数最小化的模型参数值。经过训练后，我们将需要使用这些参数来做出未来的预测。此外，有时我们希望提取参数，以便在其他环境中复用它们，将模型保存下来，以便它可以在其他软件中执行，或者为了获得科学的理解而进行检查。

此部分主要为代码实现，笔记见代码中的注释

### 延后初始化

有时在建立网络时，我们不会指定网络的输入输出维度，也就不能确定网络的参数形状，深度学习框架支持延后初始化，即当第一次将数据传入模型时自动的得到所有的维度，然后初始化所有的参数。

PyTorch也支持这一点，比如nn.LazyLinear，但本门课程中并未介绍。

### 自定义层

深度学习成功背后的一个因素是神经网络的灵活性：我们可以用创造性的方式组合不同的层，从而设计出适用于各种任务的架构。例如，研究人员发明了专门用于处理图像、文本、序列数据和执行动态规划的层。同样的，对于层而言，深度学习框架并不能满足我们所有的需求，然而，层本身也具有极大的灵活性，我们可以自定义想要的层。

此部分主要为代码实现，笔记见代码中的注释

### 读写文件

到目前为止，我们讨论了如何处理数据，以及如何构建、训练和测试深度学习模型。然而，有时我们希望保存训练的模型，以备将来在各种环境中使用（比如在部署中进行预测）。此外，当运行一个耗时较长的训练过程时，最佳的做法是定期保存中间结果，以确保在服务器电源被不小心断掉时，我们不会损失几天的计算结果。