HCompV源码再解析续二

代码逻辑到这里是个分水岭,因此另开一个博客来继续下面的源码分析。

之前一直是在为了最终目的做准备,主要包括创建HMMSet、读取proto模型文件、观察向量的配置文件,分配了内存累加器空间,其目的都是为了接下来的计算全局的方差和均值。

/* LoadFile: load whole file or segments and accumulate variance */
void LoadFile(char *fn)
{
   ParmBuf pbuf;
   BufferInfo info;
   char labfn[80];
   Transcription *trans;
   long segStIdx,segEnIdx;  
   int i,j,ncas,nObs;
   LLink p;
   
   if (segId == NULL)  {   /* load whole parameter file */
      if((pbuf=OpenBuffer(&iStack, fn, 0, dff, FALSE_dup, FALSE_dup))==NULL)
         HError(2050,"LoadFile: Config parameters invalid");
      GetBufferInfo(pbuf,&info);
      CheckData(fn,info);
      nObs = ObsInBuffer(pbuf);
      for (i=0; i<nObs; i++){
         ReadAsTable(pbuf,i,&obs);
         AccVar(obs);  
      }
      if (trace&T_LOAD) {
         printf(" %d observations loaded from %s\n",nObs,fn);
         fflush(stdout);
      }        
      CloseBuffer(pbuf);
   }
   else {                  /* load segment of parameter file */
      MakeFN(fn,labDir,labExt,labfn);
      trans = LOpen(&iStack,labfn,lff);
      ncas = NumCases(trans->head,segId);
      if ( ncas > 0) {
         if((pbuf=OpenBuffer(&iStack, fn, 0, dff, FALSE_dup, FALSE_dup))==NULL)
            HError(2050,"LoadFile: Config parameters invalid");
         GetBufferInfo(pbuf,&info);
         CheckData(fn,info);
         for (i=1,nObs=0; i<=ncas; i++) {
            p = GetCase(trans->head,segId,i);
            segStIdx= (long) (p->start/info.tgtSampRate);
            segEnIdx  = (long) (p->end/info.tgtSampRate);
            if (trace&T_SEGS)
               printf(" loading seg %s [%ld->%ld]\n",
                      segId->name,segStIdx,segEnIdx);
            if (segEnIdx >= ObsInBuffer(pbuf))
               segEnIdx = ObsInBuffer(pbuf)-1;
            if (segEnIdx >= segStIdx) {
               for (j=segStIdx;j<=segEnIdx;j++) {
                  ReadAsTable(pbuf,j,&obs);
                  AccVar(obs); ++nObs;
               }
            }
         }        
         CloseBuffer(pbuf);
         if (trace&T_LOAD)
            printf(" %d observations loaded from %s\n",nObs,fn);
      }  
   }
   ResetHeap(&iStack);
}

主逻辑是OpenBuffer(&iStack, fn, 0, dff, FALSE_dup, FALSE_dup)、GetBufferInfo(pbuf,&info)、CheckData(fn,info)、ObsInBuffer(pbuf)、 ReadAsTable(pbuf,i,&obs)、AccVar(obs)。

在OpenBuffer函数中,重要的函数是FillBufFromChannel。

/* ------------ Read and Convert Data from Channel Input ------------ */

/* FillBufFromChannel: fill buffer from channel input  */
/*  if minRows>0 ensures that after the call returns at least minRows */
/*  valid rows are available otherwise just reads and qualifies those */
/*  that can be read immediately (without blocking) */
static void FillBufFromChannel(ParmBuf pbuf,int minRows)
{
   IOConfig cf = pbuf->cf;
   PBlock *pb,*lb;
   Boolean dis,cleared;
   char b1[100];
   int availRows,newRows,space,i,head,tail,nShift;
   short *sp1=NULL, *sp2;
   float *fp1=NULL, *fp2;
   
   
   /* Fill Buffer with converted static coef vectors */
   newRows=FramesInChannel(pbuf,pbuf->chType);

   /* Number of rows that we can read immediately */
   
   ...

   /* Read the necessary frames */
   for (i=0; i<newRows; i++) {
      /* But have final check on read just in case */
      if (pbuf->dShort) {
         if (GetFrameFromChannel(pbuf,pbuf->chType,sp1)!=1) {
            pbuf->chClear=TRUE;
            break;
         }
         sp1 += cf->nCols; 
      }
      else {
         if (GetFrameFromChannel(pbuf,pbuf->chType,fp1)!=1) {
            pbuf->chClear=TRUE;
            break;
         }
         fp1 += cf->nCols; 
      }
      pbuf->inRow++;pbuf->main.nRows++;
   }

  ...

}

省略了很多检查和保证程序健壮性的代码,只保留最重要的逻辑,就是查询训练数据的有多少帧,并读取这些帧数据到内存空间中。

接下来分析 ReadAsTable(pbuf,i,&obs)、AccVar(obs)。

ReadAsTable函数调用ReadObs,它实现这个读取操作。

static void ReadObs(ParmBuf pbuf, int outRow,Observation *o)
{
   int i,numS;
   float *fp,*data;
   short *sp;
   PBlock *pb;
   char b1[50],b2[50];   

                  
   numS = o->swidth[0];
   if (outRow>=pbuf->main.stRow) {
      data=(float *) pbuf->main.data;
      i=outRow-pbuf->main.stRow;
   } else {
      for (pb=pbuf->main.next;pb!=NULL;pb=pb->next)
         if (pb->stRow+pb->nRows>outRow) break;
      if (pb==NULL) 
         HError(6395,"ReadObs: Frame discarded from buffer");
      data=(float *) pb->data;
      i=outRow-pb->stRow;
   }
   
      fp = (float *)data + i*pbuf->cf->nCols;
      ExtractObservation(fp,o);

}

主要看的就是最后两行,首先定位fp,然后调用ExtractObservation(fp, o)。

看一下它的主要代码:

/* ExtractObservation: copy vector of floats starting at fp into
   observation, splitting into streams as necessary */
static void ExtractObservation(float *fp, Observation *o)
{
   int i,j,k,n,w1,w2,w,nStatic = 0;
   int numS = o->swidth[0];
   Vector v,ev;
   Boolean wantE,skipE;
   
   ev = o->fv[numS]; 
   for (i=1,k=1; i<numS; i++){
       v = o->fv[i];
       for (j=1; j<=o->swidth[i]; j++)
           v[j] = *fp++;
       if (wantE || i>1) ev[k++] = *fp;
       fp++;    



      for (i=1,k=0; i<=numS; i++){
         v = o->fv[i];
         for (j=1; j<=o->swidth[i]; j++){
            v[j] = *fp++; k++;        
         }
      }
}

删除了些不重要的检查代码,只保留了最重要部分。其实就是最后四行,fp指定的位置值赋值给v[j],它实际上是o.fv[s]对应的位置。也是数据最终被读到的位置。接续来的处理,是从Observation对象o中提取数据,o.fv[s]赋给vector v,然后累计到acc中的相同维度的meanSum和squareSum中。

/* AccVar:  update global accumulators with given observation */
void AccVar(Observation obs)
{
   int x,y,s,V;
   float val;
   Vector v;

   totalCount++;
   for (s=1; s<=hset.swidth[0]; s++){
      v = obs.fv[s]; V = hset.swidth[s];
      for (x=1;x<=V;x++) { 
         val=v[x];            
         accs[s].meanSum[x] += val;     /* accumulate mean */                             
         if (fullcNeeded[s]) {          /* accumulate covar */ 
            accs[s].squareSum.inv[x][x] += val*val;
            for (y=1;y<x;y++) 
               accs[s].squareSum.inv[x][y] += val*v[y];
         } else                         /* accumulate var */
            accs[s].squareSum.var[x] += val*val;
      }
   }
}

到此,数据累计完成了,剩下就是除以总样本数,也就是整个训练集中的特征向量个数。它由全局变量totalCount提供。

static long totalCount=0;           /* total number of vector samples*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值