Giter Club home page Giter Club logo

pyvbmc's Introduction

PyVBMC

PyVBMC: Variational Bayesian Monte Carlo in Python

Version Conda PyPI
Discussion tests docs build

What is it?

PyVBMC is a Python implementation of the Variational Bayesian Monte Carlo (VBMC) algorithm for posterior and model inference, previously implemented in MATLAB. VBMC is an approximate inference method designed to fit and evaluate Bayesian models with a limited budget of potentially noisy likelihood evaluations (e.g., for computationally expensive models). Specifically, VBMC simultaneously computes:

  • an approximate posterior distribution of the model parameters;
  • an approximation — technically, an approximate lower bound — of the log model evidence (also known as log marginal likelihood or log Bayes factor), a metric used for Bayesian model selection.

Extensive benchmarks on both artificial test problems and a large number of real model-fitting problems from computational and cognitive neuroscience show that VBMC generally — and often vastly — outperforms alternative methods for sample-efficient Bayesian inference [2,3].

Documentation

The full documentation is available at: https://acerbilab.github.io/pyvbmc/

When should I use PyVBMC?

PyVBMC is effective when:

  • the model log-likelihood function is a black-box (e.g., the gradient is unavailable);
  • the likelihood is at least moderately expensive to compute (say, half a second or more per evaluation);
  • the model has up to D = 10 continuous parameters (maybe a few more, but no more than D = 20);
  • the target posterior distribution is continuous and reasonably smooth (see here);
  • optionally, log-likelihood evaluations may be noisy (e.g., estimated via simulation).

Conversely, if your model can be written analytically, you should exploit the powerful machinery of probabilistic programming frameworks such as Stan or PyMC.

Note: If you are interested in point estimates or in finding better starting points for PyVBMC, check out Bayesian Adaptive Direct Search in Python (PyBADS), our companion method for fast Bayesian optimization.

Installation

PyVBMC is available via pip and conda-forge.

  1. Install with:
    python -m pip install pyvbmc
    or:
    conda install --channel=conda-forge pyvbmc
    PyVBMC requires Python version 3.9 or newer.
  2. (Optional): Install Jupyter to view the example Notebooks. You can skip this step if you're working from a Conda environment which already has Jupyter, but be aware that if the wrong jupyter executable is found on your path then import errors may arise.
    conda install jupyter
    If you are running Python 3.11 and get an UnsatisfiableError you may need to install Jupyter from conda-forge:
    conda install --channel=conda-forge jupyter
    The example notebooks can then be accessed by running
    python -m pyvbmc

If you wish to install directly from latest source code, please see the instructions for developers and contributors.

Quick start

A typical PyVBMC workflow follows four steps:

  1. Define the model, which defines a target log density (i.e., an unnormalized log posterior density);
  2. Setup the parameters (parameter bounds, starting point);
  3. Initialize and run the inference;
  4. Examine and visualize the results.

PyVBMC is not concerned with how you define your model in step 1, as long as you can provide an (unnormalized) target log density. Running the inference in step 3 only involves a couple of lines of code:

from pyvbmc import VBMC
# ... define your model/target density here
vbmc = VBMC(target, x0, LB, UB, PLB, PUB)
vp, results = vbmc.optimize()

with input arguments:

  • target: the target (unnormalized) log density — often an unnormalized log posterior. target is a callable that should take as input a parameter vector and return the log density at the point. The returned log density must return a finite real value, i.e. non NaN or -inf. See the VBMC FAQ for more details;
  • x0: an array representing the starting point of the inference in parameter space;
  • LB and UB: arrays of hard lower (resp. upper) bounds constraining the parameters (possibly -/+np.inf for unbounded parameters);
  • PLB and PUB: arrays of plausible lower (resp. upper) bounds: that is, a box that ideally brackets a high posterior density region of the target.

The outputs are:

  • vp: a VariationalPosterior object which approximates the true target density;
  • results: a dict containing additional information. Important keys are:
    • "elbo": the estimated lower bound on the log model evidence (log normalization constant);
    • "elbo_sd": the standard deviation of the estimate of the ELBO (not the error between the ELBO and the true log model evidence, which is generally unknown).

The vp object can be manipulated in various ways. For example, we can draw samples from vp with the vp.sample() method, or evaluate its density at a point with vp.pdf() (or log-density with vp.log_pdf()). See the VariationalPosterior class documentation for details.

PyVBMC with noisy targets

The quick start example above works for deterministic (noiseless) evaluations of the target log-density. Py(VBMC) also supports noisy evaluations of the target. Noisy evaluations often arise from simulation-based models, for which a direct expression of the (log) likelihood is not available.

For information on how to run PyVBMC on a noisy target, see this example notebook and the VBMC FAQ (for MATLAB, but most concepts still apply).

Next steps

Once installed, example Jupyter notebooks can be found in the pyvbmc/examples directory. They can also be viewed statically on the main documentation pages. These examples will walk you through the basic usage of PyVBMC as well as some if its more advanced features.

For practical recommendations, such as how to set LB and UB and the plausible bounds, check out the FAQ on the VBMC wiki. The wiki was written with the MATLAB toolbox in mind, but the general advice applies to the Python version as well.

How does it work?

VBMC/PyVBMC combine two machine learning techniques in a novel way:

PyVBMC iteratively builds an approximation of the true, expensive target posterior via a Gaussian process (GP), and it matches a variational distribution — an expressive mixture of Gaussians — to the GP.

This matching process entails optimization of the evidence lower bound (ELBO), that is a lower bound on the log marginal likelihood (LML), also known as log model evidence. Crucially, we estimate the ELBO via Bayesian quadrature, which is fast and does not require further evaluation of the true target posterior.

In each iteration, PyVBMC uses active sampling to select which points to evaluate next in order to explore the posterior landscape and reduce uncertainty in the approximation.

VBMC Demo

In the figure above, we show an example PyVBMC run on a Rosenbrock "banana" function. The bottom-left panel shows PyVBMC at work: in grayscale are samples from the variational posterior (drawn as small points) and the corresponding estimated density (drawn as contours). The solid orange circles are the active sampling points chosen at each iteration, and the hollow blue circles are the previously sampled points. The topmost and rightnmost panels show histograms of the marginal densities along the $x_1$ and $x_2$ dimensions, respectively. PyVBMC converges to an excellent approximation of the true posterior with a few dozens evaluations of the target density.

See the VBMC papers [1-3] for more details.

Troubleshooting and contact

PyVBMC is under active development. The VBMC algorithm has been extensively tested in several benchmarks and published papers, and the benchmarks have been replicated using PyVBMC. But as with any approximate inference technique, you should double-check your results. See the examples for descriptions of the convergence diagnostics and suggestions on validating PyVBMC's results with multiple runs.

If you have trouble doing something with PyVBMC, spot bugs or strange behavior, or you simply have some questions, please feel free to:

References and citation

  1. Huggins, B., Li, C., Tobaben, M., Aarnos, M., & Acerbi, L. (2023). PyVBMC: Efficient Bayesian inference in Python. Journal of Open Source Software 8(86), 5428, https://doi.org/10.21105/joss.05428.
  2. Acerbi, L. (2018). Variational Bayesian Monte Carlo. In Advances in Neural Information Processing Systems 31: 8222-8232. (paper + supplement on arXiv, NeurIPS Proceedings)
  3. Acerbi, L. (2020). Variational Bayesian Monte Carlo with Noisy Likelihoods. In Advances in Neural Information Processing Systems 33: 8211-8222 (paper + supplement on arXiv, NeurIPS Proceedings).

Please cite all three references if you use PyVBMC in your work (the 2018 paper introduced the framework, and the 2020 paper includes a number of major improvements, including but not limited to support for noisy likelihoods). You can cite PyVBMC in your work with something along the lines of

We estimated approximate posterior distibutions and approximate lower bounds to the model evidence of our models using Variational Bayesian Monte Carlo (PyVBMC; Acerbi, 2018, 2020) via the PyVBMC software (Huggins et al., 2023). PyVBMC combines variational inference and active-sampling Bayesian quadrature to perform approximate Bayesian inference in a sample-efficient manner.

Besides formal citations, you can demonstrate your appreciation for PyVBMC in the following ways:

  • Star ⭐ the VBMC repository on GitHub;
  • Subscribe to the lab's newsletter for news and updates (new features, bug fixes, new releases, etc.);
  • Follow Luigi Acerbi on Twitter for updates about VBMC/PyVBMC and other projects;
  • Tell us about your model-fitting problem and your experience with PyVBMC (positive or negative) in the lab's Discussions forum.

You may also want to check out Bayesian Adaptive Direct Search in Python (PyBADS), our companion method for fast Bayesian optimization.

Additional references

  1. Acerbi, L. (2019). An Exploration of Acquisition and Mean Functions in Variational Bayesian Monte Carlo. In Proc. Machine Learning Research 96: 1-10. 1st Symposium on Advances in Approximate Bayesian Inference, Montréal, Canada. (paper in PMLR)

BibTeX

@article{huggins2023pyvbmc,
    title = {PyVBMC: Efficient Bayesian inference in Python},
    author = {Bobby Huggins and Chengkun Li and Marlon Tobaben and Mikko J. Aarnos and Luigi Acerbi},
    publisher = {The Open Journal},
    journal = {Journal of Open Source Software},
    url = {https://doi.org/10.21105/joss.05428},
    doi = {10.21105/joss.05428},
    year = {2023},
    volume = {8},
    number = {86},
    pages = {5428}
  }

@article{acerbi2018variational,
  title={{V}ariational {B}ayesian {M}onte {C}arlo},
  author={Acerbi, Luigi},
  journal={Advances in Neural Information Processing Systems},
  volume={31},
  pages={8222--8232},
  year={2018}
}

@article{acerbi2020variational,
  title={{V}ariational {B}ayesian {M}onte {C}arlo with noisy likelihoods},
  author={Acerbi, Luigi},
  journal={Advances in Neural Information Processing Systems},
  volume={33},
  pages={8211--8222},
  year={2020}
}

@article{acerbi2019exploration,
  title={An Exploration of Acquisition and Mean Functions in {V}ariational {B}ayesian {M}onte {C}arlo},
  author={Acerbi, Luigi},
  journal={PMLR},
  volume={96},
  pages={1--10},
  year={2019}
}

License

PyVBMC is released under the terms of the BSD 3-Clause License.

Acknowledgments

PyVBMC was developed by members (past and current) of the Machine and Human Intelligence Lab at the University of Helsinki. Work on the PyVBMC package was supported by the Academy of Finland Flagship programme: Finnish Center for Artificial Intelligence FCAI.

pyvbmc's People

Contributors

bobby-huggins avatar lacerbi avatar maarnos avatar pipme avatar solosneros avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pyvbmc's Issues

Bounds for gp hyperparameters

The default recommended bounds for gp from gpyreg may be not appropariate in some cases when we have a large range of point values, e.g. the train set contains one point with 1e3 density value and another one with 1e-18 in extreme cases. In these cases, it's better to set bounds from high posterior region. Like below:

https://github.com/lacerbi/pyvbmc/blob/670fa0ce85214436923a31ee91d685e176824119/pyvbmc/vbmc/gaussian_process_train.py#L1177-L1181
https://github.com/lacerbi/pyvbmc/blob/670fa0ce85214436923a31ee91d685e176824119/pyvbmc/vbmc/gaussian_process_train.py#L1245-L1246

After that np.inf will be replaced by gpyreg's recommended bounds (link), overall it gives a broader bounds on the gp's outputscale and lengthscale.

Also, maybe here it's also good for pyvbmc to use the PLB and PUB computed from high posterior region, to generate random samples, though I haven't tried that.

Btw, it's a bit confusing right now how the specified prior, bounds in pyvbmc and the methods gp.set_bounds, gp.get_recommended_bounds in gpyreg interact with each other. It takes me a while to understand it. Maybe better to add docs or structure a bit the code.

`test_minimize_adam_matyas_with_noise` intermittently failing

Raising issue as part of JOSS review openjournals/joss-reviews/issues/5428

When running the tests with platform linux -- Python 3.11.0, pytest-7.3.1, pluggy-1.0.0 the test in pyvbmc/testing/vbmc/test_minimize_adam.py::test_minimize_adam_matyas_with_noise intermittently fails with an AssertionError, for example two failing cases were

>       assert np.all(np.abs(x) < 1.0)
E       AssertionError: assert False
E        +  where False = <function all at 0x7fd42c38c860>(array([1.43098764, 1.41719139]) < 1.0)
E        +    where <function all at 0x7fd42c38c860> = np.all
E        +    and   array([1.43098764, 1.41719139]) = <ufunc 'absolute'>(array([1.43098764, 1.41719139]))
E        +      where <ufunc 'absolute'> = np.abs

pyvbmc/testing/vbmc/test_minimize_adam.py:70: AssertionError
>       assert np.all(np.abs(x) < 1.0)
E       AssertionError: assert False
E        +  where False = <function all at 0x7f3cda609bc0>(array([1.08179515, 1.15884769]) < 1.0)
E        +    where <function all at 0x7f3cda609bc0> = np.all
E        +    and   array([1.08179515, 1.15884769]) = <ufunc 'absolute'>(array([-1.08179515, -1.15884769]))
E        +      where <ufunc 'absolute'> = np.abs

pyvbmc/testing/vbmc/test_minimize_adam.py:70: AssertionError

but on other runs the test passes. From the difference in the reported value of the x array between the runs in which fails occurred it looks like the test is non-deterministic, and looking at the code it seems that random variates are being generated from the module-level Numpy random number generator rather than a separately seeded Generator instance:

def test_minimize_adam_matyas_with_noise():
def f(x_):
val = 0.26 * (x_[0] ** 2 + x_[1] ** 2) - 0.48 * x_[0] * x_[1]
grad_1 = 0.52 * x_[0] - 0.48 * x_[1]
grad_2 = 0.52 * x_[1] - 0.48 * x_[0]
grad = np.array([grad_1, grad_2]) + np.random.normal(
scale=3, size=(2,)
)
return val, grad
x0 = np.array([-0.3, -0.4])
lb = np.array([-10.0, -10.0])
ub = np.array([10.0, 10.0])
x, y, _, _, _ = minimize_adam(f, x0, lb, ub, use_early_stopping=False)
assert np.all(np.abs(x) < 1.0)
assert np.abs(y) < 0.1

It looks like the threshold being tested for here might be a bit tight as the probability of the test failing seems to be non-negligible. More generally I would recommend using seeded random number generators in all tests to avoid intermittent failures like this and make it easier to reproduce and debug failing tests. You could for example create a shared rng fixture in a conftest.py file and parametrize it with one or more seeds passed in as a command line argument

import pytest
import numpy


def pytest_addoption(parser):
    parser.addoption("--seed", type=int, nargs="*", default=[28375632879561])


def pytest_generate_tests(metafunc):
    if "seed" in metafunc.fixturenames:
        metafunc.parametrize("seed", metafunc.config.getoption("seed"))


@pytest.fixture(scope="function")
def rng(seed):
    return numpy.random.default_rng(seed)

The above test would then be changed to something like

 def test_minimize_adam_matyas_with_noise(rng): 
     def f(x_): 
         val = 0.26 * (x_[0] ** 2 + x_[1] ** 2) - 0.48 * x_[0] * x_[1] 
         grad_1 = 0.52 * x_[0] - 0.48 * x_[1] 
         grad_2 = 0.52 * x_[1] - 0.48 * x_[0] 
         grad = np.array([grad_1, grad_2]) + rng.normal( 
             scale=3, size=(2,) 
         ) 
         return val, grad 
     ...

This would mean the default behaviour is to run with a single fixed seed but allow the option of running all tests using the rng fixture across multiple seeds by passing in values to the --seed option to the pytest command to check for robustness to different random draws.

Some options appear to not have any effect

Raising issue as part of JOSS review openjournals/joss-reviews#5428

Some of the options documented at https://acerbilab.github.io/pyvbmc/api/options/vbmc_options.html do not appear to have any corresponding active code paths which use them. From some limited scanning, those that I've come across which this appears to apply to are:

  • retry_max_fun_evals
  • optim_toolbox
  • repeated_acq_discount - this appears to have been used at one point but the relevant code block is now commented out
    # if acq_train < options["repeated_acq_discount"]*acq_now:

Some possible mistakes in docstring for `VBMC` class

Raising issue as part of JOSS review openjournals/joss-reviews/issues/5428

The docstring for the VBMC class specifies the key in the options dict for specifying to use a noisy log target density as specifytargetnoise

``options["specifytargetnoise"]`` is true, ``log_density`` should

while elsewhere in the documentation specify_target_noise is used and this seem to correspond to what's assumed in the code

specify_target_noise = False

There is also a note indicating PyVBMC does not currently support noisy target density evaluations which I think is no longer true (?) given there is a tutorial example for this case

pyvbmc/pyvbmc/vbmc/vbmc.py

Lines 114 to 117 in b7c6e38

Notes
-----
The current version of ``VBMC`` only supports noiseless evaluations of the
log posterior [1]_. Noisy evaluations as in [2]_ are not implemented yet.

`ValueError` raised in `FunctionLogger` when target density is zero

Raising issue as part of JOSS review openjournals/joss-reviews#5428

The code block

if np.any(
not np.isscalar(f_val_orig)
or not np.isfinite(f_val_orig)
or not np.isreal(f_val_orig)
):
error_message = """FunctionLogger:InvalidFuncValue:
The returned function value must be a finite real-valued scalar
(returned value {})"""
raise ValueError(error_message.format(str(f_val_orig)))

raises a ValueError when the value returned by the function is non-scalar, non-finite or non-real. When the function corresponds to the logarithm of the target density, this excludes the target density taking value zero, and so it's logarithm being negative infinity. I imagine this might be a constraint implied by using a Gaussian process to fit to the log target density evaluations, so this check probably makes sense, but as it implies a (weak) constraint on the class of posterior distributions that can be targeted it may be worth explicitly mentioning this is disallowed in the documentation, and/or suggesting workarounds (possibly outputting a large in magnitude but finite negative value as a proxy for negative infinity?). I imagine some common cases where users might want to use a target density which may take exactly evaluate to zero are: (i) when the prior has support only on a subset of the specified domain but this doesn't correspond to a simple Cartesian product of intervals as covered by the lower / upper bound options, (ii) observation noise from some truncated distribution is assumed which will mean the likelihood may evaluate to zero, (iii) the model involves a numerical solver which may fail to converge for some choices of the parameters, for which a common resolution would be to output a target density of zero to exclude these regions of parameter space from posterior (I hit against this in the latter case when trying out PyVBMC with a model which involves solving a system of ordinary differential equations for which the solver fails to converge for some parameter settings).

As a sidenote, I might be wrong but I think the np.any call in the condition expression to the if block is not needed. np.any would usually be used on an array of boolean values. Here if f_val_orig is not a scalar and so not np.isscalar(f_val_orig) evaluates to True then because of the short-circuit evaluation semantics of or then the whole expression will evaluate to True without evaluating the not np.isfinite(f_val_orig) and not np.isreal(f_val_orig) parts of the expression. If instead f_val_orig is a scalar then both np.isfinite(f_val_orig) and not np.isfinite(f_val_orig) will output scalars I believe and the overall expression will therefore always evaluate to either (scalar) True or False without the need for np.any.

`FunctionLogger.Xn` doesn't represent number of training inputs

In python self.Xn: int = -1 # Last filled entry while in matlab it starts from 0 due to difference in indexing. This causes a problem when we want to get current number of training inputs by

 self.optim_state["N"] = self.function_logger.Xn

Two solutions: either we replace the above with self.optim_state["N"] = self.function_logger.Xn + 1 or we set self.Xn: int = 0 and modify the related indexing parts in FunctionLogger.

What do you think? @Bobby-Huggins @lacerbi

Improve Logging

Hello,

we are already using the default Python package for logging in PyVBMC. I believe that there are several open issues that need to be discussed.

In VBMC (MATLAB) the printing of messages is configured using the display option (see vbmc.m). In PyVBMC this has been done in a similar way (see vbmc.py). Logging messages are then logged using the logging levels (WARN/INFO/DEBUG). I believe that this part is ported in a pythonic way and does not need major refactoring.

Some details require refactoring in my opinion:

Output to stderr/stdout:

Currently, we initialize the root logger ourselves, when the user hasn't done that yet. That means by default we log to stdout, but the user can overwrite that logging setting before initializing PyVBMC. See the documentation of the baseConfig. We should give the user some kind of option to configure that.

Printing the column headers and plotting

In Jupiter notebooks when plotting of the iterations is enabled, we want to alternate between logging the column headers, the logging data and the plot of the current iterations. See the following picture:
image

There are edge cases where this does not work (e.g. when logging to a file the columns are always printed, even though it is not necessary). I think this is related to the output to stderr/stdout point.

Testing of logging

The logging has not been tested yet. We need to do that, but this seems tricky.

How many loggers should be there?

Currently, there is only one logger, but maybe it makes sense to split the PyVBMC logger into multiple ones.

Maybe there is more to discuss - but those are the major points.

summer intern feedback and open issues

I just copied his notes from a file on slack to discuss them here.

ToDo:

Remember to add logging for variational optimization when it is added to VBMC proper.

Pain points:

  • (1, D) type pseudovectors are quite annoying everywhere

    • -> NumPy is more designed with 1D arrays in mind for vectors
    • -> negelcbo uses (D,) internally, just need to fix everywhere else and possible locations negelcbo touches at start
  • pylint is not used that much, and the pylint file is not the best

    • -> a replacement file exists, but is not commited anywhere
    • -> if there are lots of warnings for pylint then that discourages use, what is going from 1000 to 1001 warnings compared to going from 0 to 1?
    • -> for comparision gpyreg has only 10 pylint warnings currently

Things to investigate:

I was never able to replicate ADAM VP optimization result exactly when weight optimization was on. Is there some sort of bug

  • a) in ADAM?
    • -> seems unlikely, the code is too simple. if there is anything wrong it is in the early stopping routine
  • b) in gradient computations?
    • -> we can get exact matches in test cases, and originally I could only find the tiniest difference.
    • -> maybe this is just tiny numerical error that eventually causes divergence?
    • -> if so, then why didn't this happen without weight optimization?
  • c) in VP functions?
    • -> possible, but not my area. also, this would rear its head without weight optimization as well

Ideas:

  • it could be possible to define class functions in a different file, so we could simplify variational_optimization.py and gaussian_process_train
    -> no need to pass around optim_state etc.

Notes:

If trying to get same floating point behaviour with MATLAB, remember that all random numbers that are generated must be exactly the same. This means fixing the random number seeds to be the same, but also replacing differing algorithms in both MATLAB and Python. To be specific, we have to replace the generation of normally distributed random numbers, generation of permutations and possibly more. The Python side for these is already in the library. Relatedly, commands such as "writematrix" and np.loadmatrix are your best friend, since they make it possible to compare the internal computations and find the spots where things go wrong. The tests and their data for VP optimization were generated in this way.

Beware of possible reference issues! Several bugs so far here and in gpyreg were caused by not making actual copies but copies to references.

Allowing finer grained control over random variate generation

In quite a few places in the main (non-test) code, random variates are sampled using functions in the top-level numpy.random namespace which map to the methods of a (globally shared) RandomState instance. From a reproducibility / ease of debugging perspective it would be better to instead allow explicitly passing an instance of the numpy.random.Generator class (introduced in Numpy v1.17) or the legacy numpy.random.RandomState class to functions which use (pseudo) random variates - see for example this blog post for a nice write up of why this is recommended. The current interface could be maintained by making this an optional keyword argument that defaults to a global Generator / RandomState instance if not specified, while allowing the user to explicitly control the random number generator if desired. This would also facilitate ensuring the tests are deterministic as discussed in #135.

Just to be clear as this would be quite a substantial change, I'm suggesting this more as a feature request / nice to have in future rather than as a blocker to acceptance for the JOSS review!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.