[PYTHON] Avec une légère baisse de précision, les paramètres de poids ont été incroyablement réduits ~ Résultats surprenants de CNN ~

1.Tout d'abord

En ce qui concerne l'identification d'image des réseaux de neurones, nous nous concentrons généralement sur la précision pouvant être améliorée, mais comme je suis un diable, je me concentrerai sur ** combien le paramètre de poids peut être réduit si la précision est légèrement réduite **. ..

Je pense que la plupart des ressources sont souvent utilisées pour les réseaux de neurones pour augmenter la précision finale de 1 à 2%, donc même si vous sacrifiez environ 1 à 2% de précision, vous devriez être en mesure de réduire considérablement le paramètre de poids.

Le modèle utilisé dans cette expérience utilise ** MLP (perceptron multicouche) ** et ** CNN (réseau de convolution) ** qui identifient MNIST (nombres manuscrits de 0 à 9) décrits dans le tutoriel keras. Comme la précision de ces deux modèles est d'environ 98 à 99%, définissons la ** précision de la cible sur la plage de 97% ** et essayons de réduire le paramètre de poids.

2.MLP (Perceptron multicouche)

Voici la structure de base de MLP dans le didacticiel keras (en fait, j'y ai ajouté deux Dropouts, mais je les ai omis pour plus de simplicité). スクリーンショット 2020-01-22 11.08.38.png Puisque MNIST est de 28 * 28 pixels, il y a 28 * 28 = 784 entrées. Il y a deux couches cachées, toutes deux entièrement connectées avec n = 512.

Vérifions d'abord ce qu'il advient de la précision si ce n est progressivement réduit. Exécutez le code suivant (le temps d'exécution est d'environ 3 minutes et demie sur le GPU de google colab).

from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import RMSprop

batch_size = 128
num_classes = 10
epochs = 20

# load data
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

# multi Perceptoron_1
def mlp(n):
    model = Sequential()
    model.add(Dense(n, activation='relu', input_shape=(784,)))
    model.add(Dense(n, activation='relu'))
    model.add(Dense(num_classes, activation='softmax'))

    #model.summary()

    model.compile(loss='categorical_crossentropy',
                   optimizer=RMSprop(),
                  metrics=['accuracy'])

    model.fit(x_train, y_train,
              batch_size=batch_size,
              epochs=epochs,
              verbose=0, 
              validation_data=(x_test, y_test))
    
    score = model.evaluate(x_test, y_test, verbose=0)
    return score[1]

# test
list_n = [512, 256, 128, 64, 32, 16]  
x, y = [], []
for n in list_n:
    params = n*n + 796*n + 10
    acc = mlp(n)
    x.append(params)
    y.append(acc)
    print ('n = ', n, ', ', 'params = ', params, ', ', 'accuracy = ', acc)

# graph
import matplotlib.pyplot as plt
plt.scatter(x, y)
plt.xscale('log')
plt.show()

スクリーンショット 2020-01-22 11.05.33.png L'axe horizontal du graphique correspond au nombre de paramètres de poids (log) et l'axe vertical correspond à la précision. Est-ce que n = 32, params = 26506, précision = 0,9711 est le point de retournement lorsque vous essayez d'assurer une précision de 97%?

Ensuite, en sacrifiant une certaine précision, nous pouvons réduire le paramètre de poids à environ 1/25 du modèle de base car 669706/26506 = 25,26.

En regardant le contour du modèle avec model.summary () (il est affiché en prenant le premier # et en l'exécutant), cela ressemble à ceci スクリーンショット 2020-01-22 11.39.14.png Est-il impossible de réduire davantage le paramètre de poids? Non, j'ai encore un autre mouvement.

Où le paramètre de poids consomme-t-il le plus? À 784 entrées et ** dense_1 **, (784 + 1) * 32 = 25120 et 95% des paramètres de poids totaux sont consommés ici. Au fait, il devient 784 + 1 car il y a un biais.

Nous avons émis l'hypothèse que même si la résolution des nombres est médiocre, nous pouvons les identifier dans une certaine mesure et utiliser un filtre (Max Pooling) pour créer un modèle qui utilise un filtre (Max Pooling) pour réduire 28 * 28 = 784 entrées à 1/4 de 14 * 14 = 196. pense. スクリーンショット 2020-01-22 11.51.56.png Exécutez le code de ce modèle (le temps d'exécution est d'environ 3 minutes et demie sur le GPU de google colab).

from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import RMSprop
from keras.layers import MaxPooling2D, Flatten  #ajouter à

batch_size = 128
num_classes = 10
epochs = 20

# load data
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, 28, 28, 1)  #Changement
x_test = x_test.reshape(10000, 28, 28, 1)  #Changement
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

# multi Perceptoron_2
def mlp(n):
    model = Sequential()
    model.add(MaxPooling2D(pool_size=(2, 2),input_shape=(28, 28, 1)))  #14 images*Réduit à 14
    model.add(Flatten())  #Faites un lien complet
    model.add(Dense(n, activation='relu')) 
    model.add(Dense(n, activation='relu'))
    model.add(Dense(num_classes, activation='softmax'))

    #model.summary()

    model.compile(loss='categorical_crossentropy',
                   optimizer=RMSprop(),
                  metrics=['accuracy'])

    model.fit(x_train, y_train,
              batch_size=batch_size,
              epochs=epochs,
              verbose=0, 
              validation_data=(x_test, y_test))
    
    score = model.evaluate(x_test, y_test, verbose=0)
    return score[1]

# test
list_n = [512, 256, 128, 64, 32, 16]  
x, y = [], []
for n in list_n:
    params = n*n + 208*n + 10  #Changement de modèle
    acc = mlp(n)
    x.append(params)
    y.append(acc)
    print ('n = ', n, ', ', 'params = ', params, ', ', 'accuracy = ', acc)

# graph
import matplotlib.pyplot as plt
plt.scatter(x, y)
plt.xscale('log')
plt.show()

スクリーンショット 2020-01-22 12.25.27.png Dans l'ensemble, j'ai glissé vers un peu moins précis, mais n = 64, params = 17418, précision = 0,9704 a été le tournant.

Ensuite, en sacrifiant une certaine précision, il a été constaté que le paramètre de poids peut être réduit à environ 1/38 du modèle de base par 669706/17418 = 38,44. Il peut être considérablement réduit.

3. Résultats étonnants de CNN

Voici la structure de base du CNN dans le didacticiel Keras (en fait, j'y ai ajouté deux Dropouts, mais je les ai omis pour plus de simplicité). スクリーンショット 2020-01-22 12.33.27.png Les deux couches convolutives utilisent un filtre 3 * 3 = 9. Après cela, il est réduit à 1/2 verticalement et horizontalement par Max Pooling et connecté à la couche entièrement connectée de n * 4.

Regardons maintenant le nombre et la précision des paramètres de pondération lorsque n est modifié. Exécutez le code suivant (le temps d'exécution est d'environ 3 minutes et demie sur le GPU de google colab).

from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K

batch_size = 128
num_classes = 10
epochs = 12
img_rows, img_cols = 28, 28

# load data
(x_train, y_train), (x_test, y_test) = mnist.load_data()

if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

# CNN_1
def cnn(n):
    model = Sequential()
    model.add(Conv2D(n, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))
    model.add(Conv2D(n*2, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Flatten())
    model.add(Dense(n*4, activation='relu'))
    model.add(Dense(num_classes, activation='softmax'))

    #model.summary()

    model.compile(loss=keras.losses.categorical_crossentropy,
                   optimizer=keras.optimizers.Adadelta(),
                   metrics=['accuracy'])

    model.fit(x_train, y_train,
             batch_size=batch_size,
             epochs=epochs,
             verbose=0,
             validation_data=(x_test, y_test))
    score = model.evaluate(x_test, y_test, verbose=0)
    return score[1]

# test
list_n = [32, 16, 8, 4, 2, 1] 
x, y = [], []
for n in list_n:
    params = 1170*n*n + 56*n + 10
    acc = cnn(n)
    x.append(params)
    y.append(acc)
    print ('n = ', n, ', ', 'params = ', params, ', ', 'accuracy = ', acc)

# graph
import matplotlib.pyplot as plt
plt.scatter(x, y)
plt.xscale('log')
plt.show()

スクリーンショット 2020-01-22 12.52.52.png Ceci est incroyable! La fourche est n = 2, params = 4802, précision = 0,9748.

Ensuite, en sacrifiant une certaine précision, nous avons pu réduire le nombre de paramètres de poids à environ 1/250 du modèle de base car 1199882/4802 = 249,8.

Au fait, comme précédemment, si vous regardez le contour du modèle avec model.summary (), スクリーンショット 2020-01-22 13.21.50.png Contrairement à MLP, les parties d'entrée et de convolution ont un petit nombre de paramètres. Quant aux paramètres de la couche de convolution, 3 * 3 = 9 filtres sont couramment utilisés, donc les paramètres de poids sont réduits.

Au lieu de cela, (12 * 12 * 4 + 1) * 8 = 4616, qui entre dans la liaison complète à partir de la couche de convolution finale, représente 96% du paramètre de poids total. Tu ne peux pas faire quelque chose ici?

La couche convolutive ne consomme presque aucun paramètre de poids, le modèle suivant est donc une bonne idée pour ajouter à nouveau deux couches convolutives après Max Pooling, puis multiplier par Max Pooling.

スクリーンショット 2020-01-22 13.14.00.png Maintenant, exécutons le code de ce modèle (le temps d'exécution est d'environ 3 minutes et demie sur le GPU de google colab).

from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K

batch_size = 128
num_classes = 10
epochs = 12
img_rows, img_cols = 28, 28

# load data
(x_train, y_train), (x_test, y_test) = mnist.load_data()

if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

# CNN_2
def cnn(n):
    model = Sequential()
    model.add(Conv2D(n, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))
    model.add(Conv2D(n, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Conv2D(n*2, (3, 3), activation='relu'))
    model.add(Conv2D(n*2, (3, 3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Flatten())
    model.add(Dense(num_classes, activation='softmax'))

    #model.summary()

    model.compile(loss=keras.losses.categorical_crossentropy,
                   optimizer=keras.optimizers.Adadelta(),
                   metrics=['accuracy'])

    model.fit(x_train, y_train,
             batch_size=batch_size,
             epochs=epochs,
             verbose=0,
             validation_data=(x_test, y_test))
    score = model.evaluate(x_test, y_test, verbose=0)
    return score[1]

# test
list_n = [32, 16, 8, 4, 2, 1] 
x, y = [], []
for n in list_n:
    params = 63*n*n + 335*n + 10
    acc = cnn(n)
    x.append(params)
    y.append(acc)
    print ('n = ', n, ', ', 'params = ', params, ', ', 'accuracy = ', acc)

# graph
import matplotlib.pyplot as plt
plt.scatter(x, y)
plt.xscale('log')
plt.show()

スクリーンショット 2020-01-22 13.17.01.png Étonnamment, avec seulement 932 paramètres de poids, nous avons pu garantir une précision de 97%. Ce nombre de paramètres de poids est inférieur à 1/1000 du modèle de base **! ** **

Et, par rapport à 17418 de MLP, il a été trouvé que 17418/932 = 18,68 **, la même précision peut être obtenue avec le paramètre de poids d'environ 1/18 de MLP **.

** En reconnaissance d'image, c'est un résultat que vous pouvez très bien voir que la couche convolutive de CNN fonctionne extrêmement efficacement **. CNN, c'est effrayant!

Recommended Posts

Avec une légère baisse de précision, les paramètres de poids ont été incroyablement réduits ~ Résultats surprenants de CNN ~
Comprendre le nombre de paramètres d'entrée / sortie du réseau neuronal convolutif
Implémentation d'un réseau de neurones à deux couches 2
Visualisez la couche interne du réseau neuronal
Avec une légère baisse de précision, les paramètres de poids ont été incroyablement réduits ~ Résultats surprenants de CNN ~
Recevez une liste des résultats du traitement parallèle en Python avec starmap
Prenez des captures d'écran LCD avec Python-LEGO Mindstorms
Visualisez le vocabulaire caractéristique d'un document avec D3.js
Calculer le produit des matrices avec une expression de caractère?