Wprowadzenie

Konwulsja jest operacją matematyczną, która sprawia, że produkt jest zintegrowany z 2 funkcjami (sygnałami), przy czym jeden z sygnałów jest odwrócony do góry nogami. Na przykład, poniżej zawijamy 2 f(t) i g(t) sygnałów.

Tak więc pierwszą rzeczą do zrobienia jest obrócić sygnał g w poziomie (180 stopni), a następnie przesunąć g do góry nogami na f, mnożąc i gromadząc wszystkie jego wartości.

Kolejność, w jakiej sygnały są zwodzone, nie ma znaczenia dla wyniku końcowego, więc conv(a,b)==conv(b,a)

W tym przypadku należy wziąć pod uwagę, że niebieski sygnał f(τ) jest naszym sygnałem wejściowym, a g(t) naszym jądrem, termin “jądro” jest używany w przypadku używania zawirowań do filtrowania sygnałów.

Wielkość sygnału wyjściowego 1D

W przypadku zwoju 1D wielkość wyjściowa jest obliczana w ten sposób:

outputSize=(InputSizee-KernelSize)+1

Stosowanie zwojów

Ludzie używają konwulsji do przetwarzania sygnału w następujących przypadkach użycia:

Filtrowanie sygnałów (dźwięk 1D, przetwarzanie obrazu 2D)

Sprawdź, na ile jeden sygnał jest powiązany z innym

Znajdowanie wzorców w sygnałach

Prosty przykład w matlabie i pytonie (zdrętwiały)

Poniżej znajdują się dwa sygnały x = (0,1,2,3,4) i w = (1,-1,2).


Zrób to ręcznie

Aby lepiej zrozumieć pojęcie konwekcji, weźmy powyższy przykład za rękę. Zasadniczo zamierzamy zawinąć 2 sygnały (x,w). Pierwszą rzeczą jest odwrócenie W poziomo (O obrót w lewo o 180 stopni)

Następnie musimy przesunąć odwrócone W nad wejście X

Należy pamiętać, że w krokach 3,4,5 odwrócone okno znajduje się całkowicie wewnątrz sygnału wejściowego. Wyniki te nazywane są “ważnymi” zawirowaniami. W przypadkach, w których odwrócone okno nie znajduje się całkowicie wewnątrz okna wejściowego(X), możemy je uznać za zero, lub możemy obliczyć, co można obliczyć, np. w kroku 1 mnoży się 1 przez zero, a resztę po prostu ignoruje.

Wyściółka wejściowa

Aby utrzymać wielkość wyniku zwinięcia równą wielkości wejścia, oraz aby uniknąć efektu zwanego zwinięciem okrężnym, podajemy sygnał zerami.

Miejsce umieszczenia zer zależy od tego, co chcesz zrobić, to znaczy: w przypadku 1D możesz je połączyć na każdym końcu, ale w przypadku 2D zazwyczaj umieszczamy je wokół oryginalnego sygnału.

Na matlab można użyć komendy ‘padarray’ do podparcia wejścia:

>> x

x(:,:,1) =

1 1 0 2 0

2 2 2 2 1

0 0 0 2 1

2 2 2 2 1

2 0 2 2 1

x(:,:,2) =

2 1 0 0 0

0 2 0 1 0

1 0 1 2 0

1 2 0 2 1

1 2 1 2 2

x(:,:,3) =

2 1 1 2 2

1 1 1 0 0

2 0 1 0 2

0 2 0 2 1

0 0 2 1 0

>> padarray(x,[1 1])

ans(:,:,1) =

0 0 0 0 0 0 0

0 1 1 0 2 0 0

0 2 2 2 2 1 0

0 0 0 0 2 1 0

0 2 2 2 2 1 0

0 2 0 2 2 1 0

0 0 0 0 0 0 0

ans(:,:,2) =

0 0 0 0 0 0 0

0 2 1 0 0 0 0

0 0 2 0 1 0 0

0 1 0 1 2 0 0

0 1 2 0 2 1 0

0 1 2 1 2 2 0

0 0 0 0 0 0 0

ans(:,:,3) =

0 0 0 0 0 0 0

0 2 1 1 2 2 0

0 1 1 1 0 0 0

0 2 0 1 0 2 0

0 0 2 0 2 1 0

0 0 0 2 1 0 0

0 0 0 0 0 0 0

Wielkość wyjściowa dla 2D

Proszę wiedzieć, jaka będzie wielkość naszej produkcji po wykonaniu na niej pewnych operacji zwijania. Na szczęście istnieje przydatna formuła, która dokładnie to nam mówi.

Jeśli weźmiemy pod uwagę zwijanie się wejścia o wymiarach przestrzennych [H, W] wypełnionego P, z kwadratowym jądrem o rozmiarze F i z rozkrokiem S, wówczas rozmiar wyjściowy zwijania się definiowany jest jako:

outputSizeW=(W-F+2P)/S+1 outputSizeH=(H-F+2P)/S+1 output

F jest wielkością jądra, zwykle używamy kwadratowych ziaren, więc F jest zarówno szerokością jak i wysokością jądra

Realizacja operacji konwekcyjnych

Poniższy przykład będzie obejmował wejście 5x5x3 (LxHx3), z poziomem konwertora o następujących parametrach Stride=2, Pad=1, F=3 (jądro 3×3), oraz K=2 (dwa filtry).

Nasze wejście ma 3 kanały, więc potrzebujemy 3x3x3 masy jądra. Mamy 2 filtry (K=2), więc na końcu będziemy mieli 2 aktywacje wyjściowe. Dalej możemy obliczyć wielkość tych dwóch wyjść, które mają być: (5 – 3 + 2)/2 + 1 = 3.

Poniższy kod (wersja waniliowa) nie może być używany w prawdziwym życiu, ponieważ będzie powolny, ale jest dobry dla podstawowego zrozumienia. Zazwyczaj głęboko uczące się biblioteki robią konwulsje jako pojedyncze mnożenie matrycowe, używając metody im2col/col2im.

%% Konwulsja n wymiary

% Poniższy kod jest tylko rozszerzeniem conv2d_vanila dla n wymiarów.

% Parametry:

% Wejście: Wys. x Szer. x Głębokość

% K: jądro F x F x głębokość

% S: rozkrok (ile pikseli przesunie okno na wejściu)

% Ta implementacja jest jak parametr “ważny” w przypadku normalnego zwoju

funkcja outConv = convn_vanilla(wejście, jądro, S)

% Uzyskaj rozmiar wejściowy w postaci rzędów i kolumn. Wagi powinny mieć

% taka sama głębokość jak objętość wejściowa (obraz)

[rowsIn, colsIn, ~] = rozmiar(wejście);

% Get volume dimensio

deepInput = ndims(wejście);

% Uzyskaj rozmiar jądra, biorąc pod uwagę kwadratowe jądro zawsze

F = rozmiar (jądro, 1);

%% Inicjacja wyjścia

sizeRowsOut = ((rowsIn-F)/S) + 1;

sizeColsOut = ((colsIn-F)/S) + 1; sizeColsOut = ((colsIn-F)/S) + 1;

OutConvAcc = zera (sizeRowsOut , sizeColsOut, depthInput);

% % % Do zwoju

% Obróć każdy kanał na wejściu za pomocą odpowiedniego kanału jądrowego,

% na końcu sumy wszystkich wyników kanału.

dla głębokości=1:depthInput

% Wybierz wejście i kanał prądowy jądra

inputCurrDepth = wejście(:,:,depth);

kernelCurrRDepth = jądro(:,:,depth);

% Iteracja na każdym wierszu i col, (przy użyciu rozkroku)

dla r=1:S: (wiersze IN-1)

dla c=1:S:(colsIn-1)

%Należy unikać pobierania próbek z obrazu.

if (((c+F)-1) <= colsIn) && (((r+F)-1) <= rowsIn)

% Wybierz okno dotyczące objętości wejściowej (łatka)

sampleWindow = wejścieCurrDepth(r:(r+F)-1,c:(c+F)-1);

% Czy produkt kropkowy

dotProd = suma(próbkaWindow(:) .* kernelCurrDepth(:));

% Wynik przechowywania

OutConvAcc(ceil(r/S), ceil(c/S), głębokość) = dotProd;

koniec

koniec

koniec

koniec

% Suma elementów nad wymiarem objętości wejściowej (suma wszystkich kanałów)

outConv = suma (outConvAcc, depthInput);

koniec