Text Generation
Transformers
Safetensors
English
ethoric
causal-lm
custom-architecture
custom_code
slm
small-language-model
Eval Results (legacy)
Instructions to use techdotus/Ethoric-10M with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use techdotus/Ethoric-10M with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="techdotus/Ethoric-10M", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("techdotus/Ethoric-10M", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use techdotus/Ethoric-10M with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "techdotus/Ethoric-10M" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "techdotus/Ethoric-10M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/techdotus/Ethoric-10M
- SGLang
How to use techdotus/Ethoric-10M 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 "techdotus/Ethoric-10M" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "techdotus/Ethoric-10M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'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 "techdotus/Ethoric-10M" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "techdotus/Ethoric-10M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use techdotus/Ethoric-10M with Docker Model Runner:
docker model run hf.co/techdotus/Ethoric-10M
Upload params.py
Browse files
params.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Exact parameter accounting.
|
| 2 |
+
|
| 3 |
+
The headline number is trainable weights PLUS frozen buffer values.
|
| 4 |
+
"""
|
| 5 |
+
from __future__ import annotations
|
| 6 |
+
|
| 7 |
+
from collections import OrderedDict
|
| 8 |
+
|
| 9 |
+
import torch
|
| 10 |
+
import torch.nn as nn
|
| 11 |
+
|
| 12 |
+
# Buffers that hold only derived constants would be excluded and listed here.
|
| 13 |
+
# The design deliberately has none; RoPE tables are plain Python state.
|
| 14 |
+
DERIVED_BUFFERS: tuple[str, ...] = ()
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def _tied_targets(model: nn.Module) -> set[str]:
|
| 18 |
+
"""Parameter names that are copies of another parameter, so count once.
|
| 19 |
+
|
| 20 |
+
Object identity is not enough: `from_pretrained` constructs the model before
|
| 21 |
+
tying the weights, so during construction `lm_head.weight` is still a
|
| 22 |
+
distinct tensor. Counting it would double the embedding and trip the budget
|
| 23 |
+
check on an otherwise valid model.
|
| 24 |
+
"""
|
| 25 |
+
if not getattr(model.config, "tie_word_embeddings", False):
|
| 26 |
+
return set()
|
| 27 |
+
keys = getattr(model, "_tied_weights_keys", None) or []
|
| 28 |
+
# transformers 4.x: a list of target names. 5.x: {target: source}.
|
| 29 |
+
return set(keys.keys()) if isinstance(keys, dict) else set(keys)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def account(model: nn.Module) -> dict:
|
| 33 |
+
"""Walk named_parameters() and named_buffers(). Returns a count breakdown."""
|
| 34 |
+
trainable, frozen, excluded = 0, 0, 0
|
| 35 |
+
by_param: "OrderedDict[str, int]" = OrderedDict()
|
| 36 |
+
by_buffer: "OrderedDict[str, int]" = OrderedDict()
|
| 37 |
+
excluded_names: list[str] = []
|
| 38 |
+
|
| 39 |
+
tied = _tied_targets(model)
|
| 40 |
+
seen: set[int] = set()
|
| 41 |
+
for name, p in model.named_parameters():
|
| 42 |
+
if id(p) in seen: # tied weights counted once
|
| 43 |
+
continue
|
| 44 |
+
if name in tied or any(name.endswith("." + t) for t in tied):
|
| 45 |
+
continue
|
| 46 |
+
seen.add(id(p))
|
| 47 |
+
n = p.numel()
|
| 48 |
+
by_param[name] = n
|
| 49 |
+
trainable += n
|
| 50 |
+
|
| 51 |
+
for name, b in model.named_buffers():
|
| 52 |
+
if b is None or id(b) in seen:
|
| 53 |
+
continue
|
| 54 |
+
seen.add(id(b))
|
| 55 |
+
n = b.numel()
|
| 56 |
+
if any(name.endswith(suffix) for suffix in DERIVED_BUFFERS):
|
| 57 |
+
excluded += n
|
| 58 |
+
excluded_names.append(name)
|
| 59 |
+
continue
|
| 60 |
+
by_buffer[name] = n
|
| 61 |
+
frozen += n
|
| 62 |
+
|
| 63 |
+
return {
|
| 64 |
+
"trainable": trainable,
|
| 65 |
+
"frozen": frozen,
|
| 66 |
+
"total": trainable + frozen,
|
| 67 |
+
"excluded": excluded,
|
| 68 |
+
"excluded_names": excluded_names,
|
| 69 |
+
"by_param": by_param,
|
| 70 |
+
"by_buffer": by_buffer,
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def _group(model: nn.Module) -> "OrderedDict[str, int]":
|
| 75 |
+
"""Spec-shaped component table, computed from the live model."""
|
| 76 |
+
cfg = model.config
|
| 77 |
+
base = model.model if hasattr(model, "model") else model
|
| 78 |
+
rows: "OrderedDict[str, int]" = OrderedDict()
|
| 79 |
+
|
| 80 |
+
def count(mods) -> int:
|
| 81 |
+
seen, total = set(), 0
|
| 82 |
+
for m in mods:
|
| 83 |
+
if m is None:
|
| 84 |
+
continue
|
| 85 |
+
for p in m.parameters(recurse=True):
|
| 86 |
+
if id(p) not in seen:
|
| 87 |
+
seen.add(id(p))
|
| 88 |
+
total += p.numel()
|
| 89 |
+
return total
|
| 90 |
+
|
| 91 |
+
layer0 = base.layers[0]
|
| 92 |
+
n_layer = len(base.layers)
|
| 93 |
+
|
| 94 |
+
attn = count([layer0.attn.q_proj, layer0.attn.k_proj, layer0.attn.v_proj, layer0.attn.o_proj])
|
| 95 |
+
qk = count([layer0.attn.q_norm, layer0.attn.k_norm])
|
| 96 |
+
gate = count([layer0.attn.gate_proj])
|
| 97 |
+
mlp = count([layer0.mlp])
|
| 98 |
+
norms = count([layer0.attn_in_norm, layer0.attn_out_norm, layer0.mlp_in_norm, layer0.mlp_out_norm])
|
| 99 |
+
canon = count([layer0.canon_a, layer0.canon_c])
|
| 100 |
+
per_layer = attn + qk + gate + mlp + norms + canon
|
| 101 |
+
|
| 102 |
+
rows["Attention q, k, v, o"] = attn
|
| 103 |
+
rows["QK-norm"] = qk
|
| 104 |
+
rows[f"{cfg.attn_gate.capitalize()} gate (W + b)"] = gate
|
| 105 |
+
rows[f"SwiGLU MLP (3 x {cfg.d_model} x {cfg.ffn_hidden})"] = mlp
|
| 106 |
+
rows[f"Peri-LN, 4 norms x {cfg.d_model}"] = norms
|
| 107 |
+
rows["Canon A + C"] = canon
|
| 108 |
+
rows["--- Per layer"] = per_layer
|
| 109 |
+
rows[f"{n_layer} layers"] = per_layer * n_layer
|
| 110 |
+
|
| 111 |
+
emb = base.embed_tokens.weight.numel()
|
| 112 |
+
rows[f"Tied embedding ({cfg.vocab_size} x {cfg.d_model})"] = emb
|
| 113 |
+
rows["Final norm"] = base.final_norm.weight.numel()
|
| 114 |
+
|
| 115 |
+
info = account(model)
|
| 116 |
+
rows["--- Trainable"] = info["trainable"]
|
| 117 |
+
if info["frozen"]:
|
| 118 |
+
rows["Frozen buffers"] = info["frozen"]
|
| 119 |
+
rows["--- Total"] = info["total"]
|
| 120 |
+
return rows
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def table(model: nn.Module) -> str:
|
| 124 |
+
rows = _group(model)
|
| 125 |
+
info = account(model)
|
| 126 |
+
width = max(len(k) for k in rows) + 2
|
| 127 |
+
lines = [f"{'Component'.ljust(width)}{'Count':>12}", "-" * (width + 12)]
|
| 128 |
+
for key, val in rows.items():
|
| 129 |
+
if key.startswith("--- "):
|
| 130 |
+
lines.append("-" * (width + 12))
|
| 131 |
+
key = key[4:]
|
| 132 |
+
lines.append(f"{key.ljust(width)}{val:>12,}")
|
| 133 |
+
lines.append("-" * (width + 12))
|
| 134 |
+
|
| 135 |
+
budget = getattr(model.config, "max_total_params", None)
|
| 136 |
+
warn = getattr(model.config, "warn_total_params", None)
|
| 137 |
+
if budget:
|
| 138 |
+
ok = "OK" if info["total"] <= budget else "OVER BUDGET"
|
| 139 |
+
lines.append(f"{'Budget (max_total_params)'.ljust(width)}{budget:>12,} [{ok}]")
|
| 140 |
+
if warn:
|
| 141 |
+
flag = "ok" if info["total"] <= warn else "WARN"
|
| 142 |
+
lines.append(f"{'Warn threshold'.ljust(width)}{warn:>12,} [{flag}]")
|
| 143 |
+
if info["excluded"]:
|
| 144 |
+
lines.append(
|
| 145 |
+
f"Excluded derived buffers ({info['excluded']:,}): "
|
| 146 |
+
+ ", ".join(info["excluded_names"])
|
| 147 |
+
)
|
| 148 |
+
return "\n".join(lines)
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def count_from_config(cfg_or_model) -> dict:
|
| 152 |
+
"""Build the model if given a config dict, then account for it.
|
| 153 |
+
|
| 154 |
+
Construction itself raises when the budget is exceeded, so this doubles as
|
| 155 |
+
the budget check.
|
| 156 |
+
"""
|
| 157 |
+
if isinstance(cfg_or_model, nn.Module):
|
| 158 |
+
return account(cfg_or_model)
|
| 159 |
+
from ethoric.model.configuration_ethoric import EthoricConfig
|
| 160 |
+
from ethoric.model.modeling_ethoric import EthoricForCausalLM
|
| 161 |
+
|
| 162 |
+
model_cfg = EthoricConfig.from_pipeline(cfg_or_model)
|
| 163 |
+
with torch.device("meta"):
|
| 164 |
+
model = EthoricForCausalLM(model_cfg)
|
| 165 |
+
return account(model)
|