工程趣聞 2026 年 8 月 4 日

2026-08-04 — AirLLM 用分層卸載跑 70B 模型、Rust 提案 Move/Forget trait、拿掉一個 if 讓 filter 快 4 倍

primary=https://github.com/lyogavin/airllm primary=https://github.com/rust-lang/rust-project-goals/blob/main/src/2026/move-trait.md primary=https://www.greyblake.com/blog/branchless-rust/

單張 4GB 顯卡如何推論 700 億參數模型:AirLLM 的分層卸載技術

GitHub / Hacker News · 2026-08-04

AirLLM 是一個開源 Python 函式庫,讓開發者能在僅有 4GB 顯示記憶體的消費級 GPU 上執行 Llama 3.1 70B、甚至規模更大模型的推論。專案在 2026 年 6 月釋出 v3.0,加入 FP8 支援與 DeepSeek-V3、Qwen3 相容性,是這波 Hacker News 討論的直接起因。核心手法不是把模型壓縮到更小,而是把模型「拆成一層一層來跑」。

核心技術

AirLLM 採用的做法是逐層串流權重(layer-by-layer weight streaming):推論時一次只把一個 transformer layer 的權重載入 GPU,算完立刻換下一層,GPU 上永遠只需要容納單一層的參數,而不是整個模型。這代表顯存需求只跟「單層大小」有關,而非模型總參數量。官方 README 給出的對照數字如下表。支援的模型清單涵蓋 Llama(2/3/3.1/3.3/4)Qwen(1/2/2.5/3)DeepSeek(V2/V3/R1)、Mistral、Mixtral、Phi、Gemma、ChatGLM、Baichuan、InternLM 等,透過標準的 AutoModel.from_pretrained() 介面呼叫。

模型參數量所需顯存
Llama 3.1 405B405B約 8 GB
DeepSeek-V3671B約 12 GB
Qwen3-235B235B約 3 GB
Kimi K32.8T低於 4 GB

硬體與量化

AirLLM 支援的最低硬體門檻是 1-2GB VRAM 的消費級顯卡,同時也支援 macOS Apple Silicon 與純 CPU 推論。專案另外提供 4-bit / 8-bit 模型壓縮選項,官方數據宣稱量化可為推論延遲帶來 3x 的提升。也就是說,分層卸載與量化是兩個可疊加的獨立手段——卸載解決「放得下」的問題,量化解決「跑多快」的問題。

實際限制

README 沒有提供具體的 tokens/sec 或延遲數字,只強調「瓶頸主要在硬碟讀取(disk loading)」。這句話等於承認了逐層卸載的代價:每換一層都要即時從硬碟把權重讀進 GPU,這段 I/O 等待時間取代了原本一次性把整個模型塞進顯存的耗時。換句話說,AirLLM 是用時間換取空間——犧牲吞吐量與延遲,換取讓超大模型能在小顯存裝置上「跑得起來」而非完全跑不動。專案在 2026 年 6 月的 v3.0 更新加入 FP8 精度與新模型支援,顯示這個專案目前仍在持續維護。

原始來源:lyogavin/airllm — GitHub README


Rust 提案新增 Move/Forget trait:把「不可移動」與「保證解構」寫進型別系統

Rust Project Goals / Hacker News · 2026-08-04

Rust 語言團隊在 rust-project-goals 儲存庫的 2026 目標文件中,提出為 2026-2027 週期新增兩個 auto trait——MoveForget——目標是讓編譯器能表達「這個型別不能被移動」與「這個型別的解構子一定要執行」。這份目標由 @lcnr(型別系統)與 @jackh726(語言組)共同擔任 champion,目前狀態為 Accepted for 2026-2027。

問題所在

Rust 現行的假設是:所有型別都可以被移動,也可以被 mem::forget 安全地丟棄而不執行解構子。這個假設造成兩個具體麻煩。第一是自我參照(self-referential)型別,一旦這類型別的記憶體位置被移動,內部指標就會失效,但 Rust 型別系統目前沒辦法把「不可移動」表示成型別本身的屬性,只能靠 Pin 把不可移動性掛在「記憶體位置」而非「型別」上,增加了大量使用複雜度。第二是保證解構的需求,例如交易(transaction)控制代碼這類必須執行 commit 或 rollback 的型別,因為 mem::forget 在安全 Rust 中永遠合法,沒辦法保證解構子一定會被呼叫,這也連帶擋住了 async 情境下「安全的 scoped spawn」這類模式。

提案機制

文件提出的兩個新 auto trait,延續了 Sized 系列 trait 的做法——用「選擇退出(opt-out)」取代「全域假設」。Move trait 的語意是:實作 !Move 的型別不能被移動,且必須在整個生命週期中保持穩定位址。對應的 Forget trait 則規定:實作 !Forget 的型別必須讓其解構子執行。文件給出的 lang-item 定義如下:

#[lang = "move"]
unsafe auto trait Move {}

這種做法把「能不能移動」從 Pin 那種放置(place)層級的技巧,提升成型別本身可以宣告的屬性,理論上能簡化目前圍繞 Pin 打轉的 self-referential 型別與 async 生態系複雜度。追蹤進度可見 rust-project-goals 的 issue #635,以及 rust-lang/rust 主倉庫的 issue #149607

原始來源:rust-lang/rust-project-goals — move-trait.md


拿掉一個 if,Rust 的 filter 效能提升近 4 倍

Lobsters · 2026-08-03

greyblake.com 部落格作者在 2026-08-03 發布的技術文章中,拆解了一個常見場景——依照閾值過濾一組 f64 陣列——並示範拿掉其中的 if 分支後,最差情況下效能提升了將近 4 倍。文章的重點不是什麼神奇函式庫,而是分支預測失敗(branch misprediction)在資料無法預測時的實際代價

原本的實作

最直覺的寫法是用 iterator 搭配 filter

pub fn filter_iter(input: &[f64], threshold: f64) -> Vec {
    input.iter().copied().filter(|&x| x > threshold).collect()
}

這段程式碼編譯後會產生一個條件分支——每比對一個元素,CPU 都要「猜」這個元素會不會通過 x > threshold當篩選比例接近 50%(也就是資料完全不可預測)時,CPU 的分支預測器幾乎跟丟硬幣一樣沒把握,大量的分支預測失敗會直接拖慢管線(pipeline)執行。

去分支後的作法

作者改寫成一個「永遠寫入、只是不一定前進指標」的版本:

pub fn filter_branchless(input: &[f64], threshold: f64) -> Vec {
    let mut out = vec![0.0; input.len()];
    let mut n = 0;
    for &x in input {
        out[n] = x;
        n += (x > threshold) as usize;
    }
    out.truncate(n);
    out
}

關鍵在 n += (x > threshold) as usize 這一行——把布林比較結果直接轉成 0 或 1,用算術加法取代 if 判斷式來決定要不要前進寫入位置。不管 x 有沒有通過門檻,out[n] = x 都會被執行,只是沒通過的值之後會被下一次寫入蓋掉。這樣 CPU 完全不需要猜測,也就沒有分支預測失敗的代價。

效能數據

作者針對「50% 選擇率」這個最差情況做基準測試,結果如下:

版本50% 選擇率耗時
filter_iter(含分支)3.94 ms
filter_branchless(去分支)1.03 ms

去分支版本在最差情況下速度提升了將近 4 倍,文章也特別指出,去分支後的效能「變得與資料本身無關(independent of the data)」——不論篩選比例是多少,耗時都差不多,不會再被分支預測命中率牽著走。

原始來源:greyblake.com — Branchless Rust


End of article
0
Would love your thoughts, please comment.x
()
x