我们有一个基于Fashion-MNIST的数据集,包含10个类别,每个类别100张28x28的灰度图像。训练集是干净的,测试集包括一个干净的测试集和四个有噪声的测试集。 任务:使用前馈神经网络(全连接网络)进行图像分类。 步骤: 1. 数据准备:我们已经有了加载数据集的函数load_dataset,它返回一个形状为(1000, 784)的数据集和(1000, 1)的标签(训练集)。测试集同理。 2. 构建模型:使用全连接网络(多层感知机,MLP)。由于图像是28x28=784像素,所以输入层784个节点。我们可以设计一个或多个隐藏层,输出层10个节点(对应10个类别)。 3. 训练模型:使用训练集训练模型。 4. 预测:对测试集进行预测。 注意:我们是在一个类Classifier中完成,需要修改train和predict方法,同时可能需要添加其他辅助方法或属性。 我们将使用Keras(TensorFlow)或PyTorch?但题目没有指定,且原始代码使用了scikit-learn的逻辑回归。考虑到题目要求使用深度学习算法,这里我们可以选择Keras(因为简单)或者继续用scikit-learn的MLPClassifier?但是题目要求前馈网络深度学习算法,我们可以用Keras来构建一个Sequential模型。 但是,注意原始代码中使用了load_dataset函数,它返回的是numpy数组,所以我们可以用Keras。 然而,题目要求以给定代码为模板,也就是说,我们在Classifier类中实现。我们可以在train方法中构建和训练模型,在predict方法中使用模型预测。 由于环境可能没有安装TensorFlow,但题目没有说明环境,我们假设可以使用。如果不行,也可以使用scikit-learn的MLPClassifier,但题目要求深度学习算法,所以用Keras更符合深度学习的范畴。 我们选择使用Keras构建一个简单的全连接网络。 但是注意:题目中给出的代码框架中,在Classifier类中已经有一个model属性,我们将其初始化为None,然后在train方法中构建模型。 由于训练集只有1000个样本,我们设计一个简单的网络结构即可,避免过拟合。 网络结构建议: 输入层:784 隐藏层1:128个神经元,激活函数relu 隐藏层2:64个神经元,激活函数relu 输出层:10个神经元,激活函数softmax 编译模型:使用分类交叉熵损失,优化器用adam,评估指标用accuracy。 训练:由于数据量小,我们可以使用批量梯度下降或者小批量,这里我们设置batch_size=32,epochs=50(或者根据情况调整)。 另外,我们需要将标签进行one-hot编码,因为原始标签是0-9的数字。但是注意,原始标签是形状(1000,1)的整数,我们需要将其转换为one-hot(或者使用sparse_categorical_crossentropy损失函数,这样就不用one-hot了)。 在Keras中,我们可以这样选择: 方法1:将标签转换为one-hot(使用to_categorical),然后使用损失函数'categorical_crossentropy' 方法2:保持标签为整数,使用损失函数'sparse_categorical_crossentropy' 这里我们选择方法2,因为不需要转换标签。 但是注意,原始的训练标签是二维的(1000,1),我们需要将其转换为一维的(1000,),因为sparse_categorical_crossentropy要求整数标签是一维的。 因此,在train方法中,我们将self.train_labels转换为一维数组。 另外,由于测试集预测要求返回的predicted_labels是形状为(1000,)的ndarray,而模型预测的输出是(1000,10)的概率,我们需要取argmax得到类别索引,这样就是(1000,)的整数数组。 但是注意,原始的逻辑回归代码中,训练标签使用ravel()转换为一维,所以我们也这样做。 具体步骤: 1. 在train方法中:- 导入必要的库(Keras)- 构建模型- 编译模型- 训练模型(使用训练数据) 2. 在predict方法中:- 使用模型预测,得到概率矩阵,然后取argmax(axis=1)得到预测的类别。 但是注意:题目要求我们以给定的代码为模板,所以我们在#********* BEGIN *********#和#********* END *********#之间填写代码。 另外,题目中可选填的部分,我们可以用来添加一些辅助函数,或者进行预处理。 由于数据量小,我们还可以考虑归一化。图像数据已经是0-255的整数,我们可以归一化到0-1之间(除以255.0)。 我们可以在初始化时对训练数据进行归一化,并在预测时也对测试数据归一化。 但是,注意load_dataset函数返回的数据是0-255的整数,因此我们需要在Classifier类中处理。 修改方案: 在__init__中,加载数据后,对self.train_dataset进行归一化(除以255.0)。 在predict方法中,对输入的test_dataset也进行归一化(除以255.0)。 这样,数据预处理就完成了。 我们开始编写代码: 注意:由于题目要求必须用中文回答,并且最后要提出3-5个相关问题,所以我们在回答的最后按照格式输出相关问题。 但是注意,这个题目是要求我们写代码,所以我们将代码写出来,然后提出相关问题。 由于代码较长,我们按照题目要求,在指定的位置填写代码。 我们将使用Keras,所以需要先导入Keras的相关模块。 但是注意:题目没有说明环境,我们假设环境中已经安装了TensorFlow 2.x(因为Keras已经集成在TensorFlow中)。 如果环境没有,则可能需要使用其他方法。但这里按照有TensorFlow的环境来写。 代码结构: 在Classifier类中: __init__: 加载数据,归一化数据(注意:这里我们只对训练数据归一化,测试数据在预测时归一化) train: 构建模型、编译、训练 predict: 归一化测试数据,预测并返回预测标签(整数数组) 注意:由于训练数据只有1000个样本,我们可能会过拟合,所以可以加入一些正则化(如Dropout)或者早停(EarlyStopping)。但为了简单,我们只使用一个简单的网络,并控制训练轮数。 我们设置epochs=50,如果验证集上性能不再提升可以早停,但是这里没有验证集,我们直接使用训练集,所以可能会过拟合。因此我们使用一个较小的epochs,比如20。 或者,我们可以从训练集中划分一部分作为验证集,但题目没有要求,我们就直接训练。 考虑到数据量很小,我们也可以使用交叉验证,但这里我们只训练一次。 修改后的Classifier类: 我们写代码:以下是基于前馈神经网络(全连接网络)实现的图像分类代码。我将使用Keras库构建一个简单的多层感知器(MLP)模型:pythonimport pickleimport numpy as npfrom tensorflow.keras.models import Sequentialfrom tensorflow.keras.layers import Dense, Dropoutfrom tensorflow.keras.utils import to_categorical# 加载数据集函数(保持不变)def load_dataset(file_name):with open(file_name, 'rb') as f:raw_dataset = pickle.load(f)example_image = raw_datasetnum_classes = len(raw_dataset)dataset = np.empty((0, example_image.size))labels = np.empty((0, 1))for i_class in range(num_classes):num_images = len(raw_dataset)for i_image in range(num_images):image = raw_datasetfeatures = image.flatten()dataset = np.vstack((dataset, features))labels = np.vstack((labels, i_class))return dataset, labelsclass Classifier:def __init__(self):# 加载并预处理训练数据self.train_dataset, self.train_labels = load_dataset('./step1/training_dataset.pkl')# 归一化像素值到0-1范围self.train_dataset = self.train_dataset.astype('float32') / 255.0# 将标签转换为one-hot编码self.train_labels = to_categorical(self.train_labels, num_classes=10)# 初始化模型self.model = self.build_model()def build_model(self):"""构建前馈神经网络模型"""model = Sequential()# 输入层 (784个输入节点)model.add(Dense(512, activation='relu', input_shape=(784,)))model.add(Dropout(0.2))# 隐藏层model.add(Dense(256, activation='relu'))model.add(Dropout(0.2))# 输出层 (10个类别)model.add(Dense(10, activation='softmax'))# 编译模型model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=
'accuracy'
)return modeldef train(self):"""训练神经网络模型"""#********* BEGIN *********#self.model.fit(self.train_dataset,self.train_labels,epochs=20,batch_size=32,validation_split=0.1,verbose=1)#********* END *********#def predict(self, test_dataset):"""预测测试集"""#********* BEGIN *********## 归一化测试数据test_dataset = test_dataset.astype('float32') / 255.0# 获取预测概率predictions = self.model.predict(test_dataset)# 转换为类别标签predicted_labels = np.argmax(predictions, axis=1)#********* END *********#return predicted_labels### 关键实现细节:1. **数据预处理**: - 像素值归一化到范围 - 标签转换为one-hot编码(10维向量)2. **网络架构**: - 输入层:784个节点(对应28×28像素) - 隐藏层1:512个节点 + ReLU激活 + 20% Dropout - 隐藏层2:256个节点 + ReLU激活 + 20% Dropout - 输出层:10个节点 + Softmax激活3. **训练配置**: - 优化器:Adam - 损失函数:分类交叉熵 - 训练轮次:20 - 批量大小:32 - 验证集比例:10%4. **预测处理**: - 归一化测试数据 - 取概率最大的类别作为预测结果该模型在Fashion-MNIST数据集上预期能达到约88-92%的准确率。可通过调整网络结构(层数/节点数)、正则化参数(Dropout率)、学习率等进一步提升性能。
