拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于X-AnyLabeling与Grounded-SAM的自动标注数据飞轮实战

基于X-AnyLabeling与Grounded-SAM的自动标注数据飞轮实战

数据标注这件事,干过的人都知道它有多磨人。一个中等规模的检测项目,动辄几千上万张图,人工框一遍下来,眼睛花、手腕酸,标注质量还参差不齐。更别提模型迭代的时候,数据分布一变,之前的标注可能就得推倒重来。这两年我一直在折腾怎么把这块的自动化程度提上去,试过不少方案,最后沉淀下来一套组合拳:X-AnyLabeling 做交互式标注和格式转换,autodistill 做知识蒸馏式的自动打标,Grounded-SAM 负责开放词汇的检测与分割。这三个东西串起来,基本能覆盖从零样本冷启动到半自动迭代的完整链路。

这套流程解决的核心问题是:在标注预算有限的前提下,用预训练大模型的能力把初始标注成本压到最低,再通过人工修正和模型迭代形成数据飞轮。适合谁看?如果你手头有几百到几万张图要标,团队里没有专职标注员,或者你想把标注效率提升一个数量级,那这篇内容应该能帮到你。我会把环境部署、参数选择、踩过的坑都摊开讲,代码和配置尽量给到能直接抄的程度。

1. 整体方案设计与工具选型逻辑

1.1 为什么是这三个工具的组合

先说清楚这三个工具各自的定位,不然容易混。X-AnyLabeling是一个带图形界面的标注工具,支持 SAM、YOLO 等多种模型辅助标注,还能做格式转换和批量处理,相当于一个"标注工作台"。autodistill是 Roboflow 出的一个框架,核心思路是用大模型(如 Grounding DINO、CLIP)给未标注数据打伪标签,然后训练一个小模型,让小模型去处理剩下的数据。Grounded-SAM则是把 Grounding DINO 的开放词汇检测能力和 SAM 的分割能力拼在一起,输入文本提示词就能框出并分割出对应物体。

这三个东西单独用都有局限。X-AnyLabeling 的 AI 辅助依赖你已经有模型权重,冷启动阶段没模型就抓瞎;autodistill 打出来的标签是框,没有分割掩码,做分割任务还得补;Grounded-SAM 效果好但推理慢,全量跑一遍成本高。组合起来就顺了:Grounded-SAM 负责冷启动阶段的开放词汇检测分割,autodistill 负责把大模型能力蒸馏到小模型上做批量推理,X-AnyLabeling 负责人工修正、格式转换和最终质检。

我试过只用 Grounded-SAM 全量跑,一张图在消费级显卡上要 2-3 秒,一万张图就是七八个小时,而且提示词调不好召回率波动很大。也试过只用 autodistill,冷启动阶段没有目标检测模型,它得先训一个,训完效果还不一定好。三者串起来,冷启动用 Grounded-SAM 标个几百张,训一个小模型,再用 autodistill 批量推,最后 X-AnyLabeling 人工过一遍,整体效率比纯人工高 8-10 倍。

1.2 数据飞轮的运转机制

这套流程的本质是构建一个数据飞轮:少量人工标注 → 训练初始模型 → 模型自动标注 → 人工修正 → 扩充训练集 → 模型迭代。每一轮迭代,模型的泛化能力都更强,需要人工修正的比例越来越低。

具体来说,第一轮你可能需要人工修正 30%-40% 的自动标注结果,第二轮降到 15%-20%,第三轮可能只有 5%-10%。这个衰减曲线取决于你的数据分布复杂度和模型容量。我的经验是,如果第一轮自动标注的 mAP 能到 0.5 以上,三轮迭代后基本能到 0.85 以上,人工只需要处理边缘 case。

这里有个关键点:不要追求一次性标完所有数据。正确的做法是先标 10%-20% 的高质量数据,训一个 baseline,然后用这个 baseline 去推剩下的,推完人工修正,再训。这样每一轮都有模型可用,而不是等全部标完再训。这个思路和主动学习(Active Learning)是一脉相承的,核心是让模型告诉你哪些样本最有价值。

1.3 硬件与软件环境的基本要求

硬件方面,Grounded-SAM 推理建议至少 8GB 显存的 NVIDIA 显卡,16GB 更稳。autodistill 训练小模型(如 YOLOv8n)4GB 显存就够,但批量推理时显存占用会上去。X-AnyLabeling 本身是 CPU 也能跑,但开 AI 辅助推理还是得有 GPU。

软件环境我踩过不少坑,最后稳定下来的组合是:Python 3.10、PyTorch 2.1+、CUDA 11.8 或 12.1。Python 3.11 和 3.12 在某些依赖上还有兼容问题,3.10 是最稳的。PyTorch 版本要和 CUDA 驱动匹配,这个用nvidia-smi看驱动版本,再去 PyTorch 官网查对应关系。

注意:不要用 conda 默认的 PyTorch 安装,版本经常对不上。建议用 pip 装 PyTorch 官方 wheel,或者用 conda 但指定 channel。

2. 环境部署与核心工具安装实操

2.1 X-AnyLabeling 的安装与源码运行

X-AnyLabeling 有两种用法:直接下打包好的可执行文件,或者从源码跑。如果你要改代码或者集成到自己的流程里,必须走源码方式。我一开始图省事用了打包版,后来想加个自定义的格式导出,发现改不了,只能重装源码环境。

源码安装的步骤,我按实际操作的顺序写:

# 1. 克隆仓库(建议用国内镜像加速) git clone https://github.com/CVHub520/X-AnyLabeling.git cd X-AnyLabeling # 2. 创建虚拟环境 conda create -n xany python=3.10 -y conda activate xany # 3. 安装 PyTorch(根据你的 CUDA 版本选) pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 4. 安装项目依赖 pip install -r requirements.txt # 5. 安装 onnxruntime(如果用 GPU 推理) pip install onnxruntime-gpu # 6. 启动 python anylabeling/app.py

这里有几个坑要说。第一,requirements.txt里的onnxruntime默认是 CPU 版,如果你要用 GPU 推理,得先卸载再装onnxruntime-gpu,版本要和 CUDA 匹配。第二,PyQt5 在某些 Linux 发行版上会缺系统库,报xcb相关的错,装一下libxcb-xinerama0之类的包就行。第三,如果你在 PyCharm 里跑,记得把工作目录设成项目根目录,不然相对路径会找不到模型文件。

在 PyCharm 里配置运行环境,我一般这样做:打开项目后,File → Settings → Project → Python Interpreter,选刚才创建的 conda 环境。然后 Run → Edit Configurations,新建一个 Python 配置,Script path 选anylabeling/app.py,Working directory 选项目根目录。这样点运行就能起来。

2.2 autodistill 的安装与模型选择

autodistill 的安装相对简单,但它是个框架,具体用哪个模型要装对应的子包。比如用 Grounding DINO 做基模型,用 YOLOv8 做目标模型:

pip install autodistill pip install autodistill-grounded-sam pip install autodistill-yolov8

autodistill 的核心概念是Base Model(基模型)和Target Model(目标模型)。基模型负责打伪标签,目标模型负责学习这些标签并做批量推理。基模型一般选大模型,如 Grounding DINO、CLIP、SAM;目标模型选轻量级的,如 YOLOv8n、YOLOv8s。

为什么这么设计?因为大模型精度高但慢,小模型快但需要训练。用大模型标一批数据,训小模型,小模型就能以极低的成本处理海量数据。这就是知识蒸馏的思路。

我实测下来,Grounding DINO + YOLOv8n 的组合在通用物体检测上效果不错。Grounding DINO 的文本提示词要写具体,比如 "person. car. dog." 这种用句点分隔的格式,不要写 "a photo of a person",那样召回率会低。

2.3 Grounded-SAM 的部署与权重下载

Grounded-SAM 的部署稍微麻烦点,因为它依赖两个模型:Grounding DINO 和 SAM。权重文件加起来有好几个 G,下载要有耐心。

# 克隆仓库 git clone https://github.com/IDEA-Research/Grounded-Segment-Anything.git cd Grounded-Segment-Anything # 安装依赖 pip install -r requirements.txt # 下载 Grounding DINO 权重 # 从官方 release 页面下载 groundingdino_swint_ogc.pth # 下载 SAM 权重,推荐 vit_h 版本(精度最高,但最大) # sam_vit_h_4b8939.pth

权重文件放哪?Grounding DINO 的权重放在Grounded-Segment-Anything/GroundingDINO/weights/下,SAM 的权重放在项目根目录或者你指定的路径。代码里通过参数指定路径。

提示:SAM 的 vit_h 版本有 2.4GB,推理慢但精度高;vit_b 只有 375MB,速度快但边缘精度差一些。如果做精细分割,建议 vit_h;如果只是粗标,vit_b 够用。

这里有个容易忽略的点:Grounding DINO 的配置文件也要对应。GroundingDINO_SwinT_OGC.py这个配置文件里的num_classes等参数要和权重匹配,不然加载会报错。我一开始只下了权重没注意配置,折腾了半天。

3. 核心流程实现与参数调优

3.1 冷启动:用 Grounded-SAM 做零样本标注

冷启动阶段的目标是:在没有训练数据的情况下,用文本提示词让 Grounded-SAM 标出一批种子数据。这批数据不用多,几百张就够,但质量要高,因为它是后续所有迭代的基础。

我写了一个批量推理脚本,核心逻辑是遍历图片目录,对每张图跑 Grounded-SAM,输出 COCO 格式的标注文件。关键参数有三个:box_threshold、text_threshold和prompt。

import os import cv2 import torch import numpy as np from groundingdino.util.inference import load_model, load_image, predict from segment_anything import sam_model_registry, SamPredictor # 加载模型 grounding_dino = load_model( "GroundingDINO/groundingdino/config/GroundingDINO_SwinT_OGC.py", "GroundingDINO/weights/groundingdino_swint_ogc.pth" ) sam = sam_model_registry["vit_h"](checkpoint="sam_vit_h_4b8939.pth") sam.to(device="cuda") predictor = SamPredictor(sam) # 参数设置 BOX_THRESHOLD = 0.35 TEXT_THRESHOLD = 0.25 PROMPT = "person. car. traffic light. dog." def process_image(image_path, output_dir): image_source, image = load_image(image_path) boxes, logits, phrases = predict( model=grounding_dino, image=image, caption=PROMPT, box_threshold=BOX_THRESHOLD, text_threshold=TEXT_THRESHOLD ) # 用 SAM 做分割 predictor.set_image(image_source) # ... 后续处理

box_threshold控制检测框的置信度阈值,设高了漏检,设低了误检。我一般从 0.35 开始试,根据实际效果调整。text_threshold控制文本匹配的阈值,这个和提示词的写法关系很大。提示词用句点分隔的短词,不要用完整句子。

提示词的写法直接决定召回率。比如你要标"行人",写 "person" 比写 "pedestrian" 召回率高,因为训练数据里 "person" 更常见。要标"红绿灯",写 "traffic light" 而不是 "traffic signal"。这个需要根据你的目标类别多试几次。

冷启动阶段我建议标 200-500 张,覆盖各种场景和光照条件。标完用 X-AnyLabeling 人工过一遍,修正明显的错误。这批数据就是你的"种子集"。

3.2 蒸馏:用 autodistill 训练小模型并批量推理

有了种子集,下一步是用 autodistill 训一个小模型。这里有两种用法:一种是用种子集直接训 YOLOv8,另一种是用 Grounding DINO 作为基模型,让它去标更多数据,再训 YOLOv8。我一般两种结合:先用种子集训一个初始 YOLOv8,再用它去推剩下的数据,推完人工修正,再训。

autodistill 的训练代码很简洁:

from autodistill_grounded_sam import GroundedSAM from autodistill_yolov8 import YOLOv8 from autodistill.detection import CaptionOntology # 定义本体(类别映射) ontology = CaptionOntology({ "person": "person", "car": "car", "dog": "dog" }) # 基模型 base_model = GroundedSAM(ontology=ontology) # 目标模型 target_model = YOLOv8("yolov8n.pt") # 训练 target_model.train( "./dataset/images", epochs=50, imgsz=640, batch=16 )

CaptionOntology是 autodistill 的核心概念,它定义了"文本提示词 → 类别名"的映射。比如{"person": "person"}表示用 "person" 作为提示词,检测结果归类为 "person"。这个映射可以一对多,比如{"car": "vehicle", "truck": "vehicle"}表示 car 和 truck 都归为 vehicle。

训练参数里,epochs一般 50-100 够用,imgsz用 640,batch根据显存调。YOLOv8n 在 8GB 显存上 batch=16 没问题。训练完的模型会保存在runs/detect/train/weights/best.pt。

批量推理的时候,用训好的 YOLOv8 跑全量数据:

from ultralytics import YOLO model = YOLO("runs/detect/train/weights/best.pt") results = model.predict( source="./all_images", conf=0.25, iou=0.45, save_txt=True, save_conf=True )

conf是置信度阈值,iou是 NMS 的 IoU 阈值。这两个参数对结果影响很大。conf设低了误检多,设高了漏检多。我一般从 0.25 开始,根据人工修正的工作量调整。如果误检太多,提到 0.35;如果漏检太多,降到 0.15。

3.3 人工修正:X-AnyLabeling 的高效操作技巧

自动标注的结果不可能完美,人工修正这一步省不掉。但用对工具和方法,效率能差好几倍。X-AnyLabeling 有几个功能特别实用,我逐个说。

快捷键是提效的第一要素。我常用的几个:A和D切换上一张/下一张,W创建矩形框,E创建多边形,Ctrl+S保存,Ctrl+Z撤销。这些在设置里可以自定义,建议按自己的习惯改。我习惯把"下一张"设成空格键,因为按起来最顺手。

AI 辅助标注是 X-AnyLabeling 的杀手锏。你可以加载 SAM 模型,点一下物体就能自动分割出掩码。操作方式是:先点工具栏的 AI 按钮,选 SAM 模型,然后在图上点目标物体,它会自动生成掩码。对于边缘复杂的物体,这个功能比手动画多边形快太多了。

批量处理功能也很有用。比如你要把所有标注从 COCO 格式转成 YOLO 格式,或者批量重命名,都可以在"工具"菜单里找到。我经常用它的"批量替换标签"功能,把自动标注里拼错的类别名统一改掉。

实操心得:人工修正的时候,不要一张一张从头看到尾。先用筛选功能把置信度低的标注挑出来,优先处理这些。高置信度的标注大概率是对的,快速扫一眼就行。这样能把精力集中在真正需要判断的地方。

还有一个技巧:把自动标注的结果和原图叠加显示,这样一眼就能看出哪里标错了。X-AnyLabeling 支持显示标注的置信度,低置信度的框会用不同颜色标出来,很方便。

3.4 格式转换与数据集划分

标注格式这块,不同框架要求不一样。YOLO 要 txt 格式,COCO 要 json,LabelMe 要 json 但结构不同。X-AnyLabeling 支持多种格式的导入导出,但有些细节要注意。

COCO 转 YOLO 的时候,坐标要从绝对坐标转成归一化的相对坐标。公式是:

x_center = (x_min + x_max) / 2 / image_width y_center = (y_min + y_max) / 2 / image_height width = (x_max - x_min) / image_width height = (y_max - y_min) / image_height

这个转换 X-AnyLabeling 能自动做,但你要确保图片尺寸信息是对的。我遇到过图片被旋转过但 EXIF 信息没处理,导致坐标全偏的情况。所以转换前最好统一把图片的 EXIF 方向信息处理掉。

数据集划分一般按 8:1:1 分训练/验证/测试。但如果数据量少(比如少于 1000 张),建议用交叉验证,或者按 7:2:1 分。划分的时候要注意类别平衡,不能某个类别的样本全跑到训练集里去了。我一般用 stratified split,按类别分层抽样。

4. 常见问题排查与避坑指南

4.1 环境与依赖问题速查

环境问题是最耗时间的,我把踩过的坑整理成表,方便对照排查。

问题现象可能原因解决方法
ImportError: libGL.so.1系统缺 OpenCV 依赖apt install libgl1-mesa-glx
CUDA out of memory显存不足减小 batch size 或 imgsz
ModuleNotFoundError: No module named 'groundingdino'没装 Grounding DINO进 GroundingDINO 目录pip install -e .
PyQt5 报 xcb 错误缺系统库apt install libxcb-xinerama0
onnxruntime 用不了 GPU装了 CPU 版卸载重装onnxruntime-gpu
模型加载报 key 不匹配权重和配置不对应检查配置文件的 num_classes

CUDA out of memory这个最常见。除了减小 batch,还可以用梯度累积来模拟大 batch。另外,推理的时候用torch.no_grad()能省不少显存。

4.2 标注质量问题的排查思路

自动标注的质量问题主要有三类:漏检、误检、框不准。排查思路不一样。

漏检一般是置信度阈值设高了,或者提示词没覆盖到。先降conf到 0.1 看看有没有框出来,如果有,说明是阈值问题;如果没有,说明模型根本没学到这个类别,要检查训练数据里这个类别的样本够不够。

误检一般是阈值设低了,或者背景干扰。先提conf到 0.5 看看误检还在不在,如果还在,说明模型把背景学成了目标,要检查训练数据里有没有标错的负样本。

框不准一般是训练数据里的框就不准,或者模型容量不够。检查一下种子集的标注质量,如果种子集就有偏差,后面全歪。模型容量不够的话,换大一点的模型,比如从 YOLOv8n 换到 YOLOv8s。

避坑技巧:每轮迭代后,随机抽 50-100 张图做人工评估,算一下精确率和召回率。不要只看 loss 曲线,loss 低不代表实际效果好。我遇到过 loss 降到 0.1 但实际 mAP 只有 0.4 的情况,原因是过拟合了。

4.3 数据飞轮迭代的节奏控制

迭代节奏很重要,太快了模型没学好,太慢了效率低。我的经验是:

第一轮:标 200-500 张种子集,训 50 epochs,推全量,人工修正 30%-40%。 第二轮:用修正后的数据再训,推全量,人工修正 15%-20%。 第三轮:再训,再推,人工修正 5%-10%。 第四轮:如果修正比例降到 5% 以下,基本可以停了,剩下的用规则或人工兜底。

每一轮之间,要检查一下类别分布有没有漂移。如果某一轮突然某个类别的样本暴增,可能是自动标注把相似类别混淆了,要人工介入纠正。

还有一个经验:不要一次性把所有数据都标完再训。分批标、分批训,每批训完就推下一批,这样模型一直在更新,效率最高。我一般按 500 张一批,标完一批训一次。

5. 效率提升的进阶技巧

5.1 提示词工程在自动标注中的应用

提示词写得好不好,直接决定 Grounded-SAM 的召回率。我总结了几条经验:

第一,用短词不用长句。"person" 比 "a person walking on the street" 召回率高。因为 Grounding DINO 的文本编码器对短词的表征更稳定。

第二,用常见词不用生僻词。"car" 比 "automobile" 好,"bike" 比 "bicycle" 好。训练数据里常见词的出现频率高,模型学得更充分。

第三,多试几个同义词。比如标"狗",可以试 "dog"、"puppy"、"canine",看哪个召回率高。有时候不同词的召回率能差 20%。

第四,用句点分隔多个类别。"person. car. dog." 这种格式,模型会分别检测每个类别。不要用逗号,逗号会被当成一个整体。

第五,根据场景调整。如果是室内场景,"chair. table. lamp.";如果是室外,"car. tree. building."。场景越具体,召回率越高。

5.2 模型选择与推理加速

Grounded-SAM 推理慢是公认的,但有几个加速技巧。

用 TensorRT 加速。把 Grounding DINO 和 SAM 都转成 TensorRT 引擎,推理速度能提升 2-3 倍。转换过程有点繁琐,但一次转换长期受益。具体是用torch2trt或者onnx转trt,网上有现成的脚本。

用半精度推理。把模型转成 FP16,显存占用减半,速度提升 30%-50%。代码里加.half()就行。但要注意,有些操作在 FP16 下会溢出,要加torch.autocast做混合精度。

批处理推理。如果显存够,一次推多张图,比一张一张推快很多。Grounded-SAM 的批处理要改一下代码,把单张推理改成 batch 推理。我一般 batch=4 或 8,看显存。

用更小的 SAM 模型。如果不需要精细分割,用 vit_b 代替 vit_h,速度快 3-4 倍,精度只差一点点。

5.3 数据增强与难例挖掘

数据飞轮跑起来之后,怎么进一步提升模型效果?两个方向:数据增强和难例挖掘。

数据增强方面,YOLOv8 自带 mosaic、mixup、随机翻转等增强,训练时默认开启。但如果你的场景特殊,比如红外图像、医学图像,默认增强可能不合适,要手动调整。我一般会关掉 mosaic,因为它在小数据集上容易过拟合。

难例挖掘是提升模型上限的关键。具体做法是:每轮推理后,把置信度在 0.3-0.6 之间的样本挑出来,这些是模型"拿不准"的样本,人工重点修正。这些样本对模型的提升最大。我一般每轮挑 100-200 个难例,修正后加入训练集。

还有一个技巧:用模型的不确定性做主动学习。对同一张图做多次推理(加不同的数据增强),如果结果差异大,说明模型不确定,这张图就值得人工标注。这个方法叫 Test-Time Augmentation,能有效挑出高价值样本。

6. 实际项目中的经验沉淀

6.1 一个真实项目的迭代记录

去年我做一个工业质检的项目,目标是检测产品表面的缺陷,大概有 5 类缺陷。初始数据 3000 张,人工标了 500 张做种子集。

第一轮:用 Grounded-SAM 标了 500 张,提示词是 "scratch. dent. stain. crack. discoloration."。人工修正后发现,scratch 和 crack 混淆严重,因为两者视觉上很像。修正比例大概 35%。

第二轮:把修正后的 1000 张训 YOLOv8s,推剩下的 2000 张。这次 scratch 和 crack 的混淆好了一些,但 stain 的漏检还是多。修正比例降到 18%。

第三轮:重点补了 stain 的样本,又训了一轮。这次修正比例降到 8%。

第四轮:修正比例 4%,基本收敛。最终 mAP@0.5 是 0.87,满足产线要求。

整个流程下来,人工标注的工作量大概是纯人工的 1/6。如果纯人工标 3000 张,按一张 2 分钟算,要 100 小时。用这套流程,人工修正的总时间大概 16-18 小时。

6.2 团队协作中的标注规范

如果是团队协作,标注规范一定要提前定好。我吃过亏,三个人标同一批数据,框的松紧程度不一样,导致模型学出来的框大小不一致。

规范要明确这几点:框的边界怎么定(贴边还是留白)、遮挡怎么处理(标可见部分还是整体)、最小目标尺寸(小于多少像素不标)、类别边界(相似类别怎么区分)。这些最好用示例图说明,比文字描述清楚。

X-AnyLabeling 支持导入预定义的标签列表,可以避免标签名拼写不一致的问题。团队协作时,把标签列表文件共享,所有人都用同一份。

6.3 什么情况下不适合自动标注

自动标注不是万能的,有些情况还是得人工来。

目标类别特别细粒度的时候,比如区分 10 种不同的鸟,自动标注的准确率会很低,因为大模型的细粒度分类能力有限。

图像质量特别差的时候,比如低分辨率、强噪声,大模型的检测效果也会打折。

标注规范特别复杂的时候,比如要求标出物体的关键点、属性,自动标注覆盖不了。

数据量特别小的时候,比如只有几十张图,自动标注的冷启动成本可能比人工还高。

这些情况下,老老实实人工标可能更划算。自动标注的价值在于规模效应,数据量越大,收益越明显。

6.4 后续扩展方向

这套流程跑通之后,可以往几个方向扩展。

接入更多基模型。除了 Grounding DINO,还可以试 OWL-ViT、GLIP 等开放词汇检测模型,不同模型在不同场景下效果不一样,可以做个 ensemble。

做主动学习的闭环。把模型的不确定性估计和自动标注结合起来,让模型主动挑出最有价值的样本让人工标,进一步提升效率。

做半监督学习。用少量标注数据 + 大量未标注数据,用一致性正则化等方法提升模型效果。这个方向在学术上很热,工业界落地也在增多。

做端到端的流水线。把 Grounded-SAM、autodistill、X-AnyLabeling 串成一个自动化流水线,定时跑、自动迭代,人只需要在关键节点做决策。这个适合数据量特别大的场景。

我个人在实际操作中的体会是,这套流程的核心价值不在于某个工具多强,而在于把冷启动、批量推理、人工修正、模型迭代串成了一个闭环。每个环节都有工具支撑,每个环节的输出都是下一个环节的输入,数据在流动中不断增值。真正跑起来之后,你会发现标注这件事从"体力活"变成了"脑力活",人的精力集中在判断和决策上,重复劳动交给机器。这大概就是数据飞轮最朴素的样子。

返回列表