Benchmarking maps, loops, generators and broadcasting in Julia

By: Dean Markwick's Blog -- Julia

Re-posted from: https://dm13450.github.io/2019/05/03/Map-Loop-Generator.html

A few weeks ago I wrote a blog post about the speed differences
between map and loop. I posted it to reddit and got some feedback
on a) why the map was so slow and b) other ways the calculation
could be made which are just as quick as a loop. In this post I’m
writing about these new methods and adding them to the comparison.


Enjoy these types of posts? Then sign up for my newsletter.


Previous Methods

For a more detailed explanation of the problem I’m trying to solve, check out my previous
post
here. For
now I’m just going to recap.

using BenchmarkTools
using Statistics
clusterLabels = [1,1,2,2,3,3,5]

We started off with a simple map.

function pointsPerCluster_map(clusterLabels)
    map(i-> sum(clusterLabels .== i), 1:maximum(clusterLabels))
end

pointsPerCluster_map(clusterLabels)

mapBM = @benchmark pointsPerCluster_map($clusterLabels)
BenchmarkTools.Trial: 
  memory estimate:  21.73 KiB
  allocs estimate:  18
  --------------
  minimum time:     2.944 μs (0.00% GC)
  median time:      3.624 μs (0.00% GC)
  mean time:        7.479 μs (44.30% GC)
  maximum time:     9.851 ms (99.91% GC)
  --------------
  samples:          10000
  evals/sample:     8

It turns out this was slow because with each call of the function I
was creating a temporary array with clusterLabels .== i. To improve
on this I wrote the loop explicitly.

function pointsPerCluster_loop(clusterLabels)

    maxSize = maximum(clusterLabels)
    ppc = zeros(Int64, maxSize)
    
    for i in clusterLabels
        ppc[i] += 1
    end
    ppc
end
pointsPerCluster_loop(clusterLabels)

loopBM = @benchmark pointsPerCluster_loop($clusterLabels)
BenchmarkTools.Trial: 
  memory estimate:  128 bytes
  allocs estimate:  1
  --------------
  minimum time:     53.756 ns (0.00% GC)
  median time:      82.478 ns (0.00% GC)
  mean time:        167.708 ns (21.97% GC)
  maximum time:     240.429 μs (99.95% GC)
  --------------
  samples:          10000
  evals/sample:     985

The loop method was the easy winner and orders of magnitudes
quicker. But now we’ve got some new methods to test.

New Methods

The first two methods are from a reddit comment
here. The
final new method is taken from the Performance Tips section of the
Julia documentation.

Generator

First off, we use a generator. This is a better map implementation as
it doesn’t create the temporary array, instead it runs a tally of how
many entries are equal to i for each i we are mapping across.

function pointsPerCluster_gen(clusterLabels)
    map(i-> sum(c == i for c in clusterLabels), 1:maximum(clusterLabels))
    
end

pointsPerCluster_gen(clusterLabels)

genBM = @benchmark pointsPerCluster_gen($clusterLabels)
BenchmarkTools.Trial: 
  memory estimate:  336 bytes
  allocs estimate:  8
  --------------
  minimum time:     128.594 ns (0.00% GC)
  median time:      135.287 ns (0.00% GC)
  mean time:        203.392 ns (26.73% GC)
  maximum time:     131.934 μs (99.77% GC)
  --------------
  samples:          10000
  evals/sample:     891

The results are in the nanosecond range, which is great, same order
of magnitude as the loop.

Broadcasting .

In Julia, to apply a function to each element in a vector you use .
after the function which easy vectorisation. For example sin.(x)
will apply sine to each element of x. Whereas sin(x) would error.
In this case we can create an anonymous function that applies to each
element of our array.

pointsPerCluster_broad(clusterLabels) = (k->mapreduce(i->i==k, +, clusterLabels)).(1:maximum(clusterLabels))

pointsPerCluster_broad(clusterLabels)

broadBM = @benchmark pointsPerCluster_broad($clusterLabels)
BenchmarkTools.Trial: 
  memory estimate:  128 bytes
  allocs estimate:  1
  --------------
  minimum time:     96.824 ns (0.00% GC)
  median time:      101.509 ns (0.00% GC)
  mean time:        136.465 ns (13.67% GC)
  maximum time:     94.869 μs (99.85% GC)
  --------------
  samples:          10000
  evals/sample:     947

Again, the average speed is in the nanosecond range so comparable to
the loop.

Inbounds Loop

Another method of improving performance that the official
documentation recommends (with warning) is the @simd macro and the
@inbounds macro. These are compiler level optimisations that turn
off some of the safety features in the name of speed. With the caveat
that misbehaviour of the function could be catastrophic. We decorate
the loop function with these macros and test the results.

function pointsPerCluster_loop_inb(clusterLabels)

    maxSize = maximum(clusterLabels)
    ppc = zeros(Int64, maxSize)
    
    @simd for i in clusterLabels
        @inbounds ppc[i] += 1
    end
    ppc
end
pointsPerCluster_loop_inb(clusterLabels)

inboundsBM = @benchmark pointsPerCluster_loop_inb($clusterLabels)
BenchmarkTools.Trial: 
  memory estimate:  128 bytes
  allocs estimate:  1
  --------------
  minimum time:     51.369 ns (0.00% GC)
  median time:      56.292 ns (0.00% GC)
  mean time:        80.677 ns (24.89% GC)
  maximum time:     87.980 μs (99.89% GC)
  --------------
  samples:          10000
  evals/sample:     986

Again on the nanosecond scale, so all is working well.

Visualising

You know what this post needs: graphs. Here we plot the median and
maximum time the benchmarking tool reports.

using Plots
nms = ["Map", "Loop", "Generator", "Broadcast"]
bmList = [mapBM, loopBM ,genBM, broadBM]

timeArray = mapreduce(x -> [minimum(x).time, median(x).time, maximum(x).time], hcat, bmList)'
bar(nms, log.(timeArray[:, 2]), seriestype=:scatter, labels="Median", yaxis=("log Time"))
plot!(nms, log.(timeArray[:, 3]), seriestype=:scatter, labels="Maximum")

Log running times

bar(nms[2:4], (timeArray[2:4, 2]), seriestype=:scatter, yaxis=("Time"), label="Median")

We have to plot the \(\log\) of the running times as the naive map
is that much slower. The other methods are all about the same though,
so lets remove the map and focus on the fast methods.

Median running times

Here we can see that the loop method is still the fastest. The methods
provided in the feedback improve on the naive map but still cannot
compete with the loop. Using the @simd and @inbounds macro don’t change the overall median
value for it to be worth the potential danger.

Overall there are lots of ways to accomplish this task, but the loop
still comes out on top. Even using the “go-faster” macros doesn’t
improve on the runtime significantly.

Newsletter May 2019

Q: Is there an easy-to-find, easy-to-use searchable website where I can find a comprehensive inventory of Julia packages and Julia package documentation?

A: Pkg.julialang.org now includes improved Julia package documentation and search powered by JuliaTeam. You can now search Julia package names, tags, code and documentation to find the best Julia packages that fit your requirements.

Please contact us to learn how JuliaTeam can provide this same functionality within your enterprise development environment, including your own private Julia packages and more.

Stefan Karpinski explains in JuliaTeam
Vision
:

Documentation. Providing a single place to find all documentation for the Julia packages that you use. This service offers a single consistent place and way to host and publish package documentation. It also makes cross-linking docs between packages easy since they all live in the same place. Developers shouldn’t ever have to set up or think about the how of documentation hosting‚ they should just need to follow standard conventions for inline docs and then push their code. The docs service does the rest: cross-linked, searchable (see the next bullet point) docs are generated automatically.

Search. Currently search and discovery of packages is a serious pain point in the Julia ecosystem. JuliaTeam will provide integrated search of documentation and code for all packages. This will let you find the package that does what you need, whether it’s a public open source package or a private package that your organization uses‚ they’ll all be searchable in a single place.

Los Alamos National Laboratory Uses Julia to Predict Power Outages Caused by Extreme Events: Los Alamos National Laboratory used Julia to develop free, open source package – PowerModelsMLD.jl – that simulates the impact of disasters and predicts how the electric grid will be affected. This software can be used to allocate evacuation, rescue, relief and recovery resources.

Naval Postgraduate School Researchers Use Julia for Next Generation Climate Model: Naval Postgraduate School Professors Frank Giraldo, Lucas Wilcox and Jeremy Kozdon use Julia to create a new Earth Systems Model that is “poised to be the most accurate climate modeling system to date.‚”

Julia: The Programming Language Machine Learning Needs

The discussion around the future of machine learning continues to be atopic of interest at conferences and on Twitter. As workloads become diverse and complex, and generalize from the neural networks of today to Differentiable Programming, the question about programmability naturally arises. We have published several blogs on the topic (What is Differentiable Programming and Reinforcement Learning vs. Differentiable Programming).

Facebook AI’s Soumith Chintala has this to say about Julia:

JuliaAcademy: Julia Computing’s training offerings continue to expand. JuliaAcademy is the Julia Computing training platform for 3 types of learning: self-directed, online instructor-led and in-person onsite training.

Course Title and Description Date (11 am – 3 pm EDT) Cost Register
Introduction to Machine Learning and Artificial Intelligence in Julia May 2-3 $500 Register
Parallel Computing in Julia May 8-9 $500 Register

JuliaAcademy courses include: Intro to Julia, Machine Learning and Artificial Intelligence in Julia, Parallel Computing in Julia, Deep Learning with Flux, Optimization with JuMP and Machine Learning with Knet.

JuliaAcademy provides:

  1. Self-directed training – all online, learn at your own pace

  2. Instructor-led online training – live two-day courses taught by Julia Computing instructors

  3. In-person training – contact us at [email protected] to schedule customized in-person training for your organization

Register now for instructor-led online courses. All courses include 8 hours of instruction: 4 hours per day for two consecutive days. Currently scheduled courses are from 11 am – 3 pm Eastern Daylight Time (US).

Julia & Flux – Modernizing Machine Learning: Computação Brasil published Julia e Flux: Modernizando o Aprendizado de Máquina by Dhairya Gandhi, Mike Innes, Elliot Saba, Keno Fischer and Viral Shah.

Algorithms for Optimization (Using Julia): Mykel Kochenderfer and Tim Wheeler have published Algorithms for Optimization which uses Julia to provide a comprehensive introduction to optimization with a focus on practical algorithms.

Julia Programming for Operations Research: Changhyun Kwon from the University of South Florida has published Julia Programming for Operations Research.

JuliaCon 2019: JuliaCon 2019 will be
held July 22-26 at the University of Maryland, Baltimore. Early Bird
Ticket Sales
end May 5.

JuliaCon is looking for sponsors
and university partners in diversity. Sponsorship is available at
several levels and benefits include prominent mention and logo placement
at JuliaCon and in JuliaCon conference materials and Website, an
opportunity to present to JuliaCon participants, presentation space
during the conference and registration for JuliaCon attendees. Past
JuliaCon sponsors include the Alfred P. Sloan Foundation, Microsoft,
Maven, Invenia, Julia Computing, Capital One, Gordon and Betty Moore
Foundation, Gambit Research, Tangent Works, Amazon, Alan Turing
Institute, Jeffrey Sarnoff, EVN and Conning.

Julia and Julia Computing in the News

  • Analytics
    India
    :
    10 Fastest Growing Programming Languages That Employers Demand In
    2019

  • Analytics
    India
    :
    Annual Survey On Data Science Recruitment In India: 2019

  • Apple: What Are the Biggest Software Challenges in Machine Learning?

  • Computação Brasil: Julia e Flux: Modernizando o Aprendizado de Máquina

  • Computing: The Top 10 Most In-Demand IT Skills for 2019

  • DevClass: Julia 101 – The Upstart Language with a Lot to Offer

  • Edgy: Why Julia is the Programming Language set to Dominate our Future

  • EFinancialCareers: Should You Learn to Program in Julia to Get Ahead in Finance?

  • Forbes: How Are Computer Programming Languages Created?

  • Forbes: What Will Machine Learning Look Like In Twenty Years?

  • HPCWire: Julia and NASA Help the Nature Conservancy Save the Planet with Circuitscape

  • LeiPhone: 芯片行业30年资深人士:AI为何是高性能计算史上 “最大的变革推动者”

  • MoneyControl: Algo Trading: Here Are Five Steps to Set Up Your Own Algorithm

  • ODSC:
    Reinforcement Learning vs. Differentiable Programming

  • PC Revue: Päť Predikcií: Takto Bude Vyzerať Strojové Učenie o 20 Rokov

  • Sohu:十大应用在数学的计算机语言

Julia Blog Posts

Upcoming Julia Events

Recent Julia Events

Julia Meetup Groups: There are 35 Julia Meetup groups worldwide with 8,092 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, Barnes & Noble, BlackRock, Capital One,
Charles River Analytics, Citigroup, Comcast, Cooper Tire & Rubber,
Disney, Facebook, Gallup, Genentech, General Electric, Google, Huawei,
Johnson & Johnson, Match, McKinsey, NBCUniversal, Nielsen, OKCupid,
Oracle, Pandora, Peapod, Pfizer, Raytheon, Zillow, Brown, Emory,
Harvard, Johns Hopkins, Massachusetts General Hospital, Penn State, UC
Davis, University of Chicago, University of Virginia, Argonne National
Laboratory, Lawrence Berkeley National Laboratory, Los Alamos National
Laboratory, National Renewable Energy Laboratory, Oak Ridge 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 8.4
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.