[PYTHON] Visualisierung von CNN-Feature-Maps und -Filtern (Tensorflow 2.0)

Überblick

Ich habe mir die Feature-Map und Filter im CNN angesehen, die mit dem Subclassing-Modell erstellt wurden.

Umgebung

-Software- Windows 10 Home Anaconda3 64-bit(Python3.7) VSCode -Library- Tensorflow 2.1.0 opencv-python 4.1.2.30 -Hardware- CPU: Intel core i9 9900K GPU: NVIDIA GeForce RTX2080ti RAM: 16GB 3200MHz

Referenz

Seite? ˅Keras: Visualisieren Sie CNN mit Fashion-MNIST

Programm

Ich werde es auf Github posten. https://github.com/himazin331/CNN-Visualization Das Repository enthält ein Demo-Programm (cnn_visual.py), ein Feature-Map-Visualisierungsmodul (feature_visual.py) und Enthält ein Filtervisualisierungsmodul (filter_visual.py).

Quellcode

Die weniger relevanten Teile werden weggelassen. ** Bitte beachten Sie, dass der Code verschmutzt ist ... **

cnn_visual.py


import argparse as arg
import os
import sys

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' #TF-Nachricht ausblenden

import tensorflow as tf
import tensorflow.keras.layers as kl

import numpy as np
import matplotlib.pyplot as plt

import feature_visual
import filter_visual

# CNN
class CNN(tf.keras.Model):
    
    def __init__(self, n_out, input_shape):
        super().__init__()

        self.conv1 = kl.Conv2D(16, 4, activation='relu', input_shape=input_shape)
        self.conv2 = kl.Conv2D(32, 4, activation='relu')
        self.conv3 = kl.Conv2D(64, 4, activation='relu')

        self.mp1 = kl.MaxPool2D((2, 2), padding='same')
        self.mp2 = kl.MaxPool2D((2, 2), padding='same')
        self.mp3 = kl.MaxPool2D((2, 2), padding='same')
   
        self.flt = kl.Flatten()
      
        self.link = kl.Dense(1024, activation='relu')
        self.link_class = kl.Dense(n_out, activation='softmax')

    def call(self, x):   
        
        h1 = self.mp1(self.conv1(x))
        h2 = self.mp2(self.conv2(h1))
        h3 = self.mp3(self.conv3(h2))
        
        h4 = self.link(self.flt(h3))

        return self.link_class(h4)

#Lernen
class trainer(object):

    def __init__(self, n_out, input_shape):

        self.model = CNN(n_out, input_shape)
        self.model.compile(optimizer=tf.keras.optimizers.Adam(),
                           loss=tf.keras.losses.SparseCategoricalCrossentropy(),
                           metrics=['accuracy'])
        

    def train(self, train_img, train_lab, batch_size, epochs, input_shape, test_img):
        #Lernen
        self.model.fit(train_img, train_lab, batch_size=batch_size, epochs=epochs)
        
        print("___Training finished\n\n")
        
        #Feature-Map-Visualisierung
        feature_visual.feature_vi(self.model, input_shape, train_img)
        #Filtervisualisierung
        filter_visual.filter_vi(self.model)

def main():

    """
Befehlszeilenoptionen
    """

    #Datensatzerfassung, Vorverarbeitung
    (train_img, train_lab), (test_img, _) = tf.keras.datasets.mnist.load_data()
    train_img = tf.convert_to_tensor(train_img, np.float32)
    train_img /= 255
    train_img = train_img[:, :, :, np.newaxis]

    test_img = tf.convert_to_tensor(test_img, np.float32)
    test_img /= 255
    test_img = train_img[:, :, :, np.newaxis]

    #Fang an zu lernen
    print("___Start training...")

    input_shape = (28, 28, 1)

    Trainer = trainer(10, input_shape)
    Trainer.train(train_img, train_lab, batch_size=args.batch_size,
                epochs=args.epoch, input_shape=input_shape, test_img=test_img)

if __name__ == '__main__':
    main()

Ausführungsergebnis

Dieses Mal wurde ich gebeten, handgeschriebene MNIST-Nummern einzugeben. Das Ergebnis sind 10 Epochen und 256 Mini-Batch-Größen.

Feature Map

** Faltschicht 1 ** image.png

** Pooling Schicht 1 ** image.png

** Faltschicht 2 ** image.png

** Pooling Schicht 2 ** image.png

Filter

** Faltschicht 1 ** image.png

** Faltschicht 2 ** image.png

** Faltschicht 3 ** Da das Display klein und schwer zu sehen ist, wird es durch Bearbeiten vergrößert und verkleinert. image.png

Erläuterung

Ich werde den zugehörigen Code erklären.

Das Netzwerkmodell ist ein CNN mit der folgenden Struktur.

Netzwerkmodell


# CNN
class CNN(tf.keras.Model):
    
    def __init__(self, n_out, input_shape):
        super().__init__()

        self.conv1 = kl.Conv2D(16, 4, activation='relu', input_shape=input_shape)
        self.conv2 = kl.Conv2D(32, 4, activation='relu')
        self.conv3 = kl.Conv2D(64, 4, activation='relu')

        self.mp1 = kl.MaxPool2D((2, 2), padding='same')
        self.mp2 = kl.MaxPool2D((2, 2), padding='same')
        self.mp3 = kl.MaxPool2D((2, 2), padding='same')
   
        self.flt = kl.Flatten()
      
        self.link = kl.Dense(1024, activation='relu')
        self.link_class = kl.Dense(n_out, activation='softmax')

    def call(self, x):   
        
        h1 = self.mp1(self.conv1(x))
        h2 = self.mp2(self.conv2(h1))
        h3 = self.mp3(self.conv3(h2))
        
        h4 = self.link(self.flt(h3))

        return self.link_class(h4)

Die Visualisierung der Feature-Map erfolgt in feature_visual.py.

feature_visual.py


import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' #TF-Nachricht ausblenden

import tensorflow as tf

import numpy as np
import matplotlib.pyplot as plt

#Feature-Map-Visualisierung
def feature_vi(model, input_shape, test_img):
        
    #Modell umbauen
    x = tf.keras.Input(shape=input_shape)
    model_vi = tf.keras.Model(inputs=x, outputs=model.call(x))
     
    #Netzwerkkonfigurationsausgabe
    model_vi.summary()
    print("")
        
    #Ebeneninformationen abrufen
    feature_vi = []
    feature_vi.append(model_vi.get_layer('input_1'))
    feature_vi.append(model_vi.get_layer('conv2d'))
    feature_vi.append(model_vi.get_layer('max_pooling2d'))
    feature_vi.append(model_vi.get_layer('conv2d_1'))
    feature_vi.append(model_vi.get_layer('max_pooling2d_1'))

    #Zufällige Datenextraktion
    idx = int(np.random.randint(0, len(test_img), 1))
    img = test_img[idx]
    img = img[None, :, :, :]

    for i in range(len(feature_vi)-1):
            
        #Feature-Map-Erfassung
        feature_model = tf.keras.Model(inputs=feature_vi[0].input, outputs=feature_vi[i+1].output)
        feature_map = feature_model.predict(img)
        feature_map = feature_map[0]
        feature = feature_map.shape[2]
            
        #Definition des Fensternamens
        fig = plt.gcf()
        fig.canvas.set_window_title(feature_vi[i+1].name + " feature-map visualization")
            
        #Ausgabe
        for j in range(feature):
            plt.subplots_adjust(wspace=0.4, hspace=0.8)
            plt.subplot(feature/6 + 1, 6, j+1)
            plt.xticks([])
            plt.yticks([])
            plt.xlabel(f'filter {j}')
            plt.imshow(feature_map[:,:,j])
        plt.show()

Sie können das CNN-Klassenmodell nicht so verwenden, wie es ist. Dies liegt daran, dass die Eingabeebene nicht definiert ist. Fügen Sie bei der Implementierung im SubClassing-Modell ** dem Modell eine Eingabeebene hinzu **, wie unten gezeigt.

    #Modell umbauen
    x = tf.keras.Input(shape=input_shape)
    model_vi = tf.keras.Model(inputs=x, outputs=model.call(x))

Bereiten Sie als Nächstes eine Liste vor und ** fügen Sie die Eingabeebene und beliebige Ebeneninformationen zur Liste hinzu **. Dieses Mal möchte ich die Ausgabe der ersten Faltschicht, der ersten maximalen Pooling-Schicht, der zweiten Faltschicht und der zweiten maximalen Pooling-Schicht sehen. Beschreiben Sie wie folgt.

    #Ebeneninformationen abrufen
    feature_vi = []
    feature_vi.append(model_vi.get_layer('input_1'))
    feature_vi.append(model_vi.get_layer('conv2d'))
    feature_vi.append(model_vi.get_layer('max_pooling2d'))
    feature_vi.append(model_vi.get_layer('conv2d_1'))
    feature_vi.append(model_vi.get_layer('max_pooling2d_1'))

Bereiten Sie als Nächstes die Eingabedaten vor. Die dem Index entsprechenden Testdaten werden unter Verwendung eines zufälligen numerischen Werts basierend auf einer Zufallszahl als Index erfasst. Da die Form der erfassten Testdaten (28, 28, 1) ist, fügen wir die Dimension der Anzahl der Datenelemente hinzu.

    #Zufällige Datenextraktion
    idx = int(np.random.randint(0, len(test_img), 1))
    img = test_img[idx]
    img = img[None, :, :, :]

Erstellen Sie ein Modell feature_model mit der Eingabe als Eingabeebene und der Ausgabe als Ausgabe jeder Ebene. Übergeben Sie dann die Eingabedaten mit "Vorhersagen" und erhalten Sie die Ebenenausgabe.

        #Feature-Map-Erfassung
        feature_model = tf.keras.Model(inputs=feature_vi[0].input, outputs=feature_vi[i+1].output)
        feature_map = feature_model.predict(img)
        feature_map = feature_map[0]
        feature = feature_map.shape[2]

Zeichnen Sie danach die Ebenenausgabe und wiederholen Sie sie wie die nächste Ebenenausgabe.


Die Filtervisualisierung erfolgt in fileter_visual.py.

filter_visual.py


import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' #TF-Nachricht ausblenden

import tensorflow as tf

import numpy as np
import matplotlib.pyplot as plt

#Filtervisualisierung
def filter_vi(model):
        
    vi_layer = []
        
    #Zu visualisierende Ebene
    vi_layer.append(model.get_layer('conv2d'))
    vi_layer.append(model.get_layer('conv2d_1'))
    vi_layer.append(model.get_layer('conv2d_2'))
        
    for i in range(len(vi_layer)):      
            
        #Ebenenfilter abrufen
        target_layer = vi_layer[i].get_weights()[0]
        filter_num = target_layer.shape[3]
            
        #Definition des Fensternamens
        fig = plt.gcf()
        fig.canvas.set_window_title(vi_layer[i].name + " filter visualization")
            
        #Ausgabe
        for j in range(filter_num):
            plt.subplots_adjust(wspace=0.4, hspace=0.8)
            plt.subplot(filter_num/6 + 1, 6, j+1)
            plt.xticks([])
            plt.yticks([])
            plt.xlabel(f'filter {j}')  
            plt.imshow(target_layer[ :, :, 0, j], cmap="gray") 
        plt.show()

Fügen Sie wie bei der Feature-Map-Visualisierung der Liste Faltungsebenen hinzu, die dem gewünschten Filter entsprechen.

    vi_layer = []
        
    #Zu visualisierende Ebene
    vi_layer.append(model.get_layer('conv2d'))
    vi_layer.append(model.get_layer('conv2d_1'))
    vi_layer.append(model.get_layer('conv2d_2'))

Holen Sie sich den ** Filter der Zielebene mit get_weights () [0] **. Übrigens können Sie die Verzerrung erhalten, indem Sie "get_weights () [1]" schreiben.

Die Form des erhaltenen Filters ist (H, W, I_C, O_C). I_C ist die Anzahl der Eingangskanäle und O_C ist die Anzahl der Ausgangskanäle.

        #Ebenenfilter abrufen
        target_layer = vi_layer[i].get_weights()[0]
        filter_num = target_layer.shape[3]

Geben Sie danach den Filter aus und wiederholen Sie den Vorgang wie beim nächsten Filter.

abschließend

Ich wollte die Feature-Map und die Filter sehen, habe sie also nachgeschlagen und mit verschiedenen Änderungen implementiert. Die Feature-Map ist interessant anzusehen, aber ich weiß nicht, was der Filter ist, also ist es nicht interessant ~~. In den letzten Jahren scheint es, dass erklärbare KI (KI) Aufmerksamkeit erregt hat, aber ich freue mich auf die Zeit, in der Menschen verstehen können, warum solche Filter sie erkennen können.

Recommended Posts

Visualisierung von CNN-Feature-Maps und -Filtern (Tensorflow 2.0)
Aggregation und Visualisierung akkumulierter Zahlen
pix2pix tensorflow2 Aufzeichnung von Versuch und Irrtum
Korrelationsvisualisierung der Merkmalsmenge und der Zielvariablen
Rezeptsammlung zum Vergleich der Versionen 1 und 2 von TensorFlow (Teil 1)
Aufzeichnung der TensorFlow Mnist Expert Edition (Visualisierung von TensorBoard)
Analyse von Finanzdaten durch Pandas und deren Visualisierung (2)
Analyse von Finanzdaten durch Pandas und deren Visualisierung (1)
Höchstwahrscheinlich Schätzung des Mittelwerts und der Varianz mit TensorFlow
Übersicht und Tipps von Seaborn mit statistischer Datenvisualisierung
[Regelungstechnik] Visualisierung und Analyse der PID-Regelung und der Sprungantwort
Visualisierung der Verbindung zwischen Malware und dem Callback-Server
DNN (Deep Learning) Library: Vergleich von Chainer und TensorFlow (1)
Visualisierung von Daten anhand einer erklärenden Variablen und einer objektiven Variablen