首页 > 解决方案 > NumPy - 是否可以提高相互递归数组计算的性能

问题描述

考虑以下模块 -

""" simple nn """
import numpy as np

TRAINING_SET = np.array([[0, 0, 1], [0, 1, 1], [1, 0, 1], [1, 1, 1]])
OUTPUT = np.array([[0, 0, 1, 1]]).T

def train(epochs=100000):
    """ train a single layer neural network """
    rng = np.random.default_rng()
    weights = 2 * rng.random((3, 1)) - 1

    for _ in range(epochs):
        layer = 1 /(1 + np.exp(-np.dot(TRAINING_SET, weights)))
        weights += np.dot(TRAINING_SET.T, (OUTPUT - layer) * layer * (1 - layer))
    print("Number of epochs:", epochs)
    print("layer\n", layer)
    print("weights\n", weights)

因为layerweights是相互递归的,所以我不得不使用for循环来计算它们。有没有更有效的方法?

标签: pythonnumpy

解决方案


这是一种完全摆脱for循环的方法。请注意,weights不需要为这个问题唯一定义最优值,但layer可以恢复最优值。

我假设 as趋于epochs无穷大,weightslayer收敛到一些极限值(就像这个特定示例的情况一样)。如果是这样,我们期望增量weights为零。因此,我们有以下方程组:

0 == np.dot(TRAINING_SET.T, (OUTPUT - layer) * layer * (1 - layer))
layer == 1 /(1 + np.exp(-np.dot(TRAINING_SET, weights)))

使用一点代数,我们得到

OUTPUT == 1/(1 + np.exp(-TRAINING_SET @ weights))

请注意,这个方程不能完全成立,因为OUTPUT有一些零元素。我们可以得到如下数值近似:

err = 1e-8
w = np.linalg.pinv(TRAINING_SET) @ -np.log(err + 1/(err + OUTPUT)-1)

比较结果layer

ws, lr = train(100000)

err = 1e-8
ws2 = np.linalg.pinv(TRAINING_SET) @ -np.log(err + 1/(err + OUTPUT)-1)
lr2 = 1 /(1 + np.exp(-np.dot(TRAINING_SET, ws2)))

print(lr - lr2)
# [[ 0.00301781]
#  [ 0.00246096]
#  [-0.00200824]
#  [-0.0024629 ]]

推荐阅读