package recunn.loss;
import java.util.ArrayList;
import java.util.List;

import recunn.autodiff.Graph;
import recunn.datastructs.DataSequence;
import recunn.datastructs.DataStep;
import recunn.matrix.Matrix;
import recunn.model.Model;
import recunn.util.Util;


public class LossSoftmax implements Loss {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public void backward(Matrix logprobs, Matrix targetOutput) throws Exception {
		int targetIndex = getTargetIndex(targetOutput);
		Matrix probs = getSoftmaxProbs(logprobs, 1.0);
		for (int i = 0; i < probs.w.length; i++) {
			logprobs.dw[i] = probs.w[i];
		}
		logprobs.dw[targetIndex] -= 1;
	}

	@Override
	public double measure(Matrix logprobs, Matrix targetOutput) throws Exception {
		int targetIndex = getTargetIndex(targetOutput);
		Matrix probs = getSoftmaxProbs(logprobs, 1.0);
		double cost = -Math.log(probs.w[targetIndex]);
		return cost;
	}

	public static double calculateMedianPerplexity(Model model, List sequences) throws Exception {
		double temperature = 1.0;
		List ppls = new ArrayList<>();
		for (DataSequence seq : sequences) {
			double n = 0;
			double neglog2ppl = 0;
			
			Graph g = new Graph(false);
			model.resetState();
			for (DataStep step : seq.steps) {
				Matrix logprobs = model.forward(step.input, g);
				Matrix probs = getSoftmaxProbs(logprobs, temperature);
				int targetIndex = getTargetIndex(step.targetOutput);
				double probOfCorrect = probs.w[targetIndex];
				double log2prob = Math.log(probOfCorrect)/Math.log(2); //change-of-base
				neglog2ppl += -log2prob;
				n += 1;
			}
			
			n -= 1; //don't count first symbol of sentence
			double ppl = Math.pow(2, (neglog2ppl/(n-1)));
			ppls.add(ppl);
		}
		return Util.median(ppls);
	}
	
	public static Matrix getSoftmaxProbs(Matrix logprobs, double temperature) throws Exception {	
		Matrix probs = new Matrix(logprobs.w.length);
		if (temperature != 1.0) {
			for (int i = 0; i < logprobs.w.length; i++) {
				logprobs.w[i] /= temperature;
			}
		}
		double maxval = Double.NEGATIVE_INFINITY;
		for (int i = 0; i < logprobs.w.length; i++) {
			if (logprobs.w[i] > maxval) {
				maxval = logprobs.w[i];
			}
		}
		double sum = 0;
		for (int i = 0; i < logprobs.w.length; i++) {
			probs.w[i] = Math.exp(logprobs.w[i] - maxval); //all inputs to exp() are non-positive
			sum += probs.w[i];
		}
		for (int i = 0; i < probs.w.length; i++) {
			probs.w[i] /= sum;
		}
		return probs;
	}

	private static int getTargetIndex(Matrix targetOutput) throws Exception {
		for (int i = 0; i < targetOutput.w.length; i++) {
			if (targetOutput.w[i] == 1.0) {
				return i;
			}
		}
		throw new Exception("no target index selected");
	}
}

 

Ads help maintain this website.