tek4

PyTorch Trên GPU

by - September. 21, 2021
Kiến thức
Machine Learning
Python
<p style="text-align: justify;"><em>Ch&agrave;o mừng c&aacute;c bạn quay trở lại với loạt b&agrave;i về <strong><a href="https://tek4.vn/lap-trinh-neural-network-voi-pytorch-deep-learning-voi-pytorch/">Lập Tr&igrave;nh Neural Network Với Pytorch</a>.&nbsp;</strong>Trong b&agrave;i n&agrave;y, ch&uacute;ng ta sẽ t&igrave;m hiểu c&aacute;ch chạy code Pytorch tr&ecirc;n GPU. Đồng thời&nbsp;sẽ xem c&aacute;ch sử dụng GPU n&oacute;i chung v&agrave; c&aacute;ch &aacute;p dụng c&aacute;c kỹ thuật chung n&agrave;y để huấn luyện mạng neural của ch&uacute;ng ta. Bắt đầu th&ocirc;i!</em></p> <p style="text-align: justify;"><img style="width: 100%;" src="http://tek4vn.2soft.top/public_files/pytorch-tren-gpu-png-1" alt="PyTorch Tr&ecirc;n GPU" /></p> <p style="text-align: center;"><a href="https://tek4.vn/tang-toc-qua-trinh-huan-luyen-lap-trinh-neural-network-voi-pytorch/" target="_blank" rel="noopener">Xem th&ecirc;m b&agrave;i viết trước:&nbsp;Tăng Tốc Qu&aacute; Tr&igrave;nh Huấn Luyện&nbsp;</a></p> <h3 class="section-heading" style="text-align: justify;">Sử dụng GPU cho Deep learning</h3> <p style="text-align: justify;">Nếu bạn chưa xem b&agrave;i viết n&oacute;i về <a href="https://tek4.vn/gioi-thieu-cuda-lap-trinh-neural-network-voi-pytorch-bai-3/" target="_blank" rel="noopener">l&yacute; do deep learning v&agrave; mạng neural sử dụng GPU</a>, h&atilde;y nhớ xem lại b&agrave;i đ&oacute; kết hợp c&ugrave;ng với b&agrave;i n&agrave;y để hiểu r&otilde; nhất về c&aacute;c kh&aacute;i niệm được nhắc đến.</p> <p style="text-align: justify;">B&acirc;y giờ, ch&uacute;ng ta sẽ bắt đầu chạy với v&iacute; dụ về GPU PyTorch.</p> <h4 class="sub-section-heading" style="text-align: justify;">V&iacute; dụ về GPU tr&ecirc;n PyTorch</h4> <p style="text-align: justify;">PyTorch cho ph&eacute;p ch&uacute;ng ta di chuyển dữ liệu đến v&agrave; đi từ GPU của m&igrave;nh một c&aacute;ch liền mạch khi ch&uacute;ng ta chuẩn bị c&aacute;c t&iacute;nh to&aacute;n b&ecirc;n trong c&aacute;c chương tr&igrave;nh của m&igrave;nh.</p> <p style="text-align: justify;">Khi ch&uacute;ng ta đi đến GPU, ch&uacute;ng ta c&oacute; thể sử dụng phương thức <em>cuda()</em> v&agrave; khi đến CPU, ch&uacute;ng ta c&oacute; thể sử dụng phương thức <em>cpu().</em></p> <p style="text-align: justify;">Ch&uacute;ng ta cũng c&oacute; thể sử dụng phương thức <em>to().&nbsp;</em>Để truy cập GPU, ch&uacute;ng ta viết&nbsp; <em>to('cuda')</em> v&agrave; để truy cập CPU, ch&uacute;ng ta viết&nbsp;<em>to('cpu').&nbsp;</em>Phương thức <em>to()</em> l&agrave; c&aacute;ch được ưa th&iacute;ch hơn v&igrave; n&oacute; linh hoạt hơn.&nbsp;Ch&uacute;ng ta sẽ thấy một v&iacute; dụ bằng c&aacute;ch sử dụng hai c&aacute;i đầu ti&ecirc;n v&agrave; sau đ&oacute; ch&uacute;ng ta sẽ mặc định l&agrave; lu&ocirc;n sử dụng phương&nbsp;<em>to().</em></p> <table class=" aligncenter" style="width: 33.8675%;"> <tbody> <tr> <td style="width: 37.942%;"><strong>CPU</strong></td> <td style="width: 43.308%;"><strong>GPU</strong></td> </tr> <tr> <td style="width: 37.942%;">cpu()</td> <td style="width: 43.308%;">cuda()</td> </tr> <tr> <td style="width: 37.942%;">to('cpu')</td> <td style="width: 43.308%;">to('cuda')</td> </tr> </tbody> </table> <p style="text-align: justify;">Để sử dụng GPU trong qu&aacute; tr&igrave;nh huấn luyện, c&oacute; hai y&ecirc;u cầu thiết yếu.&nbsp;C&aacute;c y&ecirc;u cầu n&agrave;y như sau, <em>dữ liệu phải được chuyển đến GPU</em> v&agrave; <em>mạng phải được chuyển đến GPU</em>.</p> <ol style="text-align: justify;"> <li>Dữ liệu tr&ecirc;n GPU</li> <li>Mạng tr&ecirc;n GPU</li> </ol> <p style="text-align: justify;">Theo mặc định, khi một tensor PyTorch hoặc một module mạng neural PyTorch được tạo, dữ liệu tương ứng sẽ được khởi tạo tr&ecirc;n CPU.&nbsp;Cụ thể, dữ liệu tồn tại b&ecirc;n trong bộ nhớ của CPU.</p> <p style="text-align: justify;">B&acirc;y giờ, h&atilde;y tạo một tensor v&agrave; một mạng, v&agrave; xem c&aacute;ch ch&uacute;ng ta thực hiện chuyển từ CPU sang GPU.</p> <p style="text-align: justify;">Ở đ&acirc;y, ch&uacute;ng ta tạo một tensor v&agrave; một mạng:</p> <pre class="language-python"><code>t = torch.ones(1,1,28,28) network = Network()</code></pre> <p style="text-align: justify;">B&acirc;y giờ, ch&uacute;ng ta gọi phương thức <em>cuda()</em>&nbsp;sau đ&oacute; g&aacute;n lại tensor v&agrave; mạng cho c&aacute;c gi&aacute; trị trả về đ&atilde; được sao ch&eacute;p v&agrave;o GPU:</p> <pre class="language-python"><code>t = t.cuda() network = network.cuda()</code></pre> <p style="text-align: justify;">Tiếp theo, ch&uacute;ng ta c&oacute; thể nhận dự đo&aacute;n từ mạng v&agrave; thấy rằng thuộc t&iacute;nh device tensor của dự đo&aacute;n x&aacute;c nhận rằng dữ liệu nằm tr&ecirc;n cuda, l&agrave; GPU:</p> <pre class="language-python"><code>&gt; gpu_pred = network(t) &gt; gpu_pred.device device(type='cuda', index=0)</code></pre> <p style="text-align: justify;">Tương tự như vậy, ch&uacute;ng ta c&oacute; thể đi theo c&aacute;ch ngược lại với CPU:</p> <pre class="language-python"><code>&gt; t = t.cpu() &gt; network = network.cpu() &gt; cpu_pred = network(t) &gt; cpu_pred.device device(type='cpu')</code></pre> <p style="text-align: justify;">T&oacute;m lại, đ&acirc;y l&agrave; c&aacute;ch ch&uacute;ng ta c&oacute; thể sử dụng để chạy Pytorch tr&ecirc;n GPU.&nbsp;Những g&igrave; ch&uacute;ng ta n&ecirc;n chuyển sang b&acirc;y giờ l&agrave; một số chi tiết quan trọng ẩn b&ecirc;n dưới bề mặt của code m&agrave; ch&uacute;ng ta vừa thấy.</p> <p style="text-align: justify;">V&iacute; dụ: mặc d&ugrave; ch&uacute;ng ta đ&atilde; sử dụng c&aacute;c phương thức <em>cuda()</em> v&agrave; <em>cpu()&nbsp;</em>nhưng ch&uacute;ng thực sự kh&ocirc;ng phải l&agrave; lựa chọn tốt nhất của ch&uacute;ng ta.</p> <h4 class="sub-section-heading" style="text-align: justify;">&Yacute; tưởng chung về việc sử dụng GPU</h4> <p style="text-align: justify;">B&agrave;i to&aacute;n ch&iacute;nh ở thời điểm n&agrave;y l&agrave; mạng v&agrave; dữ liệu của ch&uacute;ng ta đều phải tồn tại tr&ecirc;n GPU để thực hiện c&aacute;c ph&eacute;p t&iacute;nh bằng GPU v&agrave; điều n&agrave;y &aacute;p dụng cho bất kỳ ng&ocirc;n ngữ lập tr&igrave;nh hoặc framework n&agrave;o.</p> <p style="text-align: justify;"><img style="width: 100%;" src="http://tek4vn.2soft.top/public_files/gpu-vs-cpu-jpg-1" alt="gpu-vs-cpu" /></p> <p style="text-align: justify;">Như ch&uacute;ng ta sẽ thấy trong phần tiếp theo, điều n&agrave;y cũng đ&uacute;ng với CPU.&nbsp;GPU v&agrave; CPU l&agrave; c&aacute;c thiết bị t&iacute;nh to&aacute;n để t&iacute;nh to&aacute;n tr&ecirc;n dữ liệu v&agrave; v&igrave; vậy bất kỳ hai gi&aacute; trị n&agrave;o đang được sử dụng trực tiếp với nhau trong một ph&eacute;p t&iacute;nh, phải tồn tại tr&ecirc;n c&ugrave;ng một thiết bị.</p> <h3 class="section-heading" style="text-align: justify;">T&iacute;nh to&aacute;n tensor của PyTorch tr&ecirc;n GPU</h3> <p style="text-align: justify;">H&atilde;y đi s&acirc;u hơn bằng c&aacute;ch chứng minh một số t&iacute;nh to&aacute;n tensor.</p> <p style="text-align: justify;">Ch&uacute;ng ta sẽ bắt đầu bằng c&aacute;ch tạo ra hai tensors:</p> <pre class="language-python"><code>t1 = torch.tensor([ [1,2], [3,4] ]) t2 = torch.tensor([ [5,6], [7,8] ])</code></pre> <p style="text-align: justify;">B&acirc;y giờ, ch&uacute;ng ta sẽ kiểm tra thiết bị n&agrave;o m&agrave; c&aacute;c tensors n&agrave;y được khởi chạy bằng c&aacute;ch kiểm tra thuộc t&iacute;nh device:</p> <pre class="language-python"><code>&gt; t1.device, t2.device (device(type='cpu'), device(type='cpu'))</code></pre> <p style="text-align: justify;">Như ch&uacute;ng ta mong đợi, thực sự cả hai tensor đều nằm tr&ecirc;n c&ugrave;ng một thiết bị, đ&oacute; l&agrave; CPU.&nbsp;H&atilde;y di chuyển tensor <em>t1</em> đầu ti&ecirc;n đến GPU.</p> <pre class="language-python"><code>&gt; t1 = t1.to('cuda') &gt; t1.device device(type='cuda', index=0)</code></pre> <p style="text-align: justify;">Ch&uacute;ng ta c&oacute; thể thấy rằng thiết bị của tensor n&agrave;y đ&atilde; được thay đổi th&agrave;nh cuda, l&agrave; GPU.&nbsp;Lưu &yacute; việc sử dụng phương thức to () ở đ&acirc;y.&nbsp;Thay v&igrave; gọi một phương thức cụ thể để di chuyển đến một thiết bị, ch&uacute;ng ta gọi phương thức tương tự v&agrave; truyền một đối số chỉ định thiết bị.&nbsp;Sử dụng phương thức <em>to()</em> l&agrave; c&aacute;ch ưu ti&ecirc;n để di chuyển dữ liệu đến v&agrave; đi từ c&aacute;c thiết bị.</p> <p style="text-align: justify;">Ngo&agrave;i ra, h&atilde;y lưu &yacute; việc ph&acirc;n c&ocirc;ng lại.&nbsp;Hoạt động kh&ocirc;ng đ&uacute;ng vị tr&iacute;, v&agrave; do đ&oacute;, cần phải chỉ định lại.</p> <p style="text-align: justify;">H&atilde;y thử một th&iacute; nghiệm. H&atilde;y&nbsp;kiểm tra những g&igrave; ch&uacute;ng ta đ&atilde; thảo luận trước đ&oacute; bằng c&aacute;ch cố gắng thực hiện một ph&eacute;p t&iacute;nh tr&ecirc;n hai tensor n&agrave;y, <em>t1</em> v&agrave; <em>t2,</em> m&agrave; ch&uacute;ng ta biết l&agrave; tr&ecirc;n c&aacute;c thiết bị kh&aacute;c nhau.</p> <pre class="language-python"><code>try: t1 + t2 except Exception as e: print(e) expected device cuda:0 but got device cpu</code></pre> <p style="text-align: justify;">Bằng c&aacute;ch đảo ngược thứ tự của hoạt động, ch&uacute;ng ta c&oacute; thể thấy rằng lỗi cũng thay đổi:</p> <pre class="language-python"><code>try: t2 + t1 except Exception as e: print(e) expected device cpu but got device cuda:0</code></pre> <p style="text-align: justify;">Cả hai lỗi n&agrave;y đều cho ch&uacute;ng ta biết rằng ph&eacute;p to&aacute;n cộng nhị ph&acirc;n mong đợi đối số thứ hai c&oacute; c&ugrave;ng v&ugrave;ng nhớ với đối số đầu ti&ecirc;n.&nbsp;Hiểu &yacute; nghĩa của lỗi n&agrave;y c&oacute; thể hữu &iacute;ch khi gỡ lỗi c&aacute;c loại thiết bị kh&ocirc;ng khớp n&agrave;y.</p> <p style="text-align: justify;">Cuối c&ugrave;ng, để ho&agrave;n th&agrave;nh, h&atilde;y di chuyển tensor thứ hai sang thiết bị cuda để xem hoạt động th&agrave;nh c&ocirc;ng.</p> <pre class="language-python"><code>&gt; t2 = t2.to('cuda') &gt; t1 + t2 tensor([[ 6, 8], [10, 12]], device='cuda:0')</code></pre> <h3 class="section-heading" style="text-align: justify;">T&iacute;nh to&aacute;n PyTorch <em>nn.Module</em> tr&ecirc;n GPU</h3> <p style="text-align: justify;">Ch&uacute;ng ta vừa thấy c&aacute;ch c&aacute;c tensor c&oacute; thể được di chuyển đến v&agrave; đi từ CPU v&agrave; GPU.&nbsp;B&acirc;y giờ, h&atilde;y xem điều n&agrave;y được thực hiện như thế n&agrave;o với c&aacute;c instances PyTorch nn.Module.</p> <p style="text-align: justify;">Ch&uacute;ng ta đặt mạng tr&ecirc;n một thiết bị bằng c&aacute;ch di chuyển c&aacute;c th&ocirc;ng số của mạng đến thiết bị đ&oacute;.&nbsp;H&atilde;y tạo một mạng v&agrave; xem &yacute; nghĩa.</p> <pre class="language-python"><code>network = Network()</code></pre> <p style="text-align: justify;">B&acirc;y giờ, h&atilde;y xem c&aacute;c th&ocirc;ng số của mạng:</p> <pre class="language-python"><code>for name, param in network.named_parameters(): print(name, '\t\t', param.shape) conv1.weight torch.Size([6, 1, 5, 5]) conv1.bias torch.Size([6]) conv2.weight torch.Size([12, 6, 5, 5]) conv2.bias torch.Size([12]) fc1.weight torch.Size([120, 192]) fc1.bias torch.Size([120]) fc2.weight torch.Size([60, 120]) fc2.bias torch.Size([60]) out.weight torch.Size([10, 60]) out.bias torch.Size([10]) </code></pre> <p style="text-align: justify;">Ở đ&acirc;y, ch&uacute;ng t&ocirc;i đ&atilde; tạo một mạng PyTorch v&agrave; ch&uacute;ng t&ocirc;i đ&atilde; lặp lại c&aacute;c th&ocirc;ng số của mạng.&nbsp;Như ch&uacute;ng ta thấy, c&aacute;c tham số của mạng l&agrave; trọng số v&agrave; độ lệch b&ecirc;n trong mạng.</p> <p style="text-align: justify;">N&oacute;i c&aacute;ch kh&aacute;c, đ&acirc;y chỉ đơn giản l&agrave; những tensors tr&ecirc;n một thiết bị như ch&uacute;ng ta đ&atilde; thấy.&nbsp;H&atilde;y x&aacute;c minh điều n&agrave;y</p> <pre class="language-python"><code>for n, p in network.named_parameters(): print(p.device, '', n) cpu conv1.weight cpu conv1.bias cpu conv2.weight cpu conv2.bias cpu fc1.weight cpu fc1.bias cpu fc2.weight cpu fc2.bias cpu out.weight cpu out.bias</code></pre> <p style="text-align: justify;">Điều n&agrave;y cho ch&uacute;ng ta thấy rằng tất cả c&aacute;c tham số b&ecirc;n trong mạng, theo mặc định, được khởi tạo tr&ecirc;n CPU.</p> <p style="text-align: justify;">Một điều quan trọng cần lưu &yacute; l&agrave; n&oacute; giải th&iacute;ch l&yacute; do tại sao c&aacute;c instances nn.Module như mạng kh&ocirc;ng thực sự c&oacute; thiết bị.&nbsp;N&oacute; kh&ocirc;ng phải l&agrave; mạng tồn tại tr&ecirc;n một thiết bị, m&agrave; l&agrave; c&aacute;c yếu tố b&ecirc;n trong mạng tồn tại tr&ecirc;n một thiết bị.</p> <p style="text-align: justify;">H&atilde;y xem điều g&igrave; sẽ xảy ra khi ch&uacute;ng ta y&ecirc;u cầu một mạng được chuyển&nbsp; <em>to()</em> GPU:</p> <pre class="language-python"><code>network.to('cuda') Network( (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1)) (conv2): Conv2d(6, 12, kernel_size=(5, 5), stride=(1, 1)) (fc1): Linear(in_features=192, out_features=120, bias=True) (fc2): Linear(in_features=120, out_features=60, bias=True) (out): Linear(in_features=60, out_features=10, bias=True) )</code></pre> <p style="text-align: justify;">Lưu &yacute; ở đ&acirc;y rằng kh&ocirc;ng cần phải chỉ định lại.&nbsp;Điều n&agrave;y l&agrave; do hoạt động được thực hiện trong phạm vi li&ecirc;n quan đến network instance.&nbsp;Tuy nhi&ecirc;n, thao t&aacute;c n&agrave;y c&oacute; thể được sử dụng như một thao t&aacute;c g&aacute;n lại.&nbsp;Điều n&agrave;y được ưu ti&ecirc;n cho sự nhất qu&aacute;n giữa c&aacute;c instance nn.Module v&agrave; c&aacute;c tensors PyTorch.</p> <p style="text-align: justify;">Ở đ&acirc;y, ch&uacute;ng ta c&oacute; thể thấy rằng b&acirc;y giờ, tất cả c&aacute;c th&ocirc;ng số mạng đều c&oacute; một thiết bị l&agrave; cuda:</p> <pre class="language-python"><code>for n, p in network.named_parameters(): print(p.device, '', n) cuda:0 conv1.weight cuda:0 conv1.bias cuda:0 conv2.weight cuda:0 conv2.bias cuda:0 fc1.weight cuda:0 fc1.bias cuda:0 fc2.weight cuda:0 fc2.bias cuda:0 out.weight cuda:0 out.bias</code></pre> <h4 class="sub-section-heading" style="text-align: justify;">Chuyển một mẫu v&agrave;o mạng</h4> <p style="text-align: justify;">Chuyển một mẫu l&ecirc;n mạng như sau.</p> <pre class="language-python"><code>sample = torch.ones(1,1,28,28) sample.shape torch.Size([1, 1, 28, 28])</code></pre> <p style="text-align: justify;">Điều n&agrave;y cung cấp cho ch&uacute;ng ta một tensor mẫu m&agrave; ch&uacute;ng ta c&oacute; thể truyền như sau:</p> <pre class="language-python"><code>try: network(sample) except Exception as e: print(e) Expected object of device type cuda but got device type cpu for argument #1 'self' in call to _thnn_conv2d_forward</code></pre> <p style="text-align: justify;">V&igrave; mạng của ch&uacute;ng ta đang nằm tr&ecirc;n GPU v&agrave; mẫu mới được tạo n&agrave;y nằm tr&ecirc;n CPU theo mặc định n&ecirc;n ch&uacute;ng ta đang gặp lỗi.&nbsp;Lỗi cho ch&uacute;ng ta biết rằng tensor CPU được mong đợi l&agrave; tensor GPU khi gọi phương thức chuyển tiếp của layer chập đầu ti&ecirc;n.&nbsp;Đ&acirc;y ch&iacute;nh x&aacute;c l&agrave; những g&igrave; ch&uacute;ng ta đ&atilde; thấy trước đ&acirc;y khi th&ecirc;m trực tiếp hai tensor.</p> <p style="text-align: justify;">Ch&uacute;ng ta c&oacute; thể khắc phục sự cố n&agrave;y bằng c&aacute;ch gửi mẫu của ch&uacute;ng ta tới GPU như sau:</p> <pre class="language-python"><code>try: pred = network(sample.to('cuda')) print(pred) except Exception as e: print(e) tensor([[-0.0685, 0.0201, 0.1223, 0.1075, 0.0810, 0.0686, -0.0336, -0.1088, -0.0995, 0.0639]] , device='cuda:0' , grad_fn= )</code></pre> <p style="text-align: justify;">Cuối c&ugrave;ng, mọi thứ hoạt động như mong đợi v&agrave; ch&uacute;ng ta nhận được dự đo&aacute;n.</p> <h4 class="sub-section-heading" style="text-align: justify;">Writing Device Agnostic PyTorch Code</h4> <p style="text-align: justify;">Trước khi kết th&uacute;c, ch&uacute;ng ta cần n&oacute;i về việc writing device agnostic code.&nbsp;Thuật ngữ <em>device agnostic</em> n&agrave;y c&oacute; nghĩa l&agrave; code của ch&uacute;ng ta kh&ocirc;ng phụ thuộc v&agrave;o&nbsp;underlying device.&nbsp;Bạn c&oacute; thể bắt gặp thuật ngữ n&agrave;y khi đọc t&agrave;i liệu PyTorch.</p> <p style="text-align: justify;">V&iacute; dụ: giả sử ch&uacute;ng ta viết code sử dụng phương thức <em>cuda()</em> ở khắp mọi nơi v&agrave; sau đ&oacute;, ch&uacute;ng ta cung cấp code cho người d&ugrave;ng kh&ocirc;ng c&oacute; GPU.&nbsp;Điều n&agrave;y sẽ kh&ocirc;ng hoạt động.</p> <p style="text-align: justify;">H&atilde;y nhớ trước đ&oacute; khi ch&uacute;ng ta thấy c&aacute;c phương thức <em>cuda()</em> v&agrave; <em>cpu()?</em></p> <p style="text-align: justify;">Một trong những l&yacute; do m&agrave; phương thức <em>to()</em> được ưa th&iacute;ch hơn, l&agrave; v&igrave; phương thức <em>to()</em> được tham số h&oacute;a v&agrave; điều n&agrave;y l&agrave;m cho việc thay đổi thiết bị ch&uacute;ng ta đang chọn dễ d&agrave;ng hơn, tức l&agrave; n&oacute; linh hoạt!</p> <p style="text-align: justify;">V&iacute; dụ: người d&ugrave;ng c&oacute; thể chuyển cpu hoặc cuda l&agrave;m đối số cho một chương tr&igrave;nh Deep learning v&agrave; điều n&agrave;y sẽ cho ph&eacute;p chương tr&igrave;nh "device agnostic".</p> <p style="text-align: justify;">Cho ph&eacute;p người d&ugrave;ng chương tr&igrave;nh chuyển đối h&agrave;nh vi của chương tr&igrave;nh c&oacute; lẽ l&agrave; c&aacute;ch tốt nhất để biến một chương tr&igrave;nh trở th&agrave;nh&nbsp;"device agnostic".&nbsp;Tuy nhi&ecirc;n, ch&uacute;ng ta cũng c&oacute; thể sử dụng PyTorch để kiểm tra GPU được hỗ trợ v&agrave; thiết lập thiết bị của m&igrave;nh theo c&aacute;ch sau.</p> <pre class="language-python"><code>torch.cuda.is_available() True</code></pre> <h3 class="section-heading" style="text-align: justify;">Kiểm tra hiệu suất đ&agrave;o tạo GPU PyTorch</h3> <p style="text-align: justify;">B&acirc;y giờ ch&uacute;ng ta h&atilde;y xem c&aacute;ch th&ecirc;m việc sử dụng GPU v&agrave;o v&ograve;ng huấn luyện.&nbsp;Ch&uacute;ng ta sẽ thực hiện việc bổ sung n&agrave;y với code m&agrave; ch&uacute;ng ta đ&atilde; ph&aacute;t triển cho đến nay trong loạt b&agrave;i.</p> <p style="text-align: justify;">Điều n&agrave;y sẽ cho ph&eacute;p ch&uacute;ng t&ocirc;i dễ d&agrave;ng so s&aacute;nh thời gian, CPU v&agrave; GPU.</p> <h4 class="sub-section-heading" style="text-align: justify;">Cấu tr&uacute;c lại lớp <em>RunManager</em></h4> <p style="text-align: justify;">Trước khi cập nhật v&ograve;ng lặp huấn luyệ, ch&uacute;ng ta cần cập nhật lớp <em>RunManager.&nbsp;</em>B&ecirc;n trong phương thức <em>begin_run(),</em> ch&uacute;ng ta cần sửa đổi <em>device</em> của tensor <em>images</em> được chuyển cho phương thức <em>add_graph.</em></p> <p style="text-align: justify;">N&oacute; sẽ giống như thế n&agrave;y:</p> <pre class="language-python"><code>def begin_run(self, run, network, loader): self.run_start_time = time.time() self.run_params = run self.run_count += 1 self.network = network self.loader = loader self.tb = SummaryWriter(comment=f'-{run}') images, labels = next(iter(self.loader)) grid = torchvision.utils.make_grid(images) self.tb.add_image('images', grid) self.tb.add_graph( self.network ,images.to(getattr(run, 'device', 'cpu')) )</code></pre> <p style="text-align: justify;">Ở đ&acirc;y, ch&uacute;ng ta đang sử dụng h&agrave;m <em>getattr()</em> được t&iacute;ch hợp sẵn để lấy gi&aacute; trị của <em>device</em> tr&ecirc;n đối tượng <em>run.&nbsp;</em>Nếu đối tượng <em>run</em> kh&ocirc;ng c&oacute; thiết bị, th&igrave; cpu được trả về.&nbsp;N&oacute; sẽ vẫn hoạt động nếu ch&uacute;ng t&ocirc;i kh&ocirc;ng chỉ định một <em>device</em> để <em>run.</em></p> <p style="text-align: justify;">Lưu &yacute; rằng mạng kh&ocirc;ng cần phải được chuyển đến một device v&igrave; device đ&oacute; đ&atilde; được thiết lập trước khi được chuyển v&agrave;o.&nbsp;Tuy nhi&ecirc;n, tensor h&igrave;nh ảnh thu được từ loader.</p> <h4 class="sub-section-heading" style="text-align: justify;">T&aacute;i cấu tr&uacute;c lại v&ograve;ng lặp đ&agrave;o tạo</h4> <p style="text-align: justify;">Ch&uacute;ng ta sẽ đặt c&aacute;c th&ocirc;ng số cấu h&igrave;nh của m&igrave;nh để c&oacute; một thiết bị.&nbsp;Hai t&ugrave;y chọn hợp l&yacute; ở đ&acirc;y l&agrave; <em>cuda</em> v&agrave; <em>cpu.</em></p> <pre class="language-python"><code>params = OrderedDict( lr = [.01] ,batch_size = [1000, 10000, 20000] , num_workers = [0, 1] , device = ['cuda', 'cpu'] )</code></pre> <p style="text-align: justify;">Ở đầu phần <em>run,</em> ch&uacute;ng ta sẽ tạo một device được truyền xung quanh trong v&ograve;ng chạy v&agrave; b&ecirc;n trong v&ograve;ng huấn luyện.</p> <pre class="language-python"><code>device = torch.device(run.device)</code></pre> <p style="text-align: justify;">Nơi đầu ti&ecirc;n ch&uacute;ng ta sử dụng device n&agrave;y l&agrave; khi khởi tạo mạng của m&igrave;nh.</p> <pre class="language-python"><code>network = Network().to(device)</code></pre> <p style="text-align: justify;">Điều n&agrave;y sẽ đảm bảo rằng mạng được chuyển đến thiết bị th&iacute;ch hợp.&nbsp;Cuối c&ugrave;ng, ch&uacute;ng ta sẽ cập nhật tensor&nbsp;<em>images</em> v&agrave; <em>labels</em> của m&igrave;nh bằng c&aacute;ch giải n&eacute;n ch&uacute;ng ri&ecirc;ng biệt v&agrave; gửi ch&uacute;ng đến thiết bị như sau:</p> <pre class="language-python"><code>images = batch[0].to(device) labels = batch[1].to(device)</code></pre> <p style="text-align: justify;">Đ&oacute; l&agrave; tất cả những g&igrave; cần l&agrave;m, ch&uacute;ng ta đ&atilde; sẵn s&agrave;ng chạy đoạn code n&agrave;y v&agrave; xem kết quả.</p> <div class="table-responsive" style="text-align: justify;"> <table class="table table-sm table-hover" style="width: 96.3675%;"> <thead> <tr> <th style="width: 3.35693%;">run</th> <th style="width: 5.94686%;">epoch</th> <th style="width: 3.82081%;">loss</th> <th style="width: 8.45337%;">accuracy</th> <th style="width: 14.9598%;">epoch duration</th> <th style="width: 12.3678%;">run duration</th> <th style="width: 3.82081%;">lr</th> <th style="width: 9.94872%;">batch_size</th> <th style="width: 13.0676%;">num_workers</th> <th style="width: 6.26628%;">device</th> </tr> </thead> <tbody> <tr> <td style="width: 3.35693%;">1</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">1.08</td> <td style="width: 8.45337%;">0.59</td> <td style="width: 14.9598%;">7.50</td> <td style="width: 12.3678%;">9.67</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">1000</td> <td style="width: 13.0676%;">0</td> <td style="width: 6.26628%;">cuda</td> </tr> <tr> <td style="width: 3.35693%;">2</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">1.04</td> <td style="width: 8.45337%;">0.60</td> <td style="width: 14.9598%;">20.83</td> <td style="width: 12.3678%;">21.88</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">1000</td> <td style="width: 13.0676%;">0</td> <td style="width: 6.26628%;">cpu</td> </tr> <tr> <td style="width: 3.35693%;">3</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">1.03</td> <td style="width: 8.45337%;">0.61</td> <td style="width: 14.9598%;">7.84</td> <td style="width: 12.3678%;">10.69</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">1000</td> <td style="width: 13.0676%;">1</td> <td style="width: 6.26628%;">cuda</td> </tr> <tr> <td style="width: 3.35693%;">4</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">1.02</td> <td style="width: 8.45337%;">0.61</td> <td style="width: 14.9598%;">16.49</td> <td style="width: 12.3678%;">19.21</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">1000</td> <td style="width: 13.0676%;">1</td> <td style="width: 6.26628%;">cpu</td> </tr> <tr> <td style="width: 3.35693%;">5</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">2.10</td> <td style="width: 8.45337%;">0.24</td> <td style="width: 14.9598%;">7.69</td> <td style="width: 12.3678%;">12.30</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">10000</td> <td style="width: 13.0676%;">0</td> <td style="width: 6.26628%;">cuda</td> </tr> <tr> <td style="width: 3.35693%;">6</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">2.09</td> <td style="width: 8.45337%;">0.24</td> <td style="width: 14.9598%;">19.89</td> <td style="width: 12.3678%;">28.85</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">10000</td> <td style="width: 13.0676%;">0</td> <td style="width: 6.26628%;">cpu</td> </tr> <tr> <td style="width: 3.35693%;">7</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">2.11</td> <td style="width: 8.45337%;">0.25</td> <td style="width: 14.9598%;">8.05</td> <td style="width: 12.3678%;">15.21</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">10000</td> <td style="width: 13.0676%;">1</td> <td style="width: 6.26628%;">cuda</td> </tr> <tr> <td style="width: 3.35693%;">8</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">2.17</td> <td style="width: 8.45337%;">0.20</td> <td style="width: 14.9598%;">17.09</td> <td style="width: 12.3678%;">28.68</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">10000</td> <td style="width: 13.0676%;">1</td> <td style="width: 6.26628%;">cpu</td> </tr> <tr> <td style="width: 3.35693%;">9</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">2.28</td> <td style="width: 8.45337%;">0.21</td> <td style="width: 14.9598%;">9.65</td> <td style="width: 12.3678%;">17.56</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">20000</td> <td style="width: 13.0676%;">0</td> <td style="width: 6.26628%;">cuda</td> </tr> <tr> <td style="width: 3.35693%;">10</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">2.29</td> <td style="width: 8.45337%;">0.10</td> <td style="width: 14.9598%;">19.63</td> <td style="width: 12.3678%;">36.19</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">20000</td> <td style="width: 13.0676%;">0</td> <td style="width: 6.26628%;">cpu</td> </tr> <tr> <td style="width: 3.35693%;">11</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">2.29</td> <td style="width: 8.45337%;">0.14</td> <td style="width: 14.9598%;">8.18</td> <td style="width: 12.3678%;">19.59</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">20000</td> <td style="width: 13.0676%;">1</td> <td style="width: 6.26628%;">cuda</td> </tr> <tr> <td style="width: 3.35693%;">12</td> <td style="width: 5.94686%;">1</td> <td style="width: 3.82081%;">2.29</td> <td style="width: 8.45337%;">0.12</td> <td style="width: 14.9598%;">17.68</td> <td style="width: 12.3678%;">38.08</td> <td style="width: 3.82081%;">0.01</td> <td style="width: 9.94872%;">20000</td> <td style="width: 13.0676%;">1</td> <td style="width: 6.26628%;">cpu</td> </tr> </tbody> </table> </div> <p style="text-align: justify;">Ở đ&acirc;y, ch&uacute;ng ta c&oacute; thể thấy rằng thiết bị <em>cuda</em> đ&atilde; vượt trội hơn đ&aacute;ng kể so với <em>CPU</em> từ 2x đến 3x.&nbsp;Kết quả c&oacute; thể thay đổi.</p> <p style="text-align: right;"><a href="https://tek4.vn/chuan-hoa-du-lieu-lap-trinh-neural-network-voi-pytorch/" target="_blank" rel="noopener">B&agrave;i viết tiếp theo: Chuẩn H&oacute;a Dữ Liệu</a></p> <hr /> <p style="text-align: center;"><em><strong>Fanpage Facebook:</strong>&nbsp;<a href="https://www.facebook.com/tek4.vn/">TEK4.VN</a></em>&nbsp;</p> <p style="text-align: center;"><em><strong>Tham gia cộng đồng để chia sẻ, trao đổi v&agrave; thảo luận:</strong>&nbsp;<a href="https://www.facebook.com/groups/tek4.vn/">TEK4.VN - Học Lập Tr&igrave;nh Miễn Ph&iacute;</a></em></p>