深入浅出梯度下降与反向传播
文章目录
- 1. 前言
- 2. 基本概念
- 2.1 一元函数的导数
- 2.2 偏导数
- 2.3 方向导数
- 2.4 梯度
- 2.5 均方误差
- 3. 梯度下降
- 3.1 梯度下降的公式
- 3.2 梯度下降的类型(优化器)
- 4. 反向传播
- 4.1 反向传播的基本步骤
- 4.2 反向传播的数学推导
- 5. 实战
- 5.1 手动求导
- 5.2 自动求导
- 5.3 过程可视化
1. 前言
在深度学习中,梯度下降和反向传播是两个至关重要的概念。它们共同作用于优化神经网络,使其能够从数据中学习到有用的模式。尽管它们是深度学习的核心,但很多人对这两个概念仍然感到困惑。本博客将深入讲解梯度下降和反向传播的基本原理,并通过一个简单的示例来加以说明。
2. 基本概念
2.1 一元函数的导数
如果有一个函数 f ( x ) f(x) f(x),它的导数 f ′ ( x ) f^′(x) f′(x) 给出了函数在点 x 0 x_0 x0 处沿着 x x x 轴的变化速率,即:
f ′ ( x 0 ) = lim Δ x → 0 f ( x 0 + Δ x ) − f ( x 0 ) Δ x f ^\prime (x_0) = \lim_{\Delta x \to 0} \frac {f(x_0 + \Delta x) - f(x_0)} {{\Delta x}} f′(x0)=Δx→0limΔxf(x0+Δx)−f(x0) 这个导数告诉我们,沿着 x x x轴方向,函数的变化快慢情况。
2.2 偏导数
对于多变量函数 f ( x 1 , x 2 , … , x n ) f(x_1, x_2, \dots, x_n) f(x1,x2,…,xn),偏导数描述了函数在某一维度(即某个变量)上变化的速率。例如,函数 f ( x , y ) = x 2 + y 2 f(x, y) = x^2 + y^2 f(x,y)=x2+y2 的偏导数为:
∂ f ∂ x = 2 x , ∂ f ∂ y = 2 y \frac{\partial f}{\partial x} = 2x, \quad \frac{\partial f}{\partial y} = 2y ∂x∂f=2x,∂y∂f=2y 这些偏导数分别表示函数在 x x x轴方向和 y y y轴方向的变化速率。
2.3 方向导数
描述了一个多变量函数在某一点沿任意给定方向的变化率。对于一个函数 f ( x 1 , x 2 , … , x n ) f(x_1, x_2, \dots, x_n) f(x1,x2,…,xn),在点 x 0 \mathbf{x_0} x0 处沿着单位向量 v \mathbf{v} v 方向的方向导数表示为:
D v f ( x 0 ) = ∇ f ( x 0 ) ⋅ v D_{\mathbf{v}} f(\mathbf{x_0}) = \nabla f(\mathbf{x_0}) \cdot \mathbf{v} Dvf(x0)=∇f(x0)⋅v其中, ∇ f ( x 0 ) \nabla f(\mathbf{x_0}) ∇f(x0) 是函数在点 x 0 \mathbf{x_0} x0 的梯度。
方向导数的几何意义:方向导数给出了函数在某一点沿某个方向的变化速率。它可以看作是沿着某个方向的切线变化率,而不仅仅是沿坐标轴的变化率。
即在某一点 x 0 \mathbf{x_0} x0,如果我们沿着某个方向 v \mathbf{v} v 走,方向导数告诉我们,沿着这个方向走时,函数值变化的快慢。如果方向导数为正,说明函数值在增加;如果为负,说明函数值在减少;如果为零,说明函数值在这个方向上没有变化。
2.4 梯度
在一个多变量的标量函数 f ( x 1 , x 2 , … , x n ) f(x_1, x_2, \dots, x_n) f(x1,x2,…,xn) 中,梯度是一个向量,表示函数在某一点的最速上升方向。梯度不仅告诉我们函数的变化率,还告诉我们该变化率最大的方向。具体来说,梯度是函数的所有偏导数组成的向量:
∇ f ( x 1 , x 2 , … , x n ) = ( ∂ f ∂ x 1 , ∂ f ∂ x 2 , … , ∂ f ∂ x n ) \nabla f(x_1, x_2, \dots, x_n) = \left( \frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, \dots, \frac{\partial f}{\partial x_n} \right) ∇f(x1,x2,…,xn)=(∂x1∂f,∂x2∂f,…,∂xn∂f) 梯度的方向:梯度的方向指向函数值增加最快的方向。
梯度的大小:梯度的模长(即向量的长度)表示沿着这个方向,函数变化的速率。
可以把梯度看作是一个“指示器”,它告诉我们在某一点,函数增长最快的方向。换句话说,梯度指向了“上坡”的方向。
2.5 均方误差
均方误差(Mean Squared Error, MSE)
,是一种常用的衡量模型预测值与实际值之间差异的指标,尤其是回归任务中,MSE
的计算公式如下:
M S E = 1 n ∑ i = 1 n ( y i − y ^ i ) 2 MSE = \frac {1} {n} \sum _{i=1} ^ n (y_i - \hat y_i) ^ 2 MSE=n1i=1∑n(yi−y^i)2其中, n n n是样本数量, y i y_i yi是第 i i i个样本的真实值, y ^ i \hat y_i y^i是模型对第 i i i个样本的预测值。
均方误差也叫做最小二乘法。
3. 梯度下降
梯度下降(Gradient Descent, GD)
是一种优化算法,用于最小化(或最大化)一个函数,通常用来训练机器学习模型。在神经网络中,我们的目标是通过调整模型的参数(例如权重和偏置)来最小化损失函数。损失函数衡量了模型的预测与实际标签之间的差异,目标是让这个损失函数的值尽可能小。
梯度下降的核心思想是,沿着损失函数的梯度(偏导数)下降,不断更新参数,直到达到最小值。
3.1 梯度下降的公式
梯度下降的更新规则如下:
θ = θ − η ⋅ ∇ θ L ( θ ) \theta = \theta - \eta \cdot \nabla_\theta L(\theta) θ=θ−η⋅∇θL(θ)其中:
θ \theta θ 是模型的参数(例如权重和偏置)。
η \eta η 是学习率(learning rate),控制每次更新的步长。
∇ θ L ( θ ) \nabla_\theta L(\theta) ∇θL(θ) 是损失函数 L L L 关于参数 θ \theta θ 的梯度。
梯度 ∇ θ L ( θ ) \nabla_\theta L(\theta) ∇θL(θ) 告诉我们,沿着哪个方向更新参数能使损失函数下降得更快。
3.2 梯度下降的类型(优化器)
1.
批量梯度下降(Batch Gradient Descent)
:每次使用整个数据集来计算梯度和更新参数。虽然准确性高,但计算开销大,尤其是在数据量很大的时候。
2.
随机梯度下降(Stochastic Gradient Descent, SGD)
:每次只用一个样本来计算梯度和更新参数。虽然更新速度快,但可能会导致参数更新不稳定。
3.
小批量梯度下降(Mini-Batch Gradient Descent)
:每次使用数据集中的一个小批量样本来计算梯度和更新参数。这种方法结合了批量和随机梯度下降的优点。
当然,还有很多类型的优化,比如Adam
、RMSprop
、AdaW
等,这里不再细述。
4. 反向传播
反向传播(Back Propagation, BP)
是用于计算神经网络中每一层的梯度的算法。它是梯度下降的一部分,特别用于计算和传播每个参数对损失函数的贡献。
反向传播算法依赖于链式法则(Chain Rule)
,通过链式法则可以将损失函数对模型参数的梯度逐层传播回去,从而更新每一层的参数。
即从输出层一步步传播到输入层。
4.1 反向传播的基本步骤
假设我们有一个包含多个层的神经网络,每一层都有权重 W W W 和偏置 b b b。反向传播的步骤如下:
1.
前向传播:从输入层开始,将输入数据传递到输出层,并计算出预测值。
2.
计算损失:根据模型的输出与真实标签计算损失函数。
3.
反向传播:
(1)
计算输出层的梯度,即损失函数关于输出的偏导数。
(2)
逐层计算隐藏层的梯度,即损失函数关于每一层的输入、权重和偏置的偏导数。
4.
更新权重和偏置:根据梯度下降规则更新每一层的权重和偏置。
4.2 反向传播的数学推导
假设神经网络有两层,每层的输出分别为 a 1 a_1 a1 和 a 2 a_2 a2,损失函数为 L L L。反向传播的目标是计算 ∂ L ∂ W 1 \frac{\partial L}{\partial W_1} ∂W1∂L 和 ∂ L ∂ W 2 \frac{\partial L}{\partial W_2} ∂W2∂L,即每一层权重的梯度。
1.
输出层梯度计算:
∂ L ∂ a 2 = ∂ L ∂ y ⋅ ∂ y ∂ a 2 \frac{\partial L}{\partial a_2} = \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial a_2} ∂a2∂L=∂y∂L⋅∂a2∂y其中 y y y是输出层的预测值。
2.
隐藏层梯度计算:
∂ L ∂ a 1 = ∂ L ∂ a 2 ⋅ ∂ a 2 ∂ a 1 \frac{\partial L}{\partial a_1} = \frac{\partial L}{\partial a_2} \cdot \frac{\partial a_2}{\partial a_1} ∂a1∂L=∂a2∂L⋅∂a1∂a2然后,我们使用链式法则计算每一层的权重梯度。
3.
参数更新:根据计算出来的梯度使用梯度下降更新权重和偏置。
5. 实战
5.1 手动求导
我们来构建一个简单的神经网络,做一个线性回归:
模型的输入为2维数据,输出为1维数据,该模型的函数表达式可以表示为:
y ∗ = w 5 ⋅ ( w 1 ⋅ x 1 + w 3 ⋅ x 2 ) + w 6 ⋅ ( w 2 ⋅ x 1 + w 4 ⋅ x 2 ) y^* = w_5 \cdot (w_1 \cdot x_1 + w_3 \cdot x_2) + w_6 \cdot (w_2 \cdot x_1 + w_4 \cdot x_2) y∗=w5⋅(w1⋅x1+w3⋅x2)+w6⋅(w2⋅x1+w4⋅x2) 我们使用MSE
来作为损失函数,来优化我们的网络,即
L o s s = 1 n ∑ i = 1 n ( y i − y i ∗ ) 2 Loss = \frac {1} {n} \sum _{i=1} ^ n (y_i - y^*_i) ^ 2 Loss=n1i=1∑n(yi−yi∗)2
假设初始时模型的权重为:
w 1 = 1.0 , w 2 = 0.5 , w 3 = 0.5 , w 4 = 0.7 w_1=1.0,w_2=0.5,w_3=0.5,w_4=0.7 w1=1.0,w2=0.5,w3=0.5,w4=0.7 w 5 = 1.0 , w 6 = 2.0 w_5=1.0,w_6=2.0 w5=1.0,w6=2.0 已知一个样本数据:
x 1 = 0.5 , x 2 = 1.0 , y = 0.8 x_1=0.5,x_2=1.0,y=0.8 x1=0.5,x2=1.0,y=0.8 按照上述公式,计算一次前向传播,得到 y ∗ = 2.9 y^*=2.9 y∗=2.9,与真实值 y y y 的偏差可以通过 l o s s loss loss 计算得到, l o s s = ( y − y ∗ ) 2 = 4.41 loss = (y - y^*) ^ 2 = 4.41 loss=(y−y∗)2=4.41。然后我们通过梯度下降的方式来更新 w 5 w_5 w5,需要先计算出在点 ( x 1 , x 2 ) (x_1,x_2) (x1,x2)的梯度:
∇ = ∂ L ∂ w 1 = ∂ L ∂ y ∗ ⋅ ∂ y ∗ ∂ w 5 \nabla = \frac {\partial L} {\partial w_1} = \frac {\partial L} {\partial y^*} \cdot \frac {\partial y^*} {\partial w_5} ∇=∂w1∂L=∂y∗∂L⋅∂w5∂y∗ ∂ L ∂ y ∗ = − 2 ( y − y ∗ ) = 4.2 \frac {\partial L} {\partial y^*} = -2 (y- y^*) = 4.2 ∂y∗∂L=−2(y−y∗)=4.2 ∂ y ∗ ∂ w 5 = w 1 ⋅ x 1 + w 3 ⋅ x 2 = 1.0 \frac {\partial y^*} {\partial w_5} = w_1 \cdot x_1 + w_3 \cdot x_2 = 1.0 ∂w5∂y∗=w1⋅x1+w3⋅x2=1.0
所以梯度为:
∂ L ∂ w 1 = 4.2 \frac {\partial L} {\partial w_1} = 4.2 ∂w1∂L=4.2 假设,学习率为 0.01 0.01 0.01,根据梯度下降算法 θ = θ − η ⋅ ∇ θ L ( θ ) \theta = \theta - \eta \cdot \nabla_{\theta} L(\theta) θ=θ−η⋅∇θL(θ) 更新 w 5 w5 w5:
w 5 = w 5 − η ∂ L ∂ w 5 = 0.958 w_5 = w_5 - \eta \frac {\partial L} {\partial w_5} = 0.958 w5=w5−η∂w5∂L=0.958 同理,可以更新 w 1 w_1 w1:
∂ y ∗ ∂ w 1 = w 5 x 1 = 0.5 \frac {\partial y^*} {\partial w_1} = w_5x_1 = 0.5 ∂w1∂y∗=w5x1=0.5 ∂ L ∂ w 1 = ∂ L ∂ y ∗ ⋅ ∂ y ∗ ∂ w 1 = 2.1 \frac {\partial L} {\partial w_1} = \frac {\partial L} {\partial y^*} \cdot \frac {\partial y^*} {\partial w_1} = 2.1 ∂w1∂L=∂y∗∂L⋅∂w1∂y∗=2.1 w 1 = w 1 − η ∂ L ∂ w 1 = 0.979 w_1 = w_1 - \eta \frac {\partial L} {\partial w_1} = 0.979 w1=w1−η∂w1∂L=0.979
5.2 自动求导
将上面模型的表达式形式化,即
y ∗ = ( x T ⋅ W h ) ⋅ W o y* = (x^T \cdot W_h) \cdot W_o y∗=(xT⋅Wh)⋅Wo其中,
x = [ x 1 x 2 ] , W h = [ w 1 w 2 w 3 w 4 ] , W o = [ w 5 w 6 ] x = \begin{bmatrix} x_1 \\ x_2\end{bmatrix},W_h = \begin{bmatrix} w_{1} & w_{2} \\ w_{3} & w_{4} \end{bmatrix},W_o = \begin{bmatrix} w_{5} & w_{6} \end{bmatrix} x=[x1x2],Wh=[w1w3w2w4],Wo=[w5w6] 这样,我们就可以使用pytorch
来构建上述神经网络了,具体如下:
# -*- coding: utf-8 -*-
# Author : liyanpeng
# Email : yanpeng.li@cumt.edu.cn
# Datetime: 2024/11/29 17:38
# Filename: chain_rule.py
import torch
import torch.nn as nn
import torch.optim as optimdef func_y():x1 = torch.tensor(0.5, dtype=torch.float32)x2 = torch.tensor(1.0, dtype=torch.float32)w1 = torch.tensor(1.0, dtype=torch.float32)w2 = torch.tensor(0.5, dtype=torch.float32)w3 = torch.tensor(0.5, dtype=torch.float32)w4 = torch.tensor(0.7, dtype=torch.float32)w5 = torch.tensor(1.0, dtype=torch.float32)w6 = torch.tensor(2.0, dtype=torch.float32)y = w5 * (w1 * x1 + w2 * x2) + w6 * (w3 * x1 + w4 * x2)print(y)class SimpleNeuralNetwork(nn.Module):def __init__(self):super().__init__()self.linear1 = nn.Linear(in_features=2, out_features=2, bias=False)self.linear2 = nn.Linear(in_features=2, out_features=1, bias=False)self.linear1.weight.data = torch.tensor([[1.0, 0.5], [0.5, 0.7]], dtype=torch.float32)self.linear2.weight.data = torch.tensor([[1.0, 2.0]], dtype=torch.float32)def forward(self, x):x = self.linear1(x)y = self.linear2(x)return ydef grad_hook(grad):print('grad:', grad[0][0])if __name__ == '__main__':x = torch.tensor([0.5, 1.0], dtype=torch.float32)y = torch.tensor(0.8, dtype=torch.float32)model = SimpleNeuralNetwork()criterion = nn.MSELoss()optimizer = optim.SGD(model.parameters(), lr=0.01)hook_list = []for name, param in model.named_parameters():if param.requires_grad:hook = param.register_hook(grad_hook)hook_list.append(hook)y_pred = model(x)loss = criterion(y_pred, y)optimizer.zero_grad() # 清空梯度loss.backward() # 反向传播optimizer.step() # 更新权重for hook in hook_list:hook.remove()print('更新后的w1:', model.linear1.weight.data[0, 0])print('更新后的w5:', model.linear2.weight.data[0, 0])
打印结果如下,与手动计算的结果一致:
grad: tensor(4.2000)
grad: tensor(2.1000)
更新后的w1: tensor(0.9790)
更新后的w5: tensor(0.9580)
5.3 过程可视化
再加入一些可视化代码,看一下权重更新的轨迹:
# -*- coding: utf-8 -*-
# Author : liyanpeng
# Email : yanpeng.li@cumt.edu.cn
# Datetime: 2024/11/29 17:38
# Filename: chain_rule.py
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as npif __name__ == '__main__':x = torch.tensor([0.5, 1.0], dtype=torch.float32)y = torch.tensor(0.8, dtype=torch.float32)model = SimpleNeuralNetwork()criterion = nn.MSELoss()optimizer = optim.SGD(model.parameters(), lr=0.01)loss_list = []w1_list = []w2_list = []for epoch in range(5):y_pred = model(x)loss = criterion(y_pred, y)optimizer.zero_grad() # 清空梯度loss.backward() # 反向传播optimizer.step() # 更新权重loss_list.append(loss.item())w1_list.append(model.linear1.weight.data[0, 0].item())w2_list.append(model.linear2.weight.data[0, 0].item())fig = plt.figure(figsize=(8, 6))# 3D曲面图和等高线图ax1 = fig.add_subplot(111, projection='3d')ax1.set_title("3D Loss Surface with Contours and Trajectory")# 将损失值、权重映射到X, Y, Z轴ax1.plot_trisurf(w1_list, w2_list, loss_list, cmap='viridis', alpha=0.7)# 生成网格数据,用于绘制等高线图w1_range = np.linspace(min(w1_list), max(w1_list), 100)w2_range = np.linspace(min(w2_list), max(w2_list), 100)W1, W2 = np.meshgrid(w1_range, w2_range)np.random.seed(42)x_train = np.random.rand(100, 2)noise = np.random.randn(100, 1)# f(x, y) = 2x^2 + y^2 - 0.7 + noisey_train = 2 * x_train[:, 0] * x_train[:, 0] + x_train[:, 1] * x_train[:, 1] - 0.7 + noise# 计算每个网格点的损失值loss_grid = np.zeros(W1.shape)for i in range(W1.shape[0]):for j in range(W1.shape[1]):model.linear1.weight.data[0, 0] = W1[i, j]model.linear2.weight.data[0, 0] = W2[i, j]y_pred = model(torch.tensor(x_train, dtype=torch.float32))loss_grid[i, j] = criterion(y_pred, torch.tensor(y_train, dtype=torch.float32)).item()# 绘制等高线图ax1.contour(W1, W2, loss_grid, levels=20, cmap='viridis', offset=min(loss_list))# 绘制权重更新轨迹ax1.plot(w1_list, w2_list, loss_list, 'k-', marker='o', markersize=5, label="Weight Update Trajectory")ax1.plot(w1_list, w2_list, [min(loss_list)] * len(w1_list), 'r-', marker='o', markersize=5, label="Trajectory on Contours")# 在等高线图上标记权重更新的坐标for i in range(len(w1_list)):ax1.text(w1_list[i], w2_list[i], min(loss_list),f'({w1_list[i]:.4f}, {w2_list[i]:.4f})',color='red', fontsize=8, ha='center', va='center')ax1.set_xlabel('Linear1 Weight (First Element)')ax1.set_ylabel('Linear2 Weight (First Element)')ax1.set_zlabel('Loss')ax1.legend()plt.tight_layout()plt.show()
绘制的效果图如下:
损失函数从右侧至左侧逐渐收敛,最右侧的点是我们第一次更新时 w 1 w_1 w1和 w 2 w_2 w2的权重。
相关文章:

深入浅出梯度下降与反向传播
文章目录 1. 前言2. 基本概念2.1 一元函数的导数2.2 偏导数2.3 方向导数2.4 梯度2.5 均方误差 3. 梯度下降3.1 梯度下降的公式3.2 梯度下降的类型(优化器) 4. 反向传播4.1 反向传播的基本步骤4.2 反向传播的数学推导 5. 实战5.1 手动求导5.2 自动求导5.3…...

【电机控制】基于STC8H1K28的六步换向——方波驱动(硬件篇)
【电机控制】基于STC8H1K28的六步换向——方波驱动(硬件篇) 文章目录 [TOC](文章目录) 前言一、硬件原理图1. MCU主控电路2. LDO电路3. 驱动电路4. 过零检测电路 二、3D图三、参考资料总结 前言 【电机控制】STC8H无感方波驱动—反电动势过零检测六步换向…...

手搓一个ChatUI需要分几步
只关注项目代码的同学可以直接跳转目录中的正文部分,查看项目仓库和功能介绍。 引言 Chatbot的UI界面设计,是和传统软件不同的:都是当面一个简洁的对话框,框里预备着热乎的工具,可以随时更新。 像我这样做工的牛马&a…...

2024年年度总结
前言 前一段时间,看到网上有人发类似于年度总结的东西,我想我也可以写一个,今年的日记也是从开头一直贯彻到了结尾 回忆起一年的事情还是有些困难 一月 回忆起有点困难,原因是我的日记大部分都是记录我当天地感想与情绪&#x…...

labelme2yolov8-seg 草稿()
简介: 最近做实例分割分割,使用Labelme生成json格式标签后,需要转换为txt标签,才能供YOLO进行训练。 在参看b站,github后,发现GitHub有相关项目:lableme2yolo 一个是ultralyics官方的JSON2YO…...

开源简史与概览
Think 1.论述“自由软件”与“开源软件”的区别与联系? 2.GitHub Trending 是一个能够快速找到有趣的新项目的地方;而 OpenLeaderboard 也是一个能够发现有趣而有影响力项目的地方。尝试从这两个网站中找到感兴趣的若干项目,挖掘并分析出上…...

充电桩语音提示芯片方案-支持平台自定义语音NV128H让充电更便捷
随着工业化与城市化进程的加速推进,传统燃油汽车的数量急剧攀升,这直接导致了石油资源的过度开采与消耗。石油,作为不可再生的化石燃料,其储量日益枯竭,价格波动频繁,给全球能源安全带来了前所未有的挑战。…...

277-基于八路256Ksps 24bit AD生物电震动检测FMC子卡
一、板卡概述 板卡基于AD7768 AD芯片设计的八路低速采集的FMC 子卡,支持直流耦合,产品应用于生物电、脑电波、声音,震动等信号采集。 二、板卡参数及性能 板卡功能 参数 内容 ADC 芯片型号 AD7768 路数 8路ADC, 采样率 2…...
【电路理论四】正弦电流电路
正弦电流 正弦量是随时间按正弦规律变动的电路变量。 随时间按正弦规律变动的电流称为正弦电流。 正弦电流的瞬时值表达式: 称为正弦电流的三要素。 分别为振幅/幅值,角频率,初相。 幅值为正弦电流的最大值,恒为正。 为正弦电…...

【PyCharm】如何把本地整个项目同步到服务器?
在PyCharm中,您可以使用部署功能将项目同步到服务器。以下是步骤和示例配置: 打开PyCharm,选择您的项目。 点击菜单栏的 “File” -> “Settings” -> “Build, Execution, Deployment”。 在左侧菜单中,选择 “Deployme…...

露营小程序搭建有哪些步骤?小程序里面可以找个露营搭子
露营不仅仅是走进大自然的旅程,它也成为了一种社交和体验式的活动。随着小程序的普及,露营活动也越来越多地开始在线上开展。通过搭建一个露营小程序,商家不仅可以为用户提供更多的露营选择,还可以帮助他们找到合适的露营搭子。那…...

SOLID-开闭原则
单一职责原则:https://blog.csdn.net/dmk877/article/details/143447010 在前面我们学习了单一职责原则,今天来一起学习一下SOLID原则中的开闭原则(Open-Closed Principle, OCP) 通过本篇博客你将学到到以下内容 ①什么是开闭原则 ②如何实现开闭原则 ③…...

前端经典面试合集(二)——Vue/React/Node/工程化工具/计算机网络
1. 说说 Vue 中的 Diff 算法 Vue 的 Diff 算法 主要用于优化虚拟 DOM 和实际 DOM 之间的比较过程。它通过以下几种策略来提高性能: 最小化对 DOM 的操作:Vue 通过在内存中构建一个虚拟 DOM 树,在虚拟 DOM 树与真实 DOM 树之间进行比较和更新…...

PH47代码框架 24241231 重要更新
仪式感一下:2024年最后一天,发布 PH47 代码框架的一次重要更新。当然这并不是有意的,而是直到现在才把更新的所有工作全部做完(希望确实如此)。 本次更新要点: 1、加入多IMU支持。本次更新正式加入对 MPU65…...

Qt6之QML——作用域
作用域定义了表达式可以访问哪些变量、属性或对象,并决定了在变量重名时的优先级如何处理。以下将从作用、绑定、组件作用域和使用技巧四个方面详细解析 QML 中的作用域。 1. 作用:表达式的变量访问与优先级 在 QML 中,表达式能够访问的变量…...

119.【C语言】数据结构之快速排序(调用库函数)
目录 1.C语言快速排序的库函数 1.使用qsort函数前先包含头文件 2.qsort的四个参数 3.qsort函数使用 对int类型的数据排序 运行结果 对char类型的数据排序 运行结果 对浮点型数据排序 运行结果 2.题外话:函数名的本质 1.C语言快速排序的库函数 cplusplus网的介绍 ht…...

C#封送类
封送类(Marshaling classes)在.NET框架中扮演着至关重要的角色,尤其是在托管代码与非托管代码之间进行数据交换时。封送过程涉及到将托管环境中的对象转换为非托管环境中可以理解的形式,并且反之亦然。这一过程确保了两种不同类型…...

2024年度学习总结
2024年是我学业生涯的结束,是我职业生涯的开始。2024年6月19日我顺利研究生毕业,进入体制内,陆止于此,海始于斯,知识和文化最大的魅力,大概就是教会人谦卑和敬畏。读研的目的不是为了单纯拿到哪个证书&…...

我的博客年度之旅:感恩、成长与展望
目录 感恩有你 技能满点 新年新征程 嘿,各位技术大佬、数码潮咖还有屏幕前超爱学习的小伙伴们!当新年的钟声即将敲响,我们站在时光的交汇点上,回首过往,满心感慨;展望未来,豪情满怀。过去的这…...

undefined symbol: __nvJitLinkComplete_12_4, version libnvJitLink.so.12
目录 我的解决方法: 测试: 报错: undefined symbol: __nvJitLinkComplete_12_4, version libnvJitLink.so.12 from torch._C import * # noqa: F403 ImportError: /mnt/pfs/users/lbg/envs/mmpano/lib/python3.9/site-packages/torch/lib…...

【OTA】论文笔记--《智能网联汽车整车OTA功能设计研究》智能网联汽车OTA系统设计分析报告
智能网联汽车OTA系统设计分析报告 引言 随着汽车智能化、网联化水平不断提升,现代汽车中电子控制单元(ECU)的数量和复杂度持续增加。据统计,高级轿车上电子电气元件的成本已占整车开发成本的60%~70%。为了实现对这些电控单元的软件开发调试、数据标定、文件更新和故障修复,…...

c#String和StringBuilder
目录 一,String 1,string的特点: 2,string常用方法 (1)Length (2)Substring() (3)ToUpper() (4)ToLower() (5&…...

【Linux】HTTP协议
之前,我们已经做过了自定义协议,事实上,已经有很多现成已经做好又非常好用的协议,它们都是相同的,比如HTTP协议。所谓HTTP协议,就是超文本传输协议,定义了客户端和服务器之间是如何通信的&#…...

计算机网络 (14)数字传输系统
一、定义与原理 数字传输系统,顾名思义,是一种将连续变化的模拟信号转换为离散的数字信号,并通过适当的传输媒介进行传递的系统。在数字传输系统中,信息被编码成一系列的二进制数字,即0和1,这些数字序列能够…...

《向量数据库指南》——Milvus Cloud 2.5:Sparse-BM25引领全文检索新时代
Milvus Cloud BM25:重塑全文检索的未来 在最新的Milvus Cloud 2.5版本中,我们自豪地引入了“全新”的全文检索能力,这一创新不仅巩固了Milvus Cloud在向量数据库领域的领先地位,更为用户提供了前所未有的灵活性和效率。作为大禹智库的向量数据库高级研究员,以及《向量数据…...

Unity3D 网络框架设计详解
前言 Unity3D是一款强大的跨平台游戏开发引擎,网络框架的设计对于实现客户端与服务器之间的稳定通信至关重要。本文将详细介绍Unity3D网络框架的设计原理、技术要点以及代码实现。 对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一…...

网络渗透测试实验四:CTF实践
1.实验目的和要求 实验目的:通过对目标靶机的渗透过程,了解CTF竞赛模式,理解CTF涵盖的知识范围,如MISC、PPC、WEB等,通过实践,加强团队协作能力,掌握初步CTF实战能力及信息收集能力。熟悉网络扫描、探测HTTP web服务、目录枚举、提权、图像信息提取、密码破解等相关工具…...

Wend看源码-Java-Collections 工具集学习
摘要 java.util.Collections它提供了一系列静态方法,用于对集合(如List、Set、Map等)进行操作。这些操作包括排序、查找、替换、同步等多种功能,帮助开发者更方便地处理集合数据。以下是Collections 提供的一些主要方法的总结。…...

[JAVA]MyLogger
import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.*;/*** 可以自已定义日志打印格式,这样看起来比较方便些**/ class MyFormatter extends Formatter {Overridepublic String format(LogRecord ar…...

玩转OCR | 腾讯云智能结构化OCR初次体验
目录 一、什么是OCR(需要了解) 二、产品概述与核心优势 产品概述 智能结构化能做什么 举例说明(选看) 1、物流单据识别 2、常见证件识别 3、票据单据识别 4、行业材料识别 三、产品特性 高精度 泛化性 易用性 四、…...