From 965e4445255251bb6a2a9628fe26745e85e7f555 Mon Sep 17 00:00:00 2001 From: Arnaud Bergeron Date: Wed, 29 Oct 2014 17:25:21 -0400 Subject: [PATCH] Add C exercice. --- 08_scalmulc/01_scalmulc.py | 33 ++++++++++++++++++++++++++++ 08_scalmulc/01_scalmulc_soln.py | 38 +++++++++++++++++++++++++++++++++ advanced.tex | 25 ++++++++++------------ 3 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 08_scalmulc/01_scalmulc.py create mode 100644 08_scalmulc/01_scalmulc_soln.py diff --git a/08_scalmulc/01_scalmulc.py b/08_scalmulc/01_scalmulc.py new file mode 100644 index 0000000..9a45050 --- /dev/null +++ b/08_scalmulc/01_scalmulc.py @@ -0,0 +1,33 @@ +from theano import Op, Apply +from theano.tensor import as_tensor_variable + +class DoubleC(Op): + __props__ = () + + def make_node(self, x): + x = as_tensor_variable(x) + if x.ndim != 1: + raise TypeError("DoubleC only works on 1D") + return Apply(self, [x], [x.type()]) + + def c_code(self, node, name, input_names, + output_names, sub): + return """ +Py_XDECREF(%(out)s); +%(out)s = (PyArrayObject *)PyArray_NewLikeArray( + %(inp)s, NPY_ANYORDER, NULL, 0); +if (%(out)s == NULL) { + %(fail)s +} +for (npy_intp i = 0; i < PyArray_DIM(%(inp)s, 0); i++) { + *(dtype_%(out)s *)PyArray_GETPTR1(%(out)s, i) = + (*(dtype_%(inp)s *)PyArray_GETPTR1(%(inp)s, i)) * 2; +} +""" % dict(inp=input_names[0], out=output_names[0], + fail=sub["fail"]) + + def infer_shape(self, node, input_shapes): + return input_shapes + + def grad(self, inputs, output_grads): + return [output_grads[0] * 2] diff --git a/08_scalmulc/01_scalmulc_soln.py b/08_scalmulc/01_scalmulc_soln.py new file mode 100644 index 0000000..2aaebd8 --- /dev/null +++ b/08_scalmulc/01_scalmulc_soln.py @@ -0,0 +1,38 @@ +from theano import Op, Apply +from theano.tensor import as_tensor_variable + +class ScalMulC(Op): + __props__ = ('scal') + + def __init__(self, scal): + if not isinstance(scal, int): + raise TypeError('expected an int') + self.scal = scal + + def make_node(self, x): + x = as_tensor_variable(x) + if x.ndim != 1: + raise TypeError("ScalMulC only works on 1D") + return Apply(self, [x], [x.type()]) + + def c_code(self, node, name, input_names, + output_names, sub): + return """ +Py_XDECREF(%(out)s); +%(out)s = (PyArrayObject *)PyArray_NewLikeArray( + %(inp)s, NPY_ANYORDER, NULL, 0); +if (%(out)s == NULL) { + %(fail)s +} +for (npy_intp i = 0; i < PyArray_DIM(%(inp)s, 0); i++) { + *(dtype_%(out)s *)PyArray_GETPTR1(%(out)s, i) = + (*(dtype_%(inp)s *)PyArray_GETPTR1(%(inp)s, i)) * %(scal)d; +} +""" % % dict(inp=input_names[0], out=output_names[0], + fail=sub["fail"], scal=self.scal) + + def infer_shape(self, node, input_shapes): + return input_shapes + + def grad(self, inputs, output_grads): + return [output_grads[0] * self.scal] diff --git a/advanced.tex b/advanced.tex index 235437a..1159425 100644 --- a/advanced.tex +++ b/advanced.tex @@ -168,9 +168,12 @@ \section{How to Make an Op (Python)} \begin{frame}{Exercise: ScalMulOp} \begin{center} -Work though the "06\_scalmulop" directory now. -It is available at \url{https://github.com/abergeron/ccw_tutorial_theano.git}. +Work though the "06\_scalmulop" directory available at \url{https://github.com/abergeron/ccw_tutorial_theano.git}. \end{center} +\begin{itemize} +\item Take the \code{DoubleOp} code and make it work with an arbitrary scalar +\item There are more than one solution possible, both have advantages and disadvantages +\end{itemize} \end{frame} \begin{frame}{\code{infer_shape}} @@ -221,7 +224,7 @@ \section{How to Make an Op (Python)} \end{frame} \begin{frame}{Exercice: Add Special Methods to ScalMulOp} -Work through the "07\_scalmulgrad" directory +Work through the "07\_scalmulgrad" directory available at \url{https://github.com/abergeron/ccw_tutorial_theano.git} \begin{itemize} \item Take the ScalMulOp class you made and add the \code{infer_shape} and \code{grad} methods to it. \item Don't forget to make tests for your new class to make sure everything works correctly. @@ -277,13 +280,6 @@ \section{How to Make an Op (C)} \lstinputlisting[linerange={1-27}]{doublec.py} \end{frame} -\begin{frame}{Exercice: DoubleC} -\begin{itemize} -\item Make a new DoubleC op that only accepts vectors as input using the C code above. -\item Copy and modify the tests for DoubleC. Be sure to check for invalid inputs (matrices). -\end{itemize} -\end{frame} - \begin{frame}{COp} \lstinputlisting{cop.py} \end{frame} @@ -330,11 +326,12 @@ \section{How to Make an Op (C)} \end{itemize} \end{frame} -\begin{frame}{Add C Code to ScalMulOp} +\begin{frame}{Exercice: Add C Code to ScalMulOp} +Work through the "08\_scalmulc" directory available at \url{https://github.com/abergeron/ccw_tutorial_theano.git}. \begin{itemize} -\item Take the ScalMulOp from before and write C code for it using either approach -\item You can base yourself on the C code for DoubleOp -\item Don't forget to test your new implementation +\item Take the ScalMulOp from before and write C code for it using either approach (only accept vectors). +\item You can base yourself on the C code for DoubleOp. +\item Don't forget to test your new implementation! Be sure to check for invalid inputs (matrices). \end{itemize} \end{frame}