<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近在研究 Yolov2 論文的時候,發現作者在做先驗框聚類使用的指標並非歐式距離,而是IOU。在找了很多資料之後,基本確定 Python 沒有自定義指標聚類的函數,所以打算自己做一個
設訓練集的 shape 是 [n_sample, n_feature],基本思路是:
因為設計之初就打算使用自定義距離函數,所以求導是很大的難題。筆者不才,最終決定藉助 PyTorch 自動求導的天然優勢
先給出歐式距離的計算函數
def Eu_dist(data, center): """ 以 歐氏距離 為聚類準則的距離計算函數 data: 形如 [n_sample, n_feature] 的 tensor center: 形如 [n_cluster, n_feature] 的 tensor""" data = data.unsqueeze(1) center = center.unsqueeze(0) dist = ((data - center) ** 2).sum(dim=2) return dist
然後就是聚類器的程式碼:使用時只需關注 __init__、fit、classify 函數
import torch import numpy as np import matplotlib.pyplot as plt Adam = torch.optim.Adam def get_progress(current, target, bar_len=30): """ current: 當前完成任務數 target: 任務總數 bar_len: 進度條長度 return: 進度條字串""" assert current <= target percent = round(current / target * 100, 1) unit = 100 / bar_len solid = int(percent / unit) hollow = bar_len - solid return "■" * solid + "□" * hollow + f" {current}/{target}({percent}%)" class Cluster: """ 聚類器 n_cluster: 簇中心數 dist_fun: 距離計算函數 kwargs: data: 形如 [n_sample, n_feather] 的 tensor center: 形如 [n_cluster, n_feature] 的 tensor return: 形如 [n_sample, n_cluster] 的 tensor init: 初始簇中心 max_iter: 最大迭代輪數 lr: 中心點座標學習率 stop_thresh: 停止訓練的loss浮動閾值 cluster_centers_: 聚類中心 labels_: 聚類結果""" def __init__(self, n_cluster, dist_fun, init=None, max_iter=300, lr=0.08, stop_thresh=1e-4): self._n_cluster = n_cluster self._dist_fun = dist_fun self._max_iter = max_iter self._lr = lr self._stop_thresh = stop_thresh # 初始化引數 self.cluster_centers_ = None if init is None else torch.FloatTensor(init) self.labels_ = None self._bar_len = 20 def fit(self, data): """ data: 形如 [n_sample, n_feature] 的 tensor return: loss浮動紀錄檔""" if self.cluster_centers_ is None: self._init_cluster(data, self._max_iter // 5) log = self._train(data, self._max_iter, self._lr) # 開始若干輪次的訓練,得到loss浮動紀錄檔 return log def classify(self, data, show=False): """ data: 形如 [n_sample, n_feature] 的 tensor show: 繪製分類結果 return: 分類標籤""" dist = self._dist_fun(data, self.cluster_centers_) self.labels_ = dist.argmin(axis=1) # 將標籤載入到範例屬性 if show: for idx in range(self._n_cluster): container = data[self.labels_ == idx] plt.scatter(container[:, 0], container[:, 1], alpha=0.7) plt.scatter(self.cluster_centers_[:, 0], self.cluster_centers_[:, 1], c="gold", marker="p", s=50) plt.show() return self.labels_ def _init_cluster(self, data, epochs): self.cluster_centers_ = data.mean(dim=0).reshape(1, -1) for idx in range(1, self._n_cluster): dist = np.array(self._dist_fun(data, self.cluster_centers_).min(dim=1)[0]) new_cluster = data[np.random.choice(range(data.shape[0]), p=dist / dist.sum())].reshape(1, -1) # 取新的中心點 self.cluster_centers_ = torch.cat([self.cluster_centers_, new_cluster], dim=0) progress = get_progress(idx, self._n_cluster, bar_len=self._n_cluster if self._n_cluster <= self._bar_len else self._bar_len) print(f"rCluster Init: {progress}", end="") self._train(data, epochs, self._lr * 2.5, init=True) # 初始化簇中心時使用較大的lr def _train(self, data, epochs, lr, init=False): center = self.cluster_centers_.cuda() center.requires_grad = True data = data.cuda() optimizer = Adam([center], lr=lr) # 將中心資料載入到 GPU 上 init_patience = int(epochs ** 0.5) patience = init_patience update_log = [] min_loss = np.inf for epoch in range(epochs): # 對樣本分類並更新中心點 sample_dist = self._dist_fun(data, center).min(dim=1) self.labels_ = sample_dist[1] loss = sum([sample_dist[0][self.labels_ == idx].mean() for idx in range(len(center))]) # loss 函數: 所有樣本到中心點的最小距離和 - 中心點間的最小間隔 loss.backward() optimizer.step() optimizer.zero_grad() # 反向傳播梯度更新中心點 loss = loss.item() progress = min_loss - loss update_log.append(progress) if progress > 0: self.cluster_centers_ = center.cpu().detach() min_loss = loss # 脫離計算圖後記錄中心點 if progress < self._stop_thresh: patience -= 1 # 耐心值減少 if patience < 0: break # 耐心值歸零時退出 else: patience = init_patience # 恢復耐心值 progress = get_progress(init_patience - patience, init_patience, bar_len=self._bar_len) if not init: print(f"rCluster: {progress}titer: {epoch + 1}", end="") if not init: print("") return torch.FloatTensor(update_log)
KMeans++ 是以歐式距離為聚類準則的經典聚類演演算法。在 iris 資料集上,KMeans++ 遠遠快於我的聚類器。但在我反覆對比測試的幾輪裡,我的聚類器精度也是不差的 —— 可以看到下圖裡的聚類結果完全一致
KMeans++ | My Cluster | |
Cost | 145 ms | 1597 ms |
Center | [[5.9016, 2.7484, 4.3935, 1.4339], [5.0060, 3.4280, 1.4620, 0.2460], | [[5.9016, 2.7485, 4.3934, 1.4338], |
雖然速度方面與老牌演演算法對比的確不行,但是我的這個聚類器最大的亮點還是自定義距離函數
本來想用 Yolov4 檢測框聚類引入的 CIoU 做聚類,但是沒法解決梯度彌散的問題,所以退其次用了 DIoU
def DIoU_dist(boxes, anchor): """ 以 DIoU 為聚類準則的距離計算函數 boxes: 形如 [n_sample, 2] 的 tensor anchor: 形如 [n_cluster, 2] 的 tensor""" n_sample = boxes.shape[0] n_cluster = anchor.shape[0] dist = Eu_dist(boxes, anchor) # 計算歐式距離 union_inter = torch.prod(boxes, dim=1).reshape(-1, 1) + torch.prod(anchor, dim=1).reshape(1, -1) boxes = boxes.unsqueeze(1).repeat(1, n_cluster, 1) anchor = anchor.unsqueeze(0).repeat(n_sample, 1, 1) compare = torch.stack([boxes, anchor], dim=2) # 組合檢測框與 anchor 的資訊 diag = torch.sum(compare.max(dim=2)[0] ** 2, dim=2) dist /= diag # 計算外接矩形的對角線長度 inter = torch.prod(compare.min(dim=2)[0], dim=2) iou = inter / (union_inter - inter) # 計算 IoU dist += 1 - iou return dist
我提取了 DroneVehicle 資料集的 650156 個預測框的尺寸做聚類,在這個過程中發現因為小尺寸的預測框過多,導致聚類中心聚集在原點附近。所以對 loss 函數做了改進:先分類,再計算每個分類下的最大距離之和
橫軸表示檢測框的寬度,縱軸表示檢測框的高度,其數值都是相對於原圖尺寸的比例。若原圖尺寸為 608 * 608,則得到的 9 個先驗框為:
[ 2, 3 ] | [ 9, 13 ] | [ 19, 35 ] |
[ 10, 76 ] | [ 60, 14 ] | [ 25, 134 ] |
[ 167, 25 ] | [ 115, 54 ] | [ 70, 176 ] |
到此這篇關於Python自定義指標聚類的文章就介紹到這了,更多相關Python自定義指標聚類內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45