大数据文摘出品

作者:蒋宝尚

小伙伴们大家好呀~~用Numpy搭建神经网络,我们已经来到第三期了。第一期文摘菌教大家如何用Numpy搭建一个简单的神经网络,完成了前馈部分。第二期为大家带来了梯度下降相关的知识点。

这一期,教大家如何读取数据集,以及将数据集用于神经网络的训练,和上两期一样,这次依然用Numpy实现。在开始代码之前,文摘菌先带大家看看今天我们使用的数据集。

数据集介绍

数据集采用著名的MNIST的手写数据集。根据官网介绍,这个数据集有70000个样本,包括60000个训练样本,10000个测试样本。

数据集下载下来之后,文件分为4个部分,分别是:训练集图片、训练集标签、测试集图片、测试集标签。这些数据以二进制的格式储存。

其中,训练集图片文件的前16个字节是储存了图片的个数,行数以及列数等。训练集标签文件前8个字节储存了图片标签的个数等。测试集的两个文件同理。

文摘菌下载好的文件存储地址

读取数据

train_img_path=r'C:\Users\Dell\MNIST\train-images.idx3-ubyte'train_lab_path=r'C:\Users\Dell\MNIST\train-labels.idx1-ubyte'test_img_path=r'C:\Users\Dell\MNIST\t10k-images.idx3-ubyte'test_lab_path=r'C:\Users\Dell\MNIST\t10k-labels.idx1-ubyte'

根据文件在本地解压后的储存地址,生成四个地址,上面代码中‘r’是转义字符,因为\在Python中有特殊的用法,所以需用转义字符明确文件地址。

为了让后面的模型表现更好,我们将训练集拆分,拆成50000个训练集和10000个验证集。

注:验证集是模型训练过程中单独留出的样本集,它可以用于调整模型的超参数和用于对模型的能力进行初步评估。

import structtrain_num=50000valid_num=10000test_num=10000with open(train_img_path,'rb') as f:    struct.unpack('>4i',f.read(16))    tmp_img=np.fromfile(f,dtype=np.uint8).reshape(-1,28*28)    train_img=tmp_img[:train_num]  #前五万个数据是训练集    valid_img=tmp_img[train_num:]  #第五万到第六万个数据是测试集    with open(test_img_path,'rb') as f:    struct.unpack('>4i',f.read(16))    test_img=np.fromfile(f,dtype=np.uint8).reshape(-1,28*28)with open(train_lab_path,'rb') as f:    struct.unpack('>2i',f.read(8))    tmp_lab=np.fromfile(f,dtype=np.uint8)    train_lab=tmp_lab[:train_num]     valid_lab=tmp_lab[train_num:]with open(test_lab_path,'rb') as f:    struct.unpack('>2i',f.read(8))    test_lab=np.fromfile(f,dtype=np.uint8)

因为,文件是以二进制的格式储存,所以数据读取方式是‘rb’。又因为我们需要数据以阿拉伯数字的方式显示。所以这里用到了Python的struct包。struct.unpack('>4i',f.read(16))中的>号代表字节存储的方向,i是整数,4代表需要前4个整数。f.read(16)是指读取16个字节,即4个整数,因为一个整数等于4个字节。

reshape(-1,28*28):如果参数中存在-1,表示该参数由其他参数来决定.-1是将一维数组转换为二维的矩阵,并且第二个参数是表示每一行数的个数。

注:fromfile的用法np.fromfile (frame, dtype=np.float, count=‐1, sep=''),其中:frame : 文件、字符串。dtype :读取的数据类型。count : 读入元素个数,‐1表示读入整个文件。sep : 数据分割字符串。

文件读取完成,接下来按照用图片的方式显示数据。

import matplotlib.pyplot as pltdef show_train(index):    plt.imshow(train_img[index].reshape(28,28),cmap='gray')    print('label:{}'.format(train_lab[index]))def show_test(index):    plt.imshow(train_img[index].reshape(28,28),cmap='gray')    print('label:{}'.format(test_lab[index]))def valid_train(index):    plt.imshow(valid_img[index].reshape(28,28),cmap='gray')    print('label:{}'.format(valid_lab[index]))

注意,如果不定义cmap='gray',图片的底色会非常奇怪。

测试一下,定义完函数之后,显示的是这样的~

数据显示和读取完成,接下来开始训练参数。

训练数据

在开始之前,为了能够上下衔接,我们把第一次课程的代码贴上来~

def tanh(x):  return np.tanh(x)def softmax(x):  exp = np.exp(x-x.max())  return exp/exp.sum()dimensions = [28*28,10]activation = [tanh,softmax]distribution=[{  'b':[0,0]},{  'b':[0,0],  'w':[-math.sqrt(6/(dimensions[0]+dimensions[1])),math.sqrt(6/(dimensions[0]+dimensions[1]))]}]# 初始化参数bdef init_parameters_b(layer):  dist = distribution[layer]['b']  return np.random.rand(dimensions[layer])*(dist[1]-dist[0])+dist[0]# 初始化参数wdef init_parameters_w(layer):  dist = distribution[layer]['w']  return np.random.rand(dimensions[layer-1],dimensions[layer])*(dist[1]-dist[0])+dist[0]#初始化参数方法def init_parameters():  parameter=[]  for i in range(len(distribution)):    layer_parameter={}    for j in distribution[i].keys():      if j=='b':        layer_parameter['b'] = init_parameters_b(i)        continue;      if j=='w':        layer_parameter['w'] = init_parameters_w(i)        continue    parameter.append(layer_parameter)  return parameter# 预测函数def predict(img,init_parameters):  l0_in = img+parameters[0]['b']  l0_out = activation[0](l0_in)  l1_in = np.dot(l0_out,parameters[1]['w'])+parameters[1]['b']  l1_out = activation[1](l1_in)  return l1_out

先定义两个激活函数的导数,导数的具体推到过程在这里不呈现,感兴趣的同学可以自行搜索。

def d_softmax(data):  sm = softmax(data)  return np.diag(sm)-np.outer(sm,sm)def d_tanh(data):  return 1/(np.cosh(data))**2differential = {softmax:d_softmax,tanh:d_tanh}

其中tanh的导数 是np.diag(1/(np.cosh(data))**2),进行优化后的结果是1/(np.cosh(data))**2

注:diag生成对角矩阵 ,outer函数的作用是第一个参数挨个乘以第二个参数得到矩阵

然后定义一个字典,并将数解析为某一位置为1的一维矩阵

differential = {softmax:d_softmax,tanh:d_tanh}onehot = np.identity(dimensions[-1])

求平方差函数,其中parameters是我们在第一次课程定义的那个初始化的参数,在训练的过程中,会自动更新。

def sqr_loss(img,lab,parameters):  y_pred = predict(img,parameters)  y = onehot[lab]  diff = y-y_pred  return np.dot(diff,diff)

计算梯度

def grad_parameters(img,lab,init_parameters):  l0_in = img+parameters[0]['b']  l0_out = activation[0](l0_in)  l1_in = np.dot(l0_out,parameters[1]['w'])+parameters[1]['b']  l1_out = activation[1](l1_in)  diff = onehot[lab]-l1_out  act1 = np.dot(differential[activation[1]](l1_in),diff)  grad_b1 = -2*act1  grad_w1 = -2*np.outer(l0_out,act1)    # 与上文优化d_tanh有关,将矩阵乘法化为数组乘以矩阵  grad_b0 = -2*differential[activation[0]](l0_in)*np.dot(parameters[1]['w'],act1)  return {'b1':grad_b1,'w1':grad_w1,'b0':grad_b0}

这次的梯度计算公式用到了公式:(y_predict-y)^2,根据复合函数求导,所以有-2(y_prdict-y)乘以相关的导数,这也是grad_b1后面-2的来历。

按理说应该更加导数的定义[f(x+h)-f(x)]/h验证下我们的梯度求的对不对,为了照顾新手同学对神经网络的理解过程,这一步在这儿省略了哈。

下面进入训练环节,我们将数据以batch的方式输入,每个batch定位包含100个图片。batch_size=100。梯度的获取是用平均求得的,代码体现在:grad_accu[key]/=batch_size。

def train_batch(current_batch,parameters):  grad_accu = grad_parameters(train_img[current_batch*batch_size+0],train_lab[current_batch*batch_size+0],parameters)  for img_i in range(1,batch_size):    grad_tmp = grad_parameters(train_img[current_batch*batch_size+img_i],train_lab[current_batch*batch_size+img_i],parameters)    for key in grad_accu.keys():      grad_accu[key] += grad_tmp[key]  for key in grad_accu.keys():    grad_accu[key]/=batch_size  return grad_accuimport copydef combine_parameters(parameters,grad,learn_rate):  parameter_tmp = copy.deepcopy(parameters)  parameter_tmp[0]['b'] -= learn_rate*grad['b0']  parameter_tmp[1]['b'] -= learn_rate*grad['b1']  parameter_tmp[1]['w'] -= learn_rate*grad['w1']  return parameter_tmp

采用copy机制,是避免parameters变化影响全局的训练,copy.deepcopy可以重新拷贝不影响原来的数据。

并且这里用到了公式:

然后定义学习率:

def learn_self(learn_rate):  for i in range(train_num//batch_size):    if i%100 == 99:      print("running batch {}/{}".format(i+1,train_num//batch_size))    grad_tmp = train_batch(i,parameters)    global parameters    parameters = combine_parameters(parameters,grad_tmp,learn_rate)

里面的if语句可以让我们看到神经网络训练的进度。

到这里,我们就完成了神经网络的一次训练,为了验证准确度如何,我们可以用验证集看看准确度如何。

定义验证集的损失:

def valid_loss(parameters):  loss_accu = 0  for img_i in range(valid_num):    loss_accu+=sqr_loss(valid_img[img_i],valid_lab[img_i],parameters)  return loss_accu

计算准确度:

def valid_accuracy(parameters):  correct = [predict(valid_img[img_i],parameters).argmax()==valid_lab[img_i] for img_i in range(valid_num) ]  print("validation accuracy:{}".format(correct.count(True)/len(correct)))

最后得到结果:

有90%的准确度哎~结果还好,还好,毕竟没有怎么调学习率以及解决过拟合。

好了,这一期的内容就到这了,内容有些多大家多多消化,下一期我们讲讲怎么调节学习率以及看看更复杂的神经网络。

*注:此篇文章受B站up主大野喵渣的启发,并参考了其代码,感兴趣的同学可以去B站观看他关于神经网络的教学视频,以及到他的Github地址逛逛。

视频地址与Github:

https://www.bilibili.com/video/av51197008

https://github.com/YQGong

实习/全职编辑记者招聘ing

加入我们,亲身体验一家专业科技媒体采写的每个细节,在最有前景的行业,和一群遍布全球最优秀的人一起成长。坐标北京·清华东门,在大数据文摘主页对话页回复“招聘”了解详情。简历请直接发送至zz@bigdatadigest.cn

点「在看」的人都变好看了哦

c++读取图片_手工计算神经网络第三期:数据读取与完成训练相关推荐

  1. Python神经网络4之数据读取、神经网络

    Python神经网络4之数据读取.神经网络 数据读取 文件读取流程 构造文件名队列 读取与解码 批处理 线程操作 图片数据 图像基本知识 图片三要素 张量形状 图片特征值处理 数据格式 案例:狗图片读 ...

  2. os如何读取图片_图片批处理|必备小技能

    微信公众号:*AI算法与图像处理 关注可了解更多的编程小技巧和优质资源.问题或建议,请公众号留言;如果你觉得对你有帮助,欢迎 好看和分享哈 内容目录 图片批处理 简介具体事项1)分析文件的存储情况2) ...

  3. c++读取图片_四、faster-rcnn源码阅读:数据流读取

    数据读取在faster-rcnn源码里是比较简单的部分,但也是非常重要的部分,不了解数据,就不可能了解算法. 另一方面,由于python环境碎片话化,源码调用的库在你的电脑上如果碰巧(其实概率还蛮大, ...

  4. matlab 行 读取文件 跳过_MATLAB对于文本文件(txt)数据读取的技巧总结(经典中的经典)...

    本帖最后由 rocwoods 于 2010-12-29 15:09 编辑 振动论坛原版主eight的经典贴http://www.chinavib.com/thread-45622-1-1.html M ...

  5. opencv java 显示图片_【opencv三】利用opencv读取显示图片

    在opencv中读取显示图片的头文件是highgui.hpp. 整体代码如下,如要测试自己的图片,需要将代码段中的图片地址更改为自己图片的绝对路径. #include "opencv2/hi ...

  6. java nio 读取图片_给大忙人们看的 Java NIO 极简教程

    作者 | JavaEdge 来源 | JavaEdge(ID:Java-Edge) 头图 | CSDN 下载自东方IC Java NIO 的Buffer用于和NIO Channel(通道)交互.数据是 ...

  7. python read()读取图片_可以python sitk.ReadImage读取列表/系列图像吗?

    我不明白sitk.ReadImage是否可以读取或不读取图像列表?我没有设法找到一个示例显示如何列出图像应该输入到函数. 但是在功能文件中它说: ReadImage(**VectorString fi ...

  8. 从mysql读取图片_如何从sql数据库内读取图片

    privatevoidSHOW(){MemoryStreamstream=newMemoryStream();byte[]buffByte=null;stringsqlstr="select ...

  9. 实现picturecontrol控件显示图片_陕西曝光机触摸屏实时数据控件

    随着市场需求的快速发展,PCB行业对产能的要求与日俱增.为了在保证品质的前提下快速提高产能,PCB曝光领域掀起了一场新的革命,那就是对传统曝光机进行UVLED改造,用UVLED光源代替传统汞灯.目前市 ...

最新文章

  1. 程序员大厂不一定要进,算法必须要学!收藏89篇精选算法文章
  2. h5 调起相机_Html5在手机端调用相机的方法实现
  3. 1的个数 itoa函数使用
  4. 6. ZooKeeper访问控制列表
  5. linux集成开发环境
  6. 前端vscode插件合集
  7. 会议交流 | 第十五届全国知识图谱与语义计算大会(CCKS 2021)12月25日线上召开...
  8. Oracle冷备迁移过程和在线日志损坏处理
  9. use redis instance in docker hub
  10. Unity UGUI——Text组件(Character)
  11. 驰为HI8刷Win10系统出现红屏错误如何解决
  12. 最简单!阿里云服务器采用 LNMP一键安装包 配置 Linux+Nginx+Mysql+PHP
  13. 什么是法线贴图 今天教你如何制作法线贴图
  14. 跨站脚本攻击-----为什么要过滤危险字符串
  15. 图片格式导致的报错:Attribute Error: ‘NoneType‘ object has no attribute ‘astype‘ 解决方案
  16. Win7及以上笔记本设置共享WiFi热点
  17. 微信小程序图表插件(wx-charts)
  18. 联想笔记本电脑w530更换电池的电芯并进行软件重置,不再提示更换电池
  19. 自动脚本以及打包,将写好的脚本打包成exe可执行文件
  20. PHP微信公众平台开发高级篇—生成二维码接口

热门文章

  1. Yii游客允许查看页面设置
  2. 子菜单挤压下方块元素_小心上瘾!全新类型的消除游戏|《土耳其方块》
  3. java set中元素是数组_将HashSet中的元素转换为Java中的数组
  4. vue滚动条滚到到底部触发的方法
  5. PHP根据地址 获取坐标 thinkphp根据地址 获取坐标(百度地图)
  6. c++ map是有序还是无序的_C++ STL中Map的按Key排序和按Value排序
  7. ldap导入mysql_openLDAP 部署(亲测可用)
  8. python批量执行linux命令并写入log日志
  9. mysql 5.7.20主从配置_mysql5.7.20免安装版配置方法图文教程
  10. c++求平均值_云顶之弈S4:六射手娱乐吃鸡!人均刮痧王,每个人都是主C