自己定義模型
測試:
correct
= 0total
= 0for data
in test_loader
:img
,label
= dataoutputs
= net
(Variable
(img
))_
,predict
= torch
.max(outputs
.data
,1)total
+= label
.size
(0)correct
+= (predict
== label
).sum()print(str(predict
)+','+str(label
))print(100*correct
/total
)
輸出:
預測錯誤還是挺大的,居然全是1
完整代碼:
```python
import torch
.nn
.functional
as F
import torch
import torch
.nn
as nn
from torch
.autograd
import Variable
from torchvision
import transforms
from torch
.utils
.data
.dataset
import Dataset
from torch
.utils
.data
.dataloader
import DataLoader
from PIL
import Image
import torch
.optim
as optim
import os
learning_rate
= 0.0001
root
= os
.getcwd
() + '\\data\\'
def default_loader(path
):return Image
.open(path
).convert
('RGB')class MyDataset(Dataset
):def __init__(self
, txt
, transform
=None, target_transform
=None,test
= False,loader
=default_loader
):super(MyDataset
, self
).__init__
()imgs
= []fh
= open(txt
, 'r')for line
in fh
: line
= line
.strip
('\n')line
= line
.rstrip
('\n')words
= line
.split
()imgs
.append
((words
[0], int(words
[1])))self
.test
= testself
.imgs
= imgsself
.transform
= transformself
.target_transform
= target_transform
def __getitem__(self
, index
): fn
, label
= self
.imgs
[index
]if self
.test
is False:img_path
= os
.path
.join
("C:\\Users\\pic\\train", fn
)else:img_path
= os
.path
.join
("C:\\Users\\pic\\test", fn
)img
= Image
.open(img_path
).convert
('RGB')if self
.transform
is not None:img
= self
.transform
(img
)return img
, label
def __len__(self
):return len(self
.imgs
)class Net(nn
.Module
): def __init__(self
):super(Net
, self
).__init__
()self
.conv1
= nn
.Conv2d
(3, 6, 5) self
.pool
= nn
.MaxPool2d
(2, 2) self
.conv2
= nn
.Conv2d
(6, 16, 5) self
.fc1
= nn
.Linear
(16 * 5 * 5, 120) self
.fc2
= nn
.Linear
(120, 84)self
.fc3
= nn
.Linear
(84, 2) def forward(self
, x
): x
= self
.pool
(F
.relu
(self
.conv1
(x
))) x
= self
.pool
(F
.relu
(self
.conv2
(x
)))x
= x
.view
(-1, 16 * 5 * 5) x
= F
.relu
(self
.fc1
(x
))x
= F
.relu
(self
.fc2
(x
))x
= self
.fc3
(x
)return xIMG_MEAN
= [0.485, 0.456, 0.406]
IMG_STD
= [0.229, 0.224, 0.225]net
= Net
()
train_data
= MyDataset
(txt
=root
+ 'num.txt', transform
=transforms
.Compose
([transforms
.RandomHorizontalFlip
(), transforms
.Resize
((32, 32)),transforms
.CenterCrop
(32),transforms
.ToTensor
()]))
test_data
= MyDataset
(txt
=root
+'test.txt', transform
=transforms
.Compose
([transforms
.Resize
((32, 32)),transforms
.CenterCrop
(32),transforms
.ToTensor
()]),test
=True)
train_loader
= DataLoader
(dataset
=train_data
, batch_size
=227, shuffle
=True,drop_last
=True)
print('num_of_trainData:', len(train_data
))
test_loader
= DataLoader
(dataset
=test_data
, batch_size
=19, shuffle
=False)def trainandsave():print('h')net
= Net
()optimizer
= optim
.SGD
(net
.parameters
(), lr
=0.001, momentum
=0.9) criterion
= nn
.CrossEntropyLoss
() for epoch
in range(10): running_loss
= 0.0 for i
, data
in enumerate(train_loader
, 0): inputs
, labels
= data inputs
, labels
= Variable
(inputs
), Variable
(labels
) optimizer
.zero_grad
() outputs
= net
(inputs
) loss
= criterion
(outputs
, labels
) loss
.backward
() optimizer
.step
() running_loss
+= loss
.item
() if i
% 9 == 1:print('[%d, %5d] loss: %.3f' %(epoch
+ 1, i
+ 1, running_loss
/ 10)) running_loss
= 0.0 print('Finished Training')torch
.save
(net
, 'net.pkl')torch
.save
(net
.state_dict
(), 'net_params.pkl')
嘗試運行vgg16:
找了很久,預測是參數的問題,輸入圖片是224*224,一開始改的resize但還是報錯,于是改
transforms.CenterCrop((224, 224))
然后data[0]要改成item()
然后運行成功了(好慢。。)
class VGG16(nn
.Module
):def __init__(self
, nums
=2):super(VGG16
, self
).__init__
()self
.nums
= numsvgg
= []vgg
.append
(nn
.Conv2d
(in_channels
=3, out_channels
=64, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.Conv2d
(in_channels
=64, out_channels
=64, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.MaxPool2d
(kernel_size
=2, stride
=2))vgg
.append
(nn
.Conv2d
(in_channels
=64, out_channels
=128, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.Conv2d
(in_channels
=128, out_channels
=128, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.MaxPool2d
(kernel_size
=2, stride
=2))vgg
.append
(nn
.Conv2d
(in_channels
=128, out_channels
=256, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.Conv2d
(in_channels
=256, out_channels
=256, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.Conv2d
(in_channels
=256, out_channels
=256, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.MaxPool2d
(kernel_size
=2, stride
=2))vgg
.append
(nn
.Conv2d
(in_channels
=256, out_channels
=512, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.Conv2d
(in_channels
=512, out_channels
=512, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.Conv2d
(in_channels
=512, out_channels
=512, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.MaxPool2d
(kernel_size
=2, stride
=2))vgg
.append
(nn
.Conv2d
(in_channels
=512, out_channels
=512, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.Conv2d
(in_channels
=512, out_channels
=512, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.Conv2d
(in_channels
=512, out_channels
=512, kernel_size
=3, stride
=1, padding
=1))vgg
.append
(nn
.ReLU
())vgg
.append
(nn
.MaxPool2d
(kernel_size
=2, stride
=2))self
.main
= nn
.Sequential
(*vgg
)classfication
= []classfication
.append
(nn
.Linear
(in_features
=512 * 7 * 7, out_features
=4096)) classfication
.append
(nn
.ReLU
())classfication
.append
(nn
.Dropout
(p
=0.5))classfication
.append
(nn
.Linear
(in_features
=4096, out_features
=4096))classfication
.append
(nn
.ReLU
())classfication
.append
(nn
.Dropout
(p
=0.5))classfication
.append
(nn
.Linear
(in_features
=4096, out_features
=self
.nums
))self
.classfication
= nn
.Sequential
(*classfication
)def forward(self
, x
):feature
= self
.main
(x
) feature
= feature
.view
(x
.size
(0), -1) result
= self
.classfication
(feature
)return resultnet
= Net
()
train_data
= MyDataset
(txt
=root
+ 'num.txt', transform
=transforms
.Compose
([transforms
.RandomHorizontalFlip
(),
transforms
.Resize
((224, 224)),
transforms
.CenterCrop
((224, 224)),transforms
.ToTensor
()]))
test_data
= MyDataset
(txt
=root
+'test.txt', transform
=transforms
.Compose
([transforms
.Resize
((32, 32)),transforms
.CenterCrop
(32),transforms
.ToTensor
()]),test
=True)
train_loader
= DataLoader
(dataset
=train_data
, batch_size
=16, shuffle
=True,drop_last
=True)
print('num_of_trainData:', len(train_data
))
test_loader
= DataLoader
(dataset
=test_data
, batch_size
=19, shuffle
=False)if __name__
== '__main__':vgg
= VGG16
()optimizer
= optim
.SGD
(vgg
.parameters
(), lr
=0.001, momentum
=0.9) criterion
= nn
.CrossEntropyLoss
() for epoch
in range(10): running_loss
= 0.0 train_loss
= 0.train_acc
= 0.for i
, data
in enumerate(train_loader
, 0): inputs
, labels
= data inputs
, labels
= Variable
(inputs
), Variable
(labels
) optimizer
.zero_grad
() outputs
= vgg
(inputs
) loss
= criterion
(outputs
, labels
) train_loss
+= loss
.item
()pred
= torch
.max(outputs
, 1)[1]train_correct
= (pred
== labels
).sum()train_acc
+= train_correct
.item
()loss
.backward
() optimizer
.step
() running_loss
+= loss
.item
() print('Train Loss: {:.6f}, Acc: {:.6f}'.format(train_loss
/ (len(train_data
)), train_acc
/ (len(train_data
))))print('Finished Training')torch
.save
(net
, 'net.pkl')torch
.save
(net
.state_dict
(), 'net_params.pkl')
嘗試將損失函數修改:
optimizer = optim.Adam(vgg.parameters(), lr=1e-6) # 學習率為0.001
結果仍然不理想。懷疑是數據集有過大誤差。
載入已有模型進行參數優化
兩個主要的遷移學習場景:
Finetuning the convnet: 我們使用預訓練網絡初始化網絡,而不是隨機初始化,就像在imagenet 1000數據集上訓練的網絡一樣。其余訓練看起來像往常一樣。(此微調過程對應引用中所說的初始化)
ConvNet as fixed feature extractor: 在這里,我們將凍結除最終完全連接層之外的所有網絡的權重。最后一個全連接層被替換為具有隨機權重的新層,并且僅訓練該層。(此步對應引
用中的固定特征提取器
用加載預訓練模型并重置最終的全連接層的方法進行訓練。
每一個epoch都進行訓練和測試。我寫的是resnet18(先自己網上下載pkl文件,在pycharm里面下載太慢)
目前的全部代碼:
from __future__
import print_function
, division
import torch
import torch
.nn
as nn
import torch
.optim
as optim
from torch
.optim
import lr_scheduler
import numpy
as np
import torchvision
from torchvision
import datasets
, models
, transforms
import matplotlib
.pyplot
as plt
import time
import os
import copy
import torchvision
.models
as modelsdata_transforms
= {
'train': transforms
.Compose
([transforms
.RandomResizedCrop
(224),transforms
.RandomHorizontalFlip
(),transforms
.ToTensor
(),transforms
.Normalize
([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),'val': transforms
.Compose
([transforms
.Resize
(256),transforms
.CenterCrop
(224),transforms
.ToTensor
(),transforms
.Normalize
([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),}data_dir
=os
.getcwd
() + '\\data\\'
image_datasets
= {x
: datasets
.ImageFolder
(os
.path
.join
(data_dir
, x
),data_transforms
[x
]) for x
in ['train', 'val']}
dataloaders
= {x
: torch
.utils
.data
.DataLoader
(image_datasets
[x
], batch_size
=4,shuffle
=True) for x
in ['train', 'val']}
dataset_sizes
= {x
: len(image_datasets
[x
]) for x
in ['train', 'val']}
device
= torch
.device
("cuda:0" if torch
.cuda
.is_available
() else "cpu")
def imshow(inp
, title
=None):"""Imshow for Tensor."""inp
= inp
.numpy
().transpose
((1, 2, 0))mean
= np
.array
([0.485, 0.456, 0.406])std
= np
.array
([0.229, 0.224, 0.225])inp
= std
* inp
+ meaninp
= np
.clip
(inp
, 0, 1)plt
.imshow
(inp
)if title
is not None:plt
.title
(title
)plt
.pause
(0.001) def train_model(model
, criterion
, optimizer
, scheduler
, num_epochs
=25):since
= time
.time
()best_model_wts
= copy
.deepcopy
(model
.state_dict
())best_acc
= 0.0for epoch
in range(num_epochs
):print('Epoch {}/{}'.format(epoch
, num_epochs
- 1))print('-' * 10)for phase
in ['train', 'val']:if phase
== 'train':scheduler
.step
()model
.train
() running_loss
= 0.0running_corrects
= 0for inputs
, labels
in dataloaders
[phase
]:optimizer
.zero_grad
()with torch
.set_grad_enabled
(phase
== 'train'):outputs
= model
(inputs
)_
,preds
= torch
.max(outputs
, 1)loss
= criterion
(outputs
, labels
)if phase
== 'train':loss
.backward
()optimizer
.step
()running_loss
+= loss
.item
() * inputs
.size
(0)running_corrects
+= torch
.sum(preds
== labels
.data
)epoch_loss
= running_loss
/ dataset_sizes
[phase
]epoch_acc
= running_corrects
.double
() / dataset_sizes
[phase
]print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase
, epoch_loss
, epoch_acc
))
if phase
== 'val' and epoch_acc
> best_acc
:best_acc
= epoch_accbest_model_wts
= copy
.deepcopy
(model
.state_dict
())print()time_elapsed
= time
.time
() - since
print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed
// 60, time_elapsed
% 60))print('Best val Acc: {:4f}'.format(best_acc
))model
.load_state_dict
(best_model_wts
)return modelclass_names
= image_datasets
['train'].classes
def visualize_model(model
, num_images
=6):was_training
= model
.trainingmodel
.eval()images_so_far
= 0fig
= plt
.figure
()with torch
.no_grad
():for i
, (inputs
, labels
) in enumerate(dataloaders
['val']):outputs
= model
(inputs
)_
, preds
= torch
.max(outputs
, 1)for j
in range(inputs
.size
()[0]):images_so_far
+= 1ax
= plt
.subplot
(num_images
// 2, 2, images_so_far
)ax
.axis
('off')ax
.set_title
('predicted: {}'.format(class_names
[preds
[j
]]))imshow
(inputs
.cpu
().data
[j
])if images_so_far
== num_images
:model
.train
(mode
=was_training
)returnmodel
.train
(mode
=was_training
)model_ft
= models
.resnet18
(pretrained
=False)
pthfile
= r'C:\Users\14172\PycharmProjects\pythonProject4\resnet18-5c106cde.pth'
model_ft
.load_state_dict
(torch
.load
(pthfile
))
num_ftrs
= model_ft
.fc
.in_features
model_ft
.fc
= nn
.Linear
(num_ftrs
, 2)
criterion
= nn
.CrossEntropyLoss
()
optimizer_ft
= optim
.SGD
(model_ft
.parameters
(), lr
=0.001, momentum
=0.9)
exp_lr_scheduler
= lr_scheduler
.StepLR
(optimizer_ft
, step_size
=7, gamma
=0.1)
model_ft
= train_model
(model_ft
, criterion
, optimizer_ft
, exp_lr_scheduler
,num_epochs
=25)
torch
.save
(model_ft
, 'modefresnet.pkl')
torch
.save
(model_ft
.state_dict
(), 'modelresnet_params.pkl')
visualize_model
(model_ft
)
兩者差距還是比較大,后期再進行調整。先記錄。
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的【pytorch】pytorch自定义训练vgg16和测试数据集 微调resnet18全连接层的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。