BrainScript を使用したレイヤーリファレンス
CNTKでは、多数の一般的な "レイヤー" が事前に定義されているため、重ね合わせた標準レイヤーで構成される単純なネットワークを簡単に作成できます。
レイヤーは、通常の BrainScript 関数と同様に使用できる関数オブジェクトですが、学習可能なパラメーターを保持し、構築パラメーターまたは属性を渡すために追加の {}
ペアを持ちます。
たとえば、レイヤーを使用する単純な 1-hidden レイヤー モデルのネットワークの説明を次に DenseLayer{}
示します。
h = DenseLayer {1024, activation=ReLU} (features)
p = DenseLayer {9000, activation=Softmax} (h)
これにより、クロスエントロピ条件に対するトレーニングに使用できます。
ce = CrossEntropy (labels, p)
ネットワークが直接操作を連結している場合 (多くの場合)、代わりに
Sequential()
表記:
myModel = Sequential (
DenseLayer {1024, activation=ReLU} :
DenseLayer {9000, activation=Softmax}
)
次のように呼び出します。
p = myModel (features)
モデルの例
次に、単語シーケンスを埋め込み、それを繰り返し LSTM で処理し、各単語を分類するスロット タガーを示します。
taggingModel = Sequential (
EmbeddingLayer {150} : # embed into a 150-dimensional vector
RecurrentLSTMLayer {300} : # forward LSTM
DenseLayer {labelDim} # word-wise classification
)
画像認識用の単純な畳み込みネットワークを次に示します。
convNet = Sequential (
# 3 layers of convolution and dimension reduction by pooling
ConvolutionalLayer {32, (5:5), pad=true, activation=ReLU} :
MaxPoolingLayer {(3:3), stride=(2:2)} :
ConvolutionalLayer {32, (5:5), pad=true, activation=ReLU} :
MaxPoolingLayer {(3:3), stride=(2:2)} :
ConvolutionalLayer {64, (5:5), pad=true, activation=ReLU} :
MaxPoolingLayer {(3:3), stride=(2:2)} :
# 2 dense layers for classification
DenseLayer {64, activation=ReLU} :
LinearLayer {10}
)
パラメーターの共有
1 つのレイヤーを変数に割り当てて複数の場所で使用すると、 パラメーターが共有されます。 あなたが言う場合
lay = DenseLayer {1024, activation=Sigmoid}
h1 = lay (x)
h2 = lay (h1) # same weights as `h1`
h1
両方h2
のケースで同じ関数とlay()
同じパラメーターを共有します。
上記の場合、これはおそらく望まれていたものではありませんので、注意してください。
上記の両方のlay()
呼び出しが異なるパラメーターを持つ場合は、2 つの個別のインスタンス (例: lay1 = DenseLayer{...}
.lay2 = DenseLayer{...}
では、なぜこの動作でしょうか。
レイヤーを使用すると、モデルのセクション間でパラメーターを共有できます。
たとえば、同じ処理チェーンと同じように 2 つの入力画像を処理しquery
、doc
結果として得られる隠しベクトルを比較する DSSM モデルを考えてみましょう。
imageToVec = Sequential (
ConvolutionalLayer {32, (5:5), pad = true, activation = ReLU} :
MaxPoolingLayer {(3:3), stride = (2:2)} :
ConvolutionalLayer {64, (5:5), pad = true, activation = ReLU} :
MaxPoolingLayer {(3:3), stride = (2:2)} :
DenseLayer {64, activation = ReLU} :
LinearLayer {10}
)
zDoc = imageToVec (doc)
zQuery = imageToVec (query) # same model as for zDoc
sim = CosDistance (zdoc, zQuery)
ここで imageToVec
、画像をフラット ベクターに変換するモデルの一部です。
imageToVec
は、複数の関数オブジェクト (例: 3 つのインスタンス ConvolutionalLayer{}
) を含む関数オブジェクトです。
imageToVec
は 1 回インスタンス化され、このインスタンスは含まれるすべての関数オブジェクトの学習可能なパラメーターを保持します。 どちらの呼び出し model()
もアプリケーションでこれらのパラメーターを共有し、それらのグラデーションは両方の呼び出しの合計になります。
最後に、上記の例query
doc
で同じ次元を持つ必要がある場合、それらは同じ関数オブジェクトを介して処理され、その関数オブジェクトの最初のレイヤーは両方query
の入力ディメンションとdoc
一致するように推論されることに注意してください。
ディメンションが異なる場合、このネットワークの形式が正しくありません。ディメンションの推論/検証はエラー メッセージで失敗します。
実装に関するメモ
多くのレイヤーは、基になるCNTKプリミティブを囲むラッパーであり、それぞれ必要な学習可能なパラメーターです。 たとえば、 ConvolutionalLayer{}
プリミティブを Convolution()
ラップします。
レイヤーを使用する利点は次のとおりです。
- レイヤーには、正しいディメンションの学習可能なパラメーターが含まれています
- レイヤーは構成可能です (cf.
Sequential()
DenseLayer{}、LinearLayer{}
完全に接続されたレイヤーを作成するファクトリ関数。
DenseLayer{}
は省略可能な非線形性で受け取ります。
DenseLayer {outDim, activation=Identity, init='glorotUniform', initValueScale=1, bias=true}
LinearLayer {outDim, init='glorotUniform', initValueScale=1, bias=true}
パラメーター
-
outDim
: このレイヤーの出力ディメンション -
activation
(のみ): アクティブ化関数として使用する関数をここに渡します(DenseLayer{}
例:activation=ReLU
-
init
('heNormal'
|'glorotUniform'
|...): 重みの初期化の種類。 初期化オプションの完全な一覧については、こちらを参照してください。 -
initValueScale
: 分散ランダム初期化にこの値を乗算します。 -
bias
: false の場合は、バイアス パラメーターを含めないでください
戻り値
目的の完全に接続されたレイヤーを実装する関数。 説明を参照してください。
説明
これらのファクトリ関数を使用して、完全に接続されたレイヤーを作成します。
アクティブ化関数を含める場合は使用 DenseLayer{}
します。それ以外の場合 LinearLayer{}
は使用します。
これらのファクトリ関数はそれぞれ、学習可能な重み行列と、学習可能なバイアスを bias=false
含む関数オブジェクトを作成します。 関数オブジェクトは、次のいずれかの数式を実装する関数のように使用できます。
DenseLayer{...} (v) = activation (W * v + b)
LinearLayer{...} (v) = W * v + b
ここで W
は次元 [outDim x (dimension of v)]
の重み行列で、 b
次元 [outdim]
の偏りであり、結果の値には指定された次元 (またはテンソル次元) outDim
があります。
Tensor のサポート
返された関数がテンソル ランク > 1 の入力 (2D 画像など) に適用される場合、 W
次元 [outDim x (first dimension of input) x (second dimension of input) x ...]
が設定されます。
一方、 outDim
テン (10:10)
ソル次元を指定するベクトルを使用できます。
その場合、 W
寸法 [outDim[0] x outDim[1] x ... x (dimension of input)]
を持ち b
、テンソル寸法を [outDim[0] x outDim[1] x ...]
持つことになります。
CNTKのマトリックス積は、これらの余分な出力または入力次元を、長いベクトルにフラット化されたかのように解釈します。
この詳細については、次のドキュメントを参照してください。 Times()
例:
h = DenseLayer {1024, activation=Sigmoid) (v)
または、次の方法があります。
Layer = DenseLayer {1024, activation=Sigmoid)
h = Layer (v)
ConvolutionalLayer{}
オプションの非線形性を持つ畳み込みレイヤーを作成します。
ConvolutionalLayer {numOutputChannels, filterShape,
activation = Identity,
init = 'glorotUniform', initValueScale = 1,
stride = 1, pad = false, lowerPad = 0, upperPad = 0,
bias = true}
パラメーター
-
numOutputChannels
: 出力チャネルの数 (フィルターの数) -
filterShape
: フィルターの 空間 範囲 ((5:5)
2D フィルターなど)。 入力チャネル ディメンションはここに含 まれません 。 -
activation
: オプションの非線形性 (例:activation=ReLU
-
init
('heNormal'
|'glorotUniform'
|...): 重みのランダムな初期化の種類。 ランダム初期化オプションの完全な一覧については、こちらを参照してください。 -
initValueScale
: 分散ランダム初期化にこの値を乗算します。 -
stride
: 入力の上にフィルターをスライドさせるとインクリメントされます。 例:(2:2)
寸法を 2 つ減らす -
pad
: 設定されていない場合 (既定値)、フィルターは入力の "有効" 領域にシフトされます。つまり、領域外の値は使用されません。 一方、設定されている場合pad
、フィルターはすべての入力位置に適用され、有効な領域の外側の値は 0 と見なされます。 -
lowerPad
、upperPad
: パディングに異なる余白を明示的に指定します。 フィルターは、(実質的に) ゼロで拡張された有効な領域にシフトされます。 たとえば、lowerPad=(1:2)
0 の列と 0 の 2 行が追加されます。 出力のディメンションは、それに応じて拡張されます。 -
bias
: false の場合は、バイアス パラメーターを含めないでください
戻り値
目的の完全に接続されたレイヤーを実装する関数。 説明を参照してください。
説明
これらのファクトリ関数を使用して、畳み込みレイヤーを作成します。
結果のレイヤーは、N 次元テンソルに畳み込み演算を適用します。
呼び出し元は、フィルターの空間拡張を指定します。
特定の空間範囲 (たとえば (5:5)
) のフィルターのセットは、入力のすべての場所 (サイズの大きい [640 x 480]
画像など) と関連付けられます。
パディングが有効pad
() でストライドが 1 であると仮定すると、同じディメンション ([640 x 480]
) の出力領域が生成されます。
通常、多くのフィルターが同時に適用されます。
numOutputChannels
は数値を指定するため、入力位置ごとにベクトル numOutputChannels
全体が生成されます。
上の例では、64 に設定 numOutputChannels
すると、サイズの大きさ [640 x 480 x 64]
のテンソルになります。
最後の軸は チャネル寸法と呼ばれます。
チャネル ディメンションを持つ入力に畳み込みを適用すると、各フィルターも入力のチャネル ディメンションのベクトルで構成されます。
たとえば、指定された空間フィルター範囲 (5:5)
を持つ畳み込みを -size カラー イメージに [640 x 480 x 3]
適用する場合、各フィルターはテンソルになります [5 x 5 x 3]
。
一緒に積み重ねられたすべての numOutputChannels
フィルターは カーネルと呼ばれます。
この例では、カーネルシェイプは [5 x 5 x 3 x 64]
.
次に、さまざまな寸法と図形の関係をまとめます。
input shape : [ (spatial dims) x (#input channels) ]
spatial extent : [ (filterShape) ]
output shape : [ (spatial dims) x x numOutputChannels ]
kernel shape : [ (filterShape) x (#input channels) x numOutputChannels ]
この例では次のようになります。
input shape : [ 640 x 480 x 3 ]
spatial extent : [ 5 x 5 ]
output shape : [ 640 x 480 x x numOutputChannels ]
kernel shape : [ 5 x 5 x 3 x numOutputChannels ]
パディング
パディングが有効になっていない場合、出力領域は、フィルター範囲全体を適用できない境界の場所によって減少します。 たとえば、埋め込みなしでイメージに -extent フィルターを適用 (5:5)
すると、ピクセルの最も外側の 2 行と列がフィルターの範囲外に適用されます。
したがって、 ConvolutionalLayer{}
それに応じて寸法が減少します。
[640 x 480]
埋め込みなしでフィルターが(5:5)
組み込まれたイメージでは、サイズの[636 x 476]
大きな出力領域が残ります。
進歩
パラメーターは stride
、フィルターの増分を指定します。
ストライド値が 1 より大きい場合、出力領域のサブサンプリングが行われます。
たとえば、ストライドで画像を[640 x 480]
フィルター処理すると、[320 x 240]
パディングを含むサイズの(2:2)
領域が生成され[318 x 238]
、パディングはありません。
メモ
このレイヤーは、プリミティブを Convolution()
囲むラッパーです。
ログの検証セクションに示すように、フィルター カーネル パラメーターの名前は終了 .W
します。
現在、ディメンションは上記のように[ (filterShape) x (#input channels) x numOutputChannels ]
表示されませんが、代わりに [numOutputChannels x ((製品 over filter shape) * (#input チャネル))]'。
例:
c = ConvolutionalLayer {64, (3:3), pad = true, stride = (1:1), bias=false} (x)
DeconvLayer{}
デコンボリューション レイヤーを作成します。
DeconvLayer {numOutputChannels,
filterShape, numInputChannels,
bias = true,
activation = (x=>x),
init = 'glorotUniform',
initValueScale = 0.001,
initBias = 0,
stride = 1, autoPadding = false,
lowerPad = 0, upperPad = 0,
maxTempMemSizeInSamples = 0}
パラメーター
-
numOutputChannels
: 出力チャネルの数 (フィルターの数) -
filterShape
: 2D フィルターの場合など(5:5)
、フィルターの空間範囲。 入力チャネル ディメンションはここに含 まれません 。 -
numInputChannels
: 入力チャネルの数 (入力ボリュームのフィルターの数) -
bias
: false の場合は、バイアス パラメーターを含めないでください -
activation
: 省略可能な非線形性 (例:activation=ReLU
-
init
('heNormal'
|'glorotUniform'
|...): 重みのランダムな初期化の種類。 ランダム初期化オプションの完全な一覧については、こちらを参照してください。 -
initValueScale
: 分散ランダム初期化は、この値に乗算されます。 -
initBias
: バイアスの初期値 -
stride
: 入力の上にフィルターをスライドさせるとインクリメントされます。 たとえば(2:2)
、寸法を 2 ずつ減らす -
autoPadding
: (既定値) に設定されていない場合、フィルターは入力の "有効" 領域にシフトされます。つまり、領域外の値は使用されません。 一方、設定されている場合autoPadding
、フィルターはすべての入力位置に適用され、有効な領域外の値は 0 と見なされます。 -
lowerPad
、upperPad
: 出力ボリュームのパディングに異なる余白を明示的に指定します。 つまり、対応する畳み込みレイヤーの入力に使用された余白を明示的に指定します。 同じテンソル次元を実現するには、畳み込み層と対応して設定することが重要です。
戻り値
必要な完全に接続されたレイヤーを実装する関数。 説明を参照してください。
説明
これらのファクトリ関数を使用して、デコンボリューション レイヤーを作成します。
結果のレイヤーは、N 次元テンソルにデコンボリューション演算を適用します。
このレイヤーは、プリミティブを Convolution()
囲むラッパーです deconv=true
。
デコンボリューションの一般的なユースケースの 1 つは、画像の再構築です (例については、こちらを参照してください)。 畳み込みでは、入力 2D の受け取りフィールド領域を受け取り、2D フィルターとの相関関係を計算します。デコンボリューションはピクセルを受け取り、2D 領域に分散します。
画像 p(...)、ピクセル位置 (x、y) と、次のコンテンツを含む中央の [3 x 3] フィルター (現時点では特徴マップ深度ディメンションなし、つまり 1 つのチャネル) を検討してください。
[ . . c
a b .
. . . ]
ここで、b と c はフィルター '.' の重み付けです。 0 の重みに対応します。 Convolution() は、出力ピクセル q(x, y) を位置 (x, y) で次のように計算します。
q(x,y) = b * p(x,y) + a * p(x-1,y) + c * p(x+1,y-1)
デコンボリューションはピクセル q(x,y) を受け取り、それらを周りの領域 (x,y) に分散します。 同じフィルターを使用した場合、出力 r(x,y) に対して次の貢献が行われます。
r(x,y) += b * q(x,y)
r(x-1,y) += a * q(x,y)
r(x+1,y-1) += c * q(x,y)
平面上のすべての x と y に同じことが当てはまることを知って、r(x,y) に対してこれを表現できます。
r(x,y) += b * q(x,y)
r(x,y) += a * q(x+1,y)
r(x,y) += c * q(x-1,y+1)
または合計で、
r(x,y) = b * q(x,y) + a * q(x+1,y) + c * q(x-1,y+1)
フィルターが両方の軸に沿ってミラー化されている点を除き、これは上記の畳み込みと同じ形式です。
次に、このミックスに機能マップを導入します。 これは簡単です。入力深度から出力深度に進む代わりに、もう一方の方向に進みます。
要約すると、畳み込み (W、x) == デコンボリューション (W'、x)、where
W : [W x H x C x K]
および
W’ = W
その値は次のように並べ替えられます。 [(W mirrored) x (H mirrored) x K x C]
つまり、Deconvolution() が暗黙的に行う内容は次のとおりです。
- 2 つの奥行き寸法を交換する (トランスポーズ)
- 空間ディメンション (データの順序を逆にする)
- これらの畳み込み()
例:
deconv_A = DeconvLayer {inputDim, (5:5), cMap1, lowerPad=(2:2:0), upperPad=(2:2:0)}(unpool_A)
詳細な例については、 デコンボリューションとアンプールを使用した画像自動エンコーダー に関するページを参照し、手順を説明します。
MaxPoolingLayer{}、AveragePoolingLayer{}
ファクトリ関数を使用して、最大または平均プーリング レイヤーを作成します。
MaxPoolingLayer {poolShape, stride = 1, pad = false, lowerPad = 0, upperPad = 0}
AveragePoolingLayer {poolShape, stride = 1, pad = false, lowerPad = 0, upperPad = 0} =
パラメーター
-
poolShape
: プールする領域の形状(例:(2:2)
-
stride
: 入力の上にプールをスライドさせるとインクリメントされます。 たとえば(2:2)
、寸法を 2 ずつ減らす -
pad
: (既定値) に設定されていない場合、プールは入力の "有効" 領域にシフトされます。つまり、領域外の値は使用されません。 一方、設定されている場合pad
、プールはすべての入力位置に適用され、有効な領域外の値は 0 と見なされます。 平均プールの場合、平均のカウントには埋め込み値は含まれません。 -
lowerPad
、upperPad
: パディングに異なる余白を明示的に指定します。 フィルターは、(実質的に) ゼロで拡張された有効なリージョンにシフトされます。 たとえば、lowerPad=(1:2)
ゼロの列と 0 の 2 行を追加します。 それに応じて出力の次元が拡張されます。
戻り値
目的のプール レイヤーを実装する関数。 説明を参照してください。
説明
このファクトリ関数を使用して、プール操作を作成します。 プール領域内の値の最大値を計算しAveragePoolingLayer{}
、その平均値を取得するために使用MaxPoolingLayer{}
します。
プール操作は、入力リージョンの場所に "プール ウィンドウ" をスライドさせ、それぞれのプール領域の値の最大値または平均を計算します。
この操作は、スライディング ウィンドウに適用される操作が異なる性質を持つ点を除いて、畳み込みと構造的に非常によく似ています。
入力ディメンション、パディング、ストライドに関するすべての考慮事項は同じです。詳細については ConvolutionalLayer{}
、参照してください。
例:
p = MaxPoolingLayer {(3:3), stride=(2:2)} (c)
MaxUnpoolingLayer{}
max-unooling レイヤーを作成します。
MaxUnpoolingLayer {poolShape,
stride = 1, pad = false,
lowerPad = 0, upperPad = 0}
パラメーター
-
poolShape
: プール解除する領域の形状 ( 出力 領域サイズなど)。(2:2)
-
stride
: プールを出力の上にスライドさせるとインクリメントされます。 たとえば、ディメンションを 2 ずつ増やす場合などです。(2:2)
-
pad
: (既定値) に設定されていない場合、プールは出力の "有効" 領域にシフトされます。つまり、領域外の値は使用されません。 -
lowerPad
、upperPad
: パディングに異なる余白を明示的に指定します。 フィルターでは、(実質的に) 拡張された有効な出力領域が想定されます。
戻り値
目的のプール解除レイヤーを実装する関数。 説明を参照してください。
説明
このファクトリ関数を使用して、プール解除操作を作成します。
プール解除操作は、プール操作の逆です。 それには、対応するプーリング レイヤーの出力と、 p1
対応するプール レイヤー r1
の入力という 2 つの入力も必要です。 入力の p1
場所に対して "逆プール ウィンドウ" をスライドさせ、対応するプール操作の最大値を持つ出力領域のその位置に値を投影します。つまり r1
、 CNTKにはスイッチ変数と呼ばれる変数が格納されないため、CNTKで 2 番目の入力r1
が必要です (詳細については、こちらを参照してください)。
例:
unpool_A = MaxUnpoolingLayer {(2:2), stride=(2:2)}(deconv_B, relu_A)
詳細な例については、 デコンボリューションと Unpooling を使用した画像自動エンコーダー に関するページを参照し、手順を説明します。
EmbeddingLayer{}
EmbeddingLayer {outDim,
init='glorotUniform', initValueScale=1,
embeddingPath = '', transpose = false}
パラメーター
-
outDim
: 目的の埋め込みベクトルの次元 -
init
('heNormal'
|'glorotUniform'
|...): 重みの初期化の種類。 初期化オプションの完全な一覧については、こちらを参照してください。 -
initValueScale
: 分散ランダム初期化にこの値を乗算します。 -
embeddingPath
: 指定された場合、埋め込みは学習されず、ファイルから読み込まれ、トレーニング中にそれ以上更新されません -
transpose
: 入れ替えされた形式で格納されている埋め込みを読み込むことができます
戻り値
埋め込みレイヤーを実装する関数。 説明を参照してください。
説明
「埋め込み」とは、密な連続ベクトルによって単語またはその他の不連続項目を表すことを指します。 このレイヤーは、入力がワンホット形式であることを前提としています。 たとえば、ボキャブラリ サイズが 10,000 の場合、各入力ベクトルは次元 10,000 を持つと予想され、1 を含む 1 つの位置を除くゼロで構成されます。 その場所のインデックスは、それが表す単語または項目のインデックスです。
CNTKでは、対応する埋め込みベクトルがマトリックスの列として格納されます。 そのため、入力単語を埋め込みへのマッピングはマトリックス積として実装されます。 これを非常に効率的にするには、入力ベクトルがスパース形式で格納されていることが重要です。
楽しい事実:埋め込み行列のグラデーションは、ミニバッチで見られる単語に対してゼロ以外のグラデーションベクトルの形式を持っています。 数十または数十万の現実的なボキャブラリの場合、列の大部分は 0 になるため、CNTK実装には、"列スパース" 形式でグラデーションを表す特定の最適化があります。
既知の問題: 上記の列スパース グラデーション形式は、現在、 1 ビット SGD 並列化手法ではサポートされていません。 代わりに ブロック モメンタム 手法を使用してください。
例
87636 のボキャブラリの単語を 300 次元ベクトルとして表す学習された埋め込み:
input = Input{87636, sparse=true} # word sequence, as one-hot vector, sparse format
embEn = EmbeddingLayer{300} (input) # embed word as a 300-dimensional continuous vector
さらに sparse=true
、入力を構成ブロックにスパースとして宣言する reader
必要もあります。
スパース テキスト入力を読み取る例を次に CNTKTextFormatReader
示します。
reader = {
readerType = "CNTKTextFormatReader"
file = "en2fr.txt"
randomize = true
input = {
input = { alias = "E" ; dim = 87636 ; format = "sparse" }
labels = { alias = "F" ; dim = 98624 ; format = "sparse" }
}
}
代わりに、埋め込みベクトルが既に存在し、ファイルから読み込まれる必要がある場合は、次のようになります。
input = Input{87636, sparse=true} # word sequence, as one-hot vector, sparse format
embEn = EmbeddingLayer{300, embeddingPath="embedding-en.txt", transpose=true} (w) # embedding from disk
ここで、ファイル "embedding-en.txt"
は 87,636 行のテキスト行で構成され、それぞれ 300 個のスペース区切り番号で構成されます。
このファイルは列ではなく行として埋め込みを保存するため、 transpose=true
行列をその場で入れ替えます。
RecurrentLSTMLayer{}、RecurrentLSTMLayerStack{}
単一層または多層の再帰 LSTM を作成するためのファクトリ関数。
RecurrentLSTMLayer {outDim, cellShape = None,
goBackwards = false,
usePeepholes = false,
init = 'glorotUniform', initValueScale = 1,
enableSelfStabilization = false,
allowOptimizedEngine = false}
RecurrentLSTMLayerStack {layerDims,
cellShapes = None,
usePeepholes = false,
init = 'glorotUniform', initValueScale = 1,
enableSelfStabilization = false,
allowOptimizedEngine = false}
パラメーター
-
outDim
(RecurrentLSTMLayer{}
): ネットワークの出力のディメンション。 ランク>1 のテンソルを示すには、ベクトルを指定できます(例:(40:2)
-
layerDims
(RecurrentLSTMLayerStack{}
): ネットワークの内部レイヤーと出力の次元の配列 -
cellShape
( (RecurrentLSTMLayer{}
省略可能): LSTM のセルの寸法。 通常、これは次とoutDim
同じです。 別の値を指定すると、追加の線形投影が挿入され、セルディメンションから出力に変換されます。 -
cellShapes
( (RecurrentLSTMLayerStack{}
省略可能): プロジェクションを示すなどのcellShape
値のRecurrentLSTMLayer()
配列 -
goBackwards
(省略可能): true の場合、繰り返しは後方に実行されます -
usePeepholes
(省略可能): true の場合は、LSTM でピープホール接続を使用します -
init
('heNormal'
|'glorotUniform'
|...): 重みの初期化の種類。 初期化オプションの完全な一覧については、こちらを参照してください。 -
initValueScale
: 分散ランダム初期化にこの値を乗算します。 -
enableSelfStabilization
(省略可能): true の場合は、次のような "スタビライザー" 操作を挿入します。StabilizerLayer{}
-
allowOptimizedEngine
(省略可能、既定の false): true の場合は、可能な場合は cuDNN の最適化された RNN エンジンを使用します
戻り値
繰り返し LSTM をその入力シーケンスに適用/適用する目的のレイヤーを実装する関数。 このレイヤー (スタック) は、入力シーケンスを同じ長さの非表示状態のシーケンスにマップします。
説明
これにより、一連の入力に適用される繰り返し LSTM が、1 つのレイヤーと多層スタックの 2 つのバリアントで実装されます。 この操作では、可変長入力が自動的に処理されます。 非表示状態とセルの初期値は 0 です。
このレイヤーを入力シーケンスに適用すると、(スタックの最上位) 反復 LSTM の非表示状態のシーケンスが返されます (LSTM のメモリ セルの値は返されません)。
返されるシーケンスの長さは、入力と同じです。
シーケンス分類やシーケンス間のシナリオのように、最後の状態のみが必要な場合は、最後の項目の非表示状態のみを抽出するために使用 BS.Sequences.Last()
します。
(後方の繰り返しでは、. BS.Sequences.First()
)
双方向モデルRecurrentLSTMLayer()
を作成するには、2 つのレイヤー (1 つのレイヤーと goBackwards=true
Splice()
2 つの出力) を一緒に使用します。
RecurrentLSTMLayerStack()
現在、双方向モデルはサポートされていません。複数の RecurrentLSTMLayer()/Splice()
コンボを使用して手動で構築する必要があります。
CuDNN5 RNN エンジンの使用
この関数は、可能であれば、CuDNN5 の最適化された RNN エンジンを自動的に使用します。つまり、可能な場合は
- 指定されたモデルは、CuDNN5 の関数によって実装できるモデルです
- プロジェクションなし (パラメーターなし
cellShape
) - ピープホール接続なし
- 自己安定化なし
- 後方に進まない
- の場合
RecurrentLSTMLayerStack{}
、すべてのレイヤーディメンションの値は同じです
- プロジェクションなし (パラメーターなし
allowOptimizedEngine=true
具体的には、CNTKを有効にするallowOptimizedEngine=true
必要があります。
これは、CuDNN5 RNN が GPU を必要とするCNTKプリミティブ操作として実装されているためです。
ただし、実際のシステムの多くはトレーニングに GPU を使用しますが、デプロイでは CPU 専用サーバーを使用します。
ここでは CuDNN5 RNN は適していません。
(理論的には、トレーニングに CuDNN5 RNN を使用し、デプロイ用に編集 操作 に置き換え、BrainScript で同等の明示的な LSTM 実装を使用できます)。
メモ
この 2 つのレイヤーバリアントがプリミティブのラッパーであるOptimizedRNNStack()
場合allowOptimizedEngine=true
。
例
繰り返しを通じて単語シーケンスを実行し、LSTM の 最後 の隠し状態を softmax 分類子に渡す単純なテキスト分類子は、次の形式になります。
w = Input{...} # word sequence (one-hot vectors)
e = EmbeddingLayer {150} (w) # embed as a 150-dimensional dense vector
h = RecurrentLSTMLayer {300} (e) # left-to-right LSTM with hidden and cell dim 300
t = BS.Sequences.Last (h) # extract last hidden state
z = DenseLayer {10000, activation=Softmax} (t) # softmax classifier
上記の例を、CuDNN5 RNN エンジンを使用する 3 層スタックに変更するには、次の行を変更します。
h = RecurrentLSTMLayerStack {(300:300:300), allowOptimizedEngine=true} (e)
双方向の 1 層 LSTM を作成するには (たとえば、上と比較して隠しディメンションの半分を使用する場合)、次の値を使用します。
hFwd = RecurrentLSTMLayer {150} (e)
hBwd = RecurrentLSTMLayer {150, goBackwards=true} (e)
h = Splice (hFwd:hBwd)
DelayLayer{}
入力を遅らせるレイヤーを作成するファクトリ関数。
DelayLayer {T=1, defaultHiddenActivation=0}
パラメーター
-
T
: 遅延する時間ステップの数。 将来の値にアクセスするには、負の値を使用します -
defaultHiddenActivation
: 境界の遅延フレームに使用する値
戻り値
目的の遅延操作を実装する関数。
説明
この操作により、入力シーケンスがステップごとに T
遅延されます (既定値は 1)。
これは、たとえば、単語シーケンスを重複する単語の 3 重のシーケンスに変換する場合に便利です。
次のように、入力シーケンス "a b c b" をワンホット ベクターのシーケンスとしてエンコードする必要があります。
1 0 0 0
0 1 0 1
0 0 1 0
ここでは、すべての列は 1 つのホット ベクターであり、単語に対応します。
DelayLayer{T=1}
この入力に適用すると、次のシーケンスが生成されます。
0 1 0 0
0 0 1 0
0 0 0 1
すべてのトークンが 1 ずつ遅延し、最初の位置が 0 ベクトルとして入力されます。
同様に、(負の遅延) を使用すると DelayLayer{T=-1}
、将来の値にアクセスし、右側からゼロを埋め込みます。
0 0 0 0
1 0 1 0
0 1 0 0
メモ
このレイヤーは、プリミティブのPastValue()
FutureValue()
ラッパーです。
例
次に、3 つの近隣ワードをトリグラム ベクトルにスタックする方法を示します。
x = ... # input value, e.g. a N-dimensional one-hot vector
xp = DelayLayer{} (x) # previous value
xn = DelayLayer{T-1} (x) # next value (negative delay)
tg = Splice (xp : x : xn) # concatenate all into a 3N-dimensional three-hot vector
BatchNormalizationLayer{}、LayerNormalizationLayer{}、StabilizerLayer{}
バッチ正規化、レイヤー正規化、自己安定化のためのレイヤーを作成するファクトリ関数。
BatchNormalizationLayer {spatialRank = 0,
normalizationTimeConstant = 5000,
initialScale = 1, epsilon = 0.00001, useCntkEngine = true}
LayerNormalizationLayer {initialScale = 1, initialBias = 0}
StabilizerLayer{}
パラメーター
BatchNormalizationLayer
:
-
spatialRank
: 正規化パラメーターは、最初spatialRank
のディメンションにプールされます。 現在使用できる値は、0 (プーリングなし) と 2 (イメージのすべてのピクセル位置でのプーリング) です。 -
normalizationTimeConstant
(既定値 5000): 推論で使用する平均/分散統計を計算するために使用される、一次ローパス フィルターのサンプルの時間定数 -
initialScale
: スケール パラメーターの初期値 -
epsilon
: 逆数を計算するときに分散推定値に加算される小さな値 -
useCntkEngine
: true の場合は、CNTKのネイティブ実装を使用します。 false の場合は、cuDNN の実装 (GPU のみ) を使用します。
LayerNormalizationLayer
:
-
initialScale
: スケール パラメーターの初期値 -
initialBias
: バイアスパラメータの初期値
戻り値
正規化操作を実行するレイヤーを実装する関数。
説明
BatchNormalizationLayer{}
では、内部 共変量シフト (Sergey Ioffe、Christian Szegedy) を減らすことによるディープ ネットワーク トレーニングの高速化に関するペーパーバッチ正規化で説明されている手法が実装されています。
すべてのミニバッチの入力をミニバッチの平均/分散で正規化し、学習したスケーリング 係数とバイアスを使用して正規化を解除します。
推論では、ミニバッチ平均/分散を使用する代わりに、バッチ正規化では長期的な実行平均/var 推定値が使用されます。
この推定値は、ローパス フィルタリング ミニバッチ統計によってトレーニング中に計算されます。
ローパス フィルターの時間定数は、パラメーターによって normalizationTimeConstant
変更できます。
既定値 (5000) から開始することをお勧めしますが、通常は数千から数万の順序で他の値を試してください。
LayerNormalizationLayer{}
はレイヤー正規化 (Jimmy Lei Ba、Jamie Ryan Kiros、Geoffrey E. Hinton) を実装します。
各入力サンプルを正規化し、サンプルのすべての要素の平均を減算し、サンプルのすべての要素の標準偏差で除算します。
StabilizerLayer{}
は、 自己安定化ディープ ニューラル ネットワーク (P. Ghahremani、J. Droppo) ごとに自己安定化機能を実装します。
この単純で効果的な手法は、その入力に学習可能なスカラーを乗算します (ただし、レイヤー正規化とは異なり、最初に入力を正規化したり、平均を減算したりすることはありません)。
線形スカラー beta
または指数 Exp (beta)
関数を提案する元の論文と比較して、2番目の著者の提案に従ってシャープ化されたソフトプラス演算を使用すると有益であり、指数からの負の値と不安定性の両方を回避できることがわかりました。
メモ
BatchNormalizationLayer{}
はプリミティブの BatchNormalization()
ラッパーです。
LayerNormalizationLayer{}
は StabilizerLayer{}
BrainScript で直接表現されます。
例
バッチ正規化を使用した畳み込みネットワークの一般的なレイヤー:
MyLayer (x, depth, initValueScale) =
{
c = ConvolutionalLayer {depth, (5:5), pad=true, initValueScale=initValueScale} (x)
b = BatchNormalizationLayer {spatialRank = 2} (c) #####
r = ReLU (b)
p = MaxPoolingLayer {(3:3), stride = (2:2)} (r)
}.p
FeatureMVNLayer{}
フィーチャ入力を平均値と標準偏差で正規化するレイヤーを作成するファクトリ関数。
FeatureMVNLayer{}
パラメーター
空の引数リスト {}
です。
戻り値
正規化操作を実行するレイヤーを実装する関数。
説明
このレイヤーは、バイアスと分散によってニューラル ネットワークへの入力を正規化します。 これらの値は、トレーニング データを通じて完全なパスを実行して事前に推定され、保存および凍結されます。 これは自動的に行われます。
このレイヤーのパラメーターはメイン トレーニングの前に別のパスで事前計算されるため、次のように Input{}
宣言された変数にのみ適用できます。
例
これは、音声の音響モデリングのためのニューラル ネットワークの一般的な始まりです。
features = Input{40} # e.g. speech features
featNorm = FeatureMVNLayer{} (features)
h = DenseLayer{2048} (featNorm)
...