def __init__(self, device, dataset, input_channel, input_size, width, linear_size): super(cnn_2layer, self).__init__() mean, sigma = get_mean_sigma(device, dataset, IBP=True) self.normalizer = Normalization(mean, sigma) self.layers = [ Normalization(mean, sigma), Conv2d(input_channel, 4 * width, 4, stride=2, padding=1, dim=input_size), ReLU((4 * width, input_size // 2, input_size // 2)), Conv2d(4 * width, 8 * width, 4, stride=2, padding=1, dim=input_size // 2), ReLU((8 * width, input_size // 4, input_size // 4)), Flatten(), Linear(8 * width * (input_size // 4) * (input_size // 4), linear_size), ReLU(linear_size), Linear(linear_size, 10), ]
def __init__(self, C): super(SEModule, self).__init__() mid = max(C // self.reduction, 8) conv1 = Conv2d(C, mid, 1, 1, 0) conv2 = Conv2d(mid, C, 1, 1, 0) self.op = nn.Sequential(nn.AdaptiveAvgPool2d(1), conv1, nn.ReLU(inplace=True), conv2, nn.Sigmoid())
def __init__(self, inplanes, planes, stride=1, downsample=None): super(Bottleneck, self).__init__() self.conv1 = Conv2d(inplanes, planes, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(planes) self.conv3 = Conv2d(planes, planes * 4, kernel_size=1, bias=False) self.bn3 = nn.BatchNorm2d(planes * 4) self.relu = nn.ReLU(inplace=True) self.downsample = downsample self.stride = stride
def __init__(self, C_in, C_out, stride): assert stride in [1, 2] ops = [ Conv2d(C_in, C_in, 3, stride, 1, bias=False), BatchNorm2d(C_in), nn.ReLU(inplace=True), Conv2d(C_in, C_out, 3, 1, 1, bias=False), BatchNorm2d(C_out), ] super(CascadeConv3x3, self).__init__(*ops) self.res_connect = (stride == 1) and (C_in == C_out)
def __init__(self, in_channels, bottleneck_channels, out_channels, num_groups=1, stride_in_1x1=True, stride=1, padding=1, dilation=1): super(DeformConvBottleneckWithGroupNorm, self).__init__() self.downsample = None if in_channels != out_channels: self.downsample = nn.Sequential( Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False), GroupNorm(Global_Group_Num, out_channels), ) # The original MSRA ResNet models have stride in the first 1x1 conv # The subsequent fb.torch.resnet and Caffe2 ResNe[X]t implementations have # stride in the 3x3 conv stride_1x1, stride_3x3 = (stride, 1) if stride_in_1x1 else (1, stride) self.conv1 = Conv2d( in_channels, bottleneck_channels, kernel_size=1, stride=stride_1x1, bias=False, ) self.gn1 = GroupNorm(Global_Group_Num, bottleneck_channels) # TODO: specify init for the above self.conv2 = DeformConv2d(bottleneck_channels, bottleneck_channels, kernel_size=3, stride=stride_3x3, padding=padding, dilation=dilation, use_bias=False) self.gn2 = GroupNorm(Global_Group_Num, bottleneck_channels) self.conv3 = Conv2d(bottleneck_channels, out_channels, kernel_size=1, bias=False) self.gn3 = GroupNorm(Global_Group_Num, out_channels) self.reset_parameters()
def __init__(self, in_channels, bottleneck_channels, out_channels, num_groups=1, stride_in_1x1=True, stride=1, padding=1, dilation=1): super(BottleneckWithFixedBatchNorm, self).__init__() self.downsample = None if in_channels != out_channels: self.downsample = nn.Sequential( Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False), FrozenBatchNorm2d(out_channels), ) # The original MSRA ResNet models have stride in the first 1x1 conv # The subsequent fb.torch.resnet and Caffe2 ResNe[X]t implementations have # stride in the 3x3 conv stride_1x1, stride_3x3 = (stride, 1) if stride_in_1x1 else (1, stride) self.conv1 = Conv2d(in_channels, bottleneck_channels, kernel_size=1, stride=stride_1x1, bias=False) self.bn1 = FrozenBatchNorm2d(bottleneck_channels) # TODO: specify init for the above self.conv2 = Conv2d(bottleneck_channels, bottleneck_channels, kernel_size=3, stride=stride_3x3, padding=padding, dilation=dilation, bias=False, groups=num_groups) self.bn2 = FrozenBatchNorm2d(bottleneck_channels) self.conv3 = Conv2d(bottleneck_channels, out_channels, kernel_size=1, bias=False) self.bn3 = FrozenBatchNorm2d(out_channels)
def __init__(self, inplanes, planes, stride=1, downsample=None, act_dim_a=None, act_dim_b=None, weight_noise=False, act_noise_a=False, act_noise_b=False, rank=5): super(PreActBottleneck, self).__init__() self.bn1 = nn.BatchNorm2d(inplanes) self.relu = nn.ReLU(inplace=True) self.conv1 = Conv2d(inplanes, planes, kernel_size=1, bias=False, act_dim_a=act_dim_a, act_dim_b=act_dim_a, weight_noise=weight_noise, act_noise_a=act_noise_a, act_noise_b=act_noise_b, rank=rank) self.bn2 = nn.BatchNorm2d(planes) self.conv2 = Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False, act_dim_a=act_dim_a, act_dim_b=act_dim_b, weight_noise=weight_noise, act_noise_a=act_noise_a, act_noise_b=act_noise_b, rank=rank) self.bn3 = nn.BatchNorm2d(planes) self.conv3 = Conv2d(planes, planes * 4, kernel_size=1, bias=False, act_dim_a=act_dim_b, act_dim_b=act_dim_b, weight_noise=weight_noise, act_noise_a=act_noise_a, act_noise_b=act_noise_b, rank=rank) self.downsample = downsample self.stride = stride
def __init__(self, block, layers, num_classes=10): super(PreAct_ResNet_Cifar, self).__init__() self.inplanes = 16 self.conv1 = Conv2d(3, 16, kernel_size=3, stride=1, padding=1, bias=False) self.layer1 = self._make_layer(block, 16, layers[0]) self.layer2 = self._make_layer(block, 32, layers[1], stride=2) self.layer3 = self._make_layer(block, 64, layers[2], stride=2) self.bn = nn.BatchNorm2d(64 * block.expansion) self.relu = nn.ReLU(inplace=True) self.avgpool = nn.AvgPool2d(8, stride=1) self.fc = Linear(64 * block.expansion, num_classes) self.num_classes = num_classes self.noise_sd = 0.0 self.m_train = 1 self.m_test = 1 for m in self.modules(): if isinstance(m, Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2. / n)) elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_()
def _make_layer(self, block, planes, blocks, stride=1): downsample = None if stride != 1 or self.inplanes != planes * block.expansion: downsample = nn.Sequential( Conv2d(self.inplanes, planes * block.expansion, kernel_size=1, stride=stride, bias=False, weight_noise=self.weight_noise, act_noise_a=self.act_noise_a, act_noise_b=self.act_noise_b, rank=self.rank)) layers = [] layers.append( block(self.inplanes, planes, stride, downsample, weight_noise=self.weight_noise, act_noise_a=self.act_noise_a, act_noise_b=self.act_noise_b, rank=self.rank)) self.inplanes = planes * block.expansion for _ in range(1, blocks): layers.append( block(self.inplanes, planes, weight_noise=self.weight_noise, act_noise_a=self.act_noise_a, act_noise_b=self.act_noise_b)) return nn.Sequential(*layers)
def __init__(self, block, layers, width=1, num_classes=10, input_size=32, weight_noise=False, act_noise_a=False, act_noise_b=False, rank=5, noise_sd=0.0, m_test=1, m_train=1, learn_noise=False): super(ResNet_Cifar, self).__init__() self.weight_noise = weight_noise self.act_noise_a = act_noise_a self.act_noise_b = act_noise_b self.rank = rank inplanes = int(16 * width) self.inplanes = inplanes self.conv1 = Conv2d(3, inplanes, kernel_size=3, stride=1, padding=1, bias=False, act_dim_a=input_size, act_dim_b=input_size) self.bn1 = nn.BatchNorm2d(16) self.relu = nn.ReLU(inplace=True) self.layer1 = self._make_layer(block, inplanes, layers[0], input_size=input_size) self.layer2 = self._make_layer(block, 2 * inplanes, layers[1], stride=2, input_size=input_size) self.layer3 = self._make_layer(block, 4 * inplanes, layers[2], stride=2, input_size=input_size // 2) self.avgpool = nn.AvgPool2d(8, stride=1) self.fc = Linear(4 * inplanes * block.expansion, num_classes) self.num_classes = num_classes self.learn_noise = learn_noise self.noise_sd = torch.tensor(noise_sd, requires_grad=learn_noise) self.m_test = m_test self.m_train = m_train for m in self.modules(): if isinstance(m, Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels nn.init.kaiming_normal_(m.weight.data) elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_()
def conv3x3(in_planes, out_planes, stride=1): return Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False)
def __init__(self, cfg, heads): super(DeformableCombinedROIHeads, self).__init__(heads) self.cfg = cfg.clone() if cfg.MODEL.MASK_ON and cfg.MODEL.ROI_MASK_HEAD.SHARE_BOX_FEATURE_EXTRACTOR: self.mask.feature_extractor = self.box.feature_extractor feature_channels = cfg.MODEL.BACKBONE.C5_CHANNELS channels_before_Pooling = cfg.MODEL.ROI_BOX_HEAD.CHANNELS_BEFORE_POOLING self.conv = Conv2d(feature_channels, channels_before_Pooling, 1)
def conv3x3(in_planes, out_planes, stride=1): " 3x3 convolution with padding " return Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False)
def __init__(self, cfg): super(DeformMaskRCNNC5Predictor, self).__init__() num_classes = cfg.MODEL.ROI_BOX_HEAD.NUM_CLASSES dim_reduced = cfg.MODEL.ROI_MASK_HEAD.CONV_LAYERS[-1] channels_before_Pooling = cfg.MODEL.ROI_BOX_HEAD.CHANNELS_BEFORE_POOLING self.conv = Conv2d(channels_before_Pooling, dim_reduced, 3, 1, 1) self.conv5_mask = ConvTranspose2d(dim_reduced, dim_reduced, 2, 2, 0) self.mask_fcn_logits = Conv2d(dim_reduced, num_classes, 1, 1, 0) for name, param in self.named_parameters(): if "bias" in name: nn.init.constant_(param, 0) elif "weight" in name: # Caffe2 implementation uses MSRAFill, which in fact # corresponds to kaiming_normal_ in PyTorch nn.init.kaiming_normal_(param, mode="fan_out", nonlinearity="relu")
def __init__(self, device, dataset, n_class=10, input_size=32, input_channel=3, width1=1, width2=1, width3=1, linear_size=100): super(ConvMedBig, self).__init__() mean, sigma = get_mean_sigma(device, dataset) self.normalizer = Normalization(mean, sigma) layers = [ Normalization(mean, sigma), Conv2d(input_channel, 16 * width1, 3, stride=1, padding=1, dim=input_size), ReLU((16 * width1, input_size, input_size)), Conv2d(16 * width1, 16 * width2, 4, stride=2, padding=1, dim=input_size // 2), ReLU((16 * width2, input_size // 2, input_size // 2)), Conv2d(16 * width2, 32 * width3, 4, stride=2, padding=1, dim=input_size // 2), ReLU((32 * width3, input_size // 4, input_size // 4)), Flatten(), Linear(32 * width3 * (input_size // 4) * (input_size // 4), linear_size), ReLU(linear_size), Linear(linear_size, n_class), ] self.blocks = Sequential(*layers)
def __init__(self, in_channels: int, out_channels: int, dropout: bool = True): super().__init__() self.features = torch.nn.Sequential( Conv2d(in_channels, 32, 3, padding=1), torch.nn.ReLU(), torch.nn.MaxPool2d(2), Conv2d(32, 64, 3, padding=1), torch.nn.ReLU(), torch.nn.MaxPool2d(2), Conv2d(64, 128, 3, padding=1), torch.nn.Dropout(0.25 if dropout else 0.0), torch.nn.ReLU(), torch.nn.MaxPool2d(2), Conv2d(128, 256, 3, padding=1), torch.nn.ReLU(), torch.nn.Dropout(0.5 if dropout else 0.0)) # Certain neurons play a crucial role self.out_layer = Linear(256, out_channels)
def __init__(self, in_ch, out_ch, stride=1, r_lim=7, K=4): """ Implementation of the Extremely Efficient Spatial Pyramid module introduced in "ESPNetv2: A Light-weight, Power Efficient, and General Purpose Convolutional Neural Network" <https://arxiv.org/pdf/1811.11431.pdf> Parameters ---------- in_ch (int): number of channels for input out_ch (int): number of channels for output stride (int): stride of the convs r_lim (int): A maximum value of receptive field allowed for EESP block K (int): number of parallel branches """ super(EESP, self).__init__() hidden_ch = int(out_ch // K) hidden_ch1 = out_ch - hidden_ch * (K - 1) assert hidden_ch1 == hidden_ch, \ "hidden size of n={} must equal to hidden size of n1={}".format(hidden_ch, hidden_ch1) self.g_conv1 = Conv2d(in_ch, hidden_ch, 1, stride=1, groups=K, activation=M.PReLU(hidden_ch)) self.spp_convs = [] for i in range(K): ksize = int(3 + i * 2) dilation = int((ksize - 1) / 2) if ksize <= r_lim else 1 self.spp_convs.append( M.Conv2d(hidden_ch, hidden_ch, 3, stride=stride, padding=dilation, dilation=dilation, groups=hidden_ch, bias=False)) self.conv_concat = Conv2d(out_ch, out_ch, groups=K, activation=None) self.bn_pr = M.Sequential(M.BatchNorm2d(out_ch), M.PReLU(out_ch)) self.module_act = M.PReLU(out_ch) self.K = K self.stride = stride
def __init__(self, cfg): super(StemWithFixedBatchNorm, self).__init__() out_channels = cfg.MODEL.RESNETS.STEM_OUT_CHANNELS self.conv1 = Conv2d(3, out_channels, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = FrozenBatchNorm2d(out_channels)
def __init__(self, in_channels: int, out_channels: int): super().__init__() self.inplanes = 16 self.features = torch.nn.Sequential( Conv2d(in_channels, 16, kernel_size=3, padding=1, bias=False), BatchNorm2d(16), torch.nn.ReLU(inplace=True), self._make_layer(BasicBlock, 16, 18), self._make_layer(BasicBlock, 32, 18, stride=2), self._make_layer(BasicBlock, 64, 18, stride=2)) self.out_layer = Linear(64 * BasicBlock.expansion, out_channels) self.reset_parameters()
def get_block(self, in_planes, out_planes, n_blocks, stride, dim): strides = [stride] + [1]*(n_blocks-1) layers = [] if in_planes != out_planes: if self.res_block == FixupBasicBlock: downsample = Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False) # downsample = AvgPool2d(1, stride=stride) elif self.res_block == WideBlock: downsample = Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=True) else: downsample = [Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)] # downsample = [AvgPool2d(1, stride=stride)] downsample += [BatchNorm2d(out_planes)] downsample = Sequential(*downsample) for stride in strides: layers += [self.res_block(dim, in_planes, out_planes, stride, downsample)] downsample = None in_planes = out_planes dim = dim // stride return dim, Sequential(*layers)
def _make_layer(self, block, planes, blocks, stride=1): downsample = None if stride != 1 or self.inplanes != planes * block.expansion: downsample = nn.Sequential( Conv2d(self.inplanes, planes * block.expansion, kernel_size=1, stride=stride, bias=False) ) layers = [] layers.append(block(self.inplanes, planes, stride, downsample)) self.inplanes = planes * block.expansion for _ in range(1, blocks): layers.append(block(self.inplanes, planes)) return nn.Sequential(*layers)
def __init__(self, in_ch, out_ch, stride=2, r_lim=7, K=4, refin=True, refin_ch=3): """ Implementation of the Extremely Efficient Spatial Pyramid module introduced in "ESPNetv2: A Light-weight, Power Efficient, and General Purpose Convolutional Neural Network" <https://arxiv.org/pdf/1811.11431.pdf> Parameters ---------- in_ch (int): number of channels for input out_ch (int): number of channels for output stride (int): stride of the convs r_lim (int): A maximum value of receptive field allowed for EESP block K (int): number of parallel branches refin (bool): whether use the inference from input image """ super(SESSP, self).__init__() eesp_out = out_ch - in_ch self.eesp = EESP(in_ch, eesp_out, stride=stride, r_lim=r_lim, K=K) self.avg_pool = M.AvgPool2d(3, stride=stride, padding=1) self.refin = refin self.stride = stride self.activation = M.PReLU(out_ch) if refin: self.refin_conv = M.Sequential( Conv2d(refin_ch, refin_ch, ksize=3, stride=1, padding=1, activation=M.PReLU(refin_ch)), Conv2d(refin_ch, out_ch, activation=None))
def __init__(self, input_depth, output_depth, kernel, stride, pad, no_bias, use_relu, bn_type, group=1, *args, **kwargs): super(ConvBNRelu, self).__init__() assert use_relu in ["relu", None] if isinstance(bn_type, (list, tuple)): assert len(bn_type) == 2 assert bn_type[0] == "gn" gn_group = bn_type[1] bn_type = bn_type[0] assert bn_type in ["bn", "af", "gn", None] assert stride in [1, 2, 4] op = Conv2d(input_depth, output_depth, kernel_size=kernel, stride=stride, padding=pad, bias=not no_bias, groups=group, *args, **kwargs) nn.init.kaiming_normal_(op.weight, mode="fan_out", nonlinearity="relu") if op.bias is not None: nn.init.constant_(op.bias, 0.0) self.add_module("conv", op) if bn_type == "bn": bn_op = BatchNorm2d(output_depth) elif bn_type == "gn": bn_op = nn.GroupNorm(num_groups=gn_group, num_channels=output_depth) elif bn_type == "af": bn_op = FrozenBatchNorm2d(output_depth) if bn_type is not None: self.add_module("bn", bn_op) if use_relu == "relu": self.add_module("relu", nn.ReLU(inplace=True))
def __init__(self, device, dataset, input_channel, input_size, linear_size): super(cnn_IBP_large, self).__init__() mean, sigma = get_mean_sigma(device, dataset, IBP=True) self.normalizer = Normalization(mean, sigma) self.layers = [ Normalization(mean, sigma), Conv2d(input_channel, 64, 3, stride=1, padding=1, dim=input_size), ReLU((64, input_size, input_size)), Conv2d(64, 64, 3, stride=1, padding=1, dim=input_size), ReLU((64, input_size, input_size)), Conv2d(64, 128, 3, stride=2, padding=1, dim=input_size // 2), ReLU((128, input_size // 2, input_size // 2)), Conv2d(128, 128, 3, stride=1, padding=1, dim=input_size // 2), ReLU((128, input_size // 2, input_size // 2)), Conv2d(128, 128, 3, stride=1, padding=1, dim=input_size // 2), ReLU((128, input_size // 2, input_size // 2)), Flatten(), Linear(128 * (input_size // 2) * (input_size // 2), linear_size), ReLU(linear_size), Linear(linear_size, 10), ]
def test_conv2d(slow): # 3 x 1 x 2 x 2 data = torch.tensor([ [[1.0, 2.0], [3.0, 4.0]], [[5.0, 6.0], [7.0, 8.0]], [[-1.0, -2.0], [-3.0, -4.0]], ]) data = data.unsqueeze(dim=1) # perform 1x1 convolutions on data layer = Conv2d(1, 3, 1) layer.weights = torch.tensor([[[[10.0, 20.0, 30.0]]]]) layer.bias = torch.tensor([1.0, 2.0, 3.0]) out = layer(data, slow=slow) torch_out = conv2d(data, layer.weights.view(3, 1, 1, 1), layer.bias) torch_out = torch.relu(torch_out) assert torch.allclose(out, torch_out)
def _make_layer(self, block, planes, blocks, stride=1): downsample = None if stride != 1 or self.inplanes != planes * block.expansion: downsample = torch.nn.Sequential( Conv2d(self.inplanes, planes * block.expansion, kernel_size=1, stride=stride, bias=False), BatchNorm2d(planes * block.expansion), ) layers = [block(self.inplanes, planes, stride, downsample)] self.inplanes = planes * block.expansion for i in range(1, blocks): layers.append(block(self.inplanes, planes)) return torch.nn.Sequential(*layers)
def __init__(self, block, layers, width=1, num_classes=10): super(ResNet_Cifar, self).__init__() inplanes = int(16 * width) self.inplanes = inplanes self.conv1 = Conv2d(3, inplanes, kernel_size=3, stride=1, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(16) self.relu = nn.ReLU(inplace=True) self.layer1 = self._make_layer(block, inplanes, layers[0]) self.layer2 = self._make_layer(block, 2 * inplanes, layers[1], stride=2) self.layer3 = self._make_layer(block, 4 * inplanes, layers[2], stride=2) self.avgpool = nn.AvgPool2d(8, stride=1) self.fc = Linear(4 * inplanes * block.expansion, num_classes) for m in self.modules(): if isinstance(m, Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels nn.init.kaiming_normal_(m.weight.data) elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_()
def conv3x3(in_planes, out_planes, stride=1, act_dim_a=None, act_dim_b=None, weight_noise=False, act_noise_a=False, act_noise_b=False, rank=5): " 3x3 convolution with padding " return Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False, act_dim_a=act_dim_a, act_dim_b=act_dim_b, weight_noise=weight_noise, act_noise_a=act_noise_a, act_noise_b=act_noise_b, rank=rank)
def __init__(self, cfg): super(MaskRCNNC4Predictor, self).__init__() num_classes = cfg.MODEL.ROI_BOX_HEAD.NUM_CLASSES dim_reduced = cfg.MODEL.ROI_MASK_HEAD.CONV_LAYERS[-1] if cfg.MODEL.ROI_HEADS.USE_FPN: num_inputs = dim_reduced else: stage_index = 4 stage2_relative_factor = 2 ** (stage_index - 1) res2_out_channels = cfg.MODEL.RESNETS.RES2_OUT_CHANNELS num_inputs = res2_out_channels * stage2_relative_factor self.conv5_mask = ConvTranspose2d(num_inputs, dim_reduced, 2, 2, 0) self.mask_fcn_logits = Conv2d(dim_reduced, num_classes, 1, 1, 0) for name, param in self.named_parameters(): if "bias" in name: nn.init.constant_(param, 0) elif "weight" in name: # Caffe2 implementation uses MSRAFill, which in fact # corresponds to kaiming_normal_ in PyTorch nn.init.kaiming_normal_(param, mode="fan_out", nonlinearity="relu")
def main(): # time the slow version repeats = 100 data = torch.randn(64, 16, 28, 28) conv = Conv2d(16, 16, 3) start_slow_time = timer() for i in range(repeats): conv(data, slow=True) end_slow_time = timer() start_fast_time = timer() for i in range(repeats): conv(data) end_fast_time = timer() reshaped_weights = conv.weights.reshape(16, 16, 3, 3) bias = conv.bias start_torch_time = timer() for i in range(repeats): torch.relu(conv2d(data, reshaped_weights, bias)) end_torch_time = timer() print("Performance Results") print("===================") print() print() print( f"Slow Convolutional Method: {(end_slow_time - start_slow_time) / repeats} s/it" ) print( f"Faster Convolutional Method: {(end_fast_time - start_fast_time) / repeats} s/it" ) print( f"Pytorch Convolutional Method: {(end_torch_time - start_torch_time) / repeats} s/it" )