从策略梯度到A2C:Actor-Critic家族推导与TensorFlow 2.0实现
这段时间集中刷了几篇强化学习论文越看越觉得很多同学一上来就扑向PPO或者SAC反而少了一条关键的推导链策略梯度Policy Gradient是怎么一步一步变成Actor-Critic再到A3C和A2C的。我自己也是踩了不少坑才把这条主线串起来。这次打算开一个论文阅读系列第一篇就用这个标题把从PG到AC、A3C、A2C的理论推导和TensorFlow 2.0代码实现一起整理出来。如果你是刚接触深度强化学习、已经看过DQN但被策略梯度一堆公式劝退或者想跑通一个能用的AC类算法但不知道从哪下手那这篇文章基本就是按你的需求写的。我会尽量把“每个公式为什么长这样”讲清楚而不是只丢结论。代码部分用TensorFlow 2.0实现了一个可以跑在CartPole上的A2C完整可复现。1. 为什么我选择这条“论文阅读”路线1.1 从DQN转向策略梯度的原因我最早接触深度RL是从DQN开始的网络输出每个动作的Q值然后选最大那个。这套逻辑在离散动作空间里挺好用但一旦遇到连续控制问题就卡住了动作空间太大甚至无限argmax根本没法做。更麻烦的是DQN虽然能通过经验回放稳定训练但它在策略上天然是off-policy的后续想加一点策略约束各种不适应就冒出来了。于是我把目光转回策略梯度这条线。策略梯度不显式估计动作值函数然后取max而是让网络直接输出动作分布、在这个分布上采样再根据回报好坏调整概率。这种方式天生适合连续控制而且policy本身就在网络结构里后续加熵正则、KL约束都顺理成章。可以说从PG到AC、A3C、A2C甚至到PPO和SAC这条线把深度RL的一大半算法都串起来了。1.2 这条主线的知识地图很多教程喜欢按年份陈述2014年出了什么2016年又出了什么。但我更推荐“缺陷驱动”的读法也就是每一步都先搞清楚上一个方法哪里不够用下一个方法到底修了什么。PGPolicy Gradient直接用轨迹总回报加权无偏但方差爆炸。Baseline引入状态相关基线在不改变期望的前提下压低方差。Actor-Critic用价值网络充当基线优势估计器方差进一步降低。A3C/A2C解决on-policy训练时的采样效率问题前者异步后者同步。GAE给优势估计加了一个可以调节偏差方差权衡的旋钮。读完这条线再去看PPO你会发现PPO其实就是A2C/GAE再加一个对策略更新幅度的约束理解成本会低非常多。所以这篇系列第一篇我先把地基打扎实。2. PG推导REINFORCE估计量、baseline与高方差困局2.1 目标函数与一句关键的log-derivative trick策略梯度要优化的目标一般写成期望回报$$ J(\theta) \mathbb{E}{\tau \sim \pi\theta} \left[ \sum_{t0}^{T-1} \gamma^t r_t \right] $$这里 $\tau$ 是轨迹也就是状态、动作、奖励的序列。我们希望让 $\theta$ 朝着增大 $J(\theta)$ 的方向移动所以要求梯度。但问题在于轨迹是从环境采样得到的里面有环境转移的随机性也有策略自身的随机性没法直接对采样过程求导。解决办法是大家熟知的log-derivative trick。对策略概率求导时做一步变换$$ \nabla_\theta \pi_\theta(a|s) \pi_\theta(a|s) \nabla_\theta \log \pi_\theta(a|s) $$这个式子看起来就是简单的导数恒等式但它把“对策略函数求导”变成了“对log概率求导”而log概率是网络可以直接给的采样时也能算出来。把整个轨迹的展开写进去经过几行推导可以得到$$ \nabla_\theta J(\theta) \mathbb{E}{\tau \sim \pi\theta} \left[ \sum_{t0}^{T-1} \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot R(\tau) \right] $$这里的 $R(\tau)$ 是整个轨迹的累计折扣回报。这个形式就是REINFORCE估计量的基础也是策略梯度所有后续变体的出发点。2.2 baseline为什么能压方差而无偏REINFORCE直接用 $R(\tau)$ 做权重理论上没问题但实践上方差大到没法收敛。原因是 $R(\tau)$ 是一连串随机变量的和每一步的策略随机性和环境随机性都会叠加进去。同一个状态下即使策略完全相同跑两条轨迹得到的回报也可能天差地别。这时候梯度方向基本被噪声主导网络根本学不出稳定信号。一个经典修法是为每个状态减去一个基线 $b(s)$$$ \nabla_\theta J(\theta) \mathbb{E}{\tau \sim \pi\theta} \left[ \sum_{t0}^{T-1} \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot \left(R_t - b(s_t)\right) \right] $$为什么减去基线不改变期望因为$$ \mathbb{E}{a \sim \pi\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \cdot b(s) \right] b(s) \sum_a \nabla_\theta \pi_\theta(a|s) b(s) \nabla_\theta 1 0 $$也就是说基线项对梯度的期望贡献是零它不会让策略往错误方向偏移但能大幅降低不同轨迹之间的波动幅度。这一步其实就是AC的雏形如果不想要方差就引入一个和状态相关、能预测“大概能拿多少回报”的基线函数。2.3 从R到Q留给AC的伏笔继续往下想$R_t$ 本质上是对“当前状态下采取某个动作后能拿到多少回报”的一次采样估计。如果我们能直接估计这个量的期望那就更稳了。这个期望就是动作价值函数 $Q^\pi(s,a)$。于是策略梯度可以改写成$$ \nabla_\theta J(\theta) \mathbb{E}\left[ \nabla_\theta \log \pi_\theta(a|s) \cdot Q^\pi(s,a) \right] $$但 $Q^\pi(s,a)$ 本身也是未知的。该怎么办最直接的想法是用另一个网络去拟合它。到这里AC框架的逻辑就自然浮出水面了一个网络负责策略一个网络负责价值估计。下一章详细讲这个切换过程。3. Actor-Critic登场用价值函数改写策略梯度3.1 Critic的“裁判”定位Actor-Critic这个命名非常形象。Actor就是策略网络 $\pi_\theta$它负责决定动作像一个上场比赛的选手。Critic就是价值网络 $V_\omega(s)$它负责打分像一个站在场边的裁判“这个状态下你平均能拿多少分我心里有数。”关键是Critic给出的分数不是用来直接选动作的而是作为PG公式里的baseline和优势估计。前面说了baseline应该取 $V(s)$ 最好那么优势函数自然定义为$$ A^\pi(s,a) Q^\pi(s,a) - V^\pi(s) $$它的含义是“在状态 $s$ 下选动作 $a$相对平均水平到底好多少”。如果好就让这个动作的概率增大如果不好就压低概率。这个直觉比直接用回报加权要清晰得多训练也稳定得多。此时策略梯度写成$$ \nabla_\theta J(\theta) \mathbb{E}\left[ \nabla_\theta \log \pi_\theta(a|s) \cdot A^\pi(s,a) \right] $$3.2 优势函数和TD误差的连接问题来了$A^\pi(s,a)$ 需要同时知道 $Q$ 和 $V$如果各用一个网络结构复杂且方差更大。有没有办法只用一个价值网络就近似优势有答案就是TD误差。定义$$ \delta_t r_t \gamma V_\omega(s_{t1}) - V_\omega(s_t) $$对它取条件期望$$ \mathbb{E}\left[\delta_t \mid s_t, a_t\right] r_t \gamma \mathbb{E}\left[V_\omega(s_{t1})\right] - V_\omega(s_t) \approx Q^\pi(s_t, a_t) - V^\pi(s_t) A^\pi(s_t, a_t) $$这个近似非常实用Critic只需要维护一个价值网络 $V_\omega$它一边充当baseline一边通过TD误差充当优势估计器。Actor拿这个优势值去更新策略Critic自己则用TD目标去回归。训练时两个网络交替优化整体就是一个标准的AC结构。这里要特别注意一个细节TD误差使用了bootstrap也就是拿 $V_\omega(s_{t1})$ 去估计未来回报。bootstrap的好处是方差低、学习快坏处是引入了估计偏差尤其是价值网络还不准的时候。这也是后来GAE等一堆改进要解决的问题。3.3 偏差与方差的权衡GAE的思路如果完全走蒙特卡洛用整条轨迹的真实回报作为目标无偏但方差大如果完全走一步TD方差小但有偏。怎么在两者之间挑一个平衡点A3C论文里用的办法是n-step回报也就是向前看 $n$ 步剩下的用价值函数bootstrap$$ R_t \sum_{i0}^{n-1} \gamma^i r_{ti} \gamma^n V_\omega(s_{tn}) $$它能综合多步真实奖励和最终的价值估计效果比单步TD好很多。后来的GAEGeneralized Advantage Estimation更进一步把1-step、2-step、一直到无穷步的优势估计用 $\lambda$ 指数加权组合起来$$ A_t \sum_{l0}^{\infty} (\gamma\lambda)^l \delta_{tl} $$$\lambda0$ 时退化成一步TD$\lambda1$ 时接近蒙特卡洛。理解这条线之后你会发现GAE其实就是给AC加了一个可调节的偏差方差旋钮。这也是为什么后来PPO、TRPO都离不开GAE。4. A3C与A2C异步并行和同步更新的设计哲学4.1 论文动机相关性与采样效率的双重压力AC框架解决了方差问题但on-policy算法还有一个原生痛点每次更新完策略刚才采的那些轨迹就“过期”了不能像DQN那样存进经验回放池反复用。这就导致训练时每更新一步都要重新采样环境交互速度直接成为瓶颈。你可能会问DQN的经验回放不是能解决相关问题吗确实可以但它有一个隐性代价回放池里的数据来自旧策略而更新用的梯度来自当前策略两者不一致会让更新方向产生偏差。AC这类on-policy算法如果强行用回放训练很容易不稳定。A3C的核心思路是不用回放池而是开多个并行环境。每个worker有自己独立的环境副本各采各的样各算各的梯度然后异步更新到同一个全局模型上。并行带来的数据多样性天然打散相关性同时采样效率也提上去了。4.2 A3C的三个核心设计n-step、异步更新与熵正则A3C全称是Asynchronous Advantage Actor-Critic字面上就把关键点写完了异步、优势、AC。除了并行框架它还带了两个细节设计。第一个是n-step回报。每个worker在环境中连续采样 $n$ 步然后计算目标值$$ R_t \sum_{i0}^{n-1} \gamma^i r_{ti} \gamma^n V_\omega(s_{tn}) $$这比单步TD信息更丰富比完整蒙特卡洛方差更小而且因为每 $n$ 步才更新一次通信和更新频率也降下来了。第二个是熵正则项。在loss里加上一项 $-\beta H(\pi_\theta(\cdot|s))$其中 $H$ 是策略分布的信息熵。加熵的目的是防止策略过早变成一个“确定性的闷头策略”鼓励它继续探索。如果策略完全确定熵项就会一直惩罚它。论文里还有一个被反复提及的观点异步更新会造成全局模型参数滞后但这种延迟反而像一种隐式的正则化让不同worker能探索到更不一样的数据区域整体训练鲁棒性反而好。不过这个说法更多是经验观察理论保证并不强。4.3 A2C去掉异步后的收益与代价A2CAdvantage Actor-Critic常常被误解为A3C的升级版其实它是A3C的同步简化版。做法很简单多个worker依然并行采样但每个worker算完梯度之后不直接更新全局模型而是等所有worker的梯度都到齐取平均后再统一更新一次。这样一来更新每一步对应的是多个环境并行采样的一批数据相当于一个天然的大batch。梯度经过平均后噪声更小训练曲线更平滑也更容易复现。异步版本虽然理论上更快但实际调试时你会被各种问题折磨有的worker更新快有的慢、梯度互相覆盖、结果跑几次不一致这些问题在同步版里基本不存在。我在实际对比中倾向于这样总结如果硬件资源足够直接用A2C配合多环境并行采样稳定性和复现性都比A3C好A3C更适合在分布式、多机环境下压榨采样吞吐。下面是两者的一个粗略对比维度A3CA2C更新方式异步各自push梯度同步梯度取平均后更新数据效率并行采样吞吐高并行采样吞吐高梯度噪声较大但有时有正则效果较小训练更平滑调试难度较高复现性一般较低容易调参适用场景分布式、带宽受限单机多环境、研究实验5. TensorFlow 2.0代码实现一个能跑的A2C与调参笔记5.1 网络结构与损失函数三个loss如何拼在一起代码部分我用TensorFlow 2.0实现A2C。环境用gym库的CartPole-v1倒立摆任务动作空间是离散的但算法流程对连续动作空间同样适用后续换网络输出层即可。先定义Actor-Critic网络。我选择共享两个全连接层然后分叉输出策略分布和价值这种结构在CartPole这种小任务上收敛很快import numpy as np import tensorflow as tf import gym GAMMA 0.99 LR 1e-4 ENTROPY_BETA 0.01 N_STEPS 5 N_EPOCHS 400 CLIP_NORM 0.5 env gym.make(CartPole-v1) n_actions env.action_space.n class ActorCritic(tf.keras.Model): def __init__(self, n_actions): super().__init__() self.common tf.keras.Sequential([ tf.keras.layers.Dense(128, activationrelu), tf.keras.layers.Dense(128, activationrelu), ]) self.policy tf.keras.layers.Dense(n_actions, activationsoftmax) self.value tf.keras.layers.Dense(1) def call(self, obs, trainingNone): x self.common(obs, trainingtraining) probs self.policy(x) value self.value(x) return probs, value网络输出两部分probs是动作概率分布value是当前状态的估计价值。之所以共享底层是因为状态特征对策略和价值的初步提取是一致的在小任务里足够用。如果任务更复杂也可以拆成两个完全独立的网络。总损失由三部分组成actor_loss -tf.reduce_mean(chosen_log_probs * tf.stop_gradient(advantages)) critic_loss tf.reduce_mean(tf.square(targets - values)) entropy_loss -tf.reduce_mean(tf.reduce_sum(probs * log_probs, axis1)) total_loss actor_loss 0.5 * critic_loss - ENTROPY_BETA * entropy_lossactor_loss用优势值加权策略的log概率目标是让好动作概率变大、坏动作概率变小。critic_loss是价值网络和TD目标之间的MSE回归。entropy_loss乘以一个负号最大化策略熵鼓励探索。critic loss系数取0.5是常见做法避免价值网络的梯度压过策略网络。5.2 rollout采集与n-step目标的计算A2C每次更新前需要采一段rollout。我每次向前走N_STEPS步把这5步的状态、动作、奖励、结束标志收集起来最后再额外计算最后一个状态的价值作为bootstrap值def run_rollout(model, env, n_steps): states, actions, rewards, dones [], [], [], [] state env.reset() episode_rewards [] episode_total 0 for _ in range(n_steps): obs np.array([state], dtypenp.float32) probs, _ model(obs) action np.random.choice(n_actions, pprobs.numpy()[0]) next_state, reward, done, _ env.step(action) states.append(state) actions.append(action) rewards.append(reward) dones.append(done) episode_total reward if done: state env.reset() episode_rewards.append(episode_total) episode_total 0 else: state next_state _, last_value model(np.array([state], dtypenp.float32)) last_value last_value[0, 0].numpy() return states, actions, rewards, dones, last_value, episode_rewards这里有一个非常容易踩的坑如果某一时刻环境已经donen-step回报就不能再往后bootstrap了否则会把一个已经结束的episode的后续价值硬塞进来污染目标值。所以计算目标时要乘上(1 - done)def compute_targets(rewards, dones, last_value): n len(rewards) targets np.zeros(n, dtypenp.float32) running last_value for i in reversed(range(n)): running rewards[i] GAMMA * running * (1 - dones[i]) targets[i] running return targets从后往前跑running会逐步把未来折扣回报叠上来。因为N_STEPS只有5这里的bootstrap尾巴其实不长偏差不会太大实现也简单。5.3 训练主循环与梯度裁剪接下来是训练主循环。每次用tf.GradientTape计算总loss对模型参数的梯度然后应用到模型上optimizer tf.keras.optimizers.Adam(learning_rateLR) model ActorCritic(n_actions) for epoch in range(N_EPOCHS): states, actions, rewards, dones, last_value, ep_rewards run_rollout(model, env, N_STEPS) targets compute_targets(rewards, dones, last_value) states_t tf.convert_to_tensor(np.array(states, dtypenp.float32)) actions_t tf.convert_to_tensor(np.array(actions, dtypenp.int32)) targets_t tf.convert_to_tensor(targets, dtypetf.float32) with tf.GradientTape() as tape: probs, values model(states_t, trainingTrue) values tf.squeeze(values, axis1) log_probs tf.math.log(tf.clip_by_value(probs, 1e-10, 1.0)) action_mask tf.one_hot(actions_t, depthn_actions) chosen_log_probs tf.reduce_sum(action_mask * log_probs, axis1) advantages targets_t - values advantages tf.stop_gradient((advantages - tf.reduce_mean(advantages)) / (tf.math.reduce_std(advantages) 1e-8)) actor_loss -tf.reduce_mean(chosen_log_probs * advantages) critic_loss tf.reduce_mean(tf.square(targets_t - values)) entropy -tf.reduce_sum(probs * log_probs, axis1) total_loss actor_loss 0.5 * critic_loss - ENTROPY_BETA * tf.reduce_mean(entropy) grads tape.gradient(total_loss, model.trainable_variables) grads, _ tf.clip_by_global_norm(grads, CLIP_NORM) optimizer.apply_gradients(zip(grads, model.trainable_variables)) if epoch % 20 0: avg_reward np.mean(ep_rewards) if ep_rewards else 0 print(fepoch {epoch}, actor_loss {actor_loss.numpy():.3f}, avg_episode_reward {avg_reward:.1f})两点需要特别说明。一是advantages计算出来后要用tf.stop_gradient包住确保优势值不会把梯度传回价值网络再混入策略更新否则actor和critic的梯度路径会纠缠训练会变怪。二是梯度裁剪这一步在RL里几乎是必需品PG类算法对更新步长很敏感一次梯度爆炸就可能毁掉几十轮训练的成果。5.4 实验观察、踩坑记录与扩展方向这个A2C在CartPole上通常几百轮训练后平均回合奖励就能冲到500分环境满分。我手上跑过几组随机种子收敛速度略有差别但整体都能稳定到满分的阈值。几个关键超参数的经验值学习率建议在1e-4到3e-4之间太大会震荡熵系数0.01比较合适太大策略始终随机太小容易早熟N_STEPS5到20之间都算合理步数多了目标偏差小但更新频率低。一个小观察如果发现训练曲线时高时低、reward波动特别大优先检查advantage有没有做标准化和stop_gradient而不是急着调模型结构。这两个细节对稳定性的影响比换网络层数大得多。如果想把这段代码改成真正的A3C核心改动就两个每个worker维护一份local model副本开始采样前从global model拉取参数采样结束后计算梯度直接apply_gradients到global model。TensorFlow 2.0里可以靠多线程配合tf.Variable实现但你大概率会遇到Python GIL带来的性能瓶颈多线程加速有限而多进程又需要序列化传参数反而更慢。这也是我在实际项目里更推荐A2C的原因单机场景下向量化多环境采样配合同步更新的性价比远比强行异步要高。5.5 一些想补充的实战建议如果这系列后面几篇要接PPO或者SAC我的建议是你现在就把A2C的代码多跑几遍试着改改GAMMA、N_STEPS、ENTROPY_BETA观察训练曲线的变化。强化学习的算法结构看起来都挺简单但只有亲手调过超参才会理解为什么GAE、熵正则这些看似小零件的设计能对训练产生这么大影响。我自己经常用的一个习惯是在跑任何AC系算法之前先在纸上手写一遍优势函数和TD目标的关系再打开代码对着看。写多了之后即使换到新框架核心逻辑也基本能一眼看穿。毕竟A3C和A2C真正难的地方不在代码而在于理解它们各自在样本相关性和更新稳定性之间做出的取舍。

相关新闻

Oracle EBS R12.1 Linux部署避坑指南:内核调优、SELinux与数据库迁移实战

Oracle EBS R12.1 Linux部署避坑指南:内核调优、SELinux与数据库迁移实战

简介:本资源是一份面向Oracle EBS系统工程师与DBA的生产级部署实战指南,聚焦R12.1.1至R12.1.3版本在Linux环境下的全链路安装、升级与调优,专为具备Linux和Oracle数据库基础的技术人员设计,解决生产环境中OS配置、EBS安装、数据库…

2026/10/14 17:50:14 阅读更多 →
LL(1)语法分析器实战:C++手写预测分析表与栈驱动实现

LL(1)语法分析器实战:C++手写预测分析表与栈驱动实现

简介:本资源是一份面向编译原理课程学习者的语法分析实验教学文档,适用于计算机专业本科生及编程语言基础实践者,聚焦于将词法分析结果进一步进行结构化语法检查与解析。文档完整覆盖LL(1)文法设计、预测分析表构建、C实现细节及典型算术表达…

2026/10/14 17:49:13 阅读更多 →
Linux内核DMA驱动开发:从映射API到cache一致性填坑指南

Linux内核DMA驱动开发:从映射API到cache一致性填坑指南

外设要持续往内存灌数据、或者要读取大块内存数据时,CPU要么疯狂轮询寄存器,要么全程参与搬运和拷贝,这两条路在高速场景下都是灾难。做驱动的人迟早会碰到DMA——直接内存访问,它让外设和内存之间建立一条不经过CPU逐字节搬运的通…

2026/10/14 17:49:13 阅读更多 →

最新新闻

Faust 1.11.0 变更深度解析:窗口表异步回调、HTTP 状态码转发与依赖升级

Faust 1.11.0 变更深度解析:窗口表异步回调、HTTP 状态码转发与依赖升级

流处理消息队列后端 【免费下载链接】faust Python Stream Processing 项目地址: https://gitcode.com/gh_mirrors/fa/faust 点击查看 免费下载 本篇文章以 Faust 项目根目录下的 Changelog.rst(即最新版变更说明)为主体,逐条拆解…

2026/10/14 18:39:59 阅读更多 →
麻将源码拆解:从Cocos Creator状态机到胡牌AI的完整实现

麻将源码拆解:从Cocos Creator状态机到胡牌AI的完整实现

简介:一套基于cocos Creator开发的完整麻将游戏源码,面向希望快速上手麻将类项目或深入理解游戏逻辑的中高级开发者,可直接用于学习、二次开发或商用参考。压缩包为rar格式,共2000个文件,约46.44MB,主要包含…

2026/10/14 18:39:59 阅读更多 →
精确生辰八字排盘核心算法:立春、子时与真太阳时

精确生辰八字排盘核心算法:立春、子时与真太阳时

简介:这份《时间转换成精确的生辰八字》Java项目,主要面向具备基础Java语法、同时对命理周易感兴趣的开发者,用来解决公历时间自动换算成年月日时四柱干支的常见需求,可应用于星座运势、命理分析等工具的底层模块。项目不仅输出完…

2026/10/14 18:39:59 阅读更多 →
Unity快递物流查询实战:接口选型、异步请求与轨迹渲染全解析

Unity快递物流查询实战:接口选型、异步请求与轨迹渲染全解析

1. 为什么要在Unity里查快递,而不是跳个网页了事做过带电商模块或者生活服务类小游戏的朋友,大概率都遇到过这个需求:玩家在游戏里下单买了实体周边,或者完成某个任务兑换了实物奖品,接下来就得让他能查到东西到哪了。…

2026/10/14 18:39:59 阅读更多 →
分光计仿真实验操作指南:调节、读数与避坑要点

分光计仿真实验操作指南:调节、读数与避坑要点

简介:大学物理仿真实验软件6(分光计实验)是面向高校物理课程设计的虚拟仿真工具,适合学生预习、课后自学及教师课堂演示,帮助学习者在不接触真实仪器的情况下掌握分光计调节、光谱观测与波长测量方法。压缩包为RAR格式…

2026/10/14 18:39:59 阅读更多 →
华为基带芯片发展解析:从2G到5G的技术演进与工程实践

华为基带芯片发展解析:从2G到5G的技术演进与工程实践

1. 基带芯片到底在做什么:从一个被忽略的核心器件说起很多人聊手机、聊基站、聊通信设备,注意力基本都放在处理器跑分、摄像头像素、屏幕刷新率这些看得见摸得着的地方。但真正决定一台设备能不能打电话、能不能上网、信号稳不稳的,其实是一颗…

2026/10/14 18:38:58 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →