# Notebook from donwany/PipeLine.AI
Path: 60_Advanced_TensorFlow/workshops/extras/amld/notebooks/solutions/1_qd_data.ipynb

# Quickdraw Data

If machine learning is rocket science then data is your fuel! So before
doing anything we will have a close look at the data available and spend
some time bringing it into the "right" form (i.e.
[tf.train.Example](https://www.tensorflow.org/versions/r1.0/api_docs/python/tf/train/Example)).

That's why we start by spending quite a lot on this notebook, downloading
the data, understanding it, and transforming it into the right format for
Tensorflow.

The data used in this workshop is taken from Google's quickdraw (click on
the images to see loads of examples):

https://quickdraw.withgoogle.com/data

Table of contents:

- [ 1 Get the data](#1-Get-the-data)
- [ 2 Inspect the data](#2-Inspect-the-data)
- [ 3 Rasterize](#3-Rasterize)
- [ 4 tf.train.Example data format](#4-tf.train.Example-data-format)
- [ 5 Create dataset](#5-Create-dataset)
- [ 6 Prepare dataset for RNN – bonus!](#6-Prepare-dataset-for-RNN-%E2%80%93-bonus!)_____no_output_____

import base64, io, itertools, json, os, random, re, time
import numpy as np
import tensorflow as tf
from matplotlib import pyplot
from PIL import Image, ImageDraw
from IPython import display
from six.moves.urllib import request
from xml.dom import minidom

%matplotlib inline
# Always make sure you are using running the expected version.
# There are considerable differences between versions...
tf.__version_______no_output_____

# 1 Get the data

In this section we download a set of raw data files from the web._____no_output_____

# Retrieve list of classes.

def list_bucket(bucket, regexp='.*'):
    """Returns a (filtered) list of Keys in specified GCE bucket."""
    keys = []
    fh = request.urlopen('https://storage.googleapis.com/%s' % bucket)
    content = minidom.parseString(fh.read())
    for e in content.getElementsByTagName('Contents'):
        key = e.getElementsByTagName('Key')[0].firstChild.data
        if re.match(regexp, key):
            keys.append(key)
    return keys

all_ndjsons = list_bucket('quickdraw_dataset', '.*ndjson$')
print 'available: (%d)' % len(all_ndjsons)
print ' '.join([key.split('/')[-1].split('.')[0] for key in all_ndjsons])available: (309)
The Eiffel Tower The Great Wall of China The Mona Lisa aircraft carrier airplane alarm clock ambulance angel animal migration ant anvil apple arm asparagus axe backpack banana bandage barn baseball bat baseball basket basketball bat bathtub beach bear beard bed bee belt bench bicycle binoculars bird birthday cake blackberry blueberry book boomerang bottlecap bowtie bracelet brain bread bridge broccoli broom bucket bulldozer bus bush butterfly cactus cake calculator calendar camel camera camouflage campfire candle cannon canoe car carrot castle cat ceiling fan cell phone cello chair chandelier church circle clarinet clock cloud coffee cup compass computer cookie cooler couch cow crab crayon crocodile crown cruise ship cup diamond dishwasher diving board dog dolphin donut door dragon dresser drill drums duck dumbbell ear elbow elephant envelope eraser eye eyeglasses face fan feather fence finger fire hydrant fireplace firetruck fish flamingo flashlight flip flops floor lamp flower flying saucer foot fork frog frying pan garden hose garden giraffe goatee golf club grapes grass guitar hamburger hammer hand harp hat headphones hedgehog helicopter helmet hexagon hockey puck hockey stick horse hospital hot air balloon hot dog hot tub hourglass house plant house hurricane ice cream jacket jail kangaroo key keyboard knee knife ladder lantern laptop leaf leg light bulb lighter lighthouse lightning line lion lipstick lobster lollipop mailbox map marker matches megaphone mermaid microphone microwave monkey moon mosquito motorbike mountain mouse moustache mouth mug mushroom nail necklace nose ocean octagon octopus onion oven owl paint can paintbrush palm tree panda pants paper clip parachute parrot passport peanut pear peas pencil penguin piano pickup truck picture frame pig pillow pineapple pizza pliers police car pond pool popsicle postcard potato power outlet purse rabbit raccoon radio rain rainbow rake remote control rhinoceros rifle river roller coaster rollerskates sailboat sandwich saw saxophone school bus scissors scorpion screwdriver sea turtle see saw shark sheep shoe shorts shovel sink skateboard skull skyscraper sleeping bag smiley face snail snake snorkel snowflake snowman soccer ball sock speedboat spider spoon spreadsheet square squiggle squirrel stairs star steak stereo stethoscope stitches stop sign stove strawberry streetlight string bean submarine suitcase sun swan sweater swing set sword syringe t-shirt table teapot teddy-bear telephone
# Store all data locally in this directory.
data_path = '../data'

# Mini group of two animals.
pets = ['cat', 'dog']

# Somewhat larger group of zoo animals.
zoo = ['elephant', 'giraffe', 'kangaroo', 'lion', 'monkey', 'panda',
       'penguin', 'rhinoceros', 'tiger', 'zebra']

# Even larger group of all animals.
animals = ['bat', 'bird', 'butterfly', 'camel', 'cat', 'cow', 'crab',
           'crocodile', 'dog', 'dolphin', 'duck', 'elephant', 'fish',
           'frog', 'giraffe', 'hedgehog', 'horse', 'kangaroo', 'lion',
           'lobster', 'monkey', 'mosquito', 'mouse', 'octopus', 'owl',
           'panda', 'parrot', 'penguin', 'pig', 'rabbit', 'raccoon',
           'rhinoceros', 'scorpion', 'sea turtle', 'shark', 'sheep',
           'snail', 'spider', 'squirrel', 'teddy-bear', 'tiger',
           'whale', 'zebra']

# Create your own group -- the more classes you include the more challenging
# the classification task will be...

# Choose one of above groups for remainder of workshop.
classes, classes_name = zoo, 'zoo'_____no_output_____# Download above chosen group.

def retrieve(bucket, key, filename):
    """Returns a file specified by its Key from a GCE bucket."""
    url = 'https://storage.googleapis.com/%s/%s' % (bucket, key)
    request.urlretrieve(url=url, filename=filename)

if not os.path.exists(data_path):
    os.mkdir(data_path)

print '\n%d classes:' % len(classes),

for name in classes:
    print name,
    dst = '%s/%s.ndjson' % (data_path, name)
    if not os.path.exists(dst):
        retrieve('quickdraw_dataset', 'full/simplified/%s.ndjson' % name, dst)
10 classes: elephant giraffe kangaroo lion monkey panda penguin rhinoceros tiger zebra

# 2 Inspect the data

What is the format of the downloaded files?_____no_output_____

# So let's check out the downloaded files...
!ls $data_pathREADME.md	 kangaroo.ndjson  panda.ndjson	     tiger.ndjson  zoo_stroke
elephant.ndjson  lion.ndjson	  penguin.ndjson     zebra.ndjson
giraffe.ndjson	 monkey.ndjson	  rhinoceros.ndjson  zoo_img
# What is the NDJSON file format?
# Seems to be one JSON dictionary per line...
path = tf.gfile.Glob(os.path.join(data_path, '*.ndjson'))[1]
print file(path).read()[:1000] + '...'{"word":"giraffe","countrycode":"BR","timestamp":"2017-01-26 17:23:19.3785 UTC","recognized":true,"key_id":"5807561943023616","drawing":[[[25,9,0,1,13,35],[32,46,59,65,67,47]],[[64,47,36,25,25,41,53,66,69],[14,15,21,37,42,56,59,41,24]],[[20,39],[8,23]],[[51,52],[0,11]],[[56,46,46,55],[55,91,127,183]],[[74,70,73],[58,95,172]],[[53,79,100,126,149,150,138,131,96,47,39,40],[187,178,174,173,178,190,203,207,215,203,190,182]],[[54,36,22],[204,228,253]],[[73,49],[220,255]],[[118,119,132],[205,223,252]],[[142,143,159],[195,206,238]],[[143,161,165,169,166],[181,168,169,200,214]]]}
{"word":"giraffe","countrycode":"FR","timestamp":"2017-01-29 13:59:05.33086 UTC","recognized":true,"key_id":"5747753718120448","drawing":[[[34,35,45,59,65,67,69,74,79,81,79,81,88,96,99,99,103,101,104,121,129,127,137,151,158,166,163,155,177,198,191,161,115,82,65,56,53,56],[101,249,246,231,218,184,179,179,181,186,220,244,245,230,215,183,199,225,249,255,251,187,203,242,246,225,207,186,148,132,129,133,117,98,85,71,54,20]],...
# Parse single line.
data_json = json.loads(file(path).readline())
data_json.keys()_____no_output_____# So we have some meta information...
for k, v in data_json.iteritems():
    if k != 'drawing':
        print '%20s   ->   %s' % (k, v)                word   ->   giraffe
         countrycode   ->   BR
           timestamp   ->   2017-01-26 17:23:19.3785 UTC
          recognized   ->   True
              key_id   ->   5807561943023616
# ...and the actual drawing.
drawing = data_json['drawing']
# The drawing consists of a series of strokes:
[np.array(stroke).shape for stroke in drawing]_____no_output_____# Draw the image -- the strokes all have have shape (2, n)
# so the first index seems to be x/y coordinate:
for stroke in drawing:
    pyplot.plot(np.array(stroke[0]), -np.array(stroke[1]))
# Would YOU recognize this drawing successfully?_____no_output_____%%time
# Some more code to load many sketches at once.
# Let's ignore the difficult "unrecognized" sketches for now...
# (i.e. unrecognized by the official quickdraw classifier)

def convert(line):
    """Converts single line to JSON + converts 'drawing' to list of np.array."""
    d = json.loads(line)
    d['drawing'] = [np.array(stroke) for stroke in d['drawing']]
    return d

def loaditer(name, unrecognized=False):
    """Returns iterable of drawings in specified file.

    Args:
      name: Name of the downloaded object (e.g. "elephant").
      unrecognized: Whether to include drawings that were not recognized
          by Google AI (i.e. the hard ones).
    """
    for line in open('%s/%s.ndjson' % (data_path, name)):
        d = convert(line)
        if d['recognized'] or unrecognized:
            yield d

def loadn(name, n, unrecognized=False):
    """Returns list of drawings.

    Args:
      name: Name of the downloaded object (e.g. "elephant").
      n: Number of drawings to load.
      unrecognized: Whether to include drawings that were not recognized
          by Google AI (i.e. the hard ones).
    """
    it = loaditer(name, unrecognized=unrecognized)
    return list(itertools.islice(it, 0, n))

print 'loading some "%s"...' % classes[0]
sample = loadn(classes[0], 100)loading some "elephant"...
CPU times: user 10 ms, sys: 100 ms, total: 110 ms
Wall time: 25.5 ms
# Some more drawings...
pyplot.figure(figsize=(10, 10))
n = 3
for x in range(n):
    for y in range(n):
        i = x * n + y
        pyplot.subplot(n, n, i + 1)
        for stroke in sample[i]['drawing']:
            pyplot.plot(np.array(stroke[0]), -np.array(stroke[1]))_____no_output_____

# 3 Rasterize

Idea: After converting the raw drawing data into rasterized images, we can
use [MNIST](https://www.tensorflow.org/get_started/mnist/beginners)-like
image processing to classify the drawings._____no_output_____

%%writefile _derived/1_json_to_img.py
# (Written into separate file for sharing between notebooks.)

# Function that converts drawing (specified by individual strokes)
# to a rendered black/white image.

def json_to_img(drawing, img_sz=64, lw=3, maximize=True):
    img = Image.new('L', (img_sz, img_sz))
    draw = ImageDraw.Draw(img)
    lines = np.array([
        stroke[0:2, i:i+2]
        for stroke in drawing['drawing']
        for i in range(stroke.shape[1] - 1)
    ], dtype=np.float32)
    if maximize:
        for i in range(2):
            min_, max_ = lines[:,i,:].min() * 0.95, lines[:,i,:].max() * 1.05
            lines[:,i,:] = (lines[:,i,:] - min_) / max(max_ - min_, 1)
    else:
        lines /= 1024
    for line in lines:
        draw.line(tuple(line.T.reshape((-1,)) * img_sz), fill='white', width=lw)
    return imgOverwriting _derived/1_json_to_img.py
# (Load code from previous cell -- make sure to have executed above cell first.)
%run -i _derived/1_json_to_img.py

# Show some examples.

def showimg(img):
    if isinstance(img, np.ndarray):
        img = Image.fromarray(img, 'L')
    b = io.BytesIO()
    img.convert('RGB').save(b, format='png')
    enc = base64.b64encode(b.getvalue()).decode('utf-8')
    display.display(display.HTML(
        '' % enc))

# Fetch some images + shuffle order.
rows, cols = 10, 10
n_per_class = rows * cols // len(classes) + 1
drawings_matrix = [loadn(name, rows*cols) for name in classes]
drawings_list = reduce(lambda x, y: x + y, drawings_matrix, [])
drawings_list = np.random.permutation(drawings_list)

# Create mosaic of rendered images.
lw = 4
img_sz = 64
tableau = np.zeros((img_sz * rows, img_sz * cols), dtype=np.uint8)
for y in range(rows):
    for x in range(cols):
        i = y * rows + x
        img = json_to_img(drawings_list[i], img_sz=img_sz, lw=lw, maximize=True)
        tableau[y*img_sz:(y+1)*img_sz, x*img_sz:(x+1)*img_sz] = np.asarray(img)

showimg(tableau)_____no_output_____

# 4 tf.train.Example data format

Tensorflow's "native" format for data storage is the `tf.train.Example`
[protocol buffer](https://en.wikipedia.org/wiki/Protocol_Buffers).

In this section we briefly explore the API needed to access the data
inside the `tf.train.Example` protocol buffer. It's **not necessary** to read
through the
[Python API documentation](https://developers.google.com/protocol-buffers/docs/pythontutorial)._____no_output_____

# Create a new (empty) instance.
example = tf.train.Example()
# (empty example will print nothing)
print example
# An example contains a map from feature name to "Feature".
# Every "Feature" contains a list of elements of the same
# type, which is one of:
# - bytes_list (similar to Python's "str")
# - float_list (float number)
# - int64_list (integer number)

# These values can be accessed as follows (no need to understand
# details):

# Add float value "3.1416" to feature "magic_numbers"
example.features.feature['magic_numbers'].float_list.value.append(3.1416)
# Add some more values to the float list "magic_numbers".
example.features.feature['magic_numbers'].float_list.value.extend([2.7183, 1.4142, 1.6180])

### YOUR ACTION REQUIRED:
# Create a second feature named "adversaries" and add the elements
# "Alice" and "Bob".
example.features.feature['adversaries'].bytes_list.value.extend(['Alice', 'Bob']) #example.features.feature['adversaries'].

# This will now print a serialized representation of our protocol buffer
# with features "magic_numbers" and "adversaries" set...
print example

# .. et voila : that's all you need to know about protocol buffers
# for this workshop.features {
  feature {
    key: "adversaries"
    value {
      bytes_list {
        value: "Alice"
        value: "Bob"
      }
    }
  }
  feature {
    key: "magic_numbers"
    value {
      float_list {
        value: 3.14159989357
        value: 2.71830010414
        value: 1.41419994831
        value: 1.61800003052
      }
    }
  }
}

# 5 Create dataset

Now let's create a "dataset" of `tf.train.Example`
[protocol buffers](https://developers.google.com/protocol-buffers/) ("protos").

A single example contains all the information for a drawing (i.e. rasterized
image, label, and meta information).

A dataset consists of non-overlapping sets of examples that will be used for
training and evaluation of the classifier (the "test" set will be used for the
final evaluation). Because these files can quickly become very large, we
"shard" them into multiple smaller files of equal size._____no_output_____

# Let's first check how many [recognized=True] examples we have in each class.
# Depending on your choice of classes you could generate up to 200k examples...
for name in classes:
    print name, len(list(open('%s/%s.ndjson' % (data_path, name)))), 'recognized', len(list(loaditer(name)))elephant 126969 recognized 104986
giraffe 127182 recognized 122396
kangaroo 174470 recognized 152511
lion 120949 recognized 98976
monkey 127633 recognized 105650
panda 113613 recognized 94814
penguin 253791 recognized 231826
rhinoceros 188484 recognized 166539
tiger 121067 recognized 110177
zebra 144608 recognized 127159
# Helper code to create sharded recordio files.
# (No need to read through this.)

# Well... Since you continue to read through this cell, I could as
# well explain in more detail what it is about :-)
# Because we work with large amounts of data, we will create "sharded"
# files, that is, we split a single dataset into a number of files, like
# train-00000-of-00005, ..., train-00004-of-00005 (if we're using 5 shards).
# This way we have smaller individual files, and we can also easily access
# e.g. 20% of all data, or have 5 threads reading through the data
# simultaneously.

# The code in this cell simply takes a list of iterators and then
# randomly distributes the values returned by these iterators into sharded
# datasets (e.g. a train/eval/test split).

def rand_key(counts):
    """Returns a random key from "counts", using values as distribution."""
    r = random.randint(0, sum(counts.values()))
    for key, count in counts.iteritems():
        if r > count or count == 0:
            r -= count
        else:
            counts[key] -= 1
            return key

def make_sharded_files(make_example, path, classes, iters, splits,
                       shards=10, overwrite=False, report_dt=10):
    """Create sharded files from "iters".

    Args:
      make_example: Converts object returned by elements of "iters"
          to tf.train.Example() proto.
      path: Directory that will contain recordio files.
      classes: Names of classes, will be written to "labels.txt".
      splits: Dictionary mapping filename to number of examples (of
          every class).
      shards: Number of files to be created per split.
      overwrite: Whether a pre-existing directory should be overwritten.
      report_dt: Number of seconds between status updates (0=no updates).

    Returns:
      Total number of examples written to disk (this should be equal to
      the number of classes times the sum of the number of examples of
      all the splits).
    """
    assert len(iters) == len(classes)
    if not os.path.exists(path):
        os.makedirs(path)
    paths = {
        split: ['%s/%s-%05d-of-%05d' % (path, split, i, shards)
                for i in range(shards)]
        for split in splits
    }
    assert overwrite or not os.path.exists(paths.values()[0][0])
    writers = {
        split: [tf.python_io.TFRecordWriter(ps[i]) for i in range(shards)]
        for split, ps in paths.iteritems()
    }
    t0 = time.time()
    n = sum(splits.values())
    examples = 0
    for i in range(n):
        split = rand_key(splits)
        writer = writers[split][splits[split] % shards]
        for j in range(len(classes)):
            example = make_example(j, iters[j].next())
            writer.write(example.SerializeToString())
            examples += 1
        remaining = sum(splits.values())
        if report_dt > 0 and time.time() - t0 > report_dt:
            print 'processed %d/%d (%.2f%%)' % (i, n, 100. * i / n)
            t0 = time.time()
    for split in splits:
        for writer in writers[split]:
            writer.close()
    with open('%s/labels.txt' % path, 'w') as f:
        f.write('\n'.join(classes))
    return examples_____no_output_____%%writefile _derived/1_make_example_img.py
# (Written into separate file for sharing between notebooks.)

# Convert drawing tf.train.Example proto.
# Uses json_to_img() from previous cell to create raster image.

def make_example_img(label, drawing):
    example = tf.train.Example()
    example.features.feature['label'].int64_list.value.append(label)
    img_64 = np.asarray(json_to_img(drawing, img_sz=64, lw=4, maximize=True)).reshape(-1)
    example.features.feature['img_64'].int64_list.value.extend(img_64)
    example.features.feature['countrycode'].bytes_list.value.append(drawing['countrycode'].encode())
    example.features.feature['recognized'].int64_list.value.append(drawing['recognized'])
    example.features.feature['word'].bytes_list.value.append(drawing['word'].encode())
    ts = drawing['timestamp']
    ts = time.mktime(time.strptime(ts[:ts.index('.')], '%Y-%m-%d %H:%M:%S'))
    example.features.feature['timestamp'].int64_list.value.append(long(ts))
    example.features.feature['key_id'].int64_list.value.append(long(drawing['key_id']))
    return exampleWriting _derived/1_make_example_img.py
# (Load code from previous cell -- make sure to have executed above cell first.)
%run -i _derived/1_make_example_img.py

# Create the (rasterized) dataset.

path = '%s/dataset_img' % data_path
t0 = time.time()
n = make_sharded_files(
    make_example=make_example_img,
    path=path,
    classes=classes,
    iters=[loaditer(name) for name in classes],
    # Note: We only generate few examples here so you won't be
    # blocked for too long while waiting for this cell to finish.
    # You can re-run the cell with larger values (don't forget to
    # update "path" above) in the background to get a larger
    # dataset...
    splits=dict(train=5000, eval=1000, test=1000),
)

print 'stored data to "%s"' % path
print 'generated %d examples in %d seconds' % (n, time.time() - t0)processed 513/7000 (7.33%)
processed 1050/7000 (15.00%)
processed 1557/7000 (22.24%)
processed 2059/7000 (29.41%)
processed 2583/7000 (36.90%)
processed 3140/7000 (44.86%)
processed 3690/7000 (52.71%)
processed 4199/7000 (59.99%)
processed 4738/7000 (67.69%)
processed 5292/7000 (75.60%)
processed 5637/7000 (80.53%)
processed 5930/7000 (84.71%)
processed 6261/7000 (89.44%)
processed 6721/7000 (96.01%)
stored data to "../data/dataset_img"
generated 70000 examples in 145 seconds

# 6 Prepare dataset for RNN – bonus!

This section creates another dataset of example protos that contain the raw
stroke data, suitable for usage with a recurrent neural network.

Note that later notebooks will have a "bonus" section that uses this dataset,
but the "non-bonus" parts can be worked through without executing below
cells..._____no_output_____

%%writefile _derived/1_json_to_stroke.py
# (Written into separate file for sharing between notebooks.)

# Convert stroke coordinates into normalized relative coordinates,
# one single list, and add a "third dimension" that indicates when
# a new stroke starts.

def json_to_stroke(d):
    norm = lambda x: (x - x.min()) / max(1, (x.max() - x.min()))
    xy = np.concatenate([np.array(s, dtype=np.float32) for s in d['drawing']], axis=1)
    z = np.zeros(xy.shape[1])
    if len(d['drawing']) > 1:
        z[np.cumsum(np.array(map(lambda x: x.shape[1], d['drawing'][:-1])))] = 1
    dxy = np.diff(norm(xy))
    return np.concatenate([dxy, z.reshape((1, -1))[:, 1:]])Writing _derived/1_json_to_stroke.py
# (Load code from previous cell -- make sure to have executed above cell first.)
%run -i _derived/1_json_to_stroke.py

# Visualize / control output of json_to_stroke().

stroke = json_to_stroke(sample[3])
# First 2 dimensions are normalized dx/dy coordinates
# third dimension indicates "new stroke".
xy = stroke[:2, :].cumsum(axis=1)
pyplot.plot(*xy)
pxy = xy[:, stroke[2] != 0]
pyplot.plot(pxy[0], pxy[1], 'ro')_____no_output_____%%writefile _derived/1_make_example_stroke.py
# (Written into separate file for sharing between notebooks.)

# Convert drawing tf.train.Example proto.
# Uses json_to_stroke() from previous cell to create raster image.

def make_example_stroke(label, drawing):
    example = tf.train.Example()
    example.features.feature['label'].int64_list.value.append(label)
    stroke = json_to_stroke(drawing)
    example.features.feature['stroke_x'].float_list.value.extend(stroke[0, :])
    example.features.feature['stroke_y'].float_list.value.extend(stroke[1, :])
    example.features.feature['stroke_z'].float_list.value.extend(stroke[2, :])
    example.features.feature['stroke_len'].int64_list.value.append(stroke.shape[1])
    example.features.feature['countrycode'].bytes_list.value.append(drawing['countrycode'].encode())
    example.features.feature['recognized'].int64_list.value.append(drawing['recognized'])
    example.features.feature['word'].bytes_list.value.append(drawing['word'].encode())
    ts = drawing['timestamp']
    ts = time.mktime(time.strptime(ts[:ts.index('.')], '%Y-%m-%d %H:%M:%S'))
    example.features.feature['timestamp'].int64_list.value.append(long(ts))
    example.features.feature['key_id'].int64_list.value.append(long(drawing['key_id']))
    return exampleWriting _derived/1_make_example_stroke.py
# (Load code from previous cell -- make sure to have executed above cell first.)
%run -i _derived/1_make_example_stroke.py

# Create the (stroke) dataset.

path = '%s/dataset_stroke' % data_path
t0 = time.time()
n = make_sharded_files(
    make_example=make_example_stroke,
    path=path,
    classes=classes,
    iters=[loaditer(name) for name in classes],
    splits=dict(train=50000, eval=10000, test=10000),
)

print 'stored examples to "%s"' % path
print 'generated %d examples in %d seconds' % (n, time.time() - t0)processed 2327/70000 (3.32%)
processed 4688/70000 (6.70%)
processed 7048/70000 (10.07%)
processed 9359/70000 (13.37%)
processed 11632/70000 (16.62%)
processed 13902/70000 (19.86%)
processed 16119/70000 (23.03%)
processed 18376/70000 (26.25%)
processed 20768/70000 (29.67%)
processed 23116/70000 (33.02%)
processed 25435/70000 (36.34%)
processed 27738/70000 (39.63%)
processed 30097/70000 (43.00%)
processed 32440/70000 (46.34%)
processed 34718/70000 (49.60%)
processed 37030/70000 (52.90%)
processed 39334/70000 (56.19%)
processed 41703/70000 (59.58%)
processed 43874/70000 (62.68%)
processed 46054/70000 (65.79%)
processed 47988/70000 (68.55%)
processed 49686/70000 (70.98%)
processed 50680/70000 (72.40%)
processed 51709/70000 (73.87%)
processed 53728/70000 (76.75%)
processed 55087/70000 (78.70%)
processed 56160/70000 (80.23%)
processed 57815/70000 (82.59%)
processed 59451/70000 (84.93%)
processed 60503/70000 (86.43%)
processed 61686/70000 (88.12%)
processed 63619/70000 (90.88%)
processed 64625/70000 (92.32%)
processed 65865/70000 (94.09%)
processed 68018/70000 (97.17%)
processed 69080/70000 (98.69%)
stored examples to "../data/dataset_stroke"
generated 700000 examples in 369 seconds


# Notebook from bmorris3/birthmarks
Path: abc/m67.ipynb

<code>
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import astropy.units as u
from fleck import generate_spots, Star as Stars
from scipy.stats import ks_2samp, anderson_ksamp_____no_output_____amps_fast = 100 * np.load('../smamps/data/m67_amps.npy')_____no_output_____plt.hist(np.log10(amps_fast))//anaconda3/lib/python3.7/site-packages/numpy/lib/histograms.py:824: RuntimeWarning: invalid value encountered in greater_equal
  keep = (tmp_a >= first_edge)
//anaconda3/lib/python3.7/site-packages/numpy/lib/histograms.py:825: RuntimeWarning: invalid value encountered in less_equal
  keep &= (tmp_a <= last_edge)
ld = [0.5079, 0.2239]
stars = Stars(spot_contrast=0.7, n_phases=30, u_ld=ld)
n_inclinations = 50
spot_radius = 0.2
n_spots = 3
# min_smoothed_amp = 0.01336
stars = Stars(spot_contrast=0.7, n_phases=30, u_ld=ld)_____no_output_____def ad(spot_radius, max_latitude, spot_contrast):
    stars.spot_contrast = spot_contrast
    lons, lats, rads, incs = generate_spots(min_latitude=-max_latitude, max_latitude=max_latitude, n_spots=n_spots,
                                            spot_radius=spot_radius, n_inclinations=n_inclinations)
    lcs = stars.light_curve(lons, lats, rads, incs)
    smoothed_amps = 100 * lcs.ptp(axis=0)
#     smoothed_amps = smoothed_amps[smoothed_amps > min_smoothed_amp]
    if len(smoothed_amps) < 1:
        anderson_stat = 100
    else:
        anderson_stat = anderson_ksamp([np.log10(smoothed_amps), np.log10(amps_fast)]).statistic
    return anderson_stat

n_steps = 50000
init_rad = 0.23
init_max_lat = 70
init_contrast = 0.7_____no_output_____p_values = [ad(init_rad, init_max_lat, init_contrast)]
spot_radii = [init_rad]
max_lats = [init_max_lat]
spot_contrasts = [init_contrast]
steps = 0
accepted_step = 0//anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:11: UserWarning: p-value floored: true value smaller than 0.001
  # This is added back by InteractiveShellApp.init_path()
while accepted_step < n_steps:
#     if steps > 0 and steps % 100 == 0:
#         print(accepted_step, accepted_step/steps)
    spot_radius = 0.05 * np.random.randn() + spot_radii[accepted_step]
    max_lat = 5*np.random.randn() + max_lats[accepted_step]
    spot_contrast = 0.1*np.random.randn() + spot_contrasts[accepted_step]

    # Apply prior
    if 0 < spot_radius < 1 and 0 < max_lat < 90 and 0 < spot_contrast < 1:
        adstat = ad(spot_radius, max_lat, spot_contrast)

        steps += 1
        if adstat < 5:
            # Accept step
            spot_radii.append(spot_radius)
            max_lats.append(max_lat)
            spot_contrasts.append(spot_contrast)
            p_values.append(adstat)
            accepted_step += 1//anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:11: RuntimeWarning: divide by zero encountered in log10
  # This is added back by InteractiveShellApp.init_path()
//anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:11: UserWarning: p-value floored: true value smaller than 0.001
  # This is added back by InteractiveShellApp.init_path()
//anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:11: UserWarning: p-value capped: true value larger than 0.25
  # This is added back by InteractiveShellApp.init_path()
print('acceptance rate:', accepted_step/steps)acceptance rate: 0.23226645607841315
fig, ax = plt.subplots(3, 1, figsize=(14, 10), sharex=True)
ax[0].plot(spot_radii, marker=',', lw=1)
ax[1].plot(max_lats, marker=',', lw=1)
ax[2].plot(spot_contrasts, marker=',', lw=1)
# ax[3].plot(p_values, marker=',', lw=0)

titles = ['R', '$\ell_{min}$', "C", '']
for axis, title in zip(ax, titles):
    axis.set_ylabel(title)
ax[-1].set_xlabel('Step')
fig.tight_layout()
# ax[2].set_ylim([-2, 3])_____no_output_____from corner import corner

fig, ax = plt.subplots(3, 3, figsize=(5, 5))
samples = np.array([max_lats, spot_radii, spot_contrasts]).T
corner(samples, labels='$\\rm\ell_{max}$ $\\rmR_{spot}/R_{star}$ $c$'.split(), smooth=True, fig=fig);
# fig.tight_layout()
plt.savefig('plots/corner_m67.pdf', bbox_inches='tight')_____no_output_____np.save('data/m67_samples.npy', samples)_____no_output_____
</code>


# Notebook from duke-mlss/Duke-Tsinghua-MLSS-2017
Path: 00C_Git_Basics.ipynb

# Git Basics_____no_output_____The recommendation for this course is to fork this repo, take any notes/do the assignment in your fork, add the original as a remote, and regularly pull any changes that I upload to the main repo. If you understand what all that means and know how to do it, you can probably skip the rest of this notebook. If not, read on!_____no_output_____## Introduction

Git is a popular form of version control. When used properly, Git allows you to track the evolution of your files over time and eliminates the need to keep multiple copies of the same code when experimenting with breaking changes. For example, you can see the history of how the materials for this workshop were prepared [here](https://github.com/kevinjliang/Duke-Tsinghua-MLSS-2017/commits/master). Git is also an effective way to coordinate the collaboration of multiple users working on the same code base. I've chosen to put the materials of this TensorFlow workshop in a [GitHub repository](https://github.com/kevinjliang/Duke-Tsinghua-MLSS-2017) to facilitate getting this material out to the Duke-Tsinghua MLSS class, while also making it easy to send out any updates to these lecture materials._____no_output_____## Installation

If you don't already use Git or have it installed, I highly recommend it integrating it into your workflow, not just for this workshop, but for your class work, work work, or research. Follow the instructions corresponding to your operating system.

### Ubuntu

There's a good chance you already have Git installed. Check first by typing into your command line:

```Shell
git --version
```

If you get a `"git: command not found"`, Git can be easily installed with:

```Shell
sudo apt-get install git
```

Once installed, Git commands can be typed directly into the command line.

### Windows

If you're on Windows and you don't remember installing Git, you probably don't have it. Download Git for Windows [here](https://git-for-windows.github.io/), run the set-up .exe, and follow the instructions. If you're unsure, stick to the default settings.

If you chose the default installation options, you should now have Git BASH installed, a Linux/Unix style BASH emulator. See the explanation of `git status` for a screenshot of what it looks like. Git commands can be typed directly into this shell.

### Mac OS X

First, check if you have Git installed already by typing the following into a Terminal:

```Shell
git --version
```

Download Git [here](https://git-scm.com/download/mac) and follow the instructions for installation. If you're unsure, stick to the default settings.

You can verify your installation by typing `git --version` again into your terminal.

### GUI versions of Git (optional)

If command lines make you nervous, there are lots of free Git GUIs out there. If you'd rather use a GUI, you're free to download whichever you like, but as a recommendation, I personally like using [Atlassian's SourceTree](https://www.sourcetreeapp.com/):

![sourcetree](Figures/sourcetree.PNG)

The rest of this notebook is written for command line Git, but the concepts for Git with a GUI are the same, so if you're unfamiliar with Git, read on and try to find the matching buttons in your GUI._____no_output_____## Usage for this class

Git is capable of quite a bit, and learning all the commands available would both take too long and be total overkill for this workshop. If you want to understand the commands you're about to type, read the next section (**Important Commands and Terminology to Know**) first, but if you just want to get up and going:

#### Fork and clone
1. Go to [the class's repo](https://github.com/kevinjliang/Duke-Tsinghua-MLSS-2017) and click "Fork" in the upper right corner:
![mlss_repo_fork](Figures/mlss_repo_fork.png)

2. If you don't have an account, make one at the prompt. If you have one already, sign in.

3. You should arrive at the page of your shiny new fork of the class repository. Click on the green "Clone or download" button on the right side of the page.
![mlss_repo_clone](Figures/mlss_repo_clone.PNG)
Copy the HTTPS, and in your command line/Git Bash, enter the following:
```Shell
git clone [PASTE_HTTPS_HERE]
```

That's it! You now have a local copy of the class Git repo to play around with.

#### Committing changes and pushing
Throughout the class, feel free to modify any of the files however you want (e.g. to take notes); in fact, for the homework, you'll have to modify files. Any time you want to make a checkpoint of your files, you do that by commiting and pushing your changes. To do that:

1. Check your changes. This isn't a required step, but always recommend:
```Shell
git status
```
2. Stage the changes you want to commit. For example, to add your changes for your homework:
```Shell
git add 01B_MLP_CNN_Assignment.ipynb
```
3. Commit your changes, adding a commit message at the same time:
```Shell
git commit -m "Yay, finished the homework"
```
4. Push your changes to your fork:
```Shell
git push
```
You'll be asked to verify your usename and password, and assuming you type those in correctly, your changes should appear on your GitHub page.

#### Pulling updates
I may occasionally make updates to the materials in this repository. You can sync your fork to mine by first adding the main repo as a remote (you only have to do this once), and then doing a pull:

1. Add the main repo as a remote (only do this once):
```Shell
git remote add kevinjliang https://github.com/kevinjliang/Duke-Tsinghua-MLSS-2017
```
2. Pull from the upstream repo to sync:
```Shell
git pull kevinjliang
```_____no_output_____## Important Commands and Terminology to Know

My personal philosophy with Git commands is the same as with Linux/Unix commands: learn the basic commands that you use for 95% of your workflow, be generally aware of what other stuff is possible, and Google what you don't know (or don't remember). Here are some concepts to know:

### Repository (Repo)

A repository is a data structure that holds all the metadata of which files to track, a historical record of changes, commit objects, etc. All files in the root directory and any subdirectories can be tracked by the repo.

The repository on your machine that you work in is your local repository. When working in a collaborative setting, we also keep a copy of our code on a remote server (for example, provided by GitHub). Usually, I treat this remote copy as the "official" or "master" version of the code, and the local copy as my working copy. We interact with this remote repo through pushing and pulling, which are explained below.

### GitHub

A web-based version of Git that allows you browse, search, and host Git repositories. If you don't already have an account, you should [sign up](https://github.com/) for one; it's free, and you'll need it to fork this repo. GitHub provides a lot of really cool features, so I'd recommend exploring it on your own time when you get the chance. The materials for this workshop are hosted in [this GitHub repository](https://github.com/kevinjliang/Duke-Tsinghua-MLSS-2017).

### Fork

A way to create your own copy of someone else's repo, under your username. Unless you are the owner or listed as a collaborator for a repo, you won't have the ability to make any changes to the code. Forking creates a personal copy where you are the owner; thus it's good for playing around with someone else's code, using an existing repository as a starting point for your own project, or for class settings like this.

### Clone (`git clone`)

Creates a local copy of a Git repository on your machine. The repo's directory will be like any other directory on your computer, but you'll have the ability to use the various git commands. To clone:

```Shell
git clone [REPOSITORY_LINK]
```

### Status (`git status`)

Shows which files have changed since the latest commit, which changes have been staged, your current branch, and other useful things.

```Shell
git status
```

Produces something like:

![git_status](Figures/git_status.PNG)

### Stage (`git add`)

Marks a change as one to be included in a commit. This allows you to choose which files to include:

```Shell
git add [FILES_TO_ADD_SEPARATED_BY_SPACES]
```

Why not add all files? Generally, you want your commit history to tell a story of your development. As such, each commit should aim to capture one major change or added feature, even if you're working on multiple things at once. Also, sometimes, you're not ready to push a certain change yet. For example, although I want to be able to test the homework solutions to make sure they work, I don't quite want to publish them yet.

If you do find yourself wanting to stage everything though (which does happen quite often), you can do that with the following additional flag:

```Shell
git add -A
```

### Commit (`git commit`)

Saves your staged changes to the repository. This is how you add an entry to your Git commit history. Typically, it's useful to include a short summary of what is encapsulated in the commit. Typing the command `git commit` will get the job done, but it'll take you to a `vim` editor to type your message, which can be jarring if you're unfamiliar with `vim`. For larger projects with many collaborators, writing very descriptive commit messages is important, and you should absolutely learn to use the editor to write effective messages. For personal use though, it can be a bit much. Instead, I like to use the following shortcut:

```Shell
git commit -m "[YOUR_COMMIT_MESSAGE_HERE]"
```

This commits your changes and saves your commit message in one line.

### Pull (`git pull`)

Fetches any new changes from the remote server and merges them with your local copy of the repo. This'll be helpful for receiving any of the changes I make to the course materials.

```Shell
git pull
```

If you cloned your own repo from GitHub, this automatically point to that remote's repository. You can add other remotes to pull from with the following:

```Shell
git remote add [REMOTE_NAME] [REMOTE_REPOSITORY_LINK]
```

You can then pull from one of the other remotes:

```Shell
git pull [REMOTE_NAME]
```

**Warning: You should make sure your changes are not only saved but also committed before trying to pull. Accidentally clobbering all your hard work is a very painful and all-too-common mistake when it comes to version control systems.**

### Push (`git push`)

Shares your commits with a remote repository. Note, you must first make sure your local repo is synced with the remote before you push and resolve any of the change conflicts that exist.

```Shell
git push
```

By default, if you cloned your own repo from GitHub, push should point to your remote repository._____no_output_____## Other tutorials and resources

- A virtual sandbox to play with git commands: https://try.github.io/levels/1/challenges/1
- Git tutorial: https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository
- Git reference guide: https://git-scm.com/docs_____no_output_____


# Notebook from shwars/DigiArt4Teens
Path: MakeArt.ipynb

# Creating Your Own Cognitive Portrait

Hello!

We are about to explore **Science Art**, where **Science** - namely **Artificial Intelligence**, part of **Computer Science** - will help us create pieces of **Art**! Namely, we will learn the technique called [Cognitive Portrait](http://bit.do/cognitiveportrait)

In this technique, we use **[Microsoft Face API](https://docs.microsoft.com/azure/cognitive-services/face/overview/?wt.mc_id=digigirlz-event-dmitryso)** to extract **Facial Landmarks** from a series of pictures, and then we scale and align pictures in such a way that eyes on all pictures coincide. Merging those photographs, we create an interesting visual effect, like on the photo above. _____no_output_____### Using Python and Azure Notebook

To create a portrait, we will use a programming language called **Python**. Do not worry, to create your own portrait you do not even need to know programming - you need to execute existing code. But you need to be **very attentive and accurate**.

However, if you know programming or want to learn, you would eventually be able to create much more interesting visual effects. The best way to learn Python is by following [this course](http://pythontutor.ru).

The document that you see contains **text cells** (you are reading one of them now) **code cells** with Python code - they have `In [..]` printed to the left of the cell. Code cells can be **executed**, by pressing **RUN** button in the toolbar above, or keys **Ctrl-Enter**. After the cell executes, you will see the result directly below it. Try to execute the cell below, where we calculate the number of seconds in a day: _____no_output_____

24*60*60_____no_output_____

To create a portrait we need to execute a number of cells with code. You need to do it step by step, sequentially, waiting for the previous cell to finish execution. While cell is being executed, you see `In [*]` to the left of it, and when it is done - star `*` is replaced by a number, showing the order in which the cell has been executed.

We are also trying to describe what is happening in each cell. Try to understand it, but if you don't - that's fine. You should be able to get the portrait anyway._____no_output_____### Installing Required Libraries

In Python, many complex things are accomplished by using **libraries** - pieces of code that someone else has created for you. For example, to manipulate images we will use **OpenCV** library, and we also need library to use **Microsoft Face API**. To use libraries, we need to:

* **install** those libraries, i.e. download their code from the repository where they are stored. This is done using `pip` command. We need to do it once before we start working with a notebook
* **import** them into our program, so that Python sees all required functions

The following cell will install required libraries. **IMPORTANT**: it can take a few minutes to execute, and you need to wait for it to finish. You may also see a **WARNING** -- do not worry, it is normal._____no_output_____

import sys
!{sys.executable} -m pip install --quiet opencv-python azure-cognitiveservices-vision-face_____no_output_____import os, requests, glob
import cv2
import matplotlib.pyplot as plt
import numpy as np_____no_output_____

### Extracting Facial Landmarks

To extract facial landmarks, we use [Microsoft Face API](https://azure.microsoft.com/services/cognitive-services/face/?wt.mc_id=digigirlz-event-dmitryso). It will give us a lot of extra useful information, including gender, age, head's angles of rotation, emotions, makeup, accessories. The following facial landmarks are extracted:

![Facial Landmarks](https://raw.githubusercontent.com/shwars/FaceArt/master/notebooks/img/landmarks.jpg)

To read more about Face API and how to use it from different programming languages, [visit Microsoft Docs](https://docs.microsoft.com/ru-ru/azure/cognitive-services/face/index/?wt.mc_id=digigirlz-event-dmitryso)._____no_output_____To use Face API we need a special **key**, and also so-called **Endpoint URL** which is used to call the service. To get it, you need to have **Microsoft Azure Account**, and **Create Cognitive Service** resource there which will give you access information.

The easiest ways to get Azure Account are the following:
* If you are a student, get [Azure for Students](http://aka.ms/az4stud). You would need to verify your student status via university e-mail account.
* You can also apply for [GitHub Student Developer Pack](https://education.github.com/pack) that gives you access to several free resources for student developers, including Azure. You need to verify your status using university e-mail or a supporting document.
* Anyone can apply for [Azure Free Trial](http://aka.ms/azfree).

Having created your account, you need to create Cognitive Servies recourse through [Azure Portal](http://portal.azure.com/?WT.mc_id=digigirlz-event-dmitryso) as [described here](https://docs.microsoft.com/azure/cognitive-services/cognitive-services-apis-create-account?tabs=multiservice%2Cwindows&WT.mc_id=digigirlz-event-dmitryso)

After that, you need to copy one of two provided **keys** (a sequence of numbers) and **endpoint URL** (which looks like internet address) to the cell below: _____no_output_____

key = '--INSERT YOUR KEY HERE--' # key looks similar to this: 'e408f9b7c8e349ee8f5567dbea67df30'
endpoint = 'https://westus2.api.cognitive.microsoft.com' # please make sure to copy correct endpoint URL as well_____no_output_____

**IMPORTANT**: Endpoint URL provided for you on the web site looks like this: `https://westus2.api.cognitive.microsoft.com/api/face/1.0`. You need to remove the trailing part of the address `/api/face/1.0`, and leave just the server address. If you fail to do it, you will get an error._____no_output_____If you have copied everything correctly, after executing the following cell you will see the result of processing this photograph:

_____no_output_____

import azure.cognitiveservices.vision.face as cf
from msrest.authentication import CognitiveServicesCredentials
cli = cf.FaceClient(endpoint,CognitiveServicesCredentials(key))
face_url = 'https://2016.dotnext-piter.ru/assets/images/people/soshnikov.jpg'
res = cli.face.detect_with_url(face_url,return_face_landmarks=True)
print(res[0].face_landmarks.as_dict())_____no_output_____

**IMPORTANT**: You should see the coordinates of facial landmarks. If you do not see them - make sure you have copied the keys correctly. You need to make this cell working right, otherwise nothing will work. Go ahead only after you see the facial landmarks with coordinates like this:
```
{'eye_right_bottom': {'x': 172.7, 'y': 123.5}, 'eye_right_inner': {'x': 162.7, 'y': 120.8}, ... }
```_____no_output_____### Uploading Your Own Images

For experiments, we need our own portrait pictures. To create your portrait, you need to place a few (5 to 15, but no more than 20) your photographs into `images` directory of this notebook. For your convenience, this directory aleady contains a couple of photographs - feel free to delete them, if you do not want to mix them into the portrait. You can also leave them :)

It is best to take pictures that contain only your face in different settings/surroundings. If several faces are detected in one picture, our code will take any one of them, and thus if there are more people it may mix them into the portrait instead of you.

To upload images, you need to switch to previous browser tab, which contains all files for our notebook library. Then follow the steps (indicated also by digits in the picture below):

1. Go to `images` directory -- list of files should change to reflect a couple of existing pictures
2. Press upload button (with arrow) in the right corner and select **Upload from Computer**
3. A window will open. Drag the files from explorer/finder on your computer to this window, or press **Choose Files** button and select required files from your computer
4. After you do it, you should see the list of files below in the windows
5. Place check mark next to **I trust the contents of those files**
6. Press **Upload**
7. After uploading, the Upload button will change to **Done**, press it once more.

|![Upload Screen 1](.img/Upload1.PNG) | ![Upload Screen 2](.img/Upload2.PNG) |
| ---| ----|
_____no_output_____Once we have uploaded the photographs, let's see how Face API handles them:_____no_output_____

def imread(fn):
    im = cv2.imread(fn)
    return cv2.cvtColor(im,cv2.COLOR_BGR2RGB) if im is not None else None_____no_output_____fn = glob.glob('images/*')[0]
print('Analyzing image: ',fn)

img = imread(fn)
cli.face.detect_with_url(face_url)
with open(fn,'rb') as f:
    res = cli.face.detect_with_stream(f,return_face_landmarks=True)
for k,v in res[0].face_landmarks.as_dict().items():
    cv2.circle(img,(int(v['x']),int(v['y'])),7,(255,255,0),5)
plt.imshow(img)_____no_output_____

If you see an error in the cell above - it probably means that Face API did not find a face on the picture. You should try to use better pictures.

For our experiments, let's run all our faces through the Face API to get the landmarks. We will store images into `images` list, and landmarks - into `imagepoints`.

**Important**: Trial Face API key allows you to process only 20 requests per minute. Thus, if you want to process more than 20 pictures with trial key, you would need to make code a bit more complex, adding some delay between calls._____no_output_____

filenames = []
images = []
imagepoints = []
cli.face.detect_with_url(face_url)
for fn in glob.glob("images/*")[0:20]:
    print("Processing image {} ".format(fn),end='')
    try:
        with open(fn,'rb') as f:
            res = cli.face.detect_with_stream(f,return_face_landmarks=True)
    except:
        print(' - ERROR - ',end='')
        res = []
    print(' {} faces found'.format(len(res)))
    if len(res)>0:
        filenames.append(fn)
        images.append(imread(fn))
        imagepoints.append(res[0].face_landmarks.as_dict())_____no_output_____

**IMPORTANT**: If you see **ERROR** message, it means that Face API could not understand your photo. It is possible that picture is too big (Face API has some limit on image size), or format is not supported. Try to make the image smaller and upload it again. However, if there are a few errors - it does not matter, those pictures are just ignored, it is important to make sure that we have at least 3-5 faces that were recognized correctly._____no_output_____Let's see a few of loaded photographs:_____no_output_____

def display_images(l):
    n=len(l)
    fig,ax = plt.subplots(1,n)
    for i,im in enumerate(l):
        ax[i].imshow(im)
        ax[i].axis('off')
    fig.set_size_inches(fig.get_size_inches()*n)
    plt.tight_layout()
    plt.show()

display_images(images[:5])_____no_output_____

## Affine Transformations

To align all images according to their eyes, we need to scale, move and rotate them in some way. To do that, we use mathematical concept of [**affine transformation**](https://ru.wikipedia.org/wiki/Affine_transformation). You do not need to understand the details, the important thing is to know that we can use some **math magic** to align three given points in an image with any other three points. We will align coordinate of 2 eyes and middle of the mouth with three predefined points.

Magic function to do this alignment will look like this:_____no_output_____

target_triangle = np.float32([[130.0,120.0],[170.0,120.0],[150.0,160.0]])
size = 300

def affine_transform(img,attrs):
    mc_x = (attrs['mouth_left']['x']+attrs['mouth_right']['x'])/2.0
    mc_y = (attrs['mouth_left']['y'] + attrs['mouth_right']['y']) / 2.0
    tr = cv2.getAffineTransform(np.float32([(attrs['pupil_left']['x'],attrs['pupil_left']['y']),
                                            (attrs['pupil_right']['x'],attrs['pupil_right']['y']),
                                            (mc_x,mc_y)]), target_triangle)
    return cv2.warpAffine(img,tr,(size,size))_____no_output_____

Let's align all photos:_____no_output_____

img_aligned = [affine_transform(i,a) for i,a in zip(images,imagepoints)]
display_images(img_aligned[:5])_____no_output_____

## Merging the Images

To get the result, we need to merge those image together. It is not a difficult task, be we will create powerful merging function that will also allow to set different weights for each image, and to generate random weights. Let's see how first two pictures are mixed together:
_____no_output_____

def merge(images,wts=None):
    res = np.zeros_like(images[0],dtype=np.float32)
    if wts is None:
        wts = np.ones(len(images))
    wts /= np.sum(wts)
    for n,i in enumerate(images):
        res += wts[n]*i.astype(np.float32)/255.0
    return res

display_images([img_aligned[0],img_aligned[1],merge(img_aligned[0:2])])_____no_output_____

Now let's merge all pictures together, which gives us the cognitive portrait we promised you in the beginning_____no_output_____

res = merge(img_aligned)
plt.imshow(res)_____no_output_____

You can generate a series of images with random weights, and then select the one you like most:_____no_output_____

imgs = [merge(img_aligned,np.random.random(len(img_aligned))) for _ in range(5)]
display_images(imgs)_____no_output_____

Finally, let's save the result into a file. Please run the following cell until you are satisfied with the result - it will produce slightly different image each time:_____no_output_____

res = merge(img_aligned,np.random.random(len(img_aligned)))
plt.imshow(res)_____no_output_____

Now, execute the next cell to save the result to disk:_____no_output_____

cv2.imwrite('result.jpg',(cv2.cvtColor(res,cv2.COLOR_BGR2RGB)*255.0).astype(np.int))_____no_output_____

Now you can switch to another browser tab - the one that you used to upload the images. Maybe you need to refresh the page (press **F5**), but you should be able to see `result.jpg` file there. You can download it to your computer and enjoy!

Of course, you can also cut an image right from the screen using **Snipping tool** on Windows..._____no_output_____## Learn to Program and Continue Experiments!

Hoorah! We learnt how to create simple blended portraits, merging aligned photos together to achieve cool visual effects! You can experiement with different sets of photos:

* Use photos of one person at different ages to get "younger" photo
* Combine pictures of 2 different people or more (take 5 pictures of each one)!
* Try to blend many random photos!

Bleding photos (which I call **peopleblending**) is only one technique you can use with facial landmarks. You can try different other ways of aligning pictures, for example putting all eyes on a perimeter of a circle, or creating a continuous line of portraits. When you learn Python and OpenCV for image processing, you should be able to create very artistic effects with your code._____no_output_____## Share the Results!

I would like to encourage you to share your result, as I have shared this technique with you! As the creator of original **[cognitive portrait](http://bit.do/cognitiveportrait)** technique, I am very curious to see your results. You can [send me the result in a private message](http://fb.com/shwars), but even better - share the reults in social networks using **#cognitiveportrait** hashtag. For example:

> Wow, look at the cool #cognitiveportrait I have created this weekend! -- http://bit.do/cognitiveportrait!

It would also be nice if you keep the link to the original technique -- http://bit.do/cognitiveportrait -- so that more people can get inspired by it!

Don't stop at this, be creative and be happy!!!_____no_output_____


# Notebook from DianaMosquera/course-content
Path: tutorials/W0D1_PythonWorkshop1/W0D1_Tutorial1.ipynb

_____no_output_____# Neuromatch Academy: Week 0, Day 1, Tutorial 1
# Python for NMA - LIF Neuron - Part I

__Content creators:__ Marco Brigham and the [CCNSS](https://www.ccnss.org/) team

__Content reviewers:__ Michael Waskom, Karolina Stosio, Spiros Chavlis_____no_output_____---
## Tutorial objectives
NMA students, you are going to use Python skills to advance your understanding of neuroscience. Just like two legs that support and strengthen each other. One has "Python" written in it, and the other has "Neuro". And step-by-step they go.

In this notebook, we'll practice basic operations with Python variables, control flow, plotting, and a sneak peek at `np.array`, the workhorse of scientific computation in Python.

Each new concept in Python will unlock a different aspect of our implementation of a **Leaky Integrate-and-Fire (LIF)** neuron. And as if it couldn't get any better, we'll visualize the evolution of its membrane potential in time, and extract its statistical properties!

Well then, let's start our walk today!_____no_output_____---
## Imports and helper functions
Please execute the cell(s) below to initialize the notebook environment._____no_output_____

# Import libraries
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import YouTubeVideo_____no_output_____# @title Figure settings

%config InlineBackend.figure_format = 'retina'

plt.style.use("https://raw.githubusercontent.com/NeuromatchAcademy/course-content/master/nma.mplstyle")_____no_output_____

---
## Neuron model
A *membrane equation* and a *reset condition* define our *leaky-integrate-and-fire (LIF)* neuron:

\begin{align*}
\\
&\tau_m\,\frac{d}{dt}\,V(t) = E_{L} - V(t) + R\,I(t) &\text{if }\quad V(t) \leq V_{th}\\
\\
&V(t) = V_{reset} &\text{otherwise}\\
\\
\end{align*}

where $V(t)$ is the membrane potential, $\tau_m$ is the membrane time constant, $E_{L}$ is the leak potential, $R$ is the membrane resistance, $I(t)$ is the synaptic input current, $V_{th}$ is the firing threshold, and $V_{reset}$ is the reset voltage. We can also write $V_m$ for membrane potential - very convenient for plot labels.

The membrane equation is an *ordinary differential equation (ODE)* that describes the time evolution of membrane potential $V(t)$ in response to synaptic input and leaking of change across the cell membrane.

**Note that, in this tutorial the neuron model will not implement a spiking mechanism.**_____no_output_____

# @title Video: Synaptic input
video = YouTubeVideo(id='UP8rD2AwceM', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

### Exercise 1
We start by defining and initializing the main simulation variables.

**Suggestions**
* Modify the code below to print the simulation parameters_____no_output_____

# t_max = 150e-3   # second
# dt = 1e-3        # second
# tau = 20e-3      # second
# el = -60e-3      # milivolt
# vr = -70e-3      # milivolt
# vth = -50e-3     # milivolt
# r = 100e6        # ohm
# i_mean = 25e-11  # ampere

# print(t_max, dt, tau, el, vr, vth, r, i_mean)_____no_output_____

**SAMPLE OUTPUT**

```
0.15 0.001 0.02 -0.06 -0.07 -0.05 100000000.0 2.5e-10
```_____no_output_____

# to_remove solution
t_max = 150e-3   # second
dt = 1e-3        # second
tau = 20e-3      # second
el = -60e-3      # milivolt
vr = -70e-3      # milivolt
vth = -50e-3     # milivolt
r = 100e6        # ohm
i_mean = 25e-11  # ampere

print(t_max, dt, tau, el, vr, vth, r, i_mean)_____no_output_____

### Exercise 2
![synaptic input](https://github.com/mpbrigham/colaboratory-figures/raw/master/nma/python-for-nma/synaptic_input.png)

We start with a sinusoidal model to simulate the synaptic input $I(t)$ given by:
\begin{align*}
\\
I(t)=I_{mean}\left(1+\sin\left(\frac{2 \pi}{0.01}\,t\right)\right)\\
\\
\end{align*}

Compute the values of synaptic input $I(t)$ between $t=0$ and $t=0.009$ with step $\Delta t=0.001$.

**Suggestions**
* Loop variable `step` for 10 steps (`step` takes values from `0` to `9`)
* At each time step
    * Compute the value of `t` with variables `step` and `dt`
    * Compute the value of `i`
    * Print `i`
* Use `np.pi` and `np.sin` for evaluating $\pi$ and $\sin(\cdot)$, respectively_____no_output_____

# initialize t
t = 0

# loop for 10 steps, variable 'step' takes values from 0 to 9
for step in range(10):
  t = step * dt
  i = ...
  print(i)_____no_output_____

**SAMPLE OUTPUT**

```
2.5e-10
3.969463130731183e-10
4.877641290737885e-10
4.877641290737885e-10
3.9694631307311837e-10
2.5000000000000007e-10
1.0305368692688176e-10
1.2235870926211617e-11
1.223587092621159e-11
1.0305368692688186e-10
```_____no_output_____

# to_remove solution
# initialize t
t = 0

# loop for 10 steps, variable 'step' takes values from 0 to 9
for step in range(10):
  t = step * dt
  i = i_mean * (1 + np.sin((t * 2 * np.pi) / 0.01))
  print(i)_____no_output_____

### Exercise 3
Print formatting is handy for displaying simulation parameters in a clean and organized form. Python 3.6 introduced the new string formatting [f-strings](https://www.python.org/dev/peps/pep-0498). Since we are dealing with type `float` variables, we use `f'{x:.3f}'` for formatting `x` to three decimal points, and `f'{x:.4e}'` for four decimal points but in exponential notation.
```
x = 3.14159265e-1
print(f'{x:.3f}')
--> 0.314

print(f'{x:.4e}')
--> 3.1416e-01
```

Repeat the loop from the previous exercise and print the `t` values with three decimal points, and synaptic input $I(t)$ with four decimal points in exponential notation.

For additional formatting options with f-strings see [here](http://zetcode.com/python/fstring/).

**Suggestions**
* Print `t` and `i` with help of *f-strings* formatting_____no_output_____

# initialize step_end
step_end = 10

# loop for step_end steps
for step in range(step_end):
  t = step * dt
  i = ...
  print(...)_____no_output_____

**SAMPLE OUTPUT**

```
0.000 2.5000e-10
0.001 3.9695e-10
0.002 4.8776e-10
0.003 4.8776e-10
0.004 3.9695e-10
0.005 2.5000e-10
0.006 1.0305e-10
0.007 1.2236e-11
0.008 1.2236e-11
0.009 1.0305e-10
```_____no_output_____

# to_remove solution
# initialize step_end
step_end = 10

# loop for step_end steps
for step in range(step_end):
  t = step * dt
  i = i_mean * (1 + np.sin((t * 2 * np.pi) / 0.01))
  print(f'{t:.3f} {i:.4e}')_____no_output_____

## ODE integration without spikes
In the next exercises, we now simulate the evolution of the membrane equation in discrete time steps, with a sufficiently small $\Delta t$.

We start by writing the time derivative $d/dt\,V(t)$ in the membrane equation without taking the limit $\Delta t \to 0$:

\begin{align*}
\\
\tau_m\,\frac{V\left(t+\Delta t\right)-V\left(t\right)}{\Delta t} &= E_{L} - V(t) + R\,I(t) \qquad\qquad (1)\\
\\
\end{align*}

The value of membrane potential $V\left(t+\Delta t\right)$ can be expressed in terms of its previous value $V(t)$ by simple algebraic manipulation. For *small enough* values of $\Delta t$, this provides a good approximation of the continuous-time integration.

This operation is an integration since we obtain a sequence $\{V(t), V(t+\Delta t), V(t+2\Delta t),...\}$ starting from the ODE. Notice how the ODE describes the evolution of $\frac{d}{dt}\,V(t)$, the derivative of $V(t)$, but not directly the evolution of $V(t)$. For the evolution of $V(t)$ we need to integrate the ODE, and in this tutorial, we will do a discrete-time integration using the Euler method. See [Numerical methods for ordinary differential equations](https://en.wikipedia.org/wiki/Numerical_methods_for_ordinary_differential_equations) for additional details._____no_output_____

# @title Video: Discrete time integration
video = YouTubeVideo(id='kyCbeR28AYQ', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

### Exercise 4
Compute the values of $V(t)$ between $t=0$ and $t=0.01$ with step $\Delta t=0.001$ and $V(0)=E_L$.

We will write a `for` loop from scratch in this exercise. The following three formulations are all equivalent and loop for three steps:
```
for step in [0, 1, 2]:
  print(step)

for step in range(3):
  print(step)

start = 0
end = 3
stepsize = 1

for step in range(start, end, stepsize):
  print(step)
```

**Suggestions**
* Reorganize the Eq. (1) to isolate $V\left(t+\Delta t\right)$ on the left side, and express it as function of $V(t)$ and the other terms
* Initialize the membrane potential variable `v` to leak potential `el`
* Loop variable `step` for `10` steps
* At each time step
    * Compute the current value of `t`, `i`
    * Print the current value of `t` and `v`
    * Update the value of `v`_____no_output_____

# initialize step_end and v
step_end = 10
v = el

# loop for step_end steps
for step in range(step_end):
  t = step * dt
  i = ...
  print(...)
  v = ..._____no_output_____

**SAMPLE OUTPUT**

```
0.000 -6.0000e-02
0.001 -5.8750e-02
0.002 -5.6828e-02
0.003 -5.4548e-02
0.004 -5.2381e-02
0.005 -5.0778e-02
0.006 -4.9989e-02
0.007 -4.9974e-02
0.008 -5.0414e-02
0.009 -5.0832e-02
```_____no_output_____

# to_remove solution
# initialize step_end and v
step_end = 10
v = el

# loop for step_end steps
for step in range(step_end):
  t = step * dt
  i = i_mean * (1 + np.sin((t * 2 * np.pi) / 0.01))
  print(f"{t:.3f} {v:.4e}")
  v = v + dt/tau * (el - v + r*i)_____no_output_____# @title Video: Plotting
from IPython.display import YouTubeVideo
video = YouTubeVideo(id='BOh8CsuTFkY', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

### Exercise 5
![synaptic input discrete](https://github.com/mpbrigham/colaboratory-figures/raw/master/nma/python-for-nma/synaptic_input_discrete.png)

Plot the values of $I(t)$ between $t=0$ and $t=0.024$.

**Suggestions**
* Increase `step_end`
* initialize the figure with `plt.figure`, set title, x and y labels with `plt.title`, `plt.xlabel` and `plt.ylabel`, respectively
* Replace printing command `print` with plotting command `plt.plot` with argument `'ko'` (short version for `color='k'` and `marker='o'`) for black small dots
* Use `plt.show()` at the end to display the plot_____no_output_____

# initialize step_end
step_end = 25

# initialize the figure
plt.figure()
# Complete these lines and uncomment
# plt.title(...)
# plt.xlabel(...)
# plt.ylabel(...)

# loop for step_end steps
for step in range(step_end):
  t = step * dt
  i = ...
  # Complete this line and uncomment
  # plt.plot(...)

# plt.show()_____no_output_____# to_remove solution
# initialize step_end
step_end = 25

with plt.xkcd():
  # initialize the figure
  plt.figure()
  plt.title('Synaptic Input $I(t)$')
  plt.xlabel('time (s)')
  plt.ylabel('$I$ (A)')

  # loop for step_end steps
  for step in range(step_end):
    t = step * dt
    i = i_mean * (1 + np.sin((t * 2 * np.pi) / 0.01))
    plt.plot(t, i, 'ko')

  plt.show()_____no_output_____

### Exercise 6
Plot the values of $V(t)$ between $t=0$ and $t=t_{max}$.

**Suggestions**
* Compute the required number of steps with`int(t_max/dt)`
* Use plotting command for black small(er) dots with argument `'k.'`_____no_output_____

# initialize step_end and v
step_end = int(t_max / dt)
v = el

# initialize the figure
plt.figure()
plt.title('$V_m$ with sinusoidal I(t)')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)');

# loop for step_end steps
for step in range(step_end):
  t = step * dt
  i = ...
  # Complete this line and uncomment
  # plt.plot(...)

  v = ...

t = t + dt
# Complete this line and uncomment
# plt.plot(...)
plt.show()_____no_output_____# to_remove solution
# initialize step_end and v
step_end = int(t_max / dt)
v = el

with plt.xkcd():
  # initialize the figure
  plt.figure()
  plt.title('$V_m$ with sinusoidal I(t)')
  plt.xlabel('time (s)')
  plt.ylabel('$V_m$ (V)');
  # loop for step_end steps
  for step in range(step_end):
    t = step * dt
    i = i_mean * (1 + np.sin((t * 2 * np.pi) / 0.01))
    plt.plot(t, v, 'k.')

    v = v + dt/tau * (el - v + r*i)

  t = t + dt
  plt.plot(t, v, 'k.')
  plt.show()_____no_output_____

---
## Random synaptic input
From the perspective of neurons, synaptic input is random (or stochastic). We'll improve the synaptic input model by introducing random input current with statistical properties similar to the previous exercise:

\begin{align*}
\\
I(t)=I_{mean}\left(1+0.1\sqrt{\frac{t_{max}}{\Delta t}}\,\xi(t)\right)\qquad\text{with }\xi(t)\sim U(-1,1)\\
\\
\end{align*}

where $U(-1,1)$ is the [uniform distribution](https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)) with support $x\in[-1,1]$.

Random synaptic input $I(t)$ results in random time course for $V(t)$._____no_output_____### Exercise 7
Plot the values of $V(t)$ between $t=0$ and $t=t_{max}-\Delta t$ with random input $I(t)$.

Initialize the (pseudo) random number generator (RNG) to a fixed value to obtain the same random input each time.

The function `np.random.seed()` initializes the RNG, and `np.random.random()` generates samples from the uniform distribution between `0` and `1`.

**Suggestions**
* Use `np.random.seed()` to initialize the RNG to `0`
* Use `np.random.random()` to generate random input in range `[0,1]` at each timestep
* Multiply random input by an appropriate factor to expand the range to `[-1,1]`
* Verify that $V(t)$ has a random time course by changing the initial RNG value
* Alternatively, comment RNG initialization by typing `CTRL` + `\` in the relevant line_____no_output_____

# set random number generator
np.random.seed(2020)

# initialize step_end and v
step_end = int(t_max / dt)
v = el

# initialize the figure
plt.figure()
plt.title('$V_m$ with random I(t)')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

# loop for step_end steps
for step in range(step_end):
  t = step * dt
  # Complete this line and uncomment
  # plt.plot(...)

  i = ...
  v = ...

plt.show()_____no_output_____# to_remove solution
# set random number generator
np.random.seed(2020)

# initialize step_end and v
step_end = int(t_max / dt)
v = el
t = 0

with plt.xkcd():
  # initialize the figure
  plt.figure()
  plt.title('$V_m$ with random I(t)')
  plt.xlabel('time (s)')
  plt.ylabel('$V_m$ (V)')

  # loop for step_end steps
  for step in range(step_end):
    t = step * dt
    print(t)
    plt.plot(t, v, 'k.')

    i = i_mean * (1 + 0.1 * (t_max / dt)**(0.5) * (2 * np.random.random() - 1))
    v = v + (dt / tau) * (el - v + r * i)

  plt.show()_____no_output_____

## Ensemble statistics
Multiple runs of the previous exercise may give the impression of periodic regularity in the evolution of $V(t)$. We'll collect the sample mean over $N=50$ realizations of $V(t)$  with random input to test such a hypothesis. The sample mean, sample variance and sample autocovariance at times $\left\{t, s\right\}\in[0,t_{max}]$, and for $N$ realizations $V_n(t)$ are given by:

\begin{align*}
\\
\left\langle V(t)\right\rangle &= \frac{1}{N}\sum_{n=1}^N V_n(t) & & \text{sample mean}\\
\left\langle (V(t)-\left\langle V(t)\right\rangle)^2\right\rangle &= \frac{1}{N-1} \sum_{n=1}^N \left(V_n(t)-\left\langle V(t)\right\rangle\right)^2 & & \text{sample variance} \\
\left\langle \left(V(t)-\left\langle V(t)\right\rangle\right)\left(V(s)-\left\langle V(s)\right\rangle\right)\right\rangle
&= \frac{1}{N-1} \sum_{n=1}^N \left(V_n(t)-\left\langle V(t)\right\rangle\right)\left(V_n(s)-\left\langle V(s)\right\rangle\right) & & \text{sample autocovariance}\\
\\
\end{align*}_____no_output_____

# @title Video: Ensemble statistics
video = YouTubeVideo(id='4nIAS2oPEFI', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

### Exercise 8
Plot multiple realizations ($N=50$) of $V(t)$ by storing in a list the voltage of each neuron at time $t$.

Keep in mind that the plotting command `plt.plot(x, y)` requires `x` to have the same number of elements as `y`.

Mathematical symbols such as $\alpha$ and $\beta$ are specified as `$\alpha$` and `$\beta$` in [TeX markup](https://en.wikipedia.org/wiki/TeX). See additional details in [Writing mathematical expressions](https://matplotlib.org/3.2.2/tutorials/text/mathtext.html) in Matplotlib.

**Suggestions**
* Initialize a list `v_n` with `50` values of membrane leak potential `el`
* At each time step:
  * Plot `v_n` with argument `'k.'` and parameter `alpha=0.05` to adjust the transparency (by default, `alpha=1`)
  * In the plot command, replace `t` from the previous exercises with a list of size `n` with values `t`
  * Loop over `50` realizations of random input
  * Update `v_n` with the values of $V(t)$

* Why is there a black dot at $t=0$?_____no_output_____

# set random number generator
np.random.seed(2020)

# initialize step_end, n and v_n
step_end = int(t_max / dt)
n = 50
# Complete this line and uncomment
# v_n = ...

# initialize the figure
plt.figure()
plt.title('Multiple realizations of $V_m$')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

# loop for step_end steps
for step in range(step_end):
  t = step * dt
  # Complete this line and uncomment
  # plt.plot(...)

  # loop for n steps
  for j in range(0, n):
    i = ...
    # Complete this line and uncomment
    # v_n[j] = ...

plt.show()_____no_output_____# to_remove solution
# set random number generator
np.random.seed(2020)

# initialize step_end, n and v_n
step_end = int(t_max / dt)
n = 50
v_n = [el] * n

# initialize the figure
plt.figure()
plt.title('Multiple realizations of $V_m$')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

# loop for step_end steps
for step in range(step_end):
  t = step * dt
  plt.plot([t] * n, v_n, 'k.', alpha=0.05)

  # loop for n steps
  for j in range(0, n):
    i = i_mean * (1 + 0.1 * (t_max/dt)**(0.5) * (2* np.random.random() - 1))
    v_n[j] = v_n[j] + (dt / tau) * (el - v_n[j] + r*i)

plt.show()_____no_output_____

### Exercise 9
Add the sample mean $\left\langle V(t)\right\rangle=\frac{1}{N}\sum_{n=1}^N V_n(t)$ to the plot.

**Suggestions**
* At each timestep:
  * Compute and store in `v_mean` the sample mean $\left\langle V(t)\right\rangle$ by summing the values of list `v_n` with `sum` and dividing by `n`
  * Plot $\left\langle V(t)\right\rangle$ with `alpha=0.8` and argument `'C0.'` for blue (you can read more about [specifying colors](https://matplotlib.org/tutorials/colors/colors.html#sphx-glr-tutorials-colors-colors-py))
  * Loop over `50` realizations of random input
  * Update `v_n` with the values of $V(t)$_____no_output_____

# set random number generator
np.random.seed(2020)

# initialize step_end, n and v_n
step_end = int(t_max / dt)
n = 50
v_n = [el] * n

# initialize the figure
plt.figure()
plt.title('Multiple realizations of $V_m$')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

# loop for step_end steps
for step in range(step_end):
  t = step * dt

  v_mean = ...
  # Complete these lines and uncomment
  # plt.plot(...)
  # plt.plot(...)

  for j in range(0, n):
    i = ...
    v_n[j] = ...

plt.show()_____no_output_____# to_remove solution
# set random number generator
np.random.seed(2020)

# initialize step_end, n and v_n
step_end = int(t_max / dt)
n = 50
v_n = [el] * n

# initialize the figure
plt.figure()
plt.title('Multiple realizations of $V_m$')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

# loop for step_end steps
for step in range(step_end):
  t = step * dt

  v_mean = sum(v_n) / n
  plt.plot(n*[t], v_n, 'k.', alpha=0.05)
  plt.plot(t, v_mean, 'C0.', alpha=0.8, markersize=10)

  for j in range(0, n):
    i = i_mean * (1 + 0.1 * (t_max / dt)**(0.5) * (2 * np.random.random() - 1))
    v_n[j] = v_n[j] + (dt / tau) * (el - v_n[j] + r*i)

plt.show()_____no_output_____

### Exercise 10
Add the sample standard deviation $\sigma(t)\equiv\sqrt{\text{Var}\left(t\right)}$ to the plot, with sample variance $\text{Var}(t) = \frac{1}{N-1} \sum_{n=1}^N \left(V_n(t)-\left\langle V(t)\right\rangle\right)^2$.

Use a list comprehension to collect the sample variance `v_var`. Here's an example to initialize a list with squares of `0` to `9`:
```
squares = [x**2 for x in range(10)]
print(squares)
--> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
```

Why are we plotting $\sigma(t)$ rather than the $\text{Var}(t)$? What are the units of each and the units of $\left\langle V(t)\right\rangle$?

**Suggestions**
* At each timestep:
  * Compute and store in `v_mean` the sample mean $\left\langle V(t)\right\rangle$
  * Initialize a list `v_var_n` with the contribution of each $V_n(t)$ to $\text{Var}\left(t\right)$ with a list comprehension over values of `v_n`
  * Compute sample variance `v_var` by summing the values of `v_var_n` with `sum` and dividing by `n-1`
  * (alternative: loop over the values of `v_n` and add to `v_var` each contribution $V_n(t)$ and divide by `n-1` outside the loop)
  * Compute the standard deviation `v_std` with the function `np.sqrt`
  * Plot $\left\langle V(t)\right\rangle\pm\sigma(t)$ with `alpha=0.8` and argument `'C7.'`_____no_output_____

# set random number generator
np.random.seed(2020)

# initialize step_end, n and v_n
step_end = int(t_max / dt)
n = 50
v_n = [el] * n

# initialize the figure
plt.figure()
plt.title('Multiple realizations of $V_m$')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

# loop for step_end steps
for step in range(step_end):
  t = step * dt

  v_mean = ...
  v_var_n = ...
  v_var = ...
  v_std = ...

  # Complete these lines and uncomment
  # plt.plot(...)
  # plt.plot(...)
  # plt.plot(...)
  # plt.plot(...)

  for j in range(0, n):
    i = ...
    v_n[j] = ...

plt.show()_____no_output_____# to_remove solution
# set random number generator
np.random.seed(2020)

# initialize step_end, n and v_n
step_end = int(t_max / dt)
n = 50
v_n = [el] * n

# initialize the figure
plt.figure()
plt.title('Multiple realizations of $V_m$')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

# loop for step_end steps
for step in range(step_end):
  t = step * dt

  v_mean = sum(v_n) / n
  v_var_n = [(v - v_mean)**2 for v in v_n]
  v_var = sum(v_var_n) / (n - 1)
  v_std = np.sqrt(v_var)

  plt.plot(n*[t], v_n, 'k.', alpha=0.05)
  plt.plot(t, v_mean, 'C0.', alpha=0.8)
  plt.plot(t, v_mean + v_std, 'C7.', alpha=0.8)
  plt.plot(t, v_mean - v_std, 'C7.', alpha=0.8)

  for j in range(0, n):
    i = i_mean * (1 + 0.1 * (t_max / dt)**(0.5) * (2 * np.random.random() - 1))
    v_n[j] = v_n[j] + (dt / tau) * (el - v_n[j] + r*i)

plt.show()_____no_output_____

---
## Using NumPy
The next set of exercises introduces `np.array`, the workhorse from the scientific computation package [NumPy](https://numpy.org). Numpy arrays the default for numerical data storage and computation and will separate computing steps from plotting.

![NumPy package](https://github.com/mpbrigham/colaboratory-figures/raw/master/nma/python-for-nma/numpy_logo_small.png)

We updated plots inside the main loop in the previous exercises and stored intermediate results in lists for plotting them. The purpose was to simplify earlier exercises as much as possible. However, there are very few scenarios where this technique is necessary, and you should avoid it in the future. Using numpy arrays will significantly simplify our coding narrative by computing inside the main loop and plotting afterward.

Lists are much more natural for storing data for other purposes than computation. For example, lists are handy for storing numerical indexes and text._____no_output_____

# @title Video: Using NumPy
video = YouTubeVideo(id='ewyHKKa2_OU', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

### Exercise 11
Rewrite the single neuron plot with random input from _Exercise 7_ with numpy arrays. The time range, voltage values, and synaptic current are initialized or pre-computed as numpy arrays before numerical integration.

**Suggestions**
* Use `np.linspace` to initialize a numpy array `t_range` with `num=step_end=150` values from `0` to `t_max`
* Use `np.ones` to initialize a numpy array `v` with `step_end + 1` leak potential values `el`
* Pre-compute `step_end` synaptic current values in numpy array `syn` with `np.random.random(step_end)` for `step_end` random numbers
* Iterate for numerical integration of `v`
* Since `v[0]=el`, we should iterate for `step_end` steps, for example by skipping `step=0`. Why?_____no_output_____

# set random number generator
np.random.seed(2020)

# initialize step_end, t_range, v and syn
step_end = int(t_max / dt) - 1
# skip the endpoint to match Exercise 7 plot
t_range = np.linspace(0, t_max, num=step_end, endpoint=False)
v = el * np.ones(step_end)
syn = ...

# loop for step_end - 1 steps
# Complete these lines and uncomment
# for step in range(1, step_end):
  # v[step] = ...

plt.figure()
plt.title('$V_m$ with random I(t)')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

plt.plot(t_range, v, 'k.')
plt.show()_____no_output_____# to_remove solution
# set random number generator
np.random.seed(2020)

# initialize step_end, t_range, v and syn
step_end = int(t_max / dt) - 1
# skip the endpoint to match Exercise 7 plot
t_range = np.linspace(0, t_max, num=step_end, endpoint=False)
v = el * np.ones(step_end)
syn = i_mean * (1 + 0.1 * (t_max/dt) ** (0.5) * (2 * np.random.random(step_end) - 1))

# loop for step_end - 1 steps
for step in range(1, step_end):
  v[step] = v[step - 1] + (dt / tau) * (el - v[step - 1] + r * syn[step])

with plt.xkcd():
  # initialize the figure
  plt.figure()
  plt.title('$V_m$ with random I(t)')
  plt.xlabel('time (s)')
  plt.ylabel('$V_m$ (V)')

  plt.plot(t_range, v, 'k.')
  plt.show()_____no_output_____

### Exercise 12
Let's practice using `enumerate` to iterate over the indexes and values of the synaptic current array `syn`.

**Suggestions**
* Iterate indexes and values of `syn` with `enumerate` in the `for` loop
* Plot `v` with argument `'k'` for displaying a line instead of dots_____no_output_____

# set random number generator
np.random.seed(2020)

# initialize step_end, t_range, v and syn
step_end = int(t_max / dt)
t_range = np.linspace(0, t_max, num=step_end)
v = el * np.ones(step_end)
syn = i_mean * (1 + 0.1 * (t_max / dt)**(0.5) * (2 * np.random.random(step_end) - 1))

# loop for step_end values of syn
for step, i in enumerate(syn):
  # skip first iteration
  if step==0:
    continue
  # Complete this line and uncomment
  # v[step] = ...

plt.figure()
plt.title('$V_m$ with random I(t)')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

plt.plot(t_range, v, 'k')
plt.show()_____no_output_____# to_remove solution
# set random number generator
np.random.seed(2020)

# initialize step_end, t_range, v and syn
step_end = int(t_max / dt)
t_range = np.linspace(0, t_max, num=step_end)
v = el * np.ones(step_end)
syn = i_mean * (1 + 0.1 * (t_max / dt)**(0.5) * (2 * np.random.random(step_end) - 1))

# loop for step_end values of syn
for step, i in enumerate(syn):
  # skip first iteration
  if step==0:
    continue
  v[step] = v[step - 1] + (dt / tau) * (el - v[step - 1] + r*i)

with plt.xkcd():
  # initialize the figure
  plt.figure()
  plt.title('$V_m$ with random I(t)')
  plt.xlabel('time (s)')
  plt.ylabel('$V_m$ (V)')

  plt.plot(t_range, v, 'k')
  plt.show()_____no_output_____# @title Video: Aggregation
video = YouTubeVideo(id='1ME-0rJXLFg', width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video_____no_output_____

### Exercise 13
Plot multiple realizations ($N=50$) of $V(t)$ by storing the voltage of each neuron at time $t$ in a numpy array.

**Suggestions**
* Initialize a numpy array `v_n` of shape `(n, step_end)` with membrane leak potential values `el`
* Pre-compute synaptic current values in numpy array `syn` of shape `(n, step_end)`
* Iterate `step_end` steps with a `for` loop for numerical integration
* Plot results with a single plot command, by providing `v_n.T` to the plot function. `v_n.T` is the transposed version of `v_n` (with rows and columns swapped)._____no_output_____

# set random number generator
np.random.seed(2020)

# initialize step_end, n, t_range, v and syn
step_end = int(t_max / dt)
n = 50
t_range = np.linspace(0, t_max, num=step_end)
v_n = el * np.ones([n, step_end])
syn = ...

# loop for step_end - 1 steps
# Complete these lines and uncomment
# for step in range(1, step_end):
  # v_n[:, step] = ...

# initialize the figure
plt.figure()
plt.title('Multiple realizations of $V_m$')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

# Complete this line and uncomment
# plt.plot(...)
plt.show()_____no_output_____# to_remove solution
# set random number generator
np.random.seed(2020)

# initialize step_end, n, t_range, v and syn
step_end = int(t_max / dt)
n = 50
t_range = np.linspace(0, t_max, num=step_end)
v_n = el * np.ones([n, step_end])
syn = i_mean * (1 + 0.1 * (t_max / dt)**(0.5) * (2 * np.random.random([n, step_end]) - 1))

# loop for step_end - 1 steps
for step in range(1, step_end):
  v_n[:, step] = v_n[:, step - 1] + (dt / tau) * (el - v_n[:, step - 1] + r * syn[:, step])

with plt.xkcd():
  # initialize the figure
  plt.figure()
  plt.title('Multiple realizations of $V_m$')
  plt.xlabel('time (s)')
  plt.ylabel('$V_m$ (V)')

  plt.plot(t_range, v_n.T, 'k', alpha=0.3)
  plt.show()_____no_output_____

### Exercise 14
Add sample mean $\left\langle V(t)\right\rangle$ and standard deviation $\sigma(t)\equiv\sqrt{\text{Var}\left(t\right)}$ to the plot.

`np.mean(v_n, axis=0)` computes mean over rows, i.e. mean for each neuron

`np.mean(v_n, axis=1)` computes mean over columns (axis `1`), i.e. mean for each time step

**Suggestions**
* Use `np.mean` and `np.std` with `axis=0` to sum over neurons
* Use `label` argument in `plt.plot` to specify labels in each trace. Label only the last voltage trace to avoid labeling all `N` of them._____no_output_____

# set random number generator
np.random.seed(2020)

# initialize step_end, n, t_range, v and syn
step_end = int(t_max / dt)
n = 50
t_range = np.linspace(0, t_max, num=step_end)
v_n = el * np.ones([n, step_end])
syn = i_mean * (1 + 0.1 * (t_max / dt)**(0.5) * (2 * np.random.random([n, step_end]) - 1))

# loop for step_end - 1 steps
for step in range(1, step_end):
  v_n[:,step] = v_n[:,step - 1] + (dt / tau) * (el - v_n[:, step - 1] + r * syn[:, step])

v_mean = ...
v_std = ...

# initialize the figure
plt.figure()
plt.title('Multiple realizations of $V_m$')
plt.xlabel('time (s)')
plt.ylabel('$V_m$ (V)')

plt.plot(t_range, v_n[:-1].T, 'k', alpha=0.3)

# Complete these lines and uncomment
# plt.plot(t_range, v_n[-1], 'k', alpha=0.3, label=...)
# plt.plot(t_range, ..., 'C0', alpha=0.8, label='mean')
# plt.plot(t_range, ..., 'C7', alpha=0.8)
# plt.plot(t_range, ..., 'C7', alpha=0.8, label=...)

#plt.legend()
plt.show()_____no_output_____# to_remove solution
# set random number generator
np.random.seed(2020)

# initialize step_end, n, t_range, v and syn
step_end = int(t_max / dt)
n = 50
t_range = np.linspace(0, t_max, num=step_end)
v_n = el * np.ones([n, step_end])
syn = i_mean * (1 + 0.1 * (t_max / dt)**(0.5) * (2 * np.random.random([n, step_end]) - 1))

# loop for step_end - 1 steps
for step in range(1, step_end):
  v_n[:,step] = v_n[:,step - 1] + (dt / tau) * (el - v_n[:, step - 1] + r * syn[:, step])

v_mean = np.mean(v_n, axis=0)
v_std = np.std(v_n, axis=0)

with plt.xkcd():
  # initialize the figure
  plt.figure()
  plt.title('Multiple realizations of $V_m$')
  plt.xlabel('time (s)')
  plt.ylabel('$V_m$ (V)')

  plt.plot(t_range, v_n[:-1].T, 'k', alpha=0.3)

  plt.plot(t_range, v_n[-1], 'k', alpha=0.3, label='V(t)')
  plt.plot(t_range, v_mean, 'C0', alpha=0.8, label='mean')
  plt.plot(t_range, v_mean+v_std, 'C7', alpha=0.8)
  plt.plot(t_range, v_mean-v_std, 'C7', alpha=0.8, label='mean $\pm$ std')

  plt.legend()
  plt.show()_____no_output_____