深度学习信号分类:滑动窗口数据增强内存溢出优化求助
优化滑动窗口数据增强的内存占用方案
我明白你现在的困境——小数据集做信号分类,想用滑动窗口扩充数据但内存直接撑爆,12GB都扛不住确实头疼。咱们来一步步优化这段代码,从根本上减少内存消耗:
1. 优先改用生成器/迭代器,按需输出数据
原代码每次循环都把临时窗口数据拼接到大数组里,而numpy数组是不可变的,每次拼接都会创建新数组、拷贝旧数据,内存占用会指数级增长。换成生成器的话,每次只生成当前样本的窗口数据,训练时按需取用,完全不用一次性把所有增强数据都塞进内存。
优化后的代码:
def sliding_window_generator(data, labels, window_sz, n_hop, n_start=0, show_status=False): for sample_idx in range(data.shape[0]): sample_data = data[sample_idx] sample_label = labels[sample_idx] # 计算当前样本的窗口起始索引 start_indices = np.arange(n_start, data.shape[1] - window_sz + n_hop, n_hop) for idx in start_indices: window = sample_data[idx:idx+window_sz, :] yield window, sample_label if sample_idx % 100 == 0 and show_status: print(f"Sample {sample_idx} processed!")
调用示例(以TensorFlow训练为例):
import tensorflow as tf # 初始化生成器 generator = sliding_window_generator( X_train, y_train, window_sz=4*fs, n_hop=fs//10, n_start=fs*1 ) # 转换为tf.data.Dataset,支持批量、打乱等操作 dataset = tf.data.Dataset.from_generator( lambda: generator, output_signature=( tf.TensorSpec(shape=(4*fs, X_train.shape[2]), dtype=tf.float32), tf.TensorSpec(shape=(), dtype=tf.int32) # 根据你的标签类型调整 ) ) dataset = dataset.shuffle(1000).batch(32) # 后续直接用dataset喂给模型训练即可 model.fit(dataset, epochs=10)
2. 若必须保留完整数组:预分配内存再填充
如果你的场景一定要得到完整的增强后数组,那不要反复拼接,先算好总窗口数,一次性分配足够大的数组,直接填充数据,避免多次内存拷贝。
优化后的代码:
def sliding_window_prealloc(data, labels, window_sz, n_hop, n_start=0, show_status=False): n_samples, seq_len, feature_dim = data.shape # 计算单个样本的窗口数量 n_windows_per_sample = len(np.arange(n_start, seq_len - window_sz + n_hop, n_hop)) total_windows = n_samples * n_windows_per_sample # 一次性分配内存,复用原数据的dtype减少开销 new_data = np.zeros((total_windows, window_sz, feature_dim), dtype=data.dtype) new_lab = np.zeros((total_windows,), dtype=labels.dtype) current_idx = 0 for sample_idx in range(n_samples): sample_data = data[sample_idx] sample_label = labels[sample_idx] start_indices = np.arange(n_start, seq_len - window_sz + n_hop, n_hop) n_windows = len(start_indices) # 批量填充当前样本的所有窗口 for i, idx in enumerate(start_indices): new_data[current_idx + i] = sample_data[idx:idx+window_sz, :] new_lab[current_idx + i] = sample_label current_idx += n_windows if sample_idx % 100 == 0 and show_status: print(f"Sample {sample_idx} processed!") return new_data, new_lab
3. 降低数据 dtype 进一步压缩内存
检查一下你的数据类型,如果是float64,可以改成float32(甚至float16,如果模型支持混合精度训练的话),内存占用直接减半:
# 转换数据类型,前提是信号精度允许 X_train = X_train.astype(np.float32) y_train = y_train.astype(np.int32) # 标签也可以按需降级
4. 极端场景:分批次保存到磁盘
如果增强后的数据量实在太大,连预分配内存都扛不住,可以分批次处理,把每一批增强数据保存到磁盘(比如用h5py),训练时再分批加载:
import h5py def sliding_window_batch_save(data, labels, window_sz, n_hop, n_start=0, batch_size=200, save_path='augmented_data.h5'): n_samples, seq_len, feature_dim = data.shape n_windows_per_sample = len(np.arange(n_start, seq_len - window_sz + n_hop, n_hop)) total_windows = n_samples * n_windows_per_sample with h5py.File(save_path, 'w') as f: # 创建预留空间的数据集 dset_data = f.create_dataset('data', shape=(total_windows, window_sz, feature_dim), dtype=data.dtype) dset_labels = f.create_dataset('labels', shape=(total_windows,), dtype=labels.dtype) current_idx = 0 for batch_start in range(0, n_samples, batch_size): batch_end = min(batch_start + batch_size, n_samples) batch_data = data[batch_start:batch_end] batch_labels = labels[batch_start:batch_end] for sample_idx_in_batch in range(batch_data.shape[0]): sample_data = batch_data[sample_idx_in_batch] sample_label = batch_labels[sample_idx_in_batch] start_indices = np.arange(n_start, seq_len - window_sz + n_hop, n_hop) n_windows = len(start_indices) for i, idx in enumerate(start_indices): dset_data[current_idx + i] = sample_data[idx:idx+window_sz, :] dset_labels[current_idx + i] = sample_label current_idx += n_windows print(f"Batch {batch_start//batch_size + 1} processed!")
训练时分批读取:
with h5py.File('augmented_data.h5', 'r') as f: data = f['data'] labels = f['labels'] # 按需读取批次数据 batch_data = data[0:32] batch_labels = labels[0:32]
内容的提问来源于stack exchange,提问作者h_h10a
相关产品推荐
相关产品推荐

