[ディープラーニングシリーズ] PaddlePaddle 手書き数字認識

[ディープラーニングシリーズ] PaddlePaddle 手書き数字認識

先週、ディープラーニングの分散操作モードに関する情報を検索していたところ、偶然 PaddlePaddle を見つけました。このフレームワークの分散トレーニング ソリューションは非常に優れていることがわかったので、皆さんと共有したいと思います。しかし、この内容は複雑すぎるので、PaddlePaddle の最初の「hello word」プログラムである MNIST 手書き数字認識について簡単に紹介します。次回は分散トレーニングにPaddlePaddleを使用するソリューションを紹介します。実は以前、CNN を使って手書き数字を認識するという記事を書いたことがあります(リンクはこちら~)が、これは Keras を使って実装したものです。今回 PaddlePaddle を使ってみて、2 つのフレームワークのメリットとデメリットを簡単に比較できるようになりました。

PaddlePaddleとは何ですか?

PaddlePaddle は Baidu が立ち上げたディープラーニングフレームワークです。tensorflow、caffe、mxnet などを使う人が多いかもしれませんが、PaddlePaddle も非常に優れたフレームワークです (以前は Paddle と呼ばれていたそうですが、現在は PaddlePaddle に名前が変更されています。なぜかいつも何とも言えない可愛らしさを感じます)

PaddlePaddle は何ができますか?

従来のほとんどの機能を実行できますが、特に感情分析、単語埋め込み、言語モデルなどの NLP サポートが非常に優れています。とにかく、これを使用して、考えられる一般的な機能をすべて試すことができます。

PaddlePaddleのインストール

PaddlePaddle のインストールについて文句を言わなければなりません。公式サイトには、「PaddlePaddle を実行する唯一の公式にサポートされている方法は、Docker コンテナーを使用することです」と書かれています。実際、Docker は中国ではあまり人気がありません。私がこれまでに遭遇したすべてのフレームワークには、多くのインストール方法があり、非常に便利です。そのため、Docker をサポートする唯一のものは非常に奇妙に感じます = =!しかし、偶然試してみたところ、pip install が使えることが分かりました。しかし、なぜ公式サイトには書かれていないのでしょうか?したがって、初心者にとって最も簡単なインストール方法は次のとおりです。

  • CPUバージョンのインストール

pip インストール paddlepaddle

  • GPUバージョンのインストール

pip で paddlepaddle-gpu をインストールします

PaddlePaddleを使用して手書きの数字を認識する

トレーニング手順

  今回は従来の方法については詳しく説明しません。比較のため、トレーニングには引き続き CNN を使用します。 PaddlePaddle を使用してモデルをトレーニングする完全なプロセスは、次の手順に分けられます。

データのインポート ----> ネットワーク構造の定義 ----> モデルのトレーニング ----> モデルの保存 ----> テスト結果

以下では、コードを使用してトレーニング プロセスを直接示します (コードは将来 GitHub に配置されます)。

#コーディング:utf-8
インポートOS
PIL インポート画像から
numpyをnpとしてインポートする
paddle.v2をpaddleとしてインポートする

# GPU を使用するかどうかを設定します。0 は使用しない、1 は使用する with_gpu = os.getenv('WITH_GPU', '0') != '1'

#ネットワーク構造を定義する def convolutional_neural_network_org(img):
    # 最初の畳み込み層 conv_pool_1 = paddle.networks.simple_img_conv_pool(
        入力=画像、
        フィルターサイズ=5、
        フィルター数=20,
        チャンネル数=1,
        プールサイズ=2、
        プールストライド=2、
        act=paddle.activation.Relu())
    # 2番目の畳み込み層 conv_pool_2 = paddle.networks.simple_img_conv_pool(
        入力=conv_pool_1、
        フィルターサイズ=5、
        フィルター数=50,
        チャンネル数=20,
        プールサイズ=2、
        プールストライド=2、
        act=paddle.activation.Relu())
    # 完全に接続された層 predict = paddle.layer.fc(
        入力=conv_pool_2、サイズ=10、動作=paddle.activation.Softmax())
    予測を返す

main() を定義します:
    # モデルを実行するデバイスを定義する paddle.init(use_gpu=with_gpu, trainer_count=1) を初期化します。

    # データの読み取り images = paddle.layer.data(
        名前='ピクセル'、タイプ=paddle.data_type.dense_vector(784))
    ラベル = パドル.レイヤー.データ(
        名前='ラベル'、タイプ=paddle.data_type.integer_value(10))

    # 以前に定義したネットワーク構造を呼び出す predict = convolutional_neural_network_org(images)

    # 損失関数を定義する cost = paddle.layer.classification_cost(input=predict, label=label)

    # トレーニング関連のパラメータを指定するparameters = paddle.parameters.create(cost)

    # トレーニング方法を定義する optimizer = paddle.optimizer.Momentum(
        学習率=0.1 / 128.0、
        運動量=0.9、
        正規化 = paddle.optimizer.L2Regularization(レート = 0.0005 * 128))

    # トレーニングモデル trainer = paddle.trainer.SGD(
        cost=コスト、parameters=パラメータ、update_equation=オプティマイザ)


    リスト = []

    # トレーニングプロセスの結果を出力するためのevent_handlerを定義します。def event_handler(event):
        インスタンスの場合(イベント、paddle.event.EndIteration):
            event.batch_id % 100 == 0 の場合:
                print "パス %d、バッチ %d、コスト %f、%s" % (
                    イベント.pass_id、イベント.batch_id、イベント.cost、イベント.metrics)
        if isinstance(event, paddle.event.EndPass):
            # open('params_pass_%d.tar' % event.pass_id, 'w') でパラメータを保存します (f:
                パラメータ.to_tar(f)

            結果 = trainer.test(reader=paddle.batch(
                paddle.dataset.mnist.test()、batch_size=128))
            print "合格 %d、コスト %f、%s のテスト\n" % (
                イベント.pass_id、結果.cost、結果.metrics)
            リスト.append((イベント.pass_id, 結果.cost,
                          結果.metrics['分類エラー評価']))

    トレーナー.train(
        リーダー = paddle.batch(
            paddle.reader.shuffle(paddle.dataset.mnist.train(), buf_size=8192)、
            バッチサイズ=128)、
        イベントハンドラ=イベントハンドラ、
        パス数=10)

    # トレーニングエラーが最小の結果を見つける best = sorted(lists, key=lambda list: float(list[1]))[0]
    'ベストパスは%s、テスト平均コストは%s' % (best[0], best[1]) を出力します
    '分類精度は%.2f%%です' % (100 - float(best[2]) * 100) を出力します

    # データをロードする def load_image(file):
        im = Image.open(ファイル).convert('L')
        im = im.resize((28, 28), Image.ANTIALIAS)
        im = np.array(im).astype(np.float32).flatten()
        イム = イム / 255.0
        戻る

    # テスト結果 test_data = []
    cur_dir = os.path.dirname(os.path.realpath(__file__))
    test_data.append((load_image(cur_dir + '/image/infer_3.png'), ))

    probs = パドル.infer(
        出力レイヤー=予測、パラメータ=パラメータ、入力=テストデータ)
    lab = np.argsort(-probs) # probs と lab は 1 つのバッチデータの結果です
    print "image/infer_3.png のラベルは: %d" % lab[0][0]


__name__ == '__main__' の場合:
    主要()
上記のコードは長く見えますが、構造は明確です。実際のデータでテストして、どのように機能するかを確認しましょう。


BaseLine バージョンでは、まず公式 Web サイトで提供されている例を使用して、最も基本的な CNN ネットワーク構造で直接トレーニングしました。コードは次のとおりです。
 1 定義convolutional_neural_network_org(img):
 2 # 最初の畳み込み層 3 conv_pool_1 = paddle.networks.simple_img_conv_pool(
 4 入力=画像、
 5 フィルターサイズ=5、
 6 フィルター数=20,
 7 num_channel=1、
 8 プールサイズ=2、
 9 プールストライド=2、
10 行為 = paddle.activation.Relu())
11 # 2番目の畳み込み層 12 conv_pool_2 = paddle.networks.simple_img_conv_pool(
13 入力=conv_pool_1、
14 フィルターサイズ=5、
15 フィルター数=50、
16 チャンネル数=20,
17 プールサイズ=2、
18 プールストライド=2、
19 行為 = paddle.activation.Relu())
20 # 完全結合層 21 predict = paddle.layer.fc(
22 入力=conv_pool_2、サイズ=10、動作=paddle.activation.Softmax())
23 リターン予測

出力は次のようになります。

I1023 13:45:46.519075 34144 Util.cpp:166] コマンドライン: --use_gpu=True --trainer_count=1
[INFO 2017-10-23 13:45:52,667layers.py:2539] __conv_pool_0___conv の出力: c = 20、h = 24、w = 24、サイズ = 11520
[INFO 2017-10-23 13:45:52,667layers.py:2667] __conv_pool_0___pool の出力: c = 20、h = 12、w = 12、サイズ = 2880
[INFO 2017-10-23 13:45:52,668layers.py:2539] __conv_pool_1___conv の出力: c = 50、h = 8、w = 8、サイズ = 3200
[INFO 2017-10-23 13:45:52,669layers.py:2667] __conv_pool_1___pool の出力: c = 50、h = 4、w = 4、size = 800
I1023 13:45:52.675750 34144 GradientMachine.cpp:85] パラメータを初期化しています。
I1023 13:45:52.686153 34144 GradientMachine.cpp:92] 初期化パラメータが完了しました。
パス 0、バッチ 0、コスト 3.048408、{'classification_error_evaluator': 0.890625}
パス 0、バッチ 100、コスト 0.188828、{'classification_error_evaluator': 0.0546875}
パス 0、バッチ 200、コスト 0.075183、{'classification_error_evaluator': 0.015625}
パス 0、バッチ 300、コスト 0.070798、{'classification_error_evaluator': 0.015625}
パス 0、バッチ 400、コスト 0.079673、{'classification_error_evaluator': 0.046875}
合格 0、コスト 0.074587、{'classification_error_evaluator': 0.023800000548362732} のテスト
「」
「」
「」
パス 4、バッチ 0、コスト 0.032454、{'classification_error_evaluator': 0.015625}
パス 4、バッチ 100、コスト 0.021028、{'classification_error_evaluator': 0.0078125}
パス 4、バッチ 200、コスト 0.020458、{'classification_error_evaluator': 0.0}
パス 4、バッチ 300、コスト 0.046728、{'classification_error_evaluator': 0.015625}
パス 4、バッチ 400、コスト 0.030264、{'classification_error_evaluator': 0.015625}
パス 4 のテスト、コスト 0.035841、{'classification_error_evaluator': 0.01209999993443489}

ベストパスは 4、テスト平均コストは 0.0358410408473 です
分類精度は98.79%
image/infer_3.png のラベルは: 3

実数 0分31秒565
ユーザー 0m20.996s
システム 0分15秒891秒

最初の行は、選択したデバイスが GPU かどうかを出力していることがわかります。ここでは GPU を選択したので、1 になります。CPU の場合は 0 になります。次の 4 行はネットワーク構造を出力し、その後トレーニング結果の出力を開始します。トレーニングが完了すると、これらの反復の中で最小の誤差である 98.79% の結果を出力します。これは依然として非常に良好な効果です。結局のところ、反復は 5 回だけです。 ***出力時間を見てください。約 31 秒と非常に高速です。しかし、この結果に特に満足しているわけではありません。以前Kerasを使用して調整したネットワークモデルは、トレーニング後に99.72%の精度に達することができますが、速度が非常に遅く、69回の反復に約30分かかります。そのため、このネットワーク構造はまだ改善できると思います。そこで、このネットワーク構造を改善しました。改善版をご覧ください。


改良版

畳み込みニューラルネットワークを定義します。
    # 最初の畳み込み層 conv_pool_1 = paddle.networks.simple_img_conv_pool(
        入力=画像、
        フィルターサイズ=5、
        フィルター数=20,
        チャンネル数=1,
        プールサイズ=2、
        プールストライド=2、
        act=paddle.activation.Relu())
    # ドロップアウトレイヤーを追加します。drop_1 = paddle.layer.dropout(input=conv_pool_1, dropout_rate=0.2)
    # 2番目の畳み込み層 conv_pool_2 = paddle.networks.simple_img_conv_pool(
        入力=ドロップ_1、
        フィルターサイズ=5、
        フィルター数=50,
        チャンネル数=20,
        プールサイズ=2、
        プールストライド=2、
        act=paddle.activation.Relu())
    # ドロップアウトレイヤーを追加します。drop_2 = paddle.layer.dropout(input=conv_pool_2, dropout_rate=0.5)
    # 完全に接続されたレイヤー fc1 = paddle.layer.fc(input=drop_2, size=10, act=paddle.activation.Linear())
    bn = paddle.layer.batch_norm(入力=fc1、act=paddle.activation.Relu()、
         layer_attr = paddle.attr.Extra(drop_rate=0.2))
    予測 = paddle.layer.fc(入力=bn、サイズ=10、動作=paddle.activation.Softmax())
    予測を返す

改良版では、過剰適合を避けるためにドロップアウト レイヤーをいくつか追加しました。ドロップアウトは第 1 および第 2 畳み込み層の後に追加され、しきい値は 0.5 に設定されます。ネットワーク構造の変更も非常に簡単です。定義されたネットワーク構造関数でモデルを直接変更できます。これは実際にはkerasのネットワーク構造定義方法と非常に似ており、非常に使いやすいです。効果を見てみましょう:
I1023 14:01:51.653827 34244 Util.cpp:166] コマンドライン: --use_gpu=True --trainer_count=1
[INFO 2017-10-23 14:01:57,830layers.py:2539] __conv_pool_0___conv の出力: c = 20、h = 24、w = 24、サイズ = 11520
[INFO 2017-10-23 14:01:57,831layers.py:2667] __conv_pool_0___pool の出力: c = 20、h = 12、w = 12、サイズ = 2880
[INFO 2017-10-23 14:01:57,832layers.py:2539] __conv_pool_1___conv の出力: c = 50、h = 8、w = 8、サイズ = 3200
[INFO 2017-10-23 14:01:57,833layers.py:2667] __conv_pool_1___pool の出力: c = 50、h = 4、w = 4、size = 800
I1023 14:01:57.842871 34244 GradientMachine.cpp:85] パラメータを初期化しています。
I1023 14:01:57.854014 34244 GradientMachine.cpp:92] 初期化パラメータが完了しました。
パス 0、バッチ 0、コスト 2.536199、{'classification_error_evaluator': 0.875}
パス 0、バッチ 100、コスト 1.668236、{'classification_error_evaluator': 0.515625}
パス 0、バッチ 200、コスト 1.024846、{'classification_error_evaluator': 0.375}
パス 0、バッチ 300、コスト 1.086315、{'classification_error_evaluator': 0.46875}
パス 0、バッチ 400、コスト 0.767804、{'classification_error_evaluator': 0.25}
パス 0、バッチ 500、コスト 0.545784、{'classification_error_evaluator': 0.1875}
パス 0、バッチ 600、コスト 0.731662、{'classification_error_evaluator': 0.328125}
「」
「」
「」
パス 49、バッチ 0、コスト 0.415184、{'classification_error_evaluator': 0.09375}
パス 49、バッチ 100、コスト 0.067616、{'classification_error_evaluator': 0.0}
パス 49、バッチ 200、コスト 0.161415、{'classification_error_evaluator': 0.046875}
パス 49、バッチ 300、コスト 0.202667、{'classification_error_evaluator': 0.046875}
パス 49、バッチ 400、コスト 0.336043、{'classification_error_evaluator': 0.140625}
パス 49、バッチ 500、コスト 0.290948、{'classification_error_evaluator': 0.125}
パス 49、バッチ 600、コスト 0.223433、{'classification_error_evaluator': 0.109375}
パス 49、バッチ 700、コスト 0.217345、{'classification_error_evaluator': 0.0625}
パス 49、バッチ 800、コスト 0.163140、{'classification_error_evaluator': 0.046875}
パス 49、バッチ 900、コスト 0.203645、{'classification_error_evaluator': 0.078125}
合格率 49、コスト 0.033639、{'classification_error_evaluator': 0.008100000210106373} のテスト

ベストパスは48、テスト平均コストは0.0313018567383です
分類精度は99.28%
image/infer_3.png のラベルは: 3

実測5分3秒151
ユーザー 4m0.052s
システム 1分8秒084秒
上記のデータから判断すると、効果は依然として非常に良好です。以前のkerasによるトレーニング効果と比較すると、結果は次のとおりです。速度の違いが非常に大きいことがわかります。同様の精度で、トレーニング時間は以前の約6倍短くなり、ネットワーク構造は比較的単純なため、調整する必要のあるパラメータが少なくなります。まとめると、 PaddlePaddle は非常に使いやすいです。ネットワーク構造の定義やトレーニング速度など、特筆すべき点はたくさんあります。しかし、私の個人的な経験では、最も特筆すべき点は次の点だと思います。

1. データのインポートが簡単。このトレーニング用の手書き数字認識データの量は比較的少ないですが、データを追加したい場合は、対応するディレクトリに直接追加することも非常に便利です。

2. event_handler メカニズムにより、トレーニング結果の出力内容をカスタマイズできます。これまで使用してきたkerasとmxnetはすべてカプセル化された関数であり、出力情報は同じです。ここで、paddlepaddleはこの機能を完全にカプセル化するのではなく、ユーザーが出力内容をカスタマイズできるようにすることで、冗長な情報を減らし、一部のモデルトレーニングの詳細の出力を増やすことができます。また、対応する関数を使用して、モデルの収束の図を描き、収束曲線を視覚化することもできます。

3. スピードが速い。上記の例では、paddlepaddle の速度が実証されており、速度が向上しながらもモデルの精度は *** の結果とほぼ同じであり、これは大量のデータに対してモデルをトレーニングする上で大きな利点となります。

ただし、PaddlePaddle には、ドキュメントが少なすぎたり、オンラインでエラーを検索しても結果が見つからないなど、私にとっては少し使いにくい点がいくつかあります。しかし、これは大きな問題ではないと思いますし、将来的に使用する人が増えるにつれて、関連情報も増えていくはずです。それで、私はいつも疑問に思っていたのですが、なぜパドルパドルは人気がないのでしょうか?インストールが変なのが不満点ですが、実はオープンソースソフトウェアとして非常に優れており、特に分散トレーニング方法は特筆すべき点です。複数のマシンと複数のカードの設計は非常に優れています。この記事ではそれについては触れませんでした。次回は、PaddlePaddleを使用して、単一マシンと単一カード、単一マシンと複数カード、複数マシンと単一カード、複数マシンと複数カードのトレーニング方法でモデルをトレーニングする方法について説明します。みんなもっと使ってください〜〜もっとコミュニケーションできます〜 ps:PaddlePaddleに関するドキュメントが少なすぎるため、公式サイトの記事ではより多くの理論を紹介し、インターネット上のブログ投稿のほとんどは、いくつかの古典的な例を行き来しているだけなので、ディープラーニングの「hello world」プログラムだけでなく、実際の戦闘に関連するシリーズを書く予定です。今回は「hello world」を紹介として使用し、次の記事でいくつかの乾いたものを書き始めますハハ〜

<<:  将来、人工知能が自発的な感情知能を獲得することは可能でしょうか?

>>:  WOT2018 孫林:連佳は人工知能技術の応用の原理と技術を探る

ブログ    
ブログ    
ブログ    

推薦する

...

...

...

よく使われるソートアルゴリズムの比較と分析

1. よく使われるソートアルゴリズムの簡単な説明以下では、主にソートアルゴリズムの基本的な概念と原則...

最新の NaViT モデルは最高です!あらゆるアスペクト比と解像度に対応する強力なトランスフォーマー

本日は、あらゆるアスペクト比と解像度で動作する Transformer モデルである NaViT を...

警告! 「リップリーディング」キーでデータを盗む、AIは本当に怖い

コンピューターに頼って悪者を即座に見つけることができれば素晴らしいのですが、問題は AI システムが...

[ビッグガイがやってくるエピソード9] データセキュリティとデータベースセキュリティの黄金律

[51CTO.com からのオリジナル記事] ライブショー「ビッグネームがやってくる」の今回のエピソ...

...

...

...

機械学習が自動車産業を次のレベルに引き上げる方法

機械学習は、ユーザーエクスペリエンスを向上させ、ビッグデータの力を活用することで、自動車業界を次のレ...

ペイ・ジアンのチームの44ページの新作:ディープラーニングモデルの複雑さを理解するには、これを読んでください

[[388699]]モデルの複雑さは、機械学習、データマイニング、ディープラーニングにおいて常に重要...

...

...

...