张量 Tensor
张量(Tensor)是仓颉 TensorBoost 网络运算中的基本数据结构,张量支持的数据类型有整型、浮点型和布尔类型,目前整型支持 Int32 和 Int64,浮点型支持 Float16、Float32 和 Float64(注: 目前 Float64 的 Tensor 仅支持部分算子)。使用仓颉 TensorBoost Tensor 结构需要导入 ops 包和 common 包:
from CangjieTB import ops.*
from CangjieTB import common.*
初始化张量
张量的初始化方式有多种,构造张量时,支持传入Tensor
、Float16
、Float32
、Float64
、Int32
、Int64
、Bool
类型。
根据数据直接生成
可以根据数据创建张量。
var x = Tensor(Float32(0.1))
print(x)
x = Tensor(Array<Float32>([1.0, 2.0, 3.0, 1.0, 2.0, 3.0]), shape: Array<Int64>([2, 3]))
print(x)
x = Tensor(Float32(0.1), dtype:FLOAT64)
print(x)
x = Tensor(Array<Float32>([1.0, 2.0, 3.0, 1.0, 2.0, 3.0]), shape: Array<Int64>([2, 3]), dtype:FLOAT64)
print(x)
输出为:
Tensor(shape=[], dtype=Float32, value= 1.00000001e-01)
Tensor(shape=[2, 3], dtype=Float32, value=
[[ 1.00000000e+00 2.00000000e+00 3.00000000e+00]
[ 1.00000000e+00 2.00000000e+00 3.00000000e+00]])
Tensor(shape=[], dtype=Float64, value= 1.00000001e-01)
Tensor(shape=[2, 3], dtype=Float64, value=
[[ 1.00000000e+00 2.00000000e+00 3.00000000e+00]
[ 1.00000000e+00 2.00000000e+00 3.00000000e+00]])
【说明】:仓颉 TensorBoost 重载了 print 函数,可用于查看张量的数值。
继承另一个张量的属性,形成新的张量
let xZeros = zerosLike(x)
print(xZeros)
输出为:
Tensor(shape=[2, 3], dtype=Float64, value=
[[0.00000000e+00 0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00 0.00000000e+00]])
输出指定大小的恒定值或随机张量
var x = zerosTensor(Array<Int64>([2, 3]))
print("zeros x", x)
x = onesTensor(Array<Int64>([2, 3]))
print("ones x", x)
x = fillTensor(Array<Int64>([6]), 2.0)
print("fill x", x)
x = randomNormalTensor(Array<Int64>([2, 3]))
print("random x", x)
输出为:
zeros x
Tensor(shape=[2, 3], dtype=Float32, value=
[[0.00000000e+00 0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00 0.00000000e+00]])
ones x
Tensor(shape=[2, 3], dtype=Float32, value=
[[1.00000000e+00 1.00000000e+00 1.00000000e+00]
[1.00000000e+00 1.00000000e+00 1.00000000e+00]])
fill x
Tensor(shape=[6], dtype=Float32, value=
[2.00000000e+00 2.00000000e+00 2.00000000e+00 2.00000000e+00 2.00000000e+00 2.00000000e+00])
random x
Tensor(shape=[2, 3], dtype=Float32, value=
[[5.24295261e-03 -8.60292558e-03 -6.73894212e-03]
[-1.03433325e-03 -6.31256960e-03 2.36030575e-02]])
张量的属性
张量的属性包括形状(shape)和数据类型(dtype)。
- 形状:Tensor 的 shape,是一个 Int64 的数组。
- 数据类型:Tensor 的 dtype,是一个字符串。
获取属性的代码如下所示:
let t = onesTensor(Array<Int64>([2, 3]), dtype: INT32)
let shape: Array<Int64> = t.getShape()
let dtype: String = t.getStrDtype()
print("Shape of t: ${shape}\n")
print("DType of t: ${dtype}\n")
输出为:
Shape of t: [2, 3]
DType of t: INT32
张量运算
张量支持多种运算,包括算术、线性代数、矩阵处理(转置、索引、切片)等,张量运算的结果依然是张量。下面介绍其中几种操作:
取行/列
张量可以使用 gather 方法,根据轴或索引获取 Tensor 中的某些值。
let tensor: Tensor = randomNormalTensor(Array<Int64>([4, 4]))
print("tensor: ", tensor)
let firstRow = gather(tensor, Tensor(Int32(0), dtype: INT32), 0)
print("First row: ", firstRow)
let firstColumn = gather(tensor, Tensor(Int32(0), dtype: INT32), 1)
print("First column: ", firstColumn)
let otherColumn = gather(tensor, Tensor(Array<Int32>([1, 2]), shape: Array<Int64>([2])), 1)
print("column 2-3: ", otherColumn)
输出为:
tensor:
Tensor(shape=[4, 4], dtype=Float32, value=
[[1.57868862e-02 -4.30074194e-03 6.91929235e-05 1.57265477e-02]
[5.19612944e-03 -6.04318548e-03 -5.03292587e-03 4.90910932e-03]
[-1.76758785e-02 -8.70072190e-03 -5.10977907e-03 -7.41219288e-03]
[-3.73127405e-04 -5.04293945e-03 -7.56428868e-04 -2.82030297e-03]])
First row:
Tensor(shape=[1, 4], dtype=Float32, value=
[[1.57868862e-02 -4.30074194e-03 6.91929235e-05 1.57265477e-02]])
First column:
Tensor(shape=[4, 1], dtype=Float32, value=
[[1.57868862e-02]
[5.19612944e-03]
[-1.76758785e-02]
[-3.73127405e-04]])
column 2-3:
Tensor(shape=[4, 2], dtype=Float32, value=
[[-4.30074194e-03 6.91929235e-05]
[-6.04318548e-03 -5.03292587e-03]
[-8.70072190e-03 -5.10977907e-03]
[-5.04293945e-03 -7.56428868e-04]])
张量连接
张量可以用 concat 或 stack 方法进行连接。二者的区别是,concat 对输入的 Tensor 在指定轴上进行合并,stack 对输入的 Tensor 在指定轴上进行堆叠。
let t1: Tensor = concat([tensor, tensor, tensor], axis: 1)
print(t1)
let t2: Tensor = stack([tensor, tensor, tensor], axis: 1)
print(t2)
输出为:
Tensor(shape=[4, 12], dtype=Float32, value=
[[1.57868862e-02 -4.30074194e-03 6.91929235e-05 ... -4.30074194e-03 6.91929235e-05 1.57265477e-02]
[5.19612944e-03 -6.04318548e-03 -5.03292587e-03 ... -6.04318548e-03 -5.03292587e-03 4.90910932e-03]
[-1.76758785e-02 -8.70072190e-03 -5.10977907e-03 ... -8.70072190e-03 -5.10977907e-03 -7.41219288e-03]
[-3.73127405e-04 -5.04293945e-03 -7.56428868e-04 ... -5.04293945e-03 -7.56428868e-04 -2.82030297e-03]])
Tensor(shape=[4, 3, 4], dtype=Float32, value=
[[[1.57868862e-02 -4.30074194e-03 6.91929235e-05 1.57265477e-02]
[1.57868862e-02 -4.30074194e-03 6.91929235e-05 1.57265477e-02]
[1.57868862e-02 -4.30074194e-03 6.91929235e-05 1.57265477e-02]]
[[5.19612944e-03 -6.04318548e-03 -5.03292587e-03 4.90910932e-03]
[5.19612944e-03 -6.04318548e-03 -5.03292587e-03 4.90910932e-03]
[5.19612944e-03 -6.04318548e-03 -5.03292587e-03 4.90910932e-03]]
[[-1.76758785e-02 -8.70072190e-03 -5.10977907e-03 -7.41219288e-03]
[-1.76758785e-02 -8.70072190e-03 -5.10977907e-03 -7.41219288e-03]
[-1.76758785e-02 -8.70072190e-03 -5.10977907e-03 -7.41219288e-03]]
[[-3.73127405e-04 -5.04293945e-03 -7.56428868e-04 -2.82030297e-03]
[-3.73127405e-04 -5.04293945e-03 -7.56428868e-04 -2.82030297e-03]
[-3.73127405e-04 -5.04293945e-03 -7.56428868e-04 -2.82030297e-03]]])
数学运算
let mat = onesTensor(Array<Int64>([4, 4]), dtype: FLOAT32)
// matmul 可以进行矩阵乘法
let z1 = matmul(mat, mat)
print(z1)
// 下面两个操作等价,都是 element-wise 的乘法,得到的 z2 和 z3 结果相同
let z2 = mul(mat, mat)
let z3 = mat * mat
print(z2)
print(z3)
输出为:
Tensor(shape=[4, 4], dtype=Float32, value=
[[4.00000000e+00 4.00000000e+00 4.00000000e+00 4.00000000e+00]
[4.00000000e+00 4.00000000e+00 4.00000000e+00 4.00000000e+00]
[4.00000000e+00 4.00000000e+00 4.00000000e+00 4.00000000e+00]
[4.00000000e+00 4.00000000e+00 4.00000000e+00 4.00000000e+00]])
Tensor(shape=[4, 4], dtype=Float32, value=
[[1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00]
[1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00]
[1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00]
[1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00]])
Tensor(shape=[4, 4], dtype=Float32, value=
[[1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00]
[1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00]
[1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00]
[1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00]])
数组与张量的转换
数组转张量
根据数组构造 Tensor。
let xDataArray: Array<Float32> = Array<Float32>([1.0, 0.0, 1.0, 0.0])
let xDataTensor = Tensor(xDataArray, shape: Array<Int64>([2, 2]))
print("xDataTensor is: ", xDataTensor)
输出为:
xDataTensor is:
Tensor(shape=[2, 2], dtype=Float32, value=
[[1.00000000e+00 0.00000000e+00]
[1.00000000e+00 0.00000000e+00]])
张量转数组
使用 toArrayFloat32()
方法,将 Float32 类型的 Tensor 转为数组。
let zerosTensor: Tensor = zerosTensor(Array<Int64>([3, 2]), dtype: FLOAT32)
print("zerosTensor is: ", zerosTensor)
let zerosArray: Array<Float32> = zerosTensor.toArrayFloat32()
print("zerosArray is: ${zerosArray.toString()}\n")
输出为:
zerosTensor is:
Tensor(shape=[3, 2], dtype=Float32, value=
[[0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00]
[0.00000000e+00 0.00000000e+00]])
zerosArray is: [0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000]
【说明】:
- 如果 Tensor 的 dtype 为 Int32 类型,可调用toArrayInt32(),如果为 Bool 类型,可调用toArrayBool()。
toArrayFloat32()/toArrayInt32()/toArrayBool()
转数组的方法只能用于已经有值的 Tensor 上,无值的 Tensor 不能调用。如果不确定某个 Tensor 是否有值,可以调用 isConcrete 方法进行判断。
张量释放
export TENSORSIZE=100MB
考虑到在网络执行过程中会不断创建 Tensor,占用较大的内存。如遇到内存资源不足的情况,可通过配置环境变量TENSORSIZE
,及时释放设备内存,等号右侧为用户希望 Tensor 占用最大内存(必须为正整数),单位支持 KB、MB 和 GB。当 Tensor 占用的内存总量超过该值时会触发自动 GC,尝试释放出一些内存。默认情况会由仓颉 GC 自动判断,对无用 Tensor 对象进行内存回收。