转自NVIDIA开发者社区,稍作修改,仅作学习笔记使用!如有侵权,请联系博主删除!url: https://mp.weixin.qq.com/s/ASkkgfcrdQNahfQnRWbHdw
今年5月14日,NVIDIA 发布了最新的 GPU 架构: 安培,以及基于安培架构的最新的 GPU : A100。安培提供了许多新的特性,MIG 是其中一项非常重要的新特性。MIG的全名是 Multi-Instance GPU,它最多可以把 A100 GPU 切成七个 GPU 实例。每一个 GPU 实例都有各自的流处理器 (SMs) 和内存系统。因此,使用MIG后,每一个 GPU 实例都能够保证各个使用者的工作的时延和吞吐量是可预期的、提供服务品质,并且提高 GPU 的使用率。
如图表 1 所示,我们最多可以将 A100 切分成 7 个实例,每一个实例可以提供给不同的使用者运行不同的程序。在使用者的程序对 GPU 的计算量要求比较少的情况下,MIG 最多能够提供高达 7 倍的吞吐量。此外,由于每一个实例都有各自的计算资源和内存资源,因此不必担心因为其中一位使用者的计算量过大或是程式运行错误而干扰到其他的使用者。
MIG 的一个重要的应用,是让提供云服务的公司能够将 GPU 切分成数个实例,并将这些实例提供给不同的承租者使用。由于不同实例之间的计算资源与内存资源都是透过硬件分离,因此能够确保资料的安全性、错误的隔离,以及提供稳定可靠的服务。
MIG v.s. MPS v.s. multi-stream
在 MIG 推出之前,我们也能够透过 CUDA MPS (Multi-Process Service) 来提高 GPU 使用率。但 MPS 的缺点在于,多个使用者会使用共同的内存,因此使用者的程序会互相影响,除了无法保证推理的速度和吞吐量之外,也有可能因为其中一位使用者的程序出错而导致其他使用者受到干扰。而 MIG 克服了 MPS 面临的问题。MIG 藉由硬件上的分离,保证了使用者的程序不会互相干扰,进而能够让程序的时延和吞吐量能符合预期。
在表格 1当中,我们比较了多流 (multi-stream)、MPS 以及 MIG 的优缺点。其中,多流的使用限制较少,同时也很灵活,但对代码更动的需求大,并且无法避免使用者之间的互相干扰,使用者必须小心的使用以避免产生错误。MPS 则不需要更动代码即可使用,可以同时执行的程序也较 MIG 多 (48 与 7),内存的使用与分配也是自动处理的,不需要人工的介入。缺点在于,无法避免多个用户对于 GPU 资源的竞争;最后,MIG 虽然可以同时执行的程序数量最少,但和 MPS 一样不需要使用者另外更动代码,同时在安全性与可靠性上面也是三者中最佳的。这三样技术并不互相冲突,使用者可以根据使用的情境与场景选择与搭配使用。
要深入地了解 MIG 之前,需要先介绍两个 MIG 引入的重要名词与观念,GPU 实例 (GPU Instance) 和计算实例 (Compute Instance)。在这之前,我们提到的都是 GPU 实例。而在实际的使用上,GPU 实例还可以再切分成多个计算实例。同一个 GPU 实例当中的计算实例是共享内存但拥有独立的流处理器。因此若使用者有多项互相关联的工作,并且使用共享内存较为便利的话,可以选择在一个 GPU 实例当中使用多个计算实例来处理。
图表2 GPU 实例与计算实例
图表 2 展示了 GPU 实例和计算实例的区别。不同的 GPU 实例之前,他们的内存系统是分开的,以此能够保证内存的服务品质 (QoS, Quality of Service),并且避免受到其他使用者的错误干扰。而在一个 GPU 实例当中,可以有多个计算实例,例如图表 2 中最左侧的 GPU 实例包含了四个计算实例,这四个计算实例各自负责了不同的工作,但他们的内存是共用的。透过这样子的设计,MIG 提供使用者灵活的调度 GPU 的资源。
表格 2 展示了不同大小的 GPU 实例他们具备的流处理器比例、内存比例、以及可以分配的数量。从图表 3,我们可以更清楚地看到MIG是如何对整个 GPU 去进行切割。在 A100 中,我们共有 8 份内存以及 7 份流处理器可以使用。其中,最小的实例 MIG 1g.5gb,具备一份内存和一份流处理器。而 MIG 2g.10gb 具备两份内存以及两份流处理器。需要特别注意的是,MIG 3g.20gb 和 MIG 4g.20gb虽然具备的流处理器数量不同,但同样拥有四份的内存。最大的实例 MIG 7g.40gb 则具备所有的流处理器以及内存。在使用时,我们可以灵活的分配实例的大小。举例来说,我们可以使用一个 4g.20gb 实例、一个 2g.10gb 实例,以及一个 1g.5gb 实例。图表 4 展示了我们使用的 GPU 实例。这里需要注意的是,虽然我们使用了所有的流处理器,但只有用到 7 份的内存,有一份内存会浪费掉。
注意:GPU实例编号依据:1、2、3、4、7五种slice(按照计算单元compute来划分)
当然,目前 MIG 的使用上还是有限制的。首先,MIG 只支援 Linux 系统,并且要求CUDA 11 以及 450.36.06 以后的 NVIDIA 驱动软体。另外,在开启 MIG 时,不支援图像的接口(像是 OpenGL)、不支援 GPU to GPU P2P 的传输 (包括 PCIe 和 NVLINK)、GPU instance 之间的 CUDA IPC 也不支援,但支援计算实例之间的 CUDA IPC。
至此,我们已经展示了 MIG 带来的好处。但管理者要如何去管理这些 MIG 实例呢?要如何避免使用者之间只能使用被分配到的 MIG 实例,而不会去影响到其他的 MIG 实例呢?在 CUDA 11 里头,管理者可以透过赋予使用者访问特定檔案的权限来限制使用者对 MIG 实例的使用权限。这些管理的檔案放在 “/proc/driver/nvidia/capabilities” 这个资料夹下,如图表 5 所示。对于 MIG 的管理,可以透过 “mig/config” 和 “mig/monitor” 来控制权限。其中,”mig/config” 一般只有 root 权限有访问的权限。拥有访问这个檔案权限的使用者能够管理 MIG 的实例,例如实例的创建和删除。而 “mig/monitor” 的权限则能让使用者看到整个 GPU 的资讯,例如目前 GPU 内存的使用量、是否开启 MIG 模式等等。除了上述两个管理和监控 MIG 支援的权限之外,MIG 也提供针对特定 GPU 实例或是计算实例的使用权限。例如若要让使用者能够只能使用图表 5 当中的 gpu0 中 gi0 GPU实例下的ci0计算实例,则赋予该使用者访问 gpu0/gi0/access” 和 “gpu0/gi0/ci0/access” 这两个檔案的访问权限,并且移除该使用者访问其他实例的权限。如此一来,此位使用者便只能使用该实例而无法接触到其他实例。
图表5 MIG 管理树状图
在这个章节当中,我们会一步一步的展示如何使用 MIG。MIG 的相关指令都整合进了 NVIDIA System Management Interface(nvidia-smi)当中。要开启 MIG,首先需要关闭所有和 GPU 相关的程序,因为启动 MIG 的时候会对 GPU 进行重启。其次,开启 MIG 一般需要 root 权限。确认符合上述的条件之后,就可以透过来开启 MIG。需要特别注意的是,开启 MIG 之后,在还没有建立 GPU 实例和计算实例之前,是不能使用 GPU 的。如果使用者在这个情况下直接去执行程序,会返回找不到相关装置的错误。如图表 6 所示。在开启 MIG 之后,nvidia-smi 展示的界面会有所改变,增加了一栏针对 MIG 的说明,如图表 7 所示。图表7 开启 MIG 之后的 nvidia-smi
sudo nvidia-smi mig -lgip来确认我们能够创建的 GPU 实例。图表 8 是我们将看到的样子。第一列是 GPU 的号码、第二列是各个实例设定的名称、第三列是创建该实例时使用的 ID、第四列是该实例剩余可创建数目,以及该实例最多可创建数目、第五列是该实例的内存大小、第七列是流处理器的数目。
创建 GPU 实例的指令为 “sudo nvidia-smi mig -cgi <GPU Instance profile ID>”。我们先透过下列的指令创建一个 1g.5gb 的实例,并且再次确认实例的资料sudo nvidia-smi mig -cgi 19sudo nvidia-smi mig -lgip
来确认我们能够创建的 GPU 实例。图表 8 是我们将看到的样子。第一列是 GPU 的号码、第二列是各个实例设定的名称、第三列是创建该实例时使用的 ID、第四列是该实例剩余可创建数目,以及该实例最多可创建数目、第五列是该实例的内存大小、第七列是流处理器的数目。
从图表 9 我们可以发现,1g.5gb、3g.20gb、7g.39gb这三个实例剩余可创建数目减少了1。这是因为我们在创建一个 1g.5gb 实例之后,我们剩下 6 份流处理器和 7 份内存,因此无法再创建 7g.39gb 的实例,3g.20gb 的实例由于需要四份的内存,因此也只能再创建一个。下一步,我们一次再创建两个 1g.5gb 实例以及一个 4g.20gb 实例。sudo nvidia-smi mig -cgi 19,19,5sudo nvidia-smi mig -lgip
从图表 10 我们可以看到,所有 GPU 实例的剩余可创建数目都为 0。接下来,我们可以透过 “sudo nvidia-smi mig -lcip”看到我们现在拥有的 GPU 实例,以及可创建的计算实例。图表 11 展示了我们可以创建的计算实例有哪些。第一列代表的是所属的 GPU、第二列是所属的 GPU 实例的 ID、第三列是该计算实例的名称、第四列是创建该计算实例的 ID、第五列是该计算实例剩余可创建数目及最大可创建数目、第六列是该计算实例拥有的流处理器数目。另外,我们可以发现,表格中没有关于内存的资讯,这是因为一个 GPU 实例里头的所有内存是共用的,因此在创建计算实例时不需要再进行分配。例如 GPU 实例 ID 7、8、9 他们都是 1g.5gb 的 GPU 实例,因此都只能创建一份 1g.5gb 的计算实例。而 GPU 实例 ID 2 是一个 4g.20gb 的 GPU 实例,可以创建 4 个拥有 14 个流处理器的 1c.4g.20gb 的计算实例、或者 2 个拥有 28 个流处理器的 2c.4g.20gb 的计算实例、或者 1 个拥有 56 个流处理器的 4g.20gb 的计算实例。
下一步,我们透过 ”sudo nvidia-smi mig -gi <GPU Instance ID> -cci <Compute Instance Profile ID>” 在 GPU 实例 ID 7、8、9 上面各创建一个 1g.5gb 的计算实例,并在 GPU 实例 ID 2 上面创建两个 1c.4g.20gb 的计算实例与一个 2c.4g.20gb 的计算实例。sudo nvidia-smi mig -gi 7,8,9 -cci 0sudo nvidia-smi mig -gi 2 -cci 0,0,1sudo nvidia-smi mig -lcip
在创建完之后,我们可以会发现计算实例的资料会有所改变,如图表 12所示,可以发现所有 GPU 实例的可创建计算实例数目都为 0。接下来,我们再回头来看一下 “nvidia-smi” 目前的情况。从图表 13我们可以看见”MIG devices” 这一栏增加了新的资讯,里头包括了各个 GPU 实例的内存大小以及 ID,还有在 GPU 实例当中的计算实例的 ID 以及流处理器的数量。
图表12 计算实例资料-1
图表13 创建完计算实例后的 nvidia-smi
创建完计算实例之后,我们要如何在特定的实例上面执行我们的程序呢?目前,我们要在指定的 GPU 上面执行程序时,是透过 “CUDA_VISIBLE_DEVICES” 这一环境变数。而 CUDA 11 在这个环境变数上进行了扩充,除了能够指定第几个 GPU 之外,也能透过计算实例的 UUID 来直接指定使用哪个计算实例。
首先,我们透过 “nvidia-smi -L” 来得到所有计算实例的 UUID。从图表 14,我们可以看到各个计算实例对应的UUID。这边 UUID 的命名格式为MIG-<GPU-UUID>/<GPUinstance ID>/<compute instance ID>。以图表 14 为例,所有实例的GPU-UUID都是“38b3962a-109c-d69d-c3d3-3c2e8cff25cb”,而 MIG 1c.4g.20gb Device 0 的 GPU 实例 ID 为 2,计算实例 ID 为 0。
在得到计算实例的 UUID 之后,我们便可以透过 “CUDA_VISIBLE_DEVICES” 这个环境变量来指定。例如下面的指令可以在 2c.4g.20gbDevice2 上面执行程序:CUDA_VISIBLE_DEVICES=MIG-GPU-38b3962a-109c-d69d-c3d3-3c2e8cff25cb/2/2./bin/encoder_sample 32 12 32 12 64 1 0图表15为运行时 “nvidia-smi” 的结果。
图表15 在 2c.4g.20gb Device2 上运行程序
最后,在计算完之后,我们要删除目前现有的计算实例和 GPU 实例。首先,我们需要先删除 GPU 实例当中的计算实例,才能删除 GPU 实例。而删除计算实例的方式为 ”sudo nvidia-smimig -gi <GPU Instance ID> -ci <Compute Instance ID> -dci”。例如下面的指令能够删除 GPU 实例 ID 7 上的计算实例 ID 0:sudo nvidia-smi mig -gi 7 -ci 0 -dci下一步,我们可以透过 “sudo nvidia-smi mig-gi <GPU Instance ID> -dgi” 来删除 GPU 实例。例如下面的指令能够删除 GPU 实例 ID 7:sudo nvidia-smi mig -gi 7 -dgi
图表16 删除 GPU 实例 ID 7之后的 nvidia-smi
透过 "nvidia-smi",我们能看到 GPU 实例 ID 7已经被删除,如图表 16 所示。最后,我们透过以下的指令删除剩余的计算实例和 GPU 实例:sudo nvidia-smi mig -gi 2 -ci 0,1,2 -dcisudo nvidia-smi mig -gi 8,9 -ci 0 -dcisudo nvidia-smi mig -gi 2,8,9 -dgi透过 "nvidia-smi",我们能看到所有的 GPU 实例和计算实例都已经被删除,如图表 17所示。
图表17 删除剩余计算实例与 GPU 实例后的 nvidia-smi
透过 nvidia-smi 我们可以看到已经将 MIG 模式关闭,如图表 18 所示。
图表18 关闭 MIG 之后的 nvidia-smi
应用案例分享 — 以 Faster Transformer 为例
在这个章节,我们透过一个实际的例子来展示如何使用 MIG,以及 MIG 带来的效果。这里,我们使用的例子是 FasterTransformer (FT),这是 NVIDIA 发布的开源代码,针对 transformer 相关的推理进行了优化。FT 最新的代码在https://github.com/NVIDIA/DeepLearningExamples/tree/master/FasterTransformer/v2.1,使用者可以透过 git clone 下载,并按照说明檔来将 FT 建立起来。建立的流程在此不再赘述。需要特别注意的是,由于 A100 是 compute capability 是 80,在建立 FT时需要将-DSM 设为 80。
在建立完 FT 之后,我们接下来创建 7 个 1g.5gb 的 GPU 实例,并且在各个 GPU 实例上面创建一个计算实例。
nvidia-smi mig -cgi 19,19,19,19,19,19,19
nvidia-smi mig -gi 7,8,9,11,12,13,14 -cci 0
接下来透过
nvidia-smi -L
得到所有计算实例的名字之后,透过 CUDA_VISIBLE_DEVICES 这个环境变量来指定。
透过 nvidia-smi,我们可以看到7个实例同时在运行,如图表 19 所示。
接下来,我们展示 A100 在使用 MIG 前后的计算速度以及吞吐量的比较,并且和前一代的 GPU,NVIDIA T4 和 NVIDIA V100 进行比较。其中,NVIDIA T4 和 NVIDIA V100 的 CUDA 版本是 CUDA 10.2,NVIDIA A100 的 CUDA 版本是 CUDA 11。另外,这边只比较使用 FP16 的速度。当 A100 使用 MIG 时,若没有特别说明,我们的 GPU 实例和计算实例大小相同,并且每个 GPU 实例只使用一个计算实例。
表格 3 比较了 V100、T4、A100 不使用 MIG,A100 使用 7 个 MIG 计算实例、以及 A100 不使用 MIG 但使用 MPS 同时跑七个程式的时延以及吞吐量。这里需要特别注意的是,A100在batchsize 1时,会比 V100 还慢,这是由于 CUDA11 的新特性,FT 在使用 cuBLAS 时无法手动选择算法导致。从表格当中我们可以看到,在 batch size = 1 这种计算量比较小的情境下,MIG 可以带来 4 倍以上的吞吐量,而代价是时延会提升百分之五十。MPS 的效果则稍微比 MIG 要好一些。和上一代的 V100 与 T4 对比,A100 在开启 MIG 之后,吞吐量也提升成 3~4 倍。而在 batch size=128 这种计算量较大的情境下,开启 MIG 并不会带来什么效益,由于使用的流处理器较少(在使用 MIG 时,最多只能使用 98 个流处理器,而 A100 有 108 个流处理器),因此吞吐量反而会些微的下降。在这种情境下,A100 的吞吐量为 T4 的 6 倍以上,V100 的两倍左右。
表格 4 比较了 V100 与 A100 使用 7 个 MIG GPU 实例在不同 batch size 下的吞吐量与时延。我们可以看到在 batch size 为 8 的时候,A100 的吞吐量已经很接近峰值,距离峰值不到百分之十;另一方面,V100 在 batch size 8 的食后,吞吐量距离峰值还有百分之三十左右,在 batch size 32 时,吞吐量距离峰值也还有百分之十左右。这代表和上一代的 GPU 相比,MIG 在提升 GPU 的使用率上有很大的进步。
表格 5 和表格 6 比较了A100、A100 使用一个 7g.40gb 的计算实例、以及 A100 使用 7 个 1g.5gb 的计算实例,在 BERT Base 和 BERT Large 上的差别。从这两张表格当中,我们可以得到几个结论。首先,A100 在不使用 MIG 下,和使用一个 7g.40gb 的实例下,其吞吐量和时延都差不多。其次,在 BERT Base 这个较小的模型上,MIG 在 batch size 1 时能带来四倍以上的吞吐量、在 batch size 4 时能带来两倍以上的吞吐量。只有到 batch size 64 以上才没有什么效益。而在 BERT Large 上,在 batch size 1 时,MIG 能带来百分之五十以上的提升,但在更大的 batch size 上,MIG 就没有什么明显的意义。
MIG 是新 GPU 架构-安培,以及 CUDA 11 推出的新特性。它最多能将一个 A100 GPU 切分成 7 个 GPU 实例,大幅提升 GPU 的使用率,同时藉由硬件上的分离提供可靠的服务品质与错误的分离。更多 A100 与 MIG 的相关资讯,可以访问
https://www.nvidia.com/en-us/data-center/a100/
https://docs.nvidia.com/datacenter/tesla/mig-user-guide/index.html#cuda-visible-devices
欢迎大家前往参考。