参考了xinyu chen的知乎文章浅谈张量分解(二):张量分解的数学基础 ,用TensorFlow实现张量计算的相关定义。

import tensorflow as tf
import numpy as np
sess=tf.Session()

1. Kronecker product

A otimes B=egin{bmatrix}     a_{11}B & a_{12}B & a_{13}B & dots  & a_{1n}B \     a_{21}B & a_{22}B & a_{23}B & dots  & a_{2n}B \     vdots & vdots & vdots & ddots & vdots \     a_{d1}B & a_{d2}B & a_{d3}B & dots  & a_{dn}B end{bmatrix}

A0 = np.array([[1,2],[3,4]])
B0 = np.array([[5,6,7],[8,9,10]])
A = tf.placeholder(tf.float32, shape=[A0.shape[0],A0.shape[1]])
B = tf.placeholder(tf.float32, shape=[B0.shape[0],B0.shape[1]])

Cnp = np.kron(A0, B0)
print(Cnp)
[[ 5 6 7 10 12 14]
[ 8 9 10 16 18 20]
[15 18 21 20 24 28]
[24 27 30 32 36 40]]
def Kron_TF(A, B):
A_shape = A.get_shape()
B_shape = B.get_shape()

for i in range(A_shape[0]):
for j in range(A_shape[1]):
if j==0:
temp = tf.squeeze(A[i,j]*B)

else:
temp = tf.concat([temp,tf.squeeze(A[i,j]*B)],1)
if i==0:
result = temp
else:
result = tf.concat([result,temp],0)
return result

kron = Kron_TF(A,B)
print(sess.run(kron,feed_dict={A:A0,B:B0}))
[[ 5. 6. 7. 10. 12. 14.]
[ 8. 9. 10. 16. 18. 20.]
[15. 18. 21. 20. 24. 28.]
[24. 27. 30. 32. 36. 40.]]

2. Khatri-Rao product

A odot B=(overrightarrow{a_{1}}otimes overrightarrow{b_{1}},overrightarrow{a_{2}}otimes overrightarrow{b_{2}},overrightarrow{a_{3}}otimes overrightarrow{b_{3}},dots,overrightarrow{a_{k}}otimes overrightarrow{b_k})

def KhRao_TF(A,B):
A_shape = A.get_shape()
B_shape = B.get_shape()
for i in range(A_shape[1]):
if i==0:
result = tf.expand_dims(Kron_TF(tf.expand_dims(A[:,i],1),tf.expand_dims([B[:,i]],1)),1)
else:
result = tf.concat([result,tf.expand_dims(Kron_TF(tf.expand_dims(A[:,i],1),tf.expand_dims([B[:,i]],1)),1)],1)
return result

A0 = np.array([[1,2],[3,4]])
B0 = np.array([[5,6],[7,8],[9,10]])
A = tf.placeholder(tf.float32, shape=[A0.shape[0],A0.shape[1]])
B = tf.placeholder(tf.float32, shape=[B0.shape[0],B0.shape[1]])

khrao = KhRao_TF(A,B)
print(sess.run(khrao,feed_dict={A:A0,B:B0}))
[[ 5. 12.]
[ 7. 16.]
[ 9. 20.]
[15. 24.]
[21. 32.]
[27. 40.]]

3. Vector outer product

overrightarrow{a}circ overrightarrow{b}=overrightarrow{a} overrightarrow{b}^{T}

a0 = np.array([[1],[2]])
b0 = np.array([[3],[4]])
c0 = np.array([[5],[6],[7]])
a = tf.placeholder(tf.float32, shape=[None,1])
b = tf.placeholder(tf.float32, shape=[None,1])
c = tf.placeholder(tf.float32, shape=[None,1])

# vector outer product
M = tf.squeeze(tf.tensordot(a, b, axes=0))
M_ = sess.run(M, feed_dict={a:a0,b:b0})
print(M_.shape)
print(M_)
(2, 2)
[[3. 4.]
[6. 8.]]

4. matrix vector outer product

A circ overrightarrow{c}=(A*c(0,1);A*c(1,1)dots ;A*c(n,1))

# matrix & vector outer product
Mc = tf.squeeze(tf.tensordot(M, c, axes=0))
Mc_ = sess.run(Mc, feed_dict={a:a0,b:b0,c:c0})
print(Mc_.shape)
print(Mc_)
print(Mc_[:,:,0])
print(Mc_[:,:,1])
print(Mc_[:,:,2])
(2, 2, 3)
[[[15. 18. 21.]
[20. 24. 28.]]

[[30. 36. 42.]
[40. 48. 56.]]]
[[15. 20.]
[30. 40.]]
[[18. 24.]
[36. 48.]]
[[21. 28.]
[42. 56.]]

4. Unfolding

X = np.zeros([2,2,2,2])
X1 = np.array([[1,2],[3,4]])
X2 = np.array([[5,6],[7,8]])
X3 = np.array([[9,10],[11,12]])
X4 = np.array([[13,14],[15,16]])

X[:,:,0,0] = X1
X[:,:,1,0] = X2
X[:,:,0,1] = X3
X[:,:,1,1] = X4
# print(X)
print(X.shape)

X_tensor = tf.placeholder(tf.float32, shape=[2,2,2,2])
X_tensor_ = sess.run(X_tensor, feed_dict={X_tensor:X})

# modal 1 unfolding
for i in range(X.shape[3]):
for j in range(X.shape[2]):
if i==0 and j==0:
X_1 = tf.reshape(X_tensor[:,:,j,i],[X.shape[0],-1])
else:
X_1 = tf.concat([X_1,tf.reshape(X_tensor[:,:,j,i],[X.shape[0],-1])],1)

# modal 2 unfolding
for i in range(X.shape[3]):
for j in range(X.shape[2]):
if i==0 and j==0:
X_2 = tf.reshape(tf.transpose(X_tensor[:,:,j,i],[1,0]),[X.shape[1],-1])
else:
X_2 = tf.concat([X_2,tf.reshape(tf.transpose(X_tensor[:,:,j,i],[1,0]),[X.shape[1],-1])],1)

# modal 3 unfolding
for i in range(X.shape[3]):
for j in range(X.shape[1]):
if i==0 and j==0:
X_3 = tf.reshape(tf.transpose(X_tensor[:,j,:,i],[1,0]),[X.shape[2],-1])
else:
X_3 = tf.concat([X_3,tf.reshape(tf.transpose(X_tensor[:,j,:,i],[1,0]),[X.shape[2],-1])],1)

# modal 4 unfolding
for i in range(X.shape[2]):
for j in range(X.shape[1]):
if i==0 and j==0:
X_4 = tf.reshape(tf.transpose(X_tensor[:,j,i,:],[1,0]),[X.shape[3],-1])
else:
X_4 = tf.concat([X_4,tf.reshape(tf.transpose(X_tensor[:,j,i,:],[1,0]),[X.shape[3],-1])],1)

X_1_,X_2_,X_3_,X_4_ = sess.run([X_1,X_2,X_3,X_4], feed_dict={X_tensor:X})
# print(X_tensor_.shape)
print(X_1_)
print(X_2_)
print(X_3_)
print(X_4_)

(2, 2, 2, 2)
[[ 1. 2. 5. 6. 9. 10. 13. 14.]
[ 3. 4. 7. 8. 11. 12. 15. 16.]]
[[ 1. 3. 5. 7. 9. 11. 13. 15.]
[ 2. 4. 6. 8. 10. 12. 14. 16.]]
[[ 1. 3. 2. 4. 9. 11. 10. 12.]
[ 5. 7. 6. 8. 13. 15. 14. 16.]]
[[ 1. 3. 2. 4. 5. 7. 6. 8.]
[ 9. 11. 10. 12. 13. 15. 14. 16.]]

以上的unfolding方法比较简单粗暴,下面主要采用tensorflow的封装运算完成。需要注意的是:tensorflow的reshape函数与numpy的reshape函数操作维度的顺序不同,为了基于tensorflow的reshape实现张量展开,具体代码如下:

# unfolding function
tf.reset_default_graph()
sess=tf.Session()
X_tensor = tf.placeholder(tf.float32, shape=[4,3,2])
X = np.arange(1,25).reshape((4,3,2),order=F)
dim = X.shape # origin tensors shape (d_1,d_2,...d_n)

def unfold(X_tensor, dim, mode):
order_mode_dim = [mode-1]
order_others = list(range(0,mode-1))+list(range(mode,len(dim)))
order_adjust = order_mode_dim + order_others[::-1]
X_per = tf.transpose(X_tensor,order_adjust)
X_unfold = tf.reshape(X_per,[dim[mode-1],-1])
return X_unfold

X_unfold1 = unfold(X_tensor, dim, 1)
X_unfold2 = unfold(X_tensor, dim, 2)
X_unfold3 = unfold(X_tensor, dim, 3)

X_1_,X_2_,X_3_ = sess.run([X_unfold1,X_unfold2,X_unfold3], feed_dict={X_tensor:X})
print(X_1_)
print(X_2_)
print(X_3_)

5. Folding

# 4 unfolding
X_unfold1 = tf.placeholder(tf.float32, shape=[4,6])
X_unfold2 = tf.placeholder(tf.float32, shape=[3,8])
X_unfold3 = tf.placeholder(tf.float32, shape=[2,12])

def fold(X,dim,mode):
order_mode_dim = [mode-1]
order_others = list(range(0,mode-1))+list(range(mode,len(dim)))
order_adjust = order_mode_dim + order_others[::-1]
dim_set = [dim[i] for i in order_adjust]
order_adjust=[dim_set.index(dim[i]) for i in range(len(dim))]
X_tensor = tf.transpose(tf.reshape(X,dim_set),order_adjust)
print(X_tensor)
return X_tensor

X_fold1 = fold(X_unfold1, dim, 1)
X_fold2 = fold(X_unfold2, dim, 2)
X_fold3 = fold(X_unfold3, dim, 3)

ten1,ten2,ten3 = sess.run([X_fold1,X_fold2,X_fold3], feed_dict={X_unfold1:X_1_,X_unfold2:X_2_,X_unfold3:X_3_})
print(-----------------------------------------------------------------)
print(ten1[:,:,0])
print(ten2[:,:,0])
print(ten3[:,:,0])

note: 更多的源代码请移步我的GitHub

推荐阅读:

相关文章