https://wiki.swarma.org/index.php?title=%E5%AF%B9%E9%9F%B3%E4%B9%90%E8%BF%9B%E8%A1%8C%E5%88%86%E7%B1%BB&feed=atom&action=history
对音乐进行分类 - 版本历史
2024-03-28T13:47:29Z
本wiki的该页面的版本历史
MediaWiki 1.35.0
https://wiki.swarma.org/index.php?title=%E5%AF%B9%E9%9F%B3%E4%B9%90%E8%BF%9B%E8%A1%8C%E5%88%86%E7%B1%BB&diff=15144&oldid=prev
Thingamabob:创建页面,内容为“=准备数据= 这次,我们的任务是对一批音乐进行分类。 音乐的训练数据从[http://opihi.cs.uvic.ca/sound/genres.tar.gz 这里]可以下载到…”
2020-10-14T13:32:44Z
<p>创建页面,内容为“=准备数据= 这次,我们的任务是对一批音乐进行分类。 音乐的训练数据从[http://opihi.cs.uvic.ca/sound/genres.tar.gz 这里]可以下载到…”</p>
<p><b>新页面</b></p><div>=准备数据=<br />
这次,我们的任务是对一批音乐进行分类。<br />
音乐的训练数据从[http://opihi.cs.uvic.ca/sound/genres.tar.gz 这里]可以下载到。这个数据里包含了blue,classical 等十个音乐类别,每个音乐类别有一百首样本。每个样本都是一首歌的前30秒。不过这个数据集是.au格式的,我们需要先转换成比较易于python处理的格式:wma。从[http://sourceforge.net/projects/sox/ 这里]下载sox的windows安装版本。安装完之后,我们在windows的cmd窗口里,可以采取写命令的方式利用sox批量转音乐文件的格式。<br />
<br />
一个比较傻瓜的方式是<br />
<br />
1.先把cmd命令移动到genres下的某个文件夹,例如jazz(使用"cd /."回c盘根目录,使用"e:"跳转到e盘,然后继续用cd前往要去的文件夹);<br />
<br />
2.然后“mkdir converted”来新建一个converted文件夹;<br />
<br />
3.接着使用如下命令批量装换jazz中的.au文件到converted文件夹中:<br />
<br />
<syntaxhighlight lang="python"><br />
for %x in (*.au) do C:\sox-14-3-2\sox.exe %x E:\wulingfei\music_classification\genres\jazz\converted\%x.wav<br />
</syntaxhighlight><br />
在本练习中,我们只使用到jazz,classical,country, pop, rock, metal六个类型,所以只要在这六个文件夹下分别重复以上三个步骤就可以了。<br />
<br />
<br />
=音频文件的频谱图=<br />
我们可以先把一个wma文件读入python,然后绘制它的频谱图(spectrogram)来看看是什么样的。<br />
<syntaxhighlight lang="python"><br />
from scipy.io import wavfile<br />
from matplotlib.pyplot import specgram<br />
import matplotlib.pyplot as plt<br />
<br />
sample_rate, X = wavfile.read("E:\wulingfei\music_classification\genres\jazz\converted\jazz.00000.au.wav")<br />
print sample_rate, X.shape<br />
specgram(X, Fs=sample_rate, xextent=(0,30))<br />
plt.xlabel("time")<br />
plt.ylabel("frequency")<br />
</syntaxhighlight><br />
<br />
[[File:music_classification_1.png|400px]]<br />
<br />
上图就是一个jazz音乐样本的频谱图。当然,我们也可以把每一种的音乐都抽一些出来打印频谱图以便比较,如下图:<br />
[[File:music_classification_2.png|800px]]<br />
<br />
从肉眼就可以看出一些区分,金属音乐的能量在各个频率上都比较强,爵士则是分布很不均匀的。<br />
<syntaxhighlight lang="python"><br />
<br />
def plotSpec(g,n):<br />
sample_rate, X = wavfile.read("D:/genres/"+g+"/converted/"+g+"."+n+".au.wav")<br />
specgram(X, Fs=sample_rate, xextent=(0,30))<br />
plt.title(g+"_"+n[-1])<br />
<br />
figure(num=None, figsize=(18, 9), dpi=80, facecolor='w', edgecolor='k') <br />
plt.subplot(6,3,1);plotSpec("classical","00001");plt.subplot(6,3,2);plotSpec("classical","00002")<br />
plt.subplot(6,3,3);plotSpec("classical","00003");plt.subplot(6,3,4);plotSpec("jazz","00001")<br />
plt.subplot(6,3,5);plotSpec("jazz","00002");plt.subplot(6,3,6);plotSpec("jazz","00003")<br />
plt.subplot(6,3,7);plotSpec("country","00001");plt.subplot(6,3,8);plotSpec("country","00002")<br />
plt.subplot(6,3,9);plotSpec("country","00003");plt.subplot(6,3,10);plotSpec("pop","00001")<br />
plt.subplot(6,3,11);plotSpec("pop","00002");plt.subplot(6,3,12);plotSpec("pop","00003")<br />
plt.subplot(6,3,13);plotSpec("rock","00001");plt.subplot(6,3,14);plotSpec("rock","00002")<br />
plt.subplot(6,3,15);plotSpec("rock","00003");plt.subplot(6,3,16);plotSpec("metal","00001")<br />
plt.subplot(6,3,17);plotSpec("metal","00002");plt.subplot(6,3,18);plotSpec("metal","00003")<br />
plt.tight_layout(pad=0.4, w_pad=0, h_pad=1.0) <br />
</syntaxhighlight><br />
<br />
=什么是快速(离散)傅里叶变换(FFT)?=<br />
FFT是一种数据处理技巧,它可以把time domain上的数据,例如一个音频,拆成一堆基准频率,然后投射到frequency domain上。<br />
为了理解FFT,我们可以先生成三个音频文件。在cmd环境下输入<br />
<syntaxhighlight lang="python"><br />
C:\sox-14-3-2\sox.exe --null -r 22050 sine_a.wav synth 0.2 sine 400<br />
C:\sox-14-3-2\sox.exe --null -r 22050 sine_b.wav synth 0.2 sine 3000<br />
C:\sox-14-3-2\sox.exe --combine mix --volume 1 sine_b.wav --volume 0.5 sine_a.wav sine_mix.wav<br />
</syntaxhighlight><br />
生成三个音频文件。如果我们播放的话,会发现sine_a声音比较低,sine_b声音比较高,而sine_mix则混合了两者。<br />
<br />
[[File:music_classification_3.png|600px]]<br />
<syntaxhighlight lang="python"><br />
figure(num=None, figsize=(12, 8), dpi=80, facecolor='w', edgecolor='k') <br />
plt.subplot(3,2,1)<br />
sample_rate, a = wavfile.read("E:/wulingfei/music_classification/sine_a.wav")<br />
specgram(a, Fs=sample_rate, xextent=(0,30))<br />
plt.xlabel("time")<br />
plt.ylabel("frequency")<br />
plt.title("400 HZ sine wave")<br />
plt.subplot(3,2,2)<br />
fft_a = abs(scipy.fft(a))<br />
specgram(fft_a)<br />
plt.xlabel("frequency")<br />
plt.ylabel("amplitude")<br />
plt.title("FFT of 400 HZ sine wave")<br />
plt.subplot(3,2,3)<br />
sample_rate, b = wavfile.read("E:/wulingfei/music_classification/sine_b.wav")<br />
specgram(b, Fs=sample_rate, xextent=(0,30))<br />
plt.xlabel("time")<br />
plt.ylabel("frequency")<br />
plt.title("3000 HZ sine wave")<br />
plt.subplot(3,2,4)<br />
fft_b = abs(scipy.fft(b))<br />
specgram(fft_b)<br />
plt.xlabel("frequency")<br />
plt.ylabel("amplitude")<br />
plt.title("FFT of 3000 HZ sine wave")<br />
plt.subplot(3,2,5)<br />
sample_rate, c = wavfile.read("E:/wulingfei/music_classification/sine_mix.wav")<br />
specgram(c, Fs=sample_rate, xextent=(0,30))<br />
plt.xlabel("time")<br />
plt.ylabel("frequency")<br />
plt.title("Mixed sine wave")<br />
plt.subplot(3,2,6)<br />
fft_c = abs(scipy.fft(c))<br />
specgram(fft_c)<br />
plt.xlabel("frequency")<br />
plt.ylabel("amplitude")<br />
plt.title("FFT of mixed sine wave")<br />
plt.tight_layout(pad=0.4, w_pad=0, h_pad=1.0) <br />
</syntaxhighlight><br />
本文一开始的示例jazz数据经过FFT变形是这样的:<br />
[[File:music_classification_4.png|600px]]<br />
<syntaxhighlight lang="python"><br />
figure(num=None, figsize=(9, 6), dpi=80, facecolor='w', edgecolor='k') <br />
sample_rate, X = wavfile.read("E:/wulingfei/music_classification/genres/jazz/converted/jazz.00000.au.wav")<br />
plt.subplot(2,1,1)<br />
specgram(X, Fs=sample_rate, xextent=(0,30))<br />
plt.xlabel("time")<br />
plt.ylabel("frequency")<br />
plt.subplot(2,1,2)<br />
fft_X = abs(scipy.fft(X))<br />
specgram(fft_X)<br />
plt.xlabel("frequency")<br />
plt.ylabel("amplitude")<br />
plt.tight_layout(pad=0.4, w_pad=0, h_pad=1.0) <br />
</syntaxhighlight><br />
<br />
=使用频域强度特征来判别音乐=<br />
<br />
转换完数据后,我们就可以使用频域的特征来判别音乐数据了。这里我们考虑最简单的分类器,例如KNN方法。<br />
<syntaxhighlight lang="python"><br />
#---------prepare train data--------------------<br />
genre_list = ["classical", "jazz", "country", "pop", "rock", "metal"]<br />
def getdata(g,n):<br />
ad="E:/wulingfei/music_classification/genres/"+g+"/converted/"+g+"."+"0000"+str(n)+".au.wav"<br />
sample_rate, X = wavfile.read(ad)<br />
fft_X = list(abs(scipy.fft(X)[:1000]))<br />
f=fft_X+[genre_list.index(g)]<br />
return f<br />
<br />
data=[]<br />
for g in genre_list:<br />
for n in range(10):<br />
data.append(getdata(g,n))<br />
<br />
data=array(data)<br />
#-----------prepare test data-------------------<br />
sample_rate, test = wavfile.read("E:/wulingfei/music_classification/genres/metal/converted/metal.00080.au.wav")<br />
testdata=abs(scipy.fft(test))[:1000]<br />
<br />
#---------classify-----------------------<br />
<br />
def distance(p0, p1):<br />
return np.sum( (p0-p1)**2)<br />
<br />
def nn_classify(training_set, training_labels, new_example):<br />
dists = np.array([distance(t, new_example) for t in training_set])<br />
da=zip(dists,training_labels)<br />
da=array(sorted(da, key=lambda x:x[0]))<br />
votes = da[:3,1]<br />
return votes<br />
<br />
nn_classify(data[:,:-1], data[:,-1], testdata) <br />
</syntaxhighlight><br />
[[Category:旧词条迁移]]</div>
Thingamabob