美文网首页工作生活
【深度学习DL-PyTorch】四、深度学习工具PyTorch

【深度学习DL-PyTorch】四、深度学习工具PyTorch

作者: ChiangCMBA | 来源:发表于2019-11-08 21:33 被阅读0次

    神经网络又称为全连接或密集网络。

    一、张量(Tensor)

    张量(Tensor)是向量和矩阵的泛化形式。所以,张量可以是一维、二维、三维、...六维...等等。
    向量是一位的张量;
    矩阵是二维的张量;
    张量是PyTorch和其他神经网络框架中的基本数据结构。

    特征是指神经网络的输入特征/输入数据

    torch.randn()创建由正态变量组成的张量,即来自正态分布的随机正态变量。
    torch.randn_like()传入一个张量并查看该张量的形状,然后创建形状相同的另一个张量。
    torch.sum()
    可以使用矩阵乘法进行相同的运算,大多数情况下,都建议使用矩阵乘法。因为矩阵乘法更高效,这些线性代数运算已经使用了现代库加快了速度。推荐使用矩阵乘法,因为在 GPU 上使用现代库和高效计算资源使矩阵乘法更高效。
    torch.mm()矩阵乘法更简单,并且对传入的张量要求更严格。必须符合矩阵乘法的条件:第一个矩阵的列数,必须等于第二个矩阵的行数。能够按照预期的方式进行运算。
    torch.matmul() 支持广播,如果传入大小/形状很奇怪的张量,那么可能获得意料之外的输出结果。

    tensor.shape() 在构建神经网络时,最常见的错误是形状错误,所以在设计神经网络架构时很重要的步骤就是,使张量的形状保持匹配
    tensor.reshape()创建一个张量,形状是要求的形状,但是内存中的实际数据没有改变。有时候,它会返回克隆版本,也就是说,它把数据复制到内存中的另一个部分,然后返回该内存部分存储的张量。也就是说,复制数据比直接更改张量形状(不克隆数据)效率要低。
    tensor.resize_() 下划线表示resize_这个方法是原地操作(in-place operation),原地操作是指根本不改变数据,只是改变位于该内存地址中的数据对应的张量。resize_方法的问题在于如果要求的形状比原始张量的元素多或少时,可能会丢失数据或者使用未初始化的内存创建虚假的数据。
    tensor.view()会返回一个新张量包含的数据和旧张量在内存中的一样。不论什么时候,它都只是返回一个新的张量,不会更改内存中的任何数据。如果想获得新的大小使张量具有新的形状和不同数量的元素,就会报错。使用view方法可以确保在更改张量形状时始终获得相同数量的元素。

    • weights.reshape(a, b) 有时候将返回一个新的张量,数据和 weights 的一样,大小为 (a, b);有时候返回克隆版,将数据复制到内存的另一个部分。
    • weights.resize_(a, b) 返回形状不同的相同张量。但是,如果新形状的元素数量比原始张量的少,则会从张量里删除某些元素(但是不会从内存中删除)。如果新形状的元素比原始张量的多,则新元素在内存里未初始化。注意,方法末尾的下划线表示这个方法是原地运算。要详细了解如何在 PyTorch 中进行原地运算,请参阅此论坛话题
    • weights.view(a, b) 将返回一个张量,数据和 weights 的一样,大小为 (a, b)

    torch.from_numpy()
    tensor.numpy()
    需要注意的是:内存会在Numpy数组和torch张量之间共享。也就是说,如果对Numpy数组或张量执行任何原地操作就会改变对方的值。

    二、在PyTorch中构建神经网络

    反向传播_链式法则.png

    如果希望神经网络能够学习非线性关系和规律,希望输出是非线性的,那么就需要在隐藏层里使用非线性激活函数。
    ReLU是线性修正单元的简称,它是最简单的非线性函数,与S型函数和双曲正切函数相比,使用ReLU时网络的训练速度快多了。

    2.1构建神经网络

    PyTorch 提供了nn模块,大大地简化了网络构建过程。以下演示如何构建上述同一个网络,即包含 784 个输入、256 个隐藏单元、10 个输出单元和一个 softmax 输出。

    from torch import nn
    class Network(nn.Module):
        def __init__(self):
            super().__init__()
            
            # Inputs to hidden layer linear transformation
            self.hidden = nn.Linear(784, 256)
            # Output layer, 10 units - one for each digit
            self.output = nn.Linear(256, 10)
            
            # Define sigmoid activation and softmax output 
            self.sigmoid = nn.Sigmoid()
            self.softmax = nn.Softmax(dim=1)
            
        def forward(self, x):
            # Pass the input tensor through each of our operations
            x = self.hidden(x)
            x = self.sigmoid(x)
            x = self.output(x)
            x = self.softmax(x)
            
            return x
    
    
    class Network(nn.Module):
    

    先继承 nn.Module。与 super().__init__() 相结合,创建一个跟踪架构的类,并提供大量有用的方法和属性。注意,在为网络创建类时,必须继承 nn.Module。类可以随意命名。

    self.hidden = nn.Linear(784, 256)
    

    这行创建一个线性转换模块 x\mathbf{W} + b,其中有 784 个输入和 256 个输出,并赋值给 self.hidden。该模块会自动创建权重和偏差张量,供我们在 forward 方法中使用。创建网络 (net) 后,你可以使用 net.hidden.weightnet.hidden.bias 访问权重和偏差张量。

    self.output = nn.Linear(256, 10)
    

    同样,这里会创建另一个有 256 个输入和 10 个输出的线性转换。

    self.sigmoid = nn.Sigmoid()
    self.softmax = nn.Softmax(dim=1)
    

    然后,定义了 S 型激活函数和 softmax 输出的运算。在 nn.Softmax(dim=1) 中设置 dim=1 会计算各个列的 softmax 值。

    def forward(self, x):
    

    nn.Module 创建的 PyTorch 网络必须定义 forward 方法。它会接受一个张量 x 并将其传入你在 __init__ 方法中定义的运算。

    x = self.hidden(x)
    x = self.sigmoid(x)
    x = self.output(x)
    x = self.softmax(x)
    

    将输入张量 x 传入重新赋值给 x 的每个运算。可以看出输入张量经过隐藏层,然后经过 S 型函数、输出层,最终经过 softmax 函数。.变量可以命名为任何名称,只要运算的输入和输出与你要构建的网络架构匹配即可。在 __init__ 方法中的定义顺序不重要,但是需要在 forward 方法中正确地设定运算顺序。

    现在我们可以创建一个 Network 对象。

    # Create the network and look at it's text representation
    model = Network()
    model
    

    可以使用 torch.nn.functional 模块来更简练清晰地定义网络。这是最常见的网络定义方式,因为很多运算是简单的元素级函数。我们通常将此模块导入为 F,即 import torch.nn.functional as F

    import torch.nn.functional as F
    
    class Network(nn.Module):
        def __init__(self):
            super().__init__()
            # Inputs to hidden layer linear transformation
            self.hidden = nn.Linear(784, 256)
            # Output layer, 10 units - one for each digit
            self.output = nn.Linear(256, 10)
            
        def forward(self, x):
            # Hidden layer with sigmoid activation
            x = F.sigmoid(self.hidden(x))
            # Output layer with softmax activation
            x = F.softmax(self.output(x), dim=1)
            
            return x
    
    2.2 激活函数

    到目前为止,我们只学习了 softmax 激活函数,但是通常任何函数都可以用作激活函数。但是,要使网络能逼近非线性函数,激活函数必须是非线性函数。下面是一些常见的激活函数示例:Tanh(双曲正切)和 ReLU(修正线性单元)。

    activation.png

    在实践中,ReLU 几乎一直用作隐藏层激活函数。

    2.3 使用 nn.Sequential

    PyTorch 提供了一种方便的方法来构建这类网络(其中张量按顺序执行各种运算):nn.Sequential (文档)。使用它来构建等效网络:

    # Hyperparameters for our network
    input_size = 784
    hidden_sizes = [128, 64]
    output_size = 10
    
    # Build a feed-forward network
    model = nn.Sequential(nn.Linear(input_size, hidden_sizes[0]),
                          nn.ReLU(),
                          nn.Linear(hidden_sizes[0], hidden_sizes[1]),
                          nn.ReLU(),
                          nn.Linear(hidden_sizes[1], output_size),
                          nn.Softmax(dim=1))
    print(model)
    
    # Forward pass through the network and display output
    images, labels = next(iter(trainloader))
    images.resize_(images.shape[0], 1, 784)
    ps = model.forward(images[0,:])
    helper.view_classify(images[0].view(1, 28, 28), ps)
    

    还可以传入 OrderedDict 以命名单个层级和运算,而不是使用递增的整数。注意,因为字典键必须是唯一的,所以每个运算都必须具有不同的名称

    from collections import OrderedDict
    model = nn.Sequential(OrderedDict([
                          ('fc1', nn.Linear(input_size, hidden_sizes[0])),
                          ('relu1', nn.ReLU()),
                          ('fc2', nn.Linear(hidden_sizes[0], hidden_sizes[1])),
                          ('relu2', nn.ReLU()),
                          ('output', nn.Linear(hidden_sizes[1], output_size)),
                          ('softmax', nn.Softmax(dim=1))]))
    model
    

    三、训练神经网络

    3.1Autograd 自动计算梯度

    我们已经知道如何计算损失,那么如何使用损失进行反向传播呢?Torch 提供了模块 autograd,用于自动计算张量的梯度。我们可以使用它计算所有参数相对于损失的梯度。Autograd 的计算方式是跟踪对张量执行的运算,然后反向经过这些运算并一路计算梯度。为了确保 PyTorch 能跟踪对张量执行的运算并计算梯度,你需要在张量上设置 requires_grad = True。你可以在创建时使用 requires_grad 关键字或随时使用 x.requires_grad_(True)
    可以使用 torch.no_grad() 关闭某段代码的梯度:

    x = torch.zeros(1, requires_grad=True)
    >>> with torch.no_grad():
    ...     y = x * 2
    >>> y.requires_grad
    False
    
    3.2损失和 Autograd

    使用 PyTorch 创建网络时,所有参数都通过 requires_grad = True 初始化。这意味着,当我们计算损失和调用 loss.backward() 时,会计算参数的梯度。这些梯度用于在梯度下降步骤中更新权重。下面是使用反向传播计算梯度的示例。

    # Build a feed-forward network
    model = nn.Sequential(nn.Linear(784, 128),
                          nn.ReLU(),
                          nn.Linear(128, 64),
                          nn.ReLU(),
                          nn.Linear(64, 10),
                          nn.LogSoftmax(dim=1))
    
    criterion = nn.NLLLoss()
    images, labels = next(iter(trainloader))
    images = images.view(images.shape[0], -1)
    
    logps = model(images)
    loss = criterion(logps, labels)
    
    3.3Autograd 自动计算梯度

    PyTorch训练网络 的一般流程是:

    • 通过网络进行正向传递以获取logits
    • 使用 logits 计算损失
    • 通过 loss.backward() 对网络进行反向传递以计算梯度
    • 使用优化器更新权重
    model = nn.Sequential(nn.Linear(784, 128),
                          nn.ReLU(),
                          nn.Linear(128, 64),
                          nn.ReLU(),
                          nn.Linear(64, 10),
                          nn.LogSoftmax(dim=1))
    
    criterion = nn.NLLLoss()
    optimizer = optim.SGD(model.parameters(), lr=0.003)
    
    epochs = 5
    for e in range(epochs):
        running_loss = 0
        for images, labels in trainloader:
            # Flatten MNIST images into a 784 long vector
            images = images.view(images.shape[0], -1)
        
            # TODO: Training pass
            optimizer.zero_grad()
            
            output = model.forward(images)
            loss = criterion(output, labels)
            loss.backward()
            
            optimizer.step()
            
            running_loss += loss.item()
        else:
            print(f"Training loss: {running_loss/len(trainloader)}")
    
    

    四、训练神经网络的基本步骤

    • 1.清空所有已优化变量的梯度
    • 2.前向传播:通过向模型传入输入,计算预测输出。
    • 3.计算损失
    • 4.反向传播:计算损失相对于模型参数的梯度
    • 5.执行一个优化步骤(参数更新)
    • 6.更新平均训练损失

    The steps for training/learning from a batch of data are described in the comments below:

    • 1.Clear the gradients of all optimized variables
    • 2.Forward pass: compute predicted outputs by passing inputs to the model
    • 3.Calculate the loss
    • 4.Backward pass: compute gradient of the loss with respect to model parameters
    • 5.Perform a single optimization step (parameter update)
    • 6.Update average training loss
    # number of epochs to train the model
    n_epochs = 30  # suggest training between 20-50 epochs
    
    model.train() # prep model for training
    
    for epoch in range(n_epochs):
        # monitor training loss
        train_loss = 0.0
        
        ###################
        # train the model #
        ###################
        for data, target in train_loader:
            # clear the gradients of all optimized variables
            optimizer.zero_grad()
            # forward pass: compute predicted outputs by passing inputs to the model
            output = model(data)
            # calculate the loss
            loss = criterion(output, target)
            # backward pass: compute gradient of the loss with respect to model parameters
            loss.backward()
            # perform a single optimization step (parameter update)
            optimizer.step()
            # update running training loss
            train_loss += loss.item()*data.size(0)
            
        # print training statistics 
        # calculate average loss over an epoch
        train_loss = train_loss/len(train_loader.dataset)
    
        print('Epoch: {} \tTraining Loss: {:.6f}'.format(
            epoch+1, 
            train_loss
            ))
    
    

    相关文章

      网友评论

        本文标题:【深度学习DL-PyTorch】四、深度学习工具PyTorch

        本文链接:https://www.haomeiwen.com/subject/ravlhctx.html