Teknologian jakaminen

VGG16 toteuttaa kuvien luokituksen pytorch-toteutuksen ja selittää vaiheet yksityiskohtaisesti

2024-07-12

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

VGG16 toteuttaa kuvan luokituksen

Tässä toteutamme VGG-16-verkon CIFAR-tietojoukon luokittelemiseksi

VGG16-verkon esittely

Esipuhe

《Erittäin syvät konvoluutioverkot suuren mittakaavan kuvantunnistusta varten》

ICLR 2015

VGGSe on OxfordistaVisualGeometriaG Roup-ryhmän ehdottama (sinun pitäisi pystyä näkemään nimen VGG alkuperä). Tämä verkko liittyy ILSVRC 2014 -tapahtumaan liittyvään työskentelyyn. Päätyönä on osoittaa, että verkon syvyyden lisääminen voi vaikuttaa verkon lopulliseen suorituskykyyn jossain määrin. VGG:llä on kaksi rakennetta, nimittäin VGG16 ja VGG19. Näiden kahden välillä ei ole olennaista eroa, mutta verkon syvyys on erilainen.

VGG periaate

VGG16:n parannus AlexNetiin verrattuna on seKäytä useita peräkkäisiä 3x3-konvoluutioytimiä korvatakseen AlexNetin suuremmat konvoluutioytimet (11x11, 7x7, 5x5) . Tietylle vastaanottavalle kentälle (syötekuvan paikallinen koko suhteessa ulostuloon) pinottujen pienten konvoluutioytimien käyttö on parempi kuin suurten konvoluutioytimien käyttäminen, koska useat epälineaariset kerrokset voivat lisätä verkon syvyyttä monimutkaisemman oppimistilan varmistamiseksi hinta on suhteellisen pieni (vähemmän parametreja).

Yksinkertaisesti sanottuna VGG:ssä kolmea 3x3-konvoluutioytimistä käytetään korvaamaan 7x7-konvoluutioytiminen ja kahdella 3x3-konvoluutioytimellä korvataan 5x5-konvoluutioytimellä. Tämän päätarkoituksena on varmistaa sama Reseptiivisen kentän syvyys paranee ja hermoverkon vaikutus paranee jossain määrin.

Esimerkiksi kolmen 3x3 konvoluutioytimen kerros kerrokselta superpositiota askeleella 1 voidaan pitää vastaanottavana kenttänä, jonka koko on 7 (itse asiassa se tarkoittaa, että kolme 3x3 jatkuvaa konvoluutiota vastaa 7x7 konvoluutiota), ja sen Kokonaisparametrit ovat Määrä on 3x(9xC^2), jos käytetään suoraan 7x7 konvoluutioydintä, parametrien kokonaismäärä on 49xC^2, jossa C viittaa tulo- ja lähtökanavien määrään.Ilmeisesti 27xC2 alle 49xC2, eli parametrit pienenevät ja 3x3-konvoluutioydin edistää kuvan ominaisuuksien parempaa ylläpitämistä.

Tässä on selitys, miksi kahta 3x3-konvoluutioytimistä voidaan käyttää 5x5-konvoluutioytimien sijaan:

5x5-konvoluutiota pidetään pienenä täysin kytkettynä verkkona, joka liukuu 5x5-alueella. Voimme ensin konvoloida 3x3-konvoluutiosuodattimella ja sitten käyttää täysin yhdistettyä kerrosta 3x3-konvoluutiolähtöön nähdä 3x3 konvoluutiokerroksena. Tällä tavalla voimme kaskadoida (superposoida) kaksi 3x3 konvoluutiota yhden 5x5 konvoluution sijaan.

Yksityiskohdat näkyvät alla olevassa kuvassa:

Lisää kuvan kuvaus tähän

VGG-verkon rakenne

Lisää kuvan kuvaus tähän

Seuraava on VGG-verkon rakenne (sekä VGG16 että VGG19 ovat olemassa):

Lisää kuvan kuvaus tähän

GG-verkon rakenne

VGG16 sisältää 16 piilotettua kerrosta (13 konvoluutiokerrosta ja 3 täysin yhdistettyä kerrosta), kuten yllä olevan kuvan sarakkeessa D näkyy

VGG19 sisältää 19 piilotettua kerrosta (16 konvoluutiotasoa ja 3 täysin yhdistettyä kerrosta), kuten yllä olevan kuvan sarakkeessa E näkyy

VGG-verkon rakenne on hyvin johdonmukainen, ja se käyttää 3x3 konvoluutiota ja 2x2 max poolausta alusta loppuun.

VGG:n edut

VGGNetin rakenne on hyvin yksinkertainen. Koko verkko käyttää samaa konvoluutioytimen kokoa (3x3) ja maksimipoolauskokoa (2x2).

Usean pienen suodattimen (3x3) konvoluutiokerroksen yhdistelmä on parempi kuin yksi suuri suodatin (5x5 tai 7x7) konvoluutiokerros:

On todennettu, että suorituskykyä voidaan parantaa jatkuvasti syventämällä verkkorakennetta.

VGG:n huonot puolet

VGG kuluttaa enemmän laskentaresursseja ja käyttää enemmän parametreja (tämä ei ole 3x3-konvoluutiopotti), mikä johtaa enemmän muistin käyttöön (140M).

Tietojoukon käsittely

Tietojoukon esittely

CIFAR (Canadian Institute For Advanced Research) -tietojoukko on pieni kuvatietojoukko, jota käytetään laajalti tietokonenäön alalla. Sitä käytetään pääasiassa koneoppimisen ja tietokonenäköalgoritmien koulutukseen, erityisesti sellaisissa tehtävissä kuin kuvantunnistus ja luokittelu. CIFAR-tietosarja koostuu kahdesta pääosasta: CIFAR-10 ja CIFAR-100.

CIFAR-10 on tietojoukko, joka sisältää 60 000 32x32 värikuvaa, jotka on jaettu 10 luokkaan, joista jokainen sisältää 6 000 kuvaa. 10 luokkaa ovat: lentokoneet, autot, linnut, kissat, peurat, koirat, sammakot, hevoset, veneet ja kuorma-autot. Aineistossa 50 000 kuvaa käytetään harjoitteluun ja 10 000 kuvaa testaukseen. CIFAR-10-tietojoukosta on tullut yksi suosituimmista tietokokonaisuuksista tietokonenäön alan tutkimuksessa ja opetuksessa sen kohtuullisen kokonsa ja runsaan luokkatietonsa vuoksi.

Tietojoukon ominaisuudet
  • keskikokoinen: CIFAR-tietojoukon pieni kuvakoko (32x32) tekee niistä ihanteellisia nopeaan koulutukseen ja uusien tietokonenäköalgoritmien testaamiseen.
  • Erilaisia ​​luokkia: CIFAR-10 tarjoaa peruskuvan luokittelutehtävät, kun taas CIFAR-100 haastaa edelleen algoritmin hienorakeiset luokitusominaisuudet.
  • laajasti käytetty: Näiden ominaisuuksien vuoksi CIFAR-tietojoukkoa käytetään laajasti tietokonenäön, koneoppimisen, syväoppimisen ja muiden alojen tutkimuksessa ja opetuksessa.
käytettävät kohtaukset

CIFAR-tietojoukkoa käytetään yleisesti tehtäviin, kuten kuvien luokitteluun, objektien tunnistamiseen sekä konvoluutiohermoverkkojen (CNN) koulutukseen ja testaamiseen. Kohtuullisen kokonsa ja monipuolisen luokkatietonsa ansiosta se on ihanteellinen aloittelijoille ja tutkijoille, jotka tutkivat kuvantunnistusalgoritmeja. Lisäksi monet tietokonenäkö- ja koneoppimiskilpailut käyttävät CIFAR-tietoaineistoa vertailukohtana kilpailijoiden algoritmien suorituskyvyn arvioinnissa.

Tietojoukon valmistelemiseksi olen jo ladannut sen. Jos se ei toimi, lataa se vain viralliselta verkkosivustolta tai annan sen sinulle suoraan.

Jos tarvitset tietojoukon, ota yhteyttä sähköpostitse: [email protected]

Tietojoukkoni luotiin alun perin torchvisionissa ladattujen tietojen avulla. En halua tehdä sitä nyt. Haluan toteuttaa tietojoukon määrittelyn ja DataLoaderin latauksen vaihe vaiheelta, ymmärtää tämän prosessin ja ymmärtää. Tietojoukon käsittelyprosessi voi tehdä sinusta syvällisemmän oppimisen.

Tietojoukon tyyli on seuraava:

Lisää kuvan kuvaus tähän

Jäsennä kaikki tietojoukon tunnisteet

Tietojoukon tunnisteluokka käyttää a.metaTiedosto on tallennettu, joten meidän on jäsennettävä .meta tiedosto lukeaksesi kaikki tunnistetiedot. Jäsennyskoodi on seuraava:

# 首先了解所有的标签,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

Analyysin tulokset ovat seuraavat:

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

Lataa yksi tietoerä tietojen yksinkertaista testausta varten

Tietojoukkomme on ladattu, joten meidän on luettava tiedoston sisältö Koska tiedosto on binääritiedosto, meidän on käytettävä binaarilukutilaa sen lukemiseen.

Lukukoodi on seuraava:

# 载入单个批次的数据
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

tulos:

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

Lataa kaikki tiedot

Yllä olevan testin jälkeen tiedämme kuinka ladata tiedot. Ladataan nyt kaikki tiedot.

Harjoitussarjan lataus:

# 整合所有批次的数据
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

Lähtö:

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

Testisarjan lataus:

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

Lähtö:

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

Määritä tietojoukon alaluokka

Dataset-luokan alaluokan määrittäminen helpottaa Dataloaderin myöhempää lataamista eräopetusta varten.

Tietojoukon alaluokkien on otettava käyttöön kolme menetelmää.

  • __init__()luokan rakentaja
  • __len__()Palauttaa tietojoukon pituuden
  • __getitem__()Hanki osa datasta tietojoukosta

Tässä toteutukseni on seuraava:

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

Lataa tietojoukko Dataloaderina

  1. Määrittele muunnos tietojen parantamiseksi. Harjoitusjoukko on laajennettava 4 kuvapisteellä, normalisoitava, käännettävä vaakasuunnassa, käsiteltävä harmaasävy ja lopuksi palautettava alkuperäiseen pikseliin.
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. Koska se sisältää kuvankäsittelyn ja binääritiedostosta lukemamme tiedot ovat numpy-tietoja, meidän on muutettava numpy-taulukko kuvatiedoiksi kuvankäsittelyn helpottamiseksi. Prosessi seuraavasti:
# 把数据集变成 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. Hanki koulutettu tiedonlataaja
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. Test dataloader -testisarjan saaminen ei vaadi liikaa käsittelyä Koodi annetaan suoraan tässä.
# 测试集的预处理
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

Määritä verkko

Toteutamme Pytorch-kehyksen, joka perustuu edellä mainittuun VGG16-verkkoon.

pääosin jaettu:

  • konvoluutiokerros
  • Täysin yhdistetty kerros
  • luokituskerros

Toteutus on seuraava:

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

koulutusta ja testausta

Koulutusta ja testausta varten sinun tarvitsee vain instantoida malli, määrittää sitten optimointifunktio, häviöfunktio ja hävikkisuhde ja suorittaa koulutus ja testaus.

koodi näytetään alla:

Hyperparametrin määritelmä:

# 定义模型进行训练
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

Testitoiminto:

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

Harjoittelun aikakaudet:

# 定义训练步骤
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

Tallenna koulutettu malli:

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

testata

  1. Määrittele malli
model_my_vgg = VGG16()
  • 1
  1. Lisää koulutetut mallitiedot
model_my_vgg.load_state_dict(torch.load('./my-VGG16-best.pth',map_location='cpu'))
  • 1
  1. Käsittelen löytämiäni vahvistuskuvia
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

Lähtö:

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. Tulosta tulokset
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

Lisää kuvan kuvaus tähän

Tarkista hevonen

Lisää kuvan kuvaus tähän

varmistuskoira

Lisää kuvan kuvaus tähän