{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Theano 符号图结构" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "使用 `Theano`,首先要定义符号变量,然后是利用这写符号变量进行计算,这些符号被称为 **`variables`**,而操作 `+, -, **, sum(), tanh()` 被称为 **`ops`**,一个 `op` 操作接受某些类型的输入,并返回某些类型的输出。\n", "\n", "`Theano` 利用这些来构建一个图结构,一个图结构包括:\n", "- **`variable`** 节点\n", "- **`op`** 节点\n", "- **`apply`** 节点\n", "\n", "其中,`apply` 节点用来表示一个特定的 `op` 作用在一些特定的 `variables` 上,例如:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Using gpu device 0: GeForce GTX 850M\n" ] } ], "source": [ "import theano\n", "import theano.tensor as T\n", "\n", "x = T.dmatrix('x')\n", "y = T.dmatrix('y')\n", "z = x + y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "要显示这个图结构可以用 `pydotprint`,先安装 [graphviz](http://www.graphviz.org)。\n", "\n", "`Windows` 下:\n", "\n", "在环境变量 path 后加上:\n", "\n", "- path \n", " - C:\\Program Files (x86)\\Graphviz2.38\\bin\n", "\n", "然后要先安装 `pydot` 包:\n", "\n", "如果你的 `pyparsing >= 2.0` ,则将其降为 `1.5.7`,下载并安装 `pydot-1.0.28`。\n", " \n", "安装完之后,找到 `pydot.py` 将其中:\n", "\n", " graph.append( '%s %s {\\n' % (self.obj_dict['type'], self.obj_dict['name']) )\n", "\n", "修改为:\n", " \n", " graph.append( '%s %s {\\n' % (self.obj_dict['type'], quote_if_necessary(self.obj_dict['name'])) )" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The output file is available at apply1.png\n" ] } ], "source": [ "theano.printing.pydotprint(z, outfile='apply1.png', var_with_name_simple=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "它的图结构如下:\n", "\n", "![图结构1](apply1.png)\n", "\n", "`z` 的 `owner` 是一个 `apply` 结构,其 `op` 为:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Elemwise{add,no_inplace}'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z.owner.op.name" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这个 `apply` 结构的输入值有两个,输出值有一个:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2\n", "1\n" ] } ], "source": [ "print z.owner.nin\n", "print z.owner.nout" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "查看它的输入:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[x, y]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z.owner.inputs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "我们可以用 pprint 来显示它:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(x + y)\n" ] } ], "source": [ "print theano.printing.pprint(z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "用 `debugprint` 显示图结构:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Elemwise{add,no_inplace} [@A] '' \n", " |x [@B]\n", " |y [@C]\n" ] } ], "source": [ "theano.printing.debugprint(z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "再看另一个稍微复杂的例子:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true }, "outputs": [], "source": [ "y = x * 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "查看 `y` 的图谱: " ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Elemwise{mul,no_inplace} [@A] '' \n", " |x [@B]\n", " |DimShuffle{x,x} [@C] '' \n", " |TensorConstant{2} [@D]\n" ] } ], "source": [ "theano.printing.debugprint(y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这里我们看到,`y` 对应的第二个 `input` 并不是 `2`,而是一个 `DimShuffle` 的操作:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y.owner.inputs[1].owner.op" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "它的输入才是常数 2:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[TensorConstant{2}]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y.owner.inputs[1].owner.inputs" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The output file is available at apply2.png\n" ] } ], "source": [ "theano.printing.pydotprint(y, outfile='apply2.png', var_with_name_simple=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "其图结构为\n", "![结构2](apply2.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## function 对图的优化" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = T.dscalar('a')\n", "b = a + a ** 10\n", "\n", "f = theano.function([a], b)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The output file is available at apply_no_opti.png\n", "The output file is available at apply_opti.png\n" ] } ], "source": [ "theano.printing.pydotprint(b, outfile='apply_no_opti.png', var_with_name_simple=True)\n", "theano.printing.pydotprint(f, outfile='apply_opti.png', var_with_name_simple=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "比较一下 `function` 函数对图结构进行的优化:\n", "\n", "未优化前:\n", "\n", "![没有优化](apply_no_opti.png)\n", "\n", "优化后:\n", "\n", "![优化](apply_opti.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 图结构的作用" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 计算按照图结构来计算 \n", "- 优化,求导" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 0 }