In [1]:
%load_ext version_information
%version_information theano, numpy
Out[1]:
Matrix rows are examples/observations. Matrix columns are features/dimensions of the example.
In [2]:
import numpy as np
my_matrix = np.asarray([[1., 2], [3, 4], [5, 6]])
my_matrix
Out[2]:
This is a 3 row, 2 column matrix, as verified with the shape attribute.
In [3]:
my_matrix.shape
Out[3]:
Access elements as you would in R -- matrix[row_index, col_index] -- except that counting starts at 0.
In [4]:
my_matrix[2, 0]
Out[4]:
NumPy does something called broadcasting where it makes a smaller array compatible with a larger array.
Two examples are shown below, along with images from a visual guide to broadcasting.
In [5]:
np.array([1.0, 2.0, 3.0]) * 2
Out[5]:
In the example above, the scalar 2.0 is stretched into a 3-element array. This example is just like c(1, 2, 3) * 2 in R.
In [6]:
a = np.array([[ 0.0, 0.0, 0.0],
[10.0, 10.0, 10.0],
[20.0, 20.0, 20.0],
[30.0, 30.0, 30.0]])
b = np.array([0.0, 1.0, 2.0])
a + b
Out[6]:
This behavior differs from R where it adds the vector columnwise and recycles values:
matrix(rep(0:3 * 10, 3), ncol = 3) + 0:2
# [,1] [,2] [,3] == [,1] [,2] [,3]
# [1,] 0 1 2 == [1,] 0 + 0 1 + 1 2 + 2
# [2,] 11 12 10 == [2,] 10 + 1 12 + 2 10 + 0
# [3,] 22 20 21 == [3,] 22 + 2 20 + 0 21 + 1
# [4,] 30 31 32 == [4,] 30 + 0 31 + 1 32 + 2
That explains why the scalar operation matrix * 2 shows the broadcasting behavior in R: The single value is recycled for each cell in the matrix.
There's a recipe for doing computations in Theano. The tutorial on the website doesn't really emphasize this recipe until the end of the "Baby Steps" tutorial, so I'll put it front and center.
We want to really fast mathematical computations. We use Theano to create these fast functions. There are three steps to making a function:
Now, we have a fast function to do that computation.
Create a function in Theano to add two numbers together.
First, we declare the typed variables. For example, T.dscalar is a 0-dimensional array (scalar) of doubles. Next, we create a symbolic expression for the addition operation, and compile the addition function.
In [7]:
import theano.tensor as T
from theano import function
In [8]:
x = T.dscalar("x")
y = T.dscalar("y")
z = x + y
f = function([x, y], z)
Theano types are not the same as Python classes, although unfortunately we get an object's class by calling the type function.
In [9]:
# the class of x
type(x)
Out[9]:
In [10]:
# the theano type of x
x.type
Out[10]:
When we print z, we see that it describes an operation.
In [11]:
z
Out[11]:
In [12]:
# Use pp to pretty print the computation associated to z
from theano import pp
pp(z)
Out[12]:
We perform the computation in z by wrapping in that function or using its eval method.
In [13]:
f(2, 3)
Out[13]:
In [14]:
f(16.3, 12.1)
Out[14]:
In [15]:
z.eval({x: 3, y: 2})
Out[15]:
In [16]:
x = T.dmatrix("x")
y = T.dmatrix("y")
z = x + y
f = function([x, y], z)
Theano can work 2D arrays or numpy arrays.
In [17]:
f([[1, 2], [3, 4]], [[10, 20], [30, 40]])
Out[17]:
In [18]:
array1 = np.array(range(1, 5)).reshape([2, 2])
array2 = np.array(range(10, 50, 10)).reshape([2, 2])
f(array1, array2)
Out[18]:
In [19]:
a = T.vector()
b = T.vector()
z = a ** 2 + b ** 2 + 2 * a * b
f = function([a, b], z)
f(range(0, 5), range(5, 10))
Out[19]:
This matches the R code solution
a <- 0:4
b <- 5:9
a ^ 2 + b ^ 2 + 2 * a * b
#> [1] 25 49 81 121 169