pytorch 入門4-簡單圖片分類

2021-02-11 微笑那些事兒

一、總體簡介

結合一個超級詳細的卷積神經網絡的解析:

1.卷積神經網絡是一種帶有卷積結構的深度神經網絡,卷積結構可以減少深層網絡佔用的內存量,其三個關鍵的操作,其一是局部感受野,其二是權值共享,其三是pooling層,有效的減少了網絡的參數個數,緩解了模型的過擬合問題。

2.卷積神經網絡結構包括:卷積層,降採樣層,全連結層。每一層有多個特徵圖,每個特徵圖通過一種卷積濾波器提取輸入的一種特徵,每個特徵圖有多個神經元。

名稱
特點LeNet沒啥特點-不過是第一個CNN應該要知道,

包含輸入層總共8層網絡,分別為:輸入層(INPUT)、卷積層(Convolutions,C1)、池化層(Subsampling,S2)、卷積層(C3)、池化層(Subsampling,S4)、卷積層(C5)、全連接層(F6)、輸出層(徑向基層)

AlexNet引入了ReLU和dropout,引入數據增強、池化相互之間有覆蓋,三個卷積一個最大池化+三個全連接層VGGNet採用11和33的卷積核以及2*2的最大池化使得層數變得更深。常用VGGNet-16和VGGNet19微軟ResNet殘差神經網絡(Residual Neural Network)1、引入高速公路結構,可以讓神經網絡變得非常深2、ResNet第二個版本將ReLU激活函數變成y=x的線性函數DenseNet
從feature上入手,把feature應用到極致,在減少參數的同時獲得較高的準確率。DenseNet的想法是,在保證層與層之間最大程度的信息傳輸的前提下,將網絡種的所有層連接起來。

接下來就是代碼實現了:

CNN圖像分類

導入需要的庫:

import numpy as npimport torchimport torch.nn as nnimport torch.nn.functional as Fimport torch.optim as optim

我們要下載一個torchvision庫,裡面包含有datasets, transforms函數

from torchvision import datasets, transformsprint("PyTorch Version: ",torch.__version__)

首先我們定義一個基於ConvNet的簡單神經網絡(在定義一個網絡的時候,需要初始化一個函數,然後要加上一個forward函數)

class Net(nn.Module):    def __init__(self):        super(Net, self).__init__()        self.conv1 = nn.Conv2d(1, 20, 5, 1)         self.conv2 = nn.Conv2d(20, 50, 5, 1)         self.fc1 = nn.Linear(4*4*50, 500)        self.fc2 = nn.Linear(500, 10)            def forward(self, x):                x = F.relu(self.conv1(x))         x = F.max_pool2d(x,2,2)         x = F.relu(self.conv2(x))         x = F.max_pool2d(x,2,2)         x = x.view(-1, 4*4*50)         x = F.relu(self.fc1(x))        x= self.fc2(x)                return F.log_softmax(x, dim=1) 

接著利用datasets函數自動下載mnist數據

mnist_data = datasets.MNIST("./mnist_data", train=True, download=True,                           transform=transforms.Compose([                               transforms.ToTensor(),                           ]))mnist_data

接下來是將數據轉換成numpy格式

data = [d[0].data.cpu().numpy() for d in mnist_data]np.mean(data) #均值np.std(data) #方差

接下來是定義兩個function,一個是train,一個是test

def train(model, device, train_loader, optimizer, epoch):     model.train()     for idx, (data, target) in enumerate(train_loader):        data, target = data.to(device), target.to(device)
pred = model(data) loss = F.nll_loss(pred, target) optimizer.zero_grad() loss.backward() optimizer.step() if idx % 100 == 0: print("Train Epoch: {}, iteration: {}, Loss: {}".format( epoch, idx, loss.item()))

def test(model, device, test_loader):    model.eval()     total_loss = 0.     correct = 0.         with torch.no_grad():         for idx, (data, target) in enumerate(test_loader):            data, target = data.to(device), target.to(device)
output = model(data) total_loss += F.nll_loss(output, target, reduction="sum").item() pred = output.argmax(dim=1) correct += pred.eq(target.view_as(pred)).sum().item()              total_loss /= len(test_loader.dataset) acc = correct/len(test_loader.dataset) * 100. print("Test loss: {}, Accuracy: {}".format(total_loss, acc))

接下來是訓練模型在預測驗證集

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")batch_size = 32train_dataloader = torch.utils.data.DataLoader(    datasets.MNIST("./mnist_data", train=True, download=True,           transform=transforms.Compose([               transforms.ToTensor(),               transforms.Normalize((0.1307,), (0.3081,))           ])),    batch_size=batch_size, shuffle=True,     num_workers=1, pin_memory=True)test_dataloader = torch.utils.data.DataLoader(    datasets.MNIST("./mnist_data", train=False, download=True,           transform=transforms.Compose([               transforms.ToTensor(),               transforms.Normalize((0.1307,), (0.3081,))           ])),    batch_size=batch_size, shuffle=True,     num_workers=1, pin_memory=True)
lr = 0.01momentum = 0.5model = Net().to(device)optimizer = torch.optim.SGD(model.parameters(), lr=lr, momentum=momentum)
num_epochs = 2for epoch in range(num_epochs): train(model, device, train_dataloader, optimizer, epoch) test(model, device, test_dataloader) torch.save(model.state_dict(), "mnist_cnn.pt")

NLL loss的定義

導入fashion_mnist數據也試一次

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")batch_size = 32train_dataloader = torch.utils.data.DataLoader(    datasets.FashionMNIST("./fashion_mnist_data", train=True, download=True,           transform=transforms.Compose([               transforms.ToTensor(),               transforms.Normalize((0.1307,), (0.3081,))           ])),    batch_size=batch_size, shuffle=True,     num_workers=1, pin_memory=True)test_dataloader = torch.utils.data.DataLoader(    datasets.FashionMNIST("./fashion_mnist_data", train=False, download=True,           transform=transforms.Compose([               transforms.ToTensor(),               transforms.Normalize((0.1307,), (0.3081,))           ])),    batch_size=batch_size, shuffle=True,     num_workers=1, pin_memory=True)
lr = 0.01momentum = 0.5model = Net().to(device)optimizer = torch.optim.SGD(model.parameters(), lr=lr, momentum=momentum)
num_epochs = 2for epoch in range(num_epochs): train(model, device, train_dataloader, optimizer, epoch) test(model, device, test_dataloader) torch.save(model.state_dict(), "fashion_mnist_cnn.pt")

CNN模型的遷移學習

以下是構建和訓練遷移學習模型的基本步驟:

初始化預訓練模型

把最後一層的輸出層改變成我們想要分的類別總數

定義一個optimizer來更新參數

模型訓練

import numpy as npimport torchvisionfrom torchvision import datasets, transforms, modelsimport matplotlib.pyplot as pltimport timeimport osimport copyprint("Torchvision Version: ",torchvision.__version__)

數據

我們會使用hymenoptera_data數據集,數據集在https://download.pytorch.org/tutorial/hymenoptera_data.zip下載

這個數據集包括兩類圖片, bees 和 ants, 這些數據都被處理成了可以使用ImageFolder <https://pytorch.org/docs/stable/torchvision/datasets.html#torchvision.datasets.ImageFolder>來讀取的格式。我們只需要把data_dir設置成數據的根目錄,然後把model_name設置成我們想要使用的與訓練模型::: [resnet, alexnet, vgg, squeezenet, densenet, inception]

其他的參數有:

data_dir = "./hymenoptera_data"model_name = "resnet"num_classes = 2batch_size = 32num_epochs = 15feature_extract = Trueinput_size = 224

讀入數據

現在我們知道了模型輸入的size,我們就可以把數據預處理成相應的格式。

all_imgs = datasets.ImageFolder(os.path.join(data_dir, "train"), transforms.Compose([        transforms.RandomResizedCrop(input_size),        transforms.RandomHorizontalFlip(),         transforms.ToTensor(),    ]))loader = torch.utils.data.DataLoader(all_imgs, batch_size=batch_size, shuffle=True, num_workers=4)

data_transforms = {    "train": transforms.Compose([        transforms.RandomResizedCrop(input_size),        transforms.RandomHorizontalFlip(),        transforms.ToTensor(),        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])     ]),    "val": transforms.Compose([        transforms.Resize(input_size),        transforms.CenterCrop(input_size),        transforms.ToTensor(),        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])    ])}
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ["train", "val"]}dataloaders_dict = {x: torch.utils.data.DataLoader(image_datasets[x],  batch_size=batch_size, shuffle=True, num_workers=4) for x in ["train", "val"]}device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

img = next(iter(dataloaders_dict["val"]))[0]

以下是標準化以後的圖片的展示

unloader = transforms.ToPILImage()  plt.ion()def imshow(tensor, title=None):    image = tensor.cpu().clone()      image = image.squeeze(0)          image = unloader(image)    plt.imshow(image)    if title is not None:        plt.title(title)    plt.pause(0.001) plt.figure()imshow(img[1], title='Image')

定義模型:

def set_parameter_requires_grad(model, feature_extract):    if feature_extract:        for param in model.parameters():            param.requires_grad = False            def initialize_model(model_name, num_classes, feature_extract, use_pretrained=True):    if model_name == "resnet":        model_ft = models.resnet18(pretrained=use_pretrained)        set_parameter_requires_grad(model_ft, feature_extract)        num_ftrs = model_ft.fc.in_features        model_ft.fc = nn.Linear(num_ftrs, num_classes)        input_size = 224    else:        print("model not implemented")        return None, None            return model_ft, input_size
model_ft, input_size = initialize_model(model_name, num_classes, feature_extract, use_pretrained=True)print(model_ft)

       改變除了最後一層的所有層: 

model_ft.layer1[0].conv1.weight.requires_grad #前面的所有的層改變是False

改變最後一層:

model_ft.fc.weight.requires_grad #只有最後一層的改變是True,前面的是都不會更新的

定義一個完整的模型

def train_model(model, dataloaders, loss_fn, optimizer, num_epochs=5):    best_model_wts = copy.deepcopy(model.state_dict())    best_acc = 0.    val_acc_history = []    for epoch in range(num_epochs):        for phase in ["train", "val"]:            running_loss = 0.            running_corrects = 0.            if phase == "train":                model.train()            else:                model.eval()                            for inputs, labels in dataloaders[phase]:                inputs, labels = inputs.to(device), labels.to(device)                                with torch.autograd.set_grad_enabled(phase=="train"):                    outputs = model(inputs)                     loss = loss_fn(outputs, labels)                                     preds = outputs.argmax(dim=1)                if phase == "train":                    optimizer.zero_grad()                    loss.backward()                    optimizer.step()                running_loss += loss.item() * inputs.size(0)                running_corrects += torch.sum(preds.view(-1) == labels.view(-1)).item()                            epoch_loss = running_loss / len(dataloaders[phase].dataset)            epoch_acc = running_corrects / len(dataloaders[phase].dataset)                        print("Phase {} loss: {}, acc: {}".format(phase, epoch_loss, epoch_acc))                        if phase == "val" and epoch_acc > best_acc:                best_acc = epoch_acc                best_model_wts = copy.deepcopy(model.state_dict())            if phase == "val":                val_acc_history.append(epoch_acc)    model.load_state_dict(best_model_wts)        return model, val_acc_history

模型訓練

model_ft = model_ft.to(device)optimizer = torch.optim.SGD(filter(lambda p: p.requires_grad,                                    model_ft.parameters()), lr=0.001, momentum=0.9)loss_fn = nn.CrossEntropyLoss()_, ohist = train_model(model_ft, dataloaders_dict, loss_fn, optimizer, num_epochs=num_epochs)

上面訓練模型得到訓練和驗證的loss以及精度

model_scratch, _ = initialize_model(model_name,                     num_classes, feature_extract=False, use_pretrained=False)model_scratch = model_scratch.to(device)optimizer = torch.optim.SGD(filter(lambda p: p.requires_grad,                                    model_scratch.parameters()), lr=0.001, momentum=0.9)loss_fn = nn.CrossEntropyLoss()_, scratch_hist = train_model(model_scratch, dataloaders_dict, loss_fn, optimizer, num_epochs=num_epochs)

我們來plot模型訓練時候loss的變化


plt.title("Validation Accuracy vs. Number of Training Epochs")plt.xlabel("Training Epochs")plt.ylabel("Validation Accuracy")plt.plot(range(1,num_epochs+1),ohist,label="Pretrained")plt.plot(range(1,num_epochs+1),scratch_hist,label="Scratch")plt.ylim((0,1.))plt.xticks(np.arange(1, num_epochs+1, 1.0))plt.legend()plt.show()

結果展示:

在這次的學習當中,也學習了多種神經網絡的代碼

網址為:

https://github.com/pytorch/vision/tree/master/torchvision/models

裡面含有很多網絡代碼

相關焦點

  • PyTorch搭建簡單神經網絡實現回歸和分類
    4.三、PyTorch實現簡單分類完整代碼:4. torch.max()(1)torch.max(input)→ floatinput是tensor,返回input中的最大值float。自然語言處理》英、中文版PDF+源碼《21個項目玩轉深度學習:基於TensorFlow的實踐詳解》完整版PDF+附書代碼《深度學習之pytorch》pdf+附書源碼PyTorch深度學習快速實戰入門《pytorch-handbook》【下載】豆瓣評分8.1,《機器學習實戰:基於Scikit-Learn和TensorFlow
  • 60分鐘入門PyTorch
    60 分鐘帶你快速入門 PyTorch 的官方教程。4.1 訓練數據在訓練分類器前,當然需要考慮數據的問題。通常在處理如圖片、文本、語音或者視頻數據的時候,一般都採用標準的 Python 庫將其加載並轉成 Numpy 數組,然後再轉回為 PyTorch 的張量。
  • 【Pytorch】新手如何入門pytorch?
    只能說比tensorflow簡單許多, 我在火車上看了一兩個小時就感覺基本入門了. 另外jcjohnson 的Simple examples to introduce PyTorch 也不錯第二步 example 參考 pytorch/examples 實現一個最簡單的例子(比如訓練mnist )。
  • 使用Pytorch訓練分類器詳解(附python演練)
    訓練一個圖像分類器1. 使用torchvision加載並且歸一化CIFAR10的訓練和測試數據集2. 定義一個卷積神經網絡3. 定義一個損失函數4. 在訓練樣本數據上訓練網絡5. 在測試樣本數據上測試網絡三.
  • fastai 1.0 入門教程:如何訓練簡單圖像分類器
    由於剛發布不久,網上關於fastai 1.0的教程極少,因此,我們編寫了這篇入門教程,以一個簡單的圖像分類問題(異形與鐵血戰士)為例,帶你領略fastai這一高層抽象框架驚人的簡潔性。注意,fastai最近的更新節奏很瘋狂:
  • 【小白學PyTorch】15.TF2實現一個簡單的服裝分類任務
    0 為什麼學TF1 Tensorflow的安裝2 數據集構建2 預處理3 構建模型4 優化器5 訓練與預測 0 為什麼學TF 之前的15節課的pytorch的學習,應該是讓不少朋友對PyTorch有了一個全面而深刻的認識了吧 (
  • 10 分鐘完全讀懂 PyTorch
    開始一個簡單的分類器我個人在學習一門新語言,一個新框架,一個新技術時,最優先要保證的就是成就感反饋。以學習 pytorch 為例,很多教程從張量開始。我自己也按照這種教程學習過,的確內容非常全盡,但是有兩個原因,我自己不太推薦以這種方式入門:1)前期學習過於枯燥,沒有成就感;2)有的知識內容屬於深度學習的基本功,過於贅述。
  • pytorch學習筆記(7):RNN 和 LSTM 實現分類和回歸
    LSTM,以及實現一個分類器前面我們介紹了原始的 RNN,眾所周知的一些 RNN 的缺陷,我們就不贅述了(梯度爆炸,梯度消失等等)。那麼 LSTM 成為了一個在序列化數據中非常受歡迎的選項。這一部分,我們先介紹一下簡單的 LSTM 的理論基礎,然後主要是 pytorch 中對於 LSTM 提供的接口,最後通過一個分類器的例子,來完成一個分類器。
  • Pytorch簡單教程
    本文推薦一個簡單的Pytorch的入門學習教程(來源於網絡,如有問題請及時聯繫):張量  Pytorch中的Tensor和ndarray類似,區別在於ndarray不能再GPU上加速,而Tensor可以使用GPU加速。
  • 《PyTorch中文手冊》來了
    本書提供PyTorch快速入門指南並與最新版本保持一致,其中包含的 Pytorch 教程全部通過測試保證可以成功運行。PyTorch 是一個深度學習框架,旨在實現簡單靈活的實驗。自 2017 年初首次推出,PyTorch 很快成為 AI 研究人員的熱門選擇並受到推崇。PyTorch 有許多優勢,如採用 Python 語言、動態圖機制、網絡構建靈活以及擁有強大的社群等。
  • 一份超全的PyTorch資源列表(GitHub 2.2K Stars)
    項目地址:https://github.com/IBM/pytorch-seq2seq3.anuvada:PyTorch 中實現的 NLP 的可解釋模型。項目地址:https://github.com/Sandeep42/anuvada4.audio:PyTorch 的簡單音頻 I/O。
  • 教程 | 從頭開始了解PyTorch的簡單實現
    本教程展示了如何從了解張量開始到使用 PyTorch 訓練簡單的神經網絡,是非常基礎的 PyTorch 入門資源。
  • Deep Learning with PyTorch 必看教程集(4本)
    第三本:《深度學習入門之PyTorch》在本書中,我們將幫助你入門深度學習的領域。《深度學習框架PyTorch:入門與實踐》沒有簡單機械地介紹各個函數接口的使用,而是嘗試分門別類、循序漸進地向讀者介紹PyTorch的知識,希望讀者對PyTorch有一個完整的認識。《深度學習框架PyTorch:入門與實踐》內容由淺入深,無論是深度學習的初學者,還是頭次接觸PyTorch的研究人員,都能在學習本書的過程中快速掌握PyTorch。
  • 深度學習大講堂之pytorch入門
    今天小天就帶大家從數據操作、自動求梯度和神經網絡設計的pytorch版本三個方面來入門pytorch。1.2.4 線性代數官方文檔:https://pytorch.org/docs/stable/torch.html
  • 如何高效入門 PyTorch ?
    和《數據科學入門後,該做什麼?》兩篇文章裡,已經給你詳細闡釋過了。簡單來說,別人都用來溝通和協作的東西,你一竅不通,那就沒法愉快參與協作了。深度嵌入到系統的協作能力,才是你贏得競爭的秘密武器。Python 說簡單很簡單,因為它可以被當成腳本語言來使用。也就是用順序、循環和判斷組織起來,類似英文的操作說明。
  • PyTorch Lightning:專門為機器學習研究者開發的PyTorch輕量 wrapper
    # 這只是一個簡單的有一些結構的nn.Moduleclass LitClassifier(pl.LightningModule):    def __init__(self):        super().
  • 60分鐘入門深度學習工具-PyTorch
    點擊上方「AI算法與圖像處理」,選擇加"星標"或「置頂」重磅乾貨,第一時間送達來源:機器學習初學者60分鐘入門深度學習工具-PyTorch作者:Soumith Chintala原文翻譯自:https://pytorch.org/tutorials/
  • PyTorch中文版官方教程來了,附pdf下載
    教程作者來自 pytorchchina.com。教程網站:http://pytorch123.com如果不想自己下載,請通過下面方式獲取pdf資料:教程裡有什麼教程根據 PyTorch 官方版本目錄,完整地還原了所有的內容。
  • 60 分鐘入門 PyTorch(四):訓練一個分類器
    訓練一個分類器你已經學會如何去定義一個神經網絡,計算損失值和更新網絡的權重。你現在可能在思考:數據哪裡來呢?訓練一個圖像分類器我們將按照下列順序進行:使用torchvision加載和歸一化CIFAR10訓練集和測試集.1. 加載和歸一化CIFAR10使用torchvision加載CIFAR10是非常容易的。
  • 重磅 | PyTorch中文版官方教程來了,附pdf下載
    教程作者來自 pytorchchina.com。教程網站:http://pytorch123.com教程裡有什麼教程根據 PyTorch 官方版本目錄,完整地還原了所有的內容。包括簡單的環境搭建、快速入門相關 API、高級操作、圖像處理實戰、文本處理實戰、GAN 和強化學習等,基本涵蓋了目前所有深度學習相關的知識點。