mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-08-08 12:48:01 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1470ee6a2 | ||
|
|
217df17ac3 | ||
|
|
cb26014d96 | ||
|
|
82bb48500a | ||
|
|
42e98813e4 | ||
|
|
fc3f10b389 | ||
|
|
6b5c2efb4e | ||
|
|
31558dbb76 | ||
|
|
c1f4109898 | ||
|
|
eef5f3e343 | ||
|
|
c074cb3f76 | ||
|
|
5b87ed30f8 | ||
|
|
d8d9887228 | ||
|
|
e40bf88642 | ||
|
|
15586e2d71 | ||
|
|
6a32c29a74 | ||
|
|
eb5667a169 |
@@ -643,39 +643,52 @@ function gg_sum_rerank_tiny {
|
||||
|
||||
function gg_check_build_requirements {
|
||||
if ! command -v git &> /dev/null; then
|
||||
gg_printf 'git not found, please install'
|
||||
gg_printf 'git not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v git-lfs &> /dev/null; then
|
||||
gg_printf 'git-lfs not found, please install'
|
||||
gg_printf 'git-lfs not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git config --get filter.lfs.clean &> /dev/null; then
|
||||
gg_printf 'git-lfs not initialized, please run `git lfs install`\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v wget &> /dev/null; then
|
||||
gg_printf 'wget not found, please install'
|
||||
gg_printf 'wget not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
gg_printf 'python3 not found, please install'
|
||||
gg_printf 'python3 not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v pip3 &> /dev/null; then
|
||||
gg_printf 'pip3 not found, please install'
|
||||
gg_printf 'pip3 not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! python3 -m ensurepip --help &> /dev/null; then
|
||||
gg_printf 'ensurepip not found, please install python3-venv package'
|
||||
gg_printf 'ensurepip not found, please install python3-venv package\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v cmake &> /dev/null; then
|
||||
gg_printf 'cmake not found, please install'
|
||||
gg_printf 'cmake not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v ccache &> /dev/null; then
|
||||
gg_printf 'ccache not found, please consider installing for faster builds'
|
||||
gg_printf 'ccache not found, please consider installing for faster builds\n'
|
||||
fi
|
||||
|
||||
if ! command -v ctest &> /dev/null; then
|
||||
gg_printf 'ctest not found, please install'
|
||||
gg_printf 'ctest not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -533,6 +533,13 @@ class DeepseekV4Model(TextModel):
|
||||
for key, value in raw_hparams.items():
|
||||
self.hparams.setdefault(key, value)
|
||||
|
||||
# workaround for special rope_parameters (main/compress) in transformers 5.x
|
||||
if self.rope_parameters.get("full_attention", self.rope_parameters).get("rope_type") is None:
|
||||
if (rope_scaling := raw_hparams.get("rope_scaling")) is not None:
|
||||
if "rope_type" not in rope_scaling and (rope_type := rope_scaling.get("type")) is not None:
|
||||
rope_scaling["rope_type"] = rope_type
|
||||
self.rope_parameters.update(**rope_scaling)
|
||||
|
||||
self.block_count = self.hparams["num_hidden_layers"]
|
||||
if self.mtp_only:
|
||||
self.block_count += self.hparams.get("num_nextn_predict_layers", 0)
|
||||
|
||||
@@ -449,6 +449,8 @@ Or
|
||||
use 1 SYCL GPUs: [0] with Max compute units:512
|
||||
```
|
||||
|
||||
User can use the device management in [docs/multi-gpu.md](https://github.com/ggml-org/llama.cpp/blob/master/docs/multi-gpu.md), like parameter `--device SYCL0,SYCL1` to assign one or more devices.
|
||||
|
||||
## Windows
|
||||
|
||||
### Install GPU driver
|
||||
@@ -763,6 +765,7 @@ Or
|
||||
use 1 SYCL GPUs: [0] with Max compute units:512
|
||||
```
|
||||
|
||||
User can use the device management in [docs/multi-gpu.md](https://github.com/ggml-org/llama.cpp/blob/master/docs/multi-gpu.md), like parameter `--device SYCL0,SYCL1` to assign one or more devices.
|
||||
|
||||
## Environment Variable
|
||||
|
||||
@@ -895,6 +898,45 @@ Pass these via `CXXFLAGS` or add a one-off `#define` to enable a flag on the spo
|
||||
set UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1
|
||||
```
|
||||
|
||||
- When I set `SYCL_CACHE_PERSISTENT=1` in running time, I meet crash.
|
||||
|
||||
`SYCL_CACHE_PERSISTENT=1` is not recommended by llama.cpp SYCL backend.
|
||||
When cache is enabled, SYCL runtime will try to cache and reuse JIT-compiled binaries.
|
||||
|
||||
We find some AI will tell user this cmd to speed up SYCL backend. It only speeds up the startup to skip the JIT process, instead of running speed.
|
||||
|
||||
It will bring negative impact when the SYCL binary file is changed frequently in your running environment. The new & old codes mix will lead to crash.
|
||||
|
||||
Compare to the benefit, it has brought more failed cases.
|
||||
If you are not familiar with the SYCL compiler principle of JIT and AOT, please don't use it.
|
||||
|
||||
To restore, you need to remove the local cache: `~/.cache/libsycl_cache/` and execute `unset SYCL_CACHE_PERSISTENT` in running time.
|
||||
|
||||
- How to use iGPU and dGPU in same time?
|
||||
|
||||
1. Detect the devices in your running time.
|
||||
```
|
||||
source /opt/intel/oneapi/setvars.sh
|
||||
./build/bin/llama-server --list-devices
|
||||
|
||||
or
|
||||
./build/bin/llama-cli --list-devices
|
||||
./build/bin/llama-bench --list-devices
|
||||
./build/bin/llama-completion --list-devices
|
||||
|
||||
Available devices:
|
||||
SYCL0: Intel(R) Arc(TM) A770 Graphics (15473 MiB, 15473 MiB free)
|
||||
SYCL1: Intel(R) UHD Graphics 770 (59675 MiB, 44986 MiB free)
|
||||
```
|
||||
|
||||
The dGPU will be in the head of this list and iGPU will be the end.
|
||||
If not all GPUs are listed, please check the env var: ONEAPI_DEVICE_SELECTOR and unset it.
|
||||
|
||||
2. Set the iGPU and dGPU
|
||||
|
||||
Set the iGPU and dGPU by `./build/bin/llama-server --device SYCL0,SYCL1,SYCLxxx`.
|
||||
|
||||
|
||||
### **GitHub contribution**:
|
||||
Please add the `[SYCL]` prefix/tag in issues/PRs titles to help the SYCL contributors to check/address them without delay.
|
||||
|
||||
|
||||
+6
-6
@@ -15,7 +15,7 @@ Legend:
|
||||
| Operation | BLAS | CANN | CPU | CUDA | ET | MTL | OpenCL | SYCL | Vulkan | WebGPU | ZenDNN | zDNN |
|
||||
|-----------|------|------|------|------|------|------|------|------|------|------|------|------|
|
||||
| ABS | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ACC | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | 🟡 | ✅ | ❌ | ❌ | ❌ |
|
||||
| ACC | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| ADD | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ADD1 | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| ADD_ID | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -41,9 +41,9 @@ Legend:
|
||||
| DIAG | ❌ | ❌ | ✅ | ✅ | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| DIAG_MASK_INF | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | 🟡 | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| DIV | ❌ | ✅ | ✅ | ✅ | ❌ | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| DSV4_HC_COMB | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_POST | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_PRE | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_COMB | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_POST | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_PRE | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DUP | ❌ | ✅ | ✅ | 🟡 | ❌ | 🟡 | 🟡 | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| ELU | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| EXP | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -59,7 +59,7 @@ Legend:
|
||||
| GELU | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| GELU_ERF | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| GELU_QUICK | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| GET_ROWS | ❌ | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| GET_ROWS | ❌ | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | ❌ | ❌ |
|
||||
| GET_ROWS_BACK | ❌ | ❌ | 🟡 | 🟡 | ❌ | ❌ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ |
|
||||
| GROUP_NORM | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| HARDSIGMOID | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -68,7 +68,7 @@ Legend:
|
||||
| IM2COL_3D | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| L2_NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ❌ | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| LEAKY_RELU | ❌ | ✅ | ✅ | ✅ | ❌ | 🟡 | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| LIGHTNING_INDEXER | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| LIGHTNING_INDEXER | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| LOG | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MEAN | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| MUL | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
|
||||
+22870
-671
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ This script processes files with specified options.
|
||||
|
||||
Options:
|
||||
-h, --help Display this help message and exit.
|
||||
-d, --device <value> Set SYCL devices (default: SYCL0).
|
||||
-c, --context <value> Set context length. Bigger need more memory.
|
||||
-p, --promote <value> Prompt to start generation with.
|
||||
-m, --model <value> Full model file path.
|
||||
@@ -41,10 +42,16 @@ MODEL_FILE=../models/Qwen3.5-4B-Q4_0.gguf
|
||||
NGL=99
|
||||
CONTEXT=4096
|
||||
GGML_SYCL_DEVICE=-1
|
||||
SYCL_DEVICES="SYCL0"
|
||||
SPLIT_MODE=layer
|
||||
LOG_VERBOSE=3
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-d|--device)
|
||||
SYCL_DEVICES="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-c|--context)
|
||||
CONTEXT=$2
|
||||
# Shift twice to consume both the option flag and its value
|
||||
@@ -95,8 +102,6 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
|
||||
source /opt/intel/oneapi/setvars.sh
|
||||
|
||||
#export GGML_SYCL_DEBUG=1
|
||||
@@ -107,17 +112,19 @@ source /opt/intel/oneapi/setvars.sh
|
||||
export UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1
|
||||
echo "UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=${UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS}"
|
||||
|
||||
echo "ONEAPI_DEVICE_SELECTOR=${ONEAPI_DEVICE_SELECTOR}"
|
||||
|
||||
|
||||
if [ $GGML_SYCL_DEVICE -ne -1 ]; then
|
||||
echo "Use $GGML_SYCL_DEVICE as main GPU"
|
||||
#use signle GPU only
|
||||
GPUS_SETTING="-mg $GGML_SYCL_DEVICE -sm ${SPLIT_MODE}"
|
||||
echo "ONEAPI_DEVICE_SELECTOR=${ONEAPI_DEVICE_SELECTOR}"
|
||||
else
|
||||
echo "Use all Intel GPUs, including iGPU & dGPU"
|
||||
echo "Use Intel GPUs: ${SYCL_DEVICES}"
|
||||
GPUS_SETTING="-sm ${SPLIT_MODE}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "run cmd: ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --mmap --host 0.0.0.0 --port 8000"
|
||||
ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --mmap --host 0.0.0.0 --port 8000
|
||||
echo "run cmd: ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --device ${SYCL_DEVICES} --mmap --host 0.0.0.0 --port 8000"
|
||||
ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --device ${SYCL_DEVICES} --mmap --host 0.0.0.0 --port 8000
|
||||
|
||||
|
||||
|
||||
+12
-4
@@ -12,6 +12,7 @@ This script processes files with specified options.
|
||||
|
||||
Options:
|
||||
-h, --help Display this help message and exit.
|
||||
-d, --device <value> Set SYCL devices (default: SYCL0).
|
||||
-c, --context <value> Set context length. Bigger need more memory.
|
||||
-p, --promote <value> Prompt to start generation with.
|
||||
-m, --model <value> Full model file path.
|
||||
@@ -42,10 +43,16 @@ MODEL_FILE=../models/llama-2-7b.Q4_0.gguf
|
||||
NGL=99
|
||||
CONTEXT=4096
|
||||
GGML_SYCL_DEVICE=-1
|
||||
SYCL_DEVICES="SYCL0"
|
||||
SPLIT_MODE=layer
|
||||
LOG_VERBOSE=3
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-d|--device)
|
||||
SYCL_DEVICES="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-c|--context)
|
||||
CONTEXT=$2
|
||||
# Shift twice to consume both the option flag and its value
|
||||
@@ -115,16 +122,17 @@ source /opt/intel/oneapi/setvars.sh
|
||||
export UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1
|
||||
echo "UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=${UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS}"
|
||||
|
||||
echo "ONEAPI_DEVICE_SELECTOR=${ONEAPI_DEVICE_SELECTOR}"
|
||||
|
||||
if [ $GGML_SYCL_DEVICE -ne -1 ]; then
|
||||
echo "Use $GGML_SYCL_DEVICE as main GPU"
|
||||
#use signle GPU only
|
||||
GPUS_SETTING="-mg $GGML_SYCL_DEVICE -sm ${SPLIT_MODE}"
|
||||
echo "ONEAPI_DEVICE_SELECTOR=${ONEAPI_DEVICE_SELECTOR}"
|
||||
else
|
||||
echo "Use all Intel GPUs, including iGPU & dGPU"
|
||||
echo "Use Intel GPUs: ${SYCL_DEVICES}"
|
||||
GPUS_SETTING="-sm ${SPLIT_MODE}"
|
||||
fi
|
||||
|
||||
echo "run cmd: ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -no-cnv -p "${INPUT_PROMPT}" -n 200 -e -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --mmap "
|
||||
ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -no-cnv -p "${INPUT_PROMPT}" -n 200 -e -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --mmap
|
||||
echo "run cmd: ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -no-cnv -p "${INPUT_PROMPT}" -n 200 -e -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --device ${SYCL_DEVICES} --mmap "
|
||||
ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -no-cnv -p "${INPUT_PROMPT}" -n 200 -e -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --device ${SYCL_DEVICES} --mmap
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ set "MODEL_FILE=..\models\Qwen3.5-4B-Q4_0.gguf"
|
||||
set "NGL=99"
|
||||
set "CONTEXT=4096"
|
||||
set "GGML_SYCL_DEVICE=-1"
|
||||
set "SYCL_DEVICES=SYCL0"
|
||||
set "SPLIT_MODE=layer"
|
||||
set "LOG_VERBOSE=3"
|
||||
|
||||
@@ -36,6 +37,21 @@ if /I "%~1"=="--context" (
|
||||
goto parse_args
|
||||
)
|
||||
|
||||
if /I "%~1"=="-d" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "SYCL_DEVICES=%~2"
|
||||
shift
|
||||
shift
|
||||
goto parse_args
|
||||
)
|
||||
if /I "%~1"=="--device" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "SYCL_DEVICES=%~2"
|
||||
shift
|
||||
shift
|
||||
goto parse_args
|
||||
)
|
||||
|
||||
if /I "%~1"=="-m" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "MODEL_FILE=%~2"
|
||||
@@ -130,6 +146,7 @@ echo This script processes files with specified options.
|
||||
echo.
|
||||
echo Options:
|
||||
echo -h, --help Display this help message and exit.
|
||||
echo -d, --device ^<value^> Set SYCL devices (default: SYCL0).
|
||||
echo -c, --context ^<value^> Set context length. Bigger need more memory.
|
||||
echo -m, --model ^<value^> Full model file path.
|
||||
echo -mg,--main-gpu ^<value^> Set main GPU ID (0 - n) for single GPU mode.
|
||||
@@ -160,19 +177,20 @@ REM Support malloc device memory more than 4GB.
|
||||
set "UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1"
|
||||
echo UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=%UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS%
|
||||
|
||||
echo ONEAPI_DEVICE_SELECTOR=%ONEAPI_DEVICE_SELECTOR%
|
||||
|
||||
if not "%GGML_SYCL_DEVICE%"=="-1" (
|
||||
echo Use %GGML_SYCL_DEVICE% as main GPU
|
||||
REM Use single GPU only.
|
||||
set "GPUS_SETTING=-mg %GGML_SYCL_DEVICE% -sm %SPLIT_MODE%"
|
||||
echo ONEAPI_DEVICE_SELECTOR=%ONEAPI_DEVICE_SELECTOR%
|
||||
) else (
|
||||
echo Use all Intel GPUs, including iGPU ^& dGPU
|
||||
) else (
|
||||
echo Use Intel GPUs: %SYCL_DEVICES%
|
||||
set "GPUS_SETTING=-sm %SPLIT_MODE%"
|
||||
)
|
||||
|
||||
echo run cmd: ZES_ENABLE_SYSMAN=1 %BIN_FILE% -m "%MODEL_FILE%" -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --mmap --host 0.0.0.0 --port 8000
|
||||
echo run cmd: ZES_ENABLE_SYSMAN=1 %BIN_FILE% -m "%MODEL_FILE%" -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --device %SYCL_DEVICES% --mmap --host 0.0.0.0 --port 8000
|
||||
set "ZES_ENABLE_SYSMAN=1"
|
||||
%BIN_FILE% -m "%MODEL_FILE%" -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --mmap --host 0.0.0.0 --port 8000
|
||||
%BIN_FILE% -m "%MODEL_FILE%" -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --device "%SYCL_DEVICES%" --mmap --host 0.0.0.0 --port 8000
|
||||
|
||||
endlocal
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ set "MODEL_FILE=..\models\llama-2-7b.Q4_0.gguf"
|
||||
set "NGL=99"
|
||||
set "CONTEXT=4096"
|
||||
set "GGML_SYCL_DEVICE=-1"
|
||||
set "SYCL_DEVICES=SYCL0"
|
||||
set "SPLIT_MODE=layer"
|
||||
set "LOG_VERBOSE=3"
|
||||
|
||||
@@ -42,6 +43,21 @@ if /I "%~1"=="--context" (
|
||||
goto parse_args
|
||||
)
|
||||
|
||||
if /I "%~1"=="-d" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "SYCL_DEVICES=%~2"
|
||||
shift
|
||||
shift
|
||||
goto parse_args
|
||||
)
|
||||
if /I "%~1"=="--device" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "SYCL_DEVICES=%~2"
|
||||
shift
|
||||
shift
|
||||
goto parse_args
|
||||
)
|
||||
|
||||
if /I "%~1"=="-p" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "INPUT_PROMPT=%~2"
|
||||
@@ -151,6 +167,7 @@ echo This script processes files with specified options.
|
||||
echo.
|
||||
echo Options:
|
||||
echo -h, --help Display this help message and exit.
|
||||
echo -d, --device ^<value^> Set SYCL devices (default: SYCL0).
|
||||
echo -c, --context ^<value^> Set context length. Bigger need more memory.
|
||||
echo -p, --promote ^<value^> Prompt to start generation with.
|
||||
echo -m, --model ^<value^> Full model file path.
|
||||
@@ -182,19 +199,21 @@ REM Support malloc device memory more than 4GB.
|
||||
set "UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1"
|
||||
echo UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=%UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS%
|
||||
|
||||
echo ONEAPI_DEVICE_SELECTOR=%ONEAPI_DEVICE_SELECTOR%
|
||||
|
||||
if not "%GGML_SYCL_DEVICE%"=="-1" (
|
||||
echo Use %GGML_SYCL_DEVICE% as main GPU
|
||||
REM Use single GPU only.
|
||||
set "GPUS_SETTING=-mg %GGML_SYCL_DEVICE% -sm %SPLIT_MODE%"
|
||||
echo ONEAPI_DEVICE_SELECTOR=%ONEAPI_DEVICE_SELECTOR%
|
||||
) else (
|
||||
echo Use all Intel GPUs, including iGPU ^& dGPU
|
||||
)
|
||||
else (
|
||||
echo Use Intel GPUs: %SYCL_DEVICES%
|
||||
set "GPUS_SETTING=-sm %SPLIT_MODE%"
|
||||
)
|
||||
|
||||
echo run cmd: ZES_ENABLE_SYSMAN=1 %BIN_FILE% -m %MODEL_FILE% -no-cnv -p "%INPUT_PROMPT%" -n 200 -e -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --mmap
|
||||
echo run cmd: ZES_ENABLE_SYSMAN=1 %BIN_FILE% -m %MODEL_FILE% -no-cnv -p "%INPUT_PROMPT%" -n 200 -e -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --device %SYCL_DEVICES% --mmap
|
||||
set "ZES_ENABLE_SYSMAN=1"
|
||||
%BIN_FILE% -m "%MODEL_FILE%" -no-cnv -p "%INPUT_PROMPT%" -n 200 -e -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --mmap
|
||||
%BIN_FILE% -m "%MODEL_FILE%" -no-cnv -p "%INPUT_PROMPT%" -n 200 -e -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --device "%SYCL_DEVICES%" --mmap
|
||||
|
||||
endlocal
|
||||
|
||||
|
||||
@@ -8,6 +8,22 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP_FPHP)
|
||||
#define HWCAP_FPHP (1 << 9)
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP_ASIMDHP)
|
||||
#define HWCAP_ASIMDHP (1 << 10)
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP_ASIMDDP)
|
||||
#define HWCAP_ASIMDDP (1 << 20)
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP_SVE)
|
||||
#define HWCAP_SVE (1 << 22)
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP2_SVE2)
|
||||
#define HWCAP2_SVE2 (1 << 1)
|
||||
#endif
|
||||
@@ -23,7 +39,7 @@
|
||||
struct aarch64_features {
|
||||
// has_neon not needed, aarch64 has NEON guaranteed
|
||||
bool has_dotprod = false;
|
||||
bool has_fp16_va = false;
|
||||
bool has_fp16 = false;
|
||||
bool has_sve = false;
|
||||
bool has_sve2 = false;
|
||||
bool has_i8mm = false;
|
||||
@@ -36,7 +52,7 @@ struct aarch64_features {
|
||||
uint32_t hwcap2 = getauxval(AT_HWCAP2);
|
||||
|
||||
has_dotprod = !!(hwcap & HWCAP_ASIMDDP);
|
||||
has_fp16_va = !!(hwcap & HWCAP_FPHP);
|
||||
has_fp16 = !!(hwcap & HWCAP_FPHP) && !!(hwcap & HWCAP_ASIMDHP);
|
||||
has_sve = !!(hwcap & HWCAP_SVE);
|
||||
has_sve2 = !!(hwcap2 & HWCAP2_SVE2);
|
||||
has_i8mm = !!(hwcap2 & HWCAP2_I8MM);
|
||||
@@ -75,7 +91,7 @@ static int ggml_backend_cpu_aarch64_score() {
|
||||
score += 1<<1;
|
||||
#endif
|
||||
#ifdef GGML_USE_FP16_VECTOR_ARITHMETIC
|
||||
if (!af.has_fp16_va) { return 0; }
|
||||
if (!af.has_fp16) { return 0; }
|
||||
score += 1<<2;
|
||||
#endif
|
||||
#ifdef GGML_USE_SVE
|
||||
|
||||
@@ -5209,6 +5209,7 @@ static bool ggml_backend_cuda_device_offload_op(ggml_backend_dev_t dev, const gg
|
||||
|
||||
static ggml_backend_event_t ggml_backend_cuda_device_event_new(ggml_backend_dev_t dev) {
|
||||
#ifdef GGML_CUDA_NO_PEER_COPY
|
||||
GGML_UNUSED(dev);
|
||||
return nullptr;
|
||||
#else
|
||||
ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *)dev->context;
|
||||
|
||||
@@ -8,7 +8,6 @@ struct __builtin_align__(32) float8 {
|
||||
float x; float y; float z; float w;
|
||||
float p; float q; float r; float s;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CUDART_VERSION >= 12080
|
||||
static __device__ __forceinline__ float nvfp4_native_scale_error(
|
||||
@@ -49,6 +48,7 @@ static __device__ __forceinline__ float nvfp4_native_scale_error(
|
||||
return err;
|
||||
}
|
||||
#endif // CUDART_VERSION >= 12080
|
||||
#endif // defined(BLACKWELL_MMA_AVAILABLE)
|
||||
|
||||
__launch_bounds__(CUDA_QUANTIZE_BLOCK_SIZE, 1)
|
||||
static __global__ void quantize_q8_1(
|
||||
|
||||
@@ -11328,8 +11328,8 @@ kernel void kernel_lightning_indexer(
|
||||
const int i_kv_0 = tgpig.x*NK; // first key of this threadgroup
|
||||
const int i_kv = i_kv_0 + sgitg*NKPSG; // first key of this simdgroup
|
||||
|
||||
threadgroup half4x4 sk4x4[NK*DK16];
|
||||
threadgroup half * sk = (threadgroup half *) sk4x4;
|
||||
threadgroup half sk[NK * DK16 * 16];
|
||||
threadgroup half4x4 * sk4x4 = (threadgroup half4x4 *) sk;
|
||||
|
||||
for (short i = tiitg; i < NK*DK16; i += NTG) {
|
||||
const short ik = i/DK16;
|
||||
|
||||
@@ -1022,9 +1022,20 @@ static T block_reduce(T val, T * shared_vals, int block_size_template) {
|
||||
}
|
||||
|
||||
static __dpct_inline__ float ggml_sycl_ue4m3_to_fp32(uint8_t x) {
|
||||
const uint32_t bits = x * (x != 0x7F && x != 0xFF);
|
||||
const __nv_fp8_e4m3 xf = *reinterpret_cast<const __nv_fp8_e4m3 *>(&bits);
|
||||
return static_cast<float>(xf) / 2;
|
||||
// UE4M3 is unsigned: 4 exp bits (bias 7), 3 mantissa bits, no sign, no NaN.
|
||||
// exp == 0xF is a valid exponent (256-448 range), not NaN.
|
||||
if (x == 0 || x == 0x7F) {
|
||||
return 0.0f;
|
||||
}
|
||||
const int exp = (x >> 3) & 0xF;
|
||||
const int man = x & 0x7;
|
||||
float raw;
|
||||
if (exp == 0) {
|
||||
raw = man * (1.0f / 8.0f) * sycl::pow(2.0f, -6.0f);
|
||||
} else {
|
||||
raw = (1.0f + man / 8.0f) * sycl::pow(2.0f, (float) exp - 7.0f);
|
||||
}
|
||||
return raw * 0.5f;
|
||||
}
|
||||
|
||||
#endif // GGML_SYCL_COMMON_HPP
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
#include "ggml-impl.h"
|
||||
#include "dsv4-hc.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
static constexpr int DSV4_HC = 4;
|
||||
|
||||
static void dsv4_hc_pre_f32_sycl(
|
||||
const float * x, const float * weights, float * dst,
|
||||
int64_t n_embd, int64_t hc, int64_t n_tokens,
|
||||
int64_t sx0, int64_t sx1, int64_t sx2,
|
||||
int64_t sw0, int64_t sw1,
|
||||
int64_t sd0, int64_t sd1,
|
||||
queue_ptr stream) {
|
||||
const int64_t nr = n_embd * n_tokens;
|
||||
const int64_t block_size = 256;
|
||||
const int64_t num_blocks = (nr + block_size - 1) / block_size;
|
||||
|
||||
stream->parallel_for(
|
||||
sycl::nd_range<1>(sycl::range<1>(num_blocks * block_size), sycl::range<1>(block_size)),
|
||||
[=](sycl::nd_item<1> item) {
|
||||
const int64_t ir = item.get_global_id(0);
|
||||
if (ir >= nr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t i0 = ir % n_embd;
|
||||
const int64_t it = ir / n_embd;
|
||||
|
||||
float sum = x[i0*sx0 + it*sx2] * weights[it*sw1];
|
||||
for (int64_t ih = 1; ih < hc; ++ih) {
|
||||
const float xv = x[i0*sx0 + ih*sx1 + it*sx2];
|
||||
const float wv = weights[ih*sw0 + it*sw1];
|
||||
sum += xv * wv;
|
||||
}
|
||||
|
||||
dst[i0*sd0 + it*sd1] = sum;
|
||||
});
|
||||
}
|
||||
|
||||
static void dsv4_hc_comb_norm_cols(float * comb, float eps) {
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
float sum = eps;
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
sum += comb[idst + DSV4_HC*isrc];
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
comb[idst + DSV4_HC*isrc] *= inv_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dsv4_hc_comb_norm_rows(float * comb, float eps) {
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
float sum = eps;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
sum += comb[idst + DSV4_HC*isrc];
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
comb[idst + DSV4_HC*isrc] *= inv_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dsv4_hc_comb_f32_sycl(
|
||||
const float * mixes,
|
||||
const float * scale,
|
||||
const float * base,
|
||||
float * dst,
|
||||
int64_t n_tokens,
|
||||
int64_t sm0,
|
||||
int64_t sm1,
|
||||
int64_t ss0,
|
||||
int64_t sb0,
|
||||
int64_t sd0,
|
||||
int64_t sd1,
|
||||
int64_t sd2,
|
||||
float eps,
|
||||
int32_t n_iter,
|
||||
queue_ptr stream) {
|
||||
constexpr int comb_offset = 2*DSV4_HC;
|
||||
|
||||
const int64_t block_size = 256;
|
||||
const int64_t num_blocks = (n_tokens + block_size - 1) / block_size;
|
||||
|
||||
stream->parallel_for(
|
||||
sycl::nd_range<1>(sycl::range<1>(num_blocks * block_size), sycl::range<1>(block_size)),
|
||||
[=](sycl::nd_item<1> item_ct1) {
|
||||
const int64_t it = item_ct1.get_global_id(0);
|
||||
|
||||
if (it >= n_tokens) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float scale_comb = scale[2*ss0];
|
||||
float comb[DSV4_HC*DSV4_HC];
|
||||
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
float max = -INFINITY;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
const float v = mixes[(comb_offset + idx)*sm0 + it*sm1] * scale_comb + base[(comb_offset + idx)*sb0];
|
||||
comb[idx] = v;
|
||||
max = fmaxf(max, v);
|
||||
}
|
||||
|
||||
float sum = 0.0f;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
const float v = expf(comb[idx] - max);
|
||||
comb[idx] = v;
|
||||
sum += v;
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
comb[idx] = comb[idx] * inv_sum + eps;
|
||||
}
|
||||
}
|
||||
|
||||
dsv4_hc_comb_norm_cols(comb, eps);
|
||||
for (int32_t i = 1; i < n_iter; ++i) {
|
||||
dsv4_hc_comb_norm_rows(comb, eps);
|
||||
dsv4_hc_comb_norm_cols(comb, eps);
|
||||
}
|
||||
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
dst[idst*sd0 + isrc*sd1 + it*sd2] = comb[idx];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void dsv4_hc_post_f32_sycl(
|
||||
const float * x, const float * residual, const float * post, const float * comb, float * dst,
|
||||
int64_t n_embd, int64_t hc, int64_t n_tokens,
|
||||
int64_t sx0, int64_t sx1,
|
||||
int64_t sr0, int64_t sr1, int64_t sr2,
|
||||
int64_t sp0, int64_t sp1,
|
||||
int64_t sc0, int64_t sc1, int64_t sc2,
|
||||
int64_t sd0, int64_t sd1, int64_t sd2,
|
||||
queue_ptr stream) {
|
||||
const int64_t nr = n_embd * hc * n_tokens;
|
||||
const int64_t block_size = 256;
|
||||
const int64_t num_blocks = (nr + block_size - 1) / block_size;
|
||||
|
||||
stream->parallel_for(
|
||||
sycl::nd_range<1>(sycl::range<1>(num_blocks * block_size), sycl::range<1>(block_size)),
|
||||
[=](sycl::nd_item<1> item) {
|
||||
const int64_t ir = item.get_global_id(0);
|
||||
if (ir >= nr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t i0 = ir % n_embd;
|
||||
const int64_t idst = (ir / n_embd) % hc;
|
||||
const int64_t it = ir / (n_embd * hc);
|
||||
|
||||
float sum = x[i0*sx0 + it*sx1] * post[idst*sp0 + it*sp1];
|
||||
for (int64_t isrc = 0; isrc < hc; ++isrc) {
|
||||
sum += residual[i0*sr0 + isrc*sr1 + it*sr2] * comb[idst*sc0 + isrc*sc1 + it*sc2];
|
||||
}
|
||||
|
||||
dst[i0*sd0 + idst*sd1 + it*sd2] = sum;
|
||||
});
|
||||
}
|
||||
|
||||
void ggml_sycl_op_dsv4_hc_pre(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/2);
|
||||
const ggml_tensor * x = dst->src[0];
|
||||
const ggml_tensor * weights = dst->src[1];
|
||||
|
||||
GGML_ASSERT(x->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(weights->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbx, x, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbw, weights, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int64_t n_embd = x->ne[0];
|
||||
const int64_t hc = x->ne[1];
|
||||
const int64_t n_tokens = x->ne[2];
|
||||
|
||||
queue_ptr stream = ctx.stream();
|
||||
|
||||
dsv4_hc_pre_f32_sycl(
|
||||
(const float *) x->data, (const float *) weights->data, (float *) dst->data,
|
||||
n_embd, hc, n_tokens,
|
||||
nbx0 / sizeof(float), nbx1 / sizeof(float), nbx2 / sizeof(float),
|
||||
nbw0 / sizeof(float), nbw1 / sizeof(float),
|
||||
nbd0 / sizeof(float), nbd1 / sizeof(float),
|
||||
stream);
|
||||
}
|
||||
|
||||
void ggml_sycl_op_dsv4_hc_comb(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/3);
|
||||
|
||||
const ggml_tensor * mixes = dst->src[0];
|
||||
const ggml_tensor * scale = dst->src[1];
|
||||
const ggml_tensor * base = dst->src[2];
|
||||
|
||||
GGML_ASSERT(mixes->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(scale->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(base->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
constexpr int64_t hc_mix_dim = (2 + DSV4_HC)*DSV4_HC;
|
||||
|
||||
GGML_ASSERT(mixes->ne[0] == hc_mix_dim);
|
||||
GGML_ASSERT(dst->ne[0] == DSV4_HC);
|
||||
GGML_ASSERT(dst->ne[1] == DSV4_HC);
|
||||
GGML_ASSERT(dst->ne[2] == mixes->ne[1]);
|
||||
GGML_ASSERT(scale->ne[0] >= 3);
|
||||
GGML_ASSERT(base->ne[0] == hc_mix_dim);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbm, mixes, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbs, scale, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbb, base, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int64_t n_tokens = mixes->ne[1];
|
||||
const float eps = ggml_get_op_params_f32(dst, 0);
|
||||
const int32_t n_iter = ggml_get_op_params_i32(dst, 1);
|
||||
|
||||
queue_ptr stream = ctx.stream();
|
||||
|
||||
dsv4_hc_comb_f32_sycl(
|
||||
(const float *) mixes->data, (const float *) scale->data, (const float *) base->data, (float *) dst->data,
|
||||
n_tokens,
|
||||
nbm0 / sizeof(float), nbm1 / sizeof(float),
|
||||
nbs0 / sizeof(float),
|
||||
nbb0 / sizeof(float),
|
||||
nbd0 / sizeof(float), nbd1 / sizeof(float), nbd2 / sizeof(float),
|
||||
eps, n_iter, stream);
|
||||
}
|
||||
|
||||
void ggml_sycl_op_dsv4_hc_post(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/4);
|
||||
const ggml_tensor * x = dst->src[0];
|
||||
const ggml_tensor * residual = dst->src[1];
|
||||
const ggml_tensor * post = dst->src[2];
|
||||
const ggml_tensor * comb = dst->src[3];
|
||||
|
||||
GGML_ASSERT(x->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(residual->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(post->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(comb->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbx, x, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbr, residual, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbp, post, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbc, comb, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int64_t n_embd = x->ne[0];
|
||||
const int64_t n_tokens = x->ne[1];
|
||||
const int64_t hc = residual->ne[1];
|
||||
|
||||
queue_ptr stream = ctx.stream();
|
||||
|
||||
dsv4_hc_post_f32_sycl(
|
||||
(const float *) x->data, (const float *) residual->data,
|
||||
(const float *) post->data, (const float *) comb->data, (float *) dst->data,
|
||||
n_embd, hc, n_tokens,
|
||||
nbx0 / sizeof(float), nbx1 / sizeof(float),
|
||||
nbr0 / sizeof(float), nbr1 / sizeof(float), nbr2 / sizeof(float),
|
||||
nbp0 / sizeof(float), nbp1 / sizeof(float),
|
||||
nbc0 / sizeof(float), nbc1 / sizeof(float), nbc2 / sizeof(float),
|
||||
nbd0 / sizeof(float), nbd1 / sizeof(float), nbd2 / sizeof(float),
|
||||
stream);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef GGML_SYCL_DSV4_HC_HPP
|
||||
#define GGML_SYCL_DSV4_HC_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
void ggml_sycl_op_dsv4_hc_pre(ggml_backend_sycl_context & ctx, ggml_tensor * dst);
|
||||
void ggml_sycl_op_dsv4_hc_comb(ggml_backend_sycl_context & ctx, ggml_tensor * dst);
|
||||
void ggml_sycl_op_dsv4_hc_post(ggml_backend_sycl_context & ctx, ggml_tensor * dst);
|
||||
|
||||
#endif // GGML_SYCL_DSV4_HC_HPP
|
||||
@@ -420,53 +420,31 @@ static void clamp(const T * x, T * dst, const float min, const float max, const
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_geglu(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
template<typename T, typename F>
|
||||
static void unary_gated_op_flat_kernel(const T * x, const T * g, T * dst, const uint64_t k, const sycl::nd_item<1> & item_ct1, F func) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
dst[i] = func(x[i]) * g[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename F>
|
||||
static void unary_gated_op_generic_kernel(
|
||||
const T * x,
|
||||
const T * g,
|
||||
T * dst,
|
||||
const uint64_t k,
|
||||
const sycl::uint3 n_fd,
|
||||
const uint64_t o0,
|
||||
const uint64_t o1,
|
||||
const sycl::nd_item<1> & item_ct1,
|
||||
F func) {
|
||||
|
||||
// rows of n columns at strides o0 and o1: two halves of one fused tensor, or two tensors
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_gelu(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_reglu(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_relu(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_swiglu(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_silu(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_geglu_erf(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_gelu_erf(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_geglu_quick(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_gelu_quick(x[j0]) * g[j1];
|
||||
dst[i] = func(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,6 +648,35 @@ static inline void ggml_sycl_op_unary(
|
||||
});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
static inline void ggml_sycl_op_unary_gated(
|
||||
ggml_backend_sycl_context & ctx, ggml_tensor * dst, F func) {
|
||||
|
||||
dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[func](const auto * x_ptr, const auto * g_ptr, auto * dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
|
||||
const uint32_t num_blocks = (uint32_t) ceil_div(k, SYCL_GLU_BLOCK_SIZE);
|
||||
const sycl::nd_range<1> launch_range(num_blocks * sycl::range<1>(SYCL_GLU_BLOCK_SIZE),
|
||||
sycl::range<1>(SYCL_GLU_BLOCK_SIZE));
|
||||
|
||||
// o0 == n and o1 == n make the index math the identity, so index flat
|
||||
// note: not ggml_is_contiguous - a fused [gate|up] src0 is contiguous with o0 == 2n
|
||||
if (o0 == n && o1 == n) {
|
||||
main_stream->parallel_for(launch_range,
|
||||
[=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
unary_gated_op_flat_kernel(x_ptr, g_ptr, dst_ptr, k, item_ct1, func);
|
||||
});
|
||||
} else {
|
||||
// launch-invariant divisor, and only this path needs it
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(launch_range,
|
||||
[=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
unary_gated_op_generic_kernel(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1, func);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static inline void ggml_sycl_op_arange(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
@@ -967,42 +974,21 @@ static inline void ggml_sycl_op_acc(ggml_backend_sycl_context & ctx, ggml_tensor
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_geglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div(k, SYCL_GELU_BLOCK_SIZE);
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_GELU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_GELU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_geglu(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_gelu(x);
|
||||
});
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_reglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div((uint32_t)k, SYCL_RELU_BLOCK_SIZE); // Using RELU block size for reglu
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_RELU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_RELU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_reglu(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_relu(x);
|
||||
});
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_swiglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div((uint32_t)k, SYCL_SILU_BLOCK_SIZE); // Using SILU block size for swiglu
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_SILU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_SILU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_swiglu(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_silu(x);
|
||||
});
|
||||
}
|
||||
|
||||
__dpct_inline__ float ggml_sycl_op_swiglu_oai_single(float x, float g, float alpha = 1.702f, float limit = 7.0f) {
|
||||
@@ -1097,29 +1083,15 @@ void ggml_sycl_op_swiglu_oai(ggml_backend_sycl_context & ctx, ggml_tensor * dst)
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_geglu_erf(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div(k, SYCL_GELU_BLOCK_SIZE);
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_GELU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_GELU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_geglu_erf(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_gelu_erf(x);
|
||||
});
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_geglu_quick(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div(k, SYCL_GELU_BLOCK_SIZE);
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_GELU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_GELU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_geglu_quick(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_gelu_quick(x);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ static void flash_attn_ext_vec(const char* __restrict__ Q,
|
||||
const int32_t nb31,
|
||||
const int32_t nb32,
|
||||
const int64_t nb33) {
|
||||
|
||||
#ifdef SYCL_FLASH_ATTN
|
||||
// Skip unused kernel variants for faster compilation:
|
||||
|
||||
@@ -469,7 +470,6 @@ static void flash_attn_ext_vec(const char* __restrict__ Q,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
item_ct1.barrier(sycl::access::fence_space::local_space);
|
||||
|
||||
#pragma unroll
|
||||
@@ -591,22 +591,24 @@ void ggml_sycl_flash_attn_ext_vec_case_impl(ggml_backend_sycl_context & ctx, ggm
|
||||
|
||||
const auto arch = ggml_sycl_info().devices[ctx.device].hw_info.arch;
|
||||
const int nthreads = ggml_sycl_fattn_vec_get_nthreads_device(arch);
|
||||
// 256 threads would overflow the 64 KB work-group local memory at D == 512, so keep 128 there.
|
||||
if (D <= 256 && nthreads == 256) {
|
||||
constexpr int nthreads_hw = 256;
|
||||
constexpr int nwarps = nthreads_hw / warp_size;
|
||||
launch_fattn<D, cols_per_block, 1,
|
||||
flash_attn_ext_vec<D, cols_per_block, type_K, type_V,
|
||||
use_logit_softcap, warp_size, nthreads_hw>, warp_size>(
|
||||
ctx, dst, nwarps, nbytes_shared, D, need_f16_K, need_f16_V, false);
|
||||
} else {
|
||||
constexpr int nthreads_hw = 128;
|
||||
constexpr int nwarps = nthreads_hw / warp_size;
|
||||
launch_fattn<D, cols_per_block, 1,
|
||||
flash_attn_ext_vec<D, cols_per_block, type_K, type_V,
|
||||
use_logit_softcap, warp_size, nthreads_hw>, warp_size>(
|
||||
ctx, dst, nwarps, nbytes_shared, D, need_f16_K, need_f16_V, false);
|
||||
if constexpr (D <= 256) {
|
||||
if (nthreads == 256) {
|
||||
constexpr int nthreads_hw = 256;
|
||||
constexpr int nwarps = nthreads_hw / warp_size;
|
||||
launch_fattn<D, cols_per_block, 1,
|
||||
flash_attn_ext_vec<D, cols_per_block, type_K, type_V,
|
||||
use_logit_softcap, warp_size, nthreads_hw>, warp_size>(
|
||||
ctx, dst, nwarps, nbytes_shared, D, need_f16_K, need_f16_V, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int nthreads_hw = 128;
|
||||
constexpr int nwarps = nthreads_hw / warp_size;
|
||||
launch_fattn<D, cols_per_block, 1,
|
||||
flash_attn_ext_vec<D, cols_per_block, type_K, type_V,
|
||||
use_logit_softcap, warp_size, nthreads_hw>, warp_size>(
|
||||
ctx, dst, nwarps, nbytes_shared, D, need_f16_K, need_f16_V, false);
|
||||
}
|
||||
|
||||
template <int D, int type_K, int type_V>
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
#include "ggml-sycl/repeat_back.hpp"
|
||||
#include "ggml-sycl/set_rows.hpp"
|
||||
#include "ggml-sycl/set.hpp"
|
||||
#include "ggml-sycl/dsv4-hc.hpp"
|
||||
#include "ggml-sycl/lightning-indexer.hpp"
|
||||
#include "ggml-sycl/conv2d.hpp"
|
||||
#include "ggml-sycl/conv2d-dw.hpp"
|
||||
#include "ggml-sycl/conv2d-transpose.hpp"
|
||||
@@ -4942,6 +4944,18 @@ static bool ggml_sycl_compute_forward(ggml_backend_sycl_context & ctx, struct gg
|
||||
case GGML_OP_SET_ROWS:
|
||||
ggml_sycl_op_set_rows(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_PRE:
|
||||
ggml_sycl_op_dsv4_hc_pre(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_COMB:
|
||||
ggml_sycl_op_dsv4_hc_comb(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_POST:
|
||||
ggml_sycl_op_dsv4_hc_post(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_LIGHTNING_INDEXER:
|
||||
ggml_sycl_op_lightning_indexer(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DUP:
|
||||
ggml_sycl_dup(ctx, dst);
|
||||
break;
|
||||
@@ -5795,17 +5809,33 @@ static bool do_ggml_backend_sycl_device_supports_op(ggml_backend_dev_t dev, cons
|
||||
|
||||
case GGML_OP_SET_ROWS:
|
||||
{
|
||||
|
||||
auto res = ((op->type == GGML_TYPE_F32 || op->type == GGML_TYPE_F16 || op->type == GGML_TYPE_BF16 ||
|
||||
op->type == GGML_TYPE_Q8_0 || op->type == GGML_TYPE_Q5_1 || op->type == GGML_TYPE_Q5_0 ||
|
||||
op->type == GGML_TYPE_Q1_0 ||
|
||||
op->type == GGML_TYPE_Q4_1 || op->type == GGML_TYPE_Q4_0 || op->type == GGML_TYPE_IQ4_NL ||
|
||||
op->type == GGML_TYPE_MXFP4 || op->type == GGML_TYPE_NVFP4) &&
|
||||
op->src[0]->type == GGML_TYPE_F32 &&
|
||||
(op->src[1]->type == GGML_TYPE_I64 || op->src[1]->type == GGML_TYPE_I32));
|
||||
auto res = (op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_F16 ||
|
||||
op->src[0]->type == GGML_TYPE_BF16) &&
|
||||
(op->src[1]->type == GGML_TYPE_I64 || op->src[1]->type == GGML_TYPE_I32);
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_PRE:
|
||||
return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 &&
|
||||
op->type == GGML_TYPE_F32;
|
||||
case GGML_OP_DSV4_HC_COMB:
|
||||
return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 &&
|
||||
op->src[2]->type == GGML_TYPE_F32 && op->type == GGML_TYPE_F32;
|
||||
case GGML_OP_DSV4_HC_POST:
|
||||
return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 &&
|
||||
op->src[2]->type == GGML_TYPE_F32 && op->src[3]->type == GGML_TYPE_F32 &&
|
||||
op->type == GGML_TYPE_F32;
|
||||
case GGML_OP_LIGHTNING_INDEXER:
|
||||
return op->src[0]->type == GGML_TYPE_F32 &&
|
||||
(op->src[1]->type == GGML_TYPE_F16 || op->src[1]->type == GGML_TYPE_F32 ||
|
||||
op->src[1]->type == GGML_TYPE_BF16 || op->src[1]->type == GGML_TYPE_Q8_0 ||
|
||||
op->src[1]->type == GGML_TYPE_Q5_1 || op->src[1]->type == GGML_TYPE_Q5_0 ||
|
||||
op->src[1]->type == GGML_TYPE_Q4_1 || op->src[1]->type == GGML_TYPE_Q4_0 ||
|
||||
op->src[1]->type == GGML_TYPE_IQ4_NL) &&
|
||||
op->src[2]->type == GGML_TYPE_F32 &&
|
||||
op->src[3]->type == GGML_TYPE_F16 &&
|
||||
op->type == GGML_TYPE_F32 &&
|
||||
op->src[0]->ne[0] == WARP_SIZE * 8;
|
||||
case GGML_OP_CPY:
|
||||
{
|
||||
ggml_type src0_type = op->src[0]->type;
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
#include "lightning-indexer.hpp"
|
||||
#include "dequantize.hpp"
|
||||
|
||||
static void lightning_indexer_f32_sycl(
|
||||
const char * q, const char * k, const char * w, const char * m, float * dst,
|
||||
int64_t n_embd, int64_t n_head, int64_t n_batch, int64_t n_stream, int64_t n_kv,
|
||||
int64_t nem3,
|
||||
int64_t nbq1, int64_t nbq2, int64_t nbq3,
|
||||
int64_t nbk2, int64_t nbk3,
|
||||
int64_t nbw1, int64_t nbw3,
|
||||
int64_t nbm1, int64_t nbm3,
|
||||
int64_t nb1, int64_t nb3,
|
||||
ggml_type k_type,
|
||||
queue_ptr stream) {
|
||||
|
||||
constexpr int64_t LANES = WARP_SIZE;
|
||||
constexpr int64_t ELEMS_PER_LANE = 8;
|
||||
constexpr int64_t ROWS_PER_BLOCK = 4;
|
||||
constexpr int64_t BLOCK_SIZE = ROWS_PER_BLOCK * LANES;
|
||||
|
||||
const int64_t n_rows = n_batch * n_stream * n_kv;
|
||||
const int64_t n_blocks = (n_rows + ROWS_PER_BLOCK - 1) / ROWS_PER_BLOCK;
|
||||
|
||||
stream->parallel_for(
|
||||
sycl::nd_range<1>(
|
||||
sycl::range<1>(n_blocks * BLOCK_SIZE),
|
||||
sycl::range<1>(BLOCK_SIZE)),
|
||||
[=](sycl::nd_item<1> item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
const int64_t ir = item.get_global_id(0);
|
||||
const int64_t lane = ir % LANES;
|
||||
const int64_t row = ir / LANES;
|
||||
if (row >= n_rows) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t i_bs = row / n_kv;
|
||||
const int64_t i_kv = row % n_kv;
|
||||
const int64_t i_batch = i_bs / n_stream;
|
||||
const int64_t i_stream = i_bs % n_stream;
|
||||
|
||||
// load K row slice into registers (row is contiguous, nbk0 == type size)
|
||||
const char * k_base = k + i_kv*nbk2 + i_stream*nbk3;
|
||||
float k_local[ELEMS_PER_LANE];
|
||||
if (k_type == GGML_TYPE_F16) {
|
||||
const sycl::half * k_row = (const sycl::half *) k_base;
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
k_local[j] = static_cast<float>(k_row[lane*ELEMS_PER_LANE + j]);
|
||||
}
|
||||
} else if (k_type == GGML_TYPE_F32) {
|
||||
const float * k_row = (const float *) k_base;
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
k_local[j] = k_row[lane*ELEMS_PER_LANE + j];
|
||||
}
|
||||
} else {
|
||||
const int64_t lane_base = lane * ELEMS_PER_LANE;
|
||||
switch (k_type) {
|
||||
case GGML_TYPE_BF16: {
|
||||
const sycl::ext::oneapi::bfloat16 * k_row = (const sycl::ext::oneapi::bfloat16 *) k_base;
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
k_local[j] = static_cast<float>(k_row[lane_base + j]);
|
||||
}
|
||||
} break;
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
case GGML_TYPE_Q5_1: {
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
const int64_t idx = lane_base + j;
|
||||
const int64_t ib = idx / QK4_0;
|
||||
const int iqs = idx % (QK4_0/2);
|
||||
dfloat2 kv;
|
||||
if (k_type == GGML_TYPE_Q4_0) {
|
||||
dequantize_q4_0(k_base, ib, iqs, kv);
|
||||
} else if (k_type == GGML_TYPE_Q4_1) {
|
||||
dequantize_q4_1(k_base, ib, iqs, kv);
|
||||
} else if (k_type == GGML_TYPE_Q5_0) {
|
||||
dequantize_q5_0(k_base, ib, iqs, kv);
|
||||
} else {
|
||||
dequantize_q5_1(k_base, ib, iqs, kv);
|
||||
}
|
||||
k_local[j] = (idx % QK4_0) < (QK4_0/2) ? static_cast<float>(kv.x()) : static_cast<float>(kv.y());
|
||||
}
|
||||
} break;
|
||||
case GGML_TYPE_Q8_0: {
|
||||
#pragma unroll
|
||||
for (int64_t pair = 0; pair < ELEMS_PER_LANE / 2; ++pair) {
|
||||
const int64_t elem0 = lane_base + 2 * pair;
|
||||
dfloat2 kv;
|
||||
dequantize_q8_0(k_base, elem0 / QK8_0, elem0 % QK8_0, kv);
|
||||
k_local[2 * pair + 0] = static_cast<float>(kv.x());
|
||||
k_local[2 * pair + 1] = static_cast<float>(kv.y());
|
||||
}
|
||||
} break;
|
||||
case GGML_TYPE_IQ4_NL: {
|
||||
#pragma unroll
|
||||
for (int64_t pair = 0; pair < ELEMS_PER_LANE / 2; ++pair) {
|
||||
const int64_t elem0 = lane_base + 2 * pair;
|
||||
dfloat2 kv;
|
||||
dequantize_iq4_nl(k_base, elem0 / QK4_NL, elem0 % QK4_NL, kv);
|
||||
k_local[2 * pair + 0] = static_cast<float>(kv.x());
|
||||
k_local[2 * pair + 1] = static_cast<float>(kv.y());
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
k_local[j] = 0.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char * q_base = q + i_batch*nbq2 + i_stream*nbq3;
|
||||
const float * w_base = (const float *) (w + i_batch*nbw1 + i_stream*nbw3);
|
||||
|
||||
float score = 0.0f;
|
||||
for (int64_t h = 0; h < n_head; ++h) {
|
||||
const float * q_row = (const float *) (q_base + h*nbq1);
|
||||
float dot = 0.0f;
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
const int64_t i = lane*ELEMS_PER_LANE + j;
|
||||
if (i < n_embd) {
|
||||
dot += q_row[i] * k_local[j];
|
||||
}
|
||||
}
|
||||
dot = sycl::reduce_over_group(item.get_sub_group(), dot, sycl::plus<float>());
|
||||
if (lane == 0) {
|
||||
score += sycl::max(dot, 0.0f) * w_base[h];
|
||||
}
|
||||
}
|
||||
|
||||
if (lane == 0) {
|
||||
const sycl::half * m_base = (const sycl::half *) (m + i_batch*nbm1 + (i_stream % nem3)*nbm3);
|
||||
// flat-index store: storing through a strided base pointer
|
||||
// hangs/misroutes writes on this stack when n_batch*n_stream > 1
|
||||
const int64_t dst_idx = i_kv + i_batch*(nb1/sizeof(float)) + i_stream*(nb3/sizeof(float));
|
||||
dst[dst_idx] = score + static_cast<float>(m_base[i_kv]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ggml_sycl_op_lightning_indexer(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/4);
|
||||
const ggml_tensor * q = dst->src[0];
|
||||
const ggml_tensor * k = dst->src[1];
|
||||
const ggml_tensor * w = dst->src[2]; // weights
|
||||
const ggml_tensor * m = dst->src[3]; // mask
|
||||
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT( q->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT( w->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT( m->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT(k->type == GGML_TYPE_F16 || k->type == GGML_TYPE_F32 || k->type == GGML_TYPE_BF16 ||
|
||||
k->type == GGML_TYPE_Q8_0 || k->type == GGML_TYPE_Q5_1 || k->type == GGML_TYPE_Q5_0 ||
|
||||
k->type == GGML_TYPE_Q4_1 || k->type == GGML_TYPE_Q4_0 || k->type == GGML_TYPE_IQ4_NL);
|
||||
|
||||
GGML_TENSOR_LOCALS(int64_t, neq, q, ne);
|
||||
GGML_TENSOR_LOCALS(size_t, nbq, q, nb);
|
||||
GGML_TENSOR_LOCALS(int64_t, nek, k, ne);
|
||||
GGML_TENSOR_LOCALS(size_t, nbk, k, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbw, w, nb);
|
||||
GGML_TENSOR_LOCALS(int64_t, nem, m, ne);
|
||||
GGML_TENSOR_LOCALS(size_t, nbm, m, nb);
|
||||
GGML_TENSOR_LOCALS(int64_t, ne, dst, ne);
|
||||
GGML_TENSOR_LOCALS(size_t, nb, dst, nb);
|
||||
|
||||
// input rows must be contiguous
|
||||
GGML_ASSERT(nbq0 == ggml_type_size(q->type));
|
||||
GGML_ASSERT(nbk0 == ggml_type_size(k->type));
|
||||
GGML_ASSERT(nbm0 == ggml_type_size(m->type));
|
||||
GGML_ASSERT(nb0 == ggml_type_size(dst->type));
|
||||
|
||||
const int64_t n_embd = neq0;
|
||||
const int64_t n_head = neq1;
|
||||
const int64_t n_batch = neq2;
|
||||
const int64_t n_stream = neq3;
|
||||
const int64_t n_kv = nek2;
|
||||
|
||||
GGML_ASSERT(n_embd == WARP_SIZE * 8);
|
||||
|
||||
lightning_indexer_f32_sycl(
|
||||
(const char *) q->data, (const char *) k->data,
|
||||
(const char *) w->data, (const char *) m->data, (float *) dst->data,
|
||||
n_embd, n_head, n_batch, n_stream, n_kv, nem3,
|
||||
nbq1, nbq2, nbq3,
|
||||
nbk2, nbk3,
|
||||
nbw1, nbw3,
|
||||
nbm1, nbm3,
|
||||
nb1, nb3,
|
||||
k->type,
|
||||
ctx.stream());
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef GGML_SYCL_LIGHTNING_INDEXER_HPP
|
||||
#define GGML_SYCL_LIGHTNING_INDEXER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
void ggml_sycl_op_lightning_indexer(ggml_backend_sycl_context & ctx, ggml_tensor * dst);
|
||||
|
||||
#endif // GGML_SYCL_LIGHTNING_INDEXER_HPP
|
||||
@@ -20,8 +20,6 @@
|
||||
#define MATRIX_ROW_PADDING 512 // last row of quant. matrices is a multiple of this to avoid out-of-bounds memory accesses
|
||||
|
||||
#define SYCL_COL2IM_1D_BLOCK_SIZE 256
|
||||
#define SYCL_GELU_BLOCK_SIZE 256
|
||||
#define SYCL_SILU_BLOCK_SIZE 256
|
||||
#define SYCL_TANH_BLOCK_SIZE 256
|
||||
#define SYCL_RELU_BLOCK_SIZE 256
|
||||
#define SYCL_HARDSIGMOID_BLOCK_SIZE 256
|
||||
|
||||
+344
-16
@@ -1,6 +1,10 @@
|
||||
#include "set_rows.hpp"
|
||||
#include "cpy.hpp"
|
||||
|
||||
#include "ggml-quants.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace utils {
|
||||
template<typename T>
|
||||
static constexpr bool is_arithmetic_v() {
|
||||
@@ -20,7 +24,17 @@ convert (const char* src, char* dst) {
|
||||
*reinterpret_cast<TOut*>(dst) = dst_val;
|
||||
}
|
||||
|
||||
template <typename TIdx, typename blockType, int qk, cpy_kernel_t cpyblck>
|
||||
#ifdef GGML_SYCL_HAS_BF16
|
||||
// sycl::vec::convert does not provide a half -> bfloat16 path, so route through float.
|
||||
template<>
|
||||
inline void convert<sycl::half, sycl::ext::oneapi::bfloat16>(const char* src, char* dst) {
|
||||
const float tmp = sycl::vec<sycl::half, 1>(*reinterpret_cast<const sycl::half*>(src))
|
||||
.template convert<float, sycl::rounding_mode::automatic>()[0];
|
||||
*reinterpret_cast<sycl::ext::oneapi::bfloat16*>(dst) = sycl::ext::oneapi::bfloat16(tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename TIn, typename TIdx, typename blockType, int qk, cpy_kernel_t cpyblck>
|
||||
static void set_rows_sycl_q(const char * __restrict__ src0_d,
|
||||
const TIdx * __restrict__ src1_d,
|
||||
blockType * __restrict__ dst_d,
|
||||
@@ -68,13 +82,22 @@ static void set_rows_sycl_q(const char * __restrict__ src0_d,
|
||||
const int64_t i11 = i02 % ne11;
|
||||
const int64_t i10 = i01;
|
||||
const size_t src_offset = calculate_offset<3>({ nb01, nb02, nb03 }, { i01, i02, i03 });
|
||||
const char * src_block = src0_d + src_offset + i00 * sizeof(float);
|
||||
const char * src_block = src0_d + src_offset + i00 * sizeof(TIn);
|
||||
const size_t src1_offset = calculate_offset<3>({ nb10, nb11, nb12 }, { i10, i11, i12 });
|
||||
const int64_t dst_row = src1_d[src1_offset / sizeof(TIdx)];
|
||||
const size_t dst_offset =
|
||||
calculate_offset<3>({ nb1, nb2, nb3 }, { dst_row, i02, i03 }) + (i00 / qk) * sizeof(blockType);
|
||||
char * dst_block = reinterpret_cast<char *>(reinterpret_cast<char *>(dst_d) + dst_offset);
|
||||
cpyblck(src_block, dst_block);
|
||||
if constexpr (std::is_same_v<TIn, float>) {
|
||||
cpyblck(src_block, dst_block);
|
||||
} else {
|
||||
float src_block_f32[qk];
|
||||
const TIn * src_block_t = reinterpret_cast<const TIn *>(src_block);
|
||||
for (int j = 0; j < qk; ++j) {
|
||||
src_block_f32[j] = (float) src_block_t[j];
|
||||
}
|
||||
cpyblck(reinterpret_cast<const char *>(src_block_f32), dst_block);
|
||||
}
|
||||
});
|
||||
GGML_UNUSED(ne10);
|
||||
GGML_UNUSED(ne13);
|
||||
@@ -82,6 +105,139 @@ static void set_rows_sycl_q(const char * __restrict__ src0_d,
|
||||
GGML_UNUSED(nb13);
|
||||
}
|
||||
|
||||
template<typename blockType>
|
||||
using quantize_row_qk_t = void (*)(const float *, blockType *, int64_t);
|
||||
|
||||
using quantize_rows_f_t = size_t (*)(const float *, void *, int64_t, int64_t, const float *);
|
||||
|
||||
template <typename TIn, typename TIdx, typename blockType, int qk, quantize_row_qk_t<blockType> quantize_row>
|
||||
static void set_rows_sycl_qk_host(
|
||||
const ggml_tensor * src0,
|
||||
const ggml_tensor * src1,
|
||||
ggml_tensor * dst,
|
||||
const int64_t ne00,
|
||||
const int64_t ne01,
|
||||
const int64_t ne02,
|
||||
const int64_t ne03,
|
||||
const int64_t ne11,
|
||||
const int64_t ne12,
|
||||
const size_t nb01,
|
||||
const size_t nb02,
|
||||
const size_t nb03,
|
||||
const size_t nb10,
|
||||
const size_t nb11,
|
||||
const size_t nb12,
|
||||
const size_t nb1,
|
||||
const size_t nb2,
|
||||
const size_t nb3,
|
||||
queue_ptr stream) {
|
||||
GGML_ASSERT(ne00 % qk == 0);
|
||||
|
||||
const size_t src0_bytes = ggml_nbytes(src0);
|
||||
const size_t src1_bytes = ggml_nbytes(src1);
|
||||
|
||||
std::vector<char> src0_host(src0_bytes);
|
||||
std::vector<char> src1_host(src1_bytes);
|
||||
|
||||
stream->memcpy(src0_host.data(), src0->data, src0_bytes);
|
||||
stream->memcpy(src1_host.data(), src1->data, src1_bytes);
|
||||
stream->wait();
|
||||
|
||||
std::vector<float> src_row_f32(ne00);
|
||||
const int64_t nblocks = ne00 / qk;
|
||||
std::vector<blockType> dst_row_q(nblocks);
|
||||
|
||||
for (int64_t i03 = 0; i03 < ne03; ++i03) {
|
||||
for (int64_t i02 = 0; i02 < ne02; ++i02) {
|
||||
for (int64_t i01 = 0; i01 < ne01; ++i01) {
|
||||
const int64_t i12 = i03 % ne12;
|
||||
const int64_t i11 = i02 % ne11;
|
||||
const int64_t i10 = i01;
|
||||
|
||||
const size_t src1_offset = calculate_offset<3>({ nb10, nb11, nb12 }, { i10, i11, i12 });
|
||||
const int64_t dst_row = *(const TIdx *) (src1_host.data() + src1_offset);
|
||||
|
||||
const size_t src0_row_offset = calculate_offset<3>({ nb01, nb02, nb03 }, { i01, i02, i03 });
|
||||
const TIn * src_row = reinterpret_cast<const TIn *>(src0_host.data() + src0_row_offset);
|
||||
|
||||
for (int64_t i00 = 0; i00 < ne00; ++i00) {
|
||||
src_row_f32[i00] = (float) src_row[i00];
|
||||
}
|
||||
|
||||
quantize_row(src_row_f32.data(), dst_row_q.data(), ne00);
|
||||
|
||||
const size_t dst_offset = calculate_offset<3>({ nb1, nb2, nb3 }, { dst_row, i02, i03 });
|
||||
stream->memcpy((char *) dst->data + dst_offset, dst_row_q.data(), nblocks * sizeof(blockType));
|
||||
stream->wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TIn, typename TIdx, typename blockType, int qk, quantize_rows_f_t quantize_rows>
|
||||
static void set_rows_sycl_iq_host(
|
||||
const ggml_tensor * src0,
|
||||
const ggml_tensor * src1,
|
||||
ggml_tensor * dst,
|
||||
const int64_t ne00,
|
||||
const int64_t ne01,
|
||||
const int64_t ne02,
|
||||
const int64_t ne03,
|
||||
const int64_t ne11,
|
||||
const int64_t ne12,
|
||||
const size_t nb01,
|
||||
const size_t nb02,
|
||||
const size_t nb03,
|
||||
const size_t nb10,
|
||||
const size_t nb11,
|
||||
const size_t nb12,
|
||||
const size_t nb1,
|
||||
const size_t nb2,
|
||||
const size_t nb3,
|
||||
queue_ptr stream) {
|
||||
GGML_ASSERT(ne00 % qk == 0);
|
||||
|
||||
const size_t src0_bytes = ggml_nbytes(src0);
|
||||
const size_t src1_bytes = ggml_nbytes(src1);
|
||||
|
||||
std::vector<char> src0_host(src0_bytes);
|
||||
std::vector<char> src1_host(src1_bytes);
|
||||
|
||||
stream->memcpy(src0_host.data(), src0->data, src0_bytes);
|
||||
stream->memcpy(src1_host.data(), src1->data, src1_bytes);
|
||||
stream->wait();
|
||||
|
||||
std::vector<float> src_row_f32(ne00);
|
||||
const int64_t nblocks = ne00 / qk;
|
||||
std::vector<blockType> dst_row_q(nblocks);
|
||||
|
||||
for (int64_t i03 = 0; i03 < ne03; ++i03) {
|
||||
for (int64_t i02 = 0; i02 < ne02; ++i02) {
|
||||
for (int64_t i01 = 0; i01 < ne01; ++i01) {
|
||||
const int64_t i12 = i03 % ne12;
|
||||
const int64_t i11 = i02 % ne11;
|
||||
const int64_t i10 = i01;
|
||||
|
||||
const size_t src1_offset = calculate_offset<3>({ nb10, nb11, nb12 }, { i10, i11, i12 });
|
||||
const int64_t dst_row = *(const TIdx *) (src1_host.data() + src1_offset);
|
||||
|
||||
const size_t src0_row_offset = calculate_offset<3>({ nb01, nb02, nb03 }, { i01, i02, i03 });
|
||||
const TIn * src_row = reinterpret_cast<const TIn *>(src0_host.data() + src0_row_offset);
|
||||
|
||||
for (int64_t i00 = 0; i00 < ne00; ++i00) {
|
||||
src_row_f32[i00] = (float) src_row[i00];
|
||||
}
|
||||
|
||||
quantize_rows(src_row_f32.data(), dst_row_q.data(), 1, ne00, nullptr);
|
||||
|
||||
const size_t dst_offset = calculate_offset<3>({ nb1, nb2, nb3 }, { dst_row, i02, i03 });
|
||||
stream->memcpy((char *) dst->data + dst_offset, dst_row_q.data(), nblocks * sizeof(blockType));
|
||||
stream->wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TIn, typename TIdx, typename TOut>
|
||||
static void k_set_rows(
|
||||
const char * __restrict__ src0, const TIdx * __restrict__ src1, char * __restrict__ dst,
|
||||
@@ -200,31 +356,194 @@ static void set_rows_sycl(ggml_backend_sycl_context & ctx, const ggml_tensor * s
|
||||
break;
|
||||
#endif
|
||||
case GGML_TYPE_Q8_0:
|
||||
set_rows_sycl_q<TIdx, block_q8_0, QK8_0, cpy_blck_f32_q8_0>(src0_d, src1_d, (block_q8_0 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q8_0, QK8_0, cpy_blck_f32_q8_0>(
|
||||
src0_d, src1_d, (block_q8_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q1_0:
|
||||
set_rows_sycl_q<TIdx, block_q1_0, QK1_0, cpy_blck_f32_q1_0>(src0_d, src1_d, (block_q1_0 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q1_0, QK1_0, cpy_blck_f32_q1_0>(
|
||||
src0_d, src1_d, (block_q1_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q2_0:
|
||||
set_rows_sycl_q<TIn, TIdx, block_q2_0, QK2_0, cpy_blck_f32_q2_0>(
|
||||
src0_d, src1_d, (block_q2_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q5_1:
|
||||
set_rows_sycl_q<TIdx, block_q5_1, QK5_1, cpy_blck_f32_q5_1>(src0_d, src1_d, (block_q5_1 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q5_1, QK5_1, cpy_blck_f32_q5_1>(
|
||||
src0_d, src1_d, (block_q5_1 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q5_0:
|
||||
set_rows_sycl_q<TIdx, block_q5_0, QK5_0, cpy_blck_f32_q5_0>(src0_d, src1_d, (block_q5_0 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q5_0, QK5_0, cpy_blck_f32_q5_0>(
|
||||
src0_d, src1_d, (block_q5_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q4_1:
|
||||
set_rows_sycl_q<TIdx, block_q4_1, QK4_1, cpy_blck_f32_q4_1>(src0_d, src1_d, (block_q4_1 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q4_1, QK4_1, cpy_blck_f32_q4_1>(
|
||||
src0_d, src1_d, (block_q4_1 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q4_0:
|
||||
set_rows_sycl_q<TIdx, block_q4_0, QK4_0, cpy_blck_f32_q4_0>(src0_d, src1_d, (block_q4_0 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q4_0, QK4_0, cpy_blck_f32_q4_0>(
|
||||
src0_d, src1_d, (block_q4_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ4_NL:
|
||||
set_rows_sycl_q<TIdx, block_iq4_nl, QK4_NL, cpy_blck_f32_iq4_nl>(src0_d, src1_d, (block_iq4_nl *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_iq4_nl, QK4_NL, cpy_blck_f32_iq4_nl>(
|
||||
src0_d, src1_d, (block_iq4_nl *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_MXFP4:
|
||||
set_rows_sycl_q<TIdx, block_mxfp4, QK_MXFP4, cpy_blck_f32_mxfp4>(src0_d, src1_d, (block_mxfp4 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_mxfp4, QK_MXFP4, cpy_blck_f32_mxfp4>(
|
||||
src0_d, src1_d, (block_mxfp4 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_NVFP4:
|
||||
set_rows_sycl_q<TIdx, block_nvfp4, QK_NVFP4, cpy_blck_f32_nvfp4>(src0_d, src1_d, (block_nvfp4 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_nvfp4, QK_NVFP4, cpy_blck_f32_nvfp4>(
|
||||
src0_d, src1_d, (block_nvfp4 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q2_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q2_K, QK_K, quantize_row_q2_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_Q3_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q3_K, QK_K, quantize_row_q3_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_Q4_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q4_K, QK_K, quantize_row_q4_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_Q5_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q5_K, QK_K, quantize_row_q5_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_Q6_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q6_K, QK_K, quantize_row_q6_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq2_xxs, QK_K, quantize_iq2_xxs>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq2_xs, QK_K, quantize_iq2_xs>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ2_S:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq2_s, QK_K, quantize_iq2_s>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_iq3_xxs, QK_K, quantize_row_iq3_xxs_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ3_S:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_iq3_s, QK_K, quantize_row_iq3_s_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ1_S:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq1_s, QK_K, quantize_iq1_s>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ1_M:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq1_m, QK_K, quantize_iq1_m>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ4_XS:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_iq4_xs, QK_K, quantize_row_iq4_xs_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
default:
|
||||
GGML_ABORT("Unsupported tensor type!");
|
||||
@@ -237,12 +556,21 @@ void ggml_sycl_op_set_rows(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
const ggml_tensor * src1 = dst->src[1];
|
||||
|
||||
GGML_ASSERT(dst->src[0]->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->src[0]->type == GGML_TYPE_F32 || dst->src[0]->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT(dst->src[1]->type == GGML_TYPE_I64 || dst->src[1]->type == GGML_TYPE_I32);
|
||||
|
||||
if (src1->type == GGML_TYPE_I64) {
|
||||
set_rows_sycl<float, int64_t>(ctx, src0, src1, dst);
|
||||
// dispatch on the index type (src1) and the source value type (src0)
|
||||
if (src0->type == GGML_TYPE_F16) {
|
||||
if (src1->type == GGML_TYPE_I64) {
|
||||
set_rows_sycl<sycl::half, int64_t>(ctx, src0, src1, dst);
|
||||
} else {
|
||||
set_rows_sycl<sycl::half, int32_t>(ctx, src0, src1, dst);
|
||||
}
|
||||
} else {
|
||||
set_rows_sycl<float, int32_t>(ctx, src0, src1, dst);
|
||||
if (src1->type == GGML_TYPE_I64) {
|
||||
set_rows_sycl<float, int64_t>(ctx, src0, src1, dst);
|
||||
} else {
|
||||
set_rows_sycl<float, int32_t>(ctx, src0, src1, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9747,6 +9747,15 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_eval() {
|
||||
static std::vector<std::unique_ptr<test_case>> make_test_cases_perf() {
|
||||
std::vector<std::unique_ptr<test_case>> test_cases;
|
||||
|
||||
// SWIGLU at a 27B-class FFN width, fused [gate|up] vs split operands
|
||||
// note: same bytes either way, so a backend that indexes them differently shows it here
|
||||
for (ggml_type type : {GGML_TYPE_F16, GGML_TYPE_F32}) {
|
||||
for (int64_t n_tokens : {512, 2048}) {
|
||||
test_cases.emplace_back(new test_glu(GGML_GLU_OP_SWIGLU, type, { 2*17408, n_tokens, 1, 1 }, 0, false));
|
||||
test_cases.emplace_back(new test_glu_split(GGML_GLU_OP_SWIGLU, type, { 17408, n_tokens, 1, 1 }, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// Conv2d: K=CRS=NPQ=4096 matmul performance
|
||||
uint32_t iwh_idx = 0;
|
||||
uint32_t kwh_idx = 1;
|
||||
|
||||
@@ -195,7 +195,7 @@ static const std::vector<std::string> dspark_dflash = {
|
||||
|
||||
struct plan_case {
|
||||
const char * name;
|
||||
const std::vector<std::string> & files;
|
||||
const std::vector<std::string> files;
|
||||
const char * hf_repo;
|
||||
const char * hf_file;
|
||||
bool sidecars; // request mmproj + mtp + dflash + eagle3 + dspark
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mtmd.h"
|
||||
@@ -62,6 +64,72 @@ int main(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// test chunk save/load round-trip
|
||||
for (size_t i = 0; i < n_chunks; i++) {
|
||||
const mtmd_input_chunk * chunk = mtmd_input_chunks_get(chunks, i);
|
||||
assert(chunk != NULL);
|
||||
enum mtmd_input_chunk_type type = mtmd_input_chunk_get_type(chunk);
|
||||
|
||||
// query the required buffer size (out_buf == NULL)
|
||||
size_t expected_len = 0;
|
||||
int32_t rc = mtmd_input_chunk_save(chunk, NULL, 0, &expected_len);
|
||||
printf(" Chunk %zu: save query rc = %d, expected_len = %zu\n", i, rc, expected_len);
|
||||
assert(rc == 0);
|
||||
assert(expected_len > 0);
|
||||
|
||||
// saving into a too-small buffer must fail, not crash
|
||||
char tiny_buf[1];
|
||||
rc = mtmd_input_chunk_save(chunk, tiny_buf, sizeof(tiny_buf), NULL);
|
||||
printf(" Chunk %zu: save into too-small buffer rc = %d (expect non-zero)\n", i, rc);
|
||||
assert(rc != 0);
|
||||
|
||||
// save into a properly-sized buffer
|
||||
char * buf = (char *) malloc(expected_len);
|
||||
assert(buf != NULL);
|
||||
rc = mtmd_input_chunk_save(chunk, buf, expected_len, NULL);
|
||||
assert(rc == 0);
|
||||
|
||||
// loading from a truncated buffer must fail gracefully, not crash
|
||||
if (expected_len > 1) {
|
||||
mtmd_input_chunk * bad = mtmd_input_chunk_load(buf, expected_len - 1);
|
||||
printf(" Chunk %zu: load from truncated buffer = %p (expect NULL)\n", i, (void *) bad);
|
||||
assert(bad == NULL);
|
||||
}
|
||||
|
||||
// load it back
|
||||
mtmd_input_chunk * loaded = mtmd_input_chunk_load(buf, expected_len);
|
||||
assert(loaded != NULL);
|
||||
|
||||
// metadata must match the original chunk
|
||||
assert(mtmd_input_chunk_get_type(loaded) == type);
|
||||
assert(mtmd_input_chunk_get_n_tokens(loaded) == mtmd_input_chunk_get_n_tokens(chunk));
|
||||
assert(mtmd_input_chunk_get_n_pos(loaded) == mtmd_input_chunk_get_n_pos(chunk));
|
||||
|
||||
if (type == MTMD_INPUT_CHUNK_TYPE_TEXT) {
|
||||
size_t n_tok_orig, n_tok_loaded;
|
||||
const llama_token * tok_orig = mtmd_input_chunk_get_tokens_text(chunk, &n_tok_orig);
|
||||
const llama_token * tok_loaded = mtmd_input_chunk_get_tokens_text(loaded, &n_tok_loaded);
|
||||
printf(" Chunk %zu: loaded %zu text tokens (orig %zu), first token %d (orig %d)\n",
|
||||
i, n_tok_loaded, n_tok_orig,
|
||||
n_tok_loaded > 0 ? tok_loaded[0] : -1,
|
||||
n_tok_orig > 0 ? tok_orig[0] : -1);
|
||||
assert(n_tok_orig == n_tok_loaded);
|
||||
for (size_t j = 0; j < n_tok_orig; j++) {
|
||||
assert(tok_orig[j] == tok_loaded[j]);
|
||||
}
|
||||
} else if (type == MTMD_INPUT_CHUNK_TYPE_IMAGE || type == MTMD_INPUT_CHUNK_TYPE_AUDIO) {
|
||||
const char * id_orig = mtmd_input_chunk_get_id(chunk);
|
||||
const char * id_loaded = mtmd_input_chunk_get_id(loaded);
|
||||
printf(" Chunk %zu: loaded id '%s' (orig '%s')\n", i, id_loaded, id_orig);
|
||||
assert(id_orig != NULL && id_loaded != NULL);
|
||||
assert(strcmp(id_orig, id_loaded) == 0);
|
||||
}
|
||||
|
||||
mtmd_input_chunk_free(loaded);
|
||||
free(buf);
|
||||
}
|
||||
printf("Chunk save/load round-trip OK\n");
|
||||
|
||||
// Free the chunks
|
||||
mtmd_input_chunks_free(chunks);
|
||||
|
||||
|
||||
@@ -591,6 +591,8 @@ struct clip_image_u8 {
|
||||
}
|
||||
};
|
||||
|
||||
struct mtmd_serialization; // forward declaration
|
||||
|
||||
// For images, buf.size() == nx*ny*3
|
||||
// Memory layout: RGBRGBRGB...
|
||||
// For seq, buf.size() == nx*ny*3*nt
|
||||
@@ -671,6 +673,9 @@ struct clip_image_f32 {
|
||||
return buf.empty();
|
||||
}
|
||||
|
||||
void serialize(struct mtmd_serialization & ser) const;
|
||||
void deserialize(struct mtmd_serialization & ser);
|
||||
|
||||
private:
|
||||
std::vector<float> buf;
|
||||
int nx_ = 0;
|
||||
@@ -752,6 +757,9 @@ struct clip_image_f32_batch {
|
||||
}
|
||||
return new_batch;
|
||||
}
|
||||
|
||||
void serialize(struct mtmd_serialization & ser) const;
|
||||
void deserialize(struct mtmd_serialization & ser);
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
@@ -112,7 +112,6 @@ public:
|
||||
c2w_state.clear();
|
||||
audio_pcm.clear();
|
||||
overlay.clear();
|
||||
overlay_idx = 0;
|
||||
h_state_buf.clear();
|
||||
out_buf.clear();
|
||||
prompt_embd_buf.clear();
|
||||
@@ -205,11 +204,9 @@ public:
|
||||
top_p = inp->top_p > 0 ? inp->top_p : 1.0f;
|
||||
out_type = inp->out_type;
|
||||
|
||||
// the text stream keeps flowing during generation: after frame k, the input adds
|
||||
// trailing text row k on top of the codes embedding, then tts_eos, then tts_pad
|
||||
for (int i = 3; i < n_ids - 5; i++) overlay.push_back(row(ids[(size_t) i]));
|
||||
overlay.push_back(row(tts_eos));
|
||||
overlay.push_back(row(tts_pad));
|
||||
// the prompt above holds the whole text stream up to tts_eos, so every generated
|
||||
// frame adds tts_pad on top of the codes embedding
|
||||
overlay = row(tts_pad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -265,9 +262,7 @@ public:
|
||||
}
|
||||
|
||||
std::vector<float> fb(out.embd, out.embd + n_embd);
|
||||
const auto & ov = overlay[std::min(overlay_idx, overlay.size() - 1)];
|
||||
for (int i = 0; i < n_embd; i++) fb[(size_t) i] += ov[(size_t) i];
|
||||
overlay_idx++;
|
||||
for (int i = 0; i < n_embd; i++) fb[(size_t) i] += overlay[(size_t) i];
|
||||
|
||||
const int n_pos_per_embd = mrope ? 4 : 1;
|
||||
decode_embd_batch batch_embd(fb.data(), 1, n_pos_per_embd, n_embd);
|
||||
@@ -437,8 +432,7 @@ private:
|
||||
std::vector<int32_t> codes_buf;
|
||||
std::vector<uint8_t> c2w_state;
|
||||
std::vector<float> audio_pcm;
|
||||
std::vector<std::vector<float>> overlay;
|
||||
size_t overlay_idx = 0;
|
||||
std::vector<float> overlay;
|
||||
std::vector<float> h_state_buf;
|
||||
mtmd_helper_gen_audio_outtype out_type = MTMD_HELPER_GEN_AUDIO_OUTTYPE_WAV;
|
||||
std::vector<char> out_buf;
|
||||
|
||||
@@ -22,8 +22,123 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <climits>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
// remember to bump this if the serialization format changes
|
||||
#define MTMD_SERIALIZATION_VERSION 1
|
||||
|
||||
struct mtmd_serialization {
|
||||
// note: using 64-bit here for future-proofing
|
||||
uint64_t version = MTMD_SERIALIZATION_VERSION;
|
||||
std::vector<char> data;
|
||||
size_t read_pos = 0; // cursor used when reading
|
||||
|
||||
// for writing
|
||||
mtmd_serialization(uint64_t version) : version(version) {
|
||||
write(version);
|
||||
}
|
||||
|
||||
// for reading
|
||||
mtmd_serialization(uint64_t version, const char * buf, size_t len) {
|
||||
// copy buf to data
|
||||
data.assign(buf, buf + len);
|
||||
uint64_t ver_in = read<uint64_t>();
|
||||
if (ver_in != version) {
|
||||
throw std::runtime_error("version mismatch");
|
||||
}
|
||||
this->version = ver_in;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write(T value) {
|
||||
static_assert(std::is_trivially_copyable<T>::value && !std::is_same<T, bool>::value,
|
||||
"T must be trivially copyable and not bool");
|
||||
const char * p = reinterpret_cast<const char *>(&value);
|
||||
data.insert(data.end(), p, p + sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T read() {
|
||||
static_assert(std::is_trivially_copyable<T>::value && !std::is_same<T, bool>::value,
|
||||
"T must be trivially copyable and not bool");
|
||||
if (read_pos + sizeof(T) > data.size()) {
|
||||
throw std::runtime_error("read OOB");
|
||||
}
|
||||
T value;
|
||||
std::memcpy(&value, data.data() + read_pos, sizeof(T));
|
||||
read_pos += sizeof(T);
|
||||
return value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
void mtmd_serialization::write<bool>(bool value) {
|
||||
write<uint8_t>(value ? 1 : 0);
|
||||
}
|
||||
template <>
|
||||
bool mtmd_serialization::read<bool>() {
|
||||
return read<uint8_t>() != 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
void mtmd_serialization::write<std::string>(std::string value) {
|
||||
write<uint64_t>(value.size());
|
||||
data.insert(data.end(), value.begin(), value.end());
|
||||
}
|
||||
template <>
|
||||
std::string mtmd_serialization::read<std::string>() {
|
||||
uint64_t len = read<uint64_t>();
|
||||
if (read_pos + len > data.size()) {
|
||||
throw std::runtime_error("read_string OOB");
|
||||
}
|
||||
std::string str(data.data() + read_pos, len);
|
||||
read_pos += len;
|
||||
return str;
|
||||
}
|
||||
|
||||
// only mtmd.cpp needs these, so they're implemented here rather than in clip-impl.h
|
||||
void clip_image_f32::serialize(mtmd_serialization & ser) const {
|
||||
// remember to bump MTMD_SERIALIZATION_VERSION if this is changed
|
||||
// note: buf is intentionally NOT serialized; the loaded clip_image_f32 will always be a placeholder
|
||||
ser.write(add_viewsep);
|
||||
ser.write(add_newline);
|
||||
ser.write((int32_t)nx_);
|
||||
ser.write((int32_t)ny_);
|
||||
}
|
||||
void clip_image_f32::deserialize(mtmd_serialization & ser) {
|
||||
add_viewsep = ser.read<bool>();
|
||||
add_newline = ser.read<bool>();
|
||||
nx_ = ser.read<int32_t>();
|
||||
ny_ = ser.read<int32_t>();
|
||||
buf.clear(); // always a placeholder after loading
|
||||
}
|
||||
|
||||
void clip_image_f32_batch::serialize(mtmd_serialization & ser) const {
|
||||
// remember to bump MTMD_SERIALIZATION_VERSION if this is changed
|
||||
ser.write(is_audio);
|
||||
ser.write<uint64_t>(entries.size());
|
||||
for (const auto & entry : entries) {
|
||||
entry.serialize(ser);
|
||||
}
|
||||
}
|
||||
void clip_image_f32_batch::deserialize(mtmd_serialization & ser) {
|
||||
is_audio = ser.read<bool>();
|
||||
uint64_t n = ser.read<uint64_t>();
|
||||
constexpr size_t min_entry_bytes = sizeof(uint8_t) * 2 + sizeof(int32_t) * 2;
|
||||
if (n > (ser.data.size() - ser.read_pos) / min_entry_bytes) {
|
||||
throw std::runtime_error("entries count exceeds buffer size");
|
||||
}
|
||||
entries.clear();
|
||||
entries.reserve(n);
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
clip_image_f32 entry;
|
||||
entry.deserialize(ser);
|
||||
entries.push_back(std::move(entry));
|
||||
}
|
||||
}
|
||||
|
||||
// for still image data, layout is RGBRGBRGB...
|
||||
// length of data must be nx * ny * 3 bytes
|
||||
//
|
||||
@@ -83,6 +198,7 @@ enum mtmd_pos_type {
|
||||
MTMD_POS_TYPE_NORMAL, // number of positions equals to number of tokens
|
||||
MTMD_POS_TYPE_MROPE, // qwen-vl mrope style, each image takes max(t,h,w) position indexes
|
||||
MTMD_POS_TYPE_HUNYUANVL, // HunyuanVL mrope + BOI/EOI/newline layout with XD-RoPE dim-3
|
||||
MTMD_POS_TYPE_COUNT, // for validation
|
||||
};
|
||||
|
||||
struct mtmd_image_tokens {
|
||||
@@ -136,6 +252,30 @@ struct mtmd_image_tokens {
|
||||
id
|
||||
};
|
||||
}
|
||||
|
||||
void serialize(mtmd_serialization & ser) const {
|
||||
// remember to bump MTMD_SERIALIZATION_VERSION if this is changed
|
||||
ser.write(nx);
|
||||
ser.write(ny);
|
||||
ser.write((uint32_t)pos);
|
||||
ser.write(image_idx);
|
||||
ser.write(n_temporal_merge);
|
||||
ser.write(id);
|
||||
batch_f32.serialize(ser);
|
||||
}
|
||||
void deserialize(mtmd_serialization & ser) {
|
||||
nx = ser.read<uint32_t>();
|
||||
ny = ser.read<uint32_t>();
|
||||
uint32_t pos_raw = ser.read<uint32_t>();
|
||||
if (pos_raw >= MTMD_POS_TYPE_COUNT) {
|
||||
throw std::runtime_error("invalid pos type");
|
||||
}
|
||||
pos = (mtmd_pos_type)pos_raw;
|
||||
image_idx = ser.read<uint32_t>();
|
||||
n_temporal_merge = ser.read<uint32_t>();
|
||||
id = ser.read<std::string>();
|
||||
batch_f32.deserialize(ser);
|
||||
}
|
||||
};
|
||||
using mtmd_image_tokens_ptr = std::unique_ptr<mtmd_image_tokens>;
|
||||
|
||||
@@ -161,6 +301,18 @@ struct mtmd_audio_tokens {
|
||||
id
|
||||
};
|
||||
}
|
||||
|
||||
void serialize(mtmd_serialization & ser) const {
|
||||
// remember to bump MTMD_SERIALIZATION_VERSION if this is changed
|
||||
ser.write(n_tokens);
|
||||
ser.write(id);
|
||||
batch_f32.serialize(ser);
|
||||
}
|
||||
void deserialize(mtmd_serialization & ser) {
|
||||
n_tokens = ser.read<uint32_t>();
|
||||
id = ser.read<std::string>();
|
||||
batch_f32.deserialize(ser);
|
||||
}
|
||||
};
|
||||
using mtmd_audio_tokens_ptr = std::unique_ptr<mtmd_audio_tokens>;
|
||||
|
||||
@@ -192,6 +344,66 @@ struct mtmd_input_chunk {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void serialize(mtmd_serialization & ser) const {
|
||||
// remember to bump MTMD_SERIALIZATION_VERSION if this is changed
|
||||
ser.write((uint32_t)type);
|
||||
|
||||
ser.write<uint64_t>(tokens_text.size());
|
||||
for (llama_token tok : tokens_text) {
|
||||
ser.write((int32_t)tok);
|
||||
}
|
||||
|
||||
ser.write(tokens_image != nullptr);
|
||||
if (tokens_image) {
|
||||
tokens_image->serialize(ser);
|
||||
}
|
||||
|
||||
ser.write(tokens_audio != nullptr);
|
||||
if (tokens_audio) {
|
||||
tokens_audio->serialize(ser);
|
||||
}
|
||||
}
|
||||
void deserialize(mtmd_serialization & ser) {
|
||||
uint32_t type_raw = ser.read<uint32_t>();
|
||||
if (type_raw >= MTMD_INPUT_CHUNK_TYPE_COUNT) {
|
||||
throw std::runtime_error("invalid chunk type");
|
||||
}
|
||||
type = (mtmd_input_chunk_type)type_raw;
|
||||
|
||||
uint64_t n_tokens_text = ser.read<uint64_t>();
|
||||
// reject before resize() so a tiny corrupted/malicious buffer can't force a huge allocation
|
||||
if (n_tokens_text > (ser.data.size() - ser.read_pos) / sizeof(int32_t)) {
|
||||
throw std::runtime_error("tokens_text length exceeds buffer size");
|
||||
}
|
||||
tokens_text.resize(n_tokens_text);
|
||||
for (uint64_t i = 0; i < n_tokens_text; i++) {
|
||||
tokens_text[i] = (llama_token)ser.read<int32_t>();
|
||||
}
|
||||
|
||||
if (ser.read<bool>()) {
|
||||
tokens_image = std::make_unique<mtmd_image_tokens>();
|
||||
tokens_image->deserialize(ser);
|
||||
} else {
|
||||
tokens_image.reset();
|
||||
}
|
||||
|
||||
if (ser.read<bool>()) {
|
||||
tokens_audio = std::make_unique<mtmd_audio_tokens>();
|
||||
tokens_audio->deserialize(ser);
|
||||
} else {
|
||||
tokens_audio.reset();
|
||||
}
|
||||
|
||||
// catch buffers where the declared type doesn't match which payload is actually present,
|
||||
// so a mismatched chunk can't slip through and null-deref/abort later in an accessor
|
||||
if (type == MTMD_INPUT_CHUNK_TYPE_IMAGE && !tokens_image) {
|
||||
throw std::runtime_error("type is IMAGE but tokens_image is missing");
|
||||
}
|
||||
if (type == MTMD_INPUT_CHUNK_TYPE_AUDIO && !tokens_audio) {
|
||||
throw std::runtime_error("type is AUDIO but tokens_audio is missing");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct mtmd_input_chunks {
|
||||
@@ -2043,6 +2255,42 @@ void mtmd_input_chunk_free(mtmd_input_chunk * chunk) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t mtmd_input_chunk_save(const mtmd_input_chunk * chunk, char * out_buf, size_t out_len, size_t * expected_out_len) {
|
||||
try {
|
||||
mtmd_serialization ser(MTMD_SERIALIZATION_VERSION);
|
||||
chunk->serialize(ser);
|
||||
|
||||
if (expected_out_len) {
|
||||
*expected_out_len = ser.data.size();
|
||||
}
|
||||
if (!out_buf) {
|
||||
// caller is only querying the required size
|
||||
return 0;
|
||||
}
|
||||
if (out_len < ser.data.size()) {
|
||||
LOG_ERR("%s: out_buf is too small, need %zu bytes, got %zu\n", __func__, ser.data.size(), out_len);
|
||||
return -1;
|
||||
}
|
||||
std::memcpy(out_buf, ser.data.data(), ser.data.size());
|
||||
return 0;
|
||||
} catch (const std::exception & e) {
|
||||
LOG_ERR("%s: %s\n", __func__, e.what());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
mtmd_input_chunk * mtmd_input_chunk_load(const char * buf, size_t len) {
|
||||
try {
|
||||
mtmd_serialization ser(MTMD_SERIALIZATION_VERSION, buf, len);
|
||||
mtmd::input_chunk_ptr chunk(new mtmd_input_chunk());
|
||||
chunk->deserialize(ser);
|
||||
return chunk.release();
|
||||
} catch (const std::exception & e) {
|
||||
LOG_ERR("%s: %s\n", __func__, e.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// mtmd_image_tokens
|
||||
|
||||
size_t mtmd_image_tokens_get_n_tokens(const mtmd_image_tokens * image_tokens) {
|
||||
|
||||
@@ -55,6 +55,7 @@ enum mtmd_input_chunk_type {
|
||||
MTMD_INPUT_CHUNK_TYPE_TEXT,
|
||||
MTMD_INPUT_CHUNK_TYPE_IMAGE,
|
||||
MTMD_INPUT_CHUNK_TYPE_AUDIO,
|
||||
MTMD_INPUT_CHUNK_TYPE_COUNT, // for validation
|
||||
};
|
||||
|
||||
// opaque types
|
||||
@@ -232,6 +233,15 @@ MTMD_API llama_pos mtmd_input_chunk_get_n_pos (const mtmd
|
||||
MTMD_API mtmd_input_chunk * mtmd_input_chunk_copy(const mtmd_input_chunk * chunk);
|
||||
MTMD_API void mtmd_input_chunk_free(mtmd_input_chunk * chunk);
|
||||
|
||||
// save/load an input chunk to/from a buffer (useful for KV save/load)
|
||||
// important: only chunk's metadata will be saved, the actual image/audio data will not be saved
|
||||
// the loaded chunk will always be a placeholder, cannot be used for mtmd_encode() or mtmd_batch_encode()
|
||||
// out_buf can be nullptr (to query expected_out_len)
|
||||
// returns 0 on success, non-zero on failure
|
||||
MTMD_API int32_t mtmd_input_chunk_save(const mtmd_input_chunk * chunk, char * out_buf, size_t out_len, size_t * expected_out_len);
|
||||
// returns nullptr on failure
|
||||
MTMD_API mtmd_input_chunk * mtmd_input_chunk_load(const char * buf, size_t len);
|
||||
|
||||
|
||||
// mtmd_image_tokens
|
||||
//
|
||||
|
||||
@@ -721,7 +721,9 @@ void server_models::unload_lru() {
|
||||
for (const auto & m : mapping) {
|
||||
if (m.second.meta.is_running()) {
|
||||
count_active++;
|
||||
if (m.second.meta.last_used < lru_last_used) {
|
||||
// do not evict busy one
|
||||
bool is_model_idle = m.second.req_count == 0 && m.second.meta.is_ready_or_sleep();
|
||||
if (is_model_idle && m.second.meta.last_used < lru_last_used) {
|
||||
lru_model_name = m.first;
|
||||
lru_last_used = m.second.meta.last_used;
|
||||
}
|
||||
@@ -739,6 +741,7 @@ void server_models::unload_lru() {
|
||||
});
|
||||
}
|
||||
}
|
||||
// TODO @ngxson : if no idle model is found, queue the load request
|
||||
}
|
||||
|
||||
void server_models::load(const std::string & name) {
|
||||
@@ -1180,9 +1183,12 @@ server_http_res_ptr server_models::proxy_request(const server_http_req & req, co
|
||||
if (!meta->is_running()) {
|
||||
throw std::invalid_argument("model name=" + name + " is not running");
|
||||
}
|
||||
if (update_last_used) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
mapping[name].meta.last_used = ggml_time_ms();
|
||||
if (update_last_used) {
|
||||
mapping[name].meta.last_used = ggml_time_ms();
|
||||
}
|
||||
mapping[name].req_count++;
|
||||
}
|
||||
SRV_INF("proxying request to model %s on port %d\n", name.c_str(), meta->port);
|
||||
std::string proxy_path = req.path;
|
||||
@@ -1198,13 +1204,22 @@ server_http_res_ptr server_models::proxy_request(const server_http_req & req, co
|
||||
req.headers,
|
||||
req.body,
|
||||
req.files,
|
||||
// a detached request belongs to a replay session that outlives the client socket:
|
||||
// it reaches the child even when the downstream died during the load wait, the
|
||||
// session buffer is the recipient and DELETE remains the stop
|
||||
detached ? std::function<bool()>([]() { return false; }) : req.should_stop,
|
||||
// a detached request belongs to a replay session
|
||||
detached
|
||||
? std::function<bool()>([]() { return false; })
|
||||
: req.should_stop,
|
||||
base_params.timeout_read,
|
||||
base_params.timeout_write
|
||||
);
|
||||
|
||||
proxy->cleanup = [this, name]() {
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
auto it = mapping.find(name);
|
||||
if (it != mapping.end() && it->second.req_count > 0) {
|
||||
it->second.req_count--;
|
||||
}
|
||||
};
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@@ -2064,7 +2079,7 @@ server_http_proxy::server_http_proxy(
|
||||
cli->set_write_timeout(timeout_read, 0); // reversed for cli (client) vs srv (server)
|
||||
cli->set_read_timeout(timeout_write, 0);
|
||||
this->status = 500; // to be overwritten upon response
|
||||
this->cleanup = [pipe]() {
|
||||
this->cleanup_pipes = [pipe]() {
|
||||
pipe->close_read();
|
||||
pipe->close_write();
|
||||
};
|
||||
@@ -2079,9 +2094,8 @@ server_http_proxy::server_http_proxy(
|
||||
return has_next; // false if EOF or pipe broken
|
||||
};
|
||||
|
||||
// wire up the HTTP client
|
||||
// note: do NOT capture `this` pointer, as it may be destroyed before the thread ends
|
||||
httplib::ResponseHandler response_handler = [pipe, cli](const httplib::Response & response) {
|
||||
// build the header message forwarded to the reader thread, stripping internal proxy headers
|
||||
auto make_header_msg = [](const httplib::Response & response) {
|
||||
msg_t msg;
|
||||
msg.status = response.status;
|
||||
for (const auto & [key, value] : response.headers) {
|
||||
@@ -2095,7 +2109,17 @@ server_http_proxy::server_http_proxy(
|
||||
}
|
||||
msg.headers[key] = value;
|
||||
}
|
||||
return pipe->write(std::move(msg)); // send headers first
|
||||
return msg;
|
||||
};
|
||||
|
||||
// true once response_handler has already forwarded the headers
|
||||
auto headers_sent = std::make_shared<std::atomic<bool>>(false);
|
||||
|
||||
// wire up the HTTP client
|
||||
// note: do NOT capture `this` pointer, as it may be destroyed before the thread ends
|
||||
httplib::ResponseHandler response_handler = [pipe, headers_sent, make_header_msg](const httplib::Response & response) {
|
||||
headers_sent->store(true);
|
||||
return pipe->write(make_header_msg(response)); // send headers first
|
||||
};
|
||||
httplib::ContentReceiverWithProgress content_receiver = [pipe](const char * data, size_t data_length, size_t, size_t) {
|
||||
// send data chunks
|
||||
@@ -2169,13 +2193,16 @@ server_http_proxy::server_http_proxy(
|
||||
|
||||
// start the proxy thread
|
||||
SRV_DBG("start proxy thread %s %s\n", req.method.c_str(), req.path.c_str());
|
||||
this->thread = std::thread([cli, pipe, req]() {
|
||||
this->thread = std::thread([cli, pipe, req, headers_sent, make_header_msg]() {
|
||||
auto result = cli->send(std::move(req));
|
||||
if (result.error() != httplib::Error::Success) {
|
||||
auto err_str = httplib::to_string(result.error());
|
||||
SRV_ERR("http client error: %s\n", err_str.c_str());
|
||||
pipe->write({{}, 500, "", ""}); // header
|
||||
pipe->write({{}, 0, "proxy error: " + err_str, ""}); // body
|
||||
} else if (!headers_sent->load()) {
|
||||
// httplib skips response_handler for bodyless statuses like 204, send headers here instead
|
||||
pipe->write(make_header_msg(*result));
|
||||
}
|
||||
pipe->close_write(); // signal EOF to reader
|
||||
SRV_DBG("%s", "client request thread ended\n");
|
||||
|
||||
@@ -84,7 +84,6 @@ struct server_model_meta {
|
||||
int exit_code = 0; // exit code of the model instance process (only valid if status == FAILED)
|
||||
int stop_timeout = 0; // seconds to wait before force-killing the model instance during shutdown
|
||||
mtmd_caps multimodal; // multimodal capabilities
|
||||
// bool need_download = false; // whether the model needs to be downloaded before loading // TODO @ngxson: implement this
|
||||
|
||||
bool is_ready() const {
|
||||
return status == SERVER_MODEL_STATUS_LOADED;
|
||||
@@ -94,6 +93,10 @@ struct server_model_meta {
|
||||
return status == SERVER_MODEL_STATUS_LOADED || status == SERVER_MODEL_STATUS_LOADING || status == SERVER_MODEL_STATUS_SLEEPING;
|
||||
}
|
||||
|
||||
bool is_ready_or_sleep() const {
|
||||
return status == SERVER_MODEL_STATUS_LOADED || status == SERVER_MODEL_STATUS_SLEEPING;
|
||||
}
|
||||
|
||||
bool is_failed() const {
|
||||
return status == SERVER_MODEL_STATUS_UNLOADED && exit_code != 0;
|
||||
}
|
||||
@@ -113,6 +116,7 @@ private:
|
||||
std::shared_ptr<server_subproc> subproc; // shared between main thread and monitoring thread
|
||||
std::thread th;
|
||||
server_model_meta meta;
|
||||
int req_count = 0; // number of active proxy requests
|
||||
};
|
||||
|
||||
std::mutex mutex;
|
||||
@@ -343,7 +347,6 @@ struct server_models_routes {
|
||||
*/
|
||||
struct server_http_proxy : server_http_res {
|
||||
std::function<void()> cleanup = nullptr;
|
||||
public:
|
||||
server_http_proxy(const std::string & method,
|
||||
const std::string & scheme,
|
||||
const std::string & host,
|
||||
@@ -357,11 +360,15 @@ public:
|
||||
int32_t timeout_write
|
||||
);
|
||||
~server_http_proxy() {
|
||||
if (cleanup_pipes) {
|
||||
cleanup_pipes();
|
||||
}
|
||||
if (cleanup) {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::function<void()> cleanup_pipes = nullptr;
|
||||
std::thread thread;
|
||||
struct msg_t {
|
||||
std::map<std::string, std::string> headers;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import pytest
|
||||
from utils import *
|
||||
import threading
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
|
||||
server = ServerPreset.tinyllama2()
|
||||
|
||||
@@ -39,3 +41,31 @@ def test_mcp_proxy_custom_port():
|
||||
res = server.make_request("GET", f"/cors-proxy?url=http://{server.server_host}:{server.server_port}/models")
|
||||
assert res.status_code == 200
|
||||
assert "data" in res.body
|
||||
|
||||
|
||||
def test_mcp_proxy_no_content():
|
||||
# note: see issue #26598
|
||||
class NoContentHandler(BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
self.send_response(204)
|
||||
self.end_headers()
|
||||
|
||||
def log_message(self, format, *args):
|
||||
pass
|
||||
|
||||
target = ThreadingHTTPServer(("127.0.0.1", 0), NoContentHandler)
|
||||
target_thread = threading.Thread(target=target.serve_forever, daemon=True)
|
||||
target_thread.start()
|
||||
|
||||
try:
|
||||
global server
|
||||
server.ui_mcp_proxy = True
|
||||
server.start()
|
||||
|
||||
res = server.make_request("POST", f"/cors-proxy?url=http://127.0.0.1:{target.server_port}/", data={})
|
||||
assert res.status_code == 204
|
||||
assert res.body in (None, b"", "")
|
||||
finally:
|
||||
target.shutdown()
|
||||
target.server_close()
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { base } from '$app/paths';
|
||||
import { SvelteMap, SvelteSet } from 'svelte/reactivity';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { ServerModelStatus, ServerModelsSseEventType, ModelModality } from '$lib/enums';
|
||||
import {
|
||||
ServerModelStatus,
|
||||
ServerModelsSseEventType,
|
||||
ModelModality,
|
||||
FileTypeCategory
|
||||
} from '$lib/enums';
|
||||
import { ModelsService } from '$lib/services/models.service';
|
||||
import { PropsService } from '$lib/services/props.service';
|
||||
import { serverStore, isRouterMode } from '$lib/stores/server.svelte';
|
||||
@@ -394,6 +399,7 @@ class ModelsStore {
|
||||
model: modelId,
|
||||
description: details?.description,
|
||||
capabilities: rawCapabilities.filter((value: unknown): value is string => Boolean(value)),
|
||||
modalities: this.buildArchitectureModalities(item.architecture),
|
||||
details: details?.details,
|
||||
meta: item.meta ?? null,
|
||||
parsedId: ModelsService.parseModelId(modelId),
|
||||
@@ -1000,6 +1006,21 @@ class ModelsStore {
|
||||
};
|
||||
}
|
||||
|
||||
/** Map the router modalities, the only source available while a model is not loaded. */
|
||||
private buildArchitectureModalities(
|
||||
architecture: ApiModelDataEntry['architecture']
|
||||
): ModelModalities | undefined {
|
||||
if (!architecture) return undefined;
|
||||
|
||||
const inputs = architecture.input_modalities;
|
||||
|
||||
return {
|
||||
vision: inputs.includes(FileTypeCategory.IMAGE),
|
||||
audio: inputs.includes(FileTypeCategory.AUDIO),
|
||||
video: inputs.includes(FileTypeCategory.VIDEO)
|
||||
};
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.unsubscribeStatus();
|
||||
this.statusWaiters.forEach((waiter) => waiter.reject(new Error('Models store cleared')));
|
||||
|
||||
Vendored
+11
@@ -98,10 +98,21 @@ export interface ApiModelDataEntry {
|
||||
aliases?: string[];
|
||||
/** Informational tags for this model */
|
||||
tags?: string[];
|
||||
/** Modality capabilities, reported by the router for every model regardless of load state */
|
||||
architecture?: ApiModelArchitecture;
|
||||
/** Legacy meta field (may be present in older responses) */
|
||||
meta?: Record<string, unknown> | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modality capabilities of a model, as advertised by the ROUTER /models endpoint.
|
||||
* Read from the model manifest, so it is available before the model is loaded.
|
||||
*/
|
||||
export interface ApiModelArchitecture {
|
||||
/** Accepted input modalities, always contains "text" */
|
||||
input_modalities: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load stage reported by the /models/sse feed, in load order.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user