卷积神经网络(CNN)天气识别|项目一

发布于:2023-01-20 ⋅ 阅读:(142) ⋅ 点赞:(0)

天气识别-项目一

评论

项目来源: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网络

卷积核原理参考:卷积原理
Dropout层参考:参数参考

常用激活函数:
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.

 


本文含有隐藏内容,请 开通VIP 后查看