Skip to content

[EXPERIMENT][WIP][OpenVINO] Add support for Cohere2 MoE (cohere2_moe)#1806

Draft
mlukasze wants to merge 3 commits into
huggingface:mainfrom
mlukasze:enable/CohereLabs-North-Mini-Code-1.0
Draft

[EXPERIMENT][WIP][OpenVINO] Add support for Cohere2 MoE (cohere2_moe)#1806
mlukasze wants to merge 3 commits into
huggingface:mainfrom
mlukasze:enable/CohereLabs-North-Mini-Code-1.0

Conversation

@mlukasze

Copy link
Copy Markdown
Contributor

⚠️ AUTOMATICALLY GENERATED BY OMEGA AGENT — REQUIRES HUMAN REVIEW ⚠️
This PR was created by an AI agent as part of automated model enablement.
A human maintainer must review and approve it before it can be considered for merge.
Do NOT merge without human review and sign-off.

What does this PR do?

Add OpenVINO export support for the Cohere2 MoE architecture (model_type cohere2_moe, Cohere2MoeForCausalLM; e.g. CohereLabs/North-Mini-Code-1.0 — 30B total / 3B active, 128 experts / 8 active, sigmoid router, hybrid sliding-window+RoPE / global-NoPE attention, Cohere2 parallel block).

Changes (minimal, scoped to cohere2_moe):

  • Cohere2MoeOpenVINOConfig(Cohere2OpenVINOConfig) registered for cohere2_moe (text-generation[-with-past]).
  • Cohere2MoePatcher: replaces the untraceable Cohere2MoeExperts.forward (fused gate_up_proj, per-hit-expert loop) with the existing vectorized lfm2_moe_experts_forward (torch.bmm, chunk(2, dim=-2)), mirroring the Qwen3.5-MoE approach (PR [OpenVINO] Support Qwen3.5, Qwen3.5-MoE and Qwen3.6 #1689/[OpenVINO] Use performant 3GEMM MoE for Qwen3.5 #1728). Patcher numerically verified vs the original forward (max-abs diff ~3e-7 in fp32).
  • Default weight-compression config keeping embed_tokens/lm_head (tied) and per-layer MoE routers out of compression via ignored_scope — required for accuracy on this sparse-MoE model.
  • Tiny random cohere2_moe added to the OpenVINO test suite.

Validation: tiny-model greedy export matches PyTorch 25/25 tokens. Full model WWB text-similarity vs PyTorch baseline (CPU, greedy, 8 samples): INT8 = 0.925 (PASS, ≥0.9).

Known limitations (flagged for human review, NOT addressed here):

  • INT4 weight-only PTQ has a proven accuracy ceiling (~0.78) on this model (swept group_size/ratio/AWQ/scale-estimation) — INT8 is the recommended precision.
  • OpenVINO GPU: the compressed-MoE op MOECompressed is not fused on the GPU plugin for cohere2_moe routing (FuseMOE3GemmCompressed only matches activation-before-topk + normalized routers; cohere2_moe applies sigmoid after top-k with no normalization). GPU inference therefore fails (MOECompressed reached the GPU backend without being fused). Additionally INT8 (29GB) exceeds available dGPU VRAM (22.7GB). Recommended owner: OpenVINO GPU plugin / MoE team. CPU INT8 is the supported path.

Installation instructions

pip install "git+https://github.com/huggingface/optimum-intel.git@main#egg=optimum-intel[openvino]"
# transformers from main is required for cohere2_moe (PR #46115):
pip install "git+https://github.com/huggingface/transformers.git"

Exporting cmd-line

# INT8 is the recommended/validated precision (CPU). The per-model default config
# automatically keeps embeddings/lm_head + MoE routers uncompressed for accuracy.
optimum-cli export openvino -m CohereLabs/North-Mini-Code-1.0 --weight-format int8 --task text-generation-with-past ./North-Mini-Code-1.0-ov-int8

Inference script

import openvino_genai as ov_genai

pipe = ov_genai.LLMPipeline("./North-Mini-Code-1.0-ov-int8", "CPU")
config = ov_genai.GenerationConfig()
config.max_new_tokens = 128
config.apply_chat_template = False  # Cohere Jinja template uses constructs unsupported by GenAI Minja
print(pipe.generate("def fibonacci(n):\n    ", config))

Before submitting

  • This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
  • Did you make sure to update the documentation with your changes?
  • Did you write any new necessary tests?

omega-intel and others added 3 commits June 20, 2026 23:39
- Add Cohere2MoePatcher(OVDecoderModelPatcher) that replaces
  Cohere2MoeExperts.forward with the vectorized lfm2_moe_experts_forward
  (bmm over fused gate_up_proj [E,2I,H] via chunk(2,dim=-2)) to make
  the MoE expert dispatch traceable for OpenVINO export.
- Add Cohere2MoeOpenVINOConfig(Cohere2OpenVINOConfig) registered for
  model_type cohere2_moe (text-generation, text-generation-with-past).
- MIN_TRANSFORMERS_VERSION = 5.8.0 (requires transformers PR #46115).
- Add tiny cohere2_moe entry to test MODEL_NAMES, EXPECTED_NUM_SDPA,
  and decoder SUPPORTED_ARCHITECTURES (gated on transformers >= 5.8.0).

Enables CohereLabs/North-Mini-Code-1.0 (30B total / 3B active MoE,
49 layers, 128 experts/8 active, sigmoid router, hybrid 3:1
sliding-window+RoPE / global NoPE attention) for OpenVINO export and
inference at FP16/INT8/INT4 precisions.

Architecture: MoE uses fused gate_up_proj identical to lfm2_moe layout;
Cohere2MoeExperts inherits MixtralExperts - same lfm2_moe_experts_forward
vectorized BMM form applies. Hybrid attention already trace-friendly.

Validated: tiny model export + 20 decode steps, greedy match vs PyTorch
25/25 tokens (100%). Full 30B INT4 export ok, 19/20 tokens match (95%).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…figs

The cohere2_moe export graph is numerically exact (MoE patcher max-abs
3e-7; reduced-FP16 prefill max-abs 4.9e-5 with 12/12 greedy-decode match),
but INT4/INT8 WWB similarity fell below the 0.9 gate (0.752/0.796).

Root cause is weight-quantization sensitivity of this sparse MoE: the tied
embed_tokens/lm_head and the per-layer top-8 sigmoid routers, once
weight-compressed, perturb token logits enough that greedy decoding
diverges (per-step teacher-forced top-1 agreement is still 0.938, KL 0.012;
the loss is greedy compounding, not the graph).

Fix: add default quantization configs for CohereLabs/North-Mini-Code-1.0
that keep embed_tokens/lm_head and the mlp.gate routers out of weight
compression via ignored_scope. INT8 then reaches WWB 0.925 (>= 0.9).

INT4 weight-only PTQ cannot meet the gate for this model (ceiling ~0.78
across group_size 32/64, ratio 0.2-1.0, AWQ and scale_estimation; the score
is bimodal in the int4 fraction - any nonzero int4 expert fraction collapses
greedy similarity, only full int8 recovers). The INT4 default encodes the
best achievable protected recipe; INT8 is recommended for this model.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ormatting

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants