Pytorch代码复现AlexNet

AlexNet网络架构

AlexNet整体的网络结构包括:1个输入层、5个卷积层、2个全连接层和1个输出层。

输入层(Input Layer)

AlexNet输入图像的尺寸为227*227*3,并非论文中的224*224*3

卷积层(C1)

处理流程是:卷积->ReLU->局部响应归一化->池化

卷积:输入为227*227*3,使用96个11*11*3的卷积核进行卷积,padding=0,stride=4,根据公式:(input_size + 2 * padding - kernel_size) / stride + 1=(227+2*0-11)/4+1=55,得到输出是55*55*96。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

局部响应归一化:局部响应归一化层简称LRN,是在深度学习中提高准确度的技术方法。一般是在激活、池化后进行。LRN对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。

LRN公式如下:

 a为归一化之前的神经元,b为归一化之后的神经元;N是卷积核的个数,也就是生成的FeatureMap的个数;k,α,β,n是超参数,论文中使用的值是k=2,n=5,α=0.0001,β=0.75。

局部响应归一化后仍为55*55*96。单个GPU上的大小为55*55*48

池化使用3*3,stride=2的池化单元进行max pooling。(55+2*0-3)/2+1=27, 输出的大小为27*27*48

卷积层(C2)

该层的处理流程是:卷积-->ReLU-->局部响应归一化(LRN)-->池化

卷积:两组输入均是27x27x48,各组分别使用128个5x5x48的卷积核进行卷积,padding=2,stride=1,根据公式:(input_size + 2 * padding - kernel_size) / stride + 1=(27+2*2-5)/1+1=27,得到每组输出是27x27x128。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

局部响应归一化:使用参数k=2,n=5,α=0.0001,β=0.75进行归一化。每组输出仍然是27x27x128。

池化:使用3x3,stride=2的池化单元进行最大池化操作(max pooling)。注意这里使用的是重叠池化,即stride小于池化单元的边长。根据公式:(27+2*0-3)/2+1=13,每组得到的输出为13x13x128。

卷积层(C3)

该层的处理流程是: 卷积-->ReLU

卷积:输入是13x13x256,使用384个3x3x256的卷积核进行卷积,padding=1,stride=1,根据公式:(input_size + 2 * padding - kernel_size) / stride + 1=(13+2*1-3)/1+1=13,得到输出是13x13x384。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。将输出其分成两组,每组FeatureMap大小是13x13x192,分别位于单个GPU上。

卷积层(C4)

该层的处理流程是:卷积-->ReLU

卷积:两组输入均是13x13x192,各组分别使用192个3x3x192的卷积核进行卷积,padding=1,stride=1,根据公式:(input_size + 2 * padding - kernel_size) / stride + 1=(13+2*1-3)/1+1=13,得到每组FeatureMap输出是13x13x192。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

卷积层(C5)

该层的处理流程是:卷积-->ReLU-->池化

卷积:两组输入均是13x13x192,各组分别使用128个3x3x192的卷积核进行卷积,padding=1,stride=1,根据公式:(input_size + 2 * padding - kernel_size) / stride + 1=(13+2*1-3)/1+1=13,得到每组FeatureMap输出是13x13x128。

ReLU:将卷积层输出的FeatureMap输入到ReLU函数中。

池化:使用3x3,stride=2的池化单元进行最大池化操作(max pooling)。注意这里使用的是重叠池化,即stride小于池化单元的边长。根据公式:(13+2*0-3)/2+1=6,每组得到的输出为6x6x128。

全连接层(FC6)

该层的流程为:(卷积)全连接 -->ReLU -->Dropout (卷积)

全连接:输入为6×6×256,使用4096个6×6×256的卷积核进行卷积,由于卷积核尺寸与输入的尺寸完全相同,即卷积核中的每个系数只与输入尺寸的一个像素值相乘一一对应,根据公式:(input_size + 2 * padding - kernel_size) / stride + 1=(6+2*0-6)/1+1=1,得到输出是1x1x4096。既有4096个神经元,该层被称为全连接层。

ReLU:这4096个神经元的运算结果通过ReLU激活函数中。

Dropout:随机的断开全连接层某些神经元的连接,通过不激活某些神经元的方式防止过拟合。4096个神经元也被均分到两块GPU上进行运算。

全连接层(FC7)

该层的流程为:(卷积)全连接 -->ReLU -->Dropout

全连接:输入为4096个神经元,输出也是4096个神经元(作者设定的)。

ReLU:这4096个神经元的运算结果通过ReLU激活函数中。

Dropout:随机的断开全连接层某些神经元的连接,通过不激活某些神经元的方式防止过拟合。

4096个神经元也被均分到两块GPU上进行运算。

输出层(Output Layer)

该层的流程为:(卷积)全连接 -->Softmax

全连接:输入为4096个神经元,输出是1000个神经元。这1000个神经元即对应1000个检测类别。

Softmax:这1000个神经元的运算结果通过Softmax函数中,输出1000个类别对应的预测概率值。

AlexNet创新之处

Data Augmentation

在本文中,作者采用了两种数据增强(data augmentation)方法,分别是:

  • 镜像反射和随机剪裁
  • 改变训练样本RGB通道的强度值

镜像反射和随机剪裁的做法是,先对图像做镜像反射,然后在原图和镜像反射的图(256×256)中随机裁剪227×227的区域。

改变训练样本RGB通道的强度值,做法是对RGB空间做PCA(主成分分析),然后对主成分做一个(0, 0.1)的高斯扰动,也就是对颜色、光照作变换,结果使错误率又下降了1%。

激活函数ReLU

反向传播中,ReLU有输出的部分,导数始终为1。而且ReLU会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。

局部响应归一化

局部响应归一化(LRN)对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。

Dropout

dropout是神经网络中比较常用的抑制过拟合的方法。在神经网络中Dropout通过修改神经网络本身结构来实现,对于某一层的神经元,通过定义的概率将神经元置为0,这个神经元就不参与前向和后向传播,就如同在网络中被删除了一样,同时保持输入层与输出层神经元的个数不变,然后按照神经网络的学习方法进行参数更新。在下一次迭代中,又重新随机删除一些神经元(置为0),直至训练结束。

在AlexNet网络中,全连接层FC6、FC7就使用了Dropout方法。

Dropout也可以看成是一种模型组合,每次生成的网络结构都不一样,通过组合多个模型的方式能够有效地减少过拟合,Dropout只需要两倍的训练时间即可实现模型组合(类似取平均)的效果,非常高效。

重叠池化

在以前的CNN中普遍使用平均池化层(average pooling),AlexNet全部使用最大池化层 max pooling。避免了平均池化层的模糊化的效果,并且步长比池化的核的尺寸小,这样池化层的输出之间有重叠,提升了特征的丰富性。重叠池化可以避免过拟合,这个策略贡献了0.3%的Top-5错误率。

双GPU训练

双GPU网络的训练时间比单GPU网络更少。

端到端训练

AlexNet网络,CNN的输入直接是一张图片,而当时比较多的做法是先使用特征提取算法对RGB图片进行特征提取。AlexNet使用了端对端网络,除了将每个像素中减去训练集的像素均值之外,没有以任何其他方式对图像进行预处理,直接使用像素的RGB值训练网络。

模型代码

import torch
import torch.nn as nn

class AlexNet(nn.Module):
    def __init__(self, num_classes=1000, init_weights=False):
        super(AlexNet, self).__init__()

        # 特征提取层(卷积层)
        self.features = nn.Sequential(
            # Conv1
            nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),# 输入通道数 输出通道数[3, 244, 244]->[48, 55, 55]
            nn.ReLU(inplace=True), #inplace=True:对上一层Conv2d中传递下来的tensor直接进行修改,不用多存储一份变量
            nn.MaxPool2d(kernel_size=3, stride=2), # [48, 27, 27]

            # Conv2
            nn.Conv2d(48, 128, kernel_size=5, stride=1, padding=2),# [128, 27, 27]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),# [128, 13, 13]

            # Conv3
            nn.Conv2d(128, 192, kernel_size=3, stride=1, padding=1),# [192, 13, 13]
            nn.ReLU(inplace=True),
            
            # Conv4
            nn.Conv2d(192, 192, kernel_size=3, stride=1, padding=1),# [192, 13, 13]
            nn.ReLU(inplace=True),
        
            # Conv5
            nn.Conv2d(192, 128, kernel_size=3, stride=1, padding=1),# [128, 13, 13]
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2)# [128, 6, 6]
        )

        # 全连接层
        self.classifier = nn.Sequential(
            # FC_1
            nn.Dropout(p=0.5),
            nn.Linear(128*6*6, 2048),# in_features[128, 6, 6], out_features[2048]
            nn.ReLU(inplace=True),

            # FC_2
            nn.Dropout(p=0.5),
            nn.Linear(2048, 2048),
            nn.ReLU(inplace=True),

            # FC_3
            nn.Linear(2048, num_classes)
        )

        if init_weights:
            self._initialize_weights() #初始化权重
        
    def forward(self, x):
        x=self.features(x)
        x=torch.flatten(x,start_dim=1) #进入FC前,flatten函数将向量拉平
        x=self.classifier(x)
        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)
    
if __name__ == "__main__":
    model = AlexNet()
    print(model)

训练集

下载数据集:https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz

 数据集包含:玫瑰、雏菊、向日葵、郁金香、蒲公英5类。

数据划分

对数据集中的train进行了划分,按照9:1的比例划分为train和valid 

import os
from shutil import copy, rmtree
import random


def mk_file(file_path: str):
    if os.path.exists(file_path):
        # 如果文件夹存在,则先删除原文件夹在重新创建
        rmtree(file_path)
    os.makedirs(file_path)


def main():
    # 保证随机可复现
    random.seed(0)

    # 将数据集中10%的数据划分到验证集中
    split_rate = 0.1

    # 指向你解压后的flower_photos文件夹
    cwd = os.getcwd()
    data_root = os.path.join(cwd, "flower_data")
    origin_flower_path = os.path.join(data_root, "flower_photos")
    assert os.path.exists(origin_flower_path), "path '{}' does not exist.".format(origin_flower_path)

    flower_class = [cla for cla in os.listdir(origin_flower_path)
                    if os.path.isdir(os.path.join(origin_flower_path, cla))]

    # 建立保存训练集的文件夹
    train_root = os.path.join(data_root, "train")
    mk_file(train_root)
    for cla in flower_class:
        # 建立每个类别对应的文件夹
        mk_file(os.path.join(train_root, cla))

    # 建立保存验证集的文件夹
    val_root = os.path.join(data_root, "val")
    mk_file(val_root)
    for cla in flower_class:
        # 建立每个类别对应的文件夹
        mk_file(os.path.join(val_root, cla))

    for cla in flower_class:
        cla_path = os.path.join(origin_flower_path, cla)
        images = os.listdir(cla_path)
        num = len(images)
        # 随机采样验证集的索引
        eval_index = random.sample(images, k=int(num*split_rate))
        for index, image in enumerate(images):
            if image in eval_index:
                # 将分配至验证集中的文件复制到相应目录
                image_path = os.path.join(cla_path, image)
                new_path = os.path.join(val_root, cla)
                copy(image_path, new_path)
            else:
                # 将分配至训练集中的文件复制到相应目录
                image_path = os.path.join(cla_path, image)
                new_path = os.path.join(train_root, cla)
                copy(image_path, new_path)
            print("\r[{}] processing [{}/{}]".format(cla, index+1, num), end="")  # processing bar
        print()

    print("processing done!")


if __name__ == '__main__':
    main()

训练

import torch
import torch.nn as nn
from torchvision import transforms, datasets, utils
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from model import AlexNet
import os
import json
import time

# 选择训练硬件
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("训练方式为:",device)

# 定义训练集和测试集的数据转换方式
preprocess = { # dict, "key":"value"
    "train": transforms.Compose([
        transforms.RandomResizedCrop((224, 224)),# 使用224*244的窗口随机裁剪
        transforms.RandomHorizontalFlip(),# 水平翻转
        transforms.ToTensor(),# PIL Image转Tensor,自动[0, 255]归一化到[0, 1]
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))# 对数据进行归一化 参数1为mean 参数2为std 
                                                              # 图片为3通道所以mean和std也是3通道的
    ]),

    "valid": transforms.Compose([
        transforms.Resize((224,244)),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5),(0.5, 0.5, 0.5))# 标准化,即减均值,除以标准差
    ])
}

# 返回表示当前工作目录的 unicode 字符串
data_root = os.getcwd()
img_path = data_root + "/flower_data/"

# 定义训练、验证集路径和预处理方式
train_dataset = datasets.ImageFolder(root=img_path + "train", transform=preprocess["train"])
valid_dataset = datasets.ImageFolder(root=img_path + "valid", transform=preprocess["valid"])

train_num = len(train_dataset)
valid_num = len(valid_dataset)

# 定义class类别标签的list
classes_dict = train_dataset.class_to_idx
# 将上面的字典中key和value翻转
cls_dict = dict((val,key) for key, val in classes_dict.items())

# 将cls_dict这个字典写进json文件中
json_str = json.dumps(cls_dict, indent=4) # 将字典转化为字符串

# 将json_str这个变量写入硬盘,名称为:class_indices.json
with open('class_indices.json','w') as json_file:
    json_file.write(json_str)

batch_size = 32

# 加载数据集、验证集 train_loader是可迭代对象
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
# print(iter(train_loader).next())  打印第一个batch(batch_size张图片的数据,末尾是batch_size张图片的标签)
valid_loader = DataLoader(dataset=valid_dataset, batch_size=batch_size, shuffle=True)
# 查看预处理后验证集图片
# test_data_iter = iter(valid_loader)
# test_img, test_label = test_data_iter.next()# test_img中含有batch_size个图片(经过预处理后的图片),test_label中含有batch_size个标签
# print(test_img, test_label)

# 取出第0张图片,进行属性的查看和可视化
# print(test_img[0].size(), type(test_img[0]))  # torch.Size([3, 224, 224]) <class 'torch.Tensor'>
# print(test_label[0], test_label[0].item(), type(test_label[0]))  # tensor(4) 4 <class 'torch.Tensor'> —— Tensor格式可以通过.item()转化为numpy的格式

# 显示图片
def imshow(img):
    img = img / 2 + 0.5 # 反归一化
    npimg = img.numpy() # tensor转为numpy,才可正常显示
    plt.imshow(np.transpose(npimg, (1, 2, 0))) # 因为图片的size()为[3, 224, 224],所以我们需要把它变为[224, 224, 3])
    plt.show()
    
model = AlexNet(num_classes=5, init_weights=True)
model.to(device)

loss_function = nn.CrossEntropyLoss()
# optimizer = optim.SGD(params=model.parameters(), lr=8e-4, momentum=0.9, weight_decay=5e-4)
optimizer = optim.Adam(model.parameters(),lr=8e-4)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', factor=0.8, patience=10, threshold=0.001)

save_path = "./[flower_data]AlexNet.pth"
num_epoch = 200

# 开始训练
best_acc = 0.0
lr_values = []
train_acc_values = []
train_loss_values = []
val_acc_values = []
val_loss_values = []
for epoch in range(num_epoch):
    train_acc = 0.0
    train_loss = 0.0
    val_acc = 0.0
    val_loss = 0.0

    # train
    model.train()
    running_loss = 0.0
    t1 = time.perf_counter()
    for step, data in enumerate(train_loader, start=0):
        imgs, labels = data
        imgs = imgs.to(device)
        labels = labels.to(device)

        optimizer.zero_grad()
        outputs = model(imgs)

        loss = loss_function(outputs, labels)
        loss.backward()
        optimizer.step()

        _, train_pred = torch.max(outputs, 1)
        train_acc += (train_pred.detach() == labels.detach()).sum().item()
        train_loss += loss.item()

    train_acc_epoch = train_acc / len(train_dataset)
    train_acc_values.append(train_acc_epoch)
    train_loss_values.append(train_loss/len(train_loader))
    lr_values.append(optimizer.param_groups[0]['lr'])

    #valid
    model.eval()
    with torch.no_grad():
        for val_data in valid_loader:
            val_imgs, val_labels = val_data
            val_imgs = val_imgs.to(device)
            val_labels = val_labels.to(device)
            outputs = model(val_imgs)
            # print(outputs.size())  # torch.Size([32, 5])
            
            loss = loss_function(outputs, val_labels)

            _, val_pred = torch.max(outputs, 1)
            val_acc += (val_pred.cpu() == val_labels.cpu()).sum().item()
            val_loss += loss.item()

        val_acc_epoch = val_acc / len(valid_dataset)
        val_acc_values.append(val_acc_epoch)
        val_loss_values.append(val_loss/len(valid_loader))

        print(f'[{epoch+1:03d}/{num_epoch:03d}] Train Acc: {train_acc/len(train_dataset):3.5f} Loss: {train_loss/len(train_loader):3.5f} | Val Acc: {val_acc/len(valid_dataset):3.5f} loss: {val_loss/len(valid_loader):3.5f}')
        # 保存不同epoch中验证集准确率最高的那个
        if val_acc > best_acc:
            best_acc = val_acc
            torch.save(model.state_dict(), save_path)
            print(f'saving model with acc {best_acc/len(valid_dataset):.5f}')
        
        scheduler.step(val_acc/len(valid_dataset))
print("Training Finished!")

# 查看梯度
for name, param in model.named_parameters():
    if param.requires_grad and param.grad is not None:
        print(name, param.grad.abs().mean().item())

plt.figure()
plt.plot(train_loss_values, label='Train Loss', color='blue')
plt.plot(val_loss_values, label='Validation Loss', color='orange')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()

plt.figure()
plt.plot(train_acc_values, label='Train Accuracy', color='blue')
plt.plot(val_acc_values, label='Validation Accuracy', color='orange')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()
plt.show()

plt.figure()
plt.plot(lr_values, label='Learning Rate')
plt.xlabel('Epoch')
plt.ylabel('lr')
plt.title('Learning Rate')
plt.legend()
plt.show()

结果与优化

SGD(0.87363)

optimizer = optim.SGD(params=model.parameters(), lr=8e-4, momentum=0.9, weight_decay=5e-4)

使用SGD lr=8e-4 epoch=200结果如下:

adam(0.83791)

optimizer = optim.Adam(model.parameters(), lr=8e-4)

 

SGD+ReduceLROnPlateau(0.86264)

optimizer = optim.SGD(params=model.parameters(), lr=8e-4, momentum=0.9, weight_decay=5e-4)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', factor=0.9, patience=15, threshold=0.001)

  

 

adam+ReduceLROnPlateau(0.85440)

optimizer = optim.Adam(model.parameters(),lr=8e-4)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='max', factor=0.8, patience=10, threshold=0.001)

 

参考 

手撕 CNN 经典网络之 AlexNet(理论篇) - 知乎 

[PyTorch]AlexNet代码复现_alexnet复现pytorch-CSDN博客 

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 您好,以下是使用PyTorch复现YOLOv4的代码: 1. 首先,您需要下载YOLOv4的权重文件,可以从以下链接中下载: https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights 2. 接下来,您需要安装PyTorch和OpenCV库,可以使用以下命令进行安装: ``` pip install torch pip install opencv-python ``` 3. 然后,您可以使用以下代码加载YOLOv4的权重文件并进行目标检测: ``` import cv2 import torch import numpy as np # 加载YOLOv4的权重文件 model = torch.hub.load('ultralytics/yolov5', 'yolov4', pretrained=True) # 加载图像 img = cv2.imread('test.jpg') # 进行目标检测 results = model(img) # 显示检测结果 results.show() ``` 其中,'test.jpg'是您要进行目标检测的图像文件名。 希望以上代码能够帮助到您。 ### 回答2: YOLOv4是目前最先进的物体检测算法之一,它结合了YOLOv3 和 Scaled-YOLOv4的优势,具有更高的召回率和准确度。PyTorch是一种常用的深度学习框架,可以快速实现深度学习算法。 实现YOLOv4的方法有多种,其中一种是基于开源代码进行复现。 首先,需要准备数据集。数据集应包含图片和对应的标签,标签一般以XML或JSON格式保存。YOLOv4要求输入的图片尺寸是416x416,因此需要对原始图片进行缩放。可以使用OpenCV库来实现。 然后,需要下载YOLOv4的预训练模型文件。可以从互联网上下载Darknet和PyTorch版本的模型文件。Darknet版本的模型文件通常以.weights格式保存,而PyTorch版本的模型文件通常以.pt格式保存。这两种格式都可以通过相应的代码进行加载和转换。 接下来,需要编写Python程序来实现YOLOv4的物体检测功能。可以使用PyTorch和其它相关库来实现。具体的代码实现可以分为以下几步: 1. 加载预训练模型 利用PyTorch中的torch.load函数,将预训练模型加载到内存中。 2. 定义模型 定义模型的结构,包括卷积层、池化层、残差块和最终的检测层。 3. 加载图片和标签 使用相应的库读取图片和标签,并将其转换为张量形式。 4. 图像预处理 对图片进行预处理,包括缩放、裁剪、归一化和转换为张量形式。 5. 模型推理 将图片输入模型,获取物体检测的结果。检测结果包括物体类别、位置和置信度。 6. 后处理 将检测结果进行后处理,包括筛选、非极大值抑制和将边界框转换为坐标形式。 最后,运行程序即可实现YOLOv4的物体检测功能。需要注意的是,YOLOv4的精度和速度都非常高,但是在硬件资源和算法优化方面的要求也比较高。为了实现最佳的检测效果,需要进行一系列的细节优化。 ### 回答3: YOLOv4是一个非常流行的目标检测模型,由于其高效性能和较高的准确率,成为了许多研究人员的选择。在本文中,我们将介绍如何使用PyTorch复现YOLOv4的代码。 1. 数据集的准备: 在复现YOLOv4模型之前,我们需要准备一个数据集来训练模型。数据集应该包含许多训练图片和对应的标注信息。通常情况下,标注信息包括每张图片中目标的类别、位置和大小信息。 2. 下载YOLOv4的模型代码使用以下命令从GitHub上下载YOLOv4的代码: ``` !git clone https://github.com/WongKinYiu/yolov4-pytorch.git ``` 3. 修改文件夹结构: 为了更好地适应我们的数据集,我们需要修改YOLOv4代码库的文件夹结构。在代码库的“data”目录下新建“custom”目录,将训练数据集拷贝至该目录下,并在“data/custom”目录下创建“images”和“labels”两个子目录,分别存放数据集的图片和标注信息。 4. 修改配置文件: 在“cfg”目录下找到“yolov4.cfg”文件,修改该文件以适应我们的数据集。具体来说,需要将模型的输入大小修改为我们训练数据集的大小,修改检测头的类别数量为我们数据集中目标的种类数。 5. 训练模型: 要训练模型,我们需要运行如下命令: ``` !python train.py --cfg cfg/yolov4.cfg --data data/custom/custom.data --weights '' --name yolov4-custom ``` 其中,“--cfg”指定配置文件路径,“--data”指定数据集信息文件路径,“--name”指定训练模型的名称。 6. 应用模型: 我们可以使用训练得到的模型来检测新的图片。运行以下命令即可进行检测: ``` !python detect.py --weights checkpoints/yolov4-custom.pth --img-size 416 --conf-thres 0.3 --source data/samples/ ``` 其中,“--weights”指定使用的模型路径,“--img-size”指定输入图片的大小,“--conf-thres”指定过滤掉置信度较低的边界框,“--source”指定检测的图片路径。 在以上过程中,我们可以根据实际情况进行修改以适应我们的数据集。通过修改数据集、配置文件和运行命令,我们可以使用PyTorch复现YOLOv4模型,从而实现目标检测的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值