MindSpore直接将Tensor从布尔值转换为浮点数导致错误Error: IndexError: index 1 is out of bounds for dimension with size 1

1 系统环境

硬件环境(Ascend/GPU/CPU): GPU
MindSpore版本: 1.9.0
执行模式(PyNative/ Graph): Graph模式
Python版本: 3.7.13
操作系统平台: 不限

2 报错信息

2.1 问题描述

直接将Tensor从布尔值转换为浮点数,导致错误的结果。在类型转换前更改为numpy后,结果正确。

2.2 报错信息

Error: IndexError: index 1 is out of bounds for dimension with size 1复制

2.3 脚本代码

import mindspore as ms
import mindspore.nn as nn
import mindspore.ops as ops
from mindspore import Tensor


class ConditionalNet(nn.Cell):
    def __init__(self):
        super().__init__()
        self.bool_list = Tensor([True, False])  # works ok if self.bool_list = [True, False]
        self.y = Tensor([1])
        self.z = Tensor([3, 4])

    def construct(self):
        output = []
        for i in range(len(self.bool_list)):
            if self.bool_list[i]:
                output.append(self.y[i])
            else:
                output.append(self.z[i])
        return ops.stack(output)

if __name__ == '__main__':
    ms.set_context(mode=ms.GRAPH_MODE)
    net = ConditionalNet()
    print(net())  # expected: 1, 4

3 根因分析

这个问题如果把模式修改成pynative模式的话,就能正常运行不报错。
所以问题就出在GRAPH模式上。
图模式是需要先编译成图再运行的,
失败后生成了analyze_fail.dat,但是该文件也没看出什么问题。

# 1.This file shows the parsed IR info when graph evaluating failed to help find the problem.  
# 2.You can search the last `------------------------>` to the node which is inferred failed.  
# 3.Refer to https://www.mindspore.cn/search?inputValue=analyze_fail.dat to get more instructions.  
# ===============================================================================  
  
# [No.1] Default_wrapper.1  
# In file D:/ai.py:14/    def construct(self, x, a, b):/  
funcgraph fg_1(  
        %para1 : Tensor(F32)[2, 3, 4, 5]    # x  
        , %para2 : Tensor(F32)[]    # a  
        , %para3 : Tensor(F32)[]    # b  
    ) {  
  
#------------------------> 0  
    %1 = FuncGraph::fg_6(%para1, %para2, %para3)    #(Tensor(F32)[2, 3, 4, 5], Tensor(F32)[], Tensor(F32)[])    # fg_6=Default.6 #scope: Default  
#[CNode]9  
    Primitive::Return{prim_type=1}(%1)    #(Undefined) #scope: Default  
      # In file D:/ai.py:15/        if a > b:/#[CNode]10  
}  
# order:  
#   1: @Default_wrapper.1:[CNode]9{[0]: ValueNode<FuncGraph> Default.6, [1]: x, [2]: a, [3]: b}  
#   2: @Default_wrapper.1:[CNode]10{[0]: ValueNode<Primitive> Return, [1]: [CNode]9}  
  
  
# [No.2] Default.6  
# In file D:/ai.py:14/    def construct(self, x, a, b):/  
funcgraph fg_6(  
        %para4 : Tensor(F32)[2, 3, 4, 5]    # x  
        , %para5 : Tensor(F32)[]    # a  
        , %para6 : Tensor(F32)[]    # b  
    ) {  
    %1 : Tensor(Bool)[] = DoSignaturePrimitive::S-Prim-greater{prim_type=1}(%para5, %para6)    #(Tensor(F32)[], Tensor(F32)[]) #scope: Default  
      # In file D:/ai.py:15/        if a > b:/#[CNode]11  
    %2 : Tensor(Bool)[] = FuncGraph::fg_12(%1)    #(Tensor(Bool)[])    # fg_12=bool_.12 #scope: Default  
      # In file D:/ai.py:15/        if a > b:/#[CNode]13  
    %3 : FuncNoShape = Primitive::Switch{prim_type=1}(%2, FuncGraph::fg_4, FuncGraph::fg_5)    #(Tensor(Bool)[], FuncNoShape, FuncNoShape)    # fg_4=?Default.4, fg_5=?Default.5 #scope: Default  
      # In file D:/ai.py:15/        if a > b:/#[CNode]8  
  
#------------------------> 1  
    %4 = %3() #scope: Default  
      # In file D:/ai.py:15/        if a > b:/#[CNode]7  
    Primitive::Return{prim_type=1}(%4)    #(Undefined) #scope: Default  
      # In file D:/ai.py:15/        if a > b:/#[CNode]14  
}  
# order:  
#   1: @Default.6:[CNode]11{[0]: ValueNode<DoSignaturePrimitive> S-Prim-greater, [1]: a, [2]: b}  
#   2: @Default.6:[CNode]13{[0]: ValueNode<FuncGraph> bool_.12, [1]: [CNode]11}  
#   3: @Default.6:[CNode]8{[0]: ValueNode<Primitive> Switch, [1]: [CNode]13, [2]: ValueNode<FuncGraph> ?Default.4, [3]: ValueNode<FuncGraph> ?Default.5}  
#   4: @Default.6:[CNode]7{[0]: [CNode]8}  
#   5: @Default.6:[CNode]14{[0]: ValueNode<Primitive> Return, [1]: [CNode]7}  
  
  
#===============================================================================  
# num of function graphs in stack: 2  

反正是两次都走到了output.append(self.y[i]),因为y 只有1个元素,第二次的话就报错了。
把self.y = Tensor([1])修改成self.y = Tensor([1,5]) 也能正常运行。实际运行时取值并没有取self.y[1],不知道为什么在图编译的时候报错了。
图模式下打印self.bool_list[i]的值,运行中打印的是1 ,0
pynative模式下打印的是True False

4 解决方案

self.bool_list = Tensor([True, False])修改成self.bool_list = [True, False]

import mindspore as ms  
import mindspore.nn as nn  
import mindspore.ops as ops  
from mindspore import Tensor  
    
    
class ConditionalNet(nn.Cell):  
    def __init__(self):  
        super().__init__()  
        self.bool_list = [True, False]  
        self.y = Tensor([1])  
        self.z = Tensor([3, 4])  
    
    def construct(self):  
        output = []  
        for i in range(len(self.bool_list)):  
            if self.bool_list[i]:  
                output.append(self.y[i])  
            else:  
                output.append(self.z[i])  
        return ops.stack(output)  
    
if __name__ == '__main__':  
    ms.set_context(mode=ms.GRAPH_MODE)  
    net = ConditionalNet()  
    print(net())  # expected: 1, 4