tensorflow2.0教程—快速入门
文章目录
本文主要讲解tensorflow 2.0 搭建网络结构的技术细节。
在使用tensorflow 之前首先导入tensorflow
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
print(tf.__version__)
print(tf.keras.__version__)
tensorflow推荐使用keras构建网络,常见的方式有二种:序列化API、函数式API。
模型的序列化API
基本示例
序列化模型常用于:简单的神经网络层的堆叠。每一层都有一个输入tensor和一个输出tensor。
示例如下:
# Define Sequential model with 3 layers
model = keras.Sequential(
[
keras.Input(shape=(3,3)),
layers.Dense(2, activation="relu", name="layer1"),
layers.Dense(3, activation="relu", name="layer2"),
layers.Dense(4, name="layer3"),
]
)
# Call model on a test input
x = tf.ones((3, 3))
y = model(x)
或者:
# Create 3 layers
layer1 = layers.Dense(2, activation="relu", name="layer1")
layer2 = layers.Dense(3, activation="relu", name="layer2")
layer3 = layers.Dense(4, name="layer3")
# Call layers on a test input
x = tf.ones((3, 3))
y = layer3(layer2(layer1(x)))
或者:
model = keras.Sequential()
model.add(layers.Dense(2, activation="relu"))
model.add(layers.Dense(3, activation="relu"))
model.add(layers.Dense(4))
推荐在模型一开始就定义模型的输入大小:
model = keras.Sequential()
model.add(layers.Dense(2, activation="relu", input_shape=(4,)))
模型细节查看
通过以下代码查看模型细节:
model.summary() # 在模型构建过程中随时查看output Shape
model.weights
查看序列化模型中间层的输出
initial_model = keras.Sequential(
[
keras.Input(shape=(250, 250, 3)),
layers.Conv2D(32, 5, strides=2, activation="relu"),
layers.Conv2D(32, 3, activation="relu",name="my_intermediate_layer"),
layers.Conv2D(32, 3, activation="relu"),
]
)
# 方式一:查看最终结果
feature_extractor = keras.Model(
inputs=initial_model.inputs,
outputs=[layer.output for layer in initial_model.layers],
)
# 方式二:通过层名称查看输出结果
feature_extractor = keras.Model(
inputs=initial_model.inputs,
outputs=initial_model.get_layer(name="my_intermediate_layer").output,
)
# Call feature extractor on test input.
x = tf.ones((1, 250, 250, 3))
features = feature_extractor(x)
序列化API型缺陷
序列化模型不适用以下情况:
(1) 模型含有多个输入或多个输出
(2) 模型中的某一层含有多个输入或多个输出
(3) 模型中存在层共享的情况
(4) 模型中存在类似残差网络这样的非线性模型。
由于存在这些缺陷,我们引入函数式模型。
模型的函数式API
函数式API可以处理具有非线性拓扑的模型(残差神经网络),具有共享层的模型以及具有多个输入或输出的模型。
基本步骤
(1) 创建一个输入节点,常见的输入有以下两种:
# 输入是一个784维的向量,样本数不用指定,
inputs = keras.Input(shape=(784,))
# 输入是一个大小为32x32的3通道图片
img_inputs = keras.Input(shape=(32, 32, 3))
可以通过:inputs.shape,inputs.dtype来查看输入节点基本细节。
(2)定义其他网络层,以函数调用的形式同时传入inputs
x = layers.Dense(64, activation="relu")(inputs)
x = layers.Dense(64, activation="relu")(x)
outputs = layers.Dense(10)(x)
(3) 指定输入输出,创建模型
model = keras.Model(inputs=inputs, outputs=outputs, name="mnist_model")
应用
1、 图片的编码解码器
先定义一个encoder:
encoder_input = keras.Input(shape=(28, 28, 1), name="original_img")
x = layers.Conv2D(16, 3, activation="relu")(encoder_input)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.Conv2D(16, 3, activation="relu")(x)
encoder_output = layers.GlobalMaxPooling2D()(x)
encoder = keras.Model(encoder_input, encoder_output, name="encoder")
encoder.summary()
再定义一个解码器decoder:
decoder_input = keras.Input(shape=(16,), name="encoded_img")
x = layers.Reshape((4, 4, 1))(decoder_input)
x = layers.Conv2DTranspose(16, 3, activation="relu")(x)
x = layers.Conv2DTranspose(32, 3, activation="relu")(x)
x = layers.UpSampling2D(3)(x)
x = layers.Conv2DTranspose(16, 3, activation="relu")(x)
decoder_output = layers.Conv2DTranspose(1, 3, activation="relu")(x)
decoder = keras.Model(decoder_input, decoder_output, name="decoder")
decoder.summary()
将图片先输入编码器,对输出结果进行解码,形成新的模型autoencoder
autoencoder_input = keras.Input(shape=(28, 28, 1), name="img")
encoded_img = encoder(autoencoder_input)
decoded_img = decoder(encoded_img)
autoencoder = keras.Model(autoencoder_input, decoded_img, name="autoencoder")
autoencoder.summary()
2、以下是将一组模型合并为一个平均其预测的模型的方法:
def get_model():
inputs = keras.Input(shape=(128,))
outputs = layers.Dense(1)(inputs)
return keras.Model(inputs, outputs)
model1 = get_model()
model2 = get_model()
model3 = get_model()
inputs = keras.Input(shape=(128,))
y1 = model1(inputs)
y2 = model2(inputs)
y3 = model3(inputs)
outputs = layers.average([y1, y2, y3])
ensemble_model = keras.Model(inputs=inputs, outputs=outputs)
3、层共享
共享层通常用于编码来自相似空间的输入(例如,两个具有相似词汇的不同文本)。它们可以在这些不同的输入之间共享信息,并且可以在更少的数据上训练这种模型。下面是两个不同的文本输入共享的嵌入层:
# Embedding for 1000 unique words mapped to 128-dimensional vectors
shared_embedding = layers.Embedding(1000, 128)
# Variable-length sequence of integers
text_input_a = keras.Input(shape=(None,), dtype="int32")
# Variable-length sequence of integers
text_input_b = keras.Input(shape=(None,), dtype="int32")
# Reuse the same layer to encode both inputs
encoded_input_a = shared_embedding(text_input_a)
encoded_input_b = shared_embedding(text_input_b)
模型的训练和评估
(1)加载数据集
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# Preprocess the data (these are NumPy arrays)
x_train = x_train.reshape(60000, 784).astype("float32") / 255
x_test = x_test.reshape(10000, 784).astype("float32") / 255
y_train = y_train.astype("float32")
y_test = y_test.astype("float32")
# Reserve 10,000 samples for validation
x_val = x_train[-10000:]
y_val = y_train[-10000:]
x_train = x_train[:-10000]
y_train = y_train[:-10000]
(2)模型的compile
在训练之前,通过compile( ) 指定模型的损失函数,优化器,评价指标:
model.compile(
optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
loss=keras.losses.SparseCategoricalCrossentropy(),
metrics=[keras.metrics.SparseCategoricalAccuracy()],
)
或者:
model.compile(
optimizer="rmsprop",
loss="sparse_categorical_crossentropy",
metrics=["sparse_categorical_accuracy"],
)
常见的使用参数如下:
参数 | 值 |
---|---|
Optimizers | SGD(), RMSprop() ,Adam() |
Losses | MeanSquaredError(),KLDivergence(),CosineSimilarity() |
Metrics | AUC()、Precision()、Recall() |
也可自定义模型的Metrics,loss
def custom_mean_squared_error(y_true, y_pred):
return tf.math.reduce_mean(tf.square(y_true - y_pred))
model.compile(optimizer=keras.optimizers.Adam(), loss=custom_mean_squared_error)
# We need to one-hot encode the labels to use MSE
y_train_one_hot = tf.one_hot(y_train, depth=10)
model.fit(x_train, y_train_one_hot, batch_size=64, epochs=1)
为了使用上的方便,可以通常将模型的定义与编译封装到一个函数中:
def get_uncompiled_model():
inputs = keras.Input(shape=(784,), name="digits")
x = layers.Dense(64, activation="relu", name="dense_1")(inputs)
x = layers.Dense(64, activation="relu", name="dense_2")(x)
outputs = layers.Dense(10, activation="softmax", name="predictions")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
return model
def get_compiled_model():
model = get_uncompiled_model()
model.compile(
optimizer="rmsprop",
loss="sparse_categorical_crossentropy",
metrics=["sparse_categorical_accuracy"],
)
return model
(3)模型的训练
print("Fit model on training data")
history = model.fit(
x_train,
y_train,
batch_size=64,
epochs=2,
# We pass some validation for
# monitoring validation loss and metrics
# at the end of each epoch
validation_data=(x_val, y_val),
)
可以通过history查看训练的损失值:
history.history
当训练数据数Numpy时,也可以事先不做验证集切分,直接通过validation_split设置验证集的大小:
model = get_compiled_model()
model.fit(x_train, y_train, batch_size=64, validation_split=0.2, epochs=1)
在训练过程中可以指定类别权重和样本权重
指定类别权重:
import numpy as np
class_weight = {
0: 1.0,
1: 1.0,
2: 1.0,
3: 1.0,
4: 1.0,
# Set weight "2" for class "5",
# making this class 2x more important
5: 2.0,
6: 1.0,
7: 1.0,
8: 1.0,
9: 1.0,
}
print("Fit with class weight")
model = get_compiled_model()
model.fit(x_train, y_train, class_weight=class_weight, batch_size=64, epochs=1)
指定样本权重:
sample_weight = np.ones(shape=(len(y_train),))
sample_weight[y_train == 5] = 2.0
print("Fit with sample weight")
model = get_compiled_model()
model.fit(x_train, y_train, sample_weight=sample_weight, batch_size=64, epochs=1)
(4)模型的评估、预测
# Evaluate the model on the test data using `evaluate`
print("Evaluate on test data")
results = model.evaluate(x_test, y_test, batch_size=128)
print("test loss, test acc:", results)
# Generate predictions (probabilities -- the output of the last layer)
# on new data using `predict`
print("Generate predictions for 3 samples")
predictions = model.predict(x_test[:3])
print("predictions shape:", predictions.shape)
多输入多输出模型
下图是一张典型的多输入多输出模型结构图:
模型代码如下:
image_input = keras.Input(shape=(32, 32, 3), name="img_input")
timeseries_input = keras.Input(shape=(None, 10), name="ts_input")
x1 = layers.Conv2D(3, 3)(image_input)
x1 = layers.GlobalMaxPooling2D()(x1)
x2 = layers.Conv1D(3, 3)(timeseries_input)
x2 = layers.GlobalMaxPooling1D()(x2)
x = layers.concatenate([x1, x2]) # 链接两个输出
score_output = layers.Dense(1, name="score_output")(x)
class_output = layers.Dense(5, activation="softmax", name="class_output")(x)
# 注意这里如何将数据输入模型已经如何接受模型的输出
model = keras.Model(
inputs=[image_input, timeseries_input], outputs=[score_output, class_output]
)
在模型编译时可以传入多个loss和评估指标,并指定名称:
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss={
"score_output": keras.losses.MeanSquaredError(), # 设置为None 时表示不指定
"class_output": keras.losses.CategoricalCrossentropy(),
},
metrics={
"score_output": [
keras.metrics.MeanAbsolutePercentageError(),
keras.metrics.MeanAbsoluteError(),
],
"class_output": [keras.metrics.CategoricalAccuracy()],
},
#可以使用loss_weights参数为不同的特定于输出的损失赋予不同的权重
#(例如,在我们的示例中,我们可能希望通过赋予类损失的重要性2倍来赋予“得分”损失以特权)
loss_weights={"score_output": 2.0, "class_output": 1.0},
)
以合适的方式将数据传递给多输入或多输出模型
# Generate dummy NumPy data
img_data = np.random.random_sample(size=(100, 32, 32, 3))
ts_data = np.random.random_sample(size=(100, 20, 10))
score_targets = np.random.random_sample(size=(100, 1))
class_targets = np.random.random_sample(size=(100, 5))
# Fit on lists
model.fit([img_data, ts_data], [score_targets, class_targets], batch_size=32, epochs=1)
# Alternatively, fit on dicts
model.fit(
{"img_input": img_data, "ts_input": ts_data},
{"score_output": score_targets, "class_output": class_targets},
batch_size=32,
epochs=1,
)
模型的保存与读取
def get_model():
# Create a simple model.
inputs = keras.Input(shape=(32,))
outputs = keras.layers.Dense(1)(inputs)
model = keras.Model(inputs, outputs)
model.compile(optimizer="adam", loss="mean_squared_error")
return model
model = get_model()
# Train the model.
test_input = np.random.random((128, 32))
test_target = np.random.random((128, 1))
model.fit(test_input, test_target)
# Calling `save('my_model')` creates a SavedModel folder `my_model`.
model.save("my_model")
# It can be used to reconstruct the model identically.
reconstructed_model = keras.models.load_model("my_model")
# Let's check:下面的结果是一样的
model.predict(test_input), reconstructed_model.predict(test_input)
上一篇: 优化Swift的构建时间