tek4

Stack Và Concat Trong Pytorch

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ẽ ph&acirc;n t&iacute;ch sự kh&aacute;c biệt giữa concat (nối ) v&agrave; stack (xếp chồng) c&aacute;c tensor với nhau. Ch&uacute;ng ta sẽ xem x&eacute;t qua ba v&iacute; dụ, một với PyTorch, một với TensorFlow v&agrave; một với NumPy. 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/stack-va-concat-trong-pytorch-png-1" alt="Stack V&agrave; Concat Trong Pytorch" /></p> <p style="text-align: center;"><a href="https://tek4.vn/confusion-matrix-lap-trinh-neural-network-voi-pytorch/" target="_blank" rel="noopener">Xem th&ecirc;m b&agrave;i viết trước:&nbsp;Confusion Matrix</a></p> <h3 class="section-heading" style="text-align: justify;">Existing Vs New Axes</h3> <p style="text-align: justify;">Sự kh&aacute;c biệt giữa c&aacute;c tensors stack v&agrave; concat c&oacute; thể được m&ocirc; tả trong một c&acirc;u duy nhất:</p> <pre><code>Concatenating joins a sequence of tensors along an existing axis, and stacking joins a sequence of tensors along a new axis.</code></pre> <p style="text-align: justify;">Hiểu một c&aacute;ch đơn giản th&igrave;: Concat nối một chuỗi c&aacute;c tensor dọc theo một axis đ&atilde; tồn tại v&agrave; Stack nối một chuỗi c&aacute;c tensor dọc theo một axis mới.</p> <p style="text-align: justify;">Tuy nhi&ecirc;n, phần m&ocirc; tả ở đ&acirc;y hơi phức tạp, v&igrave; vậy h&atilde;y xem một số v&iacute; dụ để hiểu r&otilde; hơn về vấn đề n&agrave;y.&nbsp;Ch&uacute;ng ta sẽ xem x&eacute;t việc stack v&agrave; concat trong PyTorch, TensorFlow v&agrave; NumPy.</p> <h4 class="sub-section-heading" style="text-align: justify;">C&aacute;ch th&ecirc;m hoặc ch&egrave;n một axis v&agrave;o một Tensor</h4> <p style="text-align: justify;">Để chứng minh &yacute; tưởng th&ecirc;m axis n&agrave;y, ch&uacute;ng ta sẽ sử dụng PyTorch.</p> <pre class="language-python"><code>import torch t1 = torch.tensor([1,1,1])</code></pre> <p style="text-align: justify;">Ở đ&acirc;y, ch&uacute;ng ta đang import PyTorch v&agrave; tạo một tensor đơn giản c&oacute; một axis với độ d&agrave;i l&agrave; ba.&nbsp;B&acirc;y giờ, để th&ecirc;m một axis v&agrave;o tensor trong PyTorch, ch&uacute;ng ta sử dụng h&agrave;m <em>unsqueeze().&nbsp;</em></p> <pre class="language-python"><code>&gt; t1.unsqueeze(dim=0) tensor([[1, 1, 1]])</code></pre> <p style="text-align: justify;">Ở đ&acirc;y, ch&uacute;ng ta đang th&ecirc;m một axis ở index 0 của tensor n&agrave;y.&nbsp;Điều n&agrave;y cho ch&uacute;ng ta một tensor c&oacute; shape 1 x 3.</p> <p style="text-align: justify;">B&acirc;y giờ, ch&uacute;ng ta cũng c&oacute; thể th&ecirc;m một axis tại index thứ hai của tensor n&agrave;y.</p> <pre class="language-python"><code>&gt; t1.unsqueeze(dim=1) tensor([[1], [1], [1]])</code></pre> <p style="text-align: justify;">Điều n&agrave;y cho ch&uacute;ng ta một tensor c&oacute; shape 3 x 1.&nbsp;Việc th&ecirc;m c&aacute;c axis như thế n&agrave;y thay đổi c&aacute;ch tổ chức dữ liệu b&ecirc;n trong tensor, nhưng n&oacute; kh&ocirc;ng thay đổi ch&iacute;nh dữ liệu.&nbsp;Về cơ bản, ch&uacute;ng ta chỉ đang reshape lại tensor.&nbsp;Ch&uacute;ng ta c&oacute; thể thấy điều đ&oacute; bằng c&aacute;ch kiểm tra shape của từng c&aacute;i n&agrave;y.</p> <pre class="language-python"><code>&gt; print(t1.shape) &gt; print(t1.unsqueeze(dim=0).shape) &gt; print(t1.unsqueeze(dim=1).shape) torch.Size([3]) torch.Size([1, 3]) torch.Size([3, 1])</code></pre> <p style="text-align: justify;">Khi ch&uacute;ng ta concat, ch&uacute;ng ta đang nối một chuỗi c&aacute;c tensor dọc theo một axis hiện c&oacute;.&nbsp;Điều n&agrave;y c&oacute; nghĩa l&agrave; ch&uacute;ng ta đang mở rộng chiều d&agrave;i của một axis hiện c&oacute;.</p> <p style="text-align: justify;">Khi ch&uacute;ng ta stack, ch&uacute;ng ta đang tạo ra một axis mới chưa từng tồn tại trước đ&acirc;y v&agrave; điều n&agrave;y xảy ra tr&ecirc;n tất cả c&aacute;c tensor trong chuỗi, sau đ&oacute; ch&uacute;ng ta concat theo chuỗi mới n&agrave;y.</p> <p style="text-align: justify;">H&atilde;y xem điều n&agrave;y được thực hiện như thế n&agrave;o trong PyTorch.</p> <h3 class="section-heading" style="text-align: justify;">Stack v&agrave; concat trong PyTorch</h3> <p style="text-align: justify;">ới PyTorch, hai h&agrave;m ch&uacute;ng t&ocirc;i sử dụng cho c&aacute;c hoạt động n&agrave;y l&agrave; <em>stack</em> v&agrave;&nbsp;<em>cat.&nbsp;</em>H&atilde;y tạo một chuỗi c&aacute;c tensor.</p> <pre class="language-python"><code>import torch t1 = torch.tensor([1,1,1]) t2 = torch.tensor([2,2,2]) t3 = torch.tensor([3,3,3])</code></pre> <p style="text-align: justify;">B&acirc;y giờ, h&atilde;y concatenate ch&uacute;ng với nhau.&nbsp;Ch&uacute; &yacute; rằng mỗi tensor n&agrave;y c&oacute; một axis duy nhất.&nbsp;Điều n&agrave;y c&oacute; nghĩa l&agrave; kết quả của h&agrave;m cat cũng sẽ c&oacute; một axis duy nhất.&nbsp;Điều n&agrave;y l&agrave; do khi ch&uacute;ng ta concatenate, ch&uacute;ng ta thực hiện n&oacute; dọc theo một axis hiện c&oacute;.&nbsp;Lưu &yacute; rằng trong v&iacute; dụ n&agrave;y, axis hiện c&oacute; duy nhất l&agrave; axis đầu ti&ecirc;n.</p> <pre class="language-python"><code>&gt; torch.cat( (t1,t2,t3) ,dim=0 ) tensor([1, 1, 1, 2, 2, 2, 3, 3, 3])</code></pre> <p style="text-align: justify;">Ch&uacute;ng ta đ&atilde; lấy ba tensor axis đơn, mỗi tensor axis c&oacute; độ d&agrave;i axis l&agrave; 3 v&agrave; b&acirc;y giờ ch&uacute;ng ta c&oacute; một tensor đơn c&oacute; độ d&agrave;i axis l&agrave; 9.</p> <p style="text-align: justify;">B&acirc;y giờ, h&atilde;y xếp c&aacute;c tensor n&agrave;y dọc theo một axis mới m&agrave; ch&uacute;ng ta sẽ ch&egrave;n.&nbsp;Ch&uacute;ng ta sẽ ch&egrave;n một axis ở index đầu ti&ecirc;n.&nbsp;Lưu &yacute; rằng việc ch&egrave;n n&agrave;y sẽ diễn ra ngầm ẩn bởi h&agrave;m stack.</p> <pre class="language-python"><code>&gt; torch.stack( (t1,t2,t3) ,dim=0 ) tensor([[1, 1, 1], [2, 2, 2], [3, 3, 3]])</code></pre> <p style="text-align: justify;">Điều n&agrave;y cho ch&uacute;ng ta một tensor mới c&oacute; shape 3 x 3.&nbsp;Ch&uacute; &yacute; c&aacute;ch ba tensor được&nbsp;concatenated dọc theo axis đầu ti&ecirc;n của tensor n&agrave;y.&nbsp;Lưu &yacute; rằng ch&uacute;ng ta cũng c&oacute; thể ch&egrave;n axis mới một c&aacute;ch r&otilde; r&agrave;ng v&agrave; định dạng trực tiếp phần&nbsp;concatenation.</p> <p style="text-align: justify;">Để thấy rằng c&acirc;u n&oacute;i n&agrave;y l&agrave; đ&uacute;ng.&nbsp;H&atilde;y th&ecirc;m một axis mới c&oacute; độ d&agrave;i l&agrave; 1 v&agrave;o tất cả c&aacute;c tensors của ch&uacute;ng ta bằng c&aacute;ch unsqueezing ch&uacute;ng ra v&agrave; sau đ&oacute;, <em>cat</em> chuyển dọc theo axis đầu ti&ecirc;n.</p> <pre class="language-python"><code>&gt; torch.cat( ( t1.unsqueeze(0) ,t2.unsqueeze(0) ,t3.unsqueeze(0) ) ,dim=0 ) tensor([[1, 1, 1], [2, 2, 2], [3, 3, 3]])</code></pre> <p style="text-align: justify;">Trong trường hợp n&agrave;y, c&oacute; thể thấy rằng ch&uacute;ng ta nhận được c&ugrave;ng một kết quả m&agrave; ch&uacute;ng ta nhận được bằng c&aacute;ch stack.&nbsp;Tuy nhi&ecirc;n, lệnh gọi ngăn xếp gọn g&agrave;ng hơn nhiều .</p> <pre><code>Concatenation xảy ra dọc theo một axis hiện c&oacute;.</code></pre> <p style="text-align: justify;">Lưu &yacute; rằng ch&uacute;ng ta kh&ocirc;ng thể concat chuỗi tensor n&agrave;y với axis thứ hai v&igrave; hiện tại kh&ocirc;ng c&oacute; axis thứ hai tồn tại, v&igrave; vậy trong trường hợp n&agrave;y, stack l&agrave; lựa chọn duy nhất của ch&uacute;ng ta.</p> <p style="text-align: justify;">H&atilde;y thử stack dọc theo axis thứ hai.</p> <pre class="language-python"><code>&gt; torch.stack( (t1,t2,t3) ,dim=1 ) tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])</code></pre> <p style="text-align: justify;">V&agrave; đ&acirc;y l&agrave; kết quả.</p> <pre class="language-python"><code>&gt; torch.cat( ( t1.unsqueeze(1) ,t2.unsqueeze(1) ,t3.unsqueeze(1) ) ,dim=1 ) tensor([[1, 2, 3], [1, 2, 3], [1, 2, 3]])</code></pre> <p style="text-align: justify;">Để hiểu kết quả n&agrave;y, h&atilde;y nghĩ lại n&oacute; tr&ocirc;ng như thế n&agrave;o khi ch&uacute;ng ta ch&egrave;n một axis mới v&agrave;o cuối tensor.&nbsp;B&acirc;y giờ, ch&uacute;ng ta chỉ l&agrave;m điều đ&oacute; với tất cả c&aacute;c tensors v&agrave; ch&uacute;ng ta c&oacute; thể cat ch&uacute;ng như vậy dọc theo axis thứ hai.</p> <pre class="language-python"><code>&gt; t1.unsqueeze(1) tensor([[1], [1], [1]]) &gt; t2.unsqueeze(1) tensor([[2], [2], [2]]) &gt; t3.unsqueeze(1) tensor([[3], [3], [3]])</code></pre> <h3 class="section-heading" style="text-align: justify;">Stack v&agrave; concat trong TensorFlow</h3> <pre class="language-python"><code>import tensorflow as tf t1 = tf.constant([1,1,1]) t2 = tf.constant([2,2,2]) t3 = tf.constant([3,3,3])</code></pre> <p style="text-align: justify;">Ở đ&acirc;y, ch&uacute;ng ta đ&atilde; import TensorFlow v&agrave; tạo ba tensor bằng c&aacute;ch sử dụng h&agrave;m <em>tf.constant().&nbsp;</em>B&acirc;y giờ, h&atilde;y&nbsp; concatenate c&aacute;c tensor n&agrave;y với nhau.&nbsp;Để thực hiện điều n&agrave;y trong TensorFlow, ch&uacute;ng ta sử dụng h&agrave;m <em>tf.concat()</em> v&agrave; thay v&igrave; chỉ định một <em>dim</em> (như với PyTorch), ch&uacute;ng ta chỉ định một axis<em>.&nbsp;</em></p> <pre class="language-python"><code>&gt; tf.concat( (t1,t2,t3) ,axis=0 ) tf.Tensor: id=4, shape=(9,), dtype=int32, numpy=array([1, 1, 1, 2, 2, 2, 3, 3, 3])</code></pre> <p style="text-align: justify;">Ở đ&acirc;y, kết quả giống như khi ch&uacute;ng ta thực hiện với PyTorch. H&atilde;y stack ch&uacute;ng ngay b&acirc;y giờ.</p> <pre class="language-python"><code>&gt; tf.stack( (t1,t2,t3) ,axis=0 ) tf.Tensor: id=6, shape=(3, 3), dtype=int32, numpy= array([[1, 1, 1], [2, 2, 2], [3, 3, 3]])</code></pre> <p style="text-align: justify;">Một lần nữa, kết quả cũng giống như kết quả PyTorch.&nbsp;B&acirc;y giờ, ch&uacute;ng ta sẽ concatenate những thứ n&agrave;y sau khi ch&egrave;n dimension mới theo c&aacute;ch thủ c&ocirc;ng.</p> <pre class="language-python"><code>&gt; tf.concat( ( tf.expand_dims(t1, 0) ,tf.expand_dims(t2, 0) ,tf.expand_dims(t3, 0) ) ,axis=0 ) tf.Tensor: id=15, shape=(3, 3), dtype=int32, numpy= array([[1, 1, 1], [2, 2, 2], [3, 3, 3]])</code></pre> <p style="text-align: justify;">Sự kh&aacute;c biệt với code TensorFlow n&agrave;y tr&aacute;i ngược với lệnh gọi PyTorch l&agrave; h&agrave;m <em>cat()</em> b&acirc;y giờ được gọi l&agrave; <em>concat().&nbsp;</em>Ngo&agrave;i ra, ch&uacute;ng ta sử dụng h&agrave;m expand_dims () để th&ecirc;m một axis đối lập với h&agrave;m <em>unsqueeze()</em></p> <pre><code>Unsqueezing v&agrave; expanding dims l&agrave; giống nhau</code></pre> <p style="text-align: justify;">B&acirc;y giờ,&nbsp;h&atilde;y stack theo axis thứ hai.</p> <pre class="language-python"><code>&gt; tf.stack( (t1,t2,t3) ,axis=1 ) tf.Tensor: id=17, shape=(3, 3), dtype=int32, numpy= array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])</code></pre> <p style="text-align: justify;">V&agrave; theo c&aacute;ch ch&egrave;n trục thủ c&ocirc;ng.</p> <pre class="language-python"><code>&gt; tf.concat( ( tf.expand_dims(t1, 1) ,tf.expand_dims(t2, 1) ,tf.expand_dims(t3, 1) ) ,axis=1 ) tf.Tensor: id=26, shape=(3, 3), dtype=int32, numpy= array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])</code></pre> <p style="text-align: justify;">Quan s&aacute;t rằng những kết quả n&agrave;y giống với PyTorch.</p> <h3 class="section-heading" style="text-align: justify;">Stack v&agrave; concatenate trong NumPy</h3> <pre class="language-python"><code>import numpy as np t1 = np.array([1,1,1]) t2 = np.array([2,2,2]) t3 = np.array([3,3,3])</code></pre> <p style="text-align: justify;">Ở đ&acirc;y, ch&uacute;ng ta đ&atilde; tạo ra ba tensors.&nbsp;B&acirc;y giờ, h&atilde;y concatenate ch&uacute;ng với nhau.</p> <pre class="language-python"><code>&gt; np.concatenate( (t1,t2,t3) ,axis=0 ) array([1, 1, 1, 2, 2, 2, 3, 3, 3])</code></pre> <p style="text-align: justify;">Lưu &yacute; rằng giống như TensorFlow, NumPy cũng sử dụng t&ecirc;n tham số axis, nhưng ở đ&acirc;y, ch&uacute;ng ta cũng đang thấy một biến thể đặt t&ecirc;n kh&aacute;c.&nbsp;NumPy sử dụng&nbsp;concatenate đầy đủ l&agrave;m t&ecirc;n h&agrave;m.</p> <div class="table-responsive" style="text-align: justify;"> <table class="table table-sm table-hover" style="width: 51.6025%;"> <thead> <tr> <th style="width: 35.5628%;">Library</th> <th style="width: 51.8452%;">Function Name</th> </tr> </thead> <tbody> <tr> <td style="width: 35.5628%;">PyTorch</td> <td style="width: 51.8452%;"><code>cat()</code></td> </tr> <tr> <td style="width: 35.5628%;">TensorFlow</td> <td style="width: 51.8452%;"><code>concat()</code></td> </tr> <tr> <td style="width: 35.5628%;">NumPy</td> <td style="width: 51.8452%;"><code>concatenate()</code></td> </tr> </tbody> </table> </div> <p style="text-align: justify;">H&atilde;y stack ngay b&acirc;y giờ.</p> <pre class="language-python"><code>&gt; np.stack( (t1,t2,t3) ,axis=0 ) array([[1, 1, 1], [2, 2, 2], [3, 3, 3]])</code></pre> <p style="text-align: justify;">Đ&uacute;ng như dự đo&aacute;n, kết quả l&agrave; một tensor rank 2 c&oacute; shape 3 x 3.</p> <pre class="language-python"><code>&gt; np.concatenate( ( np.expand_dims(t1, 0) ,np.expand_dims(t2, 0) ,np.expand_dims(t3, 0) ) ,axis=0 ) array([[1, 1, 1], [2, 2, 2], [3, 3, 3]])</code></pre> <p style="text-align: justify;">Lưu &yacute; rằng kết quả giống như khi ch&uacute;ng ta sử dụng h&agrave;m <em>stack().&nbsp;</em>Ngo&agrave;i ra, h&atilde;y quan s&aacute;t rằng NumPy cũng sử dụng thuật ngữ <em>expand dims</em> cho t&ecirc;n h&agrave;m.</p> <p style="text-align: justify;">B&acirc;y giờ, ch&uacute;ng ta sẽ ho&agrave;n th&agrave;nh việc n&agrave;y bằng c&aacute;ch stack bằng axis thứ hai.</p> <pre class="language-python"><code>&gt; np.stack( (t1,t2,t3) ,axis=1 ) array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])</code></pre> <p style="text-align: justify;">V&agrave;, với ch&egrave;n thủ c&ocirc;ng.</p> <pre class="language-python"><code>&gt; np.concatenate( ( np.expand_dims(t1, 1) ,np.expand_dims(t2, 1) ,np.expand_dims(t3, 1) ) ,axis=1 ) array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])</code></pre> <p style="text-align: right;"><a href="https://tek4.vn/tensorboard-voi-pytorch-lap-trinh-neural-network-voi-pytorch/" target="_blank" rel="noopener">B&agrave;i viết tiếp theo: TensorBoard Với PyTorch</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>