当前位置:   article > 正文

猫狗二分类与四种天气多分类_四种天气数据集

四种天气数据集

提示:文章用于学习记录


前言

常见分类网络结构可以分为两部分,一部分是特征提取部分,另一部分是分类部分;特征提取部分一般由各类卷积组成,卷积拥有强大的特征提取能力;分类部分一般由全连接组成,特征提取部分获取到的特征一般是一维向量,可以直接进行全连接分类;VGG16 网络由三种不同的层组成,分别是卷积层、最大池化层、全连接层。


一、猫狗图像分类

源码链接

1.1 数据预处理

  1. 读取包含5000张猫狗图像数据集,图片名称中含有类别名称(cat和 dog 每类有2500张),把图像resize到 128* 128大小。
  2. 根据图片名称给图片打标签,狗的标签打成1,猫的标签打成0。
  3. 切分数据集: (train data,train label) 是训练数据, (test data, test label) 是测试数据,测试数据占25%。
  4. 查看经过尺寸调整后的猫狗样本图片。
import os, shutil
# c数据集解压缩所在目录的路径
original_dataset_dir = 'Cat&Dog'
# 创建一个存储较小数据集的目录
base_dir = 'find_cats_and_dogs'
os.mkdir(base_dir)

# 培训、验证和测试拆分
train_dir = os.path.join(base_dir, 'train')
os.mkdir(train_dir)
validation_dir = os.path.join(base_dir, 'validation')
os.mkdir(validation_dir)
test_dir = os.path.join(base_dir, 'test')
os.mkdir(test_dir)

# 训练猫图片
train_cats_dir = os.path.join(train_dir, 'cats')
os.mkdir(train_cats_dir)

# 训练狗图片
train_dogs_dir = os.path.join(train_dir, 'dogs')
os.mkdir(train_dogs_dir)

# 验证猫图片
validation_cats_dir = os.path.join(validation_dir, 'cats')
os.mkdir(validation_cats_dir)

# 验证狗图片
validation_dogs_dir = os.path.join(validation_dir, 'dogs')
os.mkdir(validation_dogs_dir)

# 测试猫的图片
test_cats_dir = os.path.join(test_dir, 'cats')
os.mkdir(test_cats_dir)

# 测试猫的图片
test_dogs_dir = os.path.join(test_dir, 'dogs')
os.mkdir(test_dogs_dir)

# 复制前1000个cat图像以训练模型
fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(train_cats_dir, fname)
    shutil.copyfile(src, dst)

# 将500个猫图像复制到验证
fnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(validation_cats_dir, fname)
    shutil.copyfile(src, dst)
    
# 复制500个猫图像到测试
fnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(test_cats_dir, fname)
    shutil.copyfile(src, dst)
    
# 复制1000个狗图片去训练模型
fnames = ['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(train_dogs_dir, fname)
    shutil.copyfile(src, dst)
    
# 复制500个狗图片去验证
fnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(validation_dogs_dir, fname)
    shutil.copyfile(src, dst)
    
# 复制500个狗图片去测试
fnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir, fname)
    dst = os.path.join(test_dogs_dir, fname)
    shutil.copyfile(src, dst)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
# 打印新数据集的尺寸
print('total training cat images:', len(os.listdir(train_cats_dir)))
print('total training dog images:', len(os.listdir(train_dogs_dir)))
print('total validation cat images:', len(os.listdir(validation_cats_dir)))
print('total validation dog images:', len(os.listdir(validation_dogs_dir)))
print('total test cat images:', len(os.listdir(test_cats_dir)))
print('total test dog images:', len(os.listdir(test_dogs_dir)))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

1.2 构建神经网络

  1. 使用 Keras 搭建一个 VGG16 卷积神经网络;VGG16 网络由三种不同的层组成,分别是卷积层、最大池化层、全连接层。
  2. 设置超参,设置优化器,查看刚搭建的神经网络模型结构结构详情;
  3. 模型训练,打印Loss (损失函数) 和acc (精确度) 信息,保存训练好的模型;
  4. 将 Loss 随 epoch 的变化趋势与 accurary 随 epoch 的变化趋势使用折线图进行可视化展示;
  5. 样本数据预测,直观展示10个样本数据的预测结果0;
  6. 评估模型准确度,通过测试集的预测结果,计算模型的准确度;
# 构建小型卷积网络

import tensorflow as tf
from keras import layers 
from keras import models

model = models.Sequential()
model.add(tf.keras.layers.Conv2D(32,(3,3),activation="relu",
                               input_shape=(150,150,3)))
model.add(tf.keras.layers.MaxPooling2D((2,2)))

model.add(tf.keras.layers.Conv2D(64,(3,3),activation="relu"))
model.add(tf.keras.layers.MaxPooling2D((2,2)))

model.add(tf.keras.layers.Conv2D(128,(3,3),activation="relu"))
model.add(tf.keras.layers.MaxPooling2D((2,2)))

model.add(tf.keras.layers.Conv2D(128,(3,3),activation="relu"))
model.add(tf.keras.layers.MaxPooling2D((2,2)))  # 

model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(512, activation="relu"))
model.add(tf.keras.layers.Dense(1, activation="sigmoid"))

model.summary()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这里插入图片描述

# 使用RMSprop优化器

from tensorflow.keras import optimizers

model.compile(loss="binary_crossentropy",
             optimizer=optimizers.RMSprop(learning_rate=1e-4),
             metrics=["acc"])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
# 数据预处理

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale=1./255)  # 进行缩放
test_datagen = ImageDataGenerator(rescale=1./255)  # 进行缩放

train_generator = train_datagen.flow_from_directory(
    train_dir,  # 待处理的目录
    target_size=(150,150),  # 图像大小设置
    batch_size=20,
    class_mode="binary"  # 损失函数是binary_crossentropy 所以使用二进制标签
)

validation_generator = test_datagen.flow_from_directory(
    validation_dir,  # 待处理的目录
    target_size=(150,150),  # 图像大小设置
    batch_size=20,
    class_mode="binary"  # 损失函数是binary_crossentropy 所以使用二进制标签
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里插入图片描述

# 查看生成器输出
for data_batch, labels_batch in train_generator:
    print(data_batch.shape)
    print(labels_batch.shape)
    break
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

# 使用生成器使我们的模型适合于数据
history = model.fit(
    train_generator,  # 第一个参数必须是Python生成器
    steps_per_epoch=100,  # 2000 / 20
    epochs=30,  # 迭代次数
    validation_data=validation_generator,  # 待验证的数据集
    validation_steps=50 
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

# 保存模型
model.save("cats_and_dogs_small.h5")
  • 1
  • 2
# 在训练和验证数据上绘制模型的损失和准确性
import matplotlib.pyplot as plt
%matplotlib inline
history_dict = history.history  # 字典形式
for key, _ in history_dict.items():
    print(key)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

acc = history_dict["acc"]
val_acc = history_dict["val_acc"]

loss = history_dict["loss"]
val_loss = history_dict["val_loss"]
  • 1
  • 2
  • 3
  • 4
  • 5
epochs = range(1, len(acc)+1)

# acc
plt.plot(epochs, acc, "bo", label="Training acc")
plt.plot(epochs, val_acc, "b", label="Validation acc")
plt.title("Training and Validation acc")
plt.legend()

plt.figure()

# loss
plt.plot(epochs, loss, "bo", label="Training loss")
plt.plot(epochs, val_loss, "b", label="Validation loss")
plt.title("Training and Validation loss")
plt.legend()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

这些图具有过拟合的特点,随着时间的增加,训练精度在不断增加,接近100%,而验证精度则停留在70-72%;原因是训练样本(2000)相对较少;
减轻过度拟合方法:dropout和重量衰减(L2正则化);这里使用的是在深度学习模型处理图像时几乎普遍使用的数据增强的方法。

二、四种天气图片数据分类(pytorch)

文件夹中包含1,150张图片,包含4种天气下道路的图片,
分别为City_road(晴天下道路),fog(雾天道路),rain(雨天道路),snow(雪天道路),
构建一个多分类模型(4分类),对不同天气下的道路图片进行识别。
构建模型时请严格按照如下规则进行数值标签映射{‘City_road’: 0, ‘fog’: 1, ‘rain‘: 2, ‘snow‘: 3}

源码连接

#相关包导入
import torch
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torch.nn as nn
import torch.nn.functional as F
import torchvision
from torchvision import datasets, transforms
import os
import shutil
%matplotlib inlineimport numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
# 数据分区
# 首先我们需要做的是另外建立一个新的文件夹,这个文件夹下面有两个文件夹,分别是train和test,代码如下:

base_dir = r"./weatherRoad"
if not os.path.isdir(base_dir):
    os.mkdir(base_dir)
    train_dir = os.path.join(base_dir, 'train')
    test_dir = os.path.join(base_dir, 'test')
    os.mkdir(train_dir)
    os.mkdir(test_dir)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
# 然后,在train和test文件夹中分别建立以四种天气类型命名的文件夹,代码如下:

species = ['City_road', 'fog', 'rain', 'snow']
for train_or_test in ['train', 'test']:
    for spec in species:
        os.mkdir(os.path.join(base_dir, train_or_test, spec))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
image_dir = r'./train'
for i, img in enumerate(os.listdir(image_dir)):
    for spec in species:
        if spec in img:
            s = os.path.join(image_dir, img)
            if i % 5 == 0:
                d = os.path.join(base_dir, 'test', spec, img)
            else:
                d = os.path.join(base_dir, 'train', spec, img)
            shutil.copy(s, d)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
# 操作完之后,我们可以查看一下各个文件夹中各有多少数据

for train_or_test in ['train', 'test']:
    for spec in species:
        print(train_or_test, spec, len(os.listdir(os.path.join(base_dir, train_or_test, spec))))
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

# 加载数据及数据预处理

transformation = transforms.Compose([
    transforms.Resize((96, 96)), # 改变图像大小
    transforms.ToTensor(),
    transforms.Normalize(mean = [0.5, 0.5, 0.5], std = [0.5, 0.5, 0.5]) # 标准化
])

train_ds = datasets.ImageFolder(
    train_dir,
    transform = transformation
)

test_ds = datasets.ImageFolder(
    test_dir,
    transform = transformation
)

train_dl = torch.utils.data.DataLoader(train_ds, batch_size = 16, shuffle = True)
test_dl = torch.utils.data.DataLoader(test_ds, batch_size = 16)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
train_ds.classes
  • 1

在这里插入图片描述

train_ds.class_to_idx
  • 1

在这里插入图片描述

len(train_ds),len(test_ds)
  • 1

在这里插入图片描述

# 模型定义代码如下:

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 16, 3)
        self.bn1 = nn.BatchNorm2d(16)
        self.pool = nn.MaxPool2d((2, 2))
        self.conv2 = nn.Conv2d(16, 32, 3)
        self.bn2 = nn.BatchNorm2d(32)
        self.conv3 = nn.Conv2d(32, 64, 3)
        self.bn3 = nn.BatchNorm2d(64)
        self.drop = nn.Dropout(0.5)
        self.linear_1 = nn.Linear(64 * 10 * 10, 1024)
        self.bn_l1 = nn.BatchNorm1d(1024)
        self.linear_2 = nn.Linear(1024, 256)
        self.bn_l2 = nn.BatchNorm1d(256)
        self.linear_3 = nn.Linear(256, 4)
    def forward(self, input):
        x = F.relu(self.conv1(input))
        x = self.pool(x)
        x = self.bn1(x)
        x = F.relu(self.conv2(x))
        x = self.pool(x)
        x = self.bn2(x)
        x = F.relu(self.conv3(x))
        x = self.pool(x)
        x = self.bn3(x)
        # print(x.size())
        x = x.view(-1, 64 * 10 * 10)
        x = F.relu(self.linear_1(x))
        x = self.bn_l1(x)
        x = self.drop(x)
        x = F.relu(self.linear_2(x))
        x = self.bn_l2(x)
        x = self.drop(x)
        x = self.linear_3(x)
        return x
# 这里需要注意的是各个层的位置,BN层放在池化层后面,以激活层和Dropout层之间
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
# 模型训练

loss_func = torch.nn.CrossEntropyLoss()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

def fit(epoch, model, trainloader, testloader):
    correct = 0
    total = 0
    running_loss = 0
    
    model.train()  # 训练阶段
    for x, y in trainloader:
        x, y = x.to(device), y.to(device)
        y_pred = model(x)
        loss = loss_func(y_pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        with torch.no_grad():
            y_pred = torch.argmax(y_pred, dim = 1)
            correct += (y_pred == y).sum().item()
            total += y.size(0)
            running_loss += loss.item()

    epoch_acc = correct / total
    epoch_loss = running_loss / len(trainloader.dataset)
    
    test_correct = 0
    test_total = 0
    test_running_loss = 0
    
    model.eval() # 评价阶段,一般在有dropout层和BN层的时候使用
    with torch.no_grad():
        for x, y in testloader:
            x, y = x.to(device), y.to(device)
            y_pred = model(x)
            loss = loss_func(y_pred, y)
            y_pred = torch.argmax(y_pred, dim = 1)
            test_correct += (y_pred == y).sum().item()
            test_total += y.size(0)
            test_running_loss += loss.item()
    epoch_test_acc = test_correct / test_total
    epoch_test_loss = test_running_loss / len(testloader.dataset)
    
    print('epoch: ', epoch, 
          'loss: ', round(epoch_loss, 3),
          'accuracy: ', round(epoch_acc, 3),
          'test_loss: ', round(epoch_test_loss, 3),
          'test_accuracy: ', round(epoch_test_acc, 3))
    
    return epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc

# 这里需要注意的是,要区分训练阶段和评价阶段,一般在有Dropout层和BN层的时候使用
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
model = Model()
model.to(device)
optimizer = torch.optim.Adam(model.parameters(), lr = 0.001)
epochs = 30

train_loss = []
train_acc = []
test_loss = []
test_acc = []
for epoch in range(epochs):
    epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch, model, train_dl, test_dl)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

# 保存模型
torch.save(model.cpu().state_dict(), './modeldict.pth')  # 只保留参数
torch.save(model, './model.pth')  # 保留整个模型
  • 1
  • 2
  • 3
plt.plot(range(1,epochs+1),train_loss,label='train_loss')
plt.plot(range(1,epochs+1),test_loss,label='test_loss')
plt.plot(range(1,epochs+1),train_acc,label='train_acc')
plt.plot(range(1,epochs+1),test_acc,label='test_acc')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

# 这个顺序很重要,要和训练时候的类名顺序一致
class_names = ['City_road', 'fog', 'rain', 'snow']

# 载入模型并读取权重
model.load_state_dict(torch.load('./modeldict.pth'))
model.to(device)
model.eval()  # 测试模式
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

# 图片地址列表
img_paths = ['weatherRoad/test/City_road/City_road_3.jpg', 'weatherRoad/test/fog/fog_56.jpg', 'weatherRoad/test/rain/rain_22.jpg',
             'weatherRoad/test/snow/snow_13.jpg', 'weatherRoad/test/City_road/City_road_67.jpg']
 
  • 1
  • 2
  • 3
  • 4
from PIL import Image
# 对图片地址列表中的每个地址
for path in img_paths:
    img = plt.imread(path)  # 显示图片的第一种方法
    plt.axis('off')
    plt.imshow(img)
    plt.show()

    img = Image.open(path)  # 输入地址打开图片
    # img.show()  # 显示图片的第二种方法

    # 拓张维度:
    # torch.nn只支持小批次的数据输入,不支持输入单个样本。比如nn.Conv2d接收4D
    # tensor作为输入:nSamples * nChannels * Height * Width,
    # 如果只有一个样本,那么使用input.unsqueeze(0)来增加一个批次维度。
    img_ = transformation(img).unsqueeze(0)
    img_ = img_.to(device)  # 是否使用GPU
    outputs = model(img_)  # 得出11类概率

    _, indice = torch.max(outputs, 1)  # 输出概率最大的类别索引,前面是概率值,后面是索引
    result = class_names[indice]  # 得到类别名称
    print('predicted:', result)  # 输出类别名称
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述


总结

以上就是猫狗二分类与四种天气图片数据多分类(pytorch)方法实现。
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/581930
推荐阅读
相关标签
  

闽ICP备14008679号