Giter Club home page Giter Club logo

h2o4gpu's Introduction

H2O4GPU

Join the chat at https://gitter.im/h2oai/h2o4gpu

H2O4GPU is a collection of GPU solvers by H2Oai with APIs in Python and R. The Python API builds upon the easy-to-use scikit-learn API and its well-tested CPU-based algorithms. It can be used as a drop-in replacement for scikit-learn (i.e. import h2o4gpu as sklearn) with support for GPUs on selected (and ever-growing) algorithms. H2O4GPU inherits all the existing scikit-learn algorithms and falls back to CPU algorithms when the GPU algorithm does not support an important existing scikit-learn class option. The R package is a wrapper around the H2O4GPU Python package, and the interface follows standard R conventions for modeling.

Daal library added for CPU, currently supported only x86_64 architecture.

Requirements

  • PC running Linux with glibc 2.17+

  • Install CUDA with bundled display drivers ( CUDA 8 or CUDA 9 or CUDA 9.2) or CUDA 10)

  • Python shared libraries (e.g. On Ubuntu: sudo apt-get install libpython3.6-dev)

When installing, choose to link the cuda install to /usr/local/cuda . Ensure to reboot after installing the new nvidia drivers.

  • Nvidia GPU with Compute Capability >= 3.5 (Capability Lookup).

  • For advanced features, like handling rows/32 > 2^16 (i.e., rows > 2,097,152) in K-means, need Capability >= 5.2

  • For building the R package, libcurl4-openssl-dev, libssl-dev, and libxml2-dev are needed.

User Installation

Note: Installation steps mentioned below are for users planning to use H2O4GPU. See DEVEL.md for developer installation.

H2O4GPU can be installed using either PIP or Conda

Prerequisites

Add to ~/.bashrc or environment (set appropriate paths for your OS):

export CUDA_HOME=/usr/local/cuda # or choose /usr/local/cuda9 for cuda9 and /usr/local/cuda8 for cuda8
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CUDA_HOME/lib64/:$CUDA_HOME/lib/:$CUDA_HOME/extras/CUPTI/lib64
  • Install OpenBlas dev environment:
sudo apt-get install libopenblas-dev pbzip2

If you are building the h2o4gpu R package, it is necessary to install the following dependencies:

sudo apt-get -y install libcurl4-openssl-dev libssl-dev libxml2-dev

PIP install

Download the Python wheel file (For Python 3.6):

Start a fresh pyenv or virtualenv session.

Install the Python wheel file. NOTE: If you don't use a fresh environment, this will overwrite your py3nvml and xgboost installations to use our validated versions.

pip install h2o4gpu-0.3.0-cp36-cp36m-linux_x86_64.whl

Conda installation

Ensure you meet the Requirements and have installed the Prerequisites.

If not already done you need to install conda package manager. Ensure you test your conda installation

H204GPU packages for CUDA8, CUDA 9 and CUDA 9.2 are available from h2oai channel in anaconda cloud.

Create a new conda environment with H2O4GPU based on CUDA 9.2 and all its dependencies using the following command. For other cuda versions substitute the package name as needed. Note the requirement for h2oai and conda-forge channels.

conda create -n h2o4gpuenv -c h2oai -c conda-forge -c rapidsai h2o4gpu-cuda10

Once the environment is created activate it source activate h2o4gpuenv.

To test, start an interactive python session in the environment and follow the steps in the Test Installation section below.

h2o4gpu R package

At this point, you should have installed the H2O4GPU Python package successfully. You can then go ahead and install the h2o4gpu R package via the following:

if (!require(devtools)) install.packages("devtools")
devtools::install_github("h2oai/h2o4gpu", subdir = "src/interface_r")

Detailed instructions can be found here.

Test Installation

To test your installation of the Python package, the following code:

import h2o4gpu
import numpy as np

X = np.array([[1.,1.], [1.,4.], [1.,0.]])
model = h2o4gpu.KMeans(n_clusters=2,random_state=1234).fit(X)
model.cluster_centers_

should give input/output of:

>>> import h2o4gpu
>>> import numpy as np
>>>
>>> X = np.array([[1.,1.], [1.,4.], [1.,0.]])
>>> model = h2o4gpu.KMeans(n_clusters=2,random_state=1234).fit(X)
>>> model.cluster_centers_
array([[ 1.,  1.  ],
       [ 1.,  4.  ]])

To test your installation of the R package, try the following example that builds a simple XGBoost random forest classifier:

library(h2o4gpu)

# Setup dataset
x <- iris[1:4]
y <- as.integer(iris$Species) - 1

# Initialize and train the classifier
model <- h2o4gpu.random_forest_classifier() %>% fit(x, y)

# Make predictions
predictions <- model %>% predict(x)

Next Steps

For more examples using Python API, please check out our Jupyter notebook demos. To run the demos using a local wheel run, at least download src/interface_py/requirements_runtime_demos.txt from the Github repo and do:

pip install -r src/interface_py/requirements_runtime_demos.txt

and then run the jupyter notebook demos.

For more examples using R API, please visit the vignettes.

Running Jupyter Notebooks

You can run Jupyter Notebooks with H2O4GPU in the below two ways

Creating a Conda Environment

Ensure you have a machine that meets the Requirements and Prerequisites mentioned above.

Next follow Conda installation instructions mentioned above. Once you have activated the environment, you will need to downgrade tornado to version 4.5.3 refer issue #680. Start Jupyter notebook, and navigate to the URL shown in the log output in your browser.

source activate h2o4gpuenv
conda install tornado==4.5.3
jupyter notebook --ip='*' --no-browser

Start a Python 3 kernel, and try the code in example notebooks

Using precompiled docker image

Requirements:

Download the Docker file (for linux_x86_64):

  • Bleeding edge (changes with every successful master branch build):

Load and run docker file (e.g. for bleeding-edge of cuda92):

jupyter notebook --generate-config
echo "c.NotebookApp.allow_remote_access = False >> ~/.jupyter/jupyter_notebook_config.py # Choose True if want to allow remote access
pbzip2 -dc h2o4gpu-0.3.0.10000-cuda92-runtime.tar.bz2 | nvidia-docker load
mkdir -p log ; nvidia-docker run --name localhost --rm -p 8888:8888 -u `id -u`:`id -g` -v `pwd`/log:/log -v /home/$USER/.jupyter:/jupyter --entrypoint=./run.sh opsh2oai/h2o4gpu-0.3.0.10000-cuda92-runtime &
find log -name jupyter* -type f -printf '%T@ %p\n' | sort -k1 -n | awk '{print $2}' | tail -1 | xargs cat | grep token | grep http | grep -v NotebookApp

Copy/paste the http link shown into your browser. If the "find" command doesn't work, look for the latest jupyter.log file and look at contents for the http link and token.

If the link shows no token or shows ... for token, try a token of "h2o" (without quotes). If running on your own host, the weblink will look like http://localhost:8888:token with token replaced by the actual token.

This container has a /demos directory which contains Jupyter notebooks and some data.

Plans

The vision is to develop fast GPU algorithms to complement the CPU algorithms in scikit-learn while keeping full scikit-learn API compatibility and scikit-learn CPU algorithm capability. The h2o4gpu Python module is to be used as a drop-in-replacement for scikit-learn that has the full functionality of scikit-learn's CPU algorithms.

Functions and classes will be gradually overridden by GPU-enabled algorithms (unless n_gpu=0 is set and we have no CPU algorithm except scikit-learn's). The CPU algorithms and code initially will be sklearn, but gradually those may be replaced by faster open-source codes like those in Intel DAAL.

This vision is currently accomplished by using the open-source scikit-learn and xgboost and overriding scikit-learn calls with our own GPU versions. In cases when our GPU class is currently incapable of an important scikit-learn feature, we revert to the scikit-learn class.

As noted above, there is an R API in development, which will be released as a stand-alone R package. All algorithms supported by H2O4GPU will be exposed in both Python and R in the future.

Another primary goal is to support all operations on the GPU via the GOAI initiative. This involves ensuring the GPU algorithms can take and return GPU pointers to data instead of going back to the host. In scikit-learn API language these are called fit_ptr, predict_ptr, transform_ptr, etc., where ptr stands for memory pointer.

RoadMap

2019 Q2:

  • A new processing engine that allows to scale beyond GPU memory limits
  • k-Nearest Neighbors
  • Matrix Factorization
  • Factorization Machines
  • API Support: GOAI API support
  • Data.table support

More precise information can be found in the milestone's list.

Solver Classes

Among others, the solver can be used for the following classes of problems

  • GLM: Lasso, Ridge Regression, Logistic Regression, Elastic Net Regulariation
  • KMeans
  • Gradient Boosting Machine (GBM) via XGBoost
  • Singular Value Decomposition(SVD) + Truncated Singular Value Decomposition
  • Principal Components Analysis(PCA)

Benchmarks

Our benchmarking plan is to clearly highlight when modeling benefits from the GPU (usually complex models) or does not (e.g. one-shot simple models dominated by data transfer).

We have benchmarked h2o4gpu, scikit-learn, and h2o-3 on a variety of solvers. Some benchmarks have been performed for a few selected cases that highlight the GPU capabilities (i.e. compute or on-GPU memory operations dominate data transfer to GPU from host):

Benchmarks for GLM, KMeans, and XGBoost for CPU vs. GPU.

A suite of benchmarks are computed when doing "make testperf" from a build directory. These take all of our tests and benchmarks h2o4gpu against h2o-3. These will soon be presented as a live commit-by-commit streaming plots on a website.

Contributing

Please refer to our CONTRIBUTING.md and DEVEL.md for instructions on how to build and test the project and how to contribute. The h2o4gpu Gitter chatroom can be used for discussion related to open source development.

GitHub issues are used for bugs, feature and enhancement discussion/tracking.

Questions

References

  1. Parameter Selection and Pre-Conditioning for a Graph Form Solver -- C. Fougner and S. Boyd
  2. Block Splitting for Distributed Optimization -- N. Parikh and S. Boyd
  3. Distributed Optimization and Statistical Learning via the Alternating Direction Method of Multipliers -- S. Boyd, N. Parikh, E. Chu, B. Peleato, and J. Eckstein
  4. Proximal Algorithms -- N. Parikh and S. Boyd

Copyright

Copyright (c) 2017, H2O.ai, Inc., Mountain View, CA
Apache License Version 2.0 (see LICENSE file)


This software is based on original work under BSD-3 license by:

Copyright (c) 2015, Christopher Fougner, Stephen Boyd, Stanford University
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

h2o4gpu's People

Contributors

abal5 avatar arnocandel avatar bungun avatar chrisfougner avatar creaturedev avatar far0n avatar foges avatar h2o-ops avatar hemenkapadia avatar khevn avatar ledell avatar mdymczyk avatar meganjkurka avatar michal-raska avatar mstensmo avatar navdeep-g avatar nkalonia1 avatar pseudotensor avatar sh1ng avatar stjoern avatar terrytangyuan avatar tomkraljevic avatar vopani 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  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

h2o4gpu's Issues

GLM C++/CUDA code

  • Implementation should be in cpp/cu files mostly

  • DRY the code so we don't duplicate it

Review licensing

Make sure all the license/legal related notes are in place (in the README, LICENSE and code files).

Logging framework

Add a proper logging framework for C++ and Python enabling debug prints and (maybe) performance timings.

Use Intel DAAL for CPU side of many algorithms

https://software.intel.com/en-us/intel-daal/details

Algorithms

Data Analysis: Characterization, Summarization, and Transformation

Low Order Moments
Computes the basic dataset characteristics such as sums, means, second order raw moments, variances, standard deviations, etc.

Quantile
Computes quantiles that summarize the distribution of data across equal-sized groups as defined by quantile orders.

Correlation and Variance-Covariance Matrices
Quantifies pairwise statistical relationship between feature vectors.

Cosine Distance Matrix
Measures pairwise similarity between feature vectors using cosine distances.

Correlation Distance Matrix
Measures pairwise similarity between feature vectors using correlation distances.

Cholesky Decomposition
Decomposes a symmetric positive-definite matrix into a product of a lower triangular matrix and its transpose. This decomposition is a basic operation used in solving linear systems, non-linear optimization, Kalman filtration, etc.

QR Decomposition
Decomposes a general matrix into a product of an orthogonal matrix and an upper triangular matrix. This decomposition is used in solving linear inverse and least squares problems. It is also a fundamental operation in finding eigenvalues and eigenvectors.

SVD
Singular Value Decomposition decomposes a matrix into a product of a left singular vector, singular values, and a right singular vector. It is the basis of Principal Component Analysis, solving linear inverse problems, and data fitting.

PCA
Principal Component Analysis reduces the dimensionality of data by transforming input feature vectors into a new set of principal components orthogonal to each other.

K-Means
Partitions a dataset into clusters of similar data points. Each cluster is represented by a centroid, which is the mean of all data points in the cluster.

Expectation-Maximization
Finds maximum-likelihood estimate of the parameters in models. It is used for the Gaussian Mixture Model as a clustering method. It can also be used in non-linear dimensionality reduction, missing value problems, etc.

Outlier Detection
Identifies observations that are abnormally distant from other observations. An entire feature vector (multivariate) or a single feature value (univariate), can be considered in determining if the corresponding observation is an outlier.

Association Rules
Discovers a relationship between variables with certain level of confidence.

Linear and Radial Basis Function Kernel Functions
Map data onto higher-dimensional space.

Quality Metrics
Compute a set of numeric values to characterize quantitative properties of the results returned by analytical algorithms. These metrics include Confusion Matrix, Accuracy, Precision, Recall, F-score, etc.

Machine Learning: Regression, Classification, and More

Neural Networks for Deep Learning
A programming paradigm which enables a computer to learn from observational data.

Linear and Ridge Regressions
Models relationship between dependent variables and one or more explanatory variables by fitting linear equations to observed data.

Naïve Bayes Classifier
Splits observations into distinct classes by assigning labels. Naïve Bayes is a probabilistic classifier that assumes independence between features. Often used in text classification and medical diagnosis, it works well even when there are some level of dependence between features.

Boosting
Builds a strong classifier from an ensemble of weighted weak classifiers, by iteratively re-weighting according to the accuracy measured for the weak classifiers. A decision stump is provided as a weak classifier. Available boosting algorithms include AdaBoost (a binary classifier), BrownBoost (a binary classifier), and LogitBoost (a multi-class classifier).

SVM
Support Vector Machine is a popular binary classifier. It computes a hyperplane that separates observed feature vectors into two classes.

Multi-Class Classifier
Builds a multi-class classifier using a binary classifier such as SVM.

ALS
Alternating Linear Squares is a collaborative filtering method of making predictions about the preferences of a user, based on preference information collected from many users.

Standard and Truncated SVD

Standard SVD on GPU is in place without API, but holding until can see how to do truncated SVD. Also, seems sklearn truncated SVD uses lots of memory despite being truncated -- can one optimize more for memory vs. time?

KMeans CUDA code

  • Implementation should be in cpp/cu files mostly

  • DRY the code so we don't duplicate it

GLM (all models): should accept integer for model parameters

logreg = h2o4gpu.LogisticRegression(alpha_max = 1, alpha_min = 1)

error:

---------------------------------------------------------------------------
H2O4GPUTypeError                          Traceback (most recent call last)
<ipython-input-55-55d86fdd97e3> in <module>()
      1 logreg = h2o4gpu.LogisticRegression(alpha_max = 1, 
----> 2                                     alpha_min = 1)

~/anaconda3/lib/python3.6/site-packages/h2o4gpu/solvers/logistic.py in __init__(self, n_threads, n_gpus, fit_intercept, lambda_min_ratio, n_lambdas, n_folds, n_alphas, tol, lambda_stop_early, glm_stop_early, glm_stop_early_error_fraction, max_iter, verbose, give_full_path, lambda_max, alpha_max, alpha_min)
     60             alpha_max=alpha_max,
     61             alpha_min=alpha_min,
---> 62             order=None,)

~/anaconda3/lib/python3.6/site-packages/h2o4gpu/solvers/elastic_net_base.py in __init__(self, n_threads, n_gpus, intercept, lambda_min_ratio, n_lambdas, n_folds, n_alphas, tol, lambda_stop_early, glm_stop_early, glm_stop_early_error_fraction, max_iterations, verbose, family, give_full_path, lambda_max, alpha_max, alpha_min, order)
     86                           'elasticnet'], "family should be set to 'logistic' or 'elasticnet' but got " + family
     87         assert_is_type(lambda_max, float, None)
---> 88         assert_is_type(alpha_max, float, None)
     89         assert_is_type(alpha_min, float, None)
     90 

~/anaconda3/lib/python3.6/site-packages/h2o4gpu/util/typechecks.py in assert_is_type(var, *types, **kwargs)
    448     vtn = _get_type_name(type(var))
    449     raise H2O4GPUTypeError(var_name=vname, var_value=var, var_type_name=vtn, exp_type_name=etn, message=message,
--> 450                        skip_frames=skip_frames)
    451 
    452 

H2O4GPUTypeError: Argument `alpha_max` should be a ?float, got integer 1

while the following works:
logreg = h2o4gpu.LogisticRegression(alpha_max = 1.0, alpha_min = 1.0)

GLM: pass training data as int (both X and y)

X = np.array([1,2,3])
y = np.array([1,2,3,4,5,6,7,8,9,10])
lm = h2o4gpu.LinearRegression()
lm.fit(X, y)

gives the following error

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-40-b5e451bf1fa8> in <module>()
      1 lm = h2o4gpu.LinearRegression()
----> 2 lm.fit(X, y)

~/anaconda3/lib/python3.6/site-packages/h2o4gpu/solvers/elastic_net_base.py in fit(self, train_x, train_y, valid_x, valid_y, weight, give_full_path, do_predict, free_input_data, tol, lambda_stop_early, glm_stop_early, glm_stop_early_error_fraction, max_iterations, verbose, order)
    711             valid_x_np,
    712             valid_y_np,
--> 713             weight_np,
    714         )
    715         precision = 0  # won't be used

~/anaconda3/lib/python3.6/site-packages/h2o4gpu/solvers/elastic_net_base.py in _upload_data(self, source_dev, train_x, train_y, valid_x, valid_y, weight)
   1355         d = c_void_p(0)
   1356         e = c_void_p(0)
-> 1357         if self.double_precision == 1:
   1358             c_ftype = c_double
   1359 

AttributeError: 'LinearRegression' object has no attribute 'double_precision'

if X is float but y is integer, no errors are raised but the model doesn't train properly

X = np.array([1,2,3])
X = X.astype(float)
y = np.array([1,2,3,4,5,6,7,8,9,10])

lm = h2o4gpu.LinearRegression()
lm.fit(X, y)

print(lm.predict(np.array([15.0, 16.0])))
print(lm.X)

the output is

[[ 0.  0.]]
[[ 0.]]

RandomForest wrapper

  • Add a RandomForest wrapper, API should resemble SciKit-Learn's RandomForestRegressor and RandomForestClassifier (up for discussion)

  • Implementation should for now just call XGBoost but be as generic as possible should we want to run other algorithms instead (for example performance based heuristics etc.).

  • Don't forget tests.

Implement PCA

  • CUDA implementation takes priority. Then Python API, C++ and R.

  • Add unit tests

  • Add performance tests comparing to other frameworks

Implement linear and general SVM

  • CUDA implementation takes priority. Then Python API, C++ and R.

  • Add unit tests

  • Add performance tests comparing to other frameworks

Improve contributor's guide

Add a proper contributors guide with details (best practices used in the project, our PR strategy, how to run CI tests, where to find issues etc.)

KMeans invalid pointer call.

How to reproduce:

  • run kmeans.fit(X) first using kmeans object with 1 GPU, then twice (or more) with 2 GPUs.

Error:

GPUassert: invalid device pointer gpu/include/kmeans_labels.h 170

Seems like we are deallocating something too fast or not checking if every pointer we use got properly allocated.

Jenkins do all make tests

Separate builds for make test, make testbig, make testperf, make testbigperf . Jenkins should use dotest, dotestbig, dotestperf, dotestbigperf

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.