先週は、古典的な CNN ネットワーク AlexNet が画像分類に与える影響についてお話ししました。AlexNet が登場してから 2 年後の 2014 年に、オックスフォード大学は Vgg ネットワークを提案し、ILSVRC 2014 の分類プロジェクト コンテストで 2 位を獲得しました (1 位は、同じ年に提案された GoogLeNet でした)。論文「大規模画像認識のための非常に深い畳み込みネットワーク」では、畳み込みカーネルのサイズを縮小することで、より深いネットワークを構築することを提案しました。 Vggネットワーク構造 VGGnet はオックスフォードの Visual Geometry Group のチームです。ILSVRC 2014 での主な仕事は、ネットワークの深さを増やすと、ネットワークの最終的なパフォーマンスにある程度影響を与えることができることを証明することでした。下の図に示すように、この論文では、ネットワークの深さを徐々に増やすことでパフォーマンスを向上させています。少し乱暴に見え、トリックもあまりありませんが、確かに効果的です。多くの事前トレーニング済み手法では、VGG モデル (主に 16 と 19) を使用しています。他の手法と比較して、VGG はパラメーター空間が大きいため、通常、vgg モデルのトレーニングには時間がかかります。ただし、公開されている事前トレーニング済みモデルを使用すると、非常に便利に使用できます。論文に記載されているいくつかのモデルは次のとおりです。 図1 VGGネットワーク構造 図のDとEはそれぞれVGG-16とVGG-19で、パラメータは138mと144mで、この記事で最も優れた2つのネットワーク構造です。VGGネットワーク構造は、AlexNetの深化バージョンと見なすことができます。VGGは画像検出(Faster-RCNNなど)に適しています。この従来の構造は、画像のローカル位置情報を比較的よく保持します(位置情報の混乱を引き起こす可能性があるGoogLeNetのInceptionの導入とは異なります)。 vgg16 のネットワーク構造を詳しく見てみましょう。 図2 VGG16ネットワーク構造 図からわかるように、各畳み込み層は、より小さな 3×3 畳み込みカーネルを使用して画像を畳み込み、これらの小さな畳み込みカーネルを畳み込みシーケンスとして配置します。簡単に言えば、元の画像に対して 3×3 畳み込みを実行し、次に別の 3×3 畳み込みを実行し、小さな畳み込みカーネルを継続的に使用して画像に対して複数の畳み込みを実行します。 Alexnet では、当初は 11*11 の大きな畳み込みカーネル ネットワークを使用しました。ここで画像を畳み込むのに、なぜ小さな 3*3 畳み込みカーネルを使用するのでしょうか?連続した小さな畳み込みカーネルをまだ使用しますか? VGG が最初に提案されたとき、LeNet は大きな畳み込みカーネルが画像内の同様の特徴を捉えることができる (重み共有) と信じていたため、VGG は LeNet の設計原則に反していました。 AlexNet も、浅いネットワークの開始時に 9×9 および 11×11 畳み込みカーネルを使用し、浅いネットワークで 1×1 畳み込みカーネルの使用を避けようとしました。しかし、VGG の魔法は、複数の 3×3 畳み込みカーネルを使用することで、画像のローカルな知覚を、より大きな畳み込みカーネルのようにシミュレートできることです。その後、複数の小さな畳み込みカーネルを直列に接続するというアイデアは、GoogleNet と ResNet に吸収されました。 図 1 の実験結果から、VGG は複数の 3x3 畳み込みを使用して高次元の特徴を抽出していることもわかります。より大きな畳み込みカーネルを使用すると、パラメータが大幅に増加し、計算時間が指数関数的に増加するためです。たとえば、3x3 畳み込みカーネルには 9 つの重みパラメータしかありませんが、7x7 畳み込みカーネルを使用すると重みパラメータは 49 に増加します。多数のパラメータを正規化、削減、または制限するモデルがないため、多数のコアを持つ畳み込みネットワークをトレーニングすることは非常に困難になります。 VGG は、大きな畳み込みカーネルを使用すると多くの時間の無駄が発生するため、畳み込みカーネルの数を減らすことでパラメータを減らし、計算のオーバーヘッドを節約できると考えています。トレーニング時間は増加しましたが、予測時間とパラメータは全体的に短縮されました。 Vggの利点 AlexNetとの比較:
PaddlePaddle で Vgg を実装する 1. ネットワーク構造 1 #コーディング:utf-8 2 ''' 3 作成者: huxiaoman 2017.12.12 4 vggnet.py: vgg ネットワークを使用して cifar-10 分類を実装する 5 ''' 6 7 paddle.v2をpaddleとしてインポートする 8 9 def vgg(入力): 10 def conv_block(ipt, num_filter, groups, dropouts, num_channels=None): 11 paddle.networks.img_conv_group(を返す 12 入力=ipt、 13 num_channels=チャンネル数、 14 プールサイズ=2、 15 プールストライド=2、 16 conv_num_filter=[num_filter] * グループ、 17 変換フィルタサイズ=3、 18 conv_act = paddle.activation.Relu()、 19 conv_with_batchnorm=True、 20 conv_batchnorm_drop_rate=ドロップアウト、 21 pool_type = paddle.pooling.Max()) 22 23 conv1 = conv_block(入力, 64, 2, [0.3, 0], 3) 24 conv2 = conv_block(conv1, 128, 2, [0.4, 0]) 25 conv3 = conv_block(conv2, 256, 3, [0.4, 0.4, 0]) 26 conv4 = conv_block(conv3, 512, 3, [0.4, 0.4, 0]) 27 conv5 = conv_block(conv4, 512, 3, [0.4, 0.4, 0]) 28 29 ドロップ = paddle.layer.dropout(入力=conv5、ドロップアウト率=0.5) 30 fc1 = paddle.layer.fc(入力=ドロップ、サイズ=512、動作=paddle.activation.Linear()) 31 bn = パドル.レイヤー.バッチノルム( 32 入力=fc1、 33 act=paddle.activation.Relu(), 34 レイヤー属性 = パドル属性.Extra(ドロップ率=0.5)) 35 fc2 = paddle.layer.fc(入力=bn、サイズ=512、動作=paddle.activation.Linear()) 36 戻る fc2 2. モデルのトレーニング 1 #コーディング:utf-8 2 ''' 3 作成者: huxiaoman 2017.12.12 4 train_vgg.py: vgg16 をトレーニングして cifar10 データセットを分類する 5 ''' 6 7 sys、osをインポート 8 paddle.v2をpaddleとしてインポートする 9 vggnetからvggをインポート 10 11 with_gpu = os.getenv('WITH_GPU', '0') != '1' 12 13 定義main(): 14 データ次元 = 3 * 32 * 32 15 クラス次元 = 10 16 17 # パドルパドルの初期化 18 パドル.init(use_gpu=with_gpu、trainer_count=8) 19 20 イメージ = paddle.layer.data( 21 名前 = "画像"、タイプ = paddle.data_type.dense_vector(datadim)) 22 23 ネット = vgg(画像) 24 25 アウト = パドル.レイヤー.fc( 26 入力=ネット、サイズ=classdim、動作=paddle.activation.Softmax()) 27 28 lbl = パドル.レイヤー.データ( 29 名前 = "ラベル"、タイプ = paddle.data_type.integer_value(classdim)) 30 コスト = paddle.layer.classification_cost(入力 = out、ラベル = lbl) 31 32 # パラメータを作成する 33 パラメータ = paddle.parameters.create(cost) 34 35 # オプティマイザを作成する 36 momentum_optimizer = paddle.optimizer.Momentum( 37 運動量=0.9、 38 正規化 = paddle.optimizer.L2Regularization(レート = 0.0002 * 128)、 39 学習率=0.1 / 128.0、 40 学習率減衰率=0.1、 41 学習率減衰率b=50000 * 100、 42 学習率スケジュール = 'discexp') 43 44 # バッチを終了し、イベント ハンドラーを終了します 45 定義イベントハンドラ(イベント): 46 インスタンスの場合(イベント、paddle.event.EndIteration): 47 event.batch_id % 100 == 0の場合: 48 print "\nパス %d、バッチ %d、コスト %f、%s" % ( 49 イベント.pass_id、イベント.batch_id、イベント.cost、イベント.metrics) 50 その他: 51 sys.stdout.write('.') 52 sys.stdout.flush() 53 インスタンスの場合(イベント、paddle.event.EndPass): 54 # パラメータを保存 55 を open('params_pass_%d.tar' % event.pass_id, 'w') として f として実行します: 56 パラメータ.to_tar(f) 57 58 結果 = trainer.test( 59 リーダー = paddle.batch( 60 paddle.dataset.cifar.test10()、バッチサイズ=128)、 61 給餌={'画像': 0, 62 'ラベル': 1}) 63 印刷 "\n合格したテスト %d、%s" % (event.pass_id、result.metrics) 64 65 # トレーナーを作成する 66 トレーナー = paddle.trainer.SGD( 67 コスト = コスト、パラメータ = パラメータ、update_equation = モメンタム オプティマイザ) 68 69 # 推論トポロジをprotobufに保存します。 70 推論トポロジー = paddle.topology.Topology(レイヤー = 出力) 71 を open("inference_topology.pkl", 'wb') として f として実行します: 72 推論トポロジー.serialize_for_inference(f) 73 74 トレーナー.train( 75 リーダー = paddle.batch( 76 パドル.リーダー.シャッフル( 77 paddle.dataset.cifar.train10()、buf_size=50000)、 78 バッチサイズ = 128)、 79 num_passes=200、 80 イベントハンドラ=イベントハンドラ、 81 給餌={'画像': 0, 82 'ラベル': 1}) 83 84 # 推論 85 PILインポート画像 86 numpyをnpとしてインポートする 87 インポート OS 88 89 def load_image(ファイル): 90 im = Image.open(ファイル) 91 im = im.resize((32, 32), Image.ANTIALIAS) 92 im = np.array(im).astype(np.float32) 93 im = im.transpose((2, 0, 1)) # CHW 94 im = im[(2, 1, 0), :, :] # BGR 95 im = im.flatten() 96 イム = イム / 255.0 97 戻る 98 99 テストデータ = [] 100 cur_dir = os.path.dirname(os.path.realpath(__file__)) 101 test_data.append((load_image(cur_dir + '/image/dog.png'), )) 102 103 問題 = paddle.infer( 104 出力レイヤー=out、パラメータ=parameters、入力=test_data) 105 lab = np.argsort(-probs) # probs と lab は 1 つのバッチデータの結果です 106 print "image/dog.png のラベルは: %d" % lab[0][0] 107 108 109 __name__ == '__main__' の場合: 110 メイン() 3. トレーニング結果 コードを表示トレーニング結果から判断すると、7スレッド、8つのTesla K80、200回の反復、16時間21分が開かれました。数時間を要したLeNetとAlexNetの以前のトレーニングと比較すると、時間の消費は非常に高かったが、結果は非常に良好で、精度は89.11%でした。同じ機器と反復回数では、精度はLeNetとAlexNetよりも高くなっています。 Tensorflow で vgg を実装する 1. ネットワーク構造 1 定義 inference_op(input_op, keep_prob): 2 p = [] 3 # 最初のブロック conv1_1-conv1_2-pool1 4 conv1_1 = conv_op(input_op, name='conv1_1', kh=3, kw=3, 5 n_out = 64、dh = 1、dw = 1、p = p) 6 conv1_2 = conv_op(conv1_1, name='conv1_2', kh=3, kw=3, 7 n_out = 64、dh = 1、dw = 1、p = p) 8 pool1 = mpool_op(conv1_2, name = 'pool1', kh = 2, kw = 2, 9 dw = 2、dh = 2) 10 # 2番目のブロック conv2_1-conv2_2-pool2 11 conv2_1 = conv_op(pool1, name='conv2_1', kh=3, kw=3, 12 n_out = 128、dh = 1、dw = 1、p = p) 13 conv2_2 = conv_op(conv2_1, name='conv2_2', kh=3, kw=3, 14 n_out = 128、dh = 1、dw = 1、p = p) 15 pool2 = mpool_op(conv2_2, name = 'pool2', kh = 2, kw = 2, 16 dw = 2、dh = 2) 17 # 3番目のブロック conv3_1-conv3_2-conv3_3-pool3 18 conv3_1 = conv_op(pool2, name='conv3_1', kh=3, kw=3, 19 n_out = 256、dh = 1、dw = 1、p = p) 20 conv3_2 = conv_op(conv3_1, 名前='conv3_2', kh=3, kw=3, 21 n_out = 256、dh = 1、dw = 1、p = p) 22 conv3_3 = conv_op(conv3_2, 名前='conv3_3', kh=3, kw=3, 23 n_out = 256、dh = 1、dw = 1、p = p) 24 pool3 = mpool_op(conv3_3, name = 'pool3', kh = 2, kw = 2, 25 dw = 2、dh = 2) 26 # 4番目のブロック conv4_1-conv4_2-conv4_3-pool4 27 conv4_1 = conv_op(pool3, name='conv4_1', kh=3, kw=3, 28 n_out = 512、dh = 1、dw = 1、p = p) 29 conv4_2 = conv_op(conv4_1, 名前='conv4_2', kh=3, kw=3, 30 n_out = 512、dh = 1、dw = 1、p = p) 31 conv4_3 = conv_op(conv4_2, 名前='conv4_3', kh=3, kw=3, 32 n_out = 512、dh = 1、dw = 1、p = p) 33 pool4 = mpool_op(conv4_3, name = 'pool4', kh = 2, kw = 2, 34 dw = 2、dh = 2) 35 # 5番目のブロック conv5_1-conv5_2-conv5_3-pool5 36 conv5_1 = conv_op(pool4, name='conv5_1', kh=3, kw=3, 37 n_out = 512、dh = 1、dw = 1、p = p) 38 conv5_2 = conv_op(conv5_1, 名前='conv5_2', kh=3, kw=3, 39 n_out = 512、dh = 1、dw = 1、p = p) 40 conv5_3 = conv_op(conv5_2, 名前='conv5_3', kh=3, kw=3, 41 n_out = 512、dh = 1、dw = 1、p = p) 42 pool5 = mpool_op(conv5_3, 名前 = 'pool5', kh = 2, kw = 2, 43 dw = 2、dh = 2) 44 # pool5 ( [7, 7, 512] ) をベクトルに取り込む 45 shp = pool5.get_shape() 46 フラット化された形状 = shp[1].値 * shp[2].値 * shp[3].値 47 resh1 = tf.reshape(pool5, [-1, flattened_shape], 名前 = 'resh1') 48 49 # 完全接続層 1 過剰適合を防ぐために Droput を追加 50 fc1 = fc_op(resh1, name = 'fc1', n_out = 2048, p = p) 51 fc1_drop = tf.nn.dropout(fc1, keep_prob, 名前 = 'fc1_drop') 52 53 # 完全接続層 2 過剰適合を防ぐために Droput を追加 54 fc2 = fc_op(fc1_drop, name = 'fc2', n_out = 2048, p = p) 55 fc2_drop = tf.nn.dropout(fc2, keep_prob, name = 'fc2_drop') 56 57 # 完全に接続されたレイヤー 3 指定されたカテゴリの確率を見つけるためにソフトマックスを追加します 58 fc3 = fc_op(fc2_drop, name = 'fc3', n_out = 1000, p = p) 59 ソフトマックス = tf.nn.softmax(fc3) 60 予測 = tf.argmax(softmax, 1) 61 リターン予測、ソフトマックス、fc3、p 2. トレーニングネットワーク構造 1 # -*- コーディング: utf-8 -*- 2 """ 3 作成者: huxiaoman 2017.12.12 4 vgg_tf.py: vgg16 ネットワークの tensorflow バージョンをトレーニングし、cifar-10shuju 5 を分類する """ 6 datetimeからdatetimeをインポート 7 インポート数学 8 インポート時間 9 tensorflowをtfとしてインポートする 10 インポート cifar10 11 12 バッチサイズ = 128 13 バッチ数 = 200 14 15 # 畳み込み層を初期化する関数を定義します16 # input_op: 入力データ17 # name: tf.name_scope() で命名された畳み込み層の名前18 # kh、kw: それぞれ畳み込みカーネルの高さと幅19 # n_out: 出力チャネルの数20 # dh、dw: ステップの高さと幅21 # p: VGG で使用されるパラメーターを格納するパラメーター リスト22 # 畳み込みカーネルの重みを初期化するには、xavier メソッドを使用します23 def conv_op(input_op, name, kh, kw, n_out, dh, dw, p): 24 n_in = input_op.get_shape()[-1].value # 入力画像のチャンネル数を取得します 25 tf.name_scope(name) をスコープとして使用します: 26 カーネル = tf.get_variable(スコープ+'w', 27 形状 = [kh, kw, n_in, n_out]、データタイプ = tf.float32、 28 初期化子 = tf.contrib.layers.xavier_initializer_conv2d()) 29 # 畳み込み層の計算 30 conv = tf.nn.conv2d(input_op, kernel, (1, dh, dw, 1), padding = 'SAME') 31 バイアス_init_val = tf.constant(0.0, 形状 = [n_out], dtype = tf.float32) 32 バイアス = tf.Variable(bias_init_val、trainable = True、name = 'b') 33 z = tf.nn.bias_add(変換、バイアス) 34 アクティベーション = tf.nn.relu(z, 名前 = スコープ) 35 p += [カーネル、バイアス] 36 リターンアクティベーション 37 38 # 全結合層を初期化する関数を定義します 39 # input_op: 入力データ 40 # name: 全結合層の名前 41 # n_out: 出力チャネルの数 42 # p: パラメータリスト 43 # 初期化メソッドは xavier メソッドを使用します 44 def fc_op(input_op, name, n_out, p): 45 n_in = input_op.get_shape()[-1].値 46 47 スコープとして tf.name_scope(name) を使用: 48 カーネル = tf.get_variable(スコープ+'w', 49 形状 = [n_in, n_out]、データタイプ = tf.float32、 50 初期化子 = tf.contrib.layers.xavier_initializer()) 51 バイアス = tf.Variable(tf.constant(0.1, 形状 = [n_out], 52 dtype = tf.float32)、名前 = 'b') 53 activation = tf.nn.relu_layer(input_op, kernel, # ??????????????? 54 バイアス、名前 = 範囲) 55 p += [カーネル、バイアス] 56 リターンアクティベーション 57 58 # maxpool レイヤーを作成する関数を定義します 59 # input_op: 入力データ 60 # name: tf.name_scope() で命名された畳み込みレイヤーの名前 61 # kh、kw: それぞれ畳み込みカーネルの高さと幅 62 # dh、dw: ステップの高さと幅 63 def mpool_op(input_op, name, kh, kw, dh, dw): 64 tf.nn.max_pool(input_op, ksize = [1,kh,kw,1], を返す 65 ストライド = [1, dh, dw, 1]、パディング = 'SAME'、名前 = 名前) 66 67 #--------------VGG-16の作成------------------ 68 69 定義 inference_op(input_op, keep_prob): 70ページ = [] 71 # 最初のブロック conv1_1-conv1_2-pool1 72 conv1_1 = conv_op(input_op, name='conv1_1', kh=3, kw=3, 73 n_out = 64、dh = 1、dw = 1、p = p) 74 conv1_2 = conv_op(conv1_1, name='conv1_2', kh=3, kw=3, 75 n_out = 64、dh = 1、dw = 1、p = p) 76 pool1 = mpool_op(conv1_2, name = 'pool1', kh = 2, kw = 2, 77 dw = 2、dh = 2) 78 # 2番目のブロック conv2_1-conv2_2-pool2 79 conv2_1 = conv_op(pool1, name='conv2_1', kh=3, kw=3, 80 n_out = 128、dh = 1、dw = 1、p = p) 81 conv2_2 = conv_op(conv2_1, 名前='conv2_2', kh=3, kw=3, 82 n_out = 128、dh = 1、dw = 1、p = p) 83 pool2 = mpool_op(conv2_2, name = 'pool2', kh = 2, kw = 2, 84 dw = 2、dh = 2) 85 # 3番目のブロック conv3_1-conv3_2-conv3_3-pool3 86 conv3_1 = conv_op(pool2, name='conv3_1', kh=3, kw=3, 87 n_out = 256、dh = 1、dw = 1、p = p) 88 conv3_2 = conv_op(conv3_1, 名前='conv3_2', kh=3, kw=3, 89 n_out = 256、dh = 1、dw = 1、p = p) 90 conv3_3 = conv_op(conv3_2, 名前='conv3_3', kh=3, kw=3, 91 n_out = 256、dh = 1、dw = 1、p = p) 92 pool3 = mpool_op(conv3_3, name = 'pool3', kh = 2, kw = 2, 93 dw = 2、dh = 2) 94 # 4番目のブロック conv4_1-conv4_2-conv4_3-pool4 95 conv4_1 = conv_op(pool3, name='conv4_1', kh=3, kw=3, 96 n_out = 512、dh = 1、dw = 1、p = p) 97 conv4_2 = conv_op(conv4_1, 名前='conv4_2', kh=3, kw=3, 98 n_out = 512、dh = 1、dw = 1、p = p) 99 conv4_3 = conv_op(conv4_2, 名前='conv4_3', kh=3, kw=3, 100 n_out = 512、dh = 1、dw = 1、p = p) 101 pool4 = mpool_op(conv4_3, 名前 = 'pool4', kh = 2, kw = 2, 102 dw = 2、dh = 2) 103 # 5番目のブロック conv5_1-conv5_2-conv5_3-pool5 104 conv5_1 = conv_op(pool4, name='conv5_1', kh=3, kw=3, 105 n_out = 512、dh = 1、dw = 1、p = p) 106 conv5_2 = conv_op(conv5_1, 名前='conv5_2', kh=3, kw=3, 107 n_out = 512、dh = 1、dw = 1、p = p) 108 conv5_3 = conv_op(conv5_2, 名前='conv5_3', kh=3, kw=3, 109 n_out = 512、dh = 1、dw = 1、p = p) 110 pool5 = mpool_op(conv5_3, name = 'pool5', kh = 2, kw = 2, 111 dw = 2、dh = 2) 112 # pool5 ( [7, 7, 512] ) をベクトルに取り込む 113 shp = pool5.get_shape() 114 フラット化された形状 = shp[1].値 * shp[2].値 * shp[3].値 115 resh1 = tf.reshape(pool5, [-1, flattened_shape], 名前 = 'resh1') 116 117 # 完全接続層 1 過剰適合を防ぐために Droput を追加 118 fc1 = fc_op(resh1, name = 'fc1', n_out = 2048, p = p) 119 fc1_drop = tf.nn.dropout(fc1, keep_prob, 名前 = 'fc1_drop') 120 121 # 完全接続層 2 過剰適合を防ぐために Droput を追加 122 fc2 = fc_op(fc1_drop, name = 'fc2', n_out = 2048, p = p) 123 fc2_drop = tf.nn.dropout(fc2, keep_prob, name = 'fc2_drop') 124 125 # 完全に接続されたレイヤー3 カテゴリの確率を見つけるためにソフトマックスを追加します 126 fc3 = fc_op(fc2_drop, name = 'fc3', n_out = 1000, p = p) 127 ソフトマックス = tf.nn.softmax(fc3) 128 予測 = tf.argmax(softmax, 1) 129 リターン予測、ソフトマックス、fc3、p 130 131 # 評価関数を定義する 132 133 def time_tensorflow_run(セッション、ターゲット、フィード、情報文字列): 134 バーンインステップ数 = 10 135 合計時間 = 0.0 136 合計所要時間の二乗 = 0.0 137 138 i が範囲内(num_batches + num_steps_burn_in): 139 start_time = time.time() 140 _ = セッション.run(ターゲット、feed_dict = フィード) 141 期間 = time.time() - start_time 142 i >= num_steps_burn_inの場合: 143 そうでなければ i % 10: 144 print('%s: ステップ %d、期間 = %.3f' % 145 (datetime.now(), i-num_steps_burn_in, 期間)) 146 合計期間 += 期間 147 合計所要時間の二乗 += 所要時間 * 所要時間 148 平均所要時間 = 合計所要時間 / バッチ数 149 var_dur = total_duration_squared / num_batches - mean_dur * mean_dur 150 std_dur = math.sqrt(var_dur) 151 print('%s: %s、%d ステップ、%.3f +/- %.3f 秒 / バッチ' %(datetime.now(), info_string, num_batches, mean_dur, std_dur)) 152 153 154 定義train_vgg16(): 155 tf.Graph().as_default() の場合: 156 image_size = 224 # 入力画像サイズ 157 # 実行できるかどうかをテストするために乱数を生成 158 #images = tf.Variable(tf.random_normal([batch_size, image_size, image_size, 3], dtype=tf.float32, stddev=1e-1)) 159 tf.device('/cpu:0'): 160 枚の画像、ラベル = cifar10.distorted_inputs() 161 keep_prob = tf.placeholder(tf.float32) 162 予測、ソフトマックス、fc8、p = inference_op(画像、keep_prob) 163 初期化 = tf.global_variables_initializer() 164 セッション = tf.Session() 165 セッション実行(初期化) 166 time_tensorflow_run(sess, prediction,{keep_prob:1.0}, "順方向") 167 # トレーニングプロセスをシミュレートするために使用される 168 objective = tf.nn.l2_loss(fc8) # 損失を与える 169 grad = tf.gradients(objective, p) # 損失に対するすべてのモデルパラメータの勾配 170 time_tensorflow_run(sess, grad, {keep_prob:0.5},"Forward-backward") 171 172 173 174 175 __name__ == '__main__' の場合: 176 列車_vgg16() もちろん、tf.slimを使ってネットワーク構造を簡素化することもできます。 1 def vgg16(入力): 2 スリム.arg_scope([slim.conv2d, slim.fully_connected], 3 アクティベーションfn=tf.nn.relu、 4 重み初期化子 = tf.truncated_normal_initializer(0.0, 0.01)、 5 weights_regularizer = slim.l2_regularizer(0.0005)): 6 ネット = slim.repeat(入力、2、slim.conv2d、64、[3、3]、スコープ='conv1') 7 ネット = slim.max_pool2d(ネット、[2, 2]、スコープ='pool1') 8 ネット = slim.repeat(ネット、2、slim.conv2d、128、[3、3]、スコープ='conv2') 9 ネット = slim.max_pool2d(ネット、[2, 2]、スコープ='pool2') 10 ネット = slim.repeat(ネット、3、slim.conv2d、256、[3、3]、スコープ='conv3') 11 ネット = slim.max_pool2d(ネット、[2, 2]、スコープ='pool3') 12 ネット = slim.repeat(ネット、3、slim.conv2d、512、[3、3]、スコープ='conv4') 13 ネット = slim.max_pool2d(ネット、[2, 2]、スコープ='pool4') 14 ネット = slim.repeat(ネット、3、slim.conv2d、512、[3、3]、スコープ='conv5') 15 ネット = slim.max_pool2d(ネット、[2, 2]、スコープ='pool5') 16 ネット = slim.fully_connected(ネット、4096、スコープ = 'fc6') 17 ネット = slim.dropout(ネット、0.5、スコープ='dropout6') 18 ネット = slim.fully_connected(ネット、4096、スコープ = 'fc7') 19 ネット = slim.dropout(ネット、0.5、スコープ='dropout7') 20 ネット = slim.fully_connected(ネット、1000、activation_fn=なし、スコープ='fc8') トレーニング結果を比較すると、同じ機器と環境下で、tensorflow の 200 回の反復のトレーニング結果は 89.18% で、18 時間 12 分かかります。paddlepaddle の効果と比較すると、精度は似ていますが、時間は遅くなります。実際、トレーニング前にデータを処理し、トレーニング用の tfrecord マルチスレッド入力に変換すれば、時間が大幅に短縮されるはずです。 要約する 論文と実験の結果の分析を通じて、私はいくつかの点をまとめました。 1. LRN レイヤーはコンピューティング リソースを大量に消費し、効果がほとんどないため、破棄できます。 2. 大きな畳み込みカーネルは、より大きな空間的特徴を学習できますが、より多くのパラメータ空間も必要になります。小さな畳み込みカーネルは限られた空間的特徴を学習できますが、より小さなパラメータ空間しか必要としないため、多層スタッキングトレーニングの方が効果的である可能性があります。 3. ネットワークが深くなるほど、効果は良くなります。ただし、勾配消失の問題を回避するには、relu 活性化関数、batch_normalization などを選択することで、ある程度回避できます。 4. 同じ回数繰り返した場合、小さな畳み込みカーネル + 深いネットワークの効果は、大きな畳み込みカーネル + 浅いネットワークの効果よりも優れているため、独自のネットワークを設計する際の参考になります。ただし、前者のトレーニング時間は長くなる可能性がありますが、後者よりも収束が速く、精度が向上する可能性があります。 追伸:皆さんが私の更新情報をタイムリーに確認しやすくするために、公開アカウントを設定しました。今後は、記事は公開アカウントと Blog Garden に同時に公開され、皆さんがタイムリーに通知を受け取ることができるようになります。ご質問がある場合は、公開アカウントにメッセージを残していただければ、私がタイムリーに確認して返信することができます。 下のQRコードをスキャンするか、公式アカウントCharlotteDataMiningを直接検索してください。ご清聴ありがとうございました^_^ この記事は、https://mp.weixin.qq.com/s?__biz=MzI0OTQwMTA5Ng==&mid=2247483677&idx=1&sn=9402a0532bc6330f83e58c7e18f51b93&chksm=e9935b7adee4d26cd69de6c89b25be994735094ef420befd1d275f97821819ba9528f13e079a#rdでも同時に公開されています。 参考文献: 1. https://arxiv.org/pdf/1409.1556.pdf |
<<: Google が検索エンジン Talk to Books と意味連想ゲーム Semantris をリリース
アダルト動画サイトがAI技術を導入!ウェブサイトでは、顔認識やアルゴリズムを使用したビデオプレビュー...
米国のハーバード大学とエモリー大学の研究者らが協力し、ヒト幹細胞から抽出した心筋細胞を使った「人工魚...
[[260198]]米テクノロジーメディアCNETによると、マイクロソフトの共同創業者で慈善家のビル...
2018 年には、製薬会社上位 10 社だけで 3,000 億ドルを超える収益を生み出すでしょう。...
人工知能(AI)革命は半世紀以上前に始まりました。過去 10 年間で、人工知能は学術科学の領域から私...
モノのインターネットは現代のビジネスと経済を急速に変革しています。この革新的なテクノロジーにより、膨...
[[197632]]機械学習が価値を変革するための最も重要なステップは何ですか?ビジネス上の問題に...
[[186930]]次に最も重要なテクノロジーは何でしょうか? 多くの人が「人工知能、VR、自動運...
自動運転車は自動車業界にとって非常に破壊的な技術です。現在、多くのメーカーが物流、自動運転タクシー、...
導入画像分類は、コンピューター ビジョンの最も重要なアプリケーションの 1 つです。その応用範囲は、...
[[191977]]現在、機械学習のトレンドは、従来の方法のシンプルなモデル + 少量データ (手動...
最近、南京、江蘇省、天津などではAI顔認識技術の使用を禁止し始めている。 11月末、南京市のある男性...
[[231414]]会計、税務、監査などの業務でロボットが人間に取って代わったらどうなるか想像してみ...
AI をめぐっては興奮と恐怖が同時に存在しているのは否定できない現実です。一方では、マイクロソフト...