[深層学習] 畳み込みニューラル ネットワーク (tensorflow) に基づく顔認識プロジェクト (3)

イベントアドレス: CSDN 21 日間ラーニング チャレンジ

序文

LeNet-5 手書き数字の導入から、最近の天気認識の研究まで、しばらく前に調査を行いました。私はC++/Qtの開発に従事しており、Qtに精通しているため、Qtインターフェイスに基づいた顔認識を実装したいので、大きな投票をしたいと思います。

畳み込みニューラル ネットワークの概念に慣れていない場合は、次の記事を参照してください:畳み込みは実際に何をしますか?
ニューラル ネットワークのトレーニング プロセスや環境の構築方法を理解したい場合は、この記事を参照してください。記事:環境の構築とトレーニングのプロセス

このプロジェクトについて学びたい場合は、最初の記事:畳み込みニューラル ネットワーク (tensorflow) に基づく顔認識プロジェクト (1)
2 つ目の記事:畳み込みニューラル ネットワーク (tensorflow) に基づく顔認識プロジェクト (2)をお読みください。

基本的な考え方

具体的な手順は次のとおりです。

  1. 最初にデータを収集する必要があります。私の考えは、OpenCV を介してカメラを呼び出して顔写真を収集することです。
  2. 次に、主にデータセット、トレーニング セット、検証セット、およびテスト セットを分類するために、前処理を実行します。
  3. モデルのトレーニングを開始するには、事前にラベルのキーと値のペアを作成します。
  4. 顔認識効果をテストし、OpenCV を介して顔写真をキャプチャし、画像を前処理して最後にモデルに渡し、認識結果をテキスト形式で画面に出力し、q を入力して終了するまで繰り返します。

この記事では、主に上記の手順の 3 番目の手順を実装します。

活性化機能

ニューラル ネットワークの各層の I/O は線形加算のプロセス全体であるため、前の層で一連の線形変換を実行する限り、次の層の出力を正常に取得できます。活性化関数がなければ、どんなに複雑なニューラル ネットワークを構築しても、何層であっても、最終的な出力はすべてキーの線形結合になるため、単純な線形結合ではより複雑な問題を処理できません。活性化関数を導入すると、一般的な活性化関数はすべて非線形であることがわかります.したがって、神経細胞に非線形性を導入することにより、ニューラルネットワークを非線形要素に近づけることができ、ニューラルネットワークを適用できます.多数の非線形モデルに。

シグモイド関数

シグモイド関数は滑らかで導出が容易で、値の範囲は [0, 1] です。循環系で三角関数の計算問題を解き、線形系で乗算と除算の問題を解きます。式は次のとおりです
ここに画像の説明を挿入
循環システム、線形システム、双曲線システムなどに適用して、さまざまなシステムのさまざまな複雑な計算問題を解決できます。
ここに画像の説明を挿入

Tanh/双曲線正接活性化関数

これは双曲線活性化関数の一種で、一般に数学用語で tanh と表記され、シグモイド関数の 0 中心出力を作成できますが、勾配消失の問題は依然として存在します。その本質は何層も何回も何回も通過することなので、データが小さすぎて何層もあると最終的にゼロになってしまう可能性があります。そのため、関数の微分を制御した後、この問題はある程度解決されました。

ここに画像の説明を挿入

ReLU活性化機能

そのフルネームは線形整流関数であり、人工ニューラル ネットワークで非常に一般的であり、非線形関数であり、通常はランプ関数とそれから派生した一連のバリアントです。
ここに画像の説明を挿入

次のような多くの利点があります。入力値が正の数である限り、飽和領域に入らず、他の活性化関数と比較して計算がはるかに高速です。しかし、これにはまだ解決されていない問題があります。つまり、負の値を入力すると、関数は完全に失敗し、この時点で勾配はゼロになります。もちろん、前述のシグモイド関数と tanh 関数にも同じ問題があります。また、これは 0-centered 関数ではありません。つまり、導出が非常に難しく、それをサポートするには多数の関数が必要です。方式:ここに画像の説明を挿入

損失関数

損失関数は、モデルの予測値 f(x) と実際の値 Y との差を測定するために使用される演算関数です。これは、通常 L(Y, f(x) を使用する非負の実数値関数です。 ) to 損失関数が小さいほど、モデルのロバスト性が優れていることを示します。

効果

損失関数は主にモデルのトレーニング フェーズで使用されます. トレーニング データの各バッチがモデルに送信された後、予測値は順伝播によって出力され、損失関数は予測値と実際の値の差を計算します値、つまり損失です。損失値を取得した後、モデルはバックプロパゲーションによって各パラメータを更新して、実際の値と予測値の間の損失を減らし、モデルによって生成された予測値が実際の値に近づくようにし、学習の目的を達成します。 .

ニューラル ネットワーク モデルの構築

パラメータ 説明

毎回たくさんのパラメータがありますが、ここではパラメータを紹介します。

batch_size : 各反復でキャプチャされるトレーニング サンプルの数を指定しますnb_epoch
:トレーニング ローテーションの
有効を選択すると、畳み込み後のサイズが小さくなります。
verbose : ログ表示 0 は、標準出力ストリームにログ情報を出力しないことを意味します 1 は、プログレス バー レコードを出力することを意味します 2 エポックごとに 1 行のレコードを出力することを意味します

CNN モデル

4 つの畳み込み層、6 つの活性化層、2 つのプーリング層、3 つのドロップアウト層、2 つの密層、および 1 つの平坦化層を含む、合計 18 の層があります。

    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()

ネットワーク構造

以下がニューラルネットワークの構造で、パラメータの総数は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

モデルをトレーニングする

わからない場合は、コード内のコメントを見てください。

    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)

トレーニング結果

最終的な認識効果も 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

評価モデル

モデルの精度が要件を満たすことができるかどうかを確認するために使用されます。

モデルをロード

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

評価テスト

    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))

試験結果

正解率は 99.16% です。
ここに画像の説明を挿入

要約する

この章の主な難点は、常に微調整が必​​要なモデルの設計にあります。次に、損失関数、活性化関数などの概念を理解する必要があります。

おすすめ

転載: blog.csdn.net/qq_45254369/article/details/126412574