天气识别-项目一
评论
项目来源:365深度学习训练营
学习目标:
基本:
1.本地读取并加载数据,可选择本地图片进行识别
2.如何加速代码训练?
3.测试集accuracy到达91%
拔高:
1.如何解决过拟合问题?
2.测试集accuracy到达93%
参考文章:参考文章链接深度学习100例-卷积神经网络(CNN)天气识别 | 第5天_K同学啊的博客-CSDN博客参考文章链接
一.前期准备
1.设置GPU
In [189]:
import tensorflow as tf gpus = tf.config.list_physical_devices("GPU") if gpus: gpu0 = gpus[0] #如果有多个GPU,仅使用第0个GPU tf.config.experimental.set_memory_growth(gpu0, True) #设置GPU显存用量按需使用 tf.config.set_visible_devices([gpu0],"GPU")
2.导入数据
In [190]:
import os,PIL,pathlib import matplotlib.pyplot as plt import numpy as np from tensorflow import keras from tensorflow.keras import layers,models tf.random.set_seed(3456)
In [191]:
data_dir = "/home/mw/input/weather_photos9700/weather_photos/weather_photos" data_dir = pathlib.Path(data_dir)
3.查看数据
数据集一共有cloudy-多云,rain-下雨,shine-晴天,sunrise-日出四类,分别放到四个标签文件夹中。
In [192]:
image_count = len(list(data_dir.glob('*/*.jpg'))) print("图片总数为:{}".format(image_count))
图片总数为:1125
In [193]:
shines = list(data_dir.glob('shine/*.jpg')) img=PIL.Image.open(str(shines[2])) img
Out[193]:
In [194]:
img.size #图片大小为480×640
Out[194]:
(480, 640)
二.数据预处理
1.加载数据
In [195]:
batch_size = 32 img_height = 180 img_width = 180
关于image_dataset_from_directory()的详细介绍可以参考文章
作用:将文件夹中的数据加载到tf.data.Dataset中,加载的同时会打乱顺序。
原型:tf.keras.preprocessing.image_dataset_from_directory(
directory,
labels="inferred",
label_mode="int",
class_names=None,
color_mode="rgb",
batch_size=32,
image_size=(256, 256),
shuffle=True,
seed=None,
validation_split=None,
subset=None,
interpolation="bilinear",
follow_links=False,
)
参数:
- directory: 数据所在目录。
- labels: inferred(标签从目录结构生成),或者是整数标签的列表/元组,其大小与目录中找到的图像文件的数量相同。
label_mode:
int:标签将被编码成整数(使用的损失函数应为:sparse_categorical_crossentropy loss)。 categorical:标签将被编码为分类向量(使用的损失函数应为:categorical_crossentropy loss)。 binary:意味着标签(只能有2个)被编码为值为0或1的float32标量(例如:binary_crossentropy)。 None:(无标签)。
class_names: 仅当labels为inferred时有效。这是类名称的明确列表(必须与子目录的名称匹配)。用于控制类的顺序(否则使用字母数字顺序)。
- color_mode: grayscale、rgb、rgba之一。默认值:rgb。图像将被转换为1、3或者4通道。
- batch_size: 数据批次的大小。默认值:32
- image_size: 从磁盘读取数据后将其重新调整大小。默认:(256,256)。由于管道处理的图像批次必须具有相同的大小,因此该参数必须提供。
- shuffle: 是否打乱数据。默认值:True。如果设置为False,则按字母数字顺序对数据进行排序。
- seed: 用于shuffle和转换的可选随机种子。
- validation_split: 0和1之间的可选浮点数,可保留一部分数据用于验证。
- subset: training或validation之一。仅在设置validation_split时使用。
- interpolation: 字符串,当调整图像大小时使用的插值方法。默认为:bilinear。支持bilinear, nearest, bicubic, area, lanczos3, lanczos5, gaussian, mitchellcubic。
- follow_links: 是否访问符号链接指向的子目录。默认:False。
In [196]:
train_ds = tf.keras.preprocessing.image_dataset_from_directory( data_dir, validation_split=0.2, subset="training", seed=42, image_size=(img_height, img_width), batch_size=batch_size)
Found 1125 files belonging to 4 classes. Using 900 files for training.
In [197]:
val_ds = tf.keras.preprocessing.image_dataset_from_directory( data_dir, validation_split=0.2, subset="validation", seed=42, image_size=(img_height, img_width), batch_size=batch_size)
Found 1125 files belonging to 4 classes. Using 225 files for validation.
In [198]:
class_names = train_ds.class_names print(class_names)
['cloudy', 'rain', 'shine', 'sunrise']
2.可视化数据
In [199]:
plt.figure(figsize=(20, 10)) for images, labels in train_ds.take(1): print(labels) for i in range(20): ax = plt.subplot(5, 10, i + 1) plt.imshow(images[i].numpy().astype("uint8")) plt.title(class_names[labels[i]]) plt.axis("off")
tf.Tensor([0 0 2 0 1 3 3 1 1 0 3 2 0 1 0 2 0 2 3 2 3 3 2 1 3 3 1 3 0 3 2 0], shape=(32,), dtype=int32)
3.再次检查数据
In [200]:
for image_batch, labels_batch in train_ds: print(image_batch.shape) print(labels_batch.shape) break
(32, 180, 180, 3) (32,)
Image_batch是形状的张量(32,180,180,3)。这是一批形状180x180x3的32张图片(最后一维指的是彩色通道RGB)。
Label_batch是形状(32,)的张量,这些标签对应32张图片
4.配置数据集
shuffle():打乱数据,关于此函数的详细介绍可以参考:参考文章连接
shuffle(buffer_size):逐步打乱所有数据,先取buffer_size个填充buffer,然后从buffer中随机抽走一个,再从原始数据集中取第buffer_size+1个放入buffer抽走的那个位置中,然后再从buffer中随机选择吓一条数据抽走,依次循环。
prefetch():预取数据,加速运行。
CPU 正在准备数据时,加速器处于空闲状态。相反,当加速器正在训练模型时,CPU 处于空闲状态。因此,训练所用的时间是 CPU 预处理时间和加速器训练时间的总和。prefetch()将训练步骤的预处理和模型执行过
程重叠到一起。当加速器正在执行第 N 个训练步时,CPU 正在准备第 N+1 步的数据。这样做不仅可以最大限度地缩短训练的单步用时(而不是总用时),而且可以缩短提取和转换数据所需的时间。
cache():将数据集缓存到内存当中,加速运行。
In [201]:
# AUTOTUNE = tf.data.AUTOTUNE AUTOTUNE = tf.data.experimental.AUTOTUNE #动态调整缓冲区大小 train_ds = train_ds.cache().shuffle(buffer_size=1000,seed=2022).prefetch(buffer_size=AUTOTUNE) val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
三.构建CNN网络
常用激活函数:
Sigmoid(导数最小为0,最大为1/4)
Tanh(和sigmoid相似,它会关于x轴上下对应,不至于朝某一方面偏向),
ReLU(收敛快,求梯度快,但较脆弱,左边的梯度为0),
Leaky ReLU(不会饱和或者挂掉,计算也很快,但是计算量比较大),
一般不要用sigmoid,首先试ReLU,因为快,但要小心点,如果RELU失效,请用Leaky ReLU,某些情况下tanh倒是有不错的结果。
最大池化:更多保留纹理信息,如果减少无用信息可以用它,有时候波动会很大,可以加一些归一化。
平均池化:更多保存背景信息,所有信息都有用的时候可以用它。
layers.experimental.preprocessing.Rescaling():缩放层将图片标准化
一般图片输入像素为[0.,255],缩放到[0,1]scale=1./255,缩放到[-1,1], 只需设置1./127.5,offset=-1即可.
In [211]:
num_classes = 4 model = models.Sequential([ layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)), layers.Conv2D(16, (3, 3), padding='same',activation='relu', input_shape=(img_height, img_width, 3)), # 卷积层1,卷积核3*3 layers.AveragePooling2D((2, 2)), # 池化层1,2*2采样 layers.Conv2D(32, (3, 3),padding='same', activation='relu'), # 卷积层2,卷积核3*3 layers.Dropout(0.3), layers.AveragePooling2D((2, 2)), # 池化层2,2*2采样 layers.Conv2D(64, (3, 3),padding='same', activation='relu'), # 卷积层3,卷积核3*3 layers.Dropout(0.3), layers.Conv2D(128, (3, 3),padding='same', activation='relu'), # 卷积层3,卷积核3*3 layers.Flatten(), # Flatten层,连接卷积层与全连接层 layers.Dense(128, activation='relu'), # 全连接层,特征进一步提取 layers.Dropout(0.3), layers.Dense(256, activation='relu'), layers.Dense(num_classes) # 输出层,输出预期结果 ]) model.summary() # 打印网络结构
Model: "sequential_14" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= rescaling_14 (Rescaling) (None, 180, 180, 3) 0 _________________________________________________________________ conv2d_55 (Conv2D) (None, 180, 180, 16) 448 _________________________________________________________________ average_pooling2d_28 (Averag (None, 90, 90, 16) 0 _________________________________________________________________ conv2d_56 (Conv2D) (None, 90, 90, 32) 4640 _________________________________________________________________ dropout_43 (Dropout) (None, 90, 90, 32) 0 _________________________________________________________________ average_pooling2d_29 (Averag (None, 45, 45, 32) 0 _________________________________________________________________ conv2d_57 (Conv2D) (None, 45, 45, 64) 18496 _________________________________________________________________ dropout_44 (Dropout) (None, 45, 45, 64) 0 _________________________________________________________________ conv2d_58 (Conv2D) (None, 45, 45, 128) 73856 _________________________________________________________________ flatten_14 (Flatten) (None, 259200) 0 _________________________________________________________________ dense_42 (Dense) (None, 128) 33177728 _________________________________________________________________ dropout_45 (Dropout) (None, 128) 0 _________________________________________________________________ dense_43 (Dense) (None, 256) 33024 _________________________________________________________________ dense_44 (Dense) (None, 4) 1028 ================================================================= Total params: 33,309,220 Trainable params: 33,309,220 Non-trainable params: 0 _________________________________________________________________
四.编译
In [212]:
# 设置优化器 opt = tf.keras.optimizers.Adam(learning_rate=0.001) model.compile(optimizer=opt, loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])
五.训练模型
In [213]:
epochs = 30 history = model.fit( train_ds, validation_data=val_ds, epochs=epochs )
Epoch 1/30 1/29 [>.............................] - ETA: 0s - loss: 1.3892 - accuracy: 0.2500WARNING:tensorflow:Callbacks method `on_train_batch_end` is slow compared to the batch time (batch time: 0.0117s vs `on_train_batch_end` time: 0.0183s). Check your callbacks. 29/29 [==============================] - 1s 36ms/step - loss: 0.9635 - accuracy: 0.5733 - val_loss: 0.5905 - val_accuracy: 0.7733 Epoch 2/30 29/29 [==============================] - 1s 32ms/step - loss: 0.6349 - accuracy: 0.7333 - val_loss: 0.5885 - val_accuracy: 0.7556 Epoch 3/30 29/29 [==============================] - 1s 32ms/step - loss: 0.4991 - accuracy: 0.7989 - val_loss: 0.4564 - val_accuracy: 0.8222 Epoch 4/30 29/29 [==============================] - 1s 32ms/step - loss: 0.4452 - accuracy: 0.8256 - val_loss: 0.4705 - val_accuracy: 0.8356 Epoch 5/30 29/29 [==============================] - 1s 32ms/step - loss: 0.4151 - accuracy: 0.8522 - val_loss: 0.4428 - val_accuracy: 0.8178 Epoch 6/30 29/29 [==============================] - 1s 32ms/step - loss: 0.3606 - accuracy: 0.8689 - val_loss: 0.4510 - val_accuracy: 0.8444 Epoch 7/30 29/29 [==============================] - 1s 32ms/step - loss: 0.3496 - accuracy: 0.8767 - val_loss: 0.4483 - val_accuracy: 0.8356 Epoch 8/30 29/29 [==============================] - 1s 32ms/step - loss: 0.3184 - accuracy: 0.8833 - val_loss: 0.4488 - val_accuracy: 0.8533 Epoch 9/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2551 - accuracy: 0.9200 - val_loss: 0.4592 - val_accuracy: 0.8444 Epoch 10/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2608 - accuracy: 0.9067 - val_loss: 0.4083 - val_accuracy: 0.8356 Epoch 11/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2951 - accuracy: 0.8867 - val_loss: 0.4803 - val_accuracy: 0.8711 Epoch 12/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2451 - accuracy: 0.9089 - val_loss: 0.4910 - val_accuracy: 0.8356 Epoch 13/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2491 - accuracy: 0.9178 - val_loss: 0.4526 - val_accuracy: 0.8711 Epoch 14/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2885 - accuracy: 0.8900 - val_loss: 0.5215 - val_accuracy: 0.8667 Epoch 15/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2545 - accuracy: 0.8956 - val_loss: 0.4162 - val_accuracy: 0.8756 Epoch 16/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2112 - accuracy: 0.9322 - val_loss: 0.4956 - val_accuracy: 0.8756 Epoch 17/30 29/29 [==============================] - 1s 32ms/step - loss: 0.1731 - accuracy: 0.9411 - val_loss: 0.6553 - val_accuracy: 0.8578 Epoch 18/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2051 - accuracy: 0.9300 - val_loss: 0.3368 - val_accuracy: 0.8889 Epoch 19/30 29/29 [==============================] - 1s 32ms/step - loss: 0.1309 - accuracy: 0.9589 - val_loss: 0.4017 - val_accuracy: 0.8978 Epoch 20/30 29/29 [==============================] - 1s 32ms/step - loss: 0.0859 - accuracy: 0.9644 - val_loss: 0.4454 - val_accuracy: 0.8933 Epoch 21/30 29/29 [==============================] - 1s 32ms/step - loss: 0.0871 - accuracy: 0.9633 - val_loss: 0.4012 - val_accuracy: 0.8889 Epoch 22/30 29/29 [==============================] - 1s 32ms/step - loss: 0.1129 - accuracy: 0.9622 - val_loss: 0.4510 - val_accuracy: 0.9111 Epoch 23/30 29/29 [==============================] - 1s 32ms/step - loss: 0.0753 - accuracy: 0.9700 - val_loss: 0.4407 - val_accuracy: 0.9067 Epoch 24/30 29/29 [==============================] - 1s 32ms/step - loss: 0.0584 - accuracy: 0.9756 - val_loss: 0.5224 - val_accuracy: 0.8756 Epoch 25/30 29/29 [==============================] - 1s 32ms/step - loss: 0.0715 - accuracy: 0.9733 - val_loss: 0.4900 - val_accuracy: 0.9067 Epoch 26/30 29/29 [==============================] - 1s 32ms/step - loss: 0.0696 - accuracy: 0.9800 - val_loss: 0.6428 - val_accuracy: 0.9156 Epoch 27/30 29/29 [==============================] - 1s 32ms/step - loss: 0.2392 - accuracy: 0.9322 - val_loss: 0.4604 - val_accuracy: 0.8667 Epoch 28/30 29/29 [==============================] - 1s 32ms/step - loss: 0.1076 - accuracy: 0.9644 - val_loss: 0.4521 - val_accuracy: 0.8978 Epoch 29/30 29/29 [==============================] - 1s 32ms/step - loss: 0.0705 - accuracy: 0.9756 - val_loss: 0.3636 - val_accuracy: 0.9111 Epoch 30/30 29/29 [==============================] - 1s 32ms/step - loss: 0.0635 - accuracy: 0.9789 - val_loss: 0.4456 - val_accuracy: 0.9244
六.模型评估
In [214]:
acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] epochs_range = range(epochs) plt.figure(figsize=(12, 4)) plt.subplot(1, 2, 1) plt.plot(epochs_range, acc, label='Training Accuracy') plt.plot(epochs_range, val_acc, label='Validation Accuracy') plt.legend(loc='lower right') plt.title('Training and Validation Accuracy') plt.subplot(1, 2, 2) plt.plot(epochs_range, loss, label='Training Loss') plt.plot(epochs_range, val_loss, label='Validation Loss') plt.legend(loc='upper right') plt.title('Training and Validation Loss') plt.show()
In [215]:
test_loss,test_acc=model.evaluate(val_ds,verbose=2)
8/8 - 0s - loss: 0.4456 - accuracy: 0.9244
七.实验总结
实验一:epochs=30 效果不佳,epochs=10,accuracy可达到0.911,但明显过拟合.
实验二:全连接层变为256,又添加一层全连接128层全连接,epochs=30,可达到accurcy=0.93,但不稳定。
实验三:添加一层卷积128层,加一层全连接256层,epochs=30,可达到accurcy=0.94.