微网站内页,厦门网络推广,唐山网站搭建,如何做一个微笑公众号推文文章目录 1. grid_sample算子功能解析1.1 理论介绍1.2 代码分析1.2.1 x,y取值范围[-1,1]1.2.2 x,y取值范围超出[-1,1] 2. 使用grid_sample算子构建一个网络3. 走PTQ进行模型转换与编译 实操以J5 OE1.1.60对应的docker为例 1. grid_sample算子功能解析 该段主要参考#xff1a;… 文章目录 1. grid_sample算子功能解析1.1 理论介绍1.2 代码分析1.2.1 x,y取值范围[-1,1]1.2.2 x,y取值范围超出[-1,1] 2. 使用grid_sample算子构建一个网络3. 走PTQ进行模型转换与编译 实操以J5 OE1.1.60对应的docker为例 1. grid_sample算子功能解析 该段主要参考https://blog.csdn.net/jameschen9051/article/details/124714759不想看理论可直接跳至第2节 1.1 理论介绍
在图像处理领域grid_sample 是一个常用的操作通常用于对图像进行仿射变换或透视变换。它可以在给定输入图像和一个变换矩阵的情况下对输入图像进行采样生成一个新的输出图像。 pytorch中调用接口
torch.nn.functional.grid_sample(input,grid,modebilinear,padding_modezeros,align_cornersNone)input输入特征图可以是四维或者五维张量本文主要以四维为例进行介绍表示为 (N,C,Hin,Win) 。grid采样网格包含输出特征图的shape大小(Hout、Wout)每个 网格值 通过变换对应到输入特征图的采样点位当对应四维input时其张量形式为(N,Hout,Wout,2)其中最后一维大小必须为2如果输入input为五维张量那么最后一维大小必须为3。 为什么最后一维必须为2或者3因为grid的最后一个维度实际上代表一个坐标(x,y)或者(x,y,z)对应到输入特征图的二维或三维特征图的坐标维度x,y取值范围一般为[-1,1]该范围映射到输入特征图的全图一通操作变换后对应于输出图像上的一个像素点。 mode采样模式可以是 ‘bilinear’双线性插值、 ‘nearest’最近邻插值、‘bicubic’ 双三次插值。。padding_mode填充模式用于处理采样时超出输入图像边界的情况可以是 ‘zeros’ 、 ‘border’、 ‘reflection’。align_corners一个布尔值用于指定特征图坐标与特征值对应方式设定为TRUE时特征值位于像素中心。 总的说来grid_sample 算子会根据给定的网格grid在输入图像上进行采样然后根据选择的插值方法在采样点周围的像素上进行插值最终生成输出图像。
画一个在BEV方案中grid_sample原理图来帮助理解grid_sample怎么回事
1.2 代码分析
对照代码进行下一步解读。 假设输入shape为(N,C,H_in,W_in)grid的shape设定为(N,H_out,W_out,2)使用双线性差值填充模式为zerosalign_corners需要设置为True。
首先根据input和grid设定输出特征图tensor的shape为(N,C,H_out,W_out)输出特征图上每一个cell上的值与grid最后一维(x,y)息息相关那么如何计算输出tensor上每一个点的值 首先通过(x,y)找到输入特征图上的采样位置由于xy取值范围为[-1,1]为了便于计算先将xy取值范围调整为[0,1]方法是(x1)/2(y1)/2。因此将xy映射为输入特征图的具体坐标位置(w-1)(x1)/2、(h-1)(y1)/2。 将xy映射到输入特征图实际坐标后取该坐标附近四个角点特征值通过四个特征值坐标与采样点坐标相对关系进行双线性插值得到采样点的值。 注意xy映射后的坐标可能是输入特征图上任意位置。 基于上面的思路可以进行一个简单的自定义实现。根据指定shape生成input和grid之后取grid中的第一个位置中的xy根据xy从input中通过双线性插值计算出output第一个位置的值。类比使用pytorch中的grid_sample算子生成output。
其它的看代码注释即可。
1.2.1 x,y取值范围[-1,1]
import torch
import numpy as npdef grid_sample(input, grid):N, C, H_in, W_in input.shapeN, H_out, W_out, _ grid.shapeoutput np.random.random((N,C,H_out,W_out))for i in range(N):for j in range(C):for k in range(H_out):for l in range(W_out):param [0.0, 0.0]# 通过(w-1)*(x1)/2、(h-1)*(y1)/2将xy映射为输入特征图的具体坐标位置。param[0] (W_in - 1) * (grid[i][k][l][0] 1) / 2param[1] (H_in - 1) * (grid[i][k][l][1] 1) / 2x0 int(param[0]) # int取整规则将小数部分截断去掉。x1 x0 1y0 int(param[1])y1 y0 1param[0] - x0 # 此时param里装的是小数部分param[1] - y0# 双线性插值left_top input[i][j][y0][x0] * (1 - param[0]) * (1 - param[1])left_bottom input[i][j][y1][x0] * (1 - param[0]) * param[1]right_top input[i][j][y0][x1] * param[0] * (1 - param[1])right_bottom input[i][j][y1][x1] * param[0] * param[1]result left_bottom left_top right_bottom right_topoutput[i][j][k][l] resultreturn outputif __name____main__:N, C, H_in, W_in, H_out, W_out 1, 1, 4, 4, 2, 2input np.random.random((N,C,H_in,W_in))# np.random.random()范围是[0,1),想要[a,b)的数据需要(b-a)*np.random.random() agrid -1 2*np.random.random((N,H_out,W_out,2)) # 最后一维2生成了坐标out grid_sample(input, grid)print(f自定义实现输出结果\n{out})input torch.from_numpy(input)grid torch.from_numpy(grid)# 注意这儿align_cornersTrueoutput torch.nn.functional.grid_sample(input,grid,modebilinear, padding_modezeros,align_cornersTrue)print(fgrid_sample输出结果\n{output})输出 从输出结果上看与pytorch基本一致。
注意这里没有对超出[-1,1]范围的xy值做处理只能处理四维input五维input的实现思路与这里基本一致再加一层循环内插算法改为3维。。
1.2.2 x,y取值范围超出[-1,1]
考虑到(x,y)取值范围可能越界pytorch中的padding_mode设置就是对(x,y)落在输入特征图外边缘情况进行处理一般设置’zero’也就是对靠近输入特征图范围以外的采样点进行0填充如果不进行处理显然会造成索引越界。要解决(x,y)越界问题可以进行如下修改
import torch
import numpy as npdef grid_sample(input, grid):N, C, H_in, W_in input.shapeN, H_out, W_out, _ grid.shapeoutput np.random.random((N,C,H_out,W_out))for i in range(N):for j in range(C):for k in range(H_out):for l in range(W_out):param [0.0, 0.0]# 通过(w-1)*(x1)/2、(h-1)*(y1)/2将xy映射为输入特征图的具体坐标位置。param[0] (W_in - 1) * (grid[i][k][l][0] 1) / 2param[1] (H_in - 1) * (grid[i][k][l][1] 1) / 2x1 int(param[0] 1) # int取整规则将小数部分截断去掉。x0 x1 - 1 y1 int(param[1] 1)y0 y1 - 1param[0] abs(param[0] - x0) # 此时param里装的是离x0,y0的距离param[1] abs(param[1] - y0)# 填充left_top_value, left_bottom_value, right_top_value, right_bottom_value 0, 0, 0, 0if 0 x0 W_in and 0 y0 H_in:left_top_value input[i][j][y0][x0]if 0 x1 W_in and 0 y0 H_in:right_top_value input[i][j][y0][x1]if 0 x0 W_in and 0 y1 H_in:left_bottom_value input[i][j][y1][x0]if 0 x1 W_in and 0 y1 H_in:right_bottom_value input[i][j][y1][x1]# 双线性插值left_top left_top_value * (1 - param[0]) * (1 - param[1])left_bottom left_bottom_value * (1 - param[0]) * param[1]right_top right_top_value * param[0] * (1 - param[1])right_bottom right_bottom_value * param[0] * param[1]result left_bottom left_top right_bottom right_topoutput[i][j][k][l] resultreturn outputif __name____main__:N, C, H_in, W_in, H_out, W_out 1, 1, 4, 4, 2, 2input np.random.random((N,C,H_in,W_in))# np.random.random()范围是[0,1),想要[a,b)的数据需要(b-a)*np.random.random() agrid -1 2*np.random.random((N,H_out,W_out,2)) # 最后一维2生成了坐标grid[0][0][0] [-1.2, 1.3] # 超出[-1,1]的范围out grid_sample(input, grid)print(f自定义实现输出结果\n{out})input torch.from_numpy(input)grid torch.from_numpy(grid)# 注意这儿align_cornersTrueoutput torch.nn.functional.grid_sample(input,grid,modebilinear, padding_modezeros,align_cornersTrue)print(fgrid_sample输出结果\n{output})输出
2. 使用grid_sample算子构建一个网络
先看一下地平线提供的算子支持与约束列表
据此构建一个简单的网络test.py代码如下
import torch
import torch.nn as nn
import torch.nn.functional as Ffrom horizon_nn.torch import export_onnxclass GridSampleModel(nn.Module):def __init__(self):super(GridSampleModel, self).__init__()self.unitconv nn.Conv2d(24, 24, (1, 1), groups3)nn.init.constant_(self.unitconv.weight, 1)nn.init.constant_(self.unitconv.bias, 0)def forward(self, x1, x2):x1 self.unitconv(x1)x F.grid_sample(x1,gridx2,modebilinear,padding_modezeros,align_cornersTrue)x self.unitconv(x)return xif __name__ __main__:model GridSampleModel()model.eval()input_names [x1, x2]output_names [output]x1 torch.randn((1, 24, 600, 800))x2 torch.randn((1, 48, 64, 2))export_onnx(model, (x1, x2), gridsample.onnx, verboseTrue, opset_version11,input_namesinput_names, output_namesoutput_names)print(convert to gridsampe onnx finish!!!)运行test.py生成onnx模型可视化结构如下图
3. 走PTQ进行模型转换与编译
对应config.yaml文件
# 模型转化相关的参数
model_parameters:onnx_model: ./gridsample.onnxmarch: bayesworking_dir: model_outputoutput_model_file_prefix: gridsample# 模型输入相关参数, 若输入多个节点, 则应使用;进行分隔, 使用默认缺省设置则写None
input_parameters:input_name: x1;x2input_type_rt: featuremap;featuremapinput_layout_rt: NCHW;NCHWinput_type_train: featuremap;featuremapinput_layout_train: NCHW;NCHWinput_shape: 1x24x600x800;1x48x64x2norm_type: no_preprocess;no_preprocess# 模型量化相关参数
calibration_parameters:calibration_type: skip# 编译器相关参数
compiler_parameters:compile_mode: latencyoptimize_level: O3使用的是OE1.1.60对应的docker
hb_mapper makertbin --config config.yaml --model-type onnx全一段且都在BPU上