implementação do algoritmo de coquetel SVD ... em uma linha de código?

89

Em um slide dentro da palestra introdutória sobre aprendizado de máquina por Andrew Ng de Stanford no Coursera, ele fornece a seguinte solução de uma linha do Octave para o problema da festa, já que as fontes de áudio são gravadas por dois microfones separados espacialmente:

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

Na parte inferior do slide está "fonte: Sam Roweis, Yair Weiss, Eero Simoncelli" e na parte inferior de um slide anterior está "Clipes de áudio cortesia de Te-Won Lee". No vídeo, o professor Ng diz:

“Portanto, você pode olhar para a aprendizagem não supervisionada como esta e perguntar: 'Quão complicado é implementar isso?' Parece que para construir este aplicativo, parece que para fazer este processamento de áudio, você escreveria uma tonelada de código, ou talvez vincularia a um monte de bibliotecas C ++ ou Java que processam áudio. Parece que seria realmente programa complicado para fazer este áudio: separar o áudio e assim por diante. Acontece que o algoritmo para fazer o que você acabou de ouvir, pode ser feito com apenas uma linha de código ... mostrado aqui. Demorou muito para os pesquisadores para chegar a esta linha de código. Portanto, não estou dizendo que este é um problema fácil. Mas acontece que, quando você usa o ambiente de programação certo, muitos algoritmos de aprendizagem serão programas realmente curtos. "

Os resultados de áudio separados reproduzidos na aula de vídeo não são perfeitos, mas, na minha opinião, incríveis. Alguém tem alguma ideia de como essa linha de código funciona tão bem? Em particular, alguém conhece uma referência que explica o trabalho de Te-Won Lee, Sam Roweis, Yair Weiss e Eero Simoncelli com respeito a essa linha de código?

ATUALIZAR

Para demonstrar a sensibilidade do algoritmo à distância de separação do microfone, a seguinte simulação (em Octave) separa os tons de dois geradores de tons separados espacialmente.

% 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;

Após cerca de 10 minutos de execução em meu laptop, a simulação gera as três figuras a seguir, ilustrando que os dois tons isolados têm as frequências corretas.

figura 1 Figura 2 Figura 3

No entanto, definir a distância de separação do microfone para zero (ou seja, dMic = 0) faz com que a simulação gere as três figuras a seguir, que ilustram que a simulação não conseguiu isolar um segundo tom (confirmado pelo único termo diagonal significativo retornado na matriz de svd).

Figura 1 sem separação de microfone Figura 2 sem separação de microfone Figura 3 sem separação de microfone

Eu esperava que a distância de separação do microfone em um smartphone fosse grande o suficiente para produzir bons resultados, mas definir a distância de separação do microfone para 5,25 polegadas (ou seja, dMic = 0,1333 metros) faz com que a simulação gere os seguintes números, menos encorajadores, ilustrando mais alto componentes de frequência no primeiro tom isolado.

Figura 1 no smartphone Figura 2 no smartphone Figura 3 no smartphone

GregS
fonte
1
Tenho vagas lembranças desta palestra, mas não consigo lembrar o que xé; é o espectrograma da forma de onda ou o quê?
Isaac
O professor Ng, em t = 5: 30 no vídeo introdutório 4 sobre aprendizagem não supervisionada, parece sugerir que x é um vetor das amostras de áudio. Talvez aquela seção repmat no argumento svd esteja implementando algum tipo de normalização de potência do sinal.
gregS

Respostas:

30

Eu também estava tentando descobrir isso, 2 anos depois. Mas obtive minhas respostas; espero que ajude alguém.

Você precisa de 2 gravações de áudio. Você pode obter exemplos de áudio em http://research.ics.aalto.fi/ica/cocktail/cocktail_en.cgi .

a referência para implementação é http://www.cs.nyu.edu/~roweis/kica.html

ok, aqui está o código -

[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);

insira a descrição da imagem aqui

Jack Z
fonte
1
Você consegue localizar uma referência que explica de forma mais explícita a lógica dessa linha de código?
Hans
Você poderia explicar como funciona a mixagem do sinal dentro do link fornecido? Usando o seu código, é bom extrair duas fontes de som dos dois arquivos mistos baixados do site. No entanto, quando tento misturar dois sinais separados, parece que o algoritmo não pode gerar o resultado correto. Estou usando a maneira ingênua de obter os sinais mistos: mic1 = 0,3 * trilha1 + 0,5 * trilha2, mic2 = 0,5 * trilha1 + 0,3 * trilha2. Esses são os sinais que tentei fornecer ao algoritmo. Muito obrigado!
yc2986
Eu sou meio novo no Matlab. Estou tendo erros na linha 3, dizendo que há problemas para concatenar 2 matrizes de dimensões diferentes. Como devo lidar com esse problema?
mshrestha de
1
Tentei esse código, mas ele não funciona muito bem ... (não
estou
17

x(t) é a voz original de um canal / microfone.

X = repmat(sum(x.*x,1),size(x,1),1).*x)*x'é uma estimativa do espectro de potência de x(t). Embora X' = X, os intervalos entre linhas e colunas não sejam os mesmos de todo. Cada linha representa o tempo do sinal, enquanto cada coluna é a frequência. Acho que esta é uma estimativa e simplificação de uma expressão mais estrita chamada espectrograma .

A decomposição de valores singulares no espectrograma é usada para fatorar o sinal em diferentes componentes com base nas informações do espectro. Os valores diagonais ssão a magnitude de diferentes componentes do espectro. As linhas ue colunas v'são os vetores ortogonais que mapeiam o componente de frequência com a magnitude correspondente para o Xespaço.

Não tenho dados de voz para testar, mas, no meu entendimento, por meio de SVD, os componentes que se enquadram nos vetores ortogonais semelhantes são agrupados com a ajuda de aprendizado não supervisionado. Digamos, se as primeiras 2 magnitudes diagonais de s estão agrupadas, então u*s_new*v'formaremos a voz de uma pessoa, onde s_newé o mesmo, sexceto que todos os elementos em (3:end,3:end)são eliminados.

Dois artigos sobre a matriz formada por som e SVD são para sua referência.

lennon310
fonte
1
gregS, matematicamente uma matriz x n por 2 x ainda pode formar um X com a operação repmat. No entanto, o espectrograma só pode mostrar o canal de cada vez. Portanto, acho que faz mais sentido usar n por 1 x a cada vez e tratar o problema como uma regressão linear (duas equações matriciais). Outras duas abordagens possíveis são (i) calcular a média de dois canais como n por 2 x; ou (ii) ligando-os juntos para construir um 2 * n-por-2 x.
lennon310
2
GregS, reconsiderei sua pergunta. Pode funcionar se você implementar repmat em n-por-2 x. Fisicamente, pode ser visto como uma média de potência de dois canais a cada vez e a cada frequência.
lennon310
Encontrei este post após assistir ao vídeo de introdução do Aprendizado de Máquina (o curso acaba de recomeçar). Queria saber se você conseguiu reproduzir a separação do áudio mostrada no vídeo, ou se foi desenvolvida durante o curso.
siritinga
@siritinga, pesquise a publicação de Andrew Ng sobre aprendizado profundo / não supervisionado em áudio, obrigado
lennon310
1
Por que $ X $ é a potência do espectro de $ x $? Ainda de acordo com a resposta de Jack Z, $ x $ não é a voz original da gravação, mas algum tipo de recíproca processada do autovalor da covariância da voz original.
Hans