Files
CoderSherlock.github.io/_site/posts/eddl-how-do-we-train-on-limited-edge-devices.html
T
2022-05-04 19:45:56 -04:00

1170 lines
50 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html lang="en">
<head><meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>EDDL: How do we train neural networks on limited edge devices - PART 1 - Stop Talking, Start Doing</title>
<meta name="description" content="This post introduces our previous milestone in project “Edge trainer”, as the paper “EDDL: A Distributed Deep Learning System for Resource-limited Edge Compu...">
<link rel="canonical" href="https://codersherlock.github.io/posts/eddl-how-do-we-train-on-limited-edge-devices"><link rel="alternate" type="application/rss+xml" title="Stop Talking, Start Doing" href="/feed.xml"><link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png">
<link rel="manifest" href="/assets/site.webmanifest">
<link rel="mask-icon" href="/assets/safari-pinned-tab.svg" color="#5bbad5">
<link rel="shortcut icon" href="/assets/favicon.ico">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-config" content="/assets/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/5.15.1/css/all.css" ><!-- start custom head snippets -->
<!-- end custom head snippets -->
<script>(function() {
window.isArray = function(val) {
return Object.prototype.toString.call(val) === '[object Array]';
};
window.isString = function(val) {
return typeof val === 'string';
};
window.hasEvent = function(event) {
return 'on'.concat(event) in window.document;
};
window.isOverallScroller = function(node) {
return node === document.documentElement || node === document.body || node === window;
};
window.isFormElement = function(node) {
var tagName = node.tagName;
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
};
window.pageLoad = (function () {
var loaded = false, cbs = [];
window.addEventListener('load', function () {
var i;
loaded = true;
if (cbs.length > 0) {
for (i = 0; i < cbs.length; i++) {
cbs[i]();
}
}
});
return {
then: function(cb) {
cb && (loaded ? cb() : (cbs.push(cb)));
}
};
})();
})();
(function() {
window.throttle = function(func, wait) {
var args, result, thisArg, timeoutId, lastCalled = 0;
function trailingCall() {
lastCalled = new Date;
timeoutId = null;
result = func.apply(thisArg, args);
}
return function() {
var now = new Date,
remaining = wait - (now - lastCalled);
args = arguments;
thisArg = this;
if (remaining <= 0) {
clearTimeout(timeoutId);
timeoutId = null;
lastCalled = now;
result = func.apply(thisArg, args);
} else if (!timeoutId) {
timeoutId = setTimeout(trailingCall, remaining);
}
return result;
};
};
})();
(function() {
var Set = (function() {
var add = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (data[i] === item) {
return;
}
}
this.size ++;
data.push(item);
return data;
};
var Set = function(data) {
this.size = 0;
this._data = [];
var i;
if (data.length > 0) {
for (i = 0; i < data.length; i++) {
add.call(this, data[i]);
}
}
};
Set.prototype.add = add;
Set.prototype.get = function(index) { return this._data[index]; };
Set.prototype.has = function(item) {
var i, data = this._data;
for (i = 0; i < data.length; i++) {
if (this.get(i) === item) {
return true;
}
}
return false;
};
Set.prototype.is = function(map) {
if (map._data.length !== this._data.length) { return false; }
var i, j, flag, tData = this._data, mData = map._data;
for (i = 0; i < tData.length; i++) {
for (flag = false, j = 0; j < mData.length; j++) {
if (tData[i] === mData[j]) {
flag = true;
break;
}
}
if (!flag) { return false; }
}
return true;
};
Set.prototype.values = function() {
return this._data;
};
return Set;
})();
window.Lazyload = (function(doc) {
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
var createNode = function(name, attrs) {
var node = doc.createElement(name), attr;
for (attr in attrs) {
if (attrs.hasOwnProperty(attr)) {
node.setAttribute(attr, attrs[attr]);
}
}
return node;
};
var end = function(type, url) {
var s, q, qi, cbs, i, j, cur, val, flag;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
s[url] = true;
for (i = 0; i < q.length; i++) {
cur = q[i];
if (cur.urls.has(url)) {
qi = cur, val = qi.urls.values();
qi && (cbs = qi.callbacks);
for (flag = true, j = 0; j < val.length; j++) {
cur = val[j];
if (!s[cur]) {
flag = false;
}
}
if (flag && cbs && cbs.length > 0) {
for (j = 0; j < cbs.length; j++) {
cbs[j].call(context);
}
qi.load = true;
}
}
}
}
};
var load = function(type, urls, callback) {
var s, q, qi, node, i, cur,
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
if (type === 'js' || type ==='css') {
s = sources[type], q = queue[type];
for (i = 0; i < q.length; i++) {
cur = q[i];
if (_urls.is(cur.urls)) {
qi = cur;
break;
}
}
val = _urls.values();
if (qi) {
callback && (qi.load || qi.callbacks.push(callback));
callback && (qi.load && callback());
} else {
q.push({
urls: _urls,
callbacks: callback ? [callback] : [],
load: false
});
for (i = 0; i < val.length; i++) {
node = null, url = val[i];
if (s[url] === undefined) {
(type === 'js' ) && (node = createNode('script', { src: url }));
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
if (node) {
node.onload = (function(type, url) {
return function() {
end(type, url);
};
})(type, url);
(doc.head || doc.body).appendChild(node);
s[url] = false;
}
}
}
}
}
};
return {
js: function(url, callback) {
load('js', url, callback);
},
css: function(url, callback) {
load('css', url, callback);
}
};
})(this.document);
})();
</script><script>
(function() {
var TEXT_VARIABLES = {
version: '2.2.6',
sources: {
font_awesome: 'https://cdn.bootcdn.net/ajax/libs/font-awesome/5.15.1/css/all.css',
jquery: 'https://cdn.bootcss.com/jquery/3.1.1/jquery.min.js',
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
gitalk: {
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
},
valine: 'https://unpkg.com/valine/dist/Valine.min.js',
mathjax: 'https://cdn.bootcss.com/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_CHTML',
mermaid: 'https://cdn.bootcss.com/mermaid/8.0.0-rc.8/mermaid.min.js'
},
site: {
toc: {
selectors: 'h1,h2,h3'
}
},
paths: {
search_js: '/assets/search.js'
}
};
window.TEXT_VARIABLES = TEXT_VARIABLES;
})();
</script>
</head>
<body>
<div class="root" data-is-touch="false">
<div class="layout--page js-page-root"><div class="page__main js-page-main page__viewport has-aside cell cell--auto">
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
<div class="header__title">
<div class="header__brand"><?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="231.000000pt" height="218.000000pt" viewBox="0 0 231.000000 218.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata>
<g transform="translate(0.000000,218.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M1754 2168 c-3 -4 -2 -8 3 -8 4 0 3 -4 -4 -8 -6 -4 -13 -23 -16 -42
-4 -19 -14 -41 -24 -49 -17 -12 -16 -13 6 -8 l25 6 -27 -25 c-31 -29 -33 -34
-11 -34 8 0 12 5 9 10 -3 6 -2 10 4 10 5 0 13 -5 16 -10 4 -6 12 -7 18 -4 8 5
8 3 0 -7 -7 -7 -13 -21 -13 -32 0 -10 -4 -16 -9 -13 -14 9 -7 -18 11 -45 l16
-24 16 39 c9 21 16 44 16 51 0 6 3 15 8 19 4 4 7 11 8 14 0 4 4 23 9 42 9 36
11 46 13 68 1 7 6 11 11 8 4 -3 6 5 4 18 -4 17 0 26 14 29 10 3 -8 5 -40 4
-32 0 -60 -4 -63 -9z"/>
<path d="M1936 2163 c-4 -9 -2 -20 5 -23 14 -9 14 -21 -1 -30 -8 -5 -2 -10 14
-14 15 -4 24 -11 21 -17 -4 -5 -15 -7 -26 -4 -13 5 -19 2 -19 -10 0 -9 7 -15
17 -13 14 3 17 -6 18 -52 1 -30 3 -60 7 -65 3 -6 4 -23 2 -40 -1 -16 -5 -62
-8 -102 -2 -39 -7 -80 -10 -90 -4 -12 3 -28 19 -45 14 -15 21 -30 15 -33 -6
-4 -4 -17 5 -36 9 -16 13 -34 10 -39 -3 -6 1 -10 9 -10 22 0 20 -30 -1 -31
-14 0 -15 -2 -3 -6 22 -9 42 -32 36 -42 -3 -5 -17 -11 -31 -13 -14 -3 -22 -1
-18 5 7 12 -16 27 -42 27 -19 -1 -19 -1 -2 -14 16 -12 16 -15 3 -29 -14 -13
-14 -16 0 -21 13 -5 14 -9 4 -21 -8 -10 -9 -15 -2 -15 6 0 9 -6 6 -13 -2 -7 2
-26 10 -42 8 -16 13 -32 10 -37 -3 -4 0 -8 5 -8 6 0 11 -7 11 -15 0 -8 5 -15
12 -15 6 0 3 -10 -8 -21 -19 -22 -19 -22 5 -14 16 5 21 4 17 -4 -5 -7 -1 -8
10 -4 12 5 15 3 9 -6 -6 -10 -2 -11 16 -7 19 6 21 5 8 -3 -20 -13 -66 -9 -98
8 -15 9 -21 9 -16 2 3 -6 -4 -20 -17 -31 -16 -14 -18 -18 -5 -14 12 4 17 1 17
-11 0 -14 -6 -16 -30 -11 -38 7 -39 -1 -2 -15 24 -9 25 -11 9 -20 -9 -6 -15
-14 -12 -20 4 -5 -2 -9 -12 -9 -10 0 -25 -5 -33 -11 -13 -10 -13 -10 1 -6 9 3
16 -1 16 -9 0 -12 -3 -12 -21 0 -17 10 -21 25 -22 65 -1 29 -7 58 -14 64 -10
9 -11 9 -5 -3 6 -10 1 -8 -13 4 -12 10 -19 22 -17 26 3 4 -2 11 -11 14 -8 3
-12 10 -9 16 3 6 -1 13 -10 16 -10 4 -15 14 -12 25 3 10 -2 19 -12 22 -26 6
-39 -3 -34 -24 6 -23 -13 -49 -37 -49 -10 0 -27 11 -38 25 -24 30 -32 31 -32
4 0 -16 -4 -19 -21 -14 -15 5 -19 4 -14 -5 5 -8 0 -7 -14 2 -14 9 -20 22 -19
40 1 16 6 28 11 28 5 0 3 7 -4 16 -8 9 -12 27 -11 40 7 52 -18 131 -54 168
-40 42 -76 50 -182 44 -86 -5 -133 -24 -174 -72 -23 -26 -27 -40 -28 -94 0
-66 17 -113 47 -132 17 -10 17 -10 -1 -8 -10 2 -21 -3 -24 -11 -3 -10 0 -12
13 -7 15 5 16 4 5 -9 -10 -12 -10 -15 3 -15 8 0 17 9 20 21 3 12 10 18 16 14
8 -4 6 -11 -4 -21 -8 -9 -13 -19 -10 -24 3 -4 -5 -6 -17 -4 -21 4 -21 4 -3 -5
15 -7 24 -4 37 13 21 25 22 20 7 -22 -6 -18 -14 -30 -19 -27 -4 2 -15 -4 -24
-14 -17 -18 -16 -19 18 -18 20 1 36 4 36 8 0 4 7 9 15 13 13 5 13 2 -1 -19
-13 -20 -20 -23 -34 -15 -15 8 -22 5 -33 -10 -12 -17 -16 -18 -20 -6 -4 9 -14
12 -26 9 -13 -3 -21 -1 -21 8 0 7 -3 10 -6 7 -3 -4 -1 -15 4 -25 6 -11 7 -25
3 -32 -6 -8 -10 -2 -14 18 -8 36 -22 40 -38 9 -10 -18 -9 -20 5 -15 9 4 16 1
16 -4 0 -7 -11 -9 -25 -7 -13 3 -26 0 -29 -6 -3 -7 -5 -6 -5 2 -1 7 -7 10 -13
7 -7 -4 -4 2 8 12 19 16 39 53 29 53 -2 0 -17 -14 -33 -31 l-30 -32 5 27 c4
20 1 26 -11 26 -11 0 -15 -5 -10 -12 4 -7 -2 -5 -13 4 -11 10 -27 18 -36 18
-9 0 -21 8 -27 18 -9 14 -10 11 -5 -15 5 -24 2 -34 -12 -43 -16 -10 -15 -10 5
-4 23 6 24 6 5 -14 -18 -19 -18 -19 -52 0 -33 19 -34 19 -28 -1 5 -19 3 -19
-18 -5 -26 17 -39 51 -21 57 6 2 4 3 -4 2 -8 0 -14 -6 -13 -12 1 -6 -5 -17
-14 -25 -10 -8 -14 -8 -10 -1 4 6 2 15 -4 19 -7 4 -9 3 -5 -4 3 -6 -2 -15 -11
-21 -14 -8 -14 -10 -3 -11 9 0 5 -6 -10 -17 -14 -10 -28 -17 -32 -15 -5 1 -8
-6 -8 -16 0 -10 -5 -23 -11 -29 -7 -7 -7 -13 0 -17 7 -4 6 -16 -1 -36 -7 -23
-7 -34 2 -45 11 -14 7 -19 -12 -16 -5 0 -8 -3 -8 -9 0 -13 6 -13 31 1 19 10
20 9 9 -12 -11 -19 -10 -21 4 -16 10 4 14 3 11 -2 -3 -5 -1 -12 5 -16 13 -8
13 -25 -1 -25 -5 0 -7 6 -3 13 4 7 3 9 -2 4 -5 -5 -9 -14 -9 -20 -1 -7 -7 -11
-14 -9 -7 1 -19 -5 -27 -15 -13 -17 -13 -17 -14 4 0 12 5 25 10 28 6 4 7 11 4
17 -4 7 -2 8 4 4 7 -4 12 -1 12 9 0 11 -5 15 -16 11 -8 -3 -12 -2 -9 4 3 6 1
10 -6 10 -7 0 -5 8 6 20 10 11 13 20 7 20 -6 0 -14 -5 -17 -10 -5 -8 -11 -7
-21 1 -7 6 -11 15 -8 20 3 5 -3 6 -12 2 -10 -4 -13 -8 -7 -10 6 -2 9 -16 7
-29 -3 -15 -1 -23 5 -20 5 4 12 3 14 -1 3 -5 -14 -9 -36 -10 -31 -2 -38 0 -27
7 13 9 12 13 -8 30 -13 10 -29 17 -37 14 -17 -7 -28 -34 -14 -34 6 0 9 -9 6
-20 -3 -11 -1 -20 5 -20 5 0 7 -4 3 -9 -3 -5 -1 -12 5 -16 6 -4 7 -11 4 -17
-4 -6 1 -17 11 -25 11 -7 13 -13 6 -13 -7 0 -9 -4 -6 -10 8 -13 -1 -13 -26 0
-13 7 -19 7 -19 0 0 -5 7 -10 16 -10 8 0 13 -4 9 -9 -3 -5 7 -11 22 -13 20 -2
27 -8 25 -20 -2 -10 3 -18 9 -18 7 0 3 -9 -9 -20 -22 -21 -67 -27 -77 -10 -6
10 13 14 45 11 13 -2 13 -1 0 8 -12 9 -13 11 -1 11 8 0 11 3 8 7 -4 3 -22 -2
-41 -12 l-34 -18 26 -24 c14 -12 19 -23 12 -23 -7 0 -10 -7 -6 -16 3 -9 2 -12
-4 -9 -6 4 -9 14 -8 23 2 9 -5 18 -15 20 -16 3 -17 1 -8 -16 8 -15 8 -22 -2
-25 -7 -3 -5 -6 6 -6 9 -1 16 -6 15 -13 -2 -7 8 -12 24 -12 23 1 25 -1 18 -21
-10 -26 -2 -104 13 -122 6 -9 6 -13 -2 -13 -7 0 -9 -4 -6 -10 3 -5 0 -10 -7
-10 -11 0 -11 -2 0 -9 10 -6 11 -13 1 -34 -9 -21 -9 -33 -1 -53 8 -16 9 -31 3
-43 -7 -13 -4 -24 15 -46 13 -15 24 -39 24 -53 0 -17 4 -22 14 -19 10 4 17 -4
21 -24 4 -17 13 -33 20 -35 7 -3 16 -16 19 -30 l6 -24 600 0 c368 0 600 4 600
9 0 6 -4 13 -10 16 -5 3 -10 12 -9 18 0 9 2 9 5 1 7 -16 44 -5 44 12 0 17 21
18 44 1 22 -16 12 -44 -17 -50 -12 -2 28 -5 90 -6 98 -1 112 1 117 17 3 9 20
23 37 31 20 9 28 18 24 29 -4 12 -3 13 9 3 17 -14 36 -7 36 14 0 8 -6 12 -14
9 -10 -4 -13 0 -9 14 5 20 -23 84 -59 134 -12 18 -29 29 -46 29 -24 2 -24 2
-4 6 12 2 22 7 22 10 0 2 -17 29 -37 58 -35 50 -114 115 -141 115 -6 0 -12 4
-12 8 0 5 -16 27 -36 50 -19 23 -31 42 -25 42 6 0 16 -9 23 -20 16 -24 30 -26
21 -3 -5 13 0 12 28 -7 43 -30 80 -70 115 -125 15 -24 31 -42 36 -39 5 3 7 2
6 -3 -5 -15 39 -63 57 -63 13 0 15 -3 7 -13 -9 -10 -1 -34 29 -95 23 -45 46
-82 51 -82 5 0 6 -5 3 -10 -3 -6 0 -13 8 -16 9 -3 13 -13 10 -25 -3 -10 -1
-19 5 -19 6 0 12 -10 14 -22 3 -21 8 -23 63 -23 l60 0 3 62 c3 59 2 63 -19 63
-22 0 -22 -1 -4 -13 11 -9 14 -16 7 -21 -6 -3 -18 2 -28 11 -12 13 -19 14 -22
5 -9 -28 -32 -12 -32 23 0 24 5 35 15 35 8 0 15 -5 15 -11 0 -5 5 -7 11 -3 8
5 8 9 -1 14 -8 5 -9 9 -1 11 12 5 3 49 -10 49 -5 0 -8 -3 -7 -7 2 -5 -1 -8 -7
-8 -5 0 -9 11 -7 25 l2 25 -17 -27 c-21 -33 -34 -35 -58 -8 -10 11 -26 22 -36
25 -23 8 -25 25 -4 25 8 0 15 -5 15 -11 0 -8 4 -8 13 -1 7 6 25 9 40 6 22 -3
27 -1 27 16 0 11 4 20 10 20 5 0 7 -6 4 -14 -7 -17 25 -36 52 -32 10 2 13 1 7
-1 -9 -3 -10 -10 -3 -23 6 -11 9 -23 8 -27 -4 -14 13 -53 23 -53 5 0 7 50 5
123 -6 156 -6 68 0 1050 l5 848 -28 -3 c-20 -2 -29 -9 -31 -24 -2 -16 -8 -20
-21 -17 -13 3 -17 11 -14 24 4 14 0 19 -16 19 -11 0 -21 -3 -20 -7 1 -5 -2
-18 -6 -31 -6 -19 -12 -22 -35 -17 -16 3 -31 2 -34 -3 -7 -11 -106 -3 -123 10
-8 6 -13 3 -16 -9 -3 -10 -5 -1 -6 20 -1 38 -14 49 -25 20z m-1276 -1513 c-12
-7 -12 -10 -1 -10 8 0 11 -6 7 -17 -3 -10 3 -6 15 10 23 30 41 34 59 12 11
-13 10 -14 -5 -9 -13 5 -16 4 -11 -4 4 -7 19 -12 34 -13 l27 -1 -29 -8 c-16
-5 -32 -7 -36 -5 -3 2 -6 -8 -6 -21 0 -21 4 -24 23 -19 21 5 22 4 11 -15 -7
-11 -19 -20 -26 -20 -8 0 -10 5 -6 12 5 8 2 9 -12 3 -39 -16 -67 -19 -59 -5 5
9 4 11 -4 6 -6 -4 -9 -12 -6 -17 3 -5 -1 -6 -10 -3 -9 4 -14 13 -11 20 4 10
-4 9 -29 -4 -18 -9 -32 -21 -32 -26 1 -5 -4 -11 -12 -14 -10 -3 -12 0 -8 11 3
9 1 17 -6 20 -7 2 -4 16 11 40 l22 38 -23 -13 c-12 -6 -32 -12 -45 -13 -20 -1
-21 1 -7 11 12 9 13 13 3 17 -10 3 -10 7 -1 17 10 11 15 11 28 0 11 -9 15 -9
15 -1 0 7 4 10 10 6 5 -3 18 0 29 7 15 9 25 9 46 0 14 -7 24 -8 21 -3 -6 9 8
19 29 20 6 0 3 -4 -5 -9z m914 -29 c34 -29 46 -76 46 -179 0 -87 -3 -105 -26
-148 -50 -95 -82 -115 -187 -115 -60 0 -82 4 -122 26 -44 23 -104 79 -105 97
0 10 -46 110 -82 181 -31 61 -31 78 3 121 27 34 75 34 164 2 61 -22 70 -23
101 -10 18 8 42 14 53 14 10 0 38 9 61 19 45 20 62 19 94 -8z"/>
<path d="M164 1993 c36 -55 77 -136 71 -141 -3 -3 -57 -6 -120 -6 l-115 -1 4
-755 c2 -415 4 -769 5 -786 2 -46 27 -52 35 -9 7 38 29 55 57 48 11 -3 19 0
19 6 0 6 -7 11 -15 11 -20 0 -19 27 2 38 10 6 14 16 10 26 -4 9 -3 16 2 16 7
0 17 38 25 92 1 3 4 10 8 14 4 4 3 13 -3 21 -9 10 -8 13 5 13 9 0 17 9 17 20
2 28 3 33 12 48 5 7 6 21 2 31 -4 13 2 26 15 39 12 11 24 38 27 61 3 23 10 41
16 41 7 0 7 4 -1 12 -14 14 -16 32 -3 23 6 -3 15 4 21 15 8 15 8 20 -2 20 -7
1 -4 6 7 13 11 7 21 23 22 37 1 14 4 37 7 52 6 25 3 28 -29 34 l-36 6 23 16
c13 9 26 20 30 26 7 11 -9 26 -27 26 -5 0 -3 -5 5 -10 9 -6 10 -10 3 -10 -24
0 -24 20 1 29 23 9 29 31 13 47 -4 4 1 12 10 19 11 8 13 14 5 19 -7 4 -12 2
-12 -3 0 -6 -10 -11 -22 -11 -21 0 -21 0 -2 16 13 11 14 14 3 11 -9 -3 -16 1
-16 9 0 9 6 13 14 10 8 -3 11 -1 8 4 -3 5 -2 26 4 45 6 21 6 37 0 41 -5 3 -9
14 -9 25 0 10 -6 19 -12 19 -9 0 -9 3 1 9 8 5 14 22 15 37 1 16 5 35 9 42 5 6
5 12 2 12 -4 0 1 7 10 16 9 10 15 24 12 33 -2 9 2 22 10 29 7 7 13 23 13 35 0
28 15 51 28 43 5 -3 13 2 16 11 6 15 -8 32 -26 33 -5 0 -8 7 -8 15 0 8 -6 15
-12 15 -8 0 -5 7 6 15 12 9 15 15 7 15 -9 0 -12 9 -9 24 3 17 1 23 -8 19 -25
-9 -36 8 -18 28 16 17 16 19 1 19 -10 0 -17 5 -17 10 0 6 5 10 11 10 6 0 9 6
6 13 -2 6 3 17 11 23 13 10 13 14 -1 35 -10 13 -17 18 -17 11 0 -18 -24 -15
-43 6 -59 64 -60 64 -46 74 11 8 10 9 -3 4 -11 -3 -18 0 -18 8 0 12 -20 26
-36 26 -2 0 7 -17 20 -37z"/>
<path d="M1443 1727 c-3 -6 -1 -7 5 -3 23 14 12 -12 -13 -30 -25 -19 -34 -58
-15 -69 6 -4 26 5 45 19 35 27 73 33 104 16 10 -5 42 -12 72 -15 29 -4 59 -11
66 -17 17 -14 17 3 0 27 -9 12 -16 14 -21 7 -7 -12 -64 15 -101 48 -22 20
-132 33 -142 17z"/>
<path d="M726 1647 c-31 -20 -50 -40 -76 -82 l-24 -40 27 26 c18 17 43 28 73
33 77 10 102 7 155 -19 27 -14 54 -23 59 -20 16 10 12 55 -5 55 -8 0 -15 5
-15 10 0 6 -11 10 -24 10 -16 0 -27 7 -31 20 -3 11 -11 20 -16 20 -6 0 -7 -5
-3 -12 5 -8 2 -9 -12 -3 -33 13 -88 15 -108 2z"/>
</g>
</svg>
<a title="My personal blog, with some boring research staff and some tricks I was fancy to. I'll try my best to make this blog fun and useful. Not just a place I complain about all happens in my Lab.
" href="/">Stop Talking, Start Doing</a></div><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></div><nav class="navigation">
<ul><li class="navigation__item"><a href="/archive.html">Archive</a></li><li class="navigation__item"><a href="/about.html">About</a></li><li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li></ul>
</nav></div>
</header>
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
<div class="col-aside d-print-none js-col-aside"><aside class="page__aside js-page-aside"><div class="toc-aside js-toc-root"></div>
</aside></div>
<div class="col-main cell cell--auto"><!-- start custom main top snippet -->
<!-- end custom main top snippet -->
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1>EDDL: How do we train neural networks on limited edge devices - PART 1</h1></header></div><meta itemprop="headline" content="EDDL: How do we train neural networks on limited edge devices - PART 1"><div class="article__info clearfix"><ul class="left-col menu"><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=Research">Research</a>
</li><li>
<a class="button button--secondary button--pill button--sm"
href="/archive.html?tag=Edge+computing">Edge computing</a>
</li></ul><ul class="right-col menu"><li><i class="fas fa-user"></i> <span>Pengzhan Hao</span></li><li><i class="far fa-calendar-alt"></i> <span>Oct 13, 2021</span>
</li></ul></div><meta itemprop="author" content="Pengzhan Hao"/><meta itemprop="datePublished" content="2021-10-13T16:53:20-04:00">
<meta itemprop="keywords" content="Research,Edge computing"><div class="js-article-content"><div class="layout--article"><!-- start custom article top snippet -->
<!-- end custom article top snippet -->
<div class="article__content" itemprop="articleBody"><p>This post introduces our previous milestone in project “Edge trainer”, as the paper “EDDL: A Distributed Deep Learning System for Resource-limited Edge Computing Environment.” was published.
As the first part of the introductions, I focus only on the motivation and summary of our works.
More details in design and implementation can be found in late posts.</p>
<p><img src="/static/2021-10/edgelearn-1.png" height="250" />
<!--more--></p>
<h2 id="why-do-we-need-training-on-edge">Why do we need training on edge?</h2>
<p>Cloud is not trustworthy anymore. More and more facts support that breach on the cloud happens frequently than before.
Nowadays, with more generated personal sensitive data has been uploaded to the cloud center, tech companies know better to someones than the user.</p>
<p>Researchers, no matter in the industry on academia, are working in a way that still learning from users data but also keeping raw sensitive data under users control.
Many publications have already shown the feasibility of only sharing the after-trained model instead of raw data.
One recent popular study on this is googles <a href="https://ai.googleblog.com/2017/04/federated-learning-collaborative.html">federated learning</a>.</p>
<p>During investigating this problem, we found that letting end-user train their data is safe, but sacrifice efficiency.
Since one end device has limited resources, training time and power consumption can be disappointing.
We believe there must have leverage between privacy and efficiency in some target scenarios.</p>
<p>Fortunately, we observed that users who belong to the same campus, plant, firm, and community always share similar interests.
Therefore, these co-located users have similar demands in using AI-involved routines.
Also, co-located users are easily targeted by the same type of threats, such as ransomware to financial practitioners.</p>
<p>Think about this, sending features of a new malware app to cloud services to train neural networks used by antivirus programs.
This process may take a long time and a small number of samples may not be recognized by the global neural networks model.
A customized local model trained and deployed on the edge can successfully counter the problem.
With edge training as a supplement to the cloud training can achieve better response time and let the whole system more flexible.</p>
<h2 id="why-training-on-edge-is-hard">Why training on edge is hard?</h2>
<p>Since all co-located users devices can be used for edge training, issues and challenges occur as deploying this distributed system.</p>
<p>The first challenge is <strong>struggling workers</strong>.
Training devices are heterogeneous, from limited IoT cameras to high-end media centers with powerful GPUs.
They are not designed to do machine learning.
So, a good edge-based distributed learning framework must be able to handle a variety of speeds in training tasks.</p>
<p>The second challenge is how to <strong>scale up</strong> clusters.
On a campus, thousands and more devices may contribute computing resources to the same training tasks.
However, these devices may be located far no matter in physical or in network topology.
The question of how can we well use them well, without struggling with endless transmission time remains a challenge.</p>
<p>The third issue is frequently <strong>joining and exiting</strong> of devices.
We cant rely on each device to faithfully work on training tasks rather than their original workload.
Smartly schedule work balance and handle join/exit issues also need under consideration.</p>
<h2 id="our-proposal">Our proposal</h2>
<ul>
<li>
<p>Dynamic training data distribution and runtime profiler</p>
<p>We design a dynamic training data distribution mechanism that helps both the first and the third challenges.
Preprocessing data can be transmitted without leakage of raw and sensitive information.
This can help struggling workers who can train small batches in order to upload parameters with a similar training time.
Also, for extremely slow devices, join and exit of devices cases, dynamic data distribution and profiler can help with keeping global training parameters from pollution and staleness.</p>
<p>To counter heterogeneity, more approaches were applied in our later research.
More details were introduced to the runtime profiler in the later works.</p>
</li>
<li>
<p>Asynchronous and synchronous aggregation enabled</p>
<p>In our findings, asynchronous and synchronous parameter update have their pros and cons.
Keeping sync all the time leads to struggling worker issues unsolvable.
However, asyncs harm to accuracy and convergence time also needs attention.
To carefully choose between these two update policies at the runtime is what we proposed to make use of their own advantages.</p>
</li>
<li>
<p>Leader role splitting</p>
<p>The idea is to let worker devices with higher bandwidth take leader-role during training.
Parameter updating does not require much computation but only needs a great of bandwidth.
Devices with sufficient bandwidth can also work as virtual leader devices.
This approach helps minimize physical devices we used and more leaders can further scale up workers limits.</p>
</li>
</ul>
</div><section class="article__sharing d-print-none"></section><div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2021-10-13T16:53:20-04:00"><!-- start custom article footer snippet -->
<!-- end custom article footer snippet -->
<div class="article__subscribe"><div class="subscribe"><i class="fas fa-rss"></i> <a type="application/rss+xml" href="/feed.xml">Subscribe</a></div>
</div><div class="article__license"></div></footer>
<div class="article__section-navigator clearfix"><div class="previous"><span>PREVIOUS</span><a href="/posts/generate-word-cloud-with-chinese-fenci">Generate Word Cloud Figures with Chinese-Tokenization and WordCloud python libraries</a></div><div class="next"><span>NEXT</span><a href="/posts/eddl-how-do-we-train-on-limited-edge-devices-part2">EDDL: How do we train neural networks on limited edge devices - PART 2</a></div></div></div>
</div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
$(function() {
var $this ,$scroll;
var $articleContent = $('.js-article-content');
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
$scroll = $(scroll);
$articleContent.find('.highlight').each(function() {
$this = $(this);
$this.attr('data-lang', $this.find('code').attr('data-lang'));
});
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
$this = $(this);
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
});
$articleContent.on('click', '.anchor', function() {
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
});
});
});
})();
</script>
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
<!-- end custom main bottom snippet -->
</div>
</div></div></div><div class="page__footer d-print-none">
<footer class="footer py-4 js-page-footer">
<div class="main"><div itemscope itemtype="http://schema.org/Person">
<meta itemprop="name" content="Pengzhan Hao"><meta itemprop="url" content="/"><div class="footer__author-links"><div class="author-links">
<ul class="menu menu--nowrap menu--inline"><li title="Send me an Email.">
<a class="button button--circle mail-button" itemprop="email" href="mailto:haopengzhan@gmail.com" target="_blank">
<i class="fas fa-envelope"></i>
</a><li title="Follow me on Linkedin.">
<a class="button button--circle linkedin-button" itemprop="sameAs" href="https://www.linkedin.com/in/pengzhanhao" target="_blank">
<div class="icon"><svg fill="#000000" width="24px" height="24px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M260.096 155.648c0 27.307008-9.899008 50.516992-29.696 69.632-19.796992 19.115008-45.396992 28.672-76.8 28.672-30.036992 0-54.612992-9.556992-73.728-28.672-19.115008-19.115008-28.672-42.324992-28.672-69.632 0-28.672 9.556992-52.224 28.672-70.656 19.115008-18.432 44.372992-27.648 75.776-27.648 31.403008 0 56.32 9.216 74.752 27.648 18.432 18.432 28.331008 41.984 29.696 70.656 0 0 0 0 0 0m-202.752 808.96c0 0 0-632.832 0-632.832 0 0 196.608 0 196.608 0 0 0 0 632.832 0 632.832 0 0-196.608 0-196.608 0 0 0 0 0 0 0m313.344-430.08c0-58.708992-1.364992-126.292992-4.096-202.752 0 0 169.984 0 169.984 0 0 0 10.24 88.064 10.24 88.064 0 0 4.096 0 4.096 0 40.96-68.267008 105.812992-102.4 194.56-102.4 68.267008 0 123.220992 22.868992 164.864 68.608 41.643008 45.739008 62.464 113.664 62.464 203.776 0 0 0 374.784 0 374.784 0 0-196.608 0-196.608 0 0 0 0-350.208 0-350.208 0-91.476992-33.451008-137.216-100.352-137.216-47.787008 0-81.236992 24.576-100.352 73.728-4.096 8.192-6.144 24.576-6.144 49.152 0 0 0 364.544 0 364.544 0 0-198.656 0-198.656 0 0 0 0-430.08 0-430.08 0 0 0 0 0 0" />
</svg>
</div>
</a>
</li><li title="Follow me on Github.">
<a class="button button--circle github-button" itemprop="sameAs" href="https://github.com/codersherlock" target="_blank">
<div class="icon"><svg fill="#000000" width="24px" height="24px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path class="svgpath" data-index="path_0" fill="#272636" d="M0 525.2c0 223.6 143.3 413.7 343 483.5 26.9 6.8 22.8-12.4 22.8-25.4l0-88.7c-155.3 18.2-161.5-84.6-172-101.7-21.1-36-70.8-45.2-56-62.3 35.4-18.2 71.4 4.6 113.1 66.3 30.2 44.7 89.1 37.2 119 29.7 6.5-26.9 20.5-50.9 39.7-69.6C248.8 728.2 181.7 630 181.7 513.2c0-56.6 18.7-108.7 55.3-150.7-23.3-69.3 2.2-128.5 5.6-137.3 66.5-6 135.5 47.6 140.9 51.8 37.8-10.2 80.9-15.6 129.1-15.6 48.5 0 91.8 5.6 129.8 15.9 12.9-9.8 77-55.8 138.8-50.2 3.3 8.8 28.2 66.7 6.3 135 37.1 42.1 56 94.6 56 151.4 0 117-67.5 215.3-228.8 243.7 26.9 26.6 43.6 63.4 43.6 104.2l0 128.8c0.9 10.3 0 20.5 17.2 20.5C878.1 942.4 1024 750.9 1024 525.3c0-282.9-229.3-512-512-512C229.1 13.2 0 242.3 0 525.2L0 525.2z" />
</svg>
</div>
</a>
</li></ul>
</div>
</div>
</div><div class="site-info mt-2">
<div>© Stop Talking, Start Doing 2021,
Powered by <a title="Jekyll is a simple, blog-aware, static site generator." href="http://jekyllrb.com/">Jekyll</a> & <a
title="TeXt is a super customizable Jekyll theme." href="https://github.com/kitian616/jekyll-TeXt-theme">TeXt Theme</a>.
</div>
</div>
</div>
</footer>
</div></div>
</div><script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $body = $('body'), $window = $(window);
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
var activeCount = 0;
function modal(options) {
var $root = this, visible, onChange, hideWhenWindowScroll = false;
var scrollTop;
function setOptions(options) {
var _options = options || {};
visible = _options.initialVisible === undefined ? false : show;
onChange = _options.onChange;
hideWhenWindowScroll = _options.hideWhenWindowScroll;
}
function init() {
setState(visible);
}
function setState(isShow) {
if (isShow === visible) {
return;
}
visible = isShow;
if (visible) {
activeCount++;
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
$root.addClass('modal--show');
$pageMain.scrollTop(scrollTop);
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
$window.on('keyup', handleKeyup);
} else {
activeCount > 0 && activeCount--;
$root.removeClass('modal--show');
$window.scrollTop(scrollTop);
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
$window.off('keyup', handleKeyup);
}
onChange && onChange(visible);
}
function show() {
setState(true);
}
function hide() {
setState(false);
}
function handleKeyup(e) {
// Char Code: 27 ESC
if (e.which === 27) {
hide();
}
}
setOptions(options);
init();
return {
show: show,
hide: hide,
$el: $root
};
}
$.fn.modal = modal;
});
})();
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
(function () {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
// search panel
var search = (window.search || (window.search = {}));
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
true : window.useDefaultSearchBox ;
var $searchModal = $('.js-page-search-modal');
var $searchToggle = $('.js-search-toggle');
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
var modalVisible = false;
search.searchModal = searchModal;
var $searchBox = null;
var $searchInput = null;
var $searchClear = null;
function getModalVisible() {
return modalVisible;
}
search.getModalVisible = getModalVisible;
function handleModalChange(visible) {
modalVisible = visible;
if (visible) {
search.onShow && search.onShow();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
} else {
search.onShow && search.onHide();
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
setTimeout(function() {
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
search.clear && search.clear();
window.pageAsideAffix && window.pageAsideAffix.refresh();
}, 400);
}
}
$searchToggle.on('click', function() {
modalVisible ? searchModal.hide() : searchModal.show();
});
// Char Code: 83 S, 191 /
$(window).on('keyup', function(e) {
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
modalVisible || searchModal.show();
}
});
if (useDefaultSearchBox) {
$searchBox = $('.js-search-box');
$searchInput = $searchBox.children('input');
$searchClear = $searchBox.children('.js-icon-clear');
search.getSearchInput = function() {
return $searchInput.get(0);
};
search.getVal = function() {
return $searchInput.val();
};
search.setVal = function(val) {
$searchInput.val(val);
};
$searchInput.on('focus', function() {
$(this).addClass('focus');
});
$searchInput.on('blur', function() {
$(this).removeClass('focus');
});
$searchInput.on('input', window.throttle(function() {
var val = $(this).val();
if (val === '' || typeof val !== 'string') {
search.clear && search.clear();
} else {
$searchBox.addClass('not-empty');
search.onInputNotEmpty && search.onInputNotEmpty(val);
}
}, 400));
$searchClear.on('click', function() {
$searchInput.val(''); $searchBox.removeClass('not-empty');
search.clear && search.clear();
});
}
});
})();
</script><div class="search search--dark">
<div class="main">
<div class="search__header">Search</div>
<div class="search-bar">
<div class="search-box js-search-box">
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
<input type="text" />
<div class="search-box__icon-clear js-icon-clear">
<a><i class="fas fa-times"></i></a>
</div>
</div>
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
Cancel</button>
</div>
<div class="search-result js-search-result"></div>
</div>
</div>
<script>var SOURCES = window.TEXT_VARIABLES.sources;
var PAHTS = window.TEXT_VARIABLES.paths;
window.Lazyload.js([SOURCES.jquery, PAHTS.search_js], function() {
var search = (window.search || (window.search = {}));
var searchData = window.TEXT_SEARCH_DATA || {};
function memorize(f) {
var cache = {};
return function () {
var key = Array.prototype.join.call(arguments, ',');
if (key in cache) return cache[key];
else return cache[key] = f.apply(this, arguments);
};
}
/// search
function searchByQuery(query) {
var i, j, key, keys, cur, _title, result = {};
keys = Object.keys(searchData);
for (i = 0; i < keys.length; i++) {
key = keys[i];
for (j = 0; j < searchData[key].length; j++) {
cur = searchData[key][j], _title = cur.title;
if ((result[key] === undefined || result[key] && result[key].length < 4 )
&& _title.toLowerCase().indexOf(query.toLowerCase()) >= 0) {
if (result[key] === undefined) {
result[key] = [];
}
result[key].push(cur);
}
}
}
return result;
}
var renderHeader = memorize(function(header) {
return $('<p class="search-result__header">' + header + '</p>');
});
var renderItem = function(index, title, url) {
return $('<li class="search-result__item" data-index="' + index + '"><a class="button" href="' + url + '">' + title + '</a></li>');
};
function render(data) {
if (!data) { return null; }
var $root = $('<ul></ul>'), i, j, key, keys, cur, itemIndex = 0;
keys = Object.keys(data);
for (i = 0; i < keys.length; i++) {
key = keys[i];
$root.append(renderHeader(key));
for (j = 0; j < data[key].length; j++) {
cur = data[key][j];
$root.append(renderItem(itemIndex++, cur.title, cur.url));
}
}
return $root;
}
// search box
var $result = $('.js-search-result'), $resultItems;
var lastActiveIndex, activeIndex;
function clear() {
$result.html(null);
$resultItems = $('.search-result__item'); activeIndex = 0;
}
function onInputNotEmpty(val) {
$result.html(render(searchByQuery(val)));
$resultItems = $('.search-result__item'); activeIndex = 0;
$resultItems.eq(0).addClass('active');
}
search.clear = clear;
search.onInputNotEmpty = onInputNotEmpty;
function updateResultItems() {
lastActiveIndex >= 0 && $resultItems.eq(lastActiveIndex).removeClass('active');
activeIndex >= 0 && $resultItems.eq(activeIndex).addClass('active');
}
function moveActiveIndex(direction) {
var itemsCount = $resultItems ? $resultItems.length : 0;
if (itemsCount > 1) {
lastActiveIndex = activeIndex;
if (direction === 'up') {
activeIndex = (activeIndex - 1 + itemsCount) % itemsCount;
} else if (direction === 'down') {
activeIndex = (activeIndex + 1 + itemsCount) % itemsCount;
}
updateResultItems();
}
}
// Char Code: 13 Enter, 37 ⬅, 38 ⬆, 39 ➡, 40 ⬇
$(window).on('keyup', function(e) {
var modalVisible = search.getModalVisible && search.getModalVisible();
if (modalVisible) {
if (e.which === 38) {
modalVisible && moveActiveIndex('up');
} else if (e.which === 40) {
modalVisible && moveActiveIndex('down');
} else if (e.which === 13) {
modalVisible && $resultItems && activeIndex >= 0 && $resultItems.eq(activeIndex).children('a')[0].click();
}
}
});
$result.on('mouseover', '.search-result__item > a', function() {
var itemIndex = $(this).parent().data('index');
itemIndex >= 0 && (lastActiveIndex = activeIndex, activeIndex = itemIndex, updateResultItems());
});
});
</script>
</div></div>
<script>(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function scrollToAnchor(anchor, duration, callback) {
var $root = this;
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
callback && callback();
});
}
$.fn.scrollToAnchor = scrollToAnchor;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function affix(options) {
var $root = this, $window = $(window), $scrollTarget, $scroll,
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
hasInit = false, curState;
function setOptions(options) {
var _options = options || {};
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroll && (scroll = _options.scroll);
_options.disabled !== undefined && (disabled = _options.disabled);
$scrollTarget = $(scrollTarget);
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
$scroll = $(scroll);
}
function preCalc() {
top();
rootHeight = $root.outerHeight();
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
rootLeft = $root.offset().left;
}
function calc(needPreCalc) {
needPreCalc && preCalc();
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
rootBottomTop = scrollBottom - rootTop;
}
function top() {
if (curState !== 'top') {
$root.removeClass('fixed').css({
left: 0,
top: 0
});
curState = 'top';
}
}
function fixed() {
if (curState !== 'fixed') {
$root.addClass('fixed').css({
left: rootLeft + 'px',
top: 0
});
curState = 'fixed';
}
}
function bottom() {
if (curState !== 'bottom') {
$root.removeClass('fixed').css({
left: 0,
top: rootBottomTop + 'px'
});
curState = 'bottom';
}
}
function setState() {
var scrollTop = $scrollTarget.scrollTop();
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
fixed();
} else if (scrollTop < rootTop) {
top();
} else {
bottom();
}
}
function init() {
if(!hasInit) {
var interval, timeout;
calc(true); setState();
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState();
});
$window.on('resize', function() {
disabled || (calc(true), setState());
});
hasInit = true;
}
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions,
refresh: function() {
calc(true, { animation: false }); setState();
}
};
}
$.fn.affix = affix;
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
function toc(options) {
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
function setOptions(options) {
var _options = options || {};
_options.selectors && (selectors = _options.selectors);
_options.container && (container = _options.container);
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
_options.scroller && (scroller = _options.scroller);
_options.disabled !== undefined && (disabled = _options.disabled);
$headings = $(container).find(selectors).filter('[id]');
$scrollTarget = $(scrollTarget);
$scroller = $(scroller);
}
function calc() {
headingsPos = [];
$headings.each(function() {
headingsPos.push(Math.floor($(this).position().top));
});
}
function setState(element, disabled) {
var scrollTop = $scrollTarget.scrollTop(), i;
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
if (element) {
$activeCur = element;
} else {
for (i = 0; i < headingsPos.length; i++) {
if (scrollTop >= headingsPos[i]) {
$activeCur = $tocLi.eq(i);
} else {
$activeCur || ($activeCur = $tocLi.eq(i));
break;
}
}
}
$activeLast && $activeLast.removeClass('active');
($activeLast = $activeCur).addClass('active');
}
function render() {
if(!hasRendered) {
$root.append($tocUl);
$headings.each(function() {
var $this = $(this);
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
});
$tocLi = $tocUl.children('li');
$tocUl.on('click', 'a', function(e) {
e.preventDefault();
var $this = $(this);
scrolling = true;
setState($this.parent());
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
scrolling = false;
});
});
}
hasRendered = true;
}
function init() {
var interval, timeout;
if(!hasInit) {
render(); calc(); setState(null, scrolling);
// run calc every 100 millisecond
interval = setInterval(function() {
calc();
}, 100);
timeout = setTimeout(function() {
clearInterval(interval);
}, 45000);
window.pageLoad.then(function() {
setTimeout(function() {
clearInterval(interval);
clearTimeout(timeout);
}, 3000);
});
$scrollTarget.on('scroll', function() {
disabled || setState(null, scrolling);
});
$window.on('resize', window.throttle(function() {
if (!disabled) {
render(); calc(); setState(null, scrolling);
}
}, 100));
}
hasInit = true;
}
setOptions(options);
if (!disabled) {
init();
}
$window.on('resize', window.throttle(function() {
init();
}, 200));
return {
setOptions: setOptions
};
}
$.fn.toc = toc;
});
})();
/*(function () {
})();*/
</script><script>
/* toc must before affix, since affix need to konw toc' height. */(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window);
var $articleContent = $('.js-article-content');
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
var toc;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
function disabled() {
return $col2.css('display') === 'none' || !hasToc;
}
tocDisabled = disabled();
toc = $tocRoot.toc({
selectors: TOC_SELECTOR,
container: $articleContent,
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
tocDisabled = disabled();
toc && toc.setOptions({
disabled: tocDisabled
});
}, 100));
});
})();
(function() {
var SOURCES = window.TEXT_VARIABLES.sources;
window.Lazyload.js(SOURCES.jquery, function() {
var $window = $(window), $pageFooter = $('.js-page-footer');
var $pageAside = $('.js-page-aside');
var affix;
var tocDisabled = false;
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
affix = $pageAside.affix({
offsetBottom: $pageFooter.outerHeight(),
scrollTarget: hasSidebar ? '.js-page-main' : null,
scroller: hasSidebar ? '.js-page-main' : null,
scroll: hasSidebar ? $('.js-page-main').children() : null,
disabled: tocDisabled
});
$window.on('resize', window.throttle(function() {
affix && affix.setOptions({
disabled: tocDisabled
});
}, 100));
window.pageAsideAffix = affix;
});
})();
</script>
</div>
<script>(function () {
var $root = document.getElementsByClassName('root')[0];
if (window.hasEvent('touchstart')) {
$root.dataset.isTouch = true;
document.addEventListener('touchstart', function(){}, false);
}
})();
</script>
</body>
</html>