ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

机器学习期末大作业合集:六次实验从跑通到拿满分的路径

机器学习期末大作业合集:六次实验从跑通到拿满分的路径 简介这份资源是机器学习期末大作业的六次项目合集面向高校学生、课程设计者及需要快速完成高分作业的自学者覆盖从数据预处理到模型评估的完整流程。包内包含基于KNN的手写数字识别、回归模型、参数估计与非参数估计、朴素贝叶斯分类器、层次聚类、决策树分类器六个独立项目每个项目均配有源码与实验报告代码注释详尽新手也能理解与部署。压缩包共340个文件以109个py源码、107个png图表、22个csv数据集、13个pdf报告及10个md说明为主另有ipynb、r、pptx等辅助文件整体约63.56MB目录按项目分模块组织便于检索与复用。已有84人学习下载。读者可获得六套可直接运行的完整方案、实验报告撰写模板、数据可视化结果与调参排错思路适合作为课程设计、期末大作业或机器学习入门实战的参考素材。1. 机器学习期末大作业合集六次实验从跑通到拿满分的路径每到期末机器学习课程的大作业总能把人逼到凌晨三点。你可能已经拿到了「六次大作业合集代码实验报告」这类资源包但打开一看六个文件夹、几十个脚本、几份报告模板反而不知道从哪下手。这份合集的价值不在于「有代码」而在于它把机器学习入门阶段最核心的六类任务串成了一条线数据预处理、传统机器学习模型、深度学习模型、模型评估与调参、特征工程、综合应用。对刚接触机器学习的人来说最怕的不是算法难而是环境跑不通、数据加载报错、结果对不上报告。这篇内容就是按「拿到合集后怎么复现、怎么改、怎么避坑」的顺序展开适合正在赶大作业的本科生、需要快速补齐机器学习应用流程的转行者以及想拿一份可运行代码对照复习期末的人。下面从合集结构拆解开始一步步把六次作业跑通并写出能交差的实验报告。2. 六次大作业合集的结构拆解与运行环境准备2.1 先看清六个文件夹分别对应什么任务拿到一个「六次大作业合集」压缩包第一件事不是急着跑代码而是把目录结构画出来。常见的组织方式是按作业序号分文件夹每个文件夹里包含code/、data/、report/三个子目录。但不同学校、不同老师的命名习惯差异很大有的用hw1到hw6有的用experiment1到experiment6还有的按算法名命名比如linear_regression、decision_tree、cnn。你需要先做一次「代码诊断」把每个文件夹里的入口文件找出来。我一般会先用命令行扫一遍目录树把文件类型和大小列出来这样能快速判断哪些是数据、哪些是脚本、哪些是报告。Windows 下可以用tree /fLinux 或 macOS 下用find更灵活。下面这条命令会列出所有 Python 文件和 CSV 文件并显示大小find . -type f \( -name *.py -o -name *.csv -o -name *.ipynb \) -exec ls -lh {} \;执行后你会看到类似hw1/code/linear_reg.py、hw1/data/train.csv这样的路径。重点看三类文件入口脚本通常叫main.py、train.py或.ipynb、数据文件.csv、.txt、.mat、依赖文件requirements.txt或environment.yml。如果某个文件夹里只有.ipynb没有.py说明作者是用 Jupyter Notebook 写的你需要确认 Notebook 里的输出是否已经保存否则跑起来可能看不到中间结果。提示如果压缩包里没有requirements.txt不要慌先看代码开头的import语句把用到的包记下来后面手动装。2.2 用 conda 建一个隔离环境避免包版本打架机器学习大作业最常见的翻车现场就是包版本冲突。比如你系统里已经装了 TensorFlow 2.15但某次作业的代码是用 TensorFlow 1.x 写的tf.placeholder直接报错。所以第一步一定是建独立环境不要往 base 环境里乱装。我一般用 conda 建环境Python 版本选 3.8 或 3.9这两个版本对大多数机器学习库兼容性最好。命令如下conda create -n ml_hw python3.9 conda activate ml_hw建好之后先装基础三件套numpy、pandas、matplotlib。这三个包几乎每次作业都会用到而且版本相对稳定。接着根据每次作业的具体需求装scikit-learn、tensorflow或pytorch。注意scikit-learn和tensorflow对 numpy 版本有要求如果先装了最新版 numpy后面装 tensorflow 时可能会被降级导致前面跑通的代码又报错。所以建议的顺序是先装 tensorflow 或 pytorch再装 scikit-learn最后补 numpy 和 pandas。pip install tensorflow2.10.0 pip install scikit-learn1.1.3 pip install numpy1.23.5 pandas1.5.3 matplotlib3.7.1这里指定版本号是因为不同版本的 API 有差异。比如tensorflow 2.10是最后一个支持 Windows 原生 GPU 的版本如果你在 Windows 上跑深度学习作业这个版本比较稳。scikit-learn 1.1.3的train_test_split和cross_val_score参数和最新版基本一致不会出现stratify参数报错的问题。注意如果你用的是 Apple Silicon 芯片的 Mactensorflow 需要装tensorflow-macos命令是pip install tensorflow-macos2.10.0否则会提示找不到兼容版本。2.3 数据加载的三种常见格式与读取方式六次作业里数据格式通常逃不出三种CSV、MATLAB 的.mat文件、以及图片文件夹。CSV 最好办pandas.read_csv直接读但要注意编码问题。国内老师给的数据经常是 GBK 编码用默认的 UTF-8 读会报UnicodeDecodeError。这时候加一个encodinggbk参数就能解决。import pandas as pd # 尝试用 gbk 编码读取如果失败再换 utf-8 try: df pd.read_csv(data/train.csv, encodinggbk) except UnicodeDecodeError: df pd.read_csv(data/train.csv, encodingutf-8) print(df.head()) print(df.shape).mat文件用scipy.io.loadmat读读出来是一个字典键名就是 MATLAB 里的变量名。常见坑是键名里带__前缀的元数据你需要跳过它们只取真正的数据变量。from scipy.io import loadmat mat_data loadmat(data/ex3data1.mat) # 打印所有键找到数据变量 for key in mat_data: if not key.startswith(__): print(key, mat_data[key].shape)图片文件夹一般按类别分子目录用torchvision.datasets.ImageFolder或tensorflow.keras.preprocessing.image_dataset_from_directory加载。这里的关键是确认目录结构是否符合框架要求每个类别一个子文件夹文件夹名就是类别标签。2.4 跑通第一个脚本前必须检查的三件事在按下运行键之前花两分钟检查这三件事能省下两小时的排错时间。第一确认当前工作目录是否正确。很多脚本里写的是相对路径data/train.csv如果你在上一级目录运行就会报FileNotFoundError。用os.getcwd()打印当前目录再用os.chdir()切到脚本所在目录。第二确认随机种子是否固定。机器学习作业里经常需要复现结果如果代码里没有np.random.seed(42)或torch.manual_seed(42)每次跑出来的准确率都不一样报告里写的结果就对不上。你可以在入口脚本开头手动加上种子设置。第三确认输出路径是否存在。有些代码会把训练好的模型保存到output/或results/目录如果目录不存在保存时会报错。提前用os.makedirs(output, exist_okTrue)建好目录。import os import numpy as np import random # 固定随机种子保证结果可复现 seed 42 np.random.seed(seed) random.seed(seed) # 确保输出目录存在 os.makedirs(output, exist_okTrue) os.makedirs(results, exist_okTrue) print(当前工作目录:, os.getcwd())这三件事做完再跑第一个脚本成功率会高很多。如果还是报错把错误信息完整复制下来重点看最后一行Error前面的内容通常是缺包或者路径不对。3. 传统机器学习作业从线性回归到 SVM 的代码复现与调参3.1 线性回归和逻辑回归的代码骨架六次作业里前两次通常是线性回归和逻辑回归。这两个算法虽然简单但代码里藏着不少细节。线性回归的核心是梯度下降逻辑回归的核心是 Sigmoid 函数加交叉熵损失。很多合集里的代码是用scikit-learn一行搞定的但老师往往要求手写梯度下降这时候就要看代码里有没有实现compute_cost和gradient_descent两个函数。以线性回归为例手写梯度下降的代码骨架如下import numpy as np def compute_cost(X, y, theta): 计算线性回归的代价函数 m len(y) predictions X.dot(theta) cost (1 / (2 * m)) * np.sum(np.square(predictions - y)) return cost def gradient_descent(X, y, theta, alpha, iterations): 批量梯度下降 m len(y) cost_history np.zeros(iterations) for i in range(iterations): predictions X.dot(theta) errors predictions - y # 关键theta 的更新方向是 X 转置乘以误差 theta theta - (alpha / m) * X.T.dot(errors) cost_history[i] compute_cost(X, y, theta) return theta, cost_history这里alpha是学习率一般设 0.01 或 0.03。如果代价函数不下降反而上升说明学习率太大调小到 0.001 试试。iterations设 1000 到 5000 之间看代价曲线是否收敛。注意X的第一列要手动加上全 1作为偏置项否则拟合的直线不过原点。逻辑回归的代码结构类似但要把预测函数换成sigmoid(X.dot(theta))代价函数换成对数损失。scikit-learn的LogisticRegression默认用 L2 正则如果老师要求不加正则记得设penaltynone。3.2 决策树和随机森林的参数怎么调第三次作业通常是决策树或随机森林。scikit-learn的DecisionTreeClassifier有几个关键参数max_depth、min_samples_split、min_samples_leaf、criterion。max_depth控制树的最大深度设太小会欠拟合设太大会过拟合。我一般先用默认值跑一遍看训练集和测试集的准确率差距。如果训练集 99%、测试集 70%说明过拟合把max_depth从None改成 5 或 7。from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score # 决策树限制深度防止过拟合 dt DecisionTreeClassifier(max_depth5, min_samples_split10, random_state42) dt.fit(X_train, y_train) y_pred_dt dt.predict(X_test) print(决策树准确率:, accuracy_score(y_test, y_pred_dt)) # 随机森林用多棵树投票通常比单棵树稳 rf RandomForestClassifier(n_estimators100, max_depth7, random_state42) rf.fit(X_train, y_train) y_pred_rf rf.predict(X_test) print(随机森林准确率:, accuracy_score(y_test, y_pred_rf))随机森林的n_estimators是树的数量设 100 通常够用设 200 会慢但可能略好。max_depth和决策树一样控制单棵树的复杂度。如果特征维度很高加max_featuressqrt让每棵树只考虑部分特征能进一步降低过拟合。提示调参时不要同时改多个参数一次只改一个观察准确率变化否则你根本不知道是哪个参数起了作用。3.3 SVM 的核函数选择与 C 值影响第四次作业经常是 SVM。SVM 的核心参数是C和kernel。C是惩罚系数C越大对误分类的容忍度越低容易过拟合C越小容忍度越高容易欠拟合。kernel常用linear、rbf、poly。线性核适合特征维度高、样本量大的情况RBF 核适合非线性可分的数据但需要调gamma参数。from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler # SVM 对特征尺度敏感先标准化 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) # 尝试不同 C 值和核函数 for c in [0.1, 1, 10]: for kernel in [linear, rbf]: svm SVC(Cc, kernelkernel, gammascale, random_state42) svm.fit(X_train_scaled, y_train) acc svm.score(X_test_scaled, y_test) print(fC{c}, kernel{kernel}, 准确率{acc:.4f})跑完这个循环你会看到一组准确率。通常C1或C10配合 RBF 核效果最好。如果数据量超过一万条SVM 训练会很慢这时候考虑换LinearSVC或者用随机森林替代。注意 SVM 之前一定要做标准化否则量纲大的特征会主导距离计算准确率直接崩掉。3.4 用交叉验证和网格搜索找最优参数手动调参效率低GridSearchCV能自动遍历参数组合用交叉验证选出最优。但要注意GridSearchCV的计算量是参数组合数乘以折数如果参数范围设太大跑一晚上都跑不完。我一般先粗调再细调。from sklearn.model_selection import GridSearchCV param_grid { C: [0.1, 1, 10], kernel: [rbf], gamma: [scale, 0.01, 0.001] } grid GridSearchCV(SVC(), param_grid, cv5, scoringaccuracy, n_jobs-1) grid.fit(X_train_scaled, y_train) print(最优参数:, grid.best_params_) print(最优交叉验证准确率:, grid.best_score_) print(测试集准确率:, grid.score(X_test_scaled, y_test))cv5表示五折交叉验证n_jobs-1表示用所有 CPU 核心并行跑。best_params_给出最优参数组合best_score_是交叉验证的平均准确率。注意交叉验证准确率通常比测试集准确率略高因为模型在交叉验证时见过更多数据。如果两者差距超过 5%说明数据划分有问题或者模型过拟合严重。4. 深度学习作业CNN 与 RNN 的代码实现与训练技巧4.1 用 PyTorch 搭一个 CNN 处理图像分类第五次作业通常是深度学习最常见的是用 CNN 做图像分类。合集里的代码可能用 TensorFlow 也可能用 PyTorch这里以 PyTorch 为例因为它的调试体验更直观。一个标准的 CNN 包含卷积层、池化层、全连接层代码骨架如下import torch import torch.nn as nn import torch.nn.functional as F class SimpleCNN(nn.Module): def __init__(self, num_classes10): super(SimpleCNN, self).__init__() # 输入通道 3输出通道 32卷积核 3x3 self.conv1 nn.Conv2d(3, 32, kernel_size3, padding1) self.conv2 nn.Conv2d(32, 64, kernel_size3, padding1) self.pool nn.MaxPool2d(2, 2) # 经过两次池化特征图尺寸变为原来的 1/4 self.fc1 nn.Linear(64 * 8 * 8, 128) self.fc2 nn.Linear(128, num_classes) def forward(self, x): x self.pool(F.relu(self.conv1(x))) x self.pool(F.relu(self.conv2(x))) x x.view(-1, 64 * 8 * 8) # 展平 x F.relu(self.fc1(x)) x self.fc2(x) return x这里假设输入图片是 32x32 的 CIFAR-10 格式。如果是 28x28 的 MNIST全连接层的输入维度要改成64 * 7 * 7。padding1保证卷积后尺寸不变pool每次把尺寸减半。训练时用CrossEntropyLoss和Adam优化器学习率设 0.001。device torch.device(cuda if torch.cuda.is_available() else cpu) model SimpleCNN(num_classes10).to(device) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr0.001) for epoch in range(10): model.train() running_loss 0.0 for images, labels in train_loader: images, labels images.to(device), labels.to(device) optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() print(fEpoch {epoch1}, Loss: {running_loss/len(train_loader):.4f})如果显存不够把batch_size从 64 降到 32 或 16。如果训练损失不下降检查学习率是不是太大或者数据有没有归一化。图像数据通常要除以 255 再减均值除标准差torchvision.transforms里有现成的Normalize。4.2 RNN 和 LSTM 处理序列数据的注意事项第六次作业可能是 RNN 或 LSTM处理文本分类或时间序列预测。PyTorch 的nn.LSTM输入要求是(seq_len, batch, input_size)如果你用batch_firstTrue输入就是(batch, seq_len, input_size)。这个维度顺序搞错会报各种 shape 不匹配的错误。class LSTMClassifier(nn.Module): def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes): super(LSTMClassifier, self).__init__() self.embedding nn.Embedding(vocab_size, embed_dim) self.lstm nn.LSTM(embed_dim, hidden_dim, batch_firstTrue) self.fc nn.Linear(hidden_dim, num_classes) def forward(self, x): # x: (batch, seq_len) embedded self.embedding(x) # (batch, seq_len, embed_dim) lstm_out, (hidden, cell) self.lstm(embedded) # 取最后一个时间步的输出 last_output lstm_out[:, -1, :] return self.fc(last_output)文本数据要先做词表映射把每个词转成整数 ID。如果句子长度不一用pad_sequence补齐到同一长度。LSTM 的hidden_dim一般设 128 或 256embed_dim设 100 或 200。训练时如果损失震荡厉害把学习率降到 0.0005或者加梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm5)。注意LSTM 训练比 CNN 慢很多如果作业数据量大先用小样本跑通流程再上全量数据。4.3 训练过程中的 loss 曲线怎么看不管 CNN 还是 RNN训练时都要记录 loss 和准确率画成曲线。正常的 loss 曲线应该是先快速下降然后逐渐平缓。如果 loss 一直不降检查三件事学习率是不是太大、数据标签有没有对错、模型有没有正确切换到train()模式。如果 loss 下降但验证集准确率不升说明过拟合加 Dropout 或 L2 正则。import matplotlib.pyplot as plt # 假设 train_losses 和 val_accuracies 是训练过程中记录的列表 plt.figure(figsize(10, 4)) plt.subplot(1, 2, 1) plt.plot(train_losses, labelTrain Loss) plt.xlabel(Epoch) plt.ylabel(Loss) plt.legend() plt.subplot(1, 2, 2) plt.plot(val_accuracies, labelVal Accuracy) plt.xlabel(Epoch) plt.ylabel(Accuracy) plt.legend() plt.tight_layout() plt.savefig(results/training_curve.png)这张图直接放进实验报告比只写一个最终准确率有说服力得多。老师看报告时最关注的就是你有没有分析训练过程而不是只贴一个数字。5. 实验报告撰写把代码结果变成能交差的文档5.1 报告的标准结构和每部分写什么实验报告不是代码的复制粘贴而是对「做了什么、为什么这么做、结果如何」的说明。一份能拿高分的报告通常包含实验目的、实验环境、实验原理、实验步骤、实验结果、结果分析、实验总结。其中「实验结果」和「结果分析」是重点要放图表和你的解读。实验目的写两三句话说明这次作业要解决什么问题。实验环境列出 Python 版本、主要库和版本号、硬件配置。实验原理简述算法核心公式比如逻辑回归的 Sigmoid 函数和交叉熵损失。实验步骤写数据预处理、模型搭建、训练参数设置。实验结果放准确率、混淆矩阵、loss 曲线。结果分析要解释为什么准确率是这个值有没有过拟合参数调整对结果的影响。5.2 图表和表格的规范做法报告里的图表要编号图注在图下方表注在表上方。混淆矩阵用热力图展示准确率对比用柱状图。表格用来列参数对比比如不同 C 值下 SVM 的准确率。参数组合训练集准确率测试集准确率C0.1, RBF0.920.89C1, RBF0.960.93C10, RBF0.990.91从这张表能看出C10 时训练集准确率很高但测试集下降说明过拟合。C1 是更好的选择。这种分析写进报告比只写「我用了 SVM」有深度得多。5.3 结果分析里必须回答的三个问题第一模型有没有过拟合或欠拟合依据是训练集和测试集准确率的差距。第二哪个参数对结果影响最大依据是你做的对比实验。第三这个结果在同类任务中算什么水平比如 MNIST 分类准确率 99% 是正常水平CIFAR-10 准确率 80% 已经不错。回答这三个问题报告的分析部分就立住了。提示不要编造结果。如果某次实验准确率只有 60%就如实写然后分析原因比如数据量太小、特征不够、模型太简单。老师更看重你的分析能力而不是一个漂亮的数字。6. 避坑与排查六次作业里最容易翻车的五个地方6.1 路径错误导致 FileNotFoundError现象运行脚本立刻报FileNotFoundError: [Errno 2] No such file or directory: data/train.csv。原因脚本里的相对路径是相对于当前工作目录不是相对于脚本文件。你在项目根目录运行但脚本在hw1/code/下它找的是根目录/data/train.csv而实际文件在hw1/data/train.csv。解决在脚本开头加os.chdir(os.path.dirname(os.path.abspath(__file__)))把工作目录切到脚本所在目录。或者用绝对路径拼接os.path.join(os.path.dirname(__file__), .., data, train.csv)。6.2 包版本不兼容导致 API 报错现象AttributeError: module tensorflow has no attribute placeholder。原因代码是用 TensorFlow 1.x 写的你装的是 2.xplaceholder在 2.x 默认模式下被移除了。解决要么装tensorflow1.15要么在 2.x 里用tf.compat.v1.placeholder并开启兼容模式tf.compat.v1.disable_eager_execution()。更彻底的办法是看代码开头的 import判断它原本用的哪个版本然后建对应版本的环境。6.3 数据标签编码不一致导致准确率为 0现象模型训练 loss 正常下降但准确率一直是 0 或者随机水平。原因标签编码和模型输出对不上。比如标签是字符串cat、dog但模型输出是 0 和 1没有做LabelEncoder转换。或者标签是 1 和 2但CrossEntropyLoss要求标签从 0 开始。解决用sklearn.preprocessing.LabelEncoder把标签转成 0 到 n-1 的整数打印np.unique(y)确认标签范围。6.4 忘记切换 train/eval 模式导致结果异常现象PyTorch 模型训练时准确率正常测试时准确率暴跌。原因测试时没有调用model.eval()Dropout 和 BatchNorm 还在训练模式导致输出不稳定。解决测试前加model.eval()并用with torch.no_grad():包裹推理代码关闭梯度计算既省显存又避免意外更新参数。6.5 随机种子未固定导致结果无法复现现象每次运行代码准确率都不一样报告里写的结果和实际跑出来的对不上。原因numpy、random、torch 的随机种子没有固定。解决在入口脚本最前面统一设置种子。import numpy as np import random import torch def set_seed(seed42): np.random.seed(seed) random.seed(seed) torch.manual_seed(seed) if torch.cuda.is_available(): torch.cuda.manual_seed_all(seed) # 确保 cudnn 的卷积算法确定性 torch.backends.cudnn.deterministic True torch.backends.cudnn.benchmark False set_seed(42)注意即使固定了种子如果用了 GPU 且 cudnn 的 benchmark 为 True结果仍可能有微小差异。设benchmarkFalse能保证确定性但会稍微降低训练速度。7. 进阶技巧用一份代码模板套用六次作业六次作业看起来任务不同但代码结构高度相似。我后来总结出一个模板把数据加载、模型定义、训练循环、评估、绘图五个模块拆开每次作业只改模型定义和数据加载部分其余直接复用。这样能把写代码的时间从三天压缩到半天。模板的核心是一个BaseTrainer类封装了训练和评估的通用逻辑。你只需要继承它实现build_model和load_data两个方法。下面是一个简化版class BaseTrainer: def __init__(self, model, device, lr0.001): self.model model.to(device) self.device device self.optimizer torch.optim.Adam(model.parameters(), lrlr) self.criterion nn.CrossEntropyLoss() self.train_losses [] self.val_accuracies [] def train_epoch(self, train_loader): self.model.train() total_loss 0 for x, y in train_loader: x, y x.to(self.device), y.to(self.device) self.optimizer.zero_grad() output self.model(x) loss self.criterion(output, y) loss.backward() self.optimizer.step() total_loss loss.item() return total_loss / len(train_loader) def evaluate(self, val_loader): self.model.eval() correct 0 total 0 with torch.no_grad(): for x, y in val_loader: x, y x.to(self.device), y.to(self.device) output self.model(x) pred output.argmax(dim1) correct (pred y).sum().item() total y.size(0) return correct / total def fit(self, train_loader, val_loader, epochs10): for epoch in range(epochs): loss self.train_epoch(train_loader) acc self.evaluate(val_loader) self.train_losses.append(loss) self.val_accuracies.append(acc) print(fEpoch {epoch1}: loss{loss:.4f}, val_acc{acc:.4f})用这个模板第一次作业的线性回归可以改成用nn.Linear实现第二次逻辑回归加个 Sigmoid第三次决策树虽然不能用 PyTorch 但数据加载和评估逻辑可以复用。深度学习作业直接继承BaseTrainer只写模型结构。这样六次作业的代码风格统一报告里也能体现你的工程能力。验证模板是否好用的方法很简单拿第六次作业的数据跑一遍如果能在半小时内完成从数据加载到出准确率曲线的全流程说明模板合格。我自己的习惯是每次作业结束后把新遇到的坑和解决方案追加到模板的注释里下次直接看注释就能避开。这个习惯坚持了三个学期后来帮别人看代码时一眼就能定位到问题。希望帮到你。本文还有配套的精品资源点击获取
返回列表