CoolFace
Apppublic

SaulLu/test

sourceHugging Faceupdated 5y agoView on Hugging Face
2likes
index.html592 linesDownload Raw Back to root
1<!doctype html>2<html lang="en">3<head>4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>5     <title>learning@home</title>6     <meta name="description" content="A library to train large neural networks across the internet. Imagine training GPT-3 on thousands of nodes from universities, companies, and volunteers.">7     <link rel="mask-icon" href="logo_small.png">8     <link rel="alternate icon" class="js-site-favicon" type="image/png" href="logo.png">9     <link rel="icon" class="js-site-favicon" type="image/png" href="logo.png">10     <meta property="og:url" content="https://learning-at-home.github.io">11     <meta property="og:site_name" content="learning@home">12     <meta property="og:title" content="Train vast neural networks together">13     <meta property="og:description" content="A library to train large neural networks across the internet. Imagine training one huge transformer on thousands of computers from universities, companies, and volunteers.">14     <meta property="og:image" content="https://learning-at-home.github.io/logo_small.png">15     <meta property="og:image:type" content="image/png">16     <meta property="og:image:width" content="96">17     <meta property="og:image:height" content="96">18     <meta property="twitter:site" content="https://github.com/learning-at-home/hivemind">19     <meta property="twitter:creator" content="learning@home contributors">20     <meta property="twitter:card" content="summary_large_image">21     <meta property="twitter:title" content="learning@home">22     <meta property="twitter:description" content="Hivemind is a library to train large neural networks across the internet. Imagine training one huge transformer on thousands of computers from universities, companies, and volunteers.">23     <meta property="twitter:image:src" content="https://learning-at-home.github.io/logo_horizontal.png">24    25    26     <link rel="stylesheet" href="https://unpkg.com/flickity@2/dist/flickity.min.css">27     <meta name="viewport" content="width=device-width, initial-scale=1">28     <script src="https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js"></script>29</head>30<style>31        :root {32          --border-color: black;33          --window-color: white;34          --background-move-on-cursor: false;35          --background-color: white;36          --background-cursor-width: 400;37          --background-cursor-height: 200;38          --background-show-if-wider-than: 500;39          --background-speed: 0.001;40          --energy-decay: 0.3;41        }42        body {43          width: 100%;44          margin: 0 auto;45          background-color: var(--background-color);46        }47        #container {48          position: relative;49          width: 100%;50          margin: 0 auto;51        }52        #container canvas, #overlay {53          width: 100%;54          margin: 0 auto;55          position: absolute;56        }57        canvas {58          background-color: var(--background-color);59          width: 0px; /* will be changed on init */60          overflow: hidden;61        }62        #main_window {63          width: 80%;64          min-width: 350px;65          margin: 0 auto;66          text-align: center;67        }68        .faded {69          margin: 0 auto;70          background: var(--window-color);71          box-shadow: 0 0 5px 5px var(--window-color);72          font-family: cursive;73          font-family: "Gill Sans", sans-serif;74          display: inline-block75        }76        .title {77           font-size: 48px;78           box-shadow: 0 0 5px 5px var(--window-color);79           font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,80                        sans-serif,Apple Color Emoji,Segoe UI Emoji;81        }82        .text {83           font-size: 16px;84           box-shadow: 0 0 5px 5px var(--window-color);85           font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,86                        sans-serif,Apple Color Emoji,Segoe UI Emoji;87        }88        .scrollbar {89          overflow-y: scroll;90        }91        .arxiv_button {92          position: relative;93          display: inline-block;94          width: 80px;95          height: 28px;96          background-image: linear-gradient(180deg, #fafbfc, #eff3f6 90%);97          color: #24292e;98          border: 1px solid rgba(27,31,35,.2);99          text-align: center;100          cursor: pointer;101          border-radius: 4px;102          padding-right: 0px;103          padding-top: 2.5px;104          font-size: 12px;105          font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif;106          font-weight: 600;107        }108        .arxiv_button:before {109          content: "";110          vertical-align:middle;111          display: inline-block;112          width: 24px;113          height: 24px;114          border: none;115          margin-left: -16px;116          margin-right: 4px;117          margin-top: -2px;118          background: url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" class="ionicon s-ion-icon" viewBox="0 0 512 512"><path d="M428 224H288a48 48 0 01-48-48V36a4 4 0 00-4-4h-92a64 64 0 00-64 64v320a64 64 0 0064 64h224a64 64 0 0064-64V228a4 4 0 00-4-4z"></path><path d="M419.22 188.59L275.41 44.78a2 2 0 00-3.41 1.41V176a16 16 0 0016 16h129.81a2 2 0 001.41-3.41z"></path></svg>') right center no-repeat;119          background-size: 18px 16px;120        }121        .arxiv_button:hover {122            background-color:#e6ebf1;123            background-position:-0.5em;124            border-color: #9fa4a9;125            border-color:rgba(27,31,35,.35);126            background-image:linear-gradient(180deg, #f0f3f6, #e6ebf1 90%)127        }128        a:link {129            color: #00194a;130            text-decoration: none;131        }132        a:visited {133            color: #3f004a;134            text-decoration: none;135        }136        .tooltip {137          position: relative;138          display: inline-block;139          border-bottom: 1px dotted black;140        }141 142        .tooltip .tooltiptext {143          visibility: hidden;144          width: 240px;145          background-color: #555;146          color: #fff;147          text-align: center;148          border-radius: 6px;149          padding: 5px 0;150          position: absolute;151          z-index: 1;152          bottom: 125%;153          left: 50%;154          margin-left: -60px;155          opacity: 0;156          transition: opacity 0.3s;157        }158 159        .tooltip .tooltiptext::after {160          content: "";161          position: absolute;162          top: 100%;163          left: 50%;164          margin-left: -5px;165          border-width: 5px;166          border-style: solid;167          border-color: #555 transparent transparent transparent;168        }169 170        .tooltip:hover .tooltiptext {171          visibility: visible;172          opacity: 1;173        }174    </style>175 176<body>177    <div id="container">178        <canvas></canvas>179        <div id="overlay">180            <div id="main_window">181                <div id="header">182                    <img src="logo.png" id="bug-logo" 183                         style="width: 40%; max-height: 320px; max-width: 320px; z-index:1000; position: relative;">184                    <br>185                    <h1 class="faded title" style="margin-top:-3%;">186                        <p style="margin-top: 0px; margin-bottom:0px;">187                            <sup style="font-size: 18px">learning@home</sup>188                            <span id="title_text">hivemind</span>189                            <sup style="font-size: 18px">v0.10&nbsp;beta&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</sup>190                        </p>191                        <p style="font-size: 18px; margin-top:0px; margin-bottom:0px;">train vast neural networks together</p>192                    </h1>193                </div>194                195                <div class="faded text" style="margin-top:35px; width: 100%; max-width: 900px;">196                    A library to train large neural networks across the internet. Imagine training one huge transformer on thousands of computers from universities, companies, and volunteers.197                    <br><br>198                    <div style="width:100%; margin: 0 auto;">199                        <a class="github-button" href="https://github.com/learning-at-home/hivemind" data-size="large" data-show-count="false" aria-label="Star learning-at-home/hivemind on GitHub">Code</a>200                        <div style="overflow: hidden; white-space: nowrap; margin: 0 auto; display: inline-block;">201                            <button onclick="window.open('https://arxiv.org/abs/2002.04013');" 202                                    class="arxiv_button">Paper</button>203                        </div>204                        <a href="https://twitter.com/intent/tweet?hashtags=learningathome,joinhivemind&text=Join%20the%20deep%20learning%20hivemind!%0Alearning-at-home.github.io"205                           class="twitter-hashtag-button" data-show-count="true" data-size="large">Tweet</a>206                        <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>207 208                        <script async defer src="https://buttons.github.io/buttons.js"></script>209                    </div>210                </div>211                <hr class="faded" style="width: 70%; margin-top:20px;"><br>212                213                <div class="faded" style="margin-top:35px; display: inline-block; text-align:center;">214                    <div style="width: 100%; max-width: 440px; display: inline-block; vertical-align: top; text-align:left; padding-right: 5px">215                        <p class="faded title" style="font-size:28px; margin-bottom:12px">216                            Why should you care?</p>217                        218                        <span class="faded text" style="margin-top: 4px;">219                            Larger neural networks are winning:220                            <ul style="text-align: left; list-style-position: inside; margin-top: 12px; margin-left: -32px;">221                                <li style="margin-top: 12px;">222                                    pretrained transformers <a href=https://w4ngatang.github.io/static/papers/superglue.pdf target="_blank" rel="noopener noreferrer">dominate</a> most NLP tasks;</li>223                                <li style="margin-top: 12px;">224                                    bigger CNNs <a href="https://arxiv.org/abs/1912.11370" target="_blank" rel="noopener noreferrer">perform better</a> at computer vision;</li>225                                <li style="margin-top: 12px;">226                                    GPT-3 has <a href="https://arxiv.org/abs/2005.14165" target="_blank" rel="noopener noreferrer">175B</a> parameters and <a target="_blank" rel="noopener noreferrer" href="https://arxiv.org/abs/2006.16668">the race continues</a></li>227                            </ul>228                            229                            With transfer learning, these large models can harness nearly unlimited raw data to improve performance on both <a href=https://paperswithcode.com/task/language-modelling target="_blank" rel="noopener noreferrer">academic benchmarks</a> and solve <a href=https://medium.com/towards-artificial-intelligence/crazy-gpt-3-use-cases-232c22142044 target="_blank" rel="noopener noreferrer">new unexpected</a> tasks.230                            231                            232                            <center>233                              <span style="margin-top: 16px; font-style: italic; font-size: 14px;">234                                Image credit: [1] <a href="https://arxiv.org/abs/2001.08361" target="_blank" rel="noopener noreferrer">Kaplan et al. (2020)</a>, [2,&nbsp;3] <a href="https://arxiv.org/abs/1811.06965" target="_blank" rel="noopener noreferrer">Huang et al. (2018)</a>235                              </span>236                            </center>237                        </span>238 239                    </div>240                    <div class style="width: 100%; max-width: 440px; vertical-align: middle; display: inline-block;">241                        <div class="carousel" 242                          data-flickity='{ "draggable": ">1", "pageDots": false, "groupCells": true}'>243                            <div class="carousel-cell" style="padding-left:30px; padding-right:30px;">244                                <img width=340px height=250px src="kaplan1.png">245                            </div>246                            <div class="carousel-cell" style="padding-left:30px; padding-right:40px;">247                                <img width=320px height=250px src="gpipe1.png"></div>248                            <div class="carousel-cell" style="padding-left:40px; padding-right:30px;">249                                <img width=320px height=250px src="gpipe2.png"></div>250                        </div>251                    </div>252 253                    <p class="faded text" style="width: 100%; max-width: 900px; margin-top:16px; text-align: left">254                        That said, training large neural networks isn't cheap. The hardware used for the <a href="https://arxiv.org/abs/1909.08053" target="_blank" rel="noopener noreferrer">previous largest</a> language model costs over $25 million. A single training run for GPT-3 will set you back <a href="https://lambdalabs.com/blog/demystifying-gpt-3/" target="_blank" rel="noopener noreferrer">at least $4.6M</a> in cloud GPUs. As a result, researchers can't contribute to state-of-the-art deep learning models and practitioners can't build applications without <a href=https://blogs.microsoft.com/ai/openai-azure-supercomputer target="_blank" rel="noopener noreferrer">being supported</a> by a megacorporation. If&nbsp;we&nbsp;want the future of AI to be bright, it can't be private.255                    </p>256                  257                </div>258                <br>259 260                <div class="faded" style="margin-top:32px; width: 100%; max-width: 900px; display: inline-block; text-align: left;">261                    <p class="faded title" style="font-size:28px;">262                        What is hivemind?</p>263                    <br>264                    <p class="faded text" style="margin-top:16px;">265                        Hivemind is a library for decentralized training of large neural networks. In a nutshell, you want to train a neural network, but all you have is a bunch of enthusiasts with unreliable computers that communicate over the internet. Any peer may fail or leave at any time, but the training must go on. To meet this objective, hivemind models use a specialized layer type: the <b>D</b>ecentralized <b>M</b>ixture of <b>E</b>xperts (DMoE). Here's how it works:<br>266                    </p>267                    <div class="container">268                        <video src="dmoe_demonstration.mp4" style="width:100%; max-width:880px; min-width:320px; margin-top:12px; float:center;" controls poster="poster.png">269                        </video>270                    </div>271                    <br>272                    <div style="text-align: center">273                      <div style="width: 100%; max-width: 500px; vertical-align: top; display: inline-block; padding-right: 5px; text-align: left;">274                        <span class="faded text" style="margin-top:16px">275                            In a hivemind experiment, all peers:276                            <ul style="text-align: left; list-style-position: inside; margin-top: 16px; margin-left: -32px;">277                                <li style="margin-top: 12px;">278                                    host one or more experts depending on their hardware;</li>279                                <li style="margin-top: 12px;">280                                    run asynchronous training, calling experts from other peers,</li>281                                <li style="margin-top: 12px;">282                                    form a Distributed Hash Table to discover each other's experts<br>283                                    <span style="padding-left:24px">284                                        -&nbsp;the same type of protocol that powers BitTorrent&nbsp;file&nbsp;sharing.</span>285                                </li>286                            </ul>287                            <p> Hivemind uses <a href=https://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf target="_blank" rel="noopener noreferrer">Kademlia</a>-based DHT that can scale to tens of thousands of peers with logarithmic search complexity.</p>288                        </span>289                    </div>290                    <div style="width:100%; max-width: 385px; vertical-align: top; display: inline-block; margin-top: 0px; align:center;">291                        <img src="hivemind_components.png" style="width:100%; max-width:240px">292                    </div>293                        294                    <p class="faded text" style="text-align: left;">295                      On each forward pass, a peer first determines what "speciality" of experts is needed to process the current inputs using a small "gating function" module. Then it finds <i>k</i>&nbsp;(e.g. 4) most suitable experts from other peers in the network using the DHT protocol. Finally, it sends forward pass requests to the selected experts, collects their outputs and averages them for the final prediction. Compared to traditional architectures, the Mixture-of-Experts needs much less bandwidth as every input is only sent to a small fraction of all experts.296                    </p>297                    <div style="width:100%; max-width: 900px; vertical-align: top; display: inline-block; margin-top: 0px; align:center;">298                        <img src="dmoe-forward-backward.png" style="width:100%;">299                    </div>300                    <p class="faded text" style="text-align: left; margin-top:5px">301                      More importantly, the decentralized Mixture-of-Experts layers are inherently fault-tolerant: if some of the chosen experts fail to respond, the model will simply average the remaining ones and call that <a href=https://jmlr.org/papers/v15/srivastava14a.html target="_blank" rel="noopener noreferrer">dropout</a>. In the event that all <i>k</i> experts fail simultaneously, a peer will backtrack and find another <i>k</i> experts across the DHT. Finally, since every input is likely to be processed by different experts, hivemind peers run several <a href=https://papers.nips.cc/paper/4390-hogwild-a-lock-free-approach-to-parallelizing-stochastic-gradient-descent target="_blank" rel="noopener noreferrer">asynchronous training</a> batches to better utilize their hardware.302                    </p>303 304                  </div>305                </div>306                <br>307                308                <div class="faded" style="margin-top:35px; width: 100%; max-width: 900px; align: center; vertical-align: top; display: inline-block; text-align:left;">309                    <p class="faded title" style="font-size:28px;">310                        What is hivemind for?311                    </p>312                    <br>313                    314                    <span class="faded text" style="margin-top:15px">315                        Hivemind is designed for you to:316                        <ul style="text-align: middle; list-style-position: inside; margin-top: 16px; margin-left: -32px;">317                            <li style="margin-top: 12px;">318                                run crowdsourced deep learning using compute from volunteers or decentralized participants; </li>319                            <li style="margin-top: 12px;">320                                train neural networks on multiple servers with varying compute, bandwidth and reliability; </li>321                            <li style="margin-top: 12px;">322                                 <i>[to be announced]</i> join a worldwide open deep learning experiment. </li>323                        </ul>324                        <br>325                        326                        Conversely, here's what it <b>isn't</b> for:327                        <ul style="text-align: middle; list-style-position: inside; margin-top: 16px; margin-left: -32px;">328                            <li style="margin-top: 12px;">329                                splitting your model between 2-3 servers that you fully control: use <a href=https://pytorch.org/docs/stable/rpc.html target="_blank"rel="noopener noreferrer">torch.distributed.rpc</a>;</li>330                            <li style="margin-top: 12px;">331                                distributed training for a reliable, uniform and highly connected cluster: use <a href=https://github.com/microsoft/DeepSpeed target="_blank"rel="noopener noreferrer">DeepSpeed</a>; </li>332                            <li style="margin-top: 12px;">333                                training <span class="tooltip">small <span class="tooltiptext">More specifically, models that fit into a single worker's memory.</span></span> models with dynamically allocated of in-house workers: use <a href=https://pytorch.org/elastic/0.2.0/index.html>torch.elastic</a>.</li>334 335                        </ul>336                        337                        338                        <p style="margin-top: 16px; text-align:left">339                            Hivemind v0.8 is in the early alpha stage: the core functionality to train340                            decentralized models is there, but the inferface is still in active development.341                            If you want to try hivemind for yourself or contribute to its development,342                            take a look at the <a href=https://learning-at-home.readthedocs.io/en/latest/user/quickstart.html><u>quickstart tutorial</u></a>.343                            Feel free to contact us <a href=https://github.com/learning-at-home/hivemind/issues target="_blank" rel="noopener noreferrer">on github</a> with any questions, feedback and issues.344                        </p>345                    </span>346                </div>347                348 349                <div style="margin: 0 auto; margin-top: 0px;">350                        <a class="github-button" href="https://github.com/learning-at-home/hivemind" data-size="large" data-show-count="false" aria-label="Star learning-at-home/hivemind on GitHub">Code</a>351                        <div style="overflow: hidden; white-space: nowrap; margin: 0 auto; display: inline-block;">352                            <button onclick="window.open('https://arxiv.org/abs/2002.04013');" 353                                    class="arxiv_button">Paper</button>354                        </div>355                        <a href="https://twitter.com/intent/tweet?hashtags=joinhivemind,learningathome&text=Join%20the%20deep%20learning%20hivemind!%0Alearning-at-home.github.io"356                           class="twitter-hashtag-button" data-show-count="true" data-size="large">Tweet</a>357                        <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>358 359                        <script async defer src="https://buttons.github.io/buttons.js"></script>360                </div>361                <hr style="margin-bottom: 64px; width:0%; border: 0 solid white">362            </div>363        </div>364    </div>365 366            367    <script>368// draw background; Note: this background is based on https://codepen.io/pawelqcm/pen/oxPYox by Pawel369// Note 2: Pawel, you're awesome.370(function() {371  var content_element = document.getElementById("overlay");372  var canvas = document.querySelector('canvas');373  var title_elem = document.getElementsByClassName("faded title")[0];374  var title_text = document.getElementById("title_text");375  if (screen.width < 637)376      title_text.innerHTML = "<br>hivemind<br>"377    378  ctx = canvas.getContext('2d');379  if (!ctx)380      console.warn("Your browser does not support canvas, content may be broken :'(");381 382  var SENSITIVITY, SIBLINGS_LIMIT, DENSITY, TOTAL_NODES, ANCHOR_LENGTH, CURSOR_HEIGHT, CURSOR_WIDTH;383  css_opts = getComputedStyle(document.documentElement);384  SENSITIVITY = css_opts.getPropertyValue('--background-sensitivity') || 120;385  SIBLINGS_LIMIT = css_opts.getPropertyValue('--background-siblings') || 7;386  NODE_DENSITY = css_opts.getPropertyValue('--background-node-density') || 6;387  CURSOR_WIDTH = css_opts.getPropertyValue('--background-cursor-width') || 250;388  CURSOR_HEIGHT = css_opts.getPropertyValue('--background-cursor-height') || 250;389  CURSOR_VERTICAL_SHRINK = css_opts.getPropertyValue('--background-cursor-vertical-shrink') || 0.1;390  SPEED_COEF = css_opts.getPropertyValue('--background-speed') || 1;391  ENERGY_DECAY = css_opts.getPropertyValue('--energy-decay') || 2;392  SHOW_IF_WIDER_THAN = css_opts.getPropertyValue('--background-show-if-wider-than') || 500;393  MOVE_ON_CURSOR = css_opts.getPropertyValue('--background-move-on-cursor').includes("true") || false;394    395  var nodes = [];396  choice = (choices => choices[Math.floor(Math.random() * choices.length)])397  sample_color = () => choice([[40, 40, 40], [133, 133, 133]])398 399  ANCHOR_LENGTH = 20;400 401  var cursor = {x: 0, y: 0};402 403  function centralize_cursor() {404      var rect = document.getElementById("bug-logo").getBoundingClientRect()405      var window_left = window.pageXOffset || document.documentElement.scrollLeft;406      var window_top = window.pageYOffset || document.documentElement.scrollTop;407      cursor.x = window_left + rect.left + rect.width / 2;408      cursor.y = window_top + rect.top + rect.height / 2;409  }410    411  function Node(x, y) {412    this.anchorX = x;413    this.anchorY = y;414    this.x = Math.random() * (x - (x - ANCHOR_LENGTH)) + (x - ANCHOR_LENGTH);415    this.y = Math.random() * (y - (y - ANCHOR_LENGTH)) + (y - ANCHOR_LENGTH);416    this.vx = (Math.random() * 2 - 1) * SPEED_COEF;417    this.vy = (Math.random() * 2 - 1) * SPEED_COEF;418    this.energy = Math.random() * 100;419    this.radius = Math.random();420    this.siblings = [];421    [this.r, this.g, this.b] = sample_color()422    this.brightness = 0;423  }424 425  Node.prototype.drawNode = function() {426    var color = `rgba(${this.r}, ${this.g}, ${this.b}, ${this.brightness})`;427    ctx.beginPath();428    ctx.arc(this.x, this.y, 2 * this.radius + 2 * this.siblings.length / SIBLINGS_LIMIT, 0, 2 * Math.PI);429    ctx.fillStyle = color;430    ctx.fill();431  };432 433  Node.prototype.drawConnections = function() {434    for (var i = 0; i < this.siblings.length; i++) {435      var color = `rgba(133, 133, 133, ${this.brightness})`;436      ctx.beginPath();437      ctx.moveTo(this.x, this.y);438      ctx.lineTo(this.siblings[i].x, this.siblings[i].y);439      ctx.lineWidth = 1 - calcDistance(this, this.siblings[i]) / SENSITIVITY;440      ctx.strokeStyle = color;441      ctx.stroke();442    }443  };444 445 446  Node.prototype.moveNode = function() {447    this.energy -= ENERGY_DECAY;448    if (this.energy < 1) {449      this.energy = Math.random() * 100;450      if (this.x - this.anchorX < -ANCHOR_LENGTH) {451        this.vx = Math.random() * SPEED_COEF;452      } else if (this.x - this.anchorX > ANCHOR_LENGTH) {453        this.vx = Math.random() * -SPEED_COEF;454      } else {455        this.vx = Math.random() * SPEED_COEF * 2 - SPEED_COEF;456      }457      if (this.y - this.anchorY < -ANCHOR_LENGTH) {458        this.vy = Math.random() * SPEED_COEF;459      } else if (this.y - this.anchorY > ANCHOR_LENGTH) {460        this.vy = Math.random() * -SPEED_COEF;461      } else {462        this.vy = Math.random() * SPEED_COEF * 2 - SPEED_COEF;463      }464    }465    relative_speed_rate = Math.min(canvas.height / 100, 10.0)466    this.x += this.vx * this.energy * relative_speed_rate;467    this.y += this.vy * this.energy * relative_speed_rate;468  };469 470  function initNodes() {471    centralize_cursor();472    ctx.clearRect(0, 0, canvas.width, canvas.height);473    if (canvas.width >= SHOW_IF_WIDER_THAN)474        total_nodes = Math.round(NODE_DENSITY * (canvas.width / 100 * canvas.height / 100));475    else476        total_nodes = 0;477    nodes = [];478    for (var i = 0; i < total_nodes; i++)479        nodes.push(new Node(50 + Math.random() * (canvas.width - 100), 480                            5 + Math.random() * (canvas.height - 10)));481  }482 483  function calcDistance(node1, node2) {484    return Math.sqrt(Math.pow(node1.x - node2.x, 2) + (Math.pow(node1.y - node2.y, 2)));485  }486 487  function findSiblings() {488    var node1, node2, distance;489    for (var i = 0; i < nodes.length; i++) {490      node1 = nodes[i];491      node1.siblings = [];492      for (var j = 0; j < nodes.length; j++) {493        node2 = nodes[j];494        if (node1 !== node2) {495          distance = calcDistance(node1, node2);496          if (distance < SENSITIVITY) {497            if (node1.siblings.length < SIBLINGS_LIMIT) {498              node1.siblings.push(node2);499            } else {500              var node_sibling_distance = 0;501              var max_distance = 0;502              var s;503              for (var k = 0; k < SIBLINGS_LIMIT; k++) {504                node_sibling_distance = calcDistance(node1, node1.siblings[k]);505                if (node_sibling_distance > max_distance) {506                  max_distance = node_sibling_distance;507                  s = k;508                }509              }510              if (distance < max_distance) {511                node1.siblings.splice(s, 1);512                node1.siblings.push(node2);513              }514            }515          }516        }517      }518    }519  }520 521  function redrawScene() {522    resizeWindow();523    ctx.clearRect(0, 0, canvas.width, canvas.height);524    findSiblings();525    var i, node, distance;526    for (i = 0; i < nodes.length; i++) {527      node = nodes[i];528      scaled_distance = calcDistance({x: cursor.x / CURSOR_WIDTH, y: cursor.y / CURSOR_HEIGHT},529                                     {x: node.x / CURSOR_WIDTH, y: node.y / CURSOR_HEIGHT});530      531      node.brightness = Math.max(1 - scaled_distance, 0);532    }533    for (i = 0; i < nodes.length; i++) {534      node = nodes[i];535      if (node.brightness) {536        node.drawConnections();537        node.drawNode();538      }539      node.moveNode();540    }541    requestAnimationFrame(redrawScene);542  }543 544  function initHandlers() {545    document.addEventListener('resize', resizeWindow);546    document.addEventListener('orientationchange', resizeWindow);547    if (MOVE_ON_CURSOR) {548        document.addEventListener('mousemove', moveHandler);549        document.addEventListener('touchmove', moveHandler);550    }551  }552 553  function resizeWindow(evt) {554    var new_width, new_height;555    new_width = Math.round(Math.max(title_elem.getBoundingClientRect().right, window.innerWidth))556 557    if (!MOVE_ON_CURSOR)558        new_height = Math.round(title_elem.getBoundingClientRect().top - canvas.getBoundingClientRect().top);559    else560        new_height = Math.round(Math.max(561            content_element.offsetHeight, content_element.scrollHeight,562            content_element.clientHeight, window.innerHeight));563    564    if (canvas.width != new_width || canvas.height != new_height) {565        canvas.width = new_width;566        canvas.height = new_height;567        initNodes();568    }569    if (!MOVE_ON_CURSOR)570        centralize_cursor();571  }572 573  function moveHandler(evt) {574    if (evt.type == "mousemove") {575        cursor.x = window.pageXOffset + evt.clientX;576        cursor.y = window.pageYOffset + evt.clientY;577    }578    else { // touch event579        cursor.x = window.pageXOffset + evt.changedTouches[0].clientX;580        cursor.y = window.pageYOffset + evt.changedTouches[0].clientY;581    }582  }583 584  initHandlers();585  initNodes();586  redrawScene();587 588})();589    </script>590</body>591</html>592