Instructions to use AlexWortega/SIQ-1-35B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use AlexWortega/SIQ-1-35B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="AlexWortega/SIQ-1-35B") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("AlexWortega/SIQ-1-35B") model = AutoModelForCausalLM.from_pretrained("AlexWortega/SIQ-1-35B") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - llama-cpp-python
How to use AlexWortega/SIQ-1-35B with llama-cpp-python:
# !pip install llama-cpp-python from llama_cpp import Llama llm = Llama.from_pretrained( repo_id="AlexWortega/SIQ-1-35B", filename="gguf/SIQ-1-35B-MTP.Q6_K.gguf", )
llm.create_chat_completion( messages = [ { "role": "user", "content": "What is the capital of France?" } ] ) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use AlexWortega/SIQ-1-35B with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf AlexWortega/SIQ-1-35B:Q4_K_M # Run inference directly in the terminal: llama cli -hf AlexWortega/SIQ-1-35B:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf AlexWortega/SIQ-1-35B:Q4_K_M # Run inference directly in the terminal: llama cli -hf AlexWortega/SIQ-1-35B:Q4_K_M
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf AlexWortega/SIQ-1-35B:Q4_K_M # Run inference directly in the terminal: ./llama-cli -hf AlexWortega/SIQ-1-35B:Q4_K_M
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf AlexWortega/SIQ-1-35B:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama-cli -hf AlexWortega/SIQ-1-35B:Q4_K_M
Use Docker
docker model run hf.co/AlexWortega/SIQ-1-35B:Q4_K_M
- LM Studio
- Jan
- vLLM
How to use AlexWortega/SIQ-1-35B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "AlexWortega/SIQ-1-35B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "AlexWortega/SIQ-1-35B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/AlexWortega/SIQ-1-35B:Q4_K_M
- SGLang
How to use AlexWortega/SIQ-1-35B with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "AlexWortega/SIQ-1-35B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "AlexWortega/SIQ-1-35B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "AlexWortega/SIQ-1-35B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "AlexWortega/SIQ-1-35B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Ollama
How to use AlexWortega/SIQ-1-35B with Ollama:
ollama run hf.co/AlexWortega/SIQ-1-35B:Q4_K_M
- Unsloth Studio
How to use AlexWortega/SIQ-1-35B with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for AlexWortega/SIQ-1-35B to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for AlexWortega/SIQ-1-35B to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for AlexWortega/SIQ-1-35B to start chatting
- Pi
How to use AlexWortega/SIQ-1-35B with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf AlexWortega/SIQ-1-35B:Q4_K_M
Configure the model in Pi
# Install Pi: npm install -g @mariozechner/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "AlexWortega/SIQ-1-35B:Q4_K_M" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Hermes Agent new
How to use AlexWortega/SIQ-1-35B with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf AlexWortega/SIQ-1-35B:Q4_K_M
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default AlexWortega/SIQ-1-35B:Q4_K_M
Run Hermes
hermes
- Atomic Chat new
- OpenClaw new
How to use AlexWortega/SIQ-1-35B with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf AlexWortega/SIQ-1-35B:Q4_K_M
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "AlexWortega/SIQ-1-35B:Q4_K_M" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
- Docker Model Runner
How to use AlexWortega/SIQ-1-35B with Docker Model Runner:
docker model run hf.co/AlexWortega/SIQ-1-35B:Q4_K_M
- Lemonade
How to use AlexWortega/SIQ-1-35B with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull AlexWortega/SIQ-1-35B:Q4_K_M
Run and chat with the model
lemonade run user.SIQ-1-35B-Q4_K_M
List all available models
lemonade list
MTP head integration
Recipe in https://huggingface.co/AlexWortega/SIQ-1-35B/discussions/2 was somewhat broken for me.
so, I use steps 1-2, then different script (it quantizes most of the sidecar weights to Q8_0):
#!/usr/bin/env python3
"""
merge_mtp_gguf.py β Merge an MTP (Multi-Token Prediction) sidecar GGUF into a base GGUF model.
This script was developed for Qwen3.6-MoE (e.g. SIQ-1-35B-APEX) to attach an MTP layer
(block 40) from a sidecar file to a quantized base model, preserving the base model's
quantization while re-quantizing MTP tensors to optimal types for inference speed.
Key features:
1. Preserves base model tensor quantization (raw bytes, no dequantization).
2. Splits fused ffn_gate_up_exps into separate ffn_gate_exps + ffn_up_exps.
3. Updates metadata: block_count, nextn_predict_layers, vocab_size.
4. Re-quantizes MTP tensors: heavy weights β Q8_0/BF16, norms β F32 (for SYCL compatibility).
Usage:
python merge_mtp_gguf.py base.gguf mtp.gguf output.gguf
Requirements:
pip install gguf numpy
Author: Kimi (Moonshot AI) β 2026-06-30
"""
import sys
import argparse
import numpy as np
from pathlib import Path
from gguf import GGUFWriter, GGMLQuantizationType, GGUFValueType
from gguf.gguf_reader import GGUFReader
from gguf.quants import quantize, dequantize, QuantError
def to_py_shape(shape):
"""Convert numpy shape to tuple of native Python ints.
struct.pack chokes on np.int64, so we cast everything to int().
"""
return tuple(int(x) for x in shape)
def read_gguf(path):
"""Read a GGUF file and return (reader, metadata_dict, tensors_dict).
Uses field.contents() instead of field.parts[field.data[0]] because the
latter only returns the first element for arrays (e.g. rope.dimension_sections
would come back as length-1 instead of length-4).
"""
reader = GGUFReader(path)
metadata = {}
for key, field in reader.fields.items():
metadata[key] = field.contents()
tensors = {}
for tensor in reader.tensors:
tensors[tensor.name] = {
'data': tensor.data,
'shape': to_py_shape(tensor.shape), # physical shape from file header
'data_shape': to_py_shape(tensor.data.shape), # logical shape (reversed dims; byte-shape for quantized)
'tensor_type': tensor.tensor_type,
'n_bytes': tensor.n_bytes,
'n_elements': tensor.n_elements,
}
return reader, metadata, tensors
def get_arch(meta):
"""Decode architecture string from metadata (handles bytes, ndarray, str)."""
arch = meta.get('general.architecture', '')
if isinstance(arch, bytes):
return arch.decode('utf-8')
elif isinstance(arch, np.ndarray):
if arch.dtype == object:
return str(arch[0])
return bytes(arch).decode('utf-8')
return str(arch)
def get_int(meta, key, default=0):
"""Extract an integer value from metadata."""
val = meta.get(key, default)
if isinstance(val, (list, tuple, np.ndarray)):
return int(val[0]) if len(val) > 0 else default
return int(val)
def get_str(meta, key, default=''):
"""Extract a string value from metadata."""
val = meta.get(key, default)
if isinstance(val, bytes):
return val.decode('utf-8')
return str(val)
def copy_metadata(writer, reader, skip_keys=None):
"""Copy all KV pairs from reader to writer with proper type conversion.
Skips system keys (GGUF.*) and keys that the writer will set manually.
"""
skip_keys = skip_keys or set()
for key, field in reader.fields.items():
if key in skip_keys:
continue
val = field.contents()
vtype = field.types[0]
if vtype == GGUFValueType.STRING:
if val:
writer.add_string(key, val)
elif vtype == GGUFValueType.ARRAY:
if len(val) > 0:
writer.add_array(key, val)
elif vtype == GGUFValueType.UINT8:
writer.add_uint8(key, val)
elif vtype == GGUFValueType.INT8:
writer.add_int8(key, val)
elif vtype == GGUFValueType.UINT16:
writer.add_uint16(key, val)
elif vtype == GGUFValueType.INT16:
writer.add_int16(key, val)
elif vtype == GGUFValueType.UINT32:
writer.add_uint32(key, val)
elif vtype == GGUFValueType.INT32:
writer.add_int32(key, val)
elif vtype == GGUFValueType.FLOAT32:
writer.add_float32(key, val)
elif vtype == GGUFValueType.BOOL:
writer.add_bool(key, val)
elif vtype == GGUFValueType.UINT64:
writer.add_uint64(key, val)
elif vtype == GGUFValueType.INT64:
writer.add_int64(key, val)
elif vtype == GGUFValueType.FLOAT64:
writer.add_float64(key, val)
def verify_compatibility(base_meta, mtp_meta, arch):
"""Check that base and MTP models have matching hyperparameters."""
critical_checks = [
("embedding_length", f"{arch}.embedding_length"),
("expert_count", f"{arch}.expert_count"),
("expert_feed_forward_length", f"{arch}.expert_feed_forward_length"),
("attention.head_count", f"{arch}.attention.head_count"),
("attention.head_count_kv", f"{arch}.attention.head_count_kv"),
("attention.key_length", f"{arch}.attention.key_length"),
("attention.value_length", f"{arch}.attention.value_length"),
]
all_ok = True
for label, key in critical_checks:
base_val = get_int(base_meta, key)
mtp_val = get_int(mtp_meta, key)
status = "OK" if base_val == mtp_val else "MISMATCH"
if base_val != mtp_val:
all_ok = False
print(f" {status} {label}: base={base_val}, mtp={mtp_val}")
vocab_key = f"{arch}.vocab_size"
base_vocab = get_int(base_meta, vocab_key, 0)
mtp_vocab = get_int(mtp_meta, vocab_key, 0)
if base_vocab == 0 and mtp_vocab > 0:
print(f" INFO vocab_size missing in base, using mtp: {mtp_vocab}")
elif base_vocab != mtp_vocab and mtp_vocab > 0:
print(f" WARN vocab_size differs: base={base_vocab}, mtp={mtp_vocab}")
else:
print(f" OK vocab_size: {base_vocab}")
return all_ok
def split_gate_up(gate_up_data):
"""Split fused ffn_gate_up_exps into separate gate and up tensors.
gate_up shape: [H, 2*I, E] = [2048, 1024, 256]
gate: [H, I, E] = [2048, 512, 256] β first half along dim 1
up: [H, I, E] = [2048, 512, 256] β second half along dim 1
"""
assert gate_up_data.shape[1] == 1024, f"Expected dim 1 = 1024, got {gate_up_data.shape[1]}"
gate = gate_up_data[:, :512, :]
up = gate_up_data[:, 512:, :]
return gate, up
# ---------------------------------------------------------------------------
# Quantization mapping for MTP tensors
# Heavy weights β Q8_0 or BF16 for speed
# Norms (1D/2D) β F32 for SYCL backend compatibility
# (SYCL ggml_sycl_op_bin_bcast does not support f16 + f32 broadcast)
# ---------------------------------------------------------------------------
MTP_QUANT_MAP = {
'attn_k.weight': GGMLQuantizationType.Q8_0,
'attn_q.weight': GGMLQuantizationType.Q8_0,
'attn_v.weight': GGMLQuantizationType.Q8_0,
'attn_output.weight': GGMLQuantizationType.Q8_0,
'ffn_down_exps.weight': GGMLQuantizationType.Q8_0,
'ffn_gate_exps.weight': GGMLQuantizationType.Q8_0,
'ffn_up_exps.weight': GGMLQuantizationType.Q8_0,
'ffn_gate_inp.weight': GGMLQuantizationType.BF16,
'ffn_gate_inp_shexp.weight': GGMLQuantizationType.BF16,
'ffn_down_shexp.weight': GGMLQuantizationType.Q8_0,
'ffn_gate_shexp.weight': GGMLQuantizationType.Q8_0,
'ffn_up_shexp.weight': GGMLQuantizationType.Q8_0,
'nextn.eh_proj.weight': GGMLQuantizationType.Q8_0,
# Norms β F32 (SYCL broadcast compatibility)
'nextn.enorm.weight': GGMLQuantizationType.F32,
'nextn.hnorm.weight': GGMLQuantizationType.F32,
'nextn.shared_head_norm.weight': GGMLQuantizationType.F32,
'attn_norm.weight': GGMLQuantizationType.F32,
'attn_q_norm.weight': GGMLQuantizationType.F32,
'attn_k_norm.weight': GGMLQuantizationType.F32,
'post_attention_norm.weight': GGMLQuantizationType.F32,
}
def quantize_mtp_tensor(data, src_type, target_type):
"""Re-quantize an MTP tensor from src_type to target_type.
Steps:
1. Dequantize to float32 (if needed)
2. Quantize to target_type via gguf.quants.quantize()
Falls back to src_type if quantization fails.
"""
if src_type == target_type:
return data, target_type
# Step 1: dequantize to float32
if src_type == GGMLQuantizationType.F16:
f32_data = data.astype(np.float32)
elif src_type == GGMLQuantizationType.F32:
f32_data = data
elif src_type == GGMLQuantizationType.BF16:
f32_data = dequantize(data, src_type)
else:
f32_data = dequantize(data, src_type)
# Step 2: quantize to target
try:
qdata = quantize(f32_data, target_type)
return qdata, target_type
except (QuantError, NotImplementedError) as e:
print(f" WARN quantize to {target_type.name} failed: {e}, keeping {src_type.name}")
return data, src_type
def get_target_quant(name):
"""Look up the target quantization type for an MTP tensor by its short name."""
short_name = name.split('.', 2)[-1] if name.count('.') >= 2 else name
return MTP_QUANT_MAP.get(short_name)
def merge_mtp(base_path, mtp_path, out_path):
print(f"[1/8] Reading base model: {base_path}")
base_reader, base_meta, base_tensors = read_gguf(base_path)
print(f" Tensors: {len(base_tensors)}")
print(f"[2/8] Reading MTP sidecar: {mtp_path}")
mtp_reader, mtp_meta, mtp_tensors = read_gguf(mtp_path)
print(f" Tensors: {len(mtp_tensors)}")
base_arch = get_arch(base_meta)
mtp_arch = get_arch(mtp_meta)
print(f"[3/8] Architecture: base={base_arch}, mtp={mtp_arch}")
if base_arch != mtp_arch:
print(f" FAIL architectures do not match!")
sys.exit(1)
print(f"[4/8] Checking compatibility...")
if not verify_compatibility(base_meta, mtp_meta, base_arch):
print(f" FAIL critical parameters mismatch!")
sys.exit(1)
print(f" OK models are compatible")
block_key = f"{base_arch}.block_count"
base_blocks = get_int(base_meta, block_key)
mtp_blocks = get_int(mtp_meta, block_key)
print(f"[5/8] block_count: base={base_blocks}, mtp={mtp_blocks}")
if mtp_blocks != base_blocks + 1:
print(f" WARN expected block_count={base_blocks + 1}, got {mtp_blocks}")
writer = GGUFWriter(out_path, base_arch)
print(f"[6/8] Copying metadata...")
skip = {
"GGUF.version",
"GGUF.tensor_count",
"GGUF.kv_count",
"general.architecture", # GGUFWriter sets this in __init__
block_key,
f"{base_arch}.nextn_predict_layers",
f"{base_arch}.vocab_size",
"general.file_type",
"general.name",
}
copy_metadata(writer, base_reader, skip)
new_blocks = base_blocks + 1
writer.add_uint32(block_key, new_blocks)
print(f" {block_key}: {base_blocks} β {new_blocks}")
nextn_key = f"{base_arch}.nextn_predict_layers"
nextn_val = get_int(mtp_meta, nextn_key)
if nextn_val == 0:
nextn_val = 1
writer.add_uint32(nextn_key, nextn_val)
print(f" {nextn_key}: 0 β {nextn_val}")
vocab_key = f"{base_arch}.vocab_size"
base_vocab = get_int(base_meta, vocab_key, 0)
mtp_vocab = get_int(mtp_meta, vocab_key, 0)
if base_vocab == 0 and mtp_vocab > 0:
writer.add_uint32(vocab_key, mtp_vocab)
print(f" {vocab_key}: added from MTP: {mtp_vocab}")
elif base_vocab > 0:
writer.add_uint32(vocab_key, base_vocab)
print(f" {vocab_key}: {base_vocab} (from base)")
base_ftype = get_int(base_meta, "general.file_type")
writer.add_uint32("general.file_type", base_ftype)
print(f" general.file_type: {base_ftype}")
base_name = get_str(base_meta, "general.name", "Merged Model")
writer.add_string("general.name", f"{base_name} + MTP")
print(f" general.name: {base_name} + MTP")
print(f"[7/8] Writing tensors...")
# 7a. Copy all base tensors (preserve their quantization)
base_count = 0
for name, info in base_tensors.items():
writer.add_tensor(name, info['data'], raw_shape=info['data_shape'],
raw_dtype=info['tensor_type'])
base_count += 1
print(f" From base model: {base_count} (quantization preserved)")
# 7b. Add MTP tensors for block 40
mtp_count = 0
skipped = 0
gate_up_split = 0
quant_count = 0
for name, info in mtp_tensors.items():
if name in base_tensors:
print(f" SKIP duplicate: {name}")
skipped += 1
continue
# Split fused gate_up into separate gate + up
if 'ffn_gate_up_exps' in name:
gate_data, up_data = split_gate_up(info['data'])
gate_name = name.replace('ffn_gate_up_exps', 'ffn_gate_exps')
up_name = name.replace('ffn_gate_up_exps', 'ffn_up_exps')
gate_target = MTP_QUANT_MAP.get('ffn_gate_exps.weight')
up_target = MTP_QUANT_MAP.get('ffn_up_exps.weight')
gate_data, gate_type = quantize_mtp_tensor(gate_data, info['tensor_type'], gate_target)
up_data, up_type = quantize_mtp_tensor(up_data, info['tensor_type'], up_target)
writer.add_tensor(gate_name, gate_data, raw_shape=to_py_shape(gate_data.shape),
raw_dtype=gate_type)
writer.add_tensor(up_name, up_data, raw_shape=to_py_shape(up_data.shape),
raw_dtype=up_type)
if gate_type != info['tensor_type']:
quant_count += 1
print(f" OK {name} β split into {gate_name} ({gate_type.name}) + {up_name} ({up_type.name})")
gate_up_split += 1
mtp_count += 2
continue
# Other MTP tensors
if name.startswith(f'blk.{base_blocks}.'):
target_type = get_target_quant(name)
if target_type is not None:
data, tensor_type = quantize_mtp_tensor(info['data'], info['tensor_type'], target_type)
if tensor_type != info['tensor_type']:
quant_count += 1
else:
data, tensor_type = info['data'], info['tensor_type']
writer.add_tensor(name, data, raw_shape=to_py_shape(data.shape),
raw_dtype=tensor_type)
mtp_count += 1
print(f" From MTP model: {mtp_count} (including {gate_up_split} split gate/up)")
print(f" Re-quantized: {quant_count}")
print(f" Duplicates skipped: {skipped}")
print(f" Total tensors: {base_count + mtp_count}")
nextn_list = [n for n in mtp_tensors if '.nextn.' in n]
if nextn_list:
print(f" NextN tensors added: {len(nextn_list)}")
print(f"[8/8] Writing file...")
writer.write_header_to_file()
writer.write_kv_data_to_file()
writer.write_tensors_to_file()
writer.close()
print(f"\n[DONE] Output: {out_path}")
print(f" Size: {Path(out_path).stat().st_size / 1024**3:.2f} GB")
def main():
parser = argparse.ArgumentParser(
description='Merge an MTP GGUF sidecar into a base GGUF model (Qwen3.6-MoE)'
)
parser.add_argument('base', help='Base GGUF model (e.g. SIQ-1-35B)')
parser.add_argument('mtp', help='MTP GGUF sidecar (19 tensors, block 40)')
parser.add_argument('output', help='Output merged file')
args = parser.parse_args()
merge_mtp(args.base, args.mtp, args.output)
if __name__ == '__main__':
main()
Hope it helps someone as it helped me