|
import os |
|
import shutil |
|
from tempfile import TemporaryDirectory |
|
from typing import List, Optional, Tuple |
|
|
|
from huggingface_hub import ( |
|
CommitOperationAdd, |
|
HfApi, |
|
) |
|
from huggingface_hub.file_download import repo_folder_name |
|
from optimum.exporters.onnx import main_export |
|
|
|
SPACES_URL = "https://huggingface.co/spaces/onnx/export" |
|
|
|
|
|
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 export_and_git_add(model_id: str, task: str, folder: str, opset: int) -> List: |
|
main_export( |
|
model_name_or_path=model_id, |
|
output=folder, |
|
task=task, |
|
opset=opset, |
|
) |
|
|
|
n_files = len( |
|
[ |
|
name |
|
for name in os.listdir(folder) |
|
if os.path.isfile(os.path.join(folder, name)) and not name.startswith(".") |
|
] |
|
) |
|
|
|
if n_files == 1: |
|
operations = [ |
|
CommitOperationAdd( |
|
path_in_repo=file_name, path_or_fileobj=os.path.join(folder, file_name) |
|
) |
|
for file_name in os.listdir(folder) |
|
] |
|
else: |
|
operations = [ |
|
CommitOperationAdd( |
|
path_in_repo=os.path.join("onnx", file_name), |
|
path_or_fileobj=os.path.join(folder, file_name), |
|
) |
|
for file_name in os.listdir(folder) |
|
] |
|
|
|
return operations |
|
|
|
|
|
def convert( |
|
api: "HfApi", |
|
model_id: str, |
|
task: str, |
|
force: bool = False, |
|
opset: int = None, |
|
) -> Tuple[int, "CommitInfo"]: |
|
pr_title = "Adding ONNX file of this model" |
|
info = api.model_info(model_id) |
|
filenames = set(s.rfilename for s in info.siblings) |
|
|
|
requesting_user = api.whoami()["name"] |
|
|
|
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 the export.") |
|
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}]({url})" |
|
) |
|
else: |
|
operations = export_and_git_add(model_id, task, folder, opset) |
|
|
|
commit_description = f""" |
|
Beep boop I am the [ONNX export bot 🤖🏎️]({SPACES_URL}). On behalf of [{requesting_user}](https://huggingface.co/{requesting_user}), I would like to add to this repository the model converted to ONNX. |
|
|
|
What is ONNX? It stands for "Open Neural Network Exchange", and is the most commonly used open standard for machine learning interoperability. You can find out more at [onnx.ai](https://onnx.ai/)! |
|
|
|
The exported ONNX model can be then be consumed by various backends as TensorRT or TVM, or simply be used in a few lines with 🤗 Optimum through ONNX Runtime, check out how [here](https://huggingface.co/docs/optimum/main/en/onnxruntime/usage_guides/models)! |
|
""" |
|
new_pr = api.create_commit( |
|
repo_id=model_id, |
|
operations=operations, |
|
commit_message=pr_title, |
|
commit_description=commit_description, |
|
create_pr=True, |
|
) |
|
finally: |
|
shutil.rmtree(folder) |
|
return "0", new_pr |
|
|