10、模型概览与一个实例
一、模型概览
#基本概念
#0Keras 有两个重要的概念: 模型(Model) 和 层(Layer)
#1层将各种计算流程和变量进行了封装(例如基本的全连接层,CNN 的卷积层、池化层等)
#2模型则将各种层进行组织和连接,并封装成一个整体,描述了如何将输入数据通过各种层以及运算而得到输出。
#3Keras 在 tf.keras.layers 下内置了深度学习中大量常用的的预定义层,同时也允许我们自定义层。
#4Keras 模型以类的形式呈现,我们可以通过继承 tf.keras.Model 这个 Python 类来定义自己的模型。
#5在继承类中,我们需要重写 init() (构造函数,初始化)和 call(input) (模型调用)两个方法,同时也可以根据需要增加自> 定义的方法。
class MyModel(tf.keras.Model):
def __init__(self):
super().__init__() # Python 2 下使用 super(MyModel, self).__init__()
# 此处添加初始化代码(包含 call 方法中会用到的层),例如
# layer1 = tf.keras.layers.BuiltInLayer(...)
# layer2 = MyCustomLayer(...)
def call(self, input):
# 此处添加模型调用的代码(处理输入并返回输出),例如
# x = layer1(input)
# output = layer2(x)
return output
# 还可以添加自定义的方法
模型图示例子:
import tensorflow as tf
X = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
y = tf.constant([[10.0], [20.0]])
class Linear(tf.keras.Model):
def __init__(self):
super().__init__()
self.dense = tf.keras.layers.Dense(
units=1,
activation=None,
kernel_initializer=tf.zeros_initializer(),
bias_initializer=tf.zeros_initializer()
)
def call(self, input):
output = self.dense(input)
return output
# 以下代码结构与前节类似
model = Linear()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
for i in range(100):
with tf.GradientTape() as tape:
y_pred = model(X) # 调用模型 y_pred = model(X) 而不是显式写出 y_pred = a * X + b
loss = tf.reduce_mean(tf.square(y_pred - y))
grads = tape.gradient(loss, model.variables) # 使用 model.variables 这一属性直接获得模型中的所有变量
optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
print(model.variables)
1、我们没有显式地声明 a 和 b 两个变量并写出 y_pred = a X + b 这一线性变换,而是建立了一个继承了 tf.keras.Model 的模型类 Linear 。这个类在初始化部分实例化了一个 *全连接层 ( tf.keras.layers.Dense ),并在 call 方法中对这个层进行调用,实现了线性变换的计算。
2、Keras 的全连接层:线性变换 + 激活函数
全连接层 主要参数3、为什么模型类是重载 call() 方法而不是 call() 方法?
在 Python 中,对类的实例 myClass 进行形如 myClass() 的调用等价于 myClass.call() (具体请见本章初 “前置知识” 的 call() 部分)。那么看起来,为了使用 ypred = model(X) 的形式调用模型类,应该重写 call() 方法才对呀?原因是 Keras 在模型调用的前后还需要有一些自己的内部操作,所以暴露出一个专门用于重载的 call() 方法。 tf.keras.Model 这一父类已经包含 call() 的定义。 _call() 中主要调用了 call() 方法,同时还需要在进行一些 keras 的内部操作。这里,我们通过继承 tf.keras.Model 并重载 call() 方法,即可在保持 keras 结构的同时加入模型调用的代码。
二、一个实例:使用多层感知机完成 MNIST 手写体数字图片数据集 [LeCun1998] 的分类任务。
模型的构建: tf.keras.Model 和 tf.keras.layers
多层感知机的模型类实现与上面的线性模型类似,使用 tf.keras.Model 和 tf.keras.layers 构建,所不同的地方在于层数增加了(顾名思义,“多层” 感知机),以及引入了非线性激活函数(这里使用了 ReLU 函数 , 即下方的 activation=tf.nn.relu )。该模型输入一个向量(比如这里是拉直的 1×784 手写体数字图片),输出 10 维的向量,分别代表这张图片属于 0 到 9 的概率。
代码主要分为几个部分:
1、引入/导入包
2、定义训练数据处理
3、定义模型
4、进行训练
5、评估结果
代码如下:它跑成功了呀~~~
10 import tensorflow as tf
11import numpy as np
12
13 class MNISTLoader():
14 def __init__(self):
15 mnist = tf.keras.datasets.mnist
16 (self.train_data, self.train_label), (self.test_data, self.test_label) = mnist.load_data()
17 # MNIST中的图像默认为uint8(0-255的数字)。以下代码将其归一化到0-1之间的浮点数,并在最后增加一维作为颜色通道
18 self.train_data = np.expand_dims(self.train_data.astype(np.float32) /255.0, axis=-1) # [60000, 28, 28, 1]
19 self.test_data = np.expand_dims(self.test_data.astype(np.float32) /255.0, axis=-1) # [10000, 28, 28, 1]
20 self.train_label = self.train_label.astype(np.int32) # [60000]
21 self.test_label = self.test_label.astype(np.int32) # [10000]
22 self.num_train_data, self.num_test_data = self.train_data.shape[0], self.test_data.shape[0]
23
24 def get_batch(self, batch_size):
25 # 从数据集中随机取出batch_size个元素并返回
26 index = np.random.randint(0, np.shape(self.train_data)[0], batch_size)
27 return self.train_data[index, :], self.train_label[index]
28
29 class MLP(tf.keras.Model):
30 def __init__(self):
31 super().__init__()
32 self.flatten = tf.keras.layers.Flatten() # Flatten层将除第一维(batch_size)以外的维度展平
33 self.dense1 = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)
34 self.dense2 = tf.keras.layers.Dense(units=10)
35
36 def call(self, inputs): # [batch_size, 28, 28, 1]
37 x = self.flatten(inputs) # [batch_size, 784]
38 x = self.dense1(x) # [batch_size, 100]
39 x = self.dense2(x) # [batch_size, 10]
40 output = tf.nn.softmax(x)
41 return output
42
43num_epochs = 5
44batch_size = 50
45learning_rate = 0.001
46
47model = MLP()
48data_loader = MNISTLoader()
49optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
50
51num_batches = int(data_loader.num_train_data // batch_size * num_epochs)
52 for batch_index in range(num_batches):
53 X, y = data_loader.get_batch(batch_size)
54 with tf.GradientTape() as tape:
55 y_pred = model(X)
56 loss = tf.keras.losses.sparse_categorical_crossentropy(y_true=y, y_pred=y_pred)
57 loss = tf.reduce_mean(loss)
58 print("batch %d: loss %f" % (batch_index, loss.numpy()))
59 grads = tape.gradient(loss, model.variables)
60 optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
61
62sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
63num_batches = int(data_loader.num_test_data // batch_size)
64 for batch_index in range(num_batches):
65 start_index, end_index = batch_index * batch_size, (batch_index +1) * batch_size
66 y_pred = model.predict(data_loader.test_data[start_index: end_index])
67 sparse_categorical_accuracy.update_state(y_true=data_loader.test_label[start_index: end_index], y_pred=y_pred)
68print("test accuracy: %f" % sparse_categorical_accuracy.result())
参考资料
1、简单粗暴 TensorFlow 2.0 模型(Model)与层(Layer)
https://www.bookstack.cn/read/TensorFlow2.0/spilt.1.c868281a01ad8ec0.md
2、简单粗暴 TensorFlow 2.0 基础示例:多层感知机(MLP)
https://www.bookstack.cn/read/TensorFlow2.0/spilt.2.c868281a01ad8ec0.md