In [1]:
import tensorflow as tf
from tensorflow.keras.layers import Dense, Flatten, Conv2D
from tensorflow.keras import Model
In [2]:
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
In [3]:
x_train.shape
Out[3]:
(60000, 28, 28)
In [4]:
# Add a channels dimension
# 多增加第4個 dimension:"channel"
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]
In [5]:
x_train.shape
Out[5]:
(60000, 28, 28, 1)
In [6]:
#== tf.data API 來建立 input pipeline ==#
#  * tf.data

#1."from_tensor_slices" 建立一個 Dataset Object
#  在使用"from_tensor_slices"參數(x_train, y_train)是
#  包含很多筆類型一樣的data,像這個例子有 60000筆data。
#  不要跟"from_tensor"搞混了!

#2.將training data做shuffle打亂 和 將batch size設定為 32
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(10000).batch(32)

test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_dataset = test_dataset.batch(32)
In [7]:
#== 使用 Keras 自訂一個 Model ==#
#  * tf.Keras.Model
#  * tf.Keras.layers

#1.建立一個 Class並繼承 tf.Keras.Model
#2.__init__裡面我們可以自己設計每一層 Layer長什麼樣子,
#  是哪種 Layer(Convolution, dense...)

#3.call定義了這個 Model的 forward pass

class MyModel(Model):
  def __init__(self):
    super(MyModel, self).__init__()    
    # Define your layers here.
    self.conv1 = Conv2D(32, 3, activation='relu')
    self.flatten = Flatten()
    self.d1 = Dense(128, activation='relu')
    self.d2 = Dense(10, activation='softmax')

  def call(self, x):
    # Define your forward pass here,
    # using layers you previously defined (in __init__).
    x = self.conv1(x)
    x = self.flatten(x)
    x = self.d1(x)
    return self.d2(x)

model = MyModel()
In [8]:
#== 選擇 loss, optimizer和 metrics ==#
#  * tf.keras.losses
#  * tf.keras.optimizers
#  * tf.keras.metrics


loss_object = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()

train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')

test_loss = tf.keras.metrics.Mean(name='test_loss')
test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='test_accuracy')
In [9]:
#== train the model (定義)==#
#  * tf.function
#  * tf.GradientTape

@tf.function
def train_step(images, labels):
    
    #
    with tf.GradientTape() as tape:
        # forward pass to get predictions
        predictions = model(images)
        # compute loss with the ground and our predictions
        loss = loss_object(labels, predictions)
    # compute gradient 
    gradients = tape.gradient(loss, model.trainable_variables)
    # back propagation
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

    train_loss(loss)
    train_accuracy(labels, predictions)
In [10]:
#== test the model (定義)==#
#  * tf.function

@tf.function
def test_step(images, labels):
    
    # forward pass to get predictions
    predictions = model(images)
    # compute loss with the ground and our predictions
    t_loss = loss_object(labels, predictions)

    test_loss(t_loss)
    test_accuracy(labels, predictions)
In [11]:
#== 真正開始 train model ==#

# 定義EPOCH數(整個dataset 拿來train過一次稱一個epoch)
EPOCH = 5
for epoch in range(EPOCH):
    for images, labels in train_dataset:
        train_step(images, labels)

    for test_images, test_labels in test_dataset:
        test_step(test_images, test_labels)    
    
    template = 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}\n'
    print(template.format(epoch+1,
                          train_loss.result(),
                          train_accuracy.result()*100,
                          test_loss.result(),
                          test_accuracy.result()*100))

    # Reset the metrics for the next epoch
    train_loss.reset_states()
    train_accuracy.reset_states()
    test_loss.reset_states()
    test_accuracy.reset_states()
WARNING: Logging before flag parsing goes to stderr.
W0908 04:30:25.684524 139914416629568 base_layer.py:1772] Layer my_model is casting an input tensor from dtype float64 to the layer's dtype of float32, which is new behavior in TensorFlow 2.  The layer has dtype float32 because it's dtype defaults to floatx.

If you intended to run this layer in float32, you can safely ignore this warning. If in doubt, this warning is likely only an issue if you are porting a TensorFlow 1.X model to TensorFlow 2.

To change all layers to have dtype float64 by default, call `tf.keras.backend.set_floatx('float64')`. To change just this layer, pass dtype='float64' to the layer constructor. If you are the author of this layer, you can disable autocasting by passing autocast=False to the base Layer constructor.

Epoch 1, Loss: 0.13473506271839142, Accuracy: 95.97666931152344, Test Loss: 0.06092844903469086, Test Accuracy: 98.11000061035156

Epoch 2, Loss: 0.03951505571603775, Accuracy: 98.75333404541016, Test Loss: 0.054404206573963165, Test Accuracy: 98.29000091552734

Epoch 3, Loss: 0.02091340534389019, Accuracy: 99.33333587646484, Test Loss: 0.05234690383076668, Test Accuracy: 98.37999725341797

Epoch 4, Loss: 0.012101341038942337, Accuracy: 99.59666442871094, Test Loss: 0.05848024785518646, Test Accuracy: 98.3499984741211

Epoch 5, Loss: 0.010396501049399376, Accuracy: 99.6500015258789, Test Loss: 0.05654916912317276, Test Accuracy: 98.43000030517578