Placeholder Image

Subtitles section Play video

  • DAN MOLDOVAN: Thank you all for coming.

  • My name is Dan Moldovan.

  • And today I will talk about some of the internals

  • and functionality of AutoGraph.

  • Now, this is definitely not an introductory talk.

  • And if you would like to learn more about the background

  • or the motivation behind AutoGraph,

  • here are a few resources that I believe can help.

  • The talk will be otherwise fairly fast paced, quite dense.

  • I'm hoping we'll be able to get through all of it in time.

  • But if not, I'm hoping the slides

  • will be able to serve as a good reference,

  • should you decide to come back and look at everything more

  • closely.

  • I should caution, though, that I am

  • oversimplifying a lot of things for the sake of brevity

  • and time.

  • But the essential things are in there.

  • The talk will be structured in roughly in three parts.

  • First I'll talk some about some of the more relevant

  • implementation details, which are useful to understanding

  • some of AutoGraph's behavior.

  • Then I'll describe the various ways in which

  • you can interact with it.

  • And lastly, I'll go through various use cases that

  • highlight what works, what doesn't work, common pitfalls,

  • how to stay away from them, and what are our plans

  • to eventually address them.

  • So let's begin with the implementation.

  • From a systems perspective, this is roughly

  • what AutoGraph looks like.

  • In broad strokes, we have the following.

  • Going from the bottom to the top,

  • we have an infrastructure for performing source code

  • transformations with various helpers.

  • And on top of that, we have individual transformations.

  • For instance, there is a separate transformation

  • that handles function calls.

  • Another one handles break statements.

  • And yet another transformation handles if statements.

  • And these transformations are independent and composable.

  • Many of these transformations then

  • replace your code with calls to special AutoGraph functions.

  • We call them overloads or operators.

  • The is reason that they are similar to Python's

  • overloaded operators.

  • Now, of those overloads, there are the most interesting ones,

  • the ones that specialize on creating TensorFlow ops.

  • And lastly, there's a high-level API

  • that glues them all together.

  • And this is typically what you usually

  • interact with as a user.

  • One last note that I should make is

  • that of all these pieces, only the TensorFlow specialized

  • overloads and perhaps the high-level APIs,

  • only these are specific to TensorFlow.

  • Everything else is fairly generic and reusable,

  • and we hope to eventually have them

  • in a separate library that can be used for other purposes

  • as well.

  • So one of the fundamental pieces of AutoGraph

  • is, of course, the source code transformation bit.

  • So let's look at that a bit more closely.

  • Source code transformation is essentially

  • what makes AutoGraph a transpiler.

  • It's unit of work is functions.

  • That is at runtime, a function is being

  • converted into a new function.

  • So let's look more closely at that process.

  • It is roughly, loosely speaking, a five-step process.

  • The first step is to obtain the source code of the function.

  • Now, the standard Python library makes that easy for us.

  • It provides that inspect module, which is built in,

  • and it lets us do that.

  • This also highlights one of the fundamental requirements

  • of AutoGraph.

  • In order to convert a function, that function

  • must expose its source code.

  • And that's typically true for almost all functions in Python,

  • although there are certain exceptions.

  • Normally, you can test this on your function

  • by calling the inspect get source.

  • If inspect get source returns data,

  • then AutoGraph should be fine with it.

  • The second step in this process is

  • to parse the code into an AST.

  • And once more, there is a standard Python API

  • for this, which is good.

  • We, in fact, use a thin layer on top of that.

  • It's a third-party library called Gast.

  • It's practically identical to AST,

  • but it handles all the version differences

  • between Python 2 and Python 3.

  • It's worth mentioning at this point

  • that AutoGraph operates entirely at AST level.

  • There is no lower-level intermediate representation.

  • And we never interact with the bytecode.

  • And that has some unique advantages.

  • Now, the third step does the bulk of the work.

  • And that's quite both literally and figuratively.

  • The standard Python library offers a mechanism that

  • helps us with that as well.

  • The AST module provides a mechanism

  • for visiting and transforming ASTs.

  • That mechanism uses the visitor pattern,

  • and it's sketched here.

  • Basically you get some callbacks whenever the visitor encounters

  • different types of nodes.

  • And on top of that, we have built an entire library

  • of such transformations, as we've

  • seen in the previous diagram.

  • These transformations are called in sequence.

  • Now, once transformed, the AST is unparsed back

  • into source code in the form of a string.

  • There isn't a standard library for doing that.

  • But thankfully there's a third-party library

  • called Astor, which does a decent job of that.

  • Essentially, it's lots of string concatenations.

  • There's nothing special about that.

  • Finally, the source code is being outputted into a file

  • and then loaded using a mechanism that's

  • identical to writing an import statement.

  • Once more, Python helps us with that,

  • with the standard module called Imp.

  • The special thing about Imp is that it only works

  • with files on disk, hence the need

  • to generate a temporary file.

  • I should also make a slight note that another mechanism that we

  • could have used would be Exec.

  • And we've been going back and forth

  • between using that and Imp.

  • There are pros and cons to using each.

  • So we might revisit this in the future.

  • A few other mechanisms that are worth mentioning, one of them

  • is the templating system that we developed to help us

  • with generating code.

  • It essentially lets us write templates

  • in the form of strings, code blocks of strings.

  • And they support placeholders, and they

  • let us generate more complex or new ASTs.

  • If you ever poke inside the transformations library,

  • you will see plenty of such templates.

  • Another important piece is the static analysis,

  • which is critical in supporting certain transformations,

  • and we'll see more about that in a bit.

  • The analysis itself can be viewed as just a simple walk

  • over the AST.

  • And it annotates nodes with relevant information.

  • Another important mechanism is caching.

  • Caching itself is completely transparent to the user.

  • But it does help us make sure that every function is

  • converted no more than once, loosely speaking.

  • This cache relies on the key assumption

  • that the conversion process is entirely static.

  • That is the generated code, what ends up

  • in the generated code does not depend

  • on any arguments or variables or any other state of Python.

  • Basically, if you look at some plain code on paper,

  • you would know exactly what the output code should be.

  • Next let's talk about some of the actual transformations that

  • are being made.

  • And before I proceed, I should clarify that I'll

  • use the word variable a lot.

  • These are meant to mean Python variables, not

  • to be confused with TensorFlow variables, which

  • are not involved here.

  • Once such transformation is simplifying the code

  • by replacing some statements with other statements, simpler

  • ones.

  • Such as, for instance, we replace break statements

  • with variables and additional if statements.

  • This essentially helps us avoid the need

  • to add to build special handlers in TensorFlow

  • for these statements, like break.

  • They're just easier to lower into something simpler.