text: #%%
  from __future__ import absolute_import, division, print_function
  
  # TensorFlow and tf.keras
  import tensorflow as tf
  from tensorflow import keras
  
  # Helper libraries
  import numpy as np
  import matplotlib.pyplot as plt
  
  print(tf.__version__)
  
  #%%
  fashion_mnist = keras.datasets.fashion_mnist
  
  (train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
  
  #%%
  class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 
                 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
  
  #%% [markdown]
  # ## Preprocess the data
  # The data must be preprocessed before training the network. If you inspect the first image in the training set, you will see that the pixel values fall in the range of 0 to 255:
  #%%
  plt.figure()
  plt.imshow(train_images[0])
  plt.colorbar()
  plt.grid(False)
  plt.show()
  
  #%% [markdown]
  # We scale these values to a range of 0 to 1 before feeding to the neural network model. For this, we divide the values by 255. It's important that the training set and the testing set are preprocessed in the same way.
  
  #%%
  train_images = train_images / 255.0
  test_images = test_images / 255.0
  
  #%% [markdown]
  # Display the first 25 images from the training set and display the class name below each image. Verify that the data is in the correct format and we're ready to build and train the network.
  
  #%%
  plt.figure(figsize=(10,10))
  for i in range(25):
      plt.subplot(5,5,i+1)
      plt.xticks([])
      plt.yticks([])
      plt.grid(False)
      plt.imshow(train_images[i], cmap=plt.cm.binary)
      plt.xlabel(class_names[train_labels[i]])
  plt.show()
  
  #%% [markdown]
  # ## Build the model
  #%%
  model = keras.Sequential([
      keras.layers.Flatten(input_shape=(28, 28)),
      keras.layers.Dense(128, activation=tf.nn.relu),
      keras.layers.Dense(10, activation=tf.nn.softmax)
  ])
  
  #%% [markdown]
  #
  # The first layer in this network, tf.keras.layers.Flatten, transforms the format of the images from a 2d-array (of 28 by 28 pixels), to a 1d-array of 28 * 28 = 784 pixels. Think of this layer as unstacking rows of pixels in the image and lining them up. This layer has no parameters to learn; it only reformats the data.
  #
  # After the pixels are flattened, the network consists of a sequence of two tf.keras.layers.Dense layers. These are densely-connected, or fully-connected, neural layers. The first Dense layer has 128 nodes (or neurons). The second (and last) layer is a 10-node softmax layer—this returns an array of 10 probability scores that sum to 1. Each node contains a score that indicates the probability that the current image belongs to one of the 10 classes.
  
  #%%
  model.compile(optimizer='adam', 
                loss='sparse_categorical_crossentropy',
                metrics=['accuracy'])
  
  #%%
  model.fit(train_images, train_labels, epochs=5)
  
  #%%
  test_loss, test_acc = model.evaluate(test_images, test_labels)
  
  print('Test accuracy:', test_acc)
  
  #%% [markdown]
  # It turns out, the accuracy on the test dataset is a little less than the accuracy on the training dataset. This gap between training accuracy and test accuracy is an example of overfitting. Overfitting is when a machine learning model performs worse on new data than on their training data.
  
  #%% [markdown]
  # ## Make Prediction
  
  #%%
  predictions = model.predict(test_images)
  
  #%% [markdown]
  # A prediction is an array of 10 numbers. These describe the "confidence" of the model that the image corresponds to each of the 10 different articles of clothing. We can see which label has the highest confidence value:
  
  #%%
  np.argmax(predictions[0])
  
  #%% [markdown]
  # ## Plot
  
  #%%
  def plot_image(i, predictions_array, true_label, img):
    predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])
    
    plt.imshow(img, cmap=plt.cm.binary)
  
    predicted_label = np.argmax(predictions_array)
    if predicted_label == true_label:
      color = 'blue'
    else:
      color = 'red'
    
    plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
                                  100*np.max(predictions_array),
                                  class_names[true_label]),
                                  color=color)
  
  def plot_value_array(i, predictions_array, true_label):
    predictions_array, true_label = predictions_array[i], true_label[i]
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])
    thisplot = plt.bar(range(10), predictions_array, color="#777777")
    plt.ylim([0, 1]) 
    predicted_label = np.argmax(predictions_array)
   
    thisplot[predicted_label].set_color('red')
    thisplot[true_label].set_color('blue')
  
  #%% [markdown]
  # Let's look at the 0th image, predictions, and prediction array.
  
  #%%
  i = 0
  plt.figure(figsize=(6,3))
  plt.subplot(1,2,1)
  plot_image(i, predictions, test_labels, test_images)
  plt.subplot(1,2,2)
  plot_value_array(i, predictions,  test_labels)
  plt.show()
  
  #%% [markdown]
  # Let's plot several images with their predictions. Correct prediction labels are blue and incorrect prediction labels are red. The number gives the percent (out of 100) for the predicted label. Note that it can be wrong even when very confident.
  
  #%%
  # Plot the first X test images, their predicted label, and the true label
  # Color correct predictions in blue, incorrect predictions in red
  num_rows = 5
  num_cols = 3
  num_images = num_rows*num_cols
  plt.figure(figsize=(2*2*num_cols, 2*num_rows))
  for i in range(num_images):
    plt.subplot(num_rows, 2*num_cols, 2*i+1)
    plot_image(i, predictions, test_labels, test_images)
    plt.subplot(num_rows, 2*num_cols, 2*i+2)
    plot_value_array(i, predictions, test_labels)
  plt.show()
  
  #%% [markdown]
  # ## Predict
  # Finally, use the trained model to make a prediction about a single image
  
  #%%
  # Grab an image from the test dataset
  img = test_images[0]
  # Add the image to a batch where it's the only member.
  img = (np.expand_dims(img,0))
  print(img.shape)
  # Now the prediction
  predictions_single = model.predict(img)
  print(predictions_single)
  plot_value_array(0, predictions_single, test_labels)
  _ = plt.xticks(range(10), class_names, rotation=45)