我讀 «輝達之道»

這個年假原本打算讀兩本書、 校稿兩篇專利 (?)、 準備一些美金看美股有沒有便宜可以撿、最後再看一下同事介紹的 DeepSeek 在幹啥?

不料就在年假的第一個周末, DeepSeek AI 突然直接攻佔各種新聞版面, 變得幾乎無人不知無人不曉. 週一晚上的美股 – 尤其是輝達價格大跳水! 這下我的好幾件事都連結在一起了. 因為我想讀的其中一本書就是 “輝達之道".

這本書原名 “The Nvidia Way", 作者是金泰 (Tae Kim), 譯者是洪世民和鍾玉玨. 本書非常值得推薦, 雖然翻譯有幾處比較不通順 – 不知道副詞子句是在講主詞還是受詞, 但整體可讀性沒問題. 每個人看這本書的觀點可能有些不同, 它可以是勵志的新創公司成功記、可以是黃仁勳發跡故事的側寫、或是一本 GPU 簡史. 對我來說, 它就是 Q&A. 解惑了我好幾個問題.

Q1. Nvidia 為何沒有變成一代拳王? MTK 蔡明介想過這個問題, 黃仁勳也想過. 兩個人遇到的狀況不同, 解法也不一樣. 黃仁勳認為會有一代拳王的是因為大家技術差不多, 但開發一顆 IC 要一年半的時間. 所以當你暫時領先, 對手的新產品就會比你厲害! 假設產品規格並沒有太大的改變, 只要規格疊得高, 那一代新人換舊人就是理所當然的.

黃仁勳解決這個問題的方法是成立不同 project, 開發週期彼此交錯, 共用資源和資訊, 隨時調整規格, 並且準時交貨. 從外界來看, Nvidia 推出產品的時間自然而然就縮短了, 對手很難在兩代產品交接的空檔中找到切入點! 當然這是在 graphic card 大混戰的時代才適用的策略. 如果大勢已定呢? MTK 理所當然去找下一個明星產品, 而老黃則是直接把現在的產品調整到直指未來.

他怎麼做到的呢? 當然就不是兩三句話那麼簡單. 總之我認為他好好地接受了不平凡的建議, 又壓榨出了驚人的成果. 像是光追, tensor, CUDA, NPU, GPU (替代 graphic card) 這些都是底下的人想出來, 再透過老黃鋼鐵的意志實現它. 底下會提到 Nvidia 發明了 GPU 這個名詞來和 graphic card 區隔.

Q2. 為何要叫做 GPU? Nvidia 的產品經理認為他們 graphic card 可以同時處理 4 個 pixel, 能做圖形的旋轉平移, 這些都取代了原本的 CPU 程式, 所以應該叫做 GPU. 於是老黃就在 1988 年 8 月宣稱他們的 GeForce 256 是全世界第一顆 GPU, 即使那顆 GPU 還是要下 register 才能叫它做事, 還不能真的寫高階程式語言.

Q3. 為何雲端運算需要 GPU? 這要先從高速運算說起. Nivia 的團隊在設計 Geforce 3 時, 為了解決 render 上較複雜的計算, 開發者藏了一些可編程的運算單元在圖形處理之中. 當然這代表 GPU 就有了一些浮點矩陣運算的能力. 即便只能用 OpenGL 或是 Nvidia 的 Cg (C for graphic) 來 coding, 至少硬體非常強大.

高速運算原本是 CPU 的市場, 強大的 CPU array 就是超級電腦. 當學者或研究單位擁有超級電腦, 就可以快速地完成複雜的計算. 但沒有被分配到這類珍貴資源的學者, 就算有很好的想法也無法領先發表論文, 輸家就永遠是輸家. 久而久之就形成了學術壟斷.

2002 年, 有位馬克哈里斯 (Mark Harris) 研究員發現許多科學家開始用 GPU 做 “非圖形" 的研究. 狀況就跟現在很多公司、大學都用 RTX4090 而不是 DGX B200 做 AI 實驗是一樣的道理 [1]. 所以他就架了一個 GPGPU.org (generla purpose GPU) 的網站, 幫助大家活用 GPU 來代替買不起的超級電腦. 接著 Nvidia 發現了這個網站, 招募哈里斯加入 NV50 (G80) 團隊.

G80 的 GPGPU 能力比過去更強大, 不再使用 Cg, 而是推出了 CUDA (Compute Unified Device Architecture). CUDA 呼叫 GPU 的 PTX 指令集, 讓大家不需要特別去學這個架構的組合語言, 而是有專屬的 compiler 可用. 黃仁勳說: “CUDA 讓我們的成本大為增加". 但是他們達到了目的: (1) 讓所有的人都可以用 CUDA, (2) 讓 CUDA 適用於所有領域. 於是有愈來愈多人發掘出 GPU 的用途, 從模擬新藥、挖礦 (虛擬貨幣) 到訓練 AI.

當然 Nvidia 的故事也不是都這麼正面. 他們發現科學家工程師只買電腦版 500 USD 的 GPU, 而不買他們更貴的伺服器版 2,000 USD 的 Tesla (p. 378). 於是 Nvidia 自己宣稱他們 PC 版的 floating 不太準, 伺服器版才準. 在被沃克教授證實並沒有不準後, Nvidia 改為在不影響圖形輸出的程度下把它改成不準. 沃克和它的團隊又再把它 patch 回來! 並且在他在藥廠的新工作中,買了成千上萬的電腦級 GPU 來建立 data center.

Q4. 為何大家都用 Nvidia 的 GPU 訓練 AI? 別家的卻不行? 這個問題一半的答案就是 CUDA, 它不是一張繪圖卡或是遊戲卡, 而是算力卡. 若只是要畫出滿屏的圖形, Intel 自己就可以做到了. Nvidia 預先看到這一點, 因此用 GPU 和圖形輸出做出區隔. 並且賣得超級貴. 別人的產品都是 ASP (平均銷售單價) 愈來愈低, Nvidia 主打愈賣愈高, “買愈多省愈多"!

回歸 AI 這個主題. 過去的 Machine Learning 都是先找特徵, 然後統計特徵值, 根據統計原理做分類. 直到 AlexNet 出現, 才有不找特徵, 讓系統根據 label 過的資料, 自己找出規則的 Deep Learning. 當然這就不得不歸功於當初 labeling 這些 database 的先驅李飛飛. 發明 AlexNet 的多倫多大學團隊 (當然包括其中一個學生叫做 Alex) 就是使用輝達的 GeForce 500 做訓練, 他們在第三屆 ImageNet 大賽, 成果遙遙領先其他舊演算法 10% 以上 (p.425).

從此以後, 大家都知道要用 GPU 做 Deep Learning (DL). Nvidia 也看到這個 AI 商機特別大. 因此再推出 CuDNN (CUDA Deep Neural Network) 強化對 AI 的支持度. 對於一般高速運算的市場, 硬體需要支援 FP32 或 FP64 (浮點 bit 數). 但是對於 Neural Network 的訓練來說, FP16 就夠用了. 因此 Nvidia 的 GPU 從 2016 年開始都支援 FP16. 而且還加入了 Tensor Core. 書上提到老黃臨時在 tape out 前幾個月說要加 Tensor, 大家怎麼趕工達標. 這個不是本文的重點就先略過.

Tensor Core 有什麼好處呢? 因為 DL model 裡面都是矩陣運算, 而 CUDA Core 只是浮點乘加器, 需要 CUDA compiler 來優化計算流程. 假如矩陣運算有特別的硬體, 那麼採用 CuDNN 來編 code 就可以更加地優化. P.433 說到,有 Tensor 快 3 倍. 這就解釋了為何大家都愛用 Nvidia 的 GPU 來開發 AI 軟體, 而不用市售的 NPU. 市售的 NPU 對於常用運算子的軟硬體優化差了 Nvidia 一大截. 所以做某些推論應用 (inference) 還可以, 整體而言是事倍倍功半半.

Q5. Nvidia 怎麼搭上 DPU? Mellanox 這家公司把 InfiniBand 這個標準做成高速網卡, 在數據中心可以 offload CPU 對網路封包處理的算力消耗. 雖然生意不錯, 但這家公司太小, 負擔不起高昂的研發費用, 最後只好賣公司. Nvidia, Intel, Xilinx 三家競標之下, Nvidia 看到它在數據中心的綜效, 因此花了每股 125 美元 (共 69 億美金) 標下股價 76.9 的 Mellanox.

接下來, 老黃又出來說我們發明了第一個 DPU. 當然, Nvidia 敢這樣講, 就是他們又投資了更多加速的軟硬體, 跟一般的 SmartNIC 做出區隔. 想要再重演一次“GPU 不等於繪圖卡”的劇本。

這本書的內容當然不只於此。或許可以用創業和經營事業的觀點再重新詮釋一次。像是保持扁平團隊,保証訊息一致,還有老黃偏執地好學等等。這部分就等我看完張忠謀自傳再來匯整好了。畢竟兩大管理者可以互相輝映。

[REF]

  1. https://www.cool3c.com/article/218920

Train ESRGAN 小整理

我想挑戰一面挖礦, 一面跑 AI training, 一面開艾爾登法環,… 不過看起來有點困難, 只好不跑老環了, 反正一直 “You Died". 好, 在此把 training 的步驟整理如下.

  1. 如先前所說, 用 Anaconda3 做出一個環境, 然後開 terminal.
  2. 到網路上下載訓練用的圖片.  根據原作者所述, 他用的 database 是 DF2K.DF2K is a merged training dataset consisting of 800 DIV2K  training images and 2650 Flickr2K training images.
  3. 雖然不知道有什麼特殊之處, 總之這兩個 databse 的名稱長度不一樣, 我就直接把它們塞到同一個目錄.

新目錄的位置在主目錄下自己建一個 datasets. 再下面一層開個 DF2K 子目錄, 一層 DF2K_HR 子子目錄. 2K 照片全部放這裡. 然後在與 DF2K_HR 同層開個 DF2K_multiscale 目錄. 這樣下一階段就可以開始訓練了.

train-data-150x150

4.  訓練步驟參考 [1], 首先把每張圖做縮圖, 分成 0.75, 0.5, 0.33, 0.25 四種大小. 看起來有 rounding 到特定的數字, 而且有 floor = 400.

python scripts/generate_multiscale_DF2K.py --input datasets/DF2K/DF2K_HR --output datasets/DF2K/DF2K_multiscale

例如 000001.png 就生成 000001T0.png、000001T1.png、000001T2.png 、000001T2.png 四張不同尺寸的小圖.

2048×1356 1530×1017 1020×678 680×452 601×400

5. 然後把圖形全部切齊成同樣大小的方塊. 注意 DF2K_multiscale_sub 這個目錄要留給程式建, 自己先建好會報錯.

python scripts/extract_subimages.py --input datasets/DF2K/DF2K_multiscale --output datasets/DF2K/DF2K_multiscale_sub --crop_size 400 --step 200

這裡的第一個參數顯然就是要把圖形裁切成 400×400 的小圖. 第二個參數看程式註解: “step (int): Step for overlapped sliding window."  這個意思是每個小圖有 200 pixel 和另外一張裁切圖有重疊. However, 我必須說此處就丟掉一些重要的資訊, 我想想怎模申請專利好了~~~

[原始的小圖 xxxT2: 680×452]

000001-300x199

T0 切成  35 個 400×400, T1 切成 15 個, T2 切成 6 個, T3 切成 2 個. T0 的前四張 400×400 長這樣. 也就是由左至右掃過原圖的上方.

000001T0_s001-150x150000001T0_s002-150x150000001T0_s003-150x150000001T0_s004-150x150

6. 在前一個步驟, 很多 400×400 小塊的原稿在哪裡? 這個資訊 (metadata) 需要保留起來, 因此下面這個步驟的重點就是回溯紀錄 metadata.

 python scripts/generate_meta_info.py --input datasets/DF2K/DF2K_HR, datasets/DF2K/DF2K_multiscale --root datasets/DF2K, datasets/DF2K --meta_info datasets/DF2K/meta_info/meta_info_DF2Kmultiscale.txt

7. 以上算是滿快就跑完了, 跟我打字的速度差不多. 接下來是重點, 作者的說明在不同版本有些許差異, 總之找到前面檔案總管節圖的那個目錄底下的 options, 裡面會有很多個 yml 檔. 以放大四倍來說, 需要改這兩個檔案, 確定目錄都對. 第一個訓練 generator, 第二個訓練 discrimator, 因此 pre-train 的檔案不同.

train_realesrnet_x4plus.yml

train_realesrgan_x4plus.yml

8. 接下來用 debug mode 跑一次,

python realesrgan/train.py -opt options/train_realesrnet_x4plus.yml --debug

馬上發現 Anaconda 的環境沒有安裝 cuda “Torch not compiled with CUDA enabled", 即使補安裝 cudatool, 也只是把 torch 版本由 1.10.2+CPU 變成 1.10.2, cuda 還是 unavailable.

(RealESRgan) C:\Users\ufoca\Real-ESRGAN>python
Python 3.8.12 (default, Oct 12 2021, 03:01:40) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import torch
>>> print (torch.__version__)
1.10.2
>>> print (torch.cuda.is_available())
False
>>>

看起來要先下載正確版本. 參考 [2],[3],[4]. 網站 [4] 是 pytorch 官網, 似乎只要把自己環境設定對, 就可以用 UI 生成正確的安裝指令.

conda install pytorch==1.10.2 torchvision cudatoolkit=11.3 -c pytorch

不過這招其實沒用, [5] 說的才是對的. 要用 pip install, anaconda 本身的 server 只有 cpu 的 pytorch 可以選.

pip install torch==1.10.0+cu113 torchvision==0.11.1+cu113 torchaudio===0.10.0+cu113 -f https://download.pytorch.org/whl/cu113/torch_stable.html

另外, 我本來 pytorch 是 1.10.2, torchvision 是 0.11.3, 但上面那行貼了就會動. 安裝完跑出一些紅字說沒有檢查所有版本的相容性, 所以我又重新安裝成我的版號, 不過我不知道我的 torchaudio 應該要搭哪一版? 反而安裝不成功.

於是我還是用網路版本, 並且重跑一次

pip install -r requirements.txt

讓作者的檢查系統幫我微調一下版本. 總之, AI 的技術進步很快, 網路文章上的版號參考就好. 到時候要隨機應變.

9. 接者就不用跑 debug 版了. 改跑這條.

python realesrgan/train.py -opt options/train_realesrnet_x4plus.yml --auto_resume

我估計應該會做很久很久. 記錄一下起跑時間.

run

UI 顯示要跑 5 天半.

2022-04-10 21:48:02,327 INFO: [train..][epoch: 5, iter: 6,500, lr:(2.000e-04,)] [eta: 5 days, 10:47:47, time (data): 0.476 (0.002)] l_pix: 6.8241e-02

10. 然後是訓練 discriminator

python realesrgan/train.py -opt options/train_realesrgan_x4plus.yml --auto_resume

證明環境沒問題之後, 就可以自己動手腳去改 code 了.

[Note]

1. https://github.com/xinntao/Real-ESRGAN/blob/master/Training.md

2. https://towardsdatascience.com/setting-up-tensorflow-gpu-with-cuda-and-anaconda-onwindows-2ee9c39b5c44

3. https://varhowto.com/install-pytorch-cuda-10-0/

4. https://pytorch.org/

5. https://ithelp.ithome.com.tw/articles/10282119

在 Windows 上跑 Facenet 的小筆記

最近想在 Notebook 上建一個 AI 模擬的環境, 其中遇到一些關卡值得記錄下來.

在 Notebook 上建個虛擬機來跑 AI…. 畢竟 Linux 的環境比 Windows 直覺, 所以先做了這件事. Linux 軟體安裝起來相對容易, 重點在權限開對, 路徑設定可以憑直覺.

這樣很快就可以用 CPU 跑 facenet, But, 我是想要用 GPU 來跑啊!? Google 了一下發現虛擬機的 driver 不是 cuda 相容的, 必須要裝雙系統, 有原生的 Ubuntu 才可以跑. 因此又被打回 Windows 10 環境.

在 Windows 10 上面, 當然很直覺要先裝個 Python. 但這不是最佳的選擇. 應該先裝 GPU driver, 然後裝 Anaconda [1]. 原因是 Anaconda 下可以裝很多套不同版本的虛擬 Python 環境,  即使 model 只支持特定 Python 版本, 也不需要重新安裝 Python. 畢竟 Python 2.x 和 Python 3.x 就不相容了, 換來換去很麻煩.

若先裝 Python, 再裝 Anaconda, 後者會問要不要把 Anaconda 設為 Python 的預設程式? 如果選不要, 我發現很多怪現象會發生. 例如 Anaconda Navigator 搞失蹤之類的. 即使把既有的 Python 解除安裝, 在沒有重新開機之前, 純 Python 還是會在背景干擾 Anaconda Python. 所以乾脆反過來只安裝 Anaconda, 把它設為預設程式.

Step 1: 下載並安裝 Anaconda 3. 版本 4 和 5 好像是要錢的企業版.

然後在 Anaconda 底下的 envs 目錄下可以看到多個目錄, 每一個代表一種虛擬的環境. 當然這個要按照 Anaconda 的官網說明去創建, 如果不建立這底下就是空蕩蕩的. 環境做好之後, 會在 Windows 的程式集裡面看到成對的 prompt, Spyder…等等. prompt 就是命令列, Spyder 有 GUI, 而 reset 顧名思義就是把這個虛擬環境清掉重來, 在裝錯軟體的時候很好用.

anaconda

Step 2. 建立 Anaconda 下的虛擬環境, -n 的後面跟著名字, 例如我用 tensorflow-gpu 就可以來來區隔這個環境是跑 GPU 版本的. 但這只是名字而已, 真正的安裝在後面步驟. 但我後來後悔用這麼長的名字, prompt 變得很長. 此處指定了 python 的版本.

c:> conda create -n tensorflow pip python=3.6

Step 3. 啟用這個環境.

C:> activate tensorflow
 (tensorflow)C:>  # Your prompt should change

Step 4. 安裝跑 GPU 版本的 tensorflow. 這邊的 tensorflow-gpu 就是關鍵字不能改了.

(tensorflow)C:> pip install --ignore-installed --upgrade tensorflow-gpu

以上 Step 1~4 參考 Anaconda 官網 [1], 還有教人如何驗證安裝正確與否.

此外, tensorflow-gpu 往下需要 Cuda 和 Dnn 的函式庫. 參考這篇 [2] 即可. 其中, Cuda 要用第九版, CuDnn 應該用 V7 或 V7.1. 至於 GTX 顯卡的 driver 是本來就有的, 如果您是用 AMD 系列的顯卡, 這個我就沒研究.

這裡看起來很簡單, 但是陷阱也很多.  如果裝錯的話, 後續跑 tensorflow-gpu 就會報錯, 說找不到 cudart.lib, cudablas.lib….等等. 原因在於大家可能在安裝 GTX 顯卡的時候, 就在 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0\lib\x64 底下安裝了 cuda 相關的函式庫, 所以優先被執行到.

若安裝正確的話, 應該在指定的目錄 (解開 cudnn-9.0-windows10-x64-v7.zip 後手動放的那個目錄), 看到 cudnn64_7.dll. 然後把這個目錄加入 path. 網路上有很多人求救, 他們可能是把 32 bit / 64 bit 搞錯, 或已經安裝了 cudnn-9.1 但 tensorflow 只支援到 9.0 之類的, 總之痛下殺手把電腦的版本降級配合 tensorflow 就行了.  

搞定 dnn 之後, 就可以按照滿山遍野的網路教學跑 MTCNN + Facenet [3][4]. 但還是要請大家再次釐清一個觀念是: 既然我已經用 Anaconda 做虛擬環境, 一切都要在虛擬環境下執行. 也就是 envs/tensorflow-gpu (舉例)/ 而不是 Anaconda 目錄下 [3].  然後呢…facenet 是一個 module, 必須安裝到 lib/site-packages/ 底下才能執行, 光是下載 facenet copy 進去是沒用的.

Python 中安裝 module 的方法有很多種[5]. 我們只需要用到最簡單的 pip install facenet 即可. 其他的按照 [4] 應該就可以依序執行 MTCNN 和 Facenet. 這邊會踩到的雷是: Windows 系統的字型編碼會造成 facenet error, 這個外國人可能遇不到. 大約在 facenet.py 的 577 行左右, 要把原文改為我下面的這行代碼. 當然最前面要記得 import io.

# with open(rev_info_filename, “w") as text_file:
with io.open(rev_info_filename, “w", encoding="utf-8″) as text_file:

然後, 如果要 traning 自己的 database, 還有一行要改. 在 train_softmax.py 的 95 行左右, 無論換哪個 database, 它都固定去讀 data/pairs.txt, 所以我硬改一個寫死的目錄, 以便可以測 mydata.

# pairs = lfw.read_pairs(os.path.expanduser(args.lfw_pairs))
pairs = lfw.read_pairs(os.path.expanduser(‘mydata/pairs.txt’)) #Cash modified

在跑 MTCNN 的時候, 網路上很多文章都說要執行

python ~/tensorflow/facenet/src/align/align_dataset_mtcnn.py ~/tensorflow/lfw/raw ~/tensorflow/lfw/lfw_mtcnnpy_160 –image_size 160 –margin32 –random_order –gpu_memory_fraction 0.25

最後面 –gpu_memory_fraction 0.25 這個參數, 其實是 facenet 官網 [6] 跑四個 process 的關係, 跑 4 個當然每個人用 1/4 (0.25) 囉. 如果只跑一個 process, 加上這行唯一的好處是記憶體比較不會爆掉.

以上是跑 tensorflow 主線任務的紀錄. 支線上任務則是曾經試圖跑 mxnet + opencv 的版本, 結果第一路打通就沒繼續奮鬥了.

Step 1. 下載 opencv V.3.4.1

https://opencv.org/opencv-3-4-1.html 選 https://github.com/opencv/opencv/tree/3.4.1

Step 2. 解開 opencv 發現要 cmake.

Step 3. 下載 Visual Studio Community 2017

Step 4. 在 Visual studio 的 “工具" 裡面選 “擴充功能與更新", 選 cmake 下載, 安裝.

在 “工具" 選 “取得工具與功能", 選 “工具負載" 裡的 “其他工具組"  的 “使用 c++ 進行 Linux 開發", 選 “Web 與雲端" 的 “Python 開發".

Step 5. 下載 cmake, 在 https://cmake.org/download/  選 cmake-3.12.1-win64-x64.msi

要選產生 GUI 比較方便.

Step 6. 在 Cmake GUI 選 source code 位置, Build binary 位置, 選 Configure, 跑一段時間, 選 Generate 產生 build file. 選 Open Project 帶起 Visual Studio. [7]. 

cmake-1-768x661

Step 7. 在 Visual Studio build 這個 project. 參考 [8]  作一些修改. 但它的版本比較舊, 在我的平台上要把 VC10 改為 VC15, x86 改為 x64. opencv 改為 opencv 和 opencv2.

Step 8. 編成功後, 會在 c:\opencv\build\release\bin\debug (舉例) 看到一堆檔案, 這樣就成功了. 其中 opencv_interactive-calibrationd 跑起來會自動抓 NB 前鏡頭的畫面, 看了會很有感. 上面截圖時, 我把 binary 位置選在 c:\opencv\build, 但裡面本來就有檔案了, 再放自己編出的檔案會糊成一團, 故第二次我把 target 改到 c:\opencv\build\release.

Step 9. 安裝 mxnet

這個網頁可以自訂要下載哪一種 mxnet 的版本, 相當地人性化. 我選了

mxnet-1-768x372

https://mxnet.apache.org/install/index.html?platform=Windows&language=Python&processor=GPU

Step 10. 建議安裝 Anacoda — 請參考前面說的.

Step 11. 升級 mxnet 以支援 GPU

pip install mxnet-cu92

Step 12. 調整路徑

不調整路徑的話, 直接 load mxnet 版本的 facenet 會出現找不到 module 的錯誤. 事實上, 採用 Tensor flow 版本的人也是一直再狂問為何找不到 tensorflow module. 這些都是路徑的問題.

正常安裝完的 module 都會放在 pythonxxx 下面的 Lib/site-packages.

[Note]

  1. https://www.tensorflow.org/install/install_windows
  2. http://blog.nex3z.com/2017/04/18/%E5%9C%A8-windows-%E5%B9%B3%E5%8F%B0%E5%AE%89%E8%A3%85-nvidia-gpu-%E5%8A%A0%E9%80%9F%E7%9A%84-tensorflow/
  3. https://blog.csdn.net/xiangxianghehe/article/details/72809600
  4. https://blog.csdn.net/chzylucky/article/details/79680986
  5. https://packaging.python.org/tutorials/installing-packages/
  6. https://github.com/davidsandberg/facenet/wiki/Classifier-training-of-inception-resnet-v1
  7. http://gclxry.com/use-cmake-on-windows/
  8. http://monkeycoding.com/?p=516

Android 的人對 GPU 的說法

由於很多人都認為 Android 3.0 以前, Android 只用軟體畫圖, 所以 Android  的人跑出來澄清. 雖然這篇文章已經有點久了, 正好可以呼應我上一篇的貼文. 有興趣的人可以去看原版 Dianne Hackborn 的 Google+, . 我在這邊只摘要幾個重點.

1. Android 從 1.0 版就使用硬體加速視窗的的疊加 (all window compositing to the display has been done with hardware), 當然有的時候會用軟體. 下圖共包含四層視窗 (windows): Wall Paper, Launcher, Menu, Status Bar. 如果使用者操作 menu, 只有 menu 會用軟體重畫. 而疊加 (overlay) 的部分和整張畫面滑動的效果則是用硬體做.

2. Android 3.0 開始全部由硬體加速, 4.0 也是一樣. 只不過 Android 3.0 會檢查 App 在 manifest 裡面的 “android:handwareAccelerated="true" 這行 , 以決定是否用硬體加速. 而 Android 4.0 預設就是全部用硬體加速. 這麼一來, 原本只需要局部 UI 更新的狀況也不再交給比較有效率的軟體來執行了; 如此一來導致了一些副作用.  

3. 其他用硬體加速的缺點包括浪費記憶體, Imagination Tech 的繪圖驅動程式基本上要吃掉 8MB RAM. 剩餘的 RAM 變少了, 其它的背景程式就會變慢. 因此, status bar 其實不需要用 OpenGL (GPU) 來畫. Android 4.0 就把這部分單獨用軟體處理.

4. 蘋果的 IOS 怎麼做呢? 以瀏覽器為例, IOS 把網頁的畫面以 display list 的方式來畫, 因此沒有什麼更新區域的概念, 整個頁面都要重畫. 這麼做的優點是捲動或試放大縮小的時候不會看見破圖 (artifact) – 假如畫面是分成幾個區塊 (title) 來分別渲染的話, 就可以會有 artifact. 後者恰好就是 Android 的做法, 它比較能夠對抗複雜的頁面而不致於變慢, 因此光是用軟體就可以在 Nexus S2 畫出每秒 60 楨 (60 fps). 作者說他相信 IOS 也是用軟體畫的.

5. 為了解決 GPU 不夠力的問題, Android 還是有用 HW overlay, 而且把底圖 (backgound) 放的比螢幕還大. 這樣一來, 使用者捲動畫面的時候, 底圖就不需要重畫, 只是改個座標 (offset) 而已.

6. 當我們用 CPU 畫 UI 的時候, 多核心並沒有幫助. 因為幫一個 app 繪製 UI 的時候, 沒辦法做平行處理. 這就是為什麼 Android 要用 GPU 加速. 在去年年底 Galaxy S2 出來的時候, ARM 的 CPU (大約是 CA9 1GHz) 還不能畫到 720×1280 的 UI (60 fps), 因此更細緻的解析度都必須仰賴 GPU 來畫.

以下再補充更多的觀點:

7.  Android 官網的說法: GPU 擅長放大縮小, 旋轉,  平移, 但是不擅長畫直線和曲線. 所以要多用其長, 少用其短.

8. Qualcomm 說 Android 在他們的 Snapdragon 可以用 GPU 做 composition (也就是不用 HW overlay):

如果 graphic UI (user interface) 和 video 沒有同步, 那麼一般人腦海中的狀況是這樣:

 Qualcomm 說: video 可以當作圖形處理中的紋理 (texture), 所以簡單多了. 

HW Overlay 小檔案

看到這個題目在 wiki 只有英文和韓文, 忍不住想寫一個中文的精簡版. 不過寫著寫著就偏離主題, 變成了 Android 為何不全面支持 HW Overlay?

我們在 Windows 螢幕上看到的畫面, 基本上是由視窗疊加而成的, 前景擋住後景, 就成了我們看到的模樣. 在其他有視訊輸出的產品中, 同樣會有物件互相遮蔽的現象, 例如: 字幕浮現在電影上, 這樣就是兩個個物件. 如果再加上進度條 (progress bar), 就變成 3 個物件. 當繪圖系統需要依序畫出這三個物件時, 可以用軟體去檢查前後順序, 只把需要的部份畫出. 在 Android 系統中, Surface Flinger 就在做這件事 [註1].

既然有軟體的解法, 硬體解法會不會更快更有效率呢?是的, HW overlay 就是這個硬體的解法. 當每個物件都畫在自己的記憶體, 最後再依據每個物件的先後順序和透明度 (alpha blending) 一次疊加, 那麼每個物件就不用等來等去, 只要各畫各的就好. 如此一來, 雖然浪費了好幾塊記憶體, 控制卻變得很簡單. 特別是物件的更新速率差異很大時, 互等會導致大量浪費頻寬 – 例如電影 (30~60Hz) 與字幕 (大約 0.2~0.5 Hz).

Surface Flinger HW Overlay

上面這張圖有個小問題, 就是把 SurfaceFlinger 和 Overlay 畫成兩個獨立的模組. 實際上, 在 Android 中, HW Overlay 和 Surface Flinger 關係密切. HW Overlay 算是 SurfaceFlinger 的一個特例 [註 2]. 請參考下圖.

現在的 IC 幾乎都有 HW overlay 的能力, 應該沒甚麼好討論的, 可惜故事還沒有完. 大家如果把玩手上的 Android 手機或是平板, 可能會在設定裡面看到 “停用硬體重疊圖層" 這個選項. 既然 HW overlay 看起來比較好, 幹嘛把它停用呢? 每一個 OpenGL 的 process 都需要 2~8MB 的 RAM, 浪費記憶體就不用說了. GPU 還要挺高檔才行 [註 3].

每秒可以畫 1000 M pixel/second 的 200MHz SGX544, 在 1920×1080@60FPS (frame per second) 的輸出螢幕上, 能在每個 pixel render 8.0375 次. 若是換成了 SGX531就只能 render 4 次 [註 4]. 這  4 次如果用來畫一層背景, 一層電影. 一層進度條和 OSD (on screen display), 一層字幕, 就已經達到 GPU 的硬體極限. 此時只是做到 HW overlay 的水準而已, 但什麼 3D 動畫效果都畫不出來了.

以上都是說 Android 的壞話, 但 Google 卻可以藉著不支援 HW Overlay 來統一硬體的差異, copybit 不就在 Android 4.0 上被拔掉了嗎? 若是放任每一家廠商製作的 HW Overlay 都不相同, 當然就限制了 APP (跨平台的) 的互通性. 再者, GPU 只要聰明地用, 不要常常 redraw 沒用的畫面, 效率還是不會太差 [註 3]. 按照 Android 的官方說法, 全部的畫面都能進入 GPU 的話, 使用者將可以得到更多樂趣! 至於 GPU 的計算能力….當然必須夠, 這不是 Android 的責任範圍, 它只是個做軟體的. [註5]

Media effects for transforming images and video

A set of high-performance transformation filters let developers apply rich effects to any image passed as an OpenGL ES 2.0 texture. Developers can adjust color levels and brightness, change backgrounds, sharpen, crop, rotate, add lens distortion, and apply other effects. The transformations are processed by the GPU, so they are fast enough for processing image frames loaded from disk, camera, or video stream.

[註]

1.  Android Display (surfaceflinger and Overlay)

2. Android 显示系统

3. The truth about hardware acceleration on Android

4. PowerVR

5. Ice Cream Sandwich