Python 中对象数组的矩阵乘法
Matrix Multiplication with Object Arrays in Python
我想知道如何在 numpy 中支持 dtype=object
数组的矩阵乘法。我有封装在 class Ciphertext
中的同态加密数字,为此我覆盖了基本数学运算符,如 __add__
、__mul__
等
我创建了 numpy 数组,其中每个条目都是我的 class 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 无法知道对象的形状有关,因为它可能是列表或其他东西。
朴素的解决方案:我可以编写自己的 class 来扩展 ndarray
并覆盖 __matmul__
操作,但我可能会失败出在性能上,而且这种方法需要实施广播等,所以我基本上会重新发明轮子以获得现在应该工作的东西。
问题:如何在 dtype=objects
的数组上使用 numpy 提供的标准矩阵乘法,其中对象的行为与数字完全相同?
提前致谢!
出于某种原因,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
有一个使用 object
dtype 和字符串连接的扩展示例。它实际上为此使用 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
代码已编译,因此需要更多工作来验证差异。
对于一维和二维数组,np.dot
与 np.matmul
一样好。 matmul
的引入是为了 @
运算符的便利性,以及它对 3d 及更高版本的扩展。以前,3d+ 行为只能通过 einsum
或在较高维度上迭代来实现。
matmul
对于 2 个 3d 数组有效:
for i in range(a.shape[0]):
data[i,:,:] = a[i,:,:].dot(b[i,:,:])
您可以使用 ndarray.dot
方法,即使 @
运算符失败,它显然也适用于 np.object
dtypes:
out = encryptedInput.dot(encryptedInput)
我想知道如何在 numpy 中支持 dtype=object
数组的矩阵乘法。我有封装在 class Ciphertext
中的同态加密数字,为此我覆盖了基本数学运算符,如 __add__
、__mul__
等
我创建了 numpy 数组,其中每个条目都是我的 class 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 无法知道对象的形状有关,因为它可能是列表或其他东西。
朴素的解决方案:我可以编写自己的 class 来扩展 ndarray
并覆盖 __matmul__
操作,但我可能会失败出在性能上,而且这种方法需要实施广播等,所以我基本上会重新发明轮子以获得现在应该工作的东西。
问题:如何在 dtype=objects
的数组上使用 numpy 提供的标准矩阵乘法,其中对象的行为与数字完全相同?
提前致谢!
出于某种原因,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
有一个使用 object
dtype 和字符串连接的扩展示例。它实际上为此使用 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
代码已编译,因此需要更多工作来验证差异。
对于一维和二维数组,np.dot
与 np.matmul
一样好。 matmul
的引入是为了 @
运算符的便利性,以及它对 3d 及更高版本的扩展。以前,3d+ 行为只能通过 einsum
或在较高维度上迭代来实现。
matmul
对于 2 个 3d 数组有效:
for i in range(a.shape[0]):
data[i,:,:] = a[i,:,:].dot(b[i,:,:])
您可以使用 ndarray.dot
方法,即使 @
运算符失败,它显然也适用于 np.object
dtypes:
out = encryptedInput.dot(encryptedInput)