Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ jobs:
run: |
export PYTHONPATH=.
python _doc/examples/plot_export_tiny_llm.py
continue-on-error: true

- name: tiny-llm bypass
run: |
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOGS.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Change Logs
===========

0.3.0
+++++

* :pr:`23`: dummy inputs for ``image-classification``
* :pr:`22`: api to create untrained model copying the architecture
of the trained models and dummy inputs for them,
support for ``text-generation``

0.2.1
+++++

Expand Down
109 changes: 109 additions & 0 deletions _doc/examples/plot_export_hub_codellama.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""
.. _l-plot-export-hub-codellama:

Test the export on untrained models
===================================

Checking the exporter on a whole model takes time as it is
usually big but we can create a smaller version with
the same architecture. Then fix export issues on such a
small model is faster.

codellama/CodeLlama-7b-Python-hf
++++++++++++++++++++++++++++++++

Let's grab some information about this model.
This reuses :epkg:`huggingface_hub` API.
"""

import copy
import pprint
import torch
from onnx_diagnostic import doc
from onnx_diagnostic.helpers import string_type
from onnx_diagnostic.torch_models.hghub import (
get_untrained_model_with_inputs,
)
from onnx_diagnostic.torch_models.hghub.hub_api import (
get_model_info,
get_pretrained_config,
task_from_id,
)
from onnx_diagnostic.torch_export_patches import bypass_export_some_errors

model_id = "codellama/CodeLlama-7b-Python-hf"
print("info", get_model_info(model_id))

# %%
# The configuration.

print("config", get_pretrained_config(model_id))

# %%
# The task determines the set of inputs which needs
# to be created for this input.

print("task", task_from_id(model_id))

# %%
# Untrained model
# +++++++++++++++
#
# The function :func:`get_untrained_model_with_inputs
# <onnx_diagnostic.torch_models.hghub.get_untrained_model_with_inputs>`.
# It loads the pretrained configuration, extracts the task associated
# to the model and them creates random inputs and dynamic shapes
# for :func:`torch.export.export`.

data = get_untrained_model_with_inputs(model_id, verbose=1)
print("model size:", data["size"])
print("number of weights:", data["n_weights"])
print("fields:", set(data))

# %%
# Inputs
print("inputs:", string_type(data["inputs"], with_shape=True))

# %%
# Dynamic Shapes
print("dynamic shapes:", pprint.pformat(data["dynamic_shapes"]))

# %%
# Let's check the model runs. We still needs to
# copy the inputs before using the models, the cache
# is usually modified inplace.
# Expected outputs can be used later to compute
# discrepancies.

inputs_copy = copy.deepcopy(data["inputs"])
model = data["model"]
expected_outputs = model(**inputs_copy)

print("outputs:", string_type(expected_outputs, with_shape=True))

# %%
# It works.
#
# Export
# ++++++
#
# The model uses :class:`transformers.cache_utils.DynamicCache`.
# It still requires patches to be exportable (control flow).
# See :func:`onnx_diagnostic.torch_export_patches.bypass_export_some_errors`

with bypass_export_some_errors(patch_transformers=True) as f:
ep = torch.export.export(
model,
(),
kwargs=f(data["inputs"]),
dynamic_shapes=data["dynamic_shapes"],
strict=False,
)
print(ep)


# %%

doc.plot_legend(
"untrained\ncodellama/\nCodeLlama-7b-Python-hf", "torch.export.export", "tomato"
)
1 change: 1 addition & 0 deletions _doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Enlightening Examples
* :ref:`l-plot-export-locale-issue`
* :ref:`l-plot-tiny-llm-export`
* :ref:`l-plot-tiny-llm-export-patched`
* :ref:`l-plot-export-hub-codellama`

**Investigate ONNX models**

Expand Down
24 changes: 20 additions & 4 deletions _unittests/ut_torch_models/test_hghub_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from onnx_diagnostic.ext_test_case import (
ExtTestCase,
hide_stdout,
long_test,
never_test,
requires_torch,
requires_transformers,
Expand All @@ -15,28 +16,32 @@
task_from_arch,
task_from_tags,
)
from onnx_diagnostic.torch_models.hghub.hub_data import load_architecture_task
from onnx_diagnostic.torch_models.hghub.hub_data import (
load_architecture_task,
load_models_testing,
)


class TestHuggingFaceHubApi(ExtTestCase):

@requires_transformers("4.50") # we limit to some versions of the CI
@requires_torch("2.7")
@hide_stdout()
def test_enumerate_model_list(self):
models = list(
enumerate_model_list(
2,
verbose=1,
dump="test_enumerate_model_list.csv",
filter="text-generation",
filter="image-classification",
library="transformers",
)
)
self.assertEqual(len(models), 2)
df = pandas.read_csv("test_enumerate_model_list.csv")
self.assertEqual(df.shape, (2, 12))
tasks = [task_from_id(c) for c in df.id]
self.assertEqual(["text-generation", "text-generation"], tasks)
tasks = [task_from_id(c, "missing") for c in df.id]
self.assertEqual(len(tasks), 2)

@requires_transformers("4.50")
@requires_torch("2.7")
Expand Down Expand Up @@ -111,6 +116,17 @@ def test_task_from_tags(self):
task = task_from_tags(tags)
self.assertEqual(etask, task)

def test_model_testings(self):
models = load_models_testing()
self.assertNotEmpty(models)

@long_test()
def test_model_testings_and_architectures(self):
models = load_models_testing()
for mid in models:
task = task_from_id(mid)
self.assertNotEmpty(task)


if __name__ == "__main__":
unittest.main(verbosity=2)
79 changes: 75 additions & 4 deletions _unittests/ut_torch_models/test_hghub_model.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import pprint
import unittest
import transformers
from onnx_diagnostic.ext_test_case import (
ExtTestCase,
hide_stdout,
long_test,
requires_torch,
requires_transformers,
)
from onnx_diagnostic.torch_models.hghub.model_inputs import (
config_class_from_architecture,
get_untrained_model_with_inputs,
)
from onnx_diagnostic.torch_models.hghub.hub_api import get_pretrained_config
from onnx_diagnostic.torch_models.hghub.hub_data import load_models_testing


class TestHuggingFaceHubModel(ExtTestCase):
Expand All @@ -23,25 +27,38 @@ def test_config_class_from_architecture(self):
def test_get_untrained_model_with_inputs_tiny_llm(self):
mid = "arnir0/Tiny-LLM"
data = get_untrained_model_with_inputs(mid, verbose=1)
self.assertEqual(
set(data),
{
"model",
"inputs",
"dynamic_shapes",
"configuration",
"size",
"n_weights",
"input_kwargs",
"model_kwargs",
},
)
model, inputs = data["model"], data["inputs"]
model(**inputs)
self.assertEqual((1858125824, 464531456), (data["size"], data["n_weights"]))
self.assertEqual((51955968, 12988992), (data["size"], data["n_weights"]))

@hide_stdout()
def test_get_untrained_model_with_inputs_tiny_xlm_roberta(self):
mid = "hf-internal-testing/tiny-xlm-roberta" # XLMRobertaConfig
data = get_untrained_model_with_inputs(mid, verbose=1)
model, inputs = data["model"], data["inputs"]
model(**inputs)
self.assertEqual((126190824, 31547706), (data["size"], data["n_weights"]))
self.assertEqual((8642088, 2160522), (data["size"], data["n_weights"]))

@hide_stdout()
def test_get_untrained_model_with_inputs_tiny_gpt_neo(self):
mid = "hf-internal-testing/tiny-random-GPTNeoXForCausalLM"
data = get_untrained_model_with_inputs(mid, verbose=1)
model, inputs = data["model"], data["inputs"]
model(**inputs)
self.assertEqual((4291141632, 1072785408), (data["size"], data["n_weights"]))
self.assertEqual((316712, 79178), (data["size"], data["n_weights"]))

@hide_stdout()
def test_get_untrained_model_with_inputs_phi_2(self):
Expand All @@ -52,9 +69,63 @@ def test_get_untrained_model_with_inputs_phi_2(self):
# different expected value for different version of transformers
self.assertIn(
(data["size"], data["n_weights"]),
[(1040293888, 260073472), (1040498688, 260124672)],
[(453330944, 113332736), (453126144, 113281536)],
)

@hide_stdout()
def test_get_untrained_model_with_inputs_beit(self):
mid = "hf-internal-testing/tiny-random-BeitForImageClassification"
data = get_untrained_model_with_inputs(mid, verbose=1)
model, inputs = data["model"], data["inputs"]
model(**inputs)
# different expected value for different version of transformers
self.assertIn((data["size"], data["n_weights"]), [(111448, 27862)])

@hide_stdout()
def test_get_untrained_model_with_inputs_codellama(self):
mid = "codellama/CodeLlama-7b-Python-hf"
data = get_untrained_model_with_inputs(mid, verbose=1)
model, inputs = data["model"], data["inputs"]
model(**inputs)
# different expected value for different version of transformers
self.assertIn((data["size"], data["n_weights"]), [(410532864, 102633216)])

@hide_stdout()
@long_test()
def test_get_untrained_model_Ltesting_models(self):
def _diff(c1, c2):
rows = [f"types {c1.__class__.__name__} <> {c2.__class__.__name__}"]
for k, v in c1.__dict__.items():
if isinstance(v, (str, dict, list, tuple, int, float)) and v != getattr(
c2, k, None
):
rows.append(f"{k} :: -- {v} ++ {getattr(c2, k, 'MISS')}")
return "\n".join(rows)

# UNHIDE=1 LONGTEST=1 python _unittests/ut_torch_models/test_hghub_model.py -k L -f
for mid in load_models_testing():
with self.subTest(mid=mid):
data = get_untrained_model_with_inputs(mid, verbose=1)
model, inputs = data["model"], data["inputs"]
try:
model(**inputs)
except Exception as e:
diff = _diff(get_pretrained_config(mid), data["configuration"])
raise AssertionError(
f"Computation failed due to {e}.\n--- pretrained\n"
f"{pprint.pformat(get_pretrained_config(mid))}\n"
f"--- modified\n{data['configuration']}\n"
f"--- diff\n{diff}"
) from e
# different expected value for different version of transformers
if data["size"] > 2**30:
raise AssertionError(
f"Model is too big, size={data['size'] // 2**20} Mb,"
f"config is\n{data['configuration']}"
)
self.assertLess(data["size"], 2**30)
self.assertLess(data["n_weights"], 2**28)


if __name__ == "__main__":
unittest.main(verbosity=2)
27 changes: 27 additions & 0 deletions _unittests/ut_torch_models/try_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import unittest
from onnx_diagnostic.ext_test_case import ExtTestCase, never_test
from onnx_diagnostic.helpers import string_type


class TestHuggingFaceHubModel(ExtTestCase):
@never_test()
def test_image_classiciation(self):

from transformers import ViTImageProcessor, ViTModel
from PIL import Image
import requests

url = "http://images.cocodataset.org/val2017/000000039769.jpg"
image = Image.open(requests.get(url, stream=True).raw)

processor = ViTImageProcessor.from_pretrained("google/vit-base-patch16-224-in21k")
model = ViTModel.from_pretrained("google/vit-base-patch16-224-in21k")
inputs = processor(images=image, return_tensors="pt")
print("inputs", string_type(inputs, with_shape=True, with_min_max=True))

outputs = model(**inputs)
print("outputs", string_type(outputs, with_shape=True, with_min_max=True))


if __name__ == "__main__":
unittest.main(verbosity=2)
Loading
Loading