0

0

基于 Paddle2.0 实现 HarDNet 模型

P粉084495128

P粉084495128

发布时间:2025-08-01 17:51:19

|

452人浏览过

|

来源于php中文网

原创

HarDNet是低内存流量网络,以Harmonic Dense Blocks为特色,推理时间较多种主流模型减少30%-45%。项目迁移其代码和预训练模型,前向计算结果、精度与官方一致。含多种型号,参数3.5M-36.7M,Top-1精度72.08%-78.04%。验证集用特定数据处理,还演示了Cifar100上的训练。

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

基于 paddle2.0 实现 hardnet 模型 - php中文网

引入

  • HarDNet 是一种能够在低 MAC 和内存流量的条件下实现了高效率的模型架构。
  • 与 FC-DenseNet-103,DenseNet-264,ResNet-50,ResNet-152 和 SSD-VGG 相比,新网络的推理时间减少了 35%,36%,30%,32% 和 45%。
  • 作者使用了包括 Nvidia Profiler 和 ARM Scale-Sim 在内的工具来测量内存流量,并验证推理延迟确实与内存流量消耗成正比,并且所提议的网络消耗的内存流量很低。

项目说明

  • 本项目迁移官方实现的模型代码和预训练模型参数文件
  • 模型前向计算结果与官方实现无明显差异,预训练模型的精度与官方实现和论文标称的精度对齐
  • 暂未也不打算重新进行模型训练,欢迎大家自行进行训练验证
  • 如果项目中有任何问题,也欢迎大家在评论区留言交流

相关资料

  • 论文:HarDNet: A Low Memory Traffic Network

  • 官方实现:PingoLH/Pytorch-HarDNet

  • 验证集数据处理:

    Grok
    Grok

    马斯克发起的基于大语言模型(LLM)的AI聊天机器人TruthGPT,现用名Grok

    下载
    # backend: pil# input_size: 224x224transforms = T.Compose([
        T.Resize(256),
        T.CenterCrop(224),
        T.ToTensor(),
        T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])
               
  • 模型细节:

    Model Model Name Params (M) FLOPs (G) Top-1 (%) Top-5 (%) Pretrained Model
    HarDNet-68 hardnet_68 17.6 4.3 76.48 93.01 Download
    HarDNet-85 hardnet_85 36.7 9.1 78.04 93.89 Download
    HarDNet-39-ds hardnet_39_ds 3.5 0.4 72.08 90.43 Download
    HarDNet-68-ds hardnet_68_ds 4.2 0.8 74.29 91.87 Download

HarDNet

  • HarDNet指的是 Harmonic DenseNet: A low memory traffic network,其突出的特点就是低内存占用率。
  • 过去几年,随着更强的计算能力和更大的数据集,我们能够训练更加复杂的网络。
  • 对于实时应用,我们面临的问题是如何在提高计算效率的同时,降低功耗。
  • 在这种情况下,作者们提出了HarDNet在两者之间寻求最佳平衡。

模型架构

  • HarDNet可以用于图像分割和目标检测,其架构是基于 Densely Connected Network。
  • 在 HarDNet 中,作者提出了 Harmonic Dense Bocks 的概念。
  • 如下图所示,可以看到该网络就像多个谐波。
  • HarDNet 的全称就是 Harmonic Densely Connected Network。

基于 Paddle2.0 实现 HarDNet 模型 - php中文网        

模型搭建

In [2]
import paddleimport paddle.nn as nn# ConvBN 层(卷积 + 归一化 + 激活函数)def ConvLayer(in_channels, out_channels, kernel_size=3, stride=1, bias_attr=False):
    layer = nn.Sequential(
        ('conv', nn.Conv2D(in_channels, out_channels, kernel_size=kernel_size,
                           stride=stride, padding=kernel_size//2, groups=1, bias_attr=bias_attr)),
        ('norm', nn.BatchNorm2D(out_channels)),
        ('relu', nn.ReLU6())
    )    return layer# dwConvBN 层(深度可分离卷积 + 归一化)def DWConvLayer(in_channels, out_channels, kernel_size=3, stride=1, bias_attr=False):
    layer = nn.Sequential(
        ('dwconv', nn.Conv2D(in_channels, out_channels, kernel_size=kernel_size,
                             stride=stride, padding=1, groups=out_channels, bias_attr=bias_attr)),
        ('norm', nn.BatchNorm2D(out_channels))
    )    return layer# 合并卷积层(ConvBN + dwConvBN)def CombConvLayer(in_channels, out_channels, kernel_size=1, stride=1):
    layer = nn.Sequential(
        ('layer1', ConvLayer(in_channels, out_channels, kernel_size=kernel_size)),
        ('layer2', DWConvLayer(out_channels, out_channels, stride=stride))
    )    return layer# HarD Block class HarDBlock(nn.Layer):
    def __init__(self, in_channels, growth_rate, grmul, n_layers, keepBase=False, residual_out=False, dwconv=False):
        super().__init__()
        self.keepBase = keepBase
        self.links = []
        layers_ = []
        self.out_channels = 0
        for i in range(n_layers):
            outch, inch, link = self.get_link(
                i+1, in_channels, growth_rate, grmul)
            self.links.append(link)
            use_relu = residual_out            if dwconv:
                layers_.append(CombConvLayer(inch, outch))            else:
                layers_.append(ConvLayer(inch, outch))            if (i % 2 == 0) or (i == n_layers - 1):
                self.out_channels += outch

        self.layers = nn.LayerList(layers_)    def get_link(self, layer, base_ch, growth_rate, grmul):
        if layer == 0:            return base_ch, 0, []
        out_channels = growth_rate
        link = []        for i in range(10):
            dv = 2 ** i            if layer % dv == 0:
                k = layer - dv
                link.append(k)                if i > 0:
                    out_channels *= grmul
        out_channels = int(int(out_channels + 1) / 2) * 2
        in_channels = 0
        for i in link:
            ch, _, _ = self.get_link(i, base_ch, growth_rate, grmul)
            in_channels += ch        return out_channels, in_channels, link    def forward(self, x):
        layers_ = [x]        for layer in range(len(self.layers)):
            link = self.links[layer]
            tin = []            for i in link:
                tin.append(layers_[i])            if len(tin) > 1:
                x = paddle.concat(tin, 1)            else:
                x = tin[0]
            out = self.layers[layer](x)
            layers_.append(out)

        t = len(layers_)
        out_ = []        for i in range(t):            if (i == 0 and self.keepBase) or \
               (i == t-1) or (i % 2 == 1):
                out_.append(layers_[i])
        out = paddle.concat(out_, 1)        return out# HarDNetclass HarDNet(nn.Layer):
    def __init__(self, depth_wise=False, arch=85, class_dim=1000, with_pool=True):
        super().__init__()
        first_ch = [32, 64]
        second_kernel = 3
        max_pool = True
        grmul = 1.7
        drop_rate = 0.1

        # HarDNet68
        ch_list = [128, 256, 320, 640, 1024]
        gr = [14, 16, 20, 40, 160]
        n_layers = [8, 16, 16, 16,  4]
        downSamp = [1,  0,  1,  1,  0]        if arch == 85:            # HarDNet85
            first_ch = [48, 96]
            ch_list = [192, 256, 320, 480, 720, 1280]
            gr = [24,  24,  28,  36,  48, 256]
            n_layers = [8,  16,  16,  16,  16,   4]
            downSamp = [1,   0,   1,   0,   1,   0]
            drop_rate = 0.2

        elif arch == 39:            # HarDNet39
            first_ch = [24, 48]
            ch_list = [96, 320, 640, 1024]
            grmul = 1.6
            gr = [16,  20, 64, 160]
            n_layers = [4,  16,  8,   4]
            downSamp = [1,   1,  1,   0]        if depth_wise:
            second_kernel = 1
            max_pool = False
            drop_rate = 0.05

        blks = len(n_layers)
        self.base = nn.LayerList([])        # First Layer: Standard Conv3x3, Stride=2
        self.base.append(
            ConvLayer(in_channels=3, out_channels=first_ch[0], kernel_size=3,
                      stride=2, bias_attr=False))        # Second Layer
        self.base.append(
            ConvLayer(first_ch[0], first_ch[1],  kernel_size=second_kernel))        # Maxpooling or DWConv3x3 downsampling
        if max_pool:
            self.base.append(nn.MaxPool2D(kernel_size=3, stride=2, padding=1))        else:
            self.base.append(DWConvLayer(first_ch[1], first_ch[1], stride=2))        # Build all HarDNet blocks
        ch = first_ch[1]        for i in range(blks):
            blk = HarDBlock(ch, gr[i], grmul, n_layers[i], dwconv=depth_wise)
            ch = blk.out_channels
            self.base.append(blk)            if i == blks-1 and arch == 85:
                self.base.append(nn.Dropout(0.1))

            self.base.append(ConvLayer(ch, ch_list[i], kernel_size=1))
            ch = ch_list[i]            if downSamp[i] == 1:                if max_pool:
                    self.base.append(nn.MaxPool2D(kernel_size=2, stride=2))                else:
                    self.base.append(DWConvLayer(ch, ch, stride=2))

        ch = ch_list[blks-1]

        layers = []        if with_pool:
            layers.append(nn.AdaptiveAvgPool2D((1, 1)))        if class_dim > 0:
            layers.append(nn.Flatten())
            layers.append(nn.Dropout(drop_rate))
            layers.append(nn.Linear(ch, class_dim))

        self.base.append(nn.Sequential(*layers))    def forward(self, x):
        for layer in self.base:
            x = layer(x)        return xdef hardnet_39_ds(pretrained=False, **kwargs):
    model = HarDNet(arch=39, depth_wise=True, **kwargs)    if pretrained:
        params = paddle.load('/home/aistudio/data/data78450/hardnet_39_ds.pdparams')
        model.set_dict(params)    return modeldef hardnet_68(pretrained=False, **kwargs):
    model = HarDNet(arch=68, **kwargs)    if pretrained:
        params = paddle.load('/home/aistudio/data/data78450/hardnet_68.pdparams')
        model.set_dict(params)    return modeldef hardnet_68_ds(pretrained=False, **kwargs):
    model = HarDNet(arch=68, depth_wise=True, **kwargs)    if pretrained:
        params = paddle.load('/home/aistudio/data/data78450/hardnet_68_ds.pdparams')
        model.set_dict(params)    return modeldef hardnet_85(pretrained=False, **kwargs):
    model = HarDNet(arch=85, **kwargs)    if pretrained:
        params = paddle.load('/home/aistudio/data/data78450/hardnet_85.pdparams')
        model.set_dict(params)    return model
   

模型精度验证

In [ ]
# 解压数据集!mkdir ~/data/ILSVRC2012
!tar -xf ~/data/data68594/ILSVRC2012_img_val.tar -C ~/data/ILSVRC2012
   
In [3]
import osimport cv2import numpy as npimport paddleimport paddle.vision.transforms as Tfrom PIL import Image# 构建数据集class ILSVRC2012(paddle.io.Dataset):
    def __init__(self, root, label_list, transform, backend='pil'):
        self.transform = transform
        self.root = root
        self.label_list = label_list
        self.backend = backend
        self.load_datas()    def load_datas(self):
        self.imgs = []
        self.labels = []        with open(self.label_list, 'r') as f:            for line in f:
                img, label = line[:-1].split(' ')
                self.imgs.append(os.path.join(self.root, img))
                self.labels.append(int(label))    def __getitem__(self, idx):
        label = self.labels[idx]
        image = self.imgs[idx]        if self.backend=='cv2':
            image = cv2.imread(image)        else:
            image = Image.open(image).convert('RGB')
        image = self.transform(image)        return image.astype('float32'), np.array(label).astype('int64')    def __len__(self):
        return len(self.imgs)# 配置模型val_transforms = T.Compose([
    T.Resize(256),
    T.CenterCrop(224),
    T.ToTensor(),
    T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
model = hardnet_68(pretrained=True)
model = paddle.Model(model)
model.prepare(metrics=paddle.metric.Accuracy(topk=(1, 5)))# 配置数据集val_dataset = ILSVRC2012('data/ILSVRC2012', transform=val_transforms, label_list='data/data68594/val_list.txt', backend='pil')# 模型验证acc = model.evaluate(val_dataset, batch_size=512, num_workers=0, verbose=1)print(acc)
       
Eval begin...
The loss value printed in the log is the current batch, and the metric is the average value of previous step.
       
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/tensor/creation.py:143: DeprecationWarning: `np.object` is a deprecated alias for the builtin `object`. To silence this warning, use `object` by itself. Doing this will not modify any behavior and is safe. 
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  if data.dtype == np.object:
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dataloader/dataloader_iter.py:89: DeprecationWarning: `np.bool` is a deprecated alias for the builtin `bool`. To silence this warning, use `bool` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.bool_` here.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  if isinstance(slot[0], (np.ndarray, np.bool, numbers.Number)):
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:77: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  return (isinstance(seq, collections.Sequence) and
       
step 98/98 [==============================] - acc_top1: 0.7648 - acc_top5: 0.9301 - 6s/step          
Eval samples: 50000
{'acc_top1': 0.76484, 'acc_top5': 0.9301}
       

模型训练

  • 由于 ImageNet 数据集过大,不太好加载
  • 这里使用 Cifar100 演示一下模型的训练操作
In [4]
# 导入 Paddleimport paddleimport paddle.nn as nnimport paddle.vision.transforms as Tfrom paddle.vision import Cifar100# 加载模型model = hardnet_68(pretrained=True, class_dim=100)# 使用高层 API 进行模型封装model = paddle.Model(model)# 配置优化器opt = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())# 配置损失函数loss = nn.CrossEntropyLoss()# 配置评价指标metric = paddle.metric.Accuracy(topk=(1, 5))# 模型准备model.prepare(optimizer=opt, loss=loss, metrics=metric)# 配置数据增广train_transforms = T.Compose([
    T.Resize(256),
    T.RandomCrop(224),
    T.ToTensor(),
    T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
val_transforms = T.Compose([
    T.Resize(256),
    T.CenterCrop(224),
    T.ToTensor(),
    T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])# 配置数据集train_dataset = Cifar100(mode='train', transform=train_transforms, backend='pil')
val_dataset = Cifar100(mode='test',  transform=val_transforms, backend='pil')# 模型微调model.fit(
    train_data=train_dataset, 
    eval_data=val_dataset, 
    batch_size=256, 
    epochs=1, 
    eval_freq=1, 
    log_freq=1, 
    save_dir='save_models', 
    save_freq=1, 
    verbose=1, 
    drop_last=False, 
    shuffle=True,
    num_workers=0)
       
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1303: UserWarning: Skip loading for base.16.3.weight. base.16.3.weight receives a shape [1024, 1000], but the expected shape is [1024, 100].
  warnings.warn(("Skip loading for {}. ".format(key) + str(err)))
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1303: UserWarning: Skip loading for base.16.3.bias. base.16.3.bias receives a shape [1000], but the expected shape is [100].
  warnings.warn(("Skip loading for {}. ".format(key) + str(err)))
Cache file /home/aistudio/.cache/paddle/dataset/cifar/cifar-100-python.tar.gz not found, downloading https://dataset.bj.bcebos.com/cifar/cifar-100-python.tar.gz 
Begin to download

Download finished
       
The loss value printed in the log is the current step, and the metric is the average value of previous step.
Epoch 1/1
       
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/nn/layer/norm.py:648: UserWarning: When training, we now always track global mean and variance.
  "When training, we now always track global mean and variance.")
       
step 196/196 [==============================] - loss: 1.3977 - acc_top1: 0.5135 - acc_top5: 0.8123 - 2s/step         
save checkpoint at /home/aistudio/save_models/0
Eval begin...
The loss value printed in the log is the current batch, and the metric is the average value of previous step.
step 40/40 [==============================] - loss: 1.1718 - acc_top1: 0.6054 - acc_top5: 0.8826 - 1s/step         
Eval samples: 10000
save checkpoint at /home/aistudio/save_models/final
       

模型精度和速度对比

  • 和常见的 CNN 模型对比结果如下:

基于 Paddle2.0 实现 HarDNet 模型 - php中文网        

总结

  • HarDNet 借助特别设计的 Harmonic Dense Bocks 降低了模型的内存流量,模型的运行效率提升明显
  • 对比其他常见的 CNN 模型,如 FC-DenseNet-103,DenseNet-264,ResNet-50,ResNet-152 和 SSD-VGG,HarDNet 的推理时间减少了 35%,36%,30%,32% 和 45%

相关专题

更多
pytorch是干嘛的
pytorch是干嘛的

pytorch是一个基于python的深度学习框架,提供以下主要功能:动态图计算,提供灵活性。强大的张量操作,实现高效处理。自动微分,简化梯度计算。预构建的神经网络模块,简化模型构建。各种优化器,用于性能优化。想了解更多pytorch的相关内容,可以阅读本专题下面的文章。

431

2024.05.29

Python AI机器学习PyTorch教程_Python怎么用PyTorch和TensorFlow做机器学习
Python AI机器学习PyTorch教程_Python怎么用PyTorch和TensorFlow做机器学习

PyTorch 是一种用于构建深度学习模型的功能完备框架,是一种通常用于图像识别和语言处理等应用程序的机器学习。 使用Python 编写,因此对于大多数机器学习开发者而言,学习和使用起来相对简单。 PyTorch 的独特之处在于,它完全支持GPU,并且使用反向模式自动微分技术,因此可以动态修改计算图形。

20

2025.12.22

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

公务员递补名单公布时间 公务员递补要求
公务员递补名单公布时间 公务员递补要求

公务员递补名单公布时间不固定,通常在面试前,由招录单位(如国家知识产权局、海关等)发布,依据是原入围考生放弃资格,会按笔试成绩从高到低递补,递补考生需按公告要求限时确认并提交材料,及时参加面试/体检等后续环节。要求核心是按招录单位公告及时响应、提交材料(确认书、资格复审材料)并准时参加面试。

38

2026.01.15

公务员调剂条件 2026调剂公告时间
公务员调剂条件 2026调剂公告时间

(一)符合拟调剂职位所要求的资格条件。 (二)公共科目笔试成绩同时达到拟调剂职位和原报考职位的合格分数线,且考试类别相同。 拟调剂职位设置了专业科目笔试条件的,专业科目笔试成绩还须同时达到合格分数线,且考试类别相同。 (三)未进入原报考职位面试人员名单。

52

2026.01.15

国考成绩查询入口 国考分数公布时间2026
国考成绩查询入口 国考分数公布时间2026

笔试成绩查询入口已开通,考生可登录国家公务员局中央机关及其直属机构2026年度考试录用公务员专题网站http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/examResult/written_result.html,查询笔试成绩和合格分数线,点击“笔试成绩查询”按钮,凭借身份证及准考证进行查询。

10

2026.01.15

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

65

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

36

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

75

2026.01.13

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.9万人学习

Django 教程
Django 教程

共28课时 | 3.1万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.1万人学习

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

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