Повышение эффективности вычислений с использованием двоичного файла - PullRequest
0 голосов
/ 29 января 2020

Я решаю N связанных дифференциальных уравнений (u1 (t), v1 (t), u2 (t), v2 (t), ...) итеративно. У меня есть кольцо из N осцилляторов, и каждый осциллятор связан с P соседями. Я пытаюсь повысить эффективность, не сохраняя все свои шаги итерации в списках, а вместо этого экспортируя мои результаты для каждого десятого временного шага в двоичный файл, который я позже импортирую, чтобы я мог отобразить результаты с течением времени. Ниже приведен мой старый код, где я не использовал двоичный файл. Результаты хорошие, но неэффективные:

import numpy as np
import matplotlib.pyplot as plt

dt = 0.001
ts = np.arange(0, 30, dt)
N, P = 4, 2 

u = np.array([np.zeros(len(ts)) for i in range(N)]) 
v = np.array([np.zeros(len(ts)) for i in range(N)])

def a_u(j,t,P,u,v):
    del_li = []
    for k in range(j-P,j+P):
        del_li.append(u[k][t-1] - u[j][t-1])
    return (u[j][t-1] - ((u[j][t-1])**3)/3 - v[j][t-1] + (1/(4*P))*sum(del_li)) 

for t in range(len(ts)):
    for j in range(-P,P):  

        u[j][t] = u[j][t-1] + a_u(j,t,P,u,v)*dt
        v[j][t] = v[j][t-1] + (u[j][t-1] + 1.05)*dt + np.random.normal(scale=np.sqrt(dt))  

Моя попытка ускорить приведенный выше код с помощью двоичного файла выглядит следующим образом:

u, v = np.array(np.zeros(N)), np.array(np.zeros(N))   

def a_u(j,t,P,u,v):
    del_li = []
    for k in range(j-P,j+P):
        del_li.append(u[k] - u[j])
    return (u[j] - ((u[j])**3)/3 - v[j] + (1/(4*P))*sum(del_li)) 

with open('oscillators.bin', 'wb') as f: # write binary file
    for t in range(len(ts)):
        osc_list = []

        for j in range(-P,P): 

            u[j] += a_u(j,t,P,u,v)*dt  
            v[j] += (u[j] + 1.05)*dt + np.random.normal(scale=np.sqrt(dt))

            if not t % 10:  

                osc_list.append(u[j])
                osc_list.append(v[j])

                if j==P:
                    np.save(f, osc_list) 

fp = open("oscillators.bin", 'rb') # read binary file

a = []
for i in range(int(len(ts)/10)): 
    a.append(np.load(fp))

A = np.array(a) # u[1], v[1], ... = A[:,0], A[:,1], ...

Принимаю ли я правильные меры для повысить эффективность моего кода? Мой реальный код намного сложнее, и параметры, которые я использую, намного больше, поэтому важна эффективность.

1 Ответ

1 голос
/ 29 января 2020

Во втором вычислении в первой строке вы размещаете массивы u и v в одной и той же ячейке памяти. То есть, когда вы назначаете u[j] и v[j], вы назначаете одно и то же место, перезаписывая предыдущий контент. Это приведет к совершенно другим вычислениям.

Использование циклов так, как вы делаете, будет эффективным только в том случае, если вы компилируете код с помощью Cython или аналогичного, где обычные издержки языка type-ambiguous python уменьшаются и вы получаете преимущество, избегая выделения и сборки мусора массивов u,v на каждом этапе. Иначе numpy механизм векторизованных операций

u,v = u - (u**3)/3 - v)*dt, (u + 1.05)*dt + np.random.normal(scale=np.sqrt(dt), size=len(v))

быстрее. Но, тем не менее, эта форма не представляет никакой связи с соседними узлами.

...