implementazione SVD algoritmo cocktail party ... in una riga di codice?


88

In una diapositiva all'interno della lezione introduttiva sull'apprendimento automatico di Andrew Ng di Stanford a Coursera, fornisce la seguente soluzione di una riga in ottava al problema del cocktail party dato che le sorgenti audio sono registrate da due microfoni spazialmente separati:

[W,s,v]=svd((repmat(sum(x.*x,1),size(x,1),1).*x)*x');

In fondo alla diapositiva c'è "fonte: Sam Roweis, Yair Weiss, Eero Simoncelli" e in fondo a una diapositiva precedente c'è "Clip audio per gentile concessione di Te-Won Lee". Nel video, dice il professor Ng,

"Quindi potresti considerare l'apprendimento non supervisionato in questo modo e chiederti: 'Quanto è complicato implementarlo?' Sembra che per costruire questa applicazione, sembra che si debba fare questa elaborazione audio, si scriverà un sacco di codice, o magari si collegherà a un mucchio di librerie C ++ o Java che elaborano l'audio. Sembra che sarebbe davvero un programma complicato per fare questo audio: separare l'audio e così via. Si scopre che l'algoritmo fa quello che hai appena sentito, che può essere fatto con una sola riga di codice ... mostrato qui. Ci è voluto molto tempo per i ricercatori inventare questa riga di codice. Quindi non sto dicendo che sia un problema facile. Ma risulta che quando si utilizza l'ambiente di programmazione giusto molti algoritmi di apprendimento saranno programmi davvero brevi.

I risultati audio separati riprodotti nella videoconferenza non sono perfetti ma, a mio parere, sorprendenti. Qualcuno ha qualche idea su come quella riga di codice funzioni così bene? In particolare, qualcuno conosce un riferimento che spieghi il lavoro di Te-Won Lee, Sam Roweis, Yair Weiss ed Eero Simoncelli rispetto a quella riga di codice?

AGGIORNARE

Per dimostrare la sensibilità dell'algoritmo alla distanza di separazione del microfono, la seguente simulazione (in Octave) separa i toni da due generatori di toni separati spazialmente.

% define model 
f1 = 1100;              % frequency of tone generator 1; unit: Hz 
f2 = 2900;              % frequency of tone generator 2; unit: Hz 
Ts = 1/(40*max(f1,f2)); % sampling period; unit: s 
dMic = 1;               % distance between microphones centered about origin; unit: m 
dSrc = 10;              % distance between tone generators centered about origin; unit: m 
c = 340.29;             % speed of sound; unit: m / s 

% generate tones
figure(1);
t = [0:Ts:0.025];
tone1 = sin(2*pi*f1*t);
tone2 = sin(2*pi*f2*t);
plot(t,tone1); 
hold on;
plot(t,tone2,'r'); xlabel('time'); ylabel('amplitude'); axis([0 0.005 -1 1]); legend('tone 1', 'tone 2');
hold off;

% mix tones at microphones
% assume inverse square attenuation of sound intensity (i.e., inverse linear attenuation of sound amplitude)
figure(2);
dNear = (dSrc - dMic)/2;
dFar = (dSrc + dMic)/2;
mic1 = 1/dNear*sin(2*pi*f1*(t-dNear/c)) + \
       1/dFar*sin(2*pi*f2*(t-dFar/c));
mic2 = 1/dNear*sin(2*pi*f2*(t-dNear/c)) + \
       1/dFar*sin(2*pi*f1*(t-dFar/c));
plot(t,mic1);
hold on;
plot(t,mic2,'r'); xlabel('time'); ylabel('amplitude'); axis([0 0.005 -1 1]); legend('mic 1', 'mic 2');
hold off;

% use svd to isolate sound sources
figure(3);
x = [mic1' mic2'];
[W,s,v]=svd((repmat(sum(x.*x,1),size(x,1),1).*x)*x');
plot(t,v(:,1));
hold on;
maxAmp = max(v(:,1));
plot(t,v(:,2),'r'); xlabel('time'); ylabel('amplitude'); axis([0 0.005 -maxAmp maxAmp]); legend('isolated tone 1', 'isolated tone 2');
hold off;

Dopo circa 10 minuti di esecuzione sul mio computer portatile, la simulazione genera le seguenti tre figure che illustrano che i due toni isolati hanno le frequenze corrette.

Figura 1 figura 2 Figura 3

Tuttavia, impostando la distanza di separazione del microfono su zero (cioè, dMic = 0), la simulazione genera invece le seguenti tre figure che illustrano che la simulazione non poteva isolare un secondo tono (confermato dal singolo termine diagonale significativo restituito nella matrice di svd).

Figura 1 senza separazione del microfono Figura 2 senza separazione del microfono Figura 3 senza separazione del microfono

Speravo che la distanza di separazione del microfono su uno smartphone fosse abbastanza grande da produrre buoni risultati, ma impostando la distanza di separazione del microfono a 5,25 pollici (cioè, dMic = 0,1333 metri) la simulazione genera le seguenti cifre, meno che incoraggianti, che illustrano maggiori componenti di frequenza nel primo tono isolato.

Figura 1 su smartphone Figura 2 su smartphone Figura 3 su smartphone


1
Ho vaghi ricordi di questa conferenza, ma non ricordo cosa xsia; è lo spettrogramma della forma d'onda o cosa?
Isaac

Il professor Ng, at = 5: 30 nel video introduttivo 4 sull'apprendimento non supervisionato, sembra suggerire che x sia un vettore dei campioni audio. Forse quella sezione repmat nell'argomento svd sta implementando una sorta di normalizzazione della potenza del segnale.
gregS

Risposte:


28

Stavo cercando di capire anche questo, 2 anni dopo. Ma ho le mie risposte; si spera che possa aiutare qualcuno.

Hai bisogno di 2 registrazioni audio. Puoi ottenere esempi audio da http://research.ics.aalto.fi/ica/cocktail/cocktail_en.cgi .

il riferimento per l'implementazione è http://www.cs.nyu.edu/~roweis/kica.html

ok, ecco il codice -

[x1, Fs1] = audioread('mix1.wav');
[x2, Fs2] = audioread('mix2.wav');
xx = [x1, x2]';
yy = sqrtm(inv(cov(xx')))*(xx-repmat(mean(xx,2),1,size(xx,2)));
[W,s,v] = svd((repmat(sum(yy.*yy,1),size(yy,1),1).*yy)*yy');

a = W*xx; %W is unmixing matrix
subplot(2,2,1); plot(x1); title('mixed audio - mic 1');
subplot(2,2,2); plot(x2); title('mixed audio - mic 2');
subplot(2,2,3); plot(a(1,:), 'g'); title('unmixed wave 1');
subplot(2,2,4); plot(a(2,:),'r'); title('unmixed wave 2');

audiowrite('unmixed1.wav', a(1,:), Fs1);
audiowrite('unmixed2.wav', a(2,:), Fs1);

inserisci qui la descrizione dell'immagine


1
Sei in grado di individuare un riferimento che spieghi in modo più esplicito la logica di quella riga di codice?
Hans,

Potresti spiegare come funziona il missaggio del segnale all'interno del link che hai fornito? Utilizzando il tuo codice è bene estrarre due sorgenti sonore dai due file misti scaricati dal sito. Tuttavia, quando provo a mescolare due segnali separati da solo, sembra che l'algoritmo non possa produrre il risultato corretto. Sto usando il modo ingenuo per ottenere i segnali misti: mic1 = 0.3 * track1 + 0.5 * track2, mic2 = 0.5 * track1 + 0.3 * track2. Questi sono i segnali che ho cercato di fornire all'algoritmo. Grazie mille!
yc2986

Sono un po 'nuovo su Matlab. Sto riscontrando errori nella riga 3 dicendo che ha problemi a concatenare 2 matrici di dimensioni diverse. Come dovrei gestire questo problema?
mshrestha

1
Ho provato quel codice ma non funziona molto bene ... (non ti
biasimo

17

x(t) è la voce originale di un canale / microfono.

X = repmat(sum(x.*x,1),size(x,1),1).*x)*x'è una stima dello spettro di potenza di x(t). Tuttavia X' = X, gli intervalli tra righe e colonne non sono affatto gli stessi. Ogni riga rappresenta il tempo del segnale, mentre ogni colonna è la frequenza. Immagino che questa sia una stima e una semplificazione di un'espressione più rigorosa chiamata spettrogramma .

La decomposizione del valore singolare sullo spettrogramma viene utilizzata per fattorizzare il segnale in diversi componenti in base alle informazioni sullo spettro. I valori diagonali in ssono l'ampiezza delle diverse componenti dello spettro. Le righe in ue le colonne in v'sono i vettori ortogonali che mappano la componente di frequenza con la grandezza corrispondente allo Xspazio.

Non ho dati vocali da testare, ma nella mia comprensione, per mezzo di SVD, i componenti che rientrano in vettori ortogonali simili possono essere raggruppati con l'aiuto di un apprendimento non supervisionato. Diciamo, se le prime 2 grandezze diagonali da s sono raggruppate, allora u*s_new*v'formerà la voce di una persona, dove s_newè la stessa stranne che tutti gli elementi in (3:end,3:end)vengono eliminati.

Due articoli sulla matrice in formato sonoro e sull'SVD sono per riferimento.


1
gregS, matematicamente una matrice x 2 x può ancora formare una X con l'operazione repmat. Tuttavia, lo spettrogramma può mostrare solo il canale ogni volta. Quindi penso che abbia più senso usare n per 1 x ogni volta e trattare il problema come una regressione lineare (due equazioni di matrice). Altri due possibili approcci sono (i) calcolare la media di due canali come n per 2 x; o (ii) legandoli insieme per costruire un 2 * n-per-2 x.
lennon310

2
gregS, ho riconsiderato la tua domanda. Potrebbe funzionare se si implementa repmat su un n-by-2 x. Fisicamente può essere visto come una media di potenza da due canali alla volta e ogni frequenza.
lennon310

Ho trovato questo post dopo aver visto il video introduttivo di Machine Learning (il corso è appena iniziato di nuovo). Mi chiedevo se sei riuscito a riprodurre la separazione audio mostrata nel video, o se è stata sviluppata durante il corso.
siritinga

@siritinga per favore cerca la pubblicazione di Andrew Ng sull'apprendimento senza supervisione / deep learning sull'audio, grazie
lennon310

1
Perché $ X $ è la potenza dello spettro di $ x $? Sempre secondo la risposta di Jack Z, $ x $ non è la voce originale della registrazione ma una sorta di reciproco processato dell'autovalore della covarianza della voce originale.
Hans,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.