test_modeling_tf_common.py 119 KB
Newer Older
thomwolf's avatar
thomwolf committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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.
Aymeric Augustin's avatar
Aymeric Augustin committed
15

thomwolf's avatar
thomwolf committed
16

Matt's avatar
Matt committed
17
18
from __future__ import annotations

thomwolf's avatar
thomwolf committed
19
import copy
20
import inspect
21
import json
Aymeric Augustin's avatar
Aymeric Augustin committed
22
import os
thomwolf's avatar
thomwolf committed
23
import random
Aymeric Augustin's avatar
Aymeric Augustin committed
24
import tempfile
25
import unittest
26
import unittest.mock as mock
27
from importlib import import_module
Matt's avatar
Matt committed
28
from math import isnan
Matt's avatar
Matt committed
29
from typing import List, Tuple
thomwolf's avatar
thomwolf committed
30

31
from datasets import Dataset
32
from huggingface_hub import HfFolder, Repository, delete_repo
33
from huggingface_hub.file_download import http_get
Sylvain Gugger's avatar
Sylvain Gugger committed
34
from requests.exceptions import HTTPError
35

36
from transformers import is_tf_available, is_torch_available
37
from transformers.configuration_utils import PretrainedConfig
38
from transformers.models.auto import get_values
39
from transformers.testing_utils import (  # noqa: F401
40
    TOKEN,
Sylvain Gugger's avatar
Sylvain Gugger committed
41
    USER,
42
    CaptureLogger,
43
    CaptureStdout,
Lysandre Debut's avatar
Lysandre Debut committed
44
45
    _tf_gpu_memory_limit,
    is_pt_tf_cross_test,
Sylvain Gugger's avatar
Sylvain Gugger committed
46
    is_staging_test,
Sylvain Gugger's avatar
Sylvain Gugger committed
47
    require_safetensors,
Lysandre Debut's avatar
Lysandre Debut committed
48
    require_tf,
49
    require_tf2onnx,
Lysandre Debut's avatar
Lysandre Debut committed
50
    slow,
51
    tooslow,
52
    torch_device,
Lysandre Debut's avatar
Lysandre Debut committed
53
)
54
55
56
57
58
59
60
61
from transformers.utils import (
    CONFIG_NAME,
    GENERATION_CONFIG_NAME,
    SAFE_WEIGHTS_NAME,
    TF2_WEIGHTS_INDEX_NAME,
    TF2_WEIGHTS_NAME,
    logging,
)
62
from transformers.utils.generic import ModelOutput
63

Aymeric Augustin's avatar
Aymeric Augustin committed
64

65
66
67
logger = logging.get_logger(__name__)


68
if is_tf_available():
Arthur's avatar
Arthur committed
69
    import h5py
thomwolf's avatar
thomwolf committed
70
    import numpy as np
71
    import tensorflow as tf
72

73
    from transformers import (
74
        TF_MODEL_FOR_CAUSAL_LM_MAPPING,
75
        TF_MODEL_FOR_DOCUMENT_QUESTION_ANSWERING_MAPPING,
Yih-Dar's avatar
Yih-Dar committed
76
        TF_MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING,
77
        TF_MODEL_FOR_MASKED_IMAGE_MODELING_MAPPING,
78
        TF_MODEL_FOR_MASKED_LM_MAPPING,
79
        TF_MODEL_FOR_MULTIPLE_CHOICE_MAPPING,
80
        TF_MODEL_FOR_NEXT_SENTENCE_PREDICTION_MAPPING,
81
        TF_MODEL_FOR_PRETRAINING_MAPPING,
82
        TF_MODEL_FOR_QUESTION_ANSWERING_MAPPING,
83
        TF_MODEL_FOR_SEMANTIC_SEGMENTATION_MAPPING,
84
        TF_MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING,
85
        TF_MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING,
Joao Gante's avatar
Joao Gante committed
86
        TF_MODEL_FOR_SPEECH_SEQ_2_SEQ_MAPPING,
87
        TF_MODEL_FOR_TOKEN_CLASSIFICATION_MAPPING,
Sylvain Gugger's avatar
Sylvain Gugger committed
88
        BertConfig,
89
        PreTrainedModel,
90
        PushToHubCallback,
91
        RagRetriever,
92
        TFAutoModel,
93
        TFAutoModelForSequenceClassification,
94
        TFBertForMaskedLM,
95
        TFBertForSequenceClassification,
Sylvain Gugger's avatar
Sylvain Gugger committed
96
        TFBertModel,
97
        TFPreTrainedModel,
98
        TFRagModel,
99
        TFSharedEmbeddings,
100
    )
101
    from transformers.generation import (
102
103
104
105
106
107
108
109
110
        TFBeamSampleDecoderOnlyOutput,
        TFBeamSampleEncoderDecoderOutput,
        TFBeamSearchDecoderOnlyOutput,
        TFBeamSearchEncoderDecoderOutput,
        TFGreedySearchDecoderOnlyOutput,
        TFGreedySearchEncoderDecoderOutput,
        TFSampleDecoderOnlyOutput,
        TFSampleEncoderDecoderOutput,
    )
Sylvain Gugger's avatar
Sylvain Gugger committed
111
    from transformers.modeling_tf_utils import tf_shard_checkpoint, unpack_inputs
Joao Gante's avatar
Joao Gante committed
112
    from transformers.tf_utils import stable_softmax
113

114
115
    tf.config.experimental.enable_tensor_float_32_execution(False)

Julien Chaumond's avatar
Julien Chaumond committed
116
117
118
119
120
    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:
Julien Plu's avatar
Julien Plu committed
121
122
                tf.config.set_logical_device_configuration(
                    gpu, [tf.config.LogicalDeviceConfiguration(memory_limit=_tf_gpu_memory_limit)]
Julien Chaumond's avatar
Julien Chaumond committed
123
                )
Julien Plu's avatar
Julien Plu committed
124
                logical_gpus = tf.config.list_logical_devices("GPU")
Julien Chaumond's avatar
Julien Chaumond committed
125
126
127
128
                print("Logical GPUs", logical_gpus)
            except RuntimeError as e:
                # Virtual devices must be set before GPUs have been initialized
                print(e)
thomwolf's avatar
thomwolf committed
129

130
131
132
if is_torch_available():
    import torch

Sylvain Gugger's avatar
Sylvain Gugger committed
133
134
    from transformers import BertModel

135

thomwolf's avatar
thomwolf committed
136
137
138
def _config_zero_init(config):
    configs_no_init = copy.deepcopy(config)
    for key in configs_no_init.__dict__.keys():
139
        if "_range" in key or "_std" in key:
thomwolf's avatar
thomwolf committed
140
141
142
143
            setattr(configs_no_init, key, 0.0)
    return configs_no_init


144
145
146
147
@require_tf
class TFModelTesterMixin:
    model_tester = None
    all_model_classes = ()
148
    all_generative_model_classes = ()
149
    test_mismatched_shapes = True
150
    test_resize_embeddings = True
151
    test_head_masking = True
152
    is_encoder_decoder = False
153
    has_attentions = True
154

Lysandre Debut's avatar
Lysandre Debut committed
155
    def _prepare_for_class(self, inputs_dict, model_class, return_labels=False) -> dict:
156
157
        inputs_dict = copy.deepcopy(inputs_dict)

158
        if model_class in get_values(TF_MODEL_FOR_MULTIPLE_CHOICE_MAPPING):
159
            inputs_dict = {
160
161
                k: tf.tile(tf.expand_dims(v, 1), (1, self.model_tester.num_choices) + (1,) * (v.ndim - 1))
                if isinstance(v, tf.Tensor) and v.ndim > 0
162
163
164
                else v
                for k, v in inputs_dict.items()
            }
165
166

        if return_labels:
167
            if model_class in get_values(TF_MODEL_FOR_MULTIPLE_CHOICE_MAPPING):
168
                inputs_dict["labels"] = tf.ones(self.model_tester.batch_size, dtype=tf.int32)
169
170
171
172
            elif model_class in [
                *get_values(TF_MODEL_FOR_QUESTION_ANSWERING_MAPPING),
                *get_values(TF_MODEL_FOR_DOCUMENT_QUESTION_ANSWERING_MAPPING),
            ]:
173
174
                inputs_dict["start_positions"] = tf.zeros(self.model_tester.batch_size, dtype=tf.int32)
                inputs_dict["end_positions"] = tf.zeros(self.model_tester.batch_size, dtype=tf.int32)
Yih-Dar's avatar
Yih-Dar committed
175
176
177
178
            elif model_class in [
                *get_values(TF_MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING),
                *get_values(TF_MODEL_FOR_IMAGE_CLASSIFICATION_MAPPING),
            ]:
179
                inputs_dict["labels"] = tf.zeros(self.model_tester.batch_size, dtype=tf.int32)
180
            elif model_class in get_values(TF_MODEL_FOR_NEXT_SENTENCE_PREDICTION_MAPPING):
181
                inputs_dict["next_sentence_label"] = tf.zeros(self.model_tester.batch_size, dtype=tf.int32)
182
            elif model_class in [
183
184
185
186
187
                *get_values(TF_MODEL_FOR_TOKEN_CLASSIFICATION_MAPPING),
                *get_values(TF_MODEL_FOR_CAUSAL_LM_MAPPING),
                *get_values(TF_MODEL_FOR_MASKED_LM_MAPPING),
                *get_values(TF_MODEL_FOR_PRETRAINING_MAPPING),
                *get_values(TF_MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING),
Joao Gante's avatar
Joao Gante committed
188
                *get_values(TF_MODEL_FOR_SPEECH_SEQ_2_SEQ_MAPPING),
189
            ] and "labels" in dict(inspect.signature(model_class.call).parameters):
190
191
192
                inputs_dict["labels"] = tf.zeros(
                    (self.model_tester.batch_size, self.model_tester.seq_length), dtype=tf.int32
                )
193
194
195
196
197
198
199
200
            elif model_class in get_values(TF_MODEL_FOR_MASKED_IMAGE_MODELING_MAPPING):
                num_patches = self.model_tester.image_size // self.model_tester.patch_size
                inputs_dict["bool_masked_pos"] = tf.zeros(
                    (self.model_tester.batch_size, num_patches**2), dtype=tf.int32
                )
            elif model_class in get_values(TF_MODEL_FOR_SEMANTIC_SEGMENTATION_MAPPING):
                batch_size, num_channels, height, width = inputs_dict["pixel_values"].shape
                inputs_dict["labels"] = tf.zeros((self.model_tester.batch_size, height, width), dtype=tf.int32)
201
202
203
204
205
            elif model_class.__name__.endswith("ForCTC"):
                # When we have enough CTC models for an AutoClass, we should use their mapping instead of name checks
                inputs_dict["labels"] = tf.zeros(
                    (self.model_tester.batch_size, self.model_tester.seq_length), dtype=tf.int32
                )
206

207
208
        return inputs_dict

209
210
    def test_initialization(self):
        pass
211

212
213
    def test_save_load(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
214

215
216
        for model_class in self.all_model_classes:
            model = model_class(config)
217
            outputs = model(self._prepare_for_class(inputs_dict, model_class))
218

219
            with tempfile.TemporaryDirectory() as tmpdirname:
Julien Plu's avatar
Julien Plu committed
220
                model.save_pretrained(tmpdirname, saved_model=False)
221
222
223
224
225
226
227

                # the config file (and the generation config file, if it can generate) should be saved
                self.assertTrue(os.path.exists(os.path.join(tmpdirname, CONFIG_NAME)))
                self.assertEqual(
                    model.can_generate(), os.path.exists(os.path.join(tmpdirname, GENERATION_CONFIG_NAME))
                )

228
                model = model_class.from_pretrained(tmpdirname)
229
                after_outputs = model(self._prepare_for_class(inputs_dict, model_class))
230

231
                self.assert_outputs_same(after_outputs, outputs)
232

233
234
235
236
237
238
    def test_save_load_config(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_model_classes:
            model = model_class(config)
            outputs = model(self._prepare_for_class(inputs_dict, model_class))
239
240
241
            model_config = model.get_config()
            # make sure that returned config is jsonifiable, which is required by keras
            json.dumps(model_config)
242
            new_model = model_class.from_config(model.get_config())
243
244
            # make sure it also accepts a normal config
            _ = model_class.from_config(model.config)
245
246
247
248
249
250
            _ = new_model(self._prepare_for_class(inputs_dict, model_class))  # Build model
            new_model.set_weights(model.get_weights())
            after_outputs = new_model(self._prepare_for_class(inputs_dict, model_class))

            self.assert_outputs_same(after_outputs, outputs)

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
    @slow
    def test_saved_model_creation(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        config.output_hidden_states = False
        config.output_attentions = False

        if hasattr(config, "use_cache"):
            config.use_cache = False

        model_class = self.all_model_classes[0]

        class_inputs_dict = self._prepare_for_class(inputs_dict, model_class)
        model = model_class(config)

        model(class_inputs_dict)

        with tempfile.TemporaryDirectory() as tmpdirname:
            model.save_pretrained(tmpdirname, saved_model=True)
            saved_model_dir = os.path.join(tmpdirname, "saved_model", "1")
            self.assertTrue(os.path.exists(saved_model_dir))

    def test_prepare_serving_output(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        config.output_hidden_states = True
        config.output_attentions = self.has_attentions

        for model_class in self.all_model_classes:
            model = model_class(config)
            inputs = self._prepare_for_class(inputs_dict, model_class)
            outputs = model(inputs)
            serving_outputs = model.serving_output(outputs)

            for k, v in serving_outputs.items():
                # Check that we have one of three possible outputs: None, tuple of tensors or a tensor
                if isinstance(v, tuple):
                    self.assertTrue(all(isinstance(elem, tf.Tensor) for elem in v))
                elif v is not None:
                    self.assertIsInstance(v, tf.Tensor)
                else:
                    self.assertIsNone(v)

292
293
294
295
296
297
298
299
300
301
302
    def test_forward_signature(self):
        config, _ = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_model_classes:
            model = model_class(config)
            signature = inspect.signature(model.call)
            # signature.parameters is an OrderedDict => so arg_names order is deterministic
            arg_names = [*signature.parameters.keys()]

            if model.config.is_encoder_decoder:
                expected_arg_names = [
Julien Plu's avatar
Julien Plu committed
303
                    "input_ids",
304
305
306
307
                    "attention_mask",
                    "decoder_input_ids",
                    "decoder_attention_mask",
                ]
308
                expected_arg_names.extend(["decoder_position_ids"] if "decoder_position_ids" in arg_names else [])
309
                expected_arg_names.extend(
310
311
312
313
314
                    ["head_mask", "decoder_head_mask"] if "head_mask" and "decoder_head_mask" in arg_names else []
                )
                expected_arg_names.extend(
                    ["cross_attn_head_mask", "encoder_outputs"]
                    if "cross_attn_head_mask" in arg_names
315
316
317
                    else ["encoder_outputs"]
                )
                self.assertListEqual(arg_names[: len(expected_arg_names)], expected_arg_names)
318
319

            else:
Julien Plu's avatar
Julien Plu committed
320
                expected_arg_names = ["input_ids"]
321
322
                self.assertListEqual(arg_names[:1], expected_arg_names)

323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
    def test_onnx_compliancy(self):
        if not self.test_onnx:
            return

        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        INTERNAL_OPS = [
            "Assert",
            "AssignVariableOp",
            "EmptyTensorList",
            "ReadVariableOp",
            "ResourceGather",
            "TruncatedNormal",
            "VarHandleOp",
            "VarIsInitializedOp",
        ]
        onnx_ops = []

        with open(os.path.join(".", "utils", "tf_ops", "onnx.json")) as f:
            onnx_opsets = json.load(f)["opsets"]

        for i in range(1, self.onnx_min_opset + 1):
            onnx_ops.extend(onnx_opsets[str(i)])

        for model_class in self.all_model_classes:
            model_op_names = set()

            with tf.Graph().as_default() as g:
                model = model_class(config)
                model(model.dummy_inputs)

                for op in g.get_operations():
                    model_op_names.add(op.node_def.op)

            model_op_names = sorted(model_op_names)
            incompatible_ops = []

            for op in model_op_names:
                if op not in onnx_ops and op not in INTERNAL_OPS:
                    incompatible_ops.append(op)

            self.assertEqual(len(incompatible_ops), 0, incompatible_ops)

365
    @require_tf2onnx
366
367
368
369
370
371
    @slow
    def test_onnx_runtime_optimize(self):
        if not self.test_onnx:
            return

        import onnxruntime
372
        import tf2onnx
373
374
375
376
377
378
379

        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_model_classes:
            model = model_class(config)
            model(model.dummy_inputs)

380
            onnx_model_proto, _ = tf2onnx.convert.from_keras(model, opset=self.onnx_min_opset)
381

382
            onnxruntime.InferenceSession(onnx_model_proto.SerializeToString())
383

384
385
386
    def test_keras_save_load(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

387
        tf_main_layer_classes = {
388
389
390
391
            module_member
            for model_class in self.all_model_classes
            for module in (import_module(model_class.__module__),)
            for module_member_name in dir(module)
392
            if module_member_name.endswith("MainLayer")
Yih-Dar's avatar
Yih-Dar committed
393
394
            # This condition is required, since `modeling_tf_clip.py` has 3 classes whose names end with `MainLayer`.
            and module_member_name[: -len("MainLayer")] == model_class.__name__[: -len("Model")]
395
            for module_member in (getattr(module, module_member_name),)
396
397
398
            if isinstance(module_member, type)
            and tf.keras.layers.Layer in module_member.__bases__
            and getattr(module_member, "_keras_serializable", False)
399
        }
400
        for main_layer_class in tf_main_layer_classes:
Julien Plu's avatar
Julien Plu committed
401
402
403
404
            # T5MainLayer needs an embed_tokens parameter when called without the inputs_embeds parameter
            if "T5" in main_layer_class.__name__:
                # Take the same values than in TFT5ModelTester for this shared layer
                shared = TFSharedEmbeddings(99, 32, name="shared")
Julien Plu's avatar
Julien Plu committed
405
                config.use_cache = inputs_dict.pop("use_cache", None)
Julien Plu's avatar
Julien Plu committed
406
407
408
                main_layer = main_layer_class(config, embed_tokens=shared)
            else:
                main_layer = main_layer_class(config)
Julien Plu's avatar
Julien Plu committed
409

410
411
412
            symbolic_inputs = {
                name: tf.keras.Input(tensor.shape[1:], dtype=tensor.dtype) for name, tensor in inputs_dict.items()
            }
Julien Plu's avatar
Julien Plu committed
413

414
415
416
417
418
419
            model = tf.keras.Model(symbolic_inputs, outputs=main_layer(symbolic_inputs))
            outputs = model(inputs_dict)

            with tempfile.TemporaryDirectory() as tmpdirname:
                filepath = os.path.join(tmpdirname, "keras_model.h5")
                model.save(filepath)
Julien Plu's avatar
Julien Plu committed
420
421
422
423
424
425
426
427
428
429
430
431
                if "T5" in main_layer_class.__name__:
                    model = tf.keras.models.load_model(
                        filepath,
                        custom_objects={
                            main_layer_class.__name__: main_layer_class,
                            "TFSharedEmbeddings": TFSharedEmbeddings,
                        },
                    )
                else:
                    model = tf.keras.models.load_model(
                        filepath, custom_objects={main_layer_class.__name__: main_layer_class}
                    )
432
433
434
435
436
437
                assert isinstance(model, tf.keras.Model)
                after_outputs = model(inputs_dict)
                self.assert_outputs_same(after_outputs, outputs)

    def assert_outputs_same(self, after_outputs, outputs):
        # Make sure we don't have nans
Julien Plu's avatar
Julien Plu committed
438
439
        if isinstance(after_outputs, tf.Tensor):
            out_1 = after_outputs.numpy()
Sylvain Gugger's avatar
Sylvain Gugger committed
440
        elif isinstance(after_outputs, dict):
441
            out_1 = after_outputs[list(after_outputs.keys())[0]].numpy()
Julien Plu's avatar
Julien Plu committed
442
443
        else:
            out_1 = after_outputs[0].numpy()
444
        out_2 = outputs[0].numpy()
445
        self.assertEqual(out_1.shape, out_2.shape)
446
447
448
449
        out_1 = out_1[~np.isnan(out_1)]
        out_2 = out_2[~np.isnan(out_2)]
        max_diff = np.amax(np.abs(out_1 - out_2))
        self.assertLessEqual(max_diff, 1e-5)
450

451
452
453
454
    # Don't copy this method to model specific test file!
    # TODO: remove this method once the issues are all fixed!
    def _make_attention_mask_non_null(self, inputs_dict):
        """Make sure no sequence has all zeros as attention mask"""
455

456
457
458
        for k in ["attention_mask", "encoder_attention_mask", "decoder_attention_mask"]:
            if k in inputs_dict:
                attention_mask = inputs_dict[k]
thomwolf's avatar
thomwolf committed
459

460
461
462
463
464
465
                # Make sure no all 0s attention masks - to avoid failure at this moment.
                # Put `1` at the beginning of sequences to make it still work when combining causal attention masks.
                # TODO: remove this line once a fix regarding large negative values for attention mask is done.
                attention_mask = tf.concat(
                    [tf.ones_like(attention_mask[:, :1], dtype=attention_mask.dtype), attention_mask[:, 1:]], axis=-1
                )
466

467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
                # Here we make the first sequence with all 0s as attention mask.
                # Currently, this will fail for `TFWav2Vec2Model`. This is caused by the different large negative
                # values, like `1e-4`, `1e-9`, `1e-30` and `-inf` for attention mask across models/frameworks.
                # TODO: enable this block once the large negative values thing is cleaned up.
                # (see https://github.com/huggingface/transformers/issues/14859)
                # attention_mask = tf.concat(
                #     [
                #         tf.zeros_like(attention_mask[:1], dtype=tf.int32),
                #         tf.cast(attention_mask[1:], dtype=tf.int32)
                #     ],
                #     axis=0
                # )

                inputs_dict[k] = attention_mask

    # Don't copy this method to model specific test file!
    # TODO: remove this method once the issues are all fixed!
    def _postprocessing_to_ignore_test_cases(self, tf_outputs, pt_outputs, model_class):
        """For temporarily ignoring some failed test cases (issues to be fixed)"""

487
488
        tf_keys = {k for k, v in tf_outputs.items() if v is not None}
        pt_keys = {k for k, v in pt_outputs.items() if v is not None}
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514

        key_differences = tf_keys.symmetric_difference(pt_keys)

        if model_class.__name__ in [
            "TFFlaubertWithLMHeadModel",
            "TFFunnelForPreTraining",
            "TFElectraForPreTraining",
            "TFXLMWithLMHeadModel",
            "TFTransfoXLLMHeadModel",
        ]:
            for k in key_differences:
                if k in ["loss", "losses"]:
                    tf_keys.discard(k)
                    pt_keys.discard(k)
        elif model_class.__name__.startswith("TFGPT2"):
            # `TFGPT2` has `past_key_values` as a tensor while `GPT2` has it as a tuple.
            tf_keys.discard("past_key_values")
            pt_keys.discard("past_key_values")

        # create new outputs from the remaining fields
        new_tf_outputs = type(tf_outputs)(**{k: tf_outputs[k] for k in tf_keys})
        new_pt_outputs = type(pt_outputs)(**{k: pt_outputs[k] for k in pt_keys})

        return new_tf_outputs, new_pt_outputs

    def check_pt_tf_outputs(self, tf_outputs, pt_outputs, model_class, tol=1e-5, name="outputs", attributes=None):
515
        """Check the outputs from PyTorch and TensorFlow models are close enough. Checks are done in a recursive way.
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535

        Args:
            model_class: The class of the model that is currently testing. For example, `TFBertModel`,
                TFBertForMaskedLM`, `TFBertForSequenceClassification`, etc. Mainly used for providing more informative
                error messages.
            name (`str`): The name of the output. For example, `output.hidden_states`, `output.attentions`, etc.
            attributes (`Tuple[str]`): The names of the output's element if the output is a tuple/list with each element
                being a named field in the output.
        """

        self.assertEqual(type(name), str)
        if attributes is not None:
            self.assertEqual(type(attributes), tuple, f"{name}: The argument `attributes` should be a `tuple`")

        # Allow `ModelOutput` (e.g. `CLIPOutput` has `text_model_output` and `vision_model_output`).
        if isinstance(tf_outputs, ModelOutput):
            self.assertTrue(
                isinstance(pt_outputs, ModelOutput),
                f"{name}: `pt_outputs` should an instance of `ModelOutput` when `tf_outputs` is",
            )
536

537
538
539
            # Don't copy this block to model specific test file!
            # TODO: remove this method and this line after issues are fixed
            tf_outputs, pt_outputs = self._postprocessing_to_ignore_test_cases(tf_outputs, pt_outputs, model_class)
540

541
542
            tf_keys = [k for k, v in tf_outputs.items() if v is not None]
            pt_keys = [k for k, v in pt_outputs.items() if v is not None]
543

544
            self.assertEqual(tf_keys, pt_keys, f"{name}: Output keys differ between TF and PyTorch")
545

546
547
548
549
550
551
            # convert to the case of `tuple`
            # appending each key to the current (string) `names`
            attributes = tuple([f"{name}.{k}" for k in tf_keys])
            self.check_pt_tf_outputs(
                tf_outputs.to_tuple(), pt_outputs.to_tuple(), model_class, tol=tol, name=name, attributes=attributes
            )
552

553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
        # Allow `list` (e.g. `TransfoXLModelOutput.mems` is a list of tensors.)
        elif type(tf_outputs) in [tuple, list]:
            self.assertEqual(type(tf_outputs), type(pt_outputs), f"{name}: Output types differ between TF and PyTorch")
            self.assertEqual(len(tf_outputs), len(pt_outputs), f"{name}: Output lengths differ between TF and PyTorch")

            if attributes is not None:
                # case 1: each output has assigned name (e.g. a tuple form of a `ModelOutput`)
                self.assertEqual(
                    len(attributes),
                    len(tf_outputs),
                    f"{name}: The tuple `names` should have the same length as `tf_outputs`",
                )
            else:
                # case 2: each output has no assigned name (e.g. hidden states of each layer) -> add an index to `names`
                attributes = tuple([f"{name}_{idx}" for idx in range(len(tf_outputs))])
568

569
570
            for tf_output, pt_output, attr in zip(tf_outputs, pt_outputs, attributes):
                self.check_pt_tf_outputs(tf_output, pt_output, model_class, tol=tol, name=attr)
571

572
573
574
575
        elif isinstance(tf_outputs, tf.Tensor):
            self.assertTrue(
                isinstance(pt_outputs, torch.Tensor), f"{name}: `pt_outputs` should a tensor when `tf_outputs` is"
            )
576

577
578
            tf_outputs = tf_outputs.numpy()
            pt_outputs = pt_outputs.detach().to("cpu").numpy()
579

580
581
582
            self.assertEqual(
                tf_outputs.shape, pt_outputs.shape, f"{name}: Output shapes differ between TF and PyTorch"
            )
583

584
585
586
587
588
589
590
            # deal with NumPy's scalars to make replacing nan values by 0 work.
            if np.isscalar(tf_outputs):
                tf_outputs = np.array([tf_outputs])
                pt_outputs = np.array([pt_outputs])

            tf_nans = np.isnan(tf_outputs)
            pt_nans = np.isnan(pt_outputs)
591

592
593
594
595
            pt_outputs[tf_nans] = 0
            tf_outputs[tf_nans] = 0
            pt_outputs[pt_nans] = 0
            tf_outputs[pt_nans] = 0
596

597
598
599
600
            max_diff = np.amax(np.abs(tf_outputs - pt_outputs))
            self.assertLessEqual(max_diff, tol, f"{name}: Difference between torch and tf is {max_diff} (>= {tol}).")
        else:
            raise ValueError(
Sylvain Gugger's avatar
Sylvain Gugger committed
601
602
                "`tf_outputs` should be an instance of `tf.Tensor`, a `tuple`, or an instance of `tf.Tensor`. Got"
                f" {type(tf_outputs)} instead."
603
            )
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651

    def prepare_pt_inputs_from_tf_inputs(self, tf_inputs_dict):
        pt_inputs_dict = {}
        for name, key in tf_inputs_dict.items():
            if type(key) == bool:
                pt_inputs_dict[name] = key
            elif name == "input_values":
                pt_inputs_dict[name] = torch.from_numpy(key.numpy()).to(torch.float32)
            elif name == "pixel_values":
                pt_inputs_dict[name] = torch.from_numpy(key.numpy()).to(torch.float32)
            elif name == "input_features":
                pt_inputs_dict[name] = torch.from_numpy(key.numpy()).to(torch.float32)
            # other general float inputs
            elif tf_inputs_dict[name].dtype.is_floating:
                pt_inputs_dict[name] = torch.from_numpy(key.numpy()).to(torch.float32)
            else:
                pt_inputs_dict[name] = torch.from_numpy(key.numpy()).to(torch.long)

        return pt_inputs_dict

    def check_pt_tf_models(self, tf_model, pt_model, tf_inputs_dict):
        pt_inputs_dict = self.prepare_pt_inputs_from_tf_inputs(tf_inputs_dict)

        # send pytorch inputs to the correct device
        pt_inputs_dict = {
            k: v.to(device=torch_device) if isinstance(v, torch.Tensor) else v for k, v in pt_inputs_dict.items()
        }

        # send pytorch model to the correct device
        pt_model.to(torch_device)

        # Check predictions on first output (logits/hidden-states) are close enough given low-level computational differences
        pt_model.eval()

        with torch.no_grad():
            pt_outputs = pt_model(**pt_inputs_dict)
        tf_outputs = tf_model(tf_inputs_dict)

        # tf models returned loss is usually a tensor rather than a scalar.
        # (see `hf_compute_loss`: it uses `tf.keras.losses.Reduction.NONE`)
        # Change it here to a scalar to match PyTorch models' loss
        tf_loss = getattr(tf_outputs, "loss", None)
        if tf_loss is not None:
            tf_outputs.loss = tf.math.reduce_mean(tf_loss)

        self.check_pt_tf_outputs(tf_outputs, pt_outputs, type(tf_model))

    @is_pt_tf_cross_test
Matt's avatar
Matt committed
652
    def test_pt_tf_model_equivalence(self, allow_missing_keys=False):
653
        import transformers
654
655
656

        for model_class in self.all_model_classes:
            config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
Will Rice's avatar
Will Rice committed
657

658
659
            # Output all for aggressive testing
            config.output_hidden_states = True
660
            config.output_attentions = self.has_attentions
661

662
663
664
665
            # Make sure no sequence has all zeros as attention mask, otherwise some tests fail due to the inconsistency
            # of the usage `1e-4`, `1e-9`, `1e-30`, `-inf`.
            # TODO: Use a uniform value for all models, make sure all tests pass without this processing, and remove it.
            self._make_attention_mask_non_null(inputs_dict)
666
667
668
669
670
671

            pt_model_class_name = model_class.__name__[2:]  # Skip the "TF" at the beginning
            pt_model_class = getattr(transformers, pt_model_class_name)

            tf_model = model_class(config)
            pt_model = pt_model_class(config)
Lysandre's avatar
Lysandre committed
672

673
            tf_inputs_dict = self._prepare_for_class(inputs_dict, model_class)
674
            tf_inputs_dict_with_labels = self._prepare_for_class(
675
676
677
678
679
                inputs_dict,
                model_class,
                # Not all models accept "labels" in the forward pass (yet :) )
                return_labels=True if "labels" in inspect.signature(model_class.call).parameters.keys() else False,
            )
680

681
682
            # For some models (e.g. base models), there is no label returned.
            # Set the input dict to `None` to avoid check outputs twice for the same input dicts.
683
            if not set(tf_inputs_dict_with_labels.keys()).symmetric_difference(tf_inputs_dict.keys()):
684
685
                tf_inputs_dict_with_labels = None

686
            # Check we can load pt model in tf and vice-versa with model => model functions
Matt's avatar
Matt committed
687
688
689
690
691
692
            tf_model = transformers.load_pytorch_model_in_tf2_model(
                tf_model, pt_model, tf_inputs=tf_inputs_dict, allow_missing_keys=allow_missing_keys
            )
            pt_model = transformers.load_tf2_model_in_pytorch_model(
                pt_model, tf_model, allow_missing_keys=allow_missing_keys
            )
Lysandre's avatar
Lysandre committed
693

694
695
696
697
698
            # Original test: check without `labels`
            self.check_pt_tf_models(tf_model, pt_model, tf_inputs_dict)
            # check with `labels`
            if tf_inputs_dict_with_labels:
                self.check_pt_tf_models(tf_model, pt_model, tf_inputs_dict_with_labels)
699
700

            # Check we can load pt model in tf and vice-versa with checkpoint => model functions
701
            with tempfile.TemporaryDirectory() as tmpdirname:
702
703
                pt_checkpoint_path = os.path.join(tmpdirname, "pt_model.bin")
                torch.save(pt_model.state_dict(), pt_checkpoint_path)
Matt's avatar
Matt committed
704
705
706
                tf_model = transformers.load_pytorch_checkpoint_in_tf2_model(
                    tf_model, pt_checkpoint_path, allow_missing_keys=allow_missing_keys
                )
707
708
709

                tf_checkpoint_path = os.path.join(tmpdirname, "tf_model.h5")
                tf_model.save_weights(tf_checkpoint_path)
Matt's avatar
Matt committed
710
711
712
                pt_model = transformers.load_tf2_checkpoint_in_pytorch_model(
                    pt_model, tf_checkpoint_path, allow_missing_keys=allow_missing_keys
                )
713

714
715
716
717
718
            # Original test: check without `labels`
            self.check_pt_tf_models(tf_model, pt_model, tf_inputs_dict)
            # check with `labels`
            if tf_inputs_dict_with_labels:
                self.check_pt_tf_models(tf_model, pt_model, tf_inputs_dict_with_labels)
719
720
721

    def test_compile_tf_model(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
Julien Plu's avatar
Julien Plu committed
722
        max_input = getattr(self.model_tester, "max_position_embeddings", 512)
723
724
725
726
727
        optimizer = tf.keras.optimizers.Adam(learning_rate=3e-5, epsilon=1e-08, clipnorm=1.0)
        loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
        metric = tf.keras.metrics.SparseCategoricalAccuracy("accuracy")

        for model_class in self.all_model_classes:
Joao Gante's avatar
Joao Gante committed
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
            if model_class.__name__ in ["TFSpeech2TextModel", "TFSpeech2TextForConditionalGeneration"]:
                inputs = {
                    "decoder_input_ids": tf.keras.Input(
                        batch_shape=(2, max_input),
                        name="decoder_input_ids",
                        dtype="int32",
                    ),
                    "input_features": tf.keras.Input(
                        batch_shape=(
                            2,
                            max_input,
                            self.model_tester.input_feat_per_channel * self.model_tester.input_channels,
                        ),
                        name="input_features",
                        dtype="float32",
                    ),
                }
amyeroberts's avatar
amyeroberts committed
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
            elif model_class.__name__ in ["TFWhisperModel", "TFWhisperForConditionalGeneration"]:
                inputs = {
                    "decoder_input_ids": tf.keras.Input(
                        batch_shape=(2, max_input),
                        name="decoder_input_ids",
                        dtype="int32",
                    ),
                    "input_features": tf.keras.Input(
                        batch_shape=(
                            2,
                            self.model_tester.num_mel_bins,
                            self.model_tester.seq_length,
                        ),
                        name="input_features",
                        dtype="float32",
                    ),
                }
Joao Gante's avatar
Joao Gante committed
762
            elif self.is_encoder_decoder:
Yih-Dar's avatar
Yih-Dar committed
763
                inputs = {
764
                    "decoder_input_ids": tf.keras.Input(
Julien Plu's avatar
Julien Plu committed
765
766
767
                        batch_shape=(2, max_input),
                        name="decoder_input_ids",
                        dtype="int32",
768
                    ),
Julien Plu's avatar
Julien Plu committed
769
                    "input_ids": tf.keras.Input(batch_shape=(2, max_input), name="input_ids", dtype="int32"),
770
                }
Sayak Paul's avatar
Sayak Paul committed
771
772
            # `pixel_values` implies that the input is an image
            elif model_class.main_input_name == "pixel_values":
Yih-Dar's avatar
Yih-Dar committed
773
774
775
776
777
778
779
780
781
782
                inputs = tf.keras.Input(
                    batch_shape=(
                        3,
                        self.model_tester.num_channels,
                        self.model_tester.image_size,
                        self.model_tester.image_size,
                    ),
                    name="pixel_values",
                    dtype="float32",
                )
Matt's avatar
Matt committed
783
            elif model_class.__name__ in ["TFCLIPModel", "TFGroupViTModel", "TFBlipModel"]:
Yih-Dar's avatar
Yih-Dar committed
784
785
786
787
788
789
790
791
792
793
794
795
796
                inputs = {
                    "input_ids": tf.keras.Input(batch_shape=(3, max_input), name="input_ids", dtype="int32"),
                    "pixel_values": tf.keras.Input(
                        batch_shape=(
                            3,
                            self.model_tester.vision_model_tester.num_channels,
                            self.model_tester.vision_model_tester.image_size,
                            self.model_tester.vision_model_tester.image_size,
                        ),
                        name="pixel_values",
                        dtype="float32",
                    ),
                }
797
            elif model_class in get_values(TF_MODEL_FOR_MULTIPLE_CHOICE_MAPPING):
Yih-Dar's avatar
Yih-Dar committed
798
                inputs = tf.keras.Input(batch_shape=(4, 2, max_input), name="input_ids", dtype="int32")
799
            else:
Yih-Dar's avatar
Yih-Dar committed
800
                inputs = tf.keras.Input(batch_shape=(2, max_input), name="input_ids", dtype="int32")
801

802
803
            # Prepare our model
            model = model_class(config)
804
            model(self._prepare_for_class(inputs_dict, model_class))  # Model must be called before saving.
805
            # Let's load it from the disk to be sure we can use pretrained weights
806
            with tempfile.TemporaryDirectory() as tmpdirname:
Julien Plu's avatar
Julien Plu committed
807
                model.save_pretrained(tmpdirname, saved_model=False)
808
809
                model = model_class.from_pretrained(tmpdirname)

Yih-Dar's avatar
Yih-Dar committed
810
            outputs_dict = model(inputs)
811
812
            hidden_states = outputs_dict[0]

813
            # Add a dense layer on top to test integration with other keras modules
814
815
816
            outputs = tf.keras.layers.Dense(2, activation="softmax", name="outputs")(hidden_states)

            # Compile extended model
Yih-Dar's avatar
Yih-Dar committed
817
            extended_model = tf.keras.Model(inputs=[inputs], outputs=[outputs])
818
819
820
821
822
823
824
            extended_model.compile(optimizer=optimizer, loss=loss, metrics=[metric])

    def test_keyword_and_dict_args(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_model_classes:
            model = model_class(config)
825
826
827
            inputs = self._prepare_for_class(inputs_dict, model_class)

            outputs_dict = model(inputs)
828

829
            inputs_keywords = copy.deepcopy(self._prepare_for_class(inputs_dict, model_class))
Joao Gante's avatar
Joao Gante committed
830
            outputs_keywords = model(**inputs_keywords)
831
832
833
834
835
836
            output_dict = outputs_dict[0].numpy()
            output_keywords = outputs_keywords[0].numpy()

            self.assertLess(np.sum(np.abs(output_dict - output_keywords)), 1e-6)

    def test_attention_outputs(self):
837
838
839
        if not self.has_attentions:
            self.skipTest(reason="Model does not output attentions")

840
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
841
        config.return_dict = True
842
843
844
845
        decoder_seq_length = getattr(self.model_tester, "decoder_seq_length", self.model_tester.seq_length)
        encoder_seq_length = getattr(self.model_tester, "encoder_seq_length", self.model_tester.seq_length)
        decoder_key_length = getattr(self.model_tester, "key_length", decoder_seq_length)
        encoder_key_length = getattr(self.model_tester, "key_length", encoder_seq_length)
846

Julien Plu's avatar
Julien Plu committed
847
848
        def check_decoder_attentions_output(outputs):
            out_len = len(outputs)
849
            self.assertEqual(min(out_len % 2, out_len % 5), 0)  # differentiation due to newly added cross_attentions
Julien Plu's avatar
Julien Plu committed
850
851
852
853
854
855
856
857
            decoder_attentions = outputs.decoder_attentions
            self.assertEqual(len(decoder_attentions), self.model_tester.num_hidden_layers)
            self.assertListEqual(
                list(decoder_attentions[0].shape[-3:]),
                [self.model_tester.num_attention_heads, decoder_seq_length, decoder_key_length],
            )

        def check_encoder_attentions_output(outputs):
858
859
860
            attentions = [
                t.numpy() for t in (outputs.encoder_attentions if config.is_encoder_decoder else outputs.attentions)
            ]
861
862
863
864
            self.assertEqual(len(attentions), self.model_tester.num_hidden_layers)
            self.assertListEqual(
                list(attentions[0].shape[-3:]),
                [self.model_tester.num_attention_heads, encoder_seq_length, encoder_key_length],
865
            )
Julien Plu's avatar
Julien Plu committed
866
867
868
869
870
871

        for model_class in self.all_model_classes:
            inputs_dict["output_attentions"] = True
            config.output_hidden_states = False
            model = model_class(config)
            outputs = model(self._prepare_for_class(inputs_dict, model_class))
872
            out_len = len(outputs)
Julien Plu's avatar
Julien Plu committed
873
874
            self.assertEqual(config.output_hidden_states, False)
            check_encoder_attentions_output(outputs)
thomwolf's avatar
thomwolf committed
875

876
            if self.is_encoder_decoder:
Julien Plu's avatar
Julien Plu committed
877
878
879
880
                model = model_class(config)
                outputs = model(self._prepare_for_class(inputs_dict, model_class))
                self.assertEqual(config.output_hidden_states, False)
                check_decoder_attentions_output(outputs)
thomwolf's avatar
thomwolf committed
881

882
883
            # Check that output attentions can also be changed via the config
            del inputs_dict["output_attentions"]
884
            config.output_attentions = True
885
            model = model_class(config)
886
            outputs = model(self._prepare_for_class(inputs_dict, model_class))
Julien Plu's avatar
Julien Plu committed
887
888
            self.assertEqual(config.output_hidden_states, False)
            check_encoder_attentions_output(outputs)
889
890
891

            # Check attention is always last and order is fine
            inputs_dict["output_attentions"] = True
892
893
            config.output_hidden_states = True
            model = model_class(config)
894
            outputs = model(self._prepare_for_class(inputs_dict, model_class))
Julien Plu's avatar
Julien Plu committed
895

896
897
            self.assertEqual(out_len + (2 if self.is_encoder_decoder else 1), len(outputs))
            self.assertEqual(model.config.output_hidden_states, True)
Julien Plu's avatar
Julien Plu committed
898
            check_encoder_attentions_output(outputs)
899

900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
    def test_headmasking(self):
        if not self.test_head_masking:
            return

        random.Random().seed(42)
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        random.Random().seed()

        inputs_dict["output_attentions"] = True
        config.output_hidden_states = True
        configs_no_init = _config_zero_init(config)  # To be sure we have no Nan
        for model_class in self.all_model_classes:
            model = model_class(config=configs_no_init)

            # Prepare head_mask
            def prepare_layer_head_mask(i, attention_heads, num_hidden_layers):
                if i == 0:
                    return tf.concat(
                        (tf.zeros(1, dtype=tf.float32), tf.ones(attention_heads - 1, dtype=tf.float32)), 0
                    )
                elif i == num_hidden_layers - 1:
                    return tf.concat(
                        (tf.zeros(attention_heads - 1, dtype=tf.float32), tf.ones(1, dtype=tf.float32)), 0
                    )
                else:
                    return tf.ones(attention_heads, dtype=tf.float32)

            head_mask = tf.stack(
                [
                    prepare_layer_head_mask(i, config.num_attention_heads, config.num_hidden_layers)
                    for i in range(config.num_hidden_layers)
                ],
                0,
            )

            inputs = self._prepare_for_class(inputs_dict, model_class).copy()
            inputs["head_mask"] = head_mask
            if model.config.is_encoder_decoder:
                signature = inspect.signature(model.call)
                arg_names = [*signature.parameters.keys()]
                if "decoder_head_mask" in arg_names:  # necessary diferentiation because of T5 model
                    inputs["decoder_head_mask"] = head_mask
942
943
                if "cross_attn_head_mask" in arg_names:
                    inputs["cross_attn_head_mask"] = head_mask
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967

            outputs = model(**inputs, return_dict=True)

            def check_attentions_validity(attentions):
                # Remove Nan
                for t in attentions:
                    self.assertLess(
                        (tf.math.reduce_sum(tf.cast(tf.math.is_nan(t), tf.float32))).numpy(), (tf.size(t) / 4).numpy()
                    )  # Check we don't have more than 25% nans (arbitrary)

                attentions = [
                    tf.where(tf.math.is_nan(t), 0.0, t) for t in attentions
                ]  # remove them (the test is less complete)

                self.assertAlmostEqual(tf.math.reduce_sum(attentions[0][..., 0, :, :]).numpy(), 0.0)
                self.assertNotEqual(tf.math.reduce_sum(attentions[0][..., -1, :, :]).numpy(), 0.0)
                if len(attentions) > 2:  # encoder-decodere models have only 2 layers in each modules
                    self.assertNotEqual(tf.math.reduce_sum(attentions[1][..., 0, :, :]).numpy(), 0.0)
                self.assertAlmostEqual(tf.math.reduce_sum(attentions[-1][..., -2, :, :]).numpy(), 0.0)
                self.assertNotEqual(tf.math.reduce_sum(attentions[-1][..., -1, :, :]).numpy(), 0.0)

            if model.config.is_encoder_decoder:
                check_attentions_validity(outputs.encoder_attentions)
                check_attentions_validity(outputs.decoder_attentions)
968
969
                if "cross_attn_head_mask" in arg_names:
                    check_attentions_validity(outputs.cross_attentions)
970
971
972
            else:
                check_attentions_validity(outputs.attentions)

973
974
975
    def test_hidden_states_output(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

Joseph Liu's avatar
Joseph Liu committed
976
        def check_hidden_states_output(config, inputs_dict, model_class):
977
            model = model_class(config)
978
            outputs = model(self._prepare_for_class(inputs_dict, model_class))
979
980
981
            expected_num_layers = getattr(
                self.model_tester, "expected_num_hidden_layers", self.model_tester.num_hidden_layers + 1
            )
Julien Plu's avatar
Julien Plu committed
982

Julien Plu's avatar
Julien Plu committed
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
            if model.config.is_encoder_decoder:
                encoder_hidden_states = outputs.encoder_hidden_states
                decoder_hidden_states = outputs.decoder_hidden_states

                self.assertEqual(config.output_attentions, False)
                self.assertEqual(len(encoder_hidden_states), expected_num_layers)
                self.assertListEqual(
                    list(encoder_hidden_states[0].shape[-2:]),
                    [self.model_tester.seq_length, self.model_tester.hidden_size],
                )
                self.assertEqual(len(decoder_hidden_states), expected_num_layers)
                self.assertListEqual(
                    list(decoder_hidden_states[0].shape[-2:]),
                    [self.model_tester.seq_length, self.model_tester.hidden_size],
                )
            else:
                hidden_states = outputs.hidden_states
                self.assertEqual(config.output_attentions, False)
                self.assertEqual(len(hidden_states), expected_num_layers)
                self.assertListEqual(
                    list(hidden_states[0].shape[-2:]),
                    [self.model_tester.seq_length, self.model_tester.hidden_size],
                )
1006

Joseph Liu's avatar
Joseph Liu committed
1007
1008
1009
1010
1011
1012
1013
1014
        for model_class in self.all_model_classes:
            inputs_dict["output_hidden_states"] = True
            check_hidden_states_output(config, inputs_dict, model_class)

            del inputs_dict["output_hidden_states"]
            config.output_hidden_states = True
            check_hidden_states_output(config, inputs_dict, model_class)

1015
1016
    def test_model_common_attributes(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
Joao Gante's avatar
Joao Gante committed
1017
        text_in_text_out_models = (
1018
1019
1020
            get_values(TF_MODEL_FOR_CAUSAL_LM_MAPPING)
            + get_values(TF_MODEL_FOR_MASKED_LM_MAPPING)
            + get_values(TF_MODEL_FOR_SEQ_TO_SEQ_CAUSAL_LM_MAPPING)
1021
        )
Joao Gante's avatar
Joao Gante committed
1022
        speech_in_text_out_models = get_values(TF_MODEL_FOR_SPEECH_SEQ_2_SEQ_MAPPING)
1023
1024
1025

        for model_class in self.all_model_classes:
            model = model_class(config)
1026
            assert isinstance(model.get_input_embeddings(), tf.keras.layers.Layer)
Joao Gante's avatar
Joao Gante committed
1027
            if model_class in text_in_text_out_models:
1028
                x = model.get_output_embeddings()
1029
                assert isinstance(x, tf.keras.layers.Layer)
1030
1031
1032
1033
                name = model.get_bias()
                assert isinstance(name, dict)
                for k, v in name.items():
                    assert isinstance(v, tf.Variable)
Joao Gante's avatar
Joao Gante committed
1034
1035
1036
1037
1038
            elif model_class in speech_in_text_out_models:
                x = model.get_output_embeddings()
                assert isinstance(x, tf.keras.layers.Layer)
                name = model.get_bias()
                assert name is None
1039
            else:
1040
                x = model.get_output_embeddings()
1041
                assert x is None
1042
1043
                name = model.get_bias()
                assert name is None
1044
1045
1046
1047
1048
1049

    def test_determinism(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_model_classes:
            model = model_class(config)
1050
            first, second = (
1051
1052
                model(self._prepare_for_class(inputs_dict, model_class), training=False)[0],
                model(self._prepare_for_class(inputs_dict, model_class), training=False)[0],
1053
            )
1054
1055
1056
1057
1058
1059
1060
            out_1 = first.numpy()
            out_2 = second.numpy()
            out_1 = out_1[~np.isnan(out_1)]
            out_2 = out_2[~np.isnan(out_2)]
            max_diff = np.amax(np.abs(out_1 - out_2))
            self.assertLessEqual(max_diff, 1e-5)

1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
    def test_model_outputs_equivalence(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        def check_equivalence(model, tuple_inputs, dict_inputs, additional_kwargs={}):
            tuple_output = model(tuple_inputs, return_dict=False, **additional_kwargs)
            dict_output = model(dict_inputs, return_dict=True, **additional_kwargs).to_tuple()

            def recursive_check(tuple_object, dict_object):
                if isinstance(tuple_object, (List, Tuple)):
                    for tuple_iterable_value, dict_iterable_value in zip(tuple_object, dict_object):
                        recursive_check(tuple_iterable_value, dict_iterable_value)
                elif tuple_object is None:
                    return
                else:
                    self.assertTrue(
                        all(tf.equal(tuple_object, dict_object)),
Sylvain Gugger's avatar
Sylvain Gugger committed
1077
1078
1079
1080
                        msg=(
                            "Tuple and dict output are not equal. Difference:"
                            f" {tf.math.reduce_max(tf.abs(tuple_object - dict_object))}"
                        ),
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
                    )

                recursive_check(tuple_output, dict_output)

        for model_class in self.all_model_classes:
            model = model_class(config)

            tuple_inputs = self._prepare_for_class(inputs_dict, model_class)
            dict_inputs = self._prepare_for_class(inputs_dict, model_class)
            check_equivalence(model, tuple_inputs, dict_inputs)

            tuple_inputs = self._prepare_for_class(inputs_dict, model_class)
            dict_inputs = self._prepare_for_class(inputs_dict, model_class)
            check_equivalence(model, tuple_inputs, dict_inputs, {"output_hidden_states": True})

1096
1097
1098
1099
            if self.has_attentions:
                tuple_inputs = self._prepare_for_class(inputs_dict, model_class)
                dict_inputs = self._prepare_for_class(inputs_dict, model_class)
                check_equivalence(model, tuple_inputs, dict_inputs, {"output_attentions": True})
1100

1101
1102
1103
1104
1105
            # Not all models accept "labels" in the forward pass (yet :) )
            if "labels" in inspect.signature(model.call).parameters.keys():
                tuple_inputs = self._prepare_for_class(inputs_dict, model_class, return_labels=True)
                dict_inputs = self._prepare_for_class(inputs_dict, model_class, return_labels=True)
                check_equivalence(model, tuple_inputs, dict_inputs)
1106

1107
1108
1109
                tuple_inputs = self._prepare_for_class(inputs_dict, model_class, return_labels=True)
                dict_inputs = self._prepare_for_class(inputs_dict, model_class, return_labels=True)
                check_equivalence(model, tuple_inputs, dict_inputs, {"output_hidden_states": True})
1110

1111
1112
1113
1114
                if self.has_attentions:
                    tuple_inputs = self._prepare_for_class(inputs_dict, model_class, return_labels=True)
                    dict_inputs = self._prepare_for_class(inputs_dict, model_class, return_labels=True)
                    check_equivalence(model, tuple_inputs, dict_inputs, {"output_attentions": True})
1115

1116
1117
1118
1119
1120
                    tuple_inputs = self._prepare_for_class(inputs_dict, model_class, return_labels=True)
                    dict_inputs = self._prepare_for_class(inputs_dict, model_class, return_labels=True)
                    check_equivalence(
                        model, tuple_inputs, dict_inputs, {"output_hidden_states": True, "output_attentions": True}
                    )
1121

1122
1123
1124
1125
1126
1127
    def test_inputs_embeds(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_model_classes:
            model = model_class(config)

1128
1129
            inputs = copy.deepcopy(inputs_dict)

1130
1131
1132
1133
            if not self.is_encoder_decoder:
                input_ids = inputs["input_ids"]
                del inputs["input_ids"]
            else:
1134
                encoder_input_ids = inputs["input_ids"]
1135
                decoder_input_ids = inputs.get("decoder_input_ids", encoder_input_ids)
1136
                del inputs["input_ids"]
1137
1138
                inputs.pop("decoder_input_ids", None)

thomwolf's avatar
thomwolf committed
1139
            if not self.is_encoder_decoder:
1140
                inputs["inputs_embeds"] = model.get_input_embeddings()(input_ids)
thomwolf's avatar
thomwolf committed
1141
            else:
1142
1143
                inputs["inputs_embeds"] = model.get_input_embeddings()(encoder_input_ids)
                inputs["decoder_inputs_embeds"] = model.get_input_embeddings()(decoder_input_ids)
1144

1145
1146
            inputs = self._prepare_for_class(inputs, model_class)

1147
            model(inputs)
1148

1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
    def test_numpy_arrays_inputs(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        def prepare_numpy_arrays(inputs_dict):
            inputs_np_dict = {}
            for k, v in inputs_dict.items():
                if tf.is_tensor(v):
                    inputs_np_dict[k] = v.numpy()
                else:
                    inputs_np_dict[k] = np.array(k)

            return inputs_np_dict

        for model_class in self.all_model_classes:
            model = model_class(config)

            inputs = self._prepare_for_class(inputs_dict, model_class)
            inputs_np = prepare_numpy_arrays(inputs)

1168
1169
1170
            output_for_dict_input = model(inputs_np)
            output_for_kw_input = model(**inputs_np)
            self.assert_outputs_same(output_for_dict_input, output_for_kw_input)
1171

1172
    def test_resize_token_embeddings(self):
1173
1174
1175
        # TODO (joao): after the embeddings refactor is complete, rework this test so as to rely exclusively on
        # tf.keras.layers.Embedding

1176
1177
1178
        if not self.test_resize_embeddings:
            return
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
1179
1180

        def _get_word_embedding_weight(model, embedding_layer):
1181
1182
1183
1184
1185
1186
            if isinstance(embedding_layer, tf.keras.layers.Embedding):
                # builds the embeddings layer
                model(model.dummy_inputs)
                return embedding_layer.embeddings
            else:
                return model._get_word_embedding_weight(embedding_layer)
1187

1188
1189
1190
        for model_class in self.all_model_classes:
            for size in [config.vocab_size - 10, config.vocab_size + 10, None]:
                # build the embeddings
1191
                model = model_class(config=copy.deepcopy(config))  # `resize_token_embeddings` mutates `config`
1192
1193
1194
                old_input_embeddings = _get_word_embedding_weight(model, model.get_input_embeddings())
                old_bias = model.get_bias()
                old_output_embeddings = _get_word_embedding_weight(model, model.get_output_embeddings())
1195
                # reshape the embeddings
1196
1197
1198
1199
1200
1201
                model.resize_token_embeddings(size)
                new_input_embeddings = _get_word_embedding_weight(model, model.get_input_embeddings())
                new_bias = model.get_bias()
                new_output_embeddings = _get_word_embedding_weight(model, model.get_output_embeddings())

                # check that the resized embeddings size matches the desired size.
1202
                assert_size = size if size is not None else config.vocab_size
1203
1204
                self.assertEqual(new_input_embeddings.shape[0], assert_size)

1205
1206
                # check that weights remain the same after resizing
                models_equal = True
1207
1208
                for p1, p2 in zip(old_input_embeddings.value(), new_input_embeddings.value()):
                    if tf.math.reduce_sum(tf.math.abs(p1 - p2)) > 0:
1209
1210
1211
                        models_equal = False
                self.assertTrue(models_equal)

1212
1213
                if old_bias is not None and new_bias is not None:
                    for old_weight, new_weight in zip(old_bias.values(), new_bias.values()):
1214
                        self.assertEqual(new_weight.shape[-1], assert_size)
1215
1216

                        models_equal = True
1217
                        for p1, p2 in zip(tf.squeeze(old_weight), tf.squeeze(new_weight)):
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
                            if tf.math.reduce_sum(tf.math.abs(p1 - p2)) > 0:
                                models_equal = False
                        self.assertTrue(models_equal)

                if old_output_embeddings is not None and new_output_embeddings is not None:
                    self.assertEqual(new_output_embeddings.shape[0], assert_size)
                    self.assertEqual(new_output_embeddings.shape[1], old_output_embeddings.shape[1])

                    models_equal = True
                    for p1, p2 in zip(old_output_embeddings.value(), new_output_embeddings.value()):
                        if tf.math.reduce_sum(tf.math.abs(p1 - p2)) > 0:
                            models_equal = False
                    self.assertTrue(models_equal)

1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
    # TODO (Joao): this test is not slow, but it's tagged as such to keep track of failures on the scheduled CI runs,
    # while passing push CI. Fix the underlying issues and remove the tag.
    @slow
    def test_save_load_after_resize_token_embeddings(self):
        if not self.test_resize_embeddings:
            return
        config, original_inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_model_classes:
            # create a model with resized (expended) embeddings
            new_tokens_size = 10
            old_total_size = config.vocab_size
            new_total_size = old_total_size + new_tokens_size
            model = model_class(config=copy.deepcopy(config))  # `resize_token_embeddings` mutates `config`
            model(model.dummy_inputs)  # builds the embeddings layer
            model.resize_token_embeddings(new_total_size)

            # fetch the output for an input exclusively made of new members of the vocabulary
            inputs_dict = copy.deepcopy(original_inputs_dict)
amyeroberts's avatar
amyeroberts committed
1251
1252
1253
1254
1255
1256
1257
1258
1259
            ids_feat_name = None
            if "input_ids" in inputs_dict:
                ids_feat_name = "input_ids"
            elif "decoder_input_ids" in inputs_dict:
                ids_feat_name = "decoder_input_ids"
            else:
                assert False, "No input ids feature found in the inputs dict"

            new_vocab_input_ids = ids_tensor(inputs_dict[ids_feat_name].shape, new_tokens_size)
1260
            new_vocab_input_ids += old_total_size
amyeroberts's avatar
amyeroberts committed
1261
            inputs_dict[ids_feat_name] = new_vocab_input_ids
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
            if "input_ids" in inputs_dict:
                inputs_dict["input_ids"] = new_vocab_input_ids
            if "decoder_input_ids" in inputs_dict:
                inputs_dict["decoder_input_ids"] = new_vocab_input_ids
            prepared_inputs = self._prepare_for_class(inputs_dict, model_class)
            outputs = model(**prepared_inputs)

            # save and load the model
            with tempfile.TemporaryDirectory() as tmpdirname:
                model.save_pretrained(tmpdirname, saved_model=False)
                model = model_class.from_pretrained(tmpdirname)
                restored_model_outputs = model(**prepared_inputs)

                # check that the output for the restored model is the same
                self.assert_outputs_same(restored_model_outputs, outputs)

    @unittest.skipIf(
        not is_tf_available() or len(tf.config.list_physical_devices("GPU")) == 0,
        reason="This test always passes on CPU.",
    )
    def test_embeddings_out_of_bounds_raise_exception(self):
        # TF embeddings layers don't raise an exception when an index is out of bounds on GPU, so we manually raise it.
        # This test should only fail on GPU for models where we haven't added the safety check.
        if not self.test_resize_embeddings:
            return
        config, original_inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_model_classes:
            model = model_class(config=config)
            inputs_dict = copy.deepcopy(original_inputs_dict)
            if "input_ids" in inputs_dict:
                inputs_dict["input_ids"] = inputs_dict["input_ids"] * int(1e9)
            if "decoder_input_ids" in inputs_dict:
                inputs_dict["decoder_input_ids"] = inputs_dict["decoder_input_ids"] * int(1e9)
            prepared_inputs = self._prepare_for_class(inputs_dict, model_class)
            with self.assertRaises(tf.errors.InvalidArgumentError):
                model(**prepared_inputs)

1300
    def test_lm_head_model_random_no_beam_search_generate(self):
1301
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
Will Rice's avatar
Will Rice committed
1302
        input_ids = inputs_dict.get("input_ids", None)
1303

1304
        # iterate over all generative models
1305
1306
1307
1308
        for model_class in self.all_generative_model_classes:
            model = model_class(config)

            if config.bos_token_id is None:
Joao Gante's avatar
Joao Gante committed
1309
                # if bos token id is not defined model needs input_ids
1310
                with self.assertRaises(ValueError):
1311
                    model.generate(do_sample=True, max_length=5)
1312
                # num_return_sequences = 1
1313
                self._check_generated_ids(model.generate(input_ids, do_sample=True))
Joao Gante's avatar
Joao Gante committed
1314
1315
            elif model_class.__name__ not in ["TFSpeech2TextForConditionalGeneration"]:
                # Models with non-text inputs won't work here; num_return_sequences = 1
1316
                self._check_generated_ids(model.generate(do_sample=True, max_length=5))
1317

1318
            with self.assertRaises(ValueError):
1319
                # generating multiple sequences when no beam search generation
1320
1321
1322
                # is not allowed as it would always generate the same sequences
                model.generate(input_ids, do_sample=False, num_return_sequences=2)

1323
1324
            # num_return_sequences > 1, sample
            self._check_generated_ids(model.generate(input_ids, do_sample=True, num_return_sequences=2))
1325
1326

            # check bad words tokens language generation
1327
1328
            # create list of 1-seq bad token and list of 2-seq of bad tokens
            bad_words_ids = [self._generate_random_bad_tokens(1, model), self._generate_random_bad_tokens(2, model)]
1329
            output_tokens = model.generate(
1330
                input_ids, do_sample=True, bad_words_ids=bad_words_ids, num_return_sequences=2
1331
            )
1332
            # only count generated tokens
1333
1334
            generated_ids = output_tokens[:, input_ids.shape[-1] :]
            self.assertFalse(self._check_match_tokens(generated_ids.numpy().tolist(), bad_words_ids))
1335

1336
1337
1338
    def test_lm_head_model_no_beam_search_generate_dict_outputs(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        input_ids = inputs_dict.get("input_ids", None)
Joao Gante's avatar
Joao Gante committed
1339
1340
        if input_ids is None:
            input_ids = inputs_dict.get("input_features", None)
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368

        # iterate over all generative models
        for model_class in self.all_generative_model_classes:
            model = model_class(config)
            output_greedy = model.generate(
                input_ids,
                do_sample=False,
                output_scores=True,
                output_hidden_states=True,
                output_attentions=True,
                return_dict_in_generate=True,
            )
            output_sample = model.generate(
                input_ids,
                do_sample=True,
                output_scores=True,
                output_hidden_states=True,
                output_attentions=True,
                return_dict_in_generate=True,
            )

            if model.config.is_encoder_decoder:
                self.assertIsInstance(output_greedy, TFGreedySearchEncoderDecoderOutput)
                self.assertIsInstance(output_sample, TFSampleEncoderDecoderOutput)
            else:
                self.assertIsInstance(output_greedy, TFGreedySearchDecoderOnlyOutput)
                self.assertIsInstance(output_sample, TFSampleDecoderOnlyOutput)

1369
1370
    def test_lm_head_model_random_beam_search_generate(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
Will Rice's avatar
Will Rice committed
1371
        input_ids = inputs_dict.get("input_ids", None)
1372
1373
1374
1375
1376

        for model_class in self.all_generative_model_classes:
            model = model_class(config)

            if config.bos_token_id is None:
Joao Gante's avatar
Joao Gante committed
1377
                # if bos token id is not defined model needs input_ids, num_return_sequences = 1
1378
1379
1380
1381
1382
                self._check_generated_ids(model.generate(input_ids, do_sample=True, num_beams=2))
            else:
                # num_return_sequences = 1
                self._check_generated_ids(model.generate(do_sample=True, max_length=5, num_beams=2))

1383
            with self.assertRaises(ValueError):
1384
1385
1386
1387
                # generating more sequences than having beams leads is not possible
                model.generate(input_ids, do_sample=False, num_return_sequences=3, num_beams=2)

            # num_return_sequences > 1, sample
Lysandre's avatar
Lysandre committed
1388
1389
1390
1391
1392
1393
1394
1395
            self._check_generated_ids(
                model.generate(
                    input_ids,
                    do_sample=True,
                    num_beams=2,
                    num_return_sequences=2,
                )
            )
1396
1397
1398
1399
1400
1401
            # num_return_sequences > 1, greedy
            self._check_generated_ids(model.generate(input_ids, do_sample=False, num_beams=2, num_return_sequences=2))

            # check bad words tokens language generation
            # create list of 1-seq bad token and list of 2-seq of bad tokens
            bad_words_ids = [self._generate_random_bad_tokens(1, model), self._generate_random_bad_tokens(2, model)]
1402
            output_tokens = model.generate(
1403
                input_ids, do_sample=False, bad_words_ids=bad_words_ids, num_beams=2, num_return_sequences=2
1404
            )
1405
            # only count generated tokens
1406
1407
1408
            generated_ids = output_tokens[:, input_ids.shape[-1] :]
            self.assertFalse(self._check_match_tokens(generated_ids.numpy().tolist(), bad_words_ids))

1409
1410
1411
    def test_lm_head_model_beam_search_generate_dict_outputs(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        input_ids = inputs_dict.get("input_ids", None)
Joao Gante's avatar
Joao Gante committed
1412
1413
        if input_ids is None:
            input_ids = inputs_dict.get("input_features", None)
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443

        # iterate over all generative models
        for model_class in self.all_generative_model_classes:
            model = model_class(config)
            output_beam_search = model.generate(
                input_ids,
                num_beams=2,
                do_sample=False,
                output_scores=True,
                output_hidden_states=True,
                output_attentions=True,
                return_dict_in_generate=True,
            )
            output_beam_sample = model.generate(
                input_ids,
                num_beams=2,
                do_sample=True,
                output_scores=True,
                output_hidden_states=True,
                output_attentions=True,
                return_dict_in_generate=True,
            )

            if model.config.is_encoder_decoder:
                self.assertIsInstance(output_beam_search, TFBeamSearchEncoderDecoderOutput)
                self.assertIsInstance(output_beam_sample, TFBeamSampleEncoderDecoderOutput)
            else:
                self.assertIsInstance(output_beam_search, TFBeamSearchDecoderOnlyOutput)
                self.assertIsInstance(output_beam_sample, TFBeamSampleDecoderOnlyOutput)

1444
1445
1446
1447
    def test_loss_computation(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        for model_class in self.all_model_classes:
            model = model_class(config)
1448
1449
            # The number of elements in the loss should be the same as the number of elements in the label
            prepared_for_class = self._prepare_for_class(inputs_dict.copy(), model_class, return_labels=True)
1450
            added_label_names = sorted(prepared_for_class.keys() - inputs_dict.keys(), reverse=True)
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
            if not added_label_names:
                continue  # This test is only for models with easily-separable labels
            added_label = prepared_for_class[added_label_names[0]]
            expected_loss_size = added_label.shape.as_list()[:1]

            # Test that model correctly compute the loss with kwargs
            prepared_for_class = self._prepare_for_class(inputs_dict.copy(), model_class, return_labels=True)
            possible_input_names = {"input_ids", "pixel_values", "input_features", "input_values"}
            input_name = possible_input_names.intersection(set(prepared_for_class)).pop()
            model_input = prepared_for_class.pop(input_name)

Matt's avatar
Matt committed
1462
1463
1464
1465
1466
            outputs = model(model_input, **prepared_for_class)
            if not isinstance(outputs, ModelOutput) or not hasattr(outputs, "loss"):
                continue

            loss = outputs.loss
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
            self.assertTrue(loss.shape.as_list() == expected_loss_size or loss.shape.as_list() == [1])

            # Test that model correctly compute the loss when we mask some positions
            prepared_for_class = self._prepare_for_class(inputs_dict.copy(), model_class, return_labels=True)
            possible_input_names = {"input_ids", "pixel_values", "input_features", "input_values"}
            input_name = possible_input_names.intersection(set(prepared_for_class)).pop()
            model_input = prepared_for_class.pop(input_name)
            if "labels" in prepared_for_class:
                labels = prepared_for_class["labels"].numpy()
                if len(labels.shape) > 1 and labels.shape[1] != 1:
                    labels[0] = -100
                    prepared_for_class["labels"] = tf.convert_to_tensor(labels)
                    loss = model(model_input, **prepared_for_class)[0]
                    self.assertTrue(loss.shape.as_list() == expected_loss_size or loss.shape.as_list() == [1])
                    self.assertTrue(not np.any(np.isnan(loss.numpy())))

            # Test that model correctly compute the loss with a dict
            prepared_for_class = self._prepare_for_class(inputs_dict.copy(), model_class, return_labels=True)
            loss = model(prepared_for_class)[0]
            self.assertTrue(loss.shape.as_list() == expected_loss_size or loss.shape.as_list() == [1])

            # Test that model correctly compute the loss with a tuple
            prepared_for_class = self._prepare_for_class(inputs_dict.copy(), model_class, return_labels=True)

            # Get keys that were added with the _prepare_for_class function
            label_keys = prepared_for_class.keys() - inputs_dict.keys()
            signature = inspect.signature(model.call).parameters
            signature_names = list(signature.keys())

            # Create a dictionary holding the location of the tensors in the tuple
            tuple_index_mapping = {0: input_name}
            for label_key in label_keys:
                label_key_index = signature_names.index(label_key)
                tuple_index_mapping[label_key_index] = label_key
            sorted_tuple_index_mapping = sorted(tuple_index_mapping.items())
            # Initialize a list with their default values, update the values and convert to a tuple
            list_input = []

            for name in signature_names:
                if name != "kwargs":
                    list_input.append(signature[name].default)

            for index, value in sorted_tuple_index_mapping:
                list_input[index] = prepared_for_class[value]

            tuple_input = tuple(list_input)

            # Send to model
            loss = model(tuple_input[:-1])[0]

            self.assertTrue(loss.shape.as_list() == expected_loss_size or loss.shape.as_list() == [1])
1518

1519
1520
1521
    def check_keras_fit_results(self, val_loss1, val_loss2, atol=1e-2, rtol=1e-3):
        self.assertTrue(np.allclose(val_loss1, val_loss2, atol=atol, rtol=rtol))

1522
1523
1524
1525
    def test_keras_fit(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        for model_class in self.all_model_classes:
            model = model_class(config)
1526
1527
1528
1529
1530
1531
            # Test that model correctly compute the loss with kwargs
            prepared_for_class = self._prepare_for_class(inputs_dict.copy(), model_class, return_labels=True)
            # We also remove "return_loss" as this is covered by the train_step when using fit()
            prepared_for_class = {
                key: val
                for key, val in prepared_for_class.items()
Matt's avatar
Matt committed
1532
                if key not in ("head_mask", "decoder_head_mask", "cross_attn_head_mask", "return_loss")
1533
            }
Matt's avatar
Matt committed
1534
1535
            if "labels" in prepared_for_class and "decoder_input_ids" in prepared_for_class:
                del prepared_for_class["decoder_input_ids"]
1536

1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
            accuracy_classes = [
                "ForPreTraining",
                "ForCausalLM",
                "ForMaskedLM",
                "ForQuestionAnswering",
                "ForMultipleChoice",
                "ForSequenceClassification",
                "ForTokenClassification",
                "ForNextSentencePrediction",
                "LMHeadModel",
            ]
            for accuracy_class in accuracy_classes:
                if model.__class__.__name__.endswith(accuracy_class):
                    metrics = [tf.keras.metrics.SparseCategoricalAccuracy()]
                    break
            else:
                metrics = []

1555
1556
1557
1558
            if hasattr(self.model_tester, "batch_size"):
                sample_weight = tf.convert_to_tensor([0.5] * self.model_tester.batch_size, dtype=tf.float32)
            else:
                sample_weight = None
Matt's avatar
Matt committed
1559
1560
1561
1562
            # Build the model so we can get some constant weights and check outputs
            outputs = model(prepared_for_class)
            if getattr(outputs, "loss", None) is None:
                continue
1563
1564
1565
1566
1567
1568
1569
1570
            model_weights = model.get_weights()

            # Run eagerly to save some expensive compilation times
            model.compile(optimizer=tf.keras.optimizers.SGD(0.0), run_eagerly=True, metrics=metrics)
            # Make sure the model fits without crashing regardless of where we pass the labels
            history1 = model.fit(
                prepared_for_class,
                validation_data=prepared_for_class,
1571
                sample_weight=sample_weight,
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
                steps_per_epoch=1,
                validation_steps=1,
                shuffle=False,
            )
            val_loss1 = history1.history["val_loss"][0]
            self.assertTrue(not isnan(val_loss1))
            accuracy1 = {key: val[0] for key, val in history1.history.items() if key.endswith("accuracy")}

            possible_label_cols = {
                "labels",
                "label",
                "label_ids",
                "start_positions",
                "start_position",
                "end_positions",
                "end_position",
                "next_sentence_label",
            }
            label_names = possible_label_cols.intersection(set(prepared_for_class))
            if len(label_names) == 0:
                # The next tests only make sense for models with separate inputs and labels, and do not make
                # sense for models that don't clearly distinguish between the two (e.g. CLIP)
                return
            labels = {key: val for key, val in prepared_for_class.items() if key in label_names}
            inputs_minus_labels = {key: val for key, val in prepared_for_class.items() if key not in label_names}
            self.assertGreater(len(inputs_minus_labels), 0)

            # We reinitialize the model here even though our learning rate was zero
            # because BatchNorm updates weights by means other than gradient descent.
            model.set_weights(model_weights)

            history2 = model.fit(
                inputs_minus_labels,
                labels,
                validation_data=(inputs_minus_labels, labels),
1607
                sample_weight=sample_weight,
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
                steps_per_epoch=1,
                validation_steps=1,
                shuffle=False,
            )
            val_loss2 = history2.history["val_loss"][0]
            self.assertTrue(not isnan(val_loss2))
            accuracy2 = {key: val[0] for key, val in history2.history.items() if key.endswith("accuracy")}
            self.check_keras_fit_results(val_loss1, val_loss2)
            self.assertEqual(history1.history.keys(), history2.history.keys())
            for key in history1.history.keys():
                if not key.startswith("val_"):
                    self.assertTrue("val_" + key in history1.history.keys(), "Outputs differ in train/test step!")
            if metrics:
                self.assertTrue(len(accuracy1) == len(accuracy2) > 0, "Missing metrics!")

            # Make sure fit works with tf.data.Dataset and results are consistent
            dataset = tf.data.Dataset.from_tensor_slices(prepared_for_class)
1625
1626
1627
1628
1629
1630

            if sample_weight is not None:
                # Add in the sample weight
                weighted_dataset = dataset.map(lambda x: (x, None, tf.convert_to_tensor(0.5, dtype=tf.float32)))
            else:
                weighted_dataset = dataset
1631
            # Pass in all samples as a batch to match other `fit` calls
1632
            weighted_dataset = weighted_dataset.batch(len(dataset))
1633
1634
1635
1636
            dataset = dataset.batch(len(dataset))
            # Reinitialize to fix batchnorm again
            model.set_weights(model_weights)

1637
            # To match the other calls, don't pass sample weights in the validation data
1638
            history3 = model.fit(
1639
                weighted_dataset,
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
                validation_data=dataset,
                steps_per_epoch=1,
                validation_steps=1,
                shuffle=False,
            )
            val_loss3 = history3.history["val_loss"][0]
            self.assertTrue(not isnan(val_loss3))
            accuracy3 = {key: val[0] for key, val in history3.history.items() if key.endswith("accuracy")}
            self.check_keras_fit_results(val_loss1, val_loss3)
            self.assertEqual(history1.history.keys(), history3.history.keys())
            if metrics:
                self.assertTrue(len(accuracy1) == len(accuracy3) > 0, "Missing metrics!")
1652

Matt's avatar
Matt committed
1653
    def test_int_support(self):
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        for model_class in self.all_model_classes:
            prepared_for_class = self._prepare_for_class(
                inputs_dict.copy(),
                model_class,
                return_labels=True if "labels" in inspect.signature(model_class.call).parameters.keys() else False,
            )
            if not any(
                [tensor.dtype.is_integer for tensor in prepared_for_class.values() if isinstance(tensor, tf.Tensor)]
            ):
                return  # No integer inputs means no need for this test

            prepared_for_class = {
                key: tf.cast(tensor, tf.int64) if isinstance(tensor, tf.Tensor) and tensor.dtype.is_integer else tensor
                for key, tensor in prepared_for_class.items()
            }
            model = model_class(config)
            model(**prepared_for_class)  # No assertion, we're just checking this doesn't throw an error
Matt's avatar
Matt committed
1672
1673
1674
1675
1676
1677
1678
1679
            int32_prepared_for_class = {
                key: tf.cast(tensor, tf.int32) if isinstance(tensor, tf.Tensor) and tensor.dtype.is_integer else tensor
                for key, tensor in prepared_for_class.items()
            }
            model(**int32_prepared_for_class)  # No assertion, we're just checking this doesn't throw an error

            # After testing that the model accepts all int inputs, confirm that its dummies are int32
            for key, tensor in model.dummy_inputs.items():
1680
1681
1682
1683
                self.assertTrue(
                    isinstance(tensor, tf.Tensor) or tf.keras.backend.is_keras_tensor(tensor),
                    "Dummy inputs should be tf.Tensor!",
                )
Matt's avatar
Matt committed
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
                if tensor.dtype.is_integer:
                    self.assertTrue(tensor.dtype == tf.int32, "Integer dummy inputs should be tf.int32!")

            # Also confirm that the serving sig uses int32
            if hasattr(model, "serving"):
                serving_sig = model.serving.input_signature
                for key, tensor_spec in serving_sig[0].items():
                    if tensor_spec.dtype.is_integer:
                        self.assertTrue(
                            tensor_spec.dtype == tf.int32, "Serving signatures should use tf.int32 for ints!"
                        )
1695

1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
    def test_generate_with_headmasking(self):
        attention_names = ["encoder_attentions", "decoder_attentions", "cross_attentions"]
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_generative_model_classes:
            model = model_class(config)

            # We want to test only encoder-decoder models
            if not config.is_encoder_decoder:
                continue

            head_masking = {
                "head_mask": tf.zeros((config.encoder_layers, config.encoder_attention_heads)),
                "decoder_head_mask": tf.zeros((config.decoder_layers, config.decoder_attention_heads)),
                "cross_attn_head_mask": tf.zeros((config.decoder_layers, config.decoder_attention_heads)),
            }

            signature = inspect.signature(model.call)
1714
            if set(head_masking.keys()) < {*signature.parameters.keys()}:
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
                continue

            for attn_name, (name, mask) in zip(attention_names, head_masking.items()):
                out = model.generate(
                    inputs_dict["input_ids"],
                    num_beams=1,
                    max_length=inputs_dict["input_ids"] + 5,
                    output_attentions=True,
                    return_dict_in_generate=True,
                    **{name: mask},
                )
                # We check the state of decoder_attentions and cross_attentions just from the last step
                attn_weights = out[attn_name] if attn_name == attention_names[0] else out[attn_name][-1]
                self.assertEqual(sum([tf.reduce_sum(w).numpy() for w in attn_weights]), 0.0)

1730
    def test_load_with_mismatched_shapes(self):
1731
1732
        if not self.test_mismatched_shapes:
            return
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()

        for model_class in self.all_model_classes:
            if model_class not in get_values(TF_MODEL_FOR_SEQUENCE_CLASSIFICATION_MAPPING):
                continue

            with self.subTest(msg=f"Testing {model_class}"):
                with tempfile.TemporaryDirectory() as tmp_dir:
                    model = model_class(config)
                    inputs = self._prepare_for_class(inputs_dict, model_class)
                    _ = model(**inputs)
                    model.save_pretrained(tmp_dir)

                    # Fails when we don't set ignore_mismatched_sizes=True
                    with self.assertRaises(ValueError):
                        new_model = TFAutoModelForSequenceClassification.from_pretrained(tmp_dir, num_labels=42)
1749
1750
                    with self.assertRaises(ValueError):
                        new_model_without_prefix = TFAutoModel.from_pretrained(tmp_dir, vocab_size=10)
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761

                    logger = logging.get_logger("transformers.modeling_tf_utils")
                    with CaptureLogger(logger) as cl:
                        new_model = TFAutoModelForSequenceClassification.from_pretrained(
                            tmp_dir, num_labels=42, ignore_mismatched_sizes=True
                        )
                    self.assertIn("the shapes did not match", cl.out)

                    logits = new_model(**inputs).logits
                    self.assertEqual(logits.shape[1], 42)

1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
                    with CaptureLogger(logger) as cl:
                        new_model_without_prefix = TFAutoModel.from_pretrained(
                            tmp_dir, vocab_size=10, ignore_mismatched_sizes=True
                        )
                    self.assertIn("the shapes did not match", cl.out)

                    # Although Tf models always have a prefix pointing to `MainLayer`,
                    # we still add this "without prefix" test to keep a consistency between tf and pt tests.
                    input_ids = ids_tensor((2, 8), 10)
                    if self.is_encoder_decoder:
                        new_model_without_prefix(input_ids, decoder_input_ids=input_ids)
                    else:
                        new_model_without_prefix(input_ids)

1776
1777
1778
1779
1780
1781
1782
    def test_model_main_input_name(self):
        for model_class in self.all_model_classes:
            model_signature = inspect.signature(getattr(model_class, "call"))
            # The main input is the name of the argument after `self`
            observed_main_input_name = list(model_signature.parameters.keys())[1]
            self.assertEqual(model_class.main_input_name, observed_main_input_name)

1783
1784
1785
1786
1787
    def test_dataset_conversion(self):
        config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
        for model_class in self.all_model_classes:
            model = model_class(config)
            tf_inputs_dict = self._prepare_for_class(inputs_dict, model_class, return_labels=False)
Matt's avatar
Matt committed
1788
1789
            if "labels" in tf_inputs_dict:
                return  # This is some kinda funky decoder model that needs labels in its forward pass
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
            tf_inputs_dict = {
                key: val
                for key, val in tf_inputs_dict.items()
                if "head_mask" not in key and isinstance(val, tf.Tensor)
            }
            tf_inputs_dict["extra_unwanted_column"] = list(tf_inputs_dict.values())[0]  # Use a random other tensor
            input_dataset = Dataset.from_dict(tf_inputs_dict)
            tf_dataset = model.prepare_tf_dataset(
                input_dataset, batch_size=len(input_dataset), drop_remainder=False, shuffle=False
            )
            test_batch = next(iter(tf_dataset))
            if isinstance(test_batch, tf.Tensor):
                self.assertEqual(len(test_batch), len(input_dataset))  # Assert we didn't lose any data
Matt's avatar
Matt committed
1803
            elif isinstance(test_batch, dict):
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
                # Assert we discarded the unwanted extra column but kept everything else
                self.assertEqual(len(test_batch), len(input_dataset.features) - 1)
                self.assertNotIn("extra_unwanted_column", test_batch)
                for tensor in test_batch.values():
                    self.assertTrue(isinstance(tensor, tf.Tensor))
                    self.assertEqual(len(tensor), len(input_dataset))  # Assert we didn't lose any data
                    model(test_batch, training=False)

            if "labels" in inspect.signature(model_class.call).parameters.keys():
                tf_inputs_dict = self._prepare_for_class(inputs_dict, model_class, return_labels=True)
                if "labels" not in tf_inputs_dict:
                    return  # This model isn't giving us labels after all, don't try training with it
                tf_inputs_dict = {key: val for key, val in tf_inputs_dict.items() if "head_mask" not in key}
                tf_inputs_dict["extra_unwanted_column"] = list(tf_inputs_dict.values())[0]  # Use a random other tensor
                input_dataset = Dataset.from_dict(tf_inputs_dict)
                tf_dataset = model.prepare_tf_dataset(
                    input_dataset, batch_size=len(input_dataset), drop_remainder=False, shuffle=False
                )
                test_batch, test_batch_labels = next(iter(tf_dataset))
                self.assertGreater(len(test_batch_labels), 0)  # Assert the labels are present
                feature_columns = 1 if isinstance(test_batch, tf.Tensor) else len(test_batch)
                label_columns = 1 if isinstance(test_batch_labels, tf.Tensor) else len(test_batch_labels)
                # Assert we discarded the unwanted extra column but kept everything else
                self.assertEqual(feature_columns + label_columns, len(input_dataset.features) - 1)
                if isinstance(test_batch, dict):
                    self.assertNotIn("extra_unwanted_column", test_batch)
                if isinstance(test_batch_labels, dict):
                    self.assertNotIn("extra_unwanted_column", test_batch_labels)
                model.compile(optimizer="sgd", run_eagerly=True)
                model.train_on_batch(test_batch, test_batch_labels)

1835
    def _test_xla_generate(self, **generate_kwargs):
1836
        def _generate_and_check_results(model, inputs_dict):
1837
1838
1839
            if "input_ids" in inputs_dict:
                inputs = inputs_dict["input_ids"]
                # make sure there are no pad tokens in prompt, which may trigger unwanted behavior
1840
                if model.generation_config.pad_token_id is not None:
1841
                    if config.pad_token_id == 0:
1842
                        new_pad_token = model.generation_config.pad_token_id + 1
1843
                    else:
1844
                        new_pad_token = model.generation_config.pad_token_id - 1
1845
1846
                else:
                    new_pad_token = None
1847
                inputs = tf.where(inputs != model.generation_config.pad_token_id, inputs, new_pad_token)
1848
1849
1850
1851
1852
            elif "input_features" in inputs_dict:
                inputs = inputs_dict["input_features"]
            else:
                raise ValueError("No valid generate input found in inputs_dict")

1853
            generated = model.generate(inputs, **generate_kwargs).numpy()
1854
            generate_xla = tf.function(model.generate, jit_compile=True)
1855
            generated_xla = generate_xla(inputs, **generate_kwargs).numpy()
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867

            # Due to numerical instability, let's fail the test only if there are more than 10% of input sequences give
            # different outputs between XLA and non-XLA versions. If there are less than 10 examples, let's be strict
            # and not allow any difference.
            diff = [[], []]
            for _generated, _generated_xla in zip(generated.tolist(), generated_xla.tolist()):
                if _generated != _generated_xla:
                    diff[0].append(_generated)
                    diff[1].append(_generated_xla)
            ratio = len(diff[0]) / len(generated)
            if ratio > 0.1 or (len(diff[0]) > 0 and len(generated) < 10):
                self.assertListEqual(diff[0], diff[1])
1868
1869
1870
1871
1872

        for model_class in self.all_generative_model_classes:
            config, inputs_dict = self.model_tester.prepare_config_and_inputs_for_common()
            config.eos_token_id = None  # Generate until max length
            config.do_sample = False
1873

1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
            # fix config for models with additional sequence-length limiting settings
            for var_name in ["max_position_embeddings", "max_target_positions"]:
                attr = getattr(config, var_name, None)
                if attr is not None and attr < generate_kwargs["max_new_tokens"]:
                    try:
                        setattr(config, var_name, generate_kwargs["max_new_tokens"])
                    except NotImplementedError:
                        # xlnet will raise an exception when trying to set
                        # max_position_embeddings.
                        pass

1885
1886
1887
            model = model_class(config)

            if model.supports_xla_generation:
1888
                _generate_and_check_results(model, inputs_dict)
1889
1890
            else:
                with self.assertRaises(ValueError):
1891
                    _generate_and_check_results(model, inputs_dict)
1892
1893
1894
1895
1896
1897
1898
1899

    def test_xla_generate_fast(self):
        """
        Basic quick test for generate-compatible classes that confirms that XLA-generated tokens are the same as their
        non XLA counterparts.

        Either the model supports XLA generation and passes the inner test, or it raises an appropriate exception
        """
1900
        self._test_xla_generate(num_beams=1, num_return_sequences=1, max_new_tokens=3)
1901

1902
    @slow
1903
1904
    def test_xla_generate_contrastive(self):
        """
1905
1906
1907
        Slow and challenging version of `test_xla_generate_fast` for contrastive search -- contrastive search directly
        manipulates the model cache and other outputs, and this test ensures that they are in a valid format that is
        also supported by XLA.
1908
1909
1910

        Either the model supports XLA generation and passes the inner test, or it raises an appropriate exception
        """
1911
        self._test_xla_generate(num_beams=1, num_return_sequences=1, max_new_tokens=16, penalty_alpha=0.5, top_k=4)
1912

1913
1914
1915
1916
1917
1918
1919
1920
1921
    @slow
    def test_xla_generate_slow(self):
        """
        Slow and challenging version of `test_xla_generate_fast` -- this test asks for several long sequences using
        beam search, with and without XLA. The two outputs should match, and a failure in this test indicates that the
        model may need further analysis if it is to be used for XLA generation.

        Either the model supports XLA generation and passes the inner test, or it raises an appropriate exception
        """
1922
        self._test_xla_generate(num_beams=8, num_return_sequences=2, max_new_tokens=128)
1923

1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
    def _generate_random_bad_tokens(self, num_bad_tokens, model):
        # special tokens cannot be bad tokens
        special_tokens = []
        if model.config.bos_token_id is not None:
            special_tokens.append(model.config.bos_token_id)
        if model.config.pad_token_id is not None:
            special_tokens.append(model.config.pad_token_id)
        if model.config.eos_token_id is not None:
            special_tokens.append(model.config.eos_token_id)

        # create random bad tokens that are not special tokens
        bad_tokens = []
        while len(bad_tokens) < num_bad_tokens:
            token = tf.squeeze(ids_tensor((1, 1), self.model_tester.vocab_size), 0).numpy()[0]
            if token not in special_tokens:
                bad_tokens.append(token)
        return bad_tokens

1942
    def _check_generated_ids(self, output_ids):
1943
1944
1945
1946
        for token_id in output_ids[0].numpy().tolist():
            self.assertGreaterEqual(token_id, 0)
            self.assertLess(token_id, self.model_tester.vocab_size)

1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
    def _check_match_tokens(self, generated_ids, bad_words_ids):
        # for all bad word tokens
        for bad_word_ids in bad_words_ids:
            # for all slices in batch
            for generated_ids_slice in generated_ids:
                # for all word idx
                for i in range(len(bad_word_ids), len(generated_ids_slice)):
                    # if tokens match
                    if generated_ids_slice[i - len(bad_word_ids) : i] == bad_word_ids:
                        return True
        return False

thomwolf's avatar
thomwolf committed
1959

thomwolf's avatar
thomwolf committed
1960
def ids_tensor(shape, vocab_size, rng=None, name=None, dtype=None):
thomwolf's avatar
thomwolf committed
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
    """Creates a random int32 tensor of the shape within the vocab size."""
    if rng is None:
        rng = random.Random()

    total_dims = 1
    for dim in shape:
        total_dims *= dim

    values = []
    for _ in range(total_dims):
        values.append(rng.randint(0, vocab_size - 1))

1973
    output = tf.constant(values, shape=shape, dtype=dtype if dtype is not None else tf.int32)
thomwolf's avatar
thomwolf committed
1974
1975

    return output
1976
1977


Yih-Dar's avatar
Yih-Dar committed
1978
1979
1980
def random_attention_mask(shape, rng=None, name=None, dtype=None):
    attn_mask = ids_tensor(shape, vocab_size=2, rng=None, name=None, dtype=dtype)
    # make sure that at least one token is attended to for each batch
1981
    attn_mask = tf.concat([attn_mask[:, :-1], tf.ones_like(attn_mask[:, -1:], dtype=dtype)], axis=-1)
Yih-Dar's avatar
Yih-Dar committed
1982
1983
1984
    return attn_mask


1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
def floats_tensor(shape, scale=1.0, rng=None, name=None, dtype=None):
    """Creates a random float32 tensor"""
    if rng is None:
        rng = random.Random()

    total_dims = 1
    for dim in shape:
        total_dims *= dim

    values = []
    for _ in range(total_dims):
        values.append(rng.random() * scale)

    return tf.reshape(tf.constant(values, dtype=dtype if dtype is not None else tf.float32), shape=shape)


2001
2002
@require_tf
class UtilsFunctionsTest(unittest.TestCase):
2003
2004
2005
2006
    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
2007
        response_mock.headers = {}
2008
        response_mock.raise_for_status.side_effect = HTTPError
2009
        response_mock.json.return_value = {}
2010
2011
2012
2013
2014

        # 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.
Lucain's avatar
Lucain committed
2015
        with mock.patch("requests.Session.request", return_value=response_mock) as mock_head:
2016
2017
2018
2019
            _ = TFBertModel.from_pretrained("hf-internal-testing/tiny-random-bert")
            # This check we did call the fake head request
            mock_head.assert_called()

2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
    def test_load_from_one_file(self):
        try:
            tmp_file = tempfile.mktemp()
            with open(tmp_file, "wb") as f:
                http_get("https://huggingface.co/hf-internal-testing/tiny-random-bert/resolve/main/tf_model.h5", f)

            config = BertConfig.from_pretrained("hf-internal-testing/tiny-random-bert")
            _ = TFBertModel.from_pretrained(tmp_file, config=config)
        finally:
            os.remove(tmp_file)

    def test_legacy_load_from_url(self):
        # This test is for deprecated behavior and can be removed in v5
        config = BertConfig.from_pretrained("hf-internal-testing/tiny-random-bert")
        _ = TFBertModel.from_pretrained(
            "https://huggingface.co/hf-internal-testing/tiny-random-bert/resolve/main/tf_model.h5", config=config
        )

2038
2039
2040
2041
2042
2043
    # 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)
2044
                self.main_input_name = "input_ids"
2045
2046
2047

            @unpack_inputs
            def call(
2048
2049
2050
2051
2052
2053
                self,
                input_ids=None,
                past_key_values=None,
                output_attentions=None,
                output_hidden_states=None,
                return_dict=None,
2054
            ):
2055
                return input_ids, past_key_values, output_attentions, output_hidden_states, return_dict
2056

2057
2058
2059
2060
            @unpack_inputs
            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

2061
        dummy_model = DummyModel()
Matt's avatar
Matt committed
2062
2063
2064
        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)
2065
2066

        # test case 1: Pass inputs as keyword arguments; Booleans are inherited from the config.
2067
        output = dummy_model.call(input_ids=input_ids, past_key_values=past_key_values)
2068
        tf.debugging.assert_equal(output[0], input_ids)
2069
        tf.debugging.assert_equal(output[1], past_key_values)
2070
2071
2072
2073
2074
        self.assertFalse(output[2])
        self.assertFalse(output[3])
        self.assertFalse(output[4])

        # test case 2: Same as above, but with positional arguments.
2075
        output = dummy_model.call(input_ids, past_key_values)
2076
        tf.debugging.assert_equal(output[0], input_ids)
2077
        tf.debugging.assert_equal(output[1], past_key_values)
2078
2079
2080
2081
2082
        self.assertFalse(output[2])
        self.assertFalse(output[3])
        self.assertFalse(output[4])

        # test case 3: We can also pack everything in the first input.
2083
        output = dummy_model.call(input_ids={"input_ids": input_ids, "past_key_values": past_key_values})
2084
        tf.debugging.assert_equal(output[0], input_ids)
2085
        tf.debugging.assert_equal(output[1], past_key_values)
2086
2087
2088
2089
2090
        self.assertFalse(output[2])
        self.assertFalse(output[3])
        self.assertFalse(output[4])

        # test case 4: Explicit boolean arguments should override the config.
2091
2092
2093
        output = dummy_model.call(
            input_ids=input_ids, past_key_values=past_key_values, output_attentions=False, return_dict=True
        )
2094
        tf.debugging.assert_equal(output[0], input_ids)
2095
        tf.debugging.assert_equal(output[1], past_key_values)
2096
2097
2098
2099
2100
2101
        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):
2102
            output = dummy_model.call(input_ids=input_ids, past_key_values=past_key_values, foo="bar")
2103

2104
        # test case 6: the decorator is independent from `main_input_name` -- it treats the first argument of the
2105
2106
2107
2108
2109
2110
2111
        # 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])

Joao Gante's avatar
Joao Gante committed
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
    # 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)

Arthur's avatar
Arthur committed
2147
2148
2149
2150
2151
2152
2153
    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())

2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
    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")

2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
    @is_pt_tf_cross_test
    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())

2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
    @is_pt_tf_cross_test
    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/"))

2186
2187
2188
2189
2190
2191
2192
2193
    @is_pt_tf_cross_test
    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())

Arthur's avatar
Arthur committed
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
    def test_shard_checkpoint(self):
        # This is the model we will use, total size 340,000 bytes.
        model = tf.keras.Sequential(
            [
                tf.keras.layers.Dense(200, use_bias=False),  # size 80,000
                tf.keras.layers.Dense(200, use_bias=False),  # size 160,000
                tf.keras.layers.Dense(100, use_bias=False),  # size 80,000
                tf.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,
                },
            )

2261
    @slow
Sylvain Gugger's avatar
Sylvain Gugger committed
2262
    def test_special_layer_name_sharding(self):
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
        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())

Arthur's avatar
Arthur committed
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
    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())
2310
                shards_found = {f for f in os.listdir(tmp_dir) if f.endswith(".h5")}
Arthur's avatar
Arthur committed
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
                self.assertSetEqual(all_shards, shards_found)

                # Finally, check the model can be reloaded
                new_model = TFBertModel.from_pretrained(tmp_dir)

                model(model.dummy_inputs)
                new_model(model.dummy_inputs)

                for p1, p2 in zip(model.weights, new_model.weights):
                    self.assertTrue(np.allclose(p1.numpy(), p2.numpy()))

2322
    @slow
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
    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.
        @tf.function(
            input_signature=[
                [
                    tf.TensorSpec([None, None], tf.int32, name="input_ids"),
                    tf.TensorSpec([None, None], tf.int32, name="token_type_ids"),
                    tf.TensorSpec([None, None], tf.int32, name="attention_mask"),
                ]
            ]
        )
        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 = tf.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 = tf.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 = tf.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()))

Sylvain Gugger's avatar
Sylvain Gugger committed
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
    @require_safetensors
    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, TF2_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()))

    @is_pt_tf_cross_test
    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()))

    @require_safetensors
    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()))

Sylvain Gugger's avatar
Sylvain Gugger committed
2411
2412
2413
2414
2415
2416

@require_tf
@is_staging_test
class TFModelPushToHubTester(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
2417
2418
        cls._token = TOKEN
        HfFolder.save_token(TOKEN)
Sylvain Gugger's avatar
Sylvain Gugger committed
2419
2420
2421
2422

    @classmethod
    def tearDownClass(cls):
        try:
2423
            delete_repo(token=cls._token, repo_id="test-model-tf")
Sylvain Gugger's avatar
Sylvain Gugger committed
2424
2425
2426
        except HTTPError:
            pass

2427
2428
2429
2430
2431
        try:
            delete_repo(token=cls._token, repo_id="test-model-tf-callback")
        except HTTPError:
            pass

Sylvain Gugger's avatar
Sylvain Gugger committed
2432
        try:
2433
            delete_repo(token=cls._token, repo_id="valid_org/test-model-tf-org")
Sylvain Gugger's avatar
Sylvain Gugger committed
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
        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(model.dummy_inputs)

2445
2446
2447
2448
2449
2450
        logging.set_verbosity_info()
        logger = logging.get_logger("transformers.utils.hub")
        with CaptureLogger(logger) as cl:
            model.push_to_hub("test-model-tf", use_auth_token=self._token)
        logging.set_verbosity_warning()
        # Check the model card was created and uploaded.
2451
        self.assertIn("Uploading the following files to __DUMMY_TRANSFORMERS_USER__/test-model-tf", cl.out)
2452
2453
2454
2455

        new_model = TFBertModel.from_pretrained(f"{USER}/test-model-tf")
        models_equal = True
        for p1, p2 in zip(model.weights, new_model.weights):
2456
            if not tf.math.reduce_all(p1 == p2):
2457
                models_equal = False
2458
                break
2459
2460
2461
2462
2463
2464
        self.assertTrue(models_equal)

        # Reset repo
        delete_repo(token=self._token, repo_id="test-model-tf")

        # Push to hub via save_pretrained
Matt's avatar
Matt committed
2465
        with tempfile.TemporaryDirectory() as tmp_dir:
2466
2467
2468
2469
2470
            model.save_pretrained(tmp_dir, repo_id="test-model-tf", push_to_hub=True, use_auth_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):
2471
2472
2473
2474
2475
            if not tf.math.reduce_all(p1 == p2):
                models_equal = False
                break
        self.assertTrue(models_equal)

2476
    @is_pt_tf_cross_test
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
    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):
2496
                models_equal = False
2497
                break
2498
        self.assertTrue(models_equal)
Matt's avatar
Matt committed
2499

2500
2501
2502
2503
2504
2505
        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)

Sylvain Gugger's avatar
Sylvain Gugger committed
2506
2507
2508
2509
2510
    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)
2511
2512
2513
2514
2515
2516
2517
2518
        # Make sure model is properly initialized
        _ = model(model.dummy_inputs)

        model.push_to_hub("valid_org/test-model-tf-org", use_auth_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):
2519
            if not tf.math.reduce_all(p1 == p2):
2520
                models_equal = False
2521
                break
2522
2523
2524
2525
2526
2527
        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
Sylvain Gugger's avatar
Sylvain Gugger committed
2528
2529
        with tempfile.TemporaryDirectory() as tmp_dir:
            model.save_pretrained(
2530
                tmp_dir, push_to_hub=True, use_auth_token=self._token, repo_id="valid_org/test-model-tf-org"
Sylvain Gugger's avatar
Sylvain Gugger committed
2531
2532
            )

2533
2534
2535
        new_model = TFBertModel.from_pretrained("valid_org/test-model-tf-org")
        models_equal = True
        for p1, p2 in zip(model.weights, new_model.weights):
2536
            if not tf.math.reduce_all(p1 == p2):
2537
                models_equal = False
2538
                break
2539
        self.assertTrue(models_equal)