MobileNet(v2)——CNN經典網絡模型詳解(pytorch實現)

2021-02-13 浩波的筆記

前言:一個CV小白,寫文章目的為了讓和我一樣的小白輕鬆如何,讓大佬鞏固基礎(手動狗頭),大家有任何問題可以一起在評論區留言討論~

推薦B站UP主劈裡啪啦Wz,文章中ppt就是用它的圖片,人講的非常好~

在之前的文章中講的AlexNet、VGG、GoogLeNet以及ResNet網絡,它們都是傳統卷積神經網絡(都是使用的傳統卷積層),缺點在於內存需求大、運算量大導致無法在行動裝置以及嵌入式設備上運行。而本文要講的MobileNet網絡就是專門為移動端,嵌入式端而設計。

MobileNet v1

MobileNet網絡是由google團隊在2017年提出的,專注於移動端或者嵌入式設備中的輕量級CNN網絡。相比傳統卷積神經網絡,在準確率小幅降低的前提下大大減少模型參數與運算量。(相比VGG16準確率減少了0.9%,但模型參數只有VGG的1/32)。

要說MobileNet網絡的優點,無疑是其中的Depthwise Convolution結構(大大減少運算量和參數數量)。下圖展示了傳統卷積與DW卷積的差異,在傳統卷積中,每個卷積核的channel與輸入特徵矩陣的channel相等(每個卷積核都會與輸入特徵矩陣的每一個維度進行卷積運算)。而在DW卷積中,每個卷積核的channel都是等於1的(每個卷積核只負責輸入特徵矩陣的一個channel,故卷積核的個數必須等於輸入特徵矩陣的channel數,從而使得輸出特徵矩陣的channel數也等於輸入特徵矩陣的channel數)

剛剛說了使用DW卷積後輸出特徵矩陣的channel是與輸入特徵矩陣的channel相等的,如果想改變/自定義輸出特徵矩陣的channel,那只需要在DW卷積後接上一個PW卷積即可.

如下圖所示,其實PW卷積就是普通的卷積而已(只不過卷積核大小為1)。通常DW卷積和PW卷積是放在一起使用的,一起叫做Depthwise Separable Convolution(深度可分卷積)。那Depthwise Separable Convolution(深度可分卷積)與傳統的卷積相比有到底能節省多少計算量呢,下圖對比了這兩個卷積方式的計算量,其中Df是輸入特徵矩陣的寬高(這裡假設寬和高相等),Dk是卷積核的大小,M是輸入特徵矩陣的channel,N是輸出特徵矩陣的channel,卷積計算量近似等於卷積核的高 x 卷積核的寬 x 卷積核的channel x 輸入特徵矩陣的高 x 輸入特徵矩陣的寬(這裡假設stride等於1),在我們mobilenet網絡中DW卷積都是是使用3x3大小的卷積核。所以理論上普通卷積計算量是DW+PW卷積的8到9倍(公式來源於原論文):在了解完Depthwise Separable Convolution(深度可分卷積)後在看下mobilenet v1的網絡結構,左側的表格是mobileNetv1的網絡結構,表中標Conv的表示普通卷積,Conv dw代表剛剛說的DW卷積,s表示步距,根據表格信息就能很容易的搭建出mobileNet v1網絡。

在mobilenetv1原論文中,還提出了兩個超參數,一個是α一個是β。

寬度因子為了構造這些結構更小且計算量更小的模型,我們引入了一個參數α,稱為寬度因子。寬度因子α的作用是在每層均勻地稀疏網絡,為每層通道乘以一定的比例,從而減少各層的通道數。常用值有1、0.75、0.5、0.25。

解析度因子為了減少計算量,引入了第二個參數ρ,稱為解析度因子。其作用是在每層特徵圖的大小乘以一定的比例。

下圖右側給出了使用不同α和β網絡的分類準確率,計算量以及模型參數:

在這裡插入圖片描述MobileNet v2

在MobileNet v1的網絡結構表中能夠發現,網絡的結構就像VGG一樣是個直筒型的,不像ResNet網絡有shorcut之類的連接方式。而且有人反映說MobileNet v1網絡中的DW卷積很容易訓練廢掉,效果並沒有那麼理想。所以我們接著看下MobileNet v2網絡。

MobileNet v2網絡是由google團隊在2018年提出的,相比MobileNet V1網絡,準確率更高,模型更小。

MobileNet v2 模型的特點:如上圖,mobileNet v2在V1基礎上進行了改進。

剛剛說了MobileNet v1網絡中的亮點是DW卷積,那麼在MobileNet v2中的亮點就是Inverted residual block(倒殘差結構),同時分析了v1的幾個缺點並針對性的做了改進。v2的改進策略非常簡單,但是在編寫論文時,缺點分析的時候涉及了流行學習等內容,將優化過程弄得非常難懂。我們在這裡簡單總結一下v2中給出的問題分析,希望能對論文的閱讀有所幫助,對v2的motivation感興趣的同學推薦閱讀論文。

當我們單獨去看Feature Map的每個通道的像素的值的時候,其實這些值代表的特徵可以映射到一個低維子空間的一個流形區域上。在進行完卷積操作之後往往會接一層激活函數來增加特徵的非線性性,一個最常見的激活函數便是ReLU。根據我們在殘差網絡中介紹的數據處理不等式(DPI),ReLU一定會帶來信息損耗,而且這種損耗是沒有辦法恢復的,ReLU的信息損耗是當通道數非常少的時候更為明顯。為什麼這麼說呢?我們看圖6中這個例子,其輸入是一個表示流形數據的矩陣,和卷機操作類似,他會經過 n個ReLU的操作得到 n個通道的Feature Map,然後我們試圖通過這n個Feature Map還原輸入數據,還原的越像說明信息損耗的越少。從圖6中我們可以看出,當 n的值比較小時,ReLU的信息損耗非常嚴重,但是當n 的值比較大的時候,輸入流形就能還原的很好了。

根據對上面提到的信息損耗問題分析,我們可以有兩種解決方案:

既然是ReLU導致的信息損耗,那麼我們就將ReLU替換成線性激活函數;如果比較多的通道數能減少信息損耗,那麼我們就使用更多的通道。

如下下圖所示,左側是ResNet網絡中的殘差結構,右側就是MobileNet v2中的到殘差結構。

在殘差結構中是1x1卷積降維->3x3卷積->1x1卷積升維,在倒殘差結構中正好相反,是1x1卷積升維->3x3DW卷積->1x1卷積降維。為什麼要這樣做,原文的解釋是高維信息通過ReLU激活函數後丟失的信息更少(注意倒殘差結構中基本使用的都是ReLU6激活函數,但是最後一個1x1的卷積層使用的是線性激活函數)。

在使用倒殘差結構時需要注意下,並不是所有的倒殘差結構都有shortcut連接,只有當stride=1且輸入特徵矩陣與輸出特徵矩陣shape相同時才有shortcut連接(只有當shape相同時,兩個矩陣才能做加法運算,當stride=1時並不能保證輸入特徵矩陣的channel與輸出特徵矩陣的channel相同)。

下圖是MobileNet v2網絡的結構表,其中t代表的是擴展因子(倒殘差結構中第一個1x1卷積的擴展因子),c代表輸出特徵矩陣的channel,n代表倒殘差結構重複的次數,s代表步距(注意:這裡的步距只是針對重複n次的第一層倒殘差結構,後面的都默認為1)。

一些問題

MobileNet V2中的bottleneck為什麼先擴張通道數在壓縮通道數呢?

因為MobileNet 網絡結構的核心就是Depth-wise,此卷積方式可以減少計算量和參數量。而為了引入shortcut結構,若參照Resnet中先壓縮特徵圖的方式,將使輸入給Depth-wise的特徵圖大小太小,接下來可提取的特徵信息少,所以在MobileNet V2中採用先擴張後壓縮的策略。

MobileNet V2中的bottleneck為什麼在1*1卷積之後使用Linear激活函數?

因為在激活函數之前,已經使用1*1卷積對特徵圖進行了壓縮,而ReLu激活函數對於負的輸入值,輸出為0,會進一步造成信息的損失,所以使用Linear激活函數。

3. 總結

在這篇文章中,我們介紹了兩個版本的MobileNet,它們和傳統卷積的對比如下。如圖(b)所示,MobileNet v1最主要的貢獻是使用了Depthwise Separable Convolution,它又可以拆分成Depthwise卷積和Pointwise卷積。MobileNet v2主要是將殘差網絡和Depthwise Separable卷積進行了結合。通過分析單通道的流形特徵對殘差塊進行了改進,包括對中間層的擴展(d)以及bottleneck層的線性激活(c)。Depthwise Separable Convolution的分離式設計直接將模型壓縮了8倍左右,但是精度並沒有損失非常嚴重,這一點還是非常震撼的。

Depthwise Separable卷積的設計非常精彩但遺憾的是目前cudnn對其的支持並不好,導致在使用GPU訓練網絡過程中我們無法從算法中獲益,但是使用串行CPU並沒有這個問題,這也就給了MobileNet很大的市場空間,尤其是在嵌入式平臺。

最後,不得不承認v2的論文的一系列證明非常精彩,雖然沒有這些證明我們也能明白v2的工作原理,但是這些證明過程還是非常值得仔細品鑑的,尤其是對於從事科研方向的工作人員。

代碼

註:

本次訓練集下載在AlexNet博客有詳細解說:https://blog.csdn.net/weixin_44023658/article/details/105798326使用遷移學習方法實現收錄在我的這篇blog中:遷移學習 TransferLearning—通俗易懂地介紹(pytorch實例)
#model.py

from torch import nn
import torch


def _make_divisible(ch, divisor=8, min_ch=None):
    """
    This function is taken from the original tf repo.
    It ensures that all layers have a channel number that is divisible by 8
    It can be seen here:
    https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
    """
    if min_ch is None:
        min_ch = divisor
    new_ch = max(min_ch, int(ch + divisor / 2) // divisor * divisor)
    # Make sure that round down does not go down by more than 10%.
    if new_ch < 0.9 * ch:
        new_ch += divisor
    return new_ch


class ConvBNReLU(nn.Sequential):
    def __init__(self, in_channel, out_channel, kernel_size=3, stride=1, groups=1):#groups=1普通卷積
        padding = (kernel_size - 1) // 2
        super(ConvBNReLU, self).__init__(
            nn.Conv2d(in_channel, out_channel, kernel_size, stride, padding, groups=groups, bias=False),
            nn.BatchNorm2d(out_channel),
            nn.ReLU6(inplace=True)
        )

#到殘差結構
class InvertedResidual(nn.Module):
    def __init__(self, in_channel, out_channel, stride, expand_ratio):#expand_ratio擴展因子
        super(InvertedResidual, self).__init__()
        hidden_channel = in_channel * expand_ratio
        self.use_shortcut = stride == 1 and in_channel == out_channel

        layers = []
        if expand_ratio != 1:
            # 1x1 pointwise conv
            layers.append(ConvBNReLU(in_channel, hidden_channel, kernel_size=1))
        layers.extend([
            # 3x3 depthwise conv
            ConvBNReLU(hidden_channel, hidden_channel, stride=stride, groups=hidden_channel),
            # 1x1 pointwise conv(linear)
            nn.Conv2d(hidden_channel, out_channel, kernel_size=1, bias=False),
            nn.BatchNorm2d(out_channel),
        ])

        self.conv = nn.Sequential(*layers)

    def forward(self, x):
        if self.use_shortcut:
            return x + self.conv(x)
        else:
            return self.conv(x)


class MobileNetV2(nn.Module):
    def __init__(self, num_classes=1000, alpha=1.0, round_nearest=8):#alpha超參數
        super(MobileNetV2, self).__init__()
        block = InvertedResidual
        input_channel = _make_divisible(32 * alpha, round_nearest)
        last_channel = _make_divisible(1280 * alpha, round_nearest)

        inverted_residual_setting = [
            # t, c, n, s
            [1, 16, 1, 1],
            [6, 24, 2, 2],
            [6, 32, 3, 2],
            [6, 64, 4, 2],
            [6, 96, 3, 1],
            [6, 160, 3, 2],
            [6, 320, 1, 1],
        ]

        features = []
        # conv1 layer
        features.append(ConvBNReLU(3, input_channel, stride=2))
        # building inverted residual residual blockes
        for t, c, n, s in inverted_residual_setting:
            output_channel = _make_divisible(c * alpha, round_nearest)
            for i in range(n):
                stride = s if i == 0 else 1
                features.append(block(input_channel, output_channel, stride, expand_ratio=t))
                input_channel = output_channel
        # building last several layers
        features.append(ConvBNReLU(input_channel, last_channel, 1))
        # combine feature layers
        self.features = nn.Sequential(*features)

        # building classifier
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.classifier = nn.Sequential(
            nn.Dropout(0.2),
            nn.Linear(last_channel, num_classes)
        )

        # weight initialization
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out')
                if m.bias is not None:
                    nn.init.zeros_(m.bias)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.ones_(m.weight)
                nn.init.zeros_(m.bias)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.zeros_(m.bias)

    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x

#train.py

import torch
import torch.nn as nn
from torchvision import transforms, datasets
import json
import os
import torch.optim as optim
from model import MobileNetV2
import torchvision.models.mobilenet




device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)

data_transform = {
    "train": transforms.Compose([transforms.RandomResizedCrop(224),
                                 transforms.RandomHorizontalFlip(),
                                 transforms.ToTensor(),
                                 transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),
    "val": transforms.Compose([transforms.Resize(256),
                               transforms.CenterCrop(224),
                               transforms.ToTensor(),
                               transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])}


data_root = os.path.abspath(os.path.join(os.getcwd(), "../../.."))  # get data root path
image_path = data_root + "/data_set/flower_data/"  # flower data set path

train_dataset = datasets.ImageFolder(root=image_path+"train",
                                     transform=data_transform["train"])
train_num = len(train_dataset)

# {'daisy':0, 'dandelion':1, 'roses':2, 'sunflower':3, 'tulips':4}
flower_list = train_dataset.class_to_idx
cla_dict = dict((val, key) for key, val in flower_list.items())
# write dict into json file
json_str = json.dumps(cla_dict, indent=4)
with open('class_indices.json', 'w') as json_file:
    json_file.write(json_str)

batch_size = 16
train_loader = torch.utils.data.DataLoader(train_dataset,
                                           batch_size=batch_size, shuffle=True,
                                           num_workers=0)

validate_dataset = datasets.ImageFolder(root=image_path + "val",
                                        transform=data_transform["val"])
val_num = len(validate_dataset)
validate_loader = torch.utils.data.DataLoader(validate_dataset,
                                              batch_size=batch_size, shuffle=False,
                                              num_workers=0)

net = MobileNetV2(num_classes=5)
# load pretrain weights
model_weight_path = "./mobilenet_v2.pth"
pre_weights = torch.load(model_weight_path)
# delete classifier weights
pre_dict = {k: v for k, v in pre_weights.items() if "classifier" not in k}
missing_keys, unexpected_keys = net.load_state_dict(pre_dict, strict=False)

# freeze features weights
for param in net.features.parameters():
    param.requires_grad = False

net.to(device)

loss_function = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.0001)

best_acc = 0.0
save_path = './MobileNetV2.pth'
for epoch in range(5):
    # train
    net.train()
    running_loss = 0.0
    for step, data in enumerate(train_loader, start=0):
        images, labels = data
        optimizer.zero_grad()
        logits = net(images.to(device))
        loss = loss_function(logits, labels.to(device))
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.item()
        # print train process
        rate = (step+1)/len(train_loader)
        a = "*" * int(rate * 50)
        b = "." * int((1 - rate) * 50)
        print("\rtrain loss: {:^3.0f}%[{}->{}]{:.4f}".format(int(rate*100), a, b, loss), end="")
    print()

    # validate
    net.eval()
    acc = 0.0  # accumulate accurate number / epoch
    with torch.no_grad():
        for val_data in validate_loader:
            val_images, val_labels = val_data
            outputs = net(val_images.to(device))  # eval model only have last output layer
            # loss = loss_function(outputs, test_labels)
            predict_y = torch.max(outputs, dim=1)[1]
            acc += (predict_y == val_labels.to(device)).sum().item()
        val_accurate = acc / val_num
        if val_accurate > best_acc:
            best_acc = val_accurate
            torch.save(net.state_dict(), save_path)
        print('[epoch %d] train_loss: %.3f  test_accuracy: %.3f' %
              (epoch + 1, running_loss / step, val_accurate))

print('Finished Training')

在這裡插入圖片描述
#pridict.py

import torch
from model import MobileNetV2
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
import json

data_transform = transforms.Compose(
    [transforms.Resize(256),
     transforms.CenterCrop(224),
     transforms.ToTensor(),
     transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])

# load image
img = Image.open("sunflower.jpg")
plt.imshow(img)
# [N, C, H, W]
img = data_transform(img)
# expand batch dimension
img = torch.unsqueeze(img, dim=0)

# read class_indict
try:
    json_file = open('./class_indices.json', 'r')
    class_indict = json.load(json_file)
except Exception as e:
    print(e)
    exit(-1)

# create model
model = MobileNetV2(num_classes=5)
# load model weights
model_weight_path = "./MobileNetV2.pth"
model.load_state_dict(torch.load(model_weight_path))
model.eval()
with torch.no_grad():
    # predict class
    output = torch.squeeze(model(img))
    predict = torch.softmax(output, dim=0)
    predict_cla = torch.argmax(predict).numpy()
print(class_indict[str(predict_cla)], predict[predict_cla].numpy())
plt.show()

相關焦點

  • DenseNet——CNN經典網絡模型詳解(pytorch實現)
    DenseNet——CNN經典網絡模型詳解(pytorch實現)一個CV小白,寫文章目的為了讓和我意義的小白輕鬆如何,讓大佬鞏固基礎(手動狗頭),大家有任何問題可以一起在評論區留言討論~一、概述論文:Densely Connected Convolutional Networks 論文連結:https://arxiv.org/pdf
  • ResNet——CNN經典網絡模型詳解(pytorch實現)
    ResNet的結構可以極快的加速神經網絡的訓練,模型的準確率也有比較大的提升。同時ResNet的推廣性非常好,甚至可以直接用到InceptionNet網絡中。下圖是ResNet34層模型的結構簡圖。2、ResNet詳解在ResNet網絡中有如下幾個亮點:提出residual結構(殘差結構),並搭建超深的網絡結構(突破1000層)使用Batch Normalization加速訓練(丟棄dropout)在ResNet網絡提出之前,傳統的卷積神經網絡都是通過將一系列卷積層與下採樣層進行堆疊得到的。但是當堆疊到一定網絡深度時,就會出現兩個問題。
  • 【乾貨】基於pytorch的CNN、LSTM神經網絡模型調參小結
    的結合還有多層多通道CNN、LSTM、BiLSTM等多個神經網絡模型的的實現。Demo Site:  https://github.com/bamtercelboo/cnn-lstm-bilstm-deepcnn-clstm-in-pytorchPytorch是一個較新的深度學習框架,是一個 Python 優先的深度學習框架,能夠在強大的 GPU 加速基礎上實現張量和動態神經網絡。
  • 深度學習100+經典模型TensorFlow與Pytorch代碼實現大集合
    【導讀】深度學習在過去十年獲得了極大進展,出現很多新的模型,並且伴隨TensorFlow和Pytorch框架的出現,有很多實現,但對於初學者和很多從業人員
  • mobilenet系列之又一新成員---mobilenet-v3
    簡要概述文章精華mobilenet-v3是Google繼mobilenet-v2之後的又一力作,作為mobilenet系列的新成員,自然效果會提升
  • LeNet-5——CNN經典網絡模型詳解(pytorch實現)
    一、LeNet-5這個是n多年前就有的一個CNN的經典結構,主要是用於手寫字體的識別,也是剛入門需要學習熟悉的一個網絡。原論文地址輸入:32*32的手寫字體圖片,這些手寫字體包含0~9數字,也就是相當於10個類別的圖片輸出:分類結果,0~9之間的一個數因此我們可以知道,這是一個多分類問題,總共有十個類,因此神經網絡的最後輸出層必然是SoftMax問題,然後神經元的個數是10個。
  • 小白學PyTorch | 12 SENet詳解及PyTorch實現
    PyTorch實現小白學PyTorch | 10 pytorch常見運算詳解小白學PyTorch | 9 tensor數據結構與存儲結構小白學PyTorch | 8 實戰之MNIST小試牛刀| 1 搭建一個超簡單的網絡小白學PyTorch | 動態圖與靜態圖的淺顯理解這個系列《小白學PyTorch》的所有代碼和數據集放在了公眾號【機器學習煉丹術】後臺,回復【pytorch】獲取(還在更新的呢):
  • AlexNet--CNN經典網絡模型詳解(pytorch實現)
    建議大家可以實踐下,代碼都很詳細,有不清楚的地方評論區見~二、AlexNet在imagenet上的圖像分類challenge上大神Alex提出的alexnet網絡結構模型贏得了2012屆的冠軍,振奮人心,利用CNN實現了圖片分類,別人用傳統的機器學習算法調參跳到半死也就那樣,Alex
  • onnx實現對pytorch模型推理加速
    對於硬體供應商來說,也可以簡化神經網絡計算的複雜度,實現優化算法。("cuda" if torch.cuda.is_available() else "cpu")model = torch.load("test.pth") # pytorch模型加載batch_size = 1 #批處理大小input_shape = (3, 244, 384) #輸入數據,改成自己的輸入
  • 用 PyTorch 實現一個簡單的分類器
    有的教程一上來就是寫一個 cnn,雖然其實內容很簡單,但是直接上手容易讓人找不到重點,學的雲裡霧裡。有的教程又淺嘗輒止,師傅領到了門檻跟前,總感覺自己還沒有進門,教程就結束了。所以我總結了一下自己當初學習的路線,準備繼續深入鞏固自己的 pytorch 基礎;另一方面,也想從頭整理一個教程,從沒有接觸過 pytorch 開始,到完成一些最新論文裡面的工作。
  • CNN卷積神經網絡實例(基於pytorch)
    1.關於卷積神經網絡卷積神經網絡(Convolutional Neural Network,CNN) 是一種具有局部連接、權重共享等特徵的深層前饋神經網絡
  • pytorch學習筆記(2):在 MNIST 上實現一個 cnn
    接下來進入正文吧~gogogo這篇筆記的內容包含三個部分:讀取 pytorch 自帶的數據集並分割;實現一個 CNN 的網絡結構;完成訓練。這三個部分合起來完成了一個簡單的淺層卷積神經網絡,在 MNIST 上進行訓練和測試。1.
  • 雲計算學習:用PyTorch實現一個簡單的分類器
    回想了一下自己關於 pytorch 的學習路線,一開始找的各種資料,寫下來都能跑,但是卻沒有給自己體會到學習的過程。有的教程一上來就是寫一個 cnn,雖然其實內容很簡單,但是直接上手容易讓人找不到重點,學的雲裡霧裡。
  • Keras vs PyTorch vs Caffe:CNN實現對比
    這些深度學習框架提供了高級編程接口,幫助我們設計深度學習模型。使用深度學習框架,它通過提供內置的庫函數來減少開發人員的工作,從而使我們能夠更快更容易地構建模型。在本文中,我們將構建相同的深度學習框架,即在Keras、PyTorch和Caffe中對同一數據集進行卷積神經網絡圖像分類,並對所有這些方法的實現進行比較。
  • 一行代碼即可調用18款主流模型!PyTorch Hub輕鬆解決論文可復現性
    ,加載ResNet、BERT、GPT、VGG、PGAN還是MobileNet等經典模型只需一行代碼。用戶可以提交、瀏覽模型,極大的改善了論文的可復現性難題。機器學習論文的可復現性一直是個難題。許多機器學習相關論文要麼無法復現,要麼難以重現。有時候論文讀者經常為了調用各種經典機器學習模型,還要重複造輪子。隨著提交給arXiv以及各種會議上的論文數量開始暴漲,可復現性的重要性也越來越凸顯。
  • 【深度學習】Keras vs PyTorch vs Caffe:CNN實現對比
    這些深度學習框架提供了高級編程接口,幫助我們設計深度學習模型。使用深度學習框架,它通過提供內置的庫函數來減少開發人員的工作,從而使我們能夠更快更容易地構建模型。在本文中,我們將構建相同的深度學習框架,即在Keras、PyTorch和Caffe中對同一數據集進行卷積神經網絡圖像分類,並對所有這些方法的實現進行比較。
  • 庫、教程、論文實現,這是一份超全的PyTorch資源列表(Github 2.2K星)
    項目地址:https://github.com/longcw/RoIAlign.pytorch10.pytorch-cnn-finetune:PyTorch 實現的微調預訓練卷積神經網絡。項目地址:https://github.com/creafz/pytorch-cnn-finetune11.detectorch:PyTorch 實現的 detectron 圖像分割模型。項目地址:https://github.com/ignacio-rocco/detectorch12.Augmentor:Python 圖像增強庫。
  • 【小白學PyTorch】18.TF2構建自定義模型
    實現一個簡單的服裝分類任務小白學PyTorch | 14 tensorboardX可視化教程小白學PyTorch | 13 EfficientNet詳解及PyTorch實現>小白學PyTorch | 12 SENet詳解及PyTorch實現小白學PyTorch | 11 MobileNet詳解及PyTorch實現小白學PyTorch | 10 pytorch
  • 輕鬆學pytorch-構建卷積神經網絡
    大家好,這個是我的pytorch學習筆記第三篇,主要是使用pytorch來構建一個簡單的卷積神經網絡,完成mnist手寫字符識別。涉及到主要知識點是如何使用torch.nn.Module這個基類來實現一個網絡結構定義。這個基類中最重要的是實現自己的forward方法,這個也是自定義網絡結構的實現方法。
  • 不用重新訓練,直接將現有模型轉換為 MobileNet
    點擊文末「閱讀原文」立刻申請入群~作者 | autocyz來源 | https://zhuanlan.zhihu.com/p/54425450原文 | http://bbs.cvmart.net/articles/301從MobileNet中的深度可分卷積(Depthwise Separable Convolution