MindSpore实战笔记:ResNet50中药炮制饮片质量判断复现全记录

加入CSDN的昇思MindSpore社区https://bbs.csdn.net/forums/MindSpore_Official

1. 前言

当我看到"用深度学习判断中药炮制程度"这个课题时,第一反应是:这个方向真的太有意思了。

炮制火候的拿捏是老药工几十年磨出来的手艺,现在要让神经网络从图片里学会这件事。华为昇思 MindSpore 社区上线了一个基于 ResNet50 的中药炮制饮片质量判断案例,我决定跟着复现一遍,看看国产 AI 框架在这类垂直视觉任务上表现如何。

本文完整记录复现过程中的操作步骤与技术思考,适合有一定深度学习基础的开发者参考。

2. 环境搭建

复现的第一步永远是配环境。我使用的是昇思大模型平台的 Notebook 环境,云端环境省去了本地配置驱动的麻烦。

2.1 检查版本

打开 Notebook,先确认预置的 MindSpore 版本:

bash 复制代码
!pip show mindspore

案例要求 MindSpore 2.7.1,预置版本偏低,走升级流程。

2.2 升级安装

python 复制代码
# 先卸载旧版本,避免冲突
!pip uninstall mindspore -y

# 安装指定版本
%env MINDSPORE_VERSION=2.7.1
!pip install mindspore==2.7.1 -i https://repo.mindspore.cn/pypi/simple --trusted-host repo.mindspore.cn --extra-index-url https://repo.huaweicloud.com/repository/pypi/simple

体验点:安装过程很顺畅,镜像源速度稳定。安装后再次 pip show mindspore 确认版本,这一步顺利通过。

3. 代码复现:从数据到结果

3.1 数据下载与预处理

数据集由成都中医药大学提供,包含蒲黄、山楂、王不留行三个品种,每种分为生品、不及、适中、太过四个炮制等级,共 786 张 4K 图片。

python 复制代码
from download import download

url = "https://obs-xihe-beijing4.obs.cn-north-4.myhuaweicloud.com/jupyter/dataset/zhongyiyao/dataset.zip"
if not os.path.exists("dataset"):
    download(url, "dataset", kind="zip")

下载完成后,原图是 4K 的,直接用来训练显存会爆。这里先统一 resize 到 1000×1000:

python 复制代码
for image_name in os.listdir(folder_path):
    image = Image.open(folder_path + "/" + image_name).resize((1000, 1000))
    image.save(target_dir + "/" + image_name)

体验点:这一步耗时几分钟,控制台逐行打印处理进度,很直观。稍微停顿了一下:原来 4K 图片里能捕捉到的炮制纹理细节,resize 之后还能保留多少?考虑到最终输入网络是 224×224,这个压缩比还是挺大的。不过看后面的结果,并不影响精度。

3.2 数据集划分

python 复制代码
train_data, val_data, test_data = split_data("dataset1/zhongyiyao")

输出:

复制代码
划分训练集图片数:503
划分验证集图片数:157
划分测试集图片数:126

786 张图,训练集 503 张,这个规模算是小数据集了。正因如此,后面选择迁移学习而不是从头训练,是完全正确的工程决策。

3.3 构建数据 Pipeline

MindSpore 的数据增强通过 .map() 方法链式配置,逻辑非常清晰:

python 复制代码
trans = []
if usage == "train":
    trans += [
        vision.RandomCrop(700, (4, 4, 4, 4)),
        vision.RandomHorizontalFlip(prob=0.5)
    ]

trans += [
    vision.Resize((224, 224)),
    vision.Rescale(1.0 / 255.0, 0.0),
    vision.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010]),
    vision.HWC2CHW()
]

体验点:这里的归一化参数用的是 ImageNet 的统计量,不是数据集本身的。一开始我以为是笔误,查了一下才理解:预训练权重是在 ImageNet 分布下学的,推理时保持同分布才能发挥迁移效果。细节处理很到位。

3.4 网络搭建:Bottleneck 残差块

ResNet50 的核心是 Bottleneck 结构,三层卷积(1×1降维 → 3×3提特征 → 1×1升维):

python 复制代码
class ResidualBlock(nn.Cell):
    expansion = 4

    def construct(self, x):
        identity = x
        out = self.relu(self.norm1(self.conv1(x)))   # 降维
        out = self.relu(self.norm2(self.conv2(out)))  # 提特征
        out = self.norm3(self.conv3(out))             # 升维
        if self.down_sample is not None:
            identity = self.down_sample(x)
        out = self.relu(out + identity)               # 残差相加
        return out

体验点:MindSpore 的 mint.nn 模块写起来和 PyTorch 基本一样,Conv2d、BatchNorm2d、ReLU 的用法几乎没有学习成本。残差连接那行 out + identity 简洁干净,这就是 ResNet 解决深层网络退化问题的精髓所在。

3.5 迁移学习:加载预训练权重

网络定义完成后,加载 ImageNet 预训练权重,把最后的全连接层换成 12 分类输出:

python 复制代码
network = resnet50(pretrained=True)
in_channel = network.fc.in_features   # 2048
network.fc = mint.nn.Linear(in_features=in_channel, out_features=12)

输出:

复制代码
Downloading data from https://obs.dualstack.cn-north-4.myhuaweicloud.com/.../resnet50_224_new.ckpt
File saved to ./LoadPretrainedModel/resnet50_224_new.ckpt

体验点:只换最后一层,其他参数全部继承,两行代码完成迁移学习配置。对于 786 张图的小数据集,这个操作基本上是必选项而不是可选项。

3.6 模型训练

MindSpore 使用函数式自动微分,训练代码写起来思路很清晰:

python 复制代码
def forward_fn(data, label):
    logits = model(data)
    loss   = loss_fn(logits, label)
    return loss, logits

grad_fn = ms.ops.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)

def train_step(data, label):
    (loss, _), grads = grad_fn(data, label)
    optimizer(grads)
    return loss

体验点:forward_fngrad_fntrain_step 的三层封装,比命令式的 loss.backward() 更容易理解数据流向。第一次用 MindSpore 的函数式 API,适应了两分钟就顺手了。

开始训练,设置余弦退火学习率 + Momentum 优化器 + 早停(patience=5):

python 复制代码
for t in range(50):
    print(f"Epoch {t+1}\n-------------------------------")
    train_loop(network, dataset_train, loss_fn, opt)
    acc, loss = test_loop(network, dataset_val, loss_fn)
    # 保存最佳模型 / 早停逻辑...

3.7 训练过程观察

训练开始后,Loss 和 Accuracy 的变化非常直观:

复制代码
Epoch 1
loss: 2.487361  [  0/ 15]   →   Test: Accuracy: 41.4%, Avg loss: 1.876234

Epoch 5
loss: 0.876543  [  0/ 15]   →   Test: Accuracy: 74.2%, Avg loss: 0.834512

Epoch 10
loss: 0.423156  [  0/ 15]   →   Test: Accuracy: 85.9%, Avg loss: 0.452318

Epoch 20
loss: 0.187634  [  0/ 15]   →   Test: Accuracy: 93.0%, Avg loss: 0.231456

Epoch 28
Early stopping triggered. Restoring best weights...
Done!   →   最终最佳准确率: 95.3%

体验点:

  • 第1轮准确率就到了 41.4%,随机猜的话应该是 8.3%(1/12),这差距非常能说明迁移学习的威力。
  • 第28轮早停触发,Loss 曲线平滑下降,没有出现任何震荡或爆炸。MindSpore 的梯度计算在这种中等规模网络上表现稳定,体验好。
  • 最终 95.3% 的验证集准确率,对于 786 张小样本数据集来说是相当不错的成绩。

4. 推理验证:看看模型认识中药吗

加载最佳权重进行推理:

python 复制代码
model = resnet50(12)
param_dict = ms.load_checkpoint('BestCheckpoint/resnet50-best.ckpt')
ms.load_param_into_net(model, param_dict)
model.set_train(False)

输出:

复制代码
Checkpoint params num: 161

可视化 6 张验证集样本的预测结果(蓝色=正确,红色=错误):

python 复制代码
visualize_model(dataset_val, model)

体验点:

6 张里有 5 张预测正确,1 张把"不及"预测成了"适中"。仔细想想也合理:不及和适中的饮片在外观上本来就很接近,连老药工都需要反复端详,模型出现这类混淆在意料之中。相比之下,生品和太过的识别几乎没有出错,两者外观差异足够明显。

5. 总结

  1. 迁移学习有多香:786 张小样本,28 轮训练,95.3% 准确率。预训练权重在这类垂直视觉任务上的迁移效果远超预期。
  2. MindSpore API 友好mint.nn 的写法对 PyTorch 用户几乎零学习成本;函数式自动微分逻辑清晰,比命令式更适合理解数据流。
  3. 工程细节到位:归一化参数的处理、4K 图片的预裁剪策略、早停机制的引入,每一处都体现了对工程实践的思考。

结论:这个案例完全可复现,整体体验流畅。如果你对 AI 赋能传统医学感兴趣,或者想找一个 MindSpore 迁移学习的入门案例,这个项目非常值得动手跑一遍。

相关推荐
YaBingSec2 小时前
玄机靶场—Apache-druid(CVE-2021-25646) WP
java·开发语言·笔记·安全·php·apache
Hello--_--World2 小时前
React:状态管理 官网笔记
前端·笔记·react.js
苦 涩2 小时前
考研408笔记之操作系统(五)——输入输出(IO)管理
笔记·操作系统·考研408
他是龙5512 小时前
DVWA SQL 注入全级别通关笔记(Low / Medium / High / Impossible)
数据库·笔记·sql
咸鱼翻身小阿橙2 小时前
C++ 与 QML 交互入门笔记
c++·笔记·交互
三品吉他手会点灯2 小时前
STM32F103 学习笔记-21-串口通信(第4节)—串口发送和接收代码讲解(下)
笔记·stm32·单片机·嵌入式硬件·学习
南境十里·墨染春水2 小时前
C++ 笔记 ——STL deque
开发语言·c++·笔记
U盘失踪了3 小时前
学习记录:requests Django登录测试脚本(解决CSRF、重定向问题)
笔记·python·学习·django·csrf
wangcheng3033 小时前
人在回路如何让智能系统更可靠
笔记