人工知性を作りたい

私が日々、挑戦したことや学んだことなどを紹介していく雑記ブログです。 (新しいAI技術HTM, 専門の音声信号処理, 趣味のアニメ等も書いてます。)

global navigation menu page top

NuPIC SP層の2次元入力と1次元入力におけるoutput(SDR)の違い!【Hierarchical Temporal Memoryのメモ】

f:id:hiro-htm877:20190719214000p:plain


 

 

numenta社が開発したnupicの機能を使う際のメモです。

 

本記事のテーマ

SP層のクラス生成から学習までの流れを用いて、2次元入力と1次元入力との違いを説明します。

 

基本的な内容は次のページに記載されています。

nupic.docs.numenta.org

 

1次元入力と2次元入力の違い【SP層】

まずは、SP層のクラスの紹介ページを見てみましょう!

クラスの実体は次のように宣言されます。

 

SPクラスの生成

class nupic.algorithms.spatial_pooler.SPatialPooler(inputDimensions=(3232)columnDimensions(6464)potentialRadius=16potentialPct=0.5globalInhibition=FalselocalAreaDensity=-1.0numActiveColumnsPerInhArea=10.0stimulusThreshold=0synPermInactiveDec=0.008synPermActiveInc=0.05synPermConnected=0.1minPctOverlapDutyCycle=0.001dutyCyclePeriod=1000boostStrength=0.0seed=-1, spVerbosity=0wrapAround=True)

 

この中で、入力に値するのはinputDimensionsです。また、inputDimensionsと同じ次元でcolumnDimensionsを設定しなければなりません。

 

ここで、またinputDimensionsとcolumnDimensionsの紹介をみてみます。

inputDimensionsとcolumnDimensions

 サイトをグーグル翻訳した結果を記載します。

・inputSImensions

iter)入力ベクトルの次元を表すシーケンス。フォーマットは(height、width、depth、...)です。各値は寸法のサイズを表します。100入力の1次元トポロジでは、100または(100、)を使用してください。10×5の2次元トポロジの場合は(10,5)を使用します。デフォルト(32, 32)

・columnDimensions

iter)領域内の列のサイズを表すシーケンス。フォーマットは(height、width、depth、...)です。各値は寸法のサイズを表します。2000列を含む1次元のトポロジでは、2000、または(2000、)を使用します。32×64×16の3次元トポロジの場合は、(32、64、16)を使用します。デフォルト(64, 64)

 

どちらとも3次元までの入力なら出来るようです。

では、実際に1次元入力と2次元入力のSP層による学習をしながら違いをみていきたいと思います。

 

SP層での学習(2次元入力)

まずは簡単にソースコードと出力結果から

ソースコード

if __name__ == "__main__":
    sp = SpatialPooler(inputDimensions=(5, 10),
                       columnDimensions=(2,3),
                       potentialRadius=10,
                       numActiveColumnsPerInhArea=4,
                       globalInhibition=True,
                       synPermActiveInc=0.000003,
                       potentialPct=0.5)
    inputList = []
    inputA = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
    inputB = [0, 1, 1, 1, 1, 1, 0, 0, 0, 0]
    inputC = [0, 0, 1, 1, 1, 1, 1, 0, 0, 0]
    inputD = [0, 0, 0, 1, 1, 1, 1, 1, 0, 0]
    inputE = [0, 0, 0, 0, 1, 1, 1, 1, 1, 0]

    inputList.append(np.array(inputA))
    inputList.append(np.array(inputB))
    inputList.append(np.array(inputC))
    inputList.append(np.array(inputD))
    inputList.append(np.array(inputE))
    inputList = np.array(inputList)
    print len(inputList)
    # print "----------------"*3
    # print "初期シナプス"
    for column in xrange(6):
        connected = np.zeros((50), dtype="int")
        print connected
        sp.getConnectedSynapses(column, connected)

    print "----------------"*3
    activeColumns = np.zeros((100,), dtype="int")
    print "初期activeColumns"
    sp.compute(inputList, learn=True, activeArray=activeColumns)
    print activeColumns

 

出力結果

・初期シナプスの出力結果

SP層は入力に対して、学習を行い、重要な部分(重なり)を取り出した疎なSDRを出力します。このSDRは脳科学的にはカラム(column)と呼ばれるセル(cell)という細胞のひと塊りみたいなものが、nupic上でもcolumnという変数で表現されています。よって、columnの数=SDR出力であり、今回は2次元のcolumnであるから合計2×3=6個のSDRで表現されることになります。

[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 0 0 0 0]
------------------------------------------------

 

・学習後のアクティブカラム(column)

SP 層の学習では入力配列と出力用のアクティブカラムが必要です。この時のアクティブカラムの長さは長くてもエラーは出ませんが、クラスの生成時に設定したcolumnDimensions分しか計算に含まれません。(今回は2×3=6)

[1 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

 

続いては1次元入力です。

SP層での学習(1次元入力)

ソースコード

if __name__ == "__main__":
    sp = SpatialPooler(inputDimensions=(10),
                       columnDimensions=(3),
                       potentialRadius=10,
                       numActiveColumnsPerInhArea=4,
                       globalInhibition=True,
                       synPermActiveInc=0.000003,
                       potentialPct=0.5)
    inputA = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
    inputB = [0, 1, 1, 1, 1, 1, 0, 0, 0, 0]
    inputC = [0, 0, 1, 1, 1, 1, 1, 0, 0, 0]
    inputD = [0, 0, 0, 1, 1, 1, 1, 1, 0, 0]
    inputE = [0, 0, 0, 0, 1, 1, 1, 1, 1, 0]

    inputA = np.array(inputA)
    # print "----------------"*3
    # print "初期シナプス"
    for column in xrange(3):
        connected = np.zeros((10), dtype="int")
        print connected
        sp.getConnectedSynapses(column, connected)
    print "----------------"*3
    activeColumns = np.zeros((100,), dtype="int")
    print "初期activeColumns"
    sp.compute(inputA, learn=True, activeArray=activeColumns)
    print activeColumns

 

出力結果

・初期シナプスの出力結果

1次元ではculomnDimensionsが3なので3つのカラムが用意されます。

[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]

 

・アクティブカラムの出力結果

SP 層の学習では入力配列と出力用のアクティブカラムが必要です。この時のアクティブカラムの長さは長くてもエラーは出ませんが、クラスの生成時に設定したcolumnDimensions分しか計算に含まれません。(今回は3)

 

[1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

 

 

まとめ

今回は「SP層の2次元入力と1次元入力におけるoutput(SDR)の違い!」というテーマで実験していきました。

その結果、2次元入力では"0"と複数の”1”で出力のSDRが表現されることが分かりました。一方、1次元入力では"0"と1つの"1"でしか表現されていないことが分かりました。

この違いをうまく使って今後も研究をしていこうと思います。

ちなみに使い方の例として、話者照合を考えてみますと、

・SP層のみを用いた話者照合

 入力音声が本人かそうでないかを調べればいいので1次元入力にして、SDR(出力)に変換した後、"0"と1つの"1"で表現されるため、本人かそうでないかを判断することができる。

・SP層とTM層を用いた話者照合

 まずは入力音声をSP層を用いて入力音声より少ない次元で表現されたSDRに変換することができる。そして小さい次元に変換さえれたSDRを用いてTM層で時系列の異常度を計算していくことで、少ない処理で時系列情報も用いた話者照合を行うことができる。

 

 

以上で「SP層の2次元入力と1次元入力におけるoutput(SDR)の違い!」の説明を終了します。

次はもう少し細かく理解するために、実際の計算における学習の様子も紹介していく予定です!