# mypy: 允许未类型化装饰器
# mypy: 允许未类型化定义
导入
数学
导入
数字
导入
警告
导入
弱引用
来自
打字
导入
可选,
超载
来自 typing_extensions
导入
已弃用
导入
火炬
来自
火炬
导入 _VF,
张量
来自 torch.nn
导入
初始化
来自
torch.nn 参数
导入
参数
来自 torch.nn.utils.rnn
导入 PackedSequence
来自
.模块
导入
模块
__all__ = [
RNNBase,
"循环神经网络",
"长短期记忆网络",
"门控循环单元",
"RNNCellBase",
RNN 单元,
LSTM 单元,
GRU 单元,
]
_rnn 实现 = {
RNN_TANH: _VF.
RNN-Tanh,
RNN_RELU: _VF.
RNN-ReLU,
}
def _apply_permutation(张量:
张量,
线性排列:
张量,
暗淡:
整型 = 1) ->
张量:
返回
张量.
索引选择(
暗淡,
排列)
@deprecated(
"`apply_permutation` 已弃用,请使用 `tensor.index_select(dim, permutation)` 代替",
分类=
未来警告,
)
def apply_permutation(张量:
张量,
排列:
张量,
暗淡:
整型 = 1) ->
张量:
返回
应用置换(
张量,
置换,
暗淡)
[文档]
类 RNNBase(
模块):
rRNN 模块(RNN、LSTM、GRU)的基类。
实现了 RNN、LSTM 和 GRU 类共有的方面,例如模块初始化
以及参数存储管理的实用方法。
.. 注意::
RNNBase 类没有实现前向方法。
.. 注意::
LSTM 和 GRU 类覆盖了 RNNBase 类实现的一些方法。
"源代码"
常量 = [
模式,
输入大小,
隐藏层大小,
层数数量,
偏置,
"batch_first",
随机失活率,
双向,
项目大小,
]
__jit_unused_properties__ = [所有权重]
模式:
字符串
输入大小:
整型
隐藏层大小:
整型
层数:
整型
偏差:
布尔类型
批量优先:
布尔类型
dropout: 浮点数
双向的:
布尔类型
投影大小:
整型
def 初始化(
self,
模式:
字符串,
输入大小: int,
隐藏层大小: int,
层数:
整型 = 1,
偏差:
布尔类型 = True,
批量优先:
布尔类型 =
错误,
dropout: 浮点数 = 0.0,
双向的:
布尔类型 =
错误,
投影大小:
整型 = 0,
设备=
无,
数据类型=
无,
) -> 无:
工厂参数 = {
"设备":
设备, "dtype":
数据类型}
超级().
初始化()
self.模式 =
模式
self.输入大小 =
输入大小
self.隐藏层大小 =
隐藏大小
self.层数数量 =
层数数量
self.bias = bias
self.批量优先 =
批量优先
self.dropout = float(dropout)
self.双向的 =
双向的
self.项目大小 =
项目大小
self._平面重量引用:
列表[
可选[
弱引用.
参考类型[
参数]]] = []
方向数量 = 2
如果
双向
否则 1
如果 (
not isinstance(dropout, 数字.
数字)
或 not 0
≤ dropout
≤ 1
或 isinstance(dropout,
布尔)
):
提升 ValueError(
"dropout 应该是一个在 [0, 1] 范围内的数字"
表示一个元素被置零的概率
零化
)
如果 dropout > 0
和
层数数量 == 1:
warnings.警告(
"dropout 选项在所有层之后添加 dropout,但最后一个层除外,因此非零 dropout 期望"
"循环层之后,所以非零 dropout 期望"
f"num_layers 的值大于 1,但得到了 dropout="{dropout}
和
f"num_layers="{
层数}"
)
如果 not isinstance(
隐藏层大小, int):
提升
类型错误(
f"hidden_size 应该是 int 类型,实际得到:"{
类型(
隐藏层大小).__name__}"
)
如果 hidden_size
≤ 0:
提升 ValueError(
"hidden_size 必须大于零")
如果 num_layers
≤ 0:
提升 ValueError(
"num_layers 必须大于零")
如果
项目大小 < 0:
提升 ValueError(
proj_size 应该是一个正整数或零以禁用投影
)
如果
项目大小 >=
隐藏层大小:
提升 ValueError(
"项目大小必须小于隐藏大小")
如果
模式 ==
LSTM:
门大小 = 4 *
隐藏层大小
elif 模式 ==
GRU:
门大小 = 3 *
隐藏层大小
elif 模式 ==
RNN_TANH:
门大小 =
隐藏层大小
elif 模式 ==
RNN_RELU:
网格大小 =
隐藏层大小
否则:
提升 ValueError(
识别不到的 RNN 模式: +
模式)
self._扁平化权重名称 = []
self.所有权重 = []
为
层
在
范围(
层数):
为
方向
在
范围(
方向数量):
实数隐藏层大小 =
投影大小
如果
项目大小 > 0
否则
隐藏层大小
层输入大小 = (
输入大小
如果
层 == 0
否则
实际隐藏层大小 *
数量方向
)
w_ih = 参数(
火炬.
空的((
网格大小,
层输入大小), **
工厂参数)
)
网格_hh =
参数(
火炬.
空的((
门大小,
实际隐藏大小), **
工厂参数)
)
b_ih = 参数(
火炬.
空的(
网格大小, **
工厂参数))
# 第二个偏置向量包含以兼容 CuDNN。只需要一个
# 偏置向量在标准定义中即可。
b_hh = 参数(
火炬.
空的(
网格大小, **
工厂参数))
层参数:
元组[
张量, ...] = ()
如果 self.
投影大小 == 0:
如果
偏差:
层参数 = (
我_ih,
我_hh,
你_ih,
你_hh)
否则:
层参数 = (
我_ih,
我_hh)
否则:
w_hr = 参数(
火炬.
空的((
投影大小,
隐藏层大小), **
工厂参数)
)
如果
偏差:
层参数 = (
我_ih,
我_hh,
你_ih,
你_hh, w_hr)
否则:
层参数 = (
我_ih,
我_hh, w_hr)
后缀 = "_reverse"
如果
方向 == 1
否则
请提供需要翻译的文本
参数名称 = [
"weight_ih_l"{}{}",
"weight_hh_l"{}{}"]
如果
偏差:
参数名称 += [
bias_ih_l{}{}",
bias_hh_l{}{}"]
如果 self.proj_size > 0:
参数名称 += [
weight_hr_l{}{}"]
参数名称 = [x.
格式(
层,
后缀)
为 x
在
参数名称]
为
名称,
参数
在
压缩(
参数名称,
层参数):
setattr(self, 名称,
参数)
self._扁平权重名称.
扩展(
参数名称)
self.所有权重.
追加(
参数名称)
self.初始化扁平权重()
self.重置参数()
def 初始化扁平权重(self):
self.扁平权重 = [
getattr(self, wn) 如果
有属性(self, wn)
否则
无
为 wn
在 self.
_平面权重名称
]
self.平面重量引用 = [
弱引用.ref(w)
如果 w
是 not
无
否则
无
为 w
在 self.
平面重量
]
self.展平参数()
def __setattr__(self, 属性,
值):
如果
有属性(self,
_flat_weights_names)
和
属性
在 self._flat_weights_names:
# 保持 self._flat_weights 在 self.weight = ...时更新
索引 = self._flat_weights_names.
索引(
属性)
self.平坦权重[
索引] = value
超级().__setattr__(
属性,
值)
[文档] def
展平参数(self) ->
无:
重置参数数据指针,以便它们可以使用更快的代码路径。
目前,这仅在模块位于 GPU 上且启用 cuDNN 时才有效。
否则就是空操作。
"源代码"
如果_flat_weights 只部分实例化,则短路。
如果
长度(self._flat_weights) !=
长度(self._flat_weights_names):
返回
为 w
在 self._flat_weights:
如果 not isinstance(w,
张量):
返回
# 如果 self._flat_weights 中的任何张量不符合 cuDNN 的要求,则短路
# 或者_flat_weights 中的张量数据类型不同
first_fw = self._平面权重[0]
# 类型:忽略[联合属性]
dtype = 第一个 fw.dtype
# 类型:忽略[联合属性]
为 fw
在 self.
_平面权重:
如果 (
not isinstance(外文,
张量)
或 not (
外文.dtype ==
数据类型)
或 not fw.is_cuda
或 not
火炬.
后端.cudnn.is_acceptable(fw)
):
返回
如果任何参数别名,我们将回退到较慢的复制代码路径。这是一个
足够的检查,因为重叠的参数缓冲区如果不完全
# 别名会破坏唯一性检查的假设
# Module.named_parameters()
唯一数据指针 = {
p.数据指针()
为 p
在 self.
_扁平权重
# 类型:忽略[联合属性]
}
如果
长度(
唯一数据指针) !=
长度(self.
_扁平权重):
返回
与
火炬.cuda.
设备的(
首个固件):
导入 torch.backends.cudnn.rnn
作为 rnn
# 注意:由于 _cudnn_rnn_flatten_weight 是一个对 self._flat_weights 的就地操作,因此需要使用 no_grad()
# 在 self._flat_weights 上进行就地操作
与
火炬.
不梯度():
如果
火炬.
使用_cudnn_rnn_flatten_weight():
权重数量 = 4
如果 self.bias
否则 2
如果 self.
投影大小 > 0:
权重数量 += 1
火炬._cudnn_rnn_flatten_weight(
self._flat_weights, # type: ignore[arg-type]
num_weights,
self.输入大小,
rnn.获取_cudnn 模式(self.
模式),
self.隐藏层大小,
self.项目大小,
self.层数,
self.批量优先,
布尔(self.
双向的),
)
def 应用(self,
函数,
递归=True):
self._flat_weight_refs = []
返回 =
超级().
应用(
函数,
递归)
重置_flat_weights
注意:在删除此内容之前请格外小心,因为第三方设备类型可能依赖于此行为来正确地使用 LSTM 等模块。
很可能依赖于此行为来正确地使用 LSTM 等模块。
self._init_flat_weights()
返回
返回
def 重置参数(self) ->
无:
stdv = 1.0 / 数学.
平方根(self.
隐藏层大小)
如果 self.
隐藏大小 > 0
否则 0
为
权重
在 self.
参数():
初始化.
均匀的(
重量, -stdv, stdv)
def 检查输入(self,
输入:
张量, batch_sizes:
可选[
张量]) ->
无:
如果 not
火炬.
算子.
是否正在脚本化():
如果 (
输入.dtype != self._flat_weights[0].dtype
# 类型:忽略[联合属性]
和 not
火炬._C._is_any_autocast_enabled()
):
提升 ValueError(
f输入必须具有类型{self._flat_weights[0].
数据类型}
, 获取类型{
输入.
数据类型}"
# 类型:忽略[联合属性]
)
预期输入维度 = 2
如果
批处理大小
是 not
无
否则 3
如果
输入.
暗淡() !=
预期输入维度:
提升
运行时错误(
f"输入必须具有"{
期望的输入维度}
维度,实际得到{
输入.
暗淡()}"
)
如果 self.
输入大小 !=
输入.
尺寸(-1):
提升
运行时错误(
f"input.size(-1)必须等于 input_size。期望"{self.
输入大小}
,获得{
输入.
尺寸(-1)}"
)
def 获取期望的隐藏尺寸(
self, 输入:
张量, batch_sizes:
可选[
张量]
) -> 元组[int, int, int
]:
如果
批大小
是 not
无:
小批量 = int(batch_sizes[0])
否则:
小批量 =
输入.
尺寸(0)
如果 self.
批量优先
否则
输入.
尺寸(1)
数量方向 = 2
如果 self.
双向的
否则 1
如果 self.
项目大小 > 0:
预期隐藏层大小 = (
self.层数数量 *
方向数量,
小批量,
self.项目大小,
)
否则:
预期隐藏层大小 = (
self.层数数量 *
方向数量,
微批,
self.隐藏层大小,
)
返回
预期隐藏层大小
def 检查隐藏层大小(
self,
hx: 张量,
预期隐藏层大小:
元组[int, int, int
]
信息:
字符串 =
预期隐藏大小{}
,获得{}",
) -> 无:
如果 hx.
尺寸() != expected_hidden_size:
提升
运行时错误(
信息.
格式(expected_hidden_size,
列表(hx.
尺寸())))
def 权重已更改(self):
# 返回 True,如果自上次前向传递以来权重张量已更改。
# 这是在使用 torch.func.functional_call()等情况下发生的。
weights_changed = 假
为 ref,
名称
在
压缩(self.
_平面重量引用, self.
_平面重量名称):
权重 = getattr(self,
名称)
如果
有属性(self,
名称)
否则
无
如果
权重
是 not
无
和
分支
是 not
无
和 ref()
是 not
重量:
权重已更改 =
真实
断开
返回
权重已更改
def 检查前向参数(
self, 输入:
张量,
隐藏:
张量, batch_sizes:
可选[
张量]
):
self.检查输入(
输入, batch_sizes)
预期隐藏大小 = self.
获取预期隐藏大小(
输入, batch_sizes)
self.检查隐藏大小(
隐藏,
预期隐藏大小)
def 隐藏排列(self, hx:
张量,
排列:
可选[
张量
)]
如果
排列
是
无:
返回 hx
返回
_应用排列(hx,
排列)
def 额外表示(self) ->
字符串:
s = "输入大小,
隐藏大小"
如果 self.
项目大小 != 0:
s += ", proj_size="{proj_size}"
如果 self.num_layers != 1:
s += ", num_layers="
{层数}"
如果 self.bias
是 not True:
s += ", 偏置="
{偏置}"
如果 self.
批量优先
是 not
错误:
s += ", batch_first="{batch_first}"
如果 self.dropout != 0:
s += ", dropout="{dropout}"
如果 self.
双向
是 not
错误:
s += ", 双向="
{双向}"
返回 s.
格式(**self.
字典)
def _更新平坦权重(self):
如果 not
火炬.
算子.
是否正在脚本化():
如果 self.
权重已更改():
self.初始化扁平权重()
def __getstate__(self):
如果权重已更改,请在此处更新 __getstate__ 中的 _flat_weights。
self.更新扁平权重()
不要序列化权重引用。
状态 = self.
字典.
复制()
删除
状态[
_flat_weight_refs]
返回
状态
def __setstate__(self, d):
超级().__setstate__(d)
如果
所有权重
在 d:
self._所有权重 = d[
所有权重]
在 PyTorch 1.8 版本中,我们为 LSTM 添加了一个 proj_size 成员变量。
在 PyTorch 1.8 之前通过 torch.save(module) 序列化的 LSTM
没有它,为了保持兼容性,我们在这里设置 proj_size
如果
proj_size not
在 d:
self.proj_size = 0
如果 not isinstance(self.
所有权重[0
]
[0]
字符串):
层数 = self.
层数
方向数 = 2
如果 self.
双向的
否则 1
self._flat_weights_names = []
self._all_weights = []
为
层
在
范围(
层数):
为
方向
在
范围(num_directions):
后缀 = "_reverse"
如果
方向 == 1
否则
请提供需要翻译的文本
权重 = [
weight_ih_l{}{}",
weight_hh_l{}{}",
bias_ih_l{}{}",
bias_hh_l{}{}",
重量_hr_l{}{}",
]
权重 = [x.
格式(
层,
后缀)
为 x
在
权重]
如果 self.
偏差:
如果 self.
项目大小 > 0:
self.所有权重 += [
权重]
self._扁平权重名称.
扩展(
权重)
否则:
self.所有权重 += [
权重
[4]]
self._扁平权重名称.
扩展(
权重
[4])
否则:
如果 self.proj_size > 0:
self.所有权重 += [
权重
[2]] + [
权重[-1
]]
self._扁平权重名称.
扩展(
权重
[2] + [
权重[-1
]]
)
否则:
self.所有权重 += [
权重
[2]]
self._扁平权重名称.
扩展(
权重
[2])
self.平坦权重 = [
getattr(self, wn) 如果
有属性(self, wn)
否则
无
为 wn
在 self._flat_weights_names
]
self._flat_weight_refs = [
弱引用.ref(w)
如果 w
是 not
无
否则
无
为 w
在 self.
扁平权重
]
@property
def 所有权重(self) ->
列表[
列表[
参数
]]
返回 [
[getattr(self, 重量)
为
权重
在
权重]
为
权重
在 self.
__所有权重
]
def _为数据并行复制(self):
复制品 =
超级().
_为数据并行复制()
# 需要复制这些缓存,否则副本将共享相同的
# 平坦的权重列表。
复制品.
扁平权重 =
复制品.
_平面权重
[]
复制品.
_平面权重名称 =
复制品.
_扁平权重名称
[]
返回
复制品
[文档]
类 RNN(RNNBase):
r"""__init__(input_size,hidden_size,num_layers=1,nonlinearity='tanh',bias=True,batch_first=False,dropout=0.0,bidirectional=False,device=None,dtype=None)"""
应用多层 Elman RNN,非线性函数为::math:`\tanh` 或 :math:`\text{ReLU}`
将非线性函数应用于输入序列。对于输入序列中的每个元素,
每一层计算以下函数:
.. math::
h_t = tanh(x_t W_{ih}^T + b_{ih} + h_{t-1}W_{hh}^T + b_{hh})
其中 :math:`h_t` 是时间 `t` 的隐藏状态,:math:`x_t` 是
时间 `t` 的输入,而 :math:`h_{(t-1)}` 是
上一个时间步`t-1`的层或时间`0`的初始隐藏状态。
如果:attr:`非线性`是`'relu'`,则使用 ReLU 代替 tanh。
.. 代码块 :: python
# 等效的效率实现,但 bidirectional=False
def forward(x, hx=None):
如果 batch_first:
x = x.transpose(0, 1)
seq_len, batch_size, _ = x.size()
如果 hx 是 None:
hx = torch.zeros(num_layers, batch_size, hidden_size)
h_t_minus_1 = hx
h_t = hx
output = []
for t in range(seq_len):
for layer in range(num_layers):
h_t[layer] = torch.tanh(
x[t] @ weight_ih[layer].T
+ 偏置_ih[layer]
+ h_t_minus_1[layer] @ 权重_hh[layer].T
+ 偏置_hh[layer]
)
output.append(h_t[-1])
h_t_minus_1 = h_t
output = torch.stack(output)
if batch_first:
output = output.transpose(0, 1)
返回输出,h_t
Args:
输入大小:输入 `x` 中期望的特征数量
隐藏层大小:隐藏状态 `h` 中的特征数量
num_layers:循环层的数量。例如,设置 `num_layers=2`
将意味着将两个 RNN 堆叠起来形成一个`堆叠 RNN`,
第二个 RNN 接收第一个 RNN 的输出并
计算最终结果。默认:1
非线性:要使用的非线性函数。可以是``'tanh'``或``'relu'``。默认:``'tanh'``
如果为 ``False``,则该层不使用偏置权重 `b_ih` 和 `b_hh`。
默认:``True``
batch_first:如果为 ``True``,则输入和输出张量以(batch,seq,feature)的形式提供。
以 `(batch, seq, feature)` 的形式,而不是 `(seq, batch, feature)`。
注意,此规则不适用于隐藏状态或细胞状态。详细信息请参见下面的输入/输出部分。默认:``False``
默认:``False``
dropout:如果非零,则在每个输出的基础上引入一个`Dropout`层
RNN 层除了最后一层,具有等于的 dropout 概率
:attr:`dropout`. 默认值:0
双向:如果为 ``True``,则变为双向 RNN。默认:``False``
输入:输入,hx
* **输入**:形状为 :math:`(L, H_{in})` 的张量,用于未批处理的输入,
当 ``batch_first=False`` 时为 :math:`(L, N, H_{in})`,
当 ``batch_first=True`` 时为 :math:`(N, L, H_{in})`,包含特征
输入序列。输入也可以是一个打包的可变长度序列。
请参阅 :func:`torch.nn.utils.rnn.pack_padded_sequence` 或
func:`torch.nn.utils.rnn.pack_sequence` 以获取详细信息。
* **hx**: 形状为 :math:`(D * \text{num\_layers}, H_{out})` 的张量,用于未批处理的输入或
(D * num_layers, N, H_out) 包含初始隐藏状态
状态用于输入序列批次。如未提供,则默认为零。
其中:
.. math::
\begin{aligned}
N ={} & \text{批量大小} \\
L ={} & 序列长度 \\
D ={} & 2(如果 bidirectional=True 否则 1)\\
H_{in} ={} & 输入大小 \\
H_{out} ={} & 隐藏层大小
\end{aligned}
输出:output, h_n
* **output**: 对于非批处理输入,形状为 :math:`(L, D * H_{out})` 的张量
当 `batch_first=False` 时为 `(L, N, D * H_{out})`
当 `batch_first=True` 时为 `(N, L, D * H_{out})`,包含输出特征
对于每个 `t`,从 RNN 的最后一层 `(h_t)` 中提取
如果输入为 `:class:`torch.nn.utils.rnn.PackedSequence`,则输出
也将是一个紧凑的序列。
* **h_n**: 形状为 :math:`(D * \text{num\_layers}, H_{out})` 的张量,用于未批处理的输入或
math:`(D * \text{num\_layers}, N, H_{out})` 包含每个批处理元素的最后隐藏状态
的张量。
属性:
weight_ih_l[k]: 第 k 层的可学习输入-隐藏权重,
形状为 `(hidden_size, input_size)` 对于 `k = 0`。否则,形状为
`(hidden_size, num_directions * hidden_size)`
weight_hh_l[k]: 第 k 层的可学习隐藏-隐藏权重,
形状为 `(hidden_size, hidden_size)`
bias_ih_l[k]: 第 k 层的可学习输入-隐藏偏差,
形状为 `(hidden_size)`
bias_hh_l[k]: 第 k 层的可学习隐藏-隐藏偏差,
形状为 `(hidden_size)`
.. 注意::
所有权重和偏置都初始化为 :math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})`
其中 :math:`k = \frac{1}{\text{hidden\_size}}`
.. 注意::
对于双向 RNN,正向和反向的方向分别是 0 和 1。
当 ``batch_first=False`` 时输出层拆分的示例:
``output.view(seq_len, batch, num_directions, hidden_size)``.
.. 注意::
对于非批处理输入,``batch_first`` 参数将被忽略。
.. include:: ../cudnn_rnn_determinism.rst
.. include:: ../cudnn_persistent_rnn.rst
示例:
>>> rnn = nn.RNN(10, 20, 2)
>>> input = torch.randn(5, 3, 10)
>>> h0 = torch.randn(2, 3, 20)
>>> output, hn = rnn(input, h0)
"源代码"
@overload
def 初始化(
self,
输入大小: int,
隐藏层大小: int,
层数:
整型 = 1,
非线性:
字符串 =
双曲正切,
偏差:
布尔类型 = True,
批量优先:
布尔类型 =
错误,
dropout: 浮点数 = 0.0,
双向的:
布尔类型 =
错误,
设备=
无,
数据类型=
无,
) -> 无:
...
@overload
def 初始化(self, *
参数, **kwargs):
...
def 初始化(self, *
参数, **kwargs):
如果 "proj_size"
在 kwargs:
提升 ValueError(
"proj_size 参数仅支持 LSTM,不支持 RNN 或 GRU"
)
如果
长度(
参数) > 3:
self.非线性 =
参数[3]
args = 参数
[3] +
参数[4
]
否则:
self.非线性 = kwargs.
弹出(
非线性,
双曲正切)
如果 self.
非线性 ==
双曲正切:
模式 = "RNN_TANH"
elif self.非线性 ==
ReLU:
模式 = "RNN_RELU"
否则:
提升 ValueError(
f"未知非线性"{self.
非线性}
请从 'tanh' 或 'relu' 中选择。
)
超级().
初始化(
模式, *
参数, **kwargs)
@overload
@torch._jit_internal.超载方法 # noqa: F811
def 前向(
self, 输入:
张量, hx:
可选[
张量] =
无
) -> 元组[
张量,
张量
]:
通过
@overload
@torch._jit_internal.超载方法 # noqa: F811
def 前向(
self, 输入: PackedSequence, hx:
可选[
张量] =
无
) -> 元组[PackedSequence,
张量
]:
通过
def 前向(self,
输入, hx=
无): # noqa: F811
self.更新平坦权重()
方向数量 = 2
如果 self.
双向的
否则 1
原始输入 =
输入
如果 isinstance(
原始输入, PackedSequence):
输入, batch_sizes,
排序索引,
未排序索引 =
输入
最大批量大小 = batch_sizes[0]
# 脚本在条件分支中遇到最大批量大小类型不同时会不高兴,所以我们进行复制
如果 hx
是
无:
hx = 火炬.
零(
self.num_layers * 方向数量,
最大批量大小,
self.隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备,
)
否则:
# 每个隐藏状态的批量应与用户认为他/她正在传递的输入序列相匹配。
# 用户认为他/她正在传递的。
hx = self.排列隐藏(hx,
排序索引)
否则:
批处理大小 =
无
如果
输入.
暗淡() not
在 (2, 3):
提升 ValueError(
f"RNN:期望输入为 2D 或 3D,但得到 D 张量"{
输入.
暗淡()}
的错误"
)
批处理 =
输入.
暗淡() == 3
批处理维度 = 0
如果 self.
批量优先
否则 1
如果 not
批处理:
输入 =
输入.
展平(
批处理维度)
如果 hx
是 not
无:
如果 hx.
暗淡() != 2:
提升
运行时错误(
f对于未批处理的 2-D 输入,hx 也应为 2-D,但得到了{hx.
暗淡()}
-D 张量
)
hx = hx.展平(1)
否则:
如果 hx
是 not
无
和 hx.
暗淡() != 3:
提升
运行时错误(
f对于批处理的 3-D 输入,hx 也应该为 3-D,但得到了{hx.
暗淡()}
-D 张量
)
最大批量大小 =
输入.
尺寸(0)
如果 self.
批量优先
否则
输入.
尺寸(1)
排序索引 =
无
未排序索引 =
无
如果 hx
是
无:
hx = 火炬.
零(
self.层数 *
方向数量,
最大批量大小,
self.隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备,
)
否则:
# 每个隐藏状态的批次应与用户认为他/她正在传递的输入序列相匹配。
# 用户认为他/她正在传递的输入序列相匹配。
hx = self.排序隐藏(hx,
排序索引)
断言 hx
是 not
无
self.检查前向参数(
输入, hx, batch_sizes)
断言 self.
模式 ==
RNN_TANH
或 self.
模式 ==
RNN_RELU
如果
批处理大小
是
无:
如果 self.
模式 ==
RNN_TANH:
结果 = _VF.
RNN-Tanh(
输入,
hx,
self._flat_weights, # type: ignore[arg-type]
self.偏差,
self.层数,
self.dropout,
self.训练,
self.双向的,
self.批量优先,
)
否则:
结果 = _VF.
RNN-ReLU(
输入,
hx,
self._flat_weights, # type: ignore[arg-type]
self.偏差,
self.层数,
self.dropout,
self.训练,
self.双向的,
self.批量优先,
)
否则:
如果 self.
模式 ==
RNN_TANH:
结果 = _VF.
RNN-Tanh(
输入,
batch_sizes,
hx,
self._flat_weights, # type: ignore[arg-type]
self.偏差,
self.层数,
self.dropout,
self.训练,
self.双向的,
)
否则:
结果 = _VF.
RNN-ReLU(
输入,
batch_sizes,
hx,
self._flat_weights, # type: ignore[arg-type]
self.偏差,
self.层数,
self.dropout,
self.训练,
self.双向的,
)
输出 =
结果[0]
隐藏 =
结果[1]
如果 isinstance(
原始输入, PackedSequence):
输出打包 = PackedSequence(
输出, batch_sizes,
排序索引,
未排序索引
)
返回
输出打包, self.
隐藏排列(
隐藏,
未排序索引)
如果 not
批处理: # type: ignore[possibly-undefined]
输出 =
输出.
挤压(
批处理维度) # type: ignore[possibly-undefined]
隐藏 =
隐藏.
挤压(1)
返回
输出, self.
排列隐藏(
隐藏,
未排序的索引)
# XXX:LSTM 和 GRU 的实现与 RNNBase 不同,这是因为:
我们希望在 TorchScript 中支持 nn.LSTM 和 nn.GRU,以及当前的 TorchScript 状态无法支持 Python 的 Union Type 或 Any Type
因此,TorchScript 的静态类型不允许在 Dict 的值中使用 Function 或 Callable 类型,所以我们不得不单独调用_VF 而不是使用_rnn_impls
2. TorchScript 的静态类型不允许在 Dict 的值中使用 Function 或 Callable 类型
所以我们不得不单独调用_VF 而不是使用_rnn_impls
这只是临时的,处于我们想要实现的过渡状态
确保按时发布
#
更多讨论细节请见 https://github.com/pytorch/pytorch/pull/23266
#
TODO:当 TorchScript 移除时,删除 LSTM 和 GRU 的覆盖实现
支持一般性地表达这两个模块。
[文档]
类
长短期记忆网络(RNNBase):
r"__init__(输入大小,隐藏层大小,层数=1,偏置=True,批处理第一=False,dropout=0.0,双向=False,投影大小=0,设备=None,数据类型=None)"
将多层长短期记忆(LSTM)循环神经网络(RNN)应用于输入序列。
对于输入序列中的每个元素,每一层都计算以下内容
函数:
.. math::
\begin{array}{ll} \\
\end{array}
i_t = σ(W_{ii} x_t + b_{ii} + W_{hi} h_{t-1} + b_{hi})
f_t = σ(W_{if} x_t + b_{if} + W_{hf} h_{t-1} + b_{hf})
g_t = \tanh(W_{ig} x_t + b_{ig} + W_{hg} h_{t-1} + b_{hg}) \\
o_t = \sigma(W_{io} x_t + b_{io} + W_{ho} h_{t-1} + b_{ho}) \\
c_t = f_t \odot c_{t-1} + i_t \odot g_t \\
h_t = o_t \odot \tanh(c_t) \\
\end{array}
`h_t` 是时间 `t` 的隐藏状态,`c_t` 是细胞
状态在时间`t`时,:math:`x_t`是时间`t`的输入,:math:`h_{t-1}`
是时间`t-1`层的隐藏状态或初始隐藏状态
状态在时间 `0`,以及 :math:`i_t`,:math:`f_t`,:math:`g_t`,
math:`o_t` 是输入、遗忘、细胞和输出门,分别。
math:`σ` 是 sigmoid 函数,而 :math:`⊙` 是 Hadamard 积。
在多层 LSTM 中,第 :math:`l` 层的输入 :math:`x^{(l)}_t`
(:math:`l ≥ 2`)是前一层隐藏状态 :math:`h^{(l-1)}_t` 乘以
dropout :math:`\delta^{(l-1)}_t` 其中每个 :math:`\delta^{(l-1)}_t` 是一个伯努利随机变量
变量以概率 :attr:`dropout` 为 :math:`0`
如果指定了 `proj_size > 0`,则将使用具有投影的 LSTM。这将以以下方式改变 LSTM 单元。
首先,:math:`h_t` 的维度将从
``hidden_size`` 到 ``proj_size``(:math:`W_{hi}` 的维度将相应改变)。
其次,每一层的输出隐藏状态将被一个可学习的投影矩阵相乘::math:`h_t = W_{hr}h_t`。注意,由此产生的结果,LSTM 网络的输出形状也将不同。具体请参见下面的输入/输出部分。
矩阵::math:`h_t = W_{hr}h_t`。请注意,由于这个原因,LSTM 网络的输出形状也将不同。具体请参见下面的输入/输出部分。
LSTM 网络的输出形状也将不同。具体请参见下面的输入/输出部分。
所有变量的维度。更多详情请见 https://arxiv.org/abs/1402.1128。
Args:
input_size: 输入 `x` 预期特征的数量
hidden_size: 隐藏状态 `h` 中的特征数量
num_layers: 循环层的数量。例如,设置 ``num_layers=2``
将意味着将两个 LSTM 堆叠起来形成一个`堆叠 LSTM`,
第二个 LSTM 接收第一个 LSTM 的输出并
计算最终结果。默认:1
偏置:如果为`False`,则该层不使用偏置权重`b_ih`和`b_hh`。
默认:``True``
batch_first:如果为 ``True``,则输入和输出张量以(batch,seq,feature)的形式提供。
以`(batch, seq, feature)`代替`(seq, batch, feature)`。
请注意,此规则不适用于隐藏状态或单元格状态。查看
以下部分为详细信息。默认:``False``
dropout:如果非零,则在每个输出的基础上引入一个`Dropout`层
LSTM 层除了最后一层,具有等于的 dropout 概率
attr:`dropout`。默认值:0
bidirectional:如果为 True,则变为双向 LSTM。默认值:`False`
proj_size:如果`> 0`,将使用对应大小投影的 LSTM。默认值:0
输入:输入,(h_0, c_0)
* **输入**:形状为 :math:`(L, H_{in})` 的张量,用于非批处理输入,
当 ``batch_first=False`` 时为 :math:`(L, N, H_{in})`,
当 ``batch_first=True`` 时为 :math:`(N, L, H_{in})`,包含特征
输入序列。输入也可以是一个打包的可变长度序列。
请参阅 :func:`torch.nn.utils.rnn.pack_padded_sequence` 或
func:`torch.nn.utils.rnn.pack_sequence` 以获取详细信息。
* **h_0**:对于非批处理输入,形状为 :math:`(D * \text{num\_layers}, H_{out})` 的张量
`(D * num_layers, N, H_out)` 包含的
每个输入序列元素中的初始隐藏状态。
如果未提供 (h_0, c_0),则默认为零。
* **c_0**:形状为 (D * num_layers, H_cell) 的张量,用于未批处理的输入或
`(D * num_layers, N, H_cell)` 包含的
输入序列中每个元素的初始细胞状态。
如果未提供 (h_0, c_0),则默认为零。
其中:
.. math::
\begin{aligned}
N ={} & \text{批量大小} \\
L ={} & 序列长度 \\
D ={} & 2 \text{ 如果 bidirectional=True 否则 } 1 \\
H_{in} ={} & \text{输入大小} \\
H_{cell} ={} & \text{隐藏层大小} \\
H_{out} ={} & \text{如果 proj\_size}>0 则 proj\_size 否则 hidden\_size} \\
\end{aligned}
输出:输出,(h_n, c_n)
* **输出**:对于未批处理的输入,形状为 :math:`(L, D * H_{out})` 的张量,
当 ``batch_first=False`` 时为 :math:`(L, N, D * H_{out})`,
当 ``batch_first=True`` 时为 :math:`(N, L, D * H_{out})`,包含输出特征
来自 LSTM 最后一层的 `(h_t)`,对于每个 `t`。
如果输入为 :class:`torch.nn.utils.rnn.PackedSequence`,输出也将是一个打包序列。当 `bidirectional=True` 时,`output` 将包含序列中每个时间步的正向和反向隐藏状态。
将也会是一个打包序列。当 `bidirectional=True` 时,`output` 将包含序列中每个时间步的正向和反向隐藏状态的拼接。
当 `bidirectional=True` 时,`output` 将包含序列中每个时间步的正向和反向隐藏状态的拼接。
* **h_n**: 形状为 :math:`(D * \text{num\_layers}, H_{out})` 的张量,用于未批处理的输入或
`(D * num_layers, N, H_out)` 包含的
序列中每个元素的最终隐藏状态。当 `bidirectional=True` 时,
`h_n` 将包含最终正向和反向隐藏状态的拼接。
* **c_n**: 对于未批处理的输入,形状为 :math:`(D * \text{num\_layers}, H_{cell})` 的张量
math:`(D * \text{num\_layers}, N, H_{cell})` 包含每个序列元素的最终细胞状态。
当 ``bidirectional=True`` 时,
`c_n` 将包含最终正向和反向细胞状态的连接。
属性:
weight_ih_l[k]:第 k 层的可学习输入-隐藏权重。
`(W_ii|W_if|W_ig|W_io)`,形状为 `(4*hidden_size, input_size)`,对于 `k = 0`。
否则,形状为 `(4*hidden_size, num_directions * hidden_size)`。如果
指定了 ``proj_size > 0``,则形状将为
对于 `k > 0`,形状为 `(4*hidden_size, num_directions * proj_size)`
weight_hh_l[k]:第 :math:`\text{k}^{th}` 层的可学习隐藏-隐藏权重
`(W_hi|W_hf|W_hg|W_ho)`,形状为 `(4*hidden_size, hidden_size)`。如果 ``proj_size > 0``
指定后,形状将为 `(4*hidden_size, proj_size)`。
bias_ih_l[k]:第 :math:`\text{k}^{th}` 层的可学习输入-隐藏偏差
`(b_ii|b_if|b_ig|b_io)`,形状为 `(4*hidden_size)`
bias_hh_l[k]:第 :math:`\text{k}^{th}` 层的可学习隐藏-隐藏偏差
`(b_hi|b_hf|b_hg|b_ho)`,形状为`(4*hidden_size)`
weight_hr_l[k]:第:math:`k`层的可学习投影权重
形状为`(proj_size, hidden_size)`。仅在`proj_size > 0`时存在。
已指定。
weight_ih_l[k]_reverse: 与 `weight_ih_l[k]` 在反向方向上的类似。
只有当 ``bidirectional=True`` 时才存在。
weight_hh_l[k]_reverse: 与 `weight_hh_l[k]` 在反向方向上的类似。
只有当 ``bidirectional=True`` 时才存在。
bias_ih_l[k]_reverse: 与 `bias_ih_l[k]` 在反向方向上的类似。
仅当 ``bidirectional=True`` 时存在。
bias_hh_l[k]_reverse: 与 `bias_hh_l[k]` 在反向方向上的类似。
仅当 ``bidirectional=True`` 时存在。
weight_hr_l[k]_reverse:与`weight_hr_l[k]`在反向方向上的类似。
仅当指定了`bidirectional=True`和`proj_size > 0`时存在。
.. 注意::
所有权重和偏置都初始化为:math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})`
其中:math:`k = \frac{1}{\text{hidden\_size}}`
.. 注意::
对于双向 LSTM,正向和反向分别对应方向 0 和 1。
当 ``batch_first=False`` 时输出层拆分的示例:
输出视图(seq_len, 批量, 方向数, 隐藏层大小)
.. 注意::
对于双向 LSTMs,`h_n` 不等于 `output` 的最后一个元素
前者包含最终的向前和向后隐藏状态,而后者包含
最终前向隐藏状态和初始反向隐藏状态。
.. 注意::
对于非批处理输入,"batch_first" 参数被忽略。
.. 注意::
"proj_size" 应小于 "hidden_size"。
.. include:: ../cudnn_rnn_determinism.rst
.. 包含 :: ../cudnn_persistent_rnn.rst
示例:
>>> rnn = nn.LSTM(10, 20, 2)
>>> input = torch.randn(5, 3, 10)
>>> h0 = torch.randn(2, 3, 20)
>>> c0 = torch.randn(2, 3, 20)
输出,(hn,cn) = rnn(input, (h0,c0))
"源代码"
@overload
def 初始化(
self,
输入大小: int,
隐藏层大小: int,
层数:
整型 = 1,
偏差:
布尔类型 = True,
批量优先:
布尔类型 =
错误,
dropout: 浮点数 = 0.0,
双向的:
布尔类型 =
错误,
项目大小:
整型 = 0,
设备=
无,
数据类型=
无,
) -> 无:
...
@overload
def 初始化(self, *
参数, **kwargs):
...
def 初始化(self, *
参数, **kwargs):
超级().
初始化(
LSTM, *
参数, **kwargs)
def 获取预期单元格大小(
self, 输入:
张量, batch_sizes:
可选[
张量]
) -> 元组[int, int, int
]:
如果
批处理大小
是 not
无:
小批量 = int(batch_sizes[0])
否则:
小批量 =
输入.
尺寸(0)
如果 self.
批量优先
否则
输入.
尺寸(1)
方向数 = 2
如果 self.
双向的
否则 1
预期隐藏层大小 = (
self.层数 *
方向数量,
微批,
self.隐藏层大小,
)
返回
预期隐藏层大小
未来我们应该防止 mypy 在这里应用逆变规则
查看 torch/nn/modules/module.py 中的 _forward_unimplemented
def 检查前向参数(
self,
输入:
张量,
隐藏:
元组[
张量,
张量
]
# 类型:忽略[覆盖]
batch_sizes: 可选[
张量
]
):
self.检查输入(
输入, batch_sizes)
self.检查隐藏层大小(
隐藏[0
]
self.获取期望的隐藏层大小(
输入, batch_sizes),
预期隐藏层[0]大小{}
,获得{}",
)
self.检查隐藏层大小(
隐藏[1
]
self.获取期望的单元格大小(
输入, batch_sizes),
预期隐藏[1]大小{}
,获得{}",
)
与上面相同,见 torch/nn/modules/module.py::_forward_unimplemented
def 排列隐藏(
# 类型:忽略[覆盖]
self,
hx: 元组[
张量,
张量
]
排列:
可选[
张量
]
) -> 元组[
张量,
张量
]:
如果
排列
是
无:
返回
h5
返回
应用置换(hx[0
]
排列),
应用排列(
hx[1]
排列
)
# 与上面相同,见 torch/nn/modules/module.py::_forward_unimplemented
@overload # 类型:忽略[覆盖]
@torch._jit_internal.超载方法 # noqa: F811
def 前向(
self, 输入:
张量, hx:
可选[
元组[
张量,
张量]] =
无
) -> 元组[
张量,
元组[
张量,
张量
]] # noqa: F811
通过
与上述相同,请参阅 torch/nn/modules/module.py::_forward_unimplemented
@overload
@torch._jit_internal.超载方法 # noqa: F811
def 前向(
self, 输入: PackedSequence, hx:
可选[
元组[
张量,
张量]] =
无
) -> 元组[PackedSequence,
元组[
张量,
张量
]] # noqa: F811
通过
def 前向(self,
输入, hx=
无): # noqa: F811
self.更新平坦权重()
原始输入 =
输入
对于 TorchScript 编译,isinstance 检查需要在条件中进行
批处理大小 =
无
方向数量 = 2
如果 self.
双向的
否则 1
实际隐藏层大小 = self.proj_size
如果 self.proj_size > 0
否则 self.
隐藏层大小
如果 isinstance(
原始输入, PackedSequence):
输入, batch_sizes,
排序索引,
未排序索引 =
输入
最大批量大小 = batch_sizes[0]
如果
水平方向
是
无:
零填充 =
火炬.
零(
self.层数 *
方向数量,
最大批量大小,
实际隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备,
)
c_零 =
火炬.
零(
self.层数 * num_directions,
最大批量大小,
self.隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备,
)
水平方向 = (
水平零点,
纵向零点)
否则:
每个隐藏状态的批次应与用户认为他/她正在传递的输入序列相匹配。
用户认为他/她正在传递的输入序列。
hx = self.打乱隐藏状态(hx,
排序索引)
否则:
如果
输入.
暗淡() not
在 (2, 3):
提升 ValueError(
fLSTM:期望输入为 2D 或 3D,实际得到{
输入.
暗淡()}
而不是 D
)
批处理 =
输入.
暗淡() == 3
批处理维度 = 0
如果 self.
批量优先
否则 1
如果 not
批处理:
输入 =
输入.
展平(
批处理维度)
最大批量大小 =
输入.
尺寸(0)
如果 self.
批量优先
否则
输入.
尺寸(1)
排序索引 =
无
未排序索引 =
无
如果 hx
是
无:
h_zeros = 火炬.
零(
self.层数 * num_directions,
最大批量大小,
真实隐藏大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备,
)
c_零 =
火炬.
零(
self.层数 * num_directions,
最大批量大小,
self.隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备,
)
hx = (h_zeros, c_zeros)
self.检查前向参数(
输入, hx, batch_sizes)
否则:
如果
批处理:
如果 hx[0].
暗淡() != 3
或 hx[1].
暗淡() != 3:
msg = (
"对于批处理的 3-D 输入,hx 和 cx 也应该"
f"也是 3-D 的,但是得到了("{hx[0].
暗淡()}
-D,{hx[1].
暗淡()}
-D)张量
)
提升
运行时错误(
信息)
否则:
如果 hx[0].
暗淡() != 2
或 hx[1].
暗淡() != 2:
msg = (
"对于未分批的 2-D 输入,hx 和 cx 也应该"
f"也应该是 2-D 的,但得到了("{hx[0].
暗淡()}
-D,{hx[1].
暗淡()}
-D) 张量"
)
提升
运行时错误(
信息)
hx = (hx[0].展平(1), hx[1].
展平(1))
# 每个隐藏状态的批量应与用户认为他/她正在传递的输入序列相匹配。
# 用户认为他/她正在传递的。
self.检查前向参数(
输入, hx, batch_sizes)
hx = self.隐藏排列(hx,
排序索引)
如果
批处理大小
是
无:
结果 = _VF.lstm(
输入,
hx,
self.平坦权重, # type: ignore[arg-type]
self.偏差,
self.层数,
self.dropout,
self.训练,
self.双向的,
self.批量优先,
)
否则:
结果 = _VF.lstm(
输入,
batch_sizes,
hx,
self._平面权重, # type: ignore[arg-type]
self.偏差,
self.层数,
self.dropout,
self.训练,
self.双向的,
)
输出 =
结果[0]
隐藏 =
结果[1
]
# xxx:isinstance 检查需要放在条件语句中以便 TorchScript 编译
如果 isinstance(
原始输入, PackedSequence):
输出打包 = PackedSequence(
输出, batch_sizes,
排序索引,
未排序索引
)
返回
输出打包, self.
隐藏排列(
隐藏,
未排序索引)
否则:
如果 not
批处理: # type: ignore[possibly-undefined]
输出 =
输出.
挤压(
批处理维度) # type: ignore[possibly-undefined]
隐藏 = (
隐藏[0].
挤压(1),
隐藏[1].
挤压(1))
返回
输出, self.
隐藏排列(
隐藏,
未排序索引)
[文档]
类 GRU(RNNBase):
r"__init__(输入大小,隐藏层大小,层数=1,偏置=True,批处理第一=False,dropout=0.0,双向=False,设备=None,数据类型=None)"
将多层门控循环单元(GRU)RNN 应用于输入序列。
对于输入序列中的每个元素,每一层计算以下函数:
函数:
.. math::
\begin{array}{ll}
r_t = σ(W_{ir} x_t + b_{ir} + W_{hr} h_{(t-1)} + b_{hr})
z_t = σ(W_{iz} x_t + b_{iz} + W_{hz} h_{(t-1)} + b_{hz})
n_t = tanh(W_{in} x_t + b_{in} + r_t ⊙ (W_{hn} h_{(t-1)}+ b_{hn}))
h_t = (1 - z_t) ⊙ n_t + z_t ⊙ h_{(t-1)}
\end{array}
在时间`t`,:math:`h_t`是隐藏状态,:math:`x_t`是输入
在时间`t`,:math:`h_{(t-1)}`是层的隐藏状态
在时间`t-1`或时间`0`的初始隐藏状态,以及:math:`r_t`,
math:`z_t`,:math:`n_t`分别是重置、更新和新门
σ是 Sigmoid 函数,而⊙是 Hadamard 积。
在多层 GRU 中,第 l 层的输入 x^(l)_t
(l≥2)是前一层隐藏状态 h^(l-1)_t 乘以
dropout δ^(l-1)_t,其中每个δ^(l-1)_t 是一个伯努利随机
变量以概率:attr:`dropout`取值为:math:`0`。
Args:
输入大小: 输入 `x` 中期望的特征数量。
隐藏层大小: 隐藏状态 `h` 中的特征数量。
层数数量: 循环层的数量。例如,设置 ``num_layers=2``。
这意味着将两个 GRU 堆叠起来形成一个`堆叠 GRU`,
第二个 GRU 接收第一个 GRU 的输出并
计算最终结果。默认:1
偏置:如果为`False`,则该层不使用偏置权重`b_ih`和`b_hh`。
默认:``True``
batch_first:如果为 ``True``,则输入和输出张量以(batch,seq,feature)的形式提供。
以`(batch, seq, feature)`代替`(seq, batch, feature)`。
请注意,此规则不适用于隐藏状态或单元格状态。查看
以下部分为详细信息。默认:``False``
dropout:如果非零,则在每个输出的基础上引入一个`Dropout`层
GRU 层除了最后一层,dropout 概率相等
attr:`dropout`。默认值:0
bidirectional:如果为 True,则变为双向 GRU。默认值:`False`
输入:input,h_0
* **输入**: 形状为 :math:`(L, H_{in})` 的张量,对于非批处理输入,
math:`(L, N, H_{in})` 当 `batch_first=False` 时或
math:`(N, L, H_{in})` 当 `batch_first=True` 时,包含输入序列的特征。
输入也可以是可变长度的打包序列。
查看 :func:`torch.nn.utils.rnn.pack_padded_sequence` 或
func:`torch.nn.utils.rnn.pack_sequence` 以获取详细信息。
* **h_0**: 形状为 :math:`(D * \text{num\_layers}, H_{out})` 或
math:`(D * \text{num\_layers}, N, H_{out})`
包含输入序列的初始隐藏状态。如未提供,则默认为零。
其中:
.. math::
\begin{aligned}
N ={} & \text{批量大小} \\
\( L ={} \) & \text{序列长度} \\
\( D ={} \) & 2 \text{ 如果 bidirectional=True 否则 } 1 \\
\( H_{in} ={} \) & \text{输入\_大小} \\
H_{out} ={} & 隐藏层大小
\end{aligned}
输出:输出,h_n
* **output**: 形状为 :math:`(L, D * H_{out})` 的张量,对于非批处理输入,
math:`(L, N, D * H_{out})` 当 ``batch_first=False`` 时
当 `batch_first=True` 时,包含输出特征 `(N, L, D * H_{out})`
来自 GRU 的最后一层的 `(h_t)`,对于每个 `t`
如果输入为 `:class:`torch.nn.utils.rnn.PackedSequence`,输出也将是一个打包序列
将也会是一个打包序列
* **h_n**: 形状为 :math:`(D * \text{num\_layers}, H_{out})` 或
math:`(D * \text{num\_layers}, N, H_{out})` 包含输入序列的最终隐藏状态
。
属性:
weight_ih_l[k]:第 k 层的可学习输入-隐藏权重。
(W_ir|W_iz|W_in),形状为 `(3*hidden_size, input_size)`,对于 `k = 0` 。
否则,形状为 `(3*hidden_size, num_directions * hidden_size)`
weight_hh_l[k]:第 :math:`\text{k}^{th}` 层的可学习隐藏-隐藏权重
(W_hr|W_hz|W_hn),形状为 `(3*hidden_size, hidden_size)`
bias_ih_l[k]:第 :math:`\text{k}^{th}` 层的可学习输入-隐藏偏置
(b_ir|b_iz|b_in),形状为 `(3*hidden_size)`
bias_hh_l[k]:第 :math:`\text{k}^{th}` 层的可学习隐藏-隐藏偏置
(b_hr|b_hz|b_hn),形状为 `(3*hidden_size)`
.. 注意::
所有权重和偏置都初始化为 :math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})`
其中 :math:`k = \frac{1}{\text{hidden\_size}}`
.. 注意::
双向 GRU 中,正向和反向分别对应方向 0 和 1。
当 ``batch_first=False`` 时输出层拆分的示例:
``output.view(seq_len, batch, num_directions, hidden_size)``.
.. 注意::
对于非批处理输入,``batch_first`` 参数将被忽略。
.. 注意::
新门 :math:`n_t` 的计算与原始论文和其他框架略有不同。
在原始实现中,在乘以权重矩阵之前,先进行 :math:`r_t` 和前一个隐藏状态 :math:`h_{(t-1)}` 的 Hadamard 积 :math:`(\odot)`。
在原始实现中,在乘以权重矩阵之前,先进行 :math:`r_t` 和前一个隐藏状态 :math:`h_{(t-1)}` 的 Hadamard 积 :math:`(\odot)`。
`W` 和偏置项的添加:
.. math::
\begin{aligned}
n_t = tanh(W_{in} x_t + b_{in} + W_{hn} ( r_t \odot h_{(t-1)} ) + b_{hn})
\end{aligned}
这与 PyTorch 实现不同,PyTorch 是在 :math:`W_{hn} h_{(t-1)}` 之后进行的
.. math::
\begin{aligned}
n_t = tanh(W_{in} x_t + b_{in} + r_t \odot (W_{hn} h_{(t-1)}+ b_{hn}))
\end{aligned}
故意这样实现以提高效率。
.. include:: ../cudnn_persistent_rnn.rst
示例:
>>> rnn = nn.GRU(10, 20, 2)
>>> input = torch.randn(5, 3, 10)
>>> h0 = torch.randn(2, 3, 20)
输出,hn = rnn(input, h0)
"源代码"
@overload
def 初始化(
self,
输入大小: int,
隐藏层大小: int,
层数:
整型 = 1,
偏差:
布尔类型 = True,
批量优先:
布尔类型 =
错误,
dropout: 浮点数 = 0.0,
双向的:
布尔类型 =
错误,
设备=
无,
数据类型=
无,
) -> 无:
...
@overload
def 初始化(self, *
参数, **kwargs):
...
def 初始化(self, *
参数, **kwargs):
如果
proj_size
在 kwargs:
提升 ValueError(
"proj_size 参数仅支持 LSTM,不支持 RNN 或 GRU"
)
超级().
初始化(
GRU, *
参数, **kwargs)
@overload # 类型:忽略[覆盖]
@torch._jit_internal.超载方法 # noqa: F811
def 前向(
self, 输入:
张量, hx:
可选[
张量] =
无
) -> 元组[
张量,
张量
]: # noqa: F811
通过
@overload
@torch._jit_internal.超载方法 # noqa: F811
def 前向(
self, 输入: PackedSequence, hx:
可选[
张量] =
无
) -> 元组[PackedSequence,
张量
]: # noqa: F811
通过
def 前向(self,
输入, hx=
无): # noqa: F811
self.更新平坦权重()
原始输入 =
输入
# xxx:isinstance 检查需要放在条件语句中以便 TorchScript 编译
如果 isinstance(
原始输入, PackedSequence):
输入, batch_sizes,
排序索引,
未排序索引 =
输入
最大批量大小 = batch_sizes[0]
如果
h5
是
无:
方向数量 = 2
如果 self.
双向的
否则 1
h5 =
火炬.
零(
self.层数 * num_directions,
最大批量大小,
self.隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备,
)
否则:
# 每个隐藏状态的批量应与用户认为他/她正在传递的输入序列相匹配。
# 用户认为他/她正在传递的。
h5 = self.
隐藏排列(hx,
排序索引)
否则:
批处理大小 =
无
如果
输入.
暗淡() not
在 (2, 3):
提升 ValueError(
f"GRU: 预期输入为 2D 或 3D,但得到的是"{
输入.
暗淡()}
而不是 D
)
批处理 =
输入.
暗淡() == 3
批处理维度 = 0
如果 self.
批量优先
否则 1
如果 not
批处理:
输入 =
输入.
展平(
批处理维度)
如果
h5
是 not
无:
如果 hx.
暗淡() != 2:
提升
运行时错误(
f对于未批处理的 2-D 输入,hx 也应为 2-D,但得到了{hx.
暗淡()}
-D 张量
)
h5 = hx.
展平(1)
否则:
如果
h5
是 not
无
和 hx.
暗淡() != 3:
提升
运行时错误(
f"对于批处理的 3-D 输入,hx 也应该为 3-D,但得到的是"{hx.
暗淡()}
-D 张量
)
最大批量大小 =
输入.
尺寸(0)
如果 self.
批量优先
否则
输入.
尺寸(1)
排序索引 =
无
未排序索引 =
无
如果
h5
是
无:
方向数量 = 2
如果 self.
双向的
否则 1
h5 =
火炬.
零(
self.层数 * num_directions,
最大批量大小,
self.隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备,
)
否则:
# 每个隐藏状态的批量应与用户认为他/她正在传递的输入序列相匹配。
# 用户认为他/她正在传递的。
h5 = self.
隐藏排列(hx,
排序索引)
self.检查前向参数(
输入, hx, batch_sizes)
如果
批处理大小
是
无:
结果 = _VF.gru(
输入,
hx,
self._扁平权重, # type: ignore[arg-type]
self.偏差,
self.层数,
self.dropout,
self.训练,
self.双向的,
self.批量优先,
)
否则:
结果 = _VF.gru(
输入,
batch_sizes,
hx,
self._扁平权重, # type: ignore[arg-type]
self.偏差,
self.层数,
self.dropout,
self.训练,
self.双向的,
)
输出 =
结果[0]
隐藏 =
结果[1]
# xxx:isinstance 检查需要放在条件语句中以便 TorchScript 编译
如果 isinstance(
原始输入, PackedSequence):
输出打包 = PackedSequence(
输出, batch_sizes,
排序索引,
未排序索引
)
返回
输出打包, self.
排列隐藏(
隐藏,
未排序索引)
否则:
如果 not
批处理: # type: ignore[possibly-undefined]
输出 =
输出.
挤压(
批处理维度) # type: ignore[possibly-undefined]
隐藏 =
隐藏.
挤压(1)
返回
输出, self.
隐藏排列(
隐藏,
未排序索引)
类 RNNCellBase(
模块):
常量 = [
输入大小,
隐藏层大小,
偏置]
输入大小:
整型
隐藏层大小:
整型
偏差:
布尔类型
隐藏层到输入层权重:
张量
weight_hh: 张量
# 警告:bias_ih 和 bias_hh 故意在此未定义。
# 请参阅 https://github.com/pytorch/pytorch/issues/39670
def 初始化(
self,
输入大小: int,
隐藏层大小: int,
偏差:
布尔,
num_chunks: int,
设备=
无,
数据类型=
无,
) -> 无:
工厂参数 = {
"设备":
设备, "dtype":
数据类型}
超级().
初始化()
self.输入大小 =
输入大小
self.隐藏层大小 =
隐藏层大小
self.bias = bias
self.weight_ih = 参数(
火炬.
空的((
num_chunks: 分块数量 *
隐藏层大小,
输入大小), **
工厂参数)
)
self.权重_hh =
参数(
火炬.
空的((
num_chunks: 分块数量 *
隐藏层大小,
隐藏层大小), **
工厂参数)
)
如果
偏差:
self.偏置_ih =
参数(
火炬.
空的(
num_chunks: 分块数量 *
隐藏层大小, **
工厂参数)
)
self.偏置_hh =
参数(
火炬.
空的(
num_chunks: 分块数量 *
隐藏层大小, **
工厂参数)
)
否则:
self.注册参数(
"偏置_ih",
无)
self.注册参数(
"偏差_hh",
无)
self.重置参数()
def 额外表示(self) ->
字符串:
s = "{输入大小},
{隐藏层大小}"
如果
偏差
在 self.
字典
和 self.bias
是 not True:
s += ", 偏置="
{偏置}"
如果
"非线性"
在 self.
字典
和 self.
非线性 !=
双曲正切:
s += 非线性=
{非线性}"
返回 s.
格式(**self.
字典)
def 重置参数(self) ->
无:
标准差 = 1.0 /
数学.
平方根(self.
隐藏层大小)
如果 self.
隐藏层大小 > 0
否则 0
为
权重
在 self.
参数():
初始化.
均匀的(
重量, -stdv, stdv)
[文档]
类
RNN 单元(RNNCellBase):
r一个具有 tanh 或 ReLU 非线性函数的 Elman RNN 单元。
.. math::
h' = \tanh(W_{ih} x + b_{ih} + W_{hh} h + b_{hh})
如果 :attr:`nonlinearity` 是 `'relu'`,则使用 ReLU 代替 tanh。
Args:
input_size: 输入 `x` 中期望的特征数量
hidden_size: 隐藏状态 `h` 中的特征数量
偏置:如果为`False`,则该层不使用偏置权重`b_ih`和`b_hh`。
默认:``True``
非线性:要使用非线性函数。可以是 ``'tanh'`` 或 ``'relu'``。默认:``'tanh'``
输入:input, hidden
- **input**:包含输入特征的张量
- **hidden**:包含初始隐藏状态的张量
默认情况下,如果没有提供则设置为 0。
输出:h'
- **h'** 的形状为 `(batch, hidden_size)`:包含下一个隐藏状态的张量
对于批处理中的每个元素
形状:
输入::math:`(N, H_{in})` 或 :math:`(H_{in})` 张量,包含输入特征,
math:`H_{in}` = `input_size`。
输入::math:`(N, H_{out})` 或 :math:`(H_{out})` 张量,包含初始隐藏状态,
math:`H_{out}` = `hidden_size`。如果未提供,默认为零。
- 输出::math:`(N, H_{out})` 或 :math:`(H_{out})` 张量,包含下一个隐藏状态。
属性:
weight_ih:可学习的输入-隐藏权重,形状为
`(hidden_size, input_size)`
weight_hh:可学习的隐藏-隐藏权重,形状为
`(hidden_size, hidden_size)`
bias_ih:可学习的输入-隐藏偏置,形状为`(hidden_size)`
bias_hh:可学习的隐藏-隐藏偏置,形状为`(hidden_size)`
.. 注意::
所有权重和偏置都初始化为 :math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})`
其中 :math:`k = \frac{1}{\text{hidden\_size}}`
示例:
>>> rnn = nn.RNNCell(10, 20)
>>> input = torch.randn(6, 3, 10)
>>> hx = torch.randn(3, 20)
>>> output = []
>>> for i in range(6):
... hx = rnn(input[i], hx)
... output.append(hx)
"源代码"
常量 = [
输入大小,
隐藏层大小,
偏置,
非线性]
非线性:
字符串
def 初始化(
self,
输入大小: int,
隐藏层大小: int,
偏差:
布尔类型 = True,
非线性:
字符串 =
双曲正切,
设备=
无,
数据类型=
无,
) -> 无:
工厂参数 = {
"设备":
设备, "dtype":
数据类型}
超级().
初始化(
输入大小,
隐藏层大小,
偏差, num_chunks=1, **
工厂参数)
self.非线性 =
非线性
def 前向(self,
输入:
张量, hx:
可选[
张量] =
无) ->
张量:
如果
输入.
暗淡() not
在 (1, 2):
提升 ValueError(
f"RNNCell:期望输入为 1D 或 2D,实际得到"{
输入.
暗淡()}
而不是 D
)
如果
h5
是 not
无
和 hx.
暗淡() not
在 (1, 2):
提升 ValueError(
f"RNNCell:期望隐藏状态为 1D 或 2D,实际得到"{hx.
暗淡()}
而不是 D
)
批处理 =
输入.
暗淡() == 2
如果 not
批处理:
输入 =
输入.
展平(0)
如果
h5
是
无:
h5 =
火炬.
零(
输入.
尺寸(0), self.
隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备
)
否则:
h5 = hx.
展平(0)
如果 not
批处理
否则
h5
如果 self.
非线性 ==
双曲正切:
返回 = _VF.rnn_tanh_cell(
输入,
hx,
self.输入层权重,
self.隐藏层权重,
self.输入层偏置,
self.隐藏层偏置,
)
elif self.非线性 ==
ReLU:
返回 = _VF.
RNN-ReLU 单元(
输入,
hx,
self.输入层权重,
self.隐藏层权重,
self.输入层偏置,
self.隐藏层偏置,
)
否则:
返回 =
输入
# TODO: 当 jit 支持异常流程时删除
提升
运行时错误(f
"未知非线性:"{self.
非线性}")
如果 not
批处理:
返回 =
返回.
挤压(0)
返回
返回
[文档]
类 LSTMCell(RNNCellBase):
r"一个长短期记忆(LSTM)单元。"
.. math::
\begin{array}{ll}
i = σ(W_{ii} x + b_{ii} + W_{hi} h + b_{hi}) \\
f = σ(W_{if} x + b_{if} + W_{hf} h + b_{hf})
g = tanh(W_{ig} x + b_{ig} + W_{hg} h + b_{hg})
o = σ(W_{io} x + b_{io} + W_{ho} h + b_{ho})
c' = f ⊙ c + i ⊙ g
h' = o ⊙ tanh(c')
\end{array}
其中 :math:`σ` 是 sigmoid 函数,:math:`⊙` 是 Hadamard 积。
Args:
输入大小:输入 `x` 预期特征的数量
隐藏大小:隐藏状态 `h` 中的特征数量
偏置:如果为 ``False``,则该层不使用偏置权重 `b_ih`
`b_hh`. 默认值:``True``
输入:input, (h_0, c_0)
- **input** 形状为 `(batch, input_size)` 或 `(input_size)`:包含输入特征的张量
- **h_0** 形状为 `(batch, hidden_size)` 或 `(hidden_size)`:包含初始隐藏状态的张量
- **c_0** 形状为 `(batch, hidden_size)` 或 `(hidden_size)`:包含初始细胞状态的张量
如果 `(h_0, c_0)` 未提供,则 **h_0** 和 **c_0** 默认为零。
输出:(h_1, c_1)
- **h_1** 形状为 `(batch, hidden_size)` 或 `(hidden_size)`:包含下一个隐藏状态的张量
- **c_1** 的形状为 `(batch, hidden_size)` 或 `(hidden_size)`:包含下一个细胞状态的张量
属性:
weight_ih:可学习的输入-隐藏权重,形状为
`(4*hidden_size, input_size)`
weight_hh:可学习的隐藏-隐藏权重,形状为
`(4*hidden_size, hidden_size)`
bias_ih: 可学习的输入-隐藏偏置,形状为 `(4*hidden_size)`
bias_hh: 可学习的隐藏-隐藏偏置,形状为 `(4*hidden_size)`
.. 注意::
所有权重和偏置都初始化为 :math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})`
其中 :math:`k = \frac{1}{\text{hidden\_size}}`
在某些 ROCm 设备上,当使用 float16 输入时,此模块将使用:ref:`不同精度`进行反向操作。
示例:
>>> rnn = nn.LSTMCell(10, 20) # (input_size, hidden_size)
>>> input = torch.randn(2, 3, 10) # (时间步长,批量,输入大小)
>>> hx = torch.randn(3, 20) # (批量,隐藏层大小)
>>> cx = torch.randn(3, 20)
>>> output = []
>>> for i in range(input.size()[0]):
... hx, cx = rnn(input[i], (hx, cx))
... output.append(hx)
>>> output = torch.stack(output, dim=0)
"源代码"
def 初始化(
self,
输入大小: int,
隐藏层大小: int,
偏差:
布尔类型 = True,
设备=
无,
数据类型=
无,
) -> 无:
工厂参数 = {
"设备":
设备, "dtype":
数据类型}
超级().
初始化(
输入大小,
隐藏层大小,
偏差, num_chunks=4, **
工厂参数)
def 前向(
self, 输入:
张量, hx:
可选[
元组[
张量,
张量]] =
无
) -> 元组[
张量,
张量
]:
如果
输入.
暗淡() not
在 (1, 2):
提升 ValueError(
fLSTMCell:期望输入为 1D 或 2D,实际得到{
输入.
暗淡()}
而不是 D
)
如果
h5
是 not
无:
为
索引, value
在
列举(hx):
如果
值.
暗淡() not
在 (1, 2):
提升 ValueError(
fLSTMCell:期望 hx[{
索引}
]为 1D 或 2D,实际得到{
值.
暗淡()}
而不是 D
)
批处理 =
输入.
暗淡() == 2
如果 not
批处理:
输入 =
输入.
展平(0)
如果
h5
是
无:
零值 =
火炬.
零(
输入.
尺寸(0), self.
隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备
)
hx = (零,
零)
否则:
hx = (hx[0].展平(0), hx[1].
展平(0))
如果 not
批处理
否则
h5
返回 = _VF.
LSTM 单元(
输入,
hx,
self.输入层权重,
self.隐藏层权重,
self.输入层偏置,
self.隐藏层偏置,
)
如果 not
批处理:
返回 = (
返回[0].
挤压(0),
返回[1].
挤压(0))
返回
返回
[文档]
类
GRU 单元(RNNCellBase):
r"""门控循环单元(GRU)单元。"""
.. math::
\begin{array}{ll}
r = σ(W_{ir} x + b_{ir} + W_{hr} h + b_{hr})
z = σ(W_{iz} x + b_{iz} + W_{hz} h + b_{hz})
n = tanh(W_{in} x + b_{in} + r ⊙ (W_{hn} h + b_{hn}))
h' = (1 - z) ⊙ n + z ⊙ h
\end{array}
其中 :math:`σ` 是 sigmoid 函数,:math:`⊙` 是 Hadamard 积。
Args:
输入大小:输入 `x` 预期特征的数量
隐藏大小:隐藏状态 `h` 中的特征数量
偏置:如果为 ``False``,则该层不使用偏置权重 `b_ih`
`b_hh`. 默认:``True``
输入:input, 隐藏
- **input**:包含输入特征的张量
- **hidden**:包含初始隐藏状态的张量
批量中每个元素的当前状态。
如果未提供,则默认为零。
输出:h'
- **h'**:包含下一个隐藏状态的张量
批量中的每个元素
形状:
- 输入::math:`(N, H_{in})` 或 :math:`(H_{in})` 张量,包含输入特征
math:`H_{in}` = 输入大小。
- 隐藏层::math:`(N, H_{out})` 或 :math:`(H_{out})` 张量,包含初始隐藏状态
状态,其中 :math:`H_{out}` = `hidden_size`。如果未提供,则默认为零。
输出::math:`(N, H_{out})` 或 :math:`(H_{out})` 张量,包含下一个隐藏状态。
属性:
weight_ih:可学习的输入-隐藏权重,形状为
`(3*hidden_size, input_size)`
weight_hh:可学习的隐藏-隐藏权重,形状为
`(3*hidden_size, hidden_size)`
bias_ih:可学习的输入-隐藏偏置,形状为`(3*hidden_size)`
bias_hh:可学习的隐藏-隐藏偏置,形状为`(3*hidden_size)`
.. 注意::
所有权重和偏置都初始化为 :math:`\mathcal{U}(-\sqrt{k}, \sqrt{k})`
其中 :math:`k = \frac{1}{\text{hidden\_size}}`
在某些 ROCm 设备上,当使用 float16 输入时,此模块将使用:ref:`不同精度`进行反向操作。
示例:
>>> rnn = nn.GRUCell(10, 20)
>>> input = torch.randn(6, 3, 10)
>>> hx = torch.randn(3, 20)
>>> output = []
>>> for i in range(6):
... hx = rnn(input[i], hx)
... output.append(hx)
"源代码"
def 初始化(
self,
输入大小: int,
隐藏层大小: int,
偏差:
布尔类型 = True,
设备=
无,
数据类型=
无,
) -> 无:
工厂参数 = {
"设备":
设备, "dtype":
数据类型}
超级().
初始化(
输入大小,
隐藏层大小,
偏差, num_chunks=3, **
工厂参数)
def 前向(self,
输入:
张量, hx:
可选[
张量] =
无) ->
张量:
如果
输入.
暗淡() not
在 (1, 2):
提升 ValueError(
fGRUCell:期望输入为 1D 或 2D,实际得到{
输入.
暗淡()}
而不是 D
)
如果 hx
是 not
无
和 hx.
暗淡() not
在 (1, 2):
提升 ValueError(
fGRUCell:期望隐藏状态为 1D 或 2D,实际得到{hx.
暗淡()}
而不是 D
)
批处理 =
输入.
暗淡() == 2
如果 not
批处理:
输入 =
输入.
展平(0)
如果 hx
是
无:
hx = 火炬.
零(
输入.
尺寸(0), self.
隐藏层大小,
数据类型=
输入.
数据类型,
设备=
输入.
设备
)
否则:
水平方向 = hx.
展平(0)
如果 not
批处理
否则
水平方向
返回 = _VF.
gru 单元(
输入,
hx,
self.weight_ih,
self.weight_hh,
self.偏差_ih,
self.偏差_hh,
)
如果 not
批处理:
返回 =
返回.
挤压(0)
返回
返回