Bugfix (#24027)
This commit is contained in:
@@ -0,0 +1,398 @@
|
|||||||
|
---
|
||||||
|
title: Mistral Medium 3.5
|
||||||
|
metatags:
|
||||||
|
description: "Deploy Mistral Medium 3.5 with SGLang - 128B dense flagship merged model with hybrid reasoning, 256K context, vision input, and FP8 quantization."
|
||||||
|
---
|
||||||
|
|
||||||
|
import { MistralMedium35Deployment } from '/src/snippets/autoregressive/mistral-medium-3-5-deployment.jsx';
|
||||||
|
|
||||||
|
## 1. Model Introduction
|
||||||
|
|
||||||
|
**Mistral Medium 3.5** is Mistral AI's first flagship **merged model** — a single dense 128B checkpoint that handles instruction following, reasoning, and coding in one set of weights. It replaces Mistral Medium 3.1 and Magistral in Le Chat, and replaces Devstral 2 in the Vibe coding agent. Reasoning effort is configurable per request, so the same model can answer a quick chat reply or work through a deep agentic run. The vision encoder was trained from scratch to handle variable image sizes and aspect ratios.
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
|
||||||
|
- **Dense 128B parameters** — no MoE, no MLA, plain GQA (96 heads, 8 KV heads, head_dim=128)
|
||||||
|
- **256K context window** — YARN RoPE scaling on top of the original 4K base
|
||||||
|
- **Hybrid Reasoning**: Toggle between instant reply and deep reasoning per request via `reasoning_effort` (`"none"` or `"high"`)
|
||||||
|
- **Vision**: Accepts text + image input; from-scratch encoder that handles variable image sizes/aspect ratios
|
||||||
|
- **Function Calling**: Native tool calling and JSON output
|
||||||
|
- **FP8 Native**: Released with FP8 e4m3 static-tensor quantization built in
|
||||||
|
- **Multilingual**: 24 supported languages including English, French, German, Spanish, Portuguese, Italian, Japanese, Korean, Russian, Chinese, Arabic, Persian, Indonesian, Malay, Nepali, Polish, Romanian, Serbian, Swedish, Turkish, Ukrainian, Vietnamese, Hindi, and Bengali
|
||||||
|
- **License**: Modified MIT (open for commercial and non-commercial use except for companies with large revenue)
|
||||||
|
|
||||||
|
**Architecture:**
|
||||||
|
|
||||||
|
- Mistral 3 backbone with YARN RoPE for 256K context
|
||||||
|
- Dense (no MoE), 128B parameters
|
||||||
|
- Standard GQA attention (not MLA)
|
||||||
|
- Pixtral-style vision encoder (48 layers, patch_size=14, spatial_merge=2, image_size=1540) trained from scratch
|
||||||
|
- Multimodal input: text + image
|
||||||
|
|
||||||
|
**Models:**
|
||||||
|
|
||||||
|
- **[mistralai/Mistral-Medium-3.5-128B](https://huggingface.co/mistralai/Mistral-Medium-3.5-128B)** (FP8)
|
||||||
|
|
||||||
|
The HuggingFace repo ships both the mistral native layout (`params.json` + `consolidated-*.safetensors`) and the HF layout (`config.json` + `model-*.safetensors`). SGLang auto-detects the format — the HF layout is preferred when both are present.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. SGLang Installation
|
||||||
|
|
||||||
|
SGLang offers multiple installation methods. You can choose the most suitable installation method based on your hardware platform and requirements.
|
||||||
|
|
||||||
|
Please refer to the [official SGLang installation guide](../../../docs/get-started/install) for installation instructions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Model Deployment
|
||||||
|
|
||||||
|
### 3.1 Basic Configuration
|
||||||
|
|
||||||
|
**Interactive Command Generator**: Use the configuration selector below to generate a launch command for Mistral Medium 3.5.
|
||||||
|
|
||||||
|
<MistralMedium35Deployment />
|
||||||
|
|
||||||
|
### 3.2 Configuration Tips
|
||||||
|
|
||||||
|
- **Tensor Parallelism**: Mistral Medium 3.5 FP8 (~130 GB) requires `--tp 4` on Hopper (H100/H200) and `--tp 2` on Blackwell (B200/B300).
|
||||||
|
- **Reasoning effort**: Reasoning depth is configurable per request via `reasoning_effort` (`"none"`, `"high"`). No restart required — toggle per call.
|
||||||
|
- **Recommended temperature**: `0.7` when `reasoning_effort="high"`. Anywhere from `0.0` to `0.7` when `reasoning_effort="none"`, depending on the task — lower for to-the-point answers, higher for creative output.
|
||||||
|
- **Context length vs memory**: The model has a 256K context window. If you are memory-constrained, lower `--context-length` (e.g. `32768`) and increase once things are stable.
|
||||||
|
- **Tool calling**: Enable `--tool-call-parser mistral` to activate native function calling support.
|
||||||
|
- **Reasoning parser**: Enable `--reasoning-parser mistral` to separate `reasoning_content` from the main response content.
|
||||||
|
- **System prompt**: The model ships with a recommended system prompt in `chat_template.jinja` and `SYSTEM_PROMPT.txt`. If you do not pass a system message yourself, the chat template injects Mistral's default (model identity, current date, tool-use guidelines). For full fidelity with Mistral's reference setup, load `SYSTEM_PROMPT.txt` from the HF repo and substitute `{name}`, `{today}`, `{yesterday}` (see Section 4.6).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Model Invocation
|
||||||
|
|
||||||
|
### 4.1 Thinking Mode
|
||||||
|
|
||||||
|
Mistral Medium 3.5 is a hybrid reasoning model. By default it does not produce a reasoning trace — pass `reasoning_effort="high"` to switch on the deep-reasoning path. Mistral recommends `temperature=0.7` for reasoning mode.
|
||||||
|
|
||||||
|
```python Example
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
client = OpenAI(
|
||||||
|
base_url="http://localhost:30000/v1",
|
||||||
|
api_key="EMPTY",
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model="mistralai/Mistral-Medium-3.5-128B",
|
||||||
|
messages=[
|
||||||
|
{"role": "user", "content": "Solve step by step: what is 17 × 23 + 144 / 12?"},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
extra_body={"reasoning_effort": "high"},
|
||||||
|
)
|
||||||
|
|
||||||
|
print("Reasoning:", response.choices[0].message.reasoning_content)
|
||||||
|
print("Answer:", response.choices[0].message.content)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
|
||||||
|
```text Output
|
||||||
|
Reasoning: I need to follow the order of operations (PEMDAS/BODMAS): multiplication and
|
||||||
|
division before addition, evaluated left to right.
|
||||||
|
|
||||||
|
17 × 23: I'll break it as 17 × (20 + 3) = 340 + 51 = 391.
|
||||||
|
144 / 12 = 12.
|
||||||
|
Finally, 391 + 12 = 403.
|
||||||
|
|
||||||
|
Answer: **17 × 23 + 144 / 12 = 403**
|
||||||
|
|
||||||
|
Step by step:
|
||||||
|
1. 17 × 23 = 391
|
||||||
|
2. 144 / 12 = 12
|
||||||
|
3. 391 + 12 = 403
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Instruct Mode (Reasoning Off)
|
||||||
|
|
||||||
|
To skip the reasoning trace and get a fast direct response, set `reasoning_effort="none"`. For instruct mode, Mistral recommends temperature in the `0.0`–`0.7` range depending on how creative the task is:
|
||||||
|
|
||||||
|
```python Example
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
client = OpenAI(
|
||||||
|
base_url="http://localhost:30000/v1",
|
||||||
|
api_key="EMPTY",
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model="mistralai/Mistral-Medium-3.5-128B",
|
||||||
|
messages=[
|
||||||
|
{"role": "user", "content": "What is the capital of France?"},
|
||||||
|
],
|
||||||
|
temperature=0.1,
|
||||||
|
extra_body={"reasoning_effort": "none"},
|
||||||
|
)
|
||||||
|
|
||||||
|
print(response.choices[0].message.content)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
|
||||||
|
```text Output
|
||||||
|
The capital of France is **Paris**. It is one of the most famous and visited cities in
|
||||||
|
the world, known for its rich history, art, culture, and landmarks like the Eiffel Tower,
|
||||||
|
Louvre Museum, and Notre-Dame Cathedral.
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 Streaming with Reasoning
|
||||||
|
|
||||||
|
```python Example
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
client = OpenAI(
|
||||||
|
base_url="http://localhost:30000/v1",
|
||||||
|
api_key="EMPTY",
|
||||||
|
)
|
||||||
|
|
||||||
|
stream = client.chat.completions.create(
|
||||||
|
model="mistralai/Mistral-Medium-3.5-128B",
|
||||||
|
messages=[
|
||||||
|
{"role": "user", "content": "Explain the difference between async and threading in Python."},
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
extra_body={"reasoning_effort": "high"},
|
||||||
|
stream=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
print("=== Reasoning ===")
|
||||||
|
for chunk in stream:
|
||||||
|
delta = chunk.choices[0].delta
|
||||||
|
if hasattr(delta, "reasoning_content") and delta.reasoning_content:
|
||||||
|
print(delta.reasoning_content, end="", flush=True)
|
||||||
|
elif delta.content:
|
||||||
|
print("\n=== Response ===")
|
||||||
|
print(delta.content, end="", flush=True)
|
||||||
|
print()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 Tool Calling
|
||||||
|
|
||||||
|
Mistral Medium 3.5 supports native function calling. Enable with `--tool-call-parser mistral`:
|
||||||
|
|
||||||
|
```python Example
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
client = OpenAI(
|
||||||
|
base_url="http://localhost:30000/v1",
|
||||||
|
api_key="EMPTY",
|
||||||
|
)
|
||||||
|
|
||||||
|
tools = [
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "get_weather",
|
||||||
|
"description": "Get the current weather for a city",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"location": {"type": "string", "description": "City name"},
|
||||||
|
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
|
||||||
|
},
|
||||||
|
"required": ["location"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model="mistralai/Mistral-Medium-3.5-128B",
|
||||||
|
messages=[{"role": "user", "content": "What's the weather in Paris?"}],
|
||||||
|
tools=tools,
|
||||||
|
tool_choice="auto",
|
||||||
|
)
|
||||||
|
|
||||||
|
tool_calls = response.choices[0].message.tool_calls
|
||||||
|
for tc in tool_calls:
|
||||||
|
print(f"Tool: {tc.function.name}")
|
||||||
|
print(f"Args: {tc.function.arguments}")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
|
||||||
|
```text Output
|
||||||
|
Tool: get_weather
|
||||||
|
Args: {"location": "Paris"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.5 Vision (Image Input)
|
||||||
|
|
||||||
|
Mistral Medium 3.5 accepts image inputs alongside text. The vision encoder was retrained from scratch to handle variable image sizes and aspect ratios:
|
||||||
|
|
||||||
|
```python Example
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
client = OpenAI(
|
||||||
|
base_url="http://localhost:30000/v1",
|
||||||
|
api_key="EMPTY",
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model="mistralai/Mistral-Medium-3.5-128B",
|
||||||
|
messages=[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": [
|
||||||
|
{"type": "text", "text": "Describe what you see in this image."},
|
||||||
|
{
|
||||||
|
"type": "image_url",
|
||||||
|
"image_url": {"url": "https://raw.githubusercontent.com/sgl-project/sglang/main/assets/logo.png"},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
temperature=0.7,
|
||||||
|
extra_body={"reasoning_effort": "none"},
|
||||||
|
)
|
||||||
|
|
||||||
|
print(response.choices[0].message.content)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output:**
|
||||||
|
|
||||||
|
```text Output
|
||||||
|
The image features a stylized representation of the acronym "SGL." The letters
|
||||||
|
are large, bold, and orange with a brown outline, giving them a three-dimensional
|
||||||
|
effect. To the left of the letters, there is a graphic that resembles a neuron
|
||||||
|
or a node with connections, also in a similar orange and brown color scheme. The
|
||||||
|
node has a code symbol (</>) inside a square, suggesting a connection to
|
||||||
|
programming or technology.
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.6 Loading the Reference System Prompt
|
||||||
|
|
||||||
|
Mistral ships a `SYSTEM_PROMPT.txt` alongside the weights. The reference setup loads it from the HF repo and substitutes `{name}`, `{today}`, and `{yesterday}` at runtime so the model knows its identity and the current date. SGLang's chat template will inject a default system prompt if you omit one, but for full parity with Mistral's reference, load it explicitly:
|
||||||
|
|
||||||
|
```python Example
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from huggingface_hub import hf_hub_download
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
MODEL = "mistralai/Mistral-Medium-3.5-128B"
|
||||||
|
|
||||||
|
def load_system_prompt(repo_id: str, filename: str = "SYSTEM_PROMPT.txt") -> str:
|
||||||
|
path = hf_hub_download(repo_id=repo_id, filename=filename)
|
||||||
|
today = datetime.today().strftime("%Y-%m-%d")
|
||||||
|
yesterday = (datetime.today() - timedelta(days=1)).strftime("%Y-%m-%d")
|
||||||
|
name = repo_id.split("/")[-1]
|
||||||
|
with open(path) as f:
|
||||||
|
return f.read().format(name=name, today=today, yesterday=yesterday)
|
||||||
|
|
||||||
|
client = OpenAI(base_url="http://localhost:30000/v1", api_key="EMPTY")
|
||||||
|
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model=MODEL,
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": load_system_prompt(MODEL)},
|
||||||
|
{"role": "user", "content": "Write me a sentence where every word starts with the next letter in the alphabet — start with 'a' and end with 'z'."},
|
||||||
|
],
|
||||||
|
temperature=0.1,
|
||||||
|
extra_body={"reasoning_effort": "none"},
|
||||||
|
)
|
||||||
|
|
||||||
|
print(response.choices[0].message.content)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Benchmarks
|
||||||
|
|
||||||
|
Validation runs on 4× H200 with `--tp 4`, served via the `/v1/chat/completions` endpoint.
|
||||||
|
|
||||||
|
### 5.1 Accuracy Benchmarks
|
||||||
|
|
||||||
|
#### GSM8K
|
||||||
|
|
||||||
|
```bash Command
|
||||||
|
python3 benchmark/gsm8k/bench_sglang.py --port 30000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Results:**
|
||||||
|
|
||||||
|
```text Output
|
||||||
|
Accuracy: 0.945
|
||||||
|
Invalid: 0.000
|
||||||
|
Latency: 13.594 s
|
||||||
|
Output throughput: 1560.660 token/s
|
||||||
|
```
|
||||||
|
|
||||||
|
#### MMMU
|
||||||
|
|
||||||
|
```bash Command
|
||||||
|
python3 benchmark/mmmu/bench_sglang.py --port 30000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Results:**
|
||||||
|
|
||||||
|
```text Output
|
||||||
|
Overall accuracy: 0.586
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 Speed Benchmarks
|
||||||
|
|
||||||
|
#### Latency (Low Concurrency)
|
||||||
|
|
||||||
|
```bash Command
|
||||||
|
python3 -m sglang.bench_serving \
|
||||||
|
--backend sglang \
|
||||||
|
--dataset-name random \
|
||||||
|
--num-prompts 10 \
|
||||||
|
--max-concurrency 1 \
|
||||||
|
--random-input-len 1024 \
|
||||||
|
--random-output-len 512 \
|
||||||
|
--port 30000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Results:**
|
||||||
|
|
||||||
|
```text Output
|
||||||
|
============ Serving Benchmark Result ============
|
||||||
|
Backend: sglang
|
||||||
|
Successful requests: 10
|
||||||
|
Benchmark duration (s): 38.86
|
||||||
|
Total input tokens: 6101
|
||||||
|
Total generated tokens: 2684
|
||||||
|
Output token throughput (tok/s): 69.07
|
||||||
|
Mean E2E Latency (ms): 3883.80
|
||||||
|
Median TTFT (ms): 95.90
|
||||||
|
Median TPOT (ms): 14.19
|
||||||
|
==================================================
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Throughput (High Concurrency)
|
||||||
|
|
||||||
|
```bash Command
|
||||||
|
python3 -m sglang.bench_serving \
|
||||||
|
--backend sglang \
|
||||||
|
--dataset-name random \
|
||||||
|
--num-prompts 1000 \
|
||||||
|
--max-concurrency 100 \
|
||||||
|
--random-input-len 1024 \
|
||||||
|
--random-output-len 512 \
|
||||||
|
--port 30000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Results:**
|
||||||
|
|
||||||
|
```text Output
|
||||||
|
============ Serving Benchmark Result ============
|
||||||
|
Backend: sglang
|
||||||
|
Successful requests: 1000
|
||||||
|
Benchmark duration (s): 117.28
|
||||||
|
Total input tokens: 512842
|
||||||
|
Total generated tokens: 262023
|
||||||
|
Output token throughput (tok/s): 2234.18
|
||||||
|
Total token throughput (tok/s): 6607.01
|
||||||
|
Mean E2E Latency (ms): 11303.79
|
||||||
|
Median TTFT (ms): 152.95
|
||||||
|
Median TPOT (ms): 42.53
|
||||||
|
==================================================
|
||||||
|
```
|
||||||
@@ -1057,6 +1057,7 @@
|
|||||||
"pages": [
|
"pages": [
|
||||||
"cookbook/autoregressive/Mistral/Ministral-3",
|
"cookbook/autoregressive/Mistral/Ministral-3",
|
||||||
"cookbook/autoregressive/Mistral/Mistral-Small-4",
|
"cookbook/autoregressive/Mistral/Mistral-Small-4",
|
||||||
|
"cookbook/autoregressive/Mistral/Mistral-Medium-3.5",
|
||||||
"cookbook/autoregressive/Mistral/Devstral-2"
|
"cookbook/autoregressive/Mistral/Devstral-2"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,340 @@
|
|||||||
|
export const MistralMedium35Deployment = () => {
|
||||||
|
const modelId = 'mistralai/Mistral-Medium-3.5-128B';
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
hardware: {
|
||||||
|
name: 'hardware',
|
||||||
|
title: 'Hardware Platform',
|
||||||
|
items: [
|
||||||
|
{ id: 'h100', label: 'H100', default: false },
|
||||||
|
{ id: 'h200', label: 'H200', default: true },
|
||||||
|
{ id: 'b200', label: 'B200', default: false },
|
||||||
|
{ id: 'b300', label: 'B300', default: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
reasoning: {
|
||||||
|
name: 'reasoning',
|
||||||
|
title: 'Reasoning Parser',
|
||||||
|
items: [
|
||||||
|
{ id: 'disabled', label: 'Disabled', default: false },
|
||||||
|
{ id: 'enabled', label: 'Enabled', default: true }
|
||||||
|
],
|
||||||
|
commandRule: (value) => value === 'enabled' ? '--reasoning-parser mistral' : null
|
||||||
|
},
|
||||||
|
toolcall: {
|
||||||
|
name: 'toolcall',
|
||||||
|
title: 'Tool Call Parser',
|
||||||
|
items: [
|
||||||
|
{ id: 'disabled', label: 'Disabled', default: false },
|
||||||
|
{ id: 'enabled', label: 'Enabled', default: true }
|
||||||
|
],
|
||||||
|
commandRule: (value) => value === 'enabled' ? '--tool-call-parser mistral' : null
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 128B dense FP8 ≈ 130GB, plus KV cache headroom
|
||||||
|
const modelConfigs = {
|
||||||
|
h100: { tp: 4 },
|
||||||
|
h200: { tp: 4 },
|
||||||
|
b200: { tp: 2 },
|
||||||
|
b300: { tp: 2 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateCommand = (values) => {
|
||||||
|
const { hardware } = values;
|
||||||
|
const hwConfig = modelConfigs[hardware];
|
||||||
|
if (!hwConfig) return `# Error: Unknown hardware combination`;
|
||||||
|
const { tp } = hwConfig;
|
||||||
|
|
||||||
|
let cmd = `sglang serve --model-path ${modelId}`;
|
||||||
|
cmd += ` \\\n --tp ${tp}`;
|
||||||
|
|
||||||
|
Object.entries(options).forEach(([key, option]) => {
|
||||||
|
if (key === 'hardware') return;
|
||||||
|
if (option.commandRule) {
|
||||||
|
const rule = option.commandRule(values[key]);
|
||||||
|
if (rule) cmd += ` \\\n ${rule}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInitialState = () => {
|
||||||
|
const initialState = {};
|
||||||
|
Object.entries(options).forEach(([key, option]) => {
|
||||||
|
if (option.type === 'checkbox') {
|
||||||
|
initialState[key] = (option.items || [])
|
||||||
|
.filter((item) => item.default)
|
||||||
|
.map((item) => item.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (option.type === 'text') {
|
||||||
|
initialState[key] = option.default || '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let items = option.items || [];
|
||||||
|
if (option.getDynamicItems) {
|
||||||
|
const defaultValues = {};
|
||||||
|
Object.entries(options).forEach(([innerKey, innerOption]) => {
|
||||||
|
if (innerOption.type === 'checkbox') {
|
||||||
|
defaultValues[innerKey] = (innerOption.items || [])
|
||||||
|
.filter((item) => item.default)
|
||||||
|
.map((item) => item.id);
|
||||||
|
} else if (innerOption.type === 'text') {
|
||||||
|
defaultValues[innerKey] = innerOption.default || '';
|
||||||
|
} else if (innerOption.items && innerOption.items.length > 0) {
|
||||||
|
const defaultItem = innerOption.items.find((item) => item.default);
|
||||||
|
defaultValues[innerKey] = defaultItem ? defaultItem.id : innerOption.items[0].id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
items = option.getDynamicItems(defaultValues);
|
||||||
|
}
|
||||||
|
const defaultItem = items && items.find((item) => item.default);
|
||||||
|
initialState[key] = defaultItem ? defaultItem.id : items && items[0] ? items[0].id : '';
|
||||||
|
});
|
||||||
|
return initialState;
|
||||||
|
};
|
||||||
|
|
||||||
|
const [values, setValues] = useState(getInitialState);
|
||||||
|
const [isDark, setIsDark] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const checkDarkMode = () => {
|
||||||
|
const html = document.documentElement;
|
||||||
|
const isDarkMode =
|
||||||
|
html.classList.contains('dark') ||
|
||||||
|
html.getAttribute('data-theme') === 'dark' ||
|
||||||
|
html.style.colorScheme === 'dark';
|
||||||
|
setIsDark(isDarkMode);
|
||||||
|
};
|
||||||
|
checkDarkMode();
|
||||||
|
const observer = new MutationObserver(checkDarkMode);
|
||||||
|
observer.observe(document.documentElement, {
|
||||||
|
attributes: true,
|
||||||
|
attributeFilter: ['class', 'data-theme', 'style'],
|
||||||
|
});
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleRadioChange = (optionName, value) => {
|
||||||
|
setValues((prev) => ({ ...prev, [optionName]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCheckboxChange = (optionName, itemId, isChecked) => {
|
||||||
|
setValues((prev) => {
|
||||||
|
const currentValues = prev[optionName] || [];
|
||||||
|
if (isChecked) {
|
||||||
|
return { ...prev, [optionName]: [...currentValues, itemId] };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[optionName]: currentValues.filter((id) => id !== itemId),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTextChange = (optionName, value) => {
|
||||||
|
setValues((prev) => ({ ...prev, [optionName]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const command = generateCommand(values);
|
||||||
|
|
||||||
|
const containerStyle = {
|
||||||
|
maxWidth: '900px',
|
||||||
|
margin: '0 auto',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '4px',
|
||||||
|
};
|
||||||
|
const cardStyle = {
|
||||||
|
padding: '8px 12px',
|
||||||
|
border: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,
|
||||||
|
borderLeft: `3px solid ${isDark ? '#E85D4D' : '#D45D44'}`,
|
||||||
|
borderRadius: '4px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '12px',
|
||||||
|
background: isDark ? '#1f2937' : '#fff',
|
||||||
|
};
|
||||||
|
const titleStyle = {
|
||||||
|
fontSize: '13px',
|
||||||
|
fontWeight: '600',
|
||||||
|
minWidth: '140px',
|
||||||
|
flexShrink: 0,
|
||||||
|
color: isDark ? '#e5e7eb' : 'inherit',
|
||||||
|
};
|
||||||
|
const itemsStyle = {
|
||||||
|
display: 'flex',
|
||||||
|
rowGap: '2px',
|
||||||
|
columnGap: '6px',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
alignItems: 'center',
|
||||||
|
flex: 1,
|
||||||
|
};
|
||||||
|
const labelBaseStyle = {
|
||||||
|
padding: '4px 10px',
|
||||||
|
border: `1px solid ${isDark ? '#9ca3af' : '#d1d5db'}`,
|
||||||
|
borderRadius: '3px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'inline-flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: '13px',
|
||||||
|
transition: 'all 0.2s',
|
||||||
|
userSelect: 'none',
|
||||||
|
minWidth: '45px',
|
||||||
|
textAlign: 'center',
|
||||||
|
flex: 1,
|
||||||
|
background: isDark ? '#374151' : '#fff',
|
||||||
|
color: isDark ? '#e5e7eb' : 'inherit',
|
||||||
|
};
|
||||||
|
const checkedStyle = {
|
||||||
|
background: '#D45D44',
|
||||||
|
color: 'white',
|
||||||
|
borderColor: '#D45D44',
|
||||||
|
};
|
||||||
|
const disabledStyle = {
|
||||||
|
cursor: 'not-allowed',
|
||||||
|
opacity: 0.5,
|
||||||
|
};
|
||||||
|
const subtitleStyle = {
|
||||||
|
display: 'block',
|
||||||
|
fontSize: '9px',
|
||||||
|
marginTop: '1px',
|
||||||
|
lineHeight: '1.1',
|
||||||
|
opacity: 0.7,
|
||||||
|
};
|
||||||
|
const textInputStyle = {
|
||||||
|
flex: 1,
|
||||||
|
padding: '8px 10px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
border: `1px solid ${isDark ? '#4b5563' : '#d1d5db'}`,
|
||||||
|
background: isDark ? '#111827' : '#fff',
|
||||||
|
color: isDark ? '#e5e7eb' : '#111827',
|
||||||
|
fontSize: '13px',
|
||||||
|
};
|
||||||
|
const commandDisplayStyle = {
|
||||||
|
flex: 1,
|
||||||
|
padding: '12px 16px',
|
||||||
|
background: isDark ? '#111827' : '#f5f5f5',
|
||||||
|
borderRadius: '6px',
|
||||||
|
fontFamily: "'Menlo', 'Monaco', 'Courier New', monospace",
|
||||||
|
fontSize: '12px',
|
||||||
|
lineHeight: '1.5',
|
||||||
|
color: isDark ? '#e5e7eb' : '#374151',
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
overflowX: 'auto',
|
||||||
|
margin: 0,
|
||||||
|
border: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={containerStyle} className="not-prose">
|
||||||
|
{Object.entries(options).map(([key, option]) => {
|
||||||
|
if (option.condition && !option.condition(values)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const items = option.getDynamicItems ? option.getDynamicItems(values) : option.items || [];
|
||||||
|
return (
|
||||||
|
<div key={key} style={cardStyle}>
|
||||||
|
<div style={titleStyle}>{option.title}</div>
|
||||||
|
<div style={itemsStyle}>
|
||||||
|
{option.type === 'text' ? (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={values[option.name] || ''}
|
||||||
|
placeholder={option.placeholder || ''}
|
||||||
|
onChange={(event) => handleTextChange(option.name, event.target.value)}
|
||||||
|
style={textInputStyle}
|
||||||
|
/>
|
||||||
|
) : option.type === 'checkbox' ? (
|
||||||
|
(option.items || []).map((item) => {
|
||||||
|
const isChecked = (values[option.name] || []).includes(item.id);
|
||||||
|
const isDisabled =
|
||||||
|
item.required ||
|
||||||
|
(typeof item.disabledWhen === 'function' && item.disabledWhen(values));
|
||||||
|
return (
|
||||||
|
<label
|
||||||
|
key={item.id}
|
||||||
|
title={item.disabledReason || ''}
|
||||||
|
style={{
|
||||||
|
...labelBaseStyle,
|
||||||
|
...(isChecked ? checkedStyle : {}),
|
||||||
|
...(isDisabled ? disabledStyle : {}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={isChecked}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onChange={(event) =>
|
||||||
|
handleCheckboxChange(option.name, item.id, event.target.checked)
|
||||||
|
}
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
/>
|
||||||
|
{item.label}
|
||||||
|
{item.subtitle && (
|
||||||
|
<small
|
||||||
|
style={{
|
||||||
|
...subtitleStyle,
|
||||||
|
color: isChecked ? 'rgba(255,255,255,0.85)' : 'inherit',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.subtitle}
|
||||||
|
</small>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
items.map((item) => {
|
||||||
|
const isChecked = values[option.name] === item.id;
|
||||||
|
const isDisabled = Boolean(item.disabled);
|
||||||
|
return (
|
||||||
|
<label
|
||||||
|
key={item.id}
|
||||||
|
title={item.disabledReason || ''}
|
||||||
|
style={{
|
||||||
|
...labelBaseStyle,
|
||||||
|
...(isChecked ? checkedStyle : {}),
|
||||||
|
...(isDisabled ? disabledStyle : {}),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name={option.name}
|
||||||
|
value={item.id}
|
||||||
|
checked={isChecked}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onChange={() => !isDisabled && handleRadioChange(option.name, item.id)}
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
/>
|
||||||
|
{item.label}
|
||||||
|
{item.subtitle && (
|
||||||
|
<small
|
||||||
|
style={{
|
||||||
|
...subtitleStyle,
|
||||||
|
color: isChecked ? 'rgba(255,255,255,0.85)' : 'inherit',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.subtitle}
|
||||||
|
</small>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<div style={cardStyle}>
|
||||||
|
<div style={titleStyle}>Run this Command:</div>
|
||||||
|
<pre style={commandDisplayStyle}>{command}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -499,7 +499,10 @@ class ModelConfig:
|
|||||||
or "LongcatFlashForCausalLMNextN" in self.hf_config.architectures
|
or "LongcatFlashForCausalLMNextN" in self.hf_config.architectures
|
||||||
or "DotsVLMForCausalLM" in self.hf_config.architectures
|
or "DotsVLMForCausalLM" in self.hf_config.architectures
|
||||||
or "MistralLarge3ForCausalLM" in self.hf_config.architectures
|
or "MistralLarge3ForCausalLM" in self.hf_config.architectures
|
||||||
or "PixtralForConditionalGeneration" in self.hf_config.architectures
|
or (
|
||||||
|
"PixtralForConditionalGeneration" in self.hf_config.architectures
|
||||||
|
and getattr(self.hf_text_config, "kv_lora_rank", None) is not None
|
||||||
|
)
|
||||||
or "MistralLarge3ForCausalLMEagle" in self.hf_config.architectures
|
or "MistralLarge3ForCausalLMEagle" in self.hf_config.architectures
|
||||||
or "KimiK25ForConditionalGeneration" in self.hf_config.architectures
|
or "KimiK25ForConditionalGeneration" in self.hf_config.architectures
|
||||||
):
|
):
|
||||||
|
|||||||
@@ -13,19 +13,81 @@
|
|||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
"""Inference-only Mistral model."""
|
"""Inference-only Mistral model."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from collections.abc import Iterable
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
import regex as re
|
||||||
import torch
|
import torch
|
||||||
from transformers.models.mistral3.modeling_mistral3 import Mistral3MultiModalProjector
|
from transformers.models.mistral3.modeling_mistral3 import Mistral3MultiModalProjector
|
||||||
|
|
||||||
from sglang.srt.managers.schedule_batch import MultimodalDataItem
|
from sglang.srt.managers.schedule_batch import MultimodalDataItem
|
||||||
from sglang.srt.models.llama import LlamaForCausalLM
|
from sglang.srt.models.llama import LlamaForCausalLM
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class MistralForCausalLM(LlamaForCausalLM):
|
class MistralForCausalLM(LlamaForCausalLM):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MistralForCausalLMMistralFormat(MistralForCausalLM):
|
||||||
|
"""Mistral GQA model loaded from mistral native format (params.json).
|
||||||
|
|
||||||
|
Handles weight name remapping from mistral native format to HF/Llama
|
||||||
|
format. This is the GQA counterpart to MistralLarge3ForCausalLM which
|
||||||
|
handles MLA models in mistral native format.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
remapping = {
|
||||||
|
r"layers\.(\d+)\.attention_norm\.weight": r"model.layers.\1.input_layernorm.weight",
|
||||||
|
r"layers\.(\d+)\.attention\.wq\.(\w+)": r"model.layers.\1.self_attn.q_proj.\2",
|
||||||
|
r"layers\.(\d+)\.attention\.wk\.(\w+)": r"model.layers.\1.self_attn.k_proj.\2",
|
||||||
|
r"layers\.(\d+)\.attention\.wv\.(\w+)": r"model.layers.\1.self_attn.v_proj.\2",
|
||||||
|
r"layers\.(\d+)\.attention\.wo\.(\w+)": r"model.layers.\1.self_attn.o_proj.\2",
|
||||||
|
r"layers\.(\d+)\.ffn_norm\.weight": r"model.layers.\1.post_attention_layernorm.weight",
|
||||||
|
r"layers\.(\d+)\.feed_forward\.w1\.(\w+)": r"model.layers.\1.mlp.gate_proj.\2",
|
||||||
|
r"layers\.(\d+)\.feed_forward\.w2\.(\w+)": r"model.layers.\1.mlp.down_proj.\2",
|
||||||
|
r"layers\.(\d+)\.feed_forward\.w3\.(\w+)": r"model.layers.\1.mlp.up_proj.\2",
|
||||||
|
r"norm\.weight": "model.norm.weight",
|
||||||
|
r"tok_embeddings\.weight": "model.embed_tokens.weight",
|
||||||
|
r"output\.weight": "lm_head.weight",
|
||||||
|
}
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
|
||||||
|
return super().load_weights(self._remap_mistral_to_llama(weights))
|
||||||
|
|
||||||
|
def _remap_mistral_to_llama(
|
||||||
|
self, weights: Iterable[tuple[str, torch.Tensor]]
|
||||||
|
) -> Iterable[tuple[str, torch.Tensor]]:
|
||||||
|
"""Remap Mistral native format weight names to HF/Llama format."""
|
||||||
|
for name, loaded_weight in weights:
|
||||||
|
# Pass through weights already in HF/Llama layout so this loader
|
||||||
|
# tolerates mixed-format checkpoints (e.g. native body + HF-style
|
||||||
|
# multi_modal_projector weights spliced in by a parent class).
|
||||||
|
if name.startswith("model.") or name.startswith("lm_head."):
|
||||||
|
yield name, loaded_weight
|
||||||
|
continue
|
||||||
|
|
||||||
|
for k, v in self.remapping.items():
|
||||||
|
match = re.fullmatch(k, name)
|
||||||
|
if match:
|
||||||
|
name = match.expand(v)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
logger.warning(f"Unrecognized weight: {name}. Skipping.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if name.endswith(".qscale_act"):
|
||||||
|
name = re.sub(r"\.qscale_act$", ".input_scale", name)
|
||||||
|
elif name.endswith(".qscale_weight"):
|
||||||
|
name = re.sub(r"\.qscale_weight$", ".weight_scale", name)
|
||||||
|
|
||||||
|
yield name, loaded_weight
|
||||||
|
|
||||||
|
|
||||||
class Mistral3ForConditionalGeneration:
|
class Mistral3ForConditionalGeneration:
|
||||||
MULTIMODAL_PROJECTOR_TYPE = Mistral3MultiModalProjector
|
MULTIMODAL_PROJECTOR_TYPE = Mistral3MultiModalProjector
|
||||||
|
|
||||||
@@ -89,5 +151,45 @@ class Mistral3ForConditionalGeneration:
|
|||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
return self.inner(*args, **kwargs)
|
return self.inner(*args, **kwargs)
|
||||||
|
|
||||||
|
def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
|
||||||
|
"""Normalize transformers v5 Mistral3 weight names for
|
||||||
|
LlavaForConditionalGeneration.load_weights.
|
||||||
|
|
||||||
|
v5 checkpoints lay out Mistral3 weights as:
|
||||||
|
model.language_model.{embed_tokens,layers.*,norm}.*
|
||||||
|
model.vision_tower.*
|
||||||
|
model.multi_modal_projector.*
|
||||||
|
lm_head.*
|
||||||
|
|
||||||
|
The Llava loader routes by top-level `language_model.` /
|
||||||
|
`vision_tower.` prefixes, stripping one segment before forwarding to
|
||||||
|
the sub-module. The sub-module's own `load_weights` expects the
|
||||||
|
standard HF layout: `model.layers.*`, `model.embed_tokens.weight`,
|
||||||
|
`lm_head.weight` for Llama, and `vision_tower` internals at their
|
||||||
|
top level. So we rewrite:
|
||||||
|
model.language_model.X -> language_model.model.X
|
||||||
|
model.vision_tower.X -> vision_tower.X
|
||||||
|
model.multi_modal_projector.X -> multi_modal_projector.X
|
||||||
|
lm_head.X -> language_model.lm_head.X
|
||||||
|
"""
|
||||||
|
|
||||||
|
def normalize(ws):
|
||||||
|
for name, w in ws:
|
||||||
|
if name.startswith("model.language_model."):
|
||||||
|
rest = name[len("model.language_model.") :]
|
||||||
|
name = "language_model.model." + rest
|
||||||
|
elif name.startswith("model.vision_tower."):
|
||||||
|
name = "vision_tower." + name[len("model.vision_tower.") :]
|
||||||
|
elif name.startswith("model.multi_modal_projector."):
|
||||||
|
name = (
|
||||||
|
"multi_modal_projector."
|
||||||
|
+ name[len("model.multi_modal_projector.") :]
|
||||||
|
)
|
||||||
|
elif name.startswith("lm_head."):
|
||||||
|
name = "language_model." + name
|
||||||
|
yield name, w
|
||||||
|
|
||||||
|
return self.inner.load_weights(normalize(weights))
|
||||||
|
|
||||||
|
|
||||||
EntryClass = [MistralForCausalLM, Mistral3ForConditionalGeneration]
|
EntryClass = [MistralForCausalLM, Mistral3ForConditionalGeneration]
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ from sglang.srt.managers.mm_utils import (
|
|||||||
)
|
)
|
||||||
from sglang.srt.managers.schedule_batch import MultimodalDataItem, MultimodalInputs
|
from sglang.srt.managers.schedule_batch import MultimodalDataItem, MultimodalInputs
|
||||||
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
||||||
|
from sglang.srt.models.mistral import MistralForCausalLMMistralFormat
|
||||||
from sglang.srt.models.mistral_large_3 import MistralLarge3ForCausalLM
|
from sglang.srt.models.mistral_large_3 import MistralLarge3ForCausalLM
|
||||||
|
|
||||||
USE_XFORMERS_OPS = False
|
USE_XFORMERS_OPS = False
|
||||||
@@ -94,10 +95,21 @@ class PixtralForConditionalGeneration(nn.Module):
|
|||||||
|
|
||||||
self.vision_args = VisionEncoderArgs(**vision_args)
|
self.vision_args = VisionEncoderArgs(**vision_args)
|
||||||
|
|
||||||
self.language_model = MistralLarge3ForCausalLM(
|
# Choose language model based on text architecture:
|
||||||
config=self.config.text_config,
|
# MLA text configs use DeepSeek V3 backbone (model_type="deepseek_v3"),
|
||||||
quant_config=kwargs.get("quant_config"),
|
# GQA text configs use the standard Llama-style Mistral backbone.
|
||||||
)
|
text_config = self.config.text_config
|
||||||
|
is_mla = getattr(text_config, "model_type", "") == "deepseek_v3"
|
||||||
|
if is_mla:
|
||||||
|
self.language_model = MistralLarge3ForCausalLM(
|
||||||
|
config=text_config,
|
||||||
|
quant_config=kwargs.get("quant_config"),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.language_model = MistralForCausalLMMistralFormat(
|
||||||
|
config=text_config,
|
||||||
|
quant_config=kwargs.get("quant_config"),
|
||||||
|
)
|
||||||
|
|
||||||
self.vision_encoder = VisionTransformer(self.vision_args)
|
self.vision_encoder = VisionTransformer(self.vision_args)
|
||||||
|
|
||||||
|
|||||||
@@ -227,6 +227,14 @@ def get_hf_text_config(config: PretrainedConfig):
|
|||||||
if getattr(_converted, "dtype", None) is None and parent_dtype is not None:
|
if getattr(_converted, "dtype", None) is None and parent_dtype is not None:
|
||||||
_converted.dtype = parent_dtype
|
_converted.dtype = parent_dtype
|
||||||
setattr(config, _attr, _converted)
|
setattr(config, _attr, _converted)
|
||||||
|
elif _sub is not None and parent_dtype is not None:
|
||||||
|
# transformers v5 multimodal configs (e.g. Mistral3Config) carry
|
||||||
|
# `dtype` only on the top-level config, leaving the sub-configs at
|
||||||
|
# None. Without this, _get_and_verify_dtype falls back to float32
|
||||||
|
# and then "auto" downcasts to float16, which overflows the Pixtral
|
||||||
|
# vision tower on real images and produces NaN features.
|
||||||
|
if getattr(_sub, "dtype", None) is None:
|
||||||
|
_sub.dtype = parent_dtype
|
||||||
|
|
||||||
# Priority: thinker_config > llm_config > language_config > text_config
|
# Priority: thinker_config > llm_config > language_config > text_config
|
||||||
if hasattr(config, "thinker_config"):
|
if hasattr(config, "thinker_config"):
|
||||||
|
|||||||
@@ -73,6 +73,22 @@ def adapt_config_dict(
|
|||||||
config_dict["architectures"] = ["MixtralForCausalLM"]
|
config_dict["architectures"] = ["MixtralForCausalLM"]
|
||||||
else:
|
else:
|
||||||
config_dict["architectures"] = ["MistralForCausalLM"]
|
config_dict["architectures"] = ["MistralForCausalLM"]
|
||||||
|
config_dict["model_type"] = "mistral"
|
||||||
|
# Mistral models use non-interleaved RoPE (is_neox_style=False),
|
||||||
|
# unlike Llama which defaults to True.
|
||||||
|
config_dict["rope_is_neox_style"] = False
|
||||||
|
# Remove None-valued MLA fields that would shadow defaults in
|
||||||
|
# model_config._derive_model_shapes (getattr returns None instead
|
||||||
|
# of the fallback when the attribute exists but is None).
|
||||||
|
for mla_key in (
|
||||||
|
"q_lora_rank",
|
||||||
|
"qk_rope_head_dim",
|
||||||
|
"qk_nope_head_dim",
|
||||||
|
"kv_lora_rank",
|
||||||
|
"v_head_dim",
|
||||||
|
):
|
||||||
|
if config_dict.get(mla_key) is None:
|
||||||
|
config_dict.pop(mla_key, None)
|
||||||
|
|
||||||
if bool(config_dict.get("yarn")):
|
if bool(config_dict.get("yarn")):
|
||||||
config_dict = _remap_mistral_yarn_args(config_dict)
|
config_dict = _remap_mistral_yarn_args(config_dict)
|
||||||
|
|||||||
Reference in New Issue
Block a user