File size: 2,336 Bytes
2b668de
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
"""
===============================================================================
features/augmentation.py — Data Augmentation for Training
===============================================================================

"""

import numpy as np
from config import FREQ_MASK_PARAM, TIME_MASK_PARAM, NOISE_STD, AUGMENT_PROB

AUGMENT_PROB = 0.5         # 50% chance to apply each augmentation independently
FREQ_MASK_PARAM = 24       # Max number of consecutive frequency bins to mask (out of 128)
TIME_MASK_PARAM = 40       # Max number of consecutive time frames to mask 
NOISE_STD = 0.05           # Standard deviation of the Gaussian noise

# note regarding the noise the random noise might push data over the limit we made 
# in the mel spectro gram to be between 0 and 1 so will need to clip

def apply_augmentation(mel_spec):
    """
    Apply data augmentation to a mel spectrogram (training only).

    Notes
    -----
    - This function creates a COPY of the input — the original is not modified.
    - Each call produces a DIFFERENT augmentation due to randomness.
      So each epoch, the same sample looks slightly different → diversity.
    - The augmentation is seeded by numpy's global RNG. For reproducibility
      across runs, set np.random.seed() in the training script.

    """
    augmented = mel_spec.copy()
    n_mels, time_frames = augmented.shape

    # Frequency Masking (SpecAugment) 
    if np.random.random() < AUGMENT_PROB:
        f = np.random.randint(0, FREQ_MASK_PARAM)  # Width of freq mask
        f0 = np.random.randint(0, n_mels - f)      # Starting freq bin
        augmented[f0:f0 + f, :] = 0.0              # Zero out the horizontal band

    # Time Masking (SpecAugment) 
    if np.random.random() < AUGMENT_PROB:
        t = np.random.randint(0, TIME_MASK_PARAM)    # Width of time mask
        t0 = np.random.randint(0, time_frames - t)   # Starting time frame
        augmented[:, t0:t0 + t] = 0.0                # Zero out the vertical block

    # Gaussian Noise Injection 
    if np.random.random() < AUGMENT_PROB:
        noise = np.random.normal(0, NOISE_STD, augmented.shape)
        augmented = augmented + noise
        
        # Safety clip to ensure noise doesn't break the [0, 1] normalization bounds
        augmented = np.clip(augmented, 0.0, 1.0)

    return augmented