libcm/cmRbm.c
kevin 6c66569f79 Many Files (See list in comment): Added #include "cmTime.h" to support Audio and MIDI time stamps.
app/cmOnset.c
app/cmPickup.c
app/cmScore.c
app/cmScoreProc.c
app/cmTimeLine.c
cmAudDsp.c
cmAudioAggDev.c
cmAudioFileDev.c
cmAudioNrtDev.c
cmAudioPort.c
cmAudioPortFile.c
cmDevCfg.c
cmFeatFile.c
cmMidi.c
cmMidiFile.c
cmProc2.c
cmProc3.c
cmProc4.c
cmProcTest.c
cmRbm.c
cmUiRtSysMstr.c
dsp/cmDspClass.c
dsp/cmDspFx.c
dsp/cmDspNet.c
dsp/cmDspPgmKr.c
dsp/cmDspPgmPP.c
dsp/cmDspPgmPPMain.c
dsp/cmDspSys.c
dsp/cmDspUi.c
2013-12-15 18:14:27 -05:00

700 righe
18 KiB
C

#include "cmPrefix.h"
#include "cmGlobal.h"
#include "cmFloatTypes.h"
#include "cmComplexTypes.h"
#include "cmRpt.h"
#include "cmErr.h"
#include "cmCtx.h"
#include "cmMem.h"
#include "cmMallocDebug.h"
#include "cmLinkedHeap.h"
#include "cmMath.h"
#include "cmFile.h"
#include "cmSymTbl.h"
#include "cmTime.h"
#include "cmMidi.h"
#include "cmAudioFile.h"
#include "cmVectOpsTemplateMain.h"
#include "cmStack.h"
#include "cmProcObj.h"
#include "cmProcTemplateMain.h"
#include "cmVectOps.h"
#include "cmProc.h"
#include "cmProc2.h"
#include "cmRbm.h"
typedef struct
{
double trainErr;
double testErr;
} cmRbmMonitor_t;
cmRbmRC_t cmRbmWriteMonitorFile( cmCtx_t* c, cmStackH_t monH, const cmChar_t* fn )
{
cmRbmRC_t rc = kOkRbmRC;
cmCtx* ctx = cmCtxAlloc(NULL, c->err.rpt, cmLHeapNullHandle, cmSymTblNullHandle );
if( cmBinMtxFileWrite(fn, cmStackCount(monH), sizeof(cmRbmMonitor_t)/sizeof(double), NULL, cmStackFlatten(monH), ctx, c->err.rpt ) != cmOkRC )
{
rc = cmErrMsg(&c->err,kMonitorWrFailRbmRC,"Training monitor file '%s' write failed.",cmStringNullGuard(fn));
goto errLabel;
}
errLabel:
cmCtxFree(&ctx);
return rc;
}
double* cmRbmReadDataFile( cmCtx_t* c, const char* fn, unsigned* dimNPtr, unsigned* pointCntPtr )
{
unsigned rowCnt,colCnt,eleByteCnt;
*dimNPtr = 0;
*pointCntPtr = 0;
if( cmBinMtxFileSize(c, fn, &rowCnt, &colCnt, &eleByteCnt ) != cmOkRC )
return NULL;
double* buf = cmMemAllocZ(double,rowCnt*colCnt);
if( cmBinMtxFileRead(c, fn, rowCnt, colCnt, sizeof(double), buf,NULL) != cmOkRC )
{
cmMemFree(buf);
return NULL;
}
*dimNPtr = rowCnt;
*pointCntPtr = colCnt;
return buf;
}
// Generate a matrix of 'pointsN' random binary valued column vectors of dimension dimN.
// The first i = {0...'dimN'-1} elements of each vector contain ones with prob probV[i]
// (or zeros with prob 1 - probV[i].). probV[i] in [0.0,1.0].
// The last element in each column is set to zero.
// The returned matrix m[ dimN+1, pointsN ] is in column major order and
// must be deleted by the caller (e.g. cmMemFree(m)).
double* cmRbmGenBinaryTestData( cmCtx_t* c, const char* fn, const double* probV, unsigned dimN, unsigned pointsN )
{
if( dimN == 0 || pointsN == 0 )
return NULL;
double* m = cmMemAllocZ( double, dimN*pointsN );
unsigned i,j;
for(i=0; i<pointsN; ++i)
for(j=0; j<dimN; ++j)
m[ i*dimN + j ] = rand() < (probV[j] * RAND_MAX);
if( fn != NULL )
cmBinMtxFileWrite(fn,dimN,pointsN,NULL,m,NULL,c->err.rpt);
return m;
}
typedef struct
{
unsigned vN;
double* vs;
double* vp;
double* vb;
double* vd; // std dev. (var = std_dev^2)
unsigned hN;
double* hs;
double* hp;
double* hb;
double* W; // W[vN,hN]
cmStackH_t monH;
} cmRBM_t;
void _cmRbmPrint( cmRBM_t* r, cmRpt_t* rpt )
{
cmVOD_PrintL("hb", rpt, 1, r->hN, r->hb );
cmVOD_PrintL("hp", rpt, 1, r->hN, r->hp );
cmVOD_PrintL("hs", rpt, 1, r->hN, r->hs );
cmVOD_PrintL("vb", rpt, 1, r->vN, r->vb );
cmVOD_PrintL("vp", rpt, 1, r->vN, r->vp );
cmVOD_PrintL("vs", rpt, 1, r->vN, r->vs );
cmVOD_PrintL("W", rpt, r->vN, r->hN, r->W );
}
void _cmRbmRelease( cmRBM_t* r )
{
cmStackFree(&r->monH);
cmMemFree(r);
}
// Adjust the layer geometry to force all sizes to be a multiple of 16 bytes.
// This assumes that all data will be 8 byte doubles.
void _cmRbmAdjustSizes( unsigned* vNp, unsigned* hNp, unsigned* dNp )
{
*vNp = *vNp + (cmIsOddU(*vNp) ? 1 : 0);
*hNp = *hNp + (cmIsOddU(*hNp) ? 1 : 0);
if( dNp != NULL )
*dNp = *dNp + (cmIsOddU(*dNp) ? 1 : 0);
}
cmRBM_t* _cmRbmAlloc( cmCtx_t* ctx, unsigned vN, unsigned hN )
{
unsigned monInitCnt = 1000;
unsigned monExpandCnt = 1000;
// adjust sizes to force base array addresses to be a multiple of 16 bytes.
unsigned vn = vN;
unsigned hn = hN;
_cmRbmAdjustSizes(&vn,&hn,NULL);
unsigned rn = sizeof(cmRBM_t);
// force record to be a multiple of 16
if( rn % 16 )
rn += 16 - (rn % 16);
unsigned dn = 4*vn + 3*hn + vn*hn;
unsigned bn = rn + dn*sizeof(double);
char* cp = cmMemAllocZ(char,bn);
cmRBM_t* r = (cmRBM_t*)cp;
r->vs = (double*)(cp+rn);
r->vp = r->vs + vn;
r->vb = r->vp + vn;
r->vd = r->vb + vn;
r->hs = r->vd + vn;
r->hp = r->hs + hn;
r->hb = r->hp + hn;
r->W = r->hb + hn;
r->vN = vN;
r->hN = hN;
assert(cp+bn == (char*)(r->W + vn*hn));
if( cmStackAlloc(ctx, &r->monH, monInitCnt, monExpandCnt, sizeof(cmRbmMonitor_t)) != kOkStRC )
{
cmErrMsg(&ctx->err,kStackFailRbmRC,"Stack allocation failed for the training monitor data array.");
goto errLabel;
}
return r;
errLabel:
_cmRbmRelease(r);
return NULL;
}
void cmRbmBinaryTrain(
cmCtx_t* ctx,
cmRBM_t* r,
cmRbmTrainParms_t* p,
unsigned dMN,
const double* dM )
{
cmRpt_t* rpt = ctx->err.rpt;
bool stochFl = true;
unsigned i,j,k,ei,di;
unsigned vN = r->vN;
unsigned hN = r->hN;
// adjust the memory sizes to align all arrays on 16 byte boundaries
unsigned vn = vN;
unsigned hn = hN;
unsigned dn = p->batchCnt;
_cmRbmAdjustSizes(&vn,&hn,&dn);
unsigned mn = (3 * hn * vn) + (1 * vn) + (1 * hn) + (3 * hn * dn) + (2 * vn * dn);
double* m = cmMemAllocZ(double,mn);
double* vh0M = m; // vh0M[ hN, vN ]
double* vh1M = vh0M + hn*vn; // vh1M[ hN, vN ]
double* dwM = vh1M + hn*vn; // dwM[ hN, vN ]
double* vdbV = dwM + hn*vn; // vdbV[ vN ]
double* hdbV = vdbV + vn; // hdbV[ hN ]
double* hp0M = hdbV + hn; // hp0M[ hN, dN ]
double* hs0M = hp0M + dn * hn; // hs0M[ dN, hN ]
double* hp1M = hs0M + dn * hn; // hp1M[ hN, dN ]
double* vp1M = hp1M + dn * hn; // vp1M[ dN, vN ]
double* vs1M = vp1M + dn * vn; // vs1M[ vN, dN ]
assert( vs1M + vn * dn == m + mn );
// initilaize the weights with random values
// W = p->initW * randn(vN,hN,0.0,1.0)
for(i=0; i<vN; ++i)
cmVOD_RandomGauss( r->W + i*hN, hN, 0.0, 1.0 );
cmVOD_MultVS( r->W, hN*vN, p->initW);
if(0)
{
const cmChar_t* fn = "/home/kevin/temp/cmRbmWeight.mtx";
//cmBinMtxFileWrite(fn,hN, vN,NULL,dM,NULL,ctx->err.rpt);
cmBinMtxFileRead( ctx, fn, hN, vN, sizeof(double), r->W,NULL);
}
cmVOD_Zero( dwM, vN*hN );
cmVOD_Zero( vdbV, vN );
cmVOD_Zero( hdbV, hN );
for(ei=0; ei<p->epochCnt; ++ei)
{
unsigned dN = 0;
double err = 0;
for(di=0; di<dMN; di+=dN)
{
dN = cmMin(p->batchCnt,dMN-di);
const double* d = dM + di * vN; // d[ vN, dN ]
//
// Update hidden layer from data
//
// hp0M[hN,dN] = W[hN,vN] * d[vN,dN]
cmVOD_MultMMM(hp0M,hN,dN,r->W,d,vN);
// calc hs0M[dN,hN]
for(k=0; k<dN; ++k)
for(j=0; j<hN; ++j)
{
hp0M[ k*hN + j ] = 1.0/(1.0 + exp(-(hp0M[ k*hN + j] + r->hb[j])));
hs0M[ j*dN + k ] = rand() < hp0M[ k*hN + j ] * RAND_MAX;
if( !stochFl )
hs0M[ j*dN + k ] = hp0M[ k*hN + j ] > 0.5;
}
//
// Reconstruct visible layer from hidden
//
// vp1M[dN,vN] = hs0M[dN,hN] * W[hN,vN]
cmVOD_MultMMM(vp1M,dN,vN,hs0M,r->W,hN);
// calc vs1M[vN,dN]
for(k=0; k<dN; ++k)
for(i=0; i<vN; ++i)
{
vp1M[ i*dN + k ] = 1.0/(1.0 + exp(-( vp1M[ i*dN + k ] + r->vb[i]) ) );
vs1M[ k*vN + i ] = rand() < vp1M[ i*dN + k ] * RAND_MAX;
if( !stochFl )
vs1M[ k*vN + i ] = vp1M[ i*dN + k ] > 0.5;
// calc training error
err += pow(d[ k*vN + i ] - vp1M[ i*dN + k ],2.0);
}
//
// Update hidden layer from reconstruction
//
// hp1M[hN,dN] = W[hN,vN] * vs1[vN,dN]
cmVOD_MultMMM(hp1M,hN,dN,r->W,vs1M,vN);
// calc hp1M[hN,dN]
for(k=0; k<dN; ++k)
for(j=0; j<hN; ++j)
hp1M[ k*hN + j ] = 1.0/(1.0 + exp( -hp1M[ k*hN + j ] - r->hb[j] ));
if(0)
{
cmVOD_PrintL("hp0M",rpt,hN,dN,hp0M);
cmVOD_PrintL("hs0M",rpt,dN,hN,hs0M);
cmVOD_PrintL("vp1M",rpt,dN,vN,vp1M);
cmVOD_PrintL("vs1M",rpt,vN,dN,vs1M);
cmVOD_PrintL("hp1M",rpt,hN,dN,hp1M);
}
//
// Update Wieghts
//
// vh0M[hN,vN] = hp0M[hN,dN] * d[vN,dN]'
cmVOD_MultMMMt(vh0M, hN, vN, hp0M, d, dN );
cmVOD_MultMMMt(vh1M, hN, vN, hp1M, vs1M, dN );
for(i=0; i<hN*vN; ++i)
{
dwM[i] = p->momentum * dwM[i] + p->eta * ( (vh0M[i] - vh1M[i]) / dN );
r->W[i] += dwM[i];
}
//
// Update hidden bias
//
// sum(hp0M - hp1M,2) - sum the difference of rows of hp0M and hp1M
cmVOD_SubVV(hp0M,hN*dN,hp1M); // hp0M -= hp1M
cmVOD_SumMN(hp0M,hN,dN,hp1M); // hp1M[1:hN] = sum(hp0M,2) (note: hp1M is rused as temp space)
for(j=0; j<hN; ++j)
{
hdbV[j] = p->momentum * hdbV[j] + p->eta * (hp1M[j] / dN);
r->hb[j] += hdbV[j];
}
//
// Update visible bias
//
// sum(d - vs1M, 2)
cmVOD_SubVVV(vp1M,vN*dN,d,vs1M); // vp1M = d - vs1M (vp1M is reused as temp space)
cmVOD_SumMN(vp1M,vN,dN,vs1M); // vs1M[1:vn] = sum(vp1M,2) (vs1M is reused as temp space)
for(i=0; i<vN; ++i)
{
vdbV[i] = p->momentum * vdbV[i] + p->eta * (vs1M[i] / dN );
r->vb[i] += vdbV[i];
}
if(0)
{
cmVOD_PrintL("dwM", rpt, vN, hN, dwM );
cmVOD_PrintL("vdbV",rpt, 1, vN, vdbV );
cmVOD_PrintL("hdbV",rpt, 1, hN, hdbV );
cmVOD_PrintL("W", rpt, vN, hN, r->W );
cmVOD_PrintL("vb", rpt, 1, vN, r->vb );
cmVOD_PrintL("hb", rpt, 1, hN, r->hb );
}
} // di
cmRptPrintf(rpt,"err:%f\n",err);
if( cmStackIsValid(r->monH))
{
cmRbmMonitor_t monErr;
monErr.trainErr = err;
cmStackPush(r->monH,&monErr,1);
}
} // ei
cmRptPrintf(rpt,"eta:%f momentum:%f\n",p->eta,p->momentum);
cmVOD_PrintL("dwM", rpt, vN, hN, dwM );
cmVOD_PrintL("vdbV",rpt, 1, vN, vdbV );
cmVOD_PrintL("hdbV",rpt, 1, hN, hdbV );
cmVOD_PrintL("W", rpt, vN, hN, r->W );
cmVOD_PrintL("vb", rpt, 1, vN, r->vb );
cmVOD_PrintL("hb", rpt, 1, hN, r->hb );
cmMemFree(m);
}
void cmRbmRealTrain(
cmCtx_t* ctx,
cmRBM_t* r,
cmRbmTrainParms_t* p,
unsigned dMN,
const double* dM )
{
cmRpt_t* rpt = ctx->err.rpt;
unsigned i,j,k,ei,di;
unsigned vN = r->vN;
unsigned hN = r->hN;
// adjust the memory sizes to align all arrays on 16 byte boundaries
unsigned vn = vN;
unsigned hn = hN;
unsigned dn = p->batchCnt;
_cmRbmAdjustSizes(&vn,&hn,&dn);
unsigned mn = (3 * hn * vn) + (1 * vn) + (1 * hn) + (3 * hn * dn) + (2 * vn * dn);
double* m = cmMemAllocZ(double,mn);
double* vh0M = m; // vh0M[ hN, vN ]
double* vh1M = vh0M + hn*vn; // vh1M[ hN, vN ]
double* dwM = vh1M + hn*vn; // dwM[ hN, vN ]
double* vdbV = dwM + hn*vn; // vdbV[ vN ]
double* hdbV = vdbV + vn; // hdbV[ hN ]
double* hp0M = hdbV + hn; // hp0M[ hN, dN ]
double* hs0M = hp0M + dn * hn; // hs0M[ dN, hN ]
double* hp1M = hs0M + dn * hn; // hp1M[ hN, dN ]
double* vp1M = hp1M + dn * hn; // vp1M[ dN, vN ]
double* vs1M = vp1M + dn * vn; // vs1M[ vN, dN ]
assert( vs1M + vn * dn == m + mn );
//
// Initilaize the weights with small random values
// W = p->initW * randn(vN,hN,0.0,1.0)
for(i=0; i<vN; ++i)
cmVOD_RandomGauss( r->W + i*hN, hN, 0.0, 1.0 );
cmVOD_MultVS( r->W, hN*vN, p->initW);
if(0)
{
const cmChar_t* fn = "/home/kevin/temp/cmRbmWeight.mtx";
//cmBinMtxFileWrite(fn,hN, vN,NULL,dM,NULL,ctx->err.rpt);
cmBinMtxFileRead( ctx, fn, hN, vN, sizeof(double), r->W,NULL);
}
cmVOD_Zero( dwM, vN*hN );
cmVOD_Zero( vdbV, vN );
cmVOD_Zero( hdbV, hN );
for(ei=0; ei<p->epochCnt; ++ei)
{
unsigned dN = 0;
double err = 0;
for(di=0; di<dMN; di+=dN)
{
dN = cmMin(p->batchCnt,dMN-di);
const double* d = dM + di * vN; // d[ vN, dN ]
//
// Update hidden layer from data
//
// hp0M[hN,dN] = W[hN,vN] * d[vN,dN]
cmVOD_MultMMM(hp0M,hN,dN,r->W,d,vN);
// calc hs0M[dN,hN]
for(k=0; k<dN; ++k)
for(j=0; j<hN; ++j)
{
hp0M[ k*hN + j ] = 1.0/(1.0 + exp(-(hp0M[ k*hN + j] + r->hb[j])));
hs0M[ j*dN + k ] = rand() < hp0M[ k*hN + j ] * RAND_MAX;
}
//
// Reconstruct visible layer from hidden
//
// vp1M[dN,vN] = hs0M[dN,hN] * W[hN,vN]
cmVOD_MultMMM(vp1M,dN,vN,hs0M,r->W,hN);
// calc vs1M[vN,dN]
for(k=0; k<dN; ++k)
for(i=0; i<vN; ++i)
{
vp1M[ i*dN + k ] = r->vd[i] * vp1M[ i*dN + k ] + r->vb[i];
cmVOD_GaussPDF(vs1M + k*vN + i, 1, vp1M + i*dN + k, r->vb[i], r->vd[i] );
// calc training error
err += pow(d[ k*vN + i ] - vp1M[ i*dN + k ],2.0);
}
//
// Update hidden layer from reconstruction
//
// hp1M[hN,dN] = W[hN,vN] * vs1[vN,dN]
cmVOD_MultMMM(hp1M,hN,dN,r->W,vs1M,vN);
// calc hp1M[hN,dN]
for(k=0; k<dN; ++k)
for(j=0; j<hN; ++j)
hp1M[ k*hN + j ] = 1.0/(1.0 + exp( -hp1M[ k*hN + j ] - r->hb[j] ));
if(0)
{
cmVOD_PrintL("hp0M",rpt,hN,dN,hp0M);
cmVOD_PrintL("hs0M",rpt,dN,hN,hs0M);
cmVOD_PrintL("vp1M",rpt,dN,vN,vp1M);
cmVOD_PrintL("vs1M",rpt,vN,dN,vs1M);
cmVOD_PrintL("hp1M",rpt,hN,dN,hp1M);
}
//
// Update Wieghts
//
// vh0M[hN,vN] = hp0M[hN,dN] * d[vN,dN]'
cmVOD_MultMMMt(vh0M, hN, vN, hp0M, d, dN );
cmVOD_MultMMMt(vh1M, hN, vN, hp1M, vs1M, dN );
for(i=0,k=0; i<vN; ++i)
for(j=0; j<hN; ++j,++k)
{
dwM[k] = p->momentum * dwM[k] + p->eta * ( (vh0M[k] - vh1M[k]) / (dN * r->vd[i]) );
r->W[k] += dwM[k];
}
//
// Update hidden bias
//
// sum(hp0M - hp1M,2) - sum the difference of rows of hp0M and hp1M
cmVOD_SubVV(hp0M,hN*dN,hp1M); // hp0M -= hp1M
cmVOD_SumMN(hp0M,hN,dN,hp1M); // hp1M[1:hN] = sum(hp0M,2) (note: hp1M is rused as temp space)
for(j=0; j<hN; ++j)
{
hdbV[j] = p->momentum * hdbV[j] + p->eta * (hp1M[j] / (dN * r->vd[i] * r->vd[i]));
r->hb[j] += hdbV[j];
}
//
// Update visible bias
//
// sum(d - vs1M, 2)
cmVOD_SubVVV(vp1M,vN*dN,d,vs1M); // vp1M = d - vs1M (vp1M is reused as temp space)
cmVOD_SumMN(vp1M,vN,dN,vs1M); // vs1M[1:vn] = sum(vp1M,2) (vs1M is reused as temp space)
for(i=0; i<vN; ++i)
{
vdbV[i] = p->momentum * vdbV[i] + p->eta * (vs1M[i] / dN );
r->vb[i] += vdbV[i];
}
for(i=0; i<vN; ++i)
{
for(j=0; j<hN; ++j)
{
double sum_d = 0;
double sum_m = 0;
for(k=0; k<dN; ++k)
{
sum_d += hs0M[ j*dN + k ] * r->W[ i*hN + j ];
sum_m += hp1M[ k*hN + j ] * r->W[ i*hN + j ];
}
}
}
if(0)
{
cmVOD_PrintL("dwM", rpt, vN, hN, dwM );
cmVOD_PrintL("vdbV",rpt, 1, vN, vdbV );
cmVOD_PrintL("hdbV",rpt, 1, hN, hdbV );
cmVOD_PrintL("W", rpt, vN, hN, r->W );
cmVOD_PrintL("vb", rpt, 1, vN, r->vb );
cmVOD_PrintL("hb", rpt, 1, hN, r->hb );
}
} // di
cmRptPrintf(rpt,"err:%f\n",err);
if( cmStackIsValid(r->monH))
{
cmRbmMonitor_t monErr;
monErr.trainErr = err;
cmStackPush(r->monH,&monErr,1);
}
} // ei
cmRptPrintf(rpt,"eta:%f momentum:%f\n",p->eta,p->momentum);
cmVOD_PrintL("dwM", rpt, vN, hN, dwM );
cmVOD_PrintL("vdbV",rpt, 1, vN, vdbV );
cmVOD_PrintL("hdbV",rpt, 1, hN, hdbV );
cmVOD_PrintL("W", rpt, vN, hN, r->W );
cmVOD_PrintL("vb", rpt, 1, vN, r->vb );
cmVOD_PrintL("hb", rpt, 1, hN, r->hb );
cmMemFree(m);
}
void cmRbmBinaryTest( cmCtx_t* ctx )
{
const char* monitorFn = "/home/kevin/temp/cmRbmMonitor0.mtx";
const char* dataFn = "/home/kevin/temp/cmRbmData0.mtx";
unsigned pointsN = 1000;
unsigned dimN = 4;
unsigned vN = dimN;
unsigned hN = 32;
//double probV[] = {0.1,0.2,0.8,0.7};
cmRbmTrainParms_t r;
cmRBM_t* rbm;
r.maxX = 1.0;
r.minX = 0.0;
r.initW = 0.1;
r.eta = 0.01;
r.holdOutFrac = 0.1;
r.epochCnt = 10;
r.momentum = 0.5;
r.batchCnt = 10;
if(0)
{
vN = 4;
hN = 6;
double d[] = {
0, 1, 1, 1,
1, 1, 1, 1,
0, 0, 1, 0,
0, 0, 1, 0,
0, 1, 1, 0,
0, 1, 1, 1,
1, 1, 1, 1,
0, 0, 1, 0,
0, 0, 1, 0,
0, 1, 1, 0
};
if( (rbm = _cmRbmAlloc(ctx, vN, hN )) == NULL )
return;
pointsN = sizeof(d) / (sizeof(d[0]) * vN);
cmRbmBinaryTrain(ctx,rbm,&r,pointsN,d);
return;
}
if( (rbm = _cmRbmAlloc(ctx, vN, hN )) == NULL )
return;
//double* data0M = cmRbmGenBinaryTestData(ctx,dataFn,probV,dimN,pointsN);
double* data0M = cmRbmReadDataFile(ctx,dataFn,&dimN,&pointsN);
double t[ vN ];
// Sum the columns of sp[srn,scn] into dp[scn].
// dp[] is zeroed prior to computing the sum.
cmVOD_SumMN(data0M, dimN, pointsN, t );
cmVOD_Print( &ctx->rpt, 1, dimN, t );
if(0)
{
//
// Standardize data (subtract mean and divide by standard deviation)
// then set the visible layers initial standard deviation to 1.0.
//
cmVOD_StandardizeRows( data0M, rbm->vN, pointsN, NULL, NULL );
cmVOD_Fill( rbm->vd, rbm->vN, 1.0 );
cmRbmRealTrain(ctx,rbm,&r,pointsN,data0M);
}
cmRbmBinaryTrain(ctx,rbm,&r,pointsN,data0M);
cmRbmWriteMonitorFile(ctx, rbm->monH, monitorFn );
cmMemFree(data0M);
_cmRbmRelease(rbm);
}