以下都是我学习的一些笔记,记录一下。
这次我们用经典项目:猫狗大战来进行学习。
首先是数据集下载,这里就不提供下载了,网上有很多的
1.首先我们导入可能要用到的包,如下:
import torch
import torchvision
from torchvision import datasets,transforms
import os #os包集成了一些对文件路径和目录操作的类
import matplotlib.pyplot as plt
import time
from torch.autograd import Variable
2.数据的载入以及装载,代码如下:
data_dir = "DogsVSCats"
data_transform = {x:transforms.Compose([transforms.Resize([64,64]),#统一将图片缩放至64*64
transforms.ToTensor()])
for x in ["train","valid"]}
image_datasets = {x:datasets.ImageFolder(root=os.path.join(data_dir,x),
transform = data_transform[x])
for x in ["train","valid"]}
dataloader = {x:torch.utils.data.DataLoader(dataset = image_datasets[x],
batch_size = 16,
shuffle = True)
for x in ["train","valid"]}
3.数据的预览
代码如下:
X_example,y_example = next(iter(dataloader["train"]))
print(u"X_example个数{}".format(len(X_example)))
print(u"y_example个数{}".format(len(y_example)))
index_classes = image_datasets["train"].class_to_idx
print(index_classes)
example_clasees = image_datasets["train"].classes #example_clasees 变量其实就是一个列表
print(example_clasees)
img = torchvision.utils.make_grid(X_example)
img = img.numpy().transpose([1,2,0])
print([example_clasees[i] for i in y_example])
plt.imshow(img)
plt.show()
结果如图所示:
4.构建网络模型,这边先自定义一个VGG网络,搭建一个简单的VGG网络。
代码如下:
#Vgg自定义框架
class Models(torch.nn.Module):
def __init__(self):
super(Models,self).__init__()
self.Conv = torch.nn.Sequential(
torch.nn.Conv2d(3,64,kernel_size=3,stride=1,padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(64,64,kernel_size=3,stride=1,padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2,stride=2),
torch.nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2),
torch.nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2),
torch.nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2),
)
self.Classes = torch.nn.Sequential(
torch.nn.Linear(4*4*512,1024),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(1024,1024),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(1024, 2),
)
def forward(self,input):
x = self.Conv(input)
x = x.view(-1,4*4*512)
x = self.Classes(x)
return x
5.训练即可,代码如下:
loss_f = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(),lr = 0.00001)
epoch_n = 10
time_open = time.time()
for epoch in range(epoch_n):
print("Epoch {}/{}".format(epoch, epoch_n - 1))
print("-" * 10)
for phase in ["train","valid"]:
if phase == "train":
print("Training.....")
model.train(True)
else:
print("Validing....")
model.train(False)
running_loss = 0.0 # 损失的数值
running_corrects = 0 # 预测的正确数目
for batch,data in enumerate(dataloader[phase],1):
X,y = data
X,y = Variable(X),Variable(y)
y_pred = model(X)
_,pred = torch.max(y_pred.data,1)
optimizer.zero_grad()
loss = loss_f(y_pred, y)
if phase == "train":
loss.backward() # 反向传播求导
optimizer.step()
running_loss += loss.item() # 累计所有的损失值
running_corrects += torch.sum(pred == y.data) # 累计所有的正确次数
if batch%500 == 0 and phase =="train":
print("Batch{},Train Loss:{:.4f},Train ACC:{:.4f}".format(
batch,torch.true_divide(running_loss,batch),100*torch.true_divide(running_corrects,16*batch)
))
epoch_loss = torch.true_divide(running_loss*16,len(image_datasets[phase]))
epoch_acc = 100*torch.true_divide(running_corrects,len(image_datasets[phase]))
print("{} Loss:{:.4f},Acc:{:.4f}%".format(phase,epoch_loss,epoch_acc))
time_end = time.time() - time_open
print(time_end)
到这里就结束训练与测试了,建议大家用GPU,不然CPU会花费很多的时间。
这不是今天讲的重点,今天我要记录的重点是迁移模型,很明显大家去运行测试结果发现,效果并不理想,我们可以适当的换其他模型试试。
(1)VGG16
既然要用到VGG16,那么如何使用呢,请看代码:
#迁移Vgg16
model = models.vgg16(progress=True) #迁移代码
这段直接调用VGG16,没有的会自动下载,建议下载好放到对应的文件中,不然速度感人。
打印一下模型,可以看到(没截全):
当然现在还不能用,因为我们可以看到原来的VGG16模型最终从全连接层输出的是4096个结果,而我们只需要输出两个,增加如下代码:
for parma in model.parameters():
parma.requires_grad = False
model.classifier = torch.nn.Sequential(torch.nn.Linear(25088,4096),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(4096,4096),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(4096,2)
)
上面的代码第一行,将他置为False就是不进行梯度更新,就是我们所说的冻结操作,只修改最后的地方即可。
其他的代码都没有变化,运行之后发现结果会比上一次好很多。
VGG16完整代码如下:
import torch
import torchvision
from torchvision import datasets,transforms,models
import os #os包集成了一些对文件路径和目录操作的类
import matplotlib.pyplot as plt
import time
from torch.autograd import Variable
data_dir = "DogsVSCats"
data_transform = {x:transforms.Compose([transforms.Resize([64,64]),#统一将图片缩放至64*64
transforms.ToTensor()])
for x in ["train","valid"]}
image_datasets = {x:datasets.ImageFolder(root=os.path.join(data_dir,x),
transform = data_transform[x])
for x in ["train","valid"]}
dataloader = {x:torch.utils.data.DataLoader(dataset = image_datasets[x],
batch_size = 16,
shuffle = True)
for x in ["train","valid"]}
X_example,y_example = next(iter(dataloader["train"]))
print(u"X_example个数{}".format(len(X_example)))
print(u"y_example个数{}".format(len(y_example)))
index_classes = image_datasets["train"].class_to_idx
print(index_classes)
example_clasees = image_datasets["train"].classes #example_clasees 变量其实就是一个列表
print(example_clasees)
img = torchvision.utils.make_grid(X_example)
img = img.numpy().transpose([1,2,0])
print([example_clasees[i] for i in y_example])
plt.imshow(img)
plt.show()
# #Vgg自定义框架
# class Models(torch.nn.Module):
# def __init__(self):
# super(Models,self).__init__()
# self.Conv = torch.nn.Sequential(
# torch.nn.Conv2d(3,64,kernel_size=3,stride=1,padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(64,64,kernel_size=3,stride=1,padding=1),
# torch.nn.ReLU(),
# torch.nn.MaxPool2d(kernel_size=2,stride=2),
#
# torch.nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.MaxPool2d(kernel_size=2, stride=2),
#
# torch.nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.MaxPool2d(kernel_size=2, stride=2),
#
# torch.nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.MaxPool2d(kernel_size=2, stride=2),
# )
# self.Classes = torch.nn.Sequential(
# torch.nn.Linear(4*4*512,1024),
# torch.nn.ReLU(),
# torch.nn.Dropout(p=0.5),
# torch.nn.Linear(1024,1024),
# torch.nn.ReLU(),
# torch.nn.Dropout(p=0.5),
# torch.nn.Linear(1024, 2),
# )
#
# def forward(self,input):
# x = self.Conv(input)
# x = x.view(-1,4*4*512)
# x = self.Classes(x)
# return x
#迁移Vgg16
model = models.vgg16(progress=True) #迁移代码
#调整迁移过来的模型 原来的模型输出有1000个,我们只需要两个
for parma in model.parameters():
parma.requires_grad = False
model.classifier = torch.nn.Sequential(torch.nn.Linear(25088,4096),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(4096,4096),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(4096,2)
)
print(model)
loss_f = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(),lr = 0.00001)
epoch_n = 10
time_open = time.time()
for epoch in range(epoch_n):
print("Epoch {}/{}".format(epoch, epoch_n - 1))
print("-" * 10)
for phase in ["train","valid"]:
if phase == "train":
print("Training.....")
model.train(True)
else:
print("Validing....")
model.train(False)
running_loss = 0.0 # 损失的数值
running_corrects = 0 # 预测的正确数目
for batch,data in enumerate(dataloader[phase],1):
X,y = data
X,y = Variable(X),Variable(y)
y_pred = model(X)
_,pred = torch.max(y_pred.data,1)
optimizer.zero_grad()
loss = loss_f(y_pred, y)
if phase == "train":
loss.backward() # 反向传播求导
optimizer.step()
running_loss += loss.item() # 累计所有的损失值
running_corrects += torch.sum(pred == y.data) # 累计所有的正确次数
if batch%500 == 0 and phase =="train":
print("Batch{},Train Loss:{:.4f},Train ACC:{:.4f}".format(
batch,torch.true_divide(running_loss,batch),100*torch.true_divide(running_corrects,16*batch)
))
epoch_loss = torch.true_divide(running_loss*16,len(image_datasets[phase]))
epoch_acc = 100*torch.true_divide(running_corrects,len(image_datasets[phase]))
print("{} Loss:{:.4f},Acc:{:.4f}%".format(phase,epoch_loss,epoch_acc))
time_end = time.time() - time_open
print(time_end)
(2)迁移ResNet50
废话不多说,与之前的都一样,调用以及只需修改全连接层的输出部分,代码如下:
model = models.resnet50(pretrained=True) #迁移代码
for parma in model.parameters():
parma.requires_grad = False
model.fc = torch.nn.Linear(2048,2)
此处附上完整代码:
import torch
import torchvision
from torchvision import datasets,transforms,models
import os #os包集成了一些对文件路径和目录操作的类
import matplotlib.pyplot as plt
import time
from torch.autograd import Variable
data_dir = "DogsVSCats"
data_transform = {x:transforms.Compose([transforms.Resize([64,64]),#统一将图片缩放至64*64
transforms.ToTensor()])
for x in ["train","valid"]}
image_datasets = {x:datasets.ImageFolder(root=os.path.join(data_dir,x),
transform = data_transform[x])
for x in ["train","valid"]}
dataloader = {x:torch.utils.data.DataLoader(dataset = image_datasets[x],
batch_size = 16,
shuffle = True)
for x in ["train","valid"]}
X_example,y_example = next(iter(dataloader["train"]))
print(u"X_example个数{}".format(len(X_example)))
print(u"y_example个数{}".format(len(y_example)))
index_classes = image_datasets["train"].class_to_idx
print(index_classes)
example_clasees = image_datasets["train"].classes #example_clasees 变量其实就是一个列表
print(example_clasees)
img = torchvision.utils.make_grid(X_example)
img = img.numpy().transpose([1,2,0])
print([example_clasees[i] for i in y_example])
plt.imshow(img)
plt.show()
# #Vgg自定义框架
# class Models(torch.nn.Module):
# def __init__(self):
# super(Models,self).__init__()
# self.Conv = torch.nn.Sequential(
# torch.nn.Conv2d(3,64,kernel_size=3,stride=1,padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(64,64,kernel_size=3,stride=1,padding=1),
# torch.nn.ReLU(),
# torch.nn.MaxPool2d(kernel_size=2,stride=2),
#
# torch.nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.MaxPool2d(kernel_size=2, stride=2),
#
# torch.nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.MaxPool2d(kernel_size=2, stride=2),
#
# torch.nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1),
# torch.nn.ReLU(),
# torch.nn.MaxPool2d(kernel_size=2, stride=2),
# )
# self.Classes = torch.nn.Sequential(
# torch.nn.Linear(4*4*512,1024),
# torch.nn.ReLU(),
# torch.nn.Dropout(p=0.5),
# torch.nn.Linear(1024,1024),
# torch.nn.ReLU(),
# torch.nn.Dropout(p=0.5),
# torch.nn.Linear(1024, 2),
# )
#
# def forward(self,input):
# x = self.Conv(input)
# x = x.view(-1,4*4*512)
# x = self.Classes(x)
# return x
#迁移Resnet50
model = models.resnet50(pretrained=True) #迁移代码
#调整迁移过来的模型 原来的模型输出有1000个,我们只需要两个
for parma in model.parameters():
parma.requires_grad = False
model.fc = torch.nn.Linear(2048,2)
print(model)
loss_f = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(),lr = 0.00001)
epoch_n = 10
time_open = time.time()
for epoch in range(epoch_n):
print("Epoch {}/{}".format(epoch, epoch_n - 1))
print("-" * 10)
for phase in ["train","valid"]:
if phase == "train":
print("Training.....")
model.train(True)
else:
print("Validing....")
model.train(False)
running_loss = 0.0 # 损失的数值
running_corrects = 0 # 预测的正确数目
for batch,data in enumerate(dataloader[phase],1):
X,y = data
X,y = Variable(X),Variable(y)
y_pred = model(X)
_,pred = torch.max(y_pred.data,1)
optimizer.zero_grad()
loss = loss_f(y_pred, y)
if phase == "train":
loss.backward() # 反向传播求导
optimizer.step()
running_loss += loss.item() # 累计所有的损失值
running_corrects += torch.sum(pred == y.data) # 累计所有的正确次数
if batch%500 == 0 and phase =="train":
print("Batch{},Train Loss:{:.4f},Train ACC:{:.4f}".format(
batch,torch.true_divide(running_loss,batch),100*torch.true_divide(running_corrects,16*batch)
))
epoch_loss = torch.true_divide(running_loss*16,len(image_datasets[phase]))
epoch_acc = 100*torch.true_divide(running_corrects,len(image_datasets[phase]))
print("{} Loss:{:.4f},Acc:{:.4f}%".format(phase,epoch_loss,epoch_acc))
time_end = time.time() - time_open
print(time_end)
笔记记的不好,尽情谅解,代码参考的书籍《深度学习之Pytorch实战计算机视觉》