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

ESRGAN 小註解

我參考 ESRGAN [11] 的論文導讀[1], 把其中相關的名詞做了個整理.

基本上兩大重點是 RRDB 和 GAN. 這個網路模型前者的修改是拔掉 BN, 後續又出了一篇 [9] 加上 noise 處理. 後者是修改 GAN 的對抗方式, [9] 又做了一些調整就略過. 以下把相關的名詞稍微整理如下.

首先看到 BN 這個詞, 文章中指的是第二種, 但是也順便把第一種 BN 列進來.

Bayesian Network (BN)

在 AI 中的主要應用是把人類的知識加入類神經網路 [2]. 如果單純使用 data training 叫做 machine learning. 既然它的名字裡面有 Bayesian, 顯然它考慮了條件機率, 所以在 training 的過程中, 我們要引入條件機率表 (conditional probability table – CPT).

條件式的因果關係就是 P(B|A) = C 的形式, 因此 BN 網路需要有一群輸入層的 feature 值, 然後以因果關係建立網路結構, 接著用條件機率把每個 node 到下一層 node 的機率以 CPT 表示, 最後會有一個輸出層, 告訴我們有幾種可能的 state, 以及各自有多少機率.

Batch Normalization (BN)

這是另外一個 BN, 在 RealSRGAN 裡面指的是這個, 事實上它也比較常用. 原理就是把輸入正規化為 N(0,1). 即 mean = 0, variance = 1, 這方法在 pattern recognition 和 classification 中也常用.  不過對 NN 來說, 它是指在 internal layer 去做 normalization, 不只是在輸入層.

RRDBNet Network [3]

在 RRDB 的實作中, 裡面有許多的 basic block 串接. Basic block  包括 Dense Block (DB) [4] 和 Residial Block (RB) [5]. Residual in Resisual Dense Block 就是把 dense block 以 residual network 的方式連起來 [3], 把這些 DB 都當作 RB 裡面的一層 layer 看待.

RRDBNet-768x255

RRDB 在 [1] 講得比較多. BTW, 關於噪音的改進. 可以參考 [9] 這篇的開頭.

Dense Block [4]

主要是每層都和其他幾層相連. 我把它當作 full connection 的分批簡化形式. Dense Block 的串接連成 Dense Network.

denseblock-768x653

Residual Block (RB) [5]

Residual Block 的概念, 像是 Dense block 的變形. 也就是可以跳過一層網路不連.

resisual-network-768x668

GAN

GAN 用國文來解釋很簡單, 就是正邪兩派各自去認親, 能夠訓練到邪不勝正, 那麼正的網路就大功告成了.

GAN-block-diagram

本圖取材自 [10].

從 coding 的角度來說, 當然還是要看到程式比較有感覺. 我覺得 [6] 的寫法滿好懂的. 若對於只熟悉C語言, 不熟 Pythone 的人需要克服這個底線障礙. 這邊的底線是 [7] 五種底線的第二種, ‘_’ 表示傳回的值有些是 don’t care. 例如:

validity, _, _ = discriminator(gen_imgs)

GAN 的基本流程當然是把生成對抗網路都各 train 一輪.  此時每輸入每一張圖, 都要生成一堆有噪音的圖 (靠隨機變數) – train generator. 然後把這一大把圖, 拿去 train discrimiator. 在生成 generator 的時候, 可以看到有製造噪音的 code 和最後的 back propogation.

# Train Generator
optimizer_G.zero_grad()
# Sample noise and labels as generator input
z = Variable(FloatTensor(np.random.normal(0, 1, (batch_size, opt.latent_dim))))
label_input = to_categorical(np.random.randint(0, opt.n_classes, batch_size), num_columns=opt.n_classes)
code_input = Variable(FloatTensor(np.random.uniform(1, 1, (batch_size, opt.code_dim))))
# Generate a batch of images
gen_imgs = generator(z, label_input, code_input)
# Loss measures generator’s ability to fool the discriminator
validity, _, _ = discriminator(gen_imgs)
g_loss = adversarial_loss(validity, valid)
g_loss.backward()
optimizer_G.step()

訓練 discrimator 網路時. 要得到 real image 在這個網路的 loss 評分 (終極目標是 loss = 0), 以及 fake image 的 loss 評分 (終極目標是 loss 很大). 兩組 loss 輸出, 取其平均值做 backward propogation 的分數. adversarial_loss 的實作細節看起來是在 Torch 的 loss.py 裡面 [8].

# Train Discriminator
optimizer_D.zero_grad()
# Loss for real images
real_pred, _, _ = discriminator(real_imgs)
d_real_loss = adversarial_loss(real_pred, valid)
# Loss for fake images
fake_pred, _, _ = discriminator(gen_imgs.detach())
d_fake_loss = adversarial_loss(fake_pred, fake)
# Total discriminator loss
d_loss = (d_real_loss + d_fake_loss) / 2
d_loss.backward()
optimizer_D.step()

以上是普通的 GAN 的處理方式. ESRGAN 的 GAN 不是比較 real image 和 fake image 誰的分數高, 因為我們早已經知道 real image 和 fake image 各自要扮演的角色. 花太多時間讓參數長對有點浪費時間.

ESRGAN 用的方式是讓真的和假的直接去 PK, 而不是對標準答案. 真的贏過假的參數要加分, 假的贏過真的的參數要扣分. 以下直接貼 [1] 的內容, 但用顏色標註重點.

我们可以看SRGAN的loss:

         l_d_real = self.cri_gan(real_d_pred, True, is_disc=True)
         l_d_fake = self.cri_gan(fake_d_pred, False, is_disc=True)

而ESRGAN的loss:

l_d_real = self.cri_gan( real_d_pred - torch.mean(fake_d_pred), True, is_disc=True)         
l_d_fake = self.cri_gan(fake_d_pred - torch.mean(real_d_pred), False, is_disc=True)

以上就是這篇論文會用到的重要模組. 沒有什麼創見, 就是幫入門者的障礙減少一點.

[Note]

  1. https://zhuanlan.zhihu.com/p/258532044
  2. https://towardsdatascience.com/how-to-train-a-bayesian-network-bn-using-expert-knowledge-583135d872d7
  3. https://blog.csdn.net/gwplovekimi/article/details/90032735
  4. DenseNet 學習心得
  5. https://ithelp.ithome.com.tw/articles/10204727
  6. https://github.com/eriklindernoren/PyTorch-GAN/blob/master/implementations/infogan/infogan.py
  7. https://towardsdatascience.com/5-different-meanings-of-underscore-in-python-3fafa6cd0379
  8. https://github.com/pytorch/pytorch/blob/master/torch/nn/modules/loss.py
  9. https://zhuanlan.zhihu.com/p/393350811
  10. https://github.com/jonbruner/generative-adversarial-networks/blob/master/gan-notebook.ipynb
  11. https://aiqianji.com/blog/article/1

本網站修繕小註解

因為 WordPress 一直抱怨 PHP v5.6 太老舊又不安全, 我只好破釜沉舟把網站進版. 原本只想換 PHP 就好, 但是看著一些網路教學去做, Apache 還是開不起來, 我又沒有本事 debug. 只好重新裝一個 Xampp. 這樣是能開得起來, 毛病還能一個一個修就是了.

以下紀錄比較重要的步驟, 絕對不是 copy paste 就可以搞定的. 尤其是新的 Xampp 還是用 PHP V8, 本身就跟 V7 有點小衝突.

  1. 將原來的 htdocs 底下的檔案 copy 出來. 這是為了 plugin 和 gallery 的需要. 當然 plugin 都可以重裝, 我要保存的是圖檔.
  2. 以 WordPress 控制台 –> 工具 –> 匯出程式, 將網站備份. 等效做法是從 phpmyadmin 裡面匯出 WordPress 的 sql. 要注意的是 php.ini 預設的 值很小, 我的網站已經很肥了. 所以要改成:
    post_max_size=128M
    upload_max_filesize= 256M
  3. 重新找一個 Xampp 架站, 以 phpmyadmin 開一個 WordPress 資料庫. 當然別忘了幫自己開帳號和權限. 
  4. 安裝 wordpress import 的 plugin (系統在 import 時也會提示). 
  5. 把舊的網站的 ssl key copy 到新的網站 (假設網站 URL 沒變).
  6. 把舊 plugin 和 ngg 目錄都 copy 到新網站.
  7. 安裝 ngg (gallery) 的 plugin in, 不然匯入時會報太多錯誤,
  8. 匯入舊網站的 xml.
  9. 因為新 xampp 的 PHP 是 v8.0, 要去 php.ini 把 extension=gd2 改為 gd. [1] 
  10. 到 ngg 的 plugin 去 scan gallery 目錄下的影像檔.
  11. ngg 已經不支援 shortcode 了, 也就是 slideshow=1 這種, 用新的 UI 插入 ngg 媒體. 到處冒出的 warning 就會消失.
  12. 有些文章剩下一半, 我以為是 php.ini 給的 post size 或是 upload size 太小, 或是 time out 太短? 不過更重要的是 import 文章進來後, 被主動加了一些註解. “<!–[CDATA[" 和 “]]>" 之類的. 這些要到 phpmyadmin 選 wordpress, 然後選搜尋 –> 取代. 把這些東西用空白代換掉, 隱藏的文章就會出來. 但我還沒有辦法處理消失的表格和段落間距. my_sql-620x200
  13. Zbench 這個主題有相容性問題, isHome 這個變數沒有初值, 在 functions.php 裡面, 大約 126 行的地方, 我直接 $isHome = ‘ class="current_page_item"‘;
  14. 預設字體很小, 這個要選外觀 –> 佈景主題檔案編輯器, 然後選 “系統內建的 CSS 編輯器", 把一些設定加到 “自訂項目".my-css
  15. 在 pHpMyadmin 中企圖刪除不需要的 root 帳號, 不知為何突然發生 #1034 的故障, 看了 Youtube 影片才修好. 有好幾片都是類似的. 可參考[2].
  16. 解決 #1034 後, 不再想刪 root, 而是把 phpMyadmin 裡面不需要密碼的 root 帳號都改成需要密碼, 然後我就被踢出去了. 看了[3] 才回想起進去的方法.
  17. 把phpMyAdmin 目錄底下加個 .htaccess 也可以卡住讓人無法使用 phpMyAdmin.

[note]

  1. https://lindevs.com/gd-extension-has-been-renamed-on-windows-in-php-8-0/

[2] How to Resolve error “1034 – index for Db is Corrupt in MYSQL" | Repaire MYSQL tables with xampp – YouTube

[3] 如何設定XAMPP修改phpMyAdmin的MySQL密碼 – ucamc

QMS, VRR, NFR 小整理

Netflix 花了一些功夫在影片播放的品質上, 力抗有片源但是 UI 和翻譯還不到位的 Disney+. 以 … 繼續閱讀「QMS, VRR, NFR 小整理」

Netflix 花了一些功夫在影片播放的品質上, 力抗有片源但是 UI 和翻譯還不到位的 Disney+. 以前我聽到的都是 “content 為王", 不知道有獨門 content 但介面比較陽春的那家未來會不會勝出? 先說到 Netflix 在 NRDP  先後推出 NFR (Native Frame Rate), VRR (Variable Refresh Rate), QMS (Quick Media Switching). 在此整理一下它們的差異.

NFR 要求先固定選擇 50 or 60Hz, 這個依據電視的規格是 PAL 或 NTSC 制而定. 實際上的值也可能是有頻篇的 49.95 或 59.94Hz, 然後以這個值做為上限. 以下假設輸出就是預設 60Hz.
Netflix 開 NFR 目的是切換片源時 frame rate 不要重設 (免得 reset HDMI 畫面會閃黑), 所以即使 NFR = flase, 會以軟體外插 source 的頻率到 60 Hz 播出. 假設 NFR = true 呢? 此時就會以最接近 60 Hz 但不超過 60 Hz 的倍數播放, 以 24Hz 為例, 就是 mapping 到 48Hz. 當然若 HDMI RX 不支援 48Hz, 就不在 frame rate map 裡面, 還是得輸出 60 Hz.

但 VRR 就不一樣了 (一開始我會跟 RISC-V 的 RVV 搞混), VRR 會讓 HDMI 的輸出與輸入完全同步. 這個功能對玩遊戲最有幫助, 因為遊戲的 frame rate 本來就是忽快忽慢, 明明很靜態的時候, 每秒外插個 120、144 張有點浪費電. 只要 HDMI 輸入端 (如電視) 知道遊戲機的幀率, 那麼快慢變化就不是問題了, 當然也不需要黑屏重置.

這招對播電影來說是大材小用, 不過 Netflix 也要做遊戲了, 所以 NRDP 要求未來要有 VRR 也是剛好而已.

至於 QMS, 也是避免切換幀率中的黑屏. 或曰, 都有 VRR 了, 何必有 QMS. QMS 的重點不在於單一 HDMI 的內容如何改變幀率, 而在於電視切不同 HDMI 輸入, 在遇到不同幀率變化時也不黑屏. 對 HDMI TX 來說, 這件事很單純. 比較要花功夫的應該是 HDMI RX 吧.
HDMI-feature-2022-01-03-105317-768x446
上圖擷取自 [1]
[REF]

  1. HDMI 2.1 規格發表

DAC 小註解

講到 DAC, 最先浮現腦海的一定是 digital analog converter. 然而, 偏偏就是有人 … 繼續閱讀「DAC 小註解」

講到 DAC, 最先浮現腦海的一定是 digital analog converter. 然而, 偏偏就是有人喜歡把自己的東西命名為更慣用的名詞, 藉以拉抬知名度. 此處的 DAC 是指 downloadable application container. 也就是可下載的 container.
關鍵字 container 的宗旨在於把應用程式封裝在一個容器中, 於是它幾乎不受外在環境設定的影響. 比方說 docker [2]. 當然徒 container 不足以自行, 先要 porting 好一個內應, 也就是 docker engine. 接著才能承上啟下.
docker-768x662
至於 DAC 則是 Comcast, Sky, Liberty Global, Metrological (已併入 Comcast) and Consult Red 所開發的一套 container 系統. 除了 Consult Red 是僅存的軟體服務公司, 其他都變成運營商了 – 也就是對應台灣的凱擘, 中華電信. 下圖右上角這塊 app store 的雲端, 左上角是 APP SDK, 下方是接受 APP 的 device, 像是 STB, 或者電信業名詞叫 CPE.
dac-768x842
下載的 APP 為何能動? 在這裡的共通介面就是 OCI (Open Container Initiative ) [3]. 一套 OCI Image 被下載時, 會在雲端被打包為 OCI bundle. 通常只是壓縮, 但也可以被加密. Pull 到 CPE 後由 DAC installer (packager) 打包成 OCIContainer.
OCI 中除了 OCI Image 外, 另外一個角色是 OCI runtime. 它的用途在於安裝 container 到特定 file system 上, 它也放在 OCI bundle 的裡面. 實做方式有 Crun 和 Runc 兩種. 看官您覺得這命名鬧不鬧? 兩種方式各有支持者, Runc 是 RDK 聯盟採用的版本, 優點是體積小.
OCI-768x239
OCI define both a runtime specification and an image specification. The Runtime Specification outlines how to run a “filesystem bundle” that is unpacked on disk. The OCI image is used for packaging containers in a platform-agnostic way that can be easily distributed. At a high-level, an OCI implementation would download an OCI Image then unpack that image into an OCI Runtime filesystem bundle. At this point the OCI Runtime Bundle would be run by an OCI Runtime.
當然在 RDK 環境, APP 還是會由 RDK shell 控管. RDK shell 也管第一章流程圖左邊的 thunder container, 但這不在主題中先跳過. 其他還沒解釋到的剩下 Dobby [4].
Dobby 是哈利波特裡面的家庭小精靈. Well,.. RDK 聯盟的人有一票是冰與火之歌的劇迷, 所以新技術的名字都取自劇中的大陸, 例如 Westeros, ESSOS, …etc. 幸好 Dobby 是 Sky 的技術, 英國人當然要支援國貨.
Dobby 不是 container, 而是 container management 的 daemon. 它用來管理 container 的 lifecycle (start, stop, …etc.), 它的附加功能 (plugins) 還包括這些:

  • Advanced container networking support with NAT and both IPv4 and IPv6 support. Allows for easily adding iptables rules to allow/prevent traffic flow in and out of container
  • GPU memory limiting (providing the kernel has the appropriate support)
  • Container log management to either files or directly to journald
  • Loopback storage mounts to add persistent, isolated storage to containers
  • IPC support between containers/host by allowing access to the host dbus inside containers

[Note]

  1. https://wiki.rdkcentral.com/pages/viewpage.action?pageId=113967683
  2. https://www.docker.com/resources/what-container
  3. Open Container Initiative 
  4. https://wiki.rdkcentral.com/display/ASP/Dobby