利用CVAT平台调用自训练YOLO模型,实现数据标注的自动化(liunx版本)

引言

本篇博客计划讲述一下如何下载安装CVAT,并且使用自己本地训练的YOLO模型在这个平台上对数据进行自动化标注,其中会有一些这个过程中我遇到的麻烦的记录。官网教程地址,官网是英文的,感觉网上资源不多,所以只能看官网比较可靠。

安装CVAT

这里就不介绍这个平台了(我也是想做自动化标注,所以让ai推荐的,没必要把ai输出复制过来啦~),本质上还是个标注数据的平台,似乎比较适合团队合作,有网页体验版本,用它提供的模型也可以做自动化标注,不过要收费,本地自己的模型就是免费。

下载

网址是github网址,下载之后看readme的内容,我下面写的也就是readme的内容。

clone代码

bash 复制代码
git clone https://github.com/cvat-ai/cvat
cd cvat

下载配置docker

后面需要docker,这里介绍用中科大的镜像源下载docker

bash 复制代码
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

下载完成之后,设置docker开机自启,以及将当前用户加入docker用户组。

bash 复制代码
sudo systemctl start docker
sudo systemctl enable docker
bash 复制代码
sudo usermod -aG docker $USER
newgrp docker

再配置国内镜像加速器

bash 复制代码
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com"
  ],
  "dns": ["114.114.114.114", "223.5.5.5"],
  "ipv6": false
}
EOF

重启docker使得配置失效

bash 复制代码
sudo systemctl restart docker

最后验证是否成功

bash 复制代码
docker version
docker run hello-world

配置docker环境

在cvat文件路径下,运行下面这个命令,就可以配置这个项目的docker环境。

bash 复制代码
docker compose up -d

创建一个管理员帐号

bash 复制代码
docker exec -it cvat_server bash -ic 'python3 ~/manage.py createsuperuser'

输入这个命令之后会让你输入用户名,密码,邮箱等信息,正常填写就可以。

打开cvat

打开一个浏览器输入http://localhost:8080,然后用刚刚注册的帐号进行登陆就可以,进去之后如下图。

创建项目

最开始肯定是没有一个项目的,现在开始说怎么创建项目,点击这里

先填写项目名,后面填写标签,点下图那个地方添加标签

标签顺序要跟yolo的data.yaml里面的顺序是一样的,只要写名字就可以,然后点继续,添加下一个标签

最后点submit&Continue,返回项目页面

上传数据

再看项目页面就出现了这个项目,点击进去,点加载数据按钮,如下图

数据格式建议选择YOLO1.1,虽然有ultralytics的选项,但是我试过了疯狂报错,最后都没搞出来,这个好像是后面版本官方新加的,支持没有YOLO1.1好。

格式转换

这是我数据转换成YOLO1.1的代码,可以让AI根据自己的数据格式修改一下输入,只要输出格式是这样的就可以。

python 复制代码
import os
import yaml
import shutil
from pathlib import Path

# --- 配置区 ---
src_root = Path("/home/snow/database/All_data/merged_v1_dataset")  # 你当前数据集的路径
output_dir = "cvat_yolo11_export"  # 新格式输出目录

# --- 脚本开始 ---
obj_data_dir = os.path.join(output_dir, "obj_train_data")

# 清理并创建输出目录
if os.path.exists(output_dir):
    shutil.rmtree(output_dir)
os.makedirs(obj_data_dir)

# 1. 读取你原有的 data.yaml 获取类别信息
with open(os.path.join(src_root, "data.yaml"), 'r') as f:
    data_config = yaml.safe_load(f)
# 注意:YOLO 1.1 要求 names 是一个按顺序排列的列表
names = data_config['names']

# 2. 生成 obj.names 文件 (每行一个类别)
with open(os.path.join(output_dir, "obj.names"), "w") as f:
    for name in names:
        f.write(f"{name}\n")

# 3. 收集所有图片和标签到 obj_train_data,并记录图片路径
image_paths = []
subsets = ['train', 'val', 'test']

for subset in subsets:
    img_dir = src_root / subset / 'images'
    lbl_dir = src_root / subset / 'labels'

    if not img_dir.exists():
        continue

    for img_file in img_dir.glob('*'):
        if img_file.suffix.lower() in ['.jpg', '.jpeg', '.png']:
            # 拷贝图片
            shutil.copy(img_file, os.path.join(obj_data_dir, img_file.name))
            # 拷贝对应的 .txt 标签
            label_file = lbl_dir / f"{img_file.stem}.txt"
            if label_file.exists():
                shutil.copy(label_file, os.path.join(obj_data_dir, label_file.name))
            # 记录图片的相对路径 (YOLO 1.1 的要求)
            image_paths.append(f"obj_train_data/{img_file.name}")

# 4. 生成 train.txt (列出所有图片文件)
with open(os.path.join(output_dir, "train.txt"), "w") as f:
    for path in image_paths:
        f.write(f"{path}\n")

# 5. 生成 obj.data (配置文件)
with open(os.path.join(output_dir, "obj.data"), "w") as f:
    f.write(f"classes = {len(names)}\n")
    f.write("train = train.txt\n")
    f.write("names = obj.names\n")

print(f"✅ 转换完成!结果保存在: {output_dir}")
print(f"共处理 {len(image_paths)} 个文件。")

一个小坑提示,这个数据上传对于标签的准确性要求是非常严格的,如果标签有问题就会上传不上去,这个地方我卡了很久(ps:当然如果还没开始打标就不会有标签这个问题),下面是我检查是否有问题,以及删除的代码。

python 复制代码
# 检查
import os
from pathlib import Path

data_dir = Path("/home/snow/database/All_data/cvat_yolo11_export")

# 1. 检查文件名匹配
img_files = list((data_dir / "obj_train_data").glob("*.[jJ][pP][gG]")) + \
            list((data_dir / "obj_train_data").glob("*.[pP][nN][gG]")) + \
            list((data_dir / "obj_train_data").glob("*.[jJ][pP][eE][gG]"))

print(f"📷 找到 {len(img_files)} 张图片")
print("=" * 50)

for img in img_files:
    stem = img.stem
    txt_file = data_dir / "obj_train_data" / f"{stem}.txt"
    if not txt_file.exists():
        print(f"❌ 缺少标注文件: {img.name} -> {txt_file.name}")
    else:
        # 检查标注文件内容
        with open(txt_file, 'r') as f:
            lines = f.readlines()
        for line in lines:
            parts = line.strip().split()
            if len(parts) != 5:
                print(f"⚠️ 格式错误 {txt_file.name}: 期望5个值,实际 {len(parts)} 个")
                break
            try:
                class_id, cx, cy, w, h = map(float, parts)
                if not (0 <= cx <= 1 and 0 <= cy <= 1 and 0 <= w <= 1 and 0 <= h <= 1):
                    print(f"⚠️ 坐标超出范围 {txt_file.name}: {line.strip()}")
                    break
            except ValueError:
                print(f"⚠️ 数值解析失败 {txt_file.name}: {line.strip()}")
                break

print("=" * 50)
print("✅ 检查完成")
python 复制代码
# 删除
import os
import shutil
from pathlib import Path

# ==================== 配置 ====================
# 你的转换后数据集目录(cvat_yolo11_export)
export_dir = Path("/home/snow/database/All_data/cvat_yolo11_export")
obj_data_dir = export_dir / "obj_train_data"

# 你的原始数据集目录(merged_v1_dataset)
src_dataset_dir = Path("/home/snow/database/All_data/merged_v1_dataset")

# 要删除的文件名列表(从检查脚本中收集的)
bad_files = [
    "recycle_004365.txt", "recycle_000976.txt", "recycle_001934.txt", 
    "recycle_004313.txt", "recycle_000008.txt", "recycle_001271.txt",
    "recycle_001761.txt", "recycle_002719.txt", "recycle_001068.txt",
    "recycle_004214.txt", "recycle_000506.txt", "recycle_004708.txt",
    "recycle_004551.txt", "recycle_002350.txt", "recycle_004035.txt",
    "recycle_002314.txt", "recycle_000814.txt", "recycle_000373.txt",
    "recycle_001244.txt", "recycle_000291.txt", "recycle_000301.txt",
    "recycle_002428.txt", "recycle_000058.txt", "recycle_001435.txt",
    "recycle_001446.txt", "recycle_000152.txt", "recycle_004096.txt",
    "recycle_000036.txt", "recycle_000168.txt", "recycle_000065.txt",
    "recycle_004166.txt", "recycle_000217.txt", "recycle_000320.txt",
    "recycle_000210.txt", "recycle_001156.txt", "recycle_001060.txt",
    "recycle_004595.txt", "recycle_000502.txt", "recycle_001884.txt",
    "recycle_003282.txt", "recycle_001444.txt", "recycle_003743.txt",
    "recycle_002571.txt", "recycle_000693.txt", "recycle_003441.txt",
    "recycle_000897.txt", "recycle_000577.txt", "recycle_004536.txt",
    "recycle_004707.txt", "recycle_003831.txt", "recycle_003902.txt",
    "recycle_000203.txt", "recycle_004357.txt", "recycle_001055.txt",
    "recycle_001253.txt", "recycle_000309.txt", "recycle_000155.txt",
    "recycle_003595.txt", "recycle_000951.txt", "recycle_001208.txt",
    "recycle_003184.txt", "recycle_000207.txt", "recycle_000033.txt",
    "recycle_004121.txt", "recycle_002512.txt", "recycle_002902.txt",
    "recycle_003652.txt", "recycle_000109.txt", "recycle_004298.txt",
    "recycle_004276.txt", "recycle_000268.txt", "recycle_001980.txt",
    "recycle_000472.txt", "recycle_004044.txt", "recycle_000169.txt",
    "recycle_003171.txt", "recycle_000587.txt", "recycle_000019.txt",
    "recycle_000737.txt", "recycle_004488.txt", "recycle_004308.txt",
    "recycle_003741.txt", "recycle_004356.txt", "recycle_004465.txt",
    "recycle_001240.txt", "recycle_003127.txt", "recycle_004583.txt",
    "recycle_004192.txt"
]

# 提取文件名(不含扩展名)用于匹配图片
bad_stems = [f.replace('.txt', '') for f in bad_files]

# ==================== 执行删除 ====================

print("=" * 60)
print("🗑️ 开始删除有问题的文件")
print("=" * 60)

# 1. 从 cvat_yolo11_export/obj_train_data/ 删除
deleted_count = 0
for stem in bad_stems:
    # 删除标注文件
    txt_file = obj_data_dir / f"{stem}.txt"
    if txt_file.exists():
        txt_file.unlink()
        deleted_count += 1
        print(f"✅ 删除标注: {txt_file.name}")
    
    # 删除对应的图片(尝试各种扩展名)
    for ext in ['.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG']:
        img_file = obj_data_dir / f"{stem}{ext}"
        if img_file.exists():
            img_file.unlink()
            print(f"✅ 删除图片: {img_file.name}")
            break

print(f"\n📊 从 export 目录删除了 {deleted_count} 个标注文件")

# 2. 从原始数据集 merged_v1_dataset 中删除
print("\n" + "=" * 60)
print("🗑️ 从原始数据集中删除对应文件")
print("=" * 60)

src_deleted_count = 0
for split in ['train', 'val', 'test']:
    img_dir = src_dataset_dir / split / 'images'
    lbl_dir = src_dataset_dir / split / 'labels'
    
    if not img_dir.exists() or not lbl_dir.exists():
        continue
    
    for stem in bad_stems:
        # 删除标注文件
        txt_file = lbl_dir / f"{stem}.txt"
        if txt_file.exists():
            txt_file.unlink()
            src_deleted_count += 1
            print(f"✅ 从 {split}/labels/ 删除: {txt_file.name}")
        
        # 删除对应的图片(尝试各种扩展名)
        for ext in ['.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG']:
            img_file = img_dir / f"{stem}{ext}"
            if img_file.exists():
                img_file.unlink()
                print(f"✅ 从 {split}/images/ 删除: {img_file.name}")
                break

print(f"\n📊 从原始数据集删除了 {src_deleted_count} 个标注文件")

# 3. 更新 train.txt(重新生成)
print("\n" + "=" * 60)
print("📄 重新生成 train.txt")
print("=" * 60)

# 重新扫描 obj_train_data 中剩余的图片
remaining_images = []
for img_file in obj_data_dir.glob('*'):
    if img_file.suffix.lower() in ['.jpg', '.jpeg', '.png']:
        remaining_images.append(f"obj_train_data/{img_file.name}")

# 写入新的 train.txt
train_txt_path = export_dir / "train.txt"
with open(train_txt_path, 'w') as f:
    for path in remaining_images:
        f.write(f"{path}\n")

print(f"✅ train.txt 已更新,剩余 {len(remaining_images)} 张图片")

print("\n" + "=" * 60)
print("🎉 清理完成!")
print(f"📊 原始数据总计: {len(remaining_images)} 张图片")
print("=" * 60)

# 4. 可选:验证是否还有问题文件
print("\n🔍 验证剩余文件是否都合法...")
problem_found = False
for txt_file in obj_data_dir.glob('*.txt'):
    with open(txt_file, 'r') as f:
        lines = f.readlines()
    for line in lines:
        parts = line.strip().split()
        if len(parts) != 5:
            print(f"❌ 仍有问题文件: {txt_file.name} (期望5个值,实际 {len(parts)} 个)")
            problem_found = True
            break
    if problem_found:
        break

if not problem_found:
    print("✅ 所有剩余文件格式正确!")

print("\n📝 下一步操作:")
print("1. 重新打包数据集:")
print(f"   cd {export_dir}")
print("   zip -r ../cvat_clean_upload.zip .")
print("2. 上传到CVAT重新导入")

创建任务

前面项目创建好之后,点击创建任务在任务列表和job列表里面就会出现这个任务了。

打开任务

在job列表中可以看见,点击进去就可以直接开始打标了

上传自己训练的yolo模型

这一步真的卡了好几天,只能看官网,然后网络还一直不好,下载还很慢,很崩溃。只能按照我踩的坑记录一下,如有问题,非常抱歉,尝试了很多可能记乱了。

配置文件

首先先创建模型文件夹,在cvat文件夹下运行

bash 复制代码
mkdir -p serverless/pytorch/yolo_custom/nuclio
cd serverless/pytorch/yolo_custom/nuclio

模型权重

将准备好的模型pt权重移动到这个文件夹,前半部分用你的模型权重路径

bash 复制代码
cp /home/snow/ultralytics-main/mycode/runs/detect/train-5/weights/best.pt ./

main.py

这个命令行写入

python 复制代码
# 创建 main.py
cat > main.py << 'EOF'
import json
import base64
import io
import numpy as np
from PIL import Image
from ultralytics import YOLO

_model = None

def init_context(context):
    """在容器启动时加载模型"""
    global _model
    context.logger.info("Loading custom YOLO model...")
    try:
        # 使用自定义权重文件(在容器内的路径)
        _model = YOLO("/opt/nuclio/best.pt")
        context.logger.info("Custom model loaded successfully!")
    except Exception as e:
        context.logger.error(f"Failed to load model: {str(e)}")

def handler(context, event):
    """处理推理请求"""
    global _model
    
    try:
        # 解析请求
        data = event.body
        if isinstance(data, bytes):
            data = json.loads(data)
        
        # 解码图片(base64)
        image_data = data.get("image", "")
        if not image_data:
            return context.Response(
                body=json.dumps({"error": "No image provided"}),
                status_code=400,
                content_type='application/json'
            )
        
        image_bytes = base64.b64decode(image_data)
        image = Image.open(io.BytesIO(image_bytes))
        
        # 获取阈值
        threshold = float(data.get("threshold", 0.5))
        
        # 推理
        results = _model.predict(source=image, verbose=False, conf=threshold)
        
        # 格式化结果为CVAT格式
        detections = []
        for r in results:
            if r.boxes is not None:
                for box, cls, conf in zip(r.boxes.xyxy, r.boxes.cls, r.boxes.conf):
                    x1, y1, x2, y2 = box.tolist()
                    detections.append({
                        "confidence": str(float(conf)),
                        "label": _model.names[int(cls)],
                        "points": [x1, y1, x2, y2],
                        "type": "rectangle"
                    })
        
        return context.Response(
            body=json.dumps(detections),
            status_code=200,
            content_type='application/json'
        )
    except Exception as e:
        context.logger.error(f"Inference error: {str(e)}")
        return context.Response(
            body=json.dumps({"error": str(e)}),
            status_code=500,
            content_type='application/json'
        )
EOF

function.yaml

这个文件真的问题好多,最后的版本是下面这样的,这个创建文件之后写入吧,改成命令行也可以,要根据自己的数据标签和类型进行一定修改。

bash 复制代码
metadata:
  name: yolov8-custom-v2
  namespace: cvat
  annotations:
    name: YOLOv8 Custom
    type: detector
    spec: |
      [
        {"id": 0, "name": "Metal"},
        {"id": 1, "name": "Bun"},
        {"id": 2, "name": "Egg_hard"},
        {"id": 3, "name": "Tea"},
        {"id": 4, "name": "DryBattery"},
        {"id": 5, "name": "ExpiredDrugs"}
      ]

spec:
  description: Custom YOLOv8 model
  runtime: python:3.10
  handler: main:handler
  eventTimeout: 30s

  build:
    image: cvat.yolov8.custom.v2
    baseImage: ubuntu:22.04
    directives:
      preCopy:
        - kind: RUN
          value: apt-get update
        - kind: RUN
          value: apt-get install -y python3 python3-pip
        - kind: RUN
          value: apt-get install -y libgl1-mesa-glx libglib2.0-0
        - kind: RUN
          value: ln -sf /usr/bin/python3 /usr/bin/python
        - kind: RUN
          value: python -m pip install -i https://mirrors.aliyun.com/pypi/simple/ ultralytics opencv-python-headless Pillow numpy
        - kind: COPY
          value: . /opt/nuclio
        - kind: WORKDIR
          value: /opt/nuclio

  triggers:
    myHttpTrigger:
      numWorkers: 1
      kind: http

  platform:
    attributes:
      restartPolicy:
        name: always

启动Serverless组件

bash 复制代码
# 检查nuclio是否运行
docker ps | grep nuclio

# 如果没有运行,启动它
docker compose -f docker-compose.yml -f components/serverless/docker-compose.serverless.yml up -d

# 等待几秒
sleep 5

# 确认运行
docker ps | grep nuclio

安装nuctl(如果未安装)

bash 复制代码
# 检查是否已安装
which nuctl

# 如果没有,安装
cd /tmp
wget https://github.com/nuclio/nuclio/releases/download/1.13.0/nuctl-1.13.0-linux-amd64
chmod +x nuctl-1.13.0-linux-amd64
sudo mv nuctl-1.13.0-linux-amd64 /usr/local/bin/nuctl

# 验证
nuctl version

部署

最后一个命令很容易报错,大概率是上面function.yaml的问题,当然大部分实际上是网络问题(有时候魔法也没效果,反正我基本都镜像才解决),而且这个命令很慢,要有耐心。

bash 复制代码
# 回到CVAT根目录
cd /home/snow/cvat  # 修改为你的实际路径

# 给脚本添加执行权限(如果需要)
chmod +x serverless/deploy_cpu.sh

# 部署
./serverless/deploy_cpu.sh serverless/pytorch/yolo_custom/nuclio

部署部分问题解决方法

以下解决方法是可以互通的,哪个能跑通就用哪个。

openvino

报错如下

bash 复制代码
[+] Building 64.6s (2/2) FINISHED                                docker:default
 => [internal] load build definition from Dockerfile                       0.1s
 => => transferring dockerfile: 418B                                       0.0s
 => ERROR [internal] load metadata for docker.io/openvino/ubuntu22_runti  64.5s
------
 > [internal] load metadata for docker.io/openvino/ubuntu22_runtime:2023.3.0:
------
Dockerfile:1
--------------------
   1 | >>> FROM openvino/ubuntu22_runtime:2023.3.0
   2 |     
   3 |     USER root
--------------------
ERROR: failed to build: failed to solve: openvino/ubuntu22_runtime:2023.3.0: failed to resolve source metadata for docker.io/openvino/ubuntu22_runtime:2023.3.0: unexpected status from HEAD request to https://docker.m.daocloud.io/v2/openvino/ubuntu22_runtime/manifests/2023.3.0?ns=docker.io: 401 Unauthorized

解决方法是改为国内镜像

bash 复制代码
# 编辑Docker配置
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json << 'EOF'
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://dockerproxy.com",
    "https://docker.nju.edu.cn"
  ]
}
EOF

# 重启Docker
sudo systemctl restart docker

# 重新尝试拉取
docker pull openvino/ubuntu22_runtime:2023.3.0
gcr.io/iguazio/alpine:3.17

报错如下

bash 复制代码
 => => naming to docker.io/library/cvat.openvino.base:latest               0.0s
 => => unpacking to docker.io/library/cvat.openvino.base:latest            0.6s
26.06.28 20:55:10.221 (W)     nuctl.platform.docker Failed to run container {"err": "stdout:\nUnable to find image 'gcr.io/iguazio/alpine:3.17' locally\ndocker: Error response from daemon: failed to resolve reference \"gcr.io/iguazio/alpine:3.17\": failed to do request: Head \"https://gcr.io/v2/iguazio/alpine/manifests/3.17\": dial tcp [2607:f8b0:400e:c1e::52]:443: i/o timeout\n\nRun 'docker run --help' for more information\n\nstderr:\n", "errVerbose": "\nError - exit status 125\n    /nuclio/pkg/cmdrunner/shellrunner.go:114\n\nCall stack:\nstdout:\nUnable to find image 'gcr.io/iguazio/alpine:3.17' locally\ndocker: Error response from daemon: failed to resolve reference \"gcr.io/iguazio/alpine:3.17\": failed to do request: Head \"https://gcr.io/v2/iguazio/alpine/manifests/3.17\": dial tcp [2607:f8b0:400e:c1e::52]:443: i/o timeout\n\nRun 'docker run --help' for more information\n\nstderr:\n\n    /nuclio/pkg/cmdrunner/shellrunner.go:114\nstdout:\nUnable to find image 'gcr.io/iguazio/alpine:3.17' locally\ndocker: Error response from daemon: failed to resolve reference \"gcr.io/iguazio/alpine:3.17\": failed to do request: Head \"https://gcr.io/v2/iguazio/alpine/manifests/3.17\": dial tcp [2607:f8b0:400e:c1e::52]:443: i/o timeout\n\nRun 'docker run --help' for more information\n\nstderr:\n", "stdout": "Unable to find image 'gcr.io/iguazio/alpine:3.17' locally\ndocker: Error response from daemon: failed to resolve reference \"gcr.io/iguazio/alpine:3.17\": failed to do request: Head \"https://gcr.io/v2/iguazio/alpine/manifests/3.17\": dial tcp [2607:f8b0:400e:c1e::52]:443: i/o timeout\n\nRun 'docker run --help' for more information\n", "stderr": ""}

Error - exit status 125
    /nuclio/pkg/cmdrunner/shellrunner.go:114

Call stack:
stdout:
Unable to find image 'gcr.io/iguazio/alpine:3.17' locally
docker: Error response from daemon: failed to resolve reference "gcr.io/iguazio/alpine:3.17": failed to do request: Head "https://gcr.io/v2/iguazio/alpine/manifests/3.17": dial tcp [2607:f8b0:400e:c1e::52]:443: i/o timeout

Run 'docker run --help' for more information

stderr:

    /nuclio/pkg/cmdrunner/shellrunner.go:114
Failed to run container with storage volume
    ...//nuclio/pkg/platform/local/client/store.go:

解决方法如下,这个我是拉的官方的再重新标签解决的(需要魔法),国内镜像没效果不知道为什么。

bash 复制代码
# 1. 先拉取alpine官方镜像
docker pull alpine:3.17

# 2. 重新标签为gcr.io的镜像
docker tag alpine:3.17 gcr.io/iguazio/alpine:3.17

# 3. 验证
docker images | grep alpine

# 4. 清理Docker缓存
docker system prune -f
ubuntu镜像

报错如下

bash 复制代码
Error - exit status 1
    /nuclio/pkg/cmdrunner/shellrunner.go:114

Call stack:
stdout:

stderr:
#0 building with "default" instance using docker driver

#1 [internal] load build definition from Dockerfile.processor
#1 transferring dockerfile: 1.15kB done
#1 DONE 0.0s

#2 [internal] load metadata for docker.io/library/ubuntu:22.04
#2 ERROR: unexpected status from HEAD request to https://docker.m.daocloud.io/v2/library/ubuntu/manifests/22.04?ns=docker.io: 401 Unauthorized
------
 > [internal] load metadata for docker.io/library/ubuntu:22.04:
------
Dockerfile.processor:6
--------------------
   4 |     
   5 |     # From the base image
   6 | >>> FROM ubuntu:22.04
   7 |     
   8 |     
--------------------
ERROR: failed to build: failed to solve: ubuntu:22.04: failed to resolve source metadata for docker.io/library/ubuntu:22.04: unexpected status from HEAD request to https://docker.m.daocloud.io/v2/library/ubuntu/manifests/22.04?ns=docker.io: 401 Unauthorized

    /nuclio/pkg/cmdrunner/shellrunner.go:114
Failed to build
    /nuclio/pkg/dockerclient/shell.go:119
Failed to build docker image
    .../pkg/containerimagebuilderpusher/docker.go:70
Failed to build processor image
    /nuclio/pkg/processor/build/builder.go:267
Failed to deploy function
    ...//nuclio/pkg/platform/abstract/platform.go:227

这个解决方法更抽象,镜像和官方我都拉不下来,最后是skopeo手动拉取的

bash 复制代码
# 1. 从清华镜像站下载ubuntu镜像(使用skopeo工具)
# 首先安装skopeo
sudo apt-get update && sudo apt-get install -y skopeo

# 2. 使用skopeo复制镜像
skopeo copy docker://docker.io/ubuntu:22.04 docker-archive:/tmp/ubuntu-22.04.tar

# 3. 导入镜像
docker load -i /tmp/ubuntu-22.04.tar

拉取成功之后要再次修改标签,就是给这个容器改个名字,我是下面这样改的,要根据自己拉取的容器名字进行修改。

bash 复制代码
# 1. 查看刚才导入的镜像
docker images | grep 93ec1b09bc11

# 2. 给这个镜像打上正确的标签
docker tag 93ec1b09bc11 ubuntu:22.04

# 3. 验证
docker images | grep ubuntu
# 现在应该看到 ubuntu:22.04 了

自动化标注

恭喜模型部署成功,后面就很简单了。分为两种一种是一张一张标注,另一种是一次性标注所有。

一张一张

在job项目里面有一个魔法棒,具体步骤如下图。

一次性

在task里面

总结

这部分就是我的一些碎碎念,前面所有内容已经介绍完了。之前训练yolo模型感觉能跑,结果还可以就行,但是这次开始研究怎么优化,怎么更加泛化,发现数据标注真的好难,一些物品根本看不清是什么,一些根本切分不开,到底是大框还是小框一系列问题。有些问题感觉就是二维图像固有的缺点,还有一些就是根据具体的任务需求进行改变,在标注之前要规定好标准,要不然不同标注可能使得模型崩掉(一会说那样一会说这样,模型也很苦恼),还有一些就是detect这个模型的问题了(比如这个方方的框真的很难框斜的物品,当然我知道有旋转框和分割)。体会到一种越改数据,模型越崩的感觉,只能重头再理理了。之前只觉得模型调参难,现在也是get到数据多重要了,当然调参我也还是不太会,虽然看过模型结构了(这个部分一年多前说要更新,我已经懒得更新了~),终究还是有很多需要学习的地方。