Sys path append(os path join(os path dirname



Download 145,21 Kb.
Sana03.07.2022
Hajmi145,21 Kb.
#735383
Bog'liq
code


import sys
import os.path
import cv2

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))


from manim_imports_ext import *


import warnings


warnings.warn("""
Warning: This file makes use of
ContinualAnimation, which has since
been deprecated
""")
from nn.network import *

#force_skipping


#revert_to_original_skipping_status
DEFAULT_GAUSS_BLUR_CONFIG = {
"ksize" : (5, 5),
"sigmaX" : 10,
"sigmaY" : 10,
}

DEFAULT_CANNY_CONFIG = {


"threshold1" : 100,
"threshold2" : 200,
}
def get_edges(image_array):
blurred = cv2.GaussianBlur(
image_array,
**DEFAULT_GAUSS_BLUR_CONFIG
)
edges = cv2.Canny(
blurred,
**DEFAULT_CANNY_CONFIG
)
return edges

class WrappedImage(Group):


CONFIG = {
"rect_kwargs" : {
"color" : BLUE,
"buff" : SMALL_BUFF,
}
}
def __init__(self, image_mobject, **kwargs):
Group.__init__(self, **kwargs)
rect = SurroundingRectangle(
image_mobject, **self.rect_kwargs
)
self.add(rect, image_mobject)

class PixelsAsSquares(VGroup):


CONFIG = {
"height" : 2,
}
def __init__(self, image_mobject, **kwargs):
VGroup.__init__(self, **kwargs)
for row in image_mobject.pixel_array:
for rgba in row:
square = Square(
stroke_width = 0,
fill_opacity = rgba[3]/255.0,
fill_color = rgba_to_color(rgba/255.0),
)
self.add(square)
self.arrange_in_grid(
*image_mobject.pixel_array.shape[:2],
buff = 0
)
self.replace(image_mobject)

class PixelsFromVect(PixelsAsSquares):


def __init__(self, vect, **kwargs):
PixelsAsSquares.__init__(self,
ImageMobject(layer_to_image_array(vect)),
**kwargs
)

class MNistMobject(WrappedImage):


def __init__(self, vect, **kwargs):
WrappedImage.__init__(self,
ImageMobject(layer_to_image_array(vect)),
**kwargs
)

class NetworkMobject(VGroup):


CONFIG = {
"neuron_radius" : 0.15,
"neuron_to_neuron_buff" : MED_SMALL_BUFF,
"layer_to_layer_buff" : LARGE_BUFF,
"neuron_stroke_color" : BLUE,
"neuron_stroke_width" : 3,
"neuron_fill_color" : GREEN,
"edge_color" : GREY_B,
"edge_stroke_width" : 2,
"edge_propogation_color" : YELLOW,
"edge_propogation_time" : 1,
"max_shown_neurons" : 16,
"brace_for_large_layers" : True,
"average_shown_activation_of_large_layer" : True,
"include_output_labels" : False,
}
def __init__(self, neural_network, **kwargs):
VGroup.__init__(self, **kwargs)
self.neural_network = neural_network
self.layer_sizes = neural_network.sizes
self.add_neurons()
self.add_edges()

def add_neurons(self):


layers = VGroup(*[
self.get_layer(size)
for size in self.layer_sizes
])
layers.arrange(RIGHT, buff = self.layer_to_layer_buff)
self.layers = layers
self.add(self.layers)
if self.include_output_labels:
self.add_output_labels()

def get_layer(self, size):


layer = VGroup()
n_neurons = size
if n_neurons > self.max_shown_neurons:
n_neurons = self.max_shown_neurons
neurons = VGroup(*[
Circle(
radius = self.neuron_radius,
stroke_color = self.neuron_stroke_color,
stroke_width = self.neuron_stroke_width,
fill_color = self.neuron_fill_color,
fill_opacity = 0,
)
for x in range(n_neurons)
])
neurons.arrange(
DOWN, buff = self.neuron_to_neuron_buff
)
for neuron in neurons:
neuron.edges_in = VGroup()
neuron.edges_out = VGroup()
layer.neurons = neurons
layer.add(neurons)

if size > n_neurons:


dots = Tex("\\vdots")
dots.move_to(neurons)
VGroup(*neurons[:len(neurons) // 2]).next_to(
dots, UP, MED_SMALL_BUFF
)
VGroup(*neurons[len(neurons) // 2:]).next_to(
dots, DOWN, MED_SMALL_BUFF
)
layer.dots = dots
layer.add(dots)
if self.brace_for_large_layers:
brace = Brace(layer, LEFT)
brace_label = brace.get_tex(str(size))
layer.brace = brace
layer.brace_label = brace_label
layer.add(brace, brace_label)

return layer


def add_edges(self):


self.edge_groups = VGroup()
for l1, l2 in zip(self.layers[:-1], self.layers[1:]):
edge_group = VGroup()
for n1, n2 in it.product(l1.neurons, l2.neurons):
edge = self.get_edge(n1, n2)
edge_group.add(edge)
n1.edges_out.add(edge)
n2.edges_in.add(edge)
self.edge_groups.add(edge_group)
self.add_to_back(self.edge_groups)

def get_edge(self, neuron1, neuron2):


return Line(
neuron1.get_center(),
neuron2.get_center(),
buff = self.neuron_radius,
stroke_color = self.edge_color,
stroke_width = self.edge_stroke_width,
)

def get_active_layer(self, layer_index, activation_vector):


layer = self.layers[layer_index].deepcopy()
self.activate_layer(layer, activation_vector)
return layer

def activate_layer(self, layer, activation_vector):


n_neurons = len(layer.neurons)
av = activation_vector
def arr_to_num(arr):
return (np.sum(arr > 0.1) / float(len(arr)))**(1./3)

if len(av) > n_neurons:


if self.average_shown_activation_of_large_layer:
indices = np.arange(n_neurons)
indices *= int(len(av)/n_neurons)
indices = list(indices)
indices.append(len(av))
av = np.array([
arr_to_num(av[i1:i2])
for i1, i2 in zip(indices[:-1], indices[1:])
])
else:
av = np.append(
av[:n_neurons/2],
av[-n_neurons/2:],
)
for activation, neuron in zip(av, layer.neurons):
neuron.set_fill(
color = self.neuron_fill_color,
opacity = activation
)
return layer

def activate_layers(self, input_vector):


activations = self.neural_network.get_activation_of_all_layers(input_vector)
for activation, layer in zip(activations, self.layers):
self.activate_layer(layer, activation)

def deactivate_layers(self):


all_neurons = VGroup(*it.chain(*[
layer.neurons
for layer in self.layers
]))
all_neurons.set_fill(opacity = 0)
return self

def get_edge_propogation_animations(self, index):


edge_group_copy = self.edge_groups[index].copy()
edge_group_copy.set_stroke(
self.edge_propogation_color,
width = 1.5*self.edge_stroke_width
)
return [ShowCreationThenDestruction(
edge_group_copy,
run_time = self.edge_propogation_time,
lag_ratio = 0.5
)]

def add_output_labels(self):


self.output_labels = VGroup()
for n, neuron in enumerate(self.layers[-1].neurons):
label = Tex(str(n))
label.set_height(0.75*neuron.get_height())
label.move_to(neuron)
label.shift(neuron.get_width()*RIGHT)
self.output_labels.add(label)
self.add(self.output_labels)

class MNistNetworkMobject(NetworkMobject):


CONFIG = {
"neuron_to_neuron_buff" : SMALL_BUFF,
"layer_to_layer_buff" : 1.5,
"edge_stroke_width" : 1,
"include_output_labels" : True,
}

def __init__(self, **kwargs):


network = get_pretrained_network()
NetworkMobject.__init__(self, network, **kwargs)

class NetworkScene(Scene):


CONFIG = {
"layer_sizes" : [8, 6, 6, 4],
"network_mob_config" : {},
}
def setup(self):
self.add_network()

def add_network(self):


self.network = Network(sizes = self.layer_sizes)
self.network_mob = NetworkMobject(
self.network,
**self.network_mob_config
)
self.add(self.network_mob)

def feed_forward(self, input_vector, false_confidence = False, added_anims = None):


if added_anims is None:
added_anims = []
activations = self.network.get_activation_of_all_layers(
input_vector
)
if false_confidence:
i = np.argmax(activations[-1])
activations[-1] *= 0
activations[-1][i] = 1.0
for i, activation in enumerate(activations):
self.show_activation_of_layer(i, activation, added_anims)
added_anims = []

def show_activation_of_layer(self, layer_index, activation_vector, added_anims = None):


if added_anims is None:
added_anims = []
layer = self.network_mob.layers[layer_index]
active_layer = self.network_mob.get_active_layer(
layer_index, activation_vector
)
anims = [Transform(layer, active_layer)]
if layer_index > 0:
anims += self.network_mob.get_edge_propogation_animations(
layer_index-1
)
anims += added_anims
self.play(*anims)

def remove_random_edges(self, prop = 0.9):


for edge_group in self.network_mob.edge_groups:
for edge in list(edge_group):
if np.random.random() < prop:
edge_group.remove(edge)

def make_transparent(image_mob):


alpha_vect = np.array(
image_mob.pixel_array[:,:,0],
dtype = 'uint8'
)
image_mob.set_color(WHITE)
image_mob.pixel_array[:,:,3] = alpha_vect
return image_mob

###############################


class ExampleThrees(PiCreatureScene):


def construct(self):
self.show_initial_three()
self.show_alternate_threes()
self.resolve_remaining_threes()
self.show_alternate_digits()

def show_initial_three(self):


randy = self.pi_creature

self.three_mobs = self.get_three_mobs()


three_mob = self.three_mobs[0]
three_mob_copy = three_mob[1].copy()
three_mob_copy.sort(lambda p : np.dot(p, DOWN+RIGHT))

braces = VGroup(*[Brace(three_mob, v) for v in (LEFT, UP)])


brace_labels = VGroup(*[
brace.get_text("28px")
for brace in braces
])

bubble = randy.get_bubble(height = 4, width = 6)


three_mob.generate_target()
three_mob.target.set_height(1)
three_mob.target.next_to(bubble[-1].get_left(), RIGHT, LARGE_BUFF)
arrow = Arrow(LEFT, RIGHT, color = BLUE)
arrow.next_to(three_mob.target, RIGHT)
real_three = Tex("3")
real_three.set_height(0.8)
real_three.next_to(arrow, RIGHT)

self.play(


FadeIn(three_mob[0]),
LaggedStartMap(FadeIn, three_mob[1])
)
self.wait()
self.play(
LaggedStartMap(
DrawBorderThenFill, three_mob_copy,
run_time = 3,
stroke_color = WHITE,
remover = True,
),
randy.change, "sassy",
*it.chain(
list(map(GrowFromCenter, braces)),
list(map(FadeIn, brace_labels))
)
)
self.wait()
self.play(
ShowCreation(bubble),
MoveToTarget(three_mob),
FadeOut(braces),
FadeOut(brace_labels),
randy.change, "pondering"
)
self.play(
ShowCreation(arrow),
Write(real_three)
)
self.wait()

self.bubble = bubble


self.arrow = arrow
self.real_three = real_three

def show_alternate_threes(self):


randy = self.pi_creature

three = self.three_mobs[0]


three.generate_target()
three.target[0].set_fill(opacity = 0, family = False)
for square in three.target[1]:
yellow_rgb = color_to_rgb(YELLOW)
square_rgb = color_to_rgb(square.get_fill_color())
square.set_fill(
rgba_to_color(yellow_rgb*square_rgb),
opacity = 0.5
)

alt_threes = VGroup(*self.three_mobs[1:])


alt_threes.arrange(DOWN)
alt_threes.set_height(FRAME_HEIGHT - 2)
alt_threes.to_edge(RIGHT)

for alt_three in alt_threes:


self.add(alt_three)
self.wait(0.5)
self.play(
randy.change, "plain",
*list(map(FadeOut, [
self.bubble, self.arrow, self.real_three
])) + [MoveToTarget(three)]
)
for alt_three in alt_threes[:2]:
self.play(three.replace, alt_three)
self.wait()
for moving_three in three, alt_threes[1]:
moving_three.generate_target()
moving_three.target.next_to(alt_threes, LEFT, LARGE_BUFF)
moving_three.target[0].set_stroke(width = 0)
moving_three.target[1].space_out_submobjects(1.5)
self.play(MoveToTarget(
moving_three, lag_ratio = 0.5
))
self.play(
Animation(randy),
moving_three.replace, randy.eyes[1],
moving_three.scale, 0.7,
run_time = 2,
lag_ratio = 0.5,
)
self.play(
Animation(randy),
FadeOut(moving_three)
)

self.remaining_threes = [alt_threes[0], alt_threes[2]]


def resolve_remaining_threes(self):


randy = self.pi_creature

left_three, right_three = self.remaining_threes


equals = Tex("=")
equals.move_to(self.arrow)
for three, vect in (left_three, LEFT), (right_three, RIGHT):
three.generate_target()
three.target.set_height(1)
three.target.next_to(equals, vect)

self.play(


randy.change, "thinking",
ShowCreation(self.bubble),
MoveToTarget(left_three),
MoveToTarget(right_three),
Write(equals),
)
self.wait()

self.equals = equals


def show_alternate_digits(self):


randy = self.pi_creature
cross = Cross(self.equals)
cross.stretch_to_fit_height(0.5)
three = self.remaining_threes[1]

image_map = get_organized_images()


arrays = [image_map[k][0] for k in range(8, 4, -1)]
alt_mobs = [
WrappedImage(
PixelsAsSquares(ImageMobject(layer_to_image_array(arr))),
color = GREY_B,
buff = 0
).replace(three)
for arr in arrays
]

self.play(


randy.change, "sassy",
Transform(three, alt_mobs[0]),
ShowCreation(cross)
)
self.wait()
for mob in alt_mobs[1:]:
self.play(Transform(three, mob))
self.wait()

######

def create_pi_creature(self):
return Randolph().to_corner(DOWN+LEFT)

def get_three_mobs(self):


three_arrays = get_organized_images()[3][:4]
three_mobs = VGroup()
for three_array in three_arrays:
im_mob = ImageMobject(
layer_to_image_array(three_array),
height = 4,
)
pixel_mob = PixelsAsSquares(im_mob)
three_mob = WrappedImage(
pixel_mob,
color = GREY_B,
buff = 0
)
three_mobs.add(three_mob)
return three_mobs

class BrainAndHow(Scene):


def construct(self):
brain = SVGMobject(file_name = "brain")
brain.set_height(2)
brain.set_fill(GREY_B)
brain_outline = brain.copy()
brain_outline.set_fill(opacity = 0)
brain_outline.set_stroke(BLUE_B, 3)

how = TexText("How?!?")


how.scale(2)
how.next_to(brain, UP)

self.add(brain)


self.play(Write(how))
for x in range(2):
self.play(
ShowPassingFlash(
brain_outline,
time_width = 0.5,
run_time = 2
)
)
self.wait()

class WriteAProgram(Scene):


def construct(self):
three_array = get_organized_images()[3][0]
im_mob = ImageMobject(layer_to_image_array(three_array))
three = PixelsAsSquares(im_mob)
three.sort(lambda p : np.dot(p, DOWN+RIGHT))
three.set_height(6)
three.next_to(ORIGIN, LEFT)
three_rect = SurroundingRectangle(
three,
color = BLUE,
buff = SMALL_BUFF
)

numbers = VGroup()


for square in three:
rgb = square.fill_rgb
num = DecimalNumber(
square.fill_rgb[0],
num_decimal_places = 1
)
num.set_stroke(width = 1)
color = rgba_to_color(1 - (rgb + 0.2)/1.2)
num.set_color(color)
num.set_width(0.7*square.get_width())
num.move_to(square)
numbers.add(num)

arrow = Arrow(LEFT, RIGHT, color = BLUE)


arrow.next_to(three, RIGHT)

choices = VGroup(*[Tex(str(n)) for n in range(10)])


choices.arrange(DOWN)
choices.set_height(FRAME_HEIGHT - 1)
choices.next_to(arrow, RIGHT)

self.play(


LaggedStartMap(DrawBorderThenFill, three),
ShowCreation(three_rect)
)
self.play(Write(numbers))
self.play(
ShowCreation(arrow),
LaggedStartMap(FadeIn, choices),
)

rect = SurroundingRectangle(choices[0], buff = SMALL_BUFF)


q_mark = Tex("?")
q_mark.next_to(rect, RIGHT)
self.play(ShowCreation(rect))
for n in 8, 1, 5, 3:
self.play(
rect.move_to, choices[n],
MaintainPositionRelativeTo(q_mark, rect)
)
self.wait(1)
choice = choices[3]
choices.remove(choice)
choice.add(rect)
self.play(
choice.scale, 1.5,
choice.next_to, arrow, RIGHT,
FadeOut(choices),
FadeOut(q_mark),
)
self.wait(2)

class LayOutPlan(TeacherStudentsScene, NetworkScene):


def setup(self):
TeacherStudentsScene.setup(self)
NetworkScene.setup(self)
self.remove(self.network_mob)

def construct(self):


self.force_skipping()

self.show_words()


self.show_network()
self.show_math()
self.ask_about_layers()
self.show_learning()
self.show_videos()

def show_words(self):


words = VGroup(
TexText("Machine", "learning").set_color(GREEN),
TexText("Neural network").set_color(BLUE),
)
words.next_to(self.teacher.get_corner(UP+LEFT), UP)
words[0].save_state()
words[0].shift(DOWN)
words[0].fade(1)

self.play(


words[0].restore,
self.teacher.change, "raise_right_hand",
self.get_student_changes("pondering", "erm", "sassy")
)
self.play(
words[0].shift, MED_LARGE_BUFF*UP,
FadeIn(words[1]),
)
self.change_student_modes(
*["pondering"]*3,
look_at_arg = words
)
self.play(words.to_corner, UP+RIGHT)

self.words = words


def show_network(self):


network_mob = self.network_mob
network_mob.next_to(self.students, UP)

self.play(


ReplacementTransform(
VGroup(self.words[1].copy()),
network_mob.layers
),
self.get_student_changes(
*["confused"]*3,
lag_ratio = 0
),
self.teacher.change, "plain",
run_time = 1
)
self.play(ShowCreation(
network_mob.edge_groups,
lag_ratio = 0.5,
run_time = 2,
rate_func=linear,
))
in_vect = np.random.random(self.network.sizes[0])
self.feed_forward(in_vect)

def show_math(self):


equation = Tex(
"\\textbf{a}_{l+1}", "=",
"\\sigma(",
"W_l", "\\textbf{a}_l", "+", "b_l",
")"
)
equation.set_color_by_tex_to_color_map({
"\\textbf{a}" : GREEN,
})
equation.move_to(self.network_mob.get_corner(UP+RIGHT))
equation.to_edge(UP)

self.play(Write(equation, run_time = 2))


self.wait()

self.equation = equation


def ask_about_layers(self):


self.student_says(
"Why the layers?",
student_index = 2,
bubble_kwargs = {"direction" : LEFT}
)
self.wait()
self.play(RemovePiCreatureBubble(self.students[2]))

def show_learning(self):


word = self.words[0][1].copy()
rect = SurroundingRectangle(word, color = YELLOW)
self.network_mob.neuron_fill_color = YELLOW

layer = self.network_mob.layers[-1]


activation = np.zeros(len(layer.neurons))
activation[1] = 1.0
active_layer = self.network_mob.get_active_layer(
-1, activation
)
word_group = VGroup(word, rect)
word_group.generate_target()
word_group.target.move_to(self.equation, LEFT)
word_group.target[0].set_color(YELLOW)
word_group.target[1].set_stroke(width = 0)

self.play(ShowCreation(rect))


self.play(
Transform(layer, active_layer),
FadeOut(self.equation),
MoveToTarget(word_group),
)
for edge_group in reversed(self.network_mob.edge_groups):
edge_group.generate_target()
for edge in edge_group.target:
edge.set_stroke(
YELLOW,
width = 4*np.random.random()**2
)
self.play(MoveToTarget(edge_group))
self.wait()

self.learning_word = word


def show_videos(self):


network_mob = self.network_mob
learning = self.learning_word
structure = TexText("Structure")
structure.set_color(YELLOW)
videos = VGroup(*[
VideoIcon().set_fill(RED)
for x in range(2)
])
videos.set_height(1.5)
videos.arrange(RIGHT, buff = LARGE_BUFF)
videos.next_to(self.students, UP, LARGE_BUFF)

network_mob.generate_target()


network_mob.target.set_height(0.8*videos[0].get_height())
network_mob.target.move_to(videos[0])
learning.generate_target()
learning.target.next_to(videos[1], UP)
structure.next_to(videos[0], UP)
structure.shift(0.5*SMALL_BUFF*UP)

self.revert_to_original_skipping_status()


self.play(
MoveToTarget(network_mob),
MoveToTarget(learning)
)
self.play(
DrawBorderThenFill(videos[0]),
FadeIn(structure),
self.get_student_changes(*["pondering"]*3)
)
self.wait()
self.play(DrawBorderThenFill(videos[1]))
self.wait()

class PreviewMNistNetwork(NetworkScene):


CONFIG = {
"n_examples" : 15,
"network_mob_config" : {},
}
def construct(self):
self.remove_random_edges(0.7) #Remove?

training_data, validation_data, test_data = load_data_wrapper()


for data in test_data[:self.n_examples]:
self.feed_in_image(data[0])

def feed_in_image(self, in_vect):


image = PixelsFromVect(in_vect)
image.next_to(self.network_mob, LEFT, LARGE_BUFF, UP)
image.shift_onto_screen()
image_rect = SurroundingRectangle(image, color = BLUE)
start_neurons = self.network_mob.layers[0].neurons.copy()
start_neurons.set_stroke(WHITE, width = 0)
start_neurons.set_fill(WHITE, 0)

self.play(FadeIn(image), FadeIn(image_rect))


self.feed_forward(in_vect, added_anims = [
self.get_image_to_layer_one_animation(image, start_neurons)
])
n = np.argmax([
neuron.get_fill_opacity()
for neuron in self.network_mob.layers[-1].neurons
])
rect = SurroundingRectangle(VGroup(
self.network_mob.layers[-1].neurons[n],
self.network_mob.output_labels[n],
))
self.play(ShowCreation(rect))
self.reset_display(rect, image, image_rect)

def reset_display(self, answer_rect, image, image_rect):


self.play(FadeOut(answer_rect))
self.play(
FadeOut(image),
FadeOut(image_rect),
self.network_mob.deactivate_layers,
)

def get_image_to_layer_one_animation(self, image, start_neurons):


image_mover = VGroup(*[
pixel.copy()
for pixel in image
if pixel.fill_rgb[0] > 0.1
])
return Transform(
image_mover, start_neurons,
remover = True,
run_time = 1,
)

###

def add_network(self):
self.network_mob = MNistNetworkMobject(**self.network_mob_config)
self.network = self.network_mob.neural_network
self.add(self.network_mob)

class AlternateNeuralNetworks(PiCreatureScene):


def construct(self):
morty = self.pi_creature
examples = VGroup(
VGroup(
TexText("Convolutional neural network"),
TexText("Good for image recognition"),
),
VGroup(
TexText("Long short-term memory network"),
TexText("Good for speech recognition"),
)
)
for ex in examples:
arrow = Arrow(LEFT, RIGHT, color = BLUE)
ex[0].next_to(arrow, LEFT)
ex[1].next_to(arrow, RIGHT)
ex.submobjects.insert(1, arrow)
examples.set_width(FRAME_WIDTH - 1)
examples.next_to(morty, UP).to_edge(RIGHT)

maybe_words = TexText("Maybe future videos?")


maybe_words.scale(0.8)
maybe_words.next_to(morty, UP)
maybe_words.to_edge(RIGHT)
maybe_words.set_color(YELLOW)

self.play(


Write(examples[0], run_time = 2),
morty.change, "raise_right_hand"
)
self.wait()
self.play(
examples[0].shift, MED_LARGE_BUFF*UP,
FadeIn(examples[1], lag_ratio = 0.5),
)
self.wait()
self.play(
examples.shift, UP,
FadeIn(maybe_words),
morty.change, "maybe"
)
self.wait(2)

class PlainVanillaWrapper(Scene):


def construct(self):
title = TexText("Plain vanilla")
subtitle = TexText("(aka ``multilayer perceptron'')")
title.scale(1.5)
title.to_edge(UP)
subtitle.next_to(title, DOWN)

self.add(title)


self.wait(2)
self.play(Write(subtitle, run_time = 2))
self.wait(2)

class NotPerfectAddOn(Scene):


def construct(self):
words = TexText("Not perfect!")
words.scale(1.5)
arrow = Arrow(UP+RIGHT, DOWN+LEFT, color = RED)
words.set_color(RED)
arrow.to_corner(DOWN+LEFT)
words.next_to(arrow, UP+RIGHT)

self.play(


Write(words),
ShowCreation(arrow),
run_time = 1
)
self.wait(2)

class MoreAThanI(TeacherStudentsScene):


def construct(self):
self.teacher_says(
"More \\\\ A than I",
target_mode = "hesitant"
)
self.change_student_modes("sad", "erm", "tired")
self.wait(2)

class BreakDownName(Scene):


def construct(self):
self.ask_questions()
self.show_neuron()

def ask_questions(self):


name = TexText("Neural", "network")
name.to_edge(UP)
q1 = TexText(
"What are \\\\ the ", "neuron", "s?",
arg_separator = ""
)
q2 = TexText("How are \\\\ they connected?")
q1.next_to(name[0].get_bottom(), DOWN, buff = LARGE_BUFF)
q2.next_to(name[1].get_bottom(), DOWN+RIGHT, buff = LARGE_BUFF)
a1 = Arrow(q1.get_top(), name[0].get_bottom())
a2 = Arrow(q2.get_top(), name.get_corner(DOWN+RIGHT))
VGroup(q1, a1).set_color(BLUE)
VGroup(q2, a2).set_color(YELLOW)

randy = Randolph().to_corner(DOWN+LEFT)


brain = SVGMobject(file_name = "brain")
brain.set_fill(GREY_B, opacity = 0)
brain.replace(randy.eyes, dim_to_match = 1)

self.add(name)


self.play(randy.change, "pondering")
self.play(
brain.set_height, 2,
brain.shift, 2*UP,
brain.set_fill, None, 1,
randy.look, UP
)
brain_outline = brain.copy()
brain_outline.set_fill(opacity = 0)
brain_outline.set_stroke(BLUE_B, 3)
self.play(
ShowPassingFlash(
brain_outline,
time_width = 0.5,
run_time = 2
)
)
self.play(Blink(randy))
self.wait()
self.play(
Write(q1, run_time = 1),
ShowCreation(a1),
name[0].set_color, q1.get_color(),
)
self.play(
Write(q2, run_time = 1),
ShowCreation(a2),
name[1].set_color, q2.get_color()
)
self.wait(2)

self.play(*list(map(FadeOut, [


name, randy, brain,
q2, a1, a2,
q1[0], q1[2]
])))

self.neuron_word = q1[1]


def show_neuron(self):


neuron_word = TexText("Neuron")
arrow = Tex("\\rightarrow")
arrow.shift(LEFT)
description = TexText("Thing that holds a number")
neuron_word.set_color(BLUE)
neuron_word.next_to(arrow, LEFT)
neuron_word.shift(0.5*SMALL_BUFF*UP)
description.next_to(arrow, RIGHT)

neuron = Circle(radius = 0.35, color = BLUE)


neuron.next_to(neuron_word, UP, MED_LARGE_BUFF)
num = Tex("0.2")
num.set_width(0.7*neuron.get_width())
num.move_to(neuron)
num.save_state()
num.move_to(description.get_right())
num.set_fill(opacity = 1)

self.play(


ReplacementTransform(self.neuron_word, neuron_word),
ShowCreation(neuron)
)
self.play(
ShowCreation(arrow),
Write(description, run_time = 1)
)
self.wait()
self.play(
neuron.set_fill, None, 0.2,
num.restore
)
self.wait()
for value in 0.8, 0.4, 0.1, 0.5:
mob = Tex(str(value))
mob.replace(num)
self.play(
neuron.set_fill, None, value,
Transform(num, mob)
)
self.wait()

class IntroduceEachLayer(PreviewMNistNetwork):


CONFIG = {
"network_mob_config" : {
"neuron_stroke_color" : WHITE,
"neuron_stroke_width" : 2,
"neuron_fill_color" : WHITE,
"average_shown_activation_of_large_layer" : False,
"edge_propogation_color" : YELLOW,
"edge_propogation_time" : 2,
}
}
def construct(self):
self.setup_network_mob()
self.break_up_image_as_neurons()
self.show_activation_of_one_neuron()
self.transform_into_full_network()
self.show_output_layer()
self.show_hidden_layers()
self.show_propogation()

def setup_network_mob(self):


self.remove(self.network_mob)

def break_up_image_as_neurons(self):


self.image_map = get_organized_images()
image = self.image_map[9][0]
image_mob = PixelsFromVect(image)
image_mob.set_height(4)
image_mob.next_to(ORIGIN, LEFT)
rect = SurroundingRectangle(image_mob, color = BLUE)
neurons = VGroup()
for pixel in image_mob:
pixel.set_fill(WHITE, opacity = pixel.fill_rgb[0])
neuron = Circle(
color = WHITE,
stroke_width = 1,
radius = pixel.get_width()/2
)
neuron.move_to(pixel)
neuron.set_fill(WHITE, pixel.get_fill_opacity())
neurons.add(neuron)
neurons.scale(1.2)
neurons.space_out_submobjects(1.3)
neurons.to_edge(DOWN)

braces = VGroup(*[Brace(neurons, vect) for vect in (LEFT, UP)])


labels = VGroup(*[
brace.get_tex("28", buff = SMALL_BUFF)
for brace in braces
])

equation = Tex("28", "\\times", "28", "=", "784")


equation.next_to(neurons, RIGHT, LARGE_BUFF, UP)

self.corner_image = MNistMobject(image)


self.corner_image.to_corner(UP+LEFT)

self.add(image_mob, rect)


self.wait()
self.play(
ReplacementTransform(image_mob, neurons),
FadeOut(rect),
FadeIn(braces),
FadeIn(labels),
)
self.wait()
self.play(
ReplacementTransform(labels[0].copy(), equation[0]),
Write(equation[1]),
ReplacementTransform(labels[1].copy(), equation[2]),
Write(equation[3]),
Write(equation[4]),
)
self.wait()

self.neurons = neurons


self.braces = braces
self.brace_labels = labels
self.num_pixels_equation = equation
self.image_vect = image

def show_activation_of_one_neuron(self):


neurons = self.neurons
numbers = VGroup()
example_neuron = None
example_num = None
for neuron in neurons:
o = neuron.get_fill_opacity()
num = DecimalNumber(o, num_decimal_places = 1)
num.set_width(0.7*neuron.get_width())
num.move_to(neuron)
if o > 0.8:
num.set_fill(BLACK)
numbers.add(num)
if o > 0.25 and o < 0.75 and example_neuron is None:
example_neuron = neuron
example_num = num
example_neuron.save_state()
example_num.save_state()
example_neuron.generate_target()
example_neuron.target.set_height(1.5)
example_neuron.target.next_to(neurons, RIGHT)
example_num.target = DecimalNumber(
example_neuron.get_fill_opacity()
)
example_num.target.move_to(example_neuron.target)

def change_activation(num):


self.play(
example_neuron.set_fill, None, num,
ChangingDecimal(
example_num,
lambda a : example_neuron.get_fill_opacity(),
),
UpdateFromFunc(
example_num,
lambda m : m.set_fill(
BLACK if example_neuron.get_fill_opacity() > 0.8 else WHITE
)
)
)

self.play(LaggedStartMap(FadeIn, numbers))


self.play(
MoveToTarget(example_neuron),
MoveToTarget(example_num)
)
self.wait()
curr_opacity = example_neuron.get_fill_opacity()
for num in 0.3, 0.01, 1.0, curr_opacity:
change_activation(num)
self.wait()

rect = SurroundingRectangle(example_num, color = YELLOW)


activation = TexText("``Activation''")
activation.next_to(example_neuron, RIGHT)
activation.set_color(rect.get_color())
self.play(ShowCreation(rect))
self.play(Write(activation, run_time = 1))
self.wait()
change_activation(1.0)
self.wait()
change_activation(0.2)
self.wait()

self.play(


example_neuron.restore,
example_num.restore,
FadeOut(activation),
FadeOut(rect),
)
self.play(FadeOut(numbers))

def transform_into_full_network(self):


network_mob = self.network_mob
neurons = self.neurons
layer = network_mob.layers[0]
layer.save_state()
layer.rotate(np.pi/2)
layer.center()
layer.brace_label.rotate(-np.pi/2)
n = network_mob.max_shown_neurons/2

rows = VGroup(*[


VGroup(*neurons[28*i:28*(i+1)])
for i in range(28)
])

self.play(


FadeOut(self.braces),
FadeOut(self.brace_labels),
FadeOut(VGroup(*self.num_pixels_equation[:-1]))
)

self.play(rows.space_out_submobjects, 1.2)


self.play(
rows.arrange, RIGHT, buff = SMALL_BUFF,
path_arc = np.pi/2,
run_time = 2
)
self.play(
ReplacementTransform(
VGroup(*neurons[:n]),
VGroup(*layer.neurons[:n]),
),
ReplacementTransform(
VGroup(*neurons[n:-n]),
layer.dots,
),
ReplacementTransform(
VGroup(*neurons[-n:]),
VGroup(*layer.neurons[-n:]),
),
)
self.play(
ReplacementTransform(
self.num_pixels_equation[-1],
layer.brace_label
),
FadeIn(layer.brace),
)
self.play(layer.restore, FadeIn(self.corner_image))
self.wait()
for edge_group, layer in zip(network_mob.edge_groups, network_mob.layers[1:]):
self.play(
LaggedStartMap(FadeIn, layer, run_time = 1),
ShowCreation(edge_group),
)
self.wait()

def show_output_layer(self):


layer = self.network_mob.layers[-1]
labels = self.network_mob.output_labels
rect = SurroundingRectangle(
VGroup(layer, labels)
)
neuron = layer.neurons[-1]
neuron.set_fill(WHITE, 0)
label = labels[-1]
for mob in neuron, label:
mob.save_state()
mob.generate_target()
neuron.target.scale(4)
neuron.target.shift(1.5*RIGHT)
label.target.scale(1.5)
label.target.next_to(neuron.target, RIGHT)

activation = DecimalNumber(0)


activation.move_to(neuron.target)

def change_activation(num):


self.play(
neuron.set_fill, None, num,
ChangingDecimal(
activation,
lambda a : neuron.get_fill_opacity(),
),
UpdateFromFunc(
activation,
lambda m : m.set_fill(
BLACK if neuron.get_fill_opacity() > 0.8 else WHITE
)
)
)

self.play(ShowCreation(rect))


self.play(LaggedStartMap(FadeIn, labels))
self.wait()
self.play(
MoveToTarget(neuron),
MoveToTarget(label),
)
self.play(FadeIn(activation))
for num in 0.5, 0.38, 0.97:
change_activation(num)
self.wait()
self.play(
neuron.restore,
neuron.set_fill, None, 1,
label.restore,
FadeOut(activation),
FadeOut(rect),
)
self.wait()

def show_hidden_layers(self):


hidden_layers = VGroup(*self.network_mob.layers[1:3])
rect = SurroundingRectangle(hidden_layers, color = YELLOW)
name = TexText("``Hidden layers''")
name.next_to(rect, UP, SMALL_BUFF)
name.set_color(YELLOW)
q_marks = VGroup()
for layer in hidden_layers:
for neuron in layer.neurons:
q_mark = TexText("?")
q_mark.set_height(0.8*neuron.get_height())
q_mark.move_to(neuron)
q_marks.add(q_mark)
q_marks.set_color_by_gradient(BLUE, YELLOW)
q_mark = TexText("?").scale(4)
q_mark.move_to(hidden_layers)
q_mark.set_color(YELLOW)
q_marks.add(q_mark)

self.play(


ShowCreation(rect),
Write(name)
)
self.wait()
self.play(Write(q_marks))
self.wait()
self.play(
FadeOut(q_marks),
Animation(q_marks[-1].copy())
)

def show_propogation(self):


self.revert_to_original_skipping_status()
self.remove_random_edges(0.7)
self.feed_forward(self.image_vect)

class DiscussChoiceForHiddenLayers(TeacherStudentsScene):


def construct(self):
network_mob = MNistNetworkMobject(
layer_to_layer_buff = 2.5,
neuron_stroke_color = WHITE,
)
network_mob.set_height(4)
network_mob.to_edge(UP, buff = LARGE_BUFF)
layers = VGroup(*network_mob.layers[1:3])
rects = VGroup(*list(map(SurroundingRectangle, layers)))
self.add(network_mob)

two_words = TexText("2 hidden layers")


two_words.set_color(YELLOW)
sixteen_words = TexText("16 neurons each")
sixteen_words.set_color(MAROON_B)
for words in two_words, sixteen_words:
words.next_to(rects, UP)

neurons_anim = LaggedStartMap(


Indicate,
VGroup(*it.chain(*[layer.neurons for layer in layers])),
rate_func = there_and_back,
scale_factor = 2,
color = MAROON_B,
)

self.play(


ShowCreation(rects),
Write(two_words, run_time = 1),
self.teacher.change, "raise_right_hand",
)
self.wait()
self.play(
FadeOut(rects),
ReplacementTransform(two_words, sixteen_words),
neurons_anim
)
self.wait()
self.play(self.teacher.change, "shruggie")
self.change_student_modes("erm", "confused", "sassy")
self.wait()
self.student_says(
"Why 2 \\\\ layers?",
student_index = 1,
bubble_kwargs = {"direction" : RIGHT},
run_time = 1,
target_mode = "raise_left_hand",
)
self.play(self.teacher.change, "happy")
self.wait()
self.student_says(
"Why 16?",
student_index = 0,
run_time = 1,
)
self.play(neurons_anim, run_time = 3)
self.play(
self.teacher.change, "shruggie",
RemovePiCreatureBubble(self.students[0]),
)
self.wait()

class MoreHonestMNistNetworkPreview(IntroduceEachLayer):


CONFIG = {
"network_mob_config" : {
"edge_propogation_time" : 1.5,
}
}
def construct(self):
PreviewMNistNetwork.construct(self)

def get_image_to_layer_one_animation(self, image, start_neurons):


neurons = VGroup()
for pixel in image:
neuron = Circle(
radius = pixel.get_width()/2,
stroke_width = 1,
stroke_color = WHITE,
fill_color = WHITE,
fill_opacity = pixel.fill_rgb[0]
)
neuron.move_to(pixel)
neurons.add(neuron)
neurons.scale(1.2)
neurons.next_to(image, DOWN)
n = len(start_neurons)
point = VectorizedPoint(start_neurons.get_center())
target = VGroup(*it.chain(
start_neurons[:n/2],
[point.copy() for x in range(len(neurons)-n)],
start_neurons[n/2:],
))
mover = image.copy()
self.play(Transform(mover, neurons))
return Transform(
mover, target,
run_time = 2,
lag_ratio = 0.5,
remover = True
)

class AskAboutPropogationAndTraining(TeacherStudentsScene):


def construct(self):
self.student_says(
"How does one layer \\\\ influence the next?",
student_index = 0,
run_time = 1
)
self.wait()
self.student_says(
"How does \\\\ training work?",
student_index = 2,
run_time = 1
)
self.wait(3)

class AskAboutLayers(PreviewMNistNetwork):


def construct(self):
self.play(
self.network_mob.scale, 0.8,
self.network_mob.to_edge, DOWN,
)

question = TexText("Why the", "layers?")


question.to_edge(UP)
neuron_groups = [
layer.neurons
for layer in self.network_mob.layers
]
arrows = VGroup(*[
Arrow(
question[1].get_bottom(),
group.get_top()
)
for group in neuron_groups
])
rects = list(map(SurroundingRectangle, neuron_groups[1:3]))

self.play(


Write(question, run_time = 1),
LaggedStartMap(
GrowFromPoint, arrows,
lambda a : (a, a.get_start()),
run_time = 2
)
)
self.wait()
self.play(*list(map(ShowCreation, rects)))
self.wait()

class BreakUpMacroPatterns(IntroduceEachLayer):


CONFIG = {
"camera_config" : {"background_opacity" : 1},
"prefixes" : [
"nine", "eight", "four",
"upper_loop", "right_line",
"lower_loop", "horizontal_line",
"upper_left_line"
]
}
def construct(self):
self.setup_network_mob()
self.setup_needed_patterns()
self.setup_added_patterns()
self.show_nine()
self.show_eight()
self.show_four()
self.show_second_to_last_layer()
self.show_upper_loop_activation()
self.show_what_learning_is_required()

def setup_needed_patterns(self):


prefixes = self.prefixes
vects = [
np.array(Image.open(
get_full_raster_image_path("handwritten_" + p),
))[:,:,0].flatten()/255.0
for p in prefixes
]
mobjects = list(map(MNistMobject, vects))
for mob in mobjects:
image = mob[1]
self.make_transparent(image)
for prefix, mob in zip(prefixes, mobjects):
setattr(self, prefix, mob)

def setup_added_patterns(self):


image_map = get_organized_images()
two, three, five = mobs = [
MNistMobject(image_map[n][0])
for n in (2, 3, 5)
]
self.added_patterns = VGroup()
for mob in mobs:
for i, j in it.product([0, 14], [0, 14]):
pattern = mob.deepcopy()
pa = pattern[1].pixel_array
temp = np.array(pa[i:i+14,j:j+14,:], dtype = 'uint8')
pa[:,:] = 0
pa[i:i+14,j:j+14,:] = temp
self.make_transparent(pattern[1])
pattern[1].set_color(random_bright_color())
self.added_patterns.add(pattern)
self.image_map = image_map

def show_nine(self):


nine = self.nine
upper_loop = self.upper_loop
right_line = self.right_line
equation = self.get_equation(nine, upper_loop, right_line)
equation.to_edge(UP)
equation.shift(LEFT)

parts = [upper_loop[1], right_line[1]]


for mob, color in zip(parts, [YELLOW, RED]):
mob.set_color(color)
mob.save_state()
mob.move_to(nine)
right_line[1].pixel_array[:14,:,3] = 0

self.play(FadeIn(nine))


self.wait()
self.play(*list(map(FadeIn, parts)))
self.wait()
self.play(
Write(equation[1]),
upper_loop[1].restore,
FadeIn(upper_loop[0])
)
self.wait()
self.play(
Write(equation[3]),
right_line[1].restore,
FadeIn(right_line[0]),
)
self.wait()

self.nine_equation = equation


def show_eight(self):


eight = self.eight
upper_loop = self.upper_loop.deepcopy()
lower_loop = self.lower_loop
lower_loop[1].set_color(GREEN)

equation = self.get_equation(eight, upper_loop, lower_loop)


equation.next_to(self.nine_equation, DOWN)

lower_loop[1].save_state()


lower_loop[1].move_to(eight[1])

self.play(


FadeIn(eight),
Write(equation[1]),
)
self.play(ReplacementTransform(
self.upper_loop.copy(),
upper_loop
))
self.wait()
self.play(FadeIn(lower_loop[1]))
self.play(
Write(equation[3]),
lower_loop[1].restore,
FadeIn(lower_loop[0]),
)
self.wait()

self.eight_equation = equation


def show_four(self):


four = self.four
upper_left_line = self.upper_left_line
upper_left_line[1].set_color(BLUE)
horizontal_line = self.horizontal_line
horizontal_line[1].set_color(MAROON_B)
right_line = self.right_line.deepcopy()
equation = self.get_equation(four, right_line, upper_left_line, horizontal_line)
equation.next_to(
self.eight_equation, DOWN, aligned_edge = LEFT
)

self.play(


FadeIn(four),
Write(equation[1])
)
self.play(ReplacementTransform(
self.right_line.copy(), right_line
))
self.play(LaggedStartMap(
FadeIn, VGroup(*equation[3:])
))
self.wait(2)

self.four_equation = equation


def show_second_to_last_layer(self):


everything = VGroup(*it.chain(
self.nine_equation,
self.eight_equation,
self.four_equation,
))
patterns = VGroup(
self.upper_loop,
self.lower_loop,
self.right_line,
self.upper_left_line,
self.horizontal_line,
*self.added_patterns[:11]
)
for pattern in patterns:
pattern.add_to_back(
pattern[1].copy().set_color(BLACK, alpha = 1)
)
everything.remove(*patterns)
network_mob = self.network_mob
layer = network_mob.layers[-2]
patterns.generate_target()
for pattern, neuron in zip(patterns.target, layer.neurons):
pattern.set_height(neuron.get_height())
pattern.next_to(neuron, RIGHT, SMALL_BUFF)
for pattern in patterns[5:]:
pattern.fade(1)

self.play(*list(map(FadeOut, everything)))


self.play(
FadeIn(
network_mob,
lag_ratio = 0.5,
run_time = 3,
),
MoveToTarget(patterns)
)
self.wait(2)

self.patterns = patterns


def show_upper_loop_activation(self):


neuron = self.network_mob.layers[-2].neurons[0]
words = TexText("Upper loop neuron...maybe...")
words.scale(0.8)
words.next_to(neuron, UP)
words.shift(RIGHT)
rect = SurroundingRectangle(VGroup(
neuron, self.patterns[0]
))
nine = self.nine
upper_loop = self.upper_loop.copy()
upper_loop.remove(upper_loop[0])
upper_loop.replace(nine)
nine.add(upper_loop)
nine.to_corner(UP+LEFT)
self.remove_random_edges(0.7)
self.network.get_activation_of_all_layers = lambda v : [
np.zeros(784),
sigmoid(6*(np.random.random(16)-0.5)),
np.array([1, 0, 1] + 13*[0]),
np.array(9*[0] + [1])
]

self.play(FadeIn(nine))


self.play(
ShowCreation(rect),
Write(words)
)
self.add_foreground_mobject(self.patterns)
self.feed_forward(np.random.random(784))
self.wait(2)

def show_what_learning_is_required(self):


edge_group = self.network_mob.edge_groups[-1].copy()
edge_group.set_stroke(YELLOW, 4)
for x in range(3):
self.play(LaggedStartMap(
ShowCreationThenDestruction, edge_group,
run_time = 3
))
self.wait()

######

def get_equation(self, *mobs):
equation = VGroup(
mobs[0], Tex("=").scale(2),
*list(it.chain(*[
[m, Tex("+").scale(2)]
for m in mobs[1:-1]
])) + [mobs[-1]]
)
equation.arrange(RIGHT)
return equation

def make_transparent(self, image_mob):


return make_transparent(image_mob)
alpha_vect = np.array(
image_mob.pixel_array[:,:,0],
dtype = 'uint8'
)
image_mob.set_color(WHITE)
image_mob.pixel_array[:,:,3] = alpha_vect
return image_mob

class GenerallyLoopyPattern(Scene):


def construct(self):
image_map = get_organized_images()
images = list(map(MNistMobject, it.chain(
image_map[8], image_map[9],
)))
random.shuffle(images)

for image in images:


image.to_corner(DOWN+RIGHT)
self.add(image)
self.wait(0.2)
self.remove(image)

class HowWouldYouRecognizeSubcomponent(TeacherStudentsScene):


def construct(self):
self.student_says(
"Okay, but recognizing loops \\\\",
"is just as hard!",
target_mode = "sassy"
)
self.play(
self.teacher.change, "guilty"
)
self.wait()

class BreakUpMicroPatterns(BreakUpMacroPatterns):


CONFIG = {
"prefixes" : [
"loop",
"loop_edge1",
"loop_edge2",
"loop_edge3",
"loop_edge4",
"loop_edge5",
"right_line",
"right_line_edge1",
"right_line_edge2",
"right_line_edge3",
]
}
def construct(self):
self.setup_network_mob()
self.setup_needed_patterns()

self.break_down_loop()


self.break_down_long_line()

def break_down_loop(self):


loop = self.loop
loop[0].set_color(WHITE)
edges = Group(*[
getattr(self, "loop_edge%d"%d)
for d in range(1, 6)
])
colors = color_gradient([BLUE, YELLOW, RED], 5)
for edge, color in zip(edges, colors):
for mob in edge:
mob.set_color(color)
loop.generate_target()
edges.generate_target()
for edge in edges:
edge[0].set_stroke(width = 0)
edge.save_state()
edge[1].set_opacity(0)
equation = self.get_equation(loop.target, *edges.target)
equation.set_width(FRAME_WIDTH - 1)
equation.to_edge(UP)
symbols = VGroup(*equation[1::2])

randy = Randolph()


randy.to_corner(DOWN+LEFT)

self.add(randy)


self.play(
FadeIn(loop),
randy.change, "pondering", loop
)
self.play(Blink(randy))
self.wait()
self.play(LaggedStartMap(
ApplyMethod, edges,
lambda e : (e.restore,),
run_time = 4
))
self.wait()
self.play(
MoveToTarget(loop, run_time = 2),
MoveToTarget(edges, run_time = 2),
Write(symbols),
randy.change, "happy", equation,
)
self.wait()

self.loop_equation = equation


self.randy = randy

def break_down_long_line(self):


randy = self.randy
line = self.right_line
line[0].set_color(WHITE)
edges = Group(*[
getattr(self, "right_line_edge%d"%d)
for d in range(1, 4)
])
colors = Color(MAROON_B).range_to(PURPLE, 3)
for edge, color in zip(edges, colors):
for mob in edge:
mob.set_color(color)
equation = self.get_equation(line, *edges)
equation.set_height(self.loop_equation.get_height())
equation.next_to(
self.loop_equation, DOWN, MED_LARGE_BUFF, LEFT
)
image_map = get_organized_images()
digits = VGroup(*[
MNistMobject(image_map[n][1])
for n in (1, 4, 7)
])
digits.arrange(RIGHT)
digits.next_to(randy, RIGHT)

self.revert_to_original_skipping_status()


self.play(
FadeIn(line),
randy.change, "hesitant", line
)
self.play(Blink(randy))
self.play(LaggedStartMap(FadeIn, digits))
self.wait()
self.play(
LaggedStartMap(FadeIn, Group(*equation[1:])),
randy.change, "pondering", equation
)
self.wait(3)

class SecondLayerIsLittleEdgeLayer(IntroduceEachLayer):


CONFIG = {
"camera_config" : {
"background_opacity" : 1,
},
"network_mob_config" : {
"layer_to_layer_buff" : 2,
"edge_propogation_color" : YELLOW,
}
}
def construct(self):
self.setup_network_mob()
self.setup_activations_and_nines()

self.describe_second_layer()


self.show_propogation()
self.ask_question()

def setup_network_mob(self):


self.network_mob.scale(0.7)
self.network_mob.to_edge(DOWN)
self.remove_random_edges(0.7)

def setup_activations_and_nines(self):


layers = self.network_mob.layers
nine_im, loop_im, line_im = images = [
Image.open(get_full_raster_image_path("handwritten_%s"%s))
for s in ("nine", "upper_loop", "right_line")
]
nine_array, loop_array, line_array = [
np.array(im)[:,:,0]/255.0
for im in images
]
self.nine = MNistMobject(nine_array.flatten())
self.nine.set_height(1.5)
self.nine[0].set_color(WHITE)
make_transparent(self.nine[1])
self.nine.next_to(layers[0].neurons, UP)

self.activations = self.network.get_activation_of_all_layers(


nine_array.flatten()
)
self.activations[-2] = np.array([1, 0, 1] + 13*[0])
self.edge_colored_nine = Group()
nine_pa = self.nine[1].pixel_array
n, k = 6, 4
colors = color_gradient([BLUE, YELLOW, RED, MAROON_B, GREEN], 10)
for i, j in it.product(list(range(n)), list(range(k))):
mob = ImageMobject(np.zeros((28, 28, 4), dtype = 'uint8'))
mob.replace(self.nine[1])
pa = mob.pixel_array
color = colors[(k*i + j)%(len(colors))]
rgb = (255*color_to_rgb(color)).astype('uint8')
pa[:,:,:3] = rgb
i0, i1 = 1+(28/n)*i, 1+(28/n)*(i+1)
j0, j1 = (28/k)*j, (28/k)*(j+1)
pa[i0:i1,j0:j1,3] = nine_pa[i0:i1,j0:j1,3]
self.edge_colored_nine.add(mob)
self.edge_colored_nine.next_to(layers[1], UP)

loop, line = [


ImageMobject(layer_to_image_array(array.flatten()))
for array in (loop_array, line_array)
]
for mob, color in (loop, YELLOW), (line, RED):
make_transparent(mob)
mob.set_color(color)
mob.replace(self.nine[1])
line.pixel_array[:14,:,:] = 0

self.pattern_colored_nine = Group(loop, line)


self.pattern_colored_nine.next_to(layers[2], UP)

for mob in self.edge_colored_nine, self.pattern_colored_nine:


mob.align_to(self.nine[1], UP)

def describe_second_layer(self):


layer = self.network_mob.layers[1]
rect = SurroundingRectangle(layer)
words = TexText("``Little edge'' layer?")
words.next_to(rect, UP, MED_LARGE_BUFF)
words.set_color(YELLOW)

self.play(


ShowCreation(rect),
Write(words, run_time = 2)
)
self.wait()
self.play(*list(map(FadeOut, [rect, words])))

def show_propogation(self):


nine = self.nine
edge_colored_nine = self.edge_colored_nine
pattern_colored_nine = self.pattern_colored_nine
activations = self.activations
network_mob = self.network_mob
layers = network_mob.layers
edge_groups = network_mob.edge_groups.copy()
edge_groups.set_stroke(YELLOW, 4)

v_nine = PixelsAsSquares(nine[1])


neurons = VGroup()
for pixel in v_nine:
neuron = Circle(
radius = pixel.get_width()/2,
stroke_color = WHITE,
stroke_width = 1,
fill_color = WHITE,
fill_opacity = pixel.get_fill_opacity(),
)
neuron.rotate(3*np.pi/4)
neuron.move_to(pixel)
neurons.add(neuron)
neurons.set_height(2)
neurons.space_out_submobjects(1.2)
neurons.next_to(network_mob, LEFT)
self.set_neurons_target(neurons, layers[0])

pattern_colored_nine.save_state()


pattern_colored_nine.move_to(edge_colored_nine)
edge_colored_nine.save_state()
edge_colored_nine.move_to(nine[1])
for mob in edge_colored_nine, pattern_colored_nine:
for submob in mob:
submob.set_opacity(0)

active_layers = [


network_mob.get_active_layer(i, a)
for i, a in enumerate(activations)
]

def activate_layer(i):


self.play(
ShowCreationThenDestruction(
edge_groups[i-1],
run_time = 2,
lag_ratio = 0.5
),
FadeIn(active_layers[i])
)
self.play(FadeIn(nine))
self.play(ReplacementTransform(v_nine, neurons))
self.play(MoveToTarget(
neurons,
remover = True,
lag_ratio = 0.5,
run_time = 2
))

activate_layer(1)


self.play(edge_colored_nine.restore)
self.separate_parts(edge_colored_nine)
self.wait()

activate_layer(2)


self.play(pattern_colored_nine.restore)
self.separate_parts(pattern_colored_nine)

activate_layer(3)


self.wait(2)

def ask_question(self):


question = TexText(
"Does the network \\\\ actually do this?"
)
question.to_edge(LEFT)
later = TexText("We'll get back \\\\ to this")
later.to_corner(UP+LEFT)
later.set_color(BLUE)
arrow = Arrow(later.get_bottom(), question.get_top())
arrow.set_color(BLUE)

self.play(Write(question, run_time = 2))


self.wait()
self.play(
FadeIn(later),
GrowFromPoint(arrow, arrow.get_start())
)
self.wait()

###

def set_neurons_target(self, neurons, layer):
neurons.generate_target()
n = len(layer.neurons)/2
Transform(
VGroup(*neurons.target[:n]),
VGroup(*layer.neurons[:n]),
).update(1)
Transform(
VGroup(*neurons.target[-n:]),
VGroup(*layer.neurons[-n:]),
).update(1)
Transform(
VGroup(*neurons.target[n:-n]),
VectorizedPoint(layer.get_center())
).update(1)

def separate_parts(self, image_group):


vects = compass_directions(len(image_group), UP)
image_group.generate_target()
for im, vect in zip(image_group.target, vects):
im.shift(MED_SMALL_BUFF*vect)
self.play(MoveToTarget(
image_group,
rate_func = there_and_back,
lag_ratio = 0.5,
run_time = 2,
))

class EdgeDetection(Scene):


CONFIG = {
"camera_config" : {"background_opacity" : 1}
}
def construct(self):
lion = ImageMobject("Lion")
edges_array = get_edges(lion.pixel_array)
edges = ImageMobject(edges_array)
group = Group(lion, edges)
group.set_height(4)
group.arrange(RIGHT)
lion_copy = lion.copy()

self.play(FadeIn(lion))


self.play(lion_copy.move_to, edges)
self.play(Transform(lion_copy, edges, run_time = 3))
self.wait(2)

class ManyTasksBreakDownLikeThis(TeacherStudentsScene):


def construct(self):
audio = self.get_wave_form()
audio_label = TexText("Raw audio")
letters = TexText(" ".join("recognition"))
syllables = TexText("$\\cdot$".join([
"re", "cog", "ni", "tion"
]))
word = TexText(
"re", "cognition",
arg_separator = ""
)
word[1].set_color(BLUE)
arrows = VGroup()
def get_arrow():
arrow = Arrow(ORIGIN, RIGHT, color = BLUE)
arrows.add(arrow)
return arrow
sequence = VGroup(
audio, get_arrow(),
letters, get_arrow(),
syllables, get_arrow(),
word
)
sequence.arrange(RIGHT)
sequence.set_width(FRAME_WIDTH - 1)
sequence.to_edge(UP)

audio_label.next_to(audio, DOWN)


VGroup(audio, audio_label).set_color(YELLOW)
audio.save_state()

self.teacher_says(


"Many", "recognition", "tasks\\\\",
"break down like this"
)
self.change_student_modes(*["pondering"]*3)
self.wait()
content = self.teacher.bubble.content
pre_word = content[1]
content.remove(pre_word)
audio.move_to(pre_word)
self.play(
self.teacher.bubble.content.fade, 1,
ShowCreation(audio),
pre_word.shift, MED_SMALL_BUFF, DOWN
)
self.wait(2)
self.play(
RemovePiCreatureBubble(self.teacher),
audio.restore,
FadeIn(audio_label),
*[
ReplacementTransform(
m1, m2
)
for m1, m2 in zip(pre_word, letters)
]
)
self.play(
GrowFromPoint(arrows[0], arrows[0].get_start()),
)
self.wait()
self.play(
GrowFromPoint(arrows[1], arrows[1].get_start()),
LaggedStartMap(FadeIn, syllables, run_time = 1)
)
self.wait()
self.play(
GrowFromPoint(arrows[2], arrows[2].get_start()),
LaggedStartMap(FadeIn, word, run_time = 1)
)
self.wait()

def get_wave_form(self):


func = lambda x : abs(sum([
(1./n)*np.sin((n+3)*x)
for n in range(1, 5)
]))
result = VGroup(*[
Line(func(x)*DOWN, func(x)*UP)
for x in np.arange(0, 4, 0.1)
])
result.set_stroke(width = 2)
result.arrange(RIGHT, buff = MED_SMALL_BUFF)
result.set_height(1)

return result


class AskAboutWhatEdgesAreDoing(IntroduceEachLayer):


CONFIG = {
"network_mob_config" : {
"layer_to_layer_buff" : 2,
}
}
def construct(self):
self.add_question()
self.show_propogation()

def add_question(self):


self.network_mob.scale(0.8)
self.network_mob.to_edge(DOWN)
edge_groups = self.network_mob.edge_groups
self.remove_random_edges(0.7)

question = TexText(


"What are these connections actually doing?"
)
question.to_edge(UP)
question.shift(RIGHT)
arrows = VGroup(*[
Arrow(
question.get_bottom(),
edge_group.get_top()
)
for edge_group in edge_groups
])

self.add(question, arrows)


def show_propogation(self):


in_vect = get_organized_images()[6][3]
image = MNistMobject(in_vect)
image.next_to(self.network_mob, LEFT, MED_SMALL_BUFF, UP)

self.add(image)


self.feed_forward(in_vect)
self.wait()

class IntroduceWeights(IntroduceEachLayer):


CONFIG = {
"weights_color" : GREEN,
"negative_weights_color" : RED,
}
def construct(self):
self.zoom_in_on_one_neuron()
self.show_desired_pixel_region()
self.ask_about_parameters()
self.show_weights()
self.show_weighted_sum()
self.organize_weights_as_grid()
self.make_most_weights_0()
self.add_negative_weights_around_the_edge()

def zoom_in_on_one_neuron(self):


self.network_mob.to_edge(LEFT)
layers = self.network_mob.layers
edge_groups = self.network_mob.edge_groups

neuron = layers[1].neurons[7].deepcopy()


self.play(


FadeOut(edge_groups),
FadeOut(VGroup(*layers[1:])),
FadeOut(self.network_mob.output_labels),
Animation(neuron),
neuron.edges_in.set_stroke, None, 2,
lag_ratio = 0.5,
run_time = 2
)

self.neuron = neuron


def show_desired_pixel_region(self):


neuron = self.neuron
d = 28

pixels = PixelsAsSquares(ImageMobject(


np.zeros((d, d, 4))
))
pixels.set_stroke(width = 0.5)
pixels.set_fill(WHITE, 0)
pixels.set_height(4)
pixels.next_to(neuron, RIGHT, LARGE_BUFF)
rect = SurroundingRectangle(pixels, color = BLUE)

pixels_to_detect = self.get_pixels_to_detect(pixels)


self.play(


FadeIn(rect),
ShowCreation(
pixels,
lag_ratio = 0.5,
run_time = 2,
)
)
self.play(
pixels_to_detect.set_fill, WHITE, 1,
lag_ratio = 0.5,
run_time = 2
)
self.wait(2)

self.pixels = pixels


self.pixels_to_detect = pixels_to_detect
self.pixels_group = VGroup(rect, pixels)

def ask_about_parameters(self):


pixels = self.pixels
pixels_group = self.pixels_group
neuron = self.neuron

question = TexText("What", "parameters", "should exist?")


parameter_word = question.get_part_by_tex("parameters")
parameter_word.set_color(self.weights_color)
question.move_to(neuron.edges_in.get_top(), LEFT)
arrow = Arrow(
parameter_word.get_bottom(),
neuron.edges_in[0].get_center(),
color = self.weights_color
)

p_labels = VGroup(*[


Tex("p_%d\\!:"%(i+1)).set_color(self.weights_color)
for i in range(8)
] + [Tex("\\vdots")])
p_labels.arrange(DOWN, aligned_edge = LEFT)
p_labels.next_to(parameter_word, DOWN, LARGE_BUFF)
p_labels[-1].shift(SMALL_BUFF*RIGHT)

def get_alpha_func(i, start = 0):


# m = int(5*np.sin(2*np.pi*i/128.))
m = random.randint(1, 10)
return lambda a : start + (1-2*start)*np.sin(np.pi*a*m)**2

decimals = VGroup()


changing_decimals = []
for i, p_label in enumerate(p_labels[:-1]):
decimal = DecimalNumber(0)
decimal.next_to(p_label, RIGHT, MED_SMALL_BUFF)
decimals.add(decimal)
changing_decimals.append(ChangingDecimal(
decimal, get_alpha_func(i + 5)
))
for i, pixel in enumerate(pixels):
pixel.func = get_alpha_func(i, pixel.get_fill_opacity())
pixel_updates = [
UpdateFromAlphaFunc(
pixel,
lambda p, a : p.set_fill(opacity = p.func(a))
)
for pixel in pixels
]

self.play(


Write(question, run_time = 2),
GrowFromPoint(arrow, arrow.get_start()),
pixels_group.set_height, 3,
pixels_group.to_edge, RIGHT,
LaggedStartMap(FadeIn, p_labels),
LaggedStartMap(FadeIn, decimals),
)
self.wait()
self.play(
*changing_decimals + pixel_updates,
run_time = 5,
rate_func=linear
)

self.question = question


self.weight_arrow = arrow
self.p_labels = p_labels
self.decimals = decimals

def show_weights(self):


p_labels = self.p_labels
decimals = self.decimals
arrow = self.weight_arrow
question = self.question
neuron = self.neuron
edges = neuron.edges_in

parameter_word = question.get_part_by_tex("parameters")


question.remove(parameter_word)
weights_word = TexText("Weights", "")[0]
weights_word.set_color(self.weights_color)
weights_word.move_to(parameter_word)

w_labels = VGroup()


for p_label in p_labels:
w_label = Tex(
p_label.get_tex().replace("p", "w")
)
w_label.set_color(self.weights_color)
w_label.move_to(p_label)
w_labels.add(w_label)

edges.generate_target()


random_numbers = 1.5*np.random.random(len(edges))-0.5
self.make_edges_weighted(edges.target, random_numbers)
def get_alpha_func(r):
return lambda a : (4*r)*a

self.play(


FadeOut(question),
ReplacementTransform(parameter_word, weights_word),
ReplacementTransform(p_labels, w_labels)
)
self.play(
MoveToTarget(edges),
*[
ChangingDecimal(
decimal,
get_alpha_func(r)
)
for decimal, r in zip(decimals, random_numbers)
]
)
self.play(LaggedStartMap(
ApplyMethod, edges,
lambda m : (m.rotate, np.pi/24),
rate_func = wiggle,
run_time = 2
))
self.wait()

self.w_labels = w_labels


self.weights_word = weights_word
self.random_numbers = random_numbers

def show_weighted_sum(self):


weights_word = self.weights_word
weight_arrow = self.weight_arrow
w_labels = VGroup(*[
VGroup(*label[:-1]).copy()
for label in self.w_labels
])
layer = self.network_mob.layers[0]

a_vect = np.random.random(16)


active_layer = self.network_mob.get_active_layer(0, a_vect)

a_labels = VGroup(*[


Tex("a_%d"%d)
for d in range(1, 5)
])

weighted_sum = VGroup(*it.chain(*[


[w, a, Tex("+")]
for w, a in zip(w_labels, a_labels)
]))
weighted_sum.add(
Tex("\\cdots"),
Tex("+"),
Tex("w_n").set_color(self.weights_color),
Tex("a_n")
)
weighted_sum.arrange(RIGHT, buff = SMALL_BUFF)
weighted_sum.to_edge(UP)

self.play(Transform(layer, active_layer))


self.play(
FadeOut(weights_word),
FadeOut(weight_arrow),
*[
ReplacementTransform(n.copy(), a)
for n, a in zip(layer.neurons, a_labels)
] + [
ReplacementTransform(n.copy(), weighted_sum[-4])
for n in layer.neurons[4:-1]
] + [
ReplacementTransform(
layer.neurons[-1].copy(),
weighted_sum[-1]
)
] + [
Write(weighted_sum[i])
for i in list(range(2, 12, 3)) + [-4, -3]
],
run_time = 1.5
)
self.wait()
self.play(*[
ReplacementTransform(w1.copy(), w2)
for w1, w2 in zip(self.w_labels, w_labels)[:4]
]+[
ReplacementTransform(w.copy(), weighted_sum[-4])
for w in self.w_labels[4:-1]
]+[
ReplacementTransform(
self.w_labels[-1].copy(), weighted_sum[-2]
)
], run_time = 2)
self.wait(2)

self.weighted_sum = weighted_sum


def organize_weights_as_grid(self):


pixels = self.pixels
w_labels = self.w_labels
decimals = self.decimals

weights = 2*np.sqrt(np.random.random(784))-1


weights[:8] = self.random_numbers[:8]
weights[-8:] = self.random_numbers[-8:]

weight_grid = PixelsFromVect(np.abs(weights))


weight_grid.replace(pixels)
weight_grid.next_to(pixels, LEFT)
for weight, pixel in zip(weights, weight_grid):
if weight >= 0:
color = self.weights_color
else:
color = self.negative_weights_color
pixel.set_fill(color, opacity = abs(weight))

self.play(FadeOut(w_labels))


self.play(
FadeIn(
VGroup(*weight_grid[len(decimals):]),
lag_ratio = 0.5,
run_time = 3
),
*[
ReplacementTransform(decimal, pixel)
for decimal, pixel in zip(decimals, weight_grid)
]
)
self.wait()

self.weight_grid = weight_grid


def make_most_weights_0(self):


weight_grid = self.weight_grid
pixels = self.pixels
pixels_group = self.pixels_group

weight_grid.generate_target()


for w, p in zip(weight_grid.target, pixels):
if p.get_fill_opacity() > 0.1:
w.set_fill(GREEN, 0.5)
else:
w.set_fill(BLACK, 0.5)
w.set_stroke(WHITE, 0.5)

digit = self.get_digit()


digit.replace(pixels)

self.play(MoveToTarget(


weight_grid,
run_time = 2,
lag_ratio = 0.5
))
self.wait()
self.play(Transform(
pixels, digit,
run_time = 2,
lag_ratio = 0.5
))
self.wait()
self.play(weight_grid.move_to, pixels)
self.wait()
self.play(
ReplacementTransform(
self.pixels_to_detect.copy(),
self.weighted_sum,
run_time = 3,
lag_ratio = 0.5
),
Animation(weight_grid),
)
self.wait()

def add_negative_weights_around_the_edge(self):


weight_grid = self.weight_grid
pixels = self.pixels

self.play(weight_grid.next_to, pixels, LEFT)


self.play(*[
ApplyMethod(
weight_grid[28*y + x].set_fill,
self.negative_weights_color,
0.5
)
for y in (6, 10)
for x in range(14-4, 14+4)
])
self.wait(2)
self.play(weight_grid.move_to, pixels)
self.wait(2)

####

def get_digit(self):
digit_vect = get_organized_images()[7][4]
digit = PixelsFromVect(digit_vect)
digit.set_stroke(width = 0.5)
return digit

def get_pixels_to_detect(self, pixels):


d = int(np.sqrt(len(pixels)))
return VGroup(*it.chain(*[
pixels[d*n + d/2 - 4 : d*n + d/2 + 4]
for n in range(7, 10)
]))

def get_surrounding_pixels_for_edge(self, pixels):


d = int(np.sqrt(len(pixels)))
return VGroup(*it.chain(*[
pixels[d*n + d/2 - 4 : d*n + d/2 + 4]
for n in (6, 10)
]))

def make_edges_weighted(self, edges, weights):


for edge, r in zip(edges, weights):
if r > 0:
color = self.weights_color
else:
color = self.negative_weights_color
edge.set_stroke(color, 6*abs(r))

class MotivateSquishing(Scene):


def construct(self):
self.add_weighted_sum()
self.show_real_number_line()
self.show_interval()
self.squish_into_interval()

def add_weighted_sum(self):


weighted_sum = Tex(*it.chain(*[
["w_%d"%d, "a_%d"%d, "+"]
for d in range(1, 5)
] + [
["\\cdots", "+", "w_n", "a_n"]
]))
weighted_sum.set_color_by_tex("w_", GREEN)
weighted_sum.to_edge(UP)
self.add(weighted_sum)
self.weighted_sum = weighted_sum

def show_real_number_line(self):


weighted_sum = self.weighted_sum
number_line = NumberLine(unit_size = 1.5)
number_line.add_numbers()
number_line.shift(UP)
arrow1, arrow2 = [
Arrow(
weighted_sum.get_bottom(),
number_line.number_to_point(n),
)
for n in (-3, 3)
]

self.play(Write(number_line))


self.play(GrowFromPoint(arrow1, arrow1.get_start()))
self.play(Transform(
arrow1, arrow2,
run_time = 5,
rate_func = there_and_back
))
self.play(FadeOut(arrow1))

self.number_line = number_line


def show_interval(self):


lower_number_line = self.number_line.copy()
lower_number_line.shift(2*DOWN)
lower_number_line.set_color(GREY_B)
lower_number_line.numbers.set_color(WHITE)
interval = Line(
lower_number_line.number_to_point(0),
lower_number_line.number_to_point(1),
color = YELLOW,
stroke_width = 5
)
brace = Brace(interval, DOWN, buff = 0.7)
words = TexText("Activations should be in this range")
words.next_to(brace, DOWN, SMALL_BUFF)

self.play(ReplacementTransform(


self.number_line.copy(), lower_number_line
))
self.play(
GrowFromCenter(brace),
GrowFromCenter(interval),
)
self.play(Write(words, run_time = 2))
self.wait()

self.lower_number_line = lower_number_line


def squish_into_interval(self):


line = self.number_line
line.remove(*line.numbers)
ghost_line = line.copy()
ghost_line.fade(0.5)
ghost_line.set_color(BLUE_E)
self.add(ghost_line, line)
lower_line = self.lower_number_line

line.generate_target()


u = line.unit_size
line.target.apply_function(
lambda p : np.array([u*sigmoid(p[0])]+list(p[1:]))
)
line.target.move_to(lower_line.number_to_point(0.5))

arrow = Arrow(


line.numbers.get_bottom(),
line.target.get_top(),
color = YELLOW
)

self.play(


MoveToTarget(line),
GrowFromPoint(arrow, arrow.get_start())
)
self.wait(2)

class IntroduceSigmoid(GraphScene):


CONFIG = {
"x_min" : -5,
"x_max" : 5,
"x_axis_width" : 12,
"y_min" : -1,
"y_max" : 2,
"y_axis_label" : "",
"graph_origin" : DOWN,
"x_labeled_nums" : list(range(-4, 5)),
"y_labeled_nums" : list(range(-1, 3)),
}
def construct(self):
self.setup_axes()
self.add_title()
self.add_graph()
self.show_part(-5, -2, RED)
self.show_part(2, 5, GREEN)
self.show_part(-2, 2, BLUE)

def add_title(self):


name = TexText("Sigmoid")
name.next_to(ORIGIN, RIGHT, LARGE_BUFF)
name.to_edge(UP)
char = self.x_axis_label.replace("$", "")
equation = Tex(
"\\sigma(%s) = \\frac{1}{1+e^{-%s}}"%(char, char)
)
equation.next_to(name, DOWN)
self.add(equation, name)

self.equation = equation


self.sigmoid_name = name

def add_graph(self):


graph = self.get_graph(
lambda x : 1./(1+np.exp(-x)),
color = YELLOW
)

self.play(ShowCreation(graph))


self.wait()

self.sigmoid_graph = graph


###

def show_part(self, x_min, x_max, color):
line, graph_part = [
self.get_graph(
func,
x_min = x_min,
x_max = x_max,
color = color,
).set_stroke(width = 4)
for func in (lambda x : 0, sigmoid)
]

self.play(ShowCreation(line))


self.wait()
self.play(Transform(line, graph_part))
self.wait()

class IncludeBias(IntroduceWeights):


def construct(self):
self.force_skipping()
self.zoom_in_on_one_neuron()
self.setup_start()
self.revert_to_original_skipping_status()

self.add_sigmoid_label()


self.words_on_activation()
self.comment_on_need_for_bias()
self.add_bias()
self.summarize_weights_and_biases()

def setup_start(self):


self.weighted_sum = self.get_weighted_sum()
digit = self.get_digit()
rect = SurroundingRectangle(digit)
d_group = VGroup(digit, rect)
d_group.set_height(3)
d_group.to_edge(RIGHT)
weight_grid = digit.copy()
weight_grid.set_fill(BLACK, 0.5)
self.get_pixels_to_detect(weight_grid).set_fill(
GREEN, 0.5
)
self.get_surrounding_pixels_for_edge(weight_grid).set_fill(
RED, 0.5
)
weight_grid.move_to(digit)

edges = self.neuron.edges_in


self.make_edges_weighted(
edges, 1.5*np.random.random(len(edges)) - 0.5
)

Transform(


self.network_mob.layers[0],
self.network_mob.get_active_layer(0, np.random.random(16))
).update(1)

self.add(self.weighted_sum, digit, weight_grid)


self.digit = digit
self.weight_grid = weight_grid

def add_sigmoid_label(self):


name = TexText("Sigmoid")
sigma = self.weighted_sum[0][0]
name.next_to(sigma, UP)
name.to_edge(UP, SMALL_BUFF)

arrow = Arrow(


name.get_bottom(), sigma.get_top(),
buff = SMALL_BUFF,
use_rectangular_stem = False,
max_tip_length_to_length_ratio = 0.3
)

self.play(


Write(name),
ShowCreation(arrow),
)
self.sigmoid_name = name
self.sigmoid_arrow = arrow

def words_on_activation(self):


neuron = self.neuron
weighted_sum = self.weighted_sum

activation_word = TexText("Activation")


activation_word.next_to(neuron, RIGHT)
arrow = Arrow(neuron, weighted_sum.get_bottom())
arrow.set_color(WHITE)
words = TexText("How positive is this?")
words.next_to(self.weighted_sum, UP, SMALL_BUFF)

self.play(


FadeIn(activation_word),
neuron.set_fill, WHITE, 0.8,
)
self.wait()
self.play(
GrowArrow(arrow),
ReplacementTransform(activation_word, words),
)
self.wait(2)
self.play(FadeOut(arrow))

self.how_positive_words = words


def comment_on_need_for_bias(self):


neuron = self.neuron
weight_grid = self.weight_grid
colored_pixels = VGroup(
self.get_pixels_to_detect(weight_grid),
self.get_surrounding_pixels_for_edge(weight_grid),
)

words = TexText(


"Only activate meaningfully \\\\ when",
"weighted sum", "$> 10$"
)
words.set_color_by_tex("weighted", GREEN)
words.next_to(neuron, RIGHT)

self.play(Write(words, run_time = 2))


self.play(ApplyMethod(
colored_pixels.shift, MED_LARGE_BUFF*UP,
rate_func = there_and_back,
run_time = 2,
lag_ratio = 0.5
))
self.wait()

self.gt_ten = words[-1]


def add_bias(self):


bias = Tex("-10")
wn, rp = self.weighted_sum[-2:]
bias.next_to(wn, RIGHT, SMALL_BUFF)
bias.shift(0.02*UP)
rp.generate_target()
rp.target.next_to(bias, RIGHT, SMALL_BUFF)

rect = SurroundingRectangle(bias, buff = 0.5*SMALL_BUFF)


name = TexText("``bias''")
name.next_to(rect, DOWN)
VGroup(rect, name).set_color(BLUE)

self.play(


ReplacementTransform(
self.gt_ten.copy(), bias,
run_time = 2
),
MoveToTarget(rp),
)
self.wait(2)
self.play(
ShowCreation(rect),
Write(name)
)
self.wait(2)

self.bias_name = name


def summarize_weights_and_biases(self):


weight_grid = self.weight_grid
bias_name = self.bias_name

self.play(LaggedStartMap(


ApplyMethod, weight_grid,
lambda p : (p.set_fill,
random.choice([GREEN, GREEN, RED]),
random.random()
),
rate_func = there_and_back,
lag_ratio = 0.4,
run_time = 4
))
self.wait()
self.play(Indicate(bias_name))
self.wait(2)

###

def get_weighted_sum(self):
args = ["\\sigma \\big("]
for d in range(1, 4):
args += ["w_%d"%d, "a_%d"%d, "+"]
args += ["\\cdots", "+", "w_n", "a_n"]
args += ["\\big)"]
weighted_sum = Tex(*args)
weighted_sum.set_color_by_tex("w_", GREEN)
weighted_sum.set_color_by_tex("\\big", YELLOW)
weighted_sum.to_edge(UP, LARGE_BUFF)
weighted_sum.shift(RIGHT)

return weighted_sum


class BiasForInactiviyWords(Scene):


def construct(self):
words = TexText("Bias for inactivity")
words.set_color(BLUE)
words.set_width(FRAME_WIDTH - 1)
words.to_edge(UP)

self.play(Write(words))


self.wait(3)

class ContinualEdgeUpdate(VGroup):


CONFIG = {
"max_stroke_width" : 3,
"stroke_width_exp" : 7,
"n_cycles" : 5,
"colors" : [GREEN, GREEN, GREEN, RED],
}
def __init__(self, network_mob, **kwargs):
VGroup.__init__(self, **kwargs)
self.internal_time = 0
n_cycles = self.n_cycles
edges = VGroup(*it.chain(*network_mob.edge_groups))
self.move_to_targets = []
for edge in edges:
edge.colors = [
random.choice(self.colors)
for x in range(n_cycles)
]
msw = self.max_stroke_width
edge.widths = [
msw*random.random()**self.stroke_width_exp
for x in range(n_cycles)
]
edge.cycle_time = 1 + random.random()

edge.generate_target()


edge.target.set_stroke(edge.colors[0], edge.widths[0])
edge.become(edge.target)
self.move_to_targets.append(edge)
self.edges = edges
self.add(edges)
self.add_updater(lambda m, dt: self.update_edges(dt))

def update_edges(self, dt):


self.internal_time += dt
if self.internal_time < 1:
alpha = smooth(self.internal_time)
for move_to_target in self.move_to_targets:
move_to_target.update(alpha)
return
for edge in self.edges:
t = (self.internal_time-1)/edge.cycle_time
alpha = ((self.internal_time-1)%edge.cycle_time)/edge.cycle_time
low_n = int(t)%len(edge.colors)
high_n = int(t+1)%len(edge.colors)
color = interpolate_color(edge.colors[low_n], edge.colors[high_n], alpha)
width = interpolate(edge.widths[low_n], edge.widths[high_n], alpha)
edge.set_stroke(color, width)

class ShowRemainingNetwork(IntroduceWeights):


def construct(self):
self.force_skipping()
self.zoom_in_on_one_neuron()
self.revert_to_original_skipping_status()

self.show_all_of_second_layer()


self.count_in_biases()
self.compute_layer_two_of_weights_and_biases_count()
self.show_remaining_layers()
self.show_final_number()
self.tweak_weights()

def show_all_of_second_layer(self):


example_neuron = self.neuron
layer = self.network_mob.layers[1]

neurons = VGroup(*layer.neurons)


neurons.remove(example_neuron)

words = TexText("784", "weights", "per neuron")


words.next_to(layer.neurons[0], RIGHT)
words.to_edge(UP)

self.play(FadeIn(words))


last_edges = None
for neuron in neurons[:7]:
edges = neuron.edges_in
added_anims = []
if last_edges is not None:
added_anims += [
last_edges.set_stroke, None, 1
]
edges.set_stroke(width = 2)
self.play(
ShowCreation(edges, lag_ratio = 0.5),
FadeIn(neuron),
*added_anims,
run_time = 1.5
)
last_edges = edges
self.play(
LaggedStartMap(
ShowCreation, VGroup(*[
n.edges_in for n in neurons[7:]
]),
run_time = 3,
),
LaggedStartMap(
FadeIn, VGroup(*neurons[7:]),
run_time = 3,
),
VGroup(*last_edges[1:]).set_stroke, None, 1
)
self.wait()

self.weights_words = words


def count_in_biases(self):


neurons = self.network_mob.layers[1].neurons
words = TexText("One", "bias","for each")
words.next_to(neurons, RIGHT, buff = 2)
arrows = VGroup(*[
Arrow(
words.get_left(),
neuron.get_center(),
color = BLUE
)
for neuron in neurons
])

self.play(


FadeIn(words),
LaggedStartMap(
GrowArrow, arrows,
run_time = 3,
lag_ratio = 0.3,
)
)
self.wait()

self.bias_words = words


self.bias_arrows = arrows

def compute_layer_two_of_weights_and_biases_count(self):


ww1, ww2, ww3 = weights_words = self.weights_words
bb1, bb2, bb3 = bias_words = self.bias_words
bias_arrows = self.bias_arrows

times_16 = Tex("\\times 16")


times_16.next_to(ww1, RIGHT, SMALL_BUFF)
ww2.generate_target()
ww2.target.next_to(times_16, RIGHT)

bias_count = TexText("16", "biases")


bias_count.next_to(ww2.target, RIGHT, LARGE_BUFF)

self.play(


Write(times_16),
MoveToTarget(ww2),
FadeOut(ww3)
)
self.wait()
self.play(
ReplacementTransform(times_16.copy(), bias_count[0]),
FadeOut(bb1),
ReplacementTransform(bb2, bias_count[1]),
FadeOut(bb3),
LaggedStartMap(FadeOut, bias_arrows)
)
self.wait()

self.weights_count = VGroup(ww1, times_16, ww2)


self.bias_count = bias_count

def show_remaining_layers(self):


weights_count = self.weights_count
bias_count = self.bias_count
for count in weights_count, bias_count:
count.generate_target()
count.prefix = VGroup(*count.target[:-1])

added_weights = Tex(


"+16\\!\\times\\! 16 + 16 \\!\\times\\! 10"
)
added_weights.to_corner(UP+RIGHT)
weights_count.prefix.next_to(added_weights, LEFT, SMALL_BUFF)
weights_count.target[-1].next_to(
VGroup(weights_count.prefix, added_weights),
DOWN
)

added_biases = Tex("+ 16 + 10")


group = VGroup(bias_count.prefix, added_biases)
group.arrange(RIGHT, SMALL_BUFF)
group.next_to(weights_count.target[-1], DOWN, LARGE_BUFF)
bias_count.target[-1].next_to(group, DOWN)

network_mob = self.network_mob


edges = VGroup(*it.chain(*network_mob.edge_groups[1:]))
neurons = VGroup(*it.chain(*[
layer.neurons for layer in network_mob.layers[2:]
]))

self.play(


MoveToTarget(weights_count),
MoveToTarget(bias_count),
Write(added_weights, run_time = 1),
Write(added_biases, run_time = 1),
LaggedStartMap(
ShowCreation, edges,
run_time = 4,
lag_ratio = 0.3,
),
LaggedStartMap(
FadeIn, neurons,
run_time = 4,
lag_ratio = 0.3,
)
)
self.wait(2)

weights_count.add(added_weights)


bias_count.add(added_biases)

def show_final_number(self):


group = VGroup(
self.weights_count,
self.bias_count,
)
group.generate_target()
group.target.scale(0.8)
rect = SurroundingRectangle(group.target, buff = MED_SMALL_BUFF)
num_mob = Tex("13{,}002")
num_mob.scale(1.5)
num_mob.next_to(rect, DOWN)

self.play(


ShowCreation(rect),
MoveToTarget(group),
)
self.play(Write(num_mob))
self.wait()

self.final_number = num_mob


def tweak_weights(self):


learning = TexText("Learning $\\rightarrow$")
finding_words = TexText(
"Finding the right \\\\ weights and biases"
)
group = VGroup(learning, finding_words)
group.arrange(RIGHT)
group.scale(0.8)
group.next_to(self.final_number, DOWN, MED_LARGE_BUFF)

self.add(ContinualEdgeUpdate(self.network_mob))


self.wait(5)
self.play(Write(group))
self.wait(10)

###

def get_edge_weight_wandering_anim(self, edges):
for edge in edges:
edge.generate_target()
edge.target.set_stroke(
color = random.choice([GREEN, GREEN, GREEN, RED]),
width = 3*random.random()**7
)
self.play(
LaggedStartMap(
MoveToTarget, edges,
lag_ratio = 0.6,
run_time = 2,
),
*added_anims
)

class ImagineSettingByHand(Scene):


def construct(self):
randy = Randolph()
randy.scale(0.7)
randy.to_corner(DOWN+LEFT)

bubble = randy.get_bubble()


network_mob = NetworkMobject(
Network(sizes = [8, 6, 6, 4]),
neuron_stroke_color = WHITE
)
network_mob.scale(0.7)
network_mob.move_to(bubble.get_bubble_center())
network_mob.shift(MED_SMALL_BUFF*RIGHT + SMALL_BUFF*(UP+RIGHT))

self.add(randy, bubble, network_mob)


self.add(ContinualEdgeUpdate(network_mob))
self.play(randy.change, "pondering")
self.wait()
self.play(Blink(randy))
self.wait()
self.play(randy.change, "horrified", network_mob)
self.play(Blink(randy))
self.wait(10)

class WhenTheNetworkFails(MoreHonestMNistNetworkPreview):


CONFIG = {
"network_mob_config" : {"layer_to_layer_buff" : 2}
}
def construct(self):
self.setup_network_mob()
self.black_box()
self.incorrect_classification()
self.ask_about_weights()

def setup_network_mob(self):


self.network_mob.scale(0.8)
self.network_mob.to_edge(DOWN)

def black_box(self):


network_mob = self.network_mob
layers = VGroup(*network_mob.layers[1:3])
box = SurroundingRectangle(
layers,
stroke_color = WHITE,
fill_color = BLACK,
fill_opacity = 0.8,
)
words = TexText("...rather than treating this as a black box")
words.next_to(box, UP, LARGE_BUFF)

self.play(


Write(words, run_time = 2),
DrawBorderThenFill(box)
)
self.wait()
self.play(*list(map(FadeOut, [words, box])))

def incorrect_classification(self):


network = self.network
training_data, validation_data, test_data = load_data_wrapper()
for in_vect, result in test_data[20:]:
network_answer = np.argmax(network.feedforward(in_vect))
if network_answer != result:
break
self.feed_in_image(in_vect)

wrong = TexText("Wrong!")


wrong.set_color(RED)
wrong.next_to(self.network_mob.layers[-1], UP+RIGHT)
self.play(Write(wrong, run_time = 1))

def ask_about_weights(self):


question = TexText(
"What weights are used here?\\\\",
"What are they doing?"
)
question.next_to(self.network_mob, UP)

self.add(ContinualEdgeUpdate(self.network_mob))


self.play(Write(question))
self.wait(10)
###

def reset_display(self, *args):


pass

class EvenWhenItWorks(TeacherStudentsScene):


def construct(self):
self.teacher_says(
"Even when it works,\\\\",
"dig into why."
)
self.change_student_modes(*["pondering"]*3)
self.wait(7)

class IntroduceWeightMatrix(NetworkScene):


CONFIG = {
"network_mob_config" : {
"neuron_stroke_color" : WHITE,
"neuron_fill_color" : WHITE,
"neuron_radius" : 0.35,
"layer_to_layer_buff" : 2,
},
"layer_sizes" : [8, 6],
}
def construct(self):
self.setup_network_mob()
self.show_weighted_sum()
self.organize_activations_into_column()
self.organize_weights_as_matrix()
self.show_meaning_of_matrix_row()
self.connect_weighted_sum_to_matrix_multiplication()
self.add_bias_vector()
self.apply_sigmoid()
self.write_clean_final_expression()

def setup_network_mob(self):


self.network_mob.to_edge(LEFT, buff = LARGE_BUFF)
self.network_mob.layers[1].neurons.shift(0.02*RIGHT)

def show_weighted_sum(self):


self.fade_many_neurons()
self.activate_first_layer()
self.show_first_neuron_weighted_sum()
self.add_bias()
self.add_sigmoid()
##

def fade_many_neurons(self):


anims = []
neurons = self.network_mob.layers[1].neurons
for neuron in neurons[1:]:
neuron.save_state()
neuron.edges_in.save_state()
anims += [
neuron.fade, 0.8,
neuron.set_fill, None, 0,
neuron.edges_in.fade, 0.8,
]
anims += [
Animation(neurons[0]),
Animation(neurons[0].edges_in),
]
self.play(*anims)

def activate_first_layer(self):


layer = self.network_mob.layers[0]
activations = 0.7*np.random.random(len(layer.neurons))
active_layer = self.network_mob.get_active_layer(0, activations)
a_labels = VGroup(*[
Tex("a^{(0)}_%d"%d)
for d in range(len(layer.neurons))
])
for label, neuron in zip(a_labels, layer.neurons):
label.scale(0.75)
label.move_to(neuron)

self.play(


Transform(layer, active_layer),
Write(a_labels, run_time = 2)
)

self.a_labels = a_labels


def show_first_neuron_weighted_sum(self):


neuron = self.network_mob.layers[1].neurons[0]
a_labels = VGroup(*self.a_labels[:2]).copy()
a_labels.generate_target()
w_labels = VGroup(*[
Tex("w_{0, %d}"%d)
for d in range(len(a_labels))
])
weighted_sum = VGroup()
symbols = VGroup()
for a_label, w_label in zip(a_labels.target, w_labels):
a_label.scale(1./0.75)
plus = Tex("+")
weighted_sum.add(w_label, a_label, plus)
symbols.add(plus)
weighted_sum.add(
Tex("\\cdots"),
Tex("+"),
Tex("w_{0, n}"),
Tex("a^{(0)}_n"),
)

weighted_sum.arrange(RIGHT)


a1_label = Tex("a^{(1)}_0")
a1_label.next_to(neuron, RIGHT)
equals = Tex("=").next_to(a1_label, RIGHT)
weighted_sum.next_to(equals, RIGHT)

symbols.add(*weighted_sum[-4:-2])


w_labels.add(weighted_sum[-2])
a_labels.add(self.a_labels[-1].copy())
a_labels.target.add(weighted_sum[-1])
a_labels.add(VGroup(*self.a_labels[2:-1]).copy())
a_labels.target.add(VectorizedPoint(weighted_sum[-4].get_center()))

VGroup(a1_label, equals, weighted_sum).scale(


0.75, about_point = a1_label.get_left()
)

w_labels.set_color(GREEN)


w_labels.shift(0.6*SMALL_BUFF*DOWN)
a_labels.target.shift(0.5*SMALL_BUFF*UP)

self.play(


Write(a1_label),
Write(equals),
neuron.set_fill, None, 0.3,
run_time = 1
)
self.play(MoveToTarget(a_labels, run_time = 1.5))
self.play(
Write(w_labels),
Write(symbols),
)

self.a1_label = a1_label


self.a1_equals = equals
self.w_labels = w_labels
self.a_labels_in_sum = a_labels
self.symbols = symbols
self.weighted_sum = VGroup(w_labels, a_labels, symbols)

def add_bias(self):


weighted_sum = self.weighted_sum
bias = Tex("+\\,", "b_0")
bias.scale(0.75)
bias.next_to(weighted_sum, RIGHT, SMALL_BUFF)
bias.shift(0.5*SMALL_BUFF*DOWN)
name = TexText("Bias")
name.scale(0.75)
name.next_to(bias, DOWN, MED_LARGE_BUFF)
arrow = Arrow(name, bias, buff = SMALL_BUFF)
VGroup(name, arrow, bias).set_color(BLUE)

self.play(


FadeIn(name),
FadeIn(bias),
GrowArrow(arrow),
)

self.weighted_sum.add(bias)


self.bias = bias


self.bias_name = VGroup(name, arrow)

def add_sigmoid(self):


weighted_sum = self.weighted_sum
weighted_sum.generate_target()
sigma, lp, rp = mob = Tex("\\sigma\\big(\\big)")
# mob.scale(0.75)
sigma.move_to(weighted_sum.get_left())
sigma.shift(0.5*SMALL_BUFF*(DOWN+RIGHT))
lp.next_to(sigma, RIGHT, SMALL_BUFF)
weighted_sum.target.next_to(lp, RIGHT, SMALL_BUFF)
rp.next_to(weighted_sum.target, RIGHT, SMALL_BUFF)

name = TexText("Sigmoid")


name.next_to(sigma, UP, MED_LARGE_BUFF)
arrow = Arrow(name, sigma, buff = SMALL_BUFF)
sigmoid_name = VGroup(name, arrow)
VGroup(sigmoid_name, mob).set_color(YELLOW)

self.play(


FadeIn(mob),
MoveToTarget(weighted_sum),
MaintainPositionRelativeTo(self.bias_name, self.bias),
)
self.play(FadeIn(sigmoid_name))

self.sigma = sigma


self.sigma_parens = VGroup(lp, rp)
self.sigmoid_name = sigmoid_name

##


def organize_activations_into_column(self):
a_labels = self.a_labels.copy()
a_labels.generate_target()
column = a_labels.target
a_labels_in_sum = self.a_labels_in_sum

dots = Tex("\\vdots")


mid_as = VGroup(*column[2:-1])
Transform(mid_as, dots).update(1)
last_a = column[-1]
new_last_a = Tex(
last_a.get_tex().replace("7", "n")
)
new_last_a.replace(last_a)
Transform(last_a, new_last_a).update(1)

VGroup(
*column[:2] + [mid_as] + [column[-1]]


).arrange(DOWN)
column.shift(DOWN + 3.5*RIGHT)

pre_brackets = self.get_brackets(a_labels)


post_bracketes = self.get_brackets(column)
pre_brackets.set_fill(opacity = 0)

self.play(FocusOn(self.a_labels[0]))


self.play(LaggedStartMap(
Indicate, self.a_labels,
rate_func = there_and_back,
run_time = 1
))
self.play(
MoveToTarget(a_labels),
Transform(pre_brackets, post_bracketes),
run_time = 2
)
self.wait()
self.play(*[
LaggedStartMap(Indicate, mob, rate_func = there_and_back)
for mob in (a_labels, a_labels_in_sum)
])
self.wait()

self.a_column = a_labels


self.a_column_brackets = pre_brackets

def organize_weights_as_matrix(self):


a_column = self.a_column
a_column_brackets = self.a_column_brackets
w_brackets = a_column_brackets.copy()
w_brackets.next_to(a_column_brackets, LEFT, SMALL_BUFF)
lwb, rwb = w_brackets

w_labels = self.w_labels.copy()


w_labels.submobjects.insert(
2, self.symbols[-2].copy()
)
w_labels.generate_target()
w_labels.target.arrange(RIGHT)
w_labels.target.next_to(a_column[0], LEFT, buff = 0.8)
lwb.next_to(w_labels.target, LEFT, SMALL_BUFF)
lwb.align_to(rwb, UP)

row_1, row_k = [


VGroup(*list(map(Tex, [
"w_{%s, 0}"%i,
"w_{%s, 1}"%i,
"\\cdots",
"w_{%s, n}"%i,
])))
for i in ("1", "k")
]
dots_row = VGroup(*list(map(Tex, [
"\\vdots", "\\vdots", "\\ddots", "\\vdots"
])))

lower_rows = VGroup(row_1, dots_row, row_k)


lower_rows.scale(0.75)
last_row = w_labels.target
for row in lower_rows:
for target, mover in zip(last_row, row):
mover.move_to(target)
if "w" in mover.get_tex():
mover.set_color(GREEN)
row.next_to(last_row, DOWN, buff = 0.45)
last_row = row

self.play(


MoveToTarget(w_labels),
Write(w_brackets, run_time = 1)
)
self.play(FadeIn(
lower_rows,
run_time = 3,
lag_ratio = 0.5,
))
self.wait()

self.top_matrix_row = w_labels


self.lower_matrix_rows = lower_rows
self.matrix_brackets = w_brackets

def show_meaning_of_matrix_row(self):


row = self.top_matrix_row
edges = self.network_mob.layers[1].neurons[0].edges_in.copy()
edges.set_stroke(GREEN, 5)
rect = SurroundingRectangle(row, color = GREEN_B)

self.play(ShowCreation(rect))


for x in range(2):
self.play(LaggedStartMap(
ShowCreationThenDestruction, edges,
lag_ratio = 0.8
))
self.wait()

self.top_row_rect = rect


def connect_weighted_sum_to_matrix_multiplication(self):


a_column = self.a_column
a_brackets = self.a_column_brackets
top_row_rect = self.top_row_rect

column_rect = SurroundingRectangle(a_column)


equals = Tex("=")


equals.next_to(a_brackets, RIGHT)
result_brackets = a_brackets.copy()
result_terms = VGroup()
for i in 0, 1, 4, -1:
a = a_column[i]
if i == 4:
mob = Tex("\\vdots")
else:
# mob = Circle(radius = 0.2, color = YELLOW)
mob = Tex("?").scale(1.3).set_color(YELLOW)
result_terms.add(mob.move_to(a))
VGroup(result_brackets, result_terms).next_to(equals, RIGHT)

brace = Brace(


VGroup(self.w_labels, self.a_labels_in_sum), DOWN
)
arrow = Arrow(
brace.get_bottom(),
result_terms[0].get_top(),
buff = SMALL_BUFF
)

self.play(


GrowArrow(arrow),
GrowFromCenter(brace),
)
self.play(
Write(equals),
FadeIn(result_brackets),
)
self.play(ShowCreation(column_rect))
self.play(ReplacementTransform(
VGroup(top_row_rect, column_rect).copy(),
result_terms[0]
))
self.play(LaggedStartMap(
FadeIn, VGroup(*result_terms[1:])
))
self.wait(2)
self.show_meaning_of_lower_rows(
arrow, brace, top_row_rect, result_terms
)
self.play(*list(map(FadeOut, [
result_terms, result_brackets, equals, column_rect
])))

def show_meaning_of_lower_rows(self, arrow, brace, row_rect, result_terms):


n1, n2, nk = neurons = VGroup(*[
self.network_mob.layers[1].neurons[i]
for i in (0, 1, -1)
])
for n in neurons:
n.save_state()
n.edges_in.save_state()

rect2 = SurroundingRectangle(result_terms[1])


rectk = SurroundingRectangle(result_terms[-1])
VGroup(rect2, rectk).set_color(WHITE)
row2 = self.lower_matrix_rows[0]
rowk = self.lower_matrix_rows[-1]

def show_edges(neuron):


self.play(LaggedStartMap(
ShowCreationThenDestruction,
neuron.edges_in.copy().set_stroke(GREEN, 5),
lag_ratio = 0.7,
run_time = 1,
))

self.play(


row_rect.move_to, row2,
n1.fade,
n1.set_fill, None, 0,
n1.edges_in.set_stroke, None, 1,
n2.set_stroke, WHITE, 3,
n2.edges_in.set_stroke, None, 3,
ReplacementTransform(arrow, rect2),
FadeOut(brace),
)
show_edges(n2)
self.play(
row_rect.move_to, rowk,
n2.restore,
n2.edges_in.restore,
nk.set_stroke, WHITE, 3,
nk.edges_in.set_stroke, None, 3,
ReplacementTransform(rect2, rectk),
)
show_edges(nk)
self.play(
n1.restore,
n1.edges_in.restore,
nk.restore,
nk.edges_in.restore,
FadeOut(rectk),
FadeOut(row_rect),
)

def add_bias_vector(self):


bias = self.bias
bias_name = self.bias_name
a_column_brackets = self.a_column_brackets
a_column = self.a_column

plus = Tex("+")


b_brackets = a_column_brackets.copy()
b_column = VGroup(*list(map(Tex, [
"b_0", "b_1", "\\vdots", "b_n",
])))
b_column.scale(0.85)
b_column.arrange(DOWN, buff = 0.35)
b_column.move_to(a_column)
b_column.set_color(BLUE)
plus.next_to(a_column_brackets, RIGHT)
VGroup(b_brackets, b_column).next_to(plus, RIGHT)

bias_rect = SurroundingRectangle(bias)


self.play(ShowCreation(bias_rect))


self.play(FadeOut(bias_rect))
self.play(
Write(plus),
Write(b_brackets),
Transform(self.bias[1].copy(), b_column[0]),
run_time = 1
)
self.play(LaggedStartMap(
FadeIn, VGroup(*b_column[1:])
))
self.wait()

self.bias_plus = plus


self.b_brackets = b_brackets
self.b_column = b_column

def apply_sigmoid(self):


expression_bounds = VGroup(
self.matrix_brackets[0], self.b_brackets[1]
)
sigma = self.sigma.copy()
slp, srp = self.sigma_parens.copy()

big_lp, big_rp = parens = Tex("()")


parens.scale(3)
parens.stretch_to_fit_height(expression_bounds.get_height())
big_lp.next_to(expression_bounds, LEFT, SMALL_BUFF)
big_rp.next_to(expression_bounds, RIGHT, SMALL_BUFF)
parens.set_color(YELLOW)

self.play(


sigma.scale, 2,
sigma.next_to, big_lp, LEFT, SMALL_BUFF,
Transform(slp, big_lp),
Transform(srp, big_rp),
)
self.wait(2)

self.big_sigma_group = VGroup(VGroup(sigma), slp, srp)


def write_clean_final_expression(self):


self.fade_weighted_sum()
expression = Tex(
"\\textbf{a}^{(1)}",
"=",
"\\sigma",
"\\big(",
"\\textbf{W}",
"\\textbf{a}^{(0)}",
"+",
"\\textbf{b}",
"\\big)",
)
expression.set_color_by_tex_to_color_map({
"sigma" : YELLOW,
"big" : YELLOW,
"W" : GREEN,
"\\textbf{b}" : BLUE
})
expression.next_to(self.big_sigma_group, UP, LARGE_BUFF)
a1, equals, sigma, lp, W, a0, plus, b, rp = expression

neuron_anims = []


neurons = VGroup(*self.network_mob.layers[1].neurons[1:])
for neuron in neurons:
neuron_anims += [
neuron.restore,
neuron.set_fill, None, random.random()
]
neuron_anims += [
neuron.edges_in.restore
]
neurons.add_to_back(self.network_mob.layers[1].neurons[0])

self.play(ReplacementTransform(


VGroup(
self.top_matrix_row, self.lower_matrix_rows,
self.matrix_brackets
).copy(),
VGroup(W),
))
self.play(ReplacementTransform(
VGroup(self.a_column, self.a_column_brackets).copy(),
VGroup(VGroup(a0)),
))
self.play(
ReplacementTransform(
VGroup(self.b_column, self.b_brackets).copy(),
VGroup(VGroup(b))
),
ReplacementTransform(
self.bias_plus.copy(), plus
)
)
self.play(ReplacementTransform(
self.big_sigma_group.copy(),
VGroup(sigma, lp, rp)
))
self.wait()
self.play(*neuron_anims, run_time = 2)
self.play(
ReplacementTransform(neurons.copy(), a1),
FadeIn(equals)
)
self.wait(2)

def fade_weighted_sum(self):


self.play(*list(map(FadeOut, [
self.a1_label, self.a1_equals,
self.sigma, self.sigma_parens,
self.weighted_sum,
self.bias_name,
self.sigmoid_name,
])))
###

def get_brackets(self, mob):


lb, rb = both = Tex("\\big[\\big]")
both.set_width(mob.get_width())
both.stretch_to_fit_height(1.2*mob.get_height())
lb.next_to(mob, LEFT, SMALL_BUFF)
rb.next_to(mob, RIGHT, SMALL_BUFF)
return both

class HorrifiedMorty(Scene):


def construct(self):
morty = Mortimer()
morty.flip()
morty.scale(2)

for mode in "horrified", "hesitant":


self.play(
morty.change, mode,
morty.look, UP,
)
self.play(Blink(morty))
self.wait(2)

class SigmoidAppliedToVector(Scene):


def construct(self):
tex = Tex("""
\\sigma \\left(
\\left[\\begin{array}{c}
x \\\\ y \\\\ z
\\end{array}\\right]
\\right) =
\\left[\\begin{array}{c}
\\sigma(x) \\\\ \\sigma(y) \\\\ \\sigma(z)
\\end{array}\\right]
""")
tex.set_width(FRAME_WIDTH - 1)
tex.to_edge(DOWN)
indices = it.chain(
[0], list(range(1, 5)), list(range(16, 16+4)),
list(range(25, 25+2)), [25+3],
list(range(29, 29+2)), [29+3],
list(range(33, 33+2)), [33+3],
)
for i in indices:
tex[i].set_color(YELLOW)
self.add(tex)
self.wait()

class EoLA3Wrapper(PiCreatureScene):


def construct(self):
morty = self.pi_creature
rect = ScreenRectangle(height = 5)
rect.next_to(morty, UP+LEFT)
rect.to_edge(UP, buff = LARGE_BUFF)
title = TexText("Essence of linear algebra")
title.next_to(rect, UP)

self.play(


ShowCreation(rect),
FadeIn(title),
morty.change, "raise_right_hand", rect
)
self.wait(4)

class FeedForwardCode(ExternallyAnimatedScene):


pass

class NeuronIsFunction(MoreHonestMNistNetworkPreview):


CONFIG = {
"network_mob_config" : {
"layer_to_layer_buff" : 2
}
}
def construct(self):
self.setup_network_mob()
self.activate_network()
self.write_neuron_holds_a_number()
self.feed_in_new_image(8, 7)
self.neuron_is_function()
self.show_neuron_as_function()
self.fade_network_back_in()
self.network_is_a_function()
self.feed_in_new_image(9, 4)
self.wait(2)
def setup_network_mob(self):
self.network_mob.scale(0.7)
self.network_mob.to_edge(DOWN)
self.network_mob.shift(LEFT)

def activate_network(self):


network_mob = self.network_mob
self.image_map = get_organized_images()
in_vect = self.image_map[3][0]
mnist_mob = MNistMobject(in_vect)
mnist_mob.next_to(network_mob, LEFT, MED_LARGE_BUFF, UP)
activations = self.network.get_activation_of_all_layers(in_vect)
for i, activation in enumerate(activations):
layer = self.network_mob.layers[i]
Transform(
layer, self.network_mob.get_active_layer(i, activation)
).update(1)
self.add(mnist_mob)

self.image_rect, self.curr_image = mnist_mob


def write_neuron_holds_a_number(self):


neuron_word = TexText("Neuron")
arrow = Arrow(ORIGIN, DOWN, color = BLUE)
thing_words = TexText("Thing that holds \\\\ a number")
group = VGroup(neuron_word, arrow, thing_words)
group.arrange(DOWN)
group.to_corner(UP+RIGHT, buff = LARGE_BUFF)

neuron = self.network_mob.layers[2].neurons[2]


decimal = DecimalNumber(neuron.get_fill_opacity())
decimal.set_width(0.7*neuron.get_width())
decimal.move_to(neuron)
neuron_group = VGroup(neuron, decimal)
neuron_group.save_state()
decimal.set_fill(opacity = 0)

self.play(


neuron_group.restore,
neuron_group.scale, 3,
neuron_group.next_to, neuron_word, LEFT,
FadeIn(neuron_word),
GrowArrow(arrow),
FadeIn(
thing_words, run_time = 2,
rate_func = squish_rate_func(smooth, 0.3, 1)
)
)
self.wait()
self.play(neuron_group.restore)

self.neuron_word = neuron_word


self.neuron_word_arrow = arrow
self.thing_words = thing_words
self.neuron = neuron
self.decimal = decimal

def feed_in_new_image(self, digit, choice):


in_vect = self.image_map[digit][choice]

args = []


for s in "answer_rect", "curr_image", "image_rect":
if hasattr(self, s):
args.append(getattr(self, s))
else:
args.append(VectorizedPoint())
MoreHonestMNistNetworkPreview.reset_display(self, *args)
self.feed_in_image(in_vect)

def neuron_is_function(self):


thing_words = self.thing_words
cross = Cross(thing_words)
function_word = TexText("Function")
function_word.move_to(thing_words, UP)

self.play(


thing_words.fade,
ShowCreation(cross)
)
self.play(
FadeIn(function_word),
VGroup(thing_words, cross).to_edge, DOWN,
)
self.wait()

self.function_word = function_word


def show_neuron_as_function(self):


neuron = self.neuron.copy()
edges = neuron.edges_in.copy()
prev_layer = self.network_mob.layers[1].copy()

arrow = Arrow(ORIGIN, RIGHT, color = BLUE)


arrow.next_to(neuron, RIGHT, SMALL_BUFF)
decimal = DecimalNumber(neuron.get_fill_opacity())
decimal.next_to(arrow, RIGHT)

self.play(


FadeOut(self.network_mob),
*list(map(Animation, [neuron, edges, prev_layer]))
)
self.play(LaggedStartMap(
ShowCreationThenDestruction,
edges.copy().set_stroke(YELLOW, 4),
))
self.play(
GrowArrow(arrow),
Transform(self.decimal, decimal)
)
self.wait(2)

self.non_faded_network_parts = VGroup(


neuron, edges, prev_layer
)
self.neuron_arrow = arrow

def fade_network_back_in(self):


anims = [
FadeIn(
mob,
run_time = 2,
lag_ratio = 0.5
)
for mob in (self.network_mob.layers, self.network_mob.edge_groups)
]
anims += [
FadeOut(self.neuron_arrow),
FadeOut(self.decimal),
]
anims.append(Animation(self.non_faded_network_parts))

self.play(*anims)


self.remove(self.non_faded_network_parts)

def network_is_a_function(self):


neuron_word = self.neuron_word
network_word = TexText("Network")
network_word.set_color(YELLOW)
network_word.move_to(neuron_word)

func_tex = Tex(


"f(a_0, \\dots, a_{783}) = ",
"""\\left[
\\begin{array}{c}
y_0 \\\\ \\vdots \\\\ y_{9}
\\end{array}
\\right]"""
)
func_tex.to_edge(UP)
func_tex.shift(MED_SMALL_BUFF*LEFT)

self.play(


ReplacementTransform(neuron_word, network_word),
FadeIn(func_tex)
)

###

def reset_display(self, answer_rect, image, image_rect):
#Don't do anything, just record these args
self.answer_rect = answer_rect
self.curr_image = image
self.image_rect = image_rect
return

class ComplicationIsReassuring(TeacherStudentsScene):


def construct(self):
self.student_says(
"It kind of has to \\\\ be complicated, right?",
target_mode = "speaking",
student_index = 0
)
self.play(self.teacher.change, "happy")
self.wait(4)

class NextVideo(MoreHonestMNistNetworkPreview, PiCreatureScene):


CONFIG = {
"network_mob_config" : {
"neuron_stroke_color" : WHITE,
"layer_to_layer_buff" : 2.5,
"brace_for_large_layers" : False,
}
}
def setup(self):
MoreHonestMNistNetworkPreview.setup(self)
PiCreatureScene.setup(self)

def construct(self):


self.network_and_data()
self.show_next_video()
self.talk_about_subscription()
self.show_video_neural_network()

def network_and_data(self):


morty = self.pi_creature
network_mob = self.network_mob
network_mob.to_edge(LEFT)
for obj in network_mob, self:
obj.remove(network_mob.output_labels)
network_mob.scale(0.7)
network_mob.shift(RIGHT)
edge_update = ContinualEdgeUpdate(network_mob)

training_data, validation_data, test_data = load_data_wrapper()


data_mobs = VGroup()
for vect, num in test_data[:30]:
image = MNistMobject(vect)
image.set_height(0.7)
arrow = Arrow(ORIGIN, RIGHT, color = BLUE)
num_mob = Tex(str(num))
group = Group(image, arrow, num_mob)
group.arrange(RIGHT, buff = SMALL_BUFF)
group.next_to(ORIGIN, RIGHT)
data_mobs.add(group)

data_mobs.next_to(network_mob, UP)


self.add(edge_update)


self.play(morty.change, "confused", network_mob)
self.wait(2)
for data_mob in data_mobs:
self.add(data_mob)
self.wait(0.2)
self.remove(data_mob)

self.content = network_mob


self.edge_update = edge_update

def show_next_video(self):


morty = self.pi_creature
content = self.content

video = VideoIcon()


video.set_height(3)
video.set_fill(RED, 0.8)
video.next_to(morty, UP+LEFT)

rect = SurroundingRectangle(video)


rect.set_stroke(width = 0)
rect.set_fill(BLACK, 0.5)

words = TexText("On learning")


words.next_to(video, UP)

if self.edge_update.internal_time < 1:


self.edge_update.internal_time = 2
self.play(
content.set_height, 0.8*video.get_height(),
content.move_to, video,
morty.change, "raise_right_hand",
FadeIn(rect),
FadeIn(video),
)
self.add_foreground_mobjects(rect, video)
self.wait(2)
self.play(Write(words))
self.wait(2)

self.video = Group(content, rect, video, words)


def talk_about_subscription(self):


morty = self.pi_creature
morty.generate_target()
morty.target.change("hooray")
morty.target.rotate(
np.pi, axis = UP, about_point = morty.get_left()
)
morty.target.shift(LEFT)
video = self.video
subscribe_word = TexText(
"Subscribe", "!",
arg_separator = ""
)
bang = subscribe_word[1]
subscribe_word.to_corner(DOWN+RIGHT)
subscribe_word.shift(3*UP)
q_mark = TexText("?")
q_mark.move_to(bang, LEFT)
arrow = Arrow(ORIGIN, DOWN, color = RED, buff = 0)
arrow.next_to(subscribe_word, DOWN)
arrow.shift(MED_LARGE_BUFF * RIGHT)

self.play(


Write(subscribe_word),
self.video.shift, 3*LEFT,
MoveToTarget(morty),
)
self.play(GrowArrow(arrow))
self.wait(2)
self.play(morty.change, "maybe", arrow)
self.play(Transform(bang, q_mark))
self.wait(3)

def show_video_neural_network(self):


morty = self.pi_creature

network_mob, rect, video, words = self.video


network_mob.generate_target(use_deepcopy = True)
network_mob.target.set_height(5)
network_mob.target.to_corner(UP+LEFT)
neurons = VGroup(*network_mob.target.layers[-1].neurons[:2])
neurons.set_stroke(width = 0)

video.generate_target()


video.target.set_fill(opacity = 1)
video.target.set_height(neurons.get_height())
video.target.move_to(neurons, LEFT)

self.play(


MoveToTarget(network_mob),
MoveToTarget(video),
FadeOut(words),
FadeOut(rect),
morty.change, "raise_left_hand"
)

neuron_pairs = VGroup(*[


VGroup(*network_mob.layers[-1].neurons[2*i:2*i+2])
for i in range(1, 5)
])
for pair in neuron_pairs:
video = video.copy()
video.move_to(pair, LEFT)
pair.target = video

self.play(LaggedStartMap(


MoveToTarget, neuron_pairs,
run_time = 3
))
self.play(morty.change, "shruggie")
self.wait(10)

###

class NNPatreonThanks(PatreonThanks):
CONFIG = {
"specific_patrons" : [
"Desmos",
"Burt Humburg",
"CrypticSwarm",
"Juan Benet",
"Ali Yahya",
"William",
"Mayank M. Mehrotra",
"Lukas Biewald",
"Samantha D. Suplee",
"Yana Chernobilsky",
"Kaustuv DeBiswas",
"Kathryn Schmiedicke",
"Yu Jun",
"Dave Nicponski",
"Damion Kistler",
"Markus Persson",
"Yoni Nazarathy",
"Ed Kellett",
"Joseph John Cox",
"Luc Ritchie",
"Andy Nichols",
"Harsev Singh",
"Mads Elvheim",
"Erik Sundell",
"Xueqi Li",
"David G. Stork",
"Tianyu Ge",
"Ted Suzman",
"Linh Tran",
"Andrew Busey",
"Michael McGuffin",
"John Haley",
"Ankalagon",
"Eric Lavault",
"Boris Veselinovich",
"Julian Pulgarin",
"Jeff Linse",
"Cooper Jones",
"Ryan Dahl",
"Mark Govea",
"Robert Teed",
"Jason Hise",
"Meshal Alshammari",
"Bernd Sing",
"James Thornton",
"Mustafa Mahdi",
"Mathew Bramson",
"Jerry Ling",
"Vecht",
"Shimin Kuang",
"Rish Kundalia",
"Achille Brighton",
"Ripta Pasay",
]
}

class PiCreatureGesture(PiCreatureScene):


def construct(self):
self.play(self.pi_creature.change, "raise_right_hand")
self.wait(5)
self.play(self.pi_creature.change, "happy")
self.wait(4)

class IntroduceReLU(IntroduceSigmoid):


CONFIG = {
"x_axis_label" : "$a$"
}
def construct(self):
self.setup_axes()
self.add_title()
self.add_graph()
self.old_school()
self.show_ReLU()
self.label_input_regions()

def old_school(self):


sigmoid_graph = self.sigmoid_graph
sigmoid_title = VGroup(
self.sigmoid_name,
self.equation
)
cross = Cross(sigmoid_title)
old_school = TexText("Old school")
old_school.to_corner(UP+RIGHT)
old_school.set_color(RED)
arrow = Arrow(
old_school.get_bottom(),
self.equation.get_right(),
color = RED
)

self.play(ShowCreation(cross))


self.play(
Write(old_school, run_time = 1),
GrowArrow(arrow)
)
self.wait(2)
self.play(
ApplyMethod(
VGroup(cross, sigmoid_title).shift,
FRAME_X_RADIUS*RIGHT,
rate_func = running_start
),
FadeOut(old_school),
FadeOut(arrow),
)
self.play(ShowCreation(
self.sigmoid_graph,
rate_func = lambda t : smooth(1-t),
remover = True
))

def show_ReLU(self):


graph = VGroup(
Line(
self.coords_to_point(-7, 0),
self.coords_to_point(0, 0),
),
Line(
self.coords_to_point(0, 0),
self.coords_to_point(4, 4),
),
)
graph.set_color(YELLOW)
char = self.x_axis_label.replace("$", "")
equation = TexText("ReLU($%s$) = max$(0, %s)$"%(char, char))
equation.shift(FRAME_X_RADIUS*LEFT/2)
equation.to_edge(UP)
equation.add_background_rectangle()
name = TexText("Rectified linear unit")
name.move_to(equation)
name.add_background_rectangle()

self.play(Write(equation))


self.play(ShowCreation(graph), Animation(equation))
self.wait(2)
self.play(
Write(name),
equation.shift, DOWN
)
self.wait(2)

self.ReLU_graph = graph


def label_input_regions(self):


l1, l2 = self.ReLU_graph
neg_words = TexText("Inactive")
neg_words.set_color(RED)
neg_words.next_to(self.coords_to_point(-2, 0), UP)

pos_words = TexText("Same as $f(a) = a$")


pos_words.set_color(GREEN)
pos_words.next_to(
self.coords_to_point(1, 1),
DOWN+RIGHT
)

self.revert_to_original_skipping_status()


self.play(ShowCreation(l1.copy().set_color(RED)))
self.play(Write(neg_words))
self.wait()
self.play(ShowCreation(l2.copy().set_color(GREEN)))
self.play(Write(pos_words))
self.wait(2)

class CompareSigmoidReLUOnDeepNetworks(PiCreatureScene):


def construct(self):
morty, lisha = self.morty, self.lisha
sigmoid_graph = FunctionGraph(
sigmoid,
x_min = -5,
x_max = 5,
)
sigmoid_graph.stretch_to_fit_width(3)
sigmoid_graph.set_color(YELLOW)
sigmoid_graph.next_to(lisha, UP+LEFT)
sigmoid_graph.shift_onto_screen()
sigmoid_name = TexText("Sigmoid")
sigmoid_name.next_to(sigmoid_graph, UP)
sigmoid_graph.add(sigmoid_name)

slow_learner = TexText("Slow learner")


slow_learner.set_color(YELLOW)
slow_learner.to_corner(UP+LEFT)
slow_arrow = Arrow(
slow_learner.get_bottom(),
sigmoid_graph.get_top(),
)

relu_graph = VGroup(


Line(2*LEFT, ORIGIN),
Line(ORIGIN, np.sqrt(2)*(RIGHT+UP)),
)
relu_graph.set_color(BLUE)
relu_graph.next_to(lisha, UP+RIGHT)
relu_name = TexText("ReLU")
relu_name.move_to(relu_graph, UP)
relu_graph.add(relu_name)

network_mob = NetworkMobject(Network(


sizes = [6, 4, 5, 4, 3, 5, 2]
))
network_mob.scale(0.8)
network_mob.to_edge(UP, buff = MED_SMALL_BUFF)
network_mob.shift(RIGHT)
edge_update = ContinualEdgeUpdate(
network_mob, stroke_width_exp = 1,
)

self.play(


FadeIn(sigmoid_name),
ShowCreation(sigmoid_graph),
lisha.change, "raise_left_hand",
morty.change, "pondering"
)
self.play(
Write(slow_learner, run_time = 1),
GrowArrow(slow_arrow)
)
self.wait()
self.play(
FadeIn(relu_name),
ShowCreation(relu_graph),
lisha.change, "raise_right_hand",
morty.change, "thinking"
)
self.play(FadeIn(network_mob))
self.add(edge_update)
self.wait(10)

###
def create_pi_creatures(self):


morty = Mortimer()
morty.shift(FRAME_X_RADIUS*RIGHT/2).to_edge(DOWN)
lisha = PiCreature(color = BLUE_C)
lisha.shift(FRAME_X_RADIUS*LEFT/2).to_edge(DOWN)
self.morty, self.lisha = morty, lisha
return morty, lisha

class ShowAmplify(PiCreatureScene):


def construct(self):
morty = self.pi_creature
rect = ScreenRectangle(height = 5)
rect.to_corner(UP+LEFT)
rect.shift(DOWN)
email = TexText("3blue1brown@amplifypartners.com")
email.next_to(rect, UP)

self.play(


ShowCreation(rect),
morty.change, "raise_right_hand"
)
self.wait(2)
self.play(Write(email))
self.play(morty.change, "happy", rect)
self.wait(10)

class Thumbnail(NetworkScene):


CONFIG = {
"network_mob_config" : {
'neuron_stroke_color' : WHITE,
'layer_to_layer_buff': 1.25,
},
}
def construct(self):
network_mob = self.network_mob
network_mob.set_height(FRAME_HEIGHT - 1)
for layer in network_mob.layers:
layer.neurons.set_stroke(width = 5)

network_mob.set_height(5)


network_mob.to_edge(DOWN)
network_mob.to_edge(LEFT, buff=1)

subtitle = TexText(


"From the\\\\",
"ground up\\\\",
)
# subtitle.arrange(
# DOWN,
# buff=0.25,
# aligned_edge=LEFT,
# )
subtitle.set_color(YELLOW)
subtitle.set_height(2.75)
subtitle.next_to(network_mob, RIGHT, buff=MED_LARGE_BUFF)

edge_update = ContinualEdgeUpdate(


network_mob,
max_stroke_width = 10,
stroke_width_exp = 4,
)
edge_update.internal_time = 3
edge_update.update(0)

for mob in network_mob.family_members_with_points():


if mob.get_stroke_width() < 2:
mob.set_stroke(width=2)
title = TexText("Neural Networks")
title.scale(3)
title.to_edge(UP)

self.add(network_mob)


self.add(subtitle)
self.add(title)

# Extra

class NeuralNetImageAgain(Scene):
def construct(self):
layers = VGroup()
for length in [16, 16, 16, 10]:
circs = VGroup(*[
Circle(radius=1)
for x in range(length)
])
circs.arrange(DOWN, buff=0.5)
circs.set_stroke(WHITE, 2)
layers.add(circs)
layers.set_height(6.5)
layers.arrange(RIGHT, buff=2.5)

dots = Tex("\\vdots")


dots.move_to(layers[0])
layers[0][:8].next_to(dots, UP, MED_SMALL_BUFF)
layers[0][8:].next_to(dots, DOWN, MED_SMALL_BUFF)

for layer in layers[1:3]:


for node in layer:
node.set_fill(WHITE, opacity=random.random())
layers[3][6].set_fill(WHITE, 0.9)

all_edges = VGroup()


for l1, l2 in zip(layers, layers[1:]):
edges = VGroup()
for n1, n2 in it.product(l1, l2):
edge = Line(
n1.get_center(), n2.get_center(),
buff=n1.get_height() / 2
)
edge.set_stroke(WHITE, 1, opacity=0.75)
# edge.set_stroke(
# color=random.choice([BLUE, RED]),
# width=3 * random.random()**6,
# # opacity=0.5
# )
edges.add(edge)
all_edges.add(edges)

network = VGroup(all_edges, layers, dots)


brace = Brace(network, LEFT)


self.add(network)


self.add(brace)
Download 145,21 Kb.

Do'stlaringiz bilan baham:




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©www.hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish