126 lines
4.1 KiB
Python
126 lines
4.1 KiB
Python
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
import paddle
|
|
from paddle.fluid.layers import sequence_mask
|
|
from paddle.nn import functional as F
|
|
|
|
__all__ = [
|
|
"guided_attention_loss",
|
|
"weighted_mean",
|
|
"masked_l1_loss",
|
|
"masked_softmax_with_cross_entropy",
|
|
]
|
|
|
|
|
|
def attention_guide(dec_lens, enc_lens, N, T, g, dtype=None):
|
|
"""Build that W matrix. shape(B, T_dec, T_enc)
|
|
W[i, n, t] = 1 - exp(-(n/dec_lens[i] - t/enc_lens[i])**2 / (2g**2))
|
|
|
|
See also:
|
|
Tachibana, Hideyuki, Katsuya Uenoyama, and Shunsuke Aihara. 2017. “Efficiently Trainable Text-to-Speech System Based on Deep Convolutional Networks with Guided Attention.” ArXiv:1710.08969 [Cs, Eess], October. http://arxiv.org/abs/1710.08969.
|
|
"""
|
|
dtype = dtype or paddle.get_default_dtype()
|
|
dec_pos = paddle.arange(0, N).astype(dtype) / dec_lens.unsqueeze(
|
|
-1) # n/N # shape(B, T_dec)
|
|
enc_pos = paddle.arange(0, T).astype(dtype) / enc_lens.unsqueeze(
|
|
-1) # t/T # shape(B, T_enc)
|
|
W = 1 - paddle.exp(-(dec_pos.unsqueeze(-1) - enc_pos.unsqueeze(1))**2 /
|
|
(2 * g**2))
|
|
|
|
dec_mask = sequence_mask(dec_lens, maxlen=N)
|
|
enc_mask = sequence_mask(enc_lens, maxlen=T)
|
|
mask = dec_mask.unsqueeze(-1) * enc_mask.unsqueeze(1)
|
|
mask = paddle.cast(mask, W.dtype)
|
|
|
|
W *= mask
|
|
return W
|
|
|
|
|
|
def guided_attention_loss(attention_weight, dec_lens, enc_lens, g):
|
|
"""Guided attention loss, masked to excluded padding parts."""
|
|
_, N, T = attention_weight.shape
|
|
W = attention_guide(dec_lens, enc_lens, N, T, g, attention_weight.dtype)
|
|
|
|
total_tokens = (dec_lens * enc_lens).astype(W.dtype)
|
|
loss = paddle.mean(paddle.sum(W * attention_weight, [1, 2]) / total_tokens)
|
|
return loss
|
|
|
|
|
|
def weighted_mean(input, weight):
|
|
"""Weighted mean. It can also be used as masked mean.
|
|
|
|
Parameters
|
|
-----------
|
|
input : Tensor
|
|
The input tensor.
|
|
weight : Tensor
|
|
The weight tensor with broadcastable shape with the input.
|
|
|
|
Returns
|
|
----------
|
|
Tensor [shape=(1,)]
|
|
Weighted mean tensor with the same dtype as input.
|
|
"""
|
|
weight = paddle.cast(weight, input.dtype)
|
|
broadcast_ratio = input.size / weight.size
|
|
return paddle.sum(input * weight) / (paddle.sum(weight) * broadcast_ratio)
|
|
|
|
|
|
def masked_l1_loss(prediction, target, mask):
|
|
"""Compute maksed L1 loss.
|
|
|
|
Parameters
|
|
----------
|
|
prediction : Tensor
|
|
The prediction.
|
|
target : Tensor
|
|
The target. The shape should be broadcastable to ``prediction``.
|
|
mask : Tensor
|
|
The mask. The shape should be broadcatable to the broadcasted shape of
|
|
``prediction`` and ``target``.
|
|
|
|
Returns
|
|
-------
|
|
Tensor [shape=(1,)]
|
|
The masked L1 loss.
|
|
"""
|
|
abs_error = F.l1_loss(prediction, target, reduction='none')
|
|
loss = weighted_mean(abs_error, mask)
|
|
return loss
|
|
|
|
|
|
def masked_softmax_with_cross_entropy(logits, label, mask, axis=-1):
|
|
"""Compute masked softmax with cross entropy loss.
|
|
|
|
Parameters
|
|
----------
|
|
logits : Tensor
|
|
The logits. The ``axis``-th axis is the class dimension.
|
|
label : Tensor [dtype: int]
|
|
The label. The size of the ``axis``-th axis should be 1.
|
|
mask : Tensor
|
|
The mask. The shape should be broadcastable to ``label``.
|
|
axis : int, optional
|
|
The index of the class dimension in the shape of ``logits``, by default
|
|
-1.
|
|
|
|
Returns
|
|
-------
|
|
Tensor [shape=(1,)]
|
|
The masked softmax with cross entropy loss.
|
|
"""
|
|
ce = F.softmax_with_cross_entropy(logits, label, axis=axis)
|
|
loss = weighted_mean(ce, mask)
|
|
return loss
|