GA3C算法实现倒立摆

完整代码在文章结尾

GA3C算法

GPU/CPU混合式异步优势AC算法,是由A3C算法进一步优化而来,为了更好利用GPU计算资源。
GA3C理论上与A3C相同,属于On-Policy。但由于存在延迟更新问题,导致用于策略更新的数据并非当前策略采样得到的,因此大致也可视作Off-Policy,而这也会导致算法的收敛困难。

GA3C算法主要由三部分组成:

  • 智能体:多个智能体分别与模拟的环境进行交互,但是每个智能体不需要策略网络来选择动作,而是将当前状态发送给预测序列,预测者会根据策略网络为预测序列中的请求提供决策。智能体会将探索的经验发送到训练序列,用于网络训练。
  • 预测者:从预测队列中批量获取决策请求,并输入决策网络,得到决策动作。批量的数据输入能够利用GPU的并行计算能力,提升计算效率。根据实际任务的请求数量,预测者和预测队列数目可以进行调整,来控制信息的处理速度,提升计算效率;
  • 训练者:训练者会将信息存储在训练队列中,并从中批量选取数据,用于整体策略网络和价值网络的模型训练。

GA3C算法的策略网络和价值网络优化的目标和梯度的形式是相同的。

状态价值网络梯度

对于状态价值的更新,最小化真实状态值和估计值之间的误差,而真实状态值由时序差分算法进行估计,状态价值梯度:
∇ w J ( w ) = ∇ w E [ 1 2 ( v π ( S ) − v ^ π ( S ) ) 2 ] \nabla_w J(w)=\nabla_wE[\dfrac{1}{2}(v_\pi(S)-\hat{v}_\pi(S))^2] wJ(w)=wE[21(vπ(S)v^π(S))2]

使用时序差分算法和随机梯度法近似:
∇ w J ( w ) = − ∇ w ( r t + γ v ^ t ( s t + 1 ) − v ^ t ( s t ) ) ∇ w v ^ t ( s t ) \nabla_w J(w)=-\nabla_w (r_t + \gamma \hat{v}_t(s_{t+1})-\hat{v}_t(s_t))\nabla_w \hat{v}_t(s_t) wJ(w)=w(rt+γv^t(st+1)v^t(st))wv^t(st)

能够用时序差分算法估计状态值,原因是贝尔曼期望方程:
v π ( s ) = E [ R t + 1 + γ v π ( S t + 1 ) ∣ S t = s ] v_\pi(s) = E[R_{t+1}+\gamma v_\pi(S_{t+1})|S_t=s] vπ(s)=E[Rt+1+γvπ(St+1)St=s]

策略梯度

GA3C的策略梯度表达式与A2C相同,可额外添加熵正则项。
∇ θ J ( θ ) = E [ ∇ θ ln ⁡ π ( A ∣ S ) ( q π ( S , A ) − v π ( S ) ) ] + α ∇ θ H ( π ( ⋅ ∣ S ) ) \nabla_\theta J(\theta) = E[\nabla_\theta \ln\pi(A|S)(q_\pi(S,A)-v_\pi(S))] + \alpha\nabla_\theta H(\pi(·|S)) θJ(θ)=E[θlnπ(AS)(qπ(S,A)vπ(S))]+αθH(π(S))

使用随机梯度法近似真实梯度:
∇ θ J ( θ ) = ∇ θ ln ⁡ π ( a t ∣ s t ) ( q π ( s t , a t ) − v π ( s t ) ) + α ∇ θ ∑ i = 0 N π ( a i ∣ s t ) ln ⁡ π ( a i ∣ s t ) \nabla_\theta J(\theta) = \nabla_\theta \ln\pi(a_t|s_t)(q_\pi(s_t,a_t)-v_\pi(s_t)) + \alpha\nabla_\theta \sum^N_{i=0}\pi(a_i|s_t)\ln\pi(a_i|s_t) θJ(θ)=θlnπ(atst)(qπ(st,at)vπ(st))+αθi=0Nπ(aist)lnπ(aist)

由于使用离散的动作空间,能够直接计算得到动作熵。

其中的动作状态价值能够用状态价值网络的进行估计,原因:
q π ( s , a ) = E [ R t + 1 + γ v π ( S t + 1 ) ∣ S t = s , A t = a ] q_\pi(s,a)=E[R_{t+1}+\gamma v_\pi(S_{t+1})|S_t=s,A_t=a] qπ(s,a)=E[Rt+1+γvπ(St+1)St=s,At=a]

因此策略梯度表达式:
∇ θ J ( θ ) = ∇ θ ln ⁡ π ( a t ∣ s t ) ( r t + γ v ^ t ( s t + 1 ) − v ^ t ( s t ) ) + α ∇ θ ∑ i = 0 N π ( a i ∣ s t ) ln ⁡ π ( a i ∣ s t ) \nabla_\theta J(\theta) = \nabla_\theta \ln\pi(a_t|s_t)(r_t + \gamma \hat{v}_t(s_{t+1})-\hat{v}_t(s_t)) + \alpha\nabla_\theta \sum^N_{i=0}\pi(a_i|s_t)\ln\pi(a_i|s_t) θJ(θ)=θlnπ(atst)(rt+γv^t(st+1)v^t(st))+αθi=0Nπ(aist)lnπ(aist)

策略梯度是最大化平均状态价值,因此实际使用Pytorch的反向传播时,需要取负

GA3C算法代码实践

Actor

演员使用一层隐藏层的神经网络。

class Actor(nn.Module):def __init__(self, state_dim, action_dim, hidden_dim=256):super().__init__()self.net = nn.Sequential(nn.Linear(state_dim, hidden_dim), nn.LeakyReLU(),nn.Linear(hidden_dim, hidden_dim), nn.LeakyReLU(),nn.Linear(hidden_dim, action_dim),nn.Softmax(dim=-1))def forward(self, x):result = self.net(x)return result
Critic

评论家也使用一层隐藏层的神经网络。

class Critic(nn.Module):def __init__(self, state_dim, hidden_dim=256):super().__init__()self.net = nn.Sequential(nn.Linear(state_dim, hidden_dim), nn.LeakyReLU(),nn.Linear(hidden_dim, hidden_dim), nn.LeakyReLU(),nn.Linear(hidden_dim, 1))def forward(self, x):return self.net(x).squeeze(-1)
预测者

预测者属于多线程,需要继承于threading.Thread

class Predict(Thread):def __init__(self, agent, pred_queue, device):super().__init__()self.pred_queue = pred_queueself.device = deviceself.flag = Falseself.agent = agentself.daemon = Truedef run(self):while not self.flag:if self.pred_queue.empty():continueGA3C_Id, state = self.pred_queue.get(timeout=0.5)state = torch.tensor(state, dtype=torch.float32).to(self.device)with torch.no_grad():prob = self.agent.actor(state)# prob为GPU上的tentor类型,传递到队列(通常在CPU上)时,会出现错误,导致数据丢失,所以需要先转移到CPU上self.agent.workers[GA3C_Id].wait_q.put(prob.cpu())

预测者通过传入的pred_queue,属于multiprocessing.Queue能够在多进程之间通信,从而接收多进程中的预测要求,并记录对应的进程。

通过调用主进程中的策略网络来进行决策得到动作,重新传回对应进程的等待队列中。

注意其中由策略得到的概率分布,在GPU上,而队列Queue在CPU上,因此在传入队列前,需要先转换到CPU上,防止数据丢失。

训练者

训练者也属于多线程,需要继承于threading.Thread

lass Train(Thread):def __init__(self, agent, train_queue, device, batch):super().__init__()self.train_queue = train_queueself.device = deviceself.flag = Falseself.agent = agentself.daemon = Trueself.train_list = []self.size = 0self.batch = batchdef run(self):while not self.flag:if self.train_queue.empty():continuestate, action, reward, next_state, done = self.train_queue.get(timeout=0.5)self.train_list.append((state, action, reward, next_state, done))self.size += 1if self.size >= self.batch:state, action, reward, next_state, done = zip(*self.train_list)self.train_list.clear()self.size = 0self.agent.train_model(np.array(state), np.array(action), np.array(reward), np.array(next_state), np.array(done))

用于训练的数据是成批传输的,这样有助于策略网络和价值网络的稳定更新。

交互的智能体(工作者)

与环境进行交互的智能体,也可称为工作者,需要多个独立进程,继承于multiprocessing.Process

class Worker(Process):def __init__(self, id, pred_queue, train_queue, episode, gamma, max_step):super().__init__()self.pred_queue = pred_queueself.train_queue = train_queueself.id = idself.episode = episodeself.gamma = gammaself.wait_q = Queue(maxsize=1)self.max_step = max_stepdef take_action(self, state):self.pred_queue.put((self.id, state))while self.wait_q.empty():continueprob = self.wait_q.get(block=True)dist = torch.distributions.Categorical(prob)action = dist.sample().item()return actiondef run(self):env = gym.make('CartPole-v1')return_list = []for num in range(self.episode):step_num = 0state, info = env.reset()done = Falsereward_list = []while not done and step_num < self.max_step:action = self.take_action(state)step_num += 1next_state, reward, done, _, __ = env.step(action)self.train_queue.put((np.array(state), np.array(action), np.array(reward), np.array(next_state), np.array(done)))state = next_statereward_list.append(reward)res = 0for j in range(len(reward_list)-1, -1, -1):res = res * self.gamma + reward_list[j]print(f'{self.id}号,{num}轮回报:{res}   游戏进行步数:{step_num}')return_list.append(res)average = [np.mean(return_list[i:i+9])for i in range(0, len(return_list)-8)]epi = [x for x in range(len(average))]plt.plot(epi, average)plt.show()

工作者除了与环境进行交互,还需要从预测队列中接收状态,并调用主进程的策略网络进行决策得到动作。因此,多进程之间通讯十分重要。

主进程

将预测者、训练者和工作者集成到一个类GA3C中,进行统筹控制。

class GA3C:def __init__(self, max_data, state_dim, action_dim, episode, gamma, device, Worker_num, Predict_num, Train_num, lr, batch, lock, max_step):self.pred_queue = Queue(maxsize=max_data)self.train_queue = Queue(maxsize=max_data)self.episode = episodeself.gamma = gammaself.Worker_num = Worker_numself.Predict_num = Predict_numself.Train_num = Train_numself.device = deviceself.actor = Actor(state_dim, action_dim).to(device)self.critic = Critic(state_dim).to(device)self.initialize_net(self.actor, self.critic)self.optimizer = torch.optim.AdamW(list(self.actor.parameters()) + list(self.critic.parameters()),lr=lr)self.workers = []self.predicts = []self.trains = []self.batch = batchself.lock = lockself.max_step = max_stepdef train_model(self, state, action, reward, next_state, done):state = torch.tensor(state, dtype=torch.float32).to(self.device)action = torch.tensor(action, dtype=torch.int64).reshape((-1, 1)).to(self.device)reward = torch.tensor(reward, dtype=torch.float32).to(self.device)next_state = torch.tensor(next_state, dtype=torch.float32).to(self.device)done = torch.tensor(done, dtype=torch.float32).to(self.device)with self.lock:with torch.no_grad():TD_target = reward + self.gamma * \self.critic(next_state) * (1 - done)advantage = TD_target - self.critic(state)critic_loss = F.mse_loss(TD_target.detach(), self.critic(state))prob = self.actor(state)actor_loss = - torch.mean(advantage.detach()* torch.log(prob.gather(-1, action)) + 1e-7) + 0.005 * torch.sum(prob * torch.log(prob + 1e-7), dim=1, keepdim=True).mean()total_loss = actor_loss + critic_lossself.optimizer.zero_grad()total_loss.backward()self.optimizer.step()def initialize_net(self, actor, critic):def init_weights(m):if isinstance(m, nn.Linear):nn.init.xavier_uniform_(m.weight)nn.init.zeros_(m.bias)actor.apply(init_weights)critic.apply(init_weights)def main(self):for i in range(self.Worker_num):self.workers.append(Worker(i, self.pred_queue, self.train_queue, self.episode, self.gamma, self.max_step))self.workers[-1].start()for i in range(self.Predict_num):self.predicts.append(Predict(self, self.pred_queue, self.device))self.predicts[-1].start()for i in range(self.Train_num):self.trains.append(Train(self, self.train_queue, self.device, self.batch))self.trains[-1].start()for w in range(len(self.workers)):self.workers[-1].join()self.workers.pop()for i in range(len(self.predicts)):self.predicts[-1].flag = Trueself.predicts[-1].join()self.predicts.pop()for i in range(len(self.trains)):self.trains[-1].flag = Trueself.trains[-1].join()self.trains.pop()

在GA3C类中需要定义全局策略网络和价值网络,还需要定义策略和价值网络的更新函数,并在main()函数中指定好各工作者进程和预测及训练线程的开始与结束标志。

在更新函数中,策略网络损失函数计算时,需要在取对数的动作概率上加上一个大于0的小数,防止概率过小,而使得损失无穷大,导致算法无法正常收敛。

完整代码

import os
import torch
import torch.nn as nn
import numpy as np
import gym
from multiprocessing import Queue, Process
import torch.nn.functional as F
import threading
from threading import Thread
import matplotlib.pyplot as pltclass Actor(nn.Module):def __init__(self, state_dim, action_dim, hidden_dim=256):super().__init__()self.net = nn.Sequential(nn.Linear(state_dim, hidden_dim), nn.LeakyReLU(),nn.Linear(hidden_dim, hidden_dim), nn.LeakyReLU(),nn.Linear(hidden_dim, action_dim),nn.Softmax(dim=-1))def forward(self, x):result = self.net(x)return resultclass Critic(nn.Module):def __init__(self, state_dim, hidden_dim=256):super().__init__()self.net = nn.Sequential(nn.Linear(state_dim, hidden_dim), nn.LeakyReLU(),nn.Linear(hidden_dim, hidden_dim), nn.LeakyReLU(),nn.Linear(hidden_dim, 1))def forward(self, x):return self.net(x).squeeze(-1)class Worker(Process):def __init__(self, id, pred_queue, train_queue, episode, gamma, max_step):super().__init__()self.pred_queue = pred_queueself.train_queue = train_queueself.id = idself.episode = episodeself.gamma = gammaself.wait_q = Queue(maxsize=1)self.max_step = max_stepdef take_action(self, state):self.pred_queue.put((self.id, state))while self.wait_q.empty():continueprob = self.wait_q.get(block=True)dist = torch.distributions.Categorical(prob)action = dist.sample().item()return actiondef run(self):env = gym.make('CartPole-v1')return_list = []for num in range(self.episode):step_num = 0state, info = env.reset()done = Falsereward_list = []while not done and step_num < self.max_step:action = self.take_action(state)step_num += 1next_state, reward, done, _, __ = env.step(action)self.train_queue.put((np.array(state), np.array(action), np.array(reward), np.array(next_state), np.array(done)))state = next_statereward_list.append(reward)res = 0for j in range(len(reward_list)-1, -1, -1):res = res * self.gamma + reward_list[j]print(f'{self.id}号,{num}轮回报:{res}   游戏进行步数:{step_num}')return_list.append(res)average = [np.mean(return_list[i:i+9])for i in range(0, len(return_list)-8)]epi = [x for x in range(len(average))]plt.plot(epi, average)plt.show()class Predict(Thread):def __init__(self, agent, pred_queue, device):super().__init__()self.pred_queue = pred_queueself.device = deviceself.flag = Falseself.agent = agentself.daemon = Truedef run(self):while not self.flag:if self.pred_queue.empty():continueGA3C_Id, state = self.pred_queue.get(timeout=0.5)state = torch.tensor(state, dtype=torch.float32).to(self.device)with torch.no_grad():prob = self.agent.actor(state)# prob为GPU上的tentor类型,传递到队列(通常在CPU上)时,会出现错误,导致数据丢失,所以需要先转移到CPU上self.agent.workers[GA3C_Id].wait_q.put(prob.cpu())class Train(Thread):def __init__(self, agent, train_queue, device, batch):super().__init__()self.train_queue = train_queueself.device = deviceself.flag = Falseself.agent = agentself.daemon = Trueself.train_list = []self.size = 0self.batch = batchdef run(self):while not self.flag:if self.train_queue.empty():continuestate, action, reward, next_state, done = self.train_queue.get(timeout=0.5)self.train_list.append((state, action, reward, next_state, done))self.size += 1if self.size >= self.batch:state, action, reward, next_state, done = zip(*self.train_list)self.train_list.clear()self.size = 0self.agent.train_model(np.array(state), np.array(action), np.array(reward), np.array(next_state), np.array(done))class GA3C:def __init__(self, max_data, state_dim, action_dim, episode, gamma, device, Worker_num, Predict_num, Train_num, lr, batch, lock, max_step):self.pred_queue = Queue(maxsize=max_data)self.train_queue = Queue(maxsize=max_data)self.episode = episodeself.gamma = gammaself.Worker_num = Worker_numself.Predict_num = Predict_numself.Train_num = Train_numself.device = deviceself.actor = Actor(state_dim, action_dim).to(device)self.critic = Critic(state_dim).to(device)self.initialize_net(self.actor, self.critic)self.optimizer = torch.optim.AdamW(list(self.actor.parameters()) + list(self.critic.parameters()),lr=lr)self.workers = []self.predicts = []self.trains = []self.batch = batchself.lock = lockself.max_step = max_stepdef train_model(self, state, action, reward, next_state, done):state = torch.tensor(state, dtype=torch.float32).to(self.device)action = torch.tensor(action, dtype=torch.int64).reshape((-1, 1)).to(self.device)reward = torch.tensor(reward, dtype=torch.float32).to(self.device)next_state = torch.tensor(next_state, dtype=torch.float32).to(self.device)done = torch.tensor(done, dtype=torch.float32).to(self.device)with self.lock:with torch.no_grad():TD_target = reward + self.gamma * \self.critic(next_state) * (1 - done)advantage = TD_target - self.critic(state)critic_loss = F.mse_loss(TD_target.detach(), self.critic(state))prob = self.actor(state)actor_loss = - torch.mean(advantage.detach()* torch.log(prob.gather(-1, action)) + 1e-7) + 0.005 * torch.sum(prob * torch.log(prob + 1e-7), dim=1, keepdim=True).mean()total_loss = actor_loss + critic_lossself.optimizer.zero_grad()total_loss.backward()self.optimizer.step()def initialize_net(self, actor, critic):def init_weights(m):if isinstance(m, nn.Linear):nn.init.xavier_uniform_(m.weight)nn.init.zeros_(m.bias)actor.apply(init_weights)critic.apply(init_weights)def main(self):for i in range(self.Worker_num):self.workers.append(Worker(i, self.pred_queue, self.train_queue, self.episode, self.gamma, self.max_step))self.workers[-1].start()for i in range(self.Predict_num):self.predicts.append(Predict(self, self.pred_queue, self.device))self.predicts[-1].start()for i in range(self.Train_num):self.trains.append(Train(self, self.train_queue, self.device, self.batch))self.trains[-1].start()for w in range(len(self.workers)):self.workers[-1].join()self.workers.pop()for i in range(len(self.predicts)):self.predicts[-1].flag = Trueself.predicts[-1].join()self.predicts.pop()for i in range(len(self.trains)):self.trains[-1].flag = Trueself.trains[-1].join()self.trains.pop()if __name__ == '__main__':os.system('cls')max_data = 10000 # 预测队列和训练队列最大容量,不过一般取10左右即可Worker_num = 4Predict_num = 2Train_num = 4batch = 40  # 32max_step = 1500 # 限制单回合最大步数gamma = 0.99episode = 1300 # 500lr = 1e-4 # 极其重要,过大,可能会导致发散device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')env = gym.make('CartPole-v1')state_dim = env.observation_space.shape[0]action_dim = env.action_space.nenv.close()lock = threading.Lock()agent = GA3C(max_data, state_dim, action_dim, episode,gamma, device, Worker_num, Predict_num, Train_num, lr, batch, lock, max_step)agent.main()

注意,为了防止倒立摆游戏无限进行,需要增加最大步数限制max_step

学习率的取值也十分重要,较大的学习率可能会导致算法在越过局部极小值后,开始发散无法收敛,如下图。

下图是使用lr=0.0003进行训练的结果,纵坐标是单回合的回报,横坐标是回合数。
在这里插入图片描述

该图就描述了算法在越过局部极小值后,开始发散,导致回报无法收敛。

而使用lr=0.0001进行训练,除了训练速度可能降低外,算法也没出现发散的问题,回报能够正常收敛到稳定值。
在这里插入图片描述

注意事项

  • 一般batch设置在32~64之间即可,一批训练数据的大小,影响训练的稳定性。过多会导致一个随机动作被忽视,难以发现更好的动作;过少会导致算法的振荡,稳定性较差,可能难以收敛。
  • 工作者、预测者和训练者的数量按照实际任务需要进行设置。一般预测者和训练者的比例可选取1:1,1:2,2:1。具体可见原论文内容;
  • 虽然这里使用的单步TD进行更新,与原论文中的多步TD存在差异,但实际影响的是网络更新的稳定性,一般都能够正常更新和收敛的,影响不是很大。

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

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

相关文章

基础RAG实现,最佳入门选择(六)

带有问题生成的文档增强RAG 通过问题生成使用文档增强来实现增强的RAG方法。通过为每个文本块生成相关问题&#xff0c;改进了检索过程&#xff0c;从而从语言模型中获得更好的响应。 具体实现步骤 1.数据摄取&#xff1a;从PDF文件中提取文本。 2.chunking&#xff1a;将文本…

vue3 电商类网站实现规格的选择

目前有一个这样的需求 类似淘宝 京东选择 但是在人家大厂给的数据我不清除是什么样子的 我这边后端给的数据 一开始是想把规格全部显示出来的 发现实现不了 后端的数据有限 因为必须选择一个颜色 才可以对应的第二个规格 才知道有没有库存 因为这个库存 是由两个规格决定…

HarmonyOS5 音乐播放器app(一):歌曲展示与收藏功能(附代码)

鸿蒙音乐应用开发&#xff1a;从收藏功能实现看状态管理与交互设计 在移动应用开发中&#xff0c;收藏功能是用户体验的重要组成部分。本文将以鸿蒙OS音乐应用为例&#xff0c;详细解析如何实现具有动画效果的收藏功能&#xff0c;涉及状态管理、组件通信和交互动画等核心技术…

PHP函数大全参考代码

字符串相关操作函数 去除空格或其他字符 trim删除字符串两端空格或其他预定义字符rtrim删除字符串右边空格或其他预定义字符choprtrim() 的别名 chop() 与 Perl 的 chop() 函数有所不同&#xff0c;它会删除字符串的最后一个字符。ltrim删除字符串左边空格或其他预定义字符 字…

Flowise工作流引擎的本地部署与远程访问实践

文章目录 前言1. Docker安装Flowise2. Ubuntu安装Cpolar3. 配置Flowise公网地址4. 远程访问Flowise5. 固定Cpolar公网地址6. 固定地址访问 前言 当多数团队仍深陷传统数据处理框架的桎梏时&#xff0c;创新者已率先引入Flowise智能流程引擎&#xff0c;成功将面向大型语言模型…

端侧AI+OS垂直创新研究报告

端侧AIOS垂直创新研究报告 摘要 端侧AIOS研究背景、核心创新点及产业价值 研究背景 随着AI技术的快速发展&#xff0c;端侧AI已成为2025年的重要技术趋势[4]。端侧AI是指将AI计算能力从云端迁移到终端设备上&#xff0c;实现本地化的智能处理。这一技术变革主要受到隐私安全…

【JVM 07-运行时常量池重要组成部分-StringTable】

StringTable 笔记记录 1. 常量池、运行时常量池与字符串常量池(StringTable)的关系2. String str"a"放入字符串常量池的过程3. 常见面试题4. StringTable特性5.StringTable的位置变更5.1 为什么位置变换&#xff1f;5.2 位置变更演示 6. StringTable垃圾回收7. Strin…

算法-每日一题(DAY10)打家劫舍

1.题目链接&#xff1a; 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 2.题目描述&#xff1a; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xf…

android UI 布局

一&#xff1a;约束布局 参考&#xff1a; 【约束布局】ConstraintLayout 约束布局 ( 简介 | 引入依赖 | 基本操作 | 垂直定位约束 | 角度定位约束 | 基线约束 )_韩曙亮-2048 AI社区 以下是一个基于 ConstraintLayout 的简单 Android 示例&#xff0c;包含三个控件&#xff0…

【K8S】详解Labels​​ 和 ​​Annotations

在 Kubernetes&#xff08;K8s&#xff09;中&#xff0c;​​Labels&#xff08;标签&#xff09;​​ 和 ​​Annotations&#xff08;注解&#xff09;​​ 都是用于为资源对象&#xff08;如 Pod、Service、Deployment&#xff09;附加元数据的机制&#xff0c;但它们在设计…

系统模块编程与实现

设备类&#xff08;Device Class&#xff09;​​ 和 ​​设备节点&#xff08;Device Node&#xff09;​​是深入 Linux 设备管理和驱动模型的核心基础。它们就像“骨骼”与“门户”&#xff0c;共同构建了 Linux 与硬件交互的核心桥梁。 一、设备类与设备节点 1. ​​设备…

视频压缩、码率与流媒体传输知识总结

&#x1f3a5; 视频压缩、码率与流媒体传输知识总结 本笔记整理了 I/P/B 帧结构、码率计算、文件大小估算、压缩格式对比、推流带宽建议等视频工程常见技术要点。 一、单帧与未压缩视频数据量估算 分辨率&#xff1a;19201080&#xff08;1080p&#xff09; 色深&#xff1a;…

嵌入式C++学习路线

&#x1f680; 嵌入式C学习路线图 从C语言基础到嵌入式C高手的完整路径 &#x1f4cb; 学习进度追踪 总体目标&#xff1a; 20-26周完成全部学习内容 前置条件&#xff1a; C语言基础 STM32开发经验 学习方式&#xff1a; 理论学习 实践项目 阶段1: C基础过渡 (2-3周) 目标…

VSCode1.101.1Win多语言语言编辑器便携版安装教程

软件下载 【名称】&#xff1a; VSCode1.101.1 【大小】&#xff1a; 120M 【语言】&#xff1a; 简体中文 【安装环境】&#xff1a; Win10/Win11 【迅雷网盘下载链接】&#xff08;务必手机注册&#xff09;&#xff1a; 迅雷 【网站下载链接】: 其他网盘 软件介绍 VSCod…

ssh 服务和 rsync 数据同步

目录 一、ssh服务 1、概述 2、命令解析 远程登录命令 远程拷贝命令 3、登录方式配置 1、用户名密码登录 2、公钥验证登录 二、rsync 数据同步 1、rsync概述 2、rsync运行原理 3、rsync部署 一、ssh服务 1、概述 ssh服务&#xff0c;一种远程管理连接工具&#xf…

使用随机森林实现目标检测

核心实现思路 滑动窗口策略&#xff1a;在图像上滑动固定大小的窗口&#xff0c;对每个窗口进行分类多维特征提取&#xff1a;结合统计特征、纹理特征、边缘特征、形状特征等随机森林分类&#xff1a;训练二分类器判断窗口是否包含目标后处理优化&#xff1a;使用非极大值抑制…

3.6 move_base导航初体验

1.环境搭建 在工作空间src下git wpr_simulation&#xff0c;安装install_for_noetic.sh&#xff0c;然后再回退工作空间进行编译 下载参数文件 git clone https://github.com/6-robot/wpb_home.git下载需要魔法&#xff0c;在这里可以使用手机热点进行平替 进入脚本文件夹 …

Mysql高级——MVCC(多版本并发控制)

MySQL MVCC&#xff08;多版本并发控制&#xff09;详解 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;是 MySQL InnoDB 存储引擎实现的一种并发控制机制&#xff0c;用于在保证事务隔离性的同时&#xff0c;提高数据库的并发性能。下面从原理、实现、事务隔…

Oracle union连接的怎么排序

在Oracle数据库中&#xff0c;使用UNION或UNION ALL操作符来合并两个或多个查询结果时&#xff0c;如果想对这些合并后的结果进行排序&#xff0c;通常有两种方法可以实现&#xff1a; 方法1&#xff1a;在最后的查询结果上使用ORDER BY 你可以在所有使用UNION或UNION ALL合并…

uni-app总结2-所需知识储备和学习途径

使用uni-app进行跨平台开发&#xff0c;开发者不用去掌握各个平台的开发语言&#xff0c;只需一套代码即可完成多端的产品输出。那么使用uni-app需要掌握什么呢&#xff0c;这里给大家分享一下。 Vue.js uni-app里是通过Vue来开发的&#xff0c;所以首先肯定是要掌握Vue语言。…