实验目的
通过 Tensorflow
的基础类,构建卷积神经网络,用于花朵图片的分类。
实验环境
import tensorflow as tfprint(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)# 定义cov1self.cov1 = tf.keras.layers.Conv2D(16, (3,3), padding='same', activation='relu', name='cov1')self.pool1 = tf.keras.layers.MaxPool2D(name='pool1')# 定义cov2self.cov2 = tf.keras.layers.Conv2D(32, (3,3), padding='same', activation='relu', name='cov2')self.pool2 = tf.keras.layers.MaxPool2D(name='pool2')# 定义cov3self.cov3 = tf.keras.layers.Conv2D(64, (3,3), padding='same', activation='relu', name='cov3')self.pool3 = tf.keras.layers.MaxPool2D(name='pool3')# 定义 Dropoutself.dropout = tf.keras.layers.Dropout(0.2)# 定义 flattenself.flatten = tf.keras.layers.Flatten()# 定义 Denseself.dense1 = tf.keras.layers.Dense(128, activation='relu', name='dense1')self.dense2 = tf.keras.layers.Dense(5)def call(self, img):# 执行normalizationX = self.normalization_layer(img)# 执行augX = 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 batchpredictions = 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.