持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情
1. 环境配置要求
numpy1.21.5
python3.8
cuda11.3 #这个是GPU,没有这个cuda也可以用cpu跑,都差不多。
pytorch1.12.1
还要有d2lzh_pytorch包,可以网上搜然后下载,放在运行环境的lib文件里。
2. 多层感知机原理
多层感知机又称为全连接层神经网络。
2.1 激活函数
激活函数对于这个多层感知机是非常重要的,如果没有激活函数,那么多层感知机相当于单层的。
2.1.1 Relu函数
我们简单了解一下Relu函数的作用,太详细的我也不明白,反正大家都是这么用的。只保留正数元素本身,并将负数元素清零。
Relu(x)=max(x,0)
import matplotlib_inline
import torch
import numpy as np
import matplotlib.pylab as plt
import sys
sys.path.append("E:/anaconda/envs/pytorch/Lib/d2lzh_pytorch")
import d2lzh_pytorch as d2l
def xyplot(x_vals, y_vals, name):
d2l.set_figsize(figsize=(5, 2.5))
d2l.plt.plot(x_vals.detach().numpy(), y_vals.detach().numpy())
d2l.plt.xlabel('x')
d2l.plt.ylabel(name + '(x)')
能给到的注释尽量都给到了,这部分只是库的导入和函数的定义。
x=torch.arange(-8.0,8.0,0.1,requires_grad=True)#生成一个从负八到八,附带梯度的x
y=x.relu()#使用relu方法生成y的值
xyplot(x,y,'relu')#将数值传递给函数,生成图片
根据图像我们可以看出,这是一个两段线性函数。小于0的y值都是0,大于0的y值等于x值。
y.sum().backward()
xyplot(x,x.grad,'grad of relu')#绘制Relu函数的导数
当数值是负数的时候,Relu导数值为0;当数值是正数时,Relu函数的导数为1。
激活函数只介绍Relu函数一种啊兄弟们,老师只讲了这个,后面还有sigmoid函数,tanh函数各种各样可以再去了解,这里的Relu函数会用的比较多。
3.多层感知机代码实现
3.1导入库包
import torch
import numpy as np
import sys
sys.path.append("E:/anaconda/envs/pytorch/Lib/d2lzh_pytorch")
import d2lzh_pytorch as d2l
这里代码跟上面那个很接近,额外再整一遍防止搞混
3.2 获取和读取数据
这里我们使用Fashion-MNIST数据集。我们将使用多层感知机对图像进行分类。
batch_size=256
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size)#从MNIST数据集中传递训练集和测试集
3.3 定义模型参数
我们在上一篇softmax回归里知道,MNIst数据集图像为28*28=784,类别为10.输入个数为784,输出个数为10。
num_inputs,num_outputs,num_hiddens=784,10,256 #分别设置输入个数为784,输出个数为10, 隐藏单元个数为256
W1=torch.tensor(np.random.normal(0,0.01,(num_inputs,num_hiddens)),dtype=torch.float)#np.random.normal()函数是正态分布
b1=torch.zeros(num_hiddens,dtype=torch.float)
W2=torch.tensor(np.random.normal(0,0.01,(num_hiddens,num_outputs)),dtype=torch.float)
b2=torch.zeros(num_outputs,dtype=torch.float)
params=[W1,b1,W2,b2]
for param in params:
param.requires_grad_(requires_grad=True)
这里我们先将np.random.normal()函数理解一下,这是一个正态分布,normal这里就是正态的意思。
numpy.random.normal(loc=1,scale=0.01,size=shape)
其中参数:
loc(float类型):正态分布的均值,对应着这个分布的中心。loc等于0说明这是一个以Y轴为对称轴的正态分布。
scale(float类型):正态分布的标准差,对应分布的宽度,scale越大,正态分布的曲线越胖,scale越小,曲线越瘦高。
size(int或整数元组):输出的值赋在shape里,默认为None
3.4定义激活函数
这里使用基础的max函数来实现Relu,而非直接调用relu函数。
def relu(X):
return torch.max(input=X,other=torch.tensor(0.0))
有点生猛,不确定,再看看。
3.5 定义模型
def net(X):
X=X.view((-1,num_inputs))
H=relu(torch.matmul(X,W1)+b1)
return torch.matmul(H,W2)+b2
3.6定义损失函数
直接使用pytorch提供的包括softmax运算和交叉熵损失计算的函数。
loss=torch.nn.CrossEntropyLoss()
3.7计算分类准确率
def evaluate_accuracy(data_iter,net):
acc_sum,n=0.0,0
for X,y in data_iter:
acc_sum+=(net(X).argmax(dim=1)==y).float().sum().item()
n+=y.shape[0]
return acc_sum/n
3.8 训练模型
num_epochs,lr=5,100# 设置迭代周期为5,学习率为100
def train_ch3(net,train_iter,test_iter,loss,num_epochs,batch_size,params=None,lr=None,optimizer=None):
for epoch in range(num_epochs):
train_1_sum,train_acc_sum,n=0.0,0.0,0
for X,y in train_iter:
y_hat=net(X)
l=loss(y_hat,y).sum()
#梯度清零
if optimizer is not None:
optimizer.zero_grad()
elif params is not None and params[0].grad is not None:
for param in params:
param.grad.data.zero_()
l.backward()
if optimizer is None:
d2l.sgd(params,lr,batch_size)
else:
optimizer.step()
train_1_sum+=l.item()
train_acc_sum+=(y_hat.argmax(dim=1)==y).sum().item()
n+=y.shape[0]
test_acc=evaluate_accuracy(test_iter,net)
print('epoch %d,loss %.4f,train acc %.3f,test acc%.3f'%(epoch+1,train_1_sum/n,train_acc_sum/n,test_acc))
train_ch3(net,train_iter,test_iter,loss,num_epochs,batch_size,params,lr)
我们这种实现方法比较繁琐相对于直接使用pytorch提供的库来说,但是这种手动定义模型方式会更有体验和融入感。