""
我们将重新创建所有 RNN 模块,因为我们需要的模块需要被分解
深入到其基本组成部分以便能够观察。
""
# mypy: 允许未类型化定义
导入
数字
导入
警告
来自
打字
导入
可选
导入
火炬
来自
火炬
导入
张量
__all__ = [LSTM 单元,
"长短期记忆网络"]
类 LSTMCell(
火炬.nn.
模块):
r可量化的长短期记忆(LSTM)单元。
对于描述和参数类型,请参阅:class:`~torch.nn.LSTMCell`。
`split_gates`:指定为 True 以分别计算输入/遗忘/细胞/输出门。
避免中间张量随后被分块。这种优化对设备上的推理延迟有益。此标志从父类级联下来。
适用于设备上推理延迟的优化。此标志从父类级联下来。
来自父类。
示例:
>>> 导入 torch.ao.nn.quantizable 作为 nnqa
>>> rnn = nnqa.LSTMCell(10, 20)
>>> input = torch.randn(6, 10)
>>> hx = torch.randn(3, 20)
>>> cx = torch.randn(3, 20)
>>> output = []
>>> for i in range(6):
... hx, cx = rnn(input[i], (hx, cx))
... output.append(hx)
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
浮点模块 =
火炬.nn.LSTMCell
常量 = ["split_gates"] # for jit.script
def 初始化(
自身,
输入维度: int,
隐藏维度: int,
偏差:
布尔类型 = True,
设备=
无,
数据类型=
无,
*,
分割门=
错误,
) -> 无:
工厂参数 = {
"设备":
设备, "dtype":
数据类型}
超级().
初始化()
自身.
输入大小 =
输入维度
自身.hidden_size =
隐藏维度
自身.bias = bias
自身.
分割门 =
分裂门
如果 not
分割门:
自身.igates:
火炬.nn.
模块 =
火炬.nn.
线性(
输入维度, 4 *
隐藏维度,
偏差=
偏差, **
工厂参数
)
自身.hgates:
火炬.nn.
模块 =
火炬.nn.
线性(
隐藏维度, 4 *
隐藏维度,
偏差=
偏差, **
工厂参数
)
自身.
罗格斯:
火炬.nn.
模块 =
火炬.ao.nn.
量化.
浮点功能()
否则:
每个门保持独立的线性层
自身.
网格 =
火炬.nn.ModuleDict()
自身.
网格 =
火炬.nn.ModuleDict()
自身.
门 =
火炬.nn.ModuleDict()
为 g
在 [
输入,
忘记,
细胞,
输出
]:
# pyre-fixme[29]: `Union[torch._tensor.Tensor, torch.nn.modules.module.Module]`
自身.igates[g] =
火炬.nn.
线性(
输入维度,
隐藏维度,
偏差=
偏差, **
工厂参数
)
# pyre-fixme[29]: `Union[torch._tensor.Tensor, torch.nn.modules.module.Module]`
自身.hgates[g] =
火炬.nn.
线性(
隐藏维度,
隐藏维度,
偏差=
偏差, **
工厂参数
)
# pyre-fixme[29]: `Union[torch._tensor.Tensor, torch.nn.modules.module.Module]`
自身.
门控[g] =
火炬.ao.nn.
量化.
浮点功能()
自身.
输入门 =
火炬.nn.Sigmoid()
自身.
遗忘门 =
火炬.nn.Sigmoid()
自身.
单元门 =
火炬.nn.
双曲正切函数()
自身.
输出门 =
火炬.nn.Sigmoid()
自身.fgate_cx =
火炬.ao.nn.
量化.
浮点功能()
自身.igate_cgate =
火炬.ao.nn.
量化.
浮点功能()
自身.fgate_cx_igate_cgate =
火炬.ao.nn.
量化.
浮点功能()
自身.ogate_cy =
火炬.ao.nn.
量化.
浮点功能()
自身.initial_hidden_state_qparams:
元组[float, int] = (1.0, 0)
自身.initial_cell_state_qparams:
元组[float, int] = (1.0, 0)
自身.
隐藏状态数据类型:
火炬.dtype =
火炬.
无符号 8 位整数
自身.
细胞状态数据类型:
火炬.dtype =
火炬.
无符号 8 位整数
def 前向(
自身, x:
张量,
隐藏:
可选[
元组[
张量,
张量]] = None
) -> 元组[
张量,
张量
]:
如果
隐藏
是 None
或
隐藏[0]
是 None
或
隐藏[1]
是
无:
隐藏 =
自身.
初始化隐藏层(x.shape[0
] x.
是否量化)
hx, cx = 隐藏
如果 not
自身.
分裂门:
网格 =
自身.
网格(x)
网格 =
自身.
网格(hx)
罗格斯 =
自身.
罗格斯.
添加(igates, hgates) # type: ignore[operator]
输入门,
遗忘门,
细胞门,
出口门 =
门.
数据块(4, 1)
输入门 =
自身.
输入门(
输入门)
遗忘门 =
自身.
遗忘门(
忘却门)
单元门 =
自身.
单元门(
单元门)
出口门 =
自身.
输出门(
出口门)
否则:
# 应用每个输入 + 隐藏投影并相加
门 = {}
为 (
键,
闸门),
逻辑门,
高速闸门
在
压缩(
自身.
罗格斯.
项目(), # type: ignore[operator]
自身.igates.
值(), # type: ignore[operator]
自身.hgates.
值(), # type: ignore[operator]
):
门[
键] =
罗格斯.
添加(igates(x), hgates(hx))
输入门 =
自身.
输入门(
门[
输入])
遗忘门 =
自身.
遗忘门(
闸门[
忘记])
细胞门 =
自身.
细胞门(
闸门[
细胞])
输出闸门 =
自身.
输出门(
门[
输出])
fgate_cx = 自身.fgate_cx.
多(
忘记门, cx)
igate_cgate = 自身.
逻辑门.
多(
输入门,
单元门)
F 门_CX_逻辑门_输入门 =
自身.
前门_中继门_后门.
添加(
前门_中继门,
中继门_后门)
电流 = fgate_cx_igate_cgate
# TODO: 将 tanh 作为模块的成员,以便可以配置其 qparams
tanh_cy = 火炬.
双曲正切(cy)
hy = 自身.
出口_希.
多(
出口,
湍流_希)
返回 hy, cy
def 初始化隐藏(
自身,
批处理大小: int,
是否量化:
布尔类型 =
假
) -> 元组[
张量,
张量
]:
h, c = 火炬.
零((
批处理大小,
自身.
隐藏层大小)),
火炬.
零(
(批处理大小,
自身.
隐藏层大小)
)
如果
是否量化:
(h_scale, h_zp) = 自身.initial_hidden_state_qparams
(c_scale, c_zp) = 自身.
初始细胞状态参数
h = 火炬.
按张量量化(
h, 比例=
h 比例,
零点=h_zp,
数据类型=
自身.
隐藏状态数据类型
)
c = 火炬.
按张量量化(
c, 比例=c_scale,
零点=c_zp,
数据类型=
自身.
细胞状态数据类型
)
返回 h, c
def _获取名称(
自身):
返回
"可量化的 LSTM 单元"
@classmethod
def from_params(类, wi, wh, bi=
无, bh=
无,
分裂门=
错误):
使用权重和偏置创建新的 LSTM 单元。
参数:
wi, wh:输入层和隐藏层的权重
输入和隐藏层的偏差
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
断言 (bi
是
无) == (bh
是
无)
# 要么两者都为空,要么两者都有值
输入大小 = wi.shape[1]
hidden_size = 无法翻译,输入内容为空.shape[1]
细胞 =
类(
输入维度=
输入大小,
隐藏维度=
隐藏层大小,
偏差=(
双向
是 not
无),
分裂门=
分裂门,
)
如果 not
分裂门:
细胞.
逻辑门.
权重 =
火炬.nn.
参数(wi)
如果
双极
是 not
无:
细胞.
线路.bias =
火炬.nn.
参数(
二)
细胞.
高速.
权重 =
火炬.nn.
参数(
线)
如果 bh
是 not
无:
细胞.
hgate.bias =
火炬.nn.
参数(bh)
否则:
# 分割权重/偏差
为 w, b,
门
在
压缩([wi,
为
] [
二,
乙
] [
细胞.
线路,
细胞.
线路门
)]
为
w_块,
门
在
压缩(w.
数据块(4,
暗淡=0),
窗户.
值()): # type: ignore[operator]
门.
权重 =
火炬.nn.
参数(
w 块)
如果 b
是 not
无:
为
b 块,
闸门
在
压缩(b.
数据块(4,
暗淡=0),
闸门们.
值()): # type: ignore[operator]
闸门.bias =
火炬.nn.
参数(
b 块)
返回
细胞
@classmethod
def 从浮点数(
类,
其他,
使用预计算的假量化=
错误,
分裂门=
错误):
断言
类型(
其他) ==
类.
浮点模块
断言
有属性(
其他,
qconfig),
"浮点模块必须具有 'qconfig'"
观察 =
类.
从参数(
其他.
输入层权重,
其他.weight_hh,
其他.
偏差_ih,
其他.
隐藏层偏置,
分裂门=
分裂门,
)
观察.qconfig =
其他.qconfig
观察.
逻辑门.qconfig =
其他.qconfig
观察.
高速门.qconfig =
其他.qconfig
如果
分割门:
# 也直接将 qconfig 应用到线性模块
为 g
在
观察.
纬度.
值():
g.qconfig = 其他.qconfig
为 g
在
观察.
经度.
值():
g.qconfig = 其他.qconfig
返回
观察
类 _LSTMSingleLayer(
火炬.nn.
模块):
r“一个单向 LSTM 层。
层和单元的区别在于层可以处理
序列,而细胞只期望一个瞬时的值。
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
def 初始化(
自身,
输入维度: int,
隐藏维度: int,
偏差:
布尔类型 = True,
设备=
无,
数据类型=
无,
*,
分割门=
错误,
) -> 无:
工厂参数 = {
"设备":
设备, "dtype":
数据类型}
超级().
初始化()
自身.
细胞 = LSTMCell(
输入维度,
隐藏维度,
偏差=
偏置,
分裂门=
分裂门, **
工厂参数
)
定义
前向(
自身, x:
张量,
隐藏:
可选[
元组[
张量,
张量]] =
无):
结果 = []
序列长度 = x.shape[0]
为 i
在
范围(
序列长度):
隐藏 =
自身.
细胞(x[i
]
隐藏)
结果.
追加(
隐藏[0])
忽略索引
结果张量 =
火炬.
栈(
结果, 0)
返回
结果张量,
隐藏
@classmethod
def 从参数(
类, *
参数, **kwargs):
细胞 = LSTMCell.
从参数(*
参数, **kwargs)
层 =
类(
细胞.
输入大小,
细胞.
隐藏层大小,
细胞.
偏差,
分割门=
细胞.
分割门
)
层.
细胞 =
细胞
返回
层
类
LSTM 层(
火炬.nn.
模块):
r“这是一个单向 LSTM 层。”
def 初始化(
自身,
输入维度: int,
隐藏维度: int,
偏差:
布尔类型 = True,
批量优先:
布尔类型 =
错误,
双向的:
布尔类型 =
错误,
设备=
无,
数据类型=
无,
*,
分裂门=
错误,
) -> 无:
工厂参数 = {
"设备":
设备, "dtype":
数据类型}
超级().
初始化()
自身.
批量优先 =
批量优先
自身.
双向 =
双向
自身.
层前向 = _LSTMSingleLayer(
输入维度,
隐藏维度,
偏差=
偏差,
分割门=
分割门, **
工厂参数
)
如果
自身.
双向的:
自身.
层位宽 = _LSTMSingleLayer(
输入维度,
隐藏维度,
偏差=
偏差,
分裂门=
分割门,
**工厂参数,
)
def 前向(
自身, x:
张量,
隐藏:
可选[
元组[
张量,
张量]] =
无):
如果
自身.
批量优先:
x = x.转置(0, 1)
如果
隐藏
是
无:
水平翻转,
环形翻转 = (
无,
无)
否则:
水下前向,
中心前向 =
隐藏
隐藏黑波:
可选[
元组[
张量,
张量]] = None
如果
自身.
双向的:
如果
水下前向
是
无:
hx_bw = None
否则:
hx_bw = hx_fw[1]
hx_fw = 水下前向[0]
如果
中心前向
是
无:
中心后向 = None
否则:
中心后向 = cx_fw[1]
cx_fw = cx_fw[0]
如果 hx_bw
是 not None
和 cx_bw
是 not
无:
hidden_bw = hx_bw, cx_bw
如果
火焰前部
是 None
和
火焰中心
是
无:
隐藏火焰前部 = None
否则:
隐藏火焰前部 =
火炬.
算子.
解包可选(
水下飞行器),
火炬.
算子.
解包可选(
水下推进器
)
结果飞行器,
隐藏飞行器 =
自身.
层面防火墙(x,
隐藏防火墙)
如果
有属性(
自身,
"层面后向")
和
自身.
双向的:
X 反向 = x.
翻转(0)
黑白结果,
隐藏的黑白 =
自身.
图层黑白(
X 反转,
隐藏黑白色)
黑白色结果 =
黑白色结果.
翻转(0)
结果 =
火炬.
猫([
灰度结果,
黑白结果
]
彩色结果.
暗淡() - 1)
如果
隐藏彩色
是 None
和
隐藏黑白
是
无:
h = None
c = None
elif 隐藏式前向
是
无:
(h, c) = 火炬.
算子.
解包可选(
隐藏式后向)
elif 隐藏式后向
是
无:
(h, c) = 火炬.
算子.
解包可选(
隐藏式前向)
否则:
h = 火炬.
栈([
隐藏式前向[0
]
隐藏式后向[0]], 0) # type: ignore[list-item]
c = 火炬.
栈([
隐藏式前向[1
]
隐藏式后向[1]], 0) # type: ignore[list-item]
否则:
结果 =
结果前缀
h, c = 火炬.
算子.
解包可选(
隐藏前缀)
# 类型:忽略[赋值]
如果
自身.
批量优先:
结果.
转置 _(0, 1)
返回
结果, (h, c)
@classmethod
def 从浮点数(
类,
其他,
层索引=0, qconfig=
无, **kwargs):
r""
这个类没有 FP 等效。此函数只是在这里
模拟 `torch.ao.quantization` 中 `prepare` 的行为
流
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
断言
有属性(
其他,
qconfig)
或 (qconfig
是 not
无)
输入大小 = kwargs.
获取(
输入大小,
其他.
输入大小)
hidden_size = kwargs.获取(
隐藏层大小,
其他.
隐藏层大小)
bias = kwargs.获取(
偏置,
其他.
偏差)
批量优先 = kwargs.
获取("batch_first",
其他.
批量优先)
双向 = kwargs.
获取(
双向,
其他.
双向的)
分割门 = kwargs.
获取(
"分割门",
错误)
层 =
类(
输入大小,
隐藏层大小,
偏差,
批量优先,
双向的,
分割门=
分割门,
)
层.qconfig = getattr(
其他,
qconfig, qconfig)
wi = getattr(其他, f
weight_ih_l{
层索引}")
wh = getattr(其他, f
weight_hh_l{
层索引}")
双向 = getattr(
其他, f
bias_ih_l{
层索引}",
无)
沉浸式翻译 = getattr(
其他, f
bias_hh_l{
层索引}",
无)
层.
层级防火墙 = _LSTMSingleLayer.
从参数(
wi, wh, bi, bh, 分裂门=
分割栅格
)
如果
其他.
双向的:
wi = getattr(其他, f
weight_ih_l{
层索引}
_反向")
wh = getattr(其他, f
weight_hh_l{
层索引}
反转)
双 = getattr(
其他, f
bias_ih_l{
层索引}
反转,
无)
沉浸式翻译 = getattr(
其他, f
bias_hh_l{
层索引}_reverse",
无)
层.
层位宽 = _LSTMSingleLayer.from_params(
wi, what,
双,
两者,
分裂门=
分裂门
)
返回
层
[文档]
类
长短期记忆网络(
火炬.nn.
模块):
r可量化的长短期记忆(LSTM)
关于描述和参数类型,请参阅:class:`~torch.nn.LSTM`
属性:
层:_LSTMLayer 实例
.. 注意::
要访问权重和偏差,需要逐层访问。
查看以下示例。
示例:
>>> 导入 torch.ao.nn.quantizable 作为 nnqa
>>> rnn = nnqa.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))
>>> # 获取权重:
>>> # xdoctest: +SKIP
>>> print(rnn.layers[0].weight_ih)
tensor([[...]])
>>> print(rnn.layers[0].weight_hh)
AssertionError: There is no reverse path in the non-bidirectional layer
```python
# 假设输入文本为:
input_text = '"""'
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
浮点模块 =
火炬.nn.LSTM
def 初始化(
自身,
输入大小: int,
隐藏层大小: int,
层数:
整型 = 1,
偏差:
布尔类型 = True,
批量优先:
布尔类型 =
错误,
dropout: 浮点数 = 0.0,
双向的:
布尔类型 =
错误,
设备=
无,
数据类型=
无,
*,
分裂门:
布尔类型 =
错误,
) -> 无:
工厂参数 = {
"设备":
设备, "dtype":
数据类型}
超级().
初始化()
自身.
输入大小 =
输入大小
自身.hidden_size = hidden_size
自身.
层数 =
层数
自身.
偏差 = bias
自身.
批量优先 =
批量优先
自身.dropout = float(dropout)
自身.
双向 =
双向
自身.
训练 =
假
默认为评估模式。如果我们想进行训练,我们将明确设置为训练模式。
如果 (
not isinstance(dropout, 数字.
数字)
或 not 0
≤ dropout
≤ 1
或 isinstance(dropout,
布尔)
):
抛出异常 ValueError(
"dropout 应该是一个在 [0, 1] 范围内的数字"
表示一个元素被置零的概率
零化
)
如果 dropout > 0:
warnings.警告(
"量化 LSTM 的 dropout 选项被忽略。"
"如果您正在训练,请使用 nn.LSTM 版本 "
"之后是 `准备` 步骤。"
)
如果
层数 == 1:
warnings.警告(
"dropout 选项在所有层之后添加 dropout,但最后一个层除外,因此非零 dropout 期望"
"循环层之后,所以非零 dropout 期望"
f"num_layers 的值大于 1,但得到了 dropout="{dropout} "
fand num_layers={
层数}"
)
层 = [
_LSTMLayer(
自身.
输入大小,
自身.
隐藏层大小,
自身.
偏差,
批量优先=
错误,
双向的=
自身.
双向的,
分割门=
分割门,
**factory_kwargs,
)
]
层.
扩展(
LSTM 层(
自身.
隐藏层大小,
自身.
隐藏层大小,
自身.
偏差,
批量优先=
错误,
双向的=
自身.
双向的,
分裂门=
分割门,
**工厂参数,
)
为 _
在
范围(1,
层数)
)
自身.
层 =
火炬.nn.
模块列表(
层)
def 前向(
自身, x:
张量,
隐藏:
可选[
元组[
张量,
张量]] =
无):
如果
自身.
批量优先:
x = x.转置(0, 1)
最大批量大小 = x.
尺寸(1)
方向数量 = 2
如果
自身.
双向
否则 1
如果
隐藏
是
无:
零值 =
火炬.
零(
方向数量,
最大批量大小,
自身.
隐藏层大小,
数据类型=
火炬.float,
设备=x.
设备,
)
零.
挤压_(0)
如果 x.
是否量化:
零值 =
火炬.
按张量量化(
零,
比例=1.0,
零点=0,
数据类型=x.dtype
)
恶心 =
[
零,
零)
为 _
在
范围(
自身.
层数
]
否则:
隐藏非优化 =
火炬.
算子.
解包可选(
隐藏)
如果 isinstance(
隐藏非优化[0
]
张量):
hx = 隐藏非优化[0].
重塑(
自身.
层数,
方向数量,
最大批量大小,
自身.hidden_size
)
cx = 隐藏非优化[1].
重塑(
自身.
层数,
方向数量,
最大批量大小,
自身.hidden_size
)
hxcx = [
(hx[索引].
挤压(0), cx[
索引].
挤压(0))
为
索引
在
范围(
自身.
层数)
]
否则:
恶心 =
隐藏非优化
恶心列表 = []
创意列表 = []
为
索引,
层
在
列举(
自身.
层):
x, (h, c) = 层(x,
恶心[
索引])
恶心列表.
追加(
火炬.
算子.
解包可选(h))
刺激列表.
追加(
火炬.
算子.
解包可选(c))
恶心张量 =
火炬.
栈(
hx 列表)
cx 张量 =
火炬.
栈(
cx 列表)
# 我们为双向案例创建另一个维度
需要合并
hx_tensor = hx_tensor.重塑(-1, hx_tensor.shape[-2
]
hx 张量.shape[-1])
cx 张量 =
cx 张量.
重塑(-1, cx_tensor.shape[-2
] cx_tensor.shape[-1])
如果
自身.
批量优先:
x = x.转置(0, 1)
返回 x, (hx_tensor, cx_tensor)
def _获取名称(
自身):
返回
可量化的 LSTM
@classmethod
def 从浮点数(
类,
其他, qconfig=
无,
分割门=
错误):
断言 isinstance(
其他,
类._FLOAT_MODULE)
断言
有属性(
其他,
qconfig)
或 qconfig
观察 =
类(
其他.
输入大小,
其他.
隐藏层大小,
其他.
层数,
其他.
偏差,
其他.
批量优先,
其他.dropout,
其他.
双向的,
分裂门=
分割门,
)
观察.qconfig = getattr(
其他,
qconfig, qconfig)
为
索引
在
范围(
其他.
层数):
观察.
层[
索引] =
LSTM 层.
从浮点数(
其他,
索引, qconfig,
批量优先=
错误,
分裂门=
分裂门
)
# 准备模型
如果
其他.
训练:
观察.
训练()
观察 =
火炬.ao.
量化.
准备量化加速训练(
观察,
内置=True)
否则:
观察.
评估()
观察 =
火炬.ao.
量化.prepare(
观察,
内置=True)
返回
观察
@classmethod
def 来自观察(
类,
其他):
整个流程是浮点数 -> 观察到 -> 量化
这个类只做浮点数 -> 观察到
抛出异常
不支持的操作异常(
"看起来您正在尝试转换一个"
"无法量化的 LSTM 模块。请参阅"
"可量化 LSTMs 的示例。"
)