freeswitch/libs/libcodec2/unittest/vq_train_jvm.c

487 lines
12 KiB
C
Executable File

/*---------------------------------------------------------------------------*\
FILE........: vq_train_jvm.c
AUTHOR......: Jean-Marc Valin
DATE CREATED: 21 Jan 2012
Multi-stage Vector Quantoser training program developed by Jean-Marc at
linux.conf.au 2012. Minor mods by David Rowe
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2012 Jean-Marc Valin
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef VALGRIND
#include <valgrind/memcheck.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define MIN(a,b) ((a)<(b)?(a):(b))
#define COEF 0.0f
#define MAX_ENTRIES 16384
void compute_weights(const float *x, float *w, int ndim)
{
int i;
w[0] = MIN(x[0], x[1]-x[0]);
for (i=1;i<ndim-1;i++)
w[i] = MIN(x[i]-x[i-1], x[i+1]-x[i]);
w[ndim-1] = MIN(x[ndim-1]-x[ndim-2], M_PI-x[ndim-1]);
for (i=0;i<ndim;i++)
w[i] = 1./(.01+w[i]);
w[0]*=3;
w[1]*=2;
}
int find_nearest(const float *codebook, int nb_entries, float *x, int ndim, float *min_dist)
{
int i, j;
int nearest = 0;
*min_dist = 1E15;
for (i=0;i<nb_entries;i++)
{
float dist=0;
for (j=0;j<ndim;j++)
dist += (x[j]-codebook[i*ndim+j])*(x[j]-codebook[i*ndim+j]);
if (dist<*min_dist)
{
*min_dist = dist;
nearest = i;
}
}
return nearest;
}
int find_nearest_weighted(const float *codebook, int nb_entries, float *x, const float *w, int ndim)
{
int i, j;
float min_dist = 1e15;
int nearest = 0;
for (i=0;i<nb_entries;i++)
{
float dist=0;
for (j=0;j<ndim;j++)
dist += w[j]*(x[j]-codebook[i*ndim+j])*(x[j]-codebook[i*ndim+j]);
if (dist<min_dist)
{
min_dist = dist;
nearest = i;
}
}
return nearest;
}
int quantize_lsp(const float *x, const float *codebook1, const float *codebook2,
const float *codebook3, int nb_entries, float *xq, int ndim)
{
int i, n1, n2, n3;
float err[ndim], err2[ndim], err3[ndim];
float w[ndim], w2[ndim], w3[ndim], min_dist;
w[0] = MIN(x[0], x[1]-x[0]);
for (i=1;i<ndim-1;i++)
w[i] = MIN(x[i]-x[i-1], x[i+1]-x[i]);
w[ndim-1] = MIN(x[ndim-1]-x[ndim-2], M_PI-x[ndim-1]);
/*
for (i=0;i<ndim;i++)
w[i] = 1./(.003+w[i]);
w[0]*=3;
w[1]*=2;*/
compute_weights(x, w, ndim);
for (i=0;i<ndim;i++)
err[i] = x[i]-COEF*xq[i];
n1 = find_nearest(codebook1, nb_entries, err, ndim, &min_dist);
for (i=0;i<ndim;i++)
{
xq[i] = COEF*xq[i] + codebook1[ndim*n1+i];
err[i] -= codebook1[ndim*n1+i];
}
for (i=0;i<ndim/2;i++)
{
err2[i] = err[2*i];
err3[i] = err[2*i+1];
w2[i] = w[2*i];
w3[i] = w[2*i+1];
}
n2 = find_nearest_weighted(codebook2, nb_entries, err2, w2, ndim/2);
n3 = find_nearest_weighted(codebook3, nb_entries, err3, w3, ndim/2);
for (i=0;i<ndim/2;i++)
{
xq[2*i] += codebook2[ndim*n2/2+i];
xq[2*i+1] += codebook3[ndim*n3/2+i];
}
return 0;
}
void split(float *codebook, int nb_entries, int ndim)
{
int i,j;
for (i=0;i<nb_entries;i++)
{
for (j=0;j<ndim;j++)
{
float delta = .01*(rand()/(float)RAND_MAX-.5);
codebook[i*ndim+j] += delta;
codebook[(i+nb_entries)*ndim+j] = codebook[i*ndim+j] - delta;
}
}
}
void update(float *data, int nb_vectors, float *codebook, int nb_entries, int ndim)
{
int i,j;
int count[nb_entries];
int nearest[nb_vectors];
float min_dist;
float total_min_dist = 0;
for (i=0;i<nb_entries;i++)
count[i] = 0;
for (i=0;i<nb_vectors;i++)
{
nearest[i] = find_nearest(codebook, nb_entries, data+i*ndim, ndim, &min_dist);
total_min_dist += min_dist;
}
for (i=0;i<nb_entries*ndim;i++)
codebook[i] = 0;
for (i=0;i<nb_vectors;i++)
{
int n = nearest[i];
count[n]++;
for (j=0;j<ndim;j++)
codebook[n*ndim+j] += data[i*ndim+j];
}
float w2=0;
for (i=0;i<nb_entries;i++)
{
for (j=0;j<ndim;j++)
codebook[i*ndim+j] *= (1./count[i]);
w2 += (count[i]/(float)nb_vectors)*(count[i]/(float)nb_vectors);
}
fprintf(stderr, "%f / %d var = %f\n", 1./w2, nb_entries, total_min_dist/nb_vectors );
}
void update_weighted(float *data, float *weight, int nb_vectors, float *codebook, int nb_entries, int ndim)
{
int i,j;
float count[MAX_ENTRIES][ndim];
int nearest[nb_vectors];
for (i=0;i<nb_entries;i++)
for (j=0;j<ndim;j++)
count[i][j] = 0;
for (i=0;i<nb_vectors;i++)
{
nearest[i] = find_nearest_weighted(codebook, nb_entries, data+i*ndim, weight+i*ndim, ndim);
}
for (i=0;i<nb_entries*ndim;i++)
codebook[i] = 0;
for (i=0;i<nb_vectors;i++)
{
int n = nearest[i];
for (j=0;j<ndim;j++)
{
float w = sqrt(weight[i*ndim+j]);
count[n][j]+=w;
codebook[n*ndim+j] += w*data[i*ndim+j];
}
}
//float w2=0;
for (i=0;i<nb_entries;i++)
{
for (j=0;j<ndim;j++)
codebook[i*ndim+j] *= (1./count[i][j]);
//w2 += (count[i]/(float)nb_vectors)*(count[i]/(float)nb_vectors);
}
//fprintf(stderr, "%f / %d\n", 1./w2, nb_entries);
}
void vq_train(float *data, int nb_vectors, float *codebook, int nb_entries, int ndim)
{
int i, j, e;
e = 1;
for (j=0;j<ndim;j++)
codebook[j] = 0;
for (i=0;i<nb_vectors;i++)
for (j=0;j<ndim;j++)
codebook[j] += data[i*ndim+j];
for (j=0;j<ndim;j++)
codebook[j] *= (1./nb_vectors);
while (e< nb_entries)
{
split(codebook, e, ndim);
fprintf(stderr, "%d\n", e);
e<<=1;
for (j=0;j<ndim;j++)
update(data, nb_vectors, codebook, e, ndim);
}
}
void vq_train_weighted(float *data, float *weight, int nb_vectors, float *codebook, int nb_entries, int ndim)
{
int i, j, e;
e = 1;
for (j=0;j<ndim;j++)
codebook[j] = 0;
for (i=0;i<nb_vectors;i++)
for (j=0;j<ndim;j++)
codebook[j] += data[i*ndim+j];
for (j=0;j<ndim;j++)
codebook[j] *= (1./nb_vectors);
while (e<nb_entries)
{
split(codebook, e, ndim);
fprintf(stderr, "%d\n", e);
e<<=1;
for (j=0;j<ndim;j++)
update_weighted(data, weight, nb_vectors, codebook, e, ndim);
}
}
int main(int argc, char **argv)
{
int i,j;
FILE *ftrain;
int nb_vectors, nb_entries, ndim;
float *data, *pred, *codebook, *codebook2, *codebook3;
float *weight, *weight2, *weight3;
float *delta, *delta2;
float tmp, err, min_dist, total_min_dist;
int ret;
char filename[256];
FILE *fcb;
printf("Jean-Marc Valin's Split VQ training program....\n");
if (argc != 5) {
printf("usage: %s TrainTextFile K(dimension) M(codebook size) VQFilesPrefix\n", argv[0]);
exit(1);
}
ndim = atoi(argv[2]);
nb_vectors = atoi(argv[3]);
nb_entries = atoi(argv[3]);
/* determine size of training file */
ftrain = fopen(argv[1],"rt"); assert(ftrain != NULL);
nb_vectors = 0;
while (1) {
if (feof(ftrain))
break;
for (j=0;j<ndim;j++)
{
ret = fscanf(ftrain, "%f ", &tmp);
}
nb_vectors++;
if ((nb_vectors % 1000) == 0)
printf("\r%d lines",nb_vectors);
}
rewind(ftrain);
printf("\nndim %d nb_vectors %d nb_entries %d\n", ndim, nb_vectors, nb_entries);
data = malloc(nb_vectors*ndim*sizeof(*data));
weight = malloc(nb_vectors*ndim*sizeof(*weight));
weight2 = malloc(nb_vectors*ndim*sizeof(*weight2));
weight3 = malloc(nb_vectors*ndim*sizeof(*weight3));
pred = malloc(nb_vectors*ndim*sizeof(*pred));
codebook = malloc(nb_entries*ndim*sizeof(*codebook));
codebook2 = malloc(nb_entries*ndim*sizeof(*codebook2));
codebook3 = malloc(nb_entries*ndim*sizeof(*codebook3));
for (i=0;i<nb_vectors;i++)
{
if (feof(ftrain))
break;
for (j=0;j<ndim;j++)
{
ret = fscanf(ftrain, "%f ", &data[i*ndim+j]);
}
}
nb_vectors = i;
#ifdef VALGRIND
VALGRIND_CHECK_MEM_IS_DEFINED(data, nb_entries*ndim);
#endif
/* determine weights for each training vector */
for (i=0;i<nb_vectors;i++)
{
compute_weights(data+i*ndim, weight+i*ndim, ndim);
for (j=0;j<ndim/2;j++)
{
weight2[i*ndim/2+j] = weight[i*ndim+2*j];
weight3[i*ndim/2+j] = weight[i*ndim+2*j+1];
}
}
/* 20ms (two frame gaps) initial predictor state */
for (i=0;i<ndim;i++) {
pred[i+ndim] = pred[i] = data[i] - M_PI*(i+1)/(ndim+1);
}
/* generate predicted data for training */
for (i=2;i<nb_vectors;i++)
{
for (j=0;j<ndim;j++)
pred[i*ndim+j] = data[i*ndim+j] - COEF*data[(i-2)*ndim+j];
}
#ifdef VALGRIND
VALGRIND_CHECK_MEM_IS_DEFINED(pred, nb_entries*ndim);
#endif
/* train first stage */
vq_train(pred, nb_vectors, codebook, nb_entries, ndim);
delta = malloc(nb_vectors*ndim*sizeof(*data));
err = 0;
total_min_dist = 0;
for (i=0;i<nb_vectors;i++)
{
int nearest = find_nearest(codebook, nb_entries, &pred[i*ndim], ndim, &min_dist);
total_min_dist += min_dist;
for (j=0;j<ndim;j++)
{
//delta[i*ndim+j] = data[i*ndim+j] - codebook[nearest*ndim+j];
//printf("%f ", delta[i*ndim+j]);
//err += (delta[i*ndim+j])*(delta[i*ndim+j]);
delta[i*ndim/2+j/2+(j&1)*nb_vectors*ndim/2] = pred[i*ndim+j] - codebook[nearest*ndim+j];
//printf("%f ", delta[i*ndim/2+j/2+(j&1)*nb_vectors*ndim/2]);
err += (delta[i*ndim/2+j/2+(j&1)*nb_vectors*ndim/2])*(delta[i*ndim/2+j/2+(j&1)*nb_vectors*ndim/2]);
}
//printf("\n");
}
fprintf(stderr, "Stage 1 LSP RMS error: %f\n", sqrt(err/nb_vectors/ndim));
fprintf(stderr, "Stage 1 LSP variance.: %f\n", total_min_dist/nb_vectors);
#if 1
vq_train(delta, nb_vectors, codebook2, nb_entries, ndim/2);
vq_train(delta+ndim*nb_vectors/2, nb_vectors, codebook3, nb_entries, ndim/2);
#else
vq_train_weighted(delta, weight2, nb_vectors, codebook2, nb_entries, ndim/2);
vq_train_weighted(delta+ndim*nb_vectors/2, weight3, nb_vectors, codebook3, nb_entries, ndim/2);
#endif
err = 0;
total_min_dist = 0;
delta2 = delta + nb_vectors*ndim/2;
for (i=0;i<nb_vectors;i++)
{
int n1, n2;
n1 = find_nearest(codebook2, nb_entries, &delta[i*ndim/2], ndim/2, &min_dist);
for (j=0;j<ndim/2;j++)
{
delta[i*ndim/2+j] = delta[i*ndim/2+j] - codebook2[n1*ndim/2+j];
err += (delta[i*ndim/2+j])*(delta[i*ndim/2+j]);
}
total_min_dist += min_dist;
n2 = find_nearest(codebook3, nb_entries, &delta2[i*ndim/2], ndim/2, &min_dist);
for (j=0;j<ndim/2;j++)
{
delta[i*ndim/2+j] = delta[i*ndim/2+j] - codebook2[n2*ndim/2+j];
err += (delta2[i*ndim/2+j])*(delta2[i*ndim/2+j]);
}
total_min_dist += min_dist;
}
fprintf(stderr, "Stage 2 LSP RMS error: %f\n", sqrt(err/nb_vectors/ndim));
fprintf(stderr, "Stage 2 LSP Variance.: %f\n", total_min_dist/nb_vectors);
float xq[ndim];
for (i=0;i<ndim;i++)
xq[i] = M_PI*(i+1)/(ndim+1);
for (i=0;i<nb_vectors;i++)
{
quantize_lsp(data+i*ndim, codebook, codebook2,
codebook3, nb_entries, xq, ndim);
/*for (j=0;j<ndim;j++)
printf("%f ", xq[j]);
printf("\n");*/
}
/* save output tables to text files */
sprintf(filename, "%s1.txt", argv[4]);
fcb = fopen(filename, "wt"); assert(fcb != NULL);
fprintf(fcb, "%d %d\n", ndim, nb_entries);
for (i=0;i<nb_entries;i++)
{
for (j=0;j<ndim;j++)
fprintf(fcb, "%f ", codebook[i*ndim+j]);
fprintf(fcb, "\n");
}
fclose(fcb);
sprintf(filename, "%s2.txt", argv[4]);
fcb = fopen(filename, "wt"); assert(fcb != NULL);
fprintf(fcb, "%d %d\n", ndim/2, nb_entries);
for (i=0;i<nb_entries;i++)
{
for (j=0;j<ndim/2;j++)
fprintf(fcb, "%f ", codebook2[i*ndim/2+j]);
fprintf(fcb, "\n");
}
fclose(fcb);
sprintf(filename, "%s3.txt", argv[4]);
fcb = fopen(filename, "wt"); assert(fcb != NULL);
fprintf(fcb, "%d %d\n", ndim/2, nb_entries);
for (i=0;i<nb_entries;i++)
{
for (j=0;j<ndim/2;j++)
fprintf(fcb, "%f ", codebook3[i*ndim/2+j]);
fprintf(fcb, "\n");
}
fclose(fcb);
return 0;
}