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
Minimal diffusion models - Minimal code and simple experiments to play with Denoising Diffusion Probabilistic Models (DDPMs)

Minimal code and simple experiments to play with Denoising Diffusion Probabilist

Rithesh Kumar 16 Oct 06, 2022
Data and Code for ACL 2021 Paper "Inter-GPS: Interpretable Geometry Problem Solving with Formal Language and Symbolic Reasoning"

Introduction Code and data for ACL 2021 Paper "Inter-GPS: Interpretable Geometry Problem Solving with Formal Language and Symbolic Reasoning". We cons

Pan Lu 81 Dec 27, 2022
This repository contains the implementation of the paper: "Towards Frequency-Based Explanation for Robust CNN"

RobustFreqCNN About This repository contains the implementation of the paper "Towards Frequency-Based Explanation for Robust CNN" arxiv. It primarly d

Sarosij Bose 2 Jan 23, 2022
Progressive Growing of GANs for Improved Quality, Stability, and Variation

Progressive Growing of GANs for Improved Quality, Stability, and Variation — Official TensorFlow implementation of the ICLR 2018 paper Tero Karras (NV

Tero Karras 5.9k Jan 05, 2023
ThunderSVM: A Fast SVM Library on GPUs and CPUs

What's new We have recently released ThunderGBM, a fast GBDT and Random Forest library on GPUs. add scikit-learn interface, see here Overview The miss

Xtra Computing Group 1.4k Dec 22, 2022
Establishing Strong Baselines for TripClick Health Retrieval; ECIR 2022

TripClick Baselines with Improved Training Data Welcome 🙌 to the hub-repo of our paper: Establishing Strong Baselines for TripClick Health Retrieval

Sebastian Hofstätter 3 Nov 03, 2022
Supporting code for "Autoregressive neural-network wavefunctions for ab initio quantum chemistry".

naqs-for-quantum-chemistry This repository contains the codebase developed for the paper Autoregressive neural-network wavefunctions for ab initio qua

Tom Barrett 24 Dec 23, 2022
Visualize Camera's Pose Using Extrinsic Parameter by Plotting Pyramid Model on 3D Space

extrinsic2pyramid Visualize Camera's Pose Using Extrinsic Parameter by Plotting Pyramid Model on 3D Space Intro A very simple and straightforward modu

JEONG HYEONJIN 106 Dec 28, 2022
Rotary Transformer

[中文|English] Rotary Transformer Rotary Transformer is an MLM pre-trained language model with rotary position embedding (RoPE). The RoPE is a relative

325 Jan 03, 2023
Codes and models for the paper "Learning Unknown from Correlations: Graph Neural Network for Inter-novel-protein Interaction Prediction".

GNN_PPI Codes and models for the paper "Learning Unknown from Correlations: Graph Neural Network for Inter-novel-protein Interaction Prediction". Lear

Ursa Zrimsek 2 Dec 14, 2022
A Python-based development platform for automated trading systems - from backtesting to optimisation to livetrading.

AutoTrader AutoTrader is Python-based platform intended to help in the development, optimisation and deployment of automated trading systems. From sim

Kieran Mackle 485 Jan 09, 2023
Like ThreeJS but for Python and based on wgpu

pygfx A render engine, inspired by ThreeJS, but for Python and targeting Vulkan/Metal/DX12 (via wgpu). Introduction This is a Python render engine bui

139 Jan 07, 2023
This is the official implementation for the paper "(Almost) Free Incentivized Exploration from Decentralized Learning Agents" in NeurIPS 2021.

Observe then Incentivize Experiments This is the code used for the paper "(Almost) Free Incentivized Exploration from Decentralized Learning Agents",

Cong Shen Research Group 0 Mar 08, 2022
Semantic code search implementation using Tensorflow framework and the source code data from the CodeSearchNet project

Semantic Code Search Semantic code search implementation using Tensorflow framework and the source code data from the CodeSearchNet project. The model

Chen Wu 24 Nov 29, 2022
A Pytorch implementation of "Manifold Matching via Deep Metric Learning for Generative Modeling" (ICCV 2021)

Manifold Matching via Deep Metric Learning for Generative Modeling A Pytorch implementation of "Manifold Matching via Deep Metric Learning for Generat

69 Dec 10, 2022
Open source hardware and software platform to build a small scale self driving car.

Donkeycar is minimalist and modular self driving library for Python. It is developed for hobbyists and students with a focus on allowing fast experimentation and easy community contributions.

Autorope 2.4k Jan 04, 2023
VSR-Transformer - This paper proposes a new Transformer for video super-resolution (called VSR-Transformer).

VSR-Transformer By Jiezhang Cao, Yawei Li, Kai Zhang, Luc Van Gool This paper proposes a new Transformer for video super-resolution (called VSR-Transf

Jiezhang Cao 225 Nov 13, 2022
Disentangled Cycle Consistency for Highly-realistic Virtual Try-On, CVPR 2021

Disentangled Cycle Consistency for Highly-realistic Virtual Try-On, CVPR 2021 [WIP] The code for CVPR 2021 paper 'Disentangled Cycle Consistency for H

ChongjianGE 94 Dec 11, 2022
A python3 tool to take a 360 degree survey of the RF spectrum (hamlib + rotctld + RTL-SDR/HackRF)

RF Light House (rflh) A python script to use a rotor and a SDR device (RTL-SDR or HackRF One) to measure the RF level around and get a data set and be

Pavel Milanes (CO7WT) 11 Dec 13, 2022
The world's largest toxicity dataset.

The Toxicity Dataset by Surge AI Saving the internet is fun. Combing through thousands of online comments to build a toxicity dataset isn't. That's wh

Surge AI 134 Dec 19, 2022