参考来自PyTorch从入门到放弃(目录) - 二十三岁的有德 - 博客园 (cnblogs.com)
torch.cat(inputs, dimension=0) → Tensor
链接(dim=0是列链接,1是航链接)
torch.chunk(tensor, chunks, dim=0)
切割,cat的反向操作
torch.gather(input, dim, index, out=None) → Tensor
沿着不同维度取出tensor的值:
’
torch.index_select(input, dim, index, out=None) → Tensor
切片,针对不同维度
torch.nonzero(input, out=None) → LongTensor
返回不是0的下标
利用torch解决线性回归问题:
- import numpy as np
- import torch
- import torch.nn as nn
- x=np.arange(1,12,dtype=np.float32).reshape(-1,1)
- y=2*x+3
- class LinearRegressionModel(nn.Module):
- def __init__(self,input_dim,output_dim):
- super().__init__()
- self.linear=nn.Linear(input_dim,output_dim)
- def forward(self,inp):
- out=self.linear(inp)
- return out
- regression_model=LinearRegressionModel(1,1)
- device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
- regression_model.to(device)
- epochs=20
- learning_rate=0.01
- optimizer=torch.optim.SGD(regression_model.parameters(),learning_rate)
- criterion=nn.MSELoss()
- for epoch in range(epochs):
- inputs=torch.from_numpy(x).to(device)
- labels=torch.from_numpy(y).to(device)
- optimizer.zero_grad()
- outputs=regression_model(inputs)
- loss=criterion(outputs,labels)
- loss.backward()
- optimizer.step()
-
- if epoch%10==0:
- print("epoch:",epoch,"loss:",loss.item())
-
- predict=regression_model(torch.from_numpy(x).requires_grad()).data.numpy()
- torch.save(regression_model.state_dict(),"model.pk1")
- result=regression_model.load_state_dict(torch.load("model.pk1"))
用nn手写网络lenet网络
- import torch as t
- import torch.nn as nn
- import torch.nn.functional as F
- from torch.autograd import Variable as V
- from matplotlib import pyplot as plt
- from IPython import display
-
- class Net(nn.Module):
- def __init__(self):
- super(Net,self).__init__()
- self.conv1=nn.Conv2d(1,6,5)
- 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,10)
-
- def forward(self,x):
- x=self.conv1(x)
- x=F.relu(x)
- x=F.max_pool2d(x,(2,2))
- x=self.conv2(x)
- x=F.relu(x)
- x=F.max_pool2d(x,2)
-
- x=x.view(x.size()[0],-1)
- x=F.relu(self.fc1(x))
- x=F.relu(self.fc2(x))
- x=self.fc3(x)
-
- return x
- net=Net()
- print(net)
-
练习:
- input=V(t.randn(1,1,32,32))
- out=net(input)
- output=net(input)
- target=V(t.arange(0,10)).view(1,10).float()
- criterion=nn.MSELoss()
- loss=criterion(output,target)
- optimizer=optim.SGD(net.parameters(),lr=0.01)
- optimizer.zero_grad()
- output=net(input)
- loss=criterion(output,target)
- loss.backward()
- optimizer.step()
全连接层
- import torch as t
- import torch.nn as nn
- import torch.nn.functional as F
- from torch.autograd import Variable as V
- from matplotlib import pyplot as plt
- from IPython import display
- import torch.optim as optim
-
- class Linear(nn.Module):
- def __init__(self,in_features,out_features):
- super(Linear,self).__init__()
- self.w=nn.Parameter(t.randn(in_features,out_features))
- self.b=nn.Parameter(t.randn(out_features))
- def forward(self,x):
- x=x.mm(self.w)
- return x+self.b.expand_as(x)
- layer=Linear(4,3)
- input=V(t.randn(2,4))
- output=layer(input)
- print(output)
构建多层全连接网络:
- import torch as t
- import torch.nn as nn
- import torch.nn.functional as F
- from torch.autograd import Variable as V
- from matplotlib import pyplot as plt
- from IPython import display
- import torch.optim as optim
- class Linear(nn.Module):
- def __init__(self, in_features, out_features): # 输入的数据维度,输出的数据维度
- super(Linear,
- self).__init__() # 等价于 nn.Module.__init__(self),继承父类的init构造函数
- self.w = nn.Parameter(t.randn(in_features, out_features))
- self.b = nn.Parameter(t.randn(out_features))
-
- def forward(self, x):
- x = x.mm(self.w)
- return x + self.b.expand_as(x)
-
- class Perceptron(nn.Module):
- def __init__(self,in_features,hidden_features,out_features):
- super(Perceptron,self).__init__()
- self.layer1=Linear(in_features,hidden_features)
- self.layer2=Linear(hidden_features,out_features)
- def forward(self,x):
- x=self.layer1(x)
- x=t.sigimoid(x)
- x=self.layer2(x)
- return x
- perceptron=Perceptron(3,4,1)
- for name,param in perceptron.named_parameters():
- print(name,param.size())
常用的神经网络层:
1.显示图片(温客行yyds)
- import torch as t
- import torch.nn as nn
- import torch.nn.functional as F
- from torch.autograd import Variable as V
- from matplotlib import pyplot as plt
- from IPython import display
- import torch.optim as optim
- from PIL import Image
- from torchvision.transforms import ToTensor,ToPILImage
- to_tensor=ToTensor()
- to_pil=ToPILImage()
- nick=Image.open('G:/3.bmp')
- nick.show()
加锐化卷积
- import torch as t
- import torch.nn as nn
- import torch.nn.functional as F
- from torch.autograd import Variable as V
- from matplotlib import pyplot as plt
- from IPython import display
- import torch.optim as optim
- from PIL import Image
- from torchvision.transforms import ToTensor,ToPILImage
- to_tensor=ToTensor()
- to_pil=ToPILImage()
- yeye=Image.open('G:/3.bmp')
- inp=to_tensor(yeye).unsqueeze(0)
- kernel=t.ones(3,3,3)/-9
- kernel[:,1,1]=1
-
- conv=nn.Conv2d(
- in_channels=3 , #彩色图
- out_channels=1,
- kernel_size=3,
- stride=1,
- bias=False
-
-
- )
- conv.weight.data=kernel.view(1,3,3,3)
- #输出通道数和卷积核数一样,1代表卷积核数,3代表输入数,后两个为卷积核尺寸
- out=conv(V(inp))
- y=to_pil(out.data.squeeze(0))
- y.show()
加普通卷积
- import torch as t
- import torch.nn as nn
- import torch.nn.functional as F
- from torch.autograd import Variable as V
- from matplotlib import pyplot as plt
- from IPython import display
- import torch.optim as optim
- from PIL import Image
- from torchvision.transforms import ToTensor,ToPILImage
- to_tensor=ToTensor()
- to_pil=ToPILImage()
- yeye=Image.open('G:/3.bmp')
- inp=to_tensor(yeye).unsqueeze(0)
- conv=nn.Conv2d(
- in_channels=3,
- out_channels=1,
- kernel_size=3,
- stride=1,
- bias=False
-
-
- )
- out=conv(V(inp))
- y=to_pil(out.data.squeeze(0))
- y.show()
通过Sequential 构建前馈传播网络
三种:
- net1=nn.Sequential()
- net1.add_module('conv',nn.Conv2d(3,3,3))
- net1.add_module('batchnorm',nn.BatchNorm2d(3))
- net1.add_module('activation_layer',nn.ReLU())
- net2=nn.Sequential(nn.Conv2d(3,3,3),nn.BatchNorm2d(3),nn.ReLU())
-
- from collections import OrderedDict
- net3=nn.Sequential(
- OrderedDict([('conv1',nn.Conv2d(3,3,3)),
- ('bn1',nn.BatchNorm2d(3)),
- ('relu',nn.ReLU())])
- )
- modellist=nn.ModuleList([nn.Linear(3,4),nn.ReLU(),nn.Linear(4,2)])
- inp=V(t.rand(1,3))
- for model in modellist:
- inp=model(inp)
- class MyModule(nn.Module):
- def __init__(self):
- super(MyModule,self).__init__()
- self.list=[nn.Linear(3,4),nn.ReLU()]
- self.module_list=nn.ModuleList([nn.Conv2d(3,3,3),nn.ReLU()])
- def forward(self):
- pass
- model=MyModule()
- print(model)
循环神经网络层
- t.manual_seed(1000)
- inp=V(t.randn(2,3,4))#长度为2,batchsize为3,每个元素占4维
- lstm=nn.LSTM(4,3,1)#4维,3个隐藏元,1层
-
-
- h0=V(t.randn(1,3,3))
- c0=V(t.randn(1,3,3))
- out,hn=lstm(inp,(h0,c0))
- print(out)
词向量在自然语言中应用十分广泛,torch 同样也提供了 Embedding 层
- embedding=nn.Embedding(4,5)
- embedding.weight.data=t.arange(0,20).view(4,5)
- with t.no_grad():
- inp=V(t.arange(3,0,-1)).long()
- output=embedding(inp)
- print(output)
损失函数
- score=V(t.randn(3,2))
- label=V(t.Tensor([1,0,1])).long()
- criterion=nn.CrossEntropyLoss()
- loss=criterion(score,label)
- print(loss)
优化器:
- class Net(nn.Module):
- def __init__(self):
- super(Net,self).__init__()
- self.features=nn.Sequential(nn.Conv2d(3,6,2),
- nn.ReLU(),
- nn.MaxPool2d(2,2),
- nn.Conv2d(6,16,5),
- nn.ReLU(),
- nn.MaxPool2d(2,2))
- self.classifier=nn.Sequential(nn.Linear(16*5*5,120),
- nn.ReLU(),
- nn.Linear(120,84),
- nn.ReLU(),
- nn.Linear(84,10))
- def forward(self,x):
- x=self.features(x)
- x=x.view(-1,16*5*5)
- x=self.classifier(x)
- return x
- net=Net()
- optimizer=optim.SGD(params=net.parameters(),lr=0.01)
- optimizer.zero_grad()
- inp=V(t.randn(1,3,32,32))
- output=net(inp)
- output.backward(output)
- optimizer.step()
- #针对不同的网络设置不同学习率
- ptimizer=optim.SGD(
- [
- {
- 'params':net.features.parameters()
-
- },
- {
- 'params':net.classifier.parameters(),
- 'lr':1e-2
-
- },
- ],
- lr=1e-5
- )
nn.functional 和 nn.Module 的区别
- inp=V(t.randn(2,3))
- model=nn.Linear(3,4)
- output1=model(inp)
- output2=nn.functional.linear(inp,model.weight,model.bias)
- class MyLinear(nn.Module):
- def __init__(self):
- super(MyLinear,self).__init__()
- self.weight=nn.Parameter(t.randn(3,4))
- self.bias=nn.Parameter(t.zeros(3))
-
- def forward(self):
- return F.linear(input,self.weight,self.bias)
-
-
- class ResidualBlock(nn.Module):
- def __init__(self,inchannel,outchannel,stride=1,shortcut=None):
- super(ResidualBlock,self).__init__()
-
- self.left=nn.Sequential(
- nn.Conv2d(inchannel,outchannel,3,stride,1,bias=False),
- nn.BatchNorm2d(outchannel),
- nn.ReLU(inplace=True),
- nn.Conv2d(outchannel,outchannel,3,1,1,bias=False),
- nn.BatchNorm(outchannel)
- )
- self.right=shortcut
- def forward(self,x):
- out=self.left(x)
- residual=x if self.right is None else self.right(x)
- out=out+residual
- out=F.relu(out)
- return out
- class ResNet(nn.Module):
- def __init__(self,num_classes=1000):
- super(ResNet,self).__init__()
- self.pre=nn.Sequential(
- nn.conv2d(3,64,7,2,3,bias=False),
- nn.BatchNorm2d(64),
- nn.ReLU(inplace=True),
- nn.MaxPool2d(3,2,1),
- )
- self.layer1=self._make_layer(64,128,3)
- self.layer2=self._make_layer(128,256,4,stride=2)
- self.layer3=self._make_layer(256,512,6,stride=2)
- self.layer4=self._make_layer(512,512,3,stride=2)
-
-
- self.fc=nn.Linear(512,num_classes)
- def _make_layer(self,inchannel,outchannel,block_num,stride=1):
- shortcut=nn.Sequential(
- nn.Conv2d(inchannel,outchannel,1,stride,bias=False),
- nn.BatchNorm2d(outchannel)
- )
- layers=[]
- layers.append(ResidualBlock(inchannel,outchannel,stride,shortcut))
- for i in range(1,block_num):
-
- layers.append(ResidualBlock(outchannel,outchannel))
- return nn.Sequential(*layers)
- def forward(self,x):
- x=self.pre(x)
- x=self.layer1(x)
- x=self.layer2(x)
- x=self.layer3(x)
- x=self.layer4(x)
-
- x=F.avg_pool2d(x,7)
- x=x.view(x.size(0),-1)
- res_net=ResNet()
- inp=t.autograd.Variable(t.randn(1,3,224,224))
- output=res_net(inp)
- from torchvision import models
- res_net=models.resnet34()
- inp=t.autograd.Variable(t.randn(1,3,224,224))
- output=res_net(inp)
- output.size()
tensor对象保存
- import torch as t
- a=t.Tensor(3,4)
- if t.cuda.is_available():
- a=a.cuda(1)
- t.save(a,'a.pth')
-
- b=t.load('a.pth')
- c=t.load('a.pth',map_location=lambda storage,loc:storage)
- d=t.load('a.pth',map_location={'cuda:1','cuda:0'})
Module 对象的保存和加载
- import torch as t
- t.set_default_tensor_type('torch.FloatTensor')
- from torchvision.models import AlexNet
- model=AlexNet()
- model.state_dict().keys()
- t.save(model.state_dict(),'alexnet.pth')
- model.load_state_dict(t.load('alexnet.pth'))
- optimizer=t.optim.Adam(model.parameters(),lr=0.1)
- t.save(optimizer.state_dict(),'optimizer.pth')
- optimizer.load_state_dict(t.load('optimizer.pth'))
模型定义
数据处理和加载
训练模型(Train & Validate)
训练过程可视化
测试(Test/Inference)
- checkpoints/
- data/
- __init__.py
- dataset.py
- get_data.sh
-
- models/
- __init__.py
- AlexNet.py
- BasicModule.py
- ResNet34.py
-
- utils/
- __init__.py
- visualize.py
-
- config.py
- main.py
- requirement.txt
- README.md
比较复杂的可视化工具tensorboard和visdom
使用的时候可以使用colab或者科学上网方法,不然链接会断
数据集可以百度云盘获得
1.数据加载
- class DogCat(data.Dataset):
- def __init__(self,root,transforms=None,train=True,test=False):
- self.test=test
- imgs=[os.path.join(root,img)
- for img in os.listdir(root)]
- if self.test:
- imgs=sorted(
- imgs,
- key=lambda x:int(x.split('.')[-2].split('/')[-1])
-
- )
- else:
- imgs=sorted(imgs,
- key=lambda x:int(x.split('.')[-2]))
- imgs_num=len(imgs)
- if self.test:
- self.imgs=imgs
- elif train:
- self.imgs=imgs[:int(0.7*imgs_num)]
- else:
- self.imgs=imgs[int(0.7*imgs_num):]
- if transforms is None:
- normalize=T.Normalize(mean=[0.485,0.456,0.406],
- std=[0.229,0.224,0.225])
- if self.test or not train:#测试集和验证集
- self.transforms=T.Compose([
- T.Scale(224),
- T.CenterCrop(224),
- T.ToTensor(),
- normalize
- ])
- else:#训练集
- self.transforms=T.Compose([
- T.Scale(256),
- T.RandomResizedCrop(224),
- T.RandomHorizontalFlip(),
- T.ToTensor(),
- normalize
- ])
- def __getitm__(self,index):
- #返回一张图片
- img_path=self.imgs[index]
- if self.text:
- label=self.imgs[index].split('.')[-2]
- label=int(label.split('/')[-1])
- else :
- label=1 if 'dog' in img_path.split('/')[-1] else 0
- data=Image.open(img_path)
- data=self.transforms(data)
- return data,label
- def __len__(self):
- return len(self.imgs)
2.定义模型
- import time
- import torch as t
- class BasicModule(t.nn.Module):#封装save和load
- def __init__(self):
- super(BasicModule,self).__init__()
- self.model_name=str(type(self))
- def load(self,path):
- self.load_state_dict(t.load(path))
- def save(self,name=None):
- #模型名字+时间
- if name is None:
- prefix='checkpoints/'+self.model_name+'.'
- name=time.strftime(prefix+'%m%d_%H:%M:%S.pth')
- t.save(self.state_dict(),name)
- return name
封装save和load
- class DefaultConfig(object):
- env='default'
- model='AlexNet'
- train_data_root=' ./data/train/'
- test_data_root='./data/test/'
- load_model_path='checkpoints/model.pth'
- batch_size=128
- use_gpu=False
- num_workers=4
- print_freq=20
- result_file='result.csv'
- max_epoch=10
- lr=0.1
- lr_decay=0.95
- weight_decay=1e-4
在我们这个项目的 main.py 中主要包括以下四个函数,其中三个需要命令行执行,main.py 的代码组织结构如下所示:
train:
- def train(**kwargs):
-
- opt.parse(kwargs)
- vis=Visualizer(opt.env)
-
- #模型
- model=opt.model()
- if opt.load_model_path:
- model.load(opt.laod_model_path)
- if opt,use_gpu:model.cuda()
- #数据
- train_data=DogCat(opt.train_data_root,train=True)
- val_data=DogCat(opt.train_data_root,train=False)
- train_dataloader=Dataloader(train_data,
- opt.batch_size,
- shuffle=True,
- num_workers=opt.num_workers)
- val_dataloader = Dataloader(train_data,
- opt.batch_size,
- shuffle=False,
- num_workers=opt.num_workers)
-
- #函数和优化器
- criterion=torch.nn.CrossEntropyLoss()
- lr=opt.lr
- optimizer=t.optim.Adam(model.parameters(),
- lr=lr,
- weight_decay=opt.weight.decay)
- #指标
- loss_meter = meter.AverageValueMeter() # 平均损失
- confusion_matrix = meter.ConfusionMeter(2) # 混淆矩阵
- previous_loss = 1e100
-
- #训练
- for epoch in range(opt.max_epoch):
- loss_meter.reset()
- confusion_matrix.reset()
-
- for ii,(data,label) in enumerate(train_dataloader):
- inp=Variable(data)
- target=Variable(label)
-
- if opt.use_gpu:
- inp=inp.cuda()
- target=target.cuda()
- optimizer.zero_grad()
- score=model(inp)
- loss=criterion(score,target)
- loss.backward()
- optimizer.step()
-
- loss_meter.add(loss.data[0])
- confusion_matrix.add(score.data, target.data)
-
- if ii % opt.print_freq == opt.print_freq - 1:
- vis.plot('loss', loss_meter.value()[0])
-
- # 如果需要的话,进入 debug 模式
- if os.path.exists(opt.debug_file):
- ipdb.set_trace()
-
- model.save()
- if loss_meter.value()[0] > previous_loss:
- lr = lr * opt.lr_decay
- for param_group in optimizer.param_groups:
- param_group['lr'] = lr
-
- previous_loss = loss_meter.value()[0]
val
- def val(model,dataloader):
- model.eval()
- confusion_matrix = meter.ConfusionMeter(2)
- for ii, data in enumerate(dataloader):
- inp, label = data
- val_inp = Variable(inp, volatile=True)
- val_label = Variable(label.long(), volatile=True)
- if opt.use_gpu:
- val_inp = val_inp.cuda()
- val_label = val_label.cuda()
- score = model(val_inp)
- confusion_matrix.add(score.data.squeeze(), label.long())
-
- # 把模型恢复为训练模式
- model.train()
- cm_value = confusion_matrix.value()
- accuracy = 100. * (cm_value[0][0] + cm_value[1][1]) / (cm_value.sum())
-
- return confusion_matrix, accuracy
测试
- def test(**kwargs):
- opt.parse(kwargs)
- model=getattr(models,opt.model)().eval()
- if opt.load_model_path:
- model.load(opt.load_model_path)
- if opt.use_gpu: model.cuda()
- train_data=DogCat(opt.test_data_root,test=True)
- test_dataloader=DataLoader(train_data,
- batch_sampler=opt.batch_size,
- shuffle=False,
- num_workers=opt.num_workers
- )
- result=[]
- for ii, (data, path) in enumerate(test_dataloader):
- inp = Variable(data, volatile=True)
- if opt.use_gpu: inp = inp.cuda()
- score = model(inp)
-
- probability = probability = functional.softmax(score, dim=1)[:, 0].detach().tolist()
- batch_results = [(path_, probability_) for path_, probability_ in zip(path, probability)]
- results += batch_results
-
- write_csv(results, opt.result_file)
- return results