public void Update(Real[] scoreDrop, Real[] scoreGrow, NdArray <Real> mask, NdArray <Real> weight) { int nOnes = (int)mask.Data.Sum(); int nPrune = (int)Math.Floor(nOnes * _dropFraction);//元実装はキャストで切り捨てしている int nKeep = nOnes - nPrune; int[] keepMask = new int[mask.Data.Length]; Real chackval = scoreDrop.OrderBy(a => - a).ElementAt(nKeep); //mask1にScoreDropの大きい順の先頭nKeep個に1を入れる for (int i = 0, keepCount = 0; i < keepMask.Length && keepCount < nKeep; i++) { if (scoreDrop[i] >= chackval) { keepMask[i] = 1; keepCount++; } } Real[] scoreGrowLifted = new Real[scoreGrow.Length]; //有効になっている接続のスコアが最も低くなるようにする //元実装だとscoreGrow.Min() - 1.0f for (int i = 0; i < keepMask.Length; i++) { scoreGrowLifted[i] = keepMask[i] == 1 ? Real.MinValue : scoreGrow[i]; } int[] growMask = new int[scoreGrowLifted.Length]; chackval = scoreGrowLifted.OrderBy(a => - a).ElementAt(nPrune); //mask2にscoreGrowLiftedの大きい順の先頭nPrune個に1を入れる for (int i = 0, prunedCount = 0; i < growMask.Length && prunedCount < nPrune; i++) { if (scoreGrowLifted[i] > chackval) { growMask[i] = 1; prunedCount++; } } #if DEBUG //mask1 * mask2で全て0になるか確認 int sum = 0; for (int i = 0; i < keepMask.Length; i++) { sum += keepMask[i] * growMask[i]; } if (sum != 0) { throw new Exception(); } #endif //Real[] glowTensor = getGlowTensor() //元実装がデフォルトだと0固定なので省略 bool[] newConnections = new bool[weight.Length]; for (int i = 0; i < weight.Length; i++) { newConnections[i] = growMask[i] == 1 && mask.Data[i] == 0; //マスクの更新があるか判定 if (newConnections[i]) { weight.Data[i] = 0; // この0は本来はgetGlowTensor()で取得してきたglowTensor; } } ResetMomentum(newConnections, scoreGrow, weight.Name); for (int i = 0; i < mask.Length; i++) { //mask1 * mask2で全て0になる保証があるので mask.Data[i] = keepMask[i] + growMask[i]; } }