https://github.com/msmrexe/pytorch-normalizing-flows-2d
A from-scratch implementation of a Normalizing Flow (Real NVP) to model and sample from a 2D 'two-moons' distribution. Allows for GIF visualization of the NF evolution.
https://github.com/msmrexe/pytorch-normalizing-flows-2d
change-of-variables course-project density-estimation generative-models maximum-likelihood-estimation normalizing-flows pytorch real-nvp university-project
Last synced: 3 months ago
JSON representation
A from-scratch implementation of a Normalizing Flow (Real NVP) to model and sample from a 2D 'two-moons' distribution. Allows for GIF visualization of the NF evolution.
- Host: GitHub
- URL: https://github.com/msmrexe/pytorch-normalizing-flows-2d
- Owner: msmrexe
- License: mit
- Created: 2025-10-30T09:27:20.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2025-10-30T09:40:28.000Z (3 months ago)
- Last Synced: 2025-10-30T11:37:26.126Z (3 months ago)
- Topics: change-of-variables, course-project, density-estimation, generative-models, maximum-likelihood-estimation, normalizing-flows, pytorch, real-nvp, university-project
- Language: Python
- Homepage:
- Size: 23.4 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Normalizing Flow for 2D Density Estimation
A from-scratch implementation of a Normalizing Flow model, based on Real NVP (Real Non-Volume Preserving) transformations, to learn and sample from a 2D 'two-moons' distribution. This project was developed for the M.S. Generative Models course at Sharif University of Technology.
## Features
* **Real NVP Implementation:** Core logic built using affine coupling layers.
* **Modular `Flow` Class:** A `nn.Module` that stacks multiple transformations for complex density estimation.
* **Maximum Likelihood Training:** Optimized by minimizing the negative log-likelihood (NLL) of the data.
* **Density Visualization:** Generates and saves the learned probability density at each epoch.
* **GIF Generation:** Automatically creates a GIF visualizing the evolution of the learned density over training.
* **Data Sampling:** Capable of sampling new data points from the learned distribution.
## Core Concepts & Techniques
* **Normalizing Flows:** A class of generative models that learn a data distribution $p_X(x)$ by transforming a simple base distribution $p_Z(z)$ (e.g., a Gaussian) through an invertible, differentiable mapping $f: \mathcal{Z} \to \mathcal{X}$.
* **Change of Variables Formula:** The core principle used for training. The log-likelihood of a data point $x$ is given by the formula:
$$\log p_X(x) = \log p_Z(f(x)) + \log \left| \det J_f(x) \right|$$
where $z = f(x)$ is the forward transformation (data to latent) and $J_f(x)$ is its Jacobian.
* **Coupling Layers (Real NVP):** An efficient invertible transformation $y = f(x)$ where the input $x$ is split into two parts ($x_A, x_B$). One part is left unchanged ($y_A = x_A$), while the other is transformed using a simple affine function (scaling and translation) whose parameters ($s, t$) are generated by a neural network that only takes the unchanged part as input:
$$y_B = x_B \odot \exp(s(x_A)) + t(x_A)$$
This design results in a triangular Jacobian matrix, making the determinant (and its log) trivial to compute: it is simply the sum of the scaling factors, $\sum s(x_A)$.
* **Maximum Likelihood Estimation (MLE):** The model is trained by adjusting the parameters of the $s$ and $t$ networks to maximize the log-likelihood of the training data, which is equivalent to minimizing the negative log-likelihood (NLL) loss.
---
## How It Works
This project learns a complex distribution (two moons) by mapping it to a simple one (a 2D standard Gaussian).
### 1. Core Logic & Architecture
The repository implements a `Flow` model composed of a series of `CouplingTransform` layers. Each `CouplingTransform` layer splits the 2D input $x = (x_1, x_2)$ based on an alternating binary mask.
1. **Transform 1 (Mask `[1, 0]`):**
* $x_1$ is **fixed**.
* $s_1, t_1 = \text{NN}_1(x_1)$
* $z_1 = x_1$
* $z_2 = x_2 \odot \exp(s_1) + t_1$
2. **Transform 2 (Mask `[0, 1]`):**
* $z_2$ is **fixed**.
* $s_2, t_2 = \text{NN}_2(z_2)$
* $z'_1 = z_1 \odot \exp(s_2) + t_2$
* $z'_2 = z_2$
This sequence of invertible transformations ($x \to z \to z' \dots$) maps the complex 'two-moons' data to a 2D standard Gaussian. Training is done by maximizing $\log p_X(x)$, and sampling is done by drawing $z$ from the Gaussian and applying the inverse of all transforms: $x = f_1^{-1}(f_2^{-1}(\dots f_N^{-1}(z)))$.
### 2. Key Files & Functions
* `main.py`: The main executable script. It handles argument parsing, sets up logging, loads the data, initializes the `Flow` model, and runs the training loop. After training, it generates all final visualizations.
* `src/model.py`: Defines the `Flow` class. This class stacks multiple `CouplingTransform` layers. It implements:
* `forward(x)`: Maps data to latent space ($x \to z$) and returns $z$ and the total $\log \det J$.
* `inverse(z)`: Maps latent space to data space ($z \to x$).
* `log_prob(x)`: Applies the Change of Variables formula to compute the log-likelihood of the data.
* `sample(n)`: Generates $n$ new samples by drawing from the base distribution and applying the `inverse` method.
* `src/transforms.py`: Defines the `CouplingTransform` class. This class implements the core Real NVP logic, including the $s$ and $t$ neural networks, the `forward` pass, the `inverse` pass, and the log-det-Jacobian calculation.
* `src/utils.py`: Contains all helper functions for loading the `make_moons` dataset (`load_data`), creating the alternating masks (`create_alternating_masks`), setting up logging (`setup_logging`), and handling all visualizations (`visualize_density`, `plot_comparison`, `create_gif`).
---
## Project Structure
```
pytorch-normalizing-flows-2d/
├── .gitignore # Ignores Python caches, envs, and output files
├── LICENSE # MIT License file
├── README.md # This repository README
├── main.py # Main script to train the model and generate outputs
├── requirements.txt # Required Python packages
├── run_flow_model.ipynb # Jupyter Notebook to run the training and view results
└── src/
├── __init__.py # Makes 'src' a Python package
├── model.py # Contains the main 'Flow' model class
├── transforms.py # Defines the 'CouplingTransform' layer
└── utils.py # Helper functions for data, logging, and visualization
```
## How to Use
1. **Clone the Repository:**
```bash
git clone https://github.com/msmrexe/pytorch-normalizing-flows-2d.git
cd pytorch-normalizing-flows-2d
```
2. **Setup the Environment:**
It's recommended to use a virtual environment.
```bash
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
```
3. **Run the Training Script:**
You can run the model directly from the command line.
```bash
python main.py --epochs 150 --lr 0.001 --output_dir outputs
```
* `--epochs`: Number of training epochs (e.g., 150).
* `--lr`: Learning rate (e.g., 0.001).
* `--output_dir`: Directory to save final plots and GIF.
* `--skip_frames`: (Optional) Use this flag to disable saving frames every epoch, which speeds up training.
4. **Example Output / Check Results:**
The script will log progress to the console and to `logs/flow.log`. After training, you will find the following files in the `outputs/` directory:
* `density_evolution.gif`: An animation of the learned density.
* `data_comparison.png`: A scatter plot comparing original and generated data.
* `final_density.png`: The final learned probability density.
Alternatively, you can run the `run_flow_model.ipynb` notebook in Jupyter to execute the training and see the outputs displayed inline.
---
## Author
Feel free to connect or reach out if you have any questions!
* **Maryam Rezaee**
* **GitHub:** [@msmrexe](https://github.com/msmrexe)
* **Email:** [ms.maryamrezaee@gmail.com](mailto:ms.maryamrezaee@gmail.com)
---
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for full details.