鸡尾酒会algorithmSVD实现…在一行代码?
在Coursera的斯坦福大学的Andrew Ng的机器学习的介绍性演讲中,他给出了以下一行Octave解决鸡尾酒会问题的scheme,假设audio源由两个空间分离的麦克风logging:
[W,s,v]=svd((repmat(sum(x.*x,1),size(x,1),1).*x)*x');
在幻灯片的底部是“来源:山姆·罗威斯,亚力·魏斯,埃罗·西蒙切利”,在前面的幻灯片的底部是“audio剪辑礼貌的李元媛李”。 吴教授说:
“所以你可能会这样看待无监督的学习,并问:'实现这个有多复杂? 这似乎是为了构build这个应用程序,似乎要做这个audio处理,你会写很多代码,或者链接到一堆处理audio的C ++或Java库。看起来好像是一个真正的复杂的程序来做这个audio:分离出audio等等,结果发现你刚刚听到的algorithm,只需要一行代码就可以完成……这里显示的是研究人员很长一段时间想出这样的代码,所以我并不是说这是一个简单的问题,但事实certificate,当你使用正确的编程环境时,许多学习algorithm将会是一个非常短的程序。
在video讲座中播放的分离的audio结果并不完美,但在我看来,令人惊叹。 有没有人有任何关于如何一行代码performance如此出色的见解? 特别是,有没有人知道有关Te-Won Lee,Sam Roweis,Yair Weiss和Eero Simoncelli关于这一行代码的工作的参考资料?
UPDATE
为了演示该algorithm对麦克风分离距离的敏感性,下面的模拟(在八度中)将音调从两个空间分离的音调发生器中分离出来。
% 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: mc = 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 (ie, 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;
在我的笔记本电脑上执行大约10分钟后,模拟生成以下三个数字,说明两个孤立的音调具有正确的频率。
然而,将麦克风分离距离设置为零(即,dMic = 0)会导致仿真产生以下三个图,说明仿真不能隔离第二个音调(由svd的matrix中返回的单个有效对angular项确认)。
我希望智能手机上的麦克风分离距离足够大以产生好的结果,但是将麦克风间隔距离设置为5.25英寸(即,dMic = 0.1333米)导致仿真产生下面的不太令人鼓舞的数字,在第一个孤立的音调中的频率分量。
两年后,我也试图弄清楚这一点。 但是我得到了答案。 希望它会帮助某人。
你需要2个录音。 您可以从http://research.ics.aalto.fi/ica/cocktail/cocktail_en.cgi获取audio示例。;
参考实施是http://www.cs.nyu.edu/~roweis/kica.html
好的,这里的代码 –
[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)
是来自一个声道/麦克风的原始声音。
X = repmat(sum(x.*x,1),size(x,1),1).*x)*x'
是x(t)
的功率谱估计。 尽pipeX' = X
,行和列之间的间隔根本不相同。 每行表示信号的时间,而每列是频率。 我想这是一个称为谱图的更严格expression式的估计和简化。
频谱图上的奇异值分解用于基于频谱信息将信号分解成不同的分量。 s
中的对angular线值是不同频谱分量的大小。 v'
的行和v'
中的列是正交向量,其将频率分量与对应的量值映射到X
空间。
我没有语音数据来testing,但是在我的理解中,借助于SVD,将这些分量分解成相似的正交向量,希望在无监督学习的帮助下被聚类。 假设,如果来自s的前2个对angular线量值聚集,则u*s_new*v'
将形成单人声音,其中s_new
与(3:end,3:end)
处的所有元素除外(3:end,3:end)
被淘汰。
两篇关于声音形成matrix和SVD的文章供你参考。