【课程总结】Day7:深度学习概述

2024-06-12 02:04

本文主要是介绍【课程总结】Day7:深度学习概述,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

本篇文章,我们将通过示例来逐步学习理解导数、求函数最小值、深度学习的本质、以及使用numpy和pytorch实操深度学习训练过程。

线性回归

线性回归内容回顾

在《【课程总结】Day5(下):PCA降维、SVD分解、聚类算法和集成学习》中,我们已经了解到线性回归以及线性回归可以表示为:

y = f ( x ) = x 1 w 1 + x 2 w 2 + . . . + x 13 w 13 + b y=f(x)=x_1w_1 + x_2w_2 + ... + x_{13}w_{13} + b y=f(x)=x1w1+x2w2+...+x13w13+b

其中:

  • ( x*1, x2, …, x_{13} ):输入特征向量 ( x ) 的各个特征值,代表输入数据的各个特征。*
  • ( w_1, w2, …, w{13} ):权重向量 ( w ) 的各个权重值,用来衡量每个特征对输出的影响程度。
  • ( b ):偏置项,也称为截距项,用来调整模型的输出值,即在没有特征输入时的输出值。
  • ( y ):模型的输出值,即线性回归模型对输入特征的预测值。

该公式也可以表示为内积相乘的方式,如下:

y = f ( x ) = x @ w + b y=f(x)=x@w+b y=f(x)=x@w+b

其中:

x@w:特征向量 ( x ) 与 权重向量( w ) 的内积

如果有多个样本的话,那么上面的公示可以进一步表示为:

y = f ( X ) = X @ w + b y=f(X)=X@w+b y=f(X)=X@w+b

其中:

X代表特征矩阵,矩阵的行为一条一条的样本,矩阵的列为多个特征向量。

线性回归方程的解析

  • 在训练时,xy是训练集中的特征和标签,看作是常量w和b是待优化的参数值,看作是变量
  • 在推理时,wb已经找到了比较合适的值固定下来,看作常量;此时x是待预测的样本的特征,是变量
  • 预测的本质:把x带入,求解y。

线性回归=求损失loss函数的最小值

训练过程

由上图可知,训练的大致过程是:

  1. 从训练集中取出一对x 和y
  2. 把x带入模型,求解预测结果y_pred
  3. 找到一种方法,度量y和y_pred的误差loss
  4. 由此推导:
    • loss是y和y_pred的函数;
    • y_pred是模型预测的结果,是w和b的函数;
    • 所以简单来说,loss也是w和b的函数
训练的本质

由上图推导结果可知,训练的本质:求解loss什么时候是最小值。

数学表达:当w和b取得什么值的时候,loss最小

通俗表达:求loss函数的最小值

如何求函数的最小值?

一个例子

y = 2 x 2 y = 2x^2 y=2x2

上述这个示例中,求y最小值是比较简单的,从图形中可以看到x=0时,y=0为最小值。但是实际工程中,并不是所有的函数y=f(x)都能画出来,简单地找到最小值,此时就需要使用导数求最小值。

如果你和我一样忘了导数相关的知识,可以查看《【重拾数学知识】导数、极值和最值》回顾一下。

求解方法(理论方法)

通过回归导数求极值的方法,我们知道大致步骤如下:

  • 第一步:求函数的导数
  • 第二步:令导数等于零
  • 第三步:解方程,求出疑似极值点
  • 第四步:验证该点是否是极值点以及是什么极值点

求解的问题

上述的方法是有一定前提条件的,即:

  • 第一步的求(偏)导数是可以求得的;
  • 第三步(偏)导数为零后,方程(组)是可以解的。

实际工程中,上述方法是不可行的。以Llama3-8B模型为例,其有80亿个输入参数x,按照上述的求解方法是无法求得最小值的!

由此可知,通过推导公式期望一次性求得最小值是不现实的;而我们可以借鉴人工智能中一个重要的思想:迭代法来逐步求解最小值。

求解方法(迭代法)

仍然以 y = 2 x 2 y = 2x^2 y=2x2为例,我们可以通过以下方法求得最小值。

随机选择一个出生点 x 0 x_0 x0

  • x 0 x_0 x0在最小值的左侧时, x 0 x_0 x0 + 正数(一个非常小的正数)向右侧移动;
  • x 0 x_0 x0在最小值的右侧时, x 0 x_0 x0 - 正数(一个非常小的正数)向左侧移动;
  • x 0 x_0 x0在最小值的时候,不用移动,此时就是最小值。

由导数的单调性可知:

  • x 0 x_0 x0在左侧时,由于函数是单调递减的,所以导数<0
  • x 0 x_0 x0在右侧时,由于函数是单调递增的,所以导数>0

因此上述的计算方法可以推导得到:

  • x 0 x_0 x0在0的左侧时, x 0 x_0 x0 + 正数 → x 0 x_0 x0 + 导数 → x 0 x_0 x0 - 导数

    因为导数<0,加上一个小于的导数相当于减去导数

  • x 0 x_0 x0在0的右侧时, x 0 x_0 x0 - 正数 → x 0 x_0 x0 - 导数

    因为导数>0,减去一个大于的导数相当于减去导数

  • x 0 x_0 x0=0时,也可以看作是 x 0 x_0 x0 - 导数

由此,我们可以得到结论:不管$$x_0$$在何处,求最小值时减去导数即向极值逼近。

概念补充
  • 在一元函数中,求函数f(x)在某一点的斜率为导数;在多元函数中,称为偏导数,也就是梯度。
  • 减去导数也就是减去梯度,这就是梯度下降法!

备注:深度学习在兴起之前,人工智能只能靠支持向量机撑门面;伴随着互联网+GPU芯片的兴起,梯度下降法拥有了使用的土壤,以此人工智能才真正兴起。

代码实现(手动求函数最小值)

y = 2 x 2 y = 2x^2 y=2x2为例

import numpy as npdef fn(x):"""原始函数"""return 2 * x ** 2def dfn(x):"""导函数"""return 4 * xdef gradient_descent(x0, learning_rate, dfn, epochs):"""使用梯度下降法求函数的最小值Parameters:x0 (float): 初始点的位置learning_rate (float): 学习率dfn (function): 导函数epochs (int): 迭代次数Returns:x_min (float): 最小值点的位置"""for _ in range(epochs):x0 = x0 - learning_rate * dfn(x0)return x0# 随机选择一个出生点
x0 = np.random.randint(low=-1000, high=1000, size=1)# 迭代次数
epochs = 1000# 学习率
learning_rate = 1e-2# 使用梯度下降法求最小值
x_min = gradient_descent(x0, learning_rate, dfn, epochs)# 输出最小值
print("最小值点的位置:", x_min)

运行结果:

f ( x , y , z ) = x 2 + y 2 + z 2 f(x,y,z) = x^2 + y^2 + z^2 f(x,y,z)=x2+y2+z2为例

import numpy as npdef df_x(x, y, z):"""f 对 x 求偏导"""return 2 * xdef df_y(x, y, z):"""f 对 y 求偏导"""return 2 * ydef df_z(x, y, z):"""f 对 z 求偏导"""return 2 * z# 随机选择出生点
x0 = np.random.randint(low=-1000, high=1000, size=(1,))
y0 = np.random.randint(low=-1000, high=1000, size=(1,))
z0 = np.random.randint(low=-1000, high=1000, size=(1,))# 迭代次数
epochs = 1000# 学习率
learning_rate = 1e-2for _ in range(epochs):# 求解每个变量的偏导fx = df_x(x0, y0, z0)fy = df_y(x0, y0, z0)fz = df_z(x0, y0, z0)# 每个变量都减去自己的偏导x0 = x0 - learning_rate * fxy0 = y0 - learning_rate * fyz0 = z0 - learning_rate * fz# 输出更新后的变量值
print("更新后的 x 值:", x0)
print("更新后的 y 值:", y0)
print("更新后的 z 值:", z0)

运行结果:

代码实现(使用pytorch求函数最小值)

上述通过求导数得到函数最小值的方法,也可以通过pytorch来实现,具体代码如下:

y = 2 x 2 y = 2x^2 y=2x2为例

import torch# 定义原始函数和导函数
def fn(x):return 2 * x ** 2# 说明:pytorch可以通过grad函数求导,所以可以省去写导函数
# def dfn(x):
#     return 4 * x# 随机选择出生点
# requires_grad=True用来告诉框架该变量是一个张量,需要计算梯度。
x0 = torch.randint(low=-1000, high=1001, size=(1,), dtype=torch.float32, requires_grad=True)# 迭代次数
epochs = 1000# 学习率
learning_rate = 1e-2# 使用 PyTorch 进行梯度下降
for _ in range(epochs):# 正向传播计算损失loss = fn(x0)# 反向传播计算梯度loss.backward()# 获取梯度并更新参数with torch.no_grad():grad = x0.gradx0 -= learning_rate * grad# 梯度清零x0.grad.zero_()# 输出最小值点的位置
print("最小值点的位置:", x0.item())

运行结果:

f ( x , y , z ) = x 2 + y 2 + z 2 f(x,y,z) = x^2 + y^2 + z^2 f(x,y,z)=x2+y2+z2为例

import torchdef fn(x, y, z):"""函数定义"""return x**2 + y**2 + z**2# 说明:pytorch可以通过grad函数求导,所以可以省去写导函数
# def df_x(x, y, z):
#     return 2 * x# def df_y(x, y, z):
#     return 2 * y# def df_z(x, y, z):
#     return 2 * z# 随机选择出生点
x0 = torch.randint(low=-1000, high=1001, size=(1,), dtype=torch.float32, requires_grad=True)
y0 = torch.randint(low=-1000, high=1001, size=(1,), dtype=torch.float32, requires_grad=True)
z0 = torch.randint(low=-1000, high=1001, size=(1,), dtype=torch.float32, requires_grad=True)# 迭代次数
epochs = 1000# 学习率
learning_rate = 1e-2# 使用 PyTorch 进行梯度下降
for _ in range(epochs):# 正向传播计算损失loss = fn(x0, y0, z0)# 反向传播计算梯度loss.backward()# 获取梯度并更新参数# 在测试阶段或者不需要计算梯度的情况下使用 torch.no_grad()# 以提高计算效率并避免不必要的梯度计算。with torch.no_grad():x0 -= learning_rate * x0.grady0 -= learning_rate * y0.gradz0 -= learning_rate * z0.grad# 梯度清零x0.grad.zero_()y0.grad.zero_()z0.grad.zero_()# 输出更新后的变量值
print("更新后的 x 值:", x0.item())
print("更新后的 y 值:", y0.item())
print("更新后的 z 值:", z0.item())

运行结果:

内容小结

  • 线性回归

    • 在训练时,xy是训练集中的特征和标签,看作是常量w和b是待优化的参数值,看作是变量
    • 在推理时,wb已经找到了比较合适的值固定下来,看作常量;此时x是待预测的样本的特征,是变量
    • 预测的本质:把x带入,求解y。
  • 求损失loss函数

    • 由训练的过程可知:损失函数loss也是w和b的函数
    • 训练的本质:求损失loss函数的最小值
  • 求函数最小值

    • 理论的求解方法,在现实工程中由于参数巨大,实际不可行。
    • 实际的求解方式是使用迭代思想逐步求解。
    • 不管 x 0 x_0 x0在何处,求最小值时减去导数即向极值逼近,所以我们可以通过迭代法+迭代中减去导数求最小值,这就是梯度下降法。
  • 求导即可使用numpy方法,也可以使用pytorch

    • 梯度下降法使用过程中,一般需要定义epochs迭代次数、learning_rate学习率
    • 梯度下降法的一般过程为:正向传播计算损失→反向传播计算梯度→获取梯度并更新参数→梯度清零
    • 在循环减去梯度的过程中,需要记得使用.grad.zero_()进行梯度清零

这篇关于【课程总结】Day7:深度学习概述的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1052890

相关文章

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

最新Spring Security实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)

《最新SpringSecurity实战教程之表单登录定制到处理逻辑的深度改造(最新推荐)》本章节介绍了如何通过SpringSecurity实现从配置自定义登录页面、表单登录处理逻辑的配置,并简单模拟... 目录前言改造准备开始登录页改造自定义用户名密码登陆成功失败跳转问题自定义登出前后端分离适配方案结语前言

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Python依赖库的几种离线安装方法总结

《Python依赖库的几种离线安装方法总结》:本文主要介绍如何在Python中使用pip工具进行依赖库的安装和管理,包括如何导出和导入依赖包列表、如何下载和安装单个或多个库包及其依赖,以及如何指定... 目录前言一、如何copy一个python环境二、如何下载一个包及其依赖并安装三、如何导出requirem

Redis 内存淘汰策略深度解析(最新推荐)

《Redis内存淘汰策略深度解析(最新推荐)》本文详细探讨了Redis的内存淘汰策略、实现原理、适用场景及最佳实践,介绍了八种内存淘汰策略,包括noeviction、LRU、LFU、TTL、Rand... 目录一、 内存淘汰策略概述二、内存淘汰策略详解2.1 ​noeviction(不淘汰)​2.2 ​LR

Python与DeepSeek的深度融合实战

《Python与DeepSeek的深度融合实战》Python作为最受欢迎的编程语言之一,以其简洁易读的语法、丰富的库和广泛的应用场景,成为了无数开发者的首选,而DeepSeek,作为人工智能领域的新星... 目录一、python与DeepSeek的结合优势二、模型训练1. 数据准备2. 模型架构与参数设置3