Memory management 为什么我有“我有”呢;OutOfMemoryError“;在我的Kmeans CuPy代码中?

Memory management 为什么我有“我有”呢;OutOfMemoryError“;在我的Kmeans CuPy代码中?,memory-management,out-of-memory,k-means,cupy,Memory Management,Out Of Memory,K Means,Cupy,我对gpu编码非常陌生我发现这个Kmeans cupy代码我的建议是使用大型数据库(n,3)例如,为了实现gpu和cpu上的时间差,我想要有大量的集群,但我得到了一个内存管理错误。有人能告诉我应该采取什么样的方法来研究和修复它吗?我已经研究过了,但我还没有一个明确的开始 导入上下文库 导入时间 进口丘比特 将matplotlib.pyplot作为plt导入 进口numpy @contextlib.contextmanager def定时器(消息): cupy.cuda.Stream.null.s

我对gpu编码非常陌生我发现这个Kmeans cupy代码我的建议是使用大型数据库(n,3)例如,为了实现gpu和cpu上的时间差,我想要有大量的集群,但我得到了一个内存管理错误。有人能告诉我应该采取什么样的方法来研究和修复它吗?我已经研究过了,但我还没有一个明确的开始

导入上下文库
导入时间
进口丘比特
将matplotlib.pyplot作为plt导入
进口numpy
@contextlib.contextmanager
def定时器(消息):
cupy.cuda.Stream.null.synchronize()
开始=时间。时间()
产量
cupy.cuda.Stream.null.synchronize()
end=time.time()
打印(“%s:%f秒“%”(消息,结束-开始))
var_kernel=cupy.ElementwiseKernel(
‘T x0,T x1,T c0,T c1’,‘T out’,
‘输出=(x0-c0)*(x0-c0)+(x1-c1)*(x1-c1)’,
“var_内核”
)
sum_kernel=cupy.ReductionKernel(
'tx,S mask'T out',
'掩码?x:0',
“a+b”,“out=a”,“0”,
“求和内核”
)
count\u kernel=cupy.ReductionKernel(
‘T面具’、‘浮出水面’,
“面具?1.0:0.0”,
‘a+b’、‘out=a’、‘0.0’,
“计数内核”
)
def fit_xp(X、n_群集、最大值):
断言X.ndim==2
#从提供的阵列中获取NumPy或CuPy模块。
xp=cupy.get_阵列_模块(X)
n_样本=len(X)
#制作一个数组来存储标签,指示每个样本是哪个集群
#包含。
pred=xp.zero(n_个样本)
#为每个簇选择初始质心。
初始索引=xp.random.choice(n个样本,n个集群,replace=False)
中心=X[初始索引]
对于范围内(最大值):
#计算每个样本的新标签。
距离=xp.linalg.norm(X[:,无,:]-中心[无,:,:],轴=2)
new_pred=xp.argmin(距离,轴=1)
#如果每个样品的标签没有改变,我们假设
#算法已收敛并退出循环。
如果xp.all(new_pred==pred):
打破
pred=新的pred
#计算每个簇的新质心。
i=xp.arange(n_集群)
掩码=pred==i[:,无]
sums=xp。其中(掩码[:,:,无],X,0)。sum(轴=1)
计数=xp。计数不为零(掩码,轴=1)。重塑形状((n个簇,1))
中心=总和/计数
返回中心
def fit_定制(X、n_集群、max_iter):
断言X.ndim==2
n_样本=len(X)
pred=cupy.zero(n_样本,dtype='float32')
初始索引=cupy.random.choice(n个样本,n个集群,替换=False)
中心=X[初始索引]
对于范围内(最大值):
距离=var_内核(X[:,无,0],X[:,无,1],
中心[None,:,1],中心[None,:,0])
新_pred=cupy.argmin(距离,轴=1)
如果cupy.all(新的pred==pred):
打破
pred=新的pred
i=cupy.arange(n_簇)
掩码=pred==i[:,无]
sums=sum_内核(X,掩码[:,:,无],轴=1)
计数=计数\u内核(掩码,轴=1)。重塑((n\u簇,1))
中心=总和/计数
返回中心
def绘制(X、n_簇、中心、pred、输出):
#将拟合簇的样本和质心绘制到图像文件中。
对于范围内的i(n_簇):
标签=X[pred==i]
plt.scatter(标签[:,0],标签[:,1],c=numpy.rand.rand(3))
plt.散射(
中心[:,0],中心[:,1],s=120,标记=s',面颜色=y',
edgecolors='k')
plt.savefig(输出)
def run_cpu(gpuid,n_集群,num,max_iter,使用自定义内核):##,输出
samples=numpy.random.randn(num,3)
X_列=numpy.r_[样本+1,样本-1]
使用计时器('CPU'):
中心,pred=fit_xp(X_系列,n_集群,最大iter)
def run_gpu(gpuid,n_集群,num,max_iter,使用自定义内核):##,输出
samples=numpy.random.randn(num,3)
X_列=numpy.r_[样本+1,样本-1]
使用cupy.cuda.Device(gpuid):
列车=cupy.asarray(列车)
使用计时器('GPU'):
如果使用自定义内核:
中心,pred=适合定制(X列、n列、最大iter)
其他:
中心,pred=fit_xp(X_系列,n_集群,最大iter)
顺便说一句,我在colab pro 25GB(RAM)中工作,代码使用n_clusters=200和num=1000000,但如果我使用更大的数字,则会出现错误,我运行的代码如下:

runGPU(0201000000,10,真)


任何建议都将受到欢迎,感谢您的时间。

假设CuPy足够聪明,不会创建
var_内核
的广播输入的显式副本,那么输出
距离
必须具有
2*num*num_集群
的大小,这正是它试图分配的6400000000字节。通过从不实际写入到内存的距离(这意味着将
var_内核
argmin
融合),可以减少内存占用。参见部分文档

如果我正确理解了其中的示例,这应该是可行的:

@cupy.fuse(kernel\u name='argmin\u distance')
def argmin_距离(x1、y1、x2、y2):
返回cupy.argmin((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2),轴=1)
下一个问题是其他13.7GB从何而来。其中很大一部分可能只是早期迭代中距离的实例。我不是CuPy专家,但至少在Python/Numpy中,在循环中使用距离不会重用相同的内存,而是在每次调用
var\u内核时分配更多内存。在循环之前分配的
pred
也存在同样的问题。如果CuPy用Numpy的方式做事,那么解决方法就是把
[:]