标题:【求助】提高numpy执行效率的问题
只看楼主
xiangyue0510
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:86
帖 子:934
专家分:5244
注 册:2015-8-10
结帖率:100%
已结贴  问题点数:20 回复次数:6 
【求助】提高numpy执行效率的问题
这段代码是为了实现ANSYS后处理实现规范校核,需要从文本中读出各基础工况的应力结果,按照一定的规则组合,然后再取最不利的,也就是最大。
但是我写完这段代码的时候发现执行效率不高,1000个单元的数据处理(代码中用的是随机生成的数据进行测试,未写读取数据的代码)需要一个小时,但是我的模型有20万个单元
可能是我的代码写的不够高,请教各位大神如何进行优化

程序代码:
import numpy as np
import datetime

log=open("Out.txt",mode='w',encoding='utf-8')
t1=datetime.datetime.now()
print("*************   Printout: Start Time *********",file=log)
print(t1,file=log)
# 创建测试用的矩阵, 6个维度分别为σx,σy,σz,σxy,σyz,σxz  =====> 实际代码中从文本中读取
n=150  # 单元数量204375
lc_n= 40    # 组合工况数量40
sxs=[np.random.random((n,6)) for i  in range(13)]  # 13个基础工况

# 创建2个零矩阵,用于存放最大值和最小值   所有工况
all_maxS=np.zeros((n,6))
all_minS=np.zeros((n,6))
# 创建1个零矩阵,用于存放等效应力
all_EqvS=np.zeros((n,1))

for lc_i in range(1,lc_n):   #组合工况迭代
    # 创建零矩阵,用于存放最大值和最小值
    lc_maxS = np.zeros((n, 6))
    lc_minS = np.zeros((n, 6))
    # 创建1个零矩阵,用于存放等效应力
    lc_EqvS = np.zeros((n, 1))
    for i in range(1,180):    #波峰相位角迭代
        for j in range(1,180):     #倾斜方位角迭代
            LF = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]    #工况组合系数,测试使用。     =====> 实际数据中从文本中读取, 最后几项需要根据波峰相位角、倾斜方位角计算得到
            combined_S=np.zeros((n,6))
            for k in range(1,13):        # 基础工况迭代
                combined_S = combined_S+LF[k]*sxs[k]        # 组合好的应力分量

            lc_maxS = np.maximum(lc_maxS, combined_S)   #直接用矩阵计算得到同一工况下,不同波峰相位角、倾斜方位角的最大值
            lc_minS = np.minimum(lc_minS, combined_S)   #直接用矩阵计算得到同一工况下,不同波峰相位角、倾斜方位角的最小值
            EqvS=(((combined_S[:,0]-combined_S[:,1])**2 + (combined_S[:,1]-combined_S[:,2])**2 + (combined_S[:,2]-combined_S[:,0])**2 + 6*(combined_S[:,3]**2 +combined_S[:,4]**2+combined_S[:,5]**2))/2)**0.5
            lc_EqvS=np.maximum(lc_EqvS,EqvS)     #直接用矩阵计算得到同一工况下,不同波峰相位角、倾斜方位角的最大等效应力

    #**********************   增加将 lc_maxS、lc_minS 输出到文本的代码  ************************
    all_maxS = np.maximum(lc_maxS, all_maxS)   #直接用矩阵计算得到所有工况的最大值
    all_minS = np.minimum(lc_minS, all_minS)   #直接用矩阵计算得到所有工况的最小值
    all_EqvS = np.maximum(lc_EqvS, all_EqvS)   #直接用矩阵计算得到所有工况的最大等效应力


# **********************   增加将 all_maxS、all_minS 输出到文本的代码  ************************
t2=datetime.datetime.now()
print("*************   Printout: End Time *********",file=log)
print(t2,file=log)
print("*************  Time Consumed: seconds *********")
print((t2-t1).seconds,file=log)
log.close


[此贴子已经被作者于2022-6-20 08:26编辑过]

搜索更多相关主题的帖子: datetime print 计算 代码 矩阵 
2022-06-20 08:24
xiangyue0510
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:86
帖 子:934
专家分:5244
注 册:2015-8-10
得分:0 
补充一下,运行的过程中CPU占有率只有不到20%,内存15%(96G),显然没有发挥应有的资源优势
2022-06-20 10:34
fall_bernana
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:贵宾
威 望:17
帖 子:240
专家分:2086
注 册:2019-8-16
得分:20 
以下是引用xiangyue0510在2022-6-20 08:24:13的发言:

这段代码是为了实现ANSYS后处理实现规范校核,需要从文本中读出各基础工况的应力结果,按照一定的规则组合,然后再取最不利的,也就是最大。
但是我写完这段代码的时候发现执行效率不高,1000个单元的数据处理(代码中用的是随机生成的数据进行测试,未写读取数据的代码)需要一个小时,但是我的模型有20万个单元
可能是我的代码写的不够高,请教各位大神如何进行优化


import numpy as np
import datetime

log=open("Out.txt",mode='w',encoding='utf-8')
t1=datetime.datetime.now()
print("*************   Printout: Start Time *********",file=log)
print(t1,file=log)
# 创建测试用的矩阵, 6个维度分别为σx,σy,σz,σxy,σyz,σxz  =====> 实际代码中从文本中读取
n=150  # 单元数量204375
lc_n= 40    # 组合工况数量40
sxs=[np.random.random((n,6)) for i  in range(13)]  # 13个基础工况

# 创建2个零矩阵,用于存放最大值和最小值   所有工况
all_maxS=np.zeros((n,6))
all_minS=np.zeros((n,6))
# 创建1个零矩阵,用于存放等效应力
all_EqvS=np.zeros((n,1))

for lc_i in range(1,lc_n):   #组合工况迭代
    # 创建零矩阵,用于存放最大值和最小值
    lc_maxS = np.zeros((n, 6))
    lc_minS = np.zeros((n, 6))
    # 创建1个零矩阵,用于存放等效应力
    lc_EqvS = np.zeros((n, 1))
    for i in range(1,180):    #波峰相位角迭代
        for j in range(1,180):     #倾斜方位角迭代
            LF = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]    #工况组合系数,测试使用。     =====> 实际数据中从文本中读取, 最后几项需要根据波峰相位角、倾斜方位角计算得到
            combined_S=np.zeros((n,6))
            for k in range(1,13):        # 基础工况迭代
                combined_S = combined_S+LF[k]*sxs[k]        # 组合好的应力分量

            lc_maxS = np.maximum(lc_maxS, combined_S)   #直接用矩阵计算得到同一工况下,不同波峰相位角、倾斜方位角的最大值
            lc_minS = np.minimum(lc_minS, combined_S)   #直接用矩阵计算得到同一工况下,不同波峰相位角、倾斜方位角的最小值
            EqvS=(((combined_S[:,0]-combined_S[:,1])**2 + (combined_S[:,1]-combined_S[:,2])**2 + (combined_S[:,2]-combined_S[:,0])**2 + 6*(combined_S[:,3]**2 +combined_S[:,4]**2+combined_S[:,5]**2))/2)**0.5
            lc_EqvS=np.maximum(lc_EqvS,EqvS)     #直接用矩阵计算得到同一工况下,不同波峰相位角、倾斜方位角的最大等效应力

    #**********************   增加将 lc_maxS、lc_minS 输出到文本的代码  ************************
    all_maxS = np.maximum(lc_maxS, all_maxS)   #直接用矩阵计算得到所有工况的最大值
    all_minS = np.minimum(lc_minS, all_minS)   #直接用矩阵计算得到所有工况的最小值
    all_EqvS = np.maximum(lc_EqvS, all_EqvS)   #直接用矩阵计算得到所有工况的最大等效应力


# **********************   增加将 all_maxS、all_minS 输出到文本的代码  ************************
t2=datetime.datetime.now()
print("*************   Printout: End Time *********",file=log)
print(t2,file=log)
print("*************  Time Consumed: seconds *********")
print((t2-t1).seconds,file=log)
log.close


不太懂你想做什么,所以尽供参考:
对于 for lc_i 循环:  lc_maxS  lc_minS  lc_EqvS combined_S  LF 都是重新初始化,那么循环这么多次有什么意义?

对于 for j 循环:
LF = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]    #工况组合系数,测试使用。     =====> 实际数据中从文本中读取, 最后几项需要根据波峰相位角、倾斜方位角计算得到
combined_S=np.zeros((n,6))
for k in range(1,13):        # 基础工况迭代
    combined_S = combined_S+LF[k]*sxs[k]        # 组合好的应力分量
这个每次都初始化,结果都一样,你为啥不拿到循环外面去?
总体看就是不停的重复计算。
2022-06-21 11:27
xiangyue0510
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:86
帖 子:934
专家分:5244
注 册:2015-8-10
得分:0 
以下是引用fall_bernana在2022-6-21 11:27:10的发言:



不太懂你想做什么,所以尽供参考:
对于 for lc_i 循环:  lc_maxS  lc_minS  lc_EqvS combined_S  LF 都是重新初始化,那么循环这么多次有什么意义?

对于 for j 循环:
LF = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]    #工况组合系数,测试使用。     =====> 实际数据中从文本中读取, 最后几项需要根据波峰相位角、倾斜方位角计算得到
combined_S=np.zeros((n,6))
for k in range(1,13):        # 基础工况迭代
    combined_S = combined_S+LF[k]*sxs[k]        # 组合好的应力分量
这个每次都初始化,结果都一样,你为啥不拿到循环外面去?
总体看就是不停的重复计算。

确实不停的重复循环,但是没有循坏是多余的,你看到很多是重复的,那是因为我很多的数据都是测试用的,没有用实际数据来做
第一层循环是40个组合工况的循环
for lc_i in range(1,lc_n):   #组合工况迭代,

第二、三层循环是对波峰相位角和倾斜方位角进行迭代。
    for i in range(1,180):    #波峰相位角迭代
        for j in range(1,180):     #倾斜方位角迭代
  
其实是为了计算工况组合系数,也即是
LF = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] 

我不过这里没有完成代码,实际每一次都是不一样的。直接用一个确定的list来替代了而已,先看效果和速度

第四层循环就是对某一个组合工况,将基础工况组合起来。
 for k in range(1,13):


你说的combined_S是某一个组合工况下的组合之后的应力,其初始化可以提2级到lc_i循环下,我测试了一下,速度基本没有影响
要再放外面去,那就是不是13个基础工况自己的组合了,是40个组合工况的13个基础工况全组合到一起了

[此贴子已经被作者于2022-6-21 15:41编辑过]

2022-06-21 15:29
xiangyue0510
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:86
帖 子:934
专家分:5244
注 册:2015-8-10
得分:0 
这个是最新的代码,中间用到了一个numba确实是有加速的效果,n数量不大的情况下可以缩短约50%,但是n变大之后效果就不明显了
combined_S = np.zeros((n, 6))提了到i、j循环之外的速度从21.3变成20.8,(n=100),影响不大。
程序代码:
import numpy as np
import time
import math
n = 100  # 单元数量204375
start = time.time()
import numba as nb
@nb.jit(nopython=True,fastmath=True)   # 使用jit装饰器加速
# @nb.njit(parallel=True, fastmath=True)
def Checkit(n):

    lc_n = 40  # 组合工况数量40
    sxs = [np.random.random((n, 6)) for i in range(13)]  # 13个基础工况

    # 创建2个零矩阵,用于存放最大值和最小值   所有工况
    all_maxS = np.zeros((n, 6))
    all_minS = np.zeros((n, 6))
    # 创建1个零矩阵,用于存放等效应力
    all_EqvS = np.zeros((n, 1))
    combined_S = np.zeros((n, 6))

    for lc_i in range(1, lc_n):  # 组合工况迭代
        # 创建零矩阵,用于存放最大值和最小值
        lc_maxS = np.zeros((n, 6))
        lc_minS = np.zeros((n, 6))

        # 创建1个零矩阵,用于存放等效应力
        lc_EqvS = np.zeros((n, 1))
        for i in range(1, 180):  # 波峰相位角迭代
            for j in range(1, 180):  # 倾斜方位角迭代
                LF = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
                      13]  # 工况组合系数,测试使用。     =====> 实际数据中从文本中读取, 最后几项需要根据波峰相位角、倾斜方位角计算得到


                for k in range(1, 13):  # 基础工况迭代
                    combined_S = combined_S + LF[k] * sxs[k]  # 组合好的应力分量

                lc_maxS = np.maximum(lc_maxS, combined_S)  # 直接用矩阵计算得到同一工况下,不同波峰相位角、倾斜方位角的最大值
                lc_minS = np.minimum(lc_minS, combined_S)  # 直接用矩阵计算得到同一工况下,不同波峰相位角、倾斜方位角的最小值
                EqvS = (((combined_S[:, 0] - combined_S[:, 1]) ** 2 + (combined_S[:, 1] - combined_S[:, 2]) ** 2 + (
                            combined_S[:, 2] - combined_S[:, 0]) ** 2 + 6 * (
                                     combined_S[:, 3] ** 2 + combined_S[:, 4] ** 2 + combined_S[:, 5] ** 2)) / 2) ** 0.5
                lc_EqvS = np.maximum(lc_EqvS, EqvS)  # 直接用矩阵计算得到同一工况下,不同波峰相位角、倾斜方位角的最大等效应力

        # **********************   增加将 lc_maxS、lc_minS 输出到文本的代码  ************************
        all_maxS = np.maximum(lc_maxS, all_maxS)  # 直接用矩阵计算得到所有工况的最大值
        all_minS = np.minimum(lc_minS, all_minS)  # 直接用矩阵计算得到所有工况的最小值
        all_EqvS = np.maximum(lc_EqvS, all_EqvS)  # 直接用矩阵计算得到所有工况的最大等效应力

Checkit(n)
end = time.time()
run_time = end-start
print('Average time={}'.format(run_time))


[此贴子已经被作者于2022-6-21 16:02编辑过]

2022-06-21 15:55
fall_bernana
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:贵宾
威 望:17
帖 子:240
专家分:2086
注 册:2019-8-16
得分:0 
回复 5楼 xiangyue0510
程序代码:
from line_profiler import LineProfiler
    
lp = LineProfiler()
lp_wrapper = lp(Checkit)
lp_wrapper()
lp.print_stats()

你可以通过这个来判断每行使用的时间,看看能怎么优化
2022-06-21 17:43
xiangyue0510
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:86
帖 子:934
专家分:5244
注 册:2015-8-10
得分:0 
以下是引用fall_bernana在2022-6-21 17:43:11的发言:


from line_profiler import LineProfiler
   
lp = LineProfiler()
lp_wrapper = lp(Checkit)
lp_wrapper()
lp.print_stats()

你可以通过这个来判断每行使用的时间,看看能怎么优化

明天我来试试
2022-06-21 22:19



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-509386-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.061376 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved