参与拿奖:本文已参与「新人创作礼」活动,一起开启掘金创作之路
1.神经网络
随着神经科学、认知科学的发展,我们已经知道人类的智能行为都和大脑活动有关。 人类的大脑是一个可以产生意识、思想和情感的器官。受到人脑神经系统的启发,早期的 神经科学家构造了一种模仿人脑神经系统的数学模型,称为人工神经网络,简称神经网 络。在机器学习领域,神经网络是指由很多人工神经元构成的网络结构模型,这些人工神 经元之间的连接强度是可学习的参数。
1.1 神经元
1.2 多层感知机
多层感知器可以分为3个部分:输入层、隐藏层、输出层,其中隐藏层可以包括一层
或者多层;每一层都由若干神经元组成,每个神经元承担的计算功能包括线性加权和非线
性变换;层与层之间通过权值建立联系,后一层的每个神经元与前一层的每个神经元都产
生连接。
输入信号通过不断地进行线性变换(线性加权)和非线性变换(激活函数),逐渐将 输入信号向后一层传递,直到输出层。其中输入层和输出层的神经元个数往往是通过先验 的知识确定的,而隐藏层中每层的神经元个数以及使用的层数都是超参数。
1.3 激活函数
激活函数是神经网络中一个十分重要的概念,它的非线性使得神经网络几乎可以任意 逼近任何非线性函数。如果不使用激活函数,无论神经网络有多少层,其每一层的输出都 是上一层输入的线性组合,这样构成的神经网络仍然是一个线性模型,表达能力有限。
1.3.1 S型激活函数
1.3.2 ReLU及其变种
1.4 神经网络的训练过程
神经网络的运行过程分为三步:前向传播、反向传播、参数更新,通过不断迭代进行 模型参数的更新,以从数据中挖掘出有价值的信息,如图2-8所示。 1)前向传播:给定输入和参数,逐层向前进行计算,最后输出预测结果;
2)反向传播:基于前向传播得到的预测结果,使用损失函数得到损失值,然后计算 相关参数的梯度,该计算方法称为反向传播(back-propagation);
3)参数更新:使用梯度下降算法对参数进行更新,重复上述过程,逐步迭代,直到 模型收敛。
2.卷积操作
2.1 初始化数据
# input 输入数据
# weight 卷积核
# 移动步长 stride=(h,w) 设置移动格子数(包括左右和上下)
import torch
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]])
weight_kernel=torch.tensor([[1,2,1],[0,1,0],[2,1,0]])
print(input,weight_kernel)
将创建的数据以及卷积核reshape一下
# torch.reshape(input,(1,1,5,5)).shape #转换数据形状
input=torch.reshape(input,(1,1,5,5))
kernel=torch.reshape(weight_kernel,(1,1,3,3))
2.2 卷积操作
import torch.nn.functional as F
output=F.conv2d(input,kernel,stride=1)
print(output) #卷积结果
output1=F.conv2d(input,kernel,stride=2)
print(output1)
这里第一个卷积操作使用的是2维卷积核,卷积核大小为3x3,步长为1,原始数据为5x5的张量,卷积之后维数变为3x3;第二个卷积操作也是使用的2维卷积核,卷积核大小为3x3,原始数据为5x5的张量,卷积步长变为2,卷积之后结果维数变为2x2。
计算方式如下:
其中H表示原始数据的维数,p表示padding的数目,k表示卷积核大小,s表示步长。上述例子中,第一个卷积操作的计算公式为(5+0-3)//1+1,第二个卷积操作计算公式为(5+0-3)//2+1。
2.3 卷积实例
# kernel_size 卷积核大小
import torch
import torchvision
from torch.utils.data import DataLoader
import torch.nn as nn
from torch.nn import Conv2d #卷积
from torch.utils.tensorboard import SummaryWriter
# 加载数据集
dataset=torchvision.datasets.CIFAR10('./data/02 data',train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataloader=DataLoader(dataset,batch_size=64)
class myConv(nn.Module):
def __init__(self):
super().__init__()
self.conv1=Conv2d(in_channels=3,out_channels=6,kernel_size=3,stride=1,padding=0)#卷积层
def forward(self,x): #前向传播
x=self.conv1(x)
return x
my_conv=myConv()
# print(my_conv)
writer=SummaryWriter("myConv")
step=0
for data in dataloader:
imgs,targets=data
output=my_conv(imgs)
writer.add_images("input",imgs,step)
output=torch.reshape(output,(-1,3,30,30))
writer.add_images("output",output,step)
step+=1
print(imgs.shape,output.shape)
writer.close()
3.池化
3.1 概念
池化操作的主要目的是降维,以降低计算量,并在训练初期提供一些平移不变性。 常用的两种池化操作是平均池化和最大值池化。
池化操作就是使用一个固定大小的滑窗在输入上滑动,每次将滑窗内的元素聚合为一 个值作为输出。根据聚合方式的不同,可以分为平均池化和最大值池化。
3.2 实例
import torch
from torch import nn
from torch.nn import MaxPool2d
from torch.utils.data import DataLoader
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)
input=torch.reshape(input,(-1,1,5,5))
print(input.shape)
class myConv(nn.Module):
def __init__(self):
super().__init__()
self.maxpool1=MaxPool2d(kernel_size=3,ceil_mode=True) #池化
def forward(self,input):
output=self.maxpool1(input)
return output
my_conv2=myConv()
output=my_conv2(input)
print(output)
from torch.utils.tensorboard import SummaryWriter
dataset=torchvision.datasets.CIFAR10('./data/02 data',train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataloader=DataLoader(dataset,batch_size=64)
writer=SummaryWriter("myConvPooling")
step=0
for data in dataloader:
imgs,targets=data
writer.add_images("input",imgs,step)
output=my_conv2(imgs)
writer.add_images("output",output,step)
step+=1
writer.close()
参考资料
[1] 深入浅出图神经网络
[2] b站课程链接
[3] 手敲代码链接