news 2026/8/28 6:05:47

YOLOX目标检测:无锚框设计、SimOTA与解耦头技术解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOX目标检测:无锚框设计、SimOTA与解耦头技术解析

1. 项目概述:为什么YOLOX值得你花时间精读?

如果你在2021年之后接触过目标检测,尤其是YOLO系列,那么“YOLOX”这个名字你一定不陌生。这篇名为《YOLOX: Exceeding YOLO Series in 2021》的论文,在当时就像一颗投入平静湖面的石子,激起了不小的波澜。很多人可能觉得,不就是YOLO系列又出了个新版本吗?但如果你真的深入去读,会发现它远不止一个简单的版本迭代。它更像是一个“设计哲学”的转折点,正式宣告了YOLO系列从“锚框依赖”时代迈向了“无锚框”时代,并且引入了一套非常精巧的、端到端的训练策略。

我最初读这篇论文时,正被YOLOv5的各种锚框先验和复杂的正负样本匹配规则搞得有点头疼。YOLOX的出现,让我眼前一亮。它用相对简洁清晰的架构,在速度和精度上实现了对同期YOLO模型的全面超越,尤其是在COCO数据集上的表现,让人印象深刻。这篇论文不仅是一个强大的模型,更是一份优秀的“工程实现指南”,里面很多设计选择,比如解耦头、SimOTA标签分配策略,都成为了后续很多工作的基石。无论你是想深入理解现代目标检测器的演进逻辑,还是正在寻找一个既快又准的基线模型来启动你的项目,精读YOLOX论文都是一笔稳赚不赔的时间投资。

2. 核心思想拆解:YOLOX如何实现“青出于蓝”?

YOLOX的目标很明确:在不引入大量额外计算开销的前提下,显著提升YOLO系列模型的性能,特别是精度。它没有选择重新发明轮子,而是在当时公认的优秀基线(如YOLOv3、YOLOv5)上进行了一系列关键改进。其核心思想可以概括为三个支柱:无锚框(Anchor-Free)设计、先进的标签分配策略(SimOTA)、以及一个解耦的检测头(Decoupled Head)。这三者相互配合,共同构成了YOLOX性能飞跃的基础。

2.1 从锚框到无锚框:为何要“自废武功”?

在YOLOX之前,YOLO系列(以及当时绝大多数单阶段检测器)严重依赖“锚框”。锚框可以理解为预先定义在特征图每个位置的一系列大小、宽高比固定的候选框。模型的任务是预测这些锚框的偏移量和类别。这套机制有两个明显的痛点:

  1. 超参数敏感:锚框的数量、大小、宽高比需要针对特定数据集进行仔细设计和调整(比如用K-means聚类统计)。换一个数据集,或者数据分布稍有变化,原有的锚框设置可能就不再最优,需要重新调参,这增加了工程负担和不确定性。
  2. 复杂度与歧义:每个位置需要预测多个锚框(例如YOLOv3是3个),这增加了计算量和模型复杂度。同时,一个真实物体可能被多个锚框匹配,在训练时会产生歧义,不利于模型收敛。

YOLOX果断转向了“无锚框”范式。具体来说,它让特征图上的每个位置直接预测4个值:到目标框左上角和右下角的相对偏移量。同时,每个位置还预测一个“物体度”分数和类别概率。这极大地简化了检测流程。你可能会有疑问:去掉锚框这个强有力的先验,性能不会下降吗?答案是,通过后续更精密的标签分配策略(SimOTA),模型能够更智能、更动态地决定哪些位置负责预测哪个物体,从而弥补甚至超越了锚框带来的先验优势。

2.2 SimOTA:动态且最优的标签分配策略

标签分配是目标检测训练的核心环节,即决定特征图上的哪些位置(或锚框)负责预测哪个真实物体,以及哪些是负样本(背景)。YOLOX提出的SimOTA(简化版的最优传输分配)是论文的一大亮点,也是其性能提升的关键。

传统的静态分配规则(如基于IoU的阈值分配)存在固有问题:一个真实物体可能只分配给少数几个IoU最高的锚框,而其他IoU稍低但仍有潜力的位置被忽略;或者,一个“简单”物体会被分配过多的正样本,而“困难”物体分配到的正样本却不足。这会导致训练效率低下和样本不平衡。

SimOTA将标签分配视为一个“最优传输”问题:把真实物体(供给)分配给预测位置(需求),目标是使得整体的匹配代价最小。这个代价综合了分类代价(预测类别与真实类别的差异)和回归代价(预测框与真实框的差异)。SimOTA的“简化”体现在它通过一些启发式方法(如仅为每个真实物体选择代价最小的前k个预测进行匹配)来降低原始OTA算法的计算复杂度,使其能够应用于实际训练。

注意:SimOTA是动态的,意味着在每一轮训练、每一张图片上,匹配关系都可能根据当前模型的预测能力重新计算。这使得模型能够自适应地学习,让更擅长预测某个物体的位置去负责它,极大地提升了训练效率和解耦头的性能。

2.3 解耦头:让专业的人做专业的事

在YOLOv3等早期模型中,检测头是“耦合”的:一个卷积层同时输出分类置信度和边框坐标。分类和回归任务的目标存在内在冲突(一个关注语义,一个关注位置),共享参数可能会相互干扰。

YOLOX引入了解耦头。它先用一个共享的1x1卷积进行降维,然后并行使用两个独立的小型分支网络(通常由两个3x3卷积组成)分别处理分类和回归任务。这样做的好处非常直观:

  1. 任务专精:分类分支可以更专注于学习判别性特征,回归分支可以更专注于学习精细的空间偏移,互不干扰。
  2. 加速收敛:解耦的结构使得两个任务更容易优化,实验表明,即使不改变特征提取主干网络,仅使用解耦头就能带来显著的AP提升。
  3. 兼容性强:这个解耦头设计简洁通用,后来被许多其他检测器借鉴或作为改进的起点。

3. 模型架构与实现细节深度解析

理解了核心思想,我们深入到YOLOX的具体架构实现。论文中以YOLOv3-Darknet53为基线进行了改造,但它的设计是模块化的,可以轻松迁移到其他主干网络(如CSPDarknet, ResNet等)上。

3.1 整体架构 pipeline

YOLOX的整体流程可以清晰地分为几个阶段:

  1. 主干网络:输入图像经过一个特征提取主干网络(如Darknet53, CSPDarknet)。论文中主要使用了修改后的CSPDarknet,它通过跨阶段部分连接来丰富梯度流,在保持精度的同时减少参数量。
  2. 特征金字塔网络:主干网络输出多尺度的特征图(例如,下采样率为8, 16, 32倍)。这些特征图被送入一个加强版的PANet(Path Aggregation Network)结构中。PANet通过自底向上和自顶向下的路径,将深层语义特征和浅层位置特征进行充分融合,使得每个尺度的特征图都同时具备丰富的语义信息和精确的位置信息,这对于检测不同大小的物体至关重要。
  3. 解耦检测头:经过FPN/PANet融合后的多尺度特征图,被送入解耦头。这是YOLOX的核心组件之一。对于每个尺度的特征图,解耦头会输出三个部分:
    • 回归输出:每个位置预测4个值(dx, dy, dw, dh),表示预测框相对于该网格点的偏移和尺寸对数。
    • 对象度输出:每个位置预测1个值,表示该位置存在物体的置信度(区别于类别置信度)。
    • 分类输出:每个位置预测C个值(C为类别数),表示属于各个类别的概率。
  4. 无锚框解码:在推理时,直接将特征图上的网格点坐标,加上预测的偏移量,即可得到最终的预测框坐标,完全无需锚框先验。
  5. SimOTA训练:在训练时,利用预测结果和真实标签,通过SimOTA算法动态地为每个真实物体分配正样本(特征图上的位置),并计算损失。

3.2 损失函数设计

YOLOX的损失函数由三部分组成,与解耦头的三个输出一一对应:

  1. 回归损失:采用IoU Loss的变种,通常是GIoU Loss或CIoU Loss。这些损失函数不仅衡量框的重叠面积,还考虑了中心点距离和宽高比的一致性,能提供更准确的回归梯度。论文中默认使用IoU Loss。
    • L_reg = λ_reg * Σ(1 - IoU(pred_box, gt_box)),其中求和是针对所有被分配为正样本的位置。
  2. 分类损失:采用标准的二元交叉熵损失(BCE Loss)或Focal Loss(用于缓解正负样本不平衡)。YOLOX通常对每个类别独立使用BCE。
    • L_cls = λ_cls * Σ[BCE(cls_pred, cls_gt)]
  3. 对象度损失:同样使用二元交叉熵损失。这个损失衡量的是该位置是否有物体,是一个二分类问题。
    • L_obj = λ_obj * Σ[BCE(obj_pred, obj_gt)]。其中,obj_gt对于SimOTA分配的正样本位置为1,其余为0。

总损失是这三项的加权和:L_total = L_reg + L_cls + L_obj。权重系数λ需要在训练前根据任务进行平衡调整。

3.3 数据增强与训练技巧

除了模型结构创新,YOLOX的成功也离不开一系列强力的训练时数据增强和技巧:

  • Mosaic与MixUp:这是从YOLOv4开始流行的高强度数据增强。Mosaic将四张训练图像拼接成一张,让模型学习在不同上下文中识别尺度变化很大的物体。MixUp则将两张图像线性混合,增加了数据的多样性。YOLOX在训练的最后若干轮(如最后15个epoch)会关闭Mosaic和MixUp,并缩小训练图像尺寸,进行“微调”,这被证明能显著提升模型的最终精度,避免模型过度依赖增强后的“非自然”图像分布。
  • 余弦学习率调度:使用余弦退火策略来调整学习率,使其在训练初期缓慢热身,中期平稳,后期缓慢下降至零,有助于模型更稳定地收敛到更好的局部最优解。
  • EMA(指数移动平均):在训练过程中,维护一个模型权重的滑动平均版本。在验证和测试时,使用这个平均后的模型,通常能获得更稳定、泛化能力更强的性能。

4. 关键代码实现与实操指南

理论说得再多,不如动手实现一遍。这里我们以PyTorch框架为例,拆解YOLOX最核心的几个模块的实现。请注意,以下代码是高度简化和示意性的,旨在阐明原理,完整的实现请参考官方开源代码。

4.1 解耦头的PyTorch实现

import torch import torch.nn as nn import torch.nn.functional as F class DecoupledHead(nn.Module): def __init__(self, in_channels, num_classes, num_anchors=1): # 无锚框,num_anchors默认为1 super().__init__() self.num_classes = num_classes # 共享的降维层 self.shared_conv = nn.Conv2d(in_channels, 256, kernel_size=1) # 两个独立的并行分支 # 分类分支:预测类别概率 self.cls_convs = nn.Sequential( nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.BatchNorm2d(256), nn.SiLU(), # YOLOX使用SiLU激活函数(Swish) nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.BatchNorm2d(256), nn.SiLU(), ) self.cls_pred = nn.Conv2d(256, num_classes, kernel_size=1) # 回归分支:预测框坐标和物体度 self.reg_convs = nn.Sequential( nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.BatchNorm2d(256), nn.SiLU(), nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.BatchNorm2d(256), nn.SiLU(), ) # 输出通道为4(dx, dy, dw, dh)+ 1(obj) self.reg_pred = nn.Conv2d(256, 5, kernel_size=1) def forward(self, x): # x: 输入特征图 [B, C, H, W] x = self.shared_conv(x) cls_feat = self.cls_convs(x) cls_output = self.cls_pred(cls_feat) # [B, num_classes, H, W] reg_feat = self.reg_convs(x) reg_output = self.reg_pred(reg_feat) # [B, 5, H, W] # 将回归输出拆分为框坐标和物体度 bbox_pred = reg_output[:, :4, :, :] # [B, 4, H, W] obj_pred = reg_output[:, 4:5, :, :] # [B, 1, H, W] # 通常会将输出展平,便于后续处理 # 形状变为 [B, H*W, num_classes] 和 [B, H*W, 4], [B, H*W, 1] cls_output = cls_output.flatten(2).permute(0, 2, 1) bbox_pred = bbox_pred.flatten(2).permute(0, 2, 1) obj_pred = obj_pred.flatten(2).permute(0, 2, 1) # 将物体度预测与分类预测结合(可选,也可在损失计算时处理) # 最终输出格式可以根据需要调整 outputs = { 'cls': cls_output, 'reg': bbox_pred, 'obj': obj_pred, 'grid': ... # 通常还需要传递特征图对应的网格坐标 } return outputs

4.2 SimOTA标签分配的核心步骤(伪代码逻辑)

SimOTA的实现较为复杂,以下是其核心逻辑的伪代码描述,帮助理解:

def simota_assign(predictions, gt_boxes, gt_labels, topk=10, cost_weight=[3.0, 5.0]): """ predictions: 模型预测,包含分类分数和预测框 gt_boxes: 一张图片中的真实框 [M, 4] gt_labels: 真实框的类别 [M] topk: 为每个gt初步筛选的候选预测数量 cost_weight: 分类代价和回归代价的权重 [cls_weight, reg_weight] """ num_gt = gt_boxes.shape[0] num_pred = predictions['cls'].shape[1] # 1. 计算成对的分类代价 # cls_scores: [num_pred, num_classes] -> 取对应gt类别的分数 cls_cost = -predictions['cls'][:, gt_labels] # 负对数似然形式,分数越高代价越小 # 2. 计算成对的回归代价(IoU Loss) # pred_boxes: [num_pred, 4] # gt_boxes: [num_gt, 4] # pair_wise_iou = calculate_iou(pred_boxes, gt_boxes) # [num_pred, num_gt] reg_cost = -torch.log(pair_wise_iou + 1e-8) # IoU越大,代价越小 # 3. 计算总代价矩阵 # cost_matrix: [num_pred, num_gt] cost_matrix = cost_weight[0] * cls_cost + cost_weight[1] * reg_cost # 4. 动态选择每个gt的正样本数量 # 根据预测框与gt的IoU,动态决定每个gt匹配多少个正样本(k) # 例如,iou_topk = topk_iou(pair_wise_iou, topk) # [num_gt, topk] # iou_sum = iou_topk.sum(dim=1) # [num_gt] # dynamic_ks = torch.clamp(iou_sum.int(), min=1) # 每个gt至少分配1个 # 5. 为每个gt选择代价最小的前dynamic_ks个预测作为候选正样本 # matching_matrix = torch.zeros_like(cost_matrix) # [num_pred, num_gt] # for gt_idx in range(num_gt): # k = dynamic_ks[gt_idx] # _, topk_indices = torch.topk(cost_matrix[:, gt_idx], k, largest=False) # matching_matrix[topk_indices, gt_idx] = 1 # 6. 处理冲突:一个预测框只能匹配给一个gt(代价最小的那个) # 遍历所有预测框,如果它被分配给多个gt,则只保留代价最小的那个匹配。 # 7. 生成最终的标签 # matched_gt_indices: 每个正样本预测框对应的gt索引 [-1表示负样本] # matched_gt_boxes/labels: 对应的真实框和类别 return matched_gt_indices, matched_gt_boxes, matched_gt_labels

4.3 训练一个简化版YOLOX的步骤

  1. 环境准备:安装PyTorch(>=1.7)、TorchVision、OpenCV、pycocotools等库。
  2. 数据准备:将你的数据集转换为COCO格式,或者使用YOLO格式并通过脚本转换。确保有images文件夹和annotations.json文件。
  3. 模型构建
    • 选择一个主干网络(如torchvision.models.resnet50,移除最后的全连接层和平均池化层)。
    • 实现FPN/PANet特征金字塔。
    • 将上述DecoupledHead附加到每个金字塔层级的输出上。
  4. 数据加载与增强
    • 实现Mosaic和MixUp数据增强。可以使用Albumentations库简化操作。
    • DataLoader中应用,注意在训练末期(如最后15个epoch)关闭Mosaic/MixUp并减小输入尺寸。
  5. 损失计算与训练循环
    • 在每批次数据前向传播后,你会得到多尺度的预测。
    • 调用simota_assign函数(或类似实现)为当前批次的预测分配真实标签。
    • 根据分配结果,计算回归损失(IoU Loss)、分类损失(BCEWithLogitsLoss)和物体度损失(BCEWithLogitsLoss)。
    • 反向传播,更新权重。同时,可以使用torch.optim.lr_scheduler.CosineAnnealingLR配合热身(Warmup)来调整学习率。
    • 可选地,使用torch.optim.swa_utils.AveragedModel实现EMA。
  6. 模型验证与推理
    • 推理时,关闭数据增强,使用EMA模型(如果用了的话)。
    • 将多尺度预测合并,经过置信度阈值过滤和非极大值抑制(NMS)后,得到最终检测结果。

5. 实战经验、常见问题与调优技巧

在实际复现和应用YOLOX的过程中,我踩过不少坑,也总结了一些能让模型跑得更稳、效果更好的经验。

5.1 训练不稳定或精度不达标?

  • 学习率与Batch Size:YOLOX对学习率比较敏感。如果从头开始训练,务必使用学习率热身(Warmup)。例如,在前几个epoch内,将学习率从一个小值(如1e-6)线性增加到预设的主学习率(如1e-2)。Batch Size越大,通常可以承受更高的学习率。如果资源有限只能用小Batch Size,请相应降低学习率。
  • SimOTA的超参数topk(候选数)和cost_weight(分类/回归代价权重)是关键。论文默认值(topk=10/20cost_weight=[3.0, 5.0])是一个很好的起点。如果发现模型分类不准但定位还行,可以尝试增大分类代价的权重;反之亦然。topk太小可能导致正样本不足,太大会增加计算开销并引入噪声。
  • 数据增强的强度:Mosaic和MixUp的强度需要根据数据集调整。对于小数据集,强增强非常有用;但对于已经很大的数据集,过强的增强可能有害。观察训练损失曲线,如果损失震荡剧烈或下降缓慢,可以尝试减弱增强强度。
  • 关闭增强的时机:在训练末期关闭Mosaic/MixUp并finetune是提升精度的关键一步。通常是在总epoch数的最后10%-20%进行。同时,将输入尺寸缩小到标准尺寸(如从640x640降到416x416或352x352),这有助于模型专注于学习更“自然”的图像特征,修正因强增强带来的偏差。

5.2 推理速度慢怎么办?

  • 模型简化:YOLOX提供了Nano、Tiny、Small、Medium、Large、X-Large等多个规格。根据你的硬件和实时性要求选择合适的版本。在边缘设备上,YOLOX-Nano或YOLOX-Tiny是很好的起点。
  • 解耦头的优化:解耦头虽然效果好,但增加了参数量和计算量。在一些对速度极度敏感的场景,可以尝试简化解耦头的结构(如减少卷积层数或通道数),或者探索更轻量化的头设计(如共享更多的底层特征)。
  • 后处理优化:NMS是推理时的一个瓶颈。可以尝试:
    • 使用更快的NMS实现,如torchvision.ops.nms或CUDA加速的NMS。
    • 调整NMS的阈值iou_threshold和置信度阈值score_threshold。适当提高置信度阈值可以大幅减少进入NMS的框数量。
    • 对于固定场景,可以考虑使用Batch NMS来并行处理一批图片。
  • 模型部署优化:使用TensorRT、OpenVINO、ONNX Runtime等推理引擎对模型进行量化(INT8)、层融合和图优化,通常能获得数倍的推理加速。

5.3 在小目标或密集目标上表现不佳?

  • 特征金字塔设计:确保你的FPN/PANet能够有效融合浅层高分辨率特征。有时需要增加更浅层的特征图输出(如下采样4倍的特征)来专门检测极小目标。
  • 标签分配策略:SimOTA本身是动态的,但初始的topk选择可能对小目标不友好。因为小目标在特征图上的响应区域小,匹配到的正样本位置自然就少。可以尝试针对小目标适当增加topk值,或者在计算代价时,给予小目标更高的权重,确保它们能分配到足够的正样本进行学习。
  • 数据增强:Mosaic增强天生有利于模型学习识别不同尺度的目标,对小目标检测有奇效。确保你的Mosaic实现中,小目标不会被缩放到几乎看不见的程度。
  • 损失函数:回归损失使用CIoU Loss通常比GIoU Loss对大小目标的匹配都更友好,因为它明确考虑了宽高比的相似性。

5.4 与其他YOLO版本的对比与选型建议

  • vs YOLOv5:YOLOv5在YOLOX发布时是主流,它基于锚框,拥有非常成熟的工程生态和丰富的预训练模型。YOLOX的无锚框设计使其在调参上更简单(无需聚类锚框),并且在精度上通常有优势,尤其是在跨领域泛化上。如果你的项目需要快速部署且数据集与COCO类似,YOLOv5的易用性很高。如果你追求更高精度且愿意接受一些新的实现,YOLOX是更好的选择。
  • vs YOLOv7/YOLOv8:YOLOv7和YOLOv8是更晚出现的版本,它们吸收了包括YOLOX在内的许多先进思想(如解耦头、无锚框设计),并在模型结构重参数化、训练策略等方面做了更多创新,通常代表了更高的性能基准。YOLOv8更是提供了完整的分类、检测、分割模型套件。从学习和演进的角度,精读YOLOX是理解后续v7、v8中许多设计选择的最佳切入点。如果你要从零开始实现一个现代检测器,YOLOX的代码和思想是最清晰、最经典的范本之一。
  • 选型总结
    • 学习与研究:必读YOLOX论文,必读其官方代码。它是理解无锚框和动态标签分配的经典材料。
    • 工业部署与快速原型:优先考虑YOLOv5或YOLOv8,因为它们社区活跃,教程、预训练模型和部署工具链极其丰富。
    • 追求极致精度:在相同复杂度下,YOLOX通常比同期的锚框式YOLO有优势。但可以将其与YOLOv7、YOLOv8进行对比测试,选择最适合你数据集的模型。

精读并动手实现YOLOX,不仅仅是为了复现一个模型,更是为了深入理解现代目标检测器是如何通过改进标签分配、简化预测头这些“非主干”部分来获得巨大性能提升的。这种对训练过程本身进行精细设计的思路,比单纯堆叠更深的网络或更复杂的模块,往往能带来更高的性价比。当你吃透了YOLOX,再去看其他更复杂的检测器,你会发现很多设计都似曾相识,其演进脉络也会清晰得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 6:05:41

SPSS非参数检验实战指南:处理非正态数据的统计方法

1. 项目概述:当数据不“听话”时,我们如何做决策?在数据分析的日常工作中,我们常常会遇到一些“不完美”的数据。比如,你想比较两种新教学方法对学生成绩的影响,但收集到的成绩数据分布严重偏斜&#xff0c…

作者头像 李华
网站建设 2026/8/28 6:05:26

蓝桥杯国赛Python算法实战复盘:从动态规划到位运算博弈

1. 项目概述:一次算法实战的深度复盘 最近在整理硬盘里的老项目,翻到了2021年蓝桥杯Python组国赛的代码和笔记。作为当年那场“算法马拉松”的亲历者,现在回头看,那些题目依然充满了挑战和启发性。蓝桥杯国赛,对于很多…

作者头像 李华
网站建设 2026/8/28 6:04:55

Google DeepMind换帅背后:AI进入产品化时代,开发者生态成新战场

最近 AI 圈一条人事变动让很多人停下脚步:Google DeepMind 的 CEO 换人了,而老掌门人 Demis Hassabis 并没有离开 Google,而是退到了更宏观的位置上。消息传到开发者社区,最常见的反应是:“这人谁啊?哈萨比…

作者头像 李华
网站建设 2026/8/28 6:03:16

从手工搜关键词到每日品牌简报:一种可审计的微博监测流程

品牌监测常见的做法是:运营每天搜索品牌名,挑出几条值得关注的内容,再贴进群里。问题不只是费时间,还包括口径不一致、遗漏难复盘、历史结果无法比较。weibo-cli 可以把微博搜索与用户能力输出为结构化数据,让"搜…

作者头像 李华
网站建设 2026/8/28 6:02:52

NLP损失函数实战:从SoftMax到对比学习,代码详解与避坑指南

1. 从“分类”到“度量”:NLP损失函数的演进与选择困境在自然语言处理(NLP)的实战中,模型架构和预训练范式常常是聚光灯下的主角,而损失函数(Loss Function)则更像是幕后的导演,它不…

作者头像 李华
网站建设 2026/8/28 6:02:15

#112_东山笔记_关于FreeRTOS移植树文件的内容说明

推荐FreeRTOS教程 链接一:FreeRTOS官网 链接二:百问网FreeRTOS教程 链接三:百问网移至文件 1. 核心源文件(Source 根目录) 这些文件是 FreeRTOS 内核的通用实现,与具体硬件无关,因此放在 Source 根目录下,所有移植版…

作者头像 李华