Our implementation of the networks will follow this architecture:

Let's test it on the descriptor and fingerprint maps
convnet = Convnet()
i = torch.rand((10, 13, 37, 37))
o = convnet(i)
o.shape
convnet = Convnet(3, 48)
i = torch.rand((10, 3, 37, 36))
o = convnet(i)
o.shape
Inception block
After the convolutional block, the resulting feature maps will further pass through some inception blocks.
The inceptions implemented here are the naïve Google inceptions. It passes the input through multiple convolutional layers and then concatenate the output. This inception block is actually two smaller inception blocks bridged with a max pooling layer. First the small inception block:
- Descriptor:
48*19*19-> 3 outputs of32*19*19->96*19*19, |->96*10*10-> 3 outputs of64*10*10->192*10*10 - Fingerprint:
48*19*18-> 3 outputs of32*19*18->96*19*18, |->96*10*9-> 3 outputs of64*10*9->192*10*9
inception = Inception()
i = torch.rand((10, 48, 19, 19))
o = inception(i)
o.shape
inception = Inception(96, 64)
i = torch.rand((10, 96, 10, 10))
o = inception(i)
o.shape
inception = Inception()
i = torch.rand((10, 48, 19, 18))
o = inception(i)
o.shape
inception = Inception(96, 64)
i = torch.rand((10, 96, 10, 9))
o = inception(i)
o.shape
And the double inception block:
double_inception = DoubleInception()
i = torch.rand((10, 48, 19, 19))
o = double_inception(i)
o.shape
double_inception = DoubleInception()
i = torch.rand((10, 48, 19, 18))
o = double_inception(i)
o.shape
i = torch.rand((10, 192, 10, 10))
o = i.amax(dim=(-1, -2))
o.shape
single_path_fully_connected = SinglePathFullyConnected()
i = torch.rand((10, 192))
o = single_path_fully_connected(i)
o.shape
double_path_fully_connected = DoublePathFullyConnected()
i = torch.rand((10, 384))
o = double_path_fully_connected(i)
o.shape
Single Path Molecular Mapping network
Descriptor map or Fingerprint map only. The two feature maps use identical network structures and only differ in data shape. Note that we need to specify the number of channels for the feature maps when initialising the model, but the model should be able to handle feature maps with different dimensions.
- descriptor:
13*37*37->32 - fingerprint:
3*37*36->32
The output layer is not included.
single_path = SinglePathMolMapNet()
i = torch.rand((10, 13, 37, 37))
o = single_path(i)
o.shape
single_path = SinglePathMolMapNet(conv_in=3)
i = torch.rand((10, 3, 37, 36))
o = single_path(i)
o.shape
Double Path Molecular Mapping network
Both the descriptor map and Fingerprint map will pass through the convolutional block, then the double inception block, and their results are then combined, before finally pass through the fully connected layers.
After convolutional and double inception block:
- descriptor:
13*37*37->192*10*10 - fingerprint:
3*37*36->192*10*9
After global max pooling:
- descriptor:
192*10*10->192 - fingerprint:
192*10*9->192
After Concatenation and fully connected blocks:
192 + 192->384->32
The output layer is not included.
double_path = DoublePathMolMapNet()
i1 = torch.rand((10, 13, 37, 37))
i2 = torch.rand((10, 3, 37, 36))
o = double_path(i1, i2)
o.shape
resnet = Resnet(48, 5)
i = torch.rand((10, 48, 19, 18))
o = resnet(i)
o.shape