<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Theano 
Step1:  Symbolic variables
Rather than manipulate values directly, Theano has to be able to build up the answer from the inputs - so that it can then optimise how to get to the solution (using the CPU or GPU as efficiently as possible).  Therefore, the basic building blocks are 'symbolic variables' (as opposed to variables with concrete values) 
Step2:  Variables can be used in expressions, but (IMPORTANT!) the result is symbolic as well 
Step3:  Investigating expressions
Step4:  Evaluating expressions
Supply a dict mapping variables to values
Step5:  Or compile a function
Step6:  Compiled function has been transformed
Step7:  Other tensor types
Step8:  Numpy style indexing
Step9:  Many functions/operations are available through theano.tensor or variable methods
Step10:  But don't try to use numpy functions on Theano variables. Results may vary!
Automatic differention
Here is why most people want to work the Theano way 
Step11:  Shared Variables
Symbolic + Storage  (key usage
Step12:  We can get and set the variable's value
Step13:  Shared variables can be used in expressions as well
Step14:  Their value is used as input when evaluating
Step15:  Updates
Store results of function evalution
dict mapping shared variables to new values
Main reason for using 
Step16:  Debugging
The message below should give you an idea of how easy this is...
Step17:  THE ABOVE SHOULD BE AN ERROR!
Step18:  THE ABOVE SHOULD BE AN ERROR!
Other Gotchas
Matrix multiply is element-wise...
<ASSISTANT_TASK:>
Python Code:
import theano
import theano.tensor as T
Explanation: Theano : The Basics
Theano is an optimizing compiler for symbolic math expressions.
( Credit for this workbook : Eben Olson :: https://github.com/ebenolson/pydata2015 )
End of explanation
x = T.scalar()
x
Explanation: Symbolic variables
Rather than manipulate values directly, Theano has to be able to build up the answer from the inputs - so that it can then optimise how to get to the solution (using the CPU or GPU as efficiently as possible).  Therefore, the basic building blocks are 'symbolic variables' (as opposed to variables with concrete values) :
End of explanation
y = 3*(x**2) + x
type(y)
Explanation: Variables can be used in expressions, but (IMPORTANT!) the result is symbolic as well :
End of explanation
print(y)
theano.pprint(y)
theano.printing.debugprint(y)
from IPython.display import SVG
SVG(theano.printing.pydotprint(y, return_image=True, format='svg'))
Explanation: Investigating expressions
End of explanation
y.eval({x: 2})
Explanation: Evaluating expressions
Supply a dict mapping variables to values
End of explanation
f = theano.function([x], y)
f(2)
Explanation: Or compile a function
End of explanation
SVG(theano.printing.pydotprint(f, return_image=True, format='svg'))
Explanation: Compiled function has been transformed
End of explanation
X = T.vector()
X = T.matrix()
X = T.tensor3()
X = T.tensor4()
Explanation: Other tensor types
End of explanation
X = T.vector()
X[1:-1:2]
X[ [1,2,3] ]
Explanation: Numpy style indexing
End of explanation
y = X.argmax()
y = T.cosh(X)
y = T.outer(X, X)
Explanation: Many functions/operations are available through theano.tensor or variable methods
End of explanation
x = T.scalar()
y = T.log(x)
gradient = T.grad(y, x)
gradient.eval({x: 2})
Explanation: But don't try to use numpy functions on Theano variables. Results may vary!
Automatic differention
Here is why most people want to work the Theano way : Gradients are free!
End of explanation
import numpy as np
x = theano.shared(np.zeros((2, 3), dtype=theano.config.floatX))
x
Explanation: Shared Variables
Symbolic + Storage  (key usage: computation using the GPU RAM)
End of explanation
values = x.get_value()
print(values.shape)
print(values)
x.set_value(values)
Explanation: We can get and set the variable's value
End of explanation
(x + 2) ** 2
Explanation: Shared variables can be used in expressions as well
End of explanation
((x + 2) ** 2).eval()
theano.function([], (x + 2) ** 2)()
Explanation: Their value is used as input when evaluating
End of explanation
count = theano.shared(0)
new_count = count + 1
updates = {count: new_count}
g = theano.function([], count, updates=updates)
g()
g()
g()
Explanation: Updates
Store results of function evalution
dict mapping shared variables to new values
Main reason for using : iterative methods can use these (and operate entirely within the GPU, since the updates flow 'locally)
End of explanation
x = T.matrix()
y = 3*(x**2) + x
h = theano.function([x], y)
h( 2 )
Explanation: Debugging
The message below should give you an idea of how easy this is...
End of explanation
h( np.array( [ [ 2. ] ] ) )
Explanation: THE ABOVE SHOULD BE AN ERROR!
End of explanation
h( np.array( [ [ 2. ] ], dtype='float32' ) )
h( np.array( [ [ 2., 3. ],  [ 4., 5. ] ], dtype='float32' ) )
h( np.array( [ [ 2., 3., 4. ],  [ 6., 7., 8. ] ], dtype='float32' ) )
Explanation: THE ABOVE SHOULD BE AN ERROR!
Other Gotchas
Matrix multiply is element-wise...
End of explanation
<END_TASK>