Matrix Multiplication with Object Arrays in Python



我想知道如何在 numpy 中使用dtype=object数组支持矩阵乘法。我有同态加密的数字,这些数字被封装在一个类Ciphertext中,我已经覆盖了基本的数学运算符,如__add____mul__等。

我创建了 numpy 数组,其中每个条目都是我的类Ciphertext的一个实例,numpy 知道如何很好地广播加法和乘法运算。

encryptedInput = builder.encrypt_as_array(np.array([6,7])) # type(encryptedInput) is <class 'numpy.ndarray'>
encryptedOutput = encryptedInput + encryptedInput
builder.decrypt(encryptedOutput)                           # Result: np.array([12,14])

但是,numpy 不会让我做矩阵乘

out = encryptedInput @ encryptedInput # TypeError: Object arrays are not currently supported

考虑到加法和乘法有效,我不太明白为什么会发生这种情况。我想这与numpy无法知道物体的形状有关,因为它可能是一个列表或其他东西。

朴素的解决方案:我可以编写自己的类来扩展ndarray并覆盖__matmul__操作,但我可能会失去性能,而且这种方法需要实现广播等,所以我基本上会重新发明轮子,以便像现在这样工作。

问题:如何在具有对象行为与数字完全相同的数组上使用 numpy 提供的标准矩阵乘法dtype=objects

提前谢谢你!

无论出于何种原因,matmul 都不起作用,但 tensordot 函数按预期工作。

encryptedInput = builder.encrypt_as_array(np.array([6,7]))
out = np.tensordot(encryptedInput, encryptedInput, axes=([1,0])) 
# Correct Result: [[ 92. 105.]
#                  [120. 137.]]

现在调整轴只是一件麻烦事。我仍然想知道这是否实际上比带有 for 循环的天真实现更快。

tensordot有一个使用objectdtype和字符串连接的扩展示例。 它实际上是为此使用np.dot

In [89]: np.dot(np.array([['a'],['b']],object),np.array([[2,3]]))
Out[89]: 
array([['aa', 'aaa'],
['bb', 'bbb']], dtype=object)

此示例很小,但它确实表明object版本采用的路由较慢(比等效的数字版本):

In [98]: timeit np.dot(np.array([[1],[2]]),np.array([[2,3]]))
7.3 µs ± 20.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [99]: timeit np.dot(np.array([[1],[2]],object),np.array([[2,3]]))
12 µs ± 121 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

np.dot代码已编译,因此需要更多的工作来验证差异。

对于 1 和 2D 数组,np.dotnp.matmul一样好。 引入matmul是为了@操作员的便利性,并扩展到3D及更高版本。 以前,3d+行为只能通过einsum或上维度的迭代来实现。

2 个 3D 阵列的matmul有效:

for i in range(a.shape[0]):
data[i,:,:] = a[i,:,:].dot(b[i,:,:])

您可以使用ndarray.dot方法,该方法显然适用于np.objectdtype,即使@运算符失败也是如此:

out = encryptedInput.dot(encryptedInput)

最新更新