先看问题:
我手边有一数据集,然后我想分分类!~~·
咳咳,最近刚做了一个:训练集有1143张,分为5类,里面图片是打乱的。测试集有248张,想把它分分类看看咋样。
再看一下效果:
这是经过100轮训练后准确率。(准确率最高也就72%左右,要想再升高就要改变数据集或者改网络了)
同时我们也将训练后的结果保存到了文件夹里。
经过网络训练后,最后的显示图:
预测第一张图属于第二类,它的确也确实属于第二类;但第二张图预测它是第二类,但是它事实上属于第四类。
① Prepare dataset 构建数据集
② Design model using Class 设计模型
③ Construct loss and optimizer 构造损失函数和优化器
④ Training 训练
⑤ Prediction 预测结果(第五步可适当补充想生成的图像)
在写代码的时候,如果数据集都构建不好,后续都不用进行了。
接下来,我们简单说一下两种数据集构建代码。
(1) torchvision内置的数据集
这种就是最为简单的一种,可以直接调用的。如 MNIST、Fashion-MNIST、EMNIST、COCO、LSUN、ImageFolder、DatasetFolder、Imageenet-12、CIFAR、STL10 等。
下面简单以 CIFAR-10 为例:
a. 下载
CIFAR-10 and CIFAR-100 datasets (toronto.edu)
(下载解压后如下,并将文件夹放入一个新的文件夹 CIFAR 里,并将该文件夹放入另一个文件夹SH1中。)
大致构建如下:
b. 简单介绍 CIFAR-10
c. 下载并配置数据集及加载器
1. trans = transforms.Compose([transforms.Resize((96, 96)), transforms.ToTensor()]): 这行代码创建了一个数据转换操作的组合 trans,其中包括将图像大小调整为 (96, 96) 并将其转换为张量的操作。
2. train_dataset = datasets.CIFAR10(root=r'D:SH1CIFAR', train=True, transform=trans): 这行代码创建了一个 CIFAR-10 数据集的训练集 train_dataset,指定了数据集的根目录和使用的数据转换操作。
3. test_dataset = datasets.CIFAR10(root=r'D:SH1CIFAR', train=False, transform=trans): 这行代码创建了一个 CIFAR-10 数据集的测试集 test_dataset,同样指定了数据集的根目录和使用的数据转换操作。
4. batch_size = 64: 这行代码定义了批量大小为 64。
5. train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True): 这行代码创建了一个训练数据加载器 train_loader,用于加载训练数据集,指定了数据集、批量大小和是否打乱数据顺序。
6. test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True): 这行代码创建了一个测试数据加载器 test_loader,用于加载测试数据集,同样指定了数据集、批量大小和是否打乱数据顺序。
(2)我们自己手里的数据集
a. 整理标签
以上上周我们老师给我的数据集为例。老师给我的数据集里面包含训练集和测试集以及相应的标签。
但是标签里面的信息太多了,我只需要它的名称以及类别。
以Training_Labels为例,我只需要第一列 image 和 第二列 myopic_maculopathy_grade。
所以我通过上面的代码将第一列和第二列进行了提取,并且改成了:filename', 'label',生成了另外的标签。
同样以train_Labels为例:
b. 定义一个自定义数据集类
我们要定义一个自定义数据集类 CustomDataset , 用于加载图像数据集并返回及其对应的标签。
1. class CustomDataset(Dataset)::定义了一个名为 CustomDataset 的类,该类继承自 Dataset 类,用于创建自定义数据集。
2. def __init__(self, csv_file, root_dir, transform=None)::定义了类的初始化方法,接受三个参数:csv_file 表示包含标签信息的 CSV 文件路径,root_dir 表示图像文件所在的根目录,transform 表示数据转换操作,默认为 None。
3. self.labels_df = pd.read_csv(csv_file): 从给定的 CSV 文件中读取标签信息并存储在 labels_df 中。
4. self.root_dir = root_dir:将图像文件的根目录路径存储在 root_dir 中。
5. self.transform = transform:存储数据转换操作,例如将图像转换为张量等。
6. def __len__(self)::定义了 __len__ 方法,返回数据集的长度,即标签信息的数量。
7. def __getitem__(self, idx)::定义了 __getitem__ 方法,用于获取数据集中特定索引 idx 处的图像及其标签。
8. img_name = os.path.join(self.root_dir, self.labels_df.iloc[idx, 0]):构建图像文件的完整路径。
9. try...except...:尝试打开图像文件,如果文件不存在则捕获 FileNotFoundError 异常并打印错误信息。
10. label = int(self.labels_df.iloc[idx, 1]):从标签数据中提取标签信息,转换为整数类型。
11. if self.transform::检查是否存在数据转换操作。
12. image = self.transform(image):如果存在数据转换操作,则对图像进行相应的转换。
13. return image, label:返回处理后的图像及其对应的标签。
c. 配置数据集及加载器
( 由于这个代码和下载并配置CIFAR-10数据集及加载器的代码差不多,刚才仔细讲过了,所以这里就不再讲一遍了)
我们用的是ResNet-18网络,要想更好的理解这个网络,我们需要了解一个知识点----残差块。
在 ResNet-18 中,残差块起着关键的作用,通过引入跳跃连接(skip connection)来缓解深层神经网络中的梯度消失问题,从而使得训练更深层的网络成为可能。具体来说:
1. 跳跃连接:在每个残差块中,通过将输入直接与输出相加(即跳跃连接),实现了从底层到顶层的直接信息传递。这种跳跃连接有助于梯度的流动,避免了梯度在深层网络中逐渐消失的问题。
2. 缓解梯度消失:由于跳跃连接的存在,即使在深层网络中,梯度可以通过跳跃连接直接传播到较浅层,从而减轻了梯度消失问题,使得网络更容易训练。
3. 增强网络性能:残差块的设计使得网络更加深层时仍能保持较好的性能,因为网络可以更好地学习残差(即残差块的输出与输入之间的差异),而不是直接学习原始特征。
了解后,我们要了解一下网络的结构图:
经典CNN网络:Resnet18网络结构输入和输出[通俗易懂]-腾讯云开发者社区-腾讯云 (tencent.com)
(网上有很多资料,我随便找了一个,应该还是比较容易的)
接下来,我们讲下代码:
(1) 残差块
1. class Residual(nn.Module)::定义了一个名为 Residual 的类,继承自 nn.Module 类,表示这是一个 PyTorch 模型。
2. def __init__(self, input_channels, num_channels, use_1x1conv=False, strides=1)::定义了类的初始化方法,接受输入通道数 input_channels、输出通道数 num_channels、是否使用 1x1 卷积 use_1x1conv 和步幅 strides 作为参数。
3. super().__init__():调用父类的初始化方法。
4. self.conv1 = nn.Conv2d(input_channels, num_channels, kernel_size=3, padding=1, stride=strides): 创建第一个卷积层,使用 3x3 的卷积核,填充为 1,步幅为 strides。
5. self.conv2 = nn.Conv2d(num_channels, num_channels, kernel_size=3, padding=1): 创建第二个卷积层,输入通道数为 num_channels,输出通道数为 num_channels,使用 3x3 的卷积核,填充为 1。
6. if use_1x1conv::检查是否使用 1x1 卷积。
7. self.conv3 = nn.Conv2d(input_channels, num_channels, kernel_size=1, stride=strides): 如果使用 1x1 卷积,创建一个 1x1 的卷积层。
8. self.bn1 = nn.BatchNorm2d(num_channels): 创建第一个批量归一化层。
9. self.bn2 = nn.BatchNorm2d(num_channels): 创建第二个批量归一化层。
10. def forward(self, X)::定义了前向传播方法,接受输入 X。
11. Y = F.relu(self.bn1(self.conv1(X))): 应用第一个卷积层、批量归一化和 ReLU 激活函数。
12. Y = self.bn2(self.conv2(Y)): 应用第二个卷积层和批量归一化。
13. if self.conv3::检查是否存在第三个卷积层。
14. X = self.conv3(X): 如果存在第三个卷积层,应用该卷积层。
15. Y += X: 将输入 X(或经过 1x1 卷积层的 X)加到 Y 上,实现残差连接。
16. return F.relu(Y): 返回经过激活函数处理后的输出 Y。
(2) ResNet-18 网络
(这段的讲解放在了代码里面)
1. lr = 0.001: 定义了学习率为 0.001,即优化器在更新模型参数时的步长大小。
2. optimizer = torch.optim.Adam(net.parameters(), lr=lr): 创建了一个 Adam 优化器,用于更新模型 net 中的参数。Adam 是一种常用的优化算法,通过调整学习率来最小化损失函数。
3. loss = nn.CrossEntropyLoss(): 创建了一个交叉熵损失函数,用于计算模型输出与真实标签之间的损失。交叉熵损失通常用于多分类问题,特别是在输出层使用 softmax 激活函数时。
附赠:用CIFAR-10数据集操作的代码(20轮,准确率大概在80%左右)
代码1和代码2都差不多,代码1和今天讲的差不多就改了一下数据集,代码2删减了一部分更改了一些,更为简单一点
代码1:
代码2:
到此这篇resnet18网络结构分类(resnet200网络结构)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/rfx/47091.html