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

Posted

技术标签:

【中文标题】鸡尾酒会算法 SVD 实现......在一行代码中?【英文标题】:cocktail party algorithm SVD implementation ... in one line of code? 【发布时间】:2013-12-23 06:13:30 【问题描述】:

在斯坦福大学的 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 就这一行代码所做的工作的参考资料?

更新

为了演示算法对麦克风分离距离的敏感性,以下模拟(在 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 米)会导致模拟生成以下结果,这并不令人鼓舞,图示说明了第一个孤立音调中的较高频率成分。

【问题讨论】:

我对这次讲座的记忆模糊,但不记得x是什么;是波形的频谱图,还是什么? 吴教授在 t=5:30 在关于无监督学习的介绍视频 4 中似乎暗示 x 是音频样本的向量。也许 svd 参数中的 repmat 部分正在实现信号的某种功率归一化。 【参考方案1】:

2 年后,我也试图弄清楚这一点。但我得到了答案;希望它会帮助某人。

您需要 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);

【讨论】:

您能否找到更明确地解释该代码行基本原理的参考资料? 您能否解释一下您提供的链接中的信号混合是如何工作的?使用您的代码,最好从从站点下载的两个混合文件中提取两个声源。但是,当我自己尝试将两个单独的信号混合在一起时,算法似乎无法输出正确的结果。我正在使用天真的方式来获取混合信号:mic1 = 0.3 * track1 + 0.5 * track2,mic2 = 0.5 * track1 + 0.3 * track2。这些是我试图提供给算法的信号。非常感谢! 我对 Matlab 有点陌生。我在第 3 行有错误,说连接 2 个不同维度的矩阵有问题。我该如何处理这个问题? 我试过那个代码,但效果不是很好......(不是怪你!!)【参考方案2】:

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 的前 2 个对角线幅度被聚类,则 u*s_new*v' 将形成一个人的声音,其中 s_news 相同,除了 (3:end,3:end) 处的所有元素都被消除了。

关于sound-formed matrix和SVD的两篇文章供大家参考。

【讨论】:

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

以上是关于鸡尾酒会算法 SVD 实现......在一行代码中?的主要内容,如果未能解决你的问题,请参考以下文章

大型稀疏矩阵,带火花的 svd,python

SVD原理及代码实现

鸡尾酒排序Cocktail Sort (双向冒泡排序)

利用 SVD 实现协同过滤推荐算法

python代码实现鸡尾酒排序(双向冒泡排序)

冒泡排序和鸡尾酒排序的代码分析