NoisyNet-DQN实战:用TensorFlow2.0实现Atari游戏中的智能探索(附完整代码)
NoisyNet-DQN实战用TensorFlow 2.0在Atari游戏中实现智能探索在深度强化学习的实战领域如何让智能体在复杂环境中进行高效探索始终是一个核心挑战。传统的ε-greedy策略虽然简单但其随机性探索往往缺乏方向感可能导致学习效率低下。对于希望构建更智能、更稳定游戏AI的开发者而言理解并应用更先进的探索机制是提升模型性能的关键一步。本文将聚焦于NoisyNet-DQN这一前沿技术手把手带你用TensorFlow 2.0框架在经典的Atari游戏环境中从零构建一个具备自适应探索能力的智能体。我们将绕过繁琐的理论推导直击代码实现的核心剖析噪声层的设计细节分享训练过程中的调试技巧并最终让你获得一个可直接运行、效果显著的实战项目。1. 环境搭建与核心概念解析在开始敲代码之前我们需要先搭建一个稳定且高效的开发环境。对于深度强化学习项目环境配置的细微差别都可能导致结果迥异。我推荐使用Google Colab作为实验平台它提供了免费的GPU资源非常适合快速原型验证和实验。当然如果你有本地的高性能计算环境配置过程也大同小异。首先确保你的Python环境在3.7以上然后通过pip安装必要的依赖库。这里我们使用TensorFlow 2.x的稳定版本它相比1.x版本在易用性上有了巨大提升。pip install tensorflow2.10.0 gym[atari]0.25.2 gym[accept-rom-license] opencv-python numpy matplotlib安装完成后可以通过以下代码片段快速验证环境是否就绪特别是Atari ROM的加载功能import gym import tensorflow as tf print(fTensorFlow 版本: {tf.__version__}) print(fGPU 是否可用: {tf.config.list_physical_devices(GPU)}) # 尝试创建一个Atari环境 env gym.make(PongNoFrameskip-v4) print(f环境创建成功: {env.spec.id}) print(f动作空间: {env.action_space}) env.close()NoisyNet的核心思想非常直观将探索的随机性从策略层面如ε-greedy的动作选择转移到神经网络参数本身。传统的DQN网络权重是确定性的探索依赖于外部强加的随机策略。而NoisyNet则在网络的某些层通常是全连接层的权重和偏置中注入可学习的噪声。这些噪声参数均值和方差本身也是通过梯度下降进行优化的。这意味着智能体在学习价值函数的同时也在学习“何时该有多不确定”从而实现了一种数据驱动的、自适应的探索机制。与独立高斯噪声和分解高斯噪声两种实现方式相对应我们需要在代码层面做出选择。独立噪声为每个连接赋予独立的噪声变量参数较多分解噪声则通过分解函数减少噪声变量数量计算更高效也是原论文推荐并在实验中表现良好的方法。我们的实现将主要采用分解高斯噪声。2. 构建NoisyNet层TensorFlow 2.0实现详解理解了原理接下来就是将其转化为TensorFlow 2.0的代码。我们将以子类化tf.keras.layers.Layer的方式创建一个可重用的NoisyDense层。这种方式符合TF2.0的面向对象范式能轻松集成到任何tf.keras.Model中。首先我们实现分解高斯噪声所需的辅助函数f(x)该函数用于将标准正态分布的样本转换为合适的噪声样本。import tensorflow as tf import numpy as np class NoisyDense(tf.keras.layers.Layer): NoisyNet全连接层使用分解高斯噪声。 def __init__(self, units, use_biasTrue, activationNone, sigma_init0.5, **kwargs): super(NoisyDense, self).__init__(**kwargs) self.units units self.use_bias use_bias self.activation tf.keras.activations.get(activation) self.sigma_init sigma_init # 噪声参数σ的初始值 def build(self, input_shape): # 输入维度 input_dim int(input_shape[-1]) # 分解函数 f(x) sign(x) * sqrt(|x|) self.f lambda x: tf.sign(x) * tf.sqrt(tf.abs(x)) # 可训练参数权重和偏置的均值 (mu) 和标准差 (sigma) # 初始化方式参考论文mu ~ U[-1/sqrt(p), 1/sqrt(p)], sigma sigma_init / sqrt(p) limit 1.0 / np.sqrt(input_dim) mu_initializer tf.random_uniform_initializer(minval-limit, maxvallimit) sigma_initializer tf.constant_initializer(self.sigma_init / np.sqrt(input_dim)) # 权重参数 self.w_mu self.add_weight( namew_mu, shape(input_dim, self.units), initializermu_initializer, trainableTrue ) self.w_sigma self.add_weight( namew_sigma, shape(input_dim, self.units), initializersigma_initializer, trainableTrue ) # 偏置参数 if self.use_bias: self.b_mu self.add_weight( nameb_mu, shape(self.units,), initializermu_initializer, trainableTrue ) self.b_sigma self.add_weight( nameb_sigma, shape(self.units,), initializersigma_initializer, trainableTrue ) # 为噪声采样准备随机向量 # 在训练期间每次前向传播都会采样新的噪声 self.p None self.q None super(NoisyDense, self).build(input_shape) def call(self, inputs, trainingNone): # 仅在训练模式下注入噪声 if training: # 采样噪声向量 input_dim tf.shape(inputs)[-1] # 噪声ε_p 和 ε_q 来自标准正态分布 epsilon_p tf.random.normal(shape(input_dim, 1)) epsilon_q tf.random.normal(shape(1, self.units)) # 应用分解函数 f_epsilon_p self.f(epsilon_p) # 形状: (input_dim, 1) f_epsilon_q self.f(epsilon_q) # 形状: (1, units) # 计算权重噪声和偏置噪声 w_epsilon tf.matmul(f_epsilon_p, f_epsilon_q) # 形状: (input_dim, units) b_epsilon tf.squeeze(f_epsilon_q, axis0) # 形状: (units,) # 构造带噪声的权重和偏置 w self.w_mu self.w_sigma * w_epsilon b self.b_mu self.b_sigma * b_epsilon if self.use_bias else None else: # 评估/推理时使用确定性参数均值 w self.w_mu b self.b_mu if self.use_bias else None # 执行线性变换 output tf.matmul(inputs, w) if b is not None: output output b # 应用激活函数 if self.activation is not None: output self.activation(output) return output def get_config(self): config super(NoisyDense, self).get_config() config.update({ units: self.units, use_bias: self.use_bias, activation: tf.keras.activations.serialize(self.activation), sigma_init: self.sigma_init, }) return config注意call方法中的training参数至关重要。在训练时trainingTrue我们采样新的噪声并注入网络在评估或测试时trainingFalse我们仅使用权重的均值部分使网络行为确定化。这是NoisyNet实现探索-利用平衡的关键。为了更直观地理解不同参数初始化对训练的影响我们可以参考以下对比表格。在实际项目中根据具体游戏环境微调这些初始值有时能带来意想不到的性能提升。参数独立高斯噪声初始化分解高斯噪声初始化 (本文采用)作用与影响权重均值w_muU[-sqrt(3/p), sqrt(3/p)]U[-1/sqrt(p), 1/sqrt(p)]决定网络输出的基准值初始化影响早期学习稳定性。权重标准差w_sigma固定值 (如0.017)sigma_init / sqrt(p)控制探索的初始强度。sigma_init过大可能导致早期训练不稳定过小则探索不足。偏置参数同权重初始化方式同权重初始化方式对输出进行平移通常影响较小。噪声采样ε每个参数独立采样通过分解函数减少采样维度分解噪声大幅减少计算量是实践中的首选。3. 集成NoisyNet到DQN智能体有了NoisyDense层我们就可以构建完整的NoisyNet-DQN模型了。我们的智能体将处理Atari游戏的图像输入因此需要一个卷积神经网络CNN来提取视觉特征后面再接上带有噪声的全连接层来输出每个动作的Q值。首先我们定义一个函数来创建Q网络。这里我们采用经典的DQN架构三个卷积层后接展平操作然后是两个全连接层其中最后一个全连接层被替换为我们的NoisyDense层。def create_q_network(input_shape, num_actions, noisyTrue): 创建Q值网络模型。 inputs tf.keras.Input(shapeinput_shape) # 标准化输入 (0-255 - 0-1) x tf.keras.layers.Lambda(lambda x: x / 255.0)(inputs) # 卷积层提取特征 (与Nature DQN相同) x tf.keras.layers.Conv2D(32, 8, strides4, activationrelu)(x) x tf.keras.layers.Conv2D(64, 4, strides2, activationrelu)(x) x tf.keras.layers.Conv2D(64, 3, strides1, activationrelu)(x) x tf.keras.layers.Flatten()(x) x tf.keras.layers.Dense(512, activationrelu)(x) # 输出层使用NoisyDense或普通Dense if noisy: outputs NoisyDense(num_actions, activationNone)(x) else: outputs tf.keras.layers.Dense(num_actions, activationNone)(x) model tf.keras.Model(inputsinputs, outputsoutputs) return model接下来我们构建智能体类NoisyDQNAgent。这个类将封装经验回放、目标网络、训练循环等所有逻辑。一个关键点是由于探索机制已内置于网络参数我们完全移除了ε-greedy策略。动作选择直接基于网络输出的Q值进行贪婪选择。class NoisyDQNAgent: def __init__(self, state_shape, action_dim, lr1e-4, gamma0.99, batch_size32, buffer_size100000, target_update_freq1000, noisyTrue): self.state_shape state_shape self.action_dim action_dim self.gamma gamma self.batch_size batch_size self.target_update_freq target_update_freq self.noisy noisy # 是否使用NoisyNet # 创建在线网络和目标网络 self.online_net create_q_network(state_shape, action_dim, noisynoisy) self.target_net create_q_network(state_shape, action_dim, noisynoisy) self.target_net.set_weights(self.online_net.get_weights()) # 初始化权重相同 self.target_update_counter 0 # 优化器 self.optimizer tf.keras.optimizers.Adam(learning_ratelr, epsilon1e-4) # 经验回放缓冲区 (使用简单的环形缓冲区实现) self.buffer ReplayBuffer(buffer_size, state_shape) # 训练步数计数器 self.train_step 0 def select_action(self, state, trainingTrue): 选择动作。训练和评估时都使用贪婪策略因为探索由网络噪声负责。 # 增加批次维度 state np.expand_dims(state, axis0) # 前向传播注意传入training参数 q_values self.online_net(state, trainingtraining) # 选择最大Q值对应的动作 action tf.argmax(q_values[0]).numpy() return action def store_transition(self, state, action, reward, next_state, done): 存储经验到回放缓冲区。 self.buffer.add(state, action, reward, next_state, done) def train(self): 执行一次训练步骤。 if len(self.buffer) self.batch_size: return None # 从缓冲区采样 states, actions, rewards, next_states, dones self.buffer.sample(self.batch_size) with tf.GradientTape() as tape: # 计算当前状态的Q值 (在线网络训练模式) current_q self.online_net(states, trainingTrue) # 仅获取执行动作的Q值 action_masks tf.one_hot(actions, self.action_dim) current_q_action tf.reduce_sum(current_q * action_masks, axis1) # 计算下一个状态的最大Q值 (目标网络非训练模式 - 确定性) next_q self.target_net(next_states, trainingFalse) max_next_q tf.reduce_max(next_q, axis1) # 计算目标Q值 target_q rewards self.gamma * max_next_q * (1 - dones) # 计算Huber损失 (比MSE对异常值更鲁棒) loss tf.keras.losses.Huber()(target_q, current_q_action) # 计算梯度并更新在线网络 grads tape.gradient(loss, self.online_net.trainable_variables) self.optimizer.apply_gradients(zip(grads, self.online_net.trainable_variables)) # 定期更新目标网络 (硬更新) self.target_update_counter 1 if self.target_update_counter % self.target_update_freq 0: self.target_net.set_weights(self.online_net.get_weights()) self.train_step 1 return loss.numpy()提示经验回放缓冲区ReplayBuffer是一个标准组件其实现与普通DQN无异。它负责存储状态转移元组(s, a, r, s, done)并在训练时进行随机采样以打破数据间的相关性。这里为了简洁未列出其代码你可以使用任何可靠的实现。4. 训练流程、调试技巧与结果分析万事俱备现在我们可以启动训练了。我们以Atari的PongNoFrameskip-v4环境为例这是一个经典的乒乓球游戏智能体需要控制球拍上下移动来击球得分。训练一个成功的智能体通常需要数百万帧的交互因此耐心和正确的调试方法至关重要。首先我们编写主训练循环。为了提升训练效率并稳定学习过程我们需要对原始环境进行一系列预处理这通常通过gym.wrappers实现。import gym from collections import deque import numpy as np def make_atari_env(env_namePongNoFrameskip-v4, stack_frames4): 创建并包装Atari环境。 env gym.make(env_name) # 应用标准Atari预处理包装器 (灰度化、缩放、帧堆叠等) env gym.wrappers.AtariPreprocessing(env, frame_skip4, screen_size84, grayscale_obsTrue, scale_obsTrue) env gym.wrappers.FrameStack(env, stack_frames) return env def train_agent(env_namePong, num_episodes2000, max_steps10000): # 创建环境 env make_atari_env(f{env_name}NoFrameskip-v4) state_shape env.observation_space.shape action_dim env.action_space.n print(f状态空间形状: {state_shape}) print(f动作空间大小: {action_dim}) # 初始化智能体 agent NoisyDQNAgent(state_shapestate_shape, action_dimaction_dim, lr1e-4, batch_size32, buffer_size100000, target_update_freq1000, noisyTrue) # 设置为True以启用NoisyNet # 记录训练指标 episode_rewards [] moving_avg_rewards [] loss_history [] for episode in range(num_episodes): state env.reset() total_reward 0 episode_losses [] for step in range(max_steps): # 1. 选择并执行动作 action agent.select_action(state, trainingTrue) next_state, reward, done, _ env.step(action) # 2. 存储经验 agent.store_transition(state, action, reward, next_state, done) state next_state total_reward reward # 3. 训练智能体 loss agent.train() if loss is not None: episode_losses.append(loss) if done: break # 记录本回合结果 mean_loss np.mean(episode_losses) if episode_losses else 0 episode_rewards.append(total_reward) # 计算最近100回合的平均奖励 avg_reward np.mean(episode_rewards[-100:]) moving_avg_rewards.append(avg_reward) loss_history.append(mean_loss) # 定期输出日志 if episode % 50 0: print(fEpisode {episode:4d} | fTotal Reward: {total_reward:6.1f} | fAvg Reward (last 100): {avg_reward:6.2f} | fAvg Loss: {mean_loss:.4f} | fBuffer Size: {len(agent.buffer):6d} | fTrain Steps: {agent.train_step}) # 简单的提前终止条件如果平均奖励持续很高 if avg_reward 18.0 and episode 100: # Pong游戏满分是21分 print(fSolved at episode {episode}! Average reward reached {avg_reward}.) break env.close() return agent, episode_rewards, moving_avg_rewards, loss_history运行上述训练脚本你将会看到智能体从完全随机开始逐渐学会玩转Pong游戏的过程。然而训练过程很少一帆风顺。下面是一些我实践中总结的关键调试技巧和常见问题排查点训练初期奖励不增长这是最常遇到的问题。首先检查环境预处理是否正确特别是帧堆叠Frame Stacking是否提供了必要的时序信息。其次检查学习率是否过高尝试将其降低到5e-5或1e-5。最后确保经验回放缓冲区有足够数据通常大于1万条后才开始训练。损失值剧烈波动或变为NaN这通常意味着梯度爆炸。可以尝试以下方法梯度裁剪Gradient Clipping在优化器应用梯度前对梯度范数进行限制。降低sigma_init的值减少噪声的初始强度。检查奖励是否未进行适当的缩放。Atari游戏的原始奖励差异可能很大可以考虑对奖励进行裁剪如限制在[-1, 1]或标准化。探索不足或过度NoisyNet的探索强度由噪声参数σ控制。如果智能体似乎陷入局部最优探索不足可以适当增大sigma_init。如果智能体行为过于随机长期无法学习到有效策略过度探索则减小sigma_init。一个有趣的观察点是随着训练进行网络学到的σ值通常会逐渐减小这反映了智能体从探索到利用的自然过渡。目标网络更新频率对于Atari游戏每1000到10000步更新一次目标网络是常见设置。更新太频繁可能导致训练不稳定更新太慢则可能阻碍学习。可以将其作为一个超参数进行微调。为了更系统地监控训练过程我建议实时绘制几个关键指标。下面是一个简单的可视化示例你可以将其集成到训练循环中import matplotlib.pyplot as plt def plot_training_progress(rewards, avg_rewards, losses): fig, axes plt.subplots(1, 3, figsize(15, 4)) axes[0].plot(rewards, alpha0.6, label每回合奖励) axes[0].plot(avg_rewards, linewidth2, label移动平均奖励 (100回合)) axes[0].set_xlabel(回合数) axes[0].set_ylabel(奖励) axes[0].legend() axes[0].grid(True, alpha0.3) axes[1].plot(losses) axes[1].set_xlabel(回合数) axes[1].set_ylabel(平均损失) axes[1].set_yscale(log) # 对数尺度便于观察变化 axes[1].grid(True, alpha0.3) # 可以额外绘制噪声参数σ的变化 (需要从模型中提取) # 这里假设你能访问到online_net中NoisyDense层的w_sigma参数 # axes[2].plot(sigma_history) # axes[2].set_xlabel(训练步数) # axes[2].set_ylabel(噪声参数σ均值) # axes[2].grid(True, alpha0.3) plt.tight_layout() plt.show()在实际训练Pong约50万步约800-1000回合后你应该能看到移动平均奖励从初始的-21分一直输球稳步上升最终稳定在18-21分意味着能稳定战胜内置AI。这个过程中损失函数会先上升后下降并逐渐趋于平稳表明网络正在有效地学习和收敛。与传统的ε-greedy DQN相比NoisyNet-DQN通常能更快地达到高性能并且在训练后期更加稳定因为其探索是定向的、与价值估计的不确定性相关联的而非完全随机。你可以通过设置agent NoisyDQNAgent(..., noisyFalse)并配合ε-greedy策略来运行一个对照实验亲自验证这一差异。最后保存训练好的模型以便后续评估或部署是必不可少的步骤。TensorFlow 2.0提供了便捷的保存方式# 保存整个模型 agent.online_net.save(noisy_dqn_pong_model.h5) # 或只保存权重 agent.online_net.save_weights(noisy_dqn_pong_weights.weights.h5) # 加载模型 loaded_model tf.keras.models.load_model(noisy_dqn_pong_model.h5, custom_objects{NoisyDense: NoisyDense})在评估模式下运行智能体时记得将trainingFalse传入网络和动作选择函数以确保使用的是确定性的权重均值从而得到稳定、贪婪的策略表现。通过这个从理论到代码、从构建到调试的完整流程你不仅实现了一个强大的NoisyNet-DQN智能体更掌握了解决深度强化学习实际工程问题的系统方法。

相关新闻

Ubuntu20.04下PCL 1.10安装避坑指南:从apt源配置到版本验证

Ubuntu20.04下PCL 1.10安装避坑指南:从apt源配置到版本验证

Ubuntu 20.04 下 PCL 1.10 安装避坑指南:从源配置到实战验证 最近在机器人、三维视觉或者点云处理领域折腾的朋友,估计都绕不开一个名字——PCL。全称是 Point Cloud Library,一个功能强大到让人又爱又恨的开源库。爱它,是因为它封…

2026/7/6 3:06:10 阅读更多 →
多模态融合新思路:POE模型在图像与文本联合建模中的应用

多模态融合新思路:POE模型在图像与文本联合建模中的应用

多模态融合新思路:POE模型在图像与文本联合建模中的应用 最近和几位做内容理解的朋友聊天,大家不约而同地提到了一个痛点:现有的多模态模型,无论是CLIP式的对比学习,还是BLIP式的生成式预训练,在处理图像和…

2026/5/17 8:59:53 阅读更多 →
AI Agent记忆系统避坑指南:从AutoContextMemory到Mem0的工程实践

AI Agent记忆系统避坑指南:从AutoContextMemory到Mem0的工程实践

AI Agent记忆系统避坑指南:从AutoContextMemory到Mem0的工程实践 最近在搭建一个能真正“记住”用户的智能助手时,我踩了不少坑。一开始,我天真地以为给Agent加上一个向量数据库,把历史对话往里一存,就能实现所谓的“长…

2026/5/17 8:59:52 阅读更多 →

最新新闻

普通显卡也能虚拟化?揭秘vgpu_unlock如何打破NVIDIA的限制

普通显卡也能虚拟化?揭秘vgpu_unlock如何打破NVIDIA的限制

普通显卡也能虚拟化?揭秘vgpu_unlock如何打破NVIDIA的限制 【免费下载链接】vgpu_unlock Unlock vGPU functionality for consumer grade GPUs. 项目地址: https://gitcode.com/gh_mirrors/vg/vgpu_unlock 你是否曾经想过,为什么你的GeForce RTX …

2026/7/7 23:36:41 阅读更多 →
UE5 FString::Printf 与 Format 实战对比:3种场景下的性能与易用性分析

UE5 FString::Printf 与 Format 实战对比:3种场景下的性能与易用性分析

UE5 FString::Printf 与 Format 深度对比:性能优化与工程实践指南1. 核心机制解析在Unreal Engine的字符串处理体系中,FString::Printf和FString::Format代表着两种截然不同的设计哲学。Printf源自传统C语言的printf风格,采用可变参数和类型占…

2026/7/7 23:34:40 阅读更多 →
基于PIC18LF26K22与压电蜂鸣器的工业警报模块设计

基于PIC18LF26K22与压电蜂鸣器的工业警报模块设计

1. 项目背景与核心需求在工业控制、安防系统和智能家居等领域,清晰可靠的警报系统是不可或缺的基础组件。我最近完成了一个基于EPT-14A4005P压电蜂鸣器和PIC18LF26K22微控制器的通用警报模块开发项目,这个方案能在-40C到85C的宽温范围内稳定工作&#xf…

2026/7/7 23:30:37 阅读更多 →
Poppins字体完整指南:免费开源的多语言几何字体解决方案

Poppins字体完整指南:免费开源的多语言几何字体解决方案

Poppins字体完整指南:免费开源的多语言几何字体解决方案 【免费下载链接】Poppins Poppins, a Devanagari Latin family for Google Fonts. 项目地址: https://gitcode.com/gh_mirrors/po/Poppins 在多语言项目开发中,字体选择常常成为技术团队面…

2026/7/7 23:24:35 阅读更多 →
PyTorch LSTM 多变量多任务预测:3种损失加权策略对比与MAPE优化

PyTorch LSTM 多变量多任务预测:3种损失加权策略对比与MAPE优化

PyTorch LSTM多变量多任务预测:3种损失加权策略对比与MAPE优化实战在工业预测、金融分析和环境监测等场景中,我们经常需要同时预测多个相关变量。传统单任务学习模型需要为每个变量单独训练,不仅效率低下,还忽略了变量间的潜在关联…

2026/7/7 23:22:32 阅读更多 →
IAR EWARM历史版本安装实战:嵌入式产线环境复现指南

IAR EWARM历史版本安装实战:嵌入式产线环境复现指南

1. 为什么老工程师还在用 IAR for ARM?——不是守旧,而是嵌入式开发的现实约束在当下 VS Code CMake GCC 工具链大行其道的年代,你可能很难理解:为什么还有大量工业控制、汽车电子、医疗设备领域的项目,依然死死卡在…

2026/7/7 23:20:32 阅读更多 →

日新闻

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

图片浏览是移动应用中最高频的场景之一。从社交应用的照片流到电商平台的商品图集,从旅游应用的景点相册到摄影作品展示——用户对图片浏览的体验要求不断提高:流畅的切换动画、直观的缩略图导航、便捷的收藏操作、自动播放模式。HarmonyOS NEXT ArkUI 虽…

2026/7/7 0:05:16 阅读更多 →
24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V稳压芯片完整选型指南 PW8600 PW75XX PW2815 PW2312B LDODC/DC全方案 一、24V稳压方案概述 24V直流电源在工业自动化、门禁系统、电梯控制、汽车电子、LED驱动、监控设备等场景中应用极广,是最常见的中压直流母线电压。要将24V母线稳定降压至下游MCU、传感器…

2026/7/7 0:05:16 阅读更多 →
RAG+知识图谱混合检索与Graph RAG核心对比

RAG+知识图谱混合检索与Graph RAG核心对比

做企业RAG落地的团队,往往容易卡在一容易踩坑的选型难题: 当需求单纯靠向量RAG搞不定、单纯靠知识图谱也搞不定,必须同时依赖「文本语义理解 实体关系推理」时,到底是做「向量图谱混合检索」就够了,还是必须上「Grap…

2026/7/7 0:07:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/7 14:24:45 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/7 12:34:47 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/7 15:59:06 阅读更多 →

月新闻