Tarea
Implemente un programa en bytes mínimos de código fuente o binario que haga reconocimiento de voz de una muestra de voz (yo digo "sí", "sí" o "no" en voz o en susurro, simple o peculiarmente) en base a muestras de entrenamiento con la máxima precisión .
El programa debe leer train/yes0.wav
, train/no0.wav
, train/yes1.wav
y así sucesivamente (hay 400 síes y 400 noes en formación de datos), a continuación, comenzar a leer inputs/0.wav
, inputs/1.wav
hasta que no encuentra el archivo, analizarlo y dar salida a "sí" o (u otra palabra "no" por respuesta intermedia).
Si lo desea, puede entrenar previamente el programa en lugar de leerlo train/
, pero la tabla de datos resultante cuenta para el puntaje (y tenga cuidado de adaptarse demasiado a las muestras de entrenamiento, no se superponen con las del examen). Es mejor incluir el programa utilizado para producir la tabla de datos como un anexo en este caso.
Todos los archivos de muestra son pequeños archivos WAV estéreo endian de 16 bits, solo del micrófono de una computadora portátil, sin filtro / reducción de ruido.
Límites
Características prohibidas:
- Usando la red;
- Intentando llegar al archivo de respuestas
inputs/key
; - Subvertir el
runner
programa que calcula la precisión; - Utilizando bibliotecas de reconocimiento existentes. No se permite vincular a la implementación de FFT: solo se permiten funciones matemáticas externas que toman una cantidad constante de información (como
sin
oatan2
); Si desea FFT, simplemente agregue su implementación al código fuente de su programa (puede ser multilingüe si es necesario).
Límites de recursos:
- El programa no debería tomar más de 30 minutos de tiempo de CPU en mi computadora portátil i5. Si se necesita más, solo se cuenta la producción producida en los primeros 30 minutos y se supone que todo lo demás es un medio partido;
- Límite de memoria: 1 GB (incluidos los archivos temporales);
Herramientas
El tools/runner
programa ejecuta automáticamente su solución y calcula la precisión.
$ tools/runner solutions/example train train/key
Accuracy: 548 ‰
Puede examinar el programa usando datos de entrenamiento o usando datos de exámenes reales. Probaré las respuestas enviadas en el conjunto de datos del examen y publicaré los resultados (porcentaje de precisión) hasta que haga público el conjunto de datos.
Tanteo
Hay 5 clases de solución según la precisión:
- Todas las muestras se adivinaron correctamente: clase 0;
- Precisión 950-999: Clase 1;
- Precisión 835-950: clase 2;
- Precisión 720-834: clase 3;
- Precisión 615-719: clase 4;
Dentro de cada clase, el puntaje es el número de bytes que toma la solución.
Respuesta aceptada: la solución más pequeña en la mejor clase no vacía.
Campo de golf
- Proyecto Github con herramientas: https://github.com/vi/codegolf-jein
- Conjunto de datos de entrenamiento: http://vi-server.org/pub/codegolf-jein-train.tar.xz
- El conjunto de datos de examen se mantiene privado hasta ahora, hay sumas de verificación (HMAC) disponibles en el repositorio de Github.
Todas las muestras deben considerarse CC-0 (dominio público), los scripts y los programas deben considerarse MIT.
Solución de ejemplo
Proporciona una calidad de reconocimiento muy pobre, solo muestra cómo leer archivos y generar respuestas
#define _BSD_SOURCE
#include <stdio.h>
#include <assert.h>
#include <endian.h>
#define Nvols 30
#define BASS_WINDOW 60
#define MID_WINDOW 4
struct training_info {
double bass_volumes[Nvols];
double mid_volumes[Nvols];
double treble_volumes[Nvols];
int n;
};
struct training_info yes;
struct training_info no;
static int __attribute__((const)) mod(int n, int d) {
int m = n % d;
if (m < 0) m+=d;
return m;
}
// harccoded to 2 channel s16le
int get_file_info(const char* name, struct training_info *inf) {
FILE* in = fopen(name, "rb");
if (!in) return -1;
setvbuf(in, NULL, _IOFBF, 65536);
inf->n = 1;
fseek(in, 0, SEEK_END);
long filesize = ftell(in);
fseek(in, 128, SEEK_SET);
filesize -= 128; // exclude header and some initial samples
int nsamples = filesize / 4;
double bass_a=0, mid_a=0;
const int HISTSIZE = 101;
double xhistory[HISTSIZE];
int histpointer=0;
int histsize = 0;
//FILE* out = fopen("debug.raw", "wb");
int i;
for (i=0; i<Nvols; ++i) {
int j;
double total_vol = 0;
double bass_vol = 0;
double mid_vol = 0;
double treble_vol = 0;
for (j=0; j<nsamples / Nvols; ++j) {
signed short int l, r; // a sample
if(fread(&l, 2, 1, in)!=1) break;
if(fread(&r, 2, 1, in)!=1) break;
double x = 1/65536.0 * ( le16toh(l) + le16toh(r) );
bass_a += x;
mid_a += x;
if (histsize == HISTSIZE-1) bass_a -= xhistory[mod(histpointer-BASS_WINDOW,HISTSIZE)];
if (histsize == HISTSIZE-1) mid_a -= xhistory[mod(histpointer-MID_WINDOW ,HISTSIZE)];
double bass = bass_a / BASS_WINDOW;
double mid = mid_a / MID_WINDOW - bass;
double treble = x - mid_a/MID_WINDOW;
xhistory[histpointer++] = x;
if(histpointer>=HISTSIZE) histpointer=0;
if(histsize < HISTSIZE-1) ++histsize;
total_vol += bass*bass + mid*mid + treble*treble;
bass_vol += bass*bass;
mid_vol += mid*mid;
treble_vol += treble*treble;
/*
signed short int y;
y = 65536 * bass;
y = htole16(y);
fwrite(&y, 2, 1, out);
fwrite(&y, 2, 1, out);
*/
}
inf->bass_volumes[i] = bass_vol / total_vol;
inf->mid_volumes[i] = mid_vol / total_vol;
inf->treble_volumes[i] = treble_vol / total_vol;
//fprintf(stderr, "%lf %lf %lf %s\n", inf->bass_volumes[i], inf->mid_volumes[i], inf->treble_volumes[i], name);
}
fclose(in);
return 0;
}
static void zerotrdata(struct training_info *inf) {
int i;
inf->n = 0;
for (i=0; i<Nvols; ++i) {
inf->bass_volumes[i] = 0;
inf->mid_volumes[i] = 0;
inf->treble_volumes[i] = 0;
}
}
static void train1(const char* prefix, struct training_info *inf)
{
char buf[50];
int i;
for(i=0;; ++i) {
sprintf(buf, "%s%d.wav", prefix, i);
struct training_info ti;
if(get_file_info(buf, &ti)) break;
++inf->n;
int j;
for (j=0; j<Nvols; ++j) {
inf->bass_volumes[j] += ti.bass_volumes[j];
inf->mid_volumes[j] += ti.mid_volumes[j];
inf->treble_volumes[j] += ti.treble_volumes[j];
}
}
int j;
for (j=0; j<Nvols; ++j) {
inf->bass_volumes[j] /= inf->n;
inf->mid_volumes[j] /= inf->n;
inf->treble_volumes[j] /= inf->n;
}
}
static void print_part(struct training_info *inf, FILE* f) {
fprintf(f, "%d\n", inf->n);
int j;
for (j=0; j<Nvols; ++j) {
fprintf(f, "%lf %lf %lf\n", inf->bass_volumes[j], inf->mid_volumes[j], inf->treble_volumes[j]);
}
}
static void train() {
zerotrdata(&yes);
zerotrdata(&no);
fprintf(stderr, "Training...\n");
train1("train/yes", &yes);
train1("train/no", &no);
fprintf(stderr, "Training completed.\n");
//print_part(&yes, stderr);
//print_part(&no, stderr);
int j;
for (j=0; j<Nvols; ++j) {
if (yes.bass_volumes[j] > no.bass_volumes[j]) { yes.bass_volumes[j] = 1; no.bass_volumes[j] = 0; }
if (yes.mid_volumes[j] > no.mid_volumes[j]) { yes.mid_volumes[j] = 1; no.mid_volumes[j] = 0; }
if (yes.treble_volumes[j] > no.treble_volumes[j]) { yes.treble_volumes[j] = 1; no.treble_volumes[j] = 0; }
}
}
double delta(struct training_info *t1, struct training_info *t2) {
int j;
double d = 0;
for (j=0; j<Nvols; ++j) {
double rb = t1->bass_volumes[j] - t2->bass_volumes[j];
double rm = t1->mid_volumes[j] - t2->mid_volumes[j];
double rt = t1->treble_volumes[j] - t2->treble_volumes[j];
d += rb*rb + rm*rm + rt*rt;
}
return d;
}
int main(int argc, char* argv[])
{
(void)argc; (void)argv;
train();
int i;
int yes_count = 0;
int no_count = 0;
for (i=0;; ++i) {
char buf[60];
sprintf(buf, "inputs/%d.wav", i);
struct training_info ti;
if(get_file_info(buf, &ti)) break;
double dyes = delta(&yes, &ti);
double dno = delta(&no, &ti);
//printf("%lf %lf %s ", dyes, dno, buf);
if (dyes > dno) {
printf("no\n");
++no_count;
} else {
printf("yes\n");
++yes_count;
}
}
fprintf(stderr, "yeses: %d noes: %d\n", yes_count, no_count);
}
sum
, o tenemos que usarlofoldl (+) 0
(foldl no es específico de matemáticas y+
no es variable)?sum
. Supongo que esa no es tu intención?Respuestas:
C ++ 11 (gcc;
163916251635 bytes, Clase 1, puntaje = 983, 960)Vamos a ponerlo en marcha. Es probablemente el código más largo que he acortado ...
"Ungolfed" (aunque es difícil llamar golfed a un código fuente de más de 1.5K):
No tengo ni idea de si funcionará correctamente en un conjunto de datos real (apuesto a que no lo hará, pero debo intentarlo).
Cómo funciona:
log(mean distribution)+10
y luego normalicé para que la suma de los picos más grandes fuera 1.dunno
.Como dije, probablemente en las pruebas finales se clasificará como "incluso peor que al azar". Por supuesto, espero que no sea así: D
Editar: error corregido (olvidé cerrar los archivos).
fuente
worse than random
. Literalmente, solo necesita cambiar un bytedistYes > distNo
, y lo harábetter than random
. O para decirlo de otra manera, ¡sería bastante sorprendente si pudieras adivinar el resultado de un lanzamiento de moneda incorrecto 100 veces seguidas! Y no es extraño que los algoritmos simples superen el rendimiento de los más complejos, por lo que +1 y les deseo buena suerte.EMFILE (Too many open files)
... Tratando de arreglar ...Accuracy: 983 ‰; Time: 0m27.570s;
; conjunto de datos de examen:Accuracy: 960 ‰; Time: 0m32.957s
. Buen trabajo.#define
s: P