Files
2026-07-13 13:17:40 +08:00

86 lines
2.9 KiB
Python

from ray.rllib.utils.framework import try_import_torch
torch, nn = try_import_torch()
class Stride2D(nn.Module):
"""A striding layer for doing torch Conv2DTranspose operations.
Using this layer before the 0-padding (on a 3D input "image") and before
the actual ConvTranspose2d allows for a padding="same" behavior that matches
100% that of a `tf.keras.layers.Conv2DTranspose` layer.
Examples:
Input image (4x4):
A B C D
E F G H
I J K L
M N O P
Stride with stride=2 -> output image=(7x7)
A 0 B 0 C 0 D
0 0 0 0 0 0 0
E 0 F 0 G 0 H
0 0 0 0 0 0 0
I 0 J 0 K 0 L
0 0 0 0 0 0 0
M 0 N 0 O 0 P
"""
def __init__(self, width, height, stride_w, stride_h):
"""Initializes a Stride2D instance.
Args:
width: The width of the 3D input "image".
height: The height of the 3D input "image".
stride_w: The stride in width direction, with which to stride the incoming
image.
stride_h: The stride in height direction, with which to stride the incoming
image.
"""
super().__init__()
self.width = width
self.height = height
self.stride_w = stride_w
self.stride_h = stride_h
self.register_buffer(
"zeros",
torch.zeros(
size=(
self.width * self.stride_w - (self.stride_w - 1),
self.height * self.stride_h - (self.stride_h - 1),
),
dtype=torch.float32,
),
)
self.out_width, self.out_height = self.zeros.shape[0], self.zeros.shape[1]
# Squeeze in batch and channel dims.
self.zeros = self.zeros.unsqueeze(0).unsqueeze(0)
where_template = torch.zeros(
(self.stride_w, self.stride_h), dtype=torch.float32
)
# Set upper/left corner to 1.0.
where_template[0][0] = 1.0
# then tile across the entire (strided) image size.
where_template = where_template.repeat((self.height, self.width))[
: -(self.stride_w - 1), : -(self.stride_h - 1)
]
# Squeeze in batch and channel dims and convert to bool.
where_template = where_template.unsqueeze(0).unsqueeze(0).bool()
self.register_buffer("where_template", where_template)
def forward(self, x):
# Repeat incoming image stride(w/h) times to match the strided output template.
repeated_x = (
x.repeat_interleave(self.stride_w, dim=-2).repeat_interleave(
self.stride_h, dim=-1
)
)[:, :, : -(self.stride_w - 1), : -(self.stride_h - 1)]
# Where `self.where_template` == 1.0 -> Use image pixel, otherwise use
# zero filler value.
return torch.where(self.where_template, repeated_x, self.zeros)