上一篇文章:深度学习2—任意结点数的三层全连接神经网络

距离上篇文章过去了快四个月了,真是时光飞逝,之前因为要考博所以耽误了更新,谁知道考完博后之前落下的接近半个学期的工作是如此之多,以至于弄到现在才算基本填完坑,实在是疲惫至极。

另外在这段期间,发现了一本非常好的神经网络入门书籍,本篇的很多细节问题本人就是在这本书上找到的答案,强烈推荐一下:

上篇文章介绍了如何实现一个任意结点数的三层全连接神经网络。本篇,我们将利用已经写好的代码,搭建一个输入层、隐含层、输出层分别为784、100、10的三层全连接神经网络来训练闻名已久的mnist手写数字字符集,然后自己手写一个数字来看看网络是否能比较给力的工作。

在正式做之前,还是按照惯例讲几个会用到的知识点。

  1. mnist数字字符集的结构解析,这个我单独写了一篇文章来做介绍了,如有需要了解请先移步:深度学习3番外篇—mnist数据集格式及转换
  2. 我们之前都是直接放入几个数作为输入,然后给网络几个数作为目标来训练网络的,而mnist手写字符集给我们的是一堆手写的28*28像素的图片还有图片对应的手写数字标签,我们怎么对它进行转换?
    转换是这样的,我们把图片的所有像素当做输入,也就是28*28=784个像素直接作为输入,然后用0~9总共十个数作为输出目标的指引(当标签是“5”,则目标输出为0.01、0.01、0.01、0.01、0.01、0.99、0.01、0.01、0.01、0.01,依次类推)。
    这里有一点比较有意思,为什么要用0.01而不是0,用0.99而不是1?
    答案是我们用的激活函数永远不能输出0,1这两个数,因此如果取了这两个数则网络永远无法达到预期,会有训练过度的可能。
    另外,细心的你可能也想到了,我们之前输入的数都是在0-1的范围内的,而像素的灰度取值范围在0-255,因此我们需要先对灰度值做一个归一化处理然后再放入网络中。
    这里归一化处理的方式也比较有意思,假设X为输入,我们的处理公式如下:
    X÷255×0.99+0.01X÷255×0.99+0.01X÷255×0.99+0.01
    为什么要乘0.99再加0.01?
    答案是我们不希望输入取到0值,因为0有个小学生都知道的特点,任何数乘以它都等于0,因此无论输入层到隐含层的权值是多少,在输入等于0的时候都是一样的,这会影响权值的更新。
  3. 我们前面只确定了输入和输出层的节点个数,隐含层的节点个数还不知道,那我们怎么选取呢?答案可能让人难过,没有绝对正确的公式,只有几个经验公式(似乎有优化算法可以确定隐含层节点个数,后面如有需要开一篇专门讨论):
    m=n+l+αm=\sqrt{n+l}+\alpha m=n+l​+αm=log2nm=log_{2}n m=log2​nm=nlm=\sqrt{nl} m=nl​
    其中,mmm是隐含层节点数,nnn是输入层节点数,lll是输出层节点数,α\alphaα是000~101010之间的常数
    本篇取第三个,最后因为比较接近100,就直接取了100(怎么感觉好随意。。。)。
  4. 因为这次的输入节点有784个,算是比较多的,要十分注意在初始化网络参数的时候要避免参数与输入节点的积之和过大的情况出现。因为我们用的是sigmod函数作为激活函数,它的波形如下图所示:

    可以看到,如果输入的数值过大或过小,波形会趋于平缓,也就是通常所说的“梯度消失”,我们要避免这种情况的出现。当然这也是用sigmod函数作为激活函数的问题。
    那么究竟权值取多少合适呢,一般的做法是取-1~1中间的随机数,而数学家得到的经验规则告诉我们,可以在一个节点传入链接数量平方根倒数的大致范围内随机采样,初始化权值。以我们隐含层到输出层权重为例,输出层节点有100条传入链接,则其权重范围在−1/100-1/\sqrt{100}−1/100​至1/1001/\sqrt{100}1/100​之间。
  5. 最后,我们要判断输出的是否准确,则先做前向传播,得到10个输出之后,找到最大的一个跟标签对比,如果相同则网络预测正确。

那么,原理介绍完了,我们先对下图所示的第一、二张图像和相应的标签进行训练,主要代码如下(整个工程的代码会在最后面给出):

for (size_t count = 0; count < 3000; count++)
{mnet.forwardPropagation(mNumImg[0].inputdata);//前向传播mnet.backPropagation(mNumImg[0].outputdata);//反向传播mnet.forwardPropagation(mNumImg[1].inputdata);//前向传播mnet.backPropagation(mNumImg[1].outputdata);//反向传播
}
mnet.forwardPropagation(mNumImg[0].inputdata);
mnet.printresual(0);//输出结果
mnet.forwardPropagation(mNumImg[1].inputdata);
mnet.printresual(0);

运行结果如下:

可以看到训练了3000次之后该网络可以分类之前输入的两个数字了(10个数字中最大的为预测结果,为了方便后面的正确率统计,一般会写一个函数将最大的数选出来和标签进行对比,看看网络的判断是不是正确的)。
  

可以看到,该网络基本能达到96%的准确率,而且还有上升的趋势,因为训练时间感人,所以这里就不再接着训练了,据网上查询到的结果,该网络基本精确率基本到96%多一些,不到97%就到头了。


C++实现

因为网络结构都没有改,改的只是各层节点的个数,前面提到的一些注意点,因此如果对整套代码有不明白的地方可以移步前两篇文章或看看本篇前面提到的5个注意点。

因为代码量变得比较多了,因此为了方便管理将工程分成了四个文件。

setting.h

#pragma once
#include "time.h"
#include <iostream>
using namespace std;#define IPNNUM 784
#define HDNNUM 100
#define OPNNUM 10

net.hpp

#pragma once
#include "setting.h"class node
{public:double value; //数值,存储结点最后的状态double *W = NULL;    //结点到下一层的权值void initNode(int num);//初始化函数,必须调用以初始化权值个数~node();     //析构函数,释放掉权值占用内存
};void node::initNode(int num)
{W = new double[num];srand((unsigned)time(NULL));for (size_t i = 0; i < num; i++)//给权值赋一个随机值{W[i] = rand() % 100 / double(100)*0.1;if (rand() % 2){W[i] = -W[i];}}
}node::~node()
{if (W != NULL){delete[]W;}
}//网络类,描述神经网络的结构并实现前向传播以及后向传播
class net
{public:node inlayer[IPNNUM]; //输入层node hidlayer[HDNNUM];//隐含层node outlayer[OPNNUM];//输出层double yita = 0.1;//学习率ηdouble k1;//输入层偏置项权重double k2;//隐含层偏置项权重double Tg[OPNNUM];//训练目标double O[OPNNUM];//网络实际输出net();//构造函数,用于初始化各层和偏置项权重double sigmoid(double z);//激活函数double getLoss();//损失函数,输入为目标值void forwardPropagation(double *input);//前向传播,输入为输入层节点的值void backPropagation(double *T);//反向传播,输入为目标输出值void printresual(int trainingTimes);//打印信息
};net::net()
{//初始化输入层和隐含层偏置项权值,给一个随机值srand((unsigned)time(NULL));k1 = rand() % 100 / double(100);k2 = rand() % 100 / double(100);//初始化输入层到隐含层节点权重for (size_t i = 0; i < IPNNUM; i++){inlayer[i].initNode(HDNNUM);}//初始化隐含层到输出层节点权重for (size_t i = 0; i < HDNNUM; i++){hidlayer[i].initNode(OPNNUM);}
}
//激活函数
double net::sigmoid(double z)
{return 1 / (1 + exp(-z));
}
//损失函数
double net::getLoss()
{double mloss = 0;for (size_t i = 0; i < OPNNUM; i++){mloss += pow(O[i] - Tg[i], 2);}return mloss / OPNNUM;
}
//前向传播
void net::forwardPropagation(double *input)
{for (size_t iNNum = 0; iNNum < IPNNUM; iNNum++)//输入层节点赋值{inlayer[iNNum].value = input[iNNum];}for (size_t hNNum = 0; hNNum < HDNNUM; hNNum++)//算出隐含层结点的值{double z = 0;for (size_t iNNum = 0; iNNum < IPNNUM; iNNum++){z += inlayer[iNNum].value*inlayer[iNNum].W[hNNum];}z += k1;//加上偏置项hidlayer[hNNum].value = sigmoid(z);}for (size_t oNNum = 0; oNNum < OPNNUM; oNNum++)//算出输出层结点的值{double z = 0;for (size_t hNNum = 0; hNNum < HDNNUM; hNNum++){z += hidlayer[hNNum].value*hidlayer[hNNum].W[oNNum];}z += k2;//加上偏置项O[oNNum] = outlayer[oNNum].value = sigmoid(z);}
}
//反向传播,这里为了公式好看一点多写了一些变量作为中间值
//计算过程用到的公式在博文中已经推导过了,如果代码没看明白请看看博文
void net::backPropagation(double *T)
{for (size_t i = 0; i < OPNNUM; i++){Tg[i] = T[i];}for (size_t iNNum = 0; iNNum < IPNNUM; iNNum++)//更新输入层权重{for (size_t hNNum = 0; hNNum < HDNNUM; hNNum++){double y = hidlayer[hNNum].value;double loss = 0;for (size_t oNNum = 0; oNNum < OPNNUM; oNNum++){loss += (O[oNNum] - Tg[oNNum])*O[oNNum] * (1 - O[oNNum])*hidlayer[hNNum].W[oNNum];}inlayer[iNNum].W[hNNum] -= yita * loss*y*(1 - y)*inlayer[iNNum].value;}}for (size_t hNNum = 0; hNNum < HDNNUM; hNNum++)//更新隐含层权重{for (size_t oNNum = 0; oNNum < OPNNUM; oNNum++){hidlayer[hNNum].W[oNNum] -= yita * (O[oNNum] - Tg[oNNum])*O[oNNum] * (1 - O[oNNum])*hidlayer[hNNum].value;}}
}void net::printresual(int trainingTimes)
{double loss = getLoss();cout << "训练次数:" << trainingTimes << endl;cout << "loss:" << loss << endl;for (size_t oNNum = 0; oNNum < OPNNUM; oNNum++){cout << "输出" << oNNum + 1 << ":" << O[oNNum] << endl;}
}

getImg.hpp

#pragma once
#include "setting.h"class ImgData//单张图像
{public:unsigned char tag;double data[IPNNUM];double label[OPNNUM];
};class getImg
{public:ImgData* mImgData;void imgTrainDataRead(const char *datapath, const char *labelpath);~getImg();
};void getImg::imgTrainDataRead(const char *datapath, const char *labelpath)
{/***********读取图片数据***********/unsigned char readbuf[4];//信息数据读取空间FILE *f;fopen_s(&f, datapath, "rb");fread_s(readbuf, 4, 1, 4, f);//读取魔数,即文件标志位fread_s(readbuf, 4, 1, 4, f);//读取数据集图像个数int sumOfImg = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像个数fread_s(readbuf, 4, 1, 4, f);//读取数据集图像行数int imgheight = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像行数fread_s(readbuf, 4, 1, 4, f);//读取数据集图像列数int imgwidth = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像列数mImgData = new ImgData[sumOfImg];unsigned char *data = new unsigned char[IPNNUM];for (int i = 0; i < sumOfImg; i++){fread_s(data, IPNNUM, 1, IPNNUM, f);//读取数据集图像列数for (size_t px = 0; px < IPNNUM; px++)//图像数据归一化{mImgData[i].data[px] = data[px]/(double)255*0.99+0.01;}}delete[]data;fclose(f);/**********************************//***********读取标签数据***********//**********************************/fopen_s(&f, labelpath, "rb");fread_s(readbuf, 4, 1, 4, f);//读取魔数,即文件标志位fread_s(readbuf, 4, 1, 4, f);//读取数据集图像个数sumOfImg = (readbuf[0] << 24) + (readbuf[1] << 16) + (readbuf[2] << 8) + readbuf[3];//图像个数for (int i = 0; i < sumOfImg; i++){fread_s(&mImgData[i].tag, 1, 1, 1, f);//读取数据集图像列数for (size_t j = 0; j < 10; j++){mImgData[i].label[j] = 0.01;}mImgData[i].label[mImgData[i].tag] = 0.99;}fclose(f);
}getImg::~getImg()
{delete[]mImgData;
}

BPNetC.cpp

#include "setting.h"
#include "net.hpp"//神经网络
#include "getImg.hpp"//训练数据void AccuracyRate(int time, net *mnet, getImg *mImg)//精确率评估
{double tagright = 0;//正确个数统计for (size_t count = 0; count < 10000; count++){mnet->forwardPropagation(mImg->mImgData[count].data);//前向传播double value = -100;int gettag = -100;for (size_t i = 0; i < 10; i++){if (mnet->outlayer[i].value > value){value = mnet->outlayer[i].value;gettag = i;}}if (mImg->mImgData[count].tag == gettag){tagright++;}}//mnet.printresual(0);//信息打印cout << "第" << time + 1 << "轮:  ";cout << "正确率为:" << tagright / 10000 << endl;
}int main()
{getImg mGetTrainImg;mGetTrainImg.imgTrainDataRead("train-images.idx3-ubyte", "train-labels.idx1-ubyte");getImg mGetTestImg;mGetTestImg.imgTrainDataRead("t10k-images.idx3-ubyte", "t10k-labels.idx1-ubyte");net mnet;//神经网络对象for (size_t j = 0; j < 10; j++){for (size_t i = 0; i < 60000; i++){mnet.forwardPropagation(mGetTrainImg.mImgData[i].data);//前向传播mnet.backPropagation(mGetTrainImg.mImgData[i].label);//反向传播}AccuracyRate(j,&mnet, &mGetTestImg);}std::cout << "搞完收工!\n";
}

python实现

距离C++第一个版本完成过去了有半年多了,因为入学后各种事情搞得分身乏术,剩下一点时间也用来打游戏调解了哈哈哈。

最近因为研究需要!!! 又开始看神经网络,因此顺便修改了C++的第一个版本,并且把python版本也做了出来。万万没想到之前写的版本有bug,调了一天才调通了,看了之前文章python代码的同志们实在是抱歉!

另外,虽然完美的跑通了代码(其实也就是把C++版本翻译了一下),但python的运行速度之低实在是让人想哭(这里有极大部分是本人水平不够的关系,但本人一点都不想去学怎么提高其效率,因为不需要)。因此,在这篇过后将直接取消python实现这一块,哈哈哈哈哈!那么就用该块最后一份代码送它上路吧!

ReadData.py

import numpy as np
import structdef loadImageSet(filename):print ("load image set",filename)binfile= open(filename, 'rb')buffers = binfile.read()head = struct.unpack_from('>IIII' , buffers ,0)print ("head,",head)offset = struct.calcsize('>IIII')imgNum = head[1]width = head[2]height = head[3]#[60000]*28*28bits = imgNum * width * heightbitsString = '>' + str(bits) + 'B' #读取定长数据段,即字符集图片总和imgs = struct.unpack_from(bitsString,buffers,offset)binfile.close()imgs = np.reshape(imgs,[imgNum,1,width*height])#将字符集图片分隔为单张图片print ("load imgs finished")return imgsdef loadLabelSet(filename):print ("load label set",filename)binfile = open(filename, 'rb')buffers = binfile.read()head = struct.unpack_from('>II' , buffers ,0)print ("head,",head)imgNum=head[1]offset = struct.calcsize('>II')numString = '>'+str(imgNum)+"B"labels = struct.unpack_from(numString , buffers , offset)binfile.close()labels = np.reshape(labels,[imgNum,1])print ('load label finished')return labels

BPNetPy.py

import ReadData as rd
import matplotlib.pyplot as plt
import math
import random
import numpy as npIPNNUM=784     #输入层节点数
HDNNUM=100    #隐含层节点数
OPNNUM=10     #输出层节点数class node:#结点类,用以构成网络def __init__(self,connectNum=0):self.value=0 #数值,存储结点最后的状态,对应到文章示例为X1,Y1等值self.W = (2*np.random.random_sample(connectNum)-1)*0.01class net:#网络类,描述神经网络的结构并实现前向传播以及后向传播def __init__(self):#初始化函数,用于初始化各层间节点和偏置项权重#输入层结点self.inlayer=[node(HDNNUM)];for obj in range(1, IPNNUM):self.inlayer.append(node(HDNNUM)) #隐含层结点self.hidlayer=[node(OPNNUM)];for obj in range(1, HDNNUM):self.hidlayer.append(node(OPNNUM))             #输出层结点self.outlayer=[node(0)];for obj in range(1, OPNNUM):self.outlayer=[node(0)]                 self.yita = 0.1                                            #学习率ηself.k1=random.random()                       #输入层偏置项权重self.k2=random.random()                       #隐含层偏置项权重self.Tg=np.zeros(OPNNUM)                   #训练目标self.O=np.zeros(OPNNUM)                     #网络实际输出def sigmoid(self,z):#激活函数return 1 / (1 + math.exp(-z))def getLoss(self):#损失函数loss=0for num in range(0, OPNNUM):loss+=pow(self.O[num] -self.Tg[num],2)return loss/OPNNUMdef forwardPropagation(self,input):#前向传播for i in range(0, IPNNUM):#输入层节点赋值self.inlayer[i].value = input[i]for hNNum in range(0,HDNNUM):#算出隐含层结点的值z = 0for iNNum in range(0,IPNNUM):z+=self.inlayer[iNNum].value*self.inlayer[iNNum].W[hNNum]#加上偏置项z+= self.k1self.hidlayer[hNNum].value = self.sigmoid(z)for oNNum in range(0,OPNNUM):#算出输出层结点的值z = 0for hNNum in range(0,HDNNUM):z += self.hidlayer[hNNum].value* self.hidlayer[hNNum].W[oNNum]z += self.k2self.O[oNNum] = self.sigmoid(z)def backPropagation(self,T):#反向传播,这里为了公式好看一点多写了一些变量作为中间值for num in range(0, OPNNUM):self.Tg[num] = T[num]for iNNum in range(0,IPNNUM):#更新输入层权重for hNNum in range(0,HDNNUM):y = self.hidlayer[hNNum].valueloss = 0for oNNum in range(0, OPNNUM):loss+=(self.O[oNNum] - self.Tg[oNNum])*self.O[oNNum] * (1 - self.O[oNNum])*self.hidlayer[hNNum].W[oNNum]self.inlayer[iNNum].W[hNNum] -= self.yita*loss*y*(1- y)*self.inlayer[iNNum].valuefor hNNum in range(0,HDNNUM):#更新隐含层权重for oNNum in range(0,OPNNUM):self.hidlayer[hNNum].W[oNNum]-= self.yita*(self.O[oNNum] - self.Tg[oNNum])*self.O[oNNum]*\(1- self.O[oNNum])*self.hidlayer[hNNum].valuedef printresual(self,trainingTimes):#信息打印loss = self.getLoss()print("训练次数:", trainingTimes)print("loss",loss)for oNNum in range(0,OPNNUM):print("输出",oNNum,":",self.O[oNNum])#主程序
mnet=net()
imgs=rd.loadImageSet("train-images.idx3-ubyte");
labels=rd.loadLabelSet("train-labels.idx1-ubyte");
##显示图像
#im=np.array(input)
#im = im.reshape(28,28)
#fig = plt.figure()
#plotwindow = fig.add_subplot(111)
#plt.imshow(im , cmap='gray')
#plt.show()
for n in range(0,1000):print(n)for x in range(0,3):input=(imgs[x,:]/255*0.99+0.01).ravel() #ravel多维转1维target=np.ones(10)*0.01target[labels[x]]=0.99mnet.forwardPropagation(input)mnet.backPropagation(target)if (n%200==0):mnet.printresual(n)

pytorch的CPU实现

# coding=utf-8
import time
import torch
import torch.nn as nn
from torch.autograd import Variable
import torchvision.datasets as dsets
import torchvision.transforms as transforms#网络模型
class Net(nn.Module):def __init__(self):#定义Net的初始化函数,这个函数定义了该神经网络的基本结构super(Net, self).__init__() #复制并使用Net的父类的初始化方法,即先运行nn.Module的初始化函数self.intohid_layer = nn.Linear(784, 100) #定义输入层到隐含层的连结关系函数self.hidtoout_layer = nn.Linear(100, 10)#定义隐含层到输出层的连结关系函数def forward(self, input):#定义该神经网络的向前传播函数,该函数必须定义,一旦定义成功,向后传播函数也会自动生成x = torch.sigmoid(self.intohid_layer(input))   #输入input在输入层经过经过加权和与激活函数后到达隐含层x = torch.sigmoid(self.hidtoout_layer(x))       #类似上面return xmnet = Net()
#数据集
train_dataset = dsets.MNIST(root = '../mnist/', #选择数据的根目录train = True, # 选择训练集transform = transforms.ToTensor(), # 转换成tensor变量download = False) # 不从网络上download图片
test_dataset = dsets.MNIST(root = '../mnist/', # 选择数据的根目录train = False, # 选择训练集transform = transforms.ToTensor(),# 转换成tensor变量download = False) # 不从网络上download图片
# 加载数据
train_loader = torch.utils.data.DataLoader(dataset = train_dataset, batch_size = 1,#每一次训练选用的数据个数shuffle = False)#将数据打乱
test_loader = torch.utils.data.DataLoader(dataset = test_dataset,batch_size = 1000,#每一次训练选用的数据个数shuffle = False)loss_fn = torch.nn.MSELoss()#损失函数定义,可修改
optimizer = torch.optim.SGD(mnet.parameters(), lr = 0.1, momentum=0.9)start = time.time()for epoch in range(1):#训练次数print('current epoch = %d' % epoch)for i, (images, labels) in enumerate(train_loader): #利用enumerate取出一个可迭代对象的内容images = Variable(images.view(-1, 28 * 28))labels = Variable(labels)labels = torch.LongTensor(labels).view(-1,1)#将标签转为单列矩阵target= torch.zeros(1, 10).scatter_(dim = 1, index = labels, value = 0.98)#将标签转为onehot形式target+=0.01optimizer.zero_grad()               #清空节点值outputs = mnet(images)          #前向传播loss = loss_fn(outputs, target)  #损失计算loss.backward()                         #后向传播optimizer.step()                         #更新权值if i % 10000 == 0:print(i)total = 0correct = 0.0for images, labels in test_loader:images = Variable(images.view(-1, 28 * 28))outputs = mnet(images)                                        #前向传播_, predicts = torch.max(outputs.data, 1)                #返回预测结果total += labels.size(0)correct += (predicts == labels).sum()print('Accuracy = %.2f' % (100 * float(correct) / total))end = time.time()
print('花费时间%.2f' % (end - start))

上面的代码在频率为3.40GHz的电脑上,训练10遍,每次都遍历一整个训练集要花费1000s左右,也就是16.7分钟左右,因全连接神经网络的过拟合问题,正确率基本到了97.5%之后就再也升不上去了。

pytorch的GPU实现

# coding=utf-8
import time
import torch
import torch.nn as nn
from torch.autograd import Variable
import torchvision.datasets as dsets
import torchvision.transforms as transforms#网络模型
class Net(nn.Module):def __init__(self):#定义Net的初始化函数,这个函数定义了该神经网络的基本结构super(Net, self).__init__() #复制并使用Net的父类的初始化方法,即先运行nn.Module的初始化函数self.intohid_layer = nn.Linear(784, 100) #定义输入层到隐含层的连结关系函数self.hidtoout_layer = nn.Linear(100, 10)#定义隐含层到输出层的连结关系函数def forward(self, input):#定义该神经网络的向前传播函数,该函数必须定义,一旦定义成功,向后传播函数也会自动生成x = torch.sigmoid(self.intohid_layer(input))   #输入input在输入层经过经过加权和与激活函数后到达隐含层x = torch.sigmoid(self.hidtoout_layer(x))       #类似上面return xmnet = Net().cuda()
#数据集
train_dataset = dsets.MNIST(root = '../mnist/', #选择数据的根目录train = True, # 选择训练集transform = transforms.ToTensor(), # 转换成tensor变量download = False) # 不从网络上download图片
test_dataset = dsets.MNIST(root = '../mnist/', # 选择数据的根目录train = False, # 选择训练集transform = transforms.ToTensor(),# 转换成tensor变量download = False) # 不从网络上download图片
# 加载数据
train_loader = torch.utils.data.DataLoader(dataset = train_dataset, batch_size = 1,#每一次训练选用的数据个数shuffle = False)#将数据打乱
test_loader = torch.utils.data.DataLoader(dataset = test_dataset,batch_size = 1000,#每一次训练选用的数据个数shuffle = False)loss_fn = torch.nn.MSELoss()#损失函数定义,可修改
optimizer = torch.optim.SGD(mnet.parameters(), lr = 0.1, momentum=0.9)start = time.time()for epoch in range(1):#训练次数print('current epoch = %d' % epoch)for i, (images, labels) in enumerate(train_loader): #利用enumerate取出一个可迭代对象的内容images = Variable(images.view(-1, 28 * 28).cuda())labels = Variable(labels.cuda())labels = torch.cuda.LongTensor(labels).view(-1,1)#将标签转为单列矩阵target= torch.zeros(1, 10).cuda().scatter_(dim = 1, index = labels, value = 0.98)#将标签转为onehot形式target+=0.01optimizer.zero_grad()               #清空节点值outputs = mnet(images)           #前向传播loss = loss_fn(outputs, target)  #损失计算loss.backward()                          #后向传播optimizer.step()                         #更新权值if i % 10000 == 0:print(i)total = 0correct = 0.0for images, labels in test_loader:images = Variable(images.view(-1, 28 * 28).cuda())outputs = mnet(images)                                        #前向传播_, predicts = torch.max(outputs.data, 1)                #返回预测结果total += labels.size(0)correct += (predicts == labels.cuda()).sum()print('Accuracy = %.2f' % (100 * float(correct) / total))end = time.time()
print('花费时间%.2f' % (end - start))

深度学习3—用三层全连接神经网络训练MNIST手写数字字符集相关推荐

  1. 基于PyTorch框架的多层全连接神经网络实现MNIST手写数字分类

    多层全连接神经网络实现MNIST手写数字分类 1 简单的三层全连接神经网络 2 添加激活函数 3 添加批标准化 4 训练网络 5 结论 参考资料 先用PyTorch实现最简单的三层全连接神经网络,然后 ...

  2. 全连接神经网络实现MNIST手写数字识别

    在对全连接神经网络的基本知识(全连接神经网络详解)学习之后,通过MNIST手写数字识别这个小项目来学习如何实现全连接神经网络. MNIST数据集 对于深度学习的任何项目来说,数据集是其中最为关键的部分 ...

  3. PyTorch基础入门五:PyTorch搭建多层全连接神经网络实现MNIST手写数字识别分类

    )全连接神经网络(FC) 全连接神经网络是一种最基本的神经网络结构,英文为Full Connection,所以一般简称FC. FC的准则很简单:神经网络中除输入层之外的每个节点都和上一层的所有节点有连 ...

  4. MINIST深度学习识别:python全连接神经网络和pytorch LeNet CNN网络训练实现及比较(三)...

    版权声明:本文为博主原创文章,欢迎转载,并请注明出处.联系方式:460356155@qq.com 在前两篇文章MINIST深度学习识别:python全连接神经网络和pytorch LeNet CNN网 ...

  5. 图像识别python cnn_MINIST深度学习识别:python全连接神经网络和pytorch LeNet CNN网络训练实现及比较(一)...

    版权声明:本文为博主原创文章,欢迎转载,并请注明出处.联系方式:460356155@qq.com 全连接神经网络是深度学习的基础,理解它就可以掌握深度学习的核心概念:前向传播.反向误差传递.权重.学习 ...

  6. 使用 全连接神经网络 训练MNIST数据分类模型

    (一) 实验目的 使用简单的全连接层神经网络对MNIST手写数字图片进行分类.通过本次实验,可以掌握如下知识点: 学习 TensorFlow2 神经网络模型构建方式: 学习 tf.keras.laye ...

  7. 【神经网络与深度学习】 Numpy 实现全连接神经网络

    1.实验名称 Numpy 实现全连接神经网络实验指南 2.实验要求 用 python 的 numpy 模块实现全连接神经网络. 网络结构为一个输入层.一个隐藏层.一个输出层. 隐藏层的激活函数为 Re ...

  8. 深蓝学院第二章:基于全连接神经网络(FCNN)的手写数字识别

    如何用全连接神经网络去做手写识别??? 使用的是jupyter notebook这个插件进行代码演示.(首先先装一个Anaconda的虚拟环境,然后自己构建一个自己的虚拟环境,然后在虚拟环境中安装ju ...

  9. 深度学习2---任意结点数的三层全连接神经网络

    上一篇文章:深度学习1-最简单的全连接神经网络 我们完成了一个三层(输入+隐含+输出)且每层都具有两个节点的全连接神经网络的原理分析和代码编写.本篇文章将进一步探讨如何把每层固定的两个节点变成任意个节 ...

最新文章

  1. 内存错误 处理 [CAlayer release]
  2. 九度 1371 最小的K个数
  3. Node中的Http模块和Url模块的使用
  4. leetcode 1306. Jump Game III | 1306. 跳跃游戏 III(BFS)
  5. 检查电脑是否被安装木马三个小命令
  6. C语言 结构体的初次运用
  7. BestCoder Round #36 [B] Gunner
  8. C.One Piece
  9. 下岗工人到达退休年龄,养老保险未缴纳满15年,补缴合适吗?
  10. Failed to find Build Tools revision 28.0.3
  11. Springboot属性配置绑定
  12. 黑马程序员全套Java教程_Java基础入门视频教程零基础自学Java必备教程视频讲义(4)
  13. 挑战云主机战:学习使用云端服器象棋云库
  14. AutoCAD Civil 3D-横断面-创建横断面、横断面图及采样线的编辑(断面法工程量计算)
  15. 微信订阅消息模板消息推送-JAVA
  16. 强化学习10——迭代学习
  17. joomla新建模板_WordPress v Joomla:模板和主题
  18. 小瘦牛虚拟无线路由器官方版
  19. 20年管理学范围内知识点(潘永明)by:PoilZero
  20. Kubernetes第二曲 集群部署(Etcd+Flannel)

热门文章

  1. 第六讲 Linux字符设备驱动1
  2. 二项堆与斐波那契堆各个操作时间复杂度
  3. win7系统快捷键大集合 这个最有感觉了~~:~~ 【Win+Tab】:3D切换窗口
  4. acg缩写_ACG如何在Alexa上使屡获殊荣的技术播客栩栩如生,以及我们在此过程中学到的知识...
  5. 工程图字体宋体仿宋_宋体字的发明与秦桧无关
  6. ssh备考-02多表关联关系映射(一对一、一对多、多对多如何配置)
  7. regular expression grammer
  8. 重组人碱性成纤维细胞生长因子参数说明
  9. 轻流入选 Forrester 中国制造商通过低代码加速价值交付案例研究报告
  10. mac 删除Provisioning Profiles(描述文件)