【发布时间】:2019-07-24 23:06:42
【问题描述】:
我在 pytorch 中使用质心位置的梯度下降而不是期望最大化来构建 Kmeans。损失是每个点到其最近质心的平方距离之和。为了确定离每个点最近的质心,我使用了 argmin,它在任何地方都不可微。但是,pytorch 仍然能够反向传播和更新权重(质心位置),在数据上提供与 sklearn kmeans 相似的性能。
任何想法这是如何工作的,或者我如何在 pytorch 中解决这个问题?对 pytorch github 的讨论表明 argmax 不可微:https://github.com/pytorch/pytorch/issues/1339。
下面的示例代码(在随机点上):
import numpy as np
import torch
num_pts, batch_size, n_dims, num_clusters, lr = 1000, 100, 200, 20, 1e-5
# generate random points
vector = torch.from_numpy(np.random.rand(num_pts, n_dims)).float()
# randomly pick starting centroids
idx = np.random.choice(num_pts, size=num_clusters)
kmean_centroids = vector[idx][:,None,:] # [num_clusters,1,n_dims]
kmean_centroids = torch.tensor(kmean_centroids, requires_grad=True)
for t in range(4001):
# get batch
idx = np.random.choice(num_pts, size=batch_size)
vector_batch = vector[idx]
distances = vector_batch - kmean_centroids # [num_clusters, #pts, #dims]
distances = torch.sum(distances**2, dim=2) # [num_clusters, #pts]
# argmin
membership = torch.min(distances, 0)[1] # [#pts]
# cluster distances
cluster_loss = 0
for i in range(num_clusters):
subset = torch.transpose(distances,0,1)[membership==i]
if len(subset)!=0: # to prevent NaN
cluster_loss += torch.sum(subset[:,i])
cluster_loss.backward()
print(cluster_loss.item())
with torch.no_grad():
kmean_centroids -= lr * kmean_centroids.grad
kmean_centroids.grad.zero_()
【问题讨论】:
-
Argmax 是不可微分的。但是您可以尝试一些技巧,例如homes.cs.washington.edu/~hapeng/paper/peng2018backprop.pdf,该论文还引用了类似思路中的其他一些工作,试图通过某种 argmax/sparsemax 进行反向传播。免责声明:我个人没有处理过此类问题。
标签: machine-learning cluster-analysis pytorch k-means backpropagation