Skip to content

Commit 0631cbf

Browse files
Created using Colaboratory
1 parent 7cb1431 commit 0631cbf

File tree

1 file changed

+143
-45
lines changed

1 file changed

+143
-45
lines changed

chapter11_part02_sequence-models.ipynb

Lines changed: 143 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@
8383
},
8484
{
8585
"cell_type": "code",
86-
"execution_count": 2,
86+
"execution_count": 1,
8787
"metadata": {
8888
"colab": {
8989
"base_uri": "https://localhost:8080/"
9090
},
9191
"id": "OGvK58hsjdwv",
92-
"outputId": "cd051d4b-566e-480b-8378-f152e899bf6b"
92+
"outputId": "c6039281-6ac8-4f59-d41b-06856df4f919"
9393
},
9494
"outputs": [
9595
{
@@ -98,7 +98,7 @@
9898
"text": [
9999
" % Total % Received % Xferd Average Speed Time Time Time Current\n",
100100
" Dload Upload Total Spent Left Speed\n",
101-
"100 80.2M 100 80.2M 0 0 14.5M 0 0:00:05 0:00:05 --:--:-- 16.4M\n"
101+
"100 80.2M 100 80.2M 0 0 8564k 0 0:00:09 0:00:09 --:--:-- 12.2M\n"
102102
]
103103
}
104104
],
@@ -134,7 +134,7 @@
134134
"base_uri": "https://localhost:8080/"
135135
},
136136
"id": "_JwuTAnfjdww",
137-
"outputId": "fbf0e10a-84fc-4cef-ef61-564d43f25337"
137+
"outputId": "ad3d822a-1e24-46ca-ca03-9dca124027cf"
138138
},
139139
"outputs": [
140140
{
@@ -241,7 +241,7 @@
241241
"base_uri": "https://localhost:8080/"
242242
},
243243
"id": "UJ0MDrEwjdwy",
244-
"outputId": "29ad4cc3-9954-4846-e85c-f485f4add33c"
244+
"outputId": "b2215c6e-806a-4235-8650-ceb5228783cc"
245245
},
246246
"outputs": [
247247
{
@@ -453,28 +453,11 @@
453453
},
454454
{
455455
"cell_type": "code",
456-
"execution_count": 1,
456+
"execution_count": 5,
457457
"metadata": {
458-
"colab": {
459-
"base_uri": "https://localhost:8080/",
460-
"height": 197
461-
},
462-
"id": "9mZ7UQTUjdwz",
463-
"outputId": "71a5c8be-9908-4b32-b0ea-8263b7089934"
458+
"id": "9mZ7UQTUjdwz"
464459
},
465-
"outputs": [
466-
{
467-
"output_type": "error",
468-
"ename": "NameError",
469-
"evalue": "ignored",
470-
"traceback": [
471-
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
472-
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
473-
"\u001b[0;32m<ipython-input-1-1417eb60feec>\u001b[0m in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0membedding_layer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlayers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mEmbedding\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput_dim\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmax_tokens\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moutput_dim\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m256\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# The Embedding layer takes at least two arguments: the number of\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;31m# possible tokens and the dimensionality of the embeddings (here, 256).\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
474-
"\u001b[0;31mNameError\u001b[0m: name 'layers' is not defined"
475-
]
476-
}
477-
],
460+
"outputs": [],
478461
"source": [
479462
"embedding_layer = layers.Embedding(input_dim=max_tokens, output_dim=256) # The Embedding layer takes at least two arguments: the number of\n",
480463
" # possible tokens and the dimensionality of the embeddings (here, 256)."
@@ -525,9 +508,46 @@
525508
"cell_type": "code",
526509
"execution_count": null,
527510
"metadata": {
528-
"id": "XPW1QVqijdwz"
511+
"colab": {
512+
"base_uri": "https://localhost:8080/"
513+
},
514+
"id": "XPW1QVqijdwz",
515+
"outputId": "74a25aff-765a-460d-bbf7-31bf2eae102e"
529516
},
530-
"outputs": [],
517+
"outputs": [
518+
{
519+
"output_type": "stream",
520+
"name": "stdout",
521+
"text": [
522+
"Model: \"model_1\"\n",
523+
"_________________________________________________________________\n",
524+
" Layer (type) Output Shape Param # \n",
525+
"=================================================================\n",
526+
" input_2 (InputLayer) [(None, None)] 0 \n",
527+
" \n",
528+
" embedding_1 (Embedding) (None, None, 256) 5120000 \n",
529+
" \n",
530+
" bidirectional_1 (Bidirectio (None, 64) 73984 \n",
531+
" nal) \n",
532+
" \n",
533+
" dropout_1 (Dropout) (None, 64) 0 \n",
534+
" \n",
535+
" dense_1 (Dense) (None, 1) 65 \n",
536+
" \n",
537+
"=================================================================\n",
538+
"Total params: 5,194,049\n",
539+
"Trainable params: 5,194,049\n",
540+
"Non-trainable params: 0\n",
541+
"_________________________________________________________________\n",
542+
"Epoch 1/10\n",
543+
"625/625 [==============================] - 725s 1s/step - loss: 0.5296 - accuracy: 0.7391 - val_loss: 0.3803 - val_accuracy: 0.8542\n",
544+
"Epoch 2/10\n",
545+
"625/625 [==============================] - 645s 1s/step - loss: 0.3777 - accuracy: 0.8534 - val_loss: 0.3608 - val_accuracy: 0.8566\n",
546+
"Epoch 3/10\n",
547+
"342/625 [===============>..............] - ETA: 4:23 - loss: 0.3036 - accuracy: 0.8893"
548+
]
549+
}
550+
],
531551
"source": [
532552
"inputs = keras.Input(shape=(None,), dtype=\"int64\")\n",
533553
"embedded = layers.Embedding(input_dim=max_tokens, output_dim=256)(inputs)\n",
@@ -571,18 +591,15 @@
571591
{
572592
"cell_type": "markdown",
573593
"source": [
574-
"One thing that's slightly hurting model performance here is that our input sequences are full of zeros. This comes from our use of the `output_sequence_length=max_length option` in `TextVectorization` (with `max_length` equal to 600): sentences longer than 600 tokens are truncated to a length of 600 tokens, and sentences shorter than 600 tokens are padded with zeros at the end so that they can be concatenated together with other sequences to form contiguous batches.\n",
594+
"One thing that's slightly hurting model performance here is that our <font color='blue'>input sequences</font> are full of <font color='blue'>zeros</font>. This comes from our use of the `output_sequence_length=max_length option` in `TextVectorization` (with `max_length` equal to 600): sentences <font color='blue'>longer</font> than <font color='blue'>600 tokens</font> are <font color='blue'>truncated</font> to a length of 600 tokens, and sentences <font color='blue'>shorter</font> than <font color='blue'>600 tokens</font> are <font color='blue'>padded with zeros</font> at the end so that they can be concatenated together with other sequences to form contiguous batches.\n",
575595
"\n",
576-
"We're using a bidirectional RNN: two RNN layers running in parallel, with one\n",
577-
"processing the tokens in their natural order, and the other processing the same\n",
578-
"tokens in reverse. The RNN that looks at the tokens in their natural order will spend its last iterations seeing only vectors that encode padding—possibly for several hundreds of iterations if the original sentence was short. The information stored in the internal state of the RNN will gradually fade out as it gets exposed to these meaningless inputs.\n",
596+
"We're using a bidirectional RNN: two RNN layers running in <font color='blue'>parallel</font>, with one processing the tokens in their <font color='blue'>natural order</font>, and the other processing the <font color='blue'>same</font> tokens in <font color='blue'>reverse</font>. The RNN that looks at the tokens in their natural order will spend its <font color='blue'>last iterations</font> seeing only vectors that <font color='blue'>encode padding</font>—possibly for several hundreds of iterations if the original sentence was short. The information stored in the internal state of the RNN will gradually fade out as it gets exposed to these meaningless inputs.\n",
579597
"\n",
580598
"We need some way to tell the RNN that it should skip these iterations. There's an API for that: <font color='blue'>masking<font color='blue'>.\n",
581599
"\n",
582-
"The *Embedding* layer is capable of generating a “mask” that corresponds to its\n",
583-
"input data. This mask is a tensor of ones and zeros (or True/False booleans), of shape `(batch_size, sequence_length)`, where the entry `mask[i, t]` indicates where time step `t` of sample `i` should be skipped or not (the timestep will be skipped if mask`[i, t]` is 0 or False, and processed otherwise).\n",
600+
"The *Embedding* layer is capable of generating a <font color='blue'>mask</font> that corresponds to its input data. This mask is a <font color='blue'>tensor</font> of <font color='blue'>ones</font> and <font color='blue'>zeros</font> (or True/False booleans), of shape `(batch_size, sequence_length)`, where the entry <font color='blue'>mask[i, t]</font> indicates where time step <font color='blue'>t</font> of sample <font color='blue'>i</font> should be skipped or not (the timestep will be skipped if mask`[i, t]` is 0 or False, and processed otherwise).\n",
584601
"\n",
585-
"By default, this option isn't active—you can turn it on by passing `mask_zero=True` to your *Embedding* layer. You can retrieve the mask with the `compute_mask()` method:"
602+
"By default, this option isn't active—you can turn it on by passing <font color='blue'>mask_zero=True</font> to your *Embedding* layer. You can retrieve the mask with the `compute_mask()` method:"
586603
],
587604
"metadata": {
588605
"id": "-rLx8D0Jw-cT"
@@ -611,13 +628,10 @@
611628
{
612629
"cell_type": "markdown",
613630
"source": [
614-
"(FIX FROM HERE!)\n",
631+
"In practice, you will almost never have to manage masks by hand. Instead, Keras will <font color='blue'>automatically</font> pass on the mask to <font color='blue'>every layer</font> that is able to process it (as a piece of\n",
632+
"metadata attached to the sequence it represents). This mask will be used by RNN layers to skip masked steps. If your model returns an entire sequence, the mask will also be used by the loss function to skip masked steps in the output sequence.\n",
615633
"\n",
616-
"In practice, you will almost never have to manage masks by hand. Instead, Keras will\n",
617-
"automatically pass on the mask to every layer that is able to process it (as a piece of\n",
618-
"metadata attached to the sequence it represents). This mask will be used by RNN lay-\n",
619-
"ers to skip masked steps. If your model returns an entire sequence, the mask will also\n",
620-
"be used by the loss function to skip masked steps in the output sequence."
634+
"Let’s try retraining our model with masking enabled."
621635
],
622636
"metadata": {
623637
"id": "_GYcZ_HByN4U"
@@ -661,6 +675,15 @@
661675
"print(f\"Test acc: {model.evaluate(int_test_ds)[1]:.3f}\")"
662676
]
663677
},
678+
{
679+
"cell_type": "markdown",
680+
"source": [
681+
"This time we get to <font color='blue'>88%</font> test accuracy—a small but noticeable improvement."
682+
],
683+
"metadata": {
684+
"id": "4ddOdbTRKmC9"
685+
}
686+
},
664687
{
665688
"cell_type": "markdown",
666689
"metadata": {
@@ -670,6 +693,27 @@
670693
"#### Using pretrained word embeddings"
671694
]
672695
},
696+
{
697+
"cell_type": "markdown",
698+
"source": [
699+
"Sometimes you have so little training data available that you can't use your data alone to learn an appropriate task-specific embedding of your vocabulary. In such cases, instead of learning word embeddings jointly with the problem you want to solve, you can <font color='blue'>load embedding vectors</font> from a <font color='blue'>precomputed embedding space</font> that you know is highly structured and exhibits useful properties—one that captures generic aspects of language structure. The rationale behind using pretrained word embeddings in natural language processing is much the same as for using pretrained convnets in image classification: you don't have enough data available to learn truly powerful features on your own, but you <font color='blue'>expect</font> that the <font color='blue'>features</font> you need are fairly <font color='blue'>generic</font>—that is, common visual features or semantic features. In this case, it makes sense to <font color='blue'>reuse</font> features learned on a different problem.\n",
700+
"\n",
701+
"Such word embeddings are generally computed using <font color='blue'>word-occurrence</font> statistics (observations about what words co-occur in sentences or documents), using a variety of techniques, some involving neural networks, others not. The idea of a <font color='blue'>dense, low-dimensional</font> embedding space for words, computed in an <font color='blue'>unsupervised</font> way, was initially explored by <font color='blue'>Bengio et al.</font> in the early 2000s, but it only started to take off in research and industry applications after the release of one of the most famous and successful word-embedding schemes: the <font color='blue'>Word2Vec</font> algorithm (https://code.google.com/archive/p/word2vec), developed by Tomas Mikolov at Google in 2013. Word2Vec\n",
702+
"dimensions capture specific semantic properties, such as gender.\n",
703+
"\n",
704+
"There are various precomputed databases of word embeddings that you can down-\n",
705+
"load and use in a Keras *Embedding* layer. Word2vec is one of them. Another popular one is called <font color='blue'>Global Vectors for Word Representation</font> (GloVe, https://nlp.stanford.edu/projects/glove), which was developed by Stanford researchers in 2014. This\n",
706+
"embedding technique is based on factorizing a matrix of word co-occurrence statistics. Its developers have made available precomputed embeddings for millions of English tokens, obtained from Wikipedia data and Common Crawl data.\n",
707+
"\n",
708+
"Let's look at how you can get started using <font color='blue'>GloVe</font> embeddings in a Keras model. The same method is valid for Word2Vec embeddings or any other word-embedding database. We'll start by downloading the GloVe files and parse them. We'll then load the word vectors into a Keras Embedding layer, which we'll use to build a new model.\n",
709+
"\n",
710+
"First, let's download the GloVe word embeddings precomputed on the 2014\n",
711+
"English Wikipedia dataset. It's an 822 MB zip file containing 100-dimensional embedding vectors for 400,000 words (or non-word tokens)."
712+
],
713+
"metadata": {
714+
"id": "o_Fk0FChKxAU"
715+
}
716+
},
673717
{
674718
"cell_type": "code",
675719
"execution_count": null,
@@ -682,6 +726,15 @@
682726
"!unzip -q glove.6B.zip"
683727
]
684728
},
729+
{
730+
"cell_type": "markdown",
731+
"source": [
732+
"Let's parse the unzipped file (a .txt file) to build an <font color='blue'>index</font> that <font color='blue'>maps words</font> (as strings) to their <font color='blue'>vector</font> representation."
733+
],
734+
"metadata": {
735+
"id": "-L-N4516MgzO"
736+
}
737+
},
685738
{
686739
"cell_type": "markdown",
687740
"metadata": {
@@ -712,6 +765,15 @@
712765
"print(f\"Found {len(embeddings_index)} word vectors.\")"
713766
]
714767
},
768+
{
769+
"cell_type": "markdown",
770+
"source": [
771+
"Next, let's build an embedding matrix that you can load into an *Embedding* layer. It must be a matrix of shape `(max_words, embedding_dim)`, where each entry `i` contains the `embedding_dim`-dimensional vector for the word of index `i` in the reference word index (built during tokenization)."
772+
],
773+
"metadata": {
774+
"id": "TJKhaPdMM8li"
775+
}
776+
},
715777
{
716778
"cell_type": "markdown",
717779
"metadata": {
@@ -731,17 +793,26 @@
731793
"source": [
732794
"embedding_dim = 100\n",
733795
"\n",
734-
"vocabulary = text_vectorization.get_vocabulary()\n",
735-
"word_index = dict(zip(vocabulary, range(len(vocabulary))))\n",
796+
"vocabulary = text_vectorization.get_vocabulary() # Retrieve the vocabulary indexed by our previous TextVectorization layer.\n",
797+
"word_index = dict(zip(vocabulary, range(len(vocabulary)))) # Use it to create a mapping from words to their index in the vocabulary.\n",
736798
"\n",
737-
"embedding_matrix = np.zeros((max_tokens, embedding_dim))\n",
799+
"embedding_matrix = np.zeros((max_tokens, embedding_dim)) # Prepare a matrix that we’ll fill with the GloVe vectors.\n",
738800
"for word, i in word_index.items():\n",
739-
" if i < max_tokens:\n",
740-
" embedding_vector = embeddings_index.get(word)\n",
801+
" if i < max_tokens: # Fill entry i in the matrix with the word vector for index i. Words\n",
802+
" embedding_vector = embeddings_index.get(word) # not found in the embedding index will be all zeros.\n",
741803
" if embedding_vector is not None:\n",
742804
" embedding_matrix[i] = embedding_vector"
743805
]
744806
},
807+
{
808+
"cell_type": "markdown",
809+
"source": [
810+
"Finally, we use a <font color='blue'>Constant</font> initializer to <font color='blue'>load</font> the <font color='blue'>pretrained embeddings</font> in an *Embedding* layer. So as not to disrupt the pretrained representations during training, we <font color='blue'>freeze</font> the layer via `trainable=False`:"
811+
],
812+
"metadata": {
813+
"id": "GJZ3pbusNu2E"
814+
}
815+
},
745816
{
746817
"cell_type": "code",
747818
"execution_count": null,
@@ -759,6 +830,15 @@
759830
")"
760831
]
761832
},
833+
{
834+
"cell_type": "markdown",
835+
"source": [
836+
"We're now ready to train a new model—identical to our previous model, but leveraging the 100-dimensional pretrained GloVe embeddings instead of 128-dimensional learned embeddings."
837+
],
838+
"metadata": {
839+
"id": "EhOa_ki_N4CR"
840+
}
841+
},
762842
{
763843
"cell_type": "markdown",
764844
"metadata": {
@@ -795,6 +875,24 @@
795875
"model = keras.models.load_model(\"glove_embeddings_sequence_model.keras\")\n",
796876
"print(f\"Test acc: {model.evaluate(int_test_ds)[1]:.3f}\")"
797877
]
878+
},
879+
{
880+
"cell_type": "markdown",
881+
"source": [
882+
"You'll find that on this particular task, pretrained embeddings aren't very helpful, because the dataset contains <font color='blue'>enough samples</font> that it is possible to <font color='blue'>learn</font> a specialized enough <font color='blue'>embedding space</font> from <font color='blue'>scratch</font>. However, leveraging pretrained embeddings can be very helpful when you're working with a smaller dataset."
883+
],
884+
"metadata": {
885+
"id": "8u-zMJBxOApe"
886+
}
887+
},
888+
{
889+
"cell_type": "code",
890+
"source": [],
891+
"metadata": {
892+
"id": "Ns3vzk-XOFGf"
893+
},
894+
"execution_count": null,
895+
"outputs": []
798896
}
799897
],
800898
"metadata": {

0 commit comments

Comments
 (0)