“深度学习”学习日记。与学习相关的技巧 -- 参数的更新

news2024/11/17 12:26:02

2023.1.20

在神经网络的学习这一章,学习过了利用 梯度下降法 对参数进行更新,目的是找到是损失函数的值尽量小的参数;像解决这样的问题称为 最优化 。

由于参数空间十分复杂、参数规模十分庞大,导致“最优化”的过程变得困难。

回忆一下随机梯度下降法(stochastic gradient descent),简称SGD

W\leftarrow W-\eta \frac{\partial L}{\partial W}

将要更新的权重设置为W,把损失函数关于梯度几位 \frac{\partial L}{\partial W} 。η 代表学习率;表示右边的值更新左边的值。

Python代码实现SGD:

class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr

    def update(self, params, grads):  # 为权重于偏置 w1,w2,b1,b2 这样的参数
        for key in params.key():
            params[key] -= self.lr * grads[key]

像这样单独实现进行最优化的类,功能的模块化变得简单:

import numpy as np
from collections import OrderedDict
from dataset.mnist import load_mnist
import sys, os

sys.path.append(os.pardir)


# 数值微分
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'])  # np.nditer() 迭代器处理多维数组
    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 cross_entropy_error(y, t):
    delta = 1e-7
    return -1 * np.sum(t * np.log(y + delta))


# 激活函数
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 sigmoid(x1):
    return 1 / (1 + np.exp(-x1))


# 加法层、乘法层、激活函数层、Affine层、Softmax层
class Addyer:  # 加法节点
    def __init__(self):
        pass

    def forward(self, x, y):
        out = x + y
        return out

    def backward(self, dout):
        dx = dout * 1
        dy = dout * 1
        return dx, dy


class Mullyer:  # 乘法节点
    def __init__(self):  # __init__() 中会初始化实例变量
        self.x = None
        self.y = None

    def forward(self, x, y):
        self.x = y
        self.y = x
        out = x * y

        return out

    def backward(self, dout):
        dx = dout * self.x
        dy = dout * self.y

        return dx, dy


class ReLU:
    def __init__(self):
        self.mask = None

    def forward(self, x):
        self.mask = (x <= 0)
        out = x.copy()
        out[self.mask] = 0

        return out

    def backward(self, dout):
        dout[self.mask] = 0
        dx = dout

        return dx


class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None
        self.y = None
        self.t = None

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

        return self.loss

    def backward(self, dout=1):
        batch_size = self.t.shape[0]
        dx = (self.y - self.t) / batch_size

        return dx


class Affine:
    def __init__(self, w, b):
        self.w = w
        self.b = b
        self.x = None
        self.dw = None
        self.db = None

    def forward(self, x):
        self.x = x
        out = np.dot(x, self.w) + self.b

        return out

    def backward(self, dout):
        dx = np.dot(dout, self.w.T)
        self.dw = np.dot(self.x.T, dout)
        self.db = np.sum(dout, axis=0)

        return dx


class TwoLayerNet:
    def __init__(self, input, hidden, output, weight__init__std=0.01):
        # 权重的初始化 假设一个权重
        self.params = {}
        self.params['w1'] = weight__init__std * np.random.randn(input, hidden)
        self.params['b1'] = np.zeros(hidden)
        self.params['w2'] = weight__init__std * np.random.randn(hidden, output)
        self.params['b2'] = np.zeros(output)

        # 生成层
        self.layers = OrderedDict()
        self.layers['Affine1'] = Affine(self.params['w1'], self.params['b1'])
        self.layers['ReLU1'] = ReLU()
        self.layers['Affine2'] = Affine(self.params['w2'], self.params['b2'])

        self.lastlayer = SoftmaxWithLoss()

    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)

        return x

    def loss(self, x, t):  # x:测试数据;t:监督数据
        y = self.predict(x)

        return self.lastlayer.forward(y, t)

    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)  # 正确解标签
        if t.ndim != 1:
            t = np.argmax(t, axis=1)

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

    def numerical_grandient(self, x, t):  # 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):
        # forward
        self.loss(x, t)

        # backward
        dout = 1
        dout = self.lastlayer.backward(dout)

        layers = list(self.layers.values())
        layers.reverse()
        # reserved() 是 Python 内置函数之一,其功能是对于给定的序列(包括列表、元组、字符串以及 range(n) 区间),该函数可以返回一个逆序序列的迭代器(用于遍历该逆序序列)
        for layer in layers:
            dout = layer.backward(dout)

        # setting
        grads = {}
        grads['w1'] = self.layers['Affine1'].dw
        grads['b1'] = self.layers['Affine1'].db
        grads['w2'] = self.layers['Affine2'].dw
        grads['b2'] = self.layers['Affine2'].db

        return grads


# 随机梯度下降法
class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr

    def update(self, params, grads):  # 为权重于偏置 w1,w2,b1,b2 这样的参数
        for key in params.keys():
            params[key] -= self.lr * grads[key]


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

networks = TwoLayerNet(input=784, hidden=50, output=10)
optimizer = SGD()

iters_num = 10000
train_size = x_train.shape[0]  # 60000
batch_size = 100  # 批处理数量
learning_rate = 0.1

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)  # mini——batch 处理
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

    grads = networks.gradient(x_batch, t_batch)  # 通过误差反向传播法求梯度
    params = networks.params
    print(params, grads)
    optimizer.update(params, grads)

 SGD的方法简单易于实现,但是也有缺点,现在通过一个函数来讲述:

例如:函数 f\left ( x,y\right )=\frac{1}{20}x^{2}+y^{2} 

利用Matlab绘制图像:

x = linspace(-10,10);

y = linspace(-10,10);

[X,Y] = meshgrid(x,y);

Z = (1/20)*X.^2+Y.^2;

Fig = mesh(X,Y,Z);

 易得该函数的最低点在(0,0,0)处,从图中的颜色变化我们可以看到梯度特征,y轴方向上颜色变化大,意味着坡度大;x轴方向,颜色变化小,意味值梯度小;而SGD有一个重要的性质就是随机,假设从(x,y)=(-10,-10)开始搜索,SGD只会向一个梯度减少的方向前进,具体y轴方向、还是x轴方向都有可能。也就是说SGD低效的根本原因是,更新路径没有朝着最小值的方向前进。

 所以现在学习一些更加高效的方法。

 Momentum:

momentum是动量的意思,和物理有关:

表示方法:v\leftarrow \alpha \upsilon -\eta \frac{\partial L}{\partial W} ;W \leftarrow W +\upsilon ;

这里有一个新的变量 \upsilon ,对应“速度”,v\leftarrow \alpha \upsilon -\eta \frac{\partial L}{\partial W} 表示物体在梯度上受力,在这个力的作用下,物体的“速度”增加。

v\leftarrow \alpha \upsilon -\eta \frac{\partial L}{\partial W}  中的 \alpha \upsilon 这一项 在物体不受力时,他承担时物体减速的任务,故\alpha的值在[0,1] 这样的值:

代码实现:实例变量v会保存物体的速度。初始化时,self.v=None ,表示什么都不存,当update第一次执行时,v会以dict变量的形式保存于参数结构相关的数据

class Momentum:
    def __init__(self, lr=0.01, momentum=0.9):
        self.lr = lr
        self.momentum = momentum
        self.v = None

    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for key, val in params.items():
                self.v[key] = np.zeros_like(val)

        for key in params.keys():
            self.v[key] = self.momentum * self.v[key] - self.lr * grads[key]
            params[key] += self.v[key]

与SGD相比,Momentum很大程度上减少了“随机”,如果SGD的更新路径是“Z”型随机,那么momentum的更新路是“S”型。因为x轴上的变化梯度很小,而y轴的变化梯度很大,可以看作x轴上受到的是恒力,而y轴上受到的是变力。 

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

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

相关文章

C规范编辑笔记(十二)

往期文章&#xff1a; C规范编辑笔记(一) C规范编辑笔记(二) C规范编辑笔记(三) C规范编辑笔记(四) C规范编辑笔记(五) C规范编辑笔记(六) C规范编辑笔记(七) C规范编辑笔记(八) C规范编辑笔记(九) C规则编辑笔记(十) C规范编辑笔记(十一) 正文&#xff1a; 放假了&#xff…

【数据结构】万字深入浅出讲解顺序表(附原码 | 超详解)

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;C语言实现数据结构 &#x1f4ac;总结&#xff1a;希望你看完…

智能矿山电子封条系统 YOLOv5

智能矿山电子封条系统通过yolov5深度学习技术&#xff0c;对现场画面进出口以及主要的井口等重要地方对矿井人员变化、生产作业执勤状态及出入井人员等状况实时监控分析监测。我们使用YOLO(你只看一次)算法进行对象检测。YOLO是一个聪明的卷积神经网络(CNN)&#xff0c;用于实时…

Google AIY Vision Kit安装及国内配置

Google AIY Vision Kit安装及国内配置1. AIY Vision Kit组装环节Step 1&#xff1a;收集其他附件选择1&#xff1a;使用AIY项目应用程序选择2&#xff1a;使用显示器、鼠标和键盘Step 2&#xff1a;检查硬件清单Step 3&#xff1a;构建AIY Vision KitStep 3.1&#xff1a;获取最…

旺店通·企业奇门和用友BIP接口打通对接实战

旺店通企业奇门和用友BIP接口打通对接实战接通系统&#xff1a;旺店通企业奇门旺店通是北京掌上先机网络科技有限公司旗下品牌&#xff0c;国内的零售云服务提供商&#xff0c;基于云计算SaaS服务模式&#xff0c;以体系化解决方案&#xff0c;助力零售企业数字化智能化管理升级…

Mac和Windows局域网互传文件iPhone和Windows局域网互传文件

生活中&#xff0c;我们可以通过微信和QQ或网盘等等传输工具进而实现文件互传&#xff0c;但是面临一个问题&#xff0c;大文件无法上传&#xff0c;而且受到网速的限制等诸多因素影响&#xff0c;如今我们可以通过局域网进行实现文件互传&#xff0c;进而改变此种囧境。 首先在…

17道Redis 面试题

Redis 持久化机制缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题热点数据和冷数据是什么Memcache与Redis的区别都有哪些&#xff1f;单线程的redis为什么这么快redis的数据类型&#xff0c;以及每种数据类型的使用场景&#xff0c;Redis 内部结构redis的过期策略以及…

KVM安装部署 | 举例安装虚机Windows2012R2

目录 1、基础环境准备 2、KVM的安装 3、开启服务 4、开启图形化界面 5、也可以通过浏览器管理KVM 6、举例安装一个windows2012R2 1、基础环境准备 【关闭防火墙】 systemctl stop firewalld systemctl disable firewalld 【关闭selinux】 修改文件/etc/selinux/config…

Linux常用指令及Web程序的部署

作者&#xff1a;~小明学编程 文章专栏&#xff1a;Linux 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 Linux中的常见指令 ls pwd cd 文件操作 touch cat mkdir echo rm cp mv man less vim head tail grep ps netstat Linux权限 搭建Ja…

模电相关知识

6 放大电路中的负反馈 6.1 反馈的基本概念及判断方法 6.4 深度负反馈放大电路放大倍数的分析 6.4.1 深度负反馈的实质 6.4.4 基于理想运放的放大倍数分析 6.4.4.1理想运放的线性工作区 理想运放的性能指标理想运放在线性区的特点 标准运放&#xff0c;有两个输入端和一个…

aws codesuit 在codebuild和codepipeline中集成jenkins

codebuild集成jenkins https://docs.aws.amazon.com/zh_cn/codebuild/latest/userguide/jenkins-plugin.html Setting up a CI/CD pipeline by integrating Jenkins with AWS CodeBuild and AWS CodeDeploy source选择本地的gitlab仓库&#xff0c;创建一个简单的springboot项…

Cert Manager 申请 SSL 证书流程及相关概念 - 一

2022.3.9 用 cert-manager 申请成功通配符证书 (*.ewhisper.cn), 2022.4.30 该证书距离过期还有 30 天&#xff0c;cert-manager 进行自动续期&#xff0c;但是却失败了。&#x1f631;&#x1f631;&#x1f631; 然后过了几天&#xff0c;在 2022.5.8, 最终成功了。如下图&a…

Vue3 项目实战 —— 后台管理系统( pc端 ) —— 动态多级导航菜单顶部侧边联动

前期回顾 0.活在风浪里的博客_CSDN博客-vue2,开源项目,Js领域博主0.活在风浪里擅长vue2,开源项目,Js,等方面的知识,0.活在风浪里关注css,safari,html5,scss,elementui,前端,es6,正则表达式,vue.js,express,ajax,webpack,echarts,json,html,typescript,sass,https,面试,ch…

离散数学-图论-图的矩阵表示(12.1)

图的矩阵表示 1 关联矩阵 定义&#xff1a;设无向图G<V,E>,V{v1,v2,⋅⋅⋅,vnv_1,v_2,,v_nv1​,v2​,⋅⋅⋅,vn​},E{e1,e2,⋅⋅⋅,eme_1,e_2,,e_me1​,e2​,⋅⋅⋅,em​},令mijm_{ij}mij​为顶点viv_ivi​与边eje_jej​的关联次数&#xff0c;则称(mij)nm(m_{ij})_{nm}…

九龙证券|景气度复苏与库存拐点双击,这个行业获主力看好!

今天计算机职业、电子、非银金融职业净流入规划居前&#xff0c;9股主力资金净流入超2亿元。 证券时报数据宝统计&#xff0c;今天沪深两市主力资金净流出46.1亿元&#xff0c;其间创业板净流出3.57亿元&#xff0c;沪深300成份股净流入28.21亿元。 申万一级职业中&#xff0c…

SpringAMQP - Work Queue 工作消息队列

目录 介绍 案例 测试 改进&#xff1a; 介绍 Work queues也被称为&#xff08;Task queues&#xff09;&#xff0c;任务模型简单来说就是让多个消费者绑定到一个队列&#xff0c;共同消费队列中的消息当消息处理比较耗时的时候&#xff0c;可能生产消息的速度会远远大于消…

机器人与未来

我们生活在“普适机器人”时代&#xff0c;机器人将像今天的智能手机一样融入日常生活&#xff0c;完成许多专门任务&#xff0c;并经常与人类并肩工作。 机器人革命将创造一个比现在更加生动和充满活力的未来。 到 2022 年&#xff0c;机器人将获得如此大的吸引力&#xff0…

全国地名点地统计模式分析

前言用不同的空间点模式分析方法&#xff0c;综合得出全国地名数据点的空间分布模式属于随机分布、均匀分布、聚集分布中的哪一种。一、点模式分析空间点模式分析是一种根据地理实体或事件的空间位置研究其分布模式的空间分析方法 。 空间点分布模式通常分为三种&#xff1a;随…

从汇编的角度去审视函数的调用【函数栈帧】

文章目录函数栈帧栈寄存器相关汇编指令函数栈帧的创建函数栈帧的销毁函数栈帧 我们在写C语言代码的时候&#xff0c;经常会把一个独立的功能抽象为函数&#xff0c;所以C程序是以函数为基本单位的。 那函数是如何调用的&#xff1f;函数的返回值又是如何待会的&#xff1f;函数…

17种编程语言实现排序算法-冒泡排序

开源地址 https://gitee.com/lblbc/simple-works/tree/master/sort 覆盖语言&#xff1a;C、C、C#、Java、Kotlin、Dart、Go、JavaScript(JS)、TypeScript(TS)、ArkTS、swift、PHP。 覆盖平台&#xff1a;安卓(Java、Kotlin)、iOS(SwiftUI)、Flutter(Dart)、Window桌面(C#)、前…