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
PyTorch code for the NAACL 2021 paper "Improving Generation and Evaluation of Visual Stories via Semantic Consistency"

Improving Generation and Evaluation of Visual Stories via Semantic Consistency PyTorch code for the NAACL 2021 paper "Improving Generation and Evaluat

Adyasha Maharana 28 Dec 08, 2022
Repository of our paper 'Refer-it-in-RGBD' in CVPR 2021

Refer-it-in-RGBD This is the repository of our paper 'Refer-it-in-RGBD: A Bottom-up Approach for 3D Visual Grounding in RGBD Images' in CVPR 2021 Pape

Haolin Liu 34 Nov 07, 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
A Robust Non-IoU Alternative to Non-Maxima Suppression in Object Detection

Confluence: A Robust Non-IoU Alternative to Non-Maxima Suppression in Object Detection 1. 介绍 用以替代 NMS,在所有 bbox 中挑选出最优的集合。 NMS 仅考虑了 bbox 的得分,然后根据 IOU 来

44 Sep 15, 2022
A very short and easy implementation of Quantile Regression DQN

Quantile Regression DQN Quantile Regression DQN a Minimal Working Example, Distributional Reinforcement Learning with Quantile Regression (https://arx

Arsenii Senya Ashukha 80 Sep 17, 2022
Implement object segmentation on images using HOG algorithm proposed in CVPR 2005

HOG Algorithm Implementation Description HOG (Histograms of Oriented Gradients) Algorithm is an algorithm aiming to realize object segmentation (edge

Leo Hsieh 2 Mar 12, 2022
Submodular Subset Selection for Active Domain Adaptation (ICCV 2021)

S3VAADA: Submodular Subset Selection for Virtual Adversarial Active Domain Adaptation ICCV 2021 Harsh Rangwani, Arihant Jain*, Sumukh K Aithal*, R. Ve

Video Analytics Lab -- IISc 13 Dec 28, 2022
High level network definitions with pre-trained weights in TensorFlow

TensorNets High level network definitions with pre-trained weights in TensorFlow (tested with 2.1.0 = TF = 1.4.0). Guiding principles Applicability.

Taehoon Lee 1k Dec 13, 2022
SberSwap Video Swap base on deep learning

SberSwap Video Swap base on deep learning

Sber AI 431 Jan 03, 2023
When in Doubt: Improving Classification Performance with Alternating Normalization

When in Doubt: Improving Classification Performance with Alternating Normalization Findings of EMNLP 2021 Menglin Jia, Austin Reiter, Ser-Nam Lim, Yoa

Menglin Jia 13 Nov 06, 2022
Kohei's 5th place solution for xview3 challenge

xview3-kohei-solution Usage This repository assumes that the given data set is stored in the following locations: $ ls data/input/xview3/*.csv data/in

Kohei Ozaki 2 Jan 17, 2022
Using LSTM to detect spoofing attacks in an Air-Ground network

Using LSTM to detect spoofing attacks in an Air-Ground network Specifications IDE: Spider Packages: Tensorflow 2.1.0 Keras NumPy Scikit-learn Matplotl

Tiep M. H. 1 Nov 20, 2021
Cross-platform CLI tool to generate your Github profile's stats and summary.

ghs Cross-platform CLI tool to generate your Github profile's stats and summary. Preview Hop on to examples for other usecases. Jump to: Installation

HackerRank 134 Dec 20, 2022
Emblaze - Interactive Embedding Comparison

Emblaze - Interactive Embedding Comparison Emblaze is a Jupyter notebook widget for visually comparing embeddings using animated scatter plots. It bun

CMU Data Interaction Group 77 Nov 24, 2022
Repo for FUZE project. I will also publish some Linux kernel LPE exploits for various real world kernel vulnerabilities here. the samples are uploaded for education purposes for red and blue teams.

Linux_kernel_exploits Some Linux kernel exploits for various real world kernel vulnerabilities here. More exploits are yet to come. This repo contains

Wei Wu 472 Dec 21, 2022
repro_eval is a collection of measures to evaluate the reproducibility/replicability of system-oriented IR experiments

repro_eval repro_eval is a collection of measures to evaluate the reproducibility/replicability of system-oriented IR experiments. The measures were d

IR Group at Technische Hochschule Köln 9 May 25, 2022
A GPU-optional modular synthesizer in pytorch, 16200x faster than realtime, for audio ML researchers.

torchsynth The fastest synth in the universe. Introduction torchsynth is based upon traditional modular synthesis written in pytorch. It is GPU-option

torchsynth 229 Jan 02, 2023
Code for "Searching for Efficient Multi-Stage Vision Transformers"

Searching for Efficient Multi-Stage Vision Transformers This repository contains the official Pytorch implementation of "Searching for Efficient Multi

Yi-Lun Liao 62 Oct 25, 2022
A simple algorithm for extracting tree height in sparse scene from point cloud data.

TREE HEIGHT EXTRACTION IN SPARSE SCENES BASED ON UAV REMOTE SENSING This is the offical python implementation of the paper "Tree Height Extraction in

6 Oct 28, 2022
这是一个利用facenet和retinaface实现人脸识别的库,可以进行在线的人脸识别。

Facenet+Retinaface:人脸识别模型在Keras当中的实现 目录 注意事项 Attention 所需环境 Environment 文件下载 Download 预测步骤 How2predict 参考资料 Reference 注意事项 该库中包含了两个网络,分别是retinaface和fa

Bubbliiiing 31 Nov 15, 2022