torch.distributions.continuous_bernoulli 的源代码
# mypy: 允许未类型化定义
导入
数学
导入
火炬
来自
火炬
导入
张量
来自 torch.distributions
导入
约束
来自 torch.distributions.exp_family
导入
指数族
来自 torch.distributions.utils
导入 (
广播全部,
clamp_probs,
懒属性,
logits 转概率,
概率转对数概率,
)
来自 torch.nn.functional
导入 binary_cross_entropy_with_logits
from torch.types 导入
数,
_大小
全部 = [
"连续伯努利分布"]
[文档]
类
连续伯努利(
指数族):
r"""
创建一个由 :attr:`probs` 参数化的连续伯努利分布
或 :attr:`logits`(但不能同时使用)。
分布支持在 [0, 1] 范围内,并由 'probs' 参数化
(0,1) 或 'logits'(实值)。注意,与伯努利分布不同,'probs'
不对应于概率,'logits' 不对应于
对数优势,但使用相同的名称,因为与
伯努利。参见[1]了解更多详情。
示例::
>>> # xdoctest: +IGNORE_WANT("非确定性")
>>> m = ContinuousBernoulli(torch.tensor([0.3]))
>>> m.sample()
tensor([ 0.2538])
参数:
probs (Number, Tensor): (0,1) valued parameters
logits(数字,张量):与'probs'匹配的实值参数
[1] 连续伯努利分布:纠正变分自编码器中的普遍错误
autoencoders,Loaiza-Ganem G 和 Cunningham JP,NeurIPS 2019。
https://arxiv.org/abs/1907.06845
"沉浸式翻译"
约束参数 = {
"概率":
约束.
单位区间, "logits":
约束.
真实}
支持 =
约束.
单位区间
_平均载波测量 = 0
has_rsample = 真实
def __init__(
self, 概率=
无, logits=
无, lims=(0.499, 0.501),
验证参数=
无
) -> 无:
如果 (
概率
是
无) == (logits
是
无):
抛出
值错误(
"必须指定 `probs` 或 `logits` 中的一个,但不能同时指定。"
)
如果
概率
是
不是
无:
是否为标量 = isinstance(
概率,
数)
(自身.
概率,) =
广播全部(
概率)
在此处验证 'probs',因为之后需要对其进行钳位以确保数值稳定性
接近 0 和 1,之后;否则,钳位的 'probs' 总是会通过
如果
验证参数
是
不是
无:
如果
不是
自身.
参数约束[
"概率"].
检查(
自身.
概率).
所有():
抛出
值错误(
"参数 probs 存在无效值")
自身.
概率 = clamp_probs(
自身.
概率)
否则:
是否为标量 = isinstance(logits,
数)
(自身.logits,) =
广播全部(logits)
自身.
_参数 =
自身.
概率
如果
概率
是
不是
无
否则
自身.logits
如果 is_scalar:
批量形状 = torch.
尺寸()
否则:
批量形状 =
自身._param.
大小()
自身._lims = lims
超级().__init__(
批量形状,
验证参数=
验证参数)
[文档] def expand(self, batch_shape, _instance=None):
new = self._get_checked_instance(ContinuousBernoulli, _instance)
new._lims = self._lims
batch_shape = torch.Size(batch_shape)
if "probs" in self.__dict__:
new.probs = self.probs.expand(batch_shape)
new._param = new.probs
如果 "logits" 在 self.__dict__ 中:
new.logits = self.logits.expand(batch_shape)
new._param = new.logits
super(ContinuousBernoulli, new).__init__(batch_shape, validate_args=False)
new._validate_args = self._validate_args
return new
定义
新(
自身, *
参数, **kwargs):
返回
自身._param.
新(*
参数, **kwargs)
定义
_不稳定区域外(
自身):
返回 torch.
最大值(
torch.小于等于(
自身.
概率,
自身.
_实验室信息管理系统[0
)] torch.gt(
自身.
概率,
自身.
_实验室信息管理系统[1])
)
定义
_切割概率(
自身):
返回 torch.
哪里(
我.
_不稳定区域外(),
我.
概率,
我._lims[0] * torch.
喜欢的(
我.
概率),
)
定义 _cont_bern_log_norm(
我):
计算以'probs'参数为函数的对数归一化常数
切割概率 =
我.
_切割概率()
切割概率低于一半 = torch.
哪里(
torch.小于等于(
切割概率, 0.5),
切割概率, torch.
等于零的(
切割概率)
)
切割概率超过一半 = torch.
哪里(
torch.大于等于(
切割概率, 0.5),
切割概率, torch.
喜欢的(
cut 概率)
)
对数归一化 = torch.
日志(
torch.绝对值(torch.log1p(-
cut 概率) -
火炬.
日志(
切割概率))
) - torch.哪里(
torch.小于等于(
切割概率, 0.5),
torch.log1p(-2.0 * 切割低于一半的概率),
torch.日志(2.0 *
切割高于一半的概率 - 1.0),
)
x = torch.pow(self.概率 - 0.5, 2)
泰勒 =
数学.
日志(2.0) + (4.0 / 3.0 + 104.0 / 45.0 * x) * x
返回 torch.
哪里(self.
_不稳定区域外(),
日志归一化,
泰勒)
@property
def 均值(self) ->
张量:
切割概率 = self.
_切割概率_()
肌 =
切割概率 / (2.0 *
切割概率 - 1.0) + 1.0 / (
torch.log1p(-切割概率) - torch.
日志(
切割概率)
)
x = self.概率 - 0.5
泰勒 = 0.5 + (1.0 / 3.0 + 16.0 / 45.0 * torch.pow(x, 2)) * x
返回 torch.
哪里(self.
_不稳定区域外(),
肌, taylor)
@property
def 标准差(self) ->
张量:
返回 torch.
平方根(
我.
方差)
@property
def 方差(
我) ->
张量:
切割概率 =
自身.
_切割概率()
变量 =
切割概率 * (
切割概率 - 1.0) / torch.pow(
1.0 - 2.0 * 切割概率, 2
) + 1.0 / torch.pow(torch.log1p(-cut_probs) - torch.日志(cut_probs), 2)
x = torch.pow(自身.
概率 - 0.5, 2)
taylor = 1.0 / 12.0 - (1.0 / 15.0 - 128.0 / 945.0 * x) * x
返回 torch.
哪里(
自身._outside_unstable_region(),
变量, taylor)
@lazy_property
定义 logits(
自身) ->
张量:
返回
概率转对数概率(
自身.
概率,
是否二进制=
是)
@lazy_property
定义
概率(
自身) ->
张量:
返回 clamp_probs(
logits 转概率(
自身.logits,
是否二进制=
是))
@property
定义
参数形状(
自身) -> torch.
尺寸:
返回
自身._param.
大小()
[文档] def sample(self, sample_shape=torch.Size()):
shape = self._extended_shape(sample_shape)
u = torch.rand(shape, dtype=self.probs.dtype, device=self.probs.device)
with torch.no_grad():
return self.icdf(u)
[文档] def rsample(self, sample_shape: _size = torch.Size()) -> Tensor:
shape = self._extended_shape(sample_shape)
u = torch.rand(shape, dtype=self.probs.dtype, device=self.probs.device)
return self.icdf(u)
[文档] def log_prob(self, value):
if self._validate_args:
self._validate_sample(value)
logits, value = broadcast_all(self.logits, value)
return (
-二进制交叉熵对数函数(logits, value, reduction="none")
+ 调用 self._cont_bern_log_norm()
)
[文档] def cdf(self, value):
if self._validate_args:
self._validate_sample(value)
cut_probs = self._cut_probs()
cdfs = (
torch.pow(cut_probs, value) * torch.pow(1.0 - cut_probs, 1.0 - value)
+ cut_probs
- 1.0
) / (2.0 * cut_probs - 1.0)
unbounded_cdfs = torch.where(self._outside_unstable_region(), cdfs, value)
return torch.where(
torch.le(value, 0.0),
torch.zeros_like(value),
torch.where(torch.ge(value, 1.0), torch.ones_like(value), unbounded_cdfs),
)
[文档] def icdf(self, value):
cut_probs = self._cut_probs()
return torch.where(
self._outside_unstable_region()
(
torch.log1p(-cut_probs + value * (2.0 * cut_probs - 1.0))
- torch.log1p(-cut_probs)
)
/ (torch.log(cut_probs) - torch.log1p(-cut_probs)),
value,
)
[文档] def 熵(self):
log_probs0 = torch.log1p(-self.probs)
log_probs1 = torch.log(self.probs)
return (
self.mean * (log_probs0 - log_probs1)
- self._cont_bern_log_norm()
- log_probs0
)
@property
定义
自然参数(
自身) ->
元组[
张量
]
返回 (
自身.logits,)
定义
对数归一化器(
自身, x):
计算自然参数作为对数归一化常数的函数
out_unst_reg = torch.最大值(
torch.小于等于(x,
自身._lims[0] - 0.5), torch.gt(x,
自身._lims[1] - 0.5)
)
切割自然参数 = torch.
哪里(
输出未解注册, x, (
自身._lims[0] - 0.5) * torch.
喜欢的(x)
)
日志归一化 = torch.
日志(
torch.绝对值(torch.
特别.expm1(
切割自然参数))
) - torch.日志(torch.
绝对值(
切割自然参数))
泰勒展开 = 0.5 * x + torch.pow(x, 2) / 24.0 - torch.pow(x, 4) / 2880.0
返回 torch.
哪里(
外部未注册,
日志归一化,
泰勒)