鱼书学习1

tuhr

用google的colab,将相关代码和文件保存在google 的云端硬盘中,调用时用以下代码登录账号连接资源

from google.colab import drive
drive.mount('/content/drive')
!ls "/content/drive/My Drive/"
import os
os.chdir("/content/drive/My Drive/【源代码】深度学习入门:基于Python的理论与实现_20240716")

机器学习能够学习“特征”,但特征仍是由人设计的;而神经网络中,连特征都是由机器决定的。

1. 首先,让我们了解损失函数,均方误差,softmax函数,one-hot表示法。

1.1 均方误差表示如下

def mean_squared_error(y,t):
    return 0.5*np.sum(y-t)**2)

1.2 交叉熵误差也是一种损失函数。实际上只计算对应正确结果的输出概率的自然对数。正确解标签对应的输出越大,交叉熵误差越接近0。

def cross_entropy_error(y,t):
    delta=1e-7
    return -np.sum(t*np.log(y+delta))

delta的作用在于,np.log(0)会导致计算困难,因此用delta防止负无限大的发生。

2. mini-batch的学习

为了节省训练时间,从训练集中选出一批mini-batch,对每个mini-batch进行学习。下面我们来编写从训练数据集中随机选择指定个数的数据的代码

首先,读入MNIST数据集

import sys,os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist

(x_train,t_train),(x_test,t_test)=load_mnist(normalize=True,one_hot_label=True)

print(x_train.shape)
print(t_train.shape)

如何从训练数据集随机抽取10笔数据?可以用np.random.choice()随机选择数字

train_size=x_train.shape[0]
batch_size=10
batch_mask=np.random.choice(train_size,batch_size)
x_batch=x_train[batch_mask]
t_batch=t_train[batch_mask]

2.2 mini-batch版交叉熵误差的实现

这里,我们来实现一个可以同时处理单个数据和批量数据两种情况的函数

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

以上,通过除以batch_size对batch的个数进行正规化,计算单个数据的平均交叉熵误差。

此外,当监督数据为标签形式(非one-hot表示,而是像2,7这样的标签)时,交叉熵误差可通过如下代码实现

batch_size=y.shape[0]
return np.sum(np.log(y[np.arange(batch_size),t]+1e7))/batch_size

3. 导数

计算导数时,微小值不宜过小,10-4即可。并且,为了减小误差,可以用中心差分。

def numerical_diff(f,x):
    h=1e4
    return (f(x+h)-f(x-h))/(2*h)

3.1 偏导数

多个变量的函数的导数称为偏导数

3.2 梯度

由全部变量的偏导数汇总的向量就是梯度。神经网络在寻找最优参数(权重和偏置)就会通过梯度尽可能找函数最小值。

定义函数numerical_gradient,参数f为函数,x为数组,求函数在x的各个元素的微分

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

    for idx in range(x,size):
        tmp_val=x[idx]
        
    # 计算f(x+h)
        x[idx]=tmp_val+h
        fxh1=f(x)

    # 计算f(x-h)
        x[idx]=tmp_val-h
        fxh2=f(x)

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

梯度法指的是,函数的取值从当前位置沿着梯度方向前进一段距离,在新的地方重新求梯度;继续前进,如此反复,逐渐减小函数值。

在神经网络的学习中,学习率决定了一次学习中,应该学多少,以及在多大程度上更新参数。学习率需要事先确定为某个值,比如0.01或0.001.在神经网络的学习中,一般会一边改变学习率的值,一边确认学习是否正确进行了。像学习率这样的参数称为超参数,是人工设定的。

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-=lr*grad

    return x

3.3 神经网络的梯度

神经网络的学习,也需要求梯度,这里的梯度是指损失函数关于权重参数的梯度。以一个简单的神经网络为例,来实现求梯度的代码,为此,我们要实现一个名为simpleNet的类

import sys,os
sys.path.append(os.pardir)
import numpy as np
from common.functions import softmax,cross_entropy_error
from common.gradient import numerical_gradient

class simpleNet:
    def __init__(self):
        self.W=np.random.randn(2,3)# 用高斯分布初始化W

    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

接下来求梯度,使用numerical_gradient(f,x)求梯度。神经网络的学习总体就是按照4个步骤:第一,选mini-batch;第二,计算梯度;第三,更新权重参数;第四,重复以上三步直到学习结束。由于随机选择mini-batch,所以又称为随机梯度下降法

3.4 实现手写数字识别的神经网络

这里以2层神经网络(隐藏层为1层得网络)为对象,使用MNIST数据集进行学习。

首先,我们将用一个名为TwoLayerNet的类实现2层神经网络

import sys,os
sys.path.append(os.pardir)
from common.functions import *
from common.gradient import numerical_gradient

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['b']=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['W1self.params['W2']
        b1,b2=self.params['b1'],self.params['b2']

        a1=np.dot(x,W1)+b1
        z1=sigimoid(a1)
        a2=np.dot(z1,W2)+b2
        y=softmax(a2)

        rturn 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

    def numerical_gradient(self,x,t): #x是输入数据,t是监督数据
        loss_W=lamdba 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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值