附录 B 张量 API
创建张量
使用构造函数创建
仓颉 TensorBoost 为张量(Tensor)类型提供了多个构造函数,函数原型定义如下。其中 value 是传入的数组或者单个的值,入参 shape 是所创建 Tensor 的形状大小,dtype 用于指定 Tensor 的类型。
public struct Tensor {
public init()
public init(value: Float16, dtype!: Int32 = FLOAT16)
public init(value: Float32, dtype!: Int32 = FLOAT32)
public init(value: Float64, dtype!: Int32 = FLOAT64)
public init(value: Int32, dtype!: Int32 = INT32)
public init(value: Int64, dtype!: Int32 = INT64)
public init(value: Bool, dtype!: Int32 = BOOL)
public init(value: Array<Float16>, shape!: Array<Int64>, dtype!: Int32 = FLOAT16)
public init(value: Array<Float32>, shape!: Array<Int64>, dtype!: Int32 = FLOAT32)
public init(value: Array<Float64>, shape!: Array<Int64>, dtype!: Int32 = FLOAT64)
public init(value: Array<Int32>, shape!: Array<Int64>, dtype!: Int32 = INT32)
public init(value: Array<Int64>, shape!: Array<Int64>, dtype!: Int32 = INT64)
public init(value: Array<UInt32>, shape!: Array<Int64>, dtype!: Int32 = UINT32)
public init(value: Array<Bool>, shape!: Array<Int64>, dtype!: Int32 = BOOL)
}
当在 Tensor 构造函数中指定了 dtype 时,Tensor 类型以指定的 dtype 为准; 否则 Tensor 类型同传入的值或者 Array 类型相同。对于不同的值或者 Array 类型,可指定的 dtype 目前也做了限制,参考下表。
值或者 Array 类型 | dtype 可选类型 |
---|---|
Int32, Int64, UInt32 | INT32, INT64, UINT32 |
Float16, Float32, Float64 | FLOAT16, FLOAT32, FLOAT64 |
Bool | BOOL |
构造 Tensor 时,如果输入不符合要求,会抛出异常,有以下几种类型:
- 初始化数据类型不支持
- 初始化参数值不符合要求
- 初始化 Tensor 的形状不符合要求
使用仓颉数组(数据类型为 Float32)创建大小为 Array<Int64>([2, 2]) 的张量 tensor。
let tensor = Tensor(Array<Float32>([1.0, 1.0, 1.0, 1.0]), shape: Array<Int64>([2, 2]))
print(tensor)
输出为:
Tensor(shape=[2, 2], dtype=Float32, value=
[[1.00000000e+00 1.00000000e+00]
[1.00000000e+00 1.00000000e+00]])
创建符合正态分布的张量
函数 randomNormalTensor 提供正态分布随机初始化 Tensor 的能力,函数原型定义如下,其中 dtype 是传入的 Tensor 的数据类型入参, shape 是 Tensor 的 shape 大小,sigma 是标准差,seed 是全局种子,seed2 是 op 种子,两者一起作为随机数的种子, 函数返回一个 Tensor 类型。
public func randomNormalTensor(shape: Array<Int64>, sigma!: Float32 = 0.01, dtype!: Int32 = FLOAT32, seed!: Int64 = 0, seed2!: Int64 = 0): Tensor
创建数据类型为 Float32,大小为 Array<Int64>([2, 3]) ,数值按正态分布随机初始化的张量 randTensor。
let randTensor = randomNormalTensor(Array<Int64>([2, 3]))
print(randTensor)
输出为:
Tensor(shape=[2, 3], dtype=Float32, value=
[[2.41499580e-02 -6.09102054e-03 1.38444267e-02]
[9.14979633e-03 -2.58914679e-02 -1.21405339e-02]])
【注意】: 全局种子和 op 种子均为 0 的情况下,随机数会使用时钟作为种子,生成每次都不相同的随机数。
创建符合均匀分布的张量
函数 uniformTensor 提供均匀分布随机初始化 Tensor 的能力,函数原型定义如下,其中 dtype 是传入的 Tensor 的数据类型,入参 shape 是 Tensor 的 shape 大小,以 0 为均值, boundary 为均匀分布的取值上限 (-boundary 为均匀分布的取值下限),函数返回一个 Tensor 类型。
public func uniformTensor(shape: Array<Int64>, boundary!: Float32 = 0.01, dtype!: Int32 = FLOAT32): Tensor
创建数据类型为 Float32,大小为 Array<Int64>([2, 3]) ,数值按均匀分布随机初始化的张量 randTensor。
let randTensor = uniformTensor(Array<Int64>([2, 3]))
print(randTensor)
输出为:
Tensor(shape=[2, 3], dtype=Float32, value=
[[6.29447401e-03 8.11583921e-03 -7.46026356e-03]
[8.26751627e-03 2.64718570e-03 -8.04919191e-03]])
创建数值全 1 的张量
函数 onesTensor 提供全 1 初始化 Tensor 的能力,函数原型定义如下,其中 dtype 是传入的 Tensor 的数据类型,支持 Float16\Float32\Float64\Int32\Int64\UInt32\Bool 类型;shape 是 Tensor 的 shape 大小,函数返回一个 Tensor 类型。
public func onesTensor(shape: Array<Int64>, dtype!: Int32 = FLOAT32): Tensor
创建数据类型为 Float32,大小为 Array<Int64>([2, 3]),数值全为 1 的张量 onesTensor。
let onesTensor = onesTensor(Array<Int64>([2, 3]))
print(onesTensor)
输出为:
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]])
创建数值全 0 的张量
函数 zerosTensor 提供全 0 初始化 Tensor 的能力,函数原型定义如下,其中 dtype 是传入的 Tensor 的数据类型,支持 Float16\Float32\Float64\Int32\Int64\UInt32\Bool 类型;shape 是 Tensor 的 shape 大小,函数返回一个 Tensor 类型。
public func zerosTensor(shape: Array<Int64>, dtype!: Int32 = FLOAT32): Tensor
创建数据类型为 Float32,大小为 Array<Int64>([2, 3]),数值全为 0 的张量 zerosTensor。
let zerosTensor = zerosTensor(Array<Int64>([2, 3]))
print(zerosTensor)
输出为:
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]])
创建指定数值和大小的张量
函数 fillTensor 提供指定数值 data 和大小的 Tensor 的能力,data 可以是 Float16\Float32\Float64\Int32\Bool 的数据类型,根据填充的数据类型不同,提供了五个接口,函数原型定义如下,其中 shape 是 Tensor 的 shape 大小,data 是填充数据,函数返回一个 Tensor 类型。
public func fillTensor(shape: Array<Int64>, data: Float16): Tensor
public func fillTensor(shape: Array<Int64>, data: Float32): Tensor
public func fillTensor(shape: Array<Int64>, data: Float64): Tensor
public func fillTensor(shape: Array<Int64>, data: Int32): Tensor
public func fillTensor(shape: Array<Int64>, data: Bool): Tensor
创建数值全是 2.0,大小为 Array<Int64>([6]) 的张量 newTensor。
let newTensor = fillTensor(Array<Int64>([6]), Float32(2.0))
print(newTensor)
输出为:
Tensor(shape=[6], dtype=Float32, value=
[2.00000000e+00 2.00000000e+00 2.00000000e+00 2.00000000e+00 2.00000000e+00 2.00000000e+00])
创建对角张量
函数 eyeTensor 提供一个对角线是 1,其他位置是 0 的 Tensor,支持的类型有 FLOAT16\FLOAT32\FLOAT64\INT32\INT64\UINT32\BOOL,函数原型定义如下:
public func eyeTensor(n: Int64, dtype!: Int32 = FLOAT32): Tensor
public func eyeTensor(n: Int64, m: Int64, dtype!: Int32 = FLOAT32): Tensor
其中,n、m 分别对应输出矩阵的 row 和 column,没有传入 m,则 m = n ,dtype 是传入的数据类型,默认值为 FLOAT32。
创建数据类型为 Float32,大小为 Array<Int64>([2, 3]),对角线 Tensor,使用以下代码:
let eyeTensor = eyeTensor(2, 3)
print(eyeTensor)
输出为:
Tensor(shape=[2, 3], dtype=Float32, value=
[[ 1.00000000e+00 0.00000000e+00 0.00000000e+00]
[ 0.00000000e+00 1.00000000e+00 0.00000000e+00]])
创建内容为空的张量
函数 noneTensor 提供空 Tensor 初始化的能力,该函数返回一个内置的 Tensor 类型的全局变量 NONETENSOR,表示 Tensor 对象中没有任何值。NONETENSOR 的 dtype 和 shape 无意义,无法调用 getDtype()
、 getShape()
、 isInt32()
等方法获取属性,也无法调用 evaluate()
方法进行求值。
public func noneTensor(): Tensor
创建内容为空的张量。可以调用 Tensor 的成员函数 isNone() 来判断 Tensor 对象是否为 NONETENSOR。
let none = noneTensor()
这种初始化方式可用于函数入参类型为 Tensor,但某些情况下可能为空的场景。
使用 initialize 方法创建张量
仓颉 TensorBoost 为以上提到的各种初始化方式提供了统一的调用方法:initialize 函数,这种初始化方式常用于网络中权重的初始化,如 Dense 或 Conv2d 等,参见[附录 D](###Dense 层)。定义如下:
public func initialize(shape: Array<Int64>, initializer: BaseInitializer, dtype!: Int32 = FLOAT32): Tensor
public func initialize(shape: Array<Int64>, initType!: InitType = InitType.NORMAL, dtype!: Int32 = FLOAT32): Tensor
其中:
-
BaseInitializer 是初始化器的基类,仓颉 TensorBoost 目前提供了 4 个子类:
-
RandomNormalInitializer 可以使生成的数据满足正态分布,原型定义如下,入参 sigma 代表生成数据的标准差。
public class RandomNormalInitializer <: BaseInitializer { public init(sigma!: Float32 = 0.01) }
-
TruncatedNormalInitializer 生成截断正态分布,数据要求限制在[left, right]范围内。原型定义如下,入参 sigma 代表标准差;left、right 分别代表左右数据边界。
public class TruncatedNormalInitializer <: BaseInitializer { public init() public init(sigma: Float32, left!: Float32 = -2.0, right!: Float32 = 2.0) }
-
UniformInitializer 生成在[-range, range] 之间的均匀随机分布数据。原型定义如下,入参 range 代表生成数据的边界范围。
public class UniformInitializer <: BaseInitializer { public init(range!: Float32 = 0.07) }
-
ReadFileInitializer 从文件生成 Tensor。
public class ReadFileInitializer <: BaseInitializer { public init(fromFile!: String = "") }
-
XavierUniformInitializer 按照 xavier uniform 算法生成在 [-boundary, boundary] 之间的均匀分布的数据。原型定义如下,入参 gain 代表缩放因子。
public class XavierUniformInitializer <: BaseInitializer { public init(gain!: Float32 = 1.0) }
-
XavierUniformInitializer 按照 xavier uniform 算法生成在 [-boundary, boundary] 之间的均匀分布的数据,其中 boundary 的计算公式如下:
$$ boundary = gain * \sqrt{\frac{6}{n_{in} + n_{out}}} $$
上述公式中,$n_{in}$ 为权重的输入单元数,$n_{out}$ 为权重的输出单元数。
InitType 是枚举类型,定义如下:
public enum InitType { ZERO // "全 0" 初始化
| ONE // "全 1" 初始化
| NORMAL // "sigma 为 0.01 的正态分布" 初始化
| TRUNCNORM // "sigma 为0.01, left 为-2.0, right 为2.0的截断正态分布" 初始化
| UNIFORM // "range为0.07的均匀分布" 初始化
| XAVIERUNIFORM // "gain 为 1 的 XAVIER 均匀分布" 初始化
}
通过加载 npy 文件来初始化 Tensor
npy 是 Python 的 Numpy 模块保存 ndarray 的标准格式。仓颉 TensorBoost 提供了 NpyFile 类与其对应,支持从 npy 文件初始化 Tensor ,也支持将 Tensor 保存成 npy 文件。 首先需要创建 NpyFile 类型,NpyFile 的第一个参数为需要读写的文件名(或路径),如路径不存在会自动创建;第二个参数指定读写模式。NpyFile 类定义如下:
public class NpyFile {
public init(name: String, mode: String)
public func close()
}
可以通过 Tensor 的静态 load
方法读取 npy 文件进行初始化,仅支持读模式"rb",读取的顺序需要同保存的顺序保持一致。具体用法如下:
let npy = NpyFile("test.npy", "rb")
let a = Tensor.load(npy)
let b = Tensor.load(npy)
npy.close()
另外也可以通过 Tensor 的静态 save
方法将其保存成 npy 文件,仅支持写模式"wb"。具体用法如下:
let npy = NpyFile("test.npy", "wb")
let input0 = Tensor(Array<Float32>([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]), shape: Array<Int64>([2, 3]))
let input1 = Tensor([true, false, true], shape: Array<Int64>([3]))
Tensor.save(npy, input0)
Tensor.save(npy, input1)
npy.close()
注意: close()
方法可以提前释放文件句柄。用户如果选择不调用,仓颉的 GC 也会自动进行释放,不会造成资源泄漏。
张量属性与方法
获取张量数据类型
函数 getDtype()
和 getStrDtype()
用于获取张量的数据类型。
public func getDtype(): Int32
public func getStrDtype(): String
应用示例
let input = randomNormalTensor(Array<Int64>([32, 1, 32, 32]))
let dtype = input.getDtype()
let strDtype = input.getStrDtype()
print("dtype is ${dtype}\n")
print("strDtype is ${strDtype}\n")
输出为:
dtype is 0
strDtype is FLOAT32
获取张量形状大小
函数 getShape()
用于获取张量的形状大小。
public func getShape(): Array<Int64>
应用示例
let input = randomNormalTensor(Array<Int64>([32, 1, 32, 32]))
let shape= input.getShape()
print("shape is ${shape.toString()}\n")
输出为:
shape is [32, 1, 32, 32]
获取张量维度大小
函数 getShapeDims()
用于获取张量的维度大小。
public func getShapeDims(): Int64
应用示例
let input = randomNormalTensor(Array<Int64>([32, 1, 32, 32]))
let shapeDims= input.getShapeDims()
print("shapeDims is ${shapeDims.toString()}\n")
输出为:
shapeDims is 4
判断是否是 zerosTensor 接口初始化的 Tensor
函数 isZero()
判断是否是 zerosTensor 接口初始化的 Tensor,常用于性能优化。
public func isZero(): Bool
应用示例
let zerosTensor: Tensor = zerosTensor(Array<Int64>([3, 2]), dtype: FLOAT32)
if (zerosTensor.isZero()) {
print("Zero\n")
} else {
print("not Zero\n")
}
输出为:
Zero
判断张量是否为空
函数 isNone()
用于判断张量是否为空。
public func isNone(): Bool
应用示例
let none = noneTensor()
if (none.isNone()) {
print("None\n")
} else {
print("not None\n")
}
输出为:
None
获取张量的名称
属性 name
用于获取张量的 name,默认值为空。
public prop name: String
应用示例
let input1 = parameter(onesTensor(Array<Int64>([2, 2])), "input1")
let name1 = input1.name
print("name1 is ${name1}\n")
let input2 = onesTensor(Array<Int64>([2, 2]))
let name2 = input2.name
print("name2 is ${name2}\n")
输出为:
name1 is input1
name2 is
获取对应的 Mindspore Handle 值
函数 getMsHandle()
获取对应的 Mindspore Handle 值,常用于仓颉与 Mindspore 的数据同步操作。
public func getMsHandle()
判断是否需要从主机同步数据到设备
函数 enableSyncHostToDevice()
判断是否需要从主机同步数据到设备,常用于数据集,用户无需主动调用
public func enableSyncHostToDevice()
判断张量是否需要更新梯度
属性 requiresGrad
用于控制网络参数是否需要更新梯度,默认是 false。
mut prop requiresGrad: Bool
应用示例
var input = onesTensor(Array<Int64>([2, 2]))
print("input's requiresGrad is ${input.requiresGrad}\n")
var param = parameter(input, "weight")
print("param's requiresGrad is ${param.requiresGrad}\n")
输出为:
input's requiresGrad is false
param's requiresGrad is true
判断张量数据类型
例如函数 isInt32()
、 isFloat32()
、 isFloat64()
和 isBool()
分别用于判断张量是否是 Int32、Float32、Float64 或者 Bool 数据类型。
当前提供的判断张量数据类型的接口如下:
public func isInt32(): Bool
public func isInt64(): Bool
public func isFloat16(): Bool
public func isFloat32(): Bool
public func isFloat64(): Bool
public func isBool(): Bool
public func isUInt32(): Bool
对某一个确定的 Tensor 而言,调用以上三个方法只有一个为 true,即某个确定的 Tensor 只能为一种类型。
应用示例
let a = onesTensor(Array<Int64>([1]), dtype: INT32)
print("a isInt32? : ${a.isInt32()}\n")
print("a isFloat32? : ${a.isFloat32()}\n")
print("a isBool? : ${a.isBool()}\n")
输出为:
a isInt32? : true
a isFloat32? : false
a isBool? : false
张量转为数组
例如函数 toArrayInt32()
、 toArrayFloat32()
、 toArrayFloat64()
和 toArrayBool()
分别用于将 Int32、Float32、Float64 或者 Bool 类型张量转换成对应数据类型的数组。
提供toScalar<T>()
,可以将 Tensor 转化为标量,例如当一个 dtype 为 Int32 类型的 Tensor 为标量时(shape 为空数组),应调用toScalar<Int32>()
方法。
当前提供的张量转数组或者标量的方法如下:
public func toArrayInt32(): Array<Int32>
public func toArrayInt64(): Array<Int64>
public func toArrayFloat16(): Array<Float16>
public func toArrayFloat32(): Array<Float32>
public func toArrayFloat64(): Array<Float64>
public func toArrayBool(): Array<Bool>
public func toArrayUInt32(): Array<UInt32>
public func toScalar<T>(): T
支持使用 toScalar<T>()
的类型受到接口 Number
public interface Number<T> {
static func size(): Int64
static func zero(): T
static func dtype(): Int32
static func dtypeName(): String
static func initArrayTensorByValue(
value: Array<T>,
shapePtr: CPointer<Int64>,
shapeDims: Int64,
dtype: Int32
): MSTensorHandle
static func copyTensorDataToCangjie(dest: Array<T>, tensorHandle: MSTensorHandle): Unit
}
应用示例:
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 而言,只能将其转为与数据类型相对应的数组。如果某 Tensor 对象定义为 Int32 类型,则不允许调用 toArrayFloat32()
和toArrayBool()
方法。
evaluate 方法
以静态图模式运行时,evaluate 之前计算得出的 Tensor 是无值的。需要调用 Tensor 的 evaluate()
方法触发计算图的执行之后,才能将无值的 Tensor 变为有值的 Tensor。
public func evaluate(): Tensor
如下代码以静态图模式运行时,用仓颉数组创建的t1
和t2
是有值的 Tensor,t5
为计算得出的 Tensor 且被 evaluate 过,是有值的。t4
为计算得出的 Tensor 且未被 evaluate 过,是无值的。如果不确定某个 Tensor 是否有值,可以调用 isConcrete 方法进行判断。
let t1 = Tensor(Array<Float32>([1.0, 1.0, 1.0]), shape: Array<Int64>([3]))
let t2 = Tensor(Array<Float32>([2.0, 2.0, 2.0]), shape: Array<Int64>([3]))
let t3 = t1 + t2
let t4 = t3 * t3
let t5: Tensor = t4.evaluate()
let resArr: Array<Float32> = t5.toArrayFloat32()
print("resArr: ${resArr.toString()}\n")
上述代码中,t3/t4
未被 evaluate 过,不允许对t3/t4
直接调用 toArrayFloat32()
。
判断张量是否为 Parameter
public func isParameter(): Bool
let t1 = initialize(Array<Int64>([2]), initType:InitType.NORMAL, dtype:FLOAT32)
print("t1 is Parameter? --- ${t1.isParameter()}\n")
let t2 = parameter(initialize(Array<Int64>([2]), initType:InitType.NORMAL, dtype:FLOAT32), "param")
print("t2 is Parameter? --- ${t2.isParameter()}\n")
输出为:
t1 is Parameter? --- false
t2 is Parameter? --- true
判断张量是否有值
以静态图模式运行时,evaluate 之前计算得出的 Tensor 是无值的。可以调用 Tensor 的 isConcrete()
方法来判断 Tensor 是否需要 evaluate 操作。
public func isConcrete(): Bool
如下代码以静态图模式运行时,t3 是无值的 Tensor,t4 是有值的 Tensor:
let t1 = Tensor(Array<Float32>([1.0, 1.0, 1.0]), shape: Array<Int64>([3]))
let t2 = Tensor(Array<Float32>([2.0, 2.0, 2.0]), shape: Array<Int64>([3]))
let t3 = t1 + t2
let t4 = t3.evaluate()
print("t3 is concrete?---${t3.isConcrete()}\n")
print("t4 is concrete?---${t4.isConcrete()}\n")
输出为:
t3 is concrete?---false
t4 is concrete?---true
张量自动微分
张量支持微分,提供微分初值接口和微分累加接口供自动微分系统使用
extend Tensor <: Differentiable<Tensor> {
@Differentiable
public func TangentZero(): Tensor
@Differentiable
public func TangentAdd(y: Tensor): Tensor
}
查看张量数值
仓颉 TensorBoost 提供了多种 print 重载函数,用于查看张量数值。
查看单个张量数值
public func print(tensor: Tensor): Unit
应用示例
let input = Tensor(Array<Int32>([1, 2, 3, 4]), shape: Array<Int64>([1, 4]))
print(input)
输出为:
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
查看描述和单个张量数值
public func print(str: String, tensor: Tensor): Unit
应用示例
let input = Tensor(Array<Int32>([1, 2, 3, 4]), shape: Array<Int64>([1, 4]))
print("input:", input)
输出为:
input:
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
查看张量数组
public func print(tensors: Array<Tensor>): Unit
应用示例
let input1 = Tensor(Array<Int32>([1, 2, 3, 4]), shape: Array<Int64>([1, 4]))
let input2 = Tensor(Array<Int32>([5, 6, 7, 8]), shape: Array<Int64>([1, 4]))
print([input1, input2])
输出为:
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
Tensor(shape=[1, 4], dtype=Int32, value=
[[5 6 7 8]])
查看描述和张量数组
public func print(str: String, tensors: Array<Tensor>): Unit
应用示例
let input1 = Tensor(Array<Int32>([1, 2, 3, 4]), shape: Array<Int64>([1, 4]))
let input2 = Tensor(Array<Int32>([5, 6, 7, 8]), shape: Array<Int64>([1, 4]))
print("Print input1 and input2:", [input1, input2])
输出为:
Print input1 and input2:
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
Tensor(shape=[1, 4], dtype=Int32, value=
[[5 6 7 8]])
查看(描述, Tensor) 数组
public func print(tensors: Array<(String, Tensor)>): Unit
应用示例
let input1 = Tensor(Array<Int32>([1, 2, 3, 4]), shape: Array<Int64>([1, 4]))
let input2 = Tensor(Array<Int32>([5, 6, 7, 8]), shape: Array<Int64>([1, 4]))
print([("input1:", input1), ("input2:", input2)])
输出为:
input1:
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
input2:
Tensor(shape=[1, 4], dtype=Int32, value=
[[5 6 7 8]])
查看并存储张量信息
函数 logTensor()
把 Tensor 打印到文件中。
public func logTensor(tensor: Tensor, fileName: String, appendMode!: Bool = true): Unit
动静态图下张量输出的对比
在动态图模式下,打印总是按照代码执行的顺序进行输出;在静态图模式下,当 tensor 不需要通过 op 运算获得时,直接输出结果;否则要在 evaluate()后再进行输出操作。以下代码在动态图模式下的行为与静态图模式下不同:
func TestPrint1(): Unit
{
print("STTest: Print Begin\n")
var input1 = Tensor(Array<Int32>([1, 2, 3, 4]), shape: Array<Int64>([1, 4]))
var input2 = Tensor(Array<Int32>([5, 6, 7, 8]), shape: Array<Int64>([1, 4]))
var output1 = input1 + input2
print("input1", input1) // 第 1 次打印
print("Sum of inpu1 and input2:", output1) // 第 2 次打印
print([("input1:", input1), ("input2:", input2), ("output1:", output1)]) // 第 3 次打印
print("Print input1 and input2:", [input1, input2]) // 第 4 次打印
var res = output1.evaluate()
print("STTest: Print End\n")
}
动态图下的运行结果为:
ST-Test
STTest: Print Begin
input1
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
Sum of inpu1 and input2:
Tensor(shape=[1, 4], dtype=Int32, value=
[[6 8 10 12]])
input1:
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
input2:
Tensor(shape=[1, 4], dtype=Int32, value=
[[5 6 7 8]])
output1:
Tensor(shape=[1, 4], dtype=Int32, value=
[[6 8 10 12]])
Print input1 and input2:
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
Tensor(shape=[1, 4], dtype=Int32, value=
[[5 6 7 8]])
STTest: Print End
静态图下的运行结果为:
ST-Test
STTest: Print Begin
input1
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
Print input1 and input2:
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
Tensor(shape=[1, 4], dtype=Int32, value=
[[5 6 7 8]])
Sum of inpu1 and input2:
Tensor(shape=[1, 4], dtype=Int32, value=
[[ 6 8 10 12]])
input1:
Tensor(shape=[1, 4], dtype=Int32, value=
[[1 2 3 4]])
input2:
Tensor(shape=[1, 4], dtype=Int32, value=
[[5 6 7 8]])
output1:
Tensor(shape=[1, 4], dtype=Int32, value=
[[ 6 8 10 12]])
STTest: Print End
可以看到在动态图下是按照 1、2、3、4 的顺序进行打印;而在静态图下最终打印结果的顺序为 1、4、2、3。 这是因为:第 1 次打印中 input1 是有值的,所以结果立刻进行了输出;而第 2 次打印中 output1 需要通过运算获得,所以结果在 evaluate 之后输出;第 3 次打印中包含了 1 个需要运算获得的 output1,所以也要在 evaluate 之后输出,第 4 次打印中的 2 个 Tensor 都是有值的,可以立刻输出。
Tensor 运算符重载
在仓颉 TensorBoost 中,支持对 Tensor 进行加减乘除等操作,分别对应了算子函数,以下是 Tensor 支持的运算符重载: 当前 Scalar 作为左操作数,运算符重载支持的类型有:Float16、Float32、Float64、Int32。
操作符 | 操作符含义 | 替换的仓颉 TensorBoost 算子 |
---|---|---|
- | Negative: unary | neg(input1) |
* | Multiply: binary | mul(input1, input2) |
/ | Divide: binary | realDiv(input1, input2) |
+ | Add: binary | add(input1, input2) |
- | Subtract: binary | sub(input1, input2) |
< | Less than: binary | less(input1, input2) |
<= | Less than or equal to: binary | lessEqual(input1, input2) |
> | Greater than: binary | greater(input1, input2) |
>= | Greater than or equal to: binary | greaterEqual(input1, input2) |
== | Equal: binary | equal(input1, input2) |
!= | Not equal: binary | notEqual(input1, input2) |
[] | Get Item: binary | getTupleItem(input: Tensor, index: Int64) |
** | Pow: binary (right: 2.0) | square(input1) |
** | Pow: binary (right: 0.5) | sqrt(input1) |
** | Pow: binary (right: Except for 2.0 and 0.5) | pow(input1, input2) |