Newsletter September 2019

Have you ever wondered:

  • How Julia developers decide what constitutes a major release, a minor release or a patch release?
  • How Julia developers think about an alpha release, a beta release and a release candidate?
  • What kind of long term support exists for different versions of Julia?

Stefan Karpinski has published a blog post on JuliaLang.org to help answer these questions.

The newest Julia releases are:

  • Julia v1.2.0: Current stable release
  • Julia v1.0.4: Long-term support release
  • Julia v1.3.0-rc1: Release candidate including multi-threaded parallelism

JuliaTeam and JuliaRun Available on Google Cloud Platform: Julia options on AWS, Azure and Google Cloud continue to expand. JuliaTeam is now available on AWS Marketplace and JuliaTeam and JuliaRun are available on Google Cloud Platform. Contact us for more information about JuliaTeam and JuliaRun.

How Computer Programming Is Changing Modern Life: The Society for Industrial and Applied Mathematics (SIAM) released a video featuring Julia co-creators Jeff Bezanson and Stefan Karpinski discussing how computer programming is changing modern life.

World Artificial Intelligence Conference (Shanghai): Viral Shah addressed the World Artificial Intelligence Conference, held in Shanghai Aug 29-31 with a discussion on “Julia: Generalizing Deep Learning with Differentiable Programming”.

Designing to the Limits – Algorithms for Peak Performance: Tim Wheeler and Mykel Kochendorfer, authors of Algorithms for Optimization, participated in a Center for Automotive Research at Stanford (CARS) Open Garage Talk moderated by Sebastian Thrun, founder of Google’s Self Driving Car Team. The talk is available on YouTube.

MIT Scientists Use Julia to Help Boston Public Schools Save $5 Million: MIT Operations Research Center scientists Dimitras Bertsimas, Sebastien Martin and Arthur Delarue used Julia to win first place in the 2017 Boston Public Schools Transportation Challenge. Their algorithm helped students sleep longer, reduced traffic and fuel emissions and saved Boston Public Schools $5 million.

JuliaSure: JuliaSure from Julia Computing provides enterprise Julia users with support and indemnity. Contact us for more information.

JuliaTeam: Julia Computing’s JuliaTeam solution works behind your firewall, enables enterprise governance and collaboration, including management of public and private packages and versions, licenses, indemnity and more. Contact us for more information.

Upcoming Julia Computing Events

Julia Computing will be participating in a number of upcoming conferences. Please contact us if you would like to meet with us at any of these events.

  1. Cambridge, MA: MIT Technology Review EmTech with Viral Shah (Julia Computing) at MIT Media Lab Sept 17-19
  2. New York: Strata Data Conference with Viral Shah, Stefan Karpinski, Jon Shepherd and Jerry Amaral (Julia Computing) Sept 23-26
  3. Orlando: American Conference on Pharmacometrics (ACoP10) with Viral Shah, Jon Shepherd and Andreas Noack (Julia Computing) Oct 20-23
  4. London: Open Data Science Conference (ODSC) with Avik Sengupta (Julia Computing) Nov 19-22

Live Online Instructor-Led Julia Training

Sign up now for live instructor-led online courses taught by Julia Computing instructors. Each course is 4 hours per day for two days, for a total of 8 hours of instruction per course.

Course Schedule Cost for 8 hours of live online instruction from Julia Computing instructors
Introduction to Machine Learning and Artificial Intelligence Using Julia Day 1: Wed Sept 11 from 11 am – 3 pm ET Day 2: Thurs Sept 12 from 11 am – 3 pm ET $500
Parallel Computing in Julia Day 1: Wed Sept 18 from 11 am – 3 pm ET Day 2: Thurs Sept 19 from 11 am – 3 pm ET $500
Register & Pay

Julia and Julia Computing in the News

  • Towards Data Science: Freeing the Data Scientist Mind from the Curse of VectoRization: Julia to the Rescue!
  • Data Science Central: Julia vs. R: Freeing the Data Scientist Mind from the Curse of VectoRization
  • Times of India: Techies Are Coming Together to Program a Geekier Nation
  • SD Times: Julia Programming Language Survey
  • SD Times: Julia 1.2 Released
  • DevClass: Julia 1.2 Gets Star for Special Interest Computations
  • Route Fifty: How One City Saved $5 Million by Routing School Buses with an Algorithm
  • CNBeta: TIOBE 8月排行:你说 Objective-C 将走向衰败 我不同意
  • Techzine: Julia Wint Aan Populariteit Over Python
  • Appinventiv: Introducing Julia – The Top Programming Language for Machine Learning Development
  • Zylotech: What Is All this Buzz About the Julia Programming Language?
  • JAXenter: Julia – The Programming Language of the Future?
  • ZDNet: Julia Programming Language – Users Reveal What They Love and Hate the Most About It
  • TechRepublic: Julia vs. Python – This Is Why the Fledgling Programming Language Is Winning New Fans
  • InsideBigData: Composable Multi-Threaded Parallelism in Julia
  • JAXenter: Julia v1.2.0: Technical Computing Gets Updated with New Library Functions
  • PacktHub: Julia Co-Creator, Jeff Bezanson, On What’s Wrong with Julialang and How to Tackle Issues Like Modularity and Extension
  • PacktHub: Julia v1.2 Releases with Support for Argument Splatting, Unicode 12, New Star Unary Operator, and More
  • PacktHub: The Julia Team Shares its Finalized Release Process with the Community
  • News Medical: UMB Startup Releases Cutting-Edge Software Platform for Pharmaceutical Researchers

Julia Blog Posts

Upcoming Julia Events

Recent Julia Events

Julia Meetup Groups: There are 37 Julia Meetup groups worldwide with 8,415 members. If there’s a Julia Meetup group in your area, we hope you will consider joining, participating and helping to organize events. If there isn’t, we hope you will consider starting one.

Julia Jobs, Fellowships and Internships

Do you work at or know of an organization looking to hire Julia programmers as staff, research fellows or interns? Would your employer be interested in hiring interns to work on open source packages that are useful to their business? Help us connect members of our community to great opportunities by sending us an email, and we’ll get the word out.

There are more than 300 Julia jobs currently listed on Indeed.com, including jobs at Accenture, Airbus, Amazon, AstraZeneca, AT&T, Barnes & Noble, BlackRock, Capital One, CBRE, Charles River Analytics, Citigroup, Comcast, Conde Nast, Cooper Tire & Rubber, Disney, Dow Jones, Facebook, Gallup, Genentech, General Electric, Google, Huawei, Ipsos, Johnson & Johnson, KPMG, Lockheed Martin, Match, Mathematica, McKinsey, NBCUniversal, Netflix, Nielsen, Novartis, OKCupid, Opendoor, Oracle, Pandora, Peapod, Pfizer, Raytheon, Spectrum, Wells Fargo, Zillow, Brown, BYU, Caltech, Dartmouth, Emory, Harvard, Johns Hopkins, Louisiana State University, Massachusetts General Hospital, MIT, Penn State, Princeton, UC Davis, University of Chicago, University of Delaware, University of Kentucky, UNC-Chapel Hill, USC, University of Virginia, Argonne National Laboratory, Federal Reserve Bank, Lawrence Berkeley National Laboratory, Los Alamos National Laboratory, National Renewable Energy Laboratory, Oak Ridge National Laboratory, Pacific Northwest National Laboratory, State of Wisconsin and many more.

Contact Us: Please contact us if you wish to:

  • Purchase or obtain license information for Julia products such as JuliaAcademy, JuliaTeam, or JuliaPro
  • Obtain pricing for Julia consulting projects for your organization
  • Schedule Julia training for your organization
  • Share information about exciting new Julia case studies or use cases
  • Spread the word about an upcoming conference, workshop, training, hackathon, meetup, talk or presentation involving Julia
  • Partner with Julia Computing to organize a Julia meetup, conference, workshop, training, hackathon, talk or presentation involving Julia
  • Submit a Julia internship, fellowship or job posting

About Julia and Julia Computing

Julia is the fastest high performance open source computing language for data, analytics, algorithmic trading, machine learning, artificial intelligence, and other scientific and numeric computing applications. Julia solves the two language problem by combining the ease of use of Python and R with the speed of C++. Julia provides parallel computing capabilities out of the box and unlimited scalability with minimal effort. Julia has been downloaded more than 9 million times and is used at more than 1,500 universities. Julia co-creators are the winners of the 2019 James H. Wilkinson Prize for Numerical Software. Julia has run at petascale on 650,000 cores with 1.3 million threads to analyze over 56 terabytes of data using Cori, one of the ten largest and most powerful supercomputers in the world.

Julia Computing was founded in 2015 by all the creators of Julia to develop products and provide professional services to businesses and researchers using Julia.

Building a constraint programming solver in Julia

More than 2 years ago I wrote a Sudoku solver in Python. I really enjoyed it and therefore I’ve spend some time to do the same in Julia just faster 😉 Then I wanted to build a whole constraint-programming solver in Julia. Well I actually still want to do it. It will be hard but fun. I want to share my way on my blog and instead of writing when I’ve done something I want to share my journey while I’m doing it.

Additionally the blog should be as simple as possible and everyone should be able to follow step by step.

In my dream we are building this together so if there is someone out there who is crazy and wants to build a constraint-programming solver from scratch… Send me a mail ([email protected]) and/or comment on this post.

In this first post I’ll create the package and create test cases as well as building the most basic solver using backtracking. In the next stages we will build the alldifferent, straights, sum constraint and so on together. The next post will be similar to the previous Sudoku post but with animation and of course written in Julia.

Let’s get started:

First we create a package:

julia
(v1.2) pkg> generate ConstraintSolver
Generating project ConstraintSolver:
    ConstraintSolver/Project.toml
    ConstraintSolver/src/ConstraintSolver.jl

(v1.2) pkg> activate ConstraintSolver/
Activating environment at `~/Julia/ConstraintSolver/Project.toml`

(v1.2) pkg> develop .
 Resolving package versions...
  Updating `~/.julia/environments/v1.2/Project.toml`
  [e0e52ebd] + ConstraintSolver v0.1.0 [`../../../Julia/ConstraintSolver`]
  Updating `~/.julia/environments/v1.2/Manifest.toml`
  [e0e52ebd] + ConstraintSolver v0.1.0 [`../../../Julia/ConstraintSolver`]

Info: You get to the package mode with ].

I want to have a git repository for the project and we can do this inside the julia shell as well.

shell> cd ConstraintSolver/
/home/ole/Julia/ConstraintSolver

shell> git init
Initialized empty Git repository in /home/ole/Julia/ConstraintSolver/.git/

Info: You get to the shell mode with ;.

The next thing for me is always to create a simple test file which I call current.jl which is inside .gitignore so that I can test the same thing on different branches.

shell> mkdir test
shell> touch test/current.jl
shell> vim .gitignore

Now before we do something like loading modules I would advise to use Revise which helps in general to avoid reloading the REPL when we change code.

julia> using Revise

The current.jl file is not a real test it’s more like a playground.

Inside I wrote:

using ConstraintSolver

CS = ConstraintSolver
include("sudoku_fcts.jl")

function main()
    com = CS.init()

    grid = zeros(Int8,(9,9))
    grid[1,:] = [0 0 0 5 4 6 0 0 9]
    grid[2,:] = [0 2 0 0 0 0 0 0 7]
    grid[3,:] = [0 0 3 9 0 0 0 0 4]
    grid[4,:] = [9 0 5 0 0 0 0 7 0]
    grid[5,:] = [7 0 0 0 0 0 0 2 0]
    grid[6,:] = [0 0 0 0 9 3 0 0 0]
    grid[7,:] = [0 5 6 0 0 8 0 0 0]
    grid[8,:] = [0 1 0 0 3 9 0 0 0]
    grid[9,:] = [0 0 0 0 0 0 8 0...

When do micro-optimizations matter in scientific computing?

By: Christopher Rackauckas

Re-posted from: http://www.stochasticlifestyle.com/when-do-micro-optimizations-matter-in-scientific-computing/

Something that has been bothering me about discussions about microbenchmarks is that people seem to ignore that the benchmarks are highly application-dependent. The easiest way to judge whether the benchmark really matters to a particular application is the operation overhead of the largest and most common calls. If you have a single operation dominating all of your runtime 99.9%, making everything else 100x faster still won’t do anything to your real runtime performance. But at the same time, if your bottleneck is some small operation that’s in a tight loop, then that operation may be your bottleneck. This is a classic chart to keep in the back of your mind when considering optimizations.

Here is a very brief overview on what to think about when optimizing code and how to figure out when to stop.

Function Call Overhead

When dealing with scalar operations, the cost of basic operations matters a lot. And one basic operation that can bite you in higher level languages is the function call overhead. Notice that 10’s of basic arithmetic (more with SIMD) can happen in the time that a single function can be called. Slower languages, like Python and R, have a higher function call overhead than something like C++, Fortran, of Julia for a few reasons. First of all it’s calling the function dynamically so there’s a lookup involved (and in Julia, if types are unstable there is a lookup as well, this is the cost of a “dynamic dispatch”). But secondly, in these compiled languages, of a function is determined to be sufficiently cheap, the function call can be completely gotten rid of by inlining the function (this is essentially copy-pasting the code in, instead of making it call the function). The heuristics for deciding whether a function is costly enough to inline is then very in-depth, since inlining a function means that a separately compiled function cannot be called so it’s a trade-off between run-time and compile-time speed. If the function costs too much, then inlining essentially is not helpful so you’d prefer to just compile faster, while if the function is cheap then it’s necessary to inline since otherwise the dominating cost is the function call.

In some domains this matters a lot. Ordinary differential equations for example are defined by huge swaths of scalar operations (this is one example of a common stiff ODE benchmark). If you had high operation overhead there your performance would be destroyed, which is why this domain has not only traditionally been dominated by compiled languages, but this domain is still dominated by compiled languages (counting Julia as one). In domains like optimization, ODEs, and nonlinear solving, this is particularly an issue for interpreted languages because these mathematical problems are higher order functions. This means that the API requires a function that is defined by the user, but the repeated calls to the interpreted function is the mostly costly part of the calculation, and so performance can be very hurt in this scenario. Even when accelerators like Numba are used, the context switch between the interpreted and compiled code can still hurt performance. The only way around this of course is to make an interface where you never accept a function from the user and instead you build it for them. This is why Pyomo is a Python optimization library where you use a modeling object. In both cases, a compiled function is built behind the scenes so that no interpreters get in the way.

But as you go up in computational cost per function, the performance lost by the function overhead cost goes down. This is why in languages like Python or R vectorization is encouraged because the 350ns or so function call cost is then dominated by the cost of the function calculation itself (and the cost is high enough that inlining doesn’t even play into the picture). Just for comparison, that’s taking scalar operations like + and * from 5ns-20ns to 350ns… so now you know where that performance went. With C++, Fortran, or Julia, it doesn’t matter whether you vectorize or loop through scalar operations because the vectorized call and the loop are the same under the hood, dropping down to optimally low function call cost or inlining it to remove the cost entirely (whereas the interpreted vectorized call is essentially the same as the compiled loop).

When do heap allocations matter?

Another major issue that comes up is heap allocations. The idea in brief is, allocations have a high floor and scale ~O(n). Let’s demonstrate this with some vectorized functions. First, let’s do element-wise multiplication.

using LinearAlgebra, BenchmarkTools
function alloc_timer(n)
    A = rand(n,n)
    B = rand(n,n)
    C = rand(n,n)
    t1 = @belapsed $A .* $B
    t2 = @belapsed ($C .= $A .* $B)
    t1,t2
end
ns = 2 .^ (2:11)
res = [alloc_timer(n) for n in ns]
alloc   = [x[1] for x in res]
noalloc = [x[2] for x in res]
 
using Plots
plot(ns,alloc,label="=",xscale=:log10,yscale=:log10,legend=:bottomright,
     title="Micro-optimizations matter for BLAS1")
plot!(ns,noalloc,label=".=")
savefig("microopts_blas1.png")

In this case we see that there’s almost a 3x-5x across the board advantage (remember the graph is log-scale) to using allocation-free interfaces because the allocation of the output array scales with the size of the array, and it has a high overhead. However, when we get to matrix multiplications, the scaling of the calculation comes into play:

using LinearAlgebra, BenchmarkTools
function alloc_timer(n)
    A = rand(n,n)
    B = rand(n,n)
    C = rand(n,n)
    t1 = @belapsed $A*$B
    t2 = @belapsed mul!($C,$A,$B)
    t1,t2
end
ns = 2 .^ (2:9)
res = [alloc_timer(n) for n in ns]
alloc   = [x[1] for x in res]
noalloc = [x[2] for x in res]
 
using Plots
plot(ns,alloc,label="*",xscale=:log10,yscale=:log10,legend=:bottomright,
     title="Micro-optimizations only matter for small matmuls")
plot!(ns,noalloc,label="mul!")
savefig("microopts.png")

Notice that when the matrix multiplications are small, the non-allocating `mul!` form has an advantage because of the high overhead of an allocation. However, as the size of the matrices increase, the O(n^3) scaling of matrix multiplication becomes the dominant force, and so the cost of the allocation is negligible.

Optimizing Machine Learning and Partial Differential Equations

So how much do different disciplines require lower level features? It turns out that same aspects of technical computing really require fast function calls and scalar operations, like solving nonlinear differential equations, and thus something like C++, Fortran, or Julia is really required for top notch speeds. In other disciplines, the time is completely dominated by large matrix multiplication or convolutional kernels. Machine learning is a prime example of this, where >99% of the computation time is spent inside of the large matrix multiplication of dense layers or convolution calls of a convolutional neural network. For these functions, pretty much every language, (R, Python, Julia, MATLAB, Octave, etc.), is calling into a BLAS implementation. One popular one is OpenBLAS, while another is Intel’s MKL. When things move to the GPU, essentially everyone is calling NVIDIA’s CuBLAS and cuDNN. With large matrix operations taking on the order of minutes (to even hours as it gets large and distributed), the 350ns function call overhead of a slow language just doesn’t even matter anymore.

The same tends to happen with PDE solving, where the dominant costs are sparse matrix multiplications and sparse factorizations, usually handled by SuiteSparse or libraries like PETSc when you start to get parallel. Here, factorizations taking an hour isn’t even uncommon, so I think you could sparse a few milliseconds. At this point, what matters more than a micro-optimization is the strategy that is used: whoever uses the last matrix multiplications or matrix factorizations wins the game.

This doesn’t mean that the underlying libraries can be written in a slow language. No, these pieces, like SuiteSparse, OpenBLAS, etc. need to be in a fast language like C++ or Fortran (or even Julia is starting to see performant BLAS implementations). But calling and using libraries in this domain tends to have negligible overhead.

I will just end by noting that big data analysis with pre-written kernels is another area that falls into this performance domain, while the moment you allow users to write their own kernels (“give me a function and I’ll do a map reduce with it!”) you suddenly need to compile that function in a fast way.

Optimizing Scientific Machine Learning and Differentiable Programming

When you get to scientific machine learning and differentiable programming, things get tricky. If you haven’t heard of scientific machine learning, read this overview of the tools of the domain, and for differentiable programming this paper is a good overview of things people (we) are trying to target with the technique. The amount of micro-optimizations that you need really depends on where you fall in this spectrum from numerical ODEs to machine learning. Generally, if your matrices are “small enough”, you need to use mutation and make sure scalar usage is fast, while once the matrices are large enough then all of the time is taken in GPU BLAS kernels so the name of the game is to use a better strategy.

There is a minor caveat here because tracing-based ADs, like Flux’s Tracker, PyTorch, or TensorFlow Eager, have a really really high op overhead. PyTorch announced that its overhead cost has gotten to 1us. Again, when matrix multiplications are clearly larger than seconds or minutes in any machine learning task, this overhead is so low that it does not make an impact on the total time itself, so we should congratulate the machine learning libraries for essentially eliminating overhead for their standard use case. But remember that if you compare that to the 5ns-20ns of basic scalar cost for things like `+` and `*`, you can see that, for example, tracing-based reverse mode automatic differentiation through the definition of a nonlinear ordinary differential equation will be horrifyingly slow. This means that tracing-based ADs do not do well in more general-purpose codes, making it difficult to use for things like differentiable programming in scientific machine learning where neural networks are mixed with large nonlinear kernels.

There is a way through though. Zygote has showcased operation overheads of around 500ns. The way this is done is through source-to-source automatic differentiation. This isn’t new, and the very old ADIFOR Fortran AD was a source-to-source AD that first noticed major per-op overhead advantages. The reason is because a tracing-based reverse-mode AD needs to build a tape at every single step so that way it knows the operations and the values. This tape needs to be heap allocated in any sensibly large calculation. This is why x[1] + x[2]*x[3] turns into a whopping multi-microsecond calculation when being traced while only being a ~20ns fma call if just scalar! A source-to-source AD doesn’t need to build a trace because it has already built and compiled an entire adjoint code. It does need to still store some values (since values from the forward pass need to be used in the backpass), and there are multiple ways that one can go about doing this. Zygote heap allocates forward values by making closures, this is where most of its overhead seems to come from. ADIFOR mixes forward mode in when it needs to compute values, which is another valid strategy. There are ways to also precompute some values of the fly while going in reverse, or mixing different strategies such as checkpointing. I think there’s a lot that can done to better optimize reverse-mode ADs like Zygote for the case of scalar operations (in fact, there seem to be quite a few compiler optimizations that it’s currently missing), and so if you plan to reverse-mode a bunch of scalar codes this may be an area of study to track in more detail.

Conclusion

The art of optimizing code is to only optimize what you need to. If you have small function calls (such as having lots of scalar operations), use a fast language and tools with low operation overhead. If you have really costly operations, then it really doesn’t matter what you do: optimize the costly operations. If you don’t know what regime your code lives in… then profile it. And remember that allocation costs scale almost linearly, so don’t worry about them if you’re doing O(n^3) operations with large n. You can use these ideas to know if using a feature from a higher level language like Python or R is perfectly fine performance-wise for the application. That said, this is also a good explanation as to why the libraries for those languages are not developed within the language and instead drop down to something else.

The post When do micro-optimizations matter in scientific computing? appeared first on Stochastic Lifestyle.