⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 crf2.java

📁 常用机器学习算法,java编写源代码,内含常用分类算法,包括说明文档
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/* Copyright (C) 2002 Univ. of Massachusetts Amherst, Computer Science Dept.   This file is part of "MALLET" (MAchine Learning for LanguagE Toolkit).   http://www.cs.umass.edu/~mccallum/mallet   This software is provided under the terms of the Common Public License,   version 1.0, as published by http://www.opensource.org.  For further   information, see the file `LICENSE' included with this distribution. *//** 		@author Andrew McCallum <a href="mailto:mccallum@cs.umass.edu">mccallum@cs.umass.edu</a> */package edu.umass.cs.mallet.base.fst;import edu.umass.cs.mallet.base.types.*;import edu.umass.cs.mallet.base.pipe.Pipe;import edu.umass.cs.mallet.base.minimize.*;import edu.umass.cs.mallet.base.util.Maths;import edu.umass.cs.mallet.base.util.MalletLogger;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.Arrays;import java.util.BitSet;import java.util.Random;import java.util.logging.*;import java.io.*;/* There are several different kinds of numeric values:   "weights" range from -Inf to Inf.  High weights make a path more   likely.  These don't appear directly in Transducer.java, but appear	 as parameters to many subclasses, such as CRFs.  Weights are also	 often summed, or combined in a dot product with feature vectors.	 "unnormalized costs" range from -Inf to Inf.  High costs make a	 path less likely.  Unnormalized costs can be obtained from negated	 weights or negated sums of weights.  These are often returned by a	 TransitionIterator's getCost() method.  The LatticeNode.alpha	 values are unnormalized costs.	 "normalized costs" range from 0 to Inf.  High costs make a path	 less likely.  Normalized costs can safely be considered as the	 -log(probability) of some event.  They can be obtained by	 substracting a (negative) normalizer from unnormalized costs, for	 example, subtracting the total cost of a lattice.  Typically	 initialCosts and finalCosts are examples of normalized costs, but	 they are also allowed to be unnormalized costs.  The gammas[][],	 stateGammas[], and transitionXis[][] are all normalized costs, as	 well as the return value of Lattice.getCost().	 "probabilities" range from 0 to 1.  High probabilities make a path	 more likely.  They are obtained from normalized costs by taking the	 log and negating.  	 "sums of probabilities" range from 0 to positive numbers.  They are	 the sum of several probabilities.  These are passed to the	 incrementCount() methods.	 */public class CRF2 extends Transducer implements Serializable{	private static Logger logger =	MalletLogger.getLogger(CRF2.class.getName());	static final double DEFAULT_GAUSSIAN_PRIOR_VARIANCE = 10.0;	static final double DEFAULT_HYPERBOLIC_PRIOR_SLOPE = 0.2;	static final double DEFAULT_HYPERBOLIC_PRIOR_SHARPNESS = 10.0;		// The length of each weights[i] Vector is the size of the input	// dictionary plus one; the additional column at the end is for the	// "default feature".	Alphabet inputAlphabet;	Alphabet outputAlphabet;	ArrayList states = new ArrayList ();	ArrayList initialStates = new ArrayList ();	HashMap name2state = new HashMap ();	SparseVector[] weights, constraints, expectations;	double[] defaultWeights, defaultConstraints, defaultExpectations;	// parameters for default feature	BitSet[] weightsPresent;							// Only used in setWeightsDimensionAsIn()	Alphabet weightAlphabet = new Alphabet ();	boolean trainable = false;	boolean gatheringConstraints = false;	boolean gatheringWeightsPresent = false;	//int defaultFeatureIndex;	boolean usingHyperbolicPrior = false;	double gaussianPriorVariance = DEFAULT_GAUSSIAN_PRIOR_VARIANCE;	double hyperbolicPriorSlope = DEFAULT_HYPERBOLIC_PRIOR_SLOPE;	double hyperbolicPriorSharpness = DEFAULT_HYPERBOLIC_PRIOR_SHARPNESS;	private boolean cachedCostStale = true;	private boolean cachedGradientStale = true;	// xxx temporary hack	public boolean printGradient = false;	public CRF2 (Pipe inputPipe, Pipe outputPipe)	{		this.inputPipe = inputPipe;		this.outputPipe = outputPipe;		this.inputAlphabet = inputPipe.getDataAlphabet();		this.outputAlphabet = inputPipe.getTargetAlphabet();		//this.defaultFeatureIndex = inputAlphabet.size();		//inputAlphabet.stopGrowth();	}		public CRF2 (Alphabet inputAlphabet,							Alphabet outputAlphabet)	{		inputAlphabet.stopGrowth();		logger.info ("CRF input dictionary size = "+inputAlphabet.size());		//xxx outputAlphabet.stopGrowth();		this.inputAlphabet = inputAlphabet;		this.outputAlphabet = outputAlphabet;		//this.defaultFeatureIndex = inputAlphabet.size();	}	// xxx Remove this method?	/** Create a new CRF sharing Alphabet and other attributes, but possibly			having a larger weights array. */	/*	private CRF2 (CRF2 initialCRF) {		System.out.println ("new CRF. Old weight size = "+initialCRF.weights[0].singleSize()+												" New weight size = "+initialCRF.inputAlphabet.size());		this.inputAlphabet = initialCRF.inputAlphabet;		this.outputAlphabet = initialCRF.outputAlphabet;		this.states = new ArrayList (initialCRF.states.size());		this.inputPipe = initialCRF.inputPipe;		this.outputPipe = initialCRF.outputPipe;		//this.defaultFeatureIndex = initialCRF.defaultFeatureIndex;		for (int i = 0; i < initialCRF.states.size(); i++) {			State s = (State) initialCRF.getState (i);			String[] weightNames = new String[s.weightsIndices.length];			for (int j = 0; j < weightNames.length; j++)				weightNames[j] = (String) initialCRF.weightAlphabet.lookupObject(s.weightsIndices[i]);			addState (s.name, s.initialCost, s.finalCost, s.destinationNames, s.labels, weightNames);		}		assert (weights.length > 0);		for (int i = 0; i < weights.length; i++)			weights[i].arrayCopyFrom (0, initialCRF.getWeights ((String)weightAlphabet.lookupObject(i)));	}	*/	public Alphabet getInputAlphabet () { return inputAlphabet; }	public Alphabet getOutputAlphabet () { return outputAlphabet; }		public void setUseHyperbolicPrior (boolean f) { usingHyperbolicPrior = f; }	public void setHyperbolicPriorSlope (double p) { hyperbolicPriorSlope = p; }	public void setHyperbolicPriorSharpness (double p) { hyperbolicPriorSharpness = p; }	public double getUseHyperbolicPriorSlope () { return hyperbolicPriorSlope; }	public double getUseHyperbolicPriorSharpness () { return hyperbolicPriorSharpness; }	public void setGaussianPriorVariance (double p) { gaussianPriorVariance = p; }	public double getGaussianPriorVariance () { return gaussianPriorVariance; }	//public int getDefaultFeatureIndex () { return defaultFeatureIndex;}		public void addState (String name, double initialCost, double finalCost,												String[] destinationNames,												String[] labelNames,												String[] weightNames)	{		assert (weightNames.length == destinationNames.length);		assert (labelNames.length == destinationNames.length);		setTrainable (false);		if (name2state.get(name) != null)			throw new IllegalArgumentException ("State with name `"+name+"' already exists.");		State s = new State (name, states.size(), initialCost, finalCost,												 destinationNames, labelNames, weightNames, this);		s.print ();		states.add (s);		if (initialCost < INFINITE_COST)			initialStates.add (s);		name2state.put (name, s);	}		// Default gives separate parameters to each transition	public void addState (String name, double initialCost, double finalCost,												String[] destinationNames,												String[] labelNames)	{		assert (destinationNames.length == labelNames.length);		String[] weightNames = new String[labelNames.length];		for (int i = 0; i < labelNames.length; i++)			weightNames[i] = name + "->" + destinationNames[i] + ":" + labelNames[i];		this.addState (name, initialCost, finalCost, destinationNames, labelNames, weightNames);	}													// Add a state with parameters equal zero, and labels on out-going arcs	// the same name as their destination state names.	public void addState (String name, String[] destinationNames)	{		this.addState (name, 0, 0,									 destinationNames, destinationNames);	}	// Add a group of states that are fully connected with each other,	// with parameters equal zero, and labels on their out-going arcs	// the same name as their destination state names.	public void addFullyConnectedStates (String[] stateNames)	{		for (int i = 0; i < stateNames.length; i++)			addState (stateNames[i], stateNames);	}	public void addFullyConnectedStatesForLabels ()	{		String[] labels = new String[outputAlphabet.size()];		// This is assuming the the entries in the outputAlphabet are Strings!		for (int i = 0; i < outputAlphabet.size(); i++) {			logger.info("CRF: outputAlphabet.lookup class = "+													outputAlphabet.lookupObject(i).getClass().getName());			labels[i] = (String) outputAlphabet.lookupObject(i);		}		addFullyConnectedStates (labels);	}	private boolean[][] labelConnectionsIn (InstanceList trainingSet)	{		int numLabels = outputAlphabet.size();		boolean[][] connections = new boolean[numLabels][numLabels];		for (int i = 0; i < trainingSet.size(); i++) {			Instance instance = trainingSet.getInstance(i);			FeatureSequence output = (FeatureSequence) instance.getTarget();			for (int j = 1; j < output.size(); j++) {				int sourceIndex = outputAlphabet.lookupIndex (output.get(j-1));				int destIndex = outputAlphabet.lookupIndex (output.get(j));				assert (sourceIndex >= 0 && destIndex >= 0);				connections[sourceIndex][destIndex] = true;			}		}		return connections;	}	/** Add states to create a first-order Markov model on labels,			adding only those transitions the occur in the given			trainingSet. */	public void addStatesForLabelsConnectedAsIn (InstanceList trainingSet)	{		int numLabels = outputAlphabet.size();		boolean[][] connections = labelConnectionsIn (trainingSet);		for (int i = 0; i < numLabels; i++) {			int numDestinations = 0;			for (int j = 0; j < numLabels; j++)				if (connections[i][j]) numDestinations++;			String[] destinationNames = new String[numDestinations];			int destinationIndex = 0;			for (int j = 0; j < numLabels; j++)				if (connections[i][j])					destinationNames[destinationIndex++] = (String)outputAlphabet.lookupObject(j);			addState ((String)outputAlphabet.lookupObject(i), destinationNames);		}	}	/** Add as many states as there are labels, but don't create separate weights			for each source-destination pair of states.  Instead have all the incoming			transitions to a state share the same weights. */	public void addStatesForHalfLabelsConnectedAsIn (InstanceList trainingSet)	{		int numLabels = outputAlphabet.size();		boolean[][] connections = labelConnectionsIn (trainingSet);		for (int i = 0; i < numLabels; i++) {			int numDestinations = 0;			for (int j = 0; j < numLabels; j++)				if (connections[i][j]) numDestinations++;			String[] destinationNames = new String[numDestinations];			int destinationIndex = 0;			for (int j = 0; j < numLabels; j++)				if (connections[i][j])					destinationNames[destinationIndex++] = (String)outputAlphabet.lookupObject(j);			addState ((String)outputAlphabet.lookupObject(i), 0.0, 0.0,								destinationNames, destinationNames, destinationNames);		}	}		public void addFullyConnectedStatesForBiLabels ()	{		String[] labels = new String[outputAlphabet.size()];		// This is assuming the the entries in the outputAlphabet are Strings!		for (int i = 0; i < outputAlphabet.size(); i++) {			logger.info ("CRF: outputAlphabet.lookup class = "+									 outputAlphabet.lookupObject(i).getClass().getName());			labels[i] = (String) outputAlphabet.lookupObject(i);		}		for (int i = 0; i < labels.length; i++) {			for (int j = 0; j < labels.length; j++) {				String[] destinationNames = new String[labels.length];				for (int k = 0; k < labels.length; k++)					destinationNames[k] = labels[j]+','+labels[k];				addState (labels[i]+','+labels[j], 0.0, 0.0,									destinationNames, labels);			}		}	}	/** Add states to create a second-order Markov model on labels,			adding only those transitions the occur in the given			trainingSet. */	public void addStatesForBiLabelsConnectedAsIn (InstanceList trainingSet)	{		int numLabels = outputAlphabet.size();		boolean[][] connections = labelConnectionsIn (trainingSet);		for (int i = 0; i < numLabels; i++) {			for (int j = 0; j < numLabels; j++) {				if (!connections[i][j])					continue;				int numDestinations = 0;				for (int k = 0; k < numLabels; k++)					if (connections[j][k]) numDestinations++;				String[] destinationNames = new String[numDestinations];				String[] labels = new String[numDestinations];				int destinationIndex = 0;				for (int k = 0; k < numLabels; k++)					if (connections[j][k]) {						destinationNames[destinationIndex] =							(String)outputAlphabet.lookupObject(j)+','+(String)outputAlphabet.lookupObject(k);						labels[destinationIndex] = (String)outputAlphabet.lookupObject(k);						destinationIndex++;					}				addState ((String)outputAlphabet.lookupObject(i)+','+									(String)outputAlphabet.lookupObject(j), 0.0, 0.0,									destinationNames, labels);			}		}	}		public void addFullyConnectedStatesForTriLabels ()	{		String[] labels = new String[outputAlphabet.size()];		// This is assuming the the entries in the outputAlphabet are Strings!		for (int i = 0; i < outputAlphabet.size(); i++) {			logger.info ("CRF: outputAlphabet.lookup class = "+									 outputAlphabet.lookupObject(i).getClass().getName());			labels[i] = (String) outputAlphabet.lookupObject(i);		}		for (int i = 0; i < labels.length; i++) {			for (int j = 0; j < labels.length; j++) {				for (int k = 0; k < labels.length; k++) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -