Text Generation
Transformers
Safetensors
English
canopy
browser-use
web-agent
recurrent-moe
edge-llm
lightpanda
obscura
multi-agent
robotics-web
conversational
custom_code
Instructions to use psikosen/canopy-258m-r3 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use psikosen/canopy-258m-r3 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="psikosen/canopy-258m-r3", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("psikosen/canopy-258m-r3", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use psikosen/canopy-258m-r3 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "psikosen/canopy-258m-r3" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "psikosen/canopy-258m-r3", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/psikosen/canopy-258m-r3
- SGLang
How to use psikosen/canopy-258m-r3 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 "psikosen/canopy-258m-r3" \ --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": "psikosen/canopy-258m-r3", "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 "psikosen/canopy-258m-r3" \ --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": "psikosen/canopy-258m-r3", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use psikosen/canopy-258m-r3 with Docker Model Runner:
docker model run hf.co/psikosen/canopy-258m-r3
Download canopy_r3/nora.py from psikosen/canopy-258m-r3: direct link, hf CLI and curl.
- Browser
- Download file 4.76 kB
-
https://huggingface.co/psikosen/canopy-258m-r3/resolve/main/canopy_r3/nora.py
- Command line
-
hf download hf://psikosen/canopy-258m-r3/canopy_r3/nora.py
-
curl -L -o nora.py https://huggingface.co/psikosen/canopy-258m-r3/resolve/main/canopy_r3/nora.py
4.76 kB
| """ | |
| Normalized Low-Rank Adaptation (NoRA & NoRA-Init). | |
| Reference: SphereLab, Microsoft Research, CUHK (arXiv:2608.31036, Aug 31, 2026). | |
| Normalizes the down-projection matrix A along the rank dimension: | |
| delta_W = alpha * B * Norm(A) | |
| Provides improved convergence, zero parameter overhead, and exact weight mergeability. | |
| """ | |
| from __future__ import annotations | |
| import math | |
| from typing import List, Optional | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| class NoRALinear(nn.Module): | |
| """ | |
| Linear layer with Normalized Low-Rank Adaptation (NoRA). | |
| Applies rank-dimensional normalization to down-projection A: | |
| y = W_0 x + (alpha / r) * B * Norm_r(A) * x | |
| """ | |
| def __init__( | |
| self, | |
| base_linear: nn.Linear, | |
| rank: int = 16, | |
| alpha: float = 32.0, | |
| dropout: float = 0.0, | |
| nora_mode: str = "dynamic", # "dynamic" (re-normalizes per step) or "init" (NoRA-init) | |
| ): | |
| super().__init__() | |
| self.in_features = base_linear.in_features | |
| self.out_features = base_linear.out_features | |
| self.rank = rank | |
| self.alpha = alpha | |
| self.scaling = alpha / rank | |
| self.nora_mode = nora_mode | |
| self.merged = False | |
| # Base frozen weights | |
| self.weight = base_linear.weight | |
| self.bias = base_linear.bias | |
| self.weight.requires_grad = False | |
| if self.bias is not None: | |
| self.bias.requires_grad = False | |
| # NoRA adapter weights: A (r, in_features), B (out_features, r) | |
| self.nora_a = nn.Parameter(torch.empty(rank, self.in_features)) | |
| self.nora_b = nn.Parameter(torch.zeros(self.out_features, rank)) | |
| self.dropout = nn.Dropout(p=dropout) if dropout > 0.0 else nn.Identity() | |
| self.reset_parameters() | |
| def reset_parameters(self): | |
| # Kaiming uniform for down-projection A | |
| nn.init.kaiming_uniform_(self.nora_a, a=math.sqrt(5)) | |
| # Zero-initialize B so adapter starts as exact identity | |
| nn.init.zeros_(self.nora_b) | |
| # Apply NoRA-init: normalize rows along the rank dimension | |
| with torch.no_grad(): | |
| self.nora_a.copy_(self._normalize_a(self.nora_a)) | |
| def _normalize_a(self, a_matrix: torch.Tensor) -> torch.Tensor: | |
| """Normalizes projection vectors along the rank dimension (dim 0).""" | |
| norm = torch.norm(a_matrix, p=2, dim=-1, keepdim=True) + 1e-8 | |
| # Scale by sqrt(in_features) to preserve expected activation variance | |
| return (a_matrix / norm) * math.sqrt(self.in_features) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| if self.merged: | |
| return F.linear(x, self.weight, self.bias) | |
| base_out = F.linear(x, self.weight, self.bias) | |
| # Normalize A dynamically if in dynamic mode | |
| if self.nora_mode == "dynamic" and self.training: | |
| a_effective = self._normalize_a(self.nora_a) | |
| else: | |
| a_effective = self.nora_a | |
| # Low-rank forward: (B, S, D_in) -> (B, S, r) -> (B, S, D_out) | |
| dropped_x = self.dropout(x) | |
| latent = F.linear(dropped_x, a_effective) | |
| adapter_out = F.linear(latent, self.nora_b) * self.scaling | |
| return base_out + adapter_out | |
| def merge_weights(self): | |
| """Exact merge of adapter weights into base weights.""" | |
| if self.merged: | |
| return | |
| with torch.no_grad(): | |
| a_effective = self._normalize_a(self.nora_a) if self.nora_mode == "dynamic" else self.nora_a | |
| delta_w = (self.nora_b @ a_effective) * self.scaling | |
| self.weight.add_(delta_w) | |
| self.merged = True | |
| def unmerge_weights(self): | |
| """Reverses the weight merge.""" | |
| if not self.merged: | |
| return | |
| with torch.no_grad(): | |
| a_effective = self._normalize_a(self.nora_a) if self.nora_mode == "dynamic" else self.nora_a | |
| delta_w = (self.nora_b @ a_effective) * self.scaling | |
| self.weight.sub_(delta_w) | |
| self.merged = False | |
| def apply_nora( | |
| model: nn.Module, | |
| rank: int = 16, | |
| alpha: float = 32.0, | |
| target_names: List[str] = ["q_proj", "v_proj", "k_proj"], | |
| nora_mode: str = "dynamic", | |
| ) -> List[str]: | |
| """Applies NoRA adapters to designated linear layers in the model.""" | |
| adapted_layers = [] | |
| for name, module in model.named_modules(): | |
| for child_name, child in module.named_children(): | |
| if isinstance(child, nn.Linear) and any(t in child_name for t in target_names): | |
| nora_layer = NoRALinear(child, rank=rank, alpha=alpha, nora_mode=nora_mode) | |
| setattr(module, child_name, nora_layer) | |
| adapted_layers.append(f"{name}.{child_name}") | |
| return adapted_layers | |