def calculate_receptive_field_size(layers): """ Parameters ---------- layers : list of dict Each dict must contain ─ 'kernel_size' : (k_h, k_w) ─ 'stride' : (s_h, s_w) ─ 'dilation' : (d_h, d_w) # optional; defaults to (1, 1) Returns ------- (rf_h, rf_w) : tuple of ints Receptive-field size in pixels for height and width. """ rf_h = rf_w = 1 # start with a 1×1 pixel jump_h = jump_w = 1 # effective stride so far for layer in layers: k_h, k_w = layer["kernel_size"] s_h, s_w = layer["stride"] d_h, d_w = layer.get("dilation", (1, 1)) # default = 1 # Dumoulin & Visin recurrence, now with dilation rf_h += (k_h - 1) * d_h * jump_h rf_w += (k_w - 1) * d_w * jump_w jump_h *= s_h jump_w *= s_w return rf_h, rf_w def calculate_angular_receptive_field( rf_height: int, rf_width: int, vertical_res: int, horizontal_res: int, vertical_fov: float, horizontal_fov: float, ) -> tuple[float, float]: """Calculate the angular size of a receptive field in degrees. Args: rf_height: Receptive field height in pixels rf_width: Receptive field width in pixels vertical_res: Vertical resolution of input in pixels horizontal_res: Horizontal resolution of input in pixels vertical_fov: Vertical field of view in degrees horizontal_fov: Horizontal field of view in degrees Returns: tuple[float, float]: Angular size (height, width) in degrees """ # Calculate degrees per pixel for each axis vertical_deg_per_pixel = vertical_fov / vertical_res horizontal_deg_per_pixel = horizontal_fov / horizontal_res # Calculate angular size of receptive field rf_vertical_deg = rf_height * vertical_deg_per_pixel rf_horizontal_deg = rf_width * horizontal_deg_per_pixel return rf_vertical_deg, rf_horizontal_deg horizontal_resolution = 2048 horizontal_fov = 360.0 vertical_resolution = 32 vertical_fov = 31.76 lenet_network_config = [ {"name": "Conv1", "kernel_size": (5, 5), "stride": (1, 1), "dilation": (1, 1)}, {"name": "MaxPool1", "kernel_size": (2, 2), "stride": (2, 2), "dilation": (1, 1)}, {"name": "Conv2", "kernel_size": (5, 5), "stride": (1, 1), "dilation": (1, 1)}, {"name": "MaxPool2", "kernel_size": (2, 2), "stride": (2, 2), "dilation": (1, 1)}, ] # Calculate and print results for LeNet rf_h, rf_w = calculate_receptive_field_size(lenet_network_config) rf_vert_deg, rf_horiz_deg = calculate_angular_receptive_field( rf_h, rf_w, vertical_resolution, horizontal_resolution, vertical_fov, horizontal_fov ) print(f"SubTer LeNet RF size: {rf_h} × {rf_w} pixels") print(f"SubTer LeNet RF angular size: {rf_vert_deg:.2f}° × {rf_horiz_deg:.2f}°") asym_network_config = [ {"name": "Conv1", "kernel_size": (3, 17), "stride": (1, 1), "dilation": (1, 1)}, {"name": "MaxPool1", "kernel_size": (2, 2), "stride": (2, 2), "dilation": (1, 1)}, {"name": "Conv2", "kernel_size": (3, 17), "stride": (1, 1), "dilation": (1, 1)}, {"name": "MaxPool2", "kernel_size": (2, 2), "stride": (2, 2), "dilation": (1, 1)}, ] # Calculate and print results for Asymmetric network rf_h, rf_w = calculate_receptive_field_size(asym_network_config) rf_vert_deg, rf_horiz_deg = calculate_angular_receptive_field( rf_h, rf_w, vertical_resolution, horizontal_resolution, vertical_fov, horizontal_fov ) print(f"SubTer LeNet (Asymmetric kernels) RF size: {rf_h} × {rf_w} pixels") print( f"SubTer LeNet (Asymmetric kernels) RF angular size: {rf_vert_deg:.2f}° × {rf_horiz_deg:.2f}°" )