Parsing命令行选项

Posted by lili on

本文的内容主要是翻译文档Parsing command-line options。更多本系列文章请点击Kaldi文档解读

目录

Introduction

ParseOptions用于从来自main()函数的argc和argv的参数里提取命令行的选项。我们首先给出一个典型的Kaldi命令行程序使用它的例子:

   gmm-align --transition-scale=10.0 --beam=75 \
       exp/mono/tree exp/mono/30.mdl data/L.fst \
       'ark:add-deltas --print-args=false scp:data/train.scp ark:- |' \
        ark:data/train.tra ark:exp/tri/0.ali

命令行选项只有长的形式(--beam这样的,没有常见Linux命令的单个字符的短形式(比如ls -l)),并且它必须出现在所有位置参数的前面。在这个例子里有6个位置参数,”exp/mono/tree”是第一个位置参数。注意:”ark:add-deltas”开头的参数是一个包含空格的字符串。

parsing命令行选项的示例

我们通过gmm-align.cc的代码(为了简洁做了一些修改)来展示在C++代码基本怎么处理命令行选项:

int main(int argc, char *argv[])
{
  try { // try-catch block is standard and relates to handling of errors.
    using namespace kaldi;
    const char *usage =
        "Align features given [GMM-based] models.\n" 
        "Usage: align-gmm [options] tree-in model-in lexicon-fst-in feature-rspecifier "
        "transcriptions-rspecifier alignments-wspecifier\n";
    // Initialize the ParseOptions object with the usage string.
    ParseOptions po(usage);
    // Declare options and set default values.
    bool binary = false;
    BaseFloat beam = 200.0;
    // Below is a structure containing options; its initializer sets defaults.
    TrainingGraphCompilerOptions gopts;
    // Register the options with the ParseOptions object.
    po.Register("binary", &binary, "Write output in binary mode");
    po.Register("beam", &beam, "Decoding beam");
    gopts.Register(&po);
    // The command-line options get parsed here.
    po.Read(argc, argv);
    // Check that there are a valid number of positional arguments.
    if(po.NumArgs() != 6) {
      po.PrintUsage();
      exit(1);
    }
    // The positional arguments get read here (they can only be obtained
    // from ParseOptions as strings).
    std::string tree_in_filename = po.GetArg(1);
    ...
    std::string alignment_wspecifier = po.GetArg(6);
    ...   
  } catch(const std::exception& e) {
    std::cerr << e.what();
    return -1;
  }
}

The code above is mostly self-explanatory. In a normal Kaldi program, the sequence is as follows: 上面的代码大部分是自解释的(self-explanatory)。在一个典型的Kaldi程序里,处理流程为:

  • 构造一个ParseOptions对象,参数为介绍其用法的字符串。
  • 定义和设置选项(可选参数)的默认值(以及定义option的结构体)
  • 对ParseOptions对象注册命令行选项(option的结构体有它自己注册的函数)
  • 调用”po.Read(argc, argv);”
  • 使用”po.NumArgs()”检查位置参数的个数是否正确
  • 使用”po.GetArg(1)”获取位置参数,而选项的值直接保存在对应的变量里。

比如上面的代码里binary是一个boolean类型的选项,可以通过”po.Register(“binary”, &binary, “Write output in binary mode”);”来注册它,这样命令行的用户可以使用”--binary=true”来设置。而gopts是一个结构体(TrainingGraphCompilerOptions),它通过”gopts.Register(&po);”来自己处理命令行选项:

struct TrainingGraphCompilerOptions {

  BaseFloat transition_scale;
  BaseFloat self_loop_scale;
  bool rm_eps;
  bool reorder;  // (Dan-style graphs)

  explicit TrainingGraphCompilerOptions(BaseFloat transition_scale = 1.0,
                                        BaseFloat self_loop_scale = 1.0,
                                        bool b = true) :
      transition_scale(transition_scale),
      self_loop_scale(self_loop_scale),
      rm_eps(false),
      reorder(b) { }

  void Register(OptionsItf *opts) {
    opts->Register("transition-scale", &transition_scale, "Scale of transition "
                   "probabilities (excluding self-loops)");
    opts->Register("self-loop-scale", &self_loop_scale, "Scale of self-loop vs. "
                   "non-self-loop probability mass ");
    opts->Register("reorder", &reorder, "Reorder transition ids for greater decoding efficiency.");
    opts->Register("rm-eps", &rm_eps,  "Remove [most] epsilons before minimization (only applicable "
                   "if disambig symbols present)");
  }
};

通常如果要编写一个新的Kaldi命令行程序,可以复制一个然后照着修改。

隐式的命令选项

Certain command-line options are automatically registered by the ParseOptions object itself. These include the following:

ParseOptions对象会自动的注册一些命令行选项,因此所有的Kaldi命令行程序都可以使用这些选项。这包括:

  • --config 这个选项从一个配置文件加载命令行选项。比如我们指定--config=configs/my.conf,文件my.conf可能包含:
          --first-option=15  # This is the first option
          --second-option=false # This is the second option
  • -\0print-args 这是一个boolean类型的选项,控制程序是否打印命令行参数到标准错误输出(默认是true),可以用--print-args=false关掉这个行为

  • --help 打印ParseOptions对象的用法字符串。不过你通常可以使用没有任何参数的命令,一般的命令都需要参数,它发现参数不对时也会打印用法字符串。
  • --verbose 控制verbose级别,这样决定KALDI_VLOG是否输出。值越大级别越高(--verbose=2是比较典型的用法)