diff --git a/Cargo.toml b/Cargo.toml
index 4705281b..1fd51bb7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "candle-vllm"
-version = "0.2.1"
+version = "0.3.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/README-CN.md b/README-CN.md
index 599d1081..49f3c1a1 100644
--- a/README-CN.md
+++ b/README-CN.md
@@ -88,29 +88,25 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
### 构建/运行参数
-- [`ENV_PARAM`] cargo run [`BUILD_PARAM`] -- [`PROGRAM_PARAM`] [`MODEL_ID/MODEL_WEIGHT_PATH`] [`MODEL_TYPE`] [`MODEL_PARAM`]
+- [`ENV_PARAM`] cargo run [`BUILD_PARAM`] -- [`PROGRAM_PARAM`] [`MODEL_ID/MODEL_WEIGHT_PATH`]
显示详情
**示例:**
```shell
- [RUST_LOG=warn] cargo run [--release --features cuda,nccl] -- [--multi-process --log --dtype bf16 --p 2000 --d "0,1" --mem 8192] [--w /home/weights/Qwen3-27B-GPTQ-4Bit] [qwen3] [--quant gptq --temperature 0.7 --penalty 1.0 --top-k 32 --top-p 0.95 --thinking]
+ [RUST_LOG=warn] cargo run [--release --features cuda,nccl] -- [--log --dtype bf16 --p 2000 --d 0,1 --mem 8192] [--w /home/weights/Qwen3-27B-GPTQ-4Bit]
```
`ENV_PARAM`: RUST_LOG=warn
`BUILD_PARAM`: --release --features cuda,nccl
- `PROGRAM_PARAM`:--multi-process --log --dtype bf16 --p 2000 --d "0,1" --mem 8192
+ `PROGRAM_PARAM`:--log --dtype bf16 --p 2000 --d 0,1 --mem 8192
`MODEL_WEIGHT_PATH`: --w /home/weights/Qwen3-27B-GPTQ-4Bit
- `MODEL_TYPE`: qwen3
-
- `MODEL_PARAM`: --quant gptq --temperature 0.7 --penalty 1.0 --top-k 32 --top-p 0.95 --thinking
-
- 其中,`mem` (`kvcache-mem-gpu`) 参数控制KV Cache缓存,长文本或批量推理量请增大缓存;`MODEL_TYPE`可选值为:["llama", "llama3", "mistral", "phi2", "phi3", "qwen2", "qwen3", "glm4", "gemma", "gemma3", "yi", "stable-lm", "deep-seek"]
+ 其中,`mem` (`kvcache-mem-gpu`) 参数控制KV Cache缓存,长文本或批量推理量请增大缓存;支持的模型架构有:["llama", "llama3", "mistral", "phi2", "phi3", "qwen2", "qwen3", "glm4", "gemma", "gemma3", "yi", "stable-lm", "deep-seek"]
## 如何运行?
@@ -122,13 +118,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
**本地路径**
```shell
- target/release/candle-vllm --p 2000 --w /home/DeepSeek-R1-Distill-Llama-8B/ llama3 --temperature 0. --penalty 1.0
+ target/release/candle-vllm --w /home/DeepSeek-R1-Distill-Llama-8B/
```
**模型ID(从Huggingface下载)**
```shell
- target/release/candle-vllm --model-id deepseek-ai/DeepSeek-R1-0528-Qwen3-8B qwen3
+ target/release/candle-vllm --m deepseek-ai/DeepSeek-R1-0528-Qwen3-8B
```
@@ -140,13 +136,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
**本地路径(指定端口、数据类型、采样参数)**
```shell
- target/release/candle-vllm --p 2000 --dtype bf16 --f /home/data/DeepSeek-R1-0528-Qwen3-8B-Q2_K.gguf qwen3 --quant gguf --temperature 0.7 --penalty 1.1
+ target/release/candle-vllm --f /home/data/DeepSeek-R1-0528-Qwen3-8B-Q2_K.gguf
```
**模型ID(从Huggingface下载)**
```shell
- target/release/candle-vllm --model-id unsloth/DeepSeek-R1-0528-Qwen3-8B-GGUF --f DeepSeek-R1-0528-Qwen3-8B-Q2_K.gguf qwen3 --quant gguf
+ target/release/candle-vllm --m unsloth/DeepSeek-R1-0528-Qwen3-8B-GGUF --f DeepSeek-R1-0528-Qwen3-8B-Q2_K.gguf
```
@@ -158,13 +154,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
**本地路径(假设模型已下载到/home)**
```shell
- cargo run --release --features metal -- --p 2000 --dtype bf16 --f /home/qwq-32b-q4_k_m.gguf qwen2 --quant gguf --temperature 0. --penalty 1.0
+ cargo run --release --features metal -- --f /home/qwq-32b-q4_k_m.gguf qwen2
```
**模型ID(从Huggingface下载)**
```shell
- cargo run --release --features metal -- --p 2000 --dtype bf16 --model-id Qwen/QwQ-32B-GGUF --f qwq-32b-q4_k_m.gguf qwen2 --quant gguf --temperature 0. --penalty 1.0
+ cargo run --release --features metal -- --m Qwen/QwQ-32B-GGUF --f qwq-32b-q4_k_m.gguf
```
@@ -173,13 +169,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
显示命令
- **只需在运行未量化模型时添加`quant`参数**
+ **只需在运行未量化模型时添加`isq`参数**
```shell
- target/release/candle-vllm --p 2000 --w /home/DeepSeek-R1-Distill-Llama-8B/ llama3 --quant q4k --temperature 0. --penalty 1.0
+ target/release/candle-vllm --w /home/DeepSeek-R1-Distill-Llama-8B/ llama3 --isq q4k
```
- 注:原位量化加载可能需要更长的加载时间,原位`quant`参数选项:["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k"]
+ 注:原位量化加载可能需要更长的加载时间,原位`isq`参数选项:["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k"]
- 运行**Marlin兼容的GPTQ模型**(4位GPTQ,128分组,desc_act=False)
@@ -189,19 +185,19 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
**本地路径**
```shell
- target/release/candle-vllm --dtype bf16 --p 2000 --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g qwen2 --quant gptq --temperature 0. --penalty 1.0
+ target/release/candle-vllm --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g
```
**模型ID(从Huggingface下载)**
```shell
- target/release/candle-vllm --model-id thesven/Llama-3-8B-GPTQ-4bit llama3 --quant gptq
+ target/release/candle-vllm --m thesven/Llama-3-8B-GPTQ-4bit llama3
```
**将未压缩模型转换为Marlin兼容格式**
```shell
python3 examples/convert_marlin.py --src /home/DeepSeek-R1-Distill-Qwen-14B/ --dst /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g
- target/release/candle-vllm --dtype bf16 --p 2000 --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g qwen2 --quant gptq --temperature 0. --penalty 1.0
+ target/release/candle-vllm --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g
```
@@ -217,7 +213,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
**运行转换后的AWQ模型**
```shell
- target/release/candle-vllm --multi-process --dtype f16 --p 2000 --d "0" --w /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/ llama3 --quant awq --temperature 0. --penalty 1.0
+ target/release/candle-vllm --d 0 --w /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/
```
@@ -227,7 +223,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
显示命令
```shell
- target/release/candle-vllm --dtype bf16 --p 2000 --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ-Marlin/ qwen2 --quant marlin --penalty 1.0 --temperature 0.
+ target/release/candle-vllm --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ-Marlin/
```
@@ -238,7 +234,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
**在两块GPU上运行QwQ-32B BF16模型**
```shell
- cargo run --release --features cuda,nccl -- --multi-process --dtype bf16 --p 2000 --d "0,1" --w /home/QwQ-32B/ qwen2 --penalty 1.0 --temperature 0.
+ cargo run --release --features cuda,nccl -- --d 0,1 --w /home/QwQ-32B/
```
**在两块GPU上运行QwQ-32B 4位AWQ模型**
@@ -250,7 +246,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
2) 运行转换后的AWQ模型
```shell
- cargo run --release --features cuda,nccl -- --multi-process --dtype bf16 --p 2000 --d "0,1" --w /home/QwQ-32B-AWQ-Marlin/ qwen2 --quant awq --penalty 1.0 --temperature 0.
+ cargo run --release --features cuda,nccl -- --d 0,1 --w /home/QwQ-32B-AWQ-Marlin/
```
**注意**:使用的GPU数量(`--d`)必须为2的幂次方(例如2、4或8)。
@@ -260,11 +256,11 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
显示命令
- 只需移除`--multi-process`参数。
+ 只需添加`--multithread`参数。
**在两块GPU上运行QwQ-32B BF16模型**
```shell
- cargo run --release --features cuda,nccl -- --dtype bf16 --p 2000 --d "0,1" --w /home/QwQ-32B/ qwen2 --penalty 1.0 --temperature 0.
+ cargo run --release --features cuda,nccl -- --multithread --d 0,1 --w /home/QwQ-32B/
```
如果在多线程多GPU模式下遇到问题,可以尝试:
@@ -285,7 +281,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
**2. 在8块A100(40GB)上运行DeepSeek-R1模型**
```shell
- cargo run --release --features cuda,nccl -- --log --multi-process --dtype bf16 --p 2000 --d "0,1,2,3,4,5,6,7" --w /data/DeepSeek-R1-AWQ-Marlin/ deep-seek --quant awq --temperature 0. --penalty 1.0 --num-experts-offload-per-rank 15
+ cargo run --release --features cuda,nccl -- --log --d 0,1,2,3,4,5,6,7 --w /data/DeepSeek-R1-AWQ-Marlin/ --num-experts-offload-per-rank 15
```
**注意**:此设置将每个rank的15个专家(总共256个专家中的120个)卸载到CPU(需要约150GB的额外主机内存)。在推理过程中,这些卸载的专家会根据需要交换回GPU内存。如果GPU内存更少,可以增加`--num-experts-offload-per-rank`参数(最大支持每个rank卸载32个专家)。
@@ -322,7 +318,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
**4. 使用MPI运行器在两个节点上运行模型**
```shell
- sudo mpirun -np 16 -x RUST_LOG=info -hostfile ./hostfile --allow-run-as-root -bind-to none -map-by slot --mca plm_rsh_args "-p 22" --mca btl_tcp_if_include %NET_INTERFACE% target/release/candle-vllm --log --multi-process --dtype bf16 --p 2000 --d "0,1,2,3,4,5,6,7" --w /data/DeepSeek-R1-AWQ-Marlin/ deep-seek --quant awq --temperature 0. --penalty 1.0
+ sudo mpirun -np 16 -x RUST_LOG=info -hostfile ./hostfile --allow-run-as-root -bind-to none -map-by slot --mca plm_rsh_args "-p 22" --mca btl_tcp_if_include %NET_INTERFACE% target/release/candle-vllm --log --d 0,1,2,3,4,5,6,7 --w /data/DeepSeek-R1-AWQ-Marlin/
```
@@ -341,13 +337,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
如果你想使用全部 GPU 进行推理,下面的 NUMA 绑定配置可以获得最佳性能:
```shell
- MAP_NUMA_NODE=0,0,0,0,1,1,1,1 numactl --cpunodebind=0 --membind=0 cargo run --release --features cuda,nccl -- --multi-process --dtype bf16 --p 2000 --d "0,1,2,3,4,5,6,7" --w /home/data/DeepSeek-V2-Chat-AWQ-Marlin deep-seek --quant awq --temperature 0. --penalty 1.0
+ MAP_NUMA_NODE=0,0,0,0,1,1,1,1 numactl --cpunodebind=0 --membind=0 cargo run --release --features cuda,nccl -- --d 0,1,2,3,4,5,6,7 --w /home/data/DeepSeek-V2-Chat-AWQ-Marlin
```
如果你只使用 4 张 GPU,可以使用如下的 NUMA 绑定方式:
```shell
- MAP_NUMA_NODE=0,0,0,0 numactl --cpunodebind=0 --membind=0 cargo run --release --features cuda,nccl -- --multi-process --dtype bf16 --p 2000 --d "0,1,2,3" --w /home/data/DeepSeek-V2-Chat-AWQ-Marlin deep-seek --quant awq --temperature 0. --penalty 1.0
+ MAP_NUMA_NODE=0,0,0,0 numactl --cpunodebind=0 --membind=0 cargo run --release --features cuda,nccl -- --d 0,1,2,3 --w /home/data/DeepSeek-V2-Chat-AWQ-Marlin
```
以上命令中 `numactl --cpunodebind=0 --membind=0`指定了master进程(master rank)绑定的NUMA node,其必须与 `MAP_NUMA_NODE`相匹配。
@@ -361,7 +357,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
1) 启动`Qwen3-Reranker`模型服务
```shell
- target/release/candle-vllm --p 2000 --multi-process --f /home/data/Qwen3-Reranker-4B-q4_k_m.gguf qwen3 --quant gguf
+ target/release/candle-vllm --f /home/data/Qwen3-Reranker-4B-q4_k_m.gguf
```
2) 启动迷你聊天机器人并传入`system prompt`
@@ -574,12 +570,12 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
显示量化配置
- Candle-vllm支持在模型加载时将默认权重(F32/F16/BF16)转换为任何GGML/GGUF格式,或将`4位GPTQ/AWQ`权重转换为`Marlin`格式进行加速。此功能有助于节省GPU内存(或通过Marlin内核加速推理性能),使其更适合消费级GPU(例如RTX 4090)。要使用此功能,只需在运行candle-vllm时传递相应`quant`参数。
+ Candle-vllm支持在模型加载时将默认权重(F32/F16/BF16)转换为任何GGML/GGUF格式,或将`4位GPTQ/AWQ`权重转换为`Marlin`格式进行加速。此功能有助于节省GPU内存(或通过Marlin内核加速推理性能),使其更适合消费级GPU(例如RTX 4090)。要使用此功能,只需在运行candle-vllm时传递相应`isq`参数。
**对于未量化模型:**
```
- cargo run --release --features cuda -- --p 2000 --w /home/Meta-Llama-3.1-8B-Instruct/ llama3 --quant q4k
+ cargo run --release --features cuda -- --w /home/Meta-Llama-3.1-8B-Instruct/ llama3 --isq q4k
```
`quant`参数选项:["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k"]
@@ -587,7 +583,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
**对于4位GPTQ量化模型:**
```
- cargo run --release --features cuda -- --p 2000 --w /home/mistral_7b-int4/ mistral --quant marlin
+ cargo run --release --features cuda -- --w /home/mistral_7b-int4/ mistral --isq marlin
```
**关于Marlin的注意事项**:
@@ -613,7 +609,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
你可以传递`penalty`和`temperature`参数给模型以**防止潜在的重复**,例如:
```
- cargo run --release --features cuda -- --p 2000 --w /home/mistral_7b/ mistral --repeat-last-n 64 --penalty 1.1 --temperature 0.7
+ cargo run --release --features cuda -- --w /home/mistral_7b/
```
`--max-gen-tokens`参数用于控制每次聊天响应的最大输出令牌数。默认值将设置为`max_sequence_len`的1/5。
@@ -621,10 +617,10 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
对于`消费级GPU`,建议以GGML格式(或Marlin格式)运行模型,例如:
```
- cargo run --release --features cuda -- --p 2000 --w /home/Meta-Llama-3.1-8B-Instruct/ llama3 --quant q4k
+ cargo run --release --features cuda -- --w /home/Meta-Llama-3.1-8B-Instruct/ llama3 --isq q4k
```
- 其中`quant`可选值为:["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k", "awq", "gptq", "marlin", "gguf", "ggml"]。
+ 其中`isq`可选值为:["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k", "awq", "gptq", "marlin", "gguf", "ggml"]。
- **GPTQ/AWQ模型通过Marlin Kernel加速**
@@ -634,13 +630,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #同时包含flash att
Candle-vllm现在支持GPTQ/AWQ(Marlin内核),如果你有`Marlin`格式的量化权重,可以传递`quant`(marlin)参数,例如:
```shell
- cargo run --release --features cuda -- --p 2000 --dtype f16 --w /home/Meta-Llama-3.1-8B-Instruct-GPTQ-INT4-Marlin/ llama3 --quant marlin --temperature 0. --penalty 1.
+ cargo run --release --features cuda -- --w /home/Meta-Llama-3.1-8B-Instruct-GPTQ-INT4-Marlin/
```
或者,将现有的AWQ 4位模型转换为Marlin兼容格式:
```shell
python3 examples/convert_awq_marlin.py --src /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4/ --dst /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/ --bits 4 --method awq --group 128 --nk False
- cargo run --release --features cuda,nccl -- --multi-process --dtype f16 --p 2000 --d "0" --w /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/ llama3 --quant awq --temperature 0. --penalty 1.0
+ cargo run --release --features cuda,nccl -- --d 0 --w /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/
```
你也可以使用`GPTQModel`通过脚本`examples/convert_marlin.py`将模型转换为Marlin兼容格式。
diff --git a/README.md b/README.md
index a1d1d4d8..1042513b 100644
--- a/README.md
+++ b/README.md
@@ -95,22 +95,18 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
**Example:**
```shell
- [RUST_LOG=warn] cargo run [--release --features cuda,nccl] -- [--multi-process --log --dtype bf16 --p 2000 --d "0,1" --mem 8192] [--w /home/weights/Qwen3-27B-GPTQ-4Bit] [qwen3] [--quant gptq --temperature 0.7 --penalty 1.0 --top-k 32 --top-p 0.95 --thinking]
+ [RUST_LOG=warn] cargo run [--release --features cuda,nccl] -- [--log --dtype bf16 --p 2000 --d 0,1 --mem 8192] [--w /home/weights/Qwen3-27B-GPTQ-4Bit]
```
`ENV_PARAM`: RUST_LOG=warn
`BUILD_PARAM`: --release --features cuda,nccl
- `PROGRAM_PARAM`:--multi-process --log --dtype bf16 --p 2000 --d "0,1" --mem 8192
+ `PROGRAM_PARAM`:--log --dtype bf16 --p 2000 --d 0,1 --mem 8192
- `MODEL_WEIGHT_PATH`: --w /home/weights/Qwen3-27B-GPTQ-4Bit
+ `MODEL_WEIGHT_PATH`: --w /home/weights/Qwen3-27B-GPTQ-4Bit (or `--m` specify model-id)
- `MODEL_TYPE`: qwen3
-
- `MODEL_PARAM`: --quant gptq --temperature 0.7 --penalty 1.0 --top-k 32 --top-p 0.95 --thinking
-
- where, `--mem` (`kvcache-mem-gpu`) is the key parameter to control KV cache usage (increase this for large batch); `MODEL_TYPE` in ["llama", "llama3", "mistral", "phi2", "phi3", "qwen2", "qwen3", "glm4", "gemma", "gemma3", "yi", "stable-lm", "deep-seek"]
+ where, `--mem` (`kvcache-mem-gpu`) is the key parameter to control KV cache usage (increase this for large batch); supported model archs include ["llama", "llama3", "mistral", "phi2", "phi3", "qwen2", "qwen3", "glm4", "gemma", "gemma3", "yi", "stable-lm", "deep-seek"]
@@ -124,13 +120,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
**Local Path**
```shell
- target/release/candle-vllm --p 2000 --w /home/DeepSeek-R1-Distill-Llama-8B/ llama3 --temperature 0. --penalty 1.0
+ target/release/candle-vllm --p 2000 --w /home/DeepSeek-R1-Distill-Llama-8B/
```
**Model-ID (download from Huggingface)**
```shell
- target/release/candle-vllm --m deepseek-ai/DeepSeek-R1-0528-Qwen3-8B qwen3
+ target/release/candle-vllm --m deepseek-ai/DeepSeek-R1-0528-Qwen3-8B
```
@@ -142,13 +138,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
**Local Path (with port, dtype, sampling parameter specified)**
```shell
- target/release/candle-vllm --p 2000 --dtype bf16 --f /home/data/DeepSeek-R1-0528-Qwen3-8B-Q2_K.gguf qwen3 --quant gguf --temperature 0.7 --penalty 1.1
+ target/release/candle-vllm --f /home/data/DeepSeek-R1-0528-Qwen3-8B-Q2_K.gguf
```
**Model-ID (download from Huggingface)**
```shell
- target/release/candle-vllm --m unsloth/DeepSeek-R1-0528-Qwen3-8B-GGUF --f DeepSeek-R1-0528-Qwen3-8B-Q2_K.gguf qwen3 --quant gguf
+ target/release/candle-vllm --m unsloth/DeepSeek-R1-0528-Qwen3-8B-GGUF --f DeepSeek-R1-0528-Qwen3-8B-Q2_K.gguf
```
@@ -160,13 +156,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
**Local Path (assume model downloaded in /home)**
```shell
- cargo run --release --features metal -- --p 2000 --dtype bf16 --f /home/qwq-32b-q4_k_m.gguf qwen2 --quant gguf --temperature 0. --penalty 1.0
+ cargo run --release --features metal -- --f /home/qwq-32b-q4_k_m.gguf
```
**Model-ID (download from Huggingface)**
```shell
- cargo run --release --features metal -- --p 2000 --dtype bf16 --m Qwen/QwQ-32B-GGUF --f qwq-32b-q4_k_m.gguf qwen2 --quant gguf --temperature 0. --penalty 1.0
+ cargo run --release --features metal -- --m Qwen/QwQ-32B-GGUF --f qwq-32b-q4_k_m.gguf
```
@@ -175,13 +171,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
Show command
- **Simply add `quant` parameter when running unquantized models**
+ **Simply add `isq` parameter when running unquantized models**
```shell
- target/release/candle-vllm --p 2000 --w /home/DeepSeek-R1-Distill-Llama-8B/ llama3 --quant q4k --temperature 0. --penalty 1.0
+ target/release/candle-vllm --p 2000 --w /home/DeepSeek-R1-Distill-Llama-8B/ llama3 --isq q4k
```
- Options for in-site `quant` parameters: ["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k"]
+ Options for in-site `isq` parameters: ["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k"]
@@ -192,19 +188,19 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
**Local Path**
```shell
- target/release/candle-vllm --dtype bf16 --p 2000 --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g qwen2 --quant gptq --temperature 0. --penalty 1.0
+ target/release/candle-vllm --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g
```
**Model-ID (download from Huggingface)**
```shell
- target/release/candle-vllm --m thesven/Llama-3-8B-GPTQ-4bit llama3 --quant gptq
+ target/release/candle-vllm --m thesven/Llama-3-8B-GPTQ-4bit
```
**Convert Any uncompressed model to marlin-compatible format**
```shell
python3 examples/convert_marlin.py --src /home/DeepSeek-R1-Distill-Qwen-14B/ --dst /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g
- target/release/candle-vllm --dtype bf16 --p 2000 --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g qwen2 --quant gptq --temperature 0. --penalty 1.0
+ target/release/candle-vllm --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ_4bit-128g
```
@@ -220,7 +216,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
**Run the converted AWQ model**
```shell
- target/release/candle-vllm --multi-process --dtype f16 --p 2000 --d "0" --w /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/ llama3 --quant awq --temperature 0. --penalty 1.0
+ target/release/candle-vllm --d 0 --w /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/
```
@@ -230,7 +226,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
Show command
```shell
- target/release/candle-vllm --dtype bf16 --p 2000 --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ-Marlin/ qwen2 --quant marlin --penalty 1.0 --temperature 0.
+ target/release/candle-vllm --w /home/DeepSeek-R1-Distill-Qwen-14B-GPTQ-Marlin/
```
@@ -242,7 +238,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
**QwQ-32B BF16 model on two GPUs**
```shell
- cargo run --release --features cuda,nccl -- --multi-process --dtype bf16 --p 2000 --d "0,1" --w /home/QwQ-32B/ qwen2 --penalty 1.0 --temperature 0.
+ cargo run --release --features cuda,nccl -- --d 0,1 --w /home/QwQ-32B/
```
**QwQ-32B 4-bit AWQ model on two GPUs**
@@ -254,7 +250,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
2) Run the converted AWQ model
```shell
- cargo run --release --features cuda,nccl -- --multi-process --dtype bf16 --p 2000 --d "0,1" --w /home/QwQ-32B-AWQ-Marlin/ qwen2 --quant awq --penalty 1.0 --temperature 0.
+ cargo run --release --features cuda,nccl -- --d 0,1 --w /home/QwQ-32B-AWQ-Marlin/
```
**Note:** number of GPUs (`--d`) used must be aligned to 2^n (e.g., 2, 4, or 8).
@@ -264,11 +260,11 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
Show command
- Simply remove the `--multi-process` parameter
+ Simply add the `--multithread` parameter
**QwQ-32B BF16 model on two GPUs**
```shell
- cargo run --release --features cuda,nccl -- --dtype bf16 --p 2000 --d "0,1" --w /home/QwQ-32B/ qwen2 --penalty 1.0 --temperature 0.
+ cargo run --release --features cuda,nccl -- --multithread --d 0,1 --w /home/QwQ-32B/
```
If you encountered problems under Multi-threaded Multi-GPU mode, you may:
@@ -289,7 +285,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
**2. Run DeepSeek-R1 model on 8 x A100(40GB)**
```shell
- cargo run --release --features cuda,nccl -- --log --multi-process --dtype bf16 --p 2000 --d "0,1,2,3,4,5,6,7" --w /data/DeepSeek-R1-AWQ-Marlin/ deep-seek --quant awq --temperature 0. --penalty 1.0 --num-experts-offload-per-rank 15
+ cargo run --release --features cuda,nccl -- --log --d 0,1,2,3,4,5,6,7 --w /data/DeepSeek-R1-AWQ-Marlin/--num-experts-offload-per-rank 15
```
**Note:** This setup offloads 15 experts per rank (a total of 120 out of 256 experts) to the CPU (around 150GB additional host memory required). During inference, these offloaded experts are swapped back into GPU memory as needed. If you have even less GPU memory, consider increasing the `--num-experts-offload-per-rank` parameter (up to a maximum of 32 experts per rank in this case).
@@ -326,7 +322,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
**4. Run the model on two nodes with MPI runner**
```shell
- sudo mpirun -np 16 -x RUST_LOG=info -hostfile ./hostfile --allow-run-as-root -bind-to none -map-by slot --mca plm_rsh_args "-p 22" --mca btl_tcp_if_include %NET_INTERFACE% target/release/candle-vllm --log --multi-process --dtype bf16 --p 2000 --d "0,1,2,3,4,5,6,7" --w /data/DeepSeek-R1-AWQ-Marlin/ deep-seek --quant awq --temperature 0. --penalty 1.0
+ sudo mpirun -np 16 -x RUST_LOG=info -hostfile ./hostfile --allow-run-as-root -bind-to none -map-by slot --mca plm_rsh_args "-p 22" --mca btl_tcp_if_include %NET_INTERFACE% target/release/candle-vllm --log --d 0,1,2,3,4,5,6,7 --w /data/DeepSeek-R1-AWQ-Marlin/ deep-seek
```
@@ -344,13 +340,13 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
To achieve optimal performance during inference using all GPUs, use the following NUMA binding:
```shell
- MAP_NUMA_NODE=0,0,0,0,1,1,1,1 numactl --cpunodebind=0 --membind=0 target/release/candle-vllm --multi-process --dtype bf16 --p 2000 --d "0,1,2,3,4,5,6,7" --w /home/data/DeepSeek-V2-Chat-AWQ-Marlin deep-seek --quant awq --temperature 0. --penalty 1.0
+ MAP_NUMA_NODE=0,0,0,0,1,1,1,1 numactl --cpunodebind=0 --membind=0 target/release/candle-vllm --d 0,1,2,3,4,5,6,7 --w /home/data/DeepSeek-V2-Chat-AWQ-Marlin
```
To use only 4 GPUs, you can apply this NUMA binding:
```shell
- MAP_NUMA_NODE=0,0,0,0 numactl --cpunodebind=0 --membind=0 target/release/candle-vllm --multi-process --dtype bf16 --p 2000 --d "0,1,2,3" --w /home/data/DeepSeek-V2-Chat-AWQ-Marlin deep-seek --quant awq --temperature 0. --penalty 1.0
+ MAP_NUMA_NODE=0,0,0,0 numactl --cpunodebind=0 --membind=0 target/release/candle-vllm --d 0,1,2,3 --w /home/data/DeepSeek-V2-Chat-AWQ-Marlin
```
*where* `numactl --cpunodebind=0 --membind=0` above indicates NUMA binding for the master rank (master process) which should be matched to `MAP_NUMA_NODE`.
@@ -363,7 +359,7 @@ cargo build --release --features cuda,nccl,flash-attn,mpi #build with flash-attn
1) Start the backend service for `Qwen3-Reranker` model
```shell
- target/release/candle-vllm --p 2000 --multi-process --f /home/data/Qwen3-Reranker-4B-q4_k_m.gguf qwen3 --quant gguf
+ target/release/candle-vllm --p 2000 --f /home/data/Qwen3-Reranker-4B-q4_k_m.gguf
```
2) Start the chatbot with `system prompt` for qwen3-reranker
@@ -573,20 +569,20 @@ Chat frontend (any frontend compatible with openai API, simple options available
Show quantization config
- Candle-vllm supports in-situ quantization, allowing the transformation of default weights (F32/F16/BF16) into any GGML/GGUF format, or `4-bit GPTQ/AWQ` weights into `marlin format` during model loading. This feature helps conserve GPU memory and speedup inference performance, making it more efficient for consumer-grade GPUs (e.g., RTX 4090). To use this feature, simply supply the `quant` parameter when running candle-vllm.
+ Candle-vllm supports in-situ quantization, allowing the transformation of default weights (F32/F16/BF16) into any GGML/GGUF format, or `4-bit GPTQ/AWQ` weights into `marlin format` during model loading. This feature helps conserve GPU memory and speedup inference performance, making it more efficient for consumer-grade GPUs (e.g., RTX 4090). To use this feature, simply supply the `isq` parameter when running candle-vllm.
**For unquantized models:**
```
- cargo run --release --features cuda -- --p 2000 --w /home/Meta-Llama-3.1-8B-Instruct/ llama3 --quant q4k
+ cargo run --release --features cuda -- --p 2000 --w /home/Meta-Llama-3.1-8B-Instruct/ llama3 --isq q4k
```
- Options for `quant` parameters: ["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k"]
+ Options for `isq` parameters: ["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k"]
**For quantized 4-bit GPTQ model:**
```
- cargo run --release --features cuda -- --p 2000 --w /home/mistral_7b-int4/ mistral --quant marlin
+ cargo run --release --features cuda -- --p 2000 --w /home/mistral_7b-int4/
```
**Please note for marlin**:
@@ -608,10 +604,8 @@ Chat frontend (any frontend compatible with openai API, simple options available
For chat streaming, the `stream` flag in chat request need to be set to `True`.
- You may supply `penalty` and `temperature` to the model to **prevent potential repetitions**, for example:
-
```
- cargo run --release --features cuda -- --p 2000 --w /home/mistral_7b/ mistral --repeat-last-n 64 --penalty 1.1 --temperature 0.7
+ cargo run --release --features cuda -- --p 2000 --w /home/mistral_7b/
```
`--max-gen-tokens` parameter is used to control the maximum output tokens per chat response. The value will be set to 1/5 of max_sequence_len by default.
@@ -619,27 +613,27 @@ Chat frontend (any frontend compatible with openai API, simple options available
For `consumer GPUs`, it is suggested to run the models under GGML formats (or Marlin format), e.g.,
```
- cargo run --release --features cuda -- --p 2000 --w /home/Meta-Llama-3.1-8B-Instruct/ llama3 --quant q4k
+ cargo run --release --features cuda -- --p 2000 --w /home/Meta-Llama-3.1-8B-Instruct/ llama3 --isq q4k
```
- where `quant` is one of ["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k", "awq", "gptq", "marlin", "gguf", "ggml"].
+ where `isq` is one of ["q4_0", "q4_1", "q5_0", "q5_1", "q8_0", "q2k", "q3k","q4k","q5k","q6k", "awq", "gptq", "marlin", "gguf", "ggml"].
- **Use Marlin kernel to speedup GPTQ/AWQ models**
Show details
- Candle-vllm now supports GPTQ/AWQ Marlin kernel, you may supply the `quant` (marlin) parameter if you have `Marlin` format quantized weights, such as:
+ Candle-vllm now supports GPTQ/AWQ Marlin kernel, you can run these models directly, such as:
```shell
- cargo run --release --features cuda -- --p 2000 --dtype f16 --w /home/Meta-Llama-3.1-8B-Instruct-GPTQ-INT4-Marlin/ llama3 --quant marlin --temperature 0. --penalty 1.
+ cargo run --release --features cuda -- --dtype f16 --w /home/Meta-Llama-3.1-8B-Instruct-GPTQ-INT4-Marlin/
```
or, convert existing AWQ 4bit model to marlin compatible format
```shell
python3 examples/convert_awq_marlin.py --src /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4/ --dst /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/ --bits 4 --method awq --group 128 --nk False
- cargo run --release --features cuda,nccl -- --multi-process --dtype f16 --p 2000 --d "0" --w /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/ llama3 --quant awq --temperature 0. --penalty 1.0
+ cargo run --release --features cuda,nccl -- --dtype f16 --d 0 --w /home/Meta-Llama-3.1-8B-Instruct-AWQ-INT4-Marlin/
```
You may also use `GPTQModel` to transform a model to marlin-compatible format using the given script `examples/convert_marlin.py`.
diff --git a/src/backend/cache.rs b/src/backend/cache.rs
index d6dde5e2..4fdee730 100644
--- a/src/backend/cache.rs
+++ b/src/backend/cache.rs
@@ -1,5 +1,3 @@
-#[cfg(feature = "cuda")]
-use crate::{openai::responses::APIError, try_api};
#[cfg(feature = "metal")]
use candle_core::{
backend::BackendStorage, CpuStorage, Device, IndexOp, Layout, MetalDevice, MetalStorage,
@@ -9,7 +7,7 @@ use candle_core::{
use candle_core::{
cuda_backend::cudarc::driver::{CudaSlice, DevicePtr},
cuda_backend::CudaStorageSlice,
- Device, IndexOp, Storage, Tensor,
+ Device, IndexOp, Result, Storage, Tensor,
};
#[cfg(feature = "cuda")]
use kernels::ffi::{copy_blocks_bf16, copy_blocks_f16, copy_blocks_f32};
@@ -22,7 +20,7 @@ pub unsafe fn copy_blocks(
key_caches: Vec<&mut Tensor>,
value_caches: Vec<&mut Tensor>,
block_mapping: HashMap>,
-) -> Result<(), APIError> {
+) -> Result<()> {
use candle_core::DType;
let cache_dev = key_caches.first().unwrap().device();
@@ -30,18 +28,18 @@ pub unsafe fn copy_blocks(
panic!("Expected the key caches to be on a CUDA device.")
};
if !cache_dev.same_device(value_caches.first().unwrap().device()) {
- return Err(APIError::new(format!(
+ candle_core::bail!(
"`key` and `value` caches have different devices, got {:?} and {:?} respectively.",
cache_dev,
value_caches.first().unwrap().device()
- )));
+ )
}
if key_caches.first().unwrap().dtype() != value_caches.first().unwrap().dtype() {
- return Err(APIError::new(format!(
+ candle_core::bail!(
"Key and value caches have different types, got {:?} and {:?}.",
key_caches.first().unwrap().dtype(),
value_caches.first().unwrap().dtype()
- )));
+ )
}
let num_layers: u32 = key_caches.len().try_into().unwrap();
if num_layers == 0 {
@@ -55,8 +53,8 @@ pub unsafe fn copy_blocks(
let mut dtype = DType::F32;
for (key_cache, value_cache) in zip(&key_caches, &value_caches) {
- try_api!(key_cache.to_device(cache_dev));
- try_api!(value_cache.to_device(cache_dev));
+ key_cache.to_device(cache_dev)?;
+ value_cache.to_device(cache_dev)?;
let key_offset: u64 = key_cache
.storage_and_layout()
@@ -99,9 +97,7 @@ pub unsafe fn copy_blocks(
(ptr_key, ptr_value)
}
_ => {
- return Err(APIError::from(
- "only f32, f16 and bf16 input data type supported!",
- ));
+ candle_core::bail!("only f32, f16 and bf16 input data type supported!")
}
};
key_cache_ptrs.push(key_ptr + key_offset);
@@ -121,7 +117,10 @@ pub unsafe fn copy_blocks(
let value_cache_ptr = value_cache_ptrs.as_mut_ptr() as *mut core::ffi::c_void;
let block_mapping_ptr = block_mapping_vec.as_mut_ptr() as *const core::ffi::c_void;
- let numel_per_block: u32 = try_api!(key_caches.first().unwrap().i(0))
+ let numel_per_block: u32 = key_caches
+ .first()
+ .unwrap()
+ .i(0)?
.shape()
.dims()
.iter()
@@ -174,19 +173,23 @@ pub fn swap_blocks(
src: Tensor,
dst: &mut Tensor,
block_mapping: HashMap,
-) -> Result<(), APIError> {
+) -> Result<()> {
let block_size_in_bytes = src.dtype().size_in_bytes() * src.dims()[0];
match (src.device(), dst.device()) {
(Device::Cuda(src_dev), Device::Cuda(dst_dev)) => {
if src_dev.ordinal() != dst_dev.ordinal() {
- return Err(APIError::new(format!("Tensors must be on the same device to copy, got ordinals {} (src) and {} (dst).", src_dev.ordinal(), dst_dev.ordinal())))
+ candle_core::bail!("Tensors must be on the same device to copy, got ordinals {} (src) and {} (dst).", src_dev.ordinal(), dst_dev.ordinal())
}
let (src_storage, src_layout) = src.storage_and_layout();
let (dst_storage, dst_layout) = dst.storage_and_layout();
assert!(matches!(&*src_storage, Storage::Cuda(_)));
assert!(matches!(&*dst_storage, Storage::Cuda(_)));
- let Storage::Cuda(src_storage) = &*src_storage else { unreachable!() };
- let Storage::Cuda(dst_storage) = &*dst_storage else { unreachable!() };
+ let Storage::Cuda(src_storage) = &*src_storage else {
+ unreachable!()
+ };
+ let Storage::Cuda(dst_storage) = &*dst_storage else {
+ unreachable!()
+ };
let (src_ptr, dst_ptr) = match (&src_storage.slice, &dst_storage.slice) {
(CudaStorageSlice::BF16(slice_src), CudaStorageSlice::BF16(slice_dst)) => {
let ptr_src = *slice_src.slice(src_layout.start_offset()..).device_ptr();
@@ -204,7 +207,7 @@ pub fn swap_blocks(
(ptr_src, ptr_dst)
}
_ => {
- return Err(APIError::from("only f32, f16 and bf16 input data type supported!"));
+ candle_core::bail!("only f32, f16 and bf16 input data type supported!");
}
};
// let src_ptr = src_storage.as_cuda_slice::().map_err(APIError::from)?.device_ptr() + TryInto::::try_into(src_layout.start_offset()).unwrap();
@@ -214,10 +217,16 @@ pub fn swap_blocks(
let src_offset: u64 = (src_block_number * block_size_in_bytes).try_into().unwrap();
let dst_offset: u64 = (dst_block_number * block_size_in_bytes).try_into().unwrap();
// u8s because we copy by bytes
- let src_slice: CudaSlice = unsafe { src_dev.upgrade_device_ptr(src_ptr+src_offset, block_size_in_bytes) };
- let mut dst_slice = unsafe { dst_dev.upgrade_device_ptr(dst_ptr+dst_offset, block_size_in_bytes) };
-
- try_api!(src_dev.dtod_copy(&src_slice, &mut dst_slice));
+ let src_slice: CudaSlice = unsafe {
+ src_dev.upgrade_device_ptr(src_ptr + src_offset, block_size_in_bytes)
+ };
+ let mut dst_slice = unsafe {
+ dst_dev.upgrade_device_ptr(dst_ptr + dst_offset, block_size_in_bytes)
+ };
+
+ src_dev
+ .dtod_copy(&src_slice, &mut dst_slice)
+ .map_err(candle_core::Error::wrap)?;
}
}
(Device::Cpu, Device::Cuda(dst_dev)) => {
@@ -225,22 +234,34 @@ pub fn swap_blocks(
let (dst_storage, dst_layout) = dst.storage_and_layout();
assert!(matches!(&*src_storage, Storage::Cpu(_)));
assert!(matches!(&*dst_storage, Storage::Cuda(_)));
- let Storage::Cpu(src_storage) = &*src_storage else { unreachable!() };
- let Storage::Cuda(dst_storage) = &*dst_storage else { unreachable!() };
- let dst_ptr = dst_storage.as_cuda_slice::().map_err(APIError::from)?.device_ptr() + TryInto::::try_into(dst_layout.start_offset()).unwrap();
- let src_slice = try_api!(src_storage.as_slice());
+ let Storage::Cpu(src_storage) = &*src_storage else {
+ unreachable!()
+ };
+ let Storage::Cuda(dst_storage) = &*dst_storage else {
+ unreachable!()
+ };
+ let dst_ptr = dst_storage.as_cuda_slice::()?.device_ptr()
+ + TryInto::::try_into(dst_layout.start_offset()).unwrap();
+ let src_slice = src_storage.as_slice()?;
for (src_block_number, dst_block_number) in block_mapping {
let src_offset = src_block_number * block_size_in_bytes;
let dst_offset: u64 = (dst_block_number * block_size_in_bytes).try_into().unwrap();
// u8s because we copy by bytes
- let mut dst_slice: CudaSlice = unsafe { dst_dev.upgrade_device_ptr(dst_ptr+dst_offset, block_size_in_bytes) };
+ let mut dst_slice: CudaSlice = unsafe {
+ dst_dev.upgrade_device_ptr(dst_ptr + dst_offset, block_size_in_bytes)
+ };
- try_api!(dst_dev.htod_sync_copy_into(&src_slice[src_offset..src_offset+block_size_in_bytes], &mut dst_slice));
+ dst_dev
+ .htod_sync_copy_into(
+ &src_slice[src_offset..src_offset + block_size_in_bytes],
+ &mut dst_slice,
+ )
+ .map_err(candle_core::Error::wrap)?;
}
}
(src, dst) => {
- return Err(APIError::new(format!("Tensors must be on either the GPU or CPU to swap,, got {src:?} (src) and {dst:?} (dst).")))
+ candle_core::bail!("Tensors must be on either the GPU or CPU to swap,, got {src:?} (src) and {dst:?} (dst).")
}
}
diff --git a/src/backend/gguf.rs b/src/backend/gguf.rs
index 5a3e4e02..c197ce05 100644
--- a/src/backend/gguf.rs
+++ b/src/backend/gguf.rs
@@ -618,3 +618,15 @@ impl TryFrom> for NormalizerWrapper {
Ok(value)
}
}
+
+pub fn get_arch_and_num_of_layers(ct: gguf_file::Content) -> Result<(String, usize)> {
+ let md_get = |s: &str| match ct.metadata.get(s) {
+ None => candle_core::bail!("cannot find {s} in metadata"),
+ Some(v) => Ok(v),
+ };
+ let architecture = md_get("general.architecture")?.to_string()?;
+
+ let nlayers =
+ md_get(format!("{}.block_count", architecture.as_str()).as_str())?.to_u32()? as usize;
+ Ok((architecture.clone(), nlayers))
+}
diff --git a/src/backend/gptq.rs b/src/backend/gptq.rs
index c940ef1f..2c530eb8 100644
--- a/src/backend/gptq.rs
+++ b/src/backend/gptq.rs
@@ -1,15 +1,17 @@
+#[allow(unused_imports)]
use candle::backend::BackendStorage;
#[cfg(feature = "cuda")]
use candle::CudaStorage;
+#[allow(unused_imports)]
use candle::{CpuStorage, DType, Layout, Result, Shape, Storage, Tensor};
use candle_core as candle;
-use half::{bf16, f16};
#[cfg(feature = "cuda")]
use kernels::ffi::{
awq_repack, gemm_half_q_half_alt, gptq_repack, marlin_4bit_bf16, marlin_4bit_f16,
marlin_awq_4bit_bf16, marlin_awq_4bit_f16,
};
+#[allow(unused)]
struct GPTQMatMul {
qzeros: Option,
g_idx: Option,
@@ -228,8 +230,10 @@ impl candle::CustomOp3 for GPTQMatMul {
scale_l: &Layout,
) -> Result<(CudaStorage, Shape)> {
match x.dtype() {
- DType::F16 => self.cuda_fwd_t::(x, x_l, qweight, qweight_l, scale, scale_l),
- DType::BF16 => self.cuda_fwd_t::(x, x_l, qweight, qweight_l, scale, scale_l),
+ DType::F16 => self.cuda_fwd_t::(x, x_l, qweight, qweight_l, scale, scale_l),
+ DType::BF16 => {
+ self.cuda_fwd_t::(x, x_l, qweight, qweight_l, scale, scale_l)
+ }
dt => candle::bail!("GPTQMatMul is only supported for f16 and bf16 ({dt:?})"),
}
}
diff --git a/src/backend/mod.rs b/src/backend/mod.rs
index aa2b33f1..0a14563e 100644
--- a/src/backend/mod.rs
+++ b/src/backend/mod.rs
@@ -6,10 +6,11 @@ mod paged_attention;
pub fn get_or_load_func(
ptx_file: &'static str,
kernel_base: &str,
- dtype: DType,
+ dtype: candle_core::DType,
suffix: Option<&str>,
device: &CudaDevice,
) -> Result {
+ use candle_core::DType;
let spec = match dtype {
DType::U8 => "_u8",
DType::U32 => "_u32",
@@ -30,9 +31,9 @@ pub fn get_or_load_func(
.map_err(APIError::from)
}
+#[allow(unused_imports)]
use crate::openai::responses::APIError;
pub use cache::*;
-use candle_core::DType;
#[cfg(feature = "cuda")]
use candle_core::{cuda_backend::cudarc::driver::CudaFunction, CudaDevice};
pub use gptq::*;
diff --git a/src/backend/paged_attention.rs b/src/backend/paged_attention.rs
index a004b050..2be3682e 100644
--- a/src/backend/paged_attention.rs
+++ b/src/backend/paged_attention.rs
@@ -5,8 +5,6 @@ use candle::CudaStorage;
use candle::MetalStorage;
use candle::{CpuStorage, DType, Layout, Result, Shape, Storage, Tensor};
use candle_core as candle;
-use half::{bf16, f16};
-use std::ffi::c_int;
#[allow(dead_code)]
struct PagedAttention {
softmax_scale: f32,
@@ -30,6 +28,7 @@ impl PagedAttention {
) -> Result<(CudaStorage, Shape)> {
use candle::cuda_backend::cudarc::driver::DevicePtr;
use candle::cuda_backend::WrapErr;
+ use core::ffi::c_int;
let dtype = q.dtype();
let internal_type = match dtype {
DType::F16 => 0,
@@ -480,8 +479,8 @@ impl candle::CustomOp1 for PagedAttention {
fn cuda_fwd(&self, q: &CudaStorage, q_l: &Layout) -> Result<(CudaStorage, Shape)> {
match q.dtype() {
DType::F32 => self.cuda_fwd_t::(q, q_l),
- DType::F16 => self.cuda_fwd_t::(q, q_l),
- DType::BF16 => self.cuda_fwd_t::(q, q_l),
+ DType::F16 => self.cuda_fwd_t::(q, q_l),
+ DType::BF16 => self.cuda_fwd_t::(q, q_l),
dt => candle::bail!("paged-attention is only supported for f32/f16/bf16 ({dt:?})"),
}
}
@@ -557,6 +556,7 @@ impl ReshapeCache {
slot_mapping: &Tensor,
) -> Result<()> {
use candle::cuda_backend::cudarc::driver::DevicePtr;
+ use core::ffi::c_int;
let dtype = k.dtype();
let dev = k.device();
let internal_type = match dtype {
@@ -842,7 +842,7 @@ impl candle::InplaceOp1 for ReshapeCache {
&self.value_cache,
&self.slot_mapping,
),
- DType::F16 => self.cuda_fwd_t::(
+ DType::F16 => self.cuda_fwd_t::(
k,
k_l,
&self.value,
@@ -850,7 +850,7 @@ impl candle::InplaceOp1 for ReshapeCache {
&self.value_cache,
&self.slot_mapping,
),
- DType::BF16 => self.cuda_fwd_t::(
+ DType::BF16 => self.cuda_fwd_t::(
k,
k_l,
&self.value,
diff --git a/src/lib.rs b/src/lib.rs
index c1ecd4ec..312f69f8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,839 +2,12 @@
use candle::utils::{cuda_is_available, metal_is_available};
use candle::{Device, Result};
use candle_core as candle;
-use clap::Subcommand;
-use openai::pipelines::pipeline::DefaultLoader;
-use std::fmt::Display;
use std::path::Path;
use tracing::warn;
pub mod backend;
pub mod openai;
pub mod paged_attention;
pub mod scheduler;
-#[derive(Debug, Subcommand)]
-pub enum ModelSelected {
- /// Select the llama model (default llama2-7b).
- Llama {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
- },
-
- /// Select the llama3 model (default llama3.1-8b).
- Llama3 {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
-
- #[arg(long, default_value_t = false)]
- thinking: bool,
- },
-
- /// Select the phi2 model (default 2.7b).
- Phi2 {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
- },
-
- /// Select the phi3 model (default 3.8b).
- Phi3 {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
- },
-
- /// Select the qwen model (default 1.8b).
- Qwen2 {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
- },
-
- Qwen3 {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
-
- #[arg(long, default_value_t = false)]
- thinking: bool,
- },
-
- /// Select the gemma model (default 2b).
- Gemma {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
- },
-
- Gemma3 {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
-
- #[arg(long, default_value_t = false)]
- thinking: bool,
- },
-
- /// Select the mistral model (default 7b).
- Mistral {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
- },
-
- /// Select the Yi model (default 6b).
- Yi {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
- },
-
- /// Select the stable-lm model (default zephyr-3b).
- StableLM {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
- },
-
- GLM4 {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
- },
-
- /// Select the deepseek model (default deepseek-v2-lite-chat).
- DeepSeek {
- /// Control the application of repeat penalty for the last n tokens
- #[arg(long)]
- repeat_last_n: Option,
-
- #[arg(long)]
- temperature: Option,
-
- #[arg(long)]
- top_p: Option,
-
- #[arg(long)]
- top_k: Option,
-
- #[arg(long)]
- penalty: Option,
-
- #[arg(long)]
- max_gen_tokens: Option,
-
- #[arg(long)]
- quant: Option,
-
- //the number of experts offloaded per rank,
- //suppose there are 256 experts in total which split into 8 devices (rank 8),
- //each rank has 32 experts, num-experts-offload-per-rank=16 means
- //half of the experts can be offloaded to cpu memory
- #[arg(long)]
- num_experts_offload_per_rank: Option,
-
- #[arg(long, default_value_t = false)]
- thinking: bool,
- },
-}
-
-impl Display for ModelSelected {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- ModelSelected::Llama { .. } => write!(f, "llama"),
- ModelSelected::Llama3 { .. } => write!(f, "llama3"),
- ModelSelected::Phi2 { .. } => write!(f, "phi2"),
- ModelSelected::Phi3 {
- repeat_last_n: _,
- temperature: _,
- top_k: _,
- top_p: _,
- penalty: _,
- max_gen_tokens: _,
- quant: _,
- } => write!(f, "phi3"),
- ModelSelected::Qwen2 {
- repeat_last_n: _,
- temperature: _,
- top_k: _,
- top_p: _,
- penalty: _,
- max_gen_tokens: _,
- quant: _,
- } => write!(f, "qwen2"),
- ModelSelected::Qwen3 {
- repeat_last_n: _,
- temperature: _,
- top_k: _,
- top_p: _,
- penalty: _,
- max_gen_tokens: _,
- quant: _,
- thinking: _,
- } => write!(f, "qwen3"),
- ModelSelected::Gemma { .. } => write!(f, "gemma"),
- ModelSelected::Gemma3 { .. } => write!(f, "gemma3"),
- ModelSelected::Mistral { .. } => write!(f, "mistral"),
- ModelSelected::Yi { .. } => write!(f, "yi"),
- ModelSelected::StableLM { .. } => write!(f, "stablelm"),
- ModelSelected::GLM4 { .. } => write!(f, "glm4"),
- ModelSelected::DeepSeek { .. } => write!(f, "deepseek"),
- }
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct SpecificConfig {
- repeat_last_n: Option,
- temperature: Option,
- top_k: Option,
- top_p: Option,
- penalty: Option,
- max_gen_tokens: Option,
- quant: Option,
- num_experts_offload_per_rank: Option,
- thinking: bool,
-}
-
-impl SpecificConfig {
- pub fn new(
- repeat_last_n: Option,
- temperature: Option,
- top_k: Option,
- top_p: Option,
- penalty: Option,
- max_gen_tokens: Option,
- quant: Option,
- num_experts_offload_per_rank: Option,
- thinking: bool,
- ) -> Self {
- Self {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- num_experts_offload_per_rank,
- thinking,
- }
- }
-}
-
-pub fn get_model_loader(
- selected_model: ModelSelected,
- model_id: Option,
-) -> (Box, String, Option) {
- match selected_model {
- ModelSelected::Llama {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- false,
- ),
- "llama".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "meta-llama/Llama-2-7b-chat-hf".to_string()
- },
- quant,
- ),
- ModelSelected::Llama3 {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- thinking,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- thinking,
- ),
- "llama3".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "meta-llama/Meta-Llama-3.1-8B-Instruct".to_string()
- },
- quant,
- ),
- ModelSelected::Phi2 {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- false,
- ),
- "phi2".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "microsoft/phi-2".to_string()
- },
- quant,
- ),
- ModelSelected::Phi3 {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- false,
- ),
- "phi3".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "microsoft/Phi-3-mini-4k-instruct".to_string()
- },
- quant,
- ),
- ModelSelected::Qwen2 {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- false,
- ),
- "qwen2".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "Qwen/Qwen1.5-1.8B-Chat".to_string()
- },
- quant,
- ),
- ModelSelected::Qwen3 {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- thinking,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- thinking,
- ),
- "qwen3".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "Qwen/Qwen3-8B".to_string()
- },
- quant,
- ),
- ModelSelected::Gemma {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- false,
- ),
- "gemma".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "google/gemma-2b-it".to_string()
- },
- quant,
- ),
- ModelSelected::Gemma3 {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- thinking,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- thinking,
- ),
- "gemma3".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "google/gemma-3-4b-it".to_string()
- },
- quant,
- ),
- ModelSelected::Mistral {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- false,
- ),
- "mistral".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "mistralai/Mistral-7B-Instruct-v0.3".to_string()
- },
- quant,
- ),
-
- ModelSelected::Yi {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- false,
- ),
- "yi".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "01-ai/Yi-6B-Chat".to_string()
- },
- quant,
- ),
-
- ModelSelected::StableLM {
- repeat_last_n,
- temperature,
- penalty,
- max_gen_tokens,
- quant,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- None,
- None,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- false,
- ),
- "stablelm".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "stabilityai/stablelm-zephyr-3b".to_string()
- },
- quant,
- ),
- ModelSelected::GLM4 {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- None,
- false,
- ),
- "glm4".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "ZhipuAI/GLM-4-9B-0414".to_string()
- },
- quant,
- ),
- ModelSelected::DeepSeek {
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant,
- num_experts_offload_per_rank,
- thinking,
- } => (
- Box::new(DefaultLoader::new(
- SpecificConfig::new(
- repeat_last_n,
- temperature,
- top_k,
- top_p,
- penalty,
- max_gen_tokens,
- quant.clone(),
- num_experts_offload_per_rank,
- thinking,
- ),
- "deepseek".to_string(),
- )),
- if let Some(model_id) = model_id {
- model_id
- } else {
- "deepseek-ai/DeepSeek-V2-Lite-Chat".to_string()
- },
- quant,
- ),
- }
-}
pub fn hub_load_local_safetensors(
path: &String,
diff --git a/src/main.rs b/src/main.rs
index aead678c..08307f1a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,23 +3,20 @@ use axum::{
routing::post,
Router,
};
-use candle_core::{DType, Device};
+use candle_core::{DType, Device, Result};
#[cfg(feature = "nccl")]
use candle_vllm::backend::heartbeat;
use candle_vllm::openai::openai_server::chat_completions;
use candle_vllm::openai::pipelines::llm_engine::LLMEngine;
-use candle_vllm::openai::pipelines::pipeline::DefaultModelPaths;
-use candle_vllm::openai::responses::APIError;
+use candle_vllm::openai::pipelines::pipeline::DefaultLoader;
use candle_vllm::openai::OpenAIServerData;
use candle_vllm::scheduler::cache_engine::{CacheConfig, CacheEngine};
use candle_vllm::scheduler::SchedulerConfig;
-use candle_vllm::{get_model_loader, hub_load_local_safetensors, ModelSelected};
use clap::Parser;
-use std::{path::PathBuf, sync::Arc};
+use std::sync::Arc;
use tracing::{info, warn};
const SIZE_IN_MB: usize = 1024 * 1024;
use candle_vllm::openai::models::Config;
-use std::path::Path;
use tokio::sync::Notify;
use tower_http::cors::{AllowOrigin, CorsLayer};
#[derive(Parser, Debug)]
@@ -35,16 +32,13 @@ struct Args {
hf_token_path: Option,
/// Port to serve on (localhost:port)
- #[arg(long = "p")]
+ #[arg(long = "p", default_value_t = 2000)]
port: u16,
/// Set verbose mode (print all requests)
#[arg(long)]
verbose: bool,
- #[clap(subcommand)]
- command: ModelSelected,
-
/// Maximum number of sequences to allow
#[arg(long, default_value_t = 256)]
max_num_seqs: usize,
@@ -69,6 +63,9 @@ struct Args {
#[arg(long)]
dtype: Option,
+ #[arg(long)]
+ isq: Option,
+
#[arg(long, default_value_t = false)]
cpu: bool,
@@ -92,9 +89,9 @@ struct Args {
#[arg(long, default_value_t = 500)]
holding_time: usize,
- //Whether the program running in multiprocess or multithread model for parallel inference
+ //Whether the program is forced running in multithread model for parallel inference (for debug)
#[arg(long, default_value_t = false)]
- multi_process: bool,
+ multithread: bool,
#[arg(long, default_value_t = false)]
log: bool,
@@ -105,20 +102,21 @@ fn get_cache_config(
kvcache_mem_cpu: usize,
block_size: usize,
config: &Config,
+ kv_dtype: DType,
num_shards: usize,
) -> CacheConfig {
- let dsize = config.kv_cache_dtype.size_in_bytes();
+ let dsize = kv_dtype.size_in_bytes();
let num_gpu_blocks = kvcache_mem_gpu * SIZE_IN_MB
/ dsize
/ block_size
- / (config.num_key_value_heads / num_shards)
+ / (config.num_key_value_heads.unwrap() / num_shards)
/ config.k_head_dim()
/ config.num_hidden_layers
/ 2;
let num_cpu_blocks = kvcache_mem_cpu * SIZE_IN_MB
/ dsize
/ block_size
- / (config.num_key_value_heads / num_shards)
+ / (config.num_key_value_heads.unwrap() / num_shards)
/ config.k_head_dim()
/ config.num_hidden_layers
/ 2;
@@ -127,15 +125,11 @@ fn get_cache_config(
num_gpu_blocks: Some(num_gpu_blocks),
num_cpu_blocks: Some(num_cpu_blocks),
fully_init: true,
- dtype: config.kv_cache_dtype,
+ dtype: kv_dtype,
}
}
-fn config_log(
- logger: ftail::Ftail,
- log_enable: bool,
- log_file: String,
-) -> Result<(), ftail::error::FtailError> {
+fn config_log(logger: ftail::Ftail, log_enable: bool, log_file: String) -> Result<()> {
if !log_enable {
return Ok(());
}
@@ -165,10 +159,12 @@ fn config_log(
.console(cfg_filter)
.single_file(log_file.as_str(), true, cfg_filter)
.init()
+ .map_err(candle_core::Error::wrap)
}
#[tokio::main]
-async fn main() -> Result<(), APIError> {
+#[allow(unused_mut)]
+async fn main() -> Result<()> {
let args = Args::parse();
if !args.log {
tracing_subscriber::fmt()
@@ -176,90 +172,13 @@ async fn main() -> Result<(), APIError> {
.init();
}
- let (loader, model_id, quant) = get_model_loader(args.command, args.model_id.clone());
- if args.model_id.is_none() && args.weight_path.is_none() && args.weight_file.is_none() {
- info!("No model id specified, using the default model_id or specified in the weight_path to retrieve config files!");
- }
+ let loader = Box::new(DefaultLoader::new(
+ args.model_id,
+ args.weight_path,
+ args.weight_file,
+ ));
- let paths = match (&args.weight_path, &args.weight_file) {
- //model in a folder (safetensor format, huggingface folder structure)
- (Some(path), None) => DefaultModelPaths {
- tokenizer_filename: Path::new(path).join("tokenizer.json"),
- tokenizer_config_filename: Path::new(path).join("tokenizer_config.json"),
- config_filename: Path::new(path).join("config.json"),
- filenames: if Path::new(path)
- .join("model.safetensors.index.json")
- .exists()
- {
- hub_load_local_safetensors(path, "model.safetensors.index.json").unwrap()
- } else {
- //a single weight file case
- let mut safetensors_files = Vec::::new();
- safetensors_files.insert(0, Path::new(path).join("model.safetensors"));
- safetensors_files
- },
- },
- //model in a quantized file (gguf/ggml format)
- (path, Some(file)) => DefaultModelPaths {
- tokenizer_filename: PathBuf::new(),
- tokenizer_config_filename: PathBuf::new(),
- config_filename: PathBuf::new(),
- filenames: {
- let path = path.clone().unwrap_or("".to_string());
- if Path::new(&path).join(file).exists() {
- vec![Path::new(&path).join(file)]
- } else {
- panic!("Model file not found {file}");
- }
- },
- },
- _ => {
- //try download model anonymously
- let loaded = loader.download_model(
- model_id.clone(),
- args.weight_file.clone(),
- quant.clone(),
- None,
- args.hf_token.clone(),
- args.hf_token_path.clone(),
- );
- if loaded.is_ok() {
- loaded.unwrap()
- } else {
- //if it's failed, try using huggingface token
- info!("Try request model using cached huggingface token...");
- if args.hf_token.is_none() && args.hf_token_path.is_none() {
- //no token provided
- let token_path = format!(
- "{}/.cache/huggingface/token",
- dirs::home_dir()
- .ok_or(APIError::new_str("No home directory"))?
- .display()
- );
- if !Path::new(&token_path).exists() {
- //also no token cache
- use std::io::Write;
- let mut input_token = String::new();
- warn!("Unable to request model, please provide your huggingface token to download model:\n");
- std::io::stdin()
- .read_line(&mut input_token)
- .expect("Failed to read token!");
- std::fs::create_dir_all(Path::new(&token_path).parent().unwrap()).unwrap();
- let mut output = std::fs::File::create(token_path).unwrap();
- write!(output, "{}", input_token.trim()).expect("Failed to save token!");
- }
- }
- loader.download_model(
- model_id,
- args.weight_file,
- quant.clone(),
- None,
- args.hf_token,
- args.hf_token_path,
- )?
- }
- }
- };
+ let (paths, gguf) = loader.prepare_model_weights(args.hf_token, args.hf_token_path)?;
let dtype = match args.dtype.as_deref() {
Some("f16") => DType::F16,
@@ -281,17 +200,29 @@ async fn main() -> Result<(), APIError> {
"More than one shard was given, but NCCL is not enabled for parallel inference!"
);
- if num_shards > 1
- && quant.is_some()
- && matches!(quant.as_ref().unwrap().as_str(), "ggml" | "gguf")
- {
+ if gguf && num_shards > 1 {
panic!("Multiple device-ids detected: ggml/gguf model is not supported for multi-rank inference!");
}
- let logger = ftail::Ftail::new();
+ if gguf && args.isq.is_some() {
+ panic!("Quantized gguf/ggml model does not support isq option!");
+ }
+
+ let multi_process = if num_shards > 1 {
+ if args.multithread {
+ tracing::warn!("The program is forced running under multithread mode (for debug purpose), which may not stable!");
+ false
+ } else {
+ tracing::warn!("Multi-process mode is automatically enabled for multi-rank inference!");
+ true
+ }
+ } else {
+ !args.multithread
+ };
+ let logger: ftail::Ftail = ftail::Ftail::new();
let mut port = args.port;
#[cfg(feature = "nccl")]
- let (pipelines, global_rank, daemon_manager) = if args.multi_process {
+ let (pipelines, global_rank, daemon_manager) = if multi_process {
use candle_vllm::openai::communicator::init_subprocess;
let (id, local_rank, global_rank, global_world_size, daemon_manager) =
init_subprocess(device_ids.clone()).unwrap();
@@ -310,7 +241,8 @@ async fn main() -> Result<(), APIError> {
.load_model(
paths,
dtype,
- &quant,
+ gguf,
+ args.isq.clone(),
vec![device_ids[local_rank]],
Some(id),
Some(local_rank),
@@ -330,7 +262,16 @@ async fn main() -> Result<(), APIError> {
(
loader
.load_model(
- paths, dtype, &quant, device_ids, None, None, None, None, None,
+ paths,
+ dtype,
+ gguf,
+ args.isq.clone(),
+ device_ids,
+ None,
+ None,
+ None,
+ None,
+ None,
)
.await,
0,
@@ -341,7 +282,7 @@ async fn main() -> Result<(), APIError> {
#[cfg(feature = "nccl")]
info!(
"parallel model: {}!",
- if args.multi_process {
+ if multi_process {
"multiprocess"
} else {
"multithread"
@@ -354,7 +295,7 @@ async fn main() -> Result<(), APIError> {
let _ = config_log(logger, args.log, log_file);
(
loader
- .load_model(paths, dtype, &quant, device_ids, None, None)
+ .load_model(paths, dtype, gguf, args.isq.clone(), device_ids, None, None)
.await,
0,
)
@@ -371,11 +312,17 @@ async fn main() -> Result<(), APIError> {
.into_iter()
.map(|pipeline| {
let cfg = pipeline.get_model_config();
+ let kv_dtype = if matches!(pipeline.name(), "phi2" | "PhiForCausalLM") {
+ DType::F32
+ } else {
+ dtype
+ };
let cache_cfg = get_cache_config(
args.kvcache_mem_gpu,
args.kvcache_mem_cpu, //dummy 512MB for cpu
args.block_size,
&cfg,
+ kv_dtype,
num_shards,
);
let cache_engine = CacheEngine::new(
@@ -410,7 +357,7 @@ async fn main() -> Result<(), APIError> {
Arc::new(Notify::new()),
args.holding_time,
num_shards,
- args.multi_process,
+ multi_process,
#[cfg(feature = "nccl")]
daemon_manager,
)?;
@@ -429,7 +376,7 @@ async fn main() -> Result<(), APIError> {
}
#[cfg(feature = "nccl")]
- if args.multi_process {
+ if multi_process {
let e = server_data.model.read();
let mut daemon_manager = e.daemon_manager.write();
daemon_manager.as_mut().unwrap().mpi_sync();
@@ -462,10 +409,10 @@ async fn main() -> Result<(), APIError> {
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{port}"))
.await
- .map_err(|e| APIError::new(e.to_string()))?;
+ .map_err(candle_core::Error::wrap)?;
axum::serve(listener, app)
.await
- .map_err(|e| APIError::new(e.to_string()))?;
+ .map_err(candle_core::Error::wrap)?;
Ok(())
}
diff --git a/src/openai/mod.rs b/src/openai/mod.rs
index e2f57475..812ffb05 100644
--- a/src/openai/mod.rs
+++ b/src/openai/mod.rs
@@ -39,12 +39,6 @@ where
pub struct PipelineConfig {
pub max_model_len: usize,
pub default_max_tokens: usize,
- pub penalty: f32,
- pub repeat_last_n: usize,
- pub temperature: Option,
- pub top_k: Option,
- pub top_p: Option,
- pub thinking: Option,
}
#[derive(Deserialize, Debug, Clone)]
diff --git a/src/openai/models/deepseek.rs b/src/openai/models/deepseek.rs
index 99c56e5f..f6d9afb9 100644
--- a/src/openai/models/deepseek.rs
+++ b/src/openai/models/deepseek.rs
@@ -1,7 +1,6 @@
#![allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)]
use super::{
- Config, DeepSeekRopeScaling, MoEConfig, QuantConfig, ScoringFunc, SpecificConfig, TokenID,
- TopkMethod,
+ Config, DeepSeekRopeScaling, MoEConfig, QuantConfig, ScoringFunc, TokenID, TopkMethod,
};
use crate::backend::custom_ops::moe::{masked_fill, NonZeroOp, SplitOp, TopKLastDimOp, TopKOutput};
use crate::backend::progress::{ProgressLike, ProgressReporter};
@@ -19,6 +18,7 @@ use std::cell::{Cell, RefCell};
use std::collections::HashSet;
use std::f32::consts::PI;
use std::iter::{zip, FromIterator};
+use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{Arc, RwLock};
@@ -39,7 +39,7 @@ serde_default_fn!(usize, first_k_dense_replace, 0);
serde_default_fn!(bool, norm_topk_prob, false);
serde_default_fn!(ScoringFunc, scoring_func, ScoringFunc::Softmax);
serde_default_fn!(Activation, hidden_act, Activation::Silu);
-// serde_default_fn!(bool, tie_word_embeddings, false);
+serde_default_fn!(bool, tie_word_embeddings, false);
#[derive(Deserialize, Clone, Debug)]
pub struct DeepSeekConfig {
@@ -70,8 +70,8 @@ pub struct DeepSeekConfig {
pub(crate) hidden_act: Activation,
pub(crate) max_position_embeddings: usize,
pub(crate) rms_norm_eps: f64,
- // #[serde(default = "tie_word_embeddings")]
- // pub(crate) tie_word_embeddings: bool,
+ #[serde(default = "tie_word_embeddings")]
+ pub(crate) tie_word_embeddings: bool,
pub(crate) rope_theta: f32,
pub(crate) rope_scaling: Option,
// pub(crate) attention_bias: bool,
@@ -94,68 +94,105 @@ pub struct DeepSeekV2RotaryEmbedding {
cos: Tensor,
}
-impl DeepSeekConfig {
- pub fn into_config(
- self,
- use_flash_attn: bool,
- kv_cache_dtype: DType,
- scfg: &SpecificConfig,
- ) -> Config {
+impl DeepSeek {
+ pub fn load_config(filename: &PathBuf, isq: Option) -> Result {
+ let config = match std::fs::read(filename.clone()) {
+ Ok(f) => {
+ let config: DeepSeekConfig =
+ serde_json::from_slice(&f).map_err(candle_core::Error::wrap)?;
+ config
+ }
+ Err(e) => panic!("Unable to load config file {:?}", e),
+ };
+
+ let num_experts_offload_per_rank = if let Ok(num_experts_offload_per_rank) =
+ std::env::var("NUM_EXPERTS_OFFLOAD_PER_RANK")
+ {
+ let number: usize = num_experts_offload_per_rank
+ .trim()
+ .parse::()
+ .expect("Failed to parse num_experts_offload_per_rank to number");
+ Some(number)
+ } else {
+ None
+ };
+
let moe_config = MoEConfig {
- num_experts_per_tok: self.num_experts_per_tok,
- n_routed_experts: self.n_routed_experts.unwrap_or(0),
- moe_intermediate_size: self.moe_intermediate_size,
- scoring_func: self.scoring_func,
- topk_method: self.topk_method,
- norm_topk_prob: self.norm_topk_prob,
- routed_scaling_factor: self.routed_scaling_factor,
- n_shared_experts: self.n_shared_experts,
- qk_nope_head_dim: self.qk_nope_head_dim,
- qk_rope_head_dim: self.qk_rope_head_dim,
- v_head_dim: self.v_head_dim,
- kv_lora_rank: self.kv_lora_rank,
- first_k_dense_replace: self.first_k_dense_replace,
- moe_layer_freq: self.moe_layer_freq,
- rope_scaling: self.rope_scaling,
- q_lora_rank: self.q_lora_rank,
- n_group: self.n_group,
- topk_group: self.topk_group,
- num_experts_offload_per_rank: scfg.num_experts_offload_per_rank,
+ num_experts_per_tok: config.num_experts_per_tok,
+ n_routed_experts: config.n_routed_experts.unwrap_or(0),
+ moe_intermediate_size: config.moe_intermediate_size,
+ scoring_func: config.scoring_func,
+ topk_method: config.topk_method,
+ norm_topk_prob: config.norm_topk_prob,
+ routed_scaling_factor: config.routed_scaling_factor,
+ n_shared_experts: config.n_shared_experts,
+ qk_nope_head_dim: config.qk_nope_head_dim,
+ qk_rope_head_dim: config.qk_rope_head_dim,
+ v_head_dim: config.v_head_dim,
+ kv_lora_rank: config.kv_lora_rank,
+ first_k_dense_replace: config.first_k_dense_replace,
+ moe_layer_freq: config.moe_layer_freq,
+ rope_scaling: config.rope_scaling,
+ q_lora_rank: config.q_lora_rank,
+ n_group: config.n_group,
+ topk_group: config.topk_group,
+ num_experts_offload_per_rank,
};
- Config {
- hidden_size: self.hidden_size,
- head_dim: Some(self.hidden_size / self.num_attention_heads),
- intermediate_size: self.intermediate_size,
- vocab_size: self.vocab_size,
- num_hidden_layers: self.num_hidden_layers,
- num_attention_heads: self.num_attention_heads,
- num_key_value_heads: self.num_key_value_heads.unwrap_or(self.num_attention_heads),
- rms_norm_eps: self.rms_norm_eps,
- rope_theta: f64::from(self.rope_theta),
+ let quant = if config.quantization_config.is_some() {
+ Some(
+ config
+ .quantization_config
+ .as_ref()
+ .unwrap()
+ .quant_method
+ .clone(),
+ )
+ } else if isq.is_some() {
+ panic!("DeepSeek does not support isq quantization yet!");
+ } else {
+ None
+ };
+
+ let config = Config {
+ architectures: Some(vec!["DeepseekV3ForCausalLM".to_string()]),
+ hidden_size: config.hidden_size,
+ head_dim: Some(config.hidden_size / config.num_attention_heads),
+ intermediate_size: config.intermediate_size,
+ vocab_size: config.vocab_size,
+ num_hidden_layers: config.num_hidden_layers,
+ num_attention_heads: config.num_attention_heads,
+ num_key_value_heads: Some(
+ config
+ .num_key_value_heads
+ .unwrap_or(config.num_attention_heads),
+ ),
+ rms_norm_eps: config.rms_norm_eps,
+ rope_theta: f64::from(config.rope_theta),
rope_local_base_freq: None,
- use_flash_attn,
- bos_token_id: self.bos_token_id,
- eos_token_id: self.eos_token_id,
- max_seq_len: self.max_position_embeddings,
- sliding_window: self.sliding_window,
+ bos_token_id: Some(config.bos_token_id),
+ eos_token_id: config.eos_token_id,
+ max_seq_len: config.max_position_embeddings,
+ sliding_window: config.sliding_window,
sliding_window_pattern: None,
- hidden_act: Some(self.hidden_act),
- tie_word_embeddings: false,
+ hidden_act: Some(config.hidden_act),
+ hidden_activation: None,
+ tie_word_embeddings: config.tie_word_embeddings,
rope_scaling: None,
- original_max_position_embeddings: None,
- attention_bias: false,
+ max_position_embeddings: Some(config.max_position_embeddings),
+ original_max_position_embeddings: config.max_position_embeddings,
+ attention_bias: Some(false),
partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
+ qk_layernorm: false,
use_qkv_bias: None,
custom_stop_tokens: None,
- specific_config: scfg.clone(),
attn_logit_softcapping: None,
final_logit_softcapping: None,
- quantization_config: self.quantization_config,
+ quantization_config: config.quantization_config.clone(),
moe_config: Some(moe_config),
- }
+ quant,
+ };
+ Ok(config)
}
}
@@ -391,14 +428,15 @@ impl Attention {
) -> Result {
let q_head_dim = cfg.q_head_dim();
let moe_cfg = cfg.moe_config.as_ref().unwrap();
+ let attention_bias = cfg.attention_bias.unwrap();
let q = match moe_cfg.q_lora_rank {
Some(lora_rank) => {
let a = ReplicatedLinear::load_b(
cfg.hidden_size,
lora_rank,
- cfg.attention_bias,
+ attention_bias,
vb.pp("q_a_proj"),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let norm = rms_norm(lora_rank, cfg.rms_norm_eps, vb.pp("q_a_layernorm"))?;
@@ -408,7 +446,7 @@ impl Attention {
false,
vb.pp("q_b_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
QProj::Lora { a, norm, b }
@@ -419,7 +457,7 @@ impl Attention {
false,
vb.pp("q_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?),
};
@@ -427,9 +465,9 @@ impl Attention {
let kv_a_proj_with_mqa = ReplicatedLinear::load_b(
cfg.hidden_size,
moe_cfg.kv_lora_rank + moe_cfg.qk_rope_head_dim,
- cfg.attention_bias,
+ attention_bias,
vb.pp("kv_a_proj_with_mqa"),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let kv_a_layernorm = rms_norm(
@@ -443,22 +481,22 @@ impl Attention {
false,
vb.pp("kv_b_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let o_proj = TensorParallelRowLinear::load_with_hints(
cfg.num_attention_heads * moe_cfg.v_head_dim,
cfg.hidden_size,
- cfg.attention_bias,
+ attention_bias,
vb.pp("o_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let num_attention_heads = cfg.num_attention_heads / comm.world_size();
- let num_kv_heads = cfg.num_key_value_heads / comm.world_size();
+ let num_kv_heads = cfg.num_key_value_heads.unwrap() / comm.world_size();
Ok(Self {
q,
@@ -588,7 +626,7 @@ impl Mlp {
hidden_size,
intermediate_size,
vb.pp("gate_proj"),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -596,7 +634,7 @@ impl Mlp {
hidden_size,
intermediate_size,
vb.pp("up_proj"),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -604,7 +642,7 @@ impl Mlp {
intermediate_size,
hidden_size,
vb.pp("down_proj"),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
diff --git a/src/openai/models/gemma.rs b/src/openai/models/gemma.rs
index 00924075..3fe9c856 100644
--- a/src/openai/models/gemma.rs
+++ b/src/openai/models/gemma.rs
@@ -1,95 +1,46 @@
-use super::{Config, QuantConfig};
+use super::Config;
use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::openai::distributed::{
embedding, Comm, ReplicatedLinear, TensorParallelColumnLinear, TensorParallelRowLinear,
VarBuilder,
};
-use crate::openai::models::TokenID;
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle::{DType, Device, IndexOp, Module, Result, Tensor};
use candle_core as candle;
-use candle_nn::{Activation, RmsNorm};
+use candle_nn::RmsNorm;
use std::iter::zip;
+use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{Arc, RwLock};
-use tracing::warn;
-#[derive(serde::Deserialize, Debug, Clone)]
-pub struct GemmaConfig {
- pub attention_bias: bool,
- pub head_dim: Option,
- // The code gemma configs include both hidden_act and hidden_activation.
- pub hidden_act: Option,
- pub hidden_activation: Option,
- pub hidden_size: usize,
- pub intermediate_size: usize,
- pub num_attention_heads: usize,
- pub num_hidden_layers: usize,
- pub num_key_value_heads: usize,
- pub rms_norm_eps: f64,
- pub rope_theta: f64,
- pub vocab_size: usize,
- pub bos_token_id: TokenID,
- pub eos_token_id: TokenID,
- pub sliding_window: Option,
- pub max_position_embeddings: Option,
- pub attn_logit_softcapping: Option,
- pub final_logit_softcapping: Option,
- pub quantization_config: Option,
-}
-impl GemmaConfig {
- pub fn into_config(
- self,
- use_flash_attn: bool,
- kv_cache_dtype: DType,
- scfg: &SpecificConfig,
- ) -> Config {
- let hidden_act = match (self.hidden_act, self.hidden_activation) {
- (None, Some(act)) | (Some(act), None) => Some(act),
- (Some(act), Some(_)) => {
- warn!("both hidden_act and hidden_activation are set");
- Some(act)
- }
- (None, None) => panic!("none of hidden_act and hidden_activation are set"),
- };
- Config {
- hidden_size: self.hidden_size,
- head_dim: Some(
- self.head_dim
- .unwrap_or(self.hidden_size / self.num_attention_heads),
- ),
- intermediate_size: self.intermediate_size,
- vocab_size: self.vocab_size,
- num_hidden_layers: self.num_hidden_layers,
- num_attention_heads: self.num_attention_heads,
- num_key_value_heads: self.num_key_value_heads,
- rms_norm_eps: self.rms_norm_eps,
- rope_theta: self.rope_theta,
- rope_local_base_freq: None,
- use_flash_attn,
- bos_token_id: self.bos_token_id,
- eos_token_id: self.eos_token_id,
- max_seq_len: self.max_position_embeddings.unwrap_or(4096),
- sliding_window: self.sliding_window,
- sliding_window_pattern: None,
- hidden_act,
- tie_word_embeddings: false,
- rope_scaling: None,
- original_max_position_embeddings: None,
- attention_bias: self.attention_bias,
- partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
- use_qkv_bias: None,
- custom_stop_tokens: None,
- specific_config: scfg.clone(),
- attn_logit_softcapping: self.attn_logit_softcapping,
- final_logit_softcapping: self.final_logit_softcapping,
- quantization_config: self.quantization_config,
- moe_config: None,
+impl Gemma {
+ pub fn load_config(filename: &PathBuf, isq: Option) -> Result {
+ let mut config = Config::load_config(filename.clone())?;
+ config.head_dim = Some(
+ config
+ .head_dim
+ .unwrap_or(config.hidden_size / config.num_attention_heads),
+ );
+ config.num_key_value_heads = Some(
+ config
+ .num_key_value_heads
+ .unwrap_or(config.num_attention_heads),
+ );
+ config.max_seq_len = config.max_position_embeddings.unwrap_or(config.max_seq_len);
+ if config.quantization_config.is_some() {
+ config.quant = Some(
+ config
+ .quantization_config
+ .as_ref()
+ .unwrap()
+ .quant_method
+ .clone(),
+ );
+ } else if isq.is_some() {
+ config.quant = Some(isq.unwrap().to_string());
}
+ Ok(config)
}
}
@@ -164,7 +115,7 @@ impl Mlp {
false,
vb.pp("gate_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let up_proj = TensorParallelColumnLinear::load_with_hints(
@@ -173,7 +124,7 @@ impl Mlp {
false,
vb.pp("up_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let down_proj = TensorParallelRowLinear::load_with_hints(
@@ -182,7 +133,7 @@ impl Mlp {
false,
vb.pp("down_proj"),
comm,
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
Ok(Self {
@@ -223,16 +174,16 @@ impl Attention {
) -> Result {
let hidden_sz = cfg.hidden_size;
let num_heads = cfg.num_attention_heads;
- let num_kv_heads = cfg.num_key_value_heads;
+ let num_kv_heads = cfg.num_key_value_heads.unwrap();
let head_dim = cfg.head_dim.unwrap();
- let bias = cfg.attention_bias;
+ let bias = cfg.attention_bias.unwrap();
let q_proj = TensorParallelColumnLinear::load_with_hints(
hidden_sz,
num_heads * head_dim,
bias,
vb.pp("q_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let k_proj = TensorParallelColumnLinear::load_with_hints(
@@ -241,7 +192,7 @@ impl Attention {
bias,
vb.pp("k_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let v_proj = TensorParallelColumnLinear::load_with_hints(
@@ -250,7 +201,7 @@ impl Attention {
bias,
vb.pp("v_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -260,11 +211,11 @@ impl Attention {
bias,
vb.pp("o_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let attention_heads = cfg.num_attention_heads / comm.world_size();
- let kv_heads = cfg.num_key_value_heads / comm.world_size();
+ let kv_heads = cfg.num_key_value_heads.unwrap() / comm.world_size();
Ok(Self {
q_proj,
k_proj,
diff --git a/src/openai/models/gemma3.rs b/src/openai/models/gemma3.rs
index d0e3b6b6..77be8aa1 100644
--- a/src/openai/models/gemma3.rs
+++ b/src/openai/models/gemma3.rs
@@ -4,16 +4,16 @@ use crate::openai::distributed::{
embedding, Comm, ReplicatedLinear, TensorParallelColumnLinear, TensorParallelRowLinear,
VarBuilder,
};
-use crate::openai::models::RopeScaling;
use crate::openai::models::TokenID;
+use crate::openai::models::{RopeScaling, ScalingValue};
use crate::paged_attention::input_metadata::InputMetadata;
-use crate::SpecificConfig;
use candle::{DType, Device, IndexOp, Module, Result, Tensor};
use candle_core as candle;
use candle_nn::{Activation, RmsNorm};
use either::Either;
use std::collections::HashMap;
use std::iter::zip;
+use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{Arc, RwLock};
@@ -98,31 +98,38 @@ pub struct Gemma3Config {
pub text_config: GemmaTextConfig,
}
-impl Gemma3Config {
- pub fn into_config(
- self,
- use_flash_attn: bool,
- kv_cache_dtype: DType,
- scfg: &SpecificConfig,
- ) -> Config {
- let bos_token_id = self
+impl Gemma3 {
+ pub fn load_config(filename: &PathBuf, isq: Option) -> Result {
+ let config = match std::fs::read(filename.clone()) {
+ Ok(f) => {
+ let config: Gemma3Config =
+ serde_json::from_slice(&f).map_err(candle_core::Error::wrap)?;
+ config
+ }
+ Err(e) => panic!("Unable to load config file {:?}", e),
+ };
+
+ let bos_token_id = config
.text_config
.bos_token_id
- .or(self.bos_token_id)
+ .or(config.bos_token_id)
.unwrap_or(super::TokenID(Either::Left(Some(2))));
- let eos_token_id = self
+ let eos_token_id = config
.text_config
.eos_token_id
- .or(self.eos_token_id)
+ .or(config.eos_token_id)
.unwrap_or(super::TokenID(Either::Left(Some(1))));
- let ropescaling = if self.text_config.rope_scaling.is_some() {
+ let ropescaling = if config.text_config.rope_scaling.is_some() {
let mut ropescaling = HashMap::::new();
- for (key, value) in self.text_config.rope_scaling.as_ref().unwrap() {
+ for (key, value) in config.text_config.rope_scaling.as_ref().unwrap() {
match value {
Gemma3RopeScaling(Either::Left(l)) => {
- ropescaling.insert(key.to_string(), RopeScaling(Either::Left(vec![*l])));
+ ropescaling.insert(
+ key.to_string(),
+ RopeScaling(Either::Left(ScalingValue(Either::Left(*l)))),
+ );
}
Gemma3RopeScaling(Either::Right(r)) => {
ropescaling
@@ -135,39 +142,57 @@ impl Gemma3Config {
None
};
- Config {
- hidden_size: self.text_config.hidden_size,
- head_dim: Some(self.text_config.head_dim),
- intermediate_size: self.text_config.intermediate_size,
- vocab_size: self.text_config.vocab_size,
- num_hidden_layers: self.text_config.num_hidden_layers,
- num_attention_heads: self.text_config.num_attention_heads,
- num_key_value_heads: self.text_config.num_key_value_heads,
- rms_norm_eps: self.text_config.rms_norm_eps,
- rope_theta: self.text_config.rope_theta,
- rope_local_base_freq: Some(self.text_config.rope_local_base_freq),
- use_flash_attn,
- bos_token_id,
+ let quant = if config.text_config.quantization_config.is_some() {
+ Some(
+ config
+ .text_config
+ .quantization_config
+ .as_ref()
+ .unwrap()
+ .quant_method
+ .clone(),
+ )
+ } else if isq.is_some() {
+ Some(isq.unwrap().to_string())
+ } else {
+ None
+ };
+
+ let config = Config {
+ architectures: Some(vec!["Gemma3ForConditionalGeneration".to_string()]),
+ hidden_size: config.text_config.hidden_size,
+ head_dim: Some(config.text_config.head_dim),
+ intermediate_size: config.text_config.intermediate_size,
+ vocab_size: config.text_config.vocab_size,
+ num_hidden_layers: config.text_config.num_hidden_layers,
+ num_attention_heads: config.text_config.num_attention_heads,
+ num_key_value_heads: Some(config.text_config.num_key_value_heads),
+ rms_norm_eps: config.text_config.rms_norm_eps,
+ rope_theta: config.text_config.rope_theta,
+ rope_local_base_freq: Some(config.text_config.rope_local_base_freq),
+ bos_token_id: Some(bos_token_id),
eos_token_id,
- max_seq_len: self.text_config.max_position_embeddings,
- sliding_window: self.text_config.sliding_window,
- sliding_window_pattern: Some(self.text_config.sliding_window_pattern),
- hidden_act: Some(self.text_config.hidden_activation),
- tie_word_embeddings: self.text_config.tie_word_embeddings,
+ max_seq_len: config.text_config.max_position_embeddings,
+ sliding_window: config.text_config.sliding_window,
+ sliding_window_pattern: Some(config.text_config.sliding_window_pattern),
+ hidden_act: Some(config.text_config.hidden_activation),
+ hidden_activation: None,
+ tie_word_embeddings: config.text_config.tie_word_embeddings,
rope_scaling: ropescaling,
- original_max_position_embeddings: None,
- attention_bias: self.text_config.attention_bias,
+ max_position_embeddings: Some(config.text_config.max_position_embeddings),
+ original_max_position_embeddings: config.text_config.max_position_embeddings,
+ attention_bias: Some(config.text_config.attention_bias),
partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
+ qk_layernorm: false,
use_qkv_bias: None,
custom_stop_tokens: None,
- specific_config: scfg.clone(),
- attn_logit_softcapping: self.text_config.attn_logit_softcapping,
- final_logit_softcapping: self.text_config.final_logit_softcapping,
- quantization_config: self.text_config.quantization_config,
+ attn_logit_softcapping: config.text_config.attn_logit_softcapping,
+ final_logit_softcapping: config.text_config.final_logit_softcapping,
+ quantization_config: config.text_config.quantization_config.clone(),
moe_config: None,
- }
+ quant,
+ };
+ Ok(config)
}
}
@@ -305,7 +330,7 @@ impl Mlp {
false,
vb.pp("gate_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let up_proj = TensorParallelColumnLinear::load_with_hints(
@@ -314,7 +339,7 @@ impl Mlp {
false,
vb.pp("up_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let down_proj = TensorParallelRowLinear::load_with_hints(
@@ -323,7 +348,7 @@ impl Mlp {
false,
vb.pp("down_proj"),
comm,
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
Ok(Self {
@@ -368,9 +393,9 @@ impl Attention {
) -> Result {
let hidden_sz = cfg.hidden_size;
let num_heads = cfg.num_attention_heads;
- let num_kv_heads = cfg.num_key_value_heads;
+ let num_kv_heads = cfg.num_key_value_heads.unwrap();
let head_dim = cfg.head_dim.unwrap();
- let bias = cfg.attention_bias;
+ let bias = cfg.attention_bias.unwrap();
let q_proj = TensorParallelColumnLinear::load_with_hints(
hidden_sz,
@@ -378,7 +403,7 @@ impl Attention {
bias,
vb.pp("q_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let k_proj = TensorParallelColumnLinear::load_with_hints(
@@ -387,7 +412,7 @@ impl Attention {
bias,
vb.pp("k_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let v_proj = TensorParallelColumnLinear::load_with_hints(
@@ -396,7 +421,7 @@ impl Attention {
bias,
vb.pp("v_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -406,7 +431,7 @@ impl Attention {
bias,
vb.pp("o_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -414,7 +439,7 @@ impl Attention {
let k_norm = rms_norm(head_dim, cfg.rms_norm_eps, vb.pp("k_norm"))?;
let attention_heads = cfg.num_attention_heads / comm.world_size();
- let kv_heads = cfg.num_key_value_heads / comm.world_size();
+ let kv_heads = cfg.num_key_value_heads.unwrap() / comm.world_size();
Ok(Self {
q_proj,
k_proj,
diff --git a/src/openai/models/glm4.rs b/src/openai/models/glm4.rs
index 87213fec..1975c6e9 100644
--- a/src/openai/models/glm4.rs
+++ b/src/openai/models/glm4.rs
@@ -1,83 +1,52 @@
-use super::{Config, QuantConfig};
+use super::Config;
+use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::openai::distributed::{
embedding, rms_norm, Comm, MergedParallelColumnLinear, ReplicatedLinear,
TensorParallelColumnLinear, TensorParallelRowLinear, VarBuilder,
};
use crate::paged_attention::input_metadata::InputMetadata;
-use crate::SpecificConfig;
use candle::{DType, Device, IndexOp, Result, Tensor, D};
use candle_core as candle;
use candle_nn::{Embedding, Module, RmsNorm};
-pub const MAX_SEQ_LEN: usize = 4096;
-use crate::backend::progress::{ProgressLike, ProgressReporter};
-use crate::openai::models::TokenID;
-use either::Either;
use std::iter::zip;
+use std::path::PathBuf;
pub use std::rc::Rc;
use std::sync::{Arc, RwLock};
-#[derive(Debug, Clone, serde::Deserialize)]
-pub struct GLMConfig {
- pub num_hidden_layers: Option,
- pub vocab_size: usize,
- pub hidden_size: usize,
- pub head_dim: Option,
- pub num_attention_heads: usize,
- pub num_key_value_heads: usize,
- pub intermediate_size: usize,
- pub rms_norm_eps: f64,
- pub rope_theta: Option,
- pub partial_rotary_factor: Option,
- pub hidden_act: candle_nn::Activation,
- pub attention_bias: Option,
- pub sliding_window: Option,
- pub eos_token_id: TokenID,
- pub max_position_embeddings: Option,
- pub quantization_config: Option,
-}
-impl GLMConfig {
- pub fn into_config(
- self,
- use_flash_attn: bool,
- kv_cache_dtype: DType,
- scfg: &SpecificConfig,
- ) -> Config {
- Config {
- hidden_size: self.hidden_size,
- head_dim: Some(
- self.head_dim
- .unwrap_or(self.hidden_size / self.num_attention_heads),
- ),
- intermediate_size: self.intermediate_size,
- vocab_size: self.vocab_size,
- num_hidden_layers: self.num_hidden_layers.unwrap_or(40),
- num_attention_heads: self.num_attention_heads,
- num_key_value_heads: self.num_key_value_heads,
- rms_norm_eps: self.rms_norm_eps,
- rope_theta: self.rope_theta.unwrap_or(10_000f64),
- use_flash_attn,
- bos_token_id: super::TokenID(Either::Left(Some(128256))),
- eos_token_id: self.eos_token_id,
- max_seq_len: self.max_position_embeddings.unwrap_or(32768),
- sliding_window: self.sliding_window,
- hidden_act: Some(self.hidden_act),
- tie_word_embeddings: false,
- rope_local_base_freq: None,
- sliding_window_pattern: None,
- rope_scaling: None,
- original_max_position_embeddings: None,
- attention_bias: self.attention_bias.unwrap_or(false),
- partial_rotary_factor: self.partial_rotary_factor,
- qk_layer_rms_norm: None,
- use_qkv_bias: None,
- kv_cache_dtype,
- custom_stop_tokens: None,
- specific_config: scfg.clone(),
- attn_logit_softcapping: None,
- final_logit_softcapping: None,
- quantization_config: self.quantization_config,
- moe_config: None,
+impl GLM4 {
+ pub fn load_config(filename: &PathBuf, isq: Option) -> Result {
+ let mut config = Config::load_config(filename.clone())?;
+ config.head_dim = Some(
+ config
+ .head_dim
+ .unwrap_or(config.hidden_size / config.num_attention_heads),
+ );
+ config.num_key_value_heads = Some(
+ config
+ .num_key_value_heads
+ .unwrap_or(config.num_attention_heads),
+ );
+ config.num_hidden_layers = config.num_hidden_layers;
+ config.max_seq_len = config.max_position_embeddings.unwrap_or(32768);
+ config.attention_bias = Some(config.attention_bias.unwrap_or(false));
+ config.bos_token_id = Some(
+ config
+ .bos_token_id
+ .unwrap_or(super::TokenID(either::Either::Left(Some(128256)))),
+ );
+ if config.quantization_config.is_some() {
+ config.quant = Some(
+ config
+ .quantization_config
+ .as_ref()
+ .unwrap()
+ .quant_method
+ .clone(),
+ );
+ } else if isq.is_some() {
+ config.quant = Some(isq.unwrap().to_string());
}
+ Ok(config)
}
}
@@ -198,34 +167,35 @@ impl SelfAttention {
) -> Result {
let hidden_sz = cfg.hidden_size;
let num_heads = cfg.num_attention_heads;
- let num_kv_heads = cfg.num_key_value_heads;
+ let num_kv_heads = cfg.num_key_value_heads.unwrap();
+ let attention_bias = cfg.attention_bias.unwrap_or(false);
let head_dim = cfg.head_dim.unwrap_or(hidden_sz / num_heads);
let q_proj = TensorParallelColumnLinear::load_with_hints(
hidden_sz,
num_heads * head_dim,
- cfg.attention_bias,
+ attention_bias,
vb.pp("q_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let k_proj = TensorParallelColumnLinear::load_with_hints(
hidden_sz,
num_kv_heads * head_dim,
- cfg.attention_bias,
+ attention_bias,
vb.pp("k_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let v_proj = TensorParallelColumnLinear::load_with_hints(
hidden_sz,
num_kv_heads * head_dim,
- cfg.attention_bias,
+ attention_bias,
vb.pp("v_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -235,18 +205,18 @@ impl SelfAttention {
false,
vb.pp("o_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
assert!(cfg.num_attention_heads >= comm.world_size());
assert!(cfg.num_attention_heads % comm.world_size() == 0);
- assert!(cfg.num_key_value_heads >= comm.world_size());
- assert!(cfg.num_key_value_heads % comm.world_size() == 0);
+ assert!(cfg.num_key_value_heads.unwrap() >= comm.world_size());
+ assert!(cfg.num_key_value_heads.unwrap() % comm.world_size() == 0);
let attention_heads = cfg.num_attention_heads / comm.world_size();
- let kv_heads = cfg.num_key_value_heads / comm.world_size();
+ let kv_heads = cfg.num_key_value_heads.unwrap() / comm.world_size();
Ok(Self {
q_proj,
k_proj,
@@ -332,7 +302,7 @@ impl MLP {
2,
vb.pp("gate_up_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -342,7 +312,7 @@ impl MLP {
false,
vb.pp("down_proj"),
comm,
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
diff --git a/src/openai/models/llama.rs b/src/openai/models/llama.rs
index 9bbc61b7..2085dd59 100644
--- a/src/openai/models/llama.rs
+++ b/src/openai/models/llama.rs
@@ -1,82 +1,46 @@
-use super::{Config, QuantConfig};
+use super::Config;
+use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::openai::distributed::{
embedding, rms_norm, Comm, ReplicatedLinear, TensorParallelColumnLinear,
TensorParallelRowLinear, VarBuilder,
};
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle::{DType, Device, IndexOp, Result, Tensor};
use candle_core as candle;
use candle_nn::{Embedding, Module, RmsNorm};
-pub const MAX_SEQ_LEN: usize = 4096;
-use crate::backend::progress::{ProgressLike, ProgressReporter};
-use crate::openai::models::TokenID;
use std::iter::zip;
+use std::path::PathBuf;
pub use std::rc::Rc;
use std::sync::{Arc, RwLock};
-#[derive(Debug, Clone, serde::Deserialize)]
-pub struct LlamaConfig {
- pub hidden_size: usize,
- pub intermediate_size: usize,
- pub vocab_size: usize,
- pub num_hidden_layers: usize,
- pub num_attention_heads: usize,
- pub num_key_value_heads: Option,
- pub rms_norm_eps: f64,
- #[serde(default = "default_rope")]
- pub rope_theta: f32,
- pub bos_token_id: TokenID,
- pub eos_token_id: TokenID,
- pub sliding_window: Option,
- pub max_position_embeddings: Option,
- pub quantization_config: Option,
-}
-fn default_rope() -> f32 {
- 10_000.0
-}
-
-impl LlamaConfig {
- pub fn into_config(
- self,
- use_flash_attn: bool,
- kv_cache_dtype: DType,
- scfg: &SpecificConfig,
- ) -> Config {
- Config {
- hidden_size: self.hidden_size,
- head_dim: Some(self.hidden_size / self.num_attention_heads),
- intermediate_size: self.intermediate_size,
- vocab_size: self.vocab_size,
- num_hidden_layers: self.num_hidden_layers,
- num_attention_heads: self.num_attention_heads,
- num_key_value_heads: self.num_key_value_heads.unwrap_or(self.num_attention_heads),
- rms_norm_eps: self.rms_norm_eps,
- rope_theta: f64::from(self.rope_theta),
- rope_local_base_freq: None,
- use_flash_attn,
- bos_token_id: self.bos_token_id,
- eos_token_id: self.eos_token_id,
- max_seq_len: self.max_position_embeddings.unwrap_or(MAX_SEQ_LEN),
- sliding_window: self.sliding_window,
- sliding_window_pattern: None,
- hidden_act: None,
- tie_word_embeddings: false,
- rope_scaling: None,
- original_max_position_embeddings: None,
- attention_bias: false,
- partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
- use_qkv_bias: None,
- custom_stop_tokens: None,
- specific_config: scfg.clone(),
- attn_logit_softcapping: None,
- final_logit_softcapping: None,
- quantization_config: self.quantization_config,
- moe_config: None,
+impl Llama {
+ pub fn load_config(filename: &PathBuf, isq: Option) -> Result {
+ let mut config = Config::load_config(filename.clone())?;
+ config.head_dim = Some(
+ config
+ .head_dim
+ .unwrap_or(config.hidden_size / config.num_attention_heads),
+ );
+ config.num_key_value_heads = Some(
+ config
+ .num_key_value_heads
+ .unwrap_or(config.num_attention_heads),
+ );
+ config.max_seq_len = config.max_position_embeddings.unwrap_or(config.max_seq_len);
+ if config.quantization_config.is_some() {
+ config.quant = Some(
+ config
+ .quantization_config
+ .as_ref()
+ .unwrap()
+ .quant_method
+ .clone(),
+ );
+ } else if isq.is_some() {
+ config.quant = Some(isq.unwrap().to_string());
}
+ Ok(config)
}
}
@@ -202,14 +166,15 @@ impl CausalSelfAttention {
) -> Result {
let size_in = cfg.hidden_size;
let size_q = (cfg.hidden_size / cfg.num_attention_heads) * cfg.num_attention_heads;
- let size_kv = (cfg.hidden_size / cfg.num_attention_heads) * cfg.num_key_value_heads;
+ let size_kv =
+ (cfg.hidden_size / cfg.num_attention_heads) * cfg.num_key_value_heads.unwrap();
let q_proj = TensorParallelColumnLinear::load_with_hints(
size_in,
size_q,
false,
vb.pp("q_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let k_proj = TensorParallelColumnLinear::load_with_hints(
@@ -218,7 +183,7 @@ impl CausalSelfAttention {
false,
vb.pp("k_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let v_proj = TensorParallelColumnLinear::load_with_hints(
@@ -227,7 +192,7 @@ impl CausalSelfAttention {
false,
vb.pp("v_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -237,12 +202,12 @@ impl CausalSelfAttention {
false,
vb.pp("o_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let head_dim = cfg.hidden_size / cfg.num_attention_heads;
let attention_heads = cfg.num_attention_heads / comm.world_size();
- let kv_heads = cfg.num_key_value_heads / comm.world_size();
+ let kv_heads = cfg.num_key_value_heads.unwrap() / comm.world_size();
Ok(Self {
q_proj,
k_proj,
@@ -286,7 +251,7 @@ impl Mlp {
false,
vb.pp("gate_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let c_fc2 = TensorParallelColumnLinear::load_with_hints(
@@ -295,7 +260,7 @@ impl Mlp {
false,
vb.pp("up_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let c_proj = TensorParallelRowLinear::load_with_hints(
@@ -304,7 +269,7 @@ impl Mlp {
false,
vb.pp("down_proj"),
comm,
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
Ok(Self {
diff --git a/src/openai/models/mistral.rs b/src/openai/models/mistral.rs
index 8cd2c20b..cb5aeaf1 100644
--- a/src/openai/models/mistral.rs
+++ b/src/openai/models/mistral.rs
@@ -1,77 +1,45 @@
-use super::{Config, QuantConfig};
+use super::Config;
use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::openai::distributed::{
embedding, rms_norm, Comm, ReplicatedLinear, TensorParallelColumnLinear,
TensorParallelRowLinear, VarBuilder,
};
-use crate::openai::models::TokenID;
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle_core::{DType, Device, IndexOp, Module, Result, Tensor};
use candle_nn::{Activation, RmsNorm};
use std::iter::zip;
+use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{Arc, RwLock};
-#[derive(Debug, Clone, serde::Deserialize)]
-pub struct MistralConfig {
- pub vocab_size: usize,
- pub hidden_size: usize,
- pub intermediate_size: usize,
- pub num_hidden_layers: usize,
- pub num_attention_heads: usize,
- pub num_key_value_heads: usize,
- pub hidden_act: Activation,
- pub max_position_embeddings: usize,
- pub rms_norm_eps: f64,
- pub rope_theta: f64,
- pub sliding_window: Option,
- pub bos_token_id: TokenID,
- pub eos_token_id: TokenID,
- pub tie_word_embeddings: Option,
- pub quantization_config: Option,
-}
-impl MistralConfig {
- pub fn into_config(
- self,
- use_flash_attn: bool,
- kv_cache_dtype: DType,
- scfg: &SpecificConfig,
- ) -> Config {
- Config {
- hidden_size: self.hidden_size,
- head_dim: Some(self.hidden_size / self.num_attention_heads),
- intermediate_size: self.intermediate_size,
- vocab_size: self.vocab_size,
- num_hidden_layers: self.num_hidden_layers,
- num_attention_heads: self.num_attention_heads,
- num_key_value_heads: self.num_key_value_heads,
- rms_norm_eps: self.rms_norm_eps,
- rope_theta: self.rope_theta,
- rope_local_base_freq: None,
- use_flash_attn,
- bos_token_id: self.bos_token_id,
- eos_token_id: self.eos_token_id,
- max_seq_len: self.max_position_embeddings,
- sliding_window: self.sliding_window,
- sliding_window_pattern: None,
- hidden_act: Some(self.hidden_act),
- tie_word_embeddings: self.tie_word_embeddings.unwrap_or(false),
- rope_scaling: None,
- original_max_position_embeddings: None,
- attention_bias: false,
- partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
- use_qkv_bias: None,
- custom_stop_tokens: None,
- specific_config: scfg.clone(),
- attn_logit_softcapping: None,
- final_logit_softcapping: None,
- quantization_config: self.quantization_config,
- moe_config: None,
+impl Mistral {
+ pub fn load_config(filename: &PathBuf, isq: Option) -> Result {
+ let mut config = Config::load_config(filename.clone())?;
+ config.head_dim = Some(
+ config
+ .head_dim
+ .unwrap_or(config.hidden_size / config.num_attention_heads),
+ );
+ config.num_key_value_heads = Some(
+ config
+ .num_key_value_heads
+ .unwrap_or(config.num_attention_heads),
+ );
+ config.max_seq_len = config.max_position_embeddings.unwrap_or(config.max_seq_len);
+ if config.quantization_config.is_some() {
+ config.quant = Some(
+ config
+ .quantization_config
+ .as_ref()
+ .unwrap()
+ .quant_method
+ .clone(),
+ );
+ } else if isq.is_some() {
+ config.quant = Some(isq.unwrap().to_string());
}
+ Ok(config)
}
}
@@ -143,7 +111,7 @@ impl Mlp {
false,
vb.pp("gate_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let up_proj = TensorParallelColumnLinear::load_with_hints(
@@ -152,7 +120,7 @@ impl Mlp {
false,
vb.pp("up_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let down_proj = TensorParallelRowLinear::load_with_hints(
@@ -161,7 +129,7 @@ impl Mlp {
false,
vb.pp("down_proj"),
comm,
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
Ok(Self {
@@ -202,7 +170,7 @@ impl Attention {
) -> Result {
let hidden_sz = cfg.hidden_size;
let num_heads = cfg.num_attention_heads;
- let num_kv_heads = cfg.num_key_value_heads;
+ let num_kv_heads = cfg.num_key_value_heads.unwrap();
let head_dim = hidden_sz / num_heads;
let q_proj = TensorParallelColumnLinear::load_with_hints(
hidden_sz,
@@ -210,7 +178,7 @@ impl Attention {
false,
vb.pp("q_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let k_proj = TensorParallelColumnLinear::load_with_hints(
@@ -219,7 +187,7 @@ impl Attention {
false,
vb.pp("k_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let v_proj = TensorParallelColumnLinear::load_with_hints(
@@ -228,7 +196,7 @@ impl Attention {
false,
vb.pp("v_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -238,11 +206,11 @@ impl Attention {
false,
vb.pp("o_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let attention_heads = cfg.num_attention_heads / comm.world_size();
- let kv_heads = cfg.num_key_value_heads / comm.world_size();
+ let kv_heads = cfg.num_key_value_heads.unwrap() / comm.world_size();
Ok(Self {
q_proj,
k_proj,
diff --git a/src/openai/models/mod.rs b/src/openai/models/mod.rs
index a2f9b84b..6088bddf 100644
--- a/src/openai/models/mod.rs
+++ b/src/openai/models/mod.rs
@@ -17,15 +17,18 @@ pub mod yi;
use crate::openai::distributed::Comm;
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle_core::{DType, Device, Result, Tensor};
use either::Either;
use serde::Deserialize;
use std::cell::RefCell;
use std::collections::HashMap;
+use std::path::PathBuf;
use std::rc::Rc;
#[derive(Deserialize, Debug, Clone)]
-pub struct RopeScaling(#[serde(with = "either::serde_untagged")] pub Either, String>);
+pub struct ScalingValue(#[serde(with = "either::serde_untagged")] pub Either>);
+
+#[derive(Deserialize, Debug, Clone)]
+pub struct RopeScaling(#[serde(with = "either::serde_untagged")] pub Either);
#[derive(Deserialize, Debug, Clone)]
pub struct TokenID(
@@ -60,7 +63,7 @@ pub enum ScoringFunc {
Sigmoid,
}
-#[derive(Debug, Clone)]
+#[derive(Deserialize, Debug, Clone)]
pub struct MoEConfig {
pub num_experts_per_tok: Option,
pub n_routed_experts: usize,
@@ -117,42 +120,89 @@ pub enum DeepSeekRopeScaling {
},
}
-#[derive(Debug, Clone)]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! serde_default_cfg {
+ ($t:ty, $name:ident, $v:expr) => {
+ fn $name() -> $t {
+ $v
+ }
+ };
+}
+serde_default_cfg!(usize, max_seq_len, 8192);
+serde_default_cfg!(usize, original_max_position_embeddings, 8192);
+serde_default_cfg!(bool, tie_word_embeddings, false);
+serde_default_cfg!(f64, rope_theta, 10_000.0f64);
+serde_default_cfg!(bool, qk_layernorm, false);
+
+#[derive(Deserialize, Debug, Clone)]
pub struct Config {
+ pub architectures: Option>,
pub hidden_size: usize,
pub head_dim: Option,
pub intermediate_size: usize,
pub vocab_size: usize,
pub num_hidden_layers: usize,
pub num_attention_heads: usize,
- pub num_key_value_heads: usize,
- pub use_flash_attn: bool,
+ pub num_key_value_heads: Option,
pub rms_norm_eps: f64,
+ #[serde(default = "rope_theta")]
pub rope_theta: f64,
pub rope_local_base_freq: Option,
- pub bos_token_id: TokenID,
+ pub bos_token_id: Option,
pub eos_token_id: TokenID,
+ #[serde(default = "max_seq_len")]
pub max_seq_len: usize,
+ #[serde(default = "original_max_position_embeddings")]
+ pub original_max_position_embeddings: usize,
pub sliding_window: Option,
pub sliding_window_pattern: Option,
pub hidden_act: Option,
+ pub hidden_activation: Option,
+ #[serde(default = "tie_word_embeddings")]
pub tie_word_embeddings: bool,
pub rope_scaling: Option>,
- pub original_max_position_embeddings: Option,
- pub attention_bias: bool,
+ pub max_position_embeddings: Option,
+ pub attention_bias: Option,
pub partial_rotary_factor: Option,
- pub qk_layer_rms_norm: Option,
- pub kv_cache_dtype: DType,
+ #[serde(default = "qk_layernorm")]
+ pub qk_layernorm: bool,
pub use_qkv_bias: Option,
pub custom_stop_tokens: Option>,
- pub specific_config: SpecificConfig,
pub attn_logit_softcapping: Option,
pub final_logit_softcapping: Option,
pub quantization_config: Option,
pub moe_config: Option,
+ pub quant: Option,
}
impl Config {
+ pub fn load_config(filename: PathBuf) -> Result {
+ match std::fs::read(filename) {
+ Ok(f) => {
+ let config: Config =
+ serde_json::from_slice(&f).map_err(candle_core::Error::wrap)?;
+ Ok(config)
+ }
+ Err(e) => panic!(
+ "Unable to load config file {:?}\n ***Tips: use `--f` to specify GGUF file path!",
+ e
+ ),
+ }
+ }
+
+ pub fn get_model_arch(filename: &PathBuf) -> Result {
+ let config = Config::load_config(filename.clone())?;
+ if config.architectures.is_none() {
+ candle_core::bail!("Missing architectures in config file!");
+ }
+ let architectures = config.architectures.unwrap();
+ if architectures.is_empty() {
+ candle_core::bail!("No architectures defined in config file!");
+ }
+ Ok(architectures[0].clone())
+ }
+
pub fn get_head_size(&self) -> usize {
self.head_dim
.unwrap_or(self.hidden_size / self.num_attention_heads)
@@ -261,7 +311,7 @@ pub struct NaiveAttention {
impl NaiveAttention {
pub fn new(cfg: &Config, sliding_window: Option) -> Self {
let num_heads = cfg.num_attention_heads;
- let num_kv_heads = cfg.num_key_value_heads;
+ let num_kv_heads = cfg.num_key_value_heads.unwrap();
let num_kv_groups = num_heads / num_kv_heads;
let scale = 1f64 / f64::sqrt(cfg.head_dim.unwrap() as f64);
@@ -345,7 +395,7 @@ impl AttentionSelect {
} else {
let head_dim = cfg.head_dim.unwrap();
let attention_heads = cfg.num_attention_heads / comm.world_size();
- let kv_heads = cfg.num_key_value_heads / comm.world_size();
+ let kv_heads = cfg.num_key_value_heads.unwrap() / comm.world_size();
AttentionSelect::Paged(
PagedAttention::new(
attention_heads,
diff --git a/src/openai/models/phi2.rs b/src/openai/models/phi2.rs
index 861078c9..ef7371ba 100644
--- a/src/openai/models/phi2.rs
+++ b/src/openai/models/phi2.rs
@@ -1,81 +1,45 @@
-use super::{Config, QuantConfig};
+use super::Config;
use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::openai::distributed::{
embedding, layer_norm, Comm, ReplicatedLinear, TensorParallelColumnLinear,
TensorParallelRowLinear, VarBuilder,
};
-use crate::openai::models::TokenID;
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle_core::{DType, Device, IndexOp, Module, Result, Tensor, D};
use candle_nn::{Activation, Embedding, LayerNorm};
-use serde::Deserialize;
use std::iter::zip;
+use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{Arc, RwLock};
-#[derive(Debug, Clone, Deserialize)]
-pub struct Phi2Config {
- pub vocab_size: usize,
- pub hidden_size: usize,
- pub intermediate_size: usize,
- pub num_hidden_layers: usize,
- pub num_attention_heads: usize,
- pub num_key_value_heads: Option,
- pub hidden_act: Activation,
- pub max_position_embeddings: usize,
- pub layer_norm_eps: f64,
- pub tie_word_embeddings: bool,
- pub rope_theta: f64,
- pub partial_rotary_factor: f32,
- pub qk_layernorm: bool,
- pub bos_token_id: TokenID,
- pub eos_token_id: TokenID,
- pub sliding_window: Option,
- pub original_max_position_embeddings: Option,
- pub quantization_config: Option,
-}
-impl Phi2Config {
- pub fn into_config(
- self,
- use_flash_attn: bool,
- kv_cache_dtype: DType,
- scfg: &SpecificConfig,
- ) -> Config {
- Config {
- hidden_size: self.hidden_size,
- head_dim: Some(self.hidden_size / self.num_attention_heads),
- intermediate_size: self.intermediate_size,
- vocab_size: self.vocab_size,
- num_hidden_layers: self.num_hidden_layers,
- num_attention_heads: self.num_attention_heads,
- num_key_value_heads: self.num_key_value_heads.unwrap_or(self.num_attention_heads),
- rms_norm_eps: self.layer_norm_eps,
- rope_theta: self.rope_theta,
- rope_local_base_freq: None,
- bos_token_id: self.bos_token_id,
- eos_token_id: self.eos_token_id,
- max_seq_len: self.max_position_embeddings,
- sliding_window: self.sliding_window,
- sliding_window_pattern: None,
- hidden_act: Some(self.hidden_act),
- tie_word_embeddings: false,
- rope_scaling: None,
- use_flash_attn,
- original_max_position_embeddings: self.original_max_position_embeddings,
- attention_bias: false,
- partial_rotary_factor: Some(self.partial_rotary_factor),
- qk_layer_rms_norm: Some(self.qk_layernorm),
- kv_cache_dtype,
- use_qkv_bias: None,
- custom_stop_tokens: None,
- specific_config: scfg.clone(),
- attn_logit_softcapping: None,
- final_logit_softcapping: None,
- quantization_config: self.quantization_config,
- moe_config: None,
+impl Phi2 {
+ pub fn load_config(filename: &PathBuf, isq: Option) -> Result {
+ let mut config = Config::load_config(filename.clone())?;
+ config.head_dim = Some(
+ config
+ .head_dim
+ .unwrap_or(config.hidden_size / config.num_attention_heads),
+ );
+ config.num_key_value_heads = Some(
+ config
+ .num_key_value_heads
+ .unwrap_or(config.num_attention_heads),
+ );
+ config.max_seq_len = config.max_position_embeddings.unwrap_or(config.max_seq_len);
+ if config.quantization_config.is_some() {
+ config.quant = Some(
+ config
+ .quantization_config
+ .as_ref()
+ .unwrap()
+ .quant_method
+ .clone(),
+ );
+ } else if isq.is_some() {
+ config.quant = Some(isq.unwrap().to_string());
}
+ Ok(config)
}
}
@@ -137,7 +101,7 @@ impl Mlp {
false,
vb.pp("gate_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let fc2 = TensorParallelRowLinear::load_with_hints(
@@ -146,7 +110,7 @@ impl Mlp {
false,
vb.pp("down_proj"),
comm,
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
Ok(Self {
@@ -182,7 +146,7 @@ struct Attention {
impl Attention {
fn new(cfg: &Config, vb: VarBuilder, comm: Rc) -> Result {
let num_heads = cfg.num_attention_heads;
- let num_kv_heads = cfg.num_key_value_heads;
+ let num_kv_heads = cfg.num_key_value_heads.unwrap();
let head_dim = cfg.hidden_size / cfg.num_attention_heads;
let q_proj = TensorParallelColumnLinear::load_with_hints(
@@ -191,7 +155,7 @@ impl Attention {
false,
vb.pp("q_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let k_proj = TensorParallelColumnLinear::load_with_hints(
@@ -200,7 +164,7 @@ impl Attention {
false,
vb.pp("k_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let v_proj = TensorParallelColumnLinear::load_with_hints(
@@ -209,7 +173,7 @@ impl Attention {
false,
vb.pp("v_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
@@ -219,12 +183,12 @@ impl Attention {
false,
vb.pp("o_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
// Alternative rope scalings are not supported.
let rotary_emb = RotaryEmbedding::new(cfg, vb.dtype(), vb.device())?;
- let (q_layernorm, k_layernorm) = if cfg.qk_layer_rms_norm.unwrap() {
+ let (q_layernorm, k_layernorm) = if cfg.qk_layernorm {
let q_layernorm = layer_norm(head_dim, cfg.rms_norm_eps, true, vb.pp("q_layernorm"))?;
let k_layernorm = layer_norm(head_dim, cfg.rms_norm_eps, true, vb.pp("k_layernorm"))?;
(Some(q_layernorm), Some(k_layernorm))
@@ -232,7 +196,7 @@ impl Attention {
(None, None)
};
let attention_heads = cfg.num_attention_heads / comm.world_size();
- let kv_heads = cfg.num_key_value_heads / comm.world_size();
+ let kv_heads = cfg.num_key_value_heads.unwrap() / comm.world_size();
Ok(Self {
q_proj,
k_proj,
diff --git a/src/openai/models/phi3.rs b/src/openai/models/phi3.rs
index 1b5b657b..d116f441 100644
--- a/src/openai/models/phi3.rs
+++ b/src/openai/models/phi3.rs
@@ -1,83 +1,49 @@
// This implementation is based on:
// https://huggingface.co/microsoft/Phi-3-mini-4k-instruct/blob/main/modeling_phi3.py
-use super::{Config, QuantConfig, RopeScaling};
+use super::{Config, RopeScaling, ScalingValue};
use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::openai::distributed::{
embedding, rms_norm, Comm, ReplicatedLinear, TensorParallelColumnLinear,
TensorParallelRowLinear, VarBuilder,
};
-use crate::openai::models::TokenID;
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle::{DType, Device, IndexOp, Module, Result, Tensor, D};
use candle_core as candle;
use candle_nn::RmsNorm;
use either::Either;
-use std::collections::HashMap;
use std::iter::zip;
+use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{Arc, RwLock};
-#[derive(Debug, Clone, serde::Deserialize)]
-pub struct PhiConfig {
- pub vocab_size: usize,
- pub hidden_act: candle_nn::Activation,
- pub hidden_size: usize,
- pub intermediate_size: usize,
- pub num_hidden_layers: usize,
- pub num_attention_heads: usize,
- pub num_key_value_heads: usize,
- pub rms_norm_eps: f64,
- pub rope_theta: f64,
- pub bos_token_id: TokenID,
- pub eos_token_id: TokenID,
- pub rope_scaling: Option>,
- pub max_position_embeddings: usize,
- pub original_max_position_embeddings: Option,
- pub sliding_window: Option,
- pub quantization_config: Option,
-}
-impl PhiConfig {
- pub fn into_config(
- self,
- use_flash_attn: bool,
- kv_cache_dtype: DType,
- scfg: &SpecificConfig,
- ) -> Config {
- Config {
- hidden_size: self.hidden_size,
- head_dim: Some(self.hidden_size / self.num_attention_heads),
- intermediate_size: self.intermediate_size,
- vocab_size: self.vocab_size,
- num_hidden_layers: self.num_hidden_layers,
- num_attention_heads: self.num_attention_heads,
- num_key_value_heads: self.num_key_value_heads,
- rms_norm_eps: self.rms_norm_eps,
- rope_theta: self.rope_theta,
- rope_local_base_freq: None,
- use_flash_attn,
- bos_token_id: self.bos_token_id,
- eos_token_id: self.eos_token_id,
- max_seq_len: self.max_position_embeddings,
- sliding_window: self.sliding_window,
- sliding_window_pattern: None,
- hidden_act: Some(self.hidden_act),
- tie_word_embeddings: false,
- rope_scaling: self.rope_scaling,
- original_max_position_embeddings: self.original_max_position_embeddings,
- attention_bias: false,
- partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
- use_qkv_bias: None,
- custom_stop_tokens: None,
- specific_config: scfg.clone(),
- attn_logit_softcapping: None,
- final_logit_softcapping: None,
- quantization_config: self.quantization_config,
- moe_config: None,
+impl Phi {
+ pub fn load_config(filename: &PathBuf, isq: Option) -> Result {
+ let mut config = Config::load_config(filename.clone())?;
+ config.head_dim = Some(
+ config
+ .head_dim
+ .unwrap_or(config.hidden_size / config.num_attention_heads),
+ );
+ config.num_key_value_heads = Some(
+ config
+ .num_key_value_heads
+ .unwrap_or(config.num_attention_heads),
+ );
+ config.max_seq_len = config.max_position_embeddings.unwrap_or(config.max_seq_len);
+ if config.quantization_config.is_some() {
+ config.quant = Some(
+ config
+ .quantization_config
+ .as_ref()
+ .unwrap()
+ .quant_method
+ .clone(),
+ );
+ } else if isq.is_some() {
+ config.quant = Some(isq.unwrap().to_string());
}
+ Ok(config)
}
}
@@ -94,9 +60,10 @@ impl RotaryEmbedding {
fn new(_dtype: DType, cfg: &Config, dev: &Device) -> Result {
let dim = cfg.hidden_size / cfg.num_attention_heads;
let max_seq_len = cfg.max_seq_len;
+ let rope_theta = cfg.rope_theta;
let inv_freq: Vec<_> = (0..dim)
.step_by(2)
- .map(|i| 1f32 / cfg.rope_theta.powf(i as f64 / dim as f64) as f32)
+ .map(|i| 1f32 / rope_theta.powf(i as f64 / dim as f64) as f32)
.collect();
let inv_freq_len = inv_freq.len();
let inv_freq = Tensor::from_vec(inv_freq, (1, inv_freq_len), dev)?.to_dtype(DType::F32)?;
@@ -112,19 +79,18 @@ impl RotaryEmbedding {
&rope_scaling["type"],
) {
(
- RopeScaling(Either::Left(short_factor)),
- RopeScaling(Either::Left(long_factor)),
+ RopeScaling(Either::Left(ScalingValue(Either::Right(short_factor)))),
+ RopeScaling(Either::Left(ScalingValue(Either::Right(long_factor)))),
RopeScaling(Either::Right(tp)),
) => {
- let scale = cfg.max_seq_len as f64
- / cfg.original_max_position_embeddings.unwrap() as f64;
+ let scale =
+ cfg.max_seq_len as f64 / cfg.original_max_position_embeddings as f64;
let scaling_factor = if scale <= 1.0 {
1.0
} else {
match tp.as_str() {
"su" | "longrope" => (1.0
- + scale.ln()
- / (cfg.original_max_position_embeddings.unwrap() as f64).ln())
+ + scale.ln() / (cfg.original_max_position_embeddings as f64).ln())
.sqrt(),
"yarn" => 0.1 * scale.ln() + 1.0,
_ => 1.0,
@@ -135,7 +101,7 @@ impl RotaryEmbedding {
.step_by(2)
.enumerate()
.map(|(k, i)| {
- (1f64 / (long_factor[k] * cfg.rope_theta.powf(i as f64 / dim as f64)))
+ (1f64 / (long_factor[k] * rope_theta.powf(i as f64 / dim as f64)))
as f32
})
.collect::>();
@@ -143,7 +109,7 @@ impl RotaryEmbedding {
.step_by(2)
.enumerate()
.map(|(k, i)| {
- (1f64 / (short_factor[k] * cfg.rope_theta.powf(i as f64 / dim as f64)))
+ (1f64 / (short_factor[k] * rope_theta.powf(i as f64 / dim as f64)))
as f32
})
.collect::>();
@@ -172,7 +138,9 @@ impl RotaryEmbedding {
cos: short_cos,
sin_long: Some(long_sin),
cos_long: Some(long_cos),
- original_max_position_embeddings: cfg.original_max_position_embeddings,
+ original_max_position_embeddings: Some(
+ cfg.original_max_position_embeddings,
+ ),
});
}
_ => {
@@ -204,7 +172,6 @@ impl RotaryEmbedding {
for (b, seqlen_offset) in zip(0..b_size, input_positions) {
let (cos, sin) = if self.sin_long.as_ref().is_some()
&& self.cos_long.as_ref().is_some()
- && self.original_max_position_embeddings.is_some()
&& seqlen_offset[0] > self.original_max_position_embeddings.unwrap()
{
let cos = self
@@ -252,21 +219,21 @@ impl Attention {
comm: Rc,
) -> Result {
let num_heads = cfg.num_attention_heads;
- let num_kv_heads = cfg.num_key_value_heads;
+ let num_kv_heads = cfg.num_key_value_heads.unwrap();
let head_dim = cfg.hidden_size / cfg.num_attention_heads;
let op_size = num_heads * head_dim + 2 * num_kv_heads * head_dim;
let qkv_proj = ReplicatedLinear::load_no_bias(
cfg.hidden_size,
op_size,
vb.pp("qkv_proj"),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let o_proj = ReplicatedLinear::load_no_bias(
num_heads * head_dim,
cfg.hidden_size,
vb.pp("o_proj"),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
//Fix the attention parallel
@@ -275,7 +242,7 @@ impl Attention {
"Packed qkv_proj is not supported under multi-gpu setting!"
);
let attention_heads = cfg.num_attention_heads / comm.world_size();
- let kv_heads = cfg.num_key_value_heads / comm.world_size();
+ let kv_heads = cfg.num_key_value_heads.unwrap() / comm.world_size();
Ok(Self {
qkv_proj,
o_proj,
@@ -381,7 +348,7 @@ impl Mlp {
false,
vb.pp("gate_up_proj"),
comm.clone(),
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
let down_proj = TensorParallelRowLinear::load_with_hints(
@@ -390,7 +357,7 @@ impl Mlp {
false,
vb.pp("down_proj"),
comm,
- &cfg.specific_config.quant,
+ &cfg.quant,
&cfg.quantization_config,
)?;
Ok(Self {
diff --git a/src/openai/models/quantized_glm4.rs b/src/openai/models/quantized_glm4.rs
index cea6c143..f65d5423 100644
--- a/src/openai/models/quantized_glm4.rs
+++ b/src/openai/models/quantized_glm4.rs
@@ -3,7 +3,6 @@ use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::openai::models::glm4::RotaryEmbedding;
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle_core::quantized::{gguf_file, QMatMul};
use candle_core::{DType, Device, IndexOp, Result, Tensor};
use candle_nn::{Embedding, Module};
@@ -152,44 +151,43 @@ impl GGUFGLM4 {
block_count: usize,
head_count: usize,
head_count_kv: usize,
- rope_theta: f32,
+ rope_theta: f64,
rms_eps: f64,
max_seq_len: usize,
- kv_cache_dtype: DType,
- s_cfg: SpecificConfig,
) -> Config {
Config {
+ architectures: Some(vec!["glm4".to_string()]),
hidden_size: embedding_length,
head_dim: Some(head_dim),
intermediate_size: i_size,
vocab_size: 0,
num_hidden_layers: block_count,
num_attention_heads: head_count,
- num_key_value_heads: head_count_kv,
+ num_key_value_heads: Some(head_count_kv),
rms_norm_eps: rms_eps,
- rope_theta: rope_theta as f64,
+ rope_theta,
rope_local_base_freq: None,
- use_flash_attn: false,
- bos_token_id: super::TokenID(Either::Left(None)),
+ bos_token_id: None,
eos_token_id: super::TokenID(Either::Left(None)),
max_seq_len,
sliding_window: None,
sliding_window_pattern: None,
hidden_act: None,
+ hidden_activation: None,
tie_word_embeddings: false,
rope_scaling: None,
- original_max_position_embeddings: Some(max_seq_len),
- attention_bias: false,
+ max_position_embeddings: Some(max_seq_len),
+ original_max_position_embeddings: max_seq_len,
+ attention_bias: Some(false),
partial_rotary_factor: Some(0.5),
- qk_layer_rms_norm: None,
- kv_cache_dtype,
+ qk_layernorm: false,
use_qkv_bias: None,
custom_stop_tokens: None,
- specific_config: s_cfg,
attn_logit_softcapping: None,
final_logit_softcapping: None,
quantization_config: None,
moe_config: None,
+ quant: Some("gguf".to_string()),
}
}
@@ -206,7 +204,6 @@ impl GGUFGLM4 {
reader: &mut R,
device: &Device,
dtype: DType,
- s_cfg: SpecificConfig,
progress_reporter: Arc>,
) -> Result {
let md_get = |s: &str| match ct.metadata.get(s) {
@@ -254,11 +251,9 @@ impl GGUFGLM4 {
block_count,
head_count,
head_count_kv,
- rope_freq_base,
+ rope_freq_base as f64,
rms_norm_eps,
context_length,
- dtype,
- s_cfg,
);
let rotary_emb = Arc::new(RotaryEmbedding::new(&cfg, dtype, device)?);
diff --git a/src/openai/models/quantized_llama.rs b/src/openai/models/quantized_llama.rs
index fe969985..3035ade6 100644
--- a/src/openai/models/quantized_llama.rs
+++ b/src/openai/models/quantized_llama.rs
@@ -2,7 +2,6 @@ use super::Config;
use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle_core::quantized::{ggml_file, gguf_file, QMatMul};
use candle_core::{DType, Device, IndexOp, Result, Tensor};
use candle_nn::{Embedding, Module};
@@ -10,7 +9,6 @@ use candle_transformers::quantized_nn::RmsNorm;
use either::Either;
use std::iter::zip;
use std::sync::{Arc, RwLock};
-pub const MAX_SEQ_LEN: usize = 4096;
#[derive(Debug, Clone)]
struct Mlp {
@@ -247,53 +245,46 @@ impl GGUFLLaMa {
head_count_kv: usize,
rms_eps: f64,
max_seq_len: usize,
- kv_cache_dtype: DType,
- s_cfg: SpecificConfig,
) -> Config {
Config {
+ architectures: Some(vec!["llama".to_string()]),
hidden_size: embedding_length,
head_dim: Some(head_dim),
intermediate_size: i_size,
vocab_size: 0,
num_hidden_layers: block_count,
num_attention_heads: head_count,
- num_key_value_heads: head_count_kv,
+ num_key_value_heads: Some(head_count_kv),
rms_norm_eps: rms_eps,
- rope_theta: 0.,
+ rope_theta: 10_000.0f64,
rope_local_base_freq: None,
- use_flash_attn: false,
- bos_token_id: super::TokenID(Either::Left(Some(128256))),
+ bos_token_id: Some(super::TokenID(Either::Left(Some(128256)))),
eos_token_id: super::TokenID(Either::Left(Some(128257))),
max_seq_len,
sliding_window: None,
sliding_window_pattern: None,
hidden_act: None,
+ hidden_activation: None,
tie_word_embeddings: false,
rope_scaling: None,
- original_max_position_embeddings: Some(max_seq_len),
- attention_bias: false,
+ max_position_embeddings: Some(max_seq_len),
+ original_max_position_embeddings: max_seq_len,
+ attention_bias: Some(false),
partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
+ qk_layernorm: false,
use_qkv_bias: None,
custom_stop_tokens: Some(vec!["<|end_of_text|>".to_string()]),
- specific_config: s_cfg,
attn_logit_softcapping: None,
final_logit_softcapping: None,
quantization_config: None,
moe_config: None,
+ quant: Some("gguf".to_string()),
}
}
- pub fn from_ggml(
- mut ct: ggml_file::Content,
- gqa: usize,
- dtype: DType,
- s_cfg: SpecificConfig,
- ) -> Result {
+ pub fn from_ggml(mut ct: ggml_file::Content, gqa: usize, dtype: DType) -> Result {
let head_dim = (ct.hparams.n_embd / ct.hparams.n_head) as usize;
- let (cos, sin) =
- precomput_freqs_cis(head_dim, 10000., MAX_SEQ_LEN, &ct.device, DType::F32)?;
+ let (cos, sin) = precomput_freqs_cis(head_dim, 10000., 8192, &ct.device, DType::F32)?;
let tok_embeddings = ct.remove("tok_embeddings.weight")?;
let tok_embeddings = tok_embeddings.dequantize(&ct.device)?;
let norm = RmsNorm::from_qtensor(ct.remove("norm.weight")?, 1e-5)?;
@@ -356,8 +347,6 @@ impl GGUFLLaMa {
ct.hparams.n_head as usize / gqa,
1e-5,
0,
- dtype,
- s_cfg,
),
dtype,
device: ct.device.clone(),
@@ -377,7 +366,6 @@ impl GGUFLLaMa {
reader: &mut R,
device: &Device,
dtype: DType,
- s_cfg: SpecificConfig,
progress_reporter: Arc>,
) -> Result {
let md_get = |s: &str| match ct.metadata.get(s) {
@@ -399,7 +387,7 @@ impl GGUFLLaMa {
let embedding_length = md_get("llama.embedding_length")?.to_u32()? as usize;
// let rope_dim = md_get("llama.rope.dimension_count")?.to_u32()? as usize;
let context_length = md_get("llama.context_length")?.to_u32();
- let context_length = context_length.map_or(MAX_SEQ_LEN, |v| v as usize);
+ let context_length = context_length.map_or(8192, |v| v as usize);
let head_dim = md_get("llama.attention.key_length");
let head_dim = if head_dim.is_ok() {
@@ -513,8 +501,6 @@ impl GGUFLLaMa {
head_count_kv,
rms_norm_eps,
context_length,
- dtype,
- s_cfg,
),
dtype,
device: device.clone(),
diff --git a/src/openai/models/quantized_phi3.rs b/src/openai/models/quantized_phi3.rs
index c05f9808..0a26ae21 100644
--- a/src/openai/models/quantized_phi3.rs
+++ b/src/openai/models/quantized_phi3.rs
@@ -2,7 +2,6 @@ use super::Config;
use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle_core::quantized::gguf_file;
use candle_core::quantized::QTensor;
use candle_core::{DType, Device, IndexOp, Module, Result, Tensor, D};
@@ -199,41 +198,40 @@ impl GGUFPhi3 {
head_count_kv: usize,
rms_eps: f64,
max_seq_len: usize,
- kv_cache_dtype: DType,
- s_cfg: SpecificConfig,
) -> Config {
Config {
+ architectures: Some(vec!["phi3".to_string()]),
hidden_size: embedding_length,
head_dim: Some(embedding_length / head_count),
intermediate_size: i_size,
vocab_size: 0,
num_hidden_layers: block_count,
num_attention_heads: head_count,
- num_key_value_heads: head_count_kv,
+ num_key_value_heads: Some(head_count_kv),
rms_norm_eps: rms_eps,
- rope_theta: 0.,
+ rope_theta: 10_000.0f64,
rope_local_base_freq: None,
- use_flash_attn: false,
- bos_token_id: super::TokenID(Either::Left(Some(1))),
+ bos_token_id: Some(super::TokenID(Either::Left(Some(1)))),
eos_token_id: super::TokenID(Either::Left(Some(2))),
max_seq_len,
sliding_window: None,
sliding_window_pattern: None,
hidden_act: None,
+ hidden_activation: None,
tie_word_embeddings: false,
rope_scaling: None,
- original_max_position_embeddings: Some(max_seq_len),
- attention_bias: false,
+ max_position_embeddings: Some(max_seq_len),
+ original_max_position_embeddings: max_seq_len,
+ attention_bias: Some(false),
partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
+ qk_layernorm: false,
use_qkv_bias: None,
custom_stop_tokens: None,
- specific_config: s_cfg,
attn_logit_softcapping: None,
final_logit_softcapping: None,
quantization_config: None,
moe_config: None,
+ quant: Some("gguf".to_string()),
}
}
@@ -250,7 +248,6 @@ impl GGUFPhi3 {
reader: &mut R,
device: &Device,
dtype: DType,
- s_cfg: SpecificConfig,
progress_reporter: Arc>,
) -> Result {
let md_get = |s: &str| match ct.metadata.get(s) {
@@ -331,8 +328,6 @@ impl GGUFPhi3 {
head_count_kv,
rms_eps,
max_seq_len,
- dtype,
- s_cfg,
),
dtype,
device: device.clone(),
diff --git a/src/openai/models/quantized_qwen.rs b/src/openai/models/quantized_qwen.rs
index 46eb4ae9..6c29ef91 100644
--- a/src/openai/models/quantized_qwen.rs
+++ b/src/openai/models/quantized_qwen.rs
@@ -2,7 +2,6 @@ use super::Config;
use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle_core::quantized::{gguf_file, QMatMul};
use candle_core::{DType, Device, IndexOp, Result, Tensor};
use candle_nn::{Embedding, Module};
@@ -206,41 +205,40 @@ impl GGUFQWen {
head_count_kv: usize,
rms_eps: f64,
max_seq_len: usize,
- kv_cache_dtype: DType,
- s_cfg: SpecificConfig,
) -> Config {
Config {
+ architectures: Some(vec!["qwen".to_string()]),
hidden_size: embedding_length,
head_dim: Some(head_dim),
intermediate_size: i_size,
vocab_size: 0,
num_hidden_layers: block_count,
num_attention_heads: head_count,
- num_key_value_heads: head_count_kv,
+ num_key_value_heads: Some(head_count_kv),
rms_norm_eps: rms_eps,
- rope_theta: 0.,
+ rope_theta: 10_000.0f64,
rope_local_base_freq: None,
- use_flash_attn: false,
- bos_token_id: super::TokenID(Either::Left(Some(151644))),
+ bos_token_id: Some(super::TokenID(Either::Left(Some(151644)))),
eos_token_id: super::TokenID(Either::Left(Some(151645))),
max_seq_len,
sliding_window: None,
sliding_window_pattern: None,
hidden_act: None,
+ hidden_activation: None,
tie_word_embeddings: false,
rope_scaling: None,
- original_max_position_embeddings: Some(max_seq_len),
- attention_bias: false,
+ max_position_embeddings: Some(max_seq_len),
+ original_max_position_embeddings: max_seq_len,
+ attention_bias: Some(false),
partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
+ qk_layernorm: false,
use_qkv_bias: None,
custom_stop_tokens: None,
- specific_config: s_cfg,
attn_logit_softcapping: None,
final_logit_softcapping: None,
quantization_config: None,
moe_config: None,
+ quant: Some("gguf".to_string()),
}
}
@@ -261,7 +259,6 @@ impl GGUFQWen {
reader: &mut R,
device: &Device,
dtype: DType,
- s_cfg: SpecificConfig,
progress_reporter: Arc>,
) -> Result {
let md_get = |s: &str| match ct.metadata.get(s) {
@@ -433,8 +430,6 @@ impl GGUFQWen {
head_count_kv,
rms_norm_eps,
context_length,
- dtype,
- s_cfg,
),
dtype,
device: device.clone(),
diff --git a/src/openai/models/qwen.rs b/src/openai/models/qwen.rs
index 140844d4..2537e2a9 100644
--- a/src/openai/models/qwen.rs
+++ b/src/openai/models/qwen.rs
@@ -1,90 +1,47 @@
-use super::{Config, QuantConfig};
+use super::Config;
use crate::backend::progress::{ProgressLike, ProgressReporter};
use crate::openai::distributed::{
embedding, rms_norm, Comm, ReplicatedLinear, TensorParallelColumnLinear,
TensorParallelRowLinear, VarBuilder,
};
-use crate::openai::models::TokenID;
use crate::paged_attention::input_metadata::InputMetadata;
use crate::paged_attention::PagedAttention;
-use crate::SpecificConfig;
use candle::{DType, Device, IndexOp, Module, Result, Tensor};
use candle_core as candle;
use candle_nn::RmsNorm;
use std::iter::zip;
+use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{Arc, RwLock};
-#[derive(Debug, Clone, serde::Deserialize)]
-pub struct QwenConfig {
- pub vocab_size: usize,
- pub hidden_size: usize,
- pub head_dim: Option,
- pub intermediate_size: usize,
- pub num_hidden_layers: usize,
- pub num_attention_heads: usize,
- pub num_key_value_heads: usize,
- pub max_position_embeddings: usize,
- pub sliding_window: Option,
- pub max_window_layers: usize,
- pub tie_word_embeddings: bool, //shared weights between input/output embeddings
- pub attention_bias: Option,
- pub rope_theta: f64,
- pub rms_norm_eps: f64,
- pub use_sliding_window: Option,
- pub hidden_act: candle_nn::Activation,
- pub bos_token_id: TokenID,
- pub eos_token_id: TokenID,
- pub quantization_config: Option,
-}
-impl QwenConfig {
- pub fn into_config(
- self,
- use_flash_attn: bool,
- kv_cache_dtype: DType,
- scfg: &SpecificConfig,
- ) -> Config {
- let sliding_window = if self.use_sliding_window.unwrap_or(false) {
- self.sliding_window
- } else {
- None
- };
- Config {
- hidden_size: self.hidden_size,
- head_dim: Some(
- self.head_dim
- .unwrap_or(self.hidden_size / self.num_attention_heads),
- ),
- intermediate_size: self.intermediate_size,
- vocab_size: self.vocab_size,
- num_hidden_layers: self.num_hidden_layers,
- num_attention_heads: self.num_attention_heads,
- num_key_value_heads: self.num_key_value_heads,
- rms_norm_eps: self.rms_norm_eps,
- rope_theta: self.rope_theta,
- rope_local_base_freq: None,
- use_flash_attn,
- bos_token_id: self.bos_token_id,
- eos_token_id: self.eos_token_id,
- max_seq_len: self.max_position_embeddings,
- sliding_window,
- sliding_window_pattern: None,
- hidden_act: Some(self.hidden_act),
- tie_word_embeddings: self.tie_word_embeddings,
- rope_scaling: None,
- original_max_position_embeddings: None,
- attention_bias: self.attention_bias.unwrap_or(true),
- partial_rotary_factor: None,
- qk_layer_rms_norm: None,
- kv_cache_dtype,
- use_qkv_bias: None,
- custom_stop_tokens: None,
- specific_config: scfg.clone(),
- attn_logit_softcapping: None,
- final_logit_softcapping: None,
- quantization_config: self.quantization_config,
- moe_config: None,
+impl Qwen {
+ pub fn load_config(filename: &PathBuf, isq: Option