File size: 2,189 Bytes
27813b0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""Throughput of the local build against the padded-bank conv1d formulation.

    python dev/bench.py
"""
import os
import sys
import time

import torch
import torch.nn.functional as Fn

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT)
import load_local  # noqa: E402

rp = load_local.load()

PAIRS = [("44.1k -> 16k  (speech in)", 44100, 16000),
         ("48k   -> 16k  (speech in)", 48000, 16000),
         ("16k   -> 24k  (tts out)",   16000, 24000),
         ("44.1k -> 48k  (device)",    44100, 48000)]
SECONDS = 30.0
REPS = 25


def timeit(fn, reps=REPS):
    for _ in range(5):
        fn()
    best = 1e30
    for _ in range(reps):
        t0 = time.perf_counter()
        fn()
        best = min(best, time.perf_counter() - t0)
    return best


def ref(x, plan):
    L, M, width, kern = plan.L, plan.M, plan.width, plan.kernel
    B, T = x.shape
    pad = Fn.pad(x, (width, width + M))
    r = Fn.conv1d(pad[:, None], kern[:, None, :], stride=M)
    return r.transpose(1, 2).reshape(B, -1)[:, :plan.out_len(T)]


print(f"threads={torch.get_num_threads()}  audio={SECONDS:.0f}s mono\n")
print(f"{'conversion':28} {'resample-poly':>13} {'conv1d bank':>12} "
      f"{'speedup':>8} {'taps/out':>9} {'path':>6}")

for name, orig, new in PAIRS:
    T = int(orig * SECONDS)
    g = torch.Generator().manual_seed(0)
    x = torch.randn(1, T, generator=g, dtype=torch.float32)
    plan = rp.Resampler(orig, new)

    t_mine = timeit(lambda: plan(x))
    t_ref = timeit(lambda: ref(x, plan))
    a, b = plan(x), ref(x, plan)
    rel = ((a - b).abs().max() / b.abs().max()).item()
    assert rel < 2e-5, rel
    print(f"{name:28} {t_mine*1e3:12.2f}ms {t_ref*1e3:11.2f}ms "
          f"{t_ref/t_mine:7.2f}x {plan.taps_per_output:9.1f} "
          f"{'fused' if plan.fused else 'bank':>6}")

plan = rp.Resampler(44100, 16000)
x = torch.randn(1, int(44100 * SECONDS), dtype=torch.float32)
t = timeit(lambda: plan(x))
print(f"\n44.1k->16k realtime factor: {SECONDS / t:,.0f}x  "
      f"({t*1e3:.2f} ms for {SECONDS:.0f} s)")
print(f"taps stored {plan.taps.numel()} of {plan.kernel.numel()} "
      f"padded-bank entries ({plan.density*100:.1f}%)")