pytorch-handbook/chapter1/5_data_parallel_tutorial.ipynb
古代中二龙 9af30f9bc1
修改了文章最后失效的超链接
原来的链接是失效的
2019-11-04 09:58:30 +08:00

404 lines
14 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"数据并行(选读)\n",
"==========================\n",
"**Authors**: [Sung Kim](https://github.com/hunkim) and [Jenny Kang](https://github.com/jennykang)\n",
"\n",
"在这个教程里,我们将学习如何使用 ``DataParallel`` 来使用多GPU。 \n",
"\n",
"PyTorch非常容易就可以使用多GPU用如下方式把一个模型放到GPU上\n",
"\n",
"```python\n",
"\n",
" device = torch.device(\"cuda:0\")\n",
" model.to(device)\n",
"```\n",
" GPU:\n",
"然后复制所有的张量到GPU上\n",
"```python\n",
"\n",
" mytensor = my_tensor.to(device)\n",
"```\n",
"请注意,只调用``my_tensor.to(device)``并没有复制张量到GPU上而是返回了一个copy。所以你需要把它赋值给一个新的张量并在GPU上使用这个张量。\n",
"\n",
"在多GPU上执行前向和反向传播是自然而然的事。\n",
"但是PyTorch默认将只使用一个GPU。\n",
"\n",
"使用``DataParallel``可以轻易的让模型并行运行在多个GPU上。\n",
"\n",
"\n",
"```python\n",
"\n",
" model = nn.DataParallel(model)\n",
"```\n",
"这才是这篇教程的核心,接下来我们将更详细的介绍它。\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"导入和参数\n",
"----------------------\n",
"\n",
"导入PyTorch模块和定义参数。\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"import torch.nn as nn\n",
"from torch.utils.data import Dataset, DataLoader\n",
"\n",
"# Parameters and DataLoaders\n",
"input_size = 5\n",
"output_size = 2\n",
"\n",
"batch_size = 30\n",
"data_size = 100"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Device\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"虚拟数据集\n",
"-------------\n",
"\n",
"制作一个虚拟(随机)数据集,\n",
"你只需实现 `__getitem__`\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"class RandomDataset(Dataset):\n",
"\n",
" def __init__(self, size, length):\n",
" self.len = length\n",
" self.data = torch.randn(length, size)\n",
"\n",
" def __getitem__(self, index):\n",
" return self.data[index]\n",
"\n",
" def __len__(self):\n",
" return self.len\n",
"\n",
"rand_loader = DataLoader(dataset=RandomDataset(input_size, data_size),\n",
" batch_size=batch_size, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"简单模型\n",
"------------\n",
"作为演示,我们的模型只接受一个输入,执行一个线性操作,然后得到结果。\n",
"说明:``DataParallel``能在任何模型CNNRNNCapsule Net等上使用。\n",
"\n",
"\n",
"我们在模型内部放置了一条打印语句来打印输入和输出向量的大小。\n",
"\n",
"请注意批次的秩为0时打印的内容。\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class Model(nn.Module):\n",
" # Our model\n",
"\n",
" def __init__(self, input_size, output_size):\n",
" super(Model, self).__init__()\n",
" self.fc = nn.Linear(input_size, output_size)\n",
"\n",
" def forward(self, input):\n",
" output = self.fc(input)\n",
" print(\"\\tIn Model: input size\", input.size(),\n",
" \"output size\", output.size())\n",
"\n",
" return output"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"创建一个模型和数据并行\n",
"-----------------------------\n",
"\n",
"这是本教程的核心部分。\n",
"\n",
"首先我们需要创建一个模型实例和检测我们是否有多个GPU。\n",
"如果有多个GPU使用``nn.DataParallel``来包装我们的模型。\n",
"然后通过``model.to(device)``把模型放到GPU上。\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Model(\n",
" (fc): Linear(in_features=5, out_features=2, bias=True)\n",
")"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = Model(input_size, output_size)\n",
"if torch.cuda.device_count() > 1:\n",
" print(\"Let's use\", torch.cuda.device_count(), \"GPUs!\")\n",
" # dim = 0 [30, xxx] -> [10, ...], [10, ...], [10, ...] on 3 GPUs\n",
" model = nn.DataParallel(model)\n",
"\n",
"model.to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"运行模型\n",
"-------------\n",
"\n",
"现在可以看到输入和输出张量的大小。\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\tIn Model: input size torch.Size([30, 5]) output size torch.Size([30, 2])\n",
"Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
"\tIn Model: input size torch.Size([30, 5]) output size torch.Size([30, 2])\n",
"Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
"\tIn Model: input size torch.Size([30, 5]) output size torch.Size([30, 2])\n",
"Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
"\tIn Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
"Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])\n"
]
}
],
"source": [
"for data in rand_loader:\n",
" input = data.to(device)\n",
" output = model(input)\n",
" print(\"Outside: input size\", input.size(),\n",
" \"output_size\", output.size())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"结果\n",
"-------\n",
"\n",
"当没有或者只有一个GPU时对30个输入和输出进行批处理得到了期望的一样得到30个输入和输出但是如果你有多个GPU你得到如下的结果。\n",
"\n",
"\n",
"2 GPUs\n",
"~\n",
"\n",
"If you have 2, you will see:\n",
"\n",
".. code:: bash\n",
"\n",
" # on 2 GPUs\n",
" Let's use 2 GPUs!\n",
" In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])\n",
" In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])\n",
" Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
" In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])\n",
" In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])\n",
" Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
" In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])\n",
" In Model: input size torch.Size([15, 5]) output size torch.Size([15, 2])\n",
" Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
" In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])\n",
" In Model: input size torch.Size([5, 5]) output size torch.Size([5, 2])\n",
" Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])\n",
"\n",
"3 GPUs\n",
"~\n",
"\n",
"If you have 3 GPUs, you will see:\n",
"\n",
".. code:: bash\n",
"\n",
" Let's use 3 GPUs!\n",
" In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
" In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
" In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
" Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
" In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
" In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
" In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
" Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
" In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
" In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
" In Model: input size torch.Size([10, 5]) output size torch.Size([10, 2])\n",
" Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])\n",
" Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])\n",
"\n",
"8 GPUs\n",
"~~\n",
"\n",
"If you have 8, you will see:\n",
"\n",
".. code:: bash\n",
"\n",
" Let's use 8 GPUs!\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([4, 5]) output size torch.Size([4, 2])\n",
" In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])\n",
" Outside: input size torch.Size([30, 5]) output_size torch.Size([30, 2])\n",
" In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])\n",
" In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])\n",
" In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])\n",
" In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])\n",
" In Model: input size torch.Size([2, 5]) output size torch.Size([2, 2])\n",
" Outside: input size torch.Size([10, 5]) output_size torch.Size([10, 2])\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"总结\n",
"-------\n",
"\n",
"DataParallel会自动的划分数据并将作业发送到多个GPU上的多个模型。\n",
"并在每个模型完成作业后,收集合并结果并返回。\n",
"\n",
"更多信息请看这里:\n",
"https://pytorch.org/tutorials/beginner/former_torchies/parallelism_tutorial.html.\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Pytorch for Deeplearning",
"language": "python",
"name": "pytorch"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.7"
}
},
"nbformat": 4,
"nbformat_minor": 1
}