TIK数据定义
基本数据类型
- 指用于数据定义和运算的每一个数的数值类型,包括:int8, uint8, int16, uint16, int32, uint32, float16, float32,uint1(bool)等。
- 不同的TIK API支持不同的数据类型。
- TIK为强类型语言,即不同的数据类型之间无法进行计算。
TIK对象的标准数据类型
TIK对象的标准数据类型,指在内存中的对象的数据类型,表示用户能以什么格式创建和读写数据,包括两种:Scalar标量数据、Tensor张量数据。
定义一个Scalar标量数据
TIK提供了Scalar接口用于定义Scalar数据,接口原型为:
# 接口原型(其中,name和init_value参数可以省略) Scalar(dtype="int64", name="reg_buf", init_value=None)
参数名称 |
输入/输出 |
含义 |
---|---|---|
dtype |
输入 |
指定Scalar对象的数据类型,取值: int8,uint8,int16, uint16,float16,int32,uint32,float32, int64, uint64 默认值:int64 |
name |
输入 |
Scalar名字,支持string类型。名字支持数字0-9,A-Z,a-z及下划线组成的字符串,不允许以数字开头 默认值:reg_buf$(COUNT), COUNT从零开始计数。 |
init_value |
输入 |
初始化值: 可以是立即数(支持int, float类型)、 Scalar变量(支持int, float类型)、 Tensor的某个值、 Expr:包括Scalar变量、立即数组成的Expr。
须知:
如果是Expr,立即数不能是float。 |
# 示例1:使用全部3个参数 # 定义一个初值为10.2的立即数(float32)的Scalar数据 data_A # 结果:data_A : 10.2 data_A = tik_instance.Scalar(dtype = "float32", name = "data_A", init_value = 10.2) # 示例2:省略name参数 # 定义一个初值为4的立即数(int16)的Scalar数据 data_B # 结果:data_B : 4 data_B = tik_instance.Scalar(dtype = "int16", init_value = 4) # 示例3:省略name和init_value参数 # 定义一个不设置初始值的int32的Scalar数据 data_C # 结果:相当于声明了一个类型为int32的data_C data_C = tik_instance.Scalar(dtype = "int32")
# 注意:如果init_value是Expr,Expr中的立即数不能是float,只能是int。 # 正确初始化:Expr(data_a + 1)由Scalar和int组成: data_a = tik_instance.Scalar(dtype = "int16", init_value = 1) data_b = tik_instance.Scalar(dtype = "int16", init_value = data_a + 1) # 错误初始化:Expr(data_a + 1.2)由Scalar和float组成: data_a = tik_instance.Scalar(dtype = "int16", init_value = 1) data_b = tik_instance.Scalar(dtype = "int16", init_value = data_a + 1.2)
定义一个Tensor张量数据
Tensor数据对应于存储Buffer中的数据,TIK提供了Tensor接口用于定义Tensor数据,用户一般只需关注张量定义的数据类型(dtype)、形状(shape)与数据存储空间(scope)即可,函数原型为:
# 接口原型1(仅使用基本参数) data = tik_instance.Tensor(dtype, shape, name = "", scope = tik.xxx) # 接口原型2(使用拓展参数) Tensor(dtype, shape, scope, name, enable_buffer_reuse=False, is_workspace=False, is_atomic_add=False, max_mem_size=None, init_value=None)
参数名称 |
输入/输出 |
含义 |
---|---|---|
dtype |
输入 |
指定Tensor对象的数据类型,取值: uint8、int8、uint16、int16、float16、uint32、int32、float32、uint64、int64 |
shape |
输入 |
指定Tensor对象的形状,支持List、Tuple类型,List、Tuple中的元素可以为立即数(int、float)、Scalar(int、uint)或Expr(int、uint)。不建议使用float类型的立即数。 |
scope |
输入 |
Tensor 内存类型范围,指定Tensor对象的所在buffer空间,取值:
其中scope_gm代表外部存储,其他为内部存储,只有将外部存储中的数据搬运到内部存储中,才能完成相应的计算;当scope为gm时,不能在for_range内部定义Tensor。 |
name |
输入 |
Tensor名字,string类型。名字支持数字0-9,A-Z,a-z及下划线组成的字符串,不支持以数字开头。 tensor 的名字需要保持唯一。
说明:
scope为scope_gm时,不支持为"__fake_tensor"。 |
enable_buffer_reuse |
输入 |
保留参数,不建议使用。 |
is_workspace |
输入 |
bool值,默认值为False。 当该值为True时,代表当前Tensor是用于中间存储数据,而不用于输入输出。当取值为True时,需要保证scope为scope_gm,同时,不包含在输入输出中,即输入输出的Tensor的name中不含workspace中的Tensor。 |
is_atomic_add |
输入 |
是否进行初始化GM空间,默认值为False。
当该值为True时,需要保证scope为scope_gm。
说明:
仅算子在网络中执行的场景下,此参数才生效。网络执行时,Graph Engine会根据此参数判断是否进行GM的空间初始化。 |
max_mem_size |
输入 |
Tensor所占据的空间大小。
|
init_value |
输入 |
Tensor的初始值,为单个元素或list/tuple类型的值。 注意:该参数为预留参数,当前版本暂不支持。 |
# 定义一个数值类型为float16,存储空间在global_memory,size为128的Tensor data_B data_B = tik_instance.Tensor("float16", (128,), name="data_B", scope=tik.scope_gm)
TIK会自动为每个申请的Tensor对象分配空间,并且避免各个数据块之间的地址冲突。且TIK会自动检查数据之间的数据依赖性,实现数据的同步。
注意:
用户定义的Tensor在内存分配时会对起始地址进行对齐,不同scope的对齐要求请参见通用约束。用户需特别注意因地址对齐导致的超出对应内存类型的总容量时,会引起编译报错。
Scalar数据赋值及修改值(set_as)
TIK提供了set_as接口,用于设置或改变Scalar的值。
from tbe import tik tik_instance = tik.Tik() # 示例1:将Scalar的值设置为一个立即数(整数) s1 = tik_instance.Scalar(dtype = "int32") # 声明一个int32类型的scalar变量 s1 s1.set_as(10) # 将s1的值设为10 # 示例2:将Scalar的值设置为一个立即数(float) s2 = tik_instance.Scalar(dtype = "float16") # 声明一个float16类型的scalar变量 s2 s2.set_as(10.2) # 将s2的值设为10.2 # 示例3:将Scalar的值设置为另一个Scalar变量的值 s3 = tik_instance.Scalar(dtype = "float16", init_value = 2.4) # 定义一个初值为2.4的标量s3 s4 = tik_instance.Scalar(dtype = "float16") # 声明一个float16类型的scalar变量 s4 s4.set_as(s3) # 将s3的值赋给s4 # 示例4:将Scalar的值设置为由Scalar和立即数组成的Expr的值 s5 = tik_instance.Scalar(dtype = "int32", init_value = 1) # 定义一个初值为1的标量s5 s6 = tik_instance.Scalar(dtype = "int32") # 声明一个int32类型的scalar变量 s6 s6.set_as(s5+20) # 将Expr(s5+20)的值赋给s6,结果:s6 = 21 # 示例5:将Scalar的值设置为Tensor的某个值 s7 = tik_instance.Scalar(dtype = "int16") tensor_a = tik_instance.Tensor("int16", (4,), name="tensor_a", scope=tik.scope_ubuf) s7.set_as(tensor_a[0]) ''' 例如: tensor_a = [1,2,3,4] 则经过赋值后: s7 = 1 '''
为Tensor赋值
TIK提供了两种方式为Tensor赋值,设置或修改Tensor的内容。
- 方法一:通过set_as设置或改变Tensor的值。
# 示例: from tbe import tik tik_instance = tik.Tik() data_A = tik_instance.Tensor("int16", (4,), name="data_A", scope=tik.scope_ubuf) data_B = tik_instance.Tensor("int16", (4,), name="data_B", scope=tik.scope_ubuf) data_B[1].set_as(4) # 将data_B的第二个元素的值设为4 (1) data_A[0].set_as(data_B[1]) # 将data_B的第二个元素的值赋给data_A的第一个元素 (2) ''' 例如: data_A = [1, 1, 1, 1] data_B = [0, 0, 0, 0] 经过赋值语句(1)后: data_B = [0, 4, 0, 0] 经过赋值语句(2)后: data_A = [4, 1, 1, 1] '''
- 方法二:通过Tensor数组下标,改变Tensor内容,相关接口:改变Tensor内容。
# 示例: ''' data_A初始值为:[1.2, 2.4, 3.6, 4.8] ''' from tbe import tik tik_instance = tik.Tik() data_A = tik_instance.Tensor("float16", (4,), name="data_A", scope=tik.scope_ubuf) scalar_B = tik_instance.Scalar(dtype="float16", name="scalar_B", init_value=2.0) scalar_idx = tik_instance.Scalar(dtype="int16", name="scalar_idx", init_value=1) # index为0, value为1.0, 下面这条语句将一个立即数赋给data_A的第一个元素 data_A[0] = 1.0 ''' 经过下标修改值后: data_A = [1.0, 2.4, 3.6, 4.8] ''' # index为scalar_idx, value为scalar_B, 下面这条语句将一个scalar赋给data_A的第二个元素 data_A[scalar_idx] = scalar_B ''' 经过下标修改值后: data_A = [1.0, 2.0, 3.6, 4.8] ''' # index为由scalar(int16)和立即数int组成的Expr, value为由scalar(float16)和立即数float组成的Expr, 下面这条语句将一个Expr赋给data_A的第三个元素 data_A[scalar_idx+1] = scalar_B + 2.2 ''' 经过下标修改值后: data_A = [1.0, 2.0, 4.2, 4.8] '''
除了以上两种修改Tensor值的方法,还有其余所有的Tensor运算API都可以对Tensor的值进行修改,例如:使用vec_add接口可以进行加法运算,将相加的结果赋给目的Tensor。
获取Tensor形状
TIK提供了shape接口用于获取Tensor shape。
# 示例: from tbe import tik tik_instance = tik.Tik() data_A = tik_instance.Tensor("float16", (128,), name="data_A", scope=tik.scope_ubuf) data_A.shape # 输出data_A的shape,为:[128]
改变Tensor形状
TIK提供了reshape接口用于改变Tensor shape。
# 示例: from tbe import tik tik_instance = tik.Tik() data_A = tik_instance.Tensor("int16", (4,), name="data_A", scope=tik.scope_gm) # 将data_A的形状由原来的4*1改变为2*2 data_A.reshape((2,2)) ''' 初始:data_A = [1, 2, 3, 4] 经过reshape后: data_A = [[1, 2], [3, 4]] '''
通过下标切片获取Tensor部分数据
TIK提供了相关接口,可以通过Tensor数组下标,获得Tensor内部分数据,形成新的Tensor,相关接口:获取Tensor部分数据。
# 示例: from tbe import tik tik_instance = tik.Tik() data_A = tik_instance.Tensor("int16", (8,), name="data_A", scope=tik.scope_gm) data_B = tik_instance.Tensor("int16", (4,), name="data_B", scope=tik.scope_gm) data_B = data_A[4:] # 对data_A进行切片,data_B包含data_A第5个数及其之后的所有数据 ''' 例如: data_A = [1,2,3,4,5,6,7,8] 经过切片取值后: data_B = [5,6,7,8] '''
以指定数据类型读取数据
TIK提供了reinterpret_cast_to接口,用于以用户指定的数据类型,读取相同内存数据,并对内存中的字节重新解释。
例如:128个float16,则可以使用reinterpret_cast_to指定以float32的方式读取该段数据,会获得64个float32,因此reinterpret_cast_to并非真正将每一个float16数据转化成对应float32数据,这一点与数据精度转换接口vec_conv不同。
# 示例: from tbe import tik tik_instance = tik.Tik() data_A = tik_instance.Tensor("float16", (16,), name="data_A", scope=tik.scope_gm) data_B = data_A.reinterpret_cast_to("uint32") data_C = data_B.reinterpret_cast_to("float16") """调用结果如下: 输入数据: # data_A 原本是float16的数据 data_A: [ 4.812e+00 1.870e-04 -5.692e-02 2.528e-02 -9.225e+02 -1.431e+02 -1.541e+01 -2.018e-03 1.653e-03 -4.090e+00 2.016e+01 -5.846e+04 -8.072e-03 2.627e+00 -3.174e-02 -3.088e-01] 输出数据: data_B: # data_B 是以uint32的形式读取的 [ 169952464 645507913 3631866677 2552417204 3289847493 4213394698 1094819874 3035736080] data_C: # data_C 是以float16的形式读取的 [ 4.812e+00 1.870e-04 -5.692e-02 2.528e-02 -9.225e+02 -1.431e+02 -1.541e+01 -2.018e-03 1.653e-03 -4.090e+00 2.016e+01 -5.846e+04 -8.072e-03 2.627e+00 -3.174e-02 -3.088e-01] """