mirror of
https://github.com/helblazer811/ManimML.git
synced 2025-05-17 18:55:54 +08:00
Used Black to reformat the code in the repository.
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@ -6,4 +6,7 @@ manim_ml/media
|
||||
media
|
||||
pyproject.toml
|
||||
setup.cfg
|
||||
!examples/media
|
||||
!examples/media
|
||||
examples/media/videos
|
||||
examples/media/text
|
||||
examples/media/images
|
@ -2,22 +2,21 @@ from manim import *
|
||||
from manim_ml.neural_network.layers import FeedForwardLayer
|
||||
from manim_ml.neural_network.neural_network import NeuralNetwork
|
||||
|
||||
|
||||
class NeuralNetworkScene(Scene):
|
||||
"""Test Scene for the Neural Network"""
|
||||
|
||||
def construct(self):
|
||||
# Make the Layer object
|
||||
layers = [
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3)
|
||||
]
|
||||
layers = [FeedForwardLayer(3), FeedForwardLayer(5), FeedForwardLayer(3)]
|
||||
nn = NeuralNetwork(layers)
|
||||
nn.scale(2)
|
||||
nn.move_to(ORIGIN)
|
||||
# Make Animation
|
||||
self.add(nn)
|
||||
#self.play(Create(nn))
|
||||
forward_propagation_animation = nn.make_forward_pass_animation(run_time=5, passing_flash=True)
|
||||
# self.play(Create(nn))
|
||||
forward_propagation_animation = nn.make_forward_pass_animation(
|
||||
run_time=5, passing_flash=True
|
||||
)
|
||||
|
||||
self.play(forward_propagation_animation)
|
||||
self.play(forward_propagation_animation)
|
||||
|
@ -15,6 +15,7 @@ config.frame_height = 7.0
|
||||
config.frame_width = 7.0
|
||||
ROOT_DIR = Path(__file__).parents[2]
|
||||
|
||||
|
||||
def make_code_snippet():
|
||||
code_str = """
|
||||
# Make nn
|
||||
@ -31,32 +32,34 @@ def make_code_snippet():
|
||||
"""
|
||||
|
||||
code = Code(
|
||||
code = code_str,
|
||||
code=code_str,
|
||||
tab_width=4,
|
||||
background_stroke_width=1,
|
||||
background_stroke_color=WHITE,
|
||||
insert_line_no=False,
|
||||
style='monokai',
|
||||
#background="window",
|
||||
style="monokai",
|
||||
# background="window",
|
||||
language="py",
|
||||
)
|
||||
code.scale(0.50)
|
||||
|
||||
return code
|
||||
|
||||
|
||||
class CombinedScene(ThreeDScene):
|
||||
def construct(self):
|
||||
image = Image.open(ROOT_DIR / 'assets/mnist/digit.jpeg')
|
||||
image = Image.open(ROOT_DIR / "assets/mnist/digit.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
# Make nn
|
||||
nn = NeuralNetwork([
|
||||
nn = NeuralNetwork(
|
||||
[
|
||||
ImageLayer(numpy_image, height=1.5),
|
||||
Convolutional3DLayer(1, 7, 7, 3, 3, filter_spacing=0.32),
|
||||
Convolutional3DLayer(3, 5, 5, 3, 3, filter_spacing=0.32),
|
||||
Convolutional3DLayer(5, 3, 3, 1, 1, filter_spacing=0.18),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(3),
|
||||
],
|
||||
],
|
||||
layer_spacing=0.25,
|
||||
)
|
||||
# Center the nn
|
||||
@ -71,10 +74,7 @@ class CombinedScene(ThreeDScene):
|
||||
group.move_to(ORIGIN)
|
||||
# Play animation
|
||||
forward_pass = nn.make_forward_pass_animation(
|
||||
corner_pulses=False,
|
||||
all_filters_at_once=False
|
||||
corner_pulses=False, all_filters_at_once=False
|
||||
)
|
||||
self.wait(1)
|
||||
self.play(
|
||||
forward_pass
|
||||
)
|
||||
self.play(forward_pass)
|
||||
|
@ -9,8 +9,8 @@ config.pixel_width = 1280
|
||||
config.frame_height = 6.0
|
||||
config.frame_width = 6.0
|
||||
|
||||
class ImageNeuralNetworkScene(Scene):
|
||||
|
||||
class ImageNeuralNetworkScene(Scene):
|
||||
def make_code_snippet(self):
|
||||
code_str = """
|
||||
# Make image object
|
||||
@ -32,13 +32,13 @@ class ImageNeuralNetworkScene(Scene):
|
||||
"""
|
||||
|
||||
code = Code(
|
||||
code = code_str,
|
||||
code=code_str,
|
||||
tab_width=4,
|
||||
background_stroke_width=1,
|
||||
background_stroke_color=WHITE,
|
||||
insert_line_no=False,
|
||||
style='monokai',
|
||||
#background="window",
|
||||
style="monokai",
|
||||
# background="window",
|
||||
language="py",
|
||||
)
|
||||
code.scale(0.2)
|
||||
@ -46,22 +46,22 @@ class ImageNeuralNetworkScene(Scene):
|
||||
return code
|
||||
|
||||
def construct(self):
|
||||
image = Image.open('../../tests/images/image.jpeg')
|
||||
image = Image.open("../../tests/images/image.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
# Make nn
|
||||
layers = [
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(6)
|
||||
FeedForwardLayer(6),
|
||||
]
|
||||
nn = NeuralNetwork(layers)
|
||||
nn.scale(0.9)
|
||||
# Center the nn
|
||||
nn.move_to(ORIGIN)
|
||||
nn.rotate(-PI/2)
|
||||
nn.layers[0].image_mobject.rotate(PI/2)
|
||||
nn.rotate(-PI / 2)
|
||||
nn.layers[0].image_mobject.rotate(PI / 2)
|
||||
nn.layers[0].image_mobject.shift([0, -0.4, 0])
|
||||
nn.shift([1.5, 0.3, 0])
|
||||
self.add(nn)
|
||||
@ -71,15 +71,14 @@ class ImageNeuralNetworkScene(Scene):
|
||||
code_snippet.shift([-1.25, 0, 0])
|
||||
self.add(code_snippet)
|
||||
# Play animation
|
||||
self.play(
|
||||
nn.make_forward_pass_animation(run_time=10)
|
||||
)
|
||||
self.play(nn.make_forward_pass_animation(run_time=10))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""Render all scenes"""
|
||||
# Feed Forward Neural Network
|
||||
ffnn_scene = FeedForwardNeuralNetworkScene()
|
||||
ffnn_scene.render()
|
||||
# Neural Network
|
||||
# Neural Network
|
||||
nn_scene = NeuralNetworkScene()
|
||||
nn_scene.render()
|
||||
|
@ -9,8 +9,8 @@ config.pixel_width = 720
|
||||
config.frame_height = 6.0
|
||||
config.frame_width = 6.0
|
||||
|
||||
class VAECodeSnippetScene(Scene):
|
||||
|
||||
class VAECodeSnippetScene(Scene):
|
||||
def make_code_snippet(self):
|
||||
code_str = """
|
||||
# Make Neural Network
|
||||
@ -28,33 +28,38 @@ class VAECodeSnippetScene(Scene):
|
||||
"""
|
||||
|
||||
code = Code(
|
||||
code = code_str,
|
||||
code=code_str,
|
||||
tab_width=4,
|
||||
background_stroke_width=1,
|
||||
# background_stroke_color=WHITE,
|
||||
insert_line_no=False,
|
||||
background="window",
|
||||
# font="Monospace",
|
||||
style='one-dark',
|
||||
style="one-dark",
|
||||
language="py",
|
||||
)
|
||||
|
||||
return code
|
||||
|
||||
def construct(self):
|
||||
image = Image.open('../../tests/images/image.jpeg')
|
||||
image = Image.open("../../tests/images/image.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
embedding_layer = EmbeddingLayer(dist_theme="ellipse", point_radius=0.04).scale(1.0)
|
||||
embedding_layer = EmbeddingLayer(dist_theme="ellipse", point_radius=0.04).scale(
|
||||
1.0
|
||||
)
|
||||
# Make nn
|
||||
nn = NeuralNetwork([
|
||||
ImageLayer(numpy_image, height=1.2),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
ImageLayer(numpy_image, height=1.2),
|
||||
], layer_spacing=0.1)
|
||||
nn = NeuralNetwork(
|
||||
[
|
||||
ImageLayer(numpy_image, height=1.2),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
ImageLayer(numpy_image, height=1.2),
|
||||
],
|
||||
layer_spacing=0.1,
|
||||
)
|
||||
|
||||
nn.scale(1.1)
|
||||
# Center the nn
|
||||
@ -73,13 +78,11 @@ class VAECodeSnippetScene(Scene):
|
||||
# code_snippet.shift([-1.25, 0, 0])
|
||||
self.add(code_snippet)
|
||||
# Play animation
|
||||
self.play(
|
||||
nn.make_forward_pass_animation(),
|
||||
run_time=10
|
||||
)
|
||||
|
||||
self.play(nn.make_forward_pass_animation(), run_time=10)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""Render all scenes"""
|
||||
# Neural Network
|
||||
# Neural Network
|
||||
nn_scene = VAECodeSnippetScene()
|
||||
nn_scene.render()
|
||||
|
@ -9,8 +9,8 @@ config.pixel_width = 1280
|
||||
config.frame_height = 6.0
|
||||
config.frame_width = 6.0
|
||||
|
||||
class VAECodeSnippetScene(Scene):
|
||||
|
||||
class VAECodeSnippetScene(Scene):
|
||||
def make_code_snippet(self):
|
||||
code_str = """
|
||||
# Make image object
|
||||
@ -34,14 +34,14 @@ class VAECodeSnippetScene(Scene):
|
||||
"""
|
||||
|
||||
code = Code(
|
||||
code = code_str,
|
||||
code=code_str,
|
||||
tab_width=4,
|
||||
background_stroke_width=1,
|
||||
# background_stroke_color=WHITE,
|
||||
insert_line_no=False,
|
||||
background="window",
|
||||
# font="Monospace",
|
||||
style='one-dark',
|
||||
style="one-dark",
|
||||
language="py",
|
||||
)
|
||||
code.scale(0.2)
|
||||
@ -49,27 +49,32 @@ class VAECodeSnippetScene(Scene):
|
||||
return code
|
||||
|
||||
def construct(self):
|
||||
image = Image.open('../../tests/images/image.jpeg')
|
||||
image = Image.open("../../tests/images/image.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
embedding_layer = EmbeddingLayer(dist_theme="ellipse", point_radius=0.04).scale(1.0)
|
||||
embedding_layer = EmbeddingLayer(dist_theme="ellipse", point_radius=0.04).scale(
|
||||
1.0
|
||||
)
|
||||
# Make nn
|
||||
nn = NeuralNetwork([
|
||||
ImageLayer(numpy_image, height=1.0),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
ImageLayer(numpy_image, height=1.0),
|
||||
], layer_spacing=0.1)
|
||||
nn = NeuralNetwork(
|
||||
[
|
||||
ImageLayer(numpy_image, height=1.0),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
ImageLayer(numpy_image, height=1.0),
|
||||
],
|
||||
layer_spacing=0.1,
|
||||
)
|
||||
|
||||
nn.scale(0.65)
|
||||
# Center the nn
|
||||
nn.move_to(ORIGIN)
|
||||
nn.rotate(-PI/2)
|
||||
nn.all_layers[0].image_mobject.rotate(PI/2)
|
||||
nn.rotate(-PI / 2)
|
||||
nn.all_layers[0].image_mobject.rotate(PI / 2)
|
||||
# nn.all_layers[0].image_mobject.shift([0, -0.4, 0])
|
||||
nn.all_layers[-1].image_mobject.rotate(PI/2)
|
||||
nn.all_layers[-1].image_mobject.rotate(PI / 2)
|
||||
# nn.all_layers[-1].image_mobject.shift([0, -0.4, 0])
|
||||
nn.shift([1.5, 0.0, 0])
|
||||
self.add(nn)
|
||||
@ -79,14 +84,11 @@ class VAECodeSnippetScene(Scene):
|
||||
code_snippet.shift([-1.25, 0, 0])
|
||||
self.add(code_snippet)
|
||||
# Play animation
|
||||
self.play(
|
||||
nn.make_forward_pass_animation(),
|
||||
run_time=10
|
||||
)
|
||||
|
||||
self.play(nn.make_forward_pass_animation(), run_time=10)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""Render all scenes"""
|
||||
# Neural Network
|
||||
# Neural Network
|
||||
nn_scene = VAECodeSnippetScene()
|
||||
nn_scene.render()
|
||||
|
@ -23,16 +23,24 @@ def construct_image_mobject(input_image, height=2.3):
|
||||
|
||||
return image_mobject
|
||||
|
||||
class DisentanglementVisualization(VGroup):
|
||||
|
||||
def __init__(self, model_path=ROOT_DIR / "examples/variational_autoencoder/autoencoder_models/saved_models/model_dim2.pth", image_height=0.35):
|
||||
class DisentanglementVisualization(VGroup):
|
||||
def __init__(
|
||||
self,
|
||||
model_path=ROOT_DIR
|
||||
/ "examples/variational_autoencoder/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
|
||||
with open(ROOT_DIR/ "examples/variational_autoencoder/autoencoder_models/disentanglement.pkl", "rb") as f:
|
||||
with open(
|
||||
ROOT_DIR
|
||||
/ "examples/variational_autoencoder/autoencoder_models/disentanglement.pkl",
|
||||
"rb",
|
||||
) as f:
|
||||
self.image_handler = pickle.load(f)
|
||||
|
||||
|
||||
def make_disentanglement_generation_animation(self):
|
||||
animation_list = []
|
||||
for image_index, image in enumerate(self.image_handler["images"]):
|
||||
@ -41,18 +49,24 @@ class DisentanglementVisualization(VGroup):
|
||||
# Move the image to the correct location
|
||||
r_offset = -1.2
|
||||
c_offset = 0.25
|
||||
image_location = [c_offset + c*self.image_height, r_offset + r*self.image_height, 0]
|
||||
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))
|
||||
|
||||
generation_animation = AnimationGroup(*animation_list[::-1], lag_ratio=1.0)
|
||||
return generation_animation
|
||||
|
||||
|
||||
config.pixel_height = 720
|
||||
config.pixel_width = 1280
|
||||
config.frame_height = 5.0
|
||||
config.frame_width = 5.0
|
||||
|
||||
|
||||
class DisentanglementScene(Scene):
|
||||
"""Disentanglement Scene Object"""
|
||||
|
||||
@ -76,7 +90,7 @@ class DisentanglementScene(Scene):
|
||||
self.point_dots = VGroup()
|
||||
for point in points:
|
||||
point_location = embedding.axes.coords_to_point(*point)
|
||||
dot = Dot(point_location, color=point_color, radius=dot_radius/2)
|
||||
dot = Dot(point_location, color=point_color, radius=dot_radius / 2)
|
||||
self.point_dots.add(dot)
|
||||
|
||||
embedding.add(self.point_dots)
|
||||
@ -84,10 +98,13 @@ class DisentanglementScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
# Make the VAE decoder
|
||||
vae_decoder = NeuralNetwork([
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
], layer_spacing=0.55)
|
||||
vae_decoder = NeuralNetwork(
|
||||
[
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
],
|
||||
layer_spacing=0.55,
|
||||
)
|
||||
|
||||
vae_decoder.shift([-0.55, 0, 0])
|
||||
self.play(Create(vae_decoder), run_time=1)
|
||||
@ -99,6 +116,8 @@ class DisentanglementScene(Scene):
|
||||
self.play(Create(embedding))
|
||||
# Make disentanglment visualization
|
||||
disentanglement = DisentanglementVisualization()
|
||||
disentanglement_animation = disentanglement.make_disentanglement_generation_animation()
|
||||
disentanglement_animation = (
|
||||
disentanglement.make_disentanglement_generation_animation()
|
||||
)
|
||||
self.play(disentanglement_animation, run_time=3)
|
||||
self.play(Wait(2))
|
||||
|
@ -13,6 +13,7 @@ config.pixel_width = 1200
|
||||
config.frame_height = 12.0
|
||||
config.frame_width = 12.0
|
||||
|
||||
|
||||
def make_moon_points(num_samples=100, noise=0.1, random_seed=1):
|
||||
"""Make two half moon point shapes"""
|
||||
# Make sure the points are normalized
|
||||
@ -24,17 +25,19 @@ def make_moon_points(num_samples=100, noise=0.1, random_seed=1):
|
||||
|
||||
return X
|
||||
|
||||
|
||||
def make_epsilon_balls(epsilon_value, points, axes, ball_color=RED, opacity=0.0):
|
||||
"""Draws epsilon balls """
|
||||
"""Draws epsilon balls"""
|
||||
balls = []
|
||||
for point in points:
|
||||
ball = Circle(epsilon_value, color=ball_color, fill_opacity=opacity)
|
||||
global_location = axes.coords_to_point(*point)
|
||||
ball.move_to(global_location)
|
||||
balls.append(ball)
|
||||
|
||||
|
||||
return VGroup(*balls)
|
||||
|
||||
|
||||
def make_epsilon_graph(epsilon_value, dots, points, edge_color=ORANGE):
|
||||
"""Makes an epsilon nearest neighbor graph for the given dots"""
|
||||
# First compute the adjacency matrix from the epsilon value and the points
|
||||
@ -46,7 +49,7 @@ def make_epsilon_graph(epsilon_value, dots, points, edge_color=ORANGE):
|
||||
dist = np.linalg.norm(dots[i].get_center() - dots[j].get_center())
|
||||
is_connected = 1 if dist < epsilon_value else 0
|
||||
adjacency_matrix[i, j] = is_connected
|
||||
# Draw a graph based on the adjacency matrix
|
||||
# Draw a graph based on the adjacency matrix
|
||||
edges = []
|
||||
for i in range(num_dots):
|
||||
for j in range(i):
|
||||
@ -56,28 +59,28 @@ def make_epsilon_graph(epsilon_value, dots, points, edge_color=ORANGE):
|
||||
dot_a = dots[i]
|
||||
dot_b = dots[j]
|
||||
edge = Line(
|
||||
dot_a.get_center(),
|
||||
dot_b.get_center(),
|
||||
dot_a.get_center(),
|
||||
dot_b.get_center(),
|
||||
color=edge_color,
|
||||
stroke_width=3
|
||||
stroke_width=3,
|
||||
)
|
||||
edges.append(edge)
|
||||
|
||||
return VGroup(*edges), adjacency_matrix
|
||||
|
||||
|
||||
def perform_spectral_clustering(adjacency_matrix):
|
||||
"""Performs spectral clustering given adjacency matrix"""
|
||||
clustering = SpectralClustering(
|
||||
n_clusters=2,
|
||||
affinity="precomputed",
|
||||
random_state=0
|
||||
n_clusters=2, affinity="precomputed", random_state=0
|
||||
).fit(adjacency_matrix)
|
||||
labels = clustering.labels_
|
||||
|
||||
return labels
|
||||
|
||||
|
||||
def make_color_change_animation(labels, dots, colors=[ORANGE, GREEN]):
|
||||
"""Makes a color change animation """
|
||||
"""Makes a color change animation"""
|
||||
anims = []
|
||||
|
||||
for index in range(len(labels)):
|
||||
@ -86,21 +89,30 @@ def make_color_change_animation(labels, dots, colors=[ORANGE, GREEN]):
|
||||
anims.append(dot.animate.set_color(color))
|
||||
|
||||
return AnimationGroup(*anims, lag_ratio=0.0)
|
||||
|
||||
class EpsilonNearestNeighborScene(Scene):
|
||||
|
||||
def construct(self, num_points=200, dot_radius=0.1,
|
||||
dot_color=BLUE, ball_color=WHITE, noise=0.1, ball_opacity=0.0,
|
||||
random_seed=2):
|
||||
|
||||
class EpsilonNearestNeighborScene(Scene):
|
||||
def construct(
|
||||
self,
|
||||
num_points=200,
|
||||
dot_radius=0.1,
|
||||
dot_color=BLUE,
|
||||
ball_color=WHITE,
|
||||
noise=0.1,
|
||||
ball_opacity=0.0,
|
||||
random_seed=2,
|
||||
):
|
||||
# Make moon shape points
|
||||
# Note: dot is the drawing object and point is the math concept
|
||||
moon_points = make_moon_points(num_samples=num_points, noise=noise, random_seed=random_seed)
|
||||
moon_points = make_moon_points(
|
||||
num_samples=num_points, noise=noise, random_seed=random_seed
|
||||
)
|
||||
# Make an axes
|
||||
axes = Axes(
|
||||
x_range=[-6, 6, 1],
|
||||
y_range=[-6, 6, 1],
|
||||
x_length=12,
|
||||
y_length=12,
|
||||
x_length=12,
|
||||
y_length=12,
|
||||
tips=False,
|
||||
axis_config={"stroke_color": "#000000"},
|
||||
)
|
||||
@ -116,8 +128,10 @@ class EpsilonNearestNeighborScene(Scene):
|
||||
dots = VGroup(*dots)
|
||||
self.play(Create(dots))
|
||||
# Draw epsilon bar with initial value
|
||||
epsilon_bar = NumberLine([0, 2], length=8, stroke_width=2, include_ticks=False, include_numbers=False)
|
||||
epsilon_bar.shift(4.5*DOWN)
|
||||
epsilon_bar = NumberLine(
|
||||
[0, 2], length=8, stroke_width=2, include_ticks=False, include_numbers=False
|
||||
)
|
||||
epsilon_bar.shift(4.5 * DOWN)
|
||||
self.play(Create(epsilon_bar))
|
||||
current_epsilon = ValueTracker(0.3)
|
||||
epsilon_point = epsilon_bar.number_to_point(current_epsilon.get_value())
|
||||
@ -128,7 +142,7 @@ class EpsilonNearestNeighborScene(Scene):
|
||||
label_text = MathTex("\epsilon").scale(1.5)
|
||||
# label_text = Text("Epsilon")
|
||||
label_text.move_to(epsilon_bar.get_center())
|
||||
label_text.shift(DOWN*0.5)
|
||||
label_text.shift(DOWN * 0.5)
|
||||
self.add(label_text)
|
||||
# Make an updater for the dot
|
||||
def dot_updater(epsilon_dot):
|
||||
@ -139,12 +153,17 @@ class EpsilonNearestNeighborScene(Scene):
|
||||
epsilon_dot.add_updater(dot_updater)
|
||||
# Make the epsilon balls
|
||||
epsilon_balls = make_epsilon_balls(
|
||||
current_epsilon.get_value(), moon_points, axes, ball_color=ball_color, opacity=ball_opacity
|
||||
current_epsilon.get_value(),
|
||||
moon_points,
|
||||
axes,
|
||||
ball_color=ball_color,
|
||||
opacity=ball_opacity,
|
||||
)
|
||||
# Set up updater for radius of balls
|
||||
def epsilon_balls_updater(epsilon_balls):
|
||||
for ball in epsilon_balls:
|
||||
ball.set_width(current_epsilon.get_value())
|
||||
|
||||
# Turn epsilon up and down
|
||||
epsilon_balls.add_updater(epsilon_balls_updater)
|
||||
# Fade in the initial balls
|
||||
@ -156,10 +175,7 @@ class EpsilonNearestNeighborScene(Scene):
|
||||
epsilon_value = 0.9
|
||||
# Show connecting graph
|
||||
epsilon_graph, adjacency_matrix = make_epsilon_graph(
|
||||
current_epsilon.get_value(),
|
||||
dots,
|
||||
moon_points,
|
||||
edge_color=WHITE
|
||||
current_epsilon.get_value(), dots, moon_points, edge_color=WHITE
|
||||
)
|
||||
self.play(FadeOut(epsilon_balls))
|
||||
self.play(FadeIn(epsilon_graph))
|
||||
@ -172,4 +188,4 @@ class EpsilonNearestNeighborScene(Scene):
|
||||
self.play(color_change_animation)
|
||||
# Fade out graph edges
|
||||
self.play(FadeOut(epsilon_graph))
|
||||
self.play(Wait(5.0))
|
||||
self.play(Wait(5.0))
|
||||
|
@ -17,9 +17,10 @@ config.pixel_width = 1080
|
||||
config.frame_height = 8.3
|
||||
config.frame_width = 8.3
|
||||
|
||||
|
||||
class GAN(Mobject):
|
||||
"""Generative Adversarial Network"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.make_entities()
|
||||
@ -29,27 +30,35 @@ class GAN(Mobject):
|
||||
def make_entities(self, image_height=1.2):
|
||||
"""Makes all of the network entities"""
|
||||
# Make the fake image layer
|
||||
default_image = Image.open(ROOT_DIR / 'assets/gan/fake_image.png')
|
||||
default_image = Image.open(ROOT_DIR / "assets/gan/fake_image.png")
|
||||
numpy_image = np.asarray(default_image)
|
||||
self.fake_image_layer = ImageLayer(numpy_image, height=image_height, show_image_on_create=False)
|
||||
self.fake_image_layer = ImageLayer(
|
||||
numpy_image, height=image_height, show_image_on_create=False
|
||||
)
|
||||
# Make the Generator Network
|
||||
self.generator = NeuralNetwork([
|
||||
EmbeddingLayer(covariance=np.array([[3.0, 0], [0, 3.0]])).scale(1.3),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
self.fake_image_layer
|
||||
], layer_spacing=0.1)
|
||||
self.generator = NeuralNetwork(
|
||||
[
|
||||
EmbeddingLayer(covariance=np.array([[3.0, 0], [0, 3.0]])).scale(1.3),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
self.fake_image_layer,
|
||||
],
|
||||
layer_spacing=0.1,
|
||||
)
|
||||
|
||||
self.add(self.generator)
|
||||
# Make the Discriminator
|
||||
self.discriminator = NeuralNetwork([
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(1),
|
||||
VectorLayer(1, value_func=lambda: random.uniform(0, 1)),
|
||||
], layer_spacing=0.1)
|
||||
self.discriminator = NeuralNetwork(
|
||||
[
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(1),
|
||||
VectorLayer(1, value_func=lambda: random.uniform(0, 1)),
|
||||
],
|
||||
layer_spacing=0.1,
|
||||
)
|
||||
self.add(self.discriminator)
|
||||
# Make Ground Truth Dataset
|
||||
default_image = Image.open(ROOT_DIR / 'assets/gan/real_image.jpg')
|
||||
default_image = Image.open(ROOT_DIR / "assets/gan/real_image.jpg")
|
||||
numpy_image = np.asarray(default_image)
|
||||
self.ground_truth_layer = ImageLayer(numpy_image, height=image_height)
|
||||
self.add(self.ground_truth_layer)
|
||||
@ -90,7 +99,7 @@ class GAN(Mobject):
|
||||
self.probability_title = Text("Probability").scale(0.5)
|
||||
self.probability_title.move_to(self.discriminator.input_layers[-2])
|
||||
self.probability_title.shift(UP)
|
||||
self.probability_title.shift(RIGHT*1.05)
|
||||
self.probability_title.shift(RIGHT * 1.05)
|
||||
titles.add(self.probability_title)
|
||||
|
||||
return titles
|
||||
@ -99,16 +108,10 @@ class GAN(Mobject):
|
||||
"""Returns animation that highlights the generators contents"""
|
||||
group = VGroup()
|
||||
|
||||
generator_surrounding_group = Group(
|
||||
self.generator,
|
||||
self.fake_image_layer_title
|
||||
)
|
||||
generator_surrounding_group = Group(self.generator, self.fake_image_layer_title)
|
||||
|
||||
generator_surrounding_rectangle = SurroundingRectangle(
|
||||
generator_surrounding_group,
|
||||
buff=0.1,
|
||||
stroke_width=4.0,
|
||||
color="#0FFF50"
|
||||
generator_surrounding_group, buff=0.1, stroke_width=4.0, color="#0FFF50"
|
||||
)
|
||||
group.add(generator_surrounding_rectangle)
|
||||
title = Text("Generator").scale(0.5)
|
||||
@ -124,16 +127,13 @@ class GAN(Mobject):
|
||||
self.fake_image_layer,
|
||||
self.ground_truth_layer,
|
||||
self.fake_image_layer_title,
|
||||
self.probability_title
|
||||
self.probability_title,
|
||||
)
|
||||
|
||||
group = VGroup()
|
||||
|
||||
discriminator_surrounding_rectangle = SurroundingRectangle(
|
||||
discriminator_group,
|
||||
buff=0.05,
|
||||
stroke_width=4.0,
|
||||
color="#0FFF50"
|
||||
discriminator_group, buff=0.05, stroke_width=4.0, color="#0FFF50"
|
||||
)
|
||||
group.add(discriminator_surrounding_rectangle)
|
||||
title = Text("Discriminator").scale(0.5)
|
||||
@ -144,7 +144,7 @@ class GAN(Mobject):
|
||||
|
||||
def make_generator_forward_pass(self):
|
||||
"""Makes forward pass of the generator"""
|
||||
|
||||
|
||||
forward_pass = self.generator.make_forward_pass_animation(dist_theme="ellipse")
|
||||
|
||||
return forward_pass
|
||||
@ -153,7 +153,7 @@ class GAN(Mobject):
|
||||
"""Makes forward pass of the discriminator"""
|
||||
|
||||
disc_forward = self.discriminator.make_forward_pass_animation()
|
||||
|
||||
|
||||
return disc_forward
|
||||
|
||||
@override_animation(Create)
|
||||
@ -163,18 +163,19 @@ class GAN(Mobject):
|
||||
Create(self.generator),
|
||||
Create(self.discriminator),
|
||||
Create(self.ground_truth_layer),
|
||||
Create(self.titles)
|
||||
Create(self.titles),
|
||||
)
|
||||
return animation_group
|
||||
|
||||
|
||||
class GANScene(Scene):
|
||||
"""GAN Scene"""
|
||||
|
||||
def construct(self):
|
||||
gan = GAN().scale(1.70)
|
||||
gan.move_to(ORIGIN)
|
||||
gan.shift(DOWN*0.35)
|
||||
gan.shift(LEFT*0.1)
|
||||
gan.shift(DOWN * 0.35)
|
||||
gan.shift(LEFT * 0.1)
|
||||
self.play(Create(gan), run_time=3)
|
||||
# Highlight generator
|
||||
highlight_generator_rectangle = gan.make_highlight_generator_rectangle()
|
||||
@ -184,11 +185,11 @@ class GANScene(Scene):
|
||||
self.play(gen_forward_pass, run_time=5)
|
||||
# Fade out generator highlight
|
||||
self.play(Uncreate(highlight_generator_rectangle), run_time=1)
|
||||
# Highlight discriminator
|
||||
# Highlight discriminator
|
||||
highlight_discriminator_rectangle = gan.make_highlight_discriminator_rectangle()
|
||||
self.play(Create(highlight_discriminator_rectangle), run_time=1)
|
||||
# Discriminator forward pass
|
||||
discriminator_forward_pass = gan.make_discriminator_forward_pass()
|
||||
self.play(discriminator_forward_pass, run_time=5)
|
||||
# Unhighlight discriminator
|
||||
self.play(Uncreate(highlight_discriminator_rectangle), run_time=1)
|
||||
self.play(Uncreate(highlight_discriminator_rectangle), run_time=1)
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
"""Visualization of VAE Interpolation"""
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.append(os.environ["PROJECT_ROOT"])
|
||||
from manim import *
|
||||
import pickle
|
||||
@ -12,22 +12,25 @@ import examples.variational_autoencoder.variational_autoencoder as variational_a
|
||||
"""
|
||||
The VAE Scene for the twitter video.
|
||||
"""
|
||||
config.pixel_height = 720
|
||||
config.pixel_width = 1280
|
||||
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 = 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)
|
||||
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
|
||||
@ -35,23 +38,22 @@ class InterpolationScene(MovingCameraScene):
|
||||
# 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)
|
||||
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)
|
||||
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
|
||||
forward_pass_animation_group, interpolation_animation
|
||||
)
|
||||
self.play(interpolation_animation, run_time=9.0)
|
||||
|
@ -9,16 +9,18 @@ config.pixel_width = 500
|
||||
config.frame_height = 4.0
|
||||
config.frame_width = 4.0
|
||||
|
||||
class ManimMLLogo(Scene):
|
||||
|
||||
class ManimMLLogo(Scene):
|
||||
def construct(self):
|
||||
self.text = Text("ManimML")
|
||||
self.text.scale(1.0)
|
||||
self.neural_network = FeedForwardNeuralNetwork([3, 5, 3, 6, 3], layer_spacing=0.3, node_color=BLUE)
|
||||
self.neural_network = FeedForwardNeuralNetwork(
|
||||
[3, 5, 3, 6, 3], layer_spacing=0.3, node_color=BLUE
|
||||
)
|
||||
self.neural_network.scale(1.0)
|
||||
self.neural_network.move_to(self.text.get_bottom())
|
||||
self.neural_network.shift(1.25 * DOWN)
|
||||
self.logo_group = Group(self.text, self.neural_network)
|
||||
self.logo_group = Group(self.text, self.neural_network)
|
||||
self.logo_group.scale(1.0)
|
||||
self.logo_group.move_to(ORIGIN)
|
||||
self.play(Write(self.text))
|
||||
@ -28,14 +30,14 @@ class ManimMLLogo(Scene):
|
||||
animation_group = AnimationGroup(
|
||||
self.neural_network.make_forward_pass_animation(run_time=5),
|
||||
Create(underline),
|
||||
# Create(self.surrounding_rectangle)
|
||||
# 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_pass_animation(run_time=5),
|
||||
Create(underline),
|
||||
# Create(self.surrounding_rectangle)
|
||||
# Create(self.surrounding_rectangle)
|
||||
)
|
||||
self.play(animation_group)
|
||||
self.wait(5)
|
||||
|
@ -9,11 +9,12 @@ config.pixel_width = 600
|
||||
config.frame_height = 8.0
|
||||
config.frame_width = 10.0
|
||||
|
||||
class ManimMLLogo(Scene):
|
||||
|
||||
class ManimMLLogo(Scene):
|
||||
def construct(self):
|
||||
self.neural_network = FeedForwardNeuralNetwork([3, 5, 3, 5], layer_spacing=0.6, node_color=BLUE,
|
||||
edge_width=6)
|
||||
self.neural_network = FeedForwardNeuralNetwork(
|
||||
[3, 5, 3, 5], layer_spacing=0.6, node_color=BLUE, edge_width=6
|
||||
)
|
||||
self.neural_network.scale(3)
|
||||
self.neural_network.move_to(ORIGIN)
|
||||
self.play(Create(self.neural_network))
|
||||
|
@ -23,19 +23,20 @@ config.frame_width = 6.0
|
||||
|
||||
ROOT_DIR = Path(__file__).parents[3]
|
||||
|
||||
class Localizer():
|
||||
|
||||
class Localizer:
|
||||
"""
|
||||
Holds the localizer object, which contains the queries, images, etc.
|
||||
needed to represent a localization run.
|
||||
Holds the localizer object, which contains the queries, images, etc.
|
||||
needed to represent a localization run.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, axes):
|
||||
# Set dummy values for these
|
||||
# Set dummy values for these
|
||||
self.index = -1
|
||||
self.axes = axes
|
||||
self.num_queries = 3
|
||||
self.assets_path = ROOT_DIR / "assets/oracle_guidance"
|
||||
self.ground_truth_image_path = self.assets_path / "ground_truth.jpg"
|
||||
self.ground_truth_image_path = self.assets_path / "ground_truth.jpg"
|
||||
self.ground_truth_location = np.array([2, 3])
|
||||
# Prior distribution
|
||||
print("initial gaussian")
|
||||
@ -45,52 +46,61 @@ class Localizer():
|
||||
cov=np.array([[3, 0], [0, 3]]),
|
||||
dist_theme="ellipse",
|
||||
color=GREEN,
|
||||
)
|
||||
)
|
||||
# Define the query images and embedded locations
|
||||
# Contains image paths [(positive_path, negative_path), ...]
|
||||
self.query_image_paths = [
|
||||
(os.path.join(self.assets_path, "positive_1.jpg"), os.path.join(self.assets_path, "negative_1.jpg")),
|
||||
(os.path.join(self.assets_path, "positive_2.jpg"), os.path.join(self.assets_path, "negative_2.jpg")),
|
||||
(os.path.join(self.assets_path, "positive_3.jpg"), os.path.join(self.assets_path, "negative_3.jpg")),
|
||||
]
|
||||
(
|
||||
os.path.join(self.assets_path, "positive_1.jpg"),
|
||||
os.path.join(self.assets_path, "negative_1.jpg"),
|
||||
),
|
||||
(
|
||||
os.path.join(self.assets_path, "positive_2.jpg"),
|
||||
os.path.join(self.assets_path, "negative_2.jpg"),
|
||||
),
|
||||
(
|
||||
os.path.join(self.assets_path, "positive_3.jpg"),
|
||||
os.path.join(self.assets_path, "negative_3.jpg"),
|
||||
),
|
||||
]
|
||||
# Contains 2D locations for each image [([2, 3], [2, 4]), ...]
|
||||
self.query_locations = [
|
||||
(np.array([-1, -1]), np.array([1, 1])),
|
||||
(np.array([1, -1]), np.array([-1, 1])),
|
||||
(np.array([1, -1]), np.array([-1, 1])),
|
||||
(np.array([0.3, -0.6]), np.array([-0.5, 0.7])),
|
||||
]
|
||||
]
|
||||
# Make the covariances for each query
|
||||
self.query_covariances = [
|
||||
(np.array([[0.3, 0], [0.0, 0.2]]), np.array([[0.2, 0], [0.0, 0.2]])),
|
||||
(np.array([[0.2, 0], [0.0, 0.2]]), np.array([[0.2, 0], [0.0, 0.2]])),
|
||||
(np.array([[0.2, 0], [0.0, 0.2]]), np.array([[0.2, 0], [0.0, 0.2]])),
|
||||
]
|
||||
(np.array([[0.2, 0], [0.0, 0.2]]), np.array([[0.2, 0], [0.0, 0.2]])),
|
||||
]
|
||||
# Posterior distributions over time GaussianDistribution objects
|
||||
self.posterior_distributions = [
|
||||
GaussianDistribution(
|
||||
self.axes,
|
||||
dist_theme="ellipse",
|
||||
self.axes,
|
||||
dist_theme="ellipse",
|
||||
color=GREEN,
|
||||
mean=np.array([-0.3, -0.3]),
|
||||
cov=np.array([[5, -4], [-4, 6]])
|
||||
cov=np.array([[5, -4], [-4, 6]]),
|
||||
).scale(0.6),
|
||||
GaussianDistribution(
|
||||
self.axes,
|
||||
dist_theme="ellipse",
|
||||
self.axes,
|
||||
dist_theme="ellipse",
|
||||
color=GREEN,
|
||||
mean=np.array([0.25, -0.25]),
|
||||
cov=np.array([[3, -2], [-2, 4]])
|
||||
cov=np.array([[3, -2], [-2, 4]]),
|
||||
).scale(0.35),
|
||||
GaussianDistribution(
|
||||
self.axes,
|
||||
dist_theme="ellipse",
|
||||
self.axes,
|
||||
dist_theme="ellipse",
|
||||
color=GREEN,
|
||||
mean=np.array([0.4, -0.35]),
|
||||
cov=np.array([[1, 0], [0, 1]])
|
||||
cov=np.array([[1, 0], [0, 1]]),
|
||||
).scale(0.3),
|
||||
]
|
||||
# Some assumptions
|
||||
assert len(self.query_locations) == len(self.query_image_paths)
|
||||
assert len(self.query_locations) == len(self.query_image_paths)
|
||||
assert len(self.query_locations) == len(self.posterior_distributions)
|
||||
|
||||
def __iter__(self):
|
||||
@ -105,16 +115,16 @@ class Localizer():
|
||||
|
||||
# Return query_paths, query_locations, posterior
|
||||
out_tuple = (
|
||||
self.query_image_paths[self.index],
|
||||
self.query_locations[self.index],
|
||||
self.query_image_paths[self.index],
|
||||
self.query_locations[self.index],
|
||||
self.posterior_distributions[self.index],
|
||||
self.query_covariances[self.index]
|
||||
self.query_covariances[self.index],
|
||||
)
|
||||
|
||||
return out_tuple
|
||||
|
||||
class OracleGuidanceVisualization(Scene):
|
||||
|
||||
class OracleGuidanceVisualization(Scene):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.neural_network, self.embedding_layer = self.make_vae()
|
||||
@ -125,36 +135,37 @@ class OracleGuidanceVisualization(Scene):
|
||||
# VAE embedding animation image paths
|
||||
self.assets_path = ROOT_DIR / "assets/oracle_guidance"
|
||||
self.input_embed_image_path = os.path.join(self.assets_path, "input_image.jpg")
|
||||
self.output_embed_image_path = os.path.join(self.assets_path, "output_image.jpg")
|
||||
self.output_embed_image_path = os.path.join(
|
||||
self.assets_path, "output_image.jpg"
|
||||
)
|
||||
|
||||
def make_vae(self):
|
||||
"""Makes a simple VAE architecture"""
|
||||
embedding_layer = EmbeddingLayer(dist_theme="ellipse")
|
||||
self.encoder = NeuralNetwork([
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
])
|
||||
self.encoder = NeuralNetwork(
|
||||
[
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
]
|
||||
)
|
||||
|
||||
self.decoder = NeuralNetwork([
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
])
|
||||
self.decoder = NeuralNetwork(
|
||||
[
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
]
|
||||
)
|
||||
|
||||
neural_network = NeuralNetwork([
|
||||
self.encoder,
|
||||
self.decoder
|
||||
])
|
||||
neural_network = NeuralNetwork([self.encoder, self.decoder])
|
||||
|
||||
neural_network.shift(DOWN*0.4)
|
||||
neural_network.shift(DOWN * 0.4)
|
||||
return neural_network, embedding_layer
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_animation(self):
|
||||
animation_group = AnimationGroup(
|
||||
Create(self.neural_network)
|
||||
)
|
||||
|
||||
animation_group = AnimationGroup(Create(self.neural_network))
|
||||
|
||||
return animation_group
|
||||
|
||||
def insert_at_start(self, layer, create=True):
|
||||
@ -168,20 +179,14 @@ class OracleGuidanceVisualization(Scene):
|
||||
self.encoder.all_layers.insert(1, connective_layer)
|
||||
# Move layers to the correct location
|
||||
# TODO: Fix this cause its hacky
|
||||
layer.shift(DOWN*0.4)
|
||||
layer.shift(LEFT*2.35)
|
||||
layer.shift(DOWN * 0.4)
|
||||
layer.shift(LEFT * 2.35)
|
||||
# Make insert animation
|
||||
if not create:
|
||||
animation_group = AnimationGroup(
|
||||
Create(connective_layer)
|
||||
)
|
||||
animation_group = AnimationGroup(Create(connective_layer))
|
||||
else:
|
||||
animation_group = AnimationGroup(
|
||||
Create(layer),
|
||||
Create(connective_layer)
|
||||
)
|
||||
animation_group = AnimationGroup(Create(layer), Create(connective_layer))
|
||||
self.play(animation_group)
|
||||
|
||||
|
||||
def remove_start_layer(self):
|
||||
"""Removes the first layer of the network"""
|
||||
@ -189,8 +194,7 @@ class OracleGuidanceVisualization(Scene):
|
||||
first_connective = self.encoder.all_layers.remove_at_index(0)
|
||||
# Make remove animations
|
||||
animation_group = AnimationGroup(
|
||||
FadeOut(first_layer),
|
||||
FadeOut(first_connective)
|
||||
FadeOut(first_layer), FadeOut(first_connective)
|
||||
)
|
||||
|
||||
self.play(animation_group)
|
||||
@ -205,13 +209,10 @@ class OracleGuidanceVisualization(Scene):
|
||||
self.decoder.all_layers.add(layer)
|
||||
# Move layers to the correct location
|
||||
# TODO: Fix this cause its hacky
|
||||
layer.shift(DOWN*0.4)
|
||||
layer.shift(RIGHT*2.35)
|
||||
layer.shift(DOWN * 0.4)
|
||||
layer.shift(RIGHT * 2.35)
|
||||
# Make insert animation
|
||||
animation_group = AnimationGroup(
|
||||
Create(layer),
|
||||
Create(connective_layer)
|
||||
)
|
||||
animation_group = AnimationGroup(Create(layer), Create(connective_layer))
|
||||
self.play(animation_group)
|
||||
|
||||
def remove_end_layer(self):
|
||||
@ -220,8 +221,7 @@ class OracleGuidanceVisualization(Scene):
|
||||
first_connective = self.decoder.all_layers.remove_at_index(-1)
|
||||
# Make remove animations
|
||||
animation_group = AnimationGroup(
|
||||
FadeOut(first_layer),
|
||||
FadeOut(first_connective)
|
||||
FadeOut(first_layer), FadeOut(first_connective)
|
||||
)
|
||||
|
||||
self.play(animation_group)
|
||||
@ -271,19 +271,18 @@ class OracleGuidanceVisualization(Scene):
|
||||
self.encoder.all_layers.insert(1, connective_layer)
|
||||
# Move layers to the correct location
|
||||
# TODO: Fix this cause its hacky
|
||||
input_image_layer.shift(DOWN*0.4)
|
||||
input_image_layer.shift(LEFT*2.35)
|
||||
input_image_layer.shift(DOWN * 0.4)
|
||||
input_image_layer.shift(LEFT * 2.35)
|
||||
# Play full forward pass
|
||||
forward_pass = self.neural_network.make_forward_pass_animation(
|
||||
layer_args=
|
||||
{
|
||||
layer_args={
|
||||
self.encoder: {
|
||||
self.embedding_layer: {
|
||||
"dist_args": {
|
||||
"cov": np.array([[1.5, 0], [0, 1.5]]),
|
||||
"mean": np.array([0.5, 0.5]),
|
||||
"dist_theme": "ellipse",
|
||||
"color": ORANGE
|
||||
"color": ORANGE,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -302,14 +301,14 @@ class OracleGuidanceVisualization(Scene):
|
||||
|
||||
def make_localization_time_step(self, old_posterior):
|
||||
"""
|
||||
Performs one query update for the localization procedure
|
||||
|
||||
Procedure:
|
||||
a. Embed query input images
|
||||
b. Oracle is asked a query
|
||||
c. Query is embedded
|
||||
d. Show posterior update
|
||||
e. Show current recomendation
|
||||
Performs one query update for the localization procedure
|
||||
|
||||
Procedure:
|
||||
a. Embed query input images
|
||||
b. Oracle is asked a query
|
||||
c. Query is embedded
|
||||
d. Show posterior update
|
||||
e. Show current recomendation
|
||||
"""
|
||||
# Helper functions
|
||||
def embed_query_to_latent_space(query_locations, query_covariance):
|
||||
@ -331,41 +330,42 @@ class OracleGuidanceVisualization(Scene):
|
||||
"cov": query_covariance[0],
|
||||
"mean": query_locations[0],
|
||||
"dist_theme": "ellipse",
|
||||
"color": BLUE
|
||||
"color": BLUE,
|
||||
},
|
||||
"negative_dist_args": {
|
||||
"cov": query_covariance[1],
|
||||
"mean": query_locations[1],
|
||||
"dist_theme": "ellipse",
|
||||
"color": RED
|
||||
}
|
||||
"color": RED,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
self.play(embed_query_animation)
|
||||
|
||||
# Access localizer information
|
||||
query_paths, query_locations, posterior_distribution, query_covariances = next(self.localizer)
|
||||
query_paths, query_locations, posterior_distribution, query_covariances = next(
|
||||
self.localizer
|
||||
)
|
||||
positive_path, negative_path = query_paths
|
||||
# Make subtitle for present user with query
|
||||
self.change_subtitle("2. Present User with Query")
|
||||
# Insert the layer into the encoder
|
||||
query_layer = PairedQueryLayer.from_paths(positive_path, negative_path, grayscale=False)
|
||||
query_layer = PairedQueryLayer.from_paths(
|
||||
positive_path, negative_path, grayscale=False
|
||||
)
|
||||
query_layer.scale(0.5)
|
||||
self.insert_at_start(query_layer)
|
||||
# Embed query to latent space
|
||||
query_to_latent_space_animation = embed_query_to_latent_space(
|
||||
query_locations,
|
||||
query_covariances
|
||||
query_locations, query_covariances
|
||||
)
|
||||
# Wait
|
||||
self.play(Wait(1))
|
||||
# Update the posterior
|
||||
self.change_subtitle("4. Update the Posterior")
|
||||
# Remove the old posterior
|
||||
self.play(
|
||||
ReplacementTransform(old_posterior, posterior_distribution)
|
||||
)
|
||||
self.play(ReplacementTransform(old_posterior, posterior_distribution))
|
||||
"""
|
||||
self.play(
|
||||
self.embedding_layer.remove_gaussian_distribution(self.localizer.posterior_distribution)
|
||||
@ -376,12 +376,12 @@ class OracleGuidanceVisualization(Scene):
|
||||
# Remove query layer
|
||||
self.remove_start_layer()
|
||||
# Remove query ellipses
|
||||
|
||||
|
||||
fade_outs = []
|
||||
for dist in self.embedding_layer.gaussian_distributions:
|
||||
self.embedding_layer.gaussian_distributions.remove(dist)
|
||||
fade_outs.append(FadeOut(dist))
|
||||
|
||||
|
||||
if not len(fade_outs) == 0:
|
||||
fade_outs = AnimationGroup(*fade_outs)
|
||||
self.play(fade_outs)
|
||||
@ -408,14 +408,21 @@ class OracleGuidanceVisualization(Scene):
|
||||
# Remove the image at the end
|
||||
print(self.neural_network)
|
||||
self.remove_end_layer()
|
||||
|
||||
|
||||
def make_triplet_forward_animation(self):
|
||||
"""Make triplet forward animation"""
|
||||
# Make triplet layer
|
||||
anchor_path = os.path.join(self.assets_path, "anchor.jpg")
|
||||
positive_path = os.path.join(self.assets_path, "positive.jpg")
|
||||
negative_path = os.path.join(self.assets_path, "negative.jpg")
|
||||
triplet_layer = TripletLayer.from_paths(anchor_path, positive_path, negative_path, grayscale=False, font_size=100, buff=1.05)
|
||||
triplet_layer = TripletLayer.from_paths(
|
||||
anchor_path,
|
||||
positive_path,
|
||||
negative_path,
|
||||
grayscale=False,
|
||||
font_size=100,
|
||||
buff=1.05,
|
||||
)
|
||||
triplet_layer.scale(0.10)
|
||||
self.insert_at_start(triplet_layer)
|
||||
# Make latent triplet animation
|
||||
@ -428,35 +435,35 @@ class OracleGuidanceVisualization(Scene):
|
||||
"cov": np.array([[0.3, 0], [0, 0.3]]),
|
||||
"mean": np.array([0.7, 1.4]),
|
||||
"dist_theme": "ellipse",
|
||||
"color": BLUE
|
||||
"color": BLUE,
|
||||
},
|
||||
"positive_dist": {
|
||||
"cov": np.array([[0.2, 0], [0, 0.2]]),
|
||||
"mean": np.array([0.8, -0.4]),
|
||||
"dist_theme": "ellipse",
|
||||
"color": GREEN
|
||||
"color": GREEN,
|
||||
},
|
||||
"negative_dist": {
|
||||
"cov": np.array([[0.4, 0], [0, 0.25]]),
|
||||
"mean": np.array([-1, -1.2]),
|
||||
"dist_theme": "ellipse",
|
||||
"color": RED
|
||||
}
|
||||
"color": RED,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
run_time=3
|
||||
run_time=3,
|
||||
)
|
||||
)
|
||||
|
||||
def construct(self):
|
||||
"""
|
||||
Makes the whole visualization.
|
||||
Makes the whole visualization.
|
||||
|
||||
1. Create the Architecture
|
||||
a. Create the traditional VAE architecture with images
|
||||
2. The Localization Procedure
|
||||
3. The Training Procedure
|
||||
1. Create the Architecture
|
||||
a. Create the traditional VAE architecture with images
|
||||
2. The Localization Procedure
|
||||
3. The Training Procedure
|
||||
"""
|
||||
# 1. Create the Architecture
|
||||
self.neural_network.scale(1.2)
|
||||
@ -482,7 +489,7 @@ class OracleGuidanceVisualization(Scene):
|
||||
self.play(Wait(1))
|
||||
if not query_index == self.localizer.num_queries - 1:
|
||||
# Repeat
|
||||
self.change_subtitle("5. Repeat")
|
||||
self.change_subtitle("5. Repeat")
|
||||
# Wait a second
|
||||
self.play(Wait(1))
|
||||
# Generate final estimate
|
||||
@ -499,8 +506,7 @@ class OracleGuidanceVisualization(Scene):
|
||||
# Do an Image forward pass
|
||||
self.change_subtitle("1. Unsupervised Image Reconstruction")
|
||||
self.make_embed_input_image_animation(
|
||||
self.input_embed_image_path,
|
||||
self.output_embed_image_path
|
||||
self.input_embed_image_path, self.output_embed_image_path
|
||||
)
|
||||
self.wait(1)
|
||||
# Do triplet forward pass
|
||||
|
@ -1,8 +1,13 @@
|
||||
import pickle
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.append(os.environ["PROJECT_ROOT"])
|
||||
from autoencoder_models.variational_autoencoder import VAE, load_dataset, load_vae_from_path
|
||||
from autoencoder_models.variational_autoencoder import (
|
||||
VAE,
|
||||
load_dataset,
|
||||
load_vae_from_path,
|
||||
)
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import torch
|
||||
@ -10,6 +15,7 @@ import scipy
|
||||
import scipy.stats
|
||||
import cv2
|
||||
|
||||
|
||||
def binned_images(model_path, num_x_bins=6, plot=False):
|
||||
latent_dim = 2
|
||||
model = load_vae_from_path(model_path, latent_dim)
|
||||
@ -30,8 +36,8 @@ def binned_images(model_path, num_x_bins=6, plot=False):
|
||||
embedding.append(mean)
|
||||
images = np.stack(images)
|
||||
tsne_points = np.array(embedding)
|
||||
tsne_points = (tsne_points - tsne_points.mean(axis=0))/(tsne_points.std(axis=0))
|
||||
# make vis
|
||||
tsne_points = (tsne_points - tsne_points.mean(axis=0)) / (tsne_points.std(axis=0))
|
||||
# make vis
|
||||
num_points = np.shape(tsne_points)[0]
|
||||
x_min = np.amin(tsne_points.T[0])
|
||||
y_min = np.amin(tsne_points.T[1])
|
||||
@ -41,11 +47,17 @@ def binned_images(model_path, num_x_bins=6, plot=False):
|
||||
# to keep it square the same width is used for x and y dim
|
||||
x_bins, step = np.linspace(x_min, x_max, num_x_bins, retstep=True)
|
||||
x_bins = x_bins.astype(float)
|
||||
num_y_bins = np.absolute(np.ceil((y_max - y_min)/step)).astype(int)
|
||||
num_y_bins = np.absolute(np.ceil((y_max - y_min) / step)).astype(int)
|
||||
y_bins = np.linspace(y_min, y_max, num_y_bins)
|
||||
# sort the tsne_points into a 2d histogram
|
||||
tsne_points = tsne_points.squeeze()
|
||||
hist_obj = scipy.stats.binned_statistic_dd(tsne_points, np.arange(num_points), statistic='count', bins=[x_bins, y_bins], expand_binnumbers=True)
|
||||
hist_obj = scipy.stats.binned_statistic_dd(
|
||||
tsne_points,
|
||||
np.arange(num_points),
|
||||
statistic="count",
|
||||
bins=[x_bins, y_bins],
|
||||
expand_binnumbers=True,
|
||||
)
|
||||
# sample one point from each bucket
|
||||
binnumbers = hist_obj.binnumber
|
||||
num_x_bins = np.amax(binnumbers[0]) + 1
|
||||
@ -53,30 +65,38 @@ def binned_images(model_path, num_x_bins=6, plot=False):
|
||||
binnumbers = binnumbers.T
|
||||
# some places have no value in a region
|
||||
used_mask = np.zeros((num_y_bins, num_x_bins))
|
||||
image_bins = np.zeros((num_y_bins, num_x_bins, 3, np.shape(images)[2], np.shape(images)[2]))
|
||||
image_bins = np.zeros(
|
||||
(num_y_bins, num_x_bins, 3, np.shape(images)[2], np.shape(images)[2])
|
||||
)
|
||||
for i, bin_num in enumerate(list(binnumbers)):
|
||||
used_mask[bin_num[1], bin_num[0]] = 1
|
||||
image_bins[bin_num[1], bin_num[0]] = images[i]
|
||||
# plot a grid of the images
|
||||
fig, axs = plt.subplots(nrows=np.shape(y_bins)[0], ncols=np.shape(x_bins)[0], constrained_layout=False, dpi=50)
|
||||
fig, axs = plt.subplots(
|
||||
nrows=np.shape(y_bins)[0],
|
||||
ncols=np.shape(x_bins)[0],
|
||||
constrained_layout=False,
|
||||
dpi=50,
|
||||
)
|
||||
images = []
|
||||
bin_indices = []
|
||||
for y in range(num_y_bins):
|
||||
for x in range(num_x_bins):
|
||||
if used_mask[y, x] > 0.0:
|
||||
image = np.uint8(image_bins[y][x].squeeze()*255)
|
||||
image = np.uint8(image_bins[y][x].squeeze() * 255)
|
||||
image = np.rollaxis(image, 0, 3)
|
||||
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
||||
axs[num_y_bins - 1 - y][x].imshow(image)
|
||||
images.append(image)
|
||||
bin_indices.append((y, x))
|
||||
axs[y, x].axis('off')
|
||||
axs[y, x].axis("off")
|
||||
if plot:
|
||||
plt.axis('off')
|
||||
plt.axis("off")
|
||||
plt.show()
|
||||
else:
|
||||
return images, bin_indices
|
||||
|
||||
|
||||
def generate_disentanglement(model_path="saved_models/model_dim2.pth"):
|
||||
"""Generates disentanglement visualization and serializes it"""
|
||||
# Disentanglement object
|
||||
@ -89,11 +109,12 @@ def generate_disentanglement(model_path="saved_models/model_dim2.pth"):
|
||||
with open("disentanglement.pkl", "wb") as f:
|
||||
pickle.dump(disentanglement_object, f)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
plot = False
|
||||
if plot:
|
||||
model_path = "saved_models/model_dim2.pth"
|
||||
#uniform_image_sample(model_path)
|
||||
# uniform_image_sample(model_path)
|
||||
binned_images(model_path)
|
||||
else:
|
||||
generate_disentanglement()
|
||||
generate_disentanglement()
|
||||
|
@ -13,17 +13,16 @@ vae.load_state_dict(torch.load("saved_models/model.pth"))
|
||||
# Transforms images to a PyTorch Tensor
|
||||
tensor_transform = transforms.ToTensor()
|
||||
# Download the MNIST Dataset
|
||||
dataset = datasets.MNIST(root = "./data",
|
||||
train = True,
|
||||
download = True,
|
||||
transform = tensor_transform)
|
||||
dataset = datasets.MNIST(
|
||||
root="./data", train=True, download=True, transform=tensor_transform
|
||||
)
|
||||
# Generate reconstructions
|
||||
num_recons = 10
|
||||
fig, axs = plt.subplots(num_recons, 2, figsize=(2, num_recons))
|
||||
image_pairs = []
|
||||
for i in range(num_recons):
|
||||
base_image, _ = dataset[i]
|
||||
base_image = base_image.reshape(-1, 28*28)
|
||||
base_image = base_image.reshape(-1, 28 * 28)
|
||||
_, _, recon_image, _ = vae.forward(base_image)
|
||||
base_image = base_image.detach().numpy()
|
||||
base_image = np.reshape(base_image, (28, 28)) * 255
|
||||
|
@ -14,12 +14,12 @@ dataset = load_dataset()
|
||||
# Generate reconstructions
|
||||
num_images = 50
|
||||
image_pairs = []
|
||||
save_object = {"interpolation_path":[], "interpolation_images":[]}
|
||||
save_object = {"interpolation_path": [], "interpolation_images": []}
|
||||
|
||||
# Make interpolation path
|
||||
image_a, image_b = dataset[0][0], dataset[1][0]
|
||||
image_a = image_a.view(32*32)
|
||||
image_b = image_b.view(32*32)
|
||||
image_a = image_a.view(32 * 32)
|
||||
image_b = image_b.view(32 * 32)
|
||||
z_a, _, _, _ = vae.forward(image_a)
|
||||
z_a = z_a.detach().cpu().numpy()
|
||||
z_b, _, _, _ = vae.forward(image_b)
|
||||
@ -29,7 +29,7 @@ interpolation_path = np.linspace(z_a, z_b, num=num_images)
|
||||
save_object["interpolation_path"] = interpolation_path
|
||||
|
||||
for i in range(num_images):
|
||||
# Generate
|
||||
# Generate
|
||||
z = torch.Tensor(interpolation_path[i]).unsqueeze(0)
|
||||
gen_image = vae.decode(z).detach().numpy()
|
||||
gen_image = np.reshape(gen_image, (32, 32)) * 255
|
||||
@ -46,4 +46,4 @@ for i in range(num_images):
|
||||
with open("interpolations.pkl", "wb") as f:
|
||||
pickle.dump(save_object, f)
|
||||
|
||||
plt.show()
|
||||
plt.show()
|
||||
|
@ -12,59 +12,137 @@ import math
|
||||
sizes of convolutional neural networks
|
||||
"""
|
||||
|
||||
|
||||
def num2tuple(num):
|
||||
return num if isinstance(num, tuple) else (num, num)
|
||||
|
||||
|
||||
def conv2d_output_shape(h_w, kernel_size=1, stride=1, pad=0, dilation=1):
|
||||
h_w, kernel_size, stride, pad, dilation = num2tuple(h_w), \
|
||||
num2tuple(kernel_size), num2tuple(stride), num2tuple(pad), num2tuple(dilation)
|
||||
h_w, kernel_size, stride, pad, dilation = (
|
||||
num2tuple(h_w),
|
||||
num2tuple(kernel_size),
|
||||
num2tuple(stride),
|
||||
num2tuple(pad),
|
||||
num2tuple(dilation),
|
||||
)
|
||||
pad = num2tuple(pad[0]), num2tuple(pad[1])
|
||||
|
||||
h = math.floor((h_w[0] + sum(pad[0]) - dilation[0]*(kernel_size[0]-1) - 1) / stride[0] + 1)
|
||||
w = math.floor((h_w[1] + sum(pad[1]) - dilation[1]*(kernel_size[1]-1) - 1) / stride[1] + 1)
|
||||
|
||||
|
||||
h = math.floor(
|
||||
(h_w[0] + sum(pad[0]) - dilation[0] * (kernel_size[0] - 1) - 1) / stride[0] + 1
|
||||
)
|
||||
w = math.floor(
|
||||
(h_w[1] + sum(pad[1]) - dilation[1] * (kernel_size[1] - 1) - 1) / stride[1] + 1
|
||||
)
|
||||
|
||||
return h, w
|
||||
|
||||
def convtransp2d_output_shape(h_w, kernel_size=1, stride=1, pad=0, dilation=1, out_pad=0):
|
||||
h_w, kernel_size, stride, pad, dilation, out_pad = num2tuple(h_w), \
|
||||
num2tuple(kernel_size), num2tuple(stride), num2tuple(pad), num2tuple(dilation), num2tuple(out_pad)
|
||||
|
||||
def convtransp2d_output_shape(
|
||||
h_w, kernel_size=1, stride=1, pad=0, dilation=1, out_pad=0
|
||||
):
|
||||
h_w, kernel_size, stride, pad, dilation, out_pad = (
|
||||
num2tuple(h_w),
|
||||
num2tuple(kernel_size),
|
||||
num2tuple(stride),
|
||||
num2tuple(pad),
|
||||
num2tuple(dilation),
|
||||
num2tuple(out_pad),
|
||||
)
|
||||
pad = num2tuple(pad[0]), num2tuple(pad[1])
|
||||
|
||||
h = (h_w[0] - 1)*stride[0] - sum(pad[0]) + dialation[0]*(kernel_size[0]-1) + out_pad[0] + 1
|
||||
w = (h_w[1] - 1)*stride[1] - sum(pad[1]) + dialation[1]*(kernel_size[1]-1) + out_pad[1] + 1
|
||||
|
||||
|
||||
h = (
|
||||
(h_w[0] - 1) * stride[0]
|
||||
- sum(pad[0])
|
||||
+ dialation[0] * (kernel_size[0] - 1)
|
||||
+ out_pad[0]
|
||||
+ 1
|
||||
)
|
||||
w = (
|
||||
(h_w[1] - 1) * stride[1]
|
||||
- sum(pad[1])
|
||||
+ dialation[1] * (kernel_size[1] - 1)
|
||||
+ out_pad[1]
|
||||
+ 1
|
||||
)
|
||||
|
||||
return h, w
|
||||
|
||||
|
||||
def conv2d_get_padding(h_w_in, h_w_out, kernel_size=1, stride=1, dilation=1):
|
||||
h_w_in, h_w_out, kernel_size, stride, dilation = num2tuple(h_w_in), num2tuple(h_w_out), \
|
||||
num2tuple(kernel_size), num2tuple(stride), num2tuple(dilation)
|
||||
|
||||
p_h = ((h_w_out[0] - 1)*stride[0] - h_w_in[0] + dilation[0]*(kernel_size[0]-1) + 1)
|
||||
p_w = ((h_w_out[1] - 1)*stride[1] - h_w_in[1] + dilation[1]*(kernel_size[1]-1) + 1)
|
||||
|
||||
return (math.floor(p_h/2), math.ceil(p_h/2)), (math.floor(p_w/2), math.ceil(p_w/2))
|
||||
h_w_in, h_w_out, kernel_size, stride, dilation = (
|
||||
num2tuple(h_w_in),
|
||||
num2tuple(h_w_out),
|
||||
num2tuple(kernel_size),
|
||||
num2tuple(stride),
|
||||
num2tuple(dilation),
|
||||
)
|
||||
|
||||
p_h = (
|
||||
(h_w_out[0] - 1) * stride[0]
|
||||
- h_w_in[0]
|
||||
+ dilation[0] * (kernel_size[0] - 1)
|
||||
+ 1
|
||||
)
|
||||
p_w = (
|
||||
(h_w_out[1] - 1) * stride[1]
|
||||
- h_w_in[1]
|
||||
+ dilation[1] * (kernel_size[1] - 1)
|
||||
+ 1
|
||||
)
|
||||
|
||||
return (math.floor(p_h / 2), math.ceil(p_h / 2)), (
|
||||
math.floor(p_w / 2),
|
||||
math.ceil(p_w / 2),
|
||||
)
|
||||
|
||||
|
||||
def convtransp2d_get_padding(
|
||||
h_w_in, h_w_out, kernel_size=1, stride=1, dilation=1, out_pad=0
|
||||
):
|
||||
h_w_in, h_w_out, kernel_size, stride, dilation, out_pad = (
|
||||
num2tuple(h_w_in),
|
||||
num2tuple(h_w_out),
|
||||
num2tuple(kernel_size),
|
||||
num2tuple(stride),
|
||||
num2tuple(dilation),
|
||||
num2tuple(out_pad),
|
||||
)
|
||||
|
||||
p_h = (
|
||||
-(
|
||||
h_w_out[0]
|
||||
- 1
|
||||
- out_pad[0]
|
||||
- dilation[0] * (kernel_size[0] - 1)
|
||||
- (h_w_in[0] - 1) * stride[0]
|
||||
)
|
||||
/ 2
|
||||
)
|
||||
p_w = (
|
||||
-(
|
||||
h_w_out[1]
|
||||
- 1
|
||||
- out_pad[1]
|
||||
- dilation[1] * (kernel_size[1] - 1)
|
||||
- (h_w_in[1] - 1) * stride[1]
|
||||
)
|
||||
/ 2
|
||||
)
|
||||
|
||||
return (math.floor(p_h / 2), math.ceil(p_h / 2)), (
|
||||
math.floor(p_w / 2),
|
||||
math.ceil(p_w / 2),
|
||||
)
|
||||
|
||||
def convtransp2d_get_padding(h_w_in, h_w_out, kernel_size=1, stride=1, dilation=1, out_pad=0):
|
||||
h_w_in, h_w_out, kernel_size, stride, dilation, out_pad = num2tuple(h_w_in), num2tuple(h_w_out), \
|
||||
num2tuple(kernel_size), num2tuple(stride), num2tuple(dilation), num2tuple(out_pad)
|
||||
|
||||
p_h = -(h_w_out[0] - 1 - out_pad[0] - dilation[0]*(kernel_size[0]-1) - (h_w_in[0] - 1)*stride[0]) / 2
|
||||
p_w = -(h_w_out[1] - 1 - out_pad[1] - dilation[1]*(kernel_size[1]-1) - (h_w_in[1] - 1)*stride[1]) / 2
|
||||
|
||||
return (math.floor(p_h/2), math.ceil(p_h/2)), (math.floor(p_w/2), math.ceil(p_w/2))
|
||||
|
||||
def load_dataset(train=True, digit=None):
|
||||
# Transforms images to a PyTorch Tensor
|
||||
tensor_transform = transforms.Compose([
|
||||
transforms.Pad(2),
|
||||
transforms.ToTensor()
|
||||
])
|
||||
|
||||
tensor_transform = transforms.Compose([transforms.Pad(2), transforms.ToTensor()])
|
||||
|
||||
# Download the MNIST Dataset
|
||||
dataset = datasets.MNIST(root = "./data",
|
||||
train = train,
|
||||
download = True,
|
||||
transform = tensor_transform)
|
||||
dataset = datasets.MNIST(
|
||||
root="./data", train=train, download=True, transform=tensor_transform
|
||||
)
|
||||
# Load specific image
|
||||
if not digit is None:
|
||||
idx = dataset.train_labels == digit
|
||||
@ -73,12 +151,14 @@ def load_dataset(train=True, digit=None):
|
||||
|
||||
return dataset
|
||||
|
||||
|
||||
def load_vae_from_path(path, latent_dim):
|
||||
model = VAE(latent_dim)
|
||||
model.load_state_dict(torch.load(path))
|
||||
|
||||
|
||||
return model
|
||||
|
||||
|
||||
# Creating a PyTorch class
|
||||
# 28*28 ==> 9 ==> 28*28
|
||||
class VAE(torch.nn.Module):
|
||||
@ -96,13 +176,15 @@ class VAE(torch.nn.Module):
|
||||
setattr(self, "conv%d" % (i + 1), nn.Conv2d(inputs, self.d * mul, 4, 2, 1))
|
||||
setattr(self, "conv%d_bn" % (i + 1), nn.BatchNorm2d(self.d * mul))
|
||||
h_w = (out_sizes[-1][-1], out_sizes[-1][-1])
|
||||
out_sizes.append(conv2d_output_shape(h_w, kernel_size=4, stride=2, pad=1, dilation=1))
|
||||
out_sizes.append(
|
||||
conv2d_output_shape(h_w, kernel_size=4, stride=2, pad=1, dilation=1)
|
||||
)
|
||||
inputs = self.d * mul
|
||||
mul *= 2
|
||||
|
||||
self.d_max = inputs
|
||||
self.last_size = out_sizes[-1][-1]
|
||||
self.num_linear = self.last_size ** 2 * self.d_max
|
||||
self.num_linear = self.last_size**2 * self.d_max
|
||||
# Encoder linear layers
|
||||
self.encoder_mean_linear = nn.Linear(self.num_linear, self.latent_dim)
|
||||
self.encoder_logvar_linear = nn.Linear(self.num_linear, self.latent_dim)
|
||||
@ -112,12 +194,20 @@ class VAE(torch.nn.Module):
|
||||
mul = inputs // self.d // 2
|
||||
|
||||
for i in range(1, self.layer_count):
|
||||
setattr(self, "deconv%d" % (i + 1), nn.ConvTranspose2d(inputs, self.d * mul, 4, 2, 1))
|
||||
setattr(
|
||||
self,
|
||||
"deconv%d" % (i + 1),
|
||||
nn.ConvTranspose2d(inputs, self.d * mul, 4, 2, 1),
|
||||
)
|
||||
setattr(self, "deconv%d_bn" % (i + 1), nn.BatchNorm2d(self.d * mul))
|
||||
inputs = self.d * mul
|
||||
mul //= 2
|
||||
|
||||
setattr(self, "deconv%d" % (self.layer_count + 1), nn.ConvTranspose2d(inputs, self.channels, 4, 2, 1))
|
||||
setattr(
|
||||
self,
|
||||
"deconv%d" % (self.layer_count + 1),
|
||||
nn.ConvTranspose2d(inputs, self.channels, 4, 2, 1),
|
||||
)
|
||||
|
||||
def encode(self, x):
|
||||
if len(x.shape) < 3:
|
||||
@ -127,7 +217,11 @@ class VAE(torch.nn.Module):
|
||||
batch_size = x.shape[0]
|
||||
|
||||
for i in range(self.layer_count):
|
||||
x = F.relu(getattr(self, "conv%d_bn" % (i + 1))(getattr(self, "conv%d" % (i + 1))(x)))
|
||||
x = F.relu(
|
||||
getattr(self, "conv%d_bn" % (i + 1))(
|
||||
getattr(self, "conv%d" % (i + 1))(x)
|
||||
)
|
||||
)
|
||||
|
||||
x = x.view(batch_size, -1)
|
||||
|
||||
@ -140,15 +234,20 @@ class VAE(torch.nn.Module):
|
||||
x = x.view(x.shape[0], self.latent_dim)
|
||||
x = self.decoder_linear(x)
|
||||
x = x.view(x.shape[0], self.d_max, self.last_size, self.last_size)
|
||||
#x = self.deconv1_bn(x)
|
||||
# x = self.deconv1_bn(x)
|
||||
x = F.leaky_relu(x, 0.2)
|
||||
|
||||
for i in range(1, self.layer_count):
|
||||
x = F.leaky_relu(getattr(self, "deconv%d_bn" % (i + 1))(getattr(self, "deconv%d" % (i + 1))(x)), 0.2)
|
||||
x = F.leaky_relu(
|
||||
getattr(self, "deconv%d_bn" % (i + 1))(
|
||||
getattr(self, "deconv%d" % (i + 1))(x)
|
||||
),
|
||||
0.2,
|
||||
)
|
||||
x = getattr(self, "deconv%d" % (self.layer_count + 1))(x)
|
||||
x = torch.sigmoid(x)
|
||||
return x
|
||||
|
||||
|
||||
def forward(self, x):
|
||||
batch_size = x.shape[0]
|
||||
mean, logvar = self.encode(x)
|
||||
@ -157,26 +256,25 @@ class VAE(torch.nn.Module):
|
||||
reconstructed = self.decode(z)
|
||||
return mean, logvar, reconstructed, x
|
||||
|
||||
|
||||
def train_model(latent_dim=16, plot=True, digit=1, epochs=200):
|
||||
dataset = load_dataset(train=True, digit=digit)
|
||||
# DataLoader is used to load the dataset
|
||||
# DataLoader is used to load the dataset
|
||||
# for training
|
||||
loader = torch.utils.data.DataLoader(dataset = dataset,
|
||||
batch_size = 32,
|
||||
shuffle = True)
|
||||
loader = torch.utils.data.DataLoader(dataset=dataset, batch_size=32, shuffle=True)
|
||||
# Model Initialization
|
||||
model = VAE(latent_dim=latent_dim)
|
||||
# Validation using MSE Loss function
|
||||
def loss_function(mean, log_var, reconstructed, original, kl_beta=0.0001):
|
||||
kl = torch.mean(-0.5 * torch.sum(1 + log_var - mean ** 2 - log_var.exp(), dim = 1), dim = 0)
|
||||
kl = torch.mean(
|
||||
-0.5 * torch.sum(1 + log_var - mean**2 - log_var.exp(), dim=1), dim=0
|
||||
)
|
||||
recon = torch.nn.functional.mse_loss(reconstructed, original)
|
||||
# print(f"KL Error {kl}, Recon Error {recon}")
|
||||
return kl_beta * kl + recon
|
||||
|
||||
# Using an Adam Optimizer with lr = 0.1
|
||||
optimizer = torch.optim.Adam(model.parameters(),
|
||||
lr = 1e-4,
|
||||
weight_decay = 0e-8)
|
||||
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4, weight_decay=0e-8)
|
||||
|
||||
outputs = []
|
||||
losses = []
|
||||
@ -198,22 +296,24 @@ 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(),
|
||||
torch.save(
|
||||
model.state_dict(),
|
||||
os.path.join(
|
||||
os.environ["PROJECT_ROOT"],
|
||||
f"examples/variational_autoencoder/autoencoder_model/saved_models/model_dim{latent_dim}.pth"
|
||||
)
|
||||
os.environ["PROJECT_ROOT"],
|
||||
f"examples/variational_autoencoder/autoencoder_model/saved_models/model_dim{latent_dim}.pth",
|
||||
),
|
||||
)
|
||||
|
||||
if plot:
|
||||
# Defining the Plot Style
|
||||
plt.style.use('fivethirtyeight')
|
||||
plt.xlabel('Iterations')
|
||||
plt.ylabel('Loss')
|
||||
|
||||
plt.style.use("fivethirtyeight")
|
||||
plt.xlabel("Iterations")
|
||||
plt.ylabel("Loss")
|
||||
|
||||
# Plotting the last 100 values
|
||||
plt.plot(losses)
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
train_model(latent_dim=2, digit=2, epochs=40)
|
||||
|
@ -21,22 +21,23 @@ config.pixel_width = 1900
|
||||
config.frame_height = 7.0
|
||||
config.frame_width = 7.0
|
||||
|
||||
|
||||
class VAEScene(Scene):
|
||||
"""Scene object for a Variational Autoencoder and Autoencoder"""
|
||||
|
||||
def construct(self):
|
||||
|
||||
numpy_image = np.asarray(Image.open(ROOT_DIR / 'assets/mnist/digit.jpeg'))
|
||||
vae = NeuralNetwork([
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
EmbeddingLayer(dist_theme="ellipse"),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
])
|
||||
|
||||
numpy_image = np.asarray(Image.open(ROOT_DIR / "assets/mnist/digit.jpeg"))
|
||||
vae = NeuralNetwork(
|
||||
[
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
EmbeddingLayer(dist_theme="ellipse"),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
]
|
||||
)
|
||||
|
||||
self.play(Create(vae))
|
||||
self.play(vae.make_forward_pass_animation(run_time=15))
|
||||
self.play(vae.make_forward_pass_animation(run_time=15))
|
||||
|
@ -5,20 +5,27 @@
|
||||
from manim import *
|
||||
from manim_ml.one_to_one_sync import OneToOneSync
|
||||
|
||||
|
||||
class LeafNode(VGroup):
|
||||
pass
|
||||
|
||||
|
||||
class NonLeafNode(VGroup):
|
||||
pass
|
||||
|
||||
|
||||
class DecisionTreeDiagram(Graph):
|
||||
"""Decision Tree Digram Class for Manim"""
|
||||
|
||||
pass
|
||||
|
||||
class DecisionTreeEmbedding():
|
||||
|
||||
class DecisionTreeEmbedding:
|
||||
"""Embedding for the decision tree"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class DecisionTreeContainer(OneToOneSync):
|
||||
"""Connects the DecisionTreeDiagram to the DecisionTreeEmbedding"""
|
||||
|
||||
|
@ -3,15 +3,20 @@
|
||||
"""
|
||||
from manim import *
|
||||
|
||||
|
||||
class FlowGraph(VGroup):
|
||||
"""Graph container"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class FlowNode(VGroup):
|
||||
"""Node in the FlowGraph"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class DataNode(FlowNode):
|
||||
"""Node that outputs data"""
|
||||
pass
|
||||
|
||||
pass
|
||||
|
@ -1,14 +1,27 @@
|
||||
from manim import *
|
||||
import numpy as np
|
||||
|
||||
|
||||
class GriddedRectangle(VGroup):
|
||||
"""Rectangle object with grid lines"""
|
||||
|
||||
def __init__(self, color=ORANGE, height=2.0, width=4.0,
|
||||
mark_paths_closed=True, close_new_points=True,
|
||||
grid_xstep=None, grid_ystep=None, grid_stroke_width=0.0, #DEFAULT_STROKE_WIDTH/2,
|
||||
grid_stroke_color=ORANGE, grid_stroke_opacity=1.0,
|
||||
stroke_width=2.0, fill_opacity=0.2, show_grid_lines=False, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
color=ORANGE,
|
||||
height=2.0,
|
||||
width=4.0,
|
||||
mark_paths_closed=True,
|
||||
close_new_points=True,
|
||||
grid_xstep=None,
|
||||
grid_ystep=None,
|
||||
grid_stroke_width=0.0, # DEFAULT_STROKE_WIDTH/2,
|
||||
grid_stroke_color=ORANGE,
|
||||
grid_stroke_opacity=1.0,
|
||||
stroke_width=2.0,
|
||||
fill_opacity=0.2,
|
||||
show_grid_lines=False,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__()
|
||||
# Fields
|
||||
self.mark_paths_closed = mark_paths_closed
|
||||
@ -25,8 +38,8 @@ class GriddedRectangle(VGroup):
|
||||
self.show_grid_lines = show_grid_lines
|
||||
# Make rectangle
|
||||
self.rectangle = Rectangle(
|
||||
width=width,
|
||||
height=height,
|
||||
width=width,
|
||||
height=height,
|
||||
color=color,
|
||||
stroke_width=stroke_width,
|
||||
fill_color=color,
|
||||
@ -44,29 +57,21 @@ class GriddedRectangle(VGroup):
|
||||
"""Make corners dictionary"""
|
||||
corners_dict = {
|
||||
"top_right": Dot(
|
||||
self.rectangle.get_corner([1, 1, 0]),
|
||||
fill_opacity=0.0,
|
||||
radius=0.0
|
||||
self.rectangle.get_corner([1, 1, 0]), fill_opacity=0.0, radius=0.0
|
||||
),
|
||||
"top_left": Dot(
|
||||
self.rectangle.get_corner([-1, 1, 0]),
|
||||
fill_opacity=0.0,
|
||||
radius=0.0
|
||||
self.rectangle.get_corner([-1, 1, 0]), fill_opacity=0.0, radius=0.0
|
||||
),
|
||||
"bottom_left": Dot(
|
||||
self.rectangle.get_corner([-1, -1, 0]),
|
||||
fill_opacity=0.0,
|
||||
radius=0.0
|
||||
self.rectangle.get_corner([-1, -1, 0]), fill_opacity=0.0, radius=0.0
|
||||
),
|
||||
"bottom_right": Dot(
|
||||
self.rectangle.get_corner([1, -1, 0]),
|
||||
fill_opacity=0.0,
|
||||
radius=0.0
|
||||
self.rectangle.get_corner([1, -1, 0]), fill_opacity=0.0, radius=0.0
|
||||
),
|
||||
}
|
||||
|
||||
return corners_dict
|
||||
|
||||
|
||||
def get_corners_dict(self):
|
||||
"""Returns a dictionary of the corners"""
|
||||
# Sort points through clockwise rotation of a vector in the xy plane
|
||||
@ -87,13 +92,13 @@ class GriddedRectangle(VGroup):
|
||||
v[1] + i * grid_xstep * RIGHT + self.height * DOWN,
|
||||
stroke_color=self.grid_stroke_color,
|
||||
stroke_width=self.grid_stroke_width,
|
||||
stroke_opacity = self.grid_stroke_opacity
|
||||
stroke_opacity=self.grid_stroke_opacity,
|
||||
)
|
||||
for i in range(1, count)
|
||||
)
|
||||
)
|
||||
grid_lines.add(grid)
|
||||
|
||||
|
||||
if self.grid_ystep is not None:
|
||||
grid_ystep = abs(self.grid_ystep)
|
||||
count = int(self.height / grid_ystep)
|
||||
@ -103,12 +108,12 @@ class GriddedRectangle(VGroup):
|
||||
v[1] + i * grid_ystep * DOWN,
|
||||
v[1] + i * grid_ystep * DOWN + self.width * RIGHT,
|
||||
stroke_color=self.grid_stroke_color,
|
||||
stroke_width = self.grid_stroke_width,
|
||||
stroke_opacity = self.grid_stroke_opacity
|
||||
stroke_width=self.grid_stroke_width,
|
||||
stroke_opacity=self.grid_stroke_opacity,
|
||||
)
|
||||
for i in range(1, count)
|
||||
)
|
||||
)
|
||||
)
|
||||
grid_lines.add(grid)
|
||||
|
||||
return grid_lines
|
||||
|
@ -2,13 +2,14 @@ from manim import *
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
|
||||
class GrayscaleImageMobject(ImageMobject):
|
||||
"""Mobject for creating images in Manim from numpy arrays"""
|
||||
|
||||
def __init__(self, numpy_image, height=2.3):
|
||||
self.numpy_image = numpy_image
|
||||
|
||||
assert len(np.shape(self.numpy_image)) == 2
|
||||
assert len(np.shape(self.numpy_image)) == 2
|
||||
input_image = self.numpy_image[None, :, :]
|
||||
# Convert grayscale to rgb version of grayscale
|
||||
input_image = np.repeat(input_image, 3, axis=0)
|
||||
@ -31,11 +32,13 @@ class GrayscaleImageMobject(ImageMobject):
|
||||
def create(self, run_time=2):
|
||||
return FadeIn(self)
|
||||
|
||||
|
||||
class LabeledColorImage(Group):
|
||||
"""Labeled Color Image"""
|
||||
|
||||
def __init__(self, image, color=RED, label="Positive", stroke_width=5,
|
||||
font_size=24, buff=0.2):
|
||||
def __init__(
|
||||
self, image, color=RED, label="Positive", stroke_width=5, font_size=24, buff=0.2
|
||||
):
|
||||
super().__init__()
|
||||
self.image = image
|
||||
self.color = color
|
||||
@ -46,12 +49,9 @@ class LabeledColorImage(Group):
|
||||
text = Text(label, font_size=self.font_size)
|
||||
text.next_to(self.image, UP, buff=buff)
|
||||
rectangle = SurroundingRectangle(
|
||||
self.image,
|
||||
color=color,
|
||||
buff=0.0,
|
||||
stroke_width=self.stroke_width
|
||||
self.image, color=color, buff=0.0, stroke_width=self.stroke_width
|
||||
)
|
||||
|
||||
self.add(text)
|
||||
self.add(rectangle)
|
||||
self.add(self.image)
|
||||
self.add(self.image)
|
||||
|
@ -1,7 +1,7 @@
|
||||
from manim import *
|
||||
|
||||
class LazyAnimation(Animation):
|
||||
|
||||
class LazyAnimation(Animation):
|
||||
def __init__(self, animation_function):
|
||||
self.animation_function = animation_function
|
||||
super.__init__()
|
||||
@ -10,4 +10,4 @@ class LazyAnimation(Animation):
|
||||
update_func_anim = UpdateFromFunc(self.neural_network, create_new_connective)
|
||||
self.add
|
||||
|
||||
super.begin()
|
||||
super.begin()
|
||||
|
@ -1,4 +1,5 @@
|
||||
from manim import *
|
||||
from manim import *
|
||||
|
||||
|
||||
class ListGroup(Mobject):
|
||||
"""Indexable Group with traditional list operations"""
|
||||
@ -10,7 +11,7 @@ class ListGroup(Mobject):
|
||||
def __getitem__(self, indices):
|
||||
"""Traditional list indexing"""
|
||||
return self.items[indices]
|
||||
|
||||
|
||||
def insert(self, index, item):
|
||||
"""Inserts item at index"""
|
||||
self.items.insert(index, item)
|
||||
@ -39,7 +40,7 @@ class ListGroup(Mobject):
|
||||
"""Removes first instance of item"""
|
||||
self.items.remove(item)
|
||||
self.submobjects = self.items
|
||||
|
||||
|
||||
return item
|
||||
|
||||
def get(self, index):
|
||||
@ -76,7 +77,7 @@ class ListGroup(Mobject):
|
||||
self.current_index = -1
|
||||
return self
|
||||
|
||||
def __next__(self): # Python 2: def next(self)
|
||||
def __next__(self): # Python 2: def next(self)
|
||||
self.current_index += 1
|
||||
if self.current_index < len(self.items):
|
||||
return self.items[self.current_index]
|
||||
|
@ -1,3 +1,3 @@
|
||||
"""
|
||||
Visaulization of a latent Manifold
|
||||
"""
|
||||
"""
|
||||
|
@ -1,5 +1,9 @@
|
||||
from manim_ml.neural_network.layers.convolutional_3d_to_feed_forward import Convolutional3DToFeedForward
|
||||
from manim_ml.neural_network.layers.image_to_convolutional3d import ImageToConvolutional3DLayer
|
||||
from manim_ml.neural_network.layers.convolutional_3d_to_feed_forward import (
|
||||
Convolutional3DToFeedForward,
|
||||
)
|
||||
from manim_ml.neural_network.layers.image_to_convolutional3d import (
|
||||
ImageToConvolutional3DLayer,
|
||||
)
|
||||
from .convolutional3d_to_convolutional3d import Convolutional3DToConvolutional3D
|
||||
from .convolutional2d_to_convolutional2d import Convolutional2DToConvolutional2D
|
||||
from .convolutional3d import Convolutional3DLayer
|
||||
@ -33,5 +37,5 @@ connective_layers_list = (
|
||||
Convolutional3DToConvolutional3D,
|
||||
Convolutional2DToConvolutional2D,
|
||||
ImageToConvolutional3DLayer,
|
||||
Convolutional3DToFeedForward
|
||||
Convolutional3DToFeedForward,
|
||||
)
|
||||
|
@ -2,11 +2,20 @@ from manim import *
|
||||
from matplotlib import animation
|
||||
from manim_ml.neural_network.layers.parent_layers import VGroupNeuralNetworkLayer
|
||||
|
||||
|
||||
class Convolutional2DLayer(VGroupNeuralNetworkLayer):
|
||||
|
||||
def __init__(self, feature_map_height, feature_map_width, filter_width, filter_height,
|
||||
stride=1, cell_width=0.5, feature_map_color=BLUE, filter_color=ORANGE,
|
||||
**kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
feature_map_height,
|
||||
feature_map_width,
|
||||
filter_width,
|
||||
filter_height,
|
||||
stride=1,
|
||||
cell_width=0.5,
|
||||
feature_map_color=BLUE,
|
||||
filter_color=ORANGE,
|
||||
**kwargs
|
||||
):
|
||||
super(VGroupNeuralNetworkLayer, self).__init__(**kwargs)
|
||||
self.feature_map_height = feature_map_height
|
||||
self.feature_map_width = feature_map_width
|
||||
@ -24,10 +33,10 @@ class Convolutional2DLayer(VGroupNeuralNetworkLayer):
|
||||
# Make feature map rectangle
|
||||
self.feature_map = Rectangle(
|
||||
width=self.feature_map_width * self.cell_width,
|
||||
height=self.feature_map_height * self.cell_width,
|
||||
height=self.feature_map_height * self.cell_width,
|
||||
color=self.feature_map_color,
|
||||
grid_xstep=self.cell_width,
|
||||
grid_ystep=self.cell_width
|
||||
grid_ystep=self.cell_width,
|
||||
)
|
||||
|
||||
self.add(self.feature_map)
|
||||
@ -38,4 +47,4 @@ class Convolutional2DLayer(VGroupNeuralNetworkLayer):
|
||||
|
||||
def make_forward_pass_animation(self, **kwargs):
|
||||
"""Make feed forward animation"""
|
||||
return AnimationGroup()
|
||||
return AnimationGroup()
|
||||
|
@ -3,15 +3,30 @@ from manim import *
|
||||
from manim_ml.neural_network.layers.convolutional2d import Convolutional2DLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer
|
||||
|
||||
|
||||
class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
"""2D Conv to 2d Conv"""
|
||||
|
||||
input_class = Convolutional2DLayer
|
||||
output_class = Convolutional2DLayer
|
||||
|
||||
def __init__(self, input_layer, output_layer, color=WHITE,
|
||||
filter_opacity=0.3, line_color=WHITE, pulse_color=ORANGE, **kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=Convolutional2DLayer,
|
||||
output_class=Convolutional2DLayer, **kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
color=WHITE,
|
||||
filter_opacity=0.3,
|
||||
line_color=WHITE,
|
||||
pulse_color=ORANGE,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=Convolutional2DLayer,
|
||||
output_class=Convolutional2DLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.color = color
|
||||
self.filter_color = self.input_layer.filter_color
|
||||
self.filter_width = self.input_layer.filter_width
|
||||
@ -27,7 +42,7 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
@override_animation(Create)
|
||||
def _create_override(self, **kwargs):
|
||||
return AnimationGroup()
|
||||
|
||||
|
||||
def make_filter(self):
|
||||
"""Make filter object"""
|
||||
# Make opaque rectangle
|
||||
@ -38,10 +53,12 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
height=self.cell_width * self.filter_height,
|
||||
grid_xstep=self.cell_width,
|
||||
grid_ystep=self.cell_width,
|
||||
fill_opacity=self.filter_opacity
|
||||
fill_opacity=self.filter_opacity,
|
||||
)
|
||||
# Move filter to top left of feature map
|
||||
filter.move_to(self.input_layer.feature_map.get_corner(LEFT + UP), aligned_edge=LEFT + UP)
|
||||
filter.move_to(
|
||||
self.input_layer.feature_map.get_corner(LEFT + UP), aligned_edge=LEFT + UP
|
||||
)
|
||||
|
||||
return filter
|
||||
|
||||
@ -53,10 +70,12 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
fill_color=self.filter_color,
|
||||
width=self.cell_width,
|
||||
height=self.cell_width,
|
||||
fill_opacity=self.filter_opacity
|
||||
fill_opacity=self.filter_opacity,
|
||||
)
|
||||
# Move filter to top left of feature map
|
||||
filter.move_to(self.output_layer.feature_map.get_corner(LEFT + UP), aligned_edge=LEFT + UP)
|
||||
filter.move_to(
|
||||
self.output_layer.feature_map.get_corner(LEFT + UP), aligned_edge=LEFT + UP
|
||||
)
|
||||
|
||||
return filter
|
||||
|
||||
@ -67,7 +86,7 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
Create(lines_copy, lag_ratio=0.0),
|
||||
# FadeOut(self.filter_lines),
|
||||
FadeOut(lines_copy),
|
||||
lag_ratio=1.0
|
||||
lag_ratio=1.0,
|
||||
)
|
||||
|
||||
return animation_group
|
||||
@ -90,7 +109,7 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
line = filter_lines[corner_index]
|
||||
filter_corner = self.filter.get_corner(corner_direction)
|
||||
output_corner = self.output_node.get_corner(corner_direction)
|
||||
#line._set_start_and_end_attrs(filter_corner, output_corner)
|
||||
# line._set_start_and_end_attrs(filter_corner, output_corner)
|
||||
# line.put_start_and_end_on(filter_corner, output_corner)
|
||||
line.set_points_by_ends(filter_corner, output_corner)
|
||||
# line._set_start_and_end_attrs(filter_corner, output_corner)
|
||||
@ -111,7 +130,7 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
# Make filter lines
|
||||
self.filter_lines = self.make_filter_lines()
|
||||
self.add(self.filter_lines)
|
||||
|
||||
|
||||
super().set_z_index(5)
|
||||
|
||||
def make_forward_pass_animation(self, layer_args={}, run_time=1.5, **kwargs):
|
||||
@ -127,31 +146,39 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
AnimationGroup(
|
||||
Create(self.filter),
|
||||
Create(self.output_node),
|
||||
# Create(self.filter_lines)
|
||||
# Create(self.filter_lines)
|
||||
)
|
||||
)
|
||||
# Make scan filter animation
|
||||
num_y_moves = int((self.feature_map_height - self.filter_height) / self.stride) + 1
|
||||
num_y_moves = (
|
||||
int((self.feature_map_height - self.filter_height) / self.stride) + 1
|
||||
)
|
||||
num_x_moves = int((self.feature_map_width - self.filter_width) / self.stride)
|
||||
for y_location in range(num_y_moves):
|
||||
if y_location > 0:
|
||||
# Shift filter back to start and down
|
||||
shift_animation = ApplyMethod(
|
||||
self.filter.shift,
|
||||
np.array([
|
||||
-self.cell_width * (self.feature_map_width - self.filter_width),
|
||||
-self.stride * self.cell_width,
|
||||
0
|
||||
])
|
||||
np.array(
|
||||
[
|
||||
-self.cell_width
|
||||
* (self.feature_map_width - self.filter_width),
|
||||
-self.stride * self.cell_width,
|
||||
0,
|
||||
]
|
||||
),
|
||||
)
|
||||
# Shift output node
|
||||
shift_output_node = ApplyMethod(
|
||||
self.output_node.shift,
|
||||
np.array([
|
||||
-(self.output_layer.feature_map_width - 1) * self.cell_width,
|
||||
-self.cell_width,
|
||||
0
|
||||
])
|
||||
np.array(
|
||||
[
|
||||
-(self.output_layer.feature_map_width - 1)
|
||||
* self.cell_width,
|
||||
-self.cell_width,
|
||||
0,
|
||||
]
|
||||
),
|
||||
)
|
||||
# Make animation group
|
||||
animation_group = AnimationGroup(
|
||||
@ -167,13 +194,11 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
for x_location in range(num_x_moves):
|
||||
# Shift filter right
|
||||
shift_animation = ApplyMethod(
|
||||
self.filter.shift,
|
||||
np.array([self.stride * self.cell_width, 0, 0])
|
||||
self.filter.shift, np.array([self.stride * self.cell_width, 0, 0])
|
||||
)
|
||||
# Shift output node
|
||||
shift_output_node = ApplyMethod(
|
||||
self.output_node.shift,
|
||||
np.array([self.cell_width, 0, 0])
|
||||
self.output_node.shift, np.array([self.cell_width, 0, 0])
|
||||
)
|
||||
# Make animation group
|
||||
animation_group = AnimationGroup(
|
||||
@ -183,7 +208,11 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
animations.append(animation_group)
|
||||
# Make filter passing flash
|
||||
old_z_index = self.filter_lines.z_index
|
||||
lines_copy = self.filter_lines.copy().set_color(ORANGE).set_z_index(old_z_index + 1)
|
||||
lines_copy = (
|
||||
self.filter_lines.copy()
|
||||
.set_color(ORANGE)
|
||||
.set_z_index(old_z_index + 1)
|
||||
)
|
||||
# self.add(lines_copy)
|
||||
# self.lines_copies.add(lines_copy)
|
||||
animations.append(Create(self.filter_lines, lag_ratio=0.0))
|
||||
@ -197,14 +226,11 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
AnimationGroup(
|
||||
FadeOut(self.filter),
|
||||
FadeOut(self.output_node),
|
||||
FadeOut(self.filter_lines)
|
||||
FadeOut(self.filter_lines),
|
||||
)
|
||||
)
|
||||
# Make animation group
|
||||
animation_group = Succession(
|
||||
*animations,
|
||||
lag_ratio=1.0
|
||||
)
|
||||
animation_group = Succession(*animations, lag_ratio=1.0)
|
||||
return animation_group
|
||||
|
||||
def set_z_index(self, z_index, family=False):
|
||||
@ -213,4 +239,4 @@ class Convolutional2DToConvolutional2D(ConnectiveLayer):
|
||||
|
||||
def scale(self, scale_factor, **kwargs):
|
||||
self.cell_width *= scale_factor
|
||||
super().scale(scale_factor, **kwargs)
|
||||
super().scale(scale_factor, **kwargs)
|
||||
|
@ -1,14 +1,32 @@
|
||||
from manim import *
|
||||
from manim_ml.neural_network.layers.parent_layers import ThreeDLayer, VGroupNeuralNetworkLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import (
|
||||
ThreeDLayer,
|
||||
VGroupNeuralNetworkLayer,
|
||||
)
|
||||
from manim_ml.gridded_rectangle import GriddedRectangle
|
||||
import numpy as np
|
||||
|
||||
|
||||
class Convolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
"""Handles rendering a convolutional layer for a nn"""
|
||||
|
||||
def __init__(self, num_feature_maps, feature_map_width, feature_map_height,
|
||||
filter_width, filter_height, cell_width=0.2, filter_spacing=0.1, color=BLUE,
|
||||
pulse_color=ORANGE, show_grid_lines=False, filter_color=ORANGE, stride=1, stroke_width=2.0, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
num_feature_maps,
|
||||
feature_map_width,
|
||||
feature_map_height,
|
||||
filter_width,
|
||||
filter_height,
|
||||
cell_width=0.2,
|
||||
filter_spacing=0.1,
|
||||
color=BLUE,
|
||||
pulse_color=ORANGE,
|
||||
show_grid_lines=False,
|
||||
filter_color=ORANGE,
|
||||
stride=1,
|
||||
stroke_width=2.0,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(**kwargs)
|
||||
self.num_feature_maps = num_feature_maps
|
||||
self.feature_map_height = feature_map_height
|
||||
@ -29,9 +47,9 @@ class Convolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
# Rotate stuff properly
|
||||
# normal_vector = self.feature_maps[0].get_normal_vector()
|
||||
self.rotate(
|
||||
ThreeDLayer.rotation_angle,
|
||||
about_point=self.get_center(),
|
||||
axis=ThreeDLayer.rotation_axis
|
||||
ThreeDLayer.rotation_angle,
|
||||
about_point=self.get_center(),
|
||||
axis=ThreeDLayer.rotation_axis,
|
||||
)
|
||||
"""
|
||||
self.rotate(
|
||||
@ -47,35 +65,29 @@ class Convolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
feature_maps = []
|
||||
for filter_index in range(self.num_feature_maps):
|
||||
rectangle = GriddedRectangle(
|
||||
color=self.color,
|
||||
color=self.color,
|
||||
height=self.feature_map_height * self.cell_width,
|
||||
width=self.feature_map_width * self.cell_width,
|
||||
fill_color=self.color,
|
||||
fill_opacity=0.2,
|
||||
fill_opacity=0.2,
|
||||
stroke_color=self.color,
|
||||
stroke_width=self.stroke_width,
|
||||
grid_xstep=self.cell_width,
|
||||
grid_ystep=self.cell_width,
|
||||
grid_stroke_width=self.stroke_width/2,
|
||||
grid_stroke_width=self.stroke_width / 2,
|
||||
grid_stroke_color=self.color,
|
||||
show_grid_lines=self.show_grid_lines,
|
||||
)
|
||||
# Move the feature map
|
||||
rectangle.move_to(
|
||||
[0, 0, filter_index * self.filter_spacing]
|
||||
)
|
||||
rectangle.move_to([0, 0, filter_index * self.filter_spacing])
|
||||
rectangle.set_z_index(4)
|
||||
feature_maps.append(rectangle)
|
||||
|
||||
return VGroup(*feature_maps)
|
||||
|
||||
def make_forward_pass_animation(
|
||||
self,
|
||||
run_time=5,
|
||||
corner_pulses=False,
|
||||
layer_args={},
|
||||
**kwargs
|
||||
):
|
||||
self, run_time=5, corner_pulses=False, layer_args={}, **kwargs
|
||||
):
|
||||
"""Convolution forward pass animation"""
|
||||
# Note: most of this animation is done in the Convolution3DToConvolution3D layer
|
||||
print(f"Corner pulses: {corner_pulses}")
|
||||
@ -84,12 +96,10 @@ class Convolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
passing_flashes = []
|
||||
for line in self.corner_lines:
|
||||
pulse = ShowPassingFlash(
|
||||
line.copy()
|
||||
.set_color(self.pulse_color)
|
||||
.set_stroke(opacity=1.0),
|
||||
line.copy().set_color(self.pulse_color).set_stroke(opacity=1.0),
|
||||
time_width=0.5,
|
||||
run_time=run_time,
|
||||
rate_func=rate_functions.linear
|
||||
rate_func=rate_functions.linear,
|
||||
)
|
||||
passing_flashes.append(pulse)
|
||||
|
||||
@ -97,7 +107,7 @@ class Convolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
# Make animation group
|
||||
animation_group = AnimationGroup(
|
||||
*passing_flashes,
|
||||
# filter_flashes
|
||||
# filter_flashes
|
||||
)
|
||||
else:
|
||||
animation_group = AnimationGroup()
|
||||
|
@ -5,19 +5,20 @@ from manim_ml.gridded_rectangle import GriddedRectangle
|
||||
|
||||
from manim.utils.space_ops import rotation_matrix
|
||||
|
||||
|
||||
class Filters(VGroup):
|
||||
"""Group for showing a collection of filters connecting two layers"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
line_color=ORANGE,
|
||||
cell_width=1.0,
|
||||
stroke_width=2.0,
|
||||
show_grid_lines=False,
|
||||
output_feature_map_to_connect=None # None means all at once
|
||||
):
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
line_color=ORANGE,
|
||||
cell_width=1.0,
|
||||
stroke_width=2.0,
|
||||
show_grid_lines=False,
|
||||
output_feature_map_to_connect=None, # None means all at once
|
||||
):
|
||||
super().__init__()
|
||||
self.input_layer = input_layer
|
||||
self.output_layer = output_layer
|
||||
@ -46,7 +47,7 @@ class Filters(VGroup):
|
||||
|
||||
for index, feature_map in enumerate(self.input_layer.feature_maps):
|
||||
rectangle = GriddedRectangle(
|
||||
width=rectangle_width,
|
||||
width=rectangle_width,
|
||||
height=rectangle_height,
|
||||
fill_color=filter_color,
|
||||
stroke_color=filter_color,
|
||||
@ -60,9 +61,9 @@ class Filters(VGroup):
|
||||
)
|
||||
# normal_vector = rectangle.get_normal_vector()
|
||||
rectangle.rotate(
|
||||
ThreeDLayer.rotation_angle,
|
||||
about_point=rectangle.get_center(),
|
||||
axis=ThreeDLayer.rotation_axis
|
||||
ThreeDLayer.rotation_angle,
|
||||
about_point=rectangle.get_center(),
|
||||
axis=ThreeDLayer.rotation_axis,
|
||||
)
|
||||
# Move the rectangle to the corner of the feature map
|
||||
rectangle.next_to(
|
||||
@ -74,7 +75,7 @@ class Filters(VGroup):
|
||||
rectangle.set_z_index(5)
|
||||
|
||||
rectangles.append(rectangle)
|
||||
|
||||
|
||||
feature_map_rectangles = VGroup(*rectangles)
|
||||
|
||||
return feature_map_rectangles
|
||||
@ -93,7 +94,7 @@ class Filters(VGroup):
|
||||
continue
|
||||
# Make the rectangle
|
||||
rectangle = GriddedRectangle(
|
||||
width=rectangle_width,
|
||||
width=rectangle_width,
|
||||
height=rectangle_height,
|
||||
fill_color=filter_color,
|
||||
fill_opacity=0.2,
|
||||
@ -101,15 +102,15 @@ class Filters(VGroup):
|
||||
stroke_width=self.stroke_width,
|
||||
grid_xstep=self.cell_width,
|
||||
grid_ystep=self.cell_width,
|
||||
grid_stroke_width=self.stroke_width/2,
|
||||
grid_stroke_width=self.stroke_width / 2,
|
||||
grid_stroke_color=filter_color,
|
||||
show_grid_lines=self.show_grid_lines,
|
||||
)
|
||||
# Rotate the rectangle
|
||||
rectangle.rotate(
|
||||
ThreeDLayer.rotation_angle,
|
||||
about_point=rectangle.get_center(),
|
||||
axis=ThreeDLayer.rotation_axis
|
||||
ThreeDLayer.rotation_angle,
|
||||
about_point=rectangle.get_center(),
|
||||
axis=ThreeDLayer.rotation_axis,
|
||||
)
|
||||
# Move the rectangle to the corner location
|
||||
rectangle.next_to(
|
||||
@ -119,7 +120,7 @@ class Filters(VGroup):
|
||||
# aligned_edge=feature_map.get_corners_dict()["top_left"].get_center()
|
||||
)
|
||||
rectangles.append(rectangle)
|
||||
|
||||
|
||||
feature_map_rectangles = VGroup(*rectangles)
|
||||
|
||||
return feature_map_rectangles
|
||||
@ -188,74 +189,86 @@ class Filters(VGroup):
|
||||
)
|
||||
lines.append(line)
|
||||
|
||||
return VGroup(*lines)
|
||||
|
||||
return VGroup(*lines)
|
||||
|
||||
input_lines = make_input_connective_lines()
|
||||
output_lines = make_output_connective_lines()
|
||||
input_output_lines = make_input_to_output_connective_lines()
|
||||
|
||||
connective_lines = VGroup(
|
||||
*input_lines,
|
||||
*output_lines,
|
||||
*input_output_lines
|
||||
)
|
||||
|
||||
connective_lines = VGroup(*input_lines, *output_lines, *input_output_lines)
|
||||
|
||||
return connective_lines
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self, **kwargs):
|
||||
"""
|
||||
NOTE This create override animation
|
||||
is a workaround to make sure that the filter
|
||||
does not show up in the scene before the create animation.
|
||||
NOTE This create override animation
|
||||
is a workaround to make sure that the filter
|
||||
does not show up in the scene before the create animation.
|
||||
|
||||
Without this override the filters were shown at the beginning
|
||||
of the neural network forward pass animimation
|
||||
instead of just when the filters were supposed to appear.
|
||||
I think this is a bug with Succession in the core
|
||||
Manim Community Library.
|
||||
Without this override the filters were shown at the beginning
|
||||
of the neural network forward pass animimation
|
||||
instead of just when the filters were supposed to appear.
|
||||
I think this is a bug with Succession in the core
|
||||
Manim Community Library.
|
||||
|
||||
TODO Fix this
|
||||
TODO Fix this
|
||||
"""
|
||||
|
||||
def add_content(object):
|
||||
object.add(self.input_rectangles)
|
||||
object.add(self.connective_lines)
|
||||
object.add(self.output_rectangles)
|
||||
object.add(self.input_rectangles)
|
||||
object.add(self.connective_lines)
|
||||
object.add(self.output_rectangles)
|
||||
|
||||
return object
|
||||
|
||||
return ApplyFunction(
|
||||
add_content,
|
||||
self
|
||||
)
|
||||
return ApplyFunction(add_content, self)
|
||||
return AnimationGroup(
|
||||
Create(self.input_rectangles),
|
||||
Create(self.connective_lines),
|
||||
Create(self.output_rectangles),
|
||||
lag_ratio=0.0
|
||||
lag_ratio=0.0,
|
||||
)
|
||||
|
||||
|
||||
def make_pulse_animation(self, shift_amount):
|
||||
"""Make animation of the filter pulsing"""
|
||||
passing_flash = ShowPassingFlash(
|
||||
self.connective_lines.shift(shift_amount).set_stroke_width(self.stroke_width*1.5),
|
||||
self.connective_lines.shift(shift_amount).set_stroke_width(
|
||||
self.stroke_width * 1.5
|
||||
),
|
||||
time_width=0.2,
|
||||
color=RED,
|
||||
z_index=10
|
||||
z_index=10,
|
||||
)
|
||||
|
||||
return passing_flash
|
||||
|
||||
|
||||
class Convolutional3DToConvolutional3D(ConnectiveLayer, ThreeDLayer):
|
||||
"""Feed Forward to Embedding Layer"""
|
||||
|
||||
input_class = Convolutional3DLayer
|
||||
output_class = Convolutional3DLayer
|
||||
|
||||
def __init__(self, input_layer: Convolutional3DLayer, output_layer: Convolutional3DLayer,
|
||||
color=ORANGE, filter_opacity=0.3, line_color=ORANGE,
|
||||
pulse_color=ORANGE, cell_width=0.2, show_grid_lines=True, **kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=Convolutional3DLayer,
|
||||
output_class=Convolutional3DLayer, **kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer: Convolutional3DLayer,
|
||||
output_layer: Convolutional3DLayer,
|
||||
color=ORANGE,
|
||||
filter_opacity=0.3,
|
||||
line_color=ORANGE,
|
||||
pulse_color=ORANGE,
|
||||
cell_width=0.2,
|
||||
show_grid_lines=True,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=Convolutional3DLayer,
|
||||
output_class=Convolutional3DLayer,
|
||||
**kwargs,
|
||||
)
|
||||
self.color = color
|
||||
self.filter_color = self.input_layer.filter_color
|
||||
self.filter_width = self.input_layer.filter_width
|
||||
@ -274,17 +287,14 @@ class Convolutional3DToConvolutional3D(ConnectiveLayer, ThreeDLayer):
|
||||
|
||||
def get_rotated_shift_vectors(self):
|
||||
"""
|
||||
Rotates the shift vectors
|
||||
Rotates the shift vectors
|
||||
"""
|
||||
# Make base shift vectors
|
||||
right_shift = np.array([self.input_layer.cell_width, 0, 0])
|
||||
down_shift = np.array([0, -self.input_layer.cell_width, 0])
|
||||
# Make rotation matrix
|
||||
rot_mat = rotation_matrix(
|
||||
ThreeDLayer.rotation_angle,
|
||||
ThreeDLayer.rotation_axis
|
||||
)
|
||||
# Rotate the vectors
|
||||
rot_mat = rotation_matrix(ThreeDLayer.rotation_angle, ThreeDLayer.rotation_axis)
|
||||
# Rotate the vectors
|
||||
right_shift = np.dot(right_shift, rot_mat.T)
|
||||
down_shift = np.dot(down_shift, rot_mat.T)
|
||||
|
||||
@ -295,58 +305,44 @@ class Convolutional3DToConvolutional3D(ConnectiveLayer, ThreeDLayer):
|
||||
animations = []
|
||||
# Make filters
|
||||
filters = Filters(
|
||||
self.input_layer,
|
||||
self.input_layer,
|
||||
self.output_layer,
|
||||
line_color=self.color,
|
||||
cell_width=self.cell_width,
|
||||
show_grid_lines=self.show_grid_lines,
|
||||
output_feature_map_to_connect=None # None means all at once
|
||||
)
|
||||
animations.append(
|
||||
Create(filters)
|
||||
output_feature_map_to_connect=None, # None means all at once
|
||||
)
|
||||
animations.append(Create(filters))
|
||||
# Get the rotated shift vectors
|
||||
right_shift, down_shift = self.get_rotated_shift_vectors()
|
||||
left_shift = -1 * right_shift
|
||||
# Make the animation
|
||||
# Make the animation
|
||||
num_y_moves = int((self.feature_map_height - self.filter_height) / self.stride)
|
||||
num_x_moves = int((self.feature_map_width - self.filter_width) / self.stride)
|
||||
for y_move in range(num_y_moves):
|
||||
# Go right num_x_moves
|
||||
for x_move in range(num_x_moves):
|
||||
# Shift right
|
||||
shift_animation = ApplyMethod(
|
||||
filters.shift,
|
||||
self.stride * right_shift
|
||||
)
|
||||
shift_animation = ApplyMethod(filters.shift, self.stride * right_shift)
|
||||
# shift_animation = self.animate.shift(right_shift)
|
||||
animations.append(shift_animation)
|
||||
|
||||
|
||||
# Go back left num_x_moves and down one
|
||||
shift_amount = self.stride * num_x_moves * left_shift + self.stride * down_shift
|
||||
# Make the animation
|
||||
shift_animation = ApplyMethod(
|
||||
filters.shift,
|
||||
shift_amount
|
||||
shift_amount = (
|
||||
self.stride * num_x_moves * left_shift + self.stride * down_shift
|
||||
)
|
||||
# Make the animation
|
||||
shift_animation = ApplyMethod(filters.shift, shift_amount)
|
||||
animations.append(shift_animation)
|
||||
# Do last row move right
|
||||
for x_move in range(num_x_moves):
|
||||
# Shift right
|
||||
shift_animation = ApplyMethod(
|
||||
filters.shift,
|
||||
self.stride * right_shift
|
||||
)
|
||||
shift_animation = ApplyMethod(filters.shift, self.stride * right_shift)
|
||||
# shift_animation = self.animate.shift(right_shift)
|
||||
animations.append(shift_animation)
|
||||
# Remove the filters
|
||||
animations.append(
|
||||
FadeOut(filters)
|
||||
)
|
||||
return Succession(
|
||||
*animations,
|
||||
lag_ratio=1.0
|
||||
)
|
||||
animations.append(FadeOut(filters))
|
||||
return Succession(*animations, lag_ratio=1.0)
|
||||
|
||||
def animate_filters_one_at_a_time(self):
|
||||
"""Animates each of the filters one at a time"""
|
||||
@ -355,22 +351,24 @@ class Convolutional3DToConvolutional3D(ConnectiveLayer, ThreeDLayer):
|
||||
for filter_index in range(len(output_feature_maps)):
|
||||
# Make filters
|
||||
filters = Filters(
|
||||
self.input_layer,
|
||||
self.input_layer,
|
||||
self.output_layer,
|
||||
line_color=self.color,
|
||||
cell_width=self.cell_width,
|
||||
show_grid_lines=self.show_grid_lines,
|
||||
output_feature_map_to_connect=filter_index # None means all at once
|
||||
)
|
||||
animations.append(
|
||||
Create(filters)
|
||||
output_feature_map_to_connect=filter_index, # None means all at once
|
||||
)
|
||||
animations.append(Create(filters))
|
||||
# Get the rotated shift vectors
|
||||
right_shift, down_shift = self.get_rotated_shift_vectors()
|
||||
left_shift = -1 * right_shift
|
||||
# Make the animation
|
||||
num_y_moves = int((self.feature_map_height - self.filter_height) / self.stride)
|
||||
num_x_moves = int((self.feature_map_width - self.filter_width) / self.stride)
|
||||
# Make the animation
|
||||
num_y_moves = int(
|
||||
(self.feature_map_height - self.filter_height) / self.stride
|
||||
)
|
||||
num_x_moves = int(
|
||||
(self.feature_map_width - self.filter_width) / self.stride
|
||||
)
|
||||
for y_move in range(num_y_moves):
|
||||
# Go right num_x_moves
|
||||
for x_move in range(num_x_moves):
|
||||
@ -381,48 +379,36 @@ class Convolutional3DToConvolutional3D(ConnectiveLayer, ThreeDLayer):
|
||||
)
|
||||
animations.append(pulse_animation)
|
||||
"""
|
||||
z_index_animation = ApplyMethod(
|
||||
filters.set_z_index,
|
||||
5
|
||||
)
|
||||
z_index_animation = ApplyMethod(filters.set_z_index, 5)
|
||||
animations.append(z_index_animation)
|
||||
# Shift right
|
||||
shift_animation = ApplyMethod(
|
||||
filters.shift,
|
||||
self.stride * right_shift
|
||||
filters.shift, self.stride * right_shift
|
||||
)
|
||||
# shift_animation = self.animate.shift(right_shift)
|
||||
animations.append(shift_animation)
|
||||
|
||||
|
||||
# Go back left num_x_moves and down one
|
||||
shift_amount = self.stride * num_x_moves * left_shift + self.stride * down_shift
|
||||
# Make the animation
|
||||
shift_animation = ApplyMethod(
|
||||
filters.shift,
|
||||
shift_amount
|
||||
shift_amount = (
|
||||
self.stride * num_x_moves * left_shift + self.stride * down_shift
|
||||
)
|
||||
# Make the animation
|
||||
shift_animation = ApplyMethod(filters.shift, shift_amount)
|
||||
animations.append(shift_animation)
|
||||
# Do last row move right
|
||||
for x_move in range(num_x_moves):
|
||||
# Shift right
|
||||
shift_animation = ApplyMethod(
|
||||
filters.shift,
|
||||
self.stride * right_shift
|
||||
)
|
||||
shift_animation = ApplyMethod(filters.shift, self.stride * right_shift)
|
||||
# shift_animation = self.animate.shift(right_shift)
|
||||
animations.append(shift_animation)
|
||||
# Remove the filters
|
||||
animations.append(
|
||||
FadeOut(filters)
|
||||
)
|
||||
animations.append(FadeOut(filters))
|
||||
|
||||
return Succession(
|
||||
*animations,
|
||||
lag_ratio=1.0
|
||||
)
|
||||
return Succession(*animations, lag_ratio=1.0)
|
||||
|
||||
def make_forward_pass_animation(self, layer_args={},
|
||||
all_filters_at_once=False, run_time=10.5, **kwargs):
|
||||
def make_forward_pass_animation(
|
||||
self, layer_args={}, all_filters_at_once=False, run_time=10.5, **kwargs
|
||||
):
|
||||
"""Forward pass animation from conv2d to conv2d"""
|
||||
print(f"All filters at once: {all_filters_at_once}")
|
||||
# Make filter shifting animations
|
||||
|
@ -3,17 +3,29 @@ from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer, ThreeD
|
||||
from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.convolutional3d import Convolutional3DLayer
|
||||
|
||||
|
||||
class Convolutional3DToFeedForward(ConnectiveLayer, ThreeDLayer):
|
||||
"""Feed Forward to Embedding Layer"""
|
||||
|
||||
input_class = Convolutional3DLayer
|
||||
output_class = FeedForwardLayer
|
||||
|
||||
def __init__(self, input_layer: Convolutional3DLayer, output_layer: FeedForwardLayer,
|
||||
passing_flash_color=ORANGE, **kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=Convolutional3DLayer,
|
||||
output_class=Convolutional3DLayer, **kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer: Convolutional3DLayer,
|
||||
output_layer: FeedForwardLayer,
|
||||
passing_flash_color=ORANGE,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=Convolutional3DLayer,
|
||||
output_class=Convolutional3DLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.passing_flash_color = passing_flash_color
|
||||
|
||||
|
||||
def make_forward_pass_animation(self, layer_args={}, run_time=1.5, **kwargs):
|
||||
"""Forward pass animation from conv2d to conv2d"""
|
||||
animations = []
|
||||
@ -29,9 +41,8 @@ class Convolutional3DToFeedForward(ConnectiveLayer, ThreeDLayer):
|
||||
line = Line(corner, node, stroke_width=1.0)
|
||||
line.set_z_index(self.output_layer.node_group.get_z_index())
|
||||
anim = ShowPassingFlash(
|
||||
line.set_color(self.passing_flash_color),
|
||||
time_width=0.2
|
||||
line.set_color(self.passing_flash_color), time_width=0.2
|
||||
)
|
||||
animations.append(anim)
|
||||
|
||||
return AnimationGroup(*animations)
|
||||
return AnimationGroup(*animations)
|
||||
|
@ -2,12 +2,19 @@ from manim import *
|
||||
from manim_ml.probability import GaussianDistribution
|
||||
from manim_ml.neural_network.layers.parent_layers import VGroupNeuralNetworkLayer
|
||||
|
||||
|
||||
class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
"""NeuralNetwork embedding object that can show probability distributions"""
|
||||
|
||||
def __init__(self, point_radius=0.02, mean = np.array([0, 0]),
|
||||
covariance=np.array([[1.0, 0], [0, 1.0]]), dist_theme="gaussian",
|
||||
paired_query_mode=False, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
point_radius=0.02,
|
||||
mean=np.array([0, 0]),
|
||||
covariance=np.array([[1.0, 0], [0, 1.0]]),
|
||||
dist_theme="gaussian",
|
||||
paired_query_mode=False,
|
||||
**kwargs
|
||||
):
|
||||
super(VGroupNeuralNetworkLayer, self).__init__(**kwargs)
|
||||
self.gaussian_distributions = VGroup()
|
||||
self.add(self.gaussian_distributions)
|
||||
@ -20,14 +27,8 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
y_length=0.8,
|
||||
x_range=(-1.4, 1.4),
|
||||
y_range=(-1.8, 1.8),
|
||||
x_axis_config={
|
||||
"include_ticks": False,
|
||||
"stroke_width": 0.0
|
||||
},
|
||||
y_axis_config={
|
||||
"include_ticks": False,
|
||||
"stroke_width": 0.0
|
||||
}
|
||||
x_axis_config={"include_ticks": False, "stroke_width": 0.0},
|
||||
y_axis_config={"include_ticks": False, "stroke_width": 0.0},
|
||||
)
|
||||
self.add(self.axes)
|
||||
self.axes.move_to(self.get_center())
|
||||
@ -35,7 +36,9 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
self.point_cloud = self.construct_gaussian_point_cloud(mean, covariance)
|
||||
self.add(self.point_cloud)
|
||||
# Make latent distribution
|
||||
self.latent_distribution = GaussianDistribution(self.axes, mean=mean, cov=covariance) # Use defaults
|
||||
self.latent_distribution = GaussianDistribution(
|
||||
self.axes, mean=mean, cov=covariance
|
||||
) # Use defaults
|
||||
|
||||
def add_gaussian_distribution(self, gaussian_distribution):
|
||||
"""Adds given GaussianDistribution to the list"""
|
||||
@ -57,15 +60,16 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
point = np.random.multivariate_normal(mean, cov)
|
||||
# Make dot at correct location
|
||||
location = self.axes.coords_to_point(point[0], point[1])
|
||||
|
||||
|
||||
return location
|
||||
|
||||
def get_distribution_location(self):
|
||||
"""Returns mean of latent distribution in axes frame"""
|
||||
return self.axes.coords_to_point(self.latent_distribution.mean)
|
||||
|
||||
def construct_gaussian_point_cloud(self, mean, covariance, point_color=WHITE,
|
||||
num_points=400):
|
||||
def construct_gaussian_point_cloud(
|
||||
self, mean, covariance, point_color=WHITE, num_points=400
|
||||
):
|
||||
"""Plots points sampled from a Gaussian with the given mean and covariance"""
|
||||
# Sample points from a Gaussian
|
||||
np.random.seed(5)
|
||||
@ -74,7 +78,7 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
point_dots = VGroup()
|
||||
for point in points:
|
||||
point_location = self.axes.coords_to_point(*point)
|
||||
dot = Dot(point_location, color=point_color, radius=self.point_radius/2)
|
||||
dot = Dot(point_location, color=point_color, radius=self.point_radius / 2)
|
||||
dot.set_z_index(-1)
|
||||
point_dots.add(dot)
|
||||
|
||||
@ -82,36 +86,27 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
|
||||
def make_forward_pass_animation(self, layer_args={}, **kwargs):
|
||||
"""Forward pass animation"""
|
||||
animations = []
|
||||
animations = []
|
||||
if "triplet_args" in layer_args:
|
||||
triplet_args = layer_args["triplet_args"]
|
||||
positive_dist_args = triplet_args["positive_dist"]
|
||||
negative_dist_args = triplet_args["negative_dist"]
|
||||
anchor_dist_args = triplet_args["anchor_dist"]
|
||||
# Create each dist
|
||||
anchor_dist = GaussianDistribution(
|
||||
self.axes,
|
||||
**anchor_dist_args
|
||||
)
|
||||
anchor_dist = GaussianDistribution(self.axes, **anchor_dist_args)
|
||||
animations.append(Create(anchor_dist))
|
||||
|
||||
positive_dist = GaussianDistribution(
|
||||
self.axes,
|
||||
**positive_dist_args
|
||||
)
|
||||
positive_dist = GaussianDistribution(self.axes, **positive_dist_args)
|
||||
animations.append(Create(positive_dist))
|
||||
|
||||
negative_dist = GaussianDistribution(
|
||||
self.axes,
|
||||
**negative_dist_args
|
||||
)
|
||||
negative_dist = GaussianDistribution(self.axes, **negative_dist_args)
|
||||
animations.append(Create(negative_dist))
|
||||
# Draw edges in between anchor and positive, anchor and negative
|
||||
anchor_positive = Line(
|
||||
anchor_dist.get_center(),
|
||||
positive_dist.get_center(),
|
||||
color=GOLD,
|
||||
stroke_width=DEFAULT_STROKE_WIDTH/2
|
||||
stroke_width=DEFAULT_STROKE_WIDTH / 2,
|
||||
)
|
||||
anchor_positive.set_z_index(3)
|
||||
animations.append(Create(anchor_positive))
|
||||
@ -120,7 +115,7 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
anchor_dist.get_center(),
|
||||
negative_dist.get_center(),
|
||||
color=GOLD,
|
||||
stroke_width=DEFAULT_STROKE_WIDTH/2
|
||||
stroke_width=DEFAULT_STROKE_WIDTH / 2,
|
||||
)
|
||||
anchor_negative.set_z_index(3)
|
||||
|
||||
@ -132,14 +127,13 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
if "scale_factor" in layer_args:
|
||||
scale_factor = layer_args["scale_factor"]
|
||||
self.latent_distribution = GaussianDistribution(
|
||||
self.axes,
|
||||
**layer_args["dist_args"]
|
||||
self.axes, **layer_args["dist_args"]
|
||||
).scale(scale_factor)
|
||||
else:
|
||||
# Make ellipse object corresponding to the latent distribution
|
||||
# self.latent_distribution = GaussianDistribution(
|
||||
# self.axes,
|
||||
# dist_theme=self.dist_theme,
|
||||
# self.axes,
|
||||
# dist_theme=self.dist_theme,
|
||||
# cov=np.array([[0.8, 0], [0.0, 0.8]])
|
||||
# )
|
||||
pass
|
||||
@ -153,15 +147,9 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
positive_dist_args = layer_args["positive_dist_args"]
|
||||
negative_dist_args = layer_args["negative_dist_args"]
|
||||
# Handle logic for embedding a paired query into the embedding layer
|
||||
positive_dist = GaussianDistribution(
|
||||
self.axes,
|
||||
**positive_dist_args
|
||||
)
|
||||
positive_dist = GaussianDistribution(self.axes, **positive_dist_args)
|
||||
self.gaussian_distributions.add(positive_dist)
|
||||
negative_dist = GaussianDistribution(
|
||||
self.axes,
|
||||
**negative_dist_args
|
||||
)
|
||||
negative_dist = GaussianDistribution(self.axes, **negative_dist_args)
|
||||
self.gaussian_distributions.add(negative_dist)
|
||||
|
||||
animations.append(Create(positive_dist))
|
||||
@ -182,8 +170,8 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer):
|
||||
|
||||
return point_animation
|
||||
|
||||
class NeuralNetworkEmbeddingTestScene(Scene):
|
||||
|
||||
class NeuralNetworkEmbeddingTestScene(Scene):
|
||||
def construct(self):
|
||||
nne = EmbeddingLayer()
|
||||
mean = np.array([0, 0])
|
||||
@ -195,4 +183,4 @@ class NeuralNetworkEmbeddingTestScene(Scene):
|
||||
gaussian = nne.construct_gaussian_distribution(mean, cov)
|
||||
nne.add(gaussian)
|
||||
|
||||
self.add(nne)
|
||||
self.add(nne)
|
||||
|
@ -3,15 +3,28 @@ from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer
|
||||
from manim_ml.neural_network.layers.embedding import EmbeddingLayer
|
||||
|
||||
|
||||
class EmbeddingToFeedForward(ConnectiveLayer):
|
||||
"""Feed Forward to Embedding Layer"""
|
||||
|
||||
input_class = EmbeddingLayer
|
||||
output_class = FeedForwardLayer
|
||||
|
||||
def __init__(self, input_layer, output_layer, animation_dot_color=RED, dot_radius=0.03,
|
||||
**kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=EmbeddingLayer, output_class=FeedForwardLayer,
|
||||
**kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
animation_dot_color=RED,
|
||||
dot_radius=0.03,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=EmbeddingLayer,
|
||||
output_class=FeedForwardLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.feed_forward_layer = output_layer
|
||||
self.embedding_layer = input_layer
|
||||
self.animation_dot_color = animation_dot_color
|
||||
@ -26,7 +39,9 @@ class EmbeddingToFeedForward(ConnectiveLayer):
|
||||
# Move the dots to the centers of each of the nodes in the FeedForwardLayer
|
||||
dots = []
|
||||
for node in self.feed_forward_layer.node_group:
|
||||
new_dot = Dot(location, radius=self.dot_radius, color=self.animation_dot_color)
|
||||
new_dot = Dot(
|
||||
location, radius=self.dot_radius, color=self.animation_dot_color
|
||||
)
|
||||
per_node_succession = Succession(
|
||||
Create(new_dot),
|
||||
new_dot.animate.move_to(node.get_center()),
|
||||
@ -46,4 +61,3 @@ class EmbeddingToFeedForward(ConnectiveLayer):
|
||||
@override_animation(Create)
|
||||
def _create_override(self, **kwargs):
|
||||
return AnimationGroup()
|
||||
|
@ -1,13 +1,25 @@
|
||||
from manim import *
|
||||
from manim_ml.neural_network.layers.parent_layers import VGroupNeuralNetworkLayer
|
||||
|
||||
|
||||
class FeedForwardLayer(VGroupNeuralNetworkLayer):
|
||||
"""Handles rendering a layer for a neural network"""
|
||||
|
||||
def __init__(self, num_nodes, layer_buffer=SMALL_BUFF/2, node_radius=0.08,
|
||||
node_color=BLUE, node_outline_color=WHITE, rectangle_color=WHITE,
|
||||
node_spacing=0.3, rectangle_fill_color=BLACK, node_stroke_width=2.0,
|
||||
rectangle_stroke_width=2.0, animation_dot_color=RED, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
num_nodes,
|
||||
layer_buffer=SMALL_BUFF / 2,
|
||||
node_radius=0.08,
|
||||
node_color=BLUE,
|
||||
node_outline_color=WHITE,
|
||||
rectangle_color=WHITE,
|
||||
node_spacing=0.3,
|
||||
rectangle_fill_color=BLACK,
|
||||
node_stroke_width=2.0,
|
||||
rectangle_stroke_width=2.0,
|
||||
animation_dot_color=RED,
|
||||
**kwargs
|
||||
):
|
||||
super(VGroupNeuralNetworkLayer, self).__init__(**kwargs)
|
||||
self.num_nodes = num_nodes
|
||||
self.layer_buffer = layer_buffer
|
||||
@ -29,8 +41,11 @@ class FeedForwardLayer(VGroupNeuralNetworkLayer):
|
||||
"""Creates the neural network layer"""
|
||||
# Add Nodes
|
||||
for node_number in range(self.num_nodes):
|
||||
node_object = Circle(radius=self.node_radius, color=self.node_color,
|
||||
stroke_width=self.node_stroke_width)
|
||||
node_object = Circle(
|
||||
radius=self.node_radius,
|
||||
color=self.node_color,
|
||||
stroke_width=self.node_stroke_width,
|
||||
)
|
||||
self.node_group.add(node_object)
|
||||
# Space the nodes
|
||||
# Assumes Vertical orientation
|
||||
@ -38,17 +53,24 @@ class FeedForwardLayer(VGroupNeuralNetworkLayer):
|
||||
location = node_index * self.node_spacing
|
||||
node_object.move_to([0, location, 0])
|
||||
# Create Surrounding Rectangle
|
||||
self.surrounding_rectangle = SurroundingRectangle(self.node_group, color=self.rectangle_color,
|
||||
fill_color=self.rectangle_fill_color, fill_opacity=1.0,
|
||||
buff=self.layer_buffer, stroke_width=self.rectangle_stroke_width)
|
||||
self.surrounding_rectangle.set_z_index(1)
|
||||
self.surrounding_rectangle = SurroundingRectangle(
|
||||
self.node_group,
|
||||
color=self.rectangle_color,
|
||||
fill_color=self.rectangle_fill_color,
|
||||
fill_opacity=1.0,
|
||||
buff=self.layer_buffer,
|
||||
stroke_width=self.rectangle_stroke_width,
|
||||
)
|
||||
self.surrounding_rectangle.set_z_index(1)
|
||||
# Add the objects to the class
|
||||
self.add(self.surrounding_rectangle, self.node_group)
|
||||
|
||||
def make_forward_pass_animation(self, layer_args={}, **kwargs):
|
||||
# make highlight animation
|
||||
succession = Succession(
|
||||
ApplyMethod(self.node_group.set_color, self.animation_dot_color, run_time=0.25),
|
||||
ApplyMethod(
|
||||
self.node_group.set_color, self.animation_dot_color, run_time=0.25
|
||||
),
|
||||
Wait(1.0),
|
||||
ApplyMethod(self.node_group.set_color, self.node_color, run_time=0.25),
|
||||
)
|
||||
@ -65,4 +87,4 @@ class FeedForwardLayer(VGroupNeuralNetworkLayer):
|
||||
animations.append(Create(node))
|
||||
|
||||
animation_group = AnimationGroup(*animations, lag_ratio=0.0)
|
||||
return animation_group
|
||||
return animation_group
|
||||
|
@ -3,15 +3,28 @@ from manim_ml.neural_network.layers.embedding import EmbeddingLayer
|
||||
from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer
|
||||
|
||||
|
||||
class FeedForwardToEmbedding(ConnectiveLayer):
|
||||
"""Feed Forward to Embedding Layer"""
|
||||
|
||||
input_class = FeedForwardLayer
|
||||
output_class = EmbeddingLayer
|
||||
|
||||
def __init__(self, input_layer, output_layer, animation_dot_color=RED, dot_radius=0.03,
|
||||
**kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=FeedForwardLayer, output_class=EmbeddingLayer,
|
||||
**kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
animation_dot_color=RED,
|
||||
dot_radius=0.03,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=FeedForwardLayer,
|
||||
output_class=EmbeddingLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.feed_forward_layer = input_layer
|
||||
self.embedding_layer = output_layer
|
||||
self.animation_dot_color = animation_dot_color
|
||||
@ -27,7 +40,11 @@ class FeedForwardToEmbedding(ConnectiveLayer):
|
||||
# Move the dots to the centers of each of the nodes in the FeedForwardLayer
|
||||
dots = []
|
||||
for node in self.feed_forward_layer.node_group:
|
||||
new_dot = Dot(node.get_center(), radius=self.dot_radius, color=self.animation_dot_color)
|
||||
new_dot = Dot(
|
||||
node.get_center(),
|
||||
radius=self.dot_radius,
|
||||
color=self.animation_dot_color,
|
||||
)
|
||||
per_node_succession = Succession(
|
||||
Create(new_dot),
|
||||
new_dot.animate.move_to(location),
|
||||
@ -50,4 +67,3 @@ class FeedForwardToEmbedding(ConnectiveLayer):
|
||||
@override_animation(Create)
|
||||
def _create_override(self, **kwargs):
|
||||
return AnimationGroup()
|
||||
|
||||
|
@ -5,16 +5,32 @@ from manim import *
|
||||
from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer
|
||||
|
||||
|
||||
class FeedForwardToFeedForward(ConnectiveLayer):
|
||||
"""Layer for connecting FeedForward layer to FeedForwardLayer"""
|
||||
|
||||
input_class = FeedForwardLayer
|
||||
output_class = FeedForwardLayer
|
||||
|
||||
def __init__(self, input_layer, output_layer, passing_flash=True,
|
||||
dot_radius=0.05, animation_dot_color=RED, edge_color=WHITE,
|
||||
edge_width=1.5, camera=None, **kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=FeedForwardLayer, output_class=FeedForwardLayer,
|
||||
**kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
passing_flash=True,
|
||||
dot_radius=0.05,
|
||||
animation_dot_color=RED,
|
||||
edge_color=WHITE,
|
||||
edge_width=1.5,
|
||||
camera=None,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=FeedForwardLayer,
|
||||
output_class=FeedForwardLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.passing_flash = passing_flash
|
||||
self.edge_color = edge_color
|
||||
self.dot_radius = dot_radius
|
||||
@ -29,8 +45,12 @@ class FeedForwardToFeedForward(ConnectiveLayer):
|
||||
edges = []
|
||||
for node_i in self.input_layer.node_group:
|
||||
for node_j in self.output_layer.node_group:
|
||||
line = Line(node_i.get_center(), node_j.get_center(),
|
||||
color=self.edge_color, stroke_width=self.edge_width)
|
||||
line = Line(
|
||||
node_i.get_center(),
|
||||
node_j.get_center(),
|
||||
color=self.edge_color,
|
||||
stroke_width=self.edge_width,
|
||||
)
|
||||
edges.append(line)
|
||||
|
||||
edges = VGroup(*edges)
|
||||
@ -39,7 +59,7 @@ class FeedForwardToFeedForward(ConnectiveLayer):
|
||||
@override_animation(FadeOut)
|
||||
def _fadeout_animation(self):
|
||||
animations = []
|
||||
|
||||
|
||||
for edge in self.edges:
|
||||
animations.append(FadeOut(edge))
|
||||
|
||||
@ -53,25 +73,19 @@ class FeedForwardToFeedForward(ConnectiveLayer):
|
||||
dots = []
|
||||
for edge in self.edges:
|
||||
dot = Dot(
|
||||
color=self.animation_dot_color,
|
||||
fill_opacity=1.0,
|
||||
radius=self.dot_radius
|
||||
)
|
||||
color=self.animation_dot_color, fill_opacity=1.0, radius=self.dot_radius
|
||||
)
|
||||
# Add to dots group
|
||||
dots.append(dot)
|
||||
# Make the animation
|
||||
if self.passing_flash:
|
||||
copy_edge = edge.copy()
|
||||
anim = ShowPassingFlash(
|
||||
copy_edge.set_color(self.animation_dot_color),
|
||||
time_width=0.2
|
||||
copy_edge.set_color(self.animation_dot_color), time_width=0.2
|
||||
)
|
||||
else:
|
||||
anim = MoveAlongPath(
|
||||
dot,
|
||||
edge,
|
||||
run_time=run_time,
|
||||
rate_function=sigmoid
|
||||
dot, edge, run_time=run_time, rate_function=sigmoid
|
||||
)
|
||||
path_animations.append(anim)
|
||||
|
||||
@ -83,12 +97,7 @@ class FeedForwardToFeedForward(ConnectiveLayer):
|
||||
|
||||
return path_animations
|
||||
|
||||
def modify_edge_colors(
|
||||
self,
|
||||
colors=None,
|
||||
magnitudes=None,
|
||||
color_scheme="inferno"
|
||||
):
|
||||
def modify_edge_colors(self, colors=None, magnitudes=None, color_scheme="inferno"):
|
||||
"""Changes the colors of edges"""
|
||||
# TODO implement
|
||||
pass
|
||||
|
@ -3,18 +3,31 @@ from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.image import ImageLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer
|
||||
|
||||
|
||||
class FeedForwardToImage(ConnectiveLayer):
|
||||
"""Image Layer to FeedForward layer"""
|
||||
|
||||
input_class = FeedForwardLayer
|
||||
output_class = ImageLayer
|
||||
|
||||
def __init__(self, input_layer, output_layer, animation_dot_color=RED,
|
||||
dot_radius=0.05, **kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=FeedForwardLayer, output_class=ImageLayer,
|
||||
**kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
animation_dot_color=RED,
|
||||
dot_radius=0.05,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=FeedForwardLayer,
|
||||
output_class=ImageLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.animation_dot_color = animation_dot_color
|
||||
self.dot_radius = dot_radius
|
||||
|
||||
|
||||
self.feed_forward_layer = input_layer
|
||||
self.image_layer = output_layer
|
||||
|
||||
@ -23,9 +36,13 @@ class FeedForwardToImage(ConnectiveLayer):
|
||||
animations = []
|
||||
image_mobject = self.image_layer.image_mobject
|
||||
# Move the dots to the centers of each of the nodes in the FeedForwardLayer
|
||||
image_location = image_mobject.get_center()
|
||||
image_location = image_mobject.get_center()
|
||||
for node in self.feed_forward_layer.node_group:
|
||||
new_dot = Dot(node.get_center(), radius=self.dot_radius, color=self.animation_dot_color)
|
||||
new_dot = Dot(
|
||||
node.get_center(),
|
||||
radius=self.dot_radius,
|
||||
color=self.animation_dot_color,
|
||||
)
|
||||
per_node_succession = Succession(
|
||||
Create(new_dot),
|
||||
new_dot.animate.move_to(image_location),
|
||||
@ -37,4 +54,4 @@ class FeedForwardToImage(ConnectiveLayer):
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self):
|
||||
return AnimationGroup()
|
||||
return AnimationGroup()
|
||||
|
@ -3,18 +3,31 @@ from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer
|
||||
from manim_ml.neural_network.layers.vector import VectorLayer
|
||||
|
||||
|
||||
class FeedForwardToVector(ConnectiveLayer):
|
||||
"""Image Layer to FeedForward layer"""
|
||||
|
||||
input_class = FeedForwardLayer
|
||||
output_class = VectorLayer
|
||||
|
||||
def __init__(self, input_layer, output_layer, animation_dot_color=RED,
|
||||
dot_radius=0.05, **kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=FeedForwardLayer, output_class=VectorLayer,
|
||||
**kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
animation_dot_color=RED,
|
||||
dot_radius=0.05,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=FeedForwardLayer,
|
||||
output_class=VectorLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.animation_dot_color = animation_dot_color
|
||||
self.dot_radius = dot_radius
|
||||
|
||||
|
||||
self.feed_forward_layer = input_layer
|
||||
self.vector_layer = output_layer
|
||||
|
||||
@ -22,9 +35,13 @@ class FeedForwardToVector(ConnectiveLayer):
|
||||
"""Makes dots diverge from the given location and move to the feed forward nodes decoder"""
|
||||
animations = []
|
||||
# Move the dots to the centers of each of the nodes in the FeedForwardLayer
|
||||
destination = self.vector_layer.get_center()
|
||||
destination = self.vector_layer.get_center()
|
||||
for node in self.feed_forward_layer.node_group:
|
||||
new_dot = Dot(node.get_center(), radius=self.dot_radius, color=self.animation_dot_color)
|
||||
new_dot = Dot(
|
||||
node.get_center(),
|
||||
radius=self.dot_radius,
|
||||
color=self.animation_dot_color,
|
||||
)
|
||||
per_node_succession = Succession(
|
||||
Create(new_dot),
|
||||
new_dot.animate.move_to(destination),
|
||||
@ -36,4 +53,4 @@ class FeedForwardToVector(ConnectiveLayer):
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self):
|
||||
return AnimationGroup()
|
||||
return AnimationGroup()
|
||||
|
@ -4,6 +4,7 @@ from manim_ml.neural_network.layers.parent_layers import NeuralNetworkLayer
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
class ImageLayer(NeuralNetworkLayer):
|
||||
"""Single Image Layer for Neural Network"""
|
||||
|
||||
@ -18,7 +19,9 @@ class ImageLayer(NeuralNetworkLayer):
|
||||
elif len(np.shape(self.numpy_image)) == 3:
|
||||
# Assumed RGB
|
||||
self.num_channels = 3
|
||||
self.image_mobject = ImageMobject(self.numpy_image).scale_to_fit_height(height)
|
||||
self.image_mobject = ImageMobject(self.numpy_image).scale_to_fit_height(
|
||||
height
|
||||
)
|
||||
self.add(self.image_mobject)
|
||||
|
||||
@classmethod
|
||||
@ -44,11 +47,11 @@ class ImageLayer(NeuralNetworkLayer):
|
||||
|
||||
def make_forward_pass_animation(self, layer_args={}, **kwargs):
|
||||
return AnimationGroup()
|
||||
|
||||
|
||||
# def move_to(self, location):
|
||||
# """Override of move to"""
|
||||
# self.image_mobject.move_to(location)
|
||||
|
||||
|
||||
def get_right(self):
|
||||
"""Override get right"""
|
||||
return self.image_mobject.get_right()
|
||||
@ -59,4 +62,4 @@ class ImageLayer(NeuralNetworkLayer):
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self.image_mobject.height
|
||||
return self.image_mobject.height
|
||||
|
@ -3,25 +3,27 @@ import numpy as np
|
||||
from manim import *
|
||||
from manim_ml.neural_network.layers.convolutional3d import Convolutional3DLayer
|
||||
from manim_ml.neural_network.layers.image import ImageLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ThreeDLayer, VGroupNeuralNetworkLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import (
|
||||
ThreeDLayer,
|
||||
VGroupNeuralNetworkLayer,
|
||||
)
|
||||
from manim_ml.gridded_rectangle import GriddedRectangle
|
||||
|
||||
|
||||
class ImageToConvolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
"""Handles rendering a convolutional layer for a nn"""
|
||||
|
||||
input_class = ImageLayer
|
||||
output_class = Convolutional3DLayer
|
||||
|
||||
def __init__(self, input_layer: ImageLayer, output_layer: Convolutional3DLayer, **kwargs):
|
||||
def __init__(
|
||||
self, input_layer: ImageLayer, output_layer: Convolutional3DLayer, **kwargs
|
||||
):
|
||||
super().__init__(input_layer, output_layer, **kwargs)
|
||||
self.input_layer = input_layer
|
||||
self.output_layer = output_layer
|
||||
|
||||
def make_forward_pass_animation(
|
||||
self,
|
||||
run_time=5,
|
||||
layer_args={},
|
||||
**kwargs
|
||||
):
|
||||
def make_forward_pass_animation(self, run_time=5, layer_args={}, **kwargs):
|
||||
"""Maps image to convolutional layer"""
|
||||
# Transform the image from the input layer to the
|
||||
num_image_channels = self.input_layer.num_channels
|
||||
@ -30,7 +32,9 @@ class ImageToConvolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
elif num_image_channels == 1:
|
||||
return self.grayscale_image_animation()
|
||||
else:
|
||||
raise Exception(f"Unrecognized number of image channels: {num_image_channels}")
|
||||
raise Exception(
|
||||
f"Unrecognized number of image channels: {num_image_channels}"
|
||||
)
|
||||
|
||||
def rbg_image_animation(self):
|
||||
"""Handles animation for 3 channel image"""
|
||||
@ -53,7 +57,7 @@ class ImageToConvolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
ThreeDLayer.rotation_angle,
|
||||
ThreeDLayer.rotation_axis,
|
||||
image_mobject.get_center(),
|
||||
run_time=0.5
|
||||
run_time=0.5,
|
||||
)
|
||||
"""
|
||||
x_rotation = ApplyMethod(
|
||||
@ -72,25 +76,14 @@ class ImageToConvolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
)
|
||||
"""
|
||||
# Set opacity
|
||||
set_opacity = ApplyMethod(
|
||||
image_mobject.set_opacity,
|
||||
0.2,
|
||||
run_time=0.5
|
||||
)
|
||||
# Scale the max of width or height to the
|
||||
set_opacity = ApplyMethod(image_mobject.set_opacity, 0.2, run_time=0.5)
|
||||
# Scale the max of width or height to the
|
||||
# width of the feature_map
|
||||
max_width_height = max(image_mobject.width, image_mobject.height)
|
||||
scale_factor = target_feature_map.rectangle_width / max_width_height
|
||||
scale_image = ApplyMethod(
|
||||
image_mobject.scale,
|
||||
scale_factor,
|
||||
run_time=0.5
|
||||
)
|
||||
scale_image = ApplyMethod(image_mobject.scale, scale_factor, run_time=0.5)
|
||||
# Move the image
|
||||
move_image = ApplyMethod(
|
||||
image_mobject.move_to,
|
||||
target_feature_map
|
||||
)
|
||||
move_image = ApplyMethod(image_mobject.move_to, target_feature_map)
|
||||
# Compose the animations
|
||||
animation = Succession(
|
||||
rotation,
|
||||
@ -99,10 +92,10 @@ class ImageToConvolutional3DLayer(VGroupNeuralNetworkLayer, ThreeDLayer):
|
||||
move_image,
|
||||
)
|
||||
return animation
|
||||
|
||||
|
||||
def scale(self, scale_factor, **kwargs):
|
||||
super().scale(scale_factor, **kwargs)
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self, **kwargs):
|
||||
return AnimationGroup()
|
||||
return AnimationGroup()
|
||||
|
@ -3,15 +3,28 @@ from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.image import ImageLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer
|
||||
|
||||
|
||||
class ImageToFeedForward(ConnectiveLayer):
|
||||
"""Image Layer to FeedForward layer"""
|
||||
|
||||
input_class = ImageLayer
|
||||
output_class = FeedForwardLayer
|
||||
|
||||
def __init__(self, input_layer, output_layer, animation_dot_color=RED,
|
||||
dot_radius=0.05, **kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=ImageLayer, output_class=FeedForwardLayer,
|
||||
**kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
animation_dot_color=RED,
|
||||
dot_radius=0.05,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=ImageLayer,
|
||||
output_class=FeedForwardLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.animation_dot_color = animation_dot_color
|
||||
self.dot_radius = dot_radius
|
||||
|
||||
@ -24,19 +37,21 @@ class ImageToFeedForward(ConnectiveLayer):
|
||||
dots = []
|
||||
image_mobject = self.image_layer.image_mobject
|
||||
# Move the dots to the centers of each of the nodes in the FeedForwardLayer
|
||||
image_location = image_mobject.get_center()
|
||||
image_location = image_mobject.get_center()
|
||||
for node in self.feed_forward_layer.node_group:
|
||||
new_dot = Dot(image_location, radius=self.dot_radius, color=self.animation_dot_color)
|
||||
new_dot = Dot(
|
||||
image_location, radius=self.dot_radius, color=self.animation_dot_color
|
||||
)
|
||||
per_node_succession = Succession(
|
||||
Create(new_dot),
|
||||
new_dot.animate.move_to(node.get_center()),
|
||||
)
|
||||
animations.append(per_node_succession)
|
||||
dots.append(new_dot)
|
||||
|
||||
|
||||
animation_group = AnimationGroup(*animations)
|
||||
return animation_group
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self):
|
||||
return AnimationGroup()
|
||||
return AnimationGroup()
|
||||
|
@ -3,11 +3,13 @@ from manim_ml.neural_network.layers.parent_layers import NeuralNetworkLayer
|
||||
from manim_ml.image import GrayscaleImageMobject, LabeledColorImage
|
||||
import numpy as np
|
||||
|
||||
|
||||
class PairedQueryLayer(NeuralNetworkLayer):
|
||||
"""Paired Query Layer"""
|
||||
|
||||
def __init__(self, positive, negative, stroke_width=5, font_size=18,
|
||||
spacing=0.5, **kwargs):
|
||||
def __init__(
|
||||
self, positive, negative, stroke_width=5, font_size=18, spacing=0.5, **kwargs
|
||||
):
|
||||
super().__init__(**kwargs)
|
||||
self.positive = positive
|
||||
self.negative = negative
|
||||
@ -19,7 +21,7 @@ class PairedQueryLayer(NeuralNetworkLayer):
|
||||
self.assets = self.make_assets()
|
||||
self.add(self.assets)
|
||||
self.add(self.title)
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_paths(cls, positive_path, negative_path, grayscale=True, **kwargs):
|
||||
"""Creates a query using the paths"""
|
||||
@ -37,23 +39,23 @@ class PairedQueryLayer(NeuralNetworkLayer):
|
||||
|
||||
def make_assets(self):
|
||||
"""
|
||||
Constructs the assets needed for a query layer
|
||||
Constructs the assets needed for a query layer
|
||||
"""
|
||||
# Handle positive
|
||||
positive_group = LabeledColorImage(
|
||||
self.positive,
|
||||
self.positive,
|
||||
color=BLUE,
|
||||
label="Positive",
|
||||
font_size=self.font_size,
|
||||
stroke_width=self.stroke_width
|
||||
stroke_width=self.stroke_width,
|
||||
)
|
||||
# Handle negative
|
||||
negative_group = LabeledColorImage(
|
||||
self.negative,
|
||||
self.negative,
|
||||
color=RED,
|
||||
label="Negative",
|
||||
label="Negative",
|
||||
font_size=self.font_size,
|
||||
stroke_width=self.stroke_width
|
||||
stroke_width=self.stroke_width,
|
||||
)
|
||||
# Distribute the groups uniformly vertically
|
||||
assets = Group(positive_group, negative_group)
|
||||
@ -68,4 +70,4 @@ class PairedQueryLayer(NeuralNetworkLayer):
|
||||
|
||||
def make_forward_pass_animation(self, layer_args={}, **kwargs):
|
||||
"""Forward pass for query"""
|
||||
return AnimationGroup()
|
||||
return AnimationGroup()
|
||||
|
@ -3,14 +3,28 @@ from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.paired_query import PairedQueryLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer
|
||||
|
||||
|
||||
class PairedQueryToFeedForward(ConnectiveLayer):
|
||||
"""PairedQuery layer to FeedForward layer"""
|
||||
|
||||
input_class = PairedQueryLayer
|
||||
output_class = FeedForwardLayer
|
||||
|
||||
def __init__(self, input_layer, output_layer, animation_dot_color=RED, dot_radius=0.02, **kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=PairedQueryLayer, output_class=FeedForwardLayer,
|
||||
**kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
animation_dot_color=RED,
|
||||
dot_radius=0.02,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=PairedQueryLayer,
|
||||
output_class=FeedForwardLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.animation_dot_color = animation_dot_color
|
||||
self.dot_radius = dot_radius
|
||||
|
||||
@ -26,22 +40,26 @@ class PairedQueryToFeedForward(ConnectiveLayer):
|
||||
image_animations = []
|
||||
dots = []
|
||||
# Move dots from each image to the centers of each of the nodes in the FeedForwardLayer
|
||||
image_location = image_mobject.get_center()
|
||||
image_location = image_mobject.get_center()
|
||||
for node in self.feed_forward_layer.node_group:
|
||||
new_dot = Dot(image_location, radius=self.dot_radius, color=self.animation_dot_color)
|
||||
new_dot = Dot(
|
||||
image_location,
|
||||
radius=self.dot_radius,
|
||||
color=self.animation_dot_color,
|
||||
)
|
||||
per_node_succession = Succession(
|
||||
Create(new_dot),
|
||||
new_dot.animate.move_to(node.get_center()),
|
||||
)
|
||||
image_animations.append(per_node_succession)
|
||||
dots.append(new_dot)
|
||||
|
||||
|
||||
animations.append(AnimationGroup(*image_animations))
|
||||
|
||||
|
||||
animation_group = AnimationGroup(*animations)
|
||||
|
||||
|
||||
return animation_group
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self):
|
||||
return AnimationGroup()
|
||||
return AnimationGroup()
|
||||
|
@ -1,16 +1,14 @@
|
||||
from manim import *
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class NeuralNetworkLayer(ABC, Group):
|
||||
"""Abstract Neural Network Layer class"""
|
||||
|
||||
def __init__(self, text=None, *args, **kwargs):
|
||||
super(Group, self).__init__()
|
||||
self.title_text = kwargs["title"] if "title" in kwargs else " "
|
||||
self.title = Text(
|
||||
self.title_text,
|
||||
font_size=DEFAULT_FONT_SIZE/3
|
||||
).scale(0.6)
|
||||
self.title = Text(self.title_text, font_size=DEFAULT_FONT_SIZE / 3).scale(0.6)
|
||||
self.title.next_to(self, UP, 1.2)
|
||||
# self.add(self.title)
|
||||
|
||||
@ -25,28 +23,31 @@ class NeuralNetworkLayer(ABC, Group):
|
||||
def __repr__(self):
|
||||
return f"{type(self).__name__}"
|
||||
|
||||
class VGroupNeuralNetworkLayer(NeuralNetworkLayer):
|
||||
|
||||
class VGroupNeuralNetworkLayer(NeuralNetworkLayer):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# self.camera = camera
|
||||
|
||||
@abstractmethod
|
||||
def make_forward_pass_animation(self, **kwargs):
|
||||
pass
|
||||
pass
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self):
|
||||
return super()._create_override()
|
||||
|
||||
|
||||
class ThreeDLayer(ABC):
|
||||
"""Abstract class for 3D layers"""
|
||||
|
||||
# Angle of ThreeD layers is static context
|
||||
three_d_x_rotation = 90 * DEGREES #-90 * DEGREES
|
||||
three_d_y_rotation = 0 * DEGREES # -10 * DEGREES
|
||||
three_d_x_rotation = 90 * DEGREES # -90 * DEGREES
|
||||
three_d_y_rotation = 0 * DEGREES # -10 * DEGREES
|
||||
rotation_angle = 60 * DEGREES
|
||||
rotation_axis = [0.0, 0.9, 0.0]
|
||||
|
||||
|
||||
class ConnectiveLayer(VGroupNeuralNetworkLayer):
|
||||
"""Forward pass animation for a given pair of layers"""
|
||||
|
||||
@ -67,6 +68,7 @@ class ConnectiveLayer(VGroupNeuralNetworkLayer):
|
||||
def _create_override(self):
|
||||
return super()._create_override()
|
||||
|
||||
|
||||
class BlankConnective(ConnectiveLayer):
|
||||
"""Connective layer to be used when the given pair of layers is undefined"""
|
||||
|
||||
@ -78,4 +80,4 @@ class BlankConnective(ConnectiveLayer):
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self):
|
||||
return super()._create_override()
|
||||
return super()._create_override()
|
||||
|
@ -3,11 +3,20 @@ from manim_ml.neural_network.layers import NeuralNetworkLayer
|
||||
from manim_ml.image import GrayscaleImageMobject, LabeledColorImage
|
||||
import numpy as np
|
||||
|
||||
|
||||
class TripletLayer(NeuralNetworkLayer):
|
||||
"""Shows triplet images"""
|
||||
|
||||
def __init__(self, anchor, positive, negative, stroke_width=5,
|
||||
font_size=22, buff=0.2, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
anchor,
|
||||
positive,
|
||||
negative,
|
||||
stroke_width=5,
|
||||
font_size=22,
|
||||
buff=0.2,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(**kwargs)
|
||||
self.anchor = anchor
|
||||
self.positive = positive
|
||||
@ -19,10 +28,17 @@ class TripletLayer(NeuralNetworkLayer):
|
||||
# Make the assets
|
||||
self.assets = self.make_assets()
|
||||
self.add(self.assets)
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_paths(cls, anchor_path, positive_path, negative_path, grayscale=True,
|
||||
font_size=22, buff=0.2):
|
||||
def from_paths(
|
||||
cls,
|
||||
anchor_path,
|
||||
positive_path,
|
||||
negative_path,
|
||||
grayscale=True,
|
||||
font_size=22,
|
||||
buff=0.2,
|
||||
):
|
||||
"""Creates a triplet using the anchor paths"""
|
||||
# Load images from path
|
||||
if grayscale:
|
||||
@ -40,34 +56,34 @@ class TripletLayer(NeuralNetworkLayer):
|
||||
|
||||
def make_assets(self):
|
||||
"""
|
||||
Constructs the assets needed for a triplet layer
|
||||
Constructs the assets needed for a triplet layer
|
||||
"""
|
||||
# Handle anchor
|
||||
anchor_group = LabeledColorImage(
|
||||
self.anchor,
|
||||
self.anchor,
|
||||
color=WHITE,
|
||||
label="Anchor",
|
||||
label="Anchor",
|
||||
stroke_width=self.stroke_width,
|
||||
font_size=self.font_size,
|
||||
buff=self.buff
|
||||
buff=self.buff,
|
||||
)
|
||||
# Handle positive
|
||||
positive_group = LabeledColorImage(
|
||||
self.positive,
|
||||
self.positive,
|
||||
color=GREEN,
|
||||
label="Positive",
|
||||
label="Positive",
|
||||
stroke_width=self.stroke_width,
|
||||
font_size=self.font_size,
|
||||
buff=self.buff
|
||||
buff=self.buff,
|
||||
)
|
||||
# Handle negative
|
||||
negative_group = LabeledColorImage(
|
||||
self.negative,
|
||||
self.negative,
|
||||
color=RED,
|
||||
label="Negative",
|
||||
label="Negative",
|
||||
stroke_width=self.stroke_width,
|
||||
font_size=self.font_size,
|
||||
buff=self.buff
|
||||
buff=self.buff,
|
||||
)
|
||||
# Distribute the groups uniformly vertically
|
||||
assets = Group(anchor_group, positive_group, negative_group)
|
||||
|
@ -3,15 +3,28 @@ from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer
|
||||
from manim_ml.neural_network.layers.triplet import TripletLayer
|
||||
|
||||
|
||||
class TripletToFeedForward(ConnectiveLayer):
|
||||
"""TripletLayer to FeedForward layer"""
|
||||
|
||||
input_class = TripletLayer
|
||||
output_class = FeedForwardLayer
|
||||
|
||||
def __init__(self, input_layer, output_layer, animation_dot_color=RED,
|
||||
dot_radius=0.02, **kwargs):
|
||||
super().__init__(input_layer, output_layer, input_class=TripletLayer, output_class=FeedForwardLayer,
|
||||
**kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
input_layer,
|
||||
output_layer,
|
||||
animation_dot_color=RED,
|
||||
dot_radius=0.02,
|
||||
**kwargs
|
||||
):
|
||||
super().__init__(
|
||||
input_layer,
|
||||
output_layer,
|
||||
input_class=TripletLayer,
|
||||
output_class=FeedForwardLayer,
|
||||
**kwargs
|
||||
)
|
||||
self.animation_dot_color = animation_dot_color
|
||||
self.dot_radius = dot_radius
|
||||
|
||||
@ -22,27 +35,35 @@ class TripletToFeedForward(ConnectiveLayer):
|
||||
"""Makes dots diverge from the given location and move to the feed forward nodes decoder"""
|
||||
animations = []
|
||||
# Loop through each image
|
||||
images = [self.triplet_layer.anchor, self.triplet_layer.positive, self.triplet_layer.negative]
|
||||
images = [
|
||||
self.triplet_layer.anchor,
|
||||
self.triplet_layer.positive,
|
||||
self.triplet_layer.negative,
|
||||
]
|
||||
for image_mobject in images:
|
||||
image_animations = []
|
||||
dots = []
|
||||
# Move dots from each image to the centers of each of the nodes in the FeedForwardLayer
|
||||
image_location = image_mobject.get_center()
|
||||
image_location = image_mobject.get_center()
|
||||
for node in self.feed_forward_layer.node_group:
|
||||
new_dot = Dot(image_location, radius=self.dot_radius, color=self.animation_dot_color)
|
||||
new_dot = Dot(
|
||||
image_location,
|
||||
radius=self.dot_radius,
|
||||
color=self.animation_dot_color,
|
||||
)
|
||||
per_node_succession = Succession(
|
||||
Create(new_dot),
|
||||
new_dot.animate.move_to(node.get_center()),
|
||||
)
|
||||
image_animations.append(per_node_succession)
|
||||
dots.append(new_dot)
|
||||
|
||||
|
||||
animations.append(AnimationGroup(*image_animations))
|
||||
|
||||
|
||||
animation_group = AnimationGroup(*animations)
|
||||
|
||||
|
||||
return animation_group
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self):
|
||||
return AnimationGroup()
|
||||
return AnimationGroup()
|
||||
|
@ -4,22 +4,26 @@ from manim import *
|
||||
from manim_ml.neural_network.layers.parent_layers import BlankConnective, ThreeDLayer
|
||||
from ..layers import connective_layers_list
|
||||
|
||||
|
||||
def get_connective_layer(input_layer, output_layer):
|
||||
"""
|
||||
Deduces the relevant connective layer
|
||||
Deduces the relevant connective layer
|
||||
"""
|
||||
connective_layer_class = None
|
||||
for candidate_class in connective_layers_list:
|
||||
input_class = candidate_class.input_class
|
||||
output_class = candidate_class.output_class
|
||||
if isinstance(input_layer, input_class) \
|
||||
and isinstance(output_layer, output_class):
|
||||
if isinstance(input_layer, input_class) and isinstance(
|
||||
output_layer, output_class
|
||||
):
|
||||
connective_layer_class = candidate_class
|
||||
break
|
||||
|
||||
if connective_layer_class is None:
|
||||
connective_layer_class = BlankConnective
|
||||
warnings.warn(f"Unrecognized input/output class pair: {input_class} and {output_class}")
|
||||
warnings.warn(
|
||||
f"Unrecognized input/output class pair: {input_class} and {output_class}"
|
||||
)
|
||||
|
||||
# Make the instance now
|
||||
connective_layer = connective_layer_class(input_layer, output_layer)
|
||||
|
@ -3,11 +3,11 @@ import random
|
||||
|
||||
from manim_ml.neural_network.layers.parent_layers import VGroupNeuralNetworkLayer
|
||||
|
||||
|
||||
class VectorLayer(VGroupNeuralNetworkLayer):
|
||||
"""Shows a vector"""
|
||||
|
||||
def __init__(self, num_values, value_func=lambda: random.uniform(0, 1),
|
||||
**kwargs):
|
||||
def __init__(self, num_values, value_func=lambda: random.uniform(0, 1), **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.num_values = num_values
|
||||
self.value_func = value_func
|
||||
@ -30,8 +30,8 @@ class VectorLayer(VGroupNeuralNetworkLayer):
|
||||
|
||||
def make_forward_pass_animation(self, layer_args={}, **kwargs):
|
||||
return AnimationGroup()
|
||||
|
||||
|
||||
@override_animation(Create)
|
||||
def _create_override(self):
|
||||
"""Create animation"""
|
||||
return Write(self.vector_label)
|
||||
return Write(self.vector_label)
|
||||
|
@ -17,15 +17,27 @@ from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.parent_layers import ConnectiveLayer, ThreeDLayer
|
||||
from manim_ml.neural_network.layers.util import get_connective_layer
|
||||
from manim_ml.list_group import ListGroup
|
||||
from manim_ml.neural_network.neural_network_transformations import InsertLayer, RemoveLayer
|
||||
from manim_ml.neural_network.neural_network_transformations import (
|
||||
InsertLayer,
|
||||
RemoveLayer,
|
||||
)
|
||||
|
||||
|
||||
class NeuralNetwork(Group):
|
||||
"""Neural Network Visualization Container Class"""
|
||||
|
||||
def __init__(self, input_layers, edge_color=WHITE, layer_spacing=0.2,
|
||||
animation_dot_color=RED, edge_width=2.5, dot_radius=0.03,
|
||||
title=" ", three_d_phi=-70 * DEGREES,
|
||||
three_d_theta=-80 * DEGREES):
|
||||
def __init__(
|
||||
self,
|
||||
input_layers,
|
||||
edge_color=WHITE,
|
||||
layer_spacing=0.2,
|
||||
animation_dot_color=RED,
|
||||
edge_width=2.5,
|
||||
dot_radius=0.03,
|
||||
title=" ",
|
||||
three_d_phi=-70 * DEGREES,
|
||||
three_d_theta=-80 * DEGREES,
|
||||
):
|
||||
super(Group, self).__init__()
|
||||
self.input_layers = ListGroup(*input_layers)
|
||||
self.edge_width = edge_width
|
||||
@ -44,7 +56,7 @@ class NeuralNetwork(Group):
|
||||
self.camera.add_fixed_orientation_mobjects(layer)
|
||||
self.camera.add_fixed_in_frame_mobjects(layer)
|
||||
"""
|
||||
# TODO take layer_node_count [0, (1, 2), 0]
|
||||
# TODO take layer_node_count [0, (1, 2), 0]
|
||||
# and make it have explicit distinct subspaces
|
||||
# Add camera to input layers
|
||||
"""
|
||||
@ -56,10 +68,7 @@ class NeuralNetwork(Group):
|
||||
self._place_layers()
|
||||
self.connective_layers, self.all_layers = self._construct_connective_layers()
|
||||
# Make overhead title
|
||||
self.title = Text(
|
||||
self.title_text,
|
||||
font_size=DEFAULT_FONT_SIZE/2
|
||||
)
|
||||
self.title = Text(self.title_text, font_size=DEFAULT_FONT_SIZE / 2)
|
||||
self.title.next_to(self, UP, 1.0)
|
||||
self.add(self.title)
|
||||
# Place layers at correct z index
|
||||
@ -86,11 +95,29 @@ class NeuralNetwork(Group):
|
||||
current_layer = self.input_layers[layer_index]
|
||||
current_layer.move_to(previous_layer)
|
||||
# TODO Temp fix
|
||||
if isinstance(current_layer, EmbeddingLayer) \
|
||||
or isinstance(previous_layer, EmbeddingLayer):
|
||||
shift_vector = np.array([(previous_layer.get_width()/2 + current_layer.get_width()/2 - 0.2), 0, 0])
|
||||
if isinstance(current_layer, EmbeddingLayer) or isinstance(
|
||||
previous_layer, EmbeddingLayer
|
||||
):
|
||||
shift_vector = np.array(
|
||||
[
|
||||
(
|
||||
previous_layer.get_width() / 2
|
||||
+ current_layer.get_width() / 2
|
||||
- 0.2
|
||||
),
|
||||
0,
|
||||
0,
|
||||
]
|
||||
)
|
||||
else:
|
||||
shift_vector = np.array([(previous_layer.get_width()/2 + current_layer.get_width()/2) + self.layer_spacing, 0, 0])
|
||||
shift_vector = np.array(
|
||||
[
|
||||
(previous_layer.get_width() / 2 + current_layer.get_width() / 2)
|
||||
+ self.layer_spacing,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
)
|
||||
current_layer.shift(shift_vector)
|
||||
|
||||
def _construct_connective_layers(self):
|
||||
@ -149,24 +176,25 @@ class NeuralNetwork(Group):
|
||||
insert_animation = self.insert_layer(layer, insert_index)
|
||||
# Make the animation
|
||||
animation_group = AnimationGroup(
|
||||
FadeOut(self.all_layers[insert_index]),
|
||||
FadeIn(layer),
|
||||
lag_ratio=1.0
|
||||
FadeOut(self.all_layers[insert_index]), FadeIn(layer), lag_ratio=1.0
|
||||
)
|
||||
|
||||
return animation_group
|
||||
|
||||
def make_forward_pass_animation(self, run_time=None, passing_flash=True, layer_args={},
|
||||
**kwargs):
|
||||
def make_forward_pass_animation(
|
||||
self, run_time=None, passing_flash=True, layer_args={}, **kwargs
|
||||
):
|
||||
"""Generates an animation for feed forward propagation"""
|
||||
all_animations = []
|
||||
per_layer_runtime = run_time / len(self.all_layers) if not run_time is None else None
|
||||
per_layer_runtime = (
|
||||
run_time / len(self.all_layers) if not run_time is None else None
|
||||
)
|
||||
for layer_index, layer in enumerate(self.all_layers):
|
||||
# Get the layer args
|
||||
if isinstance(layer, ConnectiveLayer):
|
||||
"""
|
||||
NOTE: By default a connective layer will get the combined
|
||||
layer_args of the layers it is connecting.
|
||||
NOTE: By default a connective layer will get the combined
|
||||
layer_args of the layers it is connecting.
|
||||
"""
|
||||
before_layer_args = {}
|
||||
after_layer_args = {}
|
||||
@ -182,16 +210,11 @@ class NeuralNetwork(Group):
|
||||
current_layer_args = layer_args[layer]
|
||||
# Perform the forward pass of the current layer
|
||||
layer_forward_pass = layer.make_forward_pass_animation(
|
||||
layer_args=current_layer_args,
|
||||
run_time=per_layer_runtime,
|
||||
**kwargs
|
||||
layer_args=current_layer_args, run_time=per_layer_runtime, **kwargs
|
||||
)
|
||||
all_animations.append(layer_forward_pass)
|
||||
# Make the animation group
|
||||
animation_group = Succession(
|
||||
*all_animations,
|
||||
lag_ratio=1.0
|
||||
)
|
||||
animation_group = Succession(*all_animations, lag_ratio=1.0)
|
||||
|
||||
return animation_group
|
||||
|
||||
@ -212,14 +235,11 @@ class NeuralNetwork(Group):
|
||||
# Make titles
|
||||
create_title = Create(layer.title)
|
||||
# Create layer animation group
|
||||
animation_group = AnimationGroup(
|
||||
layer_animation,
|
||||
create_title
|
||||
)
|
||||
animation_group = AnimationGroup(layer_animation, create_title)
|
||||
animations.append(animation_group)
|
||||
|
||||
animation_group = AnimationGroup(*animations, lag_ratio=1.0)
|
||||
|
||||
|
||||
return animation_group
|
||||
|
||||
def set_z_index(self, z_index_value: float, family=False):
|
||||
@ -240,7 +260,7 @@ class NeuralNetwork(Group):
|
||||
inner_string = ""
|
||||
for layer in self.all_layers:
|
||||
inner_string += f"{repr(layer)} ("
|
||||
for key in metadata:
|
||||
for key in metadata:
|
||||
value = getattr(layer, key)
|
||||
if not value is "":
|
||||
inner_string += f"{key}={value}, "
|
||||
@ -250,15 +270,17 @@ class NeuralNetwork(Group):
|
||||
string_repr = "NeuralNetwork([\n" + inner_string + "])"
|
||||
return string_repr
|
||||
|
||||
|
||||
class FeedForwardNeuralNetwork(NeuralNetwork):
|
||||
"""NeuralNetwork with just feed forward layers"""
|
||||
|
||||
def __init__(self, layer_node_count, node_radius=0.08,
|
||||
node_color=BLUE, **kwargs):
|
||||
def __init__(self, layer_node_count, node_radius=0.08, node_color=BLUE, **kwargs):
|
||||
# construct layers
|
||||
layers = []
|
||||
for num_nodes in layer_node_count:
|
||||
layer = FeedForwardLayer(num_nodes, node_color=node_color, node_radius=node_radius)
|
||||
layer = FeedForwardLayer(
|
||||
num_nodes, node_color=node_color, node_radius=node_radius
|
||||
)
|
||||
layers.append(layer)
|
||||
# call super class
|
||||
super().__init__(layers, **kwargs)
|
||||
super().__init__(layers, **kwargs)
|
||||
|
@ -4,17 +4,18 @@
|
||||
from manim import *
|
||||
from manim_ml.neural_network.layers.util import get_connective_layer
|
||||
|
||||
|
||||
class RemoveLayer(AnimationGroup):
|
||||
"""
|
||||
Animation for removing a layer from a neural network.
|
||||
Animation for removing a layer from a neural network.
|
||||
|
||||
Note: I needed to do something strange for creating the new connective layer.
|
||||
The issue with creating it initially is that the positions of the sides of the
|
||||
connective layer depend upon the location of the moved layers **after** the
|
||||
move animations are performed. However, all of these animations are performed
|
||||
after the animations have been created. This means that the animation depends upon
|
||||
the state of the neural network layers after previous animations have been run.
|
||||
To fix this issue I needed to use an UpdateFromFunc.
|
||||
Note: I needed to do something strange for creating the new connective layer.
|
||||
The issue with creating it initially is that the positions of the sides of the
|
||||
connective layer depend upon the location of the moved layers **after** the
|
||||
move animations are performed. However, all of these animations are performed
|
||||
after the animations have been created. This means that the animation depends upon
|
||||
the state of the neural network layers after previous animations have been run.
|
||||
To fix this issue I needed to use an UpdateFromFunc.
|
||||
"""
|
||||
|
||||
def __init__(self, layer, neural_network, layer_spacing=0.2):
|
||||
@ -32,11 +33,7 @@ class RemoveLayer(AnimationGroup):
|
||||
move_animations = self.make_move_animation()
|
||||
new_connective_animation = self.make_new_connective_animation()
|
||||
# Add all of the animations to the group
|
||||
animations_list = [
|
||||
remove_animations,
|
||||
move_animations,
|
||||
new_connective_animation
|
||||
]
|
||||
animations_list = [remove_animations, move_animations, new_connective_animation]
|
||||
|
||||
super().__init__(*animations_list, lag_ratio=1.0)
|
||||
|
||||
@ -54,10 +51,10 @@ class RemoveLayer(AnimationGroup):
|
||||
if layer_index - 2 >= 0:
|
||||
before_layer = self.neural_network.all_layers[layer_index - 2]
|
||||
before_connective = self.neural_network.all_layers[layer_index - 1]
|
||||
if layer_index + 2 < len(self.neural_network.all_layers):
|
||||
if layer_index + 2 < len(self.neural_network.all_layers):
|
||||
after_layer = self.neural_network.all_layers[layer_index + 2]
|
||||
after_connective = self.neural_network.all_layers[layer_index + 1]
|
||||
|
||||
|
||||
return before_layer, after_layer, before_connective, after_connective
|
||||
|
||||
def make_remove_animation(self):
|
||||
@ -66,8 +63,7 @@ class RemoveLayer(AnimationGroup):
|
||||
remove_connective_animation = self.make_remove_connective_layers_animation()
|
||||
# Remove animations
|
||||
remove_animations = AnimationGroup(
|
||||
remove_layer_animation,
|
||||
remove_connective_animation
|
||||
remove_layer_animation, remove_connective_animation
|
||||
)
|
||||
|
||||
return remove_animations
|
||||
@ -93,8 +89,7 @@ class RemoveLayer(AnimationGroup):
|
||||
fade_out_after_connective = FadeOut(self.after_connective)
|
||||
# Group items
|
||||
remove_connective_group = AnimationGroup(
|
||||
fade_out_after_connective,
|
||||
fade_out_before_connective
|
||||
fade_out_after_connective, fade_out_before_connective
|
||||
)
|
||||
|
||||
return remove_connective_group
|
||||
@ -106,44 +101,56 @@ class RemoveLayer(AnimationGroup):
|
||||
shift_right_amount = None
|
||||
if not self.before_layer is None:
|
||||
# Compute shift amount
|
||||
layer_dist = np.abs(self.layer.get_center() - self.before_layer.get_right())[0]
|
||||
shift_right_amount = np.array([layer_dist - self.layer_spacing/2, 0, 0])
|
||||
layer_dist = np.abs(
|
||||
self.layer.get_center() - self.before_layer.get_right()
|
||||
)[0]
|
||||
shift_right_amount = np.array([layer_dist - self.layer_spacing / 2, 0, 0])
|
||||
# Shift all layers before forward
|
||||
before_layer_index = self.neural_network.all_layers.index_of(self.before_layer)
|
||||
layers_before = Group(*self.neural_network.all_layers[:before_layer_index + 1])
|
||||
before_layer_index = self.neural_network.all_layers.index_of(
|
||||
self.before_layer
|
||||
)
|
||||
layers_before = Group(
|
||||
*self.neural_network.all_layers[: before_layer_index + 1]
|
||||
)
|
||||
move_before_layers = layers_before.animate.shift(shift_right_amount)
|
||||
move_after_layers = AnimationGroup()
|
||||
shift_left_amount = None
|
||||
if not self.after_layer is None:
|
||||
layer_dist = np.abs(self.after_layer.get_left() - self.layer.get_center())[0]
|
||||
layer_dist = np.abs(self.after_layer.get_left() - self.layer.get_center())[
|
||||
0
|
||||
]
|
||||
shift_left_amount = np.array([-layer_dist + self.layer_spacing / 2, 0, 0])
|
||||
# Shift all layers after backward
|
||||
after_layer_index = self.neural_network.all_layers.index_of(self.after_layer)
|
||||
after_layer_index = self.neural_network.all_layers.index_of(
|
||||
self.after_layer
|
||||
)
|
||||
layers_after = Group(*self.neural_network.all_layers[after_layer_index:])
|
||||
move_after_layers = layers_after.animate.shift(shift_left_amount)
|
||||
# Group the move animations
|
||||
move_group = AnimationGroup(
|
||||
move_before_layers,
|
||||
move_after_layers
|
||||
)
|
||||
move_group = AnimationGroup(move_before_layers, move_after_layers)
|
||||
|
||||
return move_group
|
||||
|
||||
def make_new_connective_animation(self):
|
||||
"""Makes new connective layer"""
|
||||
self.anim_count = 0
|
||||
|
||||
def create_new_connective(neural_network):
|
||||
"""
|
||||
Creates new connective layer
|
||||
|
||||
This is a closure that creates a new connective layer and animates it.
|
||||
Creates new connective layer
|
||||
|
||||
This is a closure that creates a new connective layer and animates it.
|
||||
"""
|
||||
self.anim_count += 1
|
||||
if self.anim_count == 1:
|
||||
if not self.before_layer is None and not self.after_layer is None:
|
||||
print(neural_network)
|
||||
new_connective_class = get_connective_layer(self.before_layer, self.after_layer)
|
||||
before_layer_index = neural_network.all_layers.index_of(self.before_layer) + 1
|
||||
new_connective_class = get_connective_layer(
|
||||
self.before_layer, self.after_layer
|
||||
)
|
||||
before_layer_index = (
|
||||
neural_network.all_layers.index_of(self.before_layer) + 1
|
||||
)
|
||||
neural_network.all_layers.insert(before_layer_index, new_connective)
|
||||
print(neural_network)
|
||||
|
||||
@ -151,6 +158,7 @@ class RemoveLayer(AnimationGroup):
|
||||
|
||||
return update_func_anim
|
||||
|
||||
|
||||
class InsertLayer(AnimationGroup):
|
||||
"""Animation for inserting layer at given index"""
|
||||
|
||||
@ -161,8 +169,8 @@ class InsertLayer(AnimationGroup):
|
||||
# Check valid index
|
||||
assert index < len(self.neural_network.all_layers)
|
||||
# Layers before and after
|
||||
self.layers_before = self.neural_network.all_layers[:self.index]
|
||||
self.layers_after = self.neural_network.all_layers[self.index:]
|
||||
self.layers_before = self.neural_network.all_layers[: self.index]
|
||||
self.layers_after = self.neural_network.all_layers[self.index :]
|
||||
# Get the non-connective layer before and after
|
||||
if len(self.layers_before) > 0:
|
||||
self.layer_before = self.layers_before[-2]
|
||||
@ -172,15 +180,18 @@ class InsertLayer(AnimationGroup):
|
||||
if not self.layer_after is None:
|
||||
self.layer.move_to(self.layer_after)
|
||||
# Make animations
|
||||
self.old_connective_layer, remove_connective_layer = self.remove_connective_layer_animation()
|
||||
(
|
||||
self.old_connective_layer,
|
||||
remove_connective_layer,
|
||||
) = self.remove_connective_layer_animation()
|
||||
move_layers = self.make_move_layers_animation()
|
||||
create_layer = self.make_create_layer_animation()
|
||||
# create_connective_layers = self.make_create_connective_layers()
|
||||
animations = [
|
||||
remove_connective_layer,
|
||||
move_layers,
|
||||
create_layer,
|
||||
# create_connective_layers
|
||||
create_layer,
|
||||
# create_connective_layers
|
||||
]
|
||||
|
||||
super().__init__(*animations, lag_ratio=1.0)
|
||||
@ -219,27 +230,39 @@ class InsertLayer(AnimationGroup):
|
||||
|
||||
def make_move_layers_animation(self):
|
||||
"""Shifts layers before and after"""
|
||||
before_connective_width, after_connective_width = self.get_connective_layer_widths()
|
||||
(
|
||||
before_connective_width,
|
||||
after_connective_width,
|
||||
) = self.get_connective_layer_widths()
|
||||
old_connective_width = 0
|
||||
if not self.old_connective_layer is None:
|
||||
old_connective_width = self.old_connective_layer.width
|
||||
# Before layer shift
|
||||
before_shift_animation = AnimationGroup()
|
||||
if len(self.layers_before) > 0:
|
||||
before_shift = np.array([-self.layer.width/2 - before_connective_width + old_connective_width, 0, 0])
|
||||
before_shift = np.array(
|
||||
[
|
||||
-self.layer.width / 2
|
||||
- before_connective_width
|
||||
+ old_connective_width,
|
||||
0,
|
||||
0,
|
||||
]
|
||||
)
|
||||
# Shift layers before
|
||||
before_shift_animation = Group(*self.layers_before).animate.shift(before_shift)
|
||||
before_shift_animation = Group(*self.layers_before).animate.shift(
|
||||
before_shift
|
||||
)
|
||||
# After layer shift
|
||||
after_shift_animation = AnimationGroup()
|
||||
if len(self.layers_after) > 0:
|
||||
after_shift = np.array([self.layer.width/2 + after_connective_width, 0, 0])
|
||||
after_shift = np.array(
|
||||
[self.layer.width / 2 + after_connective_width, 0, 0]
|
||||
)
|
||||
# Shift layers after
|
||||
after_shift_animation = Group(*self.layers_after).animate.shift(after_shift)
|
||||
# Make animation group
|
||||
shift_animations = AnimationGroup(
|
||||
before_shift_animation,
|
||||
after_shift_animation
|
||||
)
|
||||
shift_animations = AnimationGroup(before_shift_animation, after_shift_animation)
|
||||
|
||||
return shift_animations
|
||||
|
||||
@ -247,7 +270,9 @@ class InsertLayer(AnimationGroup):
|
||||
"""Animates the creation of the layer"""
|
||||
return Create(self.layer)
|
||||
|
||||
def make_create_connective_layers_animation(self, before_connective, after_connective):
|
||||
def make_create_connective_layers_animation(
|
||||
self, before_connective, after_connective
|
||||
):
|
||||
"""Create connective layers"""
|
||||
# Make the layers
|
||||
before_connective = None
|
||||
@ -260,9 +285,7 @@ class InsertLayer(AnimationGroup):
|
||||
# Insert the layers
|
||||
# Make the animation
|
||||
animation_group = AnimationGroup(
|
||||
Create(before_connective),
|
||||
Create(after_connective)
|
||||
Create(before_connective), Create(after_connective)
|
||||
)
|
||||
|
||||
return animation_group
|
||||
|
@ -10,12 +10,19 @@ from PIL import Image
|
||||
from manim_ml.neural_network.layers import FeedForwardLayer, EmbeddingLayer, ImageLayer
|
||||
from manim_ml.neural_network.neural_network import NeuralNetwork
|
||||
|
||||
|
||||
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=1.0,
|
||||
layer_spacing=0.5):
|
||||
|
||||
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=1.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
|
||||
@ -30,13 +37,15 @@ class VariationalAutoencoder(VGroup):
|
||||
"""Makes the VAE encoder, embedding layer, and decoder"""
|
||||
embedding_layer = EmbeddingLayer()
|
||||
|
||||
neural_network = NeuralNetwork([
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5)
|
||||
])
|
||||
neural_network = NeuralNetwork(
|
||||
[
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
]
|
||||
)
|
||||
|
||||
return neural_network, embedding_layer
|
||||
|
||||
@ -46,20 +55,18 @@ class VariationalAutoencoder(VGroup):
|
||||
|
||||
def make_triplet_forward_pass(self, triplet):
|
||||
pass
|
||||
|
||||
|
||||
def make_image_forward_pass(self, input_image, output_image, run_time=1.5):
|
||||
"""Override forward pass animation specific to a VAE"""
|
||||
# Make a wrapper NN with images
|
||||
wrapper_neural_network = NeuralNetwork([
|
||||
ImageLayer(input_image),
|
||||
self.neural_network,
|
||||
ImageLayer(output_image)
|
||||
])
|
||||
# Make animation
|
||||
wrapper_neural_network = NeuralNetwork(
|
||||
[ImageLayer(input_image), self.neural_network, ImageLayer(output_image)]
|
||||
)
|
||||
# Make animation
|
||||
animation_group = AnimationGroup(
|
||||
Create(wrapper_neural_network),
|
||||
wrapper_neural_network.make_forward_pass_animation(),
|
||||
lag_ratio=1.0
|
||||
lag_ratio=1.0,
|
||||
)
|
||||
|
||||
return animation_group
|
||||
return animation_group
|
||||
|
@ -6,5 +6,6 @@
|
||||
views of the same concept and visualize them at the same time.
|
||||
"""
|
||||
|
||||
class OneToOneSync():
|
||||
pass
|
||||
|
||||
class OneToOneSync:
|
||||
pass
|
||||
|
@ -2,10 +2,13 @@ from manim import *
|
||||
import numpy as np
|
||||
import math
|
||||
|
||||
|
||||
class GaussianDistribution(VGroup):
|
||||
"""Object for drawing a Gaussian distribution"""
|
||||
|
||||
def __init__(self, axes, mean=None, cov=None, dist_theme="gaussian", color=ORANGE, **kwargs):
|
||||
def __init__(
|
||||
self, axes, mean=None, cov=None, dist_theme="gaussian", color=ORANGE, **kwargs
|
||||
):
|
||||
super(VGroup, self).__init__(**kwargs)
|
||||
self.axes = axes
|
||||
self.mean = mean
|
||||
@ -18,10 +21,14 @@ class GaussianDistribution(VGroup):
|
||||
self.cov = np.array([[1, 0], [0, 1]])
|
||||
# Make the Gaussian
|
||||
if self.dist_theme is "gaussian":
|
||||
self.ellipses = self.construct_gaussian_distribution(self.mean, self.cov, color=self.color)
|
||||
self.ellipses = self.construct_gaussian_distribution(
|
||||
self.mean, self.cov, color=self.color
|
||||
)
|
||||
self.add(self.ellipses)
|
||||
elif self.dist_theme is "ellipse":
|
||||
self.ellipses = self.construct_simple_gaussian_ellipse(self.mean, self.cov, color=self.color)
|
||||
self.ellipses = self.construct_simple_gaussian_ellipse(
|
||||
self.mean, self.cov, color=self.color
|
||||
)
|
||||
self.add(self.ellipses)
|
||||
else:
|
||||
raise Exception(f"Uncrecognized distribution theme: {self.dist_theme}")
|
||||
@ -33,11 +40,10 @@ class GaussianDistribution(VGroup):
|
||||
"""
|
||||
|
||||
def compute_covariance_rotation_and_scale(self, covariance):
|
||||
|
||||
def eigsorted(cov):
|
||||
'''
|
||||
"""
|
||||
Eigenvalues and eigenvectors of the covariance matrix.
|
||||
'''
|
||||
"""
|
||||
vals, vecs = np.linalg.eigh(cov)
|
||||
order = vals.argsort()[::-1]
|
||||
return vals[order], vecs[:, order]
|
||||
@ -56,13 +62,16 @@ class GaussianDistribution(VGroup):
|
||||
return width, height, theta
|
||||
|
||||
width, height, angle = cov_ellipse(covariance, 1)
|
||||
scale_factor = np.abs(self.axes.x_range[0] - self.axes.x_range[1]) / self.axes.x_length
|
||||
scale_factor = (
|
||||
np.abs(self.axes.x_range[0] - self.axes.x_range[1]) / self.axes.x_length
|
||||
)
|
||||
width /= scale_factor
|
||||
height /= scale_factor
|
||||
return angle, width, height
|
||||
|
||||
def construct_gaussian_distribution(self, mean, covariance, color=ORANGE,
|
||||
num_ellipses=4):
|
||||
def construct_gaussian_distribution(
|
||||
self, mean, covariance, color=ORANGE, num_ellipses=4
|
||||
):
|
||||
"""Returns a 2d Gaussian distribution object with given mean and covariance"""
|
||||
# map mean and covariance to frame coordinates
|
||||
mean = self.axes.coords_to_point(*mean)
|
||||
@ -76,11 +85,11 @@ class GaussianDistribution(VGroup):
|
||||
ellipse_width = width * (1 - opacity)
|
||||
ellipse_height = height * (1 - opacity)
|
||||
ellipse = Ellipse(
|
||||
width=ellipse_width,
|
||||
height=ellipse_height,
|
||||
color=color,
|
||||
fill_opacity=opacity,
|
||||
stroke_width=0.0
|
||||
width=ellipse_width,
|
||||
height=ellipse_height,
|
||||
color=color,
|
||||
fill_opacity=opacity,
|
||||
stroke_width=0.0,
|
||||
)
|
||||
ellipse.move_to(mean)
|
||||
ellipse.rotate(rotation)
|
||||
@ -97,15 +106,15 @@ class GaussianDistribution(VGroup):
|
||||
ellipses = VGroup()
|
||||
opacity = 0.4
|
||||
ellipse = Ellipse(
|
||||
width=width,
|
||||
height=height,
|
||||
color=color,
|
||||
fill_opacity=opacity,
|
||||
stroke_width=1.0
|
||||
width=width,
|
||||
height=height,
|
||||
color=color,
|
||||
fill_opacity=opacity,
|
||||
stroke_width=1.0,
|
||||
)
|
||||
ellipse.move_to(mean)
|
||||
ellipse.rotate(angle)
|
||||
ellipses.add(ellipse)
|
||||
ellipses.set_z_index(3)
|
||||
|
||||
return ellipses
|
||||
return ellipses
|
||||
|
@ -1,17 +1,17 @@
|
||||
from manim import *
|
||||
|
||||
|
||||
class ManimML3DScene(ThreeDScene):
|
||||
"""
|
||||
This is a wrapper class for the Manim ThreeDScene
|
||||
This is a wrapper class for the Manim ThreeDScene
|
||||
|
||||
Note: the primary purpose of this is to make it so
|
||||
that everything inside of a layer
|
||||
Note: the primary purpose of this is to make it so
|
||||
that everything inside of a layer
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def play(self):
|
||||
"""
|
||||
"""
|
||||
pass
|
||||
""" """
|
||||
pass
|
||||
|
8
setup.py
8
setup.py
@ -1,8 +1,8 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name = "manim_ml",
|
||||
version = "0.0.12",
|
||||
description = (" Machine Learning Animations in python using Manim."),
|
||||
name="manim_ml",
|
||||
version="0.0.12",
|
||||
description=(" Machine Learning Animations in python using Manim."),
|
||||
packages=find_packages(),
|
||||
)
|
||||
)
|
||||
|
BIN
tests/.DS_Store
vendored
Normal file
BIN
tests/.DS_Store
vendored
Normal file
Binary file not shown.
@ -12,19 +12,21 @@ config.pixel_width = 1900
|
||||
config.frame_height = 6.0
|
||||
config.frame_width = 6.0
|
||||
|
||||
|
||||
class CombinedScene(ThreeDScene):
|
||||
def construct(self):
|
||||
image = Image.open('../assets/mnist/digit.jpeg')
|
||||
image = Image.open("../assets/mnist/digit.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
# Make nn
|
||||
nn = NeuralNetwork([
|
||||
nn = NeuralNetwork(
|
||||
[
|
||||
ImageLayer(numpy_image, height=1.5),
|
||||
Convolutional3DLayer(1, 7, 7, 3, 3, filter_spacing=0.32),
|
||||
Convolutional3DLayer(3, 5, 5, 3, 3, filter_spacing=0.32),
|
||||
Convolutional3DLayer(5, 3, 3, 1, 1, filter_spacing=0.18),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(3),
|
||||
],
|
||||
],
|
||||
layer_spacing=0.25,
|
||||
)
|
||||
# Center the nn
|
||||
@ -37,10 +39,7 @@ class CombinedScene(ThreeDScene):
|
||||
"""
|
||||
# Play animation
|
||||
forward_pass = nn.make_forward_pass_animation(
|
||||
corner_pulses=False,
|
||||
all_filters_at_once=False
|
||||
corner_pulses=False, all_filters_at_once=False
|
||||
)
|
||||
self.wait(1)
|
||||
self.play(
|
||||
forward_pass
|
||||
)
|
||||
self.play(forward_pass)
|
||||
|
@ -7,16 +7,16 @@ config.pixel_width = 1900
|
||||
config.frame_height = 12.0
|
||||
config.frame_width = 12.0
|
||||
|
||||
class TestConv2d(Scene):
|
||||
|
||||
class TestConv2d(Scene):
|
||||
def construct(self):
|
||||
nn = NeuralNetwork(
|
||||
[
|
||||
Convolutional2DLayer(5, 5, 3, 3, cell_width=0.5, stride=1),
|
||||
Convolutional2DLayer(3, 3, 2, 2, cell_width=0.5, stride=1),
|
||||
],
|
||||
],
|
||||
layer_spacing=1.5,
|
||||
camera=self.camera
|
||||
camera=self.camera,
|
||||
)
|
||||
# Center the nn
|
||||
nn.scale(1.3)
|
||||
@ -27,4 +27,4 @@ class TestConv2d(Scene):
|
||||
self.play(
|
||||
forward_pass,
|
||||
)
|
||||
self.wait(1)
|
||||
self.wait(1)
|
||||
|
@ -6,37 +6,41 @@ from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.image import ImageLayer
|
||||
from manim_ml.neural_network.neural_network import NeuralNetwork
|
||||
|
||||
class SingleConvolutionalLayerScene(ThreeDScene):
|
||||
|
||||
class SingleConvolutionalLayerScene(ThreeDScene):
|
||||
def construct(self):
|
||||
# Make nn
|
||||
layers = [
|
||||
Convolutional3DLayer(3, 4)
|
||||
]
|
||||
layers = [Convolutional3DLayer(3, 4)]
|
||||
nn = NeuralNetwork(layers)
|
||||
nn.scale(1.3)
|
||||
# Center the nn
|
||||
nn.move_to(ORIGIN)
|
||||
self.add(nn)
|
||||
# Play animation
|
||||
self.set_camera_orientation(phi=280*DEGREES, theta=-10*DEGREES, gamma=90*DEGREES)
|
||||
self.set_camera_orientation(
|
||||
phi=280 * DEGREES, theta=-10 * DEGREES, gamma=90 * DEGREES
|
||||
)
|
||||
# self.play(nn.make_forward_pass_animation(run_time=5))
|
||||
|
||||
class Simple3DConvScene(ThreeDScene):
|
||||
|
||||
class Simple3DConvScene(ThreeDScene):
|
||||
def construct(self):
|
||||
"""
|
||||
TODO
|
||||
- [X] Make grid lines for the CNN filters
|
||||
- [ ] Make Scanning filter effect
|
||||
- [ ] Have filter box go accross each input feature map
|
||||
- [ ] Make filter lines effect
|
||||
- [ ] Make flowing animation down filter lines
|
||||
TODO
|
||||
- [X] Make grid lines for the CNN filters
|
||||
- [ ] Make Scanning filter effect
|
||||
- [ ] Have filter box go accross each input feature map
|
||||
- [ ] Make filter lines effect
|
||||
- [ ] Make flowing animation down filter lines
|
||||
"""
|
||||
# Make nn
|
||||
layers = [
|
||||
Convolutional3DLayer(1, 5, 5, 5, 5, feature_map_height=3, filter_width=3, filter_height=3),
|
||||
Convolutional3DLayer(1, 3, 3, 1, 1, feature_map_width=3, filter_width=3, filter_height=3),
|
||||
Convolutional3DLayer(
|
||||
1, 5, 5, 5, 5, feature_map_height=3, filter_width=3, filter_height=3
|
||||
),
|
||||
Convolutional3DLayer(
|
||||
1, 3, 3, 1, 1, feature_map_width=3, filter_width=3, filter_height=3
|
||||
),
|
||||
]
|
||||
nn = NeuralNetwork(layers)
|
||||
# Center the nn
|
||||
@ -46,15 +50,17 @@ class Simple3DConvScene(ThreeDScene):
|
||||
# self.set_camera_orientation(phi=280*DEGREES, theta=-10*DEGREES, gamma=90*DEGREES)
|
||||
self.play(nn.make_forward_pass_animation(run_time=30))
|
||||
|
||||
|
||||
# Make the specific scene
|
||||
config.pixel_height = 1200
|
||||
config.pixel_width = 1900
|
||||
config.frame_height = 6.0
|
||||
config.frame_width = 6.0
|
||||
|
||||
|
||||
class CombinedScene(ThreeDScene):
|
||||
def construct(self):
|
||||
image = Image.open('../assets/mnist/digit.jpeg')
|
||||
image = Image.open("../assets/mnist/digit.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
# Make nn
|
||||
nn = NeuralNetwork(
|
||||
@ -63,10 +69,10 @@ class CombinedScene(ThreeDScene):
|
||||
Convolutional3DLayer(1, 5, 5, 3, 3, filter_spacing=0.2),
|
||||
Convolutional3DLayer(2, 3, 3, 1, 1, filter_spacing=0.2),
|
||||
FeedForwardLayer(3, rectangle_stroke_width=4, node_stroke_width=4),
|
||||
FeedForwardLayer(1, rectangle_stroke_width=4, node_stroke_width=4)
|
||||
],
|
||||
FeedForwardLayer(1, rectangle_stroke_width=4, node_stroke_width=4),
|
||||
],
|
||||
layer_spacing=0.5,
|
||||
camera=self.camera
|
||||
camera=self.camera,
|
||||
)
|
||||
|
||||
nn.scale(1.3)
|
||||
@ -76,11 +82,6 @@ class CombinedScene(ThreeDScene):
|
||||
# Play animation
|
||||
# self.set_camera_orientation(phi=280* DEGREES, theta=-20*DEGREES, gamma=90 * DEGREES)
|
||||
# self.begin_ambient_camera_rotation()
|
||||
forward_pass = nn.make_forward_pass_animation(
|
||||
run_time=10,
|
||||
corner_pulses=False
|
||||
)
|
||||
forward_pass = nn.make_forward_pass_animation(run_time=10, corner_pulses=False)
|
||||
print(forward_pass)
|
||||
self.play(
|
||||
forward_pass
|
||||
)
|
||||
self.play(forward_pass)
|
||||
|
@ -4,23 +4,25 @@ from manim_ml.neural_network.layers.embedding import EmbeddingLayer
|
||||
from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.neural_network import NeuralNetwork
|
||||
|
||||
config.pixel_height = 720
|
||||
config.pixel_width = 1280
|
||||
config.pixel_height = 720
|
||||
config.pixel_width = 1280
|
||||
config.frame_height = 5.0
|
||||
config.frame_width = 5.0
|
||||
|
||||
class EmbeddingNNScene(Scene):
|
||||
|
||||
class EmbeddingNNScene(Scene):
|
||||
def construct(self):
|
||||
embedding_layer = EmbeddingLayer()
|
||||
|
||||
neural_network = NeuralNetwork([
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5)
|
||||
])
|
||||
neural_network = NeuralNetwork(
|
||||
[
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
]
|
||||
)
|
||||
|
||||
self.play(Create(neural_network))
|
||||
|
||||
@ -28,17 +30,18 @@ class EmbeddingNNScene(Scene):
|
||||
|
||||
|
||||
class TripletEmbeddingNNScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
embedding_layer = EmbeddingLayer()
|
||||
|
||||
neural_network = NeuralNetwork([
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5)
|
||||
])
|
||||
neural_network = NeuralNetwork(
|
||||
[
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
]
|
||||
)
|
||||
|
||||
self.play(Create(neural_network))
|
||||
|
||||
@ -51,40 +54,42 @@ class TripletEmbeddingNNScene(Scene):
|
||||
"cov": np.array([[0.3, 0], [0, 0.3]]),
|
||||
"mean": np.array([0.7, 1.4]),
|
||||
"dist_theme": "ellipse",
|
||||
"color": BLUE
|
||||
"color": BLUE,
|
||||
},
|
||||
"positive_dist": {
|
||||
"cov": np.array([[0.2, 0], [0, 0.2]]),
|
||||
"mean": np.array([0.8, -0.4]),
|
||||
"dist_theme": "ellipse",
|
||||
"color": GREEN
|
||||
"color": GREEN,
|
||||
},
|
||||
"negative_dist": {
|
||||
"cov": np.array([[0.4, 0], [0, 0.25]]),
|
||||
"mean": np.array([-1, -1.2]),
|
||||
"dist_theme": "ellipse",
|
||||
"color": RED
|
||||
}
|
||||
"color": RED,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
run_time=5
|
||||
run_time=5,
|
||||
)
|
||||
)
|
||||
|
||||
class QueryEmbeddingNNScene(Scene):
|
||||
|
||||
class QueryEmbeddingNNScene(Scene):
|
||||
def construct(self):
|
||||
embedding_layer = EmbeddingLayer()
|
||||
embedding_layer.paired_query_mode = True
|
||||
|
||||
neural_network = NeuralNetwork([
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5)
|
||||
])
|
||||
neural_network = NeuralNetwork(
|
||||
[
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
]
|
||||
)
|
||||
|
||||
self.play(Create(neural_network), run_time=2)
|
||||
|
||||
@ -97,15 +102,15 @@ class QueryEmbeddingNNScene(Scene):
|
||||
"cov": np.array([[1, 0], [0, 1]]),
|
||||
"mean": np.array([1, 1]),
|
||||
"dist_theme": "ellipse",
|
||||
"color": GREEN
|
||||
"color": GREEN,
|
||||
},
|
||||
"negative_dist_args": {
|
||||
"cov": np.array([[1, 0], [0, 1]]),
|
||||
"mean": np.array([-1, -1]),
|
||||
"dist_theme": "ellipse",
|
||||
"color": RED
|
||||
}
|
||||
"color": RED,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
)
|
||||
|
@ -2,5 +2,3 @@
|
||||
Tests for feed forward to feed forward weight
|
||||
change animations.
|
||||
"""
|
||||
|
||||
class
|
@ -1,6 +1,6 @@
|
||||
from manim_ml.flow.flow import *
|
||||
|
||||
class TestScene(Scene):
|
||||
|
||||
class TestScene(Scene):
|
||||
def construct(self):
|
||||
self.add(Rectangle())
|
||||
self.add(Rectangle())
|
||||
|
55
tests/test_image_homotopy.py
Normal file
55
tests/test_image_homotopy.py
Normal file
@ -0,0 +1,55 @@
|
||||
from PIL import Image
|
||||
|
||||
from manim import *
|
||||
from manim_ml.image import GrayscaleImageMobject
|
||||
from manim_ml.neural_network.layers.parent_layers import ThreeDLayer
|
||||
|
||||
|
||||
class TestImageHomotopy(Scene):
|
||||
def compute_shape_at_time(self, time):
|
||||
"""Computes the shape of a transformed image at a given time"""
|
||||
|
||||
def compute_center_offset_at_time(self, x, y, z, time):
|
||||
"""Computes the center offset of a point at a given time"""
|
||||
pass
|
||||
|
||||
def construct(self):
|
||||
image = Image.open("../assets/mnist/digit.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
# Make nn
|
||||
image_mobject = GrayscaleImageMobject(numpy_image)
|
||||
self.add(image_mobject)
|
||||
self.wait(1)
|
||||
|
||||
rot = image_mobject.animate.rotate(
|
||||
axis=[0, 1, 0], angle=ThreeDLayer.three_d_y_rotation
|
||||
)
|
||||
move = image_mobject.animate.move_to()
|
||||
self.play(rot)
|
||||
"""
|
||||
# Make square
|
||||
square = Square()
|
||||
self.add(square)
|
||||
# Make polygon
|
||||
polygon = Polygon(
|
||||
[1, 0, 0],
|
||||
[0, 1, 0],
|
||||
[-1, 0, 0],
|
||||
[0, -1, 0],
|
||||
)
|
||||
polygon.shift(RIGHT)
|
||||
self.play(
|
||||
Transform(square, polygon)
|
||||
)
|
||||
# Make the homotopy
|
||||
|
||||
def shift_right_homotopy(x, y, z, t):
|
||||
return x + 1, y, z
|
||||
# Make the animation
|
||||
animation = Homotopy(
|
||||
mobject=image_mobject,
|
||||
homotopy=shift_right_homotopy
|
||||
)
|
||||
|
||||
self.play(animation, run_time=1)
|
||||
"""
|
@ -1,8 +1,11 @@
|
||||
from manim import *
|
||||
from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.feed_forward_to_feed_forward import FeedForwardToFeedForward
|
||||
from manim_ml.neural_network.layers.feed_forward_to_feed_forward import (
|
||||
FeedForwardToFeedForward,
|
||||
)
|
||||
from manim_ml.neural_network.layers.util import get_connective_layer
|
||||
|
||||
|
||||
def test_get_connective_layer():
|
||||
"""Tests get connective layer"""
|
||||
input_layer = FeedForwardLayer(3)
|
||||
|
@ -1,12 +1,21 @@
|
||||
from cv2 import exp
|
||||
from manim import *
|
||||
from manim_ml.neural_network.layers.embedding import EmbeddingLayer
|
||||
from manim_ml.neural_network.layers.embedding_to_feed_forward import EmbeddingToFeedForward
|
||||
from manim_ml.neural_network.layers.embedding_to_feed_forward import (
|
||||
EmbeddingToFeedForward,
|
||||
)
|
||||
from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.feed_forward_to_embedding import FeedForwardToEmbedding
|
||||
from manim_ml.neural_network.layers.feed_forward_to_feed_forward import FeedForwardToFeedForward
|
||||
from manim_ml.neural_network.layers.feed_forward_to_embedding import (
|
||||
FeedForwardToEmbedding,
|
||||
)
|
||||
from manim_ml.neural_network.layers.feed_forward_to_feed_forward import (
|
||||
FeedForwardToFeedForward,
|
||||
)
|
||||
from manim_ml.neural_network.layers.image import ImageLayer
|
||||
from manim_ml.neural_network.neural_network import NeuralNetwork, FeedForwardNeuralNetwork
|
||||
from manim_ml.neural_network.neural_network import (
|
||||
NeuralNetwork,
|
||||
FeedForwardNeuralNetwork,
|
||||
)
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
|
||||
@ -19,28 +28,30 @@ config.frame_width = 6.0
|
||||
Unit Tests
|
||||
"""
|
||||
|
||||
|
||||
def assert_classes_match(all_layers, expected_classes):
|
||||
assert len(list(all_layers)) == 5
|
||||
|
||||
for index, layer in enumerate(all_layers):
|
||||
expected_class = expected_classes[index]
|
||||
assert isinstance(layer, expected_class), f"Wrong layer class {layer.__class__} expected {expected_class}"
|
||||
assert isinstance(
|
||||
layer, expected_class
|
||||
), f"Wrong layer class {layer.__class__} expected {expected_class}"
|
||||
|
||||
|
||||
def test_embedding_layer():
|
||||
embedding_layer = EmbeddingLayer()
|
||||
|
||||
neural_network = NeuralNetwork([
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer
|
||||
])
|
||||
neural_network = NeuralNetwork(
|
||||
[FeedForwardLayer(5), FeedForwardLayer(3), embedding_layer]
|
||||
)
|
||||
|
||||
expected_classes = [
|
||||
FeedForwardLayer,
|
||||
FeedForwardLayer,
|
||||
FeedForwardToFeedForward,
|
||||
FeedForwardLayer,
|
||||
FeedForwardToEmbedding,
|
||||
EmbeddingLayer
|
||||
EmbeddingLayer,
|
||||
]
|
||||
|
||||
assert_classes_match(neural_network.all_layers, expected_classes)
|
||||
@ -49,18 +60,16 @@ def test_embedding_layer():
|
||||
def test_remove_layer():
|
||||
embedding_layer = EmbeddingLayer()
|
||||
|
||||
neural_network = NeuralNetwork([
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer
|
||||
])
|
||||
neural_network = NeuralNetwork(
|
||||
[FeedForwardLayer(5), FeedForwardLayer(3), embedding_layer]
|
||||
)
|
||||
|
||||
expected_classes = [
|
||||
FeedForwardLayer,
|
||||
FeedForwardLayer,
|
||||
FeedForwardToFeedForward,
|
||||
FeedForwardLayer,
|
||||
FeedForwardToEmbedding,
|
||||
EmbeddingLayer
|
||||
EmbeddingLayer,
|
||||
]
|
||||
|
||||
assert_classes_match(neural_network.all_layers, expected_classes)
|
||||
@ -72,7 +81,7 @@ def test_remove_layer():
|
||||
print(list(neural_network.all_layers))
|
||||
|
||||
expected_classes = [
|
||||
FeedForwardLayer,
|
||||
FeedForwardLayer,
|
||||
FeedForwardToFeedForward,
|
||||
FeedForwardLayer,
|
||||
]
|
||||
@ -81,36 +90,35 @@ def test_remove_layer():
|
||||
|
||||
assert_classes_match(neural_network.all_layers, expected_classes)
|
||||
|
||||
class FeedForwardNeuralNetworkScene(Scene):
|
||||
|
||||
class FeedForwardNeuralNetworkScene(Scene):
|
||||
def construct(self):
|
||||
nn = FeedForwardNeuralNetwork([3, 5, 3])
|
||||
self.play(Create(nn))
|
||||
self.play(Wait(3))
|
||||
|
||||
|
||||
class NeuralNetworkScene(Scene):
|
||||
"""Test Scene for the Neural Network"""
|
||||
|
||||
def construct(self):
|
||||
# Make the Layer object
|
||||
layers = [
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3)
|
||||
]
|
||||
layers = [FeedForwardLayer(3), FeedForwardLayer(5), FeedForwardLayer(3)]
|
||||
nn = NeuralNetwork(layers)
|
||||
nn.move_to(ORIGIN)
|
||||
# Make Animation
|
||||
self.add(nn)
|
||||
#self.play(Create(nn))
|
||||
forward_propagation_animation = nn.make_forward_pass_animation(run_time=5, passing_flash=True)
|
||||
# self.play(Create(nn))
|
||||
forward_propagation_animation = nn.make_forward_pass_animation(
|
||||
run_time=5, passing_flash=True
|
||||
)
|
||||
|
||||
self.play(forward_propagation_animation)
|
||||
|
||||
class GrayscaleImageNeuralNetworkScene(Scene):
|
||||
|
||||
class GrayscaleImageNeuralNetworkScene(Scene):
|
||||
def construct(self):
|
||||
image = Image.open('images/image.jpeg')
|
||||
image = Image.open("images/image.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
# Make nn
|
||||
layers = [
|
||||
@ -118,7 +126,7 @@ class GrayscaleImageNeuralNetworkScene(Scene):
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(6),
|
||||
ImageLayer(numpy_image, height=1.4)
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
]
|
||||
nn = NeuralNetwork(layers)
|
||||
nn.scale(1.3)
|
||||
@ -129,10 +137,10 @@ class GrayscaleImageNeuralNetworkScene(Scene):
|
||||
self.play(nn.make_forward_pass_animation(run_time=5))
|
||||
self.play(nn.make_forward_pass_animation(run_time=5))
|
||||
|
||||
|
||||
class ImageNeuralNetworkScene(Scene):
|
||||
|
||||
def construct(self):
|
||||
image = Image.open('../assets/gan/real_image.jpg')
|
||||
image = Image.open("../assets/gan/real_image.jpg")
|
||||
numpy_image = np.asarray(image)
|
||||
# Make nn
|
||||
layers = [
|
||||
@ -140,7 +148,7 @@ class ImageNeuralNetworkScene(Scene):
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(6),
|
||||
ImageLayer(numpy_image, height=1.4)
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
]
|
||||
nn = NeuralNetwork(layers)
|
||||
nn.scale(1.3)
|
||||
@ -151,44 +159,40 @@ class ImageNeuralNetworkScene(Scene):
|
||||
self.play(nn.make_forward_pass_animation(run_time=5))
|
||||
self.play(nn.make_forward_pass_animation(run_time=5))
|
||||
|
||||
class RecursiveNNScene(Scene):
|
||||
|
||||
class RecursiveNNScene(Scene):
|
||||
def construct(self):
|
||||
nn = NeuralNetwork([
|
||||
NeuralNetwork([
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(2)
|
||||
]),
|
||||
NeuralNetwork([
|
||||
FeedForwardLayer(2),
|
||||
FeedForwardLayer(3)
|
||||
])
|
||||
])
|
||||
nn = NeuralNetwork(
|
||||
[
|
||||
NeuralNetwork([FeedForwardLayer(3), FeedForwardLayer(2)]),
|
||||
NeuralNetwork([FeedForwardLayer(2), FeedForwardLayer(3)]),
|
||||
]
|
||||
)
|
||||
|
||||
self.play(Create(nn))
|
||||
|
||||
class LayerInsertionScene(Scene):
|
||||
|
||||
class LayerInsertionScene(Scene):
|
||||
def construct(self):
|
||||
pass
|
||||
|
||||
class LayerRemovalScene(Scene):
|
||||
|
||||
class LayerRemovalScene(Scene):
|
||||
def construct(self):
|
||||
image = Image.open('images/image.jpeg')
|
||||
image = Image.open("images/image.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
|
||||
layer = FeedForwardLayer(5)
|
||||
layers = [
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(3),
|
||||
layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(6)
|
||||
FeedForwardLayer(6),
|
||||
]
|
||||
|
||||
nn = NeuralNetwork(layers)
|
||||
|
||||
|
||||
self.play(Create(nn))
|
||||
remove_animation = nn.remove_layer(layer)
|
||||
print("before remove")
|
||||
@ -196,21 +200,21 @@ class LayerRemovalScene(Scene):
|
||||
print(nn)
|
||||
print("after remove")
|
||||
|
||||
class LayerInsertionScene(Scene):
|
||||
|
||||
class LayerInsertionScene(Scene):
|
||||
def construct(self):
|
||||
image = Image.open('images/image.jpeg')
|
||||
image = Image.open("images/image.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
|
||||
layers = [
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(6)
|
||||
FeedForwardLayer(6),
|
||||
]
|
||||
|
||||
nn = NeuralNetwork(layers)
|
||||
|
||||
|
||||
self.play(Create(nn))
|
||||
|
||||
layer = FeedForwardLayer(5)
|
||||
@ -219,11 +223,12 @@ class LayerInsertionScene(Scene):
|
||||
print(nn)
|
||||
print("after remove")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""Render all scenes"""
|
||||
# Feed Forward Neural Network
|
||||
ffnn_scene = FeedForwardNeuralNetworkScene()
|
||||
ffnn_scene.render()
|
||||
# Neural Network
|
||||
# Neural Network
|
||||
nn_scene = NeuralNetworkScene()
|
||||
nn_scene.render()
|
||||
|
39
tests/test_nn_dropout.py
Normal file
39
tests/test_nn_dropout.py
Normal file
@ -0,0 +1,39 @@
|
||||
from manim import *
|
||||
from manim_ml.neural_network.layers.feed_forward import FeedForwardLayer
|
||||
from manim_ml.neural_network.layers.image import ImageLayer
|
||||
from PIL import Image
|
||||
from manim_ml.neural_network.neural_network import NeuralNetwork
|
||||
import numpy as np
|
||||
|
||||
config.pixel_height = 1200
|
||||
config.pixel_width = 1900
|
||||
config.frame_height = 4.0
|
||||
config.frame_width = 4.0
|
||||
|
||||
|
||||
class DropoutNeuralNetworkScene(Scene):
|
||||
def construct(self):
|
||||
image = Image.open("../assets/gan/real_image.jpg")
|
||||
numpy_image = np.asarray(image)
|
||||
# Make nn
|
||||
layers = [
|
||||
FeedForwardLayer(3, rectangle_color=BLUE),
|
||||
FeedForwardLayer(5, rectangle_color=BLUE),
|
||||
FeedForwardLayer(3, rectangle_color=BLUE),
|
||||
FeedForwardLayer(6, rectangle_color=BLUE),
|
||||
]
|
||||
nn = NeuralNetwork(layers)
|
||||
# Center the nn
|
||||
nn.move_to(ORIGIN)
|
||||
self.add(nn)
|
||||
# Play animation
|
||||
for i in range(5):
|
||||
self.play(
|
||||
nn.make_forward_pass_animation(run_time=5, feed_forward_dropout=True)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""Render all scenes"""
|
||||
dropout_nn_scene = DropoutNeuralNetworkScene()
|
||||
dropout_nn_scene.render()
|
@ -2,6 +2,7 @@ import manim.utils.opengl as opengl
|
||||
from manim import *
|
||||
from manim.opengl import * # type: ignore
|
||||
|
||||
|
||||
class InlineShaderExample(Scene):
|
||||
def construct(self):
|
||||
config["background_color"] = "#333333"
|
||||
@ -84,4 +85,4 @@ class InlineShaderExample(Scene):
|
||||
self.add(mesh)
|
||||
|
||||
self.wait(5)
|
||||
# self.embed_2()
|
||||
# self.embed_2()
|
||||
|
@ -8,24 +8,24 @@ config.pixel_width = 1280
|
||||
config.frame_height = 6.0
|
||||
config.frame_width = 6.0
|
||||
|
||||
class PairedQueryScene(Scene):
|
||||
|
||||
class PairedQueryScene(Scene):
|
||||
def construct(self):
|
||||
positive_path = "../assets/triplet/positive.jpg"
|
||||
negative_path = "../assets/triplet/negative.jpg"
|
||||
|
||||
paired_layer = PairedQueryLayer.from_paths(positive_path, negative_path, grayscale=False)
|
||||
|
||||
paired_layer = PairedQueryLayer.from_paths(
|
||||
positive_path, negative_path, grayscale=False
|
||||
)
|
||||
|
||||
paired_layer.scale(0.08)
|
||||
|
||||
neural_network = NeuralNetwork([
|
||||
paired_layer,
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3)
|
||||
])
|
||||
neural_network = NeuralNetwork(
|
||||
[paired_layer, FeedForwardLayer(5), FeedForwardLayer(3)]
|
||||
)
|
||||
|
||||
neural_network.scale(1)
|
||||
|
||||
self.play(Create(neural_network), run_time=3)
|
||||
|
||||
self.play(neural_network.make_forward_pass_animation(), run_time=10)
|
||||
self.play(neural_network.make_forward_pass_animation(), run_time=10)
|
||||
|
@ -1,10 +1,10 @@
|
||||
from manim import *
|
||||
|
||||
class SurroundingRectangleTest(Scene):
|
||||
|
||||
class SurroundingRectangleTest(Scene):
|
||||
def construct(self):
|
||||
rectangle = Rectangle(width=1, height=1, color=WHITE, fill_opacity=1.0)
|
||||
self.add(rectangle)
|
||||
|
||||
surrounding_rectangle = SurroundingRectangle(rectangle, color=GREEN, buff=0.0)
|
||||
self.add(surrounding_rectangle)
|
||||
self.add(surrounding_rectangle)
|
||||
|
@ -8,25 +8,25 @@ config.pixel_width = 1280
|
||||
config.frame_height = 6.0
|
||||
config.frame_width = 6.0
|
||||
|
||||
class TripletScene(Scene):
|
||||
|
||||
class TripletScene(Scene):
|
||||
def construct(self):
|
||||
anchor_path = "../assets/triplet/anchor.jpg"
|
||||
positive_path = "../assets/triplet/positive.jpg"
|
||||
negative_path = "../assets/triplet/negative.jpg"
|
||||
|
||||
triplet_layer = TripletLayer.from_paths(anchor_path, positive_path, negative_path, grayscale=False)
|
||||
|
||||
triplet_layer = TripletLayer.from_paths(
|
||||
anchor_path, positive_path, negative_path, grayscale=False
|
||||
)
|
||||
|
||||
triplet_layer.scale(0.08)
|
||||
|
||||
neural_network = NeuralNetwork([
|
||||
triplet_layer,
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3)
|
||||
])
|
||||
neural_network = NeuralNetwork(
|
||||
[triplet_layer, FeedForwardLayer(5), FeedForwardLayer(3)]
|
||||
)
|
||||
|
||||
neural_network.scale(1)
|
||||
|
||||
self.play(Create(neural_network), run_time=3)
|
||||
|
||||
self.play(neural_network.make_forward_pass_animation(), run_time=10)
|
||||
self.play(neural_network.make_forward_pass_animation(), run_time=10)
|
||||
|
@ -8,26 +8,29 @@ config.pixel_width = 1280
|
||||
config.frame_height = 8.0
|
||||
config.frame_width = 8.0
|
||||
|
||||
class VariationalAutoencoderScene(Scene):
|
||||
|
||||
class VariationalAutoencoderScene(Scene):
|
||||
def construct(self):
|
||||
embedding_layer = EmbeddingLayer(dist_theme="ellipse").scale(2)
|
||||
|
||||
image = Image.open('images/image.jpeg')
|
||||
|
||||
image = Image.open("images/image.jpeg")
|
||||
numpy_image = np.asarray(image)
|
||||
# Make nn
|
||||
neural_network = NeuralNetwork([
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
], layer_spacing=0.1)
|
||||
neural_network = NeuralNetwork(
|
||||
[
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
FeedForwardLayer(5),
|
||||
FeedForwardLayer(3),
|
||||
embedding_layer,
|
||||
FeedForwardLayer(3),
|
||||
FeedForwardLayer(5),
|
||||
ImageLayer(numpy_image, height=1.4),
|
||||
],
|
||||
layer_spacing=0.1,
|
||||
)
|
||||
|
||||
neural_network.scale(1.3)
|
||||
|
||||
self.play(Create(neural_network), run_time=3)
|
||||
self.play(neural_network.make_forward_pass_animation(), run_time=5)
|
||||
self.play(neural_network.make_forward_pass_animation(), run_time=5)
|
||||
self.play(neural_network.make_forward_pass_animation(), run_time=5)
|
||||
|
Reference in New Issue
Block a user