ChessDumb / modeling_dumbc.py
56m's picture
Upload folder using huggingface_hub
34aa9f1 verified
Raw
History Blame Contribute Delete
6.07 kB
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from transformers import PreTrainedModel
# リモート読み込みとローカル直接インポートの両方に対応する互換インポート
try:
from .configuration_dumbc import DumbcConfig
except ImportError:
from configuration_dumbc import DumbcConfig
class DumbChessRetina(nn.Module):
def __init__(self, dim=192):
super().__init__()
self.piece_embed = nn.Embedding(14, 32)
self.conv_rank_file = nn.Conv1d(32, 32, kernel_size=3, padding=1, groups=32)
self.conv_diag = nn.Conv1d(32, 32, kernel_size=3, padding=1, groups=32)
self.conv_antidiag = nn.Conv1d(32, 32, kernel_size=3, padding=1, groups=32)
self.conv_knight = nn.Conv1d(32, 32, kernel_size=3, padding=1, groups=32)
self.tension_mlp = nn.Sequential(
nn.Linear(32 * 4 + 1, 64),
nn.GELU(),
nn.Linear(64, dim)
)
def forward(self, board_state, material_weights):
x = self.piece_embed(board_state)
x_t = x.transpose(1, 2)
f1 = self.conv_rank_file(x_t)
f2 = self.conv_diag(x_t)
f3 = self.conv_antidiag(x_t)
f4 = self.conv_knight(x_t)
f_all = torch.cat([f1, f2, f3, f4], dim=1).transpose(1, 2)
tension_in = torch.cat([f_all, material_weights.unsqueeze(-1)], dim=-1)
return self.tension_mlp(tension_in)
class DumbAttention(nn.Module):
def __init__(self, dim=192, heads=8, bottleneck=32):
super().__init__()
self.dim = dim
self.heads = heads
self.head_dim = dim // heads
self.qkv_proj = nn.Linear(dim, dim * 3, bias=False)
self.out_proj = nn.Linear(dim, dim, bias=False)
self.hadamard_mlp = nn.Sequential(
nn.Linear(dim, bottleneck),
nn.SiLU(),
nn.Linear(bottleneck, 1)
)
self.trinity_g = nn.Linear(dim, 16, bias=False)
self.temp_mlp = nn.Sequential(
nn.Linear(dim, 16),
nn.SiLU(),
nn.Linear(16, 1)
)
self.threat_weight = nn.Parameter(torch.ones(1) * 0.5)
def forward(self, x, mat_diff_matrix):
B, N, C = x.shape
q, k, v = self.qkv_proj(x).chunk(3, dim=-1)
q_h = q.view(B, N, self.heads, self.head_dim).transpose(1, 2)
k_h = k.view(B, N, self.heads, self.head_dim).transpose(1, 2)
v_h = v.view(B, N, self.heads, self.head_dim).transpose(1, 2)
S_base = (q_h @ k_h.transpose(-2, -1)) / math.sqrt(self.head_dim)
q_k_hadamard = q.unsqueeze(2) * k.unsqueeze(1)
S_tensor = self.hadamard_mlp(q_k_hadamard).squeeze(-1).unsqueeze(1)
g_q = torch.sigmoid(self.trinity_g(q))
g_k = torch.sigmoid(self.trinity_g(k))
S_trinity = (g_q @ g_k.transpose(-2, -1)).unsqueeze(1)
B_material = F.relu(mat_diff_matrix).unsqueeze(1) * self.threat_weight
tau = torch.sigmoid(self.temp_mlp(x.mean(dim=1))) * 0.5 + 0.75
tau = tau.unsqueeze(-1).unsqueeze(-1)
S_total = (S_base + S_tensor + S_trinity + B_material) / tau
A = F.softmax(S_total, dim=-1)
out = (A @ v_h).transpose(1, 2).reshape(B, N, C)
return self.out_proj(out)
class DumbFractalFFN(nn.Module):
def __init__(self, dim=192, hidden_dim=288):
super().__init__()
self.w1 = nn.Linear(dim, hidden_dim, bias=False)
self.w2 = nn.Linear(dim, hidden_dim, bias=False)
self.w3 = nn.Linear(hidden_dim, dim, bias=False)
def forward(self, x):
h1 = F.silu(self.w1(x))
h2 = self.w2(x)
chunk_size = h2.shape[-1] // 2
h2_a, h2_b = torch.split(h2, chunk_size, dim=-1)
fractal_interaction = torch.cat([h2_a * h2_b, h2_b**2], dim=-1)
return self.w3(h1 * fractal_interaction)
class DumbBlock(nn.Module):
def __init__(self, dim=192):
super().__init__()
self.norm1 = nn.LayerNorm(dim)
self.attn = DumbAttention(dim=dim)
self.norm2 = nn.LayerNorm(dim)
self.ffn = DumbFractalFFN(dim=dim)
self.gate = nn.Parameter(torch.ones(1) * 0.1)
def forward(self, x, mat_diff_matrix):
x = x + self.gate * self.attn(self.norm1(x), mat_diff_matrix)
x = x + self.gate * self.ffn(self.norm2(x))
return x
class DumbcPreTrainedModel(PreTrainedModel):
config_class = DumbcConfig
base_model_prefix = "dumbc"
def _init_weights(self, module):
if isinstance(module, (nn.Linear, nn.Conv1d)):
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
if module.bias is not None:
module.bias.data.zero_()
class DumbcModel(DumbcPreTrainedModel):
def __init__(self, config):
super().__init__(config)
self.config = config
self.retina = DumbChessRetina(dim=config.dim)
self.layers = nn.ModuleList([DumbBlock(dim=config.dim) for _ in range(config.num_unique_layers)])
self.step_embed = nn.Parameter(torch.randn(config.num_loops, 1, 1, config.dim) * 0.02)
self.from_head = nn.Linear(config.dim, 64)
self.to_head = nn.Linear(config.dim, 64)
self.value_head = nn.Sequential(
nn.Linear(config.dim, 64),
nn.GELU(),
nn.Linear(64, 3)
)
self.post_init()
def forward(self, board_state, mat_diff_matrix, material_weights, **kwargs):
x = self.retina(board_state, material_weights)
for loop_idx in range(self.config.num_loops):
x = x + self.step_embed[loop_idx]
for layer in self.layers:
x = layer(x, mat_diff_matrix)
from_logits = self.from_head(x)
to_logits = self.to_head(x)
policy_matrix = torch.bmm(from_logits, to_logits.transpose(1, 2))
global_pool = x.mean(dim=1)
value_logits = self.value_head(global_pool)
return {"policy_matrix": policy_matrix, "value_logits": value_logits}