import torch import math def RoPE(batch): B, L, D = batch.shape x1 = batch[..., 0::2] x2 = batch[..., 1::2] pos = torch.arange(L, device=batch.device) freqs = 10000 ** (-torch.arange(0, D, 2, device=batch.device) / D) angles = pos[:, None] * freqs[None, :] cos = torch.cos(angles).unsqueeze(0) sin = torch.sin(angles).unsqueeze(0) x1_rot = x1 * cos - x2 * sin x2_rot = x1 * sin + x2 * cos return torch.stack([x1_rot, x2_rot], dim=-1).flatten(-2) class SelfAttention(torch.nn.Module): def __init__(self, emb_size, head_size): super().__init__() self.C = math.sqrt(head_size) self.Query = torch.nn.Linear(emb_size, head_size, bias=False) self.Key = torch.nn.Linear(emb_size, head_size, bias=False) self.Value = torch.nn.Linear(emb_size, head_size, bias=False) def forward(self, x, mask=None): # x[batch_size, tok_size, emb_size], query, key, value = self.Query(x), self.Key(x), self.Value(x) #[batch, tok_size, head_size] query, key = RoPE(query), RoPE(key) internal_state = query @ key.transpose(-2, -1) #[batch, tok_size, tok_size] if mask is not None: internal_state = internal_state.masked_fill(~mask, float('-inf')) weights = torch.nn.functional.softmax(internal_state / self.C, dim=-1) #[batch, tok_size, tok_size] out = weights @ value return out # [batch, tok_size, head_size] class MultiHeadSelfAttention(torch.nn.Module): def __init__(self, emb_size, n_heads): super().__init__() head_size = emb_size // n_heads self.heads = torch.nn.ModuleList([SelfAttention(emb_size, head_size) for head in range(n_heads)]) self.Output = torch.nn.Linear(emb_size, emb_size, bias=False) def forward(self, x, mask=None): temporary_states = [head(x, mask) for head in self.heads] temporary_states = torch.cat(temporary_states, dim=-1) # [batch, tok_size, head_size] -> [batch, tok_size, emb_size] output = self.Output(temporary_states) return output # [batch, tok_size, emb_size] class FeedForward(torch.nn.Module): def __init__(self, emb_size, out_size=None): super().__init__() neurons = int((8 / 3) * emb_size) - (int((8 / 3) * emb_size) % 64) if out_size is None: out_size = emb_size self.W1 = torch.nn.Linear(emb_size, neurons, bias=False) self.SiLU = torch.nn.SiLU() self.W2 = torch.nn.Linear(emb_size, neurons, bias=False) self.W3 = torch.nn.Linear(neurons, out_size, bias=False) def forward(self, x): # [batch, tok_size, emb_size] hidden_state = self.SiLU(self.W1(x)) * self.W2(x) # [batch, tok_size, neurons] output = self.W3(hidden_state) return output # [batch, tok_size, out_size] class EncoderBlock(torch.nn.Module): def __init__(self, emb_size, n_heads): super().__init__() self.MultiHeadSelfAttention = MultiHeadSelfAttention(emb_size, n_heads) self.RMSNorm1 = torch.nn.RMSNorm(emb_size) self.FeedForward = FeedForward(emb_size) self.RMSNorm2 = torch.nn.RMSNorm(emb_size) def forward(self, context, mask): # [batch_size, context_tok_size, emb_size] # [batch_size, context_tok_size, emb_size] residual_connection1 = self.MultiHeadSelfAttention(self.RMSNorm1(context), mask) + context # [batch_size, context_tok_size, emb_size] residual_connection2 = self.FeedForward(self.RMSNorm2(residual_connection1)) + residual_connection1 return residual_connection2 # [batch_size, context_tok_size, emb_size] class Encoder(torch.nn.Module): def __init__(self, n_blocks, emb_size, n_heads): super().__init__() self.blocks = torch.nn.ModuleList([EncoderBlock(emb_size, n_heads) for block in range(n_blocks)]) self.RMSNorm = torch.nn.RMSNorm(emb_size) def forward(self, context, mask): internal_state = context for encoder in self.blocks: internal_state = encoder(internal_state, mask) output = self.RMSNorm(internal_state) return output # [batch_size, context_tok_size, emb_size] class Thinking(torch.nn.Module): def __init__(self, emb_size, internal_state_size=128, vocab_size=12288, momentum=0.1): super().__init__() self.momentum = momentum self.to_vocab = torch.nn.Linear(emb_size, vocab_size, bias=False) self.alpha = torch.nn.Parameter(torch.ones(vocab_size)) self.SiLU = torch.nn.SiLU() self.to_internal = torch.nn.Linear(vocab_size, internal_state_size, bias=False) self.ln = torch.nn.LayerNorm(internal_state_size) self.to_emb = torch.nn.Linear(internal_state_size, emb_size, bias=False) self.register_buffer("e_mean", torch.zeros(vocab_size)) self.t_in = torch.nn.Linear(vocab_size, internal_state_size, bias=False) self.t_ln = torch.nn.LayerNorm(internal_state_size) self.t_out = torch.nn.Linear(internal_state_size, emb_size, bias=False) def forward(self, x, mask_for_thinking, context_ids): # x [B, Cs, Emb], mask_for_thinking [B, Cs, 1], context_ids [B, Cs] x_unit = x / x.norm(dim=-1, keepdim=True).clamp(min=1e-6) vocab_unit = self.to_vocab.weight / self.to_vocab.weight.norm(dim=-1, keepdim=True).clamp(min=1e-6) energy = x_unit @ vocab_unit.T # [B, Cs, V], from -1 to 1 own = torch.zeros_like(energy, dtype=torch.bool).scatter_(2, context_ids[..., None], True) drop = (~mask_for_thinking) | own # padding + the position's own token kept = energy.masked_fill(drop, 0.0) # [B, Cs, V] # words channel internal_state = kept * self.alpha internal_state = self.to_internal(internal_state) internal_state = self.ln(internal_state) internal_state = self.SiLU(internal_state) words = self.to_emb(internal_state) # [B, Cs, Emb] # thought channel e = kept.sum(dim=1).float() # [B, V]: sum of energies over positions if self.training: mu = e.mean(dim=0) # mean over texts in the batch with torch.no_grad(): self.e_mean.mul_(1 - self.momentum).add_(self.momentum * mu) else: mu = self.e_mean # inference: running mean e = e - mu # how this text differs from the others e = e / e.pow(2).mean(dim=-1, keepdim=True).sqrt().clamp(min=1e-6) # unit scale thought = self.t_in(e) thought = self.t_ln(thought) thought = self.SiLU(thought) thought = self.t_out(thought) # [B, Emb] thinking_out = words + thought.unsqueeze(1) # thought is added to every position return thinking_out class CrossAttention(torch.nn.Module): def __init__(self, emb_size, head_size): super().__init__() self.C = math.sqrt(head_size) self.Query = torch.nn.Linear(emb_size, head_size, bias=False) self.Key = torch.nn.Linear(emb_size, head_size, bias=False) self.Value = torch.nn.Linear(emb_size, head_size, bias=False) def forward(self, data_for_query, data_for_key_value, mask=None): # data_for_query[batch, answer_tok_size, emb_size] # data_for_key_value[batch, context_tok_size, emb_size] query, key, value = self.Query(data_for_query), self.Key(data_for_key_value), self.Value(data_for_key_value) # query[batch, answer_tok_size, head_size] # key, value[batch, context_tok_size, head_size] internal_state = query @ key.transpose(-2, -1) #[batch, answer_tok_size, context_tok_size] if mask is not None: internal_state = internal_state.masked_fill(~mask, float('-inf')) weights = torch.nn.functional.softmax(internal_state / self.C, dim=-1) out = weights @ value return out #[batch, answer_tok_size, head_size] class MultiHeadCrossAttention(torch.nn.Module): def __init__(self, emb_size, n_heads): super().__init__() head_size = emb_size // n_heads self.heads = torch.nn.ModuleList([CrossAttention(emb_size, head_size) for head in range(n_heads)]) self.Output = torch.nn.Linear(emb_size, emb_size, bias=False) def forward(self, data_for_query, data_for_key_value, mask=None): temporary_states = [head(data_for_query, data_for_key_value, mask) for head in self.heads] temporary_states = torch.cat(temporary_states, dim=-1) # [batch, answer_tok_size, head_size] -> [batch, answer_tok_size, emb_size] output = self.Output(temporary_states) return output # [batch, answer_tok_size, emb_size] class DecoderBlock(torch.nn.Module): def __init__(self, emb_size, n_heads): super().__init__() self.MultiHeadSelfAttention = MultiHeadSelfAttention(emb_size, n_heads) self.RMSNorm1 = torch.nn.RMSNorm(emb_size) self.MultiHeadCrossAttention = MultiHeadCrossAttention(emb_size, n_heads) self.RMSNorm2 = torch.nn.RMSNorm(emb_size) self.RMSNorm3 = torch.nn.RMSNorm(emb_size) self.FeedForward = FeedForward(emb_size) def forward(self, encoder_output, answer, encoder_mask=None): # [batch, answer_tok_size, emb_size] internal_state = self.MultiHeadSelfAttention(self.RMSNorm1(answer)) residual_connection1 = internal_state + answer internal_state = self.MultiHeadCrossAttention( self.RMSNorm2(residual_connection1), encoder_output, encoder_mask) # [batch, answer_tok_size, emb_size] residual_connection2 = internal_state + residual_connection1 internal_state = self.FeedForward(self.RMSNorm3(residual_connection2)) residual_connection3 = internal_state + residual_connection2 # [batch, answer_tok_size, emb_size] return residual_connection3 # [batch, answer_tok_size, emb_size] class Decoder(torch.nn.Module): def __init__(self, n_blocks, emb_size, n_heads): super().__init__() self.blocks = torch.nn.ModuleList([DecoderBlock(emb_size, n_heads) for block in range(n_blocks)]) self.RMSNorm = torch.nn.RMSNorm(emb_size) self.final = torch.nn.Linear(emb_size, 12288, bias=False) def forward(self, answer, encoder_output, mask): internal_state = answer for decoder in self.blocks: internal_state = decoder(encoder_output, internal_state, mask) # [batch_size, answer_size, emb_size] internal_state = self.RMSNorm(internal_state) internal_state = self.final(internal_state) return internal_state # [batch_size, answer_size, dict_size] class NN_Thinking(torch.nn.Module): def _init_weights(self, m): if isinstance(m, (torch.nn.Linear, torch.nn.Embedding)): torch.nn.init.normal_(m.weight, mean=0.0, std=0.02) def __init__(self, embedding_size, encoder_num, heads_encoder, thinking_internal_state_size, decoder_num, heads_decoder): super().__init__() self.Embedding = torch.nn.Embedding(12288, embedding_size) self.Encoder = Encoder(encoder_num, embedding_size, heads_encoder) self.Thinking = Thinking(embedding_size, thinking_internal_state_size) self.Thinking.to_vocab.weight = self.Embedding.weight self.out_norm = torch.nn.RMSNorm(embedding_size) self.Decoder = Decoder(decoder_num, embedding_size, heads_decoder) self.Decoder.final.weight = self.Embedding.weight self.apply(self._init_weights) torch.nn.init.zeros_(self.Thinking.t_out.weight) def encode(self, context_ids): # context_ids [B, Cs] PAD_ID = 0 mask = (context_ids != PAD_ID)[:, None, :] # [B, 1, Cs] memory = self.Encoder(self.Embedding(context_ids), mask) # [B, Cs, Emb] memory = self.Thinking(memory, mask.transpose(1, 2), context_ids) memory = self.out_norm(memory) return memory, mask def decode(self, answer_ids, memory, mask): return self.Decoder(self.Embedding(answer_ids), memory, mask) # [B, La, V] def forward(self, context_ids, answer_ids): memory, mask = self.encode(context_ids) return self.decode(answer_ids, memory, mask)