{"id":23608667,"url":"https://github.com/hycis/tensorgraph","last_synced_at":"2026-03-15T05:40:52.582Z","repository":{"id":57474178,"uuid":"49113452","full_name":"hycis/TensorGraph","owner":"hycis","description":"A tensorflow library for building all kinds of models","archived":false,"fork":false,"pushed_at":"2021-06-30T04:45:56.000Z","size":5022,"stargazers_count":69,"open_issues_count":1,"forks_count":20,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-23T11:03:47.372Z","etag":null,"topics":["deep-learning","tensorflow"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hycis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-06T04:59:00.000Z","updated_at":"2024-07-11T09:03:15.000Z","dependencies_parsed_at":"2022-09-12T21:01:33.366Z","dependency_job_id":null,"html_url":"https://github.com/hycis/TensorGraph","commit_stats":null,"previous_names":["hycis/tensorgraphx"],"tags_count":62,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hycis%2FTensorGraph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hycis%2FTensorGraph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hycis%2FTensorGraph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hycis%2FTensorGraph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hycis","download_url":"https://codeload.github.com/hycis/TensorGraph/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252875360,"owners_count":21818012,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deep-learning","tensorflow"],"created_at":"2024-12-27T14:39:20.477Z","updated_at":"2026-03-15T05:40:52.523Z","avatar_url":"https://github.com/hycis.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"`master` [![Build Status](http://54.222.242.222:1010/buildStatus/icon?job=TensorGraph/master)](http://54.222.242.222:1010/job/TensorGraph/master)\n`develop` [![Build Status](http://54.222.242.222:1010/buildStatus/icon?job=TensorGraph/develop)](http://54.222.242.222:1010/job/TensorGraph/develop)\n\n\n# TensorGraph\nTensorGraph is a simple, lean, and clean framework on TensorFlow for building any imaginable models.\n\nAs deep learning becomes more and more common and the architectures becoming more\nand more complicated, it seems that we need some easy to use framework to quickly\nbuild these models and that's what TensorGraph is designed for. It's a very simple\nframework that adds a very thin layer above tensorflow. It is for more advanced\nusers who want to have more control and flexibility over his model building and\nwho wants efficiency at the same time.\n\n-----\n## Target Audience\nTensorGraph is targeted more at intermediate to advance users who feel keras or\nother packages is having too much restrictions and too much black box on model\nbuilding, and someone who don't want to rewrite the standard layers in tensorflow\nconstantly. Also for enterprise users who want to share deep learning models\neasily between teams.\n\n-----\n## Install\n\nFirst you need to install [tensorflow](https://www.tensorflow.org/versions/r0.9/get_started/os_setup.html)\n\nTo install tensorgraph for bleeding edge version via pip\n```bash\nsudo pip install --upgrade git+https://github.com/hycis/TensorGraph.git@master\n```\nor simply clone and add to `PYTHONPATH`.\n```bash\ngit clone https://github.com/hycis/TensorGraph.git\nexport PYTHONPATH=/path/to/TensorGraph:$PYTHONPATH\n```\nin order for the install to persist via export `PYTHONPATH`. Add `PYTHONPATH=/path/to/TensorGraph:$PYTHONPATH` to your `.bashrc` for linux or\n`.bash_profile` for mac. While this method works, you will have to ensure that\nall the dependencies in [setup.py](setup.py) are installed.\n\n-----\n## Everything in TensorGraph is about Layers\nEverything in TensorGraph is about layers. A model such as VGG or Resnet can be a layer. An identity block from Resnet or a dense block from Densenet can be a layer as well. Building models in TensorGraph is same as building a toy with lego. For example you can create a new model (layer) by subclass the `BaseModel` layer and use `DenseBlock` layer inside your `ModelA` layer.\n\n```python\nfrom tensorgraph.layers import DenseBlock, BaseModel, Flatten, Linear, Softmax\nimport tensorgraph as tg\nclass ModelA(BaseModel):\n    @BaseModel.init_name_scope\n    def __init__(self):\n        layers = []\n        layers.append(DenseBlock())\n        layers.append(Flatten())\n        layers.append(Linear())\n        layers.append(Softmax())\n        self.startnode = tg.StartNode(input_vars=[None])\n        hn = tg.HiddenNode(prev=[self.startnode], layers=layers)\n        self.endnode = tg.EndNode(prev=[hn])\n```\n\nif someone wants to use your `ModelA` in his `ModelB`, he can easily do this\n```python\nclass ModelB(BaseModel):\n    @BaseModel.init_name_scope\n    def __int__(self):\n        layers = []\n        layers.append(ModelA())\n        layers.append(Linear())\n        layers.append(Softmax())\n        self.startnode = tg.StartNode(input_vars=[None])\n        hn = tg.HiddenNode(prev=[self.startnode], layers=layers)\n        self.endnode = tg.EndNode(prev=[hn])\n```\n\ncreating a layer only created all the `Variables`. To connect the `Variables` into a graph, you can do a `train_fprop(X)` or `test_fprop(X)` to create the tensorflow graph. By abstracting `Variable` creation away from linking the `Variable` nodes into graph prevent the problem of certain tensorflow layers that always reinitialise its weights when it's called, example the [`tf.nn.batch_normalization`](https://www.tensorflow.org/api_docs/python/tf/nn/batch_normalization) layer. Also having a separate channel for training and testing is to cater to layers with different training and testing behaviours such as batchnorm and dropout.\n\n```python\nmodelb = ModelB()\nX_ph = tf.placeholder()\ny_train = modelb.train_fprop(X_ph)\ny_test = modelb.test_fprop(X_ph)\n```\n\ncheckout some well known models in TensorGraph\n1. [VGG16 code](tensorgraph/layers/backbones.py#L37) and [VGG19 code](tensorgraph/layers/backbones.py#L125) - [Very Deep Convolutional Networks for Large-Scale Image Recognition](https://arxiv.org/abs/1409.1556)\n2. [DenseNet code](tensorgraph/layers/backbones.py#L477) - [Densely Connected Convolutional Networks](https://arxiv.org/abs/1608.06993)\n3. [ResNet code](tensorgraph/layers/backbones.py#L225) - [Deep Residual Learning for Image Recognition](https://arxiv.org/abs/1512.03385)\n4. [Unet code](tensorgraph/layers/backbones.py#L531) - [U-Net: Convolutional Networks for Biomedical Image Segmentation](https://arxiv.org/abs/1505.04597)\n\n-----\n## Type of Layers\nThere are three types of layers, `BaseLayer`, `BaseModel` and `Merge`.\n\n### BaseLayer\n`BaseLayer` is a low lying layer that wraps tensorflow codes directly, and define\nthe low level operations that we want the tensorflow to perform within a layer.\nWhen implementing `BaseLayer` we need to implement `_train_fprop()` and `_test_fprop()`,\nby default `_test_fprop()` calls `_train_fprop()`.\n\n```python\nclass MyLayer(BaseLayer):\n\n    @BaseLayer.init_name_scope\n    def __init__(self):\n        ''' place all your variables and variables initialization here. '''\n        pass\n\n    @BaseLayer.init_name_scope\n    def __init_var__(self, state_below):\n        '''Define variables which requires input information from state_below,\n           this is called during forward propagation\n        '''\n        pass\n\n    def _train_fprop(self, state_below):\n        '''\n        your tensorflow operations for training,\n        do not initialize variables here.\n        '''\n        pass\n\n    def _test_fprop(self, state_below):\n        '''\n        your tensorflow operations for testing, do not initialize variables\n        here. Defaults to _train_fprop.\n        '''\n        pass\n```\n\nTo use `BaseLayer`, we can initialize the `Variables` inside ```__init__``` and/or\n```__init_var__(self, state_below)``` if our layer requires information from the\nlayer below.\n\n\n### BaseModel\n`BaseModel` is a higher level layer that can be made up of BaseLayers and\nBaseModels. For BaseModel, a default implementation of `_train_fprop`\nand `_test_fprop` has been done for a single `StartNode` and single `EndNode`\nGraph, to use this default implementation, we have to define `self.startnode`\nand `self.endnode` inside BaseModel's ```__init__```.\n\nFor Graph defined inside `BaseModel`, `BaseModel` will automatically call\nthe `_train_fprop` and `_test_fprop` within each layer inside its model.\n\n```python\nclass MyLayer(BaseModel):\n    def __init__(self):\n        '''\n         place all your layers inside here and define self.startnode and\n         self.endnode\n         example:\n           layers = []\n           layers.append(DenseBlock())\n           layers.append(Flatten())\n           layers.append(Linear())\n           layers.append(Softmax())\n           self.startnode = tg.StartNode(input_vars=[None])\n           hn = tg.HiddenNode(prev=[self.startnode], layers=layers)\n           self.endnode = tg.EndNode(prev=[hn])\n        '''\n        pass\n```\nIt is possible for BaseModel to return multiple outputs, example\n```python\nclass MyLayerFork(BaseModel):\n\n    @BaseModel.init_name_scope\n    def __init__(self):\n       # a Y shape model, where we have one input and two outputs\n       self.startnode = tg.StartNode(input_vars=[None])\n       # first fork output\n       layers = []\n       layers.append(Linear())\n       layers.append(Softmax())\n       hn = tg.HiddenNode(prev=[self.startnode], layers=layers)\n\n       # second fork output\n       layers2 = []\n       layers2.append(Linear())\n       layers2.append(Softmax())\n       hn2 = tg.HiddenNode(prev=[self.startnode], layers=layers2)\n\n       # two forks outputs\n       self.endnode = tg.EndNode(prev=[hn, h2])\n```\nIn this case, a call to `train_fprop` will return two outputs\n```python\nmylayer = MylayerFork()\ny1, y2 = mylayer.train_fprop(X_ph)\n```\n\n#### Customize inputs and outputs for BaseModel\n\nAnother way to customize your own inputs and outputs is to redefine `_train_fprop`\nand `_test_fprop` within `BaseModel`.\n\nThe default `_train_fprop` and `_test_fprop` in `BaseModel` looks like this\n\n```python\nclass BaseModel(Template):\n\n    @staticmethod\n    def check_y(y):\n        if len(y) == 1:\n            return y[0]\n        elif len(y) \u003e 1:\n            return y\n        else:\n            raise Exception('{} is empty or not a list'.format(y))\n\n\n    def _train_fprop(self, *state_belows):\n        self.startnode.input_vars = state_belows\n        graph = Graph(start=[self.startnode], end=[self.endnode])\n        y = graph.train_fprop()\n        return BaseModel.check_y(y)\n\n\n    def _test_fprop(self, *state_belows):\n        self.startnode.input_vars = state_belows\n        graph = Graph(start=[self.startnode], end=[self.endnode])\n        y = graph.test_fprop()\n        return BaseModel.check_y(y)\n```\n\nfor the `MyLayerFork` Model, for two inputs and two outputs, we can redefine it\nwith multiple `StartNodes` and `EndNodes` within `_train_fprop` and `_test_fprop`.\n\n```python\nclass MyLayerFork(BaseModel):\n\n    @BaseModel.init_name_scope\n    def __init__(self):\n       # multiple inputs and multiple outputs\n\n       self.startnode1 = tg.StartNode(input_vars=[None])\n       self.startnode2 = tg.StartNode(input_vars=[None])\n\n       layers1 = []\n       layers1.append(Linear())\n       layers1.append(Softmax())\n       hn1 = tg.HiddenNode(prev=[self.startnode1], layers=layers)\n\n       layers2 = []\n       layers2.append(Linear())\n       layers2.append(Softmax())\n       hn2 = tg.HiddenNode(prev=[self.startnode2], layers=layers2)\n\n       # two forks outputs\n       self.endnode1 = tg.EndNode(prev=[hn1])\n       self.endnode2 = tg.EndNode(prev=[hn2])\n\n\n     def _train_fprop(self, input1, input2):\n         self.startnode1.input_vars = [input1]\n         self.startnode2.input_vars = [input2]\n         graph = Graph(start=[self.startnode1, self.startnode2], end=[self.endnode1, self.endnode2])\n         y = graph.train_fprop()\n         return BaseModel.check_y(y)\n\n\n     def _test_fprop(self, input1, input2):\n         self.startnode1.input_vars = [input1]\n         self.startnode2.input_vars = [input2]\n         graph = Graph(start=[self.startnode1, self.startnode2], end=[self.endnode1, self.endnode2])\n         y = graph.test_fprop()\n         return BaseModel.check_y(y)\n\n\nif __name__ == '__main__':\n    model = MyLayerFork()\n    y1, y2 = model.train_fprop(X1, X2)\n```\n\n\n### Merge\nWhen we have more than one outputs from previous layer and we want to merge them,\nwe can use the `Merge` layer in [tensorgraph.layers.merge.Merge](./tensorgraph/layers/merge.py)\nto merge multiple inputs into one.\n\n```python\nclass Concat(Merge):\n    @Merge.init_name_scope\n    def __init__(self, axis=1):\n        '''\n        Concat which is a Merge layer is used to concat the list of states from\n        layer below into one state\n        '''\n        self.axis = axis\n\n    def _train_fprop(self, state_list):\n        return tf.concat(axis=self.axis, values=state_list)\n```\n\nWe can use `Merge` layer in conjunction with `BaseModel` layer with multiple outputs,\nexample\n\n```python\nclass MyLayerMergeFork(BaseModel):\n    def __init__(self):\n        layers = []\n        # fork layer from above example\n        layers.append(MyLayerFork())\n        # merge layer\n        layers.append(Concat())\n        self.startnode = tg.StartNode(input_vars=[None])\n        hn = tg.HiddenNode(prev=[self.startnode], input_merge_mode=NoChange(), layers=layers)\n        self.endnode = tg.EndNode(prev=[hn])\n```\n\n-----\n## How TensorGraph Works?\nIn TensorGraph models, layers are put into nodes and nodes are connected together\ninto graph. When we create nodes and layers, we also initializes all the tensorflow\n`Variables`, then we connect the nodes together to form a computational graph.\nThe initialization of `Variables` and the linking of `Variables` into a computational\ngraph are two separate steps. By splitting them into two separate steps, we ensure\nthe flexibility of building our computational graph without the worry of accidental\nreinitialization of the `Variables`.\nWe defined three types of nodes\n\n1. StartNode : for inputs to the graph\n2. HiddenNode : for putting sequential layers inside\n3. EndNode : for getting outputs from the model\n\nWe put all the sequential layers into a `HiddenNode`, `HiddenNode` can be connected\nto another `HiddenNode` or `StartNode`, the nodes are connected together to form\nan architecture. The graph always starts with `StartNode` and ends with `EndNode`.\nOnce we have defined an architecture, we can use the `Graph` object to connect the\npath we want in the architecture, there can be multiple StartNodes (s1, s2, etc)\nand multiple EndNodes (e1, e2, etc), we can define which path we want in the\nentire architecture, example to link from `s2` to `e1`. The `StartNode` is where you place\nyour starting point, it can be a `placeholder`, a symbolic output from another graph,\nor data output from `tfrecords`. `EndNode` is where you want to get an output from\nthe graph, where the output can be used to calculate loss or simply just a peek at the\noutputs at that particular layer. Below shows an\n[example](examples/example.py) of building a tensor graph.\n\n-----\n## Graph Example\n\u003cimg src=\"draw/graph.png\" height=\"250\"\u003e\n\nFirst define the `StartNode` for putting the input placeholder\n```python\ny1_dim = 50\ny2_dim = 100\nbatchsize = 32\nlearning_rate = 0.01\n\ny1 = tf.placeholder('float32', [None, y1_dim])\ny2 = tf.placeholder('float32', [None, y2_dim])\ns1 = StartNode(input_vars=[y1])\ns2 = StartNode(input_vars=[y2])\n```\nThen define the `HiddenNode` for putting the sequential layers in each `HiddenNode`\n```python\nh1 = HiddenNode(prev=[s1, s2],\n                input_merge_mode=Concat(),\n                layers=[Linear(y2_dim), RELU()])\nh2 = HiddenNode(prev=[s2],\n                layers=[Linear(y2_dim), RELU()])\nh3 = HiddenNode(prev=[h1, h2],\n                input_merge_mode=Sum(),\n                layers=[Linear(y1_dim), RELU()])\n                layers=[Linear(y1_dim+y2_dim, y2_dim), RELU()])\nh2 = HiddenNode(prev=[s2],\n                layers=[Linear(y2_dim, y2_dim), RELU()])\nh3 = HiddenNode(prev=[h1, h2],\n                input_merge_mode=Sum(),\n                layers=[Linear(y2_dim, y1_dim), RELU()])\n```\nThen define the `EndNode`. `EndNode` is used to back-trace the graph to connect\nthe nodes together.\n```python\ne1 = EndNode(prev=[h3])\ne2 = EndNode(prev=[h2])\n```\nFinally build the graph by putting `StartNodes` and `EndNodes` into `Graph`, we\ncan choose to use the entire architecture by using all the `StartNodes` and `EndNodes`\nand run the forward propagation to get symbolic output from train mode. The number\nof outputs from `graph.train_fprop` is the same as the number of `EndNodes` put\ninto `Graph`\n```python\ngraph = Graph(start=[s1, s2], end=[e1, e2])\no1, o2 = graph.train_fprop()\n```\nor we can choose which node to start and which node to end, example\n```python\ngraph = Graph(start=[s2], end=[e1])\no1, = graph.train_fprop()\n```\nFinally build an optimizer to optimize the objective function\n```python\no1_mse = tf.reduce_mean((y1 - o1)**2)\no2_mse = tf.reduce_mean((y2 - o2)**2)\nmse = o1_mse + o2_mse\noptimizer = tf.train.AdamOptimizer(learning_rate).minimize(mse)\n```\n\n-----\n## TensorGraph on Multiple GPUS\nTo use tensorgraph on multiple gpus, you can easily integrate it with [horovod](https://github.com/uber/horovod).\n\n```python\nimport horovod.tensorflow as hvd\nfrom tensorflow.python.framework import ops\nimport tensorflow as tf\nhvd.init()\n\n# tensorgraph model derived previously\nmodelb = ModelB()\nX_ph = tf.placeholder()\ny_ph = tf.placeholder()\ny_train = modelb.train_fprop(X_ph)\ny_test = modelb.test_fprop(X_ph)\n\ntrain_cost = mse(y_train, y_ph)\ntest_cost = mse(y_test, y_ph)\n\nopt = tf.train.RMSPropOptimizer(0.001)\nopt = hvd.DistributedOptimizer(opt)\n\n# required for BatchNormalization layer\nupdate_ops = ops.get_collection(ops.GraphKeys.UPDATE_OPS)\nwith ops.control_dependencies(update_ops):\n    train_op = opt.minimize(train_cost)\n\ninit_op = tf.group(tf.global_variables_initializer(),\n                   tf.local_variables_initializer())\nbcast = hvd.broadcast_global_variables(0)\n\n# Pin GPU to be used to process local rank (one GPU per process)\nconfig = tf.ConfigProto()\nconfig.gpu_options.allow_growth = True\nconfig.gpu_options.visible_device_list = str(hvd.local_rank())\n\nwith tf.Session(graph=graph, config=config) as sess:\n    sess.run(init_op)\n    bcast.run()\n\n    # training model\n    for epoch in range(100):\n        for X,y in train_data:\n            _, loss_train = sess.run([train_op, train_cost], feed_dict={X_ph:X, y_ph:y})\n```\n\nfor a full example on [tensorgraph on horovod](./examples/multi_gpus_horovod.py)\n\n-----\n## Hierachical Softmax Example\nBelow is another example for building a more powerful [hierachical softmax](examples/hierachical_softmax.py)\nwhereby the lower hierachical softmax layer can be conditioned on all the upper\nhierachical softmax layers.\n\n\u003cimg src=\"draw/hsoftmax.png\" height=\"250\"\u003e\n\n```python\n## params\nx_dim = 50\ncomponent_dim = 100\nbatchsize = 32\nlearning_rate = 0.01\n\n\nx_ph = tf.placeholder('float32', [None, x_dim])\n# the three hierachical level\ny1_ph = tf.placeholder('float32', [None, component_dim])\ny2_ph = tf.placeholder('float32', [None, component_dim])\ny3_ph = tf.placeholder('float32', [None, component_dim])\n\n# define the graph model structure\nstart = StartNode(input_vars=[x_ph])\n\nh1 = HiddenNode(prev=[start], layers=[Linear(component_dim), Softmax()])\nh2 = HiddenNode(prev=[h1], layers=[Linear(component_dim), Softmax()])\nh3 = HiddenNode(prev=[h2], layers=[Linear(component_dim), Softmax()])\nh1 = HiddenNode(prev=[start], layers=[Linear(x_dim, component_dim), Softmax()])\nh2 = HiddenNode(prev=[h1], layers=[Linear(component_dim, component_dim), Softmax()])\nh3 = HiddenNode(prev=[h2], layers=[Linear(component_dim, component_dim), Softmax()])\n\n\ne1 = EndNode(prev=[h1], input_merge_mode=Sum())\ne2 = EndNode(prev=[h1, h2], input_merge_mode=Sum())\ne3 = EndNode(prev=[h1, h2, h3], input_merge_mode=Sum())\n\ngraph = Graph(start=[start], end=[e1, e2, e3])\n\no1, o2, o3 = graph.train_fprop()\n\no1_mse = tf.reduce_mean((y1_ph - o1)**2)\no2_mse = tf.reduce_mean((y2_ph - o2)**2)\no3_mse = tf.reduce_mean((y3_ph - o3)**2)\nmse = o1_mse + o2_mse + o3_mse\noptimizer = tf.train.AdamOptimizer(learning_rate).minimize(mse)\n```\n\n-----\n## Transfer Learning Example\nBelow is an example on transfer learning with bi-modality inputs and merge at\nthe middle layer with shared representation, in fact, TensorGraph can be used\nto build any number of modalities for transfer learning.\n\n\u003cimg src=\"draw/transferlearn.png\" height=\"250\"\u003e\n\n```python\n## params\nx1_dim = 50\nx2_dim = 100\nshared_dim = 200\ny_dim = 100\nbatchsize = 32\nlearning_rate = 0.01\n\n\nx1_ph = tf.placeholder('float32', [None, x1_dim])\nx2_ph = tf.placeholder('float32', [None, x2_dim])\ny_ph = tf.placeholder('float32', [None, y_dim])\n\n# define the graph model structure\ns1 = StartNode(input_vars=[x1_ph])\ns2 = StartNode(input_vars=[x2_ph])\n\nh1 = HiddenNode(prev=[s1], layers=[Linear(shared_dim), RELU()])\nh2 = HiddenNode(prev=[s2], layers=[Linear(shared_dim), RELU()])\nh3 = HiddenNode(prev=[h1,h2], input_merge_mode=Sum(),\n                layers=[Linear(y_dim), Softmax()])\nh1 = HiddenNode(prev=[s1], layers=[Linear(x1_dim, shared_dim), RELU()])\nh2 = HiddenNode(prev=[s2], layers=[Linear(x2_dim, shared_dim), RELU()])\nh3 = HiddenNode(prev=[h1,h2], input_merge_mode=Sum(),\n                layers=[Linear(shared_dim, y_dim), Softmax()])\n\ne1 = EndNode(prev=[h3])\n\ngraph = Graph(start=[s1, s2], end=[e1])\no1, = graph.train_fprop()\n\nmse = tf.reduce_mean((y_ph - o1)**2)\noptimizer = tf.train.AdamOptimizer(learning_rate).minimize(mse)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhycis%2Ftensorgraph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhycis%2Ftensorgraph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhycis%2Ftensorgraph/lists"}