CoolFace
Apppublic

RonyForAI/Mirage_DB_RL

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
agent.py100 linesDownload Raw Back to training
1import torch2import torch.nn as nn3import torch.optim as optim4import random5import numpy as np6 7 8class Agent(nn.Module):9    def __init__(self, num_tables=3):10        super().__init__()11 12        self.num_tables = num_tables13        self.join_types = 314        self.use_index = 215 16        # total actions = 3 * 3 * 2 = 1817        self.action_size = num_tables * self.join_types * self.use_index18 19        # state size (approx)20        self.state_size = num_tables * 5 + 1  # adjust if needed21 22        self.net = nn.Sequential(23            nn.Linear(self.state_size, 64),24            nn.ReLU(),25            nn.Linear(64, 64),26            nn.ReLU(),27            nn.Linear(64, self.action_size)28        )29 30        self.optimizer = optim.Adam(self.parameters(), lr=0.001)31        self.loss_fn = nn.MSELoss()32 33        # RL params34        self.epsilon = 1.035        self.epsilon_decay = 0.99536        self.epsilon_min = 0.0537        self.gamma = 0.9538 39    def forward(self, x):40        return self.net(x)41 42    # -------- Encode state --------43    def encode_state(self, obs):44        state = []45 46        state.extend(obs.table_rows)        # num_tables values47        state.extend(obs.selectivities)     # num_tables values48        state.extend(obs.has_index)         # num_tables values49 50        # chosen order (pad with -1 to fixed length)51        padded_chosen = obs.chosen_order + [-1] * (self.num_tables - len(obs.chosen_order))52        state.extend(padded_chosen)         # num_tables values53 54        # remaining tables (pad with -1 to fixed length)55        padded_remaining = obs.remaining_tables + [-1] * (self.num_tables - len(obs.remaining_tables))56        state.extend(padded_remaining)      # num_tables values57 58        state.append(obs.current_cost)      # 1 value59 60        # total: num_tables * 5 + 161        return torch.tensor(state, dtype=torch.float32)62 63    # -------- Action encoding --------64    def decode_action(self, action_id):65        table = action_id // 666        rem = action_id % 667        join = rem // 268        index = rem % 269        return table, join, index70 71    # -------- Select action --------72    def select_action(self, obs):73        state = self.encode_state(obs)74 75        if random.random() < self.epsilon:76            action_id = random.randint(0, self.action_size - 1)77        else:78            with torch.no_grad():79                q_values = self.forward(state)80                action_id = torch.argmax(q_values).item()81 82        return self.decode_action(action_id), action_id83 84    # -------- Train step --------85    def train_step(self, state, action, reward, next_state, done):86        q_values = self.forward(state)87        next_q_values = self.forward(next_state)88 89        target = q_values.clone().detach()90        target[action] = reward + (0 if done else self.gamma * torch.max(next_q_values))91 92        loss = self.loss_fn(q_values, target)93 94        self.optimizer.zero_grad()95        loss.backward()96        self.optimizer.step()97 98        # decay epsilon99        if self.epsilon > self.epsilon_min:100            self.epsilon *= self.epsilon_decay