当前位置: 首页 > article >正文

Python 梯度下降法(七):Summary

文章目录

  • Python 梯度下降法(七):Summary
    • 一、核心思想
      • 1.1 核心思想
      • 1.2 优化方法概述
      • 1.3 第三方库的使用
    • 二、 BGD
      • 2.1 介绍
      • 2.2 torch 库算法
      • 2.2 代码示例
      • 2.3 SGD
      • 2.4 SGD代码示例
      • 2.5 MBGD
      • 2.6 MBGD 代码示例
    • 三、 Adagrad
      • 3.1 介绍
      • 3.2 torch 库算法
      • 3.3 代码示例
    • 四、 Adadelta
      • 4.1 介绍
      • 4.2 torch 库算法
      • 4.3 代码示例
    • 五、RMSProp
      • 5.1 介绍
      • 5.2 torch 库算法
      • 5.3 代码示例
    • 六、Adam
      • 6.1 介绍
      • 6.2 torch 库算法
      • 6.3 代码示例
    • 七、Nadam
      • 7.1 介绍
      • 7.2 torch 库算法
      • 7.3 代码示例
    • 八、 总结
    • 九、相关链接

Python 梯度下降法(七):Summary

一、核心思想

1.1 核心思想

梯度下降法的核心思想是通过不断调整参数,使损失函数的值逐渐减小。每次迭代中,参数沿着损失函数梯度的反方向更新,直到达到最小值或收敛。

Python 梯度下降法系列文章中,我们从基础到进阶,逐步深入探讨了梯度下降法的原理、实现和优化方法。

Python 梯度下降法(一):Gradient Descent我介绍了常用的梯度下降法,其核心公式为:
θ t + 1 : = θ t − η ∇ θ J ( θ ) \theta_{t+1}:=\theta_{t}-\eta \nabla_{\theta}J(\theta) θt+1:=θtηθJ(θ)

这篇文章详细讲解了如何有效使用这一公式,并通过 Python 实现了一个简单的梯度下降算法。

负梯度下降是下降的最快方向,但是由于步长的存在,导致路径并不是最优的,如A->C是沿负梯度进行,但是其并不是最优解,B->C的过程并不是最优的选择。

1738397220_9jbrdd9isw.png1738397219863.png

在后续的文章中,我们逐步探讨了如何基于梯度下降法的核心公式进行优化,优化思路:

  1. 使学习率 η \eta η改变,即改变步长
  2. 使梯度 ∇ θ J ( θ ) \nabla_{\theta}J(\theta) θJ(θ)改变,即改变方向
  3. θ \theta θ更新之前进行处理,可使之变小,即权重衰减

1.2 优化方法概述

1738392060_1uxgrbrx3a.png1738392059611.png

以降低算法的复杂度、资源占用率,并提升其在实际应用中的性能。这些优化方法包括:

  • 批量梯度下降(BGD):使用全部数据计算梯度,稳定性高但计算开销大。
  • 随机梯度下降(SGD):每次迭代使用单个样本计算梯度,计算速度快但收敛不稳定。
  • 小批量梯度下降(Mini-batch GD):结合 BGD 和 SGD 的优点,使用小批量数据计算梯度。
  • 动量法(Momentum):引入动量项,加速收敛并减少震荡。
  • 自适应学习率方法:如 AdaGrad、RMSProp、Adadelta、Adam 和 NAdam,动态调整学习率,适合处理稀疏数据和非凸优化问题。

1.3 第三方库的使用

这些梯度下降的方法可以使用,torch.optim 里面的库来实现

torch进行机器学习流程概述:

  1. 生成示例数据:可以使用torch生成随机数据作为训练数据
  2. 定义线性模型:使用torch.nn.Linear定义一个简答的线性模型
  3. 定义损失函数:使用均方误差损失函数torch.nn.MESLoss
  4. 定义优化器:使用torch.optim里面的类,设置参数
  5. 训练模型:进行多次迭代,每次迭代计算损失并且更新模型参数
  6. 可视化:绘制损失函数图像,当然这是博客需要,你可以绘制原始数据和拟合直线。

二、 BGD

2.1 介绍

Python 梯度下降法(一):Gradient Descent-CSDN博客

GD:
1738394278_meztd066wg.png1738394277769.png

BGD:
1738394349_l1qzd3uxld.png1738394348252.png

SGD — PyTorch 2.6 documentation

2.2 torch 库算法

1738395714_znuzvzre3n.png1738395713524.png

通过官方给定的算法,我们可以发现 momentum ≠ 0 \text{momentum}\ne 0 momentum=0时,即为Momentum梯度下降法,故就不在后文赘述。

2.2 代码示例

optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0)

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

# 生成随机数据
# 生成 100 个在 [0, 2) 之间的随机数作为输入特征
x = 2 * torch.rand(100, 1)
# 生成对应的目标值,添加一些随机噪声
y = 4 + 3 * x  +  torch.randn(100, 1)

loss_ = []   # 存储历史损失值

# 定义线性模型
model = nn.Linear(1, 1)

# 定义损失函数
criterion = nn.MSELoss()

# 定义优化器,使用批量梯度下降(BGD),学习率设置为 0.01
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0)

# 训练模型
num_epochs = 1000
threshold = 1e-8
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(x)
    loss = criterion(outputs, y)  # 使用MES(均方误差损失)的方式计算损失值
    loss_.append(loss.item())
    
    # 反向传播和优化
    optimizer.zero_grad()  # 在每次迭代中将梯度清零
    loss.backward()  # 反向传播,根据链式法则自动计算损失函数对每个参数的偏导数,并将这些梯度存储在参数的 .grad 属性
    optimizer.step()  # 根据优化算法更新参数

    # 检查是否收敛
    if epoch > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
        print(f"Converged at iteration {epoch}")
        break


# 可视化结果
print("斜率:", model.weight.item(), "偏移量:", model.bias.item())
# 绘制损失函数图像
plt.plot(range(len(loss_)), loss_)
plt.title('Linear Regression using BGD')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)  # 显示网格线
plt.show()

2.3 SGD

1738396021_a9u6ei8z5e.png1738396021090.png

2.4 SGD代码示例

其类似BGD,只是每次拟合的样本数据为1

这里使用DataLoader模块来进行数据的选择

from torch.utils.data import TensorDataset, DataLoader

# 创建数据集对象
dataset = TensorDataset(x, y)

# 设置 batch_size
batch_size = 1
# 创建数据加载器,指定 batch_size 和是否打乱数据
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

总代码:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
import matplotlib.pyplot as plt

# 生成随机数据
# 生成 100 个在 [0, 2) 之间的随机数作为输入特征
x = 2 * torch.rand(100, 1)
# 生成对应的目标值,添加一些随机噪声
y = 4 + 3 * x  +  torch.randn(100, 1)

loss_ = []   # 存储历史损失值

# 定义线性模型
model = nn.Linear(1, 1)

# 定义损失函数
criterion = nn.MSELoss()

# 定义优化器,使用批量梯度下降(BGD),学习率设置为 0.01
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0)

# 创建数据集对象
dataset = TensorDataset(x, y)

# 设置 batch_size
batch_size = 1
# 创建数据加载器,指定 batch_size 和是否打乱数据
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)


# 训练模型
num_epochs = 10
threshold = 1e-8
for epoch in range(num_epochs):
    # 前向传播
    for inputs, labels in dataloader:
        outputs = model(inputs)
        loss = criterion(outputs, labels)  # 使用MES(均方误差损失)的方式计算损失值
        loss_.append(loss.item())
        
        # 反向传播和优化
        optimizer.zero_grad()  # 在每次迭代中将梯度清零
        loss.backward()  # 反向传播,根据链式法则自动计算损失函数对每个参数的偏导数,并将这些梯度存储在参数的 .grad 属性
        optimizer.step()  # 根据优化算法更新参数

    # 检查是否收敛
    if epoch > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
        print(f"Converged at iteration {epoch}")
        break


# 可视化结果
print("斜率:", model.weight.item(), "偏移量:", model.bias.item())
# 绘制损失函数图像
plt.plot(range(len(loss_)), loss_)
plt.title('Linear Regression using BGD')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)  # 显示网格线
plt.show()

1738396865_fhoau0bveb.png1738396864461.png

2.5 MBGD

1738396232_kgrxqzhe1o.png1738396231644.png

2.6 MBGD 代码示例

设置 1 < batch_size < all 1<\text{batch\_size}<\text{all} 1<batch_size<all,即可实现

总代码:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
import matplotlib.pyplot as plt

# 生成随机数据
# 生成 100 个在 [0, 2) 之间的随机数作为输入特征
x = 2 * torch.rand(100, 1)
# 生成对应的目标值,添加一些随机噪声
y = 4 + 3 * x  +  torch.randn(100, 1)

loss_ = []   # 存储历史损失值

# 定义线性模型
model = nn.Linear(1, 1)

# 定义损失函数
criterion = nn.MSELoss()

# 定义优化器,使用批量梯度下降(BGD),学习率设置为 0.01
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0)

# 创建数据集对象
dataset = TensorDataset(x, y)

# 设置 batch_size
batch_size = 40
# 创建数据加载器,指定 batch_size 和是否打乱数据
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)


# 训练模型
num_epochs = 100
threshold = 1e-8
for epoch in range(num_epochs):
    # 前向传播
    for inputs, labels in dataloader:
        outputs = model(inputs)
        loss = criterion(outputs, labels)  # 使用MES(均方误差损失)的方式计算损失值
        loss_.append(loss.item())
        
        # 反向传播和优化
        optimizer.zero_grad()  # 在每次迭代中将梯度清零
        loss.backward()  # 反向传播,根据链式法则自动计算损失函数对每个参数的偏导数,并将这些梯度存储在参数的 .grad 属性
        optimizer.step()  # 根据优化算法更新参数

    # 检查是否收敛
    if epoch > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
        print(f"Converged at iteration {epoch}")
        break


# 可视化结果
print("斜率:", model.weight.item(), "偏移量:", model.bias.item())
# 绘制损失函数图像
plt.plot(range(len(loss_)), loss_)
plt.title('Linear Regression using SGD')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)  # 显示网格线
plt.show()

1738397089_ae580k59jf.png1738397088799.png

即,总结:

1738397138_v1fxl4yrpf.png1738397137711.png

三、 Adagrad

3.1 介绍

Python 梯度下降法(三):Adagrad Optimize-CSDN博客

学习率除一个数值,这个数值是历史上所有梯度数据的平方再开方。 g t 2 g_{t}^{2} gt2越大,学习率越小,使得学习率自适应。

假设一个参数累计历史梯度极大,那么经过计算更新这个一步之后,它的学习率反而会变小。相反的,如果一个参数累计历史梯度极小,那么经过计算更新这一步之后,它的学习率反而会变大。

缺点:累加的太快,学习率小的太快,导致最后的学习很慢。

Adagrad — PyTorch 2.6 documentation

3.2 torch 库算法

1738399503_b3eqzc4xr4.png1738399502527.png

3.3 代码示例

optimizer = optim.Adagrad(model.parameters(), lr=lr)

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

# 生成随机数据
# 生成 100 个在 [0, 2) 之间的随机数作为输入特征
x = 2 * torch.rand(100, 1)
# 生成对应的目标值,添加一些随机噪声
y = 4 + 3 * x  +  torch.randn(100, 1)

loss_ = []   # 存储历史损失值

# 定义线性模型
model = nn.Linear(1, 1)

# 定义损失函数
criterion = nn.MSELoss()

# 定义优化器,使用Adagrad,学习率设置为 0.01
lr = 0.8
optimizer = optim.Adagrad(model.parameters(), lr=lr)

# 训练模型
num_epochs = 1000
threshold = 1e-8
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(x)
    loss = criterion(outputs, y)  # 使用MES(均方误差损失)的方式计算损失值
    loss_.append(loss.item())
    
    # 反向传播和优化
    optimizer.zero_grad()  # 在每次迭代中将梯度清零
    loss.backward()  # 反向传播,根据链式法则自动计算损失函数对每个参数的偏导数,并将这些梯度存储在参数的 .grad 属性
    optimizer.step()  # 根据优化算法更新参数

    # 检查是否收敛
    if epoch > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
        print(f"Converged at iteration {epoch}")
        break


# 可视化结果
print("斜率:", model.weight.item(), "偏移量:", model.bias.item())
# 绘制损失函数图像
plt.plot(range(len(loss_)), loss_)
plt.title('Linear Regression using Adagrad')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)  # 显示网格线
plt.show()

1738402571_k9dmmhkrpk.png1738402570785.png

四、 Adadelta

4.1 介绍

Python 梯度下降法(四):Adadelta Optimize-CSDN博客

Adadelta 是正对 Adagrad 学习速率衰减过快问题做出的改进。改进思路和RMSProp很像,但是其背后是基于一次梯度近似代替二次梯度的思想。Adagrad 会累加之前所有的梯度平方,而 Adadelta 只累加固定大小的项,并且也不直接存储这些项,仅仅是近似计算对应的平均值

Adadelta — PyTorch 2.6 documentation

4.2 torch 库算法

1738401969_glujj4vtqo.png1738401968761.png

4.3 代码示例

optimizer = optim.Adadelta(model.parameters(), lr=lr)

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

# 生成随机数据
# 生成 100 个在 [0, 2) 之间的随机数作为输入特征
x = 2 * torch.rand(100, 1)
# 生成对应的目标值,添加一些随机噪声
y = 4 + 3 * x  +  torch.randn(100, 1)

loss_ = []   # 存储历史损失值

# 定义线性模型
model = nn.Linear(1, 1)

# 定义损失函数
criterion = nn.MSELoss()

# 定义优化器,Adadelta
lr = 2
optimizer = optim.Adadelta(model.parameters(), lr=lr)  # 衰减率默认为0.9


# 训练模型
num_epochs = 1000
threshold = 1e-8
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(x)
    loss = criterion(outputs, y)  # 使用MES(均方误差损失)的方式计算损失值
    loss_.append(loss.item())
    
    # 反向传播和优化
    optimizer.zero_grad()  # 在每次迭代中将梯度清零
    loss.backward()  # 反向传播,根据链式法则自动计算损失函数对每个参数的偏导数,并将这些梯度存储在参数的 .grad 属性
    optimizer.step()  # 根据优化算法更新参数

    # 检查是否收敛
    if epoch > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
        print(f"Converged at iteration {epoch}")
        break


# 可视化结果
print("斜率:", model.weight.item(), "偏移量:", model.bias.item())
# 绘制损失函数图像
plt.plot(range(len(loss_)), loss_)
plt.title('Linear Regression using Adadelta')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)  # 显示网格线
plt.show()

1738403310_yufd184q5w.png1738403309375.png

五、RMSProp

5.1 介绍

Python 梯度下降法(二):RMSProp Optimize-CSDN博客

Adagrad 根据平方梯度的整个历史来收缩学习率,可能使得学习率在达到局部最小值之前就变得太小而难以继续训练;

RMSProp 使用指数衰减平均以丢弃遥远的历史,使其能够在找到某个“凸”结构后快速收敛;此外,RMSProp 还加入了一个超参数 ρ \rho ρ用于控制衰减率。

RMSProp 主要思想:使用指数加权移动平均的方法计算累积梯度,以丢弃遥远的梯度历史信息(让距离当前越远的梯度的缩减下学习率的权重越小)

衰减率表明的是只是最近的梯度平方有意义,而很久以前的梯度基本上会被遗忘。

RMSprop — PyTorch 2.6 documentation

5.2 torch 库算法

1738402036_zg911c2sx8.png1738402035850.png

5.3 代码示例

optimizer = optim.RMSprop(model.parameters(), lr=lr)

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

# 生成随机数据
# 生成 100 个在 [0, 2) 之间的随机数作为输入特征
x = 2 * torch.rand(100, 1)
# 生成对应的目标值,添加一些随机噪声
y = 4 + 3 * x  +  torch.randn(100, 1)

loss_ = []   # 存储历史损失值

# 定义线性模型
model = nn.Linear(1, 1)

# 定义损失函数
criterion = nn.MSELoss()

# 定义优化器,RMSprop
lr = 0.01
optimizer = optim.RMSprop(model.parameters(), lr=lr)  # 衰减率默认为0.99


# 训练模型
num_epochs = 1000
threshold = 1e-8
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(x)
    loss = criterion(outputs, y)  # 使用MES(均方误差损失)的方式计算损失值
    loss_.append(loss.item())
    
    # 反向传播和优化
    optimizer.zero_grad()  # 在每次迭代中将梯度清零
    loss.backward()  # 反向传播,根据链式法则自动计算损失函数对每个参数的偏导数,并将这些梯度存储在参数的 .grad 属性
    optimizer.step()  # 根据优化算法更新参数

    # 检查是否收敛
    if epoch > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
        print(f"Converged at iteration {epoch}")
        break


# 可视化结果
print("斜率:", model.weight.item(), "偏移量:", model.bias.item())
# 绘制损失函数图像
plt.plot(range(len(loss_)), loss_)
plt.title('Linear Regression using RMSprop')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)  # 显示网格线
plt.show()

1738403341_mxolya5yrg.png1738403340437.png

六、Adam

6.1 介绍

Python 梯度下降法(五):Adam Optimize-CSDN博客

Adam 算法的本质:其实就是 Momentum + RMSProp 的结合,让后再修正其偏差。Adam 对梯度的一阶和二阶都进行了估计与偏差修正,使用梯度的一阶矩估计和二阶矩估计来动态调整每个参数的学习率(参数更新的频率)。

缺点:Adam 优化器在权重衰减的处理上存在问题,Adam 算法弱化了 L2 范数正则化的作用,导致模型过拟合或者训练效果不佳。

Adam — PyTorch 2.6 documentation

6.2 torch 库算法

1738402095_jsyfniov4n.png1738402094684.png

6.3 代码示例

optimizer = optim.Adam(model.parameters(), lr=lr)

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

# 生成随机数据
# 生成 100 个在 [0, 2) 之间的随机数作为输入特征
x = 2 * torch.rand(100, 1)
# 生成对应的目标值,添加一些随机噪声
y = 4 + 3 * x  +  torch.randn(100, 1)

loss_ = []   # 存储历史损失值

# 定义线性模型
model = nn.Linear(1, 1)

# 定义损失函数
criterion = nn.MSELoss()

# 定义优化器,Adam
lr = 0.03
optimizer = optim.Adam(model.parameters(), lr=lr)  # 默认beta: 0.9, 0.99


# 训练模型
num_epochs = 1000
threshold = 1e-8
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(x)
    loss = criterion(outputs, y)  # 使用MES(均方误差损失)的方式计算损失值
    loss_.append(loss.item())
    
    # 反向传播和优化
    optimizer.zero_grad()  # 在每次迭代中将梯度清零
    loss.backward()  # 反向传播,根据链式法则自动计算损失函数对每个参数的偏导数,并将这些梯度存储在参数的 .grad 属性
    optimizer.step()  # 根据优化算法更新参数

    # 检查是否收敛
    if epoch > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
        print(f"Converged at iteration {epoch}")
        break


# 可视化结果
print("斜率:", model.weight.item(), "偏移量:", model.bias.item())
# 绘制损失函数图像
plt.plot(range(len(loss_)), loss_)
plt.title('Linear Regression using Adam')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)  # 显示网格线
plt.show()

1738403373_3gizmxim3f.png1738403372944.png

七、Nadam

7.1 介绍

Python 梯度下降法(六):Nadam Optimize-CSDN博客

Nadam 类似带有 Nesterov 动量项的Adam

其对学习率有了更强的约束,同时对梯度的会更新也有更直观的影响。
NAdam — PyTorch 2.6 documentation

7.2 torch 库算法

1738402164_wl1if5cllj.png1738402163199.png

7.3 代码示例

optimizer = optim.NAdam(model.parameters(), lr=lr)

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt

# 生成随机数据
# 生成 100 个在 [0, 2) 之间的随机数作为输入特征
x = 2 * torch.rand(100, 1)
# 生成对应的目标值,添加一些随机噪声
y = 4 + 3 * x  +  torch.randn(100, 1)

loss_ = []   # 存储历史损失值

# 定义线性模型
model = nn.Linear(1, 1)

# 定义损失函数
criterion = nn.MSELoss()

# 定义优化器,NAdam
lr = 0.03
optimizer = optim.NAdam(model.parameters(), lr=lr)  # 默认beta: 0.9, 0.99


# 训练模型
num_epochs = 1000
threshold = 1e-8
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(x)
    loss = criterion(outputs, y)  # 使用MES(均方误差损失)的方式计算损失值
    loss_.append(loss.item())
    
    # 反向传播和优化
    optimizer.zero_grad()  # 在每次迭代中将梯度清零
    loss.backward()  # 反向传播,根据链式法则自动计算损失函数对每个参数的偏导数,并将这些梯度存储在参数的 .grad 属性
    optimizer.step()  # 根据优化算法更新参数

    # 检查是否收敛
    if epoch > 1 and abs(loss_[-1] - loss_[-2]) < threshold:
        print(f"Converged at iteration {epoch}")
        break


# 可视化结果
print("斜率:", model.weight.item(), "偏移量:", model.bias.item())
# 绘制损失函数图像
plt.plot(range(len(loss_)), loss_)
plt.title('Linear Regression using NAdam')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)  # 显示网格线
plt.show()

1738403168_x61wxcolyo.png1738403167350.png

八、 总结

使用torch库,我们可以比较轻松的实现梯度下降法的大部分算法。

1738401881_vtkr8evsm9.png1738401880447.png

九、相关链接

Python 梯度下降法合集:

  • Python 梯度下降法(一):Gradient Descent-CSDN博客
  • Python 梯度下降法(二):RMSProp Optimize-CSDN博客
  • Python 梯度下降法(三):Adagrad Optimize-CSDN博客
  • Python 梯度下降法(四):Adadelta Optimize-CSDN博客
  • Python 梯度下降法(五):Adam Optimize-CSDN博客
  • Python 梯度下降法(六):Nadam Optimize-CSDN博客
  • Python 梯度下降法(七):Summary-CSDN博客

http://www.kler.cn/a/529038.html

相关文章:

  • oracle: 多表查询之联合查询[交集intersect, 并集union,差集minus]
  • Doki Doki Mods Maker小指南
  • Java篇之继承
  • C# 环境:深入探讨与优化
  • 【题解】AtCoder Beginner Contest ABC391 D Gravity
  • 图论——最小生成树
  • 第一个Python程序
  • 深入了解 SSRF 漏洞:原理、条件、危害
  • 2021 年 12 月大学英语四级考试真题(第 1 套)——纯享题目版
  • 使用frp访问内网web、ssh和隧道搭建
  • 本地部署 DeepSeek-R1:简单易上手,AI 随时可用!
  • 85.[1] 攻防世界 WEB easyphp
  • Java小白入门教程:ArrayList
  • (超实用教程)利用MSF制作exe程序木马
  • javaSE.Object类
  • Web_php_unserialize
  • 代码随想录-训练营-day16
  • MongoDB 删除文档
  • DeepSeek回答禅宗三重境界重构交易认知
  • 项目集成Spring Security认证部分
  • 深入解析 C++ 字符串处理:提取和分割的多种方法
  • 14JavaWeb——SpringBoot原理
  • JWT入门
  • JAVA实战开源项目:甘肃非物质文化网站(Vue+SpringBoot) 附源码
  • leetcode——验证二叉搜索树(java)
  • 17.2 图形绘制6