Skip to content

edspdf.layers.cnn_pooler

CnnPooler

Bases: Module

One dimension CNN encoding multi-kernel layer. Input embeddings are convoluted using linear kernels each parametrized with a (window) size of kernel_size[kernel_i] The output of the kernels are concatenated together, max-pooled and finally projected to a size of output_size.

Source code in edspdf/layers/cnn_pooler.py
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
@registry.factory.register("cnn-pooler")
class CnnPooler(Module):
    """
    One dimension CNN encoding multi-kernel layer.
    Input embeddings are convoluted using linear kernels each parametrized with
    a (window) size of `kernel_size[kernel_i]`
    The output of the kernels are concatenated together, max-pooled and finally
    projected to a size of `output_size`.
    """

    def __init__(
        self,
        input_size: Optional[int] = None,
        output_size: Optional[int] = None,
        out_channels: Optional[int] = None,
        kernel_sizes: Sequence[int] = (3, 4, 5),
        activation: ActivationFunction = "relu",
    ):
        """
        Parameters
        ----------
        input_size: int
            Size of the input embeddings
        output_size: Optional[int]
            Size of the output embeddings
            Defaults to the `input_size`
        out_channels: int
            Number of channels
        kernel_sizes: Sequence[int]
            Window size of each kernel
        activation: str
            Activation function to use
        """
        super().__init__()

        self.input_size = input_size
        self.output_size = output_size
        self.out_channels = out_channels
        self.kernel_sizes = kernel_sizes
        self.activation = get_activation_function(activation)

    def initialize(self, gold_data, **kwargs):
        super().initialize(gold_data, **kwargs)

        if self.out_channels is None:
            self.out_channels = self.input_size
        if self.output_size is None:
            self.output_size = self.input_size

        self.convolutions = torch.nn.ModuleList(
            torch.nn.Conv1d(
                in_channels=self.input_size,
                out_channels=self.out_channels,
                kernel_size=kernel_size,
                padding=0,
            )
            for kernel_size in self.kernel_sizes
        )
        self.linear = torch.nn.Linear(
            in_features=self.out_channels * len(self.kernel_sizes),
            out_features=self.output_size,
        )

    def forward(self, embeds: torch.FloatTensor, mask: torch.BoolTensor):
        """
        Encode embeddings with a 1d convolutional network

        Parameters
        ----------
        embeds: torch.FloatTensor
            Input embeddings
            Shape: `n_samples * n_elements * input_size`
        mask: torch.BoolTensor
            Input mask. 0 values are for padding elements.
            Padding elements are masked with a 0 value before the convolution.
            Shape: `n_samples * n_elements * input_size`

        Returns
        -------
        torch.FloatTensor
        Shape: `n_samples * output_size`
        """
        embeds = embeds.masked_fill(~mask.unsqueeze(-1), 0).permute(
            0, 2, 1
        )  # sample word dim -> sample dim word
        embeds = torch.cat(
            [
                self.activation(
                    # pad by the appropriate amount on both sides of each sentence
                    conv(
                        F.pad(
                            embeds,
                            pad=[
                                conv.kernel_size[0] // 2,
                                (conv.kernel_size[0] - 1) // 2,
                            ],
                        )
                    )
                    .permute(0, 2, 1)
                    .masked_fill(~mask.unsqueeze(-1), 0)
                )
                for conv in self.convolutions
            ],
            dim=2,
        )
        pooled = embeds.max(1).values

        return self.linear(pooled)

__init__(input_size=None, output_size=None, out_channels=None, kernel_sizes=(3, 4, 5), activation='relu')

PARAMETER DESCRIPTION
input_size

Size of the input embeddings

TYPE: Optional[int] DEFAULT: None

output_size

Size of the output embeddings Defaults to the input_size

TYPE: Optional[int] DEFAULT: None

out_channels

Number of channels

TYPE: Optional[int] DEFAULT: None

kernel_sizes

Window size of each kernel

TYPE: Sequence[int] DEFAULT: (3, 4, 5)

activation

Activation function to use

TYPE: ActivationFunction DEFAULT: 'relu'

Source code in edspdf/layers/cnn_pooler.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def __init__(
    self,
    input_size: Optional[int] = None,
    output_size: Optional[int] = None,
    out_channels: Optional[int] = None,
    kernel_sizes: Sequence[int] = (3, 4, 5),
    activation: ActivationFunction = "relu",
):
    """
    Parameters
    ----------
    input_size: int
        Size of the input embeddings
    output_size: Optional[int]
        Size of the output embeddings
        Defaults to the `input_size`
    out_channels: int
        Number of channels
    kernel_sizes: Sequence[int]
        Window size of each kernel
    activation: str
        Activation function to use
    """
    super().__init__()

    self.input_size = input_size
    self.output_size = output_size
    self.out_channels = out_channels
    self.kernel_sizes = kernel_sizes
    self.activation = get_activation_function(activation)

forward(embeds, mask)

Encode embeddings with a 1d convolutional network

PARAMETER DESCRIPTION
embeds

Input embeddings Shape: n_samples * n_elements * input_size

TYPE: torch.FloatTensor

mask

Input mask. 0 values are for padding elements. Padding elements are masked with a 0 value before the convolution. Shape: n_samples * n_elements * input_size

TYPE: torch.BoolTensor

RETURNS DESCRIPTION
torch.FloatTensor
Shape
Source code in edspdf/layers/cnn_pooler.py
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def forward(self, embeds: torch.FloatTensor, mask: torch.BoolTensor):
    """
    Encode embeddings with a 1d convolutional network

    Parameters
    ----------
    embeds: torch.FloatTensor
        Input embeddings
        Shape: `n_samples * n_elements * input_size`
    mask: torch.BoolTensor
        Input mask. 0 values are for padding elements.
        Padding elements are masked with a 0 value before the convolution.
        Shape: `n_samples * n_elements * input_size`

    Returns
    -------
    torch.FloatTensor
    Shape: `n_samples * output_size`
    """
    embeds = embeds.masked_fill(~mask.unsqueeze(-1), 0).permute(
        0, 2, 1
    )  # sample word dim -> sample dim word
    embeds = torch.cat(
        [
            self.activation(
                # pad by the appropriate amount on both sides of each sentence
                conv(
                    F.pad(
                        embeds,
                        pad=[
                            conv.kernel_size[0] // 2,
                            (conv.kernel_size[0] - 1) // 2,
                        ],
                    )
                )
                .permute(0, 2, 1)
                .masked_fill(~mask.unsqueeze(-1), 0)
            )
            for conv in self.convolutions
        ],
        dim=2,
    )
    pooled = embeds.max(1).values

    return self.linear(pooled)