none
Limit on Choices and efficiency. RRS feed

  • Question

  • Hey. I'm using GrammarBuilder.Append() to add a list of choices to my grammar and then I use

    new Grammar(grammarbuilder);


    Is there a limit to how many choices there can be? Also, is there a way to make this process more efficient instead of simply adding a large list of Choices? I find that if the choices count is over 8000, it takes very long to create the new Grammar. Is there an alternate way of doing it for a large number of choices?

    Thanks for any advice. 

    Friday, December 2, 2011 3:18 AM

Answers

  • Yeah, that's exactly it. Here's a code sample:

    This is the grammar of other grammars. Below it are the calls to build the list semantic result keys, which are needed in this example. The first one is possible commands, the second one is a list of groups those commands can be applied to:

            private static Grammar BuildGrammarForGroups()
            {
                GrammarBuilder cmdArgs = new GrammarBuilder();
                cmdArgs.Append(XXXXX.Utilities.Grammar.GetPrefixKey());
                cmdArgs.Append(XXXXX.Utilities.Grammar.GetGroupsCommandChoicesKey());
                cmdArgs.AppendWildcard();
                cmdArgs.Append(XXXXX.Utilities.Grammar.GetGroupChoicesKey());
                cmdArgs.AppendWildcard();
    
                Grammar grammar = new Grammar(cmdArgs);
    
                return grammar;
            }
    
                    public static SemanticResultKey GetGroupsCommandChoicesKey()
                    {
                        return new SemanticResultKey("commandChoices", GetGroupsCommandChoices());
                    }
    
                    private static Choices GetGroupsCommandChoices()
                    {
                        Choices commandChoices = new Choices();
                        foreach (SpeechCommand cmd in SpeechCommand.GetAllSpeechCommandsForGroups)
                        {
                            commandChoices.Add((GrammarBuilder)new SemanticResultValue(cmd.CommandText, (int)cmd.CommandType));
                        }
    
                        return commandChoices;
                    }
    

    public static SemanticResultKey GetGroupChoicesKey()
    {
        return new SemanticResultKey("groupChoices", GetGroupChoices());
    }
    
    private static Choices GetGroupChoices()
    {
        DataTable dtg = XXXXX.GetAllGroups();
    
        Choices groupChoices = new Choices();
        foreach (DataRow row in dtg.Rows)
        {
            groupChoices.Add((GrammarBuilder)new SemanticResultValue(row["name"].ToString().ToLower(), row["value"].ToString()));
        }
    
        return groupChoices;
    }
    

    This is the prefix, I make all commands start with the same word. For the moment it's "computer", but it could be anything:

    public static SemanticResultKey GetPrefixKey()
    {
        return new SemanticResultKey("computerPrefix", new Choices(new string[] { "computer" }));
    }
    



     

    • Marked as answer by MolemanH Saturday, December 3, 2011 3:36 AM
    Saturday, December 3, 2011 1:49 AM

All replies

  • If you have 8000 unique commands in a flat list it will take a while. If they aren't all unique, for instance "Do X to Y", where X is a list of possible commands and Y is a list of possible receivers of those commands, you should break your grammars up. Each list should have its own SemanticResultKey. In a way you build a grammar of other grammars. "Do" has it's own SemanticResultKey, the list of commands a second SemanticResultKey, "to" a third SemanticResultKey, and the list of receivers the final SemanticResultKey. I've used this method to build grammars with tens of thousands of possible commands.
    • Edited by ChrisCicc Saturday, December 3, 2011 4:47 AM
    Saturday, December 3, 2011 12:12 AM
  • Thanks for your help ChrisCicc. I'm working on a game and I think I see one inefficiency already. I have some verbs "take, open, drop". I have a list of objects (possibly over 10000). Lets say there was an object 'ball'. I added to the Grammar, "ball" as well as "take ball", "open ball" and "drop ball". How would I go about doing it such that I can say "take" as one part and "ball" in the other part and have the system combine the two as if the user said "take ball". (i.e. I don't have to store "<verb> <object>" 10,000+ times) Is that what you were alluding to? Thanks again, I've been spending over a week on trying to understand this and hoped someone here would know. 
    • Edited by MolemanH Saturday, December 3, 2011 1:34 AM
    Saturday, December 3, 2011 1:32 AM
  • Yeah, that's exactly it. Here's a code sample:

    This is the grammar of other grammars. Below it are the calls to build the list semantic result keys, which are needed in this example. The first one is possible commands, the second one is a list of groups those commands can be applied to:

            private static Grammar BuildGrammarForGroups()
            {
                GrammarBuilder cmdArgs = new GrammarBuilder();
                cmdArgs.Append(XXXXX.Utilities.Grammar.GetPrefixKey());
                cmdArgs.Append(XXXXX.Utilities.Grammar.GetGroupsCommandChoicesKey());
                cmdArgs.AppendWildcard();
                cmdArgs.Append(XXXXX.Utilities.Grammar.GetGroupChoicesKey());
                cmdArgs.AppendWildcard();
    
                Grammar grammar = new Grammar(cmdArgs);
    
                return grammar;
            }
    
                    public static SemanticResultKey GetGroupsCommandChoicesKey()
                    {
                        return new SemanticResultKey("commandChoices", GetGroupsCommandChoices());
                    }
    
                    private static Choices GetGroupsCommandChoices()
                    {
                        Choices commandChoices = new Choices();
                        foreach (SpeechCommand cmd in SpeechCommand.GetAllSpeechCommandsForGroups)
                        {
                            commandChoices.Add((GrammarBuilder)new SemanticResultValue(cmd.CommandText, (int)cmd.CommandType));
                        }
    
                        return commandChoices;
                    }
    

    public static SemanticResultKey GetGroupChoicesKey()
    {
        return new SemanticResultKey("groupChoices", GetGroupChoices());
    }
    
    private static Choices GetGroupChoices()
    {
        DataTable dtg = XXXXX.GetAllGroups();
    
        Choices groupChoices = new Choices();
        foreach (DataRow row in dtg.Rows)
        {
            groupChoices.Add((GrammarBuilder)new SemanticResultValue(row["name"].ToString().ToLower(), row["value"].ToString()));
        }
    
        return groupChoices;
    }
    

    This is the prefix, I make all commands start with the same word. For the moment it's "computer", but it could be anything:

    public static SemanticResultKey GetPrefixKey()
    {
        return new SemanticResultKey("computerPrefix", new Choices(new string[] { "computer" }));
    }
    



     

    • Marked as answer by MolemanH Saturday, December 3, 2011 3:36 AM
    Saturday, December 3, 2011 1:49 AM
  • Thanks a lot! Just to clarify. using this method, I could potentially have 10000+ objects handled quite efficiently? (Of course, I have to experiment to be sure, but I'm away from my dev machine until tomorrow). 
    Saturday, December 3, 2011 3:36 AM
  • Indeed. I'm not entirely sure where I'm at in terms of hard numbers with this method, but I've tested it against what I'd estimate approaches 100,000 variations and it loads in about 3 seconds on an average machine. I do not see any noticeable degradation in recognition time.
    Saturday, December 3, 2011 4:45 AM
  • Brilliant, thanks a lot ChrisCicc, you have saved this man from further headaches!
    Saturday, December 3, 2011 12:49 PM