private TSNEState(TSNEState original, Cloner cloner) : base(original, cloner) { distance = cloner.Clone(original.distance); random = cloner.Clone(original.random); perplexity = original.perplexity; exact = original.exact; noDatapoints = original.noDatapoints; finalMomentum = original.finalMomentum; momSwitchIter = original.momSwitchIter; stopLyingIter = original.stopLyingIter; theta = original.theta; eta = original.eta; newDimensions = original.newDimensions; if (original.valP != null) { valP = new double[original.valP.Length]; Array.Copy(original.valP, valP, valP.Length); } if (original.rowP != null) { rowP = new int[original.rowP.Length]; Array.Copy(original.rowP, rowP, rowP.Length); } if (original.colP != null) { colP = new int[original.colP.Length]; Array.Copy(original.colP, colP, colP.Length); } if (original.p != null) { p = new double[original.p.GetLength(0), original.p.GetLength(1)]; Array.Copy(original.p, p, p.Length); } newData = new double[original.newData.GetLength(0), original.newData.GetLength(1)]; Array.Copy(original.newData, newData, newData.Length); iter = original.iter; currentMomentum = original.currentMomentum; gains = new double[original.gains.GetLength(0), original.gains.GetLength(1)]; Array.Copy(original.gains, gains, gains.Length); uY = new double[original.uY.GetLength(0), original.uY.GetLength(1)]; Array.Copy(original.uY, uY, uY.Length); dY = new double[original.dY.GetLength(0), original.dY.GetLength(1)]; Array.Copy(original.dY, dY, dY.Length); }
public static double[,] Iterate(TSNEState state) { if (state.exact) { ComputeExactGradient(state.p, state.newData, state.noDatapoints, state.newDimensions, state.dY); } else { ComputeApproximateGradient(state.rowP, state.colP, state.valP, state.newData, state.noDatapoints, state.newDimensions, state.dY, state.theta); } // Update gains for (var i = 0; i < state.noDatapoints; i++) { for (var j = 0; j < state.newDimensions; j++) { state.gains[i, j] = Math.Sign(state.dY[i, j]) != Math.Sign(state.uY[i, j]) ? state.gains[i, j] + .2 // +0.2 nd *0.8 are used in two separate implementations of tSNE -> seems to be correct : state.gains[i, j] * .8; if (state.gains[i, j] < .01) { state.gains[i, j] = .01; } } } // Perform gradient update (with momentum and gains) for (var i = 0; i < state.noDatapoints; i++) { for (var j = 0; j < state.newDimensions; j++) { state.uY[i, j] = state.currentMomentum * state.uY[i, j] - state.eta * state.gains[i, j] * state.dY[i, j]; } } for (var i = 0; i < state.noDatapoints; i++) { for (var j = 0; j < state.newDimensions; j++) { state.newData[i, j] = state.newData[i, j] + state.uY[i, j]; } } // Make solution zero-mean ZeroMean(state.newData); // Stop lying about the P-values after a while, and switch momentum if (state.iter == state.stopLyingIter) { if (state.exact) { for (var i = 0; i < state.noDatapoints; i++) { for (var j = 0; j < state.noDatapoints; j++) { state.p[i, j] /= 12.0; } } } else { for (var i = 0; i < state.rowP[state.noDatapoints]; i++) { state.valP[i] /= 12.0; } } } if (state.iter == state.momSwitchIter) { state.currentMomentum = state.finalMomentum; } state.iter++; return(state.newData); }