tek4

Thử Nghiệm Siêu Tham Số Bằng TensorBoard

by - September. 21, 2021
Kiến thức
Machine Learning
Python
<p style="text-align: justify;"><em><span style="font-weight: 400;">Ch&agrave;o mừng c&aacute;c bạn quay trở lại với loạt b&agrave;i về </span><a href="https://tek4.vn/lap-trinh-neural-network-voi-pytorch-deep-learning-voi-pytorch/"><strong>Lập Tr&igrave;nh Neural Network Với Pytorch</strong></a><span style="font-weight: 400;">. </span><span style="font-weight: 400;">Trong b&agrave;i n&agrave;y, ch&uacute;ng ta sẽ xem c&aacute;ch c&oacute; thể sử dụng TensorBoard để nhanh ch&oacute;ng thử nghiệm với c&aacute;c si&ecirc;u tham số huấn luyện kh&aacute;c nhau để hiểu s&acirc;u hơn về mạng neural của ch&uacute;ng ta. Bắt đầu th&ocirc;i!</span></em></p> <p style="text-align: justify;"><img style="width: 100%;" src="http://tek4vn.2soft.top/public_files/sieu-tham-so-png-1" alt="Si&ecirc;u Tham Số" /></p> <p style="text-align: center;"><a href="https://tek4.vn/tensorboard-voi-pytorch-lap-trinh-neural-network-voi-pytorch/" target="_blank" rel="noopener">Xem th&ecirc;m b&agrave;i viết trước:&nbsp;TensorBoard Với PyTorch</a></p> <h3 style="text-align: justify;"><strong>Tiến độ của dự &aacute;n</strong></h3> <ol style="text-align: justify;"> <li style="list-style-type: none;"> <ol> <li style="font-weight: 400;"><span style="font-weight: 400;">Chuẩn bị dữ liệu</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">X&acirc;y dựng m&ocirc; h&igrave;nh</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">Đ&agrave;o tạo m&ocirc; h&igrave;nh</span></li> <li style="font-weight: 400;"><strong>Ph&acirc;n t&iacute;ch kết quả của m&ocirc; h&igrave;nh</strong></li> </ol> </li> </ol> <p style="text-align: justify;"><span style="font-weight: 400;">Tại thời điểm n&agrave;y của loạt b&agrave;i, ch&uacute;ng ta đ&atilde; biết c&aacute;ch x&acirc;y dựng v&agrave; huấn luyện CNN với PyTorch. Trong b&agrave;i trước, ch&uacute;ng ta đ&atilde; t&igrave;m hiểu về c&aacute;ch sử dụng TensorBoard với PyTorch v&agrave; cũng đ&atilde; xem lại qu&aacute; tr&igrave;nh huấn luyện.&nbsp;&nbsp;</span></p> <p style="text-align: justify;"><span style="font-weight: 400;">B&agrave;i n&agrave;y được coi l&agrave; b&agrave;i cuối c&ugrave;ng của giai đoạn 4 l&agrave; ph&acirc;n t&iacute;ch kết quả m&ocirc; h&igrave;nh. Những g&igrave; ch&uacute;ng ta sẽ l&agrave;m trong b&agrave;i n&agrave;y l&agrave; thử nghiệm với c&aacute;c gi&aacute; trị si&ecirc;u tham số.</span></p> <h3 style="text-align: justify;"><strong>Thử nghiệm si&ecirc;u tham số bằng TensorBoard</strong></h3> <p style="text-align: justify;"><span style="font-weight: 400;">Phần hay nhất về TensorBoard l&agrave; khả năng theo d&otilde;i si&ecirc;u tham số của ch&uacute;ng ta theo thời gian v&agrave; qua c&aacute;c lần chạy. </span></p> <pre><code>Thay đổi si&ecirc;u tham số v&agrave; so s&aacute;nh kết quả.</code></pre> <p style="text-align: justify;"><span style="font-weight: 400;">Nếu kh&ocirc;ng c&oacute; TensorBoard, qu&aacute; tr&igrave;nh n&agrave;y trở n&ecirc;n cồng kềnh hơn.</span></p> <h3 style="text-align: justify;"><strong>Đặt t&ecirc;n qu&aacute; tr&igrave;nh huấn luyện cho TensorBoard</strong></h3> <p style="text-align: justify;"><span style="font-weight: 400;">Để tận dụng khả năng so s&aacute;nh TensorBoard, ch&uacute;ng ta cần thực hiện nhiều lần chạy v&agrave; đặt t&ecirc;n cho mỗi lần chạy theo c&aacute;ch m&agrave; ch&uacute;ng ta c&oacute; thể x&aacute;c định n&oacute; duy nhất.</span></p> <p style="text-align: justify;"><span style="font-weight: 400;">Với </span><em><span style="font-weight: 400;">SummaryWriter</span></em><span style="font-weight: 400;"> của PyTorch, qu&aacute; tr&igrave;nh chạy bắt đầu khi </span><span style="font-weight: 400;">writer object instance </span><span style="font-weight: 400;">được tạo v&agrave; kết th&uacute;c khi </span><span style="font-weight: 400;">writer instance</span><span style="font-weight: 400;"> bị đ&oacute;ng hoặc ra khỏi phạm vi.</span></p> <p style="text-align: justify;"><span style="font-weight: 400;">Để x&aacute;c định duy nhất mỗi lần chạy, ch&uacute;ng ta c&oacute; thể đặt trực tiếp t&ecirc;n tệp của lần chạy đ&oacute; hoặc chuyển một chuỗi ch&uacute; th&iacute;ch đến h&agrave;m tạo sẽ được nối v&agrave;o t&ecirc;n tệp được tạo tự động.</span></p> <p style="text-align: justify;"><span style="font-weight: 400;">Tại thời điểm tạo b&agrave;i viết n&agrave;y, t&ecirc;n của lần chạy được chứa b&ecirc;n trong </span><em><span style="font-weight: 400;">SummaryWriter</span></em><span style="font-weight: 400;"> trong một thuộc t&iacute;nh được gọi l&agrave; log_dir. N&oacute; được tạo ra như thế n&agrave;y:</span></p> <pre class="language-python"><code># PyTorch version 1.1.0 SummaryWriter class if not log_dir: import socket from datetime import datetime current_time = datetime.now().strftime('%b%d_%H-%M-%S') log_dir = os.path.join( 'runs', current_time + '_' + socket.gethostname() + comment ) self.log_dir = log_dir</code></pre> <p style="text-align: justify;"><span style="font-weight: 400;">Ở đ&acirc;y, ch&uacute;ng ta c&oacute; thể thấy rằng thuộc t&iacute;nh </span><em><span style="font-weight: 400;">log_dir</span></em><span style="font-weight: 400;">, tương ứng với vị tr&iacute; tr&ecirc;n ổ đĩa v&agrave; t&ecirc;n của lần chạy được đặt th&agrave;nh </span><em><span style="font-weight: 400;">running + time + host + comment</span></em><span style="font-weight: 400;">. Tất nhi&ecirc;n, điều n&agrave;y giả sử rằng tham số </span><em><span style="font-weight: 400;">log_dir</span></em><span style="font-weight: 400;"> kh&ocirc;ng c&oacute; gi&aacute; trị được truyền v&agrave;o.&nbsp;</span></p> <h4 class="sub-section-heading" style="text-align: justify;">Chọn t&ecirc;n cho lần chạy</h4> <p style="text-align: justify;">Một c&aacute;ch để đặt t&ecirc;n cho c&aacute;c lần chạy l&agrave; th&ecirc;m t&ecirc;n v&agrave; gi&aacute; trị tham số l&agrave;m comment cho lần chạy.&nbsp;&nbsp;Điều n&agrave;y sẽ cho ph&eacute;p ch&uacute;ng ta xem mỗi gi&aacute; trị tham số xếp chồng l&ecirc;n nhau như thế n&agrave;o với c&aacute;c gi&aacute; trị kh&aacute;c sau n&agrave;y khi ch&uacute;ng ta xem x&eacute;t c&aacute;c lần chạy b&ecirc;n trong TensorBoard.</p> <p style="text-align: justify;">Ch&uacute;ng ta sẽ thấy rằng đ&acirc;y l&agrave; c&aacute;ch ch&uacute;ng ta thiết lập comment sau:</p> <pre class="language-python"><code>tb = SummaryWriter(comment=f' batch_size={batch_size} lr={lr}') [Tb = SummaryWriter (comment = f 'batch_size = {batch_size} lr = {lr}')]</code></pre> <p style="text-align: justify;">TensorBoard cũng c&oacute; khả năng truy vấn, v&igrave; vậy ch&uacute;ng ta c&oacute; thể dễ d&agrave;ng c&ocirc; lập c&aacute;c gi&aacute; trị tham số th&ocirc;ng qua c&aacute;c truy vấn.</p> <p style="text-align: justify;">V&iacute; dụ, h&atilde;y tưởng tượng truy vấn SQL n&agrave;y:</p> <pre class="language-python"><code>SELECT * FROM TBL_RUNS WHERE lr = 0.01</code></pre> <p style="text-align: justify;">Nếu kh&ocirc;ng c&oacute; SQL, về cơ bản đ&acirc;y l&agrave; những g&igrave; ch&uacute;ng ta c&oacute; thể l&agrave;m b&ecirc;n trong TensorBoard.</p> <h3 class="section-heading" style="text-align: justify;">Tạo c&aacute;c biến cho si&ecirc;u tham số</h3> <p style="text-align: justify;">Để l&agrave;m cho thử nghiệm dễ d&agrave;ng, ch&uacute;ng ta sẽ lấy ra c&aacute;c gi&aacute; trị được hard-coded v&agrave; biến ch&uacute;ng th&agrave;nh c&aacute;c biến.</p> <p style="text-align: justify;">Đ&acirc;y l&agrave; c&aacute;ch&nbsp;hard-coded:</p> <pre class="language-python"><code>network = Network() train_loader = torch.utils.data.DataLoader( train_set, batch_size=100 ) optimizer = optim.Adam( network.parameters(), lr=0.01 )</code></pre> <p style="text-align: justify;">Ch&uacute; &yacute; c&aacute;ch c&aacute;c gi&aacute; trị tham số <em>batch_size</em> v&agrave; <em>lr</em> được&nbsp;hard-coded.</p> <p style="text-align: justify;">Đ&acirc;y l&agrave; những g&igrave; ch&uacute;ng ta thay đổi:</p> <pre class="language-python"><code>batch_size = 100 lr = 0.01 network = Network() train_loader = torch.utils.data.DataLoader( train_set, batch_size=batch_size ) optimizer = optim.Adam( network.parameters(), lr=lr )</code></pre> <p style="text-align: justify;">Điều n&agrave;y sẽ cho ph&eacute;p ch&uacute;ng ta thay đổi c&aacute;c gi&aacute; trị ở một nơi duy nhất v&agrave; để ch&uacute;ng truyền th&ocirc;ng qua code của ch&uacute;ng ta.</p> <p style="text-align: justify;">B&acirc;y giờ, ch&uacute;ng ta sẽ tạo gi&aacute; trị cho tham số comment của m&igrave;nh bằng c&aacute;ch sử dụng c&aacute;c biến như sau:</p> <pre class="language-python"><code>tb = SummaryWriter(comment=f' batch_size={batch_size} lr={lr}')</code></pre> <p style="text-align: justify;">Với thiết lập n&agrave;y, ch&uacute;ng ta c&oacute; thể thay đổi gi&aacute; trị của c&aacute;c si&ecirc;u tham số v&agrave; c&aacute;c lần chạy sẽ được tự động theo d&otilde;i v&agrave; nhận dạng trong TensorBoard.</p> <h3 class="section-heading" style="text-align: justify;">T&iacute;nh to&aacute;n loss với c&aacute;c batch size kh&aacute;c nhau</h3> <p style="text-align: justify;">Thay v&igrave; chỉ t&iacute;nh tổng mất m&aacute;t được trả về bởi h&agrave;m mất m&aacute;t.&nbsp;Ch&uacute;ng ta sẽ điều chỉnh n&oacute; cho ph&ugrave; hợp với batch size.</p> <pre class="language-python"><code>total_loss += loss.item() * batch_size</code></pre> <p style="text-align: justify;">Tại sao l&agrave;m điều n&agrave;y?&nbsp;H&agrave;m cross_entropy loss sẽ t&iacute;nh trung b&igrave;nh c&aacute;c loss được tạo ra bởi batch v&agrave; sau đ&oacute; trả về loss trung b&igrave;nh.&nbsp;Đ&acirc;y l&agrave; l&yacute; do tại sao ch&uacute;ng ta cần t&iacute;nh đến batch size.</p> <p style="text-align: justify;">C&oacute; một tham số m&agrave; h&agrave;m <em>cross_entropy</em> chấp nhận được gọi l&agrave; <em>reduction</em> m&agrave; ch&uacute;ng ta cũng c&oacute; thể sử dụng.</p> <p style="text-align: justify;">Tham số reduction t&ugrave;y &yacute; chấp nhận một chuỗi l&agrave;m đối số.&nbsp;Tham số n&agrave;y chỉ định mức reduction &aacute;p dụng cho đầu ra của h&agrave;m mất m&aacute;t.</p> <ol style="text-align: justify;"> <li>'none' - sẽ kh&ocirc;ng &aacute;p dụng mức reduction n&agrave;o.</li> <li>'mean' - tổng của đầu ra sẽ được chia cho số phần tử trong đầu ra.</li> <li>'sum'&nbsp;- kết quả sẽ được t&iacute;nh tổng.</li> </ol> <p style="text-align: justify;">Lưu &yacute; rằng gi&aacute; trị mặc định l&agrave; <em>'mean'.</em>&nbsp;Đ&acirc;y l&agrave; l&yacute; do tại sao <em>loss.item () * batch_size</em> hoạt động.</p> <h3 class="section-heading" style="text-align: justify;">Thử nghiệm với c&aacute;c gi&aacute; trị si&ecirc;u tham số</h3> <p style="text-align: justify;">B&acirc;y giờ ch&uacute;ng ta c&oacute; thiết lập n&agrave;y, ch&uacute;ng ta c&oacute; thể l&agrave;m nhiều hơn nữa!</p> <p style="text-align: justify;">Tất cả những g&igrave; ch&uacute;ng ta cần l&agrave;m l&agrave; tạo một số danh s&aacute;ch v&agrave; một số v&ograve;ng lặp v&agrave; ch&uacute;ng ta c&oacute; thể chạy code sau đ&oacute; đợi tất cả c&aacute;c tổ hợp chạy.</p> <p style="text-align: justify;">Đ&acirc;y l&agrave; một v&iacute; dụ:</p> <h4 class="sub-section-heading" style="text-align: justify;">Danh s&aacute;ch tham số</h4> <pre class="language-python"><code>batch_size_list = [100, 1000, 10000] lr_list = [.01, .001, .0001, .00001]</code></pre> <h4 class="sub-section-heading" style="text-align: justify;">Nested Iteration</h4> <pre class="language-python"><code>for batch_size in batch_size_list: for lr in lr_list: network = Network() train_loader = torch.utils.data.DataLoader( train_set, batch_size=batch_size ) optimizer = optim.Adam( network.parameters(), lr=lr ) images, labels = next(iter(train_loader)) grid = torchvision.utils.make_grid(images) comment=f' batch_size={batch_size} lr={lr}' tb = SummaryWriter(comment=comment) tb.add_image('images', grid) tb.add_graph(network, images) for epoch in range(5): total_loss = 0 total_correct = 0 for batch in train_loader: images, labels = batch # Get Batch preds = network(images) # Pass Batch loss = F.cross_entropy(preds, labels) # Calculate Loss optimizer.zero_grad() # Zero Gradients loss.backward() # Calculate Gradients optimizer.step() # Update Weights total_loss += loss.item() * batch_size total_correct += get_num_correct(preds, labels) tb.add_scalar( 'Loss', total_loss, epoch ) tb.add_scalar( 'Number Correct', total_correct, epoch ) tb.add_scalar( 'Accuracy', total_correct / len(train_set), epoch ) for name, param in network.named_parameters(): tb.add_histogram(name, param, epoch) tb.add_histogram(f'{name}.grad', param.grad, epoch) print( "epoch", epoch ,"total_correct:", total_correct ,"loss:", total_loss ) tb.close()</code></pre> <p style="text-align: justify;">Khi code n&agrave;y ho&agrave;n th&agrave;nh, ch&uacute;ng ta chạy TensorBoard v&agrave; tất cả c&aacute;c lần chạy sẽ được hiển thị bằng đồ họa v&agrave; dễ d&agrave;ng so s&aacute;nh.</p> <pre class="language-python"><code>tensorboard --logdir runs</code></pre> <h4 class="sub-section-heading" style="text-align: justify;">Batch Size v&agrave; Training Set Size</h4> <p style="text-align: justify;">Khi training set size kh&ocirc;ng chia hết cho batch size, th&igrave; batch dữ liệu cuối c&ugrave;ng sẽ chứa &iacute;t mẫu hơn c&aacute;c batch kh&aacute;c.&nbsp;Một c&aacute;ch đơn giản để đối ph&oacute; với việc n&agrave;y l&agrave; bỏ batch cuối c&ugrave;ng.&nbsp;Lớp PyTorch <em>DataLoader</em> cung cấp cho ch&uacute;ng ta khả năng thực hiện điều n&agrave;y bằng c&aacute;ch đặt <em>drop_last = True</em>.&nbsp;Theo mặc định, gi&aacute; trị th&ocirc;ng số drop_last được đặt th&agrave;nh False.</p> <p style="text-align: justify;">H&atilde;y xem x&eacute;t một batch c&oacute; &iacute;t mẫu hơn batch size của ch&uacute;ng ta ảnh hưởng như thế n&agrave;o đến t&iacute;nh to&aacute;n <em>total_loss</em>&nbsp;trong đoạn code tr&ecirc;n.</p> <p style="text-align: justify;">Đối với mỗi batch, ch&uacute;ng ta đang sử dụng biến <em>batch_size</em> để cập nhật gi&aacute; trị <em>total_loss.&nbsp;</em>Ch&uacute;ng ta đang nh&acirc;n rộng gi&aacute; trị loss trung b&igrave;nh của c&aacute;c mẫu trong batch bằng gi&aacute; trị batch_size.&nbsp;Tuy nhi&ecirc;n, như ch&uacute;ng ta vừa thảo luận, đ&ocirc;i khi batch cuối c&ugrave;ng sẽ chứa &iacute;t mẫu hơn.&nbsp;Do đ&oacute;, việc chia tỷ lệ theo gi&aacute; trị batch_size được x&aacute;c định trước l&agrave; kh&ocirc;ng ch&iacute;nh x&aacute;c.</p> <p style="text-align: justify;">Code&nbsp;c&oacute; thể được cập nhật để ch&iacute;nh x&aacute;c hơn bằng c&aacute;ch truy cập động (dynamically) v&agrave;o số lượng mẫu cho mỗi batch.</p> <p style="text-align: justify;">Hiện tại, ch&uacute;ng ta c&oacute; những thứ sau:</p> <pre class="language-python"><code>total_loss += loss.item() * batch_size</code></pre> <p style="text-align: justify;">Sử dụng code được cập nhật b&ecirc;n dưới, ch&uacute;ng ta c&oacute; thể đạt được gi&aacute; trị total_loss ch&iacute;nh x&aacute;c hơn:</p> <pre class="language-python"><code>total_loss += loss.item() * images.shape[0]</code></pre> <p style="text-align: justify;">Lưu &yacute; rằng hai d&ograve;ng code n&agrave;y cung cấp cho ch&uacute;ng ta c&ugrave;ng một gi&aacute; trị total_loss khi training set size chia hết cho batch size.</p> <h3 class="section-heading" style="text-align: justify;">Th&ecirc;m network parameters &amp; gradients v&agrave;o TensorBoard</h3> <p style="text-align: justify;">Lưu &yacute; rằng trong b&agrave;i trước, ch&uacute;ng ta đ&atilde; th&ecirc;m c&aacute;c gi&aacute; trị sau v&agrave;o TensorBoard:</p> <ul style="text-align: justify;"> <li><span style="color: #ff00ff;">conv1.weight</span></li> <li><span style="color: #ff00ff;">conv1.bias</span></li> <li><span style="color: #ff00ff;">conv1.weight.grad</span></li> </ul> <p style="text-align: justify;">Ch&uacute;ng ta đ&atilde; l&agrave;m điều n&agrave;y bằng c&aacute;ch sử dụng code dưới đ&acirc;y:</p> <pre class="language-python"><code>tb.add_histogram('conv1.bias', network.conv1.bias, epoch) tb.add_histogram('conv1.weight', network.conv1.weight, epoch) tb.add_histogram('conv1.weight.grad', network.conv1.weight.grad, epoch)</code></pre> <p style="text-align: justify;">B&acirc;y giờ, ch&uacute;ng ta sẽ cải thiện điều n&agrave;y bằng c&aacute;ch th&ecirc;m c&aacute;c gi&aacute; trị n&agrave;y cho tất cả c&aacute;c lớp bằng c&aacute;ch sử dụng v&ograve;ng lặp b&ecirc;n dưới:</p> <pre class="language-python"><code>for name, weight in network.named_parameters(): tb.add_histogram(name, weight, epoch) tb.add_histogram(f'{name}.grad', weight.grad, epoch)</code></pre> <p style="text-align: justify;">Điều n&agrave;y hoạt động v&igrave; phương thức PyTorch <em>nn.Module</em> được gọi l&agrave; <em>names_parameters()</em> cung cấp cho ch&uacute;ng ta t&ecirc;n v&agrave; gi&aacute; trị của tất cả c&aacute;c tham số b&ecirc;n trong mạng.</p> <h3 class="section-heading" style="text-align: justify;">Th&ecirc;m nhiều si&ecirc;u tham số hơn m&agrave; kh&ocirc;ng cần nesting</h3> <p style="text-align: justify;">Ch&uacute;ng ta c&oacute; thể tạo một tập hợp c&aacute;c tham số cho mỗi lần chạy v&agrave; g&oacute;i tất cả ch&uacute;ng lại trong một lần lặp duy nhất.&nbsp;Đ&acirc;y l&agrave; c&aacute;ch ch&uacute;ng ta sẽ l&agrave;m điều đ&oacute;.</p> <p style="text-align: justify;">Nếu ch&uacute;ng ta c&oacute; một danh s&aacute;ch c&aacute;c tham số, ch&uacute;ng ta c&oacute; thể đ&oacute;ng g&oacute;i ch&uacute;ng th&agrave;nh một tập hợp cho mỗi lần chạy của ch&uacute;ng ta bằng c&aacute;ch sử dụng t&iacute;ch <a href="https://en.wikipedia.org/wiki/Cartesian_product" target="_blank" rel="noopener">Descartes</a>.&nbsp;Đối với điều n&agrave;y, ch&uacute;ng ta sẽ sử dụng h&agrave;m&nbsp;product từ thư viện <em>itertools.&nbsp;</em></p> <pre class="language-python"><code>from itertools import product Init signature: product(*args, **kwargs) Docstring: """ product(*iterables, repeat=1) --&gt; product object Cartesian product of input iterables. Equivalent to nested for-loops. """</code></pre> <pre><br /><br /></pre> <p style="text-align: justify;">Tiếp theo, ch&uacute;ng ta x&aacute;c định một từ điển c&oacute; chứa c&aacute;c tham số l&agrave; kh&oacute;a v&agrave; c&aacute;c gi&aacute; trị tham số m&agrave; ch&uacute;ng ta muốn sử dụng l&agrave;m gi&aacute; trị.</p> <pre class="language-python"><code>parameters = dict( lr = [.01, .001] ,batch_size = [100, 1000] ,shuffle = [True, False] )</code></pre> <p style="text-align: justify;">Tiếp theo, ch&uacute;ng ta sẽ tạo một danh s&aacute;ch c&aacute;c&nbsp;iterables m&agrave; ch&uacute;ng ta c&oacute; thể chuyển cho c&aacute;c h&agrave;m <em>product.</em></p> <pre class="language-python"><code>param_values = [v for v in parameters.values()] param_values [[0.01, 0.001], [100, 1000], [True, False]]</code></pre> <p style="text-align: justify;">B&acirc;y giờ, ch&uacute;ng ta c&oacute; ba danh s&aacute;ch c&aacute;c gi&aacute; trị tham số.&nbsp;Sau khi ch&uacute;ng ta lấy t&iacute;ch Descartes của ba danh s&aacute;ch n&agrave;y, ch&uacute;ng ta sẽ c&oacute; một tập hợp c&aacute;c gi&aacute; trị tham số cho mỗi lần chạy.&nbsp;Lưu &yacute; rằng điều n&agrave;y tương đương với c&aacute;c v&ograve;ng lặp for lồng nhau, như chuỗi doc của h&agrave;m product.</p> <pre class="language-python"><code>for lr, batch_size, shuffle in product(*param_values): print (lr, batch_size, shuffle) 0.01 100 True 0.01 100 False 0.01 1000 True 0.01 1000 False 0.001 100 True 0.001 100 False 0.001 1000 True 0.001 1000 False</code></pre> <p style="text-align: justify;">B&acirc;y giờ ch&uacute;ng ta c&oacute; thể lặp lại từng bộ tham số bằng một v&ograve;ng lặp for duy nhất.&nbsp;Tất cả những g&igrave; ch&uacute;ng ta phải l&agrave;m l&agrave; giải n&eacute;n tập hợp bằng c&aacute;ch sử dụng&nbsp;sequence unpacking. Như sau:</p> <pre class="language-python"><code>for lr, batch_size, shuffle in product(*param_values): comment = f' batch_size={batch_size} lr={lr} shuffle={shuffle}' train_loader = torch.utils.data.DataLoader( train_set ,batch_size=batch_size ,shuffle=shuffle ) optimizer = optim.Adam( network.parameters(), lr=lr ) # Rest of training process given the set of parameters</code></pre> <p style="text-align: justify;">Lưu &yacute; c&aacute;ch ch&uacute;ng ta x&acirc;y dựng chuỗi comment của m&igrave;nh để x&aacute;c định lần chạy.&nbsp;Ngo&agrave;i ra, h&atilde;y lưu &yacute; to&aacute;n tử *.&nbsp;Đ&acirc;y l&agrave; một c&aacute;ch đặc biệt trong Python để giải n&eacute;n một danh s&aacute;ch th&agrave;nh một tập hợp c&aacute;c đối số.&nbsp;Do đ&oacute;, trong t&igrave;nh huống n&agrave;y, ch&uacute;ng ta đ&atilde; truyền ba đối số đ&atilde; được giải n&eacute;n ri&ecirc;ng lẻ cho h&agrave;m product đối lập với single list.</p> <p style="text-align: justify;">Bạn c&oacute; thể t&igrave;m hiểu th&ecirc;m vấn đề n&agrave;y ở 2 t&agrave;i liệu dưới đ&acirc;y:</p> <ul style="text-align: justify;"> <li><a href="https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists">Python doc: More Control Flow Tools</a></li> <li><a href="https://python.org/dev/peps/pep-0448/">PEP 448 -- Additional Unpacking Generalizations</a></li> </ul> <p style="text-align: right;"><a href="https://tek4.vn/training-loop-run-builder-lap-trinh-neural-network-voi-pytorch/" target="_blank" rel="noopener">B&agrave;i viết tiếp theo: Training Loop Run Builder</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>