基于深度学习的婴儿哭声识别 | 从数据预处理到模型训练全流程实战【附源码+数据集】

简介: 本文详解婴儿哭声识别全流程:基于Cry Sense数据集,涵盖音频格式转换、采样率统一(16kHz)、数据增强(时域/频域)、梅尔频谱/MFCC特征提取及数据集划分。附完整源码与数据集,助力构建智能监护系统。

基于深度学习的婴儿哭声识别 | 从数据预处理到模型训练全流程实战【附源码+数据集】

本文将详细介绍如何使用Python对Cry Sense婴儿哭声数据集进行完整的预处理流程,包括音频格式统一、采样率标准化、数据增强、特征提取等关键步骤。通过本文,你将掌握音频数据处理的核心技术,为构建智能婴儿监护系统打下坚实基础。

本文涉及的完整工程项目源码和数据集
链接: https://pan.baidu.com/s/1hbyttsWzbhxklidNjbQ1aw?pwd=zcd9
提取码: zcd9

一、项目背景与意义

1.1 为什么需要婴儿哭声识别?

对于新手父母来说,理解婴儿的需求是一项巨大的挑战。婴儿通过哭声来表达各种需求,包括饥饿、疼痛、困倦、需要拍嗝等。据统计,一个新生儿平均每天哭泣1-4小时,而父母往往需要花费数周甚至数月的时间才能准确识别不同类型的哭声。

智能婴儿哭声识别系统的价值:

  • 🍼 即时响应:帮助父母快速识别婴儿需求,减少猜测时间
  • 👨‍⚕️ 健康监测:及时发现异常哭声,辅助医疗诊断
  • 📱 智能监护:集成到婴儿监护设备,实现24小时智能监控
  • 📊 数据记录:追踪婴儿行为模式,提供育儿建议

在这里插入图片描述
在这里插入图片描述

1.2 Cry Sense数据集介绍

Cry Sense数据集是一个精心整理的婴儿哭声音频数据集,包含1,044个标注好的婴儿哭声录音,分为8个情感和身体状态类别

类别 文件数量 描述
hungry 382 饥饿引起的哭声(最常见)
discomfort 138 一般不适(如尿布湿了、衣服太紧)
tired 136 困倦或疲惫引起的哭声
belly_pain 124 腹痛、胀气或消化不适
burping 118 需要拍嗝后的哭声
cold_hot 115 过冷或过热引起的哭声
scared 20 恐惧或突然刺激引起的哭声
lonely 11 与照顾者分离引起的哭声

数据集特点:

  • 音频格式:主要为.wav格式,部分为.3gp、.ogg等
  • 采样率:8kHz和44.1kHz两种
  • 时长:平均6.36秒,范围4.15-8.73秒
  • 许可证:CC BY-SA 4.0,可自由使用

在这里插入图片描述

二、数据预处理流程架构

flowchart TD
    A[原始音频数据] --> B[数据探索与元数据提取]
    B --> C{格式检查}
    C -->|非WAV格式| D[格式转换<br/>3gp/ogg/mp3 → WAV]
    C -->|WAV格式| E[采样率标准化<br/>统一为16kHz]
    D --> E
    E --> F[音频质量检查]
    F --> G[数据增强]
    G --> H[时域增强<br/>时间拉伸/压缩]
    G --> I[频域增强<br/>音高变换/加噪]
    H --> J[特征提取]
    I --> J
    J --> K[梅尔频谱图<br/>Mel Spectrogram]
    J --> L[MFCC特征]
    J --> M[时频图<br/>STFT]
    K --> N[数据集划分]
    L --> N
    M --> N
    N --> O[训练集 70%]
    N --> P[验证集 15%]
    N --> Q[测试集 15%]
    O --> R[模型训练]
    P --> R
    Q --> S[模型评估]

    style A fill:#e1f5fe
    style R fill:#c8e6c9
    style S fill:#ffccbc

三、环境准备与依赖安装

3.1 核心依赖库

# 音频处理
librosa==0.10.1          # 音频特征提取
soundfile==0.12.1        # 音频读写
pydub==0.25.1            # 音频格式转换
audioread==3.0.1         # 音频解码

# 数据处理
numpy==1.24.3
pandas==2.0.3
scikit-learn==1.3.0

# 可视化
matplotlib==3.7.2
seaborn==0.12.2

# 深度学习(可选)
torch==2.0.1
torchaudio==2.0.2
tensorflow==2.13.0

3.2 安装FFmpeg(格式转换必需)

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install ffmpeg

# macOS
brew install ffmpeg

# Windows
# 下载地址:https://ffmpeg.org/download.html
# 添加到系统PATH环境变量

四、完整代码实现

4.1 数据探索与元数据提取

import os
import glob
import pandas as pd
import numpy as np
import librosa
import soundfile as sf
from tqdm import tqdm
import matplotlib.pyplot as plt
import seaborn as sns

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

class BabyCryDataExplorer:
    """婴儿哭声数据探索类"""

    def __init__(self, data_dir):
        self.data_dir = data_dir
        self.metadata = []

    def scan_audio_files(self):
        """扫描所有音频文件并提取元数据"""
        audio_extensions = ['*.wav', '*.3gp', '*.ogg', '*.mp3', '*.m4a']

        for ext in audio_extensions:
            pattern = os.path.join(self.data_dir, '**', ext)
            files = glob.glob(pattern, recursive=True)

            for file_path in tqdm(files, desc=f'扫描 {ext}'):
                try:
                    # 获取音频信息
                    info = sf.info(file_path)
                    duration = info.duration
                    sample_rate = info.samplerate

                    # 提取类别(从路径中)
                    category = os.path.basename(os.path.dirname(file_path))

                    self.metadata.append({
   
                        'file_path': file_path,
                        'filename': os.path.basename(file_path),
                        'category': category,
                        'duration': duration,
                        'sample_rate': sample_rate,
                        'format': ext.replace('*.', '')
                    })
                except Exception as e:
                    print(f"处理文件失败 {file_path}: {e}")

        return pd.DataFrame(self.metadata)

    def analyze_distribution(self, df):
        """分析数据分布"""
        print("=" * 60)
        print("数据集统计信息")
        print("=" * 60)
        print(f"\n总文件数: {len(df)}")
        print(f"类别数: {df['category'].nunique()}")
        print(f"\n类别分布:")
        print(df['category'].value_counts())
        print(f"\n采样率分布:")
        print(df['sample_rate'].value_counts())
        print(f"\n格式分布:")
        print(df['format'].value_counts())
        print(f"\n时长统计:")
        print(df['duration'].describe())

        # 可视化
        fig, axes = plt.subplots(2, 2, figsize=(15, 10))

        # 类别分布
        df['category'].value_counts().plot(kind='bar', ax=axes[0,0])
        axes[0,0].set_title('类别分布')
        axes[0,0].tick_params(axis='x', rotation=45)

        # 采样率分布
        df['sample_rate'].value_counts().plot(kind='bar', ax=axes[0,1])
        axes[0,1].set_title('采样率分布')

        # 时长分布
        df['duration'].hist(bins=30, ax=axes[1,0])
        axes[1,0].set_title('音频时长分布')
        axes[1,0].set_xlabel('时长 (秒)')

        # 格式分布
        df['format'].value_counts().plot(kind='pie', ax=axes[1,1])
        axes[1,1].set_title('音频格式分布')

        plt.tight_layout()
        plt.savefig('data_distribution.png', dpi=300)
        plt.show()

# 使用示例
explorer = BabyCryDataExplorer('/kaggle/input/baby-cry/cry')
df = explorer.scan_audio_files()
explorer.analyze_distribution(df)

4.2 音频格式统一与标准化

from pydub import AudioSegment
import shutil

class AudioPreprocessor:
    """音频预处理类"""

    def __init__(self, target_sr=16000, target_duration=7.0):
        self.target_sr = target_sr  # 目标采样率
        self.target_duration = target_duration  # 目标时长(秒)

    def convert_to_wav(self, input_path, output_path):
        """将各种格式转换为标准WAV格式"""
        try:
            ext = os.path.splitext(input_path)[1].lower()

            if ext == '.wav':
                # 已经是WAV,直接复制
                shutil.copy(input_path, output_path)
            elif ext in ['.3gp', '.3gpp']:
                # 转换3GP格式
                audio = AudioSegment.from_file(input_path, format='3gp')
                audio.export(output_path, format='wav')
            elif ext == '.ogg':
                audio = AudioSegment.from_ogg(input_path)
                audio.export(output_path, format='wav')
            elif ext == '.mp3':
                audio = AudioSegment.from_mp3(input_path)
                audio.export(output_path, format='wav')
            elif ext == '.m4a':
                audio = AudioSegment.from_file(input_path, format='m4a')
                audio.export(output_path, format='wav')
            else:
                # 尝试通用方法
                audio = AudioSegment.from_file(input_path)
                audio.export(output_path, format='wav')

            return True
        except Exception as e:
            print(f"转换失败 {input_path}: {e}")
            return False

    def resample_audio(self, input_path, output_path):
        """重采样到目标采样率并标准化时长"""
        try:
            # 加载音频
            y, sr = librosa.load(input_path, sr=self.target_sr, mono=True)

            # 标准化时长
            target_length = int(self.target_sr * self.target_duration)

            if len(y) > target_length:
                # 截断
                y = y[:target_length]
            elif len(y) < target_length:
                # 填充(零填充或重复)
                padding = target_length - len(y)
                y = np.pad(y, (0, padding), mode='constant')

            # 保存
            sf.write(output_path, y, self.target_sr)
            return True
        except Exception as e:
            print(f"重采样失败 {input_path}: {e}")
            return False

    def normalize_audio(self, input_path, output_path):
        """音频归一化"""
        try:
            y, sr = librosa.load(input_path, sr=None)

            # 归一化到[-1, 1]范围
            y = y / np.max(np.abs(y))

            # 可选:预加重
            y = librosa.effects.preemphasis(y)

            sf.write(output_path, y, sr)
            return True
        except Exception as e:
            print(f"归一化失败 {input_path}: {e}")
            return False

    def process_dataset(self, input_dir, output_dir):
        """批量处理整个数据集"""
        os.makedirs(output_dir, exist_ok=True)

        # 获取所有音频文件
        audio_files = []
        for ext in ['*.wav', '*.3gp', '*.ogg', '*.mp3', '*.m4a']:
            audio_files.extend(glob.glob(os.path.join(input_dir, '**', ext), recursive=True))

        print(f"找到 {len(audio_files)} 个音频文件")

        processed_count = 0
        failed_files = []

        for file_path in tqdm(audio_files, desc='处理音频'):
            # 确定输出路径
            rel_path = os.path.relpath(file_path, input_dir)
            category = os.path.dirname(rel_path)
            filename = os.path.splitext(os.path.basename(file_path))[0] + '.wav'

            category_dir = os.path.join(output_dir, category)
            os.makedirs(category_dir, exist_ok=True)

            output_path = os.path.join(category_dir, filename)

            # 处理流程
            temp_path = output_path + '.temp.wav'

            # 1. 格式转换
            if not self.convert_to_wav(file_path, temp_path):
                failed_files.append(file_path)
                continue

            # 2. 重采样和时长标准化
            if not self.resample_audio(temp_path, output_path):
                failed_files.append(file_path)
                continue

            # 清理临时文件
            if os.path.exists(temp_path):
                os.remove(temp_path)

            processed_count += 1

        print(f"\n处理完成!")
        print(f"成功: {processed_count}/{len(audio_files)}")
        print(f"失败: {len(failed_files)}")

        if failed_files:
            with open('failed_files.txt', 'w') as f:
                for ff in failed_files:
                    f.write(ff + '\n')

        return processed_count

# 使用示例
preprocessor = AudioPreprocessor(target_sr=16000, target_duration=7.0)
preprocessor.process_dataset(
    input_dir='/kaggle/input/baby-cry/cry',
    output_dir='/kaggle/working/processed_audio'
)

4.3 数据增强策略

import random

class AudioAugmenter:
    """音频数据增强类"""

    def __init__(self, sr=16000):
        self.sr = sr

    def time_stretch(self, y, rate_range=(0.8, 1.2)):
        """时间拉伸/压缩"""
        rate = random.uniform(*rate_range)
        return librosa.effects.time_stretch(y, rate=rate)

    def pitch_shift(self, y, n_steps_range=(-2, 2)):
        """音高变换"""
        n_steps = random.uniform(*n_steps_range)
        return librosa.effects.pitch_shift(y, sr=self.sr, n_steps=n_steps)

    def add_noise(self, y, noise_factor_range=(0.001, 0.01)):
        """添加高斯噪声"""
        noise_factor = random.uniform(*noise_factor_range)
        noise = np.random.randn(len(y))
        return y + noise_factor * noise

    def time_shift(self, y, shift_max=0.2):
        """时间平移"""
        shift = int(self.sr * shift_max * random.uniform(-1, 1))
        return np.roll(y, shift)

    def volume_adjust(self, y, gain_range=(0.8, 1.2)):
        """音量调整"""
        gain = random.uniform(*gain_range)
        return y * gain

    def augment(self, y, augmentations=None):
        """应用随机增强"""
        if augmentations is None:
            augmentations = ['time_stretch', 'pitch_shift', 'add_noise', 
                           'time_shift', 'volume_adjust']

        # 随机选择1-3种增强
        num_augmentations = random.randint(1, 3)
        selected = random.sample(augmentations, num_augmentations)

        for aug in selected:
            if aug == 'time_stretch':
                y = self.time_stretch(y)
            elif aug == 'pitch_shift':
                y = self.pitch_shift(y)
            elif aug == 'add_noise':
                y = self.add_noise(y)
            elif aug == 'time_shift':
                y = self.time_shift(y)
            elif aug == 'volume_adjust':
                y = self.volume_adjust(y)

        return y

    def generate_augmented_dataset(self, input_dir, output_dir, 
                                   augment_factor=2):
        """生成增强数据集"""
        os.makedirs(output_dir, exist_ok=True)

        wav_files = glob.glob(os.path.join(input_dir, '**', '*.wav'), 
                             recursive=True)

        for file_path in tqdm(wav_files, desc='数据增强'):
            # 加载原始音频
            y, sr = librosa.load(file_path, sr=self.sr)

            # 确定输出路径
            rel_path = os.path.relpath(file_path, input_dir)
            category_dir = os.path.join(output_dir, os.path.dirname(rel_path))
            os.makedirs(category_dir, exist_ok=True)

            # 保存原始文件
            filename = os.path.basename(file_path)
            output_path = os.path.join(category_dir, filename)
            sf.write(output_path, y, self.sr)

            # 生成增强样本
            base_name = os.path.splitext(filename)[0]
            for i in range(augment_factor):
                y_aug = self.augment(y.copy())
                aug_filename = f"{base_name}_aug{i+1}.wav"
                aug_path = os.path.join(category_dir, aug_filename)
                sf.write(aug_path, y_aug, self.sr)

# 使用示例
augmenter = AudioAugmenter(sr=16000)
augmenter.generate_augmented_dataset(
    input_dir='/kaggle/working/processed_audio',
    output_dir='/kaggle/working/augmented_audio',
    augment_factor=2
)

4.4 特征提取

class FeatureExtractor:
    """音频特征提取类"""

    def __init__(self, sr=16000, n_mels=128, n_mfcc=40, 
                 n_fft=2048, hop_length=512):
        self.sr = sr
        self.n_mels = n_mels
        self.n_mfcc = n_mfcc
        self.n_fft = n_fft
        self.hop_length = hop_length

    def extract_mel_spectrogram(self, y):
        """提取梅尔频谱图"""
        mel_spec = librosa.feature.melspectrogram(
            y=y, 
            sr=self.sr,
            n_fft=self.n_fft,
            hop_length=self.hop_length,
            n_mels=self.n_mels
        )
        # 转换为对数刻度
        log_mel_spec = librosa.power_to_db(mel_spec, ref=np.max)
        return log_mel_spec

    def extract_mfcc(self, y):
        """提取MFCC特征"""
        mfcc = librosa.feature.mfcc(
            y=y,
            sr=self.sr,
            n_mfcc=self.n_mfcc,
            n_fft=self.n_fft,
            hop_length=self.hop_length
        )
        return mfcc

    def extract_chroma(self, y):
        """提取色度特征"""
        chroma = librosa.feature.chroma_stft(
            y=y,
            sr=self.sr,
            n_fft=self.n_fft,
            hop_length=self.hop_length
        )
        return chroma

    def extract_spectral_contrast(self, y):
        """提取频谱对比度"""
        contrast = librosa.feature.spectral_contrast(
            y=y,
            sr=self.sr,
            n_fft=self.n_fft,
            hop_length=self.hop_length
        )
        return contrast

    def extract_all_features(self, y):
        """提取所有特征"""
        features = {
   
            'mel_spectrogram': self.extract_mel_spectrogram(y),
            'mfcc': self.extract_mfcc(y),
            'chroma': self.extract_chroma(y),
            'spectral_contrast': self.extract_spectral_contrast(y)
        }
        return features

    def visualize_features(self, y, sr=None):
        """可视化特征"""
        if sr is None:
            sr = self.sr

        features = self.extract_all_features(y)

        fig, axes = plt.subplots(2, 2, figsize=(15, 10))

        # 梅尔频谱图
        librosa.display.specshow(
            features['mel_spectrogram'], 
            sr=sr, 
            hop_length=self.hop_length,
            x_axis='time',
            y_axis='mel',
            ax=axes[0,0]
        )
        axes[0,0].set_title('梅尔频谱图 (Mel Spectrogram)')
        plt.colorbar(axes[0,0].collections[0], ax=axes[0,0])

        # MFCC
        librosa.display.specshow(
            features['mfcc'],
            sr=sr,
            hop_length=self.hop_length,
            x_axis='time',
            ax=axes[0,1]
        )
        axes[0,1].set_title('MFCC特征')
        plt.colorbar(axes[0,1].collections[0], ax=axes[0,1])

        # 色度特征
        librosa.display.specshow(
            features['chroma'],
            sr=sr,
            hop_length=self.hop_length,
            x_axis='time',
            y_axis='chroma',
            ax=axes[1,0]
        )
        axes[1,0].set_title('色度特征 (Chroma)')
        plt.colorbar(axes[1,0].collections[0], ax=axes[1,0])

        # 频谱对比度
        librosa.display.specshow(
            features['spectral_contrast'],
            sr=sr,
            hop_length=self.hop_length,
            x_axis='time',
            ax=axes[1,1]
        )
        axes[1,1].set_title('频谱对比度')
        plt.colorbar(axes[1,1].collections[0], ax=axes[1,1])

        plt.tight_layout()
        plt.savefig('features_visualization.png', dpi=300)
        plt.show()

        return features

# 使用示例
extractor = FeatureExtractor(sr=16000)

# 加载示例音频
y, sr = librosa.load('/kaggle/working/processed_audio/hungry/example.wav', sr=16000)

# 提取并可视化特征
features = extractor.visualize_features(y)

print(f"梅尔频谱图形状: {features['mel_spectrogram'].shape}")
print(f"MFCC形状: {features['mfcc'].shape}")

4.5 数据集划分与准备

from sklearn.model_selection import train_test_split
import json

class DatasetPreparer:
    """数据集准备类"""

    def __init__(self, data_dir, feature_type='mel_spectrogram'):
        self.data_dir = data_dir
        self.feature_type = feature_type
        self.label_map = {
   }

    def create_label_mapping(self, categories):
        """创建标签映射"""
        self.label_map = {
   cat: idx for idx, cat in enumerate(sorted(categories))}
        # 保存映射
        with open('label_mapping.json', 'w') as f:
            json.dump(self.label_map, f, indent=2)
        return self.label_map

    def prepare_dataset(self, test_size=0.15, val_size=0.15, random_state=42):
        """准备训练/验证/测试集"""
        # 获取所有文件
        audio_files = glob.glob(os.path.join(self.data_dir, '**', '*.wav'), 
                               recursive=True)

        # 提取标签
        file_paths = []
        labels = []
        categories = set()

        for file_path in audio_files:
            category = os.path.basename(os.path.dirname(file_path))
            file_paths.append(file_path)
            labels.append(category)
            categories.add(category)

        # 创建标签映射
        self.create_label_mapping(categories)
        label_ids = [self.label_map[label] for label in labels]

        # 第一次划分:分出测试集
        train_val_paths, test_paths, train_val_labels, test_labels = \
            train_test_split(
                file_paths, label_ids,
                test_size=test_size,
                random_state=random_state,
                stratify=label_ids
            )

        # 第二次划分:从训练集中分出验证集
        val_ratio = val_size / (1 - test_size)
        train_paths, val_paths, train_labels, val_labels = \
            train_test_split(
                train_val_paths, train_val_labels,
                test_size=val_ratio,
                random_state=random_state,
                stratify=train_val_labels
            )

        # 保存划分结果
        splits = {
   
            'train': {
   'paths': train_paths, 'labels': train_labels},
            'val': {
   'paths': val_paths, 'labels': val_labels},
            'test': {
   'paths': test_paths, 'labels': test_labels}
        }

        for split_name, split_data in splits.items():
            print(f"{split_name}: {len(split_data['paths'])} 样本")

        # 保存到文件
        with open('dataset_splits.json', 'w') as f:
            json.dump({
   
                'train': {
   'paths': train_paths, 'labels': train_labels},
                'val': {
   'paths': val_paths, 'labels': val_labels},
                'test': {
   'paths': test_paths, 'labels': test_labels},
                'label_map': self.label_map
            }, f, indent=2)

        return splits

    def extract_features_for_split(self, split_data, output_dir, 
                                   extractor=None):
        """为数据集划分提取特征"""
        if extractor is None:
            extractor = FeatureExtractor()

        os.makedirs(output_dir, exist_ok=True)

        features_list = []
        labels_list = []

        for file_path, label in tqdm(zip(split_data['paths'], 
                                          split_data['labels']),
                                     total=len(split_data['paths'])):
            try:
                # 加载音频
                y, sr = librosa.load(file_path, sr=extractor.sr)

                # 提取特征
                if self.feature_type == 'mel_spectrogram':
                    feature = extractor.extract_mel_spectrogram(y)
                elif self.feature_type == 'mfcc':
                    feature = extractor.extract_mfcc(y)
                else:
                    feature = extractor.extract_mel_spectrogram(y)

                features_list.append(feature)
                labels_list.append(label)

            except Exception as e:
                print(f"处理失败 {file_path}: {e}")

        # 保存为numpy数组
        X = np.array(features_list)
        y = np.array(labels_list)

        np.save(os.path.join(output_dir, f'X_{self.feature_type}.npy'), X)
        np.save(os.path.join(output_dir, 'y.npy'), y)

        print(f"特征提取完成!")
        print(f"特征形状: {X.shape}")
        print(f"标签形状: {y.shape}")

        return X, y

# 使用示例
preparer = DatasetPreparer('/kaggle/working/augmented_audio', 
                           feature_type='mel_spectrogram')

# 划分数据集
splits = preparer.prepare_dataset(test_size=0.15, val_size=0.15)

# 为每个划分提取特征
extractor = FeatureExtractor(sr=16000, n_mels=128)

for split_name, split_data in splits.items():
    print(f"\n处理 {split_name} 集...")
    X, y = preparer.extract_features_for_split(
        split_data, 
        output_dir=f'/kaggle/working/features/{split_name}',
        extractor=extractor
    )

五、完整流程整合

class BabyCryPipeline:
    """婴儿哭声数据处理完整流程"""

    def __init__(self, raw_data_dir, output_base_dir):
        self.raw_data_dir = raw_data_dir
        self.output_base_dir = output_base_dir

        # 创建输出目录结构
        self.dirs = {
   
            'processed': os.path.join(output_base_dir, 'processed_audio'),
            'augmented': os.path.join(output_base_dir, 'augmented_audio'),
            'features': os.path.join(output_base_dir, 'features'),
            'models': os.path.join(output_base_dir, 'models'),
            'visualizations': os.path.join(output_base_dir, 'visualizations')
        }

        for dir_path in self.dirs.values():
            os.makedirs(dir_path, exist_ok=True)

    def run_full_pipeline(self, augment_factor=2, feature_type='mel_spectrogram'):
        """运行完整处理流程"""

        print("=" * 60)
        print("婴儿哭声数据处理流程")
        print("=" * 60)

        # 1. 数据探索
        print("\n[1/5] 数据探索...")
        explorer = BabyCryDataExplorer(self.raw_data_dir)
        df = explorer.scan_audio_files()
        explorer.analyze_distribution(df)

        # 2. 音频预处理
        print("\n[2/5] 音频预处理(格式转换、重采样)...")
        preprocessor = AudioPreprocessor(target_sr=16000, target_duration=7.0)
        preprocessor.process_dataset(
            self.raw_data_dir,
            self.dirs['processed']
        )

        # 3. 数据增强
        print("\n[3/5] 数据增强...")
        augmenter = AudioAugmenter(sr=16000)
        augmenter.generate_augmented_dataset(
            self.dirs['processed'],
            self.dirs['augmented'],
            augment_factor=augment_factor
        )

        # 4. 数据集划分
        print("\n[4/5] 数据集划分...")
        preparer = DatasetPreparer(self.dirs['augmented'], 
                                   feature_type=feature_type)
        splits = preparer.prepare_dataset()

        # 5. 特征提取
        print("\n[5/5] 特征提取...")
        extractor = FeatureExtractor(sr=16000, n_mels=128)

        for split_name, split_data in splits.items():
            split_output_dir = os.path.join(self.dirs['features'], split_name)
            preparer.extract_features_for_split(
                split_data,
                split_output_dir,
                extractor=extractor
            )

        print("\n" + "=" * 60)
        print("处理流程完成!")
        print("=" * 60)
        print(f"\n输出目录: {self.output_base_dir}")
        print("目录结构:")
        for name, path in self.dirs.items():
            count = len(glob.glob(os.path.join(path, '**', '*'), recursive=True))
            print(f"  - {name}: {path} ({count} 文件)")

# 运行完整流程
pipeline = BabyCryPipeline(
    raw_data_dir='/kaggle/input/baby-cry/cry',
    output_base_dir='/kaggle/working'
)

pipeline.run_full_pipeline(
    augment_factor=2,
    feature_type='mel_spectrogram'
)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

六、常见问题与解决方案

6.1 格式转换问题

问题:3GP格式转换失败

# 解决方案:使用ffmpeg-python作为备选
import ffmpeg

def convert_with_ffmpeg(input_path, output_path):
    try:
        ffmpeg.input(input_path).output(output_path).run()
        return True
    except Exception as e:
        print(f"FFmpeg转换失败: {e}")
        return False

6.2 内存不足问题

问题:处理大量音频时内存溢出

# 解决方案:使用生成器分批处理
def batch_process(files, batch_size=100):
    for i in range(0, len(files), batch_size):
        yield files[i:i + batch_size]

# 使用示例
for batch in batch_process(audio_files, batch_size=100):
    process_batch(batch)
    gc.collect()  # 强制垃圾回收

6.3 类别不平衡问题

问题:hungry类别样本过多,lonely类别样本过少

# 解决方案:对少数类进行过采样
from imblearn.over_sampling import SMOTE

# 或使用数据增强增加少数类样本
minority_classes = ['lonely', 'scared']
for cls in minority_classes:
    augment_factor = 5  # 对少数类增强更多倍

在这里插入图片描述
在这里插入图片描述

七、总结与展望

7.1 本文总结

本文详细介绍了婴儿哭声数据集的完整预处理流程,包括:

  1. 数据探索:了解数据集分布、格式、质量
  2. 格式统一:将多种音频格式转换为标准WAV
  3. 采样率标准化:统一为16kHz,便于模型训练
  4. 数据增强:通过时间拉伸、音高变换等方法扩充数据
  5. 特征提取:提取梅尔频谱图、MFCC等深度学习特征
  6. 数据集划分:合理划分训练/验证/测试集

7.2 后续工作

完成数据预处理后,可以进行以下工作:

  • 模型训练:使用CNN、LSTM或Transformer模型进行分类
  • 模型优化:超参数调优、模型集成
  • 部署应用:将模型集成到移动应用或嵌入式设备
  • 实时识别:实现实时音频流处理和分类
相关文章
|
1月前
|
人工智能 监控 算法
红外无人机目标检测数据集(4500+张图片已标注)| YOLO训练数据集 AI视觉检测
本数据集含4500+张红外监控图像,专为夜间/低光照场景下无人机检测构建,采用标准YOLO格式标注(单类“drone”),已划分训练/验证/测试集,适配YOLOv5至v11等主流模型,适用于安防、边境监控、军事侦察及AI算法研究。
|
3月前
|
机器学习/深度学习 监控 算法
基于 YOLO26 的摔倒智能检测系统(中英文双版) | 附完整源码与效果演示
本文介绍了一个基于 YOLO26 的摔倒智能检测系统,该系统结合了先进的深度学习技术和友好的用户界面,实现了从数据集管理、模型训练到实时推理测试的完整工作流程。系统具有以下特点: 技术先进:采用最新的 YOLO26 目标检测算法,在精度和速度方面都达到了较高水平 易于使用:提供友好的图形界面,非专业用户也能轻松使用 功能完整:涵盖数据管理、模型训练、推理测试等完整功能 性能优异:支持 GPU 加速和多线程处理,保证高性能 可扩展性强:采用模块化设计,便于功能扩展和定制
基于 YOLO26 的摔倒智能检测系统(中英文双版) | 附完整源码与效果演示
|
3月前
|
传感器 机器学习/深度学习 安全
基于YOLOv8的道路隐患识别与城市路况安全识别|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!
项目特点在于提供 完整数据集及标注、训练代码、预训练权重和部署教程,用户可直接开箱使用或进行自定义训练。该系统兼具 高精度识别、实时性能和易用性,可广泛应用于智能交通巡检、城市道路安全管理及自动驾驶环境感知等场景,为提升城市道路安全和管理效率提供数据和技术支撑。
基于YOLOv8的道路隐患识别与城市路况安全识别|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!
|
2月前
|
弹性计算 云计算 开发者
阿里云服务器秒杀活动怎么参与?2026年入口+攻略全解
阿里云2026服务器秒杀活动火热进行中!新用户实名认证后,每日10点/15点抢购高性价比云服务器。本文详解参与资格、抢购入口、秒杀技巧及99元/年等备选方案,助个人开发者与初创企业低成本、高效率上云。
413 3
|
1月前
|
数据采集 人工智能 数据可视化
桌面 AI 智能体来了!我用 QoderWork 把一天的工作压进了一小时
阿里云QoderWork是一款本地运行的桌面AI智能体,主打“不止聊天,搞定一切”。它可直接读写本地文件、自主规划任务、一键生成Word/PPT/Excel/PDF,并支持网页抓取与自定义Skill。实测竞品调研从2天缩至11分钟,销售分析5分钟完成,真正解放双手。
|
7月前
|
人工智能 搜索推荐 程序员
实战演练:手把手构建一个“旅行规划智能体”
光说不练假把式。本文以Coze平台为例,带你五步创建“旅行规划智能体”:从命名、编写提示词,到添加插件、优化交互,直至发布测试。沉浸式体验智能体创作全流程,掌握AI时代新技能,成为智能体时代的“弄潮儿”。
|
算法 PyTorch 算法框架/工具
Pytorch学习笔记(九):Pytorch模型的FLOPs、模型参数量等信息输出(torchstat、thop、ptflops、torchsummary)
本文介绍了如何使用torchstat、thop、ptflops和torchsummary等工具来计算Pytorch模型的FLOPs、模型参数量等信息。
3260 2
|
网络协议 物联网 机器人
【毕设参考】ESP32 + HaaS Python 打造在线空气质量检测器
【毕设参考】ESP32 + HaaS Python 打造在线空气质量检测器
700 17