报错活动之vision.ToPIL在一定情况下无效

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
cke_12086.png
按照报错提示的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
cke_25667.png
这下就有点不大知道怎么往下看了。不过我也粗略尝试了一下,我想要不直接帮vision.Compose重载一个__call__方法让他直接调用_execute_py会怎么样

令我震惊的是,居然可以运行成功!这算是发现了并修复了mindspore 的bug嘛233

4 解决方案

关于怎么解决这个问题

  1. 解决方案一:就是像上面分析的那样,我直接修改安装目录下的源码解决了这个问题,但是我不确定这么改会不会有什么问题。
  2. 解决方案二:我尝试着在不修改源码的基础上,规避一下这个bug。

由于RandomGrayscale需要是一个Pillow的输入,那我就构造一个给他呗,把代码改成这样


通过灵活的python lambda表达式,我把输入先用Pillow的函数包装一层,然后再传给vision.RandomGrayscale不就好了,事实证明这么写确实也有效,结果如下:
cke_45597.png
附上最后规避这个问题的写法code