神经网络的学习-搭建神经网络实现mnist数据集分类(代码片段)

泥签 泥签     2022-11-30     656

关键词:

文章目录

四、神经网络的学习

这一章通过两层神经网络实现对mnist手写数据集的识别,本文是源于《深度学习入门》的学习笔记
若理解困难,参考上一章笔记:深度学习入门-从朴素感知机到神经网络
本文部分数学公式函数用代码实现了,另一些代码在此:数学公式函数

1.损失函数

表示神经网络性能的“恶劣程度”的指标。

1.1均方误差:可以用作损失函数如下图

这里的yk表示神经网络的输出,tk表示监督数据,也就是正确的数据,k表示数据的维度。

1.2 交叉熵误差:也被用作损失函数

注意tk用的时one-hot数组,正确解索引为1其他都为0。

接下来我们用代码实现两个损失函数

def mean_squared_error(y,t): #均方误差
    return 0.5*np.sum((y-t)**2)

def cross_entropy_error(y, t):#交叉熵误差
    if y.ndim == 1:								#变为二维
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    # 监督数据是one-hot-vector的情况下,转换为正确解标签的索引
    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
#y[np.arange(batch_size),t] 是正确索引对应的y数组值所构成的1维数组,每个元素都是一个数据的正确索引对应的值
#举例 
a = np.array([[1,2,3,4,5,6,7,8,9,10],[11,12,13,14,15,16,17,18,19,20]])
b = a[[0,1,0,1,0],[5,6,7,8,9]]
print(b)
#输出结果是[ 6 17  8 19 10]

交叉熵误差看起来有点复杂,因为我们使用了批处理。

​ 使用训练数据进行学习,严格来说, 就是针对训练数据计算损失函数的值,找出使该值尽可能小的参数。因此, 计算损失函数时必须将所有的训练数据作为对象。也就是说,如果训练数据 有100个的话,我们就要把这100个损失函数的总和作为学习的指标。

​ 神经网络的学习也是从训练数据中选出一批数据(称为mini-batch,小 批量),然后对每个mini-batch进行学习。比如,从60000个训练数据中随机 选择100笔,再用这100笔数据进行学习。这种学习方式称为mini-batch学习。

2.损失函数的意义

​ 如果我们将精度作为优化参数的目标,那诸多的参数发生的微小改变并不能影响到精度,假如参数变化零点几,精度可能不会发生变化,而损失函数的值却不然。损失函数的值会随着参数变化产生连续的变化,而不是像精度一样离散的变化,我们通过改变参数降低损失函数的值,方法就是寻找某一参数作为自变量求损失函数的导数也就是梯度。不能用阶跃函数做激活函数也是这个道理,阶跃函数会使大部分参数的导数为0,没办法进行优化。之后会详细说明,此处简单了解。

3.数值微分

3.1 导数 :导数公式我们都知道,我们用代码实现一下导数公式

def  numerical_diff(f,x):
    h = 1e-4 #0.0001 计算机所能正确表示的微小值
    return (f(x+h)-f(x-h))/2*h #与正常的前向差分不同,我们采取中心差分求导数,h不可能真的趋近去穷小,实验中 中心差分更近似

3.2 我们来实践一下求导数y=0.01x**2+0.1x

def  numerical_diff(f,x):
    h = 1e-4
    return (f(x+h)-f(x-h))/(2*h)
def function_1(x):
    return 0.01*x**2+0.1*x

print(numerical_diff(function_1,5))#0.1999999999990898
print(numerical_diff(function_1,10))#0.2999999999986347

3.3 偏导数:我们来看这样一个函数如下图

和上面的函数不同,它有两个参数,用代码实现如下

def function_2(x):
    return x[0]**2+x[1]**2

该函数图像如下

如果我们来求该函数在x0=3,x1=4时的偏导数,那就需要重新定义下函数

def function_4(x0):
    return x0**2+4.0**2

print(numerical_diff(function_4,3.0))
#结果是6.00000000000378

3.4 梯度

​ 刚才我们求了x0=3时的偏导数,现在我们考虑求x0=3,x1=4时(x0,x1)的偏导数(x0偏导数,x1偏导数),像这样由全部变量的偏导数汇总而成的向量称为梯度。

接下来我们用代码来实现一下

def numerical_gradient(f,x):
    h = 1e-4
    grad = np.zeros_like(x)

    for idx in range(x.size):
        tem_val = x[idx]

        x[idx] = tem_val + h
        fxh1 = f(x)

        x[idx] = tem_val - h
        fxh2 = f(x)

        grad[idx] = (fxh1 - fxh2) / (2*h)
        x[idx] = tem_val

    return grad

这段求梯度的函数代码看似复杂,其实很简单,然后我们求一下梯度

def function_2(x):
    return np.sum(x**2)
print(numerical_gradient(function_2,np.array([3.0,4.0])))
print(numerical_gradient(function_2,np.array([0.0,2.0])))
print(numerical_gradient(function_2,np.array([3.0,0.0])))
#结果是 [6. 8.]
#		[0. 4.]
#		[6. 0.]

然后我们画出这个函数的梯度图,注意画的是元素值为负梯度的向量,代码较复杂,暂时不必掌握

​ 虽然图中的梯度指向了最低处,但并非任何时候都这样。实际上, 梯度会指向各点处的函数值降低的方向。更严格地讲,梯度指示的方向 是各点处的函数值减小最多的方向 A。这是一个非常重要的性质,请一定 牢记

4.梯度法

​ 4.1梯度法

​ 机器学习的主要任务是在学习时寻找最优参数。同样地,神经网络也必 须在学习时找到最优参数(权重和偏置)。这里所说的最优参数是指损失函数机器学习的主要任务是在学习时寻找最优参数。同样地,神经网络也必 须在学习时找到最优参数(权重和偏置)。这里所说的最优参数是指损失函数取最小值时的参数。

​ 通过巧妙地使用梯度来寻找函数最小值 (或者尽可能小的值)的方法就是梯度法。

​ 这里需要注意的是,梯度表示的是各点处的函数值减小最多的方向。因此, 无法保证梯度所指的方向就是函数的最小值或者真正应该前进的方向。实际 上,在复杂的函数中,梯度指示的方向基本上都不是函数值最小处。

​ 虽然梯度的方向并不一定指向最小值,但沿着它的方向能够最大限度地 减小函数的值。因此,在寻找函数的最小值(或者尽可能小的值)的位置的 任务中,要以梯度的信息为线索,决定前进的方向

​ 通过不断地沿梯度方向前进, 逐渐减小函数值的过程就是梯度法。梯度法是解决机器 学习中最优化问题的常用方法,特别是在神经网络的学习中经常被使用。

​ 我们用数学式子来表示梯度法

​ η表示更新量,在神经网络的学习中,称为学习率(learning rate)。学习率决定在一次学习中,应该学习多少,以及在多大程度上更新参数。一般确定为某个值比如0.01或0.001。

下面我们来实现以下梯度下降法

#梯度下降法 --- 我们如果用二维函数就会很容易理解梯度下降法例如y=x
#虽然y = x永远找不到最小值
def gradient_descent(f,init_x,lr = 0.01,step_num = 100):
    x = init_x
    
    for i in range(step_num):
        grad = numerical_gradient(f,x)
        x = x-lr*grad
    
    return x

然后我们来尝试解决一个问题,求f(x0,x1) = x0* *2+x1 * *2的最小值

def function_2(x):
    return np.sum(x**2)
print(gradient_descent(function_2,init_x = np.array([-3.0,4.0]),lr = 0.1,step_num = 100))
# 结果是 [-6.11110793e-10  8.14814391e-10]

结果很接近(0,0),实际上(0,0)就是最小值。用途来表示下梯度法的更新过程如下,代码较为复杂暂时不需要掌握

接下来我们做个实验,将学习率lr改变一下

print(gradient_descent(function_2,init_x = np.array([-3.0,4.0]),lr = 10.0,step_num = 100))
#结果是[-2.58983747e+13 -1.29524862e+12]

print(gradient_descent(function_2,init_x = np.array([-3.0,4.0]),lr = 1e-10,step_num = 100))
#结果是[-2.99999994  3.99999992]

​ 实验结果表明,学习率过大的话,会发散成一个很大的值;反过来,学 习率过小的话,基本上没怎么更新就结束了。也就是说,设定合适的学习率 是一个很重要的问题。

4.2神经网络的梯度

​ 神经网络的学习也要求梯度。这里所说的梯度是指损失函数关于权重参 数的梯度。比如,有一个只有一个形状为2 × 3的权重W的神经网络,损失 函数用L表示。此时,梯度可以用 表示。用数学式表示的话,如下所示。

下面我们用代码实现求神经网络的梯度

from fuction import softmax,cross_entropy_error,numerical_gradient
import numpy as np

class simpleNet:
    def __init__(self):
        #self.W = np.random.randn(2,3)# 用高斯分布进行初始化 为了保证数据一致,我们自定义一个参数W
        self.W = np.array([[0.47355232,0.9977393,0.84668094],
                           [0.85557411,0.03563661,0.69422093]])
    def predict(self,x):
        return np.dot(x,self.W)

    def loss(self,x,t):
        z = self.predict(x)
        y = softmax(z)
        loss = cross_entropy_error(y,t)

        return loss
net = simpleNet()
print(net.W)#随机生成的权重参数
x = np.array([0.6,0.9]) #输入数据
p = net.predict(x) #用当前权重进行推理 得到结果
print(p)
print(np.argmax(p))#获取结果索引
#结果如下
"""[[0.47355232 0.9977393  0.84668094]
 	[0.85557411 0.03563661 0.69422093]]
	[1.05414809 0.63071653 1.1328074 ]
	2
"""

我们设置正确解标签为[0,0,1]来求一下损失函数

t = np.array([0,0,1])
print(net.loss(x,t))
#结果是
#0.9280682857864075

然后我们来求一下这个损失函数在值为x时的各个元素的偏导数,也就是梯度。在求梯度时我们需要改变一下求梯度函数,因为参数数组不是一维了,遍历元素的方式需要改变一下。

# 求梯度
def numerical_gradient(f, x):
    h = 1e-4  # 0.0001
    grad = np.zeros_like(x)

    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    #it是获得的迭代器,在下面循环中会便利每一个元素 idx是元素的索引例如(0,1)
    #这样每一个元素都求偏导数就是求梯度
    while not it.finished:
        idx = it.multi_index
        tmp_val = x[idx]
        x[idx] = float(tmp_val) + h
        fxh1 = f(x)  # f(x+h)

        x[idx] = tmp_val - h
        fxh2 = f(x)  # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2 * h)

        x[idx] = tmp_val  # 还原值
        it.iternext()

    return grad

def f(W):   #这里定义的函数f(W)的参数W是一个伪参数。因为numerical_gradient(f,x)会在内部执行f(x),为了与之兼容而定义了f(W)
    return net.loss(x,t)
# 其实我们不用管f(W),只需要知道它是一个函数就行,其他的是为了适应python代码而做出的修改。
dW = numerical_gradient(f,net.W)
print(dW)
"""
结果
[[ 0.21924757  0.14356243 -0.36281   ]
 [ 0.32887136  0.21534364 -0.544215  ]]

"""

求梯度之后我们就可以”学习“了。

5.学习算法的实现

神经网络的学习 步骤如下所示。

前提 :神经网络存在合适的权重和偏置,调整权重和偏置以便拟合训练数据的 过程称为“学习”。神经网络的学习分成下面4个步骤。

步骤1(mini-batch): 从训练数据中随机选出一部分数据,这部分数据称为mini-batch。我们 的目标是减小mini-batch的损失函数的值。

步骤2(计算梯度) :为了减小mini-batch的损失函数的值,需要求出各个权重参数的梯度。 梯度表示损失函数的值减小最多的方向。

步骤3(更新参数): 将权重参数沿梯度方向进行微小更新

步骤4(重复): 重复步骤1、步骤2、步骤3。

5.1下面我们以两层神经网络为对象,使用mnist数据集进行学习。

另外:如何设置权重参数 的初始值这个问题是关系到神经网络能否成功学习的重要问题。后面我 们会详细讨论权重参数的初始化,这里只需要知道,权重使用符合高斯 分布的随机数进行初始化,偏置使用0进行初始化。

5.2 mini-batch的实现

首先我们实现一个两层神经网络的类

import numpy as np

from deeplearning.fuction import softmax,sigmoid,cross_entropy_error,numerical_gradient,sigmoid_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

    	#计算损失函数
    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=2)

        accuracy = np.sum((y==t)/float(x.shape[0]))
        return accuracy

    	#数值微分法求梯度,但是速度太慢,不建议用
    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

然后我们来用数据训练这个神经网络,并将损失函数的值随训练次数的变化画出来

import matplotlib.pyplot as plt
import numpy as np
from deeplearning.mnist import load_mnist
from tow_layer_net import TwoLayerNet

(x_train,t_train),(x_test,t_test) = load_mnist(normalize=True,one_hot_label=True)
#这一步是从mnist数据集中读取数据,读取数据的代码暂时不用掌握,只需要知道x_train是数据集,t_train是正确标签集
#关于测试数据集和测试标签集本段代码并没有用到

train_loss_list = []

# 超参数
iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
count = 0

# 创建网络
network = TwoLayerNet(input_size=784,hidden_size=50,output_size=10)
print("数据正在训练中请稍后...")

for i in range(iters_num):  #该循环进行一万次mini_batch数据量的学习
    # 获取mini_batch
    if (i % 1000 == 0):
        print("已经完成"+str(i)+"次mini_batch...")


    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)#实在太慢,跑了将近两个多小时没有完成1000mini_batch
    grad = network.gradient(x_batch, t_batch)			#返回梯度字典
    # 更新参数
    for key in ('W1','b1',

深度学习------用nncnnrnn神经网络实现mnist数据集处理(代码片段)

1.用NN神经网络完成MNIST数据集处理#用NN神经网络完成MNIST数据集处理#1、导包importtensorflowastfimportnumpyasnpimportmatplotlib.pyplotaspltfromtensorflow.examples.tutorials.mnistimportinput_data#2、加载mnist数据集mnist=input_data.re 查看详情

如何搭建vgg网络,实现mnist数据集的图像分类

1问题如何搭建VGG网络,实现Mnist数据集的图像分类?2方法步骤:首先导包ImporttorchfromtorchimportnnVGG11由8个卷积,三个全连接组成,注意池化只改变特征图大小,不改变通道数classMyNet(nn.Module):  def__init__(self)->No... 查看详情

深度学习笔记_keras六步法搭建网络(代码片段)

...集为例一、import加载库二、设置训练集、测试集三、搭建神经网络四、配置神经网络五、执行训练六、打印网络结构及参数代码Keras六步法搭建网络,以MNIST数据集为例一、import加载库加载所需要的库,使用tensorflow库import... 查看详情

深度学习100例-卷积神经网络(cnn)实现mnist手写数字识别|第1天

...模型五、预测六、知识点详解1.MNIST手写数字数据集介绍2.神经网络程序说明3.网络结构说明我的环境:语言环境:Python3.6.5编译器:jupyternotebook深度学习环境:TensorFlow2来自专栏:【深度学习100例 查看详情

用kersa搭建神经网络mnist手写数据集(代码片段)

MNIST手写数据集的识别算得上是深度学习的”helloworld“了,所以想要入门必须得掌握。新手入门可以考虑使用Keras框架达到快速实现的目的。完整代码如下:#1.导入库和模块fromkeras.modelsimportSequentialfromkeras.layersimportConv2D,MaxPool2Df... 查看详情

ternsorflow学习:006-mnist进阶深入mnist(代码片段)

...值计算的库。其所擅长的任务之一就是实现以及训练深度神经网络。在本教程中,我们将学到构建一个TensorFlow模型的基本步骤,并将通过这些步骤为MNIST构建一个深度卷积神经网络。这个教程假设你已经熟悉神经网络和MNIST数据... 查看详情

神经网络不学习 - MNIST 数据 - 手写识别

】神经网络不学习-MNIST数据-手写识别【英文标题】:NeuralNetworknotlearning-MNISTdata-Handwritingrecognition【发布时间】:2015-04-2902:12:22【问题描述】:我写了一个神经网络程序。它适用于逻辑门,但是当我尝试用它来识别手写数字时-它... 查看详情

tensorflow框架初尝试————搭建卷积神经网络做mnist问题

Tensorflow是一个非常好用的deeplearning框架学完了cs231n,大概就可以写一个CNN做一下MNIST了tensorflow具体原理可以参见它的官方文档然后CNN的原理可以直接学习cs231n的课程。 另外这份代码本地跑得奇慢。。估计用gpu会快很多。 ... 查看详情

深度学习与tensorflow2.0卷积神经网络(cnn)(代码片段)

...ark。初学深度学习,在这个数据集上训练一个有效的卷积神经网络就相当于学习编程的时候打印出一行“HelloWorld!”。下面基于与MNIST数据集非常类似的另一个数据集Fashion-MNIST数据集来构建一个卷积神经网络。 0.Fashion-M... 查看详情

学习笔记tf057:tensorflowmnist,卷积神经网络循环神经网络无监督学习

MNIST卷积神经网络。https://github.com/nlintz/TensorFlow-Tutorials/blob/master/05_convolutional_net.py。TensorFlow搭建卷积神经网络(CNN)模型,训练MNIST数据集。构建模型。定义输入数据,预处理数据。读取数据MNIST,得到训练集图片、标记矩阵,测... 查看详情

tensorflow+keraskerasapi三种搭建神经网络的方式及以mnist举例实现(代码片段)

目录1第一种:Sequential2第二种:函数式API3第三种:class1第一种:Sequential(1)简介序列模型,官网介绍代码参考:https://github.com/eriklindernoren/Keras-GAN/blob/master/gan/gan.py理论参考: 查看详情

利用keras搭建cnn进行mnist数据集分类

...轮子的大神,so,我强烈向大家推荐keras,Keras是一个高层神经网络API,Keras由纯Python编写而成并基Tenso 查看详情

用tensorflow搭建简单神经网络测试iris数据集和mnist数据集(代码片段)

1.步骤第一步:import相关模块,如importtensorflowastf第二步:指定输入网络的训练集和测试集,如指定训练集的输入x_train和标签y_train,测试集的输入x_test和标签y_test。 第三步:逐层搭建网络结构,model=tf.keras.models.Sequential()。&n... 查看详情

使用mnist数据搭建tensorflow神经网络-notes

画个图花了我好久plt.figure(figsize=(16,8),dpi=80)displayX=X[5:10].reshape(5,28,28)forindinrange(len(displayX)):axes=plt.subplot(2,3,ind+1)pic=displayX[ind]forrowIndinrange(len(pic)):oneRow=pic[rowInd]foreachP 查看详情

pytorchnote25深层神经网络实现mnist手写数字分类(代码片段)

PytorchNote25深层神经网络实现MNIST手写数字分类文章目录PytorchNote25深层神经网络实现MNIST手写数字分类MNIST数据集多分类问题softmax交叉熵多层全连接神经网络实现MINST手写数字分类数据预处理简单的四层全连接神经网络定义loss函数... 查看详情

tensorflow学习教程------普通神经网络对mnist数据集分类(代码片段)

首先是不含隐层的神经网络,输入层是784个神经元输出层是10个神经元代码如下#coding:utf-8importtensorflowastffromtensorflow.examples.tutorials.mnistimportinput_data#载入数据集mnist=input_data.read_data_sets("MNIST_data",one_hot=True)#每个批次的大小ba 查看详情

pytorch使用mnist数据集实现手写数字识别(代码片段)

...写数字识别是入门必做吧。这里使用pyTorch框架进行简单神经网络的搭建。首先导入需要的包。1importtorch2importtorch.nnasnn3importtorch.utils.dataasData4importtorchvision 接下来需要下载mnist数据集。我们创建train_data。使用torchvision.datasets.MN... 查看详情

基于tensorflow2.x实现bp神经网络,实践mnist手写数字识别(代码片段)

一、MNIST数据集MNIST是一个非常有名的手写数字识别数据集,在很多资料中都会被用作深度学习的入门样例。在Tensorflow2.x中该数据集已被封装在了tf.keras.datasets工具包下,如果没有指定数据集的位置,并先前也没有使... 查看详情