Instructions to use konpep/aether-rwkv-25m with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- RWKV
How to use konpep/aether-rwkv-25m with RWKV:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
| """ | |
| RWKV v4 — Correct implementation with time-mix WKV formula | |
| Changes from previous version: | |
| 1. Correct time-mix WKV with time_decay + time_first (bonus) | |
| 2. state_num = w * state_num + exp(k) * v (only keeps the past) | |
| 3. wkv_t = (state_num + exp(u) * exp(k_t) * v_t) / (state_den + exp(u) * exp(k_t)) | |
| 4. ~25M params (hidden=544, layers=10) | |
| """ | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| import math | |
| class RWKV_TimeMix(nn.Module): | |
| """ | |
| Time-Mix with correct WKV formula | |
| wkv_t = (sum_{past} w * exp(k_i) * v_i + exp(u) * exp(k_t) * v_t) / | |
| (sum_{past} w * exp(k_i) + exp(u) * exp(k_t)) | |
| where w = exp(-exp(time_decay)), u = time_first | |
| """ | |
| def __init__(self, hidden_size): | |
| super().__init__() | |
| self.hidden_size = hidden_size | |
| self.key = nn.Linear(hidden_size, hidden_size, bias=False) | |
| self.value = nn.Linear(hidden_size, hidden_size, bias=False) | |
| self.receptance = nn.Linear(hidden_size, hidden_size, bias=False) | |
| # time_decay: how fast the past is forgotten (per channel) | |
| # initialized at log(1) ≈ 0, so exp(-exp(0)) ≈ 0.37 | |
| self.time_decay = nn.Parameter(torch.empty(hidden_size)) | |
| # time_first: bonus for the current token (per channel) | |
| self.time_first = nn.Parameter(torch.empty(hidden_size)) | |
| self.init_weights() | |
| def init_weights(self): | |
| nn.init.orthogonal_(self.key.weight, gain=0.1) | |
| nn.init.orthogonal_(self.value.weight, gain=1.0) | |
| nn.init.orthogonal_(self.receptance.weight, gain=1.0) | |
| nn.init.constant_(self.time_decay, 0.0) | |
| nn.init.constant_(self.time_first, 5.0) | |
| def forward(self, x, state=None): | |
| """ | |
| Time-mix for training (parallel processing) | |
| Computes correct WKV: | |
| - state_num = w * state_num + exp(k) * v (past only) | |
| - num = w * state_num + exp(u) * exp(k_t) * v_t (past + current bonus) | |
| """ | |
| B, T, C = x.shape | |
| k = self.key(x) | |
| v = self.value(x) | |
| r = self.receptance(x) | |
| decay = torch.exp(-torch.exp(self.time_decay)).view(1, 1, C) | |
| exp_bonus = torch.exp(self.time_first).view(1, 1, C) | |
| exp_k = torch.exp(k) | |
| num = torch.zeros(B, T, C, device=x.device) | |
| den = torch.zeros(B, T, C, device=x.device) | |
| if state is not None: | |
| s_num, s_den = state | |
| else: | |
| s_num = torch.zeros(B, 1, C, device=x.device) | |
| s_den = torch.zeros(B, 1, C, device=x.device) | |
| for t in range(T): | |
| ek = exp_k[:, t:t+1, :] | |
| v_t = v[:, t:t+1, :] | |
| num_t = s_num * decay + exp_bonus * ek * v_t | |
| den_t = s_den * decay + exp_bonus * ek | |
| num[:, t:t+1, :] = num_t | |
| den[:, t:t+1, :] = den_t | |
| s_num = s_num * decay + ek * v_t | |
| s_den = s_den * decay + ek | |
| wkv = num / (den + 1e-8) | |
| output = torch.sigmoid(r) * wkv | |
| return output, (s_num, s_den) | |
| def forward_step(self, x, state): | |
| k = self.key(x) | |
| v = self.value(x) | |
| r = self.receptance(x) | |
| decay = torch.exp(-torch.exp(self.time_decay)).view(1, -1, 1) | |
| exp_bonus = torch.exp(self.time_first).view(1, -1, 1) | |
| s_num, s_den = state | |
| ek = torch.exp(k) | |
| num = s_num * decay + exp_bonus * ek * v | |
| den = s_den * decay + exp_bonus * ek | |
| wkv = num / (den + 1e-8) | |
| s_num = s_num * decay + ek * v | |
| s_den = s_den * decay + ek | |
| output = torch.sigmoid(r) * wkv | |
| return output, (s_num, s_den) | |
| class RWKV_ChannelMix(nn.Module): | |
| """ | |
| Channel-Mix: MLP with ReLU² + Sigmoid gate | |
| Structure: Linear(×2) → ReLU² → Linear(÷2) × Sigmoid(receptance) | |
| """ | |
| def __init__(self, hidden_size): | |
| super().__init__() | |
| ff_size = hidden_size * 2 | |
| self.key = nn.Linear(hidden_size, ff_size, bias=False) | |
| self.value = nn.Linear(ff_size, hidden_size, bias=False) | |
| self.receptance = nn.Linear(hidden_size, hidden_size, bias=False) | |
| self.init_weights() | |
| def init_weights(self): | |
| nn.init.orthogonal_(self.key.weight, gain=1.0) | |
| nn.init.zeros_(self.value.weight) | |
| nn.init.zeros_(self.receptance.weight) | |
| def forward(self, x): | |
| k = F.relu(self.key(x)) ** 2 | |
| v = self.value(k) | |
| r = torch.sigmoid(self.receptance(x)) | |
| return r * v | |
| class RWKV_Block(nn.Module): | |
| """ | |
| Block: LayerNorm → TimeMix → Residual → LayerNorm → ChannelMix → Residual | |
| """ | |
| def __init__(self, hidden_size, dropout=0.0): | |
| super().__init__() | |
| self.ln1 = nn.LayerNorm(hidden_size) | |
| self.ln2 = nn.LayerNorm(hidden_size) | |
| self.time_mix = RWKV_TimeMix(hidden_size) | |
| self.channel_mix = RWKV_ChannelMix(hidden_size) | |
| self.dropout = nn.Dropout(dropout) | |
| def forward(self, x, state=None): | |
| tm_out, new_state = self.time_mix(self.ln1(x), state) | |
| x = x + self.dropout(tm_out) | |
| cm_out = self.channel_mix(self.ln2(x)) | |
| x = x + self.dropout(cm_out) | |
| return x, new_state | |
| def forward_step(self, x, state): | |
| tm_out, tm_state = self.time_mix.forward_step(self.ln1(x), state[0]) | |
| x = x + tm_out | |
| cm_out = self.channel_mix(self.ln2(x)) | |
| x = x + cm_out | |
| return x, (tm_state,) | |
| class RWKV(nn.Module): | |
| """ | |
| Full RWKV v4 model | |
| Embedding → 10× RWKV_Block → LayerNorm → Linear(output) | |
| ~25M params (hidden=544) | |
| """ | |
| def __init__(self, vocab_size, hidden_size=480, num_layers=12, ff_size_mult=2, dropout=0.0): | |
| super().__init__() | |
| self.vocab_size = vocab_size | |
| self.hidden_size = hidden_size | |
| self.num_layers = num_layers | |
| self.dropout = dropout | |
| # Change ff_size if needed | |
| RWKV_ChannelMix._ff_mult = ff_size_mult | |
| self.embed = nn.Embedding(vocab_size, hidden_size) | |
| self.embed_drop = nn.Dropout(dropout) | |
| self.blocks = nn.ModuleList([ | |
| RWKV_Block(hidden_size, dropout) for _ in range(num_layers) | |
| ]) | |
| self.ln_out = nn.LayerNorm(hidden_size) | |
| self.head = nn.Linear(hidden_size, vocab_size, bias=False) | |
| self.embed.weight = self.head.weight | |
| self._block_outputs = None | |
| # Init head specifically: orthogonal gain = 0.5 * sqrt(vocab / hidden) | |
| head_gain = 0.5 * (vocab_size / hidden_size) ** 0.5 | |
| nn.init.orthogonal_(self.head.weight, gain=head_gain) | |
| # Init remaining layers (LayerNorm) | |
| nn.init.ones_(self.ln_out.weight) | |
| nn.init.zeros_(self.ln_out.bias) | |
| total = sum(p.numel() for p in self.parameters()) | |
| print(f"RWKV (v4 WKV) created: {total:,} total parameters") | |
| def forward(self, x, state=None): | |
| x = self.embed_drop(self.embed(x)) | |
| new_states = [] | |
| for i, block in enumerate(self.blocks): | |
| block_state = state[i] if state is not None else None | |
| x, new_state = block(x, block_state) | |
| new_states.append(new_state) | |
| x = self.ln_out(x) | |
| logits = self.head(x) | |
| return logits, new_states | |
| def forward_step(self, x, state): | |
| x = self.embed(x) | |
| new_states = [] | |
| for i, block in enumerate(self.blocks): | |
| x, new_state = block.forward_step(x, state[i]) | |
| new_states.append(new_state) | |
| if self._block_outputs is not None: | |
| self._block_outputs.append(x.abs().mean().item()) | |
| x = self.ln_out(x) | |
| logits = self.head(x) | |
| return logits, new_states | |
| def init_state(self, batch_size=1, device='cpu'): | |
| state = [] | |
| for block in self.blocks: | |
| n = torch.zeros(batch_size, 1, self.hidden_size, device=device) | |
| d = torch.zeros(batch_size, 1, self.hidden_size, device=device) | |
| state.append(((n, d),)) | |
| return state | |
| def generate(self, prompt_ids, max_new=50, temperature=0.7, top_k=20, repetition_penalty=1.1, progress_cb=None): | |
| self.eval() | |
| device = next(self.parameters()).device | |
| generated = list(prompt_ids) | |
| state = self.init_state(device=device) | |
| with torch.no_grad(): | |
| for token_id in prompt_ids[:-1]: | |
| x = torch.tensor([[token_id]], device=device) | |
| _, state = self.forward_step(x, state) | |
| x = torch.tensor([[prompt_ids[-1]]], device=device) | |
| for step in range(max_new): | |
| if progress_cb: | |
| self._block_outputs = [] | |
| logits, state = self.forward_step(x, state) | |
| logits = logits[0, 0] # squeeze from (1,1,vocab) -> (vocab) | |
| if progress_cb: | |
| progress_cb(step + 1, max_new, list(self._block_outputs), generated) | |
| self._block_outputs = None | |
| if repetition_penalty > 1.0: | |
| for tid in set(generated[-20:]): | |
| if logits[tid] > 0: | |
| logits[tid] /= repetition_penalty | |
| else: | |
| logits[tid] *= repetition_penalty | |
| logits = logits / temperature | |
| if top_k > 0: | |
| vals, _ = torch.topk(logits, min(top_k, logits.size(-1))) | |
| logits[logits < vals[-1]] = -float('Inf') | |
| probs = F.softmax(logits, dim=-1) | |
| next_id = torch.multinomial(probs, num_samples=1).item() | |
| generated.append(next_id) | |
| x = torch.tensor([[next_id]], device=device) | |
| if next_id == 2: | |
| break | |
| self._block_outputs = None | |
| return generated | |
| if __name__ == "__main__": | |
| model = RWKV(vocab_size=1024, hidden_size=128, num_layers=2) | |
| x = torch.randint(0, 1024, (2, 10)) | |
| logits, state = model(x) | |
| print(f"Output shape: {logits.shape}") | |
| print(f"Params: {sum(p.numel() for p in model.parameters()):,}") | |