社群計算機視覺課程文件

MobileNet

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

MobileNet

MobileNet是一種專為移動裝置設計的神經網路架構。它由谷歌研究團隊開發,並於2017年首次推出。MobileNet的主要目標是在智慧手機、平板電腦和其他資源受限的裝置上提供高效能、低延遲的影像分類和目標檢測。

MobileNet透過使用深度可分離卷積來實現這一目標,深度可分離卷積是標準卷積的一種更高效的替代方案。深度可分離卷積將計算分解為兩個獨立的步驟:深度卷積,然後是逐點卷積。這大大減少了引數和計算複雜度,使MobileNet能夠在移動裝置上高效執行。

MobileNet上的卷積型別

透過用這些深度可分離卷積和逐點卷積替換常規卷積層,MobileNet在最小化計算開銷的同時實現了高精度,使其非常適合移動裝置和其他資源有限的平臺。MobileNet中使用了兩種型別的卷積:

深度可分離卷積

在傳統的卷積層中,每個濾波器同時應用於所有輸入通道。深度可分離卷積將其分解為兩個步驟:深度卷積,然後是逐點卷積。

此步驟使用一個小的濾波器(通常是3x3)對輸入影像中的每個通道(單個顏色或特徵)分別執行卷積。此步驟的輸出大小與輸入相同,但通道數更少。

逐點可分離卷積

這種型別的卷積在所有輸入和輸出層中的所有通道上應用單個濾波器(通常是1x1)。它比常規卷積具有更少的引數,可以被視為全連線層的替代,使其適用於計算資源有限的移動裝置。

在深度卷積之後,此步驟使用另一個1x1卷積層組合來自先前步驟的過濾輸出。此操作有效地將深度卷積學習到的特徵聚合到更小的特徵集中,從而在保留重要資訊的同時降低了整體複雜性。

為什麼我們使用這些卷積而不是常規卷積?

為了更好地理解,讓我們簡化並解釋一下:

常規卷積,一個大而一體的濾波器

想象一下你有一個又大又厚的濾鏡(就像一個有多層孔洞的海綿)。這個濾鏡被應用於整個影像。它一次性處理影像的所有部分和所有特徵(例如顏色)。這需要大量的工作(計算)和一個大的濾鏡(記憶體)。

深度可分離卷積——兩步、更輕的程序:

MobileNet以這種基本的方式進行處理。它將大濾波器分成兩個更小、更簡單的步驟:

  • 步驟1 - 深度卷積:首先,它對影像的每個特徵分別使用一個薄濾波器(就像海綿的一層)(例如單獨處理每種顏色)。這工作量較小,因為每個濾波器都很小且簡單。
  • 步驟2 - 逐點卷積:然後,它使用另一個小濾波器(只是一個微小的點)將這些特徵混合在一起。這一步就像對第一個濾波器發現的東西進行總結。

這些步驟是關於什麼的?

MobileNet 使用這兩個更小的步驟而不是一個大步驟,就像執行常規卷積所需工作的輕量級版本。它更高效,尤其是在智慧手機等效能不強的裝置上。

由於濾波器更小,MobileNet 不需要太多記憶體。這就像需要一個更小的盒子來存放所有工具,使其更容易適應更小的裝置。

1x1卷積與普通卷積如何工作?

普通卷積

  • 普通卷積使用較大的核(例如3x3或5x5)一次檢視影像中的一組畫素。這就像觀察圖片的一小塊區域以理解場景的一部分。
  • 這些卷積擅長透過分析畫素彼此相鄰的排列方式來理解邊緣、角和紋理等特徵。

1x1 卷積

  • 1x1 卷積一次只檢視一個畫素。它不嘗試理解相鄰畫素的排列。
  • 即使它只檢視一個畫素,它也會考慮來自不同通道的所有資訊(例如彩色影像中的 RGB 通道)。它將這些通道組合起來,建立該畫素的新版本。
  • 1x1 卷積可以增加或減少通道數量。這意味著它可以簡化資訊(透過減少通道)或建立更復雜的資訊(透過增加通道)。

主要區別

  • 關注區域:普通卷積分析一組畫素以理解模式,而 1x1 卷積則關注單個畫素,結合來自不同通道的資訊。
  • 目的:普通卷積用於檢測影像中的模式和特徵。相比之下,1x1 卷積主要用於改變通道深度,有助於調整資訊的複雜性,以提高神經網路後續層在弱裝置上的效率。

MobileNet 還採用了通道線性瓶頸層等技術,在減少引數數量的同時提高了模型準確性。該架構針對各種硬體平臺進行了最佳化設計,包括 CPU、GPU 甚至 Google 的張量處理單元 (TPU) 等專用硬體。

通道線性瓶頸層

通道線性瓶頸層有助於進一步減少引數數量和計算成本,同時在影像分類任務中保持高精度。

通道線性瓶頸層由三個主要操作按順序應用組成:

  1. 深度卷積:此步驟使用一個小的濾波器(通常是3x3)對輸入影像中的每個通道(單個顏色或特徵)分別執行卷積。此步驟的輸出大小與輸入相同,但通道數更少。
  2. 批歸一化:此操作規範化每個通道的啟用值,有助於穩定訓練過程並提高泛化效能。
  3. 啟用函式:通常,在批歸一化之後使用 ReLU(修正線性單元)啟用函式以在網路中引入非線性。

ReLU有什麼作用?

訓練過程中可能會出現一些問題。我們先解釋這些問題,然後解釋 ReLU 如何解決這些問題。

梯度消失問題

在深度神經網路中,特別是在反向傳播過程中,可能會出現梯度消失問題。當梯度(用於更新網路權重)在網路層中反向傳播時變得非常小,就會發生這種情況。如果這些梯度變得太小,它們就會“消失”,使得網路難以有效學習和調整其權重。

ReLU 對於正值具有線性、不飽和的形式(如果輸入為正,則直接輸出輸入),它確保梯度不會變得太小,從而允許在網路中更快地學習和更有效地調整權重。

非線性

如果沒有非線性,一個神經網路,無論它有多少層,都將作為一個線性模型,無法學習複雜的模式。

ReLU 等非線性函式使神經網路能夠捕獲和學習資料中複雜的關​​系。

推理

您可以使用 Hugging Face 轉換器來推斷各種轉換器模型,如下所示:

from transformers import AutoImageProcessor, AutoModelForImageClassification
from PIL import Image
import requests

url = "http://images.cocodataset.org/val2017/000000039769.jpg"
image = Image.open(requests.get(url, stream=True).raw)

# initialize processor and model
preprocessor = AutoImageProcessor.from_pretrained("google/mobilenet_v2_1.0_224")
model = AutoModelForImageClassification.from_pretrained("google/mobilenet_v2_1.0_224")

# preprocess the inputs
inputs = preprocessor(images=image, return_tensors="pt")

# get the output and the class labels
outputs = model(**inputs)
logits = outputs.logits

predicted_class_idx = logits.argmax(-1).item()
print("Predicted class:", model.config.id2label[predicted_class_idx])
Predicted class: tabby, tabby cat

使用 PyTorch 的示例實現

您可以在下面找到 MobileNet 在 PyTorch 中的示例實現

import torch
import torch.nn as nn
import torch.nn.functional as F


class DepthwiseSeparableConv(nn.Module):
    def __init__(self, in_channels, out_channels, stride):
        super().__init__()
        self.depthwise = nn.Conv2d(
            in_channels,
            in_channels,
            kernel_size=3,
            stride=stride,
            padding=1,
            groups=in_channels,
        )
        self.pointwise = nn.Conv2d(
            in_channels, out_channels, kernel_size=1, stride=1, padding=0
        )

    def forward(self, x):
        x = self.depthwise(x)
        x = self.pointwise(x)
        return x


class MobileNet(nn.Module):
    def __init__(self, num_classes=1000):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1)

        # MobileNet body
        self.dw_conv2 = DepthwiseSeparableConv(32, 64, 1)
        self.dw_conv3 = DepthwiseSeparableConv(64, 128, 2)
        self.dw_conv4 = DepthwiseSeparableConv(128, 128, 1)
        self.dw_conv5 = DepthwiseSeparableConv(128, 256, 2)
        self.dw_conv6 = DepthwiseSeparableConv(256, 256, 1)
        self.dw_conv7 = DepthwiseSeparableConv(256, 512, 2)

        # 5 depthwise separable convolutions with stride 1
        self.dw_conv8 = DepthwiseSeparableConv(512, 512, 1)
        self.dw_conv9 = DepthwiseSeparableConv(512, 512, 1)
        self.dw_conv10 = DepthwiseSeparableConv(512, 512, 1)
        self.dw_conv11 = DepthwiseSeparableConv(512, 512, 1)
        self.dw_conv12 = DepthwiseSeparableConv(512, 512, 1)

        self.dw_conv13 = DepthwiseSeparableConv(512, 1024, 2)
        self.dw_conv14 = DepthwiseSeparableConv(1024, 1024, 1)

        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Linear(1024, num_classes)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)

        x = self.dw_conv2(x)
        x = F.relu(x)
        x = self.dw_conv3(x)
        x = F.relu(x)
        x = self.dw_conv4(x)
        x = F.relu(x)
        x = self.dw_conv5(x)
        x = F.relu(x)
        x = self.dw_conv6(x)
        x = F.relu(x)
        x = self.dw_conv7(x)
        x = F.relu(x)

        x = self.dw_conv8(x)
        x = F.relu(x)
        x = self.dw_conv9(x)
        x = F.relu(x)
        x = self.dw_conv10(x)
        x = F.relu(x)
        x = self.dw_conv11(x)
        x = F.relu(x)
        x = self.dw_conv12(x)
        x = F.relu(x)

        x = self.dw_conv13(x)
        x = F.relu(x)
        x = self.dw_conv14(x)
        x = F.relu(x)

        x = self.avg_pool(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)

        return x


# Create the model
mobilenet = MobileNet(num_classes=1000)
print(mobilenet)

您還可以在此 HuggingFace 連結上找到預訓練的 MobileNet 模型檢查點。

< > 在 GitHub 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.