目标检测入门:2.使用预训练的卷积神经网络

news2024/12/23 17:51:48

目录

源码下载

一、ResNet(Deep Residual Network,深度残差网络)

1.残差结构

​编辑

2.ResNet网络结构

3.pytorch搭建ResNet

二、CIFAR-10分类:ResNet预训练权重的迁移学习实践

1.CIFAR-10数据集

2.ResNet18实现CIFAR-10分类

3.训练模型

4.测试结果

三、微调模型(冻结参数训练)

1.以ResNet18为基础搭建目标检测模型

2.模型冻结训练和解冻训练

3.测试结果


源码下载

GitHub - 1578630119/Single_Object_Detection

有时想将深度学习应用于小型图像数据集,一种常用且非常高效的方法是使用预训练网络(pretrained network)。预训练网络是一个保存好的网络,之前已在大型数据集(通常是大规模图像分类任务)上训练好。如果这个原始数据集足够大且足够通用,那么预训练网络学到的特征的空间层次结果可以有效作为视觉世界的通用模型。

简单来说就是一个已经在大规模数据集上训练好的网络模型,它的卷积层的特征提取能力具有通用性,即对没有训练过的类别也有一定的特征提取能力。这些训练好的参数和模型再在自己的数据集进行训练,能较快的收敛同时有较高的准确率。

一、ResNet(Deep Residual Network,深度残差网络)

人们认为卷积层和池化层的层数越多,在图片中提取的特征信息越全,模型的学习效果也越好。但是在实际的实验中发现,不断叠加卷积层和池化层并没有出现学习效果越来越好的情况,随着层数的增加,预测效果反而越来越差。当单方面叠加卷积层和池化层时会出现梯度消失和梯度爆炸的情况。

  • 梯度消失:若每一层的误差梯度小于1,反向传播时,网络越深,梯度越趋近于0。
  • 梯度爆炸:若每一层的误差梯度大于1,反向传播时,网络越深,梯度越来越大。

ResNet是由微软亚洲研究院的何凯明等人于2015年提出,并在2016年的CVPR会议上获得最佳论文奖。该网络结构主要用于解决深度神经网络在训练过程中的梯度消失和梯度爆炸问题,从而允许网络向更深的方向发展。

1.残差结构

其核心思想是引入残差结构(Residual connections),通过将前面网络层的输入信号直接传递到后面的网络层中,如上图所示,残差结构使得梯度可以更好地在网络中流动,避免了梯度消失的问题。ResNet由多个残差块组成,每个残差块包含两个或多个卷积层,这种设计使得网络可以更加灵活地学习到不同尺度和层次的特征。

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1=nn.Conv2d(3,32,1)
        self.conv2=nn.Conv2d(32,128,1)
        self.conv3=nn.Conv2d(128,128,3,1,1)
        self.maxpool=nn.MaxPool2d((2,2))
        self.downsample=nn.Conv2d(32,32,1,2)
    def forward(self,x):
        #输入x的形状为(batch_size,channel,height,width) 假设为(8,3,320,320)
        layer1=self.conv1(x)                                #layer1(8,32,320,320)
        layer2=self.conv2(layer1)                           #layer2(8,128,320,320)
        layer3=self.conv3(layer2)                           #layer3(8,128,320,320)
        layer3=self.maxpool(layer3)                         #layer3(8,32,160,160)

        identity=self.downsample(layer1)                    #identity(8,32,160,160)
        layer4=torch.cat((layer3,identity),dim=1)    #layer4(8,160,160,160)
        return layer4

一个简单的残差模块如上面代码和结构图所示,上图的残差模块连接是通过在通道维度上进行融合叠加,前提是保证两边网络层输出特征图的尺度一致,即长宽一致,这种残差连接有效的减少梯度消失的情况。

2.ResNet网络结构

VGG-19和ResNet34的网络结构

ResNet有多个版本,包括ResNet18、ResNet34、ResNet50,ResNet101,ResNet152,ResNet后面的数字代表该版本的ResNet网络中的神经网络层数,各个版本的ResNet的网络结构如下所示,不同的ResNet版本的网络结构有所差距,但每个都采用了残差结构,最后一层卷积层的输出是将输入图像的宽高皆缩放为原本的1/32,只有通道数不相同。

3.pytorch搭建ResNet

在pytorch中可以通过torchvision来调用各个版本的ResNet,如下代码所示:

from torchvision import models

ResNet18 = models.resnet18(pretrained=False) #设置为True则使用预训练权重
ResNet34 = models.resnet34(pretrained=False)
ResNet50 = models.resnet50(pretrained=False)
ResNet101 = models.resnet101(pretrained=False)
ResNet152 = models.resnet152(pretrained=False)

其中的pretrained参数代表是否使用预训练权重,如果使用,则会下载相对于的权重加载到模型之中,这些预训练权重都是在ImageNet数据集中训练得到的。ImageNet是一个非常大的图像数据集,包含超过1400万幅图片,涵盖超过2万个类别,ResNet通过在ImageNet等大型图像分类任务上训练,可以学习到一些通用的特征和模式,这些特征和模式可以被转移到其他任务中,使得其他任务的模型更快地收敛,并提高模型的泛化能力。

也可以自己搭建ResNet网络,以下是直接代码搭建ResNet50:

import torch
import torch.nn as nn
from torch.hub import load_state_dict_from_url

#这两个模块(conv3x3和conv1x1)用于残差链接
def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
    return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
                     padding=dilation, groups=groups, bias=False, dilation=dilation)
def conv1x1(in_planes, out_planes, stride=1):
    return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)


class Bottleneck(nn.Module): #残差模块
    expansion = 4

    def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
                 base_width=64, dilation=1, norm_layer=None):
        super(Bottleneck, self).__init__()
        if norm_layer is None:
            norm_layer = nn.BatchNorm2d
        width = int(planes * (base_width / 64.)) * groups
        self.conv1 = conv1x1(inplanes, width)
        self.bn1 = norm_layer(width)
        self.conv2 = conv3x3(width, width, stride, groups, dilation)
        self.bn2 = norm_layer(width)
        self.conv3 = conv1x1(width, planes * self.expansion)
        self.bn3 = norm_layer(planes * self.expansion)
        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample
        self.stride = stride

    def forward(self, x):
        identity = x

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)

        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)

        out = self.conv3(out)
        out = self.bn3(out)

        if self.downsample is not None:
            identity = self.downsample(x)

        out += identity
        out = self.relu(out)

        return out


class ResNet(nn.Module):

    def __init__(self, block, layers, num_classes=1000, zero_init_residual=False,
                 groups=1, width_per_group=64, replace_stride_with_dilation=None,
                 norm_layer=None):
        super(ResNet, self).__init__()
        if norm_layer is None:
            norm_layer = nn.BatchNorm2d
        self._norm_layer = norm_layer

        self.inplanes = 64
        self.dilation = 1
        if replace_stride_with_dilation is None:
            replace_stride_with_dilation = [False, False, False]

        if len(replace_stride_with_dilation) != 3:
            raise ValueError("replace_stride_with_dilation should be None "
                             "or a 3-element tuple, got {}".format(replace_stride_with_dilation))
        self.groups = groups
        self.base_width = width_per_group
        self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3,
                               bias=False)
        self.bn1 = norm_layer(self.inplanes)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        self.layer1 = self._make_layer(block, 64, layers[0])
        self.layer2 = self._make_layer(block, 128, layers[1], stride=2,
                                       dilate=replace_stride_with_dilation[0])
        self.layer3 = self._make_layer(block, 256, layers[2], stride=2,
                                       dilate=replace_stride_with_dilation[1])
        self.layer4 = self._make_layer(block, 512, layers[3], stride=2,
                                       dilate=replace_stride_with_dilation[2])
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(512 * block.expansion, num_classes)

        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
            elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)

        if zero_init_residual:
            for m in self.modules():
                if isinstance(m, Bottleneck):
                    nn.init.constant_(m.bn3.weight, 0)

    def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
        norm_layer = self._norm_layer
        downsample = None
        previous_dilation = self.dilation
        if dilate:
            self.dilation *= stride
            stride = 1
        if stride != 1 or self.inplanes != planes * block.expansion:
            downsample = nn.Sequential(
                conv1x1(self.inplanes, planes * block.expansion, stride),
                norm_layer(planes * block.expansion),
            )

        layers = []
        layers.append(block(self.inplanes, planes, stride, downsample, self.groups,
                            self.base_width, previous_dilation, norm_layer))
        self.inplanes = planes * block.expansion
        for _ in range(1, blocks):
            layers.append(block(self.inplanes, planes, groups=self.groups,
                                base_width=self.base_width, dilation=self.dilation,
                                norm_layer=norm_layer))

        return nn.Sequential(*layers)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)

        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)

        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.fc(x)

        return x


def resnet50(pretrained=False, progress=True, num_classes=1000):
    model = ResNet(Bottleneck, [3, 4, 6, 3])    #对应ResNet论文中conv2_x、conv3_x、conv4_x、conv5_x调用Bottleneck次数
    model_urls = {
        'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
    }#预训练权重下载地址

    if pretrained:
        state_dict = load_state_dict_from_url(model_urls['resnet50'], model_dir='./model_data',
                                              progress=progress)
        model.load_state_dict(state_dict)   #加载预训练权重

    if num_classes != 1000: #当前分类任务的类别如果不等于1000
        model.fc = nn.Linear(512 * model.block.expansion, num_classes) #重搭全连接层
    return model


if __name__ == "__main__":
    resnet=resnet50(pretrained=True)

二、CIFAR-10分类:ResNet预训练权重的迁移学习实践

1.CIFAR-10数据集

CIFAR-10是一个常用于图像识别的小型数据集,由10个类别的60000张32x32彩色图像组成,每个类别有6000张图像。这个数据集被分为50000张训练图像和10000张测试图像,是计算机视觉领域的一个基准数据集。CIFAR-10的10个类别是:

  • 飞机(airplane)
  • 汽车(automobile)
  • 鸟(bird)
  • 猫(cat)
  • 鹿(deer)
  • 狗(dog)
  • 蛙(frog)
  • 马(horse)
  • 船(ship)
  • 卡车(trunk)

在pytorch1中加载CIFAR-10方法如下:

import torchvision

train_data = torchvision.datasets.CIFAR10(root='./data', train=True, transform=torchvision.transforms.ToTensor(),
                                              download=True)
    test_data = torchvision.datasets.CIFAR10(root='./data', train=False, transform=torchvision.transforms.ToTensor(),
                                             download=True)

2.ResNet18实现CIFAR-10分类

ResNet18模型的全连接层是处理ImageNet数据集而设置的输出结果有1000个类,因此在我们加载好ResNet的权重参数后还需要将最后一层全连接层重写,设置为输出结果为10个类。代码如下:

import torchvision
from torch import nn

def Net():
    resnet18 = torchvision.models.resnet18(pretrained=True) #调用ResNet18,并加载预训练权重
    #print(resnet18)    #打印模型结构,可以看见最后一层输出的1000个结果
    resnet18.fc = nn.Linear(512, 10)  # 重搭全连接层
    return resnet18

3.训练模型

import torchvision
import torch
from torch import nn
import torch.nn.functional as F
import numpy as np
import cv2
from torch import optim
from tqdm import tqdm
import matplotlib.pyplot as plt

learning_rate = 0.001  # 学习率
momentum = 0.5  # 使用optim.SGD(随机梯度下降)优化器时,momentum是一个重要的参数。它代表了动量(Momentum)的大小,是动量优化算法中的一个关键概
train_batch_size = 32
eval_batch_size = 128
test_batch_size = 128
trainset = torchvision.datasets.CIFAR10('./data/', train=True, download=True,  # 训练集下载
                                        transform=torchvision.transforms.Compose([
                                            torchvision.transforms.ToTensor(),  # 转换数据类型为Tensor
                                        ]))

# ------------------------------------------------------------------#
#       将训练集再划分为训练集和测试集(训练集:测试集=4:1)    #
# ------------------------------------------------------------------#
train_size = len(trainset)
indices = list(range(train_size))

# 划分索引
split = int(0.8 * train_size)
train_indices, val_indices = indices[:split], indices[split:]

# 创建训练集和验证集的子集
trainset_subset = torch.utils.data.Subset(trainset, train_indices)
valset_subset = torch.utils.data.Subset(trainset, val_indices)

# 创建数据加载器
train_loader = torch.utils.data.DataLoader(trainset_subset, batch_size=train_batch_size, shuffle=True)
eval_loader = torch.utils.data.DataLoader(valset_subset, batch_size=eval_batch_size, shuffle=False)
test_loader = torch.utils.data.DataLoader(
    torchvision.datasets.CIFAR10('./data/', train=False, download=True,  # 测试集下载
                                 transform=torchvision.transforms.Compose([
                                     torchvision.transforms.ToTensor(),
                                 ])),
    batch_size=test_batch_size, shuffle=True)


def Net():
    resnet18 = torchvision.models.resnet18(pretrained=True) #调用ResNet18,并加载预训练权重
    #print(resnet18)    #打印模型结构,可以看见最后一层输出的1000个结果
    resnet18.fc = nn.Linear(512, 10)  # 重搭全连接层
    return resnet18


model = Net()
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum)  # 优化器
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # 检测电脑是否能使用cuda训练,不行则使用cpu
model = model.to(device)
Train_Loss = []
Eval_Loss = []


def train(epoch, epochs):
    # 训练模型
    train_loss = 0
    model.train()
    pbar = tqdm(total=len(train_loader), desc=f'Epoch {epoch + 1}/{epochs}', mininterval=0.3)
    for batch_idx, (data, target) in enumerate(train_loader):  # 批次,输入数据,标签
        data = data.to(device)
        target = target.to(device)
        optimizer.zero_grad()  # 清空优化器中的梯度
        output = F.log_softmax(model(data), dim=1)  # 前向传播,获得当前模型的预测值
        loss = F.nll_loss(output, target)  # 真实值和预测值之前的损失
        loss.backward()  # 反向传播,计算损失函数关于模型中参数梯度
        optimizer.step()  # 更新模型中参数
        # 输出当前训练轮次,批次,损失等
        Train_Loss.append(loss.item())
        train_loss += loss.item()
        pbar.set_postfix(**{'train loss': train_loss / (batch_idx + 1)})
        pbar.update(1)
    return train_loss / (batch_idx + 1)


def eval(epoch, epochs):
    # 测试模型
    model.eval()
    pbar = tqdm(total=len(eval_loader), desc=f'Epoch {epoch + 1}/{epochs}', mininterval=0.3)
    eval_loss = 0
    with (torch.no_grad()):  # 仅测试模型,禁用梯度计算
        for batch_idx, (data, target) in enumerate(eval_loader):
            data = data.to(device)
            target = target.to(device)
            output = F.log_softmax(model(data), dim=1)
            loss = F.nll_loss(output, target).item()
            eval_loss += loss

            Eval_Loss.append(loss)
            pbar.set_postfix(**{'eval loss': eval_loss / (batch_idx + 1)})
            pbar.update(1)
    return eval_loss / (batch_idx + 1)


def model_fit(epochs):
    best_loss = 1e7
    for epoch in range(epochs):
        train_loss = train(epoch, epochs)
        eval_loss = eval(epoch, epochs)
        print('\nEpoch: {}\tTrain Loss: {:.6f}\tEval Loss: {:.6f}'.format(epoch + 1, train_loss, eval_loss))
        if eval_loss < best_loss:
            best_loss = eval_loss
            torch.save(model.state_dict(), 'model.pth')
    with open("Train_Loss.txt", 'w') as f:
        for num in Train_Loss:
            f.write(str(num) + '\n')
    with open("Eval_Loss.txt", 'w') as f:
        for num in Eval_Loss:
            f.write(str(num) + '\n')


def test():
    # 如果已经训练好了权重,模型直接加载权重文件进行测试#
    model_test = Net()
    model_test.load_state_dict(torch.load('model.pth'))
    model_test.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            output = F.log_softmax(model_test(data),dim=1)
            test_loss += F.nll_loss(output, target, reduction='sum').item()
            pred = output.data.max(1, keepdim=True)[1]
            correct += pred.eq(target.data.view_as(pred)).sum()
    test_loss /= len(test_loader.dataset)
    print('\nTest set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))


def demo():
    with open('Train_Loss.txt') as f:
        lines = f.readlines()
    lines = np.array(lines, dtype=np.float32)
    iters = range(1, len(lines) + 1)  # 训练步数(或迭代次数),这里简单用1到损失值的数量来表示

    # 使用plot函数绘制损失图
    plt.plot(iters, lines, marker='.')  # marker='o' 表示在数据点上显示圆圈

    # 添加标题和坐标轴标签
    plt.title('Training Loss')
    plt.xlabel('Iterations')
    plt.ylabel('Loss')

    # 显示网格(可选)
    plt.grid(True)

    # 显示图形
    plt.show()
    model_test = Net()
    examples = enumerate(test_loader)
    batch_idx, (example_data, example_targets) = next(examples)
    with torch.no_grad():
        output = model_test(example_data)
    for i in range(6):
        plt.subplot(2, 3, i + 1)
        plt.tight_layout()
        plt.imshow(example_data[i][0], cmap='gray', interpolation='none')
        plt.title("Prediction: {}".format(output.data.max(1, keepdim=True)[1][i].item()))
        plt.xticks([])
        plt.yticks([])
    plt.show()


if __name__ == "__main__":
    model_fit(100)  #训练100轮
    test()          #测试模型
    demo()          #输出损失图,测试样本

4.测试结果

无预训练权重
有预训练权重

由图可知,在无预训练权重情况下,模型训练迭代约20000次,训练集的损失收敛到最小值附近,而在有预训练权重情况下,模型训练迭代约10000次,训练集的损失收敛到最小值附近。

三、微调模型(冻结参数训练)

微调模型是一种在深度学习领域中常用的技术,这种方法指将其顶部的几层“解冻”,并将这解冻的几层和新增加的部分(新的全连接层)联合训练,其他的层冻结,即仅参与前向传播,并不进行梯度更新,这些网络层的参数会保持一直不变的状态。

在卷积神经网络中,更靠底部的层编码的是更加通用的可复用特征,即这些层在各个任务上是通用的,而更靠顶部的层编码的是更加专业化的特征,即更加针对于当前训练任务的参数。同时,通过冻结大部分参数,可以减少训练过程中的计算量和内存消耗,加快训练速度。在某些情况下,冻结参数还可以作为一种正则化手段,有助于防治模型在新任务上过拟合。

本节将利用之前的小黄人单目标价检测任务来展示微调模型。

1.以ResNet18为基础搭建目标检测模型

class Net_res(nn.Module):
    def __init__(self):
        super(Net_res, self).__init__()
        resnet18=torchvision.models.resnet18(pretrained=True)
        # ----------------------------------------------------------------------------#
        #   获取特征提取部分,从conv1到model.layer3,最终获得一个h/16,w/16,256的特征层
        # ----------------------------------------------------------------------------#
        features = list([resnet18.conv1, resnet18.bn1, resnet18.relu, resnet18.maxpool, resnet18.layer1, resnet18.layer2])
        self.features = nn.Sequential(*features)
        self.layer3=resnet18.layer3
        self.fc1 = nn.Linear(26*20*256, 1024)
        self.fc2 = nn.Linear(1024, 4)


    def forward(self, x):
        x=self.features(x)
        x=self.layer3(x)
        x = x.view(-1, 26*20*256)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

以上代码是以ResNet18为基础搭建的神经网络模型,当然大家也可以选择ResNet的其他版本,ResNet的layer4层并没有使用,只使用到ResNet的l第一层到layer3层。此时输出的特征图形状为(batch_size,256,h/16,w/16)。同时重新搭建了全连接层。

2.模型冻结训练和解冻训练

前半部分训练为冻结训练,冻结卷积神经网络中前面的卷积层,只训练最后一部分的卷积层和后面的全连接层,优化器选择Adam。后面部分训练解冻所有网络层,训练整个神经网络,优化器此时选择SGD。

    for param in model.features.parameters():   #冻结网络的features层,即resnet的第一层到layer2层
        param.requires_grad = False
    optimizer = optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)

        for param in model.features.parameters():   #解冻features层
        param.requires_grad = True
    optimizer = optim.SGD(model.parameters(), lr=1e-3, momentum=0.9, weight_decay=1e-4)

3.测试结果

对比上一章自己搭建的简单网络模型,使用ResNet搭建的模型在测试时,不仅损失值更低,预测框也更加精准,模型的每一个预测框基本都能完美的框住目标。

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

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

相关文章

该文件没有与之关联的程序来执行该操作,请安装应用,若已经安装应用,请在‘默认应用设置’页面中创建关联。

作为一个喜欢折腾桌面外观的人,我发现桌面上的快捷方式图标都有一个小箭头。于是,我按照网上的方法在注册表中删除了 IsShortcut 键。结果,重启后任务栏上的图标点击时出现了提示:“该文件没有与之关联的程序来执行该操作,请安装应用,若已经安装应用,请在‘默认应用设置…

Markdown+VSCODE实现最完美流畅写作体验

​下载VSCODE软件 安装插件 Markdown All in One &#xff1a;支持markdown的语言的&#xff1b; Markdown Preview Enhanced &#xff1a;观看写出来文档的效果&#xff1b; Paste IMage :添加图片的 Code Spell Checker检查英文单词错误&#xff1b; 基础语法 标题 #一个…

windows USB 设备驱动开发-USB描述符

配置描述符 USB 设备以一系列称为 USB 配置的接口的形式公开其功能。 每个接口由一个或多个备用设置组成&#xff0c;每个备用设置由一组端点组成。 配置描述符中描述了 USB 配置。 配置描述符包含有关配置及其接口、备用设置及其端点的信息。 每个接口描述符或备用设置均在 …

如何使用python网络爬虫批量获取公共资源数据教程?

原文链接&#xff1a;如何使用python网络爬虫批量获取公共资源数据教程&#xff1f;https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608240&idx4&snef281f66727afabfaae2066c6e92f792&chksmfa826657cdf5ef41571115328a09b9d34367d8b11415d5a5781dc4c…

Audio Processing Graphs 管理 Audio Units

Audio Processing Graphs 管理 Audio Units Audio Processing Graphs 管理 Audio UnitsAudio Processing Graph 拥有精确的 I/O UnitAudio Processing Graph 提供线程安全通过 graph "pull" 音频流 Audio Processing Graphs 管理 Audio Units audio processing grap…

Flutter——最详细(Badge)使用教程

背景 主要常用于组件叠加上圆点提示&#xff1b; 使用场景&#xff0c;消息数量提示&#xff0c;消息红点提示 属性作用backgroundColor红点背景色smallSize设置红点大小isLabelVisible是否显示offset设置红点位置alignment设置红点位置child设置底部组件 代码块 class Badge…

Go语言学习:每日一练3

Go语言学习&#xff1a;每日一练3 目录 Go语言学习&#xff1a;每日一练3方法接口继承类型断言 方法 方法是一类有接收者参数的函数。 接收者的类型定义和方法的声明必须在一个包里 type MyInt intfunc (m MyInt) Add(add int) int {return int(m) add } //OR func (m *MyInt)…

Python绘制动态股价曲线图并保存视频

用akshare库获取英伟达(股票代码&#xff1a;105.NVDA) 在2014年6月19日到2024年6月19日期间的股票的收盘价数据&#xff08;用后复权的收盘价&#xff09;&#xff1b; 基于后复权的收盘价数据&#xff0c;做一个动态股价曲线图&#xff0c;逐日显示英伟达股价的动态变化情况&…

Python28-7.1 降维算法之PCA主成分分析

降维算法是一类数据处理技术&#xff0c;主要用于将高维数据映射到低维空间中&#xff0c;从而减少数据的维度。降维不仅可以减少计算复杂度&#xff0c;提高算法性能&#xff0c;还可以帮助数据可视化。常见的降维算法包括主成分分析&#xff08;PCA&#xff09;、线性判别分析…

DP:背包问题----0/1背包问题

文章目录 &#x1f497;背包问题&#x1f49b;背包问题的变体&#x1f9e1;0/1 背包问题的数学定义&#x1f49a;解决背包问题的方法&#x1f499;例子 &#x1f497;解决背包问题的一般步骤&#xff1f;&#x1f497;例题&#x1f497;总结 ❤️❤️❤️❤️❤️博客主页&…

力扣Hot100-19删除链表的倒数第n个节点(双指针)

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[]示例 3&#xff1a;…

UCOS-III 任务调度与就绪列表管理

01. 就绪优先级位图 在实时操作系统中&#xff0c;任务调度的效率至关重要。UCOS-III通过就绪优先级位图来快速查找最高优先级的就绪任务&#xff0c;从而实现高效调度。就绪优先级位图是一个按位表示的结构&#xff0c;每个位代表一个优先级&#xff0c;当某个优先级上有任务就…

本地Windows电脑 连接 Windows 服务器

Windows电脑 连接 Windows 服务器 方式1&#xff1a;直接搜索 在电脑的搜索栏&#xff0c;输入“远程桌面连接” 可以选择点击 “打开” 或者直接按 回车键 “Enter”&#xff0c;打开 远程桌面连接 方式2&#xff1a;运行框打开服务器连接 同时按&#xff1a;Windows徽标键…

分布式数据库HBase:从零开始了解列式存储

在接触过大量的传统关系型数据库后你可能会有一些新的问题: 无法整理成表格的海量数据该如何储存? 在数据非常稀疏的情况下也必须将数据存储成关系型数据库吗? 除了关系型数据库我们是否还有别的选择以应对Web2.0时代的海量数据? 如果你也曾经想到过这些问题, 那么HBase将是…

CTF之unseping

拿到题目看不懂&#xff1f;这是难度1&#xff1f;含泪去看大佬的wp&#xff0c;写下我的自传&#xff01; <?php highlig…

常微分方程算法之编程示例十-两点狄利克雷边值问题(理查德森外推法)

目录 一、研究问题 二、C++代码 三、计算结果 一、研究问题 本节我们采用理查德森法对示例八中的两点狄利克雷边值问题进行外推求解,相应的原理及推导思路请参考: 常微分方程算法之高精度算法(Richardson法+紧差分法)_richardson外推法-CSDN博客https://blog.csdn.net/…

【SVN的使用-源代码管理工具-SVN介绍-服务器的搭建 Objective-C语言】

一、首先,我们来介绍一下源代码管理工具 1.源代码管理工具的起源 为什么会出现源代码管理工具,是为了解决源代码开发的过程中出现的很多问题: 1)无法后悔:把项目关了,无法Command + Z后悔, 2)版本备份:非空间、费时间、写的名称最后自己都忘了干什么的了, 3)版本…

【服装识别系统】图像识别+Python+人工智能+深度学习+算法模型+TensorFlow

一、介绍 服装识别系统&#xff0c;本系统作为图像识别方面的一个典型应用&#xff0c;使用Python作为主要编程语言&#xff0c;并通过TensorFlow搭建ResNet50卷积神经算法网络模型&#xff0c;通过对18种不同的服装&#xff08;‘黑色连衣裙’, ‘黑色衬衫’, ‘黑色鞋子’, …

Linux多进程和多线程(五)进程间通信-消息队列

多进程(五) 进程间通信 消息队列 ftok()函数创建消息队列 创建消息队列示例 msgctl 函数示例:在上⼀个示例的基础上&#xff0c;加上删除队列的代码 发送消息 示例: 接收消息示例 多进程(五) 进程间通信 消息队列 消息队列是一种进程间通信机制&#xff0c;它允许两个或多个…

终身免费的Navicat数据库,不需要破解,官方支持

终身免费的Navicat数据库&#xff0c;不需要破解&#xff0c;官方支持 卸载了Navicat&#xff0c;很不爽上干货&#xff0c;Navicat免费版下载地址 卸载了Navicat&#xff0c;很不爽 公司不让用那些破解的数据库软件&#xff0c;之前一直使用Navicat。换了几款其他的数据库试了…