Goto

Collaborating Authors

 structure


Structure from Duplicates: Neural Inverse Graphics from a Pile of Objects

Neural Information Processing Systems

Our world is full of identical objects (\emph{e.g.}, cans of coke, cars of same model). These duplicates, when seen together, provide additional and strong cues for us to effectively reason about 3D. Inspired by this observation, we introduce Structure from Duplicates (SfD), a novel inverse graphics framework that reconstructs geometry, material, and illumination from a single image containing multiple identical objects. SfD begins by identifying multiple instances of an object within an image, and then jointly estimates the 6DoF pose for all instances. An inverse graphics pipeline is subsequently employed to jointly reason about the shape, material of the object, and the environment light, while adhering to the shared geometry and material constraint across instances.Our primary contributions involve utilizing object duplicates as a robust prior for single-image inverse graphics and proposing an in-plane rotation-robust Structure from Motion (SfM) formulation for joint 6-DoF object pose estimation. By leveraging multi-view cues from a single image, SfD generates more realistic and detailed 3D reconstructions, significantly outperforming existing single image reconstruction models and multi-view reconstruction approaches with a similar or greater number of observations.


Structure learning in polynomial time: Greedy algorithms, Bregman information, and exponential families

Neural Information Processing Systems

Greedy algorithms have long been a workhorse for learning graphical models, and more broadly for learning statistical models with sparse structure. In the context of learning directed acyclic graphs, greedy algorithms are popular despite their worst-case exponential runtime. In practice, however, they are very efficient. We provide new insight into this phenomenon by studying a general greedy score-based algorithm for learning DAGs. Unlike edge-greedy algorithms such as the popular GES and hill-climbing algorithms, our approach is vertex-greedy and requires at most a polynomial number of score evaluations. We then show how recent polynomial-time algorithms for learning DAG models are a special case of this algorithm, thereby illustrating how these order-based algorithms can be rigourously interpreted as score-based algorithms. This observation suggests new score functions and optimality conditions based on the duality between Bregman divergences and exponential families, which we explore in detail. Explicit sample and computational complexity bounds are derived. Finally, we provide extensive experiments suggesting that this algorithm indeed optimizes the score in a variety of settings.


Probability Paths and the Structure of Predictions over Time

Neural Information Processing Systems

In settings ranging from weather forecasts to political prognostications to financial projections, probability estimates of future binary outcomes often evolve over time. For example, the estimated likelihood of rain on a specific day changes by the hour as new information becomes available. Given a collection of such probability paths, we introduce a Bayesian framework -- which we call the Gaussian latent information martingale, or GLIM -- for modeling the structure of dynamic predictions over time. Suppose, for example, that the likelihood of rain in a week is 50%, and consider two hypothetical scenarios. In the first, one expects the forecast to be equally likely to become either 25% or 75% tomorrow; in the second, one expects the forecast to stay constant for the next several days.


Learning the Structure of Large Networked Systems Obeying Conservation Laws

Neural Information Processing Systems

Many networked systems such as electric networks, the brain, and social networks of opinion dynamics are known to obey conservation laws. Examples of this phenomenon include the Kirchoff laws in electric networks and opinion consensus in social networks. Conservation laws in networked systems are modeled as balance equations of the form $X = B^\ast Y$, where the sparsity pattern of $B^\ast \in \mathbb{R}^{p\times p}$ captures the connectivity of the network on $p$ nodes, and $Y, X \in \mathbb{R}^p$ are vectors of ''potentials'' and ''injected flows'' at the nodes respectively. The node potentials $Y$ cause flows across edges which aim to balance out the potential difference, and the flows $X$ injected at the nodes are extraneous to the network dynamics. In several practical systems, the network structure is often unknown and needs to be estimated from data to facilitate modeling, management, and control.


On The Structure of Parametric Tournaments with Application to Ranking from Pairwise Comparisons

Neural Information Processing Systems

We consider the classical problem of finding the minimum feedback arc set on tournaments (MFAST). The problem is NP-hard in general and we study it for important classes of tournaments that arise naturally in the problem of learning to rank from pairwise comparisons. Specifically, we consider tournaments classes that arise out of parametric preference matrices that can lead to cyclic preference relations. We investigate their structural properties via forbidden sub tournament configurations. Towards this, we introduce \emph{Tournament Dimension} - a combinatorial parameter that characterizes the size of a forbidden configuration for rank $r$ tournament classes i.e., classes that arise out pairwise preference matrices which lead to rank $r$ skew-symmetric matrices under a suitable link function.


Reviews: Exploiting the Structure: Stochastic Gradient Methods Using Raw Clusters

Neural Information Processing Systems

The initial motivation seems to be the work of Hoffman et al on the use of clustering to speedup stochastic methods for ERM. Their method was not proved to converge to the optimal due to the use of biased stochastic gradients. Also, that work seemed to work only for small clusters due to the approach chosen. This papers goes a long way to develop the basic idea into a satisfying theoretical framework which also gives rise to efficient implementations. This paper is truly a pleasure to read – a very fine example of academic exposition.


Are there more wheels or doors in the world? ChatGPT wades into viral debate that's been dividing the internet... its answer may surprise you

Daily Mail - Science & tech

Viral phenomena have been around for almost as long as the internet has. You might remember the dress that took Tumblr by storm back in 2015 – was it blue and black or white and gold? But using ChatGPT, MailOnline tries to settle the debate, which has seen Twitter users go to great lengths to prove whether there are more doors or wheels in the world. MailOnline spoke to ChatGPT – but the answer may surprise you. The bot produced an autogenerated response, admitting defeat in its first sentence: 'It's difficult to provide an exact answer to this question, as it depends on a variety of factors and can change over time' Even OpenAI's proudest invention couldn't directly solve the query that has taken the internet by storm – and puzzled Twitter since last year. The bot produced an autogenerated response, admitting defeat in its first sentence: 'It's difficult to provide an exact answer to this question, as it depends on a variety of factors and can change over time'.


Zachary Yahn Wants to Change the Structure of Artificial Intelligence – UVA Today

#artificialintelligence

"We were using more modern computer vision, deep–learning techniques to automatically analyze these things," Yahn said. "We had algorithms that could …


An (almost) full-GPU Implementation of Gumbel MuZero in Julia.

#artificialintelligence

AlphaZero.jl is making two significant decisions to overcome the computing challenge in those algorithms. The first is the selection of Julia as the unique programming language used for this project. The second is the main focus of this Google Summer of Code (GSoC): two fully-batched implementations of the Monte Carlo Tree Search (MCTS) algorithms running on GPU. The MCTS algorithm is a crucial bottleneck for MuZero. It could account for up to 80% of the execution time of the previous (non-batched) implementation.


API as a package: Structure

#artificialintelligence

This is part one of our three part series Part 1: API as a package: Structure (this post) Part 2: API as a package: Logging (to be published) Part 3: API as a package: Testing (to be published) Introduction At Jumping Rivers we were recently tasked with taking a prototype application built in {shiny} to a public facing production environment for a public sector organisation. During the scoping exercise it was determined that a more appropriate solution to fit the requirements was to build the application with a {plumber} API providing the interface to the Bayesian network model and other application tools written in R. When building applications in {shiny} we have for some time been using the “app as a package” approach which has been popularised by tools like {golem} and {leprechaun}, in large part due to the convenience that comes with leveraging the testing and dependency structure that our R developers are comfortable with in authoring packages, and the ease with which one can install and run an application in a new environment as a result. For this project we looked to take some of these ideas to a {plumber} application. This blog post discusses some of the thoughts and resultant structure that came as a result of that process. As I began to flesh out this blog post I realised that it was becoming very long, and there were a number of different aspects that I wanted to discuss: structure, logging and testing to name a few. To try to keep this a bit more palatable I will instead do a mini-series of blog posts around the API as a package idea and focus predominantly on the structure elements here. Do you use RStudio Pro? If so, checkout out our managed RStudio services API as a package There are a few things I really like about the {shiny} app as a package approach that I wanted to reflect in the design and build of a {plumber} application as package. It encourages a regular structure and organisation for an application. All modules have a consistent naming pattern and structure. It encourages leveraging the {testthat} package and including some common tests across a series of applications, see golem::use_reccommended_tests() for example. An instance of the app can be created via a single function call which does all the necessary set up, say my_package::run_app() Primarily I wanted these features, which could be reused across {plumber} applications that we create both internally and for our clients. As far as I know there isn’t a similar package that provides an opinionated way of laying out a {plumber} application as a package, and it is my intention to create one as a follow up to this work. Regular structure When developing the solution for this particular project I did have in the back of my mind that I wanted to create as much reusable structure for any future projects of this sort as possible. I really wanted to have an easy way to, from a package structure, be able to build out an API with nested routes, using code that could easily transfer to another package. I opted for a structure that utilised the inst/extdata/api/routes directory of a package as a basis with the idea that the following file structure | inst/extdata/api/routes/ | | - model.R | - reports/ - | | - pdf.R with example route definitions inside # model.R #* @post /prediction exported_function_from_my_package # pdf.R #* @post /weekly exported_function_from_my_package would translate to an API with the following endpoints /model/prediction /reports/pdf/weekly A few simple function definitions would allow us to do this for any given package that uses this file structure. The first function here just grabs the directory from the current package where I will define the endpoints that make up my API. get_internal_routes = function(path = ".") { system.file("extdata", "api", "routes", path, package = utils::packageName(), mustWork = TRUE) } create_routes will recursively list out all of the .R files within the chosen directory and name them according to the name of the file, this will make it easy to build out a a number of “nested” routers that will all be mounted into the same API, achieving the compartmentalisation that we desire. For example the two files at /inst/extdata/api/routes/model.R and /inst/extdata/api/routes/reports/pdf.R will take on the names "model" and "reports/pdf" respectively. add_default_route_names = function(routes, dir) { names = stringr::str_remove(routes, pattern = dir) names = stringr::str_remove(names, pattern = "\.R$") names(routes) = names routes } create_routes = function(dir) { routes = list.files( dir, recursive = TRUE, full.names = TRUE, pattern = "*\.R$" ) add_default_route_names(routes, dir) } The final few pieces to the puzzle ensure that we have / at the beginning of a string (ensure_slash()), for the purpose of mounting components to my router. add_plumber_definition() just calls the necessary functions from {plumber} to process a new route file, i.e from the decorated functions in the file create the routes, and then mount them at a given path to an existing router object. For example given a file “test.R” that has a #* @get /identity decorator against a function definition and endpoint = "test" we would add /test/identity to the existing router. generate_api() takes a full named vector/list of file paths, ensures they all have an appropriate name and mounts them all to a new Plumber router object. ensure_slash = function(string) { has_slash = grepl("^/", string) if (has_slash) string else paste0("/", string) } add_plumber_definition = function(pr, endpoint, file, ...) { router = plumber::pr(file = file, ...) plumber::pr_mount(pr = pr, path = endpoint, router = router ) } generate_api = function(routes, ...) { endpoints = purrr::map_chr(names(routes), ensure_slash) purrr::reduce2( .x = endpoints, .y = routes, .f = add_plumber_definition, ..., .init = plumber::pr(NULL) ) } With these defined I can then, as I develop my package, add new routes by defining functions and adding {plumber} tag annotations to files in /inst/ and rebuild the new API with get_internal_routes() %>% create_routes() %>% generate_api() and nothing about this code is specific to my current package so is transferable. As a concrete, but very much simplified example, I might have the following collection of files/annotations under /inst/extdata/api/routes ## File: /example.R # Taken from plumber quickstart documentation # https://www.rplumber.io/articles/quickstart.html #* @get /echo function(msg="") { list(msg = paste0("The message is: '", msg, "'")) } ## File: /test.R #* @get /is_alive function() { list(alive = TRUE) } ## File: /nested/example.R # Taken from plumber quickstart documentation # https://www.rplumber.io/articles/quickstart.html #* @get /echo function(msg="") { list(msg = paste0("The message is: '", msg, "'")) } which would give me get_internal_routes() %>% create_routes() %>% generate_api() # # Plumber router with 0 endpoints, 4 filters, and 3 sub-routers. # # Use `pr_run()` on this object to start the API. # ├──[queryString] # ├──[body] # ├──[cookieParser] # ├──[sharedSecret] # ├──/example # │ │ # Plumber router with 1 endpoint, 4 filters, and 0 sub-routers. # │ ├──[queryString] # │ ├──[body] # │ ├──[cookieParser] # │ ├──[sharedSecret] # │ └──/echo (GET) # ├──/nested # │ ├──/example # │ │ │ # Plumber router with 1 endpoint, 4 filters, and 0 sub-routers. # │ │ ├──[queryString] # │ │ ├──[body] # │ │ ├──[cookieParser] # │ │ ├──[sharedSecret] # │ │ └──/echo (GET) # ├──/test # │ │ # Plumber router with 1 endpoint, 4 filters, and 0 sub-routers. # │ ├──[queryString] # │ ├──[body] # │ ├──[cookieParser] # │ ├──[sharedSecret] # │ └──/is_alive (GET) This {cookieCutter} example is available to view at our Github blog repo. Basic testing In my real project I refrained from having any actual function definitions being made in inst/. Instead each function that was part of the exposed API was a proper exported function from my package (additionally filenames for said functions followed a regular structure too of api_.R). This allows for leveraging {testthat} against the logic of each of the functions as well as using other tools like {lintr} and ensuring that dependencies, documentation etc are all dealt with appropriately. Testing individual functions that will be exposed as routes can be a little different to other R functions in that the objects passed as arguments come from a request. As alluded to in the introduction I will prepare another blog post detailing some elements of testing for API as a package but a short snippet that I found particularly helpful for testing that a running API is functioning as I expect is included here. The following code could be used to set up (and subsequently tear down) a running API that is expecting requests for a package cookieCutter # tests/testthat/setup.R ## run before any tests # pick a random available port to serve your app locally port = httpuv::randomPort() # start a background R process that launches an instance of the API # serving on that random port running_api = callr::r_bg( function(port) { dir = cookieCutter::get_internal_routes() routes = cookieCutter::create_routes(dir) api = cookieCutter::generate_api(routes) api$run(port = port, host = "0.0.0.0") }, list(port = port) ) # Small wait for the background process to ensure it # starts properly Sys.sleep(1) ## run after all tests withr::defer(running_api$kill(), testthat::teardown_env()) A simple test to ensure that our is_alive endpoint works then might look like test_that("is alive", { res = httr::GET(glue::glue("http://0.0.0.0:{port}/test/is_alive")) expect_equal(res$status_code, 200) }) Logging {shiny} has some useful packages for adding logging, in particular {shinylogger} is very helpful at giving you plenty of logging for little effort on my part as the user. As far as I could find nothing similar exists for {plumber} so I set up a bunch of hooks, using the {logger} package to write information to both file and terminal. Since that could form it’s own blogpost I will save that discussion for the future. For updates and revisions to this article, see the original post