numenta社が開発したnupicの機能を使う際のメモです。
本記事のテーマ
SP層のクラス生成から学習までの流れを用いて、2次元入力と1次元入力との違いを説明します。
基本的な内容は次のページに記載されています。
1次元入力と2次元入力の違い【SP層】
まずは、SP層のクラスの紹介ページを見てみましょう!
クラスの実体は次のように宣言されます。
SPクラスの生成
class nupic.algorithms.sp
atial_pooler.SP
atialPooler
(inputDimensions=(32, 32), columnDimensions(64, 64), potentialRadius=16, potentialPct=0.5, globalInhibition=False, localAreaDensity=-1.0, numActiveColumnsPerInhArea=10.0, stimulusThreshold=0, synPermInactiveDec=0.008, synPermActiveInc=0.05, synPermConnected=0.1, minPctOverlapDutyCycle=0.001, dutyCyclePeriod=1000, boostStrength=0.0, seed=-1, spVerbosity=0, wrapAround=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)の違い!」の説明を終了します。
次はもう少し細かく理解するために、実際の計算における学習の様子も紹介していく予定です!