|
704 | 704 | "cell_type": "markdown",
|
705 | 705 | "metadata": {},
|
706 | 706 | "source": [
|
707 |
| - "Note that most models on the Hub compute loss internally, so we actually don't have to specify anything there! Leaving the loss field blank will cause the model to read the `loss` head as its loss value.\n", |
| 707 | + "Next, we compile our model. Note that most Transformers models compute loss internally, so we actually don't have to specify anything for that argument! You can of course set your own loss function if you want, but by default our models will choose the 'obvious' loss that matches their task, such as cross-entropy in the case of language modelling. The built-in loss will also correctly handle things like masking the loss on padding tokens, or unlabelled tokens in the case of masked language modelling, so we recommend using it unless you're an advanced user!\n", |
708 | 708 | "\n",
|
709 |
| - "This is an unusual quirk of TensorFlow models in 🤗 Transformers, so it's worth elaborating on in a little more detail. All 🤗 Transformers models are capable of computing an appropriate loss for their task internally (for example, a CausalLM model will use a cross-entropy loss). To do this, the labels must be provided in the input dict (or equivalently, in the `columns` argument to `to_tf_dataset()`), so that they are visible to the model during the forward pass.\n", |
| 709 | + "We also use the `jit_compile` argument to compile the model with [XLA](https://www.tensorflow.org/xla). XLA compilation adds a delay at the start of training, but this is quickly repaid by faster training iterations after that. It has one downside, though - if the shape of your input changes at all, then it will need to rerun the compilation again! This isn't a problem for us in this notebook, because all of our examples are exactly the same length. Be careful with it when that isn't true, though - if you have a variable sequence length in your batches, then you might spend more time compiling your model than actually training, especially for small datasets!\n", |
710 | 710 | "\n",
|
711 |
| - "This is quite different from the standard Keras way of handling losses, where labels are passed separately and not visible to the main body of the model, and loss is handled by a function that the user passes to `compile()`, which uses the model outputs and the label to compute a loss value.\n", |
712 |
| - "\n", |
713 |
| - "The approach we take is that if the user does not pass a loss to `compile()`, the model will assume you want the **internal** loss. If you are doing this, you should make sure that the labels column(s) are included in the **input dict** or in the `columns` argument to `to_tf_dataset`.\n", |
714 |
| - "\n", |
715 |
| - "If you want to use your own loss, that is of course possible too! If you do this, you should make sure your labels column(s) are passed like normal labels, either as the **second argument** to `model.fit()`, or in the `label_cols` argument to `to_tf_dataset`. " |
| 711 | + "If you encounter difficulties when training with XLA, it's a good idea to remove the `jit_compile` argument and see if that fixes things. In fact, when debugging, it can be helpful to skip graph compilation entirely with the `run_eagerly=True` argument to [`compile()`](https://www.tensorflow.org/api_docs/python/tf/keras/Model#compile). This will let you identify the exact line of code where problems arise, but it will significantly reduce your performance, so make sure to remove it again when you've fixed the problem!" |
716 | 712 | ]
|
717 | 713 | },
|
718 | 714 | {
|
719 | 715 | "cell_type": "code",
|
720 |
| - "execution_count": 19, |
| 716 | + "execution_count": 1, |
721 | 717 | "metadata": {},
|
722 | 718 | "outputs": [
|
723 | 719 | {
|
724 |
| - "name": "stderr", |
725 |
| - "output_type": "stream", |
726 |
| - "text": [ |
727 |
| - "No loss specified in compile() - the model's internal loss computation will be used as the loss. Don't panic - this is a common way to train TensorFlow models in Transformers! Please ensure your labels are passed as keys in the input dict so that they are accessible to the model during the forward pass. To disable this behaviour, please pass a loss argument, or explicitly pass loss=None if you do not want your model to compute a loss.\n" |
| 720 | + "ename": "NameError", |
| 721 | + "evalue": "name 'model' is not defined", |
| 722 | + "output_type": "error", |
| 723 | + "traceback": [ |
| 724 | + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", |
| 725 | + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", |
| 726 | + "Input \u001b[0;32mIn [1]\u001b[0m, in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mtensorflow\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mtf\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m \u001b[43mmodel\u001b[49m\u001b[38;5;241m.\u001b[39mcompile(optimizer\u001b[38;5;241m=\u001b[39moptimizer, jit_compile\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n", |
| 727 | + "\u001b[0;31mNameError\u001b[0m: name 'model' is not defined" |
728 | 728 | ]
|
729 | 729 | }
|
730 | 730 | ],
|
731 | 731 | "source": [
|
732 | 732 | "import tensorflow as tf\n",
|
733 | 733 | "\n",
|
734 |
| - "model.compile(optimizer=optimizer)" |
| 734 | + "model.compile(optimizer=optimizer, jit_compile=True)" |
735 | 735 | ]
|
736 | 736 | },
|
737 | 737 | {
|
738 | 738 | "cell_type": "markdown",
|
739 | 739 | "metadata": {},
|
740 | 740 | "source": [
|
741 |
| - "Finally, we need to convert our datasets to a format Keras understands. The easiest way to do this is with the `to_tf_dataset()` method. Because all our inputs are the same length, no padding is required, so we can use the DefaultDataCollator. Note that our data collators are designed to work for multiple frameworks, so ensure you set the `return_tensors='tf'` argument to get Tensorflow tensors out - you don't want to accidentally get a load of `torch.Tensor` objects in the middle of your nice TF code!" |
| 741 | + "Next, we convert our datasets to `tf.data.Dataset`, which Keras understands natively. There are two ways to do this - we can use the slightly more low-level [`Dataset.to_tf_dataset()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.to_tf_dataset) method, or we can use [`Model.prepare_tf_dataset()`](https://huggingface.co/docs/transformers/main_classes/model#transformers.TFPreTrainedModel.prepare_tf_dataset). The main difference between these two is that the `Model` method can inspect the model to determine which column names it can use as input, which means you don't need to specify them yourself. It also supplies a data collator by default which is appropriate for most tasks." |
742 | 742 | ]
|
743 | 743 | },
|
744 | 744 | {
|
|
747 | 747 | "metadata": {},
|
748 | 748 | "outputs": [],
|
749 | 749 | "source": [
|
750 |
| - "from transformers import DefaultDataCollator\n", |
751 |
| - "\n", |
752 |
| - "data_collator = DefaultDataCollator(return_tensors=\"tf\")\n", |
753 |
| - "\n", |
754 |
| - "train_set = lm_datasets[\"train\"].to_tf_dataset(\n", |
755 |
| - " columns=[\"attention_mask\", \"input_ids\", \"labels\"],\n", |
| 750 | + "train_set = model.prepare_tf_dataset(\n", |
| 751 | + " lm_datasets[\"train\"],\n", |
756 | 752 | " shuffle=True,\n",
|
757 | 753 | " batch_size=16,\n",
|
758 |
| - " collate_fn=data_collator,\n", |
759 | 754 | ")\n",
|
760 |
| - "validation_set = lm_datasets[\"validation\"].to_tf_dataset(\n", |
761 |
| - " columns=[\"attention_mask\", \"input_ids\", \"labels\"],\n", |
| 755 | + "\n", |
| 756 | + "validation_set = model.prepare_tf_dataset(\n", |
| 757 | + " lm_datasets[\"validation\"],\n", |
762 | 758 | " shuffle=False,\n",
|
763 | 759 | " batch_size=16,\n",
|
764 |
| - " collate_fn=data_collator,\n", |
765 | 760 | ")"
|
766 | 761 | ]
|
767 | 762 | },
|
|
914 | 909 | "```"
|
915 | 910 | ]
|
916 | 911 | },
|
| 912 | + { |
| 913 | + "cell_type": "markdown", |
| 914 | + "metadata": {}, |
| 915 | + "source": [ |
| 916 | + "## Inference" |
| 917 | + ] |
| 918 | + }, |
| 919 | + { |
| 920 | + "cell_type": "markdown", |
| 921 | + "metadata": {}, |
| 922 | + "source": [ |
| 923 | + "Models trained from scratch on small amounts of data will generally not output useful text - you'll need a much bigger dataset and a much longer training time before it starts writing text that you'd want to read! If you want to see an example of inference with causal language models, see the `language_modeling-tf` notebook, where we start with a pre-trained model and get higher-quality output much sooner as a result." |
| 924 | + ] |
| 925 | + }, |
917 | 926 | {
|
918 | 927 | "cell_type": "markdown",
|
919 | 928 | "metadata": {
|
|
942 | 951 | },
|
943 | 952 | "outputs": [],
|
944 | 953 | "source": [
|
945 |
| - "model_checkpoint = \"bert-base-cased\"\n", |
946 |
| - "tokenizer_checkpoint = \"sgugger/bert-like-tokenizer\"" |
| 954 | + "model_checkpoint = \"bert-base-cased\"" |
947 | 955 | ]
|
948 | 956 | },
|
949 | 957 | {
|
|
976 | 984 | }
|
977 | 985 | ],
|
978 | 986 | "source": [
|
979 |
| - "tokenizer = AutoTokenizer.from_pretrained(tokenizer_checkpoint)\n", |
| 987 | + "tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)\n", |
980 | 988 | "tokenized_datasets = datasets.map(\n",
|
981 | 989 | " tokenize_function, batched=True, num_proc=4, remove_columns=[\"text\"]\n",
|
982 | 990 | ")"
|
|
1074 | 1082 | "cell_type": "markdown",
|
1075 | 1083 | "metadata": {},
|
1076 | 1084 | "source": [
|
1077 |
| - "And as before, we leave the `loss` argument blank to use the internal loss." |
| 1085 | + "And as before, we leave the `loss` argument blank to use the internal loss, and use `jit_compile` to enable XLA." |
1078 | 1086 | ]
|
1079 | 1087 | },
|
1080 | 1088 | {
|
|
1093 | 1101 | "source": [
|
1094 | 1102 | "import tensorflow as tf\n",
|
1095 | 1103 | "\n",
|
1096 |
| - "model.compile(optimizer=optimizer)" |
| 1104 | + "model.compile(optimizer=optimizer, jit_compile=True)" |
1097 | 1105 | ]
|
1098 | 1106 | },
|
1099 | 1107 | {
|
|
1128 | 1136 | "id": "bqHnWcYC3l_d"
|
1129 | 1137 | },
|
1130 | 1138 | "source": [
|
1131 |
| - "Now we pass our data collator to the `to_tf_dataset()` argument." |
| 1139 | + "Now we pass our data collator to the `prepare_tf_dataset()` argument." |
1132 | 1140 | ]
|
1133 | 1141 | },
|
1134 | 1142 | {
|
|
1137 | 1145 | "metadata": {},
|
1138 | 1146 | "outputs": [],
|
1139 | 1147 | "source": [
|
1140 |
| - "train_set = lm_datasets[\"train\"].to_tf_dataset(\n", |
1141 |
| - " columns=[\"attention_mask\", \"input_ids\", \"labels\"],\n", |
| 1148 | + "train_set = model.prepare_tf_dataset(\n", |
| 1149 | + " lm_datasets[\"train\"],\n", |
1142 | 1150 | " shuffle=True,\n",
|
1143 | 1151 | " batch_size=16,\n",
|
1144 | 1152 | " collate_fn=data_collator,\n",
|
1145 | 1153 | ")\n",
|
1146 |
| - "validation_set = lm_datasets[\"validation\"].to_tf_dataset(\n", |
1147 |
| - " columns=[\"attention_mask\", \"input_ids\", \"labels\"],\n", |
| 1154 | + "\n", |
| 1155 | + "validation_set = model.prepare_tf_dataset(\n", |
| 1156 | + " lm_datasets[\"validation\"],\n", |
1148 | 1157 | " shuffle=False,\n",
|
1149 | 1158 | " batch_size=16,\n",
|
1150 | 1159 | " collate_fn=data_collator,\n",
|
|
1265 | 1274 | "```"
|
1266 | 1275 | ]
|
1267 | 1276 | },
|
| 1277 | + { |
| 1278 | + "cell_type": "markdown", |
| 1279 | + "metadata": {}, |
| 1280 | + "source": [ |
| 1281 | + "## Inference" |
| 1282 | + ] |
| 1283 | + }, |
| 1284 | + { |
| 1285 | + "cell_type": "markdown", |
| 1286 | + "metadata": {}, |
| 1287 | + "source": [ |
| 1288 | + "As with the causal LM above, masked language models trained from scratch on small amounts of data will generally not be very good at their job - you'll need a much bigger dataset and a much longer training time to make a truly useful one! If you want to see an example of inference with masked language models, see the `language_modeling-tf` notebook, where we start with a pre-trained model and get higher-quality output much sooner as a result." |
| 1289 | + ] |
| 1290 | + }, |
1268 | 1291 | {
|
1269 | 1292 | "cell_type": "code",
|
1270 | 1293 | "execution_count": null,
|
|
1293 | 1316 | "name": "python",
|
1294 | 1317 | "nbconvert_exporter": "python",
|
1295 | 1318 | "pygments_lexer": "ipython3",
|
1296 |
| - "version": "3.10.0" |
| 1319 | + "version": "3.10.4" |
1297 | 1320 | }
|
1298 | 1321 | },
|
1299 | 1322 | "nbformat": 4,
|
|
0 commit comments