AI-LECTURER 速報課|2026-07-15|約 26 分鐘

讓老 Fortran 程式學會「倒著算」:不重寫也能生出 AI 要的梯度

取材:Differentiable Fortran with LFortran and Enzyme(Hacker News(AI 高人氣))
📍 真實場景
陳工程師,42 歲,風力發電葉片外形最佳化顧問

他手上有一套用了將近 20 年、經過大量風洞實驗驗證的 Fortran 流體模擬(CFD)程式,公司最近導入一套 AI 最佳化平台,想讓演算法自動微調葉片外形。

😖 卡住的地方:AI 最佳化平台需要「外形參數改一點點,模擬結果會跟著變多少」的梯度資料,但那套 Fortran 程式從來沒被設計成會吐出梯度;重寫成 Python 至少要半年,而且沒人敢保證重寫後結果跟原本一樣準。
💡 這一課會告訴你第三條路:不重寫、不用手推數學,直接讓編譯器在幾十年前的老程式上生出正確的梯度,讓老程式碼變成 AI 系統可以呼叫的一塊積木。

🧭 這到底是什麼(白話版)

這篇文章要處理一個很實際的問題:很多重要的物理模擬程式,像是氣候預測、飛機機翼設計、核能反應爐安全分析用的程式,都是幾十年前用 Fortran 寫的,而且經過大量實驗反覆驗證過,準到可以讓人放心拿來做工程決策。問題是,現在的 AI 最佳化工具都需要梯度某個輸出結果,如果把某個輸入調整一點點,結果會跟著變化多少幅度與方向的數字,但這些老程式從來沒被設計成會吐出梯度這種東西。

要拿到梯度,過去只有三條路:花好幾個月請專家手動推導每一行程式的導數(貴又容易出錯)、用「輸入改一點點、看輸出變多少」的土法(不準又慢)、或是乾脆把整套程式重寫成 Python(等於把幾十年的驗證成果全部歸零重來)。這篇文章示範了第四條路:讓電腦自己在編譯的過程中,把梯度算出來——這就是自動微分(AD)讓電腦在執行程式的同時,自動算出每一步運算對最終結果的影響量,不用人工推導數學公式,也不是用試誤法逼近

做法是這樣:先用 LFortran 這套編譯器把人看得懂的程式碼,翻譯成電腦看得懂的機器指令的工具,把 Fortran 原始碼翻譯成LLVM 中間碼各種程式語言最後都會被轉換成的一種共通格式,讓不同語言可以共用同一套後續處理工具。接著讓 Enzyme 這套工具,直接在這份「共通格式」上動手,自動生出對應的梯度計算邏輯,完全不用碰原本的 Fortran 語法。

最後,Tesseract 這套工具把算出梯度的 Fortran 程式包裝成一個JAXGoogle 開發的一套支援自動微分與高速運算的 Python 工具,AI 研究和最佳化常拿來當主力看得懂的「自訂元件」,讓這支幾十年前的老程式,看起來就像是一個原生的 JAX 函式,可以直接接進其他 AI 程式碼裡使用。作者也很誠實地說,這整套做法還很實驗性,得有心理準備去追一個回傳 NaN 的梯度,甚至手動比對機器層級的程式碼差異除錯。

🎯 為什麼值得你花時間

老程式碼不用整套重寫幾十年份的 CFD、氣候、核能模擬程式,每一行背後可能都對應著一次昂貴的實驗驗證。重寫成 JAX 或 PyTorch,等於把這些驗證成果全部歸零重來;直接在 LLVM 這一層生出梯度,讓老程式碼不必離開崗位,就能被新的 AI 系統呼叫。
打開「用 AI 幫忙做最佳化」的大門很多工程最佳化、反問題已知結果,反推出輸入條件該設多少才會得到這個結果,跟一般「已知輸入求結果」的方向相反(像是「材料要怎麼設定才能達到某個溫度分佈」)都需要梯度才能有效率地解。過去這些領域的老程式因為吐不出梯度,只能被排除在 AI 最佳化流程之外,現在多了一張入場券。
這招不只救得了 FortranEnzyme 是在 LLVM 中間碼這一層動手,代表凡是能編譯成 LLVM 的語言——C、C++、當然也包括 Fortran——都能用同一套邏輯生出梯度,等於幫「整個舊系統現代化」這件事找到一條共通的路,不是只解決 Fortran 工程師的問題。

⚙️ 它是怎麼運作的

1
把 Fortran 翻譯成 LLVM 中間碼LFortran 這套編譯器把 Fortran 原始碼翻譯成 LLVM 中間碼,這是關鍵的第一步——因為 Enzyme 只看得懂這份共通格式,不管背後原本是什麼語言寫的。
2
Enzyme 在中間碼這一層動手術Enzyme 讀懂這份中間碼之後,自動幫每一行運算生出對應的「反向」計算邏輯,也就是梯度的計算過程,全程不需要工程師手動推導任何一條數學式。
3
把整個時間迴圈的梯度正確串起來熱傳導這類模擬通常要跑很多個時間步驟,Enzyme 得把每一步的梯度像接力賽一樣正確串接,才能算出「最初的輸入」對「最後結果」的完整影響,這一步很容易出錯,也是文章提到要手動比對中間碼差異除錯的地方。
4
包裝成 JAX 看得懂的積木Tesseract 把算出梯度的 Fortran 程式包裝成一個自訂的 JAX 元件,讓它看起來就像 JAX 原生函式一樣,能直接接進其他 AI 程式碼裡運算。
5
拿去解「反過來想」的問題有了梯度,就能有效率地解反問題,例如:想要材料達到某個溫度分佈,一開始的初始設定該怎麼調——這正是文章最後拿來展示成果的挑戰題。
三種拿到梯度的方法比一比
方法要花的力氣準確度對老程式碼的影響
手動推導伴隨方程式數個月的專家人力準確程式改一行,數學就要重推一次,很容易忘記同步更新
有限差分(試誤法)幾乎不用改程式不夠準,步長沒抓好誤差很大不用碰原始碼,但每個參數都要多跑一次模擬,成本隨參數量增加
LLVM 層級自動微分(本文作法)接好編譯工具鏈即可,不用手推公式跟解析解一樣準確原始碼幾乎不用改,但工具鏈還很新,會踩到不少邊緣案例

🛠️ 動手做:親手體驗:為什麼自動微分比「土法煉鋼」準

  1. 這是文章裡『220 行 Fortran 熱傳導解算器』的簡化 JS 玩具版:一樣是先把整個模擬跑完,再回頭問『某個輸入參數改一點點,結果會變多少』。
  2. 拖動『降溫係數 k』,看最終溫度怎麼隨它變化——這個滑桿對應文章裡那顆熱傳導模擬的角色。
  3. 拖動『有限差分步長 h』,比較土法煉鋼算出來的梯度,跟自動微分算出來的『正確答案』差多少,親自體會文章說的『有限差分不準又難搞』是什麼意思。
  4. 把 h 拖到最右邊(非常非常小)時特別留意:誤差不但沒有變小,反而開始亂跳——這就是文章作者說『追著一個回傳 NaN 的梯度、比對機器碼除錯』的縮小版現場直擊。
👇 下面是活的,直接操作

🧠 工程思維透鏡(資深工程師看到的是什麼)

🔭 為什麼作者不乾脆把整套 Fortran 程式重寫成 JAX?
重寫看似「一次到位」,但代價是必須重新驗證幾十年份的物理正確性——CFD、氣候、核能這些領域的程式,每一行背後可能都對應著一篇論文或一次昂貴的實驗校正。作者選擇「站在 LLVM 這一層動手」,本質上是工程取捨在多個都不完美的方案中,選一個在目前限制條件下最划算的方案,而不是等一個完美方案:犧牲『工具鏈的成熟穩定』,換來『不用重新驗證幾十年物理正確性』的風險降低。
🔭 為什麼 Enzyme 選擇在 LLVM 中間碼這一層做自動微分,而不是直接看 Fortran 或 C++ 原始碼?
如果自動微分工具要看懂每種語言的原始碼語法,等於要為 Fortran、C、C++ 各寫一套。選擇在 LLVM 中間碼(這些語言編譯到最後都會變成的共同格式)動手,一套邏輯就能通吃所有能編譯成 LLVM 的語言——這是典型的抽象層設計把差異先蒸發掉、找到大家共通的那一層下手,讓一份工具能服務多種情境。代價是除錯變難:出問題時得比對機器等級的中間碼差異,而不是熟悉的原始碼,這也是文章提到『要手動比對 LLVM IR 差異』的原因。
🔭 作者形容這整套東西『很實驗性』、要『準備好花時間追 NaN』,這種誠實揭露對你評估要不要採用一項新技術有什麼幫助?
工程決策不是「能不能動」,而是「在什麼條件下值得冒險」。作者自曝的踩坑成本,其實是幫你把技術成熟度一項技術從能在實驗室展示,到能穩定用在正式產品上,中間還要走多遠這個變數量化出來——如果專案時程緊、容錯低,這種還在啃邊緣案例的工具鏈可能還不是時候上;但如果是研究型、探索型的專案,願意花時間換取『不用重寫』的巨大彈性,就非常划算。

📝 隨堂考(點選答案,立即回饋)

Q1. 文章裡這套技術解決的核心問題是什麼?
✅ 重點不是效能,也不是換語言,而是讓老程式「產生梯度」,變成能被最佳化演算法使用的一塊積木。
Q2. 為什麼 Enzyme 要在 LLVM 中間碼這一層做自動微分,而不是各語言的原始碼?
✅ 選在共同的中間層下手,才不用為每種語言各寫一套自動微分工具。
Q3. 文章提到的「有限差分法」求梯度,主要缺點是什麼?
✅ 有限差分靠試誤逼近,計算次數隨參數量增加,而且步長選得不好精準度會很差。
Q4. 自動微分(AD)和有限差分最大的不同是?
✅ AD 是跟著程式邏輯精確算出來的,不像有限差分要抓一個步長去逼近,準不準看運氣。
Q5. 作者把算出梯度的 Fortran 程式包裝成什麼,才能接進 JAX?
✅ 透過 Tesseract 把它包成 JAX 看得懂的自訂元件,就能像原生 JAX 函式一樣被呼叫。

🃏 翻牌記憶卡(先想答案,再點開對答)

自動微分(AD)點我翻面
讓電腦在跑程式的同時,自動算出每個輸入對輸出的影響量,不用人工推導數學式,也不是用試誤法逼近。
LLVM 中間碼點我翻面
各種程式語言編譯到最後都會變成的共同「中間語言」,工具只要看懂這一層,就能同時支援 C、C++、Fortran 等多種語言。
Enzyme點我翻面
在 LLVM 中間碼這一層動手的自動微分工具,能幫任何能編譯成 LLVM 的程式碼生出精確梯度。
有限差分點我翻面
用「輸入改一點點、看輸出變多少」去逼近梯度的土法,計算量大、步長沒抓好還會不準。
反問題(Inverse Problem)點我翻面
已知結果,反推輸入條件該設多少才會得到這個結果——有了梯度才能有效率地解這類問題。

✅ 離開前自測(全勾=這課真的學會了)

0%