0%

Ubuntu深度学习环境构建

零、前言

本文总结了在Ubuntu上的深度学习环境配置方法,大部分可类比到其他机型、系统上。尽管笔者装过不少系统,但鲜有总结方法经验。之前即没有形成一个体系成笔记记录下来,也没有形成自己的dotfiles使得能方便地移植到其他环境中。这造成的结果就是,每次换系统都要花大量时间进行折腾。为了加速上手新系统的速度而成此文,并初步构建了自己的dotfiles,目前能够在mac和linux上同步使用。谨以此文致敬在机器上折腾的青春~

实验室师兄毕业,笔者接管服务器一台,开始了维护机器的脏乱累之旅。中间经历了

69266485

69305996

以及出了问题蹲在一角研究到深夜的时刻...

69425003

Anyway,对一个Unix爱好者来讲,这是痛并快乐着的。

机器型号

笔者安装的第一台机器为戴尔Precision 7920塔式工作站,原本系统为windows,直接重装成Ubuntu18.04.04。第二台为一个组装机,两个2080Ti显卡,安装的系统和上一台一样。

一、必要配置

1.1 远程桌面安装

远程桌面安装其实不难,一个安装脚本就能搞定xrdp桌面的安装,笔者尝试了多种远程桌面的方式,虽然安装时挺折腾,但最后都成功了: - XRDP( ✨✨✨推荐) 我的博客 ,开源代码,代码的使用方法

1
2
3
4
# go to http://www.c-nergy.be/products.html
wget http://c-nergy.be/downloads/xRDP/xrdp-installer-1.2.zip
unzip xrdp-installer-1.2.zip
bash xrdp-installer-1.2.sh

安装之后发现和原版的远程桌面一样,这是我比较喜欢的桌面,初用体验是太卡。

  • No machine ( ✨✨推荐) 参考同上,这个方案还不错,但目前发现只能一个人连接(意思是需要氪金)。安装参考了这篇博客,并且还要按这篇博客来配置,方可正常使用。使用之余感慨Unix软件还是商业的做的漂亮...
  • VNC, 根据这个教程装好了,个人感受使用体验一般般,遂再也没用过。
  • 续:从github 找到的脚本,仅供参考
    1
    2
    3
    4
    5
    6
    7
    8
    9
    echo "================================="
    echo " Installing firefox / xrdp / etc "
    echo "================================="
    sudo apt-get update -y
    sudo apt-get install -y xfce4 xfce4-goodies
    sudo apt-get install -y firefox
    sudo apt-get install -y xrdp
    echo xfce4-session >~/.xsession
    sudo service xrdp start

1.2 相关镜像源配置

尽管下一条解决了这个问题,但是还是建议配好镜像源,毕竟快~ 笔者目前经常需要apt, conda, pip,docker等进行联网下载,因此镜像源是必须要配置的。源头可以使用清华源,建议把配置操作自动化成脚本。

1.3 命令行冲浪配置

有些时候必须要科学地使用命令行,比如用git从github上克隆项目,否则一些配置安装要等个几天几夜。笔者不喜欢点击网页的下载按钮,毕竟,命令行下载那么方便!

1
2
3
4
5
6
7
8
9
10
11
12
# 注:提前装好了miniconda 的环境
# 1.前期配置
pip install shadowsocks
sudo apt install privoxy
sed -i "s|cleanup|reset|g" /usr/miniconda3/lib/python3.7/site-packages/shadowsocks/crypto/openssl.py # openssl bug,换一下变量名就可以了
# 2.接着配置privoxy 略
sudo systemctl start privoxy
# 3.启动
sslocal -c ss.json # 配置文件
export http_proxy=127.0.0.1:1087
export https_proxy=127.0.0.1:1087
# done

1.4 网络配置

笔者最开始ip相关配置是直接在图形界面设置好的,因此没有使用命令行。图形界面配置一般不会有问题。中间笔者配第二台机器的时候,把子网掩码写错了,外界网站一直连不上,为此又折腾命令行的相关网络配置。查找资料的时候发现ubuntu管理网络的命令比较繁杂,ubuntu18.04.04使用的是netplan。 网络的配置写在/etc/netplan/01-network-manager-all.yaml这个文件。如果你想通过配置文件和命令行的方式来配置的话,可以编辑这个文件,初始内容如下

68060119.png

renderer这一行表示你想通过图形界面配置网络,如果是的那么后面就不用写了。通过文件来管理网络,笔者从网上找到的一个例子如下

1
2
3
4
5
6
7
8
9
10
# Let NetworkManager manage all devices on this system
network:
version: 2
# renderer: NetworkManager
ethernets:
ens33:
addresses: [192.168.0.111/24]
gateway4: 192.168.0.1
nameservers:
addresses: [192.168.0.1]

要注意yaml文件的同级缩进一致,以及和自己的网络各种配置保持一致。填错一个配置,可能会坑你一些时间! ## 1.5 ssh安装 我装的ubuntu18.04没有ssh服务端,还需要安装,才能从外界ssh连入。运行下面两行,ssh可以直接用啦。参考

1
2
sudo apt install -y openssh-client openssh-server
sudo service ssh start
## 1.6 创建用户和组

管理用户和组是系统管理员最基本的要求

1
2
3
4
5
6
7
8
9
10
11
12
groupadd 组名 # 新增组,只能是一个组,建多个用循环
adduser 成员名 # 新增成员

# 把成员加到组里去
adduser 成员名 组名 # 这个操作更简单
usermod -a -G 组名 成员名 # 等价
# 改变login shell为zsh
chsh --shell /usr/bin/zsh qiangzibro

# 当然还可以在建用户时就把上两条做好
# 例:建用户名为小刚的用户,并把他加到专业团队和篮球队这两个队,-s指定shell为zsh,-m指定创建家目录
useradd -G 专业团队,篮球队 -m -s /bin/zsh 小刚
  • 将所有用户添加到deepones组下 参考了一篇国外博客
1
2
3
4
for ID in $(cat /etc/passwd | grep /home | cut -d ':' -f1)
do
(sudo adduser $ID deepones);
done

直接用下面这种方式也很简单

1
2
for ID in  `ls /home`; \
do (sudo adduser $ID deepones);done

最后,笔者写了一个用来建用户和组的小脚本,只需要输入相关用户名、组名,就可以创建之并相关联。目前的情况是,实验室的成员放到一个组里,我给取的名字叫做deepones。为了使用docker,还需要将所有人放在docker组里,这样做解决了docker要用sudo的问题,也就是说,你不用sudo也能用docker命令了。当然,为了有管理员权限,还需要将所有人放在sudo组里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/bash
setup_groups(){
echo "🌝 Create user groups..."

for GROUPNAME in docker deepones

do
getent group $GROUPNAME 2>&1 >/dev/null && echo "INFO: $GROUPNAME already exists"|| groupadd $GROUPNAME
done
}
create_user(){
#----------------------------------------------------------------------------------
# 创建一个用户,并进行组设置、shell设置
#----------------------------------------------------------------------------------
[ -z $1 ] && echo "No user name input and abort!" && exit 0
USERNAME=$1

if [ -d "/home/$USERNAME" ]
then
printf "INFO: User \"$USERNAME\" already exists\n"
else
# -G 该用户的其他组还应该属于的组,可以有多个
# -m 创建用户的家目录
# -s 该用户的登录shell
# -p 该用户的密码
useradd -G docker,deepones,sudo -m -s /bin/zsh $USERNAME
echo "$USERNAME:$USERNAME" | chpasswd
fi
}

create_users() {
echo "🌝 Creating users..."
for user in qiangzibro daxiongpro haochen
do
create_user $user
done
}
setup_groups
create_users

Ubuntu显式地创建成员 useradd

1
>useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u 1001 ubuntu

useradd options (see: man useradd):

1.7 硬盘自动加载

新硬盘分区

实验室新买了两块2TB硬盘,放进机器后进行了分区、创建文件系统、开机自启设置操作,才能够进行使用。ubuntu的官方文档是个不错的参考。

首先使用下面命令查看硬盘以及分区

1
2
fdisk -l
lsblk # 也可

比如我们找到了这个硬盘叫/dev/sdc,那么首先对其分区

1
fdisk /dev/sdc # 对2TB硬盘进行分区,sd后面具体实际根据fdisk -l来看

再进行格式化

1
2
3
4
5
6
mkfs.ext4 /dev/sdc
# 格式化时可以指定磁盘的block size和Inode size
mkfs.ext4 -b 4096 -I 256

# 【存疑】不使用这个会报错
partprobe /dev/sdc

手动挂载硬盘

1
2
mkdir -p /mnt/2TB # 创建挂载点
mount /dev/sdb /mnt/2TB # 挂载

开机时自动挂载硬盘

打开/etc/fstab,对要开机自动加载的硬盘设置如下的格式

70558222.png

做软链接(可选)

我希望在每个硬盘下都建立了以用户为名字的文件,并建立了软链接到所有用户家目录。这样每个用户的家目录下面都可以看到对应硬盘的文件夹,同时又不会公用一个文件夹。像这样:

54072768.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for hardware in `realpath *TB*`
do
hardware_name=`basename $hardware`
for user in `ls /home`
do
dir="$hardware"/"$user"
linkdir=/home/"$user"/"$hardware_name"

echo "$dir --> $linkdir"
mkdir -p $dir
ln -s $dir $linkdir

chown -R "$user":deepones $dir
chown -R "$user":deepones -h $linkdir
done
done

遇到的问题

发现2TB的硬盘/dev/sda1被挂载了/boot/efi上,导致的情况就是这个硬盘暂时不能被格式化,也不能被直接挂载和使用了。

image-20200925105809886

而我之前装的系统,根目录和efi都是挂载在固态硬盘里的,这里面/dev/sda是固态硬盘

image-20200925105928294

【怎么解决?】要想使用这个硬盘,必须要解除掉/boot/efi的占用,把它挂载到另外一个地方

二、软件安装

2.0 dotfiles的哲学

一台空机器往往需要一些必备的工具,干活起来才会更“舒服”。不同人喜欢不同的软件,不同的配置。笔者也有自己的一套习惯,比如命令行终端的ohmyzsh,编辑文件使用neovim再加上自己的vimrc等等。而在新机器手动安装不同的软件、配置往往会花掉我们很多功夫。想要加速这个过程,可以编写自己的安装脚本,又或者使用容器技术,使得在任何环境下都有同样的配置。在知乎大神韦易笑的文章下,我建立自己的Qdotfiles,并自动化了配置和安装的过程,只需下面一个命令:

1
bash -c "$(curl -fsSL https://raw.githubusercontent.com/QiangZiBro/Qdotfiles/master/scripts/bootstrap.sh)"
并写了一个Dockerfile,让我的配置在容器里也能测试成功,这个过程中联系了一波docker的使用。要注意的是,Qdotfiles还处于个人维护阶段,直接拿到自己的系统使用也许仍然会有一些问题,但是可以使用容器,进行一些小的尝试。 下面常见的安装,都会总结到Qdotfile项目里。

2.1 zsh

oh my zsh

以前一直想装一次ohmyzsh,所有用户使用,后来读了这条建议后,发现没有必要。ohmyzsh是一套配置,它的核心还是zsh,每个用户各安装各自的配置即可。安装方式:

1
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

上面一条安装完了,想改变用户的登录shell为zsh,使用

1
sudo  chsh $USER -s $(which zsh)

插件管理

使用zplug,官方给的安装命令:

1
curl -sL --proto-redir -all,https https://raw.githubusercontent.com/zplug/installer/master/installer.zsh | zsh

将类似于下面的语句放在~/.zshrc里面,我用的插件有

1
2
3
4
5
6
7
zplug 'plugins/git', from:oh-my-zsh, if:'which git'
zplug romkatv/powerlevel10k, as:theme, depth:1
# zplug "plugins/vi-mode", from:oh-my-zsh
zplug 'zsh-users/zsh-autosuggestions'
zplug 'zsh-users/zsh-completions', defer:2
zplug 'zsh-users/zsh-history-substring-search'
zplug 'zsh-users/zsh-syntax-highlighting', defer:2

2.2 替换你的cd命令 z.lua

从skywind3000大佬那里安利的工具

1
2
3
4
5
git clone https://github.com/skywind3000/z.lua /usr/softwares/z.lua
sudo apt install -y lua5.3
sudo ln -s /usr/bin/lua5.3 /usr/bin/lua
#接着在.zshrc添加
eval "$(lua5.3 /usr/softwares/z.lua/z.lua --init zsh)"

Note:笔者后来用了zsh-autosuggestions插件后,发现用z的机会也少了。不过各有千秋,目录跳转比刀耕火种的cd好多了,哈哈!

2.3 miniconda

安装脚本来自我的dotfiles,我将miniconda直接安装在了/usr文件夹,其实安装在/usr/softwares下更好,不过无伤大雅

1
2
3
conda_linux=~/.Qdotfiles/downloads/miniconda3_linux.sh
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O $conda_linux
sudo bash $conda_linux -p /usr/miniconda3 -b -u
- conda安装后,将各个常见的pytorch版本创建了一遍
1
2
3
4
for i in {12..17}
do
conda create -n torch$i python=3.7 -y
done
再从官网下载对应的包。 - 使用Tips 为每一个项目单独创一个环境,不同环境不要混用。比如自己项目需要torch12版本,以及其他依赖包,可以首先克隆torch12这个环境:
1
conda create -n 项目名称 --clone torch12
激活环境并在这个环境下进行构建:
1
2
3
conda activate  项目名称
conda install ...
pip install ...
## 2.4 nvim 我写的安装脚本,包括了 - 下载 - 安装 - 插件配置

等操作。更多常用软件安装,会总结在自己的dotfiles里。

2.5 CUDA驱动安装

查看GPU版本

1
2
3
➜  ~ lspci | grep -i nvidia
3b:00.0 VGA compatible controller: NVIDIA Corporation GP100GL [Quadro GP100] (rev a1)
3b:00.1 Audio device: NVIDIA Corporation Device 0fb1 (rev a1)
### 2.5.1 成功安装方式

  • 第一步:安装必备软件,官方推荐的库

    1
    sudo apt-get install -y g++ freeglut3-dev build-essential libx11-dev libxmu-dev libxi-dev libglu1-mesa libglu1-mesa-dev

  • 第二步:禁用nouveau,这是官方文档的步骤,并且还要重启。连在一起我写了如下脚本,可以直接运行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 1
    cat << EOF >>/etc/modprobe.d/blacklist-nouveau.conf
    blacklist nouveau
    options nouveau modeset=0
    EOF
    # 2
    update-initramfs -u
    # 3
    reboot

  • 第三步:在BIOS里禁用secure boot

  • 第四步【2080Ti版本】:在官网下载地址下载cuda驱动

    image-20200924184743807

在上面选好对应的选项,bash命令给你的安装方式了。文件有3G多,开了命令行代理还下了一个小时

1
2
wget https://developer.download.nvidia.com/compute/cuda/11.1.0/local_installers/cuda_11.1.0_455.23.05_linux.run
sudo sh cuda_11.1.0_455.23.05_linux.run

安装就是一路accept之后就装好了

image-20200924213610919

太长不看版:

1
2
3
#/etc/profile添加
export PATH=/usr/local/cuda-11.1/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-11.1/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}

分析下提示:

  1. 官方推荐的库还有没装,需要装参考第一步。安装cuda驱动后他们在当前目录放了一些cuda代码样例,这些例子应该是依赖这些库
  2. PATH需要包含/usr/local/cuda-11.1/bin这个路径,这个好办,在/etc/profile里面写入export PATH=/usr/local/cuda-11.1/bin${PATH:+:${PATH}},就明明白白安排了环境变量
  3. LD_LIBRARY_PATH这个变量要包含/usr/local/cuda-11.1/lib64路径,解决的方式上面也给了,那我们也是一样写export语句:export LD_LIBRARY_PATH=/usr/local/cuda-11.1/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
  4. 配置好环境变量后,你可以打印出来看看对不对:
1
2
3
4
echo $LD_LIBRARY_PATH
#/usr/local/cuda-11.1/lib64
echo $PATH
#/usr/local/cuda-11.1/bin:/usr/miniconda3/bin:/usr/miniconda3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
  1. 还可以用nvidia-smi检查一下GPU状态,如果正常运行,那就基本没问题了。

2.5.2 失败安装方式

留个纪念吧,致敬我在上面浪费掉的时间

失败原因:没有下载对正确的驱动,参考上面的链接进行下载

流程复现:直接进入英伟达官网,就开始选择驱动进行安装。看了官方安装步骤文档,我采用runfile安装的方式,盲目地下载了官网首页给的安装包 ,这个文件有2G多,下载到了/usr/softwares/downloads/下,照着官方文档的步骤安装,没有成功。 69996576.png 报错: 70067327.png 打开这个日志文件 70101642.png 注意到官网说GP100支持cuda10.2,我装的是cuda11.0 71404346.png 再去装10.2,仍以失败告终。

2.5.3 报错

错误1

每次意外断电都会遇到的情况,头大!

1
2
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. 
Make sure that the latest NVIDIA driver is installed and running.

解决方案

  • 第一步:首先看nvidia驱动具体版本号
1
2
ls /usr/src | grep nvidia
# 我的是nvidia-455.23.05
  • 第二步:用 nvcc -V 看了一下驱动还在,用下面的方法应该顺利解决问题
1
2
sudo apt install dkms
sudo dkms install -m nvidia -v 455.23.05

因为这个方法就已经解决问题了,所以更多的没探索下去了。

我写了一个脚本直接联动了查询和配置(可能有问题,仅供参考)

1
sudo dkms install -m nvidia -v `ls /usr/src | grep nvidia | sed 's|nvidia-||'`

错误2

1
Failed to initialize NVML: Driver/library version mismatch

解决方案

  1. 首先看显卡驱动版本
1
cat /proc/driver/nvidia/version

我的是450

1
2
NVRM version: NVIDIA UNIX x86_64 Kernel Module  450.102.04  Tue Dec 29 06:51:23 UTC 2020
GCC version: gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)

那么安装:

1
sudo apt install nvidia-driver-450

接下来又报错误1,那么按照错误1的解决方式做,就成功了。

错误3

3080Ti的错误

1
Unable to determine the device handle for GPU 0000:03:00.0: GPU is lost.  Reboot the system to recover this GPU

2.6 cudnn安装

在官网https://developer.nvidia.com/cudnn注册账号并下载,我直接使用Google账号登录。选择下载cuDNN Library for Linux

可以看到,对于不同的CUDA,历史有一堆cudnn

image-20200929024402667

我选了第一个的cuDNN Library for Linux (x86_64),直接wget就可以

1
2
3
4
5
6
# 1 下载
# 2 解压
tar xvzf 你的下载包
# 3. 复制
sudo cp cuda/include/* /usr/local/cuda-11.1/include
sudo cp cuda/lib64/* /usr/local/cuda-11.1/lib64

2.7 tmux 配置

tmux是一个优秀的终端复用软件,如果您经常使用终端,建议马上使用它!相信我你不会后悔。 - 首先安装 sudo apt install tmux -y - 安装好了就可以使用了,但为了更美(装)观(x)怎能止步于此!下载插件管理器 git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm - 在配置文件~/.tmux.conf里写上你需要的插件,笔者使用了onedark主题,目前觉得还不错。 笔者目前的配置文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Open in same directory
bind c new-window -c "#{pane_current_path}"
bind '"' split-window -c "#{pane_current_path}"
bind % split-window -h -c "#{pane_current_path}"

# List of plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'odedlaz/tmux-onedark-theme'

# Other examples:
# set -g @plugin 'github_username/plugin_name'
# set -g @plugin 'git@github.com:user/plugin'
# set -g @plugin 'git@bitbucket.com:user/plugin'

# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm'
- tmux source ~/.tmux.conf让配置生效 - 生效后,还不能立即看到效果,这是因为没下载插件,只需要打开tmux,然后<prefix> I就可以安装插件。<prefix>是tmux的前缀键,默认是Ctrl+B 其他命令:
1
2
<prefix> U 更新所有已安装插件
<prefix> Alt U 移除所有插件列表中不存在的插件

2.8 显卡驱动安装

1
2
3
4
5
6
7
# 1. https://www.nvidia.cn/Download/index.aspx?lang=cn 找到bin文件安装包
# 2. disable the graphical target, which is what keeps the display manager running:
systemctl isolate multi-user.target
# 3. unload the Nvidia drivers
modprobe -r nvidia-drm
# 4. 运行可执行文件,注意参数
./NVIDIA-Linux-x86_64-450.80.02.run --no-cc-version-check

三 docker服务部署

服务器配好了,配置一些服务供日常使用,下面是经常用的几个: ## 3.1 gitlab 参考韦大佬的文章,真的只要半分钟! ### 搭建 搭建一个gitlab其实非常简单,只需要半分钟,前提是用对合适的工具, 这个工具就是docker,参考搭建教程。作为管理员,搭建好之后直接docker-compose up -d就可以舒舒服服放在后台运行了。

使用

  1. 首先注册一个账号 47921521.png 接着登录就ok
  2. 免密使用 使用https和ssh连接都可以,笔者使用的是https方式,进行下面的配置可以免得每次push都要输用户名和密码。在mac和Linux的~/.git-credentials里写入账号密码
    1
    2
    # ~/.git-credentials
    https://你的名字:你的密码@你的ip地址:8443
    让配置生效,不然会发现还是要输密码。
    1
    git config --global credential.helper store
    3.屏蔽自签证书的验证,不然会报http错误git SSL certificate problem
1
git config --global http.sslVerify "false"

3.2 overleaf

参考知乎文章。 >Overleaf是开源的在线Latex编辑器软件,个人用户可以在Overleaf官网注册并免费使用Overleaf,Overleaf官网还具有Review等团队协作功能。但是Overleaf官网在国内的访问速度不佳,科学上网后速度才满足日常需求。因此,对于科研团队来说,在自己的服务器上部署Overleaf,从此为整个团队都省去了安装Latex各种包的繁琐,多么幸福的事。需要说明的事,目前开源的个人版本的Overleaf功能没有Overleaf官网齐全,也许还有些小bug,但是就目前的使用来说,足够日常使用了。

我对docker compose文件改了两个地方,一个是映射端口,另一个是挂载目录: 72125117.png

四 后话

建议每位学习计算机的小伙伴都学习一下linux,因为了解之后,对许多方向(比如做深度学习、后端开发等等)同学的工作非常方便。你可以不用纠结开发系统和娱乐系统之间的定夺,linux系统就用来做开发好了,两者兼得mac了解一下​?:smile:

五 参考与问题

应该把软件装在哪个地方?

参考了这篇文章,了解到一般情况下,我们知道的软件,可以联系管理员装在/usr/local或者 /opt/。我现在选用的方式是,把软件装在/usr/softwares,然后给这个文件夹赋给一个组,组员都能访问到。


再更

阮一峰写过一篇刨根问底的文章,讲解了linux里面目录结构的来历,有兴趣可以看看。总结下来是

  /:存放系统程序,也就是At&t开发的Unix程序。

  /usr:存放Unix系统商(比如IBM和HP)开发的程序。

  /usr/local:存放用户自己安装的程序。

  /opt:在某些系统,用于存放第三方厂商开发的程序,所以取名为option,意为"选装"。

欢迎关注我的其它发布渠道