Text Generation
Safetensors
GGUF
English
tenaos
gemma
llama.cpp
lora
qlora
clinical
openmrs
conversational
Instructions to use beza4588/TenaOS with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use beza4588/TenaOS 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 beza4588/TenaOS:BF16 # Run inference directly in the terminal: llama cli -hf beza4588/TenaOS:BF16
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf beza4588/TenaOS:BF16 # Run inference directly in the terminal: llama cli -hf beza4588/TenaOS:BF16
Build from source code
git clone https://github.com/ggml-org/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-app # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama serve -hf beza4588/TenaOS:BF16 # Run inference directly in the terminal: ./build/bin/llama cli -hf beza4588/TenaOS:BF16
Use Docker
docker model run hf.co/beza4588/TenaOS:BF16
- Llama new
- LM Studio
- Jan
- vLLM
How to use beza4588/TenaOS with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "beza4588/TenaOS" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "beza4588/TenaOS", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/beza4588/TenaOS:BF16
- Ollama
How to use beza4588/TenaOS with Ollama:
ollama run hf.co/beza4588/TenaOS:BF16
- Unsloth Desktop
- Pi
How to use beza4588/TenaOS with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf beza4588/TenaOS:BF16
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "beza4588/TenaOS:BF16" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use beza4588/TenaOS with Docker Model Runner:
docker model run hf.co/beza4588/TenaOS:BF16
- Lemonade
How to use beza4588/TenaOS with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull beza4588/TenaOS:BF16
Run and chat with the model
lemonade run user.TenaOS-BF16
List all available models
lemonade list
- Hermes Agent
How to use beza4588/TenaOS with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf beza4588/TenaOS:BF16
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 beza4588/TenaOS:BF16
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use beza4588/TenaOS with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf beza4588/TenaOS:BF16
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 "beza4588/TenaOS:BF16" \ --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"
File size: 5,975 Bytes
b150582 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | #!/usr/bin/env python3
"""Merge a LoRA checkpoint into the Gemma 4 E4B base model.
Merges LoRA deltas directly into the base model's state dict (rather than
reconstructing a PeftModel via peft.PeftModel.from_pretrained), because the
adapter's auto-generated `target_modules` regex also matches the vision
tower's Gemma4ClippableLinear wrapper modules, which peft's standard tuner
injection does not support and raises on. Manual state-dict merging sidesteps
that entirely and is also simpler to verify.
Verified (see checkpoint audit): every vision_tower.* lora_B tensor in the
adapter is exactly all-zero -- expected, since training never passed images
through the vision tower (finetune_vision_layers=False, text-only corpus), so
those slots never received gradient. This script only merges
language_model.* deltas; vision and the multi-modal projector are left as
pure base-model weights, byte-identical to upstream.
Runs on GPU by default (there is normally ample headroom alongside a training
run, and merging is a handful of quick matmuls, not sustained compute -- it
does not meaningfully compete with a concurrent training job). Pass
--device cpu to run without touching the GPU at all.
"""
from __future__ import annotations
import argparse
import json
import re
from pathlib import Path
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--adapter-dir", type=Path, required=True, help="Path to a LoRA checkpoint directory.")
parser.add_argument("--base-model", default=None, help="Override base model id (default: read from adapter_config.json).")
parser.add_argument("--output-dir", type=Path, required=True)
parser.add_argument("--device", default="cuda", choices=["cuda", "cpu"])
args = parser.parse_args()
import torch
from safetensors import safe_open
from safetensors.torch import load_file as load_safetensors
from transformers import AutoModelForImageTextToText, AutoProcessor
adapter_config = json.loads((args.adapter_dir / "adapter_config.json").read_text())
base_model_id = args.base_model or adapter_config["base_model_name_or_path"]
lora_r = adapter_config["r"]
lora_alpha = adapter_config["lora_alpha"]
scale = lora_alpha / lora_r
print(f"Base model: {base_model_id}")
print(f"Adapter: {args.adapter_dir}")
print(f"LoRA r={lora_r} alpha={lora_alpha} scale={scale} dropout={adapter_config['lora_dropout']}")
print(f"Device: {args.device}")
args.output_dir.mkdir(parents=True, exist_ok=True)
adapter_path = args.adapter_dir / "adapter_model.safetensors"
with safe_open(str(adapter_path), framework="pt") as f:
adapter_keys = list(f.keys())
lora_a_keys = [k for k in adapter_keys if k.endswith(".lora_A.weight") and ".language_model." in k]
vision_keys = [k for k in adapter_keys if ".vision_tower." in k or ".multi_modal_projector." in k]
print(f"Adapter tensors total: {len(adapter_keys)}")
print(f" language_model lora_A/B pairs to merge: {len(lora_a_keys)}")
print(f" vision/projector tensors present but SKIPPED (verified all-zero, untrained): {len(vision_keys)}")
print(f"Loading base model in bf16 on {args.device} (a few minutes)...")
model = AutoModelForImageTextToText.from_pretrained(
base_model_id,
dtype=torch.bfloat16,
device_map=args.device if args.device == "cuda" else "cpu",
low_cpu_mem_usage=True,
)
base_state = model.state_dict()
print("Loading adapter weight tensors...")
adapter_state = load_safetensors(str(adapter_path))
# Adapter keys look like: base_model.model.model.language_model.layers.N.<submodule>.lora_A.weight
# Base model state dict keys look like: model.language_model.layers.N.<submodule>.weight
prefix_re = re.compile(r"^base_model\.model\.")
merged = 0
skipped_zero = 0
for a_key in lora_a_keys:
b_key = a_key.replace(".lora_A.weight", ".lora_B.weight")
base_key = prefix_re.sub("", a_key).replace(".lora_A.weight", ".weight")
if base_key not in base_state:
raise KeyError(f"Merged base key {base_key!r} (from adapter key {a_key!r}) not found in base model state dict")
A = adapter_state[a_key].to(dtype=torch.float32, device=args.device)
B = adapter_state[b_key].to(dtype=torch.float32, device=args.device)
if B.abs().max().item() == 0.0:
skipped_zero += 1
continue
delta = (scale * (B @ A)).to(dtype=base_state[base_key].dtype)
with torch.no_grad():
base_state[base_key].add_(delta.to(base_state[base_key].device))
merged += 1
print(f"Merged {merged} language_model layers, skipped {skipped_zero} all-zero (never trained) pairs.")
if merged == 0:
raise RuntimeError("No LoRA deltas were merged -- refusing to save an unmodified base model.")
print(f"Saving merged model to {args.output_dir} ...")
model.save_pretrained(str(args.output_dir), safe_serialization=True)
print("Saving processor/tokenizer + chat template...")
processor = AutoProcessor.from_pretrained(base_model_id)
processor.save_pretrained(str(args.output_dir))
metadata = {
"schema_version": "tenaos_lora_merge_v1",
"base_model": base_model_id,
"adapter_dir": str(args.adapter_dir),
"adapter_config_step": adapter_config.get("_source_step"),
"lora_r": lora_r,
"lora_alpha": lora_alpha,
"merged_dtype": "bfloat16",
"language_layers_merged": merged,
"vision_layers_skipped_all_zero": skipped_zero,
"note": "Vision tower and multi-modal projector are unmodified base-model weights; only the text decoder was fine-tuned.",
}
(args.output_dir / "merge_metadata.json").write_text(json.dumps(metadata, indent=2) + "\n")
print("Done.")
print(json.dumps(metadata, indent=2))
if __name__ == "__main__":
main()
|