Readme changes, logo added, tags in readme

This commit is contained in:
Alec Helbling
2022-03-28 00:55:06 -04:00
committed by Alec Helbling
parent ca0e93d657
commit 4eb5296c9c
14 changed files with 178 additions and 35 deletions

9
LICENSE.md Normal file
View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) 2022 Alec Helbling
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -2,7 +2,7 @@ setup:
conda activate manim
export PROJECT_ROOT=$(pwd)
video:
manim -pqh src/vae.py VAEScene --media_dir media
manim -pqh src/variational_autoencoder.py VAEScene --media_dir media
cp media/videos/vae/720p60/VAEScene.mp4 examples
train:
cd src/autoencoder_models

View File

@@ -1,26 +1,43 @@
# Manim Machine Learning
<a href="https://github.com/helblazer811/ManimMachineLearning">
<img src="examples/ManimMLLogo.gif">
</a>
Manim Machine Learning is a project focused on providing animations and visualizations of common machine learning concepts with the [Manim Community Library](https://www.manim.community/). We want this project to be a compilation of primitive visualizations that can be easily combined to create videos about complex machine learning concepts.
[![GitHub license](https://img.shields.io/github/license/helblazer811/ManimMachineLearning)](https://github.com/helblazer811/ManimMachineLearning/blob/main/LICENSE.md)
[![GitHub tag](https://img.shields.io/github/v/release/helblazer811/ManimMachineLearning)](https://img.shields.io/github/v/release/helblazer811/ManimMachineLearning)
[![Github All releases](https://img.shields.io/github/downloads/helblazer811/ManimMachineLearning/total)](https://GitHub.com/helblazer811/ManimMachineLearning/releases/)
[![Follow Twitter](https://img.shields.io/twitter/follow/alec_helbling?style=social)](https://twitter.com/alec_helbling)
Manim Machine Learning is a project focused on providing animations and visualizations of common machine learning concepts with the [Manim Community Library](https://www.manim.community/). We want this project to be a compilation of primitive visualizations that can be easily combined to create videos about complex machine learning concepts. Additionally, we want to provide a set of abstractions which allow users to focus on explanations instead of software engineering.
## Table of Contents
1. [Getting Started](#getting-started)
2. [Examples](#examples)
## Getting Started
First you will want to install manim. Then you can run the following to generate the example videos.
`make video`
or
First you will want to [install manim](https://docs.manim.community/en/stable/installation.html). Then you can run the following to generate the example videos.
`manim -pqh src/vae.py VAEScene`
## Examples
Checkout the ```examples``` directory for some example videos with source code.
### Variational Autoencoders
This is a visualization of a Variational Autoencoder. You can also find a video form in examples/
This is a visualization of a Variational Autoencoder.
<img src="examples/VAEImage.png" width="600">
<img src="examples/VAEScene.gif" width="600">
### VAE Disentanglement
This is a visualization of disentanglement with a Variational Autoencoder
<img src="examples/DisentanglementScene.gif" width="600">
### Neural Networks
This is a visualization of a Neural Network. You can find a video animation of a neural network in examples/
This is a visualization of a Neural Network.
<img src="examples/NNImage.png" width="600">
<img src="examples/TestNeuralNetworkScene.gif" width="600">

BIN
examples/ManimMLLogo.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

View File

Binary file not shown.

View File

@@ -10,7 +10,7 @@ import scipy
import scipy.stats
import cv2
def binned_images(model_path, num_x_bins=10, plot=False):
def binned_images(model_path, num_x_bins=6, plot=False):
latent_dim = 2
model = load_vae_from_path(model_path, latent_dim)
image_dataset = load_dataset(digit=2)

View File

Binary file not shown.

View File

@@ -198,7 +198,7 @@ def train_model(latent_dim=16, plot=True, digit=1, epochs=200):
losses.append(loss.detach().cpu())
outputs.append((epochs, image, reconstructed))
torch.save(model.state_dict(), f"saved_models/model_dim{latent_dim}.pth")
torch.save(model.state_dict(), os.path.join(os.environ["PROJECT_ROOT"], f"saved_models/model_dim{latent_dim}.pth"))
if plot:
# Defining the Plot Style
@@ -211,4 +211,4 @@ def train_model(latent_dim=16, plot=True, digit=1, epochs=200):
plt.show()
if __name__ == "__main__":
train_model(latent_dim=2, digit=1, epochs=40)
train_model(latent_dim=2, digit=2, epochs=40)

View File

@@ -19,7 +19,7 @@ class VAEDecoder(VGroup):
class DisentanglementVisualization(VGroup):
def __init__(self, model_path="autoencoder_models/saved_models/model_dim2.pth", image_height=0.2):
def __init__(self, model_path="autoencoder_models/saved_models/model_dim2.pth", image_height=0.35):
self.model_path = model_path
self.image_height = image_height
# Load disentanglement image objects
@@ -33,7 +33,7 @@ class DisentanglementVisualization(VGroup):
r, c = self.image_handler["bin_indices"][image_index]
# Move the image to the correct location
r_offset = -1.2
c_offset = 0.2
c_offset = 0.25
image_location = [c_offset + c*self.image_height, r_offset + r*self.image_height, 0]
image_mobject.move_to(image_location)
animation_list.append(FadeIn(image_mobject))
@@ -54,7 +54,7 @@ class DisentanglementScene(Scene):
embedding = VGroup()
# Sample points from a Gaussian
num_points = 200
standard_deviation = [0.6, 1.0]
standard_deviation = [0.6, 0.8]
mean = [0, 0]
points = np.random.normal(mean, standard_deviation, size=(num_points, 2))
# Make an axes
@@ -78,13 +78,13 @@ class DisentanglementScene(Scene):
def construct(self):
# Make the VAE decoder
vae_decoder = VAEDecoder()
vae_decoder.shift([-0.65, 0, 0])
vae_decoder.shift([-0.55, 0, 0])
self.play(Create(vae_decoder), run_time=1)
# Make the embedding
embedding = self._construct_embedding()
embedding.scale(0.8)
embedding.scale(0.9)
embedding.move_to(vae_decoder.get_left())
embedding.shift([-0.7, 0, 0])
embedding.shift([-0.85, 0, 0])
self.play(Create(embedding))
# Make disentanglment visualization
disentanglement = DisentanglementVisualization()

57
src/interpolation.py Normal file
View File

@@ -0,0 +1,57 @@
"""Visualization of VAE Interpolation"""
import sys
import os
sys.path.append(os.environ["PROJECT_ROOT"])
from manim import *
import pickle
import numpy as np
import neural_network
import variational_autoencoder
"""
The VAE Scene for the twitter video.
"""
config.pixel_height = 720
config.pixel_width = 1280
config.frame_height = 6.0
config.frame_width = 6.0
# Set random seed so point distribution is constant
np.random.seed(1)
class InterpolationScene(MovingCameraScene):
"""Scene object for a Variational Autoencoder and Autoencoder"""
def construct(self):
# Set Scene config
vae = variational_autoencoder.VariationalAutoencoder(dot_radius=0.035, layer_spacing=0.5)
vae.move_to(ORIGIN)
vae.encoder.shift(LEFT*0.5)
vae.decoder.shift(RIGHT*0.5)
mnist_image_handler = variational_autoencoder.MNISTImageHandler()
image_pair = mnist_image_handler.image_pairs[3]
# Make forward pass animation and DO NOT run it
forward_pass_animation = vae.make_forward_pass_animation(image_pair)
# Make the interpolation animation
interpolation_images = mnist_image_handler.interpolation_images
interpolation_animation = vae.make_interpolation_animation(interpolation_images)
embedding_zoom_animation = self.camera.auto_zoom([
vae.embedding,
vae.decoder,
vae.output_image
], margin=0.5)
# Make animations
forward_pass_animations = []
for i in range(7):
anim = vae.decoder.make_forward_propagation_animation(run_time=0.5)
forward_pass_animations.append(anim)
forward_pass_animation_group = AnimationGroup(*forward_pass_animations, lag_ratio=1.0)
# Make forward pass animations
self.play(Create(vae), run_time=1.5)
self.play(FadeOut(vae.encoder), run_time=1.0)
self.play(embedding_zoom_animation, run_time=1.5)
interpolation_animation = AnimationGroup(
forward_pass_animation_group,
interpolation_animation
)
self.play(interpolation_animation, run_time=9.0)

41
src/logo.py Normal file
View File

@@ -0,0 +1,41 @@
"""
Logo for Manim Machine Learning
"""
from manim import *
from neural_network import NeuralNetwork
config.pixel_height = 500
config.pixel_width = 1920
config.frame_height = 10.0
config.frame_width = 10.0
class ManimMLLogo(Scene):
def construct(self):
self.text = Text("ManimML")
self.text.scale(1.3)
self.neural_network = NeuralNetwork([3, 5, 3, 6, 3], layer_spacing=0.6, node_color=BLUE)
self.neural_network.scale(0.8)
self.neural_network.move_to(self.text.get_right())
self.neural_network.shift(RIGHT * 1.3)
self.logo_group = VGroup(self.text, self.neural_network)
self.logo_group.scale(1.5)
self.logo_group.move_to(ORIGIN)
self.play(Write(self.text))
self.play(Create(self.neural_network))
# self.surrounding_rectangle = SurroundingRectangle(self.logo_group, buff=0.3, color=BLUE)
underline = Underline(self.text, color=BLUE)
animation_group = AnimationGroup(
self.neural_network.make_forward_propagation_animation(run_time=5),
Create(underline),
# Create(self.surrounding_rectangle)
)
# self.surrounding_rectangle = SurroundingRectangle(self.logo_group, buff=0.3, color=BLUE)
underline = Underline(self.text, color=BLUE)
animation_group = AnimationGroup(
self.neural_network.make_forward_propagation_animation(run_time=5),
Create(underline),
# Create(self.surrounding_rectangle)
)
self.play(animation_group)
self.wait(5)

View File

@@ -84,7 +84,7 @@ class NeuralNetwork(VGroup):
layers = VGroup()
# Create each layer
for layer_index, node_count in enumerate(self.layer_node_count):
layer = NeuralNetworkLayer(node_count)
layer = NeuralNetworkLayer(node_count, node_color=self.node_color)
# Manage spacing
layer.move_to([self.layer_spacing * layer_index, 0, 0])
# Add layer to VGroup

View File

@@ -0,0 +1,20 @@
from manim import *
class NeuralNetworkEmbedding(Axes):
"""NeuralNetwork embedding object that can show probability distributions"""
def construct_gaussian_distribution(self, mean, covariance, color=ORANGE, dot_radius=0.05, ellipse_stroke_width=0.3):
"""Returns a 2d Gaussian distribution object with given mean and covariance"""
# map mean and covariance to frame coordinates
mean = self.coords_to_point(*mean)
covariance = self.coords_to_point(*covariance)
# Make a covariance ellipse centered at mean
center_dot = Dot(mean, radius=dot_radius, color=color)
ellipse = Ellipse(width=covariance[0], height=covariance[1], color=color, fill_opacity=0.3, stroke_width=ellipse_stroke_width)
ellipse.move_to(mean)
gaussian_distribution = VGroup(
center_dot,
ellipse
)
return gaussian_distribution

View File

@@ -4,35 +4,34 @@ In this module I define Manim visualizations for Variational Autoencoders
and Traditional Autoencoders.
"""
from configparser import Interpolation
from random import sample
from manim import *
import pickle
import numpy as np
import os
import neural_network
from scipy.interpolate import make_interp_spline
class VariationalAutoencoder(VGroup):
"""Variational Autoencoder Manim Visualization"""
def __init__(
self, encoder_nodes_per_layer=[5, 3], decoder_nodes_per_layer=[3, 5], point_color=BLUE,
dot_radius=0.05, ellipse_stroke_width=2.0
dot_radius=0.05, ellipse_stroke_width=2.0, layer_spacing=0.5
):
super(VGroup, self).__init__()
self.encoder_nodes_per_layer = encoder_nodes_per_layer
self.decoder_nodes_per_layer = decoder_nodes_per_layer
self.point_color = point_color
self.dot_radius = dot_radius
self.layer_spacing = layer_spacing
self.ellipse_stroke_width = ellipse_stroke_width
# Make the VMobjects
self.encoder, self.decoder = self._construct_encoder_and_decoder()
self.embedding = self._construct_embedding()
# Setup the relative locations
self.embedding.move_to(self.encoder)
self.embedding.shift([1.1 * self.encoder.width, 0, 0])
self.embedding.shift([1.4 * self.encoder.width, 0, 0])
self.decoder.move_to(self.embedding)
self.decoder.shift([self.decoder.width * 1.1, 0, 0])
self.decoder.shift([self.decoder.width * 1.4, 0, 0])
# Add the objects to the VAE object
self.add(self.encoder)
self.add(self.decoder)
@@ -42,11 +41,11 @@ class VariationalAutoencoder(VGroup):
"""Makes the VAE encoder and decoder"""
# Make the encoder
layer_node_count = self.encoder_nodes_per_layer
encoder = neural_network.NeuralNetwork(layer_node_count, dot_radius=self.dot_radius)
encoder = neural_network.NeuralNetwork(layer_node_count, dot_radius=self.dot_radius, layer_spacing=self.layer_spacing)
encoder.scale(1.2)
# Make the decoder
layer_node_count = self.decoder_nodes_per_layer
decoder = neural_network.NeuralNetwork(layer_node_count, dot_radius=self.dot_radius)
decoder = neural_network.NeuralNetwork(layer_node_count, dot_radius=self.dot_radius, layer_spacing=self.layer_spacing)
decoder.scale(1.2)
return encoder, decoder
@@ -56,7 +55,7 @@ class VariationalAutoencoder(VGroup):
embedding = VGroup()
# Sample points from a Gaussian
num_points = 200
standard_deviation = [0.7, 0.7]
standard_deviation = [0.9, 0.9]
mean = [0, 0]
points = np.random.normal(mean, standard_deviation, size=(num_points, 2))
# Make an axes
@@ -152,7 +151,7 @@ class VariationalAutoencoder(VGroup):
self.input_image.move_to(self.encoder.get_left())
self.input_image.shift(LEFT)
self.output_image.move_to(self.decoder.get_right())
self.output_image.shift(RIGHT)
self.output_image.shift(RIGHT*1.3)
# Make encoder forward pass
encoder_forward_pass = self.encoder.make_forward_propagation_animation(run_time=per_unit_runtime)
# Make red dot in embedding
@@ -245,8 +244,8 @@ class MNISTImageHandler():
def __init__(
self,
image_pairs_file_path="src/autoencoder_models/image_pairs.pkl",
interpolations_file_path="src/autoencoder_models/interpolations.pkl"
image_pairs_file_path=os.path.join(os.environ["PROJECT_ROOT"], "autoencoder_models/image_pairs.pkl"),
interpolations_file_path=os.path.join(os.environ["PROJECT_ROOT"], "autoencoder_models/interpolations.pkl")
):
self.image_pairs_file_path = image_pairs_file_path
self.interpolations_file_path = interpolations_file_path
@@ -271,8 +270,8 @@ class MNISTImageHandler():
"""
config.pixel_height = 720
config.pixel_width = 1280
config.frame_height = 10.0
config.frame_width = 10.0
config.frame_height = 5.0
config.frame_width = 5.0
# Set random seed so point distribution is constant
np.random.seed(1)