• 深度学习模型部署概述


    一般地,当我们在python框架(eg:pytorch,tensorflow等)中训练好模型,需要部署到C/C++环境,有以下方案:

    • CPU方案:Libtorch、OpenCV-DNN、OpenVINO、ONNX(有个runtime可以调)
    • GPU方案:TensorRT、OpenCV-DNN(需要重新编译,带上CUDA)

    注:OpenCV、OpenVINO都是intel的开源框架库,OpenCV的DNN模块其实调用的也就是OpenVINO,另外OpenvVINO在硬件加速方面使用了intel自家CPU的集成显卡。

    模型部署的时候,我们仅需要实现数据处理、前向传播就行,不需要去管反向传播。网络架构是一定要读懂的,举个例子:

    假设现有大小为32 x 32的图片样本,输入样本的channels为1,该图片可能属于10个类中的某一类。CNN框架定义如下:

     1 class CNN(nn.Module):
     2     def __init__(self):
     3         nn.Model.__init__(self)
     4  
     5         self.conv1 = nn.Conv2d(1, 6, 5)  # 输入通道数为1,输出通道数为6
     6         self.conv2 = nn.Conv2d(6, 16, 5)  # 输入通道数为6,输出通道数为16
     7         self.fc1 = nn.Linear(5 * 5 * 16, 120)
     8         self.fc2 = nn.Linear(120, 84)
     9         self.fc3 = nn.Linear(84, 10)
    10 
    11     def forward(self,x):
    12         # 输入x -> conv1 -> relu -> 2x2窗口的最大池化
    13         x = self.conv1(x)
    14         x = F.relu(x)
    15         x = F.max_pool2d(x, 2)
    16         # 输入x -> conv2 -> relu -> 2x2窗口的最大池化
    17         x = self.conv2(x)
    18         x = F.relu(x)
    19         x = F.max_pool2d(x, 2)
    20         # view函数将张量x变形成一维向量形式,总特征数不变,为全连接层做准备
    21         x = x.view(x.size()[0], -1)
    22         x = F.relu(self.fc1(x))
    23         x = F.relu(self.fc2(x))
    24         x = self.fc3(x)
    25         return x

    要用libtorch实现上述python代码,首先得弄个清楚网络中每一层的数据维度变换,如下图,我都注释了:

     1 # 详细注释    
     2 # reference:https://www.jianshu.com/p/45a26d278473    
     3 #************************************************************************************************
     4 class CNN(nn.Module):
     5     def __init__(self):
     6         nn.Model.__init__(self)
     7  
     8         self.conv1 = nn.Conv2d(1, 6, 5)  # 输入通道数为1,输出通道数为6
     9         self.conv2 = nn.Conv2d(6, 16, 5)  # 输入通道数为6,输出通道数为16
    10         self.fc1 = nn.Linear(5 * 5 * 16, 120)
    11         self.fc2 = nn.Linear(120, 84)
    12         self.fc3 = nn.Linear(84, 10)
    13 
    14     #网络整体结构:[conv + relu + pooling] * 2 + FC * 3
    15     #原始输入样本的大小:32 x 32 x 1
    16     def forward(self,x):
    17         # 第一次卷积:使用6个大小为5 x 5的卷积核,故卷积核的规模为(5 x 5) x 6;
    18         #卷积操作的stride参数默认值为1 x 1,32 - 5 + 1 = 28,并且使用ReLU对
    19         #第一次卷积后的结果进行非线性处理,输出大小为28 x 28 x 6;
    20         x = self.conv1(x)
    21         
    22         # 第一次卷积后池化:kernel_size为2 x 2,输出大小变为14 x 14 x 6;
    23         x = F.relu(x)
    24         x = F.max_pool2d(x, 2)
    25         
    26         # 第二次卷积:使用16个卷积核,故卷积核的规模为(5 x 5 x 6) x 16;
    27         # 使用ReLU对第二次卷积后的结果进行非线性处理,14 - 5 + 1 = 10,
    28         # 故输出大小为10 x 10 x 16;
    29         x = self.conv2(x)
    30         
    31         # 第二次卷积后池化:kernel_size同样为2 x 2,输出大小变为5 x 5 x 16;
    32         x = F.relu(x)
    33         x = F.max_pool2d(x, 2)
    34         
    35         # view函数将张量x变形成一维向量形式,总特征数不变,为全连接层做准备
    36         x = x.view(x.size()[0], -1)
    37         
    38         #第一次全连接:将上一步得到的结果铺平成一维向量形式,5 x 5 x 16 = 400,
    39         #即输入大小为400 x 1,W大小为120 x 400,输出大小为120 x 1;
    40         x = F.relu(self.fc1(x))
    41         
    42         # 第二次全连接,W大小为84 x 120,输入大小为120 x 1,输出大小为84 x 1;
    43         x = F.relu(self.fc2(x))
    44         
    45         # 第三次全连接:W大小为10 x 84,输入大小为84 x 1,输出大小为10 x 1,即分别预测为10
    46         x = self.fc3(x)
    47         return x

    网络结构图如下,

     对于其他网络,在训练完毕之后,一般的,也可以使用Netron可视化一下。

    reference:

    https://www.jianshu.com/p/45a26d278473    
    CV&DL
  • 相关阅读:
    GzipOutputStream及GzipInputStream的用法
    java的ZipOutputStream压缩文件的两个问题(乱码和每次zip后文件md5变化)
    HttpClient对URL编码的处理方式解惑!
    使用tmpfs缓存文件提高性能
    eclipse attach source code support folder zip & jar format
    HTTP头部详解及使用Java套接字处理HTTP请求
    curl使用总结
    cURL: win64sslsspi from Mirrors 64bit win7 version
    httpclient解析gzip网页
    使用Gzip加速网页的传输
  • 原文地址:https://www.cnblogs.com/winslam/p/14547367.html
Copyright © 2020-2023  润新知