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

论文:HarDNet: A Low Memory Traffic Network
官方实现:PingoLH/Pytorch-HarDNet
验证集数据处理:
# 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 |
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# 解压数据集!mkdir ~/data/ILSVRC2012 !tar -xf ~/data/data68594/ILSVRC2012_img_val.tar -C ~/data/ILSVRC2012
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}# 导入 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 finishedThe 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
以上就是基于 Paddle2.0 实现 HarDNet 模型的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号