如何将 numba 用于以下代码?
How do I use numba for the following code?
我第一次尝试在 colab 中使用 Numba,我认为我已经成功安装了 Numba,因为 @jit 现在不是未定义的,但我的代码中出现错误。以下是我的尝试:
!apt-get install nvidia-cuda-toolkit
!pip3 install numba
import os
dev_lib_path = !find / -iname 'libdevice'
nvvm_lib_path = !find / -iname 'libnvvm.so'
assert len(dev_lib_path)>0, "Device Lib Missing"
assert len(nvvm_lib_path)>0, "NVVM Missing"
os.environ['NUMBAPRO_LIBDEVICE'] = dev_lib_path[0]
os.environ['NUMBAPRO_NVVM'] = nvvm_lib_path[0]
import numpy as np
import matplotlib.pyplot as plt
import random
from math import *
from random import *
from numba import jit
n=1000
mu=np.random.uniform(0,1,n)
r=[sqrt(-2*log(1-i)) for i in mu]
eta=np.random.uniform(0,1,n)
theta=2*pi*eta;
cuz=[cos(i) for i in theta]
suz=[sin(i) for i in theta]
Zinitial=[a*b for a,b in zip(r,cuz)];
Pinitial=[a*b for a,b in zip(r,suz)];
class Particle:
def __init__(self, pos, mom, spin):
self.pos = pos
self.mom = mom
self.spin = spin
SP = sorted(np.array([Particle(pos = i, mom = j, spin = choice([1, 0])) for i,j in zip(Zinitial,Pinitial)]),key=lambda x:x.pos)
Upi=[];
Downi=[];
count_plot=[];
for j in range(len(SP)):
if SP[j].spin == 1:
Upi.append(SP[j].pos)
else:
Downi.append(SP[j].pos)
Zavgi=sum(Zinitial)/len(Zinitial)
Zreli=sum(Upi)/len(Upi)-sum(Downi)/len(Downi)
"Observables"
"Time"
iter=10**(5);
dt=1/(2*n);
alf=sqrt(n);
"Dynamics"
@jit(nopython=True)
def f():
counter=0;
sum1,sum2=0,0;
Zavg=[Zavgi];
Zrelm=[Zreli];
T_plot=[0];
for i in range(1,iter+1):
t=i*dt;
T_plot.append(t)
Z=[];
Up=[];
Down=[];
c,s=cos(t),sin(t);
c1,s1=cos(t-dt),sin(t-dt);
for j in range(n-1):
collchk=((c*(SP[j].pos)+s*(SP[j].mom))-(c*(SP[j+1].pos)+s*(SP[j+1].mom)))*(c1*(SP[j].pos)+s1*(SP[j].mom)-(c1*(SP[j+1].pos)+s1*(SP[j+1].mom)));
prel=((c*(SP[j].mom)-s*(SP[j].pos))-(c*(SP[j+1].mom)-s*(SP[j+1].pos)))/2;
rcoeff=1/(1+(prel*alf)**2);
rand_value=random();
if collchk<0:
SP[j], SP[j+1]=SP[j+1],SP[j];
if rcoeff>rand_value:
counter=counter+1
SP[j].spin,SP[j+1].spin=SP[j+1].spin,SP[j].spin;
if SP[j].spin == 1:
Up.append(c*(SP[j].pos)+s*(SP[j].mom))
else:
Down.append(c*(SP[j].pos)+s*(SP[j].mom))
Z.append(c*(SP[j].pos)+s*(SP[j].mom))
Zrel=sum(Up[0:])/len(Up) - sum(Down[0:])/len(Down);
Zrelm.append(Zrel)
Zm=sum(Z)/len(Z)
Zavg.append(Zm)
return [Zavg, Zrelm, counter]
我在下面给出的 Vandan 代码中遇到的错误:
Failed in nopython mode pipeline (step: nopython frontend)
Untyped global name 'sum': cannot determine Numba type of <class 'builtin_function_or_method'>
File "<ipython-input-1-cddc88c01635>", line 52:
def f(SP, Zavgi, Zreli, alf, dt, n):
<source elided>
Zrel = sum(Up[0:]) / len(Up) - sum(Down[0:]) / len(Down);
^
最后我想绘制我返回的列表。
任何帮助将不胜感激,如果有一种方法甚至可以将 Numba 用于 class 定义,那就太好了。
编辑:
import numpy as np
import matplotlib.pyplot as plt
import random
from math import *
from random import *
from numba import jit
"Dynamics"
@jit(nopython=True)
def f(SP, Zavgi, Zreli, alf, dt, n):
"Time"
counter = 0;
sum1, sum2 = 0, 0;
Zavg = np.array([Zavgi]);
Zrelm = np.array([Zreli]);
T_plot = [0];
for i in range(1, iter + 1):
t = i * dt;
T_plot.append(t)
Z = [];
Up = [];
Down = [];
c, s = cos(t), sin(t);
c1, s1 = cos(t - dt), sin(t - dt);
for j in range(n - 1):
collchk = ((c * (SP[j][0]) + s * (SP[j][1])) - (c * (SP[j + 1][0]) + s * (SP[j + 1][1]))) * (
c1 * (SP[j][0]) + s1 * (SP[j][1]) - (c1 * (SP[j + 1][0]) + s1 * (SP[j + 1][1])));
prel = ((c * (SP[j][1]) - s * (SP[j][0])) - (c * (SP[j + 1][1]) - s * (SP[j + 1][0]))) / 2;
rcoeff = 1 / (1 + (prel * alf) ** 2);
rand_value = random();
if collchk < 0:
SP[j], SP[j + 1] = SP[j + 1], SP[j];
if rcoeff > rand_value:
counter = counter + 1
SP[j][2], SP[j + 1][2] = SP[j + 1][2], SP[j][2];
if SP[j][2] == 1:
Up.append(c * (SP[j][0]) + s * (SP[j][1]))
else:
Down.append(c * (SP[j][0]) + s * (SP[j][1]))
Z.append(c * (SP[j][0]) + s * (SP[j][1]))
Zrel = sum(Up[0:]) / len(Up) - sum(Down[0:]) / len(Down);
Zrelm = np.append(Zrelm, Zrel)
Zm = sum(Z) / len(Z)
Zavg = np.append(Zavg, Zm)
return Zavg, Zrelm, counter,T_plot
if __name__ == '__main__':
n = 1000
mu = np.random.uniform(0, 1, n)
r = [sqrt(-2 * log(1 - i)) for i in mu]
eta = np.random.uniform(0, 1, n)
theta = 2 * pi * eta;
cuz = [cos(i) for i in theta]
suz = [sin(i) for i in theta]
Zinitial = [a * b for a, b in zip(r, cuz)];
Pinitial = [a * b for a, b in zip(r, suz)];
iter = 10 ** (6);
dt = 1 / (100 * n);
alf = sqrt(n);
SP = np.array(sorted(np.array([ np.array([i,j,choice([0,1])]) for i, j in zip(Zinitial, Pinitial)]),
key=lambda x: x[0]))
Upi = [];
Downi = [];
count_plot = [];
for j in range(len(SP)):
if SP[j][2] == 1:
Upi.append(SP[j][0])
else:
Downi.append(SP[j][0])
Zavgi = sum(Zinitial) / len(Zinitial)
Zreli = sum(Upi) / len(Upi) - sum(Downi) / len(Downi)
Zavg, Zrelm, counter,T_plot = f(SP, Zavgi, Zreli, alf, dt, n)
plt.plot(T_plot, Zrelm)
我稍微修改了您的代码,并且能够将函数设置为 运行。我删除了粒子 class 并将所有列表实例更改为 numpy 数组。
这是 Zavg、Zrelm 和计数器的输出:
Zavg: [0.07047501 0.06735052 0.06728123 ... 0.39516435 0.3947497 0.39433495]
Zrelm: [-0.04179043 -0.04461464 -0.0394889 ... -0.11080628 -0.11087257
-0.11093883]
Counter: 538
修改后的代码如下:
import numpy as np
import matplotlib.pyplot as plt
import random
from math import *
from random import *
from numba import jit
"Dynamics"
@jit(nopython=True)
def f(SP, Zavgi, Zreli, alf, dt, n):
"Time"
counter = 0;
sum1, sum2 = 0, 0;
Zavg = np.array([Zavgi]);
Zrelm = np.array([Zreli]);
T_plot = [0];
for i in range(1, iter + 1):
t = i * dt;
T_plot.append(t)
Z = [];
Up = [];
Down = [];
c, s = cos(t), sin(t);
c1, s1 = cos(t - dt), sin(t - dt);
for j in range(n - 1):
collchk = ((c * (SP[j][0]) + s * (SP[j][1])) - (c * (SP[j + 1][0]) + s * (SP[j + 1][1]))) * (
c1 * (SP[j][0]) + s1 * (SP[j][1]) - (c1 * (SP[j + 1][0]) + s1 * (SP[j + 1][1])));
prel = ((c * (SP[j][1]) - s * (SP[j][0])) - (c * (SP[j + 1][1]) - s * (SP[j + 1][0]))) / 2;
rcoeff = 1 / (1 + (prel * alf) ** 2);
rand_value = random();
if collchk < 0:
SP[j], SP[j + 1] = SP[j + 1], SP[j];
if rcoeff > rand_value:
counter = counter + 1
SP[j][2], SP[j + 1][2] = SP[j + 1][2], SP[j][2];
if SP[j][2] == 1:
Up.append(c * (SP[j][0]) + s * (SP[j][1]))
else:
Down.append(c * (SP[j][0]) + s * (SP[j][1]))
Z.append(c * (SP[j][0]) + s * (SP[j][1]))
Zrel = np.sum(np.array(Up)) / len(Up) - np.sum(np.array(Down)) / len(Down);
Zrelm = np.append(Zrelm, Zrel)
Zm = np.sum(np.array(Z)) / len(Z)
Zavg = np.append(Zavg, Zm)
return Zavg, Zrelm, counter, T_plot
if __name__ == '__main__':
n = 1000
mu = np.random.uniform(0, 1, n)
r = [sqrt(-2 * log(1 - i)) for i in mu]
eta = np.random.uniform(0, 1, n)
theta = 2 * pi * eta;
cuz = [cos(i) for i in theta]
suz = [sin(i) for i in theta]
Zinitial = [a * b for a, b in zip(r, cuz)];
Pinitial = [a * b for a, b in zip(r, suz)];
iter = 10 ** (5);
dt = 1 / (2 * n);
alf = sqrt(n);
SP = np.array(sorted(np.array([ np.array([i,j,choice([0,1])]) for i, j in zip(Zinitial, Pinitial)]),
key=lambda x: x[0]))
Upi = [];
Downi = [];
count_plot = [];
for j in range(len(SP)):
if SP[j][2] == 1:
Upi.append(SP[j][0])
else:
Downi.append(SP[j][0])
Zavgi = sum(Zinitial) / len(Zinitial)
Zreli = sum(Upi) / len(Upi) - sum(Downi) / len(Downi)
Zavg, Zrelm, counter, T_plot = f(SP, Zavgi, Zreli, alf, dt, n)
print(Zavg, Zrelm, counter)
plt.plot(T_plot, Zrelm)
plt.show()
剧情是这样的:
出现错误是因为 Numba 试图访问编译时类型未知的全局变量。事实上,SP
是一个名为 反射列表 的 pure-Python 列表,它可以包含不同类型的项目。 Numba 不再支持此类列表。相反,Numba 支持与反射列表兼容的 类型化列表 。这意味着您需要构建一个新的类型化列表(具有 well-defined 类型)并将反映的列表项复制到类型化列表中。与整体计算相比,此过程可能非常昂贵。因此,当可以使用数组代替时(通常是当您不知道最终列表的大小时),通常最好不要使用列表:Numpy 数组明显更快,更紧凑,使用它们的函数可以更快地编译。
此外,Numba 不知道 was 是 Particle
类型。 Numba 默认只支持 Numpy built-in 类型。 experimental 支持 jitted 类 但我建议您使用基本数组,因为它通常更快,也更灵活因为您可以在目标数组上使用 Numpy 向量化函数,而不是 object-based 数组(AFAIK 存储在 Numpy 数组中效率低且速度慢)。
此外,您应该真正避免使用全局变量,尤其是那些变异的变量。全局变量在 CPython 中的访问速度较慢,通常被视为一种糟糕的软件工程实践。对于 Numba,它们被视为编译时常量,因此如果变量在运行时发生变化,可能会导致一些令人惊讶的结果。
我第一次尝试在 colab 中使用 Numba,我认为我已经成功安装了 Numba,因为 @jit 现在不是未定义的,但我的代码中出现错误。以下是我的尝试:
!apt-get install nvidia-cuda-toolkit
!pip3 install numba
import os
dev_lib_path = !find / -iname 'libdevice'
nvvm_lib_path = !find / -iname 'libnvvm.so'
assert len(dev_lib_path)>0, "Device Lib Missing"
assert len(nvvm_lib_path)>0, "NVVM Missing"
os.environ['NUMBAPRO_LIBDEVICE'] = dev_lib_path[0]
os.environ['NUMBAPRO_NVVM'] = nvvm_lib_path[0]
import numpy as np
import matplotlib.pyplot as plt
import random
from math import *
from random import *
from numba import jit
n=1000
mu=np.random.uniform(0,1,n)
r=[sqrt(-2*log(1-i)) for i in mu]
eta=np.random.uniform(0,1,n)
theta=2*pi*eta;
cuz=[cos(i) for i in theta]
suz=[sin(i) for i in theta]
Zinitial=[a*b for a,b in zip(r,cuz)];
Pinitial=[a*b for a,b in zip(r,suz)];
class Particle:
def __init__(self, pos, mom, spin):
self.pos = pos
self.mom = mom
self.spin = spin
SP = sorted(np.array([Particle(pos = i, mom = j, spin = choice([1, 0])) for i,j in zip(Zinitial,Pinitial)]),key=lambda x:x.pos)
Upi=[];
Downi=[];
count_plot=[];
for j in range(len(SP)):
if SP[j].spin == 1:
Upi.append(SP[j].pos)
else:
Downi.append(SP[j].pos)
Zavgi=sum(Zinitial)/len(Zinitial)
Zreli=sum(Upi)/len(Upi)-sum(Downi)/len(Downi)
"Observables"
"Time"
iter=10**(5);
dt=1/(2*n);
alf=sqrt(n);
"Dynamics"
@jit(nopython=True)
def f():
counter=0;
sum1,sum2=0,0;
Zavg=[Zavgi];
Zrelm=[Zreli];
T_plot=[0];
for i in range(1,iter+1):
t=i*dt;
T_plot.append(t)
Z=[];
Up=[];
Down=[];
c,s=cos(t),sin(t);
c1,s1=cos(t-dt),sin(t-dt);
for j in range(n-1):
collchk=((c*(SP[j].pos)+s*(SP[j].mom))-(c*(SP[j+1].pos)+s*(SP[j+1].mom)))*(c1*(SP[j].pos)+s1*(SP[j].mom)-(c1*(SP[j+1].pos)+s1*(SP[j+1].mom)));
prel=((c*(SP[j].mom)-s*(SP[j].pos))-(c*(SP[j+1].mom)-s*(SP[j+1].pos)))/2;
rcoeff=1/(1+(prel*alf)**2);
rand_value=random();
if collchk<0:
SP[j], SP[j+1]=SP[j+1],SP[j];
if rcoeff>rand_value:
counter=counter+1
SP[j].spin,SP[j+1].spin=SP[j+1].spin,SP[j].spin;
if SP[j].spin == 1:
Up.append(c*(SP[j].pos)+s*(SP[j].mom))
else:
Down.append(c*(SP[j].pos)+s*(SP[j].mom))
Z.append(c*(SP[j].pos)+s*(SP[j].mom))
Zrel=sum(Up[0:])/len(Up) - sum(Down[0:])/len(Down);
Zrelm.append(Zrel)
Zm=sum(Z)/len(Z)
Zavg.append(Zm)
return [Zavg, Zrelm, counter]
我在下面给出的 Vandan 代码中遇到的错误:
Failed in nopython mode pipeline (step: nopython frontend)
Untyped global name 'sum': cannot determine Numba type of <class 'builtin_function_or_method'>
File "<ipython-input-1-cddc88c01635>", line 52:
def f(SP, Zavgi, Zreli, alf, dt, n):
<source elided>
Zrel = sum(Up[0:]) / len(Up) - sum(Down[0:]) / len(Down);
^
最后我想绘制我返回的列表。 任何帮助将不胜感激,如果有一种方法甚至可以将 Numba 用于 class 定义,那就太好了。
编辑:
import numpy as np
import matplotlib.pyplot as plt
import random
from math import *
from random import *
from numba import jit
"Dynamics"
@jit(nopython=True)
def f(SP, Zavgi, Zreli, alf, dt, n):
"Time"
counter = 0;
sum1, sum2 = 0, 0;
Zavg = np.array([Zavgi]);
Zrelm = np.array([Zreli]);
T_plot = [0];
for i in range(1, iter + 1):
t = i * dt;
T_plot.append(t)
Z = [];
Up = [];
Down = [];
c, s = cos(t), sin(t);
c1, s1 = cos(t - dt), sin(t - dt);
for j in range(n - 1):
collchk = ((c * (SP[j][0]) + s * (SP[j][1])) - (c * (SP[j + 1][0]) + s * (SP[j + 1][1]))) * (
c1 * (SP[j][0]) + s1 * (SP[j][1]) - (c1 * (SP[j + 1][0]) + s1 * (SP[j + 1][1])));
prel = ((c * (SP[j][1]) - s * (SP[j][0])) - (c * (SP[j + 1][1]) - s * (SP[j + 1][0]))) / 2;
rcoeff = 1 / (1 + (prel * alf) ** 2);
rand_value = random();
if collchk < 0:
SP[j], SP[j + 1] = SP[j + 1], SP[j];
if rcoeff > rand_value:
counter = counter + 1
SP[j][2], SP[j + 1][2] = SP[j + 1][2], SP[j][2];
if SP[j][2] == 1:
Up.append(c * (SP[j][0]) + s * (SP[j][1]))
else:
Down.append(c * (SP[j][0]) + s * (SP[j][1]))
Z.append(c * (SP[j][0]) + s * (SP[j][1]))
Zrel = sum(Up[0:]) / len(Up) - sum(Down[0:]) / len(Down);
Zrelm = np.append(Zrelm, Zrel)
Zm = sum(Z) / len(Z)
Zavg = np.append(Zavg, Zm)
return Zavg, Zrelm, counter,T_plot
if __name__ == '__main__':
n = 1000
mu = np.random.uniform(0, 1, n)
r = [sqrt(-2 * log(1 - i)) for i in mu]
eta = np.random.uniform(0, 1, n)
theta = 2 * pi * eta;
cuz = [cos(i) for i in theta]
suz = [sin(i) for i in theta]
Zinitial = [a * b for a, b in zip(r, cuz)];
Pinitial = [a * b for a, b in zip(r, suz)];
iter = 10 ** (6);
dt = 1 / (100 * n);
alf = sqrt(n);
SP = np.array(sorted(np.array([ np.array([i,j,choice([0,1])]) for i, j in zip(Zinitial, Pinitial)]),
key=lambda x: x[0]))
Upi = [];
Downi = [];
count_plot = [];
for j in range(len(SP)):
if SP[j][2] == 1:
Upi.append(SP[j][0])
else:
Downi.append(SP[j][0])
Zavgi = sum(Zinitial) / len(Zinitial)
Zreli = sum(Upi) / len(Upi) - sum(Downi) / len(Downi)
Zavg, Zrelm, counter,T_plot = f(SP, Zavgi, Zreli, alf, dt, n)
plt.plot(T_plot, Zrelm)
我稍微修改了您的代码,并且能够将函数设置为 运行。我删除了粒子 class 并将所有列表实例更改为 numpy 数组。
这是 Zavg、Zrelm 和计数器的输出:
Zavg: [0.07047501 0.06735052 0.06728123 ... 0.39516435 0.3947497 0.39433495]
Zrelm: [-0.04179043 -0.04461464 -0.0394889 ... -0.11080628 -0.11087257
-0.11093883]
Counter: 538
修改后的代码如下:
import numpy as np
import matplotlib.pyplot as plt
import random
from math import *
from random import *
from numba import jit
"Dynamics"
@jit(nopython=True)
def f(SP, Zavgi, Zreli, alf, dt, n):
"Time"
counter = 0;
sum1, sum2 = 0, 0;
Zavg = np.array([Zavgi]);
Zrelm = np.array([Zreli]);
T_plot = [0];
for i in range(1, iter + 1):
t = i * dt;
T_plot.append(t)
Z = [];
Up = [];
Down = [];
c, s = cos(t), sin(t);
c1, s1 = cos(t - dt), sin(t - dt);
for j in range(n - 1):
collchk = ((c * (SP[j][0]) + s * (SP[j][1])) - (c * (SP[j + 1][0]) + s * (SP[j + 1][1]))) * (
c1 * (SP[j][0]) + s1 * (SP[j][1]) - (c1 * (SP[j + 1][0]) + s1 * (SP[j + 1][1])));
prel = ((c * (SP[j][1]) - s * (SP[j][0])) - (c * (SP[j + 1][1]) - s * (SP[j + 1][0]))) / 2;
rcoeff = 1 / (1 + (prel * alf) ** 2);
rand_value = random();
if collchk < 0:
SP[j], SP[j + 1] = SP[j + 1], SP[j];
if rcoeff > rand_value:
counter = counter + 1
SP[j][2], SP[j + 1][2] = SP[j + 1][2], SP[j][2];
if SP[j][2] == 1:
Up.append(c * (SP[j][0]) + s * (SP[j][1]))
else:
Down.append(c * (SP[j][0]) + s * (SP[j][1]))
Z.append(c * (SP[j][0]) + s * (SP[j][1]))
Zrel = np.sum(np.array(Up)) / len(Up) - np.sum(np.array(Down)) / len(Down);
Zrelm = np.append(Zrelm, Zrel)
Zm = np.sum(np.array(Z)) / len(Z)
Zavg = np.append(Zavg, Zm)
return Zavg, Zrelm, counter, T_plot
if __name__ == '__main__':
n = 1000
mu = np.random.uniform(0, 1, n)
r = [sqrt(-2 * log(1 - i)) for i in mu]
eta = np.random.uniform(0, 1, n)
theta = 2 * pi * eta;
cuz = [cos(i) for i in theta]
suz = [sin(i) for i in theta]
Zinitial = [a * b for a, b in zip(r, cuz)];
Pinitial = [a * b for a, b in zip(r, suz)];
iter = 10 ** (5);
dt = 1 / (2 * n);
alf = sqrt(n);
SP = np.array(sorted(np.array([ np.array([i,j,choice([0,1])]) for i, j in zip(Zinitial, Pinitial)]),
key=lambda x: x[0]))
Upi = [];
Downi = [];
count_plot = [];
for j in range(len(SP)):
if SP[j][2] == 1:
Upi.append(SP[j][0])
else:
Downi.append(SP[j][0])
Zavgi = sum(Zinitial) / len(Zinitial)
Zreli = sum(Upi) / len(Upi) - sum(Downi) / len(Downi)
Zavg, Zrelm, counter, T_plot = f(SP, Zavgi, Zreli, alf, dt, n)
print(Zavg, Zrelm, counter)
plt.plot(T_plot, Zrelm)
plt.show()
剧情是这样的:
出现错误是因为 Numba 试图访问编译时类型未知的全局变量。事实上,SP
是一个名为 反射列表 的 pure-Python 列表,它可以包含不同类型的项目。 Numba 不再支持此类列表。相反,Numba 支持与反射列表兼容的 类型化列表 。这意味着您需要构建一个新的类型化列表(具有 well-defined 类型)并将反映的列表项复制到类型化列表中。与整体计算相比,此过程可能非常昂贵。因此,当可以使用数组代替时(通常是当您不知道最终列表的大小时),通常最好不要使用列表:Numpy 数组明显更快,更紧凑,使用它们的函数可以更快地编译。
此外,Numba 不知道 was 是 Particle
类型。 Numba 默认只支持 Numpy built-in 类型。 experimental 支持 jitted 类 但我建议您使用基本数组,因为它通常更快,也更灵活因为您可以在目标数组上使用 Numpy 向量化函数,而不是 object-based 数组(AFAIK 存储在 Numpy 数组中效率低且速度慢)。
此外,您应该真正避免使用全局变量,尤其是那些变异的变量。全局变量在 CPython 中的访问速度较慢,通常被视为一种糟糕的软件工程实践。对于 Numba,它们被视为编译时常量,因此如果变量在运行时发生变化,可能会导致一些令人惊讶的结果。