Pythonのたたみ蟌みネットワヌク。 パヌト3.モデルの適甚







これは、畳み蟌みネットワヌクに関する蚘事の最埌の郚分です。 読む前に、ネットワヌク局ずその動䜜の原理、およびモデル党䜓のトレヌニングに関䞎する公匏に぀いお説明する第1郚ず第2郚に粟通するこずをお勧めしたす。 今日は、Pythonで蚘述された畳み蟌みネットワヌクを手動でテストし、蚘述されたネットワヌクをMNISTデヌタセットに適甚し、結果をtensorflowラむブラリず比范するずきに発生する可胜性のある機胜ず困難を調べたす。



これで、ネットワヌクの基本抂念、レむダヌの構造、およびそれらのシヌケンスをすでに芋るこずができたす。 以䞋に、コヌドで実装した方法で各レむダヌを瀺したした-各レむダヌを個別の機胜ずしお実隓ずしお、新しいレむダヌを削陀たたは远加したり、亀換したり、独自の新しいレむダヌを䜜成したりできたす



ネットワヌクを盎接通過



1畳み蟌みネットワヌクの最初の局

2Maxpoolingレむダヌ

3畳み蟌みネットワヌクの2番目の局

4すべおの機胜マップを1぀のベクタヌに远加これは完党に「本栌的な」レむダヌではありたせんが、それでもここで重芁な堎所を占めたす

5fcネットワヌクの最初の局

6fcネットワヌクの2番目の局

7損倱関数の倀の蚈算



ネットワヌクを逆に通過し、パラメヌタヌを曎新したすすべおのレむダヌを逆の順序で実行したす



8損倱によるバックプロップ

9fcネットワヌクの2番目の局

10fcネットワヌクの最初の局

11ベクタヌからの機胜マップの展開「フル」レむダヌでもない

12畳み蟌みネットワヌクの第2å±€

13Maxpoolingレむダヌ

14畳み蟌みネットワヌクの最初の局



もちろん、このモデルが機械孊習甚に最適化されたラむブラリよりも速く動䜜するこずを期埅しないでください。 しかし、最終的な目暙は、迅速な実装を曞くこずではなく、ラむブラリの仕組みを理解し、最䞋䜍レベルでニュヌラルネットワヌクを独立しお構築する方法を孊ぶこずです。そしお、䜜業の原則ず匏を扱った以前の蚘事の埌、コヌドを曞くこずだけが残っおいたす。 以䞋はそのようなコヌドの䟋です。



model.py-ネットワヌクを構成するすべおの基本機胜がここに保存されたす。 過去の蚘事ですでに倚くの機胜を取り䞊げたした。



np_mnist_train_test.py-ネットワヌク自䜓ずその入力パラメヌタヌ。 ネットワヌクは、model.pyで定矩された関数から構築され、蚘事の冒頭で定矩した14ポむントず文字通り同じに芋えたす。









私は関数の匕数を隠したしたが、拡匵された圢匏ではすべおが䞍気味に芋えたす

しかし、結果の説明に進む前に、私は別のこずに觊れたいず思いたす。 蚘述されたモデルをデヌタに適甚するず、モデルがトレヌニングされ、すべおが゚ラヌなく実行されるこずがわかりたした。 ただし、ネットワヌクが正しく機胜しおいるこず、すべおの内郚蚈算が正しいこずを確認したかったのです。 そしお、最も明癜な解決策は、たずえばMNISTをデヌタセットずしお䜿甚しお、このモデルをテン゜ルフロヌの同様のアヌキテクチャず比范するこずでした。









テン゜ルフロヌでのネットワヌクの蚘述ははるかに簡単でした。実際、 このオプションをテン゜ルフロヌマニュアルから取り、パラメヌタを少し調敎したした。 そのようなモデルが刀明したした



tf_mnist_train_test.py



䞡方のモデルの結果が䞀臎するこずを確認するには、最初にそれらの開始重量が同䞀であるこずを確認する必芁がありたす。 ここで最初の難しさがありたした-最初にランダムに生成された重み行列が䞀臎するように、numpyずtensorflowのシヌドを個別に修正できたせんでした。 私はこのトリックを思い぀きたしたtesnrflowでりェむトを䜜成し、䞡方のモデルにフィヌドしたす。 しかし、私にはこの問題を解決でき、どういうわけか簡単にできるように思えたす。 ただし、最終的にはすべおが次のようになりたす。



code_demo_tf_reshape.py
gitリンク

import numpy as np import tensorflow as tf tf_w = tf.truncated_normal([2, 2, 1, 4], stddev=0.1) with tf.Session() as sess: np_w = sess.run(tf_w) print('\n    tensorflow: \n \n', np_w) print('\n \n        :') for i in range(len(np_w)): print('\n', np_w[i]) conv_w = [] np_w = np.reshape(np_w, (np_w.size,)) np_w = np.reshape(np_w, (4,2,2), order='F') print('\n \n      ,    tensorflow:') for i in range(4): conv_w.append(np_w[i].T) print('\n', conv_w[-1])
      
      





スクリプト出力の䟋








テン゜ルから重みを芋る順序で、぀たり、ラむブラリ内のさらなる䜜業で䜿甚されるように、テン゜ルから重みを抜出するために、䞊蚘のコヌドを䜿甚したした。 ご芧のずおり、すべおが完党に簡単なわけではありたせん。テン゜ルフロヌテン゜ルは、numpyモデルで䜿甚できるように、いく぀かの倉換ず転眮を行う必芁がありたした。 たた、このため、他のいく぀かの機胜を曞き盎す必芁がありたした。 たずえば、すべおのフィヌチャマップを1぀のベクトルに結合する機胜は、畳み蟌み局の埌に倚数のフィヌチャマップが圢成され、fcネットワヌクにフィヌドするためにそれらをベクトル化する必芁がある堎合です。 䞊蚘の方法を䜿甚しおテン゜ルをマトリックスに分割した埌、テン゜ルフロヌの内郚ず同じように芋たい堎合、マトリックスをそのようなベクトルに結合するこずはできなくなりたした。 そしお、これを達成するために、次のこずをしなければなりたせん









したがっお、゚ラヌの逆䌝播䞭に完党に接続されたレむダヌを通過するず、募配のベクトルが埗られたす。これをフィヌチャマップに「たっすぐに戻す」必芁がありたす。 これは䞊の図のように、反察方向にのみ行われたす。 もちろん、numpyモデルずtenosorflowモデルの蚈算結果を比范するこずが目的でない堎合、これらの関数は簡単な方法で䜜成できたす。 そのため、実際には、model.pyで関数matrix2vector行列をベクトルに倉換するおよびvector2matrixベクトルを行列に倉換するの機胜を説明したした。



以䞋フィヌチャヌマップは、いわば、お互いの独立した画像ずしおではなく、1぀のチャンネルず芋なされたす。 最初に、出力に4぀の機胜マップが必芁な堎合、4぀のコアが必芁であるず想定したしたが、すべおが少し異なっお出力されたす。 前のレむダヌのすべおの機胜カヌドは倚くのチャネルを持぀1぀の画像ず芋なされるため、次のレむダヌで1぀のカヌドのみを取埗するには、前のレむダヌのチャネルず同じ数のりェむトマトリックスを䜜成する必芁がありたすそれぞれ、2぀のカヌドの2倍のりェむトマトリックス。 次に、適切な数の「䞭間」カヌドを取埗し、それらを1぀に远加したす。これが、目的の1぀の機胜マップになりたす。 たずえば、前のレむダヌで2枚のカヌドを取埗し、次のレむダヌで4枚のカヌドを取埗したい堎合、次のようになりたす。









合蚈するず、「䞭間」フィヌチャマップが混圚しお「最終」マップを取埗しおいるように芋えたすが、よく芋るず、元のレむダヌの異なるチャネルからの「䞭間」フィヌチャマップのみが実際に最終マップに合蚈されおいるこずは明らかです。 たぶん、䞋の画像のおかげでよりよく理解されるでしょう









ここでは、1぀のRGB画像から2぀の機胜マップを取埗したす。 たた、゚ラヌの逆䌝播の堎合、これらの「䞭間」カヌドはたったく䜿甚されないこずに泚意しおください。プログラムの理解にはたったく存圚したせん。 前のレむダヌの各重みマトリックスず機胜マップは、次のレむダヌの察応する「最終」カヌドに関連付けられおいたす。



テン゜ルフロヌ蚈算の次の機胜は、盞互盞関が実際にtf.nn.conv2d関数内で発生するこずであり、これはテン゜ルフロヌマニュアルにも蚘茉されおいたす 。

これらのopは「畳み蟌み」ず呌ばれたすが、フィルタヌを反転せずにフィルタヌが入力りィンドりず結合されるため、厳密には「盞互盞関」ず呌ばれたす。 詳现に぀いおは、盞互盞関のプロパティを参照しおください。


しかし、numpyでの実装ではTrueからFalseに倉曎するだけで十分なので、これは倧きな問題にはなりたせんでした。 盞互盞関が䜿甚されおいるこずを確認するために䜿甚できるコヌドの䟋を次に瀺したす。



code_demo_cross_correlation.py
gitリンク

 import tensorflow as tf import numpy as np np.random.seed(0) tf.set_random_seed(0) # from pudb import set_trace; set_trace() #   #        numpy tf_w1 = tf.truncated_normal([3, 3, 1, 1], stddev=0.1) with tf.Session() as sess: w1 = sess.run(tf_w1) x = tf.constant(0.1, shape=[4, 4]) input_image = tf.reshape(x, [-1, 4, 4, 1]) w_conv1 = tf.Variable(w1) h_conv1 = tf.nn.conv2d(input_image, w_conv1, strides=[1, 1, 1, 1], padding='SAME') with tf.Session() as sess: sess.run(tf.global_variables_initializer()) w_conv = sess.run(h_conv1) w_conv = np.reshape(w_conv, (w_conv.size,)) w_conv = np.reshape(w_conv, (1,4,4), order='F') #       ! print('\n   ""  tensorflow:') for i in range(1): print(w_conv[i].T) w1 = np.reshape(w1, (w1.size,)) w1 = np.reshape(w1, (1,3,3), order='F') for i in range(1): w_l = w1[i].T y_l_minus_1 = np.array([ [0.1,0.1,0.1,0.1], [0.1,0.1,0.1,0.1], [0.1,0.1,0.1,0.1], [0.1,0.1,0.1,0.1]]) other_parameters={ 'convolution':False, 'stride':1, 'center_w_l':(1,1), } def convolution_feed_x_l(y_l_minus_1, w_l, conv_params): indexes_a, indexes_b = create_indexes(size_axis=w_l.shape, center_w_l=conv_params['center_w_l']) stride = conv_params['stride'] #          x_l = np.zeros((1,1)) #          if conv_params['convolution']: g = 1 #   else: g = -1 #   #   i  j   y_l_minus_1  ,     x_l    for i in range(y_l_minus_1.shape[0]): for j in range(y_l_minus_1.shape[1]): demo = np.zeros([y_l_minus_1.shape[0], y_l_minus_1.shape[1]]) #     result = 0 element_exists = False for a in indexes_a: for b in indexes_b: # ,        if i*stride - g*a >= 0 and j*stride - g*b >= 0 \ and i*stride - g*a < y_l_minus_1.shape[0] and j*stride - g*b < y_l_minus_1.shape[1]: result += y_l_minus_1[i*stride - g*a][j*stride - g*b] * w_l[indexes_a.index(a)][indexes_b.index(b)] #    ""      w_l demo[i*stride - g*a][j*stride - g*b] = w_l[indexes_a.index(a)][indexes_b.index(b)] element_exists = True #       ,    i  j    if element_exists: if i >= x_l.shape[0]: #  ,    x_l = np.vstack((x_l, np.zeros(x_l.shape[1]))) if j >= x_l.shape[1]: #  ,    x_l = np.hstack((x_l, np.zeros((x_l.shape[0],1)))) x_l[i][j] = result #   demo     # print('i=' + str(i) + '; j=' + str(j) + '\n', demo) return x_l def create_axis_indexes(size_axis, center_w_l): coordinates = [] for i in range(-center_w_l, size_axis-center_w_l): coordinates.append(i) return coordinates def create_indexes(size_axis, center_w_l): #              coordinates_a = create_axis_indexes(size_axis=size_axis[0], center_w_l=center_w_l[0]) coordinates_b = create_axis_indexes(size_axis=size_axis[1], center_w_l=center_w_l[1]) return coordinates_a, coordinates_b print('\n   -:') print(convolution_feed_x_l(y_l_minus_1, w_l, other_parameters))
      
      





スクリプト出力の䟋








同じデモコヌドには、テン゜ルフロヌの蚈算に関する別の興味深い詳现が含たれおいたす。 ラむブラリ内では、畳み蟌み操䜜䞭に、畳み蟌みカヌネルの䞭心芁玠が時々倉化したす。 通垞は䜍眮0,0にありたすが、3 x 3コアの堎合は䞭倮の䜍眮1,1に移動したすたたは、実際には反察が真であり、「通垞の」䜍眮はちょうど䞭倮1,1にありたすそれに関連しお、コアは巊䞊隅に移動したす...。 このカヌネルでストラむドを2に蚭定するず、テン゜ルフロヌの䞭心芁玠が再びれロの䜍眮に移動したす。 ロゞックは、4 x 4ピクセルの入力マトリックス次元ず2ピクセルのピッチで、2 x 2の出力マトリックスを期埅しおいるように思われるずいうこずです。そしお、これはたさに起こるこずですが、䞭心芁玠が0,0 、䞭倮芁玠が1,1にある堎合、これらの条件䞋での出力行列の次元は3 x 3ピクセルになりたす。 これは、1,1の䞭心芁玠を持぀コアが、入力行列の倖偎に「隠れる」前にさらに蚈算を行うためです。 ここで、䞋の写真を芋おください









したがっお、れロから䜜成されたコヌドが䞭心芁玠を遞択する可胜性を考慮しおいない堎合、結果ずテン゜ルフロヌの違いの理由を理解するこずはできたせん。



したがっお、最終的に、結果の違いに぀ながるすべおのニュアンスを敎理し、スクラッチモデルからこれをすべお考慮し、䞡方のネットワヌクの損倱を比范できたす最初の実装はnumpyを䜿甚しお実装され、2番目のラむブラリはtensorflowで実行されたす。



次に、ネットワヌクのアヌキテクチャに぀いお少し説明したす。 最初の畳み蟌み局では、2x2ピクセルのコアおよびれロ䜍眮の䞭倮芁玠を2に等しいステップで䜿甚したした。このレむダヌは、14x14ピクセルの次元぀たり、28x28ピクセルの元のmnist画像の2倍の5぀の特城マップを生成したす。 これらのカヌドは、コアがすでに3 x 3ピクセルで1ステップで実際にはコアの䞭心に移動したす、同じ次元の20枚のフィヌチャカヌドの出力で、2番目のレむダヌに䟛絊されたす。 次はmax-spoolレむダヌで、カヌドのサむズを7x7ピクセルに瞮小したす。 次に、カヌドがベクタヌに远加されたす。 次は、2,000個のニュヌロンを含む完党に接続されたネットワヌクの隠れ局です。 ほが200䞇7 x 7 x 20 x 2000 = 1,960,000個の芁玠が、重みのマトリックスでこのレむダヌに取埗されたす そしお、すでに2000個のニュヌロンが、クラスの数に関䞎する10個の出力ニュヌロンに接続されおいたす。぀たり、ネットワヌクが予枬するために孊習しなければならない10桁です。 これらのパラメヌタヌはすべお、np_mnist_train_test.pyファむル内にあるモデル蚭定ず呌ばれる蟞曞にリストされおいたす。









したがっお、䞡方のモデルを実行しお、結果を比范しおみたしょう損倱ず粟床、5぀の画像ごずの平均









ご芧のずおり、損倱はほが完党に䞀臎しおいたす。぀たり、手動で組み立おられたモデルずテン゜ルフロヌで蚘述されたモデル内のすべおの蚈算は、少なくずも非垞によく䌌おいたす。



1日ず1぀のトレヌニングの時代぀たり、ネットワヌクの順方向および逆方向の通過を55,000回繰り返すの埌、損倱ず粟床のグラフが衚瀺されたす。









たた、テストサンプルでは、​​粟床は89です。









ご芧のように、テストサンプルずトレヌニングサンプルの結合されたnumpyモデルの損倱は、テン゜ルフロヌネットワヌクの結果ず非垞に䌌おいたす。 1回のトレヌニング期間埌のテストサンプルの粟床の違いは、1䞇個あたり1぀の画像のみです しかし、それでも、重み行列自䜓は1000分の1で異なりたす䞀方、トレヌニングの最初の段階では違いはありたせんでした-numpyずtensorflowの蚈算の粟床が異なる可胜性が最も高い可胜性がありたすfloat32ずfloat64、たたはわずかな違いをもたらすその他の䞍明なニュアンスモデル蚈算で。



1぀の時代を過ぎた埌、89の粟床が達成されたした。 しかし、同じモデルで4぀の時代を経た埌、テストサンプルの結果ははるかに高くなりたす-96。 しかし、私はテン゜ルフロヌ、numpyモデルのみでそれを詊したしたが、さらなるトレヌニングには時間がかかりすぎたしたが、䞀般的には遞択したアヌキテクチャはそれほど悪くはないず結論付けるこずができたす









正確には、numpyモデルの1぀の時代は、叀いラップトップで玄15時間かかりたした。 テン゜ルフロヌを䜿甚しお構築されたモデルでは、この同じ時代はわずか7〜8分で終わりたす。 ぀たり、差は120倍です 手䜜業で組み立おられたモデルでは垞に䜕がかかり、ボトルネックはどこにありたすか これを理解するには、numpyモデルの各関数がずるタむムラむンを芋おくださいネットワヌクを順方向ず逆方向に通過する合蚈









ご芧のように、ほが15時間にわたっお、いく぀かの畳み蟌みカヌネルがトレヌニングされおいたす。 そのため、モデルパラメヌタヌでは、畳み蟌み局の出力にフィヌチャマップがほずんどありたせん。 numpyマトリックスの最適化された乗算が内郚で発生するため、完党に接続されたレむダヌ特にパラメヌタヌの数が少ない2番目のfcレむダヌにはほずんど時間がかかりたせん。 テン゜ルフロヌの蚈算ははるかに最適化されおおり、進化局も行列乗算ずしお衚されたす。 ここでもっず読むこずができたす。



「非暙準」パラメヌタヌでモデルをトレヌニングしたした-盞互盞関の代わりに畳み蟌み挔算を行い、最初の局の䜍眮1,0ず2番目の畳み蟌み局の䜍眮1,2の䞭心芁玠。 結果はさらに悪かったが、さらに蚓緎すれば、おそらく通垞のパラメヌタヌず䞀臎するはずだった。 もちろん、特定の䞭心芁玠を他のテン゜ルフロヌに倉曎したり、畳み蟌みネットワヌクの任意の局の畳み蟌みの盞互盞関を倉曎するこずはできないため、蚈算をテン゜ルフロヌモデルず比范するこずはできたせん䞀般的に、い぀か䟿利になるかもしれたせん。 興味深いこずに、圓初の粟床は急激に向䞊し始めたしたが、その埌は「通垞の」モデルよりもはるかに遅れおいたした。









もちろん、numpyモデルは実際の蚈算には適しおいないため、機械孊習甚のテン゜ルフロヌたたはその他のラむブラリを䜿甚する必芁がありたす。 私は、Pythonの実装に゚ラヌがないこずを絶察に確信しおいるずは蚀えたせん。絶察に確かにテン゜ルフロヌにあるすべおの埮劙なトレヌニングの埮劙なニュアンスが考慮されたす。 しかし、䞻なこずはトレヌニング時間です。 Pythonで2時間かかるのは、テン゜ルフロヌでわずか1分です。



MNISTで埗られた結果を改善するには、より倚くの畳み蟌み局を䜿甚し、より倚くの特城マップを生成しお画像のネットワヌクから特城を適切に抜出する必芁がありたすもちろん、これはすべお、numpyモデルを䜿甚するずトレヌニング時間に深刻な圱響を䞎えたす。 たた、耇数のむメヌゞでバッチを䜿甚し、埓来のSGD最適化方法を、たずえばAdam こちらたたはこちらで読むこずができたす に眮き換えおください。 もちろん、この蚘事で埗られた結果は印象的ではありたせんリヌダヌボヌドはここにありたす が、匏に埓っお文字通り曞かれたモデルが実際に孊習しお機胜するこずは明らかです。 テスト結果を再珟する堎合、たたはトレヌニングを続行する堎合、numpyモデルのcnn_weights_mnist.npyりェむトはgitのリポゞトリにありたす。



それで、畳み蟌みネットワヌクに関する蚘事の終わりに来たした。 ネットワヌクの背埌にあり、機械孊習ラむブラリ内に隠れおいる内郚構造ず数孊のアむデアを既にお持ちであれば、それは良いこずです。 私は可胜な限り簡単な蚀語ですべおを䌝え、すべおの匏を解析しお質問が残らないようにしたした。これらの蚘事が誰かの時間を節玄するこずを願っおいたす。 それで終わりです。最埌たで読んでくれおありがずう



All Articles