Skip to content

BaseLogger

minnt.loggers.BaseLogger

Bases: Logger

An abstract logger providing base functionality for other loggers.

Source code in minnt/loggers/base_logger.py
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
class BaseLogger(Logger):
    """An abstract logger providing base functionality for other loggers."""

    def __del__(self) -> None:
        """Ensure proper resource cleanup on deletion."""
        self.close()

    def log_figure(self, label: str, figure: Any, epoch: int, tight_layout: bool = True, close: bool = True) -> Self:
        import matplotlib.pyplot as plt
        import matplotlib.backends.backend_agg as plt_backend_agg

        tight_layout and figure.tight_layout()
        canvas = plt_backend_agg.FigureCanvasAgg(figure)
        canvas.draw()
        width, height = figure.canvas.get_width_height()
        image = torch.frombuffer(canvas.buffer_rgba(), dtype=torch.uint8).view(height, width, 4)
        close and plt.close(figure)

        return self.log_image(label, image, epoch)

    def preprocess_audio(self, audio: AnyArray) -> torch.Tensor:
        """Produce a CPU-based [torch.Tensor][] with `dtype=torch.int16` and shape `(L, {1/2})`."""
        audio = torch.as_tensor(audio, device="cpu")
        audio = audio * 32_767 if audio.dtype.is_floating_point else audio
        audio = audio.clamp(-32_768, 32_767).to(torch.int16)
        assert audio.ndim == 1 or (audio.ndim == 2 and audio.shape[1] in (1, 2)), \
            "Audio must have shape (L,) or (L, 1/2)"
        if audio.ndim == 1:
            audio = audio.unsqueeze(-1)
        return audio

    def preprocess_image(self, image: AnyArray) -> torch.Tensor:
        """Produce a CPU-based [torch.Tensor][] with `dtype=torch.uint8` and shape `(H, W, {1/3/4})`."""
        image = torch.as_tensor(image, device="cpu")
        image = (image * 255 if image.dtype.is_floating_point else image).clamp(0, 255).to(torch.uint8)
        assert image.ndim == 2 or (image.ndim == 3 and image.shape[2] in (1, 2, 3, 4)), \
            "Image must have shape (H, W) or (H, W, 1/2/3/4)"
        if image.ndim == 2:
            image = image.unsqueeze(-1)
        if image.shape[2] == 2:
            # Convert to RGBA
            image = torch.stack([image[:, :, 0]] * 3 + [image[:, :, 1]], dim=-1)
        return image

__del__

__del__() -> None

Ensure proper resource cleanup on deletion.

Source code in minnt/loggers/base_logger.py
17
18
19
def __del__(self) -> None:
    """Ensure proper resource cleanup on deletion."""
    self.close()

log_figure

log_figure(
    label: str,
    figure: Any,
    epoch: int,
    tight_layout: bool = True,
    close: bool = True,
) -> Self

Log the given matplotlib Figure with the given label at the given epoch.

Parameters:

  • label (str) –

    The label of the logged image.

  • figure (Any) –

    A matplotlib Figure.

  • epoch (int) –

    The epoch number at which the image is logged.

  • tight_layout (bool, default: True ) –

    Whether to apply tight layout to the figure before logging it.

  • close (bool, default: True ) –

    Whether to close the figure after logging it.

Source code in minnt/loggers/base_logger.py
21
22
23
24
25
26
27
28
29
30
31
32
def log_figure(self, label: str, figure: Any, epoch: int, tight_layout: bool = True, close: bool = True) -> Self:
    import matplotlib.pyplot as plt
    import matplotlib.backends.backend_agg as plt_backend_agg

    tight_layout and figure.tight_layout()
    canvas = plt_backend_agg.FigureCanvasAgg(figure)
    canvas.draw()
    width, height = figure.canvas.get_width_height()
    image = torch.frombuffer(canvas.buffer_rgba(), dtype=torch.uint8).view(height, width, 4)
    close and plt.close(figure)

    return self.log_image(label, image, epoch)

preprocess_audio

preprocess_audio(audio: AnyArray) -> Tensor

Produce a CPU-based torch.Tensor with dtype=torch.int16 and shape (L, {1/2}).

Source code in minnt/loggers/base_logger.py
34
35
36
37
38
39
40
41
42
43
def preprocess_audio(self, audio: AnyArray) -> torch.Tensor:
    """Produce a CPU-based [torch.Tensor][] with `dtype=torch.int16` and shape `(L, {1/2})`."""
    audio = torch.as_tensor(audio, device="cpu")
    audio = audio * 32_767 if audio.dtype.is_floating_point else audio
    audio = audio.clamp(-32_768, 32_767).to(torch.int16)
    assert audio.ndim == 1 or (audio.ndim == 2 and audio.shape[1] in (1, 2)), \
        "Audio must have shape (L,) or (L, 1/2)"
    if audio.ndim == 1:
        audio = audio.unsqueeze(-1)
    return audio

preprocess_image

preprocess_image(image: AnyArray) -> Tensor

Produce a CPU-based torch.Tensor with dtype=torch.uint8 and shape (H, W, {1/3/4}).

Source code in minnt/loggers/base_logger.py
45
46
47
48
49
50
51
52
53
54
55
56
def preprocess_image(self, image: AnyArray) -> torch.Tensor:
    """Produce a CPU-based [torch.Tensor][] with `dtype=torch.uint8` and shape `(H, W, {1/3/4})`."""
    image = torch.as_tensor(image, device="cpu")
    image = (image * 255 if image.dtype.is_floating_point else image).clamp(0, 255).to(torch.uint8)
    assert image.ndim == 2 or (image.ndim == 3 and image.shape[2] in (1, 2, 3, 4)), \
        "Image must have shape (H, W) or (H, W, 1/2/3/4)"
    if image.ndim == 2:
        image = image.unsqueeze(-1)
    if image.shape[2] == 2:
        # Convert to RGBA
        image = torch.stack([image[:, :, 0]] * 3 + [image[:, :, 1]], dim=-1)
    return image