次の方法で共有


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.h1inModel.zなどのドット構文を使用して BrainScript からアクセスできます。

定数はモデルに格納されないため、モデルから NM も使用できません。 ただし、読み込まれたモデルから再構築することは可能です。 そのために、計算ノードも 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.inputfeatExtNetwork.featに接続するサブグラフです。 parameters="constant"を指定したので、featExtNetwork.feat 依存するすべてのパラメーターも複製され、読み取り専用になります。

手順 3 と 4 では、新しいネットワークが定義されています。 これは他の BrainScript モデルと同様に行われ、featExt() 関数を使用できるようになりました。

. [] でのノード名に関する問題

. または [ または ]を含むネットワーク内のノードを参照するには、それらの文字を _で置き換えます。 たとえば、networkresult.zというノードが含まれている場合、network.result.z は失敗します。代わりに network.result_zを言う.

例: 既存のネットワークのノードの変更

既存のネットワークの内部部分を変更するには、実際にネットワークを複製しますが、変更は複製プロセスの一部として適用されます。 これは、BS.Network.Edit()によって実現されます。 Edit() は、ネットワークのすべてのノードを反復処理し、呼び出し元によって渡されるラムダ関数に各ノードを 1 つずつ提供します。 これらのラムダ関数は、ノードを検査し、変更されていないノードを返すか、その代わりに新しいノードを返すことができます。 Edit() は、指定されていない順序でノードを反復処理します。 置換ノードが、置換されたネットワーク ノードを参照する場合、Edit() は最後の手順として、該当する置換へのそのような参照をすべて更新します (別名「正しいことを行う」)。

TODO: 例。

次へ: 完全な関数参照 を する