import os
import numpy as np
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
import torch.optim as optimizer
基本配置
# 批次大小
batch_size = 16
# 學(xué)習(xí)率
lr = 1e-4
# 最大迭代次數(shù)
max_epochs = 100
# 設(shè)置GPU
# 方式1
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'
# 方式2,后續(xù)對(duì)要使用GPU的變量用.to(device)
device = torch.device('cuda:1' if torch.cuda.is_available() else "cpu")
數(shù)據(jù)讀入
通過Dataset+DataLoader方式完成
Dataset類主要包含三個(gè)函數(shù):
- init: 傳入外部參數(shù),初始化
- getitem: 逐個(gè)讀取樣本
- len: 返回樣本數(shù)
import torch
from torchvision import datasets
# 數(shù)據(jù)集
train_data = datasets.ImageFolder(train_path, transform=data_transform)
val_data = datasets.ImageFolder(val_path, transform=data_transform)
# 按批次讀入數(shù)據(jù)
from torch.utils.data import DataLoader
train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, num_workers=4, shuffle=True, drop_last=True)
val_loader = torch.utils.data.DataLoader(val_data, batch_size=batch_size, num_workers=4, shuffle=False)
# 可視化下一個(gè)樣本圖片
import matplotlib.pyplot as plt
images, labels = next(iter(val_loader))
print(images.shape)
plt.imshow(images[0].transpose(1,2,0))
plt.show()
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_21680\1158052838.py in <module>
1 # 可視化下一個(gè)樣本圖片
----> 2 import matplotlib.pyplot as plt
3 images, labels = next(iter(val_loader))
4 print(images.shape)
5 plt.imshow(images[0].transpose(1,2,0))
ModuleNotFoundError: No module named 'matplotlib'
class MyDataset(Dataset):
def __init__(self, data_dir, info_csv, image_list, transform=None):
"""
Args:
data_dir: path to image directory
info_csv: path to labels
image_list: path to txt file contains image names
transform: optional transform to be applied on a sample
"""
label_info = pd.read_csv(info_csv)
image_file = open(image_list).readlines()
self.data_dir = data_dir
self.image_file = image_file
self.label_info = label_info
self.transform = transform
def __getitem__(self, index):
image_name = self.image_file[index].strip('\n')
raw_label = self.label_info.loc[self.label_info['Image_index'] == image_name]
label = raw_label.iloc[:,0]
image_name = os.path.join(self.data_dir, image_name)
image = Image.open(image_name).convert('RGB')
if self.transform is not None:
image = self.transform(image)
return image, label
def __len__(self):
return len(self.image_file)
模型構(gòu)建
神經(jīng)網(wǎng)絡(luò)的構(gòu)造
import torch
from torch import nn
class MLP(nn.Module):
# 聲明帶有模型參數(shù)的層
def __init__(self, **kwargs):
# 繼承父類時(shí)初始化
super(MLP, self).__init__(**kwargs)
self.hidden = nn.Linear(784, 256) # 輸入樣本784個(gè)var, 輸出n * 256
self.act = nn.ReLU() # Relu激活函數(shù)
self.output = nn.Linear(256, 10) # 輸出n * 10
# 定義模型的前向計(jì)算,輸入x計(jì)算返回值
def forward(self, x):
o = self.act(self.hidden(x))
return self.output(o)
X = torch.rand(2, 784)
net = MLP()
print(net)
net(X)
MLP(
(hidden): Linear(in_features=784, out_features=256, bias=True)
(act): ReLU()
(output): Linear(in_features=256, out_features=10, bias=True)
)
tensor([[-0.1357, -0.1145, 0.0626, 0.0197, 0.0813, 0.0714, -0.0941, -0.0946,
-0.2517, 0.0006],
[ 0.0474, -0.1632, 0.1313, -0.0293, 0.1087, 0.0678, -0.0179, -0.2159,
-0.1594, -0.1324]], grad_fn=<AddmmBackward0>)
神經(jīng)網(wǎng)絡(luò)常見的層
自定義層
# 不含參數(shù)的層
import torch
from torch import nn
class MyLayer(nn.Module):
def __init__(self, **kwargs):
super(MyLayer, self).__init__(**kwargs)
def forward(self, x):
return x - x.mean()
layer = MyLayer()
layer(torch.tensor([1, 2, 3, 4, 5], dtype=torch.float))
tensor([-2., -1., 0., 1., 2.])
# 含模型參數(shù)的層
class MyListDense(nn.Module):
def __init__(self):
super(MyListDense, self).__init__()
# 也可以用nn.ParameterDict
self.params = nn.ParameterList([nn.Parameter(torch.randn(4, 4)) for i in range(3)])
self.params.append(nn.Parameter(torch.randn(4, 1)))
def forward(self, x):
for i in range(len(self.params)):
x = torch.mm(x, self.params[i])
return x
二維卷積層
import torch
from torch import nn
def corr2d(X, K):
h, w = K.shape
X, K = X.float(), K.float()
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i+h, j:j+w] * K).sum()
return Y
# 二維卷積層
class Conv2D(nn.Module):
def __init__(self, kernel_size):
super(Conv2D, self).__init__()
self.weight = nn.Parameter(torch.randn(kernel_size))
self.bias = nn.Parameter(torch.randn(1))
def forward(self, x):
return corr2d(x, self.weight) + self.bias
import torch
from torch import nn
# 定義一個(gè)函數(shù)來計(jì)算卷積層。它對(duì)輸入和輸出做相應(yīng)的升維和降維
import torch
from torch import nn
# 定義一個(gè)函數(shù)來計(jì)算卷積層。它對(duì)輸入和輸出做相應(yīng)的升維和降維
def comp_conv2d(conv2d, X):
# (1, 1)代表批量大小和通道數(shù)
X = X.view((1, 1) + X.shape) # 拼接成4維數(shù)組
Y = conv2d(X)
return Y.view(Y.shape[2:]) # 排除不關(guān)心的前兩維:批量和通道
# 注意這里是兩側(cè)分別填充1?或列,所以在兩側(cè)一共填充2?或列
conv2d = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3,padding=1)
X = torch.rand(8, 8)
comp_conv2d(conv2d, X).shape
torch.Size([8, 8])
池化層
import torch
from torch import nn
def pool2d(X, pool_size, mode='max'):
p_h, p_w = pool_size
Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
if mode == 'max':
Y[i, j] = X[i: i + p_h, j: j + p_w].max()
elif mode == 'avg':
Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
return Y
X = torch.tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]], dtype=torch.float)
pool2d(X, (2, 2))
tensor([[4., 5.],
[7., 8.]])
AlexNet模型示例
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 96, 11, 4), # in_channels, out_channels, kernel_size, stride, padding
nn.ReLU(),
nn.MaxPool2d(3, 2), # kernel_size, stride
# 減小卷積窗口,使用填充為2來使得輸入與輸出的高和寬一致,且增大輸出通道數(shù)
nn.Conv2d(96, 256, 5, 1, 2),
nn.ReLU(),
nn.MaxPool2d(3, 2),
# 連續(xù)3個(gè)卷積層,且使用更小的卷積窗口。除了最后的卷積層外,進(jìn)一步增大了輸出通道數(shù)。
# 前兩個(gè)卷積層后不使用池化層來減小輸入的高和寬
nn.Conv2d(256, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 384, 3, 1, 1),
nn.ReLU(),
nn.Conv2d(384, 256, 3, 1, 1),
nn.ReLU(),
nn.MaxPool2d(3, 2)
)
# 這里全連接層的輸出個(gè)數(shù)比LeNet中的大數(shù)倍。使用丟棄層來緩解過擬合
self.fc = nn.Sequential(
nn.Linear(256*5*5, 4096),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(4096, 4096),
nn.ReLU(),
nn.Dropout(0.5),
# 輸出層。由于這里使用Fashion-MNIST,所以用類別數(shù)為10,而非論文中的1000
nn.Linear(4096, 10),
)
def forward(self, img):
feature = self.conv(img)
output = self.fc(feature.view(img.shape[0], -1))
return output
net = AlexNet()
print(net)
AlexNet(
(conv): Sequential(
(0): Conv2d(1, 96, kernel_size=(11, 11), stride=(4, 4))
(1): ReLU()
(2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
(3): Conv2d(96, 256, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
(4): ReLU()
(5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
(6): Conv2d(256, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(7): ReLU()
(8): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(9): ReLU()
(10): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU()
(12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(fc): Sequential(
(0): Linear(in_features=6400, out_features=4096, bias=True)
(1): ReLU()
(2): Dropout(p=0.5, inplace=False)
(3): Linear(in_features=4096, out_features=4096, bias=True)
(4): ReLU()
(5): Dropout(p=0.5, inplace=False)
(6): Linear(in_features=4096, out_features=10, bias=True)
)
)
模型初始化
torch.nn.init
import torch
import torch.nn as nn
conv = nn.Conv2d(1,3,3)
linear = nn.Linear(10,1)
# 查看隨機(jī)初始化的conv參數(shù)
print(conv.weight.data)
# 查看linear的參數(shù)
print(linear.weight.data)
tensor([[[[ 0.1268, -0.0083, -0.1545],
[ 0.2284, 0.0016, -0.1577],
[ 0.0579, -0.0849, -0.2911]]],
[[[ 0.0605, 0.1680, 0.1811],
[-0.1920, -0.1370, 0.2808],
[ 0.0944, 0.1277, -0.1246]]],
[[[ 0.2819, -0.2207, 0.0406],
[ 0.2280, -0.0377, 0.2743],
[ 0.3203, -0.0189, -0.0889]]]])
tensor([[-0.1381, -0.1385, 0.1530, 0.0018, -0.0307, -0.0804, -0.2288, 0.1726,
0.0550, 0.1364]])
# 對(duì)conv進(jìn)行kaiming初始化
torch.nn.init.kaiming_normal_(conv.weight.data)
print(conv.weight.data)
# 對(duì)linear進(jìn)行常數(shù)初始化
torch.nn.init.constant_(linear.weight.data,0.3)
print(linear.weight.data)
tensor([[[[-0.0482, 0.4568, -0.0451],
[ 0.5877, 0.1045, -0.0692],
[ 0.6888, 0.0516, 0.1558]]],
[[[ 0.2490, -0.1846, -0.2468],
[-0.1517, -1.1788, 0.1218],
[ 0.3340, -0.4299, 0.1132]]],
[[[ 0.1487, -0.4090, 0.6382],
[ 0.4713, -0.3765, 0.4769],
[ 0.0353, 0.2126, -0.0899]]]])
tensor([[0.3000, 0.3000, 0.3000, 0.3000, 0.3000, 0.3000, 0.3000, 0.3000, 0.3000,
0.3000]])
初始化函數(shù)的封裝
def initialize_weights(self):
for m in self.modules():
# 判斷是否屬于Conv2d
if isinstance(m, nn.Conv2d):
torch.nn.init.xavier_normal_(m.weight.data)
# 判斷是否有偏置
if m.bias is not None:
torch.nn.init.constant_(m.bias.data,0.3)
elif isinstance(m, nn.Linear):
torch.nn.init.normal_(m.weight.data, 0.1)
if m.bias is not None:
torch.nn.init.zeros_(m.bias.data)
elif isinstance(m, nn.BatchNorm2d):
m.weight.data.fill_(1)
m.bias.data.zeros_()
# 模型的定義
class MLP(nn.Module):
# 聲明帶有模型參數(shù)的層,這里聲明了兩個(gè)全連接層
def __init__(self, **kwargs):
# 調(diào)用MLP父類Block的構(gòu)造函數(shù)來進(jìn)行必要的初始化。這樣在構(gòu)造實(shí)例時(shí)還可以指定其他函數(shù)
super(MLP, self).__init__(**kwargs)
self.hidden = nn.Conv2d(1,1,3)
self.act = nn.ReLU()
self.output = nn.Linear(10,1)
# 定義模型的前向計(jì)算,即如何根據(jù)輸入x計(jì)算返回所需要的模型輸出
def forward(self, x):
o = self.act(self.hidden(x))
return self.output(o)
mlp = MLP()
print(list(mlp.parameters()))
print("-------初始化-------")
initialize_weights(mlp)
print(list(mlp.parameters()))
[Parameter containing:
tensor([[[[-0.0073, 0.1146, -0.0839],
[ 0.2442, -0.1130, 0.0334],
[-0.2217, 0.1572, 0.1452]]]], requires_grad=True), Parameter containing:
tensor([0.1457], requires_grad=True), Parameter containing:
tensor([[ 0.2057, -0.1126, -0.2133, -0.1641, 0.0404, -0.0776, -0.2792, -0.2329,
0.0734, -0.0483]], requires_grad=True), Parameter containing:
tensor([-0.2791], requires_grad=True)]
-------初始化-------
[Parameter containing:
tensor([[[[ 0.2118, -0.0682, 0.1048],
[ 0.1412, 0.4079, 0.0789],
[ 0.2269, -0.1477, -0.2181]]]], requires_grad=True), Parameter containing:
tensor([0.3000], requires_grad=True), Parameter containing:
tensor([[-0.1874, 0.3172, -0.6525, -1.3967, 0.7327, 0.5498, -0.3125, 0.5182,
0.2366, 0.0422]], requires_grad=True), Parameter containing:
tensor([0.], requires_grad=True)]
損失函數(shù)
二分類交叉熵?fù)p失函數(shù)-示例
import torch.nn as nn
m = nn.Sigmoid()
loss = nn.BCELoss()
input = torch.randn(3, requires_grad=True)
target = torch.empty(3).random_(2)
output = loss(m(input), target)
output.backward()
print('BCELoss損失函數(shù)的計(jì)算結(jié)果為',output)
BCELoss損失函數(shù)的計(jì)算結(jié)果為 tensor(1.3916, grad_fn=<BinaryCrossEntropyBackward0>)
各種損失函數(shù)
# 二分類交叉熵?fù)p失函數(shù)
torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')
# 交叉熵?fù)p失函數(shù)
torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')
# L1損失函數(shù)
torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
# MSE損失函數(shù)
torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
# 平滑L1 (Smooth L1)損失函數(shù)
torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction='mean', beta=1.0)
# 目標(biāo)泊松分布的負(fù)對(duì)數(shù)似然損失
torch.nn.PoissonNLLLoss(log_input=True, full=False, size_average=None, eps=1e-08, reduce=None, reduction='mean')
# KL散度
torch.nn.KLDivLoss(size_average=None, reduce=None, reduction='mean', log_target=False)
# MarginRankingLoss:計(jì)算兩個(gè)向量之間的相似度,用于排序任務(wù)
torch.nn.MarginRankingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')
# 多標(biāo)簽邊界損失函數(shù)-多標(biāo)簽邊界損失函數(shù)
torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction='mean')
# 二分類損失函數(shù)
torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction='mean')
# 多分類的折頁損失
torch.nn.MultiMarginLoss(p=1, margin=1.0, weight=None, size_average=None, reduce=None, reduction='mean')
# 三元組損失
torch.nn.TripletMarginLoss(margin=1.0, p=2.0, eps=1e-06, swap=False, size_average=None, reduce=None, reduction='mean')
# HingEmbeddingLoss-對(duì)輸出的embedding結(jié)果做Hing損失計(jì)算
torch.nn.HingeEmbeddingLoss(margin=1.0, size_average=None, reduce=None, reduction='mean')
# 余弦相似度
torch.nn.CosineEmbeddingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')
# CTC損失函數(shù)
torch.nn.CTCLoss(blank=0, reduction='mean', zero_infinity=False)
CTCLoss()
訓(xùn)練和評(píng)估
def train(epoch):
model.train()
train_loss = 0
for data, label in train_loader:
data, label = data.cuda(), label.cuda()
optimizer.zero_grad()
output = model(data)
loss = criterion(label, output)
loss.backward()
optimizer.step()
train_loss += loss.item()*data.size(0)
train_loss = train_loss/len(train_loader.dataset)
print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch, train_loss))
def val(epoch):
model.eval()
val_loss = 0
with torch.no_grad():
for data, label in val_loader:
data, label = data.cuda(), label.cuda()
output = model(data)
preds = torch.argmax(output, 1)
loss = criterion(output, label)
val_loss += loss.item()*data.size(0)
running_accu += torch.sum(preds == label.data)
val_loss = val_loss/len(val_loader.dataset)
print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch, val_loss))
Pytorch優(yōu)化器
- torch.optim.ASGD
- torch.optim.Adadelta
- torch.optim.Adagrad
- torch.optim.Adam
- torch.optim.AdamW
- torch.optim.Adamax
- torch.optim.LBFGS
- torch.optim.RMSprop
- torch.optim.Rprop
- torch.optim.SGD
- torch.optim.SparseAdam
Optimizer有三個(gè)屬性:
- defaults:存儲(chǔ)的是優(yōu)化器的超參數(shù)
- state:參數(shù)的緩存
- param_groups:管理的參數(shù)組,是一個(gè)list,其中每個(gè)元素是一個(gè)字典,順序是params,lr,momentum,dampening,weight_decay,nesterov
還有以下方法:
- zero_grad(): 清空所管理參數(shù)的梯度,PyTorch的特性是張量的梯度不自動(dòng)清零,因此每次反向傳播后都需要清空梯度。
- step():執(zhí)行一步梯度更新,參數(shù)更新
- load_state_dict() :加載狀態(tài)參數(shù)字典,可以用來進(jìn)行模型的斷點(diǎn)續(xù)訓(xùn)練,繼續(xù)上次的參數(shù)進(jìn)行訓(xùn)練
- state_dict():獲取優(yōu)化器當(dāng)前狀態(tài)信息字典
每個(gè)優(yōu)化器都是一個(gè)類,我們一定要進(jìn)行實(shí)例化才能使用
optimizer在一個(gè)神經(jīng)網(wǎng)絡(luò)的epoch中需要實(shí)現(xiàn)下面兩個(gè)步驟:
梯度置零
梯度更新
for epoch in range(EPOCH):
...
optimizer.zero_grad() #梯度置零
loss = ... #計(jì)算loss
loss.backward() #BP反向傳播
optimizer.step() #梯度更新
基礎(chǔ)實(shí)戰(zhàn)—FashionMNIST時(shí)裝分類
import os
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
配置訓(xùn)練環(huán)境和超參數(shù)
# 配置GPU,這里有兩種方式
## 方案一:使用os.environ
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
# 方案二:使用“device”,后續(xù)對(duì)要使用GPU的變量用.to(device)即可
device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")
## 配置其他超參數(shù),如batch_size, num_workers, learning rate, 以及總的epochs
batch_size = 4
num_workers = 0 # 對(duì)于Windows用戶,這里應(yīng)設(shè)置為0,否則會(huì)出現(xiàn)多線程錯(cuò)誤
lr = 1e-4
epochs = 2
數(shù)據(jù)讀入和加載
# 首先設(shè)置數(shù)據(jù)變換
from torchvision import transforms
image_size = 28
data_transform = transforms.Compose([
transforms.ToPILImage(),
# 這一步取決于后續(xù)的數(shù)據(jù)讀取方式,如果使用內(nèi)置數(shù)據(jù)集讀取方式則不需要
transforms.Resize(image_size),
transforms.ToTensor()
])
## 讀取方式一:使用torchvision自帶數(shù)據(jù)集,下載可能需要一段時(shí)間
from torchvision import datasets
train_data = datasets.FashionMNIST(root='./', train=True, download=True, transform=data_transform)
test_data = datasets.FashionMNIST(root='./', train=False, download=True, transform=data_transform)
## 讀取方式二:讀入csv格式的數(shù)據(jù),自行構(gòu)建Dataset類
# csv數(shù)據(jù)下載鏈接:https://www.kaggle.com/zalando-research/fashionmnist
class FMDataset(Dataset):
def __init__(self, df, transform=None):
self.df = df
self.transform = transform
self.images = df.iloc[:,1:].values.astype(np.uint8)
self.labels = df.iloc[:, 0].values
def __len__(self):
return len(self.images)
def __getitem__(self, idx):
image = self.images[idx].reshape(28,28,1)
label = int(self.labels[idx])
if self.transform is not None:
image = self.transform(image)
else:
image = torch.tensor(image/255., dtype=torch.float)
label = torch.tensor(label, dtype=torch.long)
return image, label
train_df = pd.read_csv("../data/FashionMNIST/fashion-mnist_train.csv")
test_df = pd.read_csv("../data/FashionMNIST/fashion-mnist_test.csv")
train_data = FMDataset(train_df, data_transform)
test_data = FMDataset(test_df, data_transform)
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, num_workers=num_workers, drop_last=True)
test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False, num_workers=num_workers)
# 這里不知道為啥總是服務(wù)器掛掉,后面再看看
import matplotlib.pyplot as plt
image, label = next(iter(train_loader))
print(image.shape, label.shape)
plt.imshow(image[0][0], cmap="gray")
torch.Size([4, 1, 28, 28]) torch.Size([4])
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 32, 5),
nn.ReLU(),
nn.MaxPool2d(2, stride=2),
nn.Dropout(0.3),
nn.Conv2d(32, 64, 5),
nn.ReLU(),
nn.MaxPool2d(2, stride=2),
nn.Dropout(0.3)
)
self.fc = nn.Sequential(
nn.Linear(64*4*4, 512),
nn.ReLU(),
nn.Linear(512, 10)
)
def forward(self, x):
x = self.conv(x)
x = x.view(-1, 64*4*4)
x = self.fc(x)
# x = nn.functional.normalize(x)
return x
model = Net()
model = model.cuda()
# model = nn.DataParallel(model).cuda() # 多卡訓(xùn)練時(shí)的寫法,之后的課程中會(huì)進(jìn)一步講解
設(shè)定損失函數(shù)
criterion = nn.CrossEntropyLoss()
設(shè)定優(yōu)化器
optimizer = optim.Adam(model.parameters(), lr=0.001)
訓(xùn)練和測試驗(yàn)證
def train(epoch):
model.train()
train_loss = 0
for data, label in train_loader:
data, label = data.cuda(), label.cuda()
optimizer.zero_grad()
output = model(data)
loss = criterion(output, label)
loss.backward()
optimizer.step()
train_loss += loss.item()*data.size(0)
train_loss = train_loss/len(train_loader.dataset)
print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch, train_loss))
def val(epoch):
model.eval()
val_loss = 0
gt_labels = []
pred_labels = []
with torch.no_grad():
for data, label in test_loader:
data, label = data.cuda(), label.cuda()
output = model(data)
preds = torch.argmax(output, 1)
gt_labels.append(label.cpu().data.numpy())
pred_labels.append(preds.cpu().data.numpy())
loss = criterion(output, label)
val_loss += loss.item()*data.size(0)
val_loss = val_loss/len(test_loader.dataset)
gt_labels, pred_labels = np.concatenate(gt_labels), np.concatenate(pred_labels)
acc = np.sum(gt_labels==pred_labels)/len(pred_labels)
print('Epoch: {} \tValidation Loss: {:.6f}, Accuracy: {:6f}'.format(epoch, val_loss, acc))
for epoch in range(1, epochs+1):
train(epoch)
val(epoch)
Epoch: 1 Training Loss: 0.505714
Epoch: 1 Validation Loss: 0.371850, Accuracy: 0.864200
Epoch: 2 Training Loss: 0.393027
Epoch: 2 Validation Loss: 0.329903, Accuracy: 0.878400
模型保存
save_path = "./FahionModel.pkl"
torch.save(model, save_path)