| """ |
| PixelModel - the weights ARE the image. |
| |
| model.png stores all weights as pixel RGB values (0-255 β floats). |
| Architecture: |
| - Row 0..H//3-1 β Layer 1 weights (prompt_dim β hidden) |
| - Row H//3..2*H//3-1 β Layer 2 weights (hidden β hidden) |
| - Row 2*H//3..H-1 β Layer 3 weights (hidden β output_flat) |
| |
| Width W = max(prompt_dim, hidden, output_flat), padded/sliced as needed. |
| RGB channels encode sign & magnitude: |
| R = weight magnitude (0..255 β 0..1) |
| G = reserved (bias values, layer 1) |
| B = sign bit: <128 = negative, >=128 = positive |
| """ |
|
|
| import torch |
| import torch.nn.functional as F |
| import numpy as np |
| from PIL import Image |
|
|
|
|
| |
| PROMPT_DIM = 32 |
| HIDDEN = 64 |
| OUT_SIZE = 32 |
| OUT_FLAT = OUT_SIZE * OUT_SIZE * 3 |
|
|
| |
| |
| |
| |
| MODEL_W = max(PROMPT_DIM, HIDDEN) |
| MODEL_H = HIDDEN + HIDDEN + OUT_FLAT |
| |
|
|
|
|
| def prompt_to_embedding(prompt: str) -> torch.Tensor: |
| """Deterministic char-level embedding β PROMPT_DIM vector.""" |
| vec = torch.zeros(PROMPT_DIM) |
| for i, ch in enumerate(prompt.lower()): |
| idx = i % PROMPT_DIM |
| vec[idx] += (ord(ch) / 127.0) |
| |
| norm = vec.norm() |
| if norm > 0: |
| vec = vec / norm |
| return vec |
|
|
|
|
| def pixels_to_weights(pixels: torch.Tensor) -> tuple: |
| """ |
| pixels: (H, W, 3) float32 tensor, values 0..1 |
| |
| Returns W1, W2, W3 weight matrices. |
| """ |
| H, W, _ = pixels.shape |
|
|
| r = pixels[:, :, 0] |
| b = pixels[:, :, 2] |
|
|
| |
| sign = torch.where(b >= 0.5, torch.ones_like(b), -torch.ones_like(b)) |
| vals = sign * r |
|
|
| row = 0 |
|
|
| |
| W1_rows = HIDDEN |
| W1 = vals[row: row + W1_rows, :PROMPT_DIM] |
| row += W1_rows |
|
|
| |
| W2_rows = HIDDEN |
| W2 = vals[row: row + W2_rows, :HIDDEN] |
| row += W2_rows |
|
|
| |
| W3_rows = OUT_FLAT |
| W3 = vals[row: row + W3_rows, :HIDDEN] |
| row += W3_rows |
|
|
| return W1, W2, W3 |
|
|
|
|
| def forward(pixels: torch.Tensor, prompt: str) -> torch.Tensor: |
| """ |
| pixels : (H, W, 3) float32, values 0..1 β the model |
| prompt : str |
| returns: (OUT_SIZE, OUT_SIZE, 3) float32, values 0..1 |
| """ |
| emb = prompt_to_embedding(prompt) |
| W1, W2, W3 = pixels_to_weights(pixels) |
|
|
| x = torch.tanh(W1 @ emb) |
| x = torch.tanh(W2 @ x) |
| x = torch.sigmoid(W3 @ x) |
|
|
| img = x.reshape(OUT_SIZE, OUT_SIZE, 3) |
| return img |
|
|
|
|
| def load_model(path: str) -> torch.Tensor: |
| """Load model.png β float tensor (H, W, 3) in [0,1].""" |
| img = Image.open(path).convert("RGB") |
| arr = np.array(img, dtype=np.float32) / 255.0 |
| return torch.tensor(arr) |
|
|
|
|
| def save_model(pixels: torch.Tensor, path: str): |
| """Save float tensor (H, W, 3) in [0,1] β model.png.""" |
| arr = (pixels.detach().clamp(0, 1).numpy() * 255).astype(np.uint8) |
| Image.fromarray(arr, mode="RGB").save(path) |
|
|
|
|
| def init_model(path: str): |
| """Create a fresh random model.png.""" |
| |
| r = torch.rand(MODEL_H, MODEL_W) * 0.2 |
| g = torch.zeros(MODEL_H, MODEL_W) |
| b = (torch.rand(MODEL_H, MODEL_W) > 0.5).float() |
| pixels = torch.stack([r, g, b], dim=2) |
| save_model(pixels, path) |
| print(f"Initialised model: {path} ({MODEL_W}Γ{MODEL_H} px)") |
|
|