项目实战-基于信号处理与SVM机器学习的声音情感识别系统

目录

一.背景描述

二.理论部分

三.程序设计

编程思路

流程图

1.信号部分 创建数据 generate_samples.py

头文件

生成函数 generate_emotion_sample

传入参数

存储路径

生成参数

创建基础正弦波信号

调制基础正弦波

对于愤怒可以增加噪声

归一化信号

存储

主函数 main

2.交叉部分 特征提取 audio_emotion.py

头文件

提取单个文件的特征 extract_features_from_file

传入参数

提取特征向量

计算统计值并返回矩阵

提取各情感的特征 extract_features_from_directory

传入参数

初始化

提取文件 & 识别特征

训练情感识别模型 train_emotion_model

传入参数

划分训练集和测试集

训练SVM模型

评估测试集

计算混淆矩阵

返回

保存模型

加载模型

预测单个音频的情感

混淆矩阵可视化

音频特征可视化

传入参数

处理音频

特征提取

可视化并保存

返回

3.机器学习部分 train_model.py

为何要独立出一个训练脚本

头文件

主函数 main

4.封装部分 main.py

创建项目目录

提取特征并训练模型

预测单个文件情感

显示

主逻辑

5.预测部分 predict.py

头文件

可视化音频特征

主逻辑 

应用

四.运行展示

初始化目录

生成样本

训练模型

查看结果并分析

应用模型

查看分析图


一.背景描述

智能识别不同情景下的声音信号体现的情感,比如客户接电话时的语音情感,还可以用于智能手表、人工智能助手(比如豆包的聊天过程中的人类情感反馈,提高豆包“情商”)等等

二.理论部分

1.首先分析了不同情感声音信号的特征,用于下面的构造信号

2.构造不同情感的声音信号(通过将时间序列代入基准正弦信号,接着进行加、乘操作进行调制)用于训练SVM模型

3.对信号进行时频域变换,比如傅立叶变换

chroma = librosa.feature.chroma_stft(y=y, sr=sr)

4.进行特征提取,捕捉谱质心、谱带宽、谱对比度等等

5.进行特征的统计,计算了四种统计量:均值、标准差、最小值、最大值

6.通过均方根计算能量,这是情感表达的重要指标

7.特征空间降维,通过统计的方式进行了隐式降维

三.程序设计

编程思路

整体框架是:

1.信号生成 generate_samples.py

2.特征提取 audio_emotion.py

3.训练模型 train_model.py

4.封装模块 main.py

5.应用模型 predict.py

流程图

1.信号部分 创建数据 generate_samples.py

头文件

import os
import numpy as np
import librosa
import soundfile as sf
from scipy.io import wavfile

生成函数 generate_emotion_sample

传入参数

emotion                 情感

freq_range            生成音频信号的频率范围

duration_range      生成信号的持续时间范围

num_samples        生成的音频样本数量

存储路径
    emotion_dir = os.path.join("dataset", emotion)
    os.makedirs(emotion_dir, exist_ok=True)

dataset 是数据集的根目录,在根目录下创建名为传入参数emotion的子目录

第二句的作用是保证文件夹存在

生成参数

首先我们得明确各情感声音特色

  • "happy":高频、短持续时间,模拟快乐情感。
  • "sad":低频、长持续时间,模拟悲伤情感。
  • "angry":中高频、短脉冲,模拟愤怒情感。
  • "neutral":中等频率和持续时间,模拟中性情感。

那么我们只需要判断,然后分支为各情感创建独特的参数就好

以“happy”为例

首先我们要从指定的频率中随机选择频率值,对应下面的np.random.uniform(freq_range[0], freq_range[1])语句,里面的freq_range[ 0 ] 和 freq_range[1] 分别代表频率范围的上下限,我们会在主函数中提前定义

(注意:我们这里得用numpy的random,而不是python自带的random函数,因为np的支持数组高效操作)

然后我们还需要持续时间,和频率同理也是np.random.uniform

接着我们设置了音频信号的振幅频率(音量),快乐的声音为0.6中等偏高来模拟

最后我们设置振幅调制的频率,快乐的是8.0:快速的变化,模拟快乐的活泼

其他的感情和快乐同理

    
    for i in range(num_samples):
        if emotion == "happy":
            # 高频和短持续时间
            freq = np.random.uniform(freq_range[0], freq_range[1])
            duration = np.random.uniform(duration_range[0], duration_range[1])
            amplitude = 0.6
            modulation_freq = 8.0
            
        elif emotion == "sad":
            # 低频和长持续时间
            freq = np.random.uniform(freq_range[0]/2, freq_range[1]/2)
            duration = np.random.uniform(duration_range[0]*1.5, duration_range[1]*1.5)
            amplitude = 0.4
            modulation_freq = 2.0
            
        elif emotion == "angry":
            # 中高频和短脉冲
            freq = np.random.uniform(freq_range[0]*1.2, freq_range[1]*1.2)
            duration = np.random.uniform(duration_range[0], duration_range[1])
            amplitude = 0.8
            modulation_freq = 12.0
            
        else:  # neutral
            # 中等频率和持续时间
            freq = np.random.uniform(freq_range[0]*0.8, freq_range[1]*0.8)
            duration = np.random.uniform(duration_range[0]*1.2, duration_range[1]*1.2)
            amplitude = 0.5
            modulation_freq = 4.0
创建基础正弦波信号
        sample_rate = 22050
        t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
        signal = amplitude * np.sin(2 * np.pi * freq * t)

首先我们设置了音频信号的采样频率,单位是“样本/秒”

然后我们用 numpy 的 linspace 创建了一个时间序列,用于表示信号的时间轴,第一个参数0表示时间序列起点,duration是时间序列的终点(也就是我们在上面生成的持续时间),第三个参数是时间序列的点数(计算方式:采样率乘以持续时间),endpoint保证时间序列不包含终点

然后我们生成一个正弦波信号,amplitude表示正弦波的振幅(音量),freq时频率(音调),t是上面生成的时间序列,通过 2 * np.pi * freq * t 将频率转为角频率,计算正弦波的相位

调制基础正弦波

我们还需要根据我们的情感对基础波进行处理

        modulation = 1.0 + 0.3 * np.sin(2 * np.pi * modulation_freq * t)
        signal = signal * modulation

modulation是生成的调制信号,用于改变原始信号的振幅,其中 1.0 是基础振幅(乘法的初元), 0.3表示调制强度(影响程度)

第二句代码也就是将调制信号作用在原正弦波signal上

对于愤怒可以增加噪声

对于“angry”:加上信号

        if emotion == "angry":
            noise = np.random.normal(0, 0.1, signal.shape)
            signal = signal + noise
归一化信号

进行归一化:除以max乘以1

限制信号在 [ -1,1 ] 中,确保生成的音频信号符合音频文件格式的要求,防止信号溢出

        signal = signal / np.max(np.abs(signal))
存储
        file_path = os.path.join(emotion_dir, f"{emotion}_sample_{i+1}.wav")
        sf.write(file_path, signal, sample_rate)
        print(f"生成样本: {file_path}")

emotion_dir 在函数刚进来一开始就定义了

然后我加了一句print方便调试看报错

主函数 main

def main():
    freq_range = (220, 880)

    duration_range = (2.0, 4.0)
    
    emotions = ["happy", "sad", "angry", "neutral"]
    for emotion in emotions:
        generate_emotion_sample(emotion, freq_range, duration_range, num_samples=50)
    
    print("所有测试样本生成完成!")

if __name__ == "__main__":
    main()

freq_range 是频率范围

duration_range 是持续时间

num是生成数据集的个数,我先设置为50(多多益善)

然后用 for 遍历感情

2.交叉部分 特征提取 audio_emotion.py

头文件

import os
import numpy as np
import librosa
import librosa.display 
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import classification_report, confusion_matrix
import joblib
import glob

提取单个文件的特征 extract_features_from_file

传入参数

file_path        文件的路径

win                计算特征的时间窗口长度

step               步长

提取特征向量

先读取音频文件

        y, sr = librosa.load(file_path, sr=None)

读取MFCC特征

        mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)

提取色度特征

        chroma = librosa.feature.chroma_stft(y=y, sr=sr)

提取梅尔频谱

        mel = librosa.feature.melspectrogram(y=y, sr=sr)

提取谱质心

        spectral_centroid = librosa.feature.spectral_centroid(y=y, sr=sr)

提取谱带宽

        spectral_bandwidth = librosa.feature.spectral_bandwidth(y=y, sr=sr)

提取谱对比度

        spectral_contrast = librosa.feature.spectral_contrast(y=y, sr=sr)

提取谱平坦度

        spectral_flatness = librosa.feature.spectral_flatness(y=y)

提取零交叉率

        zcr = librosa.feature.zero_crossing_rate(y)

提取能量

        energy = np.mean(librosa.feature.rms(y=y))
计算统计值并返回矩阵
        features.append(energy)

        feature_names = []
        for name in ['mfccs', 'chroma', 'mel', 'spectral_centroid', 
                    'spectral_bandwidth', 'spectral_contrast', 
                    'spectral_flatness', 'zcr']:
            for stat in ['mean', 'std', 'min', 'max']:
                feature_names.append(f"{name}_{stat}")
        feature_names.append('energy')
        
        return np.array(features), feature_names

提取各情感的特征 extract_features_from_directory

传入参数

directory        数据集根目录

emotions       情感类别

初始化
    features = []
    labels = []
    feature_names = None

其中

feature                        特征向量

labels                          情感标签

feature_names            特征的名称列表

提取文件 & 识别特征

首先我加了一句 print 方便调试

    print(f"开始从以下类别提取特征: {emotions}")

    for emotion in emotions:
        emotion_dir = os.path.join(directory, emotion)
        if not os.path.isdir(emotion_dir):
            continue
            
        for file_name in glob.glob(os.path.join(emotion_dir, "*.wav")):
            print(f"处理文件: {file_name}")
            feature_vector, names = extract_features_from_file(file_name)
            
            if feature_vector is not None:
                features.append(feature_vector)
                labels.append(emotion)
                if feature_names is None:
                    feature_names = names

然后我们开始

遍历情感类别 for emotion in emotions(如果子目录不存在那就continue跳过)

遍历音频文件 for file_name in glob.glob(os.path.join(emotion_dir, "*.wav"))

提取音频特征 对于提取到的单个文件开始调用extract_features_from_file

存储特征和标签 append

最后我们返回

    return np.array(features), np.array(labels), feature_names


后面的就是机器学习部分

训练情感识别模型 train_emotion_model

传入参数

feature         特征矩阵,每一行都是一个音频的特征向量,包含提取到的各种统计特征

labels           标签数组

test_size      测试集的比例,一般正常训练都是占比20%到30%,本次项目中设为0.2

划分训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(
        features, labels, test_size=test_size, random_state=42)
训练SVM模型
    model = SVC(kernel='rbf', probability=True)
    model.fit(X_train, y_train)
评估测试集
    y_pred = model.predict(X_test)
    report = classification_report(y_test, y_pred, output_dict=True)
计算混淆矩阵
    cm = confusion_matrix(y_test, y_pred)
返回

model        SVM模型

report        分类报告

cm             混淆矩阵

X_test        测试集的特征矩阵,来评估模型性能

y_test         测试集的真实标签,用于对比

y_pred        模型在测试集的预测标签,用于对比

    return model, report, cm, X_test, y_test, y_pred

保存模型

def save_model(model, output_path="emotion_model.pkl"):
    joblib.dump(model, output_path)
    print(f"模型已保存到 {output_path}")

加载模型

def load_model(model_path="emotion_model.pkl"):
    return joblib.load(model_path)

预测单个音频的情感

调用extract_features_from_file函数从指定file_path里面提取特征向量,然后特征预处理,将特征向量转换为模型可以接受的二维数组形状,接着调用model模型进行情感预测,返回每个情感类别的预测概率,便于分析模型的信心程度。这个函数在audio脚本中并没有被使用,而是在后面的main.py文件中被调用了

def predict_emotion(model, file_path):
    features, _ = extract_features_from_file(file_path)
    if features is not None:
        features = features.reshape(1, -1)
        prediction = model.predict(features)[0]
        probabilities = model.predict_proba(features)[0]
        return prediction, probabilities
    return None, None

混淆矩阵可视化

为了方便查看混淆矩阵,我用matplotlib来进行数据的可视化(由于我之前在数模比赛中做过斯皮尔曼相关矩阵的可视化,所以还是感觉轻车熟路的)

def visualize_confusion_matrix(cm, classes):
    plt.figure(figsize=(10, 8))
    plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)
    plt.title('混淆矩阵')
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    thresh = cm.max() / 2.
    for i in range(cm.shape[0]):
        for j in range(cm.shape[1]):
            plt.text(j, i, format(cm[i, j], 'd'),
                    horizontalalignment="center",
                    color="white" if cm[i, j] > thresh else "black")
    
    plt.ylabel('真实标签')
    plt.xlabel('预测标签')
    plt.tight_layout()
    plt.savefig('confusion_matrix.png')
    plt.show()

效果展示

从图中可以直观的看到我们的模型准确率是不错的,具体的结论在后面分析

音频特征可视化

传入参数

audio_file        待分析的音频文件路径

处理音频

音频加载

y, sr = librosa.load(audio_file, sr=None)

音频持续时间计算

duration = librosa.get_duration(y=y, sr=sr)
特征提取

梅尔频谱

mel_spec = librosa.feature.melspectrogram(y=y, sr=sr)
mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)

MFCC(梅尔频谱倒谱系数) 

mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)

色度图

chroma = librosa.feature.chroma_stft(y=y, sr=sr)
可视化并保存
    plt.figure(figsize=(12, 10))
    
    # 波形
    plt.subplot(4, 1, 1)
    librosa.display.waveshow(y, sr=sr)
    plt.title('音频波形')
    
    # 梅尔频谱
    plt.subplot(4, 1, 2)
    librosa.display.specshow(mel_spec_db, sr=sr, x_axis='time', y_axis='mel')
    plt.colorbar(format='%+2.0f dB')
    plt.title('梅尔频谱')
    
    # MFCC
    plt.subplot(4, 1, 3)
    librosa.display.specshow(mfccs, sr=sr, x_axis='time')
    plt.colorbar()
    plt.title('MFCC')
    
    # 色度图
    plt.subplot(4, 1, 4)
    librosa.display.specshow(chroma, sr=sr, x_axis='time', y_axis='chroma')
    plt.colorbar()
    plt.title('色度图')
    
    plt.tight_layout()
    plt.savefig('audio_analysis.png')
    plt.show()

效果展现

返回

将特征数据和原始数据返回,便于后面分析

return mel_spec, mfccs, chroma, sr, y

3.机器学习部分 train_model.py

为何要独立出一个训练脚本

可以看到我们之前在audio_emotion.py中包含了一系列功能,但是它只是一个功能库,并不会执行,只是定义了如何训练

那么我们就需要新写一个执行脚本来调用,他就是我们的train_model.py,这种模块化的设计方便我们更换不同的训练方法

头文件

import os
import numpy as np
import librosa
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import classification_report, confusion_matrix
import joblib
import glob
import time
from audio_emotion import extract_features_from_file

设置输出日志

LOG_FILE = "training_log.txt"

写入输出日志

def log_message(message):
    print(message)
    with open(LOG_FILE, "a") as f:
        timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
        f.write(f"[{timestamp}] {message}\n")

主函数 main

获取情感类别

    emotions = [d for d in os.listdir("dataset") if os.path.isdir(os.path.join("dataset", d))]

初始化特征和标签

    features = []
    labels = []
    feature_names = None

开始训练

    for emotion in emotions:
        emotion_dir = os.path.join("dataset", emotion)
        audio_files = glob.glob(os.path.join(emotion_dir, "*.wav"))
        
        if not audio_files:
            log_message(f"警告: {emotion} 类别中没有发现WAV文件。")
            continue
        
        log_message(f"处理 {len(audio_files)} 个 {emotion} 类别的文件...")
        
        for audio_file in audio_files:
            log_message(f"提取特征: {audio_file}")
            feature_vector, names = extract_features_from_file(audio_file)  # 使用原始函数
            
            if feature_vector is not None:
                features.append(feature_vector)
                labels.append(emotion)
                if feature_names is None:
                    feature_names = names
    
    if not features:
        log_message("错误: 没有成功提取任何特征,请检查音频文件格式。")
        return
    
    # 转换为numpy数组
    features = np.array(features)
    labels = np.array(labels)
    
    log_message(f"成功提取 {len(features)} 个样本的特征,每个样本 {features.shape[1]} 个特征。")
    
    # 划分训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(
        features, labels, test_size=0.2, random_state=42)
    
    log_message(f"训练集: {X_train.shape[0]} 个样本,测试集: {X_test.shape[0]} 个样本。")
    
    # 训练SVM模型
    log_message("开始训练SVM模型...")
    model = SVC(kernel='rbf', probability=True)
    model.fit(X_train, y_train)
    log_message("SVM模型训练完成。")
    
    # 在测试集上评估
    y_pred = model.predict(X_test)
    
    # 计算分类报告
    report = classification_report(y_test, y_pred, output_dict=True)
    
    # 输出分类报告
    log_message("\n分类报告:")
    for emotion in sorted(report.keys()):
        if emotion != "accuracy" and emotion != "macro avg" and emotion != "weighted avg":
            precision = report[emotion]['precision']
            recall = report[emotion]['recall']
            f1 = report[emotion]['f1-score']
            support = report[emotion]['support']
            log_message(f"{emotion}:\t精确率: {precision:.2f}, 召回率: {recall:.2f}, F1: {f1:.2f}, 样本数: {support}")
    
    log_message(f"\n整体准确率: {report['accuracy']:.2f}")
    
    # 保存混淆矩阵
    log_message("生成混淆矩阵...")
    cm = confusion_matrix(y_test, y_pred)
    
    plt.figure(figsize=(10, 8))
    plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)
    plt.title('混淆矩阵')
    plt.colorbar()
    
    # 添加标签
    classes = sorted(np.unique(labels))
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)
    
    # 在格子中添加数字
    thresh = cm.max() / 2.
    for i in range(cm.shape[0]):
        for j in range(cm.shape[1]):
            plt.text(j, i, format(cm[i, j], 'd'),
                    horizontalalignment="center",
                    color="white" if cm[i, j] > thresh else "black")
    
    plt.ylabel('真实标签')
    plt.xlabel('预测标签')
    plt.tight_layout()
    
    # 保存混淆矩阵图像
    plt.savefig('confusion_matrix.png')
    log_message("混淆矩阵已保存为 confusion_matrix.png")
    
    # 保存模型
    joblib.dump(model, 'emotion_model.pkl')
    log_message("模型已保存到 emotion_model.pkl")
    
    log_message("模型训练和评估完成!")

4.封装部分 main.py

最后我们还需要一个命令行界面用于调用模块、封装框架,他就是main文件

创建项目目录

def create_project_structure():
    print("开始创建项目目录结构...")
    os.makedirs("dataset", exist_ok=True)
    emotions = ["happy", "sad", "angry", "neutral"]
    for emotion in emotions:
        os.makedirs(os.path.join("dataset", emotion), exist_ok=True)
    
    print("项目目录结构已创建,请将音频文件放入相应的情感文件夹中:")
    print("  - dataset/happy/")
    print("  - dataset/sad/")
    print("  - dataset/angry/")
    print("  - dataset/neutral/")

提取特征并训练模型

def extract_and_train():
    if not os.path.exists("dataset"):
        print("数据集目录不存在,请先运行 'python main.py init'")
        return
    
    print("开始提取特征...")
    try:
        features, labels, feature_names = extract_features_from_directory("dataset")
        
        if len(features) == 0:
            print("未找到有效的特征数据,请确保数据集中包含.wav文件")
            return
        
        print(f"共提取了 {len(features)} 个样本的特征")
        
        # 训练模型
        print("开始训练模型...")
        model, report, cm, X_test, y_test, y_pred = train_emotion_model(features, labels)
        
        # 保存模型
        save_model(model)
        
        # 输出分类报告
        print("\n分类报告:")
        for emotion in report.keys():
            if emotion != "accuracy" and emotion != "macro avg" and emotion != "weighted avg":
                precision = report[emotion]['precision']
                recall = report[emotion]['recall']
                f1 = report[emotion]['f1-score']
                support = report[emotion]['support']
                print(f"{emotion}:\t精确率: {precision:.2f}, 召回率: {recall:.2f}, F1: {f1:.2f}, 样本数: {support}")
        
        print(f"\n整体准确率: {report['accuracy']:.2f}")
        
        # 可视化混淆矩阵
        classes = np.unique(labels)
        visualize_confusion_matrix(cm, classes)
        
        return model
    except Exception as e:
        import traceback
        print(f"训练过程中出错: {str(e)}")
        traceback.print_exc()
        return None

预测单个文件情感

def predict_single_file(audio_file):
    if not os.path.exists("emotion_model.pkl"):
        print("模型文件不存在,请先训练模型")
        return
    
    model = load_model()
    prediction, probabilities = predict_emotion(model, audio_file)
    
    if prediction is not None:
        print(f"预测情感: {prediction}")
        
        # 获取类别列表
        classes = model.classes_
        
        # 显示各情感的概率
        print("\n各情感的概率:")
        for i, emotion in enumerate(classes):
            print(f"{emotion}: {probabilities[i]:.2f}")
        
        # 可视化音频特征
        process_audio_features(audio_file)
    else:
        print("预测失败")

显示

def display_help():
    print("使用方法:")
    print("  python main.py init                 - 创建项目目录结构")
    print("  python main.py train                - 提取特征并训练模型")
    print("  python main.py predict <audio_file> - 预测单个音频文件的情感")
    print("  python main.py help                 - 显示此帮助信息")

主逻辑

if __name__ == "__main__":
    if len(sys.argv) < 2:
        display_help()
        sys.exit(1)
    
    command = sys.argv[1].lower()
    
    if command == "init":
        create_project_structure()
    elif command == "train":
        extract_and_train()
    elif command == "predict" and len(sys.argv) >= 3:
        predict_single_file(sys.argv[2])
    elif command == "help":
        display_help()
    else:
        print("无效的命令")
        display_help()
        sys.exit(1)

5.预测部分 predict.py

一般训练要和预测(也就是使用)部分分离,这样我们就不必每次都重新训练

头文件

import os
import sys
import numpy as np
import librosa
import librosa.display
import matplotlib.pyplot as plt
import joblib
import time

可视化音频特征

def visualize_audio(y, sr, emotion=None):
    plt.figure(figsize=(12, 8))
    
    # 波形
    plt.subplot(3, 1, 1)
    librosa.display.waveshow(y, sr=sr)
    plt.title(f'音频波形 - 预测情感: {emotion}' if emotion else '音频波形')
    
    # 梅尔频谱
    mel_spec = librosa.feature.melspectrogram(y=y, sr=sr)
    mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max)
    
    plt.subplot(3, 1, 2)
    librosa.display.specshow(mel_spec_db, sr=sr, x_axis='time', y_axis='mel')
    plt.colorbar(format='%+2.0f dB')
    plt.title('梅尔频谱')
    
    # MFCC
    mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)
    
    plt.subplot(3, 1, 3)
    librosa.display.specshow(mfccs, sr=sr, x_axis='time')
    plt.colorbar()
    plt.title('MFCC')
    
    plt.tight_layout()
    plt.savefig('audio_analysis.png')
    plt.show()

主逻辑 

def main():
    # 检查命令行参数
    if len(sys.argv) < 2:
        print("使用方法: python predict.py <音频文件路径>")
        return
    
    audio_file = sys.argv[1]
    
    # 检查文件是否存在
    if not os.path.exists(audio_file):
        print(f"错误: 文件 {audio_file} 不存在")
        return
    
    # 检查模型文件是否存在
    model_path = 'emotion_model.pkl'
    if not os.path.exists(model_path):
        print(f"错误: 模型文件 {model_path} 不存在,请先运行训练脚本")
        return
    
    # 加载模型
    print("加载情感识别模型...")
    model = joblib.load(model_path)
    
    # 提取特征
    print(f"从 {audio_file} 提取特征...")
    features, feature_names = extract_features_from_file(audio_file)  # 使用audio_emotion中的函数
    
    # 同时读取音频数据用于可视化
    y, sr = librosa.load(audio_file, sr=None)
    
    if features is None:
        print("特征提取失败")
        return
    
    # 预测情感
    features = features.reshape(1, -1)
    prediction = model.predict(features)[0]
    probabilities = model.predict_proba(features)[0]
    
    print(f"\n预测结果: {prediction}")
    
    # 显示各情感的概率
    print("\n各情感的概率:")
    for i, emotion in enumerate(model.classes_):
        print(f"{emotion}: {probabilities[i]:.2f}")
    
    # 可视化音频及其特征
    print("\n生成音频可视化分析...")
    visualize_audio(y, sr, prediction)
    print("可视化结果已保存为 audio_analysis.png")

if __name__ == "__main__":
    main()

应用

那么我们后面需要应用模型时只需要在终端执行

python predict.py <处理对象路径>

四.运行展示

下面我们从头到尾执行

初始化目录

python main.py init

生成样本

python generate_samples.py

训练模型

python main.py train

查看结果并分析

open confusion_matrix.png

可以看到模型准确度高达75%,在angry和sad方面尤其精准,说明我们后面需要优化的方面就集中在happy和neutral

应用模型

python predict.py <对象文件路径>

查看分析图

open audio_analysis.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值