Tugas
Menerapkan program dalam byte minimum sumber atau kode biner yang melakukan pengenalan suara dari sampel suara (saya mengatakan "ya", "ya" atau "tidak" dalam suara atau berbisik, polos atau unik) berdasarkan sampel pelatihan dengan akurasi maksimum .
Program harus membaca train/yes0.wav
, train/no0.wav
, train/yes1.wav
dan sebagainya (ada 400 yeses dan 400 noes dalam dataset training), kemudian mulai membaca inputs/0.wav
, inputs/1.wav
sampai gagal untuk mencari file, menganalisa dan keluaran "ya" atau "tidak" (atau kata lain untuk jawaban menengah).
Jika Anda mau, Anda bisa melakukan pra- train/
pelatihan program alih-alih membaca , tetapi tabel data yang dihasilkan diperhitungkan dalam skor (dan berhati-hatilah agar tidak terlalu cocok dengan sampel pelatihan - mereka tidak tumpang tindih dengan yang diperiksa). Lebih baik untuk memasukkan program yang digunakan untuk menghasilkan tabel data sebagai tambahan dalam kasus ini.
Semua file sampel adalah file WAV stereo 16-bit kecil endian, hanya dari mik laptop, tanpa penyaringan / pengurangan noise.
Batas
Fitur terlarang:
- Menggunakan jaringan;
- Mencoba menjangkau file jawaban
inputs/key
; - Mengubah
runner
program yang menghitung akurasi; - Menggunakan perpustakaan pengenalan yang ada. Menghubungkan ke implementasi FFT tidak diizinkan: hanya fungsi matematika eksternal yang mengambil jumlah informasi konstan (seperti
sin
atauatan2
) yang diizinkan; Jika Anda ingin FFT, tambahkan saja implementasinya ke kode sumber program Anda (bisa multibahasa jika diperlukan).
Batas sumber daya:
- Program seharusnya tidak memakan waktu lebih dari 30 menit pada CPU i5 saya. Jika dibutuhkan lebih banyak, hanya output yang dihasilkan dalam 30 menit pertama yang dihitung dan semuanya dianggap setengah-cocok;
- Batas memori: 1GB (termasuk file sementara);
Alat
The tools/runner
Program secara otomatis menjalankan solusi Anda dan menghitung akurasi.
$ tools/runner solutions/example train train/key
Accuracy: 548 ‰
Itu dapat memeriksa program menggunakan data pelatihan atau menggunakan data ujian yang sebenarnya. Saya akan mencoba jawaban yang dikirim pada dataset pemeriksaan dan menerbitkan hasil (persentase akurasi) sampai saya membuat dataset publik.
Mencetak gol
Ada 5 kelas solusi tergantung pada keakuratan:
- Semua sampel menebak dengan benar: Kelas 0;
- Akurasi 950-999: Kelas 1;
- Akurasi 835-950: Kelas 2;
- Akurasi 720-834: Kelas 3;
- Akurasi 615-719: Kelas 4;
Di dalam setiap kelas, skornya adalah jumlah byte yang diambil oleh solusi.
Jawaban yang diterima: solusi terkecil di kelas nonempty terbaik.
Tautan
- Proyek Github dengan alat: https://github.com/vi/codegolf-jein
- Dataset pelatihan: http://vi-server.org/pub/codegolf-jein-train.tar.xz
- Dataset pemeriksaan tetap dirahasiakan sejauh ini, ada checksum (HMAC) yang tersedia di repositori Github.
Semua sampel harus dianggap CC-0 (Domain Publik), skrip dan program harus dianggap MIT.
Contoh solusi
Ini memberikan kualitas pengenalan yang sangat buruk, hanya menunjukkan cara membaca file dan memberikan jawaban
#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
, atau kita perlu menggunakanfoldl (+) 0
(foldl tidak khusus matematika, dan+
tidak variadic)?sum
. Saya kira itu bukan niat Anda?Jawaban:
C ++ 11 (gcc;
163916251635 byte, Kelas 1, skor = 983, 960)Mari kita memulainya. Itu mungkin kode terpanjang yang pernah saya persingkat ...
"Tidak digabung" (meskipun sulit untuk memanggil kode sumber lebih dari 1,5 ribu golf):
Saya tidak punya ide aneh jika itu akan bekerja dengan benar pada set data nyata (saya yakin tidak, tapi saya harus mencoba).
Bagaimana itu bekerja:
log(mean distribution)+10
dan kemudian dinormalisasi sehingga jumlah puncak terbesar adalah 1.dunno
.Seperti yang saya katakan, mungkin pada tes akhir itu akan diklasifikasikan sebagai "lebih buruk daripada acak". Tentu saja, saya harap tidak akan: D
Sunting: memperbaiki bug (lupa menutup file).
sumber
worse than random
. Anda benar-benar hanya perlu mengubah satu byte -distYes > distNo
, dan itu akan dilakukanbetter than random
. Atau dengan kata lain, akan sangat mencengangkan jika Anda dapat menebak hasil koin yang salah 100 kali berturut-turut! Dan bukan hal yang aneh dari algoritma sederhana yang lebih baik daripada yang lebih kompleks, jadi +1 dan saya ucapkan semoga sukses.EMFILE (Too many open files)
... Mencoba untuk memperbaiki ...Accuracy: 983 ‰; Time: 0m27.570s;
; Pemeriksaan dataset:Accuracy: 960 ‰; Time: 0m32.957s
. Kerja bagus.#define
s: P