為 LLiMa 做出貢獻
LLiMa 包含一個主機端 GenAI 編譯器和一個用於 Modalix 的 C++ 執行階段。該執行階段透過封裝後的 CLI/HTTP/ZMQ 入口點進行操作;Python 是 CLI 編排工具,而不是一個獨立的公開執行階段 API。請將編譯器和執行階段環境及其依賴項分開。在程式碼庫的檢出過程中,CONTRIBUTING.md 提供快速入門指南,而 AGENTS.md 定義了特定代理程式的規則;本指南是詳細的貢獻者政策。
程式設計代理人的技能
將兩個 LLiMa 開發者技能作為標準開發者設定的一部分進行安裝。 它們不會被預設的 Neat SDK 腳本索引安裝,這是故意的:
sima-cli playbooks install \
gh:sima-neat/llima/skills/sima-contribute-to-llima
sima-cli playbooks install \
gh:sima-neat/llima/skills/sima-add-llima-model-support
一般貢獻 者技能涵蓋整個程式碼庫的編譯器、執行階段、封裝、測試、檔案和技能變更。模型支援技能新增了對 LLM 和 VLM 架構、檢查點、張量佈局、權杖化器和提示合約的相容性和實作流程。請確保同時安裝這兩者,以便在貢獻跨越這些界線時,提供適當的指導。
儲存庫地圖
| 區域 | 路徑 | 責任 |
|---|---|---|
| 設定 | sima_lmm/config/ | LLM、VLM 和 ASR 的設定合約。 |
| 攝取 | sima_lmm/hf/, sima_lmm/gguf/ | Hugging Face 和 GGUF 的載入和轉換。 |
| 編譯 | sima_lmm/model/, sima_lmm/preproc/ | 模型組件、量化、圖表和預處理。 |
| 主機工具 | sima_lmm/host/ | 編譯、部署、LoRA,以及進行基準測試,以評估程式的進入點。 |
| 評估 | sima_lmm/mole/ | MoLE 工作流程 |
| 執行階段 CLI | sima_lmm/devkit/ | Python CLI 流程協調與模型管理 |
| C++ 執行階段 | sima_lmm/devkit/cpp/ | 模型、權杖化器、MLA、CLI/HTTP/ZMQ 的實作,以及內部 CLI 繫結。 |
| 測試 | tests/ | 編譯器和 Modalix 執行階段測試 |
| 包裝 | CMakeLists.txt, cmake/, build*.sh, tools/install_*.sh | Debian、wheel 格式,以及成品組裝。 |
| 持續整合/快取 | .github/workflows/, tools/ci/, tools/hf-safetensors/ | 建立、測試和快取模型。 |
| 檔案/技能 | README.md, docs/, skills/ | 使用者、貢獻者和《Playbooks》指南 |
僅編譯時所需的相依性不應納入 sima_lmm/devkit/ 或 Modalix 執行階段套件。
開發環境
執行階段和封裝
請使用 Neat SDK 作為支援的建置環境。建置所有執行階段套件和封裝的測試:
./build.sh --all --clean
標準的建置程序會處理其所需的設定,包括子模組;請勿為標準工作流程執行單獨的依賴項啟動步驟。
有用的更精簡的建置程序:
./build.sh --clean --core
./build.sh --clean --core --dev
./build.sh --clean --cli
./build.sh --no-dist
輸出內容會在 build-deb/ 中產生,並在 dist/ 中進行分階段處理。Modalix 是執行 MLA 以及進行實際 llima run 驗證所必需的。
編譯器開發
請使用由 Model Compiler 安裝的 Python 3.12 環境。依序搜尋:
/sdk-extensions/model-compiler/sdk-add-on/model-compiler$HOME/sdk-extensions/model-compiler
source <model-compiler-venv>/bin/activate
python -m pip install -e '.[sdk_ext,tests]'
llima-compile --help
請勿建立另一個環境,以免遮蔽已安裝的編譯器套件。請使用以下方式建立發布設定檔:
./build_compiler_wheel.sh
./build_mole_package.sh
他們在 build/ 中使用輪式工具,並在 dist/compiler/ 和 dist/mole/ 中進行階段性輸出。
Whisper 和 ASR 的開發
公開的 llima-compile 工作流程涵蓋 LLM 模型和 VLM 模型。現有的 Whisper 編譯流程改用貢獻者工具:scripts/gen_models--openai--whisper.py。
python scripts/gen_models--openai--whisper.py \
--model_path /path/to/openai/whisper-small \
--output /path/to/whisper-output \
--part all
在 Model Compiler 環境中執 行,並明確指定模型路徑。
--part 接受 all、encoder、language_detect、init、single_pre、single_post,以及 single_cache。新增 --enable_log_probe 以編譯啟用日誌探測功能的解碼器輸出;使用 --part all --enable_log_probe 以進行完整的日誌探測建置。
Whisper 模型儲存庫中,每個編碼器層各有一個 ELF。執行階段不支援編碼器 ELF 為單一整體的舊版儲存庫;請下載分層模型,或使用目前的 LLiMa 版本重新編譯檢查點。
編譯器變更通常會影響 sima_lmm/config/whisper_config.py、sima_lmm/model/whisper_*.py 和腳本;執行階段變更會影響 sima_lmm/devkit/cpp/whisper_*。使用封裝的 C++ ASR 執行階段測試進行驗證,該測試的相關檔案位於 tests/README.md 中,並使用 Modalix 上的代表性音訊進行測試。這是一個 Whisper 專用的路徑,而不是一個通用的 ASR 架構框架。
原生圖元件
使用 sima_lmm/model/model_graph.py 中的 ModelGraph,一次綁定元件的來源權重、精度與輸出路徑。圖節點的建構放在類別內,獨立的陣列布局與命名工具則保留為模組函式。模型元件使用圖的方法,讓元件實作專注於拓撲:
from sima_lmm.model.model_graph import ModelGraph
def generate_graph(self, layer_cfg, quantizable):
graph = ModelGraph(self, {"hidden": (1, 1, self.num_tokens, self.cfg.d_model)}, quantizable)
hidden = graph.layer_norm("model.norm", graph.inputs["hidden"])
output = graph.mlp("model.mlp", hidden, "gelu", residual=graph.inputs["hidden"])
graph.save([output])
在 generate_graph() 中定義獨立元件的輸入、頂層拓撲與 graph.save()。對於共用的圖建構,例如 Whisper 整合解碼器圖使用的 pre/cache/post 部分,保留 _build_nodes(graph, inputs)。
日誌範圍由 BaseModel.gen_files() 設定,圖建構不需要額外的日誌引數。
形狀會推論輸入型別:quantizable=True 使用 FP32(稍後量化的浮點圖),False 使用 BF16(依來源權重精度直接建構的圖)。快取等整數輸入使用 input_dtypes={"cache": np.int8},名稱必須符合輸入規格。低階呼叫仍可使用現有的明確 AFE 張量規格。輸入與輸出順序遵循指定規格,形狀與輸出型別由 AFE 推論。constant() 將浮點資料轉為啟用值的精度;若整數常數需要特定位元寬度,例如使用 dtype=np.int32。節點名稱遵循 AFE 可確定的建立計數器。
圖節點的型別註記從 model_graph.py 匯入 Node。輔助函式接收圖,而非額外的 quantizable 旗標。graph.constant() 自動選擇浮點精度;主機端陣列計算需要該精度時,使用 NumPy 的 graph.dtype。階段旗標只保留在 generate_graph() 與圖建構處。
save() 完成 MLA 子網路並建立外層圖的輸出 tuple,保留整數輸出,在 EV 上將 BF16 輸出轉為 FP32,並使用標準成品名稱寫入檔案(浮點圖使用 .fp32)。若要取得完成的網路,使用 finish()。兩者都接受 transform_subnet,可在擷取外層輸出前進行模型專屬改寫。將圖本身傳給元件輔助函式,輸入、精度與來源權重仍綁定於同一物件。
以具名的 NumPy 輸入執行已完成的圖:
graph.finish([output])
outputs = graph.run(hidden=x)
outputs_jax = graph.run(hidden=x, use_jax=True)
graph.save()
輸入名稱、形狀與資料型別必須符合宣告的輸入,不會套用隱含型別轉換。輸出遵循傳給 finish() 的順序。NumPy 執行使用 AFE fast mode,結果可能與 MLA 參考運算不同。use_jax=True 選擇 JAX 參考執行,此時 fast mode 沒有作用。JAX 運算使用所設定的後端,並可在相容的 JAX 安裝環境中使用 GPU。此 API 不會量化、編譯或在 Modalix 上執行。只完成圖一次,之後重複使用 run() 與 save();仍可用 save(outputs) 一次完成並儲存圖。
常用操作包含 add, sub, mul, matmul, concat, slice, transpose, reshape, softmax, topk, sum_channels, argmax, linear, conv, layer_norm, rms_norm, activation, softcap, mlp, rope, rope2d, split_heads, merge_heads, split_concat, clip, avgpool2d, space_to_depth, quant, dequant。閘控 MLP 使用 projections=("gate_proj", "up_proj", "down_proj"),預設為 ("fc1", "fc2")。rms_norm("model.norm", input) 使用語言模型設定的 epsilon 與權重偏移。vision 和 GDN 的正規化若明確指定 epsilon,除非也提供 weight_offset,否則權重偏移維持零。rms_norm(None, input, epsilon=...) 推論無權重的通道。RoPE 支援完整、部分與按比例的 split-half 旋轉。rope2d(input, cos_x, sin_x, cos_y, sin_y) 依 [x-real, x-imag, y-real, y-imag] 順序旋轉四等分的通道。split_heads(input, heads, repeat=...) 為 grouped-query 模式重複各個 head。split_concat() 提供 AFE 的重新分組操作,處理僅靠 reshape 無法表達的空間/權杖布局。space_to_depth(input, blocksize) 將完整的空間區塊合併至通道。quant(input) 回傳 (int8_values, scale);dequant(int8_values, scale) 還原圖的啟用值精度。argmax(input) 回傳 INT32 通道索引。slice(input, begin, end, stride, axis) 對四維 FP32/BF16 張量中未對齊、連續的單軸通道切片,自動使用選擇器卷積;其他切片維持 AFE 的原生行為。
linear("model.proj", input) 解析 model.proj.weight 與可選的偏置,將 OI 來源權重轉為 SiMa 布局,並保留封裝的權重值、縮放係數、未對齊的群組大小與重定位中繼資料。conv() 推論 OIW 或 OIHW 來源布局;明確的轉換也能處理其他布局,例如 Qwen 的五維 patch 權重。WeightOptions 說明來源名稱、布局、權重/縮放係數/偏置轉換與重定位覆寫選項。 切片群組權重時,提供對應的 scale_process_func;群組必須保留檢查點的實際大小。LoRA 秩與合併 adapter 行為是 linear() 和 mlp() 的明確引數。
以投影與 head 布局操作建構 attention。將 query 縮放併入 linear(),以保留現有投影的捨入行為:
queries = graph.split_heads(graph.linear("attn.q_proj", hidden, scale=head_dim ** -0.5), heads)
keys = graph.split_heads(graph.linear("attn.k_proj", hidden), heads)
values = graph.split_heads(graph.linear("attn.v_proj", hidden), heads)
context = graph.attention(queries, keys, values)
output = graph.linear("attn.out_proj", graph.merge_heads(context))
split_heads() 透過選擇器卷積處理未對齊的 head 通道。標準 vision attention 會填補未對齊 head 的投影權重,以避免這些卷積;群組輸出權重保留原始布局。attention() 依 query/key 長度,為包含 cross-attention 的大型 attention 張量選擇各 head 的獨立分支。它接受加法 mask,且除非提供 score_scale,否則假設 query 已縮放。該縮放在 Q×K 之後、遮罩之前套用,保留 Qwen vision 等模型的 BF16 運算順序。遮罩必須是四維張量、向量或純量,且可廣播至 [N,H,T_query,T_key];不支援的形狀會引發 ValueError。
graph.matmul(lhs, rhs) 建立 MLA 批次矩陣乘法。兩個轉置旗標都預設為 False;Kᵀ×V 使用 transpose_a=True,Q×Kᵀ 使用 transpose_b=True。輸入必須是四維 FP32/BF16 張量,且批次與縮約維度相符。head 數可整除時,grouped-query attention 使用隱含重複;無效的形狀或型別會引發 ValueError。
graph.softmax(x) 預設使用最後一個軸,也支援明確的 axis。連續單軸切片使用 graph.slice(x, start=0, stop=128, axis=-1);多軸切片使用現有的 begin/end/stride/axis 列表。單軸形式的起點預設為零,必須明確指定軸與範圍內的非空邊界,並保留未對齊通道的處理。請勿混用兩種形式。
ModelGraph 擴充 AFE 的 SimaBuilder,因此可在同一物件使用原生操作與共用輔助函式:
projected = graph.linear("model.proj", graph.inputs["hidden"])
output = graph.add(projected, graph.inputs["hidden"])
graph.save([output])
簡潔的基礎操作是 AFE 方法的直接別名,保留其簽章、型別推論與可確定的命名。較少使用的操作仍可透過同一個圖繼承的 create_* 方法取得。需要自訂多子網路生命週期的圖,仍可直接使用 AFE 的 SimaBuilder 與低階操作輔助函式。
細分布局集中由 sima_analysis.get_tessellate_parameters() 推論:HWC16 布局、自動 tile 大小與可確定的持久緩衝區名稱。一般元件從 BaseModel 繼承空的覆寫設定。具步幅的 KV 快取等特殊布局,覆寫現有的 get_mla_input_tessellate_params() / get_mla_output_tessellate_params() 方法;鍵是張量索引,負索引從尾端計算。
Whisper 元件、所有原生語言圖部分與標準 vision tower 都使用此 API;其 attention、MLP 與旋轉輔助函式共用相同實作。
DFlash 的上下文融合、K/V 投影與狀態解析器元件也使用 generate_graph() 和 ModelGraph。最終的草稿圖保留配對目標模型的已打包輸出頭權重與尺度;驗證圖則保留執行階段狀態解析器所需的 S1 與已求解中間結果輸出。