基于AlexNet实现猫狗大战

卷积神经网络介绍

卷积神经网络(Convolutional Neural Network,简称CNN),是一种深度学习模型,特别适用于处理图像、视频等数据。它的核心思想是利用卷积层(Convolutional layers)来提取输入数据中的局部特征,通过滑动窗口的方式扫描数据,并应用滤波器(filter或kernel)进行特征检测。每一层卷积会捕获不同尺度和位置的特征,然后通过池化层(pooling layers)减少数据尺寸并保留重要信息。

卷积结构

如下图所示,一个简单的CNN由输入层,卷积层,池化层,全连接层,输出层组成
在这里插入图片描述

输入层(Input):

输入层的作用就是将图像转换为其对应的由像素值构成的二维矩阵,并将此二维矩阵存储,等待后面几层的操作。
**如果输入一张尺寸为(H, W)的彩色图像,则输入层的数据为一个(H×W×3)的矩阵,数值范围为[0, 255],其中,3表示RGB三个通道,一般称作该输入层为3通道(channel),或者说包含3个feature map,如果是灰度图像,则数据表示为(H×W×1),1个通道或者1个feature map。从数值上讲,此处的3通道或者1通道与后续每一层卷积结果的feature map数量是等价的。

卷积层(Conv)

假设我们已经得到图片的二维矩阵了,想要提取其中特征,那么卷积操作就会为存在特征的区域确定一个高值,否则确定一个低值。这个过程需要通过计算其与卷积核(Convolution Kernel)的乘积值来确定。假设我们现在的输入图片是一个人的脑袋,而人的眼睛是我们需要提取的特征,那么我们就将人的眼睛作为卷积核,通过在人的脑袋的图片上移动来确定哪里是眼睛,这个过程如下所示:
提取人的眼睛的特征的过程 有的读者可能注意到,每次卷积核移动的时候中间位置都被计算了,而输入图像二维矩阵的边缘却只计算了一次,会不会导致计算的结果不准确呢?

让我们仔细思考,如果每次计算的时候,边缘只被计算一次,而中间被多次计算,那么得到的特征图也会丢失边缘特征,最终会导致特征提取不准确,那为了解决这个问题,我们可以在原始的输入图像的二维矩阵周围再拓展一圈或者几圈,这样每个位置都可以被公平的计算到了,也就不会丢失任何特征,此过程可见下面两种情况,这种通过拓展解决特征丢失的方法又被称为Padding

池化层(pooling)

当特征图非常多的时候,意味着我们得到的特征也非常多,但是这么多特征都是我们所需要的么?显然不是,其实有很多特征我们是不需要的,而这些多余的特征通常会给我们带来如下两个问题

  1. 过拟合
  2. 维度过高
    为了解决这个问题,我们可以利用池化层,那什么是池化层呢?池化层又称为下采样,也就是说,当我们进行卷积操作后,再将得到的特征图进行特征提取,将其中最具有代表性的特征提取出来,可以起到减小过拟合和降低维度的作用,这个过程如下所示:
    池化的过程
    如何提取到最有代表性的特征呢,通常有两种方法:
  3. 最大池化

顾名思义,最大池化就是每次取正方形中所有值的最大值,这个最大值也就相当于当前位置最具有代表性的特征,这个过程如下所示:在这里插入图片描述
这里有几个参数需要说明一下:
① kernel_size = 2:池化过程使用的正方形尺寸是2×2,如果是在卷积的过程中就说明卷积核的大小是2×2
② stride = 2:每次正方形移动两个位置(从左到右,从上到下),这个过程其实和卷积的操作过程一样
③ padding = 0:这个之前介绍过,如果此值为0,说明没有进行拓展

2. 平均池化

平均池化就是取此正方形区域中所有值的平均值,考虑到每个位置的值对于此处特征的影响,平均池化计算也比较简单,整个过程如下图所示:
平均池化的过程 以上就是关于池化层的所有操作,我们再回顾一下,经过池化后,我们可以提取到更有代表性的特征,同时还减少了不必要的计算,这对于我们现实中的神经网络计算大有脾益,因为现实情况中神经网络非常大,而经过池化层后,就可以明显的提高模型的效率。所以说,池化层的好处很多,将其优点总结如下:

在减少参数量的同时,还保留了原图像的原始特征

有效防止过拟合

为卷积神经网络带来平移不变性

全连接层(fully connected)

假设还是上面人的脑袋的示例,现在我们已经通过卷积和池化提取到了这个人的眼睛、鼻子和嘴的特征,如果我想利用这些特征来识别这个图片是否是人的脑袋该怎么办呢?此时我们只需要将提取到的所有特征图进行“展平”,将其维度变为1 × x 1×x1×x,这个过程就是全连接的过程,也就是说,此步我们将所有的特征都展开并进行运算,最后会得到一个概率值,这个概率值就是输入图片是否是人的概率,这个过程如下所示:
在这里插入图片描述
可以看到,经过两次卷积和最大池化之后,得到最后的特征图,此时的特征都是经过计算后得到的,所以代表性比较强,最后经过全连接层,展开为一维的向量,再经过一次计算后,得到最终的识别概率,这就是卷积神经网络的整个过程。

输出层

卷积神经网络的输出层理解起来就比较简单了,我们只需要将全连接层得到的一维向量经过计算后得到识别值的一个概率,当然,这个计算可能是线性的,也可能是非线性的。在深度学习中,我们需要识别的结果一般都是多分类的,所以每个位置都会有一个概率值,代表识别为当前值的概率,取最大的概率值,就是最终的识别结果。在训练的过程中,可以通过不断地调整参数值来使识别结果更准确,从而达到最高的模型准确率。

基于AlexNet实现“猫狗分类”步骤

AlexNet网络结构相对简单,使用了8层卷积神经网络,前5层是卷积层,剩下的3层是全连接层,具体如下所示。
    在这里插入图片描述

了解AlexNet网络结构

在深度学习框架下,搭建一个网络进行训练和测试十分方便,主要包括三个步骤:

准备数据,将数据集中的数据整理成程序代码可识别读取的形式。

def mkfile(file):if not os.path.exists(file):os.makedirs(file)
# 获取data文件夹下所有文件夹名(即需要分类的类名)
file_path = 'D:/python-learning/AlexNet/data_name'
flower_class = [cla for cla in os.listdir(file_path)]# 创建 训练集train 文件夹,并由类名在其目录下创建5个子目录
mkfile('data/train')
for cla in flower_class:mkfile('data/train/' + cla)# 创建 验证集val 文件夹,并由类名在其目录下创建子目录
mkfile('data/val')
for cla in flower_class:mkfile('data/val/' + cla)# 划分比例,训练集 : 验证集 = 8 : 2
split_rate = 0.2# 遍历所有类别的全部图像并按比例分成训练集和验证集
for cla in flower_class:cla_path = file_path + '/' + cla + '/'  # 某一类别的子目录images = os.listdir(cla_path)  # iamges 列表存储了该目录下所有图像的名称num = len(images)eval_index = random.sample(images, k=int(num * split_rate))  # 从images列表中随机抽取 k 个图像名称for index, image in enumerate(images):# eval_index 中保存验证集val的图像名称if image in eval_index:image_path = cla_path + imagenew_path = 'data/val/' + clacopy(image_path, new_path)  # 将选中的图像复制到新路径# 其余的图像保存在训练集train中else:image_path = cla_path + imagenew_path = 'data/train/' + clacopy(image_path, new_path)print("\r[{}] processing [{}/{}]".format(cla, index + 1, num), end="")  # processing barprint()print("processing done!")

搭建网络,利用PyTorch提供的API搭建设计的网络

class MyAlexNet(nn.Module):def __init__(self):super(MyAlexNet, self).__init__()# 卷积层self.c1 = nn.Conv2d(in_channels=3, out_channels=48, kernel_size=11, stride=4, padding=2)# 激活函数self.ReLu = nn.ReLU()# 卷积层self.c2 = nn.Conv2d(in_channels=48, out_channels=128, kernel_size=5, stride=1, padding=2)# 池化层self.s2 = nn.MaxPool2d(2)# 卷积层self.c3 = nn.Conv2d(in_channels=128, out_channels=192, kernel_size=3, stride=1, padding=1)# 池化层self.s3 = nn.MaxPool2d(2)# 卷积层self.c4 = nn.Conv2d(in_channels=192, out_channels=192, kernel_size=3, stride=1, padding=1)# 卷积层self.c5 = nn.Conv2d(in_channels=192, out_channels=128, kernel_size=3, stride=1, padding=1)# 池化层self.s5 = nn.MaxPool2d(kernel_size=3, stride=2)self.flatten = nn.Flatten()# 全连接层self.f6 = nn.Linear(4608, 2048)self.f7 = nn.Linear(2048, 2048)self.f8 = nn.Linear(2048, 1000)self.f9 = nn.Linear(1000, 2)def forward(self, x):x = self.ReLu(self.c1(x))x = self.ReLu(self.c2(x))x = self.s2(x)x = self.ReLu(self.c3(x))x = self.s3(x)x = self.ReLu(self.c4(x))x = self.ReLu(self.c5(x))x = self.s5(x)x = self.flatten(x)x = self.f6(x)x = F.dropout(x, p=0.5)x = self.f7(x)x = F.dropout(x, p=0.5)x = self.f8(x)x = F.dropout(x, p=0.5)x = self.f9(x)return x# 实例化与测试
if __name__ == '__main__':x = torch.rand([1, 3, 224, 224])model = MyAlexNet()y = model(x)

训练网络,把1中准备好的数据送入2中搭建的网络中进行训练,获得网络各节点权值参数


# 训练集的路径
ROOT_TRAIN = r'D:/python-learning/AlexNet/data/train'
# 验证集路径
ROOT_TEST = r'D:/python-learning/AlexNet/data/val'# 将图像的像素值归一化到【-1, 1】之间
normalize = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])# 图片预处理
train_transform = transforms.Compose([transforms.Resize((224, 224)),transforms.RandomVerticalFlip(),transforms.ToTensor(),normalize])val_transform = transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),normalize])# 导入数据
train_dataset = ImageFolder(ROOT_TRAIN, transform=train_transform)
val_dataset = ImageFolder(ROOT_TEST, transform=val_transform)train_dataloader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_dataloader = DataLoader(val_dataset, batch_size=32, shuffle=True)device = 'cuda' if torch.cuda.is_available() else 'cpu'model = MyAlexNet().to(device)# 定义一个损失函数
loss_fn = nn.CrossEntropyLoss()# 定义一个优化器
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)# 学习率每隔10轮变为原来的0.5
lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)# 定义训练函数
def train(dataloader, model, loss_fn, optimizer):loss, current, n = 0.0, 0.0, 0for batch, (x, y) in enumerate(dataloader):image, y = x.to(device), y.to(device)output = model(image)cur_loss = loss_fn(output, y)  # 误差_, pred = torch.max(output, axis=1)cur_acc = torch.sum(y==pred) / output.shape[0]# 反向传播optimizer.zero_grad()cur_loss.backward()optimizer.step()loss += cur_loss.item()current += cur_acc.item()n = n+1train_loss = loss / ntrain_acc = current / nprint('train_loss' + str(train_loss))print('train_acc' + str(train_acc)) #训练的精确度return train_loss, train_acc# 定义一个验证函数
def val(dataloader, model, loss_fn):# 将模型转化为验证模型model.eval()loss, current, n = 0.0, 0.0, 0with torch.no_grad():for batch, (x, y) in enumerate(dataloader):image, y = x.to(device), y.to(device)output = model(image)cur_loss = loss_fn(output, y)_, pred = torch.max(output, axis=1)cur_acc = torch.sum(y == pred) / output.shape[0]loss += cur_loss.item()current += cur_acc.item()n = n + 1val_loss = loss / nval_acc = current / nprint('val_loss' + str(val_loss))print('val_acc' + str(val_acc))return val_loss, val_acc# 定义画图函数
def matplot_loss(train_loss, val_loss):plt.plot(train_loss, label='train_loss')plt.plot(val_loss, label='val_loss')plt.legend(loc='best')plt.ylabel('loss')plt.xlabel('epoch')plt.title("训练集和验证集loss值对比图")plt.show()def matplot_acc(train_acc, val_acc):plt.plot(train_acc, label='train_acc')plt.plot(val_acc, label='val_acc')plt.legend(loc='best')plt.ylabel('acc')plt.xlabel('epoch')plt.title("训练集和验证集acc值对比图")plt.show()# 开始训练
loss_train = []
acc_train = []
loss_val = []
acc_val = []epoch = 20
min_acc = 0
for t in range(epoch):print(f"epoch{t+1}\n-----------")train_loss, train_acc = train(train_dataloader, model, loss_fn, optimizer)val_loss, val_acc = val(val_dataloader, model, loss_fn)loss_train.append(train_loss)acc_train.append(train_acc)loss_val.append(val_loss)acc_val.append(val_acc)# 保存最好的模型权重if val_acc >min_acc:folder = 'save_model'if not os.path.exists(folder):os.mkdir('save_model')min_acc = val_accprint(f"save best model, 第{t+1}轮")torch.save(model.state_dict(), 'save_model/best_model.pth')# 保存最后一轮的权重文件if t == epoch-1:torch.save(model.state_dict(), 'save_model/last_model.pth')
lr_scheduler.step()
matplot_loss(loss_train, loss_val)
matplot_acc(acc_train, acc_val)
print('Done!')

测试网络,导入3中获取的参数,并输入网络一个数据,然后评估网络的输出结果


ROOT_TRAIN = r'D:/python-learning/AlexNet/data/train'
ROOT_TEST = r'D:/python-learning/AlexNet/data/val'# 将图像的像素值归一化到【-1, 1】之间
normalize = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])train_transform = transforms.Compose([transforms.Resize((224, 224)),transforms.RandomVerticalFlip(),transforms.ToTensor(),normalize])val_transform = transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),])train_dataset = ImageFolder(ROOT_TRAIN, transform=train_transform)
val_dataset = ImageFolder(ROOT_TEST, transform=val_transform)train_dataloader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_dataloader = DataLoader(val_dataset, batch_size=32, shuffle=True)device = 'cuda' if torch.cuda.is_available() else 'cpu'model = MyAlexNet().to(device)# 加载模型
model.load_state_dict(torch.load("D:/python-learning/AlexNet/save_model/best_model.pth"))# 获取预测结果
classes = ["cat","dog",
]# 把张量转化为照片格式
show = ToPILImage()# 进入到验证阶段
model.eval()
for i in range(2475,2525):x, y = val_dataset[i][0], val_dataset[i][1]show(x).show()x = Variable(torch.unsqueeze(x, dim=0).float(), requires_grad=True).to(device)x = torch.tensor(x).to(device)with torch.no_grad():pred = model(x)predicted, actual = classes[torch.argmax(pred[0])], classes[y]print(f'predicted:"{predicted}", Actual:"{actual}"')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/143149.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

[C语言]连子棋游戏

文章目录 一、前言二、游戏思路三、游戏方法1、初始化2、判断胜利3、交互4、电脑下棋 四、核心方法说明1、初始化游戏2、销毁棋盘3、显示游戏4、电脑下棋5、用户下棋6、判断游戏状态7、游戏交互 五、游戏效果展示与源码分享1、游戏效果2、源代码 一、前言 对于指针和数组理解尚…

关于std::swap原理

swap 操作交换两个相同类型容器的内容。调用swap之后&#xff0c;两个容器中的元素将会 交换&#xff1a; vector<striong> svec1(10); //10个元素的vector vector<string> svec2(24); //24个元素的vector swap(svec1,svec2); 调…

C++ | Leetcode C++题解之第413题等差数列划分

题目&#xff1a; 题解&#xff1a; class Solution { public:int numberOfArithmeticSlices(vector<int>& nums) {int n nums.size();if (n 1) {return 0;}int d nums[0] - nums[1], t 0;int ans 0;// 因为等差数列的长度至少为 3&#xff0c;所以可以从 i2 开…

一款免费开源且功能强大的思维导图软件-思绪思维导图

思绪思维导图是一款免费开源的思维导图软件&#xff0c;旨在帮助用户有效地组织和表达思想。它提供了丰富的功能&#xff0c;包括支持富文本、图片、图标、超链接、备注、标签等内容&#xff0c;以及关联线、概要等特性。 思绪思维导图下载&#xff1a;https://pan.quark.cn/s…

在STM32工程中使用Mavlink与飞控通信

本文讲述如何在STM32工程中使用Mavlink协议与飞控通信&#xff0c;特别适合自制飞控外设模块的项目。 需求来源&#xff1a; 1、增稳云台里的STM32单片机需要通过串口接收飞控传来的云台俯仰、横滚控制指令和相机拍照控制指令&#xff1b; 2、自制的有害气体采集器需要接收飞…

基于Springboot的医疗健康助手开题报告

文未可获取一份本项目的java源码和数据库参考。 一&#xff0e;选题意义, 研究现状,可行性分析 选题意义&#xff1a;随着科技的高速发展&#xff0c;人们的生活水平也正在稳步提高&#xff0c;解决温饱问题以后&#xff0c;广大人民群众也越来越注重自己的身体健康&#xff0…

[Redis][前置知识][下][高并发架构演进]详细讲解

目录 1.单机架构2.应⽤数据分离架构3.应⽤服务集群架构4.读写分离/主从分离架构5.引⼊缓存⸺冷热分离架构6.垂直分库/分表7.业务拆分⸺微服务8.总结 1.单机架构 只有一台服务器&#xff0c;这个服务器负责所有的工作 大部分公司的产品&#xff0c;都是这种单机架构 2.应⽤数…

自己建网站怎么建

自己建立一个网站可能听起来有点复杂&#xff0c;但实际上&#xff0c;有很多简单且免费的方法可以实现。下面将介绍一些基本步骤&#xff0c;帮助你开始自己建立一个网站。 首先&#xff0c;你需要明确你的网站目的是什么。是个人博客、商业网站&#xff0c;还是其他类型的网…

frp内网穿透功能使用教程

frp 是一款高性能的反向代理应用&#xff0c;专注于内网穿透。它支持多种协议&#xff0c;包括 TCP、UDP、HTTP、HTTPS 等&#xff0c;并且具备 P2P 通信功能。使用 frp&#xff0c;您可以安全、便捷地将内网服务暴露到公网&#xff0c;通过拥有公网 IP 的节点进行中转。 文档地…

深度学习----------------------文本预处理

目录 文本预处理读取数据集词源化词表该部分总代码该部分总代码 整合所有功能该部分总代码 文本预处理 文本预处理&#xff1a;把文本当作一个时序序列 将解析文本的常见预处理步骤。 这些步骤通常包括&#xff1a; ①将文本作为字符串加载到内存中。 ②将字符串拆分为词元&…

【数据结构篇】~链表算法题3(环形链表)

链表算法题3&#xff08;环形链表&#xff09; 环形链表的证明1. 环形链表I​1) 思路2&#xff09;代码实现 2. 环形链表II​1) 思路11) 思路22&#xff09;代码实现 环形链表的证明 1. 环形链表I​ https://leetcode.cn/problems/linked-list-cycle/description/ 1) 思路 判断…

Nginx搭建直播服务器,并用rtmp,http-flv,hls三种模式拉流观看直播的流程

一、首先搭建直播服务器 环境widows&#xff0c;并且已经集成了 &#xff1a;nginx-http-flv-module模块 nginx.conf配置如下&#xff1a; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #error…

计算机人工智能前沿进展-大语言模型方向-2024-09-15

计算机人工智能前沿进展-大语言模型方向-2024-09-15 1. Towards the holistic design of alloys with large language models Z Pei, J Yin, J Neugebauer, A Jain - Nature Reviews Materials, 2024 利用大型语言模型实现合金的全面设计 摘要 文章讨论了大型语言模型在材料…

nginx服务器安装和部署代理

文章目录 Linux下面安装nginx nginx下载官网: [nginx: download](https://nginx.org/en/download.html) 使用yum命令安装gcc环境 yum install -y wget gcc-c pcre-devel zlib-devel openssl-devel//安装多个环境 wget gcc pcre-devel 支持正则表达式 zlib-devel提供了压缩和…

CleanClip vs 传统剪贴板:究竟谁更胜一筹?

在日常工作和生活中,复制粘贴可以说是我们使用最频繁的操作之一。传统的剪贴板功能虽然简单易用,但在功能性和效率上还有很大的提升空间。今天,我们就来比较一下新兴的剪贴板增强工具CleanClip与传统剪贴板,看看到底谁更胜一筹。 1. 剪贴历史管理 传统剪贴板只能存储最后一次…

Java项目实战II基于Java+Spring Boot+MySQL的图书管理系统的设计与实现 (源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、论文参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在信息爆炸…

【图虫创意-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

用来用去还是用回了ueditor-Vue富文本编辑器二次扩展

用来用去还是用回了ueditor-Vue富文本编辑器二次扩展。我们使用用过UEditor、TinyMCE、CKEditor、wangEditor、Tiptap、Quill项目经历过多次富文本的编辑器的选型使用&#xff0c;发现现在新的富文本编辑总感觉还是没达到我们的要求&#xff0c;果然改回了ueditor。 UEditor 是…

PMP与CMMI:两种管理方法的对比

PMP与CMMI&#xff1a;两种管理方法的对比 PMP&#xff1a;专注于项目管理CMMI&#xff1a;组织过程改进的框架总结&#xff1a;互补而非替代 在现代企业管理中&#xff0c;项目管理和组织能力成熟度模型集成&#xff08;CMMI&#xff09;是两个经常被提及的概念。虽然它们都是…

java线程池编程示例

程序功能 这段代码展示了如何使用 Java 线程池 来并发执行多个任务。通过创建一个固定大小为 3 的线程池&#xff0c;程序提交了 5 个任务&#xff0c;并让线程池中的线程并发处理这些任务。每个任务模拟了一个耗时操作&#xff0c;最后程序等待所有任务完成后关闭线程池。 …