文章目录
第3章 TensorFlow构建模型的方法
第2章我们用TensorFlow的自动微分及优化器等方法,实现了一个比较简单的回归问题。在本章,我们将继续对如何高效构建模型、训练模型做进一步的说明。根据构建模型的方式,本章将分为如下3种方法:
♦ 低阶API建模
♦ 中阶API建模
♦ 高阶API建模
3.1 利用低阶API构建模型
用TensorFlow低阶API构建模型主要包括张量操作、计算图及自动微分等操作,这种方法灵活性高,如果构建模型继承tf.Module,还可以轻松实现保存模型及跨平台部署。为提高模型运行效率,我们还可以使用@tf.function装饰相关函数,使之转换为自动图。为了更好地掌握本节的相关内容,这里以分类项目为例。
3.1.1 项目背景
这里以CIFAR-10为数据集,数据导入和预处理使用自定义函数,为更有效地处理数据,这里使用tf.data工具。有关tf.data的详细使用将在第4章将介绍,这里不再详述。构建模型只使用TensorFlow的低阶API,如tf.Variable、tf.nn.relu、自动微分等。然后自定义训练过程,最后保存和恢复模型。
CIFAR-10为小型数据集,一共包含10个类别的 RGB 彩色图像:飞机(airplane)、汽车(automobile)、鸟类(bird)、猫(cat)、鹿(deer)、狗(dog)、蛙类(frog)、马(horse)、船(ship)和卡车(truck)。图像的尺寸为 32×32(像素),3个通道 ,数据集中一共有 50000 张训练圄片和 10000 张测试图像。CIFAR-10数据集有3个版本,这里使用Python版本。
3.1.2 导入数据
1)导入需要的模块。
1 2 3 4 5 6 7 |
import os import math import numpy as np import pickle as p import tensorflow as tf import matplotlib.pyplot as plt %matplotlib inline |
2)定义导入单批次的函数。因数据源分成几个批次,这里定义一个导入各批次的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def load_CIFAR_batch(filename): """ 导入单批次的cifar数据 """ with open(filename, 'rb')as f: data_dict = p.load(f, encoding='bytes') images= data_dict[b'data'] labels = data_dict[b'labels'] # 把原始数据结构调整为: BCWH images = images.reshape(10000, 3, 32, 32) # tensorflow处理图像数据的结构:BWHC # 把通道数据C移动到最后一个维度 images = images.transpose (0,2,3,1) labels = np.array(labels) return images, labels |
3)导入整个数据集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
def load_CIFAR_data(data_dir): """导入CIFAR数据集""" images_train=[] labels_train=[] for i in range(5): f=os.path.join(data_dir,'data_batch_%d' % (i+1)) print('loading ',f) # 调用 load_CIFAR_batch( )获得批量的图像及其对应的标签 image_batch,label_batch=load_CIFAR_batch(f) images_train.append(image_batch) labels_train.append(label_batch) Xtrain=np.concatenate(images_train) Ytrain=np.concatenate(labels_train) del image_batch ,label_batch Xtest,Ytest=load_CIFAR_batch(os.path.join(data_dir,'test_batch')) print('finished loadding CIFAR-10 data') # 返回训练集的图像和标签,测试集的图像和标签 return (Xtrain,Ytrain),(Xtest,Ytest) |
4)指定数据文件所在路径。
1 2 |
data_dir = '../data/cifar-10-batches-py/' (x_train,y_train),(x_test,y_test) = load_CIFAR_data(data_dir) |
5)说明类别及对应索引,并随机可视化其中5张图像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
label_dict = {0:"airplane", 1:"automobile", 2:"bird", 3:"cat", 4:"deer", 5:"dog", 6:"frog", 7:"horse", 8:"ship", 9:"truck"} def plot_images_labels(images, labels, num): total = len(images) fig = plt.gcf() fig.set_size_inches(15, math.ceil(num / 10) * 7) for i in range(0, num): choose_n = np.random.randint(0, total) ax = plt.subplot(math.ceil(num / 5), 5, 1 + i) ax.imshow(images[choose_n], cmap='binary') title = label_dict[labels[choose_n]] ax.set_title(title, fontsize=10) plt.show() |
随机抽取CIFAR-10数据集中5张图的结果如图3-1所示。
图3-1 随机抽取CIFAR-10数据集中5张图
3.1.3 预处理数据
1)对数据进行简单处理。对数据进行规范化,并设计相关超参数等。
1 2 3 4 5 6 7 8 9 |
x_train = x_train.astype('float32') / 255.0 x_test = x_test.astype('float32') / 255.0 train_num = len(x_train) num_classes = 10 learning_rate = 0.0002 batch_size = 64 training_steps = 40000 display_step = 1000 |
2)使用TensorFlow的数据预处理工具tf.data,使预处理过程打包成为一个管道。
1 2 3 |
AUTOTUNE = tf.data.experimental.AUTOTUNE train_data = tf.data.Dataset.from_tensor_slices((x_train, y_train)) train_data = train_data.shuffle(5000).repeat(training_steps).batch(batch_size).prefetch(buffer_size=AUTOTUNE) |
dataset 中 shuffle()、repeat()、batch()、prefetch()等函数的主要功能如下。
1)repeat(count=None) 表示重复此数据集 count 次,实际上,我们看到 repeat 往往是接在 shuffle 后面的。为何要这么做,而不是反过来,先 repeat 再 shuffle 呢? 如果shuffle 在 repeat 之后,epoch 与 epoch 之间的边界就会模糊,出现未遍历完数据,已经计算过的数据又出现的情况。
2)shuffle(buffer_size, seed=None, reshuffle_each_iteration=None) 表示将数据打乱,数值越大,混乱程度越大。为了完全打乱,buffer_size 应等于数据集的数量。
3)batch(batch_size, drop_remainder=False) 表示按照顺序取出 batch_size 大小数据,最后一次输出可能小于batch ,如果程序指定了每次必须输入进批次的大小,那么应将drop_remainder 设置为 True 以防止产生较小的批次,默认为 False。
4)prefetch(buffer_size) 表示使用一个后台线程以及一个buffer来缓存batch,提前为模型的执行程序准备好数据。一般来说,buffer的大小应该至少和每一步训练消耗的batch数量一致,也就是 GPU/TPU 的数量。我们也可以使用AUTOTUNE来设置。创建一个Dataset便可从该数据集中预提取元素,注意:examples.prefetch(2) 表示将预取2个元素(2个示例),而examples.batch(20).prefetch(2) 表示将预取2个元素(2个批次,每个批次有20个示例),buffer_size 表示预提取时将缓冲的最大元素数返回 Dataset。
使用prefetch可以把数据处理与模型训练的交互方式由图3-2变为图3-3。
图3-2 未使用prefetch的数据处理流程
图3-3 使用prefetch后的数据处理流程
3.1.4 构建模型
使用tf.Module 封装变量及其计算,可以使用任何Python对象,有利于保存模型和跨平台部署使用。因此,可以基于TensorFlow开发任意机器学习模型(而非仅仅是神经网络模型),并实现跨平台部署使用。
1)构建模型。构建一个继承自tf.Module的模型,修改基类的构造函数,把需要初始化的变量放在__init__构造函数中,把参数变量的正向传播过程放在__call__方法中。__call__方法在模型实例化时,将自动调用。为提供更快的运行效率,通常用@tf.function进行装饰。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
random_normal = tf.initializers.RandomNormal() #继承tf.Module来构建模型变量 class NetModel(tf.Module): def __init__(self,name = None): super(NetModel, self).__init__(name=name) self.w1 = tf.Variable(random_normal([32*32*3, 256])) self.b1 = tf.Variable(tf.zeros([256])) self.w2 = tf.Variable(random_normal([256, 128])) self.b2 = tf.Variable(tf.zeros([128])) self.w3 = tf.Variable(random_normal([128, 64])) self.b3 = tf.Variable(tf.zeros([64])) self.wout=tf.Variable(random_normal([64, 10])) self.bout=tf.Variable(tf.zeros([10])) # 实现参数的正向传播,为加速训练,这里把动态图转换为AutoGraph @tf.function def __call__(self,x): x = tf.nn.relu(x@self.w1 + self.b1) x = tf.nn.relu(x@self.w2 + self.b2) x = tf.nn.relu(x@self.w3 + self.b3) y = tf.nn.softmax(x@self.wout + self.bout) return y model = NetModel() |
2)定义损失函数和评估函数。
1 2 3 4 5 6 7 8 9 10 |
def cross_entropy(y_pred, y_true): y_pred = tf.clip_by_value(y_pred, 1e-9, 1.) loss_ = tf.keras.losses.sparse_categorical_crossentropy(y_true=y_true, y_pred=y_pred) return tf.reduce_mean(loss_) def accuracy(y_pred, y_true): correct_prediction = tf.equal(tf.argmax(y_pred, 1), tf.reshape(tf.cast(y_true, tf.int64), [-1])) return tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) optimizer = tf.optimizers.Adam(learning_rate) |
3.1.5 训练模型
1)实现反向传播。这里使用自动微分机制,并使用优化器实现梯度的自动更新,具体过程如下:
• 打开一个 GradientTape() 作用域;
• 在此作用域内,调用模型(正向传播)并计算损失;
• 在作用域之外,检索模型权重相对于损失的梯度;
• 根据梯度使用优化器来更新模型的权重;
• 利用优化器进行反向传播(更新梯度)。
1 2 3 4 5 6 7 8 |
def run_optimization(x, y): with tf.GradientTape() as g: pred = model(x) loss = cross_entropy(pred, y) #自动微分,并自动实现参数的反向传播 gradients = g.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) |
2)定义训练过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
train_loss_list = [] train_acc_list = [] for step, (batch_x, batch_y) in enumerate(train_data.take(training_steps), 1): batch_x = tf.reshape(batch_x, [-1, 32 * 32 * 3]) run_optimization(batch_x, batch_y) if step % display_step == 0: pred = model(batch_x) loss = cross_entropy(pred, batch_y) acc = accuracy(pred, batch_y) train_loss_list.append(loss) train_acc_list.append(acc) print("step: %i, loss: %f, accuracy: %f" % (step, loss, acc)) |
这是最后6次的运行结果:
step: 35000, loss: 0.910988, accuracy: 0.734375
step: 36000, loss: 0.790101, accuracy: 0.765625
step: 37000, loss: 0.753428, accuracy: 0.750000
step: 38000, loss: 0.658011, accuracy: 0.781250
step: 39000, loss: 0.817612, accuracy: 0.718750
step: 40000, loss: 0.723336, accuracy: 0.718750
3)可视化运行过程。
1 2 3 4 5 6 7 |
plt.rcParams['font.sans-serif']=['SimHei'] plt.title('训练准确率') plt.xlabel('迭代次数') plt.ylabel('准确率') plt.plot(train_acc_list, color=(0, 0, 1), label='准确率') plt.legend(loc='best') plt.show() |
随着迭代次数增加,模型准确率的变化如图3-4所示。
图3-4 随着迭代次数增加,模型准确率的变化
3.1.6 测试模型
对模型进行测试。
1 2 3 4 5 6 7 8 9 10 11 |
test_total_batch = int(len(x_test) / batch_size) test_acc_sum = 0.0 for i in range(test_total_batch): test_image_batch = x_test[i*batch_size:(i+1)*batch_size] test_image_batch = tf.reshape(test_image_batch, [-1, 32 * 32 * 3]) test_label_batch = y_test[i*batch_size:(i+1)*batch_size] pred = model(test_image_batch) test_batch_acc = accuracy(pred,test_label_batch) test_acc_sum += test_batch_acc test_acc = float(test_acc_sum / test_total_batch) print("Test accuracy:{:.6f}".format(test_acc)) |
运行结果如下:
0.535256
构建模型只使用了全连接层,没有对网络进行优化,测试能达到这个效果也不错。后续我们将采用数据增强、卷积神经网络等方法进行优化。
3.1.7 保存恢复模型
1)保存模型。
1 |
tf.saved_model.save(model, 'model_path') |
2)恢复模型。
1 2 |
#加载模型,包括权重参数,但没有model中定义的函数 mymodel = tf.saved_model.load("model_path") |
3)利用恢复的模型进行测试。
1 2 3 4 5 6 7 8 9 10 11 |
test_total_batch = int(len(x_test) / batch_size) test_acc_sum = 0.0 for i in range(test_total_batch): test_image_batch = x_test[i*batch_size:(i+1)*batch_size] test_image_batch = tf.reshape(test_image_batch, [-1, 32 * 32 * 3]) test_label_batch = y_test[i*batch_size:(i+1)*batch_size] pred = mymodel(test_image_batch) test_batch_acc = accuracy(pred,test_label_batch) test_acc_sum += test_batch_acc test_acc = float(test_acc_sum / test_total_batch) print("Test accuracy:{:.6f}".format(test_acc)) |
运行结果如下:
0.535256
由结果可知,它与原模型的测试结果完全一样!
3.2 利用中阶API构建模型
用TensorFlow的中阶API构建模型,主要使用TensorFlow或tf.keras提供的各种模型层、损失函数、优化器、数据管道、特征列等,无须自己定义网络层、损失函数等。如果定制性要求不高,这将大大提高构建模型的效率。利用中阶API构建模型时需要继承tf.Module,它是各种模型层的基类。为更好地掌握相关内容,还是使用3.1节的数据集,架构相同,只是把定义层改为直接使用tf.keras提供的层、优化器、评估函数等。
利用中阶API构建模型的导入数据、预处理数据等部分,与3.1节的相应部分一样,这里不再赘述。下面主要介绍两种方法的不同之处。
3.2.1构建模型
用TensorFlow的中阶API构建模型,需要使用TensorFlow或tf.keras提供的各种模型层、损失函数、优化器、数据管道、特征列等,无须自己定义网络层、损失函数等。因数据为图像,这里使用全连接层,故第一层使用Flatten层,把数据展平。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
from tensorflow.keras import layers,losses,metrics,optimizers #继承tf.Module来构建模型变量 class NetModel(tf.Module): def __init__(self,name = None): super(NetModel, self).__init__(name=name) #定义网络层 self.flatten = tf.keras.layers.Flatten() self.dense1 = layers.Dense(256,activation = "relu") self.dense2 = layers.Dense(128,activation = "relu") self.dense3 = layers.Dense(64,activation = "relu") self.dense4 = layers.Dense(10) # 实现参数的正向传播,为加速训练,这里把动态图转换为AutoGraph @tf.function def __call__(self,x): x = self.flatten(x) x = self.dense1(x) x = self.dense2(x) x = self.dense3(x) x = self.dense4(x) y = tf.nn.softmax(x) return y model = NetModel() |
3.2.2创建损失评估函数
损失函数使用tf.keras.metrics.Mean类,评估函数使用tf.keras.metrics.SparseCategoricalAccuracy类,使用该类标签无须转换为独热编码。
1 2 3 4 5 6 7 8 9 10 |
# 选择优化器、损失函数和评估函数等 loss_object = tf.keras.losses.SparseCategoricalCrossentropy() 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') optimizer = tf.keras.optimizers.Adam(learning_rate) |
3.2.3训练模型
1)定义训练函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
def train_step(model,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(model,images, labels): predictions = model(images) t_loss = loss_object(labels, predictions) test_loss(t_loss) test_accuracy(labels, predictions) |
2)训练模型。
1 2 3 4 5 6 7 8 9 10 |
train_loss_list = [] train_acc_list = [] for step, (batch_x, batch_y) in enumerate(train_data.take(training_steps), 1): train_step(model,batch_x, batch_y) if(step % display_step == 0): train_loss_list.append(train_loss.result()) train_acc_list.append(train_accuracy.result()) template = 'train: step {}, Loss: {:.4}, Accuracy: {:.2%}' print(template.format(step+1,train_loss.result(), train_accuracy.result(),)) |
最后6次的运行结果:
train: step 45001, Loss: 1.279, Accuracy: 54.51%
train: step 46001, Loss: 1.276, Accuracy: 54.63%
train: step 47001, Loss: 1.272, Accuracy: 54.76%
train: step 48001, Loss: 1.269, Accuracy: 54.88%
train: step 49001, Loss: 1.266, Accuracy: 55.00%
train: step 50001, Loss: 1.263, Accuracy: 55.12%
3)可视化训练结果。
1 2 3 4 5 6 7 |
plt.rcParams['font.sans-serif']=['SimHei'] plt.title('训练准确率') plt.xlabel('迭代次数') plt.ylabel('准确率') plt.plot(train_acc_list, color=(0, 0, 1), label='准确率') plt.legend(loc='best') plt.show() |
使用中阶API构建模型的可视化结果如图3-5所示。
图3-5 使用中阶API构建模型的可视化结果
4)测试模型。
1 2 3 4 |
for step, (batch_x, batch_y) in enumerate(test_data.take(1), 1): test_step(model,batch_x, batch_y) template = ' Test Loss: {:.4}, Test Accuracy: {:.2%}' print(template.format(test_loss.result(),test_accuracy.result())) |
运行结果如下:
Test Loss: 1.385, Test Accuracy: 52.14%
利用中阶API构建模型、实现训练,比直接使用低阶API简化了不少,但编码量还是比较大,尤其是定义评估函数、训练过程等,接下来我们介绍一种更简单、高效的方法,即下节将介绍的利用高阶API构建模型。
3.3利用高阶API构建模型
TensorFlow的高阶API主要是指tf.keras.models提供的模型的类接口。目前tf.keras为官方推荐的高阶API。 使用ff.keras接口构建模型的方式有3种。
• 序列API(Sequential API)模式,把多个网络层的线性堆叠构建模型。
• 函数式API(Functional API)模式,可构建任意结构模型。
• 子类模型API(Model Subclassing API)模式,使用继承Model基类的子类模型可构建自定义模型。
这里先使用序列API按层顺序构建模型,其他模式构建模型将在第7章详细介绍。
导入与数据预处理过程与3.1节一样,这里不再赘述,具体请参考本书代码及数据部分。
3.3.1 构建模型
这里主要使用tf.keras.models及tf.keras.layers高阶类,构建模型采用序列API方法,这种方法就像搭积木一样,非常直观和简单。首先实例化Sequential类,然后需要使用add方法把各层按序叠加在一起,并基于优化器、损失函数等方法编译模型,最后输入数据训练模型。这个过程可用图3-6来直观描述。
图3-6 序列API构建模型流程图
导入需要的库,构建模型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from tensorflow.keras.models import Sequentia from tensorflow.keras.layers import Dense, Dropout, Flatten # 定义模型 model = Sequential() #把输入数据形状展平为(batch_size,32*32*3)格式 model.add(Flatten(input_shape = x_train.shape[1:])) model.add(Dense(256, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(128, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(64, activation='relu')) model.add(Dropout(0.2)) #输出类别个数为10,并使用softmax激活函数,获取各类的概率值 model.add(Dense(10, activation='softmax')) model.summary() |
显示模型各层及其结构,如图3-7所示。:
图3-7 显示模型各层及其结构
构建Sequential模型时,第一层需要知道输入数据的形状,其他各层只要指明输出形状即可,输入形状可自动推导。因此,Sequential的第一层需要接收一个关于输入数据形状(shape)的参数。那么,如何指定第一层的输入形状呢?有以下几种方法来为第一层指定输入数据的形状。
• 传递一个input_shape参数给第一层。它是一个表示形状的元组 (一个由整数或None组成的元组,其中 None表示可能为任何正整数)。在input_shape中不包含数据批次(batch)大小。
• 有些2维层,如全连接层(Dense),支持通过指定其输入维度input_dim来隐式指定输入数据的形状,input_dim是一个整数类型的数据。一些3维的时域层支持通过参数input_dim和input_length来指定输入shape。
• 对某些网络层,如果需要为输入指定一个固定大小的批量值(batch_size),可以传递batch_size参数到一个层中。例如你想指定输入张量的batch大小是32,数据shape是(6,8),则需要传递batch_size=32和input_shape=(6,8)给一个层,那么每一批输入的形状就为 (32,6,8)。
3.3.2 编译及训练模型
训练模型之前,需要对模型进行编译配置,这是通过compile方法完成的。它接收三个参数。
• 优化器(optimizer):可以是内置优化器的字符串标识符,如 rmsprop 或 adagrad,也可以是Optimizer类的对象。
• 损失函数(loss):模型最小化的目标函数。它可以是内置损失函数的字符串标识符,如 categorical_crossentropy 或 mse等,也可以是自定义的损失函数。
• 评估标准(metrics):可以是内置的标准字符串标识符,也可以是自定义的评估标准函数。对于分类问题,一般将评估标准设置为 metrics = ['accuracy']。
1)编译模型。
1 |
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy']) |
2)训练模型。这里采用回调机制定时保存模型。
1 2 3 4 5 |
from tensorflow.keras.callbacks import ModelCheckpoint checkpointer = ModelCheckpoint(filepath='MLP.best_weights.hdf5', verbose=1, save_best_only=True) hist = model.fit(x_train, y_train, batch_size=64, epochs=20,validation_data=(x_valid, y_valid), callbacks=[checkpointer], verbose=2, shuffle=True) |
最后两次的迭代结果:
Epoch 19/20
704/704 - 2s - loss: 1.6917 - accuracy: 0.3892 - val_loss: 1.6291 - val_accuracy: 0.4120
Epoch 00019: val_loss did not improve from 1.62898
Epoch 20/20
704/704 - 2s - loss: 1.6903 - accuracy: 0.3869 - val_loss: 1.6163 - val_accuracy: 0.4154
Epoch 00020: val_loss improved from 1.62898 to 1.61627, saving model to MLP.best_weights.hdf5
最后,根据模型训练的结果自动保存最好的那个模型。
3)可视化运行结果。
1 2 3 4 5 6 7 8 |
plt.rcParams['font.sans-serif']=['SimHei'] plt.title('训练与验证') plt.xlabel('迭代次数') plt.ylabel('损失值') plt.plot(hist.history['loss'], color=(1, 0, 0), label='训练损失值') plt.plot(hist.history['val_loss'], color=(0, 0, 1), label='验证损失值') plt.legend(loc='best') plt.show() |
使用高阶API构建模型的可视化结果如图3-8所示。
图3-8 使用高阶API的运行结果
3.3.3测试模型
输入如下代码测试模型。
1 2 |
mlp_score = model.evaluate(x_test, y_test, verbose=0) print('Test accuracy:{:.4f}'.format(mlp_score[1])) |
运行结果如下:
Test accuracy:0.4329
3.3.4 保存恢复模型
1)选择最好的模型参数恢复模型。
1 2 |
#重新创建完全相同的模型,包括其权重和优化程序 new_model = tf.keras.models.load_model('MLP.best_weights.hdf5') |
2)查看网络结构。
1 2 |
# 显示网络结构 new_model.summary() |
运行结果与图3-7的网络结构完全一致。
3)检查其准确率(accuracy)。
1 2 |
loss, acc = new_model.evaluate(x_test, y_test, verbose=2) print("Restored model, accuracy: {:5.2f}%".format(100*acc)) |
运行结果如下:
313/313 - 1s - loss: 1.6150 - accuracy: 0.4329
Restored model, accuracy: 43.29%
由结果可知,其结果与预测结果完全一致!
3.4 小结
本章介绍了用几种常用的API构建网络和训练模型的方法。这些API从封装程度来划分,可分为低阶API、中阶API和高阶API。低阶API基本用TensorFlow实现,自定义层、损失函数等;中阶API使用层模块(如tf.keras.layers.Dense)、内置的损失函数、优化器等构建模型;高阶API的封装程度最高,使用tf.keras构建模型、训练模型。这3种方法各有优缺点,低阶API代码量稍多一些,但定制能力较高,而用高阶API构建模型和训练模型的代码比较简洁,但定制能力稍弱。实际上,我们的大部分任务基本都可以用高阶API来实现,尤其对初学者,使用高阶API构建模型、训练模型是首选。