0

0

【药智甄选】PaddlePaddle3.0助力实现ResNet50中药分拣

P粉084495128

P粉084495128

发布时间:2025-07-24 11:36:10

|

717人浏览过

|

来源于php中文网

原创

本文介绍基于resnet50网络判断中药炮制饮片质量的研究。使用成都中医药大学提供的蒲黄、山楂、王不留行3个品种,各含生品、不及、适中、太过4种状态的共6097张图片数据集,经预处理后划分训练集和测试集。构建含预训练resnet50和全连接层的模型,用adam优化器等训练,最终准确率达97.3%,实现炮制经验智能化传承。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

【药智甄选】paddlepaddle3.0助力实现resnet50中药分拣 - php中文网

ResNet50中药炮制饮片质量判断

背景介绍

中药炮制是根据中医药理论,依照临床辨证施治用药的需要和药物自身性质,以及调剂、制剂的不同要求,将中药材制备成中药饮片所采取的一项制药技术。平时我们老百姓能接触到的中药,主要指自己回家煎煮或者请医院代煎煮的中药,都是中药饮片,也就是中药炮制这个技术的结果。而中药炮制饮片,大部分涉及到水火的处理,一定需要讲究“程度适中”,炮制火候不够达不到最好药效,炮制火候过度也会丧失药效。

  • “生品”一般是指仅仅采用简单净选得到的饮片,通常没有经过火的处理,也是后续用火加工的原料。
  • “不及”就是“炮制不到位”,没有达到规定的程度,饮片不能发挥最好的效果。
  • “适中”是指炮制程度刚刚好,正是一个最佳的炮制点位,也是通常炮制结束的终点。
  • “太过”是指炮制程度过度了,超过了“适中”的最佳状态,这时候的饮片也会丧失药效,不能再使用了。

过去的炮制饮片程度的判断,都是采用的老药工经验判断,但随着老药工人数越来越少,这种经验判断可能存在“失传”的风险。而随着人工智能的发展,使用深度神经网络模型对饮片状态进行判断能达到很好的效果,可以很好的实现经验的“智能化”和经验的传承。本产品基于PaddlePaddle3.0通过使用ResNet50网络进行中药分拣,对饮片状态进行自动判断,实现经验的“智能化”和经验的传承。

数据准备

数据集介绍

我们使用“中药炮制饮片”数据集,该数据集由成都中医药大学提供,共包含中药炮制饮片的 3 个品种,分别为:蒲黄、山楂、王不留行,每个品种又有着4种炮制状态:生品、不及适中、太过,每类包含 500 张图片共12类5000张图片,图片格式为 jpg。 下面是数据集中的一些样例图片:

【药智甄选】PaddlePaddle3.0助力实现ResNet50中药分拣 - php中文网    
In [ ]
!unzip data/data298711/images.zip -d work/images
   

单例数据可视化查看

In [40]
import paddlefrom paddle.io import Datasetimport matplotlib.pyplot as pltimport PIL.Image as Image
path='/home/aistudio/work/images/ph_bj/IMG_1762.JPG'img = Image.open(path)
plt.imshow(img)          #根据数组绘制图像plt.show()               #显示图像print(img.size)
       
<Figure size 640x480 with 1 Axes>
               
(1000, 1000)
       

数据集整理

本部分地建立了图像文件路径与其对应标签索引之间的映射关系,并将数据集打乱以消除顺序相关性,为后续的训练准备了去序列化的样本数据;

同时通过打印输出,确认了样本数据的有效性和数量;

由于平台字体问题,无法正确显示中文,这里给出英文标签对应的类别:

  • ph-sp:蒲黄-生品
  • ph_bj:蒲黄-不及
  • ph_sz:蒲黄-适中
  • ph_tg:蒲黄-太过
  • sz_sp:山楂-生品
  • sz_bj:山楂-不及
  • sz_sz:山楂-适中
  • sz_tg:山楂-太过
  • wblx_sp:王不留行-生品
  • wblx_bj:王不留行-不及
  • wblx_sz:王不留行-适中
  • wblx_tg:王不留行-太过
In [54]
#以下代码用于建立样本数据读取路径与样本标签之间的关系import osimport random

data_list = [] #用个列表保存每个样本的读取路径、标签#获取work目录下的所有子目录名称,保存进一个列表之中class_list = os.listdir("/home/aistudio/work/images")
class_label_list=['ph_bj','ph_sp','ph_sz','ph_tg','sz_bj','sz_sp','sz_sz','sz_tg','wblx_bj','wblx_sp','wblx_sz','wblx_tg']for each in class_list:    for f in os.listdir("/home/aistudio/work/images/"+each):
        label=each
        label_index=class_label_list.index(label)        # print(label,label_index)
        data_list.append(["/home/aistudio/work/images/"+each+'/'+f,label_index])#按文件顺序读取,可能造成很多属种图片存在序列相关,用random.shuffle方法把样本顺序彻底打乱。random.shuffle(data_list)#打印前十个,可以看出data_list列表中的每个元素是[样本读取路径, 样本标签]。print(data_list[0:10])#打印样本数量,一共有2340个样本。print("样本数量是:{}".format(len(data_list)))
       
[['/home/aistudio/work/images/ph_bj/IMG_20221212_203008.jpg', 0], ['/home/aistudio/work/images/ph_sp/IMG_20221212_194947.JPG', 1], ['/home/aistudio/work/images/ph_sz/IMG_3606.JPG', 2], ['/home/aistudio/work/images/sz_tg/IMG_5979.JPG', 7], ['/home/aistudio/work/images/wblx_sp/IMG_20230220_151228.jpg', 9], ['/home/aistudio/work/images/wblx_tg/IMG_20230220_112000.jpg', 11], ['/home/aistudio/work/images/sz_sp/IMG_5390.JPG', 5], ['/home/aistudio/work/images/wblx_sp/IMG_20230220_103938_3.JPG', 9], ['/home/aistudio/work/images/sz_sz/IMG_3225.JPG', 6], ['/home/aistudio/work/images/ph_tg/IMG_3983.JPG', 3]]
样本数量是:6097
       

数据集可视化展示

本部分操作通过计算每个类别的样本数量并使用matplotlib库绘制条形图,直观展示了数据集中各类别的分布情况;

首先统计了每个标签的频次,然后创建了一个条形图,其中横轴表示标签,纵轴表示对应的样本数量;

【药智甄选】PaddlePaddle3.0助力实现ResNet50中药分拣 - php中文网        

In [ ]
import matplotlib.pyplot as plt# 计算每个标签的样本数量label_counts = {}for _, label_index in data_list:    if label_index in label_counts:
        label_counts[label_index] += 1
    else:
        label_counts[label_index] = 1# 将标签索引转换回标签名称label_names = class_label_list
label_counts = {label_names[key]: value for key, value in label_counts.items()}# 创建条形图plt.figure(figsize=(10, 8))
plt.bar(label_counts.keys(), label_counts.values(), tick_label=label_counts.keys())
plt.xlabel('Label')
plt.ylabel('Count')
plt.title('Dataset Distribution')
plt.xticks(rotation=45)
plt.show()
   

数据迭代器构建

本部分代码先是定义了一个数据预处理函数和一个自定义的数据读取器类,用于构造数据读取器和进行数据预处理;

通过Reader类,将数据集划分为训练集和测试集,并实现了数据的加载、预处理和标签转换,输出处理后的图像和标签供模型训练和评估使用;

同时,打印了训练集和测试集的大小以及一个样本的图像形状和标签,验证了数据读取器的正确性;

In [55]
#以下代码用于构造读取器与数据预处理#首先需要导入相关的模块import paddlefrom paddle.vision.transforms import Compose, ColorJitter, Resize,Transpose, Normalizeimport cv2import numpy as npfrom PIL import Imagefrom paddle.io import Dataset# 自定义的数据预处理函数,输入原始图像,输出处理后的图像,可以借用paddle.vision.transforms的数据处理功能def preprocess(img):
    transform = Compose([
        Resize(size=(224, 224)), # 把数据长宽像素调成224*224
        Normalize(mean=[127.5, 127.5, 127.5], std=[127.5, 127.5, 127.5], data_format='HWC'), # 标准化
        Transpose(), # 原始数据形状维度是HWC格式,经过Transpose,转换为CHW格式
        ])
    img = transform(img).astype("float32")    return img# 自定义数据读取器class Reader(Dataset):
    def __init__(self, data, is_val=False):
        super().__init__()        # 在初始化阶段,把数据集划分训练集和测试集。
        # 由于在读取前样本已经被打乱顺序,取20%的样本作为测试集,80%的样本作为训练集。
        self.samples = data[-int(len(data)*0.2):] if is_val else data[:-int(len(data)*0.2)]    def __getitem__(self, idx):
        #处理图像
        img_path = self.samples[idx][0] #得到某样本的路径
        img = Image.open(img_path)        if img.mode != 'RGB':
            img = img.convert('RGB')
        img = preprocess(img) #数据预处理--这里仅包括简单数据预处理,没有用到数据增强

        #处理标签
        label = self.samples[idx][1] #得到某样本的标签
        label = np.array([label],dtype='int64') #把标签数据类型转成int64
        return img, label    def __len__(self):
        #返回每个Epoch中图片数量
        return len(self.samples)#生成训练数据集实例train_dataset = Reader(data_list, is_val=False)#生成测试数据集实例eval_dataset = Reader(data_list, is_val=True)#打印一个训练样本print(len(train_dataset)) # 1872#打印一个测试样本print(len(eval_dataset)) # 234print(train_dataset[1136][0].shape)print(train_dataset[1136][1])print(type(train_dataset[1136][1]))
       
4878
1219
(3, 224, 224)
[11]
<class 'numpy.ndarray'>
       

模型训练

网络简介

网络背景

ResNet50网络是2015年由微软实验室的何恺明提出,获得ILSVRC2015图像分类竞赛第一名。在ResNet网络提出之前,传统的卷积神经网络都是将一系列的卷积层和池化层堆叠得到的,但当网络堆叠到一定深度时,就会出现退化问题。下图是在CIFAR-10数据集上使用56层网络与20层网络训练误差和测试误差图,由图中数据可以看出,56层网络比20层网络训练误差和测试误差更大,随着网络的加深,其误差并没有如预想的一样减小。
【药智甄选】PaddlePaddle3.0助力实现ResNet50中药分拣 - php中文网        

ResNet网络提出了残差网络结构(Residual Network)来减轻退化问题,使用ResNet网络可以实现搭建较深的网络结构(突破1000层)。论文中使用ResNet网络在CIFAR-10数据集上的训练误差与测试误差图如下图所示,图中虚线表示训练误差,实线表示测试误差。由图中数据可以看出,ResNet网络层数越深,其训练误差和测试误差越小。
【药智甄选】PaddlePaddle3.0助力实现ResNet50中药分拣 - php中文网        

网络特色

残差网络结构

残差结构是ResNet网络中最重要的结构,其结构图如下图所示,残差网络由两个分支构成:一个主分支,一个shortcuts(图中弧线表示)。主分支通过堆叠一系列的卷积操作得到,shortcuts从输入直接到输出,主分支的输出与shortcuts的输出相加后通过Relu激活函数后即为残差网络最后的输出。
【药智甄选】PaddlePaddle3.0助力实现ResNet50中药分拣 - php中文网        

残差网络结构主要由两种,一种是Building Block,适用于较浅的ResNet网络,如ResNet18和ResNet34;另一种是Bottleneck,适用于层数较深的ResNet网络,如ResNet50、ResNet101和ResNet152。

Building Block

Building Block结构图如下图所示,主分支有两层卷积网络结构:

Krea AI
Krea AI

多功能的一站式AI图像生成和编辑平台

下载
  • 主分支第一层网络以输入channel为64为例,首先通过一个3×3的卷积层,然后通过Batch Normalization层,最后通过Relu激活函数层,输出channel为64;

  • 主分支第二层网络的输入channel为64,首先通过一个3×3的卷积层,然后通过Batch Normalization层,输出channel为64。

最后将主分支输出的特征矩阵与shortcuts输出的特征矩阵相加,通过Relu激活函数即为Building Block最后的输出。
【药智甄选】PaddlePaddle3.0助力实现ResNet50中药分拣 - php中文网        

网络定义

定义一个基于ResNet50的自定义神经网络模型,其中利用了预训练的ResNet50作为特征提取器;

由于本任务为12分类,因此添加了一个全连接层以适应12个类别的分类任务;

模型的前向传播方法定义了数据如何通过这些层,实现了从输入到输出的计算过程;

【药智甄选】PaddlePaddle3.0助力实现ResNet50中药分拣 - php中文网    
In [74]
#定义模型class MyNet(paddle.nn.Layer):
    def __init__(self):
        super(MyNet,self).__init__()
        self.layer=paddle.vision.models.resnet50(pretrained=True)
        self.fc = paddle.nn.Linear(1000, 12)    #网络的前向计算过程
    def forward(self,x):
        x=self.layer(x)
        x=self.fc(x)        return x
   

模型训练

1、定义模型输入规格,实例化自定义的MyNet模型,并使用PaddlePaddle的高级API paddle.Model 进行了封装;

2、配置Adam优化器和交叉熵损失函数,设置准确率作为评估指标,并在GPU上进行了模型的训练和评估;

3、设置日志打印频率和模型保存频率,指定模型保存目录;

通过观察训练过程,准确度高达97.3%!

step 77/77 - loss: 0.7499 - acc: 0.9440 - 759ms/step
Eval begin...
step 20/20 - loss: 3.6955e-06 - acc: 0.9737 - 712ms/step
Eval samples: 1219
Epoch 15/15
   
In [ ]
# 定义输入input_define = paddle.static.InputSpec(shape=[-1,3,224,224], dtype="float32", name="img")
label_define = paddle.static.InputSpec(shape=[-1,1], dtype="int64",name="label")# 实例化网络对象并定义优化器等训练逻辑model = MyNet()
model = paddle.Model(model,inputs=input_define,labels=label_define) # 用Paddle.Model()对模型进行封装optimizer = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())# 上述优化器中的学习率(learning_rate)参数很重要。要是训练过程中得到的准确率呈震荡状态,忽大忽小,可以试试进一步把学习率调低。place = paddle.CUDAPlace(0)  # 使用第一个GPU设备model.prepare(optimizer=optimizer, # 指定优化器
              loss=paddle.nn.CrossEntropyLoss(), # 指定损失函数
              metrics=paddle.metric.Accuracy()) # 指定评估方法model.fit(train_data=train_dataset,     # 训练数据集
          eval_data=eval_dataset,         # 测试数据集
          batch_size=64,                  # 一个批次的样本数量
          epochs=15,                      # 迭代轮次
          save_dir="/home/aistudio/model/", # 把模型参数、优化器参数保存至自定义的文件夹
          save_freq=2,                    # 设定每隔多少个epoch保存模型参数及优化器参数
          log_freq=100,                    # 打印日志的频率)
   

推理测试

数据格式定义

1、定义一个用于推理的数据集类InferDataset,接受单个图像路径并进行预处理;

2、这个类继承自PaddlePaddle的Dataset类,提供了单张图像的读取和预处理功能,方便模型对单个图像进行预测;

In [79]
class InferDataset(Dataset):
    def __init__(self, img_path=None):
        """
        数据读取Reader(推理)
        :param img_path: 推理单张图片
        """
        super().__init__()        if img_path:
            self.img_paths = [img_path]        else:            raise Exception("请指定需要预测对应图片路径")    def __getitem__(self, index):
        # 获取图像路径
        img_path = self.img_paths[index]        # 使用Pillow来读取图像数据并转成Numpy格式
        img = Image.open(img_path)        if img.mode != 'RGB': 
            img = img.convert('RGB') 
        img = preprocess(img) #数据预处理--这里仅包括简单数据预处理,没有用到数据增强
        return img    def __len__(self):
        return len(self.img_paths)
   

实例化模型推理

1、实例化推理模型并加载了训练好的参数;

2、通过model.predict方法对指定图像进行预测,获取了预测结果,并根据结果索引输出了对应的类别名称;

In [90]
import matplotlib.pyplot as pltfrom PIL import Image#实例化推理模型input_define = paddle.static.InputSpec(shape=[-1,3,224,224], dtype="float32", name="img")
model = paddle.Model(MyNet(),inputs=input_define)#读取刚刚训练好的参数model.load('/home/aistudio/model/final')#准备模型model.prepare()#利用训练好的模型进行预测infer_path='/home/aistudio/work/images/wblx_sp/IMG_20230220_103938_15.JPG'infer_data = InferDataset(infer_path)
result = model.predict(test_data=infer_data)[0] #关键代码,实现预测功能result = paddle.to_tensor(result)
result = np.argmax(result.numpy()) #获得最大值所在的序号class_label_list=['ph_bj','ph_sp','ph_sz','ph_tg','sz_bj','sz_sp','sz_sz','sz_tg','wblx_bj','wblx_sp','wblx_sz','wblx_tg']

label_description_dict = {    'ph_sp': '蒲黄-生品',    'ph_bj': '蒲黄-不及',    'ph_sz': '蒲黄-适中',    'ph_tg': '蒲黄-太过',    'sz_sp': '山楂-生品',    'sz_bj': '山楂-不及',    'sz_sz': '山楂-适中',    'sz_tg': '山楂-太过',    'wblx_sp': '王不留行-生品',    'wblx_bj': '王不留行-不及',    'wblx_sz': '王不留行-适中',    'wblx_tg': '王不留行-太过'}print('识别结果为:'+label_description_dict[class_label_list[result]])# 使用Pillow库读取图像img = Image.open(infer_path)# 显示图像plt.figure(figsize=(8, 6))
plt.imshow(img)
plt.axis('off')  # 不显示坐标轴plt.show()
       
Predict begin...
step 1/1 [==============================] - 33ms/step
Predict samples: 1
识别结果为:王不留行-生品
       
<Figure size 800x600 with 1 Axes>
               

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

38

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

83

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

97

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

223

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

458

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

169

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

246

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

34

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号