1. 程式人生 > 其它 >C++ STL list容器底層實現(詳解版)

C++ STL list容器底層實現(詳解版)

技術標籤:python基礎

原文連結:https://blog.csdn.net/weixin_37589575/article/details/95856667

目錄1. 資料集介紹2. 程式碼2. 讀程式碼(個人喜歡的順序)2.1. 匯入模組部分:2.2. Main 函式:
1. 資料集介紹
一般而言,MNIST 資料集測試就是機器學習和深度學習當中的"Hello World"工程。幾乎是所有的教程都會把它放在最開始的地方。這是因為,這個簡單的工程包含了大致的機器學習流程,通過練習這個工程有助於讀者加深理解機器學習或者是深度學習的大致流程。
MNIST(Mixed National Institute of Standards and Technology database)是一個計算機視覺資料集,它包含 70000 張手寫數字的灰度圖片,其中每一張圖片包含 28 X 28 個畫素點。可以用一個數字陣列來表示這張圖片。

2. 程式碼

複製程式碼
import argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms

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)

</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> forward(self, x):
    x </span>=<span style="color: rgba(0, 0, 0, 1)"> F.relu(self.conv1(x))
    x </span>= F.max_pool2d(x, 2, 2<span style="color: rgba(0, 0, 0, 1)">)
    x </span>=<span style="color: rgba(0, 0, 0, 1)"> F.relu(self.conv2(x))
    x </span>= F.max_pool2d(x, 2, 2<span style="color: rgba(0, 0, 0, 1)">)
    x </span>= x.view(-1, 4 * 4 * 50<span style="color: rgba(0, 0, 0, 1)">)
    x </span>=<span style="color: rgba(0, 0, 0, 1)"> F.relu(self.fc1(x))
    x </span>=<span style="color: rgba(0, 0, 0, 1)"> self.fc2(x)
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> F.log_softmax(x, dim=1<span style="color: rgba(0, 0, 0, 1)">)

def train(args, model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if batch_idx % args.log_interval == 0:
print(‘Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}’.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))

def test(args, model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.nll_loss(output, target, reduction=‘sum’).item() # sum up batch loss
pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability
correct += pred.eq(target.view_as(pred)).sum().item()

test_loss </span>/=<span style="color: rgba(0, 0, 0, 1)"> len(test_loader.dataset)

</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">.format(
    test_loss, correct, len(test_loader.dataset),
    </span>100. * correct /<span style="color: rgba(0, 0, 0, 1)"> len(test_loader.dataset)))

def main():
parser = argparse.ArgumentParser(description=‘PyTorch MNIST Example’)
parser.add_argument(’–batch-size’, type=int, default=64, metavar=‘N’,
help=‘input batch size for training (default: 64)’)
parser.add_argument(’–test-batch-size’, type=int, default=1000, metavar=‘N’,
help=‘input batch size for testing (default: 1000)’)
parser.add_argument(’–epochs’, type=int, default=10, metavar=‘N’,
help=‘number of epochs to train (default: 10)’)
parser.add_argument(’–lr’, type=float, default=0.01, metavar=‘LR’,
help=‘learning rate (default: 0.01)’)
parser.add_argument(’–momentum’, type=float, default=0.5, metavar=‘M’,
help=‘SGD momentum (default: 0.5)’)
parser.add_argument(’–no-cuda’, action=‘store_true’, default=False,
help=‘disables CUDA training’)
parser.add_argument(’–seed’, type=int, default=1, metavar=‘S’,
help=‘random seed (default: 1)’)
parser.add_argument(’–log-interval’, type=int, default=10, metavar=‘N’,
help=‘how many batches to wait before logging training status’)
parser.add_argument(’–save-model’, action=‘store_true’, default=False,
help=‘For Saving the current Model’)

args </span>=<span style="color: rgba(0, 0, 0, 1)"> parser.parse_args()
use_cuda </span>= <span style="color: rgba(0, 0, 255, 1)">not</span> args.no_cuda <span style="color: rgba(0, 0, 255, 1)">and</span><span style="color: rgba(0, 0, 0, 1)"> torch.cuda.is_available()
torch.manual_seed(args.seed)
device </span>= torch.device(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">cuda</span><span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(0, 0, 255, 1)">if</span> use_cuda <span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">cpu</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
kwargs </span>= {<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">num_workers</span><span style="color: rgba(128, 0, 0, 1)">'</span>: 1, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">pin_memory</span><span style="color: rgba(128, 0, 0, 1)">'</span>: True} <span style="color: rgba(0, 0, 255, 1)">if</span> use_cuda <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {}
train_loader </span>=<span style="color: rgba(0, 0, 0, 1)"> torch.utils.data.DataLoader(
    datasets.MNIST(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">../data</span><span style="color: rgba(128, 0, 0, 1)">'</span>, train=True, download=<span style="color: rgba(0, 0, 0, 1)">True,
                   transform</span>=<span style="color: rgba(0, 0, 0, 1)">transforms.Compose([
                       transforms.ToTensor(),
                       transforms.Normalize((</span>0.1307,), (0.3081<span style="color: rgba(0, 0, 0, 1)">,))
                   ])),
    batch_size</span>=args.batch_size, shuffle=True, **<span style="color: rgba(0, 0, 0, 1)">kwargs)
test_loader </span>=<span style="color: rgba(0, 0, 0, 1)"> torch.utils.data.DataLoader(
    datasets.MNIST(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">../data</span><span style="color: rgba(128, 0, 0, 1)">'</span>, train=False, transform=<span style="color: rgba(0, 0, 0, 1)">transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((</span>0.1307,), (0.3081<span style="color: rgba(0, 0, 0, 1)">,))
    ])),
    batch_size</span>=args.test_batch_size, shuffle=True, **<span style="color: rgba(0, 0, 0, 1)">kwargs)

model </span>=<span style="color: rgba(0, 0, 0, 1)"> Net().to(device)
optimizer </span>= optim.SGD(model.parameters(), lr=args.lr, momentum=<span style="color: rgba(0, 0, 0, 1)">args.momentum)

</span><span style="color: rgba(0, 0, 255, 1)">for</span> epoch <span style="color: rgba(0, 0, 255, 1)">in</span> range(1, args.epochs + 1<span style="color: rgba(0, 0, 0, 1)">):
    train(args, model, device, train_loader, optimizer, epoch)
    test(args, model, device, test_loader)

</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (args.save_model):
    torch.save(model.state_dict(), </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mnist_cnn.pt</span><span style="color: rgba(128, 0, 0, 1)">"</span>)</pre>

if __name__ == '__main__':

main()
複製程式碼

程式碼案例二

複製程式碼
複製程式碼
import  torch
import  torch.nn as nn
import  torch.nn.functional as F
import  torch.optim as optim
from    torchvision import datasets, transforms

batch_size=200
learning_rate=0.01
epochs=10

train_loader = torch.utils.data.DataLoader(
datasets.MNIST(’…/data’, train=True, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(
datasets.MNIST(’…/data’, train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=batch_size, shuffle=True)

class MLP(nn.Module):

</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span><span style="color: rgba(0, 0, 0, 1)">(self):
    super(MLP, self).</span><span style="color: rgba(128, 0, 128, 1)">__init__</span><span style="color: rgba(0, 0, 0, 1)">()

    self.model </span>=<span style="color: rgba(0, 0, 0, 1)"> nn.Sequential(
        nn.Linear(</span>784, 200<span style="color: rgba(0, 0, 0, 1)">),
        nn.ReLU(inplace</span>=<span style="color: rgba(0, 0, 0, 1)">True),
        nn.Linear(</span>200, 200<span style="color: rgba(0, 0, 0, 1)">),
        nn.ReLU(inplace</span>=<span style="color: rgba(0, 0, 0, 1)">True),
        nn.Linear(</span>200, 10<span style="color: rgba(0, 0, 0, 1)">),
        nn.ReLU(inplace</span>=<span style="color: rgba(0, 0, 0, 1)">True),
    )

</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> forward(self, x):
    x </span>=<span style="color: rgba(0, 0, 0, 1)"> self.model(x)

    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> x

net = MLP()
optimizer = optim.SGD(net.parameters(), lr=learning_rate)
criteon = nn.CrossEntropyLoss()

for epoch in range(epochs):

</span><span style="color: rgba(0, 0, 255, 1)">for</span> batch_idx, (data, target) <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> enumerate(train_loader):
    data </span>= data.view(-1, 28*28<span style="color: rgba(0, 0, 0, 1)">)

    logits </span>=<span style="color: rgba(0, 0, 0, 1)"> net(data)
    loss </span>=<span style="color: rgba(0, 0, 0, 1)"> criteon(logits, target)

    optimizer.zero_grad()
    loss.backward()
    </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> print(w1.grad.norm(), w2.grad.norm())</span>

optimizer.step()

    </span><span style="color: rgba(0, 0, 255, 1)">if</span> batch_idx % 100 ==<span style="color: rgba(0, 0, 0, 1)"> 0:
        </span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">.format(
            epoch, batch_idx </span>*<span style="color: rgba(0, 0, 0, 1)"> len(data), len(train_loader.dataset),
                   </span>100. * batch_idx /<span style="color: rgba(0, 0, 0, 1)"> len(train_loader), loss.item()))


test_loss </span>=<span style="color: rgba(0, 0, 0, 1)"> 0
correct </span>=<span style="color: rgba(0, 0, 0, 1)"> 0
</span><span style="color: rgba(0, 0, 255, 1)">for</span> data, target <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> test_loader:
    data </span>= data.view(-1, 28 * 28<span style="color: rgba(0, 0, 0, 1)">)
    logits </span>=<span style="color: rgba(0, 0, 0, 1)"> net(data)
    test_loss </span>+=<span style="color: rgba(0, 0, 0, 1)"> criteon(logits, target).item()

    pred </span>= logits.data.max(1)[1<span style="color: rgba(0, 0, 0, 1)">]
    correct </span>+=<span style="color: rgba(0, 0, 0, 1)"> pred.eq(target.data).sum()

test_loss </span>/=<span style="color: rgba(0, 0, 0, 1)"> len(test_loader.dataset)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">.format(
    test_loss, correct, len(test_loader.dataset),
    </span>100. * correct / len(test_loader.dataset)))</pre>
複製程式碼

visdom檢視的視覺化

複製程式碼
from visdom import Visdom
viz = Visdom()
#一條線時 viz.line([0.], [0.], win='train_loss', opts=dict(title='train loss')) viz.line([loss.item()], [global_step], win='train_loss', update='append') #兩條線時 viz.line([[0.0,0.0]], [0.], win='test', opts=dict(title='test loss&acc.',legend=['loss','acc.'])) viz.line([[test_loss,correct/len(test_loader.dataset)]], [global_step], win='test', update='append') #影象視覺化 viz.images(data.view(-1,1,28,28),win='X') viz.text(str(pred.detach().cpu().numpy()),win='pred',opts=dict(title='pred'))
複製程式碼




複製程式碼

2. 讀程式碼(個人喜歡的順序)

2.1. 匯入模組部分:

複製程式碼
import argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
複製程式碼

匯入基本的 Python 庫和 Python 包:

argparse 是一個模組,非常好用,可以用來設定模型的預設引數,也可以允許使用者在命令列模式手動設定引數
torch 和 torchvision 是 pytorch 基本的的庫。torch 自然指的是 pytorch, torchvision 是獨立於 pytorch 的關於影象操作的一些方便工具庫。torchvision主要包括以下幾個包:
(1)vision.datasets : 幾個常用視覺資料集,可以下載和載入,這裡主要的高階用法就是可以看原始碼如何自己寫自己的Dataset的子類
(2)vision.models : 流行的模型,例如 AlexNet, VGG, ResNet 和 Densenet 以及 與訓練好的引數。
(3)vision.transforms : 常用的影象操作,例如:隨機切割,旋轉,資料型別轉換,影象到tensor ,numpy 陣列到tensor , tensor 到 影象等。
(4)vision.utils : 用於把形似 (3 x H x W) 的張量儲存到硬碟中,給一個mini-batch的影象可以產生一個影象格網。
torch.nn 參考 pytorch 文件:https://ptorch.com/docs/1/torch-nn
torch.nn.functional 參考 pytorch 文件:https://ptorch.com/docs/8/torch.nn.functional
import torch.optim 主要包含常見的優化演算法

2.2. Main 函式:

複製程式碼
parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
parser.add_argument('--batch-size', type=int, default=64, metavar='N',
                    help='input batch size for training (default: 64)')
parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
                    help='input batch size for testing (default: 1000)')
parser.add_argument('--epochs', type=int, default=10, metavar='N',
                    help='number of epochs to train (default: 10)')
parser.add_argument('--lr', type=float, default=0.01, metavar='LR',
                    help='learning rate (default: 0.01)')
parser.add_argument('--momentum', type=float, default=0.5, metavar='M',
                    help='SGD momentum (default: 0.5)')
parser.add_argument('--no-cuda', action='store_true', default=False,
                    help='disables CUDA training')
parser.add_argument('--seed', type=int, default=1, metavar='S',
                    help='random seed (default: 1)')
parser.add_argument('--log-interval', type=int, default=10, metavar='N',
                    help='how many batches to wait before logging training status')
parser.add_argument('--save-model', action='store_true', default=False,
                    help='For Saving the current Model')
args = parser.parse_args()
args.cuda = not args.no_cuda and torch.cuda.is_available()
複製程式碼

這裡就是使用了 argparse 模組,配置了 batch-size, test-batch-size, epochs, lr, momentum, -no-cuda, seed, log-interval, save-model 等引數,引數值就是 default 裡面的預設值,同時我們可以在命令列允許的時候修改。例如

python main.py --epochs 20 --lr 0.008

這樣就可以修改 epochs 為 20, 學習率為 0.008。

batch-size:我們一次訓練如果只訓練一張圖片,顯然效率太低了,很多 GPU, CPU 資源都沒有利用到,因此可以一次訓練多張圖片。可以提高效率,但是如果視訊記憶體太小,圖片太大,可能導致視訊記憶體不夠用的問題,因此這個值在我們 MNIST 小資料集上設定可以隨意一點,大點的資料集需要好好考量。
test-batch-size:測試時的 batch-size
epochs:訓練的 epochs 數量
lr:學習率
momentum:SGD 演算法裡面的 momentum(動量)
seed:隨機種子
log-interval:多少個 batch 列印一次訓練狀態,設定為10,即 10*64,一個batch size是 64 ,即每 640 張圖片列印一次訓練結果。
save-model:是否儲存模型
cuda:GPU 是否可用

torch.manual_seed(args.seed)
device = torch.device("cuda" if use_cuda else "cpu")

設定隨機種子,以及將 GPU 命名為 device

複製程式碼
 kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}
    train_loader = torch.utils.data.DataLoader(
        datasets.MNIST('../data', train=True, download=True,
                       transform=transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize((0.1307,), (0.3081,))
                       ])),
        batch_size=args.batch_size, shuffle=True, **kwargs)
    test_loader = torch.utils.data.DataLoader(
        datasets.MNIST('../data', train=False, transform=transforms.Compose([
            transforms.ToTensor(),
            transforms.Normalize((0.1307,), (0.3081,))
        ])),
        batch_size=args.test_batch_size, shuffle=True, **kwargs)
複製程式碼

載入訓練集和測試集,pytorch 自帶有 MNIST 資料集。 並且轉為我們需要的格式。

train_loader 裡面就是 6000 個訓練集,包含有圖片和圖片的標籤。
test_loader 裡面就是 1000 個訓練集,包含有圖片和圖片的標籤。

kwargs = {'num_workers': 1, 'pin_memory': True} 

num_workers 是多程序的載入數,pin_memory:是否將資料儲存在pin memory區,pin memory中的資料轉到GPU會快一些。

model = Net().to(device)

構建我們的模型,並送到 GPU 中加速。
模型為:

複製程式碼
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)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> forward(self, x):
    x </span>=<span style="color: rgba(0, 0, 0, 1)"> F.relu(self.conv1(x))
    x </span>= F.max_pool2d(x, 2, 2<span style="color: rgba(0, 0, 0, 1)">)
    x </span>=<span style="color: rgba(0, 0, 0, 1)"> F.relu(self.conv2(x))
    x </span>= F.max_pool2d(x, 2, 2<span style="color: rgba(0, 0, 0, 1)">)
    x </span>= x.view(-1, 4 * 4 * 50<span style="color: rgba(0, 0, 0, 1)">)
    x </span>=<span style="color: rgba(0, 0, 0, 1)"> F.relu(self.fc1(x))
    x </span>=<span style="color: rgba(0, 0, 0, 1)"> self.fc2(x)
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> F.log_softmax(x, dim=1)</pre>
複製程式碼

兩個卷積層,兩個線性層:構建我們只看 init 部分就可以了,forward 部分是將資料送到模型,模型如何處理的過程。

optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum)

優化方法是 SGD, 第一個引數是模型的引數,第二個是學習率,第三個是動量。

    for epoch in range(1, args.epochs + 1):
        train(args, model, device, train_loader, optimizer, epoch)
        test(args, model, device, test_loader)

一共訓練 10 次,每次訓練完都測試一次。

if (args.save_model):
  torch.save(model.state_dict(), "mnist_cnn.pt")

如果配置為要保持模型,就儲存模型到 mnist_cnn.pt 檔案裡面,如果沒有會新建。

複製程式碼
def train(args, model, device, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % args.log_interval == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                       100. * batch_idx / len(train_loader), loss.item()))
複製程式碼

訓練過程,接收配置 args, 模型model, GPU device, 訓練資料train_loader,優化器optimizer和當前訓練週期epoch

model.train()

模型進入訓練模式

for batch_idx, (data, target) in enumerate(train_loader):
    data, target = data.to(device), target.to(device)

載入訓練資料集合,這裡一次 64 張圖片以及對應的類別(0 - 9),data 是圖片 shape 為[64, 1, 28, 28],64張圖片,灰度圖片,畫素大小為28*28。 target 是 64 個圖片的類別,每個用 0-9 的圖片表示。

 optimizer.zero_grad()
 output = model(data)
 loss = F.nll_loss(output, target)
 loss.backward()
 optimizer.step()

優化過程開始,然後 data 送到模型,經過模型的 forward 步驟,最後一步 softmax 為這張圖片屬於 10 個類的概率,比如[0.7, 0.1, 0.1, 0.1,0, 0, 0, 0, 0, 0] 就是這張圖片屬於 0 的概率為 0.7, 屬於1. 2. 3的概率為 0.1。損失函式為 NLLLoss 。
NLLLoss 的 輸入 是一個對數概率向量和一個目標標籤. 它不會為我們計算對數概率. 適合網路的最後一層是log_softmax. 損失函式 nn.CrossEntropyLoss() 與 NLLLoss() 相同, 唯一的不同是它為我們去做 softmax. 我們視為分類問題,最常見的損失函式就是交叉熵,我們這裡本質也是交叉熵。因為模型最後一步 forward 是 softmax。

CrossEntropyLoss()=log_softmax() + NLLLoss()+softmax()

然後根據 loss 用 SGD 演算法優化引數。

 if batch_idx % args.log_interval == 0:
     print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
     epoch, batch_idx * len(data), len(train_loader.dataset),
     100. * batch_idx / len(train_loader), loss.item()))

每 10 * 64 張圖片列印訓練狀態:

複製程式碼
def test(args, model, device, test_loader):
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += F.nll_loss(output, target, reduction='sum').item()  # sum up batch loss
            pred = output.argmax(dim=1, keepdim=True)  # get the index of the max log-probability
            correct += pred.eq(target.view_as(pred)).sum().item()
test_loss </span>/=<span style="color: rgba(0, 0, 0, 1)"> len(test_loader.dataset)

</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">.format(
    test_loss, correct, len(test_loader.dataset),
    </span>100. * correct / len(test_loader.dataset)))<br><br><br><br></pre>
複製程式碼

測試模型。

    model.eval()
    test_loss = 0
    correct = 0

模型進入測試模式,初始化計數變數。然後載入測試圖片,data 送到模型,然後計算疊加損失 loss,pred 就是找出 softmax 之後數組裡面最大值得索引,最大值就是預測最有可能的概率,然後索引就是預測的數字。例如上面 [0.7, 0.1, 0.1, 0.1,0, 0, 0, 0, 0, 0] , 最大概率值是 0.7,索引就是 0,我們預測這個數字是 0。然後疊加準確的個數,最後 loss 和 準確個數除以測試圖片個數就是平均的 loss 和 準確率。