PyTorch 深度学习实战(21):元强化学习与 MAML 算法
一、元强化学习原理
1. 元学习核心思想
元强化学习(Meta-RL)旨在让智能体快速适应新任务,其核心是通过任务分布学习共享知识。与传统强化学习的区别在于:
| 对比维度 | 传统强化学习 | 元强化学习 |
|---|---|---|
| 目标 | 解决单一任务 | 快速适应任务分布中的新任务 |
| 训练方式 | 单任务大量交互 | 多任务交替训练 |
| 泛化能力 | 任务特定策略 | 跨任务可迁移策略 |
2. MAML 算法框架
Model-Agnostic Meta-Learning (MAML) 通过双层优化实现快速适应:
-
内层循环:在单个任务上执行少量梯度步
-
外层循环:跨任务更新初始参数
数学表达:

二、MAML 实现步骤(基于 Gymnasium)
我们将以 HalfCheetah 变体任务 为例,实现 MAML 算法:
-
定义任务分布:修改机器人质量参数生成不同任务
-
构建策略网络:基于 PyTorch 的 Actor-Critic 架构
-
实现双层优化:内层任务适配 + 外层元更新
-
快速适应测试:在新任务上验证策略性能
三、代码实现
import gymnasium as gym
import torch
import numpy as np
from torch import nn, optim
from collections import deque
import time
import torch.nn.functional as F
# ================== 配置参数优化 ==================
class MAMLConfig:env_name = "HalfCheetah-v5"num_tasks = 20adaptation_steps = 10 # 增加适应步数adaptation_lr = 0.1 # 调整适应学习率hidden_dim = 256 # 增大隐藏层维度gamma = 0.99tau = 0.95 # 用于GAE计算meta_batch_size = 8 # 增大元批量meta_lr = 3e-4 # 调整元学习率total_epochs = 1000device = torch.device("cuda" if torch.cuda.is_available() else "cpu")clip_grad = 0.5 # 梯度裁剪阈值
# ================== 策略网络优化 ==================
class ActorCritic(nn.Module):def __init__(self, state_dim, action_dim):super().__init__()# 独立特征提取层(修正结构命名)self.actor_net = nn.Sequential(nn.Linear(state_dim, MAMLConfig.hidden_dim),nn.LayerNorm(MAMLConfig.hidden_dim),nn.Tanh(),nn.Linear(MAMLConfig.hidden_dim, MAMLConfig.hidden_dim),nn.LayerNorm(MAMLConfig.hidden_dim),nn.Tanh())self.critic_net = nn.Sequential(nn.Linear(state_dim, MAMLConfig.hidden_dim),nn.LayerNorm(MAMLConfig.hidden_dim),nn.Tanh(),nn.Linear(MAMLConfig.hidden_dim, MAMLConfig.hidden_dim),nn.LayerNorm(MAMLConfig.hidden_dim),nn.Tanh())self.actor_mean = nn.Linear(MAMLConfig.hidden_dim, action_dim)self.log_std = nn.Parameter(torch.zeros(action_dim))self.critic = nn.Linear(MAMLConfig.hidden_dim, 1)# 初始化参数(保持原有初始化逻辑)self._init_weights()def _init_weights(self):for m in self.modules():if isinstance(m, nn.Linear):nn.init.orthogonal_(m.weight, gain=0.01) # 正交初始化nn.init.constant_(m.bias, 0)# 策略最后一层初始化较小nn.init.orthogonal_(self.actor_mean.weight, gain=0.01)nn.init.constant_(self.actor_mean.bias, 0)# 价值头初始化nn.init.orthogonal_(self.critic.weight, gain=1.0)nn.init.constant_(self.critic.bias, 0)def forward(self, state, params=None):if params is None:# 正常前向传播actor_features = self.actor_net(state)critic_features = self.critic_net(state)mean = self.actor_mean(actor_features)value = self.critic(critic_features).squeeze(-1)else:# 手动参数计算时保持维度一致性if len(state.shape) == 1:state = state.unsqueeze(0) # 添加批量维度# Actor网络计算x = F.linear(state, params['actor_net.0.weight'], params['actor_net.0.bias'])x = F.layer_norm(x, (MAMLConfig.hidden_dim,))x = torch.tanh(x)x = F.linear(x, params['actor_net.3.weight'], params['actor_net.3.bias'])x = F.layer_norm(x, (MAMLConfig.hidden_dim,))actor_features = torch.tanh(x)# Critic网络计算x = F.linear(state, params['critic_net.0.weight'], params['critic_net.0.bias'])x = F.layer_norm(x, (MAMLConfig.hidden_dim,))x = torch.tanh(x)x = F.linear(x, params['critic_net.3.weight'], params['critic_net.3.bias'])x = F.layer_norm(x, (MAMLConfig.hidden_dim,))critic_features = torch.tanh(x)mean = F.linear(actor_features, params['actor_mean.weight'],params['actor_mean.bias'])value = F.linear(critic_features,params['critic.weight'],params['critic.bias']).squeeze(-1)log_std = self.log_std.unsqueeze(0).expand(mean.shape[0], -1)return mean, log_std, value
def sample_action(self, state, params=None):mean, log_std, _ = self.forward(state, params)std = log_std.exp()dist = torch.distributions.Normal(mean, std)action = dist.rsample()# 新增维度检查逻辑if len(action.shape) > 1:if action.shape[0] == 1: # 单样本批量情况action = action.squeeze(0)else: # 多步采样情况action = action.squeeze()log_prob = dist.log_prob(action).sum(-1)return action.detach(), log_prob
# ================== 任务生成器优化 ==================
class TaskGenerator:def __init__(self):self.default_params = self._get_default_params()def _get_default_params(self):env = gym.make(MAMLConfig.env_name)params = {'mass': env.unwrapped.model.body_mass.copy(),'damping': env.unwrapped.model.dof_damping.copy()}env.close()return paramsdef sample_task(self):new_params = {'mass': self.default_params['mass'] * np.random.uniform(0.5, 2.0, size=self.default_params['mass'].shape),'damping': self.default_params['damping'] * np.random.uniform(0.5, 2.0, size=self.default_params['damping'].shape),'ctrlrange': self.default_params['damping'] * np.random.uniform(0.8, 1.2) # 新增控制力范围扰动}return new_params
# ================== MAML 训练系统优化 ==================
class MAMLTrainer:def __init__(self):self.env = gym.make(MAMLConfig.env_name)self.state_dim = self.env.observation_space.shape[0]self.action_dim = self.env.action_space.shape[0]self.policy = ActorCritic(self.state_dim, self.action_dim).to(MAMLConfig.device)self.meta_optimizer = optim.Adam(self.policy.parameters(), lr=MAMLConfig.meta_lr, betas=(0.9, 0.999))self.task_gen = TaskGenerator()self.tasks = [self.task_gen.sample_task() for _ in range(MAMLConfig.num_tasks)]def adapt_task(self, task_params, num_steps):env = gym.make(MAMLConfig.env_name)env.unwrapped.model.body_mass[:] = task_params['mass']env.unwrapped.model.dof_damping[:] = task_params['damping']fast_weights = {k: v.clone().requires_grad_(True) for k, v in self.policy.named_parameters()}# 多步适应过程for step in range(num_steps):states, actions, rewards, values, dones = [], [], [], [], []obs, _ = env.reset()done = Falsewhile not done:with torch.no_grad():state_tensor = torch.FloatTensor(obs).to(MAMLConfig.device)action, _ = self.policy.sample_action(state_tensor, params=fast_weights)_, _, value = self.policy(state_tensor, params=fast_weights)# next_obs, reward, terminated, truncated, _ = env.step(action.cpu().numpy())next_obs, reward, terminated, truncated, _ = env.step(action.cpu().numpy().astype(np.float32).flatten() # 新增flatten()
)states.append(obs)actions.append(action)rewards.append(reward)values.append(value)dones.append(terminated or truncated)obs = next_obsdone = terminated or truncated# 计算GAEwith torch.no_grad():last_value = self.policy(torch.FloatTensor(obs).to(MAMLConfig.device), params=fast_weights)[2]returns, advantages = self._compute_gae(rewards, values, dones, last_value)# 计算损失states_tensor = torch.FloatTensor(np.array(states)).to(MAMLConfig.device)actions_tensor = torch.stack(actions)mean, log_std, current_values = self.policy(states_tensor, params=fast_weights)std = log_std.exp()dist = torch.distributions.Normal(mean, std)log_probs = dist.log_prob(actions_tensor).sum(-1)# 策略损失policy_loss = -(log_probs * advantages).mean()# 价值损失value_loss = F.mse_loss(current_values, returns)# 熵正则化entropy_loss = -dist.entropy().mean()total_loss = policy_loss + 0.5 * value_loss + 0.01 * entropy_loss# 计算梯度并更新快速权重grads = torch.autograd.grad(total_loss, fast_weights.values(), create_graph=True, allow_unused=True)for (name, param), grad in zip(fast_weights.items(), grads):if grad is not None:fast_weights[name] = param - MAMLConfig.adaptation_lr * gradenv.close()return fast_weightsdef _compute_gae(self, rewards, values, dones, last_value):values = values + [last_value]gae = 0returns = []advantages = []for t in reversed(range(len(rewards))):delta = rewards[t] + MAMLConfig.gamma * values[t+1] * (1 - dones[t]) - values[t]gae = delta + MAMLConfig.gamma * MAMLConfig.tau * (1 - dones[t]) * gaeadvantages.insert(0, gae)returns.insert(0, advantages[0] + values[t])advantages = torch.tensor(advantages, device=MAMLConfig.device, dtype=torch.float32)returns = torch.tensor(returns, device=MAMLConfig.device, dtype=torch.float32)# 标准化优势advantages = (advantages - advantages.mean()) / (advantages.std() + 1e-8)return returns, advantagesdef meta_update(self, tasks):meta_loss = 0for task in tasks:fast_weights = self.adapt_task(task, MAMLConfig.adaptation_steps)# 在适应后的策略上收集轨迹env = gym.make(MAMLConfig.env_name)env.unwrapped.model.body_mass[:] = task['mass']env.unwrapped.model.dof_damping[:] = task['damping']states, actions, rewards, values, dones = [], [], [], [], []obs, _ = env.reset()done = Falsewhile not done:with torch.no_grad():state_tensor = torch.FloatTensor(obs).to(MAMLConfig.device)action, _ = self.policy.sample_action(state_tensor, params=fast_weights)_, _, value = self.policy(state_tensor, params=fast_weights)next_obs, reward, terminated, truncated, _ = env.step(action.cpu().numpy())states.append(obs)actions.append(action)rewards.append(reward)values.append(value)dones.append(terminated or truncated)obs = next_obsdone = terminated or truncated# 计算GAE和returnswith torch.no_grad():last_value = self.policy(torch.FloatTensor(obs).to(MAMLConfig.device), params=fast_weights)[2]returns, advantages = self._compute_gae(rewards, values, dones, last_value)# 计算元损失states_tensor = torch.FloatTensor(np.array(states)).to(MAMLConfig.device)actions_tensor = torch.stack(actions).to(MAMLConfig.device)mean, log_std, current_values = self.policy(states_tensor, params=fast_weights)std = log_std.exp()dist = torch.distributions.Normal(mean, std)log_probs = dist.log_prob(actions_tensor).sum(-1)policy_loss = -(log_probs * advantages).mean()value_loss = F.mse_loss(current_values, returns)entropy_loss = -dist.entropy().mean()task_loss = policy_loss + 0.5 * value_loss + 0.01 * entropy_lossmeta_loss += task_lossenv.close()meta_loss /= len(tasks)self.meta_optimizer.zero_grad()meta_loss.backward()torch.nn.utils.clip_grad_norm_(self.policy.parameters(), MAMLConfig.clip_grad)self.meta_optimizer.step()return meta_loss.item()def train(self):for epoch in range(MAMLConfig.total_epochs):batch_tasks = np.random.choice(self.tasks, MAMLConfig.meta_batch_size)loss = self.meta_update(batch_tasks)if (epoch + 1) % 50 == 0:print(f"Epoch {epoch+1:04d} | Meta Loss: {loss:.1f}")self._evaluate()
def _evaluate(self, num_tasks=3):total_rewards = []for i in range(num_tasks):task = self.task_gen.sample_task()original_params = {k: v.clone() for k, v in self.policy.named_parameters()}fast_weights = self.adapt_task(task, MAMLConfig.adaptation_steps)env = gym.make(MAMLConfig.env_name)env.unwrapped.model.body_mass[:] = task['mass']env.unwrapped.model.dof_damping[:] = task['damping']obs, _ = env.reset()total_reward = 0done = Falsewhile not done:with torch.no_grad():action, _ = self.policy.sample_action(torch.FloatTensor(obs).to(MAMLConfig.device),params=fast_weights)obs, reward, terminated, truncated, _ = env.step(action.cpu().numpy())total_reward += rewarddone = terminated or truncatedtotal_rewards.append(total_reward)self.policy.load_state_dict(original_params)env.close()avg_reward = sum(total_rewards) / num_tasksprint(f"Evaluation | Avg Reward: {avg_reward:.1f}")
if __name__ == "__main__":start = time.time()start_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start))print(f"开始时间: {start_str}")print("初始化环境...")trainer = MAMLTrainer()trainer.train()end = time.time()end_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end))print(f"训练完成时间: {end_str}")print(f"训练完成,耗时: {end - start:.2f}秒")
四、关键代码解析
-
任务生成器
-
通过修改机器人质量和关节阻尼参数生成新任务
-
每个任务对应不同的物理动力学特性
-
-
双层优化实现
-
adapt_task:内层循环在单个任务上执行策略梯度更新 -
meta_update:外层循环跨任务更新初始参数
-
-
策略快速适应
-
使用
torch.autograd.grad计算二阶梯度 -
通过参数克隆实现任务特定参数更新
-
五、训练输出示例
开始时间: 2025-03-19 12:49:54
初始化环境...
Epoch 0050 | Meta Loss: 18.0
Evaluation | Avg Reward: -299.6
Epoch 0100 | Meta Loss: 21.5
Evaluation | Avg Reward: -193.3
Epoch 0150 | Meta Loss: 14.8
Evaluation | Avg Reward: -199.7
Epoch 0200 | Meta Loss: 25.3
Evaluation | Avg Reward: -317.4
Epoch 0250 | Meta Loss: 16.7
Evaluation | Avg Reward: -174.8
Epoch 0300 | Meta Loss: 24.3
Evaluation | Avg Reward: -277.6
Epoch 0350 | Meta Loss: 12.3
Evaluation | Avg Reward: -249.0
Epoch 0400 | Meta Loss: 25.4
Evaluation | Avg Reward: -253.4
Epoch 0450 | Meta Loss: 13.6
Evaluation | Avg Reward: -222.1
Epoch 0500 | Meta Loss: 27.9
Evaluation | Avg Reward: -295.4
Epoch 0550 | Meta Loss: 23.3
Evaluation | Avg Reward: -484.5
Epoch 0600 | Meta Loss: 17.2
Evaluation | Avg Reward: -315.4
Epoch 0650 | Meta Loss: 16.0
Evaluation | Avg Reward: -250.3
Epoch 0700 | Meta Loss: 20.9
Evaluation | Avg Reward: -300.3
Epoch 0750 | Meta Loss: 33.4
Evaluation | Avg Reward: -305.0
Epoch 0800 | Meta Loss: 61.8
Evaluation | Avg Reward: -260.7
Epoch 0850 | Meta Loss: 10.9
Evaluation | Avg Reward: -311.5
Epoch 0900 | Meta Loss: 24.7
Evaluation | Avg Reward: -299.8
Epoch 0950 | Meta Loss: 14.5
Evaluation | Avg Reward: -321.9
Epoch 1000 | Meta Loss: 12.0
Evaluation | Avg Reward: -275.3
训练完成时间: 2025-03-20 09:28:03
训练完成,耗时: 74288.70秒
六、总结与扩展
本文实现了元强化学习的核心范式——MAML 算法,展示了策略快速适应新任务的能力。读者可尝试以下扩展方向:
-
高效探索策略 结合 Proximal Policy Optimization (PPO) 或 Soft Actor-Critic (SAC) 提升采样效率
-
多模态任务适应 使用条件策略网络处理离散任务类型
在下一篇文章中,我们将探索 多智能体强化学习(MARL),并实现 MADDPG 算法!
注意事项
-
安装依赖:
pip install gymnasium[mujoco] torch -
完整训练需要 GPU 加速(推荐显存 ≥ 8GB)
-
若遇到环境初始化错误,检查 MuJoCo 许可证配置:
ls ~/.mujoco/mjkey.txt
相关文章:
PyTorch 深度学习实战(21):元强化学习与 MAML 算法
一、元强化学习原理 1. 元学习核心思想 元强化学习(Meta-RL)旨在让智能体快速适应新任务,其核心是通过任务分布学习共享知识。与传统强化学习的区别在于: 对比维度传统强化学习元强化学习目标解决单一任务快速适应任务分布中的…...
23中设计模式-迭代器(Iterator)设计模式
迭代器设计模式 🚩什么是迭代器设计模式?🚩迭代器设计模式的特点🚩迭代器设计模式的结构🚩迭代器设计模式的优缺点🚩迭代器设计模式的Java实现🚩代码总结🚩总结 🚩什么是…...
Word中公式自动标号带章节编号
(1)插入一行三列的表格,设置宽度分别为0.5,13.39和1.5,设置纵向居中,中间列居中对齐,最右侧列靠右对齐,设置段落如下 (2)插入域代码 【Word】利用域代码快速实…...
基于动态 FOF(基金中的基金)策略的基金交易推荐系统的设计与实现思路
下面为你呈现一个基于动态 FOF(基金中的基金)策略的基金交易推荐系统的设计与实现思路,同时给出一个简单的 Python 示例代码。 系统设计 1. 需求分析 收集各类基金的历史数据,涵盖净值、收益率、风险指标等。依据动态 FOF 策略…...
【Spring AI】基于专属知识库的RAG智能问答小程序开发——功能优化:用户鉴权主体功能开发
系列文章目录 【Spring AI】基于专属知识库的RAG智能问答小程序开发——完整项目(含完整前端后端代码)【Spring AI】基于专属知识库的RAG智能问答小程序开发——代码逐行精讲:核心ChatClient对象相关构造函数【Spring AI】基于专属知识库的R…...
[7-01-03].SpringBoot3集成MinIo
MinIO学习大纲 一、Spingboot整合MinIo 第1步:搭建SpringBoot项目: 第2步:引入minio依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi&q…...
ISIS-3 LSDB链路状态数据库同步
上一章我们介绍了ISIS的邻居建立关系以及ISIS的路由器角色有哪些,在不同的网络类型当中建立邻居关系有什么不同,并且以实验案例抓包的形式给大家进一步介绍了建立的过程。 这一章我们来介绍ISIS中是如何实现链路状态数据库同步的,与OSPF的链路状态同步有什么不同,在不同网络类…...
快速入手-基于Django的Form和ModelForm操作(七)
1、Form组件 2、ModelForm操作 3、给前端表单里在django里添加class相关属性值 4、前端 5、后端form 新增数据处理 6、更新数据处理...
Springboot集成Debezium监听postgresql变更
1.创建springboot项目引入pom <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>io.debezium</groupI…...
Ubuntu22.04搭建freeradius操作说明
Ubuntu22.04搭建freeradius操作说明 更新依赖库 sudo apt update sudo apt install build-essential sudo apt install libtalloc-dev sudo apt install libssl-dev 按照freeradius sudo apt install freeradius 修改freeradius配置 文件路径如下 /etc/freeradius/3.…...
【重装系统】全流程记录,在 MacOS 的电脑上烧录 Ubuntu 启动盘
背景 Ubuntu 无法联网,排查下来应该是网卡驱动的问题,安装驱动的过程中又缺失各种包需要网络,陷入死循环。 全流程以及相关资料 整体流程参考:【史上最全】重装ubuntu20.04系统基本环境配置 烧录启动盘启动盘插入需要重装的服务…...
去中心化金融
什么是去中心化金融 去中心化金融(Decentralized Finance,简称 DeFi)是一种基于区块链技术构建的金融系统,旨在通过去除传统金融机构(如银行、证券公司等)作为中介,提供各种金融服务。这些服务…...
centos 7 部署FTP 服务用shell 脚本搭建
#!/bin/bash# 检查是否以root身份运行脚本 if [ "$EUID" -ne 0 ]; thenecho "请以root身份运行此脚本。"exit 1 fi# 安装vsftpd yum install -y vsftpd# 启动vsftpd服务并设置开机自启 systemctl start vsftpd systemctl enable vsftpd# 配置防火墙以允许F…...
VMware启动虚拟机报“另一个程序已锁定文件的一部分,进程无法访问”
解决方案: 1)定位到虚拟机磁盘目录,我这里是“E\VM_Disk\CactiEZ\”这个目录,每个人目录不一样,详见上图报错位置 2)在这个目录中找到后缀名以“.lck”结尾的目录,将所有以 .lck 结尾的目录删…...
Python基础(正则表达式)
正则表达式使用 在 Python 中,使用 re 模块来处理正则表达式 re.match函数 import re print(re.match(www, www.baidu.com).span()) #.span():获取匹配对象的起始和结束索引,以元组形式返回 print(re.match(com, www.baidu.com))line &q…...
CPU架构和微架构
CPU架构(CPU Architecture) CPU架构是指处理器的整体设计框架,定义了处理器的指令集、寄存器、内存管理方式等。它是处理器设计的顶层规范,决定了软件如何与硬件交互。 主要特点: 指令集架构(ISA, Instr…...
基于Zookeeper的微服务配置管理与灰度发布实战指南
引言 在分布式系统中,服务注册与发现、配置管理以及平滑发布是保障系统高可用性的关键。Apache Zookeeper作为一款成熟的分布式协调服务,结合Spring Cloud生态,能够有效解决这些挑战。本文将深入探讨Zookeeper的核心配置参数、服务注册机制&…...
帕金森病致生活艰难,如何缓解心理负担?
你是否留意到身边有人手部不由自主地颤抖,且肢体变得僵硬,行动也愈发迟缓?这很可能是帕金森病的症状。帕金森病是一种常见的神经系统退行性疾病,多发生于中老年人。 静止性震颤往往是帕金森病的首发症状,患者在安静状…...
使用 fn_dblog手动恢复误操作的 update(单列数值型数据恢复)
使用 fn_dblog手动恢复误操作的 update(单列数值型数据恢复) 事由fn_dblogfn_dblog 列数据意义 事由 通常,我们在操作数据库的时候,很对 update 指令指定一个更新范围,比如指定更新某个ID的数据,指定某个类…...
ambiq apollo3 ADC实例程序注释
#include "am_mcu_apollo.h" // Apollo MCU 外设寄存器定义和HAL库 #include "am_bsp.h" // 板级支持包(引脚定义、LED函数等) #include "am_util.h" // 通用工具函数(如printf重…...
[Windows] Edge浏览器_134.0.3124.83绿色便携增强版-集成官方Deepseek侧边栏
微软Edge浏览器 绿色便携增强版 长期更新 链接:https://pan.xunlei.com/s/VOMA-aVC_GPJiv-MzRS89lsVA1?pwdemxj# Edge浏览器_134.0.3124.83绿色便携增强版-集成官方Deepseek侧边栏...
Python大数据方向就业
一、基础必备技能 1. Python编程 核心语法:熟练掌握函数、面向对象、异常处理、文件操作等。数据处理库:Pandas(数据清洗、分析)、NumPy(数值计算)、Matplotlib/Seaborn(数据可视化&…...
从零构建大语言模型全栈开发指南:第二部分:模型架构设计与实现-2.2.3实战案例:在笔记本电脑上运行轻量级LLM
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 实战案例:在笔记本电脑上运行轻量级LLM2.2.3 模型架构设计与实现1. 环境与工具准备1.1 硬件要求1.2 软件栈选择2. 轻量级模型架构设计2.1 模型参数配置2.2 关键技术优化3. 实战流程3.1 数据准备流程3.2…...
CAN基础知识学习二
一、控制器局域网总线(CAN,Controller Area Network); 二、CAN FD 是CAN with Flexible Data rate的缩写,翻译为【可变速率的 CAN】 CAN-FD 采用了两种位速率:从控制场中的 BRS 位到 ACK 场之前(…...
新能源行业:卓越 UE/UI 设计,引领业务腾飞的新引擎
在全球积极推动可持续发展的大背景下,新能源行业蓬勃兴起,成为经济发展的新引擎。在这个充满机遇与挑战的赛道上,优秀的用户体验(UE)和用户界面(UI)设计正扮演着愈发关键的角色,它不…...
Webview详解(上)
第一阶段:基础入门 WebView基础概念 什么是Webview? WebView是一种用于在移动应用程序中展示网页内容的嵌入式浏览器组件。它允许开发者将网页内容直接加载到应用界面中,用户无需离开应用即可浏览网页。WebView 通常用于加载 HTML、CSS、J…...
Docker镜像相关命令(Day2)
文章目录 前言一、问题描述二、相关命令1.查看镜像2.搜索镜像3.拉取镜像4.删除镜像5.镜像的详细信息6.标记镜像 三、验证与总结 前言 Docker 是一个开源的容器化平台,它让开发者能够将应用及其依赖打包到一个标准化的单元(容器)中运行。在 D…...
C++值传递和引用传递
系列文章目录 值传递和引用传递是 C 中两种常见的参数传递方式,它们的主要区别在于函数内部对参数的操作是否会影响原始数据 C值传递和引用传递 系列文章目录1、值传递2、引用传递3 、常量引用传递4、值传递 vs 引用传递总结 1、值传递 值传递会复制传入的参数&…...
LangChain4J开源开发框架简介
目录 1.1、前言1.2、集成方式简单1.3、核心功能与优势1.4、两种调用方式1.5、链式调用示例代码1.6、AI服务调用示例代码1.7、典型使用场景1.8、总结 1.1、前言 LangChain4J 是一个专为 Java 开发者设计的开源框架,旨在简化大型语言模型(LLMs)…...
Qt图形视图框架在项目中的应用
一、基本概念 Qt 的图形视图框架(Graphics View Framework)提供了一套用于显示和管理2D图形对象的框架。它提供了一组类,这些类可以组合使用来构建用户界面、处理图形对象、实现缩放、平移、旋转等操作。以下是Qt GraphicsView框架的主要组件…...
