1 系统环境
硬件环境(Ascend/GPU/CPU): Ascend/GPU/CPU
MindSpore版本: mindspore=2.0.0
执行模式(PyNative/ Graph):不限
Python版本: Python=3.9.7
操作系统平台: 不限
2 报错信息
2.1 问题描述
定义了一连串的transforms,知道vision.RandomGrayscale要求是PIL作为输入,因此在这个transform前加了vision.ToPIL(),可是为什么会报错提示说输入仍然是个numpy呢? vision.ToPIL()这个操作好像没有生效。
2.2 脚本信息
2.3 问题描述
3 根因分析
我打算从源码的角度分析一下,源码其实安装在conda下,在命令行里使用pip show mindspore就可以查看到
那么mindspore的源码就位于
/home/xxxx/.conda/envs/ly37/lib/python3.7/site-packages/mindspore

按照报错提示的python路径,我在dataset里面搜索Compose算子,开始分析源码 mindspore/dataset/transforms/transforms.py
如果调用到了_execute_py函数,那么util.compose函数是会循环执行transfomrs.Compose中的数据增强算子的,这样vision.ToPIL肯定会返回一个Pillow对象给vision.RandomGrayscale,这样按理说不会出错。但当我在_execute_py里面添加一行打印
发现其竟然没有打印出来,那么肯定哪里的逻辑有点问题了。
由于是以function call的形式调用transfomrs.Compose,那么一定是触发了他的__call__方法,但是这个类里没有定义,最后在他的父类里找到了方法定义
mindspore/dataset/transforms/transforms.py
发现__call__方法里其实有分支是调用_execute_py方法的,但是为什么没走进去呢。如果78行的if条件是False,那么他肯定走了下面的分支导致计算出错,通过添加打印我也确认了这点,发现确实只打印了"go into other branch "
那么问题来了,if条件是用来判断什么的呢,导致他条件为False,于是我也把所有的if条件打印了一下,发现and前后两个条件都是False

这下就有点不大知道怎么往下看了。不过我也粗略尝试了一下,我想要不直接帮vision.Compose重载一个__call__方法让他直接调用_execute_py会怎么样
令我震惊的是,居然可以运行成功!这算是发现了并修复了mindspore 的bug嘛233
4 解决方案
关于怎么解决这个问题
- 解决方案一:就是像上面分析的那样,我直接修改安装目录下的源码解决了这个问题,但是我不确定这么改会不会有什么问题。
- 解决方案二:我尝试着在不修改源码的基础上,规避一下这个bug。
由于RandomGrayscale需要是一个Pillow的输入,那我就构造一个给他呗,把代码改成这样
通过灵活的python lambda表达式,我把输入先用Pillow的函数包装一层,然后再传给vision.RandomGrayscale不就好了,事实证明这么写确实也有效,结果如下:

附上最后规避这个问题的写法code











