Dans une diapositive de la conférence d'introduction à l'apprentissage automatique donnée par Andrew Ng de Stanford à Coursera, il donne la solution Octave à une ligne suivante pour résoudre le problème du cocktail, car les sources audio sont enregistrées par deux microphones séparés dans l'espace:
[W,s,v]=svd((repmat(sum(x.*x,1),size(x,1),1).*x)*x');
Au bas de la diapositive est "source: Sam Roweis, Yair Weiss, Eero Simoncelli" et au bas d'une diapositive précédente est "Extraits audio de courtoisie de Te-Won Lee". Dans la vidéo, le professeur Ng dit:
"Ainsi, vous pourriez envisager un apprentissage non supervisé comme celui-ci et demander:" À quel point est-il compliqué de le mettre en œuvre? " Il semble que pour construire cette application, il semblerait que vous fassiez ce traitement audio, vous écrivez une tonne de code, ou peut-être un lien dans un tas de bibliothèques C++ ou Java qui traitent l'audio. Ce serait un programme vraiment compliqué pour faire cet audio: séparer l'audio et ainsi de suite. Il s'avère que l'algorithme permet de faire ce que vous venez d'entendre, cela peut être fait avec une seule ligne de code ... affichée ici. Les chercheurs ont mis longtemps à proposer cette ligne de code. Je ne dis donc pas que c'est un problème facile. Mais il s'avère que lorsque vous utilisez le bon environnement de programmation, de nombreux algorithmes d'apprentissage seront des programmes très courts. "
Les résultats audio séparés lus dans la conférence vidéo ne sont pas parfaits mais, à mon avis, étonnants. Quelqu'un at-il une idée de la performance de cette ligne de code? En particulier, connaissez-vous une référence qui explique le travail de Te-Won Lee, Sam Roweis, Yair Weiss et Eero Simoncelli en ce qui concerne cette ligne de code?
MISE À JOUR
Pour démontrer la sensibilité de l'algorithme à la distance de séparation du microphone, la simulation suivante (en octave) sépare les tonalités de deux générateurs de sons séparés dans l'espace.
% 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;
Après environ 10 minutes d’exécution sur mon ordinateur portable, la simulation génère les trois figures suivantes illustrant que les deux tonalités isolées ont les fréquences correctes.
Toutefois, si vous définissez la distance de séparation du microphone sur zéro (c’est-à-dire que dMic = 0), la simulation génère les trois figures suivantes illustrant la simulation. Elle ne peut pas isoler une seconde tonalité (confirmée par le seul terme diagonal significatif renvoyé dans la matrice de svd).
J'espérais que la distance de séparation du microphone sur un smartphone serait suffisamment grande pour produire de bons résultats, mais si vous définissez la distance de séparation du microphone à 5,25 pouces (c'est-à-dire, dMic = 0,13333 mètres), la simulation génère les résultats suivants, moins qu'encourageants, illustrant des valeurs plus élevées. composantes de fréquence dans le premier ton isolé.
J'essayais de comprendre cela aussi, 2 ans plus tard. Mais j'ai eu mes réponses; j'espère que ça va aider quelqu'un.
Vous avez besoin de 2 enregistrements audio. Vous pouvez obtenir des exemples audio de http://research.ics.aalto.fi/ica/cocktail/cocktail_en.cgi .
la référence pour la mise en oeuvre est http://www.cs.nyu.edu/~roweis/kica.html
ok, voici le code -
[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);
x(t)
est la voix originale d'un canal/microphone.
X = repmat(sum(x.*x,1),size(x,1),1).*x)*x'
est une estimation du spectre de puissance de x(t)
. Bien que X' = X
, les intervalles entre les lignes et les colonnes ne sont pas du tout identiques. Chaque ligne représente l'heure du signal, tandis que chaque colonne est une fréquence. Je suppose que ceci est une estimation et une simplification d’une expression plus stricte appelée spectrogramme .
décomposition en valeurs singulières sur le spectrogramme est utilisé pour factoriser le signal en différentes composantes en fonction des informations du spectre. Les valeurs diagonales dans s
représentent l'amplitude de différentes composantes du spectre. Les lignes dans u
et les colonnes dans v'
sont les vecteurs orthogonaux qui mappent la composante de fréquence avec la magnitude correspondante à X
espace.
Je n'ai pas de données vocales à tester, mais d'après ce que j'ai compris, les composants qui tombent dans les vecteurs orthogonaux similaires sont, espérons-le, regroupés à l'aide d'un apprentissage non supervisé. Disons que si les 2 premières grandeurs diagonales de s sont regroupées, alors u*s_new*v'
formera la voix à une personne, où s_new
est identique à s
à l'exception de tous les éléments de (3:end,3:end)
sont éliminés.
Deux articles sur les matrice sonore et SVD sont pour référence.