数据排布格式

数据排布格式(Data Layout Format)是深度学习中对多维Tensor在内存中存储方式的描述。

常见的数据格式包括ND、NHWC和NCHW等,为Tensor的每个轴赋予了特定的业务语义。

除了上述NHWC和NCHW格式外,还存在一些特殊的私有数据格式,如FRACTAL_NZ(也简称NZ)、NC1HWC0、FRACTAL_Z、NDC1HWC0、FRACTAL_Z_3D等。这些格式的引入是为了满足AI Core中Cube计算单元的高性能计算需求,通过优化内存布局,这些格式能够提升计算效率。在使用矩阵乘、卷积API开发相关算子的过程中,您可以看到这些格式的具体应用。

普通格式

矩阵乘相关特殊格式

使用Mmad基础API进行矩阵乘计算时,对矩阵输入输出的数据排布格式有一定的要求,如下图所示,要求A矩阵(位于L0A Buffer)为FRACTAL_ZZ,B矩阵(位于L0B Buffer)为FRACTAL_ZN,C矩阵(位于L0C Buffer)为FRACTAL_NZ。这些格式将矩阵划分成了一些分形(Fractal Matrix),适配Cube计算单元每次读取(16, 16)× (16, 16) 的数据进行计算的硬件特点(以half数据类型为例),从而提高矩阵计算的效率。分形的大小和数据类型有关,也和所在的存储位置有关,具体可参见下文的详细介绍。

  • FRACTAL_NZ/NZ

    FRACTAL_NZ格式,简称NZ格式,是对一个Tensor最低两维(一个Tensor的所有维度,右侧为低维,左侧为高维)进行填充(pad)、拆分(reshape)和转置(transpose)操作后得到的格式。具体的转换过程如下:

    (M,N)大小的矩阵被分为M1 * N1个分形,按照column major(列优先)排布,形状如N字形;每个分形内部有M0 * N0个元素,按照row major(行优先)排布,形状如Z字形,所以这种数据格式称为NZ格式。其中,(M0, N0)表示一个分形的大小。

    通过公式表达为:

    (…, B, M, N)->pad->(…, B, M1 * M0, N1 * N0)->reshape->(…, B, M1, M0, N1, N0)->transpose->(…, B, N1, M1, M0, N0)

    通常情况下,NZ格式在L0C Buffer和L1 Buffer中分别用于不同的场景:

    • 在L0C Buffer中,NZ格式用于存储矩阵乘法的结果。其分形形状为16x16,包含256个元素,这种结构非常适合Cube计算单元进行高效的矩阵乘法运算。
    • 在L1 Buffer中,NZ格式被采用以便于将数据搬运到L0A Buffer和L0B Buffer时,能够方便地转换为对应的ZZ和ZN格式。此时,分形形状为16 x (32B / sizeof(Datatype)),大小为512字节。

    因此,当数据从L0C Buffer搬运到L1 Buffer时,其分形大小可能会发生变化。

    下面通过一个具体的例子来了解ND格式转换为NZ格式的过程。

    原始Tensor的Shape为(20, 28):

    1
    2
    3
    4
    data = [x for x in range(20 * 28)]
    data_a = data * np.ones((20 * 28), dtype="float16")
    tensor_a = data_a.reshape((20, 28))
    print(tensor_a)
    

    原始Tensor数据打印如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    [[  0.   1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.  12.  13.
       14.  15.  16.  17.  18.  19.  20.  21.  22.  23.  24.  25.  26.  27.]
     [ 28.  29.  30.  31.  32.  33.  34.  35.  36.  37.  38.  39.  40.  41.
       42.  43.  44.  45.  46.  47.  48.  49.  50.  51.  52.  53.  54.  55.]
     [ 56.  57.  58.  59.  60.  61.  62.  63.  64.  65.  66.  67.  68.  69.
       70.  71.  72.  73.  74.  75.  76.  77.  78.  79.  80.  81.  82.  83.]
     [ 84.  85.  86.  87.  88.  89.  90.  91.  92.  93.  94.  95.  96.  97.
       98.  99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111.]
     [112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125.
      126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139.]
     [140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153.
      154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167.]
     [168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181.
      182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195.]
     [196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209.
      210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223.]
     [224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237.
      238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251.]
     [252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265.
      266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279.]
     [280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293.
      294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307.]
     [308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321.
      322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335.]
     [336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349.
      350. 351. 352. 353. 354. 355. 356. 357. 358. 359. 360. 361. 362. 363.]
     [364. 365. 366. 367. 368. 369. 370. 371. 372. 373. 374. 375. 376. 377.
      378. 379. 380. 381. 382. 383. 384. 385. 386. 387. 388. 389. 390. 391.]
     [392. 393. 394. 395. 396. 397. 398. 399. 400. 401. 402. 403. 404. 405.
      406. 407. 408. 409. 410. 411. 412. 413. 414. 415. 416. 417. 418. 419.]
     [420. 421. 422. 423. 424. 425. 426. 427. 428. 429. 430. 431. 432. 433.
      434. 435. 436. 437. 438. 439. 440. 441. 442. 443. 444. 445. 446. 447.]
     [448. 449. 450. 451. 452. 453. 454. 455. 456. 457. 458. 459. 460. 461.
      462. 463. 464. 465. 466. 467. 468. 469. 470. 471. 472. 473. 474. 475.]
     [476. 477. 478. 479. 480. 481. 482. 483. 484. 485. 486. 487. 488. 489.
      490. 491. 492. 493. 494. 495. 496. 497. 498. 499. 500. 501. 502. 503.]
     [504. 505. 506. 507. 508. 509. 510. 511. 512. 513. 514. 515. 516. 517.
      518. 519. 520. 521. 522. 523. 524. 525. 526. 527. 528. 529. 530. 531.]
     [532. 533. 534. 535. 536. 537. 538. 539. 540. 541. 542. 543. 544. 545.
      546. 547. 548. 549. 550. 551. 552. 553. 554. 555. 556. 557. 558. 559.]]
    

    转换过程通过伪代码表达如下:

    N0 = 16
    N1 = (28 + N0 - 1) // N0
    pad_n = N1 * N0 - 28
    M0 = 16
    M1 = (20 + M0 - 1) // M0
    pad_m = M1 * M0 - 20
    tensor_b = np.pad(tensor_a, [[0, pad_m], [0, pad_n]])
    tensor_b = tensor_b.reshape((M1, M0, N1, N0))
    tensor_b = tensor_b.transpose((2, 0, 1, 3))
    print(tensor_b)

    转换过程示意图如下:

    转换后Tensor打印如下:

    [[[[  0.   1.   2. ...  13.  14.  15.]
       [ 28.  29.  30. ...  41.  42.  43.]
       [ 56.  57.  58. ...  69.  70.  71.]
       ...
       [364. 365. 366. ... 377. 378. 379.]
       [392. 393. 394. ... 405. 406. 407.]
       [420. 421. 422. ... 433. 434. 435.]]
    
      [[448. 449. 450. ... 461. 462. 463.]
       [476. 477. 478. ... 489. 490. 491.]
       [504. 505. 506. ... 517. 518. 519.]
       ...
       [  0.   0.   0. ...   0.   0.   0.]
       [  0.   0.   0. ...   0.   0.   0.]
       [  0.   0.   0. ...   0.   0.   0.]]]
    
    
     [[[ 16.  17.  18. ...   0.   0.   0.]
       [ 44.  45.  46. ...   0.   0.   0.]
       [ 72.  73.  74. ...   0.   0.   0.]
       ...
       [380. 381. 382. ...   0.   0.   0.]
       [408. 409. 410. ...   0.   0.   0.]
       [436. 437. 438. ...   0.   0.   0.]]
    
      [[464. 465. 466. ...   0.   0.   0.]
       [492. 493. 494. ...   0.   0.   0.]
       [520. 521. 522. ...   0.   0.   0.]
       ...
       [  0.   0.   0. ...   0.   0.   0.]
       [  0.   0.   0. ...   0.   0.   0.]
       [  0.   0.   0. ...   0.   0.   0.]]]]

卷积相关特殊格式

Matmul高阶API相关格式

COLUMN_MAJOR

ND数据排布格式也称为ROW_MAJOR(行优先),相应的有COLUMN_MAJOR(列优先)。这两种数据排布格式的区别是数组或矩阵中哪个方向上的连续元素在内存连续。

两种数据排布格式的示意图如下所示。