5.md 6.3 KB
Newer Older
W
wizardforcel 已提交
1 2 3 4 5 6 7 8 9 10
# 常见问题

### 我的模型报告 "cuda runtime error(2): out of memory"

如错误消息所示,您的`GPU`上的内存不足。由于我们经常在`PyTorch`中处理大量数据,因此小错误可能会迅速导致程序耗尽所有 GPU;幸运的是,这些情况下的修复通常很简单。这里有几个常见的事情要检查:

**不要在训练循环中累积历史记录**。默认情况下,当计算涉及到有需要梯度的变量时,此计算过程将保留运算的历史记录。这意味着您应该避免在计算中使用这些变量,这些变量的生存期将超出您的训练循环(例如在跟踪统计数据时)。您应该分离该变量或访问其底层数据。

有时,当可微分变量可能发生时,它可能并不明显。考虑以下训练循环(从[源代码](https://discuss.pytorch.org/t/high-memory-usage-while-training/162)节选):

W
wizardforcel 已提交
11
```py
W
wizardforcel 已提交
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
total_loss = 0
for i in range(10000):
    optimizer.zero_grad()
    output = model(input)
    loss = criterion(output)
    loss.backward()
    optimizer.step()
    total_loss += loss 
```

在本例中,由于 `loss` 是具有 `autograd` 历史记录的可微分变量,所以 `total_loss` 将在整个训练循环中累积历史记录。你可以替换成 `total_loss + = float(loss)` 来解决这个问题。

这个问题的另一个例子:[1](https://discuss.pytorch.org/t/resolved-gpu-out-of-memory-error-with-batch-size-1/3719)

**删除你不需要的张量和变量**。如果将一个张量或变量分配到一个局部栈,在局部栈超出作用域之前,Python 都不会将其释放。您可以使用 `del x` 释放该引用。同样,如果将一个张量或变量赋值给对象的成员变量,直到该对象超出作用域之前,它将不会释放。如果你及时删除你不需要的临时变量,你将获得最佳的内存使用率。

作用域的范围可能比你想象的要大。例如:

W
wizardforcel 已提交
30
```py
W
wizardforcel 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
for i in range(5):
    intermdeiate = f(input[i])
    result += g(intermediate)
output = h(result)
return output 
```

在本段代码中,即使当 `h` 在执行时,`intermediate` 仍然存在,因为它的作用域延伸出了循环的末尾。为了尽早释放它,当你不需要它时,你应该用 `del intermediate` 删除这个中间值。

**不要在太大的序列上运行 RNN。** 因为 RNN 反向传播所需的内存量与 RNN 的长度成线性关系;因此,如果尝试向 RNN 提供一个太长的序列时,会耗尽内存。

这一现象的技术术语是时间反向传播[Backpropagation through time](https://en.wikipedia.org/wiki/Backpropagation_through_time),关于如何实现截断的 BPTT 有很多参考资料,包括在单词语言模型 [word language model](https://github.com/pytorch/examples/tree/master/word_language_model) 中;截断由[这个论坛帖子](https://discuss.pytorch.org/t/help-clarifying-repackage-hidden-in-word-language-model/226)中描述的 `repackage` 函数处理。

**不要使用太大的线性图层。** 线性层 `nn.Linear(m,n)` 使用 `O(nm)` 存储器:也就是说,权值的存储器需求随着要素的数量按比例缩放。这种方式会轻易的占用你的内存(并且记住,你将至少需要两倍存储权值的内存量,因为你还需要存储梯度。)

### 我的 GPU 内存没有正确释放

PyTorch 使用缓存内存分配器来加速内存分配。因此,`nvidia-smi` 中显示的值通常不会反映真实的内存使用情况。有关 GPU 内存管理的更多细节,请参阅 [内存管理](http://pytorch.org/docs/stable/notes/cuda.html#cuda-memory-management)

如果您的 GPU 内存在 Python 退出后仍未释放,那么很可能某些 Python 子进程仍然存在。你可以通过 `ps -elf | grep python` 找到它们,并用 `kill -9 [pid]` 手动杀死它们。

### 我的多个数据加载器返回相同的随机数

您可能正使用其他库生成数据集中的随机数。例如,当通过 `fork` 启动工作子进程时,NumPy 的 RNG 会被复制。请参阅 [`torch.utils.data.DataLoader`](http://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader) 的文档,了解如何使用其 `worker_init_fn` 选项正确设置工作进程中的随机种子。

### 我的回归网络不能使用数据并行

在具有 `DataParallel``data_parallel()` 的模块中使用 `pack sequence -> recurrent network -> unpack sequence` 模式时有一个非常微妙的地方。每个设备上的 `forward()` 的输入只会是整个输入的一部分。由于默认情况下,解包操作 `torch.nn.utils.rnn.pad_packed_sequence()` 仅填充到其所见的最长输入,即该特定设备上的最长输入,所以在将结果收集在一起时会发生尺寸的不匹配。因此,您可以利用 `pad_packed_sequence()``total_length` 参数来确保 `forward()` 调用返回相同长度

的序列。例如,你可以写:

W
wizardforcel 已提交
62
```py
W
wizardforcel 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_squence

class MyModule(nn.Module):
    #  ... __init__, 以及其他访求

    # padding_input 的形状是[B x T x *](batch_first 模式),包含按长度排序的序列
    # B 是批量大小
    # T 是最大序列长度
    def forward(self, padded_input, input_lengths):
        total_length = padded_input.size(1)  # 获取最大序列长度
        packed_input = pack_padded_sequence(padded_input, input_lengths,
                                            batch_first=True)
        packed_output, _ = self.my_lstm(packed_input)
        output, _ = pad_packed_sequence(packed_output, batch_first=True,
                                        total_length=total_length)
        return output

m = MyModule().cuda()
dp_m = nn.DataParallel(m) 
```

此外,在批量的维度为 dim `1` (第 1 轴)(即 `batch_first = False` )时需要额外注意数据的并行性。在这种情况下,`pack_padded_sequence` 函数的的第一个参数 `padding_input` 维度将是 `[T x B x *]` ,并且应该沿 dim `1` (第 1 轴)分散,但第二个参数 `input_lengths` 的维度为 `[B]`,应该沿 dim `0` (第 0 轴)分散。需要额外的代码来操纵张量的维度。

### 译者署名

| 用户名 | 头像 | 职能 | 签名 |
| --- | --- | --- | --- |
| 风中劲草 | ![](img/2018033000352689884.jpeg) | 翻译 | 人生总要追求点什么 |