All Downloads are FREE. Search and download functionalities are using the official Maven repository.

marytts.unitselection.select.HalfPhoneFFRTargetCostFunction Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2006 DFKI GmbH.
 * All Rights Reserved.  Use is subject to license terms.
 *
 * This file is part of MARY TTS.
 *
 * MARY TTS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 *
 */
package marytts.unitselection.select;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import marytts.exceptions.MaryConfigurationException;
import marytts.features.FeatureDefinition;
import marytts.features.FeatureProcessorManager;
import marytts.features.FeatureVector;
import marytts.features.TargetFeatureComputer;
import marytts.server.MaryProperties;
import marytts.signalproc.display.Histogram;
import marytts.unitselection.data.FeatureFileReader;
import marytts.unitselection.data.HalfPhoneFeatureFileReader;
import marytts.unitselection.data.Unit;
import marytts.unitselection.weightingfunctions.WeightFunc;
import marytts.unitselection.weightingfunctions.WeightFunctionManager;
import marytts.util.MaryUtils;

public class HalfPhoneFFRTargetCostFunction extends FFRTargetCostFunction {
	protected FeatureDefinition leftWeights;
	protected FeatureDefinition rightWeights;
	protected WeightFunc[] leftWeightFunction;
	protected WeightFunc[] rightWeightFunction;

	public HalfPhoneFFRTargetCostFunction() {
	}

	/**
	 * Compute the goodness-of-fit of a given unit for a given target.
	 * 
	 * @param target
	 *            target
	 * @param unit
	 *            unit
	 * @return a non-negative number; smaller values mean better fit, i.e. smaller cost.
	 */
	public double cost(Target target, Unit unit) {
		if (!(target instanceof HalfPhoneTarget))
			throw new IllegalArgumentException("This target cost function can only be called for half-phone targets!");
		HalfPhoneTarget hpTarget = (HalfPhoneTarget) target;
		boolean isLeftHalf = hpTarget.isLeftHalf();
		FeatureDefinition weights = isLeftHalf ? leftWeights : rightWeights;
		WeightFunc[] weightFunctions = isLeftHalf ? leftWeightFunction : rightWeightFunction;
		return cost(target, unit, weights, weightFunctions);
	}

	/**
	 * Initialise the data needed to do a target cost computation.
	 * 
	 * @param featureFileName
	 *            name of a file containing the unit features
	 * @param weightsFile
	 *            an optional string containing weights file names -- if non-null, contains two file names separated by the
	 *            character '|', pointing to feature weights files for left and right units, respectively, that override the ones
	 *            present in the feature file.
	 * @param featProc
	 *            a feature processor manager which can provide feature processors to compute the features for a target at run
	 *            time
	 * @throws IOException
	 *             IOException
	 * @throws MaryConfigurationException
	 *             MaryConfigurationException
	 */
	public void load(String featureFileName, String weightsFile, FeatureProcessorManager featProc) throws IOException,
			MaryConfigurationException {
		HalfPhoneFeatureFileReader ffr = new HalfPhoneFeatureFileReader(featureFileName);
		load(ffr, weightsFile, featProc);
	}

	public void load(FeatureFileReader featureFileReader, String weightsFile, FeatureProcessorManager featProc)
			throws IOException {
		if (!(featureFileReader instanceof HalfPhoneFeatureFileReader))
			throw new IllegalArgumentException("Featurefilereader must be a HalfPhoneFeatureFileReader");
		HalfPhoneFeatureFileReader ffr = (HalfPhoneFeatureFileReader) featureFileReader;
		this.leftWeights = ffr.getLeftWeights();
		this.featureDefinition = this.leftWeights;
		this.rightWeights = ffr.getRightWeights();
		this.featureVectors = ffr.getFeatureVectors();

		if (weightsFile != null) {
			MaryUtils.getLogger("TargetCostFeatures").debug("Overwriting target cost weights from file " + weightsFile);
			String[] weightsFiles = weightsFile.split("\\|");
			if (weightsFiles.length != 2)
				throw new IllegalArgumentException(
						"Parameter weightsFile should contain exactly two fields separated by a '|' character -- instead, it is: '"
								+ weightsFile + "'");
			File leftF = new File(weightsFiles[0].trim());
			File rightF;
			// If the second weights file has no path, it is in the same directory as the first
			if (weightsFiles[1].indexOf("/") == -1 && weightsFiles[1].indexOf("\\") == -1) {
				File dir = leftF.getParentFile();
				rightF = new File(dir, weightsFiles[1].trim());
			} else {
				rightF = new File(weightsFiles[1].trim());
			}

			// overwrite weights from files
			FeatureDefinition newLeftWeights = new FeatureDefinition(new BufferedReader(new InputStreamReader(
					new FileInputStream(leftF), "UTF-8")), true);
			if (!newLeftWeights.featureEquals(leftWeights)) {
				throw new IOException("Weights file '" + leftF + "': feature definition incompatible with feature file");
			}
			leftWeights = newLeftWeights;
			FeatureDefinition newRightWeights = new FeatureDefinition(new BufferedReader(new InputStreamReader(
					new FileInputStream(rightF), "UTF-8")), true);
			if (!newRightWeights.featureEquals(rightWeights)) {
				throw new IOException("Weights file '" + rightF + "': feature definition incompatible with feature file");
			}
			rightWeights = newRightWeights;
		}
		WeightFunctionManager wfm = new WeightFunctionManager();
		WeightFunc linear = wfm.getWeightFunction("linear");
		int nDiscreteFeatures = leftWeights.getNumberOfByteFeatures() + leftWeights.getNumberOfShortFeatures();
		leftWeightFunction = new WeightFunc[leftWeights.getNumberOfContinuousFeatures()];
		rightWeightFunction = new WeightFunc[leftWeightFunction.length];
		for (int i = 0; i < leftWeightFunction.length; i++) {
			String weightFunctionName = leftWeights.getWeightFunctionName(nDiscreteFeatures + i);
			if ("".equals(weightFunctionName))
				leftWeightFunction[i] = linear;
			else
				leftWeightFunction[i] = wfm.getWeightFunction(weightFunctionName);
			weightFunctionName = rightWeights.getWeightFunctionName(nDiscreteFeatures + i);
			if ("".equals(weightFunctionName))
				rightWeightFunction[i] = linear;
			else
				rightWeightFunction[i] = wfm.getWeightFunction(weightFunctionName);
		}
		// TODO: If the target feature computer had direct access to the feature definition, it could do some consistency checking
		this.targetFeatureComputer = new TargetFeatureComputer(featProc, leftWeights.getFeatureNames());

		rememberWhichWeightsAreNonZero();

		if (MaryProperties.getBoolean("debug.show.cost.graph")) {
			debugShowCostGraph = true;
			cumulWeightedCosts = new double[featureDefinition.getNumberOfFeatures()];
			TargetCostReporter tcr2 = new TargetCostReporter(cumulWeightedCosts);
			tcr2.showInJFrame("Average weighted target costs", false, false);
			tcr2.start();
		}
	}

	/**
	 * Compute the features for a given target, and store them in the target.
	 * 
	 * @param target
	 *            the target for which to compute the features
	 * @see Target#getFeatureVector()
	 */
	public void computeTargetFeatures(Target target) {
		FeatureVector fv = targetFeatureComputer.computeFeatureVector(target);
		target.setFeatureVector(fv);
	}

	/**
	 * Look up the features for a given unit.
	 * 
	 * @param unit
	 *            a unit in the database
	 * @return the FeatureVector for target cost computation associated to this unit
	 */
	public FeatureVector getUnitFeatures(Unit unit) {
		return featureVectors[unit.index];
	}

	/**
	 * Get the string representation of the feature value associated with the given unit
	 * 
	 * @param unit
	 *            the unit whose feature value is requested
	 * @param featureName
	 *            name of the feature requested
	 * @return a string representation of the feature value
	 * @throws IllegalArgumentException
	 *             if featureName is not a known feature
	 */
	public String getFeature(Unit unit, String featureName) {
		int featureIndex = featureDefinition.getFeatureIndex(featureName);
		if (featureDefinition.isByteFeature(featureIndex)) {
			byte value = featureVectors[unit.index].getByteFeature(featureIndex);
			return featureDefinition.getFeatureValueAsString(featureIndex, value);
		} else if (featureDefinition.isShortFeature(featureIndex)) {
			short value = featureVectors[unit.index].getShortFeature(featureIndex);
			return featureDefinition.getFeatureValueAsString(featureIndex, value);
		} else { // continuous -- return float as string
			float value = featureVectors[unit.index].getContinuousFeature(featureIndex);
			return String.valueOf(value);
		}
	}

	public class TargetCostReporter extends Histogram {
		private double[] data;
		private int lastN = 0;

		public TargetCostReporter(double[] data) {
			super(0, 1, data);
			this.data = data;
		}

		public void start() {
			new Thread() {
				public void run() {
					while (isVisible()) {
						try {
							Thread.sleep(500);
						} catch (InterruptedException ie) {
						}
						updateGraph();
					}
				}
			}.start();
		}

		protected void updateGraph() {
			if (nCostComputations == lastN)
				return;
			lastN = nCostComputations;
			double[] newCosts = new double[data.length];
			for (int i = 0; i < newCosts.length; i++) {
				newCosts[i] = data[i] / nCostComputations;
			}
			updateData(0, 1, newCosts);
			repaint();
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy