spikingjelly.activation_based.functional.learning 源代码

from __future__ import annotations

import math
from collections.abc import Callable

import torch


__all__ = [
    "stdp_linear_step",
    "mstdp_linear_step",
    "mstdpet_linear_step",
    "stdp_conv1d_step",
    "stdp_conv2d_step",
    "mstdpet_reward_step",
]


def _identity(x: torch.Tensor) -> torch.Tensor:
    return x


[文档] def stdp_linear_step( in_spike: torch.Tensor, out_spike: torch.Tensor, trace: tuple[torch.Tensor, torch.Tensor], weight: torch.Tensor, *, tau_pre: float, tau_post: float, f_pre: Callable[[torch.Tensor], torch.Tensor] = _identity, f_post: Callable[[torch.Tensor], torch.Tensor] = _identity, ) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]: r""" **API Language** - :ref:`中文 <functional_stdp_linear_step-cn>` | :ref:`English <functional_stdp_linear_step-en>` ---- .. _functional_stdp_linear_step-cn: * **中文** 执行全连接权重的单步 STDP 更新。``trace`` 是 ``(trace_pre, trace_post)``;函数先更新两个 trace,再用更新后的 trace 计算权重增量,返回 ``(delta_w, trace_next)``。输入状态不会被原地修改。 .. math:: tr_{pre}^{t+1} &= tr_{pre}^{t} - tr_{pre}^{t} / \tau_{pre} + s_{pre}^{t} \\ tr_{post}^{t+1} &= tr_{post}^{t} - tr_{post}^{t} / \tau_{post} + s_{post}^{t} :param in_spike: 输入脉冲,形状 ``[N, in_features]`` :type in_spike: torch.Tensor :param out_spike: 输出脉冲,形状 ``[N, out_features]`` :type out_spike: torch.Tensor :param trace: 当前 ``(trace_pre, trace_post)``,两者分别与 ``in_spike`` 和 ``out_spike`` 同形状、同 device,且 dtype 可参与对应计算 :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: 权重,形状 ``[out_features, in_features]`` :type weight: torch.Tensor :param tau_pre: pre-synaptic trace 时间常数 :type tau_pre: float :param tau_post: post-synaptic trace 时间常数 :type tau_post: float :param f_pre: 作用于 pre 分支权重的调制函数 :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: 作用于 post 分支权重的调制函数 :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(delta_w, (trace_pre_next, trace_post_next))``;``delta_w`` 与 ``weight`` 同形状 :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] ---- .. _functional_stdp_linear_step-en: * **English** Run one STDP update for a linear weight. ``trace`` is ``(trace_pre, trace_post)``. The function updates both traces first, computes the weight increment from the updated traces, and returns ``(delta_w, trace_next)``. It does not mutate the input state in place. .. math:: tr_{pre}^{t+1} &= tr_{pre}^{t} - tr_{pre}^{t} / \tau_{pre} + s_{pre}^{t} \\ tr_{post}^{t+1} &= tr_{post}^{t} - tr_{post}^{t} / \tau_{post} + s_{post}^{t} :param in_spike: Input spikes shaped ``[N, in_features]`` :type in_spike: torch.Tensor :param out_spike: Output spikes shaped ``[N, out_features]`` :type out_spike: torch.Tensor :param trace: Current ``(trace_pre, trace_post)``. The tensors have the same shapes and devices as ``in_spike`` and ``out_spike``, respectively, and dtypes compatible with the corresponding computations :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: Weight shaped ``[out_features, in_features]`` :type weight: torch.Tensor :param tau_pre: Time constant of the pre-synaptic trace :type tau_pre: float :param tau_post: Time constant of the post-synaptic trace :type tau_post: float :param f_pre: Weight modulation function for the pre branch :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: Weight modulation function for the post branch :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(delta_w, (trace_pre_next, trace_post_next))``; ``delta_w`` has the same shape as ``weight`` :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] .. note:: 本函数没有独立多步形式;多步执行由调用者逐步循环。 This function has no independent multi-step form; callers iterate it. """ trace_pre, trace_post = trace trace_pre = trace_pre - trace_pre / tau_pre + in_spike trace_post = trace_post - trace_post / tau_post + out_spike delta_w_pre = -f_pre(weight) * ( trace_post.unsqueeze(2) * in_spike.unsqueeze(1) ).sum(0) delta_w_post = f_post(weight) * ( trace_pre.unsqueeze(1) * out_spike.unsqueeze(2) ).sum(0) return delta_w_pre + delta_w_post, (trace_pre, trace_post)
[文档] def mstdp_linear_step( in_spike: torch.Tensor, out_spike: torch.Tensor, trace: tuple[torch.Tensor, torch.Tensor], weight: torch.Tensor, *, tau_pre: float, tau_post: float, f_pre: Callable[[torch.Tensor], torch.Tensor] = _identity, f_post: Callable[[torch.Tensor], torch.Tensor] = _identity, ) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]: r""" **API Language** - :ref:`中文 <functional_mstdp_linear_step-cn>` | :ref:`English <functional_mstdp_linear_step-en>` ---- .. _functional_mstdp_linear_step-cn: * **中文** 执行全连接权重的单步 mSTDP eligibility 计算。``trace`` 是 ``(trace_pre, trace_post)``。返回的 eligibility 保留 batch 维,供调用者 进一步施加 reward;本函数不接收或处理 reward。 :param in_spike: 输入脉冲,形状 ``[N, in_features]`` :type in_spike: torch.Tensor :param out_spike: 输出脉冲,形状 ``[N, out_features]`` :type out_spike: torch.Tensor :param trace: 当前 ``(trace_pre, trace_post)``,两者分别与 ``in_spike`` 和 ``out_spike`` 同形状、同 device :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: 权重,形状 ``[out_features, in_features]`` :type weight: torch.Tensor :param tau_pre: pre-synaptic trace 时间常数 :type tau_pre: float :param tau_post: post-synaptic trace 时间常数 :type tau_post: float :param f_pre: 作用于 pre 分支权重的调制函数 :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: 作用于 post 分支权重的调制函数 :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(eligibility, (trace_pre_next, trace_post_next))``; ``eligibility`` 形状为 ``[N, out_features, in_features]`` :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] ---- .. _functional_mstdp_linear_step-en: * **English** Compute one mSTDP eligibility step for a linear weight. ``trace`` is ``(trace_pre, trace_post)``. The returned eligibility retains its batch dimension for subsequent reward modulation; this function neither receives nor applies a reward. :param in_spike: Input spikes shaped ``[N, in_features]`` :type in_spike: torch.Tensor :param out_spike: Output spikes shaped ``[N, out_features]`` :type out_spike: torch.Tensor :param trace: Current ``(trace_pre, trace_post)`` with the same shapes and devices as ``in_spike`` and ``out_spike``, respectively :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: Weight shaped ``[out_features, in_features]`` :type weight: torch.Tensor :param tau_pre: Time constant of the pre-synaptic trace :type tau_pre: float :param tau_post: Time constant of the post-synaptic trace :type tau_post: float :param f_pre: Weight modulation function for the pre branch :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: Weight modulation function for the post branch :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(eligibility, (trace_pre_next, trace_post_next))``; ``eligibility`` is shaped ``[N, out_features, in_features]`` :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] .. note:: 本函数没有独立多步形式;多步执行由调用者逐步循环。 This function has no independent multi-step form; callers iterate it. """ trace_pre, trace_post = trace trace_pre = trace_pre * math.exp(-1 / tau_pre) + in_spike trace_post = trace_post * math.exp(-1 / tau_post) + out_spike eligibility = f_post(weight) * ( trace_pre.unsqueeze(1) * out_spike.unsqueeze(2) ) - f_pre(weight) * (trace_post.unsqueeze(2) * in_spike.unsqueeze(1)) return eligibility, (trace_pre, trace_post)
[文档] def mstdpet_linear_step( in_spike: torch.Tensor, out_spike: torch.Tensor, trace: tuple[torch.Tensor, torch.Tensor], weight: torch.Tensor, *, tau_pre: float, tau_post: float, f_pre: Callable[[torch.Tensor], torch.Tensor] = _identity, f_post: Callable[[torch.Tensor], torch.Tensor] = _identity, ) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]: r""" **API Language** - :ref:`中文 <functional_mstdpet_linear_step-cn>` | :ref:`English <functional_mstdpet_linear_step-en>` ---- .. _functional_mstdpet_linear_step-cn: * **中文** 执行无 batch 维全连接脉冲的单步 mSTDP-ET eligibility 计算。``trace`` 是 ``(trace_pre, trace_post)``。本函数只更新神经元 trace 并计算 eligibility; eligibility trace 的衰减与 reward 调制由 :func:`mstdpet_reward_step` 完成。 :param in_spike: 输入脉冲,形状 ``[in_features]`` :type in_spike: torch.Tensor :param out_spike: 输出脉冲,形状 ``[out_features]`` :type out_spike: torch.Tensor :param trace: 当前 ``(trace_pre, trace_post)``,两者分别与 ``in_spike`` 和 ``out_spike`` 同形状、同 device :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: 权重,形状 ``[out_features, in_features]`` :type weight: torch.Tensor :param tau_pre: pre-synaptic trace 时间常数 :type tau_pre: float :param tau_post: post-synaptic trace 时间常数 :type tau_post: float :param f_pre: 作用于 pre 分支权重的调制函数 :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: 作用于 post 分支权重的调制函数 :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(eligibility, (trace_pre_next, trace_post_next))``; ``eligibility`` 与 ``weight`` 同形状 :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] ---- .. _functional_mstdpet_linear_step-en: * **English** Compute one mSTDP-ET eligibility step for unbatched linear spikes. ``trace`` is ``(trace_pre, trace_post)``. This function only updates the neuronal traces and computes eligibility. :func:`mstdpet_reward_step` handles eligibility-trace decay and reward modulation. :param in_spike: Input spikes shaped ``[in_features]`` :type in_spike: torch.Tensor :param out_spike: Output spikes shaped ``[out_features]`` :type out_spike: torch.Tensor :param trace: Current ``(trace_pre, trace_post)`` with the same shapes and devices as ``in_spike`` and ``out_spike``, respectively :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: Weight shaped ``[out_features, in_features]`` :type weight: torch.Tensor :param tau_pre: Time constant of the pre-synaptic trace :type tau_pre: float :param tau_post: Time constant of the post-synaptic trace :type tau_post: float :param f_pre: Weight modulation function for the pre branch :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: Weight modulation function for the post branch :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(eligibility, (trace_pre_next, trace_post_next))``; ``eligibility`` has the same shape as ``weight`` :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] .. note:: 本函数没有独立多步形式;多步执行由调用者逐步循环。 This function has no independent multi-step form; callers iterate it. """ trace_pre, trace_post = trace trace_pre = trace_pre * math.exp(-1 / tau_pre) + in_spike trace_post = trace_post * math.exp(-1 / tau_post) + out_spike eligibility = f_post(weight) * torch.outer(out_spike, trace_pre) - f_pre( weight ) * torch.outer(trace_post, in_spike) return eligibility, (trace_pre, trace_post)
[文档] def stdp_conv2d_step( in_spike: torch.Tensor, out_spike: torch.Tensor, trace: tuple[torch.Tensor, torch.Tensor], weight: torch.Tensor, *, stride: tuple[int, int], tau_pre: float, tau_post: float, f_pre: Callable[[torch.Tensor], torch.Tensor] = _identity, f_post: Callable[[torch.Tensor], torch.Tensor] = _identity, ) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]: r""" **API Language** - :ref:`中文 <functional_stdp_conv2d_step-cn>` | :ref:`English <functional_stdp_conv2d_step-en>` ---- .. _functional_stdp_conv2d_step-cn: * **中文** 执行二维卷积权重的单步 STDP 更新。``trace`` 是 ``(trace_pre, trace_post)``。``in_spike`` 必须已经按突触层的 padding 规则展开;函数因此只表达 dilation 为 1、groups 为 1 的卷积 STDP 方程, 不读取 ``Conv2d`` module 或解释 padding mode。 :param in_spike: 已 padding 的输入脉冲,形状 ``[N, C_in, H_pad, W_pad]`` :type in_spike: torch.Tensor :param out_spike: 输出脉冲,形状 ``[N, C_out, H_out, W_out]`` :type out_spike: torch.Tensor :param trace: 当前 ``(trace_pre, trace_post)``,两者分别与 ``in_spike`` 和 ``out_spike`` 同形状、同 device :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: 权重,形状 ``[C_out, C_in, K_h, K_w]`` :type weight: torch.Tensor :param stride: 二维卷积步长 ``(stride_h, stride_w)`` :type stride: Tuple[int, int] :param tau_pre: pre-synaptic trace 时间常数 :type tau_pre: float :param tau_post: post-synaptic trace 时间常数 :type tau_post: float :param f_pre: 作用于 pre 分支权重的调制函数 :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: 作用于 post 分支权重的调制函数 :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(delta_w, (trace_pre_next, trace_post_next))``;``delta_w`` 与 ``weight`` 同形状 :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] ---- .. _functional_stdp_conv2d_step-en: * **English** Run one STDP update for a 2D convolution weight. ``trace`` is ``(trace_pre, trace_post)``. ``in_spike`` must already include the synaptic layer's padding. The function consequently expresses only the convolutional STDP equation for dilation 1 and one group; it neither reads a ``Conv2d`` module nor interprets a padding mode. :param in_spike: Padded input spikes shaped ``[N, C_in, H_pad, W_pad]`` :type in_spike: torch.Tensor :param out_spike: Output spikes shaped ``[N, C_out, H_out, W_out]`` :type out_spike: torch.Tensor :param trace: Current ``(trace_pre, trace_post)`` with the same shapes and devices as ``in_spike`` and ``out_spike``, respectively :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: Weight shaped ``[C_out, C_in, K_h, K_w]`` :type weight: torch.Tensor :param stride: Convolution stride ``(stride_h, stride_w)`` :type stride: Tuple[int, int] :param tau_pre: Time constant of the pre-synaptic trace :type tau_pre: float :param tau_post: Time constant of the post-synaptic trace :type tau_post: float :param f_pre: Weight modulation function for the pre branch :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: Weight modulation function for the post branch :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(delta_w, (trace_pre_next, trace_post_next))``; ``delta_w`` has the same shape as ``weight`` :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] .. note:: 本函数没有独立多步形式;多步执行由调用者逐步循环。 This function has no independent multi-step form; callers iterate it. """ trace_pre, trace_post = trace trace_pre = trace_pre - trace_pre / tau_pre + in_spike trace_post = trace_post - trace_post / tau_post + out_spike delta_w = torch.zeros_like(weight) stride_h, stride_w = stride for h in range(weight.shape[2]): for w in range(weight.shape[3]): h_end = in_spike.shape[2] - weight.shape[2] + 1 + h w_end = in_spike.shape[3] - weight.shape[3] + 1 + w pre_spike = in_spike[:, :, h:h_end:stride_h, w:w_end:stride_w] tr_pre = trace_pre[:, :, h:h_end:stride_h, w:w_end:stride_w] weight_hw = weight[:, :, h, w] delta_w_pre = -( f_pre(weight_hw) * (trace_post.unsqueeze(2) * pre_spike.unsqueeze(1)) .permute([1, 2, 0, 3, 4]) .sum(dim=[2, 3, 4]) ) delta_w_post = f_post(weight_hw) * ( tr_pre.unsqueeze(1) * out_spike.unsqueeze(2) ).permute([1, 2, 0, 3, 4]).sum(dim=[2, 3, 4]) delta_w[:, :, h, w] += delta_w_pre + delta_w_post return delta_w, (trace_pre, trace_post)
[文档] def stdp_conv1d_step( in_spike: torch.Tensor, out_spike: torch.Tensor, trace: tuple[torch.Tensor, torch.Tensor], weight: torch.Tensor, *, stride: tuple[int], tau_pre: float, tau_post: float, f_pre: Callable[[torch.Tensor], torch.Tensor] = _identity, f_post: Callable[[torch.Tensor], torch.Tensor] = _identity, ) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]: r""" **API Language** - :ref:`中文 <functional_stdp_conv1d_step-cn>` | :ref:`English <functional_stdp_conv1d_step-en>` ---- .. _functional_stdp_conv1d_step-cn: * **中文** 执行一维卷积权重的单步 STDP 更新。``trace`` 是 ``(trace_pre, trace_post)``。``in_spike`` 必须已经按突触层的 padding 规则展开;函数因此只表达 dilation 为 1、groups 为 1 的卷积 STDP 方程, 不读取 ``Conv1d`` module 或解释 padding mode。 :param in_spike: 已 padding 的输入脉冲,形状 ``[N, C_in, L_pad]`` :type in_spike: torch.Tensor :param out_spike: 输出脉冲,形状 ``[N, C_out, L_out]`` :type out_spike: torch.Tensor :param trace: 当前 ``(trace_pre, trace_post)``,两者分别与 ``in_spike`` 和 ``out_spike`` 同形状、同 device :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: 权重,形状 ``[C_out, C_in, K]`` :type weight: torch.Tensor :param stride: 一维卷积步长 ``(stride,)`` :type stride: Tuple[int] :param tau_pre: pre-synaptic trace 时间常数 :type tau_pre: float :param tau_post: post-synaptic trace 时间常数 :type tau_post: float :param f_pre: 作用于 pre 分支权重的调制函数 :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: 作用于 post 分支权重的调制函数 :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(delta_w, (trace_pre_next, trace_post_next))``;``delta_w`` 与 ``weight`` 同形状 :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] ---- .. _functional_stdp_conv1d_step-en: * **English** Run one STDP update for a 1D convolution weight. ``trace`` is ``(trace_pre, trace_post)``. ``in_spike`` must already include the synaptic layer's padding. The function consequently expresses only the convolutional STDP equation for dilation 1 and one group; it neither reads a ``Conv1d`` module nor interprets a padding mode. :param in_spike: Padded input spikes shaped ``[N, C_in, L_pad]`` :type in_spike: torch.Tensor :param out_spike: Output spikes shaped ``[N, C_out, L_out]`` :type out_spike: torch.Tensor :param trace: Current ``(trace_pre, trace_post)`` with the same shapes and devices as ``in_spike`` and ``out_spike``, respectively :type trace: Tuple[torch.Tensor, torch.Tensor] :param weight: Weight shaped ``[C_out, C_in, K]`` :type weight: torch.Tensor :param stride: Convolution stride ``(stride,)`` :type stride: Tuple[int] :param tau_pre: Time constant of the pre-synaptic trace :type tau_pre: float :param tau_post: Time constant of the post-synaptic trace :type tau_post: float :param f_pre: Weight modulation function for the pre branch :type f_pre: Callable[[torch.Tensor], torch.Tensor] :param f_post: Weight modulation function for the post branch :type f_post: Callable[[torch.Tensor], torch.Tensor] :return: ``(delta_w, (trace_pre_next, trace_post_next))``; ``delta_w`` has the same shape as ``weight`` :rtype: Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]] .. note:: 本函数没有独立多步形式;多步执行由调用者逐步循环。 This function has no independent multi-step form; callers iterate it. """ trace_pre, trace_post = trace trace_pre = trace_pre - trace_pre / tau_pre + in_spike trace_post = trace_post - trace_post / tau_post + out_spike delta_w = torch.zeros_like(weight) stride_l = stride[0] for l in range(weight.shape[2]): l_end = in_spike.shape[2] - weight.shape[2] + 1 + l pre_spike = in_spike[:, :, l:l_end:stride_l] tr_pre = trace_pre[:, :, l:l_end:stride_l] weight_l = weight[:, :, l] delta_w_pre = -( f_pre(weight_l) * (trace_post.unsqueeze(2) * pre_spike.unsqueeze(1)) .permute([1, 2, 0, 3]) .sum(dim=[2, 3]) ) delta_w_post = f_post(weight_l) * ( tr_pre.unsqueeze(1) * out_spike.unsqueeze(2) ).permute([1, 2, 0, 3]).sum(dim=[2, 3]) delta_w[:, :, l] += delta_w_pre + delta_w_post return delta_w, (trace_pre, trace_post)
[文档] def mstdpet_reward_step( reward: torch.Tensor | float, eligibility: torch.Tensor, trace_e: torch.Tensor, *, tau_trace: float, ) -> tuple[torch.Tensor, torch.Tensor]: r""" **API Language** - :ref:`中文 <functional_mstdpet_reward_step-cn>` | :ref:`English <functional_mstdpet_reward_step-en>` ---- .. _functional_mstdpet_reward_step-cn: * **中文** 更新 mSTDP-ET eligibility trace,并用 reward 调制更新后的 trace。 .. math:: tr_e^{t+1} &= tr_e^t \exp(-1 / \tau_{trace}) + e^t / \tau_{trace} \\ \Delta W^t &= r^t tr_e^{t+1} :param reward: 标量或可与 ``trace_e`` 广播的 reward :type reward: torch.Tensor or float :param eligibility: 当前 eligibility,形状与 ``trace_e`` 相同或可广播 :type eligibility: torch.Tensor :param trace_e: 当前 eligibility trace :type trace_e: torch.Tensor :param tau_trace: eligibility trace 时间常数 :type tau_trace: float :return: ``(delta_w, trace_e_next)`` :rtype: Tuple[torch.Tensor, torch.Tensor] ---- .. _functional_mstdpet_reward_step-en: * **English** Update the mSTDP-ET eligibility trace and modulate the updated trace with the reward. .. math:: tr_e^{t+1} &= tr_e^t \exp(-1 / \tau_{trace}) + e^t / \tau_{trace} \\ \Delta W^t &= r^t tr_e^{t+1} :param reward: Scalar reward or a tensor broadcastable with ``trace_e`` :type reward: torch.Tensor or float :param eligibility: Current eligibility with the same shape as ``trace_e`` or a broadcast-compatible shape :type eligibility: torch.Tensor :param trace_e: Current eligibility trace :type trace_e: torch.Tensor :param tau_trace: Time constant of the eligibility trace :type tau_trace: float :return: ``(delta_w, trace_e_next)`` :rtype: Tuple[torch.Tensor, torch.Tensor] .. note:: 本函数没有独立多步形式;多步执行由调用者逐步循环。 This function has no independent multi-step form; callers iterate it. """ trace_e = trace_e * math.exp(-1 / tau_trace) + eligibility / tau_trace return reward * trace_e, trace_e