目录
GoogleNet
定义inception块,然后整合起来成Net模块:
贴个代码:
import torch
from torch.utils.data import DataLoader
from torchvision import transforms #针对图像进行处理的工具包
from torchvision import datasets
import torch.nn.functional as F #for using ReLU
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))])
train_dataset = datasets.MNIST(root='../dataset/mnist',train=True,transform=transform,download=True) #mnist为28*28大小的灰度图像
test_dataset = datasets.MNIST(root='../dataset/mnist',train=False,transform=transform,download=True)
train_loader = DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True) #打乱->shuffle=true,训练要打乱
test_loader = DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=False) #测试不用shuffle,可以观察结果
class InceptionA(torch.nn.Module):
def __init__(self,in_channels): #初始输入通道,构造函数时作为参数,将来实例化时,可以指明输出通道数是多少
super(InceptionA,self).__init__()
self.branch_pool = torch.nn.AvgPool2d(kernel_size=3,padding=1,stride=1)
self.branch1x1_1 = torch.nn.Conv2d(in_channels,24,kernel_size=1)
self.branch1x1_2 = torch.nn.Conv2d(in_channels,16,kernel_size=1)
self.branch5x5_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)
self.branch5x5_2 = torch.nn.Conv2d(16,24,kernel_size=5,padding=2) #保证输出的W,H不变
self.branch3x3_1 = torch.nn.Conv2d(in_channels,16,kernel_size=1)
self.branch3x3_2 = torch.nn.Conv2d(16,24,kernel_size=3,padding=1) #保证输出的W,H不变
self.branch3x3_3 = torch.nn.Conv2d(24,24,kernel_size=3,padding=1) #保证输出的W,H不变
def forward(self,x):
branch_pool = self.branch_pool(self.branch1x1_1(x)) #pool分支
branch1x1 = self.branch1x1_2(x) #1x1分支
branch5x5 = self.branch5x5_1(x)
branch5x5 = self.branch5x5_2(branch5x5) #5x5分支
branch3x3 = self.branch3x3_1(x)
branch3x3 = self.branch3x3_2(branch3x3)
branch3x3 = self.branch3x3_3(branch3x3) #3x3分支
outputs = [branch_pool,branch1x1,branch5x5,branch3x3] #四个分支放一个列表里
return torch.cat(outputs,dim=1) #沿着dimension的维度拼起来 (B,C,W,H) C为第一个维度
class Net(torch.nn.Module):
def __init__(self, in_channels):
super(Net, self).__init__()
self.conv1 = torch.nn.Conv2d(1,10,kernel_size=5) #输入数据是(B,1,28,28)
self.conv2 = torch.nn.Conv2d(88,20,kernel_size=5) #输入数据是(B,88,12,12)
self.incep1 = InceptionA(in_channels=10) #输入通道数为10
self.incep2 = InceptionA(in_channels=20)
self.mp = torch.nn.MaxPool2d(kernel_size=2)
self.fc = torch.nn.Linear(1408,10)
def forward(self,x):
in_size = x.size(0) #获得batch_size
#(b,10,24,24)->(b,10,12,12)->(b,10,12,12)
x = F.relu(self.mp(self.conv1(x))) #卷积-> 最大池化-> 激活
x = self.incep1(x) #W,H大小不变,通道数变化->(b,88,12,12) 88=24*3+16
#(b,20,8,8)->(b,20,4,4)->(b,20,4,4)
x = F.relu(self.mp(self.conv2(x))) #卷积-> 最大池化-> 激活
x = self.incep2(x) #W,H大小不变,通道数变化->(b,88,4,4) 所以最终像素为88*4*4=1408个
x = x.view(in_size,-1) #flatten,展平-> 行,列
x = self.fc(x)
return x
model = Net(10)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#使用GPU,可以选,不同的任务使用不同的显卡,第一块:cuda:0,第二块:cuda:1,这取决于显卡的数量
model.to(device) #整个模型的缓存、模块都放到cuda中,转成cuda Tensor
criterion = torch.nn.CrossEntropyLoss() #相当于size_average=True
optimizer = torch.optim.SGD(model.parameters(), lr=0.01,momentum=0.5) #momentum为动量参数
def train(epoch):
running_loss = 0.0
for batch_idx,data in enumerate(train_loader,0): #(x,y)放到data中,dataloader自动将它们转成tensor batch_idx相当于i
# prepare data
inputs, target = data #x存到inputs中,y存到target中
inputs, target = inputs.to(device),target.to(device) #放到同一块显卡中
optimizer.zero_grad()
# forward+backward+update
outputs = model(inputs)
loss = criterion(outputs,target)
loss.backward()
optimizer.step()
running_loss += loss.item() #用item,不然会构建计算图 计算一个batch的损失
if batch_idx % 300 ==299:
print('[%d %5d] loss:%.3f' % (epoch+1,batch_idx+1,running_loss/300))
running_loss = 0.0
def test():
correct = 0
total = 0
with torch.no_grad(): #测试时不需要计算梯度
for data in test_loader:
images,target = data
images, target = images.to(device), target.to(device) # 放到同一块显卡中
outputs = model(images)
_,predicted = torch.max(outputs.data,dim=1)
#torch.max()函数返回的是两个值,第一个值是具体的value,即输出的最大值(用下划线表示),第二个值是value所在的index(也就是predicted)
#dim=1表示输出所在行的最大值,dim=0表示输出所在列的最大值
total += target.size(0) #求样本总数
correct += (predicted==target).sum().item() #.item()将tensor转化为普通的float或int型
print('Accuracy on test set:%d %% [%d/%d]'%(100*correct/total,correct,total)) #%%表示文字% 后面的%表示传入数据
if __name__ =='__main__':
for epoch in range(10):
train(epoch)
test()
输出结果:
Residual Learning
Residual Net 做了 F(x) + x 的操作,要求两个张量维度要一样,即通道、高度、宽度要一样。
下图中,红色的是residual block。
红色的里面是一个残差块,包含两个weight layer。第一个weight layer做conv1卷积,经过relu,送入第二个weight layer,在第二个weight layer做conv2卷积,输出与x相加,最后做relu。示意图及模块代码如下图。
定义了残差块,下面为整个残差网络的架构:
完整代码:
import torch
from torch.utils.data import DataLoader
from torchvision import transforms #针对图像进行处理的工具包
from torchvision import datasets
import torch.nn.functional as F #for using ReLU
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))])
train_dataset = datasets.MNIST(root='../dataset/mnist',train=True,transform=transform,download=True) #mnist为28*28大小的灰度图像
test_dataset = datasets.MNIST(root='../dataset/mnist',train=False,transform=transform,download=True)
train_loader = DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True) #打乱->shuffle=true,训练要打乱
test_loader = DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=False) #测试不用shuffle,可以观察结果
class ResidualBlock(torch.nn.Module):
def __init__(self,channels): #初始输入通道,构造函数时作为参数,将来实例化时,可以指明输出通道数是多少
super(ResidualBlock,self).__init__()
self.channels = channels
self.conv1 = torch.nn.Conv2d(channels,channels,kernel_size=3,padding=1) #保证输入、输出通道一样,大小不变
self.conv2 = torch.nn.Conv2d(channels, channels, kernel_size=3, padding=1)
def forward(self,x):
y = F.relu(self.conv1(x)) #卷积+激活
y = self.conv2(y) #卷积
return F.relu(x+y) #相加再激活
class Net(torch.nn.Module): #如果网络结构复杂,可以用新的类去封装
def __init__(self): #定义需要调用的函数
super(Net,self).__init__()
self.conv1 = torch.nn.Conv2d(1,16,kernel_size=5)
self.conv2 = torch.nn.Conv2d(16,32,kernel_size=5)
self.mp = torch.nn.MaxPool2d(kernel_size=2)
self.rblock1 = ResidualBlock(16) #输入通道数为16
self.rblock2 = ResidualBlock(32)
self.fc = torch.nn.Linear(512,10)
def forward(self,x):
in_size = x.size(0)
x = self.mp(F.relu(self.conv1(x)))
x = self.rblock1(x)
x = self.mp(F.relu(self.conv2(x)))
x = self.rblock2(x)
x = x.view(in_size,-1)
x = self.fc(x)
return x
model = Net()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#使用GPU,可以选,不同的任务使用不同的显卡,第一块:cuda:0,第二块:cuda:1,这取决于显卡的数量
model.to(device) #整个模型的缓存、模块都放到cuda中,转成cuda Tensor
criterion = torch.nn.CrossEntropyLoss() #相当于size_average=True
optimizer = torch.optim.SGD(model.parameters(), lr=0.01,momentum=0.5) #momentum为动量参数
def train(epoch):
running_loss = 0.0
for batch_idx,data in enumerate(train_loader,0): #(x,y)放到data中,dataloader自动将它们转成tensor batch_idx相当于i
# prepare data
inputs, target = data #x存到inputs中,y存到target中
inputs, target = inputs.to(device),target.to(device) #放到同一块显卡中
optimizer.zero_grad()
# forward+backward+update
outputs = model(inputs)
loss = criterion(outputs,target)
loss.backward()
optimizer.step()
running_loss += loss.item() #用item,不然会构建计算图 计算一个batch的损失
if batch_idx % 300 ==299:
print('[%d %5d] loss:%.3f' % (epoch+1,batch_idx+1,running_loss/300))
running_loss = 0.0
def test():
correct = 0
total = 0
with torch.no_grad(): #测试时不需要计算梯度
for data in test_loader:
images,target = data
images, target = images.to(device), target.to(device) # 放到同一块显卡中
outputs = model(images)
_,predicted = torch.max(outputs.data,dim=1)
#torch.max()函数返回的是两个值,第一个值是具体的value,即输出的最大值(用下划线表示),第二个值是value所在的index(也就是predicted)
#dim=1表示输出所在行的最大值,dim=0表示输出所在列的最大值
total += target.size(0) #求样本总数
correct += (predicted==target).sum().item() #.item()将tensor转化为普通的float或int型
print('Accuracy on test set:%d %% [%d/%d]'%(100*correct/total,correct,total)) #%%表示文字% 后面的%表示传入数据
if __name__ =='__main__':
for epoch in range(10):
train(epoch)
test()
输出结果: