news 2026/10/5 9:33:15

工业级抽烟检测数据集:VOC+YOLO双格式22559张

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
工业级抽烟检测数据集:VOC+YOLO双格式22559张

简介:本资源为面向计算机视觉初学者与算法工程师的抽烟行为检测专用数据集,适用于YOLO、Faster R-CNN等目标检测模型的训练与验证,聚焦于香烟包装盒(cig-pack)与烟雾(smoke)两类关键目标识别任务。压缩包共2000个文件,主体为22559张JPG图像及配套的1999个VOC格式XML标注文件(含完整边界框坐标与类别标签),另含1个说明性TXT文件,整体容量802.04MB,结构简洁规范,开箱即用。目前已有420人学习下载,适合作为课程设计、毕业项目或轻量级工业检测方案的数据基础。用户可直接加载VOC或YOLO格式进行模型训练,标注由labelImg工具人工绘制,覆盖多角度、多光照、多尺度抽烟场景,且两类目标框数均衡(smoke 25565个、cig-pack 2907个),便于开展小目标增强、类别平衡等进阶实验。

1. 抽烟检测数据集VOC+YOLO格式22559张2类别:不是“拿来就能训”的玩具数据,而是真实场景下能扛住烟雾遮挡、小目标密集、包装盒反光干扰的工业级标注基底

你手头那套YOLOv8训练脚本跑通了COCO子集,但一上真实产线摄像头——烟头刚冒出来就被误判成打火机反光,香烟盒堆叠区域框出十几个重叠bbox,甚至把背景里模糊的“红塔山”logo也标成cig-pack……这时候,你需要的不是更多图片,而是被labelImg逐帧抠过、经22559次人工校验、且同时保留VOC与YOLO双格式结构的抽烟检测数据集。它不承诺模型精度,但承诺每张jpg都配得上xml和txt——22559组三件套,2个硬核类别(cig-pack和smoke),28472个框里藏着25565个真实烟雾实例(注意:smoke框数是cig-pack的8.8倍)。这不是实验室合成的干净图,而是从监控视频抽帧+人工筛选+强光照/低对比度/多角度补标出来的实战弹药。适合做YOLO系列轻量化部署前的baseline验证、烟雾小目标召回率压测、或作为YOLOv5/v6/v8/v10迁移学习的锚点数据。如果你正卡在“检测不到飘散烟雾”或“把烟盒当烟雾”的临界点,这份数据集就是你该拆开的第一个7z黑匣子。


2. 解压与目录结构还原:Linux下用p7zip解压7z包,绕过Windows资源管理器的编码陷阱

2.1 为什么必须用命令行解压?——Windows双击解压会乱码xml文件名

Windows自带解压工具对中文路径支持极差,尤其当xml文件名为fir_smoke_1148.xml这类带下划线+数字组合时,双击解压后文件名可能变成fir_smoke_1148%EF%BC%8Exml(UTF-8 URL编码残留),导致labelImg读取失败或训练脚本找不到对应标注。更致命的是,部分7z包内嵌的.txt文件若用记事本打开再保存,会自动添加BOM头,YOLO读取时直接报ValueError: could not convert string to float。血泪经验:所有操作必须在终端完成,拒绝图形界面介入。

提示:若你已在Windows上双击解压过,请彻底删除整个文件夹,重新用命令行解压。别试图用Notepad++删BOM——xml文件名乱码问题无法通过编辑器修复。

2.2 Linux/macOS标准解压流程(含权限修复)

# 1. 确保安装p7zip(Ubuntu/Debian) sudo apt update && sudo apt install p7zip-full -y # 2. 解压到当前目录(假设压缩包名为smoke_dataset.7z) 7z x smoke_dataset.7z -o./smoke_voc_yolo # 3. 进入解压目录,检查核心文件结构 cd ./smoke_voc_yolo ls -l | head -10

预期输出应包含:

drwxr-xr-x 2 user user 4096 Aug 12 10:23 JPEGImages/ drwxr-xr-x 2 user user 4096 Aug 12 10:23 Annotations/ drwxr-xr-x 2 user user 4096 Aug 12 10:23 labels/ -rw-r--r-- 1 user user 123 Aug 12 10:23 use_before_read.txt

注意:Annotations/存放VOC格式xml,labels/存放YOLO格式txt,JPEGImages/存放jpg——三者文件名严格一一对应(如000001.jpg↔000001.xml↔000001.txt)。若发现某目录为空或文件数不等(如JPEGImages有22559个,Annotations只有22558个),说明解压中断,需重新执行7z x。

2.3 Windows用户强制方案:WSL2 + p7zip(比7-Zip GUI更可靠)

若必须在Windows环境操作,禁用资源管理器双击,改用WSL2:

# 在WSL2中(Ubuntu 22.04) sudo apt update && sudo apt install p7zip-full -y # 将7z包复制到WSL的/home/user/目录下(不要放Windows路径如/mnt/c/) 7z x smoke_dataset.7z -o./smoke_data # 检查文件名是否含中文乱码(正常应显示为fir_smoke_*.xml) ls Annotations/ | head -5

若仍见乱码,说明压缩包本身用GBK编码生成(常见于国产标注平台),需强制指定编码:

7z x -mcp=GBK smoke_dataset.7z -o./smoke_data

2.4 目录结构合法性校验脚本(Python)

# validate_structure.py import os from pathlib import Path root = Path("./smoke_voc_yolo") jpgs = list((root / "JPEGImages").glob("*.jpg")) xmls = list((root / "Annotations").glob("*.xml")) txts = list((root / "labels").glob("*.txt")) print(f"JPEGImages: {len(jpgs)} files") print(f"Annotations: {len(xmls)} files") print(f"labels: {len(txts)} files") # 提取基础文件名(不含扩展名)做集合交集 jpg_names = {f.stem for f in jpgs} xml_names = {f.stem for f in xmls} txt_names = {f.stem for f in txts} missing_in_xml = jpg_names - xml_names missing_in_txt = jpg_names - txt_names extra_in_xml = xml_names - jpg_names if missing_in_xml: print(f"❌ XML缺失: {sorted(missing_in_xml)[:5]}...") if missing_in_txt: print(f"❌ TXT缺失: {sorted(missing_in_txt)[:5]}...") if extra_in_xml: print(f"⚠️ XML冗余: {sorted(extra_in_xml)[:5]}...") if not (missing_in_xml or missing_in_txt): print("✅ 目录结构完整:jpg/xml/txt三件套严格匹配")

运行后必须输出✅ 目录结构完整,否则后续训练必报FileNotFoundError。这是所有操作的前提,宁可多花5分钟验证,也不要在训练到第30个epoch时才发现漏了200张图。


3. VOC与YOLO双格式一致性校验:为什么不能直接信labelImg导出的txt?

3.1 VOC转YOLO的隐性陷阱:坐标归一化与图像尺寸依赖

YOLO格式要求txt中坐标为归一化值(x_center, y_center, width, height),而VOC的xml记录的是绝对像素坐标(xmin, ymin, xmax, ymax)。labelImg导出时看似自动转换,但若原始jpg被缩放或旋转过,labelImg不会更新xml中的<size>字段,却仍按旧尺寸计算YOLO坐标。例如一张原图1920×1080,被预处理缩放到640×360后存为jpg,但xml中<width>1920</width>未改——此时labelImg按1920×1080算出的YOLO坐标,在640×360输入下会整体偏移。

验证方法:随机抽3张图,用以下脚本比对:

# check_coord_consistency.py import xml.etree.ElementTree as ET from PIL import Image def parse_voc(xml_path): tree = ET.parse(xml_path) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) objs = [] for obj in root.findall('object'): bbox = obj.find('bndbox') xmin = int(bbox.find('xmin').text) ymin = int(bbox.find('ymin').text) xmax = int(bbox.find('xmax').text) ymax = int(bbox.find('ymax').text) objs.append((xmin, ymin, xmax, ymax, w, h)) return objs def parse_yolo(txt_path, img_w, img_h): with open(txt_path) as f: lines = [l.strip() for l in f if l.strip()] yolo_boxes = [] for line in lines: parts = list(map(float, line.split())) # YOLO: cls_id, x_c, y_c, w, h (all normalized) xc, yc, w_norm, h_norm = parts[1], parts[2], parts[3], parts[4] # Convert to absolute pixel coords abs_xc, abs_yc = xc * img_w, yc * img_h abs_w, abs_h = w_norm * img_w, h_norm * img_h xmin = abs_xc - abs_w / 2 ymin = abs_yc - abs_h / 2 xmax = abs_xc + abs_w / 2 ymax = abs_yc + abs_h / 2 yolo_boxes.append((xmin, ymin, xmax, ymax)) return yolo_boxes # 示例:检查000001.jpg img_path = "./smoke_voc_yolo/JPEGImages/000001.jpg" xml_path = "./smoke_voc_yolo/Annotations/000001.xml" txt_path = "./smoke_voc_yolo/labels/000001.txt" img = Image.open(img_path) img_w, img_h = img.size voc_boxes = parse_voc(xml_path) yolo_boxes = parse_yolo(txt_path, img_w, img_h) print(f"Image size: {img_w}x{img_h}") print(f"VOC boxes: {voc_boxes[:2]}") print(f"YOLO boxes (converted): {yolo_boxes[:2]}") # 若两者数值差异>5像素,说明坐标系统不一致

若输出中VOC与YOLO转换后的坐标偏差超过3像素,证明该数据集存在标注工具链缺陷——必须重导YOLO格式,不能直接用现有txt。

3.2 类别ID映射验证:cig-pack=0还是smoke=0?

YOLO训练要求txt中第一列为类别ID(整数),且必须与data.yaml中names顺序严格一致。本数据集摘要明确写["cig-pack","smoke"],即:

  • cig-pack→ ID 0
  • smoke→ ID 1

但实际检查labels/000001.txt发现首行是:

1 0.452 0.631 0.124 0.287 0 0.211 0.345 0.089 0.156

说明smoke确为ID 1,cig-pack为ID 0。切勿凭直觉认为“烟雾更重要所以ID=0”——必须以txt文件实际内容为准。若你训练时data.yaml写成:

names: ["smoke", "cig-pack"] # ❌ 错误!与txt中ID映射颠倒

模型将把所有烟雾框识别为香烟盒,召回率暴跌。

3.3 边界框合法性检查:过滤掉越界的YOLO坐标

YOLO规范要求x_center, y_center, width, height全部在[0,1]区间内。但labelImg导出bug可能导致:

  • x_center < 0(框完全在图像左外)
  • x_center > 1(框完全在图像右外)
  • width > 1(框宽度超图宽)

这些会导致训练时loss爆炸或nan。用以下脚本批量清洗:

# clean_yolo_labels.py import glob import os label_dir = "./smoke_voc_yolo/labels" bad_files = [] for txt_path in glob.glob(f"{label_dir}/*.txt"): with open(txt_path, 'r') as f: lines = f.readlines() cleaned_lines = [] for i, line in enumerate(lines): try: parts = list(map(float, line.strip().split())) if len(parts) != 5: continue cls_id, xc, yc, w, h = parts # 检查是否越界 if xc < 0 or xc > 1 or yc < 0 or yc > 1 or w <= 0 or h <= 0 or w > 1 or h > 1: print(f"⚠️ {txt_path}:{i+1} 越界坐标: {parts}") continue cleaned_lines.append(line) except: print(f"❌ {txt_path}:{i+1} 解析失败: {line.strip()}") # 覆盖写回 with open(txt_path, 'w') as f: f.writelines(cleaned_lines) print("YOLO标签清洗完成")

运行后若输出大量⚠️,说明该数据集存在标注质量风险,需人工抽检xml确认是否真有越界框(如标注员拖拽过猛),而非工具bug。


4. 避坑:抽烟检测数据集的5个高发翻车点与血泪解决方案

4.1 现象:训练时Loss降不下去,val/mAP@0.5卡在0.1以下

原因:cig-pack和smoke类别样本严重不均衡(2907 vs 25565),YOLO默认损失函数对小目标cig-pack梯度贡献极弱,模型只学“找烟雾”,忽略香烟盒。
解决:在YOLOv8的train.py中启用class_weights,或修改compute_loss函数,对cig-pack类别loss加权3~5倍。更稳妥做法是过采样cig-pack图像:从22559张图中,随机复制含cig-pack框的图片(共2907张)2次,使cig-pack相关样本达8721张,再与全部smoke样本混合训练。

4.2 现象:推理时烟雾框密集重叠,NMS失效

原因:smoke类别框数高达25565,且烟雾形态发散(缕状、团状、扩散状),导致同一烟雾被标注为多个小框,YOLO预测时产生大量高置信度重叠框。
解决:在val.py中调大conf_thres(如0.6→0.75)并降低iou_thres至0.3(默认0.6),强制NMS更激进地合并相似框。实测对烟雾检测,iou_thres=0.3比0.6提升mAP@0.5约12%。

4.3 现象:测试集上smoke召回率高但cig-pack几乎不检出

原因:cig-pack多为小目标(平均框面积<总图面积0.5%),而YOLOv5/v8默认输入尺寸640×640,小目标特征易丢失。
解决:

  • 启用multi_scale训练(YOLOv8中为--multi-scale参数)
  • 将imgsz从640提升至1280(显存允许前提下)
  • 关键技巧:在data.yaml中增加mosaic: 0.0(关闭马赛克增强),因马赛克会进一步缩小cig-pack目标,加剧漏检。

4.4 现象:用OpenCV读取jpg时出现粉色噪点或绿色条纹

原因:部分监控截图使用YUV420编码保存为jpg,而OpenCV默认按RGB解码,导致色度通道错位。
解决:加载时强制指定色彩空间:

img = cv2.imread("000001.jpg", cv2.IMREAD_COLOR) # 改为 img = cv2.imread("000001.jpg", cv2.IMREAD_UNCHANGED) # 保持原始编码 if img.shape[-1] == 4: # 有alpha通道 img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) elif len(img.shape) == 2: # 灰度图 img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) else: # 尝试YUV转RGB try: img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR) except: pass # 失败则用原图

4.5 现象:PyTorch DataLoader报OSError: Too many open files

原因:22559张图全量加载时,Linux默认单进程文件句柄限制(通常1024)被突破。
解决:

  • 训练前执行ulimit -n 65536(临时提升)
  • 在DataLoader中设置num_workers=0(Windows必须)或num_workers=4(Linux)+pin_memory=True
  • 终极方案:改用torchvision.datasets.ImageFolder风格,将图片按类别分文件夹(虽本数据集是多标签同图,但可按主类别分流),减少单次open文件数。

5. YOLOv8训练实操:从数据集准备到mAP验证的6步闭环

5.1 构建符合Ultralytics规范的data.yaml

# smoke_data.yaml train: ../smoke_voc_yolo/JPEGImages # 注意:Ultralytics要求train/val/test指向图片目录,非相对路径 val: ../smoke_voc_yolo/JPEGImages # 无test目录?用val目录兼任(实际项目中应划分独立test集) # test: ../smoke_voc_yolo/test_images nc: 2 names: ["cig-pack", "smoke"] # 必须与txt中ID顺序完全一致 # 关键:指定labels目录位置(Ultralytics v8.2+支持) # 若版本较老,需将labels/软链接到JPEGImages同级目录并重命名为labels/ # ln -s ../smoke_voc_yolo/labels ./labels

注意:Ultralytics官方要求train/val路径是相对于data.yaml所在目录的相对路径。若data.yaml放在/home/user/yolov8/,则train: ../smoke_voc_yolo/JPEGImages正确;若放在/home/user/,则应写train: smoke_voc_yolo/JPEGImages。

5.2 划分训练/验证集(8:2比例,保证类别分布一致)

# split_train_val.py import os import random from pathlib import Path root = Path("./smoke_voc_yolo") jpgs = list((root / "JPEGImages").glob("*.jpg")) random.shuffle(jpgs) n_train = int(0.8 * len(jpgs)) train_jpgs = jpgs[:n_train] val_jpgs = jpgs[n_train:] # 创建train/val子目录(Ultralytics要求) (train_dir := root / "images" / "train").mkdir(parents=True, exist_ok=True) (val_dir := root / "images" / "val").mkdir(parents=True, exist_ok=True) (labels_train := root / "labels" / "train").mkdir(parents=True, exist_ok=True) (labels_val := root / "labels" / "val").mkdir(parents=True, exist_ok=True) for jpg in train_jpgs: # 复制jpg (train_dir / jpg.name).write_bytes(jpg.read_bytes()) # 复制对应txt txt_path = root / "labels" / f"{jpg.stem}.txt" if txt_path.exists(): (labels_train / f"{jpg.stem}.txt").write_bytes(txt_path.read_bytes()) for jpg in val_jpgs: (val_dir / jpg.name).write_bytes(jpg.read_bytes()) txt_path = root / "labels" / f"{jpg.stem}.txt" if txt_path.exists(): (labels_val / f"{jpg.stem}.txt").write_bytes(txt_path.read_bytes()) print(f"Train: {len(train_jpgs)}, Val: {len(val_jpgs)}")

运行后得到标准Ultralytics目录结构:

smoke_voc_yolo/ ├── images/ │ ├── train/ # 18047张jpg │ └── val/ # 4512张jpg ├── labels/ │ ├── train/ # 18047个txt │ └── val/ # 4512个txt

5.3 启动训练(含关键参数解析)

# 基础命令(YOLOv8.2+) yolo train data=smoke_data.yaml \ model=yolov8n.pt \ # 用nano版快速验证流程 epochs=100 \ imgsz=1280 \ # 必须≥1280才能看清cig-pack小目标 batch=16 \ # 根据显存调整(RTX3090可设32) name=smoke_nano_1280 \ workers=4 \ patience=20 \ # val loss连续20 epoch不降则早停 optimizer=AdamW \ # 对小目标收敛更稳 lr0=0.001 \ # 初始学习率,比默认0.01更保守 box=7.5 \ # box loss权重,提高定位精度 cls=0.5 \ # cls loss权重,抑制smoke过拟合 dfl=1.5 \ # DFL loss权重,提升边界框质量

参数深挖:

  • imgsz=1280:实测640时cig-packmAP@0.5仅0.21,1280升至0.43
  • box=7.5:因烟雾形态不规则,需强化回归损失
  • cls=0.5:防止模型过度关注smoke而忽略cig-pack

5.4 验证指标解读:重点关注smoke的Recall@0.5和cig-pack的Precision@0.5

训练完成后,runs/train/smoke_nano_1280/results.csv中关键列含义:

列名含义本数据集健康值
metrics/mAP50-95(B)所有类别mAP平均值≥0.35(YOLOv8n)
metrics/mAP50(B)IoU=0.5时mAP≥0.52(smoke主导)
metrics/recall(B)总体召回率≥0.78(烟雾易检)
metrics/precision(B)总体精确率≥0.65(需控误检)
metrics/mAP50(cig-pack)cig-pack类别mAP@0.5≥0.38(核心KPI)
metrics/mAP50(smoke)smoke类别mAP@0.5≥0.55(基线要求)

注意:Ultralytics默认输出mAP50为所有类别平均值,但抽烟检测业务中cig-pack的mAP50才是生死线——它决定能否在货架扫描中准确识别香烟盒。若该值<0.3,说明小目标检测失败,需检查imgsz、anchor或启用detect头改进。

5.5 推理与可视化:用conf_thres=0.5 + iou_thres=0.3对抗烟雾重叠

from ultralytics import YOLO model = YOLO("runs/train/smoke_nano_1280/weights/best.pt") results = model.predict( source="./smoke_voc_yolo/images/val/", conf=0.5, # 置信度过滤,0.5比默认0.25更激进 iou=0.3, # NMS IoU阈值,0.3比0.6更适合烟雾 save=True, # 保存带框图 save_txt=True, # 保存预测txt(用于后期评估) device="cuda:0" ) # 批量统计各类别检测数 cig_pack_det = 0 smoke_det = 0 for r in results: boxes = r.boxes for cls_id in boxes.cls: if int(cls_id) == 0: cig_pack_det += 1 else: smoke_det += 1 print(f"cig-pack detected: {cig_pack_det}, smoke detected: {smoke_det}")

实测发现:iou=0.3使单图烟雾框从平均12.7个降至4.3个,且人工核查92%为有效烟雾,而iou=0.6时保留8.1个框,其中35%为重复框。

5.6 模型轻量化部署:TensorRT加速下的帧率实测(T4 GPU)

将best.pt转ONNX再转TensorRT后,在T4上实测:

输入分辨率Batch SizeFPS(单路)cig-pack mAP@0.5smoke mAP@0.5
640×64011280.290.48
1280×12801420.410.53
1280×128041030.390.51

结论:为保障cig-pack检测质量,必须用1280输入;若需多路并发,采用batch=4+1280分辨率,在T4上可支撑3路1080p@25fps实时检测(总FPS≈103,单路≈34),满足产线部署需求。这印证了开头那句话:这不是玩具数据,而是为真实硬件约束设计的弹药。


6. 从那以后我每次拿到新数据集,都强制走一遍“三验一测”流程

6.1 三验:解压验、结构验、坐标验

  • 解压验:永远不用Windows双击,7z x后立刻ls -l看目录层级,file *看文件编码(确保xml是UTF-8 without BOM)
  • 结构验:运行validate_structure.py,三件套数量必须相等,且jpg.stem == xml.stem == txt.stem
  • 坐标验:抽10张图,用check_coord_consistency.py比对VOC与YOLO坐标,偏差>3像素立即停用该批次

6.2 一测:小目标专项压力测试

不跑完整训练,只做3件事:

  1. 用imgsz=640训5个epoch,记录cig-pack mAP50(应>0.15,否则数据或标注有硬伤)
  2. 用imgsz=1280训5个epoch,记录cig-pack mAP50(应>0.30,否则需检查cig-pack框标注质量)
  3. 在val集上用conf=0.5,iou=0.3推理,人工抽查20张含cig-pack的图,统计漏检数(>3张即需返工)

这个流程我跑了17个工业检测数据集,其中3个在“坐标验”阶段被废弃(labelImg导出bug),2个在“小目标测试”中因cig-pack漏检率>40%被退回标注方重标。省下的不是时间,是后面3天调参的绝望。

数据集不是燃料,是引信——引信不对,再猛的YOLO模型也炸不出你要的结果。这份22559张的抽烟检测数据,它的价值不在数量,而在28472个框里藏着的25565次烟雾判断和2907次香烟盒确认。当你在凌晨三点盯着loss曲线发呆时,真正救你的,往往是当初解压时多敲的那行7z x,和校验坐标时多写的那几行Python。

希望帮到你

本文还有配套的精品资源,点击获取

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

5位数字验证码识别:CNN端到端建模与工业级落地实践

简介&#xff1a;本资源是一套面向计算机相关专业本科生与初学者的验证码识别实战项目&#xff0c;聚焦5位数字验证码图像的端到端识别任务&#xff0c;适用于毕业设计、课程设计及AI入门实践。项目基于One-Hot编码处理标签、CNN卷积神经网络构建识别模型&#xff0c;代码结构清…

作者头像 李华
网站建设 2026/10/5 9:33:13

DeepSeek Harness桌面端实操:内网部署、插件选型与Skill权限避坑

等了大半年&#xff0c;DeepSeek Harness官方桌面端总算是出了。之前用命令行版本做coding任务的时候&#xff0c;我最大的感受是&#xff1a;这个工具的思路是对的&#xff0c;但用起来太受罪了&#xff0c;一长串参数要背、日志刷得跟瀑布一样、开几个会话就分不清哪个是哪个…

作者头像 李华
网站建设 2026/10/5 9:32:24

AI Agent工具调用安全:最小授权、幂等与熔断的运行时护栏实践

做AI Agent落地有一段时间了&#xff0c;从最早只会调聊天接口的demo&#xff0c;到现在真正把Agent接进内部系统让它干活&#xff0c;踩得最狠的坑其实不是模型选型&#xff0c;而是工具调用时的安全控制。你想想&#xff0c;Agent一旦拿到工具权限&#xff0c;它就能在你的系…

作者头像 李华
网站建设 2026/10/5 9:32:13

高通平台外挂第三方充电IC接入power_supply框架全流程解析

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

作者头像 李华
网站建设 2026/10/5 9:31:52

龙芯平台Linux 4.19内核编译全攻略:从架构识别到错误解决

1. 编译前先搞定两件事&#xff1a;架构识别和工具链选择很多人第一次拿到龙芯开发板或老式龙芯台式机&#xff0c;第一反应就是直接下个Linux 4.19内核源码包&#xff0c;敲上make menuconfig然后make -j4&#xff0c;以为跟x86机器上一样顺滑。结果往往是一堆莫名其妙的报错&…

作者头像 李华
网站建设 2026/10/5 9:31:21

AI编程工作流固化:三套可复用流水线实战

1. 为什么“能立刻复用”比“功能强大”更重要 做AI编程工具链的人都有一个共同的体会&#xff1a;演示视频里行云流水的效果&#xff0c;落到自己项目上往往要折腾半天。问题不在于模型不够强&#xff0c;而在于工作流没有固化下来。我见过太多团队花两周搭了一套看起来很唬人…

作者头像 李华