昇思25天学习打卡营第10天|使用静态图加速

🤖 快速入门MindSpore AI:打造你的智能助手

基本介绍 || 快速入门 || 张量 Tensor || 数据集 Dataset || 数据变换 Transforms || 网络构建 || 函数式自动微分 || 模型训练 || 保存与加载 || 使用静态图加速

使用静态图加速

背景介绍

AI编译框架分为两种运行模式,分别是动态图模式以及静态图模式。MindSpore默认情况下是以动态图模式运行,但也支持手工切换为静态图模式。两种运行模式的详细介绍如下:

动态图模式

动态图的特点是计算图的构建和计算同时发生(Define by run),其符合Python的解释执行方式,在计算图中定义一个Tensor时,其值就已经被计算且确定,因此在调试模型时较为方便,能够实时得到中间结果的值,但由于所有节点都需要被保存,导致难以对整个计算图进行优化。

在MindSpore中,动态图模式又被称为PyNative模式。由于动态图的解释执行特性,在脚本开发和网络流程调试过程中,推荐使用动态图模式进行调试。 如需要手动控制框架采用PyNative模式,可以通过以下代码进行网络构建:

import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
import time

start_time = time.perf_counter()  # Start the timer
ms.set_context(mode=ms.PYNATIVE_MODE)  # 使用set_context进行动态图模式的配置

class Network(nn.Cell):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.dense_relu_sequential = nn.SequentialCell(
            nn.Dense(28*28, 512),
            nn.ReLU(),
            nn.Dense(512, 512),
            nn.ReLU(),
            nn.Dense(512, 10)
        )

    def construct(self, x):
        x = self.flatten(x)
        logits = self.dense_relu_sequential(x)
        return logits

model = Network()
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))

output = model(input)
print(output)
end_time = time.perf_counter()  # End the timer
print(f"Execution time: {end_time - start_time} seconds")
[[-0.12582509 -0.02528011 0.02076034 0.00642787 0.12087774 0.00025429 -0.05266126 -0.14020753 -0.02756083 0.18075079]
 [-0.12582509 -0.02528011 0.02076034 0.00642787 0.12087774 0.00025429 -0.05266126 -0.14020753 -0.02756083 0.18075079]
 [-0.12582509 -0.02528011 0.02076034 0.00642787 0.12087774 0.00025429 -0.05266126 -0.14020753 -0.02756083 0.18075079]
...
 [-0.12582509 -0.02528011  0.02076034  0.00642787  0.12087774  0.00025429
  -0.05266126 -0.14020753 -0.02756083  0.18075079]
 [-0.12582509 -0.02528011  0.02076034  0.00642787  0.12087774  0.00025429
  -0.05266126 -0.14020753 -0.02756083  0.18075079]]
Execution time: 35.49768170702737 seconds

静态图模式

相较于动态图而言,静态图的特点是将计算图的构建和实际计算分开(Define and run)。有关静态图模式的运行原理,可以参考静态图语法支持

在MindSpore中,静态图模式又被称为Graph模式,在Graph模式下,基于图优化、计算图整图下沉等技术,编译器可以针对图进行全局的优化,获得较好的性能,因此比较适合网络固定且需要高性能的场景。

如需要手动控制框架采用静态图模式,可以通过以下代码进行网络构建:

import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
import time

start_time = time.perf_counter()  # Start the timer
ms.set_context(mode=ms.GRAPH_MODE)  # 使用set_context进行运行静态图模式的配置

class Network(nn.Cell):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.dense_relu_sequential = nn.SequentialCell(
            nn.Dense(28*28, 512),
            nn.ReLU(),
            nn.Dense(512, 512),
            nn.ReLU(),
            nn.Dense(512, 10)
        )

    def construct(self, x):
        x = self.flatten(x)
        logits = self.dense_relu_sequential(x)
        return logits

model = Network()
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
output = model(input)
print(output)
end_time = time.perf_counter()  # End the timer
print(f"Execution time: {end_time - start_time} seconds")
[[-0.01565331 -0.09293976 0.12911086 0.07712625 -0.1893358 -0.07841216 0.09821182 0.09535077 -0.03845818 0.19483347]
 ...
 [-0.01565331 -0.09293976  0.12911086  0.07712625 -0.1893358  -0.07841216
   0.09821182  0.09535077 -0.03845818  0.19483347]
 [-0.01565331 -0.09293976  0.12911086  0.07712625 -0.1893358  -0.07841216
   0.09821182  0.09535077 -0.03845818  0.19483347]
 [-0.01565331 -0.09293976  0.12911086  0.07712625 -0.1893358  -0.07841216
   0.09821182  0.09535077 -0.03845818  0.19483347]]
Execution time: 9.588730370043777 seconds

静态图模式的使用场景

MindSpore编译器重点面向Tensor数据的计算以及其微分处理。因此使用MindSpore API以及基于Tensor对象的操作更适合使用静态图编译优化。其他操作虽然可以部分入图编译,但实际优化作用有限。另外,静态图模式先编译后执行的模式导致其存在编译耗时。因此,如果函数无需反复执行,那么使用静态图加速也可能没有价值。

有关使用静态图来进行网络编译的示例,请参考网络构建

静态图模式开启方式

通常情况下,由于动态图的灵活性,我们会选择使用PyNative模式来进行自由的神经网络构建,以实现模型的创新和优化。但是当需要进行性能加速时,我们需要对神经网络部分或整体进行加速。MindSpore提供了两种切换为图模式的方式,分别是基于装饰器的开启方式以及基于全局context的开启方式。

基于装饰器的开启方式

MindSpore提供了jit装饰器,可以通过修饰Python函数或者Python类的成员函数使其被编译成计算图,通过图优化等技术提高运行速度。此时我们可以简单的对想要进行性能优化的模块进行图编译加速,而模型其他部分,仍旧使用解释执行方式,不丢失动态图的灵活性。无论全局context是设置成静态图模式还是动态图模式,被jit修饰的部分始终会以静态图模式进行运行。

在需要对Tensor的某些运算进行编译加速时,可以在其定义的函数上使用jit修饰器,在调用该函数时,该模块自动被编译为静态图。需要注意的是,jit装饰器只能用来修饰函数,无法对类进行修饰。jit的使用示例如下:

import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
import time

start_time = time.perf_counter()  # Start the timer

class Network(nn.Cell):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.dense_relu_sequential = nn.SequentialCell(
            nn.Dense(28*28, 512),
            nn.ReLU(),
            nn.Dense(512, 512),
            nn.ReLU(),
            nn.Dense(512, 10)
        )

    def construct(self, x):
        x = self.flatten(x)
        logits = self.dense_relu_sequential(x)
        return logits

input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))

@ms.jit  # 使用ms.jit装饰器,使被装饰的函数以静态图模式运行
def run(x):
    model = Network()
    return model(x)

output = run(input)
print(output)
end_time = time.perf_counter()  # End the timer
print(f"Execution time: {end_time - start_time} seconds")
[[-0.0215508 0.0480678 -0.1456141 -0.00648155 -0.0305744 0.11991286 0.04875539 -0.05334447 0.0460235 0.05557922]
 ...
 [-0.0215508   0.0480678  -0.1456141  -0.00648155 -0.0305744   0.11991286
   0.04875539 -0.05334447  0.0460235   0.05557922]
 [-0.0215508   0.0480678  -0.1456141  -0.00648155 -0.0305744   0.11991286
   0.04875539 -0.05334447  0.0460235   0.05557922]
 [-0.0215508   0.0480678  -0.1456141  -0.00648155 -0.0305744   0.11991286
   0.04875539 -0.05334447  0.0460235   0.05557922]]
Execution time: 0.35316483105998486 seconds

除使用修饰器外,也可使用函数变换方式调用jit方法,示例如下:

import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
import time
start_time = time.perf_counter()  # Start the timer

class Network(nn.Cell):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.dense_relu_sequential = nn.SequentialCell(
            nn.Dense(28*28, 512),
            nn.ReLU(),
            nn.Dense(512, 512),
            nn.ReLU(),
            nn.Dense(512, 10)
        )

    def construct(self, x):
        x = self.flatten(x)
        logits = self.dense_relu_sequential(x)
        return logits

input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))

def run(x):
    model = Network()
    return model(x)

run_with_jit = ms.jit(run)  # 通过调用jit将函数转换为以静态图方式执行
output = run(input)
print(output)
end_time = time.perf_counter()  # End the timer
print(f"Execution time: {end_time - start_time} seconds")
[[ 0.08840896 -0.05487474 -0.08385627 -0.02559738 -0.02337795 -0.08055373 0.15511397 0.14375673 0.10823809 0.12579829] 
...
 [ 0.08840896 -0.05487474 -0.08385627 -0.02559738 -0.02337795 -0.08055373 0.15511397 0.14375673 0.10823809 0.12579829] 
 [ 0.08840896 -0.05487474 -0.08385627 -0.02559738 -0.02337795 -0.08055373 0.15511397 0.14375673 0.10823809 0.12579829] 
 [ 0.08840896 -0.05487474 -0.08385627 -0.02559738 -0.02337795 -0.08055373 0.15511397 0.14375673 0.10823809 0.12579829]] 
Execution time: 0.3577021040255204 seconds

当我们需要对神经网络的某部分进行加速时,可以直接在construct方法上使用jit修饰器,在调用实例化对象时,该模块自动被编译为静态图。示例如下:

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

class Network(nn.Cell):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.dense_relu_sequential = nn.SequentialCell(
            nn.Dense(28*28, 512),
            nn.ReLU(),
            nn.Dense(512, 512),
            nn.ReLU(),
            nn.Dense(512, 10)
        )

    @ms.jit  # 使用ms.jit装饰器,使被装饰的函数以静态图模式运行
    def construct(self, x):
        x = self.flatten(x)
        logits = self.dense_relu_sequential(x)
        return logits

input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
model = Network()
output = model(input)
print(output)
[[-0.09758487 0.03458018 0.17996584 -0.08039548 0.0494537 -0.06383591 0.04748532 0.24746855 -0.00543941 0.09128448] 
... 
 [-0.09758487 0.03458018 0.17996584 -0.08039548 0.0494537 -0.06383591 0.04748532 0.24746855 -0.00543941 0.09128448] 
 [-0.09758487 0.03458018 0.17996584 -0.08039548 0.0494537 -0.06383591 0.04748532 0.24746855 -0.00543941 0.09128448] 
 [-0.09758487 0.03458018 0.17996584 -0.08039548 0.0494537 -0.06383591 0.04748532 0.24746855 -0.00543941 0.09128448]] 
Execution time: 0.3762788278982043 seconds

基于context的开启方式

context模式是一种全局的设置模式。代码示例如下:

import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
import time
start_time = time.perf_counter()  # Start the timer

class Network(nn.Cell):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.dense_relu_sequential = nn.SequentialCell(
            nn.Dense(28*28, 512),
            nn.ReLU(),
            nn.Dense(512, 512),
            nn.ReLU(),
            nn.Dense(512, 10)
        )

    @ms.jit  # 使用ms.jit装饰器,使被装饰的函数以静态图模式运行
    def construct(self, x):
        x = self.flatten(x)
        logits = self.dense_relu_sequential(x)
        return logits

input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
model = Network()
output = model(input)
print(output)
end_time = time.perf_counter()  # End the timer
print(f"Execution time: {end_time - start_time} seconds")
[[ 0.0494143   0.04243974  0.10025572  0.10711633 -0.17206469  0.00441954
  -0.03176421  0.2095941   0.07757366 -0.05434227]
...
 [ 0.0494143   0.04243974  0.10025572  0.10711633 -0.17206469  0.00441954
  -0.03176421  0.2095941   0.07757366 -0.05434227]
 [ 0.0494143   0.04243974  0.10025572  0.10711633 -0.17206469  0.00441954
  -0.03176421  0.2095941   0.07757366 -0.05434227]
 [ 0.0494143   0.04243974  0.10025572  0.10711633 -0.17206469  0.00441954
  -0.03176421  0.2095941   0.07757366 -0.05434227]]
Execution time: 0.36335599492304027 seconds

静态图的语法约束

在Graph模式下,Python代码并不是由Python解释器去执行,而是将代码编译成静态计算图,然后执行静态计算图。因此,编译器无法支持全量的Python语法。MindSpore的静态图编译器维护了Python常用语法子集,以支持神经网络的构建及训练。详情可参考静态图语法支持

JitConfig配置选项

在图模式下,可以通过使用JitConfig配置选项来一定程度的自定义编译流程,目前JitConfig支持的配置参数如下:

  • jit_level: 用于控制优化等级。

  • exec_mode: 用于控制模型执行方式。

  • jit_syntax_level: 设置静态图语法支持级别,详细介绍请见静态图语法支持

静态图高级编程技巧

使用静态图高级编程技巧可以有效地提高编译效率以及执行效率,并可以使程序运行的更加稳定。详情可参考静态图高级编程技巧

总结:

动态图模式或静态图模式时,可以考虑以下几个因素:

  • 动态图模式

    • 当需要在运行时灵活调整计算流程或者在不同的数据输入下进行优化时,动态图模式是一个好选择。
    • 如果模型结构可能会发生变化,或者需要根据实时数据进行调整,动态图模式提供了更多的灵活性。
    • 对于初期开发阶段,或者对模型结构有不确定性的情况下,动态图模式也是一个合适的选择。
  • 静态图模式

    • 当模型结构已经确定且不会发生变化时,静态图模式可以提供更好的性能优化。
    • 如果模型需要在多个设备上部署,并且需要最小化运行时间,静态图模式是一个更好的选择。
    • 对于需要重复执行相同计算流程的场景,如在大规模数据处理中,静态图模式可以显著提高效率。

总的来说,如果需要更多的灵活性和调整能力,动态图模式是更好的选择。如果您的模型已经稳定且性能优化是主要关注点,那么静态图模式将是更合适的选择。在实际应用中,您可能还需要根据具体需求和场景来做出最终决定。

 

模式Execution time(秒)
1动态图模式 PYNATIVE_MODE35.49768170702737 
2静态图模式 GRAPH_MODE9.588730370043777
3ms,jit 使被装饰的函数以静态图模式运行0.35316483105998486 
4调用jit将函数转换为以静态图方式执行0.3577021040255204 
5construct 使被装饰的函数以静态图模式运行0.3762788278982043
6使用set_context进行运行静态图模式的配置0.36335599492304027 

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是一个简单的微信小程序制作学习计划打卡记录页面的代码。 在 wxml 文件中,我们可以设置页面的布局和样式,以及与用户进行交互的组件,例如按钮、输入框等。 ```html <view class="container"> <view class="header"> <text class="title">学习计划打卡记录</text> </view> <view class="card"> <view class="card-heading"> <text class="card-title">Day 1</text> <text class="card-date">2021-01-01</text> </view> <view class="card-body"> <text class="card-label">学习时间:</text> <input class="card-input" type="number" placeholder="请输入学习时间(单位:小时)" /> </view> <view class="card-footer"> <button class="card-button">提交</button> </view> </view> <!-- Day 2、Day 3 等的卡片同上 --> </view> ``` 在 wxss 文件中,我们可以设置页面的样式,例如字体、颜色、边距等。 ```css .container { padding: 20rpx; } .header { text-align: center; margin-bottom: 20rpx; } .title { font-size: 36rpx; font-weight: bold; color: #333333; } .card { background-color: #ffffff; border-radius: 10rpx; box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1); margin-bottom: 20rpx; } .card-heading { display: flex; justify-content: space-between; align-items: center; padding: 20rpx; border-bottom: 1rpx solid #f2f2f2; } .card-title { font-size: 28rpx; font-weight: bold; color: #333333; } .card-date { font-size: 24rpx; color: #999999; } .card-body { display: flex; align-items: center; padding: 20rpx; } .card-label { font-size: 28rpx; color: #333333; } .card-input { flex: 1; margin-left: 20rpx; font-size: 28rpx; color: #999999; border: none; } .card-footer { text-align: center; padding: 20rpx; } .card-button { font-size: 28rpx; color: #ffffff; background-color: #007aff; border-radius: 5rpx; padding: 10rpx 20rpx; } ``` 在 js 文件中,我们可以编写页面的逻辑代码。 ```javascript Page({ data: { days: [ { title: 'Day 1', date: '2021-01-01', time: null }, { title: 'Day 2', date: '2021-01-02', time: null }, { title: 'Day 3', date: '2021-01-03', time: null } // Day 4、Day 5 等的数据同上 ] }, handleInput: function(event) { // 获取输入框的值 let index = event.currentTarget.dataset.index; let value = event.detail.value; // 更新数据 let days = this.data.days; days[index].time = value; this.setData({ days: days }); }, handleSubmit: function(event) { // 获取提交按钮的索引 let index = event.currentTarget.dataset.index; // 获取对应的数据 let days = this.data.days; let day = days[index]; // 判断是否填写了学习时间 if (day.time === null || day.time === '') { wx.showToast({ title: '请填写学习时间', icon: 'none' }); return; } // 提交数据 wx.cloud.callFunction({ name: 'submit', data: { date: day.date, time: day.time }, success: res => { wx.showToast({ title: '提交成功' }); }, fail: err => { wx.showToast({ title: '提交失败', icon: 'none' }); } }); } }) ``` 以上代码是一个简单的微信小程序制作学习计划打卡记录页面的示例,仅供参考。具体实现方式可能因个人需求而异。 ### 回答2: 微信小程序制作学习计划打卡记录页面包含前几学习时间的全部代码如下: 首先,在小程序中创建一个page,命名为"studyRecord",在studyRecord.json文件中进行配置,设置"navigationBarTitleText"为"学习打卡",并设置"usingComponents"引入相关组件: ``` { "navigationBarTitleText": "学习打卡", "usingComponents": {} } ``` 接下来,在studyRecord.wxml文件中编写页面结构,包括一个日期选择器和一个列表用于展示打卡记录: ``` <view class="container"> <view class="header"> <picker mode="date" bindchange="dateChange"> <view class="date-picker">{{ currentDate }}</view> </picker> </view> <view class="record-list"> <block wx:for="{{ studyRecords }}" wx:key="index"> <view class="record-item"> <view class="item-date">{{ item.date }}</view> <view class="item-duration">{{ item.duration }}</view> </view> </block> </view> </view> ``` 我们在studyRecord.js文件中定义相关的事件处理函数和数据: ``` Page({ data: { currentDate: '', // 当前选择的日期 studyRecords: [] // 学习打卡记录 }, onLoad: function () { // 获取最近几学习打卡记录 this.getStudyRecords(); }, dateChange: function (event) { this.setData({ currentDate: event.detail.value }); // 根据选择日期的变化更新学习打卡记录 this.getStudyRecords(); }, getStudyRecords: function () { // 根据当前日期获取学习打卡记录,假设获取到的数据格式为[{ date: '2022/01/01', duration: '2小时' }, ...] // 可以通过调用接口或其他方式获取数据 const currentDate = this.data.currentDate; const studyRecords = this.getStudyRecordsByDate(currentDate); this.setData({ studyRecords: studyRecords }); }, getStudyRecordsByDate: function (date) { // 根据日期获取学习打卡记录的逻辑实现 // ... return studyRecords; // 返回按日期查询到的学习打卡记录 } }) ``` 在studyRecord.wxss文件中定义样式: ``` .container { padding: 10px; } .header { margin-bottom: 10px; } .date-picker { font-size: 18px; color: #333; padding: 10px; background-color: #f5f5f5; border-radius: 4px; text-align: center; } .record-list { background-color: #fff; border-radius: 4px; } .record-item { padding: 10px; border-bottom: solid 1px #eee; } .item-date { font-size: 14px; color: #666; } .item-duration { font-size: 16px; color: #333; } ``` 这样,一个包含前几学习时间的微信小程序制作学习计划打卡记录页面的代码就完成了。 ### 回答3: 要制作微信小程序的学习计划打卡记录页面,可以按照以下步骤进行: 1. 首先,需要在微信开发者工具中创建一个新的小程序项目,并在app.json文件中配置页面路由信息。 2. 在项目的根目录下创建一个新的文件夹,用于存放页面相关的文件,比如study-record文件夹。 3. 在study-record文件夹中创建一个study-record.wxml文件用于编写页面的结构。 4. 在study-record文件夹中创建一个study-record.wxss文件用于编写页面的样式。 5. 在study-record文件夹中创建一个study-record.js文件用于编写页面的逻辑代码。 6. 在study-record.js中定义一个数据对象,用于存储前几学习时间。可以使用数组来存储每一学习时间,比如每个元素都是一个包含日期和学习时间的对象。 7. 在study-record.js中编写一个函数来获取前几学习时间。可以使用Date对象和相关的方法来计算前几的日期,然后根据日期从数据对象中获取对应的学习时间。 8. 在study-record.js中编写一个函数来更新学习时间。可以通过用户输入的方式来更新某一学习时间,并将更新后的数据保存到数据对象中。 9. 在study-record.wxml中使用wx:for循环来遍历数据对象中的学习时间,并将日期和学习时间显示在页面上。 10. 在study-record.wxml中添加一个按钮,用于触发更新学习时间的函数。 11. 在study-record.js中监听按钮的点击事件,并在点击时触发更新学习时间的函数。 12. 在study-record.wxss中设置页面的样式,比如学习时间的字体大小、颜色等。 通过以上步骤,就可以完成微信小程序的学习计划打卡记录页面的制作。在页面中包含了前几学习时间,并提供了更新学习时间的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值