一、引子
语言是心灵的镜子,声音是语言的载体。”声音是个人的特征之一,在红楼梦经典片段的描写中,林黛玉初识王熙凤便先从她的笑声中,对她的性格就有了一半的了解。在日常社交里,声音极具富有表现力和感染力,通过听一个人说话的声音便能判断出大致的性格特点。
二、思路
下面我将通过分别通过分析声音的mfssc(梅尔频率倒谱系数)特征、基本频率(Fundamental Frequency,F0)的平均值:以赫兹(Hz)为单位、音频信号的能量、估算的语速特征,即每秒钟的音节数、短时能量的稳定性特征、短时过零率的稳定性特征、频谱质心的稳定性特征,作为不同的特征值进行提取并进行训练成模型
关于为何要提取这些做特征值可以看我上一篇博客:
[https://blog.csdn.net/qq_62042601/article/details/134491589?spm=1001.2014.3001.5502]
为何采用svm
采用支持向量机(SVM)的主要优点是其在音频特征分类任务中具有较好的性能,原因如下:
- 高维特征处理:
SVM 在高维特征空间中表现良好。提取的音频特征包括MFCCs、基本频率、能量、语速特征等,这些特征可能形成一个高维的特征向量。SVM适用于处理这样的高维数据。
- 非线性关系建模:
SVM 可以通过选择适当的核函数来有效地处理非线性关系。在音频处理中,许多关系可能是非线性的,例如音频信号的频率和能量之间的关系。SVM通过核技巧可以很好地适应这些非线性关系。
- 泛化能力强:
SVM 在训练过程中通过最大化类别间的间隔,有助于提高对未见过数据的泛化能力。这对于音频分类任务中可能遇到的不同音频样本非常重要。
- 对小样本数据集适用
: SVM 在小样本数据集上表现良好,因为它不容易过拟合。在音频领域,数据集可能相对较小,SVM能够有效地利用有限的样本进行训练。
- 线性分类器的效率:
采用线性核的 SVM 是一个高效的线性分类器。在这个例子中,kernel=‘linear’ 表明使用线性核,适用于线性可分的情况。
- 模型解释性:
SVM 提供了较好的模型解释性,能够帮助理解哪些特征对分类起到关键作用。这在音频分类任务中有助于理解不同音频特征的重要性。
综上所述,采用 SVM 是为了充分利用其在高维、非线性、小样本数据集上的良好性能,以及对模型的可解释性。
三、代码演示
代码对数据集部分没有限制,可以从网上自行查找,有几类就分几个文件夹。文章分类采用两种不同的性格。
1.代码解读
调用librosa库,使用了支持向量机(SVM)作为分类器
导入必要的库:
os:用于文件和目录操作。
librosa:用于音频处理。
numpy:用于数组操作。
train_test_split:用于划分数据集。
SVC:支持向量机分类器。
accuracy_score:用于计算分类准确率。
import os
import librosa
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
from sklearn.externals import joblib # For scikit-learn version < 0.22
定义音频特征提取函数 extract_features:
该函数使用Librosa库提取音频的MFCC(梅尔频率倒谱系数)特征。
还提取了其他一些特征,如基本频率(F0)的平均值、音频信号的能量、语速特征、稳定性特征等。
所有提取的特征被组合成一个特征向量。
def extract_features(audio_path):
# 读取音频文件
y, sr = librosa.load(audio_path)
# 提取MFCCs
mfccs = librosa.feature.mfcc(y=y, sr=sr)
# ...(省略其他特征的提取过程)
# 创建特征向量
feature_vector = np.concatenate([
mfccs.flatten(),
[average_f0],
[energy],
[syllable_rate],
[energy_stability],
[zero_crossings_stability],
[centroid_stability]
])
return feature_vector
定义构建数据集的函数 build_dataset:
该函数接收文件夹路径和标签作为输入,从文件夹中读取所有.wav文件的音频并提取特征。
返回特征和对应的标签。
def build_dataset(folder_path, label):
audio_paths = [os.path.join(folder_path, filename) for filename in os.listdir(folder_path) if filename.endswith('.wav')]
features = [extract_features(audio_path) for audio_path in audio_paths]
labels = np.full(len(features), label)
return features, labels
构建两类不同性格的数据集:
分别使用 build_dataset 函数构建两类性格不同的数据集,并为它们分配标签0和1。
folder_1_path = 'path_to_1'
folder_2_path = 'path_to_2'
features_normal, labels_normal = build_dataset(normal_folder_path, label=0)
features_mental_illness, labels_mental_illness = build_dataset(mental_illness_folder_path, label=1)
合并数据集:
使用 np.vstack 和 np.concatenate 合并两个不同性格的特征和标签。
X = np.vstack([features_1, features_2])
y = np.concatenate([labels_1, labels_2])
划分训练集和测试集:
使用 train_test_split 函数划分数据集为训练集和测试集。
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
创建SVM分类器:
使用线性核的SVM分类器。
svm_classifier = SVC(kernel='linear')
训练模型:
使用训练集训练SVM模型。
svm_classifier.fit(X_train, y_train)
模型保存:
可以在此修改模型的名字和路径。
joblib.dump(svm_classifier, 'svm_model.joblib')
模型预测:
使用模型进行预测。
loaded_model = joblib.load('svm_model.joblib')
y_pred = svm_classifier.predict(X_test)
计算准确率:
使用 accuracy_score 计算分类准确率。
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")
2.完整代码
import os
import librosa
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
import joblib
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
def extract_features(audio_path):
# 读取音频文件
y, sr = librosa.load(audio_path)
# 提取MFCCs
mfccs = librosa.feature.mfcc(y=y, sr=sr)
# 提取基本频率(F0)的平均值
f0, _ = librosa.core.piptrack(y=y, fmin=librosa.note_to_hz('C2'), fmax=librosa.note_to_hz('C7'))
average_f0 = np.mean(np.max(f0, axis=0))
# 提取音频信号的能量
energy = np.sum(np.abs(y) ** 2)
# 估算语速特征 - 每秒钟的音节数
onset_env = librosa.onset.onset_strength(y=y, sr=sr)
tempo, _ = librosa.beat.beat_track(onset_envelope=onset_env, sr=sr)
syllable_rate = tempo / 60.0 # Convert tempo to syllable rate (beats per second)
# 提取稳定性特征
energy_stability = np.std(librosa.feature.rms(y=y))
zero_crossings_stability = np.std(librosa.feature.zero_crossing_rate(y))
centroid_stability = np.std(librosa.feature.spectral_centroid(y=y, sr=sr))
# 创建特征向量
feature_vector = np.concatenate([
mfccs.flatten(),
[average_f0],
[energy],
[syllable_rate],
[energy_stability],
[zero_crossings_stability],
[centroid_stability]
])
return feature_vector
def build_dataset(folder_path, label):
audio_paths = [os.path.join(folder_path, filename) for filename in os.listdir(folder_path) if filename.endswith('.wav')]
features = [extract_features(audio_path) for audio_path in audio_paths]
labels = np.full(len(features), label)
return features, labels
# 两个文件夹路径
folder1_path = 'path_1_folder'
folder2_path = 'path_2_folder'
# 构建第一个性格的数据集
features_1, labels_1 = build_dataset(folder1_path, label=0)
# 构建第二个性格的数据集
features_2, labels_2 = build_dataset(folder2_path, label=1)
# 合并数据集
X = np.vstack([features_1, features_2])
y = np.concatenate([labels_1, labels_2])
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建SVM分类器
svm_classifier = SVC(kernel='linear')
# 训练模型
svm_classifier.fit(X_train, y_train)
# 保存模型
joblib.dump(svm_classifier, 'svm_model.joblib')
# 加载模型
loaded_model = joblib.load('svm_model.joblib')
# 预测
y_pred = loaded_model.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")
四、结果演示
由于没有显示进度,大家需要等待一段时间
最终显示出来模型的正确率:我的正确率为百分之95%
模型保存到了同路径下的svm_model.joblib文件