ในการเรียนรู้ Neural Network เราจะพบเจอโค้ดที่ใช้ List, Vector, NumPy Array ไปจนถึง High-Order Tensor หมายถึง Array ที่มีมากกว่า 2 มิติขึ้นไป เช่น 3 มิติ 4 มิติ หรือ 5 มิติ จนเป็นเรื่องธรรมดา ใน ep นี้เราจะมาเรียนรู้การใช้งาน Tensor ทำความเข้าใจ element-wise, broadcasting operations
Vector และ List คืออะไร
Vector (เวกเตอร์) และ List (ลิสต์) คือ ภาชนะบรรจุข้อมูลที่มีขนาดเท่ากัน ชนิดเดียวกัน ที่มี 1 มิติ เช่น [1, 2, 3, 4]
NumPy Array และ Matrix คืออะไร
NumPy Array (นัมไพ อาเรย์) และ Matrix (เมตริกซ์) คือ ภาชนะบรรจุข้อมูลที่มีขนาดเท่ากัน ชนิดเดียวกัน ที่มี 2 มิติ เช่น
[[1, 2, 3],
[4, 5, 6] ,
[7, 8, 9]]
Tensor คืออะไร
Tensor (เทนเซอร์) คือ ภาชนะบรรจุข้อมูลที่มีขนาดเท่ากัน ชนิดเดียวกัน ที่มีกี่มิติก็ได้ เช่น รูปสี ความละเอียด 224 x 224 Pixel จำนวน 10 รูป จะมีข้อมูล 4 มิติ ดังนี้ (10, 3, 224, 224) และสมมติเรามีข้อมูล 10 รูปแบบนี้ จาก 12 เดือน ก็จะเป็น 5 มิติ (12, 10, 3, 224, 224)
เราสามารถออกแบบมิติข้อมูลเพื่อใช้งานได้อย่างอิสระ

หมายเหตุ
- NumPy Array จริง ๆ คือ N-Dimension (ndarray) ก็สามารถใช้บรรจุข้อมูล กี่มิติก็ได้เช่นกัน แต่นิยมใช้ 1-2 มิติ
- 3 ในรูปสี คือ 3 Channels RGB
- การเรียงมิติไหนก่อนหลัง ขึ้นกับแต่ละ API
- Rank Number หมายถึง จำนวนมิติ ของ Tensor เช่น ตัวอย่างด้านบน (10, 3, 224, 224) จะเรียกว่า Rank 4 Tensor
ข้อดีของ Tensor เปรียบเทียบกับ NumPy Array
Tensor นั้นมีข้อดีหลายอย่างกว่า NumPy Array คือ สามารถใช้ GPU และรองรับ Autograd สามารถคำนวน Diff หา Gradient ให้อัตโนมัติ ทำให้เหมาะที่จะนำมาใช้สร้าง Deep Neural Network ในปัจจุบัน ที่เทรนโมเดลด้วยอัลกอริทึม Gradient Descent และ Backpropagation

และเมื่อมี GPU แทนที่เราจะเขียนโปรแกรม วน Loop ทำ Operations ทีละ Element เราจึงต้องปรับ Mindset ออกแบบด้วยแนวคิด Vectorization คือ ทำทุกอย่างให้เป็น Vector, Array หรือ Tensor แล้วทำ Operation นั้น ๆ พร้อม ๆ กันทีเดียวหมด ขนานกันไปเลย ด้วย GPU ซึ่งจะช่วยเพิ่มความเร็วขึ้นกว่าวน Loop ทำทีละอัน หลายร้อย หลายพันเท่า
เรามาเริ่มกันเลย
0. Import¶
import torch
from torch import tensor
1. Element-wise operations¶
Element-wise Operations หมายถึง ทำ Operations แยกคนละตัวเรียงตามตำแหน่ง ตัวแรกทำกับตัวแรก ตัวที่สองทำกับตัวที่สอง ... โดยอาจจะทำไปพร้อม ๆ กัน ทำขนานกันไปก็ได้
1.1 Basic operations¶
a = tensor([1., 2., 3., 4.])
บวก ลบ คูณ หาร ยกกำลัง กับ ตัวเลขธรรมดา ใส่ . จุด หลังตัวเลข หมายถึง ให้เป็นเลขแบบ Float จุดทศนิยม รองรับการคำนวนคณิตศาสตร์ เช่น 1. เหมือนกับ 1.0
a + 1
2**a
บวก ลบ คูณ หาร ยกกำลัง กับ tensor ด้วยกัน
b = torch.ones(4) + 1
b
a - b
a * b
j = torch.arange(5)
j
2**(j + 1) - j
1.2 เปรียบเทียบความเร็ว¶
Tensor
a = torch.arange(10000)
%timeit a + 1
วน loop array
l = range(10000)
%timeit [i+1 for i in l]
tensor เร็วกว่าประมาณเกือบ 40 เท่า เนื่องจากเป็นการประมวลผลแบบขนาน ไม่ได้ทำทีละ item เรียงไปเรื่อย ๆ
1.3 Multiplication¶
c = torch.ones((3, 3))
c
คูณแบบปกติ จะเป็น คูณแบบ element-wise ไม่ได้คูณแบบ matrix
c * c
คูณแบบ matrix dot product
c.matmul(c)
1.4 Comparison Operations¶
Operation เปรียบเทียบ ก็ element-wise
a = tensor([1, 2, 3, 4])
b = tensor([4, 2, 2, 4])
1 คือ True, 0 คือ False
a == b
a > b
1.5 Transcendental functions¶
ฟังก์ชันคณิตศาสตร์ ก็ element-wise
a = torch.arange(5.)
torch.sin(a)
torch.log(a)
torch.exp(a)
2. Broadcasting¶
ในกรณี 2 ฝั่งมีสมาชิกไม่เท่ากัน จะเกิดการ Broadcasting กระจายสมาชิกจาก 1 ให้กลายเป็นเท่ากัน ก่อนทำ Element-wise Operation
ใน Numpy, TensorFlow และ Pytorch มิติแรก 0 จะเป็น Row มิติที่สอง 1 จะเป็น Column
a = torch.arange(0, 40, 10).repeat(1, 1, 3).view(3, 4).t()
a
2.1 Row Broadcasting¶
กระจาย 1 Row เป็น 4 Row ก่อนบวก
b = tensor([0, 1, 2])
b
a + b
2.2 Column Broadcasting¶
กระจาย 1 Column เป็น 3 Column ก่อนบวก
c = tensor([[0], [1], [2], [3]])
c
a + c
2.3 Row and Column Broadcasting¶
d = tensor([2])
d
กระจายเป็น 4 Row 3 Column ก่อนบวก
a+d
หมายเหตุ การ Broadcasting ไม่ได้จำกัดอยู่แค่ 2 มิติ เราสามารถ Broadcast ได้ในทุก ๆ มิติ เช่น broardcast มิติที่ 4 ใน tensor 5 มิติ เป็นต้น
3. Indexing and Slicing¶
a = torch.ones((4, 5))
a
3.1 Indexing¶
Indexing คือ การเลือกเฉพาะ Row, Column ที่ต้องการขึ้นมา เช่น ให้ Row ที่ 0 เป็น ค่า 2
ไม่ได้ระบุมิติที่ 2 ให้ถือว่าเป็น : คือเอาทุก Column
a[0] = 2
a
ให้ Column ที่ 1 (เริ่มต้นที่ 0) เป็น 3
หมายเหตุ : (เครื่องหมาย colon) แปลว่าทุกอัน ถ้าอยู่ตำแหน่งแรก แปลว่าทุก Row
a[:, 1] = 3
a
ให้ Column ที่ 1 จากสุดท้าย เป็น 4
Index ติดลบ แปลว่า นับจากท้ายสุด
a[:, -1] = 4
a
3.2 Slicing¶
Slicing เลือกเอาช่วง Index ในลำดับที่ต้องการ
x = tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x
เริ่มที่ 3 ถึง 6 (ไม่รวม 6)
x[3:6]
เริ่มที่ 1 ถึง 7 (ไม่รวม 7) ข้ามทีละ 2
x[1:7:2]
เลือกอันดับ 2 จากสุดท้าย ถึง อันดับ 10 (ไม่รวม 10)
x[-2:10]
เลือกตั้งแต่ 5 เป็นต้นไป
x[5:]
เลือกตั้งแต่ต้นจนถึง 5 (ไม่รวม 5)
x[:5]
4. Summation¶
การหาผลรวมของ Tensor เนื่องจาก Tensor มีหลายมิติ เราจึงต้องกำหนดว่า จะคิดตามมิติไหน ดังตัวอย่าง
a = tensor([[1, 1, 1], [2, 2, 2], [3, 3, 3]])
a
สมมติ a คือ Tensor 2 มิติ ขนาด 3 x 3
a.shape
Sum ตามแนวมิติที่ 0 คือ Row
s = a.sum(0)
s
s.shape
Sum ตามแนวมิติที่ 1 คือ Column
s = a.sum(1)
s
s.shape
เมื่อมีการ Sum มิตินั้นจะหายไป ทำให้ Tensor 2 มิติ กลายเป็น Tensor 1 มิติ หรือ Vector ถ้าเราต้องการให้มิติคงเดิม ให้เราใส่ keepdim=True
s = a.sum(0, keepdim=True)
s
s.shape
s = a.sum(1, keepdim=True)
s
s.shape
Sum มิติท้ายสุด
a.sum(-1)
มิติ ติดลบ แปลว่า นับจากท้ายสุด
Credit¶