### Python 中张量的概念及其使用方法
#### 什么是张量?
在数学和计算机科学领域,张量可以被看作是一个多维数组。一阶张量是一维向量,二阶张量是二维矩阵,而更高维度的张量则表示三维或多维的数据结构[^2]。
---
#### 如何创建张量?
可以通过多种方式在 Python 中创建张量:
1. **NumPy 创建张量**
NumPy 提供了强大的功能来处理多维数组(即张量),以下是几种常见的创建方法:
```python
import numpy as np
# 初始化为零的张量
zero_tensor = np.zeros((2, 3, 4))
# 初始化为全1的张量
ones_tensor = np.ones((2, 3, 4))
print(zero_tensor)
print(ones_tensor)
```
这种方法适用于简单的张量初始化场景[^4]。
2. **TensorLy 和其他框架**
TensorLy 是一个专门用于张量操作的库,支持多个后端(如 NumPy、PyTorch 等)。安装并导入该库后,可以直接利用其内置函数生成张量:
```bash
conda install -c tensorly tensorly
```
```python
import tensorly as tl
# 随机生成一个形状为 (3, 4, 5) 的张量
random_tensor = tl.tensor(np.random.rand(3, 4, 5), dtype=tl.float32)
print(random_tensor.shape)
print(random_tensor.dtype)
```
此外,还可以通过 `tensor()` 方法将现有数据转换成张量对象[^3]。
---
#### 基本张量操作
##### 1. 数据索引与切片
类似于列表或数组的操作语法,可对张量进行索引和切片访问:
```python
import numpy as np
# 创建一个三阶张量
data = np.arange(24).reshape(2, 3, 4)
# 访问特定位置的元素
element = data[0, 1, 2]
# 切片部分区域
slice_data = data[:, :, :2]
print(element) # 输出单个元素
print(slice_data) # 输出切片后的子集
```
上述代码展示了如何获取指定坐标处的数值以及提取某范围内的子张量。
##### 2. 整体变换与逐元运算
- 对整个张量应用统一算法规则称为整体操作;
- 若针对每个独立单元分别施加相同逻辑,则属于逐元运算范畴。
例如求平方根就是典型的逐元例子之一:
```python
sqrt_result = np.sqrt(data)
```
##### 3. 形状调整与转置
当需要改变当前排列顺序或将某些轴互换时需要用到变形(transpose)技术:
```python
transposed = np.transpose(data, axes=(2, 0, 1))
reshaped = data.reshape(-1, 4*3)
```
这里`np.transpose`重新定义各维度间的映射关系;而`reshape`则是保持总数量不变前提下修改外部表现形式.
---
#### 实现 CP 张量分解
CP 分解是一种经典的低秩近似算法,能够有效压缩高维稀疏型数据集合。下面给出基于 Numpy 手动完成的过程示意片段:
```python
def cp_decomposition(tensor, rank):
"""
使用交替最小化法实现CP分解
参数:
tensor -- 输入待分析的目标张量(numpy array)
rank -- 设定期望达到的最大秩数(int)
返回值:
factors_list -- 存储每层因子矩阵(list of arrays)
"""
dims = len(tensor.shape)
factor_matrices = []
for d in range(dims):
shape_d = list(tensor.shape[:d]) + [rank] + list(tensor.shape[d+1:])
init_mat = np.random.uniform(size=tuple(shape_d))
factor_matrices.append(init_mat)
max_iter = 100
tol = 1e-8
prev_err = float('inf')
for it in range(max_iter):
new_factors = update_all_modes(tensor,factor_matrices,dims)[^1]
err = compute_reconstruction_error(new_factors,tensor)[^1]
if abs(prev_err - err)<tol:
break
prev_err = err
return new_factors
from functools import reduce
def khatri_rao(matrices):
"""计算Khatri-Rao乘积"""
result = matrices[0]
for mtrx in matrices[1:]:
result = krp(result,mtrx)
return result
def krp(A,B):
rows_A,cols_A=A.shape;rows_B,_=B.shape
kr_prod=np.empty([rows_A*rows_B, cols_A])
idx=0
while True:
try:
kr_prod[idx::rows_B,:]=A*B[[idx],:]
idx+=1
except IndexError:
break
return kr_prod
def reconstruct(factors):
core_ten=reduce(lambda x,y:x@y.T,factors[:-1])[None,...]*factors[-1][...,None]
rec_tens=sum(core_ten,axis=-2)
return rec_tens
def compute_reconstruction_error(factors,true_val):
pred=reconstruct(factors)
mse=((true_val-pred)**2).mean()
return mse**(0.5)
def update_mode_n(X,F,n,dimensions):
other_fs=[F[i]for i in set(range(dimensions))-set([n])]
M_kr=khatri_rao(other_fs[::-1])
unfolded_X=_unfold(X,n)
updated_fn=np.linalg.lstsq(M_kr.T @ M_kr ,M_kr.T @ unfolded_X,rcond=None)[0].T
F[n]=updated_fn.copy()
return F
def _unfold(T,k):
sz=list(T.shape);sz.pop(k);new_sz=sz+[T.shape[k]]
permuted_axes=list(set(range(len(sz)+1))-set([k]))+[k]
res=T.permute(*permuted_axes).contiguous().view(*new_sz)
return res
def update_all_modes(tensor,factors,dims):
for mode_idx in range(dims):
factors=update_mode_n(tensor,factors,mode_idx,dims)
return factors
```
此脚本实现了基本的功能模块,并提供了灵活扩展的可能性[^1]。
---