[Deep Learning] Gesichtserkennungsprojekt basierend auf Convolutional Neural Network (Tensorflow) (3)

Veranstaltungsadresse: CSDN 21-tägige Lernherausforderung

Vorwort

Nach Recherchen vor einiger Zeit, von der Einführung von LeNet-5 handschriftlichen Ziffern bis hin zu einer aktuellen Studie zur Wettererkennung. Ich möchte eine große Abstimmung machen, da ich mich mit der C++/Qt-Entwicklung befasse und mit Qt vertraut bin, daher möchte ich eine Gesichtserkennung basierend auf der Qt-Schnittstelle implementieren.

Wenn Sie mit dem Konzept der Convolutional Neural Networks nicht vertraut sind, können Sie sich diesen Artikel ansehen: Was macht Convolution eigentlich?
Wenn Sie den Trainingsprozess von Neuronalen Netzwerken verstehen oder wie man eine Umgebung aufbaut, können Sie dies lesen Artikel: Umgebungskonstruktion und Trainingsprozess

Wenn Sie dieses Projekt lernen möchten, lesen Sie bitte den ersten Artikel : Face Recognition Project Based on Convolutional Neural Network (Tensorflow) (1) Den
zweiten Artikel : Face Recognition Project Based on Convolutional Neural Network (Tensorflow) (2)

Die Grundidee

Konkrete Schritte sind wie folgt:

  1. Zuerst müssen Daten gesammelt werden, meine Idee ist, die Kamera über OpenCV anzurufen, um Gesichtsfotos zu sammeln.
  2. Führen Sie dann eine Vorverarbeitung durch, hauptsächlich um den Datensatz, den Trainingssatz, den Validierungssatz und den Testsatz zu klassifizieren.
  3. Um mit dem Training des Modells zu beginnen, erstellen Sie im Voraus Label-Schlüssel/Wert-Paare.
  4. Testen Sie den Gesichtserkennungseffekt, erfassen Sie das Gesichtsfoto über OpenCV, verarbeiten Sie das Bild dann vor und geben Sie es schließlich an das Modell weiter. Drucken Sie dann das Erkennungsergebnis in Form von Text auf dem Bildschirm aus und radeln Sie, bis Sie q zum Beenden eingeben.

Dieser Artikel implementiert hauptsächlich den dritten Schritt in den obigen Schritten.

Aktivierungsfunktion

Da die E/A jeder Schicht des neuronalen Netzwerks der gesamte Prozess der linearen Summierung ist, können wir erfolgreich die Ausgabe der nächsten Schicht erhalten, solange wir eine Reihe von linearen Transformationen auf der vorherigen Schicht durchführen. Wenn es keine Aktivierungsfunktion gibt, egal wie komplex das neuronale Netzwerk ist, das Sie bauen, egal wie viele Schichten, die endgültige Ausgabe ist alles eine lineare Kombination von Schlüsseln, sodass eine einfache lineare Kombination kompliziertere Probleme nicht bewältigen kann. Nachdem die Aktivierungsfunktion eingeführt wurde, werden Sie feststellen, dass die allgemeine Aktivierungsfunktion vollständig nichtlinear ist.Daher kann das neuronale Netzwerk gemäß der Einführung der Nichtlinearität in die Nervenzellen nahe an den nichtlinearen Elementen sein und das neuronale Netzwerk kann angewendet werden zu einer großen Anzahl nichtlinearer Modelle.

Sigmoidfunktion

Die Sigmoidfunktion ist glatt und leicht abzuleiten, ihr Wertebereich ist [0, 1]. Lösen Sie Probleme zur Berechnung trigonometrischer Funktionen in einem kreisförmigen System und lösen Sie Multiplikations- und Divisionsprobleme in einem linearen System. Die Formel lautet wie folgt:
Bildbeschreibung hier einfügen
Wie in Abb. Es kann auf kreisförmige Systeme, lineare Systeme und hyperbolische Systeme usw. angewendet werden, um verschiedene komplexe Rechenprobleme in verschiedenen Systemen zu lösen.
Bildbeschreibung hier einfügen

Tanh/hyperbolische Tangens-Aktivierungsfunktion

Es handelt sich um eine Art hyperbolische Aktivierungsfunktion, die in der mathematischen Sprache allgemein als tanh geschrieben wird.Obwohl sie die 0-zentrierte Ausgabe der Sigmoid-Funktion erzeugen kann, besteht immer noch das Problem des Verschwindens des Gradienten. Da im Wesentlichen viele Schichten immer wieder durchlaufen werden, können die Daten, wenn sie zu klein sind und viele Schichten vorhanden sind, schließlich zu Null werden. Nachdem wir also die Ableitung der Funktion kontrolliert hatten, war dieses Problem bis zu einem gewissen Grad gelöst.

Bildbeschreibung hier einfügen

ReLU-Aktivierungsfunktion

Ihr vollständiger Name ist lineare Gleichrichtungsfunktion, die in künstlichen neuronalen Netzen sehr verbreitet ist.Es ist eine nichtlineare Funktion, normalerweise eine Rampenfunktion und eine Reihe von davon abgeleiteten Varianten.
Bildbeschreibung hier einfügen

Sie hat viele Vorteile, wie z. B.: Solange Ihr Eingabewert eine positive Zahl ist, tritt sie nicht in den Sättigungsbereich ein und ist im Vergleich zu anderen Aktivierungsfunktionen viel schneller zu berechnen. Aber es hat ein Problem, das nicht erfolgreich gelöst wurde, das heißt, wenn es einen negativen Wert eingibt, schlägt die Funktion vollständig fehl und der Gradient ist zu diesem Zeitpunkt Null. Natürlich haben die oben erwähnten Sigmoid- und Tanh-Funktionen das gleiche Problem. Und es ist keine 0-zentrierte Funktion, was bedeutet, dass sie sehr schwierig abzuleiten ist und eine große Anzahl von Funktionen benötigt, um sie zu unterstützen. Formel:Bildbeschreibung hier einfügen

verlustfunktion

Die Verlustfunktion ist eine Operationsfunktion, die verwendet wird, um die Differenz zwischen dem vorhergesagten Wert f(x) des Modells und dem realen Wert Y zu messen. Es handelt sich um eine nicht negative reellwertige Funktion, die normalerweise L(Y, f(x)) verwendet. ) bis Gibt an, dass die Robustheit des Modells umso besser ist, je kleiner die Verlustfunktion ist.

Wirkung

Die Verlustfunktion wird hauptsächlich in der Trainingsphase des Modells verwendet. Nachdem jeder Batch von Trainingsdaten an das Modell gesendet wurde, wird der vorhergesagte Wert durch Vorwärtsausbreitung ausgegeben, und dann berechnet die Verlustfunktion die Differenz zwischen dem vorhergesagten Wert und dem tatsächlichen Wert Wert, das heißt, der Verlust. Nach Erhalt des Verlustwerts aktualisiert das Modell jeden Parameter durch Backpropagation, um den Verlust zwischen dem tatsächlichen Wert und dem vorhergesagten Wert zu reduzieren, sodass sich der vom Modell erzeugte vorhergesagte Wert näher an den tatsächlichen Wert bewegt, um den Zweck des Lernens zu erreichen .

Erstellen Sie ein neuronales Netzwerkmodell

Parameterbeschreibung

Es wird jedes Mal eine Reihe von Parametern geben, hier werde ich eine Einführung in die Parameter geben.

batch_size : Geben Sie die Anzahl der in jeder Iteration erfassten Trainingsmuster an
nb_epoch : Die Anzahl der Trainingsrotationen
border_mode : Der Parameter der Faltungsschicht wird als gleich ausgewählt, dann bleiben die Eingabe- und Ausgabegrößen der Faltungsoperation gleich. Wenn gültig ausgewählt ist, wird die Größe nach der Faltung kleiner.
verbose : log display 0 bedeutet keine Ausgabe von Protokollinformationen auf dem Standardausgabestrom 1 bedeutet Ausgabe von Fortschrittsbalkenaufzeichnungen 2 Ausgabe einer Zeilenaufzeichnung für jede Epoche

CNN-Modell

Es gibt insgesamt 18 Schichten, darunter 4 Faltungsschichten, 6 Aktivierungsschichten, 2 Pooling-Schichten, 3 Dropout-Schichten, 2 Dense-Schichten und eine Flatten-Schicht.

    def build_model(self, dataset, nb_classes=9):
        # 构建一个空的网络模型,它是一个线性堆叠模型,各神经网络层会被顺序添加,专业名称为序贯模型或线性堆叠模型
        self.model = Sequential()

        # 以下代码将顺序添加CNN网络需要的各层,一个add就是一个网络层
        self.model.add(Convolution2D(32, 3, 3, border_mode='same',
                                     input_shape=dataset.input_shape))  # 1 2维卷积层
        self.model.add(Activation('relu'))  # 2 激活函数层

        self.model.add(Convolution2D(32, 3, 3))  # 3 2维卷积层
        self.model.add(Activation('relu'))  # 4 激活函数层

        self.model.add(MaxPooling2D(pool_size=(2, 2)))  # 5 池化层
        self.model.add(Dropout(0.25))  # 6 Dropout层

        self.model.add(Convolution2D(64, 3, 3, border_mode='same'))  # 7  2维卷积层
        self.model.add(Activation('relu'))  # 8  激活函数层

        self.model.add(Convolution2D(64, 3, 3))  # 9  2维卷积层
        self.model.add(Activation('relu'))  # 10 激活函数层

        self.model.add(MaxPooling2D(pool_size=(2, 2)))  # 11 池化层
        self.model.add(Dropout(0.25))  # 12 Dropout层

        self.model.add(Flatten())  # 13 Flatten层
        self.model.add(Dense(512))  # 14 Dense层,又被称作全连接层
        self.model.add(Activation('relu'))  # 15 激活函数层
        self.model.add(Dropout(0.5))  # 16 Dropout层
        self.model.add(Dense(nb_classes))  # 17 Dense层
        self.model.add(Activation('softmax'))  # 18 分类层,输出最终结果

        # 输出网络结构
        self.model.summary()

Netzwerkstruktur

Das Folgende ist die Struktur des neuronalen Netzwerks, und die Gesamtzahl von Parametern beträgt 6M.

Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 64, 64, 32)        896       
_________________________________________________________________
activation_1 (Activation)    (None, 64, 64, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 62, 62, 32)        9248      
_________________________________________________________________
activation_2 (Activation)    (None, 62, 62, 32)        0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 31, 31, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 31, 31, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 31, 31, 64)        18496     
_________________________________________________________________
activation_3 (Activation)    (None, 31, 31, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 29, 29, 64)        36928     
_________________________________________________________________
activation_4 (Activation)    (None, 29, 29, 64)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 14, 14, 64)        0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 14, 14, 64)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 12544)             0         
_________________________________________________________________
dense_1 (Dense)              (None, 512)               6423040   
_________________________________________________________________
activation_5 (Activation)    (None, 512)               0         
_________________________________________________________________
dropout_3 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                5130      
_________________________________________________________________
activation_6 (Activation)    (None, 10)                0         
=================================================================
Total params: 6,493,738
Trainable params: 6,493,738
Non-trainable params: 0

Trainieren Sie das Modell

Wenn Sie es nicht verstehen, sehen Sie sich die Kommentare im Code an.

    def train(self, dataset, batch_size=20, nb_epoch=10, data_augmentation=True):
        # 参数batch_size的作用即在于此,其指定每次迭代训练样本的数量
        # nb_epoch 训练轮换次数
        sgd = SGD(lr=0.01, decay=1e-6,
                  momentum=0.9, nesterov=True)  # 采用SGD+momentum的优化器进行训练,首先生成一个优化器对象
        self.model.compile(loss='categorical_crossentropy',
                           optimizer=sgd,
                           metrics=['accuracy'])  # 完成实际的模型配置工作

        # 不使用数据提升,所谓的提升就是从我们提供的训练数据中利用旋转、翻转、加噪声等方法创造新的
        # 训练数据,有意识的提升训练数据规模,增加模型训练量
        if not data_augmentation:
            self.model.fit(dataset.train_images,
                           dataset.train_labels,
                           batch_size=batch_size,
                           nb_epoch=nb_epoch,
                           validation_data=(dataset.valid_images, dataset.valid_labels),
                           shuffle=True,
                           verbose = 1)
        # 使用实时数据提升
        else:
            # 定义数据生成器用于数据提升,其返回一个生成器对象datagen,datagen每被调用一
            # 次其生成一组数据(顺序生成),节省内存,其实就是python的数据生成器
            datagen = ImageDataGenerator(
                featurewise_center=False,  # 是否使输入数据去中心化(均值为0),
                samplewise_center=False,  # 是否使输入数据的每个样本均值为0
                featurewise_std_normalization=False,  # 是否数据标准化(输入数据除以数据集的标准差)
                samplewise_std_normalization=False,  # 是否将每个样本数据除以自身的标准差
                zca_whitening=False,  # 是否对输入数据施以ZCA白化
                rotation_range=20,  # 数据提升时图片随机转动的角度(范围为0~180)
                width_shift_range=0.2,  # 数据提升时图片水平偏移的幅度(单位为图片宽度的占比,0~1之间的浮点数)
                height_shift_range=0.2,  # 同上,只不过这里是垂直
                horizontal_flip=True,  # 是否进行随机水平翻转
                vertical_flip=False)  # 是否进行随机垂直翻转

            # 计算整个训练样本集的数量以用于特征值归一化、ZCA白化等处理
            datagen.fit(dataset.train_images)

            # 利用生成器开始训练模型
            self.model.fit_generator(datagen.flow(dataset.train_images, dataset.train_labels,
                                                  batch_size=batch_size),
                                     samples_per_epoch=dataset.train_images.shape[0],
                                     nb_epoch=nb_epoch,
                                     validation_data=(dataset.valid_images, dataset.valid_labels),
                                     verbose = 1)

Trainingsergebnisse

Der endgültige Wiedererkennungseffekt erreichte ebenfalls 99,28 %.

Epoch 1/10
 - 45s - loss: 1.5003 - accuracy: 0.4488 - val_loss: 0.2484 - val_accuracy: 0.9661
Epoch 2/10
 - 45s - loss: 0.5669 - accuracy: 0.8032 - val_loss: 0.1429 - val_accuracy: 0.9331
Epoch 3/10
 - 46s - loss: 0.3572 - accuracy: 0.8778 - val_loss: 0.3107 - val_accuracy: 0.8703
Epoch 4/10
 - 45s - loss: 0.2577 - accuracy: 0.9139 - val_loss: 0.0277 - val_accuracy: 0.9940
Epoch 5/10
 - 46s - loss: 0.2046 - accuracy: 0.9350 - val_loss: 0.0275 - val_accuracy: 0.9940
Epoch 6/10
 - 45s - loss: 0.1824 - accuracy: 0.9400 - val_loss: 0.0242 - val_accuracy: 0.9930
Epoch 7/10
 - 46s - loss: 0.1512 - accuracy: 0.9473 - val_loss: 0.1970 - val_accuracy: 0.9341
Epoch 8/10
 - 46s - loss: 0.1426 - accuracy: 0.9541 - val_loss: 0.0149 - val_accuracy: 0.9960
Epoch 9/10
 - 46s - loss: 0.1474 - accuracy: 0.9541 - val_loss: 0.0391 - val_accuracy: 0.9930
Epoch 10/10
 - 45s - loss: 0.1103 - accuracy: 0.9666 - val_loss: 0.0133 - val_accuracy: 0.9928

Bewertungsmodell

Wird verwendet, um zu bestätigen, ob die Genauigkeit des Modells die Anforderungen erfüllen kann.

Modell laden

    def load_model(self, file_path=MODEL_PATH):
        self.model = load_model(file_path)

Einstufungstest

    def evaluate(self, dataset):
        score = self.model.evaluate(dataset.test_images, dataset.test_labels, verbose=1)
        print("%s: %.2f%%" % (self.model.metrics_names[1], score[1] * 100))

Testergebnisse

Der richtige Satz ist 99,16 %.
Bildbeschreibung hier einfügen

Zusammenfassen

Die Hauptschwierigkeit dieses Kapitels liegt im Design des Modells, das immer wieder feinjustiert werden muss. Dann müssen Sie einige konzeptionelle Dinge wie Verlustfunktion, Aktivierungsfunktion und so weiter verstehen.

Je suppose que tu aimes

Origine blog.csdn.net/qq_45254369/article/details/126412574
conseillé
Classement