TheXeos commited on
Commit
b942e91
1 Parent(s): 68e9d82

Port docker to space

Browse files
Files changed (1) hide show
  1. app.py +152 -0
app.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import random
2
+ import pandas as pd
3
+ from datetime import datetime
4
+ from huggingface_hub import hf_hub_download, HfApi
5
+
6
+
7
+ class Model:
8
+ """
9
+ Class containing the info of a model.
10
+
11
+ :param name: Name of the model
12
+ :param elo: Elo rating of the model
13
+ :param games_played: Number of games played by the model (useful if we implement sigma uncertainty)
14
+ """
15
+ def __init__(self, name, elo=1200, games_played=0):
16
+ self.name = name
17
+ self.elo = elo
18
+ self.games_played = games_played
19
+
20
+
21
+ class Matchmaking:
22
+ """
23
+ Class managing the matchmaking between the models.
24
+
25
+ :param models: List of models
26
+ :param queue: Temporary list of models used for the matching process
27
+ :param k: Dev coefficient
28
+ :param max_diff: Maximum difference considered between two models' elo
29
+ :param matches: Dictionary containing the match history (to later upload as CSV)
30
+ """
31
+ def __init__(self, models, env):
32
+ self.models = models
33
+ self.env = env
34
+ self.queue = self.models.copy()
35
+ self.k = 20
36
+ self.max_diff = 500
37
+ self.matches = {
38
+ "model1": [],
39
+ "model2": [],
40
+ "result": [],
41
+ "datetime": [],
42
+ "env": []
43
+ }
44
+
45
+ def run(self):
46
+ """
47
+ Run the matchmaking process.
48
+ Add models to the queue, shuffle it, and match the models one by one to models with close ratings.
49
+ Compute the new elo for each model after each match and add the match to the match history.
50
+ """
51
+ for i in range(10):
52
+ self.queue = self.models.copy()
53
+ random.shuffle(self.queue)
54
+ while len(self.queue) > 1:
55
+ model1 = self.queue.pop(0)
56
+ model2 = self.queue.pop(self.find_n_closest_indexes(model1, 10))
57
+ result = match(model1, model2)
58
+ self.compute_elo(model1, model2, result)
59
+ self.matches["model1"].append(model1.name)
60
+ self.matches["model2"].append(model2.name)
61
+ self.matches["result"].append(result)
62
+ self.matches["datetime"].append(datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"))
63
+ self.matches["env"].append(self.env)
64
+
65
+ def compute_elo(self, model1, model2, result):
66
+ """ Compute the new elo for each model based on a match result. """
67
+ delta = model1.elo - model2.elo
68
+ win_probability = 1 / (1 + 10 ** (-delta / 500))
69
+ model1.elo += self.k * (result - win_probability)
70
+ model2.elo -= self.k * (result - win_probability)
71
+
72
+ def find_n_closest_indexes(self, model, n) -> int:
73
+ """
74
+ Get a model index with a fairly close rating. If no model is found, return the last model in the queue.
75
+ We don't always pick the closest rating to add variety to the matchups.
76
+
77
+ :param model: Model to compare
78
+ :param n: Number of close models from which to pick a candidate
79
+ :return: id of the chosen candidate
80
+ """
81
+ indexes = []
82
+ closest_diffs = [9999999] * n
83
+ for i, m in enumerate(self.queue):
84
+ if m.name == model.name:
85
+ continue
86
+ diff = abs(m.elo - model.elo)
87
+ if diff < max(closest_diffs):
88
+ closest_diffs.append(diff)
89
+ closest_diffs.sort()
90
+ closest_diffs.pop()
91
+ indexes.append(i)
92
+ random.shuffle(indexes)
93
+ return indexes[0]
94
+
95
+ def to_csv(self):
96
+ """ Save the match history as a CSV file to the hub. """
97
+ df = pd.DataFrame(columns=['name', 'elo'])
98
+ for model in self.models:
99
+ df = pd.concat([df, pd.DataFrame([[model.name, model.elo]], columns=['name', 'elo'])])
100
+ df.to_csv('elo.csv', index=False)
101
+ df_matches = pd.DataFrame(self.matches)
102
+ date = datetime.now()
103
+ df_matches.to_csv(f"matches/{self.env}__{date.strftime('%Y-%m-%d_%H-%M-%S_%f')}.csv", index=False)
104
+ api.upload_file(
105
+ path_or_fileobj=f"matches/{self.env}__{date.strftime('%Y-%m-%d_%H-%M-%S_%f')}.csv",
106
+ path_in_repo=f"match_history/{self.env}__{date.strftime('%Y-%m-%d_%H-%M-%S_%f')}.csv",
107
+ repo_id="CarlCochet/BotFights"
108
+ )
109
+
110
+
111
+ def match(model1, model2) -> float:
112
+ """
113
+ !!! Current code is placeholder !!!
114
+ TODO: Launch a Unity process with the 2 models and get the result of the match
115
+
116
+ :param model1: First Model object
117
+ :param model2: Second Model object
118
+ :return: match result (0: model1 lost, 0.5: draw, 1: model1 won)
119
+ """
120
+ result = random.randint(0, 2) / 2
121
+ return result
122
+
123
+
124
+ def get_models_list() -> list:
125
+ """
126
+ !!! Current code is placeholder !!!
127
+ TODO: Create a list of Model objects from the models found on the hub
128
+
129
+ :return: list of Model objects
130
+ """
131
+ models = []
132
+ hf_hub_download(
133
+ repo_id="CarlCochet/BotFights",
134
+ filename="elo.csv",
135
+ )
136
+ data = pd.read_csv("elo.csv")
137
+ for i, row in data.iterrows():
138
+ models.append(Model(row["name"], row["elo"]))
139
+ return models
140
+
141
+
142
+ def init_matchmaking():
143
+ models = get_models_list()
144
+ matchmaking = Matchmaking(models, "snowball-fight")
145
+ matchmaking.run()
146
+ matchmaking.to_csv()
147
+
148
+
149
+ if __name__ == "__main__":
150
+ print("It's running!")
151
+ api = HfApi()
152
+ init_matchmaking()