生成式AI领域的最新成果都在这里!抢 QCon 展区门票 了解详情
写点什么

玩转 GPU 实例 – 我的 Linux 工具箱

  • 2020-04-08
  • 本文字数:6229 字

    阅读完需:约 20 分钟

玩转GPU实例 – 我的Linux 工具箱

前言

显卡意味着什么?在不同的玩家心目中会有许多不同的答案。对我来说,开始着迷于显卡要从横空出世的 Voodoo 说起。那时候显卡市场的王者 3dfx 推出的一系列产品无论是游戏画质还是高分辨率下的流畅度都是其它产品望尘莫及的,市场的份额曾经高达 85%。只是那时候我的认识中显卡只是与游戏、视频输出效果这些场景有关,没有想到后来的所谓 GPU 居然有了今天的局面。至于后来 NVIDIA Force 的卧薪尝胆、ATI Radeon 的惊艳亮相以及 Matrox、S3 等刹那的辉煌……这些都让每一个玩家难以忘怀。



大约十年前,在饭桌上听同事说起他在读博期间参与的项目,提到了使用 CUDA 开发来以提高浮点运算的速度。那时候只是觉得所谓的高性能计算(HPC)距离我们还很远,Nvidia 的显卡用来加速运算听起来固然有趣,但更多的只是饭桌上的谈资。哪里预计得到今天的大红大紫。


至于 AWS 上的 GPU 实例最早要上溯到 2015 年。那一年发布的 EC2 G2 实例第一次为开发者提供了云计算上的 GPU 服务。四块 NVIDIA GRID GPUs 显卡提供的处理能力,让我们可以真正体会 GPU 的实力。而随着机器学习尤其是深度学习的快速发展,又进一步加速了这个领域的发展。2016 年 9 月,构建于 NVIDIA® Tesla® K80 之上的 EC2 P2 实例面世了。高达 16 块显卡的配置,不免让我们对于机器学习的发展有了更多的期望。


显然,硬件的发展还是没有及时跟上算法的进步与数据膨胀。看着明显老迈的 P2 实例难免让我心生焦虑。幸好,2017 年 10 月的 P3 实例在千呼万唤中飘然而至。8 个 NVIDIA Tesla V100 GPU、Intel Xeon E5 处理器的 64 个 vCPU、488GB RAM 以及采用 Elastic Network Adapter 技术、高达 25Gbps 的聚合网络带宽显然成为了 GPU 实例中的王者。当然仅有豪华的硬件配置是不可能解决全部的问题,还需要每个开发者充分利用好这一资源平台。在 P3 之后发布的 P3dn 以及接下来即将到来的 P4 实例,将会提供更强大的计算平台,但这都需要每个使用者的精巧构思,力求物尽其用方可尽显 GPU 的强大的能力。


去年底因为参加 NVIDIA GTC 大会的需要,又一次连接上了我的 GPU 实例,又不得不重复以往做过许多次的工作,安装、配置、编译、优化 … 这些繁琐的操作突然感觉自己在不断重复之中似乎缺少了点什么。于是心生念头,将曾经在 GPU 实例上的心得写成脚本以利于今后工作之用。这些脚本会涵盖曾经尝试过的一些内容 :


  • GPU 实例的创建与管理

  • GPU 实例的基础配置

  • 实例的系统优化

  • 实例的网络优化

  • Intel 软件的安装配置

  • OpenCV 编译安装

  • 开发工具篇

  • Nvidia 软件篇

  • Jupyter 的安装配置

  • OpenMPI 编译与配置

  • Horovod 配置

  • 深度学习框架篇(Tensorflow、PyTorch 以及 Mxnet)


在这个技术高速发展的年代,个人的努力是非常渺小的。我的这些心得与积累或有不足甚至谬误之处。非常希望听到更多的反馈与建议,也只有群智群力才能使得我们曾益其所不能。

第一部分 : GPU 实例的创建与管理

使用过 AWS 的用户都应该有过创建 EC2 实例的经验。我们常用的方法不外乎 AWS 控制台、AWS 命令行工具、CloudFormation 模版工具以及第三方的运维工具(Terraform、puppet、ansibley 以及 chef 等)。从我的经验来看,AWS 命令行工具(awscli)应该是最麻烦的一个了。原因就在于我们需要熟练的掌握的参数实在是太多了,请看完整的 awscli 中创建实例的命令 run-instance 的完整参数 :


创建实例的脚本

相信对一个普通人来说这绝对是一个不能能完成的任务。但是,事情的另一面却是 AWS 命令行工具(awscli ) 提供给我们的绝对是一个强大的、可以随心所欲进行定制的工具。用好这个工具的一个简单而有效的方法就是脚本。毫不夸张的说,一个好的脚本带给我们的价值的巨大的。它不仅可以节省我们大量的重复性的工作的时间,还可以以一种灵活的、程序化方式满足各种各样的运维的需求。而创建一个 EC2 的 GPU 实例就属于这一类的范畴。好了,我的创建实例的脚本就是这个样子的


#!/bin/bash
instance_type="p3.16xlarge"
key_name="密钥名字"
security_group_ids="安全组ID"
subnet_id="子网ID"
placement="置放群组"
block_device_mappings=""
#http://169.254.169.254/latest/user-data/
user_data="ubuntu_userdata.txt"
ebs_mapping="ebs_mapping.json"
count="数量"
region="AWS区域"
#ubuntu 18.0.4 LTS
image_id=$(aws ec2 describe-images --owners 099720109477 --filters \
'Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server*' \
'Name=state,Values=available' 'Name=architecture,Values=x86_64' --query \
'reverse(sort_by(Images, &CreationDate))[:1].ImageId' --output text --region ${region})
owner="使用者"
current_date_time="`date +%Y%m%d%H%M`";
project="项目名称"
tags="ResourceType=instance,Tags=[{Key=owner,Value=$owner},{Key=date,Value=$current_date_time},{Key=project,Value=$project}] ResourceType=volume,Tags=[{Key=owner,Value=$owner},{Key=date,Value=$current_date_time},{Key=project,Value=$project}]"
# Using --dry-run to test
INSTANCE_ID=$(aws ec2 run-instances \
--image-id ${image_id} \
--count ${count} \
--instance-type ${instance_type} \
--key-name ${key_name} \
--security-group-ids ${security_group_ids} \
--subnet-id ${subnet_id} \
--ebs-optimized --associate-public-ip-address \
--block-device-mappings "file://${ebs_mapping}" \
--user-data "file://${user_data}" \
--region ${region} \
--tag-specifications ${tags} \
--output text --query 'Instances[*].InstanceId'
)
#aws ec2 wait instance-status-ok \
aws ec2 wait instance-running \
--instance-ids ${INSTANCE_ID} --region ${region}
IP_ADDRESS=$(aws ec2 describe-instances \
--instance-ids ${INSTANCE_ID} \
--query "Reservations[*].Instances[*].PublicIpAddress" \
--region ${region} \
--output=text)
echo "The instance is availiable now, access with : ssh ubuntu@${IP_ADDRESS}."
echo "Done."
复制代码

脚本中的参数

这段脚本的内容并不复杂。理解其中的几个关键的变量就可以灵活的配置使用。其中需要提前准备几个重要的变量是-


  • 实例的类型



以 P3 实例为例,P3 实例提供了三种实例大小:带有 1 个 GPU 的 2xlarge,带有 4 个 GPU 的 p3.8xlarge 以及带有 8 个 GPU 的 p3.16xlarge。脚本中可酌情选择,例如:


instance_type=”p3.16xlarge”


  • 密钥对的名字



可以通过控制台、命令行创建。也可以将自己创建的公有密钥上传到将要使用的 AWS 区域上。关于这部分内容可以参考AWS文档,例如:


key_name=”id_rsa”


  • 安全组的ID



当我们创建实例时,以为该实例最多分配 5 个安全组。安全组是被用来控制到实例的入站数据流,以及另外一套单独规则以控制出站数据流。关于安全组的细节,请参考这里。在这里,我们的安全组设定需要开放 SSH 的端口以便于连接使用。例如:


security_group_ids=”sg-0f4bb098276d25df8″


  • 实例所属的的子网ID



子网是 VPC 内的 IP 地址范围,每个实例都要归属到一个字网当中。例如:


subnet_id=”subnet-06c44af45fcd8512f”


  • 置放群组



设置置放群组。这里提到的置放群组是放置实例的一种方式。针对深度学习,尤其是多节点分布式模型训练的场景,我们选择的是集群置放群组。这意味着,通过将一个可用区中靠近的实例打包在一起。可以实现所需的低延迟网络性能,以满足分布式模型训练通常使用的紧密耦合的节点到节点通信的要求。关于置放群组,可以通过这里了解更多。例如:


placement=”GroupName = DL-pg”


  • 块设备映射项



这里不需要使用这项设置


例如:block_device_mappings=””


上述的这些项目中,密钥对、安全组、VPC 子网以及置放群组需要预先设置好。此外,还需要了解以下几个重要的参数:


  • 用户数据



这个参数是要提供给实例的用户数据。在实例启动的时候,用户数据会被自动执行,通常用来帮助我们完善实例的构建,例如安装/升级程序包等。需要注意的是,用户数据在被执行的过程中是不能够进行与用户的交互的。在官方的文档中,并没有设计 Ubuntu 的用户数据样例。因此构建一个没有交互的自动执行的用户数据是非常关键的一步。在我的实践中,这样的一个脚本是可以很好的被实例所执行。


#!/bin/bashset -e -xexport DEBIAN_FRONTEND=noninteractiveapt-get update &&    apt-get -o Dpkg::Options::="--force-confold" upgrade -q -y --force-yes &&    apt-get -o Dpkg::Options::="--force-confold" dist-upgrade -q -y --force-yesapt-get -y autoremoveapt-get -y install awscli ec2-instance-connect git chrony screen
curl http://169.254.169.254/latest/user-data/ -o /home/ubuntu/userdata.shchmod +x /home/ubuntu/userdata.shmkdir -p /home/ubuntu/Projectschown ubuntu:ubuntu /home/ubuntu/Projectsmkdir -p /home/ubuntu/Downloadschown ubuntu:ubuntu /home/ubuntu/Downloadsecho "#---------------------¬" >> /home/ubuntu/.bashrc
复制代码


这段脚本完成的任务有 通过 apt-get update、apt-get dist-upgrade 完成的系统与软件包的升级;常用软件的安装 apt-get -y install awscli ec2-instance-connect git chrony screen;以及创建我们后续将要使用到的一些目录。我们也可以按照自己的需要进行合理的增减。要注意的一点就是不要有任何需要交互的操作,否则这个 userdate 将不会被正确的执行。另外 userdata 的大小需要控制在 16K 之内。


  • 实例数量



创建的实例的数量,这对于需要同时创建多个同样实例的场景非常用用。例如分布式训练等。例如:


count=”5″


  • AWS 区域



这里所谓的区域都是一个单独的地理区域。“区域”对于理解 AWS 的基础设施是非常重要的一个概念。如果需要更多的了解,需要参考这里。对于每一个区域都有对应的代码。例如 中国(北京)区域 的代码为 cn-north-1;中国(宁夏)区域的代码为 cn-northwest-1。

关于 Ubuntu 18.0.4

事实上,我们在使用一个 GPU 实例的时候(例如 P3 实例)会有许多个 Linux 分发版本的选择,例如 Amazon Linux 2 、Centos 以及 Ubuntu 等等。但是不得不强调的就是 NVIDA 的 CUDA 对于众多 Linux 的分发版本来说支持最好的莫过于 Ubuntu。我曾经大费周折的试图在 Debian Stretch 上为我的 GTX 1070 安装最新版本的 CUDA 。但是屡经挫折之后不得不回到了 Ubuntu 之上。按照 Canonical (Ubuntu 的开发商)的声明,Ubuntu 的下个月即将发布的 Ubuntu 20.04 LTS 将会集成 NVIDIA 私有的显卡驱动,这无疑增强了我们继续选用的信心了。


在 AWS EC2 的实例上安装 Ubuntu 18.04 不是件困难的事情。在 AWS 推荐的快速启动的操作系统清单中就提供了 Ubuntu18.04 的选项。



但是,不好的地方在于每一个操作系统的镜像(AMI)都需要有一个 AMI 的 ID。例如美国俄勒冈区域的 Ubuntu 18.04 的 64 位 X86 的 AMI ID 为 ami-0d1cd67c26f5fca19。但是不同的 AWS 区域当中的 Ubuntu 18.04 的 AMI ID 确是完全不同的。这里有一个小的技巧可以帮助我们简单的获取每个区域的 Ubuntu 18.04,只需要提供区域的代码即可。


image_id=$(aws ec2 describe-images --owners 099720109477 --filters \'Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server*' \'Name=state,Values=available' 'Name=architecture,Values=x86_64' --query \'reverse(sort_by(Images, &CreationDate))[:1].ImageId' --output text --region ${region})
复制代码


这里的关键是使用了不同 AMI 提供着的 owner 这个参数以及不同的 AMI 的描述信息。同样的方法也适用于其它的操作系统,例如 Amazon Linux 2 等。

标签(Tag)的用法

对于 AWS 资源打标签(tag)绝对是一个非常有用但很容易被忽视的地方。那么什么是“标签”呢?标签是指为 使用的 AWS 资源分配的标记。每个标签都包含我们自行定义的一个键和一个值。标签可让我们灵活的按照各种标准 (例如项目、用途、所有者) 对 AWS 资源进行分类。这在具有大量相同类型的资源时将会很有用的功能 — 可以根据分配给资源的标签快速识别特定资源。例如,您可以为不同项目的 Amazon EC2 实例定义一组标签,以跟踪不同项目实例的使用情况以及成本的状况。简单的使用方法如下:


owner="使用者名字"current_date_time="`date +%Y%m%d%H%M`";project="项目名称"tags="ResourceType=instance,Tags=[{Key=owner,Value=$owner},{Key=date,Value=$current_date_time},{Key=project,Value=$project}] ResourceType=volume,Tags=[{Key=owner,Value=$owner},{Key=date,Value=$current_date_time},{Key=project,Value=$project}]"
复制代码


这里标签的名称与标签完全是由我们自行定义的。在上面的这个例子中,就定义了实例的使用者、实例建立的日期、实例所属的项目的名称等。

网络存储(EBS)的设定

Amazon Elastic Block Store (EBS) 是 AWS 提供的一种数据块存储服务,通常与 EC2 一起使用。对于我们即将创建的实例这是一种非常适用的存储方式。设定实例中所使用的 EBS 的配置,需要在一个配置文件中声明。例如:


[{    "DeviceName": "/dev/sda1",    "Ebs": {        "DeleteOnTermination": true,        "VolumeSize": 64,        "VolumeType": "gp2",        "Encrypted": false    }}]
复制代码


在这个配置中,“DeleteOnTermination”声明了当实例终止时需要删除该存储卷;


“VolumeSize”设置的是存储容量的大小,单位是 GB;“VolumeType”需要在高性能的 io1、通用型的 gp2、吞吐量优化的 st1 以及最低成本的 sc1 四种类型中进行选择。关于这四种类型的差异可以通过这张表来一窥究竟



最后的设置项是关于数据加密。“Encrypted”用来声明存储在 EBS 上数据是否以加密方式存储。无疑,选择加密存储会很好的保护我们的隐私数据。

创建实例与连接到实例

最后的一个步骤就是利用 aws ec2 run-instances 命令在我们准备好的参数与配置项之上创建我们需要的实例。并且为了后续操作的方面,会将实例绑定 Public IP 显示出来。


IP_ADDRESS=$(aws ec2 describe-instances \
--instance-ids ${INSTANCE_ID} \
--query "Reservations[*].Instances[*].PublicIpAddress" \
--region ${region} \
--output=text)
echo "The instance is availiable now, access with : ssh ubuntu@${IP_ADDRESS}."
echo "Done."
复制代码


这样我们就可以利用 ssh 命令登陆到这台实例上面。但是,对我们而言长时间的记住一组 IP 地址显然是不切实际的。我的工作习惯是准备一组关于 EC2 使用的 Linux 的别名(在我的.bashrc 文件中定义)。通过这些别名/命令来帮助我们找到实例,甚至是帮助我们关闭或者启动实例。


alias ec2_list='aws ec2 describe-instances --output table –query '\''Reservations[*].Instances[*].[InstanceId,ImageId,State.Name,PublicIpAddress,Tags[*].Value | [0]]'\'
alias ec2_start='aws ec2 start-instances --instance-ids'
alias ec2_stop='aws ec2 stop-instances --instance-ids'
alias ec2_terminate='aws ec2 terminate-instances --instance-ids'
复制代码


只需要在命令行输入 ec2_list –region cn-northwest-1 ,就能够看到在我的账户在中国(宁夏)区域上的全部 EC2 实例,包括该实例的 Public IP。


到这里我们的 GPU 实例应该已经创建完成。接下来我们要对这台实例进行细致的优化与配置,我将在该系列的下一篇继续这项工作。


本文转载自 AWS 技术博客。


原文链接:https://amazonaws-china.com/cn/blogs/china/play-with-gpu-instances-my-linux-toolbox/


2020-04-08 15:34922

评论

发布
暂无评论
发现更多内容

《恰如其分的软件架构》随笔一:模型是解决复杂问题的重要途径

panda

模型

在线SVG在线编辑器

入门小站

工具

JVM进阶(六):鲜为人知的二次标记

No Silver Bullet

JVM 日志分析 2月月更 二次标记

Netflix是如何做决策的? | 2. 什么是A/B测试

俞凡

数据分析 netflix 大厂实践 2月月更

JVM进阶(三):内存分配与回收策略

No Silver Bullet

Java JVM 内存分配 2月月更

JVM进阶(五):JAVA GC 之标记

No Silver Bullet

JVM 2月月更 标记 MAT

一条SQL更新语句是如何执行的?

蝉沐风

MySQL MySQL InnoDB

[架构实战营] 模块八作业

Geek_0ed632

「架构实战营」

团队开周会的目的:保证有效的协同效应和构建PDCA循环

panda

管理 PDCA 周会 协同效应

Netflix是如何做决策的? | 5. 在做决定时建立信心

俞凡

数据分析 netflix 大厂实践 2月月更

Netflix是如何做决策的? | 1. Netflix的决策制定

俞凡

数据分析 netflix 大厂实践 2月月更

WebRTC 传输通道的建立过程解析 | 社区征文

liuzhen007

音视频 新春征文 2月月更

开源效能可视化平台介绍 -DevLake

夏兮。

效能平台 MARI

视频绿幕抠像一键搞定,这些好用工具你要知道。

彭宏豪95

效率 工具 视频剪辑

守护石谈学习Java之路

DaemonStone

Java 学习方法 经验分享 编程学习

计算机视觉算法探究:OpenCV CLAHE算法详解| 社区征文

老猿Python

AI 算法 计算机视觉 新春征文 CLAHE

共赴冰雪之约,见证体育场馆的数字化之旅

脑极体

架构训练营 week8 课程总结

红莲疾风

「架构实战营」

2021考了个PMP

夏兮。

PMP Certification

图解MySQL(5)-Buffer Pool的flush链表

JavaEdge

2月月更

Netflix是如何做决策的? | 4. A/B测试结果之假阴性和统计功效

俞凡

数据分析 netflix 大厂实践 2月月更

Linux之top命令

入门小站

Linux

第七节:SpringBoot高级属性配置二

入门小站

springboot Java EE

在线标准程序员计算器

入门小站

工具

如何写好代码注释?

蜜糖的代码注释

Java 后端 开发 2月月更

架构训练营 week9 课程总结

红莲疾风

「架构实战营」

如何阻止软件退化?

蜜糖的代码注释

Java 后端开发 项目实践 2月月更

Netflix是如何做决策的? | 3. A/B测试结果之假阳性和统计显著性

俞凡

数据分析 netflix 大厂实践 2月月更

JVM进阶(二):初识 JAVA 堆

No Silver Bullet

Java JVM 内存 2月月更

对 HTTP 缓存的全面总结

编程三昧

缓存 前端开发 HTTP 2月月更

Jvm 参数默认值

努力努力再努力

玩转GPU实例 – 我的Linux 工具箱_文化 & 方法_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章