Det finns en upplevd kompromiss mellan maskininlärningskod som är lätt att skriva, och maskininlärningskod som är skalbar eller snabb att utföra. I maskininlärning är imperativ stil bibliotek som Autograd och PyTorch lätta att skriva, men lider av höga tolkningsrika overhead och är inte lätt att distribuera i produktion eller mobila inställningar. Grafbaserade bibliotek som TensorFlow och Theano drar nytta av hela programoptimering och kan användas brett, men gör det svårare att uttrycka komplexa modeller. Vi beskriver hur användningen av iscensatt programmering i Python, via källkodsomvandling, erbjuder en mittpunkt mellan dessa två bibliotek design mönster, fånga fördelarna med båda. En viktig insikt är att skjuta upp alla typberoende beslut tills runtime, liknande dynamisk sändning. Vi omedelbart dessa principer i AutoGraph, ett mjukvarusystem som förbättrar programmering erfarenhet av TensorFlow bibliotek, och visa användbarhet förbättringar utan förlust i prestanda jämfört med inhemska TensorFlow grafer. Vi visar också att vårt system är backend agnostic, rikta en alternativ IR med egenskaper som inte finns i TensorFlow grafer. Programmeringsplattformar specialiserade för maskininlärning (ML) genomgår omfattande antagande, som ML-modeller såsom neurala nätverk visar state-of-the-art prestanda på många viktiga industriella problem som översättning och bildigenkänning. För att stödja denna ökade användning har det skett en snabb utveckling av plattformar för att bygga nya ML-modeller. Dessa plattformar följer två huvudparadigm, grafbaserad programmering och nödvändig programmering. Dessa har också märkts Defineand-run och Define-by-run (Tokui et al., 2015b). Grafbaserade system som TensorFlow och Theano använder en hög nivå språk (vanligtvis Python) för att metaprogram en lägre nivå mellanliggande representation (IR) av beräkning (Abadi et al., 2016; Al-Rfou et al., 2016). I TensorFlow fall, denna IR ger en representation som sedan kan distribueras automatiskt över ett datacenter, utförs på accelerator hårdvara som GPUs eller TPUs, distribueras till mobila enheter eller webbservrar, och kan dra nytta av hela programoptimering. De beräkningsvinster är betydande, men kommer på bekostnad av ytterligare kognitiv belastning för utvecklare. 1 Google Brain, Cambridge, MA 2 Purdue University. Korrespondens till: Tiark Rompf <tiark@purdue.edu>, Alexander B Wiltschko <alexbw@google.com> Imperativa programmeringssystem som PyTorch och Autograd (Paszke et al., 2017; Maclaurin et al., 2015) kör användarkod direkt, bygga upp en representation av användarens program stegvis för antingen automatisk differentiering eller sammanställning. TensorFlow stöder också imperativ kodning via "eager exekvering", där användarskriven Python-kod omedelbart kör TensorFlow-kärnor, utan att en graf byggs. Sådana system gör det möjligt för användaren att dra nytta av traditionell imperativ kodning, men har minskat möjligheterna till programoptimering, skalbar beräkning och portabilitet. Skillnaderna mellan dessa tillvägagångssätt är särskilt uppenbara för modeller som kräver databeroende kontrollflöde, såsom villkor eller slingor, som är viktiga för toppmoderna metoder inom förstärkningslärande, sekvensbaserade modeller och många andra framväxande forskningsområden. Imperativa plattformar gör det möjligt för en användare att skriva idiomatiska och inhemska Python kontrollflöde, med hjälp av traditionella syntax för databeroende kontrollflöde operationer som villkor och loopar. Detta tillvägagångssätt minskar dock möjligheterna till optimering av hela programmet och kräver retracing på varje utförande för automatisk differentiering. Grafbaserade plattformar undviker detta problem, men tillåter inte traditionell Pythonsyntax för databeroende kontrollflöde, utan kräver istället att databeroende kontrollflöde uttrycks i funktionell form. Detta krävs eftersom Python inte stöder att skjuta upp utförandet av kontrollflödet. Medan grafbaserad och imperativ programmering ofta presenteras som ortogonal och oberoende programmering AutoGraph: Imperativ-stil Kodning med Graph-baserade Performance paradigm, erbjuder vi en strategi som erbjuder det bästa av båda, behålla tvingande användbarhet fördelar samtidigt som den ger graf-baserade prestanda och bärbarhet fördelar. Vi noterar att detta tillvägagångssätt antar förmågan att omvandla kod till en specialiserad IR, och att denna IR ger verkliga fördelar till programmeraren såsom hastighet, minne och numeriska stabilitet optimeringar, samt utplaceringsbarhet till en mängd olika plattformar. Men, liksom många IR:er, antar vi också att det är besvärligt att programmera direkt. På grund av dess utbredda användning och robust IR, fokuserar vi mycket av vår diskussion på TensorFlow grafer, men visar i vår utvärdering (avsnitt 9.1) att detta tillvägagångssätt är helt oberoende av alla back-end, och faktiskt, vi kan representera program inte lätt uttrycks i TensorFlows IR genom att välja ett annat back-end för vår kodgenerering motor till mål. Bidragen i detta dokument är följande: • Vi föreslår en ny metod som ger användarna den expressiva kraften i tvingande ML-system, samtidigt som prestanda och portabilitet för grafbaserade system bibehålls. • Vi demonstrerar denna metod i Python med hjälp av statiska analyser och källkodsomvandlingar (SCT). • Med hjälp av dessa analyser och kodtransformer, möjliggör vi iscensatt programmering i Python sändning på runtime typ information, i de flesta fall kräver inga ytterligare anteckningar. • Vi använder vårt system, som kallas AutoGraph, för att omvandla idiomatic Python till TensorFlow Graph IR. Vi visar att AutoGraph generaliserar för att rikta andra back-ends, och kan konvertera Python koden till Lantern IR, som stöder funktioner som saknas från TensorFlow Graph IR, såsom re-entrant funktion samtal. • Vi visar att vårt system gör det möjligt för en användare att enkelt uttrycka komplexa ML-program som sänker sig till en optimerad IR, och köra lika snabbt som handskrivna alternativ. Ett antal befintliga system och metoder syftar också till att tillhandahålla ett användarvänligt programmeringsgränssnitt för att definiera ML-modeller utan att försämra prestandan. Ett sådant exempel är Open Neural-Network eXchange (ONNX) format (ONNX Bidragsgivare, 2018), som ger en IR med API:er för många högnivå front-ends som kan rikta ett antal populära back-ends fokuserade på optimering och högpresterande dator. Denna IR visas som en beräkningsgraf, genererad genom användning av spårning, som i många tvingande system. ONNX ger insikt i förmågan att använda en IR som mäklare mellan imperativ och grafbaserade system, men extrahera grafer via spårning kan ge en förlust av kontrollflödesinformation på grund av oförmågan att fånga databeroende kontrollflöde. En annan ny metod är att PyTorch's Torch Script ram (PyTorch Bidragare, 2018 The TensorFlow programvaruprogrammeringssystem har blivit populär för ML utövare, särskilt de som fokuserar på storskalig utbildning och utbyggnad (Hale, 2018). ML-program utförs naturligt i separata steg, när modellarkitektur och dataexempel blir tillgängliga på different-2 AutoGraph: Imperativ stil Kodning med Graph-baserade prestanda ent punkter i ett programs livscykel, och TensorFlow gör dessa steg explicita. En TensorFlow-användare måste först bygga upp en representation av den beräkning som ska köras, och sedan senare i sitt program, ange att beräkningen ska utföras. Dataflow grafer används för denna representation, eftersom de kan enkelt optimeras, distribueras och distribueras. Denna programmeringsmodell är ibland ouppenbara, vilket leder till svåra användbarhetsproblem och buggar, och är särskilt akut när det gäller att specificera kontrollflödet. Till exempel bör vissa styrflödeskonstruktioner ingå i den sänkta IR, medan andra är avsedda att specificera om beräkning ska ske i IR eller inte. Ett vanligt kodningsmönster är att villkorligt iscensätta beräkning med hjälp av modellhyperparametrar: # Villkorligt på bool läggs inte till i grafen om HParams.nonlin = ='relu': x = tf.nn.relu(x) annars: Andra användningar av kontrollflödet är dock avsedda att utföras på ett databeroende sätt: I koden ovan uttrycks det villkorliga uttalandet i en funktionell stil så att det kan utföras in-graph på ett databeroende sätt. Detta strider emellertid estetiskt och pragmatiskt mot Pythons tvingande stil. Denna svårighet förvärras när användaren behöver bo kontroll flödet, eller använda andra Python idiom som fortsätta och bryta. Vi skulle istället föredra att skriva och att det automatiskt omvandlas till den funktionella stilen. Vi vill att denna konvertering endast ska ske för uttryck som använder numeriska typer. Villkorliga byten av vanliga Python booleaner (t.ex. hyperparameterexemplet ovan) bör utföras absolut, utan iscensättning. För att kringgå denna begränsning använder vi SCT på hela funktioner för att möjliggöra överbelastning av icke-lokala delar av Python-språket. Vi beskriver en specifik momentiation av detta system, kallad AutoGraph som använder SCT för att tillåta användare att rikta en lägre nivå IR samtidigt skriva idiomatic Python. 1 Se Python Language Reference (https://docs.pytho n.org/3/referens/), avsnitt 3.3. AutoGraph: Imperativ stil Kodning med Graph-baserad prestanda Med hjälp av förmågan att överbelasta godtycklig Python syntax, byggde vi ett iscensatt programmeringssystem som heter AutoGraph för att förbättra prestandan av imperativ stil ML-program och omvänt, enkelheten i graf-baserade ML-program. AutoGraph gör det möjligt för användare att programmera med hjälp av idiomatic och imperativ stil Python, men fortfarande dra nytta av fördelarna med TensorFlow grafer, och utsätts för användare via en enda funktion API, som en Python funktion inredare som ses i Listing 1. AutoGraph arbetar med kontroll flöde, såsom om, För och medan uttalanden, även om de är godtyckligt näst eller innehåller paus och fortsätta uttalanden. AutoGraph systemet kan överbelasta villkor och loopar via SCT, så att vi kan avvika från Python standard beteende. Observera att, med samma stil av SCT, kan vi välja att överbelasta vissa uttalanden samtidigt bevara Python semantik för andra. På grund av detta förväntar vi oss att detta kan vara ett verktyg av allmänt intresse för Python utvecklare, eller en funktion som nya språk implementeringar kanske vill överväga att inkludera. För att på ett transparent sätt stödja kontrollflödet som är avsett att antingen vara iscensatt eller ostadig i TensorFlow, som i de villkorliga exemplen i Avsnitt 3, måste vi ändra beteendet hos om uttalanden baserade på typen av booleska predikat. Vi använder termen dynamisk sändning för att beskriva detta runtime beslutsfattande, eftersom det är analogt med dynamisk metod sändning vanligt i objektorienterad programmering. Dynamisk sändning gör det möjligt för oss att sömlöst växla mellan två vanliga användningsområden för kontrollflöde i ML-kod - ett "makroprogramming" läge som växlar eller loopar på värdet av hyperparametrar, och ett databeroende läge, där styrflödet sänks in i målet IR. Samma logik tillämpas för och medan slingor i motsvarigheten till ag.for_stmt och ag.while_stmt funktioner. Vi tillhandahåller även funktionalitet för att ta över utskriftsutdraget, vilket vanligtvis är oförenligt med TensorFlow grafer, eftersom utskrift skulle logga information omedelbart, och vi vill istället logga värden på grafen körtid. Observera att vissa infödda Python konstruktioner, som paus och fortsätta uttalanden har ingen direkt representation i TensorFlow. Detta kräver kodomvandlingar som helt tar bort dessa påståenden utan att påverka programsemantik. Detta uppnås genom att de respektive angivelserna sänks till motsvarande TensorFlow-konstruktioner. Till exempel fortsätter att sänkas med hjälp av extra variabler och villkor. Den dynamiska avsändningsmetoden medför extra drifttid omkostnader. I själva verket, om AutoGraph användes för att utföra normal ostadig Python beräkning, skulle det vara långsammare. Men eftersom vi riktar en lägre IR som kan utföras separat från Python runtime, är denna overhead amortized. 4 Jämförelse med statiska metoder Det är möjligt att extrahera beräkningsgrafer från Python kod statiskt, men att göra det kräver en strikt uppsättning begränsningar. System som Torch Script (PyTorch Bidragsgivare, 2018) väljer att införa dessa begränsningar i form av en DSL som är en begränsad delmängd av Python. Ett viktigt designbeslut i AutoGraph är dock att ge användare tillgång till så mycket av det ursprungliga Python-gränssnittet som möjligt (vi diskuterar begränsningar till detta i Avsnitt 10). Dessutom, på grund av bindningstidsanalys, som helt förlitar sig på statiska metoder inte tillåter iscensatt programmering i Python utan att kräva någon form av ett ersatz statiskt typsystem (t.ex. statiska typanteckningar). Samtidigt möjliggör iscensatt programmering i en dynamisk miljö för godtyckliga typer kräver noggranna överväganden (Decker et al., 2019), vårt beslut att främst rikta TensorFlow som en back-end avsevärt lindrar några av de genomförande smärtor på grund av den centrala fokuseringen av en array-baserad typ (tensor). Vi diskuterar detta i detalj i avsnitt 7. Endast en delmängd Python kan omvandlas trivialt, och betydande omskrivning av användartillhandahållen kod är nödvändig för att möjliggöra den överbelastning som krävs för iscensatt programmering. Till exempel måste slingor och villkor skrivas om i funktionell form; icke-lokala kontrollflödesangivelser måste sänkas. Vi utför dessa omskrivningar med hjälp av dataflöde och andra analyser av programstrukturen. Vi separerar också dessa omskrivningar i flera specialiserade pass. Varje specialkort föregås av flera dataflödesanalyser. Dessa beskrivs nedan, i den ordning de körs. Control Flow Graph Construction En standardkontrollflödesgraf (CFG) stöder flera statiska analyser. Kvalificerat namn Upplösning Vi skapar abstraktion av kvalificerade namn för att utvidga begreppet symboler till att omfatta sammansatta namn som a.b. Till exempel motsvarar det kvalificerade namnet a.b ungefär AST: Attribut (namn=namn('a), attr='b'). Aktivitetsanalys Här annoterar vi AST noder med listan över symboler som lästs och modifierats av respektive uttalande. Endast direkta ändringar anses skriva. Till exempel, i uttalandet a.b = c, a.b anses vara modifierad, men a är inte. Aktivitetsanalysen håller också koll på lexikala områden, deras boförhållanden (t.ex. Föräldraomfånget) och de symboler de innehåller. Denna standard dataflow analys annoterar hjälper till att identifiera den definition som når varje namn. Dessutom är förteckningen över symboler som definieras vid införande av vissa angivelser också kommenterad. Liveness Analysis Denna standard dataflow analys identifierar symboler som är levande vid inträde i eller utträde från vissa uttalanden, inklusive sammansatta uttalanden som villkor. AutoGraph utför kodkonvertering med hjälp av ett extensibelt system av flera, typiskt oberoende, AST omvandling passerar. Till exempel, en omvandling passerar skriver om om uttalanden till en överbelastningsbar funktionell form. Ett annat pass sänker bryta uttalanden i nya loop predikerar och extra villkor. Denna mekanism underlättar att lägga till stöd för fler Python idiomer i tid. För närvarande omfattar omvandlingarna följande, i tillämpningsordning: Direktiven identifierar uppmaningar till specifika funktioner som fungerar som AutoGraph samlingsdirektiv och kommenterar de relevanta AST noderna. Ett exempel på ett sådant direktiv är ag.set_loop_options. Break, Continue and Return Statements Dessa är faktiskt tre separata pass, men är mycket lika till sin natur. I varje enskilt fall sänks motsvarande uttalande till villkorade eller utvidgade slingor. Assert Statements Dessa konverteras på plats till överbelastningsbar funktionell form. Array beräkningar kräver en ytterligare idiom som inte finns i standard Python bibliotek: stacken operation. AutoGraph tillhandahåller ag.stack-funktionen som kan överbelastas på ett sätt som överensstämmer med de andra överbelastningarna. Observera att tillgång till listan (t.ex. l [i] ) och mutationen skjuts upp till ett separat övergångspass som omfattar skivoperatörer. Slices Python tillåter överbelastning av skivor operatörer ( __setitem__, __getitem__ ) i användarklasser. Men biten skriva operation har semantic av att mutera målet. Vi skriver om skivor för att använda värdesemantik som för närvarande krävs av TensorFlow. Till exempel konverteras x[i] = y på plats till x = ag.setitem (x, i, y). Skruvavläsningar omvandlas mekaniskt. Funktionssamtal Alla funktionssamtal är överbelastade. Överbelastningen kommer antingen dynamiskt omvandla målfunktionen, kalla den som-är eller ersätta den med en ny funktion, beroende på egenskaperna hos den funktion som kallas och konfigurationen av omvandlingen. Till exempel kan det inbyggda funktionstrycket konverteras till tf.print (se bilaga E för närmare information). Kontrollflöde Detta omvandlingspass ersätter allt lokalt kontrollflöde med en överlastbar ekvivalent funktionell form. Om påståendet är statslöst, kan därför dess funktionella form uttryckas med hjälp av niladiska funktioner som returnerar alla variabler som ändrats inuti uttalandet. Return x x = ag.if_stmt (x > 0, true_fn, false_fn) Observera att Python gör det möjligt att definiera (dvs. tilldela för första gången) symboler inuti kroppen av kontrollflöde uttalanden och använda dem senare. Det är möjligt att skriva kod där symboler kan vara odefinierade baserat på om grenen av en villkorad körning eller inte. Den funktionella versionen av de villkorade operatörerna anger dock alltid de symboler som det villkorade kan ändra i båda grenarna. För att simulera den odefinierade semantiken använder vi ett speciellt värde för att reifiera "odefinierat" tillstånd hos en variabel. Detta avviker för närvarande från Python semantik, men vi planerar att åtgärda detta genom att verifiera och uttryckligen ta bort "odefinierade" symboler innan de används. Medan och för loopar är stateful, och deras funktionella form kräver funktioner vars argument och returvärden representerar de variabler som modifieras inuti loopen (dess tillstånd). Utlåtandet behandlas på liknande sätt. Liknar om uttalanden, medan och för loopar kan definiera symboler inuti sin kropp. Om loopkroppen aldrig kör, förblir dessa symboler odefinierade. Detta hanteras också genom att använda speciella "odefinierade" värden för de symboler som inte definieras (som identifieras genom livenessanalys) vid inträde i slingan. Det överbelastade kontrollflödet använder dynamisk avsändning (se tillägg E). Den ternära operatören x om cond annars y omvandlas inline till den funktionella 6 AutoGraph: Imperativ stil Kodning med Graph-baserad Performance form ag.if_stmt (cond, x, y). Logiska uttryck Binära och unary logiska uttryck kan hanteras med traditionella operatör överbelastning (t.ex. __lt___ för < operatören). Tensor stöder dock inte alla operatörer av kompatibilitetsskäl (t.ex. stöds inte __eq___). Därför ersätter vi vissa binära och unary operatörer inline med överbelastningsbara funktionella former. Till exempel, a och b ersätts med ag.and_ (a, b). Funktion Wrappers Detta omvandlingspass sveper in hela blocket av funktioner med ytterligare pannplate kod. Detta rymmer för exempel de nödvändiga anropen för att skapa en TensorFlow namnomfång, vilket förbättrar läsbarheten av den utgivna grafen. Dessutom innehåller funktionsomslag specialiserade felhanterare som avlyssnar vissa fel för att förbättra användbarheten. Om TensorFlow är den enda back-end av denna kod omvandling, då begränsningarna i TensorFlow måste också gälla för AutoGraph. Men på grund av arten av metaprogrammering, SCT i AutoGraph kan lätt användas för att rikta en mängd olika back-ends. Som tidigare diskuterats är en brist i TensorFlow oförmågan att hantera re-entrant in-graph funktioner, och i förlängning, rekursiva modeller. För att visa nyttan av en allmän SCT-metod som implementerats av AutoGraph väljer vi att rikta in oss på en ny ML-ramprototyp kallad Lantern, som kan generera grafer som beskriver rekursiva modeller. Lantern IR Lantern back-end omvandlar Lisplike S-uttryck som beskriver numeriska operationer till effektiv C++-kod. På ett kritiskt sätt stöder Lantern programmeringsfunktioner som saknas i specifikationerna för TensorFlow-grafen, t.ex. rekursion och funktionsdefinitioner in-line, vilka är väsentliga i vissa toppmoderna ML-språkmodeller. Vi demonstrerar generaliteten av AutoGraph genom att rikta den Lantern S-uttryck IR, som stöds av ytterligare kod omvandling passerar. För att hantera funktioner i vår modell introducerar vi två nya funktioner: __def_staging(funktion, * args) och __call_staging(funktion, * args). Dessa avger en funktionsdefinition eller anrop, respektive i den genererade SExpression. På grund av den uppskjutna API som presenteras av AutoGraph, har vi möjlighet att specialisera de genererade funktionerna i S-Expression IR med avseende på kända parametrar. Observera att denna specialisering i funktionssamtal/definitioner inte kräver några ytterligare ändringar, eftersom det hanteras med hjälp av de befintliga avsändnings- och överbelastningsmekanismer som finns i AutoGraph. Med förmågan att definiera och anropa funktioner i den genererade beräkningskurvan, ger detta det gränssnitt som krävs för att definiera och köra rekursiva modeller. För att visa detta ger vi ett end-to-end-exempel på Python → S-Expr → C++. Vi undersöker först en rekursiv funktion i Python, enligt följande: Observera att för att korrekt generera den iscensatta funktionen, __def_staged måste skickas de argument som så småningom kommer att överföras till den funktion som definieras. Köra detta genererar S-Expression kod, som sedan matas som ingång till Lantern, som utför vissa interna beräkningar och så småningom genererar och utför följande C++ kod: Som visas, iscensätta en rekursiv funktion kräver att den genererade C++-koden också rekursiv (som noterats av rec-funktionen). Vi noterar att den genererade C++-koden ser ganska komplicerad ut, på grund av hanteringen av back-förökning. Back-propagation genomförs via callbacks (ses som fortsättningar, noteras av cont, cont_l, och cont_r i koden), vars detaljer kan refereras i 7 AutoGraph: Imperativ stil Kodning med Graph-baserad prestanda Vi testade nyttan av AutoGraph på flera axlar. Först frågade vi om AutoGraph kunde förbättra läsbarheten av ML-kod som förlitat sig på databeroende kontrollflöde utan att ådra sig en prestandapåföljd. För det andra testade vi om AutoGraph kunde användas för att flytta beräkningen vanligtvis kvar utanför TensorFlow grafen, såsom hela träningsprocessen av stokastisk lutning nedstigning (SGD), inuti grafen IR. För det tredje testade vi om AutoGraph kunde användas för att producera performantkod med hjälp av funktioner som inte stöds i TensorFlow-grafen genom att rikta in sig på alternativa IR. Vi förberedde också ytterligare prover av mer komplexa algoritmer, inklusive Neural Model Översättning med Uppmärksamhet, Sequence-to-sequence, MAML metalearning och L-BFGS optimeringar. Dessa finns i bilaga D. Koden sippet nedan är en implementering av en RNN-modell som på enkla ingångar ger resultat som är identiska med TensorFlows inbyggda tf.dynamic_rn-funktion och körs i liknande hastighet. Jämför denna terse och läsbar implementation med motsvarande grafversion i tillägg A. Vi jämförde TensorFlows officiella implementation av tf.dynamic_rn med både en handskriven, grafbaserad implementation och koden sippet ovan omvandlad till Eager 0.82 ± 0,08 1,57 ± 0,13 2,04 ± 0,14 0,43 ± 0,03 0,76 ± 0,05 ± 0,04 ± 0,04 ± 0,04 Officiellt ± 0,11 3,63 ± 0,13 ± 0,15 1,44 ± 0,04 ± 0,04 1,91 ± 0,06 2,61 ± 0,05 Handskriven 2,95 ± 0,13 3,71 ± 0,15 5,24 ± 0,11 1,52 ± 0,06 1,96 ± 0,07 2,68 ± 0,03 AutoGraf 2.72 ± 0,09 3,61 ± 0,12 5,05 ± 0,07 ± 0,04 1,86 ± 0,06 2,59 ± 0,04 grafer via AutoGraf. Varje körning bestod av en körning av en RNN med dold storlek 256, medan varierande satsstorlekar och sekvenslängd. Fem uppvärmningskörningar utfördes, och medelvärdet och standardavvikelsen för de 100 följande körningarna rapporteras. För alla exempel utförs varje körning som en tf.Session.run() anrop. Alla riktmärken kördes på en tvåtrådig 6-kärnig Intel Xeon E5-1650-processor. Användningen av AutoGraph förbättrar läsbarheten av koden och har en mycket liten effekt på prestandan.
Vissa projekt, som AutoGraph REF, fungerar på Python abstrakta syntax träd för att skriva om tvingande kod till kod som konstruerar dataflöde grafer, men sådana tekniker är utanför räckvidden för detta papper.
AutoGraph: Imperative-style Coding with Graph-based Performance
{'venue': 'ArXiv', 'journal': 'ArXiv', 'mag_field_of_study': ['Computer Science', 'Mathematics']}