Was ist ResNet?? Erstellen Sie ResNet von Grund auf mit Python

Inhalt

Dieser Artikel wurde im Rahmen der Data Science Blogathon

Einführung

Es gab eine Reihe von Fortschritten im Bereich Deep Learning und Computer Vision. Insbesondere mit der Einführung sehr tiefer faltender neuronaler Netze, diese Modelle halfen dabei, topaktuelle Ergebnisse bei Problemen wie Bilderkennung und Bildklassifizierung zu erzielen.

Dann, über die Jahre, Deep-Learning-Architekturen wurden immer tiefer (weitere Schichten hinzufügen) um immer komplexere Aufgaben zu lösen, was auch dazu beigetragen hat, die Leistung von Klassifikations- und Erkennungsaufgaben zu verbessern und sie robuster zu machen.

Aber wenn wir dem neuronalen Netzwerk immer mehr Schichten hinzufügen, es wird viel schwieriger zu trainieren und die Genauigkeit des Modells beginnt sich zu sättigen und nimmt dann auch ab. Hier kommt das ResNet, um uns aus diesem Szenario zu retten und dieses Problem zu lösen.

Was ist ResNet??

Restnetz (ResNet) ist eines der berühmten Deep-Learning-Modelle von Shaoqing Ren, Kaiming He, Jian Sun und Xiangyu Zhang in ihrem Artikel. Das Dokument wurde benannt “Deep Residual Learning zur Bilderkennung”. [1] In 2015. Das ResNet-Modell ist bisher eines der beliebtesten und erfolgreichsten Deep-Learning-Modelle.

Restblöcke

Das Problem, sehr tiefe Netze zu trainieren, wurde durch die Einführung dieser Restblöcke gemildert und das ResNet-Modell besteht aus diesen Blöcken.

63071n1-8299125
Quelle: ‘Deep Residual Learning zur Bilderkennung‘ Papier

Das Problem, sehr tiefe Netze zu trainieren, wurde durch die Einführung dieser Restblöcke gemildert und das ResNet-Modell besteht aus diesen Blöcken.

In der Abbildung oben, Das erste, was wir bemerken können, ist, dass es eine direkte Verbindung gibt, die einige Schichten des Modells auslässt. Diese Verbindung heißt “Sprungverbindung” und es ist das Herz der Restblöcke. Die Ausgabe ist aufgrund dieser Sprungverbindung nicht gleich. Ohne die Sprungverbindung, der 'X-Eintrag wird mit den Layer-Gewichten multipliziert, gefolgt vom Hinzufügen eines Schiefen-Terms.

Dann kommt die Aktivierungsfunktion, F () und wir erhalten die Ausgabe als H (x).

h (x) = f (wx + B) Oh (x) = f (x)

Jetzt, mit der Einführung einer neuen Sprungverbindungstechnik, die Ausgabe ist H (x) es ändert sich zu

h (x) = f (x) + x

Die Abmessungen des Einlasses können jedoch von denen des Auslasses abweichen, Was könnte mit einer Faltungsschicht oder gruppierten Schichten passieren?. Deswegen, Dieses Problem kann mit diesen beiden Ansätzen behandelt werden:

· Zero ist mit der Sprungverbindung gepolstert, um seine Abmessungen zu erhöhen.

· Faltungsschichten werden hinzugefügt 1 × 1 am Eingang passend zu den Maßen. In diesem Fall, die Ausgabe ist:

h (x) = f (x) + w1.x

Hier wird ein zusätzlicher Parameter w1 hinzugefügt, während beim ersten Ansatz kein zusätzlicher Parameter hinzugefügt wird.

Diese Umgehungstechnik in ResNet löst das Problem des Verschwindens von Gradienten in tiefen CNNs, indem sie einen alternativen Abkürzungspfad für den Gradienten ermöglicht.. Was ist mehr, Bypass-Verbindung hilft, wenn eine Schicht die Architekturleistung beeinträchtigt, dann wird es von der Regularisierung übersprungen.

ResNet-Architektur

Es gibt ein einfaches Netzwerk von 34 Schichten in der Architektur, die von VGG-19 inspiriert sind, in denen Direktzugriffsverbindungen oder Hop-Verbindungen hinzugefügt werden. Diese Hop-Verbindungen oder Restblöcke konvertieren dann die Architektur in das Restnetzwerk, wie in der Abbildung unten gezeigt.

28984n2-1814961

Quelle: ‘Deep Residual Learning zur Bilderkennung‘ Papier

Verwenden von ResNet mit Keras:

Keras ist eine Open-Source-Deep-Learning-Bibliothek, die auf TensorFlow ausgeführt werden kann. Keras Applications bietet die folgenden Versionen von ResNet.

– ResNet50

– ResNet50V2

– ResNet101

– ResNet101V2

– ResNet152

– ResNet152V2

Lassen Sie uns ResNet von Grund auf neu erstellen:

78567n3-1485933

Quelle: ‘Deep Residual Learning zur Bilderkennung‘ Papier

Lassen Sie uns das obige Bild als Referenz behalten und mit dem Aufbau des Netzwerks beginnen..

Die ResNet-Architektur verwendet CNN-Blöcke mehrfach, Erstellen wir also eine Klasse für den CNN-Block, das nimmt Eingangskanäle und Ausgangskanäle. Es gibt eine Batchnorm2d nach jeder conv .-Schicht.

Taschenlampe importieren
brenner.nn als nn importieren
Klassenblock(nn.Modul):
    def __init__(
        selbst, in_channels, Zwischenkanäle, identity_downsample=Keine, Schritt=1
    ):
        Super(Block, selbst).__drin__()
        Selbstexpansion = 4
        self.conv1 = nn.Conv2d(
            in_channels, Zwischenkanäle, kernel_size=1, Schritt=1, padding=0, Voreingenommenheit=Falsch
        )
        self.bn1 = nn.BatchNorm2d(Zwischenkanäle)
        self.conv2 = nn.Conv2d(
            Zwischenkanäle,
            Zwischenkanäle,
            kernel_size=3,
            Schritt = Schritt,
            Polsterung=1,
            Voreingenommenheit=Falsch
        )
        self.bn2 = nn.BatchNorm2d(Zwischenkanäle)
        self.conv3 = nn.Conv2d(
            Zwischenkanäle,
            Zwischenkanäle * Selbsterweiterung,
            kernel_size=1,
            Schritt=1,
            padding=0,
            Voreingenommenheit=Falsch
        )
        self.bn3 = nn.BatchNorm2d(Zwischenkanäle * Selbsterweiterung)
        self.relu = nn.ReLU()
        self.identity_downsample = identity_downsample
        self.schritt = Schritt

    def vorwärts(selbst, x):
        Identität = x.clone()

        x = self.conv1(x)
        x = selbst.bn1(x)
        x = self.relu(x)
        x = self.conv2(x)
        x = selbst.bn2(x)
        x = self.relu(x)
        x = self.conv3(x)
        x = selbst.bn3(x)

        wenn self.identity_downsample nicht None ist:
            Identität = self.identity_downsample(Identität)

        x += Identität
        x = self.relu(x)
        Rückgabe x

Später, Erstellen Sie eine ResNet-Klasse, die Eingaben von mehreren Blöcken entgegennimmt, deckt, Bildkanäle und die Anzahl der Klassen.

Im folgenden Code, die '_make_layer-Funktion’
Erstellen Sie die ResNet-Schichten, das nimmt die Eingabe von Blöcken, die Anzahl der Residuen
Blöcke, Ausgangskanal und Schritte.

Klasse ResNet(nn.Modul):
    def __init__(selbst, Block, Schichten, image_channels, Anzahl_Klassen):
        Super(ResNet, selbst).__drin__()
        self.in_channels = 64
        self.conv1 = nn.Conv2d(image_channels, 64, kernel_size=7, Schritt = 2, Polsterung=3, Voreingenommenheit=Falsch)
        self.bn1 = nn.BatchNorm2d(64)
        self.relu = nn.ReLU()
        self.maxpool = nn.MaxPool2d(kernel_size=3, Schritt = 2, Polsterung=1)
# Im Wesentlichen ist die gesamte ResNet-Architektur darin enthalten 4 Zeilen unten
self.layer1 = self._make_layer(
Block, Schichten[0], Zwischenkanäle=64, Schritt=1
)
self.layer2 = self._make_layer(
Block, Schichten[1], Zwischenkanäle=128, Schritt = 2
)
self.layer3 = self._make_layer(
Block, Schichten[2], Zwischenkanäle=256, Schritt = 2
)
self.layer4 = self._make_layer(
Block, Schichten[3], Zwischenkanäle=512, Schritt = 2
)

self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
self.fc = nn.Linear(512 * 4, Anzahl_Klassen)

def vorwärts(selbst, x):
x = self.conv1(x)
x = selbst.bn1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)

x = self.avgpool(x)
x = x.umformen(x.form[0], -1)
x = selbst.fc(x)

Rückgabe x

def _make_layer(selbst, Block, Anzahl_Residual_Blocks, Zwischenkanäle, schreiten):
identity_downsample = Keine
Schichten = []

# Entweder, wenn wir den Eingaberaum für ex . halbieren, 56x56 -> 28x28 (Schritt = 2), oder Kanalwechsel
# wir müssen die Identität anpassen (Verbindung überspringen) damit es hinzugefügt werden kann
# zu der Schicht, die vor uns liegt


wenn Schritt != 1 oder self.in_channels != Zwischenkanäle * 4:
identity_downsample = nn.Sequential(
nn.Conv2d(
self.in_channels,
Zwischenkanäle * 4,
kernel_size=1,
Schritt = Schritt,
Voreingenommenheit=Falsch
),
nn.BatchNorm2d(Zwischenkanäle * 4),
)

Schichten.anhängen(
Block(self.in_channels, Zwischenkanäle, Identität_Downsample, schreiten)
)

# Die Erweiterungsgröße ist immer 4 für ResNet 50,101,152
self.in_channels = Zwischenkanäle * 4

# Zum Beispiel für die erste Resnet-Schicht: 256 wird zugeordnet 64 als Zwischenschicht,
# dann endlich zurück zu 256. Daher ist kein Identitäts-Downsampling erforderlich, seit Schritt = 1,
# und auch gleich viele Kanäle.
für mich in Reichweite(Anzahl_Residual_Blocks - 1):
Schichten.anhängen(Block(self.in_channels, Zwischenkanäle))

return nn.Sequential (* deckt)

Dann definieren Sie verschiedene Versionen von ResNet

Für ResNet50, die Schichtenfolge ist [3, 4, 6, 3].

Für ResNet101, die Schichtenfolge ist [3, 4, 23, 3].

Für ResNet152, die Schichtenfolge ist [3, 8, 36, 3]. (Frag die Deep Residual Learning zur Bilderkennung‘ Papier)

def ResNet50(img_channel=3, num_classes=1000):
    zurück ResNet(Block, [3, 4, 6, 3], img_channel, Anzahl_Klassen)
def ResNet101(img_channel=3, num_classes=1000):
zurück ResNet(Block, [3, 4, 23, 3], img_channel, Anzahl_Klassen)


def ResNet152(img_channel=3, num_classes=1000):
zurück ResNet(Block, [3, 8, 36, 3], img_channel, Anzahl_Klassen)

Später, Schreiben Sie einen kleinen Testcode, um zu überprüfen, ob das Modell einwandfrei funktioniert.

def test():
    net = ResNet101(img_channel=3, num_classes=1000)
    Gerät = "Wunder" wenn fackel.cuda.is_verfügbar() anders "Zentralprozessor"
    y = netto(fackel.randn(4, 3, 224, 224)).zu(Gerät)
    drucken(y.größe())
Prüfung()

Für den Testfall oben, die Ausgabe muss sein:

76052n4-1368070

Den vollständigen Code finden Sie hier:

https://github.com/BakingBrains/Deep_Learning_models_implementation_from-scratch_using_pytorch_/blob/main/ResNet_.py

[1]. Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sonne: Restliches Deep Learning zur Bilderkennung, Dezember von 2015, DOI: https://arxiv.org/abs/1512.03385

Vielen Dank.

Ihre Vorschläge und Zweifel sind hier im Kommentarbereich willkommen. Danke, dass du meinen Artikel gelesen hast!

Abonniere unseren Newsletter

Wir senden Ihnen keine SPAM-Mail. Wir hassen es genauso wie du.