原本在看这篇论文,Information-theoretical label embeddings for large-scale image classification。
发邮件想问问可以不可分享代码,这是作者回信提到的
I don't have any of that code anymore. But the code for computing PMI-SVD embeddings is basically just a few lines of numpy. The code for training an image model is just regular Keras. There is nothing complicated or magic.
If
occ
is a vector counting label occurences,coocc
is a matrix counting cooccurences, andcardinal
is the total number of occurences, then the embedding code is:
pmi = cardinal * coocc / (np.dot(occ, occ.T) + 10e-5)
pmi[coocc > 0.] = np.log(pmi[coocc > 0.])
pmi[coocc == 0.] = 0.
u, s, _ = np.linalg.svd(pmi)
sigma = np.eye(len(s)) * np.sqrt(s)
embeddings = np.dot(u, sigma[:dim].T)
其中PMI(pointwise mutual information ) 中用到了奇异值分解。
这是论文里的相关描述
于是想找找关于奇异值分解的文章,在知乎找到了这个答案
答案里说到了秩为1的矩阵,于是又去找了几篇文章重温一下秩是什么。
http://blog.csdn.net/u011240016/article/details/52811606
http://blog.csdn.net/u011240016/article/details/52926635
http://blog.csdn.net/u011240016/article/details/52805663
http://blog.csdn.net/u011240016/article/details/53386184
http://blog.csdn.net/u011240016/article/details/52869027
总的来说,组成矩阵的线性无关的向量个数。
比如说下面的矩阵,
第二行和第三行都能用第一行乘某个数字得到,即线性无关(独立)的向量个数是1,即秩是1。
而对于一个秩为1的矩阵,常常给定的是一个列向量与自己的转置之积。
而这种秩是1的矩阵有一个特性,就是能分解成两个矩阵之积。
好了,重温完了关于矩阵和秩的内容,回到知乎看完了关于奇异值分解的答案,明白了sigma其实就是奇异值,而且是按照从大到小排列的。
不过看完了还是不知道原论文中
分解后的三个矩阵为什么这么写。因为最后一个应该是Vt才对,和Ut没什么关系。
这篇文章有一些图很棒,画出了分解后的三个矩阵,方便理解。
下面是用numpy里的而np.linalg.svd试了一下。下面的写法表示维度。2*3表示2维*3维。
A=2*3
U = 2*2
sigma = 2*2
VT = 2*3
可是发现维度是对不上的,sigma本来应该跟A矩阵的大小2*3一样,但linalg.svd()只返回了一个行向量的sigma,并且只有2个奇异值(本来应该有3个),这是因为第三个奇异值为0,舍弃掉了。之所以这样做,是因为当A是非常大的矩阵时,只返回奇异值可以节省很大的存储空间。
接下来试着用这三个矩阵再重组得到A。
sigma是奇异值,先变成奇异值矩阵。变为矩阵后,再加[0, 0]列。这样维度就都符合了
然后就是
U*dia_sigma*VT
。不过必须用np.dot()才是矩阵乘法。复原得到了A。