VGG16

2 downloads 0 likes on ModelScope updated

Model card

方案名

1. 摘要

  1. 身份编号:fwb0042

  2. 类型与序号:VGG16 方案1

  3. 进展:

    item status detail
    方案选择与硬件资源划分 1
    模型导出 1
    ~导出模型精度一致,提供python验证脚本 1
    cpu处理部分c++工程移植 1
    ~c++工程精度一致,提供验证脚本 1
    ~c++工程性能优化 0
    icraft编译通过 1
    ~存在量化精度调优工作 0
    ~完成基本pyrtcrt搭建与结果验证 0
    ~完成pyrtcrt精度测试与对齐 0
    完成上板耗时测试 0
    ~使用运行时提供的api进行基本性能优化 0
    ~存在整体方案各环节优化或优化方案的设计 0
    提出bug数 0

2. 方案简介

2.1 算法流程介绍

模型或算法背景:

  • VGGNet (Visual Geometry Group Network) 是一系列深度卷积神经网络,由牛津大学的视觉几何组提出。VGG16是其中最著名和最广泛使用的版本。
  • 源仓库链接:VGGNet没有唯一的官方开源仓库,但其实现在各大深度学习框架(Caffe, TensorFlow, PyTorch等)中均已成为标准。
  • 开发团队:牛津大学视觉几何组 (Karen Simonyan & Andrew Zisserman)
  • 发布时间:2014年 (发表于ICLR 2015 Workshop)
  • 性能水平:VGGNet在2014年的ImageNet大规模视觉识别挑战赛(ILSVRC)中取得了定位任务第一名和分类任务第二名的优异成绩。其核心贡献在于证明了通过简单、一致地堆叠更小的卷积核(3x3)来增加网络深度,是提升模型性能的有效途径。这一“深度为王”的设计哲学,深刻影响了后续所有深度学习网络的设计,如ResNet、Inception等。

VGG系列模型在ImageNet验证集上的性能:

Model Depth Parameters (M) Top-1 Accuracy Top-5 Accuracy
VGG11 11 133 69.02% 88.63%
VGG16 16 138 71.59% 90.38%
VGG19 19 144 72.38% 90.87%
GoogLeNet 22 6.8 68.7% (Single-crop) 89.9% (Single-crop)

注:VGG的精度是在多尺度、多裁剪测试下取得的,这里为了对比,也列出了单裁剪下的精度。VGG的参数量主要集中在全连接层。

算法流程梳理

VGG16的结构极其规整、优雅和统一,完全由重复的、简单的构建块组成。其名称中的“16”代表网络中包含16个带权重的层(13个卷积层和3个全连接层)。

数据输入 ——> Conv Block 1 ——> Pool ——> Conv Block 2 ——> Pool ——> Conv Block 3 ——> Pool ——> Conv Block 4 ——> Pool ——> Conv Block 5 ——> Pool ——> FC Layers ——> Softmax

VGG16模型结构

VGG16的架构可以清晰地分为两个部分:

1. 卷积基 (Convolutional Base):

  • 统一的卷积核:整个网络只使用3x3大小的卷积核。这是VGG最核心的设计思想。作者们论证了两个堆叠的3x3卷积层拥有与一个5x5卷积层相同的感受野,而三个堆叠的3x3卷积层则等效于一个7x7卷积层的感受野。使用更小的卷积核堆叠,有两大好处:
    1. 引入更多非线性:更多的层数意味着更多的ReLU激活函数,这能增强网络的表达能力。
    2. 减少参数量:例如,三个3x3卷积层的参数量(3 * (33CC) = 27C^2)远小于一个7x7卷积层的参数量(77CC = 49C^2),其中C是通道数。
  • 规整的模块化设计:卷积基由5个卷积块(Conv Block)组成。每个块包含2到3个连续的3x3卷积层,其后紧跟一个2x2的最大池化层(Max Pooling)用于下采样。
  • 通道数变化:随着网络的加深,特征图的尺寸(H, W)通过池化层减半,而通道数(C)则逐块翻倍(64 -> 128 -> 256 -> 512 -> 512),这是一种非常经典的设计模式。

2. 分类器 (Classifier):

  • 全连接层 (Fully Connected Layers):在卷积基之后,特征图被展平(Flatten)为一个长向量,然后送入三个全连接层。前两个全连接层各有4096个神经元,最后一个全连接层的神经元数量为1000,对应ImageNet的1000个类别。
  • 巨大的参数量:VGG16的绝大部分参数(约1.2亿,占总参数量1.38亿的90%)都集中在这三个庞大的全连接层中,这也是其后续被优化的主要方向。

基本组件: 3x3卷积层:网络中唯一的卷积操作单元,证明了“小而深”的有效性。 ReLU激活函数:在每个卷积层后使用,引入非线性。 2x2最大池化层:用于下采样,缩小特征图尺寸。 全连接层:用于最终的分类决策。

训练技巧

数据集

  • 模型在 ImageNet (ILSVRC 2012) 数据集上进行训练,该数据集是评估大规模图像分类模型性能的基准。

训练设置

  • 优化器与学习率:采用带动量的随机梯度下降(SGD)进行优化。学习率初始值较小,并在验证集准确率不再提升时手动进行衰减。
  • 权重初始化:采用了精心设计的随机初始化方法(后来被称为“Xavier/Glorot初始化”),这对于成功训练深层网络至关重要。
  • 分阶段训练:作者们首先训练了一个较浅的网络(如VGG11),然后用其权重来初始化更深网络的对应层,再继续训练。这种方法有助于深层网络的收敛。

前后处理

前处理:

  1. 图像缩放:
    • 将输入图像的短边等比例缩放到一个固定尺寸S(称为训练尺度)。
  2. 随机裁剪:
    • 在训练时,从缩放后的图像中随机裁剪出224x224大小的区域作为模型输入。这是一种有效的数据增强。
  3. 随机水平翻转:
    • 以50%的概率对裁剪出的图像进行水平翻转。
  4. 均值减法:
    • 从每个像素的RGB值中减去在整个训练集上计算出的RGB均值。

后处理 (测试时):

  1. 多尺度/多裁剪测试 (Multi-scale/Multi-crop Testing):
    • 为了获得更高的精度,VGG在测试时采用了非常耗时的评估策略。它会将图像缩放到多个不同的尺度S,并在每个尺度上,从图像的四个角和中心,以及它们的水平翻转版本中,裁剪出多个224x224的图像块。
  2. 结果平均:
    • 将所有这些裁剪块送入网络得到各自的预测概率,然后将这些概率向量进行平均,得到最终的分类结果。

2.2 硬件资源分配

plin模式:摄像头输入数据直接传给pl部分

前处理:fpga,做在数据流上

网络主体:npu

后处理等:cpu

可视化:cpu

4. 模型导出说明

直接运行1_save.py导出整个模型即可

5. cpu处理部分c++工程移植说明

CPU部分主要实现了图片的读取,前处理尺寸变换和后处理的Softmax激活和获取预测结果功能

// 统计图片数量
    int index = 0;
    auto namevector = toVector(imgList);
    int totalnum = namevector.size();
    for (auto name : namevector) {
        progress(index, totalnum);
        index++;
        //-------------PRE PROCESS-----------------------//
        std::string img_path = imgRoot + '/' + name;
        PicPre img(img_path, cv::IMREAD_COLOR);
        img.Resize(resize_hw, PicPre::SHORT_SIDE).rCenterCrop(crop_hw);
        Tensor img_tensor = CvMat2Tensor(img.dst_img, network);
        dmaInit(run_sim, netinfo.ImageMake_on, img_tensor, device);
        auto output_tensors = session.forward({ img_tensor});
        if (!run_sim) device.reset(1);
        // 计时
        #ifdef __linux__
        device.reset(1);
        calctime_detail(session);
        #endif

        auto host_tensor_class = output_tensors[0].to(HostDevice::MemRegion());
        auto outputs_class = (float*)host_tensor_class.data().cptr();
        auto softmax_class = softmax(outputs_class, 1, 0, N_CLASS);
        // auto softmax_class = softmax(outputs_class,  0, output_tensors[0].dtype()->shape);
        auto topk_res = topK(softmax_class, 5);//save top-5 res 
        for (int i = 0; i < 5; i++) {
            auto c = topk_res[i].first;
            auto prob = topk_res[i].second;
            std::ostringstream text;
            text << LABELS[c] << " : " << std::fixed << std::setprecision(6) << prob;
            cv::putText(img.ori_img, text.str(), cv::Point2f(10, 20 + i * 15), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(128, 0, 0), 2);
        }
        #ifdef _WIN32
        if (show) {
            cv::imshow("results", img.ori_img);
            cv::waitKey(0);
        }
        if (save) {
            //save top-5 label in txt
            auto res_path = resRoot + "//" + name;
            std::regex reg(R"(\.(\w*)$)");
            res_path = std::regex_replace(res_path, reg, ".txt");
            std::ofstream outputFile(res_path);
            if (!outputFile.is_open()) {
                std::cout << "Create txt file fail." << std::endl;
            }
            for (auto&& res : topk_res) {
                outputFile << res.first << std::endl;
            }
            outputFile.close();
        }
        #elif __linux__
        if (save) {
            //saveRes
            std::regex rgx("\\.(?!.*\\.)"); // 匹配最后一个点号(.)之前的位置,且该点号后面没有其他点号
            std::string RES_NAME = std::regex_replace(name, rgx, "_result.");
            cv::imwrite(resRoot + RES_NAME, img.ori_img);
        }
        #endif

    }
    //关闭设备
    if (!run_sim) Device::Close(device);
    return 0;

6. ICRAFT编译


编译通过

  • 16bit下推理测试结果:

    框架动态图推理 导出静态模型推理 解析组件仿真 量化组件仿真 指令组件仿真
    alt text alt text alt text alt text alt text
  • 8bit,16bit,混合精度的精度测试结果:

  • 8bit测试结果:

      top1: 65.74%
      top5: 90.02%
    
  • 16bit测试结果:

      top1: 66.32000000000001%
      top5: 90.08%
    

7. 上板测试与优化(尚未进行上版测试)

  1. 优化前各环节耗时统计

  2. 优化后耗时统计(表格)

  3. 优化项与效果

    分条描述做了哪些性能优化,提升了多少

  4. 运行时工程的整体介绍(最好带流程图)