DeepLabv3+图像分割实战:从Pytorch环境搭建到Cityscapes训练避坑
简介面向图像分割学习者和算法工程师的DeepLabv3实战资源基于Pytorch在VOC与Cityscapes两个公开数据集上完成训练、验证与推理覆盖数据加载、数据增强、网络定义、损失函数、学习率策略、评估指标和可视化等关键环节适合快速上手的初中级开发者。资源共包含55个文件以Python脚本为主辅以预测结果示例图、训练依赖配置和说明文档脚本按功能拆分为数据处理、模型结构、训练调度、损失计算、指标统计及可视化等模块并提供预测结果与原图、标注图的对照样例便于直观理解分割效果。压缩包整体约2.25MB目录结构清晰自带VOC与Cityscapes数据集适配代码主干网络可选ResNet、Xception、MobileNetV2等能够灵活调整实验配置快速切换训练场景。目前已有139人学习使用作为课程设计、论文复现或入门工程实践的参考都比较合适。1. 图像分割项目从哪开始VOC 和 Cityscapes 上的 DeepLabv3 值得做图像分割这几年从一个「学术指标好看」的方向变成了地毯质检、广告牌识别、车道可行驶区域分割这些场景里的刚需。做这类任务DeepLabv3 是我最常推荐的开局模型结构不复杂单卡能训在 VOC 与 Cityscapes 两个基准上有大量公开 mIoU 可以对照少了很多「自己骗自己」的空间。很多同学一上来就奔着 Cityscapes 去结果第一周就卡在标签编码上——官方给的 labelIds 和训练要用的 trainIds 根本不是一套东西。这篇流程按「环境 → 数据 → 训练 → 避坑 → 验证导出」的顺序把一条可复现的 Pytorch 训练链路讲清楚适合第一次做分割项目、希望少走弯路的人。看完你至少能回答三个问题这个方案值不值得投入、自己机器能不能跑、跑挂了该看哪里。2. DeepLabv3 结构与数据集选型先搞懂网络和基准再动手训练先花 20 分钟把网络和基准摸清楚比直接 clone 一个仓库开训省下至少一个周末。DeepLabv3 不是那种黑匣子式的模型它的每个模块都能对应到一个具体的工程问题理解之后再改 backbone、调空洞率、换数据集都心里有数。2.1 backbone、ASPP、Decoder 各管一块别把整个结构当黑匣子DeepLabv3 由三块拼起来backbone 负责提取多尺度特征ASPP 负责在高层特征上扩大感受野Decoder 负责把低层细节和高层语义融合回去。默认 backbone 是 ResNet101输出 stride 为 16也就是说输入 513×513backbone 出来是约 32×32 的特征图。想跑得更快就用 ResNet50 或 MobileNetV2mIoU 会掉 24 个点但显存和耗时都友好很多。ASPP 的核心是「不同空洞率的并行卷积」。常见配置是四个 3×3 卷积dilation 分别为 1、6、12、18再接一个全局平均池化分支五路输出 concat 后再用 1×1 卷积压缩到 256 通道。空洞率为什么选这几个数因为 backbone 输出 stride 已经是 16高层特征本身分辨率低如果空洞率太小3×3 卷积的实际感受野覆盖不了大目标太大又会让靠近边缘的权重稀疏小目标细节丢失。1、6、12、18 是论文调出来的折中换数据集时我一般先不动它。Decoder 是 DeepLabv3 相对 v3 最大的改进。它把 backbone 第二个 stage 输出的低层特征stride 4ResNet101 下是 256 通道先用 1×1 卷积降到 48 通道再和经过 4 倍上采样的 ASPP 输出 concat过两个 3×3 卷积后分类最后整体 4 倍上采样回原图尺寸。为什么要拼低层特征因为高层特征经过多次池化和空洞卷积后物体边缘的位置信息已经很糊了分割任务里「边缘准不准」直接决定 mIoU 上限。低层特征能把这些边界细节拉回来。所以如果发现预测结果边缘锯齿严重第一反应不是调损失而是看 Decoder 的低层特征路径有没有被 BN 或 dropout 搞坏。2.2 VOC 与 Cityscapes两个数据集的差异决定了你的参数VOC2012 和 Cityscapes 虽然都是分割基准但训练体验完全是两个量级很多人在这上面翻车是因为拿 VOC 的参数直接去跑 Cityscapes。对比项VOC2012Cityscapes类别数20 类 背景 21训练 19 类原始 30 类含 ignore训练图像数1464 张SBD 增强后 10582 张2975 张图像分辨率约 375×500尺寸不一2048×1024 固定分辨率标注精细度较粗物体轮廓简单像素级精细远处小目标多主要难点小物体、遮挡、类别不平衡细长结构杆、路灯、类别极端不平衡VOC 只有 1464 张训练图随便一个 50 层的模型都能过拟合所以训练时数据增强和 dropout 要给足Cityscapes 每张图都是 2048×1024直接整图训练一张卡基本装不下必须随机裁剪到 512×1024 或者更小的 patch 来训。VOC 的 21 类里背景占比很高Cityscapes 的 19 类里 road、building 这类大块类别占了绝大多数像素类别不平衡更严重所以后者的 mIoU 想要过 70 难度远大于 VOC 过 70。选择建议第一次跑通流程用 VOC迭代快半小时内能看到完整的训练闭环要落地到自动驾驶或园区巡检这类真实场景再用 Cityscapes。如果直接用 Cityscapes 起步建议先用少量数据把全流程跑通再放开全量训练否则很容易出现「训练了 20 个小时最后发现验证代码算错了指标」这种事。2.3 mIoU 是唯一值得盯的指标吗损失、评估与忽略类分割任务里最常用的指标是 mIoU公式是每个类别的交并比取平均mIoU (1/C) Σ TP / (TP FP FN)。它比 pixel accuracy 严格得多因为 pixel accuracy 会被背景这种大类带偏哪怕小类全错只要背景对了也能有 90% 以上的准确率而 mIoU 会如实反映小类表现。训练损失通常直接用交叉熵但有一个关键参数ignore_index。Cityscapes 的 void 类、VOC 里没有标注的区域在标签里要设成 255损失计算时跳过这些像素。Pytorch 里就是nn.CrossEntropyLoss(ignore_index255)少设这一行loss 会被一堆「不该学的像素」污染训练起来指标飘忽不定。评估时也要过滤掉 255否则一个类别的 IoU 分母被无意义像素撑大mIoU 直接失真。很多人用 MMSegmentation 训练 Cityscapes 是因为它把数据预处理、同步 BN、评估脚本都封装好了省事。但我建议第一遍还是自己写流程分割项目里数据链路占 60% 的工作量用现成框架跑通一次之后你仍然不知道标签编码怎么来的、验证尺寸为什么不一致。自己写一遍再回头看 MMSegmentation 的配置会豁然开朗。3. 环境与数据准备从安装 Pytorch 到生成 Cityscapes trainIds数据链路是分割项目里最容易出错、又最不值得花时间 debug 的部分。按顺序做每一步做完了再往下走不要一口气把五个步骤的活一起干完再回头查。3.1 用 conda 创建环境并装好 GPU 版 Pytorch环境搭建没什么玄学核心就两步建一个干净的环境然后用官方推荐的命令装 Pytorch。我一般这样建conda create -n deeplab python3.10 conda activate deeplab python -m pip install --upgrade pip装 Pytorch 的坑在于版本和 CUDA 的对应关系。去 pytorch.org 的 install 页面选你的操作系统和 CUDA 版本复制它生成的命令。不要凭记忆敲pip install torch那样装的很可能是 CPU 版。装完一定做一次检测python -c import torch; print(torch.__version__, torch.cuda.is_available())输出2.x.xcu121 True才算成功。如果cuda.is_available()是 False先看是不是装了 CPU 版再看显卡驱动是否支持对应的 CUDA 版本。没有 NVIDIA 独显的机器比如只有 Intel 核显也能跑通 VOC 的小实验但要走 Intel 的 IPEX 分支和本文主线不一致建议直接找一台带 CUDA 显卡的机器。3.2 下载并整理 VOC2012注意标签 PNG 是调色板索引图VOC2012 的官方压缩包是VOCtrainval_11-May-2012.tar从你能访问的镜像下载后解压wget 镜像地址/VOCtrainval_11-May-2012.tar tar -xvf VOCtrainval_11-May-2012.tar解压后目录结构是这样的VOCdevkit/ └─ VOC2012/ ├─ JPEGImages/ # 原图 ├─ SegmentationClass/ # 分割标签 PNG └─ ImageSets/Segmentation/ ├─ train.txt └─ val.txttrain.txt里是训练图片的文件名不含扩展名每行一个读取时拼上路径即可。这里有一个最常见的坑SegmentationClass里的 PNG 不是普通的 RGB 图而是带调色板的索引图像素值 020 对应 21 个类别。很多人读标签时用了cv2.imread或Image.open(...).convert(RGB)把索引值映射到了完全不同的 RGB 编码上训练出来的模型跟胡说八道差不多。正确的读取方式from PIL import Image import numpy as np mask Image.open(VOCdevkit/VOC2012/SegmentationClass/2007_000032.png) label np.array(mask).astype(np.int64) # 保持索引值不要转 RGB提示凡是看到分割标签读取后出现「好几个类颜色一样」「类别数对不上」的诡异现象先怀疑是不是把调色板图转成了 RGB。3.3 Cityscapes 标签转换官方 labelIds 与训练 trainIds 的映射脚本Cityscapes 官方的gtFine里给的是labelIds编码方式和训练需要的trainIds不一致。比如labelId7是 road但训练时 road 的标签是 0labelId24是 person训练时是 11。如果你直接把官方标签拿来训练等于让模型去学一套错误的映射mIoU 会非常难看。必须写脚本转换常见做法是按 cityscapes 官方脚本里的映射关系生成 trainIdsimport os import numpy as np from PIL import Image # labelId - trainId只保留训练用得到的 19 类 mapping { 7: 0, 8: 1, 11: 2, 12: 3, 13: 4, 17: 5, 19: 6, 20: 7, 21: 8, 22: 9, 23: 10, 24: 11, 25: 12, 26: 13, 27: 14, 28: 15, 31: 16, 32: 17, 33: 18, } def convert(src_path, dst_path): table np.zeros(256, dtypenp.uint8) table.fill(255) # 未映射的类全部置为 ignore for label_id, train_id in mapping.items(): table[label_id] train_id os.makedirs(dst_path, exist_okTrue) for city in os.listdir(src_path): city_src os.path.join(src_path, city) city_dst os.path.join(dst_path, city) os.makedirs(city_dst, exist_okTrue) for name in os.listdir(city_src): img np.array(Image.open(os.path.join(city_src, name))) img table[img] out_name name.replace(labelIds, trainIds) Image.fromarray(img.astype(np.uint8)).save(os.path.join(city_dst, out_name))这段脚本的核心逻辑是构建一张 256 长度的查找表把 19 个有效类的 labelId 映射到 018其余全部映射到 255损失函数里会被忽略。这样转换出来的trainIds图和gtFine目录一一对应训练时直接读。目录组织建议仿照官方leftImg8bit/train/城市名/图片.png后续写 DataLoader 时路径拼接会简单很多。3.4 数据加载与增强随机缩放、裁剪、翻转的参数怎么定分割任务的数据增强和分类不同图像和标签必须做完全相同的变换。一个最基础、效果也最稳的增强组合是「随机缩放 随机裁剪 随机翻转」。随机缩放能让模型适应不同尺度的目标随机裁剪是为了把大图切成固定尺寸 batch随机翻转是白送的样本扩充。import random import numpy as np from PIL import Image import torch class SegDataset(torch.utils.data.Dataset): def __init__(self, img_dir, mask_dir, id_list, crop_size513, scale_range(0.5, 2.0)): self.img_dir img_dir self.mask_dir mask_dir self.ids [line.strip() for line in open(id_list)] self.crop_size crop_size self.scale_range scale_range def __getitem__(self, idx): name self.ids[idx] image Image.open(f{self.img_dir}/{name}.jpg).convert(RGB) mask Image.open(f{self.mask_dir}/{name}.png) # 随机缩放mask 用 NEAREST不能用线性插值 scale random.uniform(*self.scale_range) new_w, new_h int(image.width * scale), int(image.height * scale) image image.resize((new_w, new_h), Image.BILINEAR) mask mask.resize((new_w, new_h), Image.NEAREST) # 随机裁剪到固定大小 if image.width self.crop_size and image.height self.crop_size: x random.randint(0, image.width - self.crop_size) y random.randint(0, image.height - self.crop_size) image image.crop((x, y, x self.crop_size, y self.crop_size)) mask mask.crop((x, y, x self.crop_size, y self.crop_size)) # 随机水平翻转 if random.random() 0.5: image image.transpose(Image.FLIP_LEFT_RIGHT) mask mask.transpose(Image.FLIP_LEFT_RIGHT) img np.array(image).astype(np.float32) / 255.0 img (img - [0.485, 0.456, 0.406]) / [0.229, 0.224, 0.225] img torch.from_numpy(img).permute(2, 0, 1).float() label torch.from_numpy(np.array(mask)).long() return img, label两个参数需要留意。crop_size在 VOC 上用 513 是论文惯例Cityscapes 常用 512×1024 但显存紧张的场景可以退到 512×512scale_range我习惯用 (0.5, 2.0)小目标多的数据集把下限提到 0.7防止小物体被缩得太小直接消失。标签 resize 必须用NEAREST用双线性会把类别边界插出不存在的新值。4. 训练脚本与关键参数在 Pytorch 里把 DeepLabv3 跑起来训练代码本身不难难的是每个参数背后都有代价。这一章把模型、损失、优化器、学习率调度按顺序拆开讲每个参数给推荐值抄完能直接跑。4.1 模型组装与损失ignore_index255 不设对前面白干DeepLabv3 的成熟实现网上很多项目源码里一般直接引入现成的model.py。但你要能看懂它不然改 backbone、换类别数时无从下手。ASPP 和 Decoder 的核心代码并不长import torch import torch.nn as nn import torch.nn.functional as F class ASPP(nn.Module): def __init__(self, in_channels2048, out_channels256): super().__init__() self.convs nn.ModuleList([ nn.Conv2d(in_channels, out_channels, 1, biasFalse), nn.Conv2d(in_channels, out_channels, 3, padding6, dilation6, biasFalse), nn.Conv2d(in_channels, out_channels, 3, padding12, dilation12, biasFalse), nn.Conv2d(in_channels, out_channels, 3, padding18, dilation18, biasFalse), ]) self.pool nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Conv2d(in_channels, out_channels, 1, biasFalse), ) self.project nn.Sequential( nn.Conv2d(out_channels * 5, out_channels, 1, biasFalse), nn.BatchNorm2d(out_channels), nn.ReLU(inplaceTrue), ) def forward(self, x): res [conv(x) for conv in self.convs] res.append(F.interpolate(self.pool(x), sizex.shape[-2:], modebilinear, align_cornersTrue)) return self.project(torch.cat(res, dim1))这里padding必须等于dilation否则空洞卷积会改变特征图的尺寸拼接时直接报错这是新手最常踩的维度错误。全局池化分支要上采样回输入尺寸再 concatalign_cornersTrue和训练时的上采样保持一致。Decoder 的输入是两层ASPP 输出和 backbone 的低层特征。低层特征通道较多ResNet101 的 layer1 是 256 通道直接 concat 会让低层信息占比过大所以先 1×1 降到 48 通道class Decoder(nn.Module): def __init__(self, low_level_channels256, num_classes21): super().__init__() self.reduce nn.Sequential( nn.Conv2d(low_level_channels, 48, 1, biasFalse), nn.BatchNorm2d(48), nn.ReLU(inplaceTrue), ) self.classifier nn.Sequential( nn.Conv2d(256 48, 256, 3, padding1, biasFalse), nn.BatchNorm2d(256), nn.ReLU(inplaceTrue), nn.Dropout(0.1), nn.Conv2d(256, num_classes, 1), ) def forward(self, high_level, low_level): high_level F.interpolate(high_level, sizelow_level.shape[-2:], modebilinear, align_cornersTrue) return self.classifier(torch.cat([high_level, self.reduce(low_level)], dim1))num_classes在 VOC 是 21Cityscapes 是 19改这里就好。损失函数只有一行但ignore_index255必须写criterion nn.CrossEntropyLoss(ignore_index255)4.2 训练循环SGD、poly 学习率、混合精度一次配齐分割任务的主流配置是 SGD poly 学习率。poly 的意思是学习率按(1 - epoch/max_epoch)^power衰减power 取 0.9前期下降慢、后期下降快比固定学习率稳定很多。完整的训练循环骨架import torch model DeepLabV3Plus(num_classes21) # 或加载 ImageNet 预训练 backbone model model.cuda() optimizer torch.optim.SGD(model.parameters(), lr0.01, momentum0.9, weight_decay1e-4) scaler torch.cuda.amp.GradScaler() base_lr, epochs, power 0.01, 50, 0.9 for epoch in range(epochs): lr base_lr * (1 - epoch / epochs) ** power for g in optimizer.param_groups: g[lr] lr model.train() for images, masks in train_loader: images, masks images.cuda(), masks.cuda() with torch.cuda.amp.autocast(): logits model(images) loss criterion(logits, masks) optimizer.zero_grad() scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()weight_decay1e-4就是 L2 正则化分割任务里 1e-4 是安全默认值加大到 1e-3 会明显压 mIoU。GradScaler是混合精度的核心新版推荐写成torch.amp.GradScaler(cuda)老写法也兼容。混合精度在这类任务上能把显存占用压掉近一半训练速度提升 30% 左右代价是偶尔出现 NaN loss真遇到了先把混合精度关掉跑两个 epoch 对比。4.3 训练日志与收敛判断loss 在跌不代表 mIoU 在涨训练分割模型日志至少每 50 个 iteration 打一次 loss每个 epoch 结束在验证集上算一次 mIoU。只盯 loss 会踩坑loss 在跌可能仅仅是背景类拟合得更好而 person、rider 这类小类完全没学会。这里给出两组常用参数参考VOC 和 Cityscapes 差别明显参数VOC2012Cityscapes输入尺寸513×513512×1024 或 512×512batch size16单卡 88单卡 4学习率0.01batch 160.01batch 8 时 0.007 更稳epochs50120200训练时间单卡 12 小时单卡 12 天VOC 上训练 50 个 epoch验证 mIoU 正常能到 6872Cityscapes 训练 150 epoch 左右单卡 ResNet101 能到 7276。如果训练了 30 个 epoch mIoU 还在 20 以下不是耐心问题是数据链路的 bug去查标签读取和增强。5. DeepLabv3 训练避坑记录5 条翻车现场与修复路径这章写的是我在项目里真实撞过的墙。每条按「现象 → 原因 → 解决」的顺序记录希望能帮你省下排查时间。5.1 conda activate 后提示找不到 conda现象Windows 上装完 Anaconda照着教程conda activate deeplabPowerShell 报错「无法将 conda 项识别为 cmdlet、函数、脚本文件或可运行程序的名称」。原因conda 没有被初始化到当前 shell。conda 的可执行文件装了但 PowerShell 不知道去哪找它需要先执行conda init把初始化脚本写进 shell 配置。解决在新开的终端里先跑conda init powershell然后关掉终端重新打开再执行conda activate deeplab。注意一定要重开终端同一会话里 conda 是读不到新配置的。如果你用的是 CMD则执行conda init cmd.exe。5.2 训练 loss 不下降或直接发散现象第一轮 loss 在 3.0 左右训练 10 个 epoch 后还在 2.5 附近晃或者 loss 直接冲到几百几千然后变成 NaN。原因多数情况是学习率太大或者 backbone 加载预训练权重时strictFalse导致部分层是随机初始化BN 的均值和方差还没收敛。另一个常见原因是标签里有超出类别范围的值比如 255 没有设置 ignore_index交叉熵在计算时会对不存在的类别求损失数值直接崩。解决先把学习率降到原来的 1/10 跑 3 个 epoch 看趋势检查损失函数的ignore_index255加载预训练权重后打印模型里未加载的参数名确认 backbone 的 BN 层不是从零开始。出现 NaN 时先关混合精度再用torch.nan_to_num之前先定位是哪一层产生的。5.3 CUDA out of memory现象训练到第二个 iteration 报CUDA out of memory或者显存看着够用但跑着跑着就爆了。原因分割模型的显存大头是激活值不是参数。crop_size 越大、batch size 越大中间特征图占的显存成倍增长。513×513 的输入ASPP 五路分支同时保留中间特征一个 batch 占的显存是分类模型的数倍。解决顺序是「先降 batch size 到 2再降 crop_size 到 480最后开混合精度」。VOC 上单卡 11GB 显存建议batch_size8 crop513 混合精度Cityscapes 上 11GB 建议batch_size4 crop512×512。还有一个容易忽略的点验证时记得torch.no_grad()很多人验证代码忘了写显存直接被验证阶段吃满。5.4 验证 mIoU 与训练表现对不上现象训练 loss 降得很快训练集上 mIoU 都快 80 了验证集 mIoU 只有 30看起来像是「严重过拟合」但换更强的正则化也没用。原因训练时做了随机缩放和裁剪验证时如果直接把原图缩放到某个固定尺寸GT 和预测的尺寸对齐方式不同导致 mIoU 计算时每个像素错位。更隐蔽的原因是验证时没有过滤 255 像素void 类被当成普通类别参与计算把 IoU 拉低了一大截。解决验证统一在原始分辨率上进行预测输出后argmax再和原始尺寸的 GT 对齐计算混淆矩阵前一定用mask target ! 255把 ignore 像素筛掉。先做到这两点再看 mIoU 是不是真的低。5.5 转 ONNX 后输出与 Pytorch 不一致现象Pytorch 里推理效果正常转成 ONNX 后用 onnxruntime 跑同一张图输出差异很大mIoU 掉 10 个点以上。原因F.interpolate的align_corners参数、动态输入尺寸、opset 版本这三者任何一个不匹配上采样行为就会变。DeepLabv3 里 Decoder 有两处上采样只要有一处的对齐方式变了边缘预测就会错位。解决模型内所有interpolate统一固定align_cornersTrue导出时opset_version用 12 及以上如果必须支持动态输入尺寸用dynamic_axes声明高度和宽度维度但导出前先在同一尺寸下对比 Pytorch 和 ONNX 的逐像素输出差异最大误差控制在 1e-4 量级再上线。6. 验证与导出的最后两个技巧mIoU 计算与 ONNX 导出模型训练完真正决定它能不能被用起来的是验证和导出这两步。我自己在这些地方栽过跟头最后沉淀成两个固定习惯。6.1 mIoU 计算时把 255 和边界处理干净mIoU 的计算代码看起来简单但细节决定数字是否可信。正确做法是预测argmax后只对target ! 255的像素统计混淆矩阵逐类计算 IoU最后取平均def compute_miou(pred, target, num_classes): pred pred.view(-1) target target.view(-1) mask target ! 255 pred, target pred[mask], target[mask] ious [] for cls in range(num_classes): p (pred cls) t (target cls) intersection (p t).sum().item() union (p | t).sum().item() if union 0: ious.append(float(nan)) # 该类别在验证集里没出现 else: ious.append(intersection / union) return torch.tensor(ious).nanmean().item()类别没有出现在 GT 里时IoU 记 0 会把指标压死记 1 又虚高常见做法是跳过它再取平均用nanmean实现。边界处理指的是验证前不要对预测做任何 smoothing直接argmax取硬标签。6.2 ONNX 导出固定 align_corners 与输入尺寸导出 ONNX 时最省心的做法是固定输入尺寸因为动态尺寸会让上采样行为变得更难对齐。代码很简单model.eval() dummy torch.randn(1, 3, 513, 513).cuda() torch.onnx.export( model, dummy, deeplabv3plus.onnx, opset_version12, input_names[input], output_names[logits], dynamic_axes{input: {0: batch}}, )只把 batch 维度设为动态保持高度宽度固定能显著降低上采样行为不一致的风险。导出后做一次数值对齐把同一张图分别跑 Pytorch 和 onnxruntime对比 logits 的绝对误差。我的经验是最大误差在 1e-5 量级才说明模型行为一致。我做分割项目养成的习惯是模型里所有上采样都集中到一个工具函数里强制统一align_cornersTrue每训完一个版本导出 ONNX 后先跑数值对比再交给下游绝不在没验证的情况下直接部署。这样虽然多花十分钟但能省掉后续服务端排查「为什么效果变了」的半天希望帮到你。本文还有配套的精品资源点击获取

相关新闻

第13章:新增后端设备:流程与关键点

第13章:新增后端设备:流程与关键点

本文梳理在 virglrenderer 中新增一个后端设备(backend device)的整体流程与关键设计点,示例参考上游的 DRM native context 与 HSAKMT(ROCm/HSA)两组补丁。 13.1 总体架构 13.1.1 插件式设计 virglrenderer 采用插件式架构:每类设备都是一个自包含模块,通过一组明确定…

2026/10/12 0:55:56 阅读更多 →
航拍路面病害识别数据集:YOLO与Faster R-CNN实战训练指南

航拍路面病害识别数据集:YOLO与Faster R-CNN实战训练指南

简介:这是一份面向深度学习目标检测方向的航拍路面病害识别数据集,适合从事缺陷检测、智慧交通与道路巡检研究的开发者及学生使用,可支撑YOLO系列、Faster R-CNN、SSD等主流模型的训练与验证。数据集共包含3151张航拍图像,覆盖纵向…

2026/10/13 2:21:23 阅读更多 →
论文写作卡壳时怎么突破:拆小目标、换落笔点、先写后改三条判据

论文写作卡壳时怎么突破:拆小目标、换落笔点、先写后改三条判据

写论文的人大多经历过这样一种时刻:文档打开几个钟头,光标停在开头没动。多数建议会劝你先放松、先调整状态,但对已经过了开题、手边有材料和数据的人来说,把"卡住"当成一个可以拆开的技术问题更管用。下面不谈心态&…

2026/10/12 21:36:35 阅读更多 →

最新新闻

关系模型实战指南:从二维表到业务稳定性的底层逻辑

关系模型实战指南:从二维表到业务稳定性的底层逻辑

1. 这不是教科书里的“关系”,而是你每天都在用的数据组织逻辑“关系模型的基本概念”——看到这八个字,很多人第一反应是大学数据库课上那个被粉笔灰笼罩的下午,黑板上写着“实体、属性、域、键”,讲台下有人偷偷刷手机&#xff…

2026/10/13 12:22:17 阅读更多 →
Qt国际化翻译完整实践:从tr()到动态语言切换

Qt国际化翻译完整实践:从tr()到动态语言切换

做Qt开发这么多年,遇到最多的问题不是功能写不出来,而是功能做完以后客户说看不懂。于是QT国际化翻译就成了绕不开的环节。表面上看,这事只是把界面文字换成英文、日文,真正做起来却涉及源码扫描、翻译文件管理、运行时加载、动态…

2026/10/13 12:22:17 阅读更多 →
华为+红帽双赛道:2026网工转型的破局之道

华为+红帽双赛道:2026网工转型的破局之道

1. 为什么2026年网工转型,我建议你押注"华为红帽"双赛道最近不少朋友私信问我关于2026年转行网络工程师(网工)的事,大家的焦虑点很一致:AI工具越来越强,初中级网工的活是不是要被替代&#xff1f…

2026/10/13 12:22:17 阅读更多 →
Modern.js 服务端编译核心 @modern-js/server-utils:TypeScript 编译、别名解析与原生 ESM 支持的源码级解析

Modern.js 服务端编译核心 @modern-js/server-utils:TypeScript 编译、别名解析与原生 ESM 支持的源码级解析

前端后端Web框架 【免费下载链接】modern.js A progressive web framework based on React and Rsbuild. 项目地址: https://gitcode.com/gh_mirrors/mo/modern.js 点击查看 免费下载 本文围绕 packages/server/utils/CHANGELOG.md 记录的能力演进,结合…

2026/10/13 12:22:17 阅读更多 →
基于SpringBoot+Vue的派出所健康档案管理系统设计与实现

基于SpringBoot+Vue的派出所健康档案管理系统设计与实现

选题背景 社会对公共安全的重视,派出所民警的工作压力日益增大,其健康状况备受关注。早期的健康档案管理方式效率低下,难以实现信息的实时共享和动态更新。本系统采用 Spring Boot 框架,结合前端技术和数据库技术,构建…

2026/10/13 12:22:17 阅读更多 →
EmbeddingGemma 2本地多模态嵌入模型部署与向量检索实战

EmbeddingGemma 2本地多模态嵌入模型部署与向量检索实战

1. 这个模型到底是什么:先把它的定位弄清楚拿到"EmbeddingGemma 2"这个名字,第一反应就是:这是个嵌入模型,740M参数规模,多模态,而且主打本地推理。这几个关键词放在一起,意味着它并不…

2026/10/13 12:21:16 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →