torch.distributions.lowrank_multivariate_normal 的源代码
# mypy: 允许未类型化定义
导入
数学
导入
火炬
from 火炬
导入
张量
from torch.distributions 导入
约束
from torch.distributions.distribution 导入
分布
from torch.distributions.multivariate_normal 导入 _batch_mahalanobis,
批量移动
from torch.distributions.utils 导入
标准正态,
懒加载属性
from torch.types 导入
_大小
全部 = [
低秩多元正态分布]
定义
批量电容三角(W, D):
r
```python
# 假设输入文本为:
input_text = """Immersive Translate"""
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text # 假设翻译结果与原文相同
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
输出:
```
Immersive Translate
```
计算矩阵批量的 Cholesky 分解::math:`I + W.T @ inv(D) @ W`
以及向量批量的 :math:`D`。
"""
m = W.大小(-1)
Wt_Dinv = W.mT / D.展平(-2)
K = 火炬.
矩阵乘法(Wt_Dinv, W).
连续()
K.视图(-1, m * m)[:, :: m + 1] += 1
# 添加单位矩阵到 K
return 火炬.
线性代数.
转置分解(K)
定义 _batch_lowrank_logdet(W, D,
电容_tril):
r
```python
# 假设输入文本为:
input_text = """Immersive Translate"""
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text # 假设翻译结果与原文相同
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
输出:
```
Immersive Translate
```
使用“矩阵行列式引理”
log|W @ W.T + D| = log|C| + log|D|,
其中:math:`C` 是电容矩阵:math:`I + W.T @ inv(D) @ W`,用于计算
对数行列式。
"""
return 2 * 电容三重积分.
对角线(dim1=-2, dim2=-1).
日志().
总和(-1) + D.
日志().
总和(
-1
)
定义
_低秩马氏距离批处理(W, D, x,
电容三重积分):
r
```python
# 假设输入文本为:
input_text = """Immersive Translate"""
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text # 假设翻译结果与原文相同
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
输出:
```
Immersive Translate
```
使用“Woodbury 矩阵恒等式”::
inv(W @ W.T + D) = inv(D) - inv(D) @ W @ inv(C) @ W.T @ inv(D),
其中 :math:`C` 是电容矩阵 :math:`I + W.T @ inv(D) @ W`,用于计算平方
马氏距离 :math:`x.T @ inv(W @ W.T + D) @ x`。
"""
Wt_Dinv = W.mT / D.展平(-2)
Wt_Dinv_x = _批量移动(Wt_Dinv, x)
马氏距离项 1 = (x.pow(2) / D).
总和(-1)
马氏距离项 2 =
_批量马氏距离(
电容三联, Wt_Dinv_x)
return 马哈拉诺比斯项 1 -
马哈拉诺比斯项 2
[文档]
类
低秩多元正态分布(
分发):
r
```python
# 假设输入文本为:
input_text = """Immersive Translate"""
# 翻译函数(此处仅为示例,实际翻译功能需要调用真实的翻译 API)
def translate_to_simplified_chinese(text):
# 这里应该调用真实的翻译 API 进行翻译
# 由于示例中不使用真实的 API,以下为模拟翻译结果
return text # 假设翻译结果与原文相同
# 输出翻译结果
translated_text = translate_to_simplified_chinese(input_text)
print(translated_text)
```
输出:
```
Immersive Translate
```
创建具有低秩形式的协方差矩阵的多变量正态分布
通过 :attr:`cov_factor` 和 :attr:`cov_diag` 参数化::
covariance_matrix = cov_factor @ cov_factor.T + cov_diag
示例:
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_LAPACK)
>>> # xdoctest: +IGNORE_WANT("非确定性")
>>> m = LowRankMultivariateNormal(
... torch.zeros(2), torch.tensor([[1.0], [0.0]]), torch.ones(2)
... )
>>> m.sample() # 正态分布,均值为 `[0,0]`,协方差因子为 `[[1],[0]]`,协方差对角线为 `[1,1]`
tensor([-0.2102, -0.5429])
参数:
loc (Tensor):分布的均值,形状为 `batch_shape + event_shape`
cov_factor (Tensor):协方差矩阵低秩形式的因子部分,形状为
`batch_shape + event_shape + (rank,)`
cov_diag (Tensor):协方差矩阵低秩形式的对角部分,形状为
`batch_shape + event_shape`
注意:
计算协方差矩阵的行列式和逆矩阵被避免
`cov_factor.shape[1] 小于 cov_factor.shape[0]` 多亏了 `Woodbury 矩阵恒等式`
`《伍德伯里矩阵恒等式》`_ 和
矩阵行列式引理 _.
感谢这些公式,我们只需计算行列式和逆矩阵
小型“电容”矩阵::
电容 = I + cov_factor.T @ inv(cov_diag) @ cov_factor
"""
约束参数 = {
"loc": 约束.
实向量,
cov_factor:
约束.
独立(
约束.
真实, 2),
cov_diag:
约束.
独立(
约束.
正的, 1),
}
支持 =
约束.
实向量
has_rsample = 真实
定义 __init__(self,
位置,
疫情系数,
诊断协方差,
验证参数=
无):
如果
位置.
暗() < 1:
抛出
值错误(
"位置至少需要为一维。")
事件形状 =
位置.
形状[-1
]
如果
疫情系数.
暗() < 2:
抛出
值错误(
"cov_factor 至少必须是二维的,"
"可选的批处理维度前缀"
)
如果 cov_factor.
形状[-2:-1] != event_shape:
抛出
值错误(
f"cov_factor 必须是一个形状的矩阵批处理"{event_shape[0]}
x m
)
如果
协方差诊断.
形状[-1
] != event_shape:
抛出
值错误(
f"协方差诊断必须是一个形状为向量的批次"{event_shape}"
)
loc_ = 位置.
展平(-1)
cov_diag_ = cov_diag.展平(-1)
尝试:
loc_, self.cov_factor, cov_diag_ = 火炬.
广播张量(
loc_, cov_factor, cov_diag_
)
除了
运行时错误
是 e:
抛出
值错误(
f"不兼容的批量形状:loc"{
位置.
形状}, cov_factor {cov_factor.
形状}, cov_diag {
疫情诊断.
形状}"
) from e
self.定位 =
定位_[..., 0]
self.疫情诊断 =
疫情诊断_[..., 0]
批量形状 = self.
位置.
形状
[-1]
self.未广播的协方差因子 =
协方差因子
self.未广播的对角协方差 =
对角协方差
self.三倍电容 =
批量三倍电容(
协方差因子,
协方差对角线)
超级().__init__(
批量形状, event_shape,
验证参数=
验证参数)
[文档] def expand(self, batch_shape, _instance=None):
new = self._get_checked_instance(LowRankMultivariateNormal, _instance)
batch_shape = torch.Size(batch_shape)
loc_shape = batch_shape + self.event_shape
new.loc = self.loc.expand(loc_shape)
new.cov_diag = self.cov_diag.expand(loc_shape)
new.cov_factor = self.cov_factor.expand(loc_shape + self.cov_factor.shape[-1:])
new._unbroadcasted_cov_factor = self._unbroadcasted_cov_factor
new._unbroadcasted_cov_diag = self._unbroadcasted_cov_diag
new._capacitance_tril = self._capacitance_tril
super(LowRankMultivariateNormal, new).__init__(
batch_shape, self.event_shape, validate_args=False
)
new._validate_args = self._validate_args
return new
@property
定义
均值(self)
翻译
张量:
return self.定位
@property
定义
模式(self)
翻译
张量:
return self.定位
@lazy_property
定义
方差(self)
翻译
张量:
# 类型:忽略[覆盖]
return (
self._unbroadcasted_cov_factor.pow(2).总和(-1) + self.
未广播的协方差诊断
).展开(self.
_批次形状 + self.
事件形状)
@lazy_property
定义 scale_tril(self)
翻译
张量:
以下标识符用于提高数值计算的稳定性
用于 Cholesky 分解(参见 http://www.gaussianprocess.org/gpml/,第 3.4.3 节):
# W @ W.T + D = D1/2 @ (I + D-1/2 @ W @ W.T @ D-1/2) @ D1/2
# 矩阵 "I + D-1/2 @ W @ W.T @ D-1/2" 的特征值从下限有界于 1,
# 因此它是有良好条件的,可以安全地进行 Cholesky 分解。
n = self.事件形状[0]
cov_diag_sqrt_unsqueeze = self.未广播的协方差诊断.
平方根().
展平(-1)
Dinvsqrt_W = self.未广播的协方差因子 /
协方差对角线开平方后展开
K = 火炬.
矩阵乘法(Dinvsqrt_W, Dinvsqrt_W.mT).
连续()
K.视图(-1, n * n)[:, :: n + 1] += 1
# 添加单位矩阵到 K
scale_tril = cov_diag_sqrt_unsqueeze * 火炬.
线性代数.
转置分解(K)
return scale_tril.展开(
self._批次形状 + self.
_事件形状 + self.
_事件形状
)
@lazy_property
定义 covariance_matrix(self)
翻译
张量:
协方差矩阵 =
火炬.
矩阵乘法(
self._未广播的协方差因子, self.
_未广播的协方差因子.mT
) + 火炬.
嵌入式诊断(self.
_未广播的协方差对角线)
return 协方差矩阵.
展开(
self._批次形状 + self.
_事件形状 + self.
_事件形状
)
@lazy_property
定义
精确度矩阵(self)
翻译
张量:
我们使用“Woodbury 矩阵恒等式”来利用低秩形式:
# (W @ W.T + D)^(-1) = D^(-1) - D^(-1) @ W @ C^(-1) @ W.T @ D^(-1)
# 其中 :math:`C` 是电容矩阵。
Wt_Dinv = (
self._unbroadcasted_cov_factor.mT
/ self._unbroadcasted_cov_diag.展平(-2)
)
A = 火炬.
线性代数.
解三角形方程(self.
三相电容, Wt_Dinv,
上=
错误)
精度矩阵 = (
火炬.
嵌入式诊断(self.
_未广播协方差对角线.
相互()) - A.mT @ A
)
return 精度矩阵.
展开(
self._批次形状 + self.
_事件形状 + self.
_事件形状
)
[文档] def rsample(self, sample_shape: _size = torch.Size()) -> Tensor:
shape = self._extended_shape(sample_shape)
W_shape = shape[:-1] + self.cov_factor.shape[-1:]
eps_W = _standard_normal(W_shape, dtype=self.loc.dtype, device=self.loc.device)
eps_D = _standard_normal(shape, dtype=self.loc.dtype, device=self.loc.device)
return (
self.loc
+ _batch_mv(self._unbroadcasted_cov_factor, eps_W)
+ self._unbroadcasted_cov_diag.sqrt() * eps_D
)
[文档] def log_prob(self, value):
if self._validate_args:
self._validate_sample(value)
diff = value - self.loc
M = _batch_lowrank_mahalanobis(
self._unbroadcasted_cov_factor
self._unbroadcasted_cov_diag
diff
self._capacitance_tril
)
log_det = _batch_lowrank_logdet(
self._unbroadcasted_cov_factor,
self._unbroadcasted_cov_diag,
self._capacitance_tril,
)
return -0.5 * (self._event_shape[0] * math.log(2 * math.pi) + log_det + M)
[文档] def 熵(self):
log_det = _batch_lowrank_logdet(
self._unbroadcasted_cov_factor,
self._unbroadcasted_cov_diag,
self._capacitance_tril,
)
H = 0.5 * (self._event_shape[0] * (1.0 + math.log(2 * math.pi)) + log_det)
if len(self._batch_shape) == 0:
return H
else:
返回 H.expand(self._batch_shape)