void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray*prhs[]) { int i; if (nrhs < 4) mexErrMsgTxt("At least 4 arguments are required even nb of input arguments required."); else if (nlhs != 1) mexErrMsgTxt("yael_fisher produces exactly 1 output argument."); int flags = GMM_FLAGS_MU; int verbose = 0; int fishernorm1 = 1; if(mxGetClassID(PARAM_V)!=mxSINGLE_CLASS) mexErrMsgTxt("need single precision array."); if(mxGetClassID(PARAM_W)!=mxSINGLE_CLASS) mexErrMsgTxt("need single precision array."); if(mxGetClassID(PARAM_MU)!=mxSINGLE_CLASS) mexErrMsgTxt("need single precision array."); if(mxGetClassID(PARAM_SIGMA)!=mxSINGLE_CLASS) mexErrMsgTxt("need single precision array."); float *v = (float*) mxGetPr (PARAM_V); float *w = (float*) mxGetPr (PARAM_W); float *mu = (float*) mxGetPr (PARAM_MU); float *sigma = (float*) mxGetPr (PARAM_SIGMA); { int i; for(i = 4 ; i < nrhs ; i += 1) { char varname[256]; if (mxGetClassID(prhs[i]) != mxCHAR_CLASS) mexErrMsgTxt ("variable name required"); if (mxGetString (prhs[i], varname, 256) != 0) mexErrMsgTxt ("Could not convert string data"); if (!strcmp(varname, "sigma")) flags |= GMM_FLAGS_SIGMA; else if (!strcmp(varname,"weights")) flags |= GMM_FLAGS_W; else if (!strcmp(varname,"nomu")) flags &= ~ GMM_FLAGS_MU; else if (!strcmp(varname,"verbose")) verbose = 1; else if (!strcmp(varname,"nonorm")) fishernorm1 = 0; else mexErrMsgTxt("unknown variable name"); } } if (verbose) { fprintf (stdout, "v -> %ld x %ld\n", mxGetM (PARAM_V), mxGetN (PARAM_V)); fprintf (stdout, "w -> %ld x %ld\n", mxGetM (PARAM_W), mxGetN (PARAM_W)); fprintf (stdout, "mu -> %ld x %ld\n", mxGetM (PARAM_MU), mxGetN (PARAM_MU)); fprintf (stdout, "sigma -> %ld x %ld\n", mxGetM (PARAM_SIGMA), mxGetN (PARAM_SIGMA)); } int d = mxGetM (PARAM_V); /* vector dimensionality */ int n = mxGetN (PARAM_V); /* number of fisher vector to produce */ int k = mxGetN (PARAM_W); /* number of gaussian */ if (verbose) fprintf (stdout, "d = %d\nn = %d\nk = %d\n", d, n, k); if (mxGetM (PARAM_MU) != d || mxGetM (PARAM_SIGMA) != d || mxGetN (PARAM_MU) !=k || mxGetN (PARAM_SIGMA) != k || (mxGetM (PARAM_W) != 1 && mxGetN (PARAM_W) != 1) ) mexErrMsgTxt("Invalid input dimensionalities."); /* ouptut: GMM, i.e., weights, mu and variances */ gmm_t g = {d, k, w, mu, sigma}; int dout = gmm_fisher_sizeof (&g, flags); if (verbose) fprintf (stdout, "Size of the fisher vector = %d\n", dout); plhs[0] = mxCreateNumericMatrix (dout, n, mxSINGLE_CLASS, mxREAL); float * vf = (float *) mxGetPr (plhs[0]); #pragma omp parallel for private (i) for (i = 0 ; i < n ; i++) { gmm_fisher (1, v + i * d, &g, flags, vf + i * dout); } }
void gmm_fisher_save_soft_assgn(int n, const float *v, const gmm_t * g, int flags, float *dp_dlambda, float *word_total_soft_assignment) { long d=g->d, k=g->k; float *p = fvec_new(n * k); long i,j,l; long ii=0; float * vp = NULL; /* v*p */ float * sum_pj = NULL; /* sum of p's for a given j */ gmm_compute_p(n,v,g,p,flags | GMM_FLAGS_W); #define P(j,i) p[(i)*k+(j)] #define V(l,i) v[(i)*d+(l)] #define MU(l,j) g->mu[(j)*d+(l)] #define SIGMA(l,j) g->sigma[(j)*d+(l)] #define VP(l,j) vp[(j)*d+(l)] // Save total soft assignment per centroid if (word_total_soft_assignment != NULL) { for (j=0; j<k; j++) { double sum=0; for (i=0; i<n; i++) { sum += P(j,i); } if (n != 0) { word_total_soft_assignment[j] = (float)(sum/n); } else { word_total_soft_assignment[j] = 0.0; } } } if(flags & GMM_FLAGS_W) { for(j=1; j<k; j++) { double accu=0; for(i=0; i<n; i++) accu+= P(j,i)/g->w[j] - P(0,i)/g->w[0]; /* normalization */ double f=n*(1/g->w[j]+1/g->w[0]); dp_dlambda[ii++]=accu/sqrt(f); } } if(flags & GMM_FLAGS_MU) { float *dp_dmu=dp_dlambda+ii; #define DP_DMU(l,j) dp_dmu[(j)*d+(l)] if(0) { /* simple and slow */ for(j=0; j<k; j++) { for(l=0; l<d; l++) { double accu=0; for(i=0; i<n; i++) accu += P(j,i) * (V(l,i)-MU(l,j)) / SIGMA(l,j); DP_DMU(l,j)=accu; } } } else { /* complicated and fast */ /* precompute tables that may be useful for sigma too */ vp = fvec_new(k * d); fmat_mul_tr(v,p,d,k,n,vp); sum_pj = fvec_new(k); for(j=0; j<k; j++) { double sum=0; for(i=0; i<n; i++) sum += P(j,i); sum_pj[j] = sum; } for(j=0; j<k; j++) { for(l=0; l<d; l++) DP_DMU(l,j) = (VP(l,j) - MU(l,j) * sum_pj[j]) / SIGMA(l,j); } } /* normalization */ if(!(flags & GMM_FLAGS_NO_NORM)) { for(j=0; j<k; j++) for(l=0; l<d; l++) { float nf = sqrt(n*g->w[j]/SIGMA(l,j)); if(nf > 0) DP_DMU(l,j) /= nf; } } #undef DP_DMU ii+=d*k; } if(flags & (GMM_FLAGS_SIGMA | GMM_FLAGS_1SIGMA)) { if(flags & GMM_FLAGS_1SIGMA) { /* fast not implemented for 1 sigma */ for(j=0; j<k; j++) { double accu2=0; for(l=0; l<d; l++) { double accu=0; for(i=0; i<n; i++) accu += P(j,i) * (sqr(V(l,i)-MU(l,j)) / SIGMA(l,j) - 1) / sqrt(SIGMA(l,j)); if(flags & GMM_FLAGS_SIGMA) { double f=flags & GMM_FLAGS_NO_NORM ? 1.0 : 2*n*g->w[j]/SIGMA(l,j); dp_dlambda[ii++]=accu/sqrt(f); } accu2+=accu; } if(flags & GMM_FLAGS_1SIGMA) { double f=flags & GMM_FLAGS_NO_NORM ? 1.0 : 2*d*n*g->w[j]/SIGMA(0,j); dp_dlambda[ii++]=accu2/sqrt(f); } } } else { /* fast and complicated */ assert(flags & GMM_FLAGS_SIGMA); float *dp_dsigma = dp_dlambda + ii; if(!vp) { vp = fvec_new(k * d); fmat_mul_tr(v,p,d,k,n,vp); } if(!sum_pj) { sum_pj = fvec_new(k); for(j=0; j<k; j++) { double sum=0; for(i=0; i<n; i++) sum += P(j,i); sum_pj[j] = sum; } } float *v2 = fvec_new(n * d); for(i = n*d-1 ; i >= 0; i--) v2[i] = v[i] * v[i]; float *v2p = fvec_new(k * d); fmat_mul_tr(v2,p,d,k,n,v2p); free(v2); #define V2P(l,j) v2p[(j)*d+(l)] #define DP_DSIGMA(i,j) dp_dsigma[(i)+(j)*d] for(j=0; j<k; j++) { for(l=0; l<d; l++) { double accu; accu = V2P(l, j); accu += VP(l, j) * (- 2 * MU(l,j)); accu += sum_pj[j] * (sqr(MU(l,j)) - SIGMA(l,j)); /* normalization */ double f; if(flags & GMM_FLAGS_NO_NORM) { f = pow(SIGMA(l,j), -1.5); } else { f = 1 / (SIGMA(l,j) * sqrt(2*n*g->w[j])); } DP_DSIGMA(l,j) = accu * f; } } free(v2p); #undef DP_DSIGMA #undef V2P ii += d * k; } } assert(ii==gmm_fisher_sizeof(g,flags)); #undef P #undef V #undef MU #undef SIGMA free(p); free(sum_pj); free(vp); }