BrainScript を使用したモデル編集
(注: 以前のバージョンの CNTK では、この目的で "MEL" (モデル編集言語) が使用されています。 私たちはまだ例を変換中です。 MEL に関するドキュメントについては、こちらの
CNTK を使用すると、モデルをファクトの後で編集できます。 これを行うには、変更を適用して既存のモデルを複製 (一部) しながら新しいモデルを作成します。 このため、CNTK には次の 3 つの基本的な関数が用意されています。
- 既存のモデルを読み込む
BS.Network.Load()
- 再利用のために既存のモデルのセクションを抽出する
BS.Network.CloneFunction()
- ノードごとの変更が適用されたモデルを複製する
BS.Network.Edit()
編集操作は別の手順ではありません。 むしろ、変更されたモデルを処理するコマンドでは、モデルを読み込む modelPath
ではなく、モデルを内部に読み込み、読み込まれたモデルからその場で新しいモデルを構築する BrainScriptNetworkBuilder
セクションが指定されます。
例: 差別的な事前トレーニング
差別的事前トレーニングは、一連の浅いネットワークをトレーニングすることによって深いネットワークを作成する手法です。 1 非表示レイヤー ネットワークから開始し、部分的な収束にトレーニングしてから、出力レイヤーを削除し、新しい非表示レイヤーを追加して、新しい出力レイヤーを追加します。 目的の非表示レイヤーの数に達するまで繰り返します。
非常に単純な開始モデルを想定しましょう
BrainScriptNetworkBuilder = [
N = 40; M = 9000; H = 512
W1 = Parameter (H, N); b1 = Parameter (H)
Wout = Parameter (M, H); bout = Parameter (M)
x = Input (N, tag=‘feature’) ; labels = Input (M, tag=‘labels’)
h1 = Sigmoid (W1 * x + b1)
z = Wout * h1 + bout
ce = CrossEntropyWithSoftmax (labels, z, tag=‘criterion’)
]
このモデルをトレーニングし、"model.1.dnn" の下に保存します。 次に、2 つの非表示レイヤーを使用してモデルをトレーニングします。ここで、最初の非表示レイヤーは、上記でトレーニングした値から初期化されます。 これを行うには、新しいモデルを作成する別のトレーニング アクションを作成しますが、前のモデルの一部を次のように再利用します。
BrainScriptNetworkBuilder = {
# STEP 1: load 1-hidden-layer model
inModel = BS.Network.Load ("model.1.dnn")
# get its h1 variable --and also recover its dimension
h1 = inModel.h1
H = h1.dim
# also recover the number of output classes
M = inModel.z.dim
# STEP 2: create the rest of the extended network as usual
W2 = Parameter (H, H); b2 = Parameter (H)
Wout = Parameter (M, H); bout = Parameter (M)
h2 = Sigmoid (W2 * h1 + b2)
z = Wout * h2 + bout
ce = CrossEntropyWithSoftmax (labels, z, tag=‘criterion’)
}
まず、手順 1 では、Load()
を使用して、BrainScript 変数にネットワークを読み込みます。 ネットワークは BrainScript レコードのように動作し、すべての最上位ノード (ノード名に .
または [
を含まないすべてのノード) にレコード構文を使用してアクセスできます。 新しいネットワークは、読み込まれたネットワーク内の任意のノードを参照できます。 この例では、読み込まれたネットワークには、最初の非表示レイヤーの出力であるノード h1
と、出力クラスの正規化されていないログ事後確率 (Softmax 関数への入力) であるノード z
が含まれています。 どちらのノードも、inModel.h1
や inModel.z
などのドット構文を使用して BrainScript からアクセスできます。
定数はモデルに格納されないため、モデルから N
も M
も使用できません。 ただし、読み込まれたモデルから再構築することは可能です。 そのために、計算ノードも BrainScript レコードと同様に動作し、dim
プロパティを公開します。
次に、手順 2 では、通常の BrainScript を使用して、新しいネットワークの残りの部分を構築します。 この新しいセクションでは、他のノードを使用する場合と同様に、入力モデルから h1
ノードを入力として使用するだけです。 入力ネットワークからノードを参照すると、このノードが依存するすべてのノードが、新しく作成されたネットワークの一部にも自動的に作成されます。 たとえば、入力ノード x
は自動的に新しいネットワークの一部になります。
また、出力レイヤーは新たに構築されることにも注意してください。 これにより、そのモデル パラメーターが新しく作成されます。 (これを行わず、代わりに既存のパラメーターを再利用するには、inModel.Wout
を使用できますが、この特定の例ではネットワーク設計の観点からは意味がありません)。
例: 事前トレーニング済みモデルの使用
事前トレーニング済みのモデル (ファイル "./featext.dnn"
から) を特徴抽出器として使用する例を次に示します。
BrainScriptNetworkBuilder = {
# STEP 1: load existing model
featExtNetwork = BS.Network.Load ("./featext.dnn")
# STEP 2: extract a read-only section that is the feature extractor function
featExt = BS.Network.CloneFunction (
featExtNetwork.input, # input node that AE model read data from
featExtNetwork.feat, # output node in AE model that holds the desired features
parameters="constant") # says to freeze that part of the network
# STEP 3: define the part of your network that uses the feature extractor
# from the loaded model, which above we isolated into featExt().
# featExt() can be used like any old BrainScript function.
input = Input (...)
features = featExt (input) # this will instantiate a clone of the above network
# STEP 4: and add the remaining bits of the network in BrainScript, e.g.
h = Sigmoid (W_hid * features + b_hid) # whatever your hidden layer looks like
z = W_out * h + b_out
ce = CrossEntropyWithSoftmax (labels, z)
criterionNodes = (ce)
}
手順 1 では、Load()
を使用して、BrainScript 変数にネットワークを読み込みます。
手順 2 では、CloneFunction()
を使用して、読み込まれたネットワークから特徴抽出関連セクションを複製します。これは、featExtNetwork.input
を featExtNetwork.feat
に接続するサブグラフです。
parameters="constant"
を指定したので、featExtNetwork.feat
依存するすべてのパラメーターも複製され、読み取り専用になります。
手順 3 と 4 では、新しいネットワークが定義されています。 これは他の BrainScript モデルと同様に行われ、featExt()
関数を使用できるようになりました。
.
[
と ]
でのノード名に関する問題
.
または [
または ]
を含むネットワーク内のノードを参照するには、それらの文字を _
で置き換えます。
たとえば、network
に result.z
というノードが含まれている場合、network.result.z
は失敗します。代わりに network.result_z
を言う.
例: 既存のネットワークのノードの変更
既存のネットワークの内部部分を変更するには、実際にネットワークを複製しますが、変更は複製プロセスの一部として適用されます。 これは、BS.Network.Edit()
によって実現されます。
Edit()
は、ネットワークのすべてのノードを反復処理し、呼び出し元によって渡されるラムダ関数に各ノードを 1 つずつ提供します。 これらのラムダ関数は、ノードを検査し、変更されていないノードを返すか、その代わりに新しいノードを返すことができます。
Edit()
は、指定されていない順序でノードを反復処理します。 置換ノードが、置換されたネットワーク ノードを参照する場合、Edit()
は最後の手順として、該当する置換へのそのような参照をすべて更新します (別名「正しいことを行う」)。
TODO: 例。
次へ: 完全な関数参照 を