<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          PyTorch 實戰(zhàn)之水果分類器

          共 19749字,需瀏覽 40分鐘

           ·

          2021-06-13 16:28

          點擊下面卡片關(guān)注,”AI算法與圖像處理

          最新CV成果,火速送達(dá)

          當(dāng)我們試圖提高神經(jīng)網(wǎng)絡(luò)的準(zhǔn)確性時,經(jīng)常會遇到過擬合訓(xùn)練數(shù)據(jù)的情況。當(dāng)我們運行測試數(shù)據(jù)的模型時,這會導(dǎo)致一個糟糕的預(yù)測。因此,我采取了一個數(shù)據(jù)集,并應(yīng)用這些技術(shù),不僅提高準(zhǔn)確性,而且還處理過擬合的問題。


          在本文中,我們將使用以下技術(shù)在不到5分鐘的時間內(nèi)訓(xùn)練一個最先進(jìn)的模型,以達(dá)到從 Fruit 360數(shù)據(jù)集中分類圖像的95% 以上的準(zhǔn)確率:


          1. 數(shù)據(jù)增強


          數(shù)據(jù)分析中的數(shù)據(jù)增強是通過對現(xiàn)有數(shù)據(jù)或從現(xiàn)有數(shù)據(jù)中新創(chuàng)建的合成數(shù)據(jù)進(jìn)行稍加修改的“副本”來增加數(shù)據(jù)量的技術(shù)。在訓(xùn)練機器學(xué)習(xí)模型時,它起到調(diào)節(jié)器的作用,有助于減少過擬合。


          1. 批量歸一化


          批量歸一化是一種訓(xùn)練非常深入的神經(jīng)網(wǎng)絡(luò)的技術(shù),它標(biāo)準(zhǔn)化每個小批量的輸入到一個層。這有助于穩(wěn)定學(xué)習(xí)過程,大大減少訓(xùn)練深層網(wǎng)絡(luò)所需的訓(xùn)練時期。


          1. 學(xué)習(xí)率策略


          學(xué)習(xí)率策略用于尋求調(diào)整學(xué)習(xí)率在訓(xùn)練期間通過降低學(xué)習(xí)率根據(jù)預(yù)先確定的調(diào)度器。常見的學(xué)習(xí)率策略包括基于時間的衰減,階躍衰減和指數(shù)衰減。


          1. 權(quán)重衰減


          我們使用權(quán)重衰減來保持較小的權(quán)重值,避免梯度爆炸。因為權(quán)重值將會經(jīng)過L2標(biāo)準(zhǔn)化后加入到損失中,你的網(wǎng)絡(luò)的每次迭代除了損失之外都會試圖優(yōu)化/最小化模型權(quán)重。這將有助于保持盡可能小的權(quán)重值,防止權(quán)重增長失控,從而避免梯度爆炸。


          1.  梯度裁剪

           

          使用梯度裁剪可以防止梯度在神經(jīng)網(wǎng)絡(luò)中爆炸。梯度裁剪限制梯度的大小。計算梯度裁剪的方法有很多種,但一種常見的方法是重新調(diào)整梯度。


          1. Adam 優(yōu)化器


          這一系列的優(yōu)化器被引入來解決梯度下降法的算法問題。它們最重要的特點是不需要調(diào)整學(xué)習(xí)率值。實際上,有些庫ーー例如 Keras ーー仍然可以讓您手動調(diào)整它,以便進(jìn)行更高級的試驗。


          關(guān)于數(shù)據(jù)集


          水果在當(dāng)今世界非常普遍ーー盡管有大量的快餐和精制食品,但水果仍然是人們廣泛食用的食物。舉個例子,在水果的生產(chǎn)過程中,可能需要對它們進(jìn)行分類。傳統(tǒng)上被機械地執(zhí)行,今天,基于深度學(xué)習(xí)的技術(shù)可以增強甚至接管這個過程。


          目錄


          1. 引言

          2. 數(shù)據(jù)預(yù)處理

          3. 探索數(shù)據(jù)集

          4. 應(yīng)用數(shù)據(jù)增強

          5. 訪問少量樣本圖片

          6. 訪問 GPU

          7. 配置模型

          8. 模型訓(xùn)練及成果

          9. 預(yù)測

          10. 摘要


          1. 引言


          圖片總數(shù):90483。


          訓(xùn)練集大小:67692圖像(每圖像一個水果或蔬菜)。


          測試集大小:22688圖像(每張圖像一個水果或蔬菜)。


          類別數(shù)目:131(水果和蔬菜)。


          圖像大小:100x100像素。


          同一種水果的不同品種(例如蘋果)屬于不同的類別。


          2. 數(shù)據(jù)預(yù)處理


          導(dǎo)入所需的庫


          因為我們使用 PyTorch 來構(gòu)建神經(jīng)網(wǎng)絡(luò),所以我一次性導(dǎo)入所有相關(guān)的庫。

          import osimport torchimport torchvisionimport tarfileimport torch.nn as nnimport numpy as npimport torch.nn.functional as Ffrom torchvision.datasets.utils import download_urlfrom torchvision.datasets import ImageFolderfrom torch.utils.data import DataLoaderfrom torchvision.transforms import ToTensorimport torchvision.transforms as ttfrom torch.utils.data import random_splitfrom torchvision.utils import make_gridimport matplotlibimport matplotlib.pyplot as plt%matplotlib inline
          import warningswarnings.filterwarnings("ignore")

          下載數(shù)據(jù)集

          # Upload kaggle.jason# please follow this link incase not aware: https://www.kaggle.com/general/74235from google.colab import filesfiles.upload()
          ! pip install opendatasets --upgradeimport opendatasets as od
          dataset_url = 'https://www.kaggle.com/moltean/fruits'od.download(dataset_url)

          在運行任何探索之前,數(shù)據(jù)集必須加載到 DataLoader。我們使用 PyTorch 的 ImageFolder 將圖像加載到 DataLoader。


          3. 探索數(shù)據(jù)集

          問: 訓(xùn)練和測試數(shù)據(jù)集包含多少圖像?

          dataset_size = len(train_dataset)test_dataset_size = len(test_dataset)print(train_dataset)print(test_dataset)

          輸出:

          Dataset ImageFolder    Number of datapoints: 67692    Root location: /content/fruits/fruits-360/Training    StandardTransformTransform: ToTensor()Dataset ImageFolder    Number of datapoints: 22688    Root location: /content/fruits/fruits-360/Test    StandardTransformTransform: ToTensor()

          問:數(shù)據(jù)集包含多少個輸出類?

          # Accesssing the classesdata_dir = '/content/fruits/fruits-360/'
          # print(os.listdir(data_dir))classes = os.listdir(data_dir + "Training")print(f'Total Number of Classe {len(classes)}')print(f'Classes Names: {classes}')

          輸出:

          Total Number of Classe 131Classes Names: ['Apple Braeburn', 'Cherry Wax Red', 'Melon Piel de Sapo', 'Rambutan', 'Tamarillo', 'Pepino', 'Lemon', 'Tomato Cherry Red', 'Apple Golden 1', 'Peach Flat', 'Apple Red Delicious', 'Lemon Meyer', 'Banana Red', 'Orange', 'Peach 2', 'Pepper Red', 'Grape White', 'Kaki', 'Pepper Yellow', 'Salak', 'Potato White', 'Cucumber Ripe 2', 'Apple Golden 2', 'Pitahaya Red', 'Mulberry', 'Carambula', 'Pear Abate', 'Banana', 'Tomato Maroon', 'Pear Red', 'Pear Forelle', 'Pineapple', 'Ginger Root', 'Potato Red', 'Apple Pink Lady', 'Pear Kaiser', 'Mandarine', 'Strawberry', 'Apple Golden 3', 'Nectarine', 'Plum 3', 'Avocado ripe', 'Cantaloupe 2', 'Fig', 'Tomato 1', 'Tomato Heart', 'Passion Fruit', 'Grape Blue', 'Cantaloupe 1', 'Apple Granny Smith', 'Banana Lady Finger', 'Mango Red', 'Cherry Rainier', 'Corn Husk', 'Hazelnut', 'Pear', 'Cauliflower', 'Pear Williams', 'Tangelo', 'Avocado', 'Physalis', 'Chestnut', 'Onion White', 'Granadilla', 'Strawberry Wedge', 'Plum 2', 'Plum', 'Pepper Green', 'Tomato 3', 'Grape White 4', 'Quince', 'Maracuja', 'Apple Red 1', 'Grapefruit White', 'Cherry 1', 'Walnut', 'Grape White 2', 'Cactus fruit', 'Grape Pink', 'Potato Red Washed', 'Apple Red Yellow 1', 'Cherry 2', 'Pear 2', 'Huckleberry', 'Guava', 'Apple Red 2', 'Beetroot', 'Limes', 'Kiwi', 'Tomato 2', 'Pear Stone', 'Grapefruit Pink', 'Peach', 'Mango', 'Nut Forest', 'Cherry Wax Yellow', 'Eggplant', 'Clementine', 'Pear Monster', 'Nectarine Flat', 'Pepper Orange', 'Onion Red Peeled', 'Cocos', 'Grape White 3', 'Redcurrant', 'Dates', 'Tomato Yellow', 'Pomegranate', 'Pineapple Mini', 'Pomelo Sweetie', 'Papaya', 'Corn', 'Cucumber Ripe', 'Onion Red', 'Nut Pecan', 'Potato Sweet', 'Cherry Wax Black', 'Physalis with Husk', 'Mangostan', 'Tomato not Ripened', 'Tomato 4', 'Apricot', 'Kumquats', 'Apple Red Yellow 2', 'Kohlrabi', 'Lychee', 'Apple Crimson Snow', 'Blueberry', 'Raspberry', 'Watermelon', 'Apple Red 3']

          問: 數(shù)據(jù)集中的圖像張量的形狀是什么?

          img, label = train_dataset[0]img_shape = img.shapeimg_shape

          輸出:

          torch.Size([3, 100, 100])

          讓我們打印一個示例圖像及其類和標(biāo)簽。

          img, label = train_dataset[0]plt.imshow(img.permute((1, 2, 0)))print('Label (numeric):', label)print('Label (textual):', classes[label])

          輸出:

          問: 你能確定屬于每個類別的圖像數(shù)量嗎?

          dataset_size = len(train_dataset)classes = train_dataset.classesnum_classes = len(train_dataset.classes)
          img_dict = {}for i in range(num_classes): img_dict[classes[i]] = 0 for i in range(dataset_size): img, label = train_dataset[i] img_dict[classes[label]] += 1

          ## Plotting classes along with images info
          from matplotlib import pyplot as plt
          fig, ax = plt.subplots(figsize =(16, 32))
          ax.barh(list(img_dict.keys()), list(img_dict.values()))


          # Add Plot Titleax.set_title('Each Class along with their values', loc ='left', )
          # Add annotation to barsfor i in ax.patches: plt.text(i.get_width()+0.2, i.get_y()+0.5, str(round((i.get_width()), 2)), fontsize = 10, fontweight ='bold', color ='grey')
          # Add Text watermarkfig.text(0.9, 0.15, 'gurjeet333', fontsize = 12, color ='grey', ha ='right', va ='bottom', alpha = 0.7)plt.show()

          4. 應(yīng)用數(shù)據(jù)增強


          構(gòu)建數(shù)據(jù)轉(zhuǎn)換


          我們將首先編寫轉(zhuǎn)換函數(shù),以便實現(xiàn)數(shù)據(jù)增強。

          # Data transforms (data augmentation)train_tfms = tt.Compose([                         tt.RandomCrop(100, padding=4, padding_mode='reflect'),                          tt.Resize((100,100)),                         tt.RandomHorizontalFlip(),                          # tt.RandomRotate                         # tt.RandomResizedCrop(256, scale=(0.5,0.9), ratio=(1, 1)),                          # tt.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1),                         tt.ToTensor(), 
          ])valid_tfms = tt.Compose([tt.ToTensor(), tt.Resize((100,100)), ])

          請隨時嘗試其他參數(shù),如 tt.RandomResized,tt.ColorJitter(我在代碼中添加了它們)


          將轉(zhuǎn)換應(yīng)用于數(shù)據(jù)集


          我們構(gòu)建的轉(zhuǎn)換需要應(yīng)用于訓(xùn)練和測試數(shù)據(jù)集。注意:我們不在測試數(shù)據(jù)集中應(yīng)用數(shù)據(jù)增強。

          dataset = ImageFolder(data_dir + "/Training", transform=train_tfms)
          Testing = ImageFolder(data_dir + "/Test", transform=valid_tfms)

          分割數(shù)據(jù)集


          我們將使用來自訓(xùn)練集的20%作為驗證集。為了確保每次獲得相同的驗證集,我們將 PyTorch 的隨機數(shù)生成器設(shè)置種子值為43。

          torch.manual_seed(43)val_size = round(len(dataset) * 0.2)train_size = round(len(dataset) - val_size)
          train_ds, val_ds = random_split(dataset, [train_size, val_size])len(train_ds), len(val_ds)
          batch_size=400
          train_loader = DataLoader(train_ds, batch_size, shuffle=True, num_workers=4, pin_memory=True)val_loader = DataLoader(val_ds, batch_size*2, num_workers=4, pin_memory=True)test_loader = DataLoader(test_dataset, batch_size*2, num_workers=4, pin_memory=True)

          5. 訪問樣本


          讓我們使用來自 Torchvision 的 make_grid 函數(shù)來可視化一批數(shù)據(jù)。

          def show_batch(dl):    for images, labels in dl:        fig, ax = plt.subplots(figsize=(12, 12))        ax.set_xticks([]); ax.set_yticks([])        ax.imshow(make_grid(images, nrow=16).permute(1, 2, 0))        break
          show_batch(train_loader)

          你能通過觀察標(biāo)記所有的圖像嗎?嘗試手動標(biāo)記一個隨機的數(shù)據(jù)樣本是一個很好的方式來估計問題的難度,并識別標(biāo)記錯誤


          6. 使用GPU


          如果你的電腦有連接到 NVIDIA 生產(chǎn)的 GPU 上,你可以使用一個圖形處理器圖形處理器(GPU)來更快地訓(xùn)練你的模型。按照以下說明在你選擇的平臺上使用 GPU:


          • Google Colab:使用菜單選項“ Runtime > Change Runtime Type”,從“ Hardware Accelerator”下拉菜單中選擇“ GPU”

          • Kaggle:在側(cè)邊欄的“設(shè)置”部分,從“ Accelerator”下拉菜單中選擇“ GPU”,使用右上角的按鈕打開側(cè)邊欄

          • Binder:運行在Binder上的代碼不能使用 GPU

          • Linux:如果您的筆記本/臺式機有 NVIDIA GPU (顯卡) ,請確保您已經(jīng)安裝了 NVIDIA CUDA 驅(qū)動程序

          • Windows:如果你的筆記本/臺式機有 NVIDIA GPU (顯卡) ,請確保你已經(jīng)安裝了 NVIDIA CUDA 驅(qū)動程序。

          • macOS:macOS 與 NVIDIA GPU 不兼容

          • 如果你不能訪問 GPU 或者不確定它是什么,不要擔(dān)心,你可以在沒有 GPU 的情況下很好地執(zhí)行本教程中的所有代碼


          讓我們從安裝和導(dǎo)入所需的庫開始。

          def get_default_device():    """Pick GPU if available, else CPU"""    if torch.cuda.is_available():        return torch.device('cuda')    else:        return torch.device('cpu')    def to_device(data, device):    """Move tensor(s) to chosen device"""    if isinstance(data, (list,tuple)):        return [to_device(x, device) for x in data]    return data.to(device, non_blocking=True)
          class DeviceDataLoader(): """Wrap a dataloader to move data to a device""" def __init__(self, dl, device): self.dl = dl self.device = device def __iter__(self): """Yield a batch of data after moving it to device""" for b in self.dl: yield to_device(b, self.device)
          def __len__(self): """Number of batches""" return len(self.dl)

          現(xiàn)在我使用 DeviceDataLoader 函數(shù)將訓(xùn)練和驗證集加載到 GPU 中。

          device = get_default_device()device
          train_dl = DeviceDataLoader(train_loader, device)valid_dl = DeviceDataLoader(val_loader, device)

          7. 配置模型


          設(shè)置精度函數(shù)和圖像基類


          兩者都是通用函數(shù),不需要對任何數(shù)據(jù)集進(jìn)行任何更改。這些是計算精度的輔助函數(shù),并實現(xiàn)損失函數(shù)來計算模型的訓(xùn)練和驗證損失。

          def accuracy(outputs, labels):    _, preds = torch.max(outputs, dim=1)    return torch.tensor(torch.sum(preds == labels).item() / len(preds))

          class ImageClassificationBase(nn.Module): def training_step(self, batch): images, labels = batch out = self(images) # Generate predictions loss = F.cross_entropy(out, labels) # Calculate loss return loss def validation_step(self, batch): images, labels = batch out = self(images) # Generate predictions loss = F.cross_entropy(out, labels) # Calculate loss acc = accuracy(out, labels) # Calculate accuracy return {'val_loss': loss.detach(), 'val_acc': acc} def validation_epoch_end(self, outputs): batch_losses = [x['val_loss'] for x in outputs] epoch_loss = torch.stack(batch_losses).mean() # Combine losses batch_accs = [x['val_acc'] for x in outputs] epoch_acc = torch.stack(batch_accs).mean() # Combine accuracies return {'val_loss': epoch_loss.item(), 'val_acc': epoch_acc.item()} def epoch_end(self, epoch, result): print("Epoch [{}], train_loss: {:.4f}, val_loss: {:.4f}, val_acc: {:.4f}".format(epoch, result['train_loss'], result['val_loss'], result['val_acc']))
          class ImageClassificationBase(nn.Module):    def training_step(self, batch):        images, labels = batch         out = self(images)                  # Generate predictions        loss = F.cross_entropy(out, labels) # Calculate loss        return loss        def validation_step(self, batch):        images, labels = batch         out = self(images)                    # Generate predictions        loss = F.cross_entropy(out, labels)   # Calculate loss        acc = accuracy(out, labels)           # Calculate accuracy        return {'val_loss': loss.detach(), 'val_acc': acc}            def validation_epoch_end(self, outputs):        batch_losses = [x['val_loss'] for x in outputs]        epoch_loss = torch.stack(batch_losses).mean()   # Combine losses        batch_accs = [x['val_acc'] for x in outputs]        epoch_acc = torch.stack(batch_accs).mean()      # Combine accuracies        return {'val_loss': epoch_loss.item(), 'val_acc': epoch_acc.item()}        def epoch_end(self, epoch, result):        print("Epoch [{}], train_loss: {:.4f}, val_loss: {:.4f}, val_acc: {:.4f}".format(epoch, result['train_loss'], result['val_loss'], result['val_acc']))

          實現(xiàn)批量標(biāo)準(zhǔn)化和Dropout


          我們用 nn.Squential 將多層神經(jīng)網(wǎng)絡(luò)鏈接在一起。我在代碼中添加了注釋,以便簡單地理解。注意——在這里我使用 nn.BatchNorm2d 在每一層的末尾實現(xiàn)批量歸一化。

          class Fruit360CnnModel(ImageClassificationBase):    def __init__(self):        super().__init__()        self.network = nn.Sequential(                        nn.Conv2d(3, 16, kernel_size=2, padding=1),             nn.BatchNorm2d(16),            nn.ReLU(),            nn.MaxPool2d(2, 2), # 16 X 50 X 50
          nn.Conv2d(16, 32, kernel_size=2, stride=1, padding=1), nn.BatchNorm2d(32), nn.ReLU(), nn.MaxPool2d(2, 2), # 32 X 25 X 25
          nn.Conv2d(32, 64, kernel_size=2, stride=1, padding=1), nn.BatchNorm2d(64), nn.ReLU(), nn.MaxPool2d(5, 5), # 64 X 5 X 5
          nn.Flatten(), nn.Dropout(0.3), nn.ReLU(), nn.Linear(64*5*5, 131)) def forward(self, xb): return self.network(xb)
          model = Fruit360CnnModel()model

          輸出:

          Fruit360CnnModel(  (network): Sequential(    (0): Conv2d(3, 16, kernel_size=(2, 2), stride=(1, 1), padding=(1, 1))    (1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    (2): ReLU()    (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)    (4): Conv2d(16, 32, kernel_size=(2, 2), stride=(1, 1), padding=(1, 1))    (5): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    (6): ReLU()    (7): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)    (8): Conv2d(32, 64, kernel_size=(2, 2), stride=(1, 1), padding=(1, 1))    (9): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    (10): ReLU()    (11): MaxPool2d(kernel_size=5, stride=5, padding=0, dilation=1, ceil_mode=False)    (12): Flatten(start_dim=1, end_dim=-1)    (13): Dropout(p=0.3, inplace=False)    (14): ReLU()    (15): Linear(in_features=1600, out_features=131, bias=True)  ))

          實現(xiàn)權(quán)重衰減,梯度裁剪,Adam 優(yōu)化

          @torch.no_grad()
          def evaluate(model, val_loader): model.eval() outputs = [model.validation_step(batch) for batch in val_loader] return model.validation_epoch_end(outputs)
          def get_lr(optimizer): for param_group in optimizer.param_groups: return param_group['lr']
          def fit_one_cycle(epochs, max_lr, model, train_loader, val_loader, weight_decay=0, grad_clip=None, opt_func=torch.optim.SGD): torch.cuda.empty_cache() history = [] # Set up cutom optimizer with weight decay optimizer = opt_func(model.parameters(), max_lr, weight_decay=weight_decay) # Set up one-cycle learning rate scheduler sched = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr, epochs=epochs, steps_per_epoch=len(train_loader)) for epoch in range(epochs): # Training Phase model.train() train_losses = [] lrs = [] for batch in train_loader: loss = model.training_step(batch) train_losses.append(loss) loss.backward() # Gradient clipping if grad_clip: nn.utils.clip_grad_value_(model.parameters(), grad_clip) optimizer.step() optimizer.zero_grad() # Record & update learning rate lrs.append(get_lr(optimizer)) sched.step() # Validation phase result = evaluate(model, val_loader) result['train_loss'] = torch.stack(train_losses).mean().item() result['lrs'] = lrs model.epoch_end(epoch, result) history.append(result) return history
          # Moving the model to GPUmodel = to_device(model, device)model

          輸出:

          Fruit360CnnModel(  (network): Sequential(    (0): Conv2d(3, 16, kernel_size=(2, 2), stride=(1, 1), padding=(1, 1))    (1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    (2): ReLU()    (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)    (4): Conv2d(16, 32, kernel_size=(2, 2), stride=(1, 1), padding=(1, 1))    (5): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    (6): ReLU()    (7): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)    (8): Conv2d(32, 64, kernel_size=(2, 2), stride=(1, 1), padding=(1, 1))    (9): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)    (10): ReLU()    (11): MaxPool2d(kernel_size=5, stride=5, padding=0, dilation=1, ceil_mode=False)    (12): Flatten(start_dim=1, end_dim=-1)    (13): Dropout(p=0.3, inplace=False)    (14): ReLU()    (15): Linear(in_features=1600, out_features=131, bias=True)  ))

          模型在訓(xùn)練前的表現(xiàn)似乎很差。正如下面觀察到的,模型的準(zhǔn)確度低于1% ,因為模型試圖隨機猜測輸出。

          os.environ['WANDB_CONSOLE'] = 'off'
          history = [evaluate(model, valid_dl)]history

          輸出:

          [{'val_acc': 0.005484417546540499, 'val_loss': 4.877397537231445}]

          8. 模型訓(xùn)練和結(jié)果分析


          在訓(xùn)練前設(shè)置參數(shù)

          epochs = 4max_lr = 0.01grad_clip = 0.1weight_decay = 1e-4opt_func = torch.optim.Adam

          運行4個epochs

          %%time
          os.environ['WANDB_CONSOLE'] = 'off'
          history += fit_one_cycle(epochs, max_lr, model, train_dl, valid_dl, grad_clip=grad_clip, weight_decay=weight_decay, opt_func=opt_func)

          輸出:

          Epoch [0], train_loss: 1.2414, val_loss: 0.8754, val_acc: 0.7948Epoch [1], train_loss: 0.1211, val_loss: 0.0212, val_acc: 0.9931Epoch [2], train_loss: 0.0101, val_loss: 0.0025, val_acc: 0.9996Epoch [3], train_loss: 0.0049, val_loss: 0.0011, val_acc: 0.9999CPU times: user 11.8 s, sys: 7.95 s, total: 19.8 sWall time: 3min 7

          在4個epoch4分鐘以內(nèi),我們?nèi)〉昧撕芎玫木取?/span>


          Accuracy vs No

          def plot_accuracies(history):    accuracies = [x['val_acc'] for x in history]    plt.plot(accuracies, '-x')    plt.xlabel('epoch')    plt.ylabel('accuracy')    plt.title('Accuracy vs. No. of epochs');
          plot_accuracies(history)

          Loss vs epochs

          def plot_losses(history):    train_losses = [x.get('train_loss') for x in history]    val_losses = [x['val_loss'] for x in history]    plt.plot(train_losses, '-bx')    plt.plot(val_losses, '-rx')    plt.xlabel('epoch')    plt.ylabel('loss')    plt.legend(['Training', 'Validation'])    plt.title('Loss vs. No. of epochs');
          plot_losses(history)

          由于訓(xùn)練和驗證的損失不是發(fā)散的,而是逐漸收斂的,這表明我們沒有過度擬合我們的模型。


          學(xué)習(xí)率

          def plot_lrs(history):    lrs = np.concatenate([x.get('lrs', []) for x in history])    plt.plot(lrs)    plt.xlabel('Batch no.')    plt.ylabel('Learning rate')    plt.title('Learning Rate vs. Batch no.');

          正如預(yù)期的那樣,學(xué)習(xí)率開始于一個較低的值,并且在30% 的迭代中逐漸增加到最大值0.01,然后逐漸降低到一個非常小的值。


          9. 預(yù)測


          讓我們在測試數(shù)據(jù)集上進(jìn)行模型預(yù)測

          test_tfms = tt.Compose([tt.Resize((100, 100)),                         tt.ToTensor()])test_dataset = ImageFolder(data_dir + "Test", transform=test_tfms)test_loader = DeviceDataLoader(DataLoader(test_dataset, batch_size), device)result = evaluate(model, test_loader)result

          輸出:

          {'val_acc': 0.9883334040641785, 'val_loss': 0.08684124052524567}

          驗證準(zhǔn)確率超過98% ,我們編寫了一個輔助函數(shù),獲取一個圖像并將其應(yīng)用到模型中

          def predict_image(img, model):    # Convert to a batch of 1    xb = to_device(img.unsqueeze(0), device)    # Get predictions from model    yb = model(xb)    # Pick index with highest probability    _, preds  = torch.max(yb, dim=1)    # Retrieve the class label    return dataset.classes[preds[0].item()]

          我們現(xiàn)在在樣本圖像上測試預(yù)測

          img, label = test_dataset[0]plt.imshow(img.permute(1, 2, 0))print('Label:', dataset.classes[label], 'Predicted:', predict_image(img, model))

          輸出:

          10. 總結(jié)


          下面是本教程中用于提高模型性能和減少訓(xùn)練時間的不同技術(shù)的總結(jié):


          • 數(shù)據(jù)增強:我們應(yīng)用隨機變換加載圖像時,從訓(xùn)練數(shù)據(jù)集。具體來說,我們將每張圖片填充4個像素,然后隨機裁剪100 × 100個像素,然后以50% 的概率水平翻轉(zhuǎn)圖片

          • 批量歸一化:在每個卷積層之后,我們增加了一個批量歸一化層,對前一層的輸出進(jìn)行歸一化處理。這有點類似于數(shù)據(jù)規(guī)范化,只不過它應(yīng)用于一個層的輸出,而平均值和標(biāo)準(zhǔn)差是學(xué)習(xí)參數(shù)

          • 學(xué)習(xí)率策略:不再使用固定的學(xué)習(xí)率,而是使用學(xué)習(xí)率調(diào)度器,每次訓(xùn)練后調(diào)整學(xué)習(xí)率。在訓(xùn)練過程中,有很多策略可以改變學(xué)習(xí)率,我們采用了“One Cycle Learning Rate Policy”

          • 權(quán)重衰減:我們給優(yōu)化器增加了權(quán)重衰減,這是另一種正則化技術(shù),它通過在損失函數(shù)中增加一個附加項來防止權(quán)重值變得過大

          • 梯度裁剪:我們還增加了梯度裁剪,這有助于限制梯度值在一個小的范圍,以防止不良變化的模型參數(shù)

          • Adam 優(yōu)化器:我們使用 Adam 優(yōu)化器代替 SGD (隨機梯度下降) ,該優(yōu)化器使用momentum 和 自適應(yīng)學(xué)習(xí)率等技術(shù)進(jìn)行更快的訓(xùn)練。還有許多其他的優(yōu)化器可以選擇并進(jìn)行實驗

          ·  END  ·


          HAPPY LIFE

          個人微信(如果沒有備注不拉群!
          請注明:地區(qū)+學(xué)校/企業(yè)+研究方向+昵稱



          下載1:何愷明頂會分享


          AI算法與圖像處理」公眾號后臺回復(fù):何愷明,即可下載。總共有6份PDF,涉及 ResNet、Mask RCNN等經(jīng)典工作的總結(jié)分析


          下載2:終身受益的編程指南:Google編程風(fēng)格指南


          AI算法與圖像處理」公眾號后臺回復(fù):c++,即可下載。歷經(jīng)十年考驗,最權(quán)威的編程規(guī)范!



          下載3 CVPR2021

          AI算法與圖像處公眾號后臺回復(fù):CVPR即可下載1467篇CVPR 2020論文 和 CVPR 2021 最新論文

          點亮 ,告訴大家你也在看


          瀏覽 44
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产一级黄色A片 | 婷婷五月天黄色 | 欧美日韩aA在线视频 | 亚洲无码高清视频在线播放 | 婷婷无码av |