Spaces:
Sleeping
Sleeping
File size: 6,897 Bytes
e5abc2e |
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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
"""
Data loading utilities for the Emotion Recognition System.
"""
import os
import numpy as np
from pathlib import Path
from typing import Tuple, Dict, Optional
from collections import Counter
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import sys
sys.path.append(str(Path(__file__).parent.parent.parent))
from src.config import (
TRAIN_DIR, TEST_DIR, IMAGE_SIZE, IMAGE_SIZE_TRANSFER,
BATCH_SIZE, VALIDATION_SPLIT, EMOTION_CLASSES, NUM_CLASSES,
AUGMENTATION_CONFIG
)
def create_data_generators(
use_augmentation: bool = True,
for_transfer_learning: bool = False,
batch_size: int = BATCH_SIZE,
validation_split: float = VALIDATION_SPLIT
) -> Tuple[tf.keras.preprocessing.image.DirectoryIterator,
tf.keras.preprocessing.image.DirectoryIterator,
tf.keras.preprocessing.image.DirectoryIterator]:
"""
Create data generators for training, validation, and testing.
Args:
use_augmentation: Whether to apply data augmentation for training
for_transfer_learning: If True, resize images for transfer learning models
batch_size: Batch size for generators
validation_split: Fraction of training data to use for validation
Returns:
Tuple of (train_generator, val_generator, test_generator)
"""
target_size = IMAGE_SIZE_TRANSFER if for_transfer_learning else IMAGE_SIZE
color_mode = 'rgb' if for_transfer_learning else 'grayscale'
# Training data generator with augmentation
if use_augmentation:
train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=AUGMENTATION_CONFIG["rotation_range"],
width_shift_range=AUGMENTATION_CONFIG["width_shift_range"],
height_shift_range=AUGMENTATION_CONFIG["height_shift_range"],
horizontal_flip=AUGMENTATION_CONFIG["horizontal_flip"],
zoom_range=AUGMENTATION_CONFIG["zoom_range"],
brightness_range=AUGMENTATION_CONFIG["brightness_range"],
fill_mode=AUGMENTATION_CONFIG["fill_mode"],
validation_split=validation_split
)
else:
train_datagen = ImageDataGenerator(
rescale=1./255,
validation_split=validation_split
)
# Test data generator (no augmentation)
test_datagen = ImageDataGenerator(rescale=1./255)
# Create generators
train_generator = train_datagen.flow_from_directory(
str(TRAIN_DIR),
target_size=target_size,
color_mode=color_mode,
batch_size=batch_size,
class_mode='categorical',
classes=EMOTION_CLASSES,
subset='training',
shuffle=True
)
val_generator = train_datagen.flow_from_directory(
str(TRAIN_DIR),
target_size=target_size,
color_mode=color_mode,
batch_size=batch_size,
class_mode='categorical',
classes=EMOTION_CLASSES,
subset='validation',
shuffle=False
)
test_generator = test_datagen.flow_from_directory(
str(TEST_DIR),
target_size=target_size,
color_mode=color_mode,
batch_size=batch_size,
class_mode='categorical',
classes=EMOTION_CLASSES,
shuffle=False
)
return train_generator, val_generator, test_generator
def load_dataset(
for_transfer_learning: bool = False
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
"""
Load the entire dataset into memory as numpy arrays.
Args:
for_transfer_learning: If True, resize images for transfer learning models
Returns:
Tuple of (X_train, y_train, X_test, y_test)
"""
target_size = IMAGE_SIZE_TRANSFER if for_transfer_learning else IMAGE_SIZE
color_mode = 'rgb' if for_transfer_learning else 'grayscale'
datagen = ImageDataGenerator(rescale=1./255)
# Load training data
train_gen = datagen.flow_from_directory(
str(TRAIN_DIR),
target_size=target_size,
color_mode=color_mode,
batch_size=1,
class_mode='categorical',
classes=EMOTION_CLASSES,
shuffle=False
)
# Load test data
test_gen = datagen.flow_from_directory(
str(TEST_DIR),
target_size=target_size,
color_mode=color_mode,
batch_size=1,
class_mode='categorical',
classes=EMOTION_CLASSES,
shuffle=False
)
# Extract all data
X_train = np.concatenate([train_gen[i][0] for i in range(len(train_gen))])
y_train = np.concatenate([train_gen[i][1] for i in range(len(train_gen))])
X_test = np.concatenate([test_gen[i][0] for i in range(len(test_gen))])
y_test = np.concatenate([test_gen[i][1] for i in range(len(test_gen))])
return X_train, y_train, X_test, y_test
def get_class_weights(train_generator) -> Dict[int, float]:
"""
Calculate class weights to handle class imbalance.
Args:
train_generator: Training data generator
Returns:
Dictionary mapping class indices to weights
"""
# Get class distribution
class_counts = Counter(train_generator.classes)
total_samples = sum(class_counts.values())
num_classes = len(class_counts)
# Calculate weights (inverse frequency)
class_weights = {}
for class_idx, count in class_counts.items():
class_weights[class_idx] = total_samples / (num_classes * count)
return class_weights
def get_dataset_info() -> Dict:
"""
Get information about the dataset.
Returns:
Dictionary with dataset statistics
"""
info = {
"train": {},
"test": {},
"emotion_classes": EMOTION_CLASSES,
"num_classes": NUM_CLASSES
}
# Count training samples per class
for emotion in EMOTION_CLASSES:
train_path = TRAIN_DIR / emotion
test_path = TEST_DIR / emotion
if train_path.exists():
info["train"][emotion] = len(list(train_path.glob("*.png"))) + len(list(train_path.glob("*.jpg")))
else:
info["train"][emotion] = 0
if test_path.exists():
info["test"][emotion] = len(list(test_path.glob("*.png"))) + len(list(test_path.glob("*.jpg")))
else:
info["test"][emotion] = 0
info["total_train"] = sum(info["train"].values())
info["total_test"] = sum(info["test"].values())
return info
if __name__ == "__main__":
# Test data loading
print("Dataset Information:")
info = get_dataset_info()
print(f"Total training samples: {info['total_train']}")
print(f"Total test samples: {info['total_test']}")
print("\nSamples per class (training):")
for emotion, count in info["train"].items():
print(f" {emotion}: {count}")
|