张量分解(二):高性能计算篇

张量分解(二):高性能计算篇

我们知道张量分解实验里面的问题就是计算量很大,表现在计算需要的时间长,占用内存资源多。下面我们挨个来分析。

计算时间

在张量分解的计算过程中,最后的计算核心是对unfold之后的矩阵进行svd分解,svd分解的复杂度几乎是n的3次方( O(min(m^2n,mn^2)) ),因此是最耗时的部分。

耗时意味这两件事情:1.实时性不强,所以实际应用有困难。2.实验做起来费劲,调整实验麻烦,这一点做深度学习的可能深有体会。

下面我提供两种快速计算SVD分解的方法,根据实验可以极大提高svd的计算效率。

Randomized SVD

我看到很多张量分解的库都是这样计算svd的,首先进行Full svd的计算,可以直接调用numpy的svd函数计算,然后根据精度需求进行截断,称之为Truncated svd。

在sklearn里面提供了一种近似计算截断后的svd的算法——randomized SVD,截断的奇异值个数越多,那么计算速度越快。以我实验的结果来看,结果的近似程度很高。具体的原因我不介绍了,放一下sklearn api和腾讯的一篇文章,其中腾讯的文章里面介绍的很详细了,甚至用spark实现了并行计算。

这里我直接放腾讯博客里面的试验了:

在对比Randomized SVD算法与SVD算法的运行情况时,使用了两种类型的数据:稠密型与稀疏型。各配置如下:

  1. 8001行1850列的稠密型矩阵,进行k值为800的矩阵分解,其中Randomized SVD算法的迭代类型选择none,过采样参数为5,迭代轮数为2。其他参数同SVD算法;
  2. 760万行6万列的稀疏型矩阵,进行k值为2000的矩阵分解,其中Randomized SVD算法的迭代类型选择QR,过采样参数为10,迭代轮数为2。其他参数同SVD算法。在相同的资源配置下,运行时长的结果对比如下

并行SVD分解(只包括两种特殊矩阵)

Mars 是由阿里云高级软件工程师@秦续业等人开发的一个基于张量的大规模数据计算的统一框架,目前它已在 GitHub 上开源。该工具能用于多个工作站,而且即使在单块 CPU 的情况下,它的矩阵运算速度也比 NumPy(MKL)快。

这个库里面实现了svd的并行计算(只包括两种特殊矩阵)

这里我也放一下介绍文章:

下面是文章内容的截图,据我实践,真实有效:

这个结果已经很棒了,我看到的当天直接高兴的跳起来了,也期待更一般,更好的算法实现!

至于tensorly等库里面还有用GPU计算的(以tf或者pytorch作为后端),我没有尝试,但是GPU资源更加宝贵,对于几十个G的实验,实在是emmmm.顺便提一句,mars也是支持GPU计算的。

占用内存

上面说完了计算时间部分,下面说一下占用内存。做张量分解的都知道,张量分解的优势通常需要大数据量才能体现出来,但是大数据尤其是维度增加带来的极大的内存消耗,实验难度要求变高。

怎样减少的内存的消耗的呢?答案还是阿里的mars。

这里直接上实验,具体原理可以去看mars的介绍文章。代码如下:

from time import time

start_time = time()
import numpy as np
a = np.random.rand(20000, 100)
U, s, V = np.linalg.svd(a)
print(time()-start_time)

import mars.tensor as mt
start_time = time()
a = mt.random.rand(20000, 100, chunk_size=100)
U, s, V = mt.linalg.svd(a).execute()
print(time()-start_time)

实现结果,使用numpy计算svd的时候,计算过程中内存保持在3个G左右,快计算完的时候,飙升到5个多G。使用mars,内存仅仅使用了100M,速度快了尽十倍!

好了,这篇文章到此结束。唯一遗憾的是,并没有用mars写成的张量分解库(有时间我打算写一下),不过大家在做svd分解的时候可以用到,希望帮助到有需要的人!

编辑于 2019-02-22 21:25