在前面内容的学习中,笔者采用的是标准化的深度学习流程,即数据的准备、处理,数据的输入与计算,以及最后结果的打印。虽然在真实情况中可能会遇到各种各样的问题,但是基本步骤不会变。
一个非常重要的问题是,在模型的计算过程中遇到多个数据输入端应该怎么处理(见图3.8)。
图3.8 多个数据输入端
以Tensor格式的数据为例,在数据的转化部分就需要将数据进行“打包”处理,即将不同的数据按类型进行打包,如下所示。
输入1,输入2,输入3,标签 -> (输入1,输入2,输入3),标签
注意小括号的位置,将数据分成2个部分,即“输入”与“标注”两类。多输入的部分使用小括号打包在一起,形成一个整体。
下面还是以iris数据集为例讲解多数据输入的问题。
从前面的介绍可以知道,iris数据集每行是由一个4个特征组合在一起表示的特征集合,此时可以人为地将其切分,即将长度为4的特征转化成一个长度为3和一个长度为1的两个特征集合。代码如下:
import tensorflow as tf import numpy as np from sklearn.datasets import load_iris data = load_iris() iris_data = np.float32(data.data) iris_data_1 = [] iris_data_2 = [] for iris in iris_data: iris_data_1.append(iris[0]) iris_data_2.append(iris[1:4])
打印其中的一条:
可以看到,一行4列的数据被拆分成2组特征。
数据被人为地拆分成2个部分,因此在模型的输入端也要能够处理2组数据的输入问题。
input_xs_1 = tf.keras.Input(shape=(1,), name='input_xs_1') input_xs_2 = tf.keras.Input(shape=(3,), name='input_xs_2') input_xs = tf.concat([input_xs_1,input_xs_2],axis=-1)
上述代码先用input_xs_1和input_xs_2作为数据的接收端接受传递进来的数据,之后通过一个concat重新将数据组合,恢复成一条4特征的集合。
out = tf.keras.layers.Dense(32, activation='relu', name='dense_1')(input_xs) out = tf.keras.layers.Dense(64, activation='relu', name='dense_2')(out) logits = tf.keras.layers.Dense(3, activation="softmax",name='predictions')(out) model = tf.keras.Model(inputs=[input_xs_1,input_xs_2], outputs=logits)
剩余部分没有变化,按照前面的程序处理即可。
切分后的数据需要重新组合,生成能够符合模型需求的Tensor数据。这里最为关键的是在模型中对输入输出格式的定义。把模型的输入输出格式拆分为:
input = 【输入1,输入2】,outputs = 输出 #请注意模型中的中括号
因此,在Tensor建立的过程中也要按照模型输入的格式创建对应的数据集,格式如下:
((输入1,输入2),输出)
注意,这里采用2层括号对数据进行打包,即首先将“输入1”和“输入2”打包成一个输入数据,之后重新打包“输出”共同组成一个数据集。转化Tensor数据的代码如下:
train_data = tf.data.Dataset.from_tensor_slices(((iris_data_1,iris_data_2),iris_target)).ba tch(128)
一定要注意小括号的层数。
完整的代码如下所示。
【程序3-6】
该程序的运行结果如图3.9所示。
图3.9 程序3-6的运行结果
其实对于认真阅读本书的读者来说,上面的打印输出结果应该见过很多次了,在这里TensorFlow 2.0默认输出了每个循环结束后的损失值,并且按compile函数中设定的内容输出准确率(Accuracy)值。最后的evaluate函数通过对测试集中的数据进行重新计算来获取损失值和准确率。本例使用训练数据代替测试数据。
在程序3-6中数据的准备是使用tf.data API来完成的,即通过打包的方式将数据输出,也可以直接将输出输入到模型中进行训练。代码如下所示。
【程序3-7】
import tensorflow as tf import numpy as np from sklearn.datasets import load_iris data = load_iris() iris_data = np.float32(data.data) iris_data_1 = [] iris_data_2 = [] for iris in iris_data: iris_data_1.append(iris[0]) iris_data_2.append(iris[1:4]) iris_target = np.float32(tf.keras.utils.to_categorical(data.target,num_classes=3)) input_xs_1 = tf.keras.Input(shape=(1,), name='input_xs_1') input_xs_2 = tf.keras.Input(shape=(3,), name='input_xs_2') input_xs = tf.concat([input_xs_1,input_xs_2],axis=-1) out = tf.keras.layers.Dense(32, activation='relu', name='dense_1')(input_xs) out = tf.keras.layers.Dense(64, activation='relu', name='dense_2')(out) logits = tf.keras.layers.Dense(3, activation="softmax",name='predictions')(out) model = tf.keras.Model(inputs=[input_xs_1,input_xs_2], outputs=logits) opt = tf.optimizers.Adam(1e-3) model.compile(optimizer=tf.optimizers.Adam(1e-3), loss=tf.losses.categorical_crossentropy,metrics = ['accuracy']) model.fit(x = ([iris_data_1,iris_data_2]),y=iris_target,batch_size=128, epochs=500) score = model.evaluate(x=([iris_data_1,iris_data_2]),y=iris_target) print("多头score:",score)
该程序的运行结果请读者自行验证,需要注意的是其中数据的打包情况。