tf计算矩阵维度_张量分解(二):高性能计算篇

9e190d696ad62f327cf586a2e42288d7.png

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

计算时间

在张量分解的计算过程中,最后的计算核心是对unfold之后的矩阵进行svd分解,svd分解的复杂度几乎是n的3次方(

),因此是最耗时的部分。

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

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

Randomized SVD

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

a9bdb5f0e3fd8ba579b568aa4ccf3bcb.png

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

sklearn.utils.extmath.randomized_svd - scikit-learn 0.20.2 documentation​scikit-learn.org Randomized SVD 算法介绍与实现​cloud.tencent.com

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

在对比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算法。在相同的资源配置下,运行时长的结果对比如下

7e53971f9bd0127cf59ae4f62e618441.png

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

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

  • 项目地址:https://github.com/mars-project/mars
  • 文档地址:https://mars-project.readthedocs.io/en/latest/index.html

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

3e0bde777bd63ab5ae4faf3eb92b20dd.png

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

Mars 算法实践--人脸识别-云栖社区-阿里云​yq.aliyun.com
5194504bb323c8e5e27a7bbf2c03e4bb.png

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

6c12cf05b118d57af113ba51200ed27e.png

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

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

占用内存

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

62030d65cd2e1d9f1e634f2f72f52478.png

怎样减少的内存的消耗的呢?答案还是阿里的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分解的时候可以用到,希望帮助到有需要的人!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值