kmeans算法实现及获取anchors

2023-10-30

kmeans算法网上资料很多,其原理简单来说就选取k个聚类中心,然后把剩余的点归类到与其相距最近的聚类中心,是一种无监督算法。缺点和不足有两个,第一个是k需要指定,第二个是对于聚类中心种子点的选取很敏感。本文将以yolov4算法使用kmeans算法生成anchors为例进行说明。

1、计算多个点的kmeans

import numpy as np
#生成假数据
data = np.random.rand(50,2)
print(data.shape)
#生成初始聚类中心
centers = data[np.random.choice(data.shape[0],5,replace=False)]
print(centers.shape)
new_centers = np.zeros(centers.shape)
    
while np.any(centers != new_centers):
    #distance是所有点到centers的一范数距离,使用的是矩阵计算
    distance = np.sum(np.abs(data[:,None,:]-centers),axis=-1)
    index = np.argmin(distance,axis=-1)
    for i in range(centers.shape[0]):
        new_centers[i] = np.mean(data[index==i],axis=0)
    centers = new_centers.copy()
print(new_centers)
(50, 2)
(5, 2)
[[0.33028589 0.17096868]
 [0.37237028 0.88923208]
 [0.49766799 0.553117  ]
 [0.04129898 0.4883419 ]
 [0.88315816 0.29498035]]

2、获取所有的标注框长宽

如以下代码,-filelist可以获得所有训练数据的路径,比如使用VOC格式,那么train.txt文件中存的路径就是/path/VOCdevkit/JPEGimages/XXXX.jpg,对应的标注文件在/path/VOCdevkit/Annotations/XXXX.xml中,yolo格式的标注文件在/path/VOCdevkit/labels/XXXX.xml,XXXX是图片名称。参见以下代码及注释。

def main(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument('-filelist', default = '\\path\\to\\voc\\filelist\\train.txt', 
                        help='path tlelist\n' )
    parser.add_argument('-output_dir', default = 'generated_anchors/anchors', type = str, 
                        help='Output anchor directory\n' )  
    parser.add_argument('-num_clusters', default = 0, type = int, 
                        help='number of clusters\n' )  


    args = parser.parse_args()
    #用来存放anchors文件的文件夹,保存最后的结果
    if not os.path.exists(args.output_dir):
        os.mkdir(args.output_dir)

    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))))
    #获得最后的所有标注形状是(N,2) w,h
    annotation_dims = np.array(annotation_dims)

    eps = 0.005
    #如果没有指定聚类中心,则迭代多个版本
    if args.num_clusters == 0:
        for num_clusters in range(1,11): #we make 1 through 10 clusters 
            anchor_file = join( args.output_dir,'anchors%d.txt'%(num_clusters))

            indices = [ random.randrange(annotation_dims.shape[0]) for i in range(num_clusters)]
            centroids = annotation_dims[indices]
            kmeans(annotation_dims,centroids,eps,anchor_file)
            print('centroids.shape', centroids.shape)
    else:
    #指定的情况下,需要
        anchor_file = join( args.output_dir,'anchors%d.txt'%(args.num_clusters))
        indices = [ random.randrange(annotation_dims.shape[0]) for i in range(args.num_clusters)]
        centroids = annotation_dims[indices]
        kmeans(annotation_dims,centroids,eps,anchor_file)
        print('centroids.shape', centroids.shape)

以上部分就是获得所有标注的宽和高,下面呢是核心的算法kmeans的实现,要读一下代码,我加注释了。

3、求kmeans

width_in_cfg_file = 416.
height_in_cfg_file = 416.

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:
            similarity = w*h/(c_w*c_h)
        elif c_w>=w and c_h<=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) 

def avg_IOU(X,centroids):
    n,d = X.shape
    sum = 0.
    for i in range(X.shape[0]):
        #note IOU() will return array which contains IoU for each centroid and X[i] // slightly ineffective, but I am too lazy
        sum+= max(IOU(X[i],centroids)) 
    return sum/n

def write_anchors_to_file(centroids,X,anchor_file):
    f = open(anchor_file,'w')
    
    anchors = centroids.copy()
    print(anchors.shape)

    for i in range(anchors.shape[0]):
        anchors[i][0]*=width_in_cfg_file/32.
        anchors[i][1]*=height_in_cfg_file/32.


    widths = anchors[:,0]
    sorted_indices = np.argsort(widths)

    print('Anchors = ', anchors[sorted_indices])
        
    for i in sorted_indices[:-1]:
        f.write('%0.2f,%0.2f, '%(anchors[i,0],anchors[i,1]))

    #there should not be comma after last anchor, that's why
    f.write('%0.2f,%0.2f\n'%(anchors[sorted_indices[-1:],0],anchors[sorted_indices[-1:],1]))
    
    f.write('%f\n'%(avg_IOU(X,centroids)))
    print()

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))

    while True:
        D = [] 
        iter+=1           
        for i in range(N):
            d = 1 - IOU(X[i],centroids)
            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)
        
        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)
        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()  

将以上两部分组合,即可进行kmeans聚类从而获得anchors.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

kmeans算法实现及获取anchors 的相关文章

随机推荐

  • 基于Java的航空售票管理系统

    源码下载 http www byamd xyz hui zong 1 摘 要 本课题设计的是航空购票管理系统 本系统主要设计了三个类 分别是Infor类 gongneng类和测试 Test 类 在Infor类里面主要定义了数组 分别是nam
  • 【解决】Python——Max retries exceeded with url: (Caused by NewConnectionError(‘<urllib3.connection

    HTTPConnectionPool host yzw zjnu edu cn port 80 Max retries exceeded with url Caused by NewConnectionError
  • C++Primer Section 2-1

    Section 2 1 Primitive Built in Types Section 2 1 1 Arithmetic Types Differences in Integer Types Differences between cha
  • 如何读懂别人写的vc++代码

    每个人的编程习惯各异规范程度 命名规则 使用习惯也不尽相同 有人爱用Timer 有的人用线程 有的人用PostMessage有的人用SetEvent或回调或直接调用 所以别人的程序也是良莠不齐 所以要求你对编程基础 程序构架 业务规则都要有
  • 95-34-035-Context-HeadContext和TailContext

    文章目录 1 概述 2 继承体系 3 HeadContext 3 1 类签名 4 TailContext 1 概述 HeadContext和TailContext使用继承的方式关联Handler 作为ChannelPipeline双向链表的
  • Sort()函数用法:比较函数写法

    sort 函数 sort函数可以三个参数也可以两个参数 必须包含头文件 include lt algorithm gt using namespace std 它使用的排序方法是类似于快排的方法 时间复杂度为o nlog n Sort函数有
  • 微信开发 "errcode":-1 应该怎么办

    相信不少朋友在微信开发的时候遇到了 string errcode 1 errmsg system error length 38 这个时候并不是你的代码有问题 你只需要将你的PHP文件的编码改成utf 8即可 不知道如何操作的朋友 可以按照
  • Java 前后端分离业务封装 对后端返回值进行封装 PageVO封装

    遇到前后端业务需要不一致时对Controller返回结果进行封装 后端返回结果 前后端分离后 web 端要求结果 counts 2694 pagesize 14 pages 8 page 66 items id 9009384 title
  • qtcpsocket类read函数接收大数据_一篇易懂的CAN 通讯功能实现指南2--READ

    通过一篇易懂的CAN通讯协议指南1 我们知道 CAN总线的2种架构 高速CAN和低速CAN CAN协议帧类型 数据帧 遥控帧 错误帧 过载帧 线与机制 仲裁机制 位定时与同步 以上基础的应用多数体现在硬件处理部分 所以只有少数体现在软件部分
  • Vue-搜索框实现

    热爱生活 热爱技术 热于分享 一 方法分析 1 字符串匹配 BF算法 KMP算法 库函数indexOf均可实现 2 v for循环实时更新元素 3 click 实现点击后页面的跳转同时设置不同id来根据内容的不同来跳转到不同页面 二 代码分
  • 在ESP32的Lvgl8上使用LvglFontTool显示汉字

    这里写目录标题 一 使用LvglFontTool4 0转换字体 二 修改生成的C文件 二 使用字体 用法1 在canvas上绘制 用法2 在label上显示 一 使用LvglFontTool4 0转换字体 这个工具是阿里兄大佬提供的 他的论
  • 对Java中&&和&

    初学java的话可能会对一些预算符不是很理解 什么优先级呀 运算顺序啊 今天就先谈谈 他们的区别 首先 逻辑与 按位与 逻辑或 按位或 比如 if a 2 b 3 说明两者都要满足 如果有一为false 就不会运算输出 if a 2 b 3
  • ffmpeg mkv 转 MP4

    ffmpeg i 源文件名 c v copy c a aac 目标文件名 ffmpeg i 1 mkv c v copy c a aac 1 mp4
  • 【C++】到底什么是链接,它起到了什么作用

    当程序包含了数百万行的代码 以至于人们无法维护这个程序了 于是人们开始寻找新的方法 迫切地希望将程序源代码分散到多个文件中 一个文件一个模块 以便更好地阅读和维护 这个时候 链接器就粉墨登场了 变量名 函数名等仅仅是地址的一种助记符 目的是
  • python里面的pip是什么意思_python中pip是什么

    python中pip是什么 pip是一个以Python计算机程序语言写成的软件包管理系统 他可以安装和管理软件包 另外不少的软件包也可以在 Python软件包索引 英语 Python Package Index 简称PyPI 中找到 命令行
  • 傅里叶描述子欧氏距离_基于旋转轮廓的点云局部浮点型和二值化特征描述(RCS)...

    作者 小毛 Date 2020 05 19 来源 基于旋转轮廓的点云局部浮点型和二值化特征描述 RCS 本次介绍一个发表于Computer Vision and Image Understanding的经典三维点云描述子RCS 论文地址 J
  • 第10节-函数三(高阶函数/匿名函数/闭包/装饰器)

    第10节 函数三 高阶函数 匿名函数 闭包 装饰器 一 高阶函数 二 匿名函数 1 过滤器 2 匿名函数 lambda函数 三 闭包 四 装饰器 一 高阶函数 满足下列特点之一的函数称之为高阶函数 特点1 接收一个或者多个函数作为参数 特点
  • node-formidable源码:原生javascript解析前端传输的FormData

    本系列文章是本人学习相关知识时所积累的笔记 以记录自己的学习历程 也为了方便回顾知识 故文章内容较为随意简练 抱着学习目的来的同学务必转移他处 以免我误人子弟 参考资料 酷勤网 在Koa和Express中 已经通过node formidab
  • css 实现三角形阴影

    平时工作中 设计给出的类似于对话框的样式 基本上都会有阴影 这个时候一般都是有两种方式实现 一是用背景图 二是用代码实现 如图样式 这里只说使用代码来实现
  • kmeans算法实现及获取anchors

    kmeans算法网上资料很多 其原理简单来说就选取k个聚类中心 然后把剩余的点归类到与其相距最近的聚类中心 是一种无监督算法 缺点和不足有两个 第一个是k需要指定 第二个是对于聚类中心种子点的选取很敏感 本文将以yolov4算法使用kmea