Свернуть каждый слой в стеке матриц, используя numpy / scipy - PullRequest
0 голосов
/ 02 февраля 2019

Предположим, у меня есть стек матриц A формы N*H*W и фильтр B формы h*w.Я хотел бы вычислить следующее:

C = np.stack([
    scipy.signal.convolve(
        A[i, :, :],
        B,
        mode='same'
    )
    for i in range(N)
], axis=0)

Какой самый быстрый способ сделать это?

1 Ответ

0 голосов
/ 20 февраля 2019

Вот векторизованный код:

C = scipy.signal.convolve(
    A,
    B[np.newaxis, ...],
    mode='same'
)

Однако, это удивительно медленнее, чем np.stack для N от 10 до 10000 и (H, W) = (84, 84), (h, w) = (13, 13) (это значения, которые я былинтересует для моей конкретной проблемы).

comparison of stacked and vectorized

Код бенчмаркинга (для запуска в IPython):

import numpy as np
import scipy.signal

import pandas as pd
import seaborn as sns

H, W = 84, 84
h, w = 13, 13

def benchmark(N):
    A = np.random.normal(size=(N, H, W))
    B = np.random.normal(size=(h, w))

    t1 = %timeit -qo np.stack([scipy.signal.convolve(A[i, :, :], B, mode='same') for i in range(N)])
    t2 = %timeit -qo scipy.signal.convolve(A, B[np.newaxis, ...], mode='same')

    return t1.timings, t2.timings

Ns = (10**np.linspace(1, 4, 16)).round().astype(int)

results = [benchmark(N) for N in Ns]

ns = []
timings = []
run_type = []

for N, (t1_timings, t2_timings) in zip(Ns, results):
    cnt = len(t1_timings)
    ns.extend([N] * cnt)
    timings.extend(t1_timings)
    run_type.extend(['stack'] * cnt)

    cnt = len(t2_timings)
    ns.extend([N] * cnt)
    timings.extend(t2_timings)
    run_type.extend(['vectorized'] * cnt)

df = pd.DataFrame({'N': ns, 'timings': timings, 'type': run_type})
sns.lineplot(x='N', y='timings', hue='type', data=df)
...