Skip to main content

19 posts tagged with "learning note"

View All Tags

· 7 min read
Wei Ji

刷 Linux

如果已經刷完 CFW,並且安裝 Luma3DS 的話,在 3DS 上跑起來並不會太困難,只要照著指示下載檔案並放到 SD 卡內,接著從 Luma3DS 的 ChainLoader 開機就能成功進入 Linux 了。使用者為 root ,密碼為 toor

然而這個 Linux 的檔案系統是跑在 Ram Disk 上,並且預設不會掛載記憶卡,因此在系統內進行任何修改在開機之後都會消失。要把檔案弄進去的方法有兩種:

  1. 將檔案放到 SD 卡內,並掛載 /dev/vda1
  2. 將檔案放到開機映像檔 zImage

其實單論我的目的是在 Linux 跑一個 Jvascript 程式,大可直接用掛載的方式處理,但是使用 3DS Linux 的觸控板打指令真的是一件頗麻煩的事情(包含掛載指令),如果可以預載並自動執行一些腳本免除我手動輸入的步驟是再好不過了。

製作開機映像檔

在處理自動掛載以前,我們要知道如何把東西放進 zImage 內,這過程涉及兩個步驟:

  1. 產生 rootfs.cpio.gz
  2. 製作 zImage

產生 rootfs.cpio.gz

cpio 是 UNIX 作業系統的一個檔案備份程式及檔案格式1。cpio 是一個比較古老的備份命令,也是用於磁帶機備份的工具,雖然如此現在許多時侯仍然需要使用這命令,例如製作系統內存映像檔時等。像是系統映像檔通常位於 /boot 中,文件名以 initrd 開頭。2

因為它是基於磁帶的備份工具,因此無法直接替換掉該檔案裡面的特定文件,必須要把整個 cpio 解包進行編輯後再包回去。

linux-3ds 的專案有提供一個樣板可以直接下載:

$ wget https://github.com/linux-3ds/buildroot/releases/download/latest/rootfs.cpio.gz

或是你也可以從 buildroot 自己 build ,Buildroot 是一個可高度客製化的嵌入式 Linux 映像檔生成工具。Buildroot很強大,也很容易上手使用。3 Linux 3DS 專案下有一個已經與先準備好相關設定的 buildroot fork,照著指示做一樣很快就能生成 cpio 檔了。

cpio 作為 initrd 的格式,而 initrd 的英文含義是 boot loader initialized RAM disk,就是由 boot loader 初始化的 RAM Disk。在 linux 核心啟動前, boot loader 會將儲存介質中的 initrd 檔案載入到記憶體,核心啟動時會在訪問真正的根檔案系統前先訪問該記憶體中的 initrd 檔案系統。在 boot loader 組態了 initrd 的情況下,核心啟動被分成了兩個階段,第一階段先執行 initrd檔案系統中的"某個檔案",完成載入驅動模組等任務,第二階段才會執行真正的根檔案系統中的 /sbin/init 處理程序。4

編輯 cpio

我寫了一個小腳本來處理解包、覆蓋、包回去的步驟, 只要把檔案放在 original/rootfs.cpio, 要覆蓋的檔案樹放在 override/ 下。

#!/bin/bash

EXTRACT_TEMPD=$(mktemp -d)
OUTPUT_TEMPD=$(mktemp -d)
WORK_PATH=$(pwd)

if [ ! -e "$EXTRACT_TEMPD" ]; then
>&2 echo "Failed to create temp directory"
exit 1
fi

echo Extract Path: ${EXTRACT_TEMPD}
echo Output Path: ${OUTPUT_TEMPD}

# Extract and Archive again, /dev/console would missing
mkdir ${EXTRACT_TEMPD}/root
cd ${EXTRACT_TEMPD}/root

cpio -idv < "${WORK_PATH}/original/rootfs.cpio" 2> ${EXTRACT_TEMPD}/log.txt
cp -rf "${WORK_PATH}"/override/* ./

#find . > ${OUTPUT_TEMPD}/log-1.txt
find . | cpio -ov -H newc > ${OUTPUT_TEMPD}/rootfs.cpio 2> ${OUTPUT_TEMPD}/log.txt

cd ${OUTPUT_TEMPD}
gzip -c rootfs.cpio > rootfs.cpio.gz

chown <Normal-User> -R ${OUTPUT_TEMPD}
chgrp <Normal-User> -R ${OUTPUT_TEMPD}

chown <Normal-User> -R ${EXTRACT_TEMPD}
chgrp <Normal-User> -R ${EXTRACT_TEMPD}

比如,編譯出來的程式會仰賴 /usr/lib/ld-linux-armhf.so.3,但是 linux 3ds 提供的 cpio 並沒有這個路徑,就可以在 override/ 下加入:

./usr/lib:
ld-linux-armhf.so.3 -> ../lib/libc.so

記得執行操作的時候要有 root 權限,因為 rootfs.cpio 裡面有些檔案類型需要 root 才能新增。

製作 zImage

照著指引安裝仰賴的函式庫、clone repo、把 rootfs.cpio.gz 放到專案目錄下,接著執行:

$ $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make -j$(nproc) nintendo3ds_defconfig all

它就會 build 出包含 zImage 在內,在 3DS 上跑起 Linux 需要的一些檔案。

自動掛載

這個 Linux 並沒有諸如 systemd, rc.local 之類的高級玩意,倒是有這些東西:

$ ls /etc/init.d
rcK rcS S01syslogd S02klogd S02sysctl

/etc/init.d/rcS 承擔 start 的功能 /etc/init.d/rcK 承擔 kill(stop) 的功能,會依序執行 /etc/init.d/rcS/S(\d\d.*),很好理解。

於是我就做了一個 /etc/init.d/S03sdmnt 來自動掛載 SD 卡:

#!/bin/sh

case "$1" in
start)
echo "Mount SD card"
# Mount SD card
mkdir /mnt/sdcard
mount /dev/vda1 /mnt/sdcard
;;
stop)
echo "Unmount SD card"
# Todo
;;
*)
echo "Usage: /etc/init.d/S03sdmnt {start|stop}"
exit 1
;;
esac

exit 0

小結

研究到這裡,會發現 Chain Loading5 的影子非常明顯: 刷進去的 boot9strap 會 boot Luma3DS; Luma3DS 會從 luma/payloads/ boot firm_linux_loader.firmfirm_linux_loader.firm 再去 boot arm9linuxfw.binarm9linuxfw.bin 再用 zImage 開機(?)


創用 CC 授權條款
Wei Ji以創用CC 姓名標示-相同方式分享 4.0 國際 授權條款釋出。

Footnotes

  1. Cpio - 維基百科,自由的百科全書. Retrieved 2022-11-25, from https://zh.wikipedia.org/zh-tw/Cpio

  2. 會紅的 Linux 筆記: cpio指令. Retrieved 2022-11-25, from http://canred.blogspot.com/2013/04/cpio.html

  3. 精通嵌入式Linux 第三章:Buildroot – LotLab. Retrieved 2022-11-25, from https://www.lotlab.org/2020/04/08/mastering-embedded-linux-part-3-buildroot/

  4. 【Linux技術】Linux核心Initrd機制解析,核心更新步驟,grub組態說明-阿里雲開發者社區. Retrieved 2022-11-25, from https://developer.aliyun.com/article/445357

  5. Chain loading - Wikipedia. Retrieved 2022-11-25, from https://en.wikipedia.org/wiki/Chain_loading

· 12 min read
Wei Ji

緣起 (aka 廢話)

(這一段在講整個學習過程的因果關係,只想看步驟的人可以直接跳到下一個段落)

前一陣子在尋找合適的方案來儲存 Voxel terrain 的資料,所以花了一點時間在琢磨 voxel 的檔案格式。

接著想想,或許我該把 side project 的風格都統一成 Voxel ,這樣彼此之間就可以共用技術棧,而同時手邊還有一個 FPS 相關的專案,就想:

去找找看免費的 Voxel 槍模型匯進遊戲內看效果怎樣。

就跑去 Github 翻 Ace Of Spades 的開源專案,然後發現它使用的模型檔案是 .kv6 ,全名是 "Ken Silverman's version 6 model file" 如果順著這條線索會找到一個頗有年代感的網頁1

在找這個檔案相關資料的過程中,會找到一堆 voxel 編輯器。接著我想:

既然都有編輯器了,我還用現成的幹麻,自己畫啊?

於是找到了:

  • MagicaVoxel
  • VoxelShop
  • Goxel

MagicaVoxel 雖然是免費的但是沒有開源;VoxelShop 則是用 Java 寫的,於是最後我就使用了 Goxel。

而在找軟體的過程想到,最近看到同事在用看起來很炫的 PureRef,但是它沒有開源,最後找了個 BeeRef 來用。

不過我想畫的角色有點複雜,一開始還是從簡單的開始好了,於是我就試著一邊摸索一邊畫我的 Minecraft avatar。

接著要輸出通用的 3D 檔案格式,我試著匯出幾個格式到 blender 但是會有幾個問題:

  • 貼圖遺失
  • 每個 voxel 由 2 個三角面構成;沒有 optimized,而且 mesh 沒有封閉

我想起在查資料的過程,有個 github repo 提供免費的 voxel 模型,並且作者有提到自己是怎麼輸出的。2

於是我又載了 VoxelShop 為了做轉檔,最後成功匯進 Blender ,下一步是綁骨架;試了一個晚上還是沒能設定好權重,剛好有在 FB 看到 Blender 相關的線下小聚,就報名了。在小聚上遇到野生路人指點與陪伴,終於學會正確的流程,但是權重還是沒畫好。

隔天剛好有遊戲開發相關的小聚,原本是不打算去的(前一個禮拜才去過),但是到家後發現主辦方貼文表示:「人太少啦~人來即可入場」。

去一趟吧。

到了會場我就默默的打開筆電繼續沒完成的調權重,不過還是不太熟悉要怎麼操作,沒辦法作到細緻的操作,直到一個野生的路人指點才豁然開朗。

製作 Voxel

個人是習慣使用 Goxel 作圖,輸出成 .vox

再匯入 VoxelShop ,只是圖層資訊會遺失,匯入後要重建圖層。

當然也可以直接在 VoxelShop 完成繪圖,包含調色盤、對稱繪圖等功能比 Goxel 更完整。

題外話,.vox 檔案的規格是公開的3,完全可以照它的格式實做在其他軟體上。

輸出 Collada (.dae)

這裡可以下載 VoxelShop,執行方式如下:

java -jar voxelshop-start.jar

輸出的時候 Object Seoaration 記得選 "Per Layer", "Merged" 會把所有圖層合併:

完成輸出後,你會得到兩個檔案:

  • <name>_texture0.png
  • <name>.dae

其中 dae 檔中對於貼圖路徑的描述在 blender 匯入的時候會有問題,至少在這個環境下是有問題的:

  • Linux (Ubuntu)
  • VoxelShop 1.8.26
  • Blender 2.82

要把 dae 檔案中的:

<init_from>file://test_texture0.png</init_from>

改成(檔名請依實際情況做修改):

<init_from>./test_texture0.png</init_from>

Blender Time

改變貼圖模式

匯入模型後會發現貼圖糊糊的:

這需要修改貼圖的內插模式 (texture interpolation),選擇模型後到材質的工具選項,展開 Base Color ,把 Linear 改成 Closest

重新命名 UV map

因為需要把拆件的模型合併成單一物件才能綁骨架,但是直接進行合併的話會造成 UV map 設定損壞(貼圖失效),在合併之前要先把 UV map 命名成相同的名稱。

▼依序點開不同的部件然後修改成相同的名稱

Join 模型

▼匡選所有要合併的部件後,按下滑鼠右鍵之後選擇 "Join"

綁骨架

Shift + A 叫出選單後選擇 Armature

▼開啟 In Front 我們才能看到被模型包住的骨架

▼在選擇 Armature 時的編輯模式,按 Shift + A 可以繼續新增骨架

▼持續新增、調整位置的動作直到完成骨架

▼記得要幫骨架命名,不然等等調權重時候會分不清楚是在調哪個骨架的權重

▼接著先用滑鼠選擇人物模型,按住 Shift 再用滑鼠選擇骨架,然後按下 Ctrl + P 會跳出選單

一般的骨架教學會選擇 "With Automatic Weights" 即自動權重,不過因為 Voxel 的模型所需要的權重模式和自動權重賦予的模式不相同,這裡我們選 "With Empty Groups" 就好,選了自動權重也沒關係,就是要把多餘的權重「塗掉」有點麻煩。

▼接著我們選擇模型後進入權重編輯模式

▼在編輯權重之前記得從 「Vertex Groups」 選擇想要編輯的骨架

▼接著我們需要選定要編輯的區域,「塗權重」時候才不會影響到不想影響的頂點。

  1. 進入面選擇模式
  2. 選擇一個三角面
  3. Ctrl + L 選擇所有相連的頂點

▼選擇筆刷模式後,選擇點編輯模式,接著拿筆刷對著頂點塗塗塗

▼設定完權重之後,骨架的綁定才算完成,接著只要控制骨架就能控制模型囉!

後記(aka 廢話 part 2)

除了 Warzone2100, FreeCiv 這種被文章盤點開源遊戲時一定會收錄的「大作」之外,我平時也會在 Github 上逛逛看有沒有不知名但是有趣的開源遊戲,撇除程式面的不完整,大部分作品就算具備相對完整的遊戲機制但是其美術方面通常都慘不忍睹,或是其素材的部份並沒有給出開源的 license。

舉例來說這是 Javscript 圈最大型的 Voxel 專案 (つд⊂):

https://miro.medium.com/max/5752/1*cuXvo8U9Vj0VILU9yXwYew.png

當然這樣比較有失公允,畢竟開源圈也有 0 A.D. 這種優質作品。

而另外一個面向是素材平台,opengameart 上的素材不論是質還是量都比不上 itch 這類還是以上架為核心訴求的平台。

當然這種比較基本上是滷蛋比雞腿,開源圈跟獨立遊戲圈的創作者(一併稱呼開發者跟媒體創作者)其根源就不太一樣。獨立遊戲的創作者的終極目標通常是上架獲利,對於 license 的開放與重視程度也比不上開源圈的創作者,itch 上就有很多「免費素材」但是上傳者並沒有明確的聲明 license。

而開源圈 (github) 上許多作品都是工程師拿來練手的 side project,頂多就是進階版的「Hello World」,完成度當然不能跟本就衝著遊戲開發去獨立創作者相提並論。

雖然自己也會畫一些 pixel 素材用在專案上,但是我感興趣的題目類型還是 3D 的居多。

希望我的 side project 有個好看一點的門面

在這樣的心情下,試著去學習如何使用 blender 實現我的目的。

從產生動機到綁完骨架的時間順序大致如下:

2021-11-27 找到畫 voxel 的開源軟體

2021-11-28 把人物生出來

2021-11-29 試著輸出成拆件的模型(有些軟體輸出面數很高,甚至不是封閉面)

2021-11-30 試著匯入 blender

2021-12-01 匯入 blender 試著綁骨架

2021-12-02 早上摸了一會還是不會調權重,畫面跟教學長得不一樣

2021-12-02 晚上參加 blender 小聚,解決模型合併跟 UV map 壞掉的問題(野生路人一起討論)

2021-12-03 晚上參加獨立開發小聚,解決不會畫權重的問題(野生路人指點)

我都覺得自己在「speedrun 學習綁骨架」了 (°﹃°)

雖然本職是軟體工程師,不過畢竟本人不算真正意義上的零經驗者:

  • 有學過參數建模(俗稱工程建模)
  • 做過 CS 1.6 地圖
  • 在遊戲公司上班,可以從空氣中吸收美術同事的經驗值

所以我想這個 Blender 學習曲線不能當作通例 XD


創用 CC 授權條款
Wei Ji以創用CC 姓名標示-相同方式分享 4.0 國際 授權條款釋出。

Footnotes

  1. Ken Silverman's Voxlap Page. (Ken Silverman). Retrieved 2021-12-10, from http://advsys.net/ken/voxlap.htm

  2. mikelovesrobots/mmmm. (Mike Judge). Retrieved 2021-12-10, from https://github.com/mikelovesrobots/mmmm

  3. voxel-model. (ephtracy). Retrieved 2021-12-10, from https://github.com/ephtracy/voxel-model/blob/master/MagicaVoxel-file-format-vox.txt

· 8 min read
Wei Ji

好吧,這兩件事完全是獨立事件,但是放在一起講就多了幾分戲劇性,而且 24 小時內解完兩個人生成就也是事實。

雖然稱不上資深、剋金或是忠實用戶,但是憑借著我對 Markdown 的信仰混入了 HackMD 的線下小聚。在自我介紹中,發現 16 個與會者包含我在內就有 3 個 Linux 使用者,這種同溫層空氣不禁讓我舒適了起來(?)

而在其他人自我介紹的過程中,發現有人提到用 Markdown 紀錄法規,這對我而言無疑是一個千載難逢的機會,在主議程結束後的自由時間我當然湊了過去聊天,並展示我寫的簡易 Markdown 法規編輯器,現場反應熱烈的程度是出乎我意料之外的,連開發團隊的工程師都脫口而出「哇!好漂亮」;當然我知道這個轉換過程是基於十分有限的條件,也就是十分可控的,跟他實際上遇到的輸出條件有著巨大的落差,但是聽到稱讚還是很開心。那天晚上我因為基底現實的萍水相逢而獲得了 3 顆 Github 星星。

這個 Markdown 撰寫的法規轉換成 ODT 的實作我在 2020 年二月的時候就以 PHP 完成了,無奈當時並沒有能力架設一個穩定的伺服器與一個完整的服務來調用這項功能。到了 2021 年我用 Javascript 重寫了一遍、給它一個 GUI 並在五月份的時候用 Github Page 的服務架設靜態網站。後來也在網路上以及幾次線下的技術性質小聚介紹這個 side project,大多數的反應當然是不明覺厲。畢竟對法規與 Markdown 都有點了解的人,應該可以想像這兩個東西的圈子幾乎不存在交集。因為在場的都是 Markdown 使用者(與相關開發者 XD),一群看官讀懂這麼一個小魔術值得驚奇的地方,以及被一個相對資深的工程師在面前翻 source code ,真的是一段很愉快的經驗。

當晚我興奮的幾乎難以入眠,不過劇本似乎尚未就此結束,24 小時之內還有另一段故事等著我。

「I need your help.」一早老闆就晃到我的座位交待一個高優先級的任務:我們用來管理客戶程式碼的版控伺服器出了問題無法正常使用,要我排除故障,並提到他覺得是環境設定錯誤造成的。我對該服務有點陌生,又因為服務是由多個組件構成的,而老闆特別提到的錯誤訊息看起來是主服務無法和資料庫溝通,在簡單的閱讀入門文件之後就翻開資料庫相關的設定檔,不過乍看之下並沒有問題。

接著試著把包含伺服器和 service 在內的所有 status 都調出來看,發現系統資源被某個 process 佔用的異常,跟著關鍵字查到了一篇文章,是關於軟體漏洞的,文內也附上了被攻擊跡象的確認方式,於是我把伺服器的 logs 拉回本機,並寫了小腳本把關鍵的紀錄調出來。核對之後確認伺服器被攻擊的事實回報給老闆,但是他認為這只能證明有人嘗試攻擊,但是不見得是伺服器異常的原因。

於是我繼續試著找出製造 process 佔用系統資源的原因,最後發現伺服器各處都有病毒;從 Mirai、木馬到挖礦程式都有,最後回報是挖礦程式佔用系統資源,然後因為不知道攻擊者還動了什麼手腳,所以只能試著備份資料重灌系統。(畢竟不確定資料是不是也被感染了,相關 issue 中有苦主試過備份資料後還原系統問題並沒有消失)

從手上有限的資料、鎖定 CVE 編號、調閱 Log 排查、確認攻擊者手段到確認攻擊事實存在,對我而言是十分新鮮的體驗,並且就像冒險一般。

而這件事對我而言也有著特別的意義,如果 RPG 製作大師是引起我對程式設計興趣的火花的話,The Cuckoo's Egg 這本書就是引導我進入 Linux 世界的麵包屑。這是一本關於柏克萊大學電腦被駭,作者抽絲剝繭與駭客進行一系列捉迷藏的故事,發生在中央伺服器跑著 UNIX、科學家需要用程式跑學術運算才會使用電腦的年代。我今天不是成為一個單純的開發者(一部分程式開發者的光譜並不在開源的世界內),是因為我走入 Linux 與開源的世界;而我走入 Linux 與開源的世界最初的一大動機就是來自於這本書。它對我的意義重大到在公共圖書館閱讀;我連書名都不記得的多年之後,因為一些緣故得知了書名後立刻買下一本二手書(我連所有畢業紀念冊都沒有留下,這本書是我少有的收藏品)。並且在那天,我以小規模的形式親身體驗了一次「伺服器被駭的感覺」。

· 3 min read
Wei Ji

資料的組成的基本結構是 "Chunk",而 Chunk 分成三種:

  • RIFF Chunk
  • List Chunk
  • Data Chunk

https://docs.microsoft.com/en-us/windows/win32/multimedia/images/mmio2.gif

格式

Chunk

RIFF 格式中最小的資料單元,Chunk 定義上包含了三個(或四個)部份:

  • ID (Chunk Type)
    • 這個 Chunk 的類型,除了 "RIFF" 和 "List" 可以另外定義不同的類型。
  • Size
    • 這個 Chunk 的資料長度(Data & Type 的長度,不包含填充字元)。
    • 以 little-endian 儲存。
    • 單位:位元組。
  • Type
    • 只有 "RIFF" 和 "List" Chunk 有這個段落。
    • 用來描述檔案或列表的類型。
  • Data
    • 資料本體。
    • 以 Word 為最小單元,也就是偶數個位元組。
    • 如果資料為奇數位元組,在最後補上 1 byte 的 NULL 填充字元。

RIFF Chunk

一個 RIFF 檔案就是一個 RIFF Chunk 它可以包含零個或數個 Chunk。1

  • ID (Chunk Type)
    • 4 Bytes
    • 內容為 RIFF
  • Size
    • 4 Bytes
    • 資料大小,即整個檔案的大小扣掉檔案頭 ("RIFF") 和這個欄位本身。
    • 內容為 N8N-8,N 為整個檔案的大小。
  • Type
    • 4 Bytes
    • 用來描述檔案類型。
    • 例如:AVIWAVE
  • Data
    • 包含 Data Chunk 或是 List Chunk。

List Chunk

  • ID (Chunk Type)
    • 4 Bytes
    • 內容為 List
  • Size
    • 同 Chunk 描述。
  • Type
    • 4 Bytes
    • 用來描述列表類型。
    • 例如:INFO
  • Data
    • 包含 Data Chunk。

Data Chunk

  • ID (Chunk Type)
    • 4 Bytes
    • 自訂內容。
    • 例如:fmt data
  • Size
    • 同 Chunk 描述。
  • Data
    • 同 Chunk 描述。

RIFF Style

如果參考 RIFF 的 chunk 結構,但是沒有嚴謹的遵守規範,那麼這種檔案格式則稱為 "RIFF Style"。

小結

本文只是簡單的介紹 RIFF 的結構,具體的規格細節還是要依 spec 的為準。2

有一些技術細節就沒有照搬了,比如用 C 語言定義的資料類型跟結構;或是程式可以根據 ID 和 SIZE 欄,如果遇到不認識的 Chunk 類型可以直接跳過之類的。 (其實只是懶得把整個 spec 仔細的看過)


創用 CC 授權條款
Wei Ji以創用CC 姓名標示-相同方式分享 4.0 國際 授權條款釋出。

Footnotes

  1. Resource Interchange File Format (RIFF) - Win32 apps | Microsoft Docs. Retrieved 2021-11-14, from https://docs.microsoft.com/en-us/windows/win32/xaudio2/resource-interchange-file-format--riff-

  2. Multimedia Programming Interface and Data Specifications 1.0. (IBM Corporation and Microsoft Corporation). Retrieved 2021-11-14, from https://www.aelius.com/njh/wavemetatools/doc/riffmci.pdf

· 3 min read
Wei Ji

作為一個 Minecraft 玩家,同時也是對人工智慧有興趣的工程屍,最近發現了一個新玩具:Project Malmo。以 Minecraft 這種大眾化的遊戲與近幾年特別熱門的人工智慧而言;這個項目的曝光度和資料未免也太少了吧!?雖然不知道多久之後會棄坑,不過就把手邊掌握的資訊整理一下並分享出來吧!ᕕ ( ᐛ ) ᕗ

發展

源自於微軟內部一個名叫 Project AIX 的項目1,於 2016 年開源釋出;並被命名為 Project Malmo。

微軟分別於 2017 (Project Malmo Collaborative AI Challenge ) 和 2018 (MARLO 2018) 年舉辦的人工智慧競賽就是基於該框架進行的。

Carnegie Mellon 大學的研究團隊利用該框架開發了 MineRL 框架2,這促成了日後在 NeurIPS 2019 舉辦的 MineRL 鑽石挑戰 (MineRL Competition 2019),而該競賽已經於今年 (2021) 進入了第三屆,並已經開始了第一階段的賽事。

架構

稍微瀏覽了 Malmo 的程式碼3,了解到它的架構大致如下:

也就是 server-client 架構,只是在這裡的 server 端才是那個有視窗的一方(笑)。

當運行了 server 端的啟動腳本,它會透過 Gradle 下載一個修改過得 Minecraft 1.11.2,直到遊戲視窗開啟。

乍看之下就像一般的 Minecraft 遊戲,你甚至可以點開單人遊戲開一張生存模式的圖開始遊玩(進入遊戲後你會發現不能用滑鼠操作視角,然而這是可以切換的),但是實際上它已經透過指定的埠口作為 server 端在運作了,並且等待來自 client 端的指令。

接著運行使用 API 的程式,我們會發現遊戲主程式被「遙控」了,開始根據透過 API 提供的資訊建立場景,並且在遊戲開始後,外部程式能夠透過 API 操作遊戲內的人物在 Minecraft 的世界中活動(當然也可以透過 API 獲取遊戲內的資訊)。

Footnotes

  1. Microsoft Project AIX is an open source Minecraft-based artificial intelligence solution. (Brian Fagioli). Retrieved 2021-07-18, from https://betanews.com/2016/03/14/microsoft-project-aix-open-source-minecraft-artificial-intelligence/

  2. Project Malmo competition returns with student organizers and a new mission: To democratize reinforcement learning - Microsoft Research. (Microsoft). Retrieved 2021-07-18, from https://www.microsoft.com/en-us/research/blog/project-malmo-competition-returns-with-student-organizers-and-a-new-mission-to-democratize-reinforcement-learning/

  3. Malmö. (Microsoft). Retrieved 2021-07-18, from https://github.com/microsoft/malmo

· 4 min read
Wei Ji

第一階段:一般規則

在這個階段中,團隊最多可以有六名成員,以下為參賽流程:

  1. 在 AICrowd 競賽網站上註冊並使用下列資料。 或者,可以使用競賽的頁面上找到 "Create Team" 的按鈕組建隊伍(必須登入才能創建隊伍)。
    1. 用於運行競賽任務環境的入門代碼。 另請參閱 AICrowd 上的 "Notebooks" 部分。
    2. 主辦方提供的基本實作
    3. 人類玩家的資料集
    4. 主辦方用來評分參賽隊伍提交模型時使用的 Docker image 和入門模板
    5. 支援主流的付費雲端運算服務,用於測試參賽者提交的樣本效率。
  2. 使用主辦方提供的人類玩家資料集來開發與測試模型的訓練效果,以製作出能達成比賽課題的程式。
  3. 編寫以及訓練參賽隊伍的 agents。
    1. Intro 組,撰寫/訓練他們的模型以達成 MineRLObtainDiamond-v0 環境課題。 當他們對模型感到滿意時,提交他們經過訓練的模型進行評分。
    2. Research 組,在四天內只能使用 8,000,000 個環境樣本訓練他們的模型以達成 MineRLObtainDiamondVectorObf-v0 環境課題。 提交的模板將包含用於訓練和評分 agent 的腳本(在評分的伺服器上也是使用相同的腳本)。
  4. 當參賽隊伍對模型感到滿意時,提交他們經過訓練的模型進行評分。 自動化評分系統會將提交的程式放置在測試用的環境中進行評分,並計算與回報競賽排行榜上的積分。
  5. 重複步驟 2 到步驟 4 直到第一屆階段截止!

當第一階段完成後,主辦方將會:

  • 檢查排行榜上分數最高的提交的程式碼,以確保其符合比賽規則。
  • Research 組
    • 符合比賽規則的最高分提交將自動由比賽編排平台重新訓練。
    • 執行生成的模型數百回合並對其評分,以決定最終排名。
    • Fork 團隊提交的程式碼,並清除任何大於 30MB 的文件,以確保參與者在後續輪次中不使用任何預先訓練的模型。

第二階段:決賽 (僅適用 Research 組)

在這個階段中中,來自 Research 組的前 15 名團隊將繼續開發他們的算法。 他們的作品將會在某種對所有參賽者保密的環境與額外的資料集中進行測試與評分。

參賽者將能夠在第 2 階段期間每兩週提交最多一次程式碼。對於每次提交,自動評分器將在額外的測試數據集和模擬器上訓練他們的程序,評分訓練後的模型,並報告分數和指標返回給參賽者。最終排名將基於每個團隊在第二階段中表現最好的提交 。

原文:https://www.aicrowd.com/challenges/neurips-2021-minerl-diamond-competition#competition-structure

· 8 min read
Wei Ji

以下規則指出了整個比賽的精神,任何被發現違反規則的提交都可能被主辦方註銷參賽資格。

一般規則

以下規則適用於兩種組別(Intro 組和 Research 組)。

  • MineRL Diamond 挑戰的參賽作品必須是「公開的」。 團隊將被期望透露他們方法的大部分細節,包括原始碼(對於等待出版的刊物可能會有特殊的例外)。
  • 對於有資格進入最後階段賽程(Intro 組第一階段,Research 組第二階段)的團隊,每個成員必須滿足以下所有條件:
    • 年滿 18 歲且至少達到居住地的成年年齡
    • 不居住在受美國出口法規約束的任何地區或國家
    • 不是本次比賽主辦方的工作人員,也不是主辦方工作人員的家庭成員。
  • 優勝者者必須參加 NeurIPS 研討會,才能從我們的讚助商那裡獲得獎項。
  • 一個團隊可以同時向兩個組別分別提交作品; 不同組別中的表現將單獨評分。 兩個作品之間不會互相影響。
  • 與環境的交互必須通過 "step" 函式,只能使用提供的 Gym 界面。 不得以任何方式從模擬器中提取附加信息。
  • 官方規則說明將在 AIcrowd 網站上的常見問題解答中進行。
    • FAQ 將會張貼在 AIcrowd 頁面。
    • FAQ 中的答案是官方的正式回應。 任何非正式的回答(例如,通過電子郵件)都將被 FAQ 中的回答所取代。

Research 規則

這些附加規則僅適用於 Research 組。

  • 成品必須在不依賴人類領域知識的情況下訓練機器學習模型。
    • 不可以使用基於人工調適或 hard-coded 的狀態獎勵函數。例如,接近像是樹的物件時給予獎勵是被禁止的;但是根據陌生的新狀態給予獎勵 (curiosity rewards) 則是被允許的。
    • 不可以人工影響 actions/meta-actions/sub-actions/sub-policies。例如,機器學習的多層控制器是被准許的,而 meta-controllers 不能基於人工設定的條件來選擇 policies,像是判斷 agent 的背包中是否有特定物品。此限制包括動作的組合,例如,「持續向前走兩秒」或「敲下原木並放置合成台」。
    • 除幀堆疊 (frame-stacking) 外,狀態處理/預處理不能硬編碼。例如,agent 可以根據最後兩個觀察結果並在每個偶數的幀數做出反應,但是不能使用人工指定的邊緣檢測器在觀察上。另外一個例子,agent 可以對讀觀察歷史或數據集歸一化成 z-score 。
    • 為了確保附加到動作和觀察標籤的語義不被利用,分配給動作和觀察的標籤已被混淆(在數據集和環境中)。 行動和觀察(POV 觀察除外)已被嵌入到不同的空間中。 另外,在第二階段提交期間,將重新嵌入操作。 任何繞過這些混淆的嘗試都將構成對規則的違反。
    • 模型只被訓練用於與 -VectorObf 結尾的 MineRL 環境互動。所有 MineRL 環境都有特定的競賽版本,其中包含動作和觀察空間混淆。 它們都共享相似的觀察和動作空間嵌入,這些嵌入在第二階段時會被調整。
    • 培訓預算有限。 除了提供的數據集之外,還可以與模擬環境互動 8,000,000 次。 如果疊加觀察/重複動作,那麼每個跳過的幀仍然計入此預算。
  • 參與者只能使用提供的數據集; 源文件提交中不得包含其他數據集,也不得在訓練途中下載,但在 6 月 5 日之前就被公開且可用的預訓練模型則是被允許的。
    • 在對提交的程式進行測試時,各個容器將無法訪問任何外部網絡,以避免任何信息洩漏。 添加了相關例外,以確保參與者可以下載和使用流行框架(如 PyTorch 和 TensorFlow)中包含的預訓練模型。 參與者可以請求為任何其他公開可用的預訓練模型添加網絡例外,這些模型將由 AICrowd 逐案驗證。
    • 將清理所有提交的代碼存儲庫以刪除大於 30MB 的文件,以確保參與者不會檢查在已發布的訓練數據集上預訓練的任何模型權重。
    • 不准許使用在 MineRL 訓練得預訓練模型,或是使用和 Minecraft 有關或無關的資料訓練的預訓練模型。該規則的目的是允許參與者使用在 ImageNet 或類似數據集上訓練過的模型。 不要濫用這項規則。
  • 第一階段的比賽程序如下:
    • 在第一階段時,團隊必須提交程式碼在指定平台上來訓練他們的模型。 並且必須在四天內中止訓練。
    • 對於測驗分數最高的團隊,將檢查此程式碼是否符合規則。
    • 對於發現違規的提交,將聯繫違規團隊進行申訴。 除非上訴成功,否則主辦方將從比賽中刪除這些提交的內容,然後測驗其他提交的內容,直到第二階段額滿為止。
    • Research 組的前 15 名團隊將進入第二階段。
  • 第二階段的比賽程序如下:
    • 在第二階段中,團隊最多每兩週提交一次他們的程式碼。
    • 每次提交後,模型將在重新渲染的私有數據集和域上訓練四天,團隊將收到他們模型的最終表現。 數據集和 domain 將包含對動作空間和觀察空間的匹配度。
    • 在回合結束時,最終排名基於每個團隊在第二階段中表現最好的提交。

原文:https://www.aicrowd.com/challenges/neurips-2021-minerl-competition/challenge_rules

· 6 min read
Wei Ji

前言(a.k.a. 廢話)

我修過不少次工程數學,每次都選不同老師的課,因此目前修課老師在個人經驗中算是教學相對熱忱、詳細的;在課程中安插講解實務上的應用場合,用彈簧-質點-阻尼模型來解釋這些解微分方程的方法如何處理實際的物理問題。

最近課程進度到達拉普拉斯章節中的卷積性質,很驚訝他沒有花太多時間在解釋卷積,而是直接依照數學定義開始計算,並且示範其性質,於是我就這樣盯著那個積分方程式整整一節課,想著這玩意兒的幾何意義。(˘•ω•˘)

定義

下課之後我去查詢卷積的定義:

f(τ)g(xτ)dτ\int _{-\infty }^{\infty }f(\tau )g(x-\tau )\,\mathrm {d} \tau

恩?這東西的上下限怎麼跟我在課堂上看到的不一樣?接著我找到了一段話[^zero]:

For functions f, g supported on only [0, ∞) (i.e., zero for negative arguments), the integration limits can be truncated

在工程上函數可以代表訊號,而實務上我們不會考慮時間小於 0 的訊號,並且我們通常也只需要關注一小段時間內的行為,從而產生一個卷積特例:

0tf(τ)g(tτ)dτ\int _{0}^{t}f(\tau )g(t-\tau )\,\mathrm {d} \tau

讓我們先專注於這個特例,廣義的卷積等等再回來看。

幾何解釋

本文的重點其實就是一張圖:

在一個三維空間中,f 和 g 分別在兩個互相垂直的平面上,並且方向相反, 看起來就像是兩個函數彼此擦肩而過。

可以看出 g(τ)f(tτ)g(\tau)f(t-\tau) 或是 g(tτ)f(τ)g(t-\tau)f(\tau) 便是兩函數相乘後得到的長方形面積, 乘上上 dτd \tau 的話就會變成「一片微量的體積」了, g(τ)f(tτ)dτg(\tau)f(t-\tau) d \taug(tτ)f(τ)dτg(t-\tau)f(\tau) d \tau 的差異來自於: 你是站在 f(x)f(x) 的系統上積分還是站在 g(x)g(x) 的系統上積分。

積分過後你會得到一條像是烤土司的東西,而這條土司的體積可以描述為:

V=0tA(τ)dτ=0tg(τ)f(tτ)dτ=0tg(tτ)f(τ)dτ\begin{align} V &= \int_0^t A(\tau)d\tau \\ &= \int_0^t g(\tau)f(t-\tau) d \tau \\ &= \int_0^t g(t-\tau)f(\tau) d \tau \end{align}

這個體積就是我們的卷積了。

廣義卷積的幾何解釋

即使上下限變成無限,總之還是可以用烤土司得方式去思考, 我們不難發現如果兩個函數不會收斂的話,卷積是沒有意義的,因為這會是一條體積無限大的土司(?)

※或許在數學上有其他用途或意義,不過以工程而言沒什麼作用,不難理解為什麼在工程數學裡函數被約束成有限的時間區間。

值得注意的是,如果 f(x)f(x)g(x)g(x)xx 小於零的時候,其值都為零, 依照卷積的定義會很自然的把兩端以外的函數乘以零,只留下一條長度為 tt 的土司:

這條截斷的土司就是工程上使用的卷積積分方程。

物理意義

幾何意義看起來是條烤土司,不過究竟什麼樣的物理環境會用到這個數學模型呢?🤔

我在網路上找到了一個關於饅頭的例子[^example]:

有一個饅頭工廠,能夠生產饅頭,同時,饅頭放久了會壞掉, 我們可以用一些符號描述這件事:

  • f(t)f(t):工廠生產饅頭速率與時間的關係(單位:個饅頭/單位時間)
  • g(t)g(t):饅頭的生存函數,描述尚未壞掉的饅頭比率與時間的關係(單位:好饅頭/總饅頭)

接著我們提出一個問題:

n 個單位時間之後,我們有多少沒壞的饅頭?

如果我們先用離散方式描述,在第 0 個單位時間生產的饅頭會放 n 個單位時間, 因此在 n 個單位時間後殘留的饅頭數量可以表示成: f(0)g(n)f(0)g(n) , 在第 1 個時間單位生產的饅頭會放上 n-1 個時間單位,寫作:f(1)g(n1)f(1)g(n-1), 我們可以歸納出: f(x)g(nx)f(x)g(n-x), 最後把所有瞬間的情況積分起來就會得到:

0nf(x)g(nx)dx\int_0^n f(x)g(n-x) dx

卷積的積分方程就這樣出現在我們眼前了!(⊙ω⊙)


創用 CC 授權條款
Wei Ji以創用CC 姓名標示-相同方式分享 4.0 國際 授權條款釋出。

· 11 min read
Wei Ji

https://static3.cbrimages.com/wordpress/wp-content/uploads/2019/12/mecha-fight-in-tengen-toppa-gurren-lagann.jpg

關於「巨靈」,最直接的例子就是「國家」,最貼切的形象就是「巨人」,然而國家一詞對部份人而言過於抽象,或已經被不同的意義所佔據;而巨人又不夠正確,因為巨靈雖為人類造物卻又已經成為非人之物。所以讓我在將巨靈形容成更具體或更形象的比喻之前,先從構成的它的基礎說起吧!

原始自由狀態

有一個思想實驗是這樣的:

想像一個自然環境,物理法則乃最高且唯一的規則,然後這個環境中有兩個以上的人,每個人都具有從物理上摧毀另外一個人的自由,因為這是物理法則上容許的事實,也是所有人都各自持有傷害或消滅其他人的自由(權利)。

在這個階段,生命是無法被保障的,每個人時時刻刻都活在被傷害或摧毀的恐懼之中。

而這時其中一個人向另外一個人提出「我們不要互相攻擊」的提議,並且獲得同意了,假設雙方都願意遵守約定,這時契約成立,並且同時創造了權利與義務,對甲方(暫稱)而言,權利就是不受到乙方(暫稱)的攻擊,而義務就是不得攻擊乙方,反過來對乙方來說亦同。這時對雙方而言,都脫離了原始自由狀態,他們不再持有完全的自由,而背負了一定程度的限制(義務)。

社會契約

因為受到契約限制與保護的狀態遠比原始自由狀態來得更利於生存,於是人們傾向和彼此建立社會契約,最後塑造出一群人共同遵守的契約。如果一個人不履行契約的義務便會受到社會的唾棄,從而喪失契約部份或全部的權利。

對一個人言,有義務不能傷害的不是某個(些)人,而是所有在這社會之中的人;有權利不被傷害的不只是特定的某個(些)人,而是所有在這社會之中的人,在這個階段,個人履行契約的對象不再是單獨會特定的某些人,而是「社會」這一抽象的實體。沒錯,這個抽象實體就是「法人」,一個像人能夠與之立下契約並產生權利或義務的實體,但是卻不是個「人」。

這時這群人已經脫離了原始自由狀態,受到「社會」的約束。

權利與義務的另一端所指之處

從單純的「不為之」的權利與義務關係,到產生「為之」的權利與義務關係的過程並不複雜,也不用太久。

當從人們從採集狩獵轉向農耕,從投入到獲得回報的週期變得更長,失敗的代價也變得更大,狩獵採集是幾天的事,農耕卻是數個月的事,如果搞砸了可不是靠著毅力就能忍到下一次收成的小問題,因此能夠支撐數字與計算發展的基礎就在這樣的背景下醞釀而生,不過本文的重點並不是數學的發展,而是負責算術的那個人。

統計糧食,並且計算充不充足,大家不需要減糧來熬過下一次冬天,想必這樣的工作並不是「大家一起來做」的類型,自然而然的,這樣的工作就落在少數人身上了,他(們)的責任就是讓社會不會沒飯吃,出現異常也要告訴大家並擬定對策,而權利或許就是除了不用耕田之外還有更多的話語權吧。

可以發現到非對稱的契約開始出現在社會之中,契約的一端是一個人的權利與義務;另一端是許多的人權利與義務。許多人的義務累積到一個人身上時,累加權利就變成了更為強烈的權力,這樣的非對稱契約會自然而然的讓人產生特權,並使社會的成員分成了統治者與被統治者兩類。

非對稱契約賦予了代表社會的這個法人無比的權力,到這個階段,我們就能將這個與眾人構成契約的虛構實體視為巨靈了,因為它可以集合眾人的力量去在荒地中開闢道路、攻略城池、築起高牆,甚至能在敵對巨靈的身上點燃人造的太陽。

抽象化的巨靈意志

在軟體工程中,我們會將問題拆成不同的層級,然後分別處理。比如:「我想知道今天的天氣預報」,這是問題(或是需求)本身,是最抽象的描述。而這個需求會透過「實作」最後實現,以手機為例:

  • 天氣預報有多雲、下雨、晴天三個圖示表示,並且顯示溫度和降雨率
  • 用一種特殊的文字結構描述上述的內容(HTML、CSS)
  • 把文字結構轉成電子訊號,這個電子訊號有開跟關之分
  • 把這個電子訊號跟其他訊號以特定的方式組合(訊框)
  • 電晶體用以特定的方式開開關關

越上方越接近問題或目的本身,但是越抽象; 越下方執行方式越具體,但是對問題本身的關聯性越低。

巨靈層級的問題涉及科技、法律、民生、工業、商業、地方勢力、外國勢力、既得利益勢力、國際局勢...等等,想用個人的視角去理解巨靈面對的問題,就像是電晶體要想理解 HTML 一樣。(不要試圖用誰棒棒、誰壞壞、什麼是正義、什麼是邪惡的方式去理解巨靈層級的問題)

然而就像人類發明工具來解決問題之後,工具本身帶來的問題又會多到要立一門學科去理解一樣,貨幣帶來了經濟學、電腦帶來了電腦科學...,而理解甚至操縱巨靈的技術就是所謂的政治。

巨靈,非人哉

當然,某種程度上巨靈的表現一定程度會受到它的掌權者所影響,但是在巨靈的尺度上,個人的思考與情感已經失去了意義。舉例來說,當一個工業高度發達的巨靈(已開發國家)遇上一個發展相較之下落後許多的巨靈(開發中國家),同樣是一個人一個小時的勞動代價,其產出卻必定有著巨量的差距,藉著自由貿易,造成弱勢國家的人民不斷在經濟上被霸凌,就像是一個滿懷惡意的巨靈不斷的剝削另外一個巨靈。但是對於發達國家的公民而言,他們只是如常的勞動生產與消費。(我不是在批評國際貿易,對他們而言選擇不貿易有著更糟糕的代價)

這便是巨靈的「非人性」的一面。

主流對巨靈的描述與本文的差異

Thomas Hobbes 在描述巨靈 (Leviathan) 時使用的對象是國家,但是受限於時代,那個時候並沒有富可敵國的企業體系,不過我認為以契約建構起來的「巨人」來說,並不受限於描述國家,企業自然也能代入巨靈這樣的概念。

並且以國家來說,他認為巨靈是受到一個人(君主)或是數個人(政府)所控制的,在這層意義上來說,他所描述的巨靈更為人性。

我其實還想談談「複合巨靈」與「超巨靈」,不過礙於篇幅以及本文定位在「淺談」,這些主題還是留給別篇文章吧。(°∀° )