taichi.lang.exception.TaichiSyntaxError: Invalid type annotation (argument 1) of Taichi function: <taichi.types.ndarray_type.NdarrayType object at 0x0000018406415C08>

想问问这个报错是什么问题导致的。我的程序报错如下:
(I want to ask what caused this error report. My program reports errors as follows):
f’Invalid type annotation (argument {i}) of Taichi function: {annotation}’
taichi.lang.exception.TaichiSyntaxError: Invalid type annotation (argument 1) of Taichi function: <taichi.types.ndarray_type.NdarrayType object at 0x0000018406415C08>

import taichi as ti
from OPT.nsde import sort_by_values
ti.init()

@ti.func
def index_of(a: int, in_list: ti.types.ndarray()):
    list_len = in_list.shape[0]
    for i in range(0, list_len):
        if in_list[i] == a: return i

@ti.kernel
def mid(distance: ti.types.ndarray(), sorted0: ti.types.ndarray(), values: ti.types.ndarray(), front: ti.types.ndarray()) -> ti.types.ndarray():
    front_len = front.shape[0]
    for k in range(1, front_len - 1):
        distance[index_of(sorted0[k], front)] = distance[index_of(sorted0[k], front)] + (values[sorted0[k + 1]] - values[sorted0[k - 1]]) / (max(values) - min(values))
    return distance

# Function to calculate crowding distance
# 计算相应梯队front内的个体拥挤度
def crowding_distance(objects_values, front):
    distance = [0 for i in range(0, len(front))]  # 初始化个体拥挤度距离为零
    for values in objects_values:
        # python计算
        sorted0 = sort_by_values(front, values[:])
        distance[index_of(sorted0[0], front)] = int(1e10)
        distance[index_of(sorted0[-1], front)] = int(1e10)
        # 转化为numpy
        distance = numpy.array(distance, dtype=int)
        sorted0 = numpy.array(sorted0, dtype=int)
        values = numpy.asarray(values, dtype=float)
        front = numpy.array(front, dtype=int)
        # taichi计算
        distance = mid(distance, sorted0, values, front)
    return distance

以上是我的程序。
Please help me, I do not know how to let my code run, thank you!

Hi str,
我在尝试本地复现问题,想问一下方便把调用crowding_distance()的代码也贴上来吗?(我想知道objects_values和front的值)

可以通过这个方法进行测试:

import numpy
import math
import taichi as ti
ti.init()
# Function to sort by values
# 根据values中值的大小对list1中元素进行排序(list1元素值是values的索引值)
def sort_by_values(list1, values):
    sorted_list = []
    while len(sorted_list) != len(list1):
        if index_of(min(values), values) in list1:
            sorted_list.append(index_of(min(values), values))
        values[index_of(min(values), values)] = math.inf
    return sorted_list
@ti.func
def index_of(a: int, in_list: ti.types.ndarray()):
    list_len = in_list.shape[0]
    for i in range(0, list_len):
        if in_list[i] == a: return i
@ti.kernel
def mid(distance: ti.types.ndarray(), sorted0: ti.types.ndarray(), values: ti.types.ndarray(),
        front: ti.types.ndarray()) -> ti.types.ndarray():
    front_len = front.shape[0]
    for k in range(1, front_len - 1):
        distance[index_of(sorted0[k], front)] = distance[index_of(sorted0[k], front)] + (
                    values[sorted0[k + 1]] - values[sorted0[k - 1]]) / (max(values) - min(values))
    return distance
# Function to calculate crowding distance
# 计算相应梯队front内的个体拥挤度
def crowding_distance(objects_values, front):
    distance = [0 for i in range(0, len(front))]  # 初始化个体拥挤度距离为零
    for values in objects_values:
        # python计算
        sorted0 = sort_by_values(front, values[:])
        distance[index_of(sorted0[0], front)] = int(1e10)
        distance[index_of(sorted0[-1], front)] = int(1e10)
        # 转化为numpy
        distance = numpy.array(distance, dtype=int)
        sorted0 = numpy.array(sorted0, dtype=int)
        values = numpy.asarray(values, dtype=float)
        front = numpy.array(front, dtype=int)
        # taichi计算
        distance = mid(distance, sorted0, values, front)
    return distance
# test
objects_values = [[55, 47, 89, 56, 35, 102, 3], [24, 1, 108, 99, 15, 44, 3]]
front = [0, 1, 2, 3, 4, 5, 6]
res = crowding_distance(objects_values, front)
print(res)

非常感谢您对这个问题的关注。
我现在还没有想明白要修改什么地方可以解决bug。

多谢,我在本地能复现问题,我看一下哪里出问题了哈

对你的程序来说,只需要把ti.types.ndarray()标注成ti.template()

@ti.func
def index_of(a:int, in_list:ti.template()):
    list_len = in_list.shape[0]
    for i in range(0, list_len):
        if in_list[i] == a: return i

另外对于mid这个函数:

@ti.kernel
def mid(distance: ti.types.ndarray(), sorted0: ti.types.ndarray(), values: ti.types.ndarray(),
        front: ti.types.ndarray()) -> ti.types.ndarray():
    front_len = front.shape[0]
    index_of(sorted0[k], front)
    for k in range(1, front_len - 1):
        distance[index_of(sorted0[k], front)] = distance[index_of(sorted0[k], front)] + (
                    values[sorted0[k + 1]] - values[sorted0[k - 1]]) / (max(values) - min(values))
    return distance

Taichi会对传入的ndarray进行原位修改,所以其实distance的值已经改变了,也就没必要再返回distance了(Taichi Kernel也不支持返回ndarray),可以改成:

@ti.kernel
def mid(distance: ti.types.ndarray(), sorted0: ti.types.ndarray(), values: ti.types.ndarray(),
        front: ti.types.ndarray()):
    front_len = front.shape[0]
    index_of(sorted0[k], front)
    for k in range(1, front_len - 1):
        distance[index_of(sorted0[k], front)] = distance[index_of(sorted0[k], front)] + (
                    values[sorted0[k + 1]] - values[sorted0[k - 1]]) / (max(values) - min(values))
1 个赞

你好,非常感谢你的回复。
按照你的建议,我对我对代码进行了修改。
但是会出现新的报错:TypeError: ‘Expr’ object cannot be interpreted as an integer
修改后的代码如下:

import taichi as ti
ti.init()
# Function to sort by values
# 根据values中值的大小对list1中元素进行排序(list1元素值是values的索引值)
def sort_by_values(list1, values):
    sorted_list = []
    while len(sorted_list) != len(list1):
        if index_of(min(values), values) in list1:
            sorted_list.append(index_of(min(values), values))
        values[index_of(min(values), values)] = math.inf
    return sorted_list
def index_of(a, in_list):
    list_len = in_list.shape[0]
    for i in range(0, list_len):
        if in_list[i] == a: return i
@ti.kernel
def mid(distance: ti.types.ndarray(), sorted0: ti.types.ndarray(), values: ti.types.ndarray(),
        front: ti.types.ndarray()):
    front_len = front.shape[0]
    for k in range(1, front_len - 1):
        distance[index_of(sorted0[k], front)] = distance[index_of(sorted0[k], front)] + (
                    values[sorted0[k + 1]] - values[sorted0[k - 1]]) / (max(values) - min(values))
# Function to calculate crowding distance
# 计算相应梯队front内的个体拥挤度
def crowding_distance(objects_values, front):
    distance = [0 for i in range(0, len(front))]  # 初始化个体拥挤度距离为零
    for values in objects_values:
        # 转化为numpy
        distance = numpy.array(distance, dtype=int)
        values = numpy.asarray(values, dtype=float)
        front = numpy.array(front, dtype=int)
        # python计算
        sorted0 = sort_by_values(front, values[:])
        distance[index_of(sorted0[0], front)] = int(1e5)
        distance[index_of(sorted0[-1], front)] = int(1e5)
        # 转化为numpy
        sorted0 = numpy.array(sorted0, dtype=int)
        # taichi计算
        mid(distance, sorted0, values, front)
    return distance
# test
objects_values = [[55, 47, 89, 56, 35, 102, 3], [24, 1, 108, 99, 15, 44, 3]]
front = [0, 1, 2, 3, 4, 5, 6]
res = crowding_distance(objects_values, front)
print(res)

报错信息如下:

E:\A-科研\6-Python编程\venv\Scripts\python.exe "E:/A-科研/6-Python编程/ DifferentialEvolutionAlgorithm/test.py"
[Taichi] version 1.0.4, llvm 10.0.0, commit 2827db2c, win, python 3.7.7
[Taichi] Starting on arch=x64
Traceback (most recent call last):
  File "E:/A-科研/6-Python编程/ DifferentialEvolutionAlgorithm/test.py", line 90, in <module>
    res = crowding_distance(objects_values, front)
  File "E:/A-科研/6-Python编程/ DifferentialEvolutionAlgorithm/test.py", line 84, in crowding_distance
    mid(distance, sorted0, values, front)
  File "E:\A-科研\6-Python编程\venv\lib\site-packages\taichi\lang\kernel_impl.py", line 917, in wrapped
    raise type(e)('\n' + str(e)) from None
taichi.lang.exception.TaichiCompilationError: 
On line 66 of file "E:/A-科研/6-Python编程/ DifferentialEvolutionAlgorithm/test.py", in mid:
        distance[index_of(sorted0[k], front)] = distance[index_of(sorted0[k], front)] + (
Traceback (most recent call last):
  File "E:\A-科研\6-Python编程\venv\lib\site-packages\taichi\lang\ast\ast_transformer_utils.py", line 24, in __call__
    return method(ctx, node)
  File "E:\A-科研\6-Python编程\venv\lib\site-packages\taichi\lang\ast\ast_transformer.py", line 454, in build_Call
    node.ptr = func(*args, **keywords)
  File "E:/A-科研/6-Python编程/ DifferentialEvolutionAlgorithm/test.py", line 51, in index_of
    for i in range(0, list_len):
TypeError: 'Expr' object cannot be interpreted as an integer

我越来越感到奇怪与困难了。 :crying_cat_face:

我帮你改了一版,这个应该能跑:

import taichi as ti
import numpy
import math

ti.init(ti.cpu)

# Function to sort by values
# 根据values中值的大小对list1中元素进行排序(list1元素值是values的索引值)
def sort_by_values(list1, values):
    sorted_list = []
    while len(sorted_list) != len(list1):
        if index_of(min(values), values) in list1:
            sorted_list.append(index_of(min(values), values))
        values[index_of(min(values), values)] = math.inf
    return sorted_list

def index_of(a, in_list):
    list_len = in_list.shape[0]
    for i in range(0, list_len):
        if in_list[i] == a: return i

@ti.func
def ti_index_of(a: int, in_list:ti.template()) -> ti.i32:
    list_len = in_list.shape[0]
    tmp = -1
    for i in range(0, list_len):
        if in_list[i] == a: 
            tmp = i
    return tmp

@ti.func
def calc_range(arr : ti.types.ndarray()) -> ti.f32:
    max_val = -math.inf
    min_val = math.inf

    for i in arr:
        max_val = max(arr[i], max_val)
        min_val = min(arr[i], min_val)
    
    diff = max_val - min_val
    return diff


@ti.kernel
def mid(distance: ti.types.ndarray(), sorted0: ti.types.ndarray(), values: ti.types.ndarray(),
        front: ti.types.ndarray()):
    front_len = front.shape[0]
    for k in range(1, front_len - 1):
        distance[ti_index_of(sorted0[k], front)] = distance[ti_index_of(sorted0[k], front)] + (
                    values[sorted0[k + 1]] - values[sorted0[k - 1]]) / calc_range(values)


# Function to calculate crowding distance
# 计算相应梯队front内的个体拥挤度
def crowding_distance(objects_values, front):
    distance = [0 for i in range(0, len(front))]  # 初始化个体拥挤度距离为零
    for values in objects_values:
        # 转化为numpy
        distance = numpy.array(distance, dtype=int)
        values = numpy.asarray(values, dtype=float)
        front = numpy.array(front, dtype=int)
        # python计算
        sorted0 = sort_by_values(front, values[:])
        distance[index_of(sorted0[0], front)] = int(1e5)
        distance[index_of(sorted0[-1], front)] = int(1e5)
        # 转化为numpy
        sorted0 = numpy.array(sorted0, dtype=int)
        # taichi计算
        mid(distance, sorted0, values, front)
    return distance

# test
objects_values = [[55, 47, 89, 56, 35, 102, 3], [24, 1, 108, 99, 15, 44, 3]]
front = [0, 1, 2, 3, 4, 5, 6]
res = crowding_distance(objects_values, front)
print(res)

几个问题:

  1. 一般debug的时候会用比较小的例子,比如这种复合代码写开会比较容易发现问题:
distance[index_of(sorted0[k], front)] = distance[index_of(sorted0[k], front)] + (
                    values[sorted0[k + 1]] - values[sorted0[k - 1]]) / (max(values) - min(values))
  1. 你会发现我加了一个ti_index_of()函数,对Taichi程序来说,Kernel内和Kernel外是两个完全不用的体系,有各自的约束。可以参考一下这两个文档:
    Kernels and functions | Taichi Docs
    Differences between Taichi and Python programs | Taichi Docs

  2. 加了calc_range(values)是因为Taichi Kernel里暂时不支持array整体的计算(比如一个array减另一个array),所以这里手动实现了max(values) - min(values)

你好,非常感谢。
但是我在自己电脑上运行你的程序,会得到如下报错:

E:\A-科研\6-Python编程\venv\Scripts\python.exe "E:/A-科研/6-Python编程/ DifferentialEvolutionAlgorithm/test.py"
[Taichi] version 1.0.4, llvm 10.0.0, commit 2827db2c, win, python 3.7.7
[Taichi] Starting on arch=x64
Traceback (most recent call last):
  File "E:/A-科研/6-Python编程/ DifferentialEvolutionAlgorithm/test.py", line 130, in <module>
    def calc_range(arr: ti.types.ndarray()) -> ti.f32:
  File "E:\A-科研\6-Python编程\venv\lib\site-packages\taichi\lang\kernel_impl.py", line 61, in func
    fun = Func(fn, _classfunc=is_classfunc, is_real_function=is_real_function)
  File "E:\A-科研\6-Python编程\venv\lib\site-packages\taichi\lang\kernel_impl.py", line 194, in __init__
    self.extract_arguments()
  File "E:\A-科研\6-Python编程\venv\lib\site-packages\taichi\lang\kernel_impl.py", line 312, in extract_arguments
    f'Invalid type annotation (argument {i}) of Taichi function: {annotation}'
taichi.lang.exception.TaichiSyntaxError: Invalid type annotation (argument 0) of Taichi function: <taichi.types.ndarray_type.NdarrayType object at 0x00000231E5A98648>

似乎又是之前那个ti.func修饰器引起的bug,但是去掉了也会出现问题。 :cry:

不好意思刚刚在本地修复了这个bug,所以程序里少改了一个地方:
def calc_range(arr: ti.types.ndarray()) 替换成 def calc_range(arr: ti.template())

完整程序:

import taichi as ti
import numpy
import math

ti.init(ti.cpu)

# Function to sort by values
# 根据values中值的大小对list1中元素进行排序(list1元素值是values的索引值)
def sort_by_values(list1, values):
    sorted_list = []
    while len(sorted_list) != len(list1):
        if index_of(min(values), values) in list1:
            sorted_list.append(index_of(min(values), values))
        values[index_of(min(values), values)] = math.inf
    return sorted_list

def index_of(a, in_list):
    list_len = in_list.shape[0]
    for i in range(0, list_len):
        if in_list[i] == a: return i

@ti.func
def ti_index_of(a: int, in_list:ti.template()) -> ti.i32:
    list_len = in_list.shape[0]
    tmp = -1
    for i in range(0, list_len):
        if in_list[i] == a: 
            tmp = i
    return tmp

@ti.func
def calc_range(arr : ti.template()) -> ti.f32:
    max_val = -math.inf
    min_val = math.inf

    for i in arr:
        max_val = max(arr[i], max_val)
        min_val = min(arr[i], min_val)
    
    diff = max_val - min_val
    return diff


@ti.kernel
def mid(distance: ti.types.ndarray(), sorted0: ti.types.ndarray(), values: ti.types.ndarray(),
        front: ti.types.ndarray()):
    front_len = front.shape[0]
    for k in range(1, front_len - 1):
        distance[ti_index_of(sorted0[k], front)] = distance[ti_index_of(sorted0[k], front)] + (
                    values[sorted0[k + 1]] - values[sorted0[k - 1]]) / calc_range(values)


# Function to calculate crowding distance
# 计算相应梯队front内的个体拥挤度
def crowding_distance(objects_values, front):
    distance = [0 for i in range(0, len(front))]  # 初始化个体拥挤度距离为零
    for values in objects_values:
        # 转化为numpy
        distance = numpy.array(distance, dtype=int)
        values = numpy.asarray(values, dtype=float)
        front = numpy.array(front, dtype=int)
        # python计算
        sorted0 = sort_by_values(front, values[:])
        distance[index_of(sorted0[0], front)] = int(1e5)
        distance[index_of(sorted0[-1], front)] = int(1e5)
        # 转化为numpy
        sorted0 = numpy.array(sorted0, dtype=int)
        # taichi计算
        mid(distance, sorted0, values, front)
    return distance

# test
objects_values = [[55, 47, 89, 56, 35, 102, 3], [24, 1, 108, 99, 15, 44, 3]]
front = [0, 1, 2, 3, 4, 5, 6]
res = crowding_distance(objects_values, front)
print(res)

运行结果:

1 个赞

但是这与我没有使用taichi的计算结果相比并不一致,真是让人头疼啊。:smiling_face_with_tear:
在不使用taichi的程序的基础上计算结果是:
[0.36193712829226843, 10000000000, 10000000000, 0.9415651845558387, 0.6407061266874351, 10000000000.700935, 10000000000.13084]

import math
import numpy
# Function to find index of list
# 获取出list中元素值为a的元素索引
def index_of(a, list):
    for i in range(0, len(list)):
        if list[i] == a: return i
    return -1
# Function to sort by values
# 根据values中值的大小对list1中元素进行排序(list1元素值是values的索引值)
def sort_by_values(list1, values):
    sorted_list = []
    while len(sorted_list) != len(list1):
        if index_of(min(values), values) in list1:
            sorted_list.append(index_of(min(values), values))
        values[index_of(min(values), values)] = math.inf
    return sorted_list
def crowding_distance111(objects_values, front):
    distance = [0 for i in range(0, len(front))]  # 初始化个体拥挤度距离为零
    for values in objects_values:
        sorted0 = sort_by_values(front, values[:])
        distance[index_of(sorted0[0], front)] = int(1e10)
        distance[index_of(sorted0[-1], front)] = int(1e10)
        for k in range(1, len(front) - 1):
            distance[index_of(sorted0[k], front)] = \
                distance[index_of(sorted0[k], front)] + \
                (values[sorted0[k + 1]] - values[sorted0[k - 1]]) / (max(values) - min(values))
    return distance
# test
objects_values = [[55, 47, 89, 56, 35, 102, 3], [24, 1, 108, 99, 15, 44, 3]]
front = [0, 1, 2, 3, 4, 5, 6]
res = crowding_distance111(objects_values, front)
print(res)

:smiling_face_with_tear:感觉可能还是要再debug一下,如果是找到Taichi里的某个运算导致精度有问题,可以继续提给我们哈~

主要是这让我难以信任taichi的计算结果,我还在思考为什么会结果不一致。
看来我这里的任务还是没办法用了taichi来提升计算性能了。 :smiling_face_with_tear:

主要是当我们把Python代码转化为Taichi程序的时候,其实还是改动不小的。如果结果没法对齐的话很可能是转化的时候有些bug,或者某些Taichi Kernel内的语法和Python有差别。

如果想继续探索的话,可能需要print一些中间结果来找问题

1 个赞

我觉得最好还是不要用传 values[:] 这种方式来修改一个 list ? 看起来赋值为 inf 那个操作会把 values 全都变成 in,所以结果是不对的。而且 taichi 版本的代码里面 distance 的类型是 int,所以会被 cast 到整数。