Phép biến đổi tuyến tính¶
Mọi phép nhân ma trận đều là một phép biến đổi tuyến tính — một hàm làm thay đổi hình dạng, xoay, hoặc chiếu các vector trong khi bảo toàn tính tuyến tính. File này bao quát phép xoay, phản chiếu, co giãn, xiên, chiếu, nhân và ảnh của một ánh xạ, và cách các tầng mạng nơ-ron chuỗi các phép biến đổi này lại với nhau.
-
Một phép biến đổi tuyến tính (hay ánh xạ tuyến tính) là một hàm nhận một vector và tạo ra một vector khác, trong khi bảo toàn phép cộng và co giãn. Nếu \(T\) là tuyến tính, thì:
- \(T(\mathbf{u} + \mathbf{v}) = T(\mathbf{u}) + T(\mathbf{v})\)
- \(T(c\mathbf{u}) = cT(\mathbf{u})\)
-
Mọi phép biến đổi tuyến tính đều có thể được biểu diễn dưới dạng nhân với một ma trận. Ma trận chính là phép biến đổi. Khi bạn nhân một vector với một ma trận, bạn đang áp dụng một phép biến đổi tuyến tính lên nó.
-
Hãy tưởng tượng một ma trận \(2 \times 2\) như một cỗ máy nhận vào các vector 2D và xuất ra các vector 2D mới. Các cột của ma trận cho bạn biết các vector cơ sở chuẩn \(\hat{\mathbf{i}}\) và \(\hat{\mathbf{j}}\) kết thúc ở đâu sau phép biến đổi. Mọi thứ khác tuân theo tính tuyến tính.
- Ví dụ, nếu
-
thì \(\hat{\mathbf{i}} = [1, 0]^T\) hạ cánh tại \([2, 1]^T\) (cột 1) và \(\hat{\mathbf{j}} = [0, 1]^T\) hạ cánh tại \([1, 2]^T\) (cột 2). Mọi vector khác là tổ hợp của hai vector này, nên đầu ra của nó tự động theo đó.
-
Nhân hai ma trận có thể được xem như áp dụng hết phép biến đổi này đến phép biến đổi khác. Nếu \(B\) biến đổi các vector từ một không gian và \(A\) biến đổi kết quả, thì \(AB\) thực hiện cả hai theo trình tự. Trong một engine game, xoay nhân vật rồi đưa chúng tiến lên phía trước là một kết quả khác với việc đưa chúng lên trước rồi mới xoay, đó là lý do tại sao nhân ma trận không giao hoán.
-
Phép xoay quay các vector bởi một góc \(\theta\) mà không thay đổi độ dài của chúng. Vector vẫn giữ nguyên kích thước, nó chỉ chỉ về một hướng mới.
- Trong 2D, ma trận xoay là:
- Với \(\theta = 90°\):
-
nên \([1, 0]^T\) trở thành \([0, 1]^T\). Vector chỉ sang phải giờ chỉ lên trên. Ma trận xoay là trực giao và luôn có định thức bằng 1. Khi bạn xoay một bức ảnh trên điện thoại, đây chính xác là ma trận được áp dụng cho mọi tọa độ điểm ảnh.
-
Trong 3D, có các ma trận xoay riêng cho từng trục. Một cánh tay robot xoay từng khớp quanh một trục cụ thể, và mỗi khớp là một ma trận xoay. Phép xoay quanh trục z trông giống như trường hợp 2D được gắn trong 3D:
- Phép co giãn kéo dài hoặc thu nhỏ các vector dọc theo từng trục một cách độc lập:
-
\(S(2, 1.5)\) nhân đôi thành phần x và nhân thành phần y với 1.5. Co giãn bởi \(-1\) dọc theo một trục sẽ lật thành phần đó. Một ma trận đường chéo luôn là phép biến đổi co giãn. Khi bạn thay đổi kích thước ảnh xuống 50%, bạn đang áp dụng \(S(0.5, 0.5)\) cho mọi tọa độ điểm ảnh.
-
Phép phản chiếu lật các vector qua một trục hoặc đường thẳng, như một tấm gương. Phản chiếu qua trục x giữ nguyên thành phần x và đảo dấu thành phần y:
- Ví dụ, \([3, 2]^T\) trở thành \([3, -2]^T\). Khi điện thoại của bạn lật ngược một tấm selfie theo chiều ngang để chữ đọc đúng chiều, nó đang áp dụng một ma trận phản chiếu. Phản chiếu qua đường thẳng \(y = x\) hoán đổi hai thành phần:
-
Ma trận phản chiếu có định thức \(-1\), xác nhận chúng đảo ngược hướng.
-
Phép xoay và phản chiếu đều là các phép biến đổi cứng nhắc (rigid transformations): chúng bảo toàn khoảng cách và góc. Các ma trận biểu diễn chúng là ma trận trực giao, đó là lý do tại sao ma trận trực giao luôn có định thức \(+1\) (xoay) hoặc \(-1\) (phản chiếu).
-
Phép xiên (shearing) làm lệch các vector dọc theo một trục tỷ lệ với trục kia. Một phép xiên ngang bởi hệ số \(k\):
-
Mỗi điểm trượt ngang bởi \(k\) lần chiều cao của nó. Với \(k = 0.5\), một điểm ở độ cao 2 dịch phải 1. Hàng dưới cùng giữ nguyên, hàng trên cùng trượt. Đây là cách chữ in nghiêng hoạt động: các chữ thẳng đứng bị xiên để chúng nghiêng về bên phải.
-
Tất cả những điều trên (xoay, co giãn, phản chiếu, xiên) đều là các phép biến đổi tuyến tính. Chúng giữ nguyên gốc tọa độ và bảo toàn các đường thẳng. Nhưng tịnh tiến (dịch mọi thứ bởi một lượng cố định) thì sao?
-
Tịnh tiến không phải là một phép biến đổi tuyến tính vì nó di chuyển gốc tọa độ. Nếu bạn dịch mọi điểm sang phải 3, vector không di chuyển đến \([3, 0]^T\), phá vỡ tính tuyến tính. Để xử lý nó, ta dùng một phép biến đổi affine, kết hợp một phép biến đổi tuyến tính với một phép tịnh tiến:
- Để biểu diễn điều này dưới dạng một phép nhân ma trận duy nhất, ta dùng tọa độ đồng nhất (homogeneous coordinates): thêm một số 1 vào mọi vector và dùng ma trận \((n+1) \times (n+1)\):
-
Các phép biến đổi affine bảo toàn đường thẳng và tính song song, nhưng không nhất thiết bảo toàn góc hoặc độ dài. Mọi vật thể trong trò chơi điện tử đều được định vị bằng phép biến đổi affine: xoay nó, co giãn nó, rồi đặt nó vào vị trí thích hợp, tất cả được mã hóa trong một ma trận duy nhất.
-
Một phép biến đổi suy biến (ma trận suy biến) đè bẹp không gian xuống một chiều thấp hơn.
-
Ví dụ, ma trận
-
ánh xạ mọi vector 2D lên một đường thẳng duy nhất, vì cả hai cột đều chỉ cùng một hướng. Định thức bằng không, thông tin bị mất, và phép biến đổi không thể hoàn tác.
-
Chuyển đổi ảnh màu (3 giá trị mỗi điểm ảnh: đỏ, lục, lam) thành ảnh xám (1 giá trị mỗi điểm ảnh) là một phép biến đổi suy biến: thông tin màu sắc mất đi vĩnh viễn.
-
Trong ML, các phép biến đổi tuyến tính là cốt lõi của mạng nơ-ron: dữ liệu được biểu diễn dưới dạng một ma trận (một chồng các vector biểu diễn các đặc trưng của một đối tượng như con người, máy bay, văn bản, hình ảnh... bất cứ thứ gì!)
-
Mỗi tầng áp dụng một phép nhân ma trận (biến đổi tuyến tính), chi tiết được cung cấp ở các chương khác, chúng ta cần giải thích cách cấu trúc dữ liệu này và thúc đẩy các mạng nơ-ron một cách thích hợp.
-
Tuy nhiên, các kỹ thuật được sử dụng nhiều nhất hiện nay thường gần như độc quyền truyền dữ liệu qua một loạt các phép biến đổi tuyến tính, chúng ta gọi chúng là Transformer.
-
Gemini, ChatGPT, Claude, Qwen, DeepSeek và các AI hoạt động tốt nhất trên thế giới hiện nay đều là transformer!
Bài tập lập trình (dùng CoLab hoặc notebook)¶
-
Áp dụng ma trận xoay cho một vector và vẽ đồ thị cả vector gốc lẫn vector đã xoay. Thử các góc khác nhau.
import jax.numpy as jnp import matplotlib.pyplot as plt theta = jnp.pi / 3 R = jnp.array([[jnp.cos(theta), -jnp.sin(theta)], [jnp.sin(theta), jnp.cos(theta)]]) v = jnp.array([1.0, 0.0]) v_rot = R @ v plt.figure(figsize=(5, 5)) plt.quiver(0, 0, v[0], v[1], angles='xy', scale_units='xy', scale=1, color='red', label='original') plt.quiver(0, 0, v_rot[0], v_rot[1], angles='xy', scale_units='xy', scale=1, color='blue', label='rotated') plt.xlim(-1.5, 1.5); plt.ylim(-1.5, 1.5) plt.grid(True); plt.legend(); plt.gca().set_aspect('equal') plt.show() -
Áp dụng một phép biến đổi xiên lên một tập hợp các điểm tạo thành một hình vuông và trực quan hóa hình dạng bị biến dạng.
import jax.numpy as jnp import matplotlib.pyplot as plt square = jnp.array([[0,0],[1,0],[1,1],[0,1],[0,0]]).T k = 0.5 shear = jnp.array([[1, k], [0, 1]]) sheared = shear @ square plt.figure(figsize=(6, 4)) plt.plot(square[0], square[1], 'r-o', label='original') plt.plot(sheared[0], sheared[1], 'b-o', label='sheared') plt.grid(True); plt.legend(); plt.gca().set_aspect('equal') plt.show()