-
2022-01-28 08:49:43更多相关内容
-
SpringBatch+Spring+Mybatis+MySql (spring batch 使用jar)
2015-04-01 17:35:35Spring Batch是一个轻量级的,完全面向Spring的批处理框架,可以应用于企业级大量的数据处理系统。Spring Batch以POJO和大家熟知的Spring框架为基础,使开发者更容易的访问和利用企业级服务。Spring Batch可以提供... -
spring-batch+quartz处理mysql数据示例
2016-01-14 16:39:00spring-batch+quartz处理mysql数据示例,功能:定时从mysql里读取数据,进行处理,再存入到mysql -
mybatis批量插入优化(ExecutorType.BATCH/BatchInsert/executeBatch)
2021-12-29 23:00:46batch模式重复使用已经预处理的语句,并且批量执行所有语句,大批量模式下性能更优。 请注意batch模式在Insert操作时事务没有提交之前,是没有办法获取到自增的id,所以请根据业务情况使用。 使用simple模式提交...总结
-
Mybatis内置的
ExecutorType
有3种,默认的是simple
单句模式,该模式下它为每个语句的执行创建一个新的预处理语句,单句提交sql;batch模式
重复使用已经预处理的语句,并且批量执行所有语句,大批量模式下性能更优。- 请注意
batch模式
在Insert操作时事务没有提交之前,是没有办法获取到自增的id
,所以请根据业务情况使用。 - 使用simple模式提交10000条数据,时间为19s,batch模式为6s ,大致情况如此,优化的具体还要看提交的语句情况。
- 请注意
-
如果需要使用
foreach
来优化数据插入的话,需要将每次插入的记录控制在 10-100 左右是比较快的,建议每次100来分割数据,也就是分而治之
思想。
普通插入
默认的插入方式是遍历insert语句,单条执行,效率肯定低下,如果成堆插入,更是性能有问题。
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
foreach 优化插入
如果要优化插入速度时,可以将许多小型操作组合到一个大型操作中。理想情况下,这样可以在单个连接中一次性发送许多新行的数据,并将所有索引更新和一致性检查延迟到最后才进行。
<insert id="batchInsert" parameterType="java.util.List"> insert into table1 (field1, field2) values <foreach collection="list" item="t" index="index" separator=","> (#{t.field1}, #{t.field2}) </foreach> </insert>
翻译成sql语句也就是
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"), ("data1", "data2"), ("data1", "data2"), ("data1", "data2"), ("data1", "data2");
foreach 遇到数量大,性能瓶颈
项目实践发现,当表的列数较多(超过20),以及一次性插入的行数较多(上万条)时,插入性能非常差,通常需要20分钟以上
这个时候就需要观察曲线了,10-100个来讲是很快的,当然也要根据项目请来看,总之建议100个就ok了,不要太高。
executeBatch方法批量执行的一种方式,使用
PreparedStatement
预编译进行优化。int insertNum = 100; Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/xxx?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false&rewriteBatchedStatements=true","root","root123"); connection.setAutoCommit(false); PreparedStatement ps = connection.prepareStatement( "insert into table1(field1) values(?)"); for (int i = 0; i < insertNum; i++) { ps.setString(1,"大狼狗"+insertNum); ps.addBatch(); } ps.executeBatch(); connection.commit(); connection.close();
开启ExecutorType.BATCH模式
简单的讲就是openSession的时候带上参数
ExecutorType.BATCH
,可以几乎无损优化你的代码性能。SqlSession session = sessionFactory.openSession(ExecutorType.BATCH); for (Model model : list) { session.insert("insertStatement", model); } session.flushStatements();
BatchInsert模式
也是官方针对批量数据插入优化的方法之一
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH); try { TableMapper mapper = session.getMapper(TableMapper.class); //自定义你的方法来获取需要插入的数据 List<TableRecord> records = getRecordsToInsert(); //BatchInsert BatchInsert<TableRecord> batchInsert = insert(records) .into(table) .map(id).toProperty("id") .map(field1).toProperty("field1") .map(field2).toProperty("field2") .build() .render(RenderingStrategy.MYBATIS3); batchInsert.insertStatements().stream().forEach(mapper::insert); session.commit(); } finally { session.close(); }
-
-
Batchsize不够大,如何发挥BN性能?探讨神经网络在小Batch下的训练方法
2020-12-30 10:08:34由于算力的限制,有时我们无法使用足够大的batchsize,此时该如何使用BN呢?本文将介绍两种在小batchsize也可以发挥BN性能的方法。 前言 BN(Batch Normalization)几乎是目前神经网络的必选组件,但是使用BN有两...由于算力的限制,有时我们无法使用足够大的batchsize,此时该如何使用BN呢?本文将介绍两种在小batchsize也可以发挥BN性能的方法。
前言
BN(Batch Normalization)几乎是目前神经网络的必选组件,但是使用BN有两个前提要求:
-
batchsize不能太小;
-
每一个minibatch和整体数据集同分布。
不然的话,非但不能发挥BN的优势,甚至会适得其反。但是由于算力的限制,有时我们无法使用足够大的batchsize,此时该如何使用BN呢?本文介绍两篇在小batchsize也可以发挥BN性能的方法。解决思路为:既然batchsize太小的情况下,无法保证当前minibatch收集到的数据和整体数据同分布。那么能否多收集几个batch的数据进行统计呢?这两篇工作分别分别是:
-
BRN:Batch Renormalization: Towards Reducing Minibatch Dependence in Batch-Normalized Models
-
CBN:Cross-Iteration Batch Normalization
另外,本文也会给出代码解析,帮助大家理解。
batchsize过小的场景
通常情况下,大家对CNN任务的研究一般为公开的数据集指标负责。分类任务为ImageNet数据集负责,其尺度为224X224。检测任务为coco数据集负责,其尺度为640X640左右。分割任务一般为coco或PASCAL VOC数据集负责,后者的尺度大概在500X500左右。再加上例如resize的前处理操作,真正送入网络的图片的分辨率都不算太大。一般性能的GPU也很容易实现大的batchsize(例如大于32)的支持。
但是实际的项目中,经常遇到需要处理的图片尺度过大的场景,例如我们使用500w像素甚至2000w像素的工业相机进行数据采集,500w的相机采集的图片尺度就是2500X2000左右。而对于微小的缺陷检测、高精度的关键点检测或小物体的目标检测等任务,我们一般不太想粗暴降低输入图片的分辨率,这样违背了我们使用高分辨率相机的初衷,也可能导致丢失有用特征。在算力有限的情况下,我们的batchsize就无法设置太大,甚至只能为1或2。小的batchsize会带来很多训练上的问题,其中BN问题就是最突出的。虽然大batchsize训练是一个共识,但是现实中可能无法具有充足的资源,因此我们需要一些处理手段。
BN回顾
首先Batch Normalization 中的Normalization被称为标准化,通过将数据进行平和缩放拉到一个特定的分布。BN就是在batch维度上进行数据的标准化。BN的引入是用来解决 internal covariate shift 问题,即训练迭代中网络激活的分布的变化对网络训练带来的破坏。BN通过在每次训练迭代的时候,利用minibatch计算出的当前batch的均值和方差,进行标准化来缓解这个问题。虽然How Does Batch Normalization Help Optimization 这篇文章探究了BN其实和Internal Covariate Shift (ICS)问题关系不大,本文不深入讨论,这个会在以后的文章中细说。
一般来说,BN有两个优点:
-
降低对初始化、学习率等超参的敏感程度,因为每层的输入被BN拉成相对稳定的分布,也能加速收敛过程。
-
应对梯度饱和和梯度弥散,主要是对于使用sigmoid和tanh的激活函数的网络。
当然,BN的使用也有两个前提:
-
minibatch和全部数据同分布。因为训练过程每个minibatch从整体数据中均匀采样,不同分布的话minibatch的均值和方差和训练样本整体的均值和方差是会存在较大差异的,在测试的时候会严重影响精度。
-
batchsize不能太小,否则效果会较差,论文给的一般性下限是32。
再来回顾一下BN的具体做法:
-
训练的时候:使用当前batch统计的均值和方差对数据进行标准化,同时优化优化gamma和beta两个参数。另外利用指数滑动平均收集全局的均值和方差。
-
测试的时候:使用训练时收集全局均值和方差以及优化好的gamma和beta进行推理。
可以看出,要想BN真正work,就要保证训练时当前batch的均值和方差逼近全部数据的均值和方差。
BRN
论文题目:Batch Renormalization: Towards Reducing Minibatch Dependence in Batch-Normalized Models
论文地址: https://arxiv.org/pdf/1702.03275.pdf
代码地址: https://github.com/ludvb/batchrenorm
核心解析:
本文的核心思想就是:训练过程中,由于batchsize较小,当前minibatch统计到的均值和方差与全部数据有差异,那么就对当前的均值和方差进行修正。修正的方法主要是利用到通过滑动平均收集到的全局均值和标准差。看公式:
上面公式中,i表示网络的第i层。μ和σ表示网络推理时的均值和标准差,也就是训练过程通过滑动平均收集的到均值和方差。μB和σb表示当前训练迭代过程中的实际统计到的均值和标准差。BN在小batch不work的根本原因就是这两组参数存在较大的差异。通过r和d对训练过程中数据进行线性变换,在该变化下,上公式左右两端就严格相等了。其实标准的BN就是r=1,d=0的一种情况。对于某一个特定的minibatch,其中r和d可以看成是固定的,是直接计算出来的,不需要梯度优化的。
具体流程:
-
统计当前batch数据的均值和标注差,和标准BN做法一致。
-
根据当前batch的均值和标准差结合全局的均值和标准差利用上面的公式计算r和d;注意该运算是不参与梯度反向传播的。另外,r和d需要增加一个限制,直接clip操作就好。
-
利用当前的均值和标准差对当前数据执行Normalization操作,利用上面计算得到的r和d对当前batch进行线性变换。
-
滑动平均收集全局均值和标注差。
测试过程和标准BN一样。其实本质上,就是训练的过程中使用全局的信息进行更新当前batch的数据。间接利用了全局的信息,而非当前这一个batch的信息。
实验效果:
在较大的batchsize(32)的时候,与标准BN相比,不会丢失效果,训练过程一如既往稳定高效。如下:
在小的batchsize(4)下, 本文做法依然接近batchsize为32的时候,可见在小batchsize下是work的。
代码解析:
def forward(self, x):
if x.dim() > 2:
x = x.transpose(1, -1)
if self.training: # 训练过程
dims = [i for i in range(x.dim() - 1)
batch_mean = x.mean(dims) # 计算均值
batch_std = x.std(dims, unbiased=False) + self.eps # 计算标准差
# 按照公式计算r和d
r = (batch_std.detach() / self.running_std.view_as(batch_std)).clamp_(1 / self.rmax, self.rmax)
d = ((batch_mean.detach() - self.running_mean.view_as(batch_mean))
/ self.running_std.view_as(batch_std)).clamp_(-self.dmax, self.dmax)
# 对当前数据进行标准化和线性变换
x = (x - batch_mean) / batch_std * r + d
# 滑动平均收集全局均值和标注差
self.running_mean += self.momentum * (batch_mean.detach() - self.running_mean)
self.running_std += self.momentum * (batch_std.detach() - self.running_std)
self.num_batches_tracked += 1
else: # 测试过程
x = (x - self.running_mean) / self.running_std
return x
CBN
论文题目:Cross-Iteration Batch Normalization
论文地址:https://arxiv.org/abs/2002.05712
代码地址:https://github.com/Howal/Cross-iterationBatchNorm
本文认为BRN的问题在于它使用的全局均值和标准差不是当前网络权重下获取的,因此不是exactly正确的,所以batchsize再小一点,例如为1或2时就不太work了。本文使用泰勒多项式逼近原理来修正当前的均值和标准差,同样也是间接利用了全局的均值和方差信息。简述就是:当前batch的均值和方差来自之前的K次迭代均值和方差的平均,由于网络权重一直在更新,所以不能直接粗暴求平均。本文而是利用泰勒公式估计前面的迭代在当前权重下的数值。
泰勒公式:
泰勒公式是一个用函数在某点的信息描述其附近取值的公式。如果函数满足一定的条件,泰勒公式可以用函数在某一点的各阶导数值做系数构建一个多项式来近似表达这个函数。教科书介绍如下:
核心解析:
本文做法,由于网络一般使用SGD更新权重,因此网络权重的变化是平滑的,所以适用泰勒公式。如下,t为训练过程中当前迭代时刻,t-τ为t时刻向前τ时刻。θ为网络权重,权重下标代表该权重的时刻。μ为当前minibatch均值,v为当强minibatch平方的均值,是为了计算标准差。因此直接套用泰勒公式得到:
上面这两个公式就是为了估计在t-τ时刻,t时刻的权重下的均值和方差的参数估计。BRN可以看作没有进行该方法估计,使用的依然是t-τ时刻权重的参数估计。其中O为高阶项,因为该式主要由一阶项控制,因此高阶项目可以忽略。上面的公式还要进一步简化,主要是偏导项的求法。假设当前层为l,实际上∂μ/ ∂θ 和 ∂ν/∂θ依赖与所有l层之前层的权重,求导计算量极大。不过经验观察到,l层之前层的偏数下降很快,因此可以忽略掉,仅仅计算当前层的权重偏导。
因此化简为如下,可以看出,求偏导的部分,只考虑对当前层的偏导数,注意上标l表示网络层的意思。至此,之前时刻在当前权重下的均值和方差已经估计出来了。
下面穿插代码解析整个计算过程。
首先是统计计算当前batch的数据,和标准BN没有差别。代码为:
cur_mu = y.mean(dim=1) # 当前层的均值
cur_meanx2 = torch.pow(y, 2).mean(dim=1) # 当前值平方的均值,计算标准差使用
cur_sigma2 = y.var(dim=1) # 当前值的方差
对当前网络层求偏导,直接使用torch的内置函数。代码:
# 注意 grad_outputs = self.ones : 不同值的梯度对结果影响程度不同,类似torch.sum()的作用。
dmudw = torch.autograd.grad(cur_mu, weight, self.ones, retain_graph=True)[0]
dmeanx2dw = torch.autograd.grad(cur_meanx2, weight, self.ones, retain_graph=True)[0]
使用公式(7)和(8)继续下面的计算,也就是向前累计K次估计数值,更新到当前batch的均值和方差的计算上,这里引入了一个超参就是k的大小,它表示当前的迭代向后回溯到多长的步长的迭代。实验探究k=8是一个比较折中的选择。k=1的时候,RBN退化成了原始的BN:
代码如下,其中这里的self.pre_mu, self.pre_dmudw, self.pre_weight是前面每次迭代收集到了窗口k大小的数值,分别代表均值、均值对权重的偏导、权重。self.pre_meanx2, self.pre_dmeanx2dw, self.pre_weight同理,是对应平方均值的。
# 利用泰勒公式估计
mu_all = torch.stack \
([cur_mu, ] + [tmp_mu + (self.rho * tmp_d * (weight.data - tmp_w)).sum(1).sum(1).sum(1) for tmp_mu, tmp_d, tmp_w in zip(self.pre_mu, self.pre_dmudw, self.pre_weight)])
meanx2_all = torch.stack \
([cur_meanx2, ] + [tmp_meanx2 + (self.rho * tmp_d * (weight.data - tmp_w)).sum(1).sum(1).sum(1) for tmp_meanx2, tmp_d, tmp_w in zip(self.pre_meanx2, self.pre_dmeanx2dw, self.pre_weight)])
上面所说的变量收集迭代过程如下:
# 动态维护buffer_num长度的均值、均值平方、偏导、权重
self.pre_mu = [cur_mu.detach(), ] + self.pre_mu[:(self.buffer_num - 1)]
self.pre_meanx2 = [cur_meanx2.detach(), ] + self.pre_meanx2[:(self.buffer_num - 1)]
self.pre_dmudw = [dmudw.detach(), ] + self.pre_dmudw[:(self.buffer_num - 1)]
self.pre_dmeanx2dw = [dmeanx2dw.detach(), ] + self.pre_dmeanx2dw[:(self.buffer_num - 1)]
tmp_weight = torch.zeros_like(weight.data)
tmp_weight.copy_(weight.data)
self.pre_weight = [tmp_weight.detach(), ] + self.pre_weight[:(self.buffer_num - 1)]
计算获取当前batch的均值和方差,取修正后的K次迭代数据的平均即可。
# 利用收集到的一定窗口长度的均值和平方均值,计算当前均值和方差
sigma2_all = meanx2_all - torch.pow(mu_all, 2)
re_mu_all = mu_all.clone()
re_meanx2_all = meanx2_all.clone()
re_mu_all[sigma2_all < 0] = 0
re_meanx2_all[sigma2_all < 0] = 0
count = (sigma2_all >= 0).sum(dim=0).float()
mu = re_mu_all.sum(dim=0) / count # 平均操作
sigma2 = re_meanx2_all.sum(dim=0) / count - torch.pow(mu, 2)
均值和方差使用过程,和标准BN没有区别。
# 标准化过程,和原始BN没有区别
y = y - mu.view(-1, 1)
if self.out_p: # 仅仅控制开平方的位置
y = y / (sigma2.view(-1, 1) + self.eps) ** .5
else:
y = y / (sigma2.view(-1, 1) ** .5 + self.eps)
最后再理解一下:
mu_0是当前batch统计获取的均值,mu_1是上一batch统计获取的均值。当前batch计算BN的时候也想利用到mu_1,但是统计mu_1的时候利用到网络的权重也是上一次的,直接使用肯定有问题,所以本文使用泰勒公式估计出mu_1在当前权重下应该是什么样子。方差估计同理。
实验效果:
这里的Naive CBN 是上一篇论文BRN的做法,可以认为是CBN不使用泰勒估计的一种特例。在batchsize下降的过程中,CBN指标依然坚挺,甚至超过了GN(不过也侧面反应了GN确实厉害)。而原始BN和其改进版BRN在batchsize更小的时候都不太work了。
-
-
TensorRT(8):动态batch进行推理
2021-08-19 10:29:50模型训练时,每次训练可以接受不同batch大小的数据进行迭代,同样,在推理时,也会遇到输入Tensor大小(shape)是不确定的情况,其中最常见的就是动态batch了。 动态batch,故名思意,就是只batch大小不确定的情况,...
TensorRT系列传送门(不定期更新): 深度框架|TensorRT
一、引言
模型训练时,每次训练可以接受不同batch大小的数据进行迭代,同样,在推理时,也会遇到输入Tensor大小(shape)是不确定的情况,其中最常见的就是动态batch了。
动态batch,故名思意,就是只batch大小不确定的情况,比如这次推理了一张图像,下次推理就需要同时推理两张图像。
在Tensorflow中,定义一个动态batch的Tensor可以用 -1来表示动态的维度
tf.placeholder(tf.float32, shape=(-1, 1024))
而在TensorRT中,又是如何定义动态维度的呢?
本篇文章主要记录一下博主在TensorRT中使用动态batch的一些方法及技巧,如有错误,欢迎指正。
二、TRT在线加载模型,并序列化保存支持动态batch的引擎
这里与之前固定batch建立engine的流程相似,也需要经历以下几个步骤
- 1、创建一个builder
- 3、创建一个netwok
- 4、建立一个 Parser
- 5、建立 engine
- 6、建议contex
区别时建议engine时,config里需要设置一下OptimizationProfile文件
- step1 准备工作
首先准备一个具有动态batch的onnx模型,
至于如何从pytorch转支持动态batch的onnx模型,我在另一篇文章中,做过介绍,具体见转出后,可以用netron来查看,转持的onnx模型,是否支持动态维度。
- step2 序列化保存模型的函数
#include <iostream> #include "NvInfer.h" #include "NvOnnxParser.h" #include "logging.h" #include "opencv2/opencv.hpp" #include <fstream> #include <sstream> #include "cuda_runtime_api.h" static Logger gLogger; using namespace nvinfer1; bool saveEngine(const ICudaEngine& engine, const std::string& fileName) { std::ofstream engineFile(fileName, std::ios::binary); if (!engineFile) { std::cout << "Cannot open engine file: " << fileName << std::endl; return false; } IHostMemory* serializedEngine = engine.serialize(); if (serializedEngine == nullptr) { std::cout << "Engine serialization failed" << std::endl; return false; } engineFile.write(static_cast<char*>(serializedEngine->data()), serializedEngine->size()); return !engineFile.fail(); }
- step3 加载onnx模型,并构建动态Trt引擎
// 1、创建一个builder IBuilder* pBuilder = createInferBuilder(gLogger); // 2、 创建一个 network,要求网络结构里,没有隐藏的批量处理维度 INetworkDefinition* pNetwork = pBuilder->createNetworkV2(1U << static_cast<int>(NetworkDefinitionCreationFlag::kEXPLICIT_BATCH)); // 3、 创建一个配置文件 nvinfer1::IBuilderConfig* config = pBuilder->createBuilderConfig(); // 4、 设置profile,这里动态batch专属 IOptimizationProfile* profile = pBuilder->createOptimizationProfile(); // 这里有个OptProfileSelector,这个用来设置优化的参数,比如(Tensor的形状或者动态尺寸), profile->setDimensions("input_1", OptProfileSelector::kMIN, Dims4(1, 1, 112, 112)); profile->setDimensions("input_1", OptProfileSelector::kOPT, Dims4(2, 1, 112, 112)); profile->setDimensions("input_1", OptProfileSelector::kMAX, Dims4(4, 1, 112, 112)); config->addOptimizationProfile(profile); auto parser = nvonnxparser::createParser(*pNetwork, gLogger.getTRTLogger()); char* pchModelPth = "./res_hjxu_temp_dynamic.onnx"; if (!parser->parseFromFile(pchModelPth, static_cast<int>(gLogger.getReportableSeverity()))) { printf("解析onnx模型失败\n"); } int maxBatchSize = 4; pBuilder->setMaxWorkspaceSize(1 << 30); pBuilder->setMaxBatchSize(maxBatchSize); 设置推理模式 builder->setFp16Mode(true); ICudaEngine* engine = pBuilder->buildEngineWithConfig(*pNetwork, *config); std::string strTrtSavedPath = "./res_hjxu_temp_dynamic.trt"; // 序列化保存模型 saveEngine(*engine, strTrtSavedPath); nvinfer1::Dims dim = engine->getBindingDimensions(0); // 打印维度 print_dims(dim);
这里print_dims就是打印维度
void print_dims(const nvinfer1::Dims& dim) { for (int nIdxShape = 0; nIdxShape < dim.nbDims; ++nIdxShape) { printf("dim %d=%d\n", nIdxShape, dim.d[nIdxShape]); } }
可以看到,打印的dim0就是-1啦。
- step4 类IOptimizationProfile和枚举OptProfileSelector的简短介绍
我们可以看出,和固定batch构建engine不同之处,在设置build配置时时,增加了个
IOptimizationProfile*
配置文件,如设置维度需要增加以下操作
如nvinfer1::IOptimizationProfile* createOptimizationProfile() profile->setDimensions("input_1", OptProfileSelector::kMIN, Dims4(1, 1, 112, 112)); profile->setDimensions("input_1", OptProfileSelector::kOPT, Dims4(2, 1, 112, 112)); profile->setDimensions("input_1", OptProfileSelector::kMAX, Dims4(4, 1, 112, 112));
咱们来看看
IOptimizationProfile
这个类class IOptimizationProfile { public: //! 设置动态inputTensor的最小/最合适/最大维度 //! 不管时什么网络的输入的tensor,这个函数必须被调用三次(for the minimum, optimum, and maximum) //! 一下列举了三种情况 //! (1) minDims.nbDims == optDims.nbDims == maxDims.nbDims == networkDims.nbDims //! (2) 0 <= minDims.d[i] <= optDims.d[i] <= maxDims.d[i] for i = 0, ..., networkDims.nbDims-1 //! (3) if networkDims.d[i] != -1, then minDims.d[i] == optDims.d[i] == maxDims.d[i] == networkDims.d[i] //! 如果选择了DLA,这三个值必须相同的 //! virtual bool setDimensions(const char* inputName, OptProfileSelector select, Dims dims) noexcept = 0; //! \brief Get the minimum / optimum / maximum dimensions for a dynamic input tensor. virtual Dims getDimensions(const char* inputName, OptProfileSelector select) const noexcept = 0; //! \brief Set the minimum / optimum / maximum values for an input shape tensor. virtual bool setShapeValues( const char* inputName, OptProfileSelector select, const int32_t* values, int32_t nbValues) noexcept = 0; //! \brief Get the number of values for an input shape tensor. virtual int32_t getNbShapeValues(const char* inputName) const noexcept = 0; //! \brief Get the minimum / optimum / maximum values for an input shape tensor. virtual const int32_t* getShapeValues(const char* inputName, OptProfileSelector select) const noexcept = 0; //! \brief Set a target for extra GPU memory that may be used by this profile. //! \return true if the input is in the valid range (between 0 and 1 inclusive), else false //! virtual bool setExtraMemoryTarget(float target) noexcept = 0; //! \brief Get the extra memory target that has been defined for this profile. virtual float getExtraMemoryTarget() const noexcept = 0; //! \brief Check whether the optimization profile can be passed to an IBuilderConfig object. //! \return true if the optimization profile is valid and may be passed to an IBuilderConfig, else false virtual bool isValid() const noexcept = 0; protected: ~IOptimizationProfile() noexcept = default; };
再看OptProfileSelector 这个枚举
这个枚举就三个值。最小、合适、和最大// 最小和最大,指运行时,允许的最小和最大的范围 // 最佳值,用于选择内核,这里通常为运行时,最期望的大小 // 比如在模型推理时,有两路数据,通常batch就为2,batch为1或者为4出现的概率都比较低, // 这时候,建议kOPT选择2, min选择1,如果最大路数为4,那max就选择四
enum class OptProfileSelector : int32_t { kMIN = 0, //!< This is used to set or get the minimum permitted value for dynamic dimensions etc. kOPT = 1, //!< This is used to set or get the value that is used in the optimization (kernel selection). kMAX = 2 //!< This is used to set or get the maximum permitted value for dynamic dimensions etc. };
三、反序列化加载动态batch的引擎,并构建动态context,执行动态推理
定义一个加载engine的函数,和固定batch时一样的
ICudaEngine* loadEngine(const std::string& engine, int DLACore) { std::ifstream engineFile(engine, std::ios::binary); if (!engineFile) { std::cout << "Error opening engine file: " << engine << std::endl; return nullptr; } engineFile.seekg(0, engineFile.end); long int fsize = engineFile.tellg(); engineFile.seekg(0, engineFile.beg); std::vector<char> engineData(fsize); engineFile.read(engineData.data(), fsize); if (!engineFile) { std::cout << "Error loading engine file: " << engine << std::endl; return nullptr; } IRuntime* runtime = createInferRuntime(gLogger); if (DLACore != -1) { runtime->setDLACore(DLACore); } return runtime->deserializeCudaEngine(engineData.data(), fsize, nullptr); }
然后按以下步骤执行推理
- 创建engine
- 创建context
- 在显卡上创建最大batch的的内存空间,这样只需要创建一次,避免每次推理都重复创建,浪费时间
- 拷贝动态tensor的内存
- 设置动态维度,调用context->setBindingDimensions()函数
- 调用context执行推理
- 查看输出结果
void test_engine() { std::string strTrtSavedPath = "./res_hjxu_temp_dynamic.trt"; int maxBatchSize = 4; // 1、反序列化加载引擎 ICudaEngine* engine = loadEngine(strTrtSavedPath, 0); // 2、创建context IExecutionContext* context = engine->createExecutionContext(); int nNumBindings = engine->getNbBindings(); std::vector<void*> vecBuffers; vecBuffers.resize(nNumBindings); int nInputIdx = 0; int nOutputIndex = 1; int nInputSize = 1 * 112 * 112 * sizeof(float); // 4、在cuda上创建一个最大的内存空间 (cudaMalloc(&vecBuffers[nInputIdx], nInputSize * maxBatchSize)); (cudaMalloc(&vecBuffers[nOutputIndex], maxBatchSize * 2 * sizeof(float))); char* pchImgPath = "./img.bmp"; cv::Mat matImg = cv::imread(pchImgPath, -1); std::cout << matImg.rows << std::endl; cv::Mat matRzImg; cv::resize(matImg, matRzImg, cv::Size(112, 112)); cv::Mat matF32Img; matRzImg.convertTo(matF32Img, CV_32FC1); matF32Img = matF32Img / 255.; for (int i = 0; i < maxBatchSize; ++i) { cudaMemcpy((unsigned char *)vecBuffers[nInputIdx] + nInputSize * i, matF32Img.data, nInputSize, cudaMemcpyHostToDevice); } // 动态维度,设置batch = 1 0指第0个tensor的维度 context->setBindingDimensions(0, Dims4(1, 1, 112, 112)); nvinfer1::Dims dim = context->getBindingDimensions(0); context->executeV2(vecBuffers.data()); //context->execute(1, vecBuffers.data()); float prob[8]; (cudaMemcpy(prob, vecBuffers[nOutputIndex], maxBatchSize * 2 * sizeof(float), cudaMemcpyDeviceToHost)); for (int i = 0; i < 8; ++i) { std::cout << prob[i] << " "; } std::cout <<"\n-------------------------" << std::endl; // 动态维度,设置batch = 4 context->setBindingDimensions(0, Dims4(4, 1, 112, 112)); context->executeV2(vecBuffers.data()); //context->execute(1, vecBuffers.data()); (cudaMemcpy(prob, vecBuffers[nOutputIndex], maxBatchSize * 2 * sizeof(float), cudaMemcpyDeviceToHost)); for (int i = 0; i < 8; ++i) { std::cout << prob[i] << " "; } std::cout << "\n-------------------------" << std::endl; //std::cout << prob[0] << " " << prob[1] << std::endl; // call api to release memory /// ... return ; }
结果打印中,可以看到,当batch为1时,输出后面6个值为0,当batch为4是,输出后面六个值都有正确的结果。咱们这里调用的是二分类的resnet50网络.
-
神经网络中epoch、batch、batch_size、epoch、iteration理解
2022-03-01 09:14:32在不能将数据一次性通过神经网络的适合,就需要将数据集分成几个batch。 3 batch_size 直观的理解 一个batch中的样本总数(一次训练所选取的样本数)。batch_size的大小影响模型的优化程度和速度。同时其直接影响... -
SpringBoot整合SpringBatch实用简例
2020-09-02 14:30:22SpringBatch主要是一个轻量级的大数据量的并行处理(批处理)的框架。 作用和Hadoop很相似,不过Hadoop是基于重量级的分布式环境(处理巨量数据),而SpringBatch是基于轻量的应用框架(处理中小数据)。 这里使用Spring... -
深入浅出TensorFlow2函数——tf.data.Dataset.padded_batch
2021-12-12 21:59:40padded_batch(batch_size, padded_shapes=None, padding_values=None, drop_remainder=False,name=None) 该函数可以将数据集的连续元素合并到padded batch中。即将输入数据集的多个连续元素合并到单个元素中。 tf.... -
【tensorrt】——trtexec动态batch支持与batch推理耗时评测
2021-09-06 14:08:31tensorrt, batch 1. trtexec编译 trtexec地址 参考官方的说明,进行项目编译 2. 模型转换 pytorch->onnx的时候,需要在动态尺寸上定义好,例如: dynamic_axes = { 'input': {0: 'batch_size'}, # } torch.... -
batchsize太小的缺点&随着batchsize逐渐增大的优缺点&如何平衡batchsize的大小
2022-03-21 18:53:21随着batchsize逐渐增大的优缺点:大的batchsize减少训练时间的同时所需内存容量增加;大的batchsize在提高稳定性的同时可能导致模型泛化能力下降。 平衡batchsize的大小:一般在Batchsize增加的同时,我们需要对... -
Python循环产生批量数据batch
2018-10-28 11:49:33Python循环产生批量数据batch 目录 Python循环产生批量数据batch 一、Python循环产生批量数据batch 二、TensorFlow循环产生批量数据batch (1)tf.train.slice_input_producer (2)tf.train.batch和tf.train.... -
训练过程--Batchsize(先不整理了,总之一般情况下batchsize能设多大就设多大)
2020-12-20 06:48:16训练过程--Batchsize(先不整理了,总之一般情况下batchsize能设多大就设多大)发布时间:2018-12-06 15:15,浏览次数:3888, 标签:Batchsize尽可能地设大batchsize "Large BatchLarge Batch在 keypoints上也是有用的... -
Spring.Batch批处理框架
2016-10-23 09:56:11Spring.Batch批处理框架 -
Numpy实现batch_iterator
2021-10-08 09:26:03def batch_iterator(X, y=None, batch_size=64): """ Simple batch generator """ n_samples = X.shape[0] for i in np.arange(0, n_samples, batch_size): begin, end = i, min(i+batch_size, n_samples) if y... -
spring batch批处理 教程
2014-04-03 23:30:382,什么是 Spring Batch 3 二,Spring Batch结构 4 1,Spring Batch体系结构 4 2,Spring Batch主要对象 5 三,Spring Batch流程介绍 5 四,Spring Batch之Step执行过程介绍 6 五,Spring Batch应用 7 1,简单应用 7... -
Spring Batch示例教程
2019-03-14 12:08:57Spring Batch示例教程 欢迎使用Spring Batch示例。Spring Batch是一个用于执行批处理作业的弹簧框架模块。我们可以使用spring批处理来处理一系列作业。 目录[隐藏] 1Spring Batch示例 1.1Spring Batch示例 ... -
Batch Size理解
2021-03-16 15:00:452.为什么要提出Batch Size? 3.既然 Full Batch Learning 并不适用大数据集,那么走向另一个极端怎么样? 3.Batch Size设置合适时的优点: 4.在合理范围内,增大 Batch_Size 有何好处? 5.盲目增大 Batch_Size ... -
【BatchSize简介】深度学习中Batch size对训练效果的影响
2020-06-05 11:16:00一般来说,在合理的范围之内,越大的 batch size 使下降方向越准确,震荡越小;batch size 如果过大,则可能会出现局部最优的情况。小的 bath size 引入的随机性更大,难以达到收敛,极少数情况下可能会效果变好。 ... -
Batch size对训练效果的影响
2021-10-22 10:36:30一般来说,在合理的范围之内,越大的 batch size 使下降方向越准确,震荡越小;batch size 如果过大,则可能会出现局部最优的情况。小的 bath size 引入的随机性更大,难以达到收敛,极少数情况下可能会效果变好。 ... -
Batch Normalization详解以及pytorch实验
2020-02-21 23:56:33Batch Normalization是google团队在2015年论文《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》提出的。通过该方法能够加速网络的收敛并提升准确率。在网上虽然... -
训练过程--Batchsize(总之一般情况下batchsize能设多大就设多大)
2021-01-21 12:04:51尽可能地设大batchsize 在合理范围内,增大batch size的好处 1)内存利用率提高了,大矩阵乘法的并行化效率提高。 2)跑完一次 epoch(全数据集)所需的迭代次数减少,对于相同数据量的处理速度进一步加快。 3)在... -
Numpy实现BatchNormalization
2021-09-16 09:28:35class BatchNormalization(Layer): """Batch normalization. """ def __init__(self, momentum=0.99): self.momentum = momentum self.trainable = True self.eps = 0.01 self.running_mean = None self.... -
32. Spring Boot 2 之Spring Batch集成
2022-01-16 16:52:28Spring Batch 简单来说是Spring 提供的一个用于处理海量数据任务流的批处理框架。 -
批处理框架spring batch基础知识介绍
2019-01-10 12:29:27spring batch简介 Spring Batch架构介绍 Spring Batch核心概念介绍 什么是Job 什么是JobInstance 什么是JobParameters 什么是JobExecution 什么是Step 什么是StepExecution 什么是ExecutionContext 什么是... -
tensorflow --batch内负采样
2022-01-25 16:15:58""" 自定义batch内负采样并做cosine相似度的层 """ """ 负采样原理: query_input.shape = [batch_size, dim] doc_input.shape = [batch_size, dim] 默认 query点击该doc。每个点击的item, 随机采集NEG个item... -
深度学习中学习率和batchsize对模型准确率的影响
2020-11-07 23:40:27本内容来自其他的人解析,参考链接在...学习率直接影响模型的收敛状态,batchsize则影响模型的泛化性能,两者又是分子分母的直接关系,相互也可影响,因此这一次来详述它们对模型性能的影响。 2. 学习率如何影响模型性. -
tensorflow:batch and shuffle_batch
2020-09-29 10:06:07f.train.batch与tf.train.shuffle_batch的作用都是从队列中读取数据. tf.train.batch tf.train.batch() 按顺序读取队列中的数据 队列中的数据始终是一个有序的队列.队头一直按顺序补充,队尾一直按顺序出队. ... -
(3条消息) batch size设置技巧 谈谈batchsize参数
2020-12-29 11:06:07深度学习中经常看到epoch、 iteration和batchsize,下面按自己的理解说说这三个的区别:(1)batchsize:批大小。在深度学习中,一般采用SGD训练,即每次训练在训练集中取batchsize个样本训练;(2)iteration:1个... -
动态batch和静态batch的原理和代码详解
2022-01-22 19:47:11在wenet中支持两种batch的方式, 第一种是常规的batch方案,但该方案当语音长短差异过大时,显存利用率低,同时带来显存oom的风险; 第二种是动态batch,不指定batch_size的大小,只限制了batch中的最大总帧数,这样...