PyTorch深度学习实战(45)——强化学习

PyTorch深度学习实战(45)——强化学习

    • 0. 前言
    • 1. 强化学习基础
      • 1.1 基本概念
      • 1.2 马尔科夫决策过程
      • 1.3 目标函数
      • 1.4 智能体学习过程
    • 2. 计算状态值
    • 3. 计算状态-动作值
    • 4. Q 学习
      • 4.1 Q 值
      • 4.2 Gym环境
      • 4.3 构建 Q 表
      • 4.4 探索-利用策略
    • 小结
    • 系列链接

0. 前言

强化学习是当前人工智能领域的研究热点问题,强化学习主要通过考察智能体与环境的相互作用,得到策略模型、优化策略并最大化累积回报的过程。强化学习具有巨大的研究价值和应用潜力,是实现通用人工智能的关键技术。本文首先介绍强化学习的基本原理,包括马尔可夫决策过程、价值函数、探索-利用问题等,然后介绍经典的强化学习算法,最后使用 PyTorch 实现在游戏中模拟强化学习算法。

1. 强化学习基础

1.1 基本概念

强化学习 (Reinforcement learning, RL) 是机器学习中的一个重要领域,其核心思想在于最大化智能体在相应环境中得到的累计奖励,重点研究智能体应该如何在给定环境状态下执行动作来最大化累积奖励,从而学习能够令智能体完成目标任务的最佳策略。智能体 (agent) 在每个时刻可以与环境 (environment) 交互,交互过程如下所示:

智能体

每次交互,都可以得到一个具有多维特征的观察 (observation),根据观察可以得到状态 (state),智能体根据状态选择相应的动作 (action),环境会对 agent 的不同动作给予不同奖励 (reward),从状态到动作的映射函数称为策略 (policy)。通过重复执行此过程,就可以得到令累计奖励最大化的最佳策略。
例如,在象棋对战中,计算机是一个已经学习或正在学习如何下棋的智能体,游戏的规则设置构成环境,移动棋子(执行动作)后,棋盘中棋子的位置(状态)发生了变化,游戏结束时,智能体根据游戏结果获得奖励,智能体的目标是最大化奖励。
在智能体 (agent1) 与人类进行游戏过程中,它可以进行的游戏是有限的(取决于人类水平),这可能会成为智能体的学习瓶颈。但是,如果 agent1 (正在学习如何游戏的智能体)可以与 agent2 对战(另一个正在学习的智能体或者一个已经能够出色进行游戏的棋类软件),从理论上讲,这些智能体就可以无限制的相互博弈,从而最大限度地提高智能体学习玩好游戏的机会。这样,通过在多次游戏上互相博弈,智能体有可能学习如何很好地解决游戏中的不同场景/状态。

1.2 马尔科夫决策过程

智能体从环境初始状态开始,根据策略模型采样某一动作,环境在动作的影响下,会从原状态改变为新状态,同时给予智能体奖励。以上过程不断重复直到达到游戏的终止状态,这个过程也称为轨迹 (trajectory),一个过程称为一个回合 (episode)。环境的当前状态通常取决于多个历史状态,计算非常复杂,为了简化计算流程,我们通常假设当前时间戳上的状态仅仅受上一状态的影响,这种性质称为马尔科夫性 (Markov Property),具有马尔科夫性的序列称为马尔科夫过程 (Markov Process)。
如果我们将执行的动作也考虑进状态转移概率,同样应用马尔科夫假设,当前状态只与上一状态和上一状态上执行的动作相关,则我们把状态和动作的有序序列叫做马尔科夫决策过程 (Markov Decision Process, MDP)。当智能体只能观察到环境的部分状态时,称为部分可观察马尔可夫决策过程 (Partially Observable Markov Decision Process , POMDP)

1.3 目标函数

智能体每次在与环境进行交互时,都会得到一个奖励,一次交互轨迹的累计奖励称为总回报 (return),但在某些环境中的奖励是十分稀疏的,例如在棋牌类游戏中,前面的动作奖励均为 0,只有游戏结束时才有表示输赢的奖励。为了权衡近期奖励与长期奖励,引入折扣率来令奖励随时间衰减。
由于环境状态转移和策略具有一定的随机性,即使使用同样的策略模型作用域同一环境,也可能产生截然不同的轨迹序列,因此强化学习的目标是最大化期望回报。

1.4 智能体学习过程

通常,智能体的学习过程如下:

  1. 最初,智能体在给定状态下采取随机动作
  2. 智能体将它在游戏中的各种状态下所采取的动作存储在内存中
  3. 然后,智能体将各种状态下的动作结果与奖励相关联
  4. 在进行多次游戏之后,智能体可以通过重播其经验将一个状态中的动作与潜在奖励相关联

2. 计算状态值

接下来,量化在给定状态下采取动作所对应的值问题,为了理解如何量化一个状态的值,定义环境和目标如下:

环境

环境是一个两行三列的网格,智能体从 start 单元格开始,如果智能体到达右下角的网格单元格,则表示目标实现,智能体得到 +1 的分数奖励;如果智能体到达其他单元格,将无法得到奖励,或者说奖励为 0。智能体可以通过向右、向左、底部或向上移动来执行动作,具体取决于动作的可行性,例如,智能体在起始网格单元格中只能向右或向下移动。
利用这些信息,我们可以计算一个单元格的值(即智能体在所处的状态)。假设从一个单元格移动到另一个单元格需要耗费一定能量,我们使用折扣因子 γ γ γ 表示负责从一个单元格移动到另一个单元格所花费的能量。此外,引入 γ γ γ 可以使智能体更快的进行学习。接下来形式化贝尔曼方程,用于计算单元格的值;

v a l u e o f a c t i o n t a k e n i n a s t a t e = r e w a r d o f m o v i n g t o t h e n e x t c e l l + γ × v a l u e o f t h e b e s t p o s s i b l e a c t i o n i n n e x t s t a t e \begin{aligned} value\ of\ action\ taken\ in\ a\ state&=reward\ of\ moving\ to\ the\ next\ cell + \\ &\gamma\times value\ of\ the\ best\ possible\ action\ in\ next\ state \end{aligned} value of action taken in a state=reward of moving to the next cell+γ×value of the best possible action in next state

根据以上等式,一旦确定了某一状态下的最佳动作,就可以计算所有单元格的值,设 γ γ γ 值为 0.9 0.9 0.9 ( γ γ γ 通常在 0.90.99 之间):

V 22 = R 23 + γ × V 23 = 1 + γ × 0 = 1 V 13 = R 23 + γ × V 23 = 1 + γ × 0 = 1 V 21 = R 22 + γ × V 22 = 0 + γ × 1 = 0.9 V 12 = R 13 + γ × V 13 = 1 + γ × 1 = 0.9 V 11 = R 12 + γ × V 12 = 1 + γ × 0.9 = 0.81 V_{22}=R_{23}+\gamma\times V_{23}=1+\gamma\times 0=1 \\ V_{13}=R_{23}+\gamma\times V_{23}=1+\gamma\times 0=1 \\ V_{21}=R_{22}+\gamma\times V_{22}=0+\gamma\times 1=0.9 \\ V_{12}=R_{13}+\gamma\times V_{13}=1+\gamma\times 1= 0.9\\ V_{11}=R_{12}+\gamma\times V_{12}=1+\gamma\times 0.9=0.81 V22=R23+γ×V23=1+γ×0=1V13=R23+γ×V23=1+γ×0=1V21=R22+γ×V22=0+γ×1=0.9V12=R13+γ×V13=1+γ×1=0.9V11=R12+γ×V12=1+γ×0.9=0.81

从以上计算中,我们可以了解如何计算给定单元格(状态)中的值,当给定该状态下的最佳动作时。对于本节所用的简单示例,计算方法如下:

状态值

得到这些值后,我们期望智能体能够遵循值增加的路径采取动作。了解了如何计算状态值后,在下一节中,我们将了解如何计算与状态-动作组合相关的值。

3. 计算状态-动作值

在上一节中,我们假设能够预先了解智能体如何获取最优动作,但这在实际场景中并不现实。在本节中,我们将学习如何确定与状态-动作组合对应的值。
如下图所示,单元格中的每个子单元格代表在该单元格中采取动作的值。最初,各种动作的单元格值如下:

环境状态

在上图中,如果智能体从 b1 单元格向右移动或从 c2 单元格向下移动,则 b1/c2 单元格的值为 1,而其他动作的值为 0;X 表示该动作不可行,因此没有与之相关联的值。在四次迭代过程中,给定状态下采取不同动作更新单元格值如下:

更新迭代
经过多次迭代,以获取使每个单元格的值最大化的最佳操作。
接下来,我们介绍如何计算第二个表 (Iteration2) 中的单元格值。以第二个表中第一行、第二列采取向下动作为例,得到的值为 0.3,当智能体采取向下行动时,它有 1/3 的机会在下一个状态下采取最优动作。因此,采取向下行动的值如下:

v a l u e o f t a k i n g d o w n w a r d a c t i o n = i m m e d i a t e r e w a r d + γ × ( 1 / 3 × 0 + 1 / 3 × 0 + 1 / 3 × 1 ) = 0 + 0.9 × 1 / 3 = 0.3 \begin{aligned} value\ of\ taking\ downward\ action &=immediate\ reward+ \gamma\times (1/3\times 0+1/3\times 0+1/3\times 1)\\ &=0+0.9\times 1/3\\ &=0.3 \end{aligned} value of taking downward action=immediate reward+γ×(1/3×0+1/3×0+1/3×1)=0+0.9×1/3=0.3

以类似的方式,我们可以获得在不同单元格中采取不同可能动作的值。

4. Q 学习

我们已经学习了如何计算所有组合的状态-动作值。从理论上讲,计算了所需要的各种状态-动作值后,就可以确定在每个状态下将采取的动作,但在复杂情况下(例如玩视频游戏),获取状态信息并不容易。为了能够方便的获取正在进行的游戏的预定义环境,可以使用 OpenAIGym 环境,使用 Gym 环境可以获取给定当前状态下采取动作后的下一状态信息。虽然,我们一直希望选择最优路径,但在某些情况下,智能体可能会陷入局部最小值。
在本节中,我们将首先介绍 Q 值,学习利用 Q-learning 计算给定状态下动作的值,并介绍如何利用 Gym 环境进行各种游戏。为了避免智能体陷入局部最小值,我们将利用探索-开发技术。

4.1 Q 值

Q 学习 (Q-learning) 中的 Q 值 (Q-value) 表示动作的质量,计算方法如下:

v a l u e o f a c t i o n t a k e n i n a s t a t e = r e w a r d o f m o v i n g t o t h e n e x t c e l l + γ × v a l u e o f t h e b e s t p o s s i b l e a c t i o n i n n e x t s t a t e value\ of\ action\ taken\ in\ a\ state=reward\ of\ moving\ to\ the\ next\ cell + \gamma\times value\ of\ the\ best\ possible\ action\ in\ next\ state value of action taken in a state=reward of moving to the next cell+γ×value of the best possible action in next state

网络需要不断更新给定状态下的状态-动作值,直到达到收敛状态,因此,可以改写以上公式:

v a l u e o f a c t i o n t a k e n i n a s t a t e = V a l u e o f a c t i o n t a k e n i n a s t a t e + 1 × ( r e w a r d o f m o v i n g t o t h e n e x t c e l l + γ × V a l u e o f t h e b e s t p o s s i b l e a c t i o n i n n e x t s t a t e − V a l u e o f a c t i o n t a k e n i n a s t a t e ) \begin{aligned} value\ of\ action\ taken\ in\ a\ state &= Value\ of\ action\ taken\ in\ a\ state + \\ & 1\times (reward\ of\ moving\ to\ the\ next\ cell+\\ & \gamma\times Value\ of\ the\ best\ possible\ action\ in\ next\ state-\\ & Value\ of\ action\ taken\ in\ a\ state) \end{aligned} value of action taken in a state=Value of action taken in a state+1×(reward of moving to the next cell+γ×Value of the best possible action in next stateValue of action taken in a state)

在以上等式中,将 1 替换为学习率,以便可以更稳定的更新在某个状态下采取的动作的值:

v a l u e o f a c t i o n t a k e n i n a s t a t e = V a l u e o f a c t i o n t a k e n i n a s t a t e + l e a r n i n g r a t e × ( r e w a r d o f m o v i n g t o t h e n e x t c e l l + γ × V a l u e o f t h e b e s t p o s s i b l e a c t i o n i n n e x t s t a t e − V a l u e o f a c t i o n t a k e n i n a s t a t e ) \begin{aligned} value\ of\ action\ taken\ in\ a\ state &= Value\ of\ action\ taken\ in\ a\ state + \\ & learning\ rate\times (reward\ of\ moving\ to\ the\ next\ cell+\\ & \gamma\times Value\ of\ the\ best\ possible\ action\ in\ next\ state-\\ & Value\ of\ action\ taken\ in\ a\ state) \end{aligned} value of action taken in a state=Value of action taken in a state+learning rate×(reward of moving to the next cell+γ×Value of the best possible action in next stateValue of action taken in a state)

根据以上 Q 值的正式定义,在下一节中,我们将介绍 Gym 环境以及如何获取 Q 表(存储在各个状态下采取各种动作的值的信息),从而得出给定状态下的最优动作。

4.2 Gym环境

在本节中,我们将介绍 Gym 环境,并通过进行 Frozen Lake 游戏了解 Gym 环境及其提供的常用函数。

(1) 导入相关库:

import numpy as np
import gym
import randomfrom gym import envs

(2) 查看 Gym 环境中包含的游戏:

print(envs.registry.all())

以上代码将打印以下字典,其中包含 Gym 中的所有游戏:

dict_values([EnvSpec(Copy-v0), EnvSpec(RepeatCopy-v0),..., EnvSpec(MemorizeDigits-v0)])

(3) 根据指定游戏名创建游戏环境:

env = gym.make('FrozenLake-v0', is_slippery=False)

(4) 查看创建的环境:

env.render()

以上代码输出结果如下:

Frozen Lake
在上图中,智能体从 S 开始,F 表示冰面单元格,而 H 表示陷阱单元格,当智能体进入单元格 H 时,游戏终止且智能体获得的奖励为 0,游戏的目标是让智能体到达 G

(5) 查看游戏中状态空间的大小:

print(env.observation_space.n)
# 16

以上代码输出结果为 16,表示游戏包含 16 个单元格。

(6) 查看游戏中动作空间的大小:

print(env.action_space.n)
# 4

以上代码输出结果为 4,表示游戏可以采取的四种不同的动作。

(7) 在给定状态下采样随机动作:

print(env.action_space.sample())

sample() 方法根据给定状态采样将执行的动作,每个动作都有一个对应的标量值与之关联。

(8) 将环境重置为原始状态:

print(env.reset())

(9) 采样并执行一个随机动作:

print(env.step(env.action_space.sample()))
# (0, 0.0, False, {'prob': 1.0})

step() 方法根据给定动作进行游戏,并返回下一个状态、奖励、表示游戏是否已完成的标志以及其他信息。以上步骤是构建 Q 表的基础,Q 表指示在每个状态下要采取的最佳动作。

4.3 构建 Q 表

我们已经学习了如何计算各种状态-动作对的 Q 值,在本节中,将利用 Gym 环境和与之相关的各种模块填充 Q 表,在 Q 表中行表示智能体可以处于的状态,列表示智能体可以采取的动作,Q 表的值表示在给定状态下采取动作的 Q 值。使用以下策略填充 Q 表的值:

  1. 用零初始化游戏环境和Q表
  2. 采样随机行动并获取下一个状态、奖励、指示游戏是否已完成的标志以及其他附加信息
  3. 使用贝尔曼方程更新 Q 值
  4. 重复步骤 2 和步骤 3,一回合 (episode) 游戏最多有 50 步 (step)
  5. 在多个回合上重复步骤 234

(1) 初始化 FrozenLake 游戏环境:

import numpy as np
import gym
import random
env = gym.make('FrozenLake-v0', is_slippery=False)

(2) 用零值初始化 Q 表:

action_size=env.action_space.n
state_size=env.observation_space.n
qtable=np.zeros((state_size,action_size))

以上代码用于根据环境的可能操作和状态构建 Q 表,Q 表的维度为状态数乘以动作数。

(3) 随机进行多个回合,在每一回合结束时重置环境:

episode_rewards = []
for i in range(10000):state=env.reset()

每一回合最多进行 50 步:

    total_rewards = 0for step in range(50):

为了避免智能体在两个状态之间无限循环(如无限次反复向左向右移动 0),需要指定智能体可以采取的最大步数,在 FrozenLake 游戏中,我们在每个回合中最多进行 50 步,因为智能体有可能永远在两个状态之间保持振荡(例如永远循环执行左右动作)。

采样一个随机动作并使用 step 方法执行它:

        action=env.action_space.sample()new_state,reward,done,info=env.step(action)

更新对应于状态和动作的 Q 值:

        qtable[state,action]+=0.1*(reward+0.9*np.max(qtable[new_state,:])-qtable[state,action])

在以上代码中,指定学习率为 0.1,并且在更新状态-动作组合的 Q 值时考虑下一个状态的最大 Q 值 (np.max(qtable[new_state,:]))。

state 值更新为 new_state,并将奖励累积到 total_rewards

        state=new_statetotal_rewards+=reward

将奖励放入列表 (episode_rewards) 并打印 Q 表 (qtable):

    episode_rewards.append(total_rewards)
print(qtable)

以上代码可以获取给定状态下各种动作的 Q 值:

[[0.53144032 0.59048919 0.59048927 0.53144032][0.5314403  0.         0.6560992  0.59048924][0.59048911 0.72899917 0.59048896 0.65609909][0.65609902 0.         0.59048895 0.59048889][0.59048916 0.6560991  0.         0.53144029][0.         0.         0.         0.        ][0.         0.80999921 0.         0.65609884][0.         0.         0.         0.        ][0.65609904 0.         0.72899904 0.59048903][0.65609819 0.80999503 0.80999901 0.        ][0.72899598 0.89999938 0.         0.72899835][0.         0.         0.         0.        ][0.         0.         0.         0.        ][0.         0.80998461 0.89999677 0.72899056][0.8099357  0.89995735 0.99999971 0.80996359][0.         0.         0.         0.        ]]

在下一节中,我们将介绍如何利用获 Q 表。在以上代码中,我们令智能体采取随机行动。然而,在现实场景中,智能体可以学习到在给定状态下采取哪一动作可以最大化奖励,智能体就不需要再采取随机行动了,称为探索-利用策略。

4.4 探索-利用策略

在上一节中,我们探讨了在给定空间中可以采取的可能动作。在本节中,我们将学习探索-利用的概念:

  • 探索策略:在给定状态下学习需要采取什么动作
  • 利用策略:利用已经学到的知识决定在给定状态下采取哪个动作

在初始阶段,需要进行大量的探索,因为智能体最初不知道采取哪些最优动作。随着 episode 的进行,智能体随着时间推移学习到了各种状态-动作组合的 Q 值时,将使用利用策略采取能够得到高奖励的动作。据此,我们修改上一节中构建的 Q 值计算方法,引入探索-利用策略:

episode_rewards = []
epsilon=1
max_epsilon=1
min_epsilon=0.01
decay_rate=0.005
for episode in range(1000):state=env.reset()total_rewards = 0for step in range(50):exp_exp_tradeoff=random.uniform(0,1)## Exploitation:if exp_exp_tradeoff>epsilon:action=np.argmax(qtable[state,:])else:## Explorationaction=env.action_space.sample()new_state,reward,done,info=env.step(action)qtable[state,action]+=0.9*(reward+0.9*np.max(qtable[new_state,:])-qtable[state,action])state=new_statetotal_rewards+=rewardepisode_rewards.append(total_rewards)epsilon=min_epsilon+(max_epsilon-min_epsilon)*np.exp(decay_rate*episode)
print(qtable)

在以上代码中,指定随着episode的增加,使用利用策略逐渐多于探索策略。

得到 Q 表后,我们就可以利用它来确定智能体到达目的地所需采取的动作步骤:

env.reset()
for episode in range(1):state=env.reset()step=0done=Falseprint("-----------------------")print("Episode",episode)for step in range(50):env.render()action=np.argmax(qtable[state,:])print(action)new_state,reward,done,info=env.step(action) if done:print("Number of Steps",step+1)breakstate=new_state
env.close()

在以上代码中,获取智能体所处的当前状态,识别在给定状态-动作组合中能够得到最大值的动作,使用 step 方法采取动作获取智能体的新状态 new_state 并重复以上步骤,直到游戏完成/终止。

代码输出结果如下所示:

-----------------------
Episode 0SFFF
FHFH
FFFH
HFFG
1(Down)
SFFF
FHFH
FFFH
HFFG
1(Down)
SFFF
FHFH
FFFH
HFFG
2(Right)
SFFF
FHFH
FFFH
HFFG
2(Right)
SFFF
FHFH
FFFH
HFFG
1(Down)
SFFF
FHFH
FFFH
HFFG
2
Number of Steps 6

需要注意的是,在以上简单示例中,因为状态空间是离散的,因此可以构建一个 Q 表;而如果状态空间是连续的(例如,状态空间是游戏当前状态的快照图像),由于可能的状态数可能非常多,构建 Q 表将变得非常困难。在这种情况下,通常使用深度 Q 学习来解决这一问题。

小结

强化学习通过智能体与环境的交互学习最佳行为策略,通过最大化累积奖励来指导智能体的决策,是一种面向试错和反馈的学习方法,旨在解决复杂的决策问题并实现自主学习能力。强化学习在许多领域都有广泛的应用,如机器人控制、游戏策略、自动驾驶等。它能够解决具有不确定性和复杂性的问题,并在动态环境下实现自主学习和决策能力。

系列链接

PyTorch深度学习实战(1)——神经网络与模型训练过程详解
PyTorch深度学习实战(2)——PyTorch基础
PyTorch深度学习实战(3)——使用PyTorch构建神经网络
PyTorch深度学习实战(4)——常用激活函数和损失函数详解
PyTorch深度学习实战(5)——计算机视觉基础
PyTorch深度学习实战(6)——神经网络性能优化技术
PyTorch深度学习实战(7)——批大小对神经网络训练的影响
PyTorch深度学习实战(8)——批归一化
PyTorch深度学习实战(9)——学习率优化
PyTorch深度学习实战(10)——过拟合及其解决方法
PyTorch深度学习实战(11)——卷积神经网络
PyTorch深度学习实战(12)——数据增强
PyTorch深度学习实战(13)——可视化神经网络中间层输出
PyTorch深度学习实战(14)——类激活图
PyTorch深度学习实战(15)——迁移学习
PyTorch深度学习实战(16)——面部关键点检测
PyTorch深度学习实战(17)——多任务学习
PyTorch深度学习实战(18)——目标检测基础
PyTorch深度学习实战(19)——从零开始实现R-CNN目标检测
PyTorch深度学习实战(20)——从零开始实现Fast R-CNN目标检测
PyTorch深度学习实战(21)——从零开始实现Faster R-CNN目标检测
PyTorch深度学习实战(22)——从零开始实现YOLO目标检测
PyTorch深度学习实战(23)——从零开始实现SSD目标检测
PyTorch深度学习实战(24)——使用U-Net架构进行图像分割
PyTorch深度学习实战(25)——从零开始实现Mask R-CNN实例分割
PyTorch深度学习实战(26)——多对象实例分割
PyTorch深度学习实战(27)——自编码器(Autoencoder)
PyTorch深度学习实战(28)——卷积自编码器(Convolutional Autoencoder)
PyTorch深度学习实战(29)——变分自编码器(Variational Autoencoder, VAE)
PyTorch深度学习实战(30)——对抗攻击(Adversarial Attack)
PyTorch深度学习实战(31)——神经风格迁移
PyTorch深度学习实战(32)——Deepfakes
PyTorch深度学习实战(33)——生成对抗网络(Generative Adversarial Network, GAN)
PyTorch深度学习实战(34)——DCGAN详解与实现
PyTorch深度学习实战(35)——条件生成对抗网络(Conditional Generative Adversarial Network, CGAN)
PyTorch深度学习实战(36)——Pix2Pix详解与实现
PyTorch深度学习实战(37)——CycleGAN详解与实现
PyTorch深度学习实战(38)——StyleGAN详解与实现
PyTorch深度学习实战(39)——小样本学习(Few-shot Learning)
PyTorch深度学习实战(40)——零样本学习(Zero-Shot Learning)
PyTorch深度学习实战(41)——循环神经网络与长短期记忆网络
PyTorch深度学习实战(42)——图像字幕生成
PyTorch深度学习实战(43)——手写文本识别
PyTorch深度学习实战(44)——基于 DETR 实现目标检测

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

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

相关文章

悠律凝声环开放式耳机体验:强劲低音、高颜值设计

最近发现了一款潮酷的开放式耳机,不仅颜值抗打,更重要的是能在嘈杂的环境中提供给我一份宁静的沉浸式音乐体验,号称是开放音频中的重低音之王,它就是悠律凝声环开放式耳机。 这款耳机无论其外观设计、音质效果、性价比以及续航能力…

通勤数据:Comma2k19 数据集

A Commute in Data: The comma2k19 Dataset 通勤数据:Comma2k19 数据集 https://arxiv.org/pdf/1812.05752v1 Abstract— comma.ai presents comma2k19, a dataset of over 33 hours of commute in California’s 280 highway. This means 2019 segments, 1 minut…

js实现寻找数组中满足某个条件的对象,以及找到下标后,在数组中插入某个对象

let ItemIndex fileList.findIndex((item) > { return item.xxx 你要找的属性值 }); if(ItemIndex > -1){ // 代表找到了这个元素 } else { } 参考百度AI: 在JavaScript中,‌可以使用splice()方法在指定位置插入一个或多个对象到数组…

npm、cnpm、pnpm、yarn的区别

npm, cnpm, pnpm, 和 yarn 都是 JavaScript 的包管理工具,用于自动化处理包的安装、更新、配置和管理。它们之间的主要区别在于它们各自的实现方式、性能优化、以及一些特有的功能。 npm npm (Node Package Manager) 是 Node.js 的默认包管理器,也是最…

「媒体邀约」上海请媒体的费用

传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 上海无疑是最具活动的城市之一,各种大大小小的论坛、发布会、展览展会应接不暇,那么在上海做活动想邀请媒体进行宣传报道,需要多少费用呢:…

Android --- 运行时Fragment如何获取Activity中的数据,又如何将数据传递到Activity中呢?

1.通过 getActivity() 方法获取 Activity 实例: 在 Fragment 中,可以通过 getActivity() 方法获取当前 Fragment 所依附的 Activity 实例。然后可以调用 Activity 的公共方法或者直接访问 Activity 的字段来获取数据。 // 在 Fragment 中获取 Activity…

手慢无,速看︱PMO大会内部学习资料

全国PMO专业人士年度盛会 每届PMO大会,组委会都把所有演讲嘉宾的PPT印刷在了会刊里面,供大家会后回顾与深入学习。 第十三届中国PMO大会-会刊 《2024第十三届中国PMO大会-会刊》 (内含演讲PPT) 会刊:750个页码&…

代码随想录-DAY④-链表——leetcode 24 | 19 | 142

24 思路 如果 pre 的后面没有节点或者只有一个节点,则没有更多的节点需要交换, 否则,通过更新节点的指针关系交换 pre 后面的两个节点, 最后,返回新的链表的头节点 dummyhead->next。 时间复杂度:O(n) 空间复杂…

buuctf面具下的flag

细节: 这道题可能因为是vmdk的原因 导致在window上 7z无法得到全部的信息 所以最后解压要在linux系统上 解密网站 Brainfuck/Ook! Obfuscation/Encoding [splitbrain.org] 这道题010打开,可以发现里面隐藏了很多 binwalk解压 两个文件 vmdk可以直接 用7z解压 7z x flag.…

Mysql如何高效ALTER TABL

ALTER TABLE 缺点 MySQL 的ALTER TABLE 操作的性能对大表来说是个大问题。 MySQL MySQL 执行大部分修改表结构操作的方法是用新结构的 创建一个,空表从旧表中查出所有数据插入,新表然后删除旧。表这样操作可能需要花费很长,时间 如内果存不…

Flutter TabBar与TabBarView联动及获取当前点击栏目索引

TabBar还有TabBarView都是谷歌flutter官方组件库——Material组件库提供的组件,其中TabBar用于导航切换,TabBarView则是配合其切换显示的对应的视图,官网参考地址:TabBarView class - material library - Dart API。 实现一体联动…

轻松搭建RAG:澳鹏RAG开发工具

我们很高兴地宣布推出RAG开发工具,这是澳鹏大模型智能开发平台的一项新功能。此功能可帮助团队轻松创建高质量的检索增强生成 (RAG) 模型。 什么是 RAG? 检索增强生成 (RAG) 通过利用大量外部数据源(例如企业的知识库)显著增强了…

文献阅读(1)——深度强化学习求解车辆路径问题的研究综述

doi: 10.3778/j.issn.1002-8331.2210-0153 深度强化学习求解车辆路径问题的研究综述 (ceaj.org) 组合最优化问题( combinatorial optimization problem, COP ) 日常生活中常见的 COP 问题有旅行商问题(traveling sale…

数字化转型领航者:佑美科技塑造智能健康新生态

在全球数字化转型的浪潮中,佑美专注于智能健康解决方案的创新,正以其卓越的技术实力和前瞻性的战略眼光,引领着智能穿戴设备和健身器械行业的未来趋势。佑美科技不仅深耕数字化转型,更在多个领域获得了国家级和省级的权威认可,彰显了其在智能健康领域的影响力。 智能穿戴设备正…

[数据结构] 基于选择的排序 选择排序堆排序

标题:[数据结构] 基于选择的排序 选择排序&&堆排序 水墨不写bug (图片来源于网络) 目录 (一)选择排序 实现:(默认从小到大排序) 优化后实现方法: (二)堆排序…

【Java】垃圾回收学习笔记(二):分代假说与垃圾回收算法

文章目录 0. 分代收集理论分代假说分代GC定义 1. 垃圾回收算法1.1 标记清除(Mark-Sweep)算法优点缺点 1.2 标记复制算法优点缺点为什么是8:1:1? 1.3 标记整理算法优点缺点 2. 是否移动?Reference 0. 分代收集理论 分代假说 现在…

Navicat和MySQL的安装

1、下载 Navicat Navicat 官网:www.navicat.com.cn/ 在产品中可以看到很多的产品,点击免费试用 Navicat Premium 即可,是一套多连数据库开发工具,其他的只能连接单一类型数据库 点击试用 选择系统直接下载 二、安装 Navicat 安…

代码江湖:Python 中的进程与线程

大家好,我是阔升。今天,咱们来聊聊 Python 中的两个"老熟人"——进程和线程。这两个概念可以说是 Python 多任务编程中的"双子星",既相似又不同,让不少小伙伴们头疼不已。不过别担心,今天我们就来…

element el-table实现表格动态增加/删除/编辑表格行,带校验规则

本篇文章记录el-table增加一行可编辑的数据列,进行增删改。 1.增加空白行 直接在页面mounted时对form里面的table列表增加一行数据,直接使用push() 方法增加一列数据这个时候也可以设置一些默认值。比如案例里面的 产品件数 。 mounted() {this.$nextTi…

latex 使用 thanks 首页空白 问题

写IEEE journal的时候遇到的问题……用latex写了\thanks,编译的论文第一页是空的,这是因为\thanks要在\author内部,然后再用\maketitle,即\author{… \thanks{}}。这样的话详细信息就会出现在论文首页的左下角 另外,\…