
Keras 2.x MNIST 数据预处理3 种归一化与 One-Hot 编码方案详解当你在Keras中加载MNIST数据集时原始数据是以0-255的整数形式存储的28x28像素灰度图像。这些数据需要经过预处理才能输入神经网络进行训练。本文将深入探讨三种不同的数据归一化方法以及两种标签编码方案帮助你理解每种方法的适用场景和实现细节。1. MNIST数据集基础认知MNIST数据集包含60,000张训练图像和10,000张测试图像每张都是28x28像素的手写数字灰度图。原始数据的像素值范围是0-255标签是0-9的整数。直接使用这些原始数据训练模型通常效果不佳因此我们需要进行预处理。from keras.datasets import mnist import numpy as np # 加载原始数据 (train_images, train_labels), (test_images, test_labels) mnist.load_data() print(f训练图像形状: {train_images.shape}) # (60000, 28, 28) print(f训练标签形状: {train_labels.shape}) # (60000,) print(f像素值范围: {np.min(train_images)}-{np.max(train_images)}) # 0-2552. 三种图像归一化方案对比归一化是将数据缩放到固定范围的过程有助于模型更快收敛。以下是三种常用的归一化方法2.1 简单除以255.0这是最常见的方法将像素值从0-255线性映射到0-1之间。# 方法1简单除以255.0 def normalize_divide_255(images): return images.astype(float32) / 255.0 # 实现示例 x_train_1 normalize_divide_255(train_images) x_test_1 normalize_divide_255(test_images) print(f归一化后范围: {np.min(x_train_1):.2f}-{np.max(x_train_1):.2f})特点实现简单计算速度快保持了原始数据的线性关系适用于大多数情况2.2 MinMaxScaler归一化使用sklearn的MinMaxScaler可以更灵活地控制缩放范围。from sklearn.preprocessing import MinMaxScaler # 方法2MinMaxScaler def normalize_minmax(images): scaler MinMaxScaler(feature_range(0, 1)) # 需要先将图像展平为(样本数, 784)的形状 flattened images.reshape(images.shape[0], -1) normalized scaler.fit_transform(flattened) return normalized.reshape(images.shape) # 实现示例 x_train_2 normalize_minmax(train_images) x_test_2 normalize_minmax(test_images) print(fMinMax归一化范围: {np.min(x_train_2):.2f}-{np.max(x_train_2):.2f})特点可以自定义输出范围如[-1,1]需要额外的内存存储scaler对象适合需要统一多个特征尺度的情况2.3 Z-Score标准化将数据转换为均值为0标准差为1的分布。# 方法3Z-Score标准化 def normalize_zscore(images): mean np.mean(images, axis(0,1,2), keepdimsTrue) std np.std(images, axis(0,1,2), keepdimsTrue) return (images.astype(float32) - mean) / std # 实现示例 x_train_3 normalize_zscore(train_images) x_test_3 normalize_zscore(test_images) print(fZ-Score均值: {np.mean(x_train_3):.2f}, 标准差: {np.std(x_train_3):.2f})特点对异常值更鲁棒输出范围不固定适合数据分布不均匀的情况归一化方法对比表方法公式输出范围优点缺点/255.0x/255.0[0,1]简单快速对异常值敏感MinMax(x-min)/(max-min)可自定义范围可控需要存储参数Z-Score(x-μ)/σ无固定鲁棒性强计算量较大3. 两种标签编码方案标签编码是将类别标签转换为模型可以处理的形式。MNIST有10个类别(0-9)我们需要将其转换为适合分类任务的格式。3.1 One-Hot编码将每个标签转换为长度为类别数的二进制向量。from keras.utils import to_categorical # 方法1One-Hot编码 def encode_onehot(labels, num_classes10): return to_categorical(labels, num_classes) # 实现示例 y_train_1 encode_onehot(train_labels) y_test_1 encode_onehot(test_labels) print(f原始标签: {train_labels[0]}) print(fOne-Hot编码后: {y_train_1[0]})特点明确表示类别间的互斥关系适合配合categorical_crossentropy损失函数会稍微增加内存使用3.2 整数标签直接使用0-9的整数作为标签配合稀疏分类交叉熵。# 方法2整数标签 def encode_integer(labels): return labels.astype(int32) # 实现示例 y_train_2 encode_integer(train_labels) y_test_2 encode_integer(test_labels) print(f整数标签: {y_train_2[0]})特点内存占用小适合配合sparse_categorical_crossentropy实现更简单4. 完整预处理流程示例下面展示一个结合了归一化和标签编码的完整预处理流程def preprocess_data(images, labels, normalize_methoddivide_255, encode_methodonehot): # 归一化处理 if normalize_method divide_255: images images.astype(float32) / 255.0 elif normalize_method minmax: scaler MinMaxScaler(feature_range(0, 1)) images scaler.fit_transform(images.reshape(images.shape[0], -1)) images images.reshape(images.shape[0], 28, 28) elif normalize_method zscore: mean np.mean(images, axis(0,1,2), keepdimsTrue) std np.std(images, axis(0,1,2), keepdimsTrue) images (images.astype(float32) - mean) / std # 标签编码 if encode_method onehot: labels to_categorical(labels, 10) elif encode_method integer: labels labels.astype(int32) return images, labels # 使用示例 x_train, y_train preprocess_data(train_images, train_labels, normalize_methoddivide_255, encode_methodonehot)5. 不同预处理组合的性能影响为了验证不同预处理方法的效果我们构建一个简单的全连接网络进行测试from keras.models import Sequential from keras.layers import Dense, Flatten from keras.optimizers import Adam def build_model(input_shape, output_units): model Sequential([ Flatten(input_shapeinput_shape), Dense(128, activationrelu), Dense(64, activationrelu), Dense(output_units, activationsoftmax) ]) model.compile(optimizerAdam(), losscategorical_crossentropy, metrics[accuracy]) return model # 测试不同归一化方法 normalization_methods [divide_255, minmax, zscore] results {} for method in normalization_methods: x_train, y_train preprocess_data(train_images, train_labels, normalize_methodmethod, encode_methodonehot) x_test, y_test preprocess_data(test_images, test_labels, normalize_methodmethod, encode_methodonehot) model build_model((28, 28), 10) history model.fit(x_train, y_train, validation_data(x_test, y_test), epochs10, batch_size128, verbose0) results[method] history.history[val_accuracy][-1] print(不同归一化方法的测试准确率:) for method, acc in results.items(): print(f{method}: {acc:.4f})在我的测试中三种归一化方法在MNIST上的表现差异不大/255.0方法通常能达到98.5%以上的准确率且实现最简单。选择哪种方法更多取决于具体应用场景和个人偏好。