Pytorch入门教程

  记得刚开始学TensorFlow的时候,那给我折磨的呀,我一直在想这个TensorFlow官方为什么搭建个网络还要画什么静态图呢,把简单的事情弄得麻烦死了,直到这几天我开始接触Pytorch,发现Pytorch是就是不用搭建静态图的Tensorflow版本,就想在用numpy一样,并且封装了很多深度学习高级API,numpy数据和Tensor数据相互转换不用搭建会话了,只需要一个转换函数,搭建起了numpy和TensorFlow爱的桥梁。

  Pytorch自17年推出以来,一度有赶超TensorFlow的趋势,是因为Pytorch采用动态图机制,替代Numpy使用GPU的功能,搭建网络灵活。

Pytorch和TensorFlow的区别:

  • TensorFlow是基于静态计算图的,静态计算图是先定义后运行,一次定义多次运行(Tensorflow 2.0也开始使用动态计算图)
  • PyTorch是基于动态图的,是在运行的过程中被定义的,在运行的时候构建,可以多次构建多次运行

张量

  Pytorch中的Tensor和ndarray类似,区别在于ndarray不能再GPU上加速,而Tensor可以使用GPU加速

构建一个未初始化3*3的矩阵

import torchx = torch.empty(3,3)
# tensor([[1.0469e-38, 5.9694e-39, 8.9082e-39],
#         [1.0194e-38, 9.1837e-39, 4.6837e-39],
#         [9.9184e-39, 9.0000e-39, 1.0561e-38]])

构建一个3*3的随机矩阵

x = torch.rand(3, 3)
# tensor([[0.4289, 0.6872, 0.2781],
#         [0.2129, 0.7520, 0.3994],
#         [0.0995, 0.9080, 0.7868]])

dtype long的全零矩阵:

x = torch.zeros(5, 3, dtype=torch.long)
# tensor([[0, 0, 0],
#         [0, 0, 0],
#         [0, 0, 0]])

把数据[5.5, 3]变成Tensor

x = torch.tensor([5.5, 3])
# tensor([5.5000, 3.0000])

得到数组的shape

print(x.size())
 # torch.Size([2])

torch.Size 实际上是一个元组,因此它支持所有元组操作。

Operation操作

加法

import torch

# ------------- 方法一 -------------#
x = torch.rand(2, 2)        # 构建一个(2,2)的随机数组
y = torch.rand(2, 2)        # 构建一个(2,2)的随机数组
print(x + y)

# ------------- 方法二 -------------#
print(torch.add(x, y))

# ------------- 方法三 -------------#
result = torch.empty(2, 2)
torch.add(x, y, out=result)
print(result)

# ------------- 方法四 -------------#
# 把x加到y上
y.add_(x)
print(y)
# 所有的结果都等于
# tensor([[0.5464, 0.5692],
#         [0.7211, 1.2168]])

Pytorch的索引和python一样,

调整shape

torch.view()  调整数组shape

torch.size()  查看数据shape

import torch

x = torch.randn(4, 4)

y = x.view(16)
print(y.size())     # torch.Size([16])

z = x.view(-1, 8)
print(z.size())     # torch.Size([2, 8])

如果我们的张量只有一个数值,可以使用.item()获取

import torch

x = torch.randn(1)
print(x)        # tensor([-0.8504])
print(x.item())     # -0.8503872156143188

Numpy数组和Torch Tensor转换

将Torch张量转换为NumPy数组

ndarray.numpy():Torch Tensor-->ndarray

import torch

a = torch.ones(5)
print(a)    # tensor([1., 1., 1., 1., 1.])

# torch tensor-->ndarray
b = a.numpy()
print(b, type(b))    # [1. 1. 1. 1. 1.]  <class ‘numpy.ndarray‘>

将NumPy数组转换为Torch张量

torch.from_numpy(ndarray):ndarray--Torch Tensor

import torch

import numpy as np
a = np.ones(5)      # [1. 1. 1. 1. 1.]
b = torch.from_numpy(a)
print(b)    # tensor([1., 1., 1., 1., 1.], dtype=torch.float64)

Autograd自动微分

自动微分Autograd用于自动计算复杂函数的梯度,用于神经网络的优化,

如果设置torch.tensor_1(requires_grad=True),那么会追踪所有对该张量tensor_1的所有操作。

import torch

# 创建一个张量并设置 requires_grad=True 用来追踪他的计算历史
x = torch.ones(2, 2, requires_grad=True)
print(x)
# tensor([[1., 1.],
#         [1., 1.]], requires_grad=True)

当Tensor完成一个计算过程,每个张量都会自动生成一个.grad_fn属性

# 对张量进行计算操作,grad_fn已经被自动生成了。
y = x + 2
print(y)
# tensor([[3., 3.],
#         [3., 3.]], grad_fn=<AddBackward>)
print(y.grad_fn)
# <AddBackward object at 0x00000232535FD860>

# 对y进行一个乘法操作
z = y * y * 3
out = z.mean()

print(z)
# tensor([[27., 27.],
#         [27., 27.]], grad_fn=<MulBackward>)
print(out)
# tensor(27., grad_fn=<MeanBackward1>)

.requires_grad_(...) 可以改变张量的requires_grad属性。

import torch

a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)      # 默认是requires_grad = False
a.requires_grad_(True)
print(a.requires_grad)      # True
b = (a * a).sum()
print(b.grad_fn)        # <SumBackward0 object at 0x000002325360B438>

梯度

回顾到上面

import torch

# 创建一个张量并设置 requires_grad=True 用来追踪他的计算历史
x = torch.ones(2, 2, requires_grad=True)
print(x)
# tensor([[1., 1.],
#         [1., 1.]], requires_grad=True)

# 对张量进行计算操作,grad_fn已经被自动生成了。
y = x + 2
print(y)
# tensor([[3., 3.],
#         [3., 3.]], grad_fn=<AddBackward>)
print(y.grad_fn)
# <AddBackward object at 0x00000232535FD860>

# 对y进行一个乘法操作
z = y * y * 3
out = z.mean()

print(z)
# tensor([[27., 27.],
#         [27., 27.]], grad_fn=<MulBackward>)
print(out)
# tensor(27., grad_fn=<MeanBackward1>)

让我们来反向传播,运行 out.backward() ,等于out.backward(torch.tensor(1.))

对out进行方向传播,$out = \frac{1}{4}\sum_i z_i$,其中$z_i = 3(x_i+2)^2$,因为方向传播中torch.tensor=1(out.backward中的参数)因此$z_i\bigr\rvert_{x_i=1} = 27$

对于梯度$\frac{\partial out}{\partial x_i} = \frac{3}{2}(x_i+2)$,把$x_i=1$代入$\frac{\partial out}{\partial x_i}\bigr\rvert_{x_i=1} = \frac{9}{2} = 4.5$

print(out)  # tensor(27., grad_fn=<MeanBackward1>)

print("*"*50)
out.backward()
# 打印梯度
print(x.grad)
# tensor([[4.5000, 4.5000],
#         [4.5000, 4.5000]])

对吃栗子找到规律,才能看懂

import torch

x = torch.randn(3, requires_grad=True)

y = x * 2
while y.data.norm() < 1000:
    y = y * 2

print(y)  # tensor([-920.6895, -115.7301, -867.6995], grad_fn=<MulBackward>)
gradients = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)

# 把gradients代入y的反向传播中
y.backward(gradients)   

# 计算梯度
print(x.grad)   # tensor([ 51.2000, 512.0000,   0.0512])

为了防止跟踪历史记录,可以将代码块包装在with torch.no_grad():中。 在评估模型时特别有用,因为模型的可训练参数的属性可能具有requires_grad = True,但是我们不需要梯度计算。

print(x.requires_grad)      # True
print((x ** 2).requires_grad)   # True

with torch.no_grad():
    print((x ** 2).requires_grad)   # False

神经网络

神经网络是基于自动梯度 (autograd)来定义一些模型。一个 nn.Module 包括层和一个 forward(input) 它会返回输出(output)。

一个典型的神经网络训练过程包括以下几点:

  1. 定义一个包含可训练参数的神经网络
  2. 迭代整个输入
  3. 通过神经网络处理输入
  4. 计算损失(loss)
  5. 反向传播梯度到神经网络的参数
  6. 更新网络的参数,典型的用一个简单的更新方法:weight = weight - learning_rate *gradient

我们先来定义一个网络,处理输入,调用backword

import torch
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # 1 input image channel, 6 output channels, 3x3 square convolution
        # kernel
        self.conv1 = nn.Conv2d(1, 6, 3)
        self.conv2 = nn.Conv2d(6, 16, 3)
        # an affine operation: y = Wx + b
        self.fc1 = nn.Linear(16 * 6 * 6, 120)  # 6*6 from image dimension
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        # (2, 2)大小的最大池化层
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # 如果大小是正方形,则只能指定一个数字
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)

        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        print(x.size())      # torch.Size([1, 16, 6, 6])
        size = x.size()[1:]  # 除batch维度外的所有维度
        print(size)          # torch.Size([16, 6, 6])
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

net = Net()
print(net)  # 打印模型结构
# Net(
#   (conv1): Conv2d(1, 6, kernel_size=(3, 3), stride=(1, 1))
#   (conv2): Conv2d(6, 16, kernel_size=(3, 3), stride=(1, 1))
#   (fc1): Linear(in_features=576, 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))

torch.nn只支持批输入,格式:sSamples * nChannels * Height * Width(样本数*通道数*高*宽)

如果我们只有一个样本,只需使用 ``input.unsqueeze(0)`` 来添加其它的维数

一个模型可训练的参数可以通过调用 net.parameters() 返回:

params = list(net.parameters())
print(len(params))       # 10
print(params[0].size())  # 第一个卷积层的权重 torch.Size([6, 1, 3, 3])

让我们尝试随机生成一个 32x32 的输入

input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)
# tensor([[ 0.1464,  0.0453,  0.0269,  0.0078,  0.1960, -0.1795,  0.1265,
#           -0.0742, -0.0649,  0.0592]], grad_fn=<AddmmBackward>)

把所有参数梯度缓存器置零,用随机的梯度来反向传播

# 把所有参数梯度缓存器置零
net.zero_grad()
# 用随机的梯度来反向传播
out.backward(torch.randn(1, 10))

损失函数

计算均方误差 $loss=nn.MSELoss(模型预测值-目标)$

output = net(input)     # torch.Size([1, 10])
target = torch.randn(10)  # 随便取一个target
target = target.view(1, -1)  # 让target和output的shape一样
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)     # tensor(0.8695, grad_fn=<MseLossBackward>)

现在,如果你跟随损失到反向传播路径,可以使用它的 .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
# <MseLossBackward object at 0x7fab77615278>
print(loss.grad_fn.next_functions[0][0])  # Linear
# <AddmmBackward object at 0x7fab77615940>
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])  # ReLU
# <AccumulateGrad object at 0x7fab77615940>

反向传播

为了实现反向传播损失,我们所有需要做的事情仅仅是使用 loss.backward()。你需要清空现存的梯度,要不然将会和现存的梯度累计到一起。

现在我们调用 loss.backward() ,然后看一下 con1 的偏置项在反向传播之前和之后的变化。

net.zero_grad()     # 将所有参数的梯度缓冲区归零

print(‘conv1.bias.grad 反向传播之前‘)
print(net.conv1.bias.grad)
# tensor([0., 0., 0., 0., 0., 0.])

loss.backward()

print(‘conv1.bias.grad 反向传播之后‘)
print(net.conv1.bias.grad)
# tensor([-0.0118,  0.0125, -0.0085, -0.0225,  0.0125,  0.0235])

随机梯度下降,更新神经网络参数:

基于python实现

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

使用torch.optim实现,torch.optim中包含SGD, Nesterov-SGD, Adam, RMSProp, 等优化器

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

图像分类器

torch有一个叫做totchvision 的包,支持加载类似Imagenet,CIFAR10,MNIST 等公共数据集的数据加载模块 torchvision.datasets

支持加载图像数据数据转换模块 torch.utils.data.DataLoader。

本节我们使用CIFAR10数据集,它包含十个类别:‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。CIFAR-10 中的图像尺寸为33232,也就是RGB的3层颜色通道,每层通道内的尺寸为32*32。

训练一个图像分类器

我们将按次序的做如下几步:

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

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

import torch
import torchvision
import torchvision.transforms as transforms

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)
# 下载测试数据集
testset = torchvision.datasets.CIFAR10(root=‘./data‘, train=False,
                                       download=True, transform=transform)

trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=True, num_workers=2)
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‘)

让我们来展示其中的一些训练图片

import matplotlib.pyplot as plt
import numpy as np

# 展示图片
def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

# 获取一些随机的训练图片
dataiter = iter(trainloader)
images, labels = dataiter.next()

imshow(torchvision.utils.make_grid(images)) # show images
# 打印 labels
print(‘ ‘.join(‘%5s‘ % classes[labels[j]] for j in range(4)))
# cat plane  ship  frog

定义一个卷积神经网络 在这之前先 从神经网络章节 复制神经网络,并修改它为3通道的图片(在此之前它被定义为1通道)

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(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()

定义一个损失函数和优化器 让我们使用交叉熵Cross-Entropy 作损失函数,优化器使用SGD

import torch.optim as optim

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

我们只需要在数据迭代器上将数据循环传给网络和优化器 就可以。

for epoch in range(2):  # 多次循环数据集

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # 获取输入
        inputs, labels = data

        # 把参数梯度归零
        optimizer.zero_grad()

        # 前向传播(forward) + 反向传播(backward) + 优化器(optimize)
        outputs = net(inputs)       # 前向传播
        loss = criterion(outputs, labels)
        loss.backward()     # 反向传播
        optimizer.step()    # 优化器

        running_loss += loss.item()
        if i % 2000 == 1999:    # 每2000个小batch打印一次
            print(‘[%d, %5d] loss: %.3f‘ %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print(‘Finished Training‘)

# [1,  2000] loss: 2.187
# [1,  4000] loss: 1.852
# [1,  6000] loss: 1.672
# [1,  8000] loss: 1.566
# [1, 10000] loss: 1.490
# [1, 12000] loss: 1.461
# [2,  2000] loss: 1.389
# [2,  4000] loss: 1.364
# [2,  6000] loss: 1.343
# [2,  8000] loss: 1.318
# [2, 10000] loss: 1.282
# [2, 12000] loss: 1.286
# Finished Training

在测试集上测试网络 我们已经通过训练数据集对网络进行了2次训练,但是我们需要检查网络是否已经学到了东西。

我们将用神经网络的输出作为预测的类标来检查网络的预测性能,用样本的真实类标来校对。如果预测是正确的,我们将样本添加到正确预测的列表里。

好的,第一步,让我们从测试集中显示一张图像来熟悉它。

GroundTruth: cat ship ship plane

测试

输出是预测与十个类的近似程度,与某一个类的近似程度越高,网络就越认为图像是属于这一类别。所以让我们打印其中最相似类别类标:

outputs = net(images)

_, predicted = torch.max(outputs, 1)

print(‘Predicted: ‘, ‘ ‘.join(‘%5s‘ % classes[predicted[j]] for j in range(4)))
# Predicted:    cat  ship   car  ship
# GroundTruth:  cat  ship  ship  plane

预测对了两个,让我们看看网络在整个数据集上的表现。

correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print(‘Accuracy of the network on the 10000 test images: %d %%‘ % (
    100 * correct / total))
# Accuracy of the network on the 10000 test images: 54 %

正确率有54%,看来网络学到了东西。随机预测出为10类中的哪一类:

class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1

for i in range(10):
    print(‘Accuracy of %5s : %2d %%‘ % (
        classes[i], 100 * class_correct[i] / class_total[i]))

# Accuracy of plane : 57 %
# Accuracy of   car : 73 %
# Accuracy of  bird : 49 %
# Accuracy of   cat : 54 %
# Accuracy of  deer : 18 %
# Accuracy of   dog : 20 %
# Accuracy of  frog : 58 %
# Accuracy of horse : 74 %
# Accuracy of  ship : 70 %
# Accuracy of truck : 66 %

在GPU上跑这些神经网络?

在GPU上训练,我么要将神经网络转到GPU上。前提条件是CUDA可以用,让我们首先定义下我们的设备为第一个可见的cuda设备。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# Assume that we are on a CUDA machine, then this should print a CUDA device:

print(device)
# cuda:0

接着这些方法会递归地遍历所有模块,并将它们的参数和缓冲器转换为CUDA张量。

net.to(device)

记住你也必须在每一个步骤向GPU发送输入和目标:

inputs, labels = inputs.to(device), labels.to(device)

CUDA张量

使用该.to方法可以将张量移动到任何设备上。只有在有CUDA的情况下我们才能运行这个函数

# 我们将使用“torch.device”对象来移动GPU中的张量
if torch.cuda.is_available():
    device = torch.device("cuda")          # CUDA设备对象
    y = torch.ones_like(x, device=device)  # 直接在GPU上创建张量
    x = x.to(device)                       # 或者只使用 ``.to("cuda")
    z = x + y
    print(z)
    print(z.to("cpu", torch.double))       # " ".to()还可以更改数据类型

# tensor([0.7032], device=‘cuda:0‘)
# tensor([0.7032], dtype=torch.float64)

数据并行处理

本章节教大家如何使用DataParallel来使用多GPU。

我们把模型放入GPU中

 device = torch.device("cuda:0")
 model.to(device)

将所有张量复制到GPU

mytensor = my_tensor.to(device)

在多 GPU 中执行前向、方向操作是非常自然的。尽管如此,PyTorch 默认只会使用一个 GPU。因此我们要使用DataParallel让模型在多个GPU上并行运行。

输入和参数

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader

input_size = 5
output_size = 2
batch_size = 30
data_size = 100

# 设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

制造一个随机的数据集

class RandomDataset(Dataset):
    def __init__(self, size, length):
        self.len = length
        self.data = torch.randn(length, size)

    def __getitem__(self, index):
        return self.data[index]

    def __len__(self):
        return self.len

rand_loader = DataLoader(dataset=RandomDataset(input_size, data_size),
            batch_size=batch_size, shuffle=True)

搭建一个简单的模型,我们的模型仅获取输入,执行线性运算并给出输出,

class Model(nn.Module):
    def __init__(self, input_size, output_size):
        super(Model, self).__init__()
        self.fc = nn.Linear(input_size, output_size)

    def forward(self, input):
        output = self.fc(input)
        print("\tIn Model: input size", input.size(), "output size", output.size())

        return output

创建模型和数据并行

我们先要检查模型是否有多个GPU,如果有我们再使用nn.DataParallel,然后我们可以把模型放在GPU上model.to(device)

model = Model(input_size, output_size)
if torch.cuda.device_count() > 1:
  print("我们有", torch.cuda.device_count(), "个GPUs!")
  # dim = 0 [30, xxx] -> [10, ...], [10, ...], [10, ...] on 3 GPUs
  model = nn.DataParallel(model)

model.to(device)
# 我们有2个GPU

运行模型,现在我们可以看到输入和输出张量的大小了

for data in rand_loader:
    input = data.to(device)
    output = model(input)
    print("Outside: input size", input.size(), "output_size", output.size())

输出

        In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
        In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
        In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
        In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
        In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
        In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
        In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])
        In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])

如果我们有2个GPU我们可以看到以下结果

# on 2 GPUs
Let‘s use 2 GPUs!
    In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
    In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
    In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
    In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
    In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
    In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
    In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])
    In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])

数据并行自动拆分了你的数据并且将任务单发送到多个 GPU 上。当每一个模型都完成自己的任务之后,DataParallel 收集并且合并这些结果,然后再返回给你。

http://pytorch123.com/

PyTroc官方文档:https://pytorch.org/

PyTroch中文文档:https://pytorch-cn.readthedocs.io/zh/latest/

简单易上手的PyTorch中文文档:https://github.com/fendouai/pytorch1.0-cn

原文地址:https://www.cnblogs.com/LXP-Never/p/11616289.html

时间: 2024-07-30 21:15:08

Pytorch入门教程的相关文章

深度学习框架pytorch入门与实践(一):torch的基本使用

主要内容: 1.tensor的定义 2.tensor与numpy的相互转换 3.tensor使用cuda加速 4.tensor封装成Variable后的使用 # -*- coding: utf-8 -*- """ Created on Thu Aug 8 16:40:47 2019 pytorch快速入门教程 参考书籍:<深度学习框架pytorch:入门与实践> @author: zhaoqidong """ import torch

&lt;zz&gt;bower入门教程

from http://www.cnblogs.com/xiaokai0203/p/5891927.html bower入门教程 什么是bower Bower是一个客户端技术的软件包管理器,它可用于搜索.安装和卸载如JavaScript.HTML.CSS之类的网络资源.其他一些建立在Bower基础之上的开发工具,如YeoMan和Grunt,这个会在以后的文章中介绍. 准备工作 安装node环境:node.js 安装Git,bower从远程git仓库获取代码包:git简易指南 安装bower 使用

【转载】GBDT(MART) 迭代决策树入门教程 | 简介

      转载地址:http://blog.csdn.net/w28971023/article/details/8240756        GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答案.它在被提出之初就和SVM一起被认为是泛化能力(generalization)较强的算法.近些年更因为被用于搜索排

SEO学习步骤总结入门教程

在这里,简单的把SEO的学习步骤说了一下,今天我们一起来把SEO学习步骤每一步的主要内容拿出来重点强调一下并做个总结.  定位好网站内容以后把你所想做排名的关键词定位好,关键词里包括了主关键词和长尾关键词.这里重点强调了不可以忽略长尾关键词的作用.  对于一个好的网站结构可以让搜索引擎蜘蛛顺利的抓取我网站的内容,进而达到被收录的目的.比较有利于蜘蛛抓取的网站结构,一般来说,收录数量相对来说会比较多.,只有让搜索引擎收录你网站页面那搜索引擎才会释放出来,这样网站关键词才可能有排名.  这里重点要注

Android基础入门教程——10.12 传感器专题(3)——加速度-陀螺仪传感器

Android基础入门教程--10.12 传感器专题(3)--加速度/陀螺仪传感器 标签(空格分隔): Android基础入门教程 本节引言: 本节继续来扣Android中的传感器,本节带来的是加速度传感器(Accelerometer sensor)以及 陀螺仪传感器(Gyroscope sensor),和上一节的方向传感器一样有着x,y,z 三个轴, 还是要说一点:x,y轴的坐标要和绘图那里的x,y轴区分开来!传感器的是以左下角 为原点的!x向右,y向上!好的,带着我们的套路来学本节的传感器吧

Android基础入门教程——8.1.3 Android中的13种Drawable小结 Part 3

Android基础入门教程--8.1.3 Android中的13种Drawable小结 Part 3 标签(空格分隔): Android基础入门教程 本节引言: 本节我们来把剩下的四种Drawable也学完,他们分别是: LayerDrawable,TransitionDrawable,LevelListDrawable和StateListDrawable, 依旧贴下13种Drawable的导图: 1.LayerDrawable 层图形对象,包含一个Drawable数组,然后按照数组对应的顺序来

Android基础入门教程——8.1.2 Android中的13种Drawable小结 Part 2

Android基础入门教程--8.1.2 Android中的13种Drawable小结 Part 2 标签(空格分隔): Android基础入门教程 本节引言: 本节我们继续来学习Android中的Drawable资源,上一节我们学习了: ColorDrawable:NinePatchDrawable: ShapeDrawable:GradientDrawable!这四个Drawable~ 而本节我们继续来学习接下来的五个Drawable,他们分别是: BitmapDrawable:Insert

Android基础入门教程——2.3.12 Date &amp; Time组件(下)

Android基础入门教程--2.3.12 Date & Time组件(下) 标签(空格分隔): Android基础入门教程 本节引言: 本节我们来继续学习Android系统给我们提供的几个原生的Date & Time组件,他们分别是: DatePicker(日期选择器),TimePicker(时间选择器),CalendarView(日期视图),好吧, 其实一开始让我扣这几个玩意我是拒绝的,因为在我的印象里,他们是这样的: 简直把我丑哭了,有木有,终于知道为什么那么多人喜欢自定义这种类型的

Android基础入门教程——2.1 View与ViewGroup的概念

Android基础入门教程--2.1 View与ViewGroup的概念 标签(空格分隔): Android基础入门教程 本节引言: 告别了第一章,迎来第二章--Android中的UI(User Interface)组件的详解, 而本节我们要学习的是所有控件的父类View和ViewGroup类!突发奇想,直接翻译官方文档对 这两个东西的介绍吧,对了,天朝原因,google上不去,Android developer上不去,我们可以 改hosts或者用vpn代理,当然也可以像笔者一样使用国内的API