随机数生成函数导致模型速度越来越慢

1 系统环境

硬件环境(Ascend/GPU/CPU): Ascend/GPU/CPU

MindSpore版本: mindspore=2.0.0

执行模式(PyNative/ Graph):不限

Python版本: Python=3.9.13

操作系统平台: 不限

2 报错信息

2.1 问题描述

随机数生成函数导致模型速度越来越慢

2.2 脚本代码(代码格式,可上传附件)

import os
import time
import random
import numpy as np
import mindspore as ms
from mindspore import nn, Tensor, ops

seed = 1
ms.set_seed(seed)
np.random.seed(seed)  # Numpy module.
random.seed(seed)  # Python random module.	

class net(nn.Cell):
    def __init__(self, in_dims=4, out_dims=1):
        super().__init__()
        self.fc1 = nn.Dense(in_dims, 4, has_bias=False)
        self.relu = nn.ReLU()
        self.fc2 = nn.Dense(4, out_dims, has_bias=False)

    def construct(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        rand_tensor = ms.numpy.rand(x.shape)
        return x


class NetWithLoss(nn.Cell):
    def __init__(self, net: nn.Cell):
        super(NetWithLoss, self).__init__()
        self.net = net

    def construct(self, state):
        out = self.net(state)
        return out.mean()

net = net()
optimizer = nn.Adam(net.get_parameters(), 0.001) # 使用0学习率,便于观察梯度
net_with_loss = NetWithLoss(net)
net_train_one_step = nn.TrainOneStepCell(net_with_loss, optimizer)

data = ms.Tensor(
    np.random.normal(loc=0.0, scale=1.0, size=(1,4)),
    dtype=ms.float32)

for i in range(1, 1000):
    t1 = time.time()
    out = net_train_one_step(data)
    t2 = time.time()
    print('%d-iter, time:'%(i), t2-t1)

3 根因分析

在PyNative模式下,存在算子缓存机制——每次执行一个算子,如果算子attr和input维度相同,则复用之前的缓存;否则创建新的缓存。

当前脚本中,每次执行rand_tensor = ms.numpy.rand(x.shape),UniformReal算子的随机数种子会发生变化,因此会生成新的缓存

随着调用次数增加,缓存数量增加,缓存查询操作变慢,导致执行速度变慢

def rand(*shape, dtype=mstype.float32):  
    ...  
    seed = get_seed()  
    if seed is not None:  
        seed1, seed2 = _get_seed(seed, "UniformReal")  
        uniformreal = P.UniformReal(seed=seed1, seed2=seed2)  
    else:  
        uniformreal = P.UniformReal()  
    return uniformreal(size).astype(dtype)

4 解决方案

方案1:使用图模式执行脚本

import os  
import time  
import random  
import numpy as np  
import mindspore as ms  
from mindspore import nn, Tensor, ops, context  
  
# 使用图模式执行  
context.set_context(mode=context.GRAPH_MODE)  
  
seed = 1  
ms.set_seed(seed)  
np.random.seed(seed)  # Numpy module.  
random.seed(seed)  # Python random module.	  
  
class net(nn.Cell):  
    def __init__(self, in_dims=4, out_dims=1):  
        super().__init__()  
        self.fc1 = nn.Dense(in_dims, 4, has_bias=False)  
        self.relu = nn.ReLU()  
        self.fc2 = nn.Dense(4, out_dims, has_bias=False)  
  
    def construct(self, x):  
        x = self.fc1(x)  
        x = self.relu(x)  
        x = self.fc2(x)  
        rand_tensor = ms.numpy.rand(x.shape)  
        return x  
  
  
class NetWithLoss(nn.Cell):  
    def __init__(self, net: nn.Cell):  
        super(NetWithLoss, self).__init__()  
        self.net = net  
  
    def construct(self, state):  
        out = self.net(state)  
        return out.mean()  
  
net = net()  
optimizer = nn.Adam(net.get_parameters(), 0.001) # 使用0学习率,便于观察梯度  
net_with_loss = NetWithLoss(net)  
net_train_one_step = nn.TrainOneStepCell(net_with_loss, optimizer)  
  
data = ms.Tensor(  
    np.random.normal(loc=0.0, scale=1.0, size=(1,4)),  
    dtype=ms.float32)  
  
for i in range(1, 1000):  
    t1 = time.time()  
    out = net_train_one_step(data)  
    t2 = time.time()  
    print('%d-iter, time:'%(i), t2-t1)

方案2:不再随机数种子,避免生成缓存

import os  
import time  
import random  
import numpy as np  
import mindspore as ms  
from mindspore import nn, Tensor, ops  
  
seed = 1  
# 不再设置随机数种子,避免每次执行时,UniformReal算子随机数种子发生变化  
# ms.set_seed(seed)  
np.random.seed(seed)  # Numpy module.  
random.seed(seed)  # Python random module.	  
  
class net(nn.Cell):  
    def __init__(self, in_dims=4, out_dims=1):  
        super().__init__()  
        self.fc1 = nn.Dense(in_dims, 4, has_bias=False)  
        self.relu = nn.ReLU()  
        self.fc2 = nn.Dense(4, out_dims, has_bias=False)  
  
    def construct(self, x):  
        x = self.fc1(x)  
        x = self.relu(x)  
        x = self.fc2(x)  
        rand_tensor = ms.numpy.rand(x.shape)  
        return x  
  
  
class NetWithLoss(nn.Cell):  
    def __init__(self, net: nn.Cell):  
        super(NetWithLoss, self).__init__()  
        self.net = net  
  
    def construct(self, state):  
        out = self.net(state)  
        return out.mean()  
  
net = net()  
optimizer = nn.Adam(net.get_parameters(), 0.001) # 使用0学习率,便于观察梯度  
net_with_loss = NetWithLoss(net)  
net_train_one_step = nn.TrainOneStepCell(net_with_loss, optimizer)  
  
data = ms.Tensor(  
    np.random.normal(loc=0.0, scale=1.0, size=(1,4)),  
    dtype=ms.float32)  
  
for i in range(1, 1000):  
    t1 = time.time()  
    out = net_train_one_step(data)  
    t2 = time.time()  
    print('%d-iter, time:'%(i), t2-t1)