《Day3-PyTorch 自动微分入门:从计算图到梯度下降的实践指南》

八、自动微分

        自动微分模块torch.autograd负责自动计算张量操作的梯度,具有自动求导功能。自动微分模块是构成神经网络训练的必要模块,可以实现网络权重参数的更新,使得反向传播算法的实现变得简单而高效。

1. 基础概念

张量

        Torch中一切皆为张量,属性requires_grad决定是否对其进行梯度计算。默认是 False,如需计算梯度则设置为True。

计算图

        torch.autograd通过创建一个动态计算图来跟踪张量的操作,每个张量是计算图中的一个节点,节点之间的操作构成图的边。

        在 PyTorch 中,当张量的 requires_grad=True 时,PyTorch 会自动跟踪与该张量相关的所有操作,并构建计算图。每个操作都会生成一个新的张量,并记录其依赖关系。当设置为 True 时,表示该张量在计算图中需要参与梯度计算,即在反向传播(Backpropagation)过程中会自动计算其梯度;当设置为 False 时,不会计算梯度。

例如:
z = x * y

                                                loss = z.sum()

        在上述代码中,x 和 y 是输入张量,即叶子节点,z 是中间结果,loss 是最终输出。每一步操作都会记录依赖关系:

z = x * y:z 依赖于 x 和 y。

loss = z.sum():loss 依赖于 z。

这些依赖关系形成了一个动态计算图,如下所示:

x       y\     /\   /\ /z||vloss

叶子节点

在 PyTorch 的自动微分机制中,叶子节点(leaf node) 是计算图中:

  • 由用户直接创建的张量,并且它的 requires_grad=True。
  •  这些张量是计算图的起始点,通常作为模型参数或输入变量。

特征:

  • 没有由其他张量通过操作生成。

  • 如果参与了计算,其梯度会存储在 leaf_tensor.grad 中。

  • 默认情况下,叶子节点的梯度不会自动清零,需要显式调用 optimizer.zero_grad() 或 x.grad.zero_() 清除。

如何判断一个张量是否是叶子节点?

通过 tensor.is_leaf 属性,可以判断一个张量是否是叶子节点。

x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)  # 叶子节点
y = x ** 2  # 非叶子节点(通过计算生成)
z = y.sum()
​
print(x.is_leaf)  # True
print(y.is_leaf)  # False
print(z.is_leaf)  # False

叶子节点与非叶子节点的区别

特性叶子节点非叶子节点
创建方式用户直接创建的张量通过其他张量的运算生成
is_leaf 属性TrueFalse
梯度存储梯度存储在 .grad 属性中梯度不会存储在 .grad,只能通过反向传播传递
是否参与计算图是计算图的起点是计算图的中间或终点
删除条件默认不会被删除在反向传播后,默认被释放(除非 retain_graph=True)

detach():张量 x 从计算图中分离出来,返回一个新的张量,与 x 共享数据,但不包含计算图(即不会追踪梯度)。

特点

  • 返回的张量是一个新的张量,与原始张量共享数据。

  • 对 x.detach() 的操作不会影响原始张量的梯度计算。

  • 推荐使用 detach(),因为它更安全,且在未来版本的 PyTorch 中可能会取代 data。

import torch
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x.detach()  # y 是一个新张量,不追踪梯度
​
y += 1  # 修改 y 不会影响 x 的梯度计算
print(x)  # tensor([1., 2., 3.], requires_grad=True)
print(y)  # tensor([2., 3., 4.])

反向传播

        使用tensor.backward()方法执行反向传播,从而计算张量的梯度。这个过程会自动计算每个张量对损失函数的梯度。例如:调用 loss.backward() 从输出节点 loss 开始,沿着计算图反向传播,计算每个节点的梯度。

梯度

        计算得到的梯度通过tensor.grad访问,这些梯度用于优化模型参数,以最小化损失函数。

2. 计算梯度

使用tensor.backward()方法执行反向传播,从而计算张量的梯度

2.1 标量梯度计算

参考代码如下:

import torch
​
​
def test001():# 1. 创建张量:必须为浮点类型x = torch.tensor(1.0, requires_grad=True)
​
​# 2. 操作张量y = x ** 2
​# 3. 计算梯度,也就是反向传播y.backward()
​# 4. 读取梯度值print(x.grad)  # 输出: tensor(2.)
​
​
if __name__ == "__main__":test001()
​

2.2 向量梯度计算

案例:

def test003():# 1. 创建张量:必须为浮点类型x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
​# 2. 操作张量y = x ** 2
​# 3. 计算梯度,也就是反向传播y.backward()
​# 4. 读取梯度值print(x.grad)
​
​
if __name__ == "__main__":test003()

错误预警:RuntimeError: grad can be implicitly created only for scalar outputs

由于 y 是一个向量,我们需要提供一个与 y 形状相同的向量作为 backward() 的参数,这个参数通常被称为 梯度张量(gradient tensor),它表示 y 中每个元素的梯度。

def test003():# 1. 创建张量:必须为浮点类型x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
​# 2. 操作张量y = x ** 2
​# 3. 计算梯度,也就是反向传播#反向传播默认输出是标量,如果输出是向量可以在backward()进行梯度张量初始化y.backward(torch.tensor([1.0, 1.0, 1.0]))
​# 4. 读取梯度值print(x.grad)# 输出# tensor([2., 4., 6.])
​
​
if __name__ == "__main__":test003()

我们也可以将向量 y 通过一个标量损失函数(如 y.mean())转换为一个标量,反向传播时就不需要提供额外的梯度向量参数了。这是因为标量的梯度是明确的,直接调用 .backward() 即可。

import torch
​
​
def test002():# 1. 创建张量:必须为浮点类型x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
​# 2. 操作张量y = x ** 2
​# 3. 损失函数loss = y.mean()
​# 4. 计算梯度,也就是反向传播loss.backward()
​# 5. 读取梯度值print(x.grad)
​
​
if __name__ == "__main__":test002()
​

2.3 多标量梯度计算

参考代码如下

import torch
​
​
def test003():# 1. 创建两个标量x1 = torch.tensor(5.0, requires_grad=True, dtype=torch.float64)x2 = torch.tensor(3.0, requires_grad=True, dtype=torch.float64)
​# 2. 构建运算公式y = x1**2 + 2 * x2 + 7# 3. 计算梯度,也就是反向传播y.backward()# 4. 读取梯度值print(x1.grad, x2.grad)# 输出:# tensor(10., dtype=torch.float64) tensor(2., dtype=torch.float64)
​
​
if __name__ == "__main__":test003()
​

2.4 多向量梯度计算

代码参考如下

import torch
​
​
def test004():# 创建两个张量,并设置 requires_grad=Truex = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)y = torch.tensor([4.0, 5.0, 6.0], requires_grad=True)
​# 前向传播:计算 z = x * yz = x * y
​# 前向传播:计算 loss = z.sum()loss = z.sum()
​# 查看前向传播的结果print("z:", z)  # 输出: tensor([ 4., 10., 18.], grad_fn=<MulBackward0>)print("loss:", loss)  # 输出: tensor(32., grad_fn=<SumBackward0>)
​# 反向传播:计算梯度loss.backward()
​# 查看梯度print("x.grad:", x.grad)  # 输出: tensor([4., 5., 6.])print("y.grad:", y.grad)  # 输出: tensor([1., 2., 3.])
​
​
if __name__ == "__main__":test004()
​

3. 梯度上下文控制

梯度计算的上下文控制和设置对于管理计算图、内存消耗、以及计算效率至关重要。下面我们学习下Torch中与梯度计算相关的一些主要设置方式。

3.1 控制梯度计算

梯度计算是有性能开销的,有些时候我们只是简单的运算,并不需要梯度

默认情况下叶子节点的梯度不会自动清零,会累加

import torch
​
​
def test001():x = torch.tensor(10.5, requires_grad=True)print(x.requires_grad)  # True
​# 1. 默认y的requires_grad=True,# y默认也会参与梯度计算,但不是保存该梯度值y = x**2 + 2 * x + 3print(y.requires_grad)  # True
​# 2. 如果不需要y计算梯度-with进行上下文管理with torch.no_grad():y = x**2 + 2 * x + 3print(y.requires_grad)  # False
​# 3. 如果不需要y计算梯度-使用装饰器@torch.no_grad()def y_fn(x):return x**2 + 2 * x + 3
​y = y_fn(x)print(y.requires_grad)  # False
​# 4. 如果不需要y计算梯度-全局设置,需要谨慎torch.set_grad_enabled(False)y = x**2 + 2 * x + 3print(y.requires_grad)  # False
​
​
if __name__ == "__main__":test001()
​

3.2 累计梯度

默认情况下,当我们重复对一个自变量进行梯度计算时,梯度是累加的

默认情况下叶子节点的梯度不会自动清零,会累加

import torch
​
​
def test002():# 1. 创建张量:必须为浮点类型x = torch.tensor([1.0, 2.0, 5.3], requires_grad=True)
​# 2. 累计梯度:每次计算都会累计梯度for i in range(3):y = x**2 + 2 * x + 7z = y.mean()z.backward()print(x.grad)
​
​
if __name__ == "__main__":test002()
​

输出结果:

tensor([1.3333, 2.0000, 4.2000])
tensor([2.6667, 4.0000, 8.4000])
tensor([ 4.0000,  6.0000, 12.6000])

思考:如果把 y = x**2 + 2 * x + 7放在循环外,会是什么结果?

会报错:

RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved tensors after calling backward.

PyTorch 的自动求导机制在调用 backward() 时,会计算梯度并将中间结果存储在计算图中。默认情况下,这些中间结果在第一次调用 backward() 后会被释放,以节省内存。如果再次调用 backward(),由于中间结果已经被释放,就会抛出这个错误。

3.3 梯度清零

大多数情况下是不需要梯度累加的,奇葩的事情还是需要解决的~

import torch
​
​
def test002():# 1. 创建张量:必须为浮点类型x = torch.tensor([1.0, 2.0, 5.3], requires_grad=True)
​# 2. 累计梯度:每次计算都会累计梯度for i in range(3):y = x**2 + 2 * x + 7z = y.mean()# 2.1 反向传播之前先对梯度进行清零#获取当前轮次的梯度,不是累加值# 自动清零一般放在反向传播之前if x.grad is not None:x.grad.zero_()z.backward()print(x.grad)
​
​
if __name__ == "__main__":test002()# 输出:
# tensor([1.3333, 2.0000, 4.2000])
# tensor([1.3333, 2.0000, 4.2000])
# tensor([1.3333, 2.0000, 4.2000])

3.4 案例1-求函数最小值

通过梯度下降找到函数最小值

import torch
from matplotlib import pyplot as plt
import numpy as np
​
​
def test01():x = np.linspace(-10, 10, 100)y = x ** 2
​plt.plot(x, y)
​plt.show()
​
​
def test02():# 初始化自变量Xx = torch.tensor([3.0], requires_grad=True, dtype=torch.float)# 迭代轮次epochs = 50# 学习率lr = 0.1
​list = []for i in range(epochs):# 计算函数表达式y = x ** 2
​# 梯度清零if x.grad is not None:x.grad.zero_()# 反向传播y.backward()# 梯度下降,不需要计算梯度,为什么?# 设置不参与梯度计算with torch.no_grad():#原地修改# 不能使用 x = x - lr * x.grad这个是复制x -= lr * x.grad
​print('epoch:', i, 'x:', x.item(), 'y:', y.item())list.append((x.item(), y.item()))
​# 散点图,观察收敛效果x_list = [l[0] for l in list]y_list = [l[1] for l in list]
​plt.scatter(x=x_list, y=y_list)plt.show()
​
​
if __name__ == "__main__":test01()test02()
​

代码解释:

# 梯度下降,不需要计算梯度
with torch.no_grad():x -= lr * x.grad

如果去掉梯度控制会有什么结果?

代码中去掉梯度控制会报异常:

RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.

因为代码中x是叶子节点(叶子张量),是计算图的开始节点,并且设置需要梯度。在pytorch中不允许对需要梯度的叶子变量进行原地操作。因为这会破坏计算图,导致梯度计算错误。

在代码中,x 是一个叶子变量(即直接定义的张量,而不是通过其他操作生成的张量),并且设置了 requires_grad=True,因此不能直接通过 -= 进行原地更新。

解决方法

为了避免这个错误,可以使用以下两种方法:

方法 1:使用 torch.no_grad() 上下文管理器

在更新参数时,使用 torch.no_grad() 禁用梯度计算,然后通过非原地操作更新参数。

with torch.no_grad():a -= lr * a.grad

方法 2:使用 data 属性或detach()

通过 x.data 访问张量的数据部分(不涉及梯度计算),然后进行原地操作。

x.data -= lr * x.grad

x.data返回一个与 a 共享数据的张量,但不包含计算图

特点

  • 返回的张量与原始张量共享数据。

  • 对 x.data 的操作是原地操作(in-place),可能会影响原始张量的梯度计算。

  • 不推荐使用 data,因为它可能会导致意外的行为(如梯度计算错误)。

能不能将代码修改为:

x = x - lr * x.grad

答案是不能,以上代码中=左边的x变量是由右边代码计算得出的,就不是叶子节点了,从计算图中被剥离出来后没有了梯度,报错:

RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

总结:以上方均不推荐,正确且推荐的做法是使用优化器,优化器后续会讲解。

3.5 案例2-函数参数求解

import torch
​
def test02():# 定义数据x = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float)y = torch.tensor([3, 5, 7, 9, 11], dtype=torch.float)
​# 定义模型参数 a 和 b,并初始化a = torch.tensor([1], dtype=torch.float, requires_grad=True)b = torch.tensor([1], dtype=torch.float, requires_grad=True)# 学习率lr = 0.1# 迭代轮次epochs = 100
​for epoch in range(epochs):
​
​# 前向传播:计算预测值 y_predy_pred = a * x + b
​# 定义损失函数loss = ((y_pred - y) ** 2).mean()
​if a.grad is not None and b.grad is not None:a.grad.zero_()b.grad.zero_()
​# 反向传播:计算梯度loss.backward()
​# 梯度下降with torch.no_grad():a -= lr * a.gradb -= lr * b.grad
​if (epoch + 1) % 10 == 0:print(f'Epoch [{epoch + 1}/{epochs}], Loss: {loss.item():.4f}')
​print(f'a: {a.item()}, b: {b.item()}')
​
​
if __name__ == '__main__':test02()

代码逻辑:

在 PyTorch 中,所有的张量操作都会被记录在一个计算图中。对于代码:

y_pred = a * x + b
loss = ((y_pred - y) ** 2).mean()

计算图如下:

a → y_pred → loss
x ↗
b ↗
  • a 和 b 是需要计算梯度的叶子张量(requires_grad=True)。

  • y_pred 是中间结果,依赖于 a 和 b。

  • loss 是最终的标量输出,依赖于 y_pred。

当调用 loss.backward() 时,PyTorch 会从 loss 开始,沿着计算图反向传播,计算 loss 对每个需要梯度的张量(如 a 和 b)的梯度。

1、计算 loss 对 y_pred 的梯度:

求损失函数关于 y_pred 的梯度(即偏导数组成的向量)。由于 loss 是 y_pred 的函数,我们需要对每个y_pred_i求偏导数,并将它们组合成一个向量。

应用链式法则和常数求导规则,对于每个 (y_pred_i − y_i)^2 项,梯度向量的每个分量是:

将结果组合成一个向量,我们得到:

其中n=5,y_pred和y均为向量。

2、计算 y_pred 对 a 和 b 的梯度:

y_pred = a * x + b

对 a 求导:x,x为向量

对 b 求导:1

3、根据链式法则,loss 对 a 的梯度为:

代码运行结果:

Epoch [10/100], Loss: 3020.7896
Epoch [20/100], Loss: 1550043.3750
Epoch [30/100], Loss: 795369408.0000
Epoch [40/100], Loss: 408125767680.0000
Epoch [50/100], Loss: 209420457869312.0000
Epoch [60/100], Loss: 107459239932329984.0000
Epoch [70/100], Loss: 55140217861896667136.0000
Epoch [80/100], Loss: 28293929961149737992192.0000
Epoch [90/100], Loss: 14518387713533614273593344.0000
Epoch [100/100], Loss: 7449779870375595263567855616.0000
a: -33038608105472.0, b: -9151163924480.0

损失函数在训练过程中越来越大,表明模型的学习过程出现了问题。这是因为学习率(Learning Rate)过大,参数更新可能会“跳过”最优值,导致损失函数在最小值附近震荡甚至发散。

解决方法:调小学习率,将lr=0.01

代码运行结果:

Epoch [10/100], Loss: 0.0965
Epoch [20/100], Loss: 0.0110
Epoch [30/100], Loss: 0.0099
Epoch [40/100], Loss: 0.0092
Epoch [50/100], Loss: 0.0086
Epoch [60/100], Loss: 0.0081
Epoch [70/100], Loss: 0.0075
Epoch [80/100], Loss: 0.0071
Epoch [90/100], Loss: 0.0066
Epoch [100/100], Loss: 0.0062
a: 1.9492162466049194, b: 1.1833451986312866

可以看出loss损失函数值在收敛,a接近2,b接近1

将epochs=500

代码运行结果:

Epoch [440/500], Loss: 0.0006
Epoch [450/500], Loss: 0.0006
Epoch [460/500], Loss: 0.0005
Epoch [470/500], Loss: 0.0005
Epoch [480/500], Loss: 0.0005
Epoch [490/500], Loss: 0.0004
Epoch [500/500], Loss: 0.0004
a: 1.986896276473999, b: 1.0473089218139648

a已经无限接近2,b无限接近1

总结

PyTorch 的自动微分模块torch.autograd是实现神经网络训练的核心工具,其核心功能是自动计算张量操作的梯度,支撑反向传播算法以更新模型参数。本文从基础概念、梯度计算方法、梯度上下文控制到实际案例,系统梳理了自动微分的核心逻辑:

  1. 基础概念

    • 张量与 requires_grad:张量通过requires_grad属性控制是否参与梯度计算(默认 False),需计算梯度时设为 True。
    • 计算图:动态构建的有向图,节点为张量,边为操作,记录张量依赖关系以支持反向传播。
    • 叶子节点:用户直接创建且requires_grad=True的张量(is_leaf=True),是计算图起点,梯度存储在.grad中;非叶子节点由运算生成,梯度不存储且反向传播后默认释放。
    • detach():将张量从计算图分离,返回共享数据但不追踪梯度的新张量。
    • 反向传播与梯度:通过tensor.backward()触发反向传播,计算梯度;梯度通过tensor.grad访问,用于参数优化。
  2. 梯度计算方法

    • 标量梯度:输出为标量时,直接调用backward()即可计算梯度。
    • 向量梯度:输出为向量时,需传入与向量同形的梯度张量(如torch.tensor([1.0,1.0,1.0])),或通过mean()等转换为标量后再调用backward()
    • 多变量梯度:无论是多标量还是多向量,通过构建计算图后反向传播,可同时计算多个变量的梯度。
  3. 梯度上下文控制

    • 禁用梯度计算:通过with torch.no_grad()@torch.no_grad()装饰器或全局torch.set_grad_enabled(False),减少不必要的性能开销。
    • 梯度累加与清零:默认梯度会累加,需通过tensor.grad.zero_()手动清零,确保每轮梯度计算准确。
    • 叶子节点更新:更新叶子节点(如模型参数)时需禁用梯度计算(如with torch.no_grad()),避免破坏计算图。
  4. 实践案例

    • 函数最小值求解:通过梯度下降迭代更新自变量,逐步收敛到函数最小值。
    • 线性回归参数求解:基于损失函数反向传播,优化参数拟合数据,验证了学习率对收敛的关键影响(过大导致发散,过小收敛缓慢)。

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

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

相关文章

apache cgi测试

test.cgi #!/bin/sh echo "Content-type: text/html" echo "" echo "<h1>Hello from a Mac CGI script!</h1>" echo "<p>Current time is: $(date)</p>"ƒ% 放置目录 /opt/homebrew/Cellar/mapserver/8.4.0_1…

力扣 30 天 JavaScript 挑战 第二题笔记

这道题是涉及知识–闭包 1. 闭包定义以及相关知识点 官方定义为&#xff1a;在 JavaScript 中&#xff0c;函数具有对在相同作用域以及任何外部作用域中声明的所有变量的引用。这些作用域被称为函数的 词法环境。函数与其环境的组合被称为 闭包。 简单理解&#xff1a;内层函数…

OpenAI GPT-5 深度解析:API Key定价与ChatGPT(Free, Plus, Pro)用户的区别

前言&#xff1a;两年等待&#xff0c;只为这一跃 在科技圈长达两年的屏息期待与无尽猜想之后&#xff0c;2025年8月8日北京时间凌晨&#xff0c;OpenAI终于揭开了其新一代旗舰模型——GPT-5的神秘面纱。这不仅仅是一次常规的产品迭代&#xff0c;更被整个行业视为一块试金石&a…

ClickHouse集群部署实践---3分片2副本集群

ClickHouse集群部署实践—3分片2副本集群 未完待续。。。 喜欢的先点赞收藏&#xff01;&#xff01; 由于我们准备部署的是3分片2副本的集群&#xff0c;现在来解释一下配置参数的意思&#xff1a; shard标签代表分片的意思&#xff0c;如上图我们有3个分片&#xff0c;clickh…

Unity_VR_Pico开发手册

文章目录一、配置开发环境1.下载PICO Unity Integration SDK2.安装 Unity 编辑器&#xff08;添加安卓开发平台模块&#xff09;3.导入下载的SDK4.项目配置和切换开发平台5.导入 XR Interaction Toolkit6.安装 Universal RP(通用渲染管线)并设置 (选做)二、调试环境搭建&#x…

Linux系统之Docker命令与镜像、容器管理

目录 一、 Docker命令 docker命令帮助 docker常用子命令&#xff08;必须背会&#xff09; docker管理子命令(暂时不需要) swarm集群管理子命令&#xff08;不需要&#xff09; docker容器管理子命令&#xff08;必须背会&#xff09; docker全局选项 二、 docker镜像管…

比亚迪第五代DM技术:AI能耗管理的深度解析与实测验证

比亚迪第五代DM技术&#xff1a;AI能耗管理的深度解析与实测验证 &#xff08;面向新能源汽车研发/测试工程师&#xff09;目录 技术背景与核心突破AI能耗管理系统架构解析关键技术创新点 2.1 动力域三脑合一控制2.2 全温域热管理协同2.3 导航数据深度耦合 实测数据与场景验证 …

sqli-labs通关笔记-第37关POST宽字符注入(单引号闭合 手工注入+脚本注入 3种方法)

目录 一、宽字符注入 二、sqlmap之unmagicquotes 三、addslashes与mysqli_real_escape_string 四、源码分析 1、代码审计 2、SQL注入安全性分析 五、渗透实战 1、进入靶场 2、正确用户名密码探测 3、手工注入&#xff08;方法1&#xff09; &#xff08;1&#xff…

Kubernetes 集群密钥与机密管理方案对比分析:Vault、Sealed Secrets 与 AWS KMS

Kubernetes 集群密钥与机密管理方案对比分析&#xff1a;Vault、Sealed Secrets 与 AWS KMS 在容器化与编排环境中&#xff0c;机密&#xff08;Secrets&#xff09;管理是确保应用安全性的重要环节。对于 Kubernetes 集群而言&#xff0c;内置的 Secret 对象存在明文存储的风…

Java基础-TCP通信单服务器接受多客户端

目录 案例要求&#xff1a; 实现思路&#xff1a; 代码&#xff1a; User类&#xff1a;用户端 Client类&#xff1a;服务端 ServerReader类&#xff1a;多线程通信类 总结&#xff1a; 案例要求&#xff1a; TCP通信下,正常的写法只能单个服务器和单个客户端进行通信&a…

electron:vue3+vite打包案例

1、安装electron 首先设置镜像源&#xff0c;否则安装会非常非常慢。 打开npm的配置文件。 npm config edit 修改配置项。 registryhttps://registry.npmmirror.com electron_mirrorhttps://cdn.npmmirror.com/binaries/electron/ electron_builder_binaries_mirrorhttp…

traceroute命令调试网络

文章目录 @[toc] 一、核心原理与参数解析 1. 工作原理 2. 关键参数 二、六大运维场景实战 场景1:内网服务器无法访问公网 场景2:跨国访问延迟高(电商业务卡顿) 场景3:VPN分流异常(流量泄露) 场景4:检测DNS劫持 场景5:防火墙规则验证 场景6:云服务跨区延迟优化 三、高…

自己本地搭建的服务器怎么接公网?公网IP直连服务器方法,和只有内网IP直接映射到互联网

​ 你是不是也遇到过这样的问题&#xff1a;在家里或者公司搭建了一个服务器&#xff0c;但是不知道怎么通过公网IP直接访问它&#xff1f;别急&#xff0c;其实很简单&#xff01;今天就给大家分享几种方法&#xff0c;手把手教你如何实现公网IP直连服务器&#xff0c;和无公网…

MATLAB中文乱码的解决方法

文章目录问题描述解决方法问题描述 对于matlab脚本输出乱码&#xff1a; ‘ʮ&#xfffd;&#xfffd;&#xfffd;&#xfffd;Ф&#xfffd;&#xfffd;&#xfffd;&#xfffd;һ&#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;й&#xfffd;&#xff…

工业场景反光衣识别准确率↑32%:陌讯多模态融合算法实战解析

原创声明本文为原创技术解析&#xff0c;核心数据与算法逻辑引用自《陌讯技术白皮书》&#xff0c;禁止任何形式的未经授权转载。一、行业痛点&#xff1a;反光衣识别的场景难题在建筑施工、道路养护、仓储物流等工业场景中&#xff0c;作业人员反光衣穿戴规范检测是安全生产的…

北京JAVA基础面试30天打卡05

一、Redis 的持久化机制有哪些&#xff1f;** Redis 提供两种主要的持久化机制&#xff1a; ✅ RDB&#xff08;Redis DataBase&#xff09;快照持久化 定期将 Redis 中的数据以“快照”的形式写入磁盘&#xff08;生成 .rdb 文件&#xff09;。启动 Redis 时会加载 .rdb 文件恢…

深入理解 Maven POM 文件:核心配置详解

前言 在 Java 开发领域&#xff0c;Apache Maven 是一个强大的项目管理和构建自动化工具。而pom.xml文件&#xff0c;作为 Maven 项目的“心脏”&#xff0c;定义了项目的方方面面。本文将带你深入了解pom.xml中最常用和最重要的配置项&#xff0c;帮助你快速掌握 Maven 的核心…

嵌入式学习的第四十天-51单片机

一、基本框架第一阶段&#xff1a;1980年、Intel英特尔MCS-51系列&#xff1a;8051型号单片机、工业控制领域、由MCU市场->CPU市场。1、CPU&#xff08;Central Processing Unit&#xff0c;中央处理单元&#xff09;‌是计算机的核心部件&#xff0c;负责执行计算机指令和处…

Linux(17)——Linux进程信号(上)

目录 一、信号速识 ✍️生活中的信号 ✍️技术上的信号 ✍️信号的发送和记录 ✍️信号处理概述 二、产生信号 ✍️通过终端产生信号 ✍️通过函数发送信号 ✍️通过软件产生信号 ✍️通过硬件产生信号 一、信号速识 ✍️生活中的信号 你在网上买了很多件商品&…

使用pytest对接口进行自动化测试

上篇博客中讲述了什么是接口测试&#xff0c;已经自动化接口测试流程&#xff0c;这篇博客总结如何实现接口自动化测试&#xff08;一&#xff09;requestsrequests库是Python对HTTP通信的一个工具&#xff0c;将http协议操作封装成简单的接口&#xff0c;能够让我们高效的编写…