YOLOV3剪枝源碼閱讀---模型部署加速

YOLOV3剪枝

論文:Network Slimming-Learning Efficient Convolutional Networks through Network Slimming

剪枝項(xiàng)目參考https://github.com/tanluren/yolov3-channel-and-layer-pruning

主要思路

  • 1、利用batch normalization中的縮放因子γ 作為重要性因子,即γ越小轮洋,所對應(yīng)的channel不太重要氛谜,就可以裁剪(pruning)。

  • 2、約束γ的大小,在目標(biāo)方程中增加一個(gè)關(guān)于γ的L1正則項(xiàng),使其稀疏化俊戳,這樣可以做到在訓(xùn)練中自動(dòng)剪枝,這是以往模型壓縮所不具備的馆匿。

剪枝過程

img
這里寫圖片描述

分為三部分抑胎,第一步,訓(xùn)練渐北;第二步阿逃,剪枝;第三步,微調(diào)剪枝后的模型盆昙,循環(huán)執(zhí)行

YOLOV3剪枝源碼

1羽历、正常剪枝

這部分分析來自該倉庫https://github.com/coldlarry/YOLOv3-complete-pruning,但是更新的倉庫也可以完成正常剪枝淡喜,prune.py秕磷。

使用了正常剪枝模式,不對short cut層(需要考慮add操作的維度一致問題)及上采樣層(無BN)進(jìn)行裁剪炼团。

  • 1澎嚣、找到需要裁剪的BN層的對應(yīng)的索引。

  • 2瘟芝、每次反向傳播前易桃,將L1正則產(chǎn)生的梯度添加到BN層的梯度中。

  • 3锌俱、設(shè)置裁剪率進(jìn)行裁剪晤郑。

  • 將需要裁剪的層的BN層的γ參數(shù)的絕對值提取到一個(gè)列表并從小到大進(jìn)行排序,若裁剪率0.8贸宏,則列表中0.8分位數(shù)的值為裁剪閾值造寝。

  • 將小于裁剪閾值的通道的γ置為0,驗(yàn)證裁剪后的map(并沒有將β置為0)吭练。

  • 4诫龙、創(chuàng)建新的模型結(jié)構(gòu),β合并到下一個(gè)卷積層中BN中的running_mean計(jì)算鲫咽。

  • 5签赃、生成新的模型文件。

2分尸、優(yōu)化的正常剪枝

slim_prune.py锦聊,在正常剪枝模式的基礎(chǔ)上,完成對shortcut層的剪枝箩绍,同時(shí)避免裁剪掉整個(gè)層孔庭。

  • 1、找到需要裁剪的BN層的對應(yīng)的索引伶选。
# 解析模型文件
def parse_module_defs2(module_defs):
    CBL_idx = []
    Conv_idx = []
    shortcut_idx=dict()
    shortcut_all=set()
    ignore_idx = set()
    for i, module_def in enumerate(module_defs):
        if module_def['type'] == 'convolutional':
            # 如果是卷積層中的BN層則將該層索引添加到CBL_idx
            if module_def['batch_normalize'] == '1': 
                CBL_idx.append(i)
            else:
                Conv_idx.append(i)
            if module_defs[i+1]['type'] == 'maxpool':
                #spp前一個(gè)CBL不剪
                ignore_idx.add(i)

        elif module_def['type'] == 'upsample':
            #上采樣層前的卷積層不裁剪
            ignore_idx.add(i - 1)

        elif module_def['type'] == 'shortcut':
            # 根據(jù)cfg中的from層獲得shortcut的卷積層對應(yīng)的索引
            identity_idx = (i + int(module_def['from']))
            # 如果shortcut連接的是卷積層則直接添加索引
            if module_defs[identity_idx]['type'] == 'convolutional':

                #ignore_idx.add(identity_idx)
                shortcut_idx[i-1]=identity_idx
                shortcut_all.add(identity_idx)
            # 如果shortcut連接的是shortcut層,則添加前一層卷積層的索引
            elif module_defs[identity_idx]['type'] == 'shortcut':

                #ignore_idx.add(identity_idx - 1)
                shortcut_idx[i-1]=identity_idx-1
                shortcut_all.add(identity_idx-1)
            shortcut_all.add(i-1)


        # 得到需要剪枝的BN層的索引
    prune_idx = [idx for idx in CBL_idx if idx not in ignore_idx]

    return CBL_idx, Conv_idx, prune_idx,shortcut_idx,shortcut_all
  • 2尖昏、每次反向傳播前仰税,將L1正則產(chǎn)生的梯度添加到BN層的梯度中。

  • 3抽诉、設(shè)置裁剪率進(jìn)行裁剪陨簇。

    • 將需要裁剪的層的BN層的γ參數(shù)的絕對值提取到一個(gè)列表并從小到大進(jìn)行排序,若裁剪率0.8,則列表中0.8分位數(shù)的值為裁剪閾值河绽。

      # 提取需要裁剪的層的BN參數(shù)
      bn_weights = gather_bn_weights(model.module_list, prune_idx)
      # 排序
      sorted_bn, sorted_index = torch.sort(bn_weights)
      # 分位數(shù)索引
      thresh_index = int(len(bn_weights) * opt.global_percent)
      thresh = sorted_bn[thresh_index].cuda()
      
    • 將小于裁剪閾值的通道提取出來己单;如果整層的通道γ均低于閾值,為了避免整層被裁剪耙饰,保留該層中γ值最大的幾個(gè)(根據(jù)layer_keep參數(shù)進(jìn)行設(shè)置纹笼,最小為1)通道。

      def obtain_filters_mask(model, thresh, CBL_idx, prune_idx):
          pruned = 0
          total = 0
          num_filters = []
          filters_mask = []
          for idx in CBL_idx:
              bn_module = model.module_list[idx][1]
              # 如果該層需要裁剪苟跪,則先確定裁剪后的最小通道數(shù)min_channel_num廷痘,然后根據(jù)裁剪閾值進(jìn)行通道裁剪確定mask,如果整層的通道γ均低于閾值件已,為了避免整層被裁剪笋额,留該層中γ值最大的幾個(gè)(根據(jù)layer_keep參數(shù)進(jìn)行設(shè)置,最小為1)通道篷扩。
              if idx in prune_idx:
                  weight_copy = bn_module.weight.data.abs().clone()
                  
                  channels = weight_copy.shape[0]
                  min_channel_num = int(channels * opt.layer_keep) if int(channels * opt.layer_keep) > 0 else 1
                  mask = weight_copy.gt(thresh).float()
                  
                  if int(torch.sum(mask)) < min_channel_num: 
                      _, sorted_index_weights = torch.sort(weight_copy,descending=True)
                      mask[sorted_index_weights[:min_channel_num]]=1. 
                  remain = int(mask.sum())
                  pruned = pruned + mask.shape[0] - remain
      
                  print(f'layer index: {idx:>3d} \t total channel: {mask.shape[0]:>4d} \t '
                          f'remaining channel: {remain:>4d}')
              # 如果該層不需要裁剪兄猩,則全部保留
              else:
                  mask = torch.ones(bn_module.weight.data.shape)
                  remain = mask.shape[0]
      
              total += mask.shape[0]
              num_filters.append(remain)
              filters_mask.append(mask.clone())
      
    • 合并shortcut層的mask,采用取并集的策略鉴未。

      def merge_mask(model, CBLidx2mask, CBLidx2filters):
          # 最后一層開始遍歷
          for i in range(len(model.module_defs) - 1, -1, -1):
              mtype = model.module_defs[i]['type']
              if mtype == 'shortcut':
                  if model.module_defs[i]['is_access']:
                      continue
      
                  Merge_masks =  []
                  layer_i = i
                  # 循環(huán)的停止條件是到網(wǎng)絡(luò)的feature map 發(fā)生下采樣時(shí)
                  while mtype == 'shortcut':
                      # 標(biāo)志為true
                      model.module_defs[layer_i]['is_access'] = True
      
                      # 如果前一層為卷積層枢冤,添加該層上一層卷積層通道的mask
                      if model.module_defs[layer_i-1]['type'] == 'convolutional':
                          bn = int(model.module_defs[layer_i-1]['batch_normalize'])
                          if bn:
                              Merge_masks.append(CBLidx2mask[layer_i-1].unsqueeze(0))
                      # 找到和該層shortcut連接的層的索引
                      layer_i = int(model.module_defs[layer_i]['from'])+layer_i
                      mtype = model.module_defs[layer_i]['type']
      
                      # 如果和shortcut連接的層為卷積層,則添加該層通道的mask歼狼;否則進(jìn)入下一次while循環(huán)
                      if mtype == 'convolutional':
                          bn = int(model.module_defs[layer_i]['batch_normalize'])
                          if bn:
                              Merge_masks.append(CBLidx2mask[layer_i].unsqueeze(0))
      
                  # 綜合考慮所有feature map 大小相同(即通道數(shù)相同掏导,不發(fā)生下采樣)的shortcut層對應(yīng)的卷積層通道的mask,只要一個(gè)為true則全部不剪裁
                  if len(Merge_masks) > 1:
                      Merge_masks = torch.cat(Merge_masks, 0)
                      merge_mask = (torch.sum(Merge_masks, dim=0) > 0).float()
                  else:
                      merge_mask = Merge_masks[0].float()
      
                  layer_i = i
                  mtype = 'shortcut'
                  # 更新新的merge_mask
                  while mtype == 'shortcut':
      
                      if model.module_defs[layer_i-1]['type'] == 'convolutional':
                          bn = int(model.module_defs[layer_i-1]['batch_normalize'])
                          if bn:
                              CBLidx2mask[layer_i-1] = merge_mask
                              CBLidx2filters[layer_i-1] = int(torch.sum(merge_mask).item())
      
                      layer_i = int(model.module_defs[layer_i]['from'])+layer_i
                      mtype = model.module_defs[layer_i]['type']
      
                      if mtype == 'convolutional':
                          bn = int(model.module_defs[layer_i]['batch_normalize'])
                          if bn:
                              CBLidx2mask[layer_i] = merge_mask
                              CBLidx2filters[layer_i] = int(torch.sum(merge_mask).item())
      
      
  • 4羽峰、驗(yàn)證裁剪模型之后的MAP趟咆。

  • 5、實(shí)際裁剪模型參數(shù)梅屉,β合并到下一個(gè)卷積層中BN中的running_mean計(jì)算值纱。驗(yàn)證MAP,比較模型參數(shù)量及inference速度

  • 6坯汤、創(chuàng)建新的模型結(jié)構(gòu)虐唠,保存新的cfg及weights。

3惰聂、層剪枝

和優(yōu)化的正常剪枝類似疆偿。這個(gè)策略是在之前的通道剪枝策略基礎(chǔ)上衍生出來的,針對每一個(gè)shortcut層前一個(gè)CBL進(jìn)行評價(jià)搓幌,對各層的Gmma均值進(jìn)行排序杆故,取最小的進(jìn)行層剪枝。為保證yolov3結(jié)構(gòu)完整溉愁,這里每剪一個(gè)shortcut結(jié)構(gòu)处铛,會(huì)同時(shí)剪掉一個(gè)shortcut層和它前面的兩個(gè)卷積層。是的,這里只考慮剪主干中的shortcut模塊撤蟆。但是yolov3中有23處shortcut奕塑,剪掉8個(gè)shortcut就是剪掉了24個(gè)層,剪掉16個(gè)shortcut就是剪掉了48個(gè)層家肯,總共有69個(gè)層的剪層空間龄砰;實(shí)驗(yàn)中對簡單的數(shù)據(jù)集剪掉了較多shortcut而精度降低很少。

稀疏策略

scale參數(shù)默認(rèn)0.001息楔,根據(jù)數(shù)據(jù)集寝贡,mAP,BN分布調(diào)整,數(shù)據(jù)分布廣類別多的值依,或者稀疏時(shí)掉點(diǎn)厲害的適當(dāng)調(diào)小s;-sr用于開啟稀疏訓(xùn)練圃泡;--prune 0適用于prune.py,--prune 1 適用于其他剪枝策略愿险。稀疏訓(xùn)練就是精度和稀疏度的博弈過程颇蜡,如何尋找好的策略讓稀疏后的模型保持高精度同時(shí)實(shí)現(xiàn)高稀疏度是值得研究的問題,大的s一般稀疏較快但精度掉的快辆亏,小的s一般稀疏較慢但精度掉的慢风秤;配合大學(xué)習(xí)率會(huì)稀疏加快,后期小學(xué)習(xí)率有助于精度回升扮叨。
注意:訓(xùn)練保存的pt權(quán)重包含epoch信息缤弦,可通過python -c "from models import *; convert('cfg/yolov3.cfg', 'weights/last.pt')"轉(zhuǎn)換為darknet weights去除掉epoch信息,使用darknet weights從epoch 0開始稀疏訓(xùn)練彻磁。

1碍沐、恒定s

這是一開始的策略,也是默認(rèn)的策略衷蜓。在整個(gè)稀疏過程中累提,始終以恒定的s給模型添加額外的梯度,因?yàn)榱Χ缺容^均勻磁浇,往往壓縮度較高斋陪。但稀疏過程是個(gè)博弈過程,我們不僅想要較高的壓縮度置吓,也想要在學(xué)習(xí)率下降后恢復(fù)足夠的精度无虚,不同的s最后稀疏結(jié)果也不同,想要找到合適的s往往需要較高的時(shí)間成本衍锚。

bn_module.weight.grad.data.add_(s * torch.sign(bn_module.weight.data))

2友题、全局s衰減

關(guān)鍵代碼是下面這句,在epochs的0.5階段s衰減100倍构拳。前提是0.5之前權(quán)重已經(jīng)完成大幅壓縮咆爽,這時(shí)對s衰減有助于精度快速回升,但是相應(yīng)的bn會(huì)出現(xiàn)一定膨脹置森,降低壓縮度斗埂,有利有弊,可以說是犧牲較大的壓縮度換取較高的精度凫海,同時(shí)減少尋找s的時(shí)間成本呛凶。當(dāng)然這個(gè)0.5和100可以自己調(diào)整。注意也不能為了在前半部分加快壓縮bn而大大提高s行贪,過大的s會(huì)導(dǎo)致模型精度下降厲害漾稀,且s衰減后也無法恢復(fù)。如果想使用這個(gè)策略劝术,可以在prune_utils.py中的BNOptimizer把下面這句取消注釋沟于。

# s = s if epoch <= opt.epochs * 0.5 else s * 0.01

3氧敢、局部s衰減

關(guān)鍵代碼是下面兩句,在epochs的0.5階段開始對85%的通道保持原力度壓縮殷蛇,15%的通道進(jìn)行s衰減100倍。這個(gè)85%是個(gè)先驗(yàn)知識(shí)橄浓,是由策略一稀疏后嘗試剪通道幾乎不掉點(diǎn)的最大比例粒梦,幾乎不掉點(diǎn)指的是相對稀疏后精度;如果微調(diào)后還是不及baseline荸实,或者說達(dá)不到精度要求匀们,就可以使用策略三進(jìn)行局部s衰減,從中間開始重新稀疏准给,這可以在犧牲較小壓縮度情況下提高較大精度泄朴。如果想使用這個(gè)策略可以在train.py中把下面這兩句取消注釋,并根據(jù)自己策略一情況把0.85改為自己的比例圆存,還有0.5和100也是可調(diào)的叼旋。策略二和三不建議一起用,除非你想做組合策略沦辙。

#if opt.sr and opt.prune==1 and epoch > opt.epochs * 0.5:
    # idx2mask = get_mask2(model, prune_idx, 0.85)

知識(shí)蒸餾

參考論文:Learning Efficient Object Detection Models with Knowledge Distillation夫植。

核心思想:

  • 對于obj和分類損失:將學(xué)生模型和老師模型的obj和分類的輸出展開為一維向量,計(jì)算KL散度損失
  • 對于Box損失:將學(xué)生模型xywh的輸出x_offset,y_offset油讯,w/grid_cell_w详民,h/grid_cell_h(這里是否有數(shù)量級的問題,似乎用歸一化的歐式距離更好)分別和老師模型的輸出陌兑、target計(jì)算L2距離沈跨,如果學(xué)生模型的輸出,如果學(xué)生和老師更遠(yuǎn)兔综,學(xué)生會(huì)再向target學(xué)習(xí)饿凛,而不是向老師學(xué)習(xí)狞玛。這時(shí)候老師的輸出是hard label。
image.png
def distillation_loss2(model, targets, output_s, output_t):
    '''
    :param model:  學(xué)生模型
    :param targets: 標(biāo)簽
    :param output_s: 學(xué)生模型的輸出
    :param output_t: 老師模型的輸出
    :return: 附加Loss
    '''
    reg_m = 0.0
    T = 3.0
    Lambda_cls, Lambda_box = 0.0001, 0.001
        
    # KL 損失涧窒,衡量兩個(gè)分布的差異
    criterion_st = torch.nn.KLDivLoss(reduction='sum')
    ft = torch.cuda.FloatTensor if output_s[0].is_cuda else torch.Tensor
    lcls, lbox = ft([0]), ft([0])
        # 標(biāo)簽轉(zhuǎn)換
    tcls, tbox, indices, anchor_vec = build_targets(model, targets)
    reg_ratio, reg_num, reg_nb = 0, 0, 0
    for i, (ps, pt) in enumerate(zip(output_s, output_t)):  # layer index, layer predictions
        b, a, gj, gi = indices[i]  # image, anchor, gridy, gridx

        nb = len(b)
        if nb:  # number of targets
            pss = ps[b, a, gj, gi]  # prediction subset corresponding to targets
            pts = pt[b, a, gj, gi]

            psxy = torch.sigmoid(pss[:, 0:2])  # pxy = pxy * s - (s - 1) / 2,  s = 1.5  (scale_xy)
            psbox = torch.cat((psxy, torch.exp(pss[:, 2:4]) * anchor_vec[i]), 1).view(-1, 4)  # predicted box

            ptxy = torch.sigmoid(pts[:, 0:2])  # pxy = pxy * s - (s - 1) / 2,  s = 1.5  (scale_xy)
            ptbox = torch.cat((ptxy, torch.exp(pts[:, 2:4]) * anchor_vec[i]), 1).view(-1, 4)  # predicted box


            l2_dis_s = (psbox - tbox[i]).pow(2).sum(1)
            l2_dis_s_m = l2_dis_s + reg_m
            l2_dis_t = (ptbox - tbox[i]).pow(2).sum(1)
            l2_num = l2_dis_s_m > l2_dis_t
            lbox += l2_dis_s[l2_num].sum()
            reg_num += l2_num.sum().item()
            reg_nb += nb

        output_s_i = ps[..., 4:].view(-1, model.nc + 1)
        output_t_i = pt[..., 4:].view(-1, model.nc + 1)
        lcls += criterion_st(nn.functional.log_softmax(output_s_i/T, dim=1), nn.functional.softmax(output_t_i/T,dim=1))* (T*T) / ps.size(0)

    if reg_nb:
        reg_ratio = reg_num / reg_nb

    return lcls * Lambda_cls + lbox * Lambda_box, reg_ratio

自己項(xiàng)目實(shí)驗(yàn)的總結(jié):

一心肪、測試環(huán)境

  • 宿主機(jī):Ubuntu 16.04, Docker環(huán)境:Ubuntu 16.04.6 LTS
  • CPU:32 Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
  • GPU:GTX 1080 8G
  • CUDA_CUDNN:10.1.243纠吴,7.6.3.30
  • Python:3.6.9
  • onnx:1.4.1
  • tensorrt:6.0.1.5
  • pytorch:1.3.0

二硬鞍、測試模型(YOLOV3)

模型采用pytorch框架訓(xùn)練、剪枝戴已,轉(zhuǎn)換為darknet模型固该,再轉(zhuǎn)換成ONNX模型,最后轉(zhuǎn)換為tensorrt模型糖儡。將以下六個(gè)模型依次命名為model1伐坏、model2、...握联、model6著淆。

  1. Pytorch模型:model.pt
  2. Pytorch剪枝且微調(diào)模型:model_075.weights(轉(zhuǎn)換為darknet格式)
  3. Tensorrt 模型:model_416416.trt(由model1轉(zhuǎn)換)
  4. Tensorrt 模型:model_256416.trt(由model1轉(zhuǎn)換)
  5. Tensorrt 模型:model_075_256416.trt(由model2轉(zhuǎn)換)
  6. Tensorrt 模型:model_075_416416.trt(由model2轉(zhuǎn)換)

三、測試結(jié)果

通過采用不同的輸入形狀(矩形和正方形)拴疤、不同的輸入尺寸(320永部、416、608)呐矾、不同Batch Size(1苔埋、4、8蜒犯、16)下對同一張圖片采取循環(huán)推理1000次取平均時(shí)間组橄,比較模型推理速度的差異。

注1:矩形輸入指不改變寬高比的情況下罚随,最長邊resize到320玉工、416、608淘菩,短邊采用(128,128,128)填充至32的倍數(shù)遵班。如輸入尺寸為(720,1080)的720P圖像,320潮改、416狭郑、608分別對應(yīng)(192, 320)、(256, 416)汇在、(352, 608)翰萨。

注2:model3-6括號中的時(shí)間代表純前向推理時(shí)間,batch size 均為1糕殉。

Model rec(1/4/8/16) [ms] Square(1/4/8/16) [ms]
Model1(416) 14.4/32.8/59.7/108.9 17.9/51.9/97.6/166.6
Model1(608) 21.3/63.8/122.5/196.9 31.1/105.3/205.5/322.2
Model1(320) 14.1/22.2/38.2/64.5 14.8/32.9/60.7/106.7
Model2(416) 13.9/21.6/39.9/76.6 14.4/33.4/63.9/124.7
Model2(608) 13.9/40.2/76.8/151.3 19.2/67.4/131.1/259.5
Model2(320) 13.9/14.0/24.1/44.9 14.3/20.9/38.3/73.6
Model3和Model4(416) 10.8(9.4) 16.1(14.0)
Model5和Model6(416) 8.4(6.4) 12.1(9.7)

四亩鬼、測試結(jié)論

  1. batch size 為 1 不能有效的利用顯卡資源殖告。通過多batch size 比較時(shí)間,矩形比正方形加速40%雳锋。(輸入圖片是16:9丛肮,矩形相對于正方形計(jì)算量少了43%)恰好證明了結(jié)論2。

  2. 當(dāng)輸入面積(N * H * W)大于一定值時(shí)魄缚,速度瓶頸才會(huì)出現(xiàn)在FLOPs上。詳情請見焚廊,Roofline Model與深度學(xué)習(xí)模型的性能分析冶匹,模型的推理速度是由計(jì)算量為A且訪存量為B的模型在算力為C且?guī)挒镈的計(jì)算平臺(tái)所能達(dá)到的理論性能上限E是多少決定的。

  3. Tensorrt 可以降低模型的訪存量咆瘟,加速25%嚼隘,但是似乎對模型計(jì)算量的降低非常有限。

  4. 通道剪枝可以降低模型的計(jì)算量和訪存量袒餐,加速35%飞蛹,但是在batch size 為 1時(shí)加速不明顯,說明這次通道剪枝并沒有優(yōu)化模型的計(jì)算密度灸眼。和K_iK_o的裁剪比例及大小有關(guān)卧檐。

  5. 若顯卡的算力足夠,提高batch size 為 1時(shí)的推理速度焰宣,核心是優(yōu)化模型的訪存量霉囚;提高多batch size時(shí)的推理速度核心是優(yōu)化模型的計(jì)算量。

QA:

Q1:在做了矩形框輸入和剪枝后匕积,為什么batch size 為1時(shí)盈罐,320/416/608三種輸入分辨率的前向推理的速度基本相同?


image.png

猜測:在計(jì)算量未達(dá)到GPU的瓶頸時(shí)闪唆,僅提高輸入的分辨率而不改變模型盅粪,雖然計(jì)算密度基本不變(略微提高),但是實(shí)際帶寬利用率會(huì)變大悄蕾,所以FLOPS和FLOPs都會(huì)以相同的比例增長票顾,因此最后的前向推理時(shí)間相同。
pi = \frac {K_i \times K_o \times M^2 \times F^2}{K_i \times M_2 + K_o \times F^2 }
其中\pi 表示計(jì)算密度帆调,K_i 表示輸入通道數(shù)库物,K_o 表示輸出通道數(shù),M^2 表示卷積核的平面尺寸贷帮,F^2 表示輸出特征圖的平面尺寸戚揭。僅當(dāng)F^2 改變時(shí),計(jì)算密度基本不變撵枢,但是\beta表示實(shí)際帶寬利用率變大民晒,使得在相同的計(jì)算密度下FLOPs增大精居。

Q2:多batch size進(jìn)行推理,為什么加速明顯潜必?
猜測:在多batch size中靴姿,F(xiàn)LOPS成倍增長但是時(shí)間卻沒有成倍增長,所以FLOPs提高磁滚》鹣牛可能和Q1一樣能夠提高實(shí)際帶寬利用率,并且由于模型參數(shù)均一致可以放入緩存中垂攘,同時(shí)降低訪存量维雇,提高了計(jì)算密度。

pi = \frac {B \times K_i \times K_o \times M^2 \times F^2 }{K_i \times M_2 + B \times K_o \times F^2 }

Q3:通道剪枝之后的模型晒他,在320/416和未進(jìn)行剪枝對比吱型,batch size 為 1時(shí)前向推理速度基本相同?
猜測:FLOPS降低但是時(shí)間基本相同陨仅,說明FLOPs也同比例降低津滞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市灼伤,隨后出現(xiàn)的幾起案子触徐,更是在濱河造成了極大的恐慌,老刑警劉巖狐赡,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锌介,死亡現(xiàn)場離奇詭異,居然都是意外死亡猾警,警方通過查閱死者的電腦和手機(jī)孔祸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來发皿,“玉大人崔慧,你說我怎么就攤上這事⊙ㄊ” “怎么了惶室?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長玄货。 經(jīng)常有香客問我皇钞,道長,這世上最難降的妖魔是什么松捉? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任鸠踪,我火速辦了婚禮,結(jié)果婚禮上复斥,老公的妹妹穿的比我還像新娘营密。我一直安慰自己,他們只是感情好目锭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布评汰。 她就那樣靜靜地躺著,像睡著了一般痢虹。 火紅的嫁衣襯著肌膚如雪被去。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天缀辩,我揣著相機(jī)與錄音臭埋,去河邊找鬼。 笑死臀玄,一個(gè)胖子當(dāng)著我的面吹牛荣恐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播累贤,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼叠穆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了臼膏?” 一聲冷哼從身側(cè)響起硼被,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渗磅,沒想到半個(gè)月后嚷硫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡始鱼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年仔掸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片医清。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡起暮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出会烙,到底是詐尸還是另有隱情鞋怀,我是刑警寧澤双泪,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站密似,受9級特大地震影響焙矛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜残腌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一村斟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抛猫,春花似錦蟆盹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至败匹,卻和暖如春寨昙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掀亩。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工舔哪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人槽棍。 一個(gè)月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓捉蚤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親炼七。 傳聞我的和親對象是個(gè)殘疾皇子缆巧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容