3b1b-manim/nn/part2.py
2017-10-05 10:07:28 -07:00

610 lines
18 KiB
Python

import sys
import os.path
import cv2
from helpers import *
from mobject.tex_mobject import TexMobject
from mobject import Mobject, Group
from mobject.image_mobject import ImageMobject
from mobject.vectorized_mobject import *
from animation.animation import Animation
from animation.transform import *
from animation.simple_animations import *
from animation.playground import *
from animation.continual_animation import *
from topics.geometry import *
from topics.characters import *
from topics.functions import *
from topics.fractals import *
from topics.number_line import *
from topics.combinatorics import *
from topics.numerals import *
from topics.three_dimensions import *
from topics.objects import *
from topics.probability import *
from topics.complex_numbers import *
from topics.graph_scene import *
from topics.common_scenes import *
from scene import Scene
from scene.reconfigurable_scene import ReconfigurableScene
from scene.zoomed_scene import *
from camera import Camera
from mobject.svg_mobject import *
from mobject.tex_mobject import *
from nn.network import *
from nn.part1 import *
def get_training_image_group(train_in, train_out):
image = MNistMobject(train_in)
image.scale_to_fit_height(1)
arrow = Vector(RIGHT, color = BLUE, buff = 0)
output = np.argmax(train_out)
output_tex = TexMobject(str(output)).scale(1.5)
result = Group(image, arrow, output_tex)
result.arrange_submobjects(RIGHT)
result.to_edge(UP)
return result
########
class ShowLastVideo(TeacherStudentsScene):
def construct(self):
frame = ScreenRectangle()
frame.scale_to_fit_height(4.5)
frame.to_corner(UP+LEFT)
title = TextMobject("But what \\emph{is} a Neural Network")
title.move_to(frame)
title.to_edge(UP)
frame.next_to(title, DOWN)
assumption_words = TextMobject(
"I assume you've\\\\ watched this"
)
assumption_words.move_to(frame)
assumption_words.to_edge(RIGHT)
arrow = Arrow(RIGHT, LEFT, color = BLUE)
arrow.next_to(assumption_words, LEFT)
self.play(
ShowCreation(frame),
self.teacher.change, "raise_right_hand"
)
self.play(
Write(title),
self.get_student_changes(*["thinking"]*3)
)
self.play(
Animation(title),
GrowArrow(arrow),
FadeIn(assumption_words)
)
self.dither(5)
class PreviewLearning(NetworkScene):
CONFIG = {
"layer_sizes" : DEFAULT_LAYER_SIZES,
"network_mob_config" : {
"neuron_to_neuron_buff" : SMALL_BUFF,
"layer_to_layer_buff" : 2,
"edge_stroke_width" : 1,
"neuron_stroke_color" : WHITE,
"neuron_stroke_width" : 2,
"neuron_fill_color" : WHITE,
"average_shown_activation_of_large_layer" : False,
"edge_propogation_color" : GREEN,
"edge_propogation_time" : 2,
"include_output_labels" : True,
},
"n_examples" : 15,
"max_stroke_width" : 3,
"stroke_width_exp" : 3,
"eta" : 3.0,
"positive_change_color" : average_color(*2*[GREEN] + [YELLOW]),
"negative_change_color" : average_color(*2*[RED] + [YELLOW]),
}
def construct(self):
self.initialize_network()
self.add_training_words()
self.show_training()
def initialize_network(self):
self.network_mob.scale(0.7)
self.network_mob.to_edge(DOWN)
self.color_network_edges()
def add_training_words(self):
words = TextMobject("Training in \\\\ progress$\\dots$")
words.scale(1.5)
words.to_corner(UP+LEFT)
self.add(words)
def show_training(self):
training_data, validation_data, test_data = load_data_wrapper()
for train_in, train_out in training_data[:self.n_examples]:
image = get_training_image_group(train_in, train_out)
self.activate_network(train_in, FadeIn(image))
self.backprop_one_example(
train_in, train_out,
FadeOut(image), self.network_mob.layers.restore
)
def activate_network(self, train_in, *added_anims):
network_mob = self.network_mob
layers = network_mob.layers
layers.save_state()
activations = self.network.get_activation_of_all_layers(train_in)
active_layers = [
self.network_mob.get_active_layer(i, vect)
for i, vect in enumerate(activations)
]
all_edges = VGroup(*it.chain(*network_mob.edge_groups))
edge_animation = LaggedStart(
ShowCreationThenDestruction,
all_edges.copy().set_fill(YELLOW),
run_time = 1.5,
lag_ratio = 0.3,
remover = True,
)
layer_animation = Transform(
VGroup(*layers), VGroup(*active_layers),
run_time = 1.5,
submobject_mode = "lagged_start",
rate_func = None,
)
self.play(edge_animation, layer_animation, *added_anims)
def backprop_one_example(self, train_in, train_out, *added_outro_anims):
network_mob = self.network_mob
nabla_b, nabla_w = self.network.backprop(train_in, train_out)
neuron_groups = VGroup(*[
layer.neurons
for layer in network_mob.layers[1:]
])
delta_neuron_groups = neuron_groups.copy()
edge_groups = network_mob.edge_groups
delta_edge_groups = VGroup(*[
edge_group.copy()
for edge_group in edge_groups
])
tups = zip(
it.count(), nabla_b, nabla_w,
delta_neuron_groups, neuron_groups,
delta_edge_groups, edge_groups
)
pc_color = self.positive_change_color
nc_color = self.negative_change_color
for i, nb, nw, delta_neurons, neurons, delta_edges, edges in reversed(tups):
shown_nw = self.get_adjusted_first_matrix(nw)
if np.max(shown_nw) == 0:
shown_nw = (2*np.random.random(shown_nw.shape)-1)**5
max_b = np.max(np.abs(nb))
max_w = np.max(np.abs(shown_nw))
for neuron, b in zip(delta_neurons, nb):
color = nc_color if b > 0 else pc_color
# neuron.set_fill(color, abs(b)/max_b)
neuron.set_stroke(color, 3)
for edge, w in zip(delta_edges.split(), shown_nw.T.flatten()):
edge.set_stroke(
nc_color if w > 0 else pc_color,
3*abs(w)/max_w
)
edge.rotate_in_place(np.pi)
if i == 2:
delta_edges.submobjects = [
delta_edges[j]
for j in np.argsort(shown_nw.T.flatten())
]
network = self.network
network.weights[i] -= self.eta*nw
network.biases[i] -= self.eta*nb
self.play(
ShowCreation(
delta_edges, submobject_mode = "all_at_once"
),
FadeIn(delta_neurons),
run_time = 0.5
)
edge_groups.save_state()
self.color_network_edges()
self.remove(edge_groups)
self.play(*it.chain(
[ReplacementTransform(
edge_groups.saved_state, edge_groups,
)],
map(FadeOut, [delta_edge_groups, delta_neuron_groups]),
added_outro_anims,
))
#####
def get_adjusted_first_matrix(self, matrix):
n = self.network_mob.max_shown_neurons
if matrix.shape[1] > n:
half = matrix.shape[1]/2
return matrix[:,half-n/2:half+n/2]
else:
return matrix
def color_network_edges(self):
layers = self.network_mob.layers
weight_matrices = self.network.weights
for layer, matrix in zip(layers[1:], weight_matrices):
matrix = self.get_adjusted_first_matrix(matrix)
matrix_max = np.max(matrix)
for neuron, row in zip(layer.neurons, matrix):
for edge, w in zip(neuron.edges_in, row):
color = GREEN if w > 0 else RED
msw = self.max_stroke_width
swe = self.stroke_width_exp
sw = msw*(abs(w)/matrix_max)**swe
sw = min(sw, msw)
edge.set_stroke(color, sw)
class TrainingVsTestData(Scene):
CONFIG = {
"n_examples" : 10,
"n_new_examples_shown" : 10,
}
def construct(self):
self.initialize_data()
self.introduce_all_data()
self.subdivide_into_training_and_testing()
self.scroll_through_much_data()
def initialize_data(self):
training_data, validation_data, test_data = load_data_wrapper()
self.data = training_data
self.curr_index = 0
def get_examples(self):
ci = self.curr_index
self.curr_index += self.n_examples
group = Group(*it.starmap(
get_training_image_group,
self.data[ci:ci+self.n_examples]
))
group.arrange_submobjects(DOWN)
group.scale(0.5)
return group
def introduce_all_data(self):
training_examples, test_examples = [
self.get_examples() for x in range(2)
]
training_examples.next_to(ORIGIN, LEFT)
test_examples.next_to(ORIGIN, RIGHT)
self.play(
LaggedStart(FadeIn, training_examples),
LaggedStart(FadeIn, test_examples),
)
self.training_examples = training_examples
self.test_examples = test_examples
def subdivide_into_training_and_testing(self):
training_examples = self.training_examples
test_examples = self.test_examples
for examples in training_examples, test_examples:
examples.generate_target()
training_examples.target.shift(2*LEFT)
test_examples.target.shift(2*RIGHT)
train_brace = Brace(training_examples.target, LEFT)
train_words = train_brace.get_text("Train on \\\\ these")
test_brace = Brace(test_examples.target, RIGHT)
test_words = test_brace.get_text("Test on \\\\ these")
bools = [True]*(len(test_examples)-1) + [False]
random.shuffle(bools)
marks = VGroup()
for is_correct, test_example in zip(bools, test_examples.target):
if is_correct:
mark = TexMobject("\\checkmark")
mark.highlight(GREEN)
else:
mark = TexMobject("\\times")
mark.highlight(RED)
mark.next_to(test_example, LEFT)
marks.add(mark)
self.play(
MoveToTarget(training_examples),
GrowFromCenter(train_brace),
FadeIn(train_words)
)
self.dither()
self.play(
MoveToTarget(test_examples),
GrowFromCenter(test_brace),
FadeIn(test_words)
)
self.play(Write(marks))
self.dither()
def scroll_through_much_data(self):
training_examples = self.training_examples
colors = color_gradient([BLUE, YELLOW], self.n_new_examples_shown)
for color in colors:
new_examples = self.get_examples()
new_examples.move_to(training_examples)
for train_ex, new_ex in zip(training_examples, new_examples):
self.remove(train_ex)
self.add(new_ex)
new_ex[0][0].highlight(color)
self.dither(1./30)
training_examples = new_examples
class NotSciFi(TeacherStudentsScene):
def construct(self):
students = self.students
self.student_says(
"Machines learning?!?",
student_index = 0,
target_mode = "pleading",
run_time = 1,
)
bubble = students[0].bubble
students[0].bubble = None
self.student_says(
"Should we \\\\ be worried?", student_index = 2,
target_mode = "confused",
bubble_kwargs = {"direction" : LEFT},
run_time = 1,
)
self.dither()
students[0].bubble = bubble
self.teacher_says(
"It's actually \\\\ just calculus.",
run_time = 1
)
self.teacher.bubble = None
self.dither()
self.student_says(
"Even worse!",
target_mode = "horrified",
bubble_kwargs = {
"direction" : LEFT,
"width" : 3,
"height" : 2,
},
)
self.dither(2)
class FunctionMinmization(GraphScene):
CONFIG = {
"x_labeled_nums" : range(-1, 10),
}
def construct(self):
self.setup_axes()
title = TextMobject("Finding minima")
title.to_edge(UP)
self.add(title)
def func(x):
x -= 4.5
return 0.03*(x**4 - 16*x**2) + 0.3*x + 4
graph = self.get_graph(func)
graph_label = self.get_graph_label(graph, "C(x)")
self.add(graph, graph_label)
dots = VGroup(*[
Dot().move_to(self.input_to_graph_point(x, graph))
for x in range(10)
])
dots.gradient_highlight(YELLOW, RED)
def update_dot(dot, dt):
x = self.x_axis.point_to_number(dot.get_center())
slope = self.slope_of_tangent(x, graph)
x -= slope*dt
dot.move_to(self.input_to_graph_point(x, graph))
self.add(*[
ContinualUpdateFromFunc(dot, update_dot)
for dot in dots
])
self.dither(10)
class IntroduceCostFunction(PreviewLearning):
def construct(self):
self.force_skipping()
self.isolate_one_neuron()
self.reminder_of_weights_and_bias()
self.initialize_randomly()
self.feed_in_example()
self.make_fun_of_output()
self.need_a_cost_function()
self.show_cost_function()
def isolate_one_neuron(self):
network_mob = self.network_mob
network_mob.shift(LEFT)
neuron_groups = VGroup(*[
layer.neurons
for layer in network_mob.layers[1:]
])
edge_groups = network_mob.edge_groups
neuron = neuron_groups[0][7].deepcopy()
output_labels = network_mob.output_labels
kwargs = {
"submobject_mode" : "lagged_start",
"run_time" : 2,
}
self.play(
FadeOut(edge_groups, **kwargs),
FadeOut(neuron_groups, **kwargs),
FadeOut(output_labels, **kwargs),
Animation(neuron),
neuron.edges_in.set_stroke, None, 2,
)
self.dither()
self.neuron = neuron
def reminder_of_weights_and_bias(self):
neuron = self.neuron
layer0 = self.network_mob.layers[0]
active_layer0 = self.network_mob.get_active_layer(
0, np.random.random(len(layer0.neurons))
)
prev_neurons = layer0.neurons
weights = 4*(np.random.random(len(neuron.edges_in))-0.5)
weighted_edges = VGroup(*[
edge.copy().set_stroke(
color = GREEN if w > 0 else RED,
width = abs(w)
)
for w, edge in zip(weights, neuron.edges_in)
])
formula = TexMobject(
"=", "\\sigma(",
"w_1", "a_1", "+",
"w_2", "a_2", "+",
"\\cdots", "+",
"w_n", "a_n", "+", "b", ")"
)
w_labels = formula.get_parts_by_tex("w_")
a_labels = formula.get_parts_by_tex("a_")
b = formula.get_part_by_tex("b")
sigma = VGroup(
formula.get_part_by_tex("\\sigma"),
formula.get_part_by_tex(")"),
)
symbols = VGroup(*[
formula.get_parts_by_tex(tex)
for tex in "=", "+", "dots"
])
w_labels.highlight(GREEN)
b.highlight(BLUE)
sigma.highlight(YELLOW)
# formula.to_edge(UP)
formula.next_to(neuron, RIGHT)
weights_word = TextMobject("Weights")
weights_word.next_to(neuron.edges_in, RIGHT, aligned_edge = UP)
weights_word.highlight(GREEN)
weights_arrow = Arrow(
weights_word.get_bottom(),
neuron.edges_in[0].get_center(),
color = GREEN
)
alt_weights_arrows = VGroup(*[
Arrow(
weights_word.get_bottom(),
w_label.get_top(),
color = GREEN
)
for w_label in w_labels
])
bias_word = TextMobject("Bias")
bias_arrow = Vector(DOWN, color = BLUE)
bias_arrow.next_to(b, UP, SMALL_BUFF)
bias_word.next_to(bias_arrow, UP, SMALL_BUFF)
bias_word.highlight(BLUE)
self.revert_to_original_skipping_status()
self.play(
Transform(layer0, active_layer0),
FadeIn(a_labels),
FadeIn(symbols),
run_time = 2,
submobject_mode = "lagged_start"
)
self.play(
Write(weights_word),
GrowArrow(weights_arrow),
Transform(neuron.edges_in, weighted_edges),
run_time = 1,
)
self.dither()
self.play(
ReplacementTransform(
weighted_edges.copy(), w_labels,
),
ReplacementTransform(
VGroup(weights_arrow),
alt_weights_arrows
)
)
self.dither()
self.play(
Write(b),
Write(bias_word),
GrowArrow(bias_arrow),
run_time = 1
)
self.play(Write(sigma))
self.dither(2)
def initialize_randomly(self):
pass
def feed_in_example(self):
pass
def make_fun_of_output(self):
pass
def need_a_cost_function(self):
pass
def show_cost_function(self):
pass
####
def activate_network(self, train_in, *added_anims):
##TODO
PreviewLearning.activate_network(self, train_in, *added_anims)