lewtun HF staff commited on
Commit
a1bf704
β€’
2 Parent(s): eb4376f c02722e

Merge pull request #10 from huggingface/add-caching

Browse files
Files changed (6) hide show
  1. .github/workflows/quality.yml +29 -0
  2. Makefile +8 -0
  3. app.py +90 -61
  4. evaluation.py +46 -0
  5. pyproject.toml +2 -0
  6. utils.py +13 -4
.github/workflows/quality.yml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Code quality
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+
11
+ jobs:
12
+
13
+ check_code_quality:
14
+ name: Check code quality
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - name: Checkout code
18
+ uses: actions/checkout@v2
19
+ - name: Setup Python environment
20
+ uses: actions/setup-python@v2
21
+ with:
22
+ python-version: 3.9
23
+ - name: Install dependencies
24
+ run: |
25
+ python -m pip install --upgrade pip
26
+ python -m pip install black isort flake8
27
+ - name: Code quality
28
+ run: |
29
+ make quality
Makefile ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ style:
2
+ python -m black --line-length 119 --target-version py39 .
3
+ python -m isort .
4
+
5
+ quality:
6
+ python -m black --check --line-length 119 --target-version py39 .
7
+ python -m isort --check-only .
8
+ python -m flake8 --max-line-length 119
app.py CHANGED
@@ -8,8 +8,8 @@ from datasets import get_dataset_config_names
8
  from dotenv import load_dotenv
9
  from huggingface_hub import list_datasets
10
 
11
- from utils import (get_compatible_models, get_key, get_metadata, http_get,
12
- http_post)
13
 
14
  if Path(".env").is_file():
15
  load_dotenv(".env")
@@ -33,9 +33,9 @@ TASK_TO_ID = {
33
  SUPPORTED_TASKS = list(TASK_TO_ID.keys())
34
 
35
 
36
- ###########
37
- ### APP ###
38
- ###########
39
  st.title("Evaluation as a Service")
40
  st.markdown(
41
  """
@@ -64,18 +64,22 @@ if metadata is None:
64
  st.warning("No evaluation metadata found. Please configure the evaluation job below.")
65
 
66
  with st.expander("Advanced configuration"):
67
- ## Select task
68
  selected_task = st.selectbox(
69
  "Select a task",
70
  SUPPORTED_TASKS,
71
  index=SUPPORTED_TASKS.index(metadata[0]["task_id"]) if metadata is not None else 0,
72
  )
73
- ### Select config
74
  configs = get_dataset_config_names(selected_dataset)
75
  selected_config = st.selectbox("Select a config", configs)
76
 
77
- ## Select splits
78
- splits_resp = http_get(path="/splits", domain=DATASETS_PREVIEW_API, params={"dataset": selected_dataset})
 
 
 
 
79
  if splits_resp.status_code == 200:
80
  split_names = []
81
  all_splits = splits_resp.json()
@@ -89,11 +93,15 @@ with st.expander("Advanced configuration"):
89
  index=split_names.index(metadata[0]["splits"]["eval_split"]) if metadata is not None else 0,
90
  )
91
 
92
- ## Select columns
93
  rows_resp = http_get(
94
  path="/rows",
95
  domain=DATASETS_PREVIEW_API,
96
- params={"dataset": selected_dataset, "config": selected_config, "split": selected_split},
 
 
 
 
97
  ).json()
98
  col_names = list(pd.json_normalize(rows_resp["rows"][0]["row"]).columns)
99
 
@@ -135,7 +143,7 @@ with st.expander("Advanced configuration"):
135
  st.markdown("`tags` column")
136
  with col2:
137
  tokens_col = st.selectbox(
138
- "This column should contain the parts of the text (as an array of tokens) you want to assign labels to",
139
  col_names,
140
  index=col_names.index(get_key(metadata[0]["col_mapping"], "tokens")) if metadata is not None else 0,
141
  )
@@ -244,65 +252,86 @@ with st.form(key="form"):
244
 
245
  selected_models = st.multiselect("Select the models you wish to evaluate", compatible_models)
246
  print("Selected models:", selected_models)
 
 
 
 
 
 
 
 
 
 
247
  submit_button = st.form_submit_button("Make submission")
248
 
249
  if submit_button:
250
- project_id = str(uuid.uuid4())[:3]
251
- payload = {
252
- "username": AUTOTRAIN_USERNAME,
253
- "proj_name": f"my-eval-project-{project_id}",
254
- "task": TASK_TO_ID[selected_task],
255
- "config": {
256
- "language": "en",
257
- "max_models": 5,
258
- "instance": {
259
- "provider": "aws",
260
- "instance_type": "ml.g4dn.4xlarge",
261
- "max_runtime_seconds": 172800,
262
- "num_instances": 1,
263
- "disk_size_gb": 150,
264
- },
265
- "evaluation": {
266
- "metrics": [],
267
- "models": selected_models,
268
- },
269
- },
270
- }
271
- print(f"Payload: {payload}")
272
- project_json_resp = http_post(
273
- path="/projects/create", payload=payload, token=HF_TOKEN, domain=AUTOTRAIN_BACKEND_API
274
- ).json()
275
- print(project_json_resp)
276
-
277
- if project_json_resp["created"]:
278
  payload = {
279
- "split": 4, # use "auto" split choice in AutoTrain
280
- "col_mapping": col_mapping,
281
- "load_config": {"max_size_bytes": 0, "shuffle": False},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  }
283
- data_json_resp = http_post(
284
- path=f"/projects/{project_json_resp['id']}/data/{selected_dataset}",
 
285
  payload=payload,
286
  token=HF_TOKEN,
287
  domain=AUTOTRAIN_BACKEND_API,
288
- params={"type": "dataset", "config_name": selected_config, "split_name": selected_split},
289
  ).json()
290
- print(data_json_resp)
291
- if data_json_resp["download_status"] == 1:
292
- train_json_resp = http_get(
293
- path=f"/projects/{project_json_resp['id']}/data/start_process",
 
 
 
 
 
 
 
294
  token=HF_TOKEN,
295
  domain=AUTOTRAIN_BACKEND_API,
 
 
 
 
 
296
  ).json()
297
- print(train_json_resp)
298
- if train_json_resp["success"]:
299
- st.success(f"βœ… Successfully submitted evaluation job with project ID {project_id}")
300
- st.markdown(
301
- f"""
302
- Evaluation takes appoximately 1 hour to complete, so grab a β˜• or 🍡 while you wait:
 
 
 
 
 
 
 
303
 
304
- * πŸ“Š Click [here](https://huggingface.co/spaces/autoevaluate/leaderboards) to view the results from your submission
305
- """
306
- )
307
- else:
308
- st.error("πŸ™ˆ Oh noes, there was an error submitting your submission!")
 
 
 
 
8
  from dotenv import load_dotenv
9
  from huggingface_hub import list_datasets
10
 
11
+ from evaluation import filter_evaluated_models
12
+ from utils import get_compatible_models, get_key, get_metadata, http_get, http_post
13
 
14
  if Path(".env").is_file():
15
  load_dotenv(".env")
 
33
  SUPPORTED_TASKS = list(TASK_TO_ID.keys())
34
 
35
 
36
+ #######
37
+ # APP #
38
+ #######
39
  st.title("Evaluation as a Service")
40
  st.markdown(
41
  """
 
64
  st.warning("No evaluation metadata found. Please configure the evaluation job below.")
65
 
66
  with st.expander("Advanced configuration"):
67
+ # Select task
68
  selected_task = st.selectbox(
69
  "Select a task",
70
  SUPPORTED_TASKS,
71
  index=SUPPORTED_TASKS.index(metadata[0]["task_id"]) if metadata is not None else 0,
72
  )
73
+ # Select config
74
  configs = get_dataset_config_names(selected_dataset)
75
  selected_config = st.selectbox("Select a config", configs)
76
 
77
+ # Select splits
78
+ splits_resp = http_get(
79
+ path="/splits",
80
+ domain=DATASETS_PREVIEW_API,
81
+ params={"dataset": selected_dataset},
82
+ )
83
  if splits_resp.status_code == 200:
84
  split_names = []
85
  all_splits = splits_resp.json()
 
93
  index=split_names.index(metadata[0]["splits"]["eval_split"]) if metadata is not None else 0,
94
  )
95
 
96
+ # Select columns
97
  rows_resp = http_get(
98
  path="/rows",
99
  domain=DATASETS_PREVIEW_API,
100
+ params={
101
+ "dataset": selected_dataset,
102
+ "config": selected_config,
103
+ "split": selected_split,
104
+ },
105
  ).json()
106
  col_names = list(pd.json_normalize(rows_resp["rows"][0]["row"]).columns)
107
 
 
143
  st.markdown("`tags` column")
144
  with col2:
145
  tokens_col = st.selectbox(
146
+ "This column should contain the array of tokens",
147
  col_names,
148
  index=col_names.index(get_key(metadata[0]["col_mapping"], "tokens")) if metadata is not None else 0,
149
  )
 
252
 
253
  selected_models = st.multiselect("Select the models you wish to evaluate", compatible_models)
254
  print("Selected models:", selected_models)
255
+
256
+ selected_models = filter_evaluated_models(
257
+ selected_models,
258
+ selected_task,
259
+ selected_dataset,
260
+ selected_config,
261
+ selected_split,
262
+ )
263
+ print("Selected models:", selected_models)
264
+
265
  submit_button = st.form_submit_button("Make submission")
266
 
267
  if submit_button:
268
+ if len(selected_models) > 0:
269
+ project_id = str(uuid.uuid4())[:3]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  payload = {
271
+ "username": AUTOTRAIN_USERNAME,
272
+ "proj_name": f"my-eval-project-{project_id}",
273
+ "task": TASK_TO_ID[selected_task],
274
+ "config": {
275
+ "language": "en",
276
+ "max_models": 5,
277
+ "instance": {
278
+ "provider": "aws",
279
+ "instance_type": "ml.g4dn.4xlarge",
280
+ "max_runtime_seconds": 172800,
281
+ "num_instances": 1,
282
+ "disk_size_gb": 150,
283
+ },
284
+ "evaluation": {
285
+ "metrics": [],
286
+ "models": selected_models,
287
+ },
288
+ },
289
  }
290
+ print(f"Payload: {payload}")
291
+ project_json_resp = http_post(
292
+ path="/projects/create",
293
  payload=payload,
294
  token=HF_TOKEN,
295
  domain=AUTOTRAIN_BACKEND_API,
 
296
  ).json()
297
+ print(project_json_resp)
298
+
299
+ if project_json_resp["created"]:
300
+ payload = {
301
+ "split": 4, # use "auto" split choice in AutoTrain
302
+ "col_mapping": col_mapping,
303
+ "load_config": {"max_size_bytes": 0, "shuffle": False},
304
+ }
305
+ data_json_resp = http_post(
306
+ path=f"/projects/{project_json_resp['id']}/data/{selected_dataset}",
307
+ payload=payload,
308
  token=HF_TOKEN,
309
  domain=AUTOTRAIN_BACKEND_API,
310
+ params={
311
+ "type": "dataset",
312
+ "config_name": selected_config,
313
+ "split_name": selected_split,
314
+ },
315
  ).json()
316
+ print(data_json_resp)
317
+ if data_json_resp["download_status"] == 1:
318
+ train_json_resp = http_get(
319
+ path=f"/projects/{project_json_resp['id']}/data/start_process",
320
+ token=HF_TOKEN,
321
+ domain=AUTOTRAIN_BACKEND_API,
322
+ ).json()
323
+ print(train_json_resp)
324
+ if train_json_resp["success"]:
325
+ st.success(f"βœ… Successfully submitted evaluation job with project ID {project_id}")
326
+ st.markdown(
327
+ """
328
+ Evaluation takes appoximately 1 hour to complete, so grab a β˜• or 🍡 while you wait:
329
 
330
+ * πŸ“Š Click [here](https://huggingface.co/spaces/autoevaluate/leaderboards) to view the \
331
+ results from your submission
332
+ """
333
+ )
334
+ else:
335
+ st.error("πŸ™ˆ Oh noes, there was an error submitting your evaluation job!")
336
+ else:
337
+ st.warning("⚠️ No models were selected for evaluation!")
evaluation.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+
3
+ import streamlit as st
4
+ from huggingface_hub import DatasetFilter, HfApi
5
+ from huggingface_hub.hf_api import DatasetInfo
6
+
7
+
8
+ @dataclass(frozen=True, eq=True)
9
+ class EvaluationInfo:
10
+ task: str
11
+ model: str
12
+ dataset_name: str
13
+ dataset_config: str
14
+ dataset_split: str
15
+
16
+
17
+ def compute_evaluation_id(dataset_info: DatasetInfo) -> int:
18
+ metadata = dataset_info.cardData["eval_info"]
19
+ metadata.pop("col_mapping", None)
20
+ evaluation_info = EvaluationInfo(**metadata)
21
+ return hash(evaluation_info)
22
+
23
+
24
+ def get_evaluation_ids():
25
+ filt = DatasetFilter(author="autoevaluate")
26
+ evaluation_datasets = HfApi().list_datasets(filter=filt, full=True)
27
+ return [compute_evaluation_id(dset) for dset in evaluation_datasets]
28
+
29
+
30
+ def filter_evaluated_models(models, task, dataset_name, dataset_config, dataset_split):
31
+ evaluation_ids = get_evaluation_ids()
32
+
33
+ for idx, model in enumerate(models):
34
+ evaluation_info = EvaluationInfo(
35
+ task=task,
36
+ model=model,
37
+ dataset_name=dataset_name,
38
+ dataset_config=dataset_config,
39
+ dataset_split=dataset_split,
40
+ )
41
+ candidate_id = hash(evaluation_info)
42
+ if candidate_id in evaluation_ids:
43
+ st.info(f"Model {model} has already been evaluated on this configuration. Skipping evaluation...")
44
+ models.pop(idx)
45
+
46
+ return models
pyproject.toml ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [tool.isort]
2
+ profile = "black"
utils.py CHANGED
@@ -1,7 +1,7 @@
1
  from typing import Dict, Union
2
 
3
  import requests
4
- from huggingface_hub import DatasetFilter, HfApi, ModelFilter
5
 
6
  AUTOTRAIN_TASK_TO_HUB_TASK = {
7
  "binary_classification": "text-classification",
@@ -27,7 +27,11 @@ def http_post(path: str, token: str, payload=None, domain: str = None, params=No
27
  """HTTP POST request to the AutoNLP API, raises UnreachableAPIError if the API cannot be reached"""
28
  try:
29
  response = requests.post(
30
- url=domain + path, json=payload, headers=get_auth_headers(token=token), allow_redirects=True, params=params
 
 
 
 
31
  )
32
  except requests.exceptions.ConnectionError:
33
  print("❌ Failed to reach AutoNLP API, check your internet connection")
@@ -39,7 +43,10 @@ def http_get(path: str, domain: str, token: str = None, params: dict = None) ->
39
  """HTTP POST request to the AutoNLP API, raises UnreachableAPIError if the API cannot be reached"""
40
  try:
41
  response = requests.get(
42
- url=domain + path, headers=get_auth_headers(token=token), allow_redirects=True, params=params
 
 
 
43
  )
44
  except requests.exceptions.ConnectionError:
45
  print("❌ Failed to reach AutoNLP API, check your internet connection")
@@ -58,7 +65,9 @@ def get_metadata(dataset_name: str) -> Union[Dict, None]:
58
  def get_compatible_models(task, dataset_name):
59
  # TODO: relax filter on PyTorch models once supported in AutoTrain
60
  filt = ModelFilter(
61
- task=AUTOTRAIN_TASK_TO_HUB_TASK[task], trained_dataset=dataset_name, library=["transformers", "pytorch"]
 
 
62
  )
63
  compatible_models = api.list_models(filter=filt)
64
  return [model.modelId for model in compatible_models]
 
1
  from typing import Dict, Union
2
 
3
  import requests
4
+ from huggingface_hub import HfApi, ModelFilter
5
 
6
  AUTOTRAIN_TASK_TO_HUB_TASK = {
7
  "binary_classification": "text-classification",
 
27
  """HTTP POST request to the AutoNLP API, raises UnreachableAPIError if the API cannot be reached"""
28
  try:
29
  response = requests.post(
30
+ url=domain + path,
31
+ json=payload,
32
+ headers=get_auth_headers(token=token),
33
+ allow_redirects=True,
34
+ params=params,
35
  )
36
  except requests.exceptions.ConnectionError:
37
  print("❌ Failed to reach AutoNLP API, check your internet connection")
 
43
  """HTTP POST request to the AutoNLP API, raises UnreachableAPIError if the API cannot be reached"""
44
  try:
45
  response = requests.get(
46
+ url=domain + path,
47
+ headers=get_auth_headers(token=token),
48
+ allow_redirects=True,
49
+ params=params,
50
  )
51
  except requests.exceptions.ConnectionError:
52
  print("❌ Failed to reach AutoNLP API, check your internet connection")
 
65
  def get_compatible_models(task, dataset_name):
66
  # TODO: relax filter on PyTorch models once supported in AutoTrain
67
  filt = ModelFilter(
68
+ task=AUTOTRAIN_TASK_TO_HUB_TASK[task],
69
+ trained_dataset=dataset_name,
70
+ library=["transformers", "pytorch"],
71
  )
72
  compatible_models = api.list_models(filter=filt)
73
  return [model.modelId for model in compatible_models]