Source-to-Source Debuggable Derivatives in Pure Python

Overview

Tangent

Build Status Join the chat at https://gitter.im/google/tangent

Tangent is a new, free, and open-source Python library for automatic differentiation.

Existing libraries implement automatic differentiation by tracing a program's execution (at runtime, like PyTorch) or by staging out a dynamic data-flow graph and then differentiating the graph (ahead-of-time, like TensorFlow). In contrast, Tangent performs ahead-of-time autodiff on the Python source code itself, and produces Python source code as its output. Tangent fills a unique location in the space of machine learning tools.

Autodiff Tool Space

As a result, you can finally read your automatic derivative code just like the rest of your program. Tangent is useful to researchers and students who not only want to write their models in Python, but also read and debug automatically-generated derivative code without sacrificing speed and flexibility.

Tangent works on a large and growing subset of Python, provides extra autodiff features other Python ML libraries don't have, has reasonable performance, and is compatible with TensorFlow and NumPy.

This project is an experimental release, and is under active development. As we continue to build Tangent, and respond to feedback from the community, there might be API changes.

Usage

Note: An interactive notebook with all the code in this page can be found here.

Tangent has a one-function API:

import tangent
df = tangent.grad(f)

If you want to print out derivatives at the time Tangent generates the derivative function:

import tangent
df = tangent.grad(f, verbose=1)

Here's Tangent in action in the IPython console.

Live Derivatives with Tangent

Installing and running

Installation

The easiest way to install Tangent is to use pip.

pip install tangent

We'll have a conda package soon.

Automatic Differentiation

Under the hood, tangent.grad grabs the source code of the Python function you pass it (using inspect.getsource, which is available in the Python standard library), converts the source code into an abstract syntax tree (AST) using ast.parse (also built into the Python standard library), and walks the syntax tree in reverse order.

Tangent has a library of recipes for the derivatives of basic arithmetic (+,-,/,**,*), pieces of syntax (ast.For, ast.If, ast.While) and TensorFlow Eager functions (tf.reduce_sum, tf.exp, tf.matmul, ... ). For each piece of syntax it encounters (for example, c = a + b is a single AST node ast.Assign), tangent.grad looks up the matching backward-pass recipe, and adds it to the end of the derivative function. This reverse-order processing gives the technique its name: reverse-mode automatic differentiation.

TF Eager

Tangent supports differentiating functions that use TensorFlow Eager functions that are composed together.

def f(W,x):
  h1 = tf.matmul(x,W)
  h2 = tf.tanh(h1)
  out = tf.reduce_sum(h2)
  return out

dfdW = tangent.grad(f)

SCT on TF Eager

Subroutines

When model code becomes long, using subroutines makes code more readable and reusable. Tangent handles taking derivatives of models that have user-defined functions.

SCT on Subroutines

Control Flow

Tangent has recipes for auto-generating derivatives for code that contains if statements and loops:

SCT on Conditionals

You'll notice above that we have to modify the user's code to keep track of information that we will need in the backward pass. For instance, we need to save which branch of an if-statement was followed in the forward pass, so that we run the correct branch in the backward pass. We save this information from the forward pass by pushing it onto a stack, which we then pop off in the backward pass. This is an important data structure in ahead-of-time autodiff.

For loops require a little more bookkeeping. Tangent has to save the number of iterations of the loop on the stack. Also, loops usually overwrite the values of variables inside the loop body. In order to generate a correct derivative, Tangent has to keep track of all of the overwritten values, and restore them in the backward pass in the correct order.

SCT on Loops

Custom Gradients

Tangent uses Python's built-in machinery to introspect and transform the abstract syntax tree (AST) of parsed source code at runtime. For each piece of supported Python syntax, we have implemented a rule indicating how to rewrite an AST node into its backward pass equivalent, or "adjoint". We have defined adjoints for function calls to NumPy and TF Eager methods, as well as larger pieces of syntax, such as if-statements and for-loops. The adjoints are stored in function definitions that serve as "templates", or code macros. Another alternative, which we found too cumbersome, would be to use a templating engine like Mustache and store adjoints as plain strings. Our templates also use a special syntax d[x] to refer to the derivative of a variable x.

While differentiating a function, if Tangent encounters a function call, it first checks if it has a gradient registered for that function. If not, it tries to get the function source, and generate a derivative ahead-of-time. But, it's easy to register your own gradients. Here's a toy example of defining the gradient of x^3.

import tangent
from tangent.grads import adjoint

def cube(x):
  return x * x * x
  
# Register the gradient of cube with Tangent
# NOTE! This is not a runnable function, but instead is a code template.
# Tangent will replace the names of the variables `result` and `x` with whatever
# is used in your containing function.
@adjoint(cube)
def dcube(result, x):
  d[x] = d[result] * 3 * x * x
  
def f(val):
    cubed_val = cube(val)
    return cubed_val

print(tangent.grad(f,verbose=1))

Should output something like:

def dfdval(val, bcubed_val=1.0):
    # Grad of: cubed_val = cube(val)
    bval = bcubed_val * 3 * (val * val) # <<<< this is our inlined gradient
    return bval

The signature for the custom gradient of some function

result = orig_function(arg1,arg2)

is

@adjoint(orig_function)
def grad_orig_function(result, arg1, arg2):
  d[arg1] = d[result]*...
  d[arg2] = d[result]*...

The first argument to the template is always the result of the function call, followed by the function arguments, in order. Tangent captures the variable names of the result and arguments, and then will use them to unquote the gradient template at the appropriate place in the backward pass.

Check out an example gradient definition of a NumPy function and of a TF eager function. Also, see the docstring in grads.py for more info.

Debugging

Because Tangent auto-generates derivative code you can read, you can also easily debug your backward pass. For instance, your NN might be outputting NaNs during training, and you want to find out where the NaNs are being generated in your model. Just insert a breakpoint (e.g., pdb.set_trace()) at the end of your forward pass.

SCT for Debugging

For large models, setting a breakpoint at the beginning of the backward pass and stepping through dozens of lines might be cumbersome. Instead, you might want the breakpoint to be placed later in the derivative calculation. Tangent lets you insert code directly into any location in the backward pass. First, run from tangent import insert_grad_of, then add a with insert_grad_of block containing the code you'd like to insert into the backward pass.

from tangent import insert_grad_of
def f(x):
  ...
  with insert_grad_of(x) as dx:
    print("dc/dx = %2.2f" % dx)
    pdb.set_trace()
  ...

Ad Hoc Gradient Code

Derivative Surgery

You can use the insert_grad_of feature to do more than debugging and logging. Some NN architectures benefit from tricks that directly manipulate the backward pass. For example, recurrent neural networks (RNNs) suffer from the "exploding gradient" problem, where gradients grow exponentially. This prevents the model from training properly. A typical solution is to force the derivatives inside of an RNN to not exceed a certain value by directly clipping them. We can implement this with insert_grad_of.

def f(params, x):
  h = x
  for i in range(5):
    with insert_grad_of(h) as g:
      g = tf.clip_by_value(g, -1, 1)
    h = rnn(params, h)
  return h

dfdparams = tangent.grad(f)

You can perform other backward-pass tricks with insert_grad_of, such as stop gradients (use a break in the inlined code to stop a for loop), or synthetic gradients (replace a derivative with a prediction from a neural network). This feature lets Tangent users easily debug their models, or quickly try out derivative tweaks in the backward pass.

Forward Mode

Reverse-mode autodiff, or backpropagation, generates efficient derivatives for the types of functions we use in machine learning, where there are usually many (perhaps millions) of input variables and only a single output (our loss). When the inverse is true, where there are many more outputs than inputs, reverse mode is not an efficient algorithm, as it has to be run as many times as there are output variables. However, a less famous algorithm, forward-mode autodiff, only has to be run as many times as there are input variables.). Tangent supports forward-mode autodiff.

def f(x):
  a = x * x
  b = x * a
  c = a + b
  return c

forward_df = tangent.autodiff(f, mode='forward')

SCT Forward Mode

Hessian-Vector Products

Although we won't dig into the technical details, forward-mode is very useful when combined with reverse-mode to calculate efficient higher-order derivatives, particularly for Hessian-vector products (HVP) of NNs. This is useful in research applications, and usually very painful and slow to calculate. Autograd has native forward-mode support, while TensorFlow has 3rd-party support.

To take higher-order derivatives, you can use any combination of forward- and reverse-mode autodiff in Tangent. This works because the code Tangent produces can also be fed back in as input. The autodiff literature recommends calculating HVPs in a "Forward-over-Reverse" style. This means first apply reverse mode autodiff to the function, and then apply forward mode to that.

def f(x):
    a = x * x * x
    b = a * x ** 2.0
    return tf.reduce_sum(b)

hvp = tangent.autodiff(tangent.autodiff(f,mode='reverse'),mode='forward')

Performance

Although we did not build Tangent for performance, it is competitive with major ML libraries. Because we are generating derivatives ahead-of-time, there is no interpretive overhead like there is with runtime autodiff libraries. We implemented a few compiler optimizations (dead code elimination, and constant folding), but we are still working on extra optimization passes to further increase performance.

Small Benchmark

Optimization

We are often interested in the gradients of only some of the arguments. In this case, many of the adjoint calculation might be dead code. In the optimization pass this is removed. We also perform limited constant folding and assignment propagation.

Known Limitations

Tangent is still an experiment, so expect some bugs. If you report them to us on GitHub, we will do our best to fix them quickly.

We are working to add support in Tangent for more aspects of the Python language (e.g., closures, inline function definitions, classes, more NumPy and TensorFlow functions). We also hope to add more advanced automatic differentiation and compiler functionality in the future, such as automatic trade-off between memory and compute (Griewank and Walther 2000; Gruslys et al., 2016), more aggressive optimizations, and lambda lifting.

Many of Python's advanced features are difficult to statically analyze or to define sensible gradients of, so we restrict Python to a functional subset (i.e. no mutable objects).

Closures

Closures are currently not supported for the following reasons:

  • AD relies on being able to resolve function names. If function names are resolved using the enclosing function namespace, we cannot be sure that they will resolve to the same function at each call.
  • Although we can access functions from the enclosing function namespace, we cannot write to this namespace, which is required for the gradients.

Classes

Classes are not currently supported, but are on our near-term roadmap. This will enable PyTorch/Chainer/TFEager-style class definitions of neural networks, and parameterized functions, like in TF Slim.

Team

Tangent is developed by Alex Wiltschko, Bart van Merrienboer and Dan Moldovan.

Comments
  • gradients are inconsistently vectorized

    gradients are inconsistently vectorized

    Sometimes gradients are vectorized, and sometimes they are not. Consider this example where the gradient is vectorized (ie. array in, array of derivatives out).

    def f(x):
        return x**2
    
    df = tangent.grad(f)
    
    print(df(np.array([0, 1, 2])))
    

    This comes out like I would expect.

    :RESULTS: [ 0. 2. 4.] :END:

    Compare it to this:

    def f1(x):
        return x + 2.0 * np.cos(x)
    # df/dx = 1 - 2*sin(x)
    
    df1 = tangent.grad(f1)
    
    x = np.array([0.0, 1.0, 2.0])
    print(df1(x)) # It is not clear this is even correct.
    print(1 - 2 * np.sin(x))
    
    # A vectorized version
    df1v = np.vectorize(tangent.grad(f1))
    print(df1v(np.array([0, 1, 2])))
    

    :RESULTS: -2.50153682327 [ 1. -0.68294197 -0.81859485] [ 1. -0.68294197 -0.81859485]

    :END:

    It is not clear that df1 even returns the right answer for the array.

    This seems important because an obvious thing one might want to do is pass the tangent.grad function to scipy.optimize.fsolve. But fsolve requires the fprime function to take array arguments, and return an array of derivatives.

    opened by jkitchin 9
  • Can't import

    Can't import "make_vjp"

    I pip installed tangent and can't get it to import. I think this has to do with upgrading tensorflow to 1.4 though not sure.

    Mac Os Sierra 10.12.6 Python 3.6 Tensorflow 1.4.0

    Running in Jupyter notebook (or ipython)

    ImportError                               Traceback (most recent call last)
    <ipython-input-1-b7bc666cce03> in <module>()
    ----> 1 import tangent
    
    /Users/rick.shapiro/anaconda/lib/python3.6/site-packages/tangent/__init__.py in <module>()
         18 import gast
         19 
    ---> 20 from tangent import annotate
         21 from tangent import ast as ast_
         22 from tangent import compile as compile_
    
    /Users/rick.shapiro/anaconda/lib/python3.6/site-packages/tangent/annotate.py in <module>()
         27 from tangent import cfg
         28 from tangent import quoting
    ---> 29 from tangent import tracing
         30 from tangent import utils
         31 
    
    /Users/rick.shapiro/anaconda/lib/python3.6/site-packages/tangent/tracing.py in <module>()
         14 """Utilities for tracing code, a useful fallback when ahead-of-time AD fails.
         15 """
    ---> 16 from tensorflow.python.eager.backprop import make_vjp
         17 
         18 
    
    ImportError: cannot import name 'make_vjp'
    
    opened by rshap91 7
  • UnicodeDecodeError: 'gbk' codec can't decode byte 0x9d in position 6304: illegal multibyte sequence

    UnicodeDecodeError: 'gbk' codec can't decode byte 0x9d in position 6304: illegal multibyte sequence

    Environment: Windows 7 Python: 3.6.2

    pip installation failed.

    Collecting tangent
      Using cached tangent-0.1.0.tar.gz
        Complete output from command python setup.py egg_info:
        Traceback (most recent call last):
          File "<string>", line 1, in <module>
          File "C:\Users\ADMINI~1\AppData\Local\Temp\pip-build-k2pei7vz\tangent\setu
    p.py", line 5, in <module>
            readme = f.read()
        UnicodeDecodeError: 'gbk' codec can't decode byte 0x9d in position 6304: ill
    egal multibyte sequence
    
        ----------------------------------------
    Command "python setup.py egg_info" failed with error code 1 in C:\Users\ADMINI~1
    \AppData\Local\Temp\pip-build-k2pei7vz\tangent\
    
    opened by Watesoyan 7
  • The newly released tf-nightly is incompatible with 'gast=0.2.2'

    The newly released tf-nightly is incompatible with 'gast=0.2.2'

    In the environment.yml, it require that 'tf-nightly == 1.5.0.dev20171026'. The tf-nightly 1.x is no longer available. And the newest released tf-nightly 2.2.0 is only compatible with 'gast==0.3.3', which gives rise to the problem of #97 . But the solution 'pinning the gast < 0.3.0' disables tf-nightly 2.2.0.

    I tried install the gast 0.2.2, and used tensorflow 2.1.0 instead of tf-nightly 2.2.0. But it then occured the problem #95 and then #99 , which causes failure while importing tangent.

    Thus I wonder if there is any simpler and executable way to solve this problem.

    opened by Sijie-L 6
  • Error when importing Tangent - Failed to load the native TensorFlow runtime.

    Error when importing Tangent - Failed to load the native TensorFlow runtime.

    Problem

    I get the following error when running import tangent in Python 3.6:

    In [1]: import tangent
    ---------------------------------------------------------------------------
    ImportError                               Traceback (most recent call last)
    ~/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/pywrap_tensorflow.py in <module>()
         57
    ---> 58   from tensorflow.python.pywrap_tensorflow_internal import *
         59   from tensorflow.python.pywrap_tensorflow_internal import __version__
    
    ~/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/pywrap_tensorflow_internal.py in <module>()
         27             return _mod
    ---> 28     _pywrap_tensorflow_internal = swig_import_helper()
         29     del swig_import_helper
    
    ~/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/pywrap_tensorflow_internal.py in swig_import_helper()
         23             try:
    ---> 24                 _mod = imp.load_module('_pywrap_tensorflow_internal', fp, pathname, description)
         25             finally:
    
    ~/.conda/envs/py36/lib/python3.6/imp.py in load_module(name, file, filename, details)
        242         else:
    --> 243             return load_dynamic(name, filename, file)
        244     elif type_ == PKG_DIRECTORY:
    
    ~/.conda/envs/py36/lib/python3.6/imp.py in load_dynamic(name, path, file)
        342             name=name, loader=loader, origin=path)
    --> 343         return _load(spec)
        344
    
    ImportError: /usr/lib64/libstdc++.so.6: version `CXXABI_1.3.7' not found (required by /home/pauperei/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/_pywrap_tensorflow_internal.so)
    
    During handling of the above exception, another exception occurred:
    
    ImportError                               Traceback (most recent call last)
    <ipython-input-1-b7bc666cce03> in <module>()
    ----> 1 import tangent
    
    ~/.conda/envs/py36/lib/python3.6/site-packages/tangent/__init__.py in <module>()
         18 import gast
         19
    ---> 20 from tangent import annotate
         21 from tangent import ast as ast_
         22 from tangent import compile as compile_
    
    ~/.conda/envs/py36/lib/python3.6/site-packages/tangent/annotate.py in <module>()
         27 from tangent import cfg
         28 from tangent import quoting
    ---> 29 from tangent import tracing
         30 from tangent import utils
         31
    
    ~/.conda/envs/py36/lib/python3.6/site-packages/tangent/tracing.py in <module>()
         14 """Utilities for tracing code, a useful fallback when ahead-of-time AD fails.
         15 """
    ---> 16 from tensorflow.python.eager.backprop import make_vjp
         17
         18
    
    ~/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/__init__.py in <module>()
         22
         23 # pylint: disable=wildcard-import
    ---> 24 from tensorflow.python import *  # pylint: disable=redefined-builtin
         25 # pylint: enable=wildcard-import
         26
    
    ~/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/__init__.py in <module>()
         47 import numpy as np
         48
    ---> 49 from tensorflow.python import pywrap_tensorflow
         50
         51 # Protocol buffers
    
    ~/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/pywrap_tensorflow.py in <module>()
         72 for some common reasons and solutions.  Include the entire stack trace
         73 above this error message when asking for help.""" % traceback.format_exc()
    ---> 74   raise ImportError(msg)
         75
         76 # pylint: enable=wildcard-import,g-import-not-at-top,unused-import,line-too-long
    
    ImportError: Traceback (most recent call last):
      File "/home/pauperei/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/pywrap_tensorflow.py", line 58, in <module>
        from tensorflow.python.pywrap_tensorflow_internal import *
      File "/home/pauperei/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/pywrap_tensorflow_internal.py", line 28, in <module>
        _pywrap_tensorflow_internal = swig_import_helper()
      File "/home/pauperei/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/pywrap_tensorflow_internal.py", line 24, in swig_import_helper
        _mod = imp.load_module('_pywrap_tensorflow_internal', fp, pathname, description)
      File "/home/pauperei/.conda/envs/py36/lib/python3.6/imp.py", line 243, in load_module
        return load_dynamic(name, filename, file)
      File "/home/pauperei/.conda/envs/py36/lib/python3.6/imp.py", line 343, in load_dynamic
        return _load(spec)
    ImportError: /usr/lib64/libstdc++.so.6: version `CXXABI_1.3.7' not found (required by /home/pauperei/.conda/envs/py36/lib/python3.6/site-packages/tensorflow/python/_pywrap_tensorflow_internal.so)
    
    
    Failed to load the native TensorFlow runtime.
    
    See https://www.tensorflow.org/install/install_sources#common_installation_problems
    
    for some common reasons and solutions.  Include the entire stack trace
    above this error message when asking for help.
    

    System information:

    Red Hat Enterprise Linux Server release 5.3 (Tikanga)
    Amazon Linux Bare Metal release 2012.03
    
    opened by paupereira 6
  • python3: pip install fails with UnicodeDecodeError

    python3: pip install fails with UnicodeDecodeError

    this seems to be related to issue #13 but I tried it Dec/1 and got the following error:

    Collecting tangent
      Downloading tangent-0.1.8.tar.gz (81kB)
        100% |################################| 81kB 1.9MB/s 
        Complete output from command python setup.py egg_info:
        Traceback (most recent call last):
          File "<string>", line 1, in <module>
          File "/tmp/pip-build-bifyt5f0/tangent/setup.py", line 5, in <module>
            readme = f.read()
          File "/usr/lib/python3.5/encodings/ascii.py", line 26, in decode
            return codecs.ascii_decode(input, self.errors)[0]
        UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 498: ordinal not in range(128)
    

    Note this was an attempt to install under python 3.5.2 (standard ubuntu 16 package). In contrast it seems like the python2.7 install does work OK.

    opened by utke1 6
  • AttributeError: module 'builtins' has no attribute 't'

    AttributeError: module 'builtins' has no attribute 't'

    Getting AttributeError: module 'builtins' has no attribute 't' when running the Hessian-vector products example:

    def f(x):
        a = x * x * x
        b = a * x ** 2.0
        return tf.reduce_sum(b)
    
    hvp = tangent.grad(tangent.grad(f, mode='reverse'), mode='forward')
    
    opened by amirziai 6
  • Incorrect gradient calculation

    Incorrect gradient calculation

    Hi, I've been experimenting with this library for a few months now and really like the capabilities present. I'm working to develop an AD capability via code generation for a set of aerospace engineering codes in Python.

    However, I think I've run into either a bug or a usage misunderstanding. Consider the following stand-alone function, which takes several parameters and returns a scalar:

    import tangent
    
    BTU_s2HP, HP_per_RPM_to_FT_LBF = 1.4148532, 5252.11
    
    def enthalpyandpower(W_in, W_out, ht_in, ht_out_ideal, eff, Nmech, b1_W, b1_ht, b1_ht_ideal):
    
        ht_out = W_in/W_out * (ht_in * (1.0 - eff) + ht_out_ideal * eff)
        power = W_in * eff * (ht_in - ht_out_ideal) * BTU_s2HP
    
    
        ht_out += b1_W / W_out * \
            (b1_ht * (1.0 - eff) +
             b1_ht_ideal * eff)
        power += b1_W * eff * \
            (b1_ht - b1_ht_ideal) * BTU_s2HP
    
        # calculate torque based on revised power and shaft speed
        trq = power / \
            Nmech * HP_per_RPM_to_FT_LBF
    
        return power
    

    If I generate the partial derivative of power with respect to the first parameter W_in

    dpower_dwin = tangent.autodiff(enthalpyandpower, wrt=(0,), verbose=1)
    

    then I get:

    def denthalpyandpowerdW_in(W_in, W_out, ht_in, ht_out_ideal, eff, Nmech,
        b1_W, b1_ht, b1_ht_ideal, bpower):
        # Initialize the tape
        _stack = tangent.Stack()
        _ht_out3 = ht_out_ideal * eff
        _1_0_minus_eff = 1.0 - eff
        _ht_out2 = ht_in * _1_0_minus_eff
        _ht_out = _ht_out2 + _ht_out3
        W_in_over_W_out = W_in / W_out
        ht_out = W_in_over_W_out * _ht_out
        _power2 = ht_in - ht_out_ideal
        W_in_times_eff = W_in * eff
        _power = W_in_times_eff * _power2
        power = _power * BTU_s2HP
        tangent.push(_stack, ht_out, '_1c132dd6')
        _3285 = b1_ht - b1_ht_ideal
        b1_W_times_eff = b1_W * eff
        _3244 = b1_W_times_eff * _3285
        _eb3b = _3244 * BTU_s2HP
        tangent.push(_stack, power, '_b65b4e60')
        power = power + _eb3b
        assert tangent.shapes_match(power, bpower
            ), 'Shape mismatch between return value (%s) and seed derivative (%s)' % (
            numpy.shape(power), numpy.shape(bpower))
        power = tangent.pop(_stack, '_b65b4e60')
        bpower = tangent.init_grad(power, allow_lazy_initializer=True)
        ht_out = tangent.pop(_stack, '_1c132dd6')
        bht_out = tangent.init_grad(ht_out, allow_lazy_initializer=True)
    
        # Grad of: power = W_in * eff * (ht_in - ht_out_ideal) * BTU_s2HP
        _b_power = tangent.unbroadcast(bpower * BTU_s2HP, _power)
        b_power = _b_power
        _3f78 = tangent.unbroadcast(b_power * _power2, W_in_times_eff)
        bW_in_times_eff = _3f78
        _bW_in2 = tangent.unbroadcast(bW_in_times_eff * eff, W_in)
        bW_in = _bW_in2
    
        # Grad of: ht_out = W_in / W_out * (ht_in * (1.0 - eff) + ht_out_ideal * eff)
        _a32f = tangent.unbroadcast(bht_out * _ht_out, W_in_over_W_out)
        _9f3c = _a32f
        _bW_in = _9f3c / W_out
        bW_in = tangent.add_grad(bW_in, _bW_in)
        return bW_in
    

    Running this seems to give me a partial derivative of 0.0 regardless of the evaluation point. However, the partial is certainly non-zero, e.g. at (30., 30., 10., 9.5, 0.95, 1000., 1000., 1000., 999.) it would be about 0.67206, but instead

    x = denthalpyandpowerdW_in(30., 30., 10., 9.5, 0.95, 1000., 1000., 1000., 999., 1.0)
    print(x)
    

    returns 0.0.

    The correct derivative of can be found analytically with some work, or confirmed roughly by finite difference:

    x0 = enthalpyandpower(30., 30., 10., 9.5, 0.95, 1000., 1000., 1000., 999.)
    x1 = enthalpyandpower(30.001, 30., 10., 9.5, 0.95, 1000., 1000., 1000., 999.)
    
    print((x1 - x0) / (0.001))
    

    Have I made a user error, or is this an unexpected bug? Thanks!

    opened by thearn 5
  • extra edges in control flow graph after

    extra edges in control flow graph after "return"

    Issue: The control flow graph that tangent builds sometimes has extra edges following a "return" statement.

    Example:

    def fn3(self):  # arguments
        if 2 > 1:  # compare
          return 1  # return1
        return 2  # return2
    

    The cfg produced by build_cfg has the following edges: arguments->compare compare->return1 compare->return2 return1->return2 # this is the extra edge.

    opened by dbieber 5
  • Unexpected result in LogSumExp gradient using Tangent package in Python

    Unexpected result in LogSumExp gradient using Tangent package in Python

    Problem:

    • First implementation:

    I'm trying to get Tangent to compute the gradient of a function that contains the following implementation of logsumexp:

    import numpy as np
    import tangent
    
    def logsumexp(a):
        # a = a.reshape(-1)
        result = 0.0
        largest_in_a = a[0]
        a_shape = len(a)
    
        # numba is slow when using max or np.max, so re-implementing:
        for i in range(1, a_shape):
            if a[i] > largest_in_a:
                largest_in_a = a[i]
    
        for i in range(a_shape):
            result += np.exp(a[i] - largest_in_a)
    
        return np.log(result) + largest_in_a
    

    I call tangent as follows:

    x = np.array([1,2,3,4])
    grad_logsumexp = tangent.grad(logsumexp)
    

    And get the result

    grad_logsumexp(x)
    Out[100]: array([0, 0, 0, 0])
    

    While the correct answer is

    array([0.0320586 , 0.08714432, 0.23688282, 0.64391426])
    
    • Second implementation:

    On the other hand, doing this works:

    def logsumexp_naive(a):
            return np.log(np.sum(np.exp(a)))
    
    grad_logsumexp_naive = tangent.grad(logsumexp_naive)
    grad_logsumexp_naive(x)
    

    Question:

    What's going on with the first implementation?

    opened by paupereira 4
  • Update grads.py

    Update grads.py

    Added the derivatives of the following functions: np.tan() np.arccos() np.arcsin() np.arctan()

    Added tests for the following functions: np.cos() np.sin() np.tan() np.cosh() np.sinh() np.tanh() np.arccos() np.arcsin() np.arctan()

    Changed the position of the (cos, sin, tan) functions, such that they are correctly ordered.

    opened by RikHendriks 4
  • Error in tangent tutorial notebook:

    Error in tangent tutorial notebook: "AttributeError: module 'gast' has no attribute 'Num'"

    Hi i opened your tutorial notebook and run the cells in notebook. after installing tangent at cell with following code:

    import tangent
    df = tangent.grad(f)
    

    the following error arises:

    AttributeError Traceback (most recent call last) in () ----> 1 import tangent 2 df = tangent.grad(f)

    3 frames /usr/local/lib/python3.6/dist-packages/tangent/grammar.py in () 16 import gast 17 ---> 18 LITERALS = (gast.Num, gast.Str, gast.Bytes, gast.Ellipsis, gast.NameConstant) 19 20 CONTROL_FLOW = (gast.For, gast.AsyncFor, gast.While, gast.If, gast.Try)

    AttributeError: module 'gast' has no attribute 'Num'

    opened by dariush-bahrami 6
  • docs: fix simple typo, subtituted -> substituted

    docs: fix simple typo, subtituted -> substituted

    There is a small typo in tangent/naming.py.

    Should read substituted rather than subtituted.

    Semi-automated pull request generated by https://github.com/timgates42/meticulous/blob/master/docs/NOTE.md

    opened by timgates42 0
  • Python 3.8 compatibility (gast >= 0.3.0 has breaking changes to API)

    Python 3.8 compatibility (gast >= 0.3.0 has breaking changes to API)

    As referenced in the 3.8 documentation, the ast.Num, ast.Str, etc. classes are deprecated and being removed in future versions.

    To support this (?), the gast library has changed to replace these with gast.Constant instead. (I.e., a gast.Num would be gast.Constant(value=1, kind=None) instead of gast.Num(n=1)).

    Unfortunately, this breaks tangent:

    >>> import tangent
    Traceback (most recent call last):                                                                                        
      File "<stdin>", line 1, in <module>
      File "/home/ssimmons/tangent/tangent/__init__.py", line 20, in <module>
        from tangent import annotate 
      File "/home/ssimmons/tangent/tangent/annotate.py", line 27, in <module>
        from tangent import cfg
      File "/home/ssimmons/tangent/tangent/cfg.py", line 29, in <module>
        from tangent import grammar
      File "/home/ssimmons/tangent/tangent/grammar.py", line 18, in <module>
        LITERALS = (gast.Num, gast.Str, gast.Bytes, gast.Ellipsis, gast.NameConstant)
    AttributeError: module 'gast' has no attribute 'Num'
    

    So I think that we need to restrict to the old API (and use Python <3.8) or adapt to the new API.

    opened by singularperturbation 0
  • AttributeError: module 'tensorflow' has no attribute 'to_float'

    AttributeError: module 'tensorflow' has no attribute 'to_float'

    I'm using TF 2.0, and I get this error when I import tangent, due to a list of non-differentiable functions that includes tf.to_float (line 60), which is deprecated:

    https://www.tensorflow.org/versions/r1.14/api_docs/python/tf/to_float

    help wanted good first issue 
    opened by ziofil 9
Releases(v0.1.8)
Owner
Google
Google ❤️ Open Source
Google
MASA-SR: Matching Acceleration and Spatial Adaptation for Reference-Based Image Super-Resolution (CVPR2021)

MASA-SR Official PyTorch implementation of our CVPR2021 paper MASA-SR: Matching Acceleration and Spatial Adaptation for Reference-Based Image Super-Re

DV Lab 126 Dec 20, 2022
This code is for eCaReNet: explainable Cancer Relapse Prediction Network.

eCaReNet This code is for eCaReNet: explainable Cancer Relapse Prediction Network. (Towards Explainable End-to-End Prostate Cancer Relapse Prediction

Institute of Medical Systems Biology 2 Jul 28, 2022
Data-driven reduced order modeling for nonlinear dynamical systems

SSMLearn Data-driven Reduced Order Models for Nonlinear Dynamical Systems This package perform data-driven identification of reduced order model based

Haller Group, Nonlinear Dynamics 27 Dec 13, 2022
Deep Learning and Reinforcement Learning Library for Scientists and Engineers 🔥

TensorLayer is a novel TensorFlow-based deep learning and reinforcement learning library designed for researchers and engineers. It provides an extens

TensorLayer Community 7.1k Dec 27, 2022
本项目是一个带有前端界面的垃圾分类项目,加载了训练好的模型参数,模型为efficientnetb4,暂时为40分类问题。

说明 本项目是一个带有前端界面的垃圾分类项目,加载了训练好的模型参数,模型为efficientnetb4,暂时为40分类问题。 python依赖 tf2.3 、cv2、numpy、pyqt5 pyqt5安装 pip install PyQt5 pip install PyQt5-tools 使用 程

4 May 04, 2022
2020 CCF大数据与计算智能大赛-非结构化商业文本信息中隐私信息识别-第7名方案

2020CCF-NER 2020 CCF大数据与计算智能大赛-非结构化商业文本信息中隐私信息识别-第7名方案 bert base + flat + crf + fgm + swa + pu learning策略 + clue数据集 = test1单模0.906 词向量

67 Oct 19, 2022
Robotics with GPU computing

Robotics with GPU computing Cupoch is a library that implements rapid 3D data processing for robotics using CUDA. The goal of this library is to imple

Shirokuma 625 Jan 07, 2023
The implementation of our CIKM 2021 paper titled as: "Cross-Market Product Recommendation"

FOREC: A Cross-Market Recommendation System This repository provides the implementation of our CIKM 2021 paper titled as "Cross-Market Product Recomme

Hamed Bonab 16 Sep 12, 2022
This repo implements a 3D segmentation task for an airport baggage dataset.

3D CT Scan Segmentation With Occupancy Network This repo implements a 3D superresolution segmentation task for an airport baggage dataset. Our final p

Christoph Reich 2 Mar 28, 2022
Official repository for: Continuous Control With Ensemble DeepDeterministic Policy Gradients

Continuous Control With Ensemble Deep Deterministic Policy Gradients This repository is the official implementation of Continuous Control With Ensembl

4 Dec 06, 2021
ShuttleNet: Position-aware Fusion of Rally Progress and Player Styles for Stroke Forecasting in Badminton (AAAI'22)

ShuttleNet: Position-aware Rally Progress and Player Styles Fusion for Stroke Forecasting in Badminton (AAAI 2022) Official code of the paper ShuttleN

Wei-Yao Wang 11 Nov 30, 2022
ECLARE: Extreme Classification with Label Graph Correlations

ECLARE ECLARE: Extreme Classification with Label Graph Correlations @InProceedings{Mittal21b, author = "Mittal, A. and Sachdeva, N. and Agrawal

Extreme Classification 35 Nov 06, 2022
An investigation project for SISR.

SISR-Survey An investigation project for SISR. This repository is an official project of the paper "From Beginner to Master: A Survey for Deep Learnin

Juncheng Li 79 Oct 20, 2022
Just Randoms Cats with python

Random-Cat Just Randoms Cats with python.

OriCode 2 Dec 21, 2021
NeuralTalk is a Python+numpy project for learning Multimodal Recurrent Neural Networks that describe images with sentences.

#NeuralTalk Warning: Deprecated. Hi there, this code is now quite old and inefficient, and now deprecated. I am leaving it on Github for educational p

Andrej 5.3k Jan 07, 2023
Rest API Written In Python To Classify NSFW Images.

Rest API Written In Python To Classify NSFW Images.

Wahyusaputra 2 Dec 23, 2021
A simple Neural Network that predicts the label for a series of handwritten digits

Neural_Network A simple Neural Network that predicts the label for a series of handwritten numbers This program tries to predict the label (1,2,3 etc.

Ty 1 Dec 18, 2021
Semantically Contrastive Learning for Low-light Image Enhancement

Semantically Contrastive Learning for Low-light Image Enhancement Here, we propose an effective semantically contrastive learning paradigm for Low-lig

48 Dec 16, 2022
A dataset for online Arabic calligraphy

Calliar Calliar is a dataset for Arabic calligraphy. The dataset consists of 2500 json files that contain strokes manually annotated for Arabic callig

ARBML 114 Dec 28, 2022
GEP (GDB Enhanced Prompt) - a GDB plug-in for GDB command prompt with fzf history search, fish-like autosuggestions, auto-completion with floating window, partial string matching in history, and more!

GEP (GDB Enhanced Prompt) GEP (GDB Enhanced Prompt) is a GDB plug-in which make your GDB command prompt more convenient and flexibility. Why I need th

Alan Li 23 Dec 21, 2022