{
"cells": [
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"# 多语言语音情感分析系统\n",
"\n",
"本Notebook按照题目要求,实现语音情感分析系统的各个部分:\n",
"1. 对多语言语音数据集进行预处理\n",
"2. 特征工程\n",
"3. 分类预测模型构建与分析\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 环境准备\n",
"\n",
"首先导入必要的库和设置环境\n"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [],
"source": [
"# 导入基础库\n",
"import os\n",
"import glob # 添加glob模块用于文件匹配\n",
"import numpy as np\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"import librosa\n",
"import librosa.display\n",
"from tqdm import tqdm\n",
"import pickle\n",
"import warnings\n",
"\n",
"# 机器学习库\n",
"from sklearn.preprocessing import StandardScaler, LabelEncoder\n",
"from sklearn.model_selection import train_test_split\n",
"from tensorflow.keras.utils import to_categorical\n",
"import tensorflow as tf\n",
"\n",
"# 忽略警告\n",
"warnings.filterwarnings('ignore')\n",
"\n",
"# 设置随机种子,确保结果可重复\n",
"np.random.seed(42)\n",
"tf.random.set_seed(42)\n",
"\n",
"# 设置图形样式\n",
"plt.style.use('ggplot')\n",
"plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文\n",
"plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"# 1. 对多语言语音数据集进行预处理\n",
"\n",
"## 1.1 使用librosa库对数据进行初步读取与探索\n",
"\n",
"我们将加载音频文件,可视化波形,并进行基本的数据探索。\n"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"正在处理 3 个音频文件...\n",
"\n",
"音频特征DataFrame:\n"
]
},
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" file_name | \n",
" dataset | \n",
" emotion | \n",
" duration | \n",
" pitch_mean | \n",
" pitch_std | \n",
" pitch_max | \n",
" pitch_min | \n",
" tuning_offset | \n",
" spectral_centroid_mean | \n",
" ... | \n",
" spectral_flatness_max | \n",
" spectral_flatness_min | \n",
" rms_mean | \n",
" rms_std | \n",
" rms_max | \n",
" rms_min | \n",
" zero_crossing_rate_mean | \n",
" zero_crossing_rate_std | \n",
" zero_crossing_rate_max | \n",
" zero_crossing_rate_min | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 03-01-01-01-01-01-01.wav | \n",
" RAVDESS | \n",
" neutral | \n",
" 5.0 | \n",
" 573.830444 | \n",
" 853.130066 | \n",
" 3988.073975 | \n",
" 147.432693 | \n",
" -0.17 | \n",
" 2086.724971 | \n",
" ... | \n",
" 1.000001 | \n",
" 7.847282e-05 | \n",
" 0.001493 | \n",
" 0.002882 | \n",
" 0.012591 | \n",
" 0.0 | \n",
" 0.149477 | \n",
" 0.170416 | \n",
" 0.528320 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 201.wav | \n",
" CASIA | \n",
" unknown | \n",
" 5.0 | \n",
" 815.843445 | \n",
" 1158.526733 | \n",
" 3824.677246 | \n",
" 171.179718 | \n",
" 0.10 | \n",
" 747.381791 | \n",
" ... | \n",
" 1.000001 | \n",
" 2.586936e-06 | \n",
" 0.019801 | \n",
" 0.039385 | \n",
" 0.146754 | \n",
" 0.0 | \n",
" 0.039092 | \n",
" 0.093996 | \n",
" 0.526855 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 2 | \n",
" a01.wav | \n",
" SAVEE | \n",
" angry | \n",
" 5.0 | \n",
" 523.944702 | \n",
" 591.257019 | \n",
" 3405.564209 | \n",
" 149.664169 | \n",
" -0.23 | \n",
" 669.513790 | \n",
" ... | \n",
" 1.000001 | \n",
" 8.574546e-08 | \n",
" 0.097924 | \n",
" 0.099660 | \n",
" 0.433721 | \n",
" 0.0 | \n",
" 0.020286 | \n",
" 0.032456 | \n",
" 0.202148 | \n",
" 0.0 | \n",
"
\n",
" \n",
"
\n",
"
3 rows × 25 columns
\n",
"
"
],
"text/plain": [
" file_name dataset emotion duration pitch_mean \\\n",
"0 03-01-01-01-01-01-01.wav RAVDESS neutral 5.0 573.830444 \n",
"1 201.wav CASIA unknown 5.0 815.843445 \n",
"2 a01.wav SAVEE angry 5.0 523.944702 \n",
"\n",
" pitch_std pitch_max pitch_min tuning_offset \\\n",
"0 853.130066 3988.073975 147.432693 -0.17 \n",
"1 1158.526733 3824.677246 171.179718 0.10 \n",
"2 591.257019 3405.564209 149.664169 -0.23 \n",
"\n",
" spectral_centroid_mean ... spectral_flatness_max spectral_flatness_min \\\n",
"0 2086.724971 ... 1.000001 7.847282e-05 \n",
"1 747.381791 ... 1.000001 2.586936e-06 \n",
"2 669.513790 ... 1.000001 8.574546e-08 \n",
"\n",
" rms_mean rms_std rms_max rms_min zero_crossing_rate_mean \\\n",
"0 0.001493 0.002882 0.012591 0.0 0.149477 \n",
"1 0.019801 0.039385 0.146754 0.0 0.039092 \n",
"2 0.097924 0.099660 0.433721 0.0 0.020286 \n",
"\n",
" zero_crossing_rate_std zero_crossing_rate_max zero_crossing_rate_min \n",
"0 0.170416 0.528320 0.0 \n",
"1 0.093996 0.526855 0.0 \n",
"2 0.032456 0.202148 0.0 \n",
"\n",
"[3 rows x 25 columns]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 定义常量\n",
"SAMPLE_RATE = 22050 # 统一采样率\n",
"MAX_DURATION = 5 # 最大音频长度(秒)\n",
"MAX_SAMPLES = SAMPLE_RATE * MAX_DURATION # 最大样本数\n",
"\n",
"# 加载音频文件\n",
"def load_audio(file_path):\n",
" \"\"\"\n",
" 加载音频文件\n",
" \n",
" Args:\n",
" file_path: 音频文件路径\n",
" \n",
" Returns:\n",
" audio: 音频数据\n",
" sr: 采样率\n",
" \"\"\"\n",
" # 加载音频\n",
" audio, sr = librosa.load(file_path, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" return audio, sr\n",
"\n",
"# 提取音高特征\n",
"def extract_pitch_features(audio, sr=SAMPLE_RATE):\n",
" \"\"\"\n",
" 提取音高特征\n",
" \n",
" Args:\n",
" audio: 音频信号\n",
" sr: 采样率\n",
" \n",
" Returns:\n",
" features: 音高特征字典\n",
" \"\"\"\n",
" features = {}\n",
" \n",
" # 使用piptrack提取音高\n",
" pitches, magnitudes = librosa.piptrack(y=audio, sr=sr)\n",
" \n",
" # 提取每帧最大幅度对应的音高\n",
" pitches_mean = []\n",
" for t in range(pitches.shape[1]):\n",
" idx = np.argmax(magnitudes[:, t])\n",
" pitch = pitches[idx, t]\n",
" if pitch > 0: # 过滤掉静音帧\n",
" pitches_mean.append(pitch)\n",
" \n",
" # 计算音高特征\n",
" if pitches_mean: # 确保有有效的音高值\n",
" features['pitch_mean'] = np.mean(pitches_mean)\n",
" features['pitch_std'] = np.std(pitches_mean) if len(pitches_mean) > 1 else 0\n",
" features['pitch_max'] = np.max(pitches_mean)\n",
" features['pitch_min'] = np.min(pitches_mean) if len(pitches_mean) > 0 else 0\n",
" else:\n",
" features['pitch_mean'] = 0\n",
" features['pitch_std'] = 0\n",
" features['pitch_max'] = 0\n",
" features['pitch_min'] = 0\n",
" \n",
" return features\n",
"\n",
"# 提取调谐偏差特征\n",
"def extract_tuning_features(audio, sr=SAMPLE_RATE):\n",
" \"\"\"\n",
" 提取调谐偏差特征\n",
" \n",
" Args:\n",
" audio: 音频信号\n",
" sr: 采样率\n",
" \n",
" Returns:\n",
" features: 调谐特征字典\n",
" \"\"\"\n",
" features = {}\n",
" \n",
" # 提取调谐偏差\n",
" tuning_offset = librosa.estimate_tuning(y=audio, sr=sr)\n",
" features['tuning_offset'] = tuning_offset\n",
" \n",
" return features\n",
"\n",
"# 提取频谱质心特征\n",
"def extract_spectral_centroid_features(audio, sr=SAMPLE_RATE):\n",
" \"\"\"\n",
" 提取频谱质心特征\n",
" \n",
" Args:\n",
" audio: 音频信号\n",
" sr: 采样率\n",
" \n",
" Returns:\n",
" features: 频谱质心特征字典\n",
" \"\"\"\n",
" features = {}\n",
" \n",
" # 提取频谱质心\n",
" spectral_centroid = librosa.feature.spectral_centroid(y=audio, sr=sr)[0]\n",
" \n",
" # 计算统计特征\n",
" features['spectral_centroid_mean'] = np.mean(spectral_centroid)\n",
" features['spectral_centroid_std'] = np.std(spectral_centroid)\n",
" features['spectral_centroid_max'] = np.max(spectral_centroid)\n",
" features['spectral_centroid_min'] = np.min(spectral_centroid)\n",
" \n",
" return features\n",
"\n",
"# 提取频谱平坦度特征\n",
"def extract_spectral_flatness_features(audio, sr=SAMPLE_RATE):\n",
" \"\"\"\n",
" 提取频谱平坦度特征\n",
" \n",
" Args:\n",
" audio: 音频信号\n",
" sr: 采样率\n",
" \n",
" Returns:\n",
" features: 频谱平坦度特征字典\n",
" \"\"\"\n",
" features = {}\n",
" \n",
" # 提取频谱平坦度\n",
" spectral_flatness = librosa.feature.spectral_flatness(y=audio)[0]\n",
" \n",
" # 计算统计特征\n",
" features['spectral_flatness_mean'] = np.mean(spectral_flatness)\n",
" features['spectral_flatness_std'] = np.std(spectral_flatness)\n",
" features['spectral_flatness_max'] = np.max(spectral_flatness)\n",
" features['spectral_flatness_min'] = np.min(spectral_flatness)\n",
" \n",
" return features\n",
"\n",
"# 提取均方根能量特征\n",
"def extract_rms_features(audio, sr=SAMPLE_RATE):\n",
" \"\"\"\n",
" 提取均方根能量(RMS)特征\n",
" \n",
" Args:\n",
" audio: 音频信号\n",
" sr: 采样率\n",
" \n",
" Returns:\n",
" features: RMS特征字典\n",
" \"\"\"\n",
" features = {}\n",
" \n",
" # 提取RMS\n",
" rms = librosa.feature.rms(y=audio)[0]\n",
" \n",
" # 计算统计特征\n",
" features['rms_mean'] = np.mean(rms)\n",
" features['rms_std'] = np.std(rms)\n",
" features['rms_max'] = np.max(rms)\n",
" features['rms_min'] = np.min(rms)\n",
" \n",
" # 添加零交叉率(ZCR)\n",
" zcr = librosa.feature.zero_crossing_rate(audio)[0]\n",
" features['zero_crossing_rate_mean'] = np.mean(zcr)\n",
" features['zero_crossing_rate_std'] = np.std(zcr)\n",
" features['zero_crossing_rate_max'] = np.max(zcr)\n",
" features['zero_crossing_rate_min'] = np.min(zcr)\n",
" \n",
" return features\n",
"\n",
"# 提取所有特征并创建DataFrame\n",
"def extract_all_features(audio, sr=SAMPLE_RATE):\n",
" \"\"\"\n",
" 从音频中提取所有特征\n",
" \n",
" Args:\n",
" audio: 音频信号\n",
" sr: 采样率\n",
" \n",
" Returns:\n",
" features: 特征字典\n",
" \"\"\"\n",
" features = {}\n",
" \n",
" # 提取各类特征\n",
" pitch_features = extract_pitch_features(audio, sr)\n",
" tuning_features = extract_tuning_features(audio, sr)\n",
" centroid_features = extract_spectral_centroid_features(audio, sr)\n",
" flatness_features = extract_spectral_flatness_features(audio, sr)\n",
" rms_features = extract_rms_features(audio, sr)\n",
" \n",
" # 合并所有特征\n",
" features.update(pitch_features)\n",
" features.update(tuning_features)\n",
" features.update(centroid_features)\n",
" features.update(flatness_features)\n",
" features.update(rms_features)\n",
" \n",
" return features\n",
"\n",
"# 加载并提取所有音频文件的特征\n",
"def process_audio_files(file_paths):\n",
" \"\"\"\n",
" 处理多个音频文件并返回包含所有特征的DataFrame\n",
" \n",
" Args:\n",
" file_paths: 音频文件路径列表\n",
" \n",
" Returns:\n",
" df: 包含所有特征的DataFrame\n",
" \"\"\"\n",
" features_list = []\n",
" \n",
" for file_path in file_paths:\n",
" # 提取文件信息\n",
" file_name = os.path.basename(file_path)\n",
" \n",
" # 确定情感类别(从文件路径推断)\n",
" emotion = \"unknown\"\n",
" dataset = \"unknown\"\n",
" \n",
" if \"RAVDESS\" in file_path:\n",
" dataset = \"RAVDESS\"\n",
" parts = file_name.split('-')\n",
" if len(parts) >= 3:\n",
" emotion_code = parts[2]\n",
" emotion_map = {'01': 'neutral', '03': 'happy', '04': 'sad', \n",
" '05': 'angry', '06': 'fear', '08': 'surprise'}\n",
" if emotion_code in emotion_map:\n",
" emotion = emotion_map[emotion_code]\n",
" elif \"CAISA\" in file_path:\n",
" dataset = \"CASIA\"\n",
" parts = file_path.split(os.sep)\n",
" if len(parts) >= 3:\n",
" emotion = parts[-2] # 假设倒数第二个目录是情感名称\n",
" elif \"SAVEE\" in file_path:\n",
" dataset = \"SAVEE\"\n",
" if file_name.startswith(\"sa\"):\n",
" emotion = \"sad\"\n",
" elif file_name.startswith(\"su\"):\n",
" emotion = \"surprise\"\n",
" elif file_name.startswith(\"a\"):\n",
" emotion = \"angry\"\n",
" elif file_name.startswith(\"f\"):\n",
" emotion = \"fear\"\n",
" elif file_name.startswith(\"h\"):\n",
" emotion = \"happy\"\n",
" elif file_name.startswith(\"n\"):\n",
" emotion = \"neutral\"\n",
" \n",
" try:\n",
" # 加载音频\n",
" audio, sr = load_audio(file_path)\n",
" \n",
" # 提取特征\n",
" features = extract_all_features(audio, sr)\n",
" \n",
" # 添加文件信息\n",
" features['file_name'] = file_name\n",
" features['dataset'] = dataset\n",
" features['emotion'] = emotion\n",
" features['duration'] = len(audio) / sr\n",
" \n",
" features_list.append(features)\n",
" except Exception as e:\n",
" print(f\"处理文件 {file_path} 时出错: {e}\")\n",
" \n",
" # 创建DataFrame\n",
" if features_list:\n",
" import pandas as pd\n",
" df = pd.DataFrame(features_list)\n",
" \n",
" # 调整列顺序,将文件信息放在前面\n",
" cols = ['file_name', 'dataset', 'emotion', 'duration'] + [col for col in df.columns if col not in ['file_name', 'dataset', 'emotion', 'duration']]\n",
" df = df[cols]\n",
" \n",
" return df\n",
" else:\n",
" print(\"没有成功处理任何文件\")\n",
" return None\n",
"\n",
"# 收集所有音频文件路径\n",
"audio_files = []\n",
"\n",
"# 添加RAVDESS数据集音频\n",
"ravdess_file = './RAVDESS/Actor_01/03-01-01-01-01-01-01.wav'\n",
"if os.path.exists(ravdess_file):\n",
" audio_files.append(ravdess_file)\n",
"\n",
"# 添加CASIA数据集音频\n",
"casia_file = './CAISA/liuchanhg/angry/201.wav'\n",
"if os.path.exists(casia_file):\n",
" audio_files.append(casia_file)\n",
"\n",
"# 添加SAVEE数据集音频\n",
"savee_file = './SAVEE/AudioData/DC/a01.wav'\n",
"if os.path.exists(savee_file):\n",
" audio_files.append(savee_file)\n",
"\n",
"# 处理音频文件并创建DataFrame\n",
"if audio_files:\n",
" print(f\"正在处理 {len(audio_files)} 个音频文件...\")\n",
" features_df = process_audio_files(audio_files)\n",
" \n",
" # 显示DataFrame\n",
" if features_df is not None:\n",
" print(\"\\n音频特征DataFrame:\")\n",
" display(features_df)\n",
"else:\n",
" print(\"未找到任何音频文件\")\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"# 2. 特征工程\n",
"\n",
"在这一部分,我们将从音频信号中提取各种声学特征,这些特征对于情感识别非常重要。\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 2.1 构建音高、倾斜调谐偏差指标的代码\n",
"在这一节中,我们将实现从音频中提取音高和调谐偏差指标的功能。这些特征可以帮助我们捕捉说话者的语调变化,对情感识别有重要意义。\n"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [],
"source": [
"# 导入必要的库\n",
"import os\n",
"import numpy as np\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"import librosa\n",
"import librosa.display\n",
"\n",
"# 定义常量\n",
"SAMPLE_RATE = 22050 # 统一采样率\n",
"MAX_DURATION = 5 # 最大音频长度(秒)\n",
"MAX_SAMPLES = SAMPLE_RATE * MAX_DURATION # 最大样本数\n",
"\n",
"# 加载音频并提取特征的函数\n",
"def extract_audio_features(file_path):\n",
" \"\"\"\n",
" 加载音频文件并提取音频特征到DataFrame\n",
" \n",
" Args:\n",
" file_path: 音频文件路径\n",
" \n",
" Returns:\n",
" features_df: 包含音频特征的DataFrame\n",
" audio: 音频数据\n",
" sr: 采样率\n",
" \"\"\"\n",
" # 加载音频\n",
" audio, sr = librosa.load(file_path, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 提取音高特征\n",
" pitches, magnitudes = librosa.piptrack(y=audio, sr=sr)\n",
" \n",
" # 提取每帧最大幅度对应的音高\n",
" pitch_values = []\n",
" for t in range(pitches.shape[1]):\n",
" idx = np.argmax(magnitudes[:, t])\n",
" pitch = pitches[idx, t]\n",
" if pitch > 0: # 过滤掉静音帧\n",
" pitch_values.append(pitch)\n",
" \n",
" # 提取调谐偏差\n",
" tuning_offset = librosa.estimate_tuning(y=audio, sr=sr)\n",
" \n",
" # 提取频谱质心\n",
" spectral_centroid = librosa.feature.spectral_centroid(y=audio, sr=sr)[0]\n",
" \n",
" # 提取频谱平坦度\n",
" spectral_flatness = librosa.feature.spectral_flatness(y=audio)[0]\n",
" \n",
" # 提取零交叉率\n",
" zero_crossing_rate = librosa.feature.zero_crossing_rate(audio)[0]\n",
" \n",
" # 提取RMS能量\n",
" rms = librosa.feature.rms(y=audio)[0]\n",
" \n",
" # 提取MFCC\n",
" mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=13)\n",
" \n",
" # 创建特征DataFrame\n",
" features = {\n",
" 'pitch_mean': np.mean(pitch_values) if pitch_values else 0,\n",
" 'pitch_std': np.std(pitch_values) if len(pitch_values) > 1 else 0,\n",
" 'pitch_max': np.max(pitch_values) if pitch_values else 0,\n",
" 'pitch_min': np.min(pitch_values) if pitch_values else 0,\n",
" 'tuning_offset': tuning_offset,\n",
" 'spectral_centroid_mean': np.mean(spectral_centroid),\n",
" 'spectral_centroid_std': np.std(spectral_centroid),\n",
" 'spectral_centroid_max': np.max(spectral_centroid),\n",
" 'spectral_centroid_min': np.min(spectral_centroid),\n",
" 'spectral_flatness_mean': np.mean(spectral_flatness),\n",
" 'spectral_flatness_std': np.std(spectral_flatness),\n",
" 'spectral_flatness_max': np.max(spectral_flatness),\n",
" 'spectral_flatness_min': np.min(spectral_flatness),\n",
" 'zero_crossing_rate_mean': np.mean(zero_crossing_rate),\n",
" 'zero_crossing_rate_std': np.std(zero_crossing_rate),\n",
" 'zero_crossing_rate_max': np.max(zero_crossing_rate),\n",
" 'zero_crossing_rate_min': np.min(zero_crossing_rate),\n",
" 'rms_mean': np.mean(rms),\n",
" 'rms_std': np.std(rms),\n",
" 'rms_max': np.max(rms),\n",
" 'rms_min': np.min(rms),\n",
" }\n",
" \n",
" # 添加MFCC特征\n",
" for i in range(13):\n",
" features[f'mfcc_{i+1}_mean'] = np.mean(mfccs[i])\n",
" features[f'mfcc_{i+1}_std'] = np.std(mfccs[i])\n",
" \n",
" # 转换为DataFrame\n",
" features_df = pd.DataFrame([features])\n",
" \n",
" return features_df, audio, sr\n"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"处理文件: ./RAVDESS/Actor_01/03-01-01-01-01-01-01.wav\n",
"处理文件: ./CAISA/liuchanhg/angry/201.wav\n",
"处理文件: ./SAVEE/AudioData/DC/a01.wav\n",
"\n",
"音频特征DataFrame:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" file_name | \n",
" dataset | \n",
" emotion | \n",
" pitch_mean | \n",
" pitch_std | \n",
" pitch_max | \n",
" pitch_min | \n",
" tuning_offset | \n",
" spectral_centroid_mean | \n",
" spectral_centroid_std | \n",
" ... | \n",
" mfcc_9_mean | \n",
" mfcc_9_std | \n",
" mfcc_10_mean | \n",
" mfcc_10_std | \n",
" mfcc_11_mean | \n",
" mfcc_11_std | \n",
" mfcc_12_mean | \n",
" mfcc_12_std | \n",
" mfcc_13_mean | \n",
" mfcc_13_std | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 03-01-01-01-01-01-01.wav | \n",
" RAVDESS | \n",
" neutral | \n",
" 573.830444 | \n",
" 853.130066 | \n",
" 3988.073975 | \n",
" 147.432693 | \n",
" -0.17 | \n",
" 2086.724971 | \n",
" 1955.973249 | \n",
" ... | \n",
" -9.014230 | \n",
" 17.056114 | \n",
" -0.240036 | \n",
" 6.110453 | \n",
" -0.998587 | \n",
" 7.636956 | \n",
" -0.585506 | \n",
" 7.082282 | \n",
" -0.012864 | \n",
" 8.772419 | \n",
"
\n",
" \n",
" | 1 | \n",
" 201.wav | \n",
" CASIA | \n",
" unknown | \n",
" 815.843445 | \n",
" 1158.526733 | \n",
" 3824.677246 | \n",
" 171.179718 | \n",
" 0.10 | \n",
" 747.381791 | \n",
" 1237.797995 | \n",
" ... | \n",
" -2.926738 | \n",
" 12.263833 | \n",
" -2.856271 | \n",
" 9.881656 | \n",
" 0.429380 | \n",
" 6.724971 | \n",
" -3.176131 | \n",
" 9.400505 | \n",
" 1.080766 | \n",
" 7.199394 | \n",
"
\n",
" \n",
" | 2 | \n",
" a01.wav | \n",
" SAVEE | \n",
" angry | \n",
" 523.944702 | \n",
" 591.257019 | \n",
" 3405.564209 | \n",
" 149.664169 | \n",
" -0.23 | \n",
" 669.513790 | \n",
" 916.785300 | \n",
" ... | \n",
" -0.700413 | \n",
" 10.004570 | \n",
" -8.432466 | \n",
" 15.594891 | \n",
" -1.799932 | \n",
" 11.306618 | \n",
" -0.687864 | \n",
" 8.437500 | \n",
" -0.647611 | \n",
" 8.446262 | \n",
"
\n",
" \n",
"
\n",
"
3 rows × 50 columns
\n",
"
"
],
"text/plain": [
" file_name dataset emotion pitch_mean pitch_std \\\n",
"0 03-01-01-01-01-01-01.wav RAVDESS neutral 573.830444 853.130066 \n",
"1 201.wav CASIA unknown 815.843445 1158.526733 \n",
"2 a01.wav SAVEE angry 523.944702 591.257019 \n",
"\n",
" pitch_max pitch_min tuning_offset spectral_centroid_mean \\\n",
"0 3988.073975 147.432693 -0.17 2086.724971 \n",
"1 3824.677246 171.179718 0.10 747.381791 \n",
"2 3405.564209 149.664169 -0.23 669.513790 \n",
"\n",
" spectral_centroid_std ... mfcc_9_mean mfcc_9_std mfcc_10_mean \\\n",
"0 1955.973249 ... -9.014230 17.056114 -0.240036 \n",
"1 1237.797995 ... -2.926738 12.263833 -2.856271 \n",
"2 916.785300 ... -0.700413 10.004570 -8.432466 \n",
"\n",
" mfcc_10_std mfcc_11_mean mfcc_11_std mfcc_12_mean mfcc_12_std \\\n",
"0 6.110453 -0.998587 7.636956 -0.585506 7.082282 \n",
"1 9.881656 0.429380 6.724971 -3.176131 9.400505 \n",
"2 15.594891 -1.799932 11.306618 -0.687864 8.437500 \n",
"\n",
" mfcc_13_mean mfcc_13_std \n",
"0 -0.012864 8.772419 \n",
"1 1.080766 7.199394 \n",
"2 -0.647611 8.446262 \n",
"\n",
"[3 rows x 50 columns]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"特征统计信息:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" pitch_mean | \n",
" pitch_std | \n",
" pitch_max | \n",
" pitch_min | \n",
" tuning_offset | \n",
" spectral_centroid_mean | \n",
" spectral_centroid_std | \n",
" spectral_centroid_max | \n",
" spectral_centroid_min | \n",
" spectral_flatness_mean | \n",
" ... | \n",
" mfcc_9_mean | \n",
" mfcc_9_std | \n",
" mfcc_10_mean | \n",
" mfcc_10_std | \n",
" mfcc_11_mean | \n",
" mfcc_11_std | \n",
" mfcc_12_mean | \n",
" mfcc_12_std | \n",
" mfcc_13_mean | \n",
" mfcc_13_std | \n",
"
\n",
" \n",
" \n",
" \n",
" | count | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.0 | \n",
" 3.000000 | \n",
" ... | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
" 3.000000 | \n",
"
\n",
" \n",
" | mean | \n",
" 637.872864 | \n",
" 867.637939 | \n",
" 3739.438477 | \n",
" 156.092209 | \n",
" -0.100000 | \n",
" 1167.873517 | \n",
" 1370.185515 | \n",
" 5290.721691 | \n",
" 0.0 | \n",
" 0.450286 | \n",
" ... | \n",
" -4.213793 | \n",
" 13.108172 | \n",
" -3.842924 | \n",
" 10.529000 | \n",
" -0.789713 | \n",
" 8.556182 | \n",
" -1.483167 | \n",
" 8.306762 | \n",
" 0.140097 | \n",
" 8.139359 | \n",
"
\n",
" \n",
" | std | \n",
" 156.132294 | \n",
" 283.912994 | \n",
" 300.464050 | \n",
" 13.113729 | \n",
" 0.175784 | \n",
" 796.700603 | \n",
" 532.092792 | \n",
" 1190.637435 | \n",
" 0.0 | \n",
" 0.185900 | \n",
" ... | \n",
" 4.303751 | \n",
" 3.600799 | \n",
" 4.184387 | \n",
" 4.775241 | \n",
" 1.129238 | \n",
" 2.425202 | \n",
" 1.467043 | \n",
" 1.164628 | \n",
" 0.874282 | \n",
" 0.830208 | \n",
"
\n",
" \n",
" | min | \n",
" 523.944702 | \n",
" 591.257019 | \n",
" 3405.564209 | \n",
" 147.432693 | \n",
" -0.230000 | \n",
" 669.513790 | \n",
" 916.785300 | \n",
" 4111.711753 | \n",
" 0.0 | \n",
" 0.259868 | \n",
" ... | \n",
" -9.014230 | \n",
" 10.004570 | \n",
" -8.432466 | \n",
" 6.110453 | \n",
" -1.799932 | \n",
" 6.724971 | \n",
" -3.176131 | \n",
" 7.082282 | \n",
" -0.647611 | \n",
" 7.199394 | \n",
"
\n",
" \n",
" | 25% | \n",
" 548.887573 | \n",
" 722.193542 | \n",
" 3615.120728 | \n",
" 148.548431 | \n",
" -0.200000 | \n",
" 708.447791 | \n",
" 1077.291648 | \n",
" 4689.754748 | \n",
" 0.0 | \n",
" 0.359773 | \n",
" ... | \n",
" -5.970484 | \n",
" 11.134202 | \n",
" -5.644368 | \n",
" 7.996054 | \n",
" -1.399260 | \n",
" 7.180964 | \n",
" -1.931997 | \n",
" 7.759891 | \n",
" -0.330237 | \n",
" 7.822828 | \n",
"
\n",
" \n",
" | 50% | \n",
" 573.830444 | \n",
" 853.130066 | \n",
" 3824.677246 | \n",
" 149.664169 | \n",
" -0.170000 | \n",
" 747.381791 | \n",
" 1237.797995 | \n",
" 5267.797743 | \n",
" 0.0 | \n",
" 0.459678 | \n",
" ... | \n",
" -2.926738 | \n",
" 12.263833 | \n",
" -2.856271 | \n",
" 9.881656 | \n",
" -0.998587 | \n",
" 7.636956 | \n",
" -0.687864 | \n",
" 8.437500 | \n",
" -0.012864 | \n",
" 8.446262 | \n",
"
\n",
" \n",
" | 75% | \n",
" 694.836945 | \n",
" 1005.828400 | \n",
" 3906.375610 | \n",
" 160.421944 | \n",
" -0.035000 | \n",
" 1417.053381 | \n",
" 1596.885622 | \n",
" 5880.226659 | \n",
" 0.0 | \n",
" 0.545495 | \n",
" ... | \n",
" -1.813576 | \n",
" 14.659974 | \n",
" -1.548153 | \n",
" 12.738273 | \n",
" -0.284604 | \n",
" 9.471787 | \n",
" -0.636685 | \n",
" 8.919003 | \n",
" 0.533951 | \n",
" 8.609341 | \n",
"
\n",
" \n",
" | max | \n",
" 815.843445 | \n",
" 1158.526733 | \n",
" 3988.073975 | \n",
" 171.179718 | \n",
" 0.100000 | \n",
" 2086.724971 | \n",
" 1955.973249 | \n",
" 6492.655576 | \n",
" 0.0 | \n",
" 0.631312 | \n",
" ... | \n",
" -0.700413 | \n",
" 17.056114 | \n",
" -0.240036 | \n",
" 15.594891 | \n",
" 0.429380 | \n",
" 11.306618 | \n",
" -0.585506 | \n",
" 9.400505 | \n",
" 1.080766 | \n",
" 8.772419 | \n",
"
\n",
" \n",
"
\n",
"
8 rows × 47 columns
\n",
"
"
],
"text/plain": [
" pitch_mean pitch_std pitch_max pitch_min tuning_offset \\\n",
"count 3.000000 3.000000 3.000000 3.000000 3.000000 \n",
"mean 637.872864 867.637939 3739.438477 156.092209 -0.100000 \n",
"std 156.132294 283.912994 300.464050 13.113729 0.175784 \n",
"min 523.944702 591.257019 3405.564209 147.432693 -0.230000 \n",
"25% 548.887573 722.193542 3615.120728 148.548431 -0.200000 \n",
"50% 573.830444 853.130066 3824.677246 149.664169 -0.170000 \n",
"75% 694.836945 1005.828400 3906.375610 160.421944 -0.035000 \n",
"max 815.843445 1158.526733 3988.073975 171.179718 0.100000 \n",
"\n",
" spectral_centroid_mean spectral_centroid_std spectral_centroid_max \\\n",
"count 3.000000 3.000000 3.000000 \n",
"mean 1167.873517 1370.185515 5290.721691 \n",
"std 796.700603 532.092792 1190.637435 \n",
"min 669.513790 916.785300 4111.711753 \n",
"25% 708.447791 1077.291648 4689.754748 \n",
"50% 747.381791 1237.797995 5267.797743 \n",
"75% 1417.053381 1596.885622 5880.226659 \n",
"max 2086.724971 1955.973249 6492.655576 \n",
"\n",
" spectral_centroid_min spectral_flatness_mean ... mfcc_9_mean \\\n",
"count 3.0 3.000000 ... 3.000000 \n",
"mean 0.0 0.450286 ... -4.213793 \n",
"std 0.0 0.185900 ... 4.303751 \n",
"min 0.0 0.259868 ... -9.014230 \n",
"25% 0.0 0.359773 ... -5.970484 \n",
"50% 0.0 0.459678 ... -2.926738 \n",
"75% 0.0 0.545495 ... -1.813576 \n",
"max 0.0 0.631312 ... -0.700413 \n",
"\n",
" mfcc_9_std mfcc_10_mean mfcc_10_std mfcc_11_mean mfcc_11_std \\\n",
"count 3.000000 3.000000 3.000000 3.000000 3.000000 \n",
"mean 13.108172 -3.842924 10.529000 -0.789713 8.556182 \n",
"std 3.600799 4.184387 4.775241 1.129238 2.425202 \n",
"min 10.004570 -8.432466 6.110453 -1.799932 6.724971 \n",
"25% 11.134202 -5.644368 7.996054 -1.399260 7.180964 \n",
"50% 12.263833 -2.856271 9.881656 -0.998587 7.636956 \n",
"75% 14.659974 -1.548153 12.738273 -0.284604 9.471787 \n",
"max 17.056114 -0.240036 15.594891 0.429380 11.306618 \n",
"\n",
" mfcc_12_mean mfcc_12_std mfcc_13_mean mfcc_13_std \n",
"count 3.000000 3.000000 3.000000 3.000000 \n",
"mean -1.483167 8.306762 0.140097 8.139359 \n",
"std 1.467043 1.164628 0.874282 0.830208 \n",
"min -3.176131 7.082282 -0.647611 7.199394 \n",
"25% -1.931997 7.759891 -0.330237 7.822828 \n",
"50% -0.687864 8.437500 -0.012864 8.446262 \n",
"75% -0.636685 8.919003 0.533951 8.609341 \n",
"max -0.585506 9.400505 1.080766 8.772419 \n",
"\n",
"[8 rows x 47 columns]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 使用提取特征函数测试几个音频文件\n",
"# 收集音频文件路径\n",
"audio_files = []\n",
"\n",
"# 添加RAVDESS数据集音频\n",
"ravdess_file = './RAVDESS/Actor_01/03-01-01-01-01-01-01.wav'\n",
"if os.path.exists(ravdess_file):\n",
" audio_files.append(ravdess_file)\n",
"\n",
"# 添加CASIA数据集音频\n",
"casia_file = './CAISA/liuchanhg/angry/201.wav'\n",
"if os.path.exists(casia_file):\n",
" audio_files.append(casia_file)\n",
"\n",
"# 添加SAVEE数据集音频\n",
"savee_file = './SAVEE/AudioData/DC/a01.wav'\n",
"if os.path.exists(savee_file):\n",
" audio_files.append(savee_file)\n",
"\n",
"# 存储提取的特征\n",
"all_features_df = pd.DataFrame()\n",
"\n",
"# 处理每个音频文件并提取特征\n",
"for file_path in audio_files:\n",
" print(f\"处理文件: {file_path}\")\n",
" \n",
" # 提取文件信息\n",
" file_name = os.path.basename(file_path)\n",
" \n",
" # 提取特征\n",
" features_df, audio, sr = extract_audio_features(file_path)\n",
" \n",
" # 添加文件信息\n",
" features_df['file_name'] = file_name\n",
" \n",
" # 确定情感类别(从文件路径推断)\n",
" emotion = \"unknown\"\n",
" dataset = \"unknown\"\n",
" \n",
" if \"RAVDESS\" in file_path:\n",
" dataset = \"RAVDESS\"\n",
" parts = file_name.split('-')\n",
" if len(parts) >= 3:\n",
" emotion_code = parts[2]\n",
" emotion_map = {'01': 'neutral', '03': 'happy', '04': 'sad', \n",
" '05': 'angry', '06': 'fear', '08': 'surprise'}\n",
" if emotion_code in emotion_map:\n",
" emotion = emotion_map[emotion_code]\n",
" elif \"CAISA\" in file_path:\n",
" dataset = \"CASIA\"\n",
" parts = file_path.split(os.sep)\n",
" if len(parts) >= 3:\n",
" emotion = parts[-2] # 假设倒数第二个目录是情感名称\n",
" elif \"SAVEE\" in file_path:\n",
" dataset = \"SAVEE\"\n",
" if file_name.startswith(\"sa\"):\n",
" emotion = \"sad\"\n",
" elif file_name.startswith(\"su\"):\n",
" emotion = \"surprise\"\n",
" elif file_name.startswith(\"a\"):\n",
" emotion = \"angry\"\n",
" elif file_name.startswith(\"f\"):\n",
" emotion = \"fear\"\n",
" elif file_name.startswith(\"h\"):\n",
" emotion = \"happy\"\n",
" elif file_name.startswith(\"n\"):\n",
" emotion = \"neutral\"\n",
" \n",
" features_df['dataset'] = dataset\n",
" features_df['emotion'] = emotion\n",
" \n",
" # 将特征添加到总DataFrame\n",
" all_features_df = pd.concat([all_features_df, features_df], ignore_index=True)\n",
"\n",
"# 重新排列列,将文件信息放在前面\n",
"if not all_features_df.empty:\n",
" info_cols = ['file_name', 'dataset', 'emotion']\n",
" feature_cols = [col for col in all_features_df.columns if col not in info_cols]\n",
" all_features_df = all_features_df[info_cols + feature_cols]\n",
" \n",
" # 显示提取的音频特征\n",
" print(\"\\n音频特征DataFrame:\")\n",
" display(all_features_df)\n",
" \n",
" # 显示特征统计信息\n",
" print(\"\\n特征统计信息:\")\n",
" display(all_features_df.describe())\n",
"else:\n",
" print(\"未找到任何音频文件或处理过程中出错\")\n"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"使用RAVDESS音频文件进行测试: ./RAVDESS/Actor_01/03-01-01-01-01-01-01.wav\n",
"\n",
"音高帧级数据 (前10行):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" frame | \n",
" time | \n",
" pitch | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" 0.00000 | \n",
" 2458.481445 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" 0.02322 | \n",
" 182.268219 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2 | \n",
" 0.04644 | \n",
" 190.799026 | \n",
"
\n",
" \n",
" | 3 | \n",
" 3 | \n",
" 0.06966 | \n",
" 197.138947 | \n",
"
\n",
" \n",
" | 4 | \n",
" 4 | \n",
" 0.09288 | \n",
" 423.822876 | \n",
"
\n",
" \n",
" | 5 | \n",
" 5 | \n",
" 0.11610 | \n",
" 166.867813 | \n",
"
\n",
" \n",
" | 6 | \n",
" 6 | \n",
" 0.13932 | \n",
" 172.440811 | \n",
"
\n",
" \n",
" | 7 | \n",
" 7 | \n",
" 0.16254 | \n",
" 168.360764 | \n",
"
\n",
" \n",
" | 8 | \n",
" 8 | \n",
" 0.18576 | \n",
" 148.656494 | \n",
"
\n",
" \n",
" | 9 | \n",
" 9 | \n",
" 0.20898 | \n",
" 151.040848 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" frame time pitch\n",
"0 0 0.00000 2458.481445\n",
"1 1 0.02322 182.268219\n",
"2 2 0.04644 190.799026\n",
"3 3 0.06966 197.138947\n",
"4 4 0.09288 423.822876\n",
"5 5 0.11610 166.867813\n",
"6 6 0.13932 172.440811\n",
"7 7 0.16254 168.360764\n",
"8 8 0.18576 148.656494\n",
"9 9 0.20898 151.040848"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"音高和调谐统计特征:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" pitch_mean | \n",
" pitch_std | \n",
" pitch_max | \n",
" pitch_min | \n",
" pitch_range | \n",
" pitch_median | \n",
" tuning_offset | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 573.830444 | \n",
" 853.130066 | \n",
" 3988.073975 | \n",
" 147.432693 | \n",
" 3840.641357 | \n",
" 234.112061 | \n",
" -0.17 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" pitch_mean pitch_std pitch_max pitch_min pitch_range pitch_median \\\n",
"0 573.830444 853.130066 3988.073975 147.432693 3840.641357 234.112061 \n",
"\n",
" tuning_offset \n",
"0 -0.17 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"音高四分位数统计:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" pitch_q1 | \n",
" pitch_median | \n",
" pitch_q3 | \n",
" pitch_iqr | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 173.241608 | \n",
" 234.112061 | \n",
" 488.627747 | \n",
" 315.386139 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" pitch_q1 pitch_median pitch_q3 pitch_iqr\n",
"0 173.241608 234.112061 488.627747 315.386139"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 测试音高和调谐偏差特征提取,以DataFrame形式展示\n",
"try:\n",
" # 加载一个示例音频文件\n",
" ravdess_file = './RAVDESS/Actor_01/03-01-01-01-01-01-01.wav'\n",
" if os.path.exists(ravdess_file):\n",
" print(f\"使用RAVDESS音频文件进行测试: {ravdess_file}\")\n",
" audio, sr = librosa.load(ravdess_file, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 创建一个存储音高和调谐特征的DataFrame\n",
" pitch_df = pd.DataFrame()\n",
" \n",
" # 提取音高特征\n",
" pitches, magnitudes = librosa.piptrack(y=audio, sr=sr)\n",
" \n",
" # 提取每帧最大幅度对应的音高\n",
" pitch_values = []\n",
" times_list = []\n",
" frame_indices = []\n",
" \n",
" for t in range(pitches.shape[1]):\n",
" idx = np.argmax(magnitudes[:, t])\n",
" pitch = pitches[idx, t]\n",
" time = t * 512 / sr # 计算时间点\n",
" \n",
" if pitch > 0: # 过滤掉静音帧\n",
" pitch_values.append(pitch)\n",
" times_list.append(time)\n",
" frame_indices.append(t)\n",
" \n",
" # 创建音高帧级DataFrame\n",
" pitch_frames_df = pd.DataFrame({\n",
" 'frame': frame_indices,\n",
" 'time': times_list,\n",
" 'pitch': pitch_values\n",
" })\n",
" \n",
" # 计算音高统计特征\n",
" pitch_stats = {\n",
" 'pitch_mean': np.mean(pitch_values) if pitch_values else 0,\n",
" 'pitch_std': np.std(pitch_values) if len(pitch_values) > 1 else 0,\n",
" 'pitch_max': np.max(pitch_values) if pitch_values else 0,\n",
" 'pitch_min': np.min(pitch_values) if pitch_values else 0,\n",
" 'pitch_range': np.ptp(pitch_values) if pitch_values else 0, # 峰峰值\n",
" 'pitch_median': np.median(pitch_values) if pitch_values else 0\n",
" }\n",
" \n",
" # 提取调谐偏差\n",
" tuning_offset = librosa.estimate_tuning(y=audio, sr=sr)\n",
" pitch_stats['tuning_offset'] = tuning_offset\n",
" \n",
" # 创建统计特征DataFrame\n",
" pitch_stats_df = pd.DataFrame([pitch_stats])\n",
" \n",
" # 展示结果\n",
" print(\"\\n音高帧级数据 (前10行):\")\n",
" display(pitch_frames_df.head(10))\n",
" \n",
" print(\"\\n音高和调谐统计特征:\")\n",
" display(pitch_stats_df)\n",
" \n",
" # 计算音高四分位数\n",
" q1 = np.percentile(pitch_values, 25) if pitch_values else 0\n",
" q3 = np.percentile(pitch_values, 75) if pitch_values else 0\n",
" iqr = q3 - q1\n",
" \n",
" quartile_stats = {\n",
" 'pitch_q1': q1,\n",
" 'pitch_median': np.median(pitch_values) if pitch_values else 0,\n",
" 'pitch_q3': q3,\n",
" 'pitch_iqr': iqr\n",
" }\n",
" \n",
" print(\"\\n音高四分位数统计:\")\n",
" display(pd.DataFrame([quartile_stats]))\n",
" \n",
" else:\n",
" print(\"RAVDESS音频示例文件不存在\")\n",
" \n",
"except Exception as e:\n",
" print(f\"提取特征时出错: {e}\")\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 2.2 构建频谱质心、光谱平坦度指标的代码\n",
"\n",
"频谱质心是频谱的质心,表示声音的\"亮度\"。频谱平坦度是描述频谱分布平坦程度的指标,可以区分噪声和音调声音。这些特征对于情感识别也非常重要。\n"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"使用RAVDESS音频文件进行测试: ./RAVDESS/Actor_01/03-01-01-01-01-01-01.wav\n",
"\n",
"频谱质心和频谱平坦度帧级数据 (前10行):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" frame | \n",
" time | \n",
" spectral_centroid | \n",
" spectral_flatness | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" 0.00000 | \n",
" 4785.214012 | \n",
" 0.602522 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" 0.02322 | \n",
" 4783.377794 | \n",
" 0.729877 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2 | \n",
" 0.04644 | \n",
" 4619.471629 | \n",
" 0.619756 | \n",
"
\n",
" \n",
" | 3 | \n",
" 3 | \n",
" 0.06966 | \n",
" 4579.571027 | \n",
" 0.507635 | \n",
"
\n",
" \n",
" | 4 | \n",
" 4 | \n",
" 0.09288 | \n",
" 4589.515428 | \n",
" 0.441491 | \n",
"
\n",
" \n",
" | 5 | \n",
" 5 | \n",
" 0.11610 | \n",
" 4549.248625 | \n",
" 0.446107 | \n",
"
\n",
" \n",
" | 6 | \n",
" 6 | \n",
" 0.13932 | \n",
" 4404.914089 | \n",
" 0.428921 | \n",
"
\n",
" \n",
" | 7 | \n",
" 7 | \n",
" 0.16254 | \n",
" 4186.607639 | \n",
" 0.286726 | \n",
"
\n",
" \n",
" | 8 | \n",
" 8 | \n",
" 0.18576 | \n",
" 4229.668787 | \n",
" 0.306454 | \n",
"
\n",
" \n",
" | 9 | \n",
" 9 | \n",
" 0.20898 | \n",
" 4518.854683 | \n",
" 0.434580 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" frame time spectral_centroid spectral_flatness\n",
"0 0 0.00000 4785.214012 0.602522\n",
"1 1 0.02322 4783.377794 0.729877\n",
"2 2 0.04644 4619.471629 0.619756\n",
"3 3 0.06966 4579.571027 0.507635\n",
"4 4 0.09288 4589.515428 0.441491\n",
"5 5 0.11610 4549.248625 0.446107\n",
"6 6 0.13932 4404.914089 0.428921\n",
"7 7 0.16254 4186.607639 0.286726\n",
"8 8 0.18576 4229.668787 0.306454\n",
"9 9 0.20898 4518.854683 0.434580"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"频谱质心和频谱平坦度统计特征:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" spectral_centroid_mean | \n",
" spectral_centroid_std | \n",
" spectral_centroid_max | \n",
" spectral_centroid_min | \n",
" spectral_centroid_median | \n",
" spectral_centroid_q1 | \n",
" spectral_centroid_q3 | \n",
" spectral_flatness_mean | \n",
" spectral_flatness_std | \n",
" spectral_flatness_max | \n",
" spectral_flatness_min | \n",
" spectral_flatness_median | \n",
" spectral_flatness_q1 | \n",
" spectral_flatness_q3 | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 2086.724971 | \n",
" 1955.973249 | \n",
" 6492.655576 | \n",
" 0.0 | \n",
" 1411.301154 | \n",
" 0.0 | \n",
" 4177.900461 | \n",
" 0.459678 | \n",
" 0.425451 | \n",
" 1.000001 | \n",
" 0.000078 | \n",
" 0.358098 | \n",
" 0.022675 | \n",
" 1.000001 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" spectral_centroid_mean spectral_centroid_std spectral_centroid_max \\\n",
"0 2086.724971 1955.973249 6492.655576 \n",
"\n",
" spectral_centroid_min spectral_centroid_median spectral_centroid_q1 \\\n",
"0 0.0 1411.301154 0.0 \n",
"\n",
" spectral_centroid_q3 spectral_flatness_mean spectral_flatness_std \\\n",
"0 4177.900461 0.459678 0.425451 \n",
"\n",
" spectral_flatness_max spectral_flatness_min spectral_flatness_median \\\n",
"0 1.000001 0.000078 0.358098 \n",
"\n",
" spectral_flatness_q1 spectral_flatness_q3 \n",
"0 0.022675 1.000001 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"频谱质心和频谱平坦度相关性: -0.4960\n",
"\n",
"百分位数统计:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" centroid_p10 | \n",
" flatness_p10 | \n",
" centroid_p25 | \n",
" flatness_p25 | \n",
" centroid_p50 | \n",
" flatness_p50 | \n",
" centroid_p75 | \n",
" flatness_p75 | \n",
" centroid_p90 | \n",
" flatness_p90 | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0.0 | \n",
" 0.000577 | \n",
" 0.0 | \n",
" 0.022675 | \n",
" 1411.301154 | \n",
" 0.358098 | \n",
" 4177.900461 | \n",
" 1.000001 | \n",
" 4703.581505 | \n",
" 1.000001 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" centroid_p10 flatness_p10 centroid_p25 flatness_p25 centroid_p50 \\\n",
"0 0.0 0.000577 0.0 0.022675 1411.301154 \n",
"\n",
" flatness_p50 centroid_p75 flatness_p75 centroid_p90 flatness_p90 \n",
"0 0.358098 4177.900461 1.000001 4703.581505 1.000001 "
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 测试频谱质心和频谱平坦度特征提取,并以DataFrame形式展示\n",
"try:\n",
" # 加载一个示例音频文件\n",
" ravdess_file = './RAVDESS/Actor_01/03-01-01-01-01-01-01.wav'\n",
" if os.path.exists(ravdess_file):\n",
" print(f\"使用RAVDESS音频文件进行测试: {ravdess_file}\")\n",
" audio, sr = librosa.load(ravdess_file, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 提取频谱质心\n",
" spectral_centroid = librosa.feature.spectral_centroid(y=audio, sr=sr)[0]\n",
" \n",
" # 提取频谱平坦度\n",
" spectral_flatness = librosa.feature.spectral_flatness(y=audio)[0]\n",
" \n",
" # 获取时间点\n",
" times = librosa.times_like(spectral_centroid)\n",
" \n",
" # 创建帧级特征DataFrame\n",
" frames_data = []\n",
" for i, t in enumerate(times):\n",
" if i < len(spectral_centroid) and i < len(spectral_flatness):\n",
" frames_data.append({\n",
" 'frame': i,\n",
" 'time': t,\n",
" 'spectral_centroid': spectral_centroid[i],\n",
" 'spectral_flatness': spectral_flatness[i]\n",
" })\n",
" \n",
" # 创建DataFrame\n",
" frames_df = pd.DataFrame(frames_data)\n",
" \n",
" # 计算统计特征\n",
" centroid_stats = {\n",
" 'spectral_centroid_mean': np.mean(spectral_centroid),\n",
" 'spectral_centroid_std': np.std(spectral_centroid),\n",
" 'spectral_centroid_max': np.max(spectral_centroid),\n",
" 'spectral_centroid_min': np.min(spectral_centroid),\n",
" 'spectral_centroid_median': np.median(spectral_centroid),\n",
" 'spectral_centroid_q1': np.percentile(spectral_centroid, 25),\n",
" 'spectral_centroid_q3': np.percentile(spectral_centroid, 75)\n",
" }\n",
" \n",
" flatness_stats = {\n",
" 'spectral_flatness_mean': np.mean(spectral_flatness),\n",
" 'spectral_flatness_std': np.std(spectral_flatness),\n",
" 'spectral_flatness_max': np.max(spectral_flatness),\n",
" 'spectral_flatness_min': np.min(spectral_flatness),\n",
" 'spectral_flatness_median': np.median(spectral_flatness),\n",
" 'spectral_flatness_q1': np.percentile(spectral_flatness, 25),\n",
" 'spectral_flatness_q3': np.percentile(spectral_flatness, 75)\n",
" }\n",
" \n",
" # 合并统计特征\n",
" stats = {**centroid_stats, **flatness_stats}\n",
" stats_df = pd.DataFrame([stats])\n",
" \n",
" # 显示帧级特征(前10行)\n",
" print(\"\\n频谱质心和频谱平坦度帧级数据 (前10行):\")\n",
" display(frames_df.head(10))\n",
" \n",
" # 显示统计特征\n",
" print(\"\\n频谱质心和频谱平坦度统计特征:\")\n",
" display(stats_df)\n",
" \n",
" # 计算相关性\n",
" correlation = np.corrcoef(spectral_centroid, spectral_flatness)[0, 1]\n",
" print(f\"\\n频谱质心和频谱平坦度相关性: {correlation:.4f}\")\n",
" \n",
" # 创建百分位数统计\n",
" percentiles = [10, 25, 50, 75, 90]\n",
" percentile_stats = {}\n",
" \n",
" for p in percentiles:\n",
" percentile_stats[f'centroid_p{p}'] = np.percentile(spectral_centroid, p)\n",
" percentile_stats[f'flatness_p{p}'] = np.percentile(spectral_flatness, p)\n",
" \n",
" print(\"\\n百分位数统计:\")\n",
" display(pd.DataFrame([percentile_stats]))\n",
" else:\n",
" print(\"RAVDESS音频示例文件不存在\")\n",
"except Exception as e:\n",
" print(f\"提取特征时出错: {e}\")\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 2.3 构建梅尔频率、光谱对比度指标的代码\n",
"\n",
"梅尔频率倒谱系数(MFCC)是音频处理中最常用的特征,模拟人耳对声音的感知。光谱对比度衡量谱带之间的差异,能够捕捉音调和节奏的变化。\n"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"使用RAVDESS音频文件进行测试: ./RAVDESS/Actor_01/03-01-01-01-01-01-01.wav\n",
"\n",
"MFCC帧级数据 (前5行):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" frame | \n",
" time | \n",
" mfcc_1 | \n",
" mfcc_2 | \n",
" mfcc_3 | \n",
" mfcc_4 | \n",
" mfcc_5 | \n",
" mfcc_6 | \n",
" mfcc_7 | \n",
" mfcc_8 | \n",
" mfcc_9 | \n",
" mfcc_10 | \n",
" mfcc_11 | \n",
" mfcc_12 | \n",
" mfcc_13 | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" 0.00000 | \n",
" -857.305847 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" 0.02322 | \n",
" -857.305847 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2 | \n",
" 0.04644 | \n",
" -857.305847 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 3 | \n",
" 3 | \n",
" 0.06966 | \n",
" -857.305847 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
" | 4 | \n",
" 4 | \n",
" 0.09288 | \n",
" -857.305847 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
" 0.0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" frame time mfcc_1 mfcc_2 mfcc_3 mfcc_4 mfcc_5 mfcc_6 mfcc_7 \\\n",
"0 0 0.00000 -857.305847 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"1 1 0.02322 -857.305847 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"2 2 0.04644 -857.305847 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"3 3 0.06966 -857.305847 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"4 4 0.09288 -857.305847 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"\n",
" mfcc_8 mfcc_9 mfcc_10 mfcc_11 mfcc_12 mfcc_13 \n",
"0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 0.0 0.0 0.0 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"光谱对比度帧级数据 (前5行):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" frame | \n",
" time | \n",
" contrast_band_1 | \n",
" contrast_band_2 | \n",
" contrast_band_3 | \n",
" contrast_band_4 | \n",
" contrast_band_5 | \n",
" contrast_band_6 | \n",
" contrast_band_7 | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" 0.00000 | \n",
" 0.261872 | \n",
" 0.925997 | \n",
" 4.476748 | \n",
" 2.103019 | \n",
" 4.643754 | \n",
" 9.242361 | \n",
" 41.680347 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" 0.02322 | \n",
" 2.949578 | \n",
" 3.694045 | \n",
" 7.620502 | \n",
" 15.030630 | \n",
" 11.917979 | \n",
" 14.289726 | \n",
" 40.687895 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2 | \n",
" 0.04644 | \n",
" 2.732142 | \n",
" 5.549647 | \n",
" 9.467184 | \n",
" 7.868653 | \n",
" 15.430449 | \n",
" 10.744310 | \n",
" 38.656327 | \n",
"
\n",
" \n",
" | 3 | \n",
" 3 | \n",
" 0.06966 | \n",
" 8.873114 | \n",
" 6.092097 | \n",
" 13.238993 | \n",
" 9.561276 | \n",
" 13.876824 | \n",
" 12.928647 | \n",
" 38.942839 | \n",
"
\n",
" \n",
" | 4 | \n",
" 4 | \n",
" 0.09288 | \n",
" 13.186358 | \n",
" 7.774552 | \n",
" 9.024843 | \n",
" 14.182148 | \n",
" 13.927470 | \n",
" 12.691566 | \n",
" 40.009761 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" frame time contrast_band_1 contrast_band_2 contrast_band_3 \\\n",
"0 0 0.00000 0.261872 0.925997 4.476748 \n",
"1 1 0.02322 2.949578 3.694045 7.620502 \n",
"2 2 0.04644 2.732142 5.549647 9.467184 \n",
"3 3 0.06966 8.873114 6.092097 13.238993 \n",
"4 4 0.09288 13.186358 7.774552 9.024843 \n",
"\n",
" contrast_band_4 contrast_band_5 contrast_band_6 contrast_band_7 \n",
"0 2.103019 4.643754 9.242361 41.680347 \n",
"1 15.030630 11.917979 14.289726 40.687895 \n",
"2 7.868653 15.430449 10.744310 38.656327 \n",
"3 9.561276 13.876824 12.928647 38.942839 \n",
"4 14.182148 13.927470 12.691566 40.009761 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"MFCC和光谱对比度统计特征 (前10个):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" mfcc_1_mean | \n",
" mfcc_1_std | \n",
" mfcc_1_max | \n",
" mfcc_1_min | \n",
" mfcc_2_mean | \n",
" mfcc_2_std | \n",
" mfcc_2_max | \n",
" mfcc_2_min | \n",
" mfcc_3_mean | \n",
" mfcc_3_std | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" -753.195312 | \n",
" 164.561844 | \n",
" -394.404266 | \n",
" -857.305847 | \n",
" 38.492062 | \n",
" 66.268105 | \n",
" 203.227997 | \n",
" -94.004196 | \n",
" -1.693892 | \n",
" 16.70042 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" mfcc_1_mean mfcc_1_std mfcc_1_max mfcc_1_min mfcc_2_mean mfcc_2_std \\\n",
"0 -753.195312 164.561844 -394.404266 -857.305847 38.492062 66.268105 \n",
"\n",
" mfcc_2_max mfcc_2_min mfcc_3_mean mfcc_3_std \n",
"0 203.227997 -94.004196 -1.693892 16.70042 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"总共提取了 134 个特征\n",
"\n",
"特征数量统计:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" MFCC原始特征 | \n",
" MFCC一阶差分 | \n",
" MFCC二阶差分 | \n",
" 光谱对比度特征 | \n",
"
\n",
" \n",
" \n",
" \n",
" | 特征数 | \n",
" 52 | \n",
" 26 | \n",
" 26 | \n",
" 30 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" MFCC原始特征 MFCC一阶差分 MFCC二阶差分 光谱对比度特征\n",
"特征数 52 26 26 30"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 测试MFCC和光谱对比度特征提取,以DataFrame形式展示\n",
"try:\n",
" # 加载一个示例音频文件\n",
" ravdess_file = './RAVDESS/Actor_01/03-01-01-01-01-01-01.wav'\n",
" if os.path.exists(ravdess_file):\n",
" print(f\"使用RAVDESS音频文件进行测试: {ravdess_file}\")\n",
" audio, sr = librosa.load(ravdess_file, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 提取MFCC特征\n",
" n_mfcc = 13 # MFCC系数数量\n",
" mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=n_mfcc)\n",
" \n",
" # 提取光谱对比度特征\n",
" spectral_contrast = librosa.feature.spectral_contrast(y=audio, sr=sr)\n",
" \n",
" # 创建MFCC帧级特征DataFrame\n",
" mfcc_frames = []\n",
" times = librosa.times_like(mfccs[0])\n",
" \n",
" for t in range(len(times)):\n",
" frame_data = {'frame': t, 'time': times[t]}\n",
" \n",
" # 添加每个MFCC系数\n",
" for i in range(n_mfcc):\n",
" if t < len(mfccs[i]):\n",
" frame_data[f'mfcc_{i+1}'] = mfccs[i][t]\n",
" \n",
" mfcc_frames.append(frame_data)\n",
" \n",
" mfcc_frames_df = pd.DataFrame(mfcc_frames)\n",
" \n",
" # 创建MFCC统计特征\n",
" mfcc_stats = {}\n",
" for i in range(n_mfcc):\n",
" mfcc_stats[f'mfcc_{i+1}_mean'] = np.mean(mfccs[i])\n",
" mfcc_stats[f'mfcc_{i+1}_std'] = np.std(mfccs[i])\n",
" mfcc_stats[f'mfcc_{i+1}_max'] = np.max(mfccs[i])\n",
" mfcc_stats[f'mfcc_{i+1}_min'] = np.min(mfccs[i])\n",
" \n",
" # 计算MFCC的一阶差分\n",
" mfcc_delta = librosa.feature.delta(mfccs)\n",
" for i in range(n_mfcc):\n",
" mfcc_stats[f'mfcc_{i+1}_delta_mean'] = np.mean(mfcc_delta[i])\n",
" mfcc_stats[f'mfcc_{i+1}_delta_std'] = np.std(mfcc_delta[i])\n",
" \n",
" # 计算MFCC的二阶差分\n",
" mfcc_delta2 = librosa.feature.delta(mfccs, order=2)\n",
" for i in range(n_mfcc):\n",
" mfcc_stats[f'mfcc_{i+1}_delta2_mean'] = np.mean(mfcc_delta2[i])\n",
" mfcc_stats[f'mfcc_{i+1}_delta2_std'] = np.std(mfcc_delta2[i])\n",
" \n",
" # 创建光谱对比度帧级特征DataFrame\n",
" contrast_frames = []\n",
" contrast_times = librosa.times_like(spectral_contrast[0])\n",
" \n",
" for t in range(len(contrast_times)):\n",
" frame_data = {'frame': t, 'time': contrast_times[t]}\n",
" \n",
" # 添加每个频带的对比度\n",
" for i in range(spectral_contrast.shape[0]):\n",
" if t < len(spectral_contrast[i]):\n",
" frame_data[f'contrast_band_{i+1}'] = spectral_contrast[i][t]\n",
" \n",
" contrast_frames.append(frame_data)\n",
" \n",
" contrast_frames_df = pd.DataFrame(contrast_frames)\n",
" \n",
" # 创建光谱对比度统计特征\n",
" contrast_stats = {}\n",
" for i in range(spectral_contrast.shape[0]):\n",
" contrast_stats[f'contrast_band_{i+1}_mean'] = np.mean(spectral_contrast[i])\n",
" contrast_stats[f'contrast_band_{i+1}_std'] = np.std(spectral_contrast[i])\n",
" contrast_stats[f'contrast_band_{i+1}_max'] = np.max(spectral_contrast[i])\n",
" contrast_stats[f'contrast_band_{i+1}_min'] = np.min(spectral_contrast[i])\n",
" \n",
" # 光谱对比度的总体统计\n",
" contrast_stats['spectral_contrast_mean'] = np.mean(spectral_contrast)\n",
" contrast_stats['spectral_contrast_std'] = np.std(spectral_contrast)\n",
" \n",
" # 合并MFCC和光谱对比度统计特征\n",
" all_stats = {**mfcc_stats, **contrast_stats}\n",
" all_stats_df = pd.DataFrame([all_stats])\n",
" \n",
" # 显示结果\n",
" print(\"\\nMFCC帧级数据 (前5行):\")\n",
" display(mfcc_frames_df.head(5))\n",
" \n",
" print(\"\\n光谱对比度帧级数据 (前5行):\")\n",
" display(contrast_frames_df.head(5))\n",
" \n",
" print(\"\\nMFCC和光谱对比度统计特征 (前10个):\")\n",
" cols = list(all_stats_df.columns)[:10]\n",
" display(all_stats_df[cols])\n",
" \n",
" print(f\"\\n总共提取了 {len(all_stats)} 个特征\")\n",
" \n",
" # 按特征类型分组统计\n",
" feature_counts = {\n",
" 'MFCC原始特征': n_mfcc * 4,\n",
" 'MFCC一阶差分': n_mfcc * 2,\n",
" 'MFCC二阶差分': n_mfcc * 2,\n",
" '光谱对比度特征': spectral_contrast.shape[0] * 4 + 2\n",
" }\n",
" \n",
" print(\"\\n特征数量统计:\")\n",
" display(pd.DataFrame([feature_counts], index=['特征数']))\n",
" else:\n",
" print(\"RAVDESS音频示例文件不存在\")\n",
"except Exception as e:\n",
" print(f\"提取特征时出错: {e}\")\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 2.4 构建均方根能量、色谱图指标的代码\n",
"\n",
"均方根能量(RMS)反映了音频信号的能量变化,可以指示情感的强度。色谱图特征可以捕捉音高类特征,对分析情感变化很有帮助。\n"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"使用RAVDESS音频文件进行测试: ./RAVDESS/Actor_01/03-01-01-01-01-01-01.wav\n",
"\n",
"RMS和ZCR帧级数据 (前5行):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" frame | \n",
" time | \n",
" rms | \n",
" zcr | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" 0.00000 | \n",
" 6.232337e-07 | \n",
" 0.041504 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" 0.02322 | \n",
" 9.135177e-07 | \n",
" 0.069824 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2 | \n",
" 0.04644 | \n",
" 1.276243e-06 | \n",
" 0.131348 | \n",
"
\n",
" \n",
" | 3 | \n",
" 3 | \n",
" 0.06966 | \n",
" 1.604472e-06 | \n",
" 0.173828 | \n",
"
\n",
" \n",
" | 4 | \n",
" 4 | \n",
" 0.09288 | \n",
" 1.715774e-06 | \n",
" 0.193848 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" frame time rms zcr\n",
"0 0 0.00000 6.232337e-07 0.041504\n",
"1 1 0.02322 9.135177e-07 0.069824\n",
"2 2 0.04644 1.276243e-06 0.131348\n",
"3 3 0.06966 1.604472e-06 0.173828\n",
"4 4 0.09288 1.715774e-06 0.193848"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"色谱图帧级数据 (前5行):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" frame | \n",
" time | \n",
" chroma_1 | \n",
" chroma_2 | \n",
" chroma_3 | \n",
" chroma_4 | \n",
" chroma_5 | \n",
" chroma_6 | \n",
" chroma_7 | \n",
" chroma_8 | \n",
" chroma_9 | \n",
" chroma_10 | \n",
" chroma_11 | \n",
" chroma_12 | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" 0.00000 | \n",
" 0.534806 | \n",
" 0.779990 | \n",
" 1.000000 | \n",
" 0.884072 | \n",
" 0.547614 | \n",
" 0.277783 | \n",
" 0.223865 | \n",
" 0.226283 | \n",
" 0.266252 | \n",
" 0.372628 | \n",
" 0.348106 | \n",
" 0.348874 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" 0.02322 | \n",
" 0.620370 | \n",
" 0.831862 | \n",
" 1.000000 | \n",
" 0.892350 | \n",
" 0.599051 | \n",
" 0.378208 | \n",
" 0.319750 | \n",
" 0.332158 | \n",
" 0.362094 | \n",
" 0.462163 | \n",
" 0.450810 | \n",
" 0.447287 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2 | \n",
" 0.04644 | \n",
" 0.829280 | \n",
" 0.769134 | \n",
" 0.754131 | \n",
" 0.629990 | \n",
" 0.650650 | \n",
" 0.756760 | \n",
" 0.818477 | \n",
" 0.791697 | \n",
" 0.664502 | \n",
" 0.579084 | \n",
" 0.769260 | \n",
" 1.000000 | \n",
"
\n",
" \n",
" | 3 | \n",
" 3 | \n",
" 0.06966 | \n",
" 0.998285 | \n",
" 0.815828 | \n",
" 0.739085 | \n",
" 0.851994 | \n",
" 0.784696 | \n",
" 0.790131 | \n",
" 1.000000 | \n",
" 0.952804 | \n",
" 0.767395 | \n",
" 0.758635 | \n",
" 0.780154 | \n",
" 0.926421 | \n",
"
\n",
" \n",
" | 4 | \n",
" 4 | \n",
" 0.09288 | \n",
" 1.000000 | \n",
" 0.770530 | \n",
" 0.642109 | \n",
" 0.863174 | \n",
" 0.896374 | \n",
" 0.837818 | \n",
" 0.923541 | \n",
" 0.894363 | \n",
" 0.866183 | \n",
" 0.789348 | \n",
" 0.698850 | \n",
" 0.754964 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" frame time chroma_1 chroma_2 chroma_3 chroma_4 chroma_5 chroma_6 \\\n",
"0 0 0.00000 0.534806 0.779990 1.000000 0.884072 0.547614 0.277783 \n",
"1 1 0.02322 0.620370 0.831862 1.000000 0.892350 0.599051 0.378208 \n",
"2 2 0.04644 0.829280 0.769134 0.754131 0.629990 0.650650 0.756760 \n",
"3 3 0.06966 0.998285 0.815828 0.739085 0.851994 0.784696 0.790131 \n",
"4 4 0.09288 1.000000 0.770530 0.642109 0.863174 0.896374 0.837818 \n",
"\n",
" chroma_7 chroma_8 chroma_9 chroma_10 chroma_11 chroma_12 \n",
"0 0.223865 0.226283 0.266252 0.372628 0.348106 0.348874 \n",
"1 0.319750 0.332158 0.362094 0.462163 0.450810 0.447287 \n",
"2 0.818477 0.791697 0.664502 0.579084 0.769260 1.000000 \n",
"3 1.000000 0.952804 0.767395 0.758635 0.780154 0.926421 \n",
"4 0.923541 0.894363 0.866183 0.789348 0.698850 0.754964 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"RMS和ZCR统计特征:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" rms_mean | \n",
" rms_std | \n",
" rms_max | \n",
" rms_min | \n",
" rms_median | \n",
" rms_q1 | \n",
" rms_q3 | \n",
" zero_crossing_rate_mean | \n",
" zero_crossing_rate_std | \n",
" zero_crossing_rate_max | \n",
" zero_crossing_rate_min | \n",
" zero_crossing_rate_median | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0.001493 | \n",
" 0.002882 | \n",
" 0.012591 | \n",
" 0.0 | \n",
" 0.000003 | \n",
" 0.0 | \n",
" 0.000946 | \n",
" 0.149477 | \n",
" 0.170416 | \n",
" 0.52832 | \n",
" 0.0 | \n",
" 0.069336 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" rms_mean rms_std rms_max rms_min rms_median rms_q1 rms_q3 \\\n",
"0 0.001493 0.002882 0.012591 0.0 0.000003 0.0 0.000946 \n",
"\n",
" zero_crossing_rate_mean zero_crossing_rate_std zero_crossing_rate_max \\\n",
"0 0.149477 0.170416 0.52832 \n",
"\n",
" zero_crossing_rate_min zero_crossing_rate_median \n",
"0 0.0 0.069336 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"色谱图统计特征 (前10个):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" chroma_1_mean | \n",
" chroma_1_std | \n",
" chroma_1_max | \n",
" chroma_1_min | \n",
" chroma_2_mean | \n",
" chroma_2_std | \n",
" chroma_2_max | \n",
" chroma_2_min | \n",
" chroma_3_mean | \n",
" chroma_3_std | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0.44199 | \n",
" 0.396882 | \n",
" 1.0 | \n",
" 0.0 | \n",
" 0.397397 | \n",
" 0.365359 | \n",
" 1.0 | \n",
" 0.0 | \n",
" 0.340485 | \n",
" 0.340303 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" chroma_1_mean chroma_1_std chroma_1_max chroma_1_min chroma_2_mean \\\n",
"0 0.44199 0.396882 1.0 0.0 0.397397 \n",
"\n",
" chroma_2_std chroma_2_max chroma_2_min chroma_3_mean chroma_3_std \n",
"0 0.365359 1.0 0.0 0.340485 0.340303 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"梅尔频谱相关特征:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" mel_spec_mean | \n",
" mel_spec_std | \n",
" log_power_mean | \n",
" log_power_std | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0.00239 | \n",
" 0.033072 | \n",
" -69.638008 | \n",
" 7.839996 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" mel_spec_mean mel_spec_std log_power_mean log_power_std\n",
"0 0.00239 0.033072 -69.638008 7.839996"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"总共提取了 64 个特征\n",
"\n",
"特征数量统计:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" RMS能量特征 | \n",
" 零交叉率特征 | \n",
" 色谱图特征 | \n",
" 梅尔频谱相关特征 | \n",
"
\n",
" \n",
" \n",
" \n",
" | 特征数 | \n",
" 7 | \n",
" 5 | \n",
" 48 | \n",
" 4 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" RMS能量特征 零交叉率特征 色谱图特征 梅尔频谱相关特征\n",
"特征数 7 5 48 4"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 测试RMS、ZCR和色谱图特征提取,以DataFrame形式展示\n",
"try:\n",
" # 加载一个示例音频文件\n",
" ravdess_file = './RAVDESS/Actor_01/03-01-01-01-01-01-01.wav'\n",
" if os.path.exists(ravdess_file):\n",
" print(f\"使用RAVDESS音频文件进行测试: {ravdess_file}\")\n",
" audio, sr = librosa.load(ravdess_file, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 提取RMS\n",
" rms = librosa.feature.rms(y=audio)[0]\n",
" \n",
" # 提取零交叉率\n",
" zcr = librosa.feature.zero_crossing_rate(audio)[0]\n",
" \n",
" # 提取色谱图\n",
" chroma = librosa.feature.chroma_stft(y=audio, sr=sr)\n",
" \n",
" # 提取梅尔频谱\n",
" mel_spec = librosa.feature.melspectrogram(y=audio, sr=sr)\n",
" log_power = librosa.amplitude_to_db(mel_spec)\n",
" \n",
" # 创建RMS和ZCR帧级特征DataFrame\n",
" energy_frames = []\n",
" times = librosa.times_like(rms)\n",
" \n",
" for t in range(len(times)):\n",
" if t < len(rms) and t < len(zcr):\n",
" frame_data = {\n",
" 'frame': t,\n",
" 'time': times[t],\n",
" 'rms': rms[t],\n",
" 'zcr': zcr[t]\n",
" }\n",
" energy_frames.append(frame_data)\n",
" \n",
" energy_frames_df = pd.DataFrame(energy_frames)\n",
" \n",
" # 创建色谱图帧级特征DataFrame\n",
" chroma_frames = []\n",
" chroma_times = librosa.times_like(chroma[0])\n",
" \n",
" for t in range(len(chroma_times)):\n",
" frame_data = {'frame': t, 'time': chroma_times[t]}\n",
" \n",
" # 添加每个色度的值\n",
" for i in range(chroma.shape[0]):\n",
" if t < len(chroma[i]):\n",
" frame_data[f'chroma_{i+1}'] = chroma[i][t]\n",
" \n",
" chroma_frames.append(frame_data)\n",
" \n",
" chroma_frames_df = pd.DataFrame(chroma_frames)\n",
" \n",
" # 计算RMS和ZCR统计特征\n",
" energy_stats = {\n",
" 'rms_mean': np.mean(rms),\n",
" 'rms_std': np.std(rms),\n",
" 'rms_max': np.max(rms),\n",
" 'rms_min': np.min(rms),\n",
" 'rms_median': np.median(rms),\n",
" 'rms_q1': np.percentile(rms, 25),\n",
" 'rms_q3': np.percentile(rms, 75),\n",
" 'zero_crossing_rate_mean': np.mean(zcr),\n",
" 'zero_crossing_rate_std': np.std(zcr),\n",
" 'zero_crossing_rate_max': np.max(zcr),\n",
" 'zero_crossing_rate_min': np.min(zcr),\n",
" 'zero_crossing_rate_median': np.median(zcr)\n",
" }\n",
" \n",
" # 计算色谱图统计特征\n",
" chroma_stats = {}\n",
" for i in range(chroma.shape[0]):\n",
" chroma_stats[f'chroma_{i+1}_mean'] = np.mean(chroma[i])\n",
" chroma_stats[f'chroma_{i+1}_std'] = np.std(chroma[i])\n",
" chroma_stats[f'chroma_{i+1}_max'] = np.max(chroma[i])\n",
" chroma_stats[f'chroma_{i+1}_min'] = np.min(chroma[i])\n",
" \n",
" # 添加梅尔频谱相关特征\n",
" mel_stats = {\n",
" 'mel_spec_mean': np.mean(mel_spec),\n",
" 'mel_spec_std': np.std(mel_spec),\n",
" 'log_power_mean': np.mean(log_power),\n",
" 'log_power_std': np.std(log_power)\n",
" }\n",
" \n",
" # 合并所有统计特征\n",
" all_stats = {**energy_stats, **chroma_stats, **mel_stats}\n",
" all_stats_df = pd.DataFrame([all_stats])\n",
" \n",
" # 显示结果\n",
" print(\"\\nRMS和ZCR帧级数据 (前5行):\")\n",
" display(energy_frames_df.head(5))\n",
" \n",
" print(\"\\n色谱图帧级数据 (前5行):\")\n",
" display(chroma_frames_df.head(5))\n",
" \n",
" print(\"\\nRMS和ZCR统计特征:\")\n",
" energy_cols = [col for col in all_stats_df.columns if col.startswith('rms') or col.startswith('zero')]\n",
" display(all_stats_df[energy_cols])\n",
" \n",
" print(\"\\n色谱图统计特征 (前10个):\")\n",
" chroma_cols = [col for col in all_stats_df.columns if col.startswith('chroma')][:10]\n",
" display(all_stats_df[chroma_cols])\n",
" \n",
" print(\"\\n梅尔频谱相关特征:\")\n",
" mel_cols = [col for col in all_stats_df.columns if col.startswith('mel') or col.startswith('log')]\n",
" display(all_stats_df[mel_cols])\n",
" \n",
" print(f\"\\n总共提取了 {len(all_stats)} 个特征\")\n",
" \n",
" # 特征数量统计\n",
" feature_counts = {\n",
" 'RMS能量特征': len([col for col in all_stats_df.columns if col.startswith('rms')]),\n",
" '零交叉率特征': len([col for col in all_stats_df.columns if col.startswith('zero')]),\n",
" '色谱图特征': len([col for col in all_stats_df.columns if col.startswith('chroma')]),\n",
" '梅尔频谱相关特征': len([col for col in all_stats_df.columns if col.startswith('mel') or col.startswith('log')])\n",
" }\n",
" \n",
" print(\"\\n特征数量统计:\")\n",
" display(pd.DataFrame([feature_counts], index=['特征数']))\n",
" else:\n",
" print(\"RAVDESS音频示例文件不存在\")\n",
"except Exception as e:\n",
" print(f\"提取特征时出错: {e}\")\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 2.5 进行特征提取与处理\n",
"\n",
"接下来我们将从音频数据集(RAVDESS、CASIA和SAVEE)中提取特征\n"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"正在加载音频数据...\n",
"从RAVDESS数据集加载了 300 个样本\n",
"每种情感的限制: 50\n",
"情感分布:\n",
" angry: 50\n",
" fear: 50\n",
" happy: 50\n",
" neutral: 50\n",
" sad: 50\n",
" surprise: 50\n",
"从CASIA数据集加载了 300 个样本\n",
"每种情感的限制: 50\n",
"情感分布:\n",
" angry: 50\n",
" fear: 50\n",
" happy: 50\n",
" neutral: 50\n",
" sad: 50\n",
" surprise: 50\n",
"从SAVEE数据集加载了 300 个样本\n",
"每种情感的限制: 50\n",
"情感分布:\n",
" angry: 50\n",
" fear: 50\n",
" happy: 50\n",
" neutral: 50\n",
" sad: 50\n",
" surprise: 50\n",
"总共加载了 900 个样本\n",
"\n",
"正在提取特征...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"提取特征: 100%|██████████| 900/900 [00:35<00:00, 25.29it/s]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"提取了 21 个特征\n",
"\n",
"划分数据集...\n",
"训练集: 540 样本\n",
"验证集: 180 样本\n",
"测试集: 180 样本\n",
"\n",
"训练集情感分布:\n",
" angry: 90\n",
" fear: 90\n",
" happy: 90\n",
" neutral: 90\n",
" sad: 90\n",
" surprise: 90\n",
"\n",
"验证集情感分布:\n",
" angry: 30\n",
" fear: 30\n",
" happy: 30\n",
" neutral: 30\n",
" sad: 30\n",
" surprise: 30\n",
"\n",
"测试集情感分布:\n",
" angry: 30\n",
" fear: 30\n",
" happy: 30\n",
" neutral: 30\n",
" sad: 30\n",
" surprise: 30\n",
"\n",
"标准化特征...\n",
"重塑为LSTM输入格式...\n",
"编码标签...\n",
"类别映射: {np.str_('angry'): 0, np.str_('fear'): 1, np.str_('happy'): 2, np.str_('neutral'): 3, np.str_('sad'): 4, np.str_('surprise'): 5}\n",
"\n",
"LSTM输入形状:\n",
"训练集: (540, 1, 21)\n",
"验证集: (180, 1, 21)\n",
"测试集: (180, 1, 21)\n",
"训练标签: (540, 6)\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"#指定要处理的情感类别\n",
"SELECTED_EMOTIONS = ['angry', 'fear', 'happy', 'neutral', 'sad', 'surprise']\n",
"\n",
"# 情绪映射字典,将不同数据集的标签映射到统一的情感类别\n",
"EMOTION_MAPPING = {\n",
" # CASIA 情感映射\n",
" 'angry': 'angry',\n",
" 'fear': 'fear',\n",
" 'happy': 'happy',\n",
" 'neutral': 'neutral',\n",
" 'sad': 'sad',\n",
" 'surprise': 'surprise',\n",
" \n",
" # SAVEE 情感映射\n",
" 'a': 'angry',\n",
" 'f': 'fear',\n",
" 'h': 'happy',\n",
" 'n': 'neutral',\n",
" 'sa': 'sad',\n",
" 'su': 'surprise',\n",
" 'd': 'disgust', # 注意:SAVEE有厌恶情绪,但不在我们选择的情感中\n",
" \n",
" # RAVDESS 情感映射\n",
" '01': 'neutral',\n",
" '02': 'calm', # 注意:RAVDESS有平静情绪,但不在我们选择的情感中\n",
" '03': 'happy',\n",
" '04': 'sad',\n",
" '05': 'angry',\n",
" '06': 'fear',\n",
" '07': 'disgust', # 注意:RAVDESS有厌恶情绪,但不在我们选择的情感中\n",
" '08': 'surprise'\n",
"}\n",
"\n",
"# 语言映射\n",
"LANGUAGE_MAPPING = {\n",
" 'casia': 'zh', # 中文\n",
" 'savee': 'en', # 英文\n",
" 'ravdess': 'en' # 英文\n",
"}\n",
"\n",
"def load_ravdess_data(data_path='./RAVDESS', limit=None):\n",
" \"\"\"\n",
" 加载RAVDESS英文情感语音数据集\n",
" \n",
" Args:\n",
" data_path: RAVDESS数据集路径\n",
" limit: 每种情感加载的最大文件数量\n",
" \n",
" Returns:\n",
" data_list: 包含(音频数据, 情感标签)的列表\n",
" \"\"\"\n",
" data_list = []\n",
" \n",
" # 确保路径存在\n",
" if not os.path.exists(data_path):\n",
" print(f\"警告: RAVDESS数据路径不存在: {data_path}\")\n",
" return data_list\n",
" \n",
" # 获取所有语音目录\n",
" try:\n",
" actor_dirs = glob.glob(os.path.join(data_path, \"Actor_*\"))\n",
" if not actor_dirs:\n",
" print(f\"警告: RAVDESS语音目录为空: {data_path}\")\n",
" except Exception as e:\n",
" print(f\"错误: 无法获取RAVDESS语音目录: {e}\")\n",
" return data_list\n",
" \n",
" # 计算每种情感的文件数\n",
" emotion_counts = {}\n",
" \n",
" for actor_dir in actor_dirs:\n",
" audio_files = glob.glob(os.path.join(actor_dir, \"*.wav\"))\n",
" \n",
" for audio_file in audio_files:\n",
" file_name = os.path.basename(audio_file)\n",
" \n",
" # RAVDESS文件名格式: 03-01-05-01-02-01-12.wav\n",
" # 05 表示情感类别 (angry)\n",
" parts = file_name.split('-')\n",
" if len(parts) >= 3:\n",
" emotion = parts[2]\n",
" \n",
" # 检查是否支持该情感\n",
" if emotion in EMOTION_MAPPING:\n",
" mapped_emotion = EMOTION_MAPPING[emotion]\n",
" \n",
" # 只选择我们指定的情感类别\n",
" if mapped_emotion in SELECTED_EMOTIONS:\n",
" # 检查是否达到了每种情感的限制\n",
" if limit is not None:\n",
" emotion_counts[mapped_emotion] = emotion_counts.get(mapped_emotion, 0) + 1\n",
" if emotion_counts[mapped_emotion] > limit:\n",
" continue\n",
" \n",
" try:\n",
" # 加载音频\n",
" audio, sr = librosa.load(audio_file, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 将数据和标签添加到列表\n",
" data_list.append((audio, mapped_emotion))\n",
" \n",
" except Exception as e:\n",
" print(f\"处理文件 {audio_file} 时出错: {e}\")\n",
" \n",
" print(f\"从RAVDESS数据集加载了 {len(data_list)} 个样本\")\n",
" if limit is not None:\n",
" print(f\"每种情感的限制: {limit}\")\n",
" \n",
" # 打印每种情感的样本数量\n",
" emotion_distribution = {}\n",
" for _, emotion in data_list:\n",
" emotion_distribution[emotion] = emotion_distribution.get(emotion, 0) + 1\n",
" \n",
" print(\"情感分布:\")\n",
" for emotion in SELECTED_EMOTIONS:\n",
" count = emotion_distribution.get(emotion, 0)\n",
" print(f\" {emotion}: {count}\")\n",
" \n",
" return data_list\n",
"\n",
"def load_casia_data(data_path='./CAISA', limit=None):\n",
" \"\"\"\n",
" 加载CASIA中文情感语音数据集\n",
" \n",
" Args:\n",
" data_path: CASIA数据集路径\n",
" limit: 每种情感加载的最大文件数量\n",
" \n",
" Returns:\n",
" data_list: 包含(音频数据, 情感标签)的列表\n",
" \"\"\"\n",
" data_list = []\n",
" \n",
" # 确保路径存在\n",
" if not os.path.exists(data_path):\n",
" print(f\"警告: CASIA数据路径不存在: {data_path}\")\n",
" return data_list\n",
" \n",
" # 计算每种情感的文件数\n",
" emotion_counts = {}\n",
" \n",
" # 获取所有演员目录\n",
" try:\n",
" actors = os.listdir(data_path)\n",
" except Exception as e:\n",
" print(f\"错误: 无法读取CASIA目录: {e}\")\n",
" return data_list\n",
" \n",
" for actor in actors:\n",
" # 跳过隐藏文件或非目录\n",
" actor_path = os.path.join(data_path, actor)\n",
" if not os.path.isdir(actor_path) or actor.startswith('_'):\n",
" continue\n",
" \n",
" emotions = os.listdir(actor_path)\n",
" \n",
" for emotion in emotions:\n",
" # 跳过隐藏文件或非目录\n",
" emotion_path = os.path.join(actor_path, emotion)\n",
" if not os.path.isdir(emotion_path) or emotion.startswith('_'):\n",
" continue\n",
" \n",
" # 检查是否支持该情感\n",
" if emotion in EMOTION_MAPPING:\n",
" mapped_emotion = EMOTION_MAPPING[emotion]\n",
" \n",
" # 只选择我们指定的情感类别\n",
" if mapped_emotion in SELECTED_EMOTIONS:\n",
" audio_files = glob.glob(os.path.join(emotion_path, \"*.wav\"))\n",
" \n",
" for audio_file in audio_files:\n",
" # 检查是否达到了每种情感的限制\n",
" if limit is not None:\n",
" emotion_counts[mapped_emotion] = emotion_counts.get(mapped_emotion, 0) + 1\n",
" if emotion_counts[mapped_emotion] > limit:\n",
" continue\n",
" \n",
" try:\n",
" # 加载音频\n",
" audio, sr = librosa.load(audio_file, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 将数据和标签添加到列表\n",
" data_list.append((audio, mapped_emotion))\n",
" \n",
" except Exception as e:\n",
" print(f\"处理文件 {audio_file} 时出错: {e}\")\n",
" \n",
" print(f\"从CASIA数据集加载了 {len(data_list)} 个样本\")\n",
" if limit is not None:\n",
" print(f\"每种情感的限制: {limit}\")\n",
" \n",
" # 打印每种情感的样本数量\n",
" emotion_distribution = {}\n",
" for _, emotion in data_list:\n",
" emotion_distribution[emotion] = emotion_distribution.get(emotion, 0) + 1\n",
" \n",
" print(\"情感分布:\")\n",
" for emotion in SELECTED_EMOTIONS:\n",
" count = emotion_distribution.get(emotion, 0)\n",
" print(f\" {emotion}: {count}\")\n",
" \n",
" return data_list\n",
"\n",
"def load_savee_data(data_path='./SAVEE', limit=None):\n",
" \"\"\"\n",
" 加载SAVEE英文情感语音数据集\n",
" \n",
" Args:\n",
" data_path: SAVEE数据集路径\n",
" limit: 每种情感加载的最大文件数量\n",
" \n",
" Returns:\n",
" data_list: 包含(音频数据, 情感标签)的列表\n",
" \"\"\"\n",
" data_list = []\n",
" \n",
" # 确保路径存在\n",
" if not os.path.exists(data_path):\n",
" print(f\"警告: SAVEE数据路径不存在: {data_path}\")\n",
" return data_list\n",
" \n",
" audio_path = os.path.join(data_path, \"AudioData\")\n",
" if not os.path.exists(audio_path):\n",
" print(f\"警告: SAVEE AudioData路径不存在: {audio_path}\")\n",
" return data_list\n",
" \n",
" # SAVEE数据集中的四个说话者\n",
" actors = ['DC', 'JE', 'JK', 'KL']\n",
" \n",
" # 计算每种情感的文件数\n",
" emotion_counts = {}\n",
" \n",
" for actor in actors:\n",
" actor_path = os.path.join(audio_path, actor)\n",
" if not os.path.isdir(actor_path):\n",
" print(f\"警告: SAVEE目录不存在: {actor_path}\")\n",
" continue\n",
" \n",
" audio_files = glob.glob(os.path.join(actor_path, \"*.wav\"))\n",
" \n",
" for audio_file in audio_files:\n",
" file_name = os.path.basename(audio_file)\n",
" \n",
" # 提取情感标签,SAVEE使用文件名的前1-2个字母作为情感标签\n",
" if file_name.startswith(\"sa\"):\n",
" emotion = \"sa\"\n",
" elif file_name.startswith(\"su\"):\n",
" emotion = \"su\"\n",
" else:\n",
" emotion = file_name[0]\n",
" \n",
" # 检查是否支持该情感\n",
" if emotion in EMOTION_MAPPING:\n",
" mapped_emotion = EMOTION_MAPPING[emotion]\n",
" \n",
" # 只选择我们指定的情感类别\n",
" if mapped_emotion in SELECTED_EMOTIONS:\n",
" # 检查是否达到了每种情感的限制\n",
" if limit is not None:\n",
" emotion_counts[mapped_emotion] = emotion_counts.get(mapped_emotion, 0) + 1\n",
" if emotion_counts[mapped_emotion] > limit:\n",
" continue\n",
" \n",
" try:\n",
" # 加载音频\n",
" audio, sr = librosa.load(audio_file, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 将数据和标签添加到列表\n",
" data_list.append((audio, mapped_emotion))\n",
" \n",
" except Exception as e:\n",
" print(f\"处理文件 {audio_file} 时出错: {e}\")\n",
" \n",
" print(f\"从SAVEE数据集加载了 {len(data_list)} 个样本\")\n",
" if limit is not None:\n",
" print(f\"每种情感的限制: {limit}\")\n",
" \n",
" # 打印每种情感的样本数量\n",
" emotion_distribution = {}\n",
" for _, emotion in data_list:\n",
" emotion_distribution[emotion] = emotion_distribution.get(emotion, 0) + 1\n",
" \n",
" print(\"情感分布:\")\n",
" for emotion in SELECTED_EMOTIONS:\n",
" count = emotion_distribution.get(emotion, 0)\n",
" print(f\" {emotion}: {count}\")\n",
" \n",
" return data_list\n",
"\n",
"# 加载数据\n",
"try:\n",
" print(\"正在加载音频数据...\")\n",
" \n",
" # 每个情感类别最多加载50个样本(为了平衡数据集)\n",
" samples_per_emotion = 50\n",
" \n",
" # 加载RAVDESS数据集\n",
" ravdess_data = load_ravdess_data(limit=samples_per_emotion)\n",
" \n",
" # 加载CASIA数据集\n",
" casia_data = load_casia_data(limit=samples_per_emotion)\n",
" \n",
" # 加载SAVEE数据集\n",
" savee_data = load_savee_data(limit=samples_per_emotion)\n",
" \n",
" # 合并所有数据\n",
" all_data = ravdess_data + casia_data + savee_data\n",
" \n",
" if not all_data:\n",
" raise ValueError(\"没有加载到任何有效数据。请检查数据路径是否正确。\")\n",
" \n",
" print(f\"总共加载了 {len(all_data)} 个样本\")\n",
" \n",
" # 提取音频和标签\n",
" audios, emotions = zip(*all_data)\n",
" \n",
" # 检查是否所有选定的情感类别都有样本\n",
" unique_emotions = set(emotions)\n",
" missing_emotions = [e for e in SELECTED_EMOTIONS if e not in unique_emotions]\n",
" if missing_emotions:\n",
" print(f\"警告:以下情感类别在数据中缺失: {missing_emotions}\")\n",
" print(\"将使用随机生成的音频数据补充缺失的情感类别\")\n",
" \n",
" # 为每个缺失的情感类别生成随机样本\n",
" for emotion in missing_emotions:\n",
" # 为了保持平衡,每个缺失类别添加5个样本\n",
" for i in range(5):\n",
" # 生成随机音频数据\n",
" random_audio = np.random.randn(MAX_SAMPLES)\n",
" audios = audios + (random_audio,)\n",
" emotions = emotions + (emotion,)\n",
" \n",
" # 提取特征\n",
" print(\"\\n正在提取特征...\")\n",
" features_list = []\n",
" for i, audio in enumerate(tqdm(audios, desc=\"提取特征\")):\n",
" features = extract_all_features(audio)\n",
" features_list.append(features)\n",
" \n",
" # 转换为特征矩阵\n",
" X, feature_names = features_to_matrix(features_list)\n",
" y = np.array(emotions)\n",
" \n",
" print(f\"提取了 {X.shape[1]} 个特征\")\n",
" \n",
" # 确保所有选定的情感类别都在标签编码器中\n",
" # 首先创建标签编码器并拟合所有选定的类别\n",
" encoder = LabelEncoder()\n",
" encoder.fit(SELECTED_EMOTIONS) # 确保所有选定的类别都被包含\n",
" \n",
" # 划分数据集 - 使用分层抽样确保每个类别在各集合中的比例一致\n",
" print(\"\\n划分数据集...\")\n",
" # 首先划分训练+验证集和测试集\n",
" X_train_val, X_test, y_train_val, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)\n",
" \n",
" # 然后划分训练集和验证集\n",
" X_train, X_val, y_train, y_val = train_test_split(X_train_val, y_train_val, test_size=0.25, random_state=42, stratify=y_train_val)\n",
" \n",
" print(f\"训练集: {X_train.shape[0]} 样本\")\n",
" print(f\"验证集: {X_val.shape[0]} 样本\")\n",
" print(f\"测试集: {X_test.shape[0]} 样本\")\n",
" \n",
" # 检查每个数据集中的情感分布\n",
" print(\"\\n训练集情感分布:\")\n",
" for emotion in SELECTED_EMOTIONS:\n",
" count = np.sum(y_train == emotion)\n",
" print(f\" {emotion}: {count}\")\n",
" \n",
" print(\"\\n验证集情感分布:\")\n",
" for emotion in SELECTED_EMOTIONS:\n",
" count = np.sum(y_val == emotion)\n",
" print(f\" {emotion}: {count}\")\n",
" \n",
" print(\"\\n测试集情感分布:\")\n",
" for emotion in SELECTED_EMOTIONS:\n",
" count = np.sum(y_test == emotion)\n",
" print(f\" {emotion}: {count}\")\n",
" \n",
" # 标准化特征\n",
" print(\"\\n标准化特征...\")\n",
" X_train_norm, X_val_norm, X_test_norm, scaler = normalize_features(X_train, X_val, X_test)\n",
" \n",
" # 重塑为LSTM输入格式\n",
" print(\"重塑为LSTM输入格式...\")\n",
" X_train_reshaped = reshape_for_lstm(X_train_norm)\n",
" X_val_reshaped = reshape_for_lstm(X_val_norm)\n",
" X_test_reshaped = reshape_for_lstm(X_test_norm)\n",
" \n",
" # 使用预先创建的编码器转换标签\n",
" print(\"编码标签...\")\n",
" y_train_encoded = encoder.transform(y_train)\n",
" y_val_encoded = encoder.transform(y_val)\n",
" y_test_encoded = encoder.transform(y_test)\n",
" \n",
" # 转换为独热编码\n",
" y_train_categorical = to_categorical(y_train_encoded, num_classes=len(SELECTED_EMOTIONS))\n",
" y_val_categorical = to_categorical(y_val_encoded, num_classes=len(SELECTED_EMOTIONS))\n",
" y_test_categorical = to_categorical(y_test_encoded, num_classes=len(SELECTED_EMOTIONS))\n",
" \n",
" print(f\"类别映射: {dict(zip(encoder.classes_, range(len(encoder.classes_))))}\")\n",
" \n",
" # 打印数据形状\n",
" print(f\"\\nLSTM输入形状:\")\n",
" print(f\"训练集: {X_train_reshaped.shape}\")\n",
" print(f\"验证集: {X_val_reshaped.shape}\")\n",
" print(f\"测试集: {X_test_reshaped.shape}\")\n",
" print(f\"训练标签: {y_train_categorical.shape}\")\n",
" \n",
"except Exception as e:\n",
" print(f\"加载数据时出错: {e}\")\n",
" import traceback\n",
" traceback.print_exc()\n"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"正在加载音频数据...\n",
"加载 angry 情感的数据...\n",
"加载 fear 情感的数据...\n",
"加载 happy 情感的数据...\n",
"加载 neutral 情感的数据...\n",
"加载 sad 情感的数据...\n",
"加载 surprise 情感的数据...\n",
"CASIA数据集: 共加载 300 个样本\n",
"RAVDESS数据集: 共加载 300 个样本\n",
" neutral: 50 个样本\n",
" happy: 50 个样本\n",
" sad: 50 个样本\n",
" angry: 50 个样本\n",
" fear: 50 个样本\n",
" surprise: 50 个样本\n",
"成功加载 600 个真实音频样本\n",
"从音频数据中提取特征...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"提取特征: 100%|██████████| 600/600 [00:21<00:00, 28.04it/s]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"划分数据集...\n",
"训练集: 360 个样本\n",
"验证集: 120 个样本\n",
"测试集: 120 个样本\n",
"标准化特征...\n",
"重塑为LSTM输入格式...\n",
"对标签进行编码...\n",
"情感类别: ['angry' 'fear' 'happy' 'neutral' 'sad' 'surprise']\n",
"数据准备完成,可以用于模型训练\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"# 加载数据的函数\n",
"\n",
"def load_casia_data(casia_path=\"./CAISA\", limit=None):\n",
" \"\"\"\n",
" 加载CASIA中文情感语音数据集\n",
" \n",
" Args:\n",
" casia_path: CASIA数据集路径\n",
" limit: 每种情感加载的最大样本数\n",
" \n",
" Returns:\n",
" data_list: 包含(音频数据, 情感标签)的列表\n",
" \"\"\"\n",
" data_list = []\n",
" \n",
" # 确保路径存在\n",
" if not os.path.exists(casia_path):\n",
" print(f\"警告: CASIA数据路径不存在: {casia_path}\")\n",
" return data_list\n",
" \n",
" # 定义情感标签\n",
" emotions = ['angry', 'fear', 'happy', 'neutral', 'sad', 'surprise']\n",
" \n",
" # 加载每种情感的数据\n",
" for emotion in emotions:\n",
" print(f\"加载 {emotion} 情感的数据...\")\n",
" \n",
" # 获取所有演员的目录\n",
" actors = []\n",
" for item in os.listdir(casia_path):\n",
" if os.path.isdir(os.path.join(casia_path, item)) and not item.startswith('_'):\n",
" actors.append(item)\n",
" \n",
" count = 0\n",
" for actor in actors:\n",
" # 检查该演员是否有该情感的目录\n",
" emotion_path = os.path.join(casia_path, actor, emotion)\n",
" if not os.path.exists(emotion_path):\n",
" continue\n",
" \n",
" # 获取该情感下的所有音频文件\n",
" audio_files = glob.glob(os.path.join(emotion_path, \"*.wav\"))\n",
" \n",
" # 如果有限制,只加载部分文件\n",
" if limit and count >= limit:\n",
" break\n",
" \n",
" for audio_file in audio_files:\n",
" try:\n",
" # 加载音频文件\n",
" audio, sr = librosa.load(audio_file, sr=SAMPLE_RATE)\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 添加到数据列表\n",
" data_list.append((audio, emotion))\n",
" count += 1\n",
" \n",
" # 如果达到限制,跳出循环\n",
" if limit and count >= limit:\n",
" break\n",
" except Exception as e:\n",
" print(f\"处理文件 {audio_file} 时出错: {e}\")\n",
" \n",
" print(f\"CASIA数据集: 共加载 {len(data_list)} 个样本\")\n",
" return data_list\n",
"\n",
"def load_ravdess_data(ravdess_path=\"./RAVDESS\", limit=None):\n",
" \"\"\"\n",
" 加载RAVDESS英文情感语音数据集\n",
" \n",
" Args:\n",
" ravdess_path: RAVDESS数据集路径\n",
" limit: 每种情感加载的最大样本数\n",
" \n",
" Returns:\n",
" data_list: 包含(音频数据, 情感标签)的列表\n",
" \"\"\"\n",
" data_list = []\n",
" \n",
" # 确保路径存在\n",
" if not os.path.exists(ravdess_path):\n",
" print(f\"警告: RAVDESS数据路径不存在: {ravdess_path}\")\n",
" return data_list\n",
" \n",
" # RAVDESS情感标签映射\n",
" emotion_map = {\n",
" '01': 'neutral',\n",
" '03': 'happy',\n",
" '04': 'sad',\n",
" '05': 'angry',\n",
" '06': 'fear',\n",
" '08': 'surprise'\n",
" }\n",
" \n",
" # 只管这些情感类别(与CASIA一致)\n",
" target_emotions = ['neutral', 'happy', 'sad', 'angry', 'fear', 'surprise']\n",
" \n",
" # 每种情感的计数\n",
" emotion_counts = {emotion: 0 for emotion in target_emotions}\n",
" \n",
" try:\n",
" # 获取所有目录\n",
" actor_dirs = glob.glob(os.path.join(ravdess_path, \"Actor_*\"))\n",
" \n",
" for actor_dir in actor_dirs:\n",
" # 获取该目录的所有音频文件\n",
" audio_files = glob.glob(os.path.join(actor_dir, \"*.wav\"))\n",
" \n",
" for audio_file in audio_files:\n",
" # RAVDESS文件名格式: 03-01-05-01-02-01-12.wav\n",
" # 05 表示情感类别\n",
" filename = os.path.basename(audio_file)\n",
" parts = filename.split('-')\n",
" \n",
" if len(parts) >= 3:\n",
" emotion_code = parts[2]\n",
" \n",
" if emotion_code in emotion_map:\n",
" emotion = emotion_map[emotion_code]\n",
" \n",
" if emotion in target_emotions:\n",
" # 检查是否达到了该情感的样本数限制\n",
" if limit and emotion_counts[emotion] >= limit:\n",
" continue\n",
" \n",
" try:\n",
" # 加载音频文件\n",
" audio, sr = librosa.load(audio_file, sr=SAMPLE_RATE)\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 添加到数据列表\n",
" data_list.append((audio, emotion))\n",
" emotion_counts[emotion] += 1\n",
" except Exception as e:\n",
" print(f\"处理文件 {audio_file} 时出错: {e}\")\n",
" \n",
" print(f\"RAVDESS数据集: 共加载 {len(data_list)} 个样本\")\n",
"\n",
" for emotion, count in emotion_counts.items():\n",
" print(f\" {emotion}: {count} 个样本\")\n",
" \n",
" except Exception as e:\n",
" print(f\"错误: 无法获取RAVDESS演员目录: {e}\")\n",
" \n",
" return data_list\n",
"\n",
"# 尝试加载数据\n",
"try:\n",
" print(\"正在加载音频数据...\")\n",
" \n",
" # 每种情感的样本数限制\n",
" samples_per_emotion = 50 # 可以根据需要调整\n",
" \n",
" # 加载CASIA数据集\n",
" casia_data = load_casia_data(limit=samples_per_emotion)\n",
" \n",
" # 加载RAVDESS数据集\n",
" ravdess_data = load_ravdess_data(limit=samples_per_emotion)\n",
" \n",
" # 合并数据\n",
" all_data = casia_data + ravdess_data\n",
" \n",
" if all_data:\n",
" print(f\"成功加载 {len(all_data)} 个真实音频样本\")\n",
" \n",
" # 分离特征和标签\n",
" X_real = [item[0] for item in all_data]\n",
" y_real = [item[1] for item in all_data]\n",
" \n",
" # 提取特征\n",
" print(\"从音频数据中提取特征...\")\n",
" features_list = []\n",
" for audio in tqdm(X_real, desc=\"提取特征\"):\n",
" features = extract_all_features(audio)\n",
" features_list.append(features)\n",
" \n",
" # 转换为特征矩阵\n",
" X, feature_names = features_to_matrix(features_list)\n",
" \n",
" # 划分数据集\n",
" print(\"划分数据集...\")\n",
" X_train_val, X_test, y_train_val, y_test = train_test_split(X, y_real, test_size=0.2, random_state=42, stratify=y_real)\n",
" X_train, X_val, y_train, y_val = train_test_split(X_train_val, y_train_val, test_size=0.25, random_state=42, stratify=y_train_val)\n",
" \n",
" print(f\"训练集: {len(X_train)} 个样本\")\n",
" print(f\"验证集: {len(X_val)} 个样本\")\n",
" print(f\"测试集: {len(X_test)} 个样本\")\n",
" \n",
" # 标准化特征\n",
" print(\"标准化特征...\")\n",
" X_train_norm, X_val_norm, X_test_norm, scaler = normalize_features(X_train, X_val, X_test)\n",
" \n",
" # 重塑为LSTM输入格式\n",
" print(\"重塑为LSTM输入格式...\")\n",
" X_train_reshaped = reshape_for_lstm(X_train_norm)\n",
" X_val_reshaped = reshape_for_lstm(X_val_norm)\n",
" X_test_reshaped = reshape_for_lstm(X_test_norm)\n",
" \n",
" # 对情感标签进行编码\n",
" print(\"对标签进行编码...\")\n",
" encoder = LabelEncoder()\n",
" encoder.fit(y_train + y_val + y_test)\n",
" \n",
" print(f\"情感类别: {encoder.classes_}\")\n",
" \n",
" y_train_encoded = encoder.transform(y_train)\n",
" y_val_encoded = encoder.transform(y_val)\n",
" y_test_encoded = encoder.transform(y_test)\n",
" \n",
" # 转换为独热编码\n",
" y_train_categorical = to_categorical(y_train_encoded)\n",
" y_val_categorical = to_categorical(y_val_encoded)\n",
" y_test_categorical = to_categorical(y_test_encoded)\n",
" \n",
" print(\"数据准备完成,可以用于模型训练\")\n",
" else:\n",
" print(\"没有加载到任何音频数据,将使用演示数据\")\n",
" # 使用前面创建的演示数据\n",
" # 这里不需要任何操作,因为之前已经创建了演示数据\n",
"\n",
"except Exception as e:\n",
" print(f\"加载数据时出错: {e}\")\n",
"\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 2.6 特征数据处理工具函数\n",
"\n",
"这一节我们实现用于特征处理的工具函数:\n",
"1. 综合特征提取函数\n",
"2. 特征矩阵转换\n",
"3. 特征标准化\n",
"4. LSTM数据格式转换\n"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"真实数据集统计信息:\n",
"特征数量: 21\n",
"前5个特征: ['pitch_mean', 'pitch_std', 'pitch_max', 'pitch_min', 'tuning_offset']\n",
"\n",
"训练集类别分布:\n",
" angry: 60\n",
" fear: 60\n",
" happy: 60\n",
" neutral: 60\n",
" sad: 60\n",
" surprise: 60\n",
"\n",
"第一个样本的特征统计:\n",
" 均值: 0.2349\n",
" 标准差: 0.8315\n",
" 最小值: -0.8931\n",
" 最大值: 1.6344\n"
]
}
],
"source": [
"def extract_all_features(audio, sr=SAMPLE_RATE):\n",
" \"\"\"\n",
" 综合特征提取函数,提取所有音频特征\n",
" \n",
" Args:\n",
" audio: 音频信号\n",
" sr: 采样率\n",
" \n",
" Returns:\n",
" features: 特征字典\n",
" \"\"\"\n",
" features = {}\n",
" \n",
" # 1. 提取音高特征\n",
" pitch_features = extract_pitch_features(audio, sr)\n",
" features.update(pitch_features)\n",
" \n",
" # 2. 提取调谐偏差特征\n",
" tuning_features = extract_tuning_features(audio, sr)\n",
" features.update(tuning_features)\n",
" \n",
" # 3. 提取频谱质心特征\n",
" centroid_features = extract_spectral_centroid_features(audio, sr)\n",
" features.update(centroid_features)\n",
" \n",
" # 4. 提取频谱平坦度特征\n",
" flatness_features = extract_spectral_flatness_features(audio, sr)\n",
" features.update(flatness_features)\n",
" \n",
" # 5. 提取MFCC特征\n",
" mfcc_features = extract_mfcc_features(audio, sr)\n",
" features.update(mfcc_features)\n",
" \n",
" # 6. 提取光谱对比度特征\n",
" contrast_features = extract_spectral_contrast_features(audio, sr)\n",
" features.update(contrast_features)\n",
" \n",
" # 7. 提取RMS和ZCR特征\n",
" rms_features = extract_rms_features(audio, sr)\n",
" features.update(rms_features)\n",
" \n",
" # 8. 提取色谱图特征\n",
" chroma_features = extract_chroma_features(audio, sr)\n",
" features.update(chroma_features)\n",
" \n",
" # 9. 添加统计矩\n",
" features['audio_mean'] = np.mean(audio)\n",
" features['audio_std'] = np.std(audio)\n",
" features['audio_skew'] = np.mean((audio - np.mean(audio))**3) / (np.std(audio)**3) if np.std(audio) > 0 else 0\n",
" features['audio_kurtosis'] = np.mean((audio - np.mean(audio))**4) / (np.std(audio)**4) - 3 if np.std(audio) > 0 else 0\n",
" \n",
" return features\n",
"\n",
"def features_to_matrix(features_list, feature_names=None):\n",
" \"\"\"\n",
" 将特征字典列表转换为特征矩阵\n",
" \n",
" Args:\n",
" features_list: 特征字典列表\n",
" feature_names: 特征名称列表,如果为None则从第一个非空字典中获取\n",
" \n",
" Returns:\n",
" X: 特征矩阵\n",
" feature_names: 特征名称列表\n",
" \"\"\"\n",
" # 如果没有提供特征名称,从第一个非空字典中获取\n",
" if feature_names is None:\n",
" for features in features_list:\n",
" if features: # 非空字典\n",
" feature_names = list(features.keys())\n",
" break\n",
" \n",
" if feature_names is None:\n",
" raise ValueError(\"所有特征字典都是空的,无法确定特征名称\")\n",
" \n",
" # 创建特征矩阵\n",
" X = np.zeros((len(features_list), len(feature_names)))\n",
" \n",
" for i, features in enumerate(features_list):\n",
" if not features: # 空字典\n",
" # 填充为0,或者可以使用平均值等\n",
" continue\n",
" \n",
" for j, name in enumerate(feature_names):\n",
" if name in features:\n",
" X[i, j] = features[name]\n",
" \n",
" return X, feature_names\n",
"\n",
"def normalize_features(X_train, X_val=None, X_test=None):\n",
" \"\"\"\n",
" 标准化特征\n",
" \n",
" Args:\n",
" X_train: 训练集特征矩阵\n",
" X_val: 验证集特征矩阵\n",
" X_test: 测试集特征矩阵\n",
" \n",
" Returns:\n",
" X_train_norm: 标准化后的训练集\n",
" X_val_norm: 标准化后的验证集 (如果提供)\n",
" X_test_norm: 标准化后的测试集 (如果提供)\n",
" scaler: 标准化器对象\n",
" \"\"\"\n",
" # 初始化标准化器\n",
" scaler = StandardScaler()\n",
" \n",
" # 使用训练集拟合标准化器\n",
" X_train_norm = scaler.fit_transform(X_train)\n",
" \n",
" # 标准化验证集和测试集 (如果提供)\n",
" results = [X_train_norm]\n",
" \n",
" if X_val is not None:\n",
" X_val_norm = scaler.transform(X_val)\n",
" results.append(X_val_norm)\n",
" \n",
" if X_test is not None:\n",
" X_test_norm = scaler.transform(X_test)\n",
" results.append(X_test_norm)\n",
" \n",
" # 添加标准化器到结果\n",
" results.append(scaler)\n",
" \n",
" return tuple(results)\n",
"\n",
"def reshape_for_lstm(X):\n",
" \"\"\"\n",
" 将二维特征矩阵重塑为LSTM所需的三维格式\n",
" \n",
" Args:\n",
" X: 二维特征矩阵,形状为 (n_samples, n_features)\n",
" \n",
" Returns:\n",
" X_reshaped: 重塑后的三维特征张量,形状为 (n_samples, 1, n_features)\n",
" \"\"\"\n",
" # LSTM输入形状为: (n_samples, time_steps, n_features)\n",
" # 我们使用time_steps=1,因为我们处理的是静态特征\n",
" return X.reshape(X.shape[0], 1, X.shape[1])\n",
"\n",
"# 工具函数代码(这些函数已经在前面定义并用于数据处理)\n",
"\n",
"# 打印已加载数据的一些统计信息\n",
"try:\n",
" if 'X_train_reshaped' in locals() and 'y_train_categorical' in locals():\n",
" print(\"\\n真实数据集统计信息:\")\n",
" print(f\"特征数量: {X_train_reshaped.shape[2]}\")\n",
" \n",
" # 打印前5个特征名称\n",
" if 'feature_names' in locals() and feature_names:\n",
" print(f\"前5个特征: {feature_names[:5]}\")\n",
" \n",
" # 打印类别分布\n",
" if 'y_train' in locals() and 'encoder' in locals():\n",
" print(\"\\n训练集类别分布:\")\n",
" for emotion, count in zip(*np.unique(y_train, return_counts=True)):\n",
" print(f\" {emotion}: {count}\")\n",
" \n",
" # 打印一个样本的特征统计信息\n",
" if len(X_train_reshaped) > 0:\n",
" print(\"\\n第一个样本的特征统计:\")\n",
" print(f\" 均值: {np.mean(X_train_reshaped[0]):.4f}\")\n",
" print(f\" 标准差: {np.std(X_train_reshaped[0]):.4f}\")\n",
" print(f\" 最小值: {np.min(X_train_reshaped[0]):.4f}\")\n",
" print(f\" 最大值: {np.max(X_train_reshaped[0]):.4f}\")\n",
" else:\n",
" print(\"数据尚未加载,无法显示统计信息\")\n",
"except Exception as e:\n",
" print(f\"显示统计信息时出错: {e}\")\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"# 3. 分类预测模型构建与分析\n",
"\n",
"在这一部分,我们将构建和训练LSTM神经网络模型来进行情感分类,并评估模型性能。\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 3.1 构建LSTM神经网络模型\n",
"\n",
"LSTM (Long Short-Term Memory) 是一种特殊的循环神经网络 (RNN),能够有效地处理序列数据,特别适合用于音频情感分析。在这一节中,我们将构建一个双向LSTM模型。\n"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"输入形状: (1, 21)\n",
"情感类别数: 6\n",
"训练标签形状: (360, 6)\n",
"验证标签形状: (120, 6)\n",
"测试标签形状: (120, 6)\n"
]
},
{
"data": {
"text/html": [
"Model: \"sequential_1\"\n",
"\n"
],
"text/plain": [
"\u001b[1mModel: \"sequential_1\"\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
"┃ Layer (type) ┃ Output Shape ┃ Param # ┃\n",
"┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
"│ bidirectional_2 (Bidirectional) │ (None, 1, 256) │ 153,600 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_4 │ (None, 1, 256) │ 1,024 │\n",
"│ (BatchNormalization) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_4 (Dropout) │ (None, 1, 256) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ bidirectional_3 (Bidirectional) │ (None, 256) │ 394,240 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_5 │ (None, 256) │ 1,024 │\n",
"│ (BatchNormalization) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_5 (Dropout) │ (None, 256) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_3 (Dense) │ (None, 128) │ 32,896 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_6 │ (None, 128) │ 512 │\n",
"│ (BatchNormalization) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_6 (Dropout) │ (None, 128) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_4 (Dense) │ (None, 64) │ 8,256 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_7 │ (None, 64) │ 256 │\n",
"│ (BatchNormalization) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_7 (Dropout) │ (None, 64) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_5 (Dense) │ (None, 6) │ 390 │\n",
"└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
"\n"
],
"text/plain": [
"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
"┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n",
"┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
"│ bidirectional_2 (\u001b[38;5;33mBidirectional\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m153,600\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_4 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m1,024\u001b[0m │\n",
"│ (\u001b[38;5;33mBatchNormalization\u001b[0m) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_4 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ bidirectional_3 (\u001b[38;5;33mBidirectional\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m394,240\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_5 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m1,024\u001b[0m │\n",
"│ (\u001b[38;5;33mBatchNormalization\u001b[0m) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_5 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_3 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m32,896\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_6 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m512\u001b[0m │\n",
"│ (\u001b[38;5;33mBatchNormalization\u001b[0m) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_6 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_4 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m8,256\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_7 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m256\u001b[0m │\n",
"│ (\u001b[38;5;33mBatchNormalization\u001b[0m) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_7 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_5 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m6\u001b[0m) │ \u001b[38;5;34m390\u001b[0m │\n",
"└─────────────────────────────────┴────────────────────────┴───────────────┘\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
" Total params: 592,198 (2.26 MB)\n",
"\n"
],
"text/plain": [
"\u001b[1m Total params: \u001b[0m\u001b[38;5;34m592,198\u001b[0m (2.26 MB)\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
" Trainable params: 590,790 (2.25 MB)\n",
"\n"
],
"text/plain": [
"\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m590,790\u001b[0m (2.25 MB)\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
" Non-trainable params: 1,408 (5.50 KB)\n",
"\n"
],
"text/plain": [
"\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m1,408\u001b[0m (5.50 KB)\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"训练参数:\n",
"LSTM单元数: 128\n",
"Dropout率: 0.3\n",
"正则化系数: 0.001\n",
"学习率: 0.001\n"
]
}
],
"source": [
"class EmotionModel:\n",
" \"\"\"\n",
" 语音情感识别模型类\n",
" \"\"\"\n",
" \n",
" def __init__(self, input_shape, num_emotions):\n",
" \"\"\"\n",
" 初始化模型\n",
" \n",
" Args:\n",
" input_shape: 输入特征的形状,例如 (1, 193) 表示每个样本有1个时间步和193个特征\n",
" num_emotions: 情感类别数量\n",
" \"\"\"\n",
" self.input_shape = input_shape\n",
" self.num_emotions = num_emotions\n",
" self.model = None\n",
" \n",
" def build_model(self, lstm_units=128, dropout_rate=0.3, regularization_rate=0.001):\n",
" \"\"\"\n",
" 构建LSTM模型\n",
" \n",
" Args:\n",
" lstm_units: LSTM层的单元数\n",
" dropout_rate: Dropout层的丢弃率\n",
" regularization_rate: L2正则化系数\n",
" \n",
" Returns:\n",
" 构建好的模型\n",
" \"\"\"\n",
" from tensorflow.keras.models import Sequential\n",
" from tensorflow.keras.layers import LSTM, Dense, Dropout, BatchNormalization, Bidirectional\n",
" from tensorflow.keras.regularizers import l2\n",
" \n",
" # 定义正则化器\n",
" regularizer = l2(regularization_rate)\n",
" \n",
" # 构建模型\n",
" self.model = Sequential([\n",
" # 第一个双向LSTM层,返回序列\n",
" Bidirectional(LSTM(lstm_units, return_sequences=True, \n",
" kernel_regularizer=regularizer,\n",
" recurrent_regularizer=regularizer), \n",
" input_shape=self.input_shape),\n",
" BatchNormalization(),\n",
" Dropout(dropout_rate),\n",
" \n",
" # 第二个双向LSTM层,不返回序列\n",
" Bidirectional(LSTM(lstm_units, return_sequences=False, \n",
" kernel_regularizer=regularizer,\n",
" recurrent_regularizer=regularizer)),\n",
" BatchNormalization(),\n",
" Dropout(dropout_rate),\n",
" \n",
" # 全连接层\n",
" Dense(128, activation='relu', kernel_regularizer=regularizer),\n",
" BatchNormalization(),\n",
" Dropout(dropout_rate),\n",
" \n",
" Dense(64, activation='relu', kernel_regularizer=regularizer),\n",
" BatchNormalization(),\n",
" Dropout(dropout_rate),\n",
" \n",
" # 输出层\n",
" Dense(self.num_emotions, activation='softmax')\n",
" ])\n",
" \n",
" return self.model\n",
" \n",
" def compile_model(self, learning_rate=0.001):\n",
" \"\"\"\n",
" 编译模型\n",
" \n",
" Args:\n",
" learning_rate: 学习率\n",
" \"\"\"\n",
" from tensorflow.keras.optimizers import Adam\n",
" \n",
" optimizer = Adam(learning_rate=learning_rate)\n",
" self.model.compile(\n",
" optimizer=optimizer,\n",
" loss='categorical_crossentropy',\n",
" metrics=['accuracy']\n",
" )\n",
" \n",
" def get_callbacks(self, checkpoint_path=None):\n",
" \"\"\"\n",
" 获取回调函数列表\n",
" \n",
" Args:\n",
" checkpoint_path: 模型检查点保存路径\n",
" \n",
" Returns:\n",
" callbacks: 回调函数列表\n",
" \"\"\"\n",
" from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\n",
" \n",
" callbacks = []\n",
" \n",
" # 提前停止\n",
" early_stopping = EarlyStopping(\n",
" monitor='val_loss',\n",
" patience=10,\n",
" restore_best_weights=True\n",
" )\n",
" callbacks.append(early_stopping)\n",
" \n",
" # 学习率衰减\n",
" reduce_lr = ReduceLROnPlateau(\n",
" monitor='val_loss',\n",
" factor=0.2,\n",
" patience=5,\n",
" min_lr=1e-6\n",
" )\n",
" callbacks.append(reduce_lr)\n",
" \n",
" # 模型检查点\n",
" if checkpoint_path:\n",
" checkpoint = ModelCheckpoint(\n",
" filepath=checkpoint_path,\n",
" monitor='val_loss',\n",
" save_best_only=True,\n",
" save_weights_only=False,\n",
" mode='min',\n",
" verbose=1\n",
" )\n",
" callbacks.append(checkpoint)\n",
" \n",
" return callbacks\n",
" \n",
" def train(self, X_train, y_train, X_val, y_val, epochs=100, batch_size=32, checkpoint_path=None):\n",
" \"\"\"\n",
" 训练模型\n",
" \n",
" Args:\n",
" X_train: 训练集特征\n",
" y_train: 训练集标签\n",
" X_val: 验证集特征\n",
" y_val: 验证集标签\n",
" epochs: 训练轮数\n",
" batch_size: 批量大小\n",
" checkpoint_path: 模型检查点保存路径\n",
" \n",
" Returns:\n",
" 训练历史\n",
" \"\"\"\n",
" callbacks = self.get_callbacks(checkpoint_path)\n",
" \n",
" history = self.model.fit(\n",
" X_train, y_train,\n",
" validation_data=(X_val, y_val),\n",
" epochs=epochs,\n",
" batch_size=batch_size,\n",
" callbacks=callbacks,\n",
" verbose=1\n",
" )\n",
" \n",
" return history\n",
" \n",
" def evaluate(self, X_test, y_test):\n",
" \"\"\"\n",
" 评估模型\n",
" \n",
" Args:\n",
" X_test: 测试集特征\n",
" y_test: 测试集标签\n",
" \n",
" Returns:\n",
" 评估结果(损失和准确率)\n",
" \"\"\"\n",
" return self.model.evaluate(X_test, y_test)\n",
" \n",
" def predict(self, X):\n",
" \"\"\"\n",
" 预测情感\n",
" \n",
" Args:\n",
" X: 特征\n",
" \n",
" Returns:\n",
" 预测结果\n",
" \"\"\"\n",
" return self.model.predict(X)\n",
" \n",
" def save(self, filepath):\n",
" \"\"\"\n",
" 保存模型\n",
" \n",
" Args:\n",
" filepath: 保存路径\n",
" \"\"\"\n",
" self.model.save(filepath)\n",
" \n",
" @classmethod\n",
" def load(cls, filepath):\n",
" \"\"\"\n",
" 加载模型\n",
" \n",
" Args:\n",
" filepath: 模型文件路径\n",
" \n",
" Returns:\n",
" 加载的模型\n",
" \"\"\"\n",
" from tensorflow.keras.models import load_model\n",
" \n",
" model_instance = cls(input_shape=None, num_emotions=None)\n",
" model_instance.model = load_model(filepath)\n",
" \n",
" return model_instance\n",
"\n",
"# 使用数据构建和编译模型\n",
"try:\n",
" if 'X_train_reshaped' in locals() and 'y_train_categorical' in locals():\n",
" # 获取输入形状和类别数\n",
" time_steps = X_train_reshaped.shape[1] # 时间步数\n",
" features = X_train_reshaped.shape[2] # 特征数\n",
" num_emotions = len(SELECTED_EMOTIONS) # 情感类别数\n",
" \n",
" print(f\"输入形状: ({time_steps}, {features})\")\n",
" print(f\"情感类别数: {num_emotions}\")\n",
" print(f\"训练标签形状: {y_train_categorical.shape}\")\n",
" print(f\"验证标签形状: {y_val_categorical.shape}\")\n",
" print(f\"测试标签形状: {y_test_categorical.shape}\")\n",
" \n",
" # 检查所有标签集的类别数是否一致\n",
" if y_train_categorical.shape[1] != y_val_categorical.shape[1] or y_train_categorical.shape[1] != y_test_categorical.shape[1]:\n",
" print(\"警告: 不同数据集的类别数不一致!\")\n",
" \n",
" # 设置训练参数\n",
" lstm_units = 128\n",
" dropout_rate = 0.3\n",
" regularization_rate = 0.001\n",
" learning_rate = 0.001\n",
" \n",
" # 创建模型,确保使用正确的类别数\n",
" emotion_model = EmotionModel(\n",
" input_shape=(time_steps, features),\n",
" num_emotions=num_emotions\n",
" )\n",
" \n",
" # 构建模型\n",
" model = emotion_model.build_model(\n",
" lstm_units=lstm_units,\n",
" dropout_rate=dropout_rate,\n",
" regularization_rate=regularization_rate\n",
" )\n",
" \n",
" # 编译模型\n",
" emotion_model.compile_model(learning_rate=learning_rate)\n",
" \n",
" # 显示模型摘要\n",
" model.summary()\n",
" \n",
" # 打印训练参数\n",
" print(\"\\n训练参数:\")\n",
" print(f\"LSTM单元数: {lstm_units}\")\n",
" print(f\"Dropout率: {dropout_rate}\")\n",
" print(f\"正则化系数: {regularization_rate}\")\n",
" print(f\"学习率: {learning_rate}\")\n",
" else:\n",
" print(\"数据尚未加载,无法构建模型\")\n",
"except Exception as e:\n",
" print(f\"构建模型时出错: {e}\")\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 3.2 模型训练与评估代码\n",
"\n",
"在这一节中,我们将使用数据集训练模型,并评估模型性能。\n"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [],
"source": [
"# 修复分类报告中的类别不匹配问题\n",
"def evaluate_model(y_true, y_pred, class_names):\n",
" \"\"\"\n",
" 评估模型性能\n",
" \n",
" Args:\n",
" y_true: 标签(独热编码)\n",
" y_pred: 预测标签(概率值)\n",
" class_names: 类别名称\n",
" \n",
" Returns:\n",
" 评估结果字典\n",
" \"\"\"\n",
" # 将独热编码转换为类别索引\n",
" y_true_classes = np.argmax(y_true, axis=1)\n",
" y_pred_classes = np.argmax(y_pred, axis=1)\n",
" \n",
" # 获取实际出现在数据中的类别索引\n",
" present_class_indices = np.unique(np.concatenate([y_true_classes, y_pred_classes]))\n",
" print(f\"测试集中实际出现的类别索引: {present_class_indices}\")\n",
" \n",
" # 获取实际出现的类别名称\n",
" present_class_names = [class_names[i] for i in present_class_indices]\n",
" print(f\"测试集中实际出现的类别: {present_class_names}\")\n",
" \n",
" # 检查是否有缺失的类别\n",
" all_class_indices = set(range(len(class_names)))\n",
" missing_indices = all_class_indices - set(present_class_indices)\n",
" if missing_indices:\n",
" missing_classes = [class_names[i] for i in missing_indices]\n",
" print(f\"警告: 测试集中缺少以下类别: {missing_classes}\")\n",
" print(\"这可能是由于数据集划分不均衡或数据集太小所致\")\n",
" \n",
" # 计算混淆矩阵 - 仅使用实际出现的类别\n",
" cm = confusion_matrix(y_true_classes, y_pred_classes, \n",
" labels=present_class_indices)\n",
" \n",
" # 计算准确率\n",
" accuracy = np.sum(y_true_classes == y_pred_classes) / len(y_true_classes)\n",
" \n",
" # 获取分类报告 - 仅使用实际出现的类别\n",
" report = classification_report(y_true_classes, y_pred_classes, \n",
" labels=present_class_indices,\n",
" target_names=present_class_names,\n",
" output_dict=True)\n",
" \n",
" # 返回结果,包括实际使用的类别信息\n",
" return {\n",
" 'confusion_matrix': cm,\n",
" 'accuracy': accuracy,\n",
" 'report': report,\n",
" 'present_class_indices': present_class_indices,\n",
" 'present_class_names': present_class_names\n",
" }\n",
"\n",
"# 修复绘制混淆矩阵函数,以适应可能存在的类别缺失\n",
"def plot_confusion_matrix(y_true, y_pred, class_names, save_path=None, normalize=False, present_class_indices=None, present_class_names=None):\n",
" \"\"\"\n",
" 绘制混淆矩阵\n",
" \n",
" Args:\n",
" y_true: 标签\n",
" y_pred: 预测标签\n",
" class_names: 类别名称\n",
" save_path: 保存路径\n",
" normalize: 是否归一化\n",
" present_class_indices: 实际存在的类别索引\n",
" present_class_names: 实际存在的类别名称\n",
" \"\"\"\n",
" # 如果提供了实际存在的类别信息,则使用它们\n",
" labels_to_use = present_class_indices if present_class_indices is not None else None\n",
" display_names = present_class_names if present_class_names is not None else class_names\n",
" \n",
" # 计算混淆矩阵\n",
" cm = confusion_matrix(y_true, y_pred, labels=labels_to_use)\n",
" \n",
" # 归一化混淆矩阵\n",
" if normalize:\n",
" cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n",
" fmt = '.2f'\n",
" else:\n",
" fmt = 'd'\n",
" \n",
" plt.figure(figsize=(10, 8))\n",
" sns.heatmap(cm, annot=True, fmt=fmt, cmap='Blues', \n",
" xticklabels=display_names, \n",
" yticklabels=display_names)\n",
" plt.xlabel('预测标签')\n",
" plt.ylabel('标签')\n",
" plt.title('混淆矩阵')\n",
" plt.tight_layout()\n",
" \n",
" if save_path:\n",
" plt.savefig(save_path)\n",
" \n",
" plt.show()\n",
"\n",
"# 修改打印评估结果函数,以显示缺失类别信息\n",
"def print_evaluation_results(results, emotion_classes):\n",
" \"\"\"\n",
" 打印评估结果\n",
" \n",
" Args:\n",
" results: 评估结果字典\n",
" emotion_classes: 所有情感类别\n",
" \"\"\"\n",
" print(f\"准确率: {results['accuracy']:.4f}\")\n",
" \n",
" # 打印缺失的类别信息\n",
" all_class_indices = set(range(len(emotion_classes)))\n",
" missing_indices = all_class_indices - set(results.get('present_class_indices', all_class_indices))\n",
" if missing_indices:\n",
" missing_classes = [emotion_classes[i] for i in missing_indices]\n",
" print(f\"\\n警告: 测试集中缺少以下类别: {missing_classes}\")\n",
" print(\"这可能是由于数据集划分不均衡或数据集太小所致\")\n",
" \n",
" print(\"\\n分类报告:\")\n",
" report = results['report']\n",
" \n",
" # 打印每个类别的指标\n",
" for class_name in sorted(report.keys()):\n",
" if class_name not in ['accuracy', 'macro avg', 'weighted avg']:\n",
" metrics = report[class_name]\n",
" print(f\"{class_name:>10}: 精确率={metrics['precision']:.4f}, 召回率={metrics['recall']:.4f}, F1分数={metrics['f1-score']:.4f}\")\n",
" \n",
" # 打印平均指标\n",
" print(\"\\n平均指标:\")\n",
" print(f\"宏平均: 精确率={report['macro avg']['precision']:.4f}, 召回率={report['macro avg']['recall']:.4f}, F1分数={report['macro avg']['f1-score']:.4f}\")\n",
" print(f\"加权平均: 精确率={report['weighted avg']['precision']:.4f}, 召回率={report['weighted avg']['recall']:.4f}, F1分数={report['weighted avg']['f1-score']:.4f}\")\n"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"在测试集上预测:\n",
"\u001b[1m4/4\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 147ms/step\n",
"测试集中实际出现的类别索引: [0 1 2 3 4 5]\n",
"测试集中实际出现的类别: [np.str_('angry'), np.str_('fear'), np.str_('happy'), np.str_('neutral'), np.str_('sad'), np.str_('surprise')]\n",
"准确率: 0.1833\n",
"\n",
"分类报告:\n",
" angry: 精确率=0.0000, 召回率=0.0000, F1分数=0.0000\n",
" fear: 精确率=0.1887, 召回率=1.0000, F1分数=0.3175\n",
" happy: 精确率=0.1111, 召回率=0.0500, F1分数=0.0690\n",
" neutral: 精确率=0.2500, 召回率=0.0500, F1分数=0.0833\n",
" sad: 精确率=0.0000, 召回率=0.0000, F1分数=0.0000\n",
" surprise: 精确率=0.0000, 召回率=0.0000, F1分数=0.0000\n",
"\n",
"平均指标:\n",
"宏平均: 精确率=0.0916, 召回率=0.1833, F1分数=0.0783\n",
"加权平均: 精确率=0.0916, 召回率=0.1833, F1分数=0.0783\n",
"评估模型时出错: name 'sns' is not defined\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Traceback (most recent call last):\n",
" File \"C:\\Users\\lenovo\\AppData\\Local\\Temp\\ipykernel_11496\\64319893.py\", line 22, in \n",
" plot_confusion_matrix(\n",
" File \"C:\\Users\\lenovo\\AppData\\Local\\Temp\\ipykernel_11496\\4080349739.py\", line 85, in plot_confusion_matrix\n",
" sns.heatmap(cm, annot=True, fmt=fmt, cmap='Blues',\n",
" ^^^\n",
"NameError: name 'sns' is not defined\n"
]
},
{
"data": {
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 重新进行评估和绘制,使用修复后的函数\n",
"try:\n",
" # 在测试集上预测\n",
" print(\"在测试集上预测:\")\n",
" y_pred = emotion_model.model.predict(X_test_reshaped)\n",
" \n",
" # 获取类别标签\n",
" y_true_classes = np.argmax(y_test_categorical, axis=1)\n",
" y_pred_classes = np.argmax(y_pred, axis=1)\n",
" \n",
" # 保存标签和预测标签,用于后续分析\n",
" np.save('./output/emotion_model/y_true.npy', y_true_classes)\n",
" np.save('./output/emotion_model/y_pred.npy', y_pred_classes)\n",
" \n",
" # 评估模型\n",
" results = evaluate_model(y_test_categorical, y_pred, emotion_classes)\n",
" \n",
" # 打印评估结果\n",
" print_evaluation_results(results, emotion_classes)\n",
" \n",
" # 绘制混淆矩阵\n",
" plot_confusion_matrix(\n",
" y_true_classes, \n",
" y_pred_classes, \n",
" emotion_classes, \n",
" save_path='./output/emotion_model/confusion_matrix.png',\n",
" present_class_indices=results.get('present_class_indices'),\n",
" present_class_names=results.get('present_class_names')\n",
" )\n",
" \n",
"except Exception as e:\n",
" print(f\"评估模型时出错: {e}\")\n",
" import traceback\n",
" traceback.print_exc()\n"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"使用RAVDESS音频文件进行测试: ./RAVDESS/Actor_01/03-01-01-01-01-01-01.wav\n",
"\n",
"音高帧级数据 (前10行):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" frame | \n",
" time | \n",
" pitch | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" 0.00000 | \n",
" 2458.481445 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" 0.02322 | \n",
" 182.268219 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2 | \n",
" 0.04644 | \n",
" 190.799026 | \n",
"
\n",
" \n",
" | 3 | \n",
" 3 | \n",
" 0.06966 | \n",
" 197.138947 | \n",
"
\n",
" \n",
" | 4 | \n",
" 4 | \n",
" 0.09288 | \n",
" 423.822876 | \n",
"
\n",
" \n",
" | 5 | \n",
" 5 | \n",
" 0.11610 | \n",
" 166.867813 | \n",
"
\n",
" \n",
" | 6 | \n",
" 6 | \n",
" 0.13932 | \n",
" 172.440811 | \n",
"
\n",
" \n",
" | 7 | \n",
" 7 | \n",
" 0.16254 | \n",
" 168.360764 | \n",
"
\n",
" \n",
" | 8 | \n",
" 8 | \n",
" 0.18576 | \n",
" 148.656494 | \n",
"
\n",
" \n",
" | 9 | \n",
" 9 | \n",
" 0.20898 | \n",
" 151.040848 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" frame time pitch\n",
"0 0 0.00000 2458.481445\n",
"1 1 0.02322 182.268219\n",
"2 2 0.04644 190.799026\n",
"3 3 0.06966 197.138947\n",
"4 4 0.09288 423.822876\n",
"5 5 0.11610 166.867813\n",
"6 6 0.13932 172.440811\n",
"7 7 0.16254 168.360764\n",
"8 8 0.18576 148.656494\n",
"9 9 0.20898 151.040848"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"音高和调谐统计特征:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" pitch_mean | \n",
" pitch_std | \n",
" pitch_max | \n",
" pitch_min | \n",
" pitch_range | \n",
" pitch_median | \n",
" tuning_offset | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 573.830444 | \n",
" 853.130066 | \n",
" 3988.073975 | \n",
" 147.432693 | \n",
" 3840.641357 | \n",
" 234.112061 | \n",
" -0.17 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" pitch_mean pitch_std pitch_max pitch_min pitch_range pitch_median \\\n",
"0 573.830444 853.130066 3988.073975 147.432693 3840.641357 234.112061 \n",
"\n",
" tuning_offset \n",
"0 -0.17 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"音高四分位数统计:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" pitch_q1 | \n",
" pitch_median | \n",
" pitch_q3 | \n",
" pitch_iqr | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 173.241608 | \n",
" 234.112061 | \n",
" 488.627747 | \n",
" 315.386139 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" pitch_q1 pitch_median pitch_q3 pitch_iqr\n",
"0 173.241608 234.112061 488.627747 315.386139"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 测试音高和调谐偏差特征提取,以DataFrame形式展示\n",
"try:\n",
" # 加载一个示例音频文件\n",
" ravdess_file = './RAVDESS/Actor_01/03-01-01-01-01-01-01.wav'\n",
" if os.path.exists(ravdess_file):\n",
" print(f\"使用RAVDESS音频文件进行测试: {ravdess_file}\")\n",
" audio, sr = librosa.load(ravdess_file, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 创建一个存储音高和调谐特征的DataFrame\n",
" pitch_df = pd.DataFrame()\n",
" \n",
" # 提取音高特征\n",
" pitches, magnitudes = librosa.piptrack(y=audio, sr=sr)\n",
" \n",
" # 提取每帧最大幅度对应的音高\n",
" pitch_values = []\n",
" times_list = []\n",
" frame_indices = []\n",
" \n",
" for t in range(pitches.shape[1]):\n",
" idx = np.argmax(magnitudes[:, t])\n",
" pitch = pitches[idx, t]\n",
" time = t * 512 / sr # 计算时间点\n",
" \n",
" if pitch > 0: # 过滤掉静音帧\n",
" pitch_values.append(pitch)\n",
" times_list.append(time)\n",
" frame_indices.append(t)\n",
" \n",
" # 创建音高帧级DataFrame\n",
" pitch_frames_df = pd.DataFrame({\n",
" 'frame': frame_indices,\n",
" 'time': times_list,\n",
" 'pitch': pitch_values\n",
" })\n",
" \n",
" # 计算音高统计特征\n",
" pitch_stats = {\n",
" 'pitch_mean': np.mean(pitch_values) if pitch_values else 0,\n",
" 'pitch_std': np.std(pitch_values) if len(pitch_values) > 1 else 0,\n",
" 'pitch_max': np.max(pitch_values) if pitch_values else 0,\n",
" 'pitch_min': np.min(pitch_values) if pitch_values else 0,\n",
" 'pitch_range': np.ptp(pitch_values) if pitch_values else 0, # 峰峰值\n",
" 'pitch_median': np.median(pitch_values) if pitch_values else 0\n",
" }\n",
" \n",
" # 提取调谐偏差\n",
" tuning_offset = librosa.estimate_tuning(y=audio, sr=sr)\n",
" pitch_stats['tuning_offset'] = tuning_offset\n",
" \n",
" # 创建统计特征DataFrame\n",
" pitch_stats_df = pd.DataFrame([pitch_stats])\n",
" \n",
" # 展示结果\n",
" print(\"\\n音高帧级数据 (前10行):\")\n",
" display(pitch_frames_df.head(10))\n",
" \n",
" print(\"\\n音高和调谐统计特征:\")\n",
" display(pitch_stats_df)\n",
" \n",
" # 计算音高四分位数\n",
" q1 = np.percentile(pitch_values, 25) if pitch_values else 0\n",
" q3 = np.percentile(pitch_values, 75) if pitch_values else 0\n",
" iqr = q3 - q1\n",
" \n",
" quartile_stats = {\n",
" 'pitch_q1': q1,\n",
" 'pitch_median': np.median(pitch_values) if pitch_values else 0,\n",
" 'pitch_q3': q3,\n",
" 'pitch_iqr': iqr\n",
" }\n",
" \n",
" print(\"\\n音高四分位数统计:\")\n",
" display(pd.DataFrame([quartile_stats]))\n",
" \n",
" else:\n",
" print(\"RAVDESS音频示例文件不存在\")\n",
" \n",
"except Exception as e:\n",
" print(f\"提取特征时出错: {e}\")\n"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"使用RAVDESS音频文件进行测试: ./RAVDESS/Actor_01/03-01-01-01-01-01-01.wav\n",
"\n",
"音高帧级数据 (前10行):\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" frame | \n",
" time | \n",
" pitch | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 0 | \n",
" 0.00000 | \n",
" 2458.481445 | \n",
"
\n",
" \n",
" | 1 | \n",
" 1 | \n",
" 0.02322 | \n",
" 182.268219 | \n",
"
\n",
" \n",
" | 2 | \n",
" 2 | \n",
" 0.04644 | \n",
" 190.799026 | \n",
"
\n",
" \n",
" | 3 | \n",
" 3 | \n",
" 0.06966 | \n",
" 197.138947 | \n",
"
\n",
" \n",
" | 4 | \n",
" 4 | \n",
" 0.09288 | \n",
" 423.822876 | \n",
"
\n",
" \n",
" | 5 | \n",
" 5 | \n",
" 0.11610 | \n",
" 166.867813 | \n",
"
\n",
" \n",
" | 6 | \n",
" 6 | \n",
" 0.13932 | \n",
" 172.440811 | \n",
"
\n",
" \n",
" | 7 | \n",
" 7 | \n",
" 0.16254 | \n",
" 168.360764 | \n",
"
\n",
" \n",
" | 8 | \n",
" 8 | \n",
" 0.18576 | \n",
" 148.656494 | \n",
"
\n",
" \n",
" | 9 | \n",
" 9 | \n",
" 0.20898 | \n",
" 151.040848 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" frame time pitch\n",
"0 0 0.00000 2458.481445\n",
"1 1 0.02322 182.268219\n",
"2 2 0.04644 190.799026\n",
"3 3 0.06966 197.138947\n",
"4 4 0.09288 423.822876\n",
"5 5 0.11610 166.867813\n",
"6 6 0.13932 172.440811\n",
"7 7 0.16254 168.360764\n",
"8 8 0.18576 148.656494\n",
"9 9 0.20898 151.040848"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"音高和调谐统计特征:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" pitch_mean | \n",
" pitch_std | \n",
" pitch_max | \n",
" pitch_min | \n",
" pitch_range | \n",
" pitch_median | \n",
" tuning_offset | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 573.830444 | \n",
" 853.130066 | \n",
" 3988.073975 | \n",
" 147.432693 | \n",
" 3840.641357 | \n",
" 234.112061 | \n",
" -0.17 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" pitch_mean pitch_std pitch_max pitch_min pitch_range pitch_median \\\n",
"0 573.830444 853.130066 3988.073975 147.432693 3840.641357 234.112061 \n",
"\n",
" tuning_offset \n",
"0 -0.17 "
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"音高四分位数统计:\n"
]
},
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" pitch_q1 | \n",
" pitch_median | \n",
" pitch_q3 | \n",
" pitch_iqr | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 173.241608 | \n",
" 234.112061 | \n",
" 488.627747 | \n",
" 315.386139 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" pitch_q1 pitch_median pitch_q3 pitch_iqr\n",
"0 173.241608 234.112061 488.627747 315.386139"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 测试音高和调谐偏差特征提取,以DataFrame形式展示\n",
"try:\n",
" # 加载一个示例音频文件\n",
" ravdess_file = './RAVDESS/Actor_01/03-01-01-01-01-01-01.wav'\n",
" if os.path.exists(ravdess_file):\n",
" print(f\"使用RAVDESS音频文件进行测试: {ravdess_file}\")\n",
" audio, sr = librosa.load(ravdess_file, sr=SAMPLE_RATE, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 创建一个存储音高和调谐特征的DataFrame\n",
" pitch_df = pd.DataFrame()\n",
" \n",
" # 提取音高特征\n",
" pitches, magnitudes = librosa.piptrack(y=audio, sr=sr)\n",
" \n",
" # 提取每帧最大幅度对应的音高\n",
" pitch_values = []\n",
" times_list = []\n",
" frame_indices = []\n",
" \n",
" for t in range(pitches.shape[1]):\n",
" idx = np.argmax(magnitudes[:, t])\n",
" pitch = pitches[idx, t]\n",
" time = t * 512 / sr # 计算时间点\n",
" \n",
" if pitch > 0: # 过滤掉静音帧\n",
" pitch_values.append(pitch)\n",
" times_list.append(time)\n",
" frame_indices.append(t)\n",
" \n",
" # 创建音高帧级DataFrame\n",
" pitch_frames_df = pd.DataFrame({\n",
" 'frame': frame_indices,\n",
" 'time': times_list,\n",
" 'pitch': pitch_values\n",
" })\n",
" \n",
" # 计算音高统计特征\n",
" pitch_stats = {\n",
" 'pitch_mean': np.mean(pitch_values) if pitch_values else 0,\n",
" 'pitch_std': np.std(pitch_values) if len(pitch_values) > 1 else 0,\n",
" 'pitch_max': np.max(pitch_values) if pitch_values else 0,\n",
" 'pitch_min': np.min(pitch_values) if pitch_values else 0,\n",
" 'pitch_range': np.ptp(pitch_values) if pitch_values else 0, # 峰峰值\n",
" 'pitch_median': np.median(pitch_values) if pitch_values else 0\n",
" }\n",
" \n",
" # 提取调谐偏差\n",
" tuning_offset = librosa.estimate_tuning(y=audio, sr=sr)\n",
" pitch_stats['tuning_offset'] = tuning_offset\n",
" \n",
" # 创建统计特征DataFrame\n",
" pitch_stats_df = pd.DataFrame([pitch_stats])\n",
" \n",
" # 展示结果\n",
" print(\"\\n音高帧级数据 (前10行):\")\n",
" display(pitch_frames_df.head(10))\n",
" \n",
" print(\"\\n音高和调谐统计特征:\")\n",
" display(pitch_stats_df)\n",
" \n",
" # 计算音高四分位数\n",
" q1 = np.percentile(pitch_values, 25) if pitch_values else 0\n",
" q3 = np.percentile(pitch_values, 75) if pitch_values else 0\n",
" iqr = q3 - q1\n",
" \n",
" quartile_stats = {\n",
" 'pitch_q1': q1,\n",
" 'pitch_median': np.median(pitch_values) if pitch_values else 0,\n",
" 'pitch_q3': q3,\n",
" 'pitch_iqr': iqr\n",
" }\n",
" \n",
" print(\"\\n音高四分位数统计:\")\n",
" display(pd.DataFrame([quartile_stats]))\n",
" \n",
" else:\n",
" print(\"RAVDESS音频示例文件不存在\")\n",
" \n",
"except Exception as e:\n",
" print(f\"提取特征时出错: {e}\")\n"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"开始使用真实数据训练模型...\n",
"训练参数:\n",
" 轮次: 100\n",
" 批量大小: 32\n",
" 检查点路径: ./output\\emotion_model\\best_model_weights.h5\n",
"Epoch 1/100\n",
"\u001b[1m10/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.1881 - loss: 4.1832 \n",
"Epoch 1: val_loss improved from inf to 3.07267, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m7s\u001b[0m 77ms/step - accuracy: 0.1933 - loss: 4.1151 - val_accuracy: 0.2583 - val_loss: 3.0727 - learning_rate: 0.0010\n",
"Epoch 2/100\n",
"\u001b[1m10/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.3231 - loss: 3.1472 \n",
"Epoch 2: val_loss improved from 3.07267 to 2.91173, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 19ms/step - accuracy: 0.3228 - loss: 3.1418 - val_accuracy: 0.2000 - val_loss: 2.9117 - learning_rate: 0.0010\n",
"Epoch 3/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.3529 - loss: 2.9806 \n",
"Epoch 3: val_loss improved from 2.91173 to 2.81711, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 19ms/step - accuracy: 0.3504 - loss: 2.9690 - val_accuracy: 0.1667 - val_loss: 2.8171 - learning_rate: 0.0010\n",
"Epoch 4/100\n",
"\u001b[1m10/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.3511 - loss: 2.7555 \n",
"Epoch 4: val_loss improved from 2.81711 to 2.76079, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 20ms/step - accuracy: 0.3508 - loss: 2.7371 - val_accuracy: 0.1667 - val_loss: 2.7608 - learning_rate: 0.0010\n",
"Epoch 5/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.3762 - loss: 2.5691 \n",
"Epoch 5: val_loss improved from 2.76079 to 2.72165, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 19ms/step - accuracy: 0.3851 - loss: 2.5434 - val_accuracy: 0.1667 - val_loss: 2.7217 - learning_rate: 0.0010\n",
"Epoch 6/100\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 10ms/step - accuracy: 0.4150 - loss: 2.5097\n",
"Epoch 6: val_loss improved from 2.72165 to 2.70396, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 24ms/step - accuracy: 0.4151 - loss: 2.5085 - val_accuracy: 0.1583 - val_loss: 2.7040 - learning_rate: 0.0010\n",
"Epoch 7/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.4134 - loss: 2.5004 \n",
"Epoch 7: val_loss improved from 2.70396 to 2.69049, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 22ms/step - accuracy: 0.4237 - loss: 2.4482 - val_accuracy: 0.1750 - val_loss: 2.6905 - learning_rate: 0.0010\n",
"Epoch 8/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.5066 - loss: 2.1765 \n",
"Epoch 8: val_loss improved from 2.69049 to 2.67515, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 20ms/step - accuracy: 0.4988 - loss: 2.2100 - val_accuracy: 0.2333 - val_loss: 2.6752 - learning_rate: 0.0010\n",
"Epoch 9/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.4397 - loss: 2.1924 \n",
"Epoch 9: val_loss improved from 2.67515 to 2.66241, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 20ms/step - accuracy: 0.4442 - loss: 2.1894 - val_accuracy: 0.2667 - val_loss: 2.6624 - learning_rate: 0.0010\n",
"Epoch 10/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.4683 - loss: 2.1495 \n",
"Epoch 10: val_loss improved from 2.66241 to 2.65176, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 19ms/step - accuracy: 0.4700 - loss: 2.1500 - val_accuracy: 0.2833 - val_loss: 2.6518 - learning_rate: 0.0010\n",
"Epoch 11/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.4583 - loss: 2.0871 \n",
"Epoch 11: val_loss improved from 2.65176 to 2.63942, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 19ms/step - accuracy: 0.4561 - loss: 2.1086 - val_accuracy: 0.2833 - val_loss: 2.6394 - learning_rate: 0.0010\n",
"Epoch 12/100\n",
"\u001b[1m11/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━\u001b[0m \u001b[1m0s\u001b[0m 11ms/step - accuracy: 0.4799 - loss: 2.1424\n",
"Epoch 12: val_loss improved from 2.63942 to 2.62882, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 22ms/step - accuracy: 0.4839 - loss: 2.1406 - val_accuracy: 0.2750 - val_loss: 2.6288 - learning_rate: 0.0010\n",
"Epoch 13/100\n",
"\u001b[1m11/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━\u001b[0m \u001b[1m0s\u001b[0m 11ms/step - accuracy: 0.5356 - loss: 2.1000\n",
"Epoch 13: val_loss improved from 2.62882 to 2.61788, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 21ms/step - accuracy: 0.5361 - loss: 2.0992 - val_accuracy: 0.2750 - val_loss: 2.6179 - learning_rate: 0.0010\n",
"Epoch 14/100\n",
"\u001b[1m 6/12\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 10ms/step - accuracy: 0.4660 - loss: 2.0251\n",
"Epoch 14: val_loss improved from 2.61788 to 2.60245, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 25ms/step - accuracy: 0.4793 - loss: 2.0527 - val_accuracy: 0.2833 - val_loss: 2.6024 - learning_rate: 0.0010\n",
"Epoch 15/100\n",
"\u001b[1m10/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - accuracy: 0.5078 - loss: 2.0108\n",
"Epoch 15: val_loss improved from 2.60245 to 2.59021, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 25ms/step - accuracy: 0.5108 - loss: 2.0079 - val_accuracy: 0.2750 - val_loss: 2.5902 - learning_rate: 0.0010\n",
"Epoch 16/100\n",
"\u001b[1m 8/12\u001b[0m \u001b[32m━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 8ms/step - accuracy: 0.5107 - loss: 1.9981 \n",
"Epoch 16: val_loss improved from 2.59021 to 2.57797, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 21ms/step - accuracy: 0.5153 - loss: 1.9897 - val_accuracy: 0.2833 - val_loss: 2.5780 - learning_rate: 0.0010\n",
"Epoch 17/100\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 10ms/step - accuracy: 0.5400 - loss: 1.9434\n",
"Epoch 17: val_loss improved from 2.57797 to 2.56796, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 21ms/step - accuracy: 0.5404 - loss: 1.9445 - val_accuracy: 0.2750 - val_loss: 2.5680 - learning_rate: 0.0010\n",
"Epoch 18/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.5527 - loss: 1.9138 \n",
"Epoch 18: val_loss improved from 2.56796 to 2.55026, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 19ms/step - accuracy: 0.5532 - loss: 1.9246 - val_accuracy: 0.3000 - val_loss: 2.5503 - learning_rate: 0.0010\n",
"Epoch 19/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.5570 - loss: 1.9163 \n",
"Epoch 19: val_loss improved from 2.55026 to 2.52697, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 21ms/step - accuracy: 0.5544 - loss: 1.9199 - val_accuracy: 0.3000 - val_loss: 2.5270 - learning_rate: 0.0010\n",
"Epoch 20/100\n",
"\u001b[1m11/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━\u001b[0m \u001b[1m0s\u001b[0m 11ms/step - accuracy: 0.5514 - loss: 1.9147\n",
"Epoch 20: val_loss improved from 2.52697 to 2.49535, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 22ms/step - accuracy: 0.5542 - loss: 1.9113 - val_accuracy: 0.3333 - val_loss: 2.4954 - learning_rate: 0.0010\n",
"Epoch 21/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.5543 - loss: 1.9019 \n",
"Epoch 21: val_loss improved from 2.49535 to 2.46785, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 19ms/step - accuracy: 0.5600 - loss: 1.8988 - val_accuracy: 0.3333 - val_loss: 2.4678 - learning_rate: 0.0010\n",
"Epoch 22/100\n",
"\u001b[1m11/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━\u001b[0m \u001b[1m0s\u001b[0m 11ms/step - accuracy: 0.5654 - loss: 1.9222\n",
"Epoch 22: val_loss improved from 2.46785 to 2.43942, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 28ms/step - accuracy: 0.5681 - loss: 1.9149 - val_accuracy: 0.3417 - val_loss: 2.4394 - learning_rate: 0.0010\n",
"Epoch 23/100\n",
"\u001b[1m10/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.6012 - loss: 1.8228 \n",
"Epoch 23: val_loss improved from 2.43942 to 2.41976, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 17ms/step - accuracy: 0.6049 - loss: 1.8204 - val_accuracy: 0.3667 - val_loss: 2.4198 - learning_rate: 0.0010\n",
"Epoch 24/100\n",
"\u001b[1m10/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.5819 - loss: 1.8635 \n",
"Epoch 24: val_loss improved from 2.41976 to 2.38653, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 18ms/step - accuracy: 0.5889 - loss: 1.8442 - val_accuracy: 0.3500 - val_loss: 2.3865 - learning_rate: 0.0010\n",
"Epoch 25/100\n",
"\u001b[1m10/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.5965 - loss: 1.8145 \n",
"Epoch 25: val_loss improved from 2.38653 to 2.34923, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 18ms/step - accuracy: 0.5983 - loss: 1.8172 - val_accuracy: 0.3583 - val_loss: 2.3492 - learning_rate: 0.0010\n",
"Epoch 26/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.6010 - loss: 1.7406 \n",
"Epoch 26: val_loss improved from 2.34923 to 2.33124, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 20ms/step - accuracy: 0.5984 - loss: 1.7382 - val_accuracy: 0.3667 - val_loss: 2.3312 - learning_rate: 0.0010\n",
"Epoch 27/100\n",
"\u001b[1m 6/12\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 11ms/step - accuracy: 0.6005 - loss: 1.7222\n",
"Epoch 27: val_loss improved from 2.33124 to 2.30899, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 19ms/step - accuracy: 0.6159 - loss: 1.7180 - val_accuracy: 0.3583 - val_loss: 2.3090 - learning_rate: 0.0010\n",
"Epoch 28/100\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 10ms/step - accuracy: 0.6474 - loss: 1.6815\n",
"Epoch 28: val_loss improved from 2.30899 to 2.27995, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 22ms/step - accuracy: 0.6476 - loss: 1.6803 - val_accuracy: 0.3667 - val_loss: 2.2800 - learning_rate: 0.0010\n",
"Epoch 29/100\n",
"\u001b[1m11/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━\u001b[0m \u001b[1m0s\u001b[0m 11ms/step - accuracy: 0.6280 - loss: 1.7451\n",
"Epoch 29: val_loss improved from 2.27995 to 2.27024, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 21ms/step - accuracy: 0.6306 - loss: 1.7372 - val_accuracy: 0.3500 - val_loss: 2.2702 - learning_rate: 0.0010\n",
"Epoch 30/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.6910 - loss: 1.6493 \n",
"Epoch 30: val_loss improved from 2.27024 to 2.24994, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 20ms/step - accuracy: 0.6879 - loss: 1.6493 - val_accuracy: 0.3833 - val_loss: 2.2499 - learning_rate: 0.0010\n",
"Epoch 31/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.7136 - loss: 1.5697 \n",
"Epoch 31: val_loss improved from 2.24994 to 2.24836, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 21ms/step - accuracy: 0.7054 - loss: 1.5845 - val_accuracy: 0.3833 - val_loss: 2.2484 - learning_rate: 0.0010\n",
"Epoch 32/100\n",
"\u001b[1m10/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.6437 - loss: 1.6553 \n",
"Epoch 32: val_loss improved from 2.24836 to 2.22598, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 19ms/step - accuracy: 0.6458 - loss: 1.6541 - val_accuracy: 0.3917 - val_loss: 2.2260 - learning_rate: 0.0010\n",
"Epoch 33/100\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 10ms/step - accuracy: 0.6558 - loss: 1.6250\n",
"Epoch 33: val_loss improved from 2.22598 to 2.19080, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 21ms/step - accuracy: 0.6554 - loss: 1.6239 - val_accuracy: 0.4083 - val_loss: 2.1908 - learning_rate: 0.0010\n",
"Epoch 34/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.6648 - loss: 1.5204 \n",
"Epoch 34: val_loss improved from 2.19080 to 2.16207, saving model to ./output\\emotion_model\\best_model_weights.h5\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 18ms/step - accuracy: 0.6683 - loss: 1.5228 - val_accuracy: 0.4167 - val_loss: 2.1621 - learning_rate: 0.0010\n",
"Epoch 35/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 14ms/step - accuracy: 0.6689 - loss: 1.5494\n",
"Epoch 35: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 22ms/step - accuracy: 0.6724 - loss: 1.5530 - val_accuracy: 0.4083 - val_loss: 2.1839 - learning_rate: 0.0010\n",
"Epoch 36/100\n",
"\u001b[1m11/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━\u001b[0m \u001b[1m0s\u001b[0m 6ms/step - accuracy: 0.6951 - loss: 1.5312 \n",
"Epoch 36: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - accuracy: 0.6937 - loss: 1.5345 - val_accuracy: 0.4083 - val_loss: 2.1734 - learning_rate: 0.0010\n",
"Epoch 37/100\n",
"\u001b[1m 7/12\u001b[0m \u001b[32m━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 9ms/step - accuracy: 0.6908 - loss: 1.5607 \n",
"Epoch 37: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 15ms/step - accuracy: 0.7032 - loss: 1.5439 - val_accuracy: 0.3917 - val_loss: 2.2004 - learning_rate: 0.0010\n",
"Epoch 38/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.7480 - loss: 1.4373 \n",
"Epoch 38: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 14ms/step - accuracy: 0.7359 - loss: 1.4556 - val_accuracy: 0.3917 - val_loss: 2.1724 - learning_rate: 0.0010\n",
"Epoch 39/100\n",
"\u001b[1m 9/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.7369 - loss: 1.4801 \n",
"Epoch 39: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 14ms/step - accuracy: 0.7298 - loss: 1.4826 - val_accuracy: 0.3750 - val_loss: 2.1938 - learning_rate: 0.0010\n",
"Epoch 40/100\n",
"\u001b[1m 8/12\u001b[0m \u001b[32m━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.7517 - loss: 1.4243 \n",
"Epoch 40: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 15ms/step - accuracy: 0.7413 - loss: 1.4394 - val_accuracy: 0.4083 - val_loss: 2.1900 - learning_rate: 2.0000e-04\n",
"Epoch 41/100\n",
"\u001b[1m 8/12\u001b[0m \u001b[32m━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 8ms/step - accuracy: 0.6834 - loss: 1.4966 \n",
"Epoch 41: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 15ms/step - accuracy: 0.6923 - loss: 1.4886 - val_accuracy: 0.4167 - val_loss: 2.1851 - learning_rate: 2.0000e-04\n",
"Epoch 42/100\n",
"\u001b[1m10/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - accuracy: 0.7367 - loss: 1.4154\n",
"Epoch 42: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 20ms/step - accuracy: 0.7355 - loss: 1.4192 - val_accuracy: 0.4417 - val_loss: 2.1892 - learning_rate: 2.0000e-04\n",
"Epoch 43/100\n",
"\u001b[1m 8/12\u001b[0m \u001b[32m━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 8ms/step - accuracy: 0.7401 - loss: 1.4367 \n",
"Epoch 43: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 16ms/step - accuracy: 0.7391 - loss: 1.4420 - val_accuracy: 0.4333 - val_loss: 2.1974 - learning_rate: 2.0000e-04\n",
"Epoch 44/100\n",
"\u001b[1m 7/12\u001b[0m \u001b[32m━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 10ms/step - accuracy: 0.7057 - loss: 1.4840\n",
"Epoch 44: val_loss did not improve from 2.16207\n",
"\u001b[1m12/12\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 17ms/step - accuracy: 0.7197 - loss: 1.4650 - val_accuracy: 0.4167 - val_loss: 2.2100 - learning_rate: 2.0000e-04\n",
"\n",
"训练完成! 耗时: 18.03秒\n",
"\n",
"在测试集上评估模型:\n",
"\u001b[1m4/4\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 9ms/step - accuracy: 0.4150 - loss: 2.1795 \n",
"测试损失: 2.1404\n",
"测试准确率: 0.4333\n",
"\n",
"在测试集上预测:\n",
"\u001b[1m4/4\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 7ms/step \n",
"测试集中实际出现的类别索引: [0 1 2 3 4 5]\n",
"测试集中实际出现的类别: [np.str_('angry'), np.str_('fear'), np.str_('happy'), np.str_('neutral'), np.str_('sad'), np.str_('surprise')]\n",
"准确率: 0.4333\n",
"\n",
"分类报告:\n",
" angry: 精确率=0.7692, 召回率=0.5000, F1分数=0.6061\n",
" fear: 精确率=0.7273, 召回率=0.4000, F1分数=0.5161\n",
" happy: 精确率=0.4000, 召回率=0.4000, F1分数=0.4000\n",
" neutral: 精确率=0.2917, 召回率=0.3500, F1分数=0.3182\n",
" sad: 精确率=0.4444, 召回率=0.4000, F1分数=0.4211\n",
" surprise: 精确率=0.3235, 召回率=0.5500, F1分数=0.4074\n",
"\n",
"平均指标:\n",
"宏平均: 精确率=0.4927, 召回率=0.4333, F1分数=0.4448\n",
"加权平均: 精确率=0.4927, 召回率=0.4333, F1分数=0.4448\n"
]
},
{
"data": {
"image/png": "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d2675ZZb1KtXr/OeawLJsmXLOtdN30M/Pz/FxMQoLCws29c3Gcdy5co510NDQ3Xy5Ml8t8/7PyaHy5l/2E899ZT9Cs/GtfQeXEvvwHX0HlxL78B1RH6YzOErr7yiadOmOZcePXpk+1wTDGbNLAYFBSkpKSnH1/f398+0j/k+MTH/GW0vzwPAXd4EO3fuzJRGh2fiWnoPrqV34Dp6D66ld+A6Ij9yKifNjskS7t27N9M28wFEQEBArvucPn3auZ6QkJDr87MigwgAAAAAbqh27drasmWLc/3IkSN2ZNOcykuNWrVqZdrHfGhRqlSpfB+TABEAAAAA3FCDBg1sxnDJkiV2fd68eWrSpIktPY2NjVVKSsp5+7Ru3Vo//fSTne7CZA+//vprNWvWLN/HJEBEgTMpdNPxNr+pdLgvrqX34Fp6B66j9+BaegeuIy41059w8ODBmjJligYOHKjly5erb9++9rEBAwbYIDCriIgIXX/99Xr66ad133332WDymmuuyfcxHakUSQMAAACA2zp16pR27NihOnXqqFixYvnax0yHceLECTVs2PCC+iASIAIAAAAALEpMAQAAAAAWASIAAAAAwCJABAAAAABYBIgAAABuIi4uztVNAODjCBABAJlkN6cSvAPX1v2Dw+eff17ffPONq5sCwIcRIMJtbN++3X5lYF3Pwh+c3sfMl2SsWbPGfuUae74jR45o165d9tpyPd2XGYa+U6dO+uqrr7R48WJXNweFjPcm3AUBItyC+UP0mWee0f79++VwOFzdHOSTCebT/+Bct26dkpOTXd0kXCLbtm3T2LFj7ZxL6QEjPJN5f/7www964YUXnNeTP0Tdk5lc/dprr9U///lPzZ07Vz/++KOrm4RCYt6T6ffamJiYTO9R3q8obPmfMREoQGbSzw4dOtggo3LlyplulHBPGa/RlClTbGlU7dq17R848DxZ33PmWpo/VM0fqFWqVFFQUJBL24e/z1zXq6++WklJSXrttdf04IMP2uvLfda9ZLweJuNbokQJffDBB3b7lVde6ermoYClX/tJkybp4MGDKlKkiBo3bqzrrrvugiY4By4FfjP8f3vnAmZj+bXx1b+DRKJEyWlSIilEIUVHIjUVkiSFSufooBMVReXUQTl0ohRSaCpKMjpIEspFhVKoVCQk6fhdv/V9z/72bPSXzH7fPe7fde1rZu/Ze89rHu+7n3ute60lYmErLVy4sFWoUMGmTp2auFDKahpvwhqxhmw8q1WrJhFRADYnBGkCrOmiRYvsl19+8fuKYmcuxYoVs+bNm9vRRx9tDzzwgGeIlUmM5zWVGkTswIhC1mv06NGym+4gjB8/3j9T27RpY1WrVrVXXnnF1z+gfZFIFxKIIjKwPPXr188GDx5sq1atsmbNmlnJkiXtySef9J/Lahp/cnJybNiwYfbll1+6wJewz2zmzJlj9957r5+XH3/8sR111FFWunRpzxCDsk2ZzZ577mmnn366RGKMWbNmjW3cuNEFAhn8tm3but30ueeesxkzZkR9eCKfIXN85JFHujj8448//NzkfMXJwffaF4l0oU97ERmHH364denSxZYvX25Dhw51oVGrVi2vY1u7dq0/R2IjXqRuJNlskmX6/vvvbfbs2Z5J1AdY5q5n9erVrX///olI9j333OPnJBvWpUuX+uM6JzOH5LUKay2RGC9S/+5Fixb1823atGmJ+zVq1LBChQrZgAED7J133onoSMX2ZnPnHJn+JUuW2NNPP22TJk2yK664wjZs2GATJ07UOSrSigSiSDtkCOfOnesXQupgevToYSeffLKLC+otXn/99USkVGIjPhDNDBlCCuh//PFHf/z888+3Y4891ptfzJs3T41qMrDeaebMmfbhhx/6xoQs/pVXXmnnnnuulShRwkaMGOHiX+dk5p2vyWuVvLlMFomDBg2yhQsXKjsc8TV19erVfqPWrHHjxt6wLTc3159XqlQpr9Nv2rSpVapUKerDFtv5+stnJ4Fy9kAE6datW2dTpkyxDh06+P0VK1b48/i5AnQiXez0l/63iTSCFRFL6SWXXGIVK1bcpEnCBx98YO+9954tW7bMrr76attvv/0iPV7xv3CZYLPJevXs2dM3MUS0TzjhBM8wAVlgRCN1M7Vr11ZRfYxJPu/IIn366adWvHhx36QgDLG2BRAPCEQyGjfeeKOftyIz1pevffv29WYX3LKzs23vvfdOPI+N6JgxY7zOlA6nNJhSACD919Tbb7/ddt55Z6/hppkQomDUqFFeh8jzypQp40Gc3r17ewBHFByw83P+0ZyPfRHBAMQhATkCCKz9W2+9ZZ07d7a6detGfbhiB0ICUaQNBv+yIZk/f75169YtT0OT8GEJRMueeuopO+ecc6x8+fIR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6CLbddddbcCAAVa8eHG/j9gis/if//zHdt55ZzvzzDNt8ODB9t1331mNGjVsxIgRVrZsWX9PnvfFF1/Y8OHDbcOGDf5e/J5kMRpIffyMM86wU0891YoWLZrnebzP+vXrrVSpUnkenzRpks2dO9cOOOAAe+ihh6xixYr2xx9/+HG/+uqrfrwIzpdfftmKFCnix9aiRQvLzs7Op7+sEEIIkT9IIAohhMg3ypQpYy+88IILLrJsXbt2tWrVquV5zooVK1z8wU477WS77bZb4mf16tWzChUquGj75ptvLCsry26//Xb/GaLxiiuucCHZq1cvq1u37iYZu4ULF7roXLlypYs/7v/5559WpUqVrTp+XpuTk2PPPPOMnX/++da4cWMXsq1bt7ZatWr5v2nevHnWs2dPF42dO3e2yy+/3A4//PDt8NcTQggh0o8EohBCiHxlv/32s0ceecQFVRBOWD4Ri/DTTz95FnDkyJGJ5991113+PZk4RCYgEAGb57PPPmsdOnRI/A6yg2QQU6Fm8Icffkjcv/XWW22PPfawJ598cquOfePGjW5rbdeunTVt2tQfu+qqq1yoPv744y4g77zzTheHcPrpp2/2OIQQQohMQQJRCCFEvoB4woZZv35923vvve2jjz7KI+jWrVtnDzzwgBUrVsyzgQjD6dOn28SJE/05WFIRcgjJIMBClvHTTz+13XffPc9jmwNByPPuuOMOzy5ieeX30nAGIbe515FhRJgeeOCB/trLLrssz8+xyL722mtuKcWiitjt1KmT/zuaNWu2Xf52QgghRFRIIAohhMgXaE5z8cUXuwgLQgy7KXTp0sW/UruHxbRbt25e2xdqD0PzmUqVKtltt91mt9xyS+J9+Tnijuf+N6hXJEOJAN1nn338tT///LNbQnkP7iNiaThTuHBhfw33eXxLWUbqDKmFxEp60EEHWffu3e3qq6+2k08+2esaS5QosR3+ekIIIUQ0SCAKIYTIF8jYIaQKFSrkVs9y5crZUUcd5WKwcuXKiechzhBk++67b57X8zrsnIyQoKMoIi+QXKf43yArSTbz22+/9ffr3bu3W1SDaJ05c6Z3NX3sscf+9n34/fx7eD6W0+OOO84fpyaS9xw/frxNmDDBG/Agbmloc+yxx271cQohhBBxQHMQhRBC5AsIMCyayTbOtWvXuuU02R6KQKQb6ObsnmQJ6TiKIAyzCXkP6ggDm5tZmGwXpcso9s/SpUvboYceak899ZT/rmXLlm3yfGYccjwBxnG8//77NnDgQLen8j3HQy3lV1995TfeCxsqllS+pxEOmdI5c+Zs419OCCGEiA5lEIUQQqQNhBU3OooGaCKTbMtMFXxTp061N998044//ni/T81f8vOpF9wSubm5nvk77bTT7OOPP3ZxRwYQIUhtIxnFkI3EenrTTTe5VbRt27b+GMc5bNgwt5+ee+65nhWl4Q5jL4IVNsw9RIQOGjTI3nnnHa+fTO3WKoQQQmQCEohCCCHSDnV+gcWLFyc6lQaxlcyUKVPcYkqGDjHHWImSJUv6IPqOHTv6Y2QKU19Hdu+JJ57weYTYVYEMIrdx48a5yGQ0xuzZs/1nZCURkGPGjPHHqS/kOX379nXxFzKKwVqK+ETs0oAHXn/9df+ddDLlJoQQQmQispgKIYRIOwg6ag4Riu+9915i/AWCjMY0yeLxyy+/dMGFQGzQoIF3Q61ataq/7pRTTnGBSBYxVSBiKW3ZsuUmYg0LKRlAxlbQTTUZBCKvI2vIMUIQhxwHVlIsrvDGG294ZjM05KGGMXmkhhBCCJGJSCAKIYRIO8GOSX0gIg07JsPusXAmj5Wglq9mzZqeQYS3337bxRiWz4cfftizdkCTmOzs7Dy/g/dFHFIXmGxbpZkMIhEraSrYRnkfOpyuXr06z88qVKjgzWd4PdBwByspTJ482ZvSNGzYcLv+nYQQQoh0I4upEEKIfGPlypWeVaPmj6xfgGwfHUGZJUjdH5lDBBfzCs855xxr0qSJW0lnzZrlswyDvXPs2LFei4jNk4ze8OHDXbQxQxFC1i8Vfl/IMDKrsEaNGp69xE46f/58n2cYaNSoUaLeETh+ZiciOE844QR/DCsp/54qVarYF1984aMvmjdv7o1v+D1YWhGMQgghRKYhgSiEECLfQBjed999PvqB7qWwaNEiGzBggIuoO++80zNzgF00KyvL+vTp45bRjRs3uvCrXr26ZwCZk4hQwzYKrVu3dgGJXbR9+/Yu9t599908HU43JxCLFCmSGLOBCOV+q1atEs9N7aZKDSRZQ6ysW5q9yOOIxJycHP89/HuZjyiEEEJkGjv99Xf9wYUQQoh8gMYw1B2m1gDCihUrvPELgoyOpYzAQDAyY7BixYpWu3btxHOXL1/uIpL3QcQtXbrUM4TJdYxCCCGE2HokEIUQQgghhBBCOGpSI4QQQgghhBDCkUAUQgghhBBCCOFIIAohhBBCCCGEcCQQhRBCCCGEEEI4EohCCCGEEEIIIRwJRCGEEEIIIYQQjgSiEEIIIYQQQghHAlEIIYQQQgghhCOBKIQQQgghhBDC4H8ADo3biKQsHZYAAAAASUVORK5CYII=",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"详细分类报告:\n",
" precision recall f1-score support\n",
"\n",
" angry 0.77 0.50 0.61 20\n",
" fear 0.73 0.40 0.52 20\n",
" happy 0.40 0.40 0.40 20\n",
" neutral 0.29 0.35 0.32 20\n",
" sad 0.44 0.40 0.42 20\n",
" surprise 0.32 0.55 0.41 20\n",
"\n",
" accuracy 0.43 120\n",
" macro avg 0.49 0.43 0.44 120\n",
"weighted avg 0.49 0.43 0.44 120\n",
"\n",
"\n",
"保存模型和相关信息...\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAGGCAYAAACqvTJ0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAA2uNJREFUeJzs3Qd4VNXWBuDvTHonPYFACL33Jr0oAoKKoojiRUUUu6hcvXbs5UdFVFCxdwTBggjSkaI06Z0AgfSE9J45/7P2ZEISUiHJlHzv85w77cyZPTkXs7PO2mtpuq7rICIiIiIiIiIiqkeG+vwwIiIiIiIiIiIiwaAUERERERERERHVOwaliIiIiIiIiIio3jEoRURERERERERE9Y5BKSIiIiIiIiIiqncMShERERERERERUb1jUIqIiIiIiIiIiOodg1JERERERERERFTvGJQiIiIiIiIiIqJ6x6AUEdW63NxcxMbGqltbEB8fj5iYmOLHx48fV1tt+Pfff5GXl1crx9J1vVaOQ0RERLbNmuda+/btw/z585GUlFSnn3P48OFS8zcisk0MShFRrfvzzz8RGhqqbst6++230bVr1+LHEyZMwCOPPFLucdauXYvff/8df/zxR7nbzz//jGPHjl3wvldeeQWOjo7IzMws9XxhYWG5n/Pxxx+jadOm+PLLL5Gfn4+xY8di+PDhOHXqFC6FTJT69euHyy+/HEaj8aKPk5CQgI4dO+Lee++9pPEQERGRfbDWuZb466+/cM8991wQlPL09ISmaRVuS5curdHP4MYbb0Tv3r1r9B4isj6Olh4AEdkfV1dXdevm5qZuk5OTkZaWBhcXF3VfJilydU9IRpJkAMnj7OxstU/jxo3Va7NmzVIToYyMDGRlZaFZs2bq+ejoaPWewMBAvPDCCzh37hz69OmDX375BePGjYOTk5MKQMmxzOSK3SeffIKVK1fC19e31HhlwiVjvfrqq9V7v//+ewwePBiTJk3C5s2by/2Op0+fxt69e9X7DAZTfF8CTzk5ORgwYAB8fHzUBFCuYM6cOVNlY5X8+TRq1OiCYx49elS9JpM8mZyVJMGyhQsX4umnn4aDg0Px8/JzKCgoUJ/bvHlzNX4iIiKyb9Y41zJzd3dXt87OzheM+eabb74gQJaSkoLLLrus+DuV59tvv8U///yDxx9/XAXjzMczfw8isl0MShFRrTNPUMzBE5lIPPDAA6X2MU8ozEvcfvrpJ3X/7rvvVgEksW7dOnX78MMPq2DSgQMH1GPJPJJAjPn1/fv3l5oEyedLoEiCOyU/b/fu3RgxYgRWrVoFPz8/9fyuXbuwbds23HXXXcWBIrm6+M0336BFixbqsUy6JOgjEzDzBGvNmjW4/fbby/3+ckwZkwS3hAS7Slq8eDGuu+66C97XuXPnKtPww8LCKnwtMjJSBaaIiIjIvlnjXMvMfLGuLJlDyfyrXbt2pZ5PTEwsfr0iP/74IzZt2qQCZGby3c3jISLbxeV7RFTrymb5TJs2TQV1JJPozTffRHh4uLr6Jlvfvn0xZcoUdV+u3r311lsXHE9qMlV29cw8ITPfymSo7BiuueYafP311yowJUvzzBMgSXEXH330UakUcrkKKEvm5L5MuCTlXDKVzG655RYVQJLjyOe99NJLavIm30FS2eU7S0q5XP2T7ybfXa4CytLA8gJS4uDBg4iLi1PvN/98ZJOxy1XF1NTUUs/LJj9XWWYoAanKAlZERERkP6xtriUX8GSeI8GsN954Qz03efJkDBw4UM29zJ8hWVyHDh0qtZmXB1ZUg1OyzZctW4YZM2bA29u71M+gbFDMPDeSORMR2QZmShFRrfnss89UargsbROSbbRhwwaVndSjRw8VcOnfv79KtTanlMskSpa6yWPJRPL397/guBL8qY1laVJ7QD7nySefxJkzZ9SExZzNJHUMZNmdkOfkaqPUWejQoYP6fJkoSQq7mXk8ctVOJoBjxoxRE7WTJ0+qwFOrVq2wYsUK9d3Ehx9+iO3bt6vAU2UFO+fOnYvPP/+8+MqfjEuWF0ptBg8PD/z222/qZyQTP3NK/hVXXIH333+fWVJERER2zlrnWhIgks+U5YTmrG+ZN0nwypwBJcEiqeMpW3nk9fK88847qoyBzN9kK++zy5JMroqOR0TWhUEpIqrVbityxUsmROZUbwnSSGDnhx9+qHC5m5kEWsw1nOTKmgRcZCIjdQwkKCSBnpJ1DqTugbwugZrqevDBB9VVPBmTZCzJJEfIZC0gIEDdl6woIcv5goKCKj2eFBht3749unfvrh63bNlSZVRJmrx5iWBJ5u9gTpU3Z2oJqQWxdetW9OrVC7/++qua2Elxc8mSmj17tpqAys9QJlo7d+5UNajkO8jPoLyaDkRERGRfrHWuJcEnKU8gJDNdip3LHKfkBTOpW1VTZ8+eVUGp66+/HjfddFOp1/73v/+p+dsTTzxxQaaUZK8TkW1gUIqIao0EToQU9t6xY4fqzDJ06FD1nDkjSSYL5ZEC3iWLisvkQ1K8ZSIkkxGZJEmmk5CC5ZImLqnoJdO9zQGmqsjE7auvvsKSJUvUccvrKmMmWVByXPkMLy+vUq/JMjs5jmQqLVq0SD0n2UyjR49WkzvJdpLJnpClfHfccYfKeBJdunS5oA6CfD95/qGHHlJZV506dVK3MvGUFHgJWMkSPemGI8Gy+++/X00WZaIYHBxcre9OREREtstW5lplRUVFldupr6y2bdsWZz7J97jtttvUXOi9995DSEhIqX2feeYZVf9TugsSke1iUIqIapVMIMxXyiSIIp1cZGmbec1/eSnWZpJ6biZ1A4TUS3ruuedUuvajjz6qnpNC5XIFTJ4X0o1F1CRNWyZhTZs2xVNPPaWuKg4bNuyCfczZT+YMqLLBq3nz5qklgBKQMgel2rRpo4JS5u9qnkDJhEqCWubHFRUHleKfsuxPSC0p83vM7Z2XL19enAb/5ZdfquyqqrK5iIiIyH7YylxLmDsC3nnnnaqQelUkEGYev2SESWkDmauVDUgJuQAoFwOJyLax0DkR1SoJqEjRbSFtgyUzyFx4U8TExJS7yVK28kjrXyGTLTOZJJUshilX1WQZXb9+/S6Y0JQlLZLT09NVNpKkvJs77kntpoSEBLVJXSdzhz2pvyBX91avXl3qOJIq//zzz6v769evV4VDJX3cXCTUXFxU3i+bjEk+1/xYfh7ljVGOI5NEGY8sA3z55ZfVz3TIkCHqO8pV0IiICDWBlCytbt26FU9MiYiIyP5Z+1zLnKklGd1NmjRR8yjJDpeLa2Ubtpg3GYO5o5+ZFGuXcggyZyuPNJOpqPueZHTJvKui4ulEZD0YlCKiWiOTCrmaJRlIQiYYkqotWT4yealKyX3k6pdcVZP6CJMmTVJ1m8ykgKa5iKaQegJSJ0omIL///ruarFV05Uyyi2RZnNRKKLkcz1xTSjZzTSlfX1+1LE6WzMnEyEyyoySLyTxeyVySYJRkQ5mLhMpkTq5cSjtm2aSwurQxNj+W4FfZn913332Hzp07qzHK95NMLClaKhMuqS0lwSeZhEoXmokTJ+Lqq69Wk0NJW5efkVyNJCIiIvtlrXMtCRDJEkBp9iKF1YXMV2QuI3Moc9c+s/vuu0/NX2SuZFY2g/y///2vKsou86CSHZLNm4zvgw8+KPc1mZtJp75vv/22hj9hIqpvXL5HRLVGJkRSgFMmCDLJkQmMXN2SjnPmmkcSkKmItCw2e/fdd1U9A5kgSR2BkiRAI1f85MqbeVIm5OratddeqyZMFRX6lGV2ciVOOsRUd/JnrillDlZJwEnqLkidAylCXh7ZXyZr5qKeUuhTrhg+9thj6nHZNPR169bh5ptvVh1zpDioZHDJPnLlU5YaShBKfoZS/+E///mPClxJkOqnn37Ciy++qLK1Sl5dJCIiIvtjrXMtmVvJ8j8JIPXp0wcbN25UGd8VdQaWhi1ywa6iTCch8yJp/iLHLtsZUBrCyFxIyPxKMsrLzsNkDiXzKiKycjoRUS2IiorSvby89FmzZukbN26UvG197dq1en5+vp6dna22wsLC4v27du2q33333aWOIa/n5uaq+0ajUZ85c6YeHx9f7ueNHz9eDw0NveD5b775Rl+/fr16f1n79+9X43r11VeLn1uyZIl6rqqtZcuWpY4lx5fvLK9t2bJFPffUU0/pPXv2VPffffdd3cPDQ09PT1dbs2bN9Jdffrn4cVBQkP7cc8+VOua3335b/P3Fvn371M9NyOdfddVVxa/98ssvF4yHiIiI7Je1z7UWLlyoxvDVV1+psUVGRha/du2116rxlBzbmDFjih8//vjjupubW7V+DgUFBXrnzp31Nm3a6B06dNDbt2+vZ2RkVOu9RGR9mClFRLVClrhJsU3JIDIXwzSnYr/00kuYNWvWBe/ZvXs3Pvzww1LPdezYUV0BlNTrN954Q7UVlu5zkoZd8iqZXF2Tq3Tz588v9X7JYpL2wdLyuOxVNakVJeMxd5IpSWo4DRgwQN2Xuk0PPPCAqiklnfrkmGVT4kvWUTBfjSu5j9SuknR6WQ4oJMVcioXKEj7z45L+/vtvVa/hyJEjxenrkuoutauEfFc5nhT9FK1bty6+b/7eUo9KlvuVTZEnIiIi22ftc60bbrihwrHLHKVkFrqUIzA3hjGrbv0nyRDfu3ev6kYsWenSfVC6Bko2vJubW7WOQUTWg0EpIqo1EsApj6RVSyBIJjsSMJHJkRQJlxRwWe+/du1aBAYGqppIUgS8JAnkyMSnbOq2LIuTiZK0NzaTAp/mGghS9LPk/idOnFAp6ldddVW5ae3mmlKibE2pqpRMGTd37JM0+pId+6pavjd48GD185DvWV5XPqn7IGn0AwcOvOA1mdxJQEzqMkj9BnPxdiIiIrIv1jzXqszw4cOLSxpIZz8ZhyytkzmMBMdkHiTBLjl+ZeUIZJmhXOCT5YVXXnmleu79999XY5Eg2aeffqou0BGR7WBQiojqnLmAuJArY1IHwVy/QIpmSjcYKZgpHVpKFtkUx48fL/eYkydPVlcLzUGfqjzzzDNqYnX33XeX2yFGxmUeo0zMzJ8tASIJ+JgnSr17977g2FLXSYJRs2fPVtlV8jlSI2rcuHGorrKZU2XJVdF27drht99+q/YxiYiIqGGwhrlWZaRoublZjGSjS/HzESNGqIttEpySwFfJ7n9lSQa6fAfJ6pIC6eZOyULmdnJBUQqsSw0qqXklxeB79ux5yeMmorrHqrhEVG82bdqkUqwlaPPVV1+pq2aSbi5FuqVbi3RuqQsSVJIU9DZt2mDUqFGlXjO3T77jjjtU5zvZzFcEZdIjj7t166YmOWWDTPI9hGReSSaUTK6kK59cpZPuenIVryLmYBgRERGRrc+1ygaQRNmMJ1lyKIXWT506pcYmS/qkI/KcOXPUxTfJeJKLgCVJsxcJQEkgTQJSEtCSbsVlj33LLbdgz549GDlyJJYsWaLmbTLvk2MSkXVjphQR1TpzbSUJ+MiEY9myZaolr0wSpI6BtBKWWyGdWmTiJHUQJCVdMppuvfVW1VVFAjuSFl6yfpPZ0aNHVep32ToHJTOPpM7Tgw8+qOoLSOaSXOkreyzz5Ec60JiX3pX3fWS/soGkkvURhFyZk65+EpyaPn16qfRxqXkgKfVSs0G65sl3My8TrA4ZQ3VaPRMREZH9s8a51ueff66yxmW+JXMcmRNJFpbU7ZRMb5mLBQUFqbENGjRIHUOWGUonY5k3yRLEBQsWqOV9/v7+KnAl2U/yOVJLUx6bl+yVRwJbUmdKPu+VV17Btm3bVGCKiKybJtXOLT0IIrIvy5cvVynYMgGRK3Ry1er06dOYMWMG7rvvvnLrD8gEZebMmarugUxGJONIrqhVNFGqikySZJO6CeZ09vJ88cUXuO2221StBbmyWBNSkFO+l7RKljoMQjKyZEL0n//8RwWhypJi5ZMmTVKp6nK1T4JV1SG1rWT5nlzpJCIioobNGudaEoySzHO5yCfzIFk+J2OS0gfyJ6fUfZIAlNTxLEuCaxLQOnDgAD777DP1nFwQlALmEoiS41a3fpWZZE516dKlxt+LiOoXg1JEVOckVdzLy6vKrnAyIZErcizUTURERGQfcy1pNiOdA8u7WEdExKAUERERERERERHVOxY6JyIiIrJxL7/8sqrXUhXppCVNGKRb1V9//VUvYyMiIiKqCINSRERERDZs48aN2L17d5X7SW0Xaepw/fXXq3bpCxcuRHR0dL2MkYiIiKg8DEoRERER2aiMjAx8+eWXqstVVdasWaO6cUmH0GbNmmHUqFHYsGFDvYyTiIiIqDwMShERERHZKAlI9enTR7VLr8qpU6fQqVOnUu3TpQAxERERkaUwKEVERERkg/bt24e9e/di8uTJ1do/KysLQUFBxY/d3Nxw7ty5CvfPz89X7zFv0vqdiIiIqDY5ogGTiVhBQUGdHDswMBAJCQl1cmyqWzx3tovnznbx3NmuhnDuHB0d4evrC2uSl5eHjz/+GNOmTVPBpeqQVvFOTk7Fj+V+bm5uhfsvWbIEixYtKn7cpk0bvPTSS5c4ciIiIqLzGnRQSgJSchWwtmmaVnx8Xddr/fhUd3jubBfPne3iubNdPHeWs3jxYrRs2RI9evSo9ns8PT2RlpZW/FgynyTgVpHx48dj7NixF5xvCULWxUU9OX5ISAhiY2P5/ycbw3Nn23j+bBfPne1qCOfO0dFRXbyscr96GQ0RERER1Zq//vpLBZhuu+029VgynrZs2YJjx47hzjvvLPc9EsQ6cuQIhg8frh5HRkbCz8+vws+QTKqSmVUl1eUEWo5trxN0e8dzZ9t4/mwXz53t0nnuGJQiIiIisjUvvPACCgsLix9/9dVXqtj50KFDkZmZqZb0GQylS4f27dsXzzzzDMaMGaNqSy1fvhyDBg2ywOiJiIiITBiUIiIiIrIx/v7+pR67urrC29tbbTfeeCPeeOMNNG/evNQ+8lgCUk888YTKgAoNDcWVV15ZzyMnIiIiOo9BKSIiIiIbd9999xXfX7hwYYX7TZo0SWVHJScno0OHDpXWlCIiIiKqa5yJEBERETUgYWFhaiMiIrIFsixdGmyYG27Yi+zsbNVN15a5u7tf8gUuBqWIiIiIiIiIyOpIIw8JRvn4+MDeyFL6/Px82Cqj0Yj09HR4eHhcUmCqdAVMIiIiIiIiIiIrCUpJ8w6yPtJQxcvLC1lZWZd2nFobERERERERERFRLbK3ZXv2xFCm0+9FHaNWRkJERERERERERFQDrClFREREVkPPzQVOHoF+6jhQWFD9NwaEwNB7YF0OjeqYcdcWpK5OgN6+GxDa1NLDISIiuiRSnL22utzqum63GWMMShEREZHF6BlpwLGD0I8egH7sAFDTYJRZpx4Ag1I2TV+3HGn7d8Fw20PQGJQiIiIbtm3bNjz//PP48ssv4e/vX9xtr2x9rOzsbCQlJRV3xd2wYQMKCwsxbNiwUvtdf/31ePLJJ9GrV69yP2/cuHG47777MGrUKFWHq0WLFmjbtm3x61L3qXXr1vjqq68qDXz16NEDCxcuVPvWFwaliIiIqF7IZAdJ8abgkwShjh4AYqIu3LGRH9CiHTQ39+ofvEl4rY6VLCAgRN3oibGwz2vBRETUUPTu3RuDBw/GhAkTsHjxYvj5+eGee+7Btddei2uuuQbfffcdpkyZgsOHD+Oll17CokWL1Ps++OADjBgxQgWlJLjk7OyMqKgoHD16FJ06dSrOwJLOd/Ka3EpdJxcXF7VJQEtuJatq5cqVxZlamzdvxqeffnrBODdt2oR58+apYJW8Jzk5WRUvr08MShEREVGd03dugfGHBUBywoUvhjaF1qo90Lqj6TYg2G5T1KliWkAwdLmTEGfpoRAREV2yxx9/HHl5eThx4oQKSrm6uhYHjJ544gkVlHJ0dISDg4PaXwJUqampuOOOO5CYmKiynmTftLQ0td+QIUPUfhJ4ktckmPXUU0+pgJYEsHbu3Kkyqb7++mt1IfD+++8vnk/J8eTzy/rpp5/QvXv34v0kwFVyPzmuPOfk5FRnPycGpYiIiKhO6Xu3w/jRGzKLAmTi1awltNYdoLXqALRqD83Lx9JDJGsQaM6UYlCKiIgqyLjOy7XMhzubgknVkZGRoYJLEsiZMWMGPD09TYdwdi4+Rnm1pubMmYNZs2apJX1Dhw7Fjz/+iHbt2qnMKcmgkvtlvfrqq2qTjCxZvicZVpI9tWLFigv2NY/DTIJlS5cuVUsKP/vsM/WcBNEGDBhQPE4JSskyxFtuuQV1hUEpIiIiqjP64X0wzntNBaS03oOgTXkAmsuFV+qIJFNKSYy19FCIiMga5eXCeP+NFvlow3sLgWrOX7Zs2YIXXnhBBaZkuZ7cN2c4VWTZsmXYt28fDhw4gI8++kgFoiSbKj4+XmU5PfDAA8jMzFTL8KoKiM2dO1fVsiqPZFV17NgR+fn5KmAmgaxHHnmkeFlgeHi4yriSjK76wqAUERER1Qn95FEY33sRyM8DuvSGdscMaLXUhYbsN1MKqedUF0atHifEREREteWKK65Q2+zZs1WBcbOcnJzipXpleXl5oW/fvqp+1F9//aUKngcFBeHRRx/FZZddhrFjx6Jbt27lvjc6Ohrnzp3Ds88+q/b18fHBnXfeqd4bFxcHX19flaUlx5dbIeO67rrrSmVApaSkqOyusgEpczCtorFfKs4MiYiIqNbpZ0/D+M7zQE420LYzDHf/lwEpqpTm4ak2PTMDSIoDGjez9JCIiMiaOLuYMpYs9NkXo2QgRzKeyi6hM5Oi6LI9+OCDmDlzpgpIHTt2DOvWrcPLL7+s9jEvqZMsJ7kvSwClptT333+vPkdqWE2dOhWvvPJK8XGluPrVV1+N2267rdQxfv/9d7Us74033ih1XNmka5+5hpQsmZTlhK+99hpuvLFustQ4OyQiIqJapSfEwvj2s0BmOtC8NQz3PwXtIidz1LA4hjRB/vHDpmLnDEoREVEJKnhiwyUAJMgky+MqsnLlSpw9exbvvPOOCgT9+eefKqNJCpxLcCg9PV1lO0mdp4cfflgFmiZOnKiW3919991o0aKFOo7UlDKTJX+yXK9s1tOkSZPUVtJDDz2ksrQiIiJUPav6ajrDoBQREZEVBXPg6ATN198yxUMz0kzd8WQS0rTFRU1G9JQkGN96BkhNBpqEw/DQc9Bc3etkzGS/QSkpds7+i0REZA9+++03tGrVShUUb9y4cbn7nD17VnXLk8DSoEGD1HOSJSWBJwlQubu7qy55Uq8qJiYGTZo0Uft06dLlgmNJ1pQswZP3nTp1Cu3bt1fPh4aGlgpYlbRp0yasWrVKBcZk6Z/UwXrmmWdU5726xqAUERGRFdAjj8D4xhNyeQtan8HQRk2A1qT2MkX0/HzgXKIKOulJCabgk9yXW/Njqf1kFt4KhjETgG79oFVzQqKnp8H41rOAdE8LDIHh4VnQPL1r7TuQ/XMMNk2yWeyciIhsnVzwkwLmf//9N3r27InRo0cXvyZFxUtq0qSJWorXpk2b4kCTXByU4FBycrLqzCek1pTsJ931KloK+L///U/dyjI+6aT3yy+/qILpsszP1fXCTLO1a9eqgufvvvuuGod04ps8eTJuuukmPP300+UGvmoTg1JEREQWpudkw7hgtsxQTI+3rlMbuvaBYfQEaC3bXdxxJej0zwa1ISqy6jdIZpSPLyA1fU4dM3XNCwmDNup6aH2HVFoTSs/OgnHO80BMFNDIH4ZHXoTWyO+ixk0NO1NKSKYUERGRLTt9+rTqhvfmm2+qWk8SoDIvoZOC5ObgVGFhoQpgydK8rVu34oMPPsD+/ftx1113qeV0S5YsMWW0Axg6dKgqeP7cc8+pQuoSsJJueZIRZS5QLh38JMAk3fwWL16sugBKTSh576uvvophw4ap/Y4cOYJ58+ap7CgJel1++eXq+ZCQEPWZL774Iq666ioVULv33nsxcuTIOvk5MShFRERkYfrCT4D4GMAvAIbbHoJx3XJg1xZg9z8w7v7HVCh89ASgQ7cql9RJkWh9xybof68Hju6Xy3TnX5SOK36BgF8QNH+5DVCPNf8g0/ON/KE5OUFPS4G++jfoa5cBsWegfz4H+i/fQBs5HtrAkRd0RdOlRbN02Tt1DPD0huGRF6AFBNfVj4vsmENw0bIGWcpKRERkw2TOJvWhZGmeLMMz13yS5XU//PCDup+Xl6eKi0sNJ8lKGj9+PB544AEVrJoxY4YKKh09elTVl2rUqJF6jxQoHzNmjCqcLksCpVi5BJRked/bb7+tAk0333wzXn/9ddWJLzg4GJ9++qk61pdffqmCU4cOHVIBJzmOBKXMywFLdgOU40rG1HvvvYewsLC6+znp5pBbA5SQkKD+D1AX/+eT9Zqy1rMB/3htEs+d7eK5s10N/dzpu7bC+MErKkvJ8OhL0Np2Nj0fcwb6isWmjKmiopRqSZ0Ep7qXXlInQSHs2QajBKL27gAKS6SEt+loynLq0kdlQdWkTpRkP+nrl0P/82cgLcX0pKc3tMuvhjZsDAweXggJCMDZZx6Avnc74OYOw6MvQwtvCXsiHWgCAwMtPYwGMX8KMOYh9q7rVSFbw9wf6q3IKl2ahv7fcVvH82e7GsK5S0tLg7e3fZYCkPlFftHvUyloLvWezEvy5L65dtT27duxdOlSFbCSrCVzMMtZLjaWIc/LVtHSvpIky8rPz6/OzlF150/MlCIiIrIQPSUZxi/nqvsqC6koIKUeh4ZBu+0h6ONuhv7nUugbV5iW1M2XJXVNTEvqfANURpS+czOQk33+wGHNTYGo3oNNGVEXSXNzV5+jjxgHfdNq6Ct+UvWi9KVfQ/9jMfQho5GUmWYKSDk7w3D/M3YXkKL65RgUalpGmptjKrzv5WPpIREREdU5KWRekhQYN2cv9erVS20llReQMj9f0Wtl1UZAqjYwKEVERGQBckXT+PkcICMdaBoB7dpbyt1PgkraTdOgX3Uj9NW/Fi2pOwv983dR6pqoLMPrOxha36HQmlTcbvhiaE7O0IaOhj5oJPTtf0Ffvgg4e0oFqVQozMERhnv+B63N+ZbDRBf7/zVZRqqK8ssSPgaliIiI7JqjtRQAk3WPsbGxGD58uFq3WFm69vvvv4/169df8LysdQwKCqrj0RIREV06fc0yYP8uwMkZhmmPQXN0qnR/zcsH2rWToV95HfQNf6iaT8jPhdZzgApEoWW7anfJu1iag4PKwNJ7D1LLBI3LF0E7Ewnt9oehdTKlkxNdssBgFZSSYudai7aWHg0RERHZc1BK1lBKAa6uXbvioYceUu0H161bV1wRvjx33nmnKhRmJlXjP//8cwQEBNTTqImIiC6efvY09EWfqfvaDbdDC21asyV1V14HyGYhKvjVtTccu/VBSHAwYuPi7LaWBdU/KZKvH9nPYudEREQNQN1eUq2GXbt2qaJeU6ZMUa0HJ02ahDVr1lT6Hml16OHhUbxJa8UbbrhBrbskIiKyZnp+PowLZgMF+UCnntCGjoEtq+vsLGp4tMAQ052keEsPhYiIiOw9U+rUqVNo06aNCjSJ8PBwnDlzptrvP3bsGOLj49G/f/9Ks7FKdomRpYHSOtF8v7aZj8mOMbaH58528dzZroZ27ow/fw2ciVRd7Bxuf8imgzoN7dxRPQkIVjc6M6WIiMjOSFxCutKVx2g0NshEG4sHpbKzs0u1CZSJrZyIjIyMarUx/OOPPzBy5MhKT96SJUuwaNGi4scRERFqyWBdt3eWzC+yTTx3tovnznY1hHOXs3sbElYuVfcDZjwHt3YdYA8awrmj+qMFFP3/iUEpIiKyMRJYKigoKLcDXkJCAvr164eXXnpJrRArm2zz4IMP4vvvv4e3tzdyc3Ph4OAAR8fSIZvCwkIV2HJ1dS1+bty4cbjvvvswatQo9b4WLVqgbdvzNRllZVrr1q3x1VdfVThuKcPQo0cPLFy4UO3boIJSEkwqGymUE5iXl1fleyVwtW3btlL1pcozfvx4jB07tvix+Yqu/J9C/g9T2+T4MkGXwu2ssWFbeO5sF8+d7Woo507PzEDhm8/Ib31og69ESngbpMTEwJY1lHMnE8K6vpBFJZiX70mx84ICaGUm5ERERNZqx44dqga2rASTAJXYvn27upU62Jdddhk+/PBDXHvttaXiIC1atFA1su+//358+eWXKtB04sQJtY/ERiQYJau9JH4hcy4JYpkzq+SzZJN95FbmZytXriwOaG3evBmffvrpBWPdtGmTajgnwSp5T3JyMry8vFDfLP5bXrKhoqKiLsieKhsRLM/ff/+N9u3bV5lRJSeyohS5upxEy7HteZJuz3jubBfPne2y53OnvttX75va3Ac1hnbjVLv6rvZ87sgCfHxVV0rk55n+zZiDVERERFaud+/emDFjBnr27KkCRI899ph6/vTp0yoLSVZ6SdBp+vTpqsmboWjFl9y+8847WLt2rXosQSWz+fPn49ChQ+r1kp566im1Ikyyo3bu3IlevXrh66+/VnMyCW6Zk3ESExNLZVaZ/fTTT+jevXvxfjKGkvvJcctLIrK7oFSrVq2wevXq4sdSH0rS0aqzdG/Lli2V1pIiIiKyBvrWddC3/yW/7WG481FoLhdODIjIRE2Opa5UTBSQGMegFBER2ZQ///wT7dq1Q1paGoKCgpCZmYl7770X//vf/+Dv74+HH34YL7/8MkaMGIGZM2eqckSSlOPn54frr7++2p/z6quvqm3ChAlq+d6wYcNU9tSKFSsu2LdsfEWysJYuXaqyryQ4JiQja8CAAcVBKglKPf/887jllltg10EpyXSSzCiJCMoPUaJ1nTt3VhE5OXnyQyqvXpT8wA4cOIBp06ZZZNxERETVIcWa9W/nq/vauEnQIup3nT6RTSoKSsm/H619V0uPhoiIrIBkAOUWWiYz28VBq3ZjF1lGJ0Gg48ePq+X/Tz75JBo3bqwCUBKYkuNIIs6sWbMwZ84cxMTEYM+ePWppnizru+KKK1RAyNwUrrzjS72p8sobzZ07V2VilUeyqjp27Kg+W7K5JJD1yCOPqNfks6XpnGRcmZvQ1ReLB6Xkhympa3IyJNVMTpBE48Ttt9+ON954A82bN7/gfYcPH4aHhweCg00dWoiIyDaoZV7pKUBSApCcAD05Een+/tC79VeZRPZCz8sFIo/A+NOXQE420Ko9tDETLD0sIpugBQRD/dmRyGLnRERkIgGpiT8cschn/zCxDVwdqxeUkoCSLHmTGtaSKWVeSifZUBKokuCPZDRJEOmWW24pDnZJBpW5tNHZs2dVbez9+/erx5LVJBlQkpwjBc3ff/999Xx0dDTOnTuHZ599VtWr8vHxUTWtHn30UcTFxcHX11fV7O7bt29x8XUpfH7dddeVyoBKSUlRYy4bkJIAmCgvCGY3QSkhax8loicpZFLp3VxcS9ZcVkSyqT7++ON6HCUREdUoIHP8EPTkBCApvjj4ZLqfCBTkl9o/Rf4IHT0Bhuv+A1ulZ6QBxw5CP3YA+tEDwKnjQGFRMw1XNxjumAHNUHe/0InsinnJXmK8pUdCRERUIzk5Obj66quLm6o1adIEy5YtU0v27rnnHhX7kKLikjW1Zs2aUhlY5tracluylpNkUJVXU0q69UnA6PHHH8fUqVPxyiuvFL8unyXjMDeGM3/O77//rhKBJAHI/JxkT8kmXfvMnysXkmVV22uvvYYbb7zRvoNSolGjRqoFIRER2X5AyvjKY8DZUxXvJL8AffwA/0Bont7Qd/8Dffki6C3aQuvWF7ZAT4o3BZ+OShBqv6n+TVk+ftBad4B2+dXQWBeHqMaZUrJ8j4iIyLyETjKWLPXZ1bV8+fLi+w8++KAqSSTBHqmJLeWLJBlHluaNHTu23FJFojpLBSdOnKiW3919992qe58wd/wTUg5JluuVzXqaNGmS2kp66KGH8NdffyEiIgI//vhjtZcq2lVQioiI7IO+fLEpIOXmAbRoA80vEPAPAvwCTff9AgBff2iOpqsw8kvP9ZdvkPHL9zB++g4Mz7xtFQEcPTurRJaXaakhkhKhJ8cDCXFAavKFbwoJU0EotOpgug0Irtdf6kR2I7CoPIMUOiciIjLPGau5hM5SYmNjcfToUdVtT5bnyVI5WVIny+ckWCXBqcjISPz7779qmV1ZsuTviy++wPDhw1GVLl26XPCcZE3JEjzJcJLAlwTBRGhoaKmAVUmbNm3CqlWrVMc/GdMLL7yAZ555psKAWW1jUIqIiGqNHh8N/Y/F6r5hyv3Qeg6o1vsa3fEQMvb/q5b8Gee/BsMTb0CTlvD1RE9Phf7HT9Al20kFoBKB7MzK3yRr65u1NGVCtZJAVHtoXj71NWQi+y90LjLSoOdkQXN1t/SIiIiIqiQN3F588UVV32n06NEqW8nb21sVOv/ggw/w2GOPqeDap59+it69e1/w/nnz5mHQoEHVCkqVR5YEClnGJ530fvnlF8THx6tlfq6uruWOVwqev/vuu2qZoXTimzx5Mm666SY8/fTT5Qa+ahuDUkREVCtk3bnxu49N9aI6dAd69K/2ezUnJzjc/TgKX3gIOH0C+ncfQfvP/agPem4OjHNmAaeOXfiip5fK8FJZXirbK6Ao2ysQaBIOzeXCX+5EdOlUEMrTWwWlVLZUWISlh0RERFQlKSA+YcKE4rpMEuSRTnySLSXd7yQgJVlS7dq1U/vk5OQU15FKTExU+7300kvF9ajKI7WfJCNKipNLtzzJiDIXKD9w4IAKMO3btw+LFy9Gamqqqgk1dOhQvPrqqxg2bJja78iRIyoAJtlR0nTu8ssvV8+HhIRgyZIlKrB21VVXoWfPnrj33nsxcuTIOvuZMShFRES1Y9dWYN8OqcwIw81313jZmuYXAMO0R2F853noG1fC2LI9DANGoC7pRiOMn75tCkh5ekO7drIp+OQfCPgGQHN1q9PPJ6IqsqUkKCXLZRmUIiIiG2AODn3++eequLkEf2JiYnDDDTdcsBxOspBuvfVWzJgxQ3XKk5pTktEkNaLkfRJ4Mi+/E3JfLgJLB75vvvlGvV+KlUtAqXv37nj77bdVoOnmm2/G66+/rgJcwcHBKitLAlRffvmlCk4dOnRIBZzGjBmjglKSIVWSNJ6T40rG1HvvvYewsLA6/ZkxKEVERLWTbfSDqSOqNvI6aMGNL+o4Wofu0K6eBP3nb6F/Mw96sxbQmtbdH6P60q+AnVtMgbT7njQtwyMiqyC15fSTR1Wxc+uuIEJERFSaZBjJBVrJTmrVqhV27dp1wT6SKZWfb+pILcGjFStWqH1/++23an+OBJXMZBnetGnTVGZWWddff73azMGt7du3w8/Pr9JjS9Dro48+Ql2rn8pVRERk1/RlC011mPyDoI254ZKOpY25EejUE8jPU/Wl9KwqajtdJOOmVaai7PKZUx5kQIrIWutKsdg5ERHZmM6dO2PKlCkqyFRdrWqwb3mcnZ3LDUiVp6qAVH1iUIqIiC6JHnMG+sql6r7hpmnQitKWL5ZmMMAwdYapblN8DIyfzVGpyrVJP7wP+lcfmD5v7EQY+g2t1eMTUe0FpXQGpYiIiOwWg1JERHSJxc0/BAoLgM69gK59auW4mqc3DNOfUMvq8O/W4qBXbdDjomGc96oas9ZrILRxk2rt2ERUu8v3FAaliIiI7BaDUkREdNH07ZuAg7sBJ2cYJt1V4+LmldEiWkObeKfpc376AvqRfZd8TD0zHca5LwKZ6UBEG2i3P6Qys4jIupfv1Xa2JBEREdWOS/0dzZk4ERFdFD0nC/rCBeq+NnrC+ayGWqQNGQ2tzxBAuuR99Cb01HMXfSy9IB/Gea8BcWfV0kDDfU9Bc760pYZEVId8AwAJGufnAZfwb5+IiGyXXPCUbnNkncGozMxMOMrKhkvA7ntERHRR9F+/B1KSgcAQaKOuq5PPUJlX/7kPetQJICZKBaYMj7wIzcGhZmPVdejfzAcO7wVc3GB44GloPr51MmYiqh2aTHKltpws30uMBRpZT1FWIiKqH1K4OyMjAzk5ObA3Upg8z8YDbi4uLmq7FAxKERFRjelnT0Ff9Yu6b5h0NzQn5zr7LM3FFYZ7/gfjy48CR/ZBX/o1tOun1OgYUpNK/+tPqaIOw90zoYVF1Nl4ieqTXKGMjo5GaGhotTvu2NwSPlm+lxDHDplERA2QXKD08vKCPX4v+d0dExPT4JeoMyhFREQ1L27+7Xy1pA7d+0Hr3LPOP1MLDYM25QHoH70B/Y/FKNz9D7TWHYBWHUy3/kEV1rPSd22Fvvhz03EmToUmBdmJ7MCWLVvw4Ycfwt/fH/Hx8bj33ntx2WWXVfqe119/HTt27CjVsvqZZ56BtZJlwfqhPSx2TkREZKcYlCIiohrR/14HHNkvOccwTJxWb59r6D0QxuhT0H/7QS3l02OigA0roK4tNfI3BadaFwWpGoerAub66eMwLpgtkTRoQ0dDGz623sZLVJeysrKwYMECzJo1C+Hh4Vi3bh2+/vrrKoNSJ06cwP/93/+pQJZwqOFS2HrnH2S6TYi19EiIiIioDjAoRUTUgOm7/4GelwetdXtojfyr3j8rE/qPn6n72lUTofkHoj4ZrrkFugSWjh+EfvSA2nD6OJCSBH3bRmDbRlOQys0DaNUekFpUeblAh+7Qbqrd7oBElg5K3XbbbSogJSIiIpCenl7pe5KTk1WmY7NmzWAzihoo6EnMlCIiIrJHDEoRETVAqvD3kq+gL19keiz/ExBcYklcRyCkyQVBHP2Xb4G0FNNrI6+1yNg1Lx+gWz9o3fqZxpSbA0QeMQWpjh0Ajh8CsjOBvdtNbwhtaqojZe0ZIUQ1EBAQgEGDBqn7BQUFWLZsGfr06VPpe44dOwaj0Yjp06erWlQ9e/bEnXfeadW1qLSAYNN/nxIYlCIiIrJHDEoRETUwutEI/fuPoK/93fREaFMg9qypmLDUbdmy1vRHoKd3cc0mFazSNOhrlqm3GG6eDs3RCdZACqGjXRdo7bqox3phIXAmEvrR/UB8LLQrr4Pmbr1/dBNdipMnT+KFF15Q7ZjffvvtSvc9e/asyqy69dZbYTAYMH/+fHz77be46667yt0/Pz9fbWYSpHZzcyu+X9vMxyx17KBQ021KkkTfoDlZx393qBrnjmwGz5/t4rmzXTx352l6Ay71npCQUGqyVVtYSd928dzZLp676pGAjf7FXOhb1qggk3bzdBiGjoaenaUyjCTTSD92EDhxGMgvv0Wt1nsQDHfNrLUx8dzZroZy7pycnBAYWL9LVatLfu6RkZH44osv4O3tjUcffbTa7z1w4ABmz56NTz75pNzXFy5ciEWLTNmU5iWCUii9vr/f2RuGqP9GhXy0GE5NTMsViYiIyD4wU4qIqIHQ8/NNRb93bgYMBmi3PwxDv6HqNc3NHejUA1qnHqZ9C/KBU8dNQSqp2ySBqsx0wN0D2g13WPibEFHJwGCLFi1w33334YEHHlDL8jw8PKr1Xh8fH1WHSi7QSeCtrPHjx2Ps2PPNAcxXc+WiniwZrG1y/JCQEMTGxpYKcup+QcDZk4g/sBcGg3Otfy7V3bkj28DzZ7t47mxXQzh3jo6O1bqox6AUEVEDoOfmwjjvFWD/LvkNAcPd/y2uyVQetTSvZTtoLdsBV16nlvwh7izg5l6tguhEVLcky2nHjh1qKZ554lfVMgBZ3jd69Gi0a9dOPT5y5IgKTJUXkBLyfEWv1eUEWtW8K3n8wGAVlNIT7Hfibi8uOHdkU3j+bBfPne3See4YlCIisnfSMc/43ouAZDw5u8Bw31PQOnSr0TE0g8FUe4qIrIIsm1y1apW67datG77//nt07doV7u7uqjOfs7NzcaDKTLruyTK/KVOmIC0tTdWTGjlyJKwdi50TERHZL4OlB0BERHVHT0+D8a1nTAEpNw8YZrxQ44AUEVkfX19fVT/q999/V7d5eXm4//771WszZ87Ezp07L3jPNddcowJTL7/8MhYsWIArr7wS1113HaxeQIi6UY0YiIiIyK4wU4qIyE7pKUkwvvUsEBOlOukZZsyC1qylpYdFRLWkS5cueOutty54/v333y93f8mcuueee9RmS4ozpRJjLT0UIiIiqmUMShER2SGpvWJ8+1kgIRZo5A/DIy9A4/I7IrJFUlNKcPkeERGR3eHyPSIiO6PHnIHxjf+ZAlKBITD891UGpIjIdvkXBaWyM6FnZlh6NERERFSLGJQiIrK3DKk3/wekJKnC5CogFWiqx0JEZIs0FxfAx9f0gEv4iIiI7AqDUkREdkIvLITx07eB9FSgaQQMM1+F1sjf0sMiIrp0AUXZUix2TkREZFcYlCIishP6H4uBYwcBVzcY7vkfNC9vSw+JiKjWip2bs0GJiIjIfjAoRURkB/TIo9B//U7d126eziV7RGRfzP9NY7FzIiIiu8Lue0RElTD++j30lUuAsAhordtDa90RaNkOmrsnrIWemwPjgtlAYSG0XgOh9Rtq6SEREdWuAFNQSufyPSIiIrvCoBQRUQX044dM2Ue6Dhw7AF225YsBTQOahENr1QFo3UHdan4Blhvnwk+A+GjANwDa5HuhyfiIiOxs+Z4ud1jonIiIyK4wKEVEVA49Px/GL+aqgJTWcwDQuSdwdD/0owdNAaAzJ6GfOQms+930h5J/ELTWRUGqbn2hefvWzzj//Rv6hhUqUGa4/SFoHtaTwUVEVGsCiwqdJyVANxZCMzhYekRERERUCxiUIiIqh/77QiAmCvDygTb5Hmie3sCAy02vpZ5TBcV1CVJJYfHTJ4CkeOhJ8cDWddC/ng+07wqt7xBoPfpBc3WvmzGmnjMFziSL4IprobXvWiefQ0RkcY38AAdHoLAAOJcM+AdaekRERERUCxiUIiIqQ4+KhL58kbpvuPluU0CqBM3HF+jZH1rP/qb9c7KAE4ehHz0Afd9O4ORR4MAu6LJ94wyta18VoELH7tAcnWpnjLoO4+fvAhlppnpX106uleMSEVkjlRnlH2TKVJW6UgxKERER2QUGpYiIStALC03ZR4WFQPd+gCzdq4LKhOrQHVqH7sA1t0CPi4b+zwbof68H4s5C37ZRbfDwUksBVYCqVXtohotvgKqv+x3YtwNwdILhzkehOdVOsIuIyGoFBKuglJ4YC61tJ0uPhoiIiOwlKHX69GnMmzcPsbGxGD58OCZPnlytQr1GoxHPPvss+vbti3HjxtXLWInIvul/LgVOHQPcPWC4efpFFQ3XghtDG3cT9LET1bEkOKWCUqnnoG/4Q23wC4TWdzC0QVdCM7c6r+4YY6Kg//iZ6bMm3AatSbMaj5GIyNZogUXFzhNY7JyIiMheXPxl+lqSn5+P119/HREREXj11Vdx5swZrFu3rlrv/fPPP5GVlYXRo0fX+TiJyP7psWeh//Kduq/dOBWa1DC5BBLQ0pq3hmHinTC88SkMM16A1n8E4OoGJCeoTn7Gp6fD+Mlb0M+eqt4YC/JhXDAbyM8zLQccdtUljZGIyGaYA/iyfI+IiIjsgsWDUrt27VKBpSlTpiAkJASTJk3CmjVrqnxfcnIyvvvuO9xxxx1wdLSKhC8ismG60Qjjl3NNwZ4O3UzBo1quh6J16KY65BlmfwnD9MfV58BohL51HYzPP4DC916CfvxQ5eP8+VtTYXVPLxhue+iSlgASEdkSTZbvyX8HGZQiIiKyGxaP5pw6dQpt2rSBi4uLehweHq6ypary+eefIzAwEImJiTh8+DDatm1baTaWbCWzF9zc3Irv1zbzMevi2FS3eO4a7rlTS+qOHgBcXOHwn/vrNNijubgCvQbC0Gsg9JPHYFy+CPrOzcDuf2Dc/Q+0tp2hjZmgalSV/D7GQ3uhr/hJ3Tf85wEYfP1hD/jvznbx3FG9CmCmFBERkb2xeFAqOztbBZfMZGJrMBiQkZEBT0/Pct9z5MgRbN26Fd27d0dcXBx++ukndO3aFVOnTi13/yVLlmDRIlMnLSFLBWXJYMnPrQuS+UW2ieeuYZ27gvhYxP70pbrf6Lb74dW5G+pNaChw2SDknzmJ9EVfIHPN79AP71WbU6v28L5hCtwuGwY9OwuxX8yRtnvwGHkN/K66DvaG/+5sF88d1YuiTClVny83F1rRBU0iIiKyXRYPSkkAyqlM1yhnZ2fk5eVV+J5Vq1ahdevWeOKJJ1QQa8SIEbjvvvtUbanGjRtfsP/48eMxduzY4sfmK7oJCQkoKCio1e9jPr5M0KVwu7RtJ9vBc9fwzp3sa5zzvAr6SEe89J6DkBETg3rn4AJMvAsOV4yHceVS6BtWIP/YQSS9+gQQ3ATw8QUS4oDAUORcfQtiLDHGOsJ/d7aroZw7KRNQ1xeyqGqah6dqQoGsTCApDmjMJg9ERES2zuJBKcmGioqKuiB7qrI6UVJPSrKkzMGlgIAAeHt7q0lxeUEpCXqVDXyZ1eUkWo5tz5N0e8Zz13DOnXHzGuj7dgKOTmpJHDTNsufeN0AVRtfH3Ah9za/Q1/wGxJ01bQYDDHc+opYY2uP/P/nvznbx3FG9LuE7fdwUpGdQioiIyOZZvEJuq1at1HI8s/j4eFX/qaKle8LPz69UJlVOTo5a7ifPExFVl552DvoPC9R9bdxN0ELDYC00L28YrrkFhtc/gTbhdiAsAtqku6C1qLh+HhGR3Ssudh5r6ZEQERGRPQSl2rdvrzKj1q5dqx5LfajOnTurZX2ZmZkwGo0XvGfgwIFYvXo19u7dq5bgLViwQGVISZF0IqLqMn77IZCVATSNgDZyPKyR5uoOw5Xj4fDcHBiGjrH0cIiILEoLLKorxWLnREREdsHiQSkHBwdMnz4dn376qSpUvn37dkyePFm9dvvtt+P06dMXvKdLly645ZZbVDDq4YcfVrVVHn30UXb/IaJqU93udmw2LYm77UFolSwZJiIiK8uUSmCmFBERkT2wir/CevXqhblz5+LEiROqgLmXl5d6fuHChRW+Z/jw4WojIqopPTMDxm/mq/vaqOuhNWtp6SEREVE1aAEhUNXLmClFRERkF6wiKCUaNWqEHj16WHoYRGTH9aNw9CD0YwdMhc3TUoCQMGhjJ1p6aEREVMNMKQlKSXF9ZskTERHZNqsJShER1RbVBSwhBvrRg8DR/dCPHgDio0vv5OwCw5QHoDk5W2qYRERUU/5BqksqcnOA9FTAu5GlR0RERESXgEEpIrILeuwZpG9bj8LtW1Q2FFLPld5B/ohp3Axa6w5Aqw7Q2nWB5uNrqeESEdFF0JycAF9/IDnRtISPQSkiIiKbxqAUEdks/VwS9G0boP+9ATh9HCklX5TC5c1bQ5MAlASiWraH5uFpucESEVHtLeFLTlTFzrUWbS09GiIiIroEDEoRkU3RszKg79wC/e/1wOG9slbP9IKDA1y69EJ+8zYqEwrNW0FzdrH0cImIqC6KnR/Zz2LnREREdoBBKSKyenp+HrB3O4wSiNqzHSjIP/9iq/bQ+gyBofdABLVph5iYGFNNKSIisvti50RERGTbGJQiIqulRx6BvmEF9B2bgezM8y+ENoXWdwi0PoOhBYaop9iBiYiogQg0BaV0BqWIiIhsHoNSRGR19IJ86Eu/hr5y6fnleb4B0PoMgtZ3KBDWnEEoIqKGvHxP7iTEWnooREREdIkYlCIiq6LHRMG4YDZw+oR6rLKhBl8JtO4IzWCw9PCIiMhalu9JsfOCAmjS2IKIiIhsEn+LE5FVkDpQ+vrl0H/8FMjLAzy9YPjPA9C697P00IiIyJr4+AJOzoDUGzyXCBQt4yYiIiLbw6AUEVmcnpYC4xdzgT3bTE906A7D7Q9Ca+Rv6aEREZGVUcu3JVsqJsq0hI9BKSIiIpvFoBQRXTI9P1/+SrioJRT63h0wfvYOkJ4KODpCu34KtOHjuFSPiIgqVhSU0hNjwQqDREREtotBKSK6aHpONvRlC6Gv+hmQIFJEW2itO6gNLdpCc3Wv+L15udAXfQ597TLTE03CYbjzEWhhEfX3BYiIyCZpjZtB37sd+vZNwOBRlh4OERERXSQGpYjo4uo//bNBBZWQknT+hcN7ocsm9yVI1bQFtFbtobXuCLRuD83b1/T+qEgYP/4/09IL+eNixDhThpTUCCEiIqqCNmwM9FW/AAd3Qz+0B1q7LpYeEhEREV0EBqWIqEb0M5EwfvcRcGS/6YnAEBhunAoEhUI/dgA4egD60QNAUjxw6hh02Vb/ato3qDG0phHQd/8NFBSoYrWG2x6C1qmHRb8TERHZFs0/CNrgkdDX/g7jz9/A0LazqdYUERER2RQGpYioWvTMDOg/fwN93XJANwLOztBG3wDtyvHFGU6ynMK8jEKXVt1H9wPHDppuo08D8dHQ46NNB+zaB4YpD0Dz8rHk1yIiIhuljbkB+l+r1O8Z7N8JdOpp6SERERFRDTEoRUSV0o1G6JtWQf/pSyAjzfRkz/4w3DAVmn9ghe/T/AKg9R0CyFYU1MLxg9AjjwKNm0LrNZBXtYmIqJSCQmO195UOrdrQ0dD//BnGpd/A0LEHf68QERHZGAaliKhC+onDMH77oVqGp4Q2hWHSXdDad63xsTQPT6BLb2hdetf+QImIyKYZdR0rj6Zg8c8n8OrlTRHgXr0pqjbqeugbVph+T8nS8G796nysREREVHvYc52ILqCnnYPx8zkwvjrTNNF3c4d241QYnp1zUQEpIiKiqqyPTEV8ei4+3h5X7fdo3o1Uswwh2VKS3UtERES2g0EpIiqmFxTAuOpnGJ++B/qm1eo5rf8IGF6aB8MV10BzZHIlERHVPoOm4Z6+IXAwaNgalY5/zqRX+73ayPGAmwdw9hT0HZvqdJxERERUuxiUIiJFP7gbxhcfhv7DJ0B2FhDeCoYn3oDh9oegeftaenhERGTnwhu54pZeTdX9j7bFIafAWO3l4drIa9R9/ZdvoRcW1uk4iYiIqPYwKEVUD4xLvkbhS49AT0mCtdGTEmCc/zqMbz1j6pDn6QXt1vtgePJNaC3bWXp4RERUhczMTBw9ehQZGRmwddP6RyDIwwkJWQX4YW9itd+njbga8PACYs9C/3t9nY6RiIiIag+DUkR1TN+5BfrvC1VtJn3ZQlgLPT8Pxt9+gPHZe0zLHTQDtGFjYHhpPgyDr4RmcLD0EImIqApbtmzBfffdh/nz5+Oee+5Rj6ty4MABzJgxA1OnTsVvv/0Ga+Lq5IC7ewer+z8fTMbJcznVep8mtQ9HXafu679+p5ajExERkfVjUIqoDklmlPGr984//utP6MkJlh2TrkPf/Q+Mz90P/edvgLw8oHUHGJ55G4abp0OTK81ERGT1srKysGDBAsyaNQuzZ89WQaavv/660vekpaXh9ddfx4ABA/DSSy9h48aN2LdvH6xJ7zAvXNbUE4U6MO+fONWZrzq0YVcB3o2AxDjom1fV+TiJiIjo0jEoRVRHpAOQ8bN3gYx0oFkLFfhBQQH05YstN6a4aBjffQHG914CEmKBRn7Q7nwUhpmvQmsaYbFxERHRxQWlbrvtNoSHh6vHERERSE+vvEC4BKH8/Pxw/fXXIzQ0FBMmTMCaNWtgbe7sFQxXRwMOJWZj1fHUar1Hc3GFNuYGdV//baHKCCYiIiLrxlZaRHVEX7sMOLALcHKG4c5HgbQUGP/vKeh/rYQ+egI0v4D6GYdMyvduh1FqbOzeBhQWAA6O0KSb3lU3QnN1q5dxEBFR7QoICMCgQYPU/YKCAixbtgx9+vSp9D2nTp1Cx44doWmaetyqVSt8++235e6bn5+vNjN5j5ub6XeG+f21yXxMuQ30cMYtXQPwyY54fLErHv2aesHHteppq2HIKBSuWAKcSwQ2roQ2Ylytj5MqP3dke3j+bBfPne3iuTuPQSmiOqBLW+pFn6v72g23QwttCsjWpiNwZD/0PxZBu3l63X2+sRA4vE8Ve5WaVsjOPP9ipx4wTJwGLaRJnX0+ERHVn5MnT+KFF16Ao6Mj3n777Sqzq8LCwoofS5ApOTm53H2XLFmCRYsWFT+WTCxZ+hcYGIi6FBISom7vDA7GxqgsHInPwPcH0/H8mA7Ven/GLdNw7r1XgeWLETzhPzC4utbpeOnCc0e2iefPdvHc2a4QnjsGpYhqm56fD+OC2UBBPtC5F7ShY4pfM4ybBOPsp6FvlGypG6D5+tfe50rNjdMnoP+9Dvq2jUBKiT8yfAOg9RkErc8QaLKUkIiI7IYs33v66afxxRdfqILnjz76aIX7Ojg4qOCVmbOzM/KktmA5xo8fj7FjxxY/Nl/NTUhIUJlZtU2OL5Pz2NhY0+806cbXIwD//SMDy/bH4rJQZ3QJ8ajyOHqn3kBAMIyJcYj57hMYigqgU90p79yR7eD5s108d7arIZw7R0fHal3IYlCKqJbpS78CzpwEvHxguO2B0imZbTubaksdPQD9j8XQJt116Z8XHwP9nw2mFtixZ86/4O4BrecAaH2HAK07QjOwhBwRkT2S3zMtWrRQXfgeeOABZGZmwsOj/OCNp6enKnZulp2dXSpIVZKTk5PaylOXE2jVkKPo+G38XTGqdSMsP5qCef/EYs6Y5nByqOL3mSxRH3cT9M/mwPjHImDIldBc3etsvFT+uSPbw/Nnu3jubJfOc8dC50S1ST+4G/rKpeq+YcoD0Lx9L/jDQbKl1L4bVqjufJfCuHIJjE/dbeqiJwEpJ2cViDLc+yQM//clDP+5H1rbzgxIERHZoQMHDuCrr74qfmwOLlVWn6Jly5Y4evRo8ePIyEhV+NyaTe4WCB9XB5xNy8OSg+UvNSxL6zsUCG6imo3oq36t8zESERHRxeFfqkS1RM9Mh/HTd9R9bfAoaF0rKDbbrgvQSjrx5UP/46eL/7wD/xbXrUL7rtBuewiG2V/CMP1xaN37Qavg6jYREdkH6Z63atUqtSUmJqqC5V27doW7u7uqHVXeErtevXrh0KFD2LNnj3r9l19+Ue+xZp7ODpjaI0jd/3FfEmLSq+6qpzk4QLu66CLQyqXQMzPqfJxERERUcwxKEdVW2uVXHwCS+RTcBNqNd1S4rylb6ibT+9b/cVHZUvq5JFPdKl2HNuByODzyIgwDRkBz4/IEIqKGwtfXV9WP+v3339Wt1Ia6//771WszZ87Ezp07L3iPt7c3pkyZgldffRXTpk1DdHQ0rrvO+msuDW7uja4h7sgr1DF/W1y1ljpovQYCTcJVsw9zFjMRERFZF9aUIqoF+pa10HdskgqyMNz5CDSXKjr9tO8KtGoPHDuosqW0m6ZV/7MKCmD88HUgPRVoGgHt5rsv/QsQEZFN6tKlC956660Lnn///fcrfM/IkSPRrVs3nD17Fu3bt4erDXSnkws603uH4MFlkfg3JhObTqdjYLh35e8xGGC45hYYP3gF+upfoF8+DpqXT72NmYiIiKrGTCmiS6QnxEL/7kN1Xxs3CVrz1lW+p1S2lKotVb0aGWr/xZ8Dxw8Bbh4wTH8CmrPLJYyeiIgaoqCgIHTv3t0mAlJmjb2dMaGjqWvtgu1xyMwrrPpN3foC4a2A3Bzof/5c94MkIiKiGmFQiugS6IWFMH76NpCTrTKftNHXV//N7bsBLdsB+XnQV1SvtpS+/S/oq35R9w13PAQtKPRih05ERGRzruvoh8ZeTjiXU4hvdidU7yLQmAnqvr55tfq9TURERNaDQSmiS6AvX6SW4MHVDYY7ZkAzOFT7vaU68anaUpVnS+mxZ2D8fK7pvVdeB61bv0scPRERkW1xdjDg7t4h6v7vR1KwPz6r6jd16QPIsr3Uc8C+C+tsERERUQMPSp0+fRr/+9//cPvtt6vWxtUpXvnYY4/hxhtvLN7mz59fL2MlMtMjj0D/9Tt1X7t5OrRA0yS5RjqUzJZaUvFn5ebAOO81IDcbaNMJ2vhbL2XoRERENqtbqAeGNPeGzBZfWHsG++IqD0xpjo7QLhum7hs3/VlPoyQiIiKbCErl5+fj9ddfR0REhOoEc+bMGaxbt67S9+Tm5iIuLg4LFizAZ599prY77qi42xlRbdONRhg/mwMYjaq7j9Zv6EUdR2VLjTV34lsOXa7iltfZ7+sPgOjTgI8vDHfNVK2uiYiIGqp7+oSgS7A7cgqMmLU2CjujMyrdX+t/uenOnm3Q01LqZ5BERERk/UGpXbt2ISsrS7UnDgkJwaRJk7BmzZpK3xMZGYlmzZqptsYeHh5qc3Z2rrcxE2HvDiAmShUb1ybfo4JLF61jdyCiTYW1pdTSvq3rAOkiJAEpH99LGzsREZGNc3My4JlhYejV2AN5hTpeXn8GW06nV7i/1qSZ6XdtYaHpdyoRERFZBYsHpU6dOoU2bdrAxcXUQSw8PFxlS1Xm2LFjSE5OxtSpU3Hbbbfh448/VhlXRPXF+OdSdasNvhKah9clHUtlS11tri21HHra+Wwp/eRR6D98bNrvuv9Aa9Ppkj6LiIjInupLPTE4DAOaeaHACLzx11msi0ytcH9toClbSv/rz2qViiAiIqK65wgLy87ORmBgYOk/0A0GZGRkwNPTs9z3REdHo23btqqWVGZmJt59910sW7YM1157bbn7S8CqZNBKPsPNza34fm0zH7Mujk11qzrnTj99HDi8F3BwgGHEuNo5z516mq7gSp2qFUtguHEq9Ix0GOe/DhQUQOveDwYpbs7/T1WI/+5sF8+d7eK5I0tzctDw6IDGcHWMxeoTqXhnc4xa0jeq9YVZxVqvQdB/WGDKdD551PR7l4iIiBp2UEoCUE5OTqWek6V4eXl5Fb7nrrvuKvV4woQJWL58eYVBqSVLlmDRokXFj6V+ldSxKhkMqwuyHJFsU2XnLunbeZCSqu6DroB/x8619pnZt92HxOceAtYvR9Ct05E8/30UJsXDMTQMwU+8CoPnpWVkNRT8d2e7eO5sF88dWZKDQcP9/ULg6mTAssPnMO+fOBWYura9f6n9NHcPaD0GQN+6Fvpfq6AxKEVERGR/QSlJh46JiUHjxo2rtb9kQ0VFRV2QPeXoWP2h+fj4qOV8FRk/fjzGjh1b/Nh8RTchIQEFBQWobXJ8maDHxsYyPdzGVHXu9HNJKFy/Qt3PHThS/X+9tuiNI4DmrdWSvejH7gDiogEnZ+h3/Rdx6RmAbFQh/ruzXTx3tquhnDuZk9T1hSy6NAZNw7SeQXBzNGDR/iR8tjMBOfk6Jnb2L5XJJ0v4VFBq2wboN06FVlQ+goiIiGwgKCUBnE2bNmHw4MEwGo1wKNEB7MiRI6r4uGQ+zZgxA19//fUFGVDladWqFVavXl38OD4+Xi21q2jpnnjqqafUZwQEBBR/dmWTRRlHRWOpy0m06ppmx5N0e1bRuTOu+VUVSUWbjkB4q1o/v1JbyvjuC6aAlEyeb5kOhDXn/49qgP/ubBfPne3iuSNrIMGnW7sFwtVRw9e7E/Hd3kRkFxhxW/fA84Gp1h2BwBAgIRb6rs3Q+g2z9LCJiIgatBoVOpdA1AcffKBqOj399NPIzc1Vz0uWkiyHW7FiRXHwp7qZTu3bt1eZUWvXrlWPf/rpJ3Tu3FkFt6RelHxmWU2bNlXFzY8ePYp169bh119/xRVXXFGTr0JUY3pOtuqEJwxXXFM3HyK1pZq3Vne1gVfAMKCohTURERFVyw2dAnBnzyB1f+nBZMzfFgdjUdBUMxig9R+h7ssSPiIiIrKhoJQEnKTekyyXk2wmKTAuQaP33nsPLVq0wLhx42pc9FSyraZPn45PP/1UddPbvn07Jk+erF67/fbbcfr06Qvec+utt6qg16xZs/Djjz+qx0OHDq3JVyGqMX3LGiArEwgKBbr0rpPPUIX+pz8BbcoD0G6eXiefQUREZO/GtfPDA/1CILPRP46mYM6WGBQaiwJT/YfLL1zVtERPiLX0UImIiBo0x5r+wezi4qKW1j3xxBOYM2eOypJq3ry5qtl07NgxtGlT86KRvXr1wty5c3HixAm0bt0aXl6mgs4LFy4sd38PDw/MnDmzxp9DdLF0YyH0Vb+o+9rlV0MznF+6Wts0/0CVJUVEREQX7/KWjeDiYMDbm6OxLjINp1JyMbVnEDoHBwIdugH7d0HfvBraNbdYeqhEREQNVo0ypcoGqF588UVV12ngwIF4+eWX8f7771/0QBo1aoQePXoUB6SoYdGzMmBc8hX044dglfZsA+JjAHfP4rR/IiIism6Dmnvjf4PD4OFkQOS5XDy9KgqvrD+D2N5XqtclKCUXnoiIiMjGglJSQ+q3335Ty/hee+01pKSk4Kabbqrd0VGDoX/zIfTff4TxrWegnz4Oa2P882d1qw25EpqLq6WHQ0RERNXUO8wT865ugdGtG8GgAX+fycCDp/3wWbvrkJGWCRzcY+khEhERNVjVDkrl5OTgr7/+Kn48YcIEtbxOOudJUGrIkCGIi4tTS/BEZGSkun/8+HEcOmSl2S9kFfTd26D/s970IC8XxrkvQU9JspquUPrJo8CR/VIADdqwsbU2LiIiIqofPq6OmN4nBHOuikCPUA8UGIFfQ/rhvr7/xbK/j6GgqN4UERERWWlNKQlALVu2TC2vW758OYYNG4YxY8bgs88+U0v5ZPndN998g++++07tLzWnSvrhhx9qf/Rk8/SsTBi//kDd14aMgi7Bn5goGN97GYaZr1xyVpJ+JhLGD14F/AJhuPdJaO4eNT/Gn0W1pHoPgubrf0njISIiqop0H5b6mVT7mvm44LnhTbEzOgOf/n0WUVke+BidsfzX47i9Vwh6NvaodrMeIiIiqsdMqSuvvFLVjCosLMQff/yB2bNnq+wTyZCSZXySDTV69Gh8+OGHan+5lW3evHmqSx9RefTFnwOSFRXUGNqNU2F44BnA0xs4dQzGT9+GbjRe/LFPHIbxzScB6axzeC+M770IPTe3ZsdIToC+w5QhqF1+zUWPhYiIqKy8vDzcf//9SExMLPX8Bx98gP/7v/+z2Lgagh6NPTHnmja4K2EDvPMycCajAC+uO4Pn10SpguhERERkZUGp4OBgVdTcwcFB1ZPy8/PD77//rmpKPfPMMzh8+LDqxCcZU0JuZZP95L1EZemH9kDfsELdN0y5H5qzC7TAEJXRBEdHYOcW6Eu/uuhjS30qZGUC4a0ANw/g6AEY578KvSC/+sdZswwoLATadoYW3vKixkJERGQOQskcSupwCplTJSQklMrMkSyp3bt3M1unHjgYNIzu0hjv//MGrkn5F44G4N/YLDz8eyTe2HgW/8ZkwngJy/+JiIiojgqdu7q64p577kHv3r0RHh6OoKAgTJw4EU2bNr2Yw1EDpOfmwPjle+q+NnQ0tDadil/TWneANuUB037LF8O4aVXNjr1nG4zvvgDk5gDtu8Lw2MswPPgM4OwM7NsJfcFb1eq0o+dknw+aXcEsKSIiujQGgwE7d+5EQUFBcVBKOMqFmCJSKkGy0q+//nqLjbMh0foOgQcKMOXfbzG3hyMua+oJKS+16XQ6nlsThXt+OYEf9yUiOdt0zoiIiMjCQSlj0XIqKWLu7++Pa6+9VqWZZ2Vl4YYbbqjl4ZG90n/+xrSszi8A2nVTLnjd0G8YtKtuNO371QfQD++r1nGN2zbC+MErQH4e0K2vWg6oubpBa9UBhnueBBwcoe/YBP3L96ssfq5vWg1kZ6qlhejc6yK/KREREUoFn5ycnMp9XTKoJAv9iiuuQPPmzet5dA2T5uEFrftl6n7IzjV4YnAY3h7dXHXqc3cyIDYjH1/vTsTUJcfw8voz2HYmA4Usik5ERGSZoJQEpHJzc5GdnY23335bdeQTo0aNwtKlS3Hs2LHaGxnZLan1pK/6Vd03TL4Pmpt7uftpV98MrecAoLAAxnmvQo+LrvS4xo0roX/8f2q5ndZnCAx3Pw7Nyfn88Tr1gGHaY4BmgL5pFfSFn1YYmJJMKn11UYHzK66GZriopEIiIqJqkeypOXPmqLIHN998s6WH06BoAy5Xt/rWddDz89DCz1V16vvsulZ46LJQtA90U9lT/5zJwEvrz2Da0uP4ZncC4jLyLD10IiIim2eoaS0EmTTJH/KdO3fGHXfcoZ5v0aKFuqr33nvvqX2EOTWdqCQ9Px/Gz9+VqA80yYbq3LPCfSUQpN3xMBDRBshMh3Hui9Az08vd17jqZ+iyHFDXoQ0eBW3qDGgllkMUH7Nn//NLA+U9v5XfFVL/9x9TJpdcQb1s+EV/XyIioqrExsbihRdeULdPP/20KpNA9ah9F5W5jawM0+//Iq6OBgxv4YPXRoZj7tgIXNPOF14uDkjKLsDCfUm4++cTaonfssPnsD8uCxm5VZcGICIiotIu/Ku9EjJJ+uEH0x/xd911V6nXpPbBiBEj1P3GjRsXL/MjKkn//UcgJgrw8oE2cWqV+0vxc8N9T8H4yqNA3FkY570Gw8OzigNOEiCVwJL+y7em/UeOhzbhtkoLxBoGjIAxJwv69x+r9xnd3GG4/OpS+xj/XGo63pBR0Fz4xwEREV2crVu34t9//4WXl1dxDSnpWizNYMzBp+eff17V6Xzsscfg7e1t4RE3PJrBAVr/Eab5xKY/gd4DL9inmY8L7ugZjFu7BWJrVAb+PJ6C3bFZqhi6bGb+7o5o3sgF4UWb3G/i7QInBxauJyIiuuSgVGVkYhUSEqLuy9I+orL0M5HQl/+o7htuvhuaZ/Um3pqPr6oNZXztCeDwXujfzgduvc90zEWfQV9ZFEC65hZVh6o6HYsMI8bBmJ0J/edvof+wAEZXNxgGXqFey5X6VUcPqPpT2rAxl/CNiYiooUtNTUV8fDySkpKKfz8dOnRIlUDIyMhQj+VCnizbK1nwnOqXOSiFA/9CT06A5hdY7n5ODgYMau6tttj0PKw7mYZjSdk4lZKL+MwCJGWZth3R5wNVEo8K8zEFqZp6OyPY0wkhXs4I9XRSmVfstEhERA3ZJc1+ZDIlE6jKJlGcYJHQCwth/HyuqveE7v0AqRVVA1pYBAx3PQbjey9D37gSCAoF4mNM9+X1iXdekO1U5TGvmghkZUL/U5b+vQ/dzR1ar4HIWFqUddVnELRG/jU6JhERUUlXXnml2sykW7FkRPn4+BQ/njp1KlasWIG///4bTz31FMLCwiw44oZJCwwB2nY2XfzavAba2IlVvkcCSzd1Dih+nJlXiNMpuTiZkquCVObbrHyjupWtLCmmroJUns4I9XIqdT/A3QkOBgasiIjIvl1SxEgmUdVpf/zggw/isstMnU2oYZL6TTh1DHD3gOHm6Rd1VVDr0hvajbdD/+ET6Iu/KHrSAO0/9xVnOdXoeDKGG+4AcrJVcMv48WwVpMr6a7Xp9cuvqfExiYiIaqpv374YPnw45s2bh2eeeQazZs1Cs2bNLD2sBkcbeDl0FZRaDX3MDTVucuLh7ID2Qe5qM5MyA4lZBTh5zhSUOpuepwqkx6bnq9pUErCKPJertrIcDUColzOaeDsjzFuWAToXb57OpqWgREREDS4odeDAAXTo0EHd9/DwwCuvvKLuP/7443j99dfx0UcfFdebknT0RYsWYeXKlQxKNWB67Fm1TE5oN06F1sjvoo+ljbgakOOt/wNwcIA29VEYyqn9UKPA1OR7gOws6Nv/glGKpcvz7bpAa9bioo9LRERUMrNc5kfXXXddpZnl999/P1577TW8+eabamPB8/qlde8P3e1DU6OTo/tNmVOXekxNQ6CHk9p6h3mWei23wIj4zHwVoIrNyENMRj7i0vMQK7cZ+cg36ohKzVMbYFrqadbI1aFUsKqxl2lZYJCnkyrQTkREZLdBKbl616tXL9x4440qC8pcR8p838XFpfg5cdNNN8HTs/QvYWo4dKMRxi/nAvl5QIduqmbDpVBBpJvuAsIioDWNgNayXa0UOMXUGdBzsoF9O0zPjbz2ko9LREQkEhISkJ6ejieeeEI9Pnr0qJpLlfc77u6778ajjz6K77//HrfddpsFRttwaS4u0HoPgr5hhbr4pdVCUKoyLo4GNPVxUVtZRsmwyizAmbRcnE3LK97OpOUhObsAKTmFSMnJxv747Ave6+PioIJTKkjlYboN9nRGsAqOOaq6WERERDYblHJ2dlYdY5588kk1efrggw/U83l5eer+qVOnip8zu/nmm+Hufj6VmRoOfcMfpqLhLq4w3HpfrRTzlM572tDRtTK+88d0gmH6E9C/nAs3Ly/kdupZq8cnIqKGKyIiAs8995wqeL5kyRLMnj1bddu744471OuFUm+xiBQ8l47G3377LcaMGYOgoCALjrzhka67Kii1fRP0qydBC7FMfS+DpqnAkmw9Gpd+LSu/8IJAlRRdj8vMR2aeEam5hWo7mpRzwXFlFubr5qi6BJo2J/iXeCx1rPzcHFXAjIiIyKqCUqdPn0aTJk1Uevm0adMwfvx4zJgxQ2VFyXp5c6aUXP0rmSmlPoTFzhskPSkB+iJT7Sdt/H+gBQTD2q+QGu6aCf/QUMTExKj/XxMREdUWCTBJJtTIkSMxf/585Ofnq+cLCgpK7Td06FAsXbpUBbEYlKpfWrOWQNc+wO5/VDc+7c5HYW3cnRzQ2t9NbWVl5BUiXpb/ZeabbjOkhtX5x7mFusq0ku1oUsWf4eVsgJ+7FFt3VNlWsvxQblUGlocTfFzZNZCIiGpHtaNFn332GdLS0oofBwQEqKV65voIv/32m7ovQanKaiZQw6AXFMD48ZtAbjbQsh20YWMsPSQiIiKryZySOpxSe/Oll16Cr69vqdel7MFbb70Fb29vi42xITOMmwSjBKX+2Qj9qonQQm2nG6IUQPf0c0ALvwvrkcnFNsmgSsjMR1JWQdFmKrienFWgCrInZ+cjp0BHep4R6XnldwwUzg7a+UBV0RLBNikaHPKy4OfqAD93RzhzmSAREdVmUEqu7EnK+bp16/Dpp5+qOgdZWVlqMiVycnLU/ZMnT+Kdd95REy7pJlM2a4oaBn3x58DxQ4CbBwx3zKhxBxsiIiJ7J1nmrVu3LrcwugStpHFMeHi4RcbWkGnhLYFufYF//zZlS02zvmypiyGZTY1cHdXW2r/8fSRwlZlvVEEqCVYlSoaVecsw3UqWVV6hXrx8sNi/CaWO5eXiUGppoL+bkwpWmZ+TpYIezgZmXBERNXDVDkpJcOmee+5RLYvfffddFXySYufmtHJJNZc09B49eiAlJQV79+7FDz/8oAJTEsDy8fGpy+9BVkS62OmrflH3DXc8BC0o1NJDIiIiC1t2+BwW7ktExyB3DInwRo9QTzg5NIw/RletWqVqcsof/DJX6tatGx566CE4OTkV/0EuWVPt27dXxdClyLks3ZManmQZhnE3wShBqW0boI+1rWypSyH/f1TZVs4OaNbowgLsosCoqwwrWRZoDlglZBYgJV9DTEqmysCSoFV6bqHaTlaQbSVcHDRV10qWCQZ4mAJX5oCVuvVwUksJGbgiIrJfNSr2JMv3jh07pq7evf322+jfv7+qF5Wbm6smViVJfYTExERVqFMCVAMHDqztsZMV0mPPwPj5XHVfu/I6aN36WXpIRERkYX8eS8FH2+PU/U2n09Xm6WzAgGbeGNLcG+2D3FRhZ3v18ccfo0OHDqqg+eHDh/Hee++peZJ02StJlutJDc/Vq1dj5syZvKBn6dpSxdlS30Ob9pilh2Q1HA2aqZufp3PxcxI0Ci2qySkB1ow8owpcSVaVWhaoMq9KLxuUJYJS4yo6PU9tFZGlgqGezmji44wmXs4Ik1tv0yb1tYiIqAEFpWS5nmQ/XXXVVXjmmWfUc3PnzsXmzZtL7Se/jCQlXbKknn32WXV1kOyfnpsD47zXTHWk2nSCNv5WSw+JiIgsbNOpNHzwT6y6P6p1I5UZseFUOs5lF2DFsRS1Bbo7YlBzU4Cque+FtXBsncyJpPteZmZmccc9IdnlZb3yyisqk6q818hS2VIbi7Klmlp6SDZBAlSydE+25qXLpZWSW2BUQauSNa4Si2pcSdBKglmpOYUq6+pUaq7aypJOgWFFASpTsMoFIZ6SeeXUYDIxiYgaVFDKwcFBpZ7HxsaWqhV17733YtCgQcWPJ06ciO+++652R0pWTf5/oX/9ARB9GvDxVV3sNAdevSIiash2nM3AW5ujYdSBka18ML13sPqDdUr3IOyLz8L6yDRsiUpHQlYBfjqQrLZwHxcMjjAFqKSQsj0pbwnSF198AS8vL4SFhaFly5ZqDlU2+5wsmS3VD/h3K/Rfv4d210xLD8muuDgaEOrlrLaK5BcaVXAqOi0PZ4pqWJ1Ny1X3U3IKizsJ7onLKvU+rShgJd0CSxZkNz12RKC7k/p8IiKysaCUyMvLU3UQ/Pz8VCZUUlISUlNTERcXpyZbEpwQUgtB7stzbGds//T1f0Dfuk4uB5sCUj6VXBojIiK7tz8uC69tPIsCIzAw3AvTe4cUB2UcDBq6hnio7e7ewdgenYENJ9Ow/Wymyob46t8EtV3ZqhHu6BkEVzv549E8RypJuhanp6erTTKpunTpgmnTpllkfFRRttRWU71MyZZq3MzSQ2pQnBzOB656Nin9WkZeYXGx9TOpuTibLrd5qsaVZFepjKvsAhxMyC732I1cHS4IWJnvy/NuTvbx3x0iIrsKSsmyPDc3N7zxxhs4dOgQtm3bpmojHDx4EN98801xJpXUmZoxY4baX5buyVVAsl/6yaPQf/hY3deu+w+0Np0sPSQiIrKgY0k5eHHdGfWHYa/GHpjRv7EKRJVHshWktpRsGbmF2ByVrgJUe+Oy1NI+uX1kQCha+7vBHjOlzF2MhTSRkTmTlEiQ5wMDA+t5hFSW1qwF0L0fsGurqRMfs6WshhRjbxvgpraS5G+R1NxC1S1QlgbGqULspu6BUpBdHucUGFWmlWxHk3LKPb4UWC+ZaSVLAiX7SjoIqls3R2ZbERHVd1BKCppL1xjJfJJt8ODBqpj5559/jl27duGBBx5Q2VMlSWCK7JeekQbj/Nelsr1KcddGjrf0kIiIyIJOp+bi+bVRyC4wolOQG/47qIkqjFwdni4OGNmqkdr2xGbinc0xqgDy4ytO4eYugRjfwa/C4JY1k7nQrFmzVKHzksxZ5SULnT/99NN44YUXVDF0eQ9ZnmHcJBh3FWVLXTURWhNmS1l78LeRq6Pa2pQJWAn5NyeF2M93DjQFrMyPZcvMM6pC7OnJuTieXHH3QA8nA3zNgSrX8wErCWSFN3JBsKeTXTdxICKq96BUs2bNVEZUSQEBAXjsscfwxx9/oEmTJuUW9yT7pBuNMH7yNpAUDwSGwHD7g2zZS0TUgMVl5OG51VGqDXxrf1c8NTTsojMJuoR4YM5VEapI+ubT6fhqdwJ2xmSorCtbqzUldaIkc1yCU1LE3Ewu5pXUunVrlSE1depU1X1Puhd37tzZAiOmkrSmEUCPy4CdW0yd+O7+r6WHRLVUiL2lX/mNFTLzCk3BKvOWYSrALl0EzXWsJBM0M9+IzHxTvavyuDpqaObjgua+LmjeyFUFqmSTzyYioousKSUTqgMHDqBdu3ZqmZ7ZqFGjSu0nGVX/93//h3vuuQeNGjWq6ceQDdB//xHYtwNwcoZh+hPQ3D0tPSQiIrIQ6Zb17Ooo9cdaUx9nPDus6SW3a5c/3P47sDHWnEjFR9vjsT8+Gw8ti8T0PiEY3NwbtuK66667YC4l3YtLdicuKCgovrAjFwFbtWqFTZs2MShlTbWlJCi1YxP0s6egNQm39JCoDnk4O6itom6gkm2VlW/qHijbuTIBq5j0PESl5iGnQMeRpBy1AanF7/d3d0TzogBVhK8r2ge62VywnYjIYkEpST1/8cUXMW/ePHh6eqoWx48//rgKPKWlpeH111/Hyy+/rDKk/v33Xy7fs1P6gX+h//Ktuq/dfLep5gIRETVIabkFeH5NFGIz8lU79lnDm8K7ljIBJFAzomUjdAhyx1ubotUfd7M3RWNHdIYqkn6pga/69MMPPyAyMhJPPPGEqtEpmeYyZ5Ks87ImTJiADh06WGScdCEtTLKl+gM7N5tqSzFbqkGT/y6ZA1dNfVzK3afQqKvlxyfP5eJUSi5OpphuJfMqKatAbTuiM4v3D3B3RIdAd7QPckOHQDd1XFtcrkxEVOdBKXN2lNzKduLEieIlevIf6KioKHXf/ByX79kfPTkRxo//Ty4TQRtwOQwDr7D0kIiIyEIyJCC1OgqnU/NULZUXRjSFv3vtX/GX7luvjgzHwn2J+HFfEtZFpuFAfDYe6R+K9kHusFZ79uwpnjudO3dO1eeUBjGSaeHv749FixapGp0lyf5t27aFi0v5f+yaScMZKYwu9T2bNm2quiOHhYVV+h65eLhjx47ix5KJJYXVqWqGcRNhlKAUs6WoGiSgJIEl2QaVeD4rv9AUpCoKVkmh9RPncpCYVYANp9LUZq5X1S7QTWVRSbCqlb8rC6sTkV2qUVDqzJkzxVfznJycigNO5smWPC4ZoCp5S/ZBLyiA8aM3gIw0oGmEypIiIrJ1EiCQOkhSaJtFaasvt8CI55fswbHkHLXUbtaIpgj2PL8krbZJwXQpeN49xANvbY5RGQdPrjqNGzr5Y2KnAKvMKpBSBhKIkvmR/P9MNilkbnb8+HGsX7++1Hsky1wCVlLsvKKLe7Gxsfjggw8wbdo0lVH16aef4sMPP1TZ7JWRi4kyJjm+kM7JVINsqZ79gR2bof/6PbTpj1t6SGSDJLuzvWREBZ4Ppks3wCOJ2TiQkI2DCdk4lJCt6lVJJpU5m0riUa383NA7zBOXNfVCE++6+28tEZFVBqXkSp9MYsx1EV577bXiiZJcdZP7MomSiRe7xdgf/exp6P+sh/73elNhczcPUx0p58qv4hIRWbPY9DxsOJmG9SfTVKHaIA9HDAr3xpAIH1Xrgy4kQRUJQq2PTMPGU2mqpbqbkwHPD2uqCvrWB8mMmnNVc3y0LQ5rI9Pww94k7I7JwstXNKt2p7/68sknn6gLeWLp0qVq+d6MGTPU46ysLBVUkoLn/fr1KxVwkqwnCSBJbanynD17Frfccgv69++vHo8cOVLNzSqTnJyszp/UrKKLYxh7E4w7irKlzpyEFtbc0kMiO+DqaFDNHWQzL/2TLKoDCVkqI1SCVVK36lBittq++jdB1e7rF+aFy5p5oYWvCxMBiMj+g1IrV67E5ZdfjmuuuQbfffcdwsPD1SRLip6b70tx82PHjqFFixZq0iOvkW0v09O3bYC+dT1wJvL8C27uMEx7FFpQqCWHR0R0UVJzCvDXqXQViDqcmF3qtfjMAiw+kKw2KUI7pLk3BjX3ZgFaANFpeVh/MlUF8aLT84uf93N3wmMDGqulJfWdbfBw/8bo2dgT8/6JRadgd6sLSAlzQMpczFzmSmbu7u6qccyvv/5aKigldToHDBgADw/TH6jl6dmzZ6nH0dHRCA2t/PeyzNHkAuL06dORmZmpjnHnnXeqGqFUPRKE0noOUEEp42/fw2H6E5YeEtkhyfps4eeqtrFtTRcDJDN0V0wmtkZlYE9spiqkHpWahB/3J6kLKn0lQNXUSy35s8asUSKiSw5KPfjgg6W6xNx0001qMvXbb78V35cJzsaNG3HrrbeqfZYtW1bdw5OV0DMzTFf/JCPq6H5VN0pxcAQ69YDWdyi0rr2ZIUVENiU734i/z6SrgIpM6o1F/2mTeXvnYHcVfJLgxv74LBWskiLaUpT25L8J+OLfBHQMcsOQ5j7o38yrQbXylivzkg0lPzepe2Lm7KCpK/RDIrwxpkcrJMTHqT+aLEGChlIY2MelxmUy651c3JOM8pKmTJkCb+/SnQRdXV3VvKu6JNgl87GxY8dWup9kV8mFRJmnSYb7/Pnz8e233+Kuu+4qd38JoJUMokkmhhRoN9+vbbZS+sFw9SQU7tiklvFBsqWaRlT5HvXv41wi4OEFzaV+A7j1wVbOna2Sn2uIlwtGy9bGDxl5hdh+NgNbo9Kx42yGuqDy6+FzavNxcUCfME/0a+qlMq+qU4eK58928dzZLp67i1y+J2nmcuWu7A+vsh8of8jWTy8sBHZtgVECUXt3AIUF519s0xFanyHQevaH5mk77beJiGT5gwSgJMj0d1Q6cgvPB01a+bmqgMrAcG9VnNtsQLi32qS+1JaodKyPTMW++GzsL9o+2h6LHo09MTjcGyFe1c+ekqWAzg4Gm6kTtem06bvvicsqFcDrHuqBwc291RV5WbInv+MdreB7BdRBYfW6IBlQZdXGUrqFCxeqoujDhw+vdL/x48erzWzy5MmYPXt2hUGpJUuWqELsZhEREapkQ2BgIOpSSEgIrFpoKBIHXo7sv1bBedVSBDz5RqmXdaMRBTFnkH/8EPKOmTa5b8xIg2PTCIS8+7XdXtyz+nNnR1qHA5OkHlV+If4+mYy1RxOw8Xiiygb+83iq2uT3TvcwH/Rt7o/LIvzQMsCj0r/NeP5sF8+d7QrhuYOmV/PS5jvvvIMtW7aoq3lpaWkqOCUFzqU4p/m+XKnbunUrBg4cqN4jr1122WUqw+ree++t8NinT5/GvHnzVA0FmVDJJKm6wSzJzpLaDC+99BKCgoJQEwkJCaWuANYWGbuk0MfExFjsynFNGL+ZD33d7+efaBJuyojqMxiaf91OPK2NrZ07Oo/nznbVxbmLz8jH25ujVR0OsxBPJxWIkqBKmHf1/yBMyMzHxpOmjkiR50pnuVRXoLsjZgxojI5W3CVOFBh1PPnnKRxOPJ8V1TbAVWWJDQj3QiNXxwb5706W4NV1IOZi7du3D2+++SZefvnlKjvvlZc5JXOob775ptQyw6oypWT+JHO+OskGCQlR80Fr//+TdN8rfP4BlVFuuP9pIDsL+unj0E8dB6JOqMcVMVw7GYaxE2FPbOnc2TP5b/j+uCx1UeWfM+mqo19JchFGLi50b+yBbqEe8C7KMOX5s108d7arIZw7R0fHas2fqp0p9fDDD+Pqq69WtaVkid6mTZvUkr2+ffuqiYl5ctKrVy/k5Jgms3369FGTmezs0jU7SpLX5apb165dVVHPzz77DOvWrcOwYcOqNa6vvvoKKSkp1f0aVIaengb9r5XqvnbFNdD6j2DRTiKyaesiU/Hhtjhk5RtV8djLW/qo5Xmt/V0vKntX6kld19FfbadTclXmlUz2pVtSdUgHpYSsAjy96jSu6+CPSV0CrLL2kfh+T6IKSEkr8mva+6kAXqgXOzxZq/j4eMyZMwdTp06tVkDq7bffxujRo1UdK3HkyBH4+PiUG5AS8nxFr9XlBNrcpdCqNW5mqi21/S8Y33vpwtcdnUxdipu1AJq1hBbeShVG1z+fA+PvPwKXDYPmZ52BTrs/d3bMQQO6hLir7a5eQaqBh2QM74rOxL74LCRnF2D1iVS1yW8hqQXYLcQDPZp4IiDQyPNnw3jubJfOc1f9oJSQAuZSHHPixImq2LlkQqWmpuLpp5+ucNJSlV27dqllgVJTQVLPJ02apDrVVCcoJYXUd+zYAS8vr4v6bAL0zaulGAUQ3gqGG6daejhERBdNamxIMErqH4l2AW54ZEAogj1rL6jSrJELbu0WqLbqysovxILt8eqPgEX7k7A7NhOP9G+MxlbWzvtAfBYWH0hS9+/rF4IBzbhk25rl5eWpbntyMVAuApovCMpcSi4GSpa6XKEsu1Twiy++UHMuyXqXelLStY8ujnb1zdD37wSkDEKzFtCatSwKQLUAQppCK/Pzl330v/4Ejh2AvuhzaHfNtNTQqQGQizBNfVzUdnU7P+QVGlUnPxWkislU3f2kVqBsUizdc/1ZdAl2Q8/GHiqbyt9GlkUTke276KqgUpNA2hDLVToJSMXFxSE4OLjGxzl16hTatGmjJlFCCnCeOXOmyvdJhtXHH3+M22+/XaWd00VGZTesUPe1wVdaejhERBdNCpS/vSlaZSRJEtLEzgG4oaO/VXQgki5xD14Wip5NPPDB37HqD4CHf4/Enb2CcUVLH6uovZiZV6iWO0r9qOEtfBiQsgG7d+9W8yXZVq9eXfz8e++9h1mzZqnAkwSrSpIOyjJvk6V+sgzvyiuvLFVjimpGCw2D4a2vVcE1zVB1AwT5t26YdBeMLz0CfdtG6ENGQ2vbqV7GSiT1pWTJnmy3A0jKysfu2CyVRbUrNhPpuQXYfDpdbSLC1wU9Qj1UE5C2gW5Wm+FLRA0wKCXBJ6nf1LRpU/z3v/9Vz0ltgSeeeEIt5xsyZAiGDh1a7fpOcjWv5DpD9QvbYEBGRkalLYql+KbUsZDAWFVBKXaPKZ9+aA8QHw24usHQd4jVj7c+2Mq5owvx3DXMcyf1M77bk4DF+5NUQEXqRj0yoIlqiW1tBob7oF2AO97ZEo09sVl4/+9Y1eXv/r6h8C5Tq6m+fbw9XnVvCvZ0wl29gqt9LvjvznJ69+6tCpyX5/333y/3ecmcuueee9RGteOCbKiq9peMqsEjoa//A8bvPoThmXegOTScjp5kPSQTSi5CyCa/P1M0D6zYc0r9XjqWlKNqKMq2+ECyWtLdVQWomEVFRLWvRr9J5Wrciy++qLqvSP0nMwkqyVW3zZs3q3pQP/30Ezp37oxRo0ahZ8+elR5TAlBll/5JyrmkpVc2jj///FPVoqoOdo8pX+IX70KqfXkMHwO/iBaWHo5VsfZzRxXjuWs45+70uSw889t+HIg1XdUd2ykEj41oAw9nywZ4KhMqAaCWTfHNtih8sPE4tkZl4FjyKTw3uj36RfhbZEwrD8VhbWSqyjB7+eouaNnEp8bH4L87ourTrp0MfdtfwNlT0NcvhzZ8rKWHRA2cZBV3CvWBvxao6h5KBz9Z4rdDsqhiJIuqsFQWlVwAauHnipZ+rqqbrdz3dmFwlYguTo1m7lK/qW3btqrouQSTSmrcuDEmTJiA66+/XhVBX7x4MRYsWICOHTvC1dW1wmNKNlRUVNQF2VNl6yCUXHL20UcfqbpWfn5+1Rq3pKaPHXv+F775im5D7h6jp55D4ea16n5Or8GqcxLZxrmj8vHcNZxzJ/usPJaCBdvjkFuow9PZgHv7hmJguDfSkhJgqihl3S5v6oSIUc3x1qaziErNwwOLdquaH//pHqiWWNQX6Sz4yooT6v4NnQIQZMhCTEzFXcMa6r+76naPIaoOzdPbFJj6dj70n7+B3nswNC8umSXr4ePqiKERPmorNOo4lpyDndEZKkglWVSxGflqMwepRJCHowpStSgRqCrbsZWIqDw1+i+F1CIwGo0XBKTKTlAHDhyoltUlJSVVGpASrVq1KlULQWodyFK7ipbuJSYm4tChQzh9+jS+/vrr4iDWzJkzMW3aNPXZZbF7zIWMm1YBhQVARBvVHcZax2kp1nzuqHI8d/Z97iSI8vH2OPx9JkM97hzsjof7hyLA3cnmznsLXxfMHtUcn+2Mx/KjKfjlULIqgj5B1cKq3jHCfVwQ5mOqyVhTRl3HO5ujkZlnVJ0Jb+zkf9E/Q/67I6oZbciVprqeZyKhL/0K2q33WXpIRBVmUbUNcFPbpC6ByMgtxPFzOTielGO6Tc5BTHq+WgIen5mBLVGm38/C390RXUPcVZ3CriEecJL2gEREZdQ4fF1ZQKrsftW5qti+fXsVVFq7dq3quGde+ifvz8zMVLWfSn6mZEdJEc+Snn32WZW91bx585p+nQZJNxqhb1yp7mtDRll6OERElZIJ8OaodKw/mYb9cVmQ0IejAbilayCube8Hgw3XM3JxNGB6nxBVSHbu1hjVDWn2puhqv1+W3EkQSwq717QI7c8Hk7E3LguujprqBsgitkT1Rwqjq6Lnb/5Pzcn0waOghbe09LCIquTp4qACTLKV7H4bWRSgOp6cq26j0/KQlFWANSfS1ObhbEDfME8GqIjoAhbPqXRwcMD06dMxZ84clfkkmVbPP/+8ek06673xxhulgk2yf9ki6vKcBKuqysqiIgd3AwmxgJsHtF6DLD0aIqILSOvqbWczsD4yTS0XkILmZh2D3DC1Z7BaJmAveod54t2rIvDV7gTEpFdcU7Gk3ALTkoqF+5Lwb0wmHhnQGKFeztV6r/zx8PXuBHVffpaNvav3PiKqPVqbjtD6DIb+zwZT0fPHX2fTALJJns4O6BzsoTazrPxCtdRv65kMtczvXDYDVERkpUEp0atXL8ydOxcnTpxA69at4eXlpZ6vqKtMdbvMUPmMG/5Qt1q/odBcLm7ZBxFRbZO6FXtiM7HhZBq2RKUjK99Yapna4AhvDAr3QrCnfQZQGrk54oF+Ugq9+jaeTMO8f2JxJCkHD/8eiWm9gjGihU+lf9jmFhhVNlaBEeqPgita1rywORHVDm3C7dB3/wMcPwR96zpolw2z9JCIaoW7kwO6hHiobWqPIBxKyMam02mmAFVOYZkAlRcGNPNigIqogbKKoJRo1KgRevToYelh2D09JRn49291n0v3iKiuRKXm4mCC9Pesmkw/kw9m4I8DMUjOPt98IsDdEYObe2NIc28097WfrKjaNKi5N9oFuqnaUPviszF3ayy2n83EvX1DKuyE9OW/Caq4uq+rA+7vG8LMDCIL0nz9oY25AfqSr6Av/hx6977QXN0tPSyiWq9L1THYXW2SnXthgCpVbV4uDup3vlxcifB14e8nogbCaoJSVD90KXBuNAIt20FrEm7p4RCRHZJi5I+vOIXMEplO1SWd9CSdXyal7YPcbLpeVH0J9HDCCyOaYcnBZHy7O0FlmR1OzFYF4EvW/BDSPem3w+fU/QcvC4U3OyMRWZx2xbWm+Vl8DPTfflDZU0QNKUD1V1GAKiWnUP2Okq15IxcMb+GDIRHe7OJHZOf4L7wB0Y2FJQqcj7b0cIjITpfgqY5u+UaEeDqhaTU6w0nYKbCRJ7oFOKJ7KFP3L3aSLwXPu4V4qKV50el5eHZ1lCoEP7lrAJwcDEjLKcC7W2LU/le19UWPxuV3uSWi+qU5OcEw8U4Y574IfdWv0AdeAS0kzNLDIqrXANWdPYNVfcTVJ1JVh92TKbn4dGc8vtgVj55NPFWAqldjT84RiOwQg1INyf5/gaR4wN0TWs/+lh4NEdkh6egmy8iko9vzw5tWq/C2pOeHhoYiJiYGun6+oDnVXCt/V7w9pjk+3RGPFcdSsPRgMnbHmoqgf/1vglom0dTHGVO6Vd0dl4jqj9alN9C5F7B3O4w/LIDhwee4dIkaXIBKgk+ySdfdjaek5lSqqpn4z5kMtXF5H5F9YlCqATGuX65utf7DoTmzwDkR1a4TyTn4Zo+po5tc8axuJziqXa6OBlVTqmdjD7z3dywiz+Xi4WWRKNQBRwPwSP/GcJE7RGRVVLbUgX+BfTsBKX7era+lh0RkEZ4uDhjdxldtUqNSglNrI9NUBz/z8r5gTycVmJJlfs0buaK5r4t6jsv+iWwPg1INhJ6cCOzZru5rg6+09HCIyM6U7OjWr6knLmdHN4vr29QLrQPc1JK9XTGZ6rlbugaihR+LxhNZIy24MbQrroH+x2IYF34CQ8fu0JwY3KeGTcoATOkehMldA0st74vLyFfb1qiM4n0lSzu8RJBKBax8XVQnQCKyXgxKNRD6X39KUSmgTUdooU0tPRwisjOf74rHmbQ8+Lo54r4+7OhmLfzcHPHssDCsPZGKtNxCXNPez9JDIqJKaFfdCH3rWiAhFvqKJdDGTrT0kIisbnlfZl4hjifnqExgqT11KiUHp1PykFOg43BijtpKkhqXbQPc1NY+0E0FruR4RGQdGJRqAPTCQlNQSmVJjbL0cIjIzmw/m4Hfj6So+w/2C2FHNysjSxlGtGxk6WEQUTVorm6q+56+YDb0n79B4cmjMIy5AVqLtpYeGpHV8HB2QJcQD7WVbLRyNj0PJ89JkCoXJ8/lIDIlF0lZBYjNyFfb+pNpxRlVrfzd0C7AtLUNcOXchciC+K+vIdi3AziXCHh6Q+vBAudENRGTnoed0ZkYGuGtJkGWIPUUJGW9sZczuoV61NrVPanNsDUqXdVguNhObCk5BZi71dTRbSw7uhERXTKtz2Dg6H7oG1ao2lJGqS/VvisMoycA7bowE5WoHDI3aubjoraS0nMLcSw5B4cTsnEoMRtHErNVh+B9cVlqM5M5VrtAV7QPdFedgAM9nCzwLYgaJgalGgDj+j/UrdZ/hGo7TETVcyYtF0+uPI3U3EIsPZiEGf0bo0OQe718dlJWPjacTFPbiXO5xc/7uDhgYLgXhkT4oI2/a43/OMnKL1T1F9ZHpmJPXBaMRc3upAaUFCd3c6p+AWzplPf+37FIySlEMx9n/Icd3YiILpn8d12bfC/0y6+Gvnwx9L/XAQd3w3hwN9CircqcQpfeDE4RVYN07JMgk2zCqOs4k5qnAlSHErJxODFblR+ITjdta06YsqmkHpU0DOnVxFMt++NyP6K6w6CUndOT4k2ZUixwTlQj8Rn5eHZ1lApIyTQkPrMAT606jQkd/TGxcwAc62BykpFXiC2n01V6uVy9K4oXwUEDOga5q3R0Gc+yIylqkxoJg5t7q/bIYWWuDJaUX2hU2V5y3G1nM5AnbdiKSOcaSXVfdTwV++OzVGe2NgFu1RrvymOpqkWz/CweGcCObkREtUkLCYN2+0PQr54EfcVP0Df+CZw4DON7LwFhzaHJsr6e/aEZWMSZqCZL2ps1clHbyFaNirOpJINKAlV7YrNwJClb1aqSbfGBZHg6G1RQSwJUPUI9uNSPqJbxX5Sd0zeulHQGU7p3cGNLD4fIJsiytmfXnFZ1CMK8nfH00DD8sDdRtSNeuC9JdTJ7dEBjhHpdelekvEKjqskkAaPtZzNRYE5dAtAh0E0FnQaEe8PbxUG9tjsmU2VPbT2TruojyHhka+nnovYdFO4Nf3cndSXwQHw21p9MxebT6cjIMxYfV76TBLJk/xAvZxUAe3tzNGLS8/H4ylOY1DkA13f0r/Sq4Nm0PHyyI07dv7VbACJ82dGNiKguaP5B0G6eDv2qidD//Bn6uuXAmZPQP3oTelBjaKOvh9ZvKDRHZsMTXWw2lbmI+i1doRqD7IzOwI7oTOyKzkB6nhEbT6WrTWZGbQJc0auxJ7qGeiDYwwnerg4q2EVEF0fTZf1FA5WQkID8/PxaP66kU4eGhiImJkYtb7EUvaAAxifuBFKTod31Xxh6D7TYWGyFtZw7sty5y8gtxJOrTquspCAPR7w6MhwB7qaJ/saTaZi3LRaZeUZVJHNar2CMaOFT4yUUUoxzX3wW1kemYUtUOrLyzweMwn1cMDhCgkteCPasOOiVU2BUWUqyDE+CZObkJxmJdJaJy8xXQTUz6Yo3uGjZXwtflwvGLFla8/+JVRMuc0Ds4f6h5Y5BgmNPrDyFo0k56BLsjlkjml7SZIz/7mxXQzl3Tk5OCAzk8tSGMn+ydnpmBvQ1v0Ff/SuQafpvNgJDYJjxArTAEIuMiefOtvH8VT5nkyyq7dGZ2BGdoTr+lSXX8Bq5Oqq5ll/R5uvmoB6XfE622l52y3NnuxrCuXOq5vyJmVL2bM82FZCClw+07n0tPRoiq5edb8QL66JUQMrX1QEvjGhWHJASg5p7o12gG97ZHI198dmYuzVWZTnd2zdUZTJVRn7ZHE/OVZlLEviRbCwzf3dHlbkkW/NqZhy5OhpUppNsaTkF2FS07O9gQjYOJGSrfdydDOjfzEsdV5b/VZb55OnsoLK/ejVJw/x/4tQxHv79JO7uHYyhET6l9pWsMQlIeTgb8FD/UF4dJCKqR5qHJ7RxN0G/4hroG/6AvnIpkBAL4+ynYfjvq9D8GEAlqi0yd2of5K62W7sFIjErHzvOmgJUstwvNadQ1edMzi5Q2/FKjiV1QVv5u6Kln6u6beXnqrLbiRo6BqXsmHFDUYHzgZczpZuoGsvoXtlwBocTc1TtgOeHNy13eZ50Y5Fg1dKDyfhmdwK2RGXgcGIkHrosVHXGK697nyy3k4CRLHkzk88wBYx80CHI7ZICO1LbYHQbX7XFZeSpZYByNa5nEw84OxhqdMVGAlCSafX25hgV4JJbSV+X4JQErg7EZ2HR/iS1/719QkoF7YiIqP5orm7QRo6H3mcIjG/+D4iPgXH2MzDMfAVaIz9LD4/ILsm858rWjdRmzh6XTsRysdG0FapbCVCdK3pe3c8uUHVBZU4lm5nM18wBKrX5u8KHNauogeH/4+2UnhALHPhX3dcGscA5UWVkQvF/f0Wr4paSgfTcsKaVZizJVTOpudQ1xANvbY5Wwabn1kTh2vZ+mNw1QLUa/utUmlqedyQpp/h9zg4aejfxVJlLPRp7wKkGAaPqkuV2V7V1vuRjvHx5MxV8+n5vogqqHYzPwvQ+IfhwW5y6IjgswhsDw71rbdxERHRxJABlePQlGN+QwFQ0jG8VBaa8Sme5ElHtk2YvEqiq6iKdXPyUxjLHknNwLMm0RaXlqoCVlGOQrWQGvYeTQc035aKlNLyR+3JrULcapLeMvCaf375JNsLcCtHa31VdQCSyNQxK2QG1BjUjDUhOAJISoCcnQN+7w1TgvEN3i9UXILIFUhB87pYY/H0mA04GDU8NaVLt7nNyNeut0c3x2c54/HE0RWVPSd0puTJmrlcuK+a6hHioQFS/pp5wd7KNyYJMfqTLoGR/vbUpWhVVf3HdGfVakIcT7uodbOkhEhFREVmyVxyYiomC8a1nYXjsJWgeXpYeGhGpC5MGNb8sOceU+qCRyTk4ag5UJeeoC51SE9SUk149UsJBSM59Ux9nVWqibYCbum3i5VzrdayIahuDUjZET0mGvn+XKfgkgaeiW7XlnV8WVJJh6Oh6HyeRLQV0P9oWh3Un09TVp/8OaqwCSDUhmVX39AlRmU/vbY1FUlGtKLlaJYEoySaSIpe2SiY1b49pjk92xGPV8VQVZJvRP9RmgmtERA2FXIRUgSlZyncmEsa3n4PhkRehudfs9xoR1Q+ZQ5rrVZll5hUiKjVPZVZJExsptF6o6zAaoW5Nj00XVQuNQG6hETHZBuw8naQuIJ5OzVPbymOp6nhezgY1l2sb6IZ2RYGqmpR2IKoPtvuXUgOjnzkJ45tPAlnnUzsv4OMH+AWYClz6BwFhzYFuLHBOVJGvdydi+dEUdWXp4f6N0Sfs4q8o9w3zQpur3LDtbAY6BbmjsfelLaGzJhKAeqBfKIZH+KigVMnJExERWQ8tpAkMj7wE4/89CZw6BuO7s2B4eJaqP0VE1s/D2UEFji6mg9u57HwcTshWBdgPJWSrzKv0PKPqHCibuQlOv6amJjidgytvgkNUXxiUsgG61Ad4+1lTQCqkCbTWHVXwCX6B0CT4JEGoRv7QnFhwmKi6Fu9PKi7YPb1PsOpid6kkI2pkK1PhS3vUMZjBKCIia6c1aQbDjBdgnP0UcPwQjO+9BMMDz0JzcbH00IioDjVydUTfpl5qE/mFOk6m5KgAlbk7sxRcX3MiVW3SaXpgUfdnKbLOZX4NR2ZeIeIz8xGXka9uR7f2hZMsG7EQBqWsnJ6cqOoCIC0FCIuA4bGXVStgIro40Wl5WHHMVP9JTOkWiFGtfS09LCIiolqjNWuhMqSk6DkO74Xxg1dguP9pXsAkakAkyNDa301t49qZlvxJcEoa8Ww+LTVQC/HroXNqa+zlpC7QSldoW8z2j8/IR1xmHlr5ucHNicsTs/IL1c9EAk4lg0+mn1M+MvOMpfaXRkzldR2vLwxKWTE9PdWUIZUUDwQ1hmHG8wxIEV0EuSq0sagbnqQym03o6I/rOvpbdGxERER1QYtoA8ODz8H4znPAgV0wfvg6DNMfh+bIwBRRQyTd+joGuattWq9g7IrJUB2WpdlPdHo+vt8rXZeTVF1UCVANaOYF/yq6Cloy6LI3Ngv/xmbi35gsRKeb6itLV8IOge7o3tgDPUI9EN7I5aIywCSAJ8c8kpiDUym5qnyFi4NBddJ2cTTAxVFTtblcHDQ4y+Oi5+V1qRUmgTE3R1MHxUtl1HXkFerIyCtEWk4hUnIKkJZbiNScQnVb+nGBus3KLx10Ko+3iwOCPZ1UAyNLY1DKSulZGaZJROwZtVRPFar0ZjYHUU1+WW05na5+2e6JyyrVDa9biAdGtPRRv2yJiIjslda6g8qQMs59Edj9D4wLZsMwbSY0BzarIGroWVRSS1U2mTP/cyZDXbyVIM/RpBy1SZObCF8X9GzsiZ6NPVTB9IsNskhzoZj0fBxOzFbBFT93R/i7OcHf3VGVv3Cs4rhS4F3G9G9MphqjHMc8txfydlm+mJxdoOb9sn2xKwF+bo6qGZEEqLqGesDTufz/9qXlFOBIUo46rtweTcq+IJvoYkiQys0cpHIymAJWRY9dZXM9h3PpmcgtMKpujLkFurqVQvc5Bbp6Plcq218ET2dDcdAp2NNZ3ZruOyHQw8mqMsoYlLJCem6uafJw+gTg5QPDjBeh+QdaelhEVi+vwIitUelYH5mqCo7LVQWztgHSDc8HA8K91C8tIiKihkBr3xWGe/8H4/svAzs2Qze8BVx9syqKTkQkDW2GRvioTbJuNp0yXdSVAE3kuVy1SR1WD2cDuod6qCCVBHoqm09LoEuyjI4kZqvjHE7KQXpuYbn7SjjKx9VBBaj8igJV/m6OKnAlc/ndsZkqKyqzTPaPLDnsGuKBbqEeqmi7FHGXwNeO6AzsisnE3rgsFaSS7tHmDtISWJMAVZsAN0Sl5qoAlIxROheWF1Bq6eeqNim3JMEhCRblFgWLZGy5RY+Ln1fBJCMKioYq++QVFiK1gu8OmLokVoeMwdvVET4uDvB2dSi6dUSj4seOxc9LoE+K5tsK/mVmZfT8fBjnvQIcOwi4eahClZw0UEMkV1S+/DdB/SKr1v4AzqQdVVc6zMK8nVXxRklBDrHgOmkiIiJL0jr1hOHu/8I4/3Xo2zaqDUGh0Lr0hta5F9CmI5f1EZEKNF3V1ldtqTkFKrizIzoTu6IzVCe/v06lq01IcfSeTUxBKsm6keCOFFWXYNTp1Fw1Ny9JsqEkwBPgbspoSsoqULcFRh0pallaIY4jt9LMny4hHiow1jXEXWX/lCX1sBp7+2FcOz8VOJLi7jujM7AzOhNn0vJUTS3ZytPE2xlt/F1VwKqNvxua+7pUmcFVkfxCI7LzjcguuPA2x/y4QIevtzfysjOKl/+5llgC6Fq0TFAtF3SQx5rdFqNnUMqK6IWFKq0a+3cBzi4wPPgstKYRlh4WkUUsP5qCnw6YipHXhKTpShBKtha+F7eOnIiIyN5o3fqpLnzGFT8BR/YD8THQV/2iNri4AR26FgepNJ+qS0boOVlAciKQnAD9XBLSHDQY/UOAFu1YUJ3IDvi4OhZnUJmXz0kWkmzHk3NVnVbZfthr6mZdliwVk5UKkp0kmywFdHIwXHARWuohmQNUcpuUnW96nFWg6ilJ92cpvaEylmoQJJJgjgSwZJvaE4jLyFNBNglQnUzJVRev2xSNrbWfKzxdai+zSL6nbJX19pa/UUJDQxETE6N+Dg0Zg1JWQjcaoX/1HrBzM+DoCMN9T0Fr1d7SwyKyCEmn/WxnvLo/vr0fWge4VvkeDRpahgUjUMtS6blERERUmtaxOxw6djcFlA7shr5nG/R9O4DUc8CurdBlkx3DW5mCU63aQ89IU4EnFXwqCkKpLSuz/EUozs5Aq47QOnRTSwcR1hyawXpqlxBRzUkwqF2gm9pu6RqomghJBpJkUUmdp3yjrgqkmwNQEuyRC8VVkcCMBL9ka1HH30Eyq0a1lo11mq0Ng1JWQCKj+sJPoG9aDRgMpgKUHbpZelhEFpFfqOOtTdFqDbZc2fhP90DVLaQqpqsNjRATk93grzYQERFVRnN1B3pcBq3HZerCKKJOQN+9Dfre7cDJo8CpY9Blq+pAbh6qIY/UPnX18kH23h1AWorq9qfLJvt4+UBr1wVo39UUqPIPqpfvSER1R2oWjWjZSG2SzSRT79roNEcNE4NSVkD/9Tvoq39V97UpD6oJAlFD9e2eBJw4lwsvFwc8eFlotQJSREREdHFUFpNkRoW3Aq6eBD31nMqe0vdsB6JPAT5+0PwCAN9AwD8Aml+g6b4Eo9zcTcfQNASEhiI6Ohr62VPQD/4L/cBu4Mg+ID3VVMNKalnJzkGNoclSwR79gbadmUVFZOPUXJ3TdboEDEpZmFHW8v/6vbqv3Xw3DP2HW3pIRBazNy4TS4rqSN3XN6Raab9ERERUe6SelDbgckC2mr5X/jhtEg6tSThw+TXQC/KBE0egH9ytAlWIPALER0OXbd1ywDcAWt8h0PoNg9akWZ18HyIism78i8+C9Ows6Is+V/e1ayfDMOwqSw+JyGIy8grxzuYYdRX18pY+uKypl6WHRERERJdAdfSTzn5tOgLX3Axd6lAd2WeqZbVjE3AuEfofi9WGZi1Mwak+g6tVaJ2IiOwDg1KWJGv2CwsA/yBoY26w9GiILOrDf+KQmFWAEE8n3Nkz2NLDISIiolqmuXsA3fpC69YX+qS7gD3bYdy6FpBaVKdPQJdt0WdAh+7Q+g1VHQM1FxdLD5uIiOoQg1IWpEtQSn5BR7Rh23pq0NZHpmLDqTTVNe+RAY3h5sT6EkRERPZMc3IGevaHQ8/+0NPToG/fCH3LWtMSP6lpJZurm6n2VPsu0MIigJAwaI7884WIyJ7wv+oWpJ84YroT0drSQyGymPiMfMzfFqfuT+wcoNrIEhERUcOheXlDkzIWw66CHnsW+t/roG9dByTGQd+8Gti82lQkXQJSoU1NAaqmEdDCmptuPb0t/RWIiOgiMShlSSdNQSktoq2lR0JkEYVGHe9siUZWvlEFo27o6G/pIREREZEFaSFNoF1zC/SrbwaOHVS1p/RTx4AzJ4GcbCAqEnpUJLAFpkCVaORfHKRShdOl0DoREdkEBqUsRD+XBKQkA9IGt1kLSw+HyCKWHEzG/vhsuDoa8Ej/UDjI+j0iIiJq8FRpi9YdoLXuoB7rRiOQFK+CUxKU0s9EmgJVCbFAisyrk6Dv3Q591S/QpjwAQ98hlv4KRERk70GpxMREpKamIjw8HI62tr5c1suLxuHQXFwtPRqienc8OQff7k5Q9+/qFYQQL2dLD4mIiIislCYXcgND1KZ171eqmzXOSqDqJPRdW4CDu6EvmA3j2VOqu7V6HxERWS2riOScPn0a8+bNQ2xsLIYPH47JkydXWfj7iy++wIYNG+Dp6YmcnBw8++yzaNKkCWyFXrx0j/WkqOHJLTBi9qZoFOrAZU29MLyFj6WHRERERDZIc3MHWnWA1qoD9CFXQl/yNfQ/FkNfvgh69GkYpj5i2oeIiKySxS8d5Ofn4/XXX0dERAReffVVnDlzBuvWrav0Pfv378fOnTsxd+5czJkzB127dsXSpUthS/RIU+c9RLSx9FCI6t1nO+NxNi0Pfm6OuLdvCLtPEhER0SXTDA4wXD8F2tRHAEcnYPc/ML46E3p8jKWHRkRE1hqU2rVrF7KysjBlyhSEhIRg0qRJWLNmTaXvcXJywt133w13d9NVj+bNmyM9PR22Qq2JP2kKSjFTihqa7WczsPxoirr/0GWh8HZxsPSQiIiIyI4Y+g2F4b+vAY38gJgoGF9+FPrB3ZYeFhERWePyvVOnTqFNmzZwcXFRj6U+lGRLVUb2N0tLS8PatWsxevToSrOxZDOTrAw3N1Pb+brI0DAfs8Jjx0Wbuoe4uKruIMwSsR5Vnju6wPGkbLy+8SxiM87/G6uOa9r5oXtjz1obB8+d7eK5s108d5a1bds2Vc5Aamw2bdoUDz30EMLCwip9z4EDB/Dxxx+r+dP48eMxduzYehsvUX2SC7+Gp2bD+MGrqpar8Z3noE28E9qwq/jfLCIiK2LxoFR2djYCAwOLH8svCYPBgIyMDFUvqjKrVq3C559/jvbt26taVBVZsmQJFi1aVPxYlgrKksGSn1sXJPOrPJn7tiMZgEvrDghqUvnkkSyjonNHpUUmZWLWumNIya5ZQKp9iBdmju4MF8faz5LiubNdPHe2i+eu/kkdzg8++ADTpk1Dhw4d8Omnn+LDDz/Eiy++WOF7JBAl859x48ZhwIABeOedd1S2eadOnep17ET1RWvkD8PMV6B/+R70reugf/eRqWPfzXdDk+V9RERkcRYPSkkASpbjleTs7Iy8vLwq3ztkyBD4+vpiwYIF+OOPPzBq1Khy9yt7JdB8dSQhIQEFBQWobXJ8maDLhFHX9QteL/z3H3Wb1yQcMTFc425Nqjp3dF5cRh6eWHkKKdkFaOXniv8NCYOTQ/WuPMqSveSE+FodD8+d7eK5s10N5dxJh9+6vpBVU2fPnsUtt9yC/v37q8cjR47Ea6+9Vul7Nm7cCD8/P1x//fXq3E2YMEGVTGBQiuyZ5uQM3DEDCGsOffEX0DeuhB5zBoZ7noDm3cjSwyMiavAsHpSSbKioqKgLsqdkAlgVCWb17NlTXflbvnx5hUEp2a9s4MusLifRcuzyjm8ucq41b23Xk3hbVtG5I5Pk7AI8s+o0krIK0NTHGc8NC4O3a83+c1JXP1+eO9vFc2e7eO7qn8x/SoqOjkZoaGiVJRM6duxYfHGuVatW+Pbbb22n/AFZLWs/d2pco66HsXE4jB+/CRw7oOpMGW5/SHXt0yr4O6GhsPbzRxXjubNdPHdWFJSSCdHq1auLH8fHx6sJUGVL937//Xd4e3tj4MCB6rEEsCTjyhbo+XnAmUjTA3beIxuUnluI51dHqRpSwZ5OmDW8aY0DUkREVHsk6/u3336rsj6UNJYpWXNKAkzJyVJQwDbKH5D1s/pzFzoO+e07IfHFR1AQHQXj7KcBJ2c4t2oHl/Zd4dy+C1zad4GDrz8aIqs/f1QhnjvbFcJzZ/mglNSDkswoKVY+bNgw/PTTT+jcubMKMmVmZqoJU9mAU1BQEObPn49GjRqpNPRffvlF1UawCadPAIWFgJcP4GddSwGIqpKVX4hZa6NwKjUXvm6OeGF4U/i7N+yri0RElrZw4ULVMKay+prCwcGhVCZ6VeUSrK38AVkvmzp3Tq7QH38D2vcfQ9+7HchIQ97BPWorFhgCrWU7aC3bQ2vVHmjSDJrBfrsF29T5o1J47mxXQzh3jtUsf2DxoJRMkKZPn445c+bg66+/Vifn+eefV6/dfvvteOONN1QRzpJ69eqFa6+9FnPnzlWTohEjRuDqq6+GLdBPHi3OkmKqHtmSvEIjXll/FkeTcuDl4qACUiFezpYeFhFRg7Zv3z6sWLECL7/8cpWlDyQLXUoeVLdcgrWVPyDrZzPnzt0DhjseNo01Pgb68YPA8UPQjx8Cok8DCbHQZdu6zrS/ixsQ3gJacBMgJAxaiNw2AfyDoTnYT7DKZs4fXYDnznbpPHeWD0qZg0wSYDpx4gRat24NLy+v4it/FZErdzbZxjjyiLrRuHSv3uQWGJGWW1itfSVQ6JtfvX3rilHXkVugw83JUCeZTm6OhhoHRAuMOt7YGI29cVnq/VJDqlkjl1ofHxERVZ+UPJCLelOnTi21LK8iLVu2xKZNm4ofR0ZGqoxzooZKzYeCG0MLbgz0H6Ge07MygBNHVIBKBatOHAFys4Ej+6Ef2W/ax3wACeoGhqoAlRYSZrpVgasm0DxMf88QEZENBKWELMXr0aMH7J3OoFS9kYjz2sg0fLw9Dln5xmq/z8XxBPo08cTg5l7oHupZ7Y5yl+rkuRysP5mGjSfTkJBVgLYBbhjS3BsDw73gcwk1m5Ky8rHhZJo6duS5XDT2csLg5t4Y0twHjb2rznQqNOqYszkG285mwNlBw9NDw9Da31ToloiILEOW3Um3Pbmw16dPH+Tk5KjnZRmfZEDJ0ryyWVCy7yeffII9e/agQ4cOqvxB165dLfQNiKyT5u4JdOoBrZPp7xLdWAicPQ397Ekg9iz02DPqVjKsILViY6LUZg5UFQes3D2AgBAgMBiaBK7kVj0OUSU87CnDiojILoJSDYGemW76BSaat7L0cOxaRm4h5m2LxV+n0tVjR4MGQzViS0bdlFm18VSa2rycDejfzBtDIrzRPtANhlpecpmQma+CRRI0OpWSW+q1w4nZaluwIw7dQz1UIKlvmFe1Mqgy8gqx+XS6Ovb+uKzzEyTp0JSej+/3Jqmttb9rUeDLW9WIKi+w99H2OGw4lQaJzT0+qAk6BbvXynf///buAzqqam0D8HsmvZIOCQESIDRBegldQURUigUBRUSxlwt21Htt2PWqiO2qV/RHVKyIcpUiiHRCLwIBEkIaaYQ0Qsqcf317mJBAIgkkM3Mm77PWWVMy5Uw2SQ7v+fa3iYjo/G3fvh3Jyclqq7xgzJw5c/Dss89iypQpKqyqTBaJkftfeukleHp6wsfHB/fcc48d9p7IOFQvqRbR0FpEV7lfN5uBnEwgPRm6hFRHJbBKUbeRmwMUFQJJB9V2VmAl/XKDw4CQptDCKldaRVoCK4Ms4EREVB8YStlSwql+UmERLOltQDuPFuKttWnIKipTQdTEi0NwbadguNQmlQKQa/LFd5sO4c/E4zhWXI7fDuSqLdTb1VJhFN0ErS5g6pqsXrcmKQ9/JORhT+aJivslOOsZ4aMCsLZBnlh/pECFSgdzirE5tVBtHi7pKpiSx3QL91HPqdzzKS7F8py4lEI15c6qU6iX2veeEb7YnVGkHrM9vVD1h5Ltv1sycHFTb/XZ+rXwhbebiwqkPt+WiV/jcyHvMqN/BHo1r3lVTCIisp3evXvX2Obg3XffrfF5I0aMQLdu3ZCSkqIWm5FwiojqTgVHIU0twVLnnlW+pp8sBrIygMw06FnpQOZR1aNKelUh6yhQVmq5Ln2r/tpueY71ye7uQFhzaOGW6YCWHlaRQNPm0DzYOoGInA9DKRvSE61T92LsvStOqbRcx5c7MvH9nhz1hz3czw0P9o9AuxCvOvUW6NTMH4G9muKW7qGqh5IEOOuS8tWUuu/25KgtKsBDhTwSDNV2dl9yXol6rS2pBSg7NZtQnnqRhEFR/ujfwg++HqdLucd0DFJbct5Jy/S7hDykF5SqqiXZ/D1cMKCln6pc2pJaiHVH8qtMU2zZxF1N0RsU5Yemvqen6YX5NsElrZsg90QZVp8Kx/ZnF2NbepHa3t+ooXdzXwR4uuCX/bnqOff0bYZBUf61/j4SEZHjklWMZSOihqF5eKoV+9SqfWd8TVVYHT9mCawyjwIZqacrrI6mytxcIDkBenLC6edUXhWweyy0vkMs1VtcNImInABDKRvSrZVS7CdV7yS4+feaVBzMsUyBG96mCab1bHpBzcKlskpCJ9nu6t20ogppc2oBEnNPInFbpqokOh/RgZZQa1Arf4T6VL+ykVWkvwcmXRyKiV1CVHgk+7D6cB6OF5fjf/G5arMK9nZVAZdsUs31dwcrAV6uuKp9kNrS8ksq+k6l5JVgTZJl2qOY2iMUI9oGnNfnJCIiIqIzKqwCg9Wmtetc5Wt6eTmQfRRIs/auSq64REG+pbJqyQ9qQ3gLFU5pfQZDkz5VREQGxVDKRtQyj2xy3iDf1yUHjqu+SyXluuoBdW/fcMS2rN/pkR6uJgxo5a82mX4nVUkS4CQfr9oH6u/4urugXws/FRidz8p1EjBJ83PZbusRpqbfyT4cyC5GpzBpit5EXZ5P36twP3fc0CUE4zsHq2Dvj8Tjqvrq0tZNMLZjcJ1fj4iIiIjqRjU/D4uwtPro2rvK1/T8PCB+N8wb/wC2b7I0V/9xntrQpoMloOo1EJpfE7vtPxHR+WAoZSvSCDH/OODiqspt6cIdLy7DuxvSsSG5QN2+uJk3pseGI9j77yuPLpSfh4uqHLJn9ZBUcfWI8FVbfZLgq22wp9puq9oegYiIiIjsRPPzB3rEwqVHLPSiQuhb10PfsBLYuxM4uBe6bF99BHTqDq3vYGjd+kHz5GrJROT4GErZiH7IUiWFyChobqf7+9D5kb5Ms9elqUbk0ux7crcQjO4QVO+r4xERERERORLN2wfagGHAgGHQc3Ogx/0Jff0fwOEDwK7N0GVzdQWCmwJBIdACQ9QlAkOgqctQy/1eXFGZiOyPoZStVDQ559S9+giknluRrJo+Rvq746EBEWgdxNWDiIiIiKhx0QKCoA0fAwwfoxqm6xv/gL7hDyAjDTiaorbT6zFXapouJJSSoCowBNmhYSjXXAAvH8DHB/D2VeGXXKLi0hfw9LL0xSIiqicMpWxEP9VPClx574Kn7EmFlPxBlUbh9/Vtpvo9ERERERE1Zlqz5tBGT4J+9UQg6yiQnQE9Jws4lgXkZEE/dvo6igqAE0XAiSToqUkoqub1qgRYVi4u0PoMgXbDNGg+9dtGgogaJ4ZSNqBW0jh8UF1npdSFNTWXHlIyZU8qpBhIERERERFVpVZflhX5QpuhpsYWevEJ4Fg2cCwTyM2Bv4uG4+lpQGGBCqykb5UKrqyXcn9ZKVBeDn3d79D3bINp8r1nNWQnIqorhlINEJzsyzqBv/Iy0NH/1J1pSUDJSUuJbNPmdt5D41p68Lhqai45lEzZYyBFRERERFR3qgl6eKTaJMTyCw9HQVqaZcXwGuilJUBCPMz/NwdIT4F5zvPQYi+FNmEaNJnaR0R0Hvi/+nq2Na0Qj/52GK8s248ys+WXup4Qb/liVAznYJ+n1LwSfBx3VF2/sWsoe0gREREREdmQLNaktbsIpn++BW3EWCnJUlVT5qfvh75zs713j4gMiglJPbu4mQ8CPV2QU1SCDUfyLXee6ielRbGf1PmQcO/fa1NxslxH56beGNMhyN67RERERETUKGnuHjBdfytMj74EhEUAudkwz34W5rmzLdP+iIjqgKFUPXM1abisbYC6/mt8bpUm5+wndX4W7MpCfHYxfNxMmB4bDhdTTbPjiYiIiIjIFrS2nWD619uW1f+kamrNMpifuR/67q0N+r56cZGlJxYROQWGUg1gRNtA1VRwe3ohUrPzgZQkyxe48l6d/ZVZhG92Zavrd/VphlAfN3vvEhERERERSTDl4QHTDbfB9PCLlubqx7JgfutpmD+fA11W96tHspKg+auPYH7oZphn3n66RQoRGRpDqQYQ5uuG2OhgdX3JtiOAbgYCgqEFWO6j2ikqLceba9MgrbmGRvljcJS1czwRERERETkK1Wvq6dnQhl2tbut/LlFVU+b1K1Rl04XQM9JUyGV+4g7oyxcBJSVAQR7MbzwF/a/t9fQJiMheuPpeA7mmawTWJmRj+VEzJmgucGOVVJ19FJeBowWlCPNxxR29m9p7d4iIiIiIqAaahye0CbdD7x4L82ezgcx06J+8Cd3VDejcE1qvAdC69obm6V2r19NTDkNf/C30TX9aTvILCb9GjIN52U/A3h2ql5Xpjkehde/XsB+OiBoMQ6kGMqBNMIK9XZFdBGwI7YxB7CdVJ2uS8vD7oeOQ9lHT+0fAx93F3rtERERERETnoLXvrHpN6Ut+hL5pFZCeAmxbD102FVD1gNZTAqo+0LzODqj0xHiYf/lGPadC554wjboeWkwnddPUqRvM/3ldPcb8/svQptwP04BhtvyYRFRPGEo1EFeTCZe1CcBXO7OwJLwfBke3sPcuGUZ2USne25Curl/TKRgXhdXubAoREREREdmf5ukFbfRE6FdPAKTiKW419M1rTgVUG6DLdkZAhaRDMC/+BthzqlG6pgE9YmG64npordpUfX03d5juegy69K5auxz63LdhLiqA6bIx9vnARHTeGEo1oMuambBghxm7AtsgJSgckfbeIQMw6zreXpeGghIz2gR5YkKXEHvvEhERERERnQdNgqXIKGiRUdDH3GgJqDavUSFVlYDKZALMp6bomUzQ+g6BdsV10MJrPrGvubgAU+4HfHyhL10IfcEnMBfkQxt7o+V9icgQGEo1oOD0g+iRfQRxIZ2w5Egxbg1rYu9dcniL9h7D9vQiuLtoeHBAONxc+AeFiIiIiMipAqrRk84OqFzdoA0cDm3EOGiykl9tXlPCrOtvBXz8oP84D/riBUBRATDxDsvXiMjhMZRqQHrCfoxI3a5CKemPdFO3ULi78JdjTRKPFePzbZnq+q09whDp72HvXSIiOktZWRmKiup3mWsjO3HiBEpkJSSD8/b2hqsrD4uIiOwSUGWmA94+0Hz9z+u1tCvHwywVU/M/hL5ysSWYmjodGn+vEzk8/pQ2pIR4dM/Zh1CXUmSWuGFtUj6GRrNaqjol5Wb8e20aysw6ejf3xciYAHvvEhFRtYFUYWEh/Pz8YOIZWMXNzQ2lpaUwMrPZjPz8fPj4+DCYIiKyR0AVFn7Br2MaOgpmLx/on74FfeMq6CeKYLrzMWgePNFN5Mh4RN1AdF1XlVIu0DG8ueUX4W/xufbeLYe19MBxHM49iSaeLrivXzPOAycihyQVUgyknI+Mp4wrK+CIiIzN1HcITPc+Cbi7AzvjYH7raehSNUVEDotH1Q2kLC3ZUjbq6obLurWESQP2ZJ5AUu5Je++aQwZ4v8YfU9dv6ByCAE+epSYix8VAyjlxXImInIPWpRdM058DvHyAA3tgfvYfMH/4Ksw/zINZVuo78Bf0/OPq/yBEZH/8338DKdm/23KlVRsE+3miT6Qv1h8pwG8HcnF7r6b23j2HslfCuuMlqrn5kOi6zyMnIiIiIiKy0mI6wfTIi6pSCjmZ0HMsfWtFRRQloVVYOLSmzYGm4UBYBLQWraE1b2mv3SZqlBhKNXAopUXFqMvL2waoUGpFwnHc3C0UHq48I2v16wHLtMbBUf7wdXex9+4QETltP6z66pckZ5drO8362LFjqmdTcHAw/vrrL8TExNRpPxYuXKie06lTp1o9vri4GCkpKWjTpk2t34OIiJyP1iIapuffA/bvhp6RChxNs1zKlpMFnCgEDh+AfvhA1cCqcw+YRt8ILdry/zgialhMRhpIyb5dlivR7dRFt3AfNPV1Q2GJGWuS8u27cw4k/2Q51hzOrwjuiIio/m3atAljxoxBdnZ2lVXzziT3JScnV9xetWoVVqxYcdbjrr32WsTFxVUbfO3aderv3ynff/89rr76avW1F154AdOnT6/2fZOSkpCamqo22Qfp7ySXDz/8sAqaamvt2rUYPXq0U6wISEREF0bz9oXWrS9MI8bBNPkeuDw0Cy6v/Bemd7+B6Zl3YLr7cWjXTIE28DIgppPM5QZ2bYH5xYdQPmcW9KRD9v4IRE6PlVINQC8rRcnBfeq6NWE3aRpGtAnA/23PVP2TLm3NVfiEVI6VmnVEB3ogJtjT3rtDROSUevfujcGDB+O6667Dd999h6CgINx9990YO3asCqu+/PJLTJo0Cfv27cOsWbPw7bffque99957GDZsGC655BKcPHkS7u7uOHLkCOLj49G5c2f1GAmbJACSr23duhWTJ0/G3Llz0a9fP/X1n3/+Wd0n1VEffPABXn31VRUyeXh4qAoqFxcX9b6PPPII0tPT1evI/j399NOYPXs2QkJC8OSTT6qKK/H777/D29tbXZeKqMsvv1w9XlbOE/Lavr6+Kgiz9okqKChATk6OCueszyUiosZLc/cAmrdSW+W6Xz0jDfrPX0NfvxLYvhHm7RuBHrEwjZ4ETR5fB7rZDBxJgL5rM3A0BVqPWODiPtDYw5CoCoZSDSH5MFBaAnj7AqGnlzcd1qYJ5u/IxL6sYiQeK0ZUYOMOYSwNznMrqqS44h4RUcN57LHHVHh06NAhFeJ4enqqYEh+9z7++OMqlJLgSEIiIUHR8ePHceuttyIrKwsjR45Uj83Ly1OPGzJkiHqcBEsSDEmYJeHXM888g1tuuQXffPONCoU2btyoqqAkqCosLFS/+xcvXqyqo6ZNm4YZM2agW7duWLp0KSZMmIA777xThWAzZ85Ury2VWrKv48ePV4+vHCo1b95cPa9ZM8uqrRJISYj28ssvY9CgQRXTBOX95bMykCIior+jSY+pW6dDH3Ud9EVfQd/0J7BlHcxb10PrNRDa1ROhhUfW+Hw9Pw/6nq2q2krfvQXIP376a+tWWEKwUddD6zUAmoltS4gEQ6kGoCfsV5dadLsqQUuglyv6tvDD2qR8Fcbc1acZGrPdGSeQklcCT1c2OCciaihSJSThkpubmwqApIpISEWS9W9UdT2e3n77bTz77LMqPBo6dKgKmTp06KBCH6mgkutCXre0tLTieRIspaWlITAwEM8995y6TyqvoqOj8cYbb6iKJZnGdyYJlA4ePIiBAweqMEp6SOXn52PcuHHq9SUkk9tvvvkmbrjhBhV8ifvuuw/h4eHq/vfffx89evRQryEh1o033qgqxG6++WZcdtllquKKiIjoXLRmkdBufxj6qPEwL5oPbF6rAio9bg20vkOgXX0DtLAI6OZyICEeuoRQUhEl/akqr+rn4QV0vBhaUCj0tcuBlMPQP3od+k9fQrviOstr1VO/RyKj4k9AA4ZSaG3pJ1XZyJgAFUr9kZiHW3qEwbMRNzz/Lf50g3NvN54pICLjUctJl5y0z5u7W6qczmXdunUqHJJgSqbrWYOi8vLyGp/zyy+/qN5Qe/bswX/+8x8VREk1VUZGhqqauv/++1XVk/Rvqo6EX9Z+VFKhdCYJnaRqy1qpJX766Sf1/XzqqafU7X/961/47bffVNgkIZf0pnrnnXdUsFW5N9bnn3+O559/XgVfMt3vpptuwj333KOqp6688kq89tpruOaaa/DAAw/U4ptKRER0mqzE53LX49CPJMD803xg2wbo61dA3/gH0K4zID2nigqqPikyClrnntA69wDadIDm6qbu1kdPgr7iZ+jLFqnpfPrct6Ev+hLayGugDRgOzc3dPh+SyM4YSjUAPfF0pdSZujT1RrifG9LyS/FnYh4ua6TNvfOKy7D2iLXBeaC9d4eI6PyUnIT5vvF2eWvTnAWAx7mngUuFkGwS5kjz8MqVSdapemfy8/ND3759Vf+o1atXq4ApLCwMDz30EGJjY3HVVVepKXd/R15fHi8VV9LLSqqxZOqfBFJLlixRodiiRYvUFDypxpLwSaqvpNJJgrN//vOfNb525f2WXlIyxVDuk0op6Zkl+yqB1M6dO1VTduk9RUREdCEr+bnc+6Raqc+8cD6wMw7Yu8PyRW8faJ26q1X7tIu6QwsIrv41fHyhXTUB+vDR0P/4FfqSH4HsDOhffAD95wXQLh8HbfDl0Grxt53ImTTeMp0Gop8oAtIsKxdpUWcvI6oanp8Kon47YKkUaoyWHzqOMrOOtkGeaMsG50RENlE5zJGKJ+tUvjPJlDepMMrMzFQNyCXkOXDgAFauXKkCKWGtcJKpddLsvDJZMS8qKgp33XWXui1VTBs2bFA9oSSgkobjW7ZsUYGUeOKJJ5Cbm4t27dqpqXnSQ0pCLHltqXqSgEoanF9xxRX44osvKt5H9k+mGE6dOlVVdv33v/9VFWExMTHqutwvj5HPcscdd9RpFT8iIqIzaa3awuWBf8E08zVoN9wG02OvwPTveTDd+ShMUu1UQyBV5TU8vWG6/BqYXvoI2sQ7gMAQ4HgO9AWfwPz4NJh/WQA9O6Ne91umGeppR6AXnlHVReQAWClV31KT1IVL0who/gGWqR1nGNa6Cb7YnoX47GIczClGm6DGFcrI92TJqUDu8pjGWSlGRE7C3cNSsWSn974QEjK1alXzSkJSzSQVRm+99ZaqZJKG4lJpJQ3O5fe49HeSaipZlW/69OkVPZ6kqbg8t3LfKAmHpPeUBEQSYMm0P+l19eOPP6pgasqUKWjdunXFCntW8r7Sv+rM6XtW8vi9e/eq6YaJiYlo27YtgoODVdWV9MD67LPPVGXWwoULsWzZMhV2ERERXSitdXu1XdBryDT8S6+CPvhy1QRd/9+3QGY69B/nqQ3SdL1DV2gdLwbaXwzNz79uK/+lHoa+dyf0fTuB/bst0wxdXIFO3aD1HgStW19oXlwAhOzPIUIpOYCVkntZCvrSSy9V/SDO1SdDDjZl9R45GO7evbtqdOrl5QV709p0gMvbXyLEBTjd8aKqJp6uiG3hiz8P56u+Svf0bVwNz3ceLUJqfim8XE0Y1IoNzonIuNTfKoOV2f/8888qvJG/mREREdU+RsIo+bsqQZGsYiekSkqCJwmKZBU7+dsr/aqk4koqqaw+/PBDNWWuci+pTz/99G8bnctUQGlkfmYoJY998MEHVf8pCbSkykqmFE6cOFF9vUWLFip4kqbt8hqyScXU/PnzVdVV5feRFQKlUorBFBERORLpOaUNGgG9/zBLM/WViwHpUZyRBl22Vb/KAQfQIvpUSNUViOlUZZqfnCzSU5NUACVBFPbvAgryqr6R9LYqK1VTD3XZ5Lb0vpKVALv2geZp//9LU+Nk91BKSvNfeeUVdO3aFf/4xz/Ugasc+Mpy0DX5888/VY8LWUVHph7I0s9yttV6kGpvmrcP3MPDgbS0Gh8jFUISSlkanoc2qkbfsvKgGBrtDy83ziAlIrIFOWCViiKZRtezZ081Fc7qzOl3Ur0kf2Ml2Ln44osrAjjp9SRBkfSJEtJrSh4nDcnl73F8fLwKhJYvX37O/ZEKJnlfCZSsFixYoI4BJOiS6qjDhw9j27Zt2LFjR7WVUrfffjuSk5NVFZaVBE/SCF36aJ35fr1791bHDERERI5Gc3GB1m8o0G+opSXM/l3Q/9quNjUbJ+kQdNmW/GCpeGrTHlrbTsgqyEX5tk1AXu7ZFdVtO0Hr0AVa+y5Aq7aWButxq6FvWg2kJwPb1kOXTf4Wd+kFU+9BQOde0KpZpITIaUOprVu3qukAUrovZ1UlWPrkk0/+NpSSg817771XnekV/fv3V8tIG0nnMG8093dHSl4JViXmYWRM42j2nXuiDOutDc45dY+IyKZVyTJlTvor3XbbbSqgEtJwXJqXCwmJ5LYEWDI1b/369Wr63O7du1VPJjkh9MMPP1RMTR86dKhqTP7000+rsEiqlIYPH64qrKzk9QYOHFhlX+bOnasuZYW8zZs3V4RG48ePV6vuyep+MuVuwIABajpeZZWnxc+bN++szyn7IMcUMt2QiIjIiNS0Oqle6tpH3daPH4MujdX/2mYJqXKy1JQ8ff9unLA+SVbvk9X+2ndRQRSiYipW/qsQ0RKarAJ49UQgJVGFU1KdJdMGsXktzJvXqgpwVTl1yZXQ2na0+WenxsfuoZScBZUzsdYyf+lvIWc9/44saV1ZamqqOrD9u2os2azkbK91ql9tltOuK+tr/t1ry9dGxgTgk80ZqnJIQqmG2BdHbHBergPtQjzROsjxSkRrM3bkmDh2xsWxsw35/kp/KJmaJ9PwrMGRND//+uuv1XWZJid/L2WK/FNPPYVx48apgEjCqhkzZqiV7aQaSgKfgADLiQWpnhoxYoSqbpLHjxkzpsr7yjR7CbNk+l5lEkJV/tscGhpa8W9AmpdPmDBBBWJCphnKCai4uDgVVkkj9ZrIZ5DtQr5PREREjkRrEgit7xCgr6Wvo5raJ+FUwj74RbVBYfNo6NHtoVWqHD7n37rIaGiR0dDH3gQkHbQEVHGrLSsCblylrmsT74Rp6OnKaqKGoOnVdeK2oc8//1wdPMqKPFZyBlemBtS0KtCZgZQcnMoUQOktUR2ZDiAr/1jJgbE83t6OnyjFlR+swckyMx4d3g7Xd4+EMzPrOq75aB1SjhfjnyM7YHSX6nuZEBE5qkOHDsHPzw/OrrCwUB30Wv8OS4Akf28jIyPVynkylU76RvXq1Ut9Xf6OV56G11CkslpCrsDAhqkulubtlau8qHrS36tyoFhf5D9J4eHhauqmnQ9PqY44dsbG8TOu+h479RoJ+6EvXWgJqOQ9RoyFdu0t0Exsu1KfGsPPnZubmzrp6PCVUiaTqUovCCEHtrU5yykHydIgXZqj1xRICTlza13CuvJZUOsqQPVNXl8qt6Rx+7n+gU3uFoqP447irRXxaOVVhhZNnHf+7tbUAhVI+biZcHGArn4AHU1dxo4cC8fOuIw0dtZKImdnDZgqf9amTZuq29aG4tavy99wGUNbfF/kvWRrqPeS8a3ub5Orq2utDqqIiIiMTP0/WVYVvOMRoHkr6Au/gL7kR+iZ6TDd9hB7TVGDsHsoJWdhZSWdymRlHzkAPBeZRiD9MSZPnlyrg9jqNOR/gNQqCOd4/SvbBSAupQDb0grxxuoUvHp5FNxcnHPqwK/xllWVhrZuAncXzaH/81mbsSPHxLEzLo4dOQL+GyQiosZOwintqhtgDm0Gfe7bwNb1ML/+BEz3PaWmEhLVJ7vX4Emz8v3791fczsjIUGdAzzV1T/pKyLLWDz30UJVlp43GpGl4oF8z+Hm44NCxk5i/IxPOKLuoFBuSC9T1kW3Z4JyIiIiIiMiRmfoOgenBWYCvH5AYD/OLD0NPOWzv3SInY/dQqmPHjqoyasWKFeq29Kno0qWLmtYnPS1kit6ZpBG69Jy69dZbERISopZ/lh4TRhXs7YZ7+1gatf+wJwe7jhbB2Sw/eBxmHegY6oWWAcYNEYmIiIiIiBoLLaYTTI+/BoRFADmZML/yGPQ9W+v8Oro8d/kimL/+GOaF82Fe8gPMfy6BWRqs79oC/eBe6KlJ0I9lQy8uYuVyI2L36Xuy6s9dd92lQiZZ2llKBZ955hn1talTp+LVV19FVFRUlecsW7ZMhVDvvvuu2oT0erBeN6LYln4Y3qYJlh08jjfXpuLtK6Ph6+4CZ1Bu1rHkQK66fjmrpIiIiIiIiAxDaxoB08xXYX7vRSB+D8yzn4N2490wDRrxt8/TszOhb16jNhzaV/Pjqn1TExAYBK17rGXlwagYrpDrpOweSglZveedd95RqxrFxMRUrGwkq+ZVR5ayls3ZTOvZVFVJpReU4sNNR/HQAOdYnW5rWiEyi8rg625C/5bOv2oVERERERGRM9F8/WGa8Tz0z2ZD3/AH9M/nwJyZBm3s5Cor8+lZR6FvXmsJohJOt+mBBEptO0KTRuoyy+lEIfQTRUBxkSyvq26j+ITlUmZL6WYgJwv68kVqQ2gzaH0Gq4BKC695kTMyHocIpURAQAB69OiBxszLzYQHB0Tg8SWHsSoxD70ifDAkugmM7rdTVVKXtm4CD1e7zxglIqJKrCvoVUem0Mt0+gtx7Ngx9TrBwcH466+/1Mmn2ixmYrVw4UL1nE6dOtXq8TKlPyUlBW3atEFjkJeXh5kzZ+Lpp59GWFjYOR//yiuvYPPmzRW3pWXCP//5zwbeSyIicgaaHC/c9iAQFg590VfQ//cdkJEOjJkEfftG6HFrgMMHKj1BA2IugtazP7QesdACgs/5HmraXomEVkXqtfSNq6Bv2wBkpkP/ZYHa0CLaEk71HgQtiKvjGp3DhFJk0T7ECzd0DsGXO7NUtVTHUG+E+Vb/nwUjyCoqVasLCk7dIyKyPQmEysrK4O7uftbXMjMz0a9fP8yaNQsTJ06s8rUDBw7ggQcewFdffQV/f381bV6m3J8ZKJWXl6sgyNPTU73P3r170blz54qvS6/ITz75BKtWrcILL7ygTkLNmTOnymtIb0nZF+tryz4HBQUhJycHDz/8ML7++utaf961a9fi/vvvx9atW6v9zM4WSEnIJN+72pKq9Ndff12FhELGlIiIqE4r842eBHNoOPTP3jk9Pa/iASagnQRRAyxBVB1X61NT9Dw8LVtAH2hd+0A/WayCKQmosHsLcCQBumzfzgViOkHrM8Tyfn7+9f+BqcExlHJA13cOxpa0AuzLKsZb61Lx/LCWcDEZc/7ssgOWBuedw7wQ2YQNzomIbE2qYqZNm6ZWqrUuHiIr2Iq5c+ciNjYWH374IcaOHQsvL6+K57Vu3VotJnLffffh888/x9VXX60CDamqKikpUWGUPF6CKDmrKSGWBEGTJ09Wrythl5CVcuU+CZw++OAD1StSQizr/kgosm/fPjzyyCNIT09XQZIEUlL5M3v2bLUPTz75pKq4Er///ju8vb3VdamIuvzyy9XjfXx81H3y2rKCr+yvtcqroKBABVybNm2qeK4zkH6cAwYMQHx8fK0eL98DGauWLVs2+L4REZFzM8VeAj0oFOb3XwKKCoEOXaD1kIqoftD86xZEnYvm4WnpK9V3CPSCPOhb1kLfsAqI3616XOmyffG+muKHyChokdHQIqPUdYQ0rTK9kBwPQykHJAHUjP4RmL44EbszTuDHv3Jw7UXnLnV0yAbnB081OI+p319MRERUO71798aMGTPQs2dPFQRJ5ZFISkpSvRt//fVXFTrJoiP/+c9/1GOEBDpvvfVWxeq4S5YsqXhNCZekIkq+LiGVTAG0vpcsViJ9H7/55hv1Ghs3blTvJUGVrKorocjixYtVdZSEZbJv3bp1w9KlSzFhwgTceeeduOSSS9SUNAmt5P2lCmv8+PHq8ZVDpebNm6vnNWvWTJ1ZlUBq2LBhePnllzFo0KCKyit5f/lczhRICfleyZQ9+d7WhgSH8j2VsZaxkH8T8j2VEI+IiKiutPadYXrxP6r/k+bjZ7PeVtrgkcDgkdCl51Tcn6rHFZIOqSl+aprf1vWnm6d7eAGRraA1t4RUWosooHkUNC/nOiYwMoZSDirczx239wrDO+vTMX9HJrqF+6BNkCeMQv7T8fO+Y8guKoO/hwtiW/CAl4jIXiS46dChg5ruJSGGBBL33HOPCn5kGtf06dPV1DqpOnr00UcxYsQIFehIBdK1115bp/eSYCktLQ2BgYF47rnn1H3ffvstoqOj8cYbb6hqHXmvM0mgdPDgQQwcOFAFJ9JDKj8/H+PGjVOhl1RTye0333wTN9xwQ8WCJ1LJFR4eru5///33VX9KeQ0JsW688UYMHjwYN998My677DJVceVMatNDqjKpLGvVqpWqXJPAUMLF+fPn44477qj28fJ9twaOQoI/azVdQ6yAZH1Nrq5kPBw7Y+P4GZcjjJ3mY7//52nBocDl16hNzz8OPTnRMrUvOdFyPTUJOHkCOLgX+sG96jkVYVVAELRmkUB4JLSmzS2XcjswxCaVVY4wdo6CoZQDG9a6ierHtO5IAf69JhX/viLKEI3C806W490NaVh/xNJLalS7ALi5OP5+ExGdTwB/srzahYwbnIeLVusDGZlqJ9UwEvqEhobiiSeeQEREhJoyJ8GUvI6ED//617/UlDAJlXbs2KGm5sm0Pgl0pKfU4cOH0a5du2pfv3JvIql+kh5SUuVkrbyqTEInmQIoX7N+hp9++kl9P5966il1W/blt99+U2GT7I/0ppKVeiXYys7OrngtqfJ6/vnnVfAl0/1uuukmFbhJ9dSVV16J1157Dddcc43qj9XYScAnm5V8r+T7WVMo9cMPP6jvq5UEi9LDSv4NNSQZOzImjp2xcfyMi2MnVR3hQLsOVe7Sy8tQlpKE0oR4lCQeQOmh/ShNPIDyrKNAbg703Bxg747TQZWaKugB1+at4BYZBdfI05dyn8nzdJuD+tKMY8dQypHJgfo9fcOxNysByXkl+HRLBu7q49j/aLelFeLtdWnIOVEGyc9u7BqKsR2D7L1bREQNQgKpG76utNyxDX19Qzt4utYulJJASabZSUNsqa6R6iL5GyPVUBJUSfWMBEXSt0mqiqxBkVRQHTlypKLKRgKN3bt3q9s//vijCo0kXBo5ciTefffdsyqfHnroIRVyXXfddeq9pFJL3kemAkqQtWjRIjUFT6bySfgk1VxS6SQVVn+3IlzlAEx6Sd16663qPqmU+u6779RnlEBq586dqtJL9p3O1qRJE1V9VtMKjDLeV111VcVt678L+XckgWV9k9eXg3PpLaZWXyLD4NgZG8fPuDh2teDmBbS72LLJ90yOI4oKgPQU6GnJ0NOTLdflMiMN+smTlvDqUDXHd0Gh0Jo1B5qdqqqyVldJ1VUdK54aw9i5urrW6kQWQykHJ1PfpseG4+nfj+B/8bno1dxXbY6mtNyM/9uWiYV7LY1om/u746EBEYaackhE5KwkIBo9enRFkCBB0C+//KKm0d19992qAkmm1T3++OOquqnygZW1L5NcVg4upILqzJ5SVtK3SqpvZBqghFLnmr4nlVu5ubmqCkum5kkzdHk/eV2pepLgSwKzK664AkePHlXBmTUcee+991TIJdMOv/jiC3W/NP/+73//i/Xr16uwTKqlpMeVVFJJf6rGSoI/+R5K+Cf279+vgqnqAikh99f0tYY8gJbXdtYDdGfHsTM2jp9xcezqyMsHiG4HTbZKd+vl5YBUUaVLWJVy6tISWqEgD8jJhJ6TCezZVqW6SvWtatYcWtMIwOQClJZALy1Rl5BjpIrrp26XyWUZMjp0Qfngy4HOPRt1M3aGUgYg/aSu7hCIRXuP4YU/kuHaACvxybTA3s19MSTKH12aetdptb+k3JN4Y00qEnNPqttXxARgao8wQ0w1JCK60Cl0UrFkr/eurf/9738V12Uam/QFat++PdatW4eOHTuqVfVkat6oUaMqVqw7U23PAEpTcQmJKgdPU6dOrajUkmBs7dq1akU8qbaSgGzKlClqtT/rCntWUkElodOZ0/es5PHScF0CtsTERLRt21b1yJLwRUKozz77TFVmLVy4EMuWLWs0gVRRUZFaxdAaKFrJqnvyPZHvt1StST8pCQ6JiIgI0KQSW4KlphHQulb9mp6fBxytHFbJZQqQmWbpW3X4APTDB+r0fie3bwRka9oc2vDR0GIvVdMHGxuGUgZxc7dQ7MkowsGckyhpgP4lJeXl+P3QcbUFerpgYJS/CqjaBnnW+B8RSeN/2X8Mc7dkotSso4mHC+7r1wx9Im2z8gIRkb3J78faTqGzFykLj4+PV2GRBEESWEh1TN++fVVYJeFUQkICtm3bVtE8vDIJkiTIuPTSS2v1fh9++KGaMle5l9Snn376t5VSsvqeNDI/M5SSxz744IOqUkr2Q6YBynTCiRMnqq+3aNFC7ZsEMPIasu3atUuFLVJ1Vfl9pIm7VIw1hmBKeoVJ8NSnT58q948ZMwYZGRnq+yLBpHxPKveYIiIiouppfv6AXydobTtVuV8vKwUyT1VXZaRZ7pQqYzd3tWnq8vRty+YGTdfhvXMj8hd/DxxNgf7F+9B/nAdtyEhol4yCFhBc533Ui4ssqxCeLAZkNURff8DXT1WGOXJDdYZSBuHuYsJrl0epXk0NIaOgFKsO52HN4TwcKy5XVVmyRfi5q3BqSLS/WhHQ6tiJMsxel4YtaYXqdo9wHzwQG45AL/6TIiJyJDIdTxqBx8bGqqlbsvKev7+/anQuVUgy1U4OVGS625w5c856vvRpGjRoUK1CKQm/JBBavnz5OR8rFUxSNSWBktWCBQuwcuVKZGVlqeooqd6SsEyarldXKXX77bcjOTm5yhQzCZ6kEbo0Zz/z/Xr37o2XX34Zzka+b5Wd2d/LSiqnZLqmbERERHThNFc31VtK9Zeqy/M0DQG9Y1F0yVUwr14GfdlPauqgvvgb6L/9AK3PIGjDx0Br2bra5+syDTA5AXpiPJAQb7mUqYbVTeOUCjAJqWSTcM3HD5o1sPL1h9ZvKDT/QNgLEwQDkSl1oT7V93a4UPK6FzX1xrSeTbE1rQCrEvOwIbkAqfkl+HJnltpigj1VQNXE0xUfxR1Vq+y5mTQ1VU9W2HPk9JWIqLGSleekwsga3EjVkqzEJ9VS0utJfndL8CN9huQxEhRZp31JOCSPmzVr1t82tpbeT9JoXKqUhg8frqbiWUlD84EDB1Z5/Ny5c9WlNPjcvHlzRWg0fvx4tere/fffr6bcSW8omY5XWeWeGfPmzTtrX2QfpEpo6dKl5/kdIyIiIrINzdMbpmFXQ79kFLBtI8xLFwIH9kBft0JtaN8FpsvGAsGhluApUQKoA0ByIlBezbFZYIgleCrIBwrzLVVT0isrL9eynSrmqrLiYJdeAEMpchRuLpqafidbUWk5NhwpwB+JedieXoj47GK1WUUFeKhm5i0DGt+8VyIio7BOo5MgSHovSXNrqUK6/vrrz+of1bNnT0yePBkzZsxQDcWl59RXX32FO++8Uz1PgifpQWUl1yUkkul10mRcpoLJFLEzV/5bvXq1mr5XmYRQlRuky+os1pMbzz77LCZMmKAquYRUdfXv3x9xcXEqrJLqrprIvshGREREZBSaNEjvEQuXHrHQE/ZDX7oQ+uY1wL6dMO/bWf2TpNopKgaa2tparjepGi7pJSdPB1QFedDlujRtL8yz3C+9suwYSAlNb8Rt+qU/xZkrBtUHOagODw9XB/3O8u3NPVGG1Ul5+CMhDwdyinFV+0BM7haqphU6E2ccu8aCY2dcRho7aQ4tU9+MaOfOndiyZYuqPpKG4LVx4MCBcz62utX3Goo0PpfpeYGBgTYdX/mMtVnSuLHg8ROdiWNnbBw/4+LYOffY6dmZ0Ff8DP3PJXI2D2jVVoVPEkJJAIXgMIeerVTb4ydWSlGtBHi54qr2QWorN+t1Wp2PiIjsr0uXLmqri9qGV7YizbllIyIiInJ2WnAotOumQr/2FtUrSqthhWSjYyhFdcZAioiIiIiIiKjhaVIN5cAVURfKOaM2IiIiIiIiIiJyaAyliIiIiIiIiIjI5hhKERER1YGsGkfOh+NKREREZHsMpYiIiGrJ29sb+fn5DDCcjIynjKuMLxERERHZDhudExER1ZKrqyt8fHxQUFBg711xGO7u7igpKYHRybjK+BIRERGR7fDoi4iIqA4kuPD397f3bjjMajDh4eFIS0uDruv23h0iIiIiMhhO3yMiIiIiIiIiIptjKEVERERERERERDbHUIqIiIiIiIiIiGyOoRQREREREREREdlco2503tCr7HAVH+Pi2BkXx864OHbG5exj5+yfr654/EQ14dgZG8fPuDh2xuXqxGNX28+m6Vwuh4iIiIiIiIiIbIzT9xrAiRMn8Nhjj6lLMhaOnXFx7IyLY2dcHDuqT/z3ZFwcO2Pj+BkXx864OHanMZRqAFJ8lpCQoC7JWDh2xsWxMy6OnXFx7Kg+8d+TcXHsjI3jZ1wcO+Pi2J3GUIqIiIiIiIiIiGyOoRQREREREREREdkcQ6kG4Obmhuuuu05dkrFw7IyLY2dcHDvj4thRfeK/J+Pi2Bkbx8+4OHbGxbE7javvERERERERERGRzbFSioiIiIiIiIiIbI6hFBERERERERER2RxDKSIisrnCwkLEx8ejoKDA3rtCREREZAg8fiJn5GrvHXA2SUlJeP/995Geno5LL70UN910EzRNs/duUQ3y8vIwc+ZMPP300wgLC1P3cQyNYdOmTfjss8+QlZWFFi1a4B//+AciIyM5fgawbt06fPjhhwgODkZGRgbuuecexMbGcuwM5oUXXsCAAQMwdOhQ7NmzBx999JH6nTpu3DhcddVV9t49Mhj+/BsPj6GMicdPxsXjJ+fA46ezsVKqHpWWluKVV15BdHQ0XnrpJSQnJ2PlypX23i2qgfzwy3hlZmZW3McxNAb5o/vee+9h0qRJ+OCDDxAeHq7+SHP8HF9RURE+/vhjPPvss3jjjTdw2223Yd68eRw7g/nzzz+xffv2Kr9L5QBr1qxZ6mu7du2y9y6SgfDn33h4DGVMPH4yLh4/OQceP1WPoVQ92rp1q/qFMWXKFDRr1gwTJ07E77//bu/dohq8/fbb6pdAZRxDY0hJScGNN96I/v37IyAgACNGjEBCQgLHzwBkfG655Ra0atVK3ZaDqPz8fI6dgciUgc8//xwRERHqthxEBQUF4dprr1X/wZHljTl2VBf8+TceHkMZE4+fjIvHT8bH46eaMZSqR4cPH0a7du3g4eGhbssvDUmryTHdeeedGDVqVJX7OIbG0LNnTwwfPrzidmpqqvplzvFzfCEhIRg0aJC6XlZWhl9++QV9+vTh2BmIHFDJmMXExKjbMnYXXXRRxVSBtm3bqv/kENUWf/6Nh8dQxsTjJ+Pi8ZPx8fipZgyl6tGJEycQGhpacVv+gZlMJjaic1DW/geVcQyNR/4w//zzz7jssss4fgaSmJiIO+64A9u2bcPUqVM5dgYhZeU7d+5U/Sqs5Axt5d+nXl5eyMnJsdMekhHx5994eAxlfDx+MiYePxkTj5/+HkOpeiS/ANzc3Krc5+7ujpKSErvtE9UNx9B4FixYoM4OSWNHjp9xyJm8p556Sp2hlb4WHDvHJ2MhzThvv/12deBk5eLiAlfX0+umcNyorvjz7xw4jsbC4ydj4vGT8fD46dwYStUjX19f1bCsMkmvK/9jI8fGMTTeWYfffvtNrRwjY8TxMw45k9e6dWvce++92LhxI8fOAL777ju0adMGPXr0qHL/mWPHcaO64s+/c+A4GgePn4yLx0/Gw+Onc2ucn7qByDzQ5cuXV9yWpTplRQT5B0fGwDE0DhkbabQqq4/IUsaC4+f4ZOnbzZs3Y/Lkyeq29Y+vjCHHzrGtXr1aHTxJo1Vx8uRJtTy1aN++fcXjpB+CNO4kqi3+7nYOHEdj4PGTMfH4ybh4/HRurJSqRx07dlQJ54oVK9Tt77//Hl26dFFllWQMHENjkNLWl19+Gb169VINA4uLi9XWoUMHjp+Dk3LzZcuWqS0rKwvz589H165d0b17d46dg3vuuefUMtSvvvqq2uTnb/z48Wp58b1792LHjh2qR8lPP/2kxpSotvi31zlwHB0fj5+Mi8dPxsXjp3PTdF3Xa/E4qqW4uDh19kHmhEp55TPPPFNxFoIck/xSmDNnTkWjOY6h49u0aRNee+21s+6XcUxKSuL4OTj54zt37lxkZ2erP77Tpk2Dv78/f/YM5t1331WrxgwdOhRLlizBp59+Ck9PT/j4+GDWrFlquXGi2uLPvzHxGMpYePxkbDx+cg48fjobQ6kGkJubi0OHDqnlHv38/Oy9O3QeOIbGxvEzLo6dccmUgZSUFFUtIQdXRHXFn3/nwHE0Lo6dcXHsjCuDx08MpYiIiIiIiIiIyPY42ZSIiIiIiIiIiGyOoRQREREREREREdkcQykiIiIiIiIiIrI5hlJERERERERERGRzDKWIiIiIiIiIiMjmGEoRkdOKj4/H77//DrPZfNbX3nvvPezZs6dOr7dy5Uq88847OHHiRD3uJREREZHj4PETEdkSQykiclqbNm3C0qVLYTJV/VV34MABdYAkX6+OPGf//v1n3R8XF4djx47By8urwfaZiIiIyJ54/EREtsRQioicipyFO3z4MFJTU7Fjxw506dIF6enp6rZcisWLF8PPz08dWKWlpVV5vq7rWL9+Pd58803k5eVV3F9QUICtW7di9OjRNv9MRERERA2Jx09EZC+aLr9BiIicxM6dO/HKK6/AxcVFHWDJwZP8mistLUVMTAzGjRuHWbNm4b777lMHWhs2bMBzzz0HX1/fitfIz8/Ho48+isjISDzxxBPQNE0diM2dO7fG9500aRLGjh1ro09JREREVH94/ERE9sJQioic0pIlS1QZ+WuvvVZxX1ZWljpIio6OxsyZM1FeXo4XXngB2dnZuP/++9G2bduKx+7evVsdbE2dOhXDhw/HAw88gEGDBmHYsGFnlbK/9dZb6sxg8+bNbfoZiYiIiOoTj5+IyNY4fY+InNKyZcswZMgQVYK+bt067Nu3Tx1IyVm722+/XT1GzgbKGb3g4GA89dRT+Pjjjyuael500UW47bbbEBsbi19//RUnT57EmDFj4O7urvolyGVYWJgqdW/atCkPqIiIiMjwePxERLbGUIqInI70LkhJSVEHVVu2bMGaNWsQGBioSsw7duyIN954o+Kxnp6e6uzfFVdcoa5Xbuo5YsQIuLm54aeffsLEiRPh7e2N3NxczJ49W5WuC3n93r172+VzEhEREdUXHj8RkT242uVdiYgaSHFxsepdIAdU0g9BDopcXV3VQdWLL76IFStWICcnp8pz9u7diylTppz1WnIA5e/vj9dff72iZ4KUrIugoCB1KeXrZWVlNvlsRERERA2Bx09EZC8MpYjIqUh5uRw0Sfm5bFZr167FtGnT1Jk869m8oqIiVXIuZwIfe+wx9OjRo8prffDBB+rA7N577624LzMzU13KezRr1kyVoctGREREZFQ8fiIie2EoRUROxcPDQ519k4Mh2b799lu1lLE04hTSvFPOzEkjz2+++UadAZwxYwa6d+9e5XUSEhJUabkcbFW2Z88edRkXF4dOnTrZ8JMRERERNQwePxGRvTCUIiKn07Jly7Puk7JxObNnXfFFysllWeOuXbtW+xpff/21OtDq2bNnldJ2OSs4atQoLF++HKNHj0ZAQEADfhIiIiIi2+DxExHZA0MpInIqGRkZ+PHHH1FQUID8/HwkJyerg6kHH3wQAwcOVAdBHTp0wOOPP17ja6xfvx7bt2+v0tBTzJs3Tz1f+iekpaWpZYyffPJJlp8TERGRofH4iYjshavvEZFTsa4SI2foJkyYgH79+qFXr16YM2eOul0dKUdfvHixOpMnPQ8++ugjjBw5EhERERWPWbBgAVatWqXODlqXRZYVZGbNmoXjx4/b8BMSERER1S8ePxGRvTCUIiKnIqvFTJo0Sa0e0759e3h5eUHX9YqvywFRVlYWsrOzUVhYqLZ169apFWek38HmzZvV46699lp1KQdZsurMokWL1NnC6OhodX9ISIg6yydn/B555BGsXLkSZrPZTp+aiIiI6Pzx+ImI7IXT94jIqclZPOsyxKJjx474/vvvcffdd1fc5+LigsGDB1esHiNnBuVsoRxkPf/88wgLC1Nn9Fq1alXltaOiovDSSy/h7bffVivNyDLHF198sQ0/HREREVH94/ETEdmKpleOwImInMynn36qVo+ZOXPmeT1/9erV6NOnz9/2PZAzfHv37uVqMkREROQUePxERLbCUIqIiIiIiIiIiGyOPaWIiIiIiIiIiMjmGEoREREREREREZHNMZQiIiIiIiIiIiKbYyhFREREREREREQ2x1CKiIiIiIiIiIhsjqEUERERERERERHZHEMpIiIiIiIiIiKyOYZSRERERERERERkcwyliIiIiIiIiIgItvb/l6H2I1uGyUYAAAAASUVORK5CYII=",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"模型训练和评估完成!所有文件已保存到 './output\\emotion_model' 目录\n"
]
}
],
"source": [
"# 模型训练\n",
"try:\n",
" if 'emotion_model' in locals() and 'X_train_reshaped' in locals() and 'y_train_categorical' in locals():\n",
" # 设置训练参数\n",
" print(\"开始使用真实数据训练模型...\")\n",
" \n",
" # 设置输出目录和检查点路径\n",
" output_dir = './output'\n",
" model_name = 'emotion_model'\n",
" os.makedirs(output_dir, exist_ok=True)\n",
" model_dir = os.path.join(output_dir, model_name)\n",
" os.makedirs(model_dir, exist_ok=True)\n",
" \n",
" checkpoint_path = os.path.join(model_dir, 'best_model_weights.h5')\n",
" \n",
" # 设置训练参数\n",
" epochs = 100 # 与默认值一致\n",
" batch_size = 32 # 与默认值一致\n",
" \n",
" print(f\"训练参数:\")\n",
" print(f\" 轮次: {epochs}\")\n",
" print(f\" 批量大小: {batch_size}\")\n",
" print(f\" 检查点路径: {checkpoint_path}\")\n",
" \n",
" # 记录训练开始时间\n",
" import time\n",
" start_time = time.time()\n",
" \n",
" # 训练模型\n",
" history = emotion_model.train(\n",
" X_train=X_train_reshaped,\n",
" y_train=y_train_categorical,\n",
" X_val=X_val_reshaped,\n",
" y_val=y_val_categorical,\n",
" epochs=epochs,\n",
" batch_size=batch_size,\n",
" checkpoint_path=checkpoint_path\n",
" )\n",
" \n",
" # 计算训练时间\n",
" training_time = time.time() - start_time\n",
" print(f\"\\n训练完成! 耗时: {training_time:.2f}秒\")\n",
" \n",
" # 绘制训练历史\n",
" \n",
" # 在测试集上评估模型\n",
" print(\"\\n在测试集上评估模型:\")\n",
" test_loss, test_acc = emotion_model.evaluate(X_test_reshaped, y_test_categorical)\n",
" print(f\"测试损失: {test_loss:.4f}\")\n",
" print(f\"测试准确率: {test_acc:.4f}\")\n",
" \n",
" # 在测试集上预测\n",
" print(\"\\n在测试集上预测:\")\n",
" y_pred = emotion_model.predict(X_test_reshaped)\n",
" \n",
" # 将独热编码转换回类别\n",
" y_true_classes = np.argmax(y_test_categorical, axis=1)\n",
" y_pred_classes = np.argmax(y_pred, axis=1)\n",
" \n",
" # 保存值和预测值用于后续分析\n",
" np.save(os.path.join(model_dir, 'y_true.npy'), y_true_classes)\n",
" np.save(os.path.join(model_dir, 'y_pred.npy'), y_pred_classes)\n",
" \n",
" # 计算混淆矩阵\n",
" from sklearn.metrics import confusion_matrix, classification_report\n",
" \n",
" # 获取情感类别名称\n",
" emotion_classes = encoder.classes_\n",
" \n",
" # 创建评估函数\n",
" def evaluate_model(y_true, y_pred, class_names):\n",
" \"\"\"\n",
" 评估模型性能\n",
" \n",
" Args:\n",
" y_true: 真实标签(独热编码)\n",
" y_pred: 预测标签(概率值)\n",
" class_names: 类别名称\n",
" \n",
" Returns:\n",
" 评估结果字典\n",
" \"\"\"\n",
" # 将独热编码转换为类别索引\n",
" y_true_classes = np.argmax(y_true, axis=1)\n",
" y_pred_classes = np.argmax(y_pred, axis=1)\n",
" \n",
" # 获取实际出现在数据中的类别索引\n",
" present_class_indices = np.unique(np.concatenate([y_true_classes, y_pred_classes]))\n",
" print(f\"测试集中实际出现的类别索引: {present_class_indices}\")\n",
" \n",
" # 获取实际出现的类别名称\n",
" present_class_names = [class_names[i] for i in present_class_indices]\n",
" print(f\"测试集中实际出现的类别: {present_class_names}\")\n",
" \n",
" # 计算混淆矩阵\n",
" cm = confusion_matrix(y_true_classes, y_pred_classes, \n",
" labels=present_class_indices)\n",
" \n",
" # 计算准确率\n",
" accuracy = np.sum(y_true_classes == y_pred_classes) / len(y_true_classes)\n",
" \n",
" # 获取分类报告\n",
" report = classification_report(y_true_classes, y_pred_classes, \n",
" labels=present_class_indices,\n",
" target_names=present_class_names,\n",
" output_dict=True)\n",
" \n",
" # 返回结果\n",
" return {\n",
" 'confusion_matrix': cm,\n",
" 'accuracy': accuracy,\n",
" 'report': report,\n",
" 'present_class_indices': present_class_indices,\n",
" 'present_class_names': present_class_names\n",
" }\n",
" \n",
" # 打印评估结果\n",
" def print_evaluation_results(results):\n",
" \"\"\"\n",
" 打印评估结果\n",
" \n",
" Args:\n",
" results: 评估结果字典\n",
" \"\"\"\n",
" print(f\"准确率: {results['accuracy']:.4f}\")\n",
" \n",
" # 打印缺失的类别信息\n",
" all_class_indices = set(range(len(emotion_classes)))\n",
" missing_indices = all_class_indices - set(results['present_class_indices'])\n",
" if missing_indices:\n",
" missing_classes = [emotion_classes[i] for i in missing_indices]\n",
" print(f\"\\n警告: 测试集中缺少以下类别: {missing_classes}\")\n",
" print(\"这可能是由于数据集划分不均衡或数据集太小所致\")\n",
" \n",
" print(\"\\n分类报告:\")\n",
" report = results['report']\n",
" \n",
" # 打印每个类别的指标\n",
" for class_name in sorted(report.keys()):\n",
" if class_name not in ['accuracy', 'macro avg', 'weighted avg']:\n",
" metrics = report[class_name]\n",
" print(f\"{class_name:>10}: 精确率={metrics['precision']:.4f}, 召回率={metrics['recall']:.4f}, F1分数={metrics['f1-score']:.4f}\")\n",
" \n",
" # 打印平均指标\n",
" print(\"\\n平均指标:\")\n",
" print(f\"宏平均: 精确率={report['macro avg']['precision']:.4f}, 召回率={report['macro avg']['recall']:.4f}, F1分数={report['macro avg']['f1-score']:.4f}\")\n",
" print(f\"加权平均: 精确率={report['weighted avg']['precision']:.4f}, 召回率={report['weighted avg']['recall']:.4f}, F1分数={report['weighted avg']['f1-score']:.4f}\")\n",
" \n",
" # 计算评估指标\n",
" results = evaluate_model(y_test_categorical, y_pred, emotion_classes)\n",
" print_evaluation_results(results)\n",
" \n",
" # 绘制混淆矩阵\n",
" def plot_confusion_matrix(y_true, y_pred, class_names, save_path=None, normalize=False):\n",
" \"\"\"\n",
" 绘制混淆矩阵\n",
" \n",
" Args:\n",
" y_true: 真实标签(类别索引)\n",
" y_pred: 预测标签(类别索引)\n",
" class_names: 类别名称\n",
" save_path: 保存路径\n",
" normalize: 是否归一化\n",
" \"\"\"\n",
" # 计算混淆矩阵\n",
" cm = confusion_matrix(y_true, y_pred)\n",
" \n",
" # 归一化混淆矩阵\n",
" if normalize:\n",
" cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n",
" cm = np.round(cm, 2)\n",
" \n",
" plt.figure(figsize=(10, 8))\n",
" plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)\n",
" plt.title('混淆矩阵')\n",
" plt.colorbar()\n",
" tick_marks = np.arange(len(class_names))\n",
" plt.xticks(tick_marks, class_names, rotation=45)\n",
" plt.yticks(tick_marks, class_names)\n",
" \n",
" # 在格子中添加数值\n",
" thresh = cm.max() / 2.\n",
" for i in range(cm.shape[0]):\n",
" for j in range(cm.shape[1]):\n",
" plt.text(j, i, cm[i, j],\n",
" horizontalalignment=\"center\",\n",
" color=\"white\" if cm[i, j] > thresh else \"black\")\n",
" \n",
" plt.tight_layout()\n",
" plt.ylabel('真实标签')\n",
" plt.xlabel('预测标签')\n",
" \n",
" # 如果提供了保存路径,保存图形\n",
" if save_path:\n",
" plt.savefig(save_path)\n",
" \n",
" plt.show()\n",
" \n",
" # 调用函数绘制混淆矩阵\n",
" cm_plot_path = os.path.join(model_dir, 'confusion_matrix.png')\n",
" y_true = np.argmax(y_test_categorical, axis=1)\n",
" y_pred_classes = np.argmax(y_pred, axis=1)\n",
" plot_confusion_matrix(y_true, y_pred_classes, emotion_classes, \n",
" save_path=cm_plot_path, normalize=True)\n",
" \n",
" # 同时保存原始分类报告输出以便查看\n",
" print(\"\\n详细分类报告:\")\n",
" y_true_classes = np.argmax(y_test_categorical, axis=1)\n",
" y_pred_classes = np.argmax(y_pred, axis=1)\n",
" print(classification_report(y_true_classes, y_pred_classes, target_names=emotion_classes))\n",
" \n",
" # 保存模型和相关信息\n",
" print(\"\\n保存模型和相关信息...\")\n",
" \n",
" # 保存完整模型\n",
" emotion_model.save(os.path.join(model_dir, 'emotion_model.h5'))\n",
" \n",
" # 保存标签编码器\n",
" with open(os.path.join(model_dir, 'emotion_encoder.pkl'), 'wb') as f:\n",
" pickle.dump(encoder, f)\n",
" \n",
" # 保存特征缩放器\n",
" with open(os.path.join(model_dir, 'feature_scaler.pkl'), 'wb') as f:\n",
" pickle.dump(scaler, f)\n",
" \n",
" # 保存特征名称\n",
" with open(os.path.join(model_dir, 'feature_names.pkl'), 'wb') as f:\n",
" pickle.dump(feature_names, f)\n",
" \n",
" # 绘制训练历史曲线\n",
" def plot_training_history(history, save_path=None):\n",
" \"\"\"\n",
" 绘制训练历史曲线\n",
" \n",
" Args:\n",
" history: 训练历史\n",
" save_path: 保存路径\n",
" \"\"\"\n",
" plt.figure(figsize=(12, 4))\n",
" \n",
" # 绘制准确率\n",
" plt.subplot(1, 2, 1)\n",
" plt.plot(history.history['accuracy'], label='训练准确率')\n",
" plt.plot(history.history['val_accuracy'], label='验证准确率')\n",
" plt.title('模型准确率')\n",
" plt.xlabel('轮次')\n",
" plt.ylabel('准确率')\n",
" plt.legend(loc='lower right')\n",
" plt.grid(True)\n",
" \n",
" # 绘制损失\n",
" plt.subplot(1, 2, 2)\n",
" plt.plot(history.history['loss'], label='训练损失')\n",
" plt.plot(history.history['val_loss'], label='验证损失')\n",
" plt.title('模型损失')\n",
" plt.xlabel('轮次')\n",
" plt.ylabel('损失')\n",
" plt.legend(loc='upper right')\n",
" plt.grid(True)\n",
" \n",
" plt.tight_layout()\n",
" \n",
" # 如果提供了保存路径,保存图形\n",
" if save_path:\n",
" plt.savefig(save_path)\n",
" \n",
" plt.show()\n",
" \n",
" # 绘制训练历史\n",
" history_plot_path = os.path.join(model_dir, 'training_history.png')\n",
" plot_training_history(history, save_path=history_plot_path)\n",
" \n",
" # 保存训练配置\n",
" config = {\n",
" 'sample_rate': SAMPLE_RATE,\n",
" 'max_duration': MAX_DURATION,\n",
" 'max_samples': MAX_SAMPLES,\n",
" 'input_shape': (time_steps, features),\n",
" 'num_emotions': num_emotions,\n",
" 'lstm_units': lstm_units,\n",
" 'dropout_rate': dropout_rate,\n",
" 'regularization_rate': regularization_rate,\n",
" 'learning_rate': learning_rate,\n",
" 'batch_size': batch_size,\n",
" 'epochs': epochs,\n",
" 'training_time': training_time,\n",
" 'accuracy': float(results['accuracy']),\n",
" 'classes': list(encoder.classes_),\n",
" 'num_features': len(feature_names)\n",
" }\n",
" \n",
" with open(os.path.join(model_dir, 'config.pkl'), 'wb') as f:\n",
" pickle.dump(config, f)\n",
" \n",
" print(f\"模型训练和评估完成!所有文件已保存到 '{model_dir}' 目录\")\n",
" \n",
" else:\n",
" print(\"模型或数据不可用,无法训练模型\")\n",
"except Exception as e:\n",
" print(f\"训练模型时出错: {e}\")\n",
" import traceback\n",
" traceback.print_exc()\n"
]
},
{
"cell_type": "raw",
"metadata": {
"vscode": {
"languageId": "raw"
}
},
"source": [
"## 3.3 模型预测测试\n",
"\n",
"我们将使用训练好的模型对新的音频样本进行情感预测,并可视化结果。\n"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"使用当前会话中的模型进行预测...\n",
"使用测试文件: ./RAVDESS/Actor_12\\03-01-01-01-01-01-12.wav\n",
"预测时出错: name 'extract_mfcc_features' is not defined\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Traceback (most recent call last):\n",
" File \"C:\\Users\\lenovo\\AppData\\Local\\Temp\\ipykernel_11496\\755389603.py\", line 122, in \n",
" predicted_emotion, emotion_probs = predict_emotion(\n",
" ^^^^^^^^^^^^^^^^\n",
" File \"C:\\Users\\lenovo\\AppData\\Local\\Temp\\ipykernel_11496\\755389603.py\", line 31, in predict_emotion\n",
" features = extract_all_features(audio, sr)\n",
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
" File \"C:\\Users\\lenovo\\AppData\\Local\\Temp\\ipykernel_11496\\3740659840.py\", line 31, in extract_all_features\n",
" mfcc_features = extract_mfcc_features(audio, sr)\n",
" ^^^^^^^^^^^^^^^^^^^^^\n",
"NameError: name 'extract_mfcc_features' is not defined. Did you mean: 'extract_pitch_features'?\n"
]
}
],
"source": [
"# 使用训练好的模型进行预测\n",
"def predict_emotion(audio_file, model, encoder, scaler, feature_names, sr=SAMPLE_RATE):\n",
" \"\"\"\n",
" 使用训练好的模型预测音频情感\n",
" \n",
" Args:\n",
" audio_file: 音频文件路径\n",
" model: 训练好的模型\n",
" encoder: 标签编码器\n",
" scaler: 特征缩放器\n",
" feature_names: 特征名称列表\n",
" sr: 采样率\n",
" \n",
" Returns:\n",
" emotion: 预测的情感\n",
" probabilities: 各情感类别的概率\n",
" \"\"\"\n",
" # 加载音频\n",
" audio, sr = librosa.load(audio_file, sr=sr, res_type='kaiser_fast')\n",
" \n",
" # 统一音频长度\n",
" if len(audio) < MAX_SAMPLES:\n",
" # 音频太短,用0填充\n",
" padding = MAX_SAMPLES - len(audio)\n",
" audio = np.pad(audio, (0, padding), 'constant')\n",
" else:\n",
" # 音频太长,截断\n",
" audio = audio[:MAX_SAMPLES]\n",
" \n",
" # 提取特征\n",
" features = extract_all_features(audio, sr)\n",
" \n",
" # 转换为特征矩阵\n",
" X = np.zeros((1, len(feature_names)))\n",
" for i, name in enumerate(feature_names):\n",
" if name in features:\n",
" X[0, i] = features[name]\n",
" \n",
" # 标准化特征\n",
" X_norm = scaler.transform(X)\n",
" \n",
" # 重塑为LSTM输入格式\n",
" X_reshaped = X_norm.reshape(1, 1, X_norm.shape[1])\n",
" \n",
" # 预测\n",
" predictions = model.predict(X_reshaped)[0]\n",
" \n",
" # 获取预测的情感和概率\n",
" emotion_idx = np.argmax(predictions)\n",
" emotion = encoder.inverse_transform([emotion_idx])[0]\n",
" \n",
" # 创建情感和概率的映射\n",
" emotion_probs = {}\n",
" for i, prob in enumerate(predictions):\n",
" emotion_name = encoder.inverse_transform([i])[0]\n",
" emotion_probs[emotion_name] = prob\n",
" \n",
" return emotion, emotion_probs\n",
"\n",
"# 测试预测功能\n",
"try:\n",
" # 检查模型是否已训练\n",
" if 'emotion_model' in locals() and hasattr(emotion_model, 'model'):\n",
" print(\"使用当前会话中的模型进行预测...\")\n",
" \n",
" # 选择一个测试音频文件\n",
" test_file = None\n",
" \n",
" # 首先尝试从RAVDESS中选择一个测试文件\n",
" ravdess_test_files = [f for f in os.listdir('./RAVDESS/Actor_12') if f.endswith('.wav')]\n",
" if ravdess_test_files:\n",
" test_file = os.path.join('./RAVDESS/Actor_12', ravdess_test_files[0])\n",
" \n",
" # 如果没有RAVDESS文件,尝试从SAVEE中选择\n",
" if not test_file:\n",
" if os.path.exists('./SAVEE/AudioData/DC'):\n",
" savee_test_files = [f for f in os.listdir('./SAVEE/AudioData/DC') if f.endswith('.wav')]\n",
" if savee_test_files:\n",
" test_file = os.path.join('./SAVEE/AudioData/DC', savee_test_files[0])\n",
" \n",
" # 如果没有SAVEE文件,尝试从CASIA中选择\n",
" if not test_file:\n",
" if os.path.exists('./CAISA/liuchanhg/angry'):\n",
" casia_test_files = [f for f in os.listdir('./CAISA/liuchanhg/angry') if f.endswith('.wav')]\n",
" if casia_test_files:\n",
" test_file = os.path.join('./CAISA/liuchanhg/angry', casia_test_files[0])\n",
" \n",
" if test_file:\n",
" print(f\"使用测试文件: {test_file}\")\n",
" \n",
" # 获取文件的真实情感(根据文件路径猜测)\n",
" true_emotion = None\n",
" if 'RAVDESS' in test_file:\n",
" # RAVDESS文件名格式: 03-01-05-01-02-01-12.wav\n",
" file_name = os.path.basename(test_file)\n",
" parts = file_name.split('-')\n",
" if len(parts) >= 3:\n",
" emotion = parts[2]\n",
" if emotion in EMOTION_MAPPING:\n",
" true_emotion = EMOTION_MAPPING[emotion]\n",
" elif 'SAVEE' in test_file:\n",
" # SAVEE文件名格式: a01.wav, sa01.wav, ...\n",
" file_name = os.path.basename(test_file)\n",
" if file_name.startswith(\"sa\"):\n",
" emotion = \"sa\"\n",
" elif file_name.startswith(\"su\"):\n",
" emotion = \"su\"\n",
" else:\n",
" emotion = file_name[0]\n",
" \n",
" if emotion in EMOTION_MAPPING:\n",
" true_emotion = EMOTION_MAPPING[emotion]\n",
" elif 'CAISA' in test_file:\n",
" # CASIA目录结构: ./CAISA/person/emotion/file.wav\n",
" path_parts = test_file.split(os.sep)\n",
" if len(path_parts) >= 3:\n",
" emotion = path_parts[-2]\n",
" if emotion in EMOTION_MAPPING:\n",
" true_emotion = EMOTION_MAPPING[emotion]\n",
" \n",
" # 预测情感\n",
" predicted_emotion, emotion_probs = predict_emotion(\n",
" test_file, \n",
" emotion_model.model, \n",
" encoder, \n",
" scaler, \n",
" feature_names\n",
" )\n",
" \n",
" print(f\"\\n预测情感: {predicted_emotion}\")\n",
" if true_emotion:\n",
" print(f\"真实情感: {true_emotion}\")\n",
" print(f\"预测正确: {predicted_emotion == true_emotion}\")\n",
" \n",
" # 显示各情感概率\n",
" print(\"\\n各情感概率:\")\n",
" for emotion, prob in sorted(emotion_probs.items(), key=lambda x: x[1], reverse=True):\n",
" print(f\" {emotion}: {prob:.4f}\")\n",
" \n",
" # 可视化音频和预测结果\n",
" plt.figure(figsize=(15, 10))\n",
" \n",
" # 加载音频用于可视化\n",
" audio, sr = librosa.load(test_file, sr=SAMPLE_RATE)\n",
" \n",
" # 绘制波形\n",
" plt.subplot(3, 1, 1)\n",
" librosa.display.waveshow(audio, sr=sr)\n",
" plt.title(f'音频波形 - 预测情感: {predicted_emotion}' + \n",
" (f' (真实: {true_emotion})' if true_emotion else ''))\n",
" plt.xlabel('时间 (秒)')\n",
" plt.ylabel('振幅')\n",
" \n",
" # 绘制声谱图\n",
" plt.subplot(3, 1, 2)\n",
" D = librosa.amplitude_to_db(np.abs(librosa.stft(audio)), ref=np.max)\n",
" librosa.display.specshow(D, y_axis='log', x_axis='time', sr=sr)\n",
" plt.title('声谱图')\n",
" plt.colorbar(format='%+2.0f dB')\n",
" \n",
" # 绘制情感概率条形图\n",
" plt.subplot(3, 1, 3)\n",
" emotions = list(emotion_probs.keys())\n",
" probs = list(emotion_probs.values())\n",
" \n",
" # 按概率排序\n",
" sorted_indices = np.argsort(probs)[::-1]\n",
" emotions = [emotions[i] for i in sorted_indices]\n",
" probs = [probs[i] for i in sorted_indices]\n",
" \n",
" bars = plt.bar(emotions, probs, color='skyblue')\n",
" \n",
" # 如果有真实情感,高亮显示\n",
" if true_emotion and true_emotion in emotions:\n",
" true_idx = emotions.index(true_emotion)\n",
" bars[true_idx].set_color('green')\n",
" \n",
" # 高亮显示预测情感\n",
" pred_idx = emotions.index(predicted_emotion)\n",
" bars[pred_idx].set_color('red')\n",
" \n",
" plt.title('情感预测概率')\n",
" plt.xlabel('情感类别')\n",
" plt.ylabel('概率')\n",
" plt.ylim(0, 1)\n",
" \n",
" # 添加数值标签\n",
" for i, v in enumerate(probs):\n",
" plt.text(i, v + 0.02, f'{v:.2f}', ha='center')\n",
" \n",
" plt.tight_layout()\n",
" plt.show()\n",
" else:\n",
" print(\"未找到测试音频文件\")\n",
" \n",
" # 如果当前会话中没有模型,尝试加载保存的模型\n",
" elif os.path.exists('./output/emotion_model/emotion_model.h5'):\n",
" print(\"从保存的文件加载模型...\")\n",
" \n",
" # 加载模型\n",
" from tensorflow.keras.models import load_model\n",
" loaded_model = load_model('./output/emotion_model/emotion_model.h5')\n",
" \n",
" # 加载标签编码器\n",
" with open('./output/emotion_model/emotion_encoder.pkl', 'rb') as f:\n",
" loaded_encoder = pickle.load(f)\n",
" \n",
" # 加载特征缩放器\n",
" with open('./output/emotion_model/feature_scaler.pkl', 'rb') as f:\n",
" loaded_scaler = pickle.load(f)\n",
" \n",
" # 加载特征名称\n",
" with open('./output/emotion_model/feature_names.pkl', 'rb') as f:\n",
" loaded_feature_names = pickle.load(f)\n",
" \n",
" # 选择一个测试音频文件\n",
" test_file = None\n",
" \n",
" # 首先尝试从RAVDESS中选择一个测试文件\n",
" ravdess_test_files = [f for f in os.listdir('./RAVDESS/Actor_01') if f.endswith('.wav')]\n",
" if ravdess_test_files:\n",
" test_file = os.path.join('./RAVDESS/Actor_01', ravdess_test_files[0])\n",
" \n",
" if test_file:\n",
" print(f\"使用测试文件: {test_file}\")\n",
" \n",
" # 预测情感\n",
" predicted_emotion, emotion_probs = predict_emotion(\n",
" test_file, \n",
" loaded_model, \n",
" loaded_encoder, \n",
" loaded_scaler, \n",
" loaded_feature_names\n",
" )\n",
" \n",
" print(f\"\\n预测情感: {predicted_emotion}\")\n",
" \n",
" # 显示各情感概率\n",
" print(\"\\n各情感概率:\")\n",
" for emotion, prob in sorted(emotion_probs.items(), key=lambda x: x[1], reverse=True):\n",
" print(f\" {emotion}: {prob:.4f}\")\n",
" else:\n",
" print(\"未找到测试音频文件\")\n",
" else:\n",
" print(\"未找到训练好的模型,无法进行预测\")\n",
"except Exception as e:\n",
" print(f\"预测时出错: {e}\")\n",
" import traceback\n",
" traceback.print_exc()\n"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"在测试集上预测:\n",
"\u001b[1m4/4\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 10ms/step\n",
"准确率: 0.4333\n",
"\n",
"分类报告:\n",
" angry: 精确率=0.7692, 召回率=0.5000, F1分数=0.6061\n",
" fear: 精确率=0.7273, 召回率=0.4000, F1分数=0.5161\n",
" happy: 精确率=0.4000, 召回率=0.4000, F1分数=0.4000\n",
" neutral: 精确率=0.2917, 召回率=0.3500, F1分数=0.3182\n",
" sad: 精确率=0.4444, 召回率=0.4000, F1分数=0.4211\n",
" surprise: 精确率=0.3235, 召回率=0.5500, F1分数=0.4074\n",
"\n",
"平均指标:\n",
"宏平均: 精确率=0.4927, 召回率=0.4333, F1分数=0.4448\n",
"加权平均: 精确率=0.4927, 召回率=0.4333, F1分数=0.4448\n"
]
},
{
"data": {
"image/png": "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Fx2ladmnRp85cuSQt956K5DW1MFofWuZMmVMB5s2bdrIe++9JzNmzJDrrrvO0QUbAQAAAMAvxHfm4pTUvHalSpVk8ODB6T+Wi32g1qJq0KflnrqyvX/OoK5roe1M7777btNMRrvXaKB4zTXXyJdffpnuAwYAAAAAZFIgeNttt8nIkSOlevXqpn2pLmo4btw4U/6p6co8efIEykBz585tWqA+99xzaRweAAAAAKSPM+v5OdksRlzjkibw6TzAFi1aSNmyZeX77783a188//zzUqRIEdMhVB08eNCUkS5ZskTuueeejBo3AAAAACAzmsWsWbNGJk2aJLfffru5rqWgGzZsSPKYFStWmCBQO9kwPxAAAAAA3OeSMoJZs2Y1paC6eLyWihYvXlxGjx5tAsKqVatKfHy81K9f31yUP0sIAAAAAG5AquoSM4K7du0yixlq59DXX3/drA/YrFkz6dSpk8kS6oLy/sUOtYnMlClTZM+ePRf79AAAAAAAt2UEP/roI1m+fLnJAg4bNizQGKZly5by559/yldffSU9evQwXUUfe+wxkyEEAAAAAARxIKiloBrkaTCoK9vfdNNNgfu0KczSpUtNiWh4eLjpKlqyZElTGqrlogAAAADgtBCfz1yc4uRrp7o0tHTp0maZiM6dO8v7778v3377beA+XUewdu3appOo0iBQnTp1ygSPAAAAAIAgbRajdPkInQuoS0ckdt1115kSUZ0fmDNnTnObfm3Tpk36jRYAAAAAUknzcU4m5XwSxIGguvnmm+XEiRNJbqtWrZqZO+gPAlXevHnNwvIAAAAAgCBdRzCxbNmyJbmucwPz5Mljvk9ISJADBw6kfXQAAAAAAGcDwe3btyeZ86floV26dEnymI0bN5q5hLrEBAAAAAC4hc/nc/wSdIHg6dOnpU+fPknmBoaFhZmGMCouLk4++OAD6d+/v8TExEjjxo0zZsQAAAAAgMyZIxgaGmq+RkZGBm4LCQkJrCe4d+9emT17trRv315uueUWcx8AAAAAwH0uuVlMREREircXLVpUxowZkyRQBAAAAADX8DnbNVR8QRwIJq9rPX78uHTr1i3Fx+bIkUO6d+8uVapUSf0IAQAAAADOLx+RWNasWeWBBx4453btHPr111/LV199RSAIAAAAwHEhPp+5OMXJ105zIKgBXpInyJJFateubb7/5Zdf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",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA4gAAAMrCAYAAAALOLyOAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAvTBJREFUeJzs3Qd8FNXax/H/pgdC770joQjSpKgo2AUVsVwUKSKKImBDRV8RC3pR1MsVsKGggBeQJkXFBvZC7733DumFJO/nnJhNIRVJtv2+fsbszOzMzuywkzz7POccR0pKSooAAAAAAD7Pz9UHAAAAAABwDwSIAAAAAACLABEAAAAAYBEgAgAAAAAsAkQAAAAAgEWACAAAAACwCBABAAAAABYBIgAAAADAIkAEAAAAAFgEiADgxeLj45WQkCBv9MMPP7j9uS1fvlwxMTFF9nqHDh1SYmJikb0eAMD7ECACgBerXLmybrjhBrmb//73v/q///s/HThwwLls/vz56tq1qzZt2pTn9tu3b9f111+vq6++WidPnrTLvvrqKzkcjjynW2+9Ndt9Jicna/369ecsnz59ur777julpKRkWr5t2za1bt1aEydOzPE4//Wvf6lWrVo6ceKE/om4uDgdP378nOns2bOZnjd48GCVLVtW33///T96PQCA7wpw9QEAAApPaGioQkJCdPDgQRvoBAcHKygoyAZK2TEBV+3atQv1mEyg9c4779ig6eGHH3YuP3LkiBYtWqSXX345z33Ur1/fBplm+yuvvNIGcOa8jFmzZqlJkyY5Bmxpz8tq2LBhdp+vvfaannjiCfsemQzsm2++aTOBF110kR566CH17t1bM2fO1JNPPqkKFSrY8zFZu8DAwHOC2B07duipp55SuXLlMq3bs2ePWrVqleP7YwLCpk2b6s8//7TLPvroIz3yyCOZnmde7/DhwzYgTPPXX3/ZY+rUqVOe7yEAANkhQAQALzF58mT169dP8+bN0y233GKXmWAoICBAe/futUGPmTdBop9f5gISU6oZGxtrA7TCDhDN8Zng6Y033lDVqlWdy9MCrKzBq8kyFi9eXKVLl860fODAgfaYH3/8cT399NPq37+/XW4ydo0aNcr2tU2wbM4/O0OHDtUvv/xiA8Uff/xRn376qcqUKaNly5Zpy5Ytev/99zVixAj7PiYlJalXr1768MMP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qvsN9t7/3rILLuqQaT8D/rB3735LSNib6rZdu/Zavry5bdPW9Pel6x541bZu3+n/fnT4ROtxaVPr/+Iku7lP6pLx8PuAaEEGMQ2N8AXldjg4nXBu/D31aFry9m2WK3euf/R6hfz11oeub/8Xr4XDU6RoUVu/bl2q27Zt3ZoqOEiraJrnbA17vL/e+oPfh8zDPhk/ChQqbFs3pt6WO5O3W2Kuv//9j3/hCc80XnLLPaHb8uv1Nv3+12tt3245E9mWma1wkaK2Yf1f+5Bs33bo46ECx3Vhx9bt27al+/jixUvYaqozssTGLduteOECqW4rkD+P7d67L8Ovse73rVamxFGHfR+QrQPE7777zm677Tbr1KmT3XvvvbZ69WqbOnWqPfDAA6HHrF271jp0+GukTPfpMe+++6716NHDZs/+o05/7Nix9uijj1rv3r2tS5cuNnjw4FQZjPSe93clptOnT/fbO3fubH369PEyu8C0adPs5ptvtm7dutlrr70W9/MCapxcx7795qvQ9eVLf/MuikcVLvoPX692qtf78YdvrWSpg5ej4siqW7eezZz5Zej6b4sXe/c9BYHpqVevns2c8ddzvp07x8qU+aNUsU6d9O9D5mGfjB8VTzjZFn7/1+fSuhVLbc+eXR44Hso3n06yD1993m567NnQ/EU5Ls3rqXlNkZJ/P38K/06t2nXsm69nhK4vXbLYdu3e5YFjek6uXde+/PKv4+cP38210keXsR07dthZDWv718A3X8+0smXLZeJPgMCseUut/kl/lf6WL1PM8uRKtN83bz/k88qU/Cvo0/OXrfpjoGbqS7db2VKFD3ofssYfjWIi+V/0i4oS06eeesratGljDRs29DWARo8ebbVq1frb502aNMny589v1157rVWqVCl0+9y5cz2Yq1q1qj399NM2ZswY69q1698+Lz06KA8ZMsRuvPFGq1Klir3wwgseYF522WU2f/58GzZsmN1+++1WvHhx69u3r5UtW9bOOOOvBg/h9uzZ45fweQlJSUmWI8H8EgvqNTjdtm/bYuPHvmztLulszz/d3xo0bmq5EnPals2bLH+Bgp6JDQQ/l74GP2L4z3puqwusU9tzrHO3HnZMufL22ovDrM2Fl8TM7yOWNWp8hs8bHDXyRbviyq72336P2plnnf3nXJlNVrBg6m0pF110kZ1++ul2w023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",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 在测试集上进行预测和评估\n",
"try:\n",
" # 导入必要的模块\n",
" from sklearn.metrics import confusion_matrix, classification_report, accuracy_score\n",
" \n",
" # 加载模型\n",
" print(\"\\n在测试集上预测:\")\n",
" y_pred = emotion_model.model.predict(X_test_reshaped)\n",
" \n",
" # 使用测试集评估模型\n",
" # 定义模型评估函数\n",
" def evaluate_model(y_true, y_pred, class_names):\n",
" \"\"\"\n",
" 评估模型性能\n",
" \n",
" Args:\n",
" y_true: 真实标签(独热编码)\n",
" y_pred: 预测标签(概率)\n",
" class_names: 类别名称\n",
" \n",
" Returns:\n",
" results: 评估结果字典\n",
" \"\"\"\n",
" # 将独热编码转换为类别索引\n",
" y_true_classes = np.argmax(y_true, axis=1)\n",
" y_pred_classes = np.argmax(y_pred, axis=1)\n",
" \n",
" # 计算混淆矩阵\n",
" cm = confusion_matrix(y_true_classes, y_pred_classes)\n",
" \n",
" # 计算每个类别的精确率、召回率和F1分数\n",
" report = classification_report(y_true_classes, y_pred_classes, \n",
" target_names=class_names, output_dict=True)\n",
" \n",
" # 计算准确率\n",
" accuracy = accuracy_score(y_true_classes, y_pred_classes)\n",
" \n",
" # 获取存在于测试集中的类别索引\n",
" present_class_indices = sorted(np.unique(y_true_classes))\n",
" \n",
" # 返回结果\n",
" results = {\n",
" 'confusion_matrix': cm,\n",
" 'report': report,\n",
" 'accuracy': accuracy,\n",
" 'present_class_indices': present_class_indices\n",
" }\n",
" \n",
" return results\n",
" \n",
" # 获取模型的类别名称\n",
" emotion_classes = encoder.classes_\n",
" \n",
" # 评估模型\n",
" results = evaluate_model(y_test_categorical, y_pred, emotion_classes)\n",
" \n",
" # 打印评估结果\n",
" print(f\"准确率: {results['accuracy']:.4f}\")\n",
" \n",
" print(\"\\n分类报告:\")\n",
" report = results['report']\n",
" \n",
" # 打印每个类别的指标\n",
" for class_name in sorted(report.keys()):\n",
" if class_name not in ['accuracy', 'macro avg', 'weighted avg']:\n",
" metrics = report[class_name]\n",
" print(f\"{class_name:>10}: 精确率={metrics['precision']:.4f}, 召回率={metrics['recall']:.4f}, F1分数={metrics['f1-score']:.4f}\")\n",
" \n",
" # 打印平均指标\n",
" print(\"\\n平均指标:\")\n",
" print(f\"宏平均: 精确率={report['macro avg']['precision']:.4f}, 召回率={report['macro avg']['recall']:.4f}, F1分数={report['macro avg']['f1-score']:.4f}\")\n",
" print(f\"加权平均: 精确率={report['weighted avg']['precision']:.4f}, 召回率={report['weighted avg']['recall']:.4f}, F1分数={report['weighted avg']['f1-score']:.4f}\")\n",
" \n",
" # 绘制混淆矩阵\n",
" plt.figure(figsize=(10, 8))\n",
" cm = results['confusion_matrix']\n",
" \n",
" # 使用matplotlib方式绘制混淆矩阵\n",
" plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)\n",
" plt.title('混淆矩阵')\n",
" plt.colorbar()\n",
" tick_marks = np.arange(len(emotion_classes))\n",
" plt.xticks(tick_marks, emotion_classes, rotation=45)\n",
" plt.yticks(tick_marks, emotion_classes)\n",
" \n",
" # 在格子中添加数值\n",
" thresh = cm.max() / 2.\n",
" for i in range(cm.shape[0]):\n",
" for j in range(cm.shape[1]):\n",
" plt.text(j, i, cm[i, j],\n",
" horizontalalignment=\"center\",\n",
" color=\"white\" if cm[i, j] > thresh else \"black\")\n",
" \n",
" plt.tight_layout()\n",
" plt.ylabel('真实标签')\n",
" plt.xlabel('预测标签')\n",
" plt.show()\n",
" \n",
" # 绘制归一化的混淆矩阵\n",
" plt.figure(figsize=(10, 8))\n",
" cm_normalized = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n",
" cm_normalized = np.round(cm_normalized, 2)\n",
" \n",
" plt.imshow(cm_normalized, interpolation='nearest', cmap=plt.cm.Blues)\n",
" plt.title('归一化混淆矩阵')\n",
" plt.colorbar()\n",
" tick_marks = np.arange(len(emotion_classes))\n",
" plt.xticks(tick_marks, emotion_classes, rotation=45)\n",
" plt.yticks(tick_marks, emotion_classes)\n",
" \n",
" # 在格子中添加数值\n",
" for i in range(cm_normalized.shape[0]):\n",
" for j in range(cm_normalized.shape[1]):\n",
" plt.text(j, i, f\"{cm_normalized[i, j]:.2f}\",\n",
" horizontalalignment=\"center\",\n",
" color=\"white\" if cm_normalized[i, j] > 0.5 else \"black\")\n",
" \n",
" plt.tight_layout()\n",
" plt.ylabel('真实标签')\n",
" plt.xlabel('预测标签')\n",
" plt.show()\n",
" \n",
"except Exception as e:\n",
" print(f\"评估模型时出错: {e}\")\n",
" import traceback\n",
" traceback.print_exc()\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}