All the exercices on this sheet work this way:

  1. You have a cell with TODOs that raise errors with a description of what is needed. Do that.
  2. Then run the cell(ctrl-enter) to execute it.
  3. It should print "Success" at the end (there is validation code in the cell). If not, try again.
  4. If you want to see the solution, execute the cell that start with "%load" after the exercice.

1. Builing expressions

Excercice 1.1

This exercice walks you through creating Theano variables and doing some computation with them.


In [ ]:
import numpy as np
from theano import function
raise NotImplementedError("TODO: add any other imports you need")


def make_scalar():
    """
    Returns a new Theano scalar.
    """

    raise NotImplementedError("TODO: implement this function.")


def log(x):
    """
    Returns the logarithm of a Theano scalar x.
    """

    raise NotImplementedError("TODO: implement this function.")


def add(x, y):
    """
    Adds two theano scalars together and returns the result.
    """

    raise NotImplementedError("TODO: implement this function.")
    
# The following code uses your code and tests it.
a = make_scalar()
b = make_scalar()
c = log(b)
d = add(a, c)
f = function([a, b], d)
a = np.cast[a.dtype](1.)
b = np.cast[b.dtype](2.)
actual = f(a, b)
expected = 1. + np.log(2.)
assert np.allclose(actual, expected)
print "SUCCESS!"

In [ ]:
%load 01_scalar_soln.py

Exercice 1.2

This exercice asks you to make Theano variables, elementwise multiplication and matrix/vector dot product.


In [ ]:
import numpy as np
from theano import function
raise NotImplementedError("TODO: add any other imports you need")


def make_vector():
    """
    Returns a new Theano vector.
    """

    raise NotImplementedError("TODO: implement this function.")


def make_matrix():
    """
    Returns a new Theano matrix.
    """

    raise NotImplementedError("TODO: implement this function.")

def elemwise_mul(a, b):
    """
    a: A theano matrix
    b: A theano matrix
    Returns the elementwise product of a and b
    """

    raise NotImplementedError("TODO: implement this function.")


def matrix_vector_mul(a, b):
    """
    a: A theano matrix
    b: A theano vector
    Returns the matrix-vector product of a and b
    """

    raise NotImplementedError("TODO: implement this function.")

# The following code uses your code and tests it.
a = make_vector()
b = make_vector()
c = elemwise_mul(a, b)
d = make_matrix()
e = matrix_vector_mul(d, c)

f = function([a, b, d], e)

rng = np.random.RandomState([1, 2, 3])
a_value = rng.randn(5).astype(a.dtype)
b_value = rng.rand(5).astype(b.dtype)
c_value = a_value * b_value
d_value = rng.randn(5, 5).astype(d.dtype)
expected = np.dot(d_value, c_value)

actual = f(a_value, b_value, d_value)
assert np.allclose(actual, expected)
print "SUCCESS!"

In [ ]:
%load 02_vector_mat_soln.py

Exercice 1.3

This exercices asks you to create a tensor variable, do broadcastable additions and compute the max over part of a tensor.


In [ ]:
import numpy as np
from theano import function
raise NotImplementedError("TODO: add any other imports you need")


def make_tensor(dim):
    """
    Returns a new Theano tensor with no broadcastable dimensions.
    dim: the total number of dimensions of the tensor.
    (You can use any dtype you like)
    """

    raise NotImplementedError("TODO: implement this function.")


def broadcasted_add(a, b):
    """
    a: a 3D theano tensor
    b: a 4D theano tensor
    Returns c, a 4D theano tensor, where

    c[i, j, k, l] = a[l, k, i] + b[i, j, k, l]

    for all i, j, k, l
    """

    raise NotImplementedError("TODO: implement this function.")

def partial_max(a):
    """
    a: a 4D theano tensor

    Returns b, a theano matrix, where

    b[i, j] = max_{k,l} a[i, k, l, j]

    for all i, j
    """

    raise NotImplementedError("TODO: implement this function.")

# The following code uses your code and tests it.
a = make_tensor(3)
b = make_tensor(4)
c = broadcasted_add(a, b)
d = partial_max(c)

f = function([a, b], d)

rng = np.random.RandomState([1, 2, 3])
a_value = rng.randn(2, 2, 2).astype(a.dtype)
b_value = rng.rand(2, 2, 2, 2).astype(b.dtype)
c_value = np.transpose(a_value, (2, 1, 0))[:, None, :, :] + b_value
expected = c_value.max(axis=1).max(axis=1)

actual = f(a_value, b_value)

assert np.allclose(actual, expected), (actual, expected)
print "SUCCESS!"

In [ ]:
%load 03_tensor_soln.py

2. Compiling and Running

Exercice 2.1

This exercice asks you to compile a Theano function and call it.


In [ ]:
from theano import tensor as T
raise NotImplementedError("TODO: add any other imports you need")


def evaluate(x, y, expr, x_value, y_value):
    """
    x: A theano variable
    y: A theano variable
    expr: A theano expression involving x and y
    x_value: A numpy value
    y_value: A numpy value

    Returns the value of expr when x_value is substituted for x
    and y_value is substituted for y
    """

    raise NotImplementedError("TODO: implement this function.")


# The following code use your code and test it.
x = T.iscalar()
y = T.iscalar()
z = x + y
assert evaluate(x, y, z, 1, 2) == 3
print "SUCCESS!"

In [ ]:
%load 11_function_soln.py

Exercice 2.2

This exercice makes you use shared variables. You must create some and update them by swapping 2 shared variables value.


In [ ]:
import numpy as np
raise NotImplementedError("TODO: add any other imports you need")


def make_shared(shape):
    """
    Returns a theano shared variable containing a tensor of the specified
    shape.
    You can use any value you want.
    """
    raise NotImplementedError("TODO: implement the function")


def exchange_shared(a, b):
    """
    a: a theano shared variable
    b: a theano shared variable
    Uses get_value and set_value to swap the values stored in a and b
    """
    raise NotImplementedError("TODO: implement the function")


def make_exchange_func(a, b):
    """
    a: a theano shared variable
    b: a theano shared variable
    Returns f
    where f is a theano function, that, when called, swaps the
    values in a and b
    f should not return anything
    """
    raise NotImplementedError("TODO: implement the function")


# The following code use your code and test it.
a = make_shared((5, 4, 3))
assert a.get_value().shape == (5, 4, 3)
b = make_shared((5, 4, 3))
assert a.get_value().shape == (5, 4, 3)
a.set_value(np.zeros((5, 4, 3), dtype=a.dtype))
b.set_value(np.ones((5, 4, 3), dtype=b.dtype))
exchange_shared(a, b)
assert np.all(a.get_value() == 1.)
assert np.all(b.get_value() == 0.)
f = make_exchange_func(a, b)
rval = f()
assert isinstance(rval, list)
assert len(rval) == 0
assert np.all(a.get_value() == 0.)
assert np.all(b.get_value() == 1.)

print "SUCCESS!"

In [ ]:
%load 12_shared_soln.py

Exercice 2.3

Something weird happens when you run this code, find the problem. Explain what is happening.

Hint: some compilation modes make the problem more obvious than others.


In [ ]:
import numpy as np
from theano import function
from theano import tensor as T
x = T.vector()
y = T.vector()
z = T.zeros_like(y)
a = x + z
f = function([x, y], a)
output = f(np.zeros((1,), dtype=x.dtype), np.zeros((2,), dtype=y.dtype))

In [ ]:
%load 13_bug_soln.py

3. Modifying Graphs

Exercice 3.1

This exercice makes you use the Theano symbolic grad.


In [ ]:
from theano import tensor as T


def grad_sum(x, y, z):
    """
    x: A theano variable
    y: A theano variable
    z: A theano expression involving x and y

    Returns dz / dx + dz / dy
    """
    raise NotImplementedError("TODO: implement this function.")


# The following code use your code and test it.
x = T.scalar()
y = T.scalar()
z = x + y
s = grad_sum(x, y, z)
assert s.eval({x: 0, y: 0}) == 2
print "SUCCESS!"

In [ ]:
%load 21_grad_soln.py

Exercice 3.2

This exercice is here to show you how to navigate in a Theano graph. You will need to find the inputs used to produce some computation.


In [ ]:
import numpy as np
from theano import tensor as T
raise NotImplementedError("Add any imports you need.")


def arg_to_softmax(prob):
    """
    Oh no! Someone has passed you the probability output,
    "prob", of a softmax function, and you want the unnormalized
    log probability--the argument to the softmax.

    Verify that prob really is the output of a softmax. Raise a
    TypeError if it is not.

    If it is, return the argument to the softmax.
    """

    raise NotImplementedError("Implement this function.")


x = np.ones((5, 4))
try:
    arg_to_softmax(x)
    raise Exception("You should have raised an error.")
except TypeError:
    pass

x = T.matrix()
try:
    arg_to_softmax(x)
    raise Exception("You should have raised an error.")
except TypeError:
    pass

y = T.nnet.sigmoid(x)
try:
    arg_to_softmax(y)
    raise Exception("You should have raised an error.")
except TypeError:
    pass

y = T.nnet.softmax(x)
rval = arg_to_softmax(y)
assert rval is x

print "SUCCESS!"

In [ ]:
%load 22_traverse_soln.py

4. Debugging

Exercice 4.1

The code in the next cell has a bug. Run the cell to see it.

Use Theano flags or extra parameters to function() to find the cause.

Don't try to find the bug by inspection of prints, the point of the exercice is to get you to work with the theano debugging tools that will be required for more complex code.

To modify the environement for a cell use the %env magic command like this:

%env THEANO_FLAGS=floatX=float32

You will have to restart the ipython kernel from the Kernel menu above to get the enviroment changes to work.


In [ ]:
import numpy as np
from theano import function
from theano import tensor as T
a = T.vector()
b = T.log(a)
c = T.nnet.sigmoid(b)
d = T.sqrt(c)
e = T.concatenate((d, c), axis=0)
f = b * c * d
g = e + f
h = g / c
fn = function([a], h)
fn(np.ones((3,)).astype(a.dtype))

In [ ]:
%load 31_debug_soln.py