fast.ai 深度学习笔记(三)(4)

简介: fast.ai 深度学习笔记(三)(4)

fast.ai 深度学习笔记(三)(3)https://developer.aliyun.com/article/1482898

消融研究

这是一个尝试打开和关闭模型不同部分以查看哪些部分产生哪些影响的过程,原始批量归一化论文中没有进行任何有效的消融。因此,缺失的一点是刚刚提出的这个问题——批量归一化放在哪里。这个疏忽导致了很多问题,因为原始论文实际上没有将其放在最佳位置。自那时以来,其他人已经弄清楚了这一点,当 Jeremy 向人们展示代码时,实际上放在更好位置的人们会说他的批量归一化放错了位置。

  • 尽量在每一层上都使用批量归一化。
  • 不要停止对数据进行归一化,这样使用您的数据的人就会知道您是如何对数据进行归一化的。其他库可能无法正确处理预训练模型的批量归一化,因此当人们开始重新训练时可能会出现问题。
class ConvBnNet(nn.Module):
    def __init__(self, layers, c):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 10, kernel_size=5, stride=1, padding=2)
        self.layers = nn.ModuleList([
            BnLayer(layers[i], layers[i + 1])
            for i in range(len(layers) - 1)
        ])
        self.out = nn.Linear(layers[-1], c)
    def forward(self, x):
        x = self.conv1(x)
        for l in self.layers: x = l(x)
        x = F.adaptive_max_pool2d(x, 1)
        x = x.view(x.size(0), -1)
        return F.log_softmax(self.out(x), dim=-1)
  • 代码的其余部分类似——使用BnLayer而不是ConvLayer
  • 在开始时添加了一个单个卷积层,试图接近现代方法。它具有更大的内核大小和步幅为 1。基本思想是我们希望第一层具有更丰富的输入。它使用 5x5 区域进行卷积,这使它可以尝试在该 5x5 区域中找到更有趣更丰富的特征,然后输出更大的输出(在这种情况下,是 10x5x5 个滤波器)。通常是 5x5 或 7x7,甚至是 11x11 卷积,输出相当多的滤波器(例如 32 个滤波器)。
  • 由于padding = kernel_size — 1 / 2stride=1,输入大小与输出大小相同——只是有更多的滤波器。
  • 这是尝试创建更丰富的起点的好方法。

深度批量归一化

让我们增加模型的深度。我们不能只添加更多的步幅为 2 的层,因为每次都会将图像的大小减半。相反,在每个步幅为 2 的层之后,我们插入一个步幅为 1 的层。

class ConvBnNet2(nn.Module):
    def __init__(self, layers, c):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 10, kernel_size=5, stride=1, padding=2)
        self.layers = nn.ModuleList([
            BnLayer(layers[i], layers[i+1])
            for i in range(len(layers) - 1)
        ])
        self.layers2 = nn.ModuleList([
            BnLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.out = nn.Linear(layers[-1], c)
    def forward(self, x):
        x = self.conv1(x)
        for l,l2 in zip(self.layers, self.layers2):
            x = l(x)
            x = l2(x)
        x = F.adaptive_max_pool2d(x, 1)
        x = x.view(x.size(0), -1)
        return F.log_softmax(self.out(x), dim=-1)
learn = ConvLearner.from_model_data((ConvBnNet2([10, 20, 40, 80, 160], 10), data)
%time learn.fit(1e-2, 2)
'''
A Jupyter Widget
[ 0\.       1.53499  1.43782  0.47588]                       
[ 1\.       1.28867  1.22616  0.55537]                       
CPU times: user 1min 22s, sys: 34.5 s, total: 1min 56s
Wall time: 58.2 s
'''
%time learn.fit(1e-2, 2, cycle_len=1)
'''
A Jupyter Widget
[ 0\.       1.10933  1.06439  0.61582]                       
[ 1\.       1.04663  0.98608  0.64609]                       
CPU times: user 1min 21s, sys: 32.9 s, total: 1min 54s
Wall time: 57.6 s
'''

准确率与之前相同。现在深度为 12 层,即使对于批量归一化来说也太深了。可以训练 12 层深的卷积网络,但开始变得困难。而且似乎并没有太多帮助。

ResNet

class ResnetLayer(BnLayer):
    def forward(self, x): 
        return x + super().forward(x)
class Resnet(nn.Module):
    def __init__(self, layers, c):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 10, kernel_size=5, stride=1, padding=2)
        self.layers = nn.ModuleList([
            BnLayer(layers[i], layers[i+1])
            for i in range(len(layers) - 1)
        ])
        self.layers2 = nn.ModuleList([
            ResnetLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.layers3 = nn.ModuleList([
            ResnetLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.out = nn.Linear(layers[-1], c)
    def forward(self, x):
        x = self.conv1(x)
        for l,l2,l3 in zip(self.layers, self.layers2, self.layers3):
            x = l3(l2(l(x)))
        x = F.adaptive_max_pool2d(x, 1)
        x = x.view(x.size(0), -1)
        return F.log_softmax(self.out(x), dim=-1)
  • ResnetLayer继承自BnLayer并覆盖forward
  • 然后添加一堆层,使其深度增加 3 倍,仍然可以很好地训练,只是因为x + super().forward(x)
learn = ConvLearner.from_model_data(Resnet([10, 20, 40, 80, 160], 10), data)wd=1e-5%time learn.fit(1e-2, 2, wds=wd)
'''
A Jupyter Widget
[ 0\.       1.58191  1.40258  0.49131]                       
[ 1\.       1.33134  1.21739  0.55625]                       
CPU times: user 1min 27s, sys: 34.3 s, total: 2min 1s
Wall time: 1min 3s
'''
%time learn.fit(1e-2, 3, cycle_len=1, cycle_mult=2, wds=wd)
'''
A Jupyter Widget
[ 0\.       1.11534  1.05117  0.62549]                       
[ 1\.       1.06272  0.97874  0.65185]                       
[ 2\.       0.92913  0.90472  0.68154]                        
[ 3\.       0.97932  0.94404  0.67227]                        
[ 4\.       0.88057  0.84372  0.70654]                        
[ 5\.       0.77817  0.77815  0.73018]                        
[ 6\.       0.73235  0.76302  0.73633]                        
CPU times: user 5min 2s, sys: 1min 59s, total: 7min 1s
Wall time: 3min 39s
'''
%time learn.fit(1e-2, 8, cycle_len=4, wds=wd)
'''
A Jupyter Widget
[ 0\.       0.8307   0.83635  0.7126 ]                        
[ 1\.       0.74295  0.73682  0.74189]                        
[ 2\.       0.66492  0.69554  0.75996]                        
[ 3\.       0.62392  0.67166  0.7625 ]                        
[ 4\.       0.73479  0.80425  0.72861]                        
[ 5\.       0.65423  0.68876  0.76318]                        
[ 6\.       0.58608  0.64105  0.77783]                        
[ 7\.       0.55738  0.62641  0.78721]                        
[ 8\.       0.66163  0.74154  0.7501 ]                        
[ 9\.       0.59444  0.64253  0.78106]                        
[ 10\.        0.53      0.61772   0.79385]                    
[ 11\.        0.49747   0.65968   0.77832]                    
[ 12\.        0.59463   0.67915   0.77422]                    
[ 13\.        0.55023   0.65815   0.78106]                    
[ 14\.        0.48959   0.59035   0.80273]                    
[ 15\.        0.4459    0.61823   0.79336]                    
[ 16\.        0.55848   0.64115   0.78018]                    
[ 17\.        0.50268   0.61795   0.79541]                    
[ 18\.        0.45084   0.57577   0.80654]                    
[ 19\.        0.40726   0.5708    0.80947]                    
[ 20\.        0.51177   0.66771   0.78232]                    
[ 21\.        0.46516   0.6116    0.79932]                    
[ 22\.        0.40966   0.56865   0.81172]                    
[ 23\.        0.3852    0.58161   0.80967]                    
[ 24\.        0.48268   0.59944   0.79551]                    
[ 25\.        0.43282   0.56429   0.81182]                    
[ 26\.        0.37634   0.54724   0.81797]                    
[ 27\.        0.34953   0.54169   0.82129]                    
[ 28\.        0.46053   0.58128   0.80342]                    
[ 29\.        0.4041    0.55185   0.82295]                    
[ 30\.        0.3599    0.53953   0.82861]                    
[ 31\.        0.32937   0.55605   0.82227]                    
CPU times: user 22min 52s, sys: 8min 58s, total: 31min 51s
Wall time: 16min 38s
'''

ResNet 块

return x + super().forward(x)

y = x + f(x)

其中x是来自上一层的预测,y是来自当前层的预测。重新排列公式,我们得到:公式重新排列

f(x) = y − x

差异y − x残差。残差是迄今为止我们计算的错误。这意味着尝试找到一组卷积权重,试图填补我们偏离的量。换句话说,我们有一个输入,我们有一个函数试图预测错误(即我们偏离的量)。然后我们将输入的错误预测量相加,然后再添加另一个错误预测量,然后重复这个过程,逐层放大到正确答案。这基于一种称为boosting的理论。

  • 完整的 ResNet 在将其添加回原始输入之前进行了两次卷积(我们这里只做了一次)。
  • 在每个块x = l3(l2(l(x)))中,其中一层不是ResnetLayer而是一个带有stride=2的标准卷积——这被称为“瓶颈层”。ResNet 不是卷积层,而是我们将在第 2 部分中介绍的不同形式的瓶颈块。


ResNet 2 [01:59:33]

在这里,我们增加了特征的大小并添加了 dropout。

class Resnet2(nn.Module):
    def __init__(self, layers, c, p=0.5):
        super().__init__()
        self.conv1 = BnLayer(3, 16, stride=1, kernel_size=7)
        self.layers = nn.ModuleList([
            BnLayer(layers[i], layers[i+1])
            for i in range(len(layers) - 1)
        ])
        self.layers2 = nn.ModuleList([
            ResnetLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.layers3 = nn.ModuleList([
            ResnetLayer(layers[i+1], layers[i + 1], 1)
            for i in range(len(layers) - 1)
        ])
        self.out = nn.Linear(layers[-1], c)
        self.drop = nn.Dropout(p)
    def forward(self, x):
        x = self.conv1(x)
        for l,l2,l3 in zip(self.layers, self.layers2, self.layers3):
            x = l3(l2(l(x)))
        x = F.adaptive_max_pool2d(x, 1)
        x = x.view(x.size(0), -1)
        x = self.drop(x)
        return F.log_softmax(self.out(x), dim=-1)
        
learn = ConvLearner.from_model_data(Resnet2([**16, 32, 64, 128, 256**], 10, 0.2), data)
wd=1e-6
%time learn.fit(1e-2, 2, wds=wd)
%time learn.fit(1e-2, 3, cycle_len=1, cycle_mult=2, wds=wd)
%time learn.fit(1e-2, 8, cycle_len=4, wds=wd)
log_preds,y = learn.TTA()
preds = np.mean(np.exp(log_preds),0)
metrics.log_loss(y,preds), accuracy(preds,y)
'''
(0.44507397166057938, 0.84909999999999997)
'''

85%是 2012 年或 2013 年 CIFAR 10 的最新技术。如今,它已经达到了 97%,因此还有改进的空间,但所有都基于这些技术:

  • 更好的数据增强方法
  • 更好的正则化方法
  • 对 ResNet 进行一些调整

问题[02:01:07]:我们可以将“训练残差”方法应用于非图像问题吗?是的!但是它已经被其他地方忽略了。在 NLP 中,“transformer 架构”最近出现,并被证明是翻译的最新技术,并且其中有一个简单的 ResNet 结构。这种一般方法称为“跳过连接”(即跳过一层的想法),在计算机视觉中经常出现,但似乎没有其他人多使用,尽管它与计算机视觉无关。好机会!

狗与猫 [02:02:03]

回到狗和猫。我们将创建 resnet34(如果您对尾随数字的含义感兴趣,请参阅这里——只是不同的参数)。

PATH = "data/dogscats/"
sz = 224
arch = resnet34  # <-- Name of the function 
bs = 64
m = arch(pretrained=True) # Get a model w/ pre-trained weight loaded
m
'''
ResNet(
  (conv1): Conv2d (3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
  (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
  (relu): ReLU(inplace)
  (maxpool): MaxPool2d(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), dilation=(1, 1))
  (**layer1**): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
    )
    (1): BasicBlock(
      (conv1): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
    )
    (2): BasicBlock(
      (conv1): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
    )
  )
  (layer2): Sequential(
    (0): BasicBlock(
      (conv1): Conv2d (64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (downsample): Sequential(
        (0): Conv2d (64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
        (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      )
    )
    (1): BasicBlock(
      (conv1): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
    )
    (2): BasicBlock(
      (conv1): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
    )
    (3): BasicBlock(
      (conv1): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
      (relu): ReLU(inplace)
      (conv2): Conv2d (128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
    )
  )
  ...
  (avgpool): AvgPool2d(kernel_size=7, stride=7, padding=0, ceil_mode=False, count_include_pad=True)
  (fc): Linear(in_features=512, out_features=1000)
)
'''

我们的 ResNet 模型具有 Relu → BatchNorm。TorchVision 使用 BatchNorm → Relu。有三个不同版本的 ResNet 在流传,最好的是 PreAct (arxiv.org/pdf/1603.05027.pdf)。

  • 目前,最后一层有数千个特征,因为 ImageNet 有 1000 个特征,所以我们需要摆脱它。
  • 当您使用 fast.ai 的ConvLearner时,它会为您删除最后两层。fast.ai 用自适应平均池化和自适应最大池化替换AvgPool2d,并将两者连接在一起。
  • 对于这个练习,我们将做一个简单版本。
m = nn.Sequential(*children(m)[:-2], 
    nn.Conv2d(512, 2, 3, padding=1), 
    nn.AdaptiveAvgPool2d(1), 
    Flatten(), 
    nn.LogSoftmax()
)
  • 删除最后两层
  • 添加一个只有 2 个输出的卷积。
  • 进行平均池化然后进行 softmax
  • 最后没有线性层。这是产生两个数字的不同方式——这使我们能够进行 CAM!
tfms = tfms_from_model(arch, sz, aug_tfms=transforms_side_on, max_zoom=1.1)
data = ImageClassifierData.from_paths(PATH, tfms=tfms, bs=bs)
learn = ConvLearner.from_model_data(m, data)
learn.freeze_to(-4)
learn.fit(0.01, 1)
learn.fit(0.01, 1, cycle_len=1)
  • ConvLearner.from_model是我们之前学到的——允许我们使用自定义模型创建 Learner 对象。
  • 然后冻结除了我们刚刚添加的层之外的所有层。

类激活图(CAM)[02:08:55]

我们选择一个特定的图像,并使用一种称为 CAM 的技术,询问模型哪些部分的图像被证明是重要的。



它是如何做到的?让我们逆向工作。它是通过生成这个矩阵来做到的:


大数字对应于猫。那么这个矩阵是什么?这个矩阵简单地等于特征矩阵feat乘以py向量的值:

f2=np.dot(np.rollaxis(feat,0,3), py)
f2-=f2.min()
f2/=f2.max()
f2

py 向量是预测,表示“我对这是一只猫有 100%的信心”。feat 是最终卷积层(我们添加的Conv2d层)输出的值(2×7×7)。如果我们将feat乘以py,我们会得到所有第一个通道的值,而第二个通道的值为零。因此,它将返回与猫对应的部分的最后一个卷积层的值。换句话说,如果我们将feat乘以[0, 1],它将与狗对应。

sf = SaveFeatures(m[-4])
py = m(Variable(x.cuda()))
sf.remove()
py = np.exp(to_np(py)[0]); py
'''
array([ 1.,  0.], dtype=float32)
'''
feat = np.maximum(0, sf.features[0])
feat.shape

换句话说,在模型中,卷积层之后唯一发生的事情是平均池化层。平均池化层将 7×7 的网格平均化,计算出每个部分有多少“像猫”。然后,我们将“猫样”矩阵调整大小为与原始猫图像相同的大小,并叠加在顶部,然后你就得到了热图。

您可以在家中使用这种技术的方法是:

  1. 当您有一幅大图像时,您可以在一个快速小的卷积网络上计算这个矩阵。
  2. 放大具有最高值的区域
  3. 仅在该部分重新运行

由于时间不够,我们很快跳过了这部分,但我们将在第 2 部分中学习更多关于这种方法的内容。

“Hook”是让我们要求模型返回矩阵的机制。register_forward_hook要求 PyTorch 每次计算一个层时运行给定的函数 - 类似于每次计算一个层时发生的回调。在以下情况下,它保存了我们感兴趣的特定层的值:

class SaveFeatures():
    features=None
    def __init__(self, m): 
        self.hook = m.register_forward_hook(self.hook_fn)
    def hook_fn(self, module, input, output): 
        self.features = to_np(output)
    def remove(self): 
        self.hook.remove()

Jeremy 的问题[02:14:27]:“您对深度学习的探索”和“如何跟上从业者的重要研究”

“如果您打算参加第 2 部分,您应该掌握我们在第 1 部分学到的所有技术”。以下是您可以做的一些事情:

  1. 至少观看每个视频 3 次。
  2. 确保您可以重新创建笔记本而无需观看视频 - 可能使用不同的数据集来使其更有趣。
  3. 密切关注论坛上的最新论文和最新进展。
  4. 坚持不懈,继续努力!
相关文章
|
28天前
|
人工智能 测试技术 API
AI计算机视觉笔记二十 九:yolov10竹签模型,自动数竹签
本文介绍了如何在AutoDL平台上搭建YOLOv10环境并进行竹签检测与计数。首先从官网下载YOLOv10源码并创建虚拟环境,安装依赖库。接着通过官方模型测试环境是否正常工作。然后下载自定义数据集并配置`mycoco128.yaml`文件,使用`yolo detect train`命令或Python代码进行训练。最后,通过命令行或API调用测试训练结果,并展示竹签计数功能。如需转载,请注明原文出处。
|
28天前
|
JSON 人工智能 数据格式
AI计算机视觉笔记二十六:YOLOV8自训练关键点检测
本文档详细记录了使用YOLOv8训练关键点检测模型的过程。首先通过清华源安装YOLOv8,并验证安装。接着通过示例权重文件与测试图片`bus.jpg`演示预测流程。为准备训练数据,文档介绍了如何使用`labelme`标注工具进行关键点标注,并提供了一个Python脚本`labelme2yolo.py`将标注结果从JSON格式转换为YOLO所需的TXT格式。随后,通过Jupyter Notebook可视化标注结果确保准确性。最后,文档展示了如何组织数据集目录结构,并提供了训练与测试代码示例,包括配置文件`smoke.yaml`及训练脚本`train.py`,帮助读者完成自定义模型的训练与评估。
|
13天前
|
机器学习/深度学习 人工智能 自然语言处理
探索AI的未来:深度学习与自然语言处理的融合
【9月更文挑战第22天】本文旨在探讨AI技术中深度学习与自然语言处理的结合,以及它们如何共同推动未来技术的发展。我们将通过实例和代码示例,深入理解这两种技术如何相互作用,以及它们如何影响我们的生活和工作。
34 4
|
24天前
|
机器学习/深度学习 人工智能 自然语言处理
探索AI的奥秘:深度学习与神经网络
【9月更文挑战第11天】本文将深入探讨人工智能的核心领域——深度学习,以及其背后的神经网络技术。我们将从基础理论出发,逐步深入到实践应用,揭示这一领域的神秘面纱。无论你是AI领域的初学者,还是有一定基础的开发者,都能在这篇文章中获得新的启示和理解。让我们一起踏上这场探索之旅,揭开AI的神秘面纱,体验深度学习的魅力。
|
28天前
|
人工智能 并行计算 PyTorch
AI计算机视觉笔记十八:Swin Transformer目标检测环境搭建
本文详细记录了Swin Transformer在AutoDL平台上的环境搭建与训练过程。作者从租用GPU实例开始,逐步介绍了虚拟环境的创建、PyTorch安装、mmcv及mmdetection的配置,并解决了安装过程中遇到的各种问题,如cython版本冲突等。最后,通过修改代码实现目标检测结果的保存。如需了解更多细节或获取完整代码,请联系作者。原文链接:[原文链接](请在此处插入原文链接)。
|
28天前
|
机器学习/深度学习 人工智能 PyTorch
AI计算机视觉笔记三十二:LPRNet车牌识别
LPRNet是一种基于Pytorch的高性能、轻量级车牌识别框架,适用于中国及其他国家的车牌识别。该网络无需对字符进行预分割,采用端到端的轻量化设计,结合了squeezenet和inception的思想。其创新点在于去除了RNN,仅使用CNN与CTC Loss,并通过特定的卷积模块提取上下文信息。环境配置包括使用CPU开发板和Autodl训练环境。训练和测试过程需搭建虚拟环境并安装相关依赖,执行训练和测试脚本时可能遇到若干错误,需相应调整代码以确保正确运行。使用官方模型可获得较高的识别准确率,自行训练时建议增加训练轮数以提升效果。
|
28天前
|
人工智能 开发工具 计算机视觉
AI计算机视觉笔记三十:yolov8_obb旋转框训练
本文介绍了如何使用AUTODL环境搭建YOLOv8-obb的训练流程。首先创建虚拟环境并激活,然后通过指定清华源安装ultralytics库。接着下载YOLOv8源码,并使用指定命令开始训练,过程中可能会下载yolov8n.pt文件。训练完成后,可使用相应命令进行预测测试。
|
28天前
|
人工智能 PyTorch 算法框架/工具
AI计算机视觉笔记二十二:基于 LeNet5 的手写数字识别及训练
本文介绍了使用PyTorch复现LeNet5模型并检测手写数字的过程。通过搭建PyTorch环境、安装相关库和下载MNIST数据集,实现了模型训练与测试。训练过程涉及创建虚拟环境、安装PyTorch及依赖库、准备数据集,并编写训练代码。最终模型在测试集上的准确率达到0.986,满足预期要求。此项目为后续在RK3568平台上部署模型奠定了基础。
|
28天前
|
人工智能 并行计算 测试技术
AI计算机视觉笔记三十一:基于UNetMultiLane的多车道线等识别
该项目基于开源数据集 VIL100 实现了 UNetMultiLane,用于多车道线及车道线类型的识别。数据集中标注了六个车道的车道线及其类型。项目详细记录了从环境搭建到模型训练与测试的全过程,并提供了在 CPU 上进行训练和 ONNX 转换的代码示例。训练过程约需 4 小时完成 50 个 epoch。此外,还实现了视频检测功能,可在视频中实时识别车道线及其类型。
|
28天前
|
传感器 人工智能 算法
AI计算机视觉笔记二十七:YOLOV8实现目标追踪
本文介绍了使用YOLOv8实现人员检测与追踪的方法。通过为每个人员分配唯一ID,实现持续追踪,并可统计人数,适用于小区或办公楼出入管理。首先解释了目标检测与追踪的区别,接着详细描述了使用匈牙利算法和卡尔曼滤波实现目标关联的过程。文章提供了基于IOU实现追踪的具体步骤,包括环境搭建、模型加载及追踪逻辑实现。通过示例代码展示了如何使用YOLOv8进行实时视频处理,并实现人员追踪功能。测试结果显示,该方法在实际场景中具有较好的应用潜力。
下一篇
无影云桌面