Taichi在数组访问越界时的行为

大家好!在做GAMES201作业的时候发现,Taichi在数组访问越界的时候并不会报错,而是直接返回0。比如说下面的例子:

x = ti.var(dt=ti.f32, shape = (3,3))
x[5,5] # Return 0.0

这样的特性在写边界条件的时候有时候挺方便的,因为不需要去特意处理越界访问,但是不知道这种做法是否推荐?越界访问返回0是Taichi语言特性故意为之,还是应该尽量避免使用?

2 个赞

Interesting, I think this could be a per-backend feature.
@yuanming It seems our LLVM backend can automatically detect OOB and return 0.0 on that?
Not sure this works on all backends… @houkensjtu If you have OpenGL or Metal backend, could you try this out?

import taichi as ti

ti.init(arch=ti.opengl)  # ti.metal if you're on Mac machine
ti.set_logging_level(ti.DEBUG)

x = ti.var(ti.f32, (10, 10))

@ti.kernel
def init():
    for i, j in x:
        x[i, j] = 10 * i + j

@ti.kernel
def access():
    print(x[0, 11])

init()
access()

If it works, we may want to add this behavior document :slight_smile:

BTW, FYI, if we initialize Taichi with ti.init(debug=True), out-of-bound will always result in a RuntimeError.

1 个赞

Oh! I found that this behavior only works when the tensor size is not power-of-two:

import taichi as ti
ti.init(arch=ti.cpu)

N = 8

x = ti.var(ti.i32, N)

@ti.kernel
def test():
    for i in x:
        x[i] = 1000 + i
    for i in ti.static(range(-N, 2 * N)):
        print(i, x[i])

test()

N = 8:

-8 1000
-7 1001
-6 1002
-5 1003
-4 1004
-3 1005
-2 1006
-1 1007
0 1000
1 1001
2 1002
3 1003
4 1004
5 1005
6 1006
7 1007
8 1000
9 1001
10 1002
11 1003
12 1004
13 1005
14 1006
15 1007

N = 5:

-5 1003
-4 1004
-3 0
-2 0
-1 0
0 1000
1 1001
2 1002
3 1003
4 1004
5 0
6 0
7 0
8 1000
9 1001

N = 3:

-3 1001
-2 1002
-1 0
0 1000
1 1001
2 1002
3 0
4 1000
5 1001

I think this is related to the tensor layout: Taichi always store tensors in POT.
So when a tensor is non-POT, access OOB will get 0.
When a tensor is POT, access OOB will get x[i % N, j % N].


Anyway, I think we shouldn’t depend too much on this.

1 个赞

抱歉翻了个老贴出来。。。
刚刚重新看文档的时候发现了疑似的原因是Taichi会自动扩展张量的大小?
Taichi的张量尺寸
这如果是真的话,是不是说比如我建立一个100x100的矩阵,实际则会占领2^14 = 16384的内存空间,因为那是最接近10000的二次幂?

刚刚重新看文档的时候发现了疑似的原因是Taichi会自动扩展张量的大小?

是的,所以非2次幂的大小才会自动变成0。

这如果是真的话,是不是说比如我建立一个100x100的矩阵,实际则会占领2^14 = 16384的内存空间,因为那是最接近10000的二次幂?

不,IIRC它会变成128x128的矩阵,可能是为了要所有个索引都对齐到2才能获得最佳内存性能。

1 个赞

不过话又说回来。。在这个代码里

x = ti.var(dt=ti.f32, shape = (3,3))
x[5,5] # Return 0.0
x[10000,10000] # Also return 0.0!?

按照文档的说法扩展是应该扩展到4x4,但是我试了一下访问远大于这个尺寸的元素都不会报错而返回0的。不管如何,这个问题也不是很紧急。。先谢谢大佬

I believe if you use ti.init(debug=True) then x[10000, 10000] will give you an error :slight_smile:

1 个赞