我正在尝试使用numpy python中的reshape命令在第三级/模式张量上执行展开操作。我不确定我在做什么是正确的。我发现本文在线张量分解。还找到了此代码:作者撰写的SVD图像压缩:
颜色图像在Python中表示为3维数阵列 - 表示颜色值(红色,绿色蓝色(的第三维。但是,SVD方法适用于二维矩阵。因此,我们必须找到一种将3维数组转换为2维数组的方法,应用SVD并将其重新构造为3维数组。有两种方法可以做到。我们将在下面显示这两种方法。
- 重塑方法
- 图层方法
重塑方法来压缩颜色图像:
此方法涉及使用Numpy的Reshape方法将图像阵列的第三维平坦到第二维。
image_reshaped = image.reshape((original_shape[0],original_shape[1]*3))
我正在尝试理解重塑方法。在我看来,这就像在3级/模式张量上进行的操作。假设我有一个大小nxmxp的数组,如果使用以下python命令: reshape(N, M*P)
?
这是我测试展开操作的方式:
import cv2
import numpy as np
def m_unfold(thrd_order_tensor,m):
matrix = []
if m == 1:
matrix = thrd_order_tensor.reshape((thrd_order_tensor.shape[0], thrd_order_tensor.shape[1]*3))
#matrix = np.hstack([thrd_order_tensor[:, :, i] for i in range(thrd_order_tensor.shape[2])])
if m == 2:
matrix = thrd_order_tensor.reshape((thrd_order_tensor.shape[1], thrd_order_tensor.shape[0]*3))
#matrix = np.hstack([thrd_order_tensor[:, :, i].T for i in range(thrd_order_tensor.shape[2])])
if m == 3:
matrix = thrd_order_tensor.reshape((3, thrd_order_tensor.shape[0]*thrd_order_tensor.shape[1]))
#matrix = np.vstack([thrd_order_tensor[:, :, i].ravel() for i in range(thrd_order_tensor.shape[2])])
return matrix
def fold(matrix, os):
#os is the original shape
tensor = matrix.reshape(os)
return tensor
im = cv2.imread('target.jpg')
original_shape = im.shape
image_reshaped = m_unfold(im,3)
U, sig, V = LA.svd(image_reshaped, full_matrices=False)
img_restrd = np.dot(U[:,:], np.dot(np.diag(sig[:]), V[:,:]))
img_restrd = fold(img_restrd,original_shape)
img_restrd = img_restrd.astype(np.uint8)
cv2.imshow('image',img_restrd)
cv2.waitKey(0)
cv2.destroyAllWindows()
tl; dr; dr:假设您正在使用元素的默认(c-(排序,则Tensor.Reshape(N,M*P(根据使用的定义,张量沿其第一个模式进行张量的展开。
。长答案更加微妙。展开的定义不止一个。一般而言,N模式展开对应于i(将n-th模式移至开始和ii(将结果重塑为矩阵。进行重塑的方式可以为您提供不同的展开定义。
首先,一点点术语:通过改变张量的n-th索引,同时使所有其他固定所有其他固定,从而获得了张量的n-th模式(即尺寸(的纤维。对于矩阵,我们都知道纤维是行(仅不同的第一个索引(或列(仅更改第二个索引(。该概念概括为任何阶的张量(对于三阶张量,沿第三次模式的纤维也称为管(。
通过沿张量的n-th模式堆叠纤维以获得矩阵,从而获得了张量的N模式。展开的各种定义因这些纤维的排序而有所不同。
现在,在张紧器被存储的途中:将元素存储在内存中,是一个长向量,从最后一个维度到第一个维度,或者反之亦然。这些被称为行-major(或c(和柱 - 马约尔(或fortran(排序。当您在张量上使用reshape
时,通常会在内存中读取它们的元素。
最确定的定义在他们的张量分解方面被Kolda和Bader推广。他们的论文张量分解和应用 在2009年,是一个很好的介绍。他们对展开的定义对应于张量的reshape
,并用元素的fortran排序。这是MATLAB中的默认值,他们在其中实现了方法。
由于您提到您正在使用Python,因此我假设您正在使用numpy,以及元素的默认排序(即c-ordering(。您可以使用对展开的不同定义来匹配该排序,或者使用更复杂的功能展开:
import numpy as np
def f_unfold(tensor, mode=0):
"""Unfolds a tensors following the Kolda and Bader definition
Moves the `mode` axis to the beginning and reshapes in Fortran order
"""
return np.reshape(np.moveaxis(tensor, mode, 0),
(tensor.shape[mode], -1), order='F')
或,就像我们在Tensorly中所做的那样,您可以使用与元素的C级订购的定义。
只要您保持一致(尽管在某些情况下,各种定义会诱发略有不同的属性(,这并不重要。
最后,回到您的第一个问题,如果您的大小张量(n,m,p(表示为numpy数组,并带有元素的c序列,则reshape(N, M*P)
为您提供了第一个的展开该张量的模式使用展开的"张力"定义。如果您想要" kolda&bader"版本的展开版本,则可以使用上面定义的f_unfold
函数。
请注意,无论您使用哪种定义,如果要沿n-th模式展开,则首先必须在重塑之前将此模式放置(例如使用np.moveaxis(tensor, n, 0)
(。
我写了一篇博客文章,介绍了您对详细信息感兴趣的张量的定义。
以下代码执行3D张量的三个可能的模态展开(从本文中获取符号和示例(:
In [224]: import numpy as np
In [225]: n1, n2, n3 = 3, 4, 2
In [226]: A = 1 + np.arange(n1*n2*n3).reshape(n3, n1, n2).transpose([1, 2, 0])
In [227]: A[:, :, 0] # frontal slice 1
Out[227]:
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
In [228]: A[:, :, 1] # frontal slice 2
Out[228]:
array([[13, 14, 15, 16],
[17, 18, 19, 20],
[21, 22, 23, 24]])
In [229]: A1 = np.hstack([A[:, :, i] for i in range(A.shape[2])])
In [230]: A1 # mode 1
Out[230]:
array([[ 1, 2, 3, 4, 13, 14, 15, 16],
[ 5, 6, 7, 8, 17, 18, 19, 20],
[ 9, 10, 11, 12, 21, 22, 23, 24]])
In [231]: A2 = np.hstack([A[:, :, i].T for i in range(A.shape[2])])
In [232]: A2 # mode 2
Out[232]:
array([[ 1, 5, 9, 13, 17, 21],
[ 2, 6, 10, 14, 18, 22],
[ 3, 7, 11, 15, 19, 23],
[ 4, 8, 12, 16, 20, 24]])
In [233]: A3 = np.vstack([A[:, :, i].ravel() for i in range(A.shape[2])])
In [234]: A3 # mode 3
Out[234]:
array([[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]])