human
2. Architecture
I want to have a "solid" simple ConvNet to use throughout these experiments. This model will include a large field-of-view input conv layer followed by several conv layers. Each conv layer uses BatchNorm and Leaky ReLU (I don't know if this is better than ReLU, but it sounds like a good'ish idea to me). The model's head uses an AdaptiveConcat Pooling layer (Fast AI invention that concatenates two adaptive average and max pooling layers) leading to a Linear layer. This model doesn't use dropout (I'll add that if it looks like it needs it)."
Please write code following the instructions in jupyter notebook style.
assistant
#Here is code to 2.

class AdaptiveConcatPool2d(nn.Module):
    """fast.ai, see: https://github.com/fastai/fastai/tree/master/fastai/layers.py"""
    def __init__(self, sz=None):
        super().__init__()
        sz = sz or (1,1)
        self.ap = torch.nn.AdaptiveAvgPool2d(sz)
        self.mp = torch.nn.AdaptiveAvgPool2d(sz)
    def forward(self, x):
        return torch.cat([self.mp(x), self.ap(x)], 1)
    
class Flatten(nn.Module):
    """fast.ai, see: https://github.com/fastai/fastai/tree/master/fastai/layers.py"""
    def __init__(self):
        super().__init__()
    def forward(self, x):
        return x.view(x.size(0), -1)

class ConvBNLayer(nn.Module):
    """conv layer with batchnorm"""
    def __init__(self, ch_in, ch_out, kernel_size=3, stride=1, padding=0):
        super().__init__()
        self.conv  = nn.Conv2d(ch_in, ch_out, kernel_size=kernel_size, stride=stride)
        self.bn    = nn.BatchNorm2d(ch_out, momentum=0.1) # mom at default 0.1
        self.lrelu = nn.LeakyReLU(0.01, inplace=True)     # neg slope at default 0.01
    def forward(self, x): return self.lrelu(self.bn(self.conv(x)))

class ConvNet(nn.Module):
    # see ref: https://github.com/fastai/fastai/blob/master/fastai/models/darknet.py
    def __init__(self, ch_in=1):
        super().__init__()
        self.conv0   = ConvBNLayer(ch_in, 16, kernel_size=7, stride=1, padding=2) # large FoV Conv
        self.conv1   = ConvBNLayer(16, 32)
        self.conv2   = ConvBNLayer(32, 64)
        self.conv3   = ConvBNLayer(64, 128)
        self.neck    = nn.Sequential(*[AdaptiveConcatPool2d(1), Flatten()])
        self.head    = nn.Sequential(*[nn.BatchNorm2d(256), 
                                      nn.Dropout(p=0.25),
                                      nn.Linear(256, 10)])        
    def forward(self, x):
        x = self.conv0(x)
        x = self.conv1(x)
        x = self.conv2(x)
        x = self.conv3(x)
        x = self.neck(x)
        x = self.head(x)
        return F.log_softmax(x, dim=-1)

convnet = ConvNet()