更新时间:2021-03-18 GMT+08:00
分享

数据定义

TIK支持不同的数据类型计算,但是不同API支持不同的数据类型,TIK中的数据类型有:int8, uint8, int16, uint16, int32, uint32, float16, float32,uint1(bool)等。TIK为强类型语言,即不同数据类型的之间无法进行计算。

TIK提供定义Scalar标量数据定义Tensor张量数据两种数据类型,通过本节可以了解到两种数据类型的定义方式。

定义Scalar标量数据

Scalar标量数据对应于存储在寄存器或者Scalar Buffer中的数据,TIK提供了Scalar接口用于定义Scalar数据,定义方式为:

1
data_A = tik_instance.Scalar(dtype = "float32")

通过dtype指定Scalar对象的数据类型,包括:int8,uint8,int16, uint16,float16,int32,uint32,float32, int64, uint64。

也可以通过指定init_value对scalar赋初始值:

data_A = tik_instance.Scalar(dtype="float32", init_value=10.2)

Scalar生命周期符合如下规则:

  1. Scalar自申请时被创建,跳出所在代码块,则被释放,创建与释放之间的状态称为活跃状态。
  2. Scalar只有在活跃状态时能被访问。

Scalar的生命周期示例如图1所示,该图显示了S0,S1,S2三个变量的活跃状态。

图1 Scalar生命周期示例

定义Tensor张量数据

Tensor数据对应于存储Buffer中的数据,TIK提供了Tensor接口用于定义Tensor数据,用户一般只需关注张量定义的数据类型(dtype)、形状(shape)与数据存储空间(scope)即可,定义方式为:

1
data_B = tik_instance.Tensor("float16", (128,), name="data_A", scope=tik.scope_gm)

关键参数为:

  • dtype:指定Tensor对象的数据类型,取值:uint8、int8、uint16、int16、float16、uint32、int32、float32、uint64、int64。
  • shape:指定Tensor对象的形状,支持List(int), tuple(int)类型。
  • scope:Tensor 内存类型范围,指定Tensor对象的所在buffer空间,取值:
    • scope_cbuf:L1 Buffer
    • scope_cbuf_out:L1OUT Buffer
    • scope_ubuf : Unified Buffer
    • scope_gm: Global Memory

TIK会自动为每个申请的Tensor对象分配空间,并且避免各个数据块之间的地址冲突。且TIK会自动检查数据之间的数据依赖性,实现数据的同步。

Tensor生命周期符合如下规则:

  1. Tensor自申请时被创建,跳出所在代码块,则被释放,创建与释放之间的状态称为活跃状态。
  2. Tensor只有在活跃状态时能被访问。
  3. 任何时刻,活跃状态的Tensor所占用的buffer总大小,不超过对应物理buffer的总大小。

Tensor的生命周期示例如图2所示。

图2 Tensor生命周期示例

上述示例中,代码被分成了5个时段,分别用1...5表示,每个时段活跃的Tensor以及总共使用的UB大小如表1所示。

表1 每个时段Tensor所占UB大小

时段

活跃Tensor

使用UB总大小

1

B0

256*2 Byte

2

B0,B1

256*2*2 Byte

3

B0,B1,B2

256*3*2 Byte

4

B0,B1,B3

256*3*2 Byte

5

B0,B4

256*2*2 Byte

实际开发活动中,输入张量shape可能超过Unified Buffer容量上限,必须经过多次传输才能完成计算;此时,为最大化利用Unified Buffer存储空间,数据定义指定的shape大小一般为Unified Buffer允许的最大值。代码示例如下:

# 获取Unified Buffer空间大小,单位为bytes
ub_size_bytes = te.platform.get_soc_spec("UB_SIZE")
 
# Unified Buffer上数据读取和写入必须32 bytes对齐,一个block的大小为32 bytes
block_bite_size = 32
 
# 根据输入的数据类型dtype_x,计算一个block可以存放多少个对应的元素
dtype_bytes_size = cce.cce_intrin.get_bit_len(dtype_x) // 8
data_each_block = block_bite_size // dtype_bytes_size
 
# 计算在Unified Buffer上需要分别分配多少空间,并进行32B对齐
ub_tensor_size = (ub_size_bytes // dtype_bytes_size // 
data_each_block * data_each_block)
 
# 在Unified Buffer上创建tensor input_x_ub
input_x_ub = tik_instance.Tensor(dtype_x, (ub_tensor_size,), 
name="input_x_ub", scope=tik.scope_ubuf)

与此同时,用户也可通过地址复用(或称地址重叠)以节省Unified Buffer存储空间。以矢量单目运算为例,当地址复用满足相应约束时,用户可以定义一个Tensor供源操作数与目的操作数同时使用,此时能节省一倍的存储空间。

分享:

    相关文档

    相关产品

close