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.
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).
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.
x
é; é o espectrograma da forma de onda ou o quê?Respostas:
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);
fonte
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 dex(t)
. EmboraX' = 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
s
são a magnitude de diferentes componentes do espectro. As linhasu
e colunasv'
são os vetores ortogonais que mapeiam o componente de frequência com a magnitude correspondente para oX
espaç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, ondes_new
é o mesmo,s
exceto 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.
fonte