Repository: d2l-ai/d2l-en

Issue:
show_image method will return an error may be a bug
In TensorFlow
`
TypeError: Invalid shape (28, 28, 1) for image data
`

This error will come up when running the code `data.visualize()` in the notebook. 
show_image method will return an error may be a bug
In TensorFlow
`
TypeError: Invalid shape (28, 28, 1) for image data
`

This error will come up when running the code `data.visualize()` in the notebook. 


Discussion:
Thanks. Could you be more specific on which line of code in which notebook? Besides, please also share `pip show tensorflow` output so we know the version.
The error showed up in sections 4.2 and 4.3, which used the `visualize() `method. 

`pip show tensorflow` result 
![image](https://user-images.githubusercontent.com/50707331/184283866-123cad42-39e3-48a4-b248-881dc58ccb72.png)

This issue **only** happens with TensorFlow version, the PyTorch works just fine 
![image](https://user-images.githubusercontent.com/50707331/184283943-e28cdc07-598a-460f-9ba7-23f0df4d84fc.png)


Thanks @COD1995 for reporting the problem and filing the issue. It really helps us improve the book.

**Locally**

I'm using `tensorflow==2.9.1` as suggested in our [requirements](https://github.com/d2l-ai/d2l-en/blob/2f7c62cc1dc3f30a35a43a3e75c349d7782252f5/static/build.yml#L11), and everything works perfectly for that.

Just to be double sure, I also installed `tensorflow==2.8.2` to mimic your environment, and the code seems fine.

**Colab**

I was able to reproduce the problem when running on colab. Initially it seemed to be the version difference. But after further investigation, I found the root cause. `colab` is using `python 3.7` and installs fairly old libraries `numpy==1.21.6`, `matplotlib==3.2.2` whereas locally, I had the latest version of libraries (same as we set for d2l requirements).

---

Digging further, I found that a [silent squeeze was introduced](https://github.com/matplotlib/matplotlib/blob/5b5cc0ecda2c116db7d7866de4d87e635d71380d/lib/matplotlib/image.py#L704)  if the third dimension is 1 in the following PR:

https://github.com/matplotlib/matplotlib/pull/15090  (corresponding issue discussion https://github.com/matplotlib/matplotlib/issues/15089).

This is precisely the point of difference. This change was released in v3.3.0 (See release [notes](https://matplotlib.org/3.3.0/users/whats_new.html#imshow-now-coerces-3d-arrays-with-depth-1-to-2d).). I'm surprised that the matplotlib devs did not put this change in the [release highlights](https://github.com/matplotlib/matplotlib/releases/tag/v3.3.0).

---

Anyway, I'll send a fix for this now in the master branch. @COD1995 till then you could: 

Manually do the squeeze for the fix:
`d2l.show_images(tf.squeeze(X), nrows, ncols, titles=labels)`

or

Upgrade your `matplotlib` version: `pip install --upgrade matplotlib>=3.3`
Thanks. Could you be more specific on which line of code in which notebook? Besides, please also share `pip show tensorflow` output so we know the version.
The error showed up in sections 4.2 and 4.3, which used the `visualize() `method. 

`pip show tensorflow` result 
![image](https://user-images.githubusercontent.com/50707331/184283866-123cad42-39e3-48a4-b248-881dc58ccb72.png)

This issue **only** happens with TensorFlow version, the PyTorch works just fine 
![image](https://user-images.githubusercontent.com/50707331/184283943-e28cdc07-598a-460f-9ba7-23f0df4d84fc.png)


Thanks @COD1995 for reporting the problem and filing the issue. It really helps us improve the book.

**Locally**

I'm using `tensorflow==2.9.1` as suggested in our [requirements](https://github.com/d2l-ai/d2l-en/blob/2f7c62cc1dc3f30a35a43a3e75c349d7782252f5/static/build.yml#L11), and everything works perfectly for that.

Just to be double sure, I also installed `tensorflow==2.8.2` to mimic your environment, and the code seems fine.

**Colab**

I was able to reproduce the problem when running on colab. Initially it seemed to be the version difference. But after further investigation, I found the root cause. `colab` is using `python 3.7` and installs fairly old libraries `numpy==1.21.6`, `matplotlib==3.2.2` whereas locally, I had the latest version of libraries (same as we set for d2l requirements).

---

Digging further, I found that a [silent squeeze was introduced](https://github.com/matplotlib/matplotlib/blob/5b5cc0ecda2c116db7d7866de4d87e635d71380d/lib/matplotlib/image.py#L704)  if the third dimension is 1 in the following PR:

https://github.com/matplotlib/matplotlib/pull/15090  (corresponding issue discussion https://github.com/matplotlib/matplotlib/issues/15089).

This is precisely the point of difference. This change was released in v3.3.0 (See release [notes](https://matplotlib.org/3.3.0/users/whats_new.html#imshow-now-coerces-3d-arrays-with-depth-1-to-2d).). I'm surprised that the matplotlib devs did not put this change in the [release highlights](https://github.com/matplotlib/matplotlib/releases/tag/v3.3.0).

---

Anyway, I'll send a fix for this now in the master branch. @COD1995 till then you could: 

Manually do the squeeze for the fix:
`d2l.show_images(tf.squeeze(X), nrows, ncols, titles=labels)`

or

Upgrade your `matplotlib` version: `pip install --upgrade matplotlib>=3.3`

Resolving patch:
diff --git a/d2l/mxnet.py b/d2l/mxnet.py
--- a/d2l/mxnet.py
+++ b/d2l/mxnet.py
@@ -1436,7 +1436,7 @@ def evaluate_accuracy_gpus(net, data_iter, split_f=d2l.split_batch):
 
 def train_batch_ch13(net, features, labels, loss, trainer, devices,
                      split_f=d2l.split_batch):
-    """Train for a minibatch with mutiple GPUs (defined in Chapter 13).
+    """Train for a minibatch with multiple GPUs (defined in Chapter 13).
 
     Defined in :numref:`sec_image_augmentation`"""
     X_shards, y_shards = split_f(features, labels, devices)
@@ -1456,7 +1456,7 @@ def train_batch_ch13(net, features, labels, loss, trainer, devices,
 
 def train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,
                devices=d2l.try_all_gpus(), split_f=d2l.split_batch):
-    """Train a model with mutiple GPUs (defined in Chapter 13).
+    """Train a model with multiple GPUs (defined in Chapter 13).
 
     Defined in :numref:`sec_image_augmentation`"""
     timer, num_batches = d2l.Timer(), len(train_iter)
@@ -3275,7 +3275,10 @@ def predict_seq2seq(net, src_sentence, src_vocab, tgt_vocab, num_steps,
         if pred == tgt_vocab['<eos>']:
             break
         output_seq.append(pred)
-    return ' '.join(tgt_vocab.to_tokens(output_seq)), attention_weight_seq# Alias defined in config.ini
+    return ' '.join(tgt_vocab.to_tokens(output_seq)), attention_weight_seq
+
+
+# Alias defined in config.ini
 size = lambda a: a.size
 transpose = lambda a: a.T
 nn_Module = nn.Block
diff --git a/d2l/tensorflow.py b/d2l/tensorflow.py
--- a/d2l/tensorflow.py
+++ b/d2l/tensorflow.py
@@ -406,7 +406,7 @@ def visualize(self, batch, nrows=1, ncols=8, labels=[]):
         X, y = batch
         if not labels:
             labels = self.text_labels(y)
-        d2l.show_images(X, nrows, ncols, titles=labels)
+        d2l.show_images(tf.squeeze(X), nrows, ncols, titles=labels)
 
 def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5):
     """Plot a list of images.
@@ -1908,7 +1908,10 @@ def predict_seq2seq(net, src_sentence, src_vocab, tgt_vocab, num_steps,
         if pred == tgt_vocab['<eos>']:
             break
         output_seq.append(pred.numpy())
-    return ' '.join(tgt_vocab.to_tokens(tf.reshape(output_seq, shape = -1).numpy().tolist())), attention_weight_seq# Alias defined in config.ini
+    return ' '.join(tgt_vocab.to_tokens(tf.reshape(output_seq, shape = -1).numpy().tolist())), attention_weight_seq
+
+
+# Alias defined in config.ini
 size = lambda a: tf.size(a).numpy()
 
 reshape = tf.reshape
diff --git a/d2l/torch.py b/d2l/torch.py
--- a/d2l/torch.py
+++ b/d2l/torch.py
@@ -1425,7 +1425,7 @@ def resnet_block(in_channels, out_channels, num_residuals,
     return net
 
 def train_batch_ch13(net, X, y, loss, trainer, devices):
-    """Train for a minibatch with mutiple GPUs (defined in Chapter 13).
+    """Train for a minibatch with multiple GPUs (defined in Chapter 13).
 
     Defined in :numref:`sec_image_augmentation`"""
     if isinstance(X, list):
@@ -1446,7 +1446,7 @@ def train_batch_ch13(net, X, y, loss, trainer, devices):
 
 def train_ch13(net, train_iter, test_iter, loss, trainer, num_epochs,
                devices=d2l.try_all_gpus()):
-    """Train a model with mutiple GPUs (defined in Chapter 13).
+    """Train a model with multiple GPUs (defined in Chapter 13).
 
     Defined in :numref:`sec_image_augmentation`"""
     timer, num_batches = d2l.Timer(), len(train_iter)
@@ -1530,7 +1530,7 @@ def multibox_prior(data, sizes, ratios):
     # Generate all center points for the anchor boxes
     center_h = (torch.arange(in_height, device=device) + offset_h) * steps_h
     center_w = (torch.arange(in_width, device=device) + offset_w) * steps_w
-    shift_y, shift_x = torch.meshgrid(center_h, center_w)
+    shift_y, shift_x = torch.meshgrid(center_h, center_w, indexing='ij')
     shift_y, shift_x = shift_y.reshape(-1), shift_x.reshape(-1)
 
     # Generate `boxes_per_pixel` number of heights and widths that are later
@@ -3072,7 +3072,10 @@ def predict_seq2seq(net, src_sentence, src_vocab, tgt_vocab, num_steps,
         if pred == tgt_vocab['<eos>']:
             break
         output_seq.append(pred)
-    return ' '.join(tgt_vocab.to_tokens(output_seq)), attention_weight_seq# Alias defined in config.ini
+    return ' '.join(tgt_vocab.to_tokens(output_seq)), attention_weight_seq
+
+
+# Alias defined in config.ini
 nn_Module = nn.Module
 
 ones_like = torch.ones_like


Test patch: