AI-Lab5

理论内容回顾

PyTorch

重安装conda(虽然与pytorch没什么大关系)

由于我将ai实验移动到ubuntu里来做,所以我重新在这里安装一下conda。(先使用miniconda了)

1
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

安装完如果发现重启了终端也无法查找到 conda --version ,那么就输入命令:

1
2
3
4
5
6
7
# 1. 运行安装脚本(注意用 root 权限)
bash Miniconda3-latest-Linux-x86_64.sh

# 2. 安装过程中注意以下选项:
# - 按回车阅读协议,输入 `yes` 同意。
# - 安装路径默认是 `/root/miniconda3`(root 用户)或 `~/miniconda3`(普通用户),直接回车即可。
# - 提示 `Do you wish the installer to initialize Miniconda3?` 时,必须输入 `yes`(否则需手动配置 PATH)。

然后再重启终端,发现可以查看到版本号了。

1
2
(base) root@PQCU:~/2025AI# conda --version
conda 25.1.1

配置一下清华镜像源:

1
2
3
4
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
conda config --set show_channel_urls yes

一些常用命令:

1. 环境管理

指令 功能
conda create --name myenv python=3.9 创建名为 myenv 的 Python 3.9 环境
conda activate myenv 激活 myenv 环境
conda deactivate 退出当前环境
conda env list 列出所有环境
conda remove --name myenv --all 删除 myenv 环境
conda env export > environment.yml 导出当前环境配置到 YAML 文件
conda env create -f environment.yml 从 YAML 文件创建环境

2. 包管理

指令 功能
conda install numpy 安装包(如 numpy
conda install -c conda-forge package_name 从 conda-forge 渠道安装包
conda list 列出当前环境所有已安装包
conda search numpy 搜索包(查看可用版本)
conda update numpy 更新指定包
conda remove numpy 卸载包
conda update --all 更新所有包

3. Conda 自身管理

指令 功能
conda --version 查看 Conda 版本
conda update conda 更新 Conda 到最新版本
conda clean --all 清理缓存(减少占用空间)
  1. 查看/修改配置
指令 功能
conda config --show 查看当前配置
conda config --remove-key channels 恢复默认镜像源
conda config --set auto_activate_base false 禁止自动激活 base 环境

pytorch安装

直接去官网Start Locally | PyTorch官网找到对应的版本号,然后复制命令安装即可。由于本人的电脑没有GPU,所有下载CPU版本。

linux+CPU:

1
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu

资料

英文版:
PyTorch documentation — PyTorch 2.7 documentation
中文版:
PyTorch 文档 — PyTorch 2.7 文档 - PyTorch 深度学习库
主页 - PyTorch中文文档

tensor

  • pytorch的基本数据类型,在使用torch框架进行操作时,对象一般都是要求是tensor类型

初始化tensor

  • 直接初始化

  • 通过原始数据转化

  • 通过numpy数据转化

  • 也可以通过torch.zeros()torch.ones()等创建指定大小的全0或全1张量

  • 初始化未指定数据类型时,tensor会根据数据本身的类型自行判断

梯度计算:

  • requires_grad=True –pytorch会追踪该张量的所有计算(自动微分),以便后续进行反向传播计算梯度

维度变换:

  • torch.view()或者torch.reshape() 维度重置(但总数要一致),若根据已有维度可推算出剩下的维度,可使用 -1 替代
    • 用于改变张量的形状,但是总元素的数量必须保持不变。
    • 可以使用 -1 自动计算某一维度的大小
方法 是否共享内存 是否适用于非连续内存 适用场景
view() ✅ 是 ❌ 只能在连续内存上使用 高效调整形状(不复制数据)
reshape() ✅ 是(如果可能) ✅ 可以处理非连续内存 更通用,但可能触发数据复制
  • torch.reshape()也可以重置维度
    • 压缩(删除)大小为 1 的维度
    • 如果不指定 dim,则删除所有大小为 1 的维度
    • 如果指定 dim,则只压缩该维度该维度必须为 1,否则报错)。
1
2
3
4
5
6
7
8
9
10
11
12
x = torch.randn(1, 3, 1, 2)  # shape: [1, 3, 1, 2]

# 不指定 dim,删除所有大小为 1 的维度
x_squeeze = x.squeeze() # shape: [3, 2]
print(x_squeeze.shape) # torch.Size([3, 2])

# 指定 dim=2(第3个维度,从0开始计数)
x_squeeze_dim = x.squeeze(dim=2) # shape: [1, 3, 2]
print(x_squeeze_dim.shape) # torch.Size([1, 3, 2])

# 如果 dim 不是 1,会报错
x.squeeze(dim=1) # 报错,因为 dim=1 的大小是 3,不是 1
  • torch.squeeze(dim) 若不指定维度,则会将tensor中为1的dim压缩,若指定只会压缩对应的维度
  • torch.unsqueeze(dim) 维度扩展
    • 在指定位置插入一个大小为 1 的维度(与 squeeze 相反)。
    • 常用于扩展维度,以适应某些操作(如矩阵乘法、卷积等)。
  • torch.cat(List[tensor,tensor],dim) 向量拼接,需要指定维度
    • 输入一个张量列表
    • dim指定沿哪个维度拼接
    • 非拼接维度的形状必须相同,否则会报错
    • 如果 dim=0(行拼接),则其他维度(如列数)必须相同
    • 如果 dim=1(列拼接),则行数必须相同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import torch

# 创建两个张量
x = torch.tensor([[1, 2], [3, 4]]) # shape: [2, 2]
y = torch.tensor([[5, 6], [7, 8]]) # shape: [2, 2]

# 沿第0维(行方向)拼接
z0 = torch.cat([x, y], dim=0)
print(z0)
# tensor([[1, 2],
# [3, 4],
# [5, 6],
# [7, 8]]) # shape: [4, 2]

# 沿第1维(列方向)拼接
z1 = torch.cat([x, y], dim=1)
print(z1)
# tensor([[1, 2, 5, 6],
# [3, 4, 7, 8]]) # shape: [2, 4]

torch.nn

自定义神经网络类的基本框架:继承 nn.Module 神经网络基本类,该类实例化后输入数据将自动调用 forward 前向计算

。有点没看懂。

网络训练一般步骤

实例化网络 net = Net() 后,定义网络优化器

  • optim = nn.optim.Adam(net.parameters(), lr=lr)
    计算得到 Loss,
  • loss=MSE(a,b)
    在更新前,需清除上一步的梯度,即
  • optim.zero_grad()
    然后 Loss 反向传播:
  • loss.backward()
    最后优化器更新:
  • optim.step()

CNN网络训练实例

手写数字识别作为样例
1.读入训练集和测试集中的数字图片信息以及对图片预处理
2.用pytorch搭建神经网络(包括卷积和全连接神经网络)
3.将一个batch的训练集中的图片输入至神经网络,得到所有数字的预测分类概率(总共10个数字,0123456789)

4.根据真实标签和预测标签,利用交叉熵损失函数计算loss值,并进行梯度下降
5.根据测试集计算准确率,如果准确率没收敛,跳转回步骤3
6.画出loss、测试集准确率的曲线图
参考视频:https://www.bilibili.com/video/BV1Vx411j7kT?p=19
参考代码:https://github.com/MorvanZhou/PyTorchTutorial/blob/master/tutorialcontents/401_CNN.py

CNN卷积网络卷了什么?

我们之前就知道图片的表示形式是一大堆数字(0-255),如果是灰色图数值代表的是灰度,而如果是彩色图记录的就是RGB颜色,使用三维张量或者三个矩阵来记录。

  • 每一个矩阵可以称为图片的一个channel,用宽高深来描述。

传统的神经网络会导致物体如果处在同一个图片的不同位置,就可能会识别为不同物体,但是卷积神经网络可以捕捉图像中的局部特征而不受位置的影响。(不变性)

什么是卷积

在信号与系统课程中我们与卷积打了不少交道
连续:$F(x) = \int_{-\infty}^{\infty} f(\tau) g(x - \tau) d\tau$

在卷积神经网络中,卷积操作是将一个可移动的小窗口滤波器/卷积核)与图像进行逐元素相乘然后相加的操作。滤波器相当于一组固定的权重。

例如:将一个 6*6 的网格滤波成 4*4 的网格,保留下来的是特征
这里的卷积核是一个 3*3 的矩阵,通过将黄色部分和卷积核进行卷积得到一个值填入到特征矩阵中,进行特征提取。


这个时候发现了边缘的特征丢失了
使用 padding 扩充方式,将 6*6的像素图扩充成 8*8 的像素图(用0填充)

因此在设置卷积神经网络时,我们需要关注这些参数

  • 步长stride:每次滑动的位置步长(也就是小窗口移动的距离)
  • 卷积核的个数:决定输出的depth厚度
  • 填充值zero-padding:在外围边缘用0填充(要使得总长能被步长整除)

动图:
https://i-blog.csdnimg.cn/blog_migrate/d0172774f7e42ae2f6310b63e59b4906.gif

卷积神经网络模型:

红色部分可以看做一个滤波器,多个滤波器叠加就成了卷积层

最大池化:(max pooling)
将图片特征进一步压缩,仅反映最突出的特点,也就是将图像切割成如图多个 2*2 的网格,取出每个小矩阵中最大的值。
池化后的数据保留了原始图片中最精华的特征

扁平化处理:

把池化后的数据进行扁平化处理:将两个 3*3 的像素图叠加转换为1维的数据条。
数据条作为输入,连接到全连接隐藏层,最终产生输出结果。(感觉做完转换后,得到的扁平化信息到最终输出结果就和MLP很类似了)

如果想进一步理解复杂的cnn模型:CNN Explainer

实验任务

中药图片分类任务

利用pytorch框架搭建神经网络实现中药图片分类,其中中药图片数据分为训练集 train和测试集 test,训练集仅用于网络训练阶段,测试集仅用于模型的性能测试阶段。训练集和测试集均包含五种不同类型的中药图片:baihedangshengouqihuaihuajinyinhua。请合理设计神经网络架构,利用训练集完成网络训练,统计网络模型的训练准确率和测试准确率,画出模型的训练过程的loss曲线、准确率曲线。

提示

  1. 最后提交的代码只需包含性能最好的实现方法和参数设置. 只需提交一个代码文件, 请不要提交其他文件.
  2. 本次作业可以使用 pytorch库、 numpy库、matplotlib库以及python标准库.
  3. 数据集可以在Github上下载。
  4. 模型的训练性能以及测试性能均作为本次作业的评分标准。
  5. 测试集不可用于模型训练。
  6. 不能使用开源的预训练模型进行训练。

实现过程

我们看到训练集和测试集都是彩色图,所以我们要采用三通道卷积的方式来表示。

也就是分别卷积后再相加得到结果。

n通道的卷积过程:



卷积层:

  • nn.Conv1d

    • 输入:(batch_size, channels, length)
    • 处理一维序列数据(如时间序列、文本词向量)
    • 例:音频波形、传感器数据、自然语言处理中的词嵌入序列。
  • nn.Conv2d

    • 输入:(batch_size, channels, height, width)
    • 处理二维网格数据(如图像)。
    • 例:RGB图像、二维频谱图。
  • nn.Conv3d

    • 输入:(batch_size, channels, depth, height, width)
    • 处理三维体数据(如视频或医学扫描图像)。
    • 例:视频帧(时间+空间)、CT/MRI扫描的3D体素数据。
  • Conv2d

    • 卷积核沿2个方向(高度和宽度)滑动,输出二维特征图。
    • 卷积核尺寸:(kernel_size, kernel_size)(如3x3)。
卷积类型 适用场景示例
Conv1d 文本分类(词序列)、语音识别(音频帧)、股票预测(时间序列)
Conv2d 图像分类、目标检测、风格迁移(2D图像处理)
Conv3d 视频动作识别、医学影像分析(3D体数据)
1
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)
  • in_channels (int) – 输入图像中的通道数
  • out_channels (int) – 卷积产生的通道数
  • kernel_size (int tuple) – 卷积核的大小
  • stride (int tuple, 可选的) – 卷积的步长。默认值:1
  • padding (int, tuple str, 可选的) – 输入四边添加的填充。默认值:0
  • dilation (int tuple, 可选的) – 内核元素之间的间距。默认值:1
  • groups (int, 可选的) – 从输入通道到输出通道的组连接数。默认值:1
  • bias (bool, 可选的) – 如果为 True,则向输出添加一个可学习的偏置项。默认值:True
  • padding_mode (str, 可选的) – 'zeros', 'reflect', 'replicate''circular'。默认值:'zeros'

池化层:

1
torch.nn.MaxPool2d(*kernel_size*, *stride=None*, *padding=0*, *dilation=1*, *return_indices=False*, *ceil_mode=False*)

进行测试后发现,不够稳定:
epoches=15

epoches=30

epoches=100

epoches=500
epoches=1000
epoches=2000
尝试添加归一化函数nn.BatchNorm2d(),并去掉了随机旋转和水平翻转(因为我观察到小规模测试集里的图片还是比较正的())

  • 测试了一下50代,感觉效果一般

又尝试在预处理数据部分添加了归一化:

1
2
3
transforms.Normalize(
            mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]
        ),  # 常用的参数

发现在epoches=50的情况下效果也好了很多,将进一步尝试更多代,寻找更加稳定的代数
epoches=50

资料:
【深度学习】一文搞懂卷积神经网络(CNN)的原理(超详细)_卷积神经网络原理-CSDN博客
python标准库 —— os模块_python中os库的作用-CSDN博客torch.nn — PyTorch 2.7 文档 - PyTorch 深度学习库

python进度条库tqdm详解 - 知乎


AI-Lab5
https://pqcu77.github.io/2025/04/29/AI-lab5/
作者
linqt
发布于
2025年4月29日
许可协议