深度学习基础--神经网络(4)参数更新策略,梯度法

news2024/11/28 20:59:30

导数

导数:表示某个瞬间的变化量,公式定义:
d f ( x ) d x = l i m h → 0 f ( x + h ) − f ( x ) h (4.4) \frac{df(x)}{dx} = lim_{h \to 0}\frac{f(x + h)-f(x)}{h} \tag{4.4} dxdf(x)=limh0hf(x+h)f(x)(4.4)
求导的代码实现:

import numpy as np
import matplotlib.pyplot as plt


def function_1(x):
    """函数y = 0.01x^2+0.1x"""
    return 0.01 * x ** 2 + 0.1 * x


def numerical_diff(func, x):
    """函数的导数(梯度)"""
    h = 1e-4
    return (func(x + h) - func(x - h)) / (2 * h)


def tangent_line(f, x):
    """切线"""
    d = numerical_diff(f, x)  # x点处切线斜率, 即变化率
    c = f(x) - d * x
    """
    切线格式:y = dx + c
    切线与函数f(x)交于切点(传入的x就是切点横坐标x,f(x)就是切点纵坐标y)
    c = y - dx, 即上面那行代码c = f(x) - d * x
    同时也是下面返回值lambda函数的格式t(x) = dx+c
    """
    return lambda t: d * t + c


print(numerical_diff(function_1, 5))
# 0.1999999999990898, 函数f(x)在x=5处的导数,即此处的斜率
print(numerical_diff(function_1, 10))
# 0.2999999999986347, 函数f(x)在x=10出的导数, 即此处的斜率


x = np.arange(0.0, 20.0, 0.1)
y = function_1(x)

df1 = tangent_line(function_1, 5)
y2 = df1(x)  # y2 = dx + c, x = 5

df1 = tangent_line(function_1, 10)
y3 = df1(x)  # y3 = dx + c, x = 10

plt.plot(x, y, label="f(x)")
plt.plot(x, y2, label="tangent_line at x=5")
plt.plot(x, y3, label="tangent_line at x=10")
plt.scatter(5, function_1(5))
plt.scatter(10, function_1(10))
plt.xlabel("x")
plt.ylabel("f(x)")
plt.title("f(x) = 0.01x^2+0.1x")
plt.legend()
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HKHy3k60-1669107026677)(./assets/image-20221121180844506.png)]

偏导数

针对二元或多元的函数而言,比如
f ( x 0 , x 1 ) = x 0 2 + x 1 2 f(x_0, x_1) = x_0^{2} + x_1^{2} f(x0,x1)=x02+x12
该函数的代码实现:

import numpy as np


def function_2(x):
    """函数f(x0, x1) = x0 ^ 2 + x1 ^ 2"""
    return np.sum(x ** 2)


x = np.array([1, 2])
f = function_2(x)
print(f)  # 5

该函数的偏导数:
对 x 0 的 偏 导 数 : ∂ f ∂ x 0 = 2 x 0 对x_0的偏导数: \frac{\partial f}{\partial x_0}=2x_0 x0:x0f=2x0
求某个的偏导数就把另一个当作常数

梯度

∇ f = ( ∂ f ∂ x 0 , ∂ f ∂ x 1 ) \nabla f=(\frac{\partial f}{\partial x_0},\frac{\partial f}{\partial x_1}) f=(x0f,x1f)

如上式,由全部变量的偏导数汇总成的向量称为梯度

梯度的代码实现:

import numpy as np


def function_g(x):
    """f(x0, x1) = x0 ^ 2 + x1 ^ 2"""
    return x[0] ** 2 + x[1] ** 2


def numerical_gradient(f, x):
    h = 1e-4  # 0.0001
    grad = np.zeros_like(x)  # 生成和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  # 还原值
    return grad


print(numerical_gradient(function_g, np.array([0.0, 2.0])))  # [0. 4.]
print(numerical_gradient(function_g, np.array([3.0, 4.0])))  # [6. 8.]
print(numerical_gradient(function_g, np.array([3.0, 0.0])))  # [6. 0.]

作者提供的代码,负梯度的方向:

import numpy as np
import matplotlib.pylab as plt
from mpl_toolkits.mplot3d import Axes3D


def _numerical_gradient_no_batch(f, x):
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x)
    
    for idx in range(x.size):
        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 # 还原值
        
    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


def function_2(x):
    if x.ndim == 1:
        return np.sum(x**2)
    else:
        return np.sum(x**2, axis=1)


def tangent_line(f, x):
    d = numerical_gradient(f, x)
    print(d)
    y = f(x) - d*x
    return lambda t: d*t + y
     
if __name__ == '__main__':
    x0 = np.arange(-2, 2.5, 0.25)
    x1 = np.arange(-2, 2.5, 0.25)
    X, Y = np.meshgrid(x0, x1)
    
    X = X.flatten()
    Y = Y.flatten()
    
    grad = numerical_gradient(function_2, np.array([X, Y]) )
    
    plt.figure()
    plt.quiver(X, Y, -grad[0], -grad[1],  angles="xy",color="#666666")#,headwidth=10,scale=40,color="#444444")
    plt.xlim([-2, 2])
    plt.ylim([-2, 2])
    plt.xlabel('x0')
    plt.ylabel('x1')
    plt.grid()
    plt.legend()
    plt.draw()
    plt.show()

运行截图:

在这里插入图片描述

梯度相关内容推荐吴恩达老师机器学习课程的相关内容视频

梯度法寻找最优参数

如上面的图可以看到,梯度表示的是各点处的函数值减少最多的方向,而无法保证梯度所指方向就是函数的最小值。

函数的极小值、最小值以及被称为鞍点的地方梯度为。

极小值就是局部最小值,也就是限定在某个范围内的最小值。

鞍点是从某个方向上看是极大值,从另一个方向上看则是极小值的点。

梯度为0不一定就是最小值,也可能是极小值或者鞍点

当函数很复杂且成扁平状,学习可能会陷入无法前进的停滞期

梯度法:通过不断地沿梯度方向前进,逐渐减小函数值的过程就是梯度法。

梯度法的数学表示:
x 0 = x 0 − η ∂ f ∂ x 0 , x 1 = x 1 − η ∂ f ∂ x 1 (4.7) x_0 = x_0 - \eta \frac{\partial f}{\partial x_0},x_1 = x_1 -\eta \frac{\partial f}{\partial x_1} \tag{4.7} x0=x0ηx0f,x1=x1ηx1f(4.7)
η \eta η:学习率,决定在一次学习中,应该学习多少,在多大程度上更新参数。

学习率需要事先确定为某个值,比如0.01或0.001。类似这样人工设定的参数叫超参数

在神经网络的学习中,一般会一边改变学习率的值,一边确认学习是否正确进行了。

梯度下降法代码实现:

import numpy as np


def function_g(x):
    """f(x0, x1) = x0 ^ 2 + x1 ^ 2"""
    return x[0] ** 2 + x[1] ** 2


def numerical_gradient(f, x):
    """
    梯度
    使用的依然是导数的公式
    由所有偏导数组成的向量
    """
    h = 1e-4  # 0.0001
    grad = np.zeros_like(x)  # 生成和x形状相同的数组
    # print(x.size)
    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  # 还原值
    return grad


def gradient_descent(f, init_x, lr=0.01, step_num=100):
    """
    梯度下降法
    返回使函数 f 值最小的参数 x
    """
    x = init_x
    for i in range(step_num):
        grad = numerical_gradient(f, x)
        x -= lr * grad
    return x


# 输出三个位置对应的梯度
print(numerical_gradient(function_g, np.array([0.0, 2.0])))  # [0. 4.]
print(numerical_gradient(function_g, np.array([3.0, 4.0])))  # [6. 8.]
print(numerical_gradient(function_g, np.array([3.0, 0.0])))  # [6. 0.]

x_input = np.array([-3.0, 4.0])
print(gradient_descent(function_g, init_x=x_input, lr=0.1, step_num=100))  # [-6.11110793e-10  8.14814391e-10]

梯度下降法可视化:

# coding: utf-8
import numpy as np
import matplotlib.pylab as plt
from gradient_2d import numerical_gradient


def gradient_descent(f, init_x, lr=0.01, step_num=100):
    x = init_x
    x_history = []

    for i in range(step_num):
        x_history.append(x.copy())

        grad = numerical_gradient(f, x)
        x -= lr * grad

    return x, np.array(x_history)


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


init_x = np.array([-3.0, 4.0])

lr = 0.1
step_num = 20
x, x_history = gradient_descent(function_2, init_x, lr=lr, step_num=step_num)

plt.plot([-5, 5], [0, 0], '--b')
plt.plot([0, 0], [-5, 5], '--b')
plt.plot(x_history[:, 0], x_history[:, 1], 'o')

plt.xlim(-3.5, 3.5)
plt.ylim(-4.5, 4.5)
plt.xlabel("X0")
plt.ylabel("X1")
plt.show()

运行结果:

在这里插入图片描述

原点处是函数 f ( x 0 , x 1 ) = x 0 2 + x 1 2 f(x_0,x_1)=x_0^2+x_1^2 f(x0,x1)=x02+x12的最小值,函数的取值一点点在向其靠近

神经网络的参数

上面求函数 f ( x 0 , x 1 ) = x 0 2 + x 1 2 f(x_0,x_1)=x_0^2+x_1^2 f(x0,x1)=x02+x12的最小值。

下面来对比求损失函数 L L L的最小值。

函数损失函数
参数 x 0 , x 1 x_0,x_1 x0,x1权重 W = ( w 11 , w 12 , w 13 w 21 , w 22 , w 23 ) W=\left(\begin{matrix}w_{11} ,w_{12},w_{13}\\w_{21},w_{22},w_{23}\end{matrix}\right) W=(w11,w12,w13w21,w22,w23)
梯度 ∇ f = ( ∂ f ∂ x 0 , ∂ f ∂ x 1 ) \nabla f=(\frac{\partial f}{\partial x_0},\frac{\partial f}{\partial x_1}) f=(x0f,x1f) ∂ L ∂ W = ( ∂ L ∂ w 11 , ∂ L ∂ w 12 , ∂ L ∂ w 13 ∂ L ∂ w 21 , ∂ L ∂ w 22 , ∂ L ∂ w 23 ) \frac{\partial L}{\partial W}=\left(\begin{matrix}\frac{\partial L}{\partial w_{11}},\frac{\partial L}{\partial w_{12}},\frac{\partial L}{\partial w_{13}}\\\frac{\partial L}{\partial w_{21}},\frac{\partial L}{\partial w_{22}},\frac{\partial L}{\partial w_{23}}\end{matrix}\right) WL=(w11L,w12L,w13Lw21L,w22L,w23L)

损失函数计算:

使用的激活函数为softmax

def softmax(x):
    """softmax激活函数"""
    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)

    # 监督数据是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
import numpy as np
import activate_functions as af
import loss_functions as ls
import gradient as grad


class SimpleNet:
    def __init__(self):
        """初始化权重参数"""
        self.W = np.random.randn(2, 3)  # 用随机数生成2行3列的矩阵

    def predict(self, x):
        """预测, x为输入"""
        return np.dot(x, self.W)  # x为输入的矩阵,与权重W矩阵相乘

    def loss(self, x, t):
        """计算损失函数"""
        z = self.predict(x)
        y = af.softmax(z)
        loss = ls.cross_entropy_error(y, t)
        return loss


net = SimpleNet()  # 创建SiampleNet对象
x = np.array([0.6, 0.9])  #  输入为x0 = 0.6, x1 = 0.9
p = net.predict(x)  # 前向传播,预测结果
print(p)  # softmax的结果
print(np.argmax(p))  # 以softmax结果的最大值元素的下标作为预测结果
t = np.array([0, 1, 0])  # 设定正确解的为1
print(net.loss(x, t))  # 输出loss

"""输出此时梯度"""
f = lambda w: net.loss(x, t)
dW = grad.numerical_gradient(f, net.W)
print(dW)

输出结果:

在这里插入图片描述

最后的2行三列的矩阵就是此时的梯度,意思是:

w 11 = 0.37723279 w_{11}=0.37723279 w11=0.37723279:如果 w 11 w_{11} w11增加 h h h,那么损失函数的结果loss值就会增加0.37723279。

那么我们希望损失函数越小越好,因此如果梯度为正数那么该参数就该往负梯度方向更新,如果梯度为负数,那么该参数就该向梯度方向更新

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

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

相关文章

SSM框架-Spring(三)

目录 1 Spring对事务的支持 1.1 引入事务场景 1.2 spring对事务的支持 Spring实现事务的两种方式 Spring事务管理API 1.3 事务属性 1.3.1 事务传播行为 1.3.2 事务隔离级别 1.3.3 事务超时 1.3.4 只读事务 1.3.5 异常回滚事务 1.4 事务的全注解式开发 1.5 声明式事…

玩转SQL:咱们的目标是成为SQL方面的“扫地僧”

引言 (Structured Query Language)标准结构化查询语言简称SQL,编写SQL语句是每位后端开发日常职责中,接触最多的一项工作,SQL是关系型数据库诞生的产物,无论是什么数据库,MySQL、Oracle、SQL Server、DB2、PgSQL....&…

FPGA串口接收Demo

串口接收Demo 简单介绍 在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据 空闲状态时,为高电平起始位为一个单位长度低电平,停止位为一个长度高电平 分析 帧格式 8位数据位1位停止位无校验位 …

配电站房监控系统方案

配电站为低压用户配送电能,设有中压进线(可有少量出线)、配电变压器和低压配电装置。计讯物联工业网关下配电站房监控系统方案,24小时对运行设备进行不间断数据采集上传服务器,云平台对接,远程实时在线监控设备运行状态 &#xff…

web前端-javascript-标识符(说明,命名规则、不以数字关键字保留字开头、驼峰命名,补充)

文章目录标识符1. 说明2. 命名规则3. 补充标识符 <!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title><script type"text/javascript">//千万不要这么用/* var if 123;console.log(if); *//…

Linux、阿里云服务器用tomcat部署项目

文章目录一、安装JDK和Tomcat1.1 安装JDK2.2 安装Tomcat二、把项目打包成war包&#xff08;jar也可以&#xff0c;但是有区别&#xff09;三、把war包放进webapps里面四、修改tomcat配置五、修改防火墙和开放端口等设置六、在浏览器访问项目一、安装JDK和Tomcat 1.1 安装JDK …

如果你想跨行转做数据分析师,劝你慎重

随着数字化时代的浪潮&#xff0c;数据分析师成了炽手可热的香饽饽&#xff0c;疫情当下&#xff0c;各行各业的失业人员逐渐增多&#xff0c;所以人人都想转行当数据分析师。作为业内人员&#xff0c;说实话&#xff0c;真的不建议&#xff0c;数据分析师真的不是想象的那么简…

【Webpack】webpack的基础使用详细总结 上(建议收藏)

1- 前言&#xff08;前端工程化&#xff09; 实际的前端开发&#xff1a; 模块化&#xff08;js 的模块化、css 的模块化、其它资源的模块化组件化&#xff08;复用现有的 UI 结构、样式、行为&#xff09;规范化&#xff08;目录结构的划分、编码规范化、接口规范化、文档规范…

代码随想录算法训练营第六天|LeetCode 242. 有效的字母异位词 、349. 两个数组的交集 、 202. 快乐数、1. 两数之和

LeetCode 242. 有效的字母异位词 题目链接&#xff1a;242. 有效的字母异位词 方法一&#xff1a; 分析&#xff1a; 两个字符串里的每个字母的个数相等&#xff0c;那么我对每个字符串里的字符串都进行下排序&#xff0c;排出来后岂不是两个字符串的每个字母如果一一对应就…

高通平台开发系列讲解(AI篇)高通神经网络处理引擎工作流程详解

文章目录 一、Model to Runtime Workflow(模型运行流程)二、Basic SNPE Workflow(基本工作流程)2.1、Converting a Network Model(模型转换)2.2、Quantizing a Model(模型量化)沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇章主要介绍高通平台神经网络处…

K_A07_002 基于 STM32等单片机驱动ULN2003模块按键控制步进电机正反转

目录 一、资源说明 二、基本参数 1.参数 2、引脚说明 三、驱动说明 步进电机驱动时序 反向输出 对应程序: 四、部分代码说明 1、接线说明 1.1、STC89C52RCULN2003模块 1.2、STM32F103C8T6ULN2003模块 五、基础知识学习与相关资料下载 六、视频效果展示与程序资料获取 七…

C#使用EPPlus操作Excel(读写)

之所以使用EPPlus操作Excel是因为微软自带的运行效率太低&#xff0c;数据多后会特别慢&#xff0c;不能满足现场要求。如果想速度快&#xff0c;而且只是读取Excel的配置还有另一个办法就是将Excel保存成xml文件&#xff0c;参考我的另一个文章&#xff1a;C# 读取XML格式的Ex…

概率统计·大数定律及中心极限定理【大数定律、中心极限定律】

这一章的学习更多的是为后面的知识作铺垫&#xff0c;所以内容比较少&#x1f358;&#x1f358;&#x1f358;&#xff08;当然也减轻一点复习的负担&#x1f917;&#x1f917;&#x1f917;&#xff09; 依概率收敛 需要概率P极限趋近于1 切比雪夫不等式的特殊情况 前提&…

数据库-sql执行深度剖析以及redo log和undo log(下)(二)

目录 buffer pool change Buffer Log Buffer redo log 随机IO/顺序IO redo log刷盘时机 redo logt特点 redo log结构 Adaptive Hash Index 磁盘区域 undo log 总结更新流程 BInlog 基于上一章sql执行原理基础上&#xff0c;我们来深入探讨sql更新的整个原理。 bu…

力扣(LeetCode)33. 搜索旋转排序数组(C++)

二分查找 二分的本质&#xff0c;是对某种性质的划分&#xff0c;一半满足&#xff0c;另一半不满足&#xff0c;即可划分。 比较 nums[mid]nums[mid]nums[mid] 和 nums[0]nums[0]nums[0] &#xff0c;可以知道 midmidmid 左右哪一端有序。 如果左端有序&#xff0c;我们找往…

66.基于Django学习会话技术

1. 背景介绍 ​ HTTP协议有一个特性就是无状态的&#xff0c;是指协议对于交互性场景没有记忆能力。 ​ 随着动态交互的web应用的出现&#xff0c;HTTP的无状态特性严重阻碍了动态交互应用程序的发展&#xff0c;例如一些购物网站在进行购物时候都会进行了页面跳转/刷新&…

西门子 S7-1200 与 BL200PN 通信示例

准备 IO 模块&#xff1a;耦合器 BL200PN、数字量输出模块 M2082、数字量输入 M1081、 模拟量输入模块 M3401、模拟量输出 M4043。 2、BL200PN、S7-1200、PC 要同一局域网。将 BL200PN 和 S7-1200 上电&#xff0c;打开西 门子 TIA V13 软件&#xff0c;新建项目“BL200PN”…

SpringBoot开发的实用小工具集,YYDS

真正的大师,永远都怀着一颗学徒的心&#xff01; 一、项目简介 springboot开发的实用小工具集 环境搭建说明 开发环境为jdk1.8&#xff0c;基于maven构建&#xff1b; 使用Idea或者eclipase开发&#xff1b; 基于SpringBoot搭建&#xff0c;大大简化了配置操作&#xff1b;…

DBCO-mPEG2000,二苯并环辛炔-mPEG MW 2000具有亲和力和稳定性

DBCO-mPEG2000白色固体&#xff0c; DBCO试剂在水性缓冲液中具有快速的亲和力和稳定性&#xff0c;可用于以高特异性和反应性标记叠氮化物修饰的生物分子。带有 PEG 臂的试剂会增加化合物的亲水性。西安凯新生物科技有限公司​DBCO 试剂已广泛应用于生物偶联、标记和化学生物学…

你需要知道的前端知识点,V8引擎是什么?采用哪些GC算法?

一、简单介绍V8引擎 V8引擎是一款主流的JavaScript执行引擎;V8执行引擎采用及时编译&#xff08;执行速度提升&#xff09;;V8引擎中内存设置有上限&#xff08;下方进行详解&#xff09;; 二、V8回收策略 采用分代回收思想;内存分为新生代对象存储与老生代对象存储;针对不同…