Technologieaustausch

VGG16 implementiert die Pytorch-Implementierung der Bildklassifizierung und erklärt die Schritte im Detail

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

VGG16 implementiert die Bildklassifizierung

Hier implementieren wir ein VGG-16-Netzwerk zur Klassifizierung des CIFAR-Datensatzes

Einführung in das VGG16-Netzwerk

Vorwort

《Sehr tiefe Faltungsnetzwerke für die großflächige Bilderkennung》

ICLR 2015

VGGEs ist aus OxfordVbildlichGEometrieG Vorgeschlagen von der Gruppe der Gruppe (Sie sollten den Ursprung des Namens VGG erkennen können). Dieses Netzwerk ist eine verwandte Arbeit auf der ILSVRC 2014. Die Hauptarbeit besteht darin, zu beweisen, dass eine Erhöhung der Netzwerktiefe die endgültige Leistung des Netzwerks bis zu einem gewissen Grad beeinflussen kann. VGG hat zwei Strukturen, nämlich VGG16 und VGG19. Es gibt keinen wesentlichen Unterschied zwischen den beiden, aber die Netzwerktiefe ist unterschiedlich.

VGG-Prinzip

Darin liegt eine Verbesserung von VGG16 im Vergleich zu AlexNetVerwenden Sie mehrere aufeinanderfolgende 3x3-Faltungskerne, um die größeren Faltungskerne in AlexNet (11x11, 7x7, 5x5) zu ersetzen. . Für ein bestimmtes Empfangsfeld (die lokale Größe des Eingabebildes im Verhältnis zur Ausgabe) ist die Verwendung gestapelter kleiner Faltungskerne besser als die Verwendung großer Faltungskerne, da mehrere nichtlineare Schichten die Netzwerktiefe erhöhen können, um einen komplexeren Lernmodus sicherzustellen Die Kosten sind relativ gering (weniger Parameter).

Vereinfacht ausgedrückt werden in VGG drei 3x3-Faltungskerne verwendet, um den 7x7-Faltungskern zu ersetzen, und zwei 3x3-Faltungskerne werden verwendet, um den 5*5-Faltungskern zu ersetzen. Der Hauptzweck besteht darin, das Gleiche sicherzustellen Durch das Empfangsfeld wird die Tiefe des Netzwerks verbessert und die Wirkung des neuronalen Netzwerks wird bis zu einem gewissen Grad verbessert.

Beispielsweise kann die schichtweise Überlagerung von drei 3x3-Faltungskernen mit einem Schritt von 1 als Empfangsfeld der Größe 7 betrachtet werden (eigentlich bedeutet dies, dass drei kontinuierliche 3x3-Faltungen einer 7x7-Faltung entsprechen). Die Gesamtzahl der Parameter beträgt 3x(9xC^2). Wenn der 7x7-Faltungskern direkt verwendet wird, beträgt die Gesamtzahl der Parameter 49xC^2, wobei sich C auf die Anzahl der Eingangs- und Ausgangskanäle bezieht.Offensichtlich 27xC2 weniger als 49xC2, das heißt, die Parameter werden reduziert und der 3x3-Faltungskern trägt dazu bei, die Bildeigenschaften besser aufrechtzuerhalten.

Hier ist eine Erklärung, warum zwei 3x3-Faltungskerne anstelle von 5*5-Faltungskernen verwendet werden können:

Die 5x5-Faltung wird als kleines, vollständig verbundenes Netzwerk betrachtet, das im 5x5-Bereich gleitet. Wir können dann eine vollständig verbundene Schicht verwenden, um den 3x3-Faltungsausgang zu verbinden als 3x3-Faltungsschicht angesehen werden. Auf diese Weise können wir zwei 3x3-Faltungen anstelle einer 5x5-Faltung kaskadieren (überlagern).

Die Details sind in der folgenden Abbildung dargestellt:

Fügen Sie hier eine Bildbeschreibung ein

VGG-Netzwerkstruktur

Fügen Sie hier eine Bildbeschreibung ein

Das Folgende ist die Struktur des VGG-Netzwerks (sowohl VGG16 als auch VGG19 sind vorhanden):

Fügen Sie hier eine Bildbeschreibung ein

GG-Netzwerkstruktur

VGG16 enthält 16 verborgene Schichten (13 Faltungsschichten und 3 vollständig verbundene Schichten), wie in Spalte D in der obigen Abbildung dargestellt

VGG19 enthält 19 verborgene Schichten (16 Faltungsschichten und 3 vollständig verbundene Schichten), wie in Spalte E in der obigen Abbildung dargestellt

Die Struktur des VGG-Netzwerks ist sehr konsistent und verwendet von Anfang bis Ende 3x3-Faltung und 2x2-Max-Pooling.

Vorteile von VGG

Die Struktur von VGGNet ist sehr einfach. Das gesamte Netzwerk verwendet die gleiche Faltungskerngröße (3x3) und die gleiche maximale Poolinggröße (2x2).

Die Kombination mehrerer Faltungsschichten mit kleinem Filter (3x3) ist besser als eine Faltungsschicht mit großem Filter (5x5 oder 7x7):

Es wird nachgewiesen, dass die Leistung durch eine kontinuierliche Vertiefung der Netzwerkstruktur verbessert werden kann.

Nachteile von VGG

VGG verbraucht mehr Rechenressourcen und verwendet mehr Parameter (dies ist nicht der Topf der 3x3-Faltung), was zu einer höheren Speichernutzung führt (140 MB).

Datensatzverarbeitung

Einführung in den Datensatz

Der CIFAR-Datensatz (Canadian Institute For Advanced Research) ist ein kleiner Bilddatensatz, der im Bereich Computer Vision weit verbreitet ist. Er wird hauptsächlich zum Trainieren von Algorithmen für maschinelles Lernen und Computer Vision verwendet, insbesondere für Aufgaben wie Bilderkennung und -klassifizierung. Der CIFAR-Datensatz besteht aus zwei Hauptteilen: CIFAR-10 und CIFAR-100.

CIFAR-10 ist ein Datensatz mit 60.000 32x32-Farbbildern, die in 10 Kategorien unterteilt sind, wobei jede Kategorie 6.000 Bilder enthält. Die 10 Kategorien sind: Flugzeuge, Autos, Vögel, Katzen, Hirsche, Hunde, Frösche, Pferde, Boote und Lastwagen. Im Datensatz werden 50.000 Bilder zum Training und 10.000 Bilder zum Testen verwendet. Der CIFAR-10-Datensatz hat sich aufgrund seiner moderaten Größe und reichhaltigen Klasseninformationen zu einem der sehr beliebten Datensätze in Forschung und Lehre im Bereich Computer Vision entwickelt.

Eigenschaften des Datensatzes
  • mittlere Größe: Die geringe Bildgröße des CIFAR-Datensatzes (32 x 32) macht sie ideal für das schnelle Training und Testen neuer Computer-Vision-Algorithmen.
  • Verschiedene Kategorien: CIFAR-10 bietet grundlegende Bildklassifizierungsaufgaben, während CIFAR-100 die feinkörnigen Klassifizierungsfähigkeiten des Algorithmus weiter herausfordert.
  • weit verbreitet: Aufgrund dieser Eigenschaften wird der CIFAR-Datensatz häufig in Forschung und Lehre in den Bereichen Computer Vision, maschinelles Lernen, Deep Learning und anderen Bereichen verwendet.
Szenen, die verwendet werden sollen

Der CIFAR-Datensatz wird häufig für Aufgaben wie Bildklassifizierung, Objekterkennung sowie das Training und Testen von Faltungs-Neuronalen Netzen (CNN) verwendet. Aufgrund seiner moderaten Größe und umfangreichen Kategorieinformationen ist es ideal für Anfänger und Forscher, die sich mit Bilderkennungsalgorithmen beschäftigen. Darüber hinaus verwenden viele Wettbewerbe im Bereich Computer Vision und maschinelles Lernen den CIFAR-Datensatz als Benchmark, um die Leistung der Algorithmen der Teilnehmer zu bewerten.

Um den Datensatz vorzubereiten, habe ich ihn bereits heruntergeladen. Wenn es nicht funktioniert, laden Sie ihn einfach von der offiziellen Website herunter, oder ich gebe ihn Ihnen direkt.

Wenn Sie den Datensatz benötigen, wenden Sie sich bitte an die E-Mail-Adresse: 2837468248@qq.com

Mein Datensatz wurde ursprünglich durch die heruntergeladenen Daten in Torchvision generiert. Ich möchte die Definition des Datensatzes und das Laden des DataLoaders jetzt Schritt für Schritt umsetzen und verstehen Der Prozess der Datensatzverarbeitung kann Ihnen einen tieferen Einblick in das Deep Learning verschaffen.

Der Datensatzstil ist wie folgt:

Fügen Sie hier eine Bildbeschreibung ein

Analysieren Sie alle Beschriftungen des Datensatzes

Die Beschriftungskategorie des Datensatzes verwendet a.metaDie Datei wird gespeichert, daher müssen wir sie analysieren .meta Datei zum Lesen aller Tag-Daten. Der Parsing-Code lautet wie folgt:

# 首先了解所有的标签,TODO 可以详细了解一下这个解包的过程
import pickle


def unpickle(file):
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
    return dict


meta_data = unpickle('./dataset_method_1/cifar-10-batches-py/batches.meta')
label_names = meta_data[b'label_names']
# 将字节标签转换为字符串
label_names = [label.decode('utf-8') for label in label_names]
print(label_names)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Die Ergebnisse der Analyse sind wie folgt:

['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
  • 1

Laden Sie einen einzelnen Datenstapel, um die Daten einfach zu testen

Unser Datensatz wurde heruntergeladen, daher müssen wir den Inhalt der Datei lesen. Da es sich bei der Datei um eine Binärdatei handelt, müssen wir zum Lesen den binären Lesemodus verwenden.

Der Lesecode lautet wie folgt:

# 载入单个批次的数据
import numpy as np


def load_data_batch(file):
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
        X = dict[b'data']
        Y = dict[b'labels']
        X = X.reshape(10000, 3, 32, 32).transpose(0, 2, 3, 1)  # reshape and transpose to (10000, 32, 32, 3)
        Y = np.array(Y)
    return X, Y


# 加载第一个数据批次
data_batch_1 = './dataset_method_1/cifar-10-batches-py/data_batch_1'
X1, Y1 = load_data_batch(data_batch_1)

print(f'数据形状: {X1.shape}, 标签形状: {Y1.shape}')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

Ergebnis:

数据形状: (10000, 32, 32, 3), 标签形状: (10000,)
  • 1

Laden Sie alle Daten

Nach dem obigen Test wissen wir, wie man Daten lädt. Jetzt laden wir alle Daten.

Laden des Trainingssatzes:

# 整合所有批次的数据
def load_all_data_batches(batch_files):
    X_list, Y_list = [], []
    for file in batch_files:
        X, Y = load_data_batch(file)
        X_list.append(X)
        Y_list.append(Y)
    X_all = np.concatenate(X_list)
    Y_all = np.concatenate(Y_list)
    return X_all, Y_all


batch_files = [
    './dataset_method_1/cifar-10-batches-py/data_batch_1',
    './dataset_method_1/cifar-10-batches-py/data_batch_2',
    './dataset_method_1/cifar-10-batches-py/data_batch_3',
    './dataset_method_1/cifar-10-batches-py/data_batch_4',
    './dataset_method_1/cifar-10-batches-py/data_batch_5'
]

X_train, Y_train = load_all_data_batches(batch_files)
print(f'训练数据形状: {X_train.shape}, 训练标签形状: {Y_train.shape}')
Y_train = Y_train.astype(np.int64)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Ausgabe:

训练数据形状: (50000, 32, 32, 3), 训练标签形状: (50000,)
  • 1

Laden des Testsatzes:

test_batch = './dataset_method_1/cifar-10-batches-py/test_batch'
X_test, Y_test = load_data_batch(test_batch)
Y_test = Y_test.astype(np.int64)
print(f'测试数据形状: {X_test.shape}, 测试标签形状: {Y_test.shape}')

  • 1
  • 2
  • 3
  • 4
  • 5

Ausgabe:

测试数据形状: (10000, 32, 32, 3), 测试标签形状: (10000,)
  • 1

Definieren Sie eine Unterklasse von Dataset

Durch Definieren einer Unterklasse der Dataset-Klasse soll das spätere Laden des Dataloaders für das Batch-Training erleichtert werden.

Es gibt drei Methoden, die Unterklassen von Dataset implementieren müssen.

  • __init__()Klassenkonstruktor
  • __len__()Gibt die Länge des Datensatzes zurück
  • __getitem__()Holen Sie sich ein Datenelement aus dem Datensatz

Hier ist meine Implementierung wie folgt:

from torch.utils.data import DataLoader, Dataset


# 定义 Pytorch 的数据集 
class CIFARDataset(Dataset):
    def __init__(self, images, labels, transform=None):
        self.images = images
        self.labels = labels
        self.transform = transform

    def __len__(self):
        return len(self.images)

    def __getitem__(self, idx):
        image = self.images[idx]
        label = self.labels[idx]

        if self.transform:
            image = self.transform(image)

        return image, label
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

Laden Sie den Datensatz als Dataloader

  1. Definieren Sie zunächst eine Transformation, um die Daten zu verbessern. Der Trainingssatz muss um 4 Pixel erweitert, normalisiert, horizontal gespiegelt und schließlich auf die ursprünglichen Pixel von 32 * 32 zurückgesetzt werden.
transform_train = transforms.Compose(
    [transforms.Pad(4),
     transforms.ToTensor(),
     transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
     transforms.RandomHorizontalFlip(),
     transforms.RandomGrayscale(),
     transforms.RandomCrop(32, padding=4),
     ])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  1. Da es sich um eine Bildverarbeitung handelt und es sich bei den Daten, die wir aus der Binärdatei lesen, um Numpy-Daten handelt, müssen wir das Numpy-Array in Bilddaten konvertieren, um die Bildverarbeitung zu erleichtern. Gehen Sie wie folgt vor:
# 把数据集变成 Image 的数组,不然好像不能进行数据的增强
# 改变训练数据
from PIL import Image
def get_PIL_Images(origin_data):
    datas = []
    for i in range(len(origin_data)):
        data = Image.fromarray(origin_data[i])
        datas.append(data)
    return datas
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. Holen Sie sich den trainierten Datenlader
train_data = get_PIL_Images(X_train)
train_loader = DataLoader(CIFARDataset(train_data, Y_train, transform_train), batch_size=24, shuffle=True)
  • 1
  • 2
  1. Das Abrufen des Testdatenlade-Testsatzes erfordert nicht zu viel Verarbeitung. Der Code wird hier direkt angegeben.
# 测试集的预处理
transform_test = transforms.Compose(
    [
        transforms.ToTensor(),
        transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))]
)
test_loader = DataLoader(CIFARDataset(X_test, Y_test, transform_test), batch_size=24, shuffle=False)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Netzwerk definieren

Wir implementieren das Pytorch-Framework basierend auf dem oben erwähnten VGG16-Netzwerk.

hauptsächlich unterteilt:

  • Faltungsschicht
  • Vollständig verbundene Schicht
  • Klassifizierungsschicht

Die Implementierung ist wie folgt:

class VGG16(nn.Module):
    def __init__(self):
        super(VGG16, self).__init__()
        # 卷积层,这里进行卷积
        self.convolusion = nn.Sequential(
            nn.Conv2d(3, 96, kernel_size=3, padding=1), # 设置为padding=1 卷积完后,数据大小不会变
            nn.BatchNorm2d(96),
            nn.ReLU(inplace=True),
            nn.Conv2d(96, 96, kernel_size=3, padding=1),
            nn.BatchNorm2d(96),
            nn.ReLU(inplace=True),
            nn.Conv2d(96, 96, kernel_size=3, padding=1),
            nn.BatchNorm2d(96),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(96, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(inplace=True),
            nn.Conv2d(128, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(inplace=True),
            nn.Conv2d(128, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(128, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(256, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),
            nn.Conv2d(512, 512, kernel_size=3, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),
            nn.AvgPool2d(kernel_size=1, stride=1)
        )
        # 全连接层
        self.dense = nn.Sequential(
            nn.Linear(512, 4096), # 32*32 的图像大小经过 5 次最大化池化后就只有 1*1 了,所以就是 512 个通道的数据输入全连接层
            nn.ReLU(inplace=True),
            nn.Dropout(0.4),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(0.4),
        )
        # 输出层
        self.classifier = nn.Linear(4096, 10)

    def forward(self, x):
        out = self.convolusion(x)
        out = out.view(out.size(0), -1)
        out = self.dense(out)
        out = self.classifier(out)
        return out
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

Schulung und Prüfung

Für Training und Tests müssen Sie lediglich das Modell instanziieren, dann die Optimierungsfunktion, die Verlustfunktion und die Verlustrate definieren und dann Training und Tests durchführen.

Code wie folgt anzeigen:

Hyperparameterdefinition:

# 定义模型进行训练
model = VGG16()
# model.load_state_dict(torch.load('./my-VGG16.pth'))
optimizer = optim.SGD(model.parameters(), lr=0.01, weight_decay=5e-3)
loss_func = nn.CrossEntropyLoss()
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.4, last_epoch=-1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Testfunktion:

def test():
    model.eval()
    correct = 0  # 预测正确的图片数
    total = 0  # 总共的图片数
    with torch.no_grad():
        for data in test_loader:
            images, labels = data
            images = images.to(device)
            outputs = model(images).to(device)
            outputs = outputs.cpu()
            outputarr = outputs.numpy()
            _, predicted = torch.max(outputs, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum()
    accuracy = 100 * correct / total
    accuracy_rate.append(accuracy)
    print(f'准确率为:{accuracy}%'.format(accuracy))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Ausbildungsepochen:

# 定义训练步骤
total_times = 40
total = 0
accuracy_rate = []
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

for epoch in range(total_times):
    model.train()
    model.to(device)
    running_loss = 0.0
    total_correct = 0
    total_trainset = 0
    print("epoch: ",epoch)
    for i, (data,labels) in enumerate(train_loader):
        data = data.to(device)
        outputs = model(data).to(device)
        labels = labels.to(device)
        loss = loss_func(outputs,labels).to(device)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
        _,pred = outputs.max(1)
        correct = (pred == labels).sum().item()
        total_correct += correct
        total_trainset += data.shape[0]
        if i % 100 == 0 and i > 0:
            print(f"正在进行第{i}次训练, running_loss={running_loss}".format(i, running_loss))
            running_loss = 0.0
    test()
    scheduler.step()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

Speichern Sie das trainierte Modell:

torch.save(model.state_dict(), './my-VGG16.pth')
accuracy_rate = np.array(accuracy_rate)
times = np.linspace(1, total_times, total_times)
plt.xlabel('times')
plt.ylabel('accuracy rate')
plt.plot(times, accuracy_rate)
plt.show()
print(accuracy_rate)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

prüfen

  1. Modell definieren
model_my_vgg = VGG16()
  • 1
  1. Fügen Sie trainierte Modelldaten hinzu
model_my_vgg.load_state_dict(torch.load('./my-VGG16-best.pth',map_location='cpu'))
  • 1
  1. Ich habe die Verifizierungsbilder verarbeitet, die ich selbst gefunden habe
from torchvision import transforms
from PIL import Image

# 定义图像预处理步骤
preprocess = transforms.Compose([
    transforms.Resize((32, 32)),
    transforms.ToTensor(),
    # transforms.Normalize(mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225]),
])

def load_image(image_path):
    image = Image.open(image_path)
    image = preprocess(image)
    image = image.unsqueeze(0)  # 添加批次维度
    return image

image_data = load_image('./plane2.jpg')
print(image_data.shape)
output = model_my_vgg(image_data)
verify_data = X1[9]
verify_label = Y1[9]
output_verify = model_my_vgg(transform_test(verify_data).unsqueeze(0))
print(output)
print(output_verify)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Ausgabe:

torch.Size([1, 3, 32, 32])
tensor([[ 1.5990, -0.5269,  0.7254,  0.3432, -0.5036, -0.3267, -0.5302, -0.9417,
          0.4186, -0.1213]], grad_fn=<AddmmBackward0>)
tensor([[-0.6541, -2.0759,  0.6308,  1.9791,  0.8525,  1.2313,  0.1856,  0.3243,
         -1.3374, -1.0211]], grad_fn=<AddmmBackward0>)
  • 1
  • 2
  • 3
  • 4
  • 5
  1. Ergebnisse drucken
print(label_names[torch.argmax(output,dim=1,keepdim=False)])
print(label_names[verify_label])
print("pred:",label_names[torch.argmax(output_verify,dim=1,keepdim=False)])
  • 1
  • 2
  • 3
airplane
cat
pred: cat
  • 1
  • 2
  • 3

Fügen Sie hier eine Bildbeschreibung ein

Pferd überprüfen

Fügen Sie hier eine Bildbeschreibung ein

Verifizierungshund

Fügen Sie hier eine Bildbeschreibung ein