嘉楠科技
直播中

石正厚

8年用户 1214经验值
私信 关注
[问答]

使用yolov5转为kmodel之后,运行MicroPython报错误:IndexError: index is out of bounds怎么解决?

参考k230关于yolo的pt模型转kmodel案例链接:
https://developer.canaan-creative.com/k230_canmv/zh/dev/zh/example/ai/YOLO%E5%A4%A7%E4%BD%9C%E6%88%98.html
将标准的yolov5s.pt模型转为yolov5s.kmodel模型,然后使用以上链接的案例运行如下代码:
from libs.YOLO import YOLOv5import os,sys,gcimport ulab.numpy as npimport image# 从本地读入图片,并实现HWC转CHWdef read_img(img_path):    img_data = image.Image(img_path)    img_data_rgb888=img_data.to_rgb888()    img_hwc=img_data_rgb888.to_numpy_ref()    shape=img_hwc.shape    img_tmp = img_hwc.reshape((shape[0] * shape[1], shape[2]))    img_tmp_trans = img_tmp.transpose()    img_res=img_tmp_trans.copy()    img_return=img_res.reshape((shape[2],shape[0],shape[1]))    return img_return,img_data_rgb888if __name__=="__main__":    # 测试图位于test_yolov5test_images下    img_path="/data/test_apple.jpg"    kmodel_path="/data/yolov5s.kmodel"    labels = ["person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"]    confidence_threshold = 0.5    model_input_size=[224,224]    img,img_ori=read_img(img_path)    rgb888p_size=[img.shape[2],img.shape[1]]    # 初始化YOLOv5实例    yolo=YOLOv5(task_type="classify",mode="image",kmodel_path=kmodel_path,labels=labels,rgb888p_size=rgb888p_size,model_input_size=model_input_size,conf_thresh=confidence_threshold,debug_mode=0)    yolo.config_preprocess()    try:        res=yolo.run(img)        yolo.draw_result(res,img_ori)        gc.collect()    except Exception as e:        sys.print_exception(e)    finally:        yolo.deinit()期待结果和实际结果
YOLOV.py自带源码报错:IndexError: index is out of bounds
软硬件版本信息
CanMV-K230_LCKFB_micropython_v1.2.2-0-g4b8cae1_nncase_v2.9.0.img.gz
错误日志
Traceback (most recent call last):
File "", line 31, in
File "/sdcard/libs/AIBase.py", line 74, in run
File "/sdcard/libs/YOLO.py", line 83, in postprocess
IndexError: index is out of bounds
MPY: soft reboot
CanMV v1.2.2(based on Micropython e00a144) on 2024-12-18; k230_canmv_lckfb with K230

回帖(1)

遇鱼余的小白

2025-6-13 17:12:27

遇到 IndexError: index is out of bounds 错误通常是在处理模型输出时数组索引超出范围。以下是针对YOLOv5 kmodel在MicroPython运行时的完整解决方案:


根本原因分析




  1. 模型输出与代码不匹配



    • K230转换后的kmodel输出格式可能与标准YOLOv5的[xywh, conf, class_probs]结构不同

    • 可能缺少类别概率输出或维度变化




  2. 锚点(anchor)配置错误



    • 使用的锚点与模型训练时不一致

    • 锚点尺寸与输入分辨率不匹配




  3. 输入尺寸不匹配



    • 模型转换时指定的输入尺寸(如640x640)与推理代码中预处理尺寸不一致




  4. 后处理逻辑错误



    • 在解析输出张量时计算出错的索引值




解决方案(逐步操作)


1. 检查模型转换参数


确保转换命令正确(参考官方文档):


./k230_optimize_tool optimize 
--model yolov5s.onnx
--input_shape "[1,3,640,640]"
--mean 0.0,0.0,0.0
--std 255.0,255.0,255.0
--output_io hex
--output_dir out
--target k230


特别注意:input_shape必须与推理代码中的输入尺寸完全一致



2. 修正锚点配置


在MicroPython代码中使用正确的锚点:


# yolov5s原始锚点 (COCO数据集)
anchors = [
    10,13, 16,30, 33,23,    # P3/8 (小目标)
    30,61, 62,45, 59,119,   # P4/16 (中目标)
    116,90, 156,198, 373,326 # P5/32 (大目标)
]

3. 修改输出处理逻辑(关键修复)


更新YOLO处理类中的process方法:


class YOLOv5:
    def process(self, output_data):
        """处理kmodel输出数据"""
        outputs = np.array(output_data)
        outputs = outputs.reshape((3, -1, 85))  # 假设85=4+1+80

        boxes = []
        scores = []
        class_ids = []

        # 处理每个检测层 (3层)
        for i, output in enumerate(outputs):
            # 分离坐标、置信度、类别概率
            pred_boxes = output[:, 0:4]
            pred_conf = output[:, 4]
            pred_prob = output[:, 5:]

            # 过滤低置信度检测
            mask = pred_conf > self.conf_threshold
            pred_boxes = pred_boxes[mask]
            pred_conf = pred_conf[mask]
            pred_prob = pred_prob[mask]

            # 计算类别分数
            class_score = pred_conf[:, None] * pred_prob

            # 获取最高分数类别
            class_idx = np.argmax(class_score, axis=1)
            class_score_max = np.max(class_score, axis=1)

            # 收集有效检测
            for j in range(len(pred_boxes)):
                box = pred_boxes[j]
                score = class_score_max[j]
                class_id = class_idx[j]

                if score > self.conf_threshold:
                    # 转换为[x1, y1, w, h]
                    x, y, w, h = box[0], box[1], box[2], box[3]
                    boxes.append([x-w/2, y-h/2, w, h])
                    scores.append(score)
                    class_ids.append(class_id)

        # NMS处理
        indices = np.non_max_suppression(
            boxes=np.array(boxes),
            scores=np.array(scores),
            class_ids=np.array(class_ids),
            nms_threshold=self.nms_threshold
        )

        return [boxes[i] for i in indices], [scores[i] for i in indices], [class_ids[i] for i in indices]

4. 统一输入尺寸


确保预处理尺寸与模型匹配:


# 图像预处理 (固定640x640)
def preprocess(img):
    img = img.resize(640, 640)  # 确保尺寸与模型一致
    img = img.to_rgb888()
    # HWC转CHW
    img = img.transpose([2, 0, 1])  
    # 归一化 [0-255] => [0.0-1.0]
    img = img / 255.0
    return img

5. 完整工作流程示例


from libs.YOLO import YOLOv5
import image
import ulab.numpy as np

# 1. 初始化模型
anchors = [10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326]
model = YOLOv5(
    class_num=80,
    anchors=anchors,
    net_in_size=(640, 640),
    conf_threshold=0.25,
    nms_threshold=0.45
)
model.load("yolov5s.kmodel")

# 2. 图像预处理
img = image.Image("/sd/test.jpg")
input_tensor = preprocess(img)  # 返回CHW格式

# 3. 推理
outputs = model.forward(input_tensor)

# 4. 处理输出
boxes, scores, class_ids = model.process(outputs)

# 5. 结果可视化
for box, score, class_id in zip(boxes, scores, class_ids):
    print(f"Class: {class_id}, Score: {score}, Box: {box}")
    # 在原图上绘制矩形框
    img.draw_rectangle(
        int(box[0] * img.width()),
        int(box[1] * img.height()),
        int(box[2] * img.width()),
        int(box[3] * img.height()),
        thickness=2
    )

img.save("/sd/result.jpg")

常见错误排查




  1. 确认输出张量维度


    print("Output shape:", np.array(outputs).shape)

    典型的有效输出形状:



    • (25200, 85)

    • (3, X, 85) (X为每层检测数)




  2. 调整输出处理
    如果输出维度不同:


    # 如果输出是单张量 (25200x85)
    outputs = outputs.reshape((-1, 85))



  3. 检查锚点匹配
    使用原始模型的锚点值(YOLOv5的yaml文件中定义)




  4. 内存优化
    MicroPython设备内存有限,添加内存清理:


    del outputs
    gc.collect()



官方资源参考



  1. YOLO大作战文档

  2. kmodel优化工具使用


通过以上调整,应该能解决索引越界问题。如果问题依然存在,请提供以下信息以便进一步排查:



  • 完整的错误堆栈

  • print(output_data.shape)的输出结果

  • 使用的模型转换命令参数

  • K230固件版本信息

举报

更多回帖

发帖
×
20
完善资料,
赚取积分