kmeans+yolo模型优化(附代码)

KMeans优化YOLO模型:理解与代码实践
本文探讨了KMeans算法如何用于优化YOLO模型中的anchor boxes,通过计算box之间的IOU来确定最优形状。文中提供了一个详细的优化实现过程,包括KMeans的IOU距离计算和数据处理步骤,旨在提升模型对物体检测的效率和准确性。
部署运行你感兴趣的模型镜像

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

一、yolo模型和kmeans算法

yolo模型是啥我这里就不多做介绍了,搜索能有一堆大佬解释的很仔细。
kmeans算法是如何与yolo模型结合,又是如何实现模型优化的呢?
解释:
yolo系列的模型在做boundingbox预测的时候,使用了anchor boxes锚框。
.cfg文件内配置如下:

[yolo]
mask = 3,4,5
anchors = 10,14,  23,27,  37,58,  81,82,  135,169,  344,319

主要是用来表示最有可能的object的w和h,所以当模型对一个像素单元进行预测时,会预测出无数个object的框,但是并不能随便预测,主要是要参考anchor box大小,即从已标注的数据中统计到最有可能的object形状。
那这个时候,如果anchor box能够更好的被算出来,那么这个模型就能够更快、更好的框出物品。
在用自己的数据做训练的时候,要先修改anchors,匹配我们⾃⼰的数据,anchors大小通过kmeans聚类得到。

二、优化实现(附代码)

1.kmeans实现

一般来说,计算样本点到质点的距离时,直接算的是两点的距离,然后将样本点划归为距离最小的那个质心。在yolo系列模型中样本点的数据是有具体的业务上的含义,我们其实最终目的是想要知道最有可能的object对应的bounding box的形状。

所以在kmeans算法中,样本点到质点的距离被替换成两个box的iou,即2个box的相似度。d=1-iou(box1,box_cluster),这样d越小,box1与box_cluster越类似,将box划归为box_cluster。

2.读入数据

注:
yolo模型有自己的标注格式: <x_center> <y_center>
普通labelme标注生成的json文件,在输入数据之前要转换成对应的标注格式哦。

f = open(args.filelist)
lines = [line.rstrip('\n') for line in f.readlines()]
annotation_dims = []
size = np.zeros((1,1,3))
for line in lines:
    #line = line.replace('images','labels')
    #line = line.replace('img1','labels')
    line = line.replace('JPEGImages','labels')        
    line = line.replace('.jpg','.txt')
    #line = line.replace('.png','.txt')
    print(line)
    f2 = open(line)
    for line in f2.readlines():
        line = line.rstrip('\n')
        w,h = line.split(' ')[3:]            
        #print(w,h)
        annotation_dims.append(tuple(map(float,(w,h))))
annotation_dims = np.array(annotation_dim)

感觉好像有一堆,但实际上主要是这一句:

w,h = line.split(' ')[3:]            
annotation_dims.append(tuple(map(float,(w,h))

3.功能函数实现

1.IOU计算
需要定义样本点到质⼼点的距离。
计算样本x代表的box和k个质心box_cluster的IOU。(即⽐较box之间的形状相似程度)。IOU:即交并集⽐例,交叉⾯积/总⾯积。

def IOU(x,centroids):
    similarities = []
    k = len(centroids)
    for centroid in centroids:
        c_w,c_h = centroid
        w,h = x
        if c_w>=w and c_h>=h:     #box(c_w,c_h)完全包含box(w,h)
            similarity = w*h/(c_w*c_h)
        elif c_w>=w and c_h<=h:   #box(c_w,c_h)宽⽽扁平
            similarity = w*c_h/(w*h + (c_w-w)*c_h)
        elif c_w<=w and c_h>=h:
            similarity = c_w*h/(w*h + c_w*(c_h-h))
        else: #means both w,h are bigger than c_w and c_h respectively
            similarity = (c_w*c_h)/(w*h)
        similarities.append(similarity) # will become (k,) shape
    return np.array(similarities)

2.kmeans实现

def kmeans(X,centroids,eps,anchor_file):
    N = X.shape[0]
    iterations = 0
    k,dim = centroids.shape
    prev_assignments = np.ones(N)*(-1)    
    iter = 0
    old_D = np.zeros((N,k)) #距离矩阵  N个点,每个点到k个质⼼共计N*K个距离
    while True:
        D = [] 
        iter+=1           
        for i in range(N):
            d = 1 - IOU(X[i],centroids)  #d是⼀个k维的
            D.append(d)   
        D = np.array(D) # D.shape = (N,k)
        print("iter {}: dists = {}".format(iter,np.sum(np.abs(old_D-D))))
        #assign samples to centroids 
        assignments = np.argmin(D,axis=1) #返回每⼀⾏的最⼩值的下标.即当前样本应该归为k个质⼼中的哪⼀个质⼼.
        if (assignments == prev_assignments).all() :  #质⼼已经不再变化
            print("Centroids = ",centroids)
            write_anchors_to_file(centroids,X,anchor_file)
            return
        #calculate new centroids   
        centroid_sums=np.zeros((k,dim),np.float)  #(k,2)
        for i in range(N):
            centroid_sums[assignments[i]]+=X[i]        #将每⼀个样本划分到对应质⼼
        for j in range(k):            
            centroids[j] = centroid_sums[j]/(np.sum(assignments==j)) #更新质⼼
        prev_assignments = assignments.copy()     
        old_D = D.copy()

计算每个样本点到每⼀个cluster质心的距离 d = 1- IOU(X[i],centroids)表⽰样本点到每个cluster质心的距离。
np.argmin(D,axis=1)得到每⼀个样本点离哪个cluster质心最近
argmin函数⽤法参考:https://docs.scipy.org/doc/numpy/reference/generated/numpy.argmin.html
计算每⼀个cluster中的样本点总和,取平均,更新cluster质⼼。

for i in range(N):
    centroid_sums[assignments[i]]+=X[i]        #将每⼀个样本划分到对应质⼼
for j in range(k):            
    centroids[j] = centroid_sums[j]/(np.sum(assignments==j)) #更新质⼼

不断重复上述过程,直到质心不再变化聚类完成。
保存聚类得到的anchor box大小。

您可能感兴趣的与本文相关的镜像

Yolo-v5

Yolo-v5

Yolo

YOLO(You Only Look Once)是一种流行的物体检测和图像分割模型,由华盛顿大学的Joseph Redmon 和Ali Farhadi 开发。 YOLO 于2015 年推出,因其高速和高精度而广受欢迎

### 关于 YOLO 模型训练调参的最佳实践 在 YOLO 模型的训练过程中,参数调整是一个复杂而重要的环节。以下是针对 YOLO 模型训练时的一些最佳实践和参数优化策略: #### 1. 学习率调度器的选择与配置 学习率是影响模型收敛速度的关键因素之一。通常情况下,在初始阶段采用较高的学习率以加速收敛,随后逐渐降低学习率以便更好地逼近全局最小值。推荐使用余弦退火(Cosine Annealing)或阶梯式衰减(Step Decay)的学习率调度器[^1]。 ```python import torch.optim as optim from torch.optim.lr_scheduler import CosineAnnealingLR optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9, weight_decay=5e-4) scheduler = CosineAnnealingLR(optimizer, T_max=num_epochs) ``` #### 2. 数据增强技术的应用 为了提升模型的泛化能力,可以在训练期间引入多种数据增强方法,例如随机裁剪、颜色抖动、水平翻转以及 MixUp 和 CutMix 技术。这些方法能够有效减少过拟合并提高模型对不同场景的适应性[^2]。 #### 3. Batch Size 的设置 Batch Size 对内存占用和梯度估计质量有直接影响。较大的 batch size 可能带来更好的泛化性能,但也可能导致 GPU 显存不足;较小的 batch size 则有助于节省显存资源,但可能会使训练过程更加不稳定。一般建议从小批量开始尝试,并逐步扩大直到达到硬件限制为止[^3]。 #### 4. 权重初始化与迁移学习 如果从头开始训练整个网络,则需特别注意权重初始化方式;而对于大部分实际项目而言,利用预训练权重进行微调往往更为高效。这样不仅可以缩短训练时间,还能获得更高的准确性。 #### 5. Anchor Box 的设计 Anchor box 是 YOLO 中用于预测边界框的重要组件。合理设定 anchor 尺寸对于检测效果至关重要。可以通过 K-means 聚类算法分析训练集中目标尺寸分布情况来自动计算适合当前任务需求的一组 anchors。 #### 6. Loss Function 的调节 YOLO 默认使用的损失函数由定位误差、置信度得分差异及类别概率构成。适当调整各项系数比重可以帮助平衡不同类型错误之间的关系,从而改善最终表现。 #### 7. 增量训练技巧 当需要扩展原有分类体系至新领域时,可考虑采取增量训练模式而非重新构建全新架构。具体做法包括但不限于:预先标注新增样本标签并与已有记录合并存储;挑选恰当替代项填充空白 class ID 等操作步骤。 --- ### 示例代码片段展示如何实现部分上述提到的技术要点 ```python # 定义自定义变换管道 train_transforms = transforms.Compose([ transforms.RandomResizedCrop(416), transforms.ColorJitter(brightness=0.4, contrast=0.4, saturation=0.4, hue=0.1), transforms.RandomHorizontalFlip(), transforms.ToTensor() ]) # 加载预训练权重 model.load_state_dict(torch.load('pretrained_weights.pth')) # 设置锚点聚类生成逻辑 def generate_anchors(cluster_num=9): all_boxes = [] for img_annots in dataset.annotations: boxes = np.array(img_annots['bboxes']) wh = boxes[:, 2:] - boxes[:, :2] all_boxes.extend(list(map(tuple, wh))) kmeans = KMeans(n_clusters=cluster_num).fit(np.array(all_boxes)) return sorted(kmeans.cluster_centers_, key=lambda x:x[0]*x[1]) ``` ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值