https://github.com/pasaopasen/gabor-wavelet
Python realization of wavelet transform with Gabor-kernel (from matlab)
https://github.com/pasaopasen/gabor-wavelet
math numba numpy speedup wavelet-transform
Last synced: 4 months ago
JSON representation
Python realization of wavelet transform with Gabor-kernel (from matlab)
- Host: GitHub
- URL: https://github.com/pasaopasen/gabor-wavelet
- Owner: PasaOpasen
- Created: 2020-09-09T09:21:56.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2020-09-11T19:00:03.000Z (almost 6 years ago)
- Last Synced: 2025-09-01T03:49:38.285Z (10 months ago)
- Topics: math, numba, numpy, speedup, wavelet-transform
- Language: Python
- Homepage:
- Size: 1.07 MB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Gabor wavelet
Python realization of wavelet transform with Gabor-kernel (from matlab)
Тут хранятся скрипты для выполнения прямого и обратного вейвлет-преобразования Габора + визуализаций.
## Прямое преобразование
Целью этой части работы была перезапись [кода с матлаба](https://github.com/PasaOpasen/Gabor-wavelet/tree/master/matlab_source) и его ускорение, так как очень часто требуется использовать прямое преобразование на большой сетке.
Тут имеется две функции. Первая - это сама функция вейвлета Габора:
```python
import numpy as np
import math
import cmath
def GaborWavelet(omega, t, Gabor_coef):
return 0.3251520240633*math.sqrt(omega)*cmath.exp(complex(-0.5*Gabor_coef*(t*omega*0.187390625129278)**2, omega*t))
```
Здесь `omega` и `Gabot_coef` - некоторые параметры, а `t` - время (аргумент), для которого надо посчитать функцию вейвлета.
Вторая функция - это само прямое преобразование:
```python
def DWT_signal(ut, a, b, t0, AA, BB, TT, omega0, Gabor_coef):
h_step=t0[1]-t0[0]
psi_t = np.empty(TT, dtype = np.complex128)
Wab = np.empty((BB, AA), dtype = np.complex128)
for j in range(AA):
for i in range(BB):
for k in range(TT):
t_cur=(t0[k]-b[i])/a[j]
psi_t[k] = GaborWavelet(omega0, t_cur, Gabor_coef).conjugate()
f_psi = psi_t * ut
Wab[i,j] = 0.5*(f_psi[0]+f_psi[-1]) + np.sum(f_psi[2:TT-1])
Wab = np.multiply(Wab, h_step/np.sqrt(a))
return Wab
```
`ut` - значения сигнала, `a` - значения по второй оси, `b` - значения по первой оси, `t0` - массив времен, `AA, BB, TT`- длины первых трех массивов (в Matlab и Fortran их принято передавать как аргументы).
Поработав над кодом, я добился очень существенного ускорения в сравнении с [исходным вариантом](https://github.com/PasaOpasen/Gabor-wavelet/blob/master/translation_only.py). Это было сделано с помощью комбинации трёх подходов:
1. оптимизации самого алгоритма, чтобы избавиться от повторных вычислений и множественных обращений к одним и тем же участкам памяти
2. векторизации вычислений, чтобы больше кода выполнялось с помощью низкоуровневых функций
3. jit-компиляции и возможной параллелизации
Эти подходы применялись как к вейвлету Габора, так и к прямому преобразованию, причём в разных пропорциях. В итоге получилось несколько версии этого алгоритма с разными характеристиками. Далее представлены результаты их сравнения.
### Benchmarks
Сделаем проверку скорости на среднем объёме данных:
```python
a = np.arange(1,30,0.5) # 58
b = np.arange(0,50,0.5) # 100
t = np.arange(0,101) # 101
ut = np.sin(2*math.pi/50 * t) + 100*np.cos(0.4*t)/(t*t+1)
omega = 1
Gabor_coef = 8
```
Проверка делается с помощью инструкций `%timeit` IPython:
```python
%timeit translation_only.DWT_signal(ut, a, b, t, a.size, b.size, t.size, omega, Gabor_coef)
%timeit light_vectorization.DWT_signal(ut, a, b, t, a.size, b.size, t.size, omega, Gabor_coef)
%timeit strong_vectorization.DWT_signal(ut, a, b, t, a.size, b.size, t.size, omega, Gabor_coef)
%timeit numba_strong.DWT_signal(ut, a, b, t, a.size, b.size, t.size, omega, Gabor_coef)
%timeit numba_just.DWT_signal(ut, a, b, t, a.size, b.size, t.size, omega, Gabor_coef)
%timeit numba_vectorization.DWT_signal(ut, a, b, t, a.size, b.size, t.size, omega, Gabor_coef)
%timeit numba_vec_parallel.DWT_signal(ut, a, b, t, a.size, b.size, t.size, omega, Gabor_coef)
```
Каждый модуль здесь - это отдельная версия алгоритма.
.png)
Итак, для этой размерности данных получаем результаты:
| Version | Time |
|:----------:|:-------------:|
| translation_only | 7.24 s ± 142 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)|
| light_vectorization | 372 ms ± 8.83 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) |
| strong_vectorization | 368 ms ± 8.54 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) |
| numba_strong | 219 ms ± 5.17 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) |
| numba_just | 36.3 ms ± 914 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) |
| numba_vectorization | 35.1 ms ± 350 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)|
| numba_vec_parallel | 8.33 ms ± 85.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) |
Как видно, удалось добиться ускорения примерно в 7.24s/35ms = 200 раз, не делая никакого распараллеливания. Параллельная версия работает ещё в 4 раза быстрее на моём 8-ядерном компьютере.
## Обратное преобразование
Для обратного преобразования нужно иметь исходную матрицу `W(a,b)`, вдобавок желательно посмотреть её тепловую карту, чтобы убедиться, что заданная сетка `a x b` покрывает все возвышения (иногда эту сетку придётся сдвигать либо делать больше). Получить значения сигнала (обратного преобразования) для массиво времен `t` можно командой
```python
from Reverse import St_array
s = St_array(t, Wab, a, b, omega, Gabor_coef)
```
%20from%20sin(2pi%20div%2050%20t).png)
.png)
%20from%20sin(2pi%20div%2050%20t)%2Bsin(2pi%20div%20100%20t).png)
%2Bsin(2pi%20div%20100%20t).png)
%20from%20sin(2pi%20div%2050%20t)%20%2B%204sin(2pi%20div%2010%20t).png)
%20%2B%204sin(2pi%20div%2010%20t).png)