feat: DeepSeek V4 Flash 0731 added

This commit is contained in:
Georg Bauer
2026-08-01 08:40:06 +02:00
parent 4175706533
commit d1c380f79d
7 changed files with 85 additions and 21 deletions

View File

@@ -2566,6 +2566,7 @@ mod tests {
Some(Message::FocusPrevious) Some(Message::FocusPrevious)
)); ));
assert!(ModelChoice::DeepSeekV4Flash.supports_dspark()); assert!(ModelChoice::DeepSeekV4Flash.supports_dspark());
assert!(!ModelChoice::DeepSeekV4Flash0731.supports_dspark());
assert!(!ModelChoice::DeepSeekV4Pro.supports_dspark()); assert!(!ModelChoice::DeepSeekV4Pro.supports_dspark());
assert!(!ModelChoice::Glm52.supports_dspark()); assert!(!ModelChoice::Glm52.supports_dspark());
} }

View File

@@ -150,6 +150,11 @@ const FLASH: Shape = Shape {
original_context: 65_536, original_context: 65_536,
}; };
const FLASH_0731: Shape = Shape {
model: ModelChoice::DeepSeekV4Flash0731,
..FLASH
};
const PRO: Shape = Shape { const PRO: Shape = Shape {
model: ModelChoice::DeepSeekV4Pro, model: ModelChoice::DeepSeekV4Pro,
layers: 61, layers: 61,

View File

@@ -1985,7 +1985,7 @@ impl SsdPlan {
let mut by_layer = vec![Vec::<(i32, u32)>::new(); model.shape.layers as usize]; let mut by_layer = vec![Vec::<(i32, u32)>::new(); model.shape.layers as usize];
let mut loaded = 0_u32; let mut loaded = 0_u32;
let hotlist = match model.shape.model { let hotlist = match model.shape.model {
ModelChoice::DeepSeekV4Flash => hotlist::FLASH, ModelChoice::DeepSeekV4Flash | ModelChoice::DeepSeekV4Flash0731 => hotlist::FLASH,
ModelChoice::DeepSeekV4Pro => hotlist::PRO, ModelChoice::DeepSeekV4Pro => hotlist::PRO,
ModelChoice::Glm52 => unreachable!("GLM uses its dedicated executor"), ModelChoice::Glm52 => unreachable!("GLM uses its dedicated executor"),
}; };
@@ -3437,8 +3437,10 @@ impl DeepSeekExecutor {
if self.session.position == 0 && self.ssd.is_some() { if self.session.position == 0 && self.ssd.is_some() {
unsafe { ds4_gpu_stream_expert_cache_reset_route_hotness() }; unsafe { ds4_gpu_stream_expert_cache_reset_route_hotness() };
} }
let streaming_decode_cap = if self.model.shape.model == ModelChoice::DeepSeekV4Flash let streaming_decode_cap = if matches!(
&& self.weights.layers.first().is_some_and(|layer| { self.model.shape.model,
ModelChoice::DeepSeekV4Flash | ModelChoice::DeepSeekV4Flash0731
) && self.weights.layers.first().is_some_and(|layer| {
layer.expert_gate.kind == Q4_K layer.expert_gate.kind == Q4_K
&& layer.expert_up.kind == Q4_K && layer.expert_up.kind == Q4_K
&& layer.expert_down.kind == Q4_K && layer.expert_down.kind == Q4_K
@@ -6469,16 +6471,23 @@ fn update_compressor_stage(
fn compression_ratio(shape: super::Shape, layer: u32) -> u32 { fn compression_ratio(shape: super::Shape, layer: u32) -> u32 {
match shape.model { match shape.model {
crate::model::ModelChoice::DeepSeekV4Flash if layer < 2 => 0, crate::model::ModelChoice::DeepSeekV4Flash
| crate::model::ModelChoice::DeepSeekV4Flash0731
if layer < 2 =>
{
0
}
crate::model::ModelChoice::DeepSeekV4Pro if layer < 2 => 128, crate::model::ModelChoice::DeepSeekV4Pro if layer < 2 => 128,
crate::model::ModelChoice::DeepSeekV4Flash | crate::model::ModelChoice::DeepSeekV4Pro crate::model::ModelChoice::DeepSeekV4Flash
| crate::model::ModelChoice::DeepSeekV4Flash0731
| crate::model::ModelChoice::DeepSeekV4Pro
if layer.is_multiple_of(2) => if layer.is_multiple_of(2) =>
{ {
4 4
} }
crate::model::ModelChoice::DeepSeekV4Flash | crate::model::ModelChoice::DeepSeekV4Pro => { crate::model::ModelChoice::DeepSeekV4Flash
128 | crate::model::ModelChoice::DeepSeekV4Flash0731
} | crate::model::ModelChoice::DeepSeekV4Pro => 128,
crate::model::ModelChoice::Glm52 => 0, crate::model::ModelChoice::Glm52 => 0,
} }
} }

View File

@@ -223,10 +223,11 @@ pub(super) fn validate_main(model: &Gguf, expected: ModelChoice) -> Result<Shape
}; };
let shape = match family { let shape = match family {
ModelFamily::Glm => GLM, ModelFamily::Glm => GLM,
ModelFamily::DeepSeek => match model.u32("deepseek4.block_count")? { ModelFamily::DeepSeek => match (model.u32("deepseek4.block_count")?, expected) {
43 => FLASH, (43, ModelChoice::DeepSeekV4Flash0731) => FLASH_0731,
61 => PRO, (43, _) => FLASH,
layers => return Err(format!("unsupported DeepSeek layer count: {layers}")), (61, _) => PRO,
(layers, _) => return Err(format!("unsupported DeepSeek layer count: {layers}")),
}, },
}; };
if shape.model != expected { if shape.model != expected {
@@ -993,10 +994,18 @@ fn float_eq(actual: f32, expected: f32) -> bool {
fn compression_ratio(shape: &Shape, layer: u32) -> u32 { fn compression_ratio(shape: &Shape, layer: u32) -> u32 {
match shape.model { match shape.model {
ModelChoice::DeepSeekV4Flash if layer < 2 => 0, ModelChoice::DeepSeekV4Flash | ModelChoice::DeepSeekV4Flash0731 if layer < 2 => 0,
ModelChoice::DeepSeekV4Pro if layer < 2 => 128, ModelChoice::DeepSeekV4Pro if layer < 2 => 128,
ModelChoice::DeepSeekV4Flash | ModelChoice::DeepSeekV4Pro if layer.is_multiple_of(2) => 4, ModelChoice::DeepSeekV4Flash
ModelChoice::DeepSeekV4Flash | ModelChoice::DeepSeekV4Pro => 128, | ModelChoice::DeepSeekV4Flash0731
| ModelChoice::DeepSeekV4Pro
if layer.is_multiple_of(2) =>
{
4
}
ModelChoice::DeepSeekV4Flash
| ModelChoice::DeepSeekV4Flash0731
| ModelChoice::DeepSeekV4Pro => 128,
ModelChoice::Glm52 => 0, ModelChoice::Glm52 => 0,
} }
} }

View File

@@ -847,6 +847,7 @@ fn model_code(model: ModelChoice) -> u8 {
ModelChoice::DeepSeekV4Flash => 1, ModelChoice::DeepSeekV4Flash => 1,
ModelChoice::DeepSeekV4Pro => 2, ModelChoice::DeepSeekV4Pro => 2,
ModelChoice::Glm52 => 3, ModelChoice::Glm52 => 3,
ModelChoice::DeepSeekV4Flash0731 => 4,
} }
} }
@@ -855,6 +856,7 @@ fn model_name(value: u8) -> &'static str {
1 => "DeepSeek V4 Flash", 1 => "DeepSeek V4 Flash",
2 => "DeepSeek V4 Pro", 2 => "DeepSeek V4 Pro",
3 => "GLM 5.2", 3 => "GLM 5.2",
4 => "DeepSeek V4 Flash 0731",
_ => "No model loaded", _ => "No model loaded",
} }
} }

View File

@@ -9,20 +9,23 @@ use std::fmt;
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
pub(crate) const MODEL_CHOICES: [ModelChoice; 3] = [ pub(crate) const MODEL_CHOICES: [ModelChoice; 4] = [
ModelChoice::DeepSeekV4Flash, ModelChoice::DeepSeekV4Flash,
ModelChoice::DeepSeekV4Flash0731,
ModelChoice::DeepSeekV4Pro, ModelChoice::DeepSeekV4Pro,
ModelChoice::Glm52, ModelChoice::Glm52,
]; ];
pub(crate) const MANAGED_ARTIFACTS: [ManagedArtifactId; 5] = [ pub(crate) const MANAGED_ARTIFACTS: [ManagedArtifactId; 6] = [
ManagedArtifactId::DeepSeekV4Flash, ManagedArtifactId::DeepSeekV4Flash,
ManagedArtifactId::DeepSeekV4FlashMtp, ManagedArtifactId::DeepSeekV4FlashMtp,
ManagedArtifactId::DeepSeekV4FlashDspark, ManagedArtifactId::DeepSeekV4FlashDspark,
ManagedArtifactId::DeepSeekV4Flash0731,
ManagedArtifactId::DeepSeekV4Pro, ManagedArtifactId::DeepSeekV4Pro,
ManagedArtifactId::Glm52, ManagedArtifactId::Glm52,
]; ];
const DEEPSEEK_REPOSITORY: &str = "antirez/deepseek-v4-gguf"; const DEEPSEEK_REPOSITORY: &str = "antirez/deepseek-v4-gguf";
const DEEPSEEK_FLASH_0731_REPOSITORY: &str = "Rednalreden/DeepSeek-V4-Flash-0731-dwarfstar-q2-gguf";
const GLM_REPOSITORY: &str = "antirez/glm-5.2-gguf"; const GLM_REPOSITORY: &str = "antirez/glm-5.2-gguf";
const FLASH: Artifact = Artifact { const FLASH: Artifact = Artifact {
@@ -49,6 +52,14 @@ const FLASH_MTP: Artifact = Artifact {
sha256: "afd481ee689dce9037f70f39085fcdae5a5b096d521cdad43b19fa52bf8f4083", sha256: "afd481ee689dce9037f70f39085fcdae5a5b096d521cdad43b19fa52bf8f4083",
support: Some(true), support: Some(true),
}; };
const FLASH_0731: Artifact = Artifact {
label: "DeepSeek V4 Flash 0731 model",
file_name: "DeepSeek-V4-Flash-0731-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-imatrix.gguf",
repository: DEEPSEEK_FLASH_0731_REPOSITORY,
size: 86_720_111_520,
sha256: "0b39f9c337d6b49c77db2190556b8563abf3c5fbb98be3b58cf8d3a1db191e5f",
support: Some(false),
};
const PRO: Artifact = Artifact { const PRO: Artifact = Artifact {
label: "DeepSeek V4 Pro model", label: "DeepSeek V4 Pro model",
file_name: "DeepSeek-V4-Pro-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-Instruct-imatrix.gguf", file_name: "DeepSeek-V4-Pro-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-Instruct-imatrix.gguf",
@@ -71,6 +82,8 @@ pub(crate) enum ModelChoice {
#[default] #[default]
#[serde(rename = "deepseek-v4-flash")] #[serde(rename = "deepseek-v4-flash")]
DeepSeekV4Flash, DeepSeekV4Flash,
#[serde(rename = "deepseek-v4-flash-0731")]
DeepSeekV4Flash0731,
#[serde(rename = "deepseek-v4-pro")] #[serde(rename = "deepseek-v4-pro")]
DeepSeekV4Pro, DeepSeekV4Pro,
#[serde(rename = "glm-5.2")] #[serde(rename = "glm-5.2")]
@@ -81,6 +94,7 @@ impl ModelChoice {
pub(crate) fn id(self) -> &'static str { pub(crate) fn id(self) -> &'static str {
match self { match self {
Self::DeepSeekV4Flash => "deepseek-v4-flash", Self::DeepSeekV4Flash => "deepseek-v4-flash",
Self::DeepSeekV4Flash0731 => "deepseek-v4-flash-0731",
Self::DeepSeekV4Pro => "deepseek-v4-pro", Self::DeepSeekV4Pro => "deepseek-v4-pro",
Self::Glm52 => "glm-5.2", Self::Glm52 => "glm-5.2",
} }
@@ -97,6 +111,7 @@ impl ModelChoice {
fn main_artifact(self) -> &'static Artifact { fn main_artifact(self) -> &'static Artifact {
match self { match self {
Self::DeepSeekV4Flash => &FLASH, Self::DeepSeekV4Flash => &FLASH,
Self::DeepSeekV4Flash0731 => &FLASH_0731,
Self::DeepSeekV4Pro => &PRO, Self::DeepSeekV4Pro => &PRO,
Self::Glm52 => &GLM, Self::Glm52 => &GLM,
} }
@@ -147,6 +162,7 @@ pub(crate) enum ManagedArtifactId {
DeepSeekV4Flash, DeepSeekV4Flash,
DeepSeekV4FlashMtp, DeepSeekV4FlashMtp,
DeepSeekV4FlashDspark, DeepSeekV4FlashDspark,
DeepSeekV4Flash0731,
DeepSeekV4Pro, DeepSeekV4Pro,
Glm52, Glm52,
} }
@@ -157,6 +173,7 @@ impl ManagedArtifactId {
Self::DeepSeekV4Flash | Self::DeepSeekV4FlashMtp | Self::DeepSeekV4FlashDspark => { Self::DeepSeekV4Flash | Self::DeepSeekV4FlashMtp | Self::DeepSeekV4FlashDspark => {
ModelChoice::DeepSeekV4Flash ModelChoice::DeepSeekV4Flash
} }
Self::DeepSeekV4Flash0731 => ModelChoice::DeepSeekV4Flash0731,
Self::DeepSeekV4Pro => ModelChoice::DeepSeekV4Pro, Self::DeepSeekV4Pro => ModelChoice::DeepSeekV4Pro,
Self::Glm52 => ModelChoice::Glm52, Self::Glm52 => ModelChoice::Glm52,
} }
@@ -167,6 +184,7 @@ impl ManagedArtifactId {
Self::DeepSeekV4Flash => &FLASH, Self::DeepSeekV4Flash => &FLASH,
Self::DeepSeekV4FlashMtp => &FLASH_MTP, Self::DeepSeekV4FlashMtp => &FLASH_MTP,
Self::DeepSeekV4FlashDspark => &FLASH_DSPARK, Self::DeepSeekV4FlashDspark => &FLASH_DSPARK,
Self::DeepSeekV4Flash0731 => &FLASH_0731,
Self::DeepSeekV4Pro => &PRO, Self::DeepSeekV4Pro => &PRO,
Self::Glm52 => &GLM, Self::Glm52 => &GLM,
} }
@@ -261,6 +279,7 @@ impl fmt::Display for ModelChoice {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self { formatter.write_str(match self {
Self::DeepSeekV4Flash => "DeepSeek V4 Flash", Self::DeepSeekV4Flash => "DeepSeek V4 Flash",
Self::DeepSeekV4Flash0731 => "DeepSeek V4 Flash 0731",
Self::DeepSeekV4Pro => "DeepSeek V4 Pro", Self::DeepSeekV4Pro => "DeepSeek V4 Pro",
Self::Glm52 => "GLM 5.2", Self::Glm52 => "GLM 5.2",
}) })

View File

@@ -325,17 +325,31 @@ mod tests {
#[test] #[test]
fn catalog_and_checksum_verification_are_explicit() { fn catalog_and_checksum_verification_are_explicit() {
assert_eq!(ModelChoice::from_id("glm-5.2"), Some(ModelChoice::Glm52)); assert_eq!(ModelChoice::from_id("glm-5.2"), Some(ModelChoice::Glm52));
assert_eq!(
ModelChoice::from_id("deepseek-v4-flash-0731"),
Some(ModelChoice::DeepSeekV4Flash0731)
);
assert!(ModelChoice::from_id("unknown").is_none()); assert!(ModelChoice::from_id("unknown").is_none());
assert_eq!( assert_eq!(
ModelChoice::DeepSeekV4Flash.main_artifact().size, ModelChoice::DeepSeekV4Flash.main_artifact().size,
86_720_111_488 86_720_111_488
); );
assert_eq!(ModelChoice::Glm52.main_artifact().size, 211_075_856_448); assert_eq!(ModelChoice::Glm52.main_artifact().size, 211_075_856_448);
assert_eq!(
ModelChoice::DeepSeekV4Flash0731.main_artifact().size,
86_720_111_520
);
assert_eq!( assert_eq!(
ModelChoice::DeepSeekV4Flash.artifacts(true, true).count(), ModelChoice::DeepSeekV4Flash.artifacts(true, true).count(),
3 3
); );
assert_eq!(ModelChoice::Glm52.artifacts(true, true).count(), 1); assert_eq!(ModelChoice::Glm52.artifacts(true, true).count(), 1);
assert_eq!(
ModelChoice::DeepSeekV4Flash0731
.artifacts(true, true)
.count(),
1
);
let id = SystemTime::now() let id = SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@@ -351,6 +365,11 @@ mod tests {
engine.mtp.as_deref().and_then(Path::file_name), engine.mtp.as_deref().and_then(Path::file_name),
Some(std::ffi::OsStr::new(FLASH_DSPARK.file_name)) Some(std::ffi::OsStr::new(FLASH_DSPARK.file_name))
); );
assert!(
engine_artifacts(ModelChoice::DeepSeekV4Flash0731, true, true, &models_path)
.mtp
.is_none()
);
let empty = Artifact { let empty = Artifact {
label: "empty", label: "empty",
file_name: "empty", file_name: "empty",