【MindSpore第六期两日集训营】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
(全文完,谢谢阅读)
- 点赞
- 收藏
- 关注作者
评论(0)