Download as pdf or txt
Download as pdf or txt
You are on page 1of 74

9.

Sieci głębokie
9.1 Wprowadzenie
W ostatnich latach ogromny postęp w sztucznej inteligencji dokonał się za pośrednictwem tak
zwanego głębokiego uczenia. Głębokie uczenie dotyczy głównie wielowarstwowych sieci
neuronowych, które pełnią jednocześnie funkcję generatora cech diagnostycznych dla
analizowanego procesu oraz tworzą ostateczny wynik klasyfikacji bądź regresji [22,44,69].
Uzyskuje się w ten sposób doskonałe narzędzie zastępujące człowieka przede wszystkim w
trudnym problemie opisu procesu za pomocą specjalizowanych deskryptorów, których stworzenie
wymaga dużych zdolności eksperckich. Okazuje się przy tym, że takie podejście do bez-
interwencyjnej metody generacji cech jest o wiele skuteczniejsze od stosowanych tradycyjnie
metod generacji deskryptorów, pozwalając przy tym na poprawę dokładności działania systemu. Z
tego powodu technologia sieci głębokich stała się ostatnio bardzo szybko jednym z najbardziej
popularnych obszarów w dziedzinie nauk komputerowych.
Za protoplastę tych sieci można uznać zdefiniowany na początku lat dziewięćdziesiątych
wielowarstwowy neocognitron Fukushimy [16]. Prawdziwy rozwój tych sieci zawdzięczamy
jednak profesorowi LeCun [44], który zdefiniował podstawową strukturę i algorytm uczący
specjalizowanej sieci konwolucyjnej (zwanej również splotową). Jest to sieć wielowarstwowa,
której angielska nazwa „Convolutional Neural Network” jest tradycyjnie skracana do CNN.
Aktualnie CNN stanowi podstawową strukturę stosowaną na szeroką skalę w przetwarzaniu
obrazów i sygnałów [22]. W międzyczasie powstało wiele odmian sieci będących modyfikacją
struktury podstawowej CNN (np. U-net, RCNN) jak również sieci różniących się zasadniczo od
CNN, na przykład autoenkoder, jako wielowarstwowe, nieliniowe uogólnienie liniowej sieci PCA
[22,39]. Stosowane są również struktury wielowarstwowe bazujące na maszynie Boltzmanna (ang.
Restricted Boltzmann Machine - RBM) używane w sieciach głębokiej wiarygodności (ang. Deep
Belief Network – DBN) [22,32]. Sieci głębokie znalazły również swoje miejsce w strukturach
rekurencyjnych w postaci sieci rekurencyjnej LSTM (ang. Long Short-Term Memory) [24,25,72],
stanowiąc skuteczne rozwiązanie problemu propagacji wstecznej w czasie w systemie ze
sprzężeniem zwrotnym, stosowane dziś powszechnie w predykcji szeregów czasowych.
Cechą wspólną tych rozwiązań, zwłaszcza w przypadku CNN, jest wielowarstwowość
ułożenia neuronów i ogromna (idąca w miliony) ilość połączeń wagowych między neuronami. Dla
uniknięcia problemu lawinowego narastania liczby adaptowanych wag stosuje się połączenia typu

136
lokalnego. W takich rozwiązaniach neuron jest zasilany nie przez wszystkie sygnały (na przykład
piksele obrazów) warstwy poprzedzającej, jak to jest zorganizowane w sieciach klasycznych, ale
przez wybraną małą grupę neuronów (pikseli) tej warstwy, tworzących maskę filtrującą. Analiza
całego obrazu następuje poprzez przesuwanie tej maski z ustalonym krokiem (ang. stride) wzdłuż
i wszerz obrazu. Charakterystyczną cechą jest przy tym używanie identycznych wartości wag
przesuwającej się maski filtracyjnej.
Każdy rodzaj sieci głębokich związany jest z problemem adaptacji ogromnej liczby
parametrów sieci w akceptowalnym czasie. Skuteczna implementacja i rozwój koncepcji LeCuna
stały się możliwe dzięki olbrzymiemu postępowi w rozwoju technologii informatycznych,
pozwalającemu na ogromne przyśpieszenie obliczeń. Połączenie tych najnowszych technologii z
proponowanymi rozwiązaniami sieci głębokich stworzyło podstawy zastosowań sztucznej
inteligencji w życiu codziennym.
Realne stało się zaprojektowanie pojazdów samosterujących, których podstawą jest
rozpoznawanie obrazów i obiektów prezentowanych na tych obrazach w czasie rzeczywistym,
sterowanie robotami, skuteczne rozpoznawanie głosu, automatyczna generacja tekstu na podstawie
wypowiedzi głosowej, segmentacja złożonych obrazów, zwłaszcza biomedycznych,
przewidywanie kolejnych wartości szeregów czasowych, itp. [22,24,33,80]. Ważną sferą
zastosowań jest wspomaganie diagnostyki medycznej dzięki skutecznym algorytmom
przetwarzania obrazów medycznych, na przykład mikroskopowych, histologicznych itp. W pracy
tej najwięcej uwagi poświęcimy najczęściej używanej sieci CNN.

9.2 Sieć konwolucyjna CNN


9.2.1 Struktura sieci CNN
Sieci konwolucyjne CNN, zwane również sieciami splotowymi, powstały jako narzędzie analizy i
rozpoznawania obrazów wzorowane na sposobie działania naszych zmysłów [22]. Wyeliminowały
kłopotliwy i trudny dla użytkownika etap manualnego opisu cech charakterystycznych obrazów,
stanowiących atrybuty wejściowe dla końcowego etapu klasyfikatora bądź układu regresyjnego.
W tym rozwiązaniu sieć sama odpowiada za generację cech. Poszczególne warstwy sieci CNN
przetwarzają obrazy z warstwy poprzedzającej (na wstępie jest to zbiór obrazów oryginalnych
zorganizowanych w formie tensora) poszukując prymitywnych cech (np. grupy pikseli o
podobnym stopniu szarości, krawędzie, przecinające się linie itp.). Kolejne warstwy ukryte

137
generują pewne uogólnienia cech z warstwy poprzedzającej organizowane w formie obrazów.
Przykład wyników takiego przetworzenia obrazu kolorowego w warstwie ukrytej sieci
zawierającej 48 neuronów (każdy wielowejściowy o różnych wartościach wag) pokazano na rys.
9.1. Kolejne kwadraty obrazu wynikowego przedstawiają cechy diagnostyczne (w formie
podobrazu) utworzone przez każdy z tych neuronów.

Rys. 9.1 Przykład wyników przetwarzania obrazu kolorowego w cechy diagnostyczne w pierwszej
warstwie ukrytej o 48 neuronach przez sieć CNN [49].

Obrazy te w niczym nie przypominają oryginałów, ale reprezentują cechy charakterystyczne dla
nich wyrażone w formie intensywności pikseli. W efekcie kolejnego wielowarstwowego
przetwarzania obrazów z poprzedniej warstwy ostatnia warstwa konwolucyjna generuje obrazy
stosunkowo niewielkich wymiarów (ale dużej liczebności) reprezentujące cechy charakterystyczne
dla przetwarzanego zbioru. Obrazy te w poszczególnych warstwach są reprezentowane przez
tensory (struktury 3-wymiarowe, w których szerokość i wysokość odpowiadają wymiarom obrazu
a głębokość jest równa liczbie obrazów). Elementy tensora ostatniej warstwy lokalnie połączonej
są następnie przetwarzane na postać wektorową (operacja wypłaszczania), będącą początkiem
układu w pełni połączonego (ang. fully connected – FC), stanowiącego właściwy klasyfikator bądź
układ regresyjny. Przykład takiej struktury CNN przedstawiono na rys. 9.2 [49].

138
Rys. 9.2 Przykład struktury CNN zawierającej 3 warstwy konwolucyjne o połączeniu lokalnym i
w pełni połączoną strukturę końcową stanowiącą właściwy klasyfikator.

Kolejne warstwy sieci mają zadanie wygenerować w sposób automatyczny (całkowicie bez
udziału człowieka) zbiór cech charakterystycznych dla analizowanych wzorców obrazowych,
który następnie podlegają klasycznemu przetworzeniu (w podsystemie w pełni połączonym) w
decyzję klasyfikacyjną bądź regresyjną.

9.2.2 Podstawowe operacje w sieci CNN


Nazwa sieci CNN pochodzi od operacji splotu (konwolucji) stanowiącej istotny element
procesu obliczeniowego. W przypadku obrazów tablica danych jest reprezentowana przez
dwuwymiarową macierz I o elementach reprezentujących stopnie jasności pikseli I(m,n) a jądro K
jest dwuwymiarowe. Operacja splotu dwuwymiarowego jest wówczas zapisana w postaci [22]
Y(i, j ) = I(i, j ) * K(i, j ) =  I(m, n)K(i − m, j − n) =  I(i − m, j − n)K(m, n) (9.1)
m n m n

W sieciach CNN wejściem dla pierwszej warstwy ukrytej jest zwykle reprezentacja RGB obrazów
ustawionych w formie tensora. Operacja konwolucji w pierwszej warstwic konwolucyjnej
obejmuje wszystkie trzy kanały RGB obrazu, każdy z innymi przyjętymi wartościami wag jądra w
postaci filtru liniowego stanowiącego neuron analizujący. Suma wyników poszczególnych
kanałów stanowi wynik konwolucji tworzącej obraz wyjściowy. W dalszych warstwach operacja
ta obejmuje wiele (ustalonych przez użytkownika) obrazów z warstwy poprzedzającej, stanowiąc
ich sumę. Tego typu rozwiązanie konwolucyjne nosi również nazwę konwolucji grupowej.
Przykład operacji konwolucyjnej dla kroku przesunięcia filtrów (stride) równego 1
przedstawiono na rys. 9.3. Dane wejściowe stanowią 3 obrazy obr1, obr2 i obr3. Zastosowano 2
zespoły filtrów dwuwymiarowych: filtr11, flitr12, filtr13 dla wytworzenia pierwszego obrazu
wynikowego OBR1 oraz filtr21, filtr22 i filtr23 dla drugiego obrazu wynikowego OBR2. Cyfra

139
pierwsza w oznaczeniu filtru określa który obraz wynikowy będzie tworzony. Cyfra druga
wskazuje który obraz wejściowy jest przetwarzany. Na przykład oznaczenie filtr21 wskazuje, że
tworzony jest drugi obraz wyjściowy, a przetwarzany pierwszy obraz wejściowy. Oba obrazy
OBR1 i OBR2 są tworzone jako suma trzech odpowiednich wyników. Na przykład obraz OBR1
jest sumą: wyn11+wyn12 +wyn13, podobnie OBR2 jest sumą: wyn21+wyn22+wyn23. Dwa
obrazy wyjściowe OBR1wy i OBR2wy powstają w wyniku operacji ReLU

1 0 2 
 1 0  −1 1 
obr1 = 3 1 2  filtr11=   wyn11 =   OBR1
1 1 0   −1 1   3 0

2 0   4 1
filtr 21 =   wyn 21 =   OBR2
1 −1  6 3

 −15 −4  0 0 
OBR1=   ReLU → OBR1wy =  
 −17 −7  0 0

0 1 3 
 0 −2   1 −8
obr 2 = 1 4 2  filtr12 =   wyn12 =   OBR1
6 1 5   −1 1   −13 0 

1 1   −3 2 
filtr 22 =   wyn22 =   OBR2
0 −1  4 1

12 6  12 6 
OBR2=   ReLU → OBR2wy=  
15 −1 15 0 
5 1 2
 −1 2   −15 3 
obr 3 =  4 0 1  filtr13 =   wyn13 =   OBR1
1 3 6   −3 0   −7 −7 

2 1  11 3 
filtr 23 =   wyn 23 =   OBR2
 0 −1  5 −5

Rys. 9.3 Przykład konwolucji obrazu 3x3 reprezentowanego przez obr1, obr2 i obr3. Zastosowano
2 zespoły filtrów dwuwymiarowych: filtr11, flitr12, filtr13 dla wytworzenia pierwszego obrazu
wynikowego OBR1 oraz filtr 21, filtr22 i filtr23 dla drugiego obrazu wynikowego OBR2. Dwa
obrazy wyjściowe OBR1wy i OBR2wy powstają w wyniku operacji ReLU

W efekcie, w każdej warstwie konwolucyjnej filtr jest wielowymiarowy (stosuje się


również filtry jednowymiarowe 1x1), realizujący operacje tensorowe, przy czym wymiar maski
filtrującej jest równy nx×ny, a liczba tych masek tworzących filtry jest równa liczbie obrazów
140
wejściowych (kanałów) dla danej warstwy podlegających przetworzeniu (maksymalnie liczba
obrazów poprzedniej warstwy). W przypadku pierwszej warstwy konwolucyjnej i obrazowi
reprezentowanemu przez 3 kanały RGB każdy filtr tworzący jeden obraz wynikowy składa się z
trzech jednostek. Liczba obrazów wyjściowych po konwolucji jest równa liczbie zastosowanych
filtrów wielokanałowych (w przykładzie są to 2 zestawy 2 filtrów: filtr11, fitr12 i filtr13 dla
utworzenia wynikowego obrazu OBR1, oraz filtr21, filtr22 i filtr23 dla utworzenia wynikowego
obrazu OBR2. Liczba obrazów wynikowych w każdej warstwie jest ustalana przez użytkownika
(zwykle dla zachowania jak największej porcji informacji oryginalnej liczba tworzonych obrazów
wzrasta wraz z redukcją wymiarów obrazu wynikowego).
W przetwarzaniu danych operacja konwolucji stosowana w CNN charakteryzuje się
ważnymi zaletami w stosunku do zwykłych operacji macierzowych w sieciach klasycznych.
Należą do nich: lokalność połączeń, wspólne (powtarzalne) wartości wag połączeń filtru
przesuwającego się po obrazie i powstała dzięki temu niezmienniczość (ekwiwariancja) względem
przesunięcia.
Każdy sygnał wyjściowy filtru podlega działaniu nieliniowej funkcji aktywacji, która w
przypadku CNN przybiera najczęściej postać ReLU (ang. Rectified Linear Unit) opisaną wzorem
[22]
 x dla x  0
y ( x) =  (9.2)
0 dla x  0
Funkcja ta charakteryzuje się nieciągłą pochodną. Ten fakt utrudnia nieco uczenie sieci metodami
gradientowymi. Stąd czasem zastępuje się ją aproksymacją zwaną softplus, zdefiniowaną
następująco [22]

y( x) = ln(1 + e x ) (9.3a)
Jej pochodna jest ciągła i reprezentuje sigmoidę unipolarną. W wyniku konwolucji i działania
funkcji ReLU uzyskuje się wartości reprezentujące stopień szarości pikseli obrazu wynikowego.
W niektórych implementacjach sieci głębokich, na przykład w GAN stosuje się
zmodyfikowaną funkcję aktywacji LReLU (ang. Leaky ReLU), w której w części ujemnej
charakterystyki wartości zerowe zastępuje się linią prostą o małym nachyleniu a. Funkcję taką
opisuje się wzorem
 x dla x  0
y ( x) =  (9.3b)
ax dla x  0

141
przy wartości a<1; typowa wartość to a=0.01.
Stosowana jest również wersja wykładnicza funkcji ReLU, zwana w skrócie ELU (ang.
Exponential Linear Unit), która definiowana jest wzorem
 x dla x  0
y ( x) =  x
a ( e − 1) dla x  0
(9.3c)

w którym a jest hiperparametrem o wartości dodatniej, ułamkowej (typowa wartość a=0.01)


Badania pokazały, że dzięki zastosowaniu takiej funkcji można uzyskać nieco lepszą dokładność
klasyfikatora CNN, choć okupioną większą złożonością obliczeniową.
Proces konwolucji obywa się na obrazach wejściowych warstwy poprzedzającej przy
zastosowaniu maski filtrującej, o wagach dobieranych oddzielnie dla każdego obrazu
podlegającego konwolucji. Obraz wynikowy tak zdefiniowanej konwolucji jest sumą
przetworzonych obrazów wynikowych dotyczących każdego obrazu. Proces tworzenia jednego
obrazu wynikowego może być utożsamiony z działaniem pojedynczego neuronu filtrującego.
Liczba tych neuronów decyduje o populacji obrazów wynikowych w danej warstwie i jest ustalana
z góry przez użytkownika. Każdy filtr ma określoną przez użytkownika liczbę wag podlegających
adaptacji w procesie uczenia i łączących go z określonym rejonem lokalnym obrazu (tak zwana
funkcja jądra). Dla typowych wielkości maski 3x3 stosownych dla małych obrazów lub 11x11
stosowanych dla obrazów dużych liczba wag filtru staje się więc równa 9 lub 121 (plus waga
polaryzacji). Stosuje się również maski punktowe, o wymiarze 1x1. Taka wielkość maski
zdecydowanie zmniejsza liczbę adaptowanych parametrów sieci.
Przesuwna maska analizy wędrująca po obrazie wejściowym dostarcza do wyjścia sygnał
sumacyjny będący sumą iloczynów jasności pikseli i odpowiednich, połączonych z nimi wag filtru
na zasadzie konwolucji. Filtr o parametrach ustalonych w danej iteracji przesuwany jest po obrazie
z określonym krokiem, zwanym stride. Wielkość stride=1 oznacza, że nowa maska przesuwana
jest o jeden piksel obrazu (w kierunku x lub y) w stosunku do pozycji poprzedniej maski. Rozmiar
obrazu wynikowego zależy od wielkości przetwarzanego obrazu wejściowego oraz wybranego
kroku stride i wielkości maski filtrującej.
Wymiar obrazu wynikowego filtracji zależy od wielkości kroku stride, wielkości maski
filtrującej i zastosowanego uzupełnienia zerami. Istnieje ścisła relacja wiążąca rozmiar wynikowy
O obrazu z rozmiarem obrazu wejściowego W, wielkością filtru F, kroku stride S i wielkością
uzupełnienia zerami z obu stron symetrycznie (zero padding P). Wielkości te są powiązane relacją

142
O=(W−F+2P)/S+1 (9.4)
określającą wymiar obrazu wyjściowego. Przykładowo, jeśli obraz wejściowy ma wymiar 7x7
(W=7), zastosowany filtr 3x3 (F=3), stride S=1 oraz P=0 wówczas otrzymuje się obraz wyjściowy
o wymiarze 5x5, gdyż O=(7-3)/1+1=5. Podobnie dla S=2 otrzymuje się wymiar obrazu
wyjściowego równy 3x3.
W następnym kroku powstały obraz wynikowy poddaje się działaniu operacji redukcji
wymiarów obrazu polegającemu na statystycznym łączeniu wartości stopnia szarości sąsiednich
pikseli, tzw. operacja „pooling”. Funkcja ta przekształca wynik nieliniowego działania
filtracyjnego neuronu w określonym rejonie obrazu poprzez zdefiniowaną statystykę dotyczącą
sąsiadujących (pod względem lokalizacji) wyników wyjściowych. Typowe funkcje to: max
pooling zwracająca wartość maksymalną wyników neuronów znajdujących się w sąsiedztwie
prostokątnym aktualnego wyniku oraz average pooling zwracającą wartość średnią wyników w
tym obszarze. Przykład takiej operacji uwzględniającej obszar maski 2x2 przedstawiony jest na
rys. 9.4.

Rys. 9.4 Przykład wyników działania operacji average pooling i max pooling z maską 2x2 i
krokiem stride =2 na obrazie o wymiarach 4x4.

Wymiary obrazu po operacji pooling ulegają redukcji zgodnie ze wzorem (9.4). Operacja pooling
poza zmniejszeniem wymiaru obrazu pozwala uzyskać reprezentację bardziej inwariantną
względem niewielkiego przemieszczenia danych. Stanowi pewne uogólnienie cech
reprezentowanych przez sąsiednie grupy pikseli. Często dla zachowania odpowiednich wymiarów
obrazu stosuje się operację uzupełnienia brzegów zerami tzw. „zero padding”. Zwykle jest to
uzupełnienie symetryczne zarówno wierszy jak i kolumn obrazu.

143
Dodatkowo stosuje się również normalizację stopnia szarości obrazów powstałych w
wyniku konwolucji. Najczęściej jest to to operacja stosowana na danych „mini-batch” (małego
zestawu danych wybranego losowo z pełnego zbioru używanego w operacji konwolucji).
Wykonywana jest na wynikach bezpośrednich konwolucji liniowej (przed operacją ReLU).
Odbywa się poprzez odjęcie od rzeczywistych wartości stopnia jasności obrazu wartości średniej i
podzieleniu takich wyników przez odchylenie standardowe danych zawartych w „mini-batch”.
Krok stride przyjęty zarówno w konwolucji jak i operacji pooling wpływa istotnie na
wynik. Przykład graficzny wpływu wielkości kroku stride na wynik konwolucji w przypadku
danych wejściowych jednowymiarowych o 7 elementach (W=7) przedstawiono na rys. 9.9. W obu
przypadkach neuron filtrujący ma trzy połączenia wagowe (F=3) o wartościach wag równych
kolejno: 1, 0, -1 oraz brak uzupełnienia zerami (P=0). Wynik przedstawiony jest dla 2 różnych
wartości parametru stride W pierwszym przypadku jest to wartość stride=1, w drugim stride=2. W
zależności od wyboru otrzymuje się różną liczbę elementów wynikowych: w pierwszym
przypadku jest to 5 wyników, w drugim tylko trzy.

Rys. 9.5 Przykład wpływu wyboru wartości kroku stride (S) na wynik przetworzenia: rysunek
górny: S=1, b) rysunek dolny: S=2. Przyjęto filtr o wymiarach F=3 i wartościach wag równych
kolejno: 1, 0, -1 oraz brak uzupełnienia zerami (P=0). W wyniku konwolucji nastąpiła redukcja
wymiaru danych wejściowych: przy S=1 redukcja z 7 do 5, przy S=2 redukcja z 7 do 3.

144
Zdefiniowane wartości parametrów mają ważne znaczenie przy projektowaniu struktur CNN, gdyż
niewłaściwie przyjęte liczby mogą prowadzić do niecałkowitych wartości rozmiarów obrazów
wejściowych. Przykładowo w architekturze ALEXNET Krizhevskiego [41] wymiar wejściowy
obrazów jest równy 227x227x3 (reprezentacja RGB). Zastosowane przez niego wymiary w
pierwszej warstwie ukrytej to F=11, S=4, P=0. Stąd wymiar obrazu wyjściowego po konwolucji
jest równy O=(227-11)/4+1=55, czyli obraz 55x55. Gdyby wymiar obrazu wejściowego był równy
na przykład 224x224 wówczas wymiar obrazu wyjściowego przy S=4 po konwolucji nie byłby
liczbą całkowitą, gdyż wówczas O=(224-11)/4+1=54.25, co blokuje dalszy proces przetwarzania.
W poszczególnych warstwach ukrytych obrazy wynikowe tworzą tensory, strukturę
trójwymiarową reprezentowaną przez dwa wymiary obrazu i głębokość definiowaną przez liczbę
przetwarzanych obrazów. Obrazy tworzące tensor ostatniej warstwy konwolucyjnej są
przetwarzane na postać wektorową, stanowiącą początek sieci w pełni połączonej w której każdy
neuron jest połączony z każdym sygnałem warstwy poprzedniej – połączenia globalne (ang. Fully
Connected layer – FC). Neurony w warstwie o pełnym połączeniu mają unikane (niepowtarzalne)
wagi, podlegające adaptacji w procesie uczenia.
Przejście z reprezentacji tensorowej (wiele obrazów 2-wymiarowych) na postać wektorową
(pojedyncze sygnały wektora tworzące wejście dla właściwego klasyfikatora) może odbywać się
na wiele sposobów. Jednym z nich jest przyjęcie wszystkich wartości pikselowych poszczególnych
obrazów jako cech diagnostycznych i ustawienie ich w formie wektora poprzez operację tzw.
reshape. Przy zbyt dużych wymiarach obrazów stosowane może być zmniejszenie rozdzielczości
obrazów tworzących tensor. Innym rozwiązaniem jest zastosowanie operacji pooling z
odpowiednim krokiem stride. W niektórych przypadkach można zaprojektować sieć w taki sposób,
że ostatnia warstwa konwolucyjna zawiera tylko pojedynczą wartość dla każdego kanału.
W większości rozwiązań sieci CNN zamiast klasycznej wielowarstwowej sieci neuronowej
stosuje się klasyfikator typu softmax, w którym sygnały wejściowe są bezpośrednio przetwarzane
na prawdopodobieństwo przynależności do określonej klasy [22]. Liczba neuronów wyjściowych
jest równa liczbie klas, przy czym każdy neuron podlega adaptacji wag w klasyczny sposób
poprzez optymalizację funkcji celu. Wartość sygnału sumacyjnego neuronu i-tego określona jest
wówczas wzorem

145
ui (x) =  wij x j + w0 (9.5)
j

Prawdopodobieństwo przynależności wektora x do i-tej klasy (i=1, 2, …, M) zależy od wartości


funkcji softmax obliczanej dla każdej składowej wektora wyjściowego według wzoru
exp(u i )
softmax(u) i = M
(9.6)
 exp(u j )
j =1

Wartość największa wyznacza przynależność do klasy określonej wskaźnikiem i.

9.2.3 Uczenie sieci CNN


Przystępując do uczenia sieci CNN należy w pierwszej kolejności ustalić liczbę warstw ukrytych
(konwolucyjnych), pełniących rolę ekstraktora cech procesu, liczbę neuronów filtracyjnych w
poszczególnych warstwach (każdy odpowiedzialny za wytworzenie pojedynczego obrazu),
wielkość maski filtracyjnej neuronu i związanej z tym liczby połączeń wagowych, rodzaj funkcji
aktywacji, wielkość parametru stride w każdej warstwie konwolucyjnej i warstwie pooling oraz
wybór parametru zero-padding.
Uczenie warstw ukrytych polega na doborze wartości wag przesuwających się filtrów.
Liczba tych wag zależy od przyjętej wielkości maski filtracyjnej. Wielkość maski w przypadku
obrazów zależy od ich wielkości. Przy małych obrazach typowy wymiar to 5x5 (25 wag filtru),
przy dużych - wielkość stosowanej maski może być nawet 15x15 (225 wag filtru). Każdy neuron
tworzący obraz wynikowy w warstwie powinien wykrywać inne szczegóły obrazu, np. układ
pikseli tworzący krawędzie w określonym kierunku, skupienia pikseli tworzące plamki, zmiany
jasności w regionie, itp.
Uczenie sieci odbywa się poprzez minimalizację funkcji kosztu. Funkcja kosztu może być
definiowana w różny sposób. W sieciach głębokich do regresji stosuje się zwykle klasyczną
definicję według najmniejszych kwadratów. W sieciach głębokich pełniących rolę klasyfikatora
najczęściej stosowana jest definicja kross-entropijna (ang. cross-entropy function), bazująca na
prawdopodobieństwie przynależności do określonej klasy, przy czym to prawdopodobieństwo
określane jest poprzez znormalizowaną funkcję sigmoidalną zwaną softmax zdefiniowaną wzorem
(9.6), przy czym największa wartość prawdopodobieństwa wyznacza ostateczną przynależność do
jednej spośród M klas. Oznaczmy wartość funkcji softmax w postaci f(ui) [22]

146
exp(ui )
f (ui ) == M
(9.7)
 exp(u )
j =1
j

Zmienna ui w tym wzorze jest sumą wagową sygnałów dopływających do i-tego neuronu
wyjściowego. W zdaniach klasyfikacji wieloklasowej (M klas) tylko jedna klasa jest prawdziwa
(etykieta tej klasy d=1). Pozostałe klasy mają etykietę d=0. Zatem w procesie uczenia tylko klasa
wskazana przez sieć jako prawdziwa bierze udział w obliczaniu funkcji błędu (kosztu) przyjmując
d=1. Pozostałe wyjścia mające etykiety d=0 nie biorą bezpośredniego udziału w procesie
propagacji wstecznej. Entropijna (logarytmiczna) definicja funkcji celu dla jednego rekordu
danych jest zapisana w postaci
M
E = − di ln ( f (ui ) ) (9.8)
i =1

Wobec tylko jednej wartości prawdziwej klasy di=dp (różnej od zera) funkcja ta może być
uproszczona do postaci
 
 exp ( u ) 
E = − ln ( f (u )i ) = − ln  M 
p
(9.9)
 
  exp ( u j ) 
 j =1 
Składniki funkcji celu względem klas “negatywnych” są równe zeru. Tylko klasa wskazana przez
sieć bierze bezpośredni udział w tworzeniu funkcji celu. Tym nie mniej gradient funkcji celu zależy
również od składników klas „negatywnych”, ze względu na postać mianownika w wyrażeniu (9.9).
Należy przy tym zauważyć, że składniki gradientu funkcji celu względem sygnału sumacyjnego un
dla klas „negatywnych” będą miały identyczną postać, wyrażoną wzorem

  
  exp ( u )  
   = M ( n )
exp u
− ln  M
p
(9.10a)
un   
   exp ( u j )    exp ( u j )
  j =1   j =1

natomiast dla klasy wskazanej przez sieć wyrażenie (sygnał sumacyjny up) to będzie miało postać

147
  
  exp ( u )   exp ( u p )
   = M
− ln  M −1
p
(9.10b)
u p   
   exp ( u j )    exp ( u j )
  j =1   j =1
Znając wektor gradientu względem poszczególnych sygnałów sumacyjnych składniki gradientu
poszczególnych wag w występujących w wyrażeniu (9.10) są natychmiast określane korzystając z
własności różniczkowania funkcji złożonej, mianowicie
E E u E
= = xi (9.11)
wi u wi u
Najczęściej stosowanym algorytmem w uczeniu sieci CNN jest stochastyczny algorytm
największego spadku z momentem rozpędowym (ang. Stochastic Gradient Descent – SGD)
[20,22]. Adaptacja wag odbywa się iteracyjnie zgodnie ze wzorem
w(k ) = w(k − 1) − ηg(k − 1) +  w(k − 1) − w(k − 2) (9.12)

w którym  jest współczynnikiem momentu przyjmowanym z przedziału [0, 1]. Dla przyśpieszenia
procesu uczenia w poszczególnych iteracjach zamiast pełnego zbioru danych uczących używa się
losowo wybranego podzbioru (tzw. minibatch). Powstało wiele modyfikacji tego algorytmu
przyśpieszających proces uczenia, z których najczęściej używany (między innymi w Matlabie) jest
ADAM (skrót of ang. ADAptive Momenet estimation) [40]. W odróżnieniu od SGD w tej metodzie
każdy parametr w ma adaptacyjnie dobierany parametr uczenia uzależniony od momentu
statystycznego gradientu pierwszego i drugiego rzędu. Momenty te definiowane są w postaci
średniej kroczącej

• moment pierwszego rzędu (start z wartości zerowych)


mw (k ) = 1mw (k − 1) + (1 − 1 ) g (k ) (9.13)

• moment drugiego rzędu


v w (k ) = 2v w (k − 1) + (1 − 2 ) g 2 (k ) (9.14)

gdzie β1 i β1 są hiperparametrami dobieranymi przez użytkownika , zwykle w zakresie [0.9 – 0.999].


Na tej podstawie oblicza się estymatę nieobciążoną obu momentów, używaną w adaptacji
poszczególnych wag sieci

148
mw (k )
m
ˆw (k ) = (9.15)
1 − 1k

v w (k )
vˆw (k ) = (9.16)
1 −  2k

Adaptacja wag w następuje według wzoru

m
ˆw (k )
w (k ) = w (k − 1) − η +  w (k − 1) − w (k − 2)  (9.17)
vˆw (k ) + 

Eksperymenty numeryczne wykazały pewne przyspieszenie procesu uczenia przy zastosowaniu


adaptowanego współczynnika dla każdej wagi. Tym nie mniej nie zawsze jakość uzyskanych
wyników jest lepsza niż algorytmu SGD.
Bezpośrednie podejście do adaptacji wszystkich wag przy zastosowaniu globalnej metody
propagacji wstecznej uczenia dla całej sieci jest kosztowne obliczeniowo, gdyż wiąże się z
ogromną liczbą dobieranych parametrów. Przyśpieszenie procesu uczenia jest możliwe poprzez
dobór wstępny wag neuronów warstw konwolucyjnych przy zastosowaniu różnego rodzaju
rozwiązań techniki uczenia bez nauczyciela. Stosowane są różne podejścia do tego problemu.
• Inicjalizacja losowa wag każdego neuronu w każdej warstwie konwolucyjnej. Metoda ta
jest znana i przebadana w przypadku klasycznych sieci neuronowych typu ELM (Extreme
Learning Machine).
• Inicjalizacja manualna wykorzystująca doświadczenie użytkownika, ukierunkowana na
wykrywanie krawędzi w określonym kierunku. Można tu zastosować wstępnie klasyczne
liniowe filtry cyfrowe obrazu, np. filtry Sobela, Previtta, Canny, Log, itp.
• Inicjalizacja poprzez grupowanie danych, na przykład przy pomocy algorytmu k-means. W
metodzie tej grupowanie przeprowadza się dla losowo wybranych małych fragmentów
obrazu i parametry centroidu przyjmuje się jako wartości wag neuronów filtracyjnych.
• Inicjalizacja poprzez wstępne uczenie zachłanne (greedy learning) z nauczycielem,
warstwa po warstwie (najpierw warstwa pierwsza, potem warstwa druga na bazie wyników
przetworzenia sygnałów przez warstwę pierwszą itd.). Stosowane są różne warianty tego
rozwiązania, pozwalające na znaczne przyśpieszenie procesu uczenia. Po wstępnym

149
doborze wag następuje zwykle douczenie pełnej sieci przy wykorzystaniu metody
największego spadku i propagacji wstecznej błędu.
Przy obecnym stanie równoległej techniki obliczeniowej i zastosowaniu procesora graficznego
możliwe stało się zastosowanie uczenia z nauczycielem do pełnej (losowo zainicjowanej) sieci w
każdej iteracji uczącej (ekstremalne podejście do uczenia). Tym nie mniej przy zastosowaniu
takiego podejścia należy się liczyć z długotrwałym procesem uczenia, zwłaszcza jeśli wymiary
obrazów wejściowych są duże.
Najczęściej stosowanym podejściem w tworzeniu sieci CNN jest zastosowanie metody zwanej
transfer learning. W tym podejściu korzysta się ze wstępnie nauczonej sieci dostępnej między
innymi w Matlabie i Pythonie, o strukturze i parametrach dobranych przez specjalistów.
Użytkownik dokonuje jedynie adaptacji końcowej struktury sieci (zwykle klasyfikatora
końcowego) na swoich danych. Parametry warstw odpowiedzialnych za mechanizm generacji cech
diagnostycznych pozostają zwykle zamrożone. Uczenie takie odbywa się metodami
gradientowymi z zastosowaniem propagacji wstecznej błędu i przebiega stosunkowo szybko.
W ostatnich implementacjach Matlaba (poczynając od 2016 roku) dostępne są m-pliki do
uczenia i testowania różnych struktur sieci CNN. Sposób wykorzystania tych podprogramów
można uzyskać przy pomocy komendy help cnn. Użytkownik po wczytaniu danych uczących i
testujących definiuje architekturę sieci (liczbę warstw i neuronów warstwie, funkcję aktywacji,
rodzaj funkcji pooling, etc.), opcje wyboru parametrów uczenia, następnie dokonuje procesu
uczenia (funkcja trainNetwork) i następnie testowania (funkcja classify).
Dane uczące i testujące przygotowane są w postaci tablicy 3-D dla obrazów w skali szarości
lub 4-D dla obrazów reprezentowanych w postaci RGB. Pierwsze 2 współrzędne zawierają
wartości pikseli w osi x i y obrazu, trzecia współrzędna (przy reprezentacji 4-D) jest równa 1, 2 lub
3 prezentując obraz R, G lub B a ostatnia nr kolejny obrazów w bazie. Dane dotyczące klasy
reprezentowanej przez obraz są kodowane numerycznie (klasa 1, 2, 3, itd.) w postaci wektorowej.

9.3 Transfer Learning


Ważnym elementem procesów zachodzących w CNN jest duża niezależność wyniku od
rodzaju przetwarzanych obrazów, gdyż niezależnie od typu obrazu system tworzenia cech
diagnostycznych koncentruje się na elementach prymitywnych występujących w każdym obrazie.
Stało się to przyczyną powstania specjalnego sposobu wstępnego uczenia sieci CNN, tzw. pre-

150
training na dowolnie dobranym zestawie danych uczących. Tak powstały prototypy sieci w trybie
Transfer Learning podlegające jedynie douczeniu na danych użytkownika [22,55], zwykle
poprzez adaptację wag struktury w pełni połączonej (bez zmiany parametrów filtrów warstw
lokalnie połączonych). Dzięki takiemu rozwiązaniu możliwe jest ogromne skrócenie czasu
uczenia, a przy tym znaczące polepszenie zdolności generalizacji sieci.
Takim pierwszym prototypem (dostępnym również w Matlabie poczynając od wersji z roku
2017) jest AlexNet [41], zaprojektowany przez grupę naukowców: A. Krizhevsky, I. Sutskever i G.
Hinton. W implementacji pierwotnej Matlaba struktura sieci AlexNet jest następująca [49].
MATLAB

1 'data' Image Input 227x227x3 images with 'zerocenter' normalization


2 'conv1' Convolution 96 11x11x3 convolutions with stride [4 4] and padding [0 0]
3 'relu1' ReLU
4 'norm1' Cross Channel Normalization with 5 channels per element
5 'pool1' Max Pooling 3x3 max pooling with stride [2 2] and padding [0 0]
6 'conv2' Convolution 256 5x5x48 convolutions with stride [1 1] and padding [2 2]
7 'relu2' ReLU
8 'norm2' Cross Channel Normalization with 5 channels per element
9 'pool2' Max Pooling 3x3 max pooling with stride [2 2] and padding [0 0]
10 'conv3' Convolution 384 3x3x256 convolutions with stride [1 1] and padding [0 0]
11 'relu3' ReLU
12 'conv4' Convolution 384 3x3x192 convolutions with stride [1 1] and padding [0 0]
13 'relu4' ReLU
14 'conv5' Convolution 256 3x3x192 convolutions with stride [1 1] and padding [1 1]
15 'relu5' ReLU
16 'pool5' Max Pooling 3x3 max pooling with stride [2 2] and padding [0 0]
17 'fc6' Fully Connected 4096 fully connected layer
18 'relu6' ReLU
19 'drop6' Dropout 50% dropout
20 'fc7' Fully Connected 4096 fully connected layer
21 'relu7' ReLU
22 'drop7' Dropout 50% dropout
23 'fc8' Fully Connected 1000 fully connected output layer
24 'prob' Softmax softmax
25 'output' Classification 1000 classes

W przypadku Pyhtona, sieć Alexnet może wyglądać, wykorzystując bibliotekę Keras [1] w
następujący sposób.
Python
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv1 (Conv2D) (None, 55, 55, 96) 34944
_________________________________________________________________
batch_normalization (BatchNo (None, 55, 55, 96) 384
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 27, 27, 96) 0
_________________________________________________________________
conv2 (Conv2D) (None, 27, 27, 256) 307456
_________________________________________________________________
batch_normalization_1 (Batch (None, 27, 27, 256) 1024
_________________________________________________________________

151
max_pooling2d_1 (MaxPooling2 (None, 13, 13, 256) 0
_________________________________________________________________
conv3 (Conv2D) (None, 13, 13, 384) 885120
_________________________________________________________________
batch_normalization_2 (Batch (None, 13, 13, 384) 1536
_________________________________________________________________
conv4 (Conv2D) (None, 13, 13, 384) 663936
_________________________________________________________________
batch_normalization_3 (Batch (None, 13, 13, 384) 1536
_________________________________________________________________
conv5 (Conv2D) (None, 13, 13, 256) 442624
_________________________________________________________________
batch_normalization_4 (Batch (None, 13, 13, 256) 1024
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 6, 6, 256) 0
_________________________________________________________________
flatten (Flatten) (None, 9216) 0
_________________________________________________________________
fc6 (Dense) (None, 4096) 37752832
_________________________________________________________________
dropout (Dropout) (None, 4096) 0
_________________________________________________________________
fc7 (Dense) (None, 4096) 16781312
_________________________________________________________________
dropout_1 (Dropout) (None, 4096) 0
_________________________________________________________________
fc8 (Dense) (None, 1000) 4097000
=================================================================
Total params: 60,970,728
Trainable params: 60,967,976
Non-trainable params: 2,752
_________________________________________________________________

W sumie można wyróżnić w niej 25 podwarstw (włączając w nie konwolucję liniową, operację
ReLU, normalizację i pooling). Sieć zawiera 5 warstw konwolucyjnych i 3 warstwy w pełni
połączone (FC). Pierwsza warstwa FC połączona z operacją ReLU jest warstwą zawierającą 4096
cech diagnostycznych. Druga warstwa FC (również połączona z operacją ReLU jest warstwą
ukrytą klasyfikatora końcowego zasilająca warstwę wyjściową 1000 neuronów (pozwala na
rozpoznanie 1000 klas). Zastosowany w strukturze klasyfikator to softmax. Stosując transfer
learning można wyodrębnić sygnały z pierwszej warstwy FC jako cechy diagnostyczne i zasilić
nimi dowolnie wybrany klasyfikator, np. SVM czy MLP. W chwili obecnej implementacja sieci
AlexNet różni się nieco od wersji pierwotnej (brakuje warstwy ukrytej w strukturze FC).

9.4 Przykład użycia sieci ALEXNET w trybie transfer learning


Przykład zastosowania dotyczy rozpoznania 20 klas obrazów twarzy. Każda klasa jest
reprezentowana przez 25 fotografii twarzy w różnym ujęciu i oświetleniu, przy czym klasy
umieszczone są w oddzielnych folderach, a liczba tych folderów jest równa liczbie klas. Na tej
podstawie program Matlab [49] automatycznie przypisuje dane wejściowe do klasy zgodnej z
numerem folderu.

152
MATLAB
% Przykład zastosowania ALEXNET w klasyfikacji obrazów%
wyn=[]; wynVal=[];
Pred_y=[]; Pred_yVal=[];
N_run=1 % liczba powtórzeń procesu
% Baza danych uczących
images = imageDatastore( 'C:\chmura\ALEX_obrazy20',...
'IncludeSubfolders',true,...
'ReadFcn', @customreader, ...
'LabelSource','foldernames');

[uczImages,testImages] = splitEachLabel(images,0.8,'randomized');
for i=1:No_run
[trainingImages,validationImages] = splitEachLabel(uczImages,0.70+0.1*randn(1),'randomized');
numTrainImages = numel(trainingImages.Labels);

net = alexnet;
layersTransfer = net.Layers(1:end-6);

inputSize = net.Layers(1).InputSize;

% imageAugmenter = imageDataAugmenter( ...


% 'RandRotation',[-20,20], ...
% 'RandXTranslation',[-3 3], ...
% 'RandYTranslation',[-3 3])
% augimdsTrain = augmentedImageDatastore(inputSize(1:2),trainingImages,...
'DataAugmentation',imageAugmenter);
augimdsTrain = augmentedImageDatastore(inputSize(1:2),trainingImages);
augimdsTest = augmentedImageDatastore(inputSize(1:2),testImages);
layer = 'fc7';
featuresTrain = activations(net,augimdsTrain,layer,'OutputAs','rows');
featuresTest = activations(net,augimdsTest,layer,'OutputAs','rows');

numClasses = numel(categories(trainingImages.Labels));
layers = [
layersTransfer
fullyConnectedLayer(1000+35*i, ...
'WeightLearnRateFactor',20,...
'BiasLearnRateFactor',20)
reluLayer()
dropoutLayer(0.5+0.033*randn(1))
fullyConnectedLayer(numClasses,...
'WeightLearnRateFactor',20,...
'BiasLearnRateFactor',20)
softmaxLayer
classificationLayer];

miniBatchSize = 10; % bylo 10


numIterationsPerEpoch = floor(numel(trainingImages.Labels)/miniBatchSize);
options = trainingOptions('sgdm',...
'MiniBatchSize',miniBatchSize,...
'MaxEpochs',10,...
'ExecutionEnvironment','gpu',...
'InitialLearnRate',1.3e-4,...
'Verbose',false,...
'ValidationPatience',10,...
'Plots','training-progress',...
'ValidationData',validationImages,...
'ValidationFrequency',numIterationsPerEpoch);
netTransfer = trainNetwork(trainingImages,layers,options);

predictedLabels = classify(netTransfer,testImages);
testLabels = testImages.Labels;
accuracy = (mean(predictedLabels == testLabels))*100

Pred_y=[Pred_y predictedLabels];
wyn=[wyn accuracy] %wyniki poszczególnych powtórzeń procesu uczenia i testowania

153
end

Program umożliwia wielokrotne uruchomienie uczenia ustawione wartością parametru N_run. W


wyniku określona jest względna dokładność rozpoznania klas (wartość accuracy). Przy wielu
próbach (N_run>1) kolejne wyniki umieszczone są w tabeli wyn. Z tej tabeli można obliczyć
średnia dokładność klasyfikatora w postaci mean(wyn).

W dalszej części przedstawiony zostanie dokładnie proces tworzenia modelu z wykorzystaniem


trybu transfer learning w języku Python. W części tej zapoznamy się jednocześnie z podstawowymi
funkcjami biblioteki Keras [1]. Na początku zaimportowane zostaną podstawowe moduły, które
będą wykorzystywane w dalszej części.
Python
import numpy as np
import tensorflow as tf
from tensorflow import keras
import os
import matplotlib.pyplot as plt
import time
from sklearn.metrics import classification_report, confusion_matrix, roc_curve, auc
import pandas as pd

plt.rc('font', size=6)

Następnie użyty zostanie kod, który automatycznie pobierze przykładowe obrazy udostępnione w
chmurze plików Wydziału Elekrycznego PW1. Zbiór obrazów zawiera 400 zdjęć 20 osób
przypisanych do odpowiednich klas. Procedura obejmuje kroki:
• Pobranie archiwum zip pod nazwę: alexnet_20.zip.
• Rozpakowanie archiwum do bieżącego folderu.
• Sprawdzenie czy został utworzony wybrany plik z obrazem.
Python
!wget -O alexnet_20.zip https://cloud.ee.pw.edu.pl/nextcloud/index.php/s/3Qn5HHRQ38Axk5G/download
!unzip -o -q alexnet_20.zip
with open("./Alex_obrazy20/1/1.jpg") as f:
print(f"{'-'*70}\nZrobione. Pliki znajdują się w podfolderach w katalogu ./Alex_obrazy20\n{'-
'*70}")

W kolejnym fragmencie zdefiniujemy funkcję wczytującą obrazy z zadanego folderu.


Python

1
https://cloud.ee.pw.edu.pl/nextcloud/index.php/s/3Qn5HHRQ38Axk5G
154
def read_images(folder="./Alex_obrazy20"):
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array

images_list=[]
target_list=[]
folder="./Alex_obrazy20"
for sub in next(os.walk(folder))[1]:
for im in next(os.walk(os.path.join(folder,sub)))[2]:

# load the image


img = load_img(os.path.join(folder,sub,im))
# print("Original:", type(img))

# convert to numpy array


img_array = img_to_array(img)
# print(img_array.shape)
images_list.append(img_array)
target_list.append(int(sub))

images = np.array(images_list)
target = np.array(target_list)
return images, target

images, labels = read_images()


display(images.shape)
display(labels.shape)

Domyślnie, nazwy folderów a zatem wartości klas zaczynają się od liczby 1. Sieć w dalszej części
będzie numerować klasy zaczynając od wartości 0. Zatem zmniejszamy automatycznie wszystkie
klasy na początku.
Python
labels = labels - 1

Dzielimy wczytany zbiór danych na trzy części: dane uczące, walidujące oraz testowe.
Skorzystamy z funkcji SciKit-Learn, aby wybór danych był automatycznie losowy. Dane będą
odpowiednio wymieszane z wszystkich klas.
Python
from sklearn.model_selection import train_test_split

train_images, test_images, train_labels, test_labels = train_test_split(images, labels,


test_size=0.2)
train_images, validation_images, train_labels, validation_labels = train_test_split(train_images,
train_labels, test_size=0.2)

print(f"Rozmiar danych uczących: {train_images.shape}")


print(f"Rozmiar danych walidujących: {validation_images.shape}")
print(f"Rozmiar danych testujących: {test_images.shape}")
print(f"Rozmiar etykiet uczących: {train_labels.shape}")
print(f"Rozmiar etykiet walidujących: {validation_labels.shape}")
print(f"Rozmiar etykiet testujących: {test_labels.shape}")

W kolejnym etapie tworzymy obiekty do których będzie odwoływać się Keras w celu pobierania
porcji danych. Obiekty są dostosowane do pobierania danych w porcjach (ang. batch),

155
udostępniania danych do procesora GPU, rozpraszania danych między wieloma węzłami
obliczeniowymi.
Python
train_ds = tf.data.Dataset.from_tensor_slices( (train_images, train_labels) )
test_ds = tf.data.Dataset.from_tensor_slices( (test_images, test_labels) )
validation_ds = tf.data.Dataset.from_tensor_slices( (validation_images, validation_labels) )

train_ds_size = tf.data.experimental.cardinality(train_ds).numpy()
test_ds_size = tf.data.experimental.cardinality(test_ds).numpy()
validation_ds_size = tf.data.experimental.cardinality(validation_ds).numpy()

print(f"Training data size: {train_ds_size}")


print(f"Test data size: {test_ds_size}")
print(f"Validation data size: {validation_ds_size}")

Następnie definiujemy funkcję, która przeprowadzi standaryzację obrazów wejściowych (-1.7... do


1.7...) oraz przeskaluje obrazy do wymiaru zgodnego z siecią AlexNet (z uwagi na konfigurację
wejść sieci obrazy muszą być rozmiarów 227x227 pixeli). Tworzymy potoki (ang. pipes), których
zadaniem jest przetwarzanie obrazów w locie, utworzenie ich małych podzbiorów (ang. batch) oraz
losowe wybieranie danych ze zbioru (ang. shuffle).
Python
def process_images(image, label):
image = tf.image.per_image_standardization(image)
image = tf.image.resize(image, [227,227] )
return image, label

train_ds = (train_ds
.map(process_images)
.shuffle(buffer_size=train_ds_size)
.batch(batch_size=32, drop_remainder=True))
test_ds = (test_ds
.map(process_images)
.shuffle(buffer_size=test_ds_size)
.batch(batch_size=32, drop_remainder=True))
validation_ds = (validation_ds
.map(process_images)
.shuffle(buffer_size=validation_ds_size)
.batch(batch_size=32, drop_remainder=True))

Tworzymy funkcję zwracającą pustą konfigurację modelu z architekturą sieci AlexNet. Trzy
ostatnie warstwy modelu stanowią oryginalny klasyfikator, który zignorujemy w naszym modelu.
Python
def AlexNet():
NUMBER_OF_CLASSES = 1000
return keras.models.Sequential([
keras.layers.Conv2D(name='conv1', filters=96, kernel_size=(11,11), strides=(4,4),
activation='relu', input_shape=(227,227,3)),
keras.layers.BatchNormalization(),
keras.layers.MaxPool2D(pool_size=(3,3), strides=(2,2)),
keras.layers.Conv2D(name='conv2', filters=256, kernel_size=(5,5), strides=1,
activation='relu', padding="same", groups=2),
keras.layers.BatchNormalization(),
keras.layers.MaxPool2D(pool_size=(3,3), strides=(2,2)),

156
keras.layers.Conv2D(name='conv3', filters=384, kernel_size=(3,3), strides=(1,1),
activation='relu', padding="same"),
keras.layers.BatchNormalization(),
keras.layers.Conv2D(name='conv4', filters=384, kernel_size=(3,3), strides=(1,1),
activation='relu', padding="same", groups=2),
keras.layers.BatchNormalization(),
keras.layers.Conv2D(name='conv5', filters=256, kernel_size=(3,3), strides=(1,1),
activation='relu', padding="same", groups=2),
keras.layers.BatchNormalization(),
keras.layers.MaxPool2D(pool_size=(3,3), strides=(2,2)),
keras.layers.Flatten(),
keras.layers.Dense(4096, name='fc6', activation='relu'),
keras.layers.Dropout(0.5),
keras.layers.Dense(4096, name='fc7', activation='relu'),
keras.layers.Dropout(0.5),
keras.layers.Dense(NUMBER_OF_CLASSES, name='fc8', activation='softmax')
])

# tworzymy model

model = AlexNet()
model.summary()

Następnie pobieramy wartości wag nauczonej wstępnie sieci AlexNet. Oryginalne źródło danych:
http://www.cs.toronto.edu/~guerzhoy/tf_alexnet/bvlc_alexnet.npy. Wczytujemy plik ze
słownikiem numpy. Zawierającym macierze z wagami poszczególnych warstw sieci AlexNet i
ostatecznie ustawiamy wagi z oryginalnego AlexNeta nauczone na milionach obrazów z tysiącem
różnych klas.
Python
!wget -O bvlc_alexnet.npy
https://cloud.ee.pw.edu.pl/nextcloud/index.php/s/3RWeqX94WjF8Nyg/download

net_data = np.load(open("bvlc_alexnet.npy", "rb"), encoding="latin1", allow_pickle=True).item()

display(net_data.keys())

model.get_layer('conv1').set_weights(net_data["conv1"])
model.get_layer('conv2').set_weights(net_data["conv2"])
model.get_layer('conv3').set_weights(net_data["conv3"])
model.get_layer('conv4').set_weights(net_data["conv4"])
model.get_layer('conv5').set_weights(net_data["conv5"])

model.get_layer('fc6').set_weights(net_data["fc6"])
model.get_layer('fc7').set_weights(net_data["fc7"])
model.get_layer('fc8').set_weights(net_data["fc8"])

# sama architektura sieci nie uległa zmianie, wczytaliśmy wyłącznie wagi.

model.summary()

Kopiujemy tyko warstwy konwolucyjne odpowiedzialne za ekstrakcję cech i włącznie z warstwą


flatten (która zamienia nam wielowymiarowe wyjście na wektor jednowymiarowy). To będzie
wejście ostatecznego klasyfikatora. Blokujemy uczenie dla warstw konwolucyjnych, aby nie
zniszczyć oryginalnie nauczonej sieci. Dodatkowo, przyspieszymy uczenie i polegamy na
ekstrakcji cech z już nauczonej sieci.

157
Python
new_model = tf.keras.models.Sequential(model.layers[:-5])
new_model.summary()

for l in new_model.layers:
l.trainable = False

Kopiujemy warstwy konwolucyjne z AlexNeta i dodajemy własne warstwy klasyfikacyjne.


Ostatecznie kompilujemy model z optymalizatorem stochastycznym największego spadku (ang.
Stochastic Gradient Descent). Ustalamy współczynnik uczenia Learning Rate (lr).
Python
# Automatycznie liczymy liczbę unikalnych klas w zbiorze uczącym.

numClasses = np.unique(train_labels).shape[0]
numClasses

i = 1
layers = new_model.layers + [
keras.layers.Dense(500+35*i, activation='relu'),
keras.layers.Dropout(0.2+0.23*np.random.uniform(0,1)),
keras.layers.Dense(numClasses, activation='softmax')
]

new_model_transfer = tf.keras.models.Sequential(layers)
display(layers)

new_model_transfer.compile(loss='sparse_categorical_crossentropy',
optimizer=tf.optimizers.SGD(lr=0.005),
metrics=['accuracy'])
new_model_transfer.summary()

W kolejnym fragmencie tworzymy narzędzie do augmentacji danych w którym definiujemy cztery


rodzaje augmentacji.
Python
from tensorflow.keras.preprocessing.image import ImageDataGenerator
#help(ImageDataGenerator)
datagen = ImageDataGenerator(rotation_range=20,
width_shift_range=0.1,
height_shift_range=0.1,
zoom_range=0.1,
vertical_flip=True
)
datagen.fit(train_images)

Konwertujemy obrazy do odpowiedniego rozmiaru - zgodnego z wejściem AlexNeta.


Python
train_images_processed = []
for img, lbl in zip(train_images, train_labels):
i,l = process_images(img,lbl)
train_images_processed.append(i)
train_images_processed = np.array( train_images_processed )

# tylko sprawdzmy czy wszystko poszło ok.


img = train_images_processed[1,:,:,:].copy()

158
img = (img -np.min(img)) * 255 / (np.max(img) - np.min(img))
plt.imshow(img.astype(np.uint8))
train_images_processed.dtype

Na końcu przechodzimy do procesu uczenia sieci oraz sprawdzamy jej dokładność, oraz
wyświetlamy przebiegi procesu uczenia dla danych walidacyjnych i testowych zaprezentowane na
rys. 9.6.
Python
# uczenie z augmentacją
history = new_model_transfer.fit(datagen.flow(train_images_processed, train_labels,
batch_size=16), epochs=30, validation_data=validation_ds,
validation_freq=1)

# uczenie bez augmentacji


#new_model_transfer.fit(train_ds, epochs=40, validation_data=validation_ds,
# validation_freq=1)

f,ax = plt.subplots(1,2, dpi=150, figsize=(9,3))


ax[0].plot(history.history['loss'], label='Test Loss')
ax[0].plot(history.history['val_loss'], label='Validate Loss')
ax[0].set_title("Loss")
ax[0].legend()
ax[1].plot(history.history['accuracy'], label='Test Accuracy')
ax[1].plot(history.history['val_accuracy'], label='Validate Accuracy')
ax[1].set_title("Accuracy")
ax[1].legend()

Rys. 9.6 Wyniki uzyskane dla sieci pre-trenowanej sieci AlexNex z wykorzystaniem własnych
warstw klasyfikacyjnych.

Na końcu sprawdzamy jakość uzyskanego modelu wykonując ewaluację. Na poniższym


fragmencie dla przykładowego rozkładu danych uczących i testowych uzyskano wynik 0.9219.
Python
new_model_transfer.evaluate(test_ds)

159
2/2 [==============================] - 1s 309ms/step - loss: 0.2674 - accuracy: 0.9219
[0.26736074686050415, 0.921875]

Jako dodatek prześledźmy, jak możemy wykorzystać wytrenowaną sieć do wykonania predykcji.
Wykorzystując metodę głosowania większościowego wybieramy klasę. Technicznie określamy
numer kolumny w każdym wierszu zwracanym przez sieć pred o wartości największego
prawdopodobieństwa. Pamiętamy, że biblioteka Keras obliczy wartości dla całego podzbioru batch
zawierającego 32 obrazy, zwróci zatem macierz o rozmiarach: 32 wierszy na 20 kolumn.
Python
images = []
y_true = []
y_pred = []
for batch in test_ds:
pred = new_model_transfer.predict(batch[0])
for idx, (prawdopodobienstwo, oczekiwane) in enumerate(zip(pred, batch[1])):
images.append(batch[0][idx,:,:,:]) # zapamietaj skojarzony obrazek
y_true.append(oczekiwane) # zapamiętaj wartosć rzeczywistą
y_pred.append(np.argmax(prawdopodobienstwo)) # zapamiętaj pozycję z największym
prawdopodobieństwem

y_true = np.array(y_true)
y_pred = np.array(y_pred)

confusion_matrix(y_pred, y_true)

array([[3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]])

print(classification_report(y_pred, y_true))

precision recall f1-score support

0 1.00 1.00 1.00 3


1 1.00 1.00 1.00 3
2 1.00 1.00 1.00 2
3 1.00 1.00 1.00 4
4 1.00 1.00 1.00 5
5 1.00 1.00 1.00 3
6 0.50 0.50 0.50 2
7 0.67 1.00 0.80 2
8 1.00 0.83 0.91 6

160
9 1.00 0.50 0.67 2
10 0.80 1.00 0.89 4
11 1.00 1.00 1.00 4
12 1.00 0.50 0.67 2
13 1.00 1.00 1.00 5
14 1.00 1.00 1.00 3
15 0.67 1.00 0.80 2
16 1.00 0.75 0.86 4
17 0.80 1.00 0.89 4
18 1.00 1.00 1.00 1
19 1.00 1.00 1.00 3

accuracy 0.92 64
macro avg 0.92 0.90 0.90 64
weighted avg 0.94 0.92 0.92 64

9.5 Inne rozwiązania pre-trenowanej architektury sieci CNN


Sieci CNN ze względu na ich uniwersalność i prostotę użycia w przetwarzaniu obrazów
zyskały wiele różnych rozwiązań, poprawiających działanie i ułatwiających uczenie sieci. Istnieje
aktualnie wiele dostępnych struktur CNN, wytrenowanych wstępnie i dostosowanych do operacji
„transfer learning”. Można tu wymienić między innymi:
• GoogLeNet – zaprojektowany przez zespół Google, operuje zmniejszoną liczbą parametrów
podlegających uczeniu (z 61 milionów w AlexNet do 7 milionów) przez wprowadzenie
modułu wstępnego przetwarzania. Poza tym stosuje Average Pooling zamiast Max Pooling, co
zmniejsza utratę informacji w kolejnych etapach przetwarzania. Aktualnie programy z tej serii
są stale ulepszane pod nazwą inception [81].
• ResNet ukształtowany przez zespół Kaiming He [31]. Główną nowością jest pomijanie
pewnych powiązań między sąsiednimi warstwami i występowanie powiązań z dalszą warstwą,
jak również zastosowanie tzw. batch normalization, czyli normalizacji zastosowanej do
małego zbioru próbek uczących (wartość średnia zerowa i jednostkowa wariancja). Taka
normalizacja zdecydowanie przyspiesza proces uczenia. Architektura unika również warstw
końcowych globalnie połączonych.
• EfficientNet – model skalowanej sieci CNN zaproponowany przez M. Tana i Q.V. Le [76,83].
Cechą charakterystyczną tej architektury jest dobór odpowiednich proporcji parametrów skali
dotyczących głębokości (liczba warstw), szerokości (liczba równolegle tworzonych obrazów w
warstwie) oraz rozdzielczości obrazów w poszczególnych warstwach. Metodya stosowalna do
dowolnej architektury sieci.

161
• U-NET – struktura sieci CNN opracowana przez zespół Ronnebergera [70] dostosowana
specjalnie do zadań segmentacji obrazów, zwłaszcza medycznych. Pozwala na odtworzenie
poszczególnych rejonów obrazów w pełnej rozdzielczości.
Matlab ma zaimplementowane wiele gotowych (pre-trenowanych) prototypów takich sieci.
Poniżej przedstawione są dostępne aktualnie w Matlabie (Matlab 2021b) modele pre-trenowane
oraz ich podstawowe parametry: depth (głębokość), size (wymagana pamięć minimalna),
parameters (liczba adaptowanych parametrów sieci) oraz image input size (wymagany wymiar
obrazów wejściowych).

Tabela 9.1 Lista sieci głębokich pre-trenowanych w środowisku Matlab [48]. Parametry dotyczą
głębokości, wielkości, liczby parametrów podlegających uczeniu oraz wielkość obrazu wejściowego do
modelu.

Jak widać różne rozwiązania sieciowe są mocno zróżnicowane pod wieloma względami.
Najmniejsza liczba adaptowanych parametrów to 1.24 miliona w sieci squeezenet, podczas gdy

162
największa sieć vgg19 zawiera 144 milionów parametrów. Różne są również wymagania dotyczące
wymiaru obrazów wejściowych dla sieci: 224x224, 227x227, 256x256, 299x299 czy nawet
331x331. Badania eksperymentalne porównujące różne rozwiązania pokazują, że poszczególne
rodzaje sieci są zbliżone do siebie pod względem dokładności. Różnice w architekturze wynikają
głównie ze specyfiki zastosowań, zwłaszcza w przypadku rozwiązań do zadań mobilnych.
Jednym z problemów w sieciach wielowarstwowych jest zanikanie bądź eksplozja wartości
gradientu w procesie uczenia. Przy wzrastającej liczbie warstw ukrytych obserwowany był nawet
wzrost błędu dopasowania. Rozwiązanie, zwane Resnet, zaproponowane w [31] polegało na
wprowadzeniu dodatkowego połączenia między-warstwowego o tym samym kierunku przepływu
sygnałów. Sposób połączenia przedstawiony jest na rys. 9.7, w którym operacje sumowania
dotyczą wszystkich elementów poszczególnych warstw.

Rys. 9.7 Podstawowy blok residualny w sieci Resnet.

Idea rozwiązania polega a zastąpieniu odwzorowania F(x) reprezentowanego przez 2 warstwy


konwolucyjne poprzez odwzorowanie F(x)+x. Oznacza to, że w rzeczywistości wagi sieci
adaptowane są w procesie uczenia do odwzorowania resztkowego (residualnego) F(x)-x.
Przykładowy fragment struktury sieci Resnet przedstawiony jest na rys. 9.8. Bloki konwolucji
składają się z operacji konwolucji, batch normalization oraz funkcji nieliniowej ReLU.

Rys. 9.8 Przykładowy fragment struktury Resnet.

163
Linie ciągłe dotyczą połączeń międzywarstwowych o tych samych wymiarach macierzy.
Połączenie kropkowane dotyczy przypadku, gdy wymiary warstwy startowej i docelowej różnią
się (warstwa startowa 256×256, warstwa docelowa 128×128. . Zmniejszanie wymiaru między
warstwami uzyskane jest dzięki parametrowi stride (krok przesunięcia filtra konwolucyjnego)
równemu 2. W przypadku odwrotnym, gdy wymiary bloku startowego są mniejsze niż docelowego
wymiary x uzupełnia się przez dodanie odpowiedniej liczby zer (tzw. zero padding).
Przykład bardziej złożonej struktury Resnet o 34 warstwach parametrycznych z
powiązaniami residualnymi przedstawia rys. 9.9 (Resnet34).

Rys. 9.9 Struktura sieci Resnet34 [31,49]

Ważnym problemem występującym w sieciach CNN jest ogromna liczba parametrów


adaptowanych w procesie uczenia. Przykładowo, w pierwszym rozwiązaniu sieci AlexNet ich
liczba sięga 61 milionów. Oznacza to duże koszty czasowe uczenia takiej sieci jak również jej
implementacji scalonej. Stąd wysiłek wielu badaczy jest skierowany na zredukowanie liczby
parametrów poprzez odpowiednią modyfikację struktury sieci i sposobu przetwarzania sygnałów.
Stosowane są przy tym różne strategie. Jedną z nich jest częściowe zastępowanie większych
filtrów, np. 3x3 poprzez filtr 1x1. Szczególnie interesujący jest zastosowanie w konwolucji filtru
1x1, tworzącego konwolucję punktową (ang. Pointwise convolution - PConv). Jego zastosowanie
oznacza automatycznie wielokrotną redukcję liczby parametrów w procesie przetwarzania. Innym
kierunkiem jest zmniejszenie liczby kanałów (obrazów) wejściowych poddanych filtracji. W
procesie konwolucji dzieli się zbiór obrazów na określona liczbę podzbiorów i do każdego
podzbioru obrazów stosowana jest konwolucja grupowa (ang. Group Convolution - GConv), czyli
tworzenie wielu obrazów wynikowych przez zastosowanie różnych filtrów. Jeszcze inne
rozwiązanie to w procesie tworzenie nowego obrazu (konwolucji) brać pod uwagę jedynie jeden
obraz wejściowy. Jet to technika nazwana Depthwise separable Convolution (DWConv).
Tego typu rozwiązania zastosowano w sieci SqueezeNet [36], wprowadzając specjalne
moduły przetwarzania (tzw. Fire module), przedstawione na rys. 9.10a.

164
b)

Rys. 9.10 Organizacja warstwy konwolucyjnej w SqueezeNet, stanowiącej Fire module (a).
Obrazy wejściowe przechodzą przez warstwę zwężającą (squeeze) złożoną z filtrów 1x1.
Następnie przetwarzane są w drugiej warstwie rozszerzającej (expand) zawierającej filtry 1x1
oraz 3x3. Liczba filtrów w obu warstwach jest dobierana przez użytkownika. Rysunek b
przedstawia typową strukturę sieci sqeezenet [36]. Bloki Conv1 i Conv10 oznaczają zwykłe
(typowe dla CNN) rozwiązanie konwolucji. Maxpool/2 oznacza operacje max poolingu
zmniejszającą dwukrotnie wymiary obrazów wejsciowych.

Dla zmniejszenia złożoności przetwarzania liczba filtrów 1x1 w warstwie squeeze (a więc i liczba
obrazów wyjściowych tej podwarstwy poddanych następnie konwolucji w warstwie
rozszerzającej) jest mniejsza niż suma filtrów 1x1 i 3x3 w warstwie expand, co redukuje skutecznie
liczbę adaptowanych parametrów. W zaproponowanej strukturze sieci (rys. 9.10b) stosuje się 8
modułów „Fire” zakończonych warstwą con10 o 1000 obrazach wyjściowych poddanych operacji
global average pooling (każdy obraz jest zastąpiony jedną wartością średnią stopnia jasności

165
wszystkich pikseli) tworzących 1000 sygnałów wejściowych dla warstwy softmax (brak w sieci
warstw w pełni połączonych). Szczegóły dotyczące doboru liczby filtrów w poszczególnych
warstwach znaleźć można w pracy [36].
Dzięki wprowadzonym modułom Fire udało się zredukować liczbę parametrów adaptowanych do
1.24 miliona uzyskując na bazie danych ImageNet tę samą dokładność co AlexNet o 61 milionach
parametrów.
Inne rozwiązanie problemu zmniejszenia wymiarów sieci (liczby parametrów poddanych
adaptacji) i zmniejszenia liczby operacji zmiennoprzecinkowych w procesie uczenia zostało
zastosowane w sieci ShuffleNet [92]. Idea przyśpieszenia obliczeń polega na grupowaniu filtrów
1x1 w grupy operujące na zredukowanej liczbie kanałów (obrazów) wejściowych, a nie na całym
zbiorze obrazów warstwy poprzedniej. Tworzy się równolegle wiele grup operujących na
wybranych losowo podgrupach obrazów wejściowych. Niestety część informacji globalnej
uzyskanej z takiego grupowego przetworzenia nie wykazuje wzajemnych relacji, ponieważ
przetworzeniu podlegały inne zestawy obrazów wejściowych. Stąd autorzy sieci zaproponowali w
następnym etapie przetasowanie podgrup (operacja shuffle). Każda grupa wytworzona w etapie
poprzednim podlega podziałowi na wiele podgrup. Podgrupy te po przetasowaniu tworzą zestawy
obrazów zasilające warstwę następną. Typowy schemat przetwarzania w ramach jednej warstwy
przedstawiony jest na rys. 9.11 [92].

Rys. 9.11 Schemat przetwarzania grupowego punktowego (1x1) połączonego z przetasowaniem


zastosowane w ShuffleNet: a) ilustracja procesu grupowania i przetasowania, b) schemat
komórki podstawowej sieci: GConv oznacza konwolucję typu grupowego, DWConv –

166
konwolucja z użyciem pojedynczego obrazu wejściowego, BN – normalizacja danych w zbiorze
MiniBatch, Concat – konkatenacja (złączenie) danych z obu kanałów.
W sumie sieć ShuffleNet ma głębokość równą 50 (liczba wszystkich warstw równa 203). Udało
się zredukować liczbę parametrów adaptowanych do 1.4 miliona przy porównywalnej do
AlexNet dokładności działania.
Inne rozwiązanie problemu przyspieszenia obliczeń poprzez zmniejszenie złożoności
obliczeniowej zaproponowane zostało w sieci MobileNet [33]. W sieci tej stosuje się 2 rodzaje
konwolucji. Pierwsza z nich tzw. DWConv stosująca pojedynczy filtr do każdego kanału
(obrazu). Następuje po niej drugi etap konwolucji punktowej PConv, stosującej filtr 1x1
działający na sumie obrazów wytworzonych w etapie poprzednim. Jest to zasadnicza różnica w
stosunku do klasycznego rozwiązania konwolucyjnego, w którym filtracja i sumowanie jej
wyników w tworzeniu obrazów wyjściowych dotyczyło wielu obrazów wejściowych na raz i
występowało dla każdego nowo tworzonego obrazu.

Rys. 9.12 Schemat działania typowej warstwy w sieci MobileNet

W efekcie organizacja przetwarzania sygnałów w warstwie może być przedstawiona jak na


rys. 9.12., na którym 3x3 DepthWise Conv (DWConv) dotyczy działania filtru 3x3 na
pojedynczym obrazie, a 1x1 Conv dotyczy klasycznej konwolucji punktowej z filtrem 1x1
działającym na zbiorze wszytkich wygenerowanych obrazach. BN oznacza operację normalizacji
na podzbiorze MiniBatch, a ReLU funkcję nieliniową aktywacji. W efekcie uzyskuje się dużą
redukcję wymiarów sieci. Zaproponowane rozwiązanie MobileNetv2 w Matlabie zredukowało
wymiar sieci do 13MB przy głębokości 53 i 3.5 miliona adaptowanych parametrów.
Ciekawym krokiem w rozwoju sieci głębokich było opracowanie struktury GoogLeNet
(traktowana później jako Inception-v1). Idea modyfikacji polega na prowadzeniu równolegle
działających filtrów o różnych wymiarach. Każdy z takich filtrów specjalizuje się w rejonach
obrazu o różnej skali szczegółowości. Inną modyfikacją było rozszerzanie sieci wszerz, a nie tylko

167
w głąb. Autorzy rozwiązania wprowadzili równolegle działające bloki konwolucyjne stosujące
filtry o wymiarach 1×1, 3×3 oraz 5×5. Blok o małych wymiarach 1×1 odpowiedzialny jest za
liniową redukcję wymiarowości obrazu wejściowego jednocześnie pozwalając na zmniejszenie
czasu obliczeń, w stosunku do większych filtrów konwolucyjnych. Rolę taką pełni komórka zwana
Inception. Struktura takiej komórki przedstawiona jest na rys. 9.13.

Rys. 9.13 Struktura komórki Inception [81].

Komórka Inception zawiera 4 równolegle połączone gałęzie i w każdej z nich występuje


konwolucja 1×1 jako sposób redukcji wymiarowości problemu i złożoności obliczeniowej.

Rys. 9.14 Architektura sieci GoogLeNet [49].

Struktura sieci GoogLeNet składa się z 9 połączonych ze sobą komórek Inception, jak to
przedstawiono na rys. 9.14. Zawiera w sumie około 100 niezależnych bloków, przy czym
głębokość liczona w liczbie warstw podlegających uczeniu jest równa 22 (nie wliczając warstwy

168
typu pooling). Jak podają autorzy uczenie takiej sieci jest bardzo czasochłonne (około tygodnia
przy zastosowaniu kilku GPU pracujących w trybie równoległym).
Dalsze prace zespołu rozwijały powyższy model pod zmienioną nazwą Inception. Powstało
kilka kolejno ulepszanych struktur komórki Inception i połączeń warstwowych. Jedną z nich jest
hybryda różnych modeli Inception i ResNet, czyli InceptionResNet-v2, w której dodano podejście
residualne do komórek Inception. Przykład tak zmodyfikowanej struktury komórki przedstawiono
na rys. 9. 15.

Rys. 9.15 Jedna z wersji komórki Inception z połączeniem residualnym [81]

Badania nad skutecznością działania sieci CNN pokazały, że dużą rolę odgrywa dobór
odpowiednich proporcji między głębokością (depth) architektury traktowaną jako liczba warstw
konwolucyjnych, liczbą równolegle tworzonych obrazów wynikowych w poszczególnych
warstwach (width) oraz rozdzielczością obrazów tworzonych w poszczególnych warstwach
(resolution). Rys. 9.16 przedstawia ideę skalowania sieci Efficientnet, stworzona przez M. Tana i
Q.V. Le [83].

169
Rys. 9.16 Ilustracja idei skalowania szerokości (width scaling), głębokości (depth scaling),
rozdzielczości (resolution scaling) oraz równoległego skalowania wszystkich wymienionych
wyżej parametrów (compound scaling).

Odpowiednie zwiększenie skali dotyczącej głębokości, szerokości i rozdzielczości w stosunku do


struktury konwencjonalnej (baseline) pozwala uzyskać znacznie większą dokładność klasyfikatora
przy znakomicie zmniejszonej złożoności obliczeniowej [76,83]. W pracy tej pokazano
porównanie uzyskanej dokładności różnych rozwiązań sieciowych przy odpowiadającej sobie
liczbie operacji zmiennoprzecinkowych, wykazując zdecydowaną przewagę sieci EfficientNetB6
w problemie benchmarkowym „ImageNet”.
Oryginalnym rozwiązaniem sieci konwolucyjnych jest sieć DenseNet operująca wieloma
połączeniami między-warstwowymi w przód [35]. W klasycznym rozwiązaniu CNN
przekazywanie sygnałów następuje kolejno z warstwy na warstwę sąsiadującą (brak połączeń
między odległymi warstwami). W efekcie traci się wiele istotnych informacji, obserwując
jednocześnie zanikanie gradientu (skorygowane w sieci Resnet). Poza tym nie wykorzystuje się
bezpośrednio oryginalnych cech wytworzonych w warstwach wcześniejszych osłabiając w efekcie
ich działanie. Struktura przetwarzania sygnałów zaproponowana przez autorów [35] przedstawiona
jest na rys. 9.17.

170
Rys. 9.17 Struktura ogólna przepływu sygnałów w Dense bloku wykorzystywana w sieci
DenseNet.

Sygnały wyjściowe poszczególnych warstw przekazywane są bezpośrednio nie tylko na warstwę


sąsiednią, ale również na wszystkie warstwy następne. Dzięki temu możliwe stało się ograniczenie
głębokości sieci (liczby warstw). Struktura sieci DenseNet przedstawiona jest na rys. 9.18.

Rys. 9.18 Struktura sieci DenseNet z trzema blokami Dense z rys. 9.16.

Pomiędzy blokami typu Dense stosowane są dodatkowo operacje konwolucji i poolingu. W jej
ramach wykonuje się normalizację danych w MiniBatch, konwolucję jednopunktową filtrem 1x1
oraz operacje 2x2 average pooling. Implementacja DenseNet w Matlabie pod nazwą densenet201
zawiera 20 milionów adaptowanych parametrów i głębokość równą 201. Jej skuteczność jest
porównywalna z najlepszymi rozwiązaniami sieci.

9.6 Sieci CNN do detekcji obiektów w obrazie


9.6.1 Sieć YOLO
Struktury sieci CNN przedstawione wcześniej stosowane są bezpośrednio w rozwiązywaniu zadań
klasyfikacji i regresji, gdzie sieć pracuje w trybie z nauczycielem (na etapie uczenia znane są
stowarzyszone ze sobą pary (x,d)). Oryginalnym obszarem takich zastosowań jest również detekcja
171
obiektów, w której poszukuje się konkretnych obiektów występujących w analizowanych obrazach
(zadanie klasyfikacji). Jest ona połączona ze wskazaniem współrzędnych tych obszarów (zadanie
regresji). W takim rozwiązaniu sieć pracuje więc jednocześnie jako klasyfikator i układ regresyjny.
Jest trenowana na zbiorze obrazów, w których występują poszukiwane obiekty traktowane jako
„destination”. Po zamrożeniu parametrów wytrenowana sieć jest gotowa do wydobycia
nauczonych obiektów z serii obrazów nie uczestniczących w uczeniu.
Ważnym rozwiązaniem w tej dziedzinie jest sieć YOLO (skrót od You Only Look Once),
wykonująca jednocześnie funkcje klasyfikatora i systemu regresyjnego [66]. Służy do wykrywania
określonych obiektów w obrazie (zadanie klasyfikacji) oraz ich umiejscowienia (zadanie regresji).
Obiektami mogą być różne przedmioty występujące na obrazie. Zadanie regresji polega na
określeniu współrzędnych wykrytych obiektów. Opracowany system dzieli analizowany obraz na
siatkę komórek o wymiarach SxS. Każda komórka jest odpowiedzialna za wykrycie obiektów,
które znajduję się w jej obrębie. Jeśli centrum poszukiwanego obiektu znajdzie się wewnątrz
komórki w siatce, wówczas ta komórka jest odpowiedzialna za wykryty obiekt. Komórka może
być odpowiedzialna za wykrycie jednoczesne B obiektów, wskazując na współczynnik ufności co
do wystąpienia każdego z nich w obrębie danej komórki.
Ważnym elementem rozwiązania jest tu współczynnik ufności IOU (ang. Intersection Over
Union), określający w jakim stopniu w danej komórce występuje pokrywanie się rzeczywistego
pola obwiedni poszukiwanego obiektu z polem prognozowanym obwiedni (tzw. bounding box) dla
wszystkich B badanych obwiedni. Współczynnik ufności C dla danej komórki reprezentuje
prawdopodobieństwo, że określony obiekt znajduje się w obrębie określonej obwiedni (bounding
box). Opisuje się go wzorem
C = Pr(obiekt ) IOU truth
pred (9.18)

gdzie Pr(obiekt) oznacza prawdopodobieństwo wystąpienia obiektu w obwiedni danej komórki a


IOU truth
pred przyjmuje procentową wartość części wspólnej Sintersection powierzchni rzeczywistej i
prognozowanej obwiedni (iloczyn logiczny) do ich całkowitej powierzchni Sunion (suma logiczna)
Sintersection
IOU = (9.19)
Sunion
Rys. 9.19 ilustruje interpretację obu powierzchni. Jeśli określony obiekt nie pojawia się w danej
obwiedni współczynnik ufności jest z definicji równy zeru [66].

172
Rys. 9.19 Ilustracja sposobu obliczania współczynnika IOU.

Jeśli dany obiekt nie występuje w komórce wówczas C=0, w przeciwnym wypadku C= IOU truth
pred dla

danego obiektu. Równolegle z analizą pokrywania się obu obwiedni w komórce obliczane jest
warunkowe prawdopodobieństwo klasy obiektu. Jest ono wyrażone wzorem
Pr(klasai | obiekt ) = Pr(klasai ) IOU truth
pred (9.20)

Przewidywane jest prawdopodobieństwo i-tej klasy obiektu w danej komórce. Warunkowa


przynależność klasowa obiektu do klasy i-tej określana jest według wzoru [66]
Pr(klasai | obiekt )  Pr(obiekt )  IOU truth
pred = Pr(klasai )  IOU pred
truth
(9.21)

Powyższe wyrażenie określa współczynnik ufności wystąpienia klasy i-tej w każdej komórce,
pozwalając określić jak dobrze dana komórka jest dopasowana do obiektu..
Każdy „bounding box” skojarzony z komórką jest charakteryzowany w systemie poprzez kilka
parametrów: (x,y) – współrzędne centrum obiektu mierzone względem danej komórki, (w,h) –
szerokość i wysokość obwiedni (traktowanej jako prostokąt) mierzone względem całego obrazu
oraz współczynnik ufności reprezentujący wartość IOU przewidywanej aktualnie obwiedni obiektu
względem prawdziwej (tzw. ground truth). Każda komórka jest dodatkowo odpowiedzialna za
wykrycie klasy każdego z obiektów i określenia prawdopodobieństwa przynależności klasowej
Pr(klasai|obiekt).
Struktura pierwotnie zaproponowanej sieci YOLO [66] przedstawiona jest na rys. 9.20.
Zawiera 24 warstwy konwolucyjne lokalnie połączone do generacji cech diagnostycznych i dwie
w pełni połączone warstwy odpowiedzialne jednocześnie za zadanie klasyfikacji (rozpoznanie
klasy obiektów) oraz zadanie regresji (określenie współrzędnych wystąpienia poszczególnych
obiektów). Zastosowany wymiar komórki S=7. Wyjściowa warstwa sieci generuje jednocześnie
prawdopodobieństwo przynależności określonej komórki do klasy obiektu (klasyfikacja) oraz
współrzędne obwiedni poszczególnych obiektów (regresja). Sieć używa funkcje aktywacji typu

173
Leaky ReLU. Uczenie sprowadza się do odpowiednio zdefiniowanej funkcji celu w postaci
najmniejszych kwadratów (LMS). Funkcja taka jest złożeniem składników odpowiedzialnych za
klasyfikację oraz składników odpowiedzialnych za regresję. W jego procesie przyjmuje się, że
każda obwiednia (bounding box) skojarzona jest jedynie z jednym obiektem na podstawie
największej wartości IOU.

Rys. 9.20 Struktura sieci YOLO zaproponowana w [49,66].

W międzyczasie powstały różne udoskonalone rozwiązania struktury sieci, charakteryzujące się


większą szybkością przy mniejszej liczbie parametrów podlegających adaptacji w procesie
uczenia. Takim przykładem jest rozwiązanie znane pod nazwą YOLOX [93].

9.6.2 Sieć R- CNN


Innym rozwiązaniem segmentacji wykorzystującym sieci CNN jest R-CNN (ang. Region
based CNN). Istnieje kilka wersji rozwiązań tego typu [17]. W tym punkcie ograniczymy się do
tzw. Faster R-CNN. Ogólna struktura tej sieci przedstawiona jest na rys. 9.21.

174
Rys. 9.21 Struktura sieci R-CNN do detekcji obiektów w obrazie [17]

Rozwiązanie bazuje na zastosowaniu dwu podstruktur CNN. Pierwsza z nich, tzw. Region
Proposal Network (RPN) jest odpowiedzialny za generację cech diagnostycznych i znajduje rejony
obrazu zawierające propozycję ewentualnych obszarów obiektów. Druga część rozwiązania to
struktura CNN, zwana przez autorów RoI pooling (ang. RoI - region of interest) stwierdza
rzeczywiste istnienie bądź negację określonego obiektu (detekcję) w obrazie. Po stwierdzeniu
istnienia obiektu stosuje się w niej max pooling do przetworzenia cech zawartych w każdym
istotnym RoI obrazu w niewielkich wymiarów mapę cech (zwykle 7×7) na podstawie których
definiuje prawdopodobieństwo przynależności badanego RoI obrazu do obiektu i parametry
określające jego wymiar. Obie części sieci wykorzystują strukturę wielowarstwową CNN i
współpracują ze sobą, zarówno w trybie uczenia jak i testowania [17].
RPN przyjmuje na wejściu surowe obrazy podlegające analizie i przekazuje na wyjście (do
warstwy RoI pooling) propozycje prostokątnych rejonów z estymowanym stopniem
przynależności do klas poszukiwanych obiektów. RPN ma strukturę i zasadę działania sieci CNN.
W każdej warstwie używa przesuwającego się filtru (typowy wymiar 3×3) działającego na mapie
cech ostatniej warstwy konwolucyjnej. Sygnał wyjściowy filtru (po operacji ReLU) odpowiadający
każdej pozycji na obrazie jest rzutowany na małowymiarowy wektor cech (typowa wartość 256).
Cechy te stanowią wejście dla dwu w pełni połączonych warstw działających równolegle:

175
• warstwa regresyjna - generująca na wyjściu współrzędne bloków reprezentujących
proponowane rejony odpowiadające pozycji filtru na obrazie,
• warstwa klasyfikacyjna – estymująca przynależność bloków do określonego obiektu.
Każdej pozycji przesuwającego się okna filtrującego przypisuje się wiele propozycji rejonów,
zwanych kotwicami. Ich liczba k jest ustalana z góry. Stąd warstwa regresyjna generuje 4k wartości
(pozycje x, y lewego górnego piksela rejonu, szerokość w oraz wysokość h). Warstwa
klasyfikacyjna generuje 2k wartości estymujących prawdopodobieństwo przynależności oraz
braku przynależności k-tego rejonu do poszukiwanego obiektu, reprezentowanego przez ROI.
Każdy obraz analizowany jest w 3 skalach i dla 3 wartości współczynników kształtu kotwic (1:1,
1:2 oraz 2:1), co daje 9 kotwic dla każdej pozycji filtru. W przypadku obrazu o wymiarach W×H
liczba kotwic jest równa W×H×k.
Uczenie RPN w funkcji klasyfikatora generuje wynik binarny (±1). Znak dodatni (kotwica
pozytywna) przypisany jest kotwicy w dwu przypadkach: gdy jej powierzchnia pokrywa się z
obiektem poszukiwanym w stopniu powyżej 70% lub w przypadku skrajnym, gdy nie ma żadnego
takiego przypadku. Przyjmuje się wówczas kotwice o jak największej wartości współczynnika
pokrycia. Wartość negatywna klasyfikatora (kotwica negatywna) jest generowana, gdy
współczynnik pokrycia kotwicy z obiektem poszukiwanym jest poniżej 30%. Kotwice nie
zaliczone ani do pozytywnych ani negatywnych nie biorą udziału w dalszej procedurze uczenia.
Uczenie RPN polega na minimalizacji funkcji kosztu definiowanej w postaci [17]

 L ( p , p ) +  N  p L (t , t )
1 1
min L ( pi , ti ) = cl i
*
i
*
i reg i
*
i (9.22)
Ncl i reg i

W wyrażeniu tym indeksy i reprezentują kotwice, pi prawdopodobieństwo, że kotwica należy do

obiektu i-tego; pi* przyjmuje wartość 1 gdy kotwica jest pozytywna lub wartość 0 w przypadku

gdy kotwica jest negatywna. Parametr ti reprezentuje 4 wartości charakteryzujące rejon kotwicy (x,
y, w, h) a ti* te same wartości przypisane współrzędnym poszukiwanego obiektu (ground true box)

skojarzonego z dodatnią kotwicą. Składnik klasyfikacyjny funkcji kosztu Lcl ( pi , pi* ) przyjmuje

się w postaci logarytmicznej Lcl ( pi , pi* ) = − log pi gdzie pi reprezentuje estymowaną wartość

prawdopodobieństwa przynależności kotwicy do i-tego obiektu podlegającego wykryciu. Drugi


składnik odpowiada regresji Lreg ( ti , ti* ) = R ( ti − ti* ) , gdzie funkcja R reprezentuje przyjętą miarę

176
różnic między wartościami parametrów (x, y, w, h) przypisanych kotwicy i obiektu poszukiwanego
[17]. Może ona przyjmować różne postacie. Parametr λ stanowi współczynnik regularyzacji części
klasyfikacyjnej i regresyjnej we wzorze (9.17). Przy znormalizowanych wartościach
reprezentujących obiekt przyjmuje się zwykle λ=1.
W uczeniu gradientowym RPN stosuje się metodę SGD (stochastic gradient descent) przy
użyciu tzw. mini-zbiorów (ang. mini-batches) generowanych z określonych losowo obszarów
obrazów ROI (typowa populacja mini-batches przyjmowana w R-CNN jest równa 128 a jej skład
wynika z losowego wyboru ROI z wielu obrazów). Zakłada się przy tym, że przynajmniej 25%
ROI pokrywa się w stopniu 50% z obiektem podlegającym wykryciu. W uczeniu SGD stosuje się
zwykle technikę wspomagającą, wykorzystującą metodę momentu rozpędowego.
W rozwiązaniu R-CNN sieć RPN generuje propozycje obszarów podlegających dalszej
detekcji obiektów reprezentowanych w postaci określonych cech diagnostycznych. Funkcję
detektora pełni sieć Fast R-CNN, pełniąca rolę końcowego dostrajania. Dla przyspieszenia uczenia
i unifikacji rozwiązania obie części systemu (RPN i Fast R_CNN) współpracują ze sobą w
kolejnych cyklach obliczeniowych (tzw. alternative training). Fast R-CNN wykorzystuje jako
wejście rejony wskazane przez RPN, inicjalizując z kolei RPN swoimi wynikami w następnych
cyklach obliczeniowych. Dzięki temu proces detekcji poszukiwanych obiektów w obrazie jest
bardzo szybki [49].
Przykład programu Matlaba wykorzystującego sieć R-CNN do detekcji znaku STOP na
obrazach przedstawiony jest poniżej. W uczeniu zastosowano 27 obrazów zawierających znak
STOP-u i jeden obraz testowy.
MATLAB
% RCNN do detekcji znaku STOP
load('rcnnStopSigns.mat', 'stopSigns', 'layers')
imDir = fullfile(matlabroot, 'toolbox', 'vision', 'visiondata',...
'stopSignImages');
addpath(imDir);
options = trainingOptions('sgdm', ...
'MiniBatchSize', 32, ...
'InitialLearnRate', 1e-6, ...
'MaxEpochs', 10);
% Train the R-CNN detector. Training can take a few minutes to complete.
rcnn = trainRCNNObjectDetector(stopSigns, layers, options, 'NegativeOverlapRange', [0 0.3]);
% Test the R-CNN detector on a test image.
img = imread('stopSignTest.jpg');
[bbox, score, label] = detect(rcnn, img, 'MiniBatchSize', 32);
% Display strongest detection result.
[score, idx] = max(score);
bbox = bbox(idx, :);
annotation = sprintf('%s: (Confidence = %f)', label(idx), score);
detectedImg = insertObjectAnnotation(img, 'rectangle', bbox, annotation);
figure
imshow(detectedImg)

177
Wynik testowania programu na nowym obrazie nie uczestniczącym w uczeniu przedstawiony jest
poniżej na rys. 9.22.

Rys. 9.22 Wynik detekcji znaku STOP z obrazu nie uczestniczącego w uczeniu

9.7 Sieć U-NET w segmentacji obrazów biomedycznych


Segmentacja obrazów biomedycznych ma za zadanie wyłowić w obrazie obszary należące do tej
samej klasy (zbiór pikseli o podobnej jasności). Zadanie należy do bardzo trudnych ze względu na
dużą różnorodność obszarów, zmienność położenia względnego pikseli względem siebie czy
rozmycia granic obszarów jak również rozmycia barw. Jednym ze skutecznych rozwiązań w tym
zakresie jest sieć U-net stworzona przez autorów pracy [70]. Struktura tej sieci przypomina kształt
litery U i zawiera podsieć CNN zwężającą oraz drugą podsieć CNN rozszerzającą, obie
współpracujące ze sobą. Struktura takiej sieci przedstawiona jest na rys. 9.23. Na każdym poziomie
przetwarzania stosowane są 2 warstwy konwolucyjne.

178
Rys. 9.23 Struktura sieci U-net [70].

Obrazy występujące w warstwach zwężających (lewa część sieci) o coraz mniejszych wymiarach
(operacje pooling) zmniejszają rozdzielczość wyników, co powoduje pogorszenie lokalizacji
poszczególnych segmentów. Ta część sieci nazywana jest również enkoderem. W części
rozszerzającej struktury (prawa część sieci) operacja pooling w każdej warstwie jest zastąpiona
przez operację odwrotną (interpolacją) zwaną z angielska upsampling (pooling 2×2 zastępuje 4
piksele przez 1 piksel, natomiast upsampling 2×2 działa odwrotnie: 1 piksel jest replikowany w 4
piksele). Ta część sieci jest również nazywana dekoderem. Sieć U-net nie posiada warstw w pełni
połączonych, typowych w rozwiązaniach klasycznych CNN.
Część zwężająca U-net stosuje konwolucję przy użyciu maski filtrującej 3×3 z krokiem
stride=2, funkcję aktywacji ReLU i max pooling 2×2. W efekcie wymiar mapy cech (obrazu) w
każdej kolejnej warstwie jest zmniejszany dwukrotnie, ale jednocześnie generowana jest liczba
obrazów wzrastająca 2-krotnie.
Warstwy rozszerzające stosują operację interpolacji o wymiarze 2×2, w której jeden piksel
jest zastępowany 4 pikselami. Stosowane są różne metody, na przykład metoda najbliższych
sąsiadów, zastosowanie splinów, itp. Za bardziej optymalną uważa się operację konwolucji
transponowanej, zwanej również dekonwolucją, definiowanej jako operacja odwrotna do

179
konwolucji. Operacja 2×2 dekonwolucji zwiększa 2-krotnie wymiar mapy cech (obrazu
wynikowego) przy dwukrotnie zmniejszonej ich liczbie. Jednocześnie na każdym poziomie
warstwowym interpolacji następuje dołączenie odpowiedniego obrazu niższej rozdzielczości z
części zwężającej (część biała obrazów wejściowych na danym poziomie). Podobnie jak w
warstwie zwężającej stosowana jest konwolucja z filtrem 3×3 i operacja ReLU. W części końcowej
warstwy wyjściowej stosowana jest konwolucja 1×1 tworząca wysegmentowany obraz wyjściowy,
w którym każdy piksel jest reprezentowany przez przypisany do niego numer klasy (podział na
klastry reprezentujące oddzielne segmenty).
Uczenie sieci odbywa się z udziałem obrazów zawierających segmenty opisane przez
eksperta. Proces uczenia ma za zadanie zminimalizować sumę różnic między stopniami szarości
pikseli tworzących ROI segmentu zakreślonego przez eksperta i tych wygenerowanych przez
warstwę końcową sieci U-net (funkcja celu z użyciem definicji entropijnej). Odbywa się to zwykle
przy zastosowaniu metody stochastycznej największego spadku (SGD) z momentem rozpędowym.
Szczegóły można znaleźć w publikacji [70].

9.8 Autoenkoder
9.8.1 Struktura autoenkodera
Autoenkoder jest specjalnym rozwiązaniem sztucznej sieci neuronowej, którego zadaniem jest
skopiowanie danych wejściowych w wyjściowe z akceptowalnym błędem [22,39] za
pośrednictwem warstw ukrytych o zredukowanym wymiarze względem wymiaru danych
wejściowych. Jest to wielowarstwowy układ autoasocjacyjny stowarzyszający dane wejściowe ze
sobą. Struktura składa się z dwu następujących po sobie części: układu kodującego (enkoder)
rzutującego dane wejściowe w postaci wektora x w dane zakodowane reprezentowane przez wektor
h=f(x) i dekodera wykonującego działanie odwrotne rekonstruujące z określoną dokładnością
dane wejściowe x’=g(h). Przykład struktury autoenkodera o jednej warstwie sygnałów
zakodowanych i części dekodującej przedstawiony jest na rys. 9.24. Dane wejściowe w postaci
wektora x są kodowane w wektorze h jako sygnały ukryte (część tworząca enkoder). Dekodowanie
odbywa się w strukturze symetrycznej, odtwarzając za pośrednictwem wektora h’ wektor x’ (część
zwana dekoderem).

180
Rys. 9.24 Przykład struktury autoenkodera zawierający część kodująca (enkoder) i
rekonstrukcję sygnałów wejściowych (dekoder).

Podstawą jego działania jest kompresja danych polegająca na wychwyceniu głównych cech
procesu reprezentowanego przez zbiór wektorów x. Oznacza to, że dane zrekonstruowane x’ nie
reprezentują dokładnych kopii danych wejściowych, ale ich aproksymację. Wektor h stanowiący
podstawę kodowania i następnie rekonstrukcji, reprezentuje zatem cechy główne procesu
eliminując elementy nieistotne (traktowane jako szum) zawarte w zbiorze danych wejściowych x.
Autoenkoder jest uogólnieniem dwuwarstwowej sieci liniowej PCA. Różni go od niej liczba
warstw, która może być dowolna, jak również nieliniowa funkcja aktywacji neuronów stosowana
w przypadku ogólnym.

9.8.2 Funkcja celu


Bezpośrednie, dokładne kopiowanie danych uczących x w siebie nie ma sensu praktycznego,
gdyż nie pozwala na wychwycenie najważniejszych cech procesu zawartych w zbiorze danych
uczących. Dopiero ograniczenie liczby neuronów warstwy ukrytej definiującej kodowanie danych
wejściowych zmusza proces uczenia do wychwycenia cech najważniejszych i pominięcie cech
drugorzędnych, nie mających większego wpływu na wynik rekonstrukcji danych. Proces uczenia

181
sieci może być zdefiniowany jako dobór parametrów (wag neuronowych) prowadzący do
minimalizacji funkcji kosztu (celu) E(x,g(h(x)).
Podstawowa definicja funkcji kosztu przyjmowana jest zwykle w postaci wartości błędu
średniokwadratowego [22] po wszystkich zmiennych n= 1, 2,…,N dla danych uczących przy k=1,
2, …, p, przy czym N jest wymiarem wektora wejściowego a p liczbą danych uczących
(obserwacji).

E =  ( xn − x 'n ) =  ( xn − gn (h(x( k ) ) )
1 N p (k ) (k ) 2 1 N p (k ) 2
(9.23)
p n=1 k =1 p n=1 k =1
Dla uzyskania lepszej odporności autoenkodera na szum w uczeniu stosuje się również wersję
zmodyfikowaną, w której zamiast dopasowywać sygnały wyjściowe g(h(x)) do sygnałów
wejściowych x porównanie z sygnałami x dotyczy odpowiedzi autoenkodera g(h(xs)) na sygnały
zaszumione xs,. Układ przetwarza wówczas xs w taki sposób, aby uzyskać na wyjściu najlepszą
możliwie aproksymację wektorów oryginalnych x. Oznacza to, że funkcja celu podlegająca
minimalizacji przyjmuje zmodyfikowaną formę [22]
1 N p (k )
 ( xn − gn (h(x(sk ) ) )
2
E= (9.24)
p n=1 k =1
Zastosowanie liniowej funkcji aktywacji neuronów przy jednej warstwie ukrytej prowadzi do
znanego rozwiązania PCA. Autoenkoder stosujący nieliniowe funkcje aktywacji i kilka warstw ma
wiele zalet w stosunku do rozwiązania liniowego, z których najważniejsze to [22]
• duża oszczędność (ang. sparsity) w reprezentacji danych,
• ograniczone wartości pochodnej sygnałów,
• krzepkość systemu względem szumu oraz brakujących danych.
Oszczędność autoenkodera może być osiągnięta w procesie uczenia poprzez włączenie do funkcji
kosztu czynnika kary za nadmiernie rozbudowaną strukturę. Wówczas zmodyfikowana
funkcja kosztu E przyjmie postać
E=E(x,g(h(x)))+λΩ1(h) (9.25)
w której wielkość E(x,g(h(x))) reprezentuje klasyczną definicję funkcji kosztów, a  stanowi
współczynnik regularyzacji. Funkcja 1 (h) stanowi karę za zbyt rozbudowaną strukturę układu.
Typowa definicja tej funkcji to

1 (h) =
1
( )
 wij(h)
2 h i, j
2
(9.26)

182
gdzie h reprezentuje warstwy ukryte zastosowane w rozwiązaniu. W wyniku uczenia wymusza się
zmniejszenie wartości wag określonych grup neuronów. W efekcie pewne połączenia synaptyczne
o małej wartości wag mają minimalny wpływ na działanie systemu.
Dla dalszego zmniejszenia wpływu zmian danych wejściowych x na wynik działania
układu wprowadza się regularyzację uwzględniającą pochodne sygnałów warstwy ukrytej
względem elementów wektora wejściowego x. Funkcja regularyzacyjna przyjmuje wówczas
następującą formę [22]
H
2 (h, x) =   x hi
2
(9.27)
h =1

w której  x hi oznacza wektor pochodnych sygnałów hi warstw ukrytych względem składowych

wektora wejściowego x. Taki rodzaj regularyzacji zmusza algorytm uczący do wytworzenia


sygnałów wyjściowych sieci, które zmieniają się niewiele przy niewielkich zmianach wartości
sygnałów wejściowych.
Inny rodzaj regularyzacji autoenkodera uwzględnia zgodność średniej statystycznej
aktywacji neuronów ̂ i w aktualnym stanie uczenia z jej wartością pożądaną  i . Wartość

aktualna jest określona dla pojedynczego neuronu warstwy ukrytej w postaci


1
𝜌̂𝑖 = ∑𝑝𝑗=1 ℎ𝑖 (𝒙𝑗 ) (9.28)
𝑝

gdzie p oznacza liczbę obserwacji (wektorów x). Mała wartość średniej aktywacji neuronu
oznacza, że neuron ten aktywuje się jedynie dla niewielkiej ilości danych wejściowych,
specjalizując się w ich reprezentacji. Dodając taki czynnik do minimalizowanej funkcji kosztu
zmusza się neurony do reprezentowania jedynie określonych (specyficznych) cech procesu.
W praktyce ten czynnik regularyzacyjny definiuje się z wykorzystaniem dywergencji
Kullbacka-Leiblera, mierzącego zgodność wartości aktualnej z pożądaną wartością średniej
funkcji aktywacji dla określonego zbioru danych. Składnik regularyzacyjny definiuje się w postaci
[22]
   1 − i 
3 (  ) =  i log  i  + (1 − i ) log   (9.29)
i  ˆi   1 − ˆi 
Regularyzacja Kulbacka-Leiblera jest statystyczną miarą zgodności dwu rozkładów
stochastycznych. Przyjmuje małą wartość, przy niewielkiej niezgodności i wartość zerową gdy
ˆ i =  i . Przy wzrastającej niezgodności miara ta rośnie.

183
W praktyce definiuje się wartość pożądaną stosunku i / ˆ i (w Matlabie [38] jest to

parametr zwany 'SparsityProportion' przyjmujący wartość dodatnią z przedziału [(0, 1) z wartością


wbudowaną 0.05). Dzięki zastosowaniu tego typu regularyzacji poszczególne neurony ukryte
„specjalizują” się w wytwarzaniu dużego sygnału jedynie dla małej liczby danych uczących
(lokalizacja aktywności) co oznacza w ogólności lepsze, bo wyspecjalizowane działanie sieci.
W efekcie, w procesie uczenia minimalizacji podlega funkcja kosztu zmodyfikowana o
poszczególne rodzaje czynników regularyzacyjnych. W ogólności zadanie minimalizacji może
przyjąć następującą postać [22,49]

min E =  ( xn − gn (h(x( k ) ) ) + 11 (h) +22 (h, x) + 33 (  )


1 N p (k ) 2
(9.30)
p n=1 k =1
w której współczynniki λi (dobierane przez użytkownika) stanowią wagi, z jakimi poszczególne
funkcje regularyzacyjne wpływają na wartość funkcji kosztu. Taka postać wymusza kompromis
między zgodnością zrekonstruowanego sygnału wyjściowego układu z wartościami wejściowymi
a złożonością tego układu, uwzględniając jednocześnie wrażliwość na niewielkie zmiany mogące
nastąpić w rozkładzie wartości sygnałów wejściowym w trybie odtwarzania.

9.8.3 Proces uczenia


Istnieją różne implementacje algorytmu uczącego. Najbardziej popularne podejście polega
na stopniowym uczeniu następujących po sobie warstwach. Proces rozpoczyna się w warstwie
pierwszej, dla której sygnałami wejściowymi są sygnały oryginalne opisane wektorem x, a sygnały
wyjściowe oznaczone są jako x̂ . Celem uczenia jest dobór liczby neuronów ukrytych i wag tych
neuronów, które zapewnią właściwe (zgodnie z regularyzowaną funkcją celu) odtworzenie
sygnałów wejściowych w warstwie wyjściowej (rys. 9.25a). W tej sytuacji sygnały warstwy ukrytej
stanowią kod sygnałów wejściowych dla następnej warstwy, a warstwa wyjściowa podlega
eliminacji.

184
a)

b)
Rys. 9.25 Ilustracja sposobu kształtowania pierwszej warstwy ukrytej: a) struktura stosowana w
uczeniu, b) postać wyjściowa sieci dla doboru następnej warstwy.

Po doborze parametrów warstwy ukrytej odrzuca się warstwę rekonstrukcji i sygnały z warstwy
ukrytej stają się wejściowymi dla następnej warstwy (rys. 9.25b). Proces uczenia jest
kontynuowany dla następnej warstwy, dobierając jej parametry w taki sposób, aby uzyskać

185
możliwie najlepsze odwzorowanie sygnałów wejściowych a w sygnały wyjściowe. W efekcie po
odrzuceniu warstwy wyjściowej sieć zawiera dwie warstwy neuronowe a i b jak to pokazano na
rys. 9.26, przy czym liczba neuronów w każdej kolejnej warstwie jest kolejno redukowana w
identyczny sposób jak to miało miejsce w przypadku pierwszej warstwy ukrytej, zmuszając sieć
do kompresji danych.

Rys. 9.26 Struktura sieci po następnym etapie uczenia autoenkodera.

Sygnały warstwy ukrytej b stają się ponownie sygnałami wejściowymi dla ukształtowania
następnej warstwy o dalej zredukowanej liczbie neuronów Proces jest następnie kontynuowany dla
następnych warstw, w sposób identyczny do omówionego. Kształtowanie kolejnych warstw
autoenkodera może odbywać się przy użyciu dowolnego algorytmu gradientowego. Jest to
stosunkowo prosty proces ze względu na fakt, że w każdym etapie uczenie dotyczy tylko
parametrów jednej warstwy.
Ostatnia warstwa ukryta autoenkodera (po wyeliminowaniu warstwy rekonstrukcyjnej)
zawiera kodowanie na najwyższym poziomie, zwykle o najbardziej ograniczonej liczbie
neuronów. Sygnały wyjściowe tej warstwy stanowią cechy diagnostyczne wyselekcjonowane
przez strukturę układu w procesie uczenia z udziałem zbioru danych uczących. Mogą one stanowić
atrybuty wejściowe dla końcowego stopnia klasyfikatora bądź układu regresyjnego o dowolnej
konstrukcji. W ostatnim etapie tak ukształtowana struktura sieci podlega regularnemu uczeniu na
danych parach uczących (x,d).

186
9.8.4 Przykład zastosowania autoenkodera w kodowaniu danych
Poniżej przedstawiony będzie przykład zdolności kodowania autoenkodera dla zbioru 8 obrazów
czarno-białych o wymiarach 64x64 (w sumie 4096 sygnałów wejściowych) reprezentowanych na
rys. 9.27 i zawartych w plikach RBx.png. Zbiór ten został użyty najpierw w uczeniu a następnie
przetestowane zostało odtwarzanie zakodowanych obrazów (identycznych jak w uczeniu).
Zastosowano jedną warstwę ukrytą o 30 neuronach. Współczynnik kompresji równał się więc
4096/30=136.9.

Rys. 9.27 Zbiór obrazów oryginalnych użytych w uczeniu.

Linie programu Matlaba podane są jak niżej


MATLAB
x1=imread('RB1.png');x2=imread('RB2.png');x3=imread('RB3.png');x4=imread('RB4.png');
x5=imread('RB9.png');x6=imread('RB6.png');x7=imread('RB7.png');x8=imread('RB8.png');
xc{1,1}=x1; xc{1,2}=x2;xc{1,3}=x3; xc{1,4}=x4;
xc{1,5}=x5; xc{1,6}=x6;xc{1,7}=x7; xc{1,8}=x8;
figure(1);
for i = 1:8
subplot(2,4,i);
imshow(xc{i}); title('Original')
end
hiddenSize = 20;
% 'ScaleData',false, ...
autoenc = trainAutoenkoder(xc, hiddenSize, ...
'L2WeightRegularization', 0.004, ...
'SparsityRegularization', 4, ...
'SparsityProportion', 0.15, ...
'MaxEpochs', 1000);
xReconstructed = predict(autoenc, xc);
figure(2);
for i = 1:8
subplot(2,4,i);
% imshow((xReconstructed{i})>0.5); title('Reconstructed')
imshow(xReconstructed{i}); title('Reconstructed')
end
figure(3)
for i = 1:8
err=xReconstructed{i}-double(xc{i});
errBW(err<0.5)=0;
errBW(err>=0.5)=1;

187
nerr(i)=sum(errBW);
subplot(2,4,i);
% imshow(1-err);
imshow(reshape(1-errBW,64,64)); title('Error')
end
liczba_err=nerr
rate_err=nerr/4096*100

Wygląd obrazów w skali szarości odtworzonych po rekonstrukcji przedstawiony jest na rys. 9.28.
Szare piksele obrazu (ledwie widoczne) nałożone na inne czarno–białe obrazy odtworzone przez
sieć mają niewielkie wartości, które przetworzone na reprezentację czarno-białą nie wnoszą
istotnych błędów rekonstrukcji obrazów czarno-białych. Błąd rekonstrukcji kolejnych 8 obrazów
czarno-białych w postaci liczby błędnych pikseli (po wcześniejszym zaokrągleniu wartości pikseli
do 1 lub 0) uzyskany w programie podany jest poniżej
Liczba błędnych pikseli kolejnych obrazów=[ 3 4 7 9 0 8 92 2]
Błąd odtworzenia dotyczył znikomej ilości pikseli w obrazach czarno-białych (oryginalna liczba
pikseli każdego obrazu równa 4096). Jeden obraz czarno-biały został odtworzony bezbłędnie
(wynik po zaokrągleniu do wartości bitów 1 lub 0). Procentowa zawartość błędów odtworzenia
kolejnych obrazów czarno-białych jest równa
Błąd procentowy=[ 0.07% 0.10% 0.17% 0.22% 0 0.19% 2.25% 0.05%]
Należy zauważyć, że jest to wynik rekonstrukcji autoenkodera jedynie w trybie odtwarzania na
tych samych danych, które były użyte w uczeniu. Świadczą one o dobrych wynikach uczenia sieci.
Na tej podstawie nie można jednak wyciągać daleko idących wniosków co do zdolności
generalizacji systemu przy tej wartości współczynnika kompresji.

Rys. 9.28 Wynik rekonstrukcji obrazów.

Sieć autoenkodera znajduje zastosowanie w typowych obszarach przetwarzania danych, takich jak:

188
• Redukcja szumu zakłócającego dane – w tym przypadku zakłada się, że dane wejściowe
zniekształcone są szumem; po zakodowaniu i rekonstrukcji szum ten może ulec znacznej
redukcji przy właściwym doborze parametrów sieci.
• Generacja cech diagnostycznych procesu reprezentowanego przez dane uczące. W tym
przypadku wyjściem sieci jest warstwa ukryta. W przypadku programu autoenkoder
Matlaba [38] dostęp do sygnałów h warstwy ukrytej (kodującej) odbywa się komendą
h=encode(autoenc, dane_wej)
gdzie autoenc jest nazwą struktury sieciowej użytej w wywołaniu autoenkodera, a dane_wej jest
zbiorem danych które mają podlegać kodowaniu.
Program Matlaba zakłada istnienie jednej warstwy ukrytej. Przy strukturze
wielowarstwowej jego wywołanie musi być wielokrotne, przy czym za każdym razem
wymuszeniem dla następnej warstwy są sygnały wyjściowe warstwy ukrytej. Ostatnia warstwa
ukryta reprezentować będzie najbardziej skompresowane cechy diagnostyczne procesu.
Przykład zastosowania autoenkodera przedstawiony zostanie przy rozpoznaniu 2 rodzajów
komórek krwiotwórczych (kodowanie binarne zero-jedynkowe wektora destination T) na podstawie 87
cech diagnostycznych typu numerycznego zawartych w macierzy X. Stosowane są 2 warstwy kodujące
(ukryte) i warstwa typu Softmax na wyjściu działająca w trybie klasyfikacji. Wydruk programu w Matlabie
wykonującego zadanie przedstawiony jest poniżej. Dane dotyczące cech diagnostycznych (macierz
sygnałów wejściowych X) oraz przynależności klasowej kolejnych obserwacji (wektor T) zawarte są w
pliku Matlaba XT_autoenkoder.mat.

MATLAB
load XT_autoencoder.mat
a=randperm(293);Xrand=X(:,a);Trand=T(:,a);
Xucz=Xrand(:,1:193);Tucz=Trand(:,1:193);
Xtest=Xrand(:,194:end); Ttest=Trand(:,194:end);
% Train an autoencoder with a hidden layer and a linear transfer function for the
% decoder. Set the L2 weight regularizer to 0.001, sparsity regularizer to 4 and sparsity
% proportion to 0.05.
hiddenSize = 40;
autoenc1 = trainAutoencoder(Xucz,hiddenSize,...
'L2WeightRegularization',0.001,...
'SparsityRegularization',4,...
'SparsityProportion',0.05,...
'DecoderTransferFunction','purelin');
% Extract the features in the hidden layer.
features1 = encode(autoenc1,Xucz);
% Train a second autoencoder using the features from the first autoencoder.
hiddenSize = 15;
autoenc2 = trainAutoencoder(features1,hiddenSize,...
'L2WeightRegularization',0.001,...
'SparsityRegularization',4,...
'SparsityProportion',0.05,...
'DecoderTransferFunction','purelin',...
'ScaleData',false);

189
% Extract the features in the hidden layer.
features2 = encode(autoenc2,features1);
% Train a softmax layer for classification using the features, features2
softnet = trainSoftmaxLayer(features2,Tucz,'LossFunction','crossentropy');
% Stack the encoders and the softmax layer to form a deep network.
deepnet = stack(autoenc1,autoenc2,softnet);
% Retraining deep network
deepnet = train(deepnet,Xucz,Tucz);
% Estimate the cell types using the trained deep network: deepnet.
cell_type = deepnet(Xtest);
% Plot the confusion matrix.
plotconfusion(Ttest,cell_type);

Wynik testowania sieci na danych testujących nie uczestniczących w uczeniu jest zależny od
losowego podziału zbioru danych na zbiór uczący i testujący i może przyjmować różne wartości
w zależności od ich składu. Przykładowy wynik dla jednej próby w postaci macierzy rozkładu klas
(ang. confusion matrix) przedstawiony jest na rys. 9.29.

Rys. 9.29 Przykładowy wynik (w postaci macierzy rozkładu klasowego) testowania systemu
autoenkodera z klasyfikatorem typu Softmax na wyjściu.

9.9Autoenkoder wariacyjny
9.9.1 Podstawy działania
Autoenkoder wariacyjny (ang. Variational Autoenkoder - VA) jest innym rozwiązaniem sieci
głębokiej umożliwiającym generację obrazów podobnych do oryginału (proces często stosowany

190
do wzbogacenia zbioru danych uczących). Będzie dalej oznaczany skrótem VAR [39]. Sieć taka
działa na innych zasadach niż przedstawiona wcześniej sieć klasycznego autoenkodera (AE).
Nazwa sieci wywodzi się z bliskiej relacji mechanizmu działania z zasadą regularyzacji sieci i
wnioskowania wariacyjnego w statystyce.
Sieć VAR wykorzystuje w swoim działaniu zasadę redukcji wymiarowości danych, tak
przeprowadzoną, że możliwe jest odtworzenie danych oryginalnych z określoną dokładnością przy
zachowaniu w miarę wiernego odwzorowania rozkładu statystycznego (wartości średniej i
wariancji), a nie odtworzenia wartości poszczególnych pikseli, jak to miało miejsce w przypadku
autoenkodera AE [39]. Redukcja wymiarowości danych oznacza reprezentację danych poprzez
zmniejszoną liczbę cech (deskryptorów) charakteryzujących dostatecznie dokładnie analizowany
proces. Redukcja taka może polegać na wyborze ograniczonej liczby zmiennych oryginalnych (bez
zmiany ich wartości), bądź na generacji nowego zbioru deskryptorów jako funkcji liniowej (np.
PCA) bądź nieliniowej wszystkich zmiennych oryginalnych (AE).
Klasycznym rozwiązaniem tego typu jest autoenkoder, poznany wcześniej. Idea uczenia
autoenkodera polegała na takim doborze parametrów (wag sieci głębokiej), aby obraz wyjściowy
po rekonstrukcji sygnałów skompresowanych przypominał jak najbardziej obraz oryginalny. W
procesie uczenia klasycznego autoenkodera porównywane były wartości sygnałów bądź piksele
obrazów oryginalnego i zrekonstruowanego. Redukcja wymiarowości w takim rozwiązaniu
autoenkodera może być zinterpretowana jako kompresja danych, w której enkoder kompresuje
dane z przestrzeni oryginalnej do przestrzeni zredukowanej traktowanej zwykle jako przestrzeń
ukryta (ang. latent space), natomiast dekoder dokonuje dekompresji, czyli rekonstrukcji danych
oryginalnych. Sposób uczenia klasycznego autoenkodera ukierunkowany jest na zgodność
kolejnych elementów danych zrekonstruowanych z oryginalnymi
Oczywiście, odtworzenie danych oryginalnych poprzez dekompresję charakteryzuje się
pewną utratą informacji oryginalnej. Wielkość tej straty uzależniona jest od wymiaru przestrzeni
skompresowanej jak również od mechanizmu uczenia sieci. Ilustracja tego typu procesu
przetwarzania danych przedstawiona jest na rys. 9.30. Wektor oryginalny x kodowany jest w
wektor e(x) o zmniejszonym wymiarze, po czym dekodowany w postać d(e(x)). Istotą klasycznego
algorytmu uczenia sieci autoenkodera jest taki dobór parametrów sieci, aby utrata informacji
oryginalnej, czyli różnica między elementami wektora zrekonstruowanego i oryginalnego była jak
najmniejsza. Minimalizacji podlega zwykle funkcja błędu

191
min E = x - d(e(x))
2
(9.31)

Klasyczny autoenkoder ma pewną wadę, wynikającą z nieciągłości danych (na przykład puste
przestrzenie między klastrami danych). Na etapie testowania na danych nie uczestniczących w
uczeniu dekoder układu wygeneruje nierealistyczny wynik (nieprzystający do danych
oryginalnych), gdyż na etapie uczenia nie „widział” statystycznego rozkładu dotyczącego danych
enkodera z obszaru pustego.

x e(x) d(e(x))
Rys. 9.30 Struktura klasycznego autoenkodera AE [96].

Dobrze wytrenowany autoenkoder pozwala zwykle odtworzyć dane weryfikacyjne (testujące)


pochodzące ze zbioru różnego od zbioru uczącego tylko z określoną dokładnością. Remedium na
to jest automatyczna regularyzacja sieci w procesie uczenia. Stąd powstała idea autoenkodera
wariacyjnego (VAR) jako rozwiązania w którym dopasowuje się równolegle również statystyczne
parametry rozkładu danych. Proces uczenia VAR podlega automatycznej regularyzacji w specjalny
sposób zabezpieczający przed przeuczeniem i zapewniający najlepszą reprezentację danych w
przestrzeni ukrytej, umożliwiającą właściwe odtworzenie (generację) procesu oryginalnego z
punktu widzenia statystycznego. Enkoder wariacyjny stosuje kodowanie w warstwie ukrytej
nie oryginalnych danych wejściowych, ale rozkładu dwu wektorów: wektora wartości
średnich μ oraz wektora odchyleń standardowych σ. W efekcie proces uczenia składa się z
następujących etapów [39,96]:
• Dane wejściowe są kodowane w przestrzeni ukrytej (zredukowanej) na podstawie rozkładu
statystycznego danych (ich dystrybucji). Przyjmując rozkład normalny wystarczy
192
scharakteryzować proces poprzez wartość średnią (oczekiwaną) i macierz kowariancji
(zwykle wariancji σ2).
• Punkty z przestrzeni ukrytej są próbkowane na podstawie tej dystrybucji (a nie
oryginalnych wartości pikseli).
• Na podstawie tych próbek dokonuje się rekonstrukcji danych i oblicza błąd rekonstrukcji.
• Błąd rekonstrukcji jest kierowany z powrotem do wejścia sieci (propagacja wsteczna) i na
tej podstawie metoda gradientową dokonywana jest adaptacja parametrów sieci.
Przykładową generację danych poprzez próbkowanie przy znanym rozkładzie określonym poprzez
wektor wartości średnich μ oraz wektor standardowych odchyleń σ dla dekodera przedstawiono
poniżej w tabeli 9.2.

Tabela 9.2 Przykładowa generacja danych przy znanym rozkładzie statystycznym


Wektor μ [0.13 1.35 0.27 0.78 ...]
Wektor σ [0.21 0.53 0.88 1.38 ...]
Rozkład statystyczny X1~N(0.13, 0.21), X2~N(1.35, 0.53), X3~N(0.27, 0.88), X4~N(0.78, 1.38),...
próbek
Wektor po próbkowaniu [0.29 1.82 0.87 1.03 ...]

Zauważmy, że wielokrotna generacja stochastyczna próbek według określonego rozkładu generuje


różne wartości nawet przy tych samych wartościach średnich i wariancji. Wektor wartości średnich
wskazuje centrum, wokół którego z odchyleniem standardowym generowane są próbki. W efekcie
dekoder uczy się nie pojedynczych (ściśle zdefiniowanych) próbek, ale otoczenia, z którego
są one próbkowane. Różnice między klasycznym i wariacyjnym rozwiązaniem autoenkodera
pokazane są w tabeli 9.3.

Tabela 9.3 Ilustracja różnicy między klasycznym AE i wariacyjnym VAR autoenkoderem


Autoenkoder x z=e(x) d(z)
Autoenkoder x dystrybucja Próbkowanie d(z)
wariacyjny p(z x) z~ p(z x)

Takie rozwiązanie (przy założeniu rozkładu danych jako normalny) sprowadza się w uczeniu
VAR również do reprezentacji danych poprzez wartości średnie i macierz kowariancji,
193
zamiast jedynie reprezentacji poszczególnych danych (pikseli obrazu). Takie rozwiązanie
umożliwia regularyzację sieci w prosty sposób, zmuszając enkoder do zapewnienia
normalności rozkładu danych w przestrzeni ukrytej. Proces realizowany przez VAR można
więc przedstawić jak na rys. 9.31 [96].

Rys. 9.31 Struktura VAR ilustrująca elementy składowe używane w procesie uczenia: μx
reprezentuje wartość średnią a σx odchylenie standardowe danych w warstwie ukrytej [96].

Funkcja celu podlegająca minimalizacji zawiera 2 składniki: składnik rekonstrukcyjny


(dopasowanie warstwy wyjściowej do wejściowej) oraz składnik regularyzacyjny, związany z
warstwą ukrytą, który dąży do zapewnienia normalności rozkładu danych w warstwie ukrytej.
Składnik regularyzacyjny wyrażany jest przy użyciu dywergencji Kulbacka-Leiblera KL() między
aktualnie zwracanym rozkładem danych ukrytych a pożądanym rozkładem normalnym.
Minimalizowaną funkcję celu można więc zapisać w postaci

min E = x - d(z) + KL ( N (x , x ), N (0,1) )


2
(9.32)

Aby zapewnić prawidłowy przebieg procesu uczenia należy zapewnić regularyzację zarówno
wartości średniej jak i macierzy kowariancji, sprowadzając proces do normalnego o zerowej
wartości średniej i jednostkowej macierzy kowariancji. Minimalizacja wartości czynnika
regularyzacyjnego odbywa się kosztem składnika rekonstrukcyjnego (składnik pierwszy we
wzorze (9.27)). Właściwy balans między nimi można uzyskać przez wprowadzenie odpowiedniej
wagi we wzorze (9.27).

9.9.2. Proces uczenia sieci VAR


194
Niech x oznacza zbiór danych rekonstruowanych, generowany na podstawie ukrytych próbek z
warstwy ukrytej z. W związku z tym wyróżnia się 2 kroki stanowiące metodę probabilistyczną
uczenia [39]
• Próbkowanie zmiennych z na podstawie rozkładu p(z)
• Próbkowanie zmiennych x na podstawie rozkładu warunkowego p(x|z). Zadanie: znajdź
rozkład zmiennej dekodowanej x przy założeniu znajomości rozkładu zmiennej
zakodowanej z.
Procesy kodowania (operator e) i dekodowania (operator d) powiązane są wzorem Bayesa
p( x z ) p( z ) p( x z ) p( z )
p ( z x) = = (9.33)
p ( x)  p( x u) p(u)
u

Przyjmuje się, że p(z) ma standardowy rozkład Gaussa p(z)=N(0,1), o wartości średniej zerowej i
jednostkowej macierzy kowariancji 1. Z kolei p(x|z) jest rozkładem gaussowskim, którego wartość
średnia jest funkcją deterministyczną f(z) zmiennej z a macierz kowariancji jest postaci
jednostkowej pomnożonej przez dodatnią stałą wartość c, co zapisuje się w postaci
p(x|z)=N(f(z),c1). Zarówno c jak i postać funkcji nie są z góry zadane i podlegają estymacji w
procesie uczenia. Mianownik w wyrażeniu Bayesa wymaga zastosowania wnioskowania
wariacyjnego, techniki stosowanej w złożonych rozkładach statystycznych.
W tym podejściu stosuje się sparametryzowane rodziny rozkładów (zwykle gaussowskich
o różnej wartości średniej i macierzy kowariancji). Spośród nich wybiera się tę rodzinę, która
minimalizuje błąd aproksymacji na danych pomiarowych (zwykle dywergencję Kulbacka-Leiblera
między aproksymacją i wartościami zadanymi). Funkcja p(z|x) jest w podejściu wariacyjnym
aproksymowana poprzez rozkład gaussowski [39,96]
qx(z)=N(g(x), h(x)) (9.34)
w którym wartość średnia jest aproksymowana przez g(x) a kowariancja przez h(x). Obie
funkcje podlegają procesowi minimalizacji z użyciem miary Kulbacka-Leiblera
( g*, h*) = arg min KL ( qx ( z ), p( z | x) ) (9.35)
g ,h

Proces ten sprowadza się do rozwiązania problemu optymalizacyjnego o postaci []


 x − f ( z) 2 
( g *, h*) = arg max  − − KL ( qx ( z ), p( z )  (9.36)
 2c 
g ,h
 

195
Składnik pierwszy w tym wzorze odpowiada za dopasowanie sygnałów wyjściowych sieci do
wartości zadanych x, natomiast składnik drugi za rozkład statystyczny danych wejściowych i
sygnałów w warstwie ukrytej, stanowiąc naturalny składnik regularyzacyjny procesu. Istotnym
parametrem jest c. Wartość tej zmiennej pozwala regulować relację między składnikiem
pierwszym i drugim. Duża wartość c oznacza większy wpływ czynnika KL, czyli dopasowania
statystycznego obu rozkładów. Mała wartość – większy wpływ dopasowania pikselowego
zrekonstruowanego obrazu do oryginalnego.
Funkcje f, g i h użyte w modelu matematycznym podlegają w praktyce modelowaniu
aproksymacyjnemu przy użyciu sieci neuronowych. Obie funkcje g i h wykorzystują wspólny
fragment architektury sieci, co można zapisać w postaci [39,96]
g(x)= g2(g1(x))=g2(h1(x)) (9.37)
h(x)=h2(h1(x)) (9.38)
Przyjmuje się w praktyce założenie upraszczające, że h(x) jest wektorem złożonym z elementów
diagonalnych macierzy kowariancji i jest jednakowych rozmiarów jak g(x). Przy rozkładzie
gaussowskim zmiennej z o wartości średniej g(x) i wariancji h(x) przyjmuje się, że
z = h( x) + g ( x) (9.39)
gdzie  jest zmienną losową o rozkładzie normalnym  ~ N (0,1) . Rys. 9.31 przedstawia ogólną
strukturę układową enkodera implementującą funkcje g(x) oraz h(x), przy czym wektor g(x)
reprezentuje wartości średnie a h(x) kowariancje (wartości diagonalne macierzy kowariancji).
Rekonstrukcja sygnałów wyjściowych f(z) realizowana przez dekoder realizuje rozkład p(x|z)
generowany przez enkoder zakładając przy tym stałą kowariancję. Jej implementacja jest możliwa
przez strukturę neuronową implementującą funkcję f o postaci ogólnej prezentowanej na rys. 9.32
przy założeniu trzech neuronów w warstwie ukrytej. Stan tych neuronów dla dekodera ustalany
jest według rozkładu normalnego o wartościach średnich i odchyleniu standardowym ustalonym
poprzez warstwę h i g enkodera.

196
Rys. 9.32 Struktura neuronowa realizująca autoenkoder wariacyjny w ujęciu implementacyjnym [2]

W efekcie proces uczenia sprowadza się do minimalizacji funkcji celu o postaci [39,96]
min E = C x - f (z) + KL ( N ( g ( x), h( x) ) , N (0,1) )
2
(9.40)

Czynnik pierwszy odpowiada za odtworzenie sygnałów wejściowych na wyjściu sieci, natomiast


drugi za odwzorowanie rozkładu statystycznego sygnałów wejściowych w sygnałach
wyjściowych. Obie struktury (enkoder i dekoder) są implementowane w postaci głębokiej sieci
neuronowej, podlegającej uczeniu typowemu dla sieci głębokich. Przykład takiej sieci pokazany
jest na rys. 9.33.

Rys. 9.33 Przykładowa struktura sieci autoenkodera wariacyjnego [96].

197
9.10 Sieci generatywne GAN
Sieć generatywna GAN (ang. Generative Adversarial Network) stworzona przez zespół Iana
Goodfellow [23] w 2014 roku, jest implementacją koncepcji przeciwstawienia sobie dwu sieci
neuronowych, z których jedna reprezentuje dane rzeczywiste, a druga dane generowane sztucznie,
udając dane rzeczywiste. Obie sieci rywalizują ze sobą. System jest trenowany w taki sposób aby
generator nowych danych był w stanie oszukać rzeczywistość, prezentując dane (sygnały bądź
obrazy) które są trudne do odróżnienia od rzeczywistych. Generator sztucznych danych ma za
zadanie wygenerować je w taki sposób, aby statystyki danych oryginalnych i danych
generowanych przez niego były takie same [13,23]. Przykładowo w przypadku obrazów, obraz
wygenerowany sztucznie powinien przypominać obraz oryginalny.

Rys. 9.34 Struktura podstawowa sieci GAN. Blok X reprezentuje dane oryginalne, Z – wektor
losowy zasilający generator G, generujący dane G(Z) „udające” dane oryginalne. Dyskryminator
D porównuje dane oryginalne X z G(Z) wygenerowanymi rzez generator wskazując na
prawdopodobieństwo zgodności obu danych X i G(Z) [23].

Idea działania sieci GAN jest przedstawiona na rys. 9.34. Blok X reprezentuje dane oryginalne, Z
– wektor losowy zasilający generator G, generujący na tej podstawie dane G(Z) „udające” dane
oryginalne. Dyskryminator D porównuje dane oryginalne X z G(Z) wygenerowanymi przez
generator wskazując na prawdopodobieństwo zgodności obu danych X i G(Z). Proces uczenia sieci

198
polega na takim doborze parametrów, aby oszukać dyskryminator (uznać, że dane wygenerowane
sztucznie G(Z) niczym nie różnią się od danych oryginalnych X. W efekcie generator G generuje
kolejnych kandydatów do porównania, a dyskryminator D ocenia ich jakość w stosunku do
oryginału.
Proces uczenia polega na maksymalizacji prawdopodobieństwa, że dyskryminator popełni
błąd przyjmując że obie grupy danych (oryginalne i sztucznie wygenerowane) są identyczne pod
względem rozkładu statystycznego (maksymalizacja prawdopodobieństwa zaliczenia obu
obrazów: oryginalnego i wygenerowanego sztucznie do tej samej klasy). Można go zapisać jako
programowanie minimaksowe zdefiniowane w postaci [13,23]
min max V (G , D ) = x ~p x log D (X)  + z~ p z
log (1 − D (G (z)) ) (9.41)
G D

gdzie symbol E reprezentuje wartość oczekiwaną, natomiast px i pz rozkłady statystyczne


odpowiednio danych rzeczywistych (oryginalnych) i wygenerowanych sztucznie. D(X) oraz G(X)
są wartościami generowanymi odpowiednio przez dyskryminator D i generator G dla danych X.
W efekcie proces optymalizacyjny ukierunkowany jest na poszukiwanie minimum względem
generatora G i maksimum względem dyskryminatora D.
Generator G zasilany jest poprzez wektor losowy Z o określonym wymiarze. Na bazie tego
wektora próbuje wygenerować obraz przypominający oryginał X. Dyskryminator zasilany jest
przez obraz oryginalny X i obraz wygenerowany przez generator G(Z). W wyniku ich porównania
generuje wartość prawdopodobieństwa, że obraz G(Z) jest nierozpoznawalny od oryginału X. Oba
modele G i D mogą być implementowane przy użyciu różnych struktur sieci neuronowych,
aczkolwiek aktualnie najlepsze wyniki uzyskuje się przy użyciu sieci głębokich o strukturze CNN.
Proces uczenia sieci GAN przyjmuje formę iteracyjną. Przy aktualnych parametrach
generatora G wykonuje się k kroków w optymalizacji dyskryminatora D a następnie jeden krok
optymalizacji generatora. W pętli wewnętrznej adaptacji dyskryminator jest ukierunkowany na
rozróżnienie próbek obu obrazów. W kroku drugim dotyczącym adaptacji generatora jego
parametry są zmieniane w takim kierunku, aby wynik generatora był bliższy obrazowi
oryginalnemu. Po wykonaniu wielu iteracji osiągnięty jest punkt, w którym nie występuje
możliwość poprawy wyniku w obu krokach, czyli dyskryminator nie jest w stanie rozróżnić obrazu
G(Z) od oryginalnego X.

199
Powstało wiele modyfikacji podstawowej struktury GAN polepszających sprawność
wykrywania „podróbki” od danych oryginalnych. Przykład takiego rozwiązania zwanego BIGAN
(skrót Bidirectional Generative Adversarial Networks) przedstawiony jest na rys. 9.35 [13].

Rys. 9.35 Zmodyfikowana struktura sieci zwana BIGAN [13]

Struktura sieci BIGAN zawiera enkoder E który transformuje dane oryginalne X do przestrzeni
wektorowej E(X), generując wektor cech o wymiarach identycznych z wektorem losowym Z.
Dyskryminator D sieci BIGAN dokonuje więc rozróżnienia pary danych (x, E(x)) oraz (G(z), z)
zamiast (x versus G(z)) w klasycznej implementacji GAN. Jest oczywiste, że enkoder E próbuje
„nauczyć” się inwersji generatora G (czyli wektora Z), choć nie występuje tu bezpośrednia
komunikacja. Zwiększona informacja (w stosunku do wersji oryginalnej GAN) dostarczona do
dyskryminatora umożliwia polepszenie dokładności rozpoznania „podróbki” od oryginału.
Sieci generatywne (GAN i jego różne modyfikacje) znajdują różne zastosowania [13].
Jednym z nich jest wzbogacanie zbioru danych oryginalnych (tak zwana augmentacja zbioru)
użytych w uczeniu sieci CNN. Dane wygenerowane przez GAN są podobne statystycznie do
danych oryginalnych, ale nie tożsame, co jest warunkiem polepszenia zdolności generalizacyjnych
trenowanych sieci. Innym zastosowaniem sieci GAN jest wykrywanie różnic między oryginałami
i podróbkami. Dotyczy to zarówno obrazów jak i sygnałów. Sieci te wykazują się zwiększoną
czułością w stosunku do innych rozwiązań.

9.11 Głębokie sieci rekurencyjne LSTM


9.11.1 Wprowadzenie

200
Sieci rekurencyjne zbudowane na bazie perceptronu wielowarstwowego stanowią ogólniejszą
strukturę niż sieci jednokierunkowe, gdyż dopuszczają sprzężenia zwrotne między neuronami.
Systemy tego typu są bardzo pożądane w analizie szeregów czasowych, w których sygnały
sąsiednie są ze sobą powiązane. Typowy przykład struktury rekurencyjnej zawierającej sprzężenia
zwrotne jedynie między neuronami ukrytymi w warstwie przedstawiono na rys. 9.36.

Rys. 9.36 Struktura sieci rekurencyjnej ze sprzężeniami zwrotnymi w warstwie ukrytej.

Głównym problemem w uczeniu takich sieci jest fakt, że sygnał wyjściowy neuronu zależy nie
tylko od pobudzenia w danej chwili, ale również od stanu neuronów w chwili poprzedniej. Można
to przedstawić w postaci rozłożonej w czasie jak na rys. 9.37 [24], w której sprzężenie zostało
zamienione na przepływ jednokierunkowy sygnałów z uwzględnieniem kolejnych chwil
czasowych. Stan neuronów w kolejnych chwilach: t, t+1, t+2 aż do końca okna pomiarowego T
zależy również od ich stanu w chwilach wcześniejszych. Układ taki można więc traktować jako
sieć głęboką.
t t+1 t+2 t→T
Warstwa wyjściowa

Warstwa ukryta

Warstwa wejściowa

Rys. 9.37 Struktura sieci rekurencyjnej rozłożona w czasie.

201
Uczenie takiej sieci jest znacznie bardziej złożone w stosunku do klasycznych sieci
jednokierunkowych, gdyż gradient w chwili aktualnej zależy również od chwil poprzednich.
Niestety, występuje tu problem tak zwanego zanikającego gradientu, co oznacza zanikanie
powiązań chwili bieżącej z wcześniejszymi. W kolejnych chwilach czasowych zależność funkcji
gradientu od sygnału wejściowego sprzed poprzednich chwil czasowych powoli zanika, co
powoduje utratę pewnej ilości informacji pierwotnie dostarczonej do sieci. Ten efekt może być
zilustrowany jak na rys. 9.38. Stopień zaczernienia węzłów ilustruje wpływ sygnału wejściowego
z chwili t=1 na stan neuronów w chwilach późniejszych (im bardziej ciemny kolor tym większy
wpływ). Klasyczne rozwiązanie sieci rekurencyjnej nie gwarantuje więc dobrego zapamiętania
wcześniej wytrenowanych wzorców. Oznacza to utratę informacji, która była wprowadzona we
wcześniejszych etapach uczenia sieci.
Skuteczne rozwiązanie tego problemu było możliwe dzięki wprowadzeniu specjalizowanej
struktury rekurencyjnej, zwanej siecią Long Short-Term Memory (w skrócie LSTM) [24,25],
reprezentującą pamięć długoterminową krótkich wzorców. Operuje ona neuronami w formie
komórek, w których istnieje dodatkowy tor pamięci z chwil poprzednich.

Warstwa wyjściowa

Warstwa ukryta

Sygnały wejściowe
Kolejne iteracje

Rys. 9.38 Ilustracja problemu zanikającego w czasie gradientu w klasycznej sieci RNN.

9.11.2 Zasada działania sieci LSTM


Sieć ta należy do sieci rekurencyjnych o strukturze specjalnie dostosowanej do długiego
zapamiętywania krótkich wzorców (short term). Składa się z wielu rekurencyjnie połączonych
bloków zwanych blokami pamięciowymi [24,25,72], które stanowią model neuronów. Każdy taki
blok zawiera trzy bramki multiplikatywne: wejściową, wyjściową oraz pamięci, pełniące rolę

202
sterowanych zaworów. Typowa struktura komórki bloku pamięciowego używanej w LSTM
przedstawiona jest na rys. 9.39.

Rys. 9.39 Typowa struktura bloku pamięciowego LSTM.

Komórka pamięciowa zawiera trzy wejścia. Są to


Xt – sygnał wejściowy w aktualnej chwili czasowej t (wektor wejściowy)
Ct-1 – sygnał pamięci z chwili t-1 poprzedniej komórki pamięci
ht-1 – sygnał wyjściowy z chwili t-1 poprzedniej komórki pamięci
Jednocześnie komórka LSTM wytwarza dwa rodzaje sygnałów wyjściowych istotnych z punktu
widzenia współdziałania komórek ze sobą. Są to
Ct – sygnał pamięci w aktualnej chwili czasowej t danej komórki pamięci
ht – sygnał wyjściowy w aktualnej chwili czasowej t danej komórki pamięci; jest to sygnał
wyjściowy neuronu ukrytego podawany na warstwę wyjściową neuronów sieci.
Komórka przetwarza nieliniowo zarówno aktualny sygnał wejściowy podany na jej wejście
jak i sygnały wyjściowe oraz pamięci z chwili poprzedniej wszystkich bloków z którymi jest
sprzężona. Struktura przepływu sygnałów w czasie dla sieci LSTM dla jednej komórki może być
przedstawiona jak na rys. 9.40.

203
Rys. 9.40 Model przepływu sygnałów w czasie dla sieci LSTM złożonej z komórki pamięci w dwu
chwilach czasowych.

Bardzo istotną rolę w przetwarzaniu sygnałów odgrywają bramki multiplikatywne, oznaczone


symbolem ×. Górna bramka z lewej strony komórki jest sterowaną bramką (zaworem) pamięci.
Decyduje o tym jaka część pamięci z poprzedniej chwili czasowej przejdzie do chwili następnej.
Stanowi zatem regulowany system zaworowy, który przepuszcza w określonym stopniu (od zera
do 1) informację zawartą w pamięci z chwili poprzedniej. O poziomie przejścia tej zawartości
decyduje sygnał wytworzony przez warstwę neuronową sigmoidalną, widoczną z lewej strony
modelu.
Druga bramka (symbol środkowy ×) stanowi następny regulowany zawór nowej pamięci i
uczestniczy w wytworzeniu zawartości pamięci Ct dla aktualnej chwili czasowej. Stanowi
sterowane połączenie nowo wytworzonego stanu pamięci i pamięci poprzedniej Ct-1, która została
przepuszczona przez zawór pierwszy. Połączenie tych informacji następuje w bloku sumatora. W
efekcie takiej operacji stara zawartość pamięci Ct-1 zostaje zamieniona na nową Ct.
Poszczególne zawory mają swoje wymuszenia i sygnały wyjściowe. Zawór pamięci jest
sterowany poprzez jednowarstwową sieć neuronową o sigmoidalnej (jedno-polarnej) funkcji
aktywacji. Sygnały wejściowe dla tej warstwy stanowią: Xt – sygnał wejściowy w aktualnej chwili
czasowej t, Ct-1 – sygnał pamięci z chwili t-1 poprzedniej komórki pamięci, ht-1 – sygnał wyjściowy
z chwili t-1 poprzedniej komórki pamięci oraz sygnał polaryzacji. Sumacyjny sygnał wyjściowy
zaworu pamięci po przetworzeniu sigmoidalnym mnożony jest z sygnałem pamięci z chwili
poprzedniej i stanowi dla niej współczynnik z jakim poprzednia pamięć przechodzi do następnej
chwili czasowej.

204
Drugi zawór reprezentowany przez środkowy mnożnik × decyduje o nowym stanie pamięci
Ct w chwili t i jest nazywany zaworem nowej pamięci. Składa się z dwu równolegle działających
warstw neuronowych. Pierwsza warstwa sigmoidalna jedno-polarna przyjmuje identyczne
wymuszenia jak warstwa neuronowa w zaworze pamięci (Xt, Ct-1, ht-1 i polaryzacja) i stanowi
przetworzoną zawartość starej pamięci. Druga warstwa operuje jedynie sygnałami Xt, ht-1 oraz
polaryzacją, a więc nie zależy od zawartości starej pamięci. Funkcja aktywacji tej warstwy jest
sigmoidą bipolarną realizowaną przez funkcję tangensa hiperbolicznego. Mnożnik decyduje o
wpływie starej pamięci na stan wyjściowy tego zaworu, który będzie następnie dodany do
zawartości starej pamięci wychodzącej z bloku pamięci (symbol sumatora) tworząc aktualny (w
chwili t) stan pamięci Ct.
Ostatnią operacją komórki pamięciowej jest wytworzenie sygnału wyjściowego ht w
aktualnej chwili czasowej t. Sygnał wyjściowy komórki jest iloczynem dwu sygnałów: aktualnego
sygnału pamięci Ct przepuszczonego przez funkcję sigmoidalną bipolarną oraz sygnału
wyjściowego z warstwy neuronowej zasilonej poprzez Xt, ht-1 oraz polaryzację (bramka
multiplikatywna z prawej strony schematu). System ten stanowi zawór wyjściowy komórki,
decydujący o tym jak duża porcja nowej pamięci zostanie przekazana na wyjście komórki, czyli
sygnału komórki, który zasili komórkę w następnej chwili czasowej.
W efekcie wysterowania poszczególnych zaworów możliwe jest przepuszczenie lub
zablokowanie określonej porcji informacji z chwil poprzednich. Na rys. 9.41 zilustrowano możliwy
wpływ informacji dostarczonej do sieci w chwili t1 na stan komórki w następnych chwilach
czasowych. Symbol „o” oznacza pełne otwarcie zaworu a symbol „–„ pełne zamknięcie. Stan
wyjścia komórek w poszczególnych chwilach czasowych w zależności od informacji z chwili t1
jest funkcją otwarcia lub zamknięcia odpowiednich zaworów i ilustrowany ciemnym stanem węzła
(informacja przechodzi) lub jasnym (przepływ informacji zablokowany).

205
Rys. 9.41 Ilustracja przepływu informacji z chwili t1 do wyjścia w kolejnych chwilach czasowych
w zależności od stanu wysterowania zaworów. Symbol „o” oznacza pełne otwarcie zaworu a
symbol „–„ pełne zamknięcie.

W procesie uczenia doborowi podlegają wagi poszczególnych połączeń sieci poprzez


minimalizację funkcji błędu na danych uczących w postaci par (wielkość wejściowa x i wielkość
zadana na wyjściu d) określonych w kolejnych chwilach czasowych. Minimalizacja odbywa się
metodą gradientową przy generacji gradientu poprzez zastosowanie propagacji wstecznej. Sygnały
wejściowe przesyłane są najpierw wprzód (w obrębie przyjętego okna czasowego T) a następnie
błąd na wyjściu w poszczególnych chwilach czasowych przesyłany jest w kierunku odwrotnym
(od wyjścia do wejścia). Na tej podstawie generowane są składniki gradientu względem
poszczególnych wag sieci, podobnie jak odbywało się to w klasycznych sieciach neuronowych.
Przyjmijmy oznaczenia wskaźnikowe jak na rys. 9.39. Poszczególne warstwy neuronowe
charakteryzowane są poprzez macierze wagowe opisane za pomocą dwu wskaźników: pierwszy
pochodzi od numeru przypisanego warstwie, drugi od symbolu wielkości wejściowej dla tej
warstwy. Przykładowo w1h oznacza wagę pierwszego zaworu przetwarzającą sygnały wyjściowe
komórki ht-1 z poprzedniej chwili wagowej, 𝐰1𝑥 wektor wagowy przetwarzający sygnały
wejściowe tworzące wektor aktualnych sygnałów pomiarowych. Funkcja sigmoidalna oznaczona
jest symbolem sigm a symbol tgh oznacza funkcję tangensa hiperbolicznego. Sygnały w
poszczególnych punktach komórki są wyrażone wzorami [24,25,72]
y1 = 𝑠𝑖𝑔𝑚(w1𝑐 c𝑡−1 + w1ℎ h𝑡−1 + 𝐰1𝑥 𝐱 𝑡 + w10 ) (9.42)
y2 = 𝑠𝑖𝑔𝑚(w2𝑐 c𝑡−1 + w2ℎ h𝑡−1 + 𝐰2𝑥 𝐱 𝑡 + w20 ) (9.43)
y3 = 𝑡𝑔ℎ(w3ℎ h𝑡−1 + 𝐰3𝑥 𝐱𝑡 + w30 ) (9.44)

206
y4 = 𝑠𝑖𝑔𝑚(w4𝑐 c𝑡 + w4ℎ h𝑡−1 + 𝐰4𝑥 𝐱 𝑡 + w40 ) (9.45)
Na tej podstawie tworzone są: stan pamięciowy komórki ct oraz sygnał wyjściowy komórki ht (oba
w chwili t). Są one określone wzorami
c𝑡 = 𝑦2 ∙ y3 + c𝑡−1 y1 (9.46)
h𝑡 = 𝑦4 ∙ 𝑡𝑔ℎ(c𝑡 ) (9.47)
Przetwarzanie wsteczne sygnałów odbywa się w identyczny sposób jak w metodzie klasycznej
propagacji wstecznej (odwrócenie kierunku przepływu przy tych samych wartościach wag gałęzi
liniowej i zastąpieniu funkcji aktywacji poprzez wartość pochodnej w punkcie pracy sieci o
normalnym kierunku przepływu). W przypadku węzła realizującego mnożenie korzysta się z
zależności pochodnej iloczynu, zgodnie z którą, jeśli sygnał y jest iloczynem dwu sygnałów v1 i v2,
𝑦 = 𝑣1 (𝑤) ∙ 𝑣2 (𝑤) (9.48)
to
𝑑𝑦 𝑑𝑣 𝑑𝑣1
= 𝑣1 𝑑𝑤2 + 𝑣2 (9.49)
𝑑𝑤 𝑑𝑤

Pełna informacja o gradiencie jest sumą pochodnych po wszystkich krokach czasowych


wykonanych wewnątrz okna pomiarowego T. W uczeniu wykorzystuje się z reguły metodę
największego spadku z momentem rozpędowym.
Jako przykład pokażemy zastosowanie sieci LSTM do prognozy średniego dziennego
stężenia pyłu PM10 na podstawie pomiarów z przeszłości. Wyniki pomiarów dotyczą Ursynowa
w Warszawie i zawarte są w pliku pmday i dotyczą wartości błędów MAPE, MAE oraz
współczynnika korelacji R. Program umożliwia również utworzenie zespołu predyktorów LSTM
poprzez przyjęcie odpowiedniej wartości zmiennej kmax.

MATLAB
load pmday;data=pmday; % prognozowanie sredniej dziennej PM10
ll=size(data);ll=ll(2);
wyn=[]; ywyn=[];meansum=[]; rmsesum=[];R=[];MAEsum=[];
numTimeStepsTrain = floor(0.8*ll);
kmax=1 % liczba powtórzeń (w przypadku zespołu sieci)
for k=1:kmax
dataTrain = data(:,50:numTimeStepsTrain+1);
dataTest = data(:, numTimeStepsTrain+1:end);
mu = mean(mean(dataTrain));
sig = std(dataTrain);
dataTrainStandardized = (dataTrain - mu) / sig;
XTrain = dataTrainStandardized(:,1:end-1);
YTrain = dataTrainStandardized(:,2:end);
numFeatures = 1;
numResponses =1;
numHiddenUnits = 400
layers = [ ...
sequenceInputLayer(numFeatures)
lstmLayer(numHiddenUnits)
dropoutLayer(0.5)
fullyConnectedLayer(numResponses)

207
regressionLayer];
options = trainingOptions('adam', ...
'MaxEpochs',300, ...
'ExecutionEnvironment','gpu',...
'GradientThreshold',1, ...
'InitialLearnRate',0.005, ...
'LearnRateSchedule','piecewise', ...
'LearnRateDropPeriod',125, ...
'LearnRateDropFactor',0.5, ...
'Verbose',0, ...
'Plots','training-progress');
%Training
net = trainNetwork(XTrain,YTrain,layers,options);
dataTestStandardized = (dataTest - mu) / sig;
XTest = dataTestStandardized(:,1:end-1);
net = predictAndUpdateState(net,XTrain);
[net,YPred] = predictAndUpdateState(net,YTrain(:,end));

numTimeStepsTest = numel(XTest(1,:));
for i = 2:numTimeStepsTest
[net,YPred(:,i)] = predictAndUpdateState(net,YPred(:,i-1),'ExecutionEnvironment','cpu');
end
%Unstandardize the predictions using the parameters calculated earlier.
YPred = sig*YPred + mu;
%The training progress plot reports the root-mean-square error (RMSE)
YTest = dataTest(:, 2:end);

%If you have access to the actual values of time steps between predictions, then you can update
%the network state with the observed values instead of the predicted values. First, initialize
%the network state. To make predictions on a new sequence, reset the network state using
%resetState
net = resetState(net);
net = predictAndUpdateState(net,XTrain);

%Predict on each time step. For each prediction, predict the next time step using the observed
value of the previous time step. Set the 'ExecutionEnvironment' option of predictAndUpdateState
to 'cpu'.
YPred = [];
numTimeStepsTest = length(XTest(1,:));
for i = 1:numTimeStepsTest
[net,YPred(:,i)] = predictAndUpdateState(net,XTest(:,i),'ExecutionEnvironment','cpu');
end

%Unstandardize the predictions using the parameters calculated for learning data.
YPred = sig*YPred + mu;
MAPE=mean(mean((abs((YPred-YTest)))./(abs((YTest)))*100))
meansum=[meansum MAPE];
rmse = sqrt(mean((YPred-YTest).^2));
rmsesum=[rmsesum rmse]
MAE=mean(abs(YPred-YTest));
MAEsum=[MAEsum MAE]
r1=corrcoef(YTest, YPred);
R=[R r1(1,2)]
wyn=[wyn;YPred];
%Compare the forecasted values with the test data.
figure
subplot(2,1,1)
plot(YTest(:))
hold on
plot(YPred(:),'.-')
hold off
legend(["Rzeczywiste" "Prognozowane"])
ylabel("Prognoza")
title("Wartosci rzeczywiste i prognozowane")

subplot(2,1,2)
stem(YPred(:) - YTest(:))
xlabel("Dni")
ylabel("Błąd prognozy")
title("MAPE = " + MAPE)
end

208
Dane pomiarowe zawierają 1534 dni, przy czym 80% danych zostało użytych do uczenia a
pozostałe 20% do testowania Wyniki przedstawione poniżej dotyczą pojedynczej sieci (kmax=1).
Błąd średni procentowy MAPE na danych testujących wyniósł 9.23%, błąd średni absolutny
MAE=2.98μg/m3 a współczynnik korelacji wartości prognozowanych i rzeczywistych był równy
0.68. Na rys. 9.42 przedstawiono wykresy zmienności wartości rzeczywistych PM10 w kolejnych
dniach i wielkości prognozowanej przez sieć (rysunek górny). Na rysunku dolnym przedstawiono
różnice między wartościami rzeczywistymi i prognozowanymi w kolejnych dniach testu.

Rys. 9.42 Wyniki graficzne prognozy stężenia PM10 dla danych testowych nie uczestniczących
w uczeniu

209

You might also like