优化 Numba 和 Numpy 功能
Optimize Numba and Numpy function
我正在尝试使这段代码更快 运行,但我找不到更多可以加快速度的技巧。
我得到的 运行时间大约是 3 微秒,问题是我调用了这个函数几百万次,这个过程最终花费了很长时间。我在 Java 中有相同的实现(只有基本的 for 循环),基本上,即使是大型训练数据,计算也是即时的(这是针对 ANN)
有没有办法加快速度?
我 运行宁 Python 2.7,numba 0.43.1 和 numpy 1.16.3 Windows 10
x = True
expected = 0.5
eligibility = np.array([0.1,0.1,0.1])
positive_weight = np.array([0.2,0.2,0.2])
total_sq_grad_positive = np.array([0.1,0.1,0.1])
learning_rate = 1
@nb.njit(fastmath= True, cache = True)
def update_weight_from_post_post_jit(x, expected,eligibility,positive_weight,total_sq_grad_positive,learning_rate):
if x:
g = np.multiply(eligibility,(1-expected))
else:
g = np.negative(np.multiply(eligibility,expected))
gg = np.multiply(g,g)
total_sq_grad_positive = np.add(total_sq_grad_positive,gg)
#total_sq_grad_positive = np.where(divide_by_zero,total_sq_grad_positive, tsgp_temp)
temp = np.multiply(learning_rate, g)
temp2 = np.sqrt(total_sq_grad_positive)
#temp2 = np.where(temp2 == 0,1,temp2 )
temp2[temp2 == 0] = 1
temp = np.divide(temp,temp2)
positive_weight = np.add(positive_weight, temp)
return [positive_weight, total_sq_grad_positive]
编辑:看来@max9111 是对的。不必要的临时数组是开销的来源。
对于您的函数的当前语义,似乎无法避免两个临时数组 --- return 值 [positive_weight, total_sq_grad_positive]
。但是,令我吃惊的是,您可能正计划使用此函数来更新这两个输入数组。如果是这样,通过做所有事情 in-place 我们可以获得最大的加速。像这样:
import numba as nb
import numpy as np
x = True
expected = 0.5
eligibility = np.array([0.1,0.1,0.1])
positive_weight = np.array([0.2,0.2,0.2])
total_sq_grad_positive = np.array([0.1,0.1,0.1])
learning_rate = 1
@nb.njit(fastmath= True, cache = True)
def update_weight_from_post_post_jit(x, expected,eligibility,positive_weight,total_sq_grad_positive,learning_rate):
for i in range(eligibility.shape[0]):
if x:
g = eligibility[i] * (1-expected)
else:
g = -(eligibility[i] * expected)
gg = g * g
total_sq_grad_positive[i] = total_sq_grad_positive[i] + gg
temp = learning_rate * g
temp2 = np.sqrt(total_sq_grad_positive[i])
if temp2 == 0: temp2 = 1
temp = temp / temp2
positive_weight[i] = positive_weight[i] + temp
@nb.jit
def test(n, *args):
for i in range(n): update_weight_from_post_post_jit(*args)
如果更新输入数组不是您想要的,您可以使用
开始函数
positive_weight = positive_weight.copy()
total_sq_grad_positive = total_sq_grad_positive.copy()
和 return 它们与您的原始代码相同。这不是那么快,但仍然更快。
不知道能不能优化成"instantaneous";我有点惊讶 Java 可以做到这一点,因为这对我来说看起来是一个非常复杂的函数,具有 time-consuming 操作,例如 sqrt
.
但是,您是否在调用此函数的函数上使用了 nb.jit
?像这样:
@nb.jit
def test(n):
for i in range(n): update_weight_from_post_post_jit(x, expected,eligibility,positive_weight,total_sq_grad_positive,learning_rate)
在我的计算机上,这将 运行 时间减半,这是有道理的,因为 Python 函数调用的开销非常高。
我正在尝试使这段代码更快 运行,但我找不到更多可以加快速度的技巧。
我得到的 运行时间大约是 3 微秒,问题是我调用了这个函数几百万次,这个过程最终花费了很长时间。我在 Java 中有相同的实现(只有基本的 for 循环),基本上,即使是大型训练数据,计算也是即时的(这是针对 ANN)
有没有办法加快速度?
我 运行宁 Python 2.7,numba 0.43.1 和 numpy 1.16.3 Windows 10
x = True
expected = 0.5
eligibility = np.array([0.1,0.1,0.1])
positive_weight = np.array([0.2,0.2,0.2])
total_sq_grad_positive = np.array([0.1,0.1,0.1])
learning_rate = 1
@nb.njit(fastmath= True, cache = True)
def update_weight_from_post_post_jit(x, expected,eligibility,positive_weight,total_sq_grad_positive,learning_rate):
if x:
g = np.multiply(eligibility,(1-expected))
else:
g = np.negative(np.multiply(eligibility,expected))
gg = np.multiply(g,g)
total_sq_grad_positive = np.add(total_sq_grad_positive,gg)
#total_sq_grad_positive = np.where(divide_by_zero,total_sq_grad_positive, tsgp_temp)
temp = np.multiply(learning_rate, g)
temp2 = np.sqrt(total_sq_grad_positive)
#temp2 = np.where(temp2 == 0,1,temp2 )
temp2[temp2 == 0] = 1
temp = np.divide(temp,temp2)
positive_weight = np.add(positive_weight, temp)
return [positive_weight, total_sq_grad_positive]
编辑:看来@max9111 是对的。不必要的临时数组是开销的来源。
对于您的函数的当前语义,似乎无法避免两个临时数组 --- return 值 [positive_weight, total_sq_grad_positive]
。但是,令我吃惊的是,您可能正计划使用此函数来更新这两个输入数组。如果是这样,通过做所有事情 in-place 我们可以获得最大的加速。像这样:
import numba as nb
import numpy as np
x = True
expected = 0.5
eligibility = np.array([0.1,0.1,0.1])
positive_weight = np.array([0.2,0.2,0.2])
total_sq_grad_positive = np.array([0.1,0.1,0.1])
learning_rate = 1
@nb.njit(fastmath= True, cache = True)
def update_weight_from_post_post_jit(x, expected,eligibility,positive_weight,total_sq_grad_positive,learning_rate):
for i in range(eligibility.shape[0]):
if x:
g = eligibility[i] * (1-expected)
else:
g = -(eligibility[i] * expected)
gg = g * g
total_sq_grad_positive[i] = total_sq_grad_positive[i] + gg
temp = learning_rate * g
temp2 = np.sqrt(total_sq_grad_positive[i])
if temp2 == 0: temp2 = 1
temp = temp / temp2
positive_weight[i] = positive_weight[i] + temp
@nb.jit
def test(n, *args):
for i in range(n): update_weight_from_post_post_jit(*args)
如果更新输入数组不是您想要的,您可以使用
开始函数positive_weight = positive_weight.copy()
total_sq_grad_positive = total_sq_grad_positive.copy()
和 return 它们与您的原始代码相同。这不是那么快,但仍然更快。
不知道能不能优化成"instantaneous";我有点惊讶 Java 可以做到这一点,因为这对我来说看起来是一个非常复杂的函数,具有 time-consuming 操作,例如 sqrt
.
但是,您是否在调用此函数的函数上使用了 nb.jit
?像这样:
@nb.jit
def test(n):
for i in range(n): update_weight_from_post_post_jit(x, expected,eligibility,positive_weight,total_sq_grad_positive,learning_rate)
在我的计算机上,这将 运行 时间减半,这是有道理的,因为 Python 函数调用的开销非常高。