关于window下的yolov8n.pt转.onnx再转.kmodel
问题:
(1)nncase无法识别中文路径
(2)模型骨干结构是自定义的,必须对应的版本
(3)已有虚拟环境
一,.pt转.onnx
.pt是yolo的权重文件,通过训练后再自动生成文件夹的weights文件夹下下有best.pt文件。best.pt文件是训练生成的文件,可以通过"export"函数转为best.onnx文件。(需要下载ultralytics,当然能够训练出了best.pt文件说明已经下载好了)
示例:
from ultralytics import YOLO
# 加载 YOLOv8 模型(替换成你的 .pt 模型路径)
model = YOLO("C:/Users/Desktop/pipe_detection_v1/train/weights/best.pt")
# 若你的模型是自定义的,填绝对路径如 "C:\\Users\\Desktop\\YOLOv8-yan\\best.pt"
# 导出 ONNX 格式
model.export(
format="onnx",
opset=11, # Tengine 兼容的 opset 版本
imgsz=320, # 输入尺寸,和后续量化/推理一致
simplify=True, # 简化模型,去除冗余节点
int8=True # 量化模型,提升推理速度
)
print("✅ YOLOv8 .pt → ONNX 转换完成!")
export中的参数决定导出模型的检测效果精度等等,使用 Ultralytics YOLO 进行模型导出 | Ultralytics 文档中有该函数中参数的使用详细教程。
二,.onnx转.kmodel
我遇到了以下问题:
(1)我创建了虚拟环境隔离外部配置,模型中存在骨干是自定义的,因此导出模型也必须复用原来的虚拟环境,保证下载的配置版本一致,且能让它“看懂”自定义骨干。
(2)nncase/.NET在中文路径下不稳定,可能会报错,针对包含中文路径的虚拟环境,需要做一个别名入口
目标:把C:\Users\中文路径\Desktop\pipe_detection_v1\train\weights\best.onnx导出成 K230 可用的 .kmodel
1.给虚拟环境等等加英文路径确保nncase能识别
cmd /c mklink /J C:\k230_env "C:\Users\中文路径\source\code_file\yolonew_env"
cmd /c mklink /J C:\k230_proj "C:\Users\中文路径\Desktop\YOLOv8-yan"
cmd /c mklink /J C:\k230_pipe "C:\Users\中文路径\Desktop\pipe_detection_v1"
作用分别是(解决nncase无法识别中文路径问题,注意修改路径):
- C:\k230_env:现有虚拟环境的英文入口
- C:\k230_proj:项目目录的英文入口
- C:\k230_pipe:模型目录的英文入口
2.下载需要的文件
(1)Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile "C:\Users\中文路径\Desktop\YOLOv8-yan\convert_ascii\dotnet-install.ps1"
作用:.NET SDK 自动安装脚本,用于部署 .NET 运行环境(从官方地址下载的)
(2)Invoke-WebRequest -Uri "https://github.com/kendryte/nncase/releases/download/v2.11.0/nncase-2.11.0-cp39-cp39-win_amd64.whl" -OutFile "C:\Users\中文路径\Desktop\YOLOv8-yan\convert_ascii\nncase-2.11.0-cp39-cp39-win_amd64.whl"
作用:nncase 核心库(Python 3.9 Windows 专用),模型转换核心依赖
(3)Invoke-WebRequest -Uri "https://github.com/kendryte/nncase/releases/download/v2.11.0/nncase_kpu-2.11.0-py2.py3-none-win_amd64.whl" -OutFile "C:\Users\中文路径\Desktop\YOLOv8-yan\convert_ascii\nncase_kpu-2.11.0-py2.py3-none-win_amd64.whl"
作用:nncase KPU 加速库,用于 Kendryte KPU 模型编译
注意: - Python 版本要匹配 wheel 标签
- nncase 和 nncase_kpu 版本要一致
- .NET 用 7.x,且要和这版 nncase 能正常启动
我的信息:Python 版本是 3.9
pip 所在环境是 yolonew_env
我的环境是 Windows win-x64
环境里一开始没有装 nncase
我需要的是 K230 的 .kmodel,所以必须用 nncase + nncase_kpu 这套配套包
3.执行下载命令
(1)在终端执行:powershell -ExecutionPolicy Bypass -File .\convert_ascii\install_in_yolonew_env.ps1
作用:加载配置到虚拟环境
指令代码:
$ErrorActionPreference = "Stop"
$convertDir = $PSScriptRoot
$pythonExe = "C:\k230_env\Scripts\python.exe"
$pipExe = "C:\k230_env\Scripts\pip.exe"
$dotnetDir = Join-Path $convertDir "dotnet"
$dotnetInstallScript = Join-Path $convertDir "dotnet-install.ps1"
$nncaseWheel = Join-Path $convertDir "nncase-2.11.0-cp39-cp39-win_amd64.whl"
$nncaseKpuWheel = Join-Path $convertDir "nncase_kpu-2.11.0-py2.py3-none-win_amd64.whl"
if (-not (Test-Path $pythonExe)) {
throw "Missing python: $pythonExe"
}
if (-not (Test-Path $nncaseWheel)) {
throw "Missing file: $nncaseWheel"
}
if (-not (Test-Path $nncaseKpuWheel)) {
throw "Missing file: $nncaseKpuWheel"
}
if (-not (Test-Path $dotnetInstallScript)) {
throw "Missing file: $dotnetInstallScript"
}
if (-not (Test-Path $dotnetDir)) {
New-Item -ItemType Directory -Path $dotnetDir -Force | Out-Null
}
$env:PYTHONDONTWRITEBYTECODE = "1"
& $pythonExe -m pip install --upgrade pip
& $pythonExe -m pip install --no-compile $nncaseWheel
& $pythonExe -m pip install --no-compile $nncaseKpuWheel
& powershell -ExecutionPolicy Bypass -File $dotnetInstallScript -Version 7.0.410 -InstallDir $dotnetDir
$env:DOTNET_ROOT = $dotnetDir
$env:PATH = "C:\k230_env\Scripts;$dotnetDir;$env:PATH"
Write-Host ""
Write-Host "Install finished."
Write-Host "Python: $pythonExe"
Write-Host "DOTNET_ROOT: $dotnetDir"
(2)在终端执行:powershell -ExecutionPolicy Bypass -File .\convert\run_best_onnx_to_kmodel.ps1
作用:onnx转kmodel(注意代码里的路径和模型尺寸等配置修改)
指令代码:
$ErrorActionPreference = "Stop"
$convertDir = $PSScriptRoot
$pythonExe = "C:\k230_env\Scripts\python.exe"
$dotnetDir = Join-Path $convertDir "dotnet"
$projectConverter = "C:\k230_proj\onnx_to_kmodel.py"
$onnxPath = "C:\k230_pipe\train\weights\best.onnx"
$outputPath = Join-Path $convertDir "best.kmodel"
if (-not (Test-Path $pythonExe)) {
throw "Missing python: $pythonExe"
}
if (-not (Test-Path $projectConverter)) {
throw "Missing converter script: $projectConverter"
}
$env:PYTHONDONTWRITEBYTECODE = "1"
$env:DOTNET_ROOT = $dotnetDir
$env:NNCASE_PLUGIN_PATH = "C:\k230_env\Lib\site-packages\nncase\modules"
$env:PATH = "C:\k230_env\Scripts;$dotnetDir;$env:PATH"
& $pythonExe $projectConverter `
--onnx $onnxPath `
--output $outputPath `
--target k230 `
--input-shape 1,3,320,320 `
--no-quant
onnx_to_kmodel.py代码
import argparse
import os
import sys
from pathlib import Path
import nncase
def parse_csv_numbers(raw: str, cast):
items = [item.strip() for item in raw.split(",") if item.strip()]
if not items:
raise argparse.ArgumentTypeError(f"Invalid value: {raw}")
try:
return [cast(item) for item in items]
except ValueError as exc:
raise argparse.ArgumentTypeError(str(exc)) from exc
def configure_plugin_path():
site_packages = Path(nncase.__file__).resolve().parent.parent
modules_dir = site_packages / "nncase" / "modules"
if modules_dir.exists():
os.environ["NNCASE_PLUGIN_PATH"] = str(modules_dir)
return modules_dir
def create_compiler(args):
options = nncase.CompileOptions()
options.target = args.target
options.input_file = str(args.onnx.resolve())
options.preprocess = True
options.input_type = args.input_type
options.input_shape = args.input_shape
options.input_range = [0.0, 1.0]
options.mean = args.mean
options.std = args.std
options.input_layout = "NCHW"
options.output_layout = "NCHW"
options.dump_ir = False
options.dump_asm = False
return nncase.Compiler(options)
def load_ptq_dataset(dataset_dir: Path, input_shape):
try:
import cv2
import numpy as np
except ImportError as exc:
raise RuntimeError("Quantized export needs opencv-python and numpy.") from exc
exts = {".jpg", ".jpeg", ".png", ".bmp"}
image_paths = [p for p in sorted(dataset_dir.iterdir()) if p.suffix.lower() in exts]
if not image_paths:
raise RuntimeError(f"No calibration images found in: {dataset_dir}")
_, channels, height, width = input_shape
samples = []
for image_path in image_paths[:50]:
image = cv2.imread(str(image_path))
if image is None:
continue
image = cv2.resize(image, (width, height))
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = image.astype(np.float32) / 255.0
image = image.transpose(2, 0, 1)
image = np.expand_dims(image, axis=0)
samples.append([image])
if not samples:
raise RuntimeError(f"Failed to load calibration images from: {dataset_dir}")
return samples
def compile_kmodel(args):
modules_dir = configure_plugin_path()
print(f"NNCASE_PLUGIN_PATH={modules_dir}")
if not nncase.check_target(args.target):
raise RuntimeError(f"Unsupported target: {args.target}")
compiler = create_compiler(args)
import_options = nncase.ImportOptions()
with open(args.onnx.resolve(), "rb") as f:
compiler.import_onnx(f.read(), import_options)
if not args.no_quant and args.dataset:
ptq_options = nncase.PTQTensorOptions()
ptq_options.quant_type = args.quant_type
ptq_options.w_quant_type = args.quant_type
ptq_options.samples_count = 5
ptq_options.set_tensor_data(load_ptq_dataset(args.dataset.resolve(), args.input_shape))
compiler.use_ptq(ptq_options)
compiler.compile()
output_path = args.output.resolve()
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, "wb") as f:
compiler.gencode(f)
def main():
default_onnx = Path(os.path.expanduser(r"~\Desktop\pipe_detection_v1\train\weights\best.onnx"))
parser = argparse.ArgumentParser(
description="Convert an ONNX model to Kendryte .kmodel using nncase/ncc."
)
parser.add_argument(
"--onnx",
type=Path,
default=default_onnx,
help="Path to the input ONNX file.",
)
parser.add_argument(
"--output",
type=Path,
default=Path("best.kmodel"),
help="Path to the output .kmodel file.",
)
parser.add_argument(
"--target",
default="k230",
help="Kendryte target, for example: k230, k510, k210.",
)
parser.add_argument(
"--input-shape",
type=lambda x: parse_csv_numbers(x, int),
default=[1, 3, 320, 320],
help="Input tensor shape, for example: 1,3,320,320",
)
parser.add_argument(
"--input-type",
default="float32",
help="Input tensor type used by nncase, for example: float32 or uint8.",
)
parser.add_argument(
"--dataset",
type=Path,
help="Calibration dataset directory. Recommended for quantized kmodel export.",
)
parser.add_argument(
"--mean",
type=lambda x: parse_csv_numbers(x, float),
default=[0.0, 0.0, 0.0],
help="Normalization mean values, for example: 0,0,0",
)
parser.add_argument(
"--std",
type=lambda x: parse_csv_numbers(x, float),
default=[255.0, 255.0, 255.0],
help="Normalization std values, for example: 255,255,255",
)
parser.add_argument(
"--quant-type",
default="uint8",
help="Quantization type when dataset is provided, for example: uint8.",
)
parser.add_argument(
"--no-quant",
action="store_true",
help="Disable quantization. Useful when debugging compiler compatibility first.",
)
parser.add_argument(
"--print-only",
action="store_true",
help="Print resolved paths and exit.",
)
args = parser.parse_args()
if not args.onnx.exists():
print(f"ONNX file not found: {args.onnx}", file=sys.stderr)
sys.exit(1)
if args.dataset and not args.dataset.exists():
print(f"Dataset directory not found: {args.dataset}", file=sys.stderr)
sys.exit(1)
print(f"ONNX: {args.onnx.resolve()}")
print(f"Output: {args.output.resolve()}")
print(f"Target: {args.target}")
print(f"Input shape: {args.input_shape}")
print(f"Input type: {args.input_type}")
print(f"Quantized: {not args.no_quant and bool(args.dataset)}")
if args.print_only:
return
try:
compile_kmodel(args)
except Exception as exc:
print(
f"\nCompilation failed: {exc}\n"
"Common reasons:\n"
"1. target does not match your chip\n"
"2. ONNX input shape or unsupported operators need adjustment\n"
"3. K230 plugin path or runtime environment is incomplete",
file=sys.stderr,
)
sys.exit(1)
print(f"\nKModel export finished: {args.output.resolve()}")
if __name__ == "__main__":
main()
注意:各个代码里都附带了文件路径,.pt文件地址等等,必须确定该地址正确
更多推荐


所有评论(0)