概述

 

本文主要记录个人学习Pytorch的过程,因为最近在尝试用Pytorch搭建神经网络,但是对Pytorch缺少整体的了解,导致在使用过程中存在这样或者那样的问题。记录主要分为三个部分。

  • 结合pytorch官网上的60分钟示例,对pytorch的使用有个整体的认识。

  • 使用tensorboard可视化网络模型。

  • torchaudio使用。

 

Pytorch初体验

利用Pytorch训练神经网络的步骤比较简单,主要分为以下几个步骤:

  • 加载数据集。

  • 定义网络结构

  • 定义损失函数以及优化器

  • 保存模型

加载数据集

Pytorch中和数据集相关的两个模块是DataSetDataLoader,其中DataSet里定义了数据和标签的获得方式,而DataLoader能让我们以迭代的方式处理DataSet。加载Pytorch自带的数据集时,可以直接使用如下代码。

 

training_data = datasets.FashionMNIST(    root='data',    train=True,    download=True,    transform=ToTensor())test_data = datasets.FashionMNIST(    root='data',    train=False,    download=True,    transform=ToTensor())

 

 

但是实际中一般会重写Dataset类来操作自己的数据集。重写DataSet类必须实现三个方法:__init__,__len__以及__getitem__,其它的方法可根据需要实现。

 

 

class CustomImageData(Dataset):    # 初始化    def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):        self.img_labels = pd.read_csv(annotations_file)        self.img_dir = img_dir        self.transform = transform        self.target_transform = target_transform    # 数据集大小    def __len__(self):        return len(self.img_labels)    # 得到数据和标签    def __getitem__(self, idx):        img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])        image = read_image(img_path)        label = self.img_labels.iloc[idx, 1]        if self.transform:            image = self.transform(image)        if self.target_transform:            label = self.target_transform(label)        sample = {"image": image, "label": label}        return sample

 

 

然后再使用DataLoader,可以转成可迭代对象。

 

batch_size = 64train_dataloader = DataLoader(training_data, batch_size=batch_size, shuffle=True)test_dataloader = DataLoader(test_data, batch_size=batch_size, shuffle=True)

 

这样就可以直接访问该数据了。

 

train_features, train_labels = next(iter(train_dataloader))print(f"Feature batch shape: {train_features.size()}")print(f"Labels batch shape: {train_labels.size()}")

 


 

 

定义网络结构

数据搞定以后,就要定义神经网络结构了。Pytorch定义网络结构也很方便。通过创建一个继承自nn.Module的类,在__init__中定义网络中的模块,然后在forward()函数中定义数据的流通方向。一个简单的例子如下

 

 

class NeuralNetwork(nn.Module):    def __init__(self):        super(NeuralNetwork, self).__init__()        self.flatten = nn.Flatten()        self.linear_relu_stack = nn.Sequential(            nn.Linear(28 * 28, 512),            nn.ReLU(),            nn.Linear(512, 512),            nn.ReLU(),            nn.Linear(512, 10),            nn.ReLU()        )    def forward(self, x):        x = self.flatten(x)        logits = self.linear_relu_stack(x)        return logits

另外为了加速神经网络的运算速度,可以将其放到GPU进行计算。

 

# 设备是否支持cudadevice = "cuda" if torch.cuda.is_available() else "cpu"print("Using {} device".format(device))# 创建NeuralNetwork实例并将其放到gpu上model = NeuralNetwork().to(device)print(model)

 

 

Pytorch初体验_java

 

定义损失函数和优化器

神经网络结构定义完成后,接下来就需要定义损失函数以及优化器了。Pytorch中包含了大多数的损失函数,比如NLLLoss,GaussianNLLLoss,MSELoss等等。如果Pytorch中没有所需要的损失函数,那么就需要自己定义了。

 

loss_fn = nn.CrossEntropyLoss()

另外Pytorch中在torch.optim中定义了大量的优化器,比如SGD, Adam,RMSprop等等,这些优化器可以直接使用。

 

optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
训练并保存保存模型

在数据集、网络结构、损失函数以及优化器都定义完之后,就可一开始训练了。训练部分的代码结构基本上也比较固定。

  • 读取数据和标签

  • 计算预测值

  • 计算损失函数值

  • 损失函数后向传播,在后向传播之前,需要清零梯度,不然梯度会累积。

  • 参数更新

 

# 训练代码def train(dataloader, model, loss_fn, optimizer):    size = len(dataloader.dataset)    for batch, (X, y) in enumerate(dataloader):        X, y = X.to(device), y.to(device)        # 计算预测误差        pred = model(X)        loss = loss_fn(pred, y)        # 后向传播        optimizer.zero_grad()        loss.backward()        optimizer.step()        if batch % 100 == 0:            loss, current = loss.item(), batch * len(X)            print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")# testdef test(dataloader, model):    size = len(dataloader.dataset)    model.eval()    test_loss, correct = 0, 0    with torch.no_grad():        for X, y in dataloader:            X, y = X.to(device), y.to(device)            pred = model(X)            test_loss += loss_fn(pred, y).item()            correct += (pred.argmax(1) == y).type(torch.float).sum().item()    test_loss /= size    correct /= correct    print(f"Test Error: \n Accuracy: {(100 * correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")# 网络训练epoch = 1for t in range(epoch):    print(f"Epoch {t + 1}\n-------------------------------")    train(train_dataloader, model, loss_fn, optimizer)    test(test_dataloader, model)print("Done")
 

Pytorch初体验_java_02

 

网络训练完成后,需要将模型进行保存,Pytorch中使用torch.save()来保存所训练的模型。

 

# 保存模型torch.save(model.state_dict(), "model.pth")print("Saved PyTorch Model State to model.pth")# 加载模型# 先定义网络model = NeuralNetwork()# 然后加载网络模型权重model.load_state_dict(torch.load("model.pth"))另外也可以查看模型中具体层的参数
model1 = NeuralNetwork()model1.load_state_dict(torch.load('model.pth'))print("model1 is load successfully")print("Model structure: ", model1, "\n\n")for name, param in model1.named_parameters(): print(f"Layer: {name} | Size: {param.size()} | Values : {param[:2]} \n")

 

Pytorch初体验_java_03

 

这样使用Pytorch训练神经网络的基本过程已经介绍完了,流程上还是很清晰的。实际使用中,网络结构,数据集,损失函数可能需要自己重新定义。

 

总结

 

使用Pytorch的一般流程总结如下。

  • 加载数据集

    • 若数据集Pytorch中已有,可以直接加载数据集

    • 如果数据集Pytorch中没有,需要重写DataSet类,并实现__init__,__len__以及__getitem__这三个方法。

  • 定义网络结构

  • 定义损失函数和优化器

    • Pytorch中包含了大量的损失函数,可以直接使用。如果需要自定义损失函数,需要继承nn.Module并实现forward函数。

  • 保存和加载模型

    • 保存模型:torch.save(model.parameters(),'')

    • 记载模型:model1.load_state_dict(torch.load('model.pth'))https://mp.weixin.qq.com/s/vgDxz6JwkUKLbnzn4eewNw