[Julius-cvs 806] CVS update: julius4/libjulius/src

Back to archive index

sumom****@users***** sumom****@users*****
2013年 6月 12日 (水) 18:48:58 JST


Index: julius4/libjulius/src/mbr.c
diff -u /dev/null julius4/libjulius/src/mbr.c:1.1
--- /dev/null	Wed Jun 12 18:48:58 2013
+++ julius4/libjulius/src/mbr.c	Wed Jun 12 18:48:58 2013
@@ -0,0 +1,465 @@
+/**
+ * @file   mbr.c
+ * 
+ * <JA>
+ * @brief  認識された文をMBRの枠組みでリスコア
+ *
+ * 認識された文をMBRの枠組みでリスコアする.
+ * </JA>
+ * 
+ * @author Hiroaki NANJO, Ryo FURUTANI
+ * @date   28 March 2011
+ *
+ * $Revision: 1.1 $
+ * 
+ */
+/*
+ * Copyright (c) 2010-2011 NANJO lab. Ryukoku University
+ * All rights reserved
+ */
+
+#include <julius/julius.h>
+
+#ifdef USE_MBR
+
+/** 
+ * <JA>
+ * MBRスコアでソートするための qsort コールバック関数. 
+ * 
+ * @param a [in] 要素1
+ * @param b [in] 要素2
+ * 
+ * @return 演算の結果の符合を返す. 
+ * </JA>
+ */
+
+static int
+mbr_cmp(NODE **a, NODE **b)
+{
+  if ((*a)->score_mbr > (*b)->score_mbr) return 1;
+  if ((*a)->score_mbr < (*b)->score_mbr) return -1;
+  return 0;
+}
+
+
+/** 
+ * <JA>
+ * DPマッチングの結果を出力するデバッグ関数.
+ * 
+ * @param d [in] DPマッチングの結果
+ * @param len1 [in] 要素1の要素数
+ * @param len2 [in] 要素2の要素数
+ * 
+ * @return 最短距離
+ * </JA>
+ */
+
+static int
+dp_print(DP *d, int len1, int len2)
+{
+  int i, j;
+
+  jlog("Distance\n");
+  for(i = 0; i < len1; i++){
+    for(j = 0; j < len2; j++){
+      jlog("%d ", d[j * len1 + i].d);
+    }
+    jlog("\n");
+  }
+
+  jlog("\nTransition from\n");
+  for(i = 0; i < len1; i++){
+    for(j = 0; j < len2; j++){
+      jlog("%d ", d[j * len1 + i].r);
+    }
+    jlog("\n");
+  }
+
+  jlog("\nCost\n");
+  for(i = 0; i < len1; i++){
+    for(j = 0; j < len2; j++){
+      jlog("%d ", d[j * len1 + i].c);
+    }
+    jlog("\n");
+  }
+
+  return d[len1 * len2 - 1].d;
+}
+
+
+/** 
+ * <JA>
+ * 
+ * 最もコストが小さいパスを返す.
+ * 
+ * @param a [in] 値1
+ * @param b [in] 値2
+ * @param c [in] 値3
+ * @param cost [in] 遷移コスト
+ * 
+ * @return コストと遷移元.
+ * </JA>
+ */
+
+static DP
+dppath(int a, int b, int c, int cost)
+{
+  DP min;
+
+  if (a < b){
+    min.d = a;
+    min.r = 1;
+  }
+  else{
+    min.d = b;
+    min.r = 2;
+  }
+
+  if (c < min.d){
+    min.d = c;
+    min.r = 3;
+  }
+
+  min.c = cost;
+
+  return min;
+}
+
+
+/** 
+ * <JA>
+ * 
+ * DPマッチングを行う.
+ * 
+ * @param a [in] 要素1
+ * @param b [in] 要素2
+ * @param w [in] 言語モデル
+ * 
+ * @return DPマッチングの結果.
+ * </JA>
+ */
+
+static DP*
+dpmatch(NODE *a, NODE *b, WORD_INFO *winfo)
+{
+  int len1, len2;
+  DP *d;
+  int i, j;
+  int cost;
+
+  char *c1, *c2;
+
+  len1 = a->seqnum + 1;
+  len2 = b->seqnum + 1;
+
+  d = (DP *)mymalloc(sizeof(DP) * len1 * len2);
+
+  d[0].d = 0;
+  d[0].r = 0;
+  d[0].c = 0;
+
+  for(i = 1; i < len1; i++){
+
+    d[i].d = i;
+    d[i].r = 1;
+    d[i].c = 0;
+  }
+
+  for(i = 1; i < len2; i++){
+
+    d[i * len1].d = i;
+    d[i * len1].r = 2;
+    d[i * len1].c = 0;
+  }
+
+  for(i = 1; i < len1; i++){
+
+    c1 = winfo->woutput[a->seq[i - 1]];
+
+    for(j = 1; j < len2; j++){
+
+      c2 = winfo->woutput[b->seq[j - 1]];
+
+      if (strmatch(c1, c2)) {
+
+	cost = 0;
+      }
+      else {
+
+	cost = 1;
+      }
+
+      d[j * len1 + i] = dppath(d[j * len1 + (i - 1)].d + 1,
+			       d[(j - 1) * len1 + i].d + 1,
+			       d[(j - 1) * len1 + (i - 1)].d + cost,
+			       cost);
+     }
+  }
+
+  if(debug2_flag){
+    dp_print(d, len1, len2);
+  }
+
+  return d;
+}
+
+
+/** 
+ * <JA>
+ * Weighed Levenstein distanceを計算する.
+ * 
+ * @param a [in] 要素1
+ * @param b [in] 要素2
+ * @param w [in] 言語モデル
+ * 
+ * @return Weighed Levenstein distanceの値を返す.
+ * </JA>
+ */
+
+static float
+calc_wld(NODE *a, NODE *b, WORD_INFO *winfo)
+{
+  float weight, error1, error2;
+  DP *d;
+  int i, j, now;
+
+  /* DPマッチングのパスを求める */
+  d = dpmatch(a, b, winfo);
+
+  weight = 0.0;
+  i = a->seqnum;
+  j = b->seqnum;
+
+  /* バックトレースしつつ重みを確定 */
+  if(d[i * j - 1].d > 0){
+
+    error1 = 0.0;
+    error2 = 0.0;
+
+    while(i > 0 || j > 0){
+
+      now = j * (a->seqnum + 1) + i;
+
+      if(d[now].r == 1){
+	/* Deletion error */
+	error1 += winfo->weight[a->seq[i - 1]];
+	i--;
+      }
+      else if(d[now].r == 2){
+	/* Insertion error */
+	error2 += winfo->weight[b->seq[j - 1]];
+	j--;
+      }
+      else if(d[now].r == 3){
+	if(d[now].c == 1){
+	  /* Substitution error */
+	  error1 += winfo->weight[a->seq[i - 1]];
+	  error2 += winfo->weight[b->seq[j - 1]];
+	}
+	else if(d[now].c == 0){
+	  /* Correct word */
+	  weight += error1 > error2 ? error1 : error2;
+	  error1 = 0.0;
+	  error2 = 0.0;
+	}
+	else{
+	  jlog("Error: calc_wld: cannot calculation Weighted Levenstein distance: cost error\n");
+	  return -1.0;
+	}
+
+	i--;
+	j--;
+      }
+      else{
+	jlog("Error: calc_wld: cannot calculation Weighted Levenstein distance: table error: i = %d, j = %d\n", i, j);
+	return -1.0;
+      }
+    }
+
+    weight += error1 > error2 ? error1 : error2;
+  }
+
+  free(d);
+
+  return weight;
+}
+
+
+/** 
+ * <JA>
+ * Levenstein distanceを計算する.
+ * 
+ * @param a [in] 要素1
+ * @param b [in] 要素2
+ * @param w [in] 言語モデル
+ * 
+ * @return Levenstein distanceの値を返す.
+ * </JA>
+ */
+
+static int
+calc_ld(NODE *a, NODE *b, WORD_INFO *winfo)
+{
+  int distance;
+  DP *d;
+
+  /* DPマッチングのパスを求める */
+  d = dpmatch(a, b, winfo);
+
+  distance = d[(a->seqnum + 1) * (b->seqnum + 1) - 1].d;
+
+  free(d);
+
+  return distance;
+}
+
+
+/** 
+ * <JA>
+ * 音声認識スコアを正規化する.
+ * MBRスコアの初期化も同時に行う.
+ * 
+ * @param table [in] スタックテーブル
+ * @param r_stacknum [in] スタックのデータ数
+ * @param r [in] 認識インスタンス
+ * 
+ * @return 正規化されたスコアの配列を返す.
+ * </JA>
+ */
+
+static float *
+normalization_score(NODE **table, int r_stacknum, RecogProcess *r)
+{
+  float *n_score;
+  int i;
+  float max;
+
+  n_score = (float *)mymalloc(sizeof(float) * r_stacknum);
+
+  /* 最も高いスコアで正規化する */
+  max = table[0]->score;
+  n_score[0] = 1.0;
+  table[0]->score_mbr = 0.0;
+
+  if(debug2_flag){
+    jlog("n_score[0] = %f\n", n_score[0]);
+  }
+
+  for(i = 1; i < r_stacknum; i++){
+
+    n_score[i] = pow(10, (table[i]->score - max) * r->config->mbr.score_weight);
+    table[i]->score_mbr = 0.0;
+
+    if(debug2_flag){
+      jlog("n_score[%d] = %f\n", i, n_score[i]);
+    }
+  }
+
+  return n_score;
+}
+
+
+/** 
+ * <JA>
+ * @brief  MBR処理のメイン関数
+ *
+ * 認識した文をMBRの枠組みでリスコアする.
+ * 
+ * @param r_start [i/o] 結果格納用スタックの先頭ノードへのポインタ
+ * @param r_bottom [i/o] 結果格納用スタックの底ノードへのポインタ
+ * @param r_stacknum [in] スタックに格納されているノード数へのポインタ
+ * @param r [in] 認識処理インスタンス
+ * </JA>
+ *
+ * @callgraph
+ * @callergraph
+ * 
+ */
+
+
+void 
+candidate_mbr(NODE **r_start, NODE **r_bottom, int r_stacknum, RecogProcess *r)
+{
+  JCONF_SEARCH *jconf = r->config;
+  NODE **table;
+  NODE *now;
+
+  int i, j;
+  int dist;
+
+  float *n_score;
+  float error;
+
+  /* リストのままでは扱いにくいので配列に変換 */
+  table = (NODE **)mymalloc(sizeof(NODE *) * r_stacknum);
+  i = 0;
+  for(now = *r_start; now; now = now->next){
+    table[i] = now;
+    i++;
+  }
+
+  /* 認識スコア(ゆう度)を正規化 */
+  n_score = normalization_score(table, r_stacknum, r);
+
+  /* MBRスコアを計算 */
+  for(i = 0; i < r_stacknum - 1; i++){
+    for(j = i + 1; j < r_stacknum; j++){
+
+      if(jconf->mbr.use_word_weight){
+	/* 損失関数はWeighted Levenstein distance */
+	if((error = calc_wld(table[i], table[j], r->lm->winfo)) < 0.0){
+	  jlog("Error: candidate_mbr: cannot calculation Weighted Levenstein distance\n");
+	  free(n_score);
+	  free(table);
+	  return;
+	}
+
+	error = pow(error, jconf->mbr.loss_weight);
+      }
+      else{
+	/* 損失関数はLevenstein distance */
+	if((dist = calc_ld(table[i], table[j], r->lm->winfo)) < 0){
+	  jlog("Error: candidate_mbr: cannot calculation Levenstein distance\n");
+	  free(n_score);
+	  free(table);
+	  return;
+	}
+
+	error = pow(dist, jconf->mbr.loss_weight);
+      }
+
+      table[i]->score_mbr += n_score[j] * error;
+      table[j]->score_mbr += n_score[i] * error;
+
+      if(debug2_flag){
+	jlog("i = %d, j = %d\n", i, j);
+	jlog("error = %f\n", error);
+	jlog("n_score[%d] * error = %f\n", j, n_score[j] * error);
+	jlog("table[%d]->score_mbr = %f\n", i, table[i]->score_mbr);
+	jlog("n_score[%d] * error = %f\n", i, n_score[i] * error);
+	jlog("table[%d]->score_mbr = %f\n", j, table[j]->score_mbr);
+      }
+    }
+  }
+
+  /* 結果をリスコア */
+  qsort(table, r_stacknum, sizeof(NODE *),
+	(int (*)(const void *, const void *))mbr_cmp);
+
+  /* 配列をリストに変換 */
+  *r_start = table[0];
+  (*r_start)->prev = NULL;
+  for(i = 1; i < r_stacknum; i++){
+    table[i]->prev = table[i - 1];
+    table[i - 1]->next = table[i];
+  }
+  *r_bottom = table[r_stacknum - 1];
+  (*r_bottom)->next = NULL;
+
+  free(n_score);
+  free(table);
+
+  return;
+}
+
+#endif  /* USE_MBR */



Julius-cvs メーリングリストの案内
Back to archive index