【个人总结】基于项目的AI Studio平台下Linux深度学习环境配置心得

前言

PS:本部分主要是对本周工作的总结,标题对应的内容可以跳过本部分
上周主要的工作是研究了一下项目utils文件夹中的内容,实现了针对于各类数据集例如EgoHands、GTEA和EGTEA的data_loader,用于模型的训练。并且完成了数据增广相关的方法,与data_loader结合后能够有效地提升数据泛化能力。
语义分割问题场景的数据一般都是原图及其对应的像素级标注。例如项目研究的手部分割问题,则是手部的Mask图像,将手从空间中分割出来。
值得一提的是在原论文中使用的GTEA与EGTEA的基础上,官网已经对这个数据集进行了进一步扩充,相信在模型结构结合最新技术进行优化与调参后,使用该数据集能够更好地提升手部分割的效果。EgoHands官网提供了三种可下载文件分别是标注数据集、原视频和全部的视频帧。标注数据集中的数据可以理解为从全部视频帧中采样得到,而正如官网提到的,也可以用于手部追踪之类的工作。但是标注并非是直接提供了Mask图像,也就是无法直接用于data_loader中,经过各种查看与研究也未能找到。不过,官网提供了MATLAB API,能够生成Mask图像,经过对其用法的简单学习便可以编写一个批量处理的工具得到Mask图像。生成好的数据集我已经放到了AI Studio上,也算是对平台小小的回馈吧。

这样所有的手部分割数据集便收集好了,在此基础上进行了目录设计统一化,方便项目的使用。但是数据集直接使用肯定是不合理的,需要对训练集和验证集进行划分。基于之前看到一个ResNet教程作者提供的划分工具,对其进行了简单的改造,也能够统一的划分图像及其对应Mask标签。这类工具的设计比较简单,就是遍历文件夹,然后通过随机数随机划分到train和val两个文件夹中,对用过Python的同学来说应该不是特别困难。
使用这个工具便可以将数据集划分,几个数据集的处理便基本完成了。然后便可以进入模型的搭建过程了。
项目目前的思路主要是先复现论文作者的效果,然后再按照上面提到的方法进行改良。所以首先还是从论文代码出发。论文使用的主干为Wide ResNet,然后配合特殊的模块,使用Batch Normalization和空洞卷积等技术。而模型中很多模块并非PyTorch中内置的,需要自己编写供模型调用,同时可能是出于速度和效果的考虑。编写并非通过Python进行,而是使用近似C++的CUDA语言编写,然后用nvcc编译,再通过PyTorch进一步处理得到so文件链接库,从而供模型直接使用。过程很像是用C++为Python编写库,只不过如同pyc文件,其内容已经锁死,并不是像开源库提供py文件可以直接看到代码。最初我对这些过程并不了解,毕竟从没有用CUDA为PyTorch写过扩展包,所以也走了很多弯路。
由于时间关系,并没有好好研究这些自定义模块,基本是改了改路径直接复制过来,这也引发了后面很多问题。
有了模块以后,便可以像搭积木一样编写模型,其设计的原理我也不太懂,只是照着葫芦画瓢走了一边代码,打算在复现成功后的优化过程进行进一步研究。
后来我发现,代码中训练过程用到的很多东西都自定义了,包括loss与评价标准,并且使用了比较高级的学习率控制机制,还是很有研究的余地的。
这样,所以的数据、工具包、模型、模块都编写好了,尽管还没有进行调试,便可以编写train、eval相关的代码了。深度学习框架的结构都很像,之前对Tensorflow有过简单的了解,PyTorch的思路便也不是太难。train一般通过argparse读入参数,然后定义一些量,读入数据,如果有预训练模型或者之前训练的过的Epoch对其进行读入继续训练,然后训练每个Epoch的所有batch后验证一下,再择优保存模型,平均标准对于语义分割问题使用了mIOU。
代码准备好了以后环境配置与进行训练的过程遇到坑还是挺多的,在后面的部分进行介绍。虽然最后基本解决了这些问题,但是花费的时间还是不短的。
研究代码的体会还是觉得深度学习就是高维度下的模式识别,尽管用了很多高级的方法与强大的算力去提高训练速度与拟合泛化效果,但还是离不开其本质,尽管对于比较高级的问题。不过我觉得这个项目的意义挺大的,目前5G加上处理器性能的不断提高,AR/VR可能在未来并不只是玩具,而有很大的实际应用前景。三维重建、语义分割例如项目中对手部的精准分割能为其提供很大的帮助,无人驾驶领域也与之有关,还是很值得研究的。

AI Studio及其使用技巧

我自己的电脑去跑这些数据肯定是不行的,配置好了环境后一上来就cuda就提示out of memory,而实验室的电脑目前用不了,所以果断使用AI Studio来训练。
AI Studio是百度开发的一个深度学习模型训练的云平台,发展到现在我在使用过程中觉得可以说是非常完善了。功能很人性化也很符合实际需要,包括自主研发的深度学习框架Paddle Paddle也能看出百度在向人工智能领域转型的决心。
虽然说AI Studio不是免费的,毕竟服务器和带宽费用都很贵,但是每天赠送12个小时时长,连续登陆还有更多额外奖励。之前参加活动拿到一张100小时算力卡,过期了没用现在感觉好可惜。AI Studio的配置还是很可以的,16G显存的Tesla V100和32G内存。虽然比实验室的稍微差一点但毕竟是面向大规模用户,投入可想而知。不过不带Tesla V100的环境是免费的,如果需要Linux环境还是可以考虑的,虽然没有sudo权限,但是很多常用的工具都有了,使用pip也没有限制,清华镜像等等也都配置好了,总体网速也是挺快的。
创建环境的时候可以选择Python版本与模式,为了灵活性,推荐使用Notebook模式,其他几个没怎么用过。另外我开始以为项目因为使用的一些包的限制Python3下无法运行所以使用了Python2,后来发现其实没有影响,这个在后面再说。
虽然说使用Notebook模式,但并不去用jupyter,因为这个模式下可以使用终端,那么就相当于拥有了一台无sudo权限的高性能Linux服务器。但是注意一点,用户目录下有work和data两个文件夹,整个服务器也就只有work不会被清空,data应该只保留你创建时选择的数据集。所以东西都要存在work中。在侧栏设置里可以设置终端存活时间,也就会关闭页面后可以保留一会儿,最长10个小时,这样很有利于模型训练,记得设置checkpoint就好。如上面说的,一般pip的包因为保存在特定目录下,也会被清空,所以环境经常需要重配。没有去使用Paddle Paddle和而是自己装了PyTorch,并且也没有用选择的jupyter,白嫖的感觉越来越浓了,还是谢谢百度。
总的来说,AI Studio该有的都有了,其实和用学校的服务器跑模型没有太大差别。也可以上传和下载文件,不过上传大小是有限制的,所以不要指望上传数据集。
那么一般来说该怎么使用呢?
数据集可以在平台创建,然后以此为基础创建项目,或者在创建的时候选择,好像是最多上传10个,每个不超过10G,因为项目也就拥有100G硬盘肯定不能超的。这样它就会存在data文件夹中,因为数据集不会去审核,我觉得其实很多大文件放在里面也可以。
数据传好了在项目中在work文件夹下上传脚本的压缩包,解压出来以后通过tar或者unzip之类的把data总的数据集解压到work文件下的目录,就可以使用了。
这样相当于把自己电脑上的东西转移到了服务器上,上传速度感觉也挺快的,比国外例如亚马逊、谷歌提供的平台也友好很多。缺点就是可能下载国外的东西会有点慢,但比自己的电脑一般还是快一些。数据集除了这种方式也可以通过wget下载,只是因为很多数据集都是国外的会有些慢,所以不一定比本地上传快(前提你之前已经下载过了,如果有国外服务器的话可以先下载好了再从服务器下载到自己的电脑上,有的会比直接下载快)。wget能做的事情太多了,包括下载数据集,连一些包都可以提前下载在work文件夹下,以后环境被清空了直接安装,再自己写个脚本,就再也不怕配置环境了。不过记得可以通过wget -c断点续传,对很多下载不下来或者很慢的东西有奇效。比如我测试发现一般下载一会儿就慢了,这时候ctrl+c然后断点续传速度就又回来了,甚至比原来还快。总的来说除了没有sudo权限,算力、带宽都有,用的比我双系统的Ubuntu舒服多了。
虽然没有sudo权限,但是一般的需要都能满足。包括给conda换个源提提速,或者下载一些数据和包,需要编辑就vim,但是AI Studio其实可以通过侧栏选择在Tab中在线编辑,效率更高也更人性化。系统甚至环境变量都可以修改,可以说已经给了很大自主权了,几乎无异于租了一台服务器。总之记得需要保存的东西放在work文件夹下。
直到我遇到了一个问题,我想更改CUDA版本,默认的是9.2,但是因为包的兼容性需要使用9.0。按照我以前的思路,这肯定要重装显卡驱动的,甚至要保存到系统文件夹下,sudo避免不了,后来发现AI Studio提高的权限其实已经够了。
通过wget下载CUDA9.0的run文件以后(不得不说速度真的快,峰值接近于100M/s,比我从U盘拷还快),然后提前再work下创建一个cuda文件夹,然后安装的过程中显卡驱动与某个链接库都不安装,因为必须要sudo权限,然后将cuda toolkit装在cuda文件夹下,也能完成安装。
这时候,nvcc -V,还是9.2。因为环境变量还没改,所以还是指向系统文件夹中。可以export -p查看一下,然后执行下面的指令:

export NVIDIA_REQUIRE_CUDA="cuda>=9.0"
export PATH=~/work/cuda/bin:$PATH
export LD_LIBRARY_PATH=~/work/cuda/lib64:$LD_LIBRARY_PATH
source ~/.bashrc

如果原来没有记得用declare。
再nvcc -V一看,已经降级到9.0了。但是也要考虑与显卡的兼容性,因为Tesla V100应该是支持9.0的,所以nvcc用起来没啥问题。
最终,连CUDA版本都更换了,数据随便wget,包也可以pip或者conda,环境被重置也不怕,完全建立在AI Studio提供的权限基础上。不过环境变量还是会被还原的,毕竟不在work文件夹内,提前写个sh文件每次运行跑一下即可。
另外apt-get应该是用不了,可能也有办法?我还没发现。但是对于一些程序可以下载源码然后自己在work文件夹下编译一下,最后如果有需要再加入一波环境变量。

PyTorch配置

PyTorch的配置卡了很久很久,甚至导致我自己的Ubuntu重装还陷过了无限登录界面,花了不少时间。这里主要介绍一下在AI Studio上的配置。
配置环境往往是很多任务中最恶心的事情,随着时间的发展,包的版本众多,而且包之间各种相互依赖,加上GPU也不断更新换代,CUDA版本也很多,所以尽管代码在原来作者的电脑上是没问题的,但是自己去跑却报各种错误。尝试的过程会花费很长的时间与很大的精力,这也正是为什么很多包都要写一个Require文件介绍其依赖的包。
软件因为难以一眼看穿其全部扩展与发展空间,所以迭代的过程中很容易出现一些大改动,尽管开发者们也都在尽可能提高其兼容性,但是有些问题还是需要某一特定版本。如果不在最新版本或者本机版本的基础上去重写代码,就只能尝试恢复作者的环境。这里因为时间原因选择了后者,尽管发现还是花费了很多时间。
发现如果torch版本较高,那么用cuda重写的模块加载就有问题,已经不兼容了,而只有0.4.0或者0.4.1效果比较好。而这两个版本也并非都可以,记得有一个还会导致与numpy出现不兼容,调整后又会引发新的问题,总之因为耦合性较高以及代码比较老所以互相制约,最终我觉得还是得重写代码以适配最新的PyTorch。
最开始尝试的是Python2.7,之前一个错误的理解以为Python3不支持0.4的PyTorch。AI Studio上的CUDA版本为9.2,Python2版本为2.7,而Python3版本为3.7,但不知道为啥conda其实3.6,所以中间一部分尝试也踩了坑,这里先不管了。
PyTorch的官网怎么也进不去,没法用那个版本选择,所以摸索了很久。虽然后来进去了,但其实用处也不是特别大。
总之,结论就是对于这两个版本,也就是不需要重写代码的版本,
CUDA9.0下py27 0.4.0和0.4.1都支持,py37只支持0.4.1
CUDA9.2下py27 只支持0.4.1,而py37也只支持0.4.1
可以参考这两个网站,支持的应该都会有相应的包:https://download.pytorch.org/whl/cu90/torch_stable.html
https://download.pytorch.org/whl/cu92/torch_stable.html
安装或者下载也比较简单,根据下面的方法改成需要的版本即可:
比如这个例子对应的环境是Linux CUDA9.2 Python2.7 PyTorch 0.4.1

pip install http://download.pytorch.org/whl/cu92/torch-0.4.1-cp27-cp27mu-linux_x86_64.whl
wget -c http://download.pytorch.org/whl/cu92/torch-0.4.1-cp27-cp27mu-linux_x86_64.whl

如果PyTorch的版本和CUDA或者说nvcc不匹配,那么运行CUDA写好的代码就会有问题。
所以可以发现,AI Studio下内置的CUDA9.2无论是Python2.7还是3.7都只能安装PyTorch 0.4.1,这就很有问题,因为0.4.1运行时和部分涉及到numpy的代码不兼容,只有torch-0.4.1.post2才可以(这个版本只有Python2.7才有)。那么是不是Python3.7 + CUDA9.2 + PyTorch0.4.1就可以了呢?后来发现有个指针错误,应该是来自CUDA写的模块,查了一下需要apt-get一个malloc包才可以,虽然不一定有用但是AI Studio下也无法apt-get,也尝试从GitHub上下载源码自己编译一下,然后链接一下nvcc编译的文件,但是并没有解决。也好像是因为CUDA9.2还是不够兼容,尽管使用了0.4.1.post2。具体记不清了,总之这个情况就是,互相制约,改好一个不兼容问题会有新的,几乎是不可能跑起来的,让我甚至想放弃AI Studio。
在被配置环境折磨得身心俱疲将要放弃的时候,我突然觉得没有必要动系统文件夹,不需要重装显卡驱动,毕竟nvcc就是一个编译工具,也没有必要放在指定位置,既然可以修改环境变量那么只需要安装在work文件夹下即可。所以CUDA降级应该是能实现的。
前提是,Tesla V100支持CUDA9.0。
很幸运,是支持的。
安装之前提到的方法装了CUDA9.0的nvcc后,重新编译了cu文件,然后通过PyTorch生成了对应可调用的so文件。这里突然想起来,我开始在Windows上配置环境,想配置好了再到AI Studio上跑是多么可笑,而且我还浪费了一下午,因为我在Windows下尝试调用so文件,而且还是作者编译的so文件,就算Windows能用我的电脑也不一定行。总而言之,还是自己Linux下编译吧。
结果还是报错,这次真的感觉自己没办法了,正在要放弃的时候又发现了这个build.sh代码有点怪。

#!/bin/bash

# Configuration
CUDA_GENCODE="\
-gencode=arch=compute_35,code=sm_35 \
-gencode=arch=compute_61,code=sm_61 \
-gencode=arch=compute_52,code=sm_52 \
-gencode=arch=compute_50,code=sm_50"


cd src
nvcc -I ~/work/cuda/include --expt-extended-lambda -O3 -c -o bn.o bn.cu -x cu -Xcompiler -fPIC -std=c++11 ${CUDA_GENCODE}
cd ..

可以看到我后来也想起来把链接库改成自己的nvcc 9.0的,但是依然没用。而这么CUDA_GENCODE又是什么呢?直到我找到这篇博客http://arnon.dk/matching-sm-architectures-arch-and-gencode-for-various-nvidia-cards/

不同的显卡支持不同的架构与CUDA版本,很幸运Tesla V100是支持到9以后,幸亏没尝试装CUDA 8.0,不然不知道又有什么错误。可以看到Tesla V100对应的是sm_70,在CUDA_GENCODE的Configuration中并没有,所以我将其修改为

# Configuration
CUDA_GENCODE="\
-gencode=arch=compute_35,code=sm_35 \
-gencode=arch=compute_61,code=sm_61 \
-gencode=arch=compute_52,code=sm_52 \
-gencode=arch=compute_50,code=sm_50 \
-gencode=arch=compute_70,code=sm_70"

也就是加了一行关于sm_70的,然后用nvcc重新编译cu文件,PyTorch编译为so文件,再重新跑代码,模型训练成功开始了。尽管代码里有些参数不太合适最后还改了一下,包括有些方法已经启用了,但是训练完全可以进行了。一反调试后没啥大问题了。

虽然这也不是长久之计,最后还是要重写代码的,但是经过一番折腾,感觉自己对CUDA环境配置有了新的认识,以后也许凭借这些经验会少踩一些坑。感谢自己坚持到了最后。
不过如果实在不行,那就重写代码吧,甚至不用自定义模块了,只是效果估计会差很多。
总结一下,包的版本很多,但注意nvcc -V和torch.version.cuda的版本要对应上,不然很容易报错。
另外之前一直不怎么了解PyTorch,以为大家都在用TensorFlow或者Keras没人用这个,就像Caffe,感觉都没啥人用了。后来发现这个框架还是非常常用的,尤其在学术界,地位不低于TensorFlow。

Python再认识

一开始学Python的时候就说Python3,这次因为一些原因也尝试了一下Python2。就我的使用而言,总体代码上差异不大,就说个别地方不太一样。比如print和input的用法,以及包的支持程度。
印象比较深的是Python3支持form . import进行相对引用,所以同一个模块的文件可以互相调用比较方便,Python2就会出错。
另外对模块由了新的认识,pip得到的放在指定的位置,因为加入到了环境变量可以直接调用。而自己写的模块也能调用,只是如果在同级文件夹下可能需要添加索引目录来调用,不然找不到。import的用法比我想象的复杂的多,一不小心很容易import不到。比如上层目录的包怎么调用,同级目录的包怎么调用,子目录的包怎么调用,从本文件夹下调用和从上层调用路径有什么区别,if name == 'main’的含义是什么,学问还是不少的。另外就是__init__.py,用处还是很多的。
import的问题也折腾了很久,现在其实也不是特别优雅,存在重复调用,勉强能用了,下次好好设计一下。
除此之外,模块又不一定是py文件,像上面提到的类C语言写的.so文件,以及非开源的.pyc文件。我们的代码一般都是建立在别人写好的模块的基础上,这些模块有的是继续调用别的,甚至是一个集成,有的则更接近底层。但前提是满足语言的语法。熟练的使用轮子的重要性也不压于造轮子,但要对语言底层有一定的了解,至少面试经常问。
另外再这次折腾之中,很多资源都因为在国外速度特别慢甚至无法访问,国内的镜像真的帮了大忙,速度提升巨大。包括pip和conda的包,以及一些GNU的工具,因为本机环境配置的时候出现了一个gcc版本问题导致显卡驱动无法通过dkms重构,所以又尝试自己编译了一下gcc,后来也没解决这个version match问题,还是重装显卡驱动了。下载不下来一般来说有镜像就通过镜像,没有就尝试找个中转,实在不行就一点点下,记得wget加上-c实现断点续传。

Linux再认识

这几天的感觉,相比于更加面向一般用户的Windows,Linux真的很优雅,尽管很多商业软件不一定支持。Linux更接近于书本上的操作系统,各种机制也比较原生,而Windows因为各种需要就复杂了很多。Linux同时也赋予了用户更大的权力,尽管BUG可能也会很多。Linux使用过程中可以更直观地看到和《操作系统》中的对应,也能更好地看到C与编译的痕迹,这也许就是开源的魅力吧。
shell确实很方便,无论是图形化界面下的shell还是ctrl+alt+F1后的shell,几行命令可以做很多事,有的时候GUI确实没那么重要。通过指令,或者说提前写好的程序,效率不比GUI低。程序都在shell进行,其实也是一种协调与统一。
但最大的感受还是面向开发方便了很多,比如各种编译、各种make和各种脚本,而且轻量级的系统运行的感觉更快,ssh和服务器连接感觉也比xshell方便很多。

后记

不得不说这几天真的是花了很多时间,各种折腾,各种报错。尽管相对于项目研究本身都是一些“预处理”的工作,也没有什么理论方面的难度,但“工欲利其事必先利其器”,对工具有更好地认识才能更好地从理论到落地吧。

发布了75 篇原创文章 · 获赞 28 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Swocky/article/details/105141693