EfficientNet模型Pytorch版本具体实现

EfficientNet模型原理:EfficientNet:对模型深度、宽度和分辨率的混合缩放策略-CSDN博客

一、激活函数:

EfficientNet模型使用了Swish激活函数而不是更常见的Relu激活函数

1、公式定义

  • Swish(x) = x * sigmoid(x)
  • 是一个平滑的非线性激活函数

2、优势分析

  • 相比 ReLU:
    • 平滑可导
    • 允许负值通过
    • 不会出现梯度消失问题
  • 相比 Sigmoid:
    • 无上界限制
    • 计算更简单
    • 梯度更稳定

3、实现原理

class Swish(nn.Module):
    def forward(self, x):
        return x * torch.sigmoid(x)  # 自门控机制

4、性能特点

  • 在深层网络中表现更好
  • 训练更稳定
  • 有助于模型收敛
  • 适合 EfficientNet 这样的大型网络

5、自适应性

  • 当 x < 0 时,趋近于 0
  • 当 x > 0 时,近似线性
  • 动态调节信息流

二、自适应特征提取模块:

1、目的

  • 自适应学习特征通道间的重要性
  • 增强有用特征,抑制不重要特征
  • 提高模型对特征的利用效率

2、核心步骤

  • Squeeze(压缩):将空间信息压缩为通道描述符
  • Excitation(激发):学习通道间的相互依赖关系
  • Scale(缩放):对原始特征进行重标定

3、具体实现

class SEModule(nn.Module):
    def __init__(self, channels, se_ratio):
        super(SEModule, self).__init__()
        # 将特征图压缩为 1x1:[B,C,H,W] -> [B,C,1,1]
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        # 两个全连接层(使用卷积层实现),通过激活函数 ReLU 和 Sigmoid 来实现特征图的压缩
        self.fc1 = nn.Conv2d(channels, int(channels * se_ratio), kernel_size=1, bias=False)
        # 稀疏化特征:负值置零,减少信息冗余
        self.relu = nn.ReLU(inplace=True)
        self.fc2 = nn.Conv2d(int(channels * se_ratio), channels, kernel_size=1, bias=False)
        # 特征重标定:将特征图的每个通道的重要性系数压缩到 0~1 之间(归一化)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        # out是每个通道的重要性系数
        out = self.avg_pool(x)
        out = self.fc1(out)
        out = self.relu(out)  # max(0,x)
        out = self.fc2(out)
        out = self.sigmoid(out)  # 1/(1+e^(-x))
        return x * out

三、MBConvBlock:

1、具体实现:

class MBConvBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, expand_ratio, se_ratio, drop_rate):
        super(MBConvBlock, self).__init__()
        self.expand_ratio = expand_ratio
        self.stride = stride
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.swish = Swish()

        # 扩张阶段
        self.expanded_channels = int(in_channels * expand_ratio)
        if expand_ratio > 1:
            self.expand_conv = nn.Conv2d(in_channels, self.expanded_channels, kernel_size=1, bias=False)
            self.expand_bn = nn.BatchNorm2d(self.expanded_channels)

        # 深度可分离卷积阶段
        # 每个通道独立进行空间卷积
        self.depthwise_conv = nn.Conv2d(self.expanded_channels, self.expanded_channels, kernel_size=kernel_size,
                                        stride=stride, groups=self.expanded_channels, bias=False, padding=kernel_size//2)
        self.depthwise_bn = nn.BatchNorm2d(self.expanded_channels)

        # SE注意力模块
        self.se = SEModule(self.expanded_channels, se_ratio)

        # 输出阶段
        self.project_conv = nn.Conv2d(self.expanded_channels, out_channels, kernel_size=1, bias=False)
        self.project_bn = nn.BatchNorm2d(out_channels)
        self.dropout = nn.Dropout(drop_rate)

    def forward(self, x):
        out = x
        if self.expand_ratio > 1:
            out = self.expand_conv(out)
            out = self.expand_bn(out)
            out = self.swish(out)

        out = self.depthwise_conv(out)
        out = self.depthwise_bn(out)
        out = self.swish(out)

        out = self.se(out)

        out = self.project_conv(out)
        out = self.project_bn(out)
        out = self.dropout(out)

        if self.in_channels == self.out_channels and self.stride == 1:
            out = out + x
        return out

 2、卷积层分析:

2.1、扩张阶段 (当 expand_ratio > 1)

  • 1x1 卷积层: self.expand_conv

2.2、深度可分离卷积阶段

  • KxK 深度卷积: self.depthwise_conv

2.3、SE模块中的卷积

  • 1x1 降维卷积: self.fc1
  • 1x1 升维卷积: self.fc2

2.4、输出阶段

  • 1x1 投影卷积: self.project_conv

2.5、总结:

  • 当 expand_ratio > 1 时:共 5 个卷积层
    • 1个扩张卷积
    • 1个深度卷积
    • 2个SE模块卷积
    • 1个投影卷积
  • 当 expand_ratio = 1 时:共 4 个卷积层
    • 不包含扩张卷积
    • 其他层保持不变

四、宽度与深度扩展:

1、深度扩展

向上取整确保至少保持原有深度

def _round_repeats(self, repeats, depth_multiplier):
    """计算模块的重复次数"""
    return int(math.ceil(depth_multiplier * repeats))

2、宽度扩展

确保通道数是8的倍数,便于硬件优化

def _round_filters(self, filters, width_multiplier):
        """计算卷积层的输出通道数"""
        filters *= width_multiplier
        new_filters = max(8, int(filters + 4) // 8 * 8)
        # 确保通道数不会减少超过10%
        if new_filters < 0.9 * filters:
            new_filters += 8
        return int(new_filters)

五、完整模型:

1、具体实现:

class EfficientNet(nn.Module):
    def __init__(self, width_multiplier=1.0, depth_multiplier=1.0, dropout=0.2, num_classes=10):
        super(EfficientNet, self).__init__()
        self.num_classes = num_classes

        # 基础配置
        settings = [
            # expand_ratio, channels, repeats, stride, kernel_size
            [1, 16, 1, 1, 3],
            [6, 24, 2, 2, 3],
            [6, 40, 2, 2, 5],
            [6, 80, 3, 2, 3],
            [6, 112, 3, 1, 5],
            [6, 192, 4, 2, 5],
            [6, 320, 1, 1, 3]
        ]
        stem_channels = self._round_filters(32, width_multiplier)
        # Define the inverted residual blocks
        self.stem = nn.Sequential(
            nn.Conv2d(3, stem_channels, 3, stride=2, padding=1, bias=False),
            nn.BatchNorm2d(stem_channels),
            Swish()
        )

        # 构建主干网络
        self.blocks = nn.Sequential()
        input_channels = stem_channels
        total_blocks = sum(setting[2] for setting in settings)
        block_idx = 0

        for idx, (expand_ratio, channels, repeats, stride, kernel_size) in enumerate(settings):
            output_channels = self._round_filters(channels, width_multiplier)
            repeats = self._round_repeats(repeats, depth_multiplier)

            for i in range(repeats):
                drop_rate = dropout * block_idx / total_blocks
                self.blocks.add_module(f'block_{block_idx}',
                                       MBConvBlock(
                                           in_channels=input_channels,
                                           out_channels=output_channels,
                                           kernel_size=kernel_size,
                                           stride=stride if i == 0 else 1,
                                           expand_ratio=expand_ratio,
                                           se_ratio=0.25,
                                           drop_rate=drop_rate
                                       ))
                input_channels = output_channels
                block_idx += 1

        # Head
        head_channels = self._round_filters(1280, width_multiplier)
        self.head = nn.Sequential(
            nn.Conv2d(input_channels, head_channels, 1, bias=False),
            nn.BatchNorm2d(head_channels),
            Swish()
        )

        self.avgpool = nn.AdaptiveAvgPool2d(1)
        self.classifier = nn.Sequential(
            nn.Dropout(dropout),
            nn.Linear(head_channels, num_classes)
        )

    def _round_filters(self, filters, width_multiplier):
        """计算卷积层的输出通道数"""
        filters *= width_multiplier
        new_filters = max(8, int(filters + 4) // 8 * 8)
        # 确保通道数不会减少超过10%
        if new_filters < 0.9 * filters:
            new_filters += 8
        return int(new_filters)

    def _round_repeats(self, repeats, depth_multiplier):
        """计算模块的重复次数"""
        return int(math.ceil(depth_multiplier * repeats))

    def forward(self, x):
        x = self.stem(x)
        x = self.blocks(x)
        x = self.head(x)
        x = self.avgpool(x)
        x = x.flatten(1)
        x = self.classifier(x)
        return x

2、卷积层分析:

 # 基础配置
        settings = [
            # expand_ratio, channels, repeats, stride, kernel_size
            [1, 16, 1, 1, 3],
            [6, 24, 2, 2, 3],
            [6, 40, 2, 2, 5],
            [6, 80, 3, 2, 3],
            [6, 112, 3, 1, 5],
            [6, 192, 4, 2, 5],
            [6, 320, 1, 1, 3]
        ]

这里的基础配置指的是B0模型中的MBConvBlock的配置,按照这个配置, B0模型的第一个MBConvBlock由于扩张比率是1,没有扩张卷积,只有4个卷积层,从第二个MBConvBlock开始,每个MBConvBlock都有5个卷积层,并且,第二个和第三个MBConvBlock重复执行2次,第四个和第五个MBConvBlock重复执行3次,第六个MBConvBlock重复执行4次、第七个卷积层执行1次。外加最开始执行的卷积和最后执行的卷积,总共需要执行81个。

六、不同版本模型配置:

def efficient_config(model_name):
    """EfficientNet 配置"""
    params_dict = {
        # (width, depth, resolution, dropout)
        'efficientnet-b0': (1.0, 1.0, 224, 0.2),
        'efficientnet-b1': (1.0, 1.1, 240, 0.2),
        'efficientnet-b2': (1.1, 1.2, 260, 0.3),
        'efficientnet-b3': (1.2, 1.4, 300, 0.3),
        'efficientnet-b4': (1.4, 1.8, 380, 0.4),
        'efficientnet-b5': (1.6, 2.2, 456, 0.4),
        'efficientnet-b6': (1.8, 2.6, 528, 0.5),
        'efficientnet-b7': (2.0, 3.1, 600, 0.5)
    }
    return params_dict[model_name]
def build_efficientnet(model_name, num_classes=10):
    config = efficient_config(model_name)
    return EfficientNet(
        width_multiplier=config[0],
        depth_multiplier=config[1],
        dropout=config[3],
        num_classes=num_classes
    )

 

按照这个配置,B1到B7模型的outchannels和repeats为:

B1 (1.0, 1.1): 
- channels 不变
- repeats: [1, 3, 3, 4, 4, 5, 2]

B2 (1.1, 1.2):
- channels: [16, 26, 44, 88, 123, 211, 352]
- repeats: [1, 3, 3, 4, 4, 5, 2]

B3 (1.2, 1.4):
- channels: [19, 29, 48, 96, 134, 230, 384]
- repeats: [1, 3, 3, 5, 5, 6, 2]

B4 (1.4, 1.8):
- channels: [22, 34, 56, 112, 157, 269, 448]
- repeats: [2, 4, 4, 6, 6, 8, 2]

B5 (1.6, 2.2):
- channels: [26, 38, 64, 128, 179, 307, 512]
- repeats: [2, 5, 5, 7, 7, 9, 3]

B6 (1.8, 2.6):
- channels: [29, 43, 72, 144, 202, 346, 576]
- repeats: [2, 6, 6, 8, 8, 11, 3]

B7 (2.0, 3.1):
- channels: [32, 48, 80, 160, 224, 384, 640]
- repeats: [3, 7, 7, 10, 10, 13, 4]

那么B1模型需要经过111个卷积层;

那么B2模型需要经过111个卷积层;

那么B3模型需要经过126个卷积层;

那么B4模型需要经过161个卷积层;

那么B5模型需要经过191个卷积层;

那么B6模型需要经过221个卷积层;

那么B7模型需要经过271个卷积层;

七、数据处理:

使用CIAFR-10数据集:

# 数据增强
def create_transforms(image_size):
    """根据模型配置创建数据变换"""
    transform_train = transforms.Compose([
        transforms.Resize((image_size, image_size)),
        transforms.RandomHorizontalFlip(p=0.5),
        transforms.RandomRotation(15),
        transforms.RandomCrop(image_size, padding=4),
        transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
        transforms.ToTensor(),
        transforms.Normalize(mean=(0.4914, 0.4822, 0.4465), std=(0.2023, 0.1994, 0.2010))
    ])

    transform_test = transforms.Compose([
        transforms.Resize((image_size, image_size)),
        transforms.ToTensor(),
        transforms.Normalize(mean=(0.4914, 0.4822, 0.4465), std=(0.2023, 0.1994, 0.2010))
    ])

    return transform_train, transform_test


# 加载数据集
def load_data(data_path, model_name, num_gpus=4):
    config = efficient_config(model_name)
    image_size = config[2]
    transform_train, transform_test = create_transforms(image_size)
    train_dataset = datasets.CIFAR10(root=data_path, train=True, download=False, transform=transform_train)
    test_dataset = datasets.CIFAR10(root=data_path, train=False, download=False, transform=transform_test)

    batch_size = 32 * num_gpus

    train_loader = DataLoader(
        train_dataset,
        batch_size=batch_size,
        shuffle=True,
        num_workers=4 * num_gpus,  # 每个 GPU 配置 4 个工作进程
        pin_memory=True  # 加快数据传输到 GPU
    )

    test_loader = DataLoader(
        test_dataset,
        batch_size=512,
        shuffle=False,
        num_workers=4 * num_gpus,
        pin_memory=True
    )
    return train_loader, test_loader

八、训练与测试:

# 设置训练与测试
def train(model, device, train_loader, optimizer, epoch, criterion, scaler):
    model.train()
    total_loss = 0
    total_samples = 0

    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()

        with autocast('cuda'):
            output = model(data)
            loss = criterion(output, target)

        scaler.scale(loss).backward()
        scaler.step(optimizer)
        scaler.update()

        # 更精确的损失计算
        total_loss += loss.item() * data.size(0)
        total_samples += data.size(0)

        if batch_idx % 100 == 0:
            current_avg_loss = total_loss / total_samples
            print(
                f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)} '
                f'({100. * batch_idx / len(train_loader):.0f}%)]\tAVG_Loss: {current_avg_loss:.6f}'
            )
def test(model, device, test_loader, criterion):
    model.eval()
    test_loss = 0
    correct = 0
    total = len(test_loader.dataset)

    with torch.no_grad():
        pbar = tqdm(test_loader, desc='Testing')
        for data, target in pbar:
            data, target = data.to(device), target.to(device)
            output = model(data)

            # 计算批次损失
            loss = criterion(output, target)
            test_loss += loss.item() * data.size(0)  # 累积实际batch size的损失

            # 计算准确率
            pred = output.argmax(dim=1, keepdim=True)
            correct += pred.eq(target.view_as(pred)).sum().item()

            # 更新进度条信息
            acc = 100. * correct / total
            pbar.set_postfix({'Loss': f'{test_loss / total:.4f}', 'Acc': f'{acc:.2f}%'})

    avg_loss = test_loss / total
    accuracy = 100. * correct / total

    print(f'\nTest set: Average loss: {avg_loss:.4f}, '
          f'Accuracy: {correct}/{total} ({accuracy:.2f}%)\n')

    return accuracy

九、模型训练配置:

if __name__ == '__main__':
    data_path = r'你的数据地址'
    model_save_path = '你的模型保存地址'
    model_name = 'efficientnet-b3'#选择要训练的模型
    # 设置多GPU
    devices = [3, 4, 6]
    device = torch.device(f"cuda:{devices[0]}")  # 主GPU

    epoch = 40
    num_classes = 10
    print('Building model...')
    model = build_efficientnet(model_name=model_name, num_classes=num_classes)
    # 使用DataParallel包装模型
    model = nn.DataParallel(model, device_ids=devices)
    model.to(device)

    print('==> Preparing data...')
    train_loader, test_loader = load_data(data_path, model_name, num_gpus=len(devices))

    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)
    model.to(device)
    scaler = GradScaler()  # 用于缩放梯度
    print('Start training...')
    best_acc = 0
    best_epoch = 0
    for epoch in range(1, epoch + 1):
        train(model, device, train_loader, optimizer, epoch, criterion, scaler)
        acc = test(model, device, test_loader, criterion)
        if acc > best_acc:
            best_acc = acc
            best_epoch = epoch
            torch.save({
                'epoch': epoch,
                'model_state_dict': model.module.state_dict(),  # 注意这里要用.module来获取原始模型
                'accuracy': acc,
            }, model_save_path)
    print('Finished Training')
    print('Start Evaing...')
    print('train_data:')
    test(model, device, train_loader, criterion)
    print(f'Best Epoch: {best_epoch}   Best Accuracy: {best_acc:.2f}%')
    print('Finished!')

十、模型训练结果:

1、实验环境:

PyTorch2.4.0
Python3.12.7
Cuda12.0
CPUAMD EPYC 7402 24-Core Processor
GPUA30(24G)
环境Linux

2、训练配置:

optimizer = optim.Adam(model.parameters(), lr=1e-5, weight_decay=0.001)
criterion = nn.CrossEntropyLoss()
epoch=40
num_classes = 10

3、训练结果:

3.1、B0模型:

3.2、B1模型:

3.3、B2模型:

3.4、B3模型:

3.5、B4模型:

由于CIFAR-10数据集过于的小,所以对于这几个模型来说性能没有太大差距,反倒是模型越复杂性能还降低了。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Git连接远程仓库(超详细)

目录 一、Gitee 远程仓库连接 1. HTTPS 方式 2. SSH公钥方式 &#xff08;1&#xff09;账户公钥 &#xff08;2&#xff09;仓库公钥 仓库的 SSH Key 和账户 SSH Key 的区别&#xff1f;​ 二、GitHub远程仓库连接 1. HTTPS方式 2.SSH公钥方式 本文将介绍如何通过 H…

AutoMQ 流表一体新特性 Table Topic 发布: 无缝集成 AWS S3 Table 和 Iceberg

超越共享存储&#xff1a;使用 Apache Iceberg 中的 AutoMQ Table Topic 实现流处理与分析的统一 自 2023 年底官宣以来&#xff0c;AutoMQ 成功地将 Apache Kafka 从“Shared Nothing architecture”转变为“Shared Storage architecture”&#xff0c;这为京东、知乎、小红书…

Upload-labs 靶场(通关攻略)

WebShell 一句话木马: <?php eval($_POST[a])?> <?php system($_POST[a])?> 第一关&#xff08;删除前端js校验&#xff09; 删除return checkFile() 就能上传成功 第二关(抓包文件类型校验) BP抓包修改后缀 改为2.php后放行 第三关(上传php同种类型的不…

Linux —— 管理进程

一、查看进程 运行态&#xff08;Running&#xff09; 定义&#xff1a;处于运行态的进程正在 CPU 上执行指令。在单 CPU 系统中&#xff0c;同一时刻只有一个进程处于运行态&#xff1b;在多 CPU 或多核系统中&#xff0c;可能有多个进程同时处于运行态。示例&#xff1a; 当…

Linux脚本语言学习--下

4.Bash的变量 4.1.用户自定义变量 4.1.1.什么是变量 变量是计算机内存的单元&#xff0c;其中存放的值可以改变。当Shell脚本需要保存一些信息的时候&#xff0c;如一个文件名或是一个数字&#xff0c;就把他存放在一个变量中。每个变量有一个名字&#xff0c;所以很容易引用…

武汉市电子信息与通信工程职称公示了

2024年武汉市电子信息与通信工程专业职称公示了&#xff0c;本次公示通过人员有109人。 基本这已经是今年武汉市工程相关职称最后公示了&#xff0c;等待出证即可。 为什么有人好奇&#xff0c;一样的资料&#xff0c;都是业绩、论文等&#xff0c;有的人可以过&#xff0c;有的…

ModelScope-Agent(3):docker启动

目录 前两篇并没有使用到docker,但我看项目中是有docker配置的&#xff0c;不过没有在教程中写出来。学习了ragflow的docker配置流程之后&#xff0c;试一下modelscope-agent的配置。 先创建model-scope的cuda环境 conda create --name modelscope-agent python3.10 conda acti…

如何高效获取Twitter数据:Apify平台上的推特数据采集解决方案

引言 在数据分析和市场研究领域&#xff0c;Twitter&#xff08;现在的X&#xff09;数据一直是重要的信息来源。但是&#xff0c;自从Twitter更改API定价策略后&#xff0c;获取数据的成本大幅提升。本文将介绍一个经济实惠的替代方案。 为什么需要Twitter数据&#xff1f; …

MySql 中的解决某列中多个字段查询是否存在指定某个值, FIND_IN_SET 用法。

简言&#xff1a;今天公司数据库里面有个列是多个数据拼接而成的比如&#xff1a;**“,131113,749932833,749932825,749932826,749932827,749932828,749932829,”**想要通过sql 查找749932833值的列&#xff0c;很多同学第一想到的就是like 模糊匹配&#xff0c;模糊匹配不能保…

go引用包生成不了vendor的问题

比如我要引入github.com/jinzhu/gorm这个包. 1. 首先获取包 go get github.com/jinzhu/gorm 这时go.mod文件中也有这个包依赖信息了. 2. 然后构建vendor go mod vendor 结果发现vendor目录下没有生成对应的包, 而且modules.txt也注释掉这个包了. 原因是没有其进行引用, go…

基于 SSM 框架 Vue 电脑测评系统:引领电脑评测新方向

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

知识分享第三十天-力扣343.(整数拆分)

343 整数拆分 给定一个正整数 n&#xff0c;将其拆分为至少两个正整数的和&#xff0c;并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 示例 1: 输入: 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: 10 输出: 36 解释: 10 3 3 4, 3 3 4 36。 说明: 你可…

Nginx常用配置详解(1)

Nginx常用配置详解 一、全局块&#xff08;main&#xff09;配置 在Nginx的配置文件中&#xff0c;最外层的部分是全局块。这部分配置通常会影响Nginx服务器整体的运行参数。 worker_processes 作用&#xff1a;这个配置指令用于指定Nginx工作进程的数量。工作进程是Nginx处理…

力扣2300.咒语和药水的成功对数(二分法)

根据 灵茶山艾府 题解所写 题目描述&#xff1a; 给你两个正整数数组 spells 和 potions &#xff0c;长度分别为 n 和 m &#xff0c;其中 spells[i] 表示第 i 个咒语的能量强度&#xff0c;potions[j] 表示第 j 瓶药水的能量强度。 同时给你一个整数 success 。一个咒语和药…

电商大数据的几种获取渠道分享!

在当今数字化时代&#xff0c;电商大数据已成为企业决策和运营的重要基础。如何高效地获取、分析和利用这些数据&#xff0c;对于提升电商企业的竞争力至关重要。本文将详细介绍几种电商大数据的获取渠道&#xff0c;帮助电商从业者更好地掌握数据资源&#xff0c;提升业务洞察…

CQRS Design Pattern in Microservices - CQRS模式

原文链接 CQRS Design Pattern in Microservices - GeeksforGeeks 【文章看起来像是AI写的。。。 &#x1f602;&#x1f602;&#x1f602;】 简介 实现步骤 1&#xff0c;识别有界上下文&#xff1a;&#xff08;Identify Bounded Contexts:&#xff09; 2&#xff0c;命…

c语言----选择结构

基本概念 选择结构是C语言中用于根据条件判断来执行不同代码块的结构。它允许程序在不同的条件下执行不同的操作&#xff0c;使程序具有决策能力。 if语句 单分支if语句 语法格式&#xff1a; if (条件表达式) { 执行语句块; } 功能&#xff1a; 当条件表达式的值为真&#…

RK3588 , mpp硬编码rgb, 保存MP4视频文件.

RK3588 , mpp硬编码yuv, 保存MP4视频文件. ⚡️ 传送 ➡️ RK3588, FFmpeg 拉流 RTSP, mpp 硬解码转RGBRk3588 FFmpeg 拉流 RTSP, 硬解码转RGBUbuntu x64 架构, 交叉编译aarch64 FFmpeg mppCode Init MppMPP_RET init_mpp

uniapp blob格式转换为video .mp4文件使用ffmpeg工具

前言 介绍一下这三种对象使用场景 您前端一旦涉及到文件或图片上传Q到服务器&#xff0c;就势必离不了 Blob/File /base64 三种主流的类型它们之间 互转 也成了常态 Blob - FileBlob -Base64Base64 - BlobFile-Base64Base64 _ File uniapp 上传文件 现在已获取到了blob格式的…

【Linux运维】配置ssh免密登录

1.场景描述 内网环境&#xff0c;需要同步17服务器的文件到10服务器进行备份。因为每次输入密码比较繁琐&#xff0c;如果实现免密登录后&#xff0c;即可简化脚本。 要求&#xff1a;需要2台服务器-免密登录 2.方案分析 &#xff08;1&#xff09;现状&#xff1a;登录需要输…