碎碎念
问题是这样的,今天在看鱼书(《深度学习进阶:自然语言处理》)。看到SVD分解:使用奇异值分解(singular value decomposition,SVD)对矩阵进行降维。
然后我手写了一下书里的代码,结果和书中的输出不一样。本来我想越过这个问题不管它,因为书里还用matplotlib画了散点图,我想我画一下看看和人家结果一不一样不就行了嘛。结果我画图也出bug了。在不能使用图的情况下我只好硬着头皮查资料看看我的SVD分解是不是出错了。
然后我去百度,百度到了什么SVD结果和书上不一样啊和PPT不一样啊怎么的,但是到底也没说为什么,所以我只好自己写一下子了。
SVD是什么
SVD就是把一个矩阵分解成U、S、V三个矩阵。其中U、V是两个列向量彼此正交的矩阵。S是除了对角线元素其他都为0的对角矩阵。
示意图大概长这样:
然后知乎上一个例子写的分解公式大概是这样:
原答主是用图像举的例子,分解的项数越多图片越精细(可以参考拉格朗日余项啊之类的项数越多越精细)。
更详细的看知乎:奇异值的物理意义是什么? - 知乎 (zhihu.com)
回到代码
我是个数学废物,所以我也不知道结果不一样究竟是什么造成的,但是看完上边那个公式,据我猜测可能是计算保留的项数不一样。所以造成了我和书上的答案不一样。
那如何验证你的结果是否正确呢?
使用一句简单的u@torch.diag(s)@v
即可。
-
@
是pytorch里的张量乘法(区分*
是按位乘) - 结果中的S矩阵是个对角矩阵,但是给出的是个向量,需要使用
torch.diag()
将其转化为对角矩阵
给一段代码自己试一下:
import torch
# 随机生成一个5*5的张量
tensor = torch.rand(5,5)
# 使用pytorch自带的svd进行分解
u,s,v = torch.linalg.svd(tensor)
# 输出源张量,分解后的三个张量,验证结果
print(f'tensor:\n{tensor}')
print(f'U:\n{u}\nS:\n{s}\nV\n{v}')
print(f'res:\n{u@torch.diag(s)@v}')
我的结果长这样,可以看到tensor和res的结果是一样的。
你的结果可能和你的矩阵还是不一样?
比如下图这种。
其实下图这种只是乍一看不一样而已。 实际上仔细看一下数字还是一样的,看一下数量级,比如tensor[0][0]这个位置,原来是0,最后计算结果是5.0037e-07,给0.00000050037和0差别很大吗……所以这点差异可以忽而略。还是可以认为结果矩阵是和原矩阵一样的。