Tips:实践过程中多参考Pytorch官方文档torch.nn
import torch
from torch import nn
#定义自己的神经网络模型,继承pytorch.nn.Module类
class MyModule(nn.Module):
#nn.Module类中有两个方法需要重写:init and forward
#可以手动重写方法/Code-Generate-Override Method-init
def __init__(self):
super().__init__()
def forward(self,input):
output=input+1 #神经网络中输入与输出的关系
return output
#创建神经网络
myModule=MyModule()
# Note:torch.Tensor torch.tensor
x=torch.tensor(1.0) #input
output=myModule(x)
print(output)#tensor(2.)
# x=torch.Tensor([1.0])
# output=myModule(x)
# print(output)#tensor([2.])
卷积层nn.Conv.py
#输入单个数据进行卷积
import torch
import torch.nn.functional as F
input = torch.tensor([[1,2,0,3,1],
[0,1,2,3,1],
[1,2,1,0,0],
[5,2,3,1,1],
[2,1,0,1,1]])#图像输入为5*5二维矩阵,将其转换为tensor类型
kernel = torch.tensor([[1,2,1],
[0,1,0],
[2,1,0]])#卷积核为3*3二维矩阵 kernel也就是weight
# print(input.shape)
# print(kernel.shape)
#此时输出的只有两个数,不满足参数要求
#pytorch官网-torch.nn.functional 文档中有conv2d的使用参数说明
#input、kernel格式要求均需要四个数字
#Parameters
#input – input tensor of shape (\text{minibatch} , \text{in\_channels} , iT , iH , iW)(minibatch,in_channels,iT,iH,iW)
#weight – filters of shape (\text{out\_channels} , \frac{\text{in\_channels}}{\text{groups}} , kT , kH , kW)(out_channels, in_channels/groups ,kT,kH,kW)
#使用pytorch提供的尺寸变化
input = torch.reshape(input,(1,1,5,5)) #batchsize=1,channels=1 数据维度=5*5
kernel = torch.reshape(kernel,(1,1,3,3)) #out_channel=1,in_channel=1 数据维度=3*3
print(input.shape)
print(kernel.shape)
#reshape为四维,所以输出也是四维
output = F.conv2d(input,kernel,stride=1)
print(output)
output2 = F.conv2d(input,kernel,stride=2)
print(output2)
output3 = F.conv2d(input,kernel,stride=1,padding=1)
print(output3)
#使用padding可以使输出与输入维度相同
卷积层nn_Conv2d.py
#输入整个数据集进行卷积
#卷积层进行的处理就是卷积运算 对于输入数据,卷积运算以一定间隔stride滑动滤波器的窗口(卷积核)并应用。
#卷积核中的数字对应全连接网络中的权重
#将各个位置上滤波器(卷积核)的元素和输入的对应元素进行乘积累加运算,输出到对应位置
#在进行卷积层运算前,有时会使用padding填充,向输入数据的周围填入固定的数据(比如0等)
#padding的目的/作用是调整输出的大小
import torch
import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
#加载数据
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataloader=DataLoader(dataset,batch_size=64)
#定义神经网络模型
class myModel(nn.Module):
#初始化方法
def __init__(self): #Note:不要把init写成int
super(myModel,self).__init__()#父类初始化
#定义卷积层
self.conv1=Conv2d(in_channels=3,out_channels=6,kernel_size=3,stride=1,padding=0)#kernel:3*3
#卷积核中数据是自动生成的,在训练过程中自动更新。这些数字就是我们所需要的结果。
def forward(self,x):
x=self.conv1(x)
return x
model=myModel()
# print(model)
writer=SummaryWriter("logs")
step=0
for data in dataloader:
imgs,targets = data
output = model(imgs)
print(imgs.shape) #torch.Size([64, 3, 32, 32]) batchsize=64 in_channels=3 输入数据32*32
print(output.shape) #torch.Size([64, 6, 30, 30]) batchsize=64 out_channels=6 输出数据30*30
# 卷积核的通道数等于输入的通道数(In_channel)
# 卷积层特征图的通道数(Out_channel)等于该卷积层中卷积核的数量 同一个卷积核得到的数据叠加为一个通道
# torch.Size([64, 3, 32, 32])
writer.add_images("input",imgs,step)#同时显示多张图片,注意使用images
# torch.Size([64, 6, 30, 30])->[xxx,3,30,30] 6个通道转换成3个通道,多余的像素就放在batchsize中
# 只有3个通道才可以在tensorboard可视化出来,所以需要转换shape
output=torch.reshape(output,(-1,3,30,30)) #-1是让机器自己配置batchsize
writer.add_images("output",output,step)
step = step+1
#writer.close()
nn.maxpool.py
#最大池化取局部接受域中值最大的点
#最大池化的目的在于保留原特征的同时减少神经网络训练的参数,使得训练时间减少。相当于1080p的视频变为了720p
#图像经最大池化后会变模糊,类似于马赛克效果
import torch
import torchvision
from torch import nn
from torch.nn import MaxPool2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
#加载数据集
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,download=True,transform=torchvision.transforms.ToTensor())
dataloader=DataLoader(dataset,batch_size=64)
#输入单个数据
# input=torch.tensor([[1,2,0,3,1],
# [0,1,2,3,1],
# [1,2,1,0,0],
# [5,2,3,1,1],
# [2,1,0,1,1]],dtype=torch.float32)#添加dtype是因为不支持输入"Long"型数据,直接放进神经网络训练会报错
# print(input.shape)#目前input只含H,W信息
# #Maxpool2d要求input需要有四个参数,batch_size、channels、输入的高H、输入的宽W,则进行reshape:
# input=torch.reshape(input,(-1,1,5,5))
# print(input.shape)
#创建神经网络
class myModel(nn.Module):
def __init__(self):
super(myModel, self).__init__()
self.maxpool1=MaxPool2d(kernel_size=3,ceil_mode=False)
# kernel_size池化核3*3 默认stride=kernel_size
# 若池化核移动过程中数据没有凑足kernel_size的大小,便涉及取舍问题
# ceil_mode=True时,当移动stride后不足3*3有空值时,采用ceil保留;ceil_mode=False时,采用舍弃 默认为False
def forward(self,input):
output=self.maxpool1(input)
return output
model=myModel()
#输入单个数据时的输出测试
# output=model(input)
# print(output)
#数据集池化的可视化
writer=SummaryWriter("logs")
step=0
for data in dataloader:
imgs,targets=data
writer.add_images("maxpool_input",imgs,step)
output=model(imgs)#池化不影响channel数,原来是三维,经过池化后还是三维的,所以不需要像conv后还要reshape
writer.add_images("maxpool_output",output,step)
step += 1
writer.close()
nn.ReLU/sigmoid.py
#激活函数实际上是给模型增加非线性的表达能力或者因素,有了非线性函数模型的表达能力就会更强
#没有激活函数的神经网络实际上是线性可加的,那么多线性层其实可以归为一层
#只具有线性的神经网络表达能力极其有限
import torch
import torchvision
from torch import nn
from torch.nn import ReLU, Sigmoid
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
input=torch.tensor([[1,-0.5],
[-1,3]])
output=torch.reshape(input,(-1,1,2,2))#input要有batch_size
print(output.shape)
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,download=True,transform=torchvision.transforms.ToTensor())
dataloader=DataLoader(dataset,batch_size=64)
class myModel(nn.Module):
def __init__(self):
super(myModel, self).__init__()
self.relu1=ReLU()
#inplace就是原地操作的意思 默认为False
# Input=-1,ReLU(input,inplace=True)=>Input=0
# Input=-1,Output=ReLU(input,inplace=False)=>Input=-1 Output=0
self.sigmoid1=Sigmoid()
def forward(self,input):
# output=self.relu1(input)
output = self.sigmoid1(input)
return output
model=myModel()
output=model(input)
print(output)
writer=SummaryWriter("logs")
step=0
for data in dataloader:
imgs,targets=data
writer.add_images("sigmoid_input",imgs,step)
output=model(imgs)
writer.add_images("sigmoid_output",output,step)
step+=1
writer.close()
nn.Linear.py
#线性层
#全连接层包括线性层和非线性激活
#in_feature就是Input layer的神经元个数,输入数据的特征数
#out_feature是Output layer的神经元个数,输出数据
#该代码展示将特征矩阵展平为一维向量,再进行线性输入
import torch
import torchvision
from torch import nn
from torch.nn import Linear
from torch.utils.data import DataLoader
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,download=True,transform=torchvision.transforms.ToTensor())
dataloader=DataLoader(dataset,batch_size=64,drop_last=True)
class myModel(nn.Module):
def __init__(self):
super(myModel, self).__init__()
self.linear1=Linear(196608,10) #in_feature out_feature
def forward(self,input):
output=self.linear1(input)
return output
model=myModel()
for data in dataloader:
imgs,targets=data
print(imgs.shape)#torch.Size([64, 3, 32, 32])
# #展平 方法①
# output=torch.reshape(imgs,(1,1,1,-1)) #batch_size,channels,h,w 把原来的张量flatten为一个行向量
#展平 方法②
output=torch.flatten(imgs)#把原来的张量flatten为一个行向量 torch.Size([196608])
print(output.shape)#torch.Size([1, 1, 1, 196608])
output=model(output)
print(output.shape)#torch.Size([10])
nn.sequential.py
#搭建小实战和Sequential的使用
#把网络结构直接放入Sequential中
#写一个对CIFAR-10数据集进行分类的网络
#使用Sequential使得代码更简洁,并且运行后各层会序列化
import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.tensorboard import SummaryWriter
class myModel(nn.Module):
#model结构:conv1-maxpool1-conv2-maxpool2-conv3-maxpool3-flatten-linear1-linear2
def __init__(self):
super(myModel, self).__init__()
#①逐层创建网络
# Inputs3@32*32 Convolution 5*5 kernel => Feature maps 32@32*32
# 根据Inputs\Conv kernel\Feature maps可以得出in_channels、out_channels、kernel_size;
# 默认 dilation=1 根据输出尺寸32*32计算公式可以求出padding、stride值
self.conv1 = Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2, stride=1, dilation=1)
#Feature maps 32@32*32 Max-pooling 2*2 kernel => Feature maps 32@16*16
self.maxpool1=MaxPool2d(kernel_size=2)#池化的stride默认为kernel_size 池化不更改channel数
#Feature maps 32@16*16 Convolution 5*5 kernel => Feature maps 32@16*16
# 同样根据输入、输出、kernel可以计算出个参数值
self.conv2=Conv2d(in_channels=32,out_channels=32,kernel_size=5,padding=2)
# Feature maps 32@16*16 Max-pooling 2*2 kernel => Feature maps 32@8*8
self.maxpool2 = MaxPool2d(kernel_size=2)
# Feature maps 32@8*8 Convolution 5*5 kernel => Feature maps 64@8*8
# 同样根据输入、输出、kernel可以计算出个参数值
self.conv3 = Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2)
# Feature maps 64@16*16 Max-pooling 2*2 kernel => Feature maps 64@4*4
self.maxpool3 = MaxPool2d(kernel_size=2)
# Feature maps 64@4*4 => 64*4*4=1024(线性层的In_feature)
self.flatten = Flatten()
# 64*4*4=1024(线性层的In_features) =>Hidden units 64(线性层的Out_features)
self.linear1=Linear(in_features=1024,out_features=64)
# Hidden units 64(线性层的In_features) =>Outputs 10(线性层的Out_features,10个类别)
self.linear2 = Linear(in_features=64, out_features=10)
#②使用Sequential创建网络
self.model1=Sequential(
Conv2d(3,32,5,padding=2),
MaxPool2d(2),
Conv2d(32,32,5,padding=2),
MaxPool2d(2),
Conv2d(32,64,5,padding=2),
MaxPool2d(2),
Flatten(),
Linear(1024,64),
Linear(64,10),
)
#层与层之间用逗号分隔
def forward(self,x):
#①逐层创建网络对应的forward函数内容
x = self.conv1(x)
x = self.maxpool1(x)
x = self.conv2(x)
x = self.maxpool2(x)
x = self.conv3(x)
x = self.maxpool3(x)
x = self.flatten(x)
#若我们不知道展开后线性输入数据是多大,我们可以将下面两行linear注释掉,运行后会看到模型经前面操作后得到的尺寸
#torch.Size([64, 1024]) batch_size=64,每张图片都会展开为1024个
x = self.linear1(x)
x = self.linear2(x)
return x
#②使用Sequential对应的forward函数内容
x=self.model1(x)
return x
model = myModel()
print(model)
#对网络进行检验
input = torch.ones((64,3,32,32))#batch_size channels H W
output = model(input)
print(output.shape)#torch.Size([64, 10])
#可视化网络
#在tensorboard中双击可以看到网络结构
writer=SummaryWriter("logs")
writer.add_graph(model,input)
writer.close()
①逐层搭建网络
②将model添加到Sequential中
tensorboard中网络可视化