实验目的
通过 Tensorflow
的基础类,构建卷积神经网络,用于花朵图片的分类。
实验环境
import tensorflow as tf
print(tf.__version__)
output:
2.3.0
实验步骤
(一) 数据获取和预处理
1.1 数据选择 TensorFlow 官方提供的花朵图片数据,经如下代码获取:
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
img_dir= tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
1.2 读取图片:这里,我们通过 tf.keras.preprocessing.image_dataset_from_directory
函数批量读入图片。
import pathlib
# 数据保存路径
data_dir = pathlib.Path(data_dir)
BATCH_SIZE = 32 # BATCH size 设为32
img_height = 180 # 读取图片后,高度转换为180像素
img_width = 180 # 读取图片后,宽度转换为180像素
# 读入images (training data)
train_ds = tf.keras.preprocessing.image_dataset_from_directory(img_dir,
shuffle=True,
validation_split=0.2,
seed=123,
subset='training',
batch_size=BATCH_SIZE,
image_size=(img_height, img_width)
)
# 读入images(test data)
val_ds = tf.keras.preprocessing.image_dataset_from_directory(img_dir,
shuffle=True,
validation_split=0.2,
seed=123,
subset='validation',
image_size=(img_height, img_width),
batch_size=BATCH_SIZE
)
1.3 查看训练数据的前9张图片.
plt.figure(figsize=(6, 6))
for imgs, labels in train_ds.take(1):
for i in range(9):
ax = plt.subplot(3,3,i+1)
plt.imshow(imgs[i].numpy().astype("uint8"))
plt.title(class_names[labels[i]])
plt.axis("off")
(二) 通过 tf 的基础类,自定义模型
class Mymodel(tf.keras.Model):
def __init__(self):
super().__init__()
# 定义normalization 层
self.normalization_layer = tf.keras.layers.experimental.preprocessing.Rescaling(1.0 / 255)
# 定义数据增强层
self.aug1 = tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal')
self.aug2 = tf.keras.layers.experimental.preprocessing.RandomRotation(0.1)
self.aug3 = tf.keras.layers.experimental.preprocessing.RandomZoom(0.1)
# 定义cov1
self.cov1 = tf.keras.layers.Conv2D(16, (3,3), padding='same', activation='relu', name='cov1')
self.pool1 = tf.keras.layers.MaxPool2D(name='pool1')
# 定义cov2
self.cov2 = tf.keras.layers.Conv2D(32, (3,3), padding='same', activation='relu', name='cov2')
self.pool2 = tf.keras.layers.MaxPool2D(name='pool2')
# 定义cov3
self.cov3 = tf.keras.layers.Conv2D(64, (3,3), padding='same', activation='relu', name='cov3')
self.pool3 = tf.keras.layers.MaxPool2D(name='pool3')
# 定义 Dropout
self.dropout = tf.keras.layers.Dropout(0.2)
# 定义 flatten
self.flatten = tf.keras.layers.Flatten()
# 定义 Dense
self.dense1 = tf.keras.layers.Dense(128, activation='relu', name='dense1')
self.dense2 = tf.keras.layers.Dense(5)
def call(self, img):
# 执行normalization
X = self.normalization_layer(img)
# 执行aug
X = self.aug1(X)
X = self.aug2(X)
X = self.aug3(X)
X = self.cov1(X)
X = self.pool1(X)
X = self.cov2(X)
X = self.pool2(X)
X = self.cov3(X)
X = self.pool3(X)
X = self.flatten(X)
X = self.dense1(X)
X = self.dense2(X)
return X
(三) 定义损失函数
def loss(y_true, y_predict):
return tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)(y_true, y_predict)
(四) 定义优化函数
optimizer = tf.keras.optimizers.Adam()
(五) 定义训练函数
def train_step(batch_inp, batch_targ, model):
with tf.GradientTape() as tape:
dense_ = model(batch_inp)
batch_loss = loss(batch_targ, dense_)
gradients = tape.gradient(batch_loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
return batch_loss
(六) 训练模型
# 实例化模型
model = Mymodel()
epochs = 50 # 训练50个epoch
els = [] # 存储每个epoch的损失函数,用于后续绘图
for epoch in range(epochs):
epoch_loss = 0
# 由于我的计算机显存太小,这里每个epoch只取前20个batch进行训练
for batch, (inp, targ) in enumerate(train_ds.take(20)):
batch_loss = train_step(inp, targ, model)
epoch_loss += batch_loss.numpy()
print('epoch {}: {:.4f}'.format(epoch, epoch_loss/10))
els.append(epoch_loss/10)
训练过程如下:
epoch 0: 0.5867
epoch 1: 0.6709
epoch 2: 0.6393
epoch 3: 0.6831
epoch 4: 0.6870
epoch 5: 0.6461
epoch 6: 0.4888
…
Loss 随训练过程的变化情况:
(七) 通过模型进行预测
预测的代码来之 TensorFlow 官方社区。
sunflower_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg"
sunflower_path = tf.keras.utils.get_file('Red_sunflower', origin=sunflower_url)
img = keras.preprocessing.image.load_img(
sunflower_path, target_size=(img_height, img_width)
)
img_array = keras.preprocessing.image.img_to_array(img)
img_array = tf.expand_dims(img_array, 0) # Create a batch
predictions = model.predict(img_array)
score = tf.nn.softmax(predictions[0])
print(
"This image most likely belongs to {} with a {:.2f} percent confidence."
.format(class_names[np.argmax(score)], 100 * np.max(score))
)
图片为:
预测结果:
This image most likely belongs to sunflowers with a 97.69 percent confidence.