/// <summary>
        /// Gets the pre-selection triphone for each leaf nodes in pre-selection forest.
        /// </summary>
        /// <param name="forest">The pre-selection forest.</param>
        /// <param name="labels">The given list of the labels in training set.</param>
        /// <returns>A Dictionary whose key is a Label to indicate a triphone, whose value is leaf nodes in forest.</returns>
        public static Dictionary<Label, DecisionTreeNode> GetPreselectionTriphone(this DecisionForest forest, List<Label> labels)
        {
            Dictionary<Label, DecisionTreeNode> triphoneToNode = new Dictionary<Label, DecisionTreeNode>();

            // In order to get the all pre-selection tri-phone, all full-context label in training set will be visited.
            foreach (Label label in labels)
            {
                // Get the tri-phone label from the full-context label.
                Label triphone = new Label(label);
                triphone.ResizeFeatureValue(LabelFeatureNameSet.Triphone);

                // If the tri-phone exists, it can be ignored. However, we can process it again to perform verifications.
                if (!triphoneToNode.ContainsKey(triphone))
                {
                    // Travel the forest using the full-context label to get the matched leaf nodes.
                    List<DecisionTreeNode> nodes = FilterDecisionForest(forest, label);

                    // Please notice: in pre-selection tree, each label only match one leaf node since the pre-selection tree is clustered by phone model.
                    if (nodes.Count != 1)
                    {
                        throw new InvalidDataException("The forest is not a invalid pre-selection forest.");
                    }

                    triphoneToNode.Add(triphone, nodes[0]);
                }
            }

            return triphoneToNode;
        }
        /// <summary>
        /// Extracts the features of the given utterance.
        /// </summary>
        /// <param name="sentId">
        /// Sentence id.
        /// </param>
        /// <param name="utterance">
        /// Service Provider utterance object.
        /// </param>
        /// <returns>
        /// The sentence contains all the features.
        /// </returns>
        /// <exception cref="InvalidDataException">
        /// Exception.
        /// </exception>
        public Sentence Extract(string sentId, TtsUtterance utterance)
        {
            List<FeatureVector> vectors;

            try
            {
                // Then, extracts the features.
                vectors = ExtractionEngine.Extract(utterance, FeatureMetas);
            }
            catch (EspException e)
            {
                throw new InvalidDataException(Helper.NeutralFormat("Extract feature error on sentence \"{0}\"",
                    sentId), e);
            }

            // Validates the extracted vectors.
            if (vectors.Count != FeatureMetas.Count)
            {
                throw new InvalidDataException(
                    Helper.NeutralFormat("Length of result is mismatch on sentence \"{0}\"", sentId));
            }

            for (int i = 0; i < vectors.Count; i++)
            {
                if (vectors[i].Count != utterance.Phones.Count)
                {
                    throw new InvalidDataException(
                        Helper.NeutralFormat("Length of vector is mismatch on sentence \"{0}\"", sentId));
                }
            }

            // Creates a sentence to store all the features.
            Sentence sentence = new Sentence { Id = sentId };
            for (int i = 0; i < vectors[0].Count; ++i)
            {
                // Create candidates for each phoneme.
                PhoneSegment p = new PhoneSegment
                {
                    Sentence = sentence,
                    Index = i,
                    Features = vectors.Select(v => v[i])
                        .Skip(LabelFeatureNameSet.MandatoryFeatureNames.Length).ToArray(),
                };

                // Create the label to store the features.
                Label label = new Label(FeatureNameSet);
                for (int j = 0; j < vectors.Count; ++j)
                {
                    if (vectors[j][i].ValueType == FeatureValueType.FEATURE_VALUE_TYPE_UNKOWN)
                    {
                        label.SetFeatureValue(FeatureNameSet.FeatureNames[j], Label.NotApplicableFeatureValue);
                    }
                    else if (FeatureMetas[j].Property == TtsFeatureProperty.TTS_FEATURE_PROPERTY_PHONE_ID)
                    {
                        Phone phone = PhoneSet.GetPhone(vectors[j][i].IntValue);
                        label.SetFeatureValue(FeatureNameSet.FeatureNames[j], Offline.Phoneme.ToHtk(phone.Name));
                    }
                    else
                    {
                        label.SetFeatureValue(FeatureNameSet.FeatureNames[j],
                            vectors[j][i].IntValue.ToString(CultureInfo.InvariantCulture));
                    }

                    // Updates the corresponding value records.
                    FeatureValueRecords[j].Update(vectors[j][i]);
                }

                p.Label = label;
                sentence.PhoneSegments.Add(p);
            }

            return sentence;
        }
        /// <summary>
        /// Build cross correlation matrix.
        /// </summary>
        /// <param name="phoneList">Mono phone list.</param>
        /// <returns>Cross correlation matrix.</returns>
        public List<Pair<CandidateGroup, CandidateGroup>> BuildCCMatrix(IEnumerable<string> phoneList)
        {
            List<Pair<CandidateGroup, CandidateGroup>> matrix = new List<Pair<CandidateGroup, CandidateGroup>>();

            foreach (CandidateGroup group in CandidateGroups)
            {
                Label label = new Label(LabelFeatureNameSet.Triphone) { Text = group.Name };
                foreach (string phone in phoneList)
                {
                    string triphone = Helper.NeutralFormat("{0}-{1}+{2}", label.CentralPhoneme, label.RightPhoneme, phone);
                    if (_nameIndexedCandidateGroup.ContainsKey(triphone))
                    {
                        Pair<CandidateGroup, CandidateGroup> pair =
                            new Pair<CandidateGroup, CandidateGroup>(group, _nameIndexedCandidateGroup[triphone]);
                        matrix.Add(pair);
                    }
                }
            }

            return matrix;
        }
        /// <summary>
        /// Finds the corresponding candidate in the given sentence set.
        /// </summary>
        /// <param name="sentenceSet">The given sentence set.</param>
        /// <param name="sentId">The sentence id which contains the candidate.</param>
        /// <param name="indexOfNonSilence">The index of non-silence unit of the candidate.</param>
        /// <param name="label">The label of the candidate.</param>
        /// <returns>The corresponding candidate.</returns>
        private static UnitCandidate FindCandidate(TrainingSentenceSet sentenceSet, string sentId, int indexOfNonSilence, string label)
        {
            if (!sentenceSet.Sentences.ContainsKey(sentId))
            {
                throw new InvalidDataException(Helper.NeutralFormat("Cannot find the sentence \"{0}\"", sentId));
            }

            Sentence sentence = sentenceSet.Sentences[sentId];
            UnitCandidate result = null;
            foreach (UnitCandidate candidate in sentence.Candidates)
            {
                if (candidate.IndexOfNonSilence == indexOfNonSilence)
                {
                    result = candidate;
                    break;
                }
            }

            if (result == null)
            {
                throw new InvalidDataException(Helper.NeutralFormat("Cannot find the candidate \"{0}:{1}\"", sentId, indexOfNonSilence));
            }

            Label myLabel = new Label { Text = label };
            if (result.Label.CentralPhoneme != myLabel.CentralPhoneme)
            {
                throw new InvalidDataException(
                    Helper.NeutralFormat(
                    "Mismatched full-context label, expected current phone \"{0}\" but \"{1}\"",
                    result.Label.CentralPhoneme,
                    myLabel.CentralPhoneme));
            }

            return result;
        }
        /// <summary>
        /// Gets the all leaf nodes which can match the given label in the decision forst.
        /// </summary>
        /// <param name="forest">The given decision forest.</param>
        /// <param name="label">The given label.</param>
        /// <returns>A List object contains all the matched leaf nodes.</returns>
        public static List<DecisionTreeNode> FilterDecisionForest(this DecisionForest forest, Label label)
        {
            List<DecisionTreeNode> nodes = new List<DecisionTreeNode>();

            // For each decision tree in forest, it need to be traveled.
            foreach (DecisionTree tree in forest.TreeList)
            {
                // Firstly, the tree should be matched by phone name if it is a phone-dependent tree.
                bool matched;
                string phone = tree.Phone;
                if (Phoneme.IsAnyPhone(phone))
                {
                    matched = true;
                }
                else
                {
                    matched = label.CentralPhoneme == phone;
                }

                if (matched)
                {
                    // Travel the matched tree, each tree will return a single leaf node.
                    nodes.Add(FilterTree(tree.NodeList[0], forest.Questions, label));
                }
            }

            return nodes;
        }
        /// <summary>
        /// Gets the all possible tri-phone from this set.
        /// </summary>
        /// <returns>The list of Label object to hold the tri-phone.</returns>
        public List<Label> GetAllTriphone()
        {
            List<Label> list = new List<Label>();
            foreach (string left in LeftPhones)
            {
                foreach (string central in CentralPhones)
                {
                    foreach (string right in RightPhones)
                    {
                        Label label = new Label(LabelFeatureNameSet.Triphone);
                        label.LeftPhoneme = left;
                        label.CentralPhoneme = central;
                        label.RightPhoneme = right;
                        list.Add(label);
                    }
                }
            }

            return list;
        }
        /// <summary>
        /// Filters a tree to get the leaf node.
        /// </summary>
        /// <param name="node">The first node of the tree.</param>
        /// <param name="questions">A Dictionary to contains all the Question used by the tree.</param>
        /// <param name="label">The given label.</param>
        /// <returns>The leaf node which match the label.</returns>
        public static DecisionTreeNode FilterTree(DecisionTreeNode node, IDictionary<string, Question> questions, Label label)
        {
            while (node.NodeType != DecisionTreeNodeType.Leaf)
            {
                Question question = questions[node.QuestionName];

                // If the value set of question contains the feature value, it means matched with question mark.
                if (MatchHtsQuestion(question.ValueSet, label.GetFeatureValue(question.FeatureName)))
                {
                    node = node.RightChild;
                }
                else
                {
                    node = node.LeftChild;
                }
            }

            return node;
        }
Esempio n. 8
0
 /// <summary>
 /// Initializes a new instance of the Label class as a copy of the given one.
 /// </summary>
 /// <param name="label">The given label to copy.</param>
 public Label(Label label)
 {
     _featureNames = label._featureNames;
     Text = label.Text;
 }