Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 5,125 Bytes
f75daf5 |
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 |
from optimum.exporters.tasks import TasksManager
from optimum.exporters.onnx import OnnxConfigWithPast, export, validate_model_outputs
from tempfile import TemporaryDirectory
from transformers import AutoConfig, is_torch_available
from transformers import AutoConfig
from pathlib import Path
import os
import shutil
import argparse
from typing import Optional
from huggingface_hub import CommitOperationAdd, HfApi, hf_hub_download, get_repo_discussions
from huggingface_hub.file_download import repo_folder_name
def previous_pr(api: "HfApi", model_id: str, pr_title: str) -> Optional["Discussion"]:
try:
discussions = api.get_repo_discussions(repo_id=model_id)
except Exception:
return None
for discussion in discussions:
if discussion.status == "open" and discussion.is_pull_request and discussion.title == pr_title:
return discussion
def convert_onnx(model_id: str, task: str, folder: str):
model_class = TasksManager.get_model_class_for_task(task)
config = AutoConfig.from_pretrained(model_id)
model = model_class.from_config(config)
device = "cpu" # ?
# Dynamic axes aren't supported for YOLO-like models. This means they cannot be exported to ONNX on CUDA devices.
# See: https://github.com/ultralytics/yolov5/pull/8378
if model.__class__.__name__.startswith("Yolos") and device != "cpu":
return
onnx_config_class_constructor = TasksManager.get_exporter_config_constructor(model_type=config.model_type, exporter="onnx", task=task, model_name=model_id)
onnx_config = onnx_config_class_constructor(model.config)
# We need to set this to some value to be able to test the outputs values for batch size > 1.
if (
isinstance(onnx_config, OnnxConfigWithPast)
and getattr(model.config, "pad_token_id", None) is None
and task == "sequence-classification"
):
model.config.pad_token_id = 0
if is_torch_available():
from optimum.exporters.onnx.utils import TORCH_VERSION
if not onnx_config.is_torch_support_available:
print(
"Skipping due to incompatible PyTorch version. Minimum required is"
f" {onnx_config.MIN_TORCH_VERSION}, got: {TORCH_VERSION}"
)
onnx_inputs, onnx_outputs = export(
model, onnx_config, onnx_config.DEFAULT_ONNX_OPSET, Path(folder), device=device
)
atol = onnx_config.ATOL_FOR_VALIDATION
if isinstance(atol, dict):
atol = atol[task.replace("-with-past", "")]
validate_model_outputs(
onnx_config,
model,
Path(folder),
onnx_outputs,
atol,
)
# TODO: iterate in folder and add all
operations = [CommitOperationAdd(path_in_repo=local.split("/")[-1], path_or_fileobj=local) for local in local_filenames]
return operations
def convert(api: "HfApi", model_id: str, task:str, force: bool=False) -> Optional["CommitInfo"]:
pr_title = "Adding ONNX file of this model"
info = api.model_info(model_id)
filenames = set(s.rfilename for s in info.siblings)
with TemporaryDirectory() as d:
folder = os.path.join(d, repo_folder_name(repo_id=model_id, repo_type="models"))
os.makedirs(folder)
new_pr = None
try:
pr = previous_pr(api, model_id, pr_title)
if "model.onnx" in filenames and not force:
raise Exception(f"Model {model_id} is already converted, skipping..")
elif pr is not None and not force:
url = f"https://huggingface.co/{model_id}/discussions/{pr.num}"
new_pr = pr
raise Exception(f"Model {model_id} already has an open PR check out {url}")
else:
convert_onnx(model_id, task, folder)
finally:
shutil.rmtree(folder)
return new_pr
if __name__ == "__main__":
DESCRIPTION = """
Simple utility tool to convert automatically a model on the hub to onnx format.
It is PyTorch exclusive for now.
It works by downloading the weights (PT), converting them locally, and uploading them back
as a PR on the hub.
"""
parser = argparse.ArgumentParser(description=DESCRIPTION)
parser.add_argument(
"model_id",
type=str,
help="The name of the model on the hub to convert. E.g. `gpt2` or `facebook/wav2vec2-base-960h`",
)
parser.add_argument(
"task",
type=str,
help="The task the model is performing",
)
parser.add_argument(
"--force",
action="store_true",
help="Create the PR even if it already exists of if the model was already converted.",
)
args = parser.parse_args()
api = HfApi()
convert(api, args.model_id, task=args.task, force=args.force) |