读书笔记:神经网络的学习 train_neuralnet.py ← 斋藤康毅

news2024/12/22 18:17:08

提醒:本例涉及到三个 Python 文件,即 two_layer_net.pytrain_neuralnet.pymnist.py 等。

显然,要进行神经网络的学习,必须先构建神经网络。
因此,本文先构建了一个2层神经网络。代码详见 
two_layer_net.py,内容如下:

import numpy as np
import sys,os
sys.path.append(os.pardir)

def sigmoid(x):
    return 1/(1+np.exp(-x))   

def sigmoid_grad(x):
    return (1.0-sigmoid(x))*sigmoid(x)

def softmax(x):
    if x.ndim==2:
        x=x.T
        x=x-np.max(x,axis=0)
        y=np.exp(x)/np.sum(np.exp(x),axis=0)
        return y.T 

    x=x-np.max(x)
    return np.exp(x)/np.sum(np.exp(x))

def cross_entropy_error(y,t):
    if y.ndim==1:
        t=t.reshape(1,t.size)
        y=y.reshape(1,y.size)
        
    if t.size==y.size:
        t=t.argmax(axis=1)
             
    batch_size=y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size),t]+1e-7))/batch_size

def numerical_gradient_no_batch(f,x):
    h=1e-4
    grad=np.zeros_like(x)
    
    for idx in range(x.size):
        tmp_val=x[idx]
        x[idx]=float(tmp_val)+h
        fxh1=f(x)
        
        x[idx]=tmp_val-h 
        fxh2=f(x)
        grad[idx]=(fxh1-fxh2)/(2*h)
        
        x[idx]=tmp_val
        
    return grad
 
def numerical_gradient(f,X):
    if X.ndim==1:
        return numerical_gradient_no_batch(f,X)
    else:
        grad=np.zeros_like(X)
        
        for idx,x in enumerate(X):
            grad[idx]=numerical_gradient_no_batch(f,x)
        
        return grad


class TwoLayerNet:
    def __init__(self,input_size,hidden_size,output_size,weight_init_std=0.01):
        # 初始化权重
        self.params={}
        self.params['W1']=weight_init_std*np.random.randn(input_size,hidden_size)
        self.params['b1']=np.zeros(hidden_size)
        self.params['W2']=weight_init_std*np.random.randn(hidden_size,output_size)
        self.params['b2']=np.zeros(output_size)

    def predict(self,x):
        W1,W2=self.params['W1'],self.params['W2']
        b1,b2=self.params['b1'],self.params['b2']
    
        a1=np.dot(x,W1)+b1
        z1=sigmoid(a1)
        a2=np.dot(z1,W2)+b2
        y=softmax(a2)
        
        return y
        
    # x:输入数据,t:监督数据
    def loss(self,x,t):
        y=self.predict(x)
        
        return cross_entropy_error(y,t)
    
    def accuracy(self,x,t):
        y=self.predict(x)
        y=np.argmax(y,axis=1)
        t=np.argmax(t,axis=1)
        
        accuracy=np.sum(y == t)/float(x.shape[0])
        return accuracy
        
    # x:输入数据,t:监督数据
    def numerical_gradient(self,x,t):
        loss_W=lambda W: self.loss(x,t)
        
        grads={}
        grads['W1']=numerical_gradient(loss_W,self.params['W1'])
        grads['b1']=numerical_gradient(loss_W,self.params['b1'])
        grads['W2']=numerical_gradient(loss_W,self.params['W2'])
        grads['b2']=numerical_gradient(loss_W,self.params['b2'])
        
        return grads
        
    def gradient(self,x,t):
        W1,W2=self.params['W1'],self.params['W2']
        b1,b2=self.params['b1'],self.params['b2']
        grads={}
        
        batch_num=x.shape[0]
        
        # forward
        a1=np.dot(x,W1)+b1
        z1=sigmoid(a1)
        a2=np.dot(z1,W2)+b2
        y=softmax(a2)
        
        # backward
        dy=(y-t)/batch_num
        grads['W2']=np.dot(z1.T,dy)
        grads['b2']=np.sum(dy,axis=0)
        
        da1=np.dot(dy,W2.T)
        dz1=sigmoid_grad(a1)*da1
        grads['W1']=np.dot(x.T,dz1)
        grads['b1']=np.sum(dz1,axis=0)

        return grads

紧接着,要对上文所构建的神经网络进行学习,其参见神经网络学习的一般步骤如下:
● 前提
神经网络存在合适的权重和偏置,调整权重和偏置以便拟合训练数据的过程称为“学习”。神经网络的学习分成下面4个步骤。
● 步骤1(mini-batch)
从训练数据中随机选出一部分数据,这部分数据称为mini-batch。我们的目标是减小mini-batch的损失函数的值。
● 步骤2(计算梯度)
为了减小mini-batch的损失函数的值,需要求出各个权重参数的梯度。梯度表示损失函数的值减小最多的方向。
● 步骤3(更新参数)
将权重参数沿梯度方向进行微小更新。
● 步骤4(重复)
重复步骤1、步骤2、步骤3。

之后,按照上面步骤,对上文代码  
two_layer_net.py 所构建的神经网络进行学习的代码 train_neuralnet.py 的内容如下:

import sys,os
sys.path.append(os.pardir)
import numpy as np
import matplotlib.pyplot as plt
from mnist import load_mnist
from two_layer_net import TwoLayerNet

# 读入数据
(x_train,t_train),(x_test,t_test)=load_mnist(normalize=True,one_hot_label=True)

network=TwoLayerNet(input_size=784,hidden_size=50,output_size=10)

iters_num=10000  # 适当设定循环的次数
train_size=x_train.shape[0]
batch_size=100
learning_rate=0.1

train_loss_list=[]
train_acc_list=[]
test_acc_list=[]

# 平均每个epoch的重复次数
iter_per_epoch=max(train_size/batch_size,1)

for i in range(iters_num):
    batch_mask=np.random.choice(train_size,batch_size)
    x_batch=x_train[batch_mask]
    t_batch=t_train[batch_mask]
    
    # 计算梯度
    #grad=network.numerical_gradient(x_batch,t_batch)
    grad=network.gradient(x_batch,t_batch)
    
    # 更新参数
    for key in ('W1','b1','W2','b2'):
        network.params[key]-=learning_rate*grad[key]
    
    loss=network.loss(x_batch,t_batch)
    train_loss_list.append(loss)
    
    # 计算每个epoch的识别精度
    if i % iter_per_epoch==0:
        train_acc=network.accuracy(x_train,t_train)
        test_acc=network.accuracy(x_test,t_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)
        print("train acc,test acc | "+str(train_acc)+","+str(test_acc))

# 绘制图形
markers={'train': 'o','test': 's'}
x=np.arange(len(train_acc_list))
plt.plot(x,train_acc_list,label='train acc')
plt.plot(x,test_acc_list,label='test acc',linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0,1.0)
plt.legend(loc='lower right')
plt.show()

运行代码 train_neuralnet.py 后的结果,每次都有差异。其中一次的运行结果如下:

train acc,test acc | 0.09915,0.1009
train acc,test acc | 0.7660833333333333,0.7735
train acc,test acc | 0.8770666666666667,0.8797
train acc,test acc | 0.8981666666666667,0.9027
train acc,test acc | 0.907,0.9103
train acc,test acc | 0.9135666666666666,0.9156
train acc,test acc | 0.91935,0.9208
train acc,test acc | 0.924,0.9257
train acc,test acc | 0.9277833333333333,0.929
train acc,test acc | 0.9300666666666667,0.9324
train acc,test acc | 0.9336,0.9343
train acc,test acc | 0.93635,0.9362
train acc,test acc | 0.9387333333333333,0.9378
train acc,test acc | 0.9407333333333333,0.9384
train acc,test acc | 0.9430833333333334,0.9421
train acc,test acc | 0.9452666666666667,0.9437
train acc,test acc | 0.9463666666666667,0.9438

顺便提一下,代码 train_neuralnet.py 中会用到代码 mnist.py,其内容可详见:
https://blog.csdn.net/hnjzsyjyj/article/details/128721706
为方便起见,此处再把 mnist.py 的内容复写如下:

try:
    import urllib.request
except ImportError:
    raise ImportError('You should use Python 3.x')
import os.path
import gzip
import pickle
import os
import numpy as np
 
 
url_base = 'http://yann.lecun.com/exdb/mnist/'
key_file = {
    'train_img':'train-images-idx3-ubyte.gz',
    'train_label':'train-labels-idx1-ubyte.gz',
    'test_img':'t10k-images-idx3-ubyte.gz',
    'test_label':'t10k-labels-idx1-ubyte.gz'
}
 
dataset_dir = os.path.dirname(os.path.abspath('__file__'))
save_file = dataset_dir + "/mnist.pkl"
 
train_num = 60000
test_num = 10000
img_dim = (1, 28, 28)
img_size = 784
 
 
def _download(file_name):
    file_path = dataset_dir + "/" + file_name
    
    if os.path.exists(file_path):
        return
 
    print("Downloading " + file_name + " ... ")
    urllib.request.urlretrieve(url_base + file_name, file_path)
    print("Done")
    
def download_mnist():
    for v in key_file.values():
       _download(v)
        
def _load_label(file_name):
    file_path = dataset_dir + "/" + file_name
    
    print("Converting " + file_name + " to NumPy Array ...")
    with gzip.open(file_path, 'rb') as f:
            labels = np.frombuffer(f.read(), np.uint8, offset=8)
    print("Done")
    
    return labels
 
def _load_img(file_name):
    file_path = dataset_dir + "/" + file_name
    
    print("Converting " + file_name + " to NumPy Array ...")    
    with gzip.open(file_path, 'rb') as f:
            data = np.frombuffer(f.read(), np.uint8, offset=16)
    data = data.reshape(-1, img_size)
    print("Done")
    
    return data
    
def _convert_numpy():
    dataset = {}
    dataset['train_img'] =  _load_img(key_file['train_img'])
    dataset['train_label'] = _load_label(key_file['train_label'])    
    dataset['test_img'] = _load_img(key_file['test_img'])
    dataset['test_label'] = _load_label(key_file['test_label'])
    
    return dataset
 
def init_mnist():
    download_mnist()
    dataset = _convert_numpy()
    print("Creating pickle file ...")
    with open(save_file, 'wb') as f:
        pickle.dump(dataset, f, -1)
    print("Done!")
 
def _change_one_hot_label(X):
    T = np.zeros((X.size, 10))
    for idx, row in enumerate(T):
        row[X[idx]] = 1
        
    return T
    
 
def load_mnist(normalize=True, flatten=True, one_hot_label=False):
    """读入MNIST数据集
    
    Parameters
    ----------
    normalize : 将图像的像素值正规化为0.0~1.0
    one_hot_label : 
        one_hot_label为True的情况下,标签作为one-hot数组返回
        one-hot数组是指[0,0,1,0,0,0,0,0,0,0]这样的数组
    flatten : 是否将图像展开为一维数组
    
    Returns
    -------
    (训练图像, 训练标签), (测试图像, 测试标签)
    """
    if not os.path.exists(save_file):
        init_mnist()
        
    with open(save_file, 'rb') as f:
        dataset = pickle.load(f)
    
    if normalize:
        for key in ('train_img', 'test_img'):
            dataset[key] = dataset[key].astype(np.float32)
            dataset[key] /= 255.0
            
    if one_hot_label:
        dataset['train_label'] = _change_one_hot_label(dataset['train_label'])
        dataset['test_label'] = _change_one_hot_label(dataset['test_label'])
    
    if not flatten:
         for key in ('train_img', 'test_img'):
            dataset[key] = dataset[key].reshape(-1, 1, 28, 28)
 
    return (dataset['train_img'], dataset['train_label']), (dataset['test_img'], dataset['test_label']) 
 
 
if __name__ == '__main__':
    init_mnist()

本文所涉及的神经网络学习的所有文件如下图所示:


 

当然,运行此代码前,可将之前 https://blog.csdn.net/hnjzsyjyj/article/details/128721706 例子中下载的 MNIST 数据集的 'train-images-idx3-ubyte.gz'、'train-labels-idx1-ubyte.gz'、't10k-images-idx3-ubyte.gz'、't10k-labels-idx1-ubyte.gz' 等四个文件,以及生成的 mnist.pkl 文件直接复制过来。
 

【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/128759703
https://blog.csdn.net/hnjzsyjyj/article/details/128721706

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/183513.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

玩转代码|解决Chrome浏览器内置谷歌翻译功能无法使用问题!

最近这几天在使用Chrome浏览器的内置谷歌翻译功能时,总是一直停留在不翻译的状态,一开始我还以为是网络波动过几天就好了,过了好几天依旧是这样。去看了新闻才知道谷歌翻译已经退出了中国市场。根据TechCrunch的消息称,谷歌发言人…

我本芬芳

我本芬芳推荐语: 读完前几章,一边为惠才遇人不淑感到遗憾,又不觉想起自己的童年种种,书中简单的三言两语,却又不断地在触动我。我不由得想到上世纪六七十年代的女子们,也就是我的奶奶外婆们,将自…

我的周刊(第076期)

我的信息周刊,记录这周我看到的有价值的信息,主要针对计算机领域,内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。🎯 项目python-wechaty[1]Wechaty 是一个开源聊天机器人框架…

力扣刷题|226.翻转二叉树、101. 对称二叉树

文章目录LeetCode 226.翻转二叉树题目链接🔗思路递归法迭代法LeetCode 101. 对称二叉树题目链接🔗思路递归法迭代法相关题目LeetCode 226.翻转二叉树 题目链接🔗 LeetCode 226.翻转二叉树 思路 这道题目使用前序遍历和后序遍历都可以&…

PVID和VID相关小知识

欢迎来到东用知识小课堂!1.PVID和VID的区别PVID和VID经常出现于二、三层交换机里,很多时候由于PVID和VID的设置不合理,造成VLAN划分变得混乱。一般你去超市买东西有个扫描设备扫描一下商品上的标签,然后价格就会出现。商品上的标签…

分布式锁与数据库悲观、乐观锁

分布式锁 什么是分布式锁 要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。 1.线程锁 主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为…

Redis主从复制与读写分离

1、为什么要主从复制、读写分离Redis在作为缓存的时候,随着项目访问量的增加,对Redis服务器的操作也越加频繁,虽然Redis读写速度都很快,但是一定程度上也会造成一定的延时,甚至出现宕机的可能性,这时候就出…

如何使用知行之桥搭建SFTPServer

知行之桥EDI系统同时支持SFTP Server和SFTP Client功能,既可以作为SFTP Server供多个Client连接,也可以作为Client连接多个Server。无论是作为SFTP Server还是SFTP Client,都只需要简单的配置即可实现。 SFTP Server的特性包括一下几点&…

【React全家桶】react路由

react路由5.1. 路由的简介5.2 路由的基本使用5.3 路由组件与一般组件5.4 NavLink及其封装5.5 Switch5.6 路由的模糊匹配与严格匹配5.7 Redirect重定向5.8 向路由组件传递参数5.9 编程式路由导航5.10withRouter的使用5.12 BrowserRouter与HashRouter的区别5.1. 路由的简介 单页W…

代码随想录--二叉树章节总结 Part III

代码随想录–二叉树章节总结Part III 1.Leetcode106 从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 解题思路…

【Go基础】并发编程

文章目录1. 并发模型2. Goroutine的使用3. Channel的同步与异步4. 并发安全性5. 多路复用6. 协程泄漏7. 协程管理1. 并发模型 任何语言的并行,到操作系统层面,都是内核线程的并行。同一个进程内的多个线程共享系统资源,进程的创建、销毁、切…

【监控开发】jps命令怎么远程调用另一个IP的机器,jstatd服务支持

jsp命令远程调用咩有Linux服务器启动jstatd服务的时候Linux服务器如何启动jstatd服务1.查找jdk所在目录2.在jdk的bin目录下创建文件jstatd.all.policy3.给这个文件赋权4.这个文件写入安全配置,赋值粘贴即可5.启动jstatd服务6.查看是否启动成功再去另外一台服务器调用…

第一章:Go语言为并发而生

在早期 CPU 都是以单核的形式顺序执行机器指令。Go语言的祖先C语言正是这种顺序编程语言的代表。顺序编程语言中的顺序是指:所有的指令都是以串行的方式执行,在相同的时刻有且仅有一个 CPU 在顺序执行程序的指令。 随着处理器技术的发展,单核…

C语言深度解剖-关键字(4)

目录 signed、unsigned 关键字补充内容 关于大端和小端 大小端存储数据方式 判断大小端 深入理解数据存储 练习: 写在最后: signed、unsigned 关键字补充内容 关于大端和小端 我们通过在内存中存储一个值, 用于观察数据在内存中的存…

Python连接Liunx中mysql数据库-保姆级教程

首先确保你的liunx中已经安装好了mysql数据库如果没有安装mysql数据库看这篇文章Centos6从零开始安装mysql和tomcat后台环境,并成功部署Tomcat项目图文详细过程 python连接Liunx中mysql数据库进行增删改查liunx中相关环境改变Python中连接liunx中的mysql数据库在Nav…

上班第一件事:马上卸载这个恶心的软件!

一上班就被Notepad给恶心到了。“如果不同意政治观点,就在你的源码中添加随机字符。”这个Notepad作者侯今吾真是把自己当做大人物了啊?!率性而为,根本不再考虑用户的感受了。 这个Twitter帖子很快就被一片骂声淹没,这…

【每日CSS3代码】

1-1 两栏布局【1/27】 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevi…

OpenJudge NOI 2.4 8463:Stupid cat Doge

【题目链接】 OpenJudge NOI 2.4 8463:Stupid cat & Doge 【题目考点】 1. 递归 2. 分形图 【解题思路】 解法1&#xff1a;递归 1级正方形边长是212^121&#xff0c;2级正方形边长为222^222&#xff0c;。。。&#xff0c;n级正方形边长为2n2^n2n&#xff0c;总格子…

autojs画六边形

牙叔教程 简单易懂 界面基础代码 "nodejs ui"; require("rhino").install(); const ui require("ui"); class MainActivity extends ui.Activity {constructor() {super();}get layoutXmlFile() {return "layout.xml";}onContentVi…

高效学 C++|继承与组合

继承是面向对象程序设计的重要特性之一。作为面向对象的编程语言&#xff0c;C语言也自然支持这个特性。继承是代码复用的基本方法之一&#xff0c;也是接口和复用设计的关键。本文介绍继承的含义和继承与组合的关系。 01、继承的含义 面向对象程序设计通过将问题域中的事物抽…