当前位置: 首页 > article >正文

智能识别猫猫

鸡蛋饼是什么猫

今天,有一位爱猫人士找到了我:“9月25日啦,炉石传说重新开服了!”

我:“哦!我知道这个,你是说,我现在该去领金卡了吗?”

爱猫人士:“不!是我看到他们又在讨论狗贼嘘嘘家的猫是什么品种的了!。”

狗贼叔叔是一位知名的老战士,在那样一个简单的下午,他组了一套平时最常用的卡牌,然后普普通通的登了一个顶,然后就再也没有回来。他有一只心爱的小猫叫做“鸡蛋饼”,大概是这样的:

在这里插入图片描述

我:“嗯,然后呢?”

爱猫人士:“我已经受够了有人管它叫做橘猫了!这些人对猫的种类太没有认知,张口就来!”

其实,鸡蛋饼是一只乳色的英短,或者也称为英短金渐层,这也是一个不常见的稀有品种了。英短就是人们常说的“蓝胖子”,这种猫一般都是蓝的或者蓝白的,因此,虽然很多人天天见“蓝胖子”,但是,遇到了鸡蛋饼,就认不出来了,这也不奇怪。

我:”那这不是显得你的水平高嘛?“

爱猫人士:”不,我觉得,你应该写一篇文章,给大家科普一下猫的种类的知识!“

啊这,科普猫的种类?我自己还认不全呢,不过,我想到了一个好办法,我应该训练一个ai,用来识别猫的种类。

资源下载

没有猫,我们也不能凭空变出猫来,因此,首先,我们需要得到一些猫的图片。

猫狗分类:https://www.kaggle.com/datasets/zippyz/cats-and-dogs-breeds-classification-oxford-dataset

比如说,这个数据集看起来不错,直接用这个好了。

我大致查阅了一下,感觉有些不太妙,关于英短的品种
在这里插入图片描述
这全是“蓝胖子”啊,一只英短金渐层也没有,如果就拿这个去给ai训练,到时候认不出鸡蛋饼的可能性非常高啊!

不过,这也正常,鸡蛋饼毕竟是稀有品种,而且这个数据集也有几年的历史了,那个时候,像鸡蛋饼这样的猫比现在还要更稀少,所以没有包括也正常。不过,我并不打算添加额外的图片进去,就先这样好了。

预处理

这个数据集原本叫做“cats and dogs“,肯定不只有猫,那还有狗呢!狗现在可不是我们需要的,首先,我们要想办法把狗删掉,但是,要怎么做呢!我怎么知道谁是猫,谁是狗啊?

还好,数据集的作者早就想到了,猫都是首字母大写的,狗都是首字母小写的,这样的话,我们只需要把首字母大写的图片提取出来就好了。

import os
import shutil
import pandas as pd
from sklearn.model_selection import train_test_split




dataset_path = "images"
cat_folder = os.path.join(dataset_path, "cats")
cat_data = []


os.makedirs(cat_folder, exist_ok=True)




for filename in os.listdir(dataset_path):
    if filename.endswith(".jpg"):
        if filename[0].isupper():
            shutil.move(os.path.join(dataset_path, filename), os.path.join(cat_folder, filename))
            
for filename in os.listdir(cat_folder):
    if filename.lower().endswith('.jpg'):
        filename_no_ext = os.path.splitext(filename)[0]
        try:
            cat_breed, number = filename_no_ext.rsplit('_', 1)
            cat_data.append({'filename': filename, 'breed': cat_breed})
        except ValueError:
            print(f"文件名格式不正确: {filename}")




cat_df = pd.DataFrame(cat_data)


breed_to_num = {breed: idx for idx, breed in enumerate(cat_df["breed"].unique())}
cat_df["breed_num"] = cat_df["breed"].map(breed_to_num)


train_df, test_df = train_test_split(df, test_size=0.2, stratify=cat_df["breed_num"], random_state=240925)


train_df.to_csv("train_dataset.csv", index=False)
test_df.to_csv("test_dataset.csv", index=False)


print("训练集样本数:", len(train_df))
print("测试集样本数:", len(test_df))

模型训练

import torch
import torch.nn as nn
import torchvision.models as models
import pandas as pd
import os
from PIL import Image
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms




class CatDataset(Dataset):
    def __init__(self, csv_file, img_dir, transform=None):
        self.data_frame = pd.read_csv(csv_file)
        self.img_dir = img_dir
        self.transform = transform


    def __len__(self):
        return len(self.data_frame)


    def __getitem__(self, idx):
        img_name = os.path.join(self.img_dir, self.data_frame.iloc[idx, 0])
        image = Image.open(img_name).convert("RGB")
        label = int(self.data_frame.iloc[idx, 2])


        if self.transform:
            image = self.transform(image)


        return image, label




transform = transforms.Compose([
    transforms.Resize(224, 224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],
                         std=[0.229, 0.224, 0.225]),
])




train_dataset = CatDataset(csv_file="train_dataset.csv", img_dir="cats", transform=transform)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)


test_dataset = CatDataset(csv_file="test_dataset.csv", img_dir="cats", transform=transform)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)




class CatClassifier(nn.Module):
    def __init__(self, num_classes):
        super(CatClassifier, self).__init__()
        self.model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
        self.model.fc = nn.Linear(self.model.fc.in_features, num_classes)


    def forward(self, x):
        return self.model(x)


num_classes = len(train_dataset.data_frame["breed_num"].unique())
model = CatClassifier(num_classes)


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)


criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)




num_epochs = 10


for epoch in range(num_epochs):
    model.train()
    running_loss = 0.0
    correct = 0
    total = 0


    for images, labels in train_loader:
        images, labels = images.to(device), labels.to(device)


        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()


        running_loss += loss.item() * images.size(0)


        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()


    epoch_loss = running_loss / len(train_loader.dataset)
    epoch_acc = correct / total


    print(f"Epoch [{epoch + 1}/{num_epochs}], Loss: {epoch_loss:.4f}, Accuracy: {epoch_acc:.4f}")

加载与使用

现在,我们已经得到了一个能够识别猫的种类的模型了,要怎么使用呢?

# 注意:你划分的数据集有可能不是这样的,要根据实际情况进行修改
breed_num_to_name = {11: 'British_Shorthair', 0: 'Maine_Coon', 3: 'Sphynx', 10: 'Egyptian_Mau', 2: 'Birman', 8: 'Bombay', 1: 'Siamese', 5: 'Ragdoll', 7: 'Abyssinian', 9: 'Russian_Blue', 4: 'Bengal', 6: 'Persian'}




def predict_image(image_path, threshold=0.8):
    transform = transforms.Compose([
        transforms.Resize(224, 224)
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                             std=[0.229, 0.224, 0.225]),
    ])


    image = Image.open(image_path).convert("RGB")
    input_image = transform(image).unsqueeze(0).to(device)


    with torch.no_grad():
        outputs = model(input_image)
        probabilities = torch.nn.functional.softmax(outputs, dim=1)
        max_prob, predicted = torch.max(probabilities, 1)
        max_prob = max_prob.item()
        predicted_class = predicted.item()


        if max_prob >= threshold:
            predicted_breed = breed_num_to_name.get(predicted_class)
            print(f"这是一个: {predicted_breed}")
        else:
            print("这个我可能不认识~")




predict_image("cats/British_Shorthair_241.jpg", threshold=0.8)

最终结果

我们的ai确实已经可以认出测试集中猫的品种了,此时我们拿出来鸡蛋饼的照片:
在这里插入图片描述
我们的ai居然表示:“这个我可能不认识~”,怎么能这样,一定是打开的方式不对!再换一张!
在这里插入图片描述

结果还是一样的,“这个我可能不认识~”。唉,枉费我花费了这么多心血,不过其实也是很正常的事情啦,毕竟我们的训练集中,一张英短金渐层也没,这个时候,想把鸡蛋饼归类为蓝胖子一类,还是太不容易了!

相关链接

普通的一个下午:https://www.bilibili.com/video/BV16w411N7FT/

历史直播回放(up主饕餮):https://space.bilibili.com/10579668/

ai狗贼唱心会很痛:https://www.bilibili.com/video/BV11m411S7rf/

看看鸡蛋饼,突然又有一些伤感,“国服炉石今又在,不见当年叠甲人。”,再排队>15分钟我就要进去了,那位战士说他的补偿不要了,可以给我吗?在这里插入图片描述


http://www.kler.cn/a/319653.html

相关文章:

  • postgresql.conf与postgresql.auto.conf区别
  • 【卡尔曼滤波】数据融合Fusion的应用 C语言、Python实现(Kalman Filter)
  • kubesphere环境-本地Harbor仓库+k8s集群(单master 多master)+Prometheus监控平台部署
  • python爬虫(二)爬取国家博物馆的信息
  • C#中 layout的用法
  • 算法每日双题精讲——滑动窗口(长度最小的子数组,无重复字符的最长子串)
  • 【JVM】垃圾回收机制|死亡对象的判断算法|垃圾回收算法
  • 谷歌的AI反击战:创始人谢尔盖·布林的回归与大模型组合的未来
  • vue2使用npm引入依赖(例如axios),报错Module parse failed: Unexpected token解决方案
  • 复制他人 CSDN 文章到自己的博客
  • 快递物流短信API接口代码
  • ​​​​​​​月考发成绩,为什么老师都用易查分?
  • MySQL数据库的备份与恢复
  • 力扣(leetcode)每日一题 815 公交路线 (图的宽度优先遍历变种)
  • 实验19:ds18b20温度实验
  • Unity屏幕震动效果
  • 「数学::质数」试除法 / Luogu P5736(C++)
  • 使用ChatGPT引导批判性思维,提升论文的逻辑与说服力的全过程
  • 华为HarmonyOS灵活高效的消息推送服务(Push Kit) - 3 获取AAID
  • Python内置的re库
  • Android平台Unity3D下如何同时播放多路RTMP|RTSP流?
  • 什么是电商云手机?可以用来干什么?
  • 内容生态短缺,Rokid AR眼镜面临市场淘汰赛
  • 影刀RPA实战:网页爬虫之天猫商品数据
  • 在 Windows 上安装和配置 NVIDIA 驱动程序、CUDA、cuDNN 和 TensorRT
  • Vue2学习笔记(02条件渲染 、监视数据的原理)