五十一.DQN原理和实战

news2025/7/19 12:24:05

值函数近似法

经典强化学习方法的共同点是它们的求解过程都要维持一个值函数表格,策略函数也可以通过一个表格来表示,所以也称这些方法为表格法表格法要求状态空间和动作空间都是离散的,这类强化学习任务只占所有强化学习任务的很小一部分,大部分强化学习任务具有多维连续状态和动作空间,用经典强化学习方法很难求解。其次,表格的表征容量也是有限的,即使强化学习任务的状态和动作空间离散,如果状态-动作空间极大,则表格法也无能为力。
其实,表格只是值函数和策略函数的一种表征方式,适用于小规模离散情况,对于大规模或连续情况,可以用一个复杂函数模型来表征,例如用深度神经网络来表征值函数或策略函数,这正是深度强化学习的由来。
本章考虑状态空间连续、动作空间离散的强化学习任务。假设环境存在明确的初始状态和终止状态,并且可在有限步交互后达到终止状态,则称这种强化学习任务为有局的(Episodic)。从任何一个初始状态出发,经过有限次交互后到达终止状态的过程称为一局(Episode)。

1.线性值函数近似算法

状态空间连续的有局强化学习任务显然不能使用表格法求解。虽然也可以将连续状态空间离散化,但这容易造成“维数灾难”,并且离散化后精度也不能得到保证。在经典强化学习中,Q值矩阵的本质是一个将状态-动作对映射到实数域的离散函数,对于连续状态空间问题,可以用一个函数来近似这个映射关系,这个函数可以是线性函数、非线性函数、神经网络等。

1.1线性值函数近似时序差分算法

设环境的状态空间为S,动作空间为A,称映射:
ϕ : S ∗ A → R l \phi :S*A\to R^{l} ϕ:SARl
状态-动作特征函数,它将环境的状态-动作对映射到一个抽象的特征空间。
假设状态空间是n维空间,即:
s = ( s 1 , s 2 , s 3 , . . . , s n ) ∈ R n s=(s_{1},s_{2},s_{3},...,s_{n})\in R^{n} s=(s1,s2,s3,...,sn)Rn
动作空间是有限且离散的,一个比较简单的特征函数可以写成:
ϕ ( s , a i ) ≜ ( s 1 , s 2 , … , s n , 0 , 1 , 0 , . . . , 0 ) T \phi (s,a_{i})\triangleq (s_{1},s_{2},\dots ,s_{n},0,1,0,...,0)^{T} ϕ(s,ai)(s1,s2,,sn,0,1,0,...,0)T
其中, s i s_{i} si表示第i种状态,(0,…,0,1,0,…,0)是指将 a i a_{i} ai转化成One-Hot向量。
在策略 π \pi π下,将动作值函数近似为状态-动作特征向量的线性函数,系数向量为 θ \theta θ,即:
Q ^ π ( s , a ; θ ) ≜ ϕ ( s , a ) ⋅ θ \hat{Q}_{\pi} (s,a;\theta )\triangleq \phi (s,a)\cdot \theta Q^π(s,a;θ)ϕ(s,a)θ
强化化学习的目标是学习近似函数系数θ,使近似线性函数的值和实际动作值 Q π ( s , a ) Q_π(s,a) Qπ(s,a)尽量接近。可以使用最小二乘期望作为损失函数,即:
L ( θ ) ≜ E π [ ( Q π ( s , a ) − Q ^ π ( s , a ; θ ) 2 ] L(\theta )\triangleq E_{\pi } [(Q_{\pi }(s,a)-\hat{Q}_{\pi} (s,a;\theta )^{2}] L(θ)Eπ[(Qπ(s,a)Q^π(s,a;θ)2]
其中, E π E_{\pi} Eπ表示根据策略 π \pi π采样而得到的平方误差的期望。
由此,强化学习的目标即可转换为:求解以 θ \theta θ为决策变量、以 L ( θ ) L(θ) L(θ)为目标函数的无约束优化问题:
arg ⁡ min ⁡ θ L ( θ ) ≜ E π [ ( Q π ( s , a ) − Q ^ π ( s , a ; θ ) 2 ] θ ∈ R l \arg\min_{\theta }L(\theta )\triangleq E_{\pi } [(Q_{\pi }(s,a)-\hat{Q}_{\pi} (s,a;\theta )^{2}]\\ \theta\in R^{l} argθminL(θ)Eπ[(Qπ(s,a)Q^π(s,a;θ)2]θRl
采用梯度下降法最小化损失函数 L ( θ ) L(θ) L(θ),损失函数关于 θ \theta θ的梯度为:
▽ θ L ( θ ) = [ ∂ L ( θ ) θ 1 , ∂ L ( θ ) θ 2 , ⋯   , ∂ L ( θ ) θ l ] T \triangledown _{\mathbf{\theta} } L(\mathbf{\theta } )= [\frac{\partial L(\mathbf{\theta } )}{\theta _{1}},\frac{\partial L(\mathbf{\theta } )}{\theta _{2}},\cdots ,\frac{\partial L(\mathbf{\theta } )}{\theta _{l}}]^{T} θL(θ)=[θ1L(θ),θ2L(θ),,θlL(θ)]T
其中
∂ L ( θ ) θ i = − E π [ 2 ( Q π ( s , a ) − Q ^ π ( s , a ; θ ) ) ϕ ( s , a ) ] \frac{\partial L(\mathbf{\theta } )}{\theta _{i}}=-E_{\pi } [2(Q_{\pi }(s,a)-\hat{Q}_{\pi} (s,a;\theta ))\phi (s,a)] θiL(θ)=Eπ[2(Qπ(s,a)Q^π(s,a;θ))ϕ(s,a)]
则单个样本的更新规则:
θ ← θ + α ( Q π ( s , a ) − Q ^ π ( s , a ; θ ) ) ϕ ( s , a ) \theta \leftarrow \theta +\alpha (Q_{\pi }(s,a)-\hat{Q}_{\pi} (s,a;\theta ))\phi (s,a) θθ+α(Qπ(s,a)Q^π(s,a;θ))ϕ(s,a)
上式不能真正用作算法迭代式,因为真实动作值 Q π ( s , a ) Q_{\pi}(s,a) Qπ(s,a)是未知的。可以借助时序差分强化学习的思想来解决这一问题,用TD目标值来近似真实动作值,即:
Q π ( s , a ) ≈ R ( s , a ) + γ Q ^ π ( s ′ , a ′ ; θ ) Q_{\pi }(s,a)\approx R(s,a)+\gamma \hat{Q}_{\pi} (s^{'},a^{'};\theta ) Qπ(s,a)R(s,a)+γQ^π(s,a;θ)
于是得到线性值函数近似法的参数更新公式:
θ ← θ + α ( R ( s , a ) + γ ϕ ( s ′ , a ′ ) ⋅ θ − ϕ ( s , a ) ⋅ θ ) ϕ ( s , a ) \theta \leftarrow \theta +\alpha (R(s,a)+\gamma \phi (s^{'},a^{'})\cdot \theta -\phi (s,a)\cdot \theta)\phi (s,a) θθ+α(R(s,a)+γϕ(s,a)θϕ(s,a)θ)ϕ(s,a)

1.2特征函数

线性值函数近似方法引起人们的兴趣不仅是因为它具有良好的收敛性质,也因为它在数据搜索和计算上的高效性,但线性值函数近似法的数值表现还取决于状态-动作特征函数。
状态-动作特征函数需要准确地描述状态-动作对的特征,它其实是为强化学习的训练过程提前准备了一些关于环境状态和动作的先验知识。一种比较简单的构造状态-动作特征向量的方式是直接将状态特征向量和动作特征向量拼接成状态-动作特征向量。
由于本章的讨论限于连续状态空间、离散动作空间的强化学习问题,离散动作一般直接使用One-Hot向量作为其特征向量,所以本节重点讨论连续状态空间的状态特征向量构造问题。如果是连续状态空间、连续动作空间强化学习问题,则只需将这些方法再应用到连续动作空间,得出连续动作的特征向量,然后将它们拼接成状态-动作特征向量。
常见线性值函数:多项式特征函数、傅里叶特征函数、粗编码、瓦片编码、径向基函数。

2.神经网络值函数近似法

对于比较复杂的动作值函数来讲,用线性函数近似显然是不够的。
用泛化能力更强的深度神经网络来近似动作值函数。
将线性函数换成深度神经网络会带来许多新的问题,例如神经网络的结构、损失函数、训练数据、训练方法等。

2.1DQN算法原理

2.1.1Q网络

将深度神经网络近似地动作值函数嵌入Q-learning算法框架就可得到Deep Q-learning算法,简称DQN。
DQN中用于近似动作值函数的深度神经网络简称Q网络。
根据强化学习任务的状态来选择,Q网络可以是任意一种神经网络:
(1)如果状态是由小规模向量来表示的,则可以选择一般前馈式深度神经网络。
(2)如果状态是图像信息,则可以选择卷积神经网络;如果状态是序列数据,则可以选择循环神经网络。
(3)如果状态是图像信息,则可以选择卷积神经网络;如果状态是序列数据,则可以选择循环神经网络。
无论选择什么网络,Q网络的输入输出结构是不变的,因此,可以将Q网络看作一个黑箱,只考虑其输入输出结构。
Q网络有以下3种输入输出结构:
(1)输入为状态s,输出为状态值 V ^ ( s ; θ ) \hat{V}(s;\theta ) V^(s;θ)
(2)输入为状态-动作对(s,a),输出为动作值 Q ^ ( s , a ; θ ) \hat{Q}(s,a;\theta ) Q^(s,a;θ)
(3)输入为状态s,输出为该状态下的所有动作值 Q ^ ( s , a 1 ; θ ) , Q ^ ( s , a 2 ; θ ) , ⋯   , Q ^ ( s , a n ; θ ) \hat{Q}(s,a_{1} ;\theta ),\hat{Q}(s,a_{2} ;\theta ),\cdots ,\hat{Q}(s,a_{n} ;\theta ) Q^(s,a1;θ),Q^(s,a2;θ),,Q^(s,an;θ)
在这里插入图片描述

2.1.2损失函数

损失函数仍然是最小二乘的期望,即:
L ( θ ) ≜ E ( s , a ) ∼ π [ ( Q π ( s , a ) − Q ^ π ( s , a ; θ ) 2 ] L(\theta )\triangleq E_{(s,a)\sim \pi } [(Q_{\pi }(s,a)-\hat{Q}_{\pi} (s,a;\theta )^{2}] L(θ)E(s,a)π[(Qπ(s,a)Q^π(s,a;θ)2]
由于不能直接计算,所以仍然使用TD目标值来近似真实动作值,即:
Q π ( s , a ) ≈ R ( s , a ) + γ Q ^ π ( s ′ , a ′ ; θ ) Q_{\pi }(s,a)\approx R(s,a)+\gamma \hat{Q}_{\pi} (s^{'},a^{'};\theta ) Qπ(s,a)R(s,a)+γQ^π(s,a;θ)

2.1.3经验回放技术

经验回放技术是DQN的关键技术,可以说正是因为引入了经验回放技术,才能使深度学习和强化学习有机结合。
深度学习是监督学习,需要大量带标签的训练数据,但强化学习本身的机制并不能大量提供带标签的数据,这是将深度学习和强化学习结合的难点。
经验回放技术将历史经验数据存放在一个经验回放池中,这些经验数据通过计算整理,可以作为深度Q网络的训练数据使用,很好地解决了上述矛盾,达到了深度学习和强化学习的有机结合。
Q网络的输入是状态-动作对 ( s , a ) (s,a) (s,a),输出是预测动作值 Q ^ π ( s , a ; θ ) \hat{Q}_{\pi} (s,a;\theta ) Q^π(s,a;θ),所以Q网络的训练数据也应该由状态-动作对和其对应的真实动作值组成,真实动作值使用TD目标值来近似真实动作值估计。
在DQN的训练过程中,智能体每次与环境交互都会产生一段MDP序列 ( s , a , R , s ′ , e n d ) (s,a,R,s′,end) (s,a,R,s,end)表示在状态 s s s下执行动作 a a a,环境状态转移到 s ′ s′ s,并且反馈即时奖励 R R R和交互回合是否结束的指示end,令:
y ≜ { R , i f   e n d = T r u e R + γ Q ^ π ( s ′ , a ′ ; θ ) , i f   e n d = F a l s e y\triangleq \left\{\begin{matrix} R,&if\space end=True\\ R+\gamma \hat{Q}_{\pi} (s^{'},a^{'};\theta ),&if \space end=False \end{matrix}\right. y{R,R+γQ^π(s,a;θ),if end=Trueif end=False
y y y就是状态-动作对 ( s , a ) (s,a) (s,a)对应的真实动作值 Q ( s , a ) Q(s,a) Q(s,a)的估计,称 y y y为TD目标值。这样,在当前时刻,之前交互生成的每段MDP序列 ( s , a , R , s ′ , e n d ) (s,a,R,s′,end) (s,a,R,s,end)都可以生成一个训练数据 ( ( s , a ) , y ) ((s,a),y) ((s,a)y),这些训练数据又可以用来训练当前Q网络。
经验回放技术就是指将历史上交互生成的MDP序列片段存储起来,然后在当前时刻转化成训练数据,并用这些训练数据来训练当前Q网络的过程。
在实际应用中,经验回放池是从无到有的,当在回放池中的训练数据还很少时(小于一个批量)是不能进行Q网络训练的,此时就要继续搜集经验数据,而暂时不开始训练Q网络,但随着交互的进行,回放池中的数据会一直增加。一般会设置一个回放池最大容量,当超出最大容量时,就将最初搜集的训练数据删除。删除最初的数据是因为随着训练的进行,越往后搜集到的经验数据质量越高。

2.1.4训练Q网络

训练Q网络实际上是求解优化问题:
arg ⁡ min ⁡ θ L ( θ ) ≜ E π [ ( Q π ( s , a ) − Q ^ π ( s , a ; θ ) 2 ]   \arg\min_{\theta }L(\theta )\triangleq E_{\pi } [(Q_{\pi }(s,a)-\hat{Q}_{\pi} (s,a;\theta )^{2}]\ argθminL(θ)Eπ[(Qπ(s,a)Q^π(s,a;θ)2] 
在深度学习中,我们使用批量(Batch)数据来估计均值,再考虑到式TD目标值对 Q ( s , a ) Q(s,a) Q(s,a)的近似估计,上述优化公式改写为:
arg ⁡ min ⁡ θ L θ ( θ ) ≜ 1 B ∑ i = 1 B ( y i − Q ^ π ( s , a ; θ ) ) 2 \arg\min _{\theta }L_{\theta }(\theta )\triangleq \frac{1}{B} \sum_{i=1}^{B} (y_{i}-\hat{Q}_{\pi} (s,a;\theta))^{2} argθminLθ(θ)B1i=1B(yiQ^π(s,a;θ))2
其中,B为批量大小(Batch Size)。基于随机梯度下降的参数 θ θ θ更新公式为:
θ ← θ + α 1 B ∑ i = 1 B ( y i − Q ^ π ( s , a ; θ ) ) ▽ θ Q ^ π ( s , a ; θ ) \theta \leftarrow \theta +\alpha \frac{1}{B} \sum_{i=1}^{B} (y_{i}-\hat{Q}_{\pi} (s,a;\theta))\triangledown_{\theta} \hat{Q}_{\pi} (s,a;\theta) θθ+αB1i=1B(yiQ^π(s,a;θ))θQ^π(s,a;θ)
实际上,在Q网络训练时并不直接使用上述迭代式,而是通过神经网络的误差反向传播机制逐层更新权重参数和偏置参数。

2.2DQN算法流程

通常认为DQN算法有两个版本:DQN和DQN-2015。
DQN-2015主要对DQN的经验回放技术做了一些改进。

2.2.1DQN

在这里插入图片描述

2.2.2DQN-2015

在前一章节,TD目标值和预测动作值的计算使用了相同的Q网络,这相当于用由Q网络自身产生的数据来训练自己,导致预测值和目标值关联性太强,不利于算法的收敛和模型泛化能力的提高。
在Volodymyr Mnih等学者于2015年发表的论文中,他们对DQN算法的这一缺陷进行了优化,提出了双Q网络的构想。双Q网络的核心思想是使用两个结构相同但参数不同的Q网络来分别负责动作值预测和TD目标值计算任务
负责动作值预测的Q网络叫作预测网络或当前网络,负责TD目标值计算的Q网络叫作目标网络
预测网络和目标网络的网络结构相同,但参数更新频率和方式不同。预测网络在每个时间步都进行参数更新,更新方式是常规的Q网络训练,而目标网络每隔若干个时间步才进行参数更新,更新方式是直接复制预测网络的当前参数。
双Q网络的设计将动作值预测和TD目标值计算分离,使训练输出和预测输出的相关性大幅降低,有效地解决了训练过程的稳定性和收敛性问题。
在这里插入图片描述

3.DQN案例(CartPole-v0倒立钟摆)

import torch
from torch import nn
import numpy as np
import gym
import matplotlib.pyplot as plt

if torch.cuda.is_available():
    device = 'cuda'
else:
    device = 'cpu'

BATCH_SIZE = 32  # 批处理数据量
LR = 0.01  # 学习率
EPISILON = 0.9  # 贪婪阈值
GAMMA = 0.9  # 折扣系数
TARGET_REPLACE_ITER = 100  # 目标网络跟新频率
MEMORY_CAPACITY = 500  # 经验回放池大小
env = gym.make('CartPole-v1', render_mode='human')
STATE_SIZE = env.observation_space.shape[0]  # 状态维度
ACTION_SIZE = env.action_space.n  # 动作维度


# 定义Q网络
class QNet(nn.Module):
    def __init__(self):
        super(QNet, self).__init__()
        self.flatten = nn.Flatten()
        self.linear_ReLU_stack = nn.Sequential(
            nn.Linear(STATE_SIZE, 20),
            nn.ReLU(),
            nn.Linear(20, 20),
            nn.ReLU(),
            nn.Linear(20, ACTION_SIZE)
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_ReLU_stack(x)
        return logits


# 定义DQN2015
class DQN2015(object):
    def __init__(self):
        self.eval_net, self.target_net = QNet().to(device), QNet().to(device)  # 评价网络和目标网络
        self.learn_step_counter = 0  # 学习步数记录
        self.memory_counter = 0  # 回放池存储量
        # 存储空间容量:(s,a,r,s_next),a,r为标量,s,s_next是维度STATE_SIZE的向量
        self.memory = np.zeros((MEMORY_CAPACITY, STATE_SIZE * 2 + 2))
        self.optimazer = torch.optim.Adam(self.eval_net.parameters(), lr=LR)  # 优化器
        self.loss_func = nn.MSELoss().to(device)  # 均方误差损失函数

    def choose_action(self, x):  # 动作选择策略
        x = torch.unsqueeze(torch.FloatTensor(x), 0).to(device)
        action_value = self.eval_net(x)  # 神经网络模拟的动作值
        # e-greedy动作选择:小于阈值,贪婪;大于阈值,随机
        if np.random.uniform() < EPISILON:
            action_value = self.eval_net(x)  # 神经网络模拟的动作值
            action = torch.max(action_value, 1)[1].data.cpu().numpy()
            action = action[0]
        else:
            action = np.random.randint(0, ACTION_SIZE)
        return action

    def store_transition(self, s, a, r, s_next):
        transition = np.hstack((s, a, r, s_next))
        # 如果没有满,把数据插入index后,如果满了,覆盖之前的旧数据
        index = self.memory_counter % MEMORY_CAPACITY  # 新数据在
        self.memory[index, :] = transition
        self.memory_counter += 1

    def learn(self):
        # 如果到达目标网络更新轮数,将评价网络的参数给目标网络
        if self.learn_step_counter % TARGET_REPLACE_ITER == 0:
            self.target_net.load_state_dict(self.eval_net.state_dict())
        self.learn_step_counter += 1

        # 在[0,MEMORY_CAPACITY)内随机抽取BATCH_SIZE个数,可能会重复
        sample_index = np.random.choice(MEMORY_CAPACITY, BATCH_SIZE)
        b_memory = self.memory[sample_index, :]

        # 以BATCH_SIZE为一组,分别取出s,a,r,s_next的值
        b_s = torch.FloatTensor(b_memory[:, :STATE_SIZE]).to(device)
        b_a = torch.LongTensor(b_memory[:, STATE_SIZE:STATE_SIZE + 1]).to(device)
        b_r = torch.FloatTensor(b_memory[:, STATE_SIZE + 1:STATE_SIZE + 2]).to(device)
        b_s_next = torch.FloatTensor(b_memory[:, -STATE_SIZE:]).to(device)

        q_eval = self.eval_net(b_s).gather(1, b_a)  # 将b_a中动作编号作为索引,取出对应动作的Q值(动作预测值)
        q_next = self.target_net(b_s_next).detach()  # 取出目标网络对应的next动作q值
        q_target = b_r + GAMMA * q_next.max(1)[0].view(BATCH_SIZE, 1)  # TD目标值
        loss = self.loss_func(q_eval, q_target)
        self.optimazer.zero_grad()
        loss.backward()
        self.optimazer.step()


if __name__ == '__main__':
    dqn = DQN2015()
    reward_list = []

    for i in range(500):
        s, _ = env.reset()
        episode_reward_sum = 0
        print(f'*********************************第{i}轮****************************')
        while True:
            env.render()
            a = dqn.choose_action(s)
            s_next,r,done,info,_ = env.step(a)

            # 可以修改reward值让其训练速度加快
            x, x_dot, theta, theta_dot = s_next
            r1 = (env.x_threshold - abs(x)) / env.x_threshold - 0.8
            r2 = (env.theta_threshold_radians - abs(theta)) / env.theta_threshold_radians - 0.5
            new_r = r1 + r2

            dqn.store_transition(s,a,new_r,s_next)
            episode_reward_sum+=r
            s = s_next

            if dqn.memory_counter>MEMORY_CAPACITY:
                dqn.learn()

            if done:
                print(f'episode:{i},reward_sum:{episode_reward_sum}')
                reward_list.append(episode_reward_sum)
                break
    x_list = [x for x in range(0,500)]
    plt.title('Episode Reward')
    plt.xlabel('Episode')
    plt.ylabel('Reward')
    plt.plot(x_list,reward_list)
    plt.show()

智能体可视化
在这里插入图片描述
reward曲线(可以看到,在第50轮的时候,已经开始收敛)
在这里插入图片描述

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

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

相关文章

Spring Bean的生命周期和扩展点源码解读

目录 1 Bean的生命周期2 Bean的定义、注册及创建过程3 Bean的注入过程4 Bean的销毁过程5 Bean的生命周期 1 Bean的生命周期 在Spring框架中&#xff0c;Bean对象也有着它的生命周期&#xff0c;然而对于Bean对象的生命周期&#xff0c;我们并不是很清楚&#xff0c;因为Spring帮…

学习pytorch10 神经网络-最大池化的作用

神经网络-最大池化的作用 官方文档参数说明运算演示公式最大池化 代码code 1执行结果code2执行结果 B站小土堆学习视频 https://www.bilibili.com/video/BV1hE411t7RN?p19&spm_id_frompageDriver&vd_source9607a6d9d829b667f8f0ccaaaa142fcb 官方文档 https://pytorch…

UML基础与应用之面向对象

UML&#xff08;Unified Modeling Language&#xff09;是一种用于软件系统建模的标准化语言&#xff0c;它使用图形符号和文本来描述软件系统的结构、行为和交互。在面向对象编程中&#xff0c;UML被广泛应用于软件系统的设计和分析阶段。本文将总结UML基础与应用之面向对象的…

34.KMP算法,拒绝暴力美学

概述 今天我们来聊一聊字符串匹配的问题。 比如有字符串str1 “豫章故那&#xff0c;洪都新府。星分翼轸&#xff0c;地接衡庐。襟三江而带五湖&#xff0c;控蛮荆而引瓯越。”&#xff0c;字符串str2 “襟三江而带五湖”。 现要判断str1是否含有str2&#xff0c;如果有则的…

zabbix介绍及部署(五十一)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、zabbix的基本概述 二、zabbix的构成 1、Server 2、web页面 3、数据库 4、proxy 5、Agent 三、zabbix的监控对象 四、zabbix的常用术语 五、zabbix的工作流程 六、za…

区域气象-大气化学在线耦合模式(WRF/Chem)在大气环境领域实践技术应用

大气污染是工农业生产、生活、交通、城市化等方面人为活动的综合结果&#xff0c;同时气象因素是控制大气污染的关键自然因素。大气污染问题既是局部、当地的&#xff0c;也是区域的&#xff0c;甚至是全球的。本地的污染物排放除了对当地造成严重影响外&#xff0c;同时还会在…

基于docker进行Grafana + prometheus实现服务监听

基于docker进行Grafana Prometheus实现服务监听 Grafana安装Prometheus安装Jvm监控配置 Grafana安装 docker pull grafana/grafanamkdir /server/grafanachmod 777 /server/grafanadocker run -d -p 3000:3000 --namegrafana -v /server/grafana:/var/lib/grafana grafana/gr…

Databend 开源周报第 111 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 理解 SHARE END…

9、DVWA——XSS(Stored)

文章目录 一、存储型XSS概述二、low2.1 源码分析2.2 通关分析 三、medium3.1 源码分析3.2 通关思路 四、high4.1 源码分析4.2 通关思路 一、存储型XSS概述 XSS&#xff0c;全称Cross Site Scripting&#xff0c;即跨站脚本攻击&#xff0c;某种意义上也是一种注入攻击&#xff…

MATLAB中filloutliers函数用法

目录 语法 说明 示例 在向量中对离群值进行插值 使用均值检测和最邻近值填充方法 使用移窗检测法 填充矩阵行中的离群值 指定离群值位置 返回离群值阈值 filloutliers函数功能是检测并替换数据中的离群值。 语法 B filloutliers(A,fillmethod) B filloutliers(A,f…

Paper Reading: RSPrompter,基于视觉基础模型的遥感实例分割提示学习

目录 简介目标工作重点方法实验总结 简介 题目&#xff1a;《RSPrompter: Learning to Prompt for Remote Sensing Instance Segmentation based on Visual Foundation Model 》&#xff0c;基于视觉基础模型的遥感实例分割提示学习 日期&#xff1a;2023.6.28 单位&#xf…

接口测试学习

1、curl 命令 无参&#xff1a;curl -X POST -H"Authorization: abcdefghijklmn" https://xxx.xxxxx.com/xxxx 有参&#xff1a;curl -X POST -H"Authorization:abcdefghijklmn " -H"Content-Type:application/json" https://xxx.xxxxx.com/…

synchronized锁详解

本文主要是对synchronized使用各个情况&#xff0c;加解锁底层原理的讲解 一&#xff0c;重量级锁 对象头 讲重量级锁之前&#xff0c;先了解一下一个对象的构成&#xff0c;一个对象是由对象头和对象体组成的&#xff0c;本文主要讲对象头&#xff0c;对象体其实就是对象的…

核心实验21_BGP高级(了解)(配置略)_ENSP

项目场景&#xff1a; 核心实验21_BGP基础_ENSP 通过bgp实现省市互通。 实搭拓扑图&#xff1a; 具体操作&#xff1a; 其他基础配置略&#xff08;接口地址&#xff0c;ospf&#xff09; 1.BGP邻居建立&#xff1a; R1: [R1]bgp 200 [R1-bgp]peer 10.2.2.2 as-number 200 …

Java高级之File类、节点流、缓冲流、转换流、标准I/O流、打印流、数据流

第13章 IO流 文章目录 一、File类的使用1.1、如何创建File类的实例1.2、常用方法1.2.1、File类的获取功能1.2.2、File类的重命名功能1.2.3、File类的判断功能1.2.4、File类的创建功能1.2.5、File类的删除功能 二、IO流原理及流的分类2.1、Java IO原理2.2、流的分类/体系结构 三…

LINUX内核启动流程-2

向32位模式转变,为main函数的调用做准备 1、关中断并将system移动到内存地址起始位置0x00000 1.1 关中断:将CPU的标志寄存器(EFLAGS)中的中断允许标志(IF)置0。 main函数中能够适应保护模式的中断服务体系被重建完毕才会打开中断,而那时候响应中断的服务程序将不再是…

【数据结构与算法】不就是数据结构

前言 嗨喽小伙伴们你们好呀&#xff0c;好久不见了,我已经好久没更新博文了&#xff01;之前因为实习没有时间去写博文&#xff0c;现在已经回归校园了。我看了本学期的课程中有数据结构这门课程&#xff08;这么课程特别重要&#xff09;&#xff0c;因为之前学过一点&#xf…

天宇微纳芯片测试软件如何测试电源芯片的持续电流?

持续电流&#xff08;连续电流&#xff09;是指元器件在工作状态下内部电流持续流动的状态&#xff0c;一般都是用于对元器件允许连续通过电流限制的一种描述。比如电源芯片允许的持续电流&#xff0c;就表示该芯片可连续通过的最大电流。 通过上面的描述我们可以知道&#xff…

爬虫 — 验证码反爬

目录 一、超级鹰二、图片验证模拟登录1、页面分析1.1、模拟用户正常登录流程1.2、识别图片里面的文字 2、代码实现 三、滑块模拟登录1、页面分析2、代码实现&#xff08;通过对比像素获取缺口位置&#xff09; 四、openCV1、简介2、代码3、案例 五、selenium 反爬六、百度智能云…