Κοινή χρήση τεχνολογίας

Το VGG16 υλοποιεί την εφαρμογή pytorch της ταξινόμησης εικόνων και εξηγεί τα βήματα λεπτομερώς

2024-07-12

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

Το VGG16 εφαρμόζει ταξινόμηση εικόνων

Εδώ υλοποιούμε ένα δίκτυο VGG-16 για την ταξινόμηση του συνόλου δεδομένων CIFAR

Εισαγωγή δικτύου VGG16

Πρόλογος

《Πολύ βαθιά συνελικτικά δίκτυα για αναγνώριση εικόνας μεγάλης κλίμακας》

ICLR 2015

VGGΕίναι από την ΟξφόρδηVείναι συνήθωςσοληομετρίασολ Προτείνεται από την ομάδα του roup (θα πρέπει να μπορείτε να δείτε την προέλευση του ονόματος VGG). Αυτό το δίκτυο είναι σχετική εργασία στο ILSVRC 2014. Η κύρια εργασία είναι να αποδειχθεί ότι η αύξηση του βάθους του δικτύου μπορεί να επηρεάσει την τελική απόδοση του δικτύου σε κάποιο βαθμό. Το VGG έχει δύο δομές, δηλαδή το VGG16 και το VGG19 Δεν υπάρχει ουσιαστική διαφορά μεταξύ των δύο, αλλά το βάθος του δικτύου είναι διαφορετικό.

Αρχή VGG

Μια βελτίωση του VGG16 σε σύγκριση με το AlexNet είναι αυτήΧρησιμοποιήστε πολλούς διαδοχικούς πυρήνες συνέλιξης 3x3 για να αντικαταστήσετε τους μεγαλύτερους πυρήνες συνέλιξης στο AlexNet (11x11, 7x7, 5x5) . Για ένα δεδομένο δεκτικό πεδίο (το τοπικό μέγεθος της εικόνας εισόδου σε σχέση με την έξοδο), η χρήση στοιβαγμένων μικρών πυρήνων συνέλιξης είναι καλύτερη από τη χρήση μεγάλων πυρήνων συνέλιξης, επειδή πολλαπλά μη γραμμικά επίπεδα μπορούν να αυξήσουν το βάθος του δικτύου για να εξασφαλίσουν πιο σύνθετη λειτουργία εκμάθησης το κόστος είναι σχετικά μικρό (λιγότερες παράμετροι).

Για να το θέσω απλά, στο VGG, τρεις πυρήνες συνέλιξης 3x3 χρησιμοποιούνται για να αντικαταστήσουν τον πυρήνα συνέλιξης 7x7 και δύο πυρήνες συνέλιξης 3x3 χρησιμοποιούνται για να αντικαταστήσουν τον πυρήνα συνέλιξης 5*5. Ο κύριος σκοπός αυτού είναι να διασφαλιστεί η ίδια υπό την προϋπόθεση του δεκτικού πεδίου, το βάθος του δικτύου βελτιώνεται και η επίδραση του νευρωνικού δικτύου βελτιώνεται σε κάποιο βαθμό.

Για παράδειγμα, η υπέρθεση στρώμα προς στρώμα τριών πυρήνων συνέλιξης 3x3 με διασκελισμό 1 μπορεί να θεωρηθεί ως δεκτικό πεδίο μεγέθους 7 (στην πραγματικότητα, σημαίνει ότι τρεις συνεχείς συνέλιξεις 3x3 ισοδυναμούν με μια συνέλιξη 7x7) και Οι συνολικές παράμετροι είναι Το ποσό είναι 3x(9xC^2).Προφανώς, 27xC2 λιγότερο από 49xC2, δηλαδή, οι παράμετροι μειώνονται και ο πυρήνας συνέλιξης 3x3 συμβάλλει στην καλύτερη διατήρηση των ιδιοτήτων της εικόνας.

Ακολουθεί μια εξήγηση για το γιατί μπορούν να χρησιμοποιηθούν δύο πυρήνες συνέλιξης 3x3 αντί για πυρήνες συνέλιξης 5*5:

Η συνέλιξη 5x5 θεωρείται ως ένα μικρό πλήρως συνδεδεμένο δίκτυο που ολισθαίνει στην περιοχή 5x5 να θεωρηθεί ως ένα συνελικτικό στρώμα 3x3. Με αυτόν τον τρόπο, μπορούμε να καταρρεύσουμε (υπερθέτουμε) δύο συνέλιξεις 3x3 αντί για μία συνέλιξη 5x5.

Οι λεπτομέρειες φαίνονται στο παρακάτω σχήμα:

Εισαγάγετε την περιγραφή της εικόνας εδώ

Δομή δικτύου VGG

Εισαγάγετε την περιγραφή της εικόνας εδώ

Ακολουθεί η δομή του δικτύου VGG (υπάρχουν και τα δύο VGG16 και VGG19):

Εισαγάγετε την περιγραφή της εικόνας εδώ

Δομή δικτύου GG

Το VGG16 περιέχει 16 κρυφά επίπεδα (13 συνελικτικά επίπεδα και 3 πλήρως συνδεδεμένα επίπεδα), όπως φαίνεται στη στήλη D στο παραπάνω σχήμα

Το VGG19 περιέχει 19 κρυφά επίπεδα (16 συνελικτικά επίπεδα και 3 πλήρως συνδεδεμένα επίπεδα), όπως φαίνεται στη στήλη Ε στο παραπάνω σχήμα

Η δομή του δικτύου VGG είναι πολύ συνεπής, χρησιμοποιώντας συνέλιξη 3x3 και συγκέντρωση 2x2 max από την αρχή μέχρι το τέλος.

Πλεονεκτήματα του VGG

Η δομή του VGGNet είναι πολύ απλή. Ολόκληρο το δίκτυο χρησιμοποιεί το ίδιο μέγεθος πυρήνα συνέλιξης (3x3) και μέγιστο μέγεθος συγκέντρωσης (2x2).

Ο συνδυασμός πολλών μικρών συνελικτικών στρωμάτων φίλτρου (3x3) είναι καλύτερος από ένα μεγάλο συνελικτικό στρώμα φίλτρου (5x5 ή 7x7):

Επαληθεύεται ότι η απόδοση μπορεί να βελτιωθεί με τη συνεχή εμβάθυνση της δομής του δικτύου.

Μειονεκτήματα του VGG

Το VGG καταναλώνει περισσότερους υπολογιστικούς πόρους και χρησιμοποιεί περισσότερες παραμέτρους (αυτό δεν είναι το pot της συνέλιξης 3x3), με αποτέλεσμα περισσότερη χρήση μνήμης (140M).

Επεξεργασία συνόλων δεδομένων

Εισαγωγή συνόλου δεδομένων

Το σύνολο δεδομένων CIFAR (Canadian Institute For Advanced Research) είναι ένα μικρό σύνολο δεδομένων εικόνων που χρησιμοποιείται ευρέως στον τομέα της όρασης υπολογιστών. Χρησιμοποιείται κυρίως για την εκπαίδευση αλγορίθμων μηχανικής μάθησης και όρασης υπολογιστών, ειδικά σε εργασίες όπως η αναγνώριση και ταξινόμηση εικόνων. Το σύνολο δεδομένων CIFAR αποτελείται από δύο κύρια μέρη: CIFAR-10 και CIFAR-100.

Το CIFAR-10 είναι ένα σύνολο δεδομένων που περιέχει 60.000 έγχρωμες εικόνες 32x32, οι οποίες χωρίζονται σε 10 κατηγορίες, με κάθε κατηγορία να περιέχει 6.000 εικόνες. Οι 10 κατηγορίες είναι: αεροπλάνα, αυτοκίνητα, πουλιά, γάτες, ελάφια, σκύλοι, βάτραχοι, άλογα, βάρκες και φορτηγά. Στο σύνολο δεδομένων, 50.000 εικόνες χρησιμοποιούνται για εκπαίδευση και 10.000 εικόνες για δοκιμή. Το σύνολο δεδομένων CIFAR-10 έχει γίνει ένα από τα πολύ δημοφιλή σύνολα δεδομένων στην έρευνα και τη διδασκαλία στον τομέα της όρασης υπολογιστών λόγω του μέτριου μεγέθους και των πλούσιων πληροφοριών τάξης.

Χαρακτηριστικά συνόλου δεδομένων
  • μεσαίο μέγεθος: Το μικρό μέγεθος εικόνας του συνόλου δεδομένων CIFAR (32x32) τα καθιστά ιδανικά για γρήγορη εκπαίδευση και δοκιμή νέων αλγορίθμων όρασης υπολογιστή.
  • Διάφορες κατηγορίες: Το CIFAR-10 παρέχει βασικές εργασίες ταξινόμησης εικόνων, ενώ το CIFAR-100 αμφισβητεί περαιτέρω τις λεπτομερείς δυνατότητες ταξινόμησης του αλγορίθμου.
  • ευρέως χρησιμοποιημένο: Λόγω αυτών των χαρακτηριστικών, το σύνολο δεδομένων CIFAR χρησιμοποιείται ευρέως στην έρευνα και τη διδασκαλία στην όραση υπολογιστών, τη μηχανική μάθηση, τη βαθιά μάθηση και άλλους τομείς.
σκηνές που θα χρησιμοποιηθούν

Το σύνολο δεδομένων CIFAR χρησιμοποιείται συνήθως για εργασίες όπως η ταξινόμηση εικόνων, η αναγνώριση αντικειμένων και η εκπαίδευση και η δοκιμή συνελικτικών νευρωνικών δικτύων (CNN). Λόγω του μέτριου μεγέθους και των πλούσιων πληροφοριών κατηγορίας, είναι ιδανικό για αρχάριους και ερευνητές που εξερευνούν αλγόριθμους αναγνώρισης εικόνων. Επιπλέον, πολλοί διαγωνισμοί υπολογιστικής όρασης και μηχανικής μάθησης χρησιμοποιούν επίσης το σύνολο δεδομένων CIFAR ως σημείο αναφοράς για την αξιολόγηση της απόδοσης των αλγορίθμων των διαγωνιζομένων.

Για να προετοιμάσω το σύνολο δεδομένων, το έχω ήδη κατεβάσει εάν δεν λειτουργεί, απλώς κατεβάστε το από τον επίσημο ιστότοπο, διαφορετικά θα σας το δώσω απευθείας.

Εάν χρειάζεστε το σύνολο δεδομένων, επικοινωνήστε με το email: [email protected]

Το σύνολο δεδομένων μου δημιουργήθηκε αρχικά μέσω των ληφθέντων δεδομένων στο torchvision. Δεν θέλω πραγματικά να το κάνω τώρα. Θέλω να εφαρμόσω τον ορισμό του συνόλου δεδομένων και τη φόρτωση του DataLoader βήμα προς βήμα, να κατανοήσω αυτήν τη διαδικασία. η διαδικασία επεξεργασίας συνόλων δεδομένων μπορεί να σας κάνει πιο εμπεριστατωμένους στη βαθιά μάθηση.

Το στυλ συνόλου δεδομένων έχει ως εξής:

Εισαγάγετε την περιγραφή της εικόνας εδώ

Αναλύστε όλες τις ετικέτες του συνόλου δεδομένων

Η κατηγορία ετικέτας του συνόλου δεδομένων χρησιμοποιεί α.metaΤο αρχείο είναι αποθηκευμένο, επομένως πρέπει να αναλύσουμε .meta αρχείο για ανάγνωση όλων των δεδομένων ετικετών. Ο κώδικας ανάλυσης είναι ο εξής:

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

Τα αποτελέσματα της ανάλυσης έχουν ως εξής:

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

Φορτώστε μία μόνο παρτίδα δεδομένων για απλή δοκιμή των δεδομένων

Το σύνολο δεδομένων μας έχει ληφθεί, επομένως πρέπει να διαβάσουμε τα περιεχόμενα του αρχείου Δεδομένου ότι το αρχείο είναι δυαδικό αρχείο, πρέπει να χρησιμοποιήσουμε τη λειτουργία δυαδικής ανάγνωσης για να το διαβάσουμε.

Ο κώδικας ανάγνωσης είναι ο εξής:

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

αποτέλεσμα:

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

Φόρτωση όλων των δεδομένων

Μετά την παραπάνω δοκιμή, ξέρουμε πώς να φορτώνουμε δεδομένα Τώρα ας φορτώσουμε όλα τα δεδομένα.

Φόρτωση του σετ εκπαίδευσης:

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

Παραγωγή:

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

Φόρτωση του συνόλου δοκιμής:

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

Παραγωγή:

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

Ορίστε μια υποκλάση του συνόλου δεδομένων

Ο καθορισμός μιας υποκλάσης της κλάσης συνόλου δεδομένων είναι για να διευκολυνθεί η επακόλουθη φόρτωση του Dataloader για ομαδική εκπαίδευση.

Υπάρχουν τρεις μέθοδοι που πρέπει να εφαρμόσουν οι υποκλάσεις του συνόλου δεδομένων.

  • __init__()κατασκευαστής τάξης
  • __len__()Επιστρέφει το μήκος του συνόλου δεδομένων
  • __getitem__()Λάβετε ένα κομμάτι δεδομένων από το σύνολο δεδομένων

Εδώ η εφαρμογή μου έχει ως εξής:

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

Φορτώστε το σύνολο δεδομένων ως Dataloader

  1. Ορίστε έναν μετασχηματισμό για να βελτιώσετε τα δεδομένα Εδώ είναι πρώτα το σύνολο εκπαίδευσης.
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. Επειδή περιλαμβάνει επεξεργασία εικόνας και τα δεδομένα που διαβάζουμε από το δυαδικό αρχείο είναι numpy δεδομένα, πρέπει να μετατρέψουμε τον numpy πίνακα σε δεδομένα εικόνας για να διευκολύνουμε την επεξεργασία εικόνας. Διαδικασία ως εξής:
# 把数据集变成 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. Αποκτήστε το εκπαιδευμένο πρόγραμμα φόρτωσης δεδομένων
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. Η απόκτηση του δοκιμαστικού σετ φόρτωσης δεδομένων δεν απαιτεί υπερβολική επεξεργασία Ο κωδικός δίνεται απευθείας εδώ.
# 测试集的预处理
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

Ορισμός δικτύου

Υλοποιούμε το πλαίσιο Pytorch με βάση το δίκτυο VGG16 που αναφέρθηκε παραπάνω.

κυρίως διαιρείται:

  • στρώμα συνέλιξης
  • Πλήρως συνδεδεμένο στρώμα
  • στρώμα ταξινόμησης

Η υλοποίηση έχει ως εξής:

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

εκπαίδευση και δοκιμές

Για εκπαίδευση και δοκιμή, χρειάζεται μόνο να δημιουργήσετε το μοντέλο, στη συνέχεια να ορίσετε τη συνάρτηση βελτιστοποίησης, τη συνάρτηση απώλειας και το ποσοστό απώλειας και, στη συνέχεια, να εκτελέσετε εκπαίδευση και δοκιμή.

ο κώδικας εμφανίζεται ως εξής:

Ορισμός υπερπαραμέτρου:

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

Λειτουργία δοκιμής:

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

Εποχές εκπαίδευσης:

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

Αποθηκεύστε το εκπαιδευμένο μοντέλο:

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

δοκιμή

  1. Ορίστε το μοντέλο
model_my_vgg = VGG16()
  • 1
  1. Προσθήκη εκπαιδευμένων δεδομένων μοντέλου
model_my_vgg.load_state_dict(torch.load('./my-VGG16-best.pth',map_location='cpu'))
  • 1
  1. Επεξεργάζομαι τις εικόνες επαλήθευσης που βρήκα
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

Παραγωγή:

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. Εκτύπωση αποτελεσμάτων
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

Εισαγάγετε την περιγραφή της εικόνας εδώ

Επαληθεύστε το άλογο

Εισαγάγετε την περιγραφή της εικόνας εδώ

σκύλος επαλήθευσης

Εισαγάγετε την περιγραφή της εικόνας εδώ