PyTorch是一款基于自动微分且越来越流行的神经网络框架。
核心数据类型Tensor
首先,手动初始化Tensor:
a = torch.Tensor([[3., 3.],
[3., 3.]], requires_grad=True)
- 像处理ndarray一样,可以通过将其中包含的数据简单地包装在torch.Tensor中来初始化Tensor。
- 当用这种方式初始化Tensor时,必须传递require_grad = True的参数,来告诉Tensor累积梯度。
执行计算:
b = a * 4
c = b + 3
d = (a + 2)
e = c * d
e_sum = e.sum()
e_sum.backward()
如示例,一旦对计算的输出调用backward方法,就可以自动正确计算梯度。
使用PyTorch进行深度学习
- 一个Model类,其中包含Layer类
- 一个Optimizer类
- 一个Loss类
- 一个Trainer类
Model类及其Layer类
PyTorchLayer类可以写成如下形式:
from torch import nn, Tensor
class PyTorchLayer(nn.Module):
def __init__(self) -> None:
super().__init__()
def forward(self, x: Tensor,
inference: bool = False) -> Tensor:
raise NotImplementedError()
PyTorchModel类可以写成如下形式:
class PyTorchModel(nn.Module):
def __init__(self) -> None:
super().__init__()
def forward(self, x: Tensor,
inference: bool = False) -> Tensor:
raise NotImplementedError()
PyTorchLayer类和PyTorchModel类的每个子类都只需要实现__init__()方法和forward()方法,以便直接使用它们。
dropout技术
dropout技术可以改变神经网络的容量,并降低发生过拟合的可能性。
dropout只是简单地在一层中随机选择一定比例的神经元p,并在每次前向传递训练中将它们设置为0。
Dropout类具有两种模式:应用了dropout的训练模式和没有应用dropout的推理模式。
inference标志位
在PyTorch中,可以通过在模型或层(或任何从nn.Module类中继承的对象)上运行m.eval,从而将模型或层从默认的训练模式切换到推理模式。
使用apply函数快速更改层的所有子类的行为:
def inference_mode(m: nn.Module):
m.eval()
在定义的PyTorchLayer类和PyTorchModel类的每个子类的forward方法中都包含如下代码,从而获得预期的标志位:
if inference:
self.apply(inference_mode)
基本要素:DenseLayer类
神经元层的一个关键特征是,每个输出神经元都是所有输入神经元的函数。
每一个新特征都是所有
n
i
n
n_{in}
nin个输入特征的加权线性组合,因此这些层通常称为全连接层(fully connected layer),在Keras库中,它们也被称为Dense层。
class DenseLayer(PyTorchLayer):
def __init__(self,
input_size: int,
neurons: int,
dropout: float = 1.0,
activation: nn.Module = None) -> None:
super().__init__()
self.linear == nn.Linear(input_size, neurons)
self.activation = activation
if dropout < 1.0:
self.dropout = nn.Dropout(1 - dropout)
def forward(self, x: Tensor,
inference: bool = False) -> Tensor:
if inference:
self.apply(inference_mode)
x = self.linear(x) # does weight multiplication + bias
if self.activation:
x = self.activation(x)
if hasattr(self, "dropout"):
x = self.dropout(x)
return x
nn.Linear对象不仅在前向传递中处理权重乘积和增加偏差项,还会累积x的梯度,从而在后向传递中正确计算出损失相对于参数的导数。
DataLoader类和transforms模块
可以对数据应用一个简单的预处理步骤,即减去总体均值并除以标准偏差,从而对数据集进行大致的归一化:
X_train, X_test = X_train - X_train.mean(), X_test - X_test.mean()
X_train, X_test = X_train / X_train.std(), X_test / X_test.std()
在这之前,需要将这两个数组完全读入内存。
在神经网络中,随着批量数据的输入,动态执行此预处理步骤将更加高效。
PyTorch的一些内置功能可以执行此操作,比如通过transforms模块执行转换,以及通过torch.utils.data引入DataLoader类:
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
首先,定义一个转换列表,对读取的每一批数据执行转换操作。
my_transforms = transforms.Compose([
transforms.ToTensor,
transforms.Normalize((0.1305,), (0.3081,))
])
接着,定义DataLoader类来接收此数据集,并定义用于生成批量数据的规则:
dataloader = DataLoader(dataset, batch_size=60, shuffle=True)