Getting Started with Pytorch and Tensors
作者:禅与计算机程序设计艺术
1.简介
PyTorch是一个基于Python语言开发的开源机器学习框架,默认由Facebook公司维护并提供技术支持服务。其显著优势在于支持在普通处理器(CPU)或图形处理器(GPU)上实现高效的运算能力,并通过内置的自动微分机制(autograd)和多种优化算法(optimizers)提升模型训练效率的同时还为不同应用场景设计了模块化化的接口体系(module API)。该框架的主要开发者包括Facebook的研究人员及技术团队等优秀人才。近年来随着深度学习技术的快速发展PyTorch已经成为全球科研界最具影响力的主要深度学习框架之一并且以其快速迭代更新和广泛的应用前景吸引了越来越多的研究机构企业以及个人的关注与投入。作为一个功能强大的深度学习框架PyTorch拥有庞大的用户基础涵盖了高校研究机构以及产业界等多个领域的人才群体因此掌握该技术的核心知识点及其实际应用方法对于个人职业发展以及未来深入研究深度学习都具有重要的现实意义与价值所在。本文将通过系统介绍PyTorch的基本概念与操作流程帮助读者全面了解这一强大工具并为其后续深入学习与实践应用奠定坚实的基础此外本文还将结合多个典型实例深入探讨如何利用PyTorch实现一系列经典的深度学习任务
2. 基本概念术语说明
2.1 Tensor
深度学习模型中的输入数据多为向量形式表示的数据,即它们都可以以向量的形式存在。因此,在PyTorch框架中,我们将向量子数据组织成张量(tensor)的形式。其中,一个张 tensor 是一个n维数组结构,其中n代表张 tensor 的阶数(rank)。具体而言:
- 当n=0时,则为标量化(scalar),即单一数值;
 - 当n=1时,则为一维数组(vector);
 - 当n=2时,则为二维数组(matrix);
 - 当n≥3时,则被统称为高维数组(tensor)。
 
2.2 Autograd
该算法在深度学习领域发挥着关键作用,在训练神经网络的过程中扮演着核心角色。
通过上下文管理器的方式进行操作时能够追踪并计算每一层参数的梯度
如示例代码所示
    import torch
    from torch.autograd import Variable
    
    x = Variable(torch.ones(2), requires_grad=True) # 定义变量
    y = x + 2
    z = y * y 
    out = z.mean()
    print('input:', x)
    print('output:', out)
    
    out.backward() # 求导
    print('grad:', x.grad)
    
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
        输出结果如下:
    input: 
     1  1
    [torch.FloatTensor of size 2]
    
    output: 
     27.0000
    [torch.FloatTensor of size 1]
    
    grad: 
     54.0000
     54.0000
    [torch.FloatTensor of size 2]
    
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
        在此处我们引入了一个输入变量x,其取值设定为(1,1),并将其requires_grad属性设为True以实现该变量对所有其他变量的导数计算功能。随后我们进行了多个运算步骤的具体实施:加法运算用于将各中间结果相加;乘法运算用于将两个相邻节点的结果相乘;平方操作则用于对每个中间结果进行二次幂运算;平均值计算则用于将总和除以节点数量以获得最终平均值。最终调用autograd库中的backward函数进行梯度计算后得到了张量x相对于整个计算图的梯度值(54.0, 54.0)
2.3 Module
模块在PyTorch中扮演着核心角色。作为一个抽象概念模块可以在神经网络架构中被看作是一个由多个神经元组成的集合体但这一概念并不局限于特定领域应用。在PyTorch框架内我们通常会定义一个继承自torch.nn.Module类的对象来表示一个模块该对象不仅承载着可学习的权重参数还负责构建网络架构并执行前向传播过程当模块实例化后会自动接收输入数据进行处理生成输出结果同时还会集成反向传播机制负责更新模型参数类似于神经元组件模块内部包含了大量可调谐权重参数。为了方便操作通常我们需要导入nn模块并利用其提供的高级功能库就可以轻松地构建复杂的深度学习模型。
    import torch.nn as nn
    
    class Net(nn.Module):
    
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(500, 200)
        self.fc2 = nn.Linear(200, 10)
    
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x)
    
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
        该网络包含了两个全连接层结构设计。其中第一个全连接层接收了500个输入特征并生成200维的表示结果,并采用ReLU作为激活函数以引入非线性特性;随后第二个全连接层基于上一层输出的200维特征进一步降维为10维的概率分布估计,并选用Softmax函数对其进行归一化处理以满足分类任务的需求
2.4 Optimization Algorithm
深度学习模型通常需要经过多次迭代方能达到最佳效果。在PyTorch框架中,我们能够利用优化器库中的多种优化算法来进行模型训练。常见的优化算法包括Adagrad、SGD(随机梯度下降)和Adam(基于梯度的自适应矩估计)等。以下是一个使用SGD优化器进行神经网络训练的例子:
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=args.momentum)
    
    for epoch in range(args.epochs):
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        inputs, labels = data
    
        optimizer.zero_grad()
    
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
    
        running_loss += loss.data[0]
    
    print('[%d] loss: %.3f' % (epoch+1, running_loss / len(trainset)))
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
        在本研究中, 我们构建了交叉熵损失函数(CrossEntropyLoss), 并设定学习率为lr=0.001, 同时配置动量参数为momentum=0.9, 采用了SGD优化算法来进行模型迭代运算。具体而言, 我们通过遍历整个训练数据集, 每次从数据集中选取一批样本用于训练, 在这一过程中, 首先清除当前梯度, 计算当前批次的损失值, 对损失函数进行反向传播并计算梯度值, 最终通过优化器更新模型权重参数以最小化整体误差指标。经过持续迭代, 模型表现出逐渐减小的平均损失值趋势, 最终收敛于最优解状态
3. Core Algorithms and Operations
下面我们将重点讲解PyTorch的关键算法设计。其中包含了深度学习领域的主要技术路线包括但不限于卷积神经网络循环神经网络以及基于注意力机制的序列到序列模型等前沿研究方向
3.1 Convolutional Neural Networks(CNNs)
卷积神经网络(Convolutional Neural Network, CNN)是深度学习领域中经典的模型。它可以处理图像、语音、视频等多媒体数据,并且通常比传统的全连接神经网络(Fully Connected Neural Network, FCN)或其他更复杂的神经网络表现更好。它的主要特点是使用卷积层代替全连接层来提取特征。卷积层在空间维度上扫描输入图像,提取图像区域之间的相似模式,并生成中间特征图。之后,这些特征图被送到分类器或回归器进行进一步处理。下面是一个利用卷积层训练MNIST数据集的示例:
    import torchvision
    import torchvision.transforms as transforms
    import torch.optim as optim
    import torch.nn as nn
    
    transform = transforms.Compose([
                               transforms.ToTensor(),
                               transforms.Normalize((0.5, ), (0.5,))
                              ])
    
    trainset = torchvision.datasets.MNIST(root='./data', train=True,
                                        download=True, transform=transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=True, num_workers=2)
    
    class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)
    
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x
    
    
    net = Net()
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
    
    for epoch in range(2):    # loop over the dataset multiple times
    
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs
        inputs, labels = data
    
        # zero the parameter gradients
        optimizer.zero_grad()
    
        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
    
        # print statistics
        running_loss += loss.item()
    
    print('[%d] loss: %.3f' % (epoch+1, running_loss / len(trainloader)))
    
    print('Finished Training')
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
        在本研究中,我们构建了一个由两个卷积层和三层全连接网络构成的架构.该网络由多个组件模块组成,其中每个卷积模块均采用[5\times 5]尺寸,而每个池化模块的池化窗口尺寸设定为[2\times 2].在整个训练过程中,默认采用CrossEntropyLoss作为损失函数,并结合SGD优化器进行参数更新.经过持续训练后发现,在每一轮迭代中损失值呈现持续下降趋势,并最终稳定在理想状态.
3.2 Recurrent Neural Networks(RNNs)
在深度学习领域中,循环神经网络(Recurrent Neural Network, RNN)被视为一类经典的模型。它主要应用于序列数据的预测与建模任务。其核心优势在于能够存储信息并记住过去的数据,并能有效处理长程依赖关系的问题。通常情况下,RNN架构由多个循环单元构成,每个循环单元不仅接收当前输入信号以及前一时刻的状态表示,并生成新的状态和输出信号。这种机制使得RNN在处理不同长度的序列时具有良好的适应性,在实际应用中表现出色的例子包括但不限于以下情况:下面是一个利用RNN进行语言模型训练的示例:
    import torch.nn as nn
    import torch.nn.functional as F
    
    class RNN(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(RNN, self).__init__()
    
        self.hidden_dim = hidden_dim
    
        self.i2h = nn.Linear(input_dim + hidden_dim, hidden_dim)
        self.i2o = nn.Linear(input_dim + hidden_dim, output_dim)
        self.softmax = nn.LogSoftmax(dim=1)
    
    def forward(self, input, hidden):
        combined = torch.cat((input, hidden), 1)
        hidden = self.i2h(combined)
        output = self.i2o(combined)
        output = self.softmax(output)
        return output, hidden
    
    def initHidden(self):
        return torch.zeros(1, self.hidden_dim)
    
    
    def categoryFromOutput(output):
    top_n, top_i = output.topk(1)
    category_i = top_i[0].item()
    return categories[category_i], category_i
    
    
    rnn = RNN(n_letters, 128, n_categories)
    
    learning_rate = 0.005
    criterion = nn.NLLLoss()
    optimizer = torch.optim.SGD(rnn.parameters(), lr=learning_rate)
    
    for epoch in range(n_epochs):
    for i, (inputs, labels) in enumerate(training_data):
        hidden = rnn.initHidden()
    
        inputs = inputs.reshape(len(inputs), 1, -1)
        outputs = []
    
        for input in inputs:
            output, hidden = rnn(input, hidden)
            outputs.append(output)
    
        loss = criterion(torch.stack(outputs), labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    
        if (i+1)%100 == 0:
            print('Epoch [%d/%d], Step [%d/%d], Loss: %.4f'
                  %(epoch+1, n_epochs, i+1, len(training_data), loss.item()))
    
    def predict(input):
    hidden = rnn.initHidden()
    
    input = letterToTensor(input).reshape(1, 1, -1)
    
    for i in range(max_length):
        output, hidden = rnn(input, hidden)
    
        _, topi = output.topk(1)
        ni = topi[0][0].item()
    
        if ni == n_letters-1:
            break
    
        input = variable(letterToTensor(all_letters[ni]))
        input = input.reshape(1, 1, -1)
    
    return ''.join(map(lambda x : all_letters[int(x)], output))
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读
        在本研究中,在这里我们构建了一个基于长短期记忆单元(LSTM)设计的单隐层RNN模型,在每一个时间步长中都采用了带有teacher forcing策略的优化方法。该模型具有输入、输出向量空间分别为n个字母和n类分类任务目标的空间维度设定,并且其中隐层的空间维度设定为128维。该网络在训练过程中会利用当前状态信息来预测后续输入,在完成训练后可以通过调用预测函数可推断新样本类别。例如:"How are you?"这个简单的查询就可以被该系统处理并给出响应结果。
3.3 Sequence-to-Sequence Models
该种模型在深度学习领域发挥着重要作用
            
            
              python import torch.nn as nn import torch.nn.functional as F from torch.autograd import Variable
              
              
              
            
          
          class EncoderRNN(nn.Module): def **init**(self, input_size, hidden_size): super(EncoderRNN, self).**init**() self.hidden_size = hidden_size
        将嵌入层初始化为nn.Embedding(input_size,hidden_size)的实例
def forward(self, inputs):
embedded_representation = self.embedding(inputs).view(1, 1, -1)
the_output = embedded_representation
outputs_and_new_hidden_state = self.gru(the_output.view(1,-1), None)
return outputs_and_new_hidden_state[0], outputs_and_new_hidden_state[1]
def initHidden(self):
return Variable(torch.zeros(1, 1, self.hidden_size))
代码解读
        class DecoderRNN(nn.Module): def **init**(self, hidden_size, output_size): super(DecoderRNN, self).**init**() self.hidden_size = hidden_size
        神经网络中的嵌入层将输出大小设置为output_size,并将隐藏层数量设置为hidden_size。
GRU层接受输入特征数和隐藏层数量均为hidden_size。
线性变换层接受input_features=hidden_size并输出output_features=output_size。
此函数用于执行前向传播过程。
将输入数据通过嵌入层处理并重塑其形状。
对输出结果施加ReLU激活函数。
经过GRU模块处理后得到新的输出状态和隐藏状态。
将前一层的输出传递给全连接层进行计算。
返回当前时间步的输出结果以及新的隐藏状态信息。
def initHidden(self):
return Variable(torch.zeros(1, 1, self.hidden_size))
代码解读
        encoder = EncoderRNN(input_lang.n_words, hidden_size) decoder = AttnDecoderRNN(hidden_size, output_lang.n_words, max_length)
criterion = nn.NLLLoss() params = list(encoder.parameters()) + list(decoder.parameters()) optimizer = torch.optim.Adam(params, lr=learning_rate)
for iter in range(num_iter): training_pair = variablesFromPair(random.choice(pairs)) input_variable = training_pair[0] target_variable = training_pair[1]
        执行训练过程以计算损失值 loss 的过程涉及多个组件包括输入变量 input\_variable 目标变量 target\_variable 编码器 encoder 解码器 decoder 编码器优化器(encoder_optimizer)以及解码器优化器(decoder_optimizer) 等关键参数 并结合损失函数 (criterion) 和教师强制比率 (teacher_forcing_ratio) 以实现模型的学习与改进
print_loss_total += loss
plot_loss_total += loss
        当迭代次数能被print_every整除时执行以下操作:
首先计算当前平均损失值为总损失除以print_every。
接着将总损失重置为零。
最后打印信息:时间为...次迭代所花的时间、当前迭代次数、占总迭代比例以及当前平均损失值。
代码解读
        
        