電顯領域該學Python、Matlab、還是C/C++?

    隨著計算能力的加強與普及化,程式語言也迅速擴散到除了計算機科學以外的領域。這五年來人工智慧的瘋狂熱潮更再度將這股風從軟體吹到了金融、製造、以及科研領域。計算速度的提升也使得以往難以實行的自動像差調整、高品質斷層成像、高準確度影像模擬成為可能,大幅加速了相關領域的進展。這篇文章將介紹電顯領域內常用到的幾個程式語言及其優缺點,以及我認為初學者該從哪裡入門。

Python 與 C++的 rigid registration 與 multislice source code,
分別來自 Benjamin Savitzky 與 Earl Kirkland

註:我並沒有以「電顯領域需不需要學程式語言?」做為標題,因為我認為不管你想走理論還是實務,用程式語言進行數據分析與測試模型的能力已經逐漸成為科學研究者的必備技能之一,就好比個人電腦普及幾十年之後,「會使用作業系統與文書處理軟體」已經是標準配備,而不再是個你會特別列在履歷上的加分項目。

前言

    首先我想強調「不管用什麼方法或工具,能解決問題才是最重要的」。進一步考慮現實因素,更貼切的說法應該是「在有限時間與資源內,用最經濟的方法解決問題」才是我們的終極目標。畢竟真正能為大眾產生價值的只有最後成果,如果過於鑽研技術本身,往往會迷失在細節中,而忘記原先的目標。學習工具是很有趣的過程,但是光學習工具而不實際運用是無法解決任何問題的。

一、為什麼你應該運用程式語言去加速你的研究進程?

    假設你今天聘請了一位很有能力的工匠,他能夠用精妙的手藝做出產品,但是他只講一種你不懂的語言,例如英文。那麼驅使這位工匠的方法,就只剩下請人將你的點子翻譯成工匠看得懂的英文一途。而每次你有不同需求的時候,就必須再次仰賴翻譯員。翻譯員為了簡單起見只願意翻譯特定需求,而且翻譯員也有別的任務,可能每年只能來幫你一次。結果就是你的產品研發常常因為這個翻譯的問題卡在那邊動彈不得,不是你沒點子,也不是你的工匠手藝不足。

對很多人來說,套裝軟體就是這樣的一個翻譯員。替你將想法轉換成電腦看得懂的語言並且執行。但是套裝軟體最大的問題就是不夠客制化,如果套裝軟體沒有你想要的功能,那麼你就只能聯絡開發者,拜託他們把這個功能加進去,至於何年何月會實裝?沒人知道,你就祈禱吧。

但是科學研究常常需要去測試不同的點子,為了獲取新的知識必須要不斷翻新實驗設計、實驗儀器、分析方法。套裝軟體為市場需求的成果,不可能跟得上各種科學研究者的需求,你想要做出創新的結果,常常得親自站在第一線去開發自己需要的工具。如果你想要在理論上有所突破,就必須要深入了解每一步處理是否都合乎你的假設,而套裝軟體常常是不公開其原始碼的,你只能用,不能問為什麼。

即使你今天已經有一套處理數據的流程,也有套裝軟體能讓你一個點擊一個拖拉慢慢完成處理與分析。要手動反覆施作直到獲取足夠統計意義也常常是不切實際的,也很難保證可重複性。因此用程式語言去直接與電腦溝通,自動化這個流程,可以更好地保證科學研究的可重複性。同樣的事情如果能夠讓電腦自動執行,你就不需要聘請一大堆能力背景個性各不相同的研究員,經過漫長的培訓後去做那些重複又枯燥乏味的工作。

現在硬體設備與輔助軟體逐年迅速精進,即使是初學者也可以輕鬆地獲取高品質的實驗數據。數據的產生速度早已經遠遠超過了研究員能處理的速度,以電子顯微鏡來說,一次數小時的實驗就可以輕易獲取幾十GB到幾TB的資料。當你還在手動用套裝軟體一張影像一張影像分析資料時,其他人可能已經同時在跑三個不同計畫的分析了。速度上的差異會大幅影響你測試點子的效率,使用程式語言大概就像是走路跟坐飛機那樣的差距,有些地方走路還到不了



二、電顯領域裡有什麼情境需要用到程式語言?

    讓我們先思考常見的S/TEM究竟會產生何種訊號與data?電子顯微鏡的本質是精確控制的電子散射實驗儀器,可以蒐集各種電子與樣品作用後產生的訊號,例如不同角度的彈性散射電子、非彈性散射電子、特徵X-ray或其他光子 (CL)。以特定方式去篩選、組合、呈現這些訊號便成為了我們常見的data,例如S/TEM顯微影像 (Micrograph)、繞射圖譜 (Diffraction pattern)、電子能量損失能譜 (EELS)或能量色散X射線能譜 (XEDS)等等。其中顯微影像與繞射圖譜算是應用範圍最廣的兩類,因常以二維圖像方式呈現,我在此並稱為影像 (Image),以下的討論也會盡量以影像為例。

1. 影像處理 (Image processing)

    調整影像的亮度對比 (B/C)、柔化 (Smooth)、銳化 (Sharpen)、去噪 (Denoise)、扭曲校正 (Distortion correction)、傅立葉轉換 (Fourier transform)、邊緣檢測 (Edge detection)、捲積 (Convolution)等等都屬於影像處理。影像處理的目的是突出或削減特定訊號以利後續分析,套裝軟體如Digital Micrograph或TIA、Velox通常只提供基本的影像處理工具,且不見得會揭露其背後實行算法,也不一定能批次處理或是提供API接口,因此若是要進行一連串的影像處理,建議是在程式語言內實行,還能順便保存實行細節與參數。

2. 影像分析 (Image analysis)

    例如粒子挑揀 (Particle picking)、粒徑分析 (Size analysis)、鍵長分析 (Bond length analyzation)、缺陷檢測 (Defect identification)、應變場分析 (Strain analysis)、相鑑定 (Phase mapping/characterization)、強度積分(Intensity integration)等等從影像中獲取實際資訊的過程都屬於影像分析。這個步驟與影像處理息息相關,也牽涉數據統計與誤差分析等過程。分析過程常常極度仰賴人為輸入,使用程式語言自動化能大幅縮減其花費時間。以我自己使用Deep learning去辨識原子缺陷的paper為例,電腦辨別一張影像的缺陷位置只需要不到1分鐘,訓練有素的研究生手動標記要花2小時以上還無法保證穩定的準確度。

3. 影像重建 (Image reconstruction)

    將原有的實驗數據,以特定演算法重組成另一種影像,可以視作是一連串考慮物理過程的影像處理。例如電子斷層成像 (Electron tomography)、電子疊層成像 (Electron Ptychography)、Cryo EM裡常見的單粒子重建 (Single particle reconstruction)等等。這些重建工作常常牽涉大量數據運算與處理,有些人將整個領域稱為計算顯微鏡學 (Computational Microscopy)。這些領域上的突破常伴隨著開放package與套裝軟體商業化兩種極端,例如 IMOD、Tomviz、cryoSPARK、EMAN2 等等。對使用者而言,理解package所使用的程式語言能大幅提升對演算法細節的理解程度,並提供了修改精進的可能性。

4. 影像模擬 (Image simulation)

    與前三者不同,影像模擬更接近一種生成模型 (Generative model)。輸入參數並模擬物理過程以產生符合其理論模型的結果。常見的影像模擬方法像是 multislice 或 Bloch wave simulation,多用來模擬給定實驗參數下的理論影像,並與實驗結果比較。有些時候也會拿來測試或開發新的影像處理與重建技術。高品質的影像模擬有點類似高品質的DFT材料計算,是理論的實踐以及實驗結果的理想對照組。當你的實驗結果超出了目前理論模擬的預測,那可能正是新的科學發現。與影像重建類似,理解影像模擬所用的程式語言能大幅提升你的理解程度、更好地設定參數、抓出現有算法可能有的錯誤,還可能藉由API或腳本去批次計算。就像模擬HRTEM影像要測試各種不同實驗參數一樣,如果每次都用GUI手動輸入可能輸到天荒地老還做不完。

 

UCI的Prof. Huolin Xin開發的AtomSegNet
兼具影像處理與分析

三、該怎麼挑選學哪個程式語言?

    「用哪個程式語言最好?」可以算是萬年不敗的經典問題,在網路上也可以找到各路高手的精彩攻防論戰,從底層架構、執行效率、學習曲線、社群風氣、職場愛好程度、語法優美與否都有人討論,但從使用者的角度而言,往往只有當下最適合你的語言,而沒有所謂最強或最萬用的語言。根據不同情境使用適合的工具去解決問題才是重點,不需要意氣用事拿石頭砸自己的腳,堅持要用不合適的工具自己從頭手刻一遍非常沒有效率。理解並善用他人的成果,跟站在前人的肩膀上是一樣的。

我先條列出幾個比較的重點,這些常常比語言本身的個性還要重要,例如現成的package或open source software在某些情況下可以推翻所有條件,畢竟可以節省自己手刻的時間,但不一定每個都值得你親自去測試。
  • 有沒有前人已經寫好的package或open source software?
    • 能直接用現成的地方就直接用,即使是套裝軟體也偶爾會佛心提供API接口
    • 公開的package除了直接套用以外,還可以因需求修改或是學習思路,算是最有用的資源
  • 這個領域大多數人/你身邊的人用什麼語言?
    • 因為研究包含了大量的協作,你的原始碼 (source code) 不會只有自己看,還要與他人協作。用一樣的程式語言可以大幅減小溝通成本。
    • 你遇到問題時可以找得到人問,而且學習起來也比較有動力
      (但不一定要跟老闆用同一個語言,他可能會在你背後直接看你coding或是對你的code指手畫腳......壓力山大)
    • 足夠的使用人口數保障了這個語言的存續與第三方package的持續更新,這就是程式語言界的人口紅利,甚至可能影響大型供應商,形成正循環與複利效應
  • 你的任務種類是什麼?
    • 影像處理、影像分析、影像重建還是模擬?前兩者計算量通常比後兩者小,故後者對語言的效能要求更高。而影像分析又比影像處理抽象,盡量用更高等的語言來提高編寫的效率 (高等語言: 更接近人類語法的語言)
    • 需要多少人為互動、即時調整參數?影像處理常需要迅速測試不同參數,這個時候用直譯式語言會容易很多 (直譯式語言: 不需經過編譯 (Compile),可以逐行執行)
總結來說,如果你的研究題目已經有某個重要的package或套裝軟體被發表出來,那麼就直接使用其相關的程式語言。稍退一步若是沒有現成的可以套用,那麼盡量參考領域內多數人/身邊人都用什麼語言實作,這通常隱含了他們對語言特性與任務需求的權衡,而且他們很可能就是未來發表 source code、 package或套裝軟體的那群人。最後才是考量你的任務種類,從頭自己刻一遍。雖然開發上或許比較慢,但可能也是最有希望做出開創性研究的一種選擇。


最後在進入個別語言介紹之前,簡單解釋一些常用於形容程式語言的分類:
  • 通用 (General)
    • 指它不為特定領域應用而設計,即為multi-purpose。例如寫遊戲、網站、計算、應用程式等。
  • 高等 (High-level)
    • 指它更接近人類語言與思考邏輯,將機械運作抽象化成人類能理解的操作。高低是相對的概念,現代定義的低階語言可能只剩下機械碼 (machine code) 與組合語言 (assembly language)。越低階的語言就越接近系統底層,也是俗稱的靠近硬體,可以直接操控記憶體或是做一些位元操作。
  • 動態 (Dynamic)
    • 指它的變數可以在運行中被改變結構、甚至引入新的函數或對象,這使得程式碼本身非常具有彈性,但也可能造成一定程度的混亂與效能代價。相對的概念是靜態 (static),變數一經宣告就不能在運行間改變,這多少會使編寫難度上升,但運行效能則提升。
  • 直譯式 (Interpreted)
    • 指它的原始碼可以通過直譯器 (interpreter)一句一句逐步翻譯成機械碼供電腦執行。與之對應的是編譯式 (compiled)語言,原始碼會一次全部通過編譯器(compiler)去編譯成機械碼。直譯式語言因為步驟比較繁雜,牽涉到層層轉譯(位元組碼、虛擬機)等,因此運算效能通常比不上編譯式語言,所以編譯式語言常被用來寫有效能需求的場合,例如作業系統。更詳細的介紹可以看這篇文章

四、Python、Matlab、C/C++到底差在哪裡?

1. Python

    Python是通用、高等、動態、直譯式語言,最大特色是簡潔易懂,用空格縮排表示區塊,不用再被{}或 ; 逼死。這幾年Python搭上AI與ML的風潮,使用人口急速成長,根本原因是易讀性與彈性,讀Python的原始碼跟讀英文差不多,有人甚至說Python是可以被執行的pseudo code。所以Python非常容易學,好讀好寫,一個沒有程式語言經驗的人也可以在幾天內弄好環境、安裝好現成套件然後開始做分析,開發新專案非常迅速,因此使用者社群很活絡,與Python相關的開源專案相當多。

Python最為人詬病的問題大概就是執行速度,但執行速度牽涉到原始碼結構、演算法、直譯器類型、硬體條件等各種因素。而且除非是做大量大型運算,否則以現在的硬體條件即使是拿來訓練ML model也是綽綽有餘。甚至開始有人拿Python寫需要大量運算的multislice影像模擬(py_multislice)。大部分科學研究者看上的是Python本身在編寫上的效率提升,比起你花兩天寫C/C++ code然後一分鐘執行,用Python可能30分鐘就寫好了然後再跑10分鐘。真的想要提升執行效率也有很多手段可以選擇,Numba、Cython、CuPy等等,極端一點就直接將核心部分用高效率的C/C++重寫。反正Python對各種語言的接口都很完整,也有人稱其為膠水語言。

就我自己參加這幾年M&M的感覺,有點資歷的大老們普遍主力是Matlab,研究生們或新進PI們都用Python或是兩者都用。以我自己為例,老闆用Matlab但我主力是Python。幾個National lab如ORNL與LBNL的一些團隊公布的package也都是以Python為主,例如NCEM的openNCEM、ORNL的pycroscopy與今年剛加入的STEMtool,還有做EELS的HyperSpy。雖然不確定這股熱潮還會延續多久,但因為Python本身是通用語言以及這五年內累積的人口紅利,學習Python可以即刻享受廣大的開發者社群,也不太需要擔心會迅速被淘汰掉。

2. Matlab

    Matlab是商業數學計算軟體,提供用於演算法開發、資料視覺化、分析、數值計算等工作的互動環境。可以視作是一個開發平台,在科學與工程領域歷史悠久,有著崇高的地位。語言本身跟Python類似,也是高等動態直譯語言,但並不是一種通用語言,至少我沒聽說過有人用Matlab寫網頁。與一般程式語言最大的差異在於Matlab是商用軟體,你必須要購買序號、安裝程式後才能在你的電腦上運行用Matlab撰寫的程式碼。因此很多人離開學校之後就沒有辦法繼續合法使用Matlab,這點大幅限制了社群的成長,相對應地也沒有那麼多第三方寫好的現成package可以用。知乎上有關於Matlab的能力與歷史地位很精彩的討論

在讀寫難度、執行效率方面,我個人是感覺不出太多與Python的差異。在影像處理上也有很豐富且飽經測試的Toolbox,因此就做研究而言,選Matlab不會碰到什麼大問題。在某些特定領域Matlab可能會有更好的表現,這主要是基於對矩陣運算的最佳化,前提是你的程式碼也要符合這些運算的要求,例如向量化 (vectorize)你的運算。

整體來說,Matlab與Python在各方面都能夠很好地符合研究所需。關鍵差異可能僅在於你的子領域有沒有已經用某種語言寫好的package。大部分學校都有買Matlab的license所以只要留在學界就影響不大,不過缺乏新血加入可能會是一個長期的隱憂,可以參考這篇文章對於Matlab與Python在bioimage的比較。就我所知,電顯領域使用Matlab作分析的group像是Cornell的David Muller group及他的徒子徒孫們,英國的Lewys Jones group發表了不少用Matlab寫的電顯影像處理package,還有NCEM的Colin Ophus與他非常好認的Matlab 動畫/繪圖風格。


3. C/C++

   C/C++是靜態且編譯式語言,有者動態直譯語言難以匹敵的執行效率。 C/C++也是通用語言可以運用於各種場合,但是沒有Python那麼高等,所以沒有那麼好讀。另外一般而言,Python與Matlab的底層都是用C/C++實現的 (CPython直譯器)。編譯式語言最常用來寫作業系統、大型軟體、或是需要大量運算的情況。因此文章開頭的那段multislice simulation原始碼,使用的就是C++。事實上大部分的multislice程式都是用編譯語言寫的,例如C/C++或Fortran。Fortran甚至還是現在某些材料計算package的首選實作語言,例如VASP、CASTEP、WIEN2k、LAMMPS 都是(或曾是)用Fortran寫的 (雖然使用這些package實際上不需要懂Fortran,而且LAMMPS在2004年後就用C++重寫了)

但是編譯式語言的執行必須將整個原始碼編譯,不利於使用者即時互動,對於科研開發測試而言並不像Python或Matlab那麼方便。雖然執行效率最高,但是實際編寫與操作都更花時間。因此一般只有在需要把package封裝成exe應用程式並且供廣大使用者使用時,才會把code用C/C++重寫並且發布。

C/C++依然是現在學校教授計算機概論/程式設計的熱門選擇,主要是因為其通用性及效能。至少在業界很難想像它們會被淘汰,對建立程式邏輯也有不錯的效果。只是跟現在的高等語言比起來,自學者可能會碰到更多問題,更容易產生挫折感。

五、結論

    總結來說,我會更建議初學者去學習Python或Matlab。考慮到電顯社群現在的使用趨勢,Python可能會有更好的未來性。但是如果你的project可以直接利用前人寫好的Matlab code,那麼從Matlab入門也沒什麼不好。程式撰寫邏輯都很接近,它們的互相移植也不困難,頂多就是檢查一下函數的輸入輸出結構,以及一些語法上的細微差異。

不過如果研究上有大量計算需求,或是對於軟體的更底層是如何實現的有興趣。那麼學習C/C++做為編譯式語言會是一個很好的互補,保障了當你需要高效能時的選項。終歸來說,選用何種程式語言實作就跟選用哪種實驗儀器做實驗是類似的,只有當下最適合而沒有所謂的萬用選擇。多會一種語言就是多一種看待世界的方式,人與人溝通的語言如此,人與機器溝通的語言亦如是。

我們是研究者,只要是能解決問題的方法都該盡量去嘗試。如果這篇文章能帶給你一點學習程式語言的動力與勇氣,並且運用它去解決你研究上的問題,那麼我寫它也就值了!

留言

熱門文章