本文引入strip pooling策略,以1×N或N×1长条形核实现池化,高效获取大范围感受野信息,并构建相关模块。基于此,使用Caltech101的16类数据集,对比ResNet50等经典模型,搭建含该注意力机制的TowerNet,经训练优化,在像素级预测任务中有效建模远程依赖,取得良好效果。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜
1.事实证明,空间池化在捕获用于场景解析等像素级预测任务的远程上下文信息方面非常有效。在本文中,除了通常具有N x N规则形状的常规空间池化之外,我们通过引入一种称为strip pooling的新池化策略来重新考虑空间池化的公式,该策略考虑了一个长而窄的核,即1 x N或N x1。基于strip pooling,我们进一步研究空间池化体系结构的设计方法。
2.池化操作是在逐像素预测任务中获取较大感受野范围较为高效的做法,传统一般采取N ∗N N* NN∗N的正规矩形区域进行池化,在这篇文章中引入了一种新的池化策略,就是使用长条形的池化kernel来实现池化,即是池化的核心被重新设计为构建了strip pooling操作。
3.这个操作的引入使得网络可以更加高效获取网络大范围感受野下的信息,在这个理念的基础上搭建了使用多个长条池化层构建的新模块。
论文地址:https://arxiv.org/pdf/2003.13328.pdf
我们将网上获取的数据集以压缩包的方式上传到aistudio数据集中,并加载到我们的项目内。
在使用之前我们进行数据集压缩包的一个解压。
In [3]!unzip -oq /home/aistudio/data/data69664/Images.zip -d work/datasetIn [4]
import paddleimport numpy as npfrom typing import Callable#参数配置config_parameters = { "class_dim": 16, #分类数 "target_path":"/home/aistudio/work/", 'train_image_dir': '/home/aistudio/work/trainImages', 'eval_image_dir': '/home/aistudio/work/evalImages', 'epochs':100, 'batch_size': 32, 'lr': 0.01}
接下来我们使用标注好的文件进行数据集类的定义,方便后续模型训练使用。
In [5]import osimport shutil
train_dir = config_parameters['train_image_dir']
eval_dir = config_parameters['eval_image_dir']
paths = os.listdir('work/dataset/Images')if not os.path.exists(train_dir):
os.mkdir(train_dir)if not os.path.exists(eval_dir):
os.mkdir(eval_dir)for path in paths:
imgs_dir = os.listdir(os.path.join('work/dataset/Images', path))
target_train_dir = os.path.join(train_dir,path)
target_eval_dir = os.path.join(eval_dir,path) if not os.path.exists(target_train_dir):
os.mkdir(target_train_dir) if not os.path.exists(target_eval_dir):
os.mkdir(target_eval_dir) for i in range(len(imgs_dir)): if ' ' in imgs_dir[i]:
new_name = imgs_dir[i].replace(' ', '_') else:
new_name = imgs_dir[i]
target_train_path = os.path.join(target_train_dir, new_name)
target_eval_path = os.path.join(target_eval_dir, new_name)
if i % 5 == 0:
shutil.copyfile(os.path.join(os.path.join('work/dataset/Images', path), imgs_dir[i]), target_eval_path) else:
shutil.copyfile(os.path.join(os.path.join('work/dataset/Images', path), imgs_dir[i]), target_train_path)print('finished train val split!')
finished train val split!
我们先看一下解压缩后的数据集长成什么样子,对比分析经典模型在Caltech201抽取16类mini版数据集上的效果
In [7]import osimport randomfrom matplotlib import pyplot as pltfrom PIL import Image
imgs = []
paths = os.listdir('work/dataset/Images')for path in paths:
img_path = os.path.join('work/dataset/Images', path) if os.path.isdir(img_path):
img_paths = os.listdir(img_path)
img = Image.open(os.path.join(img_path, random.choice(img_paths)))
imgs.append((img, path))
f, ax = plt.subplots(4, 4, figsize=(12,12))for i, img in enumerate(imgs[:16]):
ax[i//4, i%4].imshow(img[0])
ax[i//4, i%4].axis('off')
ax[i//4, i%4].set_title('label: %s' % img[1])
plt.show()
#数据集的定义class Dataset(paddle.io.Dataset):
"""
步骤一:继承paddle.io.Dataset类
"""
def __init__(self, transforms: Callable, mode: str ='train'):
"""
步骤二:实现构造函数,定义数据读取方式
"""
super(Dataset, self).__init__()
self.mode = mode
self.transforms = transforms
train_image_dir = config_parameters['train_image_dir']
eval_image_dir = config_parameters['eval_image_dir']
train_data_folder = paddle.vision.DatasetFolder(train_image_dir)
eval_data_folder = paddle.vision.DatasetFolder(eval_image_dir)
if self.mode == 'train':
self.data = train_data_folder elif self.mode == 'eval':
self.data = eval_data_folder def __getitem__(self, index):
"""
步骤三:实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签)
"""
data = np.array(self.data[index][0]).astype('float32')
data = self.transforms(data)
label = np.array([self.data[index][1]]).astype('int64')
return data, label
def __len__(self):
"""
步骤四:实现__len__方法,返回数据集总数目
"""
return len(self.data)
In [ ]
from paddle.vision import transforms as T#数据增强transform_train =T.Compose([T.Resize((256,256)), #T.RandomVerticalFlip(10),
#T.RandomHorizontalFlip(10),
T.RandomRotation(10),
T.Transpose(),
T.Normalize(mean=[0, 0, 0], # 像素值归一化
std =[255, 255, 255]), # transforms.ToTensor(), # transpose操作 + (img / 255),并且数据结构变为PaddleTensor
T.Normalize(mean=[0.50950350, 0.54632660, 0.57409690],# 减均值 除标准差
std= [0.26059777, 0.26041326, 0.29220656])# 计算过程:output[channel] = (input[channel] - mean[channel]) / std[channel]
])
transform_eval =T.Compose([ T.Resize((256,256)),
T.Transpose(),
T.Normalize(mean=[0, 0, 0], # 像素值归一化
std =[255, 255, 255]), # transforms.ToTensor(), # transpose操作 + (img / 255),并且数据结构变为PaddleTensor
T.Normalize(mean=[0.50950350, 0.54632660, 0.57409690],# 减均值 除标准差
std= [0.26059777, 0.26041326, 0.29220656])# 计算过程:output[channel] = (input[channel] - mean[channel]) / std[channel]
])
根据所使用的数据集需求实例化数据集类,并查看总样本量。
In [ ]train_dataset =Dataset(mode='train',transforms=transform_train)
eval_dataset =Dataset(mode='eval', transforms=transform_eval )#数据异步加载train_loader = paddle.io.DataLoader(train_dataset,
places=paddle.CUDAPlace(0),
batch_size=32,
shuffle=True, #num_workers=2,
#use_shared_memory=True
)
eval_loader = paddle.io.DataLoader (eval_dataset,
places=paddle.CUDAPlace(0),
batch_size=32, #num_workers=2,
#use_shared_memory=True
)print('训练集样本量: {},验证集样本量: {}'.format(len(train_loader), len(eval_loader)))
训练集样本量: 45,验证集样本量: 12
本次我们选取了经典的卷积神经网络resnet50,vgg19,mobilenet_v2来进行实验比较。
In [ ]network = paddle.vision.models.vgg19(num_classes=16)#模型封装model = paddle.Model(network)#模型可视化model.summary((-1, 3,256 , 256))In [ ]
network = paddle.vision.models.resnet50(num_classes=16)#模型封装model2 = paddle.Model(network)#模型可视化model2.summary((-1, 3,256 , 256))
#优化器选择class SaveBestModel(paddle.callbacks.Callback):
def __init__(self, target=0.5, path='work/best_model', verbose=0):
self.target = target
self.epoch = None
self.path = path def on_epoch_end(self, epoch, logs=None):
self.epoch = epoch def on_eval_end(self, logs=None):
if logs.get('acc') > self.target:
self.target = logs.get('acc')
self.model.save(self.path) print('best acc is {} at epoch {}'.format(self.target, self.epoch))
callback_visualdl = paddle.callbacks.VisualDL(log_dir='work/vgg19')
callback_savebestmodel = SaveBestModel(target=0.5, path='work/best_model')
callbacks = [callback_visualdl, callback_savebestmodel]
base_lr = config_parameters['lr']
epochs = config_parameters['epochs']def make_optimizer(parameters=None):
momentum = 0.9
learning_rate= paddle.optimizer.lr.CosineAnnealingDecay(learning_rate=base_lr, T_max=epochs, verbose=False)
weight_decay=paddle.regularizer.L2Decay(0.0001)
optimizer = paddle.optimizer.Momentum(
learning_rate=learning_rate,
momentum=momentum,
weight_decay=weight_decay,
parameters=parameters) return optimizer
optimizer = make_optimizer(model.parameters())
model.prepare(optimizer,
paddle.nn.CrossEntropyLoss(),
paddle.metric.Accuracy())
model.fit(train_loader,
eval_loader,
epochs=100,
batch_size=1, # 是否打乱样本集
callbacks=callbacks,
verbose=1) # 日志展示格式
这两种依赖关系对于网络的预测来说都至关重要。因此,MPM分别使用这两个分支生成对应的特征图,然后将两个子模块的输出拼接并用1x1卷积得到最终的输出特征。
In [4]import paddlefrom paddle.fluid.layers.nn import transposeimport paddle.nn as nnimport mathimport paddle.nn.functional as Fclass SPBlock(nn.Layer):
def __init__(self, inplanes, outplanes, norm_layer=None):
super(SPBlock, self).__init__()
midplanes = outplanes
self.conv1 = nn.Conv2D(inplanes, midplanes, kernel_size=(3, 1), padding=(1, 0), bias_attr=False)
self.bn1 = nn.BatchNorm(midplanes)
self.conv2 = nn.Conv2D(inplanes, midplanes, kernel_size=(1, 3), padding=(0, 1), bias_attr=False)
self.bn2 = nn.BatchNorm(midplanes)
self.conv3 = nn.Conv2D(midplanes, outplanes, kernel_size=1, bias_attr=True)
self.pool1 = nn.AdaptiveAvgPool2D((None, 1))
self.pool2 = nn.AdaptiveAvgPool2D((1, None))
self.relu = nn.ReLU()
self.sigmoid = nn.Sigmoid() def forward(self, x):
identity = x
_, _, h, w = x.shape
x1 = self.pool1(x)
x1 = self.conv1(x1)
x1 = self.bn1(x1)
x1 = paddle.expand(x1,[-1, -1, h, w]) #x1 = F.interpolate(x1, (h, w))
x2 = self.pool2(x)
x2 = self.conv2(x2)
x2 = self.bn2(x2)
x2 = paddle.expand(x2,[-1, -1, h, w]) #x2 = F.interpolate(x2, (h, w))
x = self.relu(x1 + x2)
x = x * self.sigmoid(self.conv3(x)) return xif __name__ == '__main__':
x = paddle.randn(shape=[1, 16, 64, 128]) # b, c, h, w
sp_model = SPBlock(16,16)
y = sp_model(x) print(y.shape)
[1, 16, 64, 128]
import paddle.nn.functional as F# 构建模型(Inception层)class Inception(paddle.nn.Layer):
def __init__(self, in_channels, c1, c2, c3, c4):
super(Inception, self).__init__() # 路线1,卷积核1x1
self.route1x1_1 = paddle.nn.Conv2D(in_channels, c1, kernel_size=1) # 路线2,卷积层1x1、卷积层3x3
self.route1x1_2 = paddle.nn.Conv2D(in_channels, c2[0], kernel_size=1)
self.route3x3_2 = paddle.nn.Conv2D(c2[0], c2[1], kernel_size=3, padding=1) # 路线3,卷积层1x1、卷积层5x5
self.route1x1_3 = paddle.nn.Conv2D(in_channels, c3[0], kernel_size=1)
self.route5x5_3 = paddle.nn.Conv2D(c3[0], c3[1], kernel_size=5, padding=2) # 路线4,池化层3x3、卷积层1x1
self.route3x3_4 = paddle.nn.MaxPool2D(kernel_size=3, stride=1, padding=1)
self.route1x1_4 = paddle.nn.Conv2D(in_channels, c4, kernel_size=1) def forward(self, x):
route1 = F.relu(self.route1x1_1(x))
route2 = F.relu(self.route3x3_2(F.relu(self.route1x1_2(x))))
route3 = F.relu(self.route5x5_3(F.relu(self.route1x1_3(x))))
route4 = F.relu(self.route1x1_4(self.route3x3_4(x)))
out = [route1, route2, route3, route4] return paddle.concat(out, axis=1) # 在通道维度(axis=1)上进行连接# 构建 BasicConv2d 层def BasicConv2d(in_channels, out_channels, kernel, stride=1, padding=0):
layer = paddle.nn.Sequential(
paddle.nn.Conv2D(in_channels, out_channels, kernel, stride, padding),
paddle.nn.BatchNorm2D(out_channels, epsilon=1e-3),
paddle.nn.ReLU()) return layer# 搭建网络class TowerNet(paddle.nn.Layer):
def __init__(self, in_channel, num_classes):
super(TowerNet, self).__init__()
self.b1 = paddle.nn.Sequential(
BasicConv2d(in_channel, out_channels=64, kernel=3, stride=2, padding=1),
paddle.nn.MaxPool2D(2, 2))
self.b2 = paddle.nn.Sequential(
BasicConv2d(64, 128, kernel=3, padding=1),
paddle.nn.MaxPool2D(2, 2))
self.b3 = paddle.nn.Sequential(
BasicConv2d(128, 256, kernel=3, padding=1),
paddle.nn.MaxPool2D(2, 2),
SPBlock(256,256))
self.b4 = paddle.nn.Sequential(
BasicConv2d(256, 256, kernel=3, padding=1),
paddle.nn.MaxPool2D(2, 2),
SPBlock(256,256))
self.b5 = paddle.nn.Sequential(
Inception(256, 64, (64, 128), (16, 32), 32),
paddle.nn.MaxPool2D(2, 2),
SPBlock(256,256),
Inception(256, 64, (64, 128), (16, 32), 32),
paddle.nn.MaxPool2D(2, 2),
SPBlock(256,256),
Inception(256, 64, (64, 128), (16, 32), 32))
self.AvgPool2D=paddle.nn.AvgPool2D(2)
self.flatten=paddle.nn.Flatten()
self.b6 = paddle.nn.Linear(256, num_classes) def forward(self, x):
x = self.b1(x)
x = self.b2(x)
x = self.b3(x)
x = self.b4(x)
x = self.b5(x)
x = self.AvgPool2D(x)
x = self.flatten(x)
x = self.b6(x) return x
In [ ]
model = paddle.Model(TowerNet(3, config_parameters['class_dim'])) model.summary((-1, 3, 256, 256))
#优化器选择class SaveBestModel(paddle.callbacks.Callback):
def __init__(self, target=0.5, path='work/best_model', verbose=0):
self.target = target
self.epoch = None
self.path = path def on_epoch_end(self, epoch, logs=None):
self.epoch = epoch def on_eval_end(self, logs=None):
if logs.get('acc') > self.target:
self.target = logs.get('acc')
self.model.save(self.path) print('best acc is {} at epoch {}'.format(self.target, self.epoch))
callback_visualdl = paddle.callbacks.VisualDL(log_dir='work/CA_Inception_Net')
callback_savebestmodel = SaveBestModel(target=0.5, path='work/best_model')
callbacks = [callback_visualdl, callback_savebestmodel]
base_lr = config_parameters['lr']
epochs = config_parameters['epochs']def make_optimizer(parameters=None):
momentum = 0.9
learning_rate= paddle.optimizer.lr.CosineAnnealingDecay(learning_rate=base_lr, T_max=epochs, verbose=False)
weight_decay=paddle.regularizer.L2Decay(0.0002)
optimizer = paddle.optimizer.Momentum(
learning_rate=learning_rate,
momentum=momentum,
weight_decay=weight_decay,
parameters=parameters) return optimizer
optimizer = make_optimizer(model.parameters())
In [ ]
model.prepare(optimizer,
paddle.nn.CrossEntropyLoss(),
paddle.metric.Accuracy())
In [24]
model.fit(train_loader,
eval_loader,
epochs=100,
batch_size=1, # 是否打乱样本集
callbacks=callbacks,
verbose=1) # 日志展示格式
# 压缩包
# 在这个
# 长条形
# 如上图
# 是在
# 标准差
# 加载
# 均值
# 解压缩
# ai
# 数据结构
# 重构
# https
# asic
# igs
# red
# cos
# 异步加载
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
网络优化91478 】
【
技术知识72672 】
【
云计算0 】
【
GEO优化84317 】
【
优选文章0 】
【
营销推广36048 】
【
网络运营41350 】
【
案例网站102563 】
【
AI智能45237 】
相关推荐:
Logic Pro 11更新全面解析:免费升级、AI功能与音乐制作流程
AI一键生成原创SEO文章
谷歌 Nano Banana:免费AI图像生成的强大工具
百度ai助手通知栏怎么关 百度ai助手通知消息屏蔽
AI视频制作教程:从图像到病毒式Vlog全攻略
Amazon Rekognition: 图像与视频分析的强大AI工具
雷小兔ai智能写作怎样导入素材_雷小兔ai智能写作素材上传与引用【技巧】
百度APP搜索框ai怎么关 百度APP搜索框ai图标去除
提升企业效率:QR Platform管理后台功能全面解析
DeepSeek分析Excel怎么用_DeepSeek分析Excel使用方法详细指南【教程】
豆包 AI 辅助进行家庭装修风格对比分析
软件工程师必备的AI工具:提升效率的六款利器
利用Gen AI和AI Agent进行软件测试:Ollama本地LLM实践
寻宝者的发现:古董探测与文物挖掘揭秘
壹伴AI智能排版如何自动生成文章配图_壹伴AI智能排版配图生成与版权说明【教程】
如何让ChatGPT模仿特定文风 创意写作与品牌话术生成教程
AI赋能招聘:高级策略助你领先猎头行业
PandaDoc vs. SignEasy: 2025 eSignature 平台终极对比
AI旅游攻略生成工具有哪些_一键生成行程规划的AI工具推荐
豆包AI怎么生成员工成长总结_豆包AI成长指标提取与案例编写【方法】
百度AI助手直接入口 一键直达官网入口
Semrush AI标题生成器:免费提升SEO和内容创作效率
AI 播客脚本写作工具:提升内容创作效率的终极指南
2025 YouTube自动化终极指南:利用AI实现高效内容创作和多平台发布
一键改变发型:Gemini AI 助你轻松打造时尚造型
Gemini手机端怎么开无障碍_Gemini无障碍设置方法【步骤】
eBookWriter AI:无需写作也能创作专业电子书
即梦ai能否生成节日主题插画_即梦ai节日主题关键词与元素库使用【攻略】
通义万相做小红书配图怎么用_通义万相做小红书配图使用方法详细指南【教程】
Claude如何导出对话记录_Claude对话导出方法【方法】
扣子AI如何绑定自有域名_扣子AI域名绑定与SSL配置【步骤】
理论框架写作指南:3步构建研究基石
Google Gemini 对复杂物理解题过程的逐步解析
10平米房间设计终极挑战:人类 vs AI,DIY极简主义胜出!
AI破译古文字:重现失落文明之声,揭秘历史真相
AI PPT生成工具有哪些_一键生成演示文稿的AI工具推荐
AI赋能抵押贷款:Total Expert AI 销售助理深度解析
如何用AI一键生成手机壁纸?4K高清AI壁纸生成关键词【分享】
豆包AI里的智能体有什么用_不同类型智能体使用场景介绍
Google NotebookLM:科研文献综述的免费AI工具
Tenorshare PDNob:免费AI图像翻译器,即时转换图像为文本
AI赋能科研探索:Google Research创新加速科学发现
AI时代软件工程师如何破局?未来必备技能全解析
TopMedi AI:AI语音克隆和文本转语音终极指南
SEO必备工具:网站分析与优化终极指南
Weavernote:AI驱动的知识管理与高效笔记应用
支付宝出行AI能否自动抢票_支付宝AI出行抢票设置与免密支付【方法】
AI末日预言?智能聊天机器人真的能替代信仰吗?
提升房地产业务:AI语音助手赋能房地产经纪公司
利用AI自动化回复Google Voice短信:终极指南
2025-07-25
南京市珐之弘网络技术有限公司专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。