没等到yolo26,等来了VajraV1
【总结】VajraV1:一种实时目标检测新框架,在现有 YOLO 的检测器基础上进行了架构增强,融合了先前 YOLO 模型中的有效设计,在保持具有竞争力的推理速度的同时,实现了实时目标检测器中最先进的精度!代码已开源
【简介】近年来,实时目标检测技术取得了显著进展,YOLOv10、YOLOv11、YOLOv12 和 YOLOv13 于 2024 年至 2025 年间相继发布。本技术报告介绍了 VajraV1 模型架构,该架构在现有基于 YOLO 的检测器基础上进行了架构增强。VajraV1 融合了先前 YOLO 模型中的有效设计,在保持具有竞争力的推理速度的同时,实现了实时目标检测器中最先进的精度。
在 COCO 验证集上,VajraV1-Nano 的 mAP 达到了 44.3%,比 YOLOv12-N 高出 3.7%,比 YOLOv13-N 高出 2.7%,延迟与 YOLOv12-N 和 YOLOv11-N 相当。 VajraV1-Small 的 mAP 达到 50.4%,比 YOLOv12-S 和 YOLOv13-S 高出 2.4%。VajraV1-Medium 的 mAP 达到 52.7%,比 YOLOv12-M 高出 0.2%。VajraV1-Large 的 mAP 达到 53.7%,比 YOLOv13-L 高出 0.3%。VajraV1-Xlarge 的 mAP 达到 56.2%,优于所有现有的实时目标检测器。
《VajraV1 — The most accurate Real Time Object Detector of the YOLO family》
第一步:下载源码
地址:
https://github.com/NamanMakkar/VayuAI
在pycharm中打开这个源码,python版本最好选择3.8以上,我用的3.10
第二步:配置环境
#打开终端用Python3.10创建新虚拟环境,其中的C:\\Python310换成自己的安装的python路径
C:\\Python310\\python.exe -m venv .venv
#安装PyTorch(国内镜像+超长的超时时间防止安装包过大安装失败)
pip3 install –default-timeout=1000 torch==2.2.0 torchvision==0.17.0 torchaudio==2.2.0 -i https://pypi.tuna.tsinghua.edu.cn/simple –index-url https://download.pytorch.org/whl/cu121
#安装其余的环境
pip install –default-timeout=1000 numpy>=1.21 pandas>=1.3 matplotlib>=3.5 pillow>=9.0 scipy>=1.7 tqdm>=4.64 pyyaml>=6.0 ultralytics>=8.0 onnx>=1.13 onnxruntime>=1.14 opencv-python>=4.5 -i https://pypi.tuna.tsinghua.edu.cn/simple
可以用下面的代码检查自己的环境是否安装完全
import sys
import platform
import pkg_resources
from pkg_resources import DistributionNotFound, VersionConflict
# 1. 项目要求的基础配置
REQUIRED_PYTHON = (3, 8) # VayuAI要求Python≥3.8
REQUIRED_DEPENDENCIES = { # 从VayuAI的pyproject.toml提取的核心依赖
"torch": ">=2.0",
"torchvision": ">=0.15",
# "flash-attn": ">=2.7.4",
"numpy": ">=1.21",
"pandas": ">=1.3",
"matplotlib": ">=3.5",
"pillow": ">=9.0",
"scipy": ">=1.7",
"tqdm": ">=4.64",
"pyyaml": ">=6.0",
"ultralytics": ">=8.0",
"onnx": ">=1.13",
"onnxruntime": ">=1.14",
"opencv-python": ">=4.5"
}
# 2. 检查Python版本
def check_python_version():
print(f"当前Python版本: {sys.version.split()[0]}")
if sys.version_info < REQUIRED_PYTHON:
print(f"错误: 需要Python {REQUIRED_PYTHON[0]}.{REQUIRED_PYTHON[1]} 或更高版本")
return False
print("Python版本符合要求")
return True
# 3. 检查系统平台兼容性
def check_platform():
current_platform = platform.system()
print(f"\\n当前系统平台: {current_platform}")
# 重点提示:flash-attn在Windows上无官方预编译包
if current_platform == "Windows":
print("注意: flash-attn在Windows系统上没有官方预编译wheel,可能需要从源码编译或寻找替代方案")
return True
# 4. 检查依赖包(版本+是否缺失)
def check_dependencies():
missing = []
version_mismatch = []
for pkg_name, req_version in REQUIRED_DEPENDENCIES.items():
try:
# 获取已安装版本并验证
installed_version = pkg_resources.get_distribution(pkg_name).version
pkg_resources.require(f"{pkg_name}{req_version}")
print(f"{pkg_name}: {installed_version} (符合要求 {req_version})")
except DistributionNotFound:
missing.append(f"{pkg_name} (需要 {req_version})")
except VersionConflict as e:
installed = e.dist.version
version_mismatch.append(f"{pkg_name}: 已安装{installed},需要{req_version}")
# 输出问题依赖
if missing:
print("\\n缺少以下依赖:")
for pkg in missing:
print(f"- {pkg}")
if version_mismatch:
print("\\n版本不匹配的依赖:")
for pkg in version_mismatch:
print(f"- {pkg}")
return len(missing) == 0 and len(version_mismatch) == 0
# 5. 执行检测
def main():
print("=== VayuAI环境配置检测 ===")
python_ok = check_python_version()
platform_ok = check_platform()
deps_ok = check_dependencies()
print("\\n=== 检测总结 ===")
if python_ok and platform_ok and deps_ok:
print("环境配置完全符合要求")
else:
print("环境存在问题,请根据上述提示修复")
if __name__ == "__main__":
main()
步骤三:添加训练代码和配置文件mydata.yaml
新建mydata.yaml,内容如下(路径自己看着来)
nc: 3 # 若仅1类,与names长度一致
path: D:KuaKeDW/VayuAI-main/datasets # 数据集所在路径 也可使用绝对路径
train: D:KuaKeDW/VayuAI-main/datasets/train.txt # 数据集路径下的train.txt
val: D:KuaKeDW/VayuAI-main/datasets/val.txt # 数据集路径下的val.txt
test: D:KuaKeDW/VayuAI-main/datasets/test.txt # 数据集路径下的test.txt
# Classes
names:
0: 1
1: 2
2: 3
新建train.py内容如下(参数依照自己所需来修改)
from vajra import Vajra
import torch
# 核心:Windows 多进程必须包裹在 if __name__ == '__main__' 中
if __name__ == '__main__':
# 1. 检查GPU是否可用
if torch.cuda.is_available():
print(f"检测到GPU:{torch.cuda.get_device_name(0)}")
train_device = "cuda"
else:
print("未检测到GPU,将使用CPU训练")
train_device = "cpu"
# 2. 加载预训练模型
model = Vajra("vajra-v1-small-det.pt")
# 3. 训练(关键:workers先设为0,避免多进程报错)
result = model.train(
data="D:/KuaKeDW/VayuAI-main/mydata.yaml",
epochs=100,
img_size=640,
batch=4,
device=train_device,
amp=True,
workers=0, # 核心修正:Windows下先设为0,调试通过后可改为2/4
# 可选:添加其他稳定训练的参数
rect=False, # 关闭矩形训练,减少内存占用
mosaic=0.0 # 暂时关闭mosaic增强,避免数据加载报错(可选)
)
注:其中的训练模型 vajra-v1-small-det.pt 需自己在项目的release里面提前下载,不然运行时找不到程序自己下载时会非常慢,还有可能会运行失败
步骤四:准备数据集并开始训练
首先把自己的数据放在同目录下的data文件夹中,区分为(images和label两个文件夹)
然后新建一个划分数据集的.py文件
代码如下
import shutil
import random
import os
def check_paths(image_path, label_path):
"""检查源路径是否存在以及是否包含文件"""
if not os.path.exists(image_path):
raise FileNotFoundError(f"图片源路径不存在: {image_path}")
if not os.path.exists(label_path):
raise FileNotFoundError(f"标签源路径不存在: {label_path}")
# 扩展支持的图片文件类型,包括 .bmp 格式(大小写敏感)
image_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.JPG', '.JPEG', '.PNG', '.BMP')
image_files = [f for f in os.listdir(image_path) if f.endswith(image_extensions)]
label_files = [f for f in os.listdir(label_path) if f.endswith('.txt')]
if not image_files:
raise ValueError(f"图片源路径 {image_path} 不包含任何图片文件")
if not label_files:
raise ValueError(f"标签源路径 {label_path} 不包含任何标签文件")
print(f"找到 {len(image_files)} 张图片和 {len(label_files)} 个标签文件")
return image_files, label_files
def del_file(path):
"""删除目录下的所有文件"""
if os.path.exists(path):
for i in os.listdir(path):
file_data = os.path.join(path, i)
if os.path.isfile(file_data):
os.remove(file_data)
def mkdir():
"""创建输出目录,如果目录已存在则清空"""
dirs = [
train_image_path, train_label_path,
val_image_path, val_label_path,
test_image_path, test_label_path
]
for path in dirs:
if not os.path.exists(path):
os.makedirs(path)
else:
del_file(path)
def clearfile():
"""清除之前的列表文件"""
files = [list_train, list_val, list_test]
for file_path in files:
if os.path.exists(file_path):
os.remove(file_path)
def main():
# 原始路径
global image_original_path, label_original_path
# 如果需要,这里可以修改为绝对路径
image_original_path = "data/images/"
label_original_path = "data/labels/"
# 确保路径以斜杠结尾
if not image_original_path.endswith(('/', '\\\\')):
image_original_path += '/'
if not label_original_path.endswith(('/', '\\\\')):
label_original_path += '/'
# 转换为绝对路径,便于调试
image_original_path = os.path.abspath(image_original_path)
label_original_path = os.path.abspath(label_original_path)
cur_path = os.getcwd()
print(f"当前工作目录: {cur_path}")
# 训练集路径
global train_image_path, train_label_path
train_image_path = os.path.join(cur_path, "datasets/images/train/")
train_label_path = os.path.join(cur_path, "datasets/labels/train/")
# 验证集路径
global val_image_path, val_label_path
val_image_path = os.path.join(cur_path, "datasets/images/val/")
val_label_path = os.path.join(cur_path, "datasets/labels/val/")
# 测试集路径
global test_image_path, test_label_path
test_image_path = os.path.join(cur_path, "datasets/images/test/")
test_label_path = os.path.join(cur_path, "datasets/labels/test/")
# 训练集目录
global list_train, list_val, list_test
list_train = os.path.join(cur_path, "datasets/train.txt")
list_val = os.path.join(cur_path, "datasets/val.txt")
list_test = os.path.join(cur_path, "datasets/test.txt")
global train_percent, val_percent, test_percent
train_percent = 0.8
val_percent = 0.1
test_percent = 0.1
try:
# 检查源路径和文件
image_files, label_files = check_paths(image_original_path, label_original_path)
# 确保图片和标签文件数量匹配
image_names = {f.split('.')[0] for f in image_files}
label_names = {f.split('.')[0] for f in label_files}
common_names = image_names & label_names
if len(common_names) < len(image_names):
print(f"警告: 找到 {len(image_names) – len(common_names)} 张图片没有对应的标签")
if len(common_names) < len(label_names):
print(f"警告: 找到 {len(label_names) – len(common_names)} 个标签没有对应的图片")
total_txt = sorted(list(common_names))
print(f"将处理 {len(total_txt)} 对匹配的图片和标签")
mkdir()
clearfile()
file_train = open(list_train, 'w')
file_val = open(list_val, 'w')
file_test = open(list_test, 'w')
num_txt = len(total_txt)
list_all_txt = range(num_txt)
num_train = int(num_txt * train_percent)
num_val = int(num_txt * val_percent)
num_test = num_txt – num_train – num_val
train = random.sample(list_all_txt, num_train)
val_test = [i for i in list_all_txt if not i in train]
val = random.sample(val_test, num_val)
print("训练集数目:{}, 验证集数目:{}, 测试集数目:{}".format(len(train), len(val), len(val_test) – len(val)))
# 用于记录复制失败的文件
failed_files = []
for i in list_all_txt:
name = total_txt[i]
# 查找该名称对应的图片文件扩展名
image_ext = None
for ext in ('.jpg', '.jpeg', '.png', '.bmp', '.JPG', '.JPEG', '.PNG', '.BMP'):
if os.path.exists(os.path.join(image_original_path, name + ext)):
image_ext = ext
break
if image_ext is None:
print(f"警告: 找不到对应的图片文件: {name}")
failed_files.append(f"{name} (找不到匹配的扩展名)")
continue
srcImage = os.path.join(image_original_path, name + image_ext)
srcLabel = os.path.join(label_original_path, name + ".txt")
# 检查文件是否存在
if not os.path.exists(srcImage):
failed_files.append(srcImage)
continue
if not os.path.exists(srcLabel):
failed_files.append(srcLabel)
continue
if i in train:
dst_train_Image = os.path.join(train_image_path, name + image_ext)
dst_train_Label = os.path.join(train_label_path, name + '.txt')
try:
shutil.copyfile(srcImage, dst_train_Image)
shutil.copyfile(srcLabel, dst_train_Label)
file_train.write(dst_train_Image + '\\n')
except Exception as e:
print(f"复制失败 {srcImage}: {e}")
failed_files.append(srcImage)
elif i in val:
dst_val_Image = os.path.join(val_image_path, name + image_ext)
dst_val_Label = os.path.join(val_label_path, name + '.txt')
try:
shutil.copyfile(srcImage, dst_val_Image)
shutil.copyfile(srcLabel, dst_val_Label)
file_val.write(dst_val_Image + '\\n')
except Exception as e:
print(f"复制失败 {srcImage}: {e}")
failed_files.append(srcImage)
else:
dst_test_Image = os.path.join(test_image_path, name + image_ext)
dst_test_Label = os.path.join(test_label_path, name + '.txt')
try:
shutil.copyfile(srcImage, dst_test_Image)
shutil.copyfile(srcLabel, dst_test_Label)
file_test.write(dst_test_Image + '\\n')
except Exception as e:
print(f"复制失败 {srcImage}: {e}")
failed_files.append(srcImage)
file_train.close()
file_val.close()
file_test.close()
if failed_files:
print(f"共有 {len(failed_files)} 个文件复制失败")
for file in failed_files[:10]: # 只显示前10个
print(f" – {file}")
if len(failed_files) > 10:
print(f" … 等 {len(failed_files) – 10} 个文件")
else:
print("所有文件复制成功!")
except Exception as e:
print(f"程序执行出错: {e}")
if __name__ == "__main__":
main()
然后运行即可划分完成
划分完成之后运行train.py即可开始训练
步骤五:.pt ——> .onnx(可选)
首先按装转换的环境
# 先安装基础ONNX(若未安装)
pip install onnx==1.15.0 –upgrade
# 安装onnxslim(简化ONNX模型)
pip install onnxslim
# 安装onnxruntime-gpu
pip install onnxruntime-gpu==1.16.3 –upgrade
# 若onnxruntime-gpu安装失败,可先装CPU版临时用:
# pip install onnxruntime==1.16.3
然后 新建.py文件,代码如下
from vajra import Vajra
import torch
if __name__ == '__main__':
# 1. 加载训练好的.pt模型(best.pt/last.pt)
model_path = r"D:\\KuaKeDW\\VayuAI-main\\runs\\detect\\train5\\weights\\best-vajra-v1-small-det.pt" # 替换为你的.pt文件路径
model = Vajra(model_path) # 加载模型
# 2. 导出ONNX(指定输入尺寸、保存路径)
onnx_save_path = r"D:\\KuaKeDW\\VayuAI-main\\best.onnx" # 自定义ONNX保存路径
model.export(
format="onnx", # 导出格式为ONNX
img_size=2048, # 输入尺寸(必须和训练时的img_size一致!)
save_dir=onnx_save_path, # ONNX文件保存路径
dynamic=True # 可选:开启动态维度(支持不同尺寸输入)
)
print(f"ONNX文件已导出到:{onnx_save_path}")
最后运行即可进行.pt -> .onnx



