[PYTHON] Ich habe versucht, Shake-Shake Regularization (ShakeNet) mit PyTorch zu implementieren

Was ist Shake-Shake-Regularisierung?

Es ist eine der Regularisierung. Durch pseudo-erhöhtes Erhöhen der Trainingsdaten besteht der Vorteil, dass Sie lange Zeit langsam lernen können.

Ist es als Datenerweiterung wirksam, wenn die Anzahl der Daten gering ist? Vorerst möchte ich es diesmal mit CIFAR10 versuchen.

shake-shake-regularization.jpg

Eine kurze Beschreibung der Shake-Shake-Regularisierung ist oben dargestellt. Erstellen Sie in Resnet zwei parallele Redisualblöcke und fügen Sie der Ausgabe der Restblöcke die folgenden Operationen hinzu.

Einzelheiten finden Sie in den Artikeln anderer Personen. Ich habe diesen Artikel gelesen und verstanden. https://qiita.com/masataka46/items/fc7f31073c89b02f8a04

Weitere Details in der Zeitung geschrieben

Das Papier wurde auf verschiedene Arten entworfen.

Restblock erstellen

Es gibt zwei Arten von Resnet, die einfache Architektur und die Engpassarchitektur, aber dieses Mal möchte ich die einfache Architektur verwenden, die dem Papier folgt.

test.py


class ResidualPlainBlock(nn.Module):

    def __init__(self, in_channels, out_channels, stride, padding=0):
        super(ResidualPlainBlock, self).__init__()

        self.in_channels = in_channels
        self.out_channels = out_channels

        self.conv1 = nn.Conv2d(in_channels,  out_channels, kernel_size=3,  stride=stride, padding=1)
        self.bn1 = nn.BatchNorm2d(out_channels)

        self.conv2 = nn.Conv2d(out_channels, out_channels,  kernel_size=3, stride=1, padding=1)
        self.bn2 = nn.BatchNorm2d(out_channels)

        self.conv1_2 = nn.Conv2d(in_channels,  out_channels, kernel_size=3,  stride=stride, padding=1)
        self.bn1_2 = nn.BatchNorm2d(out_channels)

        self.conv2_2 = nn.Conv2d(out_channels, out_channels,  kernel_size=3, stride=1, padding=1)
        self.bn2_2 = nn.BatchNorm2d(out_channels)

        self.identity = nn.Identity()

        if in_channels != out_channels:
          self.down_avg1 = nn.AvgPool2d(kernel_size=1, stride=1)
          self.down_conv1 = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=stride, padding=0)
          self.down_pad1 = nn.ZeroPad2d((1,0,1,0))
          self.down_avg2 = nn.AvgPool2d(kernel_size=1, stride=1)
          self.down_conv2 = nn.Conv2d(in_channels, in_channels, kernel_size=1, stride=stride, padding=0)

    #Spezielle Verarbeitung während der Probenahme
    def shortcut(self,x):
      x = F.relu(x)
      h1 = self.down_avg1(x)
      h1 = self.down_conv1(h1)
      h2 = self.down_pad1(x[:,:,1:,1:])
      h2 = self.down_avg1(h2)
      h2 = self.down_conv2(h2)
      return torch.cat((h1,h2),axis=1)


    def forward(self, x):
      if self.training:
        #1. Restblock
          out = self.bn1(self.conv1(F.relu(x)))
          out = self.bn2(self.conv2(F.relu(out)))
          
        #Zweiter Restblock
          out2 = self.bn1_2(self.conv1_2(F.relu(x)))
          out2 = self.bn2_2(self.conv2_2(F.relu(out2)))

          if self.in_channels != self.out_channels:
            output = self.shortcut(x) + ShakeShake.apply(out,out2)
          else:
            output = self.identity(x) + ShakeShake.apply(out,out2)
          
          return output
      else:
          out = self.bn1(self.conv1(F.relu(x)))
          out = self.bn2(self.conv2(F.relu(out)))
          
          out2 = self.bn1_2(self.conv1_2(F.relu(x)))
          out2 = self.bn2_2(self.conv2_2(F.relu(out2)))

          if self.in_channels != self.out_channels:
            output = self.shortcut(x) + (out+out2)*0.5
          else:
            output = self.identity(x) + (out+out2)*0.5
          
          return output

Der Konstruktor ist chaotisch, aber ich denke, Sie können es verstehen, wenn Sie sich die Vorwärtsfunktion ansehen.

Der Inhalt der Vorwärtsfunktion ist 1: Geben Sie das empfangene x zwei Blöcken 2: Ausgabe aus und aus2 3: Lassen Sie out and out2 von ** ShakeShake.apply () ** verarbeiten 4: Fügen Sie die Verknüpfung und 3 hinzu und geben Sie sie zusammen aus

Capture 1: ShakeShake.apply ()

Sie können eine Klasse namens ShakeShake-Klasse definieren, um die Vorwärts- und Rückwärtsverarbeitung zu definieren.

test.py


class ShakeShake(torch.autograd.Function):
  @staticmethod
  def forward(ctx, i1, i2):
    alpha = random.random()
    result = i1 * alpha + i2 * (1-alpha)

    return result
  @staticmethod
  def backward(ctx, grad_output):
    beta  = random.random()

    return grad_output * beta, grad_output * (1-beta)

In Forward wird eine Zufallszahl Alpha generiert und mit out und out2 multipliziert.

Rückwärts wird eine neue Zufallszahl Beta generiert und auf grad_output angewendet (Wert, der durch Fehlerrückübertragung übertragen wird).

Aufnahme 2: Ändern Sie die Lernrate mit einer Kosinuskurve

Mit PyTorch können Sie Lernraten planen.

Implementieren Sie wie folgt.

test.py


learning_rate = 0.02
optimizer = optim.SGD(net.parameters(),lr=learning_rate,momentum=0.9,weight_decay=0.0001)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=50, eta_min=0.001)

for i in range(200):
  #for 1epoch
    #Lerne hier für 1 Epoche...
  scheduler.step()

Auf diese Weise schwankt die Lernrate für jede Epoche entlang der Kosinuskurve.

Rufen Sie nach dem Definieren des Optimierers den Namen ** CosineAnnealingLR ** auf.

Das erste Argument ist Optimierer, das zweite Argument (T_max) ist die Anzahl der Schritte (Epochennummer) bis zum halben Kosinuszyklus, und das dritte Argument ist die minimale Lernrate.

Im obigen Fall sinkt die Lernrate nach 50 Epochen von 0,02 auf 0,001, kehrt dann nach 50 Epochen zurück, sinkt dann nach 50 Epochen und so weiter.

Ausführungsergebnis

** Die Genauigkeit betrug 89,43% **.

Es ist subtil, weil es zu über 95% im Papier ist.

Die Genauigkeit von normalem ResNet, das nicht entwickelt wurde, liegt jedoch bei etwa 80%, sodass die Genauigkeit anscheinend besser ist.

Das blaue ist train_acc und das orange ist test_acc. 17-89.43.png

Tatsächlich gibt es einige Stellen, die laut dem Papier nicht implementiert sind.

Schließlich

Shake-Shake-Regularisierung macht als leistungsstarke Regularisierungsmethode auf sich aufmerksam.

Vor kurzem wurde anscheinend eine neue Methode namens Shake Drop entwickelt, die ich auch implementieren werde.

Recommended Posts

Ich habe versucht, Shake-Shake Regularization (ShakeNet) mit PyTorch zu implementieren
Ich habe versucht, Attention Seq2Seq mit PyTorch zu implementieren
Ich habe versucht, VQE mit Blueqat zu implementieren
Ich habe Word2Vec mit Pytorch gemacht
Ich habe versucht, DeepPose mit PyTorch zu implementieren
[Einführung in Pytorch] Ich habe mit sinGAN ♬ gespielt
Ich habe versucht, DeepPose mit PyTorch PartⅡ zu implementieren
Ich habe versucht, CVAE mit PyTorch zu implementieren
Ich habe versucht, das Lesen von Dataset mit PyTorch zu implementieren
Ich habe den MNIST-Code von Chainer mit PyTorch + Ignite neu geschrieben
Spiele mit PyTorch
Ich habe CycleGAN (1) implementiert.
Kreuzvalidierung mit PyTorch
Beginnend mit PyTorch
Ich habe ResNet implementiert!
Ich habe versucht, Faster R-CNN mit Pytorch auszuführen
Ich habe versucht, DCGAN mit PyTorch zu implementieren und zu lernen
[Einführung in Pytorch] Ich habe versucht, Cifar10 mit VGG16 ♬ zu kategorisieren
Ich habe versucht, Co-Filtering (Empfehlung) mit Redis und Python zu implementieren
Ich habe versucht, SSD jetzt mit PyTorch zu implementieren (Dataset)
Bei der Verwendung von Tensorboard mit Pytorch ist ein Fehler aufgetreten
Verwenden Sie RTX 3090 mit PyTorch
Ich habe mit Wordcloud gespielt!
Qiskit: Ich habe VQE implementiert
Installieren Sie Fackelstreuung mit PyTorch 1.7
Ich habe versucht, den FloodFill-Algorithmus mit TRON BATTLE von CodinGame zu implementieren
Ich habe versucht, MNIST nach GNN zu klassifizieren (mit PyTorch-Geometrie).
Ich habe versucht, SSD jetzt mit PyTorch zu implementieren (Modellversion)