Skip to content

Commit ee25436

Browse files
committed
Add applications of deep neural networks in chemical research
- Introduced a new section on the application of deep neural networks in chemical research, focusing on dimensionality reduction using autoencoders and generative modeling with variational autoencoders. - Added detailed explanations of autoencoder architecture, implementation in PyTorch, and visualization of the latent space. - Discussed the use of variational autoencoders for generating new molecules from SMILES strings, including the integration of a property predictor for optimizing molecular properties. - Included relevant figures to illustrate concepts and enhance understanding.
1 parent 0fd035c commit ee25436

1 file changed

Lines changed: 137 additions & 1 deletion

File tree

src/06-neural_networks/02-mlp.md

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,140 @@ PyTorch provides many additional features for building sophisticated models:
205205
~~~
206206
```
207207

208-
## Application of Deep Neural Networks in Chemical Research
208+
## Application of Deep Neural Networks in Chemical Research
209+
210+
Let's now dive into some applications of deep neural networks in chemical research.
211+
212+
### Dimensionality Reduction using Autoencoders
213+
214+
So far, we have focused on supervised learning tasks where we have labeled data. However, neural networks can also be powerful tools for unsupervised learning, particularly for dimensionality reduction. One of the most elegant approaches is the **Autoencoder** (AE), which learns to compress data into a lower-dimensional representation and then reconstruct it.
215+
216+
The key insight behind autoencoders is to force a neural network to learn an efficient encoding of the data by creating a bottleneck in the network architecture. The network consists of two parts:
217+
218+
1. **Encoder**: Maps the input data $\vec{x} \in \mathbb{R}^d$ to a compressed representation $\vec{z} \in \mathbb{R}^{d'}$ where $d' < d$
219+
2. **Decoder**: Reconstructs the original data from the compressed representation: $\vec{x}' = \text{Decoder}(\vec{z})$
220+
221+
<figure>
222+
<center>
223+
<img src="../assets/figures/07-summary/Autoencoder_scheme.svg"
224+
alt="Autoencoder Architecture"
225+
width="500"\>
226+
<figcaption>Architecture of an autoencoder with encoder (left) and decoder (right) components.</figcaption>
227+
</center>
228+
</figure>
229+
230+
The training objective is to minimize the reconstruction error:
231+
232+
$$
233+
\mathcal{L}_{\text{recon}}(\vec{x}, \vec{x}') = \frac{1}{2} \sum_{i=1}^{N} \| \vec{x}_i - \vec{x}_i' \|^2
234+
$$
235+
236+
By forcing the network to reconstruct the input through a bottleneck, the encoder learns to capture the most important features of the data in the compressed representation $\vec{z}$. This compressed space is often called the **latent space** or **hidden space**.
237+
238+
#### Autoencoder Implementation in PyTorch
239+
240+
Here's a simple implementation of an autoencoder for the [MNIST dataset](https://en.wikipedia.org/wiki/MNIST_database), which is a collection of handwritten digits:
241+
242+
```python
243+
class Autoencoder(nn.Module):
244+
def __init__(self, input_dim=784, hidden_dim=128, latent_dim=2):
245+
super(Autoencoder, self).__init__()
246+
247+
# Encoder
248+
self.encoder = nn.Sequential(
249+
nn.Linear(input_dim, hidden_dim),
250+
nn.ReLU(),
251+
nn.Linear(hidden_dim, latent_dim)
252+
)
253+
254+
# Decoder
255+
self.decoder = nn.Sequential(
256+
nn.Linear(latent_dim, hidden_dim),
257+
nn.ReLU(),
258+
nn.Linear(hidden_dim, input_dim),
259+
nn.Sigmoid() # For MNIST pixel values [0,1]
260+
)
261+
262+
def forward(self, x):
263+
# Flatten the input
264+
x = x.view(x.size(0), -1)
265+
266+
# Encode
267+
z = self.encoder(x)
268+
269+
# Decode
270+
x_recon = self.decoder(z)
271+
272+
return x_recon, z
273+
```
274+
275+
#### Visualizing the Latent Space
276+
277+
One of the most fascinating aspects of autoencoders is that they can learn meaningful structure in the latent space, even without explicit supervision. When trained on MNIST, the autoencoder often organizes digits by their visual similarity in the 2D latent space:
278+
279+
<figure>
280+
<center>
281+
<img src="../assets/figures/07-summary/autoencoder_latent_space.svg"
282+
alt="MNIST Latent Space"
283+
width="400"\>
284+
<figcaption>2D latent space representation of MNIST digits learned by an autoencoder.</figcaption>
285+
</center>
286+
</figure>
287+
288+
This visualization shows that the autoencoder has learned to cluster similar digits together, demonstrating that it has captured meaningful features of the data in the compressed representation.
289+
290+
### Generative Modeling using Variational Autoencoders
291+
292+
While autoencoders are excellent for dimensionality reduction, they have a fundamental limitation for generative modeling: the latent space is not structured in a way that allows for meaningful sampling. If we randomly sample points from the latent space and decode them, we often get poor or nonsensical results.
293+
294+
**Variational Autoencoders (VAEs)** address this limitation by imposing a specific structure on the latent space. Instead of encoding data to a single point in latent space, the encoder learns to map each input to a probability distribution over the latent space.
295+
296+
<figure>
297+
<center>
298+
<img src="../assets/figures/07-summary/VAE_scheme.svg"
299+
alt="VAE Architecture"
300+
width="500"\>
301+
<figcaption>Architecture of a Variational Autoencoder with probabilistic encoder and decoder.</figcaption>
302+
</center>
303+
</figure>
304+
305+
#### Key Differences from Standard Autoencoders
306+
307+
1. **Probabilistic Encoder**: Instead of outputting a single latent vector $\vec{z}$, the encoder outputs parameters of a probability distribution (typically mean $\vec{\mu}$ and variance $\vec{\sigma}^2$ of a Gaussian)
308+
309+
2. **Sampling**: During training and generation, we sample from this distribution: $\vec{z} \sim \mathcal{N}(\vec{\mu}, \vec{\sigma}^2)$
310+
311+
3. **Regularization**: The VAE loss function includes a regularization term that encourages the learned distributions to be close to a standard normal distribution $\mathcal{N}(0, I)$
312+
313+
The VAE loss function consists of two terms:
314+
315+
$$
316+
\mathcal{L}(\vec{x}, \vec{x}') = \mathcal{L}_{\text{recon}}(\vec{x}, \vec{x}') + \mathcal{L}_{\text{KL}}
317+
$$
318+
319+
where $\mathcal{L}_{\text{KL}}$ is the Kullback-Leibler divergence between the learned distribution and the standard normal distribution:
320+
321+
$$
322+
\mathcal{L}_{\text{KL}} = D_{KL}(\mathcal{N}(\vec{\mu}, \vec{\sigma}^2) \| \mathcal{N}(0, I))
323+
$$
324+
325+
This regularization ensures that the latent space is well-structured and continuous, making it possible to generate new data by sampling from the latent space and decoding, which is shown in the figure below. Sampling from this latent space now allows us to generate new data.
326+
327+
<figure>
328+
<center>
329+
<img src="../assets/figures/07-summary/vae_latent_space.svg"
330+
alt="VAE Latent Space"
331+
width="400"\>
332+
<figcaption>2D latent space of a VAE trained on MNIST, showing better structure than standard autoencoders.</figcaption>
333+
</center>
334+
</figure>
335+
336+
### Generative Modeling in Chemical Research
337+
338+
The [paper by Gómez-Bombarelli and co-workers](https://doi.org/10.1021/acscentsci.7b00572) applies exactly this idea to molecules. Instead of working with images or digits, they train a VAE to encode and decode SMILES strings, which are text-based representations of molecules. The encoder network learns to map each SMILES string into a continuous vector — a point in latent space — and the decoder reconstructs the original SMILES from that vector. In this way, the network learns a compact and continuous representation of molecular structure.
339+
340+
But the goal here is not just to reconstruct molecules — the real innovation is using the latent space to generate new molecules. Because the latent space is continuous and smooth, you can take a point (representing a known molecule), slightly change it, and decode the result into a new molecule that is chemically similar. This is powerful: rather than building molecules by hand or randomly combining fragments, we can navigate through chemical space in a structured way.
341+
342+
To guide this navigation, the authors add a third component to their model: a property predictor. This is a neural network that learns to predict molecular properties (such as drug-likeness or solubility) directly from the latent vector. During training, the autoencoder and the property predictor are optimized together. This means the latent space becomes organized not just by molecular structure, but also by chemical functionality — nearby points tend to correspond to molecules with similar properties.
343+
344+
This setup allows for gradient-based optimization in chemical space. Instead of searching for good molecules by trial and error, one can compute the gradient of the property of interest with respect to the latent vector, and then move in the direction that improves the property — just like you would in regular optimization problems. Once a promising point is found, it can be decoded back into a molecule using the decoder.

0 commit comments

Comments
 (0)