blob: 501c20d009f616696758078d58afe3b32ed0e647 [file] [log] [blame]
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>Distributed Training · Apache SINGA</title><meta name="viewport" content="width=device-width"/><meta name="generator" content="Docusaurus"/><meta name="description" content="&lt;!--- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --&gt;"/><meta name="docsearch:version" content="4.0.0_Viet"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="Distributed Training · Apache SINGA"/><meta property="og:type" content="website"/><meta property="og:url" content="https://singa.apache.org/"/><meta property="og:description" content="&lt;!--- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the &quot;License&quot;); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --&gt;"/><meta property="og:image" content="https://singa.apache.org/img/singa_twitter_banner.jpeg"/><meta name="twitter:card" content="summary"/><meta name="twitter:image" content="https://singa.apache.org/img/singa_twitter_banner.jpeg"/><link rel="shortcut icon" href="/img/favicon.ico"/><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css"/><link rel="alternate" type="application/atom+xml" href="https://singa.apache.org/blog/atom.xml" title="Apache SINGA Blog ATOM Feed"/><link rel="alternate" type="application/rss+xml" href="https://singa.apache.org/blog/feed.xml" title="Apache SINGA Blog RSS Feed"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,700"/><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Baloo+Paaji+2&amp;family=Source+Sans+Pro:wght@200;300&amp;display=swap"/><script type="text/javascript" src="https://buttons.github.io/buttons.js"></script><script src="https://unpkg.com/vanilla-back-to-top@7.1.14/dist/vanilla-back-to-top.min.js"></script><script>
document.addEventListener('DOMContentLoaded', function() {
addBackToTop(
{"zIndex":100}
)
});
</script><script src="/js/scrollSpy.js"></script><link rel="stylesheet" href="/css/main.css"/><script src="/js/codetabs.js"></script></head><body class="sideNavVisible separateOnPageNav"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="/"><img class="logo" src="/img/singa.png" alt="Apache SINGA"/></a><a href="/versions"><h3>4.0.0_Viet</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="/docs/4.0.0_Viet/installation" target="_self">Docs</a></li><li class=""><a href="/docs/4.0.0_Viet/source-repository" target="_self">Community</a></li><li class=""><a href="/blog/" target="_self">News</a></li><li class=""><a href="https://apache-singa.readthedocs.io/en/latest/" target="_self">API</a></li><li class="navSearchWrapper reactNavSearchWrapper"><input type="text" id="search_input_react" placeholder="Search" title="Search"/></li><li class=""><a href="https://github.com/apache/singa" target="_self">GitHub</a></li></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><div class="hamburger-menu"><div class="line1"></div><div class="line2"></div><div class="line3"></div></div></div><h2><i></i><span>Guides</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Getting Started</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/installation">Cài đặt</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/software-stack">Software Stack</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/examples">Ví Dụ</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Guides</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/device">Device</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/tensor">Tensor</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/autograd">Autograd</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/optimizer">Optimizer</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/graph">Model</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/onnx">ONNX</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/docs/4.0.0_Viet/dist-train">Distributed Training</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/time-profiling">Time Profiling</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Development</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/downloads">Tải SINGA</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/build">Cài đặt SINGA từ Nguồn (Source)</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/contribute-code">Tham gia viết code</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/contribute-docs">Tham gia chỉnh sửa Hướng Dẫn Sử Dụng</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/how-to-release">Chuẩn bị trước khi phát hành</a></li><li class="navListItem"><a class="navItem" href="/docs/4.0.0_Viet/git-workflow">Quy Trình Sử Dụng Git</a></li></ul></div></div></section></div><script>
var coll = document.getElementsByClassName('collapsible');
var checkActiveCategory = true;
for (var i = 0; i < coll.length; i++) {
var links = coll[i].nextElementSibling.getElementsByTagName('*');
if (checkActiveCategory){
for (var j = 0; j < links.length; j++) {
if (links[j].classList.contains('navListItemActive')){
coll[i].nextElementSibling.classList.toggle('hide');
coll[i].childNodes[1].classList.toggle('rotate');
checkActiveCategory = false;
break;
}
}
}
coll[i].addEventListener('click', function() {
var arrow = this.childNodes[1];
arrow.classList.toggle('rotate');
var content = this.nextElementSibling;
content.classList.toggle('hide');
});
}
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
var headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
var el = event.target;
while(el !== headings){
if (el.tagName === 'A') {
document.body.classList.remove('tocActive');
break;
} else{
el = el.parentNode;
}
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer docsContainer"><div class="wrapper"><div class="post"><header class="postHeader"><a class="edit-page-link button" href="https://github.com/apache/singa-doc/blob/master/docs-site/docs/dist-train.md" target="_blank" rel="noreferrer noopener">Edit</a><h1 id="__docusaurus" class="postHeaderTitle">Distributed Training</h1></header><article><div><span><!--- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -->
<p>SINGA hỗ trợ data parallel training trên nhiều GPUs (trên một node hoặc nhiều
node khác nhau). Sơ đồ sau mô phỏng data parallel training:</p>
<p><img src="/docs/assets/MPI.png" alt="MPI.png"></p>
<p>Trong distributed training, mỗi chỉ lệnh (gọi là worker) chạy một training
script trên một máy GPU. Mỗi chỉ lệnh (process) có một communication rank riêng.
Dữ liệu để training được phân cho các worker và model thì được sao chép cho mỗi
worker. Ở mỗi vòng, worker đọc một mini-batch dữ liệu (vd., 256 hình ảnh) từ
phần được chia và chạy thuật toán BackPropagation để tính ra độ dốc (gradient)
của weight, được lấy trung bình qua all-reduce (cung cấp bởi
<a href="https://developer.nvidia.com/nccl">NCCL</a>) để cập nhật weight theo thuật toán
stochastic gradient descent (SGD).</p>
<p>Hàm all-reduce operation bởi NCCL có thể được sử dụng để giảm và đồng bộ hoá độ
dốc từ các máy GPU các nhau. Xem thử training với 4 GPUs như dưới đây. Sau khi
độ dốc (gradients) từ 4 GPUs được tính, all-reduce sẽ trả lại tổng độ dốc
(gradient) cho các GPU và đưa tới mỗi GPU. Sau đó có thể dễ dàng tính ra độ dốc
trung bình.</p>
<p><img src="/docs/assets/AllReduce.png" alt="AllReduce.png"></p>
<h2><a class="anchor" aria-hidden="true" id="sử-dụng"></a><a href="#sử-dụng" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Sử Dụng</h2>
<p>SINGA áp dụng một module gọi là <code>DistOpt</code> (là dạng con của <code>Opt</code>) cho
distributed training. Nó gói lại normal SGD optimizer và gọi <code>Communicator</code> để
động bộ hoá độ dốc. Ví dụ sau mô phỏng cách sử dụng <code>DistOpt</code> để training một
CNN model với dữ liệu MNIST. Nguồn code có thể tìm
<a href="https://github.com/apache/singa/blob/master/examples/cnn/">tại đây</a>, và
<a href="">Colab notebook</a>.</p>
<h3><a class="anchor" aria-hidden="true" id="code-ví-dụ"></a><a href="#code-ví-dụ" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Code Ví Dụ</h3>
<ol>
<li>Định nghĩa neural network model:</li>
</ol>
<pre><code class="hljs css language-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CNN</span><span class="hljs-params">(model.Model)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span><span class="hljs-params">(self, num_classes=<span class="hljs-number">10</span>, num_channels=<span class="hljs-number">1</span>)</span>:</span>
super(CNN, self).__init__()
self.conv1 = layer.Conv2d(num_channels, <span class="hljs-number">20</span>, <span class="hljs-number">5</span>, padding=<span class="hljs-number">0</span>, activation=<span class="hljs-string">"RELU"</span>)
self.conv2 = layer.Conv2d(<span class="hljs-number">20</span>, <span class="hljs-number">50</span>, <span class="hljs-number">5</span>, padding=<span class="hljs-number">0</span>, activation=<span class="hljs-string">"RELU"</span>)
self.linear1 = layer.Linear(<span class="hljs-number">500</span>)
self.linear2 = layer.Linear(num_classes)
self.pooling1 = layer.MaxPool2d(<span class="hljs-number">2</span>, <span class="hljs-number">2</span>, padding=<span class="hljs-number">0</span>)
self.pooling2 = layer.MaxPool2d(<span class="hljs-number">2</span>, <span class="hljs-number">2</span>, padding=<span class="hljs-number">0</span>)
self.relu = layer.ReLU()
self.flatten = layer.Flatten()
self.softmax_cross_entropy = layer.SoftMaxCrossEntropy()
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">forward</span><span class="hljs-params">(self, x)</span>:</span>
y = self.conv1(x)
y = self.pooling1(y)
y = self.conv2(y)
y = self.pooling2(y)
y = self.flatten(y)
y = self.linear1(y)
y = self.relu(y)
y = self.linear2(y)
<span class="hljs-keyword">return</span> y
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">train_one_batch</span><span class="hljs-params">(self, x, y, dist_option=<span class="hljs-string">'fp32'</span>, spars=<span class="hljs-number">0</span>)</span>:</span>
out = self.forward(x)
loss = self.softmax_cross_entropy(out, y)
<span class="hljs-comment"># cho phép nhiều lựa chọn dùng trong distributed training</span>
<span class="hljs-comment"># Tham khảo mục "Optimizations về Distributed Training"</span>
<span class="hljs-keyword">if</span> dist_option == <span class="hljs-string">'fp32'</span>:
self.optimizer(loss)
<span class="hljs-keyword">elif</span> dist_option == <span class="hljs-string">'fp16'</span>:
self.optimizer.backward_and_update_half(loss)
<span class="hljs-keyword">elif</span> dist_option == <span class="hljs-string">'partialUpdate'</span>:
self.optimizer.backward_and_partial_update(loss)
<span class="hljs-keyword">elif</span> dist_option == <span class="hljs-string">'sparseTopK'</span>:
self.optimizer.backward_and_sparse_update(loss,
topK=<span class="hljs-literal">True</span>,
spars=spars)
<span class="hljs-keyword">elif</span> dist_option == <span class="hljs-string">'sparseThreshold'</span>:
self.optimizer.backward_and_sparse_update(loss,
topK=<span class="hljs-literal">False</span>,
spars=spars)
<span class="hljs-keyword">return</span> out, loss
<span class="hljs-comment"># tạo model</span>
model = CNN()
</code></pre>
<ol start="2">
<li>Tạo <code>DistOpt</code> instance và đính nó vào model đã tạo:</li>
</ol>
<pre><code class="hljs css language-python">sgd = opt.SGD(lr=<span class="hljs-number">0.005</span>, momentum=<span class="hljs-number">0.9</span>, weight_decay=<span class="hljs-number">1e-5</span>)
sgd = opt.DistOpt(sgd)
model.set_optimizer(sgd)
dev = device.create_cuda_gpu_on(sgd.local_rank)
</code></pre>
<p>Đây là giải thích cho các biến sử dụng trong code:</p>
<p>(i) <code>dev</code></p>
<p>dev dùng để chỉ <code>Device</code> instance, nơi tải dữ liệu và chạy CNN model.</p>
<p>(ii)<code>local_rank</code></p>
<p>Local rank chỉ số GPU mà chỉ lệnh (process) hiện tại đang sử dụng trên cùng một
node. Ví dụ, nếu bạn đang sử dụng một node có 2 GPUs, <code>local_rank=0</code> nghĩa là
chỉ lệnh này đang sử dụng máy GPU đầu tiên, trong khi <code>local_rank=1</code> nghĩa là
đang sử dụng máy GPU thứ hai. Sử dụng MPI hay đa xử lý, bạn có thể chạy cùng một
tập lệnh training chỉ khác giá trị của <code>local_rank</code>.</p>
<p>(iii)<code>global_rank</code></p>
<p>Rank trong global biểu thị global rank cho tất cả các chỉ lệnh (process) trong
các nodes mà bạn đang sử dụng. Lấy ví dụ trường hợp bạn có 3 nodes và mỗi một
node có hai GPUs, <code>global_rank=0</code> nghĩa là chỉ lệnh đang sử dụng máy GPU đầu
tiên ở node đầu tiên, <code>global_rank=2</code> nghĩa là chỉ lệnh đang sử dụng máy GPU đầu
tiên ở node thứ 2, và <code>global_rank=4</code> nghĩa là chỉ lệnh đang sử dụng máy GPU đầu
tiên ở node thứ 3.</p>
<ol start="3">
<li>Tải và phân chia dữ liệu để training/validation</li>
</ol>
<pre><code class="hljs css language-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">data_partition</span><span class="hljs-params">(dataset_x, dataset_y, global_rank, world_size)</span>:</span>
data_per_rank = dataset_x.shape[<span class="hljs-number">0</span>] // world_size
idx_start = global_rank * data_per_rank
idx_end = (global_rank + <span class="hljs-number">1</span>) * data_per_rank
<span class="hljs-keyword">return</span> dataset_x[idx_start:idx_end], dataset_y[idx_start:idx_end]
train_x, train_y, test_x, test_y = load_dataset()
train_x, train_y = data_partition(train_x, train_y,
sgd.global_rank, sgd.world_size)
test_x, test_y = data_partition(test_x, test_y,
sgd.global_rank, sgd.world_size)
</code></pre>
<p>Một phần của bộ dữ liệu (dataset) được trả lại cho <code>dev</code>.</p>
<p>Tại đây, <code>world_size</code> thể hiện tổng số chỉ lệnh trong tất cả các node mà bạn
đang sử dụng cho distributed training.</p>
<ol start="4">
<li>Khởi tạo và đồng bộ các tham số của model cho tất cả workers:</li>
</ol>
<pre><code class="hljs css language-python"><span class="hljs-comment"># Đồng bộ tham số ban đầu</span>
tx = tensor.Tensor((batch_size, <span class="hljs-number">1</span>, IMG_SIZE, IMG_SIZE), dev, tensor.float32)
ty = tensor.Tensor((batch_size, num_classes), dev, tensor.int32)
model.compile([tx], is_train=<span class="hljs-literal">True</span>, use_graph=graph, sequential=<span class="hljs-literal">True</span>)
...
<span class="hljs-comment"># Sử dụng cùng một random seed cho các ranks khác nhau</span>
seed = <span class="hljs-number">0</span>
dev.SetRandSeed(seed)
np.random.seed(seed)
</code></pre>
<ol start="5">
<li>Chạy BackPropagation và distributed SGD</li>
</ol>
<pre><code class="hljs css language-python"><span class="hljs-keyword">for</span> epoch <span class="hljs-keyword">in</span> range(max_epoch):
<span class="hljs-keyword">for</span> b <span class="hljs-keyword">in</span> range(num_train_batch):
x = train_x[idx[b * batch_size: (b + <span class="hljs-number">1</span>) * batch_size]]
y = train_y[idx[b * batch_size: (b + <span class="hljs-number">1</span>) * batch_size]]
tx.copy_from_numpy(x)
ty.copy_from_numpy(y)
<span class="hljs-comment"># Train the model</span>
out, loss = model(tx, ty)
</code></pre>
<h3><a class="anchor" aria-hidden="true" id="hướng-dẫn-thực-hiện"></a><a href="#hướng-dẫn-thực-hiện" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Hướng Dẫn Thực Hiện</h3>
<p>Có hai cách để bắt đầu quá trình training: MPI hoặc Python đa xử lý.</p>
<h4><a class="anchor" aria-hidden="true" id="python-đa-xử-lý"></a><a href="#python-đa-xử-lý" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Python Đa Xử Lý</h4>
<p>Chạy trên một node với nhiều GPUs, trong đó mỗi GPU là một worker.</p>
<ol>
<li>Đặt tất cả các training codes trong cùng một hàm (function)</li>
</ol>
<pre><code class="hljs css language-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">train_mnist_cnn</span><span class="hljs-params">(nccl_id=None, local_rank=None, world_size=None)</span>:</span>
...
</code></pre>
<ol start="2">
<li>Tạo <code>mnist_multiprocess.py</code></li>
</ol>
<pre><code class="hljs css language-python"><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
<span class="hljs-comment"># Generate a NCCL ID to be used for collective communication</span>
nccl_id = singa.NcclIdHolder()
<span class="hljs-comment"># Define the number of GPUs to be used in the training process</span>
world_size = int(sys.argv[<span class="hljs-number">1</span>])
<span class="hljs-comment"># Define and launch the multi-processing</span>
<span class="hljs-keyword">import</span> multiprocessing
process = []
<span class="hljs-keyword">for</span> local_rank <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, world_size):
process.append(multiprocessing.Process(target=train_mnist_cnn,
args=(nccl_id, local_rank, world_size)))
<span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> process:
p.start()
</code></pre>
<p>Dưới đây là giải thích cho các biến tạo ở trên:</p>
<p>(i) <code>nccl_id</code></p>
<p>Lưu ý rằng chúng ta cần phải tạo một NCCL ID ở đây để sử dụng cho collective
communication, sau đó gửi nó tới tất cả các chỉ lệnh. NCCL ID giống như là vé
vào cửa, khi chỉ có chỉ lệnh với ID này có thể tham gia vào quá trình
all-reduce. (Về sua nếu dùng MPI, thì việc sử dụng NCCL ID là không cần thiết,
bởi vì ID được gửi đi bởi MPI trong code của chúng tôi một cách tự động)</p>
<p>(ii) <code>world_size</code></p>
<p>world_size là số lượng máy GPUs bạn muốn sử dụng cho training.</p>
<p>(iii) <code>local_rank</code></p>
<p>local_rank xác định local rank của distributed training và máy gpu được sử dụng
trong chỉ lệnh. Trong code bên trên, for loop được sử dụng để chạy hàm train
function, và local_rank chạy vòng từ 0 tới world_size. Trong trường hợp này, chỉ
lệnh khác nhau có thể sử dụng máy GPUs khác nhau để training.</p>
<p>Tham số để tạo <code>DistOpt</code> instance cần được cập nhật như sau:</p>
<pre><code class="hljs css language-python">sgd = opt.DistOpt(sgd, nccl_id=nccl_id, local_rank=local_rank, world_size=world_size)
</code></pre>
<ol start="3">
<li>Chạy <code>mnist_multiprocess.py</code></li>
</ol>
<pre><code class="hljs css language-sh">python mnist_multiprocess.py 2
</code></pre>
<p>Kết qủa hiển thị tốc độ so với training trên một máy GPU.</p>
<pre><code class="hljs">Starting Epoch <span class="hljs-number">0</span>:
Training loss = <span class="hljs-number">408.909790</span>, training accuracy = <span class="hljs-number">0.880475</span>
Evaluation accuracy = <span class="hljs-number">0.956430</span>
Starting Epoch <span class="hljs-number">1</span>:
Training loss = <span class="hljs-number">102.396790</span>, training accuracy = <span class="hljs-number">0.967415</span>
Evaluation accuracy = <span class="hljs-number">0.977564</span>
Starting Epoch <span class="hljs-number">2</span>:
Training loss = <span class="hljs-number">69.217010</span>, training accuracy = <span class="hljs-number">0.977915</span>
Evaluation accuracy = <span class="hljs-number">0.981370</span>
Starting Epoch <span class="hljs-number">3</span>:
Training loss = <span class="hljs-number">54.248390</span>, training accuracy = <span class="hljs-number">0.982823</span>
Evaluation accuracy = <span class="hljs-number">0.984075</span>
Starting Epoch <span class="hljs-number">4</span>:
Training loss = <span class="hljs-number">45.213406</span>, training accuracy = <span class="hljs-number">0.985560</span>
Evaluation accuracy = <span class="hljs-number">0.985276</span>
Starting Epoch <span class="hljs-number">5</span>:
Training loss = <span class="hljs-number">38.868435</span>, training accuracy = <span class="hljs-number">0.987764</span>
Evaluation accuracy = <span class="hljs-number">0.986278</span>
Starting Epoch <span class="hljs-number">6</span>:
Training loss = <span class="hljs-number">34.078186</span>, training accuracy = <span class="hljs-number">0.989149</span>
Evaluation accuracy = <span class="hljs-number">0.987881</span>
Starting Epoch <span class="hljs-number">7</span>:
Training loss = <span class="hljs-number">30.138697</span>, training accuracy = <span class="hljs-number">0.990451</span>
Evaluation accuracy = <span class="hljs-number">0.988181</span>
Starting Epoch <span class="hljs-number">8</span>:
Training loss = <span class="hljs-number">26.854443</span>, training accuracy = <span class="hljs-number">0.991520</span>
Evaluation accuracy = <span class="hljs-number">0.988682</span>
Starting Epoch <span class="hljs-number">9</span>:
Training loss = <span class="hljs-number">24.039650</span>, training accuracy = <span class="hljs-number">0.992405</span>
Evaluation accuracy = <span class="hljs-number">0.989083</span>
</code></pre>
<h4><a class="anchor" aria-hidden="true" id="mpi"></a><a href="#mpi" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>MPI</h4>
<p>Có thể dùng cho cả một node và nhiều node miễn là có nhiều máy GPUs.</p>
<ol>
<li>Tạo <code>mnist_dist.py</code></li>
</ol>
<pre><code class="hljs css language-python"><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
train_mnist_cnn()
</code></pre>
<ol start="2">
<li>Tạo một hostfile cho MPI, vd. hostfile dưới đây sử dụng 2 chỉ lệnh (vd., 2
GPUs) trên một node</li>
</ol>
<pre><code class="hljs css language-txt">localhost:<span class="hljs-number">2</span>
</code></pre>
<ol start="3">
<li>Khởi động quá trình training qua <code>mpiexec</code></li>
</ol>
<pre><code class="hljs css language-sh">mpiexec --hostfile host_file python mnist_dist.py
</code></pre>
<p>Kết qủa có thể hiển thị tốc độ so với training trên một máy GPU.</p>
<pre><code class="hljs">Starting Epoch <span class="hljs-number">0</span>:
Training loss = <span class="hljs-number">383.969543</span>, training accuracy = <span class="hljs-number">0.886402</span>
Evaluation accuracy = <span class="hljs-number">0.954327</span>
Starting Epoch <span class="hljs-number">1</span>:
Training loss = <span class="hljs-number">97.531479</span>, training accuracy = <span class="hljs-number">0.969451</span>
Evaluation accuracy = <span class="hljs-number">0.977163</span>
Starting Epoch <span class="hljs-number">2</span>:
Training loss = <span class="hljs-number">67.166870</span>, training accuracy = <span class="hljs-number">0.978516</span>
Evaluation accuracy = <span class="hljs-number">0.980769</span>
Starting Epoch <span class="hljs-number">3</span>:
Training loss = <span class="hljs-number">53.369656</span>, training accuracy = <span class="hljs-number">0.983040</span>
Evaluation accuracy = <span class="hljs-number">0.983974</span>
Starting Epoch <span class="hljs-number">4</span>:
Training loss = <span class="hljs-number">45.100403</span>, training accuracy = <span class="hljs-number">0.985777</span>
Evaluation accuracy = <span class="hljs-number">0.986078</span>
Starting Epoch <span class="hljs-number">5</span>:
Training loss = <span class="hljs-number">39.330826</span>, training accuracy = <span class="hljs-number">0.987447</span>
Evaluation accuracy = <span class="hljs-number">0.987179</span>
Starting Epoch <span class="hljs-number">6</span>:
Training loss = <span class="hljs-number">34.655270</span>, training accuracy = <span class="hljs-number">0.988799</span>
Evaluation accuracy = <span class="hljs-number">0.987780</span>
Starting Epoch <span class="hljs-number">7</span>:
Training loss = <span class="hljs-number">30.749735</span>, training accuracy = <span class="hljs-number">0.989984</span>
Evaluation accuracy = <span class="hljs-number">0.988281</span>
Starting Epoch <span class="hljs-number">8</span>:
Training loss = <span class="hljs-number">27.422146</span>, training accuracy = <span class="hljs-number">0.991319</span>
Evaluation accuracy = <span class="hljs-number">0.988582</span>
Starting Epoch <span class="hljs-number">9</span>:
Training loss = <span class="hljs-number">24.548153</span>, training accuracy = <span class="hljs-number">0.992171</span>
Evaluation accuracy = <span class="hljs-number">0.988682</span>
</code></pre>
<h2><a class="anchor" aria-hidden="true" id="tối-ưu-hoá-distributed-training"></a><a href="#tối-ưu-hoá-distributed-training" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Tối Ưu Hoá Distributed Training</h2>
<p>SINGA cung cấp chiến lược đa tối ưu hoá cho distributed training để giảm
communication cost. Tham khảo API của <code>DistOpt</code> cho cấu hình của mỗi cách.</p>
<p>Khi sử dụng <code>model.Model</code> để tạo một model, cần phải đặt các lựa chọn cho
distributed training trong phương pháp <code>train_one_batch</code>. Tham khảo code ví dụ
trên đầu trang. Bạn có thể chỉ cần copy code cho các lựa chọn và sử dụng nó cho
các model khác. Với các lựa chọn xác định, ta có thể đặt tham số<code>dist_option</code>
<code>spars</code> khi bắt đầu training với <code>model(tx, ty, dist_option, spars)</code></p>
<h3><a class="anchor" aria-hidden="true" id="không-tối-ưu-hoá"></a><a href="#không-tối-ưu-hoá" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Không Tối Ưu Hoá</h3>
<pre><code class="hljs css language-python">out, loss = model(tx, ty)
</code></pre>
<p><code>loss</code> là output tensor từ hàm loss function, vd., cross-entropy cho
classification tasks.</p>
<h3><a class="anchor" aria-hidden="true" id="half-precision-gradients"></a><a href="#half-precision-gradients" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Half-precision Gradients</h3>
<pre><code class="hljs css language-python">out, loss = model(tx, ty, dist_option = <span class="hljs-string">'fp16'</span>)
</code></pre>
<p>Chuyển đổi gía trị độ dốc sang hiển thị dạng 16-bit (vd., half-precision) trước
khi gọi hàm all-reduce.</p>
<h3><a class="anchor" aria-hidden="true" id="đồng-bộ-cục-bộ-partial-synchronization"></a><a href="#đồng-bộ-cục-bộ-partial-synchronization" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Đồng Bộ Cục Bộ (Partial Synchronization)</h3>
<pre><code class="hljs css language-python">out, loss = model(tx, ty, dist_option = <span class="hljs-string">'partialUpdate'</span>)
</code></pre>
<p>Ở mỗi vòng lặp (iteration), mỗi rank thực hiện việc cập nhật sgd. Sau đó chỉ một
nhóm tham số là được tính trung bình để đồng bộ hoá. Điều này giúp tiết kiệm
communication cost. Độ lớn của nhóm này được xác định khi tạo hàm <code>DistOpt</code>
instance.</p>
<h3><a class="anchor" aria-hidden="true" id="phân-bổ-độ-dốc-gradient-sparsification"></a><a href="#phân-bổ-độ-dốc-gradient-sparsification" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Phân Bổ Độ Dốc (Gradient Sparsification)</h3>
<p>Kế hoạch phân bổ để chọn ra một nhóm nhỏ độ dốc nhằm thực hiện all-reduce. Có
hai cách:</p>
<ul>
<li>Chọn K phần tử lớn nhất. spars là một phần (0 - 1) của tổng số phần tử được
chọn.</li>
</ul>
<pre><code class="hljs css language-python">out, loss = model(tx, ty, dist_option = <span class="hljs-string">'sparseTopK'</span>, spars = spars)
</code></pre>
<ul>
<li>Tất cả độ dốc có giá trị tuyệt đối lớn hơn ngưỡng spars đặt trước được lựa
chọn.</li>
</ul>
<pre><code class="hljs css language-python">out, loss = model(tx, ty, dist_option = <span class="hljs-string">'sparseThreshold'</span>, spars = spars)
</code></pre>
<p>Các hyper-parameter được cấu tạo khi tạo hàm <code>DistOpt</code> instance.</p>
<h2><a class="anchor" aria-hidden="true" id="thực-hiện"></a><a href="#thực-hiện" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Thực Hiện</h2>
<p>Mục này chủ yếu dành cho các lập trình viên (developer) muốn biết lập trình
trong distribute module được thực hiện như thế nào.</p>
<h3><a class="anchor" aria-hidden="true" id="giao-diện-c-cho-bộ-chuyển-mạch-communicator-nccl"></a><a href="#giao-diện-c-cho-bộ-chuyển-mạch-communicator-nccl" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Giao Diện C cho Bộ Chuyển Mạch (communicator) NCCL</h3>
<p>Trước tiên, communication layer được lập trình bằng ngôn ngữ C
<a href="https://github.com/apache/singa/blob/master/src/io/communicator.cc">communicator.cc</a>.
Nó áp dụng NCCL library cho collective communication.</p>
<p>Có hai hàm tạo nên communicator, một cho MPI và một cho đa phương thức
(multiprocess).</p>
<p>(i) Hàm tạo sử dụng MPI</p>
<p>Hàm tạo bước đầu sẽ sử dụng global rank và world size, sau đó tính toán ra local
rank. Tiếp theo, rank 0 sẽ tạo ra NCCL ID và phát nó lên mỗi rank. Sau đó, nó
gọi hàm setup để khởi tạo NCCL communicator, cuda streams, và buffers.</p>
<p>(ii) Hàm tạo sử dụng Python đa phương thức</p>
<p>Hàm tạo bước đầu sẽ sử dụng rank, world size, và NCCL ID từ input argument. Sau
đó, nó gọi hàm setup function để khởi tạo NCCL communicator, cuda streams, và
buffers.</p>
<p>Sau khi khởi động, nó thực hiện chức năng all-reduce để đồng bộ hoá các tham số
model và độ dốc. Ví dụ, synch sử dụng một input tensor và tiến hành all-reduce
qua đoạn chương trình NCCL. Sau khi gọi synch, cần gọi hàm wait để đợi hàm
all-reduce operation kết thúc.</p>
<h3><a class="anchor" aria-hidden="true" id="giao-diện-python-của-distopt"></a><a href="#giao-diện-python-của-distopt" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Giao Diện Python của DistOpt</h3>
<p>Sau đó, giao diện python sẽ tạo ra một
<a href="https://github.com/apache/singa/blob/master/python/singa/opt.py">DistOpt</a> class
để gói một
<a href="https://github.com/apache/singa/blob/master/python/singa/opt.py">optimizer</a>
object để thực hiện distributed training dựa trên MPI hoặc đa xử lý. Trong khi
khởi động, nó tạo ra một NCCL communicator object (từ giao diện C đề cập ở mục
nhỏ phía trên). Sau đó, communicator object này được sử dụng trong mỗi hàm
all-reduce trong DistOpt.</p>
<p>Trong MPI hoặc đa xử lý, mỗi chỉ lệnh có một rank, cho biết thông tin máy GPU
nào qui trình này đang sử dụng. Dữ liệu training được chia nhỏ để mỗi chỉ lệnh
có thể đánh giá sub-gradient dựa trên dữ liệu đã chia trước đó. Sau khi
sub-gradient được tạo ra ở mỗi chỉ lệnh, độ dốc stochastic gradient tổng hợp sẽ
được tạo ra bằng cách all-reduce các sub-gradients đánh giá bởi tất cả các chỉ
lệnh.</p>
</span></div></article></div><div class="docs-prevnext"><a class="docs-prev button" href="/docs/4.0.0_Viet/onnx"><span class="arrow-prev"></span><span>ONNX</span></a><a class="docs-next button" href="/docs/4.0.0_Viet/time-profiling"><span>Time Profiling</span><span class="arrow-next"></span></a></div></div></div><nav class="onPageNav"><ul class="toc-headings"><li><a href="#sử-dụng">Sử Dụng</a><ul class="toc-headings"><li><a href="#code-ví-dụ">Code Ví Dụ</a></li><li><a href="#hướng-dẫn-thực-hiện">Hướng Dẫn Thực Hiện</a></li></ul></li><li><a href="#tối-ưu-hoá-distributed-training">Tối Ưu Hoá Distributed Training</a><ul class="toc-headings"><li><a href="#không-tối-ưu-hoá">Không Tối Ưu Hoá</a></li><li><a href="#half-precision-gradients">Half-precision Gradients</a></li><li><a href="#đồng-bộ-cục-bộ-partial-synchronization">Đồng Bộ Cục Bộ (Partial Synchronization)</a></li><li><a href="#phân-bổ-độ-dốc-gradient-sparsification">Phân Bổ Độ Dốc (Gradient Sparsification)</a></li></ul></li><li><a href="#thực-hiện">Thực Hiện</a><ul class="toc-headings"><li><a href="#giao-diện-c-cho-bộ-chuyển-mạch-communicator-nccl">Giao Diện C cho Bộ Chuyển Mạch (communicator) NCCL</a></li><li><a href="#giao-diện-python-của-distopt">Giao Diện Python của DistOpt</a></li></ul></li></ul></nav></div><footer class="nav-footer" id="footer"><section class="sitemap"><a href="/" class="nav-home"><img src="/img/singa-logo-square.png" alt="Apache SINGA" width="66" height="58"/></a><div><h5>Docs</h5><a href="/docs/installation">Getting Started</a><a href="/docs/device">Guides</a><a href="/en/https://apache-singa.readthedocs.io/en/latest/">API Reference</a><a href="/docs/examples">Examples</a><a href="/docs/download-singa">Development</a></div><div><h5>Community</h5><a href="/en/users.html">User Showcase</a><a href="/docs/history-singa">SINGA History</a><a href="/docs/team-list">SINGA Team</a><a href="/blog">SINGA News</a><a href="https://github.com/apache/singa">GitHub</a><div class="social"><a class="github-button" href="https://github.com/apache/singa" data-count-href="/apache/singa/stargazers" data-show-count="true" data-count-aria-label="# stargazers on GitHub" aria-label="Star this project on GitHub">apache/singa-doc</a></div><div class="social"><a href="https://twitter.com/ApacheSINGA" class="twitter-follow-button">Follow @ApacheSINGA</a></div></div><div><h5>Apache Software Foundation</h5><a href="https://apache.org/" target="_blank" rel="noreferrer noopener">Foundation</a><a href="http://www.apache.org/licenses/" target="_blank" rel="noreferrer noopener">License</a><a href="http://www.apache.org/foundation/sponsorship.html" target="_blank" rel="noreferrer noopener">Sponsorship</a><a href="http://www.apache.org/foundation/thanks.html" target="_blank" rel="noreferrer noopener">Thanks</a><a href="http://www.apache.org/events/current-event" target="_blank" rel="noreferrer noopener">Events</a><a href="http://www.apache.org/security/" target="_blank" rel="noreferrer noopener">Security</a></div></section><div style="width:100%;text-align:center"><a href="https://apache.org/" target="_blank" rel="noreferrer noopener" class="ApacheOpenSource"><img src="/img/asf_logo_wide.svg" alt="Apache Open Source"/></a><section class="copyright" style="max-width:60%;margin:0 auto">Copyright © 2023
The Apache Software Foundation. All rights reserved.
Apache SINGA, Apache, the Apache feather logo, and
the Apache SINGA project logos are trademarks of The
Apache Software Foundation. All other marks mentioned
may be trademarks or registered trademarks of their
respective owners.</section></div></footer></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script><script>window.twttr=(function(d,s, id){var js,fjs=d.getElementsByTagName(s)[0],t=window.twttr||{};if(d.getElementById(id))return t;js=d.createElement(s);js.id=id;js.src='https://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js, fjs);t._e = [];t.ready = function(f) {t._e.push(f);};return t;}(document, 'script', 'twitter-wjs'));</script><script>
document.addEventListener('keyup', function(e) {
if (e.target !== document.body) {
return;
}
// keyCode for '/' (slash)
if (e.keyCode === 191) {
const search = document.getElementById('search_input_react');
search && search.focus();
}
});
</script><script>
var search = docsearch({
apiKey: '45202133606c0b5fa6d21cddc4725dd8',
indexName: 'apache_singa',
inputSelector: '#search_input_react',
algoliaOptions: {"facetFilters":["language:en","version:3.0.0"]}
});
</script></body></html>