File size: 12,816 Bytes
91cb2a2
1c0393e
91cb2a2
 
e1149ce
 
fc77bd1
421b84e
91cb2a2
065a30a
421b84e
065a30a
91cb2a2
 
 
 
421b84e
 
 
93e0d72
421b84e
93e0d72
421b84e
 
 
93e0d72
91cb2a2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c44e865
91cb2a2
1c0393e
1bff76c
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
8bf192d
91cb2a2
 
e9b5b0a
91cb2a2
 
5dd610e
91cb2a2
 
8bf192d
91cb2a2
 
e9b5b0a
91cb2a2
 
5dd610e
91cb2a2
 
 
 
 
8bf192d
91cb2a2
 
 
 
 
 
 
 
 
5dd610e
91cb2a2
 
 
421b84e
 
 
 
898ea9f
0e270cd
0c05807
7539ced
91cb2a2
421b84e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b783df7
421b84e
 
a4a7f09
421b84e
e9b5b0a
156c338
 
1c0393e
156c338
421b84e
 
 
b783df7
421b84e
 
 
 
e9b5b0a
156c338
 
1c0393e
156c338
 
421b84e
 
 
622fe78
b783df7
c86d5c1
e9b5b0a
156c338
1c0393e
156c338
 
22d8e29
b783df7
e9b5b0a
421b84e
 
 
 
 
 
 
 
bbb451a
a4a7f09
421b84e
 
 
 
 
 
 
 
 
 
 
 
 
452a3a4
c7e38ac
 
 
a3fe4eb
a43ba57
0e84131
 
dbd1567
69d75a6
421b84e
b783df7
e9b5b0a
e183e91
421b84e
 
1c0393e
 
 
4ab2c19
421b84e
 
b2cc946
 
413416c
98559f1
2cb378a
3096d19
 
 
b2cc946
421b84e
 
 
91cb2a2
 
 
e9b5b0a
 
91cb2a2
e9b5b0a
 
91cb2a2
e9b5b0a
 
 
91cb2a2
 
421b84e
 
 
 
0e270cd
0c05807
94b9645
 
 
 
0c05807
 
a3fe4eb
421b84e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
import gradio as gr
from huggingface_hub import HfApi, hf_hub_download, Repository
from huggingface_hub.repocard import metadata_load

from PIL import Image, ImageDraw, ImageFont

from datetime import date
import time  

import os
import pandas as pd

from utils import *

api = HfApi()

DATASET_REPO_URL = "https://huggingface.co/datasets/huggingface-projects/Deep-RL-Course-Certification"
CERTIFIED_USERS_FILENAME = "certified_users.csv"
CERTIFIED_USERS_DIR = "certified_users"

HF_TOKEN = os.environ.get("HF_TOKEN")

repo = Repository(
    local_dir=CERTIFIED_USERS_DIR, clone_from=DATASET_REPO_URL, use_auth_token=HF_TOKEN
)

def get_user_models(hf_username, env_tag, lib_tag):
    """
    List the Reinforcement Learning models
    from user given environment and lib
    :param hf_username: User HF username
    :param env_tag: Environment tag
    :param lib_tag: Library tag
    """
    api = HfApi()
    models = api.list_models(author=hf_username, filter=["reinforcement-learning", env_tag, lib_tag])

    user_model_ids = [x.modelId for x in models]
    return user_model_ids


def get_metadata(model_id):
  """
  Get model metadata (contains evaluation data)
  :param model_id
  """
  try:
    readme_path = hf_hub_download(model_id, filename="README.md")
    return metadata_load(readme_path)
  except requests.exceptions.HTTPError:
    # 404 README.md not found
    return None


def parse_metrics_accuracy(meta):
  """
  Get model results and parse it
  :param meta: model metadata
  """
  if "model-index" not in meta:
    return None
  result = meta["model-index"][0]["results"]
  metrics = result[0]["metrics"]
  accuracy = metrics[0]["value"]
  
  return accuracy


def parse_rewards(accuracy):
  """
  Parse mean_reward and std_reward
  :param accuracy: model results
  """
  default_std = -1000
  default_reward= -1000
  if accuracy !=  None:
      accuracy = str(accuracy)
      parsed =  accuracy.split(' +/- ')
      if len(parsed)>1:
          mean_reward = float(parsed[0])
          std_reward =  float(parsed[1])
      elif len(parsed)==1: #only mean reward   
          mean_reward = float(parsed[0])
          std_reward =  float(0)
      else: 
          mean_reward = float(default_std)
          std_reward = float(default_reward)
  else:
      mean_reward = float(default_std)
      std_reward = float(default_reward)
  
  return mean_reward, std_reward

def calculate_best_result(user_model_ids):
  """
  Calculate the best results of a unit
  best_result = mean_reward - std_reward
  :param user_model_ids: RL models of a user
  """
  best_result = -100
  best_model_id = ""
  for model in user_model_ids:
    meta = get_metadata(model)
    if meta is None:
      continue
    accuracy = parse_metrics_accuracy(meta)
    mean_reward, std_reward = parse_rewards(accuracy)
    result = mean_reward - std_reward
    if result > best_result:
      best_result = result
      best_model_id = model
      
  return best_result, best_model_id

def check_if_passed(model):
  """
  Check if result >= baseline
  to know if you pass
  :param model: user model
  """
  if model["best_result"] >= model["min_result"]:
    model["passed_"] = True


def certification(hf_username, first_name, last_name):
  results_certification = [
      {
          "unit": "Unit 1",
          "env": "LunarLander-v2",
          "library": "stable-baselines3",
          "min_result": 200,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
      },
  {
          "unit": "Unit 2",
          "env": "Taxi-v3",
          "library": "q-learning",
          "min_result": 4,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
  },
  {
          "unit": "Unit 3",
          "env": "SpaceInvadersNoFrameskip-v4",
          "library": "stable-baselines3",
          "min_result": 200,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
  },
  {
          "unit": "Unit 4",
          "env": "CartPole-v1",
          "library": "reinforce",
          "min_result": 350,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
  },
    {
          "unit": "Unit 4",
          "env": "Pixelcopter-PLE-v0",
          "library": "reinforce",
          "min_result": 5,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
    },
      {
          "unit": "Unit 5",
          "env": "ML-Agents-SnowballTarget",
          "library": "ml-agents",
          "min_result": -100,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
    },
      {
          "unit": "Unit 5",
          "env": "ML-Agents-Pyramids",
          "library": "ml-agents",
          "min_result": -100,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
    },
      {
          "unit": "Unit 6",
          "env": "AntBulletEnv-v0",
          "library": "stable-baselines3",
          "min_result": 650,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
    },
      {
          "unit": "Unit 6",
          "env": "PandaReachDense-v2",
          "library": "stable-baselines3",
          "min_result": -3.5,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
    },
      {
          "unit": "Unit 7",
          "env": "ML-Agents-SoccerTwos",
          "library": "ml-agents",
          "min_result": -100,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
    },
      {
          "unit": "Unit 8 PI",
          "env": "GodotRL-JumperHard",
          "library": "cleanrl",
          "min_result": 100,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
    },
      {
          "unit": "Unit 8 PII",
          "env": "Vizdoom-Battle",
          "library": "cleanrl",
          "min_result": 100,
          "best_result": 0,
          "best_model_id": "",
          "passed_": False
    },
  ] 
  for unit in results_certification:
    # Get user model
    user_models = get_user_models(hf_username, unit['env'], unit['library'])

    # Calculate the best result and get the best_model_id
    best_result, best_model_id = calculate_best_result(user_models)

    # Save best_result and best_model_id
    unit["best_result"] = best_result
    unit["best_model_id"] = make_clickable_model(best_model_id)

    # Based on best_result do we pass the unit?
    check_if_passed(unit)
    unit["passed"] = pass_emoji(unit["passed_"])
    
  print(results_certification)
 
  df1 = pd.DataFrame(results_certification)

  df = df1[['passed', 'unit', 'env', 'min_result', 'best_result', 'best_model_id']]

  certificate, message, pdf = verify_certification(results_certification, hf_username, first_name, last_name)
  print("MESSAGE", message)

  return message, pdf, certificate, df

"""
Verify that the user pass.
If yes:
- Generate the certification
- Send an email
- Print the certification

If no:
- Explain why the user didn't pass yet
"""
def verify_certification(df, hf_username, first_name, last_name):
  # Check that we pass
  model_pass_nb = 0
  pass_percentage = 0
  for unit in df:
    if unit["passed_"] is True:
      model_pass_nb += 1
  
  pass_percentage = (model_pass_nb/12) * 100 
  print("pass_percentage", pass_percentage)
  
  if pass_percentage == 100:
    # Generate a certificate of excellence
    certificate, pdf = generate_certificate("./certificate_models/certificate-excellence.png", first_name, last_name)

    # Add this user to our database
    add_certified_user(hf_username, first_name, last_name, pass_percentage)
    
    # Add a message
    message = """
    Congratulations, you successfully completed the Hugging Face Deep Reinforcement Learning Course πŸŽ‰ \n 
    **Since you pass 100% of the hands-on you get a Certificate of Excellence πŸŽ“.**
    """

  elif pass_percentage < 100 and pass_percentage >= 80:
    # Certificate of completion
    certificate, pdf = generate_certificate("./certificate_models/certificate-completion.png", first_name, last_name)

    # Add this user to our database
    add_certified_user(hf_username, first_name, last_name, pass_percentage)

    # Add a message
    message = """
    Congratulations, you successfully completed the Hugging Face Deep Reinforcement Learning Course πŸŽ‰ \n 
    **Since you pass 80% of the hands-on you get a Certificate of Completion πŸŽ“**. You can try to get a Certificate of Excellence 
    if you pass 100% of the hands-on, don't hesitate to check which unit you didn't pass and update these models.
    """
  
  else:
    # Not pass yet
    certificate = Image.new("RGB", (100, 100), (255, 255, 255))
    pdf = ""
      
    # Add a message
    message = """
    You **didn't pass the minimum of 80%** of the hands-on to get a certificate of completion. **But don't be discouraged**. 
    Check below which units you need to do again to get your certificate πŸ’ͺ
    """
  print("return certificate")
  return certificate, message, pdf
    

def generate_certificate(certificate_model, first_name, last_name):
    im = Image.open(certificate_model)
    d = ImageDraw.Draw(im)

    name_font = ImageFont.truetype("Quattrocento-Regular.ttf", 100)
    date_font = ImageFont.truetype("Quattrocento-Regular.ttf", 48)
    
    name = str(first_name) + " " + str(last_name)
    print("NAME", name)
    
    # Debug line name
    #d.line(((200, 740), (1800, 740)), "gray")
    #d.line(((1000, 0), (1000, 1400)), "gray")
    
    # Name
    d.text((1000, 740), name, fill="black", anchor="mm", font=name_font)

    # Debug line date
    #d.line(((1500, 0), (1500, 1400)), "gray")

    # Date of certification
    d.text((1480, 1170), str(date.today()), fill="black", anchor="mm", font=date_font)

    rgba = im
    rgb = Image.new('RGB', im.size, (255, 255, 255))  # white background
    rgb.paste(rgba, mask=rgba.split()[3]) # 3 is the alpha channel
    pdf_ = rgb.save("certificate.pdf", 'PDF', save_all = True, resolution=100.0)
    pdf__ = im.save("certificate.png")
    print("RGB", rgb)
    print("PDF", pdf_)
    print("PDF", pdf__)
    pdf = pdf_.filename

    return im, pdf



def add_certified_user(hf_username, first_name, last_name, pass_percentage):
  """
  Add the certified user to the database
  """
  print("ADD CERTIFIED USER")
  repo.git_pull()
  history = pd.read_csv(os.path.join(CERTIFIED_USERS_DIR, CERTIFIED_USERS_FILENAME))

  # Check if this hf_username is already in our dataset:
  check = history.loc[history['hf_username'] == hf_username]
  if not check.empty:
    history = history.drop(labels=check.index[0], axis=0)
  
  new_row = pd.DataFrame({'hf_username': hf_username, 'first_name': first_name, 'last_name': last_name, 'pass_percentage': pass_percentage, 'datetime': time.time()}, index=[0])
  history = pd.concat([new_row, history[:]]).reset_index(drop=True)
    
  history.to_csv(os.path.join(CERTIFIED_USERS_DIR, CERTIFIED_USERS_FILENAME), index=False)
  repo.push_to_hub(commit_message="Update certified users list")


with gr.Blocks() as demo:
    gr.Markdown(f"""
    # Get your certificate πŸŽ“
    The certification process is completely free:

    - To get a *certificate of completion*: you need to **pass 80% of the assignments before the end of April 2023**.
    - To get a *certificate of honors*: you need to **pass 100% of the assignments before the end of April 2023**.

    For more information about the certification process [check this](https://huggingface.co/deep-rl-course/communication/certification)

    Don’t hesitate to share your certificate on Twitter (tag me @ThomasSimonini and @huggingface) and on Linkedin.
    """)
    
    hf_username = gr.Textbox(placeholder="ThomasSimonini", label="Your Hugging Face Username (case sensitive)")
    first_name = gr.Textbox(placeholder="Jane", label="Your First Name")
    last_name = gr.Textbox(placeholder="Doe", label="Your Last Name")
    #email = gr.Textbox(placeholder="jane.doe@gmail.com", label="Your Email (to receive your certificate)")
    check_progress_button = gr.Button(value="Check if I pass")
    #with gr.Row(visible=False) as output_row:
    output_text = gr.components.Textbox()
    output_pdf = gr.File()
    output_img = gr.components.Image(type="pil")
    output_dataframe = gr.components.Dataframe(headers=["Pass?", "Unit", "Environment", "Baseline", "Your best result", "Your best model id"], datatype=["markdown", "markdown", "markdown", "number", "number", "markdown", "bool"]) #value= certification(hf_username, first_name, last_name), 
    check_progress_button.click(fn=certification, inputs=[hf_username, first_name, last_name], outputs=[output_text, output_pdf, output_img, output_dataframe])#[output1, output2])

    
demo.launch(debug=True)