• 【pytorch】pytorch学习笔记(一)


    原文地址:https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html

     什么是pytorch?

      pytorch是一个基于python语言的的科学计算包,主要分为两种受众:

    • 能够使用GPU运算取代NumPy
    • 提供最大灵活度和速度的深度学习研究平台

    开始

    Tensors

      Tensors与numpy的ndarray相似,且Tensors能使用GPU进行加速计算。

      

      创建5 * 3的未初始化矩阵:

      

      创建并随机初始化矩阵:

      

      创建一个类型为long且值全为0的矩阵:

      

      直接赋值创建tensor:

      

      使用已有的tensor创建一个tensor,这个方法能使用已有tensor的属性如类型:

      new_* 方法的参数是张量形状大小

      

      重写类型,结果具有相同的形状大小

      

      获取张量的尺寸大小:

      

      注:torch.Size实际上是一个元组,所以它支持所有的元组操作。

    Operations(运算)

      pytorch有多种运算的语法。在下列例子中,我们看一下加法运算:

      加法1

      

      加法2:

      

      加法:提供一个输出tensor作为参数

      

      加法:in-place ( 相当于+= ,将结果直接赋值到左侧的变量)

      

      注:任何方法名中使用“_”的都是in-place操作,比如x.copy_(y),x.t_(),都会使x的值发生改变。

      同时,你也可以使用标准NumPy风格的索引操作:

      

      Resizing:如果你想要resize或reshape一个张量,可以使用方法 torch.view :

      

      如果张量只有一个元素,可以使用.item()来获取一个python数值

      

    NumPy Bridge

      Torch的张量和NumPy数组的相互转换,他们共享底层的内存位置,更改一个另一个也会改变。

      张量转换为NumPy数组

      

      当张量的值改变时,numpy数组的值也同时改变:

      

      Numpy数组转换为张量

      

      除了字符张量,所有在CPU上的张量都能与NumPy数组相互转换。

    CUDA Tensors

      张量能够被转移到任何设备通过使用 .to 方法。

      

    AUTOGRAD: AUTOMATIC DIFFERENTIATION

      autograd包在pytorch中是所有神经网络的核心,我们先看一下然后将会训练自己的神经网络。

      autograd包给所有张量运算提供了自动微分。他是一个运行定义框架(define-by-run framework),意为着被你的代码如何运行所定义,每次的单个迭代都是不同的。

      让我们用简单的术语和一些例子来看下:

    Tensor

      torch.Tensor是核心类。如果你设置了它的属性 .requires_grad为True, 它就开始跟踪所有的运算。当完成所有的计算可以通过 .backward() 然后就可以自动进行所有的梯度计算。该张量的所有梯度将会累加到.grad() 属性。

      通过调用 .detach() 方法可以停止一个张量对计算记录的追踪。

      另一种阻止张量计算追踪的方法是,将代码块写入 with torch.no_grad(): ,这在训练中评价测试一个模型的时候尤其有用,因为我们设置了requires_grad =True,而此时并不需要梯度。

      自动微分的另一个重要实现是类Function。

      Tensor和Function是相互联系的并建立了一个非循环图,记录了计算的完整历史。每个张量有.grad_fn属性,这个属性与创建张量的Function相关联(除了用户自己创建张量,该属性grad_fn is None)

      如果你想要计算导数,你可以调用张量的.backward()方法,如果张量是一个标量,如只有一个元素的数据,则backward()不需要指定任何参数;如果其有更多参数,则需要指定一个具有匹配张量大小的gradient参数。

      创建一个张量并设置 requires_grad = True来追踪计算:

      

      张量运算:

      

      y是作为运算的结果所创建的,所以它有属性 grad_fn。

      

      y的更多运算:

      

      .require_grad_()方法可以改变张量requires_grad的值,如果没指定的话,默认值为False。

      

      

    Gradients

      开始反向传播。因为 out 包含一个单一的标量,out.backward() 相当于 out.backward((torch.tensor(1.))) 。  

      打印梯度d(out)/dx:

    x = [ [1, 1], [1, 1] ]
    
    y = x + 2
    
     z =  y * y * 3
    
    out = z.mean
    
    d(out)/dx = 3/2(x + 2)

      

      

      

      当.requires_grad=True 时,你也可以通过写入代码块with torch.no_grad()停止追踪历史和自动微分:

      

    NEURAL NETWORKS

      torch.nn可以创建神经网络,nn依赖于 autograd 来定义模型和微分。nn.Moudle包括各种层和返回output的方法forward(input)。

      例如,以下为对数字图片进行分类的网络:

      

      一个简单的前馈网络,获得输入并经过一个个网络层,最终得到输出。

      以下是一个神经网络的训练步骤:

    • 定义一个具有可学习参数或权重的神经网络;
    • 对一个数据集的输入进行迭代;
    • 通过网络处理输入;
    • 计算损失
    • 将梯度反向传播给网络参数
    • 更新网络参数,通常的更新方法为 weight weight learning_rategradien

    Define the network

    #encoding:utf-8
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
     
    class Net(nn.Module):
     
        def __init__(self):
            super(Net,self).__init__()
            #定义2个卷积层
            self.conv1=nn.Conv2d(in_channels=1,out_channels=6,kernel_size=5)
            self.conv2=nn.Conv2d(in_channels=6,out_channels=16,kernel_size=5)
            #定义了3个线性层,即y=wx+b
            self.fc1=nn.Linear(in_features=16*5*5,out_features=120)
            self.fc2=nn.Linear(120,84)
            self.fc3=nn.Linear(84,10)
     
        def forward(self, x):
            #在第一层卷积网络和第二层之间增加了relu激活函数和池化层
            x=F.max_pool2d(input=F.relu(input=self.conv1(x)),kernel_size=(2,2))
            #如果池化层是方块形的可以用一个number指定
            x=F.max_pool2d(input=F.relu(input=self.conv2(x)),kernel_size=2)
            x=x.view(-1,self.num_flat_features(x))
            x=F.relu(input=self.fc1(x))
            x=F.relu(self.fc2(x))
            x=self.fc3(x)
            return x
     
        def num_flat_features(self,x):
            size=x.size()[1:]#切片0里面放的是当前训练batch的number,不是特征信息
            num_features=1
            for s in size:
                num_features*=s
            return num_features
    net=Net()
    print(net)
    Net(
      (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
      (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
      (fc1): Linear(in_features=400, out_features=120, bias=True)
      (fc2): Linear(in_features=120, out_features=84, bias=True)
      (fc3): Linear(in_features=84, out_features=10, bias=True)
    )

      你只要定义前向函数,当你使用 autograd 时,后向传播函数将会自动定义。在前向函数中你可以使用任何张量运算。

      模型的可学习参数由 net.parameters() 返回。

    params = list(net.parameters())
    print(len(params))
    print(params[0].size())  # conv1's .weight

      这个网络适合32*32的数据集(1*32*32经过一个核心为5的卷积层,大小变为6*28*28;经过一个核心为2的池化层,大小变为6*14*14;再经过一个核心为5的卷积层,大小变为16*10*10;池化层,16*5*5,正好是下一个线性层的输入特征数),我们随机一个输入数据集,运行一下我们的模型吧:

    input = torch.randn(1, 1, 32, 32)
    out = net(input)
    print(out)
    tensor([[-8.2934e-03, -1.9684e-02, -7.6836e-02,  5.3187e-02,  1.1083e-01,
             -2.5156e-02, -6.1870e-05, -8.3843e-03,  4.1401e-02, -5.8330e-02]],
           grad_fn=<AddmmBackward>)

      将所有参数的梯度设为0,使用随机梯度进行反向传播:

    net.zero_grad()
    out.backward(torch.randn(1, 10))

      注:torch.nn只支持批量数据的处理,而不是单个样本。例如,nn.Conv2d 将会使用 4D张量,nSamples nChannels Height Width,如果只有单个样本,可以使用input.unsqueeze(0)来增加一个假的batch维度。

      回顾下刚学到的几个类:

    • torch.Tensor- 多维数组并支持自动微分运算如backward()
    • nn.Moudle-神经网络模型,帮助我们封装参数,移植到GPU,导出和加载等
    • nn.Parameter-张量,当你给Module定义属性时,参数会自动生成
    • autograd.Function-实现前向和反向定义的自动微分运算。每个张量运算至少创建一个Function结点,来连接创建张量和记录历史的函数

    Loss Function

      损失函数计算输出和目标之间的值,来衡量两者的差距。在nn中有多种不同的损失函数,一个简单的损失函数是:nn.MSELoss,它返回的是均方差,即每一个分量相减的平方累计最后除分量的个数。

    output = net(input)
    target = torch.randn(10)  # a dummy target, for example
    target = target.view(1, -1)  # make it the same shape as output
    criterion = nn.MSELoss()
    
    loss = criterion(output, target)
    print(loss)
    tensor(0.9531, grad_fn=<MseLossBackward>)

      如果你沿着loss反向传播的方向,用.grad_fn属性可以看到计算图:

    input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
          -> view -> linear -> relu -> linear -> relu -> linear
          -> MSELoss
          -> loss

      所以,当你调用loss.backward()时,在整个计算图都会进行微分,所有requires_grad=True的张量的.grad属性都会累加。

      为了说明,打印如下少数几步的反向传播:

    print(loss.grad_fn)  # MSELoss
    print(loss.grad_fn.next_functions[0][0])  # Linear
    print(loss.grad_fn.next_functions[0][0].next_functions[0][0])  # ReLU
    <MseLossBackward object at 0x7f6e48d5ee48>
    <AddmmBackward object at 0x7f6e48d5eac8>
    <AccumulateGrad object at 0x7f6e48d5eac8>

    Backprop

      为了反向传播误差我们需要做的只要使用 loss.backward() ,同时也需要清除已有的梯度,否则梯度会累加到已经存在的梯度。

      调用 loss.backward() ,观察conv1 层bias的梯度反向传播前后的变化  

    net.zero_grad()     # zeroes the gradient buffers of all parameters
    
    print('conv1.bias.grad before backward')
    print(net.conv1.bias.grad)
    
    loss.backward()
    
    print('conv1.bias.grad after backward')
    print(net.conv1.bias.grad)
    conv1.bias.grad before backward
    tensor([0., 0., 0., 0., 0., 0.])
    conv1.bias.grad after backward
    tensor([-0.0022,  0.0022, -0.0139,  0.0072,  0.0029,  0.0035])

       现在我们已经知道了如何使用损失函数。

    Update the weights

      在实际中使用的最简单的更新规则是随即梯度下降SGD:

    weight = weight - learning_rate * gradient

      我们可以简单地使用python代码进行实现:

    learning_rate = 0.01
    for f in net.parameters():
        f.data.sub_(f.grad.data * learning_rate)

      如果需要使用其他的更新规则,比如SGD,Nesterov-SGD, Adam, RMSProp等等,pytorch也提供了相关的包:torch.optim ,实现了这些方法。

      使用实例:

    import torch.optim as optim
    
    # create your optimizer
    optimizer = optim.SGD(net.parameters(), lr=0.01)
    
    # in your training loop:
    optimizer.zero_grad()   # zero the gradient buffers
    output = net(input)
    loss = criterion(output, target)
    loss.backward()
    optimizer.step()    # Does the update

      注:代码中我们手动将梯度设置为0,optimizer.zero_grad(),这是因为梯度不置0的话将会累加以前的值,在反向传播那一节我们也提到过。

    TRAINING A CLASSIFIER

      我们已经知道了如何定义网络,计算损失和更新网络权重,那我们将会思考,那数据呢?

      通常来讲,当你处理图片,文本,语音和视频数据,可以使用标准的python包来加载数据为numpy数组,然后转换为张量torch.*Tensor。

    • 图片,通常可以使用Pillow, OpenCV
    • 语音,使用scipy 和 librosa
    • 文本,纯python或Cython,也可以使用NLTK和SpaCy

      对于视觉,我们专门创建了一个名为 torchvision 的包,其拥有加载普通数据集(Imagenet, CIFAR10, MNIST)的加载器和图片数据转换器,即torchvision.datasets 和 torch.utils.data.DataLoader。

      在本教程中,我们将使用CIFAR10数据集。它有10个类别:‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’. CIFAR10中的图像的大小为3*32*32,即大小为32*32的有3个通道的彩色图像。  

    Training an image classifier

      接下来我们要做一步步完成以下内容:

    1. 使用torchvision加载和归一化CIFAR10的训练和测试数据集
    2. 定义一个卷积神经网络
    3. 定义一个损失函数
    4. 在训练数据上训练数据
    5. 在测试集上测试网络

    1. Loading and normalizing CIFAR10

    import torch
    import torchvision
    import torchvision.transforms as transforms

      torchvision数据集的输出是在[0,1]范围的]PILImage,我们将其转化为归一化范围[-1, 1]的张量。

    transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
    
    trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                            download=True, transform=transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                              shuffle=True, num_workers=2)
    
    testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                           download=True, transform=transform)
    testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                             shuffle=False, num_workers=2)
    
    classes = ('plane', 'car', 'bird', 'cat',
               'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
    Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz
    Files already downloaded and verified

       使用matplotlib库查看训练数据:

    import matplotlib.pyplot as plt
    import numpy as np
    
    # functions to show an image
    
    
    def imshow(img):
        img = img / 2 + 0.5     # unnormalize
        npimg = img.numpy()
        plt.imshow(np.transpose(npimg, (1, 2, 0)))
        plt.show()
    
    
    # get some random training images
    dataiter = iter(trainloader)
    images, labels = dataiter.next()
    
    # show images
    imshow(torchvision.utils.make_grid(images))
    # print labels
    print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

    frog  bird truck  ship

    2. Define a Convolutional Neural Network

      复制神经网络那一节的代码,然后将输入图像的通道改为3个,

    import torch.nn as nn
    import torch.nn.functional as F
     
    class Net(nn.Module):
        def __init__(self):
            super(Net,self).__init__()
            self.conv1=nn.Conv2d(3,6,5)
            self.pool=nn.MaxPool2d(kernel_size=2,stride=2)
            self.conv2=nn.Conv2d(6,16,5)
            self.fc1=nn.Linear(16*5*5,120)
            self.fc2=nn.Linear(in_features=120,out_features=84)
            self.fc3 = nn.Linear(in_features=84, out_features=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()
    print(net)
    Net(
      (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
      (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
      (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
      (fc1): Linear(in_features=400, out_features=120, bias=True)
      (fc2): Linear(in_features=120, out_features=84, bias=True)
      (fc3): Linear(in_features=84, out_features=10, bias=True)
    ) 

    3. Define a Loss function and optimizer

       使用分类的交叉熵损失函数和带动量的随机梯度下降。

    import torch.optim as optim
    
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

    4. Train the network  

    for epoch in range(2):#循环整个数据集多少遍
     
        running_loss=0.0
        for i,data in enumerate(trainloader,start=0):
            #get the inputs
            inputs, labels = data
     
            # 梯度清0
            optimizer.zero_grad()
     
            #forward + backword + optimize
            outputs = net(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
     
            #打印统计信息
            running_loss += loss.item()
            if i % 2000 == 1999: #每2000个mini-batches打印一次
                print("[%d, %d] loss: %.3f" %
                      (epoch+1, i+1, running_loss/2000))
                running_loss=0.0
    print('Finished Training')

      

      

          

      

      

      

  • 相关阅读:
    react开发环境搭建
    react 组件创建
    Redux 视频教程
    echars3.0 柱状图y轴字体斜放
    echars3.0 柱状图大小设置
    ECharts地图详解 【转】
    html 超出出现省略号
    html JS打印添加水印图片
    js 重庆38区县 数组
    docker 暴露2375 端口。
  • 原文地址:https://www.cnblogs.com/White-xzx/p/10324118.html
Copyright © 2020-2023  润新知