matlab中的k-均值是否内存不足取决于距离函数?
我在一个大而稀疏的矩阵(10000000000x1000)上使用了k-means和matlab。现在问题来了-使用余弦相似性作为距离函数,我在几分钟内得到“内存不足。键入帮助内存以获取选项”消息。然而,如果我使用欧几里德距离,它运行得非常完美(相同的矩阵) 这有点奇怪,因为距离是成对计算的,每次距离计算不需要超过一个小的常量内存 在较小的矩阵(1000x1000,但不是稀疏矩阵)上使用k-均值时,余弦效果非常好 技术细节: 这台机器是64位的,带有8GB RAM。 如果您想尝试:可以找到矩阵(它位于sendspace上,因此它将在几周内可用) 文件采用稀疏格式:[行]\t[列]\t[值]\n matlab代码:matlab中的k-均值是否内存不足取决于距离函数?,matlab,memory-management,cluster-analysis,distance,k-means,Matlab,Memory Management,Cluster Analysis,Distance,K Means,我在一个大而稀疏的矩阵(10000000000x1000)上使用了k-means和matlab。现在问题来了-使用余弦相似性作为距离函数,我在几分钟内得到“内存不足。键入帮助内存以获取选项”消息。然而,如果我使用欧几里德距离,它运行得非常完美(相同的矩阵) 这有点奇怪,因为距离是成对计算的,每次距离计算不需要超过一个小的常量内存 在较小的矩阵(1000x1000,但不是稀疏矩阵)上使用k-均值时,余弦效果非常好 技术细节: 这台机器是64位的,带有8GB RAM。 如果您想尝试:可以找到矩阵(它
f=load(filename);
v=spconvert(f);
c=kmeans(v,9);
c=kmeans(v,9,'distance','cosine');
谢谢 如果检查
kmeans.m
函数,则余弦距离的代码可归结为两个关键部分,这可能会引发内存不足错误。首先让我介绍一下涉及的主要变量:
:行是观察向量,列是维度(数据)X
:行是质心,列是尺寸(簇质心)C
>> whos X Xnorm
Name Size Bytes Class Attributes
X 1017564x1000 83056640 double sparse
Xnorm 1017564x1 12210776 double sparse
因此,Xnorm(:,one(1,p))
将尝试分配大小为12210776*1000字节=11.3722 GB的临时矩阵,这显然是导致内存不足错误的原因
(对于感兴趣的人来说,双稀疏矩阵X
内部需要12*nnz(X)+4*size(X,2)字节
进行存储,而完整表示需要prod(size(X))*8字节
。在您的情况下,这大约需要80MB而不是11.5GB的内存!)
这一行可以用不同的(可能更慢的)方式编写,这样可以避免巨大的空间需求,这通常是矢量化的一个缺点。只需在每一行上循环并除以范数。更好的是,我们可以使用专门为此类情况设计的BSXFUN函数(避免使用REPMAT和索引技巧):
有趣的是,在KMEANS文件的其他地方有注释的代码段,在这些地方,这个问题得到了明确的考虑,因此选择了使用较慢的for循环,但保证不会耗尽内存
2)
第二个临界段是实际计算距离的地方。兴趣代码如下所示:
n = size(X,1);
nclusts = size(C,1);
D = zeros(n,nclusts);
for i = 1:nclusts
D(:,i) = max(1 - X*C(i,:)', 0);
end
基本上,它计算每个数据实例与每个集群质心的内积(一次一个质心,相对于整个数据向量)。同样,如果这会导致问题,您可以简单地将矢量化产品展开成一个逐步循环,如下所示:
for i = 1:nclusts
for j = 1:n
D(j,i) = max(1 - dot(X(j,:),C(i,:)), 0);
end
end
所以你明白了;当你的矩阵非常大时,你必须小心那些会产生较大中间结果的操作,如果可能的话,用一个在较小范围内操作的显式循环来代替它们
顺便说一句,使用欧几里德距离时,您不会遇到相同的问题,因为它是用循环而不是单线矢量化解决方案编写的。以下是计算距离函数的部分:
for i = 1:nclusts
D(:,i) = (X(:,1) - C(i,1)).^2;
for j = 2:p
D(:,i) = D(:,i) + (X(:,j) - C(i,j)).^2;
end
% D(:,i) = sum((X - C(repmat(i,n,1),:)).^2, 2); %# <--- commented code
end
请注意,在完成之前,我没有尝试对整个数据进行集群。我在一台4GB的32位机器上运行(由于架构限制,其中MATLAB只能访问3GB),因此请报告建议的更改是否确实对64位/8GB硬件产生了影响;) 第一个kmeans需要多长时间@ScienceFriction:下载文件太大。。您应该这样做:f=load(文件名);v=SPF;保存output.mat v
然后上传mat文件(应该小得多),感谢您提供的详细答案。我会试着报告。在男性时代,我选择了这里描述的算法:(源代码可用:),它非常快,尽管不能保证是最优的。@ScienceFriction:我认为这是一个很好的选择。但为了澄清你的最后一句话,这个小批量方法被认为是相对于完全收敛的批处理Kmeans算法而言不是最优的,该算法本身只在给定初始种子的情况下给出局部最优。毕竟这是一个NP难问题,在相同的数据上花了大约20分钟。这很好。当然是局部最优的(我们尝试了不同的种子采样/创建方法,以获得更好的、仍然是启发式的结果。再次感谢。
for i = 1:nclusts
for j = 1:n
D(j,i) = max(1 - dot(X(j,:),C(i,:)), 0);
end
end
for i = 1:nclusts
D(:,i) = (X(:,1) - C(i,1)).^2;
for j = 2:p
D(:,i) = D(:,i) + (X(:,j) - C(i,j)).^2;
end
% D(:,i) = sum((X - C(repmat(i,n,1),:)).^2, 2); %# <--- commented code
end
for i=1:nclusts
D(:,i) = sum(bsxfun(@minus, X, C(i,:)).^2, 2);
end