先月は、ディープラーニングにおける「Hello World」であるMNIST画像認識を中心に、畳み込みニューラルネットワークの基本原理、手書きCNN、PaddlePaddleのソースコード解析など、その原理の詳しい説明を含んだ4つの記事を公開しました。この記事では主に、PaddlePaddle と Tensorflow を使用して画像分類を行う方法について説明します。すべてのプログラムは私の github にありますので、ダウンロードして自分でトレーニングすることができます。 畳み込みニューラル ネットワークには、LeNet-5、AlexNet、GoogleNet、Vgg、ResNet という 5 つの古典的なモデルがあります。この記事では、まず画像を分類するための小さな CNN ネットワーク構造を設計し、次に画像分類用の LeNet-5 ネットワーク構造について学習し、比較的人気のある Tensorflow フレームワークと Baidu の PaddlePaddle を使用して LeNet-5 ネットワーク構造を実装し、結果を比較します。 画像分類とは何か 画像分類とは、意味情報に基づいて異なるカテゴリの画像を区別することです。これは、コンピューター ビジョンにおける重要な基本問題であり、画像検出、画像セグメンテーション、オブジェクト追跡、動作分析などの他の高度な視覚タスクの基礎となります。画像分類は、セキュリティ分野での顔認識やインテリジェントビデオ分析、交通分野での交通シーン認識、インターネット分野でのコンテンツベースの画像検索や自動アルバム分類、医療分野での画像認識など、多くの分野で広く使用されています。(公式サイトより引用) cifar-10 データセット CIFAR-10 分類問題は、機械学習の分野で一般的なベンチマークです。これは、10 のカテゴリを持つ 60,000 枚の 32 x 32 RGB カラー画像で構成されます。トレーニング セットには 50,000 枚の画像が使用され、テスト セットには 10,000 枚の画像が使用されます。問題は、32x32 ピクセルの RGB 画像を、
自分だけのCNNをデザインする CNN の基本的なネットワーク構造を理解した後、まず cifar-10 データを分類するための単純な CNN ネットワーク構造を設計します。 ネットワーク構造 コードの実装 1. ネットワーク構造: simple_cnn.py 1 #コーディング:utf-8 2 ''' 3 作成者: huxiaoman 2017.11.27 4 simple_cnn.py: 自分で設計したシンプルな CNN ネットワーク構造 5 ''' 6 7 インポートOS 8 PILインポート画像 9 numpyをnpとしてインポートする 10 paddle.v2をpaddleとしてインポートする 11 paddle.trainer_config_helpers からインポート * 12 13 with_gpu = os.getenv('WITH_GPU', '0') != '1' 14 15 定義 simple_cnn(画像): 16 conv_pool_1 = paddle.networks.simple_img_conv_pool( 17 入力=画像、 18 フィルターサイズ=5、 19 フィルター数=20, 20 チャンネル数=3, 21 プールサイズ=2、 22 プールストライド=2、 23 行為 = paddle.activation.Relu()) 24 conv_pool_2 = paddle.networks.simple_img_conv_pool( 25 入力=conv_pool_1、 26 フィルターサイズ=5、 27 フィルター数=50, 28 チャンネル数=20、 29 プールサイズ=2、 30 プールストライド=2、 31 行為 = paddle.activation.Relu()) 32 fc = パドル.レイヤー.fc( 33 入力=conv_pool_2、サイズ=512、動作=paddle.activation.Softmax()) 2.トレーニングプログラム: train_simple_cnn.py 1 #コーディング:utf-8 2 ''' 3 作成者: huxiaoman 2017.11.27 4 train_simple-_cnn.py: simple_cnn をトレーニングして cifar10 データセットを分類する 5 ''' 6 sys、osをインポート 7 8 paddle.v2をpaddleとしてインポートする 9 simple_cnnからsimple_cnnをインポート 10 11 with_gpu = os.getenv('WITH_GPU', '0') != '1' 12 13 14 定義main(): 15 データ次元 = 3 * 32 * 32 16 クラス次元 = 10 17 18 # パドルパドルの初期化 19 パドル.init(use_gpu=with_gpu、trainer_count=7) 20 21 イメージ = paddle.layer.data( 22 名前 = "画像"、タイプ = paddle.data_type.dense_vector(datadim)) 23 24 # ニューラルネットワーク設定を追加 25 # オプション 1. resnet 26 # ネット = resnet_cifar10(画像、深さ=32) 27 # オプション2. vgg 28 ネット = simple_cnn(画像) 29 30 アウト = paddle.layer.fc( 31 入力=ネット、サイズ=classdim、動作=paddle.activation.Softmax()) 32 33 lbl = パドル.レイヤー.データ( 34 名前 = "ラベル"、タイプ = paddle.data_type.integer_value(classdim)) 35 コスト = paddle.layer.classification_cost(入力 = out、ラベル = lbl) 36 37 # パラメータを作成する 38 パラメータ = paddle.parameters.create(cost) 39 40 # オプティマイザを作成する 41 momentum_optimizer = paddle.optimizer.Momentum( 42 運動量=0.9、 43 正規化 = paddle.optimizer.L2Regularization(レート = 0.0002 * 128)、 44 学習率=0.1 / 128.0、 45 学習率減衰率=0.1、 46 学習率減衰率b=50000 * 100、 47 学習率スケジュール = 'discexp') 48 49 # バッチを終了し、イベント ハンドラーを終了します 50 定義イベントハンドラ(イベント): 51 インスタンスの場合(イベント、paddle.event.EndIteration): 52 event.batch_id % 100 == 0の場合: 53 print "\nパス %d、バッチ %d、コスト %f、%s" % ( 54 イベント.pass_id、イベント.batch_id、イベント.cost、イベント.metrics) 55 その他: 56 sys.stdout.write('.') 57 sys.stdout.flush() 58 インスタンスの場合(イベント、paddle.event.EndPass): 59 # パラメータを保存 60 で open('params_pass_%d.tar' % event.pass_id, 'w') を f として実行します: 61 パラメータ.to_tar(f) 62 63 結果 = trainer.test( 64 リーダー = パドル.バッチ( 65 paddle.dataset.cifar.test10()、バッチサイズ=128)、 66 給餌={'画像': 0, 67 'ラベル': 1}) 68 印刷 "\n合格したテスト %d、%s" % (event.pass_id、result.metrics) 69 70 # トレーナーを作成する 71 トレーナー = paddle.trainer.SGD( 72 コスト = コスト、パラメータ = パラメータ、update_equation = モメンタム オプティマイザ) 73 74 # 推論トポロジをprotobufに保存します。 75 inference_topology = paddle.topology.Topology(layers=out) 76 を open("inference_topology.pkl", 'wb') として f として実行します: 77 推論トポロジー.シリアル化_for_inference(f) 78 79 トレーナー.train( 80 リーダー = パドル.バッチ( 81 パドル.リーダー.シャッフル( 82 paddle.dataset.cifar.train10()、buf_size=50000)、 83 バッチサイズ=128)、 84 num_passes=200、 85 イベントハンドラ=イベントハンドラ、 86 給餌={'画像': 0, 87 'ラベル': 1}) 88 89 # 推論 PILインポート画像90枚 91 numpyをnpとしてインポートする 92 インポート OS 93 94 def load_image(ファイル): 95 im = Image.open(ファイル) 96 im = im.resize((32, 32), Image.ANTIALIAS) 97 im = np.array(im).astype(np.float32) 98 # 読み込まれた画像の保存順序はW(幅)、 99 # H(高さ)、C(チャンネル)。パドルパドルには 100 # CHW の順序は異なるため、転置します。 101 im = im.transpose((2, 0, 1)) # CHW 102 # トレーニングフェーズでは、CIFARのチャネル順序は 103 # 画像はB(青)、G(緑)、R(赤)です。しかしPILは開いています 104 # RGB モードの画像。チャンネルの順序を入れ替える必要があります。 105 im = im[(2, 1, 0), :, :] # BGR 106 im = im.flatten() 107 イム = イム / 255.0 108 戻るim 109 110 テストデータ = [] 111 cur_dir = os.path.dirname(os.path.realpath(__file__)) 112 test_data.append((load_image(cur_dir + '/image/dog.png'), )) 113 114 # ユーザーはコメントを削除し、モデル名を変更できます 115 # open('params_pass_50.tar', 'r') を f として実行: 116 # パラメータ = paddle.parameters.Parameters.from_tar(f) 117 118 問題 = paddle.infer( 119 出力レイヤー=out、パラメータ=parameters、入力=test_data) 120 lab = np.argsort(-probs) # probs と lab は 1 つのバッチデータの結果です 121 print "image/dog.png のラベルは: %d" % lab[0][0] 122 123 124 __name__ == '__main__' の場合: 125 メイン() 3. 結果出力 1 I1128 21:44:30.218085 14733 Util.cpp:166] コマンドライン: --use_gpu=True --trainer_count=7 2 [INFO 2017-11-28 21:44:35,874layers.py:2539] __conv_pool_0___conv の出力: c = 20、h = 28、w = 28、サイズ = 15680 3 [INFO 2017-11-28 21:44:35,874layers.py:2667] __conv_pool_0___pool の出力: c = 20、h = 14、w = 14、サイズ = 3920 4 [INFO 2017-11-28 21:44:35,875layers.py:2539] __conv_pool_1___conv の出力: c = 50、h = 10、w = 10、size = 5000 5 [INFO 2017-11-28 21:44:35,876layers.py:2667] __conv_pool_1___pool の出力: c = 50、h = 5、w = 5、size = 1250 6 I1128 21:44:35.881502 14733 MultiGradientMachine.cpp:99] numLogicalDevices=1 numThreads=7 numDevices=8 7 I1128 21:44:35.928449 14733 GradientMachine.cpp:85] パラメータを初期化しています。 8 I1128 21:44:36.056259 14733 GradientMachine.cpp:92] 初期化パラメータが完了しました。 9 10 パス 0、バッチ 0、コスト 2.302628、{'classification_error_evaluator': 0.9296875} 11 ................................................................................ 12 ``` 13 パス 199、バッチ 200、コスト 0.869726、{'classification_error_evaluator': 0.3671875} 14 ................................................................................................... 15 パス 199、バッチ 300、コスト 0.801396、{'classification_error_evaluator': 0.3046875} 16 ..........................................................................................I1128 23:21:39.443141 14733 MultiGradientMachine.cpp:99] numLogicalDevices=1 numThreads=7 numDevices=8 17 18 テスト合格 199、{'classification_error_evaluator': 0.5248000025749207} 19 image/dog.png のラベルは: 9 7 つのスレッドを開き、トレーニングに 8 つの Tesla K80 GPU を使用しました。batch_size = 128、反復回数 200 回、所要時間 1 時間 37 分、エラー分類率は 0.5248 でした。この結果は、あまり高くありません。これをベースラインとして使用し、後で調整することができます。 LeNet-5 ネットワーク構造 Lenet-5 ネットワーク構造は Yan LeCun が提案した論文から派生したもので、原文は「文書認識に適用される勾配ベース学習」であり、この論文では検証のために MNIST 手書き数字を入力データ (32 * 32) として使用しています。ネットワーク構造を見てみましょう。 LeNet-5 には、入力層 1 つ、畳み込み層 3 つ (C1、C3、C5)、ダウンサンプリング層 2 つ (S2、S4)、完全接続層 1 つ (F6)、出力層 1 つの合計 8 つの層があり、各層には複数の特徴マップ (自動的に抽出される複数の特徴セット) があります。 入力層
C1畳み込み層
S2 ダウンサンプリング層(プーリング層)
C3畳み込み層
S4 ダウンサンプリング レイヤー
C5畳み込み層
F6完全結合層
出力層
LeNet-5 の PaddlePaddle 実装 1. ネットワーク構造 lenet.py 1 #コーディング:utf-8 2 ''' 3 作成者: huxiaoman 2017.11.27 4 lenet.py:LeNet-5 5 ''' 6 7 インポートOS 8 PILインポート画像 9 numpyをnpとしてインポートする 10 paddle.v2をpaddleとしてインポートする 11 paddle.trainer_config_helpers からインポート * 12 13 with_gpu = os.getenv('WITH_GPU', '0') != '1' 14 15 定義 lenet(画像): 16 conv_pool_1 = paddle.networks.simple_img_conv_pool( 17 入力=画像、 18 フィルターサイズ=5、 19 フィルター数=6, 20 チャンネル数=3, 21 プールサイズ=2、 22 プールストライド=2、 23 行為 = paddle.activation.Relu()) 24 conv_pool_2 = paddle.networks.simple_img_conv_pool( 25 入力=conv_pool_1、 26 フィルターサイズ=5、 27 フィルター数=16, 28 プールサイズ=2、 29 プールストライド=2、 30 act=paddle.activation.Relu()) 31 conv_3 = img_conv_layer( 32 入力 = conv_pool_2、 33 フィルターサイズ = 1、 34 フィルター数 = 120、 35 歩幅 = 1) 36 fc = パドル.レイヤー.fc( 37 入力=conv_3、サイズ=84、動作=paddle.activation.Sigmoid()) 38 リターン fc 2. トレーニングコード train_lenet.py 1 #コーディング:utf-8 2 ''' 3 作成者: huxiaoman 2017.11.27 4 train_lenet.py: LeNet-5 をトレーニングして cifar10 データセットを分類する 5 ''' 6 7 sys、osをインポート 8 9 paddle.v2をpaddleとしてインポートする 10 lenetからインポートlenet 11 12 with_gpu = os.getenv('WITH_GPU', '0') != '1' 13 14 15 定義main(): 16 データ次元 = 3 * 32 * 32 17 クラス次元 = 10 18 19 # パドルパドルの初期化 20 パドル.init(use_gpu=with_gpu、trainer_count=7) 21 22 イメージ = paddle.layer.data( 23 名前 = "画像"、タイプ = paddle.data_type.dense_vector(datadim)) 24 25 # ニューラルネットワーク設定を追加 26 # オプション 1. resnet 27 # ネット = resnet_cifar10(画像、深さ=32) 28 # オプション2. vgg 29 ネット = lenet(画像) 30 31 アウト = パドル.レイヤー.fc( 32 入力=ネット、サイズ=classdim、動作=paddle.activation.Softmax()) 33 34 lbl = パドル.レイヤー.データ( 35 名前 = "ラベル"、タイプ = paddle.data_type.integer_value(classdim)) 36 コスト = paddle.layer.classification_cost(入力 = out、ラベル = lbl) 37 38 # パラメータを作成する 39 パラメータ = paddle.parameters.create(cost) 40 41 # オプティマイザを作成する 42 momentum_optimizer = paddle.optimizer.Momentum( 43 運動量=0.9、 44 正規化 = paddle.optimizer.L2Regularization(レート = 0.0002 * 128)、 45 学習率=0.1 / 128.0、 46 学習率減衰率=0.1、 47 学習率減衰率b=50000 * 100、 48 学習率スケジュール = 'discexp') 49 50 # バッチを終了し、イベント ハンドラーを終了します 51 定義イベントハンドラ(イベント): 52 インスタンスの場合(イベント、paddle.event.EndIteration): 53 event.batch_id % 100 == 0の場合: 54 印刷 "\nパス %d、バッチ %d、コスト %f、%s" % ( 55 イベント.pass_id、イベント.batch_id、イベント.cost、イベント.metrics) 56 その他: 57 sys.stdout.write('.') 58 sys.stdout.flush() 59 インスタンスの場合(イベント、paddle.event.EndPass): 60 # パラメータを保存 61 を open('params_pass_%d.tar' % event.pass_id, 'w') として f として実行: 62 パラメータ.to_tar(f) 63 64 結果 = trainer.test( 65 リーダー = paddle.batch( 66 paddle.dataset.cifar.test10()、バッチサイズ=128)、 67 給餌={'画像': 0, 68 'ラベル': 1}) 69 印刷 "\n合格したテスト %d、%s" % (event.pass_id、result.metrics) 70 71 # トレーナーを作成する 72 トレーナー = paddle.trainer.SGD( 73 コスト = コスト、パラメータ = パラメータ、update_equation = モメンタム オプティマイザ) 74 75 # 推論トポロジをprotobufに保存します。 76 inference_topology = paddle.topology.Topology(layers=out) 77 を open("inference_topology.pkl", 'wb') として f として実行します: 78 推論トポロジー.シリアル化_for_inference(f) 79 80 トレーナー.train( 81 リーダー = paddle.batch( 82 パドル.リーダー.シャッフル( 83 paddle.dataset.cifar.train10()、buf_size=50000)、 84 バッチサイズ=128)、 85 num_passes=200、 86 イベントハンドラ=イベントハンドラ、 87 給餌={'画像': 0, 88 'ラベル': 1}) 89 90 # 推論 91 PILインポート画像 92 numpyをnpとしてインポートする 93 インポート OS 94 95 def load_image(ファイル): 96 im = Image.open(ファイル) 97 im = im.resize((32, 32), Image.ANTIALIAS) 98 im = np.array(im).astype(np.float32) 99 # 読み込まれた画像の保存順序はW(幅)、 100 # H(高さ)、C(チャンネル)。パドルパドルには 101 # CHW の順序が異なるため、転置します。 102 im = im.transpose((2, 0, 1)) # CHW 103 # トレーニングフェーズでは、CIFARのチャネル順序は 104 # 画像はB(青)、G(緑)、R(赤)です。しかしPILは開いています 105 # RGB モードの画像。チャンネルの順序を入れ替える必要があります。 106 im = im[(2, 1, 0), :, :] # BGR 107 im = im.flatten() 108 イム = イム / 255.0 109 戻る 110 111 テストデータ = [] 112 cur_dir = os.path.dirname(os.path.realpath(__file__)) 113 test_data.append((load_image(cur_dir + '/image/dog.png'), )) 114 115 # ユーザーはコメントを削除し、モデル名を変更できます 116 # open('params_pass_50.tar', 'r') を f として: 117 # パラメータ = paddle.parameters.Parameters.from_tar(f) 118 119 問題 = paddle.infer( 120 出力レイヤー=out、パラメータ=parameters、入力=test_data) 121 lab = np.argsort(-probs) # probs と lab は 1 つのバッチデータの結果です 122 print "image/dog.png のラベルは: %d" % lab[0][0] 123 124 125 __name__ == '__main__' の場合: 126 メイン() 3. 結果出力 1 I1129 14:52:44.314946 15153 Util.cpp:166] コマンドライン: --use_gpu=True --trainer_count=7 2 [INFO 2017-11-29 14:52:50,490layers.py:2539] __conv_pool_0___conv の出力: c = 6、h = 28、w = 28、サイズ = 4704 3 [INFO 2017-11-29 14:52:50,491layers.py:2667] __conv_pool_0___pool の出力: c = 6、h = 14、w = 14、サイズ = 1176 4 [INFO 2017-11-29 14:52:50,491layers.py:2539] __conv_pool_1___conv の出力: c = 16、h = 10、w = 10、サイズ = 1600 5 [INFO 2017-11-29 14:52:50,492layers.py:2667] __conv_pool_1___pool の出力: c = 16、h = 5、w = 5、サイズ = 400 6 [INFO 2017-11-29 14:52:50,493layers.py:2539] __conv_0__ の出力: c = 120、h = 5、w = 5、size = 3000 7 I1129 14:52:50.498749 15153 MultiGradientMachine.cpp:99] numLogicalDevices=1 numThreads=7 numDevices=8 8 I1129 14:52:50.545882 15153 GradientMachine.cpp:85] パラメータを初期化しています。 9 I1129 14:52:50.651103 15153 GradientMachine.cpp:92] 初期化パラメータが完了しました。 10 11 パス 0、バッチ 0、コスト 2.331898、{'classification_error_evaluator': 0.9609375} 12 ``` 13 ...... 14 パス 199、バッチ 300、コスト 0.004373、{'classification_error_evaluator': 0.0} 15 .............................................................................................I1129 16:17:08.678097 15153 MultiGradientMachine.cpp:99] numLogicalDevices=1 numThreads=7 numDevices=8 16 17 テスト合格 199、{'classification_error_evaluator': 0.39579999446868896} 18 image/dog.png のラベルは: 7 同じ 7 つのスレッド、8 つの Tesla K80 GPU、batch_size = 128、200 回の反復で 1 時間 25 分かかり、誤分類率は 0.3957 で、simple_cnn の 0.5248 より 12.91% 高くなりました。もちろん、この結果はあまり良いものではありません。詳細なログを出力すると、トレーニングの過程で損失が最初は減少し、その後増加していることがわかります。これは、ある程度のオーバーフィッティングを示しています。オーバーフィッティングを防ぐ方法については、後ほど詳しく説明します。 CNN を可視化するウェブサイトがあり、mnist と cifar10 分類のネットワーク構造を可視化することができます。以下は cifar-10 BaseCNN のネットワーク構造です。 LeNet-5 の Tensorflow 実装 LeNet-5 の Tensorflow バージョンは、モデル/tutorials/image/ cifar10/( https://github.com/tensorflow/models/tree/master/tutorials/image/cifar10) の手順を参照してトレーニングできますが、ここでのコードには、過剰適合を防ぐためのデータ処理、重み減衰、および正規化の方法が多数含まれています。公式の説明によると、batch_size=128 の場合、Tesla K40 で 100,000 回反復するのに 4 時間かかり、精度は 86% に達することができます。ただし、データを処理せずに直接実行すると、効果はあまり良くありません。ただし、cifar10_inputs.py の distorted_inouts 関数によってデータセットを増やすためのデータの前処理のアイデアや、cifar10.py の重みとバイアスの減衰設定を注意深く参照することができます。現在、反復は約10,000回に達し、コストは0.98、accは78.4%です。 データ処理なしで cifar10 を実行し、そのパフォーマンスを確認し、paddle の結果と比較する予定です。でも、それを補うには週末まで待たなければなりません = = 要約する このセクションでは、画像分類に従来の cifar-10 データセットを使用します。3 つの実装方法が使用されます。1 つ目は私が設計したシンプルな CNN、2 つ目は LeNet-5、3 つ目は Tensorflow によって実装された LeNet-5 です。速度の比較は次の表で確認できます。 LeNet-5 は、オリジナルの simple_cnn と比較して、精度と速度が確実に向上していることがわかります。Tensorflow バージョンが終了したら、結果を追加して比較することができます。しかし、Lenet-5 ネットワーク構造を使用した後、結果はある程度改善されましたが、まだ理想的ではありません。ログの損失情報から、基本的にオーバーフィッティングであることが推測できます。ニューラル ネットワークのトレーニング プロセスでオーバーフィッティングを回避するにはどうすればよいでしょうか。次の号ではこの点に焦点を当てます。さらに、次のセクションでは、AlexNet を紹介し、その効果を比較するための分類の実験を行います。 参考文献 1.LeNet-5 論文:「文書認識への勾配ベース学習の適用」 2. ビジュアル CNN: http://shixialiu.com/publications/cnnvis/demo/ |
<<: 2018年世界大学AIランキングが発表、中国の大学が好成績!
>>: ディープラーニングと従来の機械学習のメリットとデメリット!
ミスティはとんでもない乗り心地を体験した。 FoundryとVenrockから1,150万ドルを調達...
オープンソースのMoEモデルがついに国内初のプレイヤーを迎えます!そのパフォーマンスは高密度の Ll...
春節の直前に、同義千文モデル(Qwen)バージョン1.5がリリースされました。今朝、新バージョンのニ...
[[208505]]強固な経済基盤がなければ、豊かな国と強い国民は実現できません。中国共産党第19回...
この記事は公開アカウント「Reading Core Technique」(ID: AI_Discov...
2023 年は世界中の IT 部門に多くの変化をもたらしました。これまでのところ、最大の驚きは Ge...
この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...
先月、Meta FAIR の Tian Yuandong が参加した研究が大きな称賛を受けました。彼...
知識の蓄積は規模の拡大をもたらし、規模の拡大は市場の集中につながります。 産業が「組立ライン」の形で...
人間の知覚は客観的な刺激だけでなく過去の経験によっても形成され、それらが組み合わさって脳内で複雑な活...
売上予測は、機械学習 (ML) の一般的かつ重要な用途です。予測売上は、ベースラインを確立して新しい...