blitz_data_parallel_tutorial.md 9.6 KB
Newer Older
1
# 可选: 数据并行处理
W
wizardforcel 已提交
2

3
> **作者**: [Sung Kim](https://github.com/hunkim)  [Jenny Kang](https://github.com/jennykang)
Font Tian's avatar
Font Tian 已提交
4
>
5 6 7
> 译者: [bat67](https://github.com/bat67)
>
> 校对者: [FontTian](https://github.com/fonttian)  [片刻](https://github.com/jiangzhonglian)
W
wizardforcel 已提交
8

片刻小哥哥's avatar
片刻小哥哥 已提交
9
在这个教程里,我们将学习如何使用数据并行(`DataParallel`)来使用多GPU。
W
wizardforcel 已提交
10

11
PyTorch非常容易的就可以使用GPU,可以用如下方式把一个模型放到GPU上: 
W
wizardforcel 已提交
12

W
wizardforcel 已提交
13
```python
14
device = torch.device("cuda: 0")
W
wizardforcel 已提交
15 16 17
model.to(device)
```

18
然后可以复制所有的张量到GPU上: 
W
wizardforcel 已提交
19

W
wizardforcel 已提交
20
```python
W
wizardforcel 已提交
21 22 23
mytensor = my_tensor.to(device)
```

W
wizardforcel 已提交
24
请注意,调用`my_tensor.to(device)`返回一个GPU上的`my_tensor`副本,而不是重写`my_tensor`。我们需要把它赋值给一个新的张量并在GPU上使用这个张量。
W
wizardforcel 已提交
25

W
wizardforcel 已提交
26
在多GPU上执行前向和反向传播是自然而然的事。然而,PyTorch默认将只是用一个GPU。你可以使用`DataParallel`让模型并行运行来轻易的让你的操作在多个GPU上运行。
W
wizardforcel 已提交
27

W
wizardforcel 已提交
28
```python
W
wizardforcel 已提交
29 30 31
model = nn.DataParallel(model)
```

W
wizardforcel 已提交
32
这是这篇教程背后的核心,我们接下来将更详细的介绍它。
W
wizardforcel 已提交
33

W
wizardforcel 已提交
34
## 导入和参数
W
wizardforcel 已提交
35

W
wizardforcel 已提交
36
导入PyTorch模块和定义参数。
W
wizardforcel 已提交
37

W
wizardforcel 已提交
38
```python
W
wizardforcel 已提交
39 40 41 42
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader

43
# Parameters 和 DataLoaders
W
wizardforcel 已提交
44 45 46 47 48 49 50
input_size = 5
output_size = 2

batch_size = 30
data_size = 100
```

片刻小哥哥's avatar
片刻小哥哥 已提交
51
设备(Device): 
W
wizardforcel 已提交
52

W
wizardforcel 已提交
53
```python
54
device = torch.device("cuda: 0" if torch.cuda.is_available() else "cpu")
W
wizardforcel 已提交
55 56
```

W
wizardforcel 已提交
57
## 虚拟数据集
W
wizardforcel 已提交
58

片刻小哥哥's avatar
片刻小哥哥 已提交
59
要制作一个虚拟(随机)数据集,只需实现`__getitem__`
W
wizardforcel 已提交
60

W
wizardforcel 已提交
61
```python
62
class RandomDataset(Dataset):
W
wizardforcel 已提交
63

64
    def __init__(self, size, length):
W
wizardforcel 已提交
65 66 67
        self.len = length
        self.data = torch.randn(length, size)

68
    def __getitem__(self, index):
W
wizardforcel 已提交
69 70
        return self.data[index]

71
    def __len__(self):
W
wizardforcel 已提交
72 73 74 75 76 77
        return self.len

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

W
wizardforcel 已提交
78
## 简单模型
W
wizardforcel 已提交
79

片刻小哥哥's avatar
片刻小哥哥 已提交
80
作为演示,我们的模型只接受一个输入,执行一个线性操作,然后得到结果。然而,你能在任何模型(CNN,RNN,Capsule Net等)上使用`DataParallel`
W
wizardforcel 已提交
81

W
wizardforcel 已提交
82
我们在模型内部放置了一条打印语句来检测输入和输出向量的大小。请注意批等级为0时打印的内容。
W
wizardforcel 已提交
83

W
wizardforcel 已提交
84
```python
85
class Model(nn.Module):
W
wizardforcel 已提交
86 87
    # Our model

88
    def __init__(self, input_size, output_size):
W
wizardforcel 已提交
89 90 91
        super(Model, self).__init__()
        self.fc = nn.Linear(input_size, output_size)

92
    def forward(self, input):
W
wizardforcel 已提交
93
        output = self.fc(input)
94
        print("\tIn Model: input size", input.size(),
W
wizardforcel 已提交
95 96 97 98 99
              "output size", output.size())

        return output
```

W
wizardforcel 已提交
100
## 创建一个模型和数据并行
W
wizardforcel 已提交
101

W
wizardforcel 已提交
102
这是本教程的核心部分。首先,我们需要创建一个模型实例和检测我们是否有多个GPU。如果我们有多个GPU,我们使用`nn.DataParallel`来包装我们的模型。然后通过`model.to(device)`把模型放到GPU上。
W
wizardforcel 已提交
103

W
wizardforcel 已提交
104
```python
W
wizardforcel 已提交
105
model = Model(input_size, output_size)
106
if torch.cuda.device_count() > 1: 
W
wizardforcel 已提交
107 108 109 110 111 112 113
  print("Let's use", torch.cuda.device_count(), "GPUs!")
  # dim = 0 [30, xxx] -> [10, ...], [10, ...], [10, ...] on 3 GPUs
  model = nn.DataParallel(model)

model.to(device)
```

114
输出: 
W
wizardforcel 已提交
115

W
wizardforcel 已提交
116
```python
W
wizardforcel 已提交
117 118 119
Let's use 2 GPUs!
```

W
wizardforcel 已提交
120
## 运行模型
W
wizardforcel 已提交
121

W
wizardforcel 已提交
122
现在我们可以看输入和输出张量的大小。
W
wizardforcel 已提交
123

W
wizardforcel 已提交
124
```python
125
for data in rand_loader: 
W
wizardforcel 已提交
126 127
    input = data.to(device)
    output = model(input)
128
    print("Outside: input size", input.size(),
W
wizardforcel 已提交
129 130 131
          "output_size", output.size())
```

132
输出: 
W
wizardforcel 已提交
133 134

```python
135 136 137 138 139 140 141 142 143 144 145 146
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])
W
wizardforcel 已提交
147 148
```

W
wizardforcel 已提交
149
## 结果
W
wizardforcel 已提交
150

W
wizardforcel 已提交
151
当我们对30个输入和输出进行批处理时,我们和期望的一样得到30个输入和30个输出,但是若有多个GPU,会得到如下的结果。
W
wizardforcel 已提交
152

W
wizardforcel 已提交
153
### 2个GPU
W
wizardforcel 已提交
154

155
若有2个GPU,将看到: 
W
wizardforcel 已提交
156

W
wizardforcel 已提交
157
```python
W
wizardforcel 已提交
158
Let's use 2 GPUs!
159 160 161 162 163 164 165 166 167 168 169 170
    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])
W
wizardforcel 已提交
171 172
```

W
wizardforcel 已提交
173
### 3个GPU
W
wizardforcel 已提交
174

175
若有3个GPU,将看到: 
W
wizardforcel 已提交
176

W
wizardforcel 已提交
177
```python
W
wizardforcel 已提交
178
Let's use 3 GPUs!
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
    In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
    In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
    In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
    In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
    In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
    In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
    In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
    In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
    In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])
W
wizardforcel 已提交
195 196
```

W
wizardforcel 已提交
197
### 8个GPU
W
wizardforcel 已提交
198

199
若有8个GPU,将看到: 
W
wizardforcel 已提交
200

W
wizardforcel 已提交
201
```python
W
wizardforcel 已提交
202
Let's use 8 GPUs!
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])
    In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])
    In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
    In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
    In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
    In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
    In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])
Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])
W
wizardforcel 已提交
236 237
```

W
wizardforcel 已提交
238
## 总结
W
wizardforcel 已提交
239

Font Tian's avatar
Font Tian 已提交
240
`DataParallel`自动的划分数据,并将作业发送到多个GPU上的多个模型。`DataParallel`会在每个模型完成作业后,收集与合并结果然后返回给你。
W
wizardforcel 已提交
241

242
更多信息,请参考: https://pytorch.org/tutorials/beginner/former_torchies/parallelism_tutorial.html