Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

UB in to_float callback for I2_S (missing scale param) + 3 more bugs on ARM Ampere Altra

オープン
#468 コメント 2 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
20/100
issue の種類
バグ
明瞭さ
説明が足りない
活発さ
停滞
技術スタック
cmake, cpp

調査の方向性

まず、issue に記載されているコマンドと build flags を使って ARM の結果を再現し、その後 3rdparty/llama.cpp/ggml/src/ggml.c、CMakeLists.txt、ggml-bitnet-mad.cpp の ARM パスを調べます。I2_S callback と dotprod configuration を含めて、-b 1 の gemv パスと -b 32 の gemm パスを比較します。残っている ARM の正確性の問題を特定して修正し、一貫した出力を確認できれば完了です。

索引モデルが issue の本文から書いたものです。

説明

Environment

  • Platform: Oracle Cloud Compute A1 Flex (Ampere Altra, armv8.2-a, asimddp present in /proc/cpuinfo)
  • OS: Ubuntu 22.04 LTS
  • Compiler: clang 14.0
  • Commit: main branch, March 2026
  • Build flags:
    -DBITNET_ARM_TL1=ON
    -DCMAKE_C_COMPILER=clang
    -DCMAKE_CXX_COMPILER=clang++
    -DCMAKE_C_FLAGS="-march=armv8.2-a+fp16+dotprod"
    
  • Model: microsoft/BitNet-b1.58-2B-4T-gguf (ggml-model-i2_s.gguf, 1.2GB)
  • Python: 3.12 (venv)

System info (from llama-cli output)

NEON = 1 | ARM_FMA = 1 | SVE = 0 | MATMUL_INT8 = 0 | (all x86 = 0)

Problem

With -b 1 (gemv path): model produces real words but completely incoherent output.
With -b 32+ (gemm path for prompt): model produces GGGG garbage for all generated tokens.

# gemv path (-b 1, default in run_inference.py)
$ python run_inference.py -m models/BitNet-b1.58-2B-4T-gguf/ggml-model-i2_s.gguf \
    -p "The capital of France is" -n 30 -t 4

The capital of France is offline officially.ai happy collective lower sl ruled m unit proven-for...

# gemm path (-b 32)
$ ./build/bin/llama-cli -m models/BitNet-b1.58-2B-4T-gguf/ggml-model-i2_s.gguf \
    -p "Hello, my name is" -n 50 -t 4 -b 32

Hello, my name isGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG

Speed is correct (~18 tok/s on 4 ARM cores), model loads without errors.


Bug 1: to_float callback — type mismatch (confirmed, patched)

In 3rdparty/llama.cpp/ggml/src/ggml.c, the type table for GGML_TYPE_I2_S registers dequantize_row_i2_s as a ggml_to_float_t callback, but the signatures do not match:

// Typedef (3 params):
typedef void (*ggml_to_float_t)(const void * x, float * y, int64_t n);

// Actual function (4 params — 4th is the i2 scale):
void dequantize_row_i2_s(const uint8_t * x, float * y, int64_t n, const float i2_scale);

// Bug in type table (ggml.c ~line 1185):
.to_float = (ggml_to_float_t) dequantize_row_i2_s,  // scale never passed → UB

The cast silences the compiler but causes undefined behavior — on ARM, the 4th argument register is garbage → i2_scale is random → dequantized weights are garbage.

Applied fix — wrapper in the same translation unit:

// At top of ggml.c:
static void dequantize_row_i2_s_wrapper(const void * vx, float * y, int64_t n) {
    const uint8_t * x = (const uint8_t *) vx;
    const float i2_scale = ((const float *)(x + (n / 4)))[0];
    dequantize_row_i2_s(x, y, n, i2_scale);
}

// In type table:
.to_float = dequantize_row_i2_s_wrapper,

Effect: without this fix → GGGG for all configs. With fix → real words with -b 1 (but still incoherent, see Bug 3).


Bug 2: +dotprod not enabled in CMakeLists for ARM (build issue)

The build system generates -march=armv8.2-a without +dotprod. On ARM Ampere Altra:

  • CPU has asimddp (dotprod SDOT/UDOT) in /proc/cpuinfo
  • Without +dotprod, __ARM_FEATURE_DOTPROD is not defined by clang
  • ggml-bitnet-mad.cpp falls to the #else path using vmlal_s8 (int16 accumulator)
  • For vectors of 2560+ elements, int16 accumulator overflows → incorrect results (related to #411)

Verification:

clang -march=armv8.2-a+fp16+dotprod -dM -E - < /dev/null | grep DOTPROD
# → #define __ARM_FEATURE_DOTPROD 1

clang -march=armv8.2-a+fp16 -dM -E - < /dev/null | grep DOTPROD
# → (nothing)

Suggested fix: add +dotprod to CMakeLists.txt for AArch64 targets when CPU supports it, or document it as a required flag.


Bug 3: gemm path (ne11 > 3) produces GGGG on ARM — root cause unknown

When the batch has more than 3 tokens (prompt evaluation with -b 32), the code takes the ggml_gemm_i2_i8_s path instead of ggml_gemv_i2_i8_s. On ARM, this path produces completely wrong output:

# Relevant code path in ggml.c (~line 13268):
if (gemm && (ne11 > 3)) {
    if (src0->type == GGML_TYPE_I2_S) {
        // gemm path — produces GGGG on ARM
        const float * scale = (float *)((uint8_t*)(src0->data) + (ne00 * ne01 / 4));
        gemm(...);
        for (...) {
            tmp[...] = (tmp[...] - act_sums[col]) / (act_scales[col]) * (*scale);
        }
    }
}

Since prompt tokens are processed via gemm and corrupt the KV cache, all subsequent generated tokens are also garbage.

Workaround: use -b 1 to force all computation through the gemv path (avoids the bug but is slower and still produces incoherent text).


Bug 4: incoherent output even with gemv path (remaining issue)

Even with -b 1 + Bug 1 fix + dotprod enabled, output is semantically incoherent. The model generates real vocabulary tokens but with no semantic coherence:

"The capital of France is offline officially.ai happy collective..."
"Hello, my name is Freedom reduce Dispatch linear Dahl tent corps..."

This persists even with temperature=0 (greedy decoding), suggesting the issue is in the logit distribution rather than sampling. Possible causes:

  • act_sums (activation zero-point correction) computed incorrectly for ARM
  • Scale offset wrong for GQA tensors (K/V: [2560, 640] with 5 KV heads vs Q: [2560, 2560])
  • Activation quantization (quantize_row_i8_s) producing incorrect scale values

Steps to reproduce

# 1. Clone and build (Ubuntu 22.04, ARM Ampere)
git clone https://github.com/microsoft/BitNet.git && cd BitNet
git submodule update --init --depth=1
python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt

# 2. Build (add +dotprod — not in default CMakeLists)
cmake -S . -B build \
  -DBITNET_ARM_TL1=ON \
  -DCMAKE_C_COMPILER=clang \
  -DCMAKE_CXX_COMPILER=clang++ \
  -DCMAKE_C_FLAGS="-march=armv8.2-a+fp16+dotprod" \
  -DCMAKE_CXX_FLAGS="-march=armv8.2-a+fp16+dotprod" \
  -DCMAKE_BUILD_TYPE=Release
make -C build -j4

# 3. Download model
huggingface-cli download microsoft/BitNet-b1.58-2B-4T-gguf \
  --local-dir models/BitNet-b1.58-2B-4T-gguf

# 4. Test (without Bug 1 fix — GGGG for all batch sizes)
python run_inference.py -m models/BitNet-b1.58-2B-4T-gguf/ggml-model-i2_s.gguf \
  -p "The capital of France is" -n 30

# 5. Apply Bug 1 fix to 3rdparty/llama.cpp/ggml/src/ggml.c (see above)
# Rebuild and test — now produces words with -b 1 but still incoherent

Related issues

  • #411 — int16 overflow in NEON 1x1 kernel (same root area, different manifestation)
  • #195 — ARM inference issues (similar platform)

Hardware confirmation

Tested exclusively on Oracle Cloud Compute A1 Flex (ARM Ampere Altra).
Reports from Reddit/r/LocalLLaMA indicate M1/M2/M3 Mac users achieve coherent output — suggesting the issue may be ARM Ampere-specific or related to the dotprod/vmlal path difference.

主要言語
C++
スター
40.3k
フォーク
3.7k
PR マージ指標
30日以内にマージされた PR はありません

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

microsoft/BitNet のほかの issue

microsoft/BitNet の issue をすべて見る

似ている issue

C++ の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。