mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-08-17 18:23:01 +02:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 39be55c97e | |||
| 34af94cd9a | |||
| 666f8898a2 | |||
| 805984d676 | |||
| 9cd719af21 | |||
| 7077abbe14 | |||
| d83f72d463 | |||
| 9f0d017efb | |||
| 7c35571e5d | |||
| f9779dda86 | |||
| fa88ae9368 | |||
| 3733366720 | |||
| 4197155add | |||
| cea66f4c5a | |||
| 4695f001fe | |||
| f275595dd1 | |||
| 37a215c9e9 | |||
| 4df29be4f4 | |||
| 3cb7ffb1a1 | |||
| b94041a98e | |||
| 10bf611e53 | |||
| ece963f41b | |||
| 0d9ceae1e3 | |||
| ad1de39e07 | |||
| 22b8e310b9 | |||
| adb55e5148 | |||
| 77140d247c | |||
| 5f754ea0e2 | |||
| 27df9199d1 | |||
| 9b0a2ce859 | |||
| 0177dcc730 | |||
| 6b4344ecc7 | |||
| 7b38cb71b9 |
@@ -44,6 +44,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
|
||||
|
||||
- name: Determine source tag name
|
||||
id: srctag
|
||||
|
||||
@@ -3,6 +3,11 @@ name: Make Release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
commit:
|
||||
description: 'Commit SHA to release (empty = branch HEAD)'
|
||||
required: false
|
||||
default: ''
|
||||
type: string
|
||||
dry_run:
|
||||
description: 'Dry run - validate without creating the tag'
|
||||
required: true
|
||||
@@ -22,12 +27,17 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
|
||||
ref: ${{ inputs.commit != '' && inputs.commit || github.ref_name }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Run release checks
|
||||
id: checks
|
||||
run: bash scripts/make-release-checks.sh ${{ github.event.inputs.dry_run == 'true' && '--dry-run' || '' }}
|
||||
env:
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
RELEASE_BRANCH: ${{ github.ref_name }}
|
||||
|
||||
- name: Create release tag
|
||||
if: ${{ github.event.inputs.dry_run == 'false' }}
|
||||
@@ -42,5 +52,10 @@ jobs:
|
||||
- name: Dry run summary
|
||||
if: ${{ github.event.inputs.dry_run == 'true' }}
|
||||
run: |
|
||||
echo "Dry run complete - all checks passed."
|
||||
echo "Would have created tag: ${{ steps.checks.outputs.version }}"
|
||||
if [[ "${{ steps.checks.outputs.checks_passed }}" == "true" ]]; then
|
||||
echo "Dry run complete - all checks passed."
|
||||
echo "Would have created tag: ${{ steps.checks.outputs.version }}"
|
||||
else
|
||||
echo "::error::Dry run found release check failures. A release tag would not be created."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -1439,7 +1439,9 @@ jobs:
|
||||
- name: xcodebuild for swift package
|
||||
id: xcodebuild
|
||||
run: |
|
||||
./build-xcframework.sh
|
||||
# note: only macos and ios-device due to long build time
|
||||
# ref: https://github.com/ggml-org/llama.cpp/pull/27252
|
||||
./build-xcframework.sh macos ios-device
|
||||
|
||||
- name: Build Xcode project
|
||||
run: xcodebuild -project examples/llama.swiftui/llama.swiftui.xcodeproj -scheme llama.swiftui -sdk iphoneos CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= -destination 'generic/platform=iOS' FRAMEWORK_FOLDER_PATH=./build-ios build
|
||||
@@ -1598,6 +1600,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
|
||||
|
||||
- name: Determine tag name
|
||||
id: tag
|
||||
@@ -1659,6 +1662,16 @@ jobs:
|
||||
run: |
|
||||
tar -czvf release/llama-${{ steps.tag.outputs.name }}-ui.tar.gz --transform "s,^\.,llama-${{ steps.tag.outputs.name }}," -C ./ui-dist .
|
||||
|
||||
- name: Create and push git tag
|
||||
run: |
|
||||
TAG="${{ steps.tag.outputs.name }}"
|
||||
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null 2>&1; then
|
||||
echo "Tag ${TAG} already exists, skipping creation"
|
||||
else
|
||||
git tag "${TAG}"
|
||||
git push origin "${TAG}"
|
||||
fi
|
||||
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: ggml-org/action-create-release@v1
|
||||
|
||||
@@ -2,6 +2,7 @@ You are a coding agent. Here are some very important rules that you must follow:
|
||||
|
||||
General:
|
||||
- Be very precise and concise when writing code, comments, explanations, etc.
|
||||
- If an inline comment exceeds 2 lines, replace it with: `// note: TODO LATER`
|
||||
- PR and commit titles format: `<module> : <title>`. Lookup recents for examples
|
||||
- Don't try to build or run the code unless you are explicitly asked to do so
|
||||
- Use the `gh` CLI tool when querying PRs, issues, or other GitHub resources
|
||||
|
||||
+2
-1
@@ -5,7 +5,7 @@ include(CheckIncludeFileCXX)
|
||||
### llama.cpp version
|
||||
set(LLAMA_VERSION_MAJOR 0)
|
||||
set(LLAMA_VERSION_MINOR 1)
|
||||
set(LLAMA_VERSION_PATCH 0)
|
||||
set(LLAMA_VERSION_PATCH 1)
|
||||
set(LLAMA_VERSION_BASE "${LLAMA_VERSION_MAJOR}.${LLAMA_VERSION_MINOR}.${LLAMA_VERSION_PATCH}")
|
||||
|
||||
# whether this is a development/nightly build
|
||||
@@ -227,6 +227,7 @@ add_subdirectory(src)
|
||||
if (LLAMA_BUILD_COMMON)
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(vendor/cpp-httplib)
|
||||
add_subdirectory(vendor/hash)
|
||||
endif()
|
||||
|
||||
if (LLAMA_BUILD_COMMON AND LLAMA_BUILD_TESTS AND NOT CMAKE_JS_VERSION)
|
||||
|
||||
+209
-128
@@ -1,5 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# usage: ./build-xcframework.sh [BUILD ...] (default: all builds)
|
||||
# builds: ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device
|
||||
#
|
||||
# Options
|
||||
IOS_MIN_OS_VERSION=16.4
|
||||
MACOS_MIN_OS_VERSION=13.3
|
||||
@@ -19,6 +22,43 @@ GGML_METAL_EMBED_LIBRARY=ON
|
||||
GGML_BLAS_DEFAULT=ON
|
||||
GGML_OPENMP=OFF
|
||||
|
||||
# Max number of concurrent platform builds
|
||||
MAX_PARALLEL_BUILDS=1
|
||||
|
||||
# Split the available cores between the concurrent builds (min 1)
|
||||
JOBS_PER_BUILD=$(( $(sysctl -n hw.logicalcpu) / MAX_PARALLEL_BUILDS ))
|
||||
if [[ "$JOBS_PER_BUILD" -lt 1 ]]; then
|
||||
JOBS_PER_BUILD=1
|
||||
fi
|
||||
|
||||
# echo "build_fn build_dir release_dir platform is_simulator min_os" for a build name
|
||||
build_spec() {
|
||||
case "$1" in
|
||||
ios-sim) echo "build_ios_sim build-ios-sim Release-iphonesimulator ios true ${IOS_MIN_OS_VERSION}" ;;
|
||||
ios-device) echo "build_ios_device build-ios-device Release-iphoneos ios false ${IOS_MIN_OS_VERSION}" ;;
|
||||
macos) echo "build_macos build-macos Release macos false ${MACOS_MIN_OS_VERSION}" ;;
|
||||
visionos) echo "build_visionos build-visionos Release-xros visionos false ${VISIONOS_MIN_OS_VERSION}" ;;
|
||||
visionos-sim) echo "build_visionos_sim build-visionos-sim Release-xrsimulator visionos true ${VISIONOS_MIN_OS_VERSION}" ;;
|
||||
tvos-sim) echo "build_tvos_sim build-tvos-sim Release-appletvsimulator tvos true ${TVOS_MIN_OS_VERSION}" ;;
|
||||
tvos-device) echo "build_tvos_device build-tvos-device Release-appletvos tvos false ${TVOS_MIN_OS_VERSION}" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Default: build everything
|
||||
if [[ $# -eq 0 ]]; then
|
||||
BUILDS=(ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device)
|
||||
else
|
||||
BUILDS=("$@")
|
||||
fi
|
||||
for b in "${BUILDS[@]}"; do
|
||||
if ! build_spec "$b" >/dev/null; then
|
||||
echo "Error: unknown build '$b'" >&2
|
||||
echo "Valid builds: ios-sim ios-device macos visionos visionos-sim tvos-sim tvos-device" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
COMMON_C_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
|
||||
COMMON_CXX_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
|
||||
|
||||
@@ -401,148 +441,189 @@ combine_static_libraries() {
|
||||
rm -rf "${temp_dir}"
|
||||
}
|
||||
|
||||
echo "Building for iOS simulator..."
|
||||
cmake -B build-ios-sim -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
||||
-DIOS=ON \
|
||||
-DCMAKE_SYSTEM_NAME=iOS \
|
||||
-DCMAKE_OSX_SYSROOT=iphonesimulator \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphonesimulator \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-ios-sim --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||
build_ios_sim() {
|
||||
echo "Building for iOS simulator..."
|
||||
cmake -B build-ios-sim -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
||||
-DIOS=ON \
|
||||
-DCMAKE_SYSTEM_NAME=iOS \
|
||||
-DCMAKE_OSX_SYSROOT=iphonesimulator \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphonesimulator \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-ios-sim --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
||||
}
|
||||
|
||||
echo "Building for iOS devices..."
|
||||
cmake -B build-ios-device -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_SYSTEM_NAME=iOS \
|
||||
-DCMAKE_OSX_SYSROOT=iphoneos \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphoneos \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-ios-device --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||
build_ios_device() {
|
||||
echo "Building for iOS devices..."
|
||||
cmake -B build-ios-device -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_SYSTEM_NAME=iOS \
|
||||
-DCMAKE_OSX_SYSROOT=iphoneos \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphoneos \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-ios-device --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
||||
}
|
||||
|
||||
echo "Building for macOS..."
|
||||
cmake -B build-macos -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-S .
|
||||
cmake --build build-macos --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||
build_macos() {
|
||||
echo "Building for macOS..."
|
||||
cmake -B build-macos -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-S .
|
||||
cmake --build build-macos --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
||||
}
|
||||
|
||||
echo "Building for visionOS..."
|
||||
cmake -B build-visionos -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DCMAKE_SYSTEM_NAME=visionOS \
|
||||
-DCMAKE_OSX_SYSROOT=xros \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xros \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DLLAMA_BUILD_SERVER=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-visionos --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||
build_visionos() {
|
||||
echo "Building for visionOS..."
|
||||
cmake -B build-visionos -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DCMAKE_SYSTEM_NAME=visionOS \
|
||||
-DCMAKE_OSX_SYSROOT=xros \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xros \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DLLAMA_BUILD_SERVER=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-visionos --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
||||
}
|
||||
|
||||
echo "Building for visionOS simulator..."
|
||||
cmake -B build-visionos-sim -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DCMAKE_SYSTEM_NAME=visionOS \
|
||||
-DCMAKE_OSX_SYSROOT=xrsimulator \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xrsimulator \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DLLAMA_BUILD_SERVER=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-visionos-sim --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||
build_visionos_sim() {
|
||||
echo "Building for visionOS simulator..."
|
||||
cmake -B build-visionos-sim -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DCMAKE_SYSTEM_NAME=visionOS \
|
||||
-DCMAKE_OSX_SYSROOT=xrsimulator \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xrsimulator \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DLLAMA_BUILD_SERVER=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-visionos-sim --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
||||
}
|
||||
|
||||
# Add tvOS builds (might need the same u_int definitions as watchOS and visionOS)
|
||||
echo "Building for tvOS simulator..."
|
||||
cmake -B build-tvos-sim -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||
-DCMAKE_OSX_SYSROOT=appletvsimulator \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DGGML_METAL=ON \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvsimulator \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-tvos-sim --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||
build_tvos_sim() {
|
||||
echo "Building for tvOS simulator..."
|
||||
cmake -B build-tvos-sim -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||
-DCMAKE_OSX_SYSROOT=appletvsimulator \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DGGML_METAL=ON \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvsimulator \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-tvos-sim --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
||||
}
|
||||
|
||||
echo "Building for tvOS devices..."
|
||||
cmake -B build-tvos-device -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||
-DCMAKE_OSX_SYSROOT=appletvos \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DGGML_METAL=ON \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvos \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-tvos-device --config Release -j $(sysctl -n hw.logicalcpu) -- -quiet
|
||||
build_tvos_device() {
|
||||
echo "Building for tvOS devices..."
|
||||
cmake -B build-tvos-device -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||
-DCMAKE_OSX_SYSROOT=appletvos \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DGGML_METAL=ON \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvos \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DMTMD_VIDEO=OFF \
|
||||
-S .
|
||||
cmake --build build-tvos-device --config Release -j "${JOBS_PER_BUILD}" -- -quiet
|
||||
}
|
||||
|
||||
run_builds_parallel() {
|
||||
local -a pids=()
|
||||
local -a names=()
|
||||
local name i
|
||||
for name in "$@"; do
|
||||
# Wait for the oldest running build to free a slot
|
||||
if [[ "${#pids[@]}" -ge "$MAX_PARALLEL_BUILDS" ]]; then
|
||||
if ! wait "${pids[0]}"; then
|
||||
echo "ERROR: build '${names[0]}' failed, log follows (${names[0]}.log):" >&2
|
||||
kill "${pids[@]}" 2>/dev/null || true
|
||||
cat "${names[0]}.log" >&2
|
||||
exit 1
|
||||
fi
|
||||
pids=("${pids[@]:1}")
|
||||
names=("${names[@]:1}")
|
||||
fi
|
||||
echo "Starting build: $name (log: ${name}.log, -j ${JOBS_PER_BUILD})"
|
||||
"$name" > "${name}.log" 2>&1 &
|
||||
pids+=("$!")
|
||||
names+=("$name")
|
||||
done
|
||||
# Wait for the remaining builds
|
||||
for i in "${!pids[@]}"; do
|
||||
if ! wait "${pids[$i]}"; then
|
||||
echo "ERROR: build '${names[$i]}' failed, log follows (${names[$i]}.log):" >&2
|
||||
kill "${pids[@]}" 2>/dev/null || true
|
||||
cat "${names[$i]}.log" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
BUILD_FNS=()
|
||||
for b in "${BUILDS[@]}"; do
|
||||
read -r fn _ < <(build_spec "$b")
|
||||
BUILD_FNS+=("$fn")
|
||||
done
|
||||
echo "Building: ${BUILDS[*]} (max ${MAX_PARALLEL_BUILDS} at a time, -j ${JOBS_PER_BUILD} each)..."
|
||||
run_builds_parallel "${BUILD_FNS[@]}"
|
||||
|
||||
# Setup frameworks and copy binaries and headers
|
||||
echo "Setting up framework structures..."
|
||||
setup_framework_structure "build-ios-sim" ${IOS_MIN_OS_VERSION} "ios"
|
||||
setup_framework_structure "build-ios-device" ${IOS_MIN_OS_VERSION} "ios"
|
||||
setup_framework_structure "build-macos" ${MACOS_MIN_OS_VERSION} "macos"
|
||||
setup_framework_structure "build-visionos" ${VISIONOS_MIN_OS_VERSION} "visionos"
|
||||
setup_framework_structure "build-visionos-sim" ${VISIONOS_MIN_OS_VERSION} "visionos"
|
||||
setup_framework_structure "build-tvos-sim" ${TVOS_MIN_OS_VERSION} "tvos"
|
||||
setup_framework_structure "build-tvos-device" ${TVOS_MIN_OS_VERSION} "tvos"
|
||||
for b in "${BUILDS[@]}"; do
|
||||
read -r _ bdir _ platform _ min_os < <(build_spec "$b")
|
||||
setup_framework_structure "$bdir" "$min_os" "$platform"
|
||||
done
|
||||
|
||||
# Create dynamic libraries from static libraries
|
||||
echo "Creating dynamic libraries from static libraries..."
|
||||
combine_static_libraries "build-ios-sim" "Release-iphonesimulator" "ios" "true"
|
||||
combine_static_libraries "build-ios-device" "Release-iphoneos" "ios" "false"
|
||||
combine_static_libraries "build-macos" "Release" "macos" "false"
|
||||
combine_static_libraries "build-visionos" "Release-xros" "visionos" "false"
|
||||
combine_static_libraries "build-visionos-sim" "Release-xrsimulator" "visionos" "true"
|
||||
combine_static_libraries "build-tvos-sim" "Release-appletvsimulator" "tvos" "true"
|
||||
combine_static_libraries "build-tvos-device" "Release-appletvos" "tvos" "false"
|
||||
for b in "${BUILDS[@]}"; do
|
||||
read -r _ bdir rdir platform is_sim _ < <(build_spec "$b")
|
||||
combine_static_libraries "$bdir" "$rdir" "$platform" "$is_sim"
|
||||
done
|
||||
|
||||
# Create XCFramework with correct debug symbols paths
|
||||
echo "Creating XCFramework..."
|
||||
XCFW_ARGS=()
|
||||
for b in "${BUILDS[@]}"; do
|
||||
read -r _ bdir _ _ _ _ < <(build_spec "$b")
|
||||
XCFW_ARGS+=(-framework "$(pwd)/${bdir}/framework/llama.framework")
|
||||
XCFW_ARGS+=(-debug-symbols "$(pwd)/${bdir}/dSYMs/llama.dSYM")
|
||||
done
|
||||
xcrun xcodebuild -create-xcframework \
|
||||
-framework $(pwd)/build-ios-sim/framework/llama.framework \
|
||||
-debug-symbols $(pwd)/build-ios-sim/dSYMs/llama.dSYM \
|
||||
-framework $(pwd)/build-ios-device/framework/llama.framework \
|
||||
-debug-symbols $(pwd)/build-ios-device/dSYMs/llama.dSYM \
|
||||
-framework $(pwd)/build-macos/framework/llama.framework \
|
||||
-debug-symbols $(pwd)/build-macos/dSYMs/llama.dSYM \
|
||||
-framework $(pwd)/build-visionos/framework/llama.framework \
|
||||
-debug-symbols $(pwd)/build-visionos/dSYMs/llama.dSYM \
|
||||
-framework $(pwd)/build-visionos-sim/framework/llama.framework \
|
||||
-debug-symbols $(pwd)/build-visionos-sim/dSYMs/llama.dSYM \
|
||||
-framework $(pwd)/build-tvos-device/framework/llama.framework \
|
||||
-debug-symbols $(pwd)/build-tvos-device/dSYMs/llama.dSYM \
|
||||
-framework $(pwd)/build-tvos-sim/framework/llama.framework \
|
||||
-debug-symbols $(pwd)/build-tvos-sim/dSYMs/llama.dSYM \
|
||||
-output $(pwd)/build-apple/llama.xcframework
|
||||
"${XCFW_ARGS[@]}" \
|
||||
-output "$(pwd)/build-apple/llama.xcframework"
|
||||
|
||||
+1
-1
@@ -3362,7 +3362,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
||||
{"--tools"}, "TOOL1,TOOL2,...",
|
||||
"experimental: whether to enable built-in tools for AI agents - do not enable in untrusted environments (default: no tools)\n"
|
||||
"specify \"all\" to enable all tools\n"
|
||||
"available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_datetime, get_info\n"
|
||||
"available tools: read_file, file_glob_search, grep_search, exec_shell_command, write_file, edit_file, get_info\n"
|
||||
"note: for security reasons, this will limit --cors-origins to localhost by default",
|
||||
[](common_params & params, const std::string & value) {
|
||||
params.server_tools = parse_csv_row(value);
|
||||
|
||||
@@ -193,6 +193,14 @@ static std::vector<std::function<void(const common_chat_template & tmpl, autopar
|
||||
LOG_DBG(ANSI_ORANGE "[Patch: Laguna]\n" ANSI_RESET);
|
||||
}
|
||||
},
|
||||
// Bailing V3
|
||||
[](const common_chat_template & tmpl, autoparser & analysis) -> void {
|
||||
if (tmpl.src.find("Bailing V3 chat template") != std::string::npos) {
|
||||
analysis.tools.arguments.value_suffix = trim_whitespace(analysis.tools.arguments.value_suffix);
|
||||
analysis.tools.arguments.tolerate_intertag_whitespace = true;
|
||||
LOG_DBG(ANSI_ORANGE "[Patch: Bailing V3]\n" ANSI_RESET);
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
+252
-27
@@ -470,36 +470,80 @@ std::vector<common_chat_msg> common_chat_msgs_parse_oaicompat(const json & messa
|
||||
return msgs;
|
||||
}
|
||||
|
||||
struct messages_inp_normalizer {
|
||||
const jinja::caps & caps;
|
||||
|
||||
messages_inp_normalizer(const jinja::caps & c) : caps(c) {}
|
||||
|
||||
// handle supports_string_content / supports_typed_content
|
||||
// if string=true and array=false, convert array to string
|
||||
// if string=false and array=true, convert string to array
|
||||
// if both are true, do nothing
|
||||
json normalize(const json & messages) {
|
||||
bool only_string = caps.supports_string_content && !caps.supports_typed_content;
|
||||
bool only_typed = !caps.supports_string_content && caps.supports_typed_content;
|
||||
if ((!only_string && !only_typed) || !messages.is_array()) {
|
||||
return messages;
|
||||
}
|
||||
json normalized = json::array();
|
||||
for (const auto & msg : messages) {
|
||||
json copy = msg;
|
||||
auto it = copy.find("content");
|
||||
if (it != copy.end()) {
|
||||
if (only_typed && it->is_string()) {
|
||||
*it = json::array({
|
||||
json{
|
||||
{"type", "text"},
|
||||
{"text", it->get<std::string>()},
|
||||
}
|
||||
});
|
||||
} else if (only_string && it->is_array()) {
|
||||
*it = concat_content_parts(*it);
|
||||
}
|
||||
}
|
||||
normalized.push_back(std::move(copy));
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
// join parts with newline, do not add newline before or after media markers
|
||||
static std::string concat_content_parts(const json & parts) {
|
||||
std::string text;
|
||||
bool last_was_media_marker = false;
|
||||
for (const auto & part : parts) {
|
||||
std::string type = part.value("type", "");
|
||||
bool add_new_line = true;
|
||||
if (type == "text") {
|
||||
add_new_line = !last_was_media_marker && !text.empty();
|
||||
last_was_media_marker = false;
|
||||
} else if (type == "media_marker") {
|
||||
add_new_line = false;
|
||||
last_was_media_marker = true;
|
||||
} else {
|
||||
LOG_WRN("Ignoring content part type: %s\n", type.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (add_new_line) {
|
||||
text += '\n';
|
||||
}
|
||||
|
||||
text += part.value("text", "");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
static json render_message_to_json(const std::vector<common_chat_msg> & msgs, const jinja::caps & c) {
|
||||
if (!c.supports_string_content && !c.supports_typed_content) {
|
||||
LOG_WRN("%s: Neither string content nor typed content is supported by the template. This is unexpected and may lead to issues.\n", __func__);
|
||||
}
|
||||
|
||||
bool only_string_accepted = c.supports_string_content && !c.supports_typed_content;
|
||||
bool only_typed_accepted = !c.supports_string_content && c.supports_typed_content;
|
||||
|
||||
json messages = json::array();
|
||||
for (const auto & msg : msgs) {
|
||||
if (only_string_accepted) {
|
||||
json jmsg = msg.to_json_oaicompat(/* concat_typed_text= */ true);
|
||||
messages.push_back(jmsg);
|
||||
} else if (only_typed_accepted) {
|
||||
json jmsg = msg.to_json_oaicompat(/* concat_typed_text= */ false);
|
||||
if (jmsg.at("content").is_string()) {
|
||||
jmsg["content"] = json::array({
|
||||
json{
|
||||
{"type", "text"},
|
||||
{"text", jmsg.at("content").get<std::string>()},
|
||||
}
|
||||
});
|
||||
}
|
||||
messages.push_back(jmsg);
|
||||
} else {
|
||||
json jmsg = msg.to_json_oaicompat(/* concat_typed_text= */ false);
|
||||
messages.push_back(jmsg);
|
||||
}
|
||||
messages.push_back(msg.to_json_oaicompat(/* concat_typed_text= */ false));
|
||||
}
|
||||
return messages;
|
||||
return messages_inp_normalizer(c).normalize(messages);
|
||||
}
|
||||
|
||||
// DEPRECATED: only used in tests
|
||||
@@ -892,8 +936,11 @@ static std::string common_chat_template_direct_apply_impl(
|
||||
const std::optional<json> & additional_context = std::nullopt) {
|
||||
jinja::context ctx(tmpl.source());
|
||||
|
||||
// messages_override is already built for this template, do not touch its content parts
|
||||
nlohmann::ordered_json inp = nlohmann::ordered_json{
|
||||
{"messages", messages_override.has_value() ? *messages_override : inputs.messages},
|
||||
{"messages", messages_override.has_value()
|
||||
? *messages_override
|
||||
: messages_inp_normalizer(tmpl.original_caps()).normalize(inputs.messages)},
|
||||
{"bos_token", tmpl.bos_token()},
|
||||
{"eos_token", tmpl.eos_token()},
|
||||
{"enable_thinking", inputs.enable_thinking},
|
||||
@@ -957,14 +1004,12 @@ static std::string common_chat_template_generation_prompt_impl(
|
||||
const std::optional<json> & tools_override = std::nullopt,
|
||||
const std::optional<json> & additional_context = std::nullopt) {
|
||||
|
||||
auto adjusted_messages = messages_override ? *messages_override : inputs.messages;
|
||||
|
||||
autoparser::generation_params params = inputs;
|
||||
params.add_generation_prompt = false;
|
||||
params.continue_final_message = COMMON_CHAT_CONTINUATION_NONE;
|
||||
std::string no_gen_prompt = common_chat_template_direct_apply_impl(tmpl, params, adjusted_messages, tools_override, additional_context);
|
||||
std::string no_gen_prompt = common_chat_template_direct_apply_impl(tmpl, params, messages_override, tools_override, additional_context);
|
||||
params.add_generation_prompt = true;
|
||||
std::string gen_prompt = common_chat_template_direct_apply_impl(tmpl, params, adjusted_messages, tools_override, additional_context);
|
||||
std::string gen_prompt = common_chat_template_direct_apply_impl(tmpl, params, messages_override, tools_override, additional_context);
|
||||
|
||||
size_t prefix_len = 0;
|
||||
size_t min_size = std::min(no_gen_prompt.size(), gen_prompt.size());
|
||||
@@ -2325,6 +2370,179 @@ static common_chat_params common_chat_params_init_deepseek_v3_2(const common_cha
|
||||
return data;
|
||||
}
|
||||
|
||||
// Kimi K3 - XTML tagged format, built by open_tag/close_tag macros:
|
||||
// open_tag(t, attrs) = <|open|>t k="v"...<|sep|> close_tag(t) = <|close|>t<|sep|>
|
||||
// assistant := [think] [response] [tools] close_tag(message) <|end_of_msg|>
|
||||
// the generation prompt already opens the think (or response) section, so the
|
||||
// section opener is optional here - same as Kimi K2 Thinking
|
||||
static common_chat_params common_chat_params_init_kimi_k3(const common_chat_template & tmpl,
|
||||
const autoparser::generation_params & inputs) {
|
||||
common_chat_params data;
|
||||
|
||||
data.prompt = common_chat_template_direct_apply_impl(tmpl, inputs);
|
||||
data.generation_prompt = common_chat_template_generation_prompt_impl(tmpl, inputs);
|
||||
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
||||
data.supports_thinking = true;
|
||||
|
||||
const std::string SEP = "<|sep|>";
|
||||
const std::string MSG_START = "<|open|>message role=\"assistant\"<|sep|>";
|
||||
const std::string THINK_START = "<|open|>think<|sep|>";
|
||||
const std::string THINK_END = "<|close|>think<|sep|>";
|
||||
const std::string RESP_START = "<|open|>response<|sep|>";
|
||||
const std::string RESP_END = "<|close|>response<|sep|>";
|
||||
const std::string TOOLS_START = "<|open|>tools<|sep|>";
|
||||
const std::string TOOLS_END = "<|close|>tools<|sep|>";
|
||||
const std::string CALL_START = "<|open|>call tool=\"";
|
||||
const std::string CALL_END = "<|close|>call<|sep|>";
|
||||
const std::string ARG_START = "<|open|>argument key=\"";
|
||||
const std::string ARG_END = "<|close|>argument<|sep|>";
|
||||
const std::string MSG_END = "<|close|>message<|sep|>";
|
||||
const std::string EOM_TOKEN = "<|end_of_msg|>";
|
||||
|
||||
// only the markers are special tokens. tag names ("think", "response", ...) are
|
||||
// normal tokens and must not be preserved, or prose with those words is broken
|
||||
data.preserved_tokens = {
|
||||
"<|open|>",
|
||||
"<|close|>",
|
||||
"<|sep|>",
|
||||
"<|end_of_msg|>",
|
||||
};
|
||||
|
||||
data.thinking_start_tag = THINK_START;
|
||||
data.thinking_end_tags = { THINK_END };
|
||||
|
||||
// per-role message-start delimiters. user/assistant messages only have the role
|
||||
// attribute, so the full opener is used. system and tool messages have more
|
||||
// attributes, so those delimiters stop after the closing quote of the role
|
||||
data.message_delimiters = {
|
||||
{ COMMON_CHAT_ROLE_ASSISTANT, "<|open|>message role=\"assistant\"<|sep|>" },
|
||||
{ COMMON_CHAT_ROLE_USER, "<|open|>message role=\"user\"<|sep|>" },
|
||||
{ COMMON_CHAT_ROLE_TOOL, "<|open|>message role=\"tool\"" },
|
||||
{ COMMON_CHAT_ROLE_SYSTEM, "<|open|>message role=\"system\"" },
|
||||
};
|
||||
|
||||
auto has_tools = inputs.tools.is_array() && !inputs.tools.empty();
|
||||
auto extract_reasoning = inputs.reasoning_format != COMMON_REASONING_FORMAT_NONE;
|
||||
auto include_grammar = has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE;
|
||||
|
||||
if (inputs.has_continuation()) {
|
||||
const auto & msg = inputs.continue_msg;
|
||||
|
||||
data.generation_prompt = MSG_START + THINK_START + msg.reasoning_content;
|
||||
if (inputs.continue_final_message == COMMON_CHAT_CONTINUATION_CONTENT) {
|
||||
data.generation_prompt += THINK_END + RESP_START + msg.render_content();
|
||||
}
|
||||
|
||||
data.prompt += data.generation_prompt;
|
||||
}
|
||||
|
||||
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
||||
auto end = p.end();
|
||||
|
||||
auto start = p.optional(p.literal(MSG_START));
|
||||
|
||||
// the think section is always consumed, even with reasoning extraction off:
|
||||
// the generation prompt ends with open_tag('think'), so it is always present.
|
||||
// reasoning stops at its own closer, or at the response opener if the model
|
||||
// skips the closer
|
||||
auto think_body = extract_reasoning ? p.reasoning(p.until_one_of({ THINK_END, RESP_START })) :
|
||||
p.content(p.until_one_of({ THINK_END, RESP_START }));
|
||||
|
||||
auto reasoning = p.optional(p.optional(p.literal(THINK_START)) + think_body +
|
||||
p.optional(p.literal(THINK_END)));
|
||||
|
||||
// content runs to the response closer, or to the next section if truncated
|
||||
auto response = p.optional(p.literal(RESP_START)) +
|
||||
p.content(p.until_one_of({ RESP_END, TOOLS_START, MSG_END })) +
|
||||
p.optional(p.literal(RESP_END));
|
||||
|
||||
// the EOG token after the message closer reaches the parser as text,
|
||||
// so it must be consumed or the parse stays incomplete
|
||||
auto trailer = p.optional(p.literal(MSG_END)) + p.optional(p.literal(EOM_TOKEN));
|
||||
|
||||
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
|
||||
return start + reasoning + response + trailer + end;
|
||||
}
|
||||
|
||||
auto tool_choices = p.choice();
|
||||
foreach_function(inputs.tools, [&](const json & tool) {
|
||||
const auto & function = tool.at("function");
|
||||
std::string name = function.at("name");
|
||||
const json schema = function.contains("parameters") ? function.at("parameters") : json::object();
|
||||
|
||||
// arguments come one tag per key, with the JSON type in a type="..."
|
||||
// attribute. the type is taken from the tool schema instead, as it tells
|
||||
// us if the value is JSON or a literal string
|
||||
auto args = p.eps();
|
||||
if (schema.contains("properties") && !schema.at("properties").empty()) {
|
||||
auto arg_choices = p.choice();
|
||||
for (const auto & prop : schema.at("properties").items()) {
|
||||
const std::string & key = prop.key();
|
||||
|
||||
std::string type = "string";
|
||||
if (prop.value().is_object() && prop.value().contains("type") &&
|
||||
prop.value().at("type").is_string()) {
|
||||
type = prop.value().at("type").get<std::string>();
|
||||
}
|
||||
|
||||
auto value = type == "string" ? p.tool_arg_string_value(p.until(ARG_END)) :
|
||||
p.tool_arg_value(p.until(ARG_END));
|
||||
|
||||
// skip the trailing type="..." attribute: anything up to <|sep|>
|
||||
arg_choices |= p.rule("kimi-k3-arg-" + name + "-" + key,
|
||||
p.tool_arg(p.tool_arg_open(p.literal(ARG_START)) +
|
||||
p.tool_arg_name(p.literal(key)) + p.literal("\"") +
|
||||
p.until(SEP) + p.literal(SEP) + value +
|
||||
p.tool_arg_close(p.literal(ARG_END))));
|
||||
}
|
||||
args = p.zero_or_more(arg_choices);
|
||||
}
|
||||
|
||||
// skip the trailing index="N" attribute the same way
|
||||
auto call = p.tool(p.tool_open(p.literal(CALL_START) + p.tool_name(p.literal(name)) + p.literal("\"") +
|
||||
p.until(SEP) + p.literal(SEP)) +
|
||||
p.tool_args(args) + p.tool_close(p.literal(CALL_END)));
|
||||
|
||||
tool_choices |= p.rule("kimi-k3-tool-" + name, call);
|
||||
});
|
||||
|
||||
// all calls go inside one tools section, then the message is closed. the
|
||||
// message closer is part of the trigger rule, or else the lazy grammar
|
||||
// rejects it once tool calls have started
|
||||
auto tools_section =
|
||||
p.trigger_rule("kimi-k3-tool-call", p.literal(TOOLS_START) + p.one_or_more(tool_choices) +
|
||||
p.literal(TOOLS_END) + p.optional(p.literal(MSG_END)) +
|
||||
p.optional(p.literal(EOM_TOKEN)));
|
||||
|
||||
auto tools = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED ? tools_section :
|
||||
p.optional(tools_section);
|
||||
|
||||
return start + reasoning + response + tools + trailer + end;
|
||||
});
|
||||
|
||||
data.parser = parser.save();
|
||||
|
||||
if (include_grammar) {
|
||||
data.grammar_lazy = inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_REQUIRED;
|
||||
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
|
||||
foreach_function(inputs.tools, [&](const json & tool) {
|
||||
const auto & function = tool.at("function");
|
||||
if (function.contains("parameters")) {
|
||||
auto schema = function.at("parameters");
|
||||
builder.resolve_refs(schema);
|
||||
}
|
||||
});
|
||||
parser.build_grammar(builder, data.grammar_lazy);
|
||||
});
|
||||
|
||||
data.grammar_triggers = {
|
||||
{ COMMON_GRAMMAR_TRIGGER_TYPE_WORD, TOOLS_START },
|
||||
};
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Cohere2 MoE (a.k.a. "North Code") parser.
|
||||
//
|
||||
// The assistant turn is fully marker-wrapped:
|
||||
@@ -3293,6 +3511,13 @@ std::optional<common_chat_params> common_chat_try_specialized_template(
|
||||
return common_chat_params_init_kimi_k2(tmpl, params);
|
||||
}
|
||||
|
||||
// Kimi K3 - the <|open|>/<|close|>/<|end_of_msg|> markers are unique to it
|
||||
if (src.find("<|open|>") != std::string::npos && src.find("<|close|>") != std::string::npos &&
|
||||
src.find("<|end_of_msg|>") != std::string::npos) {
|
||||
LOG_DBG("Using specialized template: Kimi K3\n");
|
||||
return common_chat_params_init_kimi_k3(tmpl, params);
|
||||
}
|
||||
|
||||
// Cohere2 MoE / North Code - marker-wrapped format with <|START_TEXT|> content and
|
||||
// <|START_ACTION|> JSON tool calls. <|START_TEXT|> is unique to this template (the older
|
||||
// Command-R templates use <|START_RESPONSE|>).
|
||||
|
||||
@@ -102,7 +102,8 @@ bool common_imatrix_load(const std::string & fname, common_imatrix & imatrix) {
|
||||
const int64_t chunk_count_key = gguf_find_key(ctx_gguf, LLM_KV_IMATRIX_CHUNK_COUNT);
|
||||
const int64_t chunk_size_key = gguf_find_key(ctx_gguf, LLM_KV_IMATRIX_CHUNK_SIZE);
|
||||
|
||||
if (datasets_key != -1 && gguf_get_arr_type(ctx_gguf, datasets_key) == GGUF_TYPE_STRING) {
|
||||
if (datasets_key != -1 && gguf_get_kv_type(ctx_gguf, datasets_key) == GGUF_TYPE_ARRAY &&
|
||||
gguf_get_arr_type(ctx_gguf, datasets_key) == GGUF_TYPE_STRING) {
|
||||
const int64_t n = gguf_get_arr_n(ctx_gguf, datasets_key);
|
||||
imatrix.datasets.reserve(imatrix.datasets.size() + n);
|
||||
for (int64_t i = 0; i < n; ++i) {
|
||||
@@ -143,6 +144,13 @@ bool common_imatrix_load(const std::string & fname, common_imatrix & imatrix) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (in_sum2->type != GGML_TYPE_F32 || counts->type != GGML_TYPE_F32) {
|
||||
LOG_ERR("%s: sums and counts for %s must be F32\n", __func__, name.c_str());
|
||||
gguf_free(ctx_gguf);
|
||||
ggml_free(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto & e = imatrix.entries[name];
|
||||
|
||||
const int64_t nval = ggml_nelements(in_sum2);
|
||||
|
||||
+10
-4
@@ -23,7 +23,7 @@ void caps_apply_preserve_reasoning(jinja::context & ctx, bool enabled) {
|
||||
ctx.set_val("preserve_thinking", mk_val<value_bool>(enabled));
|
||||
ctx.set_val("clear_thinking", mk_val<value_bool>(!enabled));
|
||||
ctx.set_val("truncate_history_thinking", mk_val<value_bool>(!enabled));
|
||||
ctx.set_val("drop_thinking", mk_val<value_bool>(!enabled));
|
||||
ctx.set_val("drop_thinking", mk_val<value_bool>(!enabled));
|
||||
}
|
||||
|
||||
void caps_apply_reasoning_effort(jinja::context & ctx, const std::string & effort) {
|
||||
@@ -117,6 +117,8 @@ caps caps_get(jinja::program & prog) {
|
||||
|
||||
JJ_DEBUG("%s\n", ">>> Running capability check: typed content");
|
||||
|
||||
static const std::string content_marker = "STRING_MARKER";
|
||||
|
||||
// case: typed content support
|
||||
caps_try_execute(
|
||||
prog,
|
||||
@@ -125,22 +127,26 @@ caps caps_get(jinja::program & prog) {
|
||||
return json::array({
|
||||
{
|
||||
{"role", "user"},
|
||||
{"content", "content"}
|
||||
{"content", content_marker}
|
||||
}
|
||||
});
|
||||
},
|
||||
nullptr, // ctx_fn
|
||||
nullptr, // tools_fn
|
||||
[&](context &, bool success, value & messages, value &, const std::string &) {
|
||||
[&](context &, bool success, value & messages, value &, const std::string & rendered) {
|
||||
auto & content = messages->at(0)->at("content");
|
||||
caps_print_stats(content, "messages[0].content");
|
||||
if (has_op(content, "selectattr") || has_op(content, "array_access")) {
|
||||
bool used_as_array = has_op(content, "selectattr") || has_op(content, "array_access");
|
||||
if (used_as_array) {
|
||||
// accessed as an array
|
||||
result.supports_typed_content = true;
|
||||
}
|
||||
if (!success) {
|
||||
// failed to execute with content as string
|
||||
result.supports_string_content = false;
|
||||
} else if (used_as_array && rendered.find(content_marker) == std::string::npos) {
|
||||
// edge case: string may be accessed for checking, but does not appear in the output
|
||||
result.supports_string_content = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
+33
-3
@@ -365,8 +365,25 @@ struct local_model {
|
||||
std::string name;
|
||||
std::string path;
|
||||
std::string path_mmproj;
|
||||
std::string path_draft;
|
||||
};
|
||||
|
||||
// TODO @ngxson: handle "eagle3-" when it's supported by common_speculative_types_from_gguf()
|
||||
static const char * draft_prefixes[] = { "mtp-", "dspark-", "dflash-" };
|
||||
|
||||
static bool is_mmproj_file(const std::string & fname) {
|
||||
return fname.find("mmproj") != std::string::npos;
|
||||
}
|
||||
|
||||
static bool is_draft_file(const std::string & fname) {
|
||||
for (const auto & prefix : draft_prefixes) {
|
||||
if (fname.rfind(prefix, 0) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
common_presets common_preset_context::load_from_models_dir(const std::string & models_dir) const {
|
||||
if (!std::filesystem::exists(models_dir) || !std::filesystem::is_directory(models_dir)) {
|
||||
throw std::runtime_error(string_format("error: '%s' does not exist or is not a directory\n", models_dir.c_str()));
|
||||
@@ -378,10 +395,15 @@ common_presets common_preset_context::load_from_models_dir(const std::string & m
|
||||
common_file_info model_file;
|
||||
common_file_info first_shard_file;
|
||||
common_file_info mmproj_file;
|
||||
common_file_info draft_file;
|
||||
for (const auto & file : files) {
|
||||
if (string_ends_with(file.name, ".gguf")) {
|
||||
if (file.name.find("mmproj") != std::string::npos) {
|
||||
if (is_mmproj_file(file.name)) {
|
||||
mmproj_file = file;
|
||||
} else if (is_draft_file(file.name)) {
|
||||
if (draft_file.path.empty()) {
|
||||
draft_file = file; // first sidecar found wins
|
||||
}
|
||||
} else if (file.name.find("-00001-of-") != std::string::npos) {
|
||||
first_shard_file = file;
|
||||
} else {
|
||||
@@ -393,7 +415,8 @@ common_presets common_preset_context::load_from_models_dir(const std::string & m
|
||||
local_model model{
|
||||
/* name */ name,
|
||||
/* path */ first_shard_file.path.empty() ? model_file.path : first_shard_file.path,
|
||||
/* path_mmproj */ mmproj_file.path // can be empty
|
||||
/* path_mmproj */ mmproj_file.path, // can be empty
|
||||
/* path_draft */ draft_file.path // can be empty
|
||||
};
|
||||
if (!model.path.empty()) {
|
||||
models.push_back(model);
|
||||
@@ -405,13 +428,17 @@ common_presets common_preset_context::load_from_models_dir(const std::string & m
|
||||
if (file.is_dir) {
|
||||
scan_subdir(file.path, file.name);
|
||||
} else if (string_ends_with(file.name, ".gguf")) {
|
||||
if (is_mmproj_file(file.name) || is_draft_file(file.name)) {
|
||||
continue; // companion file, cannot be loaded as a model on its own
|
||||
}
|
||||
// single file model
|
||||
std::string name = file.name;
|
||||
string_replace_all(name, ".gguf", "");
|
||||
local_model model{
|
||||
/* name */ name,
|
||||
/* path */ file.path,
|
||||
/* path_mmproj */ ""
|
||||
/* path_mmproj */ "",
|
||||
/* path_draft */ ""
|
||||
};
|
||||
models.push_back(model);
|
||||
}
|
||||
@@ -426,6 +453,9 @@ common_presets common_preset_context::load_from_models_dir(const std::string & m
|
||||
if (!model.path_mmproj.empty()) {
|
||||
preset.set_option(*this, "LLAMA_ARG_MMPROJ", model.path_mmproj);
|
||||
}
|
||||
if (!model.path_draft.empty()) {
|
||||
preset.set_option(*this, "LLAMA_ARG_SPEC_DRAFT_MODEL", model.path_draft);
|
||||
}
|
||||
out[preset.name] = preset;
|
||||
}
|
||||
|
||||
|
||||
+15
-8
@@ -926,6 +926,9 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
|
||||
// draft-dspark: the draft carries a Markov head and uses an anchor-first block layout
|
||||
const bool is_dspark;
|
||||
|
||||
// dspark speculators
|
||||
bool sample_from_anchor = true;
|
||||
|
||||
const int32_t * target_layer_ids = nullptr; // model_dft's extract layer indices
|
||||
uint32_t target_layer_ids_n = 0;
|
||||
|
||||
@@ -960,16 +963,20 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
|
||||
if (llama_model_meta_val_str(model_dft, "dflash.block_size", buf, sizeof(buf)) >= 0) {
|
||||
block_size = std::atoi(buf);
|
||||
}
|
||||
if (llama_model_meta_val_str(model_dft, "dflash.sample_from_anchor", buf, sizeof(buf)) >= 0) {
|
||||
sample_from_anchor = std::strcmp(buf, "true") == 0;
|
||||
}
|
||||
}
|
||||
mask_token_id = llama_vocab_mask(llama_model_get_vocab(model_dft));
|
||||
|
||||
LOG_INF("%s: adding speculative implementation '%s'\n", __func__, common_speculative_type_to_str(type).c_str());
|
||||
LOG_INF("%s: - n_max=%d, n_min=%d, p_min=%.2f\n", __func__, this->params.n_max, this->params.n_min, this->params.p_min);
|
||||
LOG_INF("%s: - block_size=%d, mask_token_id=%d, n_extract=%u\n", __func__, block_size, mask_token_id, target_layer_ids_n);
|
||||
LOG_INF("%s: - block_size=%d, mask_token_id=%d, n_extract=%u, sample_from_anchor=%s\n", __func__,
|
||||
block_size, mask_token_id, target_layer_ids_n, sample_from_anchor ? "true" : "false");
|
||||
|
||||
// DFlash input is [id_last, <mask> * (block_size-1)]: in-place denoising yields at most
|
||||
// block_size-1 draft tokens, DSpark yield a full block_size draft tokens
|
||||
const int32_t n_draft_max = is_dspark ? block_size : block_size - 1;
|
||||
// block_size-1 draft tokens, anchor-first DSpark yields a full block_size draft tokens
|
||||
const int32_t n_draft_max = is_dspark && sample_from_anchor ? block_size : block_size - 1;
|
||||
if (this->params.n_max > n_draft_max || this->params.n_min > n_draft_max) {
|
||||
LOG_WRN("%s: requested draft size (n_max=%d, n_min=%d) exceeds the trained block size %d -- clamping to %d\n",
|
||||
__func__, this->params.n_max, this->params.n_min, block_size, n_draft_max);
|
||||
@@ -1175,7 +1182,7 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
|
||||
|
||||
const int32_t n_draft = params.n_max;
|
||||
|
||||
const int32_t n_block_tokens = n_draft + (is_dspark ? 0 : 1);
|
||||
const int32_t n_block_tokens = n_draft + (is_dspark && sample_from_anchor ? 0 : 1);
|
||||
i_block_beg[seq_id] = batch.n_tokens;
|
||||
n_block [seq_id] = n_block_tokens;
|
||||
for (int32_t i = 0; i < n_block_tokens; ++i) {
|
||||
@@ -1208,11 +1215,11 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
|
||||
auto & result = *dp.result;
|
||||
|
||||
if (is_dspark) {
|
||||
// DSpark predicts the next token from position 0 and optionally truncates
|
||||
// at the first position below the confidence threshold.
|
||||
// DSpark: read from the first draft slot, truncate below the confidence threshold
|
||||
const float * conf = params.p_min > 0.0f ? llama_get_embeddings_nextn(ctx_dft) : nullptr;
|
||||
|
||||
for (int32_t i = 0; i < n_block_tokens; ++i) {
|
||||
// bonus-anchor drafts read the mask positions only, like DFlash
|
||||
const int32_t i_draft_beg = sample_from_anchor ? 0 : 1;
|
||||
for (int32_t i = i_draft_beg; i < n_block_tokens; ++i) {
|
||||
const int32_t idx = beg + i;
|
||||
|
||||
if (conf && conf[(size_t) idx * n_embd_dec] < params.p_min) {
|
||||
|
||||
@@ -27,6 +27,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"BaichuanForCausalLM": "baichuan",
|
||||
"BailingMoeForCausalLM": "bailingmoe",
|
||||
"BailingMoeV2ForCausalLM": "bailingmoe",
|
||||
"BailingMoeV3ForCausalLM": "bailingmoe3",
|
||||
"BambaForCausalLM": "granite",
|
||||
"BertForMaskedLM": "bert",
|
||||
"BertForSequenceClassification": "bert",
|
||||
@@ -54,6 +55,8 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"DeepseekV32ForCausalLM": "deepseek",
|
||||
"DFlashDraftModel": "qwen",
|
||||
"Qwen3DSparkModel": "qwen",
|
||||
"DSparkDraftModel": "qwen",
|
||||
"DSparkSpeculator": "qwen",
|
||||
"DeepseekV4ForCausalLM": "deepseek",
|
||||
"DeepseekV4DSparkModel": "deepseek",
|
||||
"DistilBertForMaskedLM": "bert",
|
||||
@@ -125,6 +128,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"JinaEmbeddingsV5Model": "bert",
|
||||
"KORMoForCausalLM": "qwen",
|
||||
"KimiK25ForConditionalGeneration": "deepseek",
|
||||
"KimiK3ForConditionalGeneration": "kimi_k3",
|
||||
"KimiLinearForCausalLM": "kimi_linear",
|
||||
"KimiLinearModel": "kimi_linear",
|
||||
"KimiVLForConditionalGeneration": "deepseek",
|
||||
|
||||
@@ -13,6 +13,7 @@ from .llama import LlamaModel
|
||||
|
||||
|
||||
@ModelBase.register("AfmoeForCausalLM")
|
||||
@ModelBase.example("arcee-ai/Trinity-Large-Thinking")
|
||||
class AfmoeModel(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.AFMOE
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ from .llama import LlamaModel
|
||||
|
||||
|
||||
@ModelBase.register("ArcticForCausalLM")
|
||||
@ModelBase.example("Snowflake/snowflake-arctic-instruct")
|
||||
class ArcticModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.ARCTIC
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("BaichuanForCausalLM", "BaiChuanForCausalLM")
|
||||
@ModelBase.example("baichuan-inc/Baichuan2-7B-Chat", "baichuan-inc/Baichuan-7B")
|
||||
class BaichuanModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.BAICHUAN
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("BailingMoeForCausalLM")
|
||||
@ModelBase.example("inclusionAI/Ling-lite")
|
||||
class BailingMoeModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.BAILINGMOE
|
||||
|
||||
@@ -108,6 +109,7 @@ class BailingMoeModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("BailingMoeV2ForCausalLM")
|
||||
@ModelBase.example("inclusionAI/Ling-mini-2.0")
|
||||
class BailingMoeV2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.BAILINGMOE2
|
||||
|
||||
@@ -189,6 +191,7 @@ class BailingMoeV2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("SarvamMoEForCausalLM", "modeling_sarvam_moe.SarvamMoEForCausalLM")
|
||||
@ModelBase.example("sarvamai/sarvam-30b")
|
||||
class SarvamMoEModel(BailingMoeV2Model):
|
||||
model_arch = gguf.MODEL_ARCH.BAILINGMOE2
|
||||
# Sarvam-MoE shares the BailingMoeV2 architecture; only differences:
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
from typing import Callable, Iterable, TYPE_CHECKING
|
||||
|
||||
import torch
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("BailingMoeV3ForCausalLM")
|
||||
@ModelBase.example("inclusionAI/Ling-3.0-tiny", "inclusionAI/Ling-3.0-flash")
|
||||
class BailingMoeV3Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.BAILINGMOE3
|
||||
supports_mtp_export = True
|
||||
|
||||
_experts: list[dict[str, Tensor]] | None = None
|
||||
_main_layers: int | None = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
nextn_layers = self.hparams.get("num_nextn_predict_layers", 0) or 0
|
||||
if self.no_mtp:
|
||||
nextn_layers = 0
|
||||
self.block_count = self.hparams["num_hidden_layers"] + nextn_layers
|
||||
self.tensor_map = gguf.get_tensor_name_map(self.model_arch, self.block_count)
|
||||
|
||||
def index_tensors(self, remote_hf_model_id: str | None = None):
|
||||
type(self)._main_layers = self.hparams["num_hidden_layers"]
|
||||
return super().index_tensors(remote_hf_model_id=remote_hf_model_id)
|
||||
|
||||
def set_vocab(self):
|
||||
self._set_vocab_gpt2()
|
||||
|
||||
def is_full_attention(self, bid: int) -> bool:
|
||||
n_layer = self.hparams["num_hidden_layers"]
|
||||
layer_group_size = self.hparams["layer_group_size"]
|
||||
return bid >= n_layer or (bid + 1) % layer_group_size == 0 or bid >= n_layer // layer_group_size * layer_group_size
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
if not self.hparams.get("no_kda_lora", False):
|
||||
raise ValueError("BailingMoeV3 KDA LoRA projections are not supported")
|
||||
if not self.hparams.get("kda_safe_gate", False):
|
||||
raise ValueError("BailingMoeV3 non-safe KDA gates are not supported")
|
||||
if self.hparams.get("gated_attention_proj_granularity_type") != "head_wise":
|
||||
raise ValueError("BailingMoeV3 requires head-wise attention gates")
|
||||
|
||||
self.hparams["num_key_value_heads"] = 1
|
||||
super().set_gguf_parameters()
|
||||
|
||||
n_head_kv = [1 if self.is_full_attention(il) else 0 for il in range(self.block_count)]
|
||||
self.gguf_writer.add_head_count_kv(n_head_kv)
|
||||
|
||||
self.gguf_writer.add_vocab_size(self.hparams["vocab_size"])
|
||||
self.gguf_writer.add_ssm_conv_kernel(self.hparams["short_conv_kernel_size"])
|
||||
self.gguf_writer.add_kda_head_dim(self.hparams["head_dim"])
|
||||
self.gguf_writer.add_kda_safe_gate(self.hparams["kda_safe_gate"])
|
||||
self.gguf_writer.add_kda_gate_lower_bound(self.hparams["kda_lower_bound"])
|
||||
|
||||
kv_lora_rank = self.hparams["kv_lora_rank"]
|
||||
qk_nope_head_dim = self.hparams["qk_nope_head_dim"]
|
||||
qk_rope_head_dim = self.hparams["qk_rope_head_dim"]
|
||||
if (q_lora_rank := self.hparams.get("q_lora_rank")) is not None:
|
||||
self.gguf_writer.add_q_lora_rank(q_lora_rank)
|
||||
self.gguf_writer.add_kv_lora_rank(kv_lora_rank)
|
||||
self.gguf_writer.add_rope_dimension_count(qk_rope_head_dim)
|
||||
self.gguf_writer.add_key_length(kv_lora_rank + qk_rope_head_dim)
|
||||
self.gguf_writer.add_key_length_mla(qk_nope_head_dim + qk_rope_head_dim)
|
||||
self.gguf_writer.add_value_length_mla(self.hparams["v_head_dim"])
|
||||
|
||||
self.gguf_writer.add_expert_feed_forward_length(self.hparams["moe_intermediate_size"])
|
||||
self.gguf_writer.add_expert_shared_feed_forward_length(self.hparams["moe_shared_expert_intermediate_size"])
|
||||
self.gguf_writer.add_expert_shared_count(self.hparams["num_shared_experts"])
|
||||
self.gguf_writer.add_leading_dense_block_count(self.hparams["first_k_dense_replace"])
|
||||
self.gguf_writer.add_expert_weights_scale(self.hparams["routed_scaling_factor"])
|
||||
self.gguf_writer.add_expert_weights_norm(self.hparams["norm_topk_prob"])
|
||||
|
||||
def clamp_limits(key: str) -> list[float] | None:
|
||||
values = self.hparams.get(key)
|
||||
if values is None:
|
||||
return None
|
||||
values = [0.0 if value is None else float(value) for value in values[:self.block_count]]
|
||||
return values + [0.0] * (self.block_count - len(values))
|
||||
|
||||
if (values := clamp_limits("expert_swiglu_limit_list")) is not None:
|
||||
self.gguf_writer.add_swiglu_clamp_exp(values)
|
||||
if (values := clamp_limits("share_expert_swiglu_limit_list")) is not None:
|
||||
self.gguf_writer.add_swiglu_clamp_shexp(values)
|
||||
|
||||
if not self.no_mtp and (nextn_layers := self.hparams.get("num_nextn_predict_layers", 0)):
|
||||
self.gguf_writer.add_nextn_predict_layers(nextn_layers)
|
||||
|
||||
def prepare_metadata(self, vocab_only: bool):
|
||||
from_dir = self.fname_out.is_dir()
|
||||
super().prepare_metadata(vocab_only=vocab_only)
|
||||
|
||||
if not self.mtp_only or not from_dir:
|
||||
return
|
||||
|
||||
output_type: str = self.ftype.name.partition("_")[2]
|
||||
fname_default: str = gguf.naming_convention(
|
||||
self.metadata.name, self.metadata.basename, self.metadata.finetune,
|
||||
self.metadata.version, size_label=None, output_type=output_type, model_type=None)
|
||||
self.fname_out = self.fname_out.parent / f"mtp-{fname_default}.gguf"
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
name, gen = item
|
||||
if name.endswith(".expert_bias"):
|
||||
name += ".bias"
|
||||
|
||||
if cls._main_layers is None:
|
||||
return super().filter_tensors((name, gen))
|
||||
|
||||
m = re.match(r"model\.layers\.(\d+)\.", name)
|
||||
is_mtp = m is not None and int(m.group(1)) >= cls._main_layers
|
||||
|
||||
if is_mtp and cls.no_mtp:
|
||||
return None
|
||||
if cls.mtp_only and not is_mtp and name not in (
|
||||
"model.word_embeddings.weight", "model.norm.weight", "lm_head.weight",
|
||||
):
|
||||
return None
|
||||
|
||||
return super().filter_tensors((name, gen))
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
if name.endswith((".q_conv1d.weight", ".k_conv1d.weight", ".v_conv1d.weight")) and data_torch.ndim in (2, 3):
|
||||
d_inner = data_torch.shape[0]
|
||||
d_conv = data_torch.shape[-1]
|
||||
data_torch = data_torch.reshape(1, d_inner, 1, d_conv)
|
||||
|
||||
if name.endswith(".A_log"):
|
||||
data_torch = torch.exp(data_torch).reshape(-1, 1)
|
||||
|
||||
if name.endswith(".dt_bias"):
|
||||
name = name.rpartition(".dt_bias")[0] + ".dt_proj.bias"
|
||||
|
||||
if name.endswith(".attention.f_proj.weight"):
|
||||
assert bid is not None
|
||||
if self.is_full_attention(bid):
|
||||
raise ValueError(f"unexpected f_proj on full-attention layer {bid}")
|
||||
name = self.format_tensor_name(gguf.MODEL_TENSOR.SSM_F_A, bid)
|
||||
|
||||
if name.endswith(".attention.g_proj.weight"):
|
||||
assert bid is not None
|
||||
tensor = gguf.MODEL_TENSOR.ATTN_GATE if self.is_full_attention(bid) else gguf.MODEL_TENSOR.SSM_G_A
|
||||
name = self.format_tensor_name(tensor, bid)
|
||||
|
||||
if ".mlp.experts." in name:
|
||||
n_experts = self.hparams["num_experts"]
|
||||
assert bid is not None
|
||||
|
||||
if self._experts is None:
|
||||
self._experts = [{} for _ in range(self.block_count)]
|
||||
|
||||
self._experts[bid][name] = data_torch
|
||||
if len(self._experts[bid]) >= n_experts * 3:
|
||||
for weight_name in ("down_proj", "gate_proj", "up_proj"):
|
||||
tensors = []
|
||||
for expert_id in range(n_experts):
|
||||
expert_name = f"model.layers.{bid}.mlp.experts.{expert_id}.{weight_name}.weight"
|
||||
tensors.append(self._experts[bid].pop(expert_name))
|
||||
merged_name = f"model.layers.{bid}.mlp.experts.{weight_name}.weight"
|
||||
yield from super().modify_tensors(torch.stack(tensors, dim=0), merged_name, bid)
|
||||
return
|
||||
|
||||
if name.endswith(".attention.kv_b_proj.weight"):
|
||||
assert bid is not None
|
||||
n_head = self.hparams["num_attention_heads"]
|
||||
v_head_dim = self.hparams["v_head_dim"]
|
||||
qk_nope_head_dim = self.hparams["qk_nope_head_dim"]
|
||||
assert data_torch.shape[0] == n_head * (v_head_dim + qk_nope_head_dim)
|
||||
kv_b = data_torch.view(n_head, v_head_dim + qk_nope_head_dim, data_torch.shape[-1])
|
||||
k_b, v_b = torch.split(kv_b, [qk_nope_head_dim, v_head_dim], dim=1)
|
||||
name_k = self.format_tensor_name(gguf.MODEL_TENSOR.ATTN_K_B, bid)
|
||||
name_v = self.format_tensor_name(gguf.MODEL_TENSOR.ATTN_V_B, bid)
|
||||
yield from super().modify_tensors(k_b.transpose(1, 2), name_k, bid)
|
||||
yield from super().modify_tensors(v_b, name_v, bid)
|
||||
return
|
||||
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
def prepare_tensors(self):
|
||||
super().prepare_tensors()
|
||||
if self._experts is not None:
|
||||
experts = [name for layer in self._experts for name in layer]
|
||||
if experts:
|
||||
raise ValueError(f"Unprocessed experts: {experts}")
|
||||
+49
-1
@@ -658,6 +658,43 @@ class ModelBase:
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
return ()
|
||||
|
||||
@staticmethod
|
||||
def repack_mxfp4_blocks(packed: Tensor, scale: Tensor) -> np.ndarray:
|
||||
"""
|
||||
Repack 4-bit MX weights into ggml `block_mxfp4`. Lossless - only moves bits.
|
||||
|
||||
Source (compressed-tensors "mxfp4-pack-quantized", also used by DeepSeek-V4):
|
||||
packed uint8 [rows, cols/2] element 2i in the low nibble, 2i+1 in the high one
|
||||
scale uint8 [rows, cols/32] one E8M0 biased exponent per 32-element group
|
||||
|
||||
Destination, per group: one scale byte then 16 code bytes, where byte j holds
|
||||
element j in the low nibble and element j+16 in the high one.
|
||||
|
||||
The 4-bit codes need no remapping: both sides index into ggml's kvalues_mxfp4
|
||||
order. ggml doubles the kvalues and halves the scale, so the value is the same.
|
||||
"""
|
||||
p = packed.contiguous().view(torch.uint8)
|
||||
s = scale.contiguous().view(torch.uint8)
|
||||
|
||||
rows, packed_cols = p.shape
|
||||
cols = packed_cols * 2
|
||||
if cols % 32 != 0:
|
||||
raise ValueError(f"MXFP4 source row has {cols} values, expected a multiple of 32")
|
||||
|
||||
n_blocks = cols // 32
|
||||
if tuple(s.shape) != (rows, n_blocks):
|
||||
raise ValueError(f"MXFP4 scale shape {tuple(s.shape)} does not match {(rows, n_blocks)}")
|
||||
|
||||
src = p.reshape(rows, n_blocks, 16)
|
||||
lo = src & 0x0F # elements 0, 2, 4, ...
|
||||
hi = (src >> 4) & 0x0F # elements 1, 3, 5, ...
|
||||
|
||||
vals = torch.stack((lo, hi), dim=-1).reshape(rows, n_blocks, 32)
|
||||
qs = vals[:, :, :16] | (vals[:, :, 16:] << 4)
|
||||
|
||||
raw = torch.cat((s.unsqueeze(-1), qs.to(torch.uint8)), dim=-1)
|
||||
return raw.reshape(rows, n_blocks * 17).cpu().numpy()
|
||||
|
||||
@staticmethod
|
||||
def _nvfp4_pack(weight: Tensor, scale: Tensor) -> tuple[np.ndarray, list[int]]:
|
||||
"""Repack NVFP4 ModelOpt tensors into ggml super-block layout.
|
||||
@@ -1112,6 +1149,14 @@ class ModelBase:
|
||||
return modelcls
|
||||
return func
|
||||
|
||||
@classmethod
|
||||
def example(cls, *hf_repos: str) -> Callable[[AnyModel], AnyModel]:
|
||||
del hf_repos # unused
|
||||
|
||||
def func(modelcls: AnyModel) -> AnyModel:
|
||||
return modelcls
|
||||
return func
|
||||
|
||||
@classmethod
|
||||
def print_registered_models(cls):
|
||||
for model_type, model_classes in cls._model_classes.items():
|
||||
@@ -2661,7 +2706,10 @@ def get_model_architecture(hparams: dict[str, Any], model_type: ModelType) -> st
|
||||
# Step3-VL keeps text config under text_config but uses a custom top-level architecture.
|
||||
# For text conversion we route to a dedicated text-only class.
|
||||
# TODO: refactor this later to avoid adding exception here
|
||||
if model_type == ModelType.TEXT and arch in ("StepVLForConditionalGeneration", "Sarashina2VisionForCausalLM", "Exaone4_5_ForConditionalGeneration", "Step3p7ForConditionalGeneration"):
|
||||
# Kimi-K3's text_config reports "KimiLinearForCausalLM", which is the older
|
||||
# Kimi-Linear-48B architecture and cannot load K3 (no attention residuals,
|
||||
# latent MoE, situ, ...). Route on the top-level architecture instead.
|
||||
if model_type == ModelType.TEXT and arch in ("StepVLForConditionalGeneration", "Sarashina2VisionForCausalLM", "Exaone4_5_ForConditionalGeneration", "Step3p7ForConditionalGeneration", "KimiK3ForConditionalGeneration"):
|
||||
return arch
|
||||
|
||||
# if "architectures" is found in the sub-config, use that instead
|
||||
|
||||
@@ -15,6 +15,7 @@ from .base import ModelBase, SentencePieceTokenTypes, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("BertModel", "BertForMaskedLM", "CamembertModel", "BertForSequenceClassification")
|
||||
@ModelBase.example("BAAI/bge-small-en-v1.5", "dangvantuan/sentence-camembert-base")
|
||||
class BertModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.BERT
|
||||
|
||||
@@ -240,6 +241,7 @@ class BertModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("DistilBertModel", "DistilBertForMaskedLM", "DistilBertForSequenceClassification")
|
||||
@ModelBase.example("distilbert/distilbert-base-uncased")
|
||||
class DistilBertModel(BertModel):
|
||||
model_arch = gguf.MODEL_ARCH.BERT
|
||||
|
||||
@@ -263,6 +265,7 @@ class DistilBertModel(BertModel):
|
||||
|
||||
|
||||
@ModelBase.register("RobertaModel", "RobertaForSequenceClassification")
|
||||
@ModelBase.example("sentence-transformers/stsb-roberta-base")
|
||||
class RobertaModel(BertModel):
|
||||
model_arch = gguf.MODEL_ARCH.BERT
|
||||
|
||||
@@ -312,6 +315,7 @@ class RobertaModel(BertModel):
|
||||
|
||||
|
||||
@ModelBase.register("NomicBertModel")
|
||||
@ModelBase.example("nomic-ai/nomic-embed-text-v1.5")
|
||||
class NomicBertModel(BertModel):
|
||||
model_arch = gguf.MODEL_ARCH.BERT
|
||||
|
||||
@@ -400,6 +404,7 @@ class NomicBertModel(BertModel):
|
||||
|
||||
|
||||
@ModelBase.register("NeoBERT", "NeoBERTLMHead", "NeoBERTForSequenceClassification")
|
||||
@ModelBase.example("chandar-lab/NeoBERT")
|
||||
class NeoBert(BertModel):
|
||||
model_arch = gguf.MODEL_ARCH.NEO_BERT
|
||||
|
||||
@@ -431,6 +436,7 @@ class NeoBert(BertModel):
|
||||
|
||||
|
||||
@ModelBase.register("EuroBertModel", "JinaEmbeddingsV5Model")
|
||||
@ModelBase.example("hf-tiny-v2/tiny-random-EuroBertModel", "jinaai/jina-embeddings-v5-text-nano")
|
||||
class EuroBertModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.EUROBERT
|
||||
|
||||
@@ -459,6 +465,7 @@ class EuroBertModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("XLMRobertaModel", "XLMRobertaForSequenceClassification")
|
||||
@ModelBase.example("BAAI/bge-m3")
|
||||
class XLMRobertaModel(BertModel):
|
||||
model_arch = gguf.MODEL_ARCH.BERT
|
||||
_lora_files = {}
|
||||
@@ -561,6 +568,7 @@ class XLMRobertaModel(BertModel):
|
||||
|
||||
|
||||
@ModelBase.register("JinaBertModel", "JinaBertForMaskedLM")
|
||||
@ModelBase.example("jinaai/jina-embeddings-v2-base-en")
|
||||
class JinaBertV2Model(BertModel):
|
||||
model_arch = gguf.MODEL_ARCH.JINA_BERT_V2
|
||||
|
||||
@@ -588,6 +596,7 @@ class JinaBertV2Model(BertModel):
|
||||
|
||||
|
||||
@ModelBase.register("ModernBertModel", "ModernBertForMaskedLM", "ModernBertForSequenceClassification")
|
||||
@ModelBase.example("answerdotai/ModernBERT-base")
|
||||
class ModernBertModel(BertModel):
|
||||
model_arch = gguf.MODEL_ARCH.MODERN_BERT
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("BitnetForCausalLM", "BitNetForCausalLM")
|
||||
@ModelBase.example("microsoft/bitnet-b1.58-2B-4T")
|
||||
class BitnetModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.BITNET
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("BloomForCausalLM", "BloomModel")
|
||||
@ModelBase.example("bigscience/bloom-560m")
|
||||
class BloomModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.BLOOM
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ from .llama import LlamaModel
|
||||
|
||||
@ModelBase.register("ChameleonForConditionalGeneration")
|
||||
@ModelBase.register("ChameleonForCausalLM") # obsolete
|
||||
# [TAG_HF_EXAMPLE_GATED] facebook/chameleon-7b is gated
|
||||
# [TAG_HF_EXAMPLE_MISSING]
|
||||
class ChameleonModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.CHAMELEON
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import ModelBase, SentencePieceTokenTypes, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("GlmForCausalLM", "ChatGLMModel", "ChatGLMForConditionalGeneration")
|
||||
@ModelBase.example("THUDM/chatglm3-6b", "zai-org/glm-4-9b-chat-hf")
|
||||
class ChatGLMModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.CHATGLM
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("CodeShellForCausalLM")
|
||||
@ModelBase.example("WisdomShell/CodeShell-7B")
|
||||
class CodeShellModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.CODESHELL
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .llama import LlamaModel
|
||||
|
||||
|
||||
@ModelBase.register("CogVLMForCausalLM")
|
||||
@ModelBase.example("THUDM/cogvlm2-llama3-chat-19B", "THUDM/cogvlm-chat-hf")
|
||||
class CogVLMVisionModel(MmprojModel):
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
@@ -29,5 +30,6 @@ class CogVLMVisionModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("CogVLMForCausalLM")
|
||||
@ModelBase.example("THUDM/cogvlm2-llama3-chat-19B", "THUDM/cogvlm-chat-hf")
|
||||
class CogVLMModel(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.COGVLM
|
||||
|
||||
@@ -12,6 +12,8 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("CohereForCausalLM")
|
||||
# [TAG_HF_EXAMPLE_GATED] CohereLabs/c4ai-command-r-v01 is gated
|
||||
# [TAG_HF_EXAMPLE_MISSING]
|
||||
class CommandR2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.COMMAND_R
|
||||
|
||||
@@ -30,6 +32,8 @@ class CommandR2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Cohere2ForCausalLM")
|
||||
# [TAG_HF_EXAMPLE_GATED] CohereLabs/c4ai-command-r7b-12-2024 is gated
|
||||
@ModelBase.example("hf-tiny-v2/tiny-random-Cohere2ForCausalLM")
|
||||
class Cohere2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.COHERE2
|
||||
|
||||
@@ -59,6 +63,7 @@ class Cohere2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Cohere2MoeForCausalLM")
|
||||
@ModelBase.example("CohereLabs/North-Mini-Code-1.0")
|
||||
class Cohere2MoeModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.COHERE2MOE
|
||||
_n_main_layers: int | None = None
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("DbrxForCausalLM")
|
||||
@ModelBase.example("alpindale/dbrx-instruct")
|
||||
class DbrxModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.DBRX
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("DeciLMForCausalLM")
|
||||
@ModelBase.example("nvidia/Llama-3_1-Nemotron-51B-Instruct", "Deci/DeciLM-7B")
|
||||
class DeciModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.DECI
|
||||
|
||||
|
||||
+9
-26
@@ -18,6 +18,7 @@ from .qwen import QwenModel
|
||||
|
||||
|
||||
@ModelBase.register("DeepseekOCRForCausalLM")
|
||||
@ModelBase.example("deepseek-ai/DeepSeek-OCR")
|
||||
class DeepseekOCRVisionModel(MmprojModel):
|
||||
# HF dynamic_preprocess() max_num, which differs per model
|
||||
preproc_max_tiles = 9
|
||||
@@ -100,11 +101,13 @@ class DeepseekOCRVisionModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("UnlimitedOCRForCausalLM")
|
||||
@ModelBase.example("baidu/Unlimited-OCR")
|
||||
class UnlimitedOCRVisionModel(DeepseekOCRVisionModel):
|
||||
preproc_max_tiles = 32
|
||||
|
||||
|
||||
@ModelBase.register("DeepseekOCR2ForCausalLM")
|
||||
@ModelBase.example("deepseek-ai/DeepSeek-OCR-2")
|
||||
class DeepseekOCR2VisionModel(DeepseekOCRVisionModel):
|
||||
preproc_max_tiles = 6
|
||||
|
||||
@@ -134,6 +137,7 @@ class DeepseekOCR2VisionModel(DeepseekOCRVisionModel):
|
||||
|
||||
|
||||
@ModelBase.register("DeepseekForCausalLM")
|
||||
@ModelBase.example("deepseek-ai/deepseek-moe-16b-chat")
|
||||
class DeepseekModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.DEEPSEEK
|
||||
|
||||
@@ -228,6 +232,7 @@ class DeepseekModel(TextModel):
|
||||
"YoutuForCausalLM",
|
||||
"YoutuVLForConditionalGeneration",
|
||||
)
|
||||
@ModelBase.example("deepseek-ai/DeepSeek-V2-Lite", "deepseek-ai/DeepSeek-V3")
|
||||
class DeepseekV2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.DEEPSEEK2
|
||||
|
||||
@@ -457,6 +462,7 @@ class DeepseekV2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("DeepseekV32ForCausalLM")
|
||||
@ModelBase.example("deepseek-ai/DeepSeek-V3.2-Exp")
|
||||
class DeepseekV32Model(DeepseekV2Model):
|
||||
model_arch = gguf.MODEL_ARCH.DEEPSEEK32
|
||||
skip_mtp = False
|
||||
@@ -517,6 +523,7 @@ class DeepseekV32Model(DeepseekV2Model):
|
||||
|
||||
|
||||
@ModelBase.register("DeepseekV4ForCausalLM")
|
||||
@ModelBase.example("deepseek-ai/DeepSeek-V4-Flash-Base")
|
||||
class DeepseekV4Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.DEEPSEEK4
|
||||
supports_mtp_export = True
|
||||
@@ -709,31 +716,6 @@ class DeepseekV4Model(TextModel):
|
||||
for name in tensors_to_remove:
|
||||
del self.model_tensors[name]
|
||||
|
||||
@staticmethod
|
||||
def _pack_mxfp4_blocks(weight: Tensor, scale: Tensor) -> np.ndarray:
|
||||
packed = weight.contiguous().view(torch.uint8)
|
||||
scale_u8 = scale.contiguous().view(torch.uint8)
|
||||
|
||||
out_features, packed_cols = packed.shape
|
||||
logical_cols = packed_cols * 2
|
||||
if logical_cols % 32 != 0:
|
||||
raise ValueError(f"MXFP4 source row has {logical_cols} values, expected a multiple of 32")
|
||||
|
||||
n_blocks = logical_cols // 32
|
||||
if tuple(scale_u8.shape) != (out_features, n_blocks):
|
||||
raise ValueError(f"MXFP4 scale shape {tuple(scale_u8.shape)} does not match {(out_features, n_blocks)}")
|
||||
|
||||
src = packed.reshape(out_features, n_blocks, 16)
|
||||
low = src & 0x0F
|
||||
high = (src >> 4) & 0x0F
|
||||
|
||||
# The safetensors bytes store adjacent values as low/high nibbles.
|
||||
# ggml MXFP4 blocks store values 0..15 in low nibbles and 16..31 in high nibbles.
|
||||
vals = torch.stack((low, high), dim=-1).reshape(out_features, n_blocks, 32)
|
||||
qs = vals[:, :, :16] | (vals[:, :, 16:] << 4)
|
||||
raw = torch.cat((scale_u8.unsqueeze(-1), qs.to(torch.uint8)), dim=-1)
|
||||
return raw.reshape(out_features, n_blocks * 17).cpu().numpy()
|
||||
|
||||
def _write_mxfp4_expert_tensor(self, bid: int, proj: str, tensor_key: gguf.MODEL_TENSOR) -> list[str]:
|
||||
n_experts = self.hparams["n_routed_experts"]
|
||||
data: np.ndarray | None = None
|
||||
@@ -747,7 +729,7 @@ class DeepseekV4Model(TextModel):
|
||||
|
||||
weight = LazyTorchTensor.to_eager(self.model_tensors[weight_name]())
|
||||
scale = LazyTorchTensor.to_eager(self.model_tensors[scale_name]())
|
||||
packed = self._pack_mxfp4_blocks(weight, scale)
|
||||
packed = self.repack_mxfp4_blocks(weight, scale)
|
||||
if data is None:
|
||||
data = np.empty((n_experts, *packed.shape), dtype=packed.dtype)
|
||||
data[eid] = packed
|
||||
@@ -936,6 +918,7 @@ class DeepseekV4Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("DeepseekV4DSparkModel")
|
||||
@ModelBase.example("deepseek-ai/DeepSeek-V4-Flash-DSpark")
|
||||
class DeepseekV4DSparkModel(DeepseekV4Model):
|
||||
model_arch = gguf.MODEL_ARCH.DFLASH
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .qwen import Qwen2MoeModel
|
||||
|
||||
|
||||
@ModelBase.register("Dots1ForCausalLM")
|
||||
@ModelBase.example("rednote-hilab/dots.llm1.inst")
|
||||
class Dots1Model(Qwen2MoeModel):
|
||||
model_arch = gguf.MODEL_ARCH.DOTS1
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import MmprojModel, ModelBase, gguf
|
||||
|
||||
|
||||
@ModelBase.register("DotsOCRForCausalLM")
|
||||
@ModelBase.example("rednote-hilab/dots.ocr")
|
||||
class DotsOCRVisionModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("DreamModel")
|
||||
@ModelBase.example("Dream-org/Dream-v0-Instruct-7B")
|
||||
class DreamModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.DREAM
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ from .base import MmprojModel, ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("Ernie4_5_ForCausalLM", "Ernie4_5ForCausalLM")
|
||||
@ModelBase.example("baidu/ERNIE-4.5-0.3B-PT")
|
||||
class Ernie4_5Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.ERNIE4_5
|
||||
|
||||
@@ -73,6 +74,7 @@ class Ernie4_5Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Ernie4_5_MoeForCausalLM")
|
||||
@ModelBase.example("baidu/ERNIE-4.5-21B-A3B-PT")
|
||||
class Ernie4_5MoeModel(Ernie4_5Model):
|
||||
model_arch = gguf.MODEL_ARCH.ERNIE4_5_MOE
|
||||
_experts: list[dict[str, Tensor]] | None = None
|
||||
@@ -156,11 +158,13 @@ class Ernie4_5MoeModel(Ernie4_5Model):
|
||||
|
||||
|
||||
@ModelBase.register("PaddleOCRVLForConditionalGeneration")
|
||||
@ModelBase.example("PaddlePaddle/PaddleOCR-VL")
|
||||
class PaddleOCRModel(Ernie4_5Model):
|
||||
model_arch = gguf.MODEL_ARCH.PADDLEOCR
|
||||
|
||||
|
||||
@ModelBase.register("PaddleOCRVisionModel")
|
||||
@ModelBase.example("PaddlePaddle/PaddleOCR-VL")
|
||||
class PaddleOCRVisionModel(MmprojModel):
|
||||
# PaddleOCR-VL uses a modified version of Siglip
|
||||
min_pixels: int = 0
|
||||
|
||||
@@ -15,6 +15,7 @@ from .qwenvl import Qwen2VLVisionModel
|
||||
|
||||
|
||||
@ModelBase.register("ExaoneForCausalLM")
|
||||
@ModelBase.example("LGAI-EXAONE/EXAONE-3.5-2.4B-Instruct")
|
||||
class ExaoneModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.EXAONE
|
||||
|
||||
@@ -60,6 +61,7 @@ class ExaoneModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Exaone4ForCausalLM")
|
||||
@ModelBase.example("LGAI-EXAONE/EXAONE-4.0-32B")
|
||||
class Exaone4Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.EXAONE4
|
||||
|
||||
@@ -126,6 +128,7 @@ class Exaone4Model(TextModel):
|
||||
# note: transformers >= 5.1 renamed the class to "ExaoneMoeForCausalLM" (lowercase 'e'),
|
||||
# so accept both spellings - LG AI have updated the configs of already-released models
|
||||
@ModelBase.register("ExaoneMoEForCausalLM", "ExaoneMoeForCausalLM")
|
||||
@ModelBase.example("LGAI-EXAONE/K-EXAONE-236B-A23B")
|
||||
class ExaoneMoEModel(Exaone4Model):
|
||||
model_arch = gguf.MODEL_ARCH.EXAONE_MOE
|
||||
|
||||
@@ -214,6 +217,7 @@ class ExaoneMoEModel(Exaone4Model):
|
||||
|
||||
|
||||
@ModelBase.register("Exaone4_5_ForConditionalGeneration")
|
||||
@ModelBase.example("LGAI-EXAONE/EXAONE-4.5-33B")
|
||||
class Exaone4_5_TextModel(Exaone4Model):
|
||||
"""Text tower of EXAONE 4.5; Tensors match EXAONE4"""
|
||||
|
||||
@@ -267,6 +271,7 @@ class Exaone4_5_TextModel(Exaone4Model):
|
||||
|
||||
|
||||
@ModelBase.register("Exaone4_5_ForConditionalGeneration")
|
||||
@ModelBase.example("LGAI-EXAONE/EXAONE-4.5-33B")
|
||||
class Exaone4_5VisionModel(Qwen2VLVisionModel):
|
||||
"""Vision tower for EXAONE 4.5; Qwen2-VL-style ViT (GQA) + patch merger"""
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("FalconForCausalLM", "RWForCausalLM")
|
||||
@ModelBase.example("tiiuae/falcon-7b")
|
||||
class FalconModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.FALCON
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from .mamba import Mamba2Model
|
||||
|
||||
|
||||
@ModelBase.register("FalconH1ForCausalLM")
|
||||
@ModelBase.example("tiiuae/Falcon-H1-0.5B-Base")
|
||||
class FalconH1Model(Mamba2Model):
|
||||
model_arch = gguf.MODEL_ARCH.FALCON_H1
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ from .base import MmprojModel, ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("GemmaForCausalLM")
|
||||
# [TAG_HF_EXAMPLE_GATED] google/gemma-2b is gated
|
||||
@ModelBase.example("trl-internal-testing/tiny-GemmaForCausalLM")
|
||||
class GemmaModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GEMMA
|
||||
|
||||
@@ -68,6 +70,8 @@ class GemmaModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma2ForCausalLM")
|
||||
# [TAG_HF_EXAMPLE_GATED] google/gemma-2-9b-it is gated
|
||||
@ModelBase.example("trl-internal-testing/tiny-Gemma2ForCausalLM")
|
||||
class Gemma2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GEMMA2
|
||||
|
||||
@@ -118,6 +122,8 @@ class Gemma2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma3ForCausalLM", "Gemma3ForConditionalGeneration")
|
||||
# [TAG_HF_EXAMPLE_GATED] google/gemma-3-4b-it is gated
|
||||
@ModelBase.example("trl-internal-testing/tiny-Gemma3ForConditionalGeneration", "hf-tiny-v2/tiny-random-Gemma3ForCausalLM")
|
||||
class Gemma3Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GEMMA3
|
||||
|
||||
@@ -174,6 +180,8 @@ class Gemma3Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma3TextModel")
|
||||
# [TAG_HF_EXAMPLE_GATED] google/embeddinggemma-300m is gated
|
||||
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma3TextModel")
|
||||
class EmbeddingGemma(Gemma3Model):
|
||||
model_arch = gguf.MODEL_ARCH.GEMMA_EMBEDDING
|
||||
module_paths = []
|
||||
@@ -248,6 +256,8 @@ class EmbeddingGemma(Gemma3Model):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma3ForConditionalGeneration")
|
||||
# [TAG_HF_EXAMPLE_GATED] google/gemma-3-4b-it is gated
|
||||
@ModelBase.example("trl-internal-testing/tiny-Gemma3ForConditionalGeneration")
|
||||
class Gemma3VisionModel(MmprojModel):
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
@@ -352,6 +362,8 @@ class ConformerAudioModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma3nForConditionalGeneration")
|
||||
# [TAG_HF_EXAMPLE_GATED] google/gemma-3n-E2B-it is gated
|
||||
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma3nForConditionalGeneration")
|
||||
class Gemma3nVisionAudioModel(ConformerAudioModel):
|
||||
has_audio_encoder = True
|
||||
has_vision_encoder = True
|
||||
@@ -471,6 +483,8 @@ class Gemma3nVisionAudioModel(ConformerAudioModel):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma3nForCausalLM", "Gemma3nForConditionalGeneration")
|
||||
# [TAG_HF_EXAMPLE_GATED] google/gemma-3n-E2B-it is gated
|
||||
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma3nForConditionalGeneration")
|
||||
class Gemma3NModel(Gemma3Model):
|
||||
model_arch = gguf.MODEL_ARCH.GEMMA3N
|
||||
|
||||
@@ -615,6 +629,7 @@ class Gemma3NModel(Gemma3Model):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma4ForConditionalGeneration", "Gemma4ForCausalLM")
|
||||
@ModelBase.example("google/gemma-4-31B-it", "google/gemma-4-26B-A4B-it", "google/gemma-4-E2B-it")
|
||||
class Gemma4Model(Gemma3Model):
|
||||
model_arch = gguf.MODEL_ARCH.GEMMA4
|
||||
|
||||
@@ -795,6 +810,7 @@ class Gemma4Model(Gemma3Model):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma4UnifiedForConditionalGeneration")
|
||||
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma4UnifiedForConditionalGeneration")
|
||||
class Gemma4UnifiedModel(Gemma4Model):
|
||||
model_arch = gguf.MODEL_ARCH.GEMMA4
|
||||
|
||||
@@ -815,6 +831,7 @@ class Gemma4UnifiedModel(Gemma4Model):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma4AssistantForCausalLM", "Gemma4UnifiedAssistantForCausalLM")
|
||||
@ModelBase.example("google/gemma-4-31B-it-assistant", "google/gemma-4-26B-A4B-it-assistant", "google/gemma-4-E2B-it-assistant")
|
||||
class Gemma4AssistantModel(Gemma4Model):
|
||||
model_arch = gguf.MODEL_ARCH.GEMMA4_ASSISTANT
|
||||
|
||||
@@ -835,6 +852,7 @@ class Gemma4AssistantModel(Gemma4Model):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma4ForConditionalGeneration")
|
||||
@ModelBase.example("google/gemma-4-31B-it", "google/gemma-4-26B-A4B-it", "google/gemma-4-E2B-it")
|
||||
class Gemma4VisionAudioModel(MmprojModel):
|
||||
has_audio_encoder = True
|
||||
has_vision_encoder = True
|
||||
@@ -913,6 +931,7 @@ class Gemma4VisionAudioModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("Gemma4UnifiedForConditionalGeneration")
|
||||
@ModelBase.example("hf-tiny-v2/tiny-random-Gemma4UnifiedForConditionalGeneration")
|
||||
class Gemma4UnifiedVisionAudioModel(Gemma4VisionAudioModel):
|
||||
has_audio_encoder = True
|
||||
has_vision_encoder = True
|
||||
|
||||
@@ -15,6 +15,7 @@ from .deepseek import DeepseekV2Model
|
||||
|
||||
|
||||
@ModelBase.register("Glm4ForCausalLM", "Glm4vForConditionalGeneration")
|
||||
@ModelBase.example("zai-org/GLM-4-9B-0414")
|
||||
class Glm4Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GLM4
|
||||
use_mrope = False
|
||||
@@ -86,6 +87,7 @@ class Glm4Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("GlmOcrForConditionalGeneration")
|
||||
@ModelBase.example("zai-org/GLM-OCR")
|
||||
class GlmOCRModel(Glm4Model):
|
||||
model_arch = gguf.MODEL_ARCH.GLM4
|
||||
use_mrope = False
|
||||
@@ -107,6 +109,7 @@ class GlmOCRModel(Glm4Model):
|
||||
|
||||
|
||||
@ModelBase.register("Glm4MoeForCausalLM", "Glm4vMoeForConditionalGeneration")
|
||||
@ModelBase.example("zai-org/GLM-4.5-Air")
|
||||
class Glm4MoeModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GLM4_MOE
|
||||
|
||||
@@ -204,6 +207,7 @@ class Glm4MoeModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Glm4MoeLiteForCausalLM")
|
||||
@ModelBase.example("zai-org/GLM-4.7-Flash")
|
||||
class Glm4MoeLiteModel(DeepseekV2Model):
|
||||
model_arch = gguf.MODEL_ARCH.DEEPSEEK2
|
||||
skip_mtp = False
|
||||
@@ -272,6 +276,7 @@ class Glm4MoeLiteModel(DeepseekV2Model):
|
||||
|
||||
|
||||
@ModelBase.register("GlmMoeDsaForCausalLM")
|
||||
@ModelBase.example("zai-org/GLM-5.2")
|
||||
class GlmMoeDsaModel(DeepseekV2Model):
|
||||
model_arch = gguf.MODEL_ARCH.GLM_DSA
|
||||
skip_mtp = False
|
||||
@@ -340,6 +345,7 @@ class GlmMoeDsaModel(DeepseekV2Model):
|
||||
|
||||
|
||||
@ModelBase.register("SolarOpenForCausalLM")
|
||||
@ModelBase.example("upstage/Solar-Open-100B")
|
||||
class SolarOpenModel(Glm4MoeModel):
|
||||
model_arch = gguf.MODEL_ARCH.GLM4_MOE
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("GPT2LMHeadModel")
|
||||
@ModelBase.example("openai-community/gpt2")
|
||||
class GPT2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GPT2
|
||||
|
||||
@@ -38,6 +39,7 @@ class GPT2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("RuGPT3XLForCausalLM")
|
||||
@ModelBase.example("evilfreelancer/ruGPT3XL")
|
||||
class RuGPT3XLModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GPT2
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("GptOssForCausalLM")
|
||||
@ModelBase.example("openai/gpt-oss-20b")
|
||||
class GptOssModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GPT_OSS
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("GPTNeoXForCausalLM")
|
||||
@ModelBase.example("EleutherAI/pythia-70m")
|
||||
class GPTNeoXModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GPTNEOX
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ from .mamba import Mamba2Model
|
||||
|
||||
|
||||
@ModelBase.register("GraniteForCausalLM")
|
||||
@ModelBase.example("ibm-granite/granite-3.3-2b-instruct")
|
||||
class GraniteModel(LlamaModel):
|
||||
"""Conversion for IBM's GraniteForCausalLM"""
|
||||
model_arch = gguf.MODEL_ARCH.GRANITE
|
||||
@@ -74,6 +75,7 @@ class GraniteModel(LlamaModel):
|
||||
|
||||
|
||||
@ModelBase.register("GraniteMoeForCausalLM", "GraniteMoeSharedForCausalLM")
|
||||
@ModelBase.example("ibm-granite/granite-3.1-3b-a800m-instruct")
|
||||
class GraniteMoeModel(GraniteModel):
|
||||
"""Conversion for IBM's GraniteMoeForCausalLM"""
|
||||
model_arch = gguf.MODEL_ARCH.GRANITE_MOE
|
||||
@@ -124,6 +126,7 @@ class GraniteMoeModel(GraniteModel):
|
||||
|
||||
|
||||
@ModelBase.register("GraniteSwitchForCausalLM")
|
||||
@ModelBase.example("ibm-granite/granite-switch-4.1-3b-preview")
|
||||
class GraniteSwitchModel(GraniteMoeModel):
|
||||
"""Dense, all-attention Granite with N per-token embedded LoRA adapters, stacked
|
||||
over the adapter dim with a zero adapter at slot 0 (N = num_adapters + 1)."""
|
||||
@@ -284,6 +287,7 @@ class GraniteSwitchModel(GraniteMoeModel):
|
||||
|
||||
|
||||
@ModelBase.register("GraniteMoeHybridForCausalLM", "BambaForCausalLM")
|
||||
@ModelBase.example("ibm-granite/granite-4.0-h-tiny", "ibm-ai-platform/Bamba-9B-v2")
|
||||
class GraniteHybridModel(Mamba2Model, GraniteMoeModel):
|
||||
"""GraniteHybrid is a hybrid SSM + Attention model that uses Mamba2 SSM
|
||||
layers and optionally uses MoE w/ a shared expert"""
|
||||
@@ -426,6 +430,7 @@ class GraniteHybridModel(Mamba2Model, GraniteMoeModel):
|
||||
|
||||
|
||||
@ModelBase.register("GraniteSpeechForConditionalGeneration")
|
||||
@ModelBase.example("ibm-granite/granite-speech-3.3-2b", "ibm-granite/granite-4.0-1b-speech")
|
||||
class GraniteSpeechMmprojModel(MmprojModel):
|
||||
has_vision_encoder = False
|
||||
has_audio_encoder = True
|
||||
@@ -509,6 +514,7 @@ class GraniteSpeechMmprojModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("GraniteSpeechPlusForConditionalGeneration")
|
||||
@ModelBase.example("ibm-granite/granite-speech-4.1-2b-plus")
|
||||
class GraniteSpeechPlusMmprojModel(GraniteSpeechMmprojModel):
|
||||
"""Conversion for GraniteSpeechPlus - extends GraniteSpeech with feature layer concatenation"""
|
||||
has_vision_encoder = False
|
||||
@@ -537,6 +543,7 @@ class GraniteSpeechPlusMmprojModel(GraniteSpeechMmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("Granite4VisionForConditionalGeneration")
|
||||
@ModelBase.example("ibm-granite/granite-4.0-3b-vision")
|
||||
class Granite4VisionMmprojModel(MmprojModel):
|
||||
has_vision_encoder = True
|
||||
has_audio_encoder = False
|
||||
|
||||
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("GrokForCausalLM", "Grok1ForCausalLM")
|
||||
@ModelBase.example("keyfan/grok-1-hf")
|
||||
class GrokModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GROK
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("GroveMoeForCausalLM", "modeling_grove_moe.GroveMoeForCausalLM")
|
||||
@ModelBase.example("inclusionAI/GroveMoE-Inst")
|
||||
class GroveMoeModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.GROVEMOE
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from .qwen import QwenModel
|
||||
|
||||
|
||||
@ModelBase.register("HunYuanMoEV1ForCausalLM")
|
||||
@ModelBase.example("tencent/Hunyuan-A13B-Instruct")
|
||||
class HunYuanMoEModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.HUNYUAN_MOE
|
||||
|
||||
@@ -154,6 +155,7 @@ class HunYuanMoEModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("HunYuanDenseV1ForCausalLM")
|
||||
@ModelBase.example("tencent/Hunyuan-4B-Instruct")
|
||||
class HunYuanModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.HUNYUAN_DENSE
|
||||
|
||||
@@ -290,6 +292,7 @@ class HunYuanModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("HunYuanVLForConditionalGeneration")
|
||||
@ModelBase.example("tencent/HunyuanOCR")
|
||||
class HunyuanVLVisionModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -333,6 +336,7 @@ class HunyuanVLVisionModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("HunYuanVLForConditionalGeneration")
|
||||
@ModelBase.example("tencent/HunyuanOCR")
|
||||
class HunyuanVLTextModel(HunYuanModel):
|
||||
model_arch = gguf.MODEL_ARCH.HUNYUAN_VL
|
||||
|
||||
@@ -365,6 +369,7 @@ class HunyuanVLTextModel(HunYuanModel):
|
||||
|
||||
|
||||
@ModelBase.register("HYV3ForCausalLM")
|
||||
@ModelBase.example("tencent/Hy3")
|
||||
class HYV3Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.HY_V3
|
||||
supports_mtp_export = True
|
||||
|
||||
@@ -14,6 +14,7 @@ from .llama import LlamaModel
|
||||
|
||||
|
||||
@ModelBase.register("InternLM2ForCausalLM")
|
||||
@ModelBase.example("internlm/internlm2-chat-7b")
|
||||
class InternLM2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.INTERNLM2
|
||||
|
||||
@@ -170,6 +171,7 @@ class InternLM2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("InternLM3ForCausalLM")
|
||||
@ModelBase.example("internlm/internlm3-8b-instruct")
|
||||
class InternLM3Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLAMA
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import MmprojModel, ModelBase, gguf
|
||||
|
||||
|
||||
@ModelBase.register("InternVisionModel")
|
||||
@ModelBase.example("OpenGVLab/InternVL3-2B", "OpenGVLab/InternVL2_5-1B")
|
||||
class InternVisionModel(MmprojModel):
|
||||
|
||||
min_dynamic_tiles: int = 0
|
||||
|
||||
@@ -11,6 +11,8 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("Jais2ForCausalLM")
|
||||
# [TAG_HF_EXAMPLE_GATED] inceptionai/Jais-2-8B-Chat is gated
|
||||
# [TAG_HF_EXAMPLE_MISSING]
|
||||
class Jais2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.JAIS2
|
||||
|
||||
@@ -22,6 +24,7 @@ class Jais2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("JAISLMHeadModel")
|
||||
@ModelBase.example("inceptionai/jais-family-590m")
|
||||
class JaisModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.JAIS
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("JambaForCausalLM")
|
||||
@ModelBase.example("ai21labs/Jamba-v0.1")
|
||||
class JambaModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.JAMBA
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .llama import LlamaModel
|
||||
|
||||
|
||||
@ModelBase.register("JanusForConditionalGeneration")
|
||||
@ModelBase.example("deepseek-community/Janus-Pro-1B")
|
||||
class JanusProModel(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLAMA # reuse Llama arch
|
||||
|
||||
@@ -34,6 +35,7 @@ class JanusProModel(LlamaModel):
|
||||
|
||||
|
||||
@ModelBase.register("JanusForConditionalGeneration")
|
||||
@ModelBase.example("deepseek-community/Janus-Pro-1B")
|
||||
class JanusProVisionModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Callable, Iterable, Iterator, TYPE_CHECKING
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import LazyTorchTensor, ModelBase, TextModel, gguf, logger
|
||||
|
||||
from .kimi_linear import KimiLinearModel
|
||||
|
||||
|
||||
@ModelBase.register("KimiK3ForConditionalGeneration")
|
||||
@ModelBase.example("moonshotai/Kimi-K3")
|
||||
class KimiK3Model(TextModel):
|
||||
"""
|
||||
Kimi-K3 text model (KimiLinearForCausalLM under a `language_model.` prefix).
|
||||
|
||||
Shares the hybrid MLA + KDA skeleton with kimi-linear, but that converter
|
||||
cannot load it: K3 adds cross-layer attention residuals, a latent MoE, the
|
||||
situ activation, an MLA output gate and a full-rank KDA gate.
|
||||
|
||||
The vision tower and mm_projector are skipped - text only for now.
|
||||
"""
|
||||
|
||||
model_arch = gguf.MODEL_ARCH.KIMI_K3
|
||||
|
||||
_experts: list[dict[str, Tensor]] | None = None
|
||||
|
||||
# `<x>_res_norm.weight` and `<x>_res_proj.weight` are only used as their
|
||||
# elementwise product, so they are fused into one [n_embd] vector here.
|
||||
# they arrive apart, so buffer the first one and tag it with its kind.
|
||||
_res_parts: dict[str, tuple[str, Tensor]]
|
||||
|
||||
# HF suffix -> (gguf tensor, per-layer?)
|
||||
_RES_FUSIONS = {
|
||||
"self_attention_res": (gguf.MODEL_TENSOR.ATTN_RES_SCORE, True),
|
||||
"mlp_res": (gguf.MODEL_TENSOR.FFN_RES_SCORE, True),
|
||||
"output_attn_res": (gguf.MODEL_TENSOR.OUTPUT_RES_SCORE, False),
|
||||
}
|
||||
|
||||
# compressed-tensors MXFP4. the `language_model.` prefix is still there, as
|
||||
# self.model_tensors is keyed by the raw checkpoint names
|
||||
_MXFP4_FORMAT = "mxfp4-pack-quantized"
|
||||
_MXFP4_EXPERT_RE = re.compile(
|
||||
r"^(?:language_model\.)?model\.layers\.(\d+)"
|
||||
r"\.block_sparse_moe\.experts\.(\d+)\.(w[123])\.weight_packed$"
|
||||
)
|
||||
_MXFP4_PROJ = {
|
||||
"w1": gguf.MODEL_TENSOR.FFN_GATE_EXP,
|
||||
"w2": gguf.MODEL_TENSOR.FFN_DOWN_EXP,
|
||||
"w3": gguf.MODEL_TENSOR.FFN_UP_EXP,
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._res_parts = {}
|
||||
|
||||
def set_vocab(self):
|
||||
# K3 has the same TikToken vocab as K2, so kimi-linear's vocab handling works.
|
||||
# borrowed, not inherited: the method only touches TextModel members, and K3
|
||||
# shares none of kimi-linear's tensor layout.
|
||||
KimiLinearModel.set_vocab(self) # ty: ignore[invalid-argument-type]
|
||||
|
||||
# ...but that forces eos to the tokenizer's eos_id, which is [EOS], the
|
||||
# document terminator. K3's config says <|end_of_msg|>, the turn terminator;
|
||||
# with [EOS] the generation never stops at the end of a turn.
|
||||
if (eos := self.hparams.get("eos_token_id")) is not None:
|
||||
logger.info(f"restoring configured eos_token_id {eos} (kimi-linear forces the tokenizer's)")
|
||||
self.gguf_writer.add_eos_token_id(eos)
|
||||
|
||||
# K3 renders chats in python (encoding_k3.py) and ships no jinja template,
|
||||
# so add the bundled one when the model has none
|
||||
if gguf.SpecialVocab(self.dir_model, load_merges=False).chat_template is None:
|
||||
template_path = Path(__file__).parent.parent / "models" / "templates" / "Kimi-K3.jinja"
|
||||
logger.info(f"gguf: model has no chat template, using {template_path.name}")
|
||||
self.gguf_writer.add_chat_template(template_path.read_text(encoding="utf-8"))
|
||||
|
||||
#
|
||||
# compressed-tensors MXFP4 -> ggml MXFP4
|
||||
#
|
||||
|
||||
def _is_mxfp4_packed(self) -> bool:
|
||||
quant_config = self.hparams.get("quantization_config") or {}
|
||||
return (quant_config.get("quant_method") == "compressed-tensors"
|
||||
and quant_config.get("format") == self._MXFP4_FORMAT)
|
||||
|
||||
def dequant_model(self):
|
||||
if not self._is_mxfp4_packed():
|
||||
return super().dequant_model()
|
||||
|
||||
# skipping base.py's dequant is only safe if the experts are the only
|
||||
# quantized tensors, so check it
|
||||
stray = [n for n in self.model_tensors
|
||||
if n.endswith(".weight_packed") and not self._MXFP4_EXPERT_RE.match(n)]
|
||||
if stray:
|
||||
raise NotImplementedError(
|
||||
f"{len(stray)} MXFP4 tensor(s) outside the routed experts, e.g. {stray[0]!r}; "
|
||||
"only the routed experts have a repack path"
|
||||
)
|
||||
|
||||
def _mxfp4_expert_tensor(self, loaders: list[tuple[Callable[[], Tensor], Callable[[], Tensor]]]):
|
||||
"""
|
||||
One stacked [n_expert, rows, cols] MXFP4 tensor, built lazily.
|
||||
|
||||
gguf_writer holds every added tensor until the final write, so building
|
||||
this eagerly (like the DeepSeek-V4 path does) keeps all ~1.38 TB of
|
||||
experts in memory. lazy means only the tensor being written is resident.
|
||||
"""
|
||||
# meta shapes, so this does not read any weights
|
||||
rows, packed_cols = loaders[0][0]().shape
|
||||
n_blocks = (packed_cols * 2) // 32
|
||||
byte_shape = (len(loaders), rows, n_blocks * 17)
|
||||
|
||||
def load(fns: list[tuple[Callable[[], Tensor], Callable[[], Tensor]]]) -> np.ndarray:
|
||||
out = np.empty(byte_shape, dtype=np.uint8)
|
||||
for eid, (packed_fn, scale_fn) in enumerate(fns):
|
||||
out[eid] = self.repack_mxfp4_blocks(
|
||||
LazyTorchTensor.to_eager(packed_fn()),
|
||||
LazyTorchTensor.to_eager(scale_fn()),
|
||||
)
|
||||
return out
|
||||
|
||||
# loaders goes through args, not the closure, so that `func` matches
|
||||
# LazyBase's single-argument shape
|
||||
return gguf.LazyNumpyTensor(
|
||||
meta=gguf.LazyNumpyTensor.meta_with_dtype_and_shape(np.uint8, byte_shape),
|
||||
args=(loaders,),
|
||||
func=load,
|
||||
)
|
||||
|
||||
def _write_mxfp4_experts(self) -> None:
|
||||
n_experts = self.hparams["num_experts"]
|
||||
|
||||
# (bid, wid) -> {expert id: (packed name, scale name)}
|
||||
groups: dict[tuple[int, str], dict[int, tuple[str, str]]] = {}
|
||||
for name in self.model_tensors:
|
||||
m = self._MXFP4_EXPERT_RE.match(name)
|
||||
if m is None:
|
||||
continue
|
||||
bid, eid, wid = int(m.group(1)), int(m.group(2)), m.group(3)
|
||||
scale_name = name.removesuffix("_packed") + "_scale"
|
||||
if scale_name not in self.model_tensors:
|
||||
raise KeyError(f"missing {scale_name} for {name}")
|
||||
groups.setdefault((bid, wid), {})[eid] = (name, scale_name)
|
||||
|
||||
consumed: list[str] = []
|
||||
for (bid, wid), experts in sorted(groups.items()):
|
||||
missing = [e for e in range(n_experts) if e not in experts]
|
||||
if missing:
|
||||
raise KeyError(
|
||||
f"layer {bid} {wid}: {len(missing)} of {n_experts} experts missing, "
|
||||
f"first is {missing[0]}"
|
||||
)
|
||||
if len(experts) != n_experts:
|
||||
raise KeyError(f"layer {bid} {wid}: {len(experts)} experts, expected {n_experts}")
|
||||
|
||||
loaders = []
|
||||
for eid in range(n_experts):
|
||||
packed_name, scale_name = experts[eid]
|
||||
loaders.append((self.model_tensors[packed_name], self.model_tensors[scale_name]))
|
||||
consumed += [packed_name, scale_name]
|
||||
|
||||
data = self._mxfp4_expert_tensor(loaders)
|
||||
new_name = self.format_tensor_name(self._MXFP4_PROJ[wid], bid)
|
||||
shape = gguf.quant_shape_from_byte_shape(data.shape, gguf.GGMLQuantizationType.MXFP4)
|
||||
logger.info(
|
||||
f"{new_name}: repacked {n_experts} experts to MXFP4, "
|
||||
f"shape = {{{', '.join(str(n) for n in reversed(shape))}}}"
|
||||
)
|
||||
self.gguf_writer.add_tensor(new_name, data, raw_dtype=gguf.GGMLQuantizationType.MXFP4)
|
||||
|
||||
for name in consumed:
|
||||
del self.model_tensors[name]
|
||||
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
# not a generator on purpose: base.py chains this with get_tensors(), so the
|
||||
# tensors used here must be removed from model_tensors before that starts
|
||||
if self._is_mxfp4_packed():
|
||||
self._write_mxfp4_experts()
|
||||
return ()
|
||||
|
||||
def get_tensors(self) -> Iterator[tuple[str, Tensor]]:
|
||||
for name, data in super().get_tensors():
|
||||
if name.startswith(("vision_tower.", "mm_projector.")):
|
||||
continue # text only
|
||||
if name.startswith("language_model."):
|
||||
name = name[len("language_model."):]
|
||||
yield name, data
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
# MLA is served as MQA with a single large head, then decompressed
|
||||
self.hparams["num_key_value_heads"] = 1
|
||||
|
||||
super().set_gguf_parameters()
|
||||
self.gguf_writer.add_vocab_size(self.hparams["vocab_size"])
|
||||
|
||||
linear_attn_config = self.hparams["linear_attn_config"]
|
||||
|
||||
# n_head_kv == 0 marks a KDA (recurrent) layer. the layer lists are 1-indexed,
|
||||
# as KimiLinearConfig.is_kda_layer uses (layer_idx + 1)
|
||||
full_attn_layers = linear_attn_config["full_attn_layers"]
|
||||
n_kv_heads = [
|
||||
self.hparams["num_key_value_heads"] if (il + 1) in full_attn_layers else 0
|
||||
for il in range(self.hparams["num_hidden_layers"])
|
||||
]
|
||||
assert len(n_kv_heads) == self.hparams["num_hidden_layers"]
|
||||
self.gguf_writer.add_head_count_kv(n_kv_heads)
|
||||
|
||||
# --- KDA ---
|
||||
self.gguf_writer.add_ssm_conv_kernel(linear_attn_config["short_conv_kernel_size"])
|
||||
self.gguf_writer.add_kda_head_dim(linear_attn_config["head_dim"])
|
||||
if (lb := linear_attn_config.get("gate_lower_bound")) is not None:
|
||||
self.gguf_writer.add_kda_gate_lower_bound(lb)
|
||||
|
||||
# --- MLA ---
|
||||
if (q_lora_rank := self.hparams.get("q_lora_rank")) is not None:
|
||||
self.gguf_writer.add_q_lora_rank(q_lora_rank)
|
||||
kv_lora_rank = self.hparams["kv_lora_rank"]
|
||||
self.gguf_writer.add_kv_lora_rank(kv_lora_rank)
|
||||
|
||||
qk_nope_head_dim = self.hparams["qk_nope_head_dim"]
|
||||
qk_rope_head_dim = self.hparams["qk_rope_head_dim"]
|
||||
v_head_dim = self.hparams["v_head_dim"]
|
||||
# K3 is nope-only; qk_rope_head_dim still sizes the un-absorbed part of K
|
||||
assert self.hparams.get("mla_use_nope"), "K3 MLA is expected to be nope-only"
|
||||
self.gguf_writer.add_rope_dimension_count(qk_rope_head_dim)
|
||||
# MLA is served as MQA, so the cache holds the compressed latent
|
||||
self.gguf_writer.add_key_length(kv_lora_rank + qk_rope_head_dim)
|
||||
self.gguf_writer.add_value_length(kv_lora_rank)
|
||||
self.gguf_writer.add_key_length_mla(qk_nope_head_dim + qk_rope_head_dim)
|
||||
self.gguf_writer.add_value_length_mla(v_head_dim)
|
||||
|
||||
# --- MoE ---
|
||||
self.gguf_writer.add_expert_feed_forward_length(self.hparams["moe_intermediate_size"])
|
||||
self.gguf_writer.add_expert_shared_count(self.hparams["num_shared_experts"])
|
||||
self.gguf_writer.add_leading_dense_block_count(self.hparams["first_k_dense_replace"])
|
||||
self.gguf_writer.add_expert_weights_scale(self.hparams["routed_scaling_factor"])
|
||||
self.gguf_writer.add_expert_weights_norm(self.hparams["moe_renormalize"])
|
||||
assert self.hparams["moe_router_activation_func"] == "sigmoid"
|
||||
self.gguf_writer.add_expert_gating_func(gguf.ExpertGatingFuncType.SIGMOID)
|
||||
# latent MoE: routed experts live in a down-projected space
|
||||
if (latent := self.hparams.get("routed_expert_hidden_size")) is not None:
|
||||
self.gguf_writer.add_expert_latent_length(latent)
|
||||
|
||||
# --- situ activation ---
|
||||
assert self.hparams["hidden_act"] == "situ", \
|
||||
f"unexpected hidden_act {self.hparams['hidden_act']!r}"
|
||||
self.gguf_writer.add_activation_situ_beta(self.hparams["activation_situ_beta"])
|
||||
self.gguf_writer.add_activation_situ_linear_beta(self.hparams["activation_situ_linear_beta"])
|
||||
|
||||
# --- cross-layer attention residuals ---
|
||||
self.gguf_writer.add_attn_res_block_size(self.hparams["attn_res_block_size"])
|
||||
|
||||
def prepare_tensors(self):
|
||||
super().prepare_tensors()
|
||||
if self._experts is not None:
|
||||
leftover = [k for d in self._experts for k in d.keys()]
|
||||
if leftover:
|
||||
raise ValueError(f"Unprocessed experts: {leftover}")
|
||||
if self._res_parts:
|
||||
raise ValueError(f"Unpaired attention-residual tensors: {sorted(self._res_parts)}")
|
||||
if self._is_mxfp4_packed():
|
||||
# label the file for what it is; prepare_metadata runs after this
|
||||
self._is_mxfp4 = True
|
||||
self.ftype = gguf.LlamaFileType.MOSTLY_MXFP4_MOE
|
||||
|
||||
def _try_fuse_res(self, data_torch: Tensor, name: str, bid: int | None):
|
||||
"""
|
||||
Pair <x>_res_norm.weight with <x>_res_proj.weight and emit their product.
|
||||
|
||||
Returns None if this is not a res tensor, [] if buffered until its pair.
|
||||
"""
|
||||
for prefix, (tensor_id, per_layer) in self._RES_FUSIONS.items():
|
||||
for kind in ("norm", "proj"):
|
||||
if not name.endswith(f"{prefix}_{kind}.weight"):
|
||||
continue
|
||||
key = f"{prefix}.{bid}"
|
||||
other = self._res_parts.pop(key, None)
|
||||
if other is None:
|
||||
self._res_parts[key] = (kind, data_torch)
|
||||
return []
|
||||
other_kind, other_data = other
|
||||
assert other_kind != kind, f"duplicate {kind} for {key}"
|
||||
norm = data_torch if kind == "norm" else other_data
|
||||
proj = data_torch if kind == "proj" else other_data
|
||||
fused = norm.float().flatten() * proj.float().flatten()
|
||||
# ".weight" suffix matches the convention map_tensor_name applies
|
||||
new_name = (self.format_tensor_name(tensor_id, bid) if per_layer
|
||||
else gguf.TENSOR_NAMES[tensor_id] + ".weight")
|
||||
logger.info(f"fused {prefix}_norm * {prefix}_proj -> {new_name}")
|
||||
return [(new_name, fused)]
|
||||
return None
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
# --- cross-layer attention residuals: fuse norm * proj ---
|
||||
fused = self._try_fuse_res(data_torch, name, bid)
|
||||
if fused is not None:
|
||||
yield from fused
|
||||
return
|
||||
|
||||
# --- KDA conv1d: HF [d_inner, 1, d_conv] -> ggml ne [d_conv, 1, d_inner, 1] ---
|
||||
# GGUF reverses the numpy shape on write, so target numpy (1, d_inner, 1, d_conv).
|
||||
# conv_step varies fastest in both layouts, so this is a pure reshape.
|
||||
if name.endswith((".q_conv1d.weight", ".k_conv1d.weight", ".v_conv1d.weight")):
|
||||
if data_torch.ndim == 3: # [d_inner, 1, d_conv]
|
||||
d_inner, _, d_conv = data_torch.shape
|
||||
elif data_torch.ndim == 2: # [d_inner, d_conv]
|
||||
d_inner, d_conv = data_torch.shape
|
||||
else:
|
||||
raise ValueError(f"unexpected conv1d rank {data_torch.ndim} for {name}")
|
||||
data_torch = data_torch.reshape(1, d_inner, 1, d_conv)
|
||||
|
||||
# -exp(A_log) is folded here so the graph does not have to
|
||||
if name.endswith(".A_log"):
|
||||
n_head = self.hparams["num_attention_heads"]
|
||||
data_torch = -torch.exp(data_torch.float()[:n_head])
|
||||
|
||||
# dt_bias -> the name SSM_DT's mapping expects
|
||||
if name.endswith(".dt_bias"):
|
||||
name = name.rpartition(".dt_bias")[0] + ".dt_proj.bias"
|
||||
|
||||
# --- g_proj is two different tensors sharing one HF name ---
|
||||
# KDA layers: full-rank gate, [d_inner, n_embd] (replaces g_a/g_b)
|
||||
# MLA layers: output gate, [n_head*v_head_dim, n_embd]
|
||||
# Name-based mapping cannot tell them apart, so resolve by layer type.
|
||||
if name.endswith(".self_attn.g_proj.weight"):
|
||||
assert bid is not None
|
||||
is_kda = (bid + 1) not in self.hparams["linear_attn_config"]["full_attn_layers"]
|
||||
tensor_id = gguf.MODEL_TENSOR.SSM_G if is_kda else gguf.MODEL_TENSOR.ATTN_GATE
|
||||
yield self.format_tensor_name(tensor_id, bid), data_torch
|
||||
return
|
||||
|
||||
# --- routed experts: stack per-expert 2D weights into one 3D tensor ---
|
||||
if ".block_sparse_moe.experts." in name:
|
||||
n_experts = self.hparams["num_experts"]
|
||||
assert bid is not None
|
||||
|
||||
if self._experts is None:
|
||||
self._experts = [{} for _ in range(self.block_count)]
|
||||
self._experts[bid][name] = data_torch
|
||||
|
||||
if len(self._experts[bid]) < n_experts * 3:
|
||||
return
|
||||
|
||||
# w1: gate, w2: down, w3: up
|
||||
for wid, tensor_id in (("w1", gguf.MODEL_TENSOR.FFN_GATE_EXP),
|
||||
("w2", gguf.MODEL_TENSOR.FFN_DOWN_EXP),
|
||||
("w3", gguf.MODEL_TENSOR.FFN_UP_EXP)):
|
||||
datas = []
|
||||
for xid in range(n_experts):
|
||||
ename = f"model.layers.{bid}.block_sparse_moe.experts.{xid}.{wid}.weight"
|
||||
datas.append(self._experts[bid].pop(ename))
|
||||
stacked = torch.stack(datas, dim=0)
|
||||
yield from super().modify_tensors(stacked, self.format_tensor_name(tensor_id, bid), bid)
|
||||
return
|
||||
|
||||
# --- MLA absorption: split kv_b into k_b (transposed) and v_b ---
|
||||
if name.endswith("kv_b_proj.weight"):
|
||||
n_head_kv = self.hparams["num_key_value_heads"]
|
||||
v_head_dim = self.hparams["v_head_dim"]
|
||||
qk_nope_head_dim = self.hparams["qk_nope_head_dim"]
|
||||
assert data_torch.shape[0] == n_head_kv * (v_head_dim + qk_nope_head_dim)
|
||||
kv_b = data_torch.view(n_head_kv, v_head_dim + qk_nope_head_dim, data_torch.shape[-1])
|
||||
k_b, v_b = torch.split(kv_b, [qk_nope_head_dim, v_head_dim], dim=1)
|
||||
k_b = k_b.transpose(1, 2)
|
||||
yield from super().modify_tensors(k_b, name.replace("kv_b_proj", "k_b_proj"), bid)
|
||||
yield from super().modify_tensors(v_b, name.replace("kv_b_proj", "v_b_proj"), bid)
|
||||
return
|
||||
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
@@ -13,6 +13,7 @@ from .qwen import QwenModel
|
||||
|
||||
|
||||
@ModelBase.register("KimiLinearModel", "KimiLinearForCausalLM")
|
||||
@ModelBase.example("moonshotai/Kimi-Linear-48B-A3B-Instruct")
|
||||
class KimiLinearModel(TextModel):
|
||||
"""Kimi-Linear model with hybrid MLA+KDA architecture"""
|
||||
model_arch = gguf.MODEL_ARCH.KIMI_LINEAR
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import MmprojModel, ModelBase, gguf
|
||||
|
||||
|
||||
@ModelBase.register("KimiVLForConditionalGeneration")
|
||||
@ModelBase.example("moonshotai/Kimi-VL-A3B-Instruct")
|
||||
class KimiVLModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -52,6 +53,7 @@ class KimiVLModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("KimiK25ForConditionalGeneration")
|
||||
@ModelBase.example("moonshotai/Kimi-K2.5")
|
||||
class KimiK25Model(MmprojModel):
|
||||
"""Kimi-K2.5 with MoonViT3d vision encoder"""
|
||||
|
||||
@@ -155,6 +157,7 @@ class KimiK25Model(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("Glm5vForConditionalGeneration")
|
||||
# [TAG_HF_EXAMPLE_MISSING]
|
||||
class Glm5vModel(KimiK25Model):
|
||||
"""GLM-5.2-Vision MoonViT3d encoder and projector
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("LagunaForCausalLM")
|
||||
@ModelBase.example("poolside/Laguna-XS.2", "poolside/Laguna-S-2.1")
|
||||
class LagunaModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LAGUNA
|
||||
_experts: list[dict] | None = None
|
||||
|
||||
@@ -13,6 +13,7 @@ from .gemma import ConformerAudioModel
|
||||
|
||||
|
||||
@ModelBase.register("Lfm2ForCausalLM", "LFM2ForCausalLM")
|
||||
@ModelBase.example("LiquidAI/LFM2-1.2B", "LiquidAI/LFM2.5-350M")
|
||||
class LFM2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LFM2
|
||||
|
||||
@@ -65,6 +66,7 @@ class LFM2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Lfm2Model", "Lfm2BidirectionalModel")
|
||||
@ModelBase.example("LiquidAI/LFM2.5-ColBERT-350M", "LiquidAI/LFM2.5-Embedding-350M")
|
||||
class LFM2ColBertModel(LFM2Model):
|
||||
model_arch = gguf.MODEL_ARCH.LFM2
|
||||
dense_tensor_name = "dense_2"
|
||||
@@ -93,6 +95,7 @@ class LFM2ColBertModel(LFM2Model):
|
||||
|
||||
|
||||
@ModelBase.register("Lfm2MoeForCausalLM")
|
||||
@ModelBase.example("LiquidAI/LFM2-8B-A1B")
|
||||
class LFM2MoeModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LFM2MOE
|
||||
|
||||
@@ -166,6 +169,7 @@ class LFM2MoeModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Lfm2VlForConditionalGeneration")
|
||||
@ModelBase.example("LiquidAI/LFM2-VL-450M")
|
||||
class LFM2VLModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -200,6 +204,7 @@ class LFM2VLModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("Lfm2AudioForConditionalGeneration")
|
||||
@ModelBase.example("LiquidAI/LFM2.5-Audio-1.5B", "LiquidAI/LFM2-Audio-1.5B")
|
||||
class LFM2AudioModel(ConformerAudioModel):
|
||||
has_vision_encoder = False
|
||||
has_audio_encoder = True
|
||||
@@ -238,6 +243,7 @@ class LFM2AudioModel(ConformerAudioModel):
|
||||
|
||||
|
||||
@ModelBase.register("Lfm25AudioTokenizer")
|
||||
@ModelBase.example("LiquidAI/LFM2.5-Audio-1.5B")
|
||||
class LFM25AudioTokenizer(LFM2Model):
|
||||
model_arch = gguf.MODEL_ARCH.LFM2
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .llava import LlavaVisionModel
|
||||
|
||||
|
||||
@ModelBase.register("LightOnOCRForConditionalGeneration")
|
||||
@ModelBase.example("lightonai/LightOnOCR-1B-1025")
|
||||
class LightOnOCRVisionModel(LlavaVisionModel):
|
||||
is_mistral_format = False
|
||||
use_break_tok = False
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("LLaDAModelLM")
|
||||
@ModelBase.example("GSAI-ML/LLaDA-8B-Instruct")
|
||||
class LLaDAModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLADA
|
||||
undo_permute = True
|
||||
@@ -114,6 +115,7 @@ class LLaDAModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("LLaDAMoEModel", "LLaDAMoEModelLM")
|
||||
@ModelBase.example("inclusionAI/LLaDA-MoE-7B-A1B-Instruct")
|
||||
class LLaDAMoEModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLADA_MOE
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
"Eagle3DraftModel",
|
||||
"IQuestCoderForCausalLM",
|
||||
"LlamaModel")
|
||||
# [TAG_HF_EXAMPLE_GATED] meta-llama/Llama-3.2-1B-Instruct is gated
|
||||
@ModelBase.example("unsloth/Llama-3.2-1B-Instruct", "mistralai/Mistral-7B-Instruct-v0.3", "mistralai/Mixtral-8x7B-Instruct-v0.1")
|
||||
class LlamaModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLAMA
|
||||
undo_permute = True
|
||||
@@ -359,6 +361,7 @@ class LlamaModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("ArceeForCausalLM")
|
||||
@ModelBase.example("arcee-ai/AFM-4.5B")
|
||||
class ArceeModel(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.ARCEE
|
||||
|
||||
@@ -371,6 +374,8 @@ class ArceeModel(LlamaModel):
|
||||
"Llama4ForConditionalGeneration",
|
||||
"Llama4ForCausalLM",
|
||||
)
|
||||
# [TAG_HF_EXAMPLE_GATED] meta-llama/Llama-4-Scout-17B-16E-Instruct is gated
|
||||
@ModelBase.example("unsloth/Llama-4-Scout-17B-16E-Instruct")
|
||||
class Llama4Model(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLAMA4
|
||||
undo_permute = False
|
||||
@@ -412,16 +417,19 @@ class Llama4Model(LlamaModel):
|
||||
|
||||
|
||||
@ModelBase.register("LlamaBidirectionalModel")
|
||||
@ModelBase.example("nvidia/llama-embed-nemotron-8b")
|
||||
class LlamaEmbedNemotronModel(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLAMA_EMBED
|
||||
|
||||
|
||||
@ModelBase.register("SmolLM3ForCausalLM")
|
||||
@ModelBase.example("HuggingFaceTB/SmolLM3-3B")
|
||||
class SmolLM3Model(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.SMOLLM3
|
||||
|
||||
|
||||
@ModelBase.register("ApertusForCausalLM")
|
||||
@ModelBase.example("swiss-ai/Apertus-8B-Instruct-2509")
|
||||
class ApertusModel(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.APERTUS
|
||||
undo_permute = False
|
||||
|
||||
@@ -9,6 +9,8 @@ from .base import MmprojModel, ModelBase, gguf
|
||||
|
||||
|
||||
@ModelBase.register("Llama4ForConditionalGeneration")
|
||||
# [TAG_HF_EXAMPLE_GATED] meta-llama/Llama-4-Scout-17B-16E-Instruct is gated
|
||||
@ModelBase.example("unsloth/Llama-4-Scout-17B-16E-Instruct")
|
||||
class Llama4VisionModel(MmprojModel):
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
|
||||
@@ -16,6 +16,7 @@ from .llama import LlamaModel
|
||||
"LlavaForConditionalGeneration", # pixtral
|
||||
"Mistral3ForConditionalGeneration", # mistral small 3.1
|
||||
)
|
||||
@ModelBase.example("mistral-community/pixtral-12b", "mistralai/Mistral-Small-3.1-24B-Instruct-2503")
|
||||
class LlavaVisionModel(MmprojModel):
|
||||
img_break_tok_id = -1
|
||||
use_break_tok = True
|
||||
|
||||
@@ -4,6 +4,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("MaincoderForCausalLM")
|
||||
@ModelBase.example("Maincode/Maincoder-1B")
|
||||
class MaincoderModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MAINCODER
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("MambaForCausalLM", "MambaLMHeadModel", "FalconMambaForCausalLM")
|
||||
@ModelBase.example("state-spaces/mamba-130m-hf", "tiiuae/falcon-mamba-7b")
|
||||
class MambaModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MAMBA
|
||||
|
||||
@@ -100,6 +101,7 @@ class MambaModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Mamba2ForCausalLM")
|
||||
@ModelBase.example("mistralai/Mamba-Codestral-7B-v0.1")
|
||||
class Mamba2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MAMBA2
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("MellumForCausalLM")
|
||||
@ModelBase.example("JetBrains/Mellum2-12B-A2.5B-Base")
|
||||
class MellumModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MELLUM
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ from .base import MmprojModel, ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("MiMoV2FlashForCausalLM", "MiMoV2ForCausalLM")
|
||||
@ModelBase.example("XiaomiMiMo/MiMo-V2.5")
|
||||
class MimoV2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MIMO2
|
||||
|
||||
@@ -230,6 +231,7 @@ class MimoV2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("MiMoV2ForCausalLM")
|
||||
@ModelBase.example("XiaomiMiMo/MiMo-V2.5")
|
||||
class MiMoV2VisionAudioModel(MmprojModel):
|
||||
has_audio_encoder = True
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ from .qwen import Qwen3_5TextModel
|
||||
|
||||
|
||||
@ModelBase.register("MiniCPMForCausalLM")
|
||||
@ModelBase.example("openbmb/MiniCPM-2B-sft-bf16")
|
||||
class MiniCPMModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MINICPM
|
||||
|
||||
@@ -61,6 +62,7 @@ class MiniCPMModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("MiniCPM3ForCausalLM")
|
||||
@ModelBase.example("openbmb/MiniCPM3-4B")
|
||||
class MiniCPM3Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MINICPM3
|
||||
|
||||
@@ -117,6 +119,7 @@ class MiniCPM3Model(TextModel):
|
||||
# the LM (text mode) and once as the mmproj (vision mode), mirroring the Qwen3-VL setup.
|
||||
|
||||
@ModelBase.register("MiniCPMV4_6ForConditionalGeneration")
|
||||
@ModelBase.example("openbmb/MiniCPM-V-4_6")
|
||||
class MiniCPMV4_6TextModel(Qwen3_5TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN35
|
||||
|
||||
@@ -134,6 +137,7 @@ class MiniCPMV4_6TextModel(Qwen3_5TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("MiniCPMV4_6ForConditionalGeneration")
|
||||
@ModelBase.example("openbmb/MiniCPM-V-4_6")
|
||||
class MiniCPMV4_6VisionModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -12,6 +12,7 @@ from .base import ModelBase, TextModel, MmprojModel, gguf, logger
|
||||
|
||||
@ModelBase.register("MiniMaxText01ForCausalLM")
|
||||
@ModelBase.register("MiniMaxM1ForCausalLM")
|
||||
@ModelBase.example("MiniMaxAI/MiniMax-Text-01", "MiniMaxAI/MiniMax-M1-40k")
|
||||
class MiniMaxText01Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MINIMAX01
|
||||
|
||||
@@ -119,6 +120,7 @@ class MiniMaxText01Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("MiniMaxM2ForCausalLM")
|
||||
@ModelBase.example("MiniMaxAI/MiniMax-M2")
|
||||
class MiniMaxM2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MINIMAXM2
|
||||
_experts_cache: dict[int, dict[str, Tensor]] = {}
|
||||
@@ -163,6 +165,7 @@ class MiniMaxM2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("MiniMaxM3SparseForCausalLM", "MiniMaxM3SparseForConditionalGeneration")
|
||||
@ModelBase.example("MiniMaxAI/MiniMax-M3")
|
||||
class MiniMaxM3Model(MiniMaxM2Model):
|
||||
model_arch = gguf.MODEL_ARCH.MINIMAXM3
|
||||
|
||||
@@ -203,6 +206,7 @@ class MiniMaxM3Model(MiniMaxM2Model):
|
||||
|
||||
|
||||
@ModelBase.register("MiniMaxM3SparseForConditionalGeneration", "MiniMaxM3VLForConditionalGeneration")
|
||||
@ModelBase.example("MiniMaxAI/MiniMax-M3")
|
||||
class MiniMaxM3VisionModel(MmprojModel):
|
||||
@classmethod
|
||||
def filter_tensors(cls, item):
|
||||
|
||||
@@ -15,6 +15,7 @@ from .llama import LlamaModel
|
||||
"Mistral3ForConditionalGeneration",
|
||||
"Ministral3ForCausalLM",
|
||||
)
|
||||
@ModelBase.example("mistralai/Mistral-Small-3.1-24B-Instruct-2503", "hf-tiny-v2/tiny-random-Ministral3ForCausalLM")
|
||||
class Mistral3Model(TextModel):
|
||||
class Ministral3Model(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.MISTRAL3
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("MPTForCausalLM")
|
||||
@ModelBase.example("anas-awadalla/mpt-7b")
|
||||
class MPTModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MPT
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ def _unpermute_for_rope(tensor: "Tensor", n_heads: int) -> "Tensor":
|
||||
|
||||
|
||||
@ModelBase.register("MuseGlimmerForConditionalGeneration")
|
||||
@ModelBase.example("meta-models/Muse-Glimmer-30B")
|
||||
class MuseGlimmerModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.MUSE_GLIMMER
|
||||
|
||||
@@ -78,6 +79,7 @@ class MuseGlimmerModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("MuseGlimmerForConditionalGeneration")
|
||||
@ModelBase.example("meta-models/Muse-Glimmer-30B")
|
||||
class MuseGlimmerVisionModel(MmprojModel):
|
||||
def get_vision_config(self) -> dict[str, Any] | None:
|
||||
c = self.global_config.get("vision_config")
|
||||
@@ -131,6 +133,7 @@ class MuseGlimmerVisionModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("MuseGlimmerAssistantModel")
|
||||
@ModelBase.example("meta-models/Muse-Glimmer-30B-assistant")
|
||||
class MuseGlimmerAssistantModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.DFLASH
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ from .llama import LlamaModel
|
||||
|
||||
|
||||
@ModelBase.register("NanbeigeForCausalLM")
|
||||
@ModelBase.example("Nanbeige/Nanbeige4.2-3B")
|
||||
class NanbeigeModel(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.NANBEIGE
|
||||
undo_permute = True
|
||||
|
||||
@@ -16,6 +16,7 @@ from .granite import GraniteHybridModel
|
||||
"NemotronH_Nano_VL_V2",
|
||||
"RADIOModel",
|
||||
)
|
||||
@ModelBase.example("nvidia/NVIDIA-Nemotron-Nano-12B-v2-VL-BF16")
|
||||
class NemotronNanoV2VLModel(MmprojModel):
|
||||
# ViT-Huge architecture parameters for RADIO v2.5-h
|
||||
_vit_hidden_size = 1280
|
||||
@@ -151,6 +152,7 @@ class NemotronNanoV2VLModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("NemotronForCausalLM")
|
||||
@ModelBase.example("nvidia/Minitron-4B-Base")
|
||||
class NemotronModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.NEMOTRON
|
||||
|
||||
@@ -193,6 +195,7 @@ class NemotronModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("NemotronHForCausalLM")
|
||||
@ModelBase.example("nvidia/Nemotron-H-8B-Base-8K")
|
||||
class NemotronHModel(GraniteHybridModel):
|
||||
"""Hybrid mamba2/attention model from NVIDIA"""
|
||||
model_arch = gguf.MODEL_ARCH.NEMOTRON_H
|
||||
|
||||
@@ -14,6 +14,7 @@ from .llama import LlamaModel
|
||||
|
||||
@ModelBase.register("OlmoForCausalLM")
|
||||
@ModelBase.register("OLMoForCausalLM")
|
||||
@ModelBase.example("allenai/OLMo-1.7-7B-hf")
|
||||
class OlmoModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.OLMO
|
||||
|
||||
@@ -39,12 +40,14 @@ class OlmoModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("SeedOssForCausalLM")
|
||||
@ModelBase.example("ByteDance-Seed/Seed-OSS-36B-Instruct")
|
||||
class SeedOssModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.SEED_OSS
|
||||
|
||||
|
||||
@ModelBase.register("Olmo2ForCausalLM")
|
||||
@ModelBase.register("Olmo3ForCausalLM")
|
||||
@ModelBase.example("allenai/OLMo-2-1124-7B-Instruct", "allenai/Olmo-3-7B-Instruct")
|
||||
class Olmo2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.OLMO2
|
||||
|
||||
@@ -67,6 +70,7 @@ class Olmo2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("OlmoeForCausalLM")
|
||||
@ModelBase.example("allenai/OLMoE-1B-7B-0924")
|
||||
class OlmoeModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.OLMOE
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("OpenELMForCausalLM")
|
||||
@ModelBase.example("apple/OpenELM-270M")
|
||||
class OpenELMModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.OPENELM
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("OrionForCausalLM")
|
||||
@ModelBase.example("OrionStarAI/Orion-14B-Base")
|
||||
class OrionModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.ORION
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("PanguEmbeddedForCausalLM")
|
||||
@ModelBase.example("FreedomIntelligence/openPangu-Embedded-7B-V1.1")
|
||||
class PanguEmbeddedModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.PANGU_EMBED
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ from .base import MmprojModel, ModelBase, SentencePieceTokenTypes, TextModel, gg
|
||||
|
||||
|
||||
@ModelBase.register("PhiForCausalLM")
|
||||
@ModelBase.example("microsoft/phi-2")
|
||||
class Phi2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.PHI2
|
||||
|
||||
@@ -36,6 +37,7 @@ class Phi2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Phi3ForCausalLM", "Phi4ForCausalLMV")
|
||||
@ModelBase.example("microsoft/Phi-3-mini-4k-instruct")
|
||||
class Phi3MiniModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.PHI3
|
||||
|
||||
@@ -210,6 +212,7 @@ class Phi3MiniModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Phi4ForCausalLMV")
|
||||
# [TAG_HF_EXAMPLE_MISSING]
|
||||
class Phi4VisionMmprojModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -336,6 +339,7 @@ class Phi4VisionMmprojModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("PhiMoEForCausalLM")
|
||||
@ModelBase.example("microsoft/Phi-3.5-MoE-instruct")
|
||||
class PhiMoeModel(Phi3MiniModel):
|
||||
model_arch = gguf.MODEL_ARCH.PHIMOE
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("PlamoForCausalLM")
|
||||
@ModelBase.example("pfnet/plamo-13b")
|
||||
class PlamoModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.PLAMO
|
||||
|
||||
@@ -58,6 +59,7 @@ class PlamoModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Plamo2ForCausalLM", "PLaMo2ForCausalLM")
|
||||
@ModelBase.example("pfnet/plamo-2-1b")
|
||||
class Plamo2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.PLAMO2
|
||||
|
||||
@@ -147,6 +149,8 @@ class Plamo2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Plamo3ForCausalLM", "PLaMo3ForCausalLM")
|
||||
# [TAG_HF_EXAMPLE_GATED] pfnet/plamo-3-nict-2b-base is gated
|
||||
@ModelBase.example("midorin-Linux/plamo-3-12b-self-merged-base")
|
||||
class Plamo3Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.PLAMO3
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("PLMForCausalLM")
|
||||
@ModelBase.example("PLM-Team/PLM-1.8B-Instruct")
|
||||
class PLMModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.PLM
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ def _load_hparams(dir_model: Path) -> dict[str, Any]:
|
||||
|
||||
|
||||
@ModelBase.register("PocketTTSModel")
|
||||
# [TAG_HF_EXAMPLE_MISSING] model is gated, and the checkpoint requires cd to subdir, not supported here
|
||||
class PocketTTSModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.POCKETTTS
|
||||
|
||||
@@ -174,6 +175,7 @@ class PocketTTSModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("PocketTTSModel")
|
||||
# [TAG_HF_EXAMPLE_MISSING] model is gated, and the checkpoint requires cd to subdir, not supported here
|
||||
class PocketTTSMmprojModel(MmprojModel):
|
||||
has_audio_encoder = True
|
||||
has_vision_encoder = False
|
||||
|
||||
+84
-12
@@ -4,15 +4,17 @@ import json
|
||||
|
||||
from typing import Any, Callable, Iterable, TYPE_CHECKING
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import ModelBase, TextModel, gguf, logger
|
||||
from .base import LazyTorchTensor, ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("QWenLMHeadModel")
|
||||
@ModelBase.example("Qwen/Qwen-7B")
|
||||
class QwenModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN
|
||||
|
||||
@@ -51,6 +53,7 @@ class QwenModel(TextModel):
|
||||
"AudioFlamingo3ForConditionalGeneration",
|
||||
"DotsOCRForCausalLM",
|
||||
)
|
||||
@ModelBase.example("Qwen/Qwen2.5-7B-Instruct")
|
||||
class Qwen2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN2
|
||||
|
||||
@@ -71,6 +74,7 @@ class Qwen2Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen2MoeForCausalLM")
|
||||
@ModelBase.example("Qwen/Qwen1.5-MoE-A2.7B")
|
||||
class Qwen2MoeModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN2MOE
|
||||
|
||||
@@ -153,6 +157,7 @@ class Qwen2MoeModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3ForCausalLM", "Qwen3Model")
|
||||
@ModelBase.example("Qwen/Qwen3-8B")
|
||||
class Qwen3Model(Qwen2Model):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3
|
||||
|
||||
@@ -251,6 +256,7 @@ class Qwen3Model(Qwen2Model):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3MoeForCausalLM")
|
||||
@ModelBase.example("Qwen/Qwen3-30B-A3B")
|
||||
class Qwen3MoeModel(Qwen2MoeModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3MOE
|
||||
|
||||
@@ -362,6 +368,7 @@ class _QwenMtpMixin:
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3NextForCausalLM")
|
||||
@ModelBase.example("Qwen/Qwen3-Next-80B-A3B-Instruct")
|
||||
class Qwen3NextModel(_QwenMtpMixin, Qwen2MoeModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3NEXT
|
||||
|
||||
@@ -421,6 +428,7 @@ class Qwen3NextModel(_QwenMtpMixin, Qwen2MoeModel):
|
||||
|
||||
|
||||
@ModelBase.register("RND1")
|
||||
@ModelBase.example("radicalnumerics/RND1-Base-0910")
|
||||
class RND1Model(Qwen2MoeModel):
|
||||
model_arch = gguf.MODEL_ARCH.RND1
|
||||
|
||||
@@ -620,16 +628,19 @@ class _Qwen35MRopeMixin:
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3_5ForConditionalGeneration", "Qwen3_5ForCausalLM")
|
||||
@ModelBase.example("Qwen/Qwen3.5-9B")
|
||||
class Qwen3_5TextModel(_Qwen35MRopeMixin, _LinearAttentionVReorderBase):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN35
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3_5MoeForConditionalGeneration", "Qwen3_5MoeForCausalLM")
|
||||
@ModelBase.example("Qwen/Qwen3.5-35B-A3B")
|
||||
class Qwen3_5MoeTextModel(_Qwen35MRopeMixin, _LinearAttentionVReorderBase):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN35MOE
|
||||
|
||||
|
||||
@ModelBase.register("DFlashDraftModel")
|
||||
@ModelBase.example("z-lab/Qwen3.5-9B-DFlash")
|
||||
class DFlashModel(Qwen3Model):
|
||||
model_arch = gguf.MODEL_ARCH.DFLASH
|
||||
|
||||
@@ -698,21 +709,82 @@ class DFlashModel(Qwen3Model):
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3DSparkModel")
|
||||
@ModelBase.register("Qwen3DSparkModel", "DSparkDraftModel", "DSparkSpeculator")
|
||||
@ModelBase.example("satgeze/Qwen3.6-27B-DSpark")
|
||||
class DSparkModel(DFlashModel):
|
||||
# DSpark = DFlash + a semi-autoregressive Markov head
|
||||
# DSpark = DFlash + a semi-autoregressive Markov head.
|
||||
model_arch = gguf.MODEL_ARCH.DFLASH
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# normalize the flat DeepSpec schema to DFlash's nested dflash_config
|
||||
self.hparams.setdefault("dflash_config", {
|
||||
k: self.hparams[k] for k in ("target_layer_ids", "mask_token_id") if k in self.hparams
|
||||
})
|
||||
def __init__(self, dir_model, *args, **kwargs):
|
||||
hparams = kwargs.pop("hparams", None)
|
||||
if hparams is None:
|
||||
hparams = ModelBase.load_hparams(dir_model, False)
|
||||
|
||||
# EAGLE3-style exports use the 1+N bonus-anchor block, DFlash-lineage exports sample from the anchor
|
||||
self._sample_from_anchor = hparams.get(
|
||||
"sample_from_anchor",
|
||||
"transformer_layer_config" not in hparams and "aux_hidden_state_layer_ids" not in hparams)
|
||||
if "transformer_layer_config" in hparams:
|
||||
hparams = {**hparams, **hparams["transformer_layer_config"]}
|
||||
|
||||
super().__init__(dir_model, *args, hparams=hparams, **kwargs)
|
||||
|
||||
# normalize both schemas to DFlash's nested dflash_config
|
||||
if "aux_hidden_state_layer_ids" in self.hparams:
|
||||
self.hparams.setdefault("dflash_config", {
|
||||
"mask_token_id": self.hparams.get("mask_token_id"),
|
||||
"target_layer_ids": [i - 1 for i in self.hparams["aux_hidden_state_layer_ids"]],
|
||||
})
|
||||
else:
|
||||
self.hparams.setdefault("dflash_config", {
|
||||
k: self.hparams[k] for k in ("target_layer_ids", "mask_token_id") if k in self.hparams
|
||||
})
|
||||
|
||||
if (markov_head_type := self.hparams.get("markov_head_type", "vanilla")) != "vanilla":
|
||||
raise ValueError(f"unsupported markov_head_type {markov_head_type!r} (only 'vanilla' is supported)")
|
||||
|
||||
n_vocab = self.hparams["vocab_size"]
|
||||
self._n_vocab_draft = self.hparams.get("draft_vocab_size") or n_vocab
|
||||
if self._n_vocab_draft > n_vocab:
|
||||
raise ValueError(f"draft_vocab_size {self._n_vocab_draft} exceeds vocab_size {n_vocab}")
|
||||
self._d2t: Tensor | None = None
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
self.gguf_writer.add_sample_from_anchor(self._sample_from_anchor)
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
name, gen = item
|
||||
if name.endswith(("embed_tokens.weight", "lm_head.weight")):
|
||||
if item[0] == "t2d": # not used at runtime
|
||||
return None
|
||||
return super().filter_tensors((name, gen))
|
||||
return super().filter_tensors(item)
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
if name == "model.d2t":
|
||||
self._d2t = data_torch
|
||||
return
|
||||
|
||||
if self._n_vocab_draft == self.hparams["vocab_size"] and name.endswith(("embed_tokens.weight", "lm_head.weight")):
|
||||
return
|
||||
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
def prepare_tensors(self):
|
||||
super().prepare_tensors()
|
||||
|
||||
n_vocab = self.hparams["vocab_size"]
|
||||
if self._n_vocab_draft < n_vocab and self._d2t is None:
|
||||
raise ValueError(f"draft_vocab_size {self._n_vocab_draft} < vocab_size {n_vocab} but no d2t table found")
|
||||
|
||||
# write d2t as absolute target token ids
|
||||
if self._d2t is not None:
|
||||
data = LazyTorchTensor.to_eager(self._d2t).to(torch.int64).cpu().numpy().reshape(-1)
|
||||
if data.size != self._n_vocab_draft:
|
||||
raise ValueError(f"d2t size {data.size} does not match draft_vocab_size {self._n_vocab_draft}")
|
||||
data = data + np.arange(data.size, dtype=np.int64)
|
||||
if np.any((data < 0) | (data >= n_vocab)):
|
||||
raise ValueError(f"d2t target ids out of range for target vocab size {n_vocab}")
|
||||
if np.unique(data).size != data.size:
|
||||
raise ValueError("d2t contains duplicate target ids")
|
||||
logger.info(f"{'d2t,':<30} --> I64, shape = {{{data.size}}}")
|
||||
self.gguf_writer.add_tensor("d2t", data, raw_dtype=gguf.GGMLQuantizationType.I64)
|
||||
|
||||
@@ -37,6 +37,7 @@ _ACT2FN = {
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3TTSForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-TTS-12Hz-1.7B-Base")
|
||||
class Qwen3TTSTalkerModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3TTS
|
||||
|
||||
@@ -185,6 +186,7 @@ class Qwen3TTSTalkerModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3TTSForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-TTS-12Hz-1.7B-Base")
|
||||
class Qwen3TTSSpeakerEncoderModel(MmprojModel):
|
||||
has_vision_encoder = False
|
||||
has_audio_encoder = True
|
||||
|
||||
@@ -14,6 +14,7 @@ from .qwenvl import Qwen25AudioModel
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3VLForConditionalGeneration", "Qwen3VLMoeForConditionalGeneration", "Qwen3_5ForConditionalGeneration", "Qwen3_5MoeForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-VL-4B-Instruct", "Qwen/Qwen3-VL-30B-A3B-Instruct", "Qwen/Qwen3.5-9B", "Qwen/Qwen3.5-35B-A3B")
|
||||
class Qwen3VLVisionModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -144,6 +145,7 @@ class Qwen3VLVisionModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3OmniMoeForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-Omni-30B-A3B-Instruct")
|
||||
class Qwen3OmniMmprojModel(Qwen3VLVisionModel, Qwen25AudioModel):
|
||||
has_audio_encoder = True
|
||||
has_vision_encoder = True
|
||||
@@ -217,12 +219,14 @@ class Qwen3OmniMmprojModel(Qwen3VLVisionModel, Qwen25AudioModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3ASRForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-ASR-0.6B-hf")
|
||||
class Qwen3ASRMmprojModel(Qwen3OmniMmprojModel):
|
||||
has_audio_encoder = True
|
||||
has_vision_encoder = False
|
||||
|
||||
|
||||
@ModelBase.register("Glm4vForConditionalGeneration", "Glm4vMoeForConditionalGeneration", "GlmOcrForConditionalGeneration")
|
||||
@ModelBase.example("zai-org/GLM-4.1V-9B-Thinking", "zai-org/GLM-4.5V")
|
||||
class Glm4VVisionModel(Qwen3VLVisionModel):
|
||||
def set_gguf_parameters(self):
|
||||
MmprojModel.set_gguf_parameters(self) # skip Qwen3VLVisionModel parameters
|
||||
@@ -246,6 +250,7 @@ class Glm4VVisionModel(Qwen3VLVisionModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3VLForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-VL-4B-Instruct")
|
||||
class Qwen3VLTextModel(Qwen3Model):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3VL
|
||||
|
||||
@@ -268,6 +273,7 @@ class Qwen3VLTextModel(Qwen3Model):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3VLMoeForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-VL-30B-A3B-Instruct")
|
||||
class Qwen3VLMoeTextModel(Qwen3MoeModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3VLMOE
|
||||
|
||||
@@ -317,6 +323,7 @@ class Qwen3VLMoeTextModel(Qwen3MoeModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3OmniMoeForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-Omni-30B-A3B-Instruct")
|
||||
class Qwen3OmniMoeTextModel(Qwen3VLMoeTextModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3VLMOE
|
||||
|
||||
@@ -338,6 +345,7 @@ class Qwen3OmniMoeTextModel(Qwen3VLMoeTextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3ASRForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-ASR-0.6B-hf")
|
||||
class Qwen3ASRTextModel(Qwen3VLTextModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3VL
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from .base import MmprojModel, ModelBase, TextModel, gguf
|
||||
"Qwen2_5_VLForConditionalGeneration",
|
||||
"Qwen2_5OmniModel",
|
||||
)
|
||||
@ModelBase.example("Qwen/Qwen2-VL-2B-Instruct", "Qwen/Qwen2.5-VL-3B-Instruct")
|
||||
class Qwen2VLModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN2VL
|
||||
|
||||
@@ -40,6 +41,7 @@ class Qwen2VLModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen2VLModel", "Qwen2VLForConditionalGeneration", "Qwen2_5_VLForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen2-VL-2B-Instruct", "Qwen/Qwen2.5-VL-3B-Instruct")
|
||||
class Qwen2VLVisionModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -161,6 +163,7 @@ class Qwen25AudioModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen2_5OmniModel")
|
||||
@ModelBase.example("Qwen/Qwen2.5-Omni-3B")
|
||||
class Qwen25OmniModel(Qwen2VLVisionModel, Qwen25AudioModel):
|
||||
has_audio_encoder = True
|
||||
has_vision_encoder = True
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("GPTRefactForCausalLM")
|
||||
@ModelBase.example("smallcloudai/Refact-1_6-base")
|
||||
class RefactModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.REFACT
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("Rwkv6ForCausalLM")
|
||||
@ModelBase.example("RWKV/v6-Finch-1B6-HF")
|
||||
class Rwkv6Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.RWKV6
|
||||
|
||||
@@ -83,6 +84,7 @@ class Rwkv6Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("RWKV6Qwen2ForCausalLM")
|
||||
@ModelBase.example("recursal/QRWKV6-32B-Instruct-Preview-v0.1")
|
||||
class RWKV6Qwen2Model(Rwkv6Model):
|
||||
model_arch = gguf.MODEL_ARCH.RWKV6QWEN2
|
||||
|
||||
@@ -136,6 +138,7 @@ class RWKV6Qwen2Model(Rwkv6Model):
|
||||
|
||||
|
||||
@ModelBase.register("Rwkv7ForCausalLM", "RWKV7ForCausalLM")
|
||||
@ModelBase.example("fla-hub/rwkv7-1.5B-world")
|
||||
class Rwkv7Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.RWKV7
|
||||
|
||||
@@ -261,6 +264,7 @@ class Rwkv7Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("RwkvHybridForCausalLM")
|
||||
@ModelBase.example("RWKV-Red-Team/ARWKV-7B-Preview-0.1")
|
||||
class ARwkv7Model(Rwkv7Model):
|
||||
model_arch = gguf.MODEL_ARCH.ARWKV7
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from .qwenvl import Qwen2VLVisionModel
|
||||
|
||||
|
||||
@ModelBase.register("Sarashina2VisionForCausalLM")
|
||||
@ModelBase.example("sbintuitions/sarashina2.2-vision-3b")
|
||||
class Sarashina2VLTextModel(LlamaModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLAMA
|
||||
|
||||
@@ -26,6 +27,7 @@ class Sarashina2VLTextModel(LlamaModel):
|
||||
|
||||
|
||||
@ModelBase.register("Sarashina2VisionForCausalLM")
|
||||
@ModelBase.example("sbintuitions/sarashina2.2-vision-3b")
|
||||
class Sarashina2VLVisionModel(Qwen2VLVisionModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("SmallThinkerForCausalLM")
|
||||
@ModelBase.example("PowerInfer/SmallThinker-4BA0.6B-Instruct")
|
||||
class SmallThinkerModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.SMALLTHINKER
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import MmprojModel, ModelBase, gguf
|
||||
|
||||
|
||||
@ModelBase.register("Idefics3ForConditionalGeneration", "SmolVLMForConditionalGeneration")
|
||||
@ModelBase.example("HuggingFaceTB/SmolVLM-Instruct", "HuggingFaceM4/Idefics3-8B-Llama3")
|
||||
class SmolVLMModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("StableLmForCausalLM", "StableLMEpochForCausalLM", "LlavaStableLMEpochForCausalLM")
|
||||
@ModelBase.example("stabilityai/stablelm-2-1_6b")
|
||||
class StableLMModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.STABLELM
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("GPTBigCodeForCausalLM")
|
||||
@ModelBase.example("bigcode/gpt_bigcode-santacoder")
|
||||
class StarCoderModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.STARCODER
|
||||
|
||||
@@ -19,5 +20,6 @@ class StarCoderModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("Starcoder2ForCausalLM")
|
||||
@ModelBase.example("bigcode/starcoder2-3b")
|
||||
class StarCoder2Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.STARCODER2
|
||||
|
||||
@@ -16,6 +16,7 @@ from .qwen import Qwen3Model
|
||||
|
||||
|
||||
@ModelBase.register("StepVLForConditionalGeneration", "Step3p7ForConditionalGeneration")
|
||||
@ModelBase.example("stepfun-ai/Step3-VL-10B", "stepfun-ai/Step-3.7-Flash")
|
||||
class Step3VLVisionModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -91,11 +92,13 @@ class Step3VLVisionModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("StepVLForConditionalGeneration")
|
||||
@ModelBase.example("stepfun-ai/Step3-VL-10B")
|
||||
class Step3VLTextModel(Qwen3Model):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3
|
||||
|
||||
|
||||
@ModelBase.register("Step3p5ForCausalLM", "Step3p7ForConditionalGeneration")
|
||||
@ModelBase.example("stepfun-ai/Step-3.7-Flash")
|
||||
class Step35Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.STEP35
|
||||
supports_mtp_export = True
|
||||
|
||||
@@ -16,6 +16,7 @@ from .base import ModelBase, SentencePieceTokenTypes, TextModel, gguf, logger
|
||||
@ModelBase.register("MT5ForConditionalGeneration")
|
||||
@ModelBase.register("UMT5ForConditionalGeneration")
|
||||
@ModelBase.register("UMT5Model")
|
||||
@ModelBase.example("google-t5/t5-small", "google/flan-t5-small", "google/umt5-small")
|
||||
class T5Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.T5
|
||||
|
||||
@@ -153,6 +154,7 @@ class T5Model(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("T5EncoderModel")
|
||||
@ModelBase.example("sentence-transformers/sentence-t5-base")
|
||||
class T5EncoderModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.T5ENCODER
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import LazyTorchTensor, ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("TalkieForCausalLM")
|
||||
@ModelBase.example("lewtun/talkie-1930-13b-it-hf")
|
||||
class TalkieModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.TALKIE
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import MmprojModel, ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("UltravoxModel")
|
||||
@ModelBase.example("fixie-ai/ultravox-v0_5-llama-3_2-1b")
|
||||
class UltravoxModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLAMA # dummy
|
||||
|
||||
@@ -18,6 +19,7 @@ class UltravoxModel(TextModel):
|
||||
|
||||
|
||||
@ModelBase.register("GlmasrModel")
|
||||
@ModelBase.example("zai-org/GLM-ASR-Nano-2512")
|
||||
class GlmASRWhisperEncoderModel(MmprojModel):
|
||||
has_vision_encoder = False
|
||||
has_audio_encoder = True
|
||||
@@ -82,6 +84,7 @@ class GlmASRWhisperEncoderModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("Qwen2AudioForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen2-Audio-7B-Instruct")
|
||||
class WhisperEncoderModel(MmprojModel):
|
||||
has_vision_encoder = False # no vision encoder
|
||||
has_audio_encoder = True
|
||||
@@ -123,6 +126,7 @@ class WhisperEncoderModel(MmprojModel):
|
||||
|
||||
|
||||
@ModelBase.register("UltravoxModel")
|
||||
@ModelBase.example("fixie-ai/ultravox-v0_5-llama-3_2-1b")
|
||||
class UltravoxWhisperEncoderModel(WhisperEncoderModel):
|
||||
has_vision_encoder = False # no vision encoder
|
||||
has_audio_encoder = True
|
||||
@@ -134,6 +138,7 @@ class UltravoxWhisperEncoderModel(WhisperEncoderModel):
|
||||
|
||||
|
||||
@ModelBase.register("MERaLiON2ForConditionalGeneration")
|
||||
@ModelBase.example("MERaLiON/MERaLiON-2-3B")
|
||||
class MERaLiONWhisperEncoderModel(WhisperEncoderModel):
|
||||
has_vision_encoder = False
|
||||
has_audio_encoder = True
|
||||
@@ -180,6 +185,7 @@ class MERaLiONWhisperEncoderModel(WhisperEncoderModel):
|
||||
|
||||
|
||||
@ModelBase.register("VoxtralForConditionalGeneration")
|
||||
@ModelBase.example("mistralai/Voxtral-Mini-3B-2507")
|
||||
class VoxtralWhisperEncoderModel(WhisperEncoderModel):
|
||||
has_vision_encoder = False # no vision encoder
|
||||
has_audio_encoder = True
|
||||
@@ -191,6 +197,7 @@ class VoxtralWhisperEncoderModel(WhisperEncoderModel):
|
||||
|
||||
|
||||
@ModelBase.register("AudioFlamingo3ForConditionalGeneration")
|
||||
@ModelBase.example("nvidia/audio-flamingo-3-hf")
|
||||
class AudioFlamingo3WhisperEncoderModel(WhisperEncoderModel):
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("WavTokenizerDec")
|
||||
@ModelBase.example("novateur/WavTokenizer-large-speech-75token")
|
||||
class WavTokenizerDecModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.WAVTOKENIZER_DEC
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("XverseForCausalLM")
|
||||
@ModelBase.example("xverse/XVERSE-7B")
|
||||
class XverseModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.XVERSE
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from .base import MmprojModel, ModelBase, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("YoutuVLForConditionalGeneration")
|
||||
@ModelBase.example("tencent/Youtu-VL-4B-Instruct")
|
||||
class YoutuVLVisionModel(MmprojModel):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -428,13 +428,13 @@ Examples:
|
||||
- Use device 0:
|
||||
|
||||
```sh
|
||||
ZES_ENABLE_SYSMAN=1 ./build/bin/llama-completion -no-cnv -m models/llama-2-7b.Q4_0.gguf -p "Building a website can be done in 10 simple steps:" -n 400 -e -ngl 99 -sm none -mg 0 --mmap
|
||||
ZES_ENABLE_SYSMAN=1 ./build/bin/llama-completion -no-cnv -m models/llama-2-7b.Q4_0.gguf -p "Building a website can be done in 10 simple steps:" -n 400 -e -ngl 99 -sm none -mg 0 --load-mode auto
|
||||
```
|
||||
|
||||
- Use multiple devices:
|
||||
|
||||
```sh
|
||||
ZES_ENABLE_SYSMAN=1 ./build/bin/llama-completion -no-cnv -m models/llama-2-7b.Q4_0.gguf -p "Building a website can be done in 10 simple steps:" -n 400 -e -ngl 99 -sm layer --mmap
|
||||
ZES_ENABLE_SYSMAN=1 ./build/bin/llama-completion -no-cnv -m models/llama-2-7b.Q4_0.gguf -p "Building a website can be done in 10 simple steps:" -n 400 -e -ngl 99 -sm layer --load-mode auto
|
||||
```
|
||||
|
||||
*Notes:*
|
||||
@@ -741,13 +741,13 @@ Examples:
|
||||
- Use device 0:
|
||||
|
||||
```
|
||||
build\bin\llama-completion.exe -no-cnv -m models\llama-2-7b.Q4_0.gguf -p "Building a website can be done in 10 simple steps:\nStep 1:" -n 400 -e -ngl 99 -sm none -mg 0 --mmap
|
||||
build\bin\llama-completion.exe -no-cnv -m models\llama-2-7b.Q4_0.gguf -p "Building a website can be done in 10 simple steps:\nStep 1:" -n 400 -e -ngl 99 -sm none -mg 0 --load-mode auto
|
||||
```
|
||||
|
||||
- Use multiple devices:
|
||||
|
||||
```
|
||||
build\bin\llama-completion.exe -no-cnv -m models\llama-2-7b.Q4_0.gguf -p "Building a website can be done in 10 simple steps:\nStep 1:" -n 400 -e -ngl 99 -sm layer --mmap
|
||||
build\bin\llama-completion.exe -no-cnv -m models\llama-2-7b.Q4_0.gguf -p "Building a website can be done in 10 simple steps:\nStep 1:" -n 400 -e -ngl 99 -sm layer --load-mode auto
|
||||
```
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user