こんにちは、
前回の記事で 、エラーを逆伝播するアルゴリズムについて話し、エラー関数とニューロンの活性化関数に依存しない実装をもたらしました。 これらの同じパラメーターの置換のいくつかの簡単な例が示されました:ユークリッド平方の最小化とシグモイド関数と双曲線正接の対数尤度。 この投稿は過去の論理的な続きであり、ここではやや非標準的な例、つまり
クロスエントロピーを最小
化するSoftmaxアクティベーション関数を検討します。 このモデルは、入力画像が交差しないクラスの1つに属する確率をニューラルネットワークの出力で取得する必要がある場合、分類問題に関連します。 明らかに、出力層のすべてのニューロンのネットワーク出力の合計は1に等しくなければなりません(トレーニングサンプルの出力画像も)。 ただし、出力を正規化するだけでは十分ではありませんが、ネットワークに確率分布をシミュレートさせ、それを教える必要があります。 ところで、
ニューラルネットワークのコースは現在
coursera.orgで
教えられて
おり 、
softmaxの理解を深める手助けをしたのは彼でした。そうでなければ、サードパーティの実装を使い続けます。
を使用して
ここでは、すべての表記法、インターフェース、および学習アルゴリズム自体が変更なしで使用されるため、
以前の投稿をよく理解することをお勧めします。
ソフトマックス活性化機能
したがって、私たちが直面する最初のタスクは、ネットワークが確率分布をモデル化する方法を提供することです。 これを行うには、次のような直接配布ネットワークを作成します。
- ネットワークには多くの隠れ層が含まれ、すべてのニューロンは独自の活性化機能を持つことができます。
- 最後の層には、クラスの数に対応するそのような数のニューロンがあります。 これらのニューロンはすべて、ソフトマックスレイヤーまたはグループと呼ばれます。
Softmaxグループのニューロンには、
次の活性化機能があります (このセクションでは、レイヤーインデックスを省略します。これは最後であり、
n個のニューロンが含まれることを意味します)。
i番目のニューロン
式から、各ニューロンの出力はsoftmaxグループの他のすべてのニューロンの加算器に依存し、グループ全体の出力値の合計は1であることがわかります。 この関数の利点は、加算器のi番目のニューロンの偏導関数が次と等しいことです。
前の記事の IFunctionインターフェイスを使用して、この関数を実装します。
softmax関数を実装するdouble Compute(double x)
メソッドの実装は、softmaxレイヤーの実装でグループの出力値を計算する方が安価であるため、通常は必要ないことに注意してください。 しかし、完全を期すために、万が一の場合に備えて、-)
internal class SoftMaxActivationFunction : IFunction { private ILayer _layer = null; private int _ownPosition = 0; internal SoftMaxActivationFunction(ILayer layer, int ownPosition) { _layer = layer; _ownPosition = ownPosition; } public double Compute(double x) { double numerator = Math.Exp(x); double denominator = numerator; for (int i = 0; i < _layer.Neurons.Length; i++) { if (i == _ownPosition) { continue; } denominator += Math.Exp(_layer.Neurons[i].LastNET); } return numerator/denominator; } public double ComputeFirstDerivative(double x) { double y = Compute(x); return y*(1 - y); } public double ComputeSecondDerivative(double x) { throw new NotImplementedException(); } }
エラー機能
各トレーニングの例では、必要な確率分布をモデル化したネットワーク出力を取得し、2つの確率分布を比較するための正しい測定が必要です。
クロスエントロピーはそのような尺度として使用されます:

- t-現在のトレーニング例に必要な出力
- y-ニューラルネットワークの実出力
一般的なネットワークエラーは次のように計算されます。

モデル全体の優雅さを実現するには、出力次元の1つまたはニューロンから勾配がどのように計算されるかを確認する必要があります。 「出力層」セクションの
以前の投稿で、タスクはdC / dz_iの計算に限定されると説明されていますが、これからも続けます。
なぜなら 各ニューロンの出力には電流の加算器が含まれているため、全体の量を区別する必要があります。 コスト関数はニューロンの出力のみに依存し、出力は加算器のみに依存するため、2つの偏導関数に分解できます。 次に、合計の各メンバーを個別に検討します(主なことは、インデックスに注意を払うことです。この場合、 jはグループのsoftmaxニューロンを通り、 iは現在のニューロンです)



最後の変換は、softmaxグループのニューロンの特性に従って、出力ベクトルの値の合計が1に等しくなければならないという事実により得られます。 これは、トレーニングサンプルの重要な要件です。そうしないと、勾配が正しく計算されません。
前と同じ表現を使用して実装に進みます。
クロスエントロピーの実装 internal class CrossEntropy : IMetrics<double> { internal CrossEntropy() { }
ソフトマックス層
一般的に、特別なレイヤーを行う必要はありません。上記のアクティベーション関数を使用して通常の直接配信ネットワークのコンストラクターに最後のレイヤーを作成し、コンストラクターでsoftmaxレイヤーへのリンクを渡すだけで、各ニューロンの出力を計算するたびに関数の分母が計算されますただし
double[] ComputeOutput(double[] inputVector)
ニューラルネットワークの
double[] ComputeOutput(double[] inputVector)
適切に実装する場合:
public double[] ComputeOutput(double[] inputVector) { double[] outputVector = inputVector; for (int i = 0; i < _layers.Length; i++) { outputVector = _layers[i].Compute(outputVector); } return outputVector; }
その後、ネットワークはニューロンのComputeメソッドを直接呼び出すのではなく、この関数をレイヤーに委任するため、活性化関数の分母を一度計算することができます。
ソフトマックス層 internal class SoftmaxFullConnectedLayer : FullConnectedLayer { internal SoftmaxFullConnectedLayer(int inputDimension, int size) { _neurons = new INeuron[size]; for (int i = 0; i < size; i++) { IFunction smFunction = new SoftMaxActivationFunction(this, i); _neurons[i] = new InLayerFullConnectedNeuron(inputDimension, smFunction); } } public override double[] Compute(double[] inputVector) { double[] numerators = new double[_neurons.Length]; double denominator = 0; for (int i = 0; i < _neurons.Length; i++) { numerators[i] = Math.Exp(_neurons[i].NET(inputVector)); denominator += numerators[i]; } double[] output = new double[_neurons.Length]; for (int i = 0; i < _neurons.Length; i++) { output[i] = numerators[i]/denominator; _neurons[i].LastState = output[i]; } return output; } }
まとめ
そのため、不足している部分は準備ができており、
コンストラクタを組み立てることができます。 たとえば、
コンストラクターが異なるだけで、同じ直接配信ネットワーク実装を使用します。