掘金 人工智能 15小时前
Pytorch实现天气识别
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文旨在介绍如何使用PyTorch构建卷积神经网络(CNN)来识别天气图片,包括数据准备、模型搭建、训练、评估以及真实图片预测的全过程。通过搭建CNN网络、训练模型并保存,最终实现对新天气图片的准确分类。实验结果表明,该模型在识别天气方面具有一定的应用潜力。

🖼️ **数据准备与预处理:** 首先,文章定义了数据目录,并使用`datasets.ImageFolder`加载天气图片,然后通过`transforms.Compose`进行图像预处理,包括调整大小、随机翻转、转换为张量以及标准化,为模型训练做好准备。

🧠 **CNN模型构建:** 文章构建了一个CNN模型,包括卷积层、批标准化层、最大池化层和全连接层。模型结构的设计旨在提取图像特征并进行分类。模型定义了`Network_bn`类,使用`nn.Conv2d`进行卷积操作,`nn.BatchNorm2d`进行批标准化,`nn.MaxPool2d`进行最大池化,最后通过全连接层输出分类结果。

🚀 **模型训练与评估:** 使用交叉熵损失函数和SGD优化器训练模型,并使用训练集和测试集进行评估。训练过程中,记录训练损失、训练精度、测试损失和测试精度,并可视化结果,展示模型的训练效果。代码中定义了`train`和`test`函数,分别用于训练和评估模型。

🔮 **模型预测:** 训练完成后,模型被保存并用于预测新的天气图片。通过加载已保存的模型,对新的图片进行预处理,然后使用模型进行预测,并显示预测结果。`pred.py`文件实现了这一功能。

目标

    读取天气图片,按文件夹分类搭建CNN网络,保存网络模型并加载模型使用保存的模型预测真实天气

具体实现

(一)环境

语言环境:Python 3.10编 译 器: PyCharm框 架: Pytorch 2.5.1

(二)具体步骤

1. 通用文件Utils.py
import torch    # 第一步:设置GPU  def USE_GPU():      if torch.cuda.is_available():          print('CUDA is available, will use GPU')          device = torch.device("cuda")      else:          print('CUDA is not available. Will use CPU')          device = torch.device("cpu")        return device
2. 模型代码
import os    from torchinfo import summary    from Utils import USE_GPU  import pathlib  from PIL import Image  import matplotlib.pyplot as plt  import numpy as np  import torch  import torch.nn as nn  import torchvision.transforms as transforms  import torchvision  from torchvision import datasets    device = USE_GPU()    # 导入数据  data_dir = './data/weather_photos/'  data_dir = pathlib.Path(data_dir)    data_paths = list(data_dir.glob('*'))  # print(data_paths)  classNames = [str(path).split("\\")[2] for path in data_paths]  print(classNames)    # 查看一下图片  image_folder = './data/weather_photos/cloudy'  # 获取image_folder下的所有图片  image_files = [f for f in os.listdir(image_folder) if f.endswith((".jpg", ".png", ".jpeg"))]  #创建matplotlib图像  fig, axes = plt.subplots(3, 8, figsize=(16, 6))    for ax, img_file in zip(axes.flat, image_files):      img_path = os.path.join(image_folder, img_file)      img = Image.open(img_path)      ax.imshow(img)      ax.axis('off')    plt.tight_layout()  plt.title(image_folder, loc='center')  # plt.show()  

train_transforms = transforms.Compose([      transforms.Resize([224, 224]),  # 将输入图片统一resize成224大小      transforms.RandomHorizontalFlip(),      transforms.RandomVerticalFlip(),      transforms.ToTensor(),      transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  ])    total_data = datasets.ImageFolder(data_dir, transform=train_transforms)  print(total_data)    # 划分数据集  train_size = int(0.8 * len(total_data))  test_size = len(total_data) - train_size  train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size])  print(train_size, test_size)  print(train_dataset, test_dataset)    # 设置dataloader  batch_size = 32  train_dl = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)  test_dl = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size, shuffle=False)    for X, y in test_dl:      print("Shape of X [N, C, H, W]: ", X.shape)      print("Shape of y: ", y.shape, y.dtype)      break    # 构建CNN网络  import torch.nn.functional as F    class Network_bn(nn.Module):      def __init__(self):          super(Network_bn, self).__init__()            self.conv1 = nn.Conv2d(3, 12, 5, 1, 0)          self.bn1 = nn.BatchNorm2d(12)          self.conv2 = nn.Conv2d(12, 12, 5, 1, 0)          self.bn2 = nn.BatchNorm2d(12)          self.pool1 = nn.MaxPool2d(2, 2)          self.conv4 = nn.Conv2d(12, 24, 5, 1, 0)          self.bn4 = nn.BatchNorm2d(24)          self.conv5 = nn.Conv2d(24, 24, 5, 1, 0)          self.bn5 = nn.BatchNorm2d(24)          self.pool2 = nn.MaxPool2d(2, 2)          self.fc1 = nn.Linear(24 * 50 * 50, len(classNames))        def forward(self, x):          x = F.relu(self.bn1(self.conv1(x)))          x = F.relu(self.bn2(self.conv2(x)))          x = self.pool1(x)          x = F.relu(self.bn4(self.conv4(x)))          x = F.relu(self.bn5(self.conv5(x)))          x = self.pool2(x)          x = x.view(-1, 24 * 50 * 50)          x = self.fc1(x)            return x    model = Network_bn().to(device)  print(model)  summary(model)  # 训练模型  loss_fn = nn.CrossEntropyLoss()  learn_rate = 1e-4  opt = torch.optim.SGD(model.parameters(), lr=learn_rate)    # 循环训练  def train(dataloader, model, loss_fn, optimizer):      size = len(dataloader.dataset)      num_batches = len(dataloader)        train_loss, train_acc = 0, 0        for X, y in dataloader:          X, y = X.to(device), y.to(device)            pred = model(X)          loss = loss_fn(pred, y)            optimizer.zero_grad()          loss.backward()          optimizer.step()            train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()          train_loss += loss.item()        train_acc /= size      train_loss /= num_batches        return  train_acc,train_loss    def test(dataloader, model, loss_fn):      size = len(dataloader.dataset)      num_batches = len(dataloader)      test_loss, test_acc = 0, 0        with torch.no_grad():          for imgs, target in dataloader:              imgs, target = imgs.to(device), target.to(device)                target_pred = model(imgs)              loss = loss_fn(target_pred, target)                test_loss += loss.item()              test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()        test_acc /= size      test_loss /= num_batches        return test_acc, test_loss    epochs = 25  train_loss = []  train_acc = []  test_loss = []  test_acc = []    for epoch in range(epochs):      model.train()      epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)        model.eval()      epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)        train_acc.append(epoch_train_acc)      train_loss.append(epoch_train_loss)      test_acc.append(epoch_test_acc)      test_loss.append(epoch_test_loss)        template = 'Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%,Test_loss:{:.3f}'      print(template.format(epoch + 1, epoch_train_acc * 100, epoch_train_loss, epoch_test_acc * 100, epoch_test_loss))  print('Done')    # 结果可视化  import matplotlib.pyplot as plt  #隐藏警告  import warnings  warnings.filterwarnings("ignore")               #忽略警告信息  plt.rcParams['font.sans-serif']    = ['SimHei'] # 用来正常显示中文标签  plt.rcParams['axes.unicode_minus'] = False      # 用来正常显示负号  plt.rcParams['figure.dpi']         = 100        #分辨率    epochs_range = range(epochs)    plt.figure(figsize=(12, 3))  plt.subplot(1, 2, 1)    plt.plot(epochs_range, train_acc, label='Training Accuracy')  plt.plot(epochs_range, test_acc, label='Test Accuracy')  plt.legend(loc='lower right')  plt.title('Training and Validation Accuracy')    plt.subplot(1, 2, 2)  plt.plot(epochs_range, train_loss, label='Training Loss')  plt.plot(epochs_range, test_loss, label='Test Loss')  plt.legend(loc='upper right')  plt.title('Training and Validation Loss')  plt.show()    # 保存模型  torch.save(model, "./models/cnn-weather.pth")
3. 预测真实图片:pred.py
from pydoc import classname    from PIL import Image  from matplotlib import pyplot as plt  from torch import nn    from Utils import USE_GPU  import torch  import  torchvision.transforms as transforms  from torchvision import datasets  import pathlib    device = USE_GPU()    # 构建CNN网络  import torch.nn.functional as F    class Network_bn(nn.Module):      def __init__(self):          super(Network_bn, self).__init__()            self.conv1 = nn.Conv2d(3, 12, 5, 1, 0)          self.bn1 = nn.BatchNorm2d(12)          self.conv2 = nn.Conv2d(12, 12, 5, 1, 0)          self.bn2 = nn.BatchNorm2d(12)          self.pool1 = nn.MaxPool2d(2, 2)          self.conv4 = nn.Conv2d(12, 24, 5, 1, 0)          self.bn4 = nn.BatchNorm2d(24)          self.conv5 = nn.Conv2d(24, 24, 5, 1, 0)          self.bn5 = nn.BatchNorm2d(24)          self.pool2 = nn.MaxPool2d(2, 2)          self.fc1 = nn.Linear(24 * 50 * 50, 4)        def forward(self, x):          x = F.relu(self.bn1(self.conv1(x)))          x = F.relu(self.bn2(self.conv2(x)))          x = self.pool1(x)          x = F.relu(self.bn4(self.conv4(x)))          x = F.relu(self.bn5(self.conv5(x)))          x = self.pool2(x)          x = x.view(-1, 24 * 50 * 50)          x = self.fc1(x)            return x    model = torch.load('./models/cnn-weather.pth', weights_only=False)  model.eval()    transform = transforms.Compose([      transforms.Resize([224, 224]),  # 将输入图片统一resize成224大小      transforms.RandomHorizontalFlip(),      transforms.RandomVerticalFlip(),      transforms.ToTensor(),      transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  ])    className = ['cloudy', 'rain', 'shine', 'sunshine']    # 导入数据  weather_data_directory = './mydata/weather'  weather_data_directory = pathlib.Path(weather_data_directory)  print(weather_data_directory)  image_count = len(list(weather_data_directory.glob('*.jpg')))  print("待识别天气图片数量:", image_count)    plt.figure(figsize=(5, 3))  i = 0  for path in weather_data_directory.glob('*.jpg'):      print(path) # 天气图片路径      image_source = Image.open(path)    # 打开图片转换成图片数据      image = transform(image_source)      image = image.unsqueeze(0)  # 增加维度      print(image.shape)      output = model(image.to(device))      pred = className[torch.argmax(output, dim=1).item()]      print(pred)        plt.subplot(2, 5, i+1)      plt.imshow(image_source)      plt.title(pred)      plt.xticks([])      plt.yticks([])        i += 1  plt.show()

准确率80%.

(三)总结

下载一个大数据集训练一下,数据如下:

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

CNN PyTorch 天气识别 深度学习
相关文章