鸡尾酒会算法 SVD 实现... 一行代码?

91
在Coursera上,斯坦福大学的Andrew Ng在机器学习的介绍课程中给出了一个幻灯片,其中提供了以下一行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提供”。在视频中,Ng教授说:
“So you might look at unsupervised learning like this and ask, 'How complicated is it to implement this?' It seems like in order to build this application, it seems like to do this audio processing, you would write a ton of code, or maybe link into a bunch of C++ or Java libraries that process audio. It seems like it would be a really complicated program to do this audio: separating out audio and so on. It turns out the algorithm to do what you just heard, that can be done with just one line of code ... shown right here. It did take researchers a long time to come up with this line of code. So I'm not saying this is an easy problem. But it turns out that when you use the right programming environment many learning algorithms will be really short programs."
视频演示的分离音频结果并不完美,但在我看来仍然非常惊人。有人对这一行代码是如何表现得如此出色有任何见解吗?特别是,有人知道Te-Won Lee、Sam Roweis、Yair Weiss和Eero Simoncelli关于这一行代码的工作的参考资料吗?
更新:
为了展示该算法对麦克风分离距离的敏感性,以下Octave模拟将两个空间分离的音调发生器的音调分离出来。
% 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米)会导致模拟生成以下不太令人鼓舞的图示,说明第一个隔离音调中存在更高频率的成分。

1
我对这个讲座有模糊的记忆,但是不记得 x 是什么;它是波形的频谱图还是其他什么? - Isaac
在无监督学习介绍视频4中,Ng教授在t=5:30时似乎暗示x是音频样本的向量。也许svd参数中的repmat部分正在实现某种信号功率归一化。 - gregS
2个回答

31

我也曾尝试解决这个问题,两年后终于找到了答案。希望对有需要的人有所帮助。

你需要2个音频录音。你可以从http://research.ics.aalto.fi/ica/cocktail/cocktail_en.cgi获取音频例子。

实现的参考资料在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);

在此输入图片描述


1
你能找到一份更明确解释那行代码背后原理的参考资料吗? - Hans
请问您能否解释一下您提供的链接中信号混合是如何工作的?使用您的代码,可以从该网站下载的两个混合文件中提取出两个声源。然而,当我尝试自己混合两个单独的信号时,似乎算法无法输出正确的结果。我正在使用简单的方法来获取混合信号:mic1 = 0.3 * track1 + 0.5 * track2,mic2 = 0.5 * track1 + 0.3 * track2。这些是我尝试输入到算法中的信号。非常感谢! - yc2986
我对Matlab还比较新手。第3行出现错误,说是在连接两个不同维度的矩阵时出了问题。我该如何解决这个问题? - mshrestha
1
我尝试了那段代码,但它并不是很好用...(不是责怪你!!) - anderstood

19
x(t)是来自一个声道/麦克风的原始音频。 X = repmat(sum(x.*x,1),size(x,1),1).*x)*x'x(t)功率谱的估计。尽管X' = X,但行和列之间的间隔完全不同。每一行代表信号的时间,而每一列代表频率。我猜这是一种更严格的表达式spectrogram的估计和简化。 Singular Value Decomposition在谱图上用于根据谱信息将信号分解为不同的组件。s中的对角线值是不同频谱组件的幅度。u中的行和v'中的列是将频率分量与相应幅度映射到X空间的正交向量。
我没有语音数据进行测试,但据我理解,通过奇异值分解(SVD),相似正交向量的组件可以通过无监督学习的帮助进行聚类。例如,如果从 s 中选择前两个对角线幅度进行聚类,则 u*s_new*v' 将形成一个人的声音,其中 s_news 相同,除了在 (3:end,3:end) 处的所有元素都被消除。
关于sound-formed matrixSVD,有两篇文章供您参考。

1
从数学上讲,一个n乘2的矩阵x仍然可以通过repmat操作形成一个X。然而,频谱图每次只能显示一个通道。因此,我认为每次使用n乘1的x更有意义,并将问题视为线性回归(两个矩阵方程)。另外两种可能的方法是(i)将两个通道平均为n乘2的x;或者(ii)将它们绑在一起构造一个2n乘2的x。 - lennon310
2
gregS,我重新考虑了你的问题。如果在n-by-2 x上实现repmat,它可能会起作用。从物理上讲,它可以被视为每个时间和每个频率两个通道功率的平均值。 - lennon310
在观看了机器学习的介绍视频之后,我发现了这篇帖子(该课程刚刚开始)。我想知道你是否成功实现了视频中展示的音频分离,或者它是在课程期间开发的? - siritinga
@siritinga,请搜索Andrew Ng在音频无监督/深度学习方面的出版物,谢谢。 - lennon310
1
为什么$X$是$x$频谱的幂?根据Jack Z的答案,$x$不是录音中的原始声音,而是原始声音协方差的特征值的某种处理倒数。 - Hans
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接