2017年4月17日 星期一

在 proxmox 裡的 ubuntu lxc 安裝 nvidia GPU 驅動程式及 cuda [失敗, 不推薦這個型號]

[4/29 先講結論: 不要買這張卡! 可以的話, 最好不要買 nvidia 的產品。]

最近在玩機器學習 ML/DL。 沒有 GPU 的話, 很多程式跑起來都很慢。 盡管 Linux Torvolds 曾經說過 nvidia 是我們交手過最可惡的公司, 但是因為 tensorflow 不支援 OpenCL, 所以我還是很不爭氣地買了一張 NVIDIA GeForce GTX750Ti 晶片的電競入門顯示卡。 (不想買太新款是因為 900 之後的系列對自由軟體更加極不友善。) [4/29 最後的結果顯示不爭氣一半的下場就是白花錢了。]

未來我要拿來跑 docker 的環境是 裝在 zfs 上面的 proxmox 裡面的 lxc。 因為 container 跟 host 共用 kernel, 而驅動程式是核心模組, 所以要裝在 proxmox 4.2 的 host 上。 至於較高階的 cuda 函式庫就裝在 ubuntu 16.04 的 lxc 裡面。

一、 proxmox host

Proxmox 基本上是 debian, 所以大致按照 debian wiki 的步驟。 摘要如下:

  1. 你的顯卡可以用的最新版本是哪一版? 例如我的 GTX 750 Ti 看來可以用 340.96。 點進 「supported devices」、 搜尋確認一下。
  2. 照著適當版本的那一節做, 修改 /etc/apt/sources.list 並且安裝 linux-headers-* 跟 nvidia-driver。
  3. 如果安裝 linux-headers-* 失敗, 可能是 這個原因。 那就要照著 這一節 把 /etc/apt/sources.list 裡面的 pve-enterprise 改成 pve-no-subscription 、 再 update 、 再重裝一次。

又, 如果遇到 GPG error ... NO_PUBKEY 的錯誤, 可以照著 這篇 把三把公鑰加入信任清單。 用 apt-key list 確認一下三個新的名單的 e-mail 都是以 debian.org 結尾, 確實是可信任的名單。

二、 lxc guest

接下來, 其他套件不裝在 proxmox host 上, 而是裝在 lxc guest 裡。

  1. 再次照著 debian 的文件修改 /etc/apt/sources.list 。 Ubuntu 有自己的 ppa (請在該頁搜尋 ppa); 但是 nvidia 的程式很龜毛, 很多地方要求版本必須一模一樣 (= 而非一般自由軟體常見的 >=) 因為 host 的 kernel 模組來自 debian, 所以還是用 debian 的比較簡單。
  2. 結果安裝 nvidia-cuda-toolkit 時, 果然出現版本衝突的問題: nvidia-profiler、 nvidia-cuda-dev、 nvidia-visual-profiler 三個套件被指定要安裝 7.5.18-0ubuntu1 版; 可是底層的驅動程式卻是 debian 的版本 :-(
  3. cd /var/lib/apt/lists ; grep -l nvidia-profiler * 可以看出 archive.ubuntu.com_ubuntu_dists_xenial_multiverse_binary-amd64_Packages 跟 httpredir.debian.org_debian_dists_jessie_non-free_binary-amd64_Packages 兩個來源裡面都有 nvidia-profiler。 所以再度進入 /etc/apt/sources.list 把三句 http://archive.ubuntu.com/ubuntu 後面的 multiverse 那一小段都刪掉。 再 update 、 再重裝一次, 就成功了! [我在這裡卡好久, 差點想要放棄、退貨~~]

dpkg -l | grep cuda 查看, 得知我的版本是 6.0.37-5。 這個版本沒有把測試用的 samples 包進去。 因為授權的關係, 搜不到有人直接把範例檔放上網。 於是從 官網 下載回 cuda-repo-ubuntu1604-8-0-local-ga2_8.0.61-1_amd64.deb、 用 dpkg -c 查看內容、 用 dpkg -x 抓出其中的 cuda-samples-8-0_8.0.61-1_amd64.deb、 直接安裝失敗 (版本問題), 於是再用 dpkg -x 直接解開, 進到最簡單的 usr/local/cuda-8.0/samples/0_Simple/vectorAddDrv/ 裡面測試編譯, 即使改了 nvcc 的路徑還是失敗 (版本問題)。

其實, 在 lxc 裡面安裝 cuda 根本是多餘的, 只是想確認可以跟 host 的版本相容; 實際上使用時, 這些 (沒有直接碰觸硬體的) 函式庫應該是安裝在 docker 裡面。

三、 docker

[4/29 補充本節]

網路上已經有很多大大包好現成的機器學習用 docker, 有些還提供 Dockerfile 原始碼。 忘記是哪一個, 總之先前我曾下載一個 Dockerfile.gpu, 照著 build, 竟然成功! 好感動。 而且仔細一看, 它是從 cuda 8.0 出發, 跟底下 proxmox 的驅動程式版本不同, 居然可以編譯成功。 後來真的要啟動時, 才發現執行時還是會檢查版本。 改用 caffe docker 重新手動 build 一次, 記錄如下:

  1. 網頁上已經說了, 如果想用打包好的現成 image, 驅動程式必須支援 cuda 8.0。 我的只支援 6.0, 所以就只好從 gpu 版的 Dockerfile 開始, 自己 build 吧。
  2. 必須把第一句 FROM nvidia/cuda:8.0-cudnn6-devel-ubuntu16.04 改成適當的版本。 從 這個問答 得知可以這樣取得 tags 清單: wget -q https://registry.hub.docker.com/v1/repositories/nvidia/cuda/tags -O cuda-tags.json 然後用 json 轉檔萬用瑞士刀 jq 排版: jq . cuda-tags.json。 看來我的卡太古老了, 唯一有希望的版本是 6.5 囉。 注意: 6.5-runtime 欠缺 nvcc 編譯器等等開發工具; 要選 6.5-devel 才對。
  3. 把第一句改成 FROM nvidia/cuda:6.5-devel, 開始 build 並且記錄錯誤訊息: (date ; docker build -t caffe:gpu . ; date) &> build.log 看到這個錯誤訊息:
    Compiling src/core.cu > /opt/caffe/nccl/build/obj/core.o
    nvcc fatal   : Unsupported gpu architecture 'compute_60'
    
    又來了, 又是版本不相容的問題: 底層驅動是 6.0, 上層 cuda-devel 是 6.5。
  4. 學到一招: docker build 失敗時, 如何檢視半成品? 不過這次的場合, 即使進入半成品檢查, 也沒什麼結果。

現在越來越懂了: 目前的主流版本是 8.0。 nvidia 的態度就是: 你要用舊版的不想買新卡, 那就讓我們好好地整整你, 然後也許讓你成功, 或者也可能讓你失敗, 但是我們絕不會一開始就跟你講清楚說明白哪張卡可以做到哪個地步。

再換一條路: 又從 安裝 caffe 頁面發現 kaixhin/cuda-caffe 有幫舊版驅動程式建好 dockers。 照樣用 wget -q https://registry.hub.docker.com/v1/repositories/kaixhin/cuda-caffe/tags -O kcc.json 找出適用的 tag ("6.5"), 直接啟動: nvidia-docker run -it kaixhin/cuda-caffe:6.5 發現 nvidia-docker 的 daemon 根本沒有成功啟動。 從 ArchWiki 學到很讚的一招: 當 journalctl 的錯誤訊息不清不楚時, 可以先找到出問題的 Process, 再用 journalctl _PID=... 取得更多資訊。 再根據錯誤訊息 "nvml ... permissions" 搜尋到 GPU isolation, 改用 docker run --device=/dev/nvidiactl --device=/dev/nvidia-uvm --device=/dev/nvidia0 啟動, 終於成功進入 docker! 再照著 這篇 在 shell 底下下指令, 或是照著 這篇 在 python 裡面 caffe.set_device(0) 結果都是一樣的錯誤: CUDA driver version is insufficient for CUDA runtime version 。

我不玩了。

四、 結語

總之 nvidia 的環境一整個大不友善, 特別是龜毛的版本控管樹立起許多不必要的圍牆 (連最基本的向量加法也受到版本影響? 這根本是 API 設計不良啊!) 文件卻又不寫清楚哪個版本的驅動程式對應到哪個版本的 cuda。 到很後來才找到 這個問答 列出 cuda vs 驅動程式版本的對應關係 -- 這不是應該放在官網顯眼的地方嗎? 怎麼會是在 stackoverflow 上網友幫忙回答的呢? 更可惡的是, 我的 GTX750Ti 明明成功地安裝了 340.xx 驅動程式, 按照上面的問答, 應該支援 cuda 6.5 才對。 但實際上在 lxc 裡, cuda 卻只能裝到 6.0, 而且後來的各種 docker 版實驗也顯示不論如何, 底層的驅動程式也都不足以支援 cuda 6.5。 爬了那麼多文 (本文列出來的連結可能只有 「已爬未連」 文章的不到三分之一或不到十分之一), 卻找不到任何一份文件可以解釋這個版本不相容的問題。

從這個不愉快的經驗得到的最大正能量是: 學到很多 docker 技巧。

現在正在考慮租用 amazon 的服務。 雖然他們底下買的也是 nvidia 的顯卡, 但至少我的錢不是直接付給 nvidia, 感覺沒有那麼肚爛。 在此同時, 也祝 AMD 的 OpenCL 跟 HSA 等等 開放圖形驅動標準 突飛猛進、 趕快進步到可以跟 cuda 競爭的地步。

3 則留言:

  1. 補上一大節 [三、docker] 先講結論: 不要買這張卡! 可以的話, 最好不要買 nvidia 的產品。

    回覆刪除
  2. https://devtalk.nvidia.com/default/topic/617414/-solved-cuda-driver-version-is-insufficient-for-cuda-runtime-version-fedora-18-rpmfusion-driver/

    回覆刪除
  3. 謝謝分享! 可是還是不行耶。 用 find 找了一下, 我的 libcuda 放在 /usr/lib/x86_64-linux-gnu 底下。 連結本來就有了。 把 /usr/lib/x86_64-linux-gnu 加進 /etc/ld.so.conf.d/nvidia-lib64.conf 再 ldconfig 也沒用。 其實從原來的症狀大概也猜得出來: 都已經進入 docker 進入 python 載入函式庫了, 顯然有找到函式庫, 只是版本不對而已。

    回覆刪除