One place for hosting & domains

      Python

      Cómo usar la función de filtro en Python


      Introducción

      La función filter() integrada de Python puede usarse para crear un nuevo iterador a partir de un iterable existente (como una lista o un diccionario) que filtrará de forma eficiente los elementos usando una función que proporcionamos. Un iterable es un objeto Python que puede “repetirse” es decir, devolverá elementos en una secuencia de forma que podamos usarla en un bucle for.

      La sintaxis básica para la función filter() es:

      filter(function, iterable)
      

      Esto devolverá un objetivo de filtro, que es un iterable. Podemos usar una función como list() para hacer una lista de todos los elementos devueltos en un objeto de filtro.

      La función filter() proporciona una forma de filtrar valores que a menudo pueden ser más eficientes que un list comprehension, especialmente cuando comenzamos a trabajar con conjuntos de datos más grandes. Por ejemplo, un list comprehension creará una nueva lista, que aumentará el tiempo de ejecución para ese procesamiento. Esto significa que una vez que nuestro list comprehension haya completado su expresión, tendremos dos listas en la memoria. Sin embargo, filter() creará un objeto simple que alberga una referencia a la lista original, la función proporcionada y un índice de dónde ir en la lista original, lo que ocupa menos memoria.

      En este tutorial, revisaremos cuatro formas diferentes de usar filter(): con dos estructuras iterables diferentes, con una función lambda y sin función definida.

      Usar filter() con una función

      El primer argumento para filter() es una función, que usamos para decidir si incluir o filtrar cada elemento. La función se invoca una vez para cada elemento en el iterable pasado como segundo argumento y cada vez que devuelve False, se suelta el valor. Ya que este argumento es una función, podemos pasar una función normal o podemos usar las funciones lambda, sobre todo cuando la expresión es menos compleja.

      A continuación, está la sintaxis de un lambda con filter():

      filter(lambda item: item[] expression, iterable)
      

      Con una lista, como la siguiente, podemos incorporar una función lambda con una expresión contra la cual queremos evaluar cada elemento de la lista:

      creature_names = ['Sammy', 'Ashley', 'Jo', 'Olly', 'Jackie', 'Charlie']
      

      Para filtrar esta lista para encontrar los nombres de nuestras criaturas de acuario que comienzan con vocal, podemos ejecutar la siguiente función lambda:

      print(list(filter(lambda x: x[0].lower() in 'aeiou', creature_names)))
      

      Aquí declaramos un elemento en nuestra lista como x. Luego establecemos nuestra expresión para acceder al primer carácter de cada cadena (o carácter “cero”, de forma que x[0]. Reduciendo la capitalización de cada nombre garantiza que esto hará coincidir las letras con la cadena en nuestra expresión "aeiou".

      Finalmente, pasamos el iterable creature_names. Al igual que la sección anterior, aplicamos list() al resultado para crear una lista desde el iterador filter() que devuelve.

      El resultado será el siguiente:

      Output

      ['Ashley', 'Olly']

      Este mismo resultado puede conseguirse usando una función que definamos:

      creature_names = ['Sammy', 'Ashley', 'Jo', 'Olly', 'Jackie', 'Charlie']
      
      def names_vowels(x):
        return x[0].lower() in 'aeiou'
      
      filtered_names = filter(names_vowels, creature_names)
      
      print(list(filtered_names))
      

      Nuestra función names_vowels define la expresión que implementaremos para filtrar creature_names.

      De nuevo, el resultado será el siguiente:

      Output

      ['Ashley', 'Olly']

      En general, las funciones lambda consiguen el mismo resultado con filter() que cuando usamos una función regular. La necesidad de definir una función regular aumenta a medida que la complejidad de las expresiones para filtrar nuestros datos se incrementa, lo que probablemente promueva una mejor legibilidad de nuestro código.

      Usar None con filter()

      Podemos pasar None como el primer argumento para que filter() tenga el filtro iterador devuelto de cualquier valor que Python considere falso. Generalmente, Python considera cualquier cosa con una longitud de 0 (como una lista vacía o una cadena vacía) o numéricamente equivalente a 0 como falso, por tanto el uso del término “falso”.

      En el siguiente caso, queremos filtrar nuestra lista para que solo muestre los números de tanques en nuestro acuario:

      aquarium_tanks = [11, False, 18, 21, "", 12, 34, 0, [], {}]
      

      En este código tenemos una lista que contiene enteros, secuencias vacías y un valor boleano.

      filtered_tanks = filter(None, aquarium_tanks)
      

      Usamos la función filter() con None y pasamos la lista aquarium_tanks como nuestro iterable. Ya que hemos pasado None como el primer argumento, comprobaremos si los elementos de nuestra lista se consideran falsos.

      print(list(filtered_tanks))
      

      Luego envolvemos filtered_tanks en una función list() de forma que devuelva una lista para filtered_tanks cuando imprimamos.

      Aquí vemos que el resultado muestra solo los enteros. Todos los elementos que evaluaron a False, que son equivalentes a 0 en longitud, han sido eliminados por filter():

      Output

      [11, 25, 18, 21, 12, 34]

      Nota: Si no usamos list() e imprimimos filtered_tanks, recibiríamos un objeto de filtro similar a este: <filter object at 0x7fafd5903240>. El objeto de filtro es un iterable, de forma que podríamos hacer un bucle sobre él con for o podemos usar list() para convertirlo en una lista, lo que haremos aquí porque es una buena forma de revisar los resultados.

      Con None hemos usado filter() para eliminar rápidamente elementos de nuestra lista que se consideraban falsos.

      Usar filter() con una Lista de diccionarios

      Cuando tengamos una estructura de datos más compleja, aún podemos usar filter() para evaluar cada uno de los elementos. Por ejemplo, si tenemos una lista de diccionarios, no solo queremos iterar sobre cada elemento en la lista, uno de los diccionarios, sino que también queremos iterar sobre cada par key:value en un diccionario para evaluar todos los datos.

      Como ejemplo, digamos que tenemos una lista de cada criatura en nuestro acuario junto con detalles diferentes sobre cada una de ellas:

      aquarium_creatures = [
        {"name": "sammy", "species": "shark", "tank number": "11", "type": "fish"},
        {"name": "ashley", "species": "crab", "tank number": "25", "type": "shellfish"},
        {"name": "jo", "species": "guppy", "tank number": "18", "type": "fish"},
        {"name": "jackie", "species": "lobster", "tank number": "21", "type": "shellfish"},
        {"name": "charlie", "species": "clownfish", "tank number": "12", "type": "fish"},
        {"name": "olly", "species": "green turtle", "tank number": "34", "type": "turtle"}
      ]
      

      Queremos filtrar estos datos mediante una cadena de búsqueda que damos a la función. Para que filter() acceda a cada diccionario y a cada elemento en los diccionarios, construimos una función anidada, como la siguiente:

      def filter_set(aquarium_creatures, search_string):
          def iterator_func(x):
              for v in x.values():
                  if search_string in v:
                      return True
              return False
          return filter(iterator_func, aquarium_creatures)
      

      Definimos una función filter_set() que toma aquarium_creatures y search_string como parámetros. En filter_set(), pasamos nuestra iterator_func() como la función para filter(). La función filter_set() devolverá el iterador resultante de filter().

      iterator_func() toma x como argumento, lo que representa un elemento en nuestra lista (es decir, un único diccionario).

      A continuación, el bucle for accede a los valores en cada par key:value en nuestros diccionarios, y luego utiliza una instrucción condicional para coprobar si search_string está en v, representando un valor.

      Igual que en nuestros ejemplos anteriores, si la expresión evalúa a True, la función añade el elemento al objeto de filtro. Esto devolverá una vez la función filter_set() que ha completado. Posicionamos return False fuera de nuestro bucle para que compruebe cada elemento en cada diccionario, en vez de devolver tras comprobar solo el primer diccionario.

      Invocamos filter_set() con nuestra lista de diccionarios y la cadena de búsqueda para la que queremos encontrar coincidencias:

      filtered_records = filter_set(aquarium_creatures, "2")    
      

      Una vez que la función se complete, tenemos nuestro objeto de filtro almacenado en la variable filtered_records, que convertimos en una lista e imprimimos:

      print(list(filtered_records))      
      

      Veremos el siguiente resultado de este programa:

      Output

      [{'name': 'ashley', 'species': 'crab', 'tank number': '25', 'type': 'shellfish'}, {'name': 'jackie', 'species': 'lobster', 'tank number': '21', 'type': 'shellfish'}, {'name': 'charlie', 'species': 'clownfish', 'tank number': '12', 'type': 'fish'}]

      Hemos filtrado la lista de diccionarios con la cadena de búsqueda 2. Podemos ver que los tres diccionarios que incluyen un número de tanque con 2 han sido devueltos. Usar nuestra función anidada nos ha permitido acceder a cada elemento y comprobar de forma eficiente en comparación con la cadena de búsqueda.

      Conclusión

      En este tutorial, hemos aprendido las diferentes formas de usar la función filter() en Python. Ahora puede usar filter() con su propia función, una función lambda, o con None para filtrar elementos en estructuras de datos de diferentes complejidades.

      Aunque en este tutorial imprimimos los resultados de filter() inmediatamente en un formato de lista, es probable que en nuestros programas usemos el objeto filter() devuelto y manipulemos aún más los datos.

      Si desea aprender más sobre Python, consulte nuestra serie Cómo crear código en Python 3 y en nuestra página de tema Python.



      Source link

      Austricksen eines neuronalen Netzwerks in Python 3


      Der Autor hat Dev Color dazu ausgewählt, im Rahmen des Programms Write for DOnations eine Spende zu erhalten.

      Kann ein neuronales Netzwerk zur Klassifizierung von Tieren ausgetrickst werden? Das Austricksen einer solchen Klassifizierung mag vielleicht wenig Konsequenzen haben, doch sieht das bei Gesichtsauthentifizierung schon anders aus. Und was ist mit der Software von Prototypen selbstfahrender Autos? Zum Glück gibt es zahlreiche Ingenieure und Forscher, die bei unseren mobilen Geräten und Autos zwischen einem Computermodell für Prototypen und Modellen mit Produktionsqualität stehen. Dennoch haben diese Risiken erhebliche Auswirkungen und müssen von Benutzern, die maschinelles Lernen anwenden, berücksichtigt werden.

      In diesem Tutorial versuchen Sie, eine Klassifizierungsanwendung für Tiere zu täuschen bzw. auszutricksen. Wenn Sie das Tutorial durcharbeiten, verwenden Sie OpenCV, eine Computer-Vision-Bibliothek, und PyTorch, eine Deep Learning Library. Wir werden die folgenden Themen im zugehörigen Bereich des Adversarial Machine Learning behandeln:

      • Erstellen eines gezielten Adversial-Beispiels. Auswählen eines Bilds – etwa eines Hunds. Auswählen einer Zielklasse, z. B. eine Katze. Ihr Ziel besteht darin, das neuronale Netzwerk so zu täuschen, dass es denkt, dass der abgebildete Hund eine Katze sei.
      • Erstellen Sie eine Adversarial-Verteidigung. Kurz gesagt: Schützen Sie Ihr neuronales Netzwerk vor diesen trickreichen Bildern, ohne zu wissen, was der Trick ist.

      Am Ende des Tutorials verfügen Sie über ein Werkzeug zum Austricksen neuronaler Netzwerke und ein Verständnis dafür, wie man sich gegen Tricks verteidigen kann.

      Voraussetzungen

      Um dieses Tutorial zu absolvieren, benötigen Sie Folgendes:

      • Eine lokale Entwicklungsumgebung für Python 3 mit mindestens 1 GB RAM. Unter How to Install and Set Up a Local Programming Environment for Python 3 (Installieren und Einrichten einer lokalen Programmierumgebung für Python 3) finden Sie Informationen darüber, wie Sie die benötigten Konfigurationen vornehmen.
      • Es wird empfohlen, Build an Emotion-Based Dog Filter (Erstellen eines emotionsbasierten Hundefilters) zu konsultieren; dieses Tutorial wird nicht explizit verwendet, führt aber in den Begriff der Klassifizierung ein.

      Schritt 1 – Erstellen des Projekts und Installieren von Abhängigkeiten

      Wir wollen einen Arbeitsbereich für dieses Projekt erstellen und die Abhängigkeiten installieren, die wir benötigen. Sie nennen Ihren Arbeitsbereich AdversarialML:

      Navigieren Sie zum Verzeichnis AdversarialML:

      Erstellen Sie ein Verzeichnis, das alle Ihre Ressourcen enthält:

      • mkdir ~/AdversarialML/assets

      Erstellen Sie dann eine neue virtuelle Umgebung für das Projekt:

      • python3 -m venv adversarialml

      Aktivieren Sie Ihre Umgebung:

      • source adversarialml/bin/activate

      Installieren Sie anschließend PyTorch, ein Deep-Learning-Framework für Python, das wir in diesem Tutorial verwenden werden.

      Auf macOS installieren Sie Pytorch mit dem folgenden Befehl:

      • python -m pip install torch==1.2.0 torchvision==0.4.0

      Auf Linux und Windows verwenden Sie die folgenden Befehle für einen reinen CPU-Build:

      • pip install torch==1.2.0+cpu torchvision==0.4.0+cpu -f https://download.pytorch.org/whl/torch_stable.html
      • pip install torchvision

      Installieren Sie nun vorgepackte Binaries für OpenCV und numpy; das sind Bibliotheken für Computer-Vision bzw. lineare Algebra. OpenCV bietet Hilfsfunktionen wie Bilddrehung und numpy bietet Hilfsfunktionen für lineare Algebra an, z. B. eine Matrixinversion:

      • python -m pip install opencv-python==3.4.3.18 numpy==1.14.5

      Auf Linux-Distributionen müssen Sie libSM.so installieren:

      • sudo apt-get install libsm6 libxext6 libxrender-dev

      Nach Installation der Abhängigkeiten führen wir eine Tierklassifizierung namens ResNet18 aus, was wir als Nächstes beschreiben werden.

      Schritt 2 — Ausführen einer vordefinierten Tierklassifizierung

      Die torchvision-Bibliothek, die offizielle Computer-Vision-Bibliothek für PyTorch, enthält vortrainierte Versionen von verbreiteten neuronalen Computer-Vision-Netzwerken. Diese neuronalen Netzwerke werden alle in ImageNet 2012 trainiert, einem Datensatz mit 1,2 Millionen Trainingsbildern und 1.000 Klassen. Diese Klassen umfassen Fahrzeuge, Orte und vor allem Tiere. In diesem Schritt werden Sie eines dieser vortrainierten neuronalen Netzwerke (ResNet18) ausführen. Wir werden ResNet18, trainiert in ImageNet, als „Tierklassifizierung“ bezeichnen.

      Was ist ResNet18? ResNet18 ist das kleinste neuronale Netzwerk in einer Familie neuronaler Netzwerke, die Residual Neural Networks genannt werden, entwickelt von MSR (et al.). Kurz gesagt: Er hat herausgefunden, dass ein neuronales Netzwerk (angegeben als Funktion f mit Eingabe x und Ausgabe f(x)) mit einer "residual connection" x + f(x) bessere Ergebnisse liefern würde. Diese Residual Connection wird auch heute noch in hochmodernen neuronalen Netzwerken häufig verwendet. Beispielsweise FBNetV2, FBNetV3.

      Laden Sie dieses Bild eines Hundes mit dem folgenden Befehl herunter:

      • wget -O assets/dog.jpg https://www.xpresservers.com/wp-content/uploads/2020/06/How-To-Trick-a-Neural-Network-in-Python-3.png

      Bild von Corgi nahe Teich

      Laden Sie dann eine JSON-Datei herunter, um die neuronale Netzwerkausgabe in einen menschenlesbaren Klassennamen zu konvertieren:

      • wget -O assets/imagenet_idx_to_label.json https://raw.githubusercontent.com/do-community/tricking-neural-networks/master/utils/imagenet_idx_to_label.json

      Erstellen Sie als Nächstes ein Skript zum Ausführen Ihres vortrainierten Modells für das Hundebild. Erstellen Sie eine neue Datei namens step_2_pretrained.py:

      • nano step_2_pretrained.py

      Fügen Sie zunächst das Python-Boilerplate hinzu, indem Sie die erforderlichen Pakete importieren und eine main-Funktion deklarieren:

      step_2_pretrained.py

      from PIL import Image
      import json
      import torchvision.models as models
      import torchvision.transforms as transforms
      import torch
      import sys
      
      def main():
          pass
      
      if __name__ == '__main__':
          main()
      

      Als Nächstes laden Sie das Mapping von neuronaler Netzwerkausgabe zu menschenlesbaren Klassennamen. Fügen Sie dies direkt nach Ihren Importanweisungen und vor Ihrer main-Funktion hinzu:

      step_2_pretrained.py

      . . .
      def get_idx_to_label():
          with open("assets/imagenet_idx_to_label.json") as f:
              return json.load(f)
      . . .
      

      Erstellen Sie eine Funktion zur Bildtransformation, die sicherstellt, dass Ihr Eingabebild zum einen die richtigen Dimensionen aufweist und zum anderen richtig normalisiert ist. Fügen Sie direkt nach der letzten Funktion folgende Funktion hinzu:

      step_2_pretrained.py

      . . .
      def get_image_transform():
          transform = transforms.Compose([
            transforms.Resize(224),
            transforms.CenterCrop(224),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                 std=[0.229, 0.224, 0.225])
          ])
          return transform
      . . .
      

      In get_image_transform definieren Sie eine Reihe verschiedener Transformationen für die Bilder, die an Ihr neuronales Netzwerk übergeben werden:

      • transforms.Resize(224): Ändert die kleinere Seite des Bildes auf 224. Wenn Ihr Bild beispielsweise 448 x 672 groß ist, würde diese Operation das Bild beispielsweise auf 224 x 336 reduzieren.
      • transforms.CenterCrop(224): Nimmt einen Zuschnitt von der Bildmitte mit der Größe 224 x 224 vor.
      • transforms.ToTensor(): Konvertiert das Bild in einen PyTorch-Tensor. Alle PyTorch-Modelle erfordern PyTorch-Tensoren als Eingabe.
      • transforms.Normalize(mean=..., std=...): Standardisiert Ihre Eingabe, indem der Mittelwert subtrahiert und dann durch die Standardabweichung geteilt wird. Dies wird in der torchvision-Dokumentation genauer beschrieben.

      Fügen Sie ein Dienstprogramm hinzu, um die Tierklasse je nach Bild vorherzusagen. Diese Methode verwendet die beiden vorherigen Dienstprogramme zur Durchführung der Tierklassifizierung:

      step_2_pretrained.py

      . . .
      def predict(image):
          model = models.resnet18(pretrained=True)
          model.eval()
      
          out = model(image)
      
          _, pred = torch.max(out, 1)  
          idx_to_label = get_idx_to_label()  
          cls = idx_to_label[str(int(pred))]  
          return cls
      . . .
      

      Hier klassifiziert die Funktion predict das bereitgestellte Bild mit einem vortrainierten neuronalen Netzwerk:

      • model.resnet18(pretrained=True): Lädt ein vortrainiertes neuronales Netzwerk namens ResNet18.
      • model.eval(): Ändert das vorhandene Modell so, dass es im Modus ‘evaluation’ ausgeführt wird. Der einzige andere Modus ist der Modus ‘training’, doch ist der Trainingsmodus nicht erforderlich, da Sie das Modell in diesem Tutorial nicht trainieren (d. h. die Parameter des Modells nicht aktualisieren).
      • out = model(image): Führt das neuronale Netzwerk für das bereitgestellte, transformierte Bild aus.
      • _, pred = torch.max(out, 1): Das neuronale Netzwerk gibt eine Wahrscheinlichkeit für jede mögliche Klasse aus. Dieser Schritt berechnet den Index der Klasse mit der höchsten Wahrscheinlichkeit. Beispielsweise wenn out = [0.4, 0.1, 0.2], dann pred = 0.
      • idx_to_label = idx_to_label: Erhält ein Mapping vom Klassenindex zu menschenlesbaren Klassennamen. Beispielsweise könnte das Mapping {0: Katze, 1: Hund, 2: Fisch} lauten.
      • cls = idx_to_label[str(int(pred))]: Konvertiert den vorhergesagten Klassenindex in einen Klassennamen. Die in den letzten beiden Punkten genannten Beispiele würden cls = idx_to_label[0] = 'cat' ergeben.

      Als Nächstes fügen Sie nach der letzten Funktion ein Dienstprogramm zum Laden von Bildern hinzu:

      step_2_pretrained.py

      . . .
      def load_image():
          assert len(sys.argv) > 1, 'Need to pass path to image'
          image = Image.open(sys.argv[1])
      
          transform = get_image_transform()
          image = transform(image)[None]
          return image
      . . .
      

      Dadurch wird ein Bild aus dem im ersten Argument angegebenen Pfad in das Skript geladen. transform(image)[None] wendet die Reihenfolge der in den vorherigen Zeilen definierten Bildtransformationen an.

      Abschließend füllen Sie Ihre main-Funktion mit Folgendem, um Ihr Bild zu laden und das Tier im Bild zu klassifizieren:

      step_2_pretrained.py

      def main():
          x = load_image()
          print(f'Prediction: {predict(x)}')
      

      Vergewissern Sie sich, dass Ihre Datei mit unserem letzten Schritt 2 bei step_2_pretrained.py in GitHub übereinstimmt. Speichern und beenden Sie Ihr Skript und führen Sie die Tierklassifizierung aus:

      • python step_2_pretrained.py assets/dog.jpg

      Dadurch wird folgende Ausgabe erstellt, was zeigt, dass Ihre Tierklassifizierung wie erwartet funktioniert:

      Output

      Prediction: Pembroke, Pembroke Welsh corgi

      Das beschließt die Ausführung von Inferenz mit Ihrem vortrainierten Modell. Als Nächstes sehen Sie ein Adversarial-Beispiel in der Praxis, bei dem ein neuronales Netzwerk mit unmerklichen Unterschieden im Bild ausgetrickst wird.

      Schritt 3 — Ausprobieren eines Adversarial-Beispiels

      Jetzt werden Sie ein Adversarial-Beispiel synchronisieren und das neuronale Netzwerk für dieses Beispiel testen. Für dieses Tutorial erstellen Sie verschiedene Adversarial-Beispiele im Format x + r, wobei x das ursprüngliche Bild und r eine „Perturbation“ ist. Sie werden die Perturbation r noch selbst erstellen, doch in diesem Schritt werden Sie eine herunterladen, die wir zuvor für Sie erstellt haben. Starten Sie mit dem Herunterladen der Perturbation r:

      • wget -O assets/adversarial_r.npy https://github.com/do-community/tricking-neural-networks/blob/master/outputs/adversarial_r.npy?raw=true

      Verbinden Sie nun das Bild mit der Perturbation. Erstellen Sie eine neue Datei namens step_3_adversarial.py:

      • nano step_3_adversarial.py

      In dieser Datei führen Sie den folgenden Prozess mit drei Schritten aus, um ein adversarial-Beispiel zu erstellen:

      1. Transformieren eines Bilds
      2. Anwenden der Perturbation r
      3. Inverses Transformieren des pertubierten Bilds

      Am Ende von Schritt 3 werden Sie über ein gegensätzliches Bild verfügen. Importieren Sie zunächst die erforderlichen Pakete und deklarieren Sie eine Hauptfunktion:

      step_3_adversarial.py

      from PIL import Image
      import torchvision.transforms as transforms
      import torch
      import numpy as np
      import os
      import sys
      
      from step_2_pretrained import get_idx_to_label, get_image_transform, predict, load_image
      
      
      def main():
          pass
      
      
      if __name__ == '__main__':
          main()
      

      Erstellen Sie als Nächstes eine “Bildtransformation”, die die frühere Bildtransformation umkehrt. Platzieren Sie dies nach Ihren Importen vor der main-Funktion:

      step_3_adversarial.py

      . . .
      def get_inverse_transform():
          return transforms.Normalize(
              mean=[-0.485/0.229, -0.456/0.224, -0.406/0.255],  # INVERSE normalize images, according to https://pytorch.org/docs/stable/torchvision/models.html
              std=[1/0.229, 1/0.224, 1/0.255])
      . . .
      

      Wie zuvor subtrahiert die Funktion transforms.Normalize den Mittelwert und teilt durch die Standardabweichung (d. h. für das ursprüngliche Bild x, y = transforms.Normalize(mean=u, std=o) = (x - u) / o). Sie machen etwas Algebra und definieren eine neue Operation, die diese Normalisierungsfunktion umkehrt (transforms.Normalize(mean=-u/o, std=1/o) = (y - -u/o) / 1/o = (y + u/o) o = yo + u = x).

      Fügen Sie im Rahmen der inversen Transformation eine Methode hinzu, die einen PyTorch-Tensor in ein PIL-Bild umwandelt. Fügen Sie dies nach der letzten Funktion hinzu:

      step_3_adversarial.py

      . . .
      def tensor_to_image(tensor):
          x = tensor.data.numpy().transpose(1, 2, 0) * 255.  
          x = np.clip(x, 0, 255)
          return Image.fromarray(x.astype(np.uint8))
      . . .
      
      • tensor.data.numpy() konvertiert den PyTorch-Tensor in ein NumPy-Array. .transpose(1, 2, 0) arrangiert (Kanäle, Breite, Höhe) in (Höhe, Breite, Kanäle) um. Dieses NumPy-Array befindet sich etwa im Bereich (0, 1). Abschließend multiplizieren Sie mit 255, um sicherzustellen, dass das Bild nun im Bereich (0, 255) ist.
      • np.clip sorgt dafür, dass alle Werte im Bild zwischen (0, 255) liegen.
      • x.astype(np.uint8) sorgt dafür, dass alle Bildwerte integer sind. Abschließend erstellt Image.fromarray(...) ein PIL-Bildobjekt aus dem NumPy-Array.

      Verwenden Sie dann diese Dienstprogramme zum Erstellen des adversarial-Beispiels mit Folgendem:

      step_3_adversarial.py

      . . .
      def get_adversarial_example(x, r):
          y = x + r
          y = get_inverse_transform()(y[0])
          image = tensor_to_image(y)
          return image
      . . .
      

      Diese Funktion generiert das adversarial-Beispiel, wie zu Anfang des Abschnitts beschrieben:

      1. y = x + r. Nehmen Sie Ihre Perturbation r und fügen Sie sie dem Originalbild x hinzu.
      2. get_inverse_transform: Erhalten und wenden Sie die umgekehrte Bildtransformation an, die Sie in einigen Zeilen vorher definiert haben.
      3. tensor_to_image: Konvertieren Sie abschließend den PyTorch-Tensor wieder in ein Bildobjekt.

      Als Letztes ändern Sie Ihre main-Funktion so, dass sie das Laden des Bilds, das Laden der adversarial-Perturbation r, das Anwenden der Perturbation, das Speichern des adversarial-Beispiels auf Festplatte und das Ausführen der Vorhersage für das adversarial-Beispiel ausführt:

      step_3_adversarial.py

      def main():
          x = load_image()
          r = torch.Tensor(np.load('assets/adversarial_r.npy'))
      
          # save perturbed image
          os.makedirs('outputs', exist_ok=True)
          adversarial = get_adversarial_example(x, r)
          adversarial.save('outputs/adversarial.png')
      
          # check prediction is new class
          print(f'Old prediction: {predict(x)}')
          print(f'New prediction: {predict(x + r)}')
      

      Ihre abgeschlossene Datei sollte mit step_3_adversarial.py in GitHub übereinstimmen. Speichern Sie die Datei, beenden Sie den Editor und starten Sie Ihr Skript mit:

      • python step_3_adversarial.py assets/dog.jpg

      Sie sehen diese Ausgabe:

      Output

      Old prediction: Pembroke, Pembroke Welsh corgi New prediction: goldfish, Carassius auratus

      Sie haben nun ein Adversarial-Beispiel erstellt: Es täuscht das neuronale Netzwerk, sodass es denkt, ein Corgi sei ein Goldfisch. Im nächsten Schritt erstellen Sie tatsächlich die Perturbation r, die Sie hier verwendet haben.

      Schritt 4 — Verstehen eines Adversarial-Beispiels

      Informationen zur Klassifizierung finden Sie in „How to Build an Emotion-Based Dog Filter“ („Erstellen eines emotionsbasierten Hundefilters“).

      Sie erinnern sich bestimmt daran, dass Ihr Klassifizierungsmodell für jede Klasse eine Wahrscheinlichkeit ausgibt. Bei der Inferenz prognostiziert das Modell die Klasse mit der höchsten Wahrscheinlichkeit. Beim Training aktualisieren Sie die Modellparameter t so, dass die Wahrscheinlichkeit der richtigen Klasse y angesichts Ihrer Daten x maximiert wird.

      argmax_y P(y|x,t)
      

      Um jedoch Adversarial-Beispiele zu generieren, ändern Sie nun Ihr Ziel. Anstatt eine Klasse zu finden, besteht Ihr Ziel nun darin, ein neues Bild (x) zu finden. Wählen Sie eine beliebige andere Klasse als die richtige Klasse. Wir nennen diese neue Klasse w. Ihr neues Ziel besteht nun darin, die Wahrscheinlichkeit der falschen Klasse zu maximieren.

      argmax_x P(w|x)
      

      Beachten Sie, dass die neuronalen Netzwerkgewichtungen t aus dem obigen Ausdruck fehlen. Das liegt daran, dass Sie nun die Rolle des Adversary übernehmen: Jemand anderes hat ein Modell trainiert und bereitgestellt. Sie dürfen nur Adversarial-Eingaben erstellen und dürfen das bereitgestellte Modell nicht ändern. Um das Adversarial-Beispiel x zu generieren, können Sie “training” ausführen. Allerdings aktualisieren Sie nicht die neuronalen Netzwerkgewichtungen, sondern das Eingabebild mit dem neuen Ziel.

      Zur Erinnerung: In diesem Tutorial gehen Sie davon aus, dass das Adversarial-Beispiel eine affine Transformation von x ist. Mit anderen Worten: Ihr Adversarial-Beispiel nimmt die Form x + r für einige r an. Im nächsten Schritt schreiben Sie ein Skript zur Generierung dieses r.

      Schritt 5 — Erstellen eines Adversarial-Beispiels

      In diesem Schritt lernen Sie eine Perturbation r, sodass Ihr Corgi als Goldfisch falsch klassifiziert wird. Erstellen Sie eine neue Datei namens step_5_perturb.py:

      Importieren Sie zunächst die erforderlichen Pakete und deklarieren Sie eine main-Funktion:

      step_5_perturb.py

      from torch.autograd import Variable
      import torchvision.models as models
      import torch.nn as nn
      import torch.optim as optim
      import numpy as np
      import torch
      import os
      
      from step_2_pretrained import get_idx_to_label, get_image_transform, predict, load_image
      from step_3_adversarial import get_adversarial_example
      
      
      def main():
          pass
      
      
      if __name__ == '__main__':
          main()
      

      Definieren Sie direkt nach Ihren Importen und vor der main-Funktion zwei Konstanten:

      step_5_perturb.py

      . . .
      TARGET_LABEL = 1
      EPSILON = 10 / 255.
      . . .
      

      Die erste Konstante TARGET_LABEL ist die Klasse, um den Corgi falsch zu klassifizieren. In diesem Fall entspricht der Index 1 „Goldfisch“. Die zweite Konstante EPSILON ist die maximale Perturbation, die für jeden Bildwert erlaubt ist. Diese Grenze wird eingeführt, damit das Bild unmerklich verändert wird.

      Fügen Sie nach Ihren beiden Konstanten eine helper-Funktion hinzu, um ein neuronales Netzwerk und den Perturbationsparameter r zu definieren:

      step_5_perturb.py

      . . .
      def get_model():
          net = models.resnet18(pretrained=True).eval()
          r = nn.Parameter(data=torch.zeros(1, 3, 224, 224), requires_grad=True)
          return net, r
      . . .
      
      • model.resnet18(pretrained=True) lädt ein vortrainiertes neuronales Netzwerk namens ResNet18, wie zuvor. Ebenso wie zuvor versetzen Sie das Modell mit .eval in den Evaluierungsmodus.
      • nn.Parameter(...) definiert eine neue Perturbation r, die Größe des Eingabebilds. Das Eingabebild ist auch von der Größe (1, 3, 224, 224). Das Schlüsselwortargument requires_grad=True sorgt dafür, dass Sie diese Perturbation r in dieser Datei in späteren Zeilen aktualisieren können.

      Als Nächstes beginnen Sie, Ihre main-Funktion zu ändern. Laden Sie zunächst das Modell net sowie die Eingänge x und definieren die Bezeichnung label:

      step_5_perturb.py

      . . .
      def main():
          print(f'Target class: {get_idx_to_label()[str(TARGET_LABEL)]}')
          net, r = get_model()
          x = load_image()
          labels = Variable(torch.Tensor([TARGET_LABEL])).long()
        . . .
      

      Als Nächstes definieren Sie sowohl das Kriterium als auch den Optimizer in Ihrer main-Funktion. Das Kriterium sagt PyTorch, was das Ziel ist – das heißt, welcher Verlust minimiert werden soll. Der Optimizer sagt PyTorch, wie Ihr Parameter r trainiert werden soll:

      step_5_perturb.py

      . . .
          criterion = nn.CrossEntropyLoss()
          optimizer = optim.SGD([r], lr=0.1, momentum=0.1)
      . . .
      

      Fügen Sie direkt danach die Haupttrainingsschleife für Ihren Parameter r hinzu:

      step_5_perturb.py

      . . .
          for i in range(30):
              r.data.clamp_(-EPSILON, EPSILON)
              optimizer.zero_grad()
      
              outputs = net(x + r)
              loss = criterion(outputs, labels)
              loss.backward()
              optimizer.step()
      
              _, pred = torch.max(outputs, 1)
              if i % 5 == 0:
                  print(f'Loss: {loss.item():.2f} / Class: {get_idx_to_label()[str(int(pred))]}')
      . . .
      

      Bei jeder Iteration dieser Trainingsschleife tun Sie Folgendes:

      • r.data.clamp_(...): Stellen Sie sicher, dass der Parameter r klein ist, innerhalb von EPSILON 0.
      • optimizer.zero_grad(): Löschen Sie alle Gradiente, die Sie in der vorherigen Iteration berechnet haben.
      • model(x + r): Führen Sie Inferenz für das modifizierte Bild x + r aus.
      • Berechnen Sie den loss.
      • Berechnen Sie den Gradienten loss.backward.
      • Nehmen Sie einen Gradientenabstiegsschritt optimizer.step vor.
      • Berechnen Sie die Vorhersage pred.
      • Melden Sie abschließend den Verlust und die prognostizierten Klasse print(...).

      Speichern Sie als Nächstes die letzte Perturbation r:

      step_5_perturb.py

      def main():
          . . .
          for i in range(30):
              . . .
          . . .
          np.save('outputs/adversarial_r.npy', r.data.numpy())
      

      Speichern Sie direkt danach, noch in der main-Funktion, das perturbierte Bild:

      step_5_perturb.py

      . . .
          os.makedirs('outputs', exist_ok=True)
          adversarial = get_adversarial_example(x, r)
      

      Führen Sie abschließend die Vorhersage sowohl für das Originalbild als auch das Adversarial-Beispiel aus:

      step_5_perturb.py

          print(f'Old prediction: {predict(x)}')
          print(f'New prediction: {predict(x + r)}')
      

      Überprüfen Sie sorgfältig Ihre Skriptübereinstimmungen step_5_perturb.py in GitHub. Speichern, beenden und führen Sie das Skript aus:

      • python step_5_perturb.py assets/dog.jpg

      Ihr Skript gibt Folgendes aus.

      Output

      Target class: goldfish, Carassius auratus Loss: 17.03 / Class: Pembroke, Pembroke Welsh corgi Loss: 8.19 / Class: Pembroke, Pembroke Welsh corgi Loss: 5.56 / Class: Pembroke, Pembroke Welsh corgi Loss: 3.53 / Class: Pembroke, Pembroke Welsh corgi Loss: 1.99 / Class: Pembroke, Pembroke Welsh corgi Loss: 1.00 / Class: goldfish, Carassius auratus Old prediction: Pembroke, Pembroke Welsh corgi New prediction: goldfish, Carassius auratus

      Die letzten beiden Zeilen zeigen, dass Sie die Gestaltung eines Adversarial-Beispiels von Grund auf nun abgeschlossen haben. Ihr neuronales Netzwerk klassifiziert nun ein perfekt vernünftiges Corgi-Bild als Goldfisch.

      Damit haben Sie gezeigt, dass neuronale Netzwerke leicht getäuscht werden können. Außerdem hat das Fehlen von Robustheit bei Adversarial-Beispielen erhebliche Folgen. Die nächste natürliche Frage ist diese: Wie können Sie Adversarial-Beispiele bekämpfen? Verschiedene Organisationen wie OpenAI haben viel Forschung betrieben. Im nächsten Abschnitt führen Sie eine Verteidigungsmaßnahme aus, um dieses Adversarial-Beispiel zu vereiteln.

      Schritt 6 — Verteidigen vor Adversarial-Beispielen

      In diesem Schritt werden Sie eine Verteidigung gegen Adversarial-Beispiele implementieren. Die Idee ist folgendermaßen: Sie sind nun Eigentümer der Tierklassifizierung, die in der Produktion bereitgestellt wird. Sie wissen nicht, welche Adversarial-Beispiele generiert werden können. Sie können jedoch das Bild oder das Modell ändern, um sich vor Angriffen zu schützen.

      Bevor Sie sich schützen, sollten Sie selbst sehen, wie unmerklich die Bildmanipulation ist. Öffnen Sie die beiden folgenden Bilder:

      1. assets/dog.jpg
      2. outputs/adversarial.png

      Hier sehen Sie beide nebeneinander. Ihr Originalbild wird ein anderes Seitenverhältnis aufweisen. Können Sie sagen, welches das Adversarial-Beispiel ist?

      (links) Corgi als Goldfisch, Adversarial, (rechts) Corgi als Hund nicht Adversarial

      Beachten Sie, dass das neue Bild genau wie das Original aussieht. Beim linken Bild handelt es sich um Ihr Adversarial-Bild. Laden Sie das Bild zur Sicherheit herunter und führen Sie Ihr Evaluierungsskript aus:

      • wget -O assets/adversarial.png https://github.com/alvinwan/fooling-neural-network/blob/master/outputs/adversarial.png?raw=true
      • python step_2_pretrained.py assets/adversarial.png

      Dadurch wird die Klasse Goldfisch ausgeben, was als Beleg für das Adversarial-Bild dient:

      Output

      Prediction: goldfish, Carassius auratus

      Sie führen eine ziemlich naive, aber effektive Schutzmaßnahme aus: Komprimieren Sie das Bild durch Schreiben in ein verlustreiches JPEG-Format. Öffnen Sie die interaktive Python-Aufforderung:

      Laden Sie dann das Adversarial-Bild als PNG und speichern Sie nun als JPG.

      • from PIL import Image
      • image = Image.open('assets/adversarial.png')
      • image.save('outputs/adversarial.jpg')

      Geben Sie Strg+D ein, um die interaktive Python-Eingabeaufforderung zu verlassen. Führen Sie als Nächstes Inferenz mit Ihrem Modell für das komprimierte Adversarial-Beispiel aus:

      • python step_2_pretrained.py outputs/adversarial.jpg

      Dadurch wird jetzt die Klasse Corgi ausgegeben, was die Wirksamkeit Ihrer einfachen Verteidigung beweist.

      Output

      Prediction: Pembroke, Pembroke Welsh corgi

      Sie haben nun Ihre erste Adversarial-Verteidigung abgeschlossen. Beachten Sie, dass Sie für diese Verteidigung nicht nicht wissen müssen, wie das Adversarial-Beispiel generiert wurde. Dadurch wird die Verteidigung so effektiv. Außerdem gibt es viele andere Formen der Verteidigung, von denen viele ein Neutrainieren des neuronalen Netzwerks beinhalten. Allerdings sind diese Verfahren zum Neutrainieren ein eigenes Thema, das über den Umfang dieses Tutorials hinausgeht. Damit schließt dieser Leitfaden zum Adversarial Machine Learning ab.

      Zusammenfassung

      Um die Auswirkungen Ihrer Arbeit in diesem Tutorial zu verstehen, sehen Sie noch einmal die beiden Bilder nebeneinander an: das Original und das Adversarial-Beispiel.

      (links) Corgi als Goldfisch, Adversarial, (rechts) Corgi als Hund, nicht Adversarial

      Obwohl beide Bilder mit dem menschlichen Auge gleich aussehen, wurde das erste manipuliert, um Ihr Modell zu täuschen. Beide Bilder zeigen eindeutig einen Corgi, doch ist das Modell sehr zuversichtlich, dass das zweite Modell einen Goldfisch enthält. Das sollte Ihnen Sorge bereiten; denken Sie am Ende dieses Tutorial daran, dass Ihr Modell fragil ist. Einfach durch Anwendung einer simplen Transformation können Sie es täuschen. Dies sind reale, plausible Gefahren, denen auch hochmoderne Forschung nicht gewachsen ist. Forschung über Machine-Learning-Sicherheit ist genauso anfällig für diese Fehler; als Benutzer ist es Ihre Aufgabe, maschinelles Lernen sicher anzuwenden. Weiteres Lesematerial finden Sie unter folgenden Links:

      Für mehr Informationen über maschinelles Lernen und Tutorials können Sie unsere Themenseite zum maschinellen Lernen besuchen.



      Source link

      Como enganar uma rede neural no Python 3


      O autor selecionou a Dev Color para receber uma doação como parte do programa Write for DOnations.

      Será que uma rede neural para classificação de animais pode ser enganada? Enganar um classificador de animais pode gerar poucas consequências, mas e se nosso autenticador facial pudesse ser enganado? Ou o software do nosso protótipo de carro autônomo? Felizmente,existem legiões de engenheiros e pesquisas entre um modelo visual computacional protótipo e modelos de qualidade de produção em nossos dispositivos móveis ou carros. Ainda assim, esses riscos têm implicações significativas e é importante que sejam considerados pelos profissionais de machine learning.

      Neste tutorial, você irá tentar “iludir” ou enganar um classificador de animais. Ao longo do tutorial, você irá usar o OpenCV, uma biblioteca de visão computacional e o PyTorch, uma biblioteca de deep learning. Os seguintes tópicos serão abordados no campo associado do adversarial machine learning (machine learning contraditório):

      • Crie um exemplo contraditório direcionado. Escolha uma imagem, digamos, de um cachorro. Escolha uma classe alvo, digamos, um gato. Seu objetivo é enganar a rede neural para acreditar que o cão retratado é um gato.
      • Crie uma defesa contraditória. Em resumo, proteja sua rede neural contra essas imagens suspeitas, sem saber qual é o truque.

      Ao final do tutorial, você terá uma ferramenta para enganar redes neurais e um entendimento sobre como se defender contra os truques.

      Pré-requisitos

      Para concluir este tutorial, você precisará do seguinte:

      Passo 1 — Criando o projeto e instalando as dependências

      Vamos criar um espaço de trabalho para este projeto e instalar as dependências que você irá precisar. Você irá chamar seu espaço de trabalho AdversarialML:

      Navegue até o diretório AdversarialML:

      Crie um diretório para manter todos os seus recursos:

      • mkdir ~/AdversarialML/assets

      A seguir, crie um novo ambiente virtual para o projeto:

      • python3 -m venv adversarialml

      Ative seu ambiente:

      • source adversarialml/bin/activate

      Em seguida, instale o PyTorch, um framework de deep learning para Python que você usará neste tutorial.

      No macOS, instale o Pytorch com o seguinte comando:

      • python -m pip install torch==1.2.0 torchvision==0.4.0

      No Linux e Windows, utilize os seguintes comandos para uma compilação CPU-only:

      • pip install torch==1.2.0+cpu torchvision==0.4.0+cpu -f https://download.pytorch.org/whl/torch_stable.html
      • pip install torchvision

      Agora, instale binários pré-empacotados para o OpenCV e numpy, que são bibliotecas para visão computacional e álgebra linear, respectivamente. O OpenCV oferece utilitários como rotações de imagem, e o numpy oferece utilitários de álgebra linear, como inversão de matriz:

      • python -m pip install opencv-python==3.4.3.18 numpy==1.14.5

      Em distribuições Linux, você precisará instalar a libSM.so:

      • sudo apt-get install libsm6 libxext6 libxrender-dev

      Com as dependências instaladas, vamos executar um classificador de animais chamado ResNet18, que descrevemos a seguir.

      Passo 2 — Executando um classificador de animais pré-treinado

      A biblioteca torchvision, que é a biblioteca oficial de visão computacional para o PyTorch, contém versões pré-treinadas de redes neurais de visão computacional comumente usadas. Essas redes neurais são todas treinadas no ImageNet 2012, um conjunto de dados que consiste em 1,2 milhões de imagens de treinamento com 1000 classes. Essas classes incluem veículos, lugares e, acima de tudo, animais. Neste passo, você irá executar uma dessas redes neurais pré-treinadas chamada ResNet18. Chamaremos a rede neural ResNet18 treinada no ImageNet de “classificador de animais”.

      O que é o ResNet18? O ResNet18 é a menor rede neural em uma família de redes neurais chamada redes neurais residuais, desenvolvida pela MSR (He et al.). Em resumo, ele descobriu que uma rede neural (denotada como uma função f, com entrada x, e saída f(x)) teria melhor desempenho com uma “conexão residual” x + f(x). Essa conexão residual é usada prolificamente em redes neurais no estado da arte, mesmo hoje. Por exemplo, FBNetV2, FBNetV3.

      Baixe esta imagem de um cachorro com o seguinte comando:

      • wget -O assets/dog.jpg https://www.xpresservers.com/wp-content/uploads/2020/06/How-To-Trick-a-Neural-Network-in-Python-3.png

      Imagem de um corgi correndo perto de uma lagoa

      Então, baixe um arquivo JSON para converter o resultado da rede neural em um nome de classe humanamente legível:

      • wget -O assets/imagenet_idx_to_label.json https://raw.githubusercontent.com/do-community/tricking-neural-networks/master/utils/imagenet_idx_to_label.json

      Em seguida, crie um script para executar seu modelo pré-treinado na imagem do cão. Crie um novo arquivo chamado step_2_pretrained.py:

      • nano step_2_pretrained.py

      Primeiro, adicione o código padrão Python importando os pacotes necessários e declarando uma função main (principal):

      step_2_pretrained.py

      from PIL import Image
      import json
      import torchvision.models as models
      import torchvision.transforms as transforms
      import torch
      import sys
      
      def main():
          pass
      
      if __name__ == '__main__':
          main()
      

      Em seguida, carregue o mapeamento a partir do resultado da rede neural para nomes de classe humanamente legíveis. Adicione isto diretamente após suas declarações de importação e antes de sua função main:

      step_2_pretrained.py

      . . .
      def get_idx_to_label():
          with open("assets/imagenet_idx_to_label.json") as f:
              return json.load(f)
      . . .
      

      Crie uma função de transformação de imagem que irá garantir que sua imagem de entrada tenha as dimensões corretas e que seja normalizada corretamente. Adicione a seguinte função diretamente após a última:

      step_2_pretrained.py

      . . .
      def get_image_transform():
          transform = transforms.Compose([
            transforms.Resize(224),
            transforms.CenterCrop(224),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                 std=[0.229, 0.224, 0.225])
          ])
          return transform
      . . .
      

      Em get_image_transform, você define um número de transformações diferentes para aplicar às imagens que são passadas para sua rede neural:

      • transforms.Resize(224): redimensiona o lado menor da imagem para 224. Por exemplo, se a imagem tiver 448 x 672, esta operação reduziria a resolução dela para 224 x 336.
      • transforms.CenterCrop(224): faz um recorte do centro da imagem, de tamanho 224 x 224.
      • transforms.ToTensor(): Converte a imagem em um tensor do PyTorch. Todos os modelos PyTorch exigem os tensores do PyTorch como entrada.
      • transforms.Normalize(mean=..., std=...): Normaliza sua entrada primeiro subtraindo a média, então dividindo pelo desvio padrão. Isso é descrito mais precisamente na documentação do torchvision.

      Adicione um utilitário para prever a classe animal, dada a imagem. Este método usa ambos os utilitários anteriores para realizar a classificação de animais:

      step_2_pretrained.py

      . . .
      def predict(image):
          model = models.resnet18(pretrained=True)
          model.eval()
      
          out = model(image)
      
          _, pred = torch.max(out, 1)  
          idx_to_label = get_idx_to_label()  
          cls = idx_to_label[str(int(pred))]  
          return cls
      . . .
      

      Aqui a função de predict (prever) classifica a imagem fornecida usando uma rede neural pré-treinada:

      • models.resnet18(pretrained=True): Carrega uma rede neural pré-treinada chamada ResNet18.
      • model.eval(): modifica o modelo em vigor para ser executar no modo ‘avaliação’. O único outro modo é o modo ‘treinamento’, mas o modo de treinamento não é necessário, pois você não está treinando o modelo (ou seja, atualizando os parâmetros do modelo) neste tutorial.
      • out = model(image): Executa a rede neural na imagem transformada fornecida.
      • _, pred = torch.max(out, 1): A rede neural gera uma probabilidade para cada classe possível. Esse passo computa o índice da classe com a maior probabilidade. Por exemplo, se out = [0.4, 0.1, 0.2], então pred = 0.
      • idx_to_label = get_idx_to_label(): Obtém um mapeamento do índice de classes para nomes de classe humanamente legíveis. Por exemplo, o mapeamento poderia ser {0: cat, 1: dog, 2: fish}.
      • cls = idx_to_label[str(int(pred))]: Converte o índice de classe previsto em um nome de classe. Os exemplos fornecidos nos dois últimos tópicos iriam gerar cls = idx_to_label[0] = 'cat'.

      Em seguida, adicione um utilitário para carregar imagens após a última função:

      step_2_pretrained.py

      . . .
      def load_image():
          assert len(sys.argv) > 1, 'Need to pass path to image'
          image = Image.open(sys.argv[1])
      
          transform = get_image_transform()
          image = transform(image)[None]
          return image
      . . .
      

      Isso irá carregar uma imagem a partir do caminho fornecido no primeiro argumento para o script. transform(image)[None] aplica a sequência de transformações de imagem definida nas linhas anteriores.

      Por fim, preencha sua função main da seguinte forma, para carregar sua imagem e classificar o animal na imagem:

      step_2_pretrained.py

      def main():
          x = load_image()
          print(f'Prediction: {predict(x)}')
      

      Verifique se seu arquivo corresponde ao nosso script do final do passo 2 em step_2_pretrained.py no GitHub. Salve e saia do seu script. Em seguida, execute o classificador de animais:

      • python step_2_pretrained.py assets/dog.jpg

      Isso irá produzir o seguinte resultado, mostrando que seu classificador de animais funciona como esperado:

      Output

      Prediction: Pembroke, Pembroke Welsh corgi

      Isso conclui que há uma inferência em execução com seu modelo pré-treinado. Em seguida, você verá um exemplo contraditório em ação enganando uma rede neural com diferenças imperceptíveis na imagem.

      Passo 3 — Tentando um exemplo contraditório

      Agora, você irá sintetizar um exemplo contraditório e testar a rede neural nesse exemplo. Para este tutorial, você irá compilar exemplos contraditórios da forma x + r, onde x é a imagem original e r é alguma “perturbação”. Eventualmente, você irá criar a perturbação r por conta própria, mas, neste passo, irá baixar uma que já criamos para você. Comece baixando a perturbação r:

      • wget -O assets/adversarial_r.npy https://github.com/do-community/tricking-neural-networks/blob/master/outputs/adversarial_r.npy?raw=true

      Agora, crie uma composição da figura com a perturbação. Crie um novo arquivo chamado step_3_adversarial.py:

      • nano step_3_adversarial.py

      Neste arquivo, você irá realizar o seguinte processo de três etapas, para produzir um exemplo contraditório:

      1. Transformar uma imagem
      2. Aplicar a perturbação r
      3. Fazer a transformação inversa da imagem perturbada

      No final do passo 3, você terá uma imagem contraditória. Primeiro, importe os pacotes necessários e declare uma função main:

      step_3_adversarial.py

      from PIL import Image
      import torchvision.transforms as transforms
      import torch
      import numpy as np
      import os
      import sys
      
      from step_2_pretrained import get_idx_to_label, get_image_transform, predict, load_image
      
      
      def main():
          pass
      
      
      if __name__ == '__main__':
          main()
      

      Em seguida, crie uma “transformação de imagem” que inverte a transformação de imagem anterior. Coloque isto após suas importações, antes da função main:

      step_3_adversarial.py

      . . .
      def get_inverse_transform():
          return transforms.Normalize(
              mean=[-0.485/0.229, -0.456/0.224, -0.406/0.255],  # INVERSE normalize images, according to https://pytorch.org/docs/stable/torchvision/models.html
              std=[1/0.229, 1/0.224, 1/0.255])
      . . .
      

      Assim como antes, a operação transforms.Normalize subtrai a média e divide o valor pelo desvio padrão (ou seja, para a imagem original x, y = transforms.Normalize(mean=u, std=o) = (x - u) / o). Você aplica um pouco de álgebra e define uma nova operação que reverte essa função normalizadora (transforms.Normalize(mean=-u/o, std=1/o) = (y - -u/o) / 1/o = (y + u/o) o = yo + u = x).

      Como parte da transformação inversa, adicione um método que transforma um tensor do PyTorch de volta em uma imagem PIL. Adicione isto após a última função:

      step_3_adversarial.py

      . . .
      def tensor_to_image(tensor):
          x = tensor.data.numpy().transpose(1, 2, 0) * 255.  
          x = np.clip(x, 0, 255)
          return Image.fromarray(x.astype(np.uint8))
      . . .
      
      • O tensor.data.numpy() converte o tensor do PyTorch em uma matriz do NumPy. .transpose(1, 2, 0) reorganiza (channels, width, height) em (height, width, channels). Essa matriz do NumPy está aproximadamente no intervalo (0, 1). Por fim, multiplique isso por 255 para garantir que a imagem esteja agora na faixa (0, 255).
      • O np.clip garante que todos os valores na imagem estejam entre (0, 255).
      • O x.astype(np.uint8) garante que todos os valores de imagem sejam inteiros. Por fim, o Image.fromarray(...) cria um objeto de imagem PIL a partir da matriz do NumPy.

      Em seguida, use esses utilitários para criar o exemplo contraditório da seguinte forma:

      step_3_adversarial.py

      . . .
      def get_adversarial_example(x, r):
          y = x + r
          y = get_inverse_transform()(y[0])
          image = tensor_to_image(y)
          return image
      . . .
      

      Essa função gera o exemplo contraditório como descrito no início da seção:

      1. y = x + r. Pega sua perturbação r e a adiciona à imagem original x.
      2. get_inverse_transform: Obtém e aplica a transformação reversa de imagem que você definiu várias linhas atrás.
      3. tensor_to_image: Por fim, converte o tensor do PyTorch de volta para um objeto de imagem.

      Em último lugar, modifique sua função main para carregar a imagem, carregar a perturbação contraditória r, aplicar a perturbação, salvar o exemplo contraditório no disco e executar uma previsão no exemplo contraditório:

      step_3_adversarial.py

      def main():
          x = load_image()
          r = torch.Tensor(np.load('assets/adversarial_r.npy'))
      
          # save perturbed image
          os.makedirs('outputs', exist_ok=True)
          adversarial = get_adversarial_example(x, r)
          adversarial.save('outputs/adversarial.png')
      
          # check prediction is new class
          print(f'Old prediction: {predict(x)}')
          print(f'New prediction: {predict(x + r)}')
      

      Seu arquivo finalizado deve corresponder ao step_3_adversarial.py no GitHub. Salve o arquivo, saia do editor e inicie seu script com:

      • python step_3_adversarial.py assets/dog.jpg

      Você verá este resultado:

      Output

      Old prediction: Pembroke, Pembroke Welsh corgi New prediction: goldfish, Carassius auratus

      Agora, você criou um exemplo contraditório: enganou a rede neural para pensar que um corgi é um peixe dourado. No próximo passo, você irá efetivamente criar a perturbação r que você usou aqui.

      Passo 4 — Compreendendo um exemplo contraditório

      Para uma cartilha sobre classificação, consulte “How to Build an Emotion-Based Dog Filter”.

      Dando um passo para trás, lembre-se que seu modelo de classificação gera uma probabilidade para cada classe. Durante a inferência, o modelo prevê a classe que tenha a maior probabilidade. Durante o treinamento, você atualiza os parâmetros t do modelo para maximizar a probabilidade da classe correta y, dado os seus dados x.

      argmax_y P(y|x,t)
      

      No entanto, para gerar exemplos contraditórios, agora seu objetivo é outro. Em vez de encontrar uma classe, seu objetivo agora é encontrar uma nova imagem, x. Escolha qualquer classe que não seja a correta. Chamemos essa nova classe de w. Seu novo objetivo é maximizar a probabilidade da classe errada.

      argmax_x P(w|x)
      

      Observe que os pesos t da rede neural foram deixados de fora da expressão acima. Isso ocorre porque agora assumem o papel da contradição: outra pessoa treinou e implantou um modelo. Você só pode criar entradas contraditórias e não é permitido modificar o modelo implantado. Para gerar o exemplo contraditório x, é possível executar um “treinamento”, exceto que, em vez de atualizar os pesos da rede neural, você atualiza a imagem de entrada com o novo objetivo.

      Como um lembrete, para este tutorial, você supõe que o exemplo contraditório é uma transformação afim de x. Em outras palavras, seu exemplo contraditório assume a forma x + r para alguns r. No próximo passo, você irá escrever um script para gerar este r.

      Passo 5 — Criando um exemplo contraditório

      Neste passo, você irá aprender uma perturbação r, para que seu corgi seja classificado erroneamente como um peixe dourado. Crie um novo arquivo chamado step_5_perturb.py:

      Importe os pacotes necessários e declare uma função main:

      step_5_perturb.py

      from torch.autograd import Variable
      import torchvision.models as models
      import torch.nn as nn
      import torch.optim as optim
      import numpy as np
      import torch
      import os
      
      from step_2_pretrained import get_idx_to_label, get_image_transform, predict, load_image
      from step_3_adversarial import get_adversarial_example
      
      
      def main():
          pass
      
      
      if __name__ == '__main__':
          main()
      

      Logo após suas importações e antes da função main, defina duas constantes:

      step_5_perturb.py

      . . .
      TARGET_LABEL = 1
      EPSILON = 10 / 255.
      . . .
      

      A primeira constante, TARGET_LABEL, é a classe que será utilizada para classificar erroneamente o corgi. Neste caso, o índice 1 corresponde a “goldfish”(peixe dourado). A segunda constante do EPSILON é a quantidade máxima de perturbação permitida para cada valor da imagem. Este limite é introduzido para que a imagem seja alterada de maneira imperceptível.

      Após suas duas constantes, adicione uma função auxiliar para definir uma rede neural e o parâmetro de perturbação r:

      step_5_perturb.py

      . . .
      def get_model():
          net = models.resnet18(pretrained=True).eval()
          r = nn.Parameter(data=torch.zeros(1, 3, 224, 224), requires_grad=True)
          return net, r
      . . .
      
      • O model.resnet18(pré-trained=True) carrega uma rede neural pré-treinada chamada ResNet18, como antes. Também como antes, você define o modelo para o modo de avaliação usando .eval.
      • O nn.Parameter(...) define uma nova perturbação r, com o tamanho da imagem de entrada. A imagem de entrada também tem o tamanho (1, 3, 224, 224). O argumento de palavra-chave requires_grad=True garante que você possa atualizar essa perturbação r em linhas posteriores neste arquivo.

      Em seguida, comece a modificar sua função main. Comece carregando o modelo net, carregando as entradas x e definindo a etiqueta label:

      step_5_perturb.py

      . . .
      def main():
          print(f'Target class: {get_idx_to_label()[str(TARGET_LABEL)]}')
          net, r = get_model()
          x = load_image()
          labels = Variable(torch.Tensor([TARGET_LABEL])).long()
        . . .
      

      Em seguida, defina tanto o critério quanto o otimizador em sua função main. O primeiro diz ao PyTorch qual é o objetivo – ou seja, qual perda deve ser minimizada. O último diz ao PyTorch como treinar seu parâmetro r:

      step_5_perturb.py

      . . .
          criterion = nn.CrossEntropyLoss()
          optimizer = optim.SGD([r], lr=0.1, momentum=0.1)
      . . .
      

      Diretamente a seguir, adicione o loop de treinamento principal para seu parâmetro r:

      step_5_perturb.py

      . . .
          for i in range(30):
              r.data.clamp_(-EPSILON, EPSILON)
              optimizer.zero_grad()
      
              outputs = net(x + r)
              loss = criterion(outputs, labels)
              loss.backward()
              optimizer.step()
      
              _, pred = torch.max(outputs, 1)
              if i % 5 == 0:
                  print(f'Loss: {loss.item():.2f} / Class: {get_idx_to_label()[str(int(pred))]}')
      . . .
      

      Em cada iteração deste loop de treinamento, você:

      • r.data.clamp_(...): certifica-se que o parâmetro r é pequeno, dentro do EPSILON de 0.
      • optimizer.zero_grad(): limpa quaisquer gradientes que você computou na iteração anterior.
      • model(x + r): executa uma inferência na imagem modificada x + r.
      • Computa a loss (perda).
      • Computa o gradiente loss.backward.
      • Dá um passo de descendência de gradiente optimizer.step.
      • Computa a previsão pred.
      • Por fim, reporta a perda e a classe prevista print(...).

      Em seguida, salve a perturbação final r:

      step_5_perturb.py

      def main():
          . . .
          for i in range(30):
              . . .
          . . .
          np.save('outputs/adversarial_r.npy', r.data.numpy())
      

      Logo a seguir, ainda na função main, salve a imagem perturbada:

      step_5_perturb.py

      . . .
          os.makedirs('outputs', exist_ok=True)
          adversarial = get_adversarial_example(x, r)
      

      Por fim, execute uma previsão tanto na imagem original quanto no exemplo contraditório:

      step_5_perturb.py

          print(f'Old prediction: {predict(x)}')
          print(f'New prediction: {predict(x + r)}')
      

      Verifique novamente se seu script corresponde ao step_5_perturb.py no GitHub. Salve, saia e execute o script:

      • python step_5_perturb.py assets/dog.jpg

      Seu script irá gerar o seguinte resultado.

      Output

      Target class: goldfish, Carassius auratus Loss: 17.03 / Class: Pembroke, Pembroke Welsh corgi Loss: 8.19 / Class: Pembroke, Pembroke Welsh corgi Loss: 5.56 / Class: Pembroke, Pembroke Welsh corgi Loss: 3.53 / Class: Pembroke, Pembroke Welsh corgi Loss: 1.99 / Class: Pembroke, Pembroke Welsh corgi Loss: 1.00 / Class: goldfish, Carassius auratus Old prediction: Pembroke, Pembroke Welsh corgi New prediction: goldfish, Carassius auratus

      As duas últimas linhas indicam que agora você completou a construção de um exemplo contraditório do zero. Sua rede neural agora classifica uma imagem perfeitamente razoável de um corgi como um peixe dourado.

      Agora, você mostrou que as redes neurais podem ser enganadas com facilidade—mais que isso, a falta de robustez nos exemplos contraditórios tem consequências significativas. Uma pergunta que surge naturalmente é: Como se combate exemplos contraditórios? Muitas pesquisas foram realizadas por várias organizações, incluindo a OpenAI. Na próxima seção, você irá executar uma defesa para impedir este exemplo contraditório.

      Passo 6 — Defendendo-se contra exemplos contraditórios

      Neste passo, você irá implementar uma defesa contra exemplos contraditórios. A ideia é a seguinte: agora você é o proprietário do classificador de animais que está sendo implantado para a produção. Você não sabe quais exemplos contraditórios podem ser gerados, mas pode modificar a imagem ou o modelo para proteger-se contra os ataques.

      Antes de se defender, você deve ver por si mesmo como a manipulação de imagem é imperceptível. Abra as duas imagens a seguir:

      1. assets/dog.jpg
      2. outputs/adversarial.png

      Aqui estão as duas lado a lado. Sua imagem original terá uma taxa de proporção diferente. Consegue dizer qual delas é o exemplo contraditório?

      (esquerda) Corgi como peixe dourado, contraditório, (direita)Corgi como ele mesmo, não contraditório

      Observe que a nova imagem parece ser idêntica à original. Na realidade, a imagem da esquerda é sua imagem contraditória. Para ter certeza disso, faça o download da imagem e execute seu script de avaliação:

      • wget -O assets/adversarial.png https://github.com/alvinwan/fooling-neural-network/blob/master/outputs/adversarial.png?raw=true
      • python step_2_pretrained.py assets/adversarial.png

      Isso irá mostrar como resultado a classe de peixe dourado, para provar sua natureza contraditória:

      Output

      Prediction: goldfish, Carassius auratus

      Você irá por em prática uma defesa bastante ingênua, mas eficaz: comprima a imagem gravando-a em um formato JPEG com perdas. Abra o prompt interativo do Python:

      Em seguida, carregue a imagem contraditória como PNG e a salve de volta como JPEG.

      • from PIL import Image
      • image = Image.open('assets/adversarial.png')
      • image.save('outputs/adversarial.jpg')

      Digite CTRL + D para sair do prompt interativo do Python. Depois disso, realize uma inferência com seu modelo no exemplo contraditório comprimido:

      • python step_2_pretrained.py outputs/adversarial.jpg

      Isso gera uma classe corgi, mostrando a eficácia de sua defesa ingênua.

      Output

      Prediction: Pembroke, Pembroke Welsh corgi

      Agora, você completou sua primeira defesa contraditória. Observe que essa defesa não requer saber como o exemplo contraditório foi gerado. Isso é o que torna uma defesa eficaz. Há ainda muitas outras formas de defesa, muitas das quais envolvem um maior treinamento da rede neural. No entanto, esses procedimentos de treinamento são um tema próprio e estão fora do âmbito deste tutorial. Com isso, isso conclui seu guia sobre o machine learning contraditório.

      Conclusão

      Para compreender as implicações do seu trabalho neste tutorial, revisite as duas imagens lado a lado – o exemplo original e o contraditório.

      (esquerda) Corgi como peixe dourado, contraditório, (direita)Corgi como ele mesmo, não contraditório

      Apesar do fato de ambas as imagens serem idênticas ao olho humano, a primeira foi manipulada para enganar seu modelo. As duas imagens exibem claramente um corgi, mas o modelo está totalmente convencido de que o segundo modelo contém um peixe dourado. Isso deve gerar-lhe preocupação. Enquanto finaliza este tutorial, tenha em mente a fragilidade do seu modelo. Apenas aplicando uma simples transformação, você foi capaz de enganá-lo. Esses são perigos reais e plausíveis que escapam aos olhos, até mesmo de uma pesquisa de ponta. Pesquisas que vão além da segurança em machine learning são igualmente suscetíveis a essas falhas e, como um profissional, cabe a você aplicar o machine learning com segurança. Para mais leituras, confira os seguintes links:

      Para mais conteúdo e tutoriais de machine learning, visite nossa página do tópico de Machine Learning.



      Source link