Spaces:
Runtime error
Runtime error
| # coding=utf-8 | |
| # Copyright 2019 HuggingFace Inc. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| from __future__ import annotations | |
| import inspect | |
| import json | |
| import os | |
| import random | |
| import tempfile | |
| import unittest | |
| import unittest.mock as mock | |
| from huggingface_hub import HfFolder, Repository, delete_repo, snapshot_download | |
| from requests.exceptions import HTTPError | |
| from transformers import is_tf_available, is_torch_available | |
| from transformers.configuration_utils import PretrainedConfig | |
| from transformers.testing_utils import ( # noqa: F401 | |
| TOKEN, | |
| USER, | |
| CaptureLogger, | |
| _tf_gpu_memory_limit, | |
| is_pt_tf_cross_test, | |
| is_staging_test, | |
| require_safetensors, | |
| require_tf, | |
| require_torch, | |
| slow, | |
| ) | |
| from transformers.utils import ( | |
| SAFE_WEIGHTS_INDEX_NAME, | |
| SAFE_WEIGHTS_NAME, | |
| TF2_WEIGHTS_INDEX_NAME, | |
| TF2_WEIGHTS_NAME, | |
| logging, | |
| ) | |
| logger = logging.get_logger(__name__) | |
| if is_tf_available(): | |
| import h5py | |
| import numpy as np | |
| import tensorflow as tf | |
| from transformers import ( | |
| BertConfig, | |
| PreTrainedModel, | |
| PushToHubCallback, | |
| RagRetriever, | |
| TFAutoModel, | |
| TFBertForMaskedLM, | |
| TFBertForSequenceClassification, | |
| TFBertModel, | |
| TFPreTrainedModel, | |
| TFRagModel, | |
| ) | |
| from transformers.modeling_tf_utils import keras, tf_shard_checkpoint, unpack_inputs | |
| from transformers.tf_utils import stable_softmax | |
| tf.config.experimental.enable_tensor_float_32_execution(False) | |
| if _tf_gpu_memory_limit is not None: | |
| gpus = tf.config.list_physical_devices("GPU") | |
| for gpu in gpus: | |
| # Restrict TensorFlow to only allocate x GB of memory on the GPUs | |
| try: | |
| tf.config.set_logical_device_configuration( | |
| gpu, [tf.config.LogicalDeviceConfiguration(memory_limit=_tf_gpu_memory_limit)] | |
| ) | |
| logical_gpus = tf.config.list_logical_devices("GPU") | |
| print("Logical GPUs", logical_gpus) | |
| except RuntimeError as e: | |
| # Virtual devices must be set before GPUs have been initialized | |
| print(e) | |
| if is_torch_available(): | |
| from transformers import BertModel | |
| class TFModelUtilsTest(unittest.TestCase): | |
| def test_cached_files_are_used_when_internet_is_down(self): | |
| # A mock response for an HTTP head request to emulate server down | |
| response_mock = mock.Mock() | |
| response_mock.status_code = 500 | |
| response_mock.headers = {} | |
| response_mock.raise_for_status.side_effect = HTTPError | |
| response_mock.json.return_value = {} | |
| # Download this model to make sure it's in the cache. | |
| _ = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| # Under the mock environment we get a 500 error when trying to reach the model. | |
| with mock.patch("requests.Session.request", return_value=response_mock) as mock_head: | |
| _ = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| # This check we did call the fake head request | |
| mock_head.assert_called() | |
| # tests whether the unpack_inputs function behaves as expected | |
| def test_unpack_inputs(self): | |
| class DummyModel: | |
| def __init__(self): | |
| config_kwargs = {"output_attentions": False, "output_hidden_states": False, "return_dict": False} | |
| self.config = PretrainedConfig(**config_kwargs) | |
| self.main_input_name = "input_ids" | |
| def call( | |
| self, | |
| input_ids=None, | |
| past_key_values=None, | |
| output_attentions=None, | |
| output_hidden_states=None, | |
| return_dict=None, | |
| ): | |
| return input_ids, past_key_values, output_attentions, output_hidden_states, return_dict | |
| def foo(self, pixel_values, output_attentions=None, output_hidden_states=None, return_dict=None): | |
| return pixel_values, output_attentions, output_hidden_states, return_dict | |
| dummy_model = DummyModel() | |
| input_ids = tf.constant([0, 1, 2, 3], dtype=tf.int32) | |
| past_key_values = tf.constant([4, 5, 6, 7], dtype=tf.int32) | |
| pixel_values = tf.constant([8, 9, 10, 11], dtype=tf.int32) | |
| # test case 1: Pass inputs as keyword arguments; Booleans are inherited from the config. | |
| output = dummy_model.call(input_ids=input_ids, past_key_values=past_key_values) | |
| tf.debugging.assert_equal(output[0], input_ids) | |
| tf.debugging.assert_equal(output[1], past_key_values) | |
| self.assertFalse(output[2]) | |
| self.assertFalse(output[3]) | |
| self.assertFalse(output[4]) | |
| # test case 2: Same as above, but with positional arguments. | |
| output = dummy_model.call(input_ids, past_key_values) | |
| tf.debugging.assert_equal(output[0], input_ids) | |
| tf.debugging.assert_equal(output[1], past_key_values) | |
| self.assertFalse(output[2]) | |
| self.assertFalse(output[3]) | |
| self.assertFalse(output[4]) | |
| # test case 3: We can also pack everything in the first input. | |
| output = dummy_model.call(input_ids={"input_ids": input_ids, "past_key_values": past_key_values}) | |
| tf.debugging.assert_equal(output[0], input_ids) | |
| tf.debugging.assert_equal(output[1], past_key_values) | |
| self.assertFalse(output[2]) | |
| self.assertFalse(output[3]) | |
| self.assertFalse(output[4]) | |
| # test case 4: Explicit boolean arguments should override the config. | |
| output = dummy_model.call( | |
| input_ids=input_ids, past_key_values=past_key_values, output_attentions=False, return_dict=True | |
| ) | |
| tf.debugging.assert_equal(output[0], input_ids) | |
| tf.debugging.assert_equal(output[1], past_key_values) | |
| self.assertFalse(output[2]) | |
| self.assertFalse(output[3]) | |
| self.assertTrue(output[4]) | |
| # test case 5: Unexpected arguments should raise an exception. | |
| with self.assertRaises(ValueError): | |
| output = dummy_model.call(input_ids=input_ids, past_key_values=past_key_values, foo="bar") | |
| # test case 6: the decorator is independent from `main_input_name` -- it treats the first argument of the | |
| # decorated function as its main input. | |
| output = dummy_model.foo(pixel_values=pixel_values) | |
| tf.debugging.assert_equal(output[0], pixel_values) | |
| self.assertFalse(output[1]) | |
| self.assertFalse(output[2]) | |
| self.assertFalse(output[3]) | |
| # Tests whether the stable softmax is stable on CPU, with and without XLA | |
| def test_xla_stable_softmax(self): | |
| large_penalty = -1e9 | |
| n_tokens = 10 | |
| batch_size = 8 | |
| def masked_softmax(x, boolean_mask): | |
| numerical_mask = (1.0 - tf.cast(boolean_mask, dtype=tf.float32)) * large_penalty | |
| masked_x = x + numerical_mask | |
| return stable_softmax(masked_x) | |
| xla_masked_softmax = tf.function(masked_softmax, jit_compile=True) | |
| xla_stable_softmax = tf.function(stable_softmax, jit_compile=True) | |
| x = tf.random.normal((batch_size, n_tokens)) | |
| # Same outcome regardless of the boolean mask here | |
| masked_tokens = random.randint(0, n_tokens) | |
| boolean_mask = tf.convert_to_tensor([[1] * (n_tokens - masked_tokens) + [0] * masked_tokens], dtype=tf.int32) | |
| # We can randomly mask a random numerical input OUTSIDE XLA | |
| numerical_mask = (1.0 - tf.cast(boolean_mask, dtype=tf.float32)) * large_penalty | |
| masked_x = x + numerical_mask | |
| xla_out = xla_stable_softmax(masked_x) | |
| out = stable_softmax(masked_x) | |
| assert tf.experimental.numpy.allclose(xla_out, out) | |
| # The stable softmax has the same output as the original softmax | |
| unstable_out = tf.nn.softmax(masked_x) | |
| assert tf.experimental.numpy.allclose(unstable_out, out) | |
| # We can randomly mask a random numerical input INSIDE XLA | |
| xla_out = xla_masked_softmax(x, boolean_mask) | |
| out = masked_softmax(x, boolean_mask) | |
| assert tf.experimental.numpy.allclose(xla_out, out) | |
| def test_checkpoint_sharding_from_hub(self): | |
| model = TFBertModel.from_pretrained("ArthurZ/tiny-random-bert-sharded") | |
| # the model above is the same as the model below, just a sharded version. | |
| ref_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| for p1, p2 in zip(model.weights, ref_model.weights): | |
| assert np.allclose(p1.numpy(), p2.numpy()) | |
| def test_sharded_checkpoint_with_prefix(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert", load_weight_prefix="a/b") | |
| sharded_model = TFBertModel.from_pretrained("ArthurZ/tiny-random-bert-sharded", load_weight_prefix="a/b") | |
| for p1, p2 in zip(model.weights, sharded_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| self.assertTrue(p1.name.startswith("a/b/")) | |
| self.assertTrue(p2.name.startswith("a/b/")) | |
| def test_sharded_checkpoint_transfer(self): | |
| # If this doesn't throw an error then the test passes | |
| TFBertForSequenceClassification.from_pretrained("ArthurZ/tiny-random-bert-sharded") | |
| def test_checkpoint_sharding_local_from_pt(self): | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| _ = Repository(local_dir=tmp_dir, clone_from="hf-internal-testing/tiny-random-bert-sharded") | |
| model = TFBertModel.from_pretrained(tmp_dir, from_pt=True) | |
| # the model above is the same as the model below, just a sharded pytorch version. | |
| ref_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| for p1, p2 in zip(model.weights, ref_model.weights): | |
| assert np.allclose(p1.numpy(), p2.numpy()) | |
| def test_checkpoint_loading_with_prefix_from_pt(self): | |
| model = TFBertModel.from_pretrained( | |
| "hf-internal-testing/tiny-random-bert", from_pt=True, load_weight_prefix="a/b" | |
| ) | |
| ref_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert", from_pt=True) | |
| for p1, p2 in zip(model.weights, ref_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| self.assertTrue(p1.name.startswith("a/b/")) | |
| def test_checkpoint_sharding_hub_from_pt(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert-sharded", from_pt=True) | |
| # the model above is the same as the model below, just a sharded pytorch version. | |
| ref_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| for p1, p2 in zip(model.weights, ref_model.weights): | |
| assert np.allclose(p1.numpy(), p2.numpy()) | |
| def test_shard_checkpoint(self): | |
| # This is the model we will use, total size 340,000 bytes. | |
| model = keras.Sequential( | |
| [ | |
| keras.layers.Dense(200, use_bias=False), # size 80,000 | |
| keras.layers.Dense(200, use_bias=False), # size 160,000 | |
| keras.layers.Dense(100, use_bias=False), # size 80,000 | |
| keras.layers.Dense(50, use_bias=False), # size 20,000 | |
| ] | |
| ) | |
| inputs = tf.zeros((1, 100), dtype=tf.float32) | |
| model(inputs) | |
| weights = model.weights | |
| weights_dict = {w.name: w for w in weights} | |
| with self.subTest("No shard when max size is bigger than model size"): | |
| shards, index = tf_shard_checkpoint(weights) | |
| self.assertIsNone(index) | |
| self.assertDictEqual(shards, {TF2_WEIGHTS_NAME: weights}) | |
| with self.subTest("Test sharding, no weights bigger than max size"): | |
| shards, index = tf_shard_checkpoint(weights, max_shard_size="300kB") | |
| # Split is first two layers then last two. | |
| self.assertDictEqual( | |
| index, | |
| { | |
| "metadata": {"total_size": 340000}, | |
| "weight_map": { | |
| "dense/kernel:0": "tf_model-00001-of-00002.h5", | |
| "dense_1/kernel:0": "tf_model-00001-of-00002.h5", | |
| "dense_2/kernel:0": "tf_model-00002-of-00002.h5", | |
| "dense_3/kernel:0": "tf_model-00002-of-00002.h5", | |
| }, | |
| }, | |
| ) | |
| shard1 = [weights_dict["dense/kernel:0"], weights_dict["dense_1/kernel:0"]] | |
| shard2 = [weights_dict["dense_2/kernel:0"], weights_dict["dense_3/kernel:0"]] | |
| self.assertDictEqual(shards, {"tf_model-00001-of-00002.h5": shard1, "tf_model-00002-of-00002.h5": shard2}) | |
| with self.subTest("Test sharding with weights bigger than max size"): | |
| shards, index = tf_shard_checkpoint(weights, max_shard_size="100kB") | |
| # Split is first layer, second layer then last 2. | |
| self.assertDictEqual( | |
| index, | |
| { | |
| "metadata": {"total_size": 340000}, | |
| "weight_map": { | |
| "dense/kernel:0": "tf_model-00001-of-00003.h5", | |
| "dense_1/kernel:0": "tf_model-00002-of-00003.h5", | |
| "dense_2/kernel:0": "tf_model-00003-of-00003.h5", | |
| "dense_3/kernel:0": "tf_model-00003-of-00003.h5", | |
| }, | |
| }, | |
| ) | |
| shard1 = [weights_dict["dense/kernel:0"]] | |
| shard2 = [weights_dict["dense_1/kernel:0"]] | |
| shard3 = [weights_dict["dense_2/kernel:0"], weights_dict["dense_3/kernel:0"]] | |
| self.assertDictEqual( | |
| shards, | |
| { | |
| "tf_model-00001-of-00003.h5": shard1, | |
| "tf_model-00002-of-00003.h5": shard2, | |
| "tf_model-00003-of-00003.h5": shard3, | |
| }, | |
| ) | |
| def test_special_layer_name_sharding(self): | |
| retriever = RagRetriever.from_pretrained("facebook/rag-token-nq", index_name="exact", use_dummy_dataset=True) | |
| model = TFRagModel.from_pretrained("facebook/rag-token-nq", retriever=retriever) | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| for max_size in ["150kB", "150kiB", "200kB", "200kiB"]: | |
| model.save_pretrained(tmp_dir, max_shard_size=max_size) | |
| ref_model = TFRagModel.from_pretrained(tmp_dir, retriever=retriever) | |
| for p1, p2 in zip(model.weights, ref_model.weights): | |
| assert np.allclose(p1.numpy(), p2.numpy()) | |
| def test_checkpoint_sharding_local(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| # We use the same folder for various sizes to make sure a new save erases the old checkpoint. | |
| for max_size in ["150kB", "150kiB", "200kB", "200kiB"]: | |
| model.save_pretrained(tmp_dir, max_shard_size=max_size) | |
| # Get each shard file and its size | |
| shard_to_size = {} | |
| for shard in os.listdir(tmp_dir): | |
| if shard.endswith(".h5"): | |
| shard_file = os.path.join(tmp_dir, shard) | |
| shard_to_size[shard_file] = os.path.getsize(shard_file) | |
| index_file = os.path.join(tmp_dir, TF2_WEIGHTS_INDEX_NAME) | |
| # Check there is an index but no regular weight file | |
| self.assertTrue(os.path.isfile(index_file)) | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, TF2_WEIGHTS_NAME))) | |
| # Check a file is bigger than max_size only when it has a single weight | |
| for shard_file, size in shard_to_size.items(): | |
| if max_size.endswith("kiB"): | |
| max_size_int = int(max_size[:-3]) * 2**10 | |
| else: | |
| max_size_int = int(max_size[:-2]) * 10**3 | |
| # Note: pickle adds some junk so the weight of the file can end up being slightly bigger than | |
| # the size asked for (since we count parameters) | |
| if size >= max_size_int + 50000: | |
| with h5py.File(shard_file, "r") as state_file: | |
| self.assertEqual(len(state_file), 1) | |
| # Check the index and the shard files found match | |
| with open(index_file, "r", encoding="utf-8") as f: | |
| index = json.loads(f.read()) | |
| all_shards = set(index["weight_map"].values()) | |
| shards_found = {f for f in os.listdir(tmp_dir) if f.endswith(".h5")} | |
| self.assertSetEqual(all_shards, shards_found) | |
| # Finally, check the model can be reloaded | |
| new_model = TFBertModel.from_pretrained(tmp_dir) | |
| model.build_in_name_scope() | |
| new_model.build_in_name_scope() | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_checkpoint_sharding_local(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| # We use the same folder for various sizes to make sure a new save erases the old checkpoint. | |
| for max_size in ["150kB", "150kiB", "200kB", "200kiB"]: | |
| model.save_pretrained(tmp_dir, max_shard_size=max_size, safe_serialization=True) | |
| # Get each shard file and its size | |
| shard_to_size = {} | |
| for shard in os.listdir(tmp_dir): | |
| if shard.endswith(".h5"): | |
| shard_file = os.path.join(tmp_dir, shard) | |
| shard_to_size[shard_file] = os.path.getsize(shard_file) | |
| index_file = os.path.join(tmp_dir, SAFE_WEIGHTS_INDEX_NAME) | |
| # Check there is an index but no regular weight file | |
| self.assertTrue(os.path.isfile(index_file)) | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, SAFE_WEIGHTS_NAME))) | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, TF2_WEIGHTS_NAME))) | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, TF2_WEIGHTS_INDEX_NAME))) | |
| # Check the index and the shard files found match | |
| with open(index_file, "r", encoding="utf-8") as f: | |
| index = json.loads(f.read()) | |
| all_shards = set(index["weight_map"].values()) | |
| shards_found = {f for f in os.listdir(tmp_dir) if f.endswith(".safetensors")} | |
| self.assertSetEqual(all_shards, shards_found) | |
| # Finally, check the model can be reloaded | |
| new_model = TFBertModel.from_pretrained(tmp_dir) | |
| model.build_in_name_scope() | |
| new_model.build_in_name_scope() | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_bfloat16_torch_loading(self): | |
| # Assert that neither of these raise an error - both repos contain bfloat16 tensors | |
| model1 = TFAutoModel.from_pretrained("Rocketknight1/tiny-random-gpt2-bfloat16-pt", from_pt=True) | |
| model2 = TFAutoModel.from_pretrained("Rocketknight1/tiny-random-gpt2-bfloat16") # PT-format safetensors | |
| # Check that PT and safetensors loading paths end up with the same values | |
| for weight1, weight2 in zip(model1.weights, model2.weights): | |
| self.assertTrue(tf.reduce_all(weight1 == weight2)) | |
| def test_save_pretrained_signatures(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| # Short custom TF signature function. | |
| # `input_signature` is specific to BERT. | |
| def serving_fn(input): | |
| return model(input) | |
| # Using default signature (default behavior) overrides 'serving_default' | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| model.save_pretrained(tmp_dir, saved_model=True, signatures=None) | |
| model_loaded = keras.models.load_model(f"{tmp_dir}/saved_model/1") | |
| self.assertTrue("serving_default" in list(model_loaded.signatures.keys())) | |
| # Providing custom signature function | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| model.save_pretrained(tmp_dir, saved_model=True, signatures={"custom_signature": serving_fn}) | |
| model_loaded = keras.models.load_model(f"{tmp_dir}/saved_model/1") | |
| self.assertTrue("custom_signature" in list(model_loaded.signatures.keys())) | |
| # Providing multiple custom signature function | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| model.save_pretrained( | |
| tmp_dir, | |
| saved_model=True, | |
| signatures={"custom_signature_1": serving_fn, "custom_signature_2": serving_fn}, | |
| ) | |
| model_loaded = keras.models.load_model(f"{tmp_dir}/saved_model/1") | |
| self.assertTrue("custom_signature_1" in list(model_loaded.signatures.keys())) | |
| self.assertTrue("custom_signature_2" in list(model_loaded.signatures.keys())) | |
| def test_safetensors_save_and_load(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| model.save_pretrained(tmp_dir, safe_serialization=True) | |
| # No tf_model.h5 file, only a model.safetensors | |
| self.assertTrue(os.path.isfile(os.path.join(tmp_dir, SAFE_WEIGHTS_NAME))) | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, SAFE_WEIGHTS_INDEX_NAME))) | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, TF2_WEIGHTS_NAME))) | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, TF2_WEIGHTS_INDEX_NAME))) | |
| new_model = TFBertModel.from_pretrained(tmp_dir) | |
| # Check models are equal | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_sharded_save_and_load(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| model.save_pretrained(tmp_dir, safe_serialization=True, max_shard_size="150kB") | |
| # No tf weights or index file, only a safetensors index | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, SAFE_WEIGHTS_NAME))) | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, TF2_WEIGHTS_NAME))) | |
| self.assertTrue(os.path.isfile(os.path.join(tmp_dir, SAFE_WEIGHTS_INDEX_NAME))) | |
| self.assertFalse(os.path.isfile(os.path.join(tmp_dir, TF2_WEIGHTS_INDEX_NAME))) | |
| new_model = TFBertModel.from_pretrained(tmp_dir) | |
| # Check models are equal | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_save_and_load_pt_to_tf(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| pt_model = BertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| pt_model.save_pretrained(tmp_dir, safe_serialization=True) | |
| # Check we have a model.safetensors file | |
| self.assertTrue(os.path.isfile(os.path.join(tmp_dir, SAFE_WEIGHTS_NAME))) | |
| new_model = TFBertModel.from_pretrained(tmp_dir) | |
| # Check models are equal | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_sharded_safetensors_save_and_load_pt_to_tf(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| pt_model = BertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| pt_model.save_pretrained(tmp_dir, safe_serialization=True, max_shard_size="150kB") | |
| # Check we have a safetensors shard index file | |
| self.assertTrue(os.path.isfile(os.path.join(tmp_dir, SAFE_WEIGHTS_INDEX_NAME))) | |
| new_model = TFBertModel.from_pretrained(tmp_dir) | |
| # Check models are equal | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_load_from_hub(self): | |
| tf_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert") | |
| # Can load from the TF-formatted checkpoint | |
| safetensors_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert-safetensors-tf") | |
| # Check models are equal | |
| for p1, p2 in zip(safetensors_model.weights, tf_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| # Can load from the PyTorch-formatted checkpoint | |
| safetensors_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert-safetensors") | |
| # Check models are equal | |
| for p1, p2 in zip(safetensors_model.weights, tf_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_tf_from_tf(self): | |
| model = TFBertModel.from_pretrained("hf-internal-testing/tiny-bert-tf-only") | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| model.save_pretrained(tmp_dir, safe_serialization=True) | |
| new_model = TFBertModel.from_pretrained(tmp_dir) | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_tf_from_torch(self): | |
| hub_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-bert-tf-only") | |
| model = BertModel.from_pretrained("hf-internal-testing/tiny-bert-pt-only") | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| model.save_pretrained(tmp_dir, safe_serialization=True) | |
| new_model = TFBertModel.from_pretrained(tmp_dir) | |
| for p1, p2 in zip(hub_model.weights, new_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_tf_from_sharded_h5_with_sharded_safetensors_local(self): | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| path = snapshot_download("hf-internal-testing/tiny-bert-tf-safetensors-h5-sharded", cache_dir=tmp_dir) | |
| # This should not raise even if there are two types of sharded weights | |
| TFBertModel.from_pretrained(path) | |
| def test_safetensors_tf_from_sharded_h5_with_sharded_safetensors_hub(self): | |
| # Confirm that we can correctly load the safetensors weights from a sharded hub repo even when TF weights present | |
| TFBertModel.from_pretrained("hf-internal-testing/tiny-bert-tf-safetensors-h5-sharded", use_safetensors=True) | |
| # Confirm that we can access the TF weights too | |
| TFBertModel.from_pretrained("hf-internal-testing/tiny-bert-tf-safetensors-h5-sharded", use_safetensors=False) | |
| def test_safetensors_load_from_local(self): | |
| """ | |
| This test checks that we can load safetensors from a checkpoint that only has those on the Hub | |
| """ | |
| with tempfile.TemporaryDirectory() as tmp: | |
| location = snapshot_download("hf-internal-testing/tiny-bert-tf-only", cache_dir=tmp) | |
| tf_model = TFBertModel.from_pretrained(location) | |
| with tempfile.TemporaryDirectory() as tmp: | |
| location = snapshot_download("hf-internal-testing/tiny-bert-tf-safetensors-only", cache_dir=tmp) | |
| safetensors_model = TFBertModel.from_pretrained(location) | |
| for p1, p2 in zip(tf_model.weights, safetensors_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_load_from_hub_from_safetensors_pt(self): | |
| """ | |
| This test checks that we can load safetensors from a checkpoint that only has those on the Hub. | |
| saved in the "pt" format. | |
| """ | |
| tf_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-bert-h5") | |
| # Can load from the PyTorch-formatted checkpoint | |
| safetensors_model = TFBertModel.from_pretrained("hf-internal-testing/tiny-bert-pt-safetensors") | |
| for p1, p2 in zip(tf_model.weights, safetensors_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_load_from_local_from_safetensors_pt(self): | |
| """ | |
| This test checks that we can load safetensors from a local checkpoint that only has those | |
| saved in the "pt" format. | |
| """ | |
| with tempfile.TemporaryDirectory() as tmp: | |
| location = snapshot_download("hf-internal-testing/tiny-bert-h5", cache_dir=tmp) | |
| tf_model = TFBertModel.from_pretrained(location) | |
| # Can load from the PyTorch-formatted checkpoint | |
| with tempfile.TemporaryDirectory() as tmp: | |
| location = snapshot_download("hf-internal-testing/tiny-bert-pt-safetensors", cache_dir=tmp) | |
| safetensors_model = TFBertModel.from_pretrained(location) | |
| for p1, p2 in zip(tf_model.weights, safetensors_model.weights): | |
| self.assertTrue(np.allclose(p1.numpy(), p2.numpy())) | |
| def test_safetensors_load_from_hub_h5_before_safetensors(self): | |
| """ | |
| This test checks that we'll first download h5 weights before safetensors | |
| The safetensors file on that repo is a pt safetensors and therefore cannot be loaded without PyTorch | |
| """ | |
| TFBertModel.from_pretrained("hf-internal-testing/tiny-bert-pt-safetensors-msgpack") | |
| def test_safetensors_load_from_local_h5_before_safetensors(self): | |
| """ | |
| This test checks that we'll first download h5 weights before safetensors | |
| The safetensors file on that repo is a pt safetensors and therefore cannot be loaded without PyTorch | |
| """ | |
| with tempfile.TemporaryDirectory() as tmp: | |
| location = snapshot_download("hf-internal-testing/tiny-bert-pt-safetensors-msgpack", cache_dir=tmp) | |
| TFBertModel.from_pretrained(location) | |
| class TFModelPushToHubTester(unittest.TestCase): | |
| def setUpClass(cls): | |
| cls._token = TOKEN | |
| HfFolder.save_token(TOKEN) | |
| def tearDownClass(cls): | |
| try: | |
| delete_repo(token=cls._token, repo_id="test-model-tf") | |
| except HTTPError: | |
| pass | |
| try: | |
| delete_repo(token=cls._token, repo_id="test-model-tf-callback") | |
| except HTTPError: | |
| pass | |
| try: | |
| delete_repo(token=cls._token, repo_id="valid_org/test-model-tf-org") | |
| except HTTPError: | |
| pass | |
| def test_push_to_hub(self): | |
| config = BertConfig( | |
| vocab_size=99, hidden_size=32, num_hidden_layers=5, num_attention_heads=4, intermediate_size=37 | |
| ) | |
| model = TFBertModel(config) | |
| # Make sure model is properly initialized | |
| model.build_in_name_scope() | |
| logging.set_verbosity_info() | |
| logger = logging.get_logger("transformers.utils.hub") | |
| with CaptureLogger(logger) as cl: | |
| model.push_to_hub("test-model-tf", token=self._token) | |
| logging.set_verbosity_warning() | |
| # Check the model card was created and uploaded. | |
| self.assertIn("Uploading the following files to __DUMMY_TRANSFORMERS_USER__/test-model-tf", cl.out) | |
| new_model = TFBertModel.from_pretrained(f"{USER}/test-model-tf") | |
| models_equal = True | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| if not tf.math.reduce_all(p1 == p2): | |
| models_equal = False | |
| break | |
| self.assertTrue(models_equal) | |
| # Reset repo | |
| delete_repo(token=self._token, repo_id="test-model-tf") | |
| # Push to hub via save_pretrained | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| model.save_pretrained(tmp_dir, repo_id="test-model-tf", push_to_hub=True, token=self._token) | |
| new_model = TFBertModel.from_pretrained(f"{USER}/test-model-tf") | |
| models_equal = True | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| if not tf.math.reduce_all(p1 == p2): | |
| models_equal = False | |
| break | |
| self.assertTrue(models_equal) | |
| def test_push_to_hub_callback(self): | |
| config = BertConfig( | |
| vocab_size=99, hidden_size=32, num_hidden_layers=5, num_attention_heads=4, intermediate_size=37 | |
| ) | |
| model = TFBertForMaskedLM(config) | |
| model.compile() | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| push_to_hub_callback = PushToHubCallback( | |
| output_dir=tmp_dir, | |
| hub_model_id="test-model-tf-callback", | |
| hub_token=self._token, | |
| ) | |
| model.fit(model.dummy_inputs, model.dummy_inputs, epochs=1, callbacks=[push_to_hub_callback]) | |
| new_model = TFBertForMaskedLM.from_pretrained(f"{USER}/test-model-tf-callback") | |
| models_equal = True | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| if not tf.math.reduce_all(p1 == p2): | |
| models_equal = False | |
| break | |
| self.assertTrue(models_equal) | |
| tf_push_to_hub_params = dict(inspect.signature(TFPreTrainedModel.push_to_hub).parameters) | |
| tf_push_to_hub_params.pop("base_model_card_args") | |
| pt_push_to_hub_params = dict(inspect.signature(PreTrainedModel.push_to_hub).parameters) | |
| pt_push_to_hub_params.pop("deprecated_kwargs") | |
| self.assertDictEaual(tf_push_to_hub_params, pt_push_to_hub_params) | |
| def test_push_to_hub_in_organization(self): | |
| config = BertConfig( | |
| vocab_size=99, hidden_size=32, num_hidden_layers=5, num_attention_heads=4, intermediate_size=37 | |
| ) | |
| model = TFBertModel(config) | |
| # Make sure model is properly initialized | |
| model.build_in_name_scope() | |
| model.push_to_hub("valid_org/test-model-tf-org", token=self._token) | |
| new_model = TFBertModel.from_pretrained("valid_org/test-model-tf-org") | |
| models_equal = True | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| if not tf.math.reduce_all(p1 == p2): | |
| models_equal = False | |
| break | |
| self.assertTrue(models_equal) | |
| # Reset repo | |
| delete_repo(token=self._token, repo_id="valid_org/test-model-tf-org") | |
| # Push to hub via save_pretrained | |
| with tempfile.TemporaryDirectory() as tmp_dir: | |
| model.save_pretrained(tmp_dir, push_to_hub=True, token=self._token, repo_id="valid_org/test-model-tf-org") | |
| new_model = TFBertModel.from_pretrained("valid_org/test-model-tf-org") | |
| models_equal = True | |
| for p1, p2 in zip(model.weights, new_model.weights): | |
| if not tf.math.reduce_all(p1 == p2): | |
| models_equal = False | |
| break | |
| self.assertTrue(models_equal) | |