目录
-
- 1. 神经网络
-
- 1.1 神经网络是怎么工作的?
- 1.2 神经网络为什么要这样工作呢?
-
- softmax回归
- 损失
- 梯度下降算法
- 反向传播算法
- 2.卷积神经网络
-
- 2.1 与传统卷积神经网络的区别
- 2.2 卷积神经网络工作原理
-
- 卷积层
- 激活函数——Relu
- 池化计算
- 全连接层
- 2.3 卷积神经网络常见架构
- 3. 使用Pytorch搭建神经网络
- 4. 使用Pytorch实现卷积神经网络
1. 神经网络
1.1 神经网络是怎么工作的?
首先神经网络的结构包括三个层次:输入层、隐藏层和输出层。如下图所示:
其中每个圆圈代表一个神经元,输入层和隐藏层之间有很多箭头相连接,每个连接都有一个权值,同层的神经元没有连接,通常神经网络都是全l连接的,也就是所有层都相互有链接且中间没有断层。
第一层有4个输入结点,每个输入节点分别对应五个权值,则可以让输入的数据分别和权值作矩阵乘法最后再相加,得到的数据即为第二层,以此类推。最后会得到值Oj。
1.2 神经网络为什么要这样工作呢?
主要从两个方面来说:损失和优化
神经网络输出结果的分类问题最常用的方法是设置n个输出节点(n为类别的个数),将分类的结果看成概率事件,符合一定的概率分布。通常使用softmax回归将神经网络前向传播的到的结果也变成概率分布。
softmax回归
计算公式:
过程图示是这样的:
然后将得到的输出结果变成了概率输出:
损失
计算公式:
为了衡量神经网络预测的概率分布与真实概率分布之间的距离,要对结果进行one-hot编码:
最终结果是H(y) = -0.1log(0.1)
为了减少这个损失值,即找到损失函数的最小值,我们通常采用梯度下降算法,
梯度下降算法
之前有详细说过梯度下降算法,这里不再赘述——传送门。
反向传播算法
反向传播算法实际就是:我们使用链式求导法则,反向层层推进,计算出每一层神经节点的偏导数,然后使用梯度下降,不断调整每一个节点的权重,从而达到求得全局最小值的目的。
2.卷积神经网络
2.1 与传统卷积神经网络的区别
传统的多层神经网络只有输入层、隐藏层、输出层。其中隐藏层层数依情况而定。
首先什么是卷积?
对图像(不同的数据窗口数据)和滤波矩阵(一组固定的权重:因为每个神经元的多个权重固定,所以又可以看做一个恒定的滤波器filter)做内积(逐个元素相乘再求和)的操作就是卷积,也是卷积神经网络的名字来源。
卷积神经网络CNN,在原来多层神经网络上加入了更有效的特征学习部分,具体就是在全连接层之前增加了卷积层、激活层和池化层。卷积神经网络出现,使得神经网络层数得以加深,“深度” 学习由此而来。
2.2 卷积神经网络工作原理
如图:
新增的三个层次的作用分别是:
卷积层:通过在原始图像上平移来提取特征
激活层:增加非线性分割能力
池化层:减少学习的参数,降低网络的复杂度(最大池化和平均池化)
下边分别对这三个层次进行展开论述:
卷积层
四个参数:
-
过滤器
过滤器的大小是指设定的,一般都为3x3、5x5、7x7等
-
深度
输出深度(个数)是由卷积中的Filter的个数决定
-
步幅
也叫步长,就是Filter移动的间隔大小,
-
零填充
主要为了解决步长移动与Filter大大小不合适,不能刚好移动到边缘的情况。
激活函数——Relu
常见的激活函数有sigmod、softmax
relu等,但我们常用的是Relu,因为他可以减少梯度消失和梯度爆炸情况。
函数图像如下:
池化计算
池化层的作用主要是通过采样减少参数数量。常用的是最大值池化,也就是在n个样本中取最大值,作为新的样本值,如下图:
池化后深度不变。
全连接层
前面的卷积和池化相当于做特征工程,后面的全连接相当于做特征加权,最后的全连接层在整个卷积神经网络中起到 “分类器” 的作用。
2.3 卷积神经网络常见架构
3. 使用Pytorch搭建神经网络
1.先定义网络:写网络Net的Class,声明网络的实例net=Net(),
2.定义优化器opt=torch.optim.xxx(net.parameters(),lr=xxx),
3.再定义损失函数(自己写class或者直接用官方的,lossfunc=nn.MSELoss()或者其他。
4.在定义完之后,开始一次一次的循环:
①先清空优化器里的梯度信息,opt.zero_grad();
②再将input传入,output=net(input) ,正向传播
③算损失,loss=lossfunc(target,output) ##这里target就是参考标准值GT,需要自己准备,和之前传入的input一一对应
④误差反向传播,loss.backward()
⑤更新参数,opt.step()
import torch
import torch.nn.functional as F
from torch.autograd import Variable
import matplotlib.pyplot as plt
x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1)
#对输入的制定位置插入维度 1,无torch.unsqueeze,x是向量torch.Size([100]),
#有之后x是torch.Size([100, 1])的矩阵
y = x**2+0.2*torch.rand(x.size())
#x的平方,加噪声(从区间[0,1)的均匀分布中抽取的一组随机数,输出形状与x相同)
print(x,y,x.size())
x,y = Variable(x),Variable(y) #将x,y张量转化为变量
##定义一个类,用来继承nn.Module
class Net(torch.nn.Module):
def __init__(self,n_feature,n_hidden,n_output):#搭建层所要的初始信息,特征数,隐藏层单元数和输出单元数
super(Net,self).__init__()#继承Net到模块,官方步骤
self.hidden = torch.nn.Linear(n_feature,n_hidden)#从输入层到隐藏层的函数
self.predict = torch.nn.Linear(n_hidden,n_output)#从隐藏层的输出层的函数
def forward(self,x):#前向传播
x = F.relu(self.hidden(x))#self.hidden(x)给x加权成为a,用激励函数将a变成特征b
x = self.predict(x)#self.predict(b)给b加权,预测最终结果
return x #返回最终预测值
net = Net(1,10,1) #只有一个输入单元,一个输出单元,隐藏单元定为10个
print(net) #搭建神经网络完毕
plt.ion()
plt.show()
opt = torch.optim.SGD(net.parameters(),lr=0.5)#设置学习率为0.5,用随机梯度下降法优化net神经网络的参数
lossfunc = torch.nn.MSELoss() #设置损失函数为均方差函数
for t in range(100):#训练步数100
prediction=net(x)#预测值
loss=lossfunc(prediction,y)#预测值与真实值的误差
opt.zero_grad()#梯度降0
loss.backward()#反向传播
opt.step()#梯度优化
if t%5 == 0:#此时,打印一下图片
plt.cla()#清除当前图形中的当前活动轴,其他轴不受影响。
plt.scatter(x.data.numpy(),y.data.numpy())#numpy类型才支持plt,所以要转化
plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=3)#拟合线图
plt.text(0.5,0,'loss=%.4f'%loss.data[0],fontdict = {'size':10,'color':'red'})#在(0.5,0)的位置写loss的变化
plt.pause(0.1)#间隔时间
plt.ioff()
plt.show()
4. 使用Pytorch实现卷积神经网络
主要实现图像分类:
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
from torchvision import transforms
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torch import optim
class CNN_net(nn.Module):
def __init__(self):
# 先运行nn.Module的初始化函数
super(CNN_net, self).__init__()
# 卷积层的定义,输入为1channel的灰度图,输出为4特征,每个卷积kernal为9*9
self.conv = nn.Conv2d(1, 4, 9)
# 均值池化
self.pool = nn.AvgPool2d(2, 2)
# 全连接后接softmax
self.fc = nn.Linear(10*10*4, 10)
self.softmax = nn.Softmax()
def forward(self, x):
# 卷积层,分别是二维卷积->sigmoid激励->池化
out = self.conv(x)
out = F.sigmoid(out)
out = self.pool(out)
print(out.size())
# 将特征的维度进行变化(batchSize*filterDim*featureDim*featureDim->batchSize*flat_features)
out = out.view(-1, self.num_flat_features(out))
# 全连接层和softmax处理
out = self.fc(out)
out = self.softmax(out)
return out
def num_flat_features(self, x):
# 四维特征,第一维是batchSize
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
# 定义一个cnn网络
net = CNN_net()
print(net)
# 参数设置
learning_rate = 1e-3
batch_size = 100
epoches = 10
# MNIST图像数据的转换函数
trans_img = transforms.Compose([
transforms.ToTensor()
])
# 下载MNIST的训练集和测试集
trainset = MNIST('./MNIST', train=True, transform=trans_img, download=True)
testset = MNIST('./MNIST', train=False, transform=trans_img, download=True)
# 构建Dataloader
trainloader = DataLoader(trainset, batch_size=batch_size, shuffle=True, num_workers=4)
testloader = DataLoader(testset, batch_size=batch_size, shuffle=False, num_workers=4)
# cost function的选用
criterian = nn.CrossEntropyLoss(size_average=False)
# 选用SGD来求解
opt = optim.SGD(net.parameters(), lr=learning_rate, momentum=0.95)
# 训练过程
for i in range(epoches):
running_loss = 0.
running_acc = 0.
for (img, label) in trainloader:
# 转换为Variable类型
img = Variable(img)
label = Variable(label)
opt.zero_grad()
# feedforward
output = net(img)
loss = criterian(output, label)
# backward
loss.backward()
opt.step()
# 记录当前的lost以及batchSize数据对应的分类准确数量
running_loss += loss.data[0]
_, predict = torch.max(output, 1)
correct_num = (predict == label).sum()
running_acc += correct_num.data[0]
# 计算并打印训练的分类准确率
running_loss /= len(trainset)
running_acc /= len(trainset)
print("[%d/%d] Loss: %.5f, Acc: %.2f" %(i+1, epoches, running_loss, 100*running_acc))
# 将当前模型设置到测试模式
net.eval()
# 测试过程
testloss = 0.
testacc = 0.
for (img, label) in testloader:
# 转换为Variable类型
img = Variable(img)
label = Variable(label)
# feedforward
output = net(img)
loss = criterian(output, label)
# 记录当前的lost以及累加分类正确的样本数
testloss += loss.data[0]
_, predict = torch.max(output, 1)
num_correct = (predict == label).sum()
testacc += num_correct.data[0]
# 计算并打印测试集的分类准确率
testloss /= len(testset)
testacc /= len(testset)
print("Test: Loss: %.5f, Acc: %.2f %%" %(testloss, 100*testacc))