【MindSpore第六期两日集训营】MindSpore控制流作业记录

举报
张辉 发表于 2021/11/25 21:49:46 2021/11/25
【摘要】 MindSpore 1.5的新特性:MindSpore控制流。

【MindSpore第六期两日集训营】于2021年11月6日到11月7日在B站拉开了帷幕,错过直播 https://live.bilibili.com/22127570 的老铁们别忘了还有录播,链接分别为:


第一天:

第六期两日集训营 | MindSpore AI电磁仿真 https://www.bilibili.com/video/BV1Y34y1Z7E8?spm_id_from=333.999.0.0

第六期两日集训营 | MindSpore并行使能大模型训练 https://www.bilibili.com/video/BV193411b7on?spm_id_from=333.999.0.0

第六期两日集训营 | MindSpore Boost,让你的训练变得飞快 https://www.bilibili.com/video/BV1c341187ML?spm_id_from=333.999.0.0


第二天:

第六期两日集训营 | MindSpore 控制流概述 https://www.bilibili.com/video/BV1A34y1d7G7?spm_id_from=333.999.0.0

第六期两日集训营 | MindSpore Lite1.5特性发布,带来全新端侧AI体验 https://www.bilibili.com/video/BV1f34y1o7mR?spm_id_from=333.999.0.0

第六期两日集训营 | 可视化集群调优重磅发布,从LeNet到盘古大模型都能调优 https://www.bilibili.com/video/BV1dg411K7Nb?spm_id_from=333.999.0.0

我们来看第二天第一讲:MindSpore 控制流概述

作业如下:

作业思路:

1.先看看如果不用控制流,Python本身应该怎么做这个题目。

2.看看如何能启动MindSpore控制流。

3.将Python相关代码放入MindSpore控制流的建立方式中,实现相关功能。

张小白的解题思路:

递归的话,看一下0~1000的累加求和,相当于实现满足两种要求:

n>=1时:

f(n)=f(n-1)+n

n=0时:

f(n)=0

其实从0开始加和从1开始加都一样。所以题目即可以从0开始算,也可以从1开始算。

先用Python实现一个简单的递归:

vi python_recursion_01.py

def f(n):
    if n == 0:
        return 0
    else:
        return f(n-1) + n


sum = f(100)
print(sum)

执行一下:

python python_recursion_01.py

貌似没啥问题。

改成1000试试:

不行了。

因为Python3缺省的递归最大数为998,所以执行后直接报错。

我们试一下:

确实如此,但是有一种方法提高堆栈的最大值:

在代码中加入以下代码:

import sys
sys.setrecursionlimit(20000)

这个20000是张小白自己设置的。越大估计越占内存吧。

不如再改为10000试试:

也不用再往上试了。按理说这样子就可以迁移到控制流里面了。

听了老师的控制流视频后,

也可以再看看官网介绍的文档 https://www.mindspore.cn/docs/programming_guide/zh-CN/r1.5/control_flow.html

因为MindSpore默认的模式为GRAPH_MODE模式,所以直接按照示例来写代码就可以直接用到MindSpore控制流了。

我们来依葫芦画瓢一下:

看示例,首先要在网络中生成控制流算子。所以需要按下图示例使用MindSpore特有的方式建立一个SingleIfNet的网络:

我们如法炮制:

vi python_recursion_02.py

import numpy as np
from mindspore import context
from mindspore import Tensor, nn
from mindspore import dtype as ms

import sys
sys.setrecursionlimit(20000)

zero = Tensor(np.array(0), dtype=ms.int32)
one = Tensor(np.array(1), dtype=ms.int32)
count = Tensor(np.array(100), dtype=ms.int32)

class SingleIfNet(nn.Cell):
    def construct(self, n):
        if n == zero:
            return zero
        else:
            return self.construct( n - one ) + n

forward_net = SingleIfNet()
output = forward_net(count)
print (output)

当然在这种情况下,我们需要进入mindspore1.5-gpu的conda 环境,运行一下:

加到100没问题,那加到10000呢?

看样子是没啥问题。

前面张小白的代码要解释一下,原来代码中使用0,1这些整型数进行比较,但是由于现在是进行控制流计算,所以直接比较整型和tensor是不行的。需要把整型换成tensor(张量)来比较。

所以张小白才定义了

zero = Tensor(np.array(0), dtype=ms.int32)
one = Tensor(np.array(1), dtype=ms.int32)
count = Tensor(np.array(100), dtype=ms.int32)

这几个值,然后 所谓的0,1,count比较也是变量跟这些tensor的比较。

其实如果这样实现的话,那么while循环的实现反而简单了。

先看一下纯Python怎么做。

vi python_while.py

def f(n):
    x = 0
    out = 0
    while x < n:
        x = x + 1
        out = out + x
    return out

sum = f(100)
print(sum)

改成10000,1000000试试:

都没啥问题。

那么就继续改造成MindSpore控制流的方式:

vi python_while_02.py

import numpy as np
from mindspore import context
from mindspore import Tensor, nn
from mindspore import dtype as ms

import sys
sys.setrecursionlimit(20000)

zero = Tensor(np.array(0), dtype=ms.int32)
one = Tensor(np.array(1), dtype=ms.int32)
count = Tensor(np.array(100), dtype=ms.int32)

class SingleIfNet(nn.Cell):
    def construct(self, n):
        x = zero
        out = zero
        while  x < n:
            x = x + 1
            out = out + x
        return out

forward_net = SingleIfNet()
output = forward_net(count)
print (output)

执行一下:

python python_while_02.py

改成 普通python能计算的100万,看来mindspore控制流计算得比较吃力。

不过它算出来了:

而且似乎算错了,好像是溢出了——32位操作系统int类型的最大值是 2147483647,一共10位。

100万的计算结果,是500000500000,一共12位。

显然溢出了。

那只有改成int64:

cat python_while_03.py

python python_while_03.py

改成这样就没问题了。


张小白觉得前面maxdepth的显示非常得让人恼火。张小白也搜索到一些方式,比如尾递归的方法。

张小白找到了这篇:

https://blog.csdn.net/fall_song/article/details/106732276

先试试这篇好不好使:

vi python_recursion_03.py

import types

def f_recursive(cur_i, cur_computer_result=1):
    if cur_i == 1:
        yield cur_computer_result

    yield f_recursive(cur_i - 1, cur_i + cur_computer_result)

def f_recursive_wapper(generator, i):
    gen = generator(i)
    while isinstance(gen, types.GeneratorType):
        gen = gen.__next__()

    return gen

print(f_recursive_wapper(f_recursive,10000))

执行一下代码,好像确实没问题。

那么能不能将其改造到MindSpore里面去呢。。。

按照 @Chameleon 老师 的提示,“定义一个函数f。然后f进行递归,在construct里去调用这个f”,我们来试试:

import types
import numpy as np
from mindspore import context
from mindspore import Tensor, nn
from mindspore import dtype as ms

zero = Tensor(np.array(0), dtype=ms.int32)
one = Tensor(np.array(1), dtype=ms.int32)
count = Tensor(np.array(10000), dtype=ms.int32)
count0 = 10000

def f_recursive(cur_i, cur_computer_result=one):
    if cur_i == one:
        yield cur_computer_result

    yield f_recursive(cur_i - one, cur_i + cur_computer_result)

def f_recursive_wapper(generator, i):
    gen = generator(i)
    while isinstance(gen, types.GeneratorType):
        gen = gen.__next__()
    return gen

output0 = f_recursive_wapper(f_recursive,count0)
print(output0)

class SingleIfNet(nn.Cell):
    def construct(self,n):
        out = f_recursive_wapper(f_recursive,n)
        return out


forward_net = SingleIfNet()
output = forward_net( count )
print (output)

python python_recursion_04.py

原生的方法输出的output0出来了。

但是mindspore控制流的方式报不支持yield.

也问了老师,说目前MindSpore控制流确实不支持yield语法。

张小白又找到一篇更高大上的做法:

https://zhuanlan.zhihu.com/p/37060182

不过这个改造成mindspore控制流方式估计难度更大。

好了,先不试验了。综上,MindSpore控制流的用法通过递归和非递归的例子,大家应该都能了解了吧。如果大家还有兴趣了解一下控制流是怎么做出来了,可以再听听视频,或者看看MIndSpore的源代码。MindSpore是开源的项目,你想看到的东西应该都能看到,就看你有没有心思去找了。

MindSpore代码仓:https://gitee.com/mindspore/mindspore.git

MindSpore官网:https://mindspore.cn

(全文完,谢谢阅读)

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。