YOLOv3源码阅读之一:test_single_image.py

一、YOLO简介

  YOLO(You Only Look Once)是一个高效的目标检测算法,属于One-Stage大家族,针对于Two-Stage目标检测算法普遍存在的运算速度慢的缺点,YOLO创造性的提出了One-Stage。也就是将物体分类和物体定位在一个步骤中完成。YOLO直接在输出层回归bounding box的位置和bounding box所属类别,从而实现one-stage。

  经过两次迭代,YOLO目前的最新版本为YOLOv3,在前两版的基础上,YOLOv3进行了一些比较细节的改动,效果有所提升。

  本文正是希望可以将源码加以注释,方便自己学习,同时也愿意分享出来和大家一起学习。由于本人还是一学生,如果有错还请大家不吝指出。

  本文参考的源码地址为:https://github.com/wizyoung/YOLOv3_TensorFlow

二、代码和注释

  文件目录:YOUR_PATH\YOLOv3_TensorFlow-master\test_single_image.py

  需要注意的是,我们默认输入图片尺寸为 [ 416 , 416 ] [416, 416] [416,416]

# coding: utf-8

from __future__ import division, print_function

import tensorflow as tf
import numpy as np
import argparse
import cv2

from utils.misc_utils import parse_anchors, read_class_names
from utils.nms_utils import gpu_nms
from utils.plot_utils import get_color_table, plot_one_box

from model import yolov3

# 设置命令行参数,具体可参见每一个命令行参数的含义
parser = argparse.ArgumentParser(description="YOLO-V3 test single image test procedure.")
parser.add_argument("input_image", type=str,
                    help="The path of the input image.")
parser.add_argument("--anchor_path", type=str, default="./data/yolo_anchors.txt",
                    help="The path of the anchor txt file.")
parser.add_argument("--new_size", nargs='*', type=int, default=[416, 416],
                    help="Resize the input image with `new_size`, size format: [width, height]")
parser.add_argument("--class_name_path", type=str, default="./data/coco.names",
                    help="The path of the class names.")
parser.add_argument("--restore_path", type=str, default="./data/darknet_weights/yolov3.ckpt",
                    help="The path of the weights to restore.")
args = parser.parse_args()

# 处理anchors,这些anchors是通过数据聚类获得,一共9个,shape为:[9, 2]。
# 需要注意的是,最后一个维度的顺序是[width, height]
args.anchors = parse_anchors(args.anchor_path)

# 处理classes, 这里是将所有的class的名称提取了出来,组成了一个列表
args.classes = read_class_names(args.class_name_path)

# 类别的数目
args.num_class = len(args.classes)

# 根据类别的数目为每一个类别分配不同的颜色,以便展示
color_table = get_color_table(args.num_class)

# 读取图片
img_ori = cv2.imread(args.input_image)

# 获取图片的尺寸
height_ori, width_ori = img_ori.shape[:2]

# resize,根据之前设定的尺寸值进行resize,默认是[416, 416],还是[width, height]的顺序
img = cv2.resize(img_ori, tuple(args.new_size))

# 对图片像素进行一定的数据处理
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = np.asarray(img, np.float32)
img = img[np.newaxis, :] / 255.

# TF会话
with tf.Session() as sess:
    # 输入的placeholder,用于输入图片
    input_data = tf.placeholder(tf.float32, [1, args.new_size[1], args.new_size[0], 3], name='input_data')
    # 定义一个YOLOv3的类,在后面可以用来做模型建立以及loss计算等操作,参数分别是类别的数目和anchors
    yolo_model = yolov3(args.num_class, args.anchors)
    with tf.variable_scope('yolov3'):
        # 对图片进行正向传播,返回多张特征图
        pred_feature_maps = yolo_model.forward(input_data, False)
    # 对这些特征图进行处理,获得计算出的bounding box以及属于前景的概率已经每一个类别的概率分布
    pred_boxes, pred_confs, pred_probs = yolo_model.predict(pred_feature_maps)

    # 将两个概率值分别相乘就可以获得最终的概率值
    pred_scores = pred_confs * pred_probs

    # 对这些bounding boxes和概率值进行非最大抑制(NMS)就可以获得最后的bounding boxes和与其对应的概率值以及标签
    boxes, scores, labels = gpu_nms(pred_boxes, pred_scores, args.num_class, max_boxes=30, score_thresh=0.4, nms_thresh=0.5)

    # Saver类,用以保存和恢复模型
    saver = tf.train.Saver()
    # 恢复模型参数
    saver.restore(sess, args.restore_path)

    # 运行graph,获得对应tensors的具体数值,这里是[boxes, scores, labels],对应于NMS之后获得的结果
    boxes_, scores_, labels_ = sess.run([boxes, scores, labels], feed_dict={input_data: img})

    # rescale the coordinates to the original image
    # 将坐标重新映射到原始图片上,因为前面的计算都是在resize之后的图片上进行的,所以需要进行映射
    boxes_[:, 0] *= (width_ori/float(args.new_size[0]))
    boxes_[:, 2] *= (width_ori/float(args.new_size[0]))
    boxes_[:, 1] *= (height_ori/float(args.new_size[1]))
    boxes_[:, 3] *= (height_ori/float(args.new_size[1]))

    # 输出
    print("box coords:")
    print(boxes_)
    print('*' * 30)
    print("scores:")
    print(scores_)
    print('*' * 30)
    print("labels:")
    print(labels_)

    # 绘制并展示,保存最后的结果
    for i in range(len(boxes_)):
        x0, y0, x1, y1 = boxes_[i]
        plot_one_box(img_ori, [x0, y0, x1, y1], label=args.classes[labels_[i]], color=color_table[labels_[i]])
    cv2.imshow('Detection result', img_ori)
    cv2.imwrite('detection_result.jpg', img_ori)
    cv2.waitKey(0)

C:\Users\泽熙\.conda\envs\material\python.exe D:\yolo_picture\yolo\yolov5-5.0\train.py github: skipping check (not a git repository) YOLOv5 2025-3-13 torch 1.10.2+cpu CPU Namespace(adam=False, artifact_alias=&#39;latest&#39;, batch_size=2, bbox_interval=-1, bucket=&#39;&#39;, cache_images=False, cfg=&#39;models/yolov5s_train.yaml&#39;, data=&#39;data/material.yaml&#39;, device=&#39;&#39;, entity=None, epochs=5, evolve=False, exist_ok=False, global_rank=-1, hyp=&#39;data/hyp.scratch.yaml&#39;, image_weights=False, img_size=[640, 640], label_smoothing=0.0, linear_lr=False, local_rank=-1, multi_scale=False, name=&#39;exp&#39;, noautoanchor=False, nosave=False, notest=False, project=&#39;runs/train&#39;, quad=False, rect=False, resume=False, save_dir=&#39;runs\\train\\exp4&#39;, save_period=-1, single_cls=False, sync_bn=False, total_batch_size=2, upload_dataset=False, weights=&#39;yolov5s.pt&#39;, workers=8, world_size=1) tensorboard: Start with &#39;tensorboard --logdir runs/train&#39;, view at http://localhost:6006/ hyperparameters: lr0=0.01, lrf=0.2, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, warmup_bias_lr=0.1, box=0.05, cls=0.5, cls_pw=1.0, obj=1.0, obj_pw=1.0, iou_t=0.2, anchor_t=4.0, fl_gamma=0.0, hsv_h=0.015, hsv_s=0.7, hsv_v=0.4, degrees=0.0, translate=0.1, scale=0.5, shear=0.0, perspective=0.0, flipud=0.0, fliplr=0.5, mosaic=1.0, mixup=0.0 Traceback (most recent call last): File "D:\yolo_picture\yolo\yolov5-5.0\train.py", line 547, in <module> train(hyp, opt, device, tb_writer) File "D:\yolo_picture\yolo\yolov5-5.0\train.py", line 73, in train weights) else None File "C:\Users\泽熙\.conda\envs\material\lib\site-packages\torch\serialization.py", line 607, in load return _load(opened_zipfile, map_location, pickle_module, **pickle_load_args) File "C:\Users\泽熙\.conda\envs\material\lib\site-packages\torch\serialization.py", line 880, in _load unpickler = UnpicklerWrapper(data_file, **pickle_load_args) TypeError: &#39;weights_only&#39; is an invalid keyword argument for this function
最新发布
03-14
<think>好的,我现在需要解决用户在使用YOLOv5训练时遇到的TypeError,具体错误是“TypeError: &#39;weights_only&#39; is an invalid keyword argument for this function”,而且用户提到他们使用的是PyTorch 1.10.2。首先,我得理解这个错误的原因。 用户提供的引用[^1]中提到,类似的错误出现在加载模型时,可能与PyTorch版本有关。YOLOv5的某些脚本可能依赖于特定版本的PyTorch。例如,`weights_only`参数是在PyTorch 1.13.0及更高版本中引入的,用于控制加载模型时的安全检查。如果用户使用的PyTorch版本低于这个版本,就会出现参数无效的错误。 接下来,我需要验证这个假设是否正确。查阅PyTorch的文档,发现`torch.load()`函数中的`weights_only`参数确实是在1.13.0版本中添加的。因此,当用户在旧版本如1.10.2中使用这个参数时,解释器会抛出TypeError,因为它不认识这个关键字参数。 解决方案可能有两个方向:升级PyTorch到兼容的版本,或者修改YOLOv5的代码以移除或适配旧版本的参数。用户可能希望保持当前PyTorch版本不变,因此需要调整代码。 在YOLOv5的代码库中,检查`train.py`或其他相关脚本,找到调用`torch.load()`的地方,查看是否有传递`weights_only`参数。例如,可能在加载模型权重的时候有这样的代码: ```python model = torch.load(weights, map_location=device, weights_only=True) ``` 对于PyTorch 1.10.2,这个参数是无效的,所以需要将其删除或添加条件判断,根据PyTorch的版本动态决定是否使用该参数。例如: ```python import torch if torch.__version__ >= &#39;1.13.0&#39;: model = torch.load(weights, map_location=device, weights_only=True) else: model = torch.load(weights, map_location=device) ``` 这样可以确保在不同版本中兼容。但是,用户可能需要手动修改YOLOv5的源代码,或者检查是否有可用的补丁或更新版本的YOLOv5已经解决了这个问题。 另外,建议用户确认他们使用的YOLOv5版本是否与PyTorch 1.10.2兼容。可能官方文档或GitHub的issue中已经有相关讨论,用户可以参考这些资源。 如果用户不想修改代码,另一个选择是升级PyTorch到1.13.0或更高版本。但需要注意,升级PyTorch可能导致其他依赖问题,需要测试整个环境是否稳定。 总结解决方案步骤: 1. 检查YOLOv5代码中调用`torch.load()`的地方,移除`weights_only`参数。 2. 或者根据PyTorch版本动态设置该参数。 3. 升级PyTorch到兼容版本,如1.13.0+。 4. 确保YOLOv5版本与PyTorch版本匹配。 最后,用户需要验证修改后是否解决了错误,并确保训练过程正常运行。</think>针对YOLOv5训练时出现的`TypeError: &#39;weights_only&#39; is an invalid keyword argument`错误,以下是逐步解决方案: ### 错误原因分析 该错误源于PyTorch版本与YOLOv5代码的兼容性问题。`weights_only`参数是PyTorch 1.13.0及以上版本新增的功能,用于限制仅加载模型权重数据[^1]。若使用PyTorch 1.10.2等旧版本,调用此参数会导致语法错误。 ### 解决方案 #### 方法一:修改YOLOv5源码(推荐) 1. **定位代码位置** 打开`utils/torch_utils.py`文件,搜索`torch.load`调用语句。常见代码段为: ```python model = torch.load(weights, map_location=device, weights_only=True) ``` 2. **移除非法参数** 删除`weights_only=True`参数,修改为: ```python model = torch.load(weights, map_location=device) ``` 3. **保存并重试训练** 修改后保存文件,重新运行`train.py`。 #### 方法二:升级PyTorch版本 若需保留`weights_only`参数的安全检查功能: ```bash # 升级PyTorch至1.13.0+ pip install torch==1.13.0 torchvision==0.14.0 ``` 注意:升级后需验证CUDA驱动、其他依赖库的兼容性。 ### 验证结果 ```bash python train.py --img 640 --batch 16 --epochs 3 --data coco128.yaml --weights yolov5s.pt ``` 若不再报错且正常开始训练,则问题已解决。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值