Tensorflow2.0 正确的Python打开方式

浏览: 2314

Keras 作者 @François Chollet说:开发Keras的时候,我遵循一个关键原则,就是“逐步揭示复杂性”。开始可以很简单,也可以逐渐复杂化、应对更灵活的场景,只需要增量化的学习。就像在复杂地图里局部放大一样。本文将按照增量化学习的原则,帮助大家逐步揭示Tensorflow2.0版本的复杂性。

我们都知道,在 Tensorflow2.0 中模型构建方式主要有三种:

• Sequential API• Functional API• Subclassing

三种模型构建方法其复杂性以及对应的灵活性如下图所示:

同样的,在 Tensorflow2.0 中也有多种训练模型的方式,最简单的可以直接调用fit()train_on_batch()方法,如果仍然不够灵活,我们可以利用GradientTape()来自定义训练循环。

现在我们将上面两幅图正交后合并到一起,就可以形成如下图所示的二维的坐标轴。

上面这幅图信息量其实很大,横轴表示模型构建的 API, 从低级到高级,对应的复杂性由高到低;纵轴表示模型训练的API, 从低级到高级,对应的复杂由高到低。按照象限来划分的话,可以看到第一象限的复杂性是最低的,其次是2、4象限,复杂性最高的是第3象限,但是其灵活性也是最高的。

从这幅图我们观察到,在Tensorflow2.0中,我们可以灵活搭配使用模型构建 API 和模型训练 API。

•第一象限:高级API搭建模型+高级API训练模型•第二象限:低级API搭建模型+高级API训练模型•第三象限:低级API搭建模型+低级API训练模型•第四象限:高级API搭建模型+低级API训练模型

这一切都能够按照我们的预期正常工作,只取决于我们的需要。

在文章接下来的内容中,我们将在 Fashion-MNIST 数据集上演示对应四个象限不同复杂度的模型构建和训练方法。

准备工作

Fashion-MNIST是一个替代MNIST手写数字集的图像数据集。其涵盖了来自10种类别的共7万个不同商品的正面图片。可以用它来测试你的机器学习和深度学习算法性能。

为了方便后面的演示,我们先下载 Fashion-MNIST 数据集,进行预处理后,拆分为训练集和测试集。

    # !pip install -q -U tensorflow==2.0
    import tensorflow as tf
    import matplotlib.pyplot as plt

    # Load the fashion-mnist pre-shuffled train data and test data
    (x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
    plt.imshow(x_train[10])

    x_train, x_test = x_train / 255.0, x_test / 255.0
    x_train = x_train[..., tf.newaxis]
    x_test = x_test[..., tf.newaxis]
    print("x_train shape:", x_train.shape, "y_train shape:", y_train.shape)
      x_train shape: (60000, 28, 28, 1) y_train shape: (60000,)

      高级API搭建模型+高级API训练模型

      Sequential API 搭建的模型是layer-by-layer的,它是最简单的定义模型的方法,但是有几个不足:

      •不能够共享某一层•不能有多个分支•不能有多个输入

        # !pip install -q -U tensorflow==2.0
        import tensorflow as tf
        import matplotlib.pyplot as plt

        # Load the fashion-mnist pre-shuffled train data and test data
        (x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
        plt.imshow(x_train[10])

        x_train, x_test = x_train / 255.0, x_test / 255.0
        x_train = x_train[..., tf.newaxis]
        x_test = x_test[..., tf.newaxis]
        print("x_train shape:", x_train.shape, "y_train shape:", y_train.shape)

        使用 fit() 训练模型:

          model.compile(loss='sparse_categorical_crossentropy',
          optimizer='adam',
          metrics=['accuracy'])

          checkpointer = ModelCheckpoint(filepath='model.weights.best.hdf5', verbose = 1, save_best_only=True)
          model.fit(x_train,
          y_train,
          batch_size=32,
          epochs=10,
          validation_data=(x_valid, y_valid),
          callbacks=[checkpointer])

          低级API搭建模型+高级API训练模型

          模型子类化具有很多优势。它可以更容易地实施模型检查。我们可以通过断点调试的方式,在指定代码行停留,并检查模型的激活函数或 logit 函数。当然,灵活性也意味着更多的问题,需要我们掌握更多的知识。

          使用Subclass Model 训练模型:

            classFashionNet(Model):
            def __init__(self):
            super(FashionNet, self).__init__()
            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):
            x = self.conv1(x)
            x = self.flatten(x)
            x = self.d1(x)
            returnself.d2(x)

            使用 fit() 训练模型:

              model = FashionNet()
              model.build(input_shape=(None,28,28,1))

              model.compile(loss='sparse_categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

              checkpointer = ModelCheckpoint(filepath='model.weights.best.hdf5', verbose = 1, save_best_only=True)
              model.fit(x_train,
              y_train,
              batch_size=32,
              epochs=10,
              validation_data=(x_valid, y_valid),
              callbacks=[checkpointer])

              低级API搭建模型+低级API训练模型

              使用Subclass Model 训练模型:

                classFashionNet(Model):
                def __init__(self):
                super(FashionNet, self).__init__()
                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):
                x = self.conv1(x)
                x = self.flatten(x)
                x = self.d1(x)
                returnself.d2(x)

                使用 tf.GradientTape() 来训练模型:

                  train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train))
                  train_ds = train_ds.batch(batch_size=32)

                  test_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train))
                  test_ds = test_ds.batch(batch_size=32)

                  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')

                  def train_step(images, labels):
                  with tf.GradientTape() as tape:
                  predictions = model(images)
                  loss = loss_object(labels, predictions)
                  gradients = tape.gradient(loss, model.trainable_variables)
                  optimizer.apply_gradients(zip(gradients, model.trainable_variables))

                  train_loss(loss)
                  train_accuracy(labels, predictions)

                  def test_step(images, labels):
                  predictions = model(images)
                  t_loss = loss_object(labels, predictions)

                  test_loss(t_loss)
                  test_accuracy(labels, predictions)

                  EPOCHS = 5
                  for epoch in range(EPOCHS):
                  train_loss.reset_states()
                  train_accuracy.reset_states()
                  test_loss.reset_states()
                  test_accuracy.reset_states()

                  for images, labels in train_ds:
                  train_step(images, labels)

                  for test_images, test_labels in test_ds:
                  test_step(test_images, test_labels)

                  template= 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'
                  print(template.format(epoch+1,
                  train_loss.result(),
                  train_accuracy.result()*100,
                  test_loss.result(),
                  test_accuracy.result()*100))

                  高级API搭建模型+低级API训练模型

                  函数API是一种创建更灵活模型的方法。它可以处理非线性拓扑、具有共享层的模型和具有多个输入或输出的模型。函数式API有更强的功能

                  •定义更复杂的模型•支持多输入多输出模型•可以定义模型分支,比如 inception block , resnet block•方便layer共享

                    inputs = Input(shape=(28,28,1))

                    conv2d = Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')(inputs)
                    flat = Flatten()(conv2d)
                    dense = Dense(128, activation='relu')(flat)
                    outputs = Dense(10, activation='softmax')(dense)

                    model.summary()

                    如果我们想要更清晰地了解梯度和损失函数运行机制的话,你可以使用梯度带。这对研究学者尤其有用。通过梯度带,我们可以手动定义训练过程的每一步。

                    训练一个神经网络的基本步骤如下:

                    •正向传播•损失函数评估•反向传播•梯度下降

                    当你想要进一步了解神经网络训练的时候,梯度带就变得很有指导意义。如果你需要检查不同模型权重的损失值或者梯度矢量本身的话,你可以直接把它们打印出来。梯度带提供了很大的灵活性。但是正如子类化对比序列化一样,更好的灵活性也需要额外的代价。同 fit() 方法相比,我们在这里只需要手动定义一个训练循环。

                    使用 tf.GradientTape() 来训练模型:

                      train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train))
                      train_ds = train_ds.batch(batch_size=32)

                      test_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train))
                      test_ds = test_ds.batch(batch_size=32)

                      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')

                      def train_step(images, labels):
                      with tf.GradientTape() as tape:
                      predictions = model(images)
                      loss = loss_object(labels, predictions)
                      gradients = tape.gradient(loss, model.trainable_variables)
                      optimizer.apply_gradients(zip(gradients, model.trainable_variables))

                      train_loss(loss)
                      train_accuracy(labels, predictions)

                      def test_step(images, labels):
                      predictions = model(images)
                      t_loss = loss_object(labels, predictions)

                      test_loss(t_loss)
                      test_accuracy(labels, predictions)

                      EPOCHS = 5
                      for epoch in range(EPOCHS):
                      train_loss.reset_states()
                      train_accuracy.reset_states()
                      test_loss.reset_states()
                      test_accuracy.reset_states()

                      for images, labels in train_ds:
                      train_step(images, labels)

                      for test_images, test_labels in test_ds:
                      test_step(test_images, test_labels)

                      template= 'Epoch {}, Loss: {}, Accuracy: {}, Test Loss: {}, Test Accuracy: {}'
                      print(template.format(epoch+1,
                      train_loss.result(),
                      train_accuracy.result()*100,
                      test_loss.result(),
                      test_accuracy.result()*100))

                      总结

                      Tensorflow2.0 版本后,上手难度的确降低了很多, 正如 François Chollet 所说,一开始可以很简单,当我们需要处理更复杂的问题、应对更灵活的场景的时候,只需要增量化的学习。使我们很容易在灵活性和复杂性之间找到满意的折中方案。

                      推荐 0
                      本文由 ID王大伟 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
                      转载、引用前需联系作者,并署名作者且注明文章出处。
                      本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

                      0 个评论

                      要回复文章请先登录注册