在斯坦福大学的 Andrew Ng 在 Coursera 举办的机器学习入门讲座的幻灯片中,他给出了鸡尾酒会问题的一行 Octave 解决方案,因为音频来源是由两个空间分离的麦克风记录的:
[W,s,v]=svd((repmat(sum(x.*x,1),size(x,1),1).*x)*x');
幻灯片的底部是“来源: Sam Roweis,Yair Weiss,Eero Simoncelli”,早期幻灯片的底部是“ Te-Won Lee 提供的音频剪辑”。在视频中,吴教授说,
“因此,你可能会看到这样的非监督式学习,然后问,‘实现这一点有多复杂?似乎为了构建这个应用程序,似乎需要进行音频处理,需要编写大量代码,或者链接到一堆处理音频的 C + + 或 Java 库中。这似乎是一个非常复杂的程序来做这个音频: 分离出音频等。你们刚才听到的算法,只需要一行代码就可以完成,就在这里。研究人员花了很长时间才想出这行代码。所以我不是说这是个简单的问题。但事实证明,当你使用正确的编程环境时,许多学习算法将是非常短的程序。”
在视频讲座中播放的分离音频结果并不完美,但在我看来,令人惊讶。有人知道为什么这一行代码执行得这么好吗?特别是,有没有人知道关于这一行代码的参考文献,可以解释 Te-Won Lee、 Sam Roweis、 Yair Weiss 和 Eero Simoncelli 的工作?
更新
为了证明算法对麦克风分离距离的敏感性,下面的模拟(用八度音阶)将音调从两个空间分离的音调发生器中分离出来。
% 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;
在我的笔记本电脑上执行大约10分钟后,模拟生成以下三个数字,说明两个孤立的音调具有正确的频率。
然而,将麦克风分离距离设置为零(即 dMic = 0)会导致模拟转而生成以下三个图形,说明模拟不能隔离第二个音调(由 svd 的 s 矩阵中返回的单个有意义的对角项证实)。
我希望智能手机上的麦克风分离距离足够大,以产生良好的结果,但设置麦克风分离距离为5.25英寸(即,dMic = 0.1333米)导致模拟产生以下,不是令人鼓舞的,数字说明第一个隔离音调的高频分量。