| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import os |
| import math |
| from dataclasses import dataclass |
| from typing import List, Optional, Tuple, Union |
|
|
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
|
|
| from transformers.modeling_utils import PreTrainedModel |
| from transformers.utils import ModelOutput |
| from transformers.generation import GenerationMixin |
|
|
| try: |
| from .configuration_rwkv7 import RWKV7Config |
| except ImportError: |
| from configuration_rwkv7 import RWKV7Config |
|
|
|
|
| |
| LayerState = Tuple[torch.Tensor, torch.Tensor, torch.Tensor] |
|
|
|
|
| |
| |
| |
|
|
|
|
| @dataclass |
| class RWKV7Output(ModelOutput): |
| last_hidden_state: torch.FloatTensor = None |
| state: Optional[List[LayerState]] = None |
| hidden_states: Optional[Tuple[torch.FloatTensor, ...]] = None |
|
|
|
|
| @dataclass |
| class RWKV7CausalLMOutput(ModelOutput): |
| loss: Optional[torch.FloatTensor] = None |
| logits: torch.FloatTensor = None |
| state: Optional[List[LayerState]] = None |
| hidden_states: Optional[Tuple[torch.FloatTensor, ...]] = None |
|
|
|
|
| |
| |
| |
| |
|
|
| _KERNEL_STATE = {"loaded": False, "ok": False, "op": None, "chunk_len": 16, "head_size": 64} |
|
|
|
|
| def _try_load_cuda_kernel(head_size: int, chunk_len: int): |
| """Compile & register the wind_backstepping RWKV-7 CUDA op. Returns True on success.""" |
| if _KERNEL_STATE["loaded"]: |
| return _KERNEL_STATE["ok"] |
| _KERNEL_STATE["loaded"] = True |
| _KERNEL_STATE["head_size"] = head_size |
| _KERNEL_STATE["chunk_len"] = chunk_len |
|
|
| if not torch.cuda.is_available(): |
| _KERNEL_STATE["ok"] = False |
| return False |
|
|
| try: |
| from torch.utils.cpp_extension import load |
|
|
| this_dir = os.path.dirname(os.path.abspath(__file__)) |
| cuda_dir = os.path.join(this_dir, "cuda") |
| sources = [ |
| os.path.join(cuda_dir, "wkv7_op.cpp"), |
| os.path.join(cuda_dir, "wkv7_cuda.cu"), |
| ] |
| print(sources) |
| print([os.path.exists(s) for s in sources]) |
| if not all(os.path.exists(s) for s in sources): |
|
|
| _KERNEL_STATE["ok"] = False |
| return False |
|
|
| flags = [ |
| "-res-usage", |
| f"-D_C_={head_size}", |
| f"-D_CHUNK_LEN_={chunk_len}", |
| "--use_fast_math", |
| "-O3", |
| "-Xptxas -O3", |
| "--extra-device-vectorization", |
| ] |
| load( |
| name=f"wind_backstepping_c{head_size}_l{chunk_len}", |
| sources=sources, |
| is_python_module=False, |
| verbose=False, |
| extra_cuda_cflags=flags, |
| ) |
| _KERNEL_STATE["op"] = torch.ops.wind_backstepping |
| _KERNEL_STATE["ok"] = True |
| return True |
| except Exception as e: |
| print(f"[RWKV7] CUDA kernel unavailable, using PyTorch fallback ({type(e).__name__}: {e})") |
| import traceback |
|
|
| traceback.print_exc() |
| _KERNEL_STATE["ok"] = False |
| return False |
|
|
|
|
| |
| |
| _KERNEL_S_STATE = {"loaded": False, "ok": False, "op": None, "head_size": 64} |
|
|
|
|
| def _try_load_cuda_kernel_s(head_size: int): |
| """Compile & register the wkv7s stateful RWKV-7 CUDA op. Returns True on success.""" |
| if _KERNEL_S_STATE["loaded"]: |
| return _KERNEL_S_STATE["ok"] |
| _KERNEL_S_STATE["loaded"] = True |
| _KERNEL_S_STATE["head_size"] = head_size |
|
|
| if not torch.cuda.is_available(): |
| _KERNEL_S_STATE["ok"] = False |
| return False |
|
|
| try: |
| from torch.utils.cpp_extension import load |
|
|
| this_dir = os.path.dirname(os.path.abspath(__file__)) |
| cuda_dir = os.path.join(this_dir, "cuda") |
| sources = [ |
| os.path.join(cuda_dir, "wkv7s_op.cpp"), |
| os.path.join(cuda_dir, "wkv7s.cu"), |
| ] |
| if not all(os.path.exists(s) for s in sources): |
| _KERNEL_S_STATE["ok"] = False |
| return False |
|
|
| flags = [ |
| "-res-usage", |
| f"-D_N_={head_size}", |
| "--use_fast_math", |
| "-O3", |
| "-Xptxas -O3", |
| "--extra-device-vectorization", |
| ] |
| load( |
| name=f"wkv7s_n{head_size}", |
| sources=sources, |
| is_python_module=False, |
| verbose=False, |
| extra_cuda_cflags=flags, |
| ) |
| _KERNEL_S_STATE["op"] = torch.ops.wkv7s |
| _KERNEL_S_STATE["ok"] = True |
| return True |
| except Exception as e: |
| print(f"[RWKV7] stateful CUDA kernel unavailable, using PyTorch fallback ({type(e).__name__}: {e})") |
| _KERNEL_S_STATE["ok"] = False |
| return False |
|
|
|
|
| class _WindBackstepping(torch.autograd.Function): |
| """Fused RWKV-7 kernel wrapper (bf16). Implements both forward and backward. |
| Inputs are shaped (B, T, H, C) with T % CHUNK_LEN == 0 and dtype bfloat16. |
| NOTE: the kernel always starts from a zero WKV state and does not expose the |
| final state, so it is only used on the no-cache (training / plain forward) path. |
| """ |
|
|
| @staticmethod |
| def forward(ctx, w, q, k, v, z, b): |
| op = _KERNEL_STATE["op"] |
| chunk_len = _KERNEL_STATE["chunk_len"] |
| B, T, H, C = w.shape |
| assert T % chunk_len == 0, "pad T to a multiple of CHUNK_LEN" |
| assert all(i.dtype == torch.bfloat16 for i in [w, q, k, v, z, b]) |
| assert all(i.is_contiguous() for i in [w, q, k, v, z, b]) |
| y = torch.empty_like(v) |
| s = torch.empty(B, H, T // chunk_len, C, C, dtype=torch.float32, device=w.device) |
| sa = torch.empty(B, T, H, C, dtype=torch.float32, device=w.device) |
| op.forward(w, q, k, v, z, b, y, s, sa) |
| ctx.save_for_backward(w, q, k, v, z, b, s, sa) |
| return y |
|
|
| @staticmethod |
| def backward(ctx, dy): |
| op = _KERNEL_STATE["op"] |
| assert dy.dtype == torch.bfloat16 |
| dy = dy.contiguous() |
| w, q, k, v, z, b, s, sa = ctx.saved_tensors |
| dw, dq, dk, dv, dz, db = [torch.empty_like(x) for x in [w, q, k, v, z, b]] |
| op.backward(w, q, k, v, z, b, dy, s, sa, dw, dq, dk, dv, dz, db) |
| return dw, dq, dk, dv, dz, db |
|
|
|
|
| def _rwkv7_cuda(r, w, k, v, a, b, head_size, chunk_len): |
| """CUDA path. r,w,k,v,a,b are (B, T, C) bf16. a = -kk, b = kk*a_gate.""" |
| B, T, C = r.shape |
| H = C // head_size |
| pad = (chunk_len - T % chunk_len) % chunk_len |
| if pad: |
| r, w, k, v, a, b = [F.pad(x, (0, 0, 0, pad)) for x in (r, w, k, v, a, b)] |
| Tp = T + pad |
| r, w, k, v, a, b = [x.view(B, Tp, H, head_size).contiguous() for x in (r, w, k, v, a, b)] |
| y = _WindBackstepping.apply(w, r, k, v, a, b).view(B, Tp, C) |
| if pad: |
| y = y[:, :T] |
| return y |
|
|
|
|
| def _rwkv7_cuda_stateful(r, w, k, v, a, b, head_size, initial_state=None): |
| """Stateful CUDA path (wkv7s kernel). Forward-only (no backward), any T, |
| no chunk padding needed. The kernel updates the fp32 state in place, so we |
| always hand it a fresh tensor and return it as the final state.""" |
| op = _KERNEL_S_STATE["op"] |
| B, T, C = r.shape |
| H = C // head_size |
| N = head_size |
| if initial_state is not None: |
| state = initial_state.to(device=r.device, dtype=torch.float32).contiguous().clone() |
| else: |
| state = torch.zeros(B, H, N, N, dtype=torch.float32, device=r.device) |
| r, w, k, v, a, b = [x.contiguous() for x in (r, w, k, v, a, b)] |
| y = torch.empty_like(v) |
| op.forward(B, T, C, H, state, r, w, k, v, a, b, y) |
| return y, state |
|
|
|
|
| def _rwkv7_pytorch(r, w, k, v, a, b, head_size, initial_state=None, output_final_state=False): |
| """Pure-PyTorch reference (sequential over time). Differentiable via autograd. |
| w is the raw (pre-exp) log-decay; the recurrence uses exp(-exp(w)). |
| Supports an initial WKV state and optionally returns the final state, |
| which is what enables cached (RNN-mode) generation. |
| """ |
| B, T, C = r.size() |
| H = C // head_size |
| N = head_size |
| dtype_in = r.dtype |
| r = r.view(B, T, H, N).float() |
| k = k.view(B, T, H, N).float() |
| v = v.view(B, T, H, N).float() |
| a = a.view(B, T, H, N).float() |
| b = b.view(B, T, H, N).float() |
| w = torch.exp(-torch.exp(w.view(B, T, H, N).float())) |
|
|
| out = torch.zeros((B, T, H, N), device=r.device, dtype=torch.float32) |
| if initial_state is not None: |
| state = initial_state.to(device=r.device, dtype=torch.float32) |
| else: |
| state = torch.zeros((B, H, N, N), device=r.device, dtype=torch.float32) |
| for t in range(T): |
| kk = k[:, t, :].view(B, H, 1, N) |
| rr = r[:, t, :].view(B, H, N, 1) |
| vv = v[:, t, :].view(B, H, N, 1) |
| aa = a[:, t, :].view(B, H, N, 1) |
| bb = b[:, t, :].view(B, H, 1, N) |
| state = state * w[:, t, :, None, :] + state @ aa @ bb + vv @ kk |
| out[:, t, :] = (state @ rr).view(B, H, N) |
| final_state = state if output_final_state else None |
| return out.view(B, T, C).to(dtype=dtype_in), final_state |
|
|
|
|
| def run_rwkv7( |
| r, w, k, v, a, b, config, |
| initial_state=None, |
| output_final_state=False, |
| force_fallback=False, |
| ): |
|
|
| stateful = initial_state is not None or output_final_state |
|
|
| common_ok = ( |
| config.use_cuda_kernel |
| and not force_fallback |
| and r.is_cuda |
| and r.dtype == torch.bfloat16 |
| ) |
|
|
| print( |
| "RWKV7 DEBUG:", |
| "stateful=", stateful, |
| "common_ok=", common_ok, |
| "cuda=", r.is_cuda, |
| "dtype=", r.dtype, |
| "use_kernel=", config.use_cuda_kernel, |
| "force=", force_fallback, |
| "kernel_loaded=", _KERNEL_STATE["loaded"], |
| "kernel_ok=", _KERNEL_STATE["ok"], |
| ) |
|
|
| if not stateful: |
| if common_ok and _try_load_cuda_kernel(config.head_size, config.chunk_len): |
| print("USING CUDA KERNEL") |
| return _rwkv7_cuda( |
| r,w,k,v,a,b, |
| config.head_size, |
| config.chunk_len |
| ) ,None |
|
|
| print("USING PYTORCH FALLBACK") |
| return _rwkv7_pytorch( |
| r, w, k, v, a, b, config.head_size, |
| initial_state=initial_state, output_final_state=output_final_state, |
| ) |
|
|
|
|
| |
| |
| |
|
|
|
|
| class RWKV7TimeMix(nn.Module): |
| def __init__(self, config: RWKV7Config, layer_id: int): |
| super().__init__() |
| self.config = config |
| self.layer_id = layer_id |
| self.head_size = config.head_size |
| C = config.hidden_size |
| self.n_head = C // self.head_size |
| H, N = self.n_head, self.head_size |
|
|
| self.x_r = nn.Parameter(torch.empty(1, 1, C)) |
| self.x_w = nn.Parameter(torch.empty(1, 1, C)) |
| self.x_k = nn.Parameter(torch.empty(1, 1, C)) |
| self.x_v = nn.Parameter(torch.empty(1, 1, C)) |
| self.x_a = nn.Parameter(torch.empty(1, 1, C)) |
| self.x_g = nn.Parameter(torch.empty(1, 1, C)) |
|
|
| self.w0 = nn.Parameter(torch.empty(1, 1, C)) |
| self.w1 = nn.Parameter(torch.empty(C, config.decay_lora)) |
| self.w2 = nn.Parameter(torch.empty(config.decay_lora, C)) |
|
|
| self.a0 = nn.Parameter(torch.empty(1, 1, C)) |
| self.a1 = nn.Parameter(torch.empty(C, config.aaa_lora)) |
| self.a2 = nn.Parameter(torch.empty(config.aaa_lora, C)) |
|
|
| self.v0 = nn.Parameter(torch.empty(1, 1, C)) |
| self.v1 = nn.Parameter(torch.empty(C, config.mv_lora)) |
| self.v2 = nn.Parameter(torch.empty(config.mv_lora, C)) |
|
|
| self.g1 = nn.Parameter(torch.empty(C, config.gate_lora)) |
| self.g2 = nn.Parameter(torch.empty(config.gate_lora, C)) |
|
|
| self.k_k = nn.Parameter(torch.empty(1, 1, C)) |
| self.k_a = nn.Parameter(torch.empty(1, 1, C)) |
| self.r_k = nn.Parameter(torch.empty(H, N)) |
|
|
| self.time_shift = nn.ZeroPad2d((0, 0, 1, -1)) |
| self.receptance = nn.Linear(C, C, bias=False) |
| self.key = nn.Linear(C, C, bias=False) |
| self.value = nn.Linear(C, C, bias=False) |
| self.output = nn.Linear(C, C, bias=False) |
| self.ln_x = nn.GroupNorm(H, C, eps=config.group_norm_epsilon) |
|
|
| def forward(self, x, v_first, x_prev=None, wkv_state=None, use_cache=False): |
| """x_prev: (B, C) last input token from the previous chunk (post-ln1), |
| wkv_state: (B, H, N, N) float32 WKV state from the previous chunk.""" |
| B, T, C = x.size() |
| H = self.n_head |
|
|
| if x_prev is None: |
| shifted = self.time_shift(x) |
| else: |
| shifted = torch.cat([x_prev.to(x.dtype).unsqueeze(1), x[:, :-1]], dim=1) |
| xx = shifted - x |
| new_x_prev = x[:, -1] if use_cache else None |
|
|
| xr = x + xx * self.x_r |
| xw = x + xx * self.x_w |
| xk = x + xx * self.x_k |
| xv = x + xx * self.x_v |
| xa = x + xx * self.x_a |
| xg = x + xx * self.x_g |
|
|
| r = self.receptance(xr) |
| |
| w = -F.softplus(-(self.w0 + torch.tanh(xw @ self.w1) @ self.w2)) - 0.5 |
| k = self.key(xk) |
| v = self.value(xv) |
| if self.layer_id == 0: |
| v_first = v |
| else: |
| v = v + (v_first - v) * torch.sigmoid(self.v0 + (xv @ self.v1) @ self.v2) |
| a = torch.sigmoid(self.a0 + (xa @ self.a1) @ self.a2) |
| g = torch.sigmoid(xg @ self.g1) @ self.g2 |
|
|
| kk = k * self.k_k |
| kk = F.normalize(kk.view(B, T, H, -1), dim=-1, p=2.0).view(B, T, C) |
| k = k * (1 + (a - 1) * self.k_a) |
|
|
| x, new_wkv_state = run_rwkv7( |
| r, w, k, v, -kk, kk * a, self.config, |
| initial_state=wkv_state, output_final_state=use_cache, |
| ) |
| x = self.ln_x(x.view(B * T, C)).view(B, T, C) |
|
|
| x = x + ( |
| (r.view(B, T, H, -1) * k.view(B, T, H, -1) * self.r_k).sum(dim=-1, keepdim=True) |
| * v.view(B, T, H, -1) |
| ).view(B, T, C) |
| x = self.output(x * g) |
| return x, v_first, new_x_prev, new_wkv_state |
|
|
|
|
| |
| |
| |
|
|
|
|
| class RWKV7ChannelMix(nn.Module): |
| def __init__(self, config: RWKV7Config, layer_id: int): |
| super().__init__() |
| self.layer_id = layer_id |
| self.time_shift = nn.ZeroPad2d((0, 0, 1, -1)) |
| self.x_k = nn.Parameter(torch.empty(1, 1, config.hidden_size)) |
| self.key = nn.Linear(config.hidden_size, config.intermediate_size, bias=False) |
| self.value = nn.Linear(config.intermediate_size, config.hidden_size, bias=False) |
|
|
| def forward(self, x, x_prev=None, use_cache=False): |
| """x_prev: (B, C) last input token from the previous chunk (post-ln2).""" |
| if x_prev is None: |
| shifted = self.time_shift(x) |
| else: |
| shifted = torch.cat([x_prev.to(x.dtype).unsqueeze(1), x[:, :-1]], dim=1) |
| xx = shifted - x |
| new_x_prev = x[:, -1] if use_cache else None |
| k = x + xx * self.x_k |
| k = torch.relu(self.key(k)) ** 2 |
| return self.value(k), new_x_prev |
|
|
|
|
| class RWKV7Block(nn.Module): |
| def __init__(self, config: RWKV7Config, layer_id: int): |
| super().__init__() |
| self.layer_id = layer_id |
| eps = config.layer_norm_epsilon |
| if layer_id == 0: |
| self.ln0 = nn.LayerNorm(config.hidden_size, eps=eps) |
| self.ln1 = nn.LayerNorm(config.hidden_size, eps=eps) |
| self.ln2 = nn.LayerNorm(config.hidden_size, eps=eps) |
| self.att = RWKV7TimeMix(config, layer_id) |
| self.ffn = RWKV7ChannelMix(config, layer_id) |
|
|
| def forward(self, x, v_first, layer_state: Optional[LayerState] = None, use_cache: bool = False): |
| if self.layer_id == 0: |
| x = self.ln0(x) |
|
|
| if layer_state is not None: |
| att_x_prev, wkv_state, ffn_x_prev = layer_state |
| else: |
| att_x_prev = wkv_state = ffn_x_prev = None |
|
|
| x_attn, v_first, att_x_prev, wkv_state = self.att( |
| self.ln1(x), v_first, x_prev=att_x_prev, wkv_state=wkv_state, use_cache=use_cache |
| ) |
| x = x + x_attn |
|
|
| ffn_out, ffn_x_prev = self.ffn(self.ln2(x), x_prev=ffn_x_prev, use_cache=use_cache) |
| x = x + ffn_out |
|
|
| new_state = (att_x_prev, wkv_state, ffn_x_prev) if use_cache else None |
| return x, v_first, new_state |
|
|
|
|
| |
| |
| |
|
|
|
|
| class RWKV7PreTrainedModel(PreTrainedModel): |
| config_class = RWKV7Config |
| base_model_prefix = "rwkv" |
| supports_gradient_checkpointing = True |
| _no_split_modules = ["RWKV7Block"] |
|
|
| def _init_weights(self, module): |
| |
| |
| if isinstance(module, nn.Linear): |
| module.weight.data.normal_(mean=0.0, std=0.02) |
| if module.bias is not None: |
| module.bias.data.zero_() |
| elif isinstance(module, nn.Embedding): |
| module.weight.data.normal_(mean=0.0, std=1e-4) |
| elif isinstance(module, nn.LayerNorm): |
| module.weight.data.fill_(1.0) |
| module.bias.data.zero_() |
|
|
|
|
| class RWKV7Model(RWKV7PreTrainedModel): |
| def __init__(self, config: RWKV7Config): |
| super().__init__(config) |
| self.config = config |
| self.emb = nn.Embedding(config.vocab_size, config.hidden_size) |
| self.blocks = nn.ModuleList( |
| [RWKV7Block(config, i) for i in range(config.num_hidden_layers)] |
| ) |
| self.ln_out = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_epsilon) |
| self.gradient_checkpointing = False |
| self.post_init() |
|
|
| def get_input_embeddings(self): |
| return self.emb |
|
|
| def set_input_embeddings(self, value): |
| self.emb = value |
|
|
| def forward( |
| self, |
| input_ids: Optional[torch.LongTensor] = None, |
| inputs_embeds: Optional[torch.FloatTensor] = None, |
| state: Optional[List[LayerState]] = None, |
| use_cache: Optional[bool] = None, |
| output_hidden_states: Optional[bool] = None, |
| return_dict: Optional[bool] = None, |
| **kwargs, |
| ) -> Union[Tuple, RWKV7Output]: |
| return_dict = return_dict if return_dict is not None else True |
| output_hidden_states = ( |
| output_hidden_states |
| if output_hidden_states is not None |
| else self.config.output_hidden_states |
| ) |
| use_cache = ( |
| use_cache if use_cache is not None else getattr(self.config, "use_cache", False) |
| ) |
| if state is not None: |
| use_cache = True |
| if self.gradient_checkpointing and self.training and use_cache: |
| use_cache = False |
|
|
| if inputs_embeds is None: |
| inputs_embeds = self.emb(input_ids) |
| x = inputs_embeds |
|
|
| all_hidden_states = () if output_hidden_states else None |
| new_states: Optional[List[LayerState]] = [] if use_cache else None |
| v_first = torch.empty_like(x) |
| for i, block in enumerate(self.blocks): |
| if output_hidden_states: |
| all_hidden_states += (x,) |
| layer_state = state[i] if state is not None else None |
| if self.gradient_checkpointing and self.training: |
| x, v_first, layer_new_state = self._gradient_checkpointing_func( |
| block.__call__, x, v_first, layer_state, use_cache |
| ) |
| else: |
| x, v_first, layer_new_state = block(x, v_first, layer_state, use_cache) |
| if use_cache: |
| new_states.append(layer_new_state) |
|
|
| x = self.ln_out(x) |
| if output_hidden_states: |
| all_hidden_states += (x,) |
|
|
| if not return_dict: |
| return tuple(v for v in [x, new_states, all_hidden_states] if v is not None) |
| return RWKV7Output( |
| last_hidden_state=x, |
| state=new_states, |
| hidden_states=all_hidden_states, |
| ) |
|
|
|
|
| class RWKV7ForCausalLM(RWKV7PreTrainedModel, GenerationMixin): |
| _tied_weights_keys = [] |
|
|
| def __init__(self, config: RWKV7Config): |
| super().__init__(config) |
| self.rwkv = RWKV7Model(config) |
| self.head = nn.Linear(config.hidden_size, config.vocab_size, bias=False) |
| self.post_init() |
|
|
| def get_input_embeddings(self): |
| return self.rwkv.emb |
|
|
| def set_input_embeddings(self, value): |
| self.rwkv.emb = value |
|
|
| def get_output_embeddings(self): |
| return self.head |
|
|
| def set_output_embeddings(self, new_embeddings): |
| self.head = new_embeddings |
|
|
| def get_decoder(self): |
| return self.rwkv |
|
|
| def forward( |
| self, |
| input_ids: Optional[torch.LongTensor] = None, |
| inputs_embeds: Optional[torch.FloatTensor] = None, |
| state: Optional[List[LayerState]] = None, |
| use_cache: Optional[bool] = None, |
| labels: Optional[torch.LongTensor] = None, |
| output_hidden_states: Optional[bool] = None, |
| return_dict: Optional[bool] = None, |
| **kwargs, |
| ) -> Union[Tuple, RWKV7CausalLMOutput]: |
| return_dict = return_dict if return_dict is not None else True |
|
|
| outputs = self.rwkv( |
| input_ids=input_ids, |
| inputs_embeds=inputs_embeds, |
| state=state, |
| use_cache=use_cache, |
| output_hidden_states=output_hidden_states, |
| return_dict=True, |
| ) |
| hidden = outputs.last_hidden_state |
| logits = self.head(hidden) |
|
|
| loss = None |
| if labels is not None: |
| labels = labels.to(logits.device) |
| shift_logits = logits[:, :-1, :].contiguous() |
| shift_labels = labels[:, 1:].contiguous() |
| loss = F.cross_entropy( |
| shift_logits.view(-1, shift_logits.size(-1)).float(), |
| shift_labels.view(-1), |
| ) |
|
|
| if not return_dict: |
| output = (logits, outputs.state, outputs.hidden_states) |
| output = tuple(v for v in output if v is not None) |
| return ((loss,) + output) if loss is not None else output |
|
|
| return RWKV7CausalLMOutput( |
| loss=loss, |
| logits=logits, |
| state=outputs.state, |
| hidden_states=outputs.hidden_states, |
| ) |
|
|
| def prepare_inputs_for_generation( |
| self, input_ids, state=None, inputs_embeds=None, use_cache=True, **kwargs |
| ): |
| |
| |
| if state is not None: |
| input_ids = input_ids[:, -1:] |
| model_inputs = {"input_ids": input_ids} |
| elif inputs_embeds is not None: |
| model_inputs = {"inputs_embeds": inputs_embeds} |
| else: |
| model_inputs = {"input_ids": input_ids} |
| model_inputs["state"] = state |
| model_inputs["use_cache"] = use_cache |
| return model_inputs |
|
|
| def _update_model_kwargs_for_generation(self, outputs, model_kwargs, **kwargs): |
| |
| |
| model_kwargs = super()._update_model_kwargs_for_generation(outputs, model_kwargs, **kwargs) |
| model_kwargs["state"] = getattr(outputs, "state", None) |
| return model_kwargs |
|
|