我有一部分 metalab 函式,它將兩個矩陣乘以 8,8 塊。Table1 是 8x8 形狀,table2 是 320x240 形狀。我想將下面的代碼轉換為 python。
fun = @(x)x.data .*table1;
I_spatial = blockproc(table2,[8 8],fun);
我想使用方法來乘np.dot之類的矩陣,但是輸入陣列的大小在行列連接中不一樣,所以我不能輕易做到。有人可以幫助我,我如何將該片段移植到 Python?我還有這個功能的第二部分
fun=@(x)idct2(x.data);
I_spatial = blockproc(I_spatial,[8 8],fun) 128;
我怎樣才能用 Python 寫那部分?
uj5u.com熱心網友回復:
我知道沒有任何預制版本,但是這種實作將非常快,因為資料復制很少,只要它總是將輸出填充為適當的大小。
def blockproc(A,m,n,fun):
results_rows = []
for y in range(0,A.shape[0],m):
results_cols = []
for x in range(0,A.shape[1],n):
results_cols.append(fun(A[y:y m,x:x n]))
results_rows.append(results_cols)
patch_rows = results_rows[0][0].shape[0]
patch_cols = results_rows[0][0].shape[1]
final_array_cols = results_rows[0][0].shape[1] * len(results_rows[0])
final_array_rows = results_rows[0][0].shape[0] * len(results_rows)
final_array = np.zeros([final_array_rows,final_array_cols],dtype=results_rows[0][0].dtype)
for y in range(len(results_rows)):
for x in range(len(results_rows[y])):
data = results_rows[y][x]
final_array[y*patch_rows:y*patch_rows data.shape[0],x*patch_cols:x*patch_cols data.shape[1]] = data
return final_array
測驗它:
a = np.ones([320,240])
b = np.zeros([8,8])
def func_mul(x):
return x@b
result = blockproc(a,8,8,func_mul)
print('dims:',result.shape)
import time
t1 = time.time()
for i in range(1000):
blockproc(a, 8, 8, func_mul)
pass
t2 = time.time()
print('time:',(t2-t1)/1000)
暗淡:(320, 240)
時間:0.006634121179580689
uj5u.com熱心網友回復:
就像@Ahmed AEK 提到的那樣,沒有內置的解決方案。我想出了一個解決方案,它利用了numpy' 的極度優化vsplit和hsplit功能,甚至允許您就地執行功能:
import scipy
import numpy as np
from typing import *
from scipy.fftpack import idct
npd = NewType('npd', np.ndarray)
id = lambda x: x # default function is nothing
def blockproc(A: npd, blockdims: Tuple[int, int], func: Callable[npd, Any]=id, inplace: bool = False)-> npd:
blocks: List[npd] = []
if A.shape[0]%blockdims[0] != 0 or A.shape[1]%blockdims[1] != 0:
print(f"Invalid block dimensions - {A.shape} must be divided evenly by {tuple(blockdims)}")
vr, hr = A.shape[0]//blockdims[0], A.shape[1]//blockdims[1]
B = A if inplace else A.copy()
verts: List[npd] = np.vsplit(B,vr)
try:
for i in range(len(verts)):
for j,v in enumerate(np.hsplit(verts[i], hr)):
B[i*blockdims[0]:(i 1)*blockdims[0], j*blockdims[1]: (j 1)*blockdims[1]] = func(h)
except Exception as e: print("Invalid block function"); exit(e)
return B
if __name__ == "__main__":
# Assume table1 and table2 are defined above ...
# First code sample
fun = lambda x: x@table1
I_spatial = blockproc(table2 ,[8,8], fun)
# Second code sample
fun = lambda x: idct(x)
I_spatial = blockproc(I_spatial,[8 8],fun) 128
查看您提供的兩個代碼示例 - 幾乎相同!如果你好奇,點擊這里了解更多關于idct
編輯:
根據@Ahmed AEK 的評論(見下文),它似乎enumerate顯著減慢了代碼速度。我現在已經移除了外部enumerate以減少運行時間。
uj5u.com熱心網友回復:
使用 Ahmed 的函式和示例:
In [284]: a = np.ones([320, 240])
...: b = np.zeros([8, 8])
...:
...:
...: def func_mul(x):
...: return x @ b
In [285]: result = blockproc(a, 8, 8, func_mul)
In [286]: result.shape
Out[286]: (320, 240)
在評論中,我建議將其重塑/轉置a為 (n,m,8,8) 陣列:
In [287]: a1 = a.reshape(40, 8, 30, 8).transpose(0, 2, 1, 3)
In [288]: a1.shape
Out[288]: (40, 30, 8, 8)
In [289]: res = a1 @ b # matmul does 'batch' on lead dimensions
In [290]: res.shape
Out[290]: (40, 30, 8, 8)
In [291]: res1 = res.transpose(0, 2, 1, 3).reshape(a.shape)
比較時間:
In [292]: timeit result = blockproc(a, 8, 8, func_mul)
10.2 ms ± 171 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [293]: def foo(a, b):
...: a1 = a.reshape(40, 8, 30, 8).transpose(0, 2, 1, 3)
...: res = a1 @ b
...: res1 = res.transpose(0, 2, 1, 3).reshape(a.shape)
...: return res1
In [294]: timeit foo(a,b)
918 μs ± 2.19 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
更改陣列以使結果值顯著(并非全為 0)以驗證這些方法的相等性:
In [295]: a = np.arange(320 * 240).reshape(320, 240)
In [296]: b = np.arange(64).reshape(8, 8)
In [297]: result = blockproc(a, 8, 8, func_mul)
In [298]: res1 = foo(a, b)
In [299]: np.allclose(result, res1)
Out[299]: True
我的方法要快得多,因為它不會在前導 (40,30) 維度上進行迭代。但這取決于這樣的func存在matmul是否可以與這種混合維度一起作業。換句話說,一個充分利用numpy broadcasting.
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/441977.html
上一篇:獲取值從0到1的組
