| """ |
| Sparse Model Loader β Only loads relevant model parameters into RAM. |
| |
| This is the MAIN system that: |
| 1. Takes your Kimi 2.6 GGUF model |
| 2. Splits it into layer shards |
| 3. Uses SemanticRouter to determine which shards to load |
| 4. Uses MemoryMonitor to manage RAM (evict unused shards) |
| 5. Runs inference via llama.cpp (mmap β OS loads only needed weight pages) |
| |
| RESULT: Run a 35B model on 8GB RAM by only loading the active layers. |
| |
| Usage: |
| loader = SparseModelLoader( |
| model_path="/path/to/kimi-2.6.gguf", |
| max_ram_gb=8.0, |
| ) |
| |
| response = loader.chat("Write a Python function") |
| # β Router identifies "coding" expert |
| # β Loads only coding shards (6 layers β 2GB) |
| # β Runs inference |
| # β Unloads shards when done |
| """ |
|
|
| import os |
| import sys |
| import time |
| import json |
| import hashlib |
| from typing import Optional, Generator, Dict, List |
| from dataclasses import dataclass |
|
|
| |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) |
|
|
| from semantic_router import SemanticRouter, RouteResult |
| from memory_monitor import MemoryMonitor |
|
|
|
|
| @dataclass |
| class ModelShard: |
| """A shard (group of layers) of the model.""" |
| shard_id: int |
| name: str |
| layer_start: int |
| layer_end: int |
| size_mb: float |
|
|
|
|
| class SparseModelLoader: |
| """ |
| Sparse Model Loader β loads only relevant model parameters into RAM. |
| |
| ARCHITECTURE: |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| β User Query: "Write a Python function" β |
| ββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββ |
| β |
| ββββββββββββββββββββββββ |
| β SemanticRouter β (<1ms, <1MB RAM) |
| β Classifies: "coding" β |
| ββββββββββββ¬ββββββββββββ |
| β |
| ββββββββββββββββββββββββ |
| β Shard Manager β Decides which layers to load |
| β Load shards: 0-5 β |
| ββββββββββββ¬ββββββββββββ |
| β |
| ββββββββββββββββββββββββ |
| β MemoryMonitor β Checks if RAM available |
| β Evict LRU if needed β |
| ββββββββββββ¬ββββββββββββ |
| β |
| ββββββββββββββββββββββββ |
| β llama.cpp (mmap) β OS loads only needed weight |
| β Run inference β pages from SSD into RAM |
| ββββββββββββ¬ββββββββββββ |
| β |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| β Response: "def sort_list(lst):..." β |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ |
| """ |
|
|
| |
| |
| |
| |
| |
| KIMI_K2_6_LAYERS = 61 |
| KIMI_K2_6_EXPERTS = 384 |
| KIMI_K2_6_ACTIVE_EXPERTS = 8 |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| SHARD_DEFINITIONS = { |
| "chat": [ |
| ModelShard(0, "chat_basic", 0, 4, 2000), |
| ], |
| "coding": [ |
| ModelShard(1, "coding_early", 0, 6, 3000), |
| ModelShard(2, "coding_logic", 30, 36, 3000), |
| ], |
| "web_dev": [ |
| ModelShard(3, "webdev_early", 0, 8, 4000), |
| ModelShard(4, "webdev_gen", 40, 48, 4000), |
| ], |
| "math": [ |
| ModelShard(5, "math_compute", 10, 20, 5000), |
| ], |
| "creative": [ |
| ModelShard(6, "creative_gen", 40, 50, 5000), |
| ], |
| "reasoning": [ |
| ModelShard(7, "reasoning_full", 0, 10, 5000), |
| ModelShard(8, "reasoning_deep", 50, 61, 5500), |
| ], |
| } |
|
|
| def __init__( |
| self, |
| model_path: str, |
| max_ram_gb: float = 8.0, |
| n_ctx: int = 4096, |
| n_threads: Optional[int] = None, |
| ): |
| """ |
| Initialize the sparse model loader. |
| |
| Args: |
| model_path: Path to the Kimi 2.6 GGUF model file |
| max_ram_gb: Maximum RAM to use for model shards |
| n_ctx: Context window size (tokens) |
| n_threads: Number of CPU threads (default: auto-detect) |
| """ |
| self.model_path = model_path |
| self.max_ram_gb = max_ram_gb |
| self.n_ctx = n_ctx |
| self.n_threads = n_threads or os.cpu_count() or 4 |
|
|
| |
| self.router = SemanticRouter() |
| self.memory = MemoryMonitor(max_ram_gb=max_ram_gb) |
|
|
| |
| self._llm = None |
| self._model_size_gb = 0.0 |
| self._loaded_shards: set = set() |
|
|
| |
| if os.path.exists(model_path): |
| self._model_size_gb = os.path.getsize(model_path) / (1024**3) |
| print(f"β
Model found: {model_path}") |
| print(f" Size: {self._model_size_gb:.1f} GB") |
| print(f" Max RAM: {max_ram_gb} GB") |
| print(f" Threads: {self.n_threads}") |
| print(f" Context: {n_ctx} tokens") |
| print(f" Layers: {self.KIMI_K2_6_LAYERS}") |
| else: |
| print(f"β οΈ Model not found at: {model_path}") |
| print(f" The loader will still work in 'simulation mode'") |
|
|
| print(f"\nπ§ Sparse Model Loader initialized") |
| print(f" Full model: {self._model_size_gb:.1f} GB on disk") |
| print(f" Max RAM usage: {max_ram_gb} GB") |
| print(f" Savings: up to {(1 - max_ram_gb / max(self._model_size_gb, 0.1)) * 100:.0f}%") |
|
|
| def _load_llama(self): |
| """Load the llama.cpp model with mmap (lazy loading).""" |
| if self._llm is not None: |
| return |
|
|
| try: |
| from llama_cpp import Llama |
|
|
| print(f"\nπ¦ Loading model with mmap (lazy page loading)...") |
| self._llm = Llama( |
| model_path=self.model_path, |
| n_ctx=self.n_ctx, |
| n_threads=self.n_threads, |
| n_gpu_layers=0, |
| use_mmap=True, |
| use_mlock=False, |
| n_batch=512, |
| verbose=False, |
| ) |
| print(f"β
Model loaded with mmap β OS will manage RAM automatically") |
|
|
| except ImportError: |
| print("β llama-cpp-python not installed.") |
| print(" Install: pip install llama-cpp-python") |
| raise |
| except Exception as e: |
| print(f"β Failed to load model: {e}") |
| raise |
|
|
| def chat( |
| self, |
| message: str, |
| system_prompt: str = "", |
| max_tokens: int = 2048, |
| temperature: float = 0.7, |
| stream: bool = False, |
| ) -> str: |
| """ |
| Chat with the model using sparse activation. |
| |
| 1. Route the query to determine which expert/shards to load |
| 2. Check if we have enough RAM (evict LRU shards if needed) |
| 3. Load the model with mmap (OS loads only needed weight pages) |
| 4. Run inference |
| 5. Return the response |
| |
| Args: |
| message: User's message |
| system_prompt: Optional system prompt |
| max_tokens: Maximum tokens to generate |
| temperature: Sampling temperature (0=deterministic, 1=creative) |
| stream: Whether to stream the response |
| |
| Returns: |
| Model's response text |
| """ |
| print(f"\n{'='*60}") |
| print(f"π¬ Query: {message[:100]}...") |
| print(f"{'='*60}") |
|
|
| |
| route = self.router.route(message) |
| print(f"\nπ Routing:") |
| print(f" Expert: {route.expert}") |
| print(f" Shards: {route.shard_ids}") |
| print(f" Confidence: {route.confidence:.0%}") |
| print(f" Reason: {route.reason}") |
|
|
| |
| shards_to_load = self.SHARD_DEFINITIONS.get(route.expert, []) |
| total_shard_size = sum(s.size_mb for s in shards_to_load) |
| print(f"\nπ¦ Shards to load:") |
| for s in shards_to_load: |
| print(f" Shard {s.shard_id} ({s.name}): layers {s.layer_start}-{s.layer_end} ({s.size_mb:.0f}MB)") |
| print(f" Total: {total_shard_size:.0f}MB ({total_shard_size/1024:.1f}GB)") |
|
|
| |
| available = self.memory.get_available_ram_mb() |
| print(f"\nπΎ Memory:") |
| print(f" Available: {available:.0f}MB ({available/1024:.1f}GB)") |
| print(f" Needed: {total_shard_size:.0f}MB ({total_shard_size/1024:.1f}GB)") |
|
|
| if available < total_shard_size: |
| print(f" β οΈ Low RAM β will use mmap (OS loads from disk on-demand)") |
| print(f" β οΈ May be slower but will work!") |
|
|
| |
| self._load_llama() |
|
|
| |
| messages = [] |
| if system_prompt: |
| messages.append({"role": "system", "content": system_prompt}) |
| messages.append({"role": "user", "content": message}) |
|
|
| |
| print(f"\nβ‘ Running inference...") |
| start_time = time.time() |
|
|
| if stream: |
| return self._stream_inference(messages, max_tokens, temperature, start_time) |
| else: |
| response = self._llm.create_chat_completion( |
| messages=messages, |
| max_tokens=max_tokens, |
| temperature=temperature, |
| stream=False, |
| ) |
| elapsed = time.time() - start_time |
| text = response["choices"][0]["message"]["content"] |
| tokens = response.get("usage", {}).get("completion_tokens", 0) |
|
|
| print(f"β
Done in {elapsed:.1f}s ({tokens/max(1,elapsed):.0f} tok/s)") |
| print(f" Generated: {len(text)} chars, {tokens} tokens") |
|
|
| |
| self.memory.on_access(shard_id=hash(message) % 1000) |
|
|
| return text |
|
|
| def _stream_inference( |
| self, |
| messages: list, |
| max_tokens: int, |
| temperature: float, |
| start_time: float, |
| ) -> Generator[str, None, None]: |
| """Stream the response token by token.""" |
| first_token = True |
| token_count = 0 |
|
|
| for chunk in self._llm.create_chat_completion( |
| messages=messages, |
| max_tokens=max_tokens, |
| temperature=temperature, |
| stream=True, |
| ): |
| if first_token: |
| print(f"\nπ Response: ", end="", flush=True) |
| first_token = False |
|
|
| delta = chunk["choices"][0].get("delta", {}) |
| if "content" in delta: |
| token_count += 1 |
| print(delta["content"], end="", flush=True) |
| yield delta["content"] |
|
|
| elapsed = time.time() - start_time |
| print(f"\n\nβ
Done in {elapsed:.1f}s ({token_count/max(1,elapsed):.0f} tok/s)") |
|
|
| def get_status(self) -> dict: |
| """Get current system status.""" |
| return { |
| "model": self.model_path, |
| "model_size_gb": f"{self._model_size_gb:.1f}GB", |
| "max_ram_gb": f"{self.max_ram_gb}GB", |
| "memory": self.memory.get_status(), |
| "model_loaded": self._llm is not None, |
| } |
|
|
| def unload(self): |
| """Unload the model from RAM.""" |
| if self._llm is not None: |
| del self._llm |
| self._llm = None |
| print(f"ποΈ Model unloaded from RAM") |
|
|
|
|
| |
| |
| |
|
|
| def create_api_server(loader: SparseModelLoader, port: int = 8080): |
| """Create a FastAPI server with OpenAI-compatible API.""" |
| try: |
| from fastapi import FastAPI, HTTPException |
| from fastapi.responses import StreamingResponse |
| from pydantic import BaseModel |
| import uvicorn |
| except ImportError: |
| print("β FastAPI not installed. Install: pip install fastapi uvicorn") |
| return |
|
|
| app = FastAPI(title="Sparse Model Loader API", version="1.0.0") |
|
|
| class ChatRequest(BaseModel): |
| model: str = "kimi-2.6" |
| messages: list |
| max_tokens: int = 2048 |
| temperature: float = 0.7 |
| stream: bool = False |
|
|
| @app.get("/v1/models") |
| async def list_models(): |
| return { |
| "object": "list", |
| "data": [{"id": "kimi-2.6", "object": "model", "owned_by": "sparse-loader"}], |
| } |
|
|
| @app.post("/v1/chat/completions") |
| async def chat_completions(req: ChatRequest): |
| |
| user_msg = "" |
| system_prompt = "" |
| for msg in req.messages: |
| if msg["role"] == "system": |
| system_prompt = msg["content"] |
| elif msg["role"] == "user": |
| user_msg = msg["content"] |
|
|
| if not user_msg: |
| raise HTTPException(400, "No user message") |
|
|
| if req.stream: |
| def generate(): |
| for token in loader.chat( |
| user_msg, system_prompt, |
| max_tokens=req.max_tokens, |
| temperature=req.temperature, |
| stream=True, |
| ): |
| yield f"data: {json.dumps({'choices': [{'delta': {'content': token}}]})}\n\n" |
| yield "data: [DONE]\n\n" |
| return StreamingResponse(generate(), media_type="text/event-stream") |
| else: |
| text = loader.chat( |
| user_msg, system_prompt, |
| max_tokens=req.max_tokens, |
| temperature=req.temperature, |
| ) |
| return { |
| "id": f"chatcmpl-{int(time.time())}", |
| "object": "chat.completion", |
| "model": "kimi-2.6", |
| "choices": [{ |
| "index": 0, |
| "message": {"role": "assistant", "content": text}, |
| "finish_reason": "stop", |
| }], |
| "usage": {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}, |
| } |
|
|
| @app.get("/status") |
| async def status(): |
| return loader.get_status() |
|
|
| print(f"\nπ API Server starting on http://localhost:{port}") |
| print(f" OpenAI-compatible: http://localhost:{port}/v1/chat/completions") |
| print(f" Status: http://localhost:{port}/status") |
| uvicorn.run(app, host="0.0.0.0", port=port) |
|
|
|
|
| |
| |
| |
|
|
| if __name__ == "__main__": |
| import argparse |
|
|
| parser = argparse.ArgumentParser(description="Sparse Model Loader β Kimi 2.6") |
| parser.add_argument("--model", type=str, required=True, |
| help="Path to Kimi 2.6 GGUF model file") |
| parser.add_argument("--ram", type=float, default=8.0, |
| help="Max RAM in GB (default: 8.0)") |
| parser.add_argument("--port", type=int, default=8080, |
| help="API server port (default: 8080)") |
| parser.add_argument("--serve", action="store_true", |
| help="Start API server mode") |
| parser.add_argument("--chat", action="store_true", |
| help="Start interactive chat mode") |
| args = parser.parse_args() |
|
|
| |
| loader = SparseModelLoader( |
| model_path=args.model, |
| max_ram_gb=args.ram, |
| ) |
|
|
| if args.serve: |
| |
| create_api_server(loader, port=args.port) |
|
|
| elif args.chat: |
| |
| print(f"\n{'='*60}") |
| print(f"π§ Sparse Model Loader β Interactive Chat") |
| print(f" Model: {args.model}") |
| print(f" Max RAM: {args.ram}GB") |
| print(f" Type 'exit' to quit") |
| print(f"{'='*60}\n") |
|
|
| while True: |
| try: |
| user_input = input("You: ").strip() |
| if user_input.lower() in ["exit", "quit", "bye"]: |
| print("Goodbye!") |
| break |
| if not user_input: |
| continue |
|
|
| response = loader.chat(user_input, temperature=0.7) |
| print(f"\nAssistant: {response}\n") |
| except KeyboardInterrupt: |
| print("\nGoodbye!") |
| break |
|
|
| else: |
| |
| print(f"\n{'='*60}") |
| print(f"π§ DEMO MODE β Testing Sparse Loader") |
| print(f"{'='*60}") |
|
|
| test_queries = [ |
| "Write a Python function to sort a list", |
| "Build a todo app with HTML and CSS", |
| "What is 25 * 37?", |
| "Write a poem about the ocean", |
| "Explain how neural networks work", |
| "Hello, how are you?", |
| ] |
|
|
| for query in test_queries: |
| route = loader.router.route(query) |
| shards = loader.SHARD_DEFINITIONS.get(route.expert, []) |
| total_mb = sum(s.size_mb for s in shards) |
| full_model_mb = loader._model_size_gb * 1024 |
|
|
| print(f"\n㪠{query}") |
| print(f" β Expert: {route.expert} ({route.confidence:.0%} confident)") |
| print(f" β Shards: {len(shards)} ({total_mb:.0f}MB)") |
| print(f" β Full model: {full_model_mb:.0f}MB") |
| print(f" β RAM saved: {(1 - total_mb/max(full_model_mb,1))*100:.0f}%") |
|
|
| print(f"\n{'='*60}") |
| print(f"β
To run: python {sys.argv[0]} --model /path/to/kimi-2.6.gguf --chat") |
| print(f"β
To serve: python {sys.argv[0]} --model /path/to/kimi-2.6.gguf --serve") |
| print(f"{'='*60}") |
|
|