这三个选项中哪一个对矩阵方程"Wx + b"最有效?



我正在尝试从头开始编写神经网络,我想知道在相应层的权重矩阵中包含每层的偏差的性能:

# For a single layer i of feed forward:
z = W[i] @ a[i-1] + b[i].reshape(-1,1)

而不是:

z = ((w[i] @ a[i-1]).T + b[i]).T

或者初始化权重,使偏差作为最后一个"列"包含在内,并且每个激活矩阵获得一行相应的矩阵:

ones = np.ones(len(X))
z = w[i] @ a[i-1].append(ones)

出现这个问题的原因是,如果我希望X是包含许多样本和许多变量的 2d 数组,那么当我尝试将 1d 数组添加到 2d 数组的每一列时,第一个代码片段往往会给出广播错误(因此.reshape(-1,1)(。

我希望SO具有LaTeX功能,但我希望上述选项是明确的。如果没有,请发表评论,我会尝试解释。

在numpy中,.T.reshape()等操作非常快,因为它们不会移动任何数据。前两个选项之间不太可能有任何性能差异。第三个选项(使用append(ones)(是你通常应该避免的,因为附加到 numpy 数组会导致分配一个新数组并复制所有值。

尽管.T.reshape都很快,但可能会有一些差异,具体取决于原始数据是存储行主("C"(还是列主("F"(;请参阅 numpy 数组文档 这将在很大程度上取决于底层矩阵乘法代码以及数组(或至少行和列(是否适合 CPU 的缓存。如果您使用 Anaconda Python,那么它是幕后的英特尔 MKL,这是非常高效的(只要您在英特尔 CPU 上运行它(。假设您使用单精度浮点数,并且 W 通常不大于 3500 个元素(14 kB 的数据(,则整个数组很可能适合 L1 缓存。

如果a是一个 2D 数组,并且您在a[i-1]中一次选择一行,则使用内存中顺序a元素(如果a以 C 顺序存储((默认值为 numpy(。如果从aa是 C 顺序数组的aa.T获取a,则a[i-1]中的元素在内存中不会连续,这将产生额外的开销。我做了一些测试;在实践中,差异似乎很小(小阵列为 15%(;我假设矩阵库将在必要时重新排列内存中的数组。

如果您使用IPython(在Jupyter Notebook或Spyder中(,那么您可以使用

例如
%timeit -n 10 -r 10 a @ b

(有关详细信息,请使用?timeit(。

最新更新