Finished draft of part1

This commit is contained in:
Grant Sanderson
2017-10-02 12:59:23 -07:00
parent 7f69b6aa93
commit c474207c34
5 changed files with 4925 additions and 48 deletions

View File

@ -63,12 +63,12 @@ RIGHT_SIDE = SPACE_WIDTH*RIGHT
# Change this to point to where you want
# animation files to output
MOVIE_DIR = os.path.join(os.path.expanduser('~'), "Dropbox/3b1b_videos/animations/")
STAGED_SCENES_DIR = os.path.join(MOVIE_DIR, "staged_scenes")
###
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
FILE_DIR = os.path.join(THIS_DIR, "files")
IMAGE_DIR = os.path.join(FILE_DIR, "images")
GIF_DIR = os.path.join(FILE_DIR, "gifs")
STAGED_SCENES_DIR = os.path.join(FILE_DIR, "staged_scenes")
TEX_DIR = os.path.join(FILE_DIR, "Tex")
TEX_IMAGE_DIR = os.path.join(IMAGE_DIR, "Tex")
MOBJECT_DIR = os.path.join(FILE_DIR, "mobjects")

View File

@ -21,13 +21,14 @@ import cPickle
from nn.mnist_loader import load_data_wrapper
NN_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
# PRETRAINED_DATA_FILE = os.path.join(NN_DIRECTORY, "pretrained_weights_and_biases_36")
PRETRAINED_DATA_FILE = os.path.join(NN_DIRECTORY, "pretrained_weights_and_biases")
IMAGE_MAP_DATA_FILE = os.path.join(NN_DIRECTORY, "image_map")
# PRETRAINED_DATA_FILE = "/Users/grant/cs/manim/nn/pretrained_weights_and_biases_on_zero"
# DEFAULT_LAYER_SIZES = [28**2, 36, 10]
DEFAULT_LAYER_SIZES = [28**2, 16, 16, 10]
class Network(object):
def __init__(self, sizes):
"""The list ``sizes`` contains the number of neurons in the
respective layers of the network. For example, if the list
@ -192,12 +193,12 @@ def test_network():
network = get_pretrained_network()
training_data, validation_data, test_data = load_data_wrapper()
n_right, n_wrong = 0, 0
for test_in, test_out in test_data[:30]:
for test_in, test_out in test_data:
if np.argmax(network.feedforward(test_in)) == test_out:
n_right += 1
else:
n_wrong += 1
print float(n_right)/(n_right + n_wrong)
print n_right, n_wrong, float(n_right)/(n_right + n_wrong)
def layer_to_image_array(layer):
w = int(np.ceil(np.sqrt(len(layer))))

4248
nn/part1.py Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -27,6 +27,7 @@ from topics.objects import *
from topics.probability import *
from topics.complex_numbers import *
from topics.graph_scene import *
from topics.common_scenes import *
from scene import Scene
from scene.reconfigurable_scene import ReconfigurableScene
from scene.zoomed_scene import *
@ -529,6 +530,31 @@ class ExampleThrees(PiCreatureScene):
three_mobs.add(three_mob)
return three_mobs
class BrainAndHow(Scene):
def construct(self):
brain = SVGMobject(file_name = "brain")
brain.scale_to_fit_height(2)
brain.set_fill(LIGHT_GREY)
brain_outline = brain.copy()
brain_outline.set_fill(opacity = 0)
brain_outline.set_stroke(BLUE_B, 3)
how = TextMobject("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.dither()
class WriteAProgram(Scene):
def construct(self):
three_array = get_organized_images()[3][0]
@ -608,6 +634,7 @@ class LayOutPlan(TeacherStudentsScene, NetworkScene):
self.show_math()
self.ask_about_layers()
self.show_learning()
self.show_videos()
def show_words(self):
words = VGroup(
@ -722,6 +749,37 @@ class LayOutPlan(TeacherStudentsScene, NetworkScene):
self.play(MoveToTarget(edge_group))
self.dither()
self.learning_word = word
def show_videos(self):
network_mob = self.network_mob
learning = self.learning_word
videos = VGroup(*[
VideoIcon().set_fill(RED)
for x in range(2)
])
videos.scale_to_fit_height(1.5)
videos.arrange_submobjects(RIGHT, buff = LARGE_BUFF)
videos.next_to(self.students, UP, LARGE_BUFF)
network_mob.generate_target()
network_mob.target.scale_to_fit_height(0.8*videos[0].get_height())
network_mob.target.move_to(videos[0])
learning.generate_target()
learning.target.next_to(videos[1], UP)
self.play(
MoveToTarget(network_mob),
MoveToTarget(learning)
)
self.play(
DrawBorderThenFill(videos[0]),
self.get_student_changes(*["pondering"]*3)
)
self.dither()
self.play(DrawBorderThenFill(videos[1]))
self.dither()
class PreviewMNistNetwork(NetworkScene):
CONFIG = {
"n_examples" : 15,
@ -737,6 +795,7 @@ class PreviewMNistNetwork(NetworkScene):
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)
@ -1598,6 +1657,20 @@ class BreakUpMacroPatterns(IntroduceEachLayer):
image_mob.pixel_array[:,:,3] = alpha_vect
return image_mob
class GenerallyLoopyPattern(Scene):
def construct(self):
image_map = get_organized_images()
images = 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.dither(0.2)
self.remove(image)
class HowWouldYouRecognizeSubcomponent(TeacherStudentsScene):
def construct(self):
self.student_says(
@ -2624,6 +2697,7 @@ class IncludeBias(IntroduceWeights):
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()
@ -2657,10 +2731,29 @@ class IncludeBias(IntroduceWeights):
).update(1)
self.add(self.weighted_sum, digit, weight_grid)
self.add_sigmoid_label()
self.digit = digit
self.weight_grid = weight_grid
def add_sigmoid_label(self):
name = TextMobject("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
@ -2702,11 +2795,11 @@ class IncludeBias(IntroduceWeights):
words.next_to(neuron, RIGHT)
self.play(Write(words, run_time = 2))
self.play(LaggedStart(
ApplyMethod, colored_pixels,
lambda p : (p.shift, MED_LARGE_BUFF*UP),
self.play(ApplyMethod(
colored_pixels.shift, MED_LARGE_BUFF*UP,
rate_func = there_and_back,
run_time = 2
run_time = 2,
submobject_mode = "lagged_start"
))
self.dither()
@ -2775,26 +2868,25 @@ class IncludeBias(IntroduceWeights):
return weighted_sum
def add_sigmoid_label(self):
name = TextMobject("Sigmoid")
sigma = self.weighted_sum[0][0]
name.next_to(sigma, UP)
name.to_edge(UP, SMALL_BUFF)
class BiasForInactiviyWords(Scene):
def construct(self):
words = TextMobject("Bias for inactivity")
words.highlight(BLUE)
words.scale_to_fit_width(2*SPACE_WIDTH - 1)
words.to_edge(UP)
arrow = Arrow(
name.get_bottom(), sigma.get_top(),
buff = SMALL_BUFF,
use_rectangular_stem = False,
max_tip_length_to_length_ratio = 0.3
)
self.add(name, arrow)
self.sigmoid_name = name
self.sigmoid_arrow = arrow
self.play(Write(words))
self.dither(3)
class ContinualEdgeUpdate(ContinualAnimation):
CONFIG = {
"max_stroke_width" : 3,
"stroke_width_exp" : 7,
"n_cycles" : 5,
}
def __init__(self, network_mob, **kwargs):
n_cycles = 5
digest_config(self, kwargs)
n_cycles = self.n_cycles
edges = VGroup(*it.chain(*network_mob.edge_groups))
self.move_to_targets = []
for edge in edges:
@ -2802,8 +2894,9 @@ class ContinualEdgeUpdate(ContinualAnimation):
random.choice([GREEN, GREEN, GREEN, RED])
for x in range(n_cycles)
]
msw = self.max_stroke_width
edge.widths = [
3*random.random()**7
msw*random.random()**self.stroke_width_exp
for x in range(n_cycles)
]
edge.cycle_time = 1 + random.random()
@ -3177,7 +3270,6 @@ class IntroduceWeightMatrix(NetworkScene):
self.show_first_neuron_weighted_sum()
self.add_bias()
self.add_sigmoid()
self.dither()
##
def fade_many_neurons(self):
@ -3356,9 +3448,11 @@ class IntroduceWeightMatrix(NetworkScene):
post_bracketes = self.get_brackets(column)
pre_brackets.set_fill(opacity = 0)
self.play(FocusOn(self.a_labels[0]))
self.play(LaggedStart(
Indicate, self.a_labels,
rate_func = there_and_back
rate_func = there_and_back,
run_time = 1
))
self.play(
MoveToTarget(a_labels),
@ -3593,6 +3687,7 @@ class IntroduceWeightMatrix(NetworkScene):
neuron_anims += [
neuron.edges_in.restore
]
neurons.add_to_back(self.network_mob.layers[1].neurons[0])
self.play(ReplacementTransform(
VGroup(
@ -3646,27 +3741,497 @@ class IntroduceWeightMatrix(NetworkScene):
rb.next_to(mob, RIGHT, SMALL_BUFF)
return both
class EoLA3Wrapper(Scene):
class HorrifiedMorty(Scene):
def construct(self):
pass
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.dither(2)
class SigmoidAppliedToVector(Scene):
def construct(self):
tex = TexMobject("""
\\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.scale_to_fit_width(2*SPACE_WIDTH - 1)
tex.to_edge(DOWN)
indices = it.chain(
[0], range(1, 5), range(16, 16+4),
range(25, 25+2), [25+3],
range(29, 29+2), [29+3],
range(33, 33+2), [33+3],
)
for i in indices:
tex[i].highlight(YELLOW)
self.add(tex)
self.dither()
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 = TextMobject("Essence of linear algebra")
title.next_to(rect, UP)
self.play(
ShowCreation(rect),
FadeIn(title),
morty.change, "raise_right_hand", rect
)
self.dither(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.dither(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 = TextMobject("Neuron")
arrow = Arrow(ORIGIN, DOWN, color = BLUE)
thing_words = TextMobject("Thing that holds \\\\ a number")
group = VGroup(neuron_word, arrow, thing_words)
group.arrange_submobjects(DOWN)
group.to_corner(UP+RIGHT, buff = LARGE_BUFF)
neuron = self.network_mob.layers[2].neurons[2]
decimal = DecimalNumber(neuron.get_fill_opacity())
decimal.scale_to_fit_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.dither()
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 = TextMobject("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.dither()
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),
*map(Animation, [neuron, edges, prev_layer])
)
self.play(LaggedStart(
ShowCreationThenDestruction,
edges.copy().set_stroke(YELLOW, 4),
))
self.play(
GrowArrow(arrow),
Transform(self.decimal, decimal)
)
self.dither(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,
submobject_mode = "lagged_start"
)
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 = TextMobject("Network")
network_word.highlight(YELLOW)
network_word.move_to(neuron_word)
func_tex = TexMobject(
"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.dither(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.scale_to_fit_height(0.7)
arrow = Arrow(ORIGIN, RIGHT, color = BLUE)
num_mob = TexMobject(str(num))
group = Group(image, arrow, num_mob)
group.arrange_submobjects(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.dither(2)
for data_mob in data_mobs:
self.add(data_mob)
self.dither(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.scale_to_fit_height(2)
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 = TextMobject("On learning")
words.next_to(video, UP)
if self.edge_update.internal_time < 1:
self.edge_update.internal_time = 2
self.play(
content.scale_to_fit_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.dither(2)
self.play(Write(words))
self.dither(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 = TextMobject(
"Subscribe", "!",
arg_separator = ""
)
bang = subscribe_word[1]
subscribe_word.to_corner(DOWN+RIGHT)
subscribe_word.shift(2*UP)
q_mark = TextMobject("?")
q_mark.move_to(bang, LEFT)
arrow = Arrow(ORIGIN, DOWN, color = RED, buff = 0)
arrow.next_to(subscribe_word, DOWN)
arrow.shift(RIGHT)
self.play(
Write(subscribe_word),
self.video.shift, 3*LEFT,
MoveToTarget(morty),
)
self.play(GrowArrow(arrow))
self.dither(2)
self.play(morty.change, "maybe", arrow)
self.play(Transform(bang, q_mark))
self.dither(3)
def show_video_neural_network(self):
morty = self.pi_creature
network_mob, rect, video, words = self.video
network_mob.generate_target()
network_mob.target.scale_to_fit_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.scale_to_fit_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(LaggedStart(
MoveToTarget, neuron_pairs,
run_time = 3
))
self.play(morty.change, "shruggie")
self.dither(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 Thumbnail(NetworkScene):
CONFIG = {
"network_mob_config" : {
'neuron_stroke_color' : WHITE
}
}
def construct(self):
network_mob = self.network_mob
network_mob.scale_to_fit_height(2*SPACE_HEIGHT - 1)
edge_update = ContinualEdgeUpdate(
network_mob,
max_stroke_width = 10,
stroke_width_exp = 5,
)
edge_update.internal_time = 3
edge_update.update(0)
self.add(network_mob)