Advertisement
alkkofficial

Untitled

Apr 12th, 2023
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.25 KB | None | 0 0
  1. # zan1ling4 | 真零 | (pronounced Jun Ling)
  2. # imports
  3. import numpy as np
  4. import torch
  5. import matplotlib.pyplot as plt
  6. import copy
  7. import tqdm
  8. import torch.nn as nn
  9. import torch.optim as optim
  10. from sklearn.model_selection import train_test_split
  11. import chess
  12.  
  13. # from torch.cuda.amp import autocast, GradScaler # NEED GPU
  14. from chess import Move
  15. import torch.nn.init as init
  16.  
  17. # from memory_profiler import profile
  18. import sqlite3
  19.  
  20. # puzzle presets
  21. board = chess.Board()
  22. completed = 0
  23. # find number of lines in a database
  24.  
  25. # Connect to the database
  26. conn = sqlite3.connect(
  27. "chess_games.db"
  28. ) # TODO: implement a variable to replace manually entering DB address
  29.  
  30. # Create a cursor object
  31. cursor = conn.cursor()
  32.  
  33. # # Execute the query to get the length of the table
  34. cursor.execute("SELECT COUNT(*) FROM games")
  35.  
  36. # # Fetch the result
  37. result = cursor.fetchone()[0]
  38. # print(result)
  39. conn.close()
  40. size = 50000
  41.  
  42.  
  43. class DataManager:
  44. def __init__(self, training_size, completed):
  45. self.training_size = training_size
  46. self.completed = completed
  47.  
  48. def get_status(self, move_turn, result):
  49. status = 0
  50. if (move_turn == 0 and result == "1") or (move_turn == 1 and result == "-1"):
  51. status = 1
  52. elif (move_turn == 0 and result == "-1") or (move_turn == 1 and result == "1"):
  53. status = -1
  54. elif result == "0":
  55. status = 0
  56. return status
  57.  
  58. def board_data(self, board):
  59. board_array = np.zeros((8, 8, 13), dtype=np.float32)
  60. for i in range(64):
  61. piece = board.piece_at(i)
  62. if piece is not None:
  63. color = int(piece.color)
  64. piece_type = piece.piece_type - 1
  65. board_array[i // 8][i % 8][piece_type + 6 * color] = 1
  66. else:
  67. board_array[i // 8][i % 8][-1] = 1
  68. board_array = board_array.flatten()
  69. # board_array.shape = 832 (1D)
  70. yield board_array
  71.  
  72. def load(self, completed, size):
  73. conn = sqlite3.connect("chess_games.db")
  74. cursor = conn.cursor()
  75. # select all rows from the table
  76. cursor.execute("SELECT * FROM games LIMIT ? OFFSET ?", (size, completed))
  77. # Execute the SQL query to select the next 1000 rows after skipping the first 1000
  78. # replace reading from file with reading from SQLite
  79. games = cursor.fetchall()
  80.  
  81. for g in tqdm.tqdm(games, desc="each game"):
  82. game = g[2]
  83. MAX_MOMENTS = min(20, len(game))
  84. unsampled_idx = [
  85. np.random.randint(1, len(game)) for _ in range(MAX_MOMENTS - 1)
  86. ]
  87. game = game.split(" ")
  88. for move in range(MAX_MOMENTS - 1):
  89. board = chess.Board()
  90. up_to = unsampled_idx[move]
  91. moment = game[:up_to]
  92. for counter, move in enumerate(moment):
  93. move = Move.from_uci(move)
  94. board.push(move)
  95. matrix_game = np.array(
  96. [self.board_data(board).__next__()]
  97. ) # game after one hot encoding
  98. # Add move_turn as a feature to matrix_game
  99. move_turn = counter % 2
  100. matrix_game = np.concatenate(
  101. (matrix_game, np.array([[move_turn]])), axis=1
  102. )
  103. yield matrix_game.flatten(), self.get_status(move_turn, g[1])
  104.  
  105. conn.close()
  106.  
  107. def loading(self, train_data, train_target):
  108. train_data, train_target = np.array(train_data), np.array(train_target)
  109.  
  110. X_train, X_val, y_train, y_val = train_test_split(
  111. train_data, train_target, test_size=0.2, shuffle=True
  112. )
  113.  
  114. X_train = torch.tensor(X_train, dtype=torch.float32)
  115. y_train = torch.tensor(y_train, dtype=torch.float32)
  116. X_val = torch.tensor(X_val, dtype=torch.float32)
  117. y_val = torch.tensor(y_val, dtype=torch.float32)
  118. return X_train, y_train, X_val, y_val
  119.  
  120.  
  121. class Tanh200(nn.Module):
  122. def forward(self, x):
  123. return torch.tanh(x / 200)
  124.  
  125.  
  126. class Train(Tanh200):
  127. def __init__(self, X_train, y_train, X_val, y_val):
  128. self.X_train = X_train
  129. self.y_train = y_train
  130. self.X_val = X_val
  131. self.y_val = y_val
  132.  
  133. def cycle(self, X_train, y_train, X_val, y_val):
  134. model = nn.Sequential(
  135. nn.Linear(833, 1024),
  136. nn.BatchNorm1d(1024),
  137. nn.ReLU(),
  138. nn.Linear(1024, 512),
  139. nn.Dropout(p=0.25),
  140. nn.BatchNorm1d(512),
  141. nn.LeakyReLU(0.075),
  142. nn.Linear(512, 256),
  143. nn.BatchNorm1d(256),
  144. nn.ReLU(),
  145. nn.Linear(256, 128),
  146. nn.Dropout(p=0.25),
  147. nn.BatchNorm1d(128),
  148. nn.LeakyReLU(0.075),
  149. nn.Linear(128, 64),
  150. nn.ReLU(),
  151. nn.Linear(64, 1),
  152. nn.Dropout(p=0.25),
  153. Tanh200(),
  154. )
  155.  
  156. # Weight initialization
  157. try:
  158. weights_path = "./zlv6.pt"
  159. state_dict = torch.load(weights_path)
  160. model.load_state_dict(state_dict)
  161. except FileNotFoundError:
  162. for m in model.modules():
  163. if isinstance(m, nn.Linear):
  164. nn.init.xavier_uniform_(m.weight)
  165. if m.bias is not None:
  166. init.constant_(m.bias, 0)
  167.  
  168. # scaler = GradScaler()
  169.  
  170. # loss function and optimizer
  171. loss_fn = nn.MSELoss() # mean square error
  172. optimizer = optim.AdamW(
  173. model.parameters(),
  174. lr=1.25e-4, # 1e-3
  175. betas=(0.99, 0.999),
  176. eps=1e-08,
  177. weight_decay=0,
  178. amsgrad=False,
  179. )
  180. scheduler = optim.lr_scheduler.ReduceLROnPlateau(
  181. optimizer, factor=0.9999999, patience=2, verbose=True
  182. )
  183. n_epochs = 200 # number of epochs to run optimal = 40, 220
  184. batch_size = 128 # size of each batch
  185. batch_start = torch.arange(0, len(X_train), batch_size)
  186. # Hold the best model
  187. best_mse = np.inf # initialise value as infinite
  188. best_weights = None
  189. history = []
  190. accumulation_steps = 4 # accumulate gradients over 4 batches
  191. for epoch in tqdm.tqdm(range(n_epochs), desc="Epochs"):
  192. model.train()
  193. epoch_loss = 0.0
  194. for i, batch_idx in enumerate(batch_start):
  195. batch_X, batch_y = (
  196. X_train[batch_idx : batch_idx + batch_size],
  197. y_train[batch_idx : batch_idx + batch_size],
  198. )
  199. optimizer.zero_grad()
  200. y_pred = model(batch_X)
  201. loss = loss_fn(y_pred, batch_y.view(-1, 1))
  202. # scaler.scale(loss).backward() # NEED GPU
  203.  
  204. # accumulate gradients over several batches
  205. if (i + 1) % accumulation_steps == 0 or (i + 1) == len(batch_start):
  206. # scaler.step(optimizer) # NEED GPU
  207. # scaler.update() # NEED GPU
  208. model.zero_grad()
  209. y_pred = model(batch_X)
  210. loss = loss_fn(y_pred, batch_y.view(-1, 1))
  211. loss.backward()
  212. optimizer.step()
  213. epoch_loss += loss.item() * batch_X.shape[0]
  214. epoch_loss /= len(X_train)
  215. print(epoch_loss)
  216. scheduler.step(epoch_loss)
  217. history.append(epoch_loss)
  218. if epoch_loss < best_mse:
  219. best_mse = epoch_loss
  220. best_weights = copy.deepcopy(model.state_dict())
  221.  
  222. # load the best weights into the model
  223. model.load_state_dict(best_weights)
  224.  
  225. print("MSE: %.2f" % best_mse)
  226. print("RMSE: %.2f" % np.sqrt(best_mse))
  227. plt.plot(history)
  228. plt.title("Epoch loss for ZL")
  229. plt.xlabel("Number of Epochs")
  230. plt.ylabel("Epoch Loss")
  231. plt.draw()
  232. plt.savefig("ai-eval-losses.jpg")
  233. model.eval()
  234. with torch.no_grad():
  235. # Test out inference with 5 samples
  236. for i in range(5):
  237. X_sample = X_val[i : i + 1]
  238. X_sample = X_sample.clone().detach()
  239. y_pred = model(X_sample)
  240. print(y_pred)
  241. torch.save(best_weights, "zlv6.pt")
  242. # return scheduler.optimizer.param_groups[0][
  243. # "lr"
  244. # ] # get learning rate of training
  245.  
  246.  
  247. # Training loop
  248. completed = 0
  249. counter = 1
  250. all_completed = False
  251. while all_completed == False:
  252. not_done = result - completed
  253. if not_done == 0:
  254. all_completed = True
  255. break
  256. if not_done < size: # size is the number of chess games processed/cycle in total
  257. size = not_done # this is for the final cycle if there are any remainders
  258. all_completed = True
  259. print("SIZE", size)
  260. print("NOT DONE", not_done)
  261. d = DataManager(size, 0)
  262. train_data, train_target = zip(*d.load(completed, size))
  263. X_train, y_train, X_val, y_val = d.loading(train_data, train_target)
  264. t = Train(X_train, y_train, X_val, y_val)
  265. t.cycle(X_train, y_train, X_val, y_val)
  266. completed = counter * size
  267. counter += 1
  268.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement