Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book

Jak zepsuć uczenie maszynowe? Wprowadzenie do ataków adwersarialnych.

20 września 2024, 18:53 | Narzędzia, Teksty | komentarzy 7

Poniższe obrazki wydają się jednakowe; czy jesteś w stanie określić, czym się różnią?

Przykład adwersarialny z wykorzystaniem FGSM, Źródło: TensorFlow, https://www.tensorflow.org/tutorials/generative/adversarial_fgsm?hl=pl

Mam mocne przeczucie, że nie widzisz różnicy. Natomiast dla AI (sieci neuronowej) mogą to być dwa absolutnie różne obrazki; ten po lewej przedstawia pandę, a drugi – rzecz jasna – gibbona.

Jak to możliwe? Otóż jeden z tych obrazków zawiera bardzo drobne zmiany w stosunku do drugiego, niemożliwe do wychwycenia przez ludzkie oko. Te zmiany zostały metodycznie wykalkulowane w celu oszukania sieci neuronowej. Do wartości pikseli w bazowym zdjęciu pandy został dodany szum, w taki sposób aby sieć rozpoznała na obrazku już zupełnie inne zwierzę (przedstawione poniżej – po prawej). 

Przykład bazowego obrazka (lewa strona) adwersarialnej maski modyfikującej obrazek bazowy (środek) oraz wynikowy obrazek adwersarialny (prawa strona). Źródło: TensorFlow, Przykład kontradyktoryjny z wykorzystaniem FGSM, https://www.tensorflow.org/tutorials/generative/adversarial_fgsm?hl=p

Zauważ, że jedyna zmiana, jaka tutaj występuje, to drobna modyfikacja zdjęcia. Niepotrzebny nam dostęp do samego modelu rozpoznającego zdjęcie (aczkolwiek potrzebujemy wiedzieć, jaki to rodzaj modelu) czy jakiegokolwiek zaplecza; wystarczy tylko pieczołowicie przygotowana próbka, która jest w stanie oszukać model AI. Co więcej, by do tego doszło, nie są konieczne zmiany całego obrazka, w niektórych przypadkach wystarczy tylko kilka pikseli, a model zostanie wyprowadzony tak głęboko w pole, że może zacząć się ubezpieczać w KRUS-ie. 

Brzmi jak ciekawostka, ale ta metoda może być wykorzystana na wiele różnych sposobów. Co jeżeli ktoś oblepi znak STOP w taki sposób, że przez AI zostanie on rozpoznany jako znak pierwszeństwa lub nie zostanie w ogóle zauważony? Za pomocą tego prostego zabiegu można wprowadzić autonomiczne auto w błąd i spowodować nieoczekiwane zachowanie. Co jeżeli jesteśmy w stanie namalować taki wzór na pojeździe, że wojskowy dron rozpozna go jako wrogi czołg? Już teraz wiemy o przypadkach wykorzystywania AI do namierzania celów wojskowych. Co jeżeli jesteśmy w stanie stworzyć ubrania, dzięki którym staniemy się niewidzialni dla systemów obsługujących monitoring?

Przykład z artykułu opisującego adwersarialny przypadek prawdziwego znaku stop, który nie został rozpoznany prawidłowo. Źródło: K. Eykholt i in., Robust Physical-World Attacks on Deep Learning Visual Classification, Conference on Computer Vision and Pattern Recognition, April 10, 2018, https://arxiv.org/pdf/1707.08945
Przykład adwersarialnego swetra, który pomaga ukryć się przed detekcją.Źródło: Z. Wu i in., Making an Invisibility Cloak: Real World. Adversarial Attacks on Object Detectors, „Computer Vision and Pattern Recognition”, July 22, 2020, https://arxiv.org/pdf/1910.14667

Fala zachwytu nad AI co rusz przetacza się przez media, które, chwaląc, jednocześnie biją na alarm odnośnie do zagrożeń wynikających z posiłkowania się wsparciem sztucznej inteligencji. Natomiast nie każdy jest świadom występowania podstawowych problemów wynikających ze stosowania modeli sieci neuronowych, które towarzyszą nam od początków ich istnienia.

Skąd się to bierze

Większość nowoczesnych systemów AI bazuje na sieciach neuronowych, a konkretniej – na głębokich sieciach neuronowych. Co to oznacza? Głębokie sieci neuronowe to inny sposób na powiedzenie: „bardzo skomplikowane sieci neuronowe”. Na tyle skomplikowane, że możemy traktować je jako „czarną skrzynkę” – choć bowiem wiemy, jak działają sieci neuronowe, praktycznie nie mamy pojęcia, co dokładnie dzieje się w środku konkretnej jednej głębokiej sieci.

Rysunek koncepcyjny przedstawiający model sieci neuronowej jako czarną skrzynkę (black box)

Dlaczego tak się dzieje? Nie wchodząc w szczegóły uczenia maszynowego, można stwierdzić, że każdą siecią neuronową steruje zestaw parametrów, taki sam jak w prostym równaniu na krzywej, którą możesz pamiętać ze szkoły średniej: np. z = ax + by + c, czyli np. z = 50x + 0,01y + 1, gdzie a, b, c to właśnie te parametry (analogicznie a = 50, b = 0,01, c = 1), x oraz y to wejście do sieci neuronowej, z to wyjście z sieci. W głębokich sieciach neuronowych liczba tych parametrów to setki tysięcy, a nawet miliony lub miliardy. Już ten fakt sam w sobie rodzi komplikacje. Kluczowa jednak jest tutaj nie tyle liczba parametrów, co fakt połączeń między nimi. W dużym uproszczeniu można by rzec, że każdy z tych parametrów jest połączony z innym. 

Na chwilę zapomnijmy jednak o parametrach sieci i wyobraźmy sobie grupę 100 osób. Załóżmy, że każdy chce się przywitać z każdym poprzez podanie dłoni. Ile unikalnych par osób witających się będzie w takiej grupie? Z kombinatoryki wiemy, że będzie to n * (n – 1) / 2, czyli (100 * 99 / 2) = 4950. Być może tego nie widać od razu we wzorze, ale jest to relacja kwadratowa, tzn liczba unikalnych par witających się będzie rosnąć wraz z kwadratem osób. 

Taka sama zasada dotyczy relacji parametrów sieci neuronowej. Zakładając, że każdy parametr komunikuje się z każdym parametrem, można zauważyć, że liczba możliwych połączeń rośnie niebotycznie. Takie modele przerastają nasze możliwości poznawcze w celu wytłumaczenia ich zachowania. Istnieje cała gałąź uczenia maszynowego – explainability in machine learning – które pracuje (jak dotąd, niestety, z małymi tylko sukcesami) nad stworzeniem narzędzi pozwalających nam na zrozumienie tego, co dzieje się wewnątrz sieci neuronowych. Niestety, do tej pory w większości przypadków pozostaje to zagadką.

Wracając do kwestii przykładów adwersarialnych: ta liczba połączeń sprawia, że jesteśmy w stanie użyć niektórych połączeń, które zazwyczaj mają mały wkład do wyjścia z sieci, aby zmienić jej wynik. Jeśli znów odniesiemy się do przykładowej funkcji z = 50x + 0,01y + 1 i założymy, że modeluje ona sieć neuronową, gdzie wartość blisko 1 to gibbon, a wartość większa lub równa 2 to panda, możemy zauważyć, że w większości przypadków, gdy x i y są dodatnie, wyjście będzie większe lub równe 2. Natomiast jeżeli argumenty x oraz y funkcji zostaną zmodyfikowane tak, że x = 0, a y = 2, to dostaniemy wyjście bardzo bliskie 1. W ten sposób, mimo że y w tej funkcji stanowi bardzo mały wkład do wyniku w stosunku do x, będziemy w stanie sterować wartością końcową.

Dzięki temu, że wewnętrzne matematyczne działanie sieci neuronowych oparte jest na różniczkowaniu funkcji, w sposób podobny do przedstawionego powyżej jesteśmy w stanie wytworzyć taki obrazek, który, mimo iż pozornie nie różni się wyglądem od poprzedniego, nasza sieć skategoryzuje jako zupełnie inny obiekt. 

Jak to robić? O tym poniżej.

Jak przeprowadzić atak z użyciem biblioteki torchattacks

Istnieje wiele wariantów ataków adwersarialnych – rozwijanych przez grupy naukowców zajmujących się badaniem podatności sieci na takie zagrożenia. Biblioteka torchattacks, dostępna w repozytorium użytkownika Hoki Kim (Harry24k) na GitHubie, agreguje wiele przydatnych implementacji różnych ataków. Możemy wyróżnić dwa typy ataków: celowane oraz niecelowane. Mówiąc obrazowo: atak niecelowany nie kładzie nacisku na to, aby obrazek pandy był uznany za konkretne inne zwierzę, a po prostu za cokolwiek innego. 

W przykładzie poniżej przedstawiam, jak użyć tej biblioteki, aby na podstawie bazowego zdjęcia pandy z Wikipedii stworzyć obrazek, który dla człowieka jest zgoła nieodróżnialny od bazowego, a dla sieci neuronowej wygląda jak gibbon. Całość kodu wraz z dokładną informacją o wymaganych zależnościach można znaleźć w moim repozytorium na GitHubie.

Ustawiamy środowisko Pythona i instalujemy biblioteki: pytorch, huggingface hub, transformers. Ponadto pobieramy paczkę adversarial-attacks-pytorch. Całość ładujemy w Pythonie:

Z Wikipedii pobieramy przykładowy obrazek pandy oraz listę etykiet:

Następnie ładujemy model ConvNext z serwisu huggingface, używając biblioteki transformers; pomocniczo wczytujemy listę etykiet dla zbioru imagenet: 

Tworzymy własną klasę biblioteki pytorch i wczytujemy uprzednio pobrane zdjęcie pandy:

Sprawdzamy, jak klasyfikowane jest zdjęcie pandy. Obrazek został poprawnie sklasyfikowany jako id 388 – giant panda. Wybieramy również docelowe id, które ma zostać przypisane zdjęciu po modyfikacji, czyli gibbona (id 368):

Jak widać, powyżej wczytany obrazek jest poprawnie klasyfikowany jako panda wielka, o id 388, a nasz cel to gibbon – id 363. Teraz ostatni krok przed samym tworzeniem zdjęcia: pomocniczo utworzymy funkcję target_fun, która po przybraniu zdjęcia i etykiety zwróci docelową etykietę (w naszym przypadku id 363 – gibbon):

A teraz – do ataku! 

W pierwszej kolejności tworzymy obiekt z wykorzystaniem klasy torchattacks.PGD, określamy kilka parametrów, takich jak krok alfa oraz wartość eps (epsylon – pomocnicza wartość określająca maksymalną różnice w pikselu w każdym kroku), a także liczbę kroków algorytmu.

Po drodze ustawiamy parametry normalizacyjne. Są to wartości, które powinny być zastosowane dla każdego kanału RGB w obrazku w celu normalizacji – te wartości są podawane do informacji razem z siecią neuronową bądź ze zbiorem danych.

Dalej ustawiamy funkcję celu jako target_fun – wskazuje ona, jaką etykietę chcemy mieć na wyjściu z modelu przy podaniu wejścia.

Przekazujemy oryginalny bazowy obrazek oraz oryginalną bazową etykietę. Obliczenia mogą chwilę potrwać. Efektem tej pracy jest obiekt, adv_images, zawierający nowy obrazek, który powinien zostać skategoryzowany jako inna klasa (gibbon). 

Zobaczmy, jak wygląda wyjście z modelu przy podaniu naszego adwersarialnego zdjęcia:

Sprawdźmy, jak to wygląda w praktyce:

Jak widać, obrazek po prawej został zakwalifikowany jako gibbon, pomimo braku wielkich różnic.

Poza metodą PGD biblioteka torchattacks oferuje kilkadziesiąt różnych metod.

Projected gradient descent – PGD

Metoda optymalizacyjna wykorzystana do stworzenia adwersarialnego wejścia, przedstawiona powyżej, jest stosunkowo prosta. Można ją z grubsza opisać następującym równaniem:

xt+1 = xt+* sgn(-L(xt,y))

– gdzie x to obrazek wejściowy, y to oczekiwane wyjście z modelu (w naszym przypadku jest to zdjęcie pandy oraz etykieta gibbon), a α to parametr, który ustawiamy ręcznie. Należy zauważyć, że x w tym przypadku to zdjęcie, a więc każda z tych operacji jest efektywnie przeprowadzana per wartość piksela. Intuicyjnie można to wytłumaczyć w ten sposób: sprawdzamy, w którą stronę (plus czy minus – stąd signum) każdemu pikselowi jest bliżej do bycia skategoryzowanym jako gibbon, a następnie do każdego piksela dodajemy małą wartość o „rozmiarze” α w tym kierunku.

Jak się zabezpieczać?

Cóż, niestety, nie zabrzmi to optymistycznie – nie ma takiej metody, która da stuprocentową pewność ochrony przed atakiem adwersarialnym. Na tym etapie możemy założyć, że jest to permanentny bug, wpisany na wieki w matematyczne podstawy sieci neuronowych. Kto wie, być może w przyszłości uda się komuś okiełznać jakąś metodą dżunglę połączeń neuronowych, ale w tym momencie jest to praktycznie niemożliwe.

Najbardziej optymistycznym faktem jest ten, że ataki celowane są trudniejsze od niecelowanych – tj. o wiele trudniej jest uzyskać konkretną złą kategoryzację niż dowolną złą kategoryzację.

Jest natomiast szereg kroków, które możemy przedsięwziąć w celu ochrony: 

Dopasowanie progu – aby utrudnić atakującemu proces, możemy ustalić próg, po którym uznajemy poprawną kategoryzację – tj. zamiast uwzględniać na ślepo najlepszy wynik wyjścia z sieci, możemy sprawdzić, czy przebija się przez pewien próg. 

Używanie dodatkowych metryk i modeli do oceny kategorii możemy użyć więcej niż jednego modelu, co bardzo utrudni pracę potencjalnemu atakującemu.

Wzbogacenie trenowanej sieci o różne typy szumu – tzw. augmentation, czyli dodawanie różnych typów zakłóceń do procesu uczenia sieci neuronowej, może uodpornić sieć na szum.

Pruning – to popularna metoda służąca do optymalizacji sieci. Polega ona na usuwaniu parametrów stanowiących niski wkład do sygnału. Dzięki temu możemy zawęzić pole możliwego ataku.

Trenowanie adwersarialne – powyżej przedstawiona metoda ataku może również służyć do adwersarialnego tworzenia przypadków, o które możemy urozmaicić zbiór treningowy – i przez to uodpornić sieć.

Autorem powyższego wpisu jest Maciej W. Majewski | gingerbreadideas.com

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. Szymon

    To co miało być siłą modeli staje się ich słabością.

    Odpowiedz
  2. Michał

    Taki atak na tych samych danych będzie możliwy tylko na konkretnej grupie aplikacji i tylko do ponownego przeliczenia modelu. Jeśli winny jest szum który dołożył szczegóły nierozpoznawalne dla człowieka, to może od strony aplikacji możnaby było też zaingerować? Przepuścić to przez filtr, który wygładzi cały obrazek. Jeśli obrazek wygładzony zostałby inaczej sklasyfikowany od oryginalnego. Na znak stopu nie pomoże. Nie wiemy, które elementy – detale są identyfikowane przez model jako znak stopu. Czy naklejki były celowo umieszczone, czy jest to przypadek z życia?

    Odpowiedz
  3. Marek

    Super artykuł! Dawać takich wincej! :)

    Odpowiedz
  4. Weronika

    No to mamy bardzo szeroko otwartą furtkę dla oszustów. Strach pomyśleć na ile nowych sposobów będziemy oszukiwani :O

    Odpowiedz
  5. Małgorzata

    Bardzo merytoryczny, przystępny artykuł – dziękuję!

    Odpowiedz
  6. SeeM

    Dziękuję za „popularnonaukowe” podejście do tematu. Łatwiej będzie nam przetrawić dokumentację od badaczy.

    Odpowiedz
  7. Nie lubie byc podgladanym!

    Chetnie kupilbym takie ubranie chroniace przed wykrywaniem w miejscach publicznych.
    Juz nawet w parku nie mozna intymnie przytulic sie do dziewczyny, bo wladze miast instaluja kamery na potege.

    Odpowiedz

Odpowiedz