神经网络不处理原始的数据,例文本文件、 JPEG图像文件、CSV文件。需要处理成矢量化表示或标准化的表示。
(1)文本文件:需要被读取为字符串张量,然后拆分成单次,最后单次需要索引并转换为整型张量。
(2)图像:需要解码为整数张量,然后将其转换为浮点并归一化为较小值(通常在0-1之间)
(3)CSV数据:将数字特征转换为浮点张量,对类特征进行索引并转换为整型张量。通常每个特征需要归一化为0均值和单位方差。
keras接受3种类型的输入:
(1)numpy数组: 如果你对数据不是特别多,内存能够满足,则选择这种方法。
(2)TensorFlow的Dataset对象: 这是一种高性能的选择,它更适合于内存不足且从磁盘胡分布式文件系统传输的数据集。
(3)python生成器: 产生批量的数据(keras.utils.Sequence类的自定义子类)
模型的输入数据必须是以上三种格式之一。
举例:加载Dataset对象形式的输入数据
如果你有大量的数据集,请考虑使用Dataset对象,因为它有以下优点:1)当GPU繁忙时,在cpu上异步处理数据,并将其缓冲到队列中。2)在GPU上预取数据以便在GPU处理完前一批数据后立即可用,可以充分利用GPU的资源。
keras具有一系列工具,可以将磁盘上的原始数据转换为Dataset对象:
tf.keras.preprocessing.image_dataset_from_directory:将分类到特定于类的文件夹中的图像转换为带标签的图像张量数据集。
tf.keras.preprocessing.text_dataset_from_directory:同上作用,只不过对象是文本文件
tf.data.experimental.make_csv_dataset:从CSV文件加载结构化数据
原图像数据: 磁盘上的图像文件数据,其中不同的文件夹包含不同类别的图像数据。(每一个文件夹包好指定一个类别的图像)
执行以下操作: 获得批量组成的数据集对象。数据为图像,标签为图像对应的文件夹的索引。例class_names=[‘class_a’, ‘class_b’],在这种情况下,标签0为class_a和 1将为class_b。
# 创建一个Dataset对象
dataset = keras.preprocessing.image_dataset_from_directory(
'path/to/main_directory', batch_size=64, image_size=(200, 200))
#为了演示,对数据集产生的批次进行迭代。
for data, labels in dataset:
print(data.shape) # (64, 200, 200, 3)
print(data.dtype) # float32
print(labels.shape) # (64,)
print(labels.dtype) # int32
一旦加载好数据(numpy数组、Dataset对象、Python生成器),就可以对数据进行预处理。例:
(1)字符串数据的标记化,然后进行标记索引。
(2)特征规范化
(3)将数据重新缩放为较小的值(通常我们希望数据有0均值和单位方差,或数据在[0-1]范围)。
理想的机器学习模型是端到端的:
通常应该尽可能地将数据作为模型的一部分进行预处理,而不是通过外部数据预处理管道进行。理想模型期望输入的内容尽可能接近原始数据:图像模型应该期望RGB像素值在[0, 255] 范围内,而文本模型应该接受字符串utf-8。这样模型的使用者就不必了解预处理管道。直接便可以使用。
keras预处理层:
(1)TextVectorization层。矢量化文本原始字符串,将单词映射到整数索引。
(2)Normalization层。进行特征规范化。保证特征的均值和方差
(3)图像调整尺寸、裁剪或图像数据增强层。
使用keras预处理层的优点主要是,可以在训练过程中或训练后将他们直接包含在模型中,从而使模型可移植。预处理层的状态是通过在训练数据样本上调用layer.adapt(data)获得的。
例1: 将字符串转换为整数单词索引序列
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization
# 示例训练数据, 类型为 `string`.
training_data = np.array([["This is the 1st sample."], ["And here's the 2nd sample."]])
# 创建一个 TextVectorization 层的实例。可以配置为返回整型索引或密集表示 (e.g. multi-hot or TF-IDF).
vectorizer = TextVectorization(output_mode="int")
#在数组或dataset对象上调用`adapt`
vectorizer.adapt(training_data)
# 调用Adapt之后,该层能够对在adapt()数据中之前看到的任何n-gram进行编码。
integer_data = vectorizer(training_data)
print(integer_data)
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization
# 示例训练数据, 类型为 `string`.
training_data = np.array([["This is the 1st sample."], ["And here's the 2nd sample."]])
## 创建一个 TextVectorization 层的实例。可以配置为返回整型索引或密集表示 (e.g. multi-hot or TF-IDF).
vectorizer = TextVectorization(output_mode="binary", ngrams=2)
# 在数组或dataset对象上调用`adapt`让层产生 使该层为数据生成词汇索引,然后在查看新数据时可以重用该索引。
vectorizer.adapt(training_data)
# 调用Adapt之后,该层能够对在adapt()数据中之前看到的任何n-gram进行编码。
integer_data = vectorizer(training_data)
print(integer_data)
from tensorflow.keras.layers.experimental.preprocessing import Normalization
# 示例图像数据,值在 [0, 255] 范围
training_data = np.random.randint(0, 256, size=(64, 200, 200, 3)).astype("float32")
normalizer = Normalization(axis=-1)
normalizer.adapt(training_data)
normalized_data = normalizer(training_data)
print("var: %.4f" % np.var(normalized_data))
print("mean: %.4f" % np.mean(normalized_data))
Rescaling层与CenterCrop层是无状态的,不需要调用adapt()
from tensorflow.keras.layers.experimental.preprocessing import CenterCrop
from tensorflow.keras.layers.experimental.preprocessing import Rescaling
# 示例图像数据,值在 [0, 255] 范围
training_data = np.random.randint(0, 256, size=(64, 200, 200, 3)).astype("float32")
cropper = CenterCrop(height=150, width=150)
scaler = Rescaling(scale=1.0 / 255)
output_data = scaler(cropper(training_data))
print("shape:", output_data.shape)
print("min:", np.min(output_data))
print("max:", np.max(output_data))
层: 是简单的输入-输出的转换(例如上面的缩放和中心裁剪转换、规范化层…)
模型: 是层的有向无环图,可以将模型视为包含多个子层的更大层,通过传入数据进行训练。
构建模型最常见、最强大的方法是Functional API,使用Functional API
(1)首先定义输入的形状(以及可选的dtype)。如果输入的任何维度可以变换,则可以将其指定为None。
#(1)定义输入
inputs = keras.Input(shape=(None, None, 3))
(2)定义完输入后,构建模型的各个网络层:
from tensorflow.keras import layers
#(2)构建层
# 中心裁剪层,图像至150x150
x = CenterCrop(height=150, width=150)(inputs)
# 缩放层 [0, 1]
x = Rescaling(scale=1.0 / 255)(x)
# 卷积层和池化层
x = layers.Conv2D(filters=32, kernel_size=(3, 3), activation="relu")(x)
x = layers.MaxPooling2D(pool_size=(3, 3))(x)
x = layers.Conv2D(filters=32, kernel_size=(3, 3), activation="relu")(x)
x = layers.MaxPooling2D(pool_size=(3, 3))(x)
x = layers.Conv2D(filters=32, kernel_size=(3, 3), activation="relu")(x)
# 全局平均池化层
x = layers.GlobalAveragePooling2D()(x)
#密集分类器层,输出
num_classes = 10
outputs = layers.Dense(num_classes, activation="softmax")(x)
(3)实例化Model对象:定义模型网络层,为将输入转换为输出,需要实例化Model对象
model = keras.Model(inputs=inputs, outputs=outputs)
打印模型结构:为每个层显示的输出形状包括批次大小
model.summary()
data = np.random.randint(0, 256, size=(64, 200, 200, 3)).astype("float32")
processed_data = model(data)
print(processed_data.shape)
已经了解了:1)加载处理数据;2)建立模型。下一步是根据数据训练模型。
(1)编译模型:指定优化器和损失函数compile()
model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3), loss=keras.losses.CategoricalCrossentropy())
#或
model.compile(optimizer='rmsprop',loss='categorical_crossentropy')
(2)训练模型:将模型“拟合”到数据fit()
#例:使用numpy数据拟合:数据将按batch进行切片
model.fit(numpy_array_of_samples,numpy_array_of_labels,batch_size=32, epochs=10)
完整示例:
# (1)获取数据:得到numpy类型的数据
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# (2)构建模型
inputs = keras.Input(shape=(28, 28))
x = layers.experimental.preprocessing.Rescaling(1.0 / 255)(inputs)
x = layers.Flatten()(x)
x = layers.Dense(128, activation="relu")(x)
x = layers.Dense(128, activation="relu")(x)
outputs = layers.Dense(10, activation="softmax")(x)
#(3)实例化Model对象
model = keras.Model(inputs, outputs)
model.summary()
#(4)编译模型
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy")
#(5)训练模型
# Numpy 数据
batch_size = 64
print("Fit on NumPy data")
history = model.fit(x_train, y_train, batch_size=batch_size, epochs=1)
# dataset对象,因为dataset数据集对象在创建的时候就划分了批量,不需要再fit的时候指定批量。
dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(batch_size)
print("Fit on Dataset")
history = model.fit(dataset, epochs=1)
使用fit()返回的对象查看训练发生的情况。history.history字典包含每个epoch时间序列的度量的值(这里只有一个度量,损失和一个epoch,因此只能得到一个标量)
print(history.history)
在训练模型时,您希望跟踪指标,例如分类准确性,精度,召回率,AUC等。此外,不仅要在训练数据上而且要在验证集上监视这些指标。
类型一:增加监控指标,将想要监控的指标传递给compile(),
#添加监控指标
model.compile(optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=[keras.metrics.SparseCategoricalAccuracy(name="acc")])
#训练
history = model.fit(dataset, epochs=1)
938/938 [==============================] - 1s 1ms/step - loss: 0.0556 - acc: 0.9829 - val_loss: 0.1163 - val_acc: 0.9670
类型二:训练过程中进行验证,传递验证数据以fit()监视验证损失和验证指标
val_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(batch_size)
history = model.fit(dataset, epochs=1, validation_data=val_dataset)
938/938 [==============================] - 1s 1ms/step - loss: 0.0556 - acc: 0.9829 - val_loss: 0.1163 - val_acc: 0.9670
类型三: 使用回调进行点检查。回调是模型在训练过程中的不同点被调用的对象,例每批开始的结束和开始、每epoch的开始和结束
例:ModelCheckpoint配置为在每个时期结束时保存模型的 回调。
callbacks = [
keras.callbacks.ModelCheckpoint(
filepath='path/to/my/model_{epoch}',
save_freq='epoch')
]
model.fit(dataset, epochs=2, callbacks=callbacks)
类型四: 使用TensorBoard监控训练进度。监控您的损失和指标随着时间的变化
#将TensorBoard与fit()结合使用,只需传递一个keras.callbacks.TensorBoard回调,指定存储TensorBoard日志的目录:
callbacks = [
keras.callbacks.TensorBoard(log_dir='./logs')
]
model.fit(dataset, epochs=2, callbacks=callbacks)
您可以启动一个TensorBoard实例,您可以在浏览器中打开该实例
tensorboard --logdir=./logs
#通过以下方式评估其损失和新数据的指标 evaluate():
loss, acc = model.evaluate(val_dataset) # returns loss and metrics
print("loss: %.2f" % loss)
print("acc: %.2f" % acc)
#通过以下方式生成预测的NumPy数组(模型中输出层的激活)predict():
predictions = model.predict(val_dataset)
print(predictions.shape)