.. _sec_linear-algebra:
Đại số tuyến tính
=================
Bây giờ bạn có thể lưu trữ và thao tác dữ liệu, chúng ta hãy xem xét
ngắn gọn tập hợp con của đại số tuyến tính cơ bản mà bạn sẽ cần hiểu và
thực hiện hầu hết các mô hình được đề cập trong cuốn sách này. Dưới đây,
chúng tôi giới thiệu các đối tượng toán học cơ bản, số học, và phép toán
trong đại số tuyến tính, thể hiện từng đối tượng trong số chúng thông
qua ký hiệu toán học và việc thực hiện tương ứng trong mã.
Vô hướng
--------
Nếu bạn chưa bao giờ học đại số tuyến tính hoặc học máy, thì kinh nghiệm
trong quá khứ của bạn với toán học có thể bao gồm suy nghĩ về một số tại
một thời điểm. Và, nếu bạn đã bao giờ cân bằng một sổ séc hoặc thậm chí
trả tiền cho bữa tối tại một nhà hàng thì bạn đã biết làm thế nào để làm
những việc cơ bản như thêm và nhân các cặp số. Ví dụ, nhiệt độ ở Palo
Alto là :math:`52` độ F. Chính thức, chúng ta gọi các giá trị chỉ bao
gồm một số lượng \* vô số\ *. Nếu bạn muốn chuyển đổi giá trị này sang
Celsius (thang nhiệt độ hợp lý hơn của hệ mét), bạn sẽ đánh giá biểu
thức :math:`c = \frac{5}{9}(f - 32)`, đặt :math:`f` thành :math:`52`.
Trong phương trình này, mỗi thuật ngữ — :math:`5`, :math:`9`, và
:math:`32`—là những giá trị vô hướng. Các giữ chỗ :math:`c` và :math:`f`
được gọi là *\ variables\* và chúng đại diện cho các giá trị vô hướng
không xác định.
Trong cuốn sách này, chúng ta áp dụng ký hiệu toán học trong đó các biến
vô hướng được biểu thị bằng các chữ cái thường thấp hơn (ví dụ:
:math:`x`, :math:`y` và :math:`z`). Chúng tôi biểu thị không gian của
tất cả (liên tục) \* có giá trị thực\* vô hướng bởi :math:`\mathbb{R}`.
Đối với sự nhanh chóng, chúng ta sẽ xem xét các định nghĩa nghiêm ngặt
về chính xác *không gian* là gì, nhưng chỉ cần nhớ rằng biểu thức
:math:`x \in \mathbb{R}` là một cách chính thức để nói rằng :math:`x` là
một vô hướng có giá trị thực. Ký hiệu :math:`\in` có thể được phát âm
“trong” và chỉ đơn giản là biểu thị thành viên trong một bộ. Tương tự,
chúng ta có thể viết :math:`x, y \in \{0, 1\}` để nói rằng :math:`x` và
:math:`y` là những con số có giá trị chỉ có thể là :math:`0` hoặc
:math:`1`.
Một vô hướng được biểu diễn bằng một tensor chỉ với một yếu tố. Trong
đoạn tiếp theo, chúng ta khởi tạo hai vô hướng và thực hiện một số phép
toán số học quen thuộc với chúng, cụ thể là cộng, nhân, chia và hàm mũ.
.. raw:: html
.. raw:: html
.. code:: python
from mxnet import np, npx
npx.set_np()
x = np.array(3.0)
y = np.array(2.0)
x + y, x * y, x / y, x ** y
.. parsed-literal::
:class: output
(array(5.), array(6.), array(1.5), array(9.))
.. raw:: html
.. raw:: html
.. code:: python
import torch
x = torch.tensor(3.0)
y = torch.tensor(2.0)
x + y, x * y, x / y, x**y
.. parsed-literal::
:class: output
(tensor(5.), tensor(6.), tensor(1.5000), tensor(9.))
.. raw:: html
.. raw:: html
.. code:: python
import tensorflow as tf
x = tf.constant(3.0)
y = tf.constant(2.0)
x + y, x * y, x / y, x**y
.. parsed-literal::
:class: output
(,
,
,
)
.. raw:: html
.. raw:: html
Vectơ
-----
Bạn có thể nghĩ một vector chỉ đơn giản là một danh sách các giá trị vô
hướng. Chúng ta gọi các giá trị này là \* element\* (*entries* hoặc
*components*) của vector. Khi vectơ của chúng ta đại diện cho các ví dụ
từ tập dữ liệu của chúng ta, các giá trị của chúng giữ một số ý nghĩa
trong thế giới thực. Ví dụ: nếu chúng ta đang đào tạo một mô hình để dự
đoán rủi ro mà một khoản vay mặc định, chúng ta có thể liên kết mỗi ứng
viên với một vectơ có thành phần tương ứng với thu nhập, thời gian làm
việc, số lượng mặc định trước đó và các yếu tố khác. Nếu chúng ta đang
nghiên cứu nguy cơ đau tim bệnh nhân bệnh viện có khả năng phải đối mặt,
chúng ta có thể đại diện cho mỗi bệnh nhân bằng một vectơ có thành phần
nắm bắt các dấu hiệu quan trọng gần đây nhất của họ, mức cholesterol,
phút tập thể dục mỗi ngày, vv Trong ký hiệu toán học, chúng ta thường sẽ
biểu thị vectơ là mặt đậm, thấp hơn cased các chữ cái (ví dụ:
:math:`\mathbf{x}`, :math:`\mathbf{y}` và :math:`\mathbf{z})`.
Chúng tôi làm việc với các vectơ thông qua các hàng chục một chiều.
Trong hàng chục nói chung có thể có độ dài tùy ý, tùy thuộc vào giới hạn
bộ nhớ của máy của bạn.
.. raw:: html
.. raw:: html
.. code:: python
x = np.arange(4)
x
.. parsed-literal::
:class: output
array([0., 1., 2., 3.])
.. raw:: html
.. raw:: html
.. code:: python
x = torch.arange(4)
x
.. parsed-literal::
:class: output
tensor([0, 1, 2, 3])
.. raw:: html
.. raw:: html
.. code:: python
x = tf.range(4)
x
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Chúng ta có thể tham khảo bất kỳ phần tử nào của vectơ bằng cách sử dụng
chỉ số dưới. Ví dụ: chúng ta có thể tham khảo phần tử
:math:`i^\mathrm{th}` của :math:`\mathbf{x}` bởi :math:`x_i`. Lưu ý rằng
phần tử :math:`x_i` là vô hướng, vì vậy chúng ta không phải đối mặt với
phông chữ khi đề cập đến nó. Văn học mở rộng coi vectơ cột là định hướng
mặc định của vectơ, cuốn sách này cũng vậy. Trong toán học, một vector
:math:`\mathbf{x}` có thể được viết là
.. math:: \mathbf{x} =\begin{bmatrix}x_{1} \\x_{2} \\ \vdots \\x_{n}\end{bmatrix},
:label: eq_vec_def
trong đó :math:`x_1, \ldots, x_n` là các yếu tố của vectơ. Trong code,
chúng ta truy cập bất kỳ phần tử nào bằng cách lập chỉ mục vào tensor.
.. raw:: html
.. raw:: html
.. code:: python
x[3]
.. parsed-literal::
:class: output
array(3.)
.. raw:: html
.. raw:: html
.. code:: python
x[3]
.. parsed-literal::
:class: output
tensor(3)
.. raw:: html
.. raw:: html
.. code:: python
x[3]
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Chiều dài, kích thước và hình dạng
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Chúng ta hãy xem lại một số khái niệm từ :numref:`sec_ndarray`. Một
vectơ chỉ là một mảng các số. Và cũng giống như mỗi mảng có một chiều
dài, vì vậy không mỗi vector. Trong ký hiệu toán học, nếu chúng ta muốn
nói rằng một vector :math:`\mathbf{x}` bao gồm :math:`n` vô hướng có giá
trị thực, chúng ta có thể thể hiện điều này là
:math:`\mathbf{x} \in \mathbb{R}^n`. Độ dài của một vectơ thường được
gọi là *dimension* của vectơ.
Như với một mảng Python thông thường, chúng ta có thể truy cập độ dài
của một tensor bằng cách gọi hàm ``len()`` tích hợp của Python.
.. raw:: html
.. raw:: html
.. code:: python
len(x)
.. parsed-literal::
:class: output
4
.. raw:: html
.. raw:: html
.. code:: python
len(x)
.. parsed-literal::
:class: output
4
.. raw:: html
.. raw:: html
.. code:: python
len(x)
.. parsed-literal::
:class: output
4
.. raw:: html
.. raw:: html
Khi một tensor đại diện cho một vectơ (với chính xác một trục), chúng ta
cũng có thể truy cập độ dài của nó thông qua thuộc tính ``.shape``. Hình
dạng là một tuple liệt kê chiều dài (chiều) dọc theo mỗi trục của
tensor. Đối với hàng chục chỉ với một trục, hình dạng chỉ có một yếu tố.
.. raw:: html
.. raw:: html
.. code:: python
x.shape
.. parsed-literal::
:class: output
(4,)
.. raw:: html
.. raw:: html
.. code:: python
x.shape
.. parsed-literal::
:class: output
torch.Size([4])
.. raw:: html
.. raw:: html
.. code:: python
x.shape
.. parsed-literal::
:class: output
TensorShape([4])
.. raw:: html
.. raw:: html
Lưu ý rằng từ “chiều” có xu hướng bị quá tải trong các bối cảnh này và
điều này có xu hướng gây nhầm lẫn cho mọi người. Để làm rõ, chúng ta sử
dụng chiều của một \* vector\* hoặc một \* axis\* để chỉ chiều dài của
nó, tức là số phần tử của một vectơ hoặc một trục. Tuy nhiên, chúng ta
sử dụng chiều của một tensor để chỉ số trục mà một tensor có. Theo nghĩa
này, chiều của một số trục của một tensor sẽ là chiều dài của trục đó.
Ma trận
-------
Cũng giống như các vectơ tổng quát hóa vô hướng từ thứ tự số 0 để đặt
hàng một, ma trận khái quát hóa vectơ từ thứ tự một đến thứ tự hai. Ma
trận, mà chúng ta thường sẽ biểu thị bằng chữ in hoa, có mặt đậm (ví dụ:
:math:`\mathbf{X}`, :math:`\mathbf{Y}` và :math:`\mathbf{Z}`), được biểu
diễn bằng mã dưới dạng hàng chục với hai trục.
Trong ký hiệu toán, ta sử dụng
:math:`\mathbf{A} \in \mathbb{R}^{m \times n}` để thể hiện rằng ma trận
:math:`\mathbf{A}` bao gồm :math:`m` hàng và :math:`n` cột vô hướng có
giá trị thực. Trực quan, chúng ta có thể minh họa bất kỳ ma trận
:math:`\mathbf{A} \in \mathbb{R}^{m \times n}` như một bảng, trong đó
mỗi phần tử :math:`a_{ij}` thuộc về hàng :math:`i^{\mathrm{th}}` và cột
:math:`j^{\mathrm{th}}`:
.. math:: \mathbf{A}=\begin{bmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\ a_{21} & a_{22} & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \cdots & a_{mn} \\ \end{bmatrix}.
:label: eq_matrix_def
Đối với bất kỳ :math:`\mathbf{A} \in \mathbb{R}^{m \times n}`, hình dạng
của :math:`\mathbf{A}` là (:math:`m`, :math:`n`) hoặc
:math:`m \times n`. Cụ thể, khi một ma trận có cùng số hàng và cột, hình
dạng của nó trở thành một hình vuông; do đó, nó được gọi là matrận
*vuông*.
Chúng ta có thể tạo một ma trận :math:`m \times n` bằng cách chỉ định
một hình dạng với hai thành phần :math:`m` và :math:`n` khi gọi bất kỳ
chức năng yêu thích nào của chúng tôi để khởi tạo một tensor.
.. raw:: html
.. raw:: html
.. code:: python
A = np.arange(20).reshape(5, 4)
A
.. parsed-literal::
:class: output
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]])
.. raw:: html
.. raw:: html
.. code:: python
A = torch.arange(20).reshape(5, 4)
A
.. parsed-literal::
:class: output
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
.. raw:: html
.. raw:: html
.. code:: python
A = tf.reshape(tf.range(20), (5, 4))
A
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Chúng ta có thể truy cập phần tử vô hướng :math:`a_{ij}` của ma trận
:math:`\mathbf{A}` trong :eq:`eq_matrix_def` bằng cách chỉ định các
chỉ số cho hàng (:math:`i`) và cột (:math:`j`), chẳng hạn như
:math:`[\mathbf{A}]_{ij}`. Khi các yếu tố vô hướng của ma trận
:math:`\mathbf{A}`, chẳng hạn như trong :eq:`eq_matrix_def`, không
được đưa ra, chúng ta có thể chỉ đơn giản sử dụng chữ thường của ma trận
:math:`\mathbf{A}` với chỉ số dưới, :math:`a_{ij}`, để tham khảo
:math:`[\mathbf{A}]_{ij}`. Để giữ ký hiệu đơn giản, dấu phẩy chỉ được
chèn vào các chỉ số riêng biệt khi cần thiết, chẳng hạn như
:math:`a_{2, 3j}` và :math:`[\mathbf{A}]_{2i-1, 3}`.
Đôi khi, chúng tôi muốn lật các trục. Khi chúng ta trao đổi các hàng và
cột của ma trận, kết quả được gọi là *transpose* của ma trận. Chính
thức, chúng tôi biểu thị một ma trận :math:`\mathbf{A}` của transpose
bởi :math:`\mathbf{A}^\top` và nếu :math:`\mathbf{B} = \mathbf{A}^\top`,
sau đó :math:`b_{ij} = a_{ji}` cho bất kỳ :math:`i` và :math:`j`. Như
vậy, transpose của :math:`\mathbf{A}` trong :eq:`eq_matrix_def` là
một ma trận :math:`n \times m`:
.. math::
\mathbf{A}^\top =
\begin{bmatrix}
a_{11} & a_{21} & \dots & a_{m1} \\
a_{12} & a_{22} & \dots & a_{m2} \\
\vdots & \vdots & \ddots & \vdots \\
a_{1n} & a_{2n} & \dots & a_{mn}
\end{bmatrix}.
Bây giờ chúng ta truy cập vào một matrix của transpose trong mã.
.. raw:: html
.. raw:: html
.. code:: python
A.T
.. parsed-literal::
:class: output
array([[ 0., 4., 8., 12., 16.],
[ 1., 5., 9., 13., 17.],
[ 2., 6., 10., 14., 18.],
[ 3., 7., 11., 15., 19.]])
.. raw:: html
.. raw:: html
.. code:: python
A.T
.. parsed-literal::
:class: output
tensor([[ 0, 4, 8, 12, 16],
[ 1, 5, 9, 13, 17],
[ 2, 6, 10, 14, 18],
[ 3, 7, 11, 15, 19]])
.. raw:: html
.. raw:: html
.. code:: python
tf.transpose(A)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Là một loại đặc biệt của ma trận vuông, a *matrix đối xứng *
:math:`\mathbf{A}` bằng chuyển vị của nó:
:math:`\mathbf{A} = \mathbf{A}^\top`. Ở đây chúng ta xác định ma trận
đối xứng ``B``.
.. raw:: html
.. raw:: html
.. code:: python
B = np.array([[1, 2, 3], [2, 0, 4], [3, 4, 5]])
B
.. parsed-literal::
:class: output
array([[1., 2., 3.],
[2., 0., 4.],
[3., 4., 5.]])
.. raw:: html
.. raw:: html
.. code:: python
B = torch.tensor([[1, 2, 3], [2, 0, 4], [3, 4, 5]])
B
.. parsed-literal::
:class: output
tensor([[1, 2, 3],
[2, 0, 4],
[3, 4, 5]])
.. raw:: html
.. raw:: html
.. code:: python
B = tf.constant([[1, 2, 3], [2, 0, 4], [3, 4, 5]])
B
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Bây giờ chúng tôi so sánh ``B`` với transpose của nó.
.. raw:: html
.. raw:: html
.. code:: python
B == B.T
.. parsed-literal::
:class: output
array([[ True, True, True],
[ True, True, True],
[ True, True, True]])
.. raw:: html
.. raw:: html
.. code:: python
B == B.T
.. parsed-literal::
:class: output
tensor([[True, True, True],
[True, True, True],
[True, True, True]])
.. raw:: html
.. raw:: html
.. code:: python
B == tf.transpose(B)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Ma trận là cấu trúc dữ liệu hữu ích: chúng cho phép chúng ta tổ chức dữ
liệu có các phương thức biến thể khác nhau. Ví dụ: các hàng trong ma
trận của chúng ta có thể tương ứng với các ngôi nhà khác nhau (ví dụ dữ
liệu), trong khi các cột có thể tương ứng với các thuộc tính khác nhau.
Điều này nghe có vẻ quen thuộc nếu bạn đã từng sử dụng phần mềm bảng
tính hoặc đã đọc :numref:`sec_pandas`. Do đó, mặc dù định hướng mặc
định của một vectơ duy nhất là một vectơ cột, trong một ma trận đại diện
cho một tập dữ liệu dạng bảng, nó là thông thường hơn để coi mỗi ví dụ
dữ liệu như một vectơ hàng trong ma trận. Và, như chúng ta sẽ thấy trong
các chương sau, quy ước này sẽ cho phép các thực hành học sâu phổ biến.
Ví dụ, dọc theo trục ngoài cùng của một tensor, chúng ta có thể truy cập
hoặc liệt kê minibatches ví dụ dữ liệu, hoặc chỉ các ví dụ dữ liệu nếu
không có minibatch tồn tại.
Tensors
-------
Cũng giống như vectơ tổng quát hóa vô hướng, và ma trận tổng quát hóa
vectơ, chúng ta có thể xây dựng cấu trúc dữ liệu với nhiều trục hơn nữa.
`**Tensors** <“tensors”%20trong%20tiểu%20mục%20này%20đề%20cập%20đến%20các%20đối%20tượng%20đại%20số>`__
cung cấp cho chúng ta một cách chung để mô tả các mảng :math:`n` chiều
với một số trục tùy ý. Vectơ, ví dụ, là các hàng chục bậc nhất, và ma
trận là hàng chục bậc hai. Tensors được ký hiệu bằng chữ in hoa của một
khuôn mặt phông chữ đặc biệt (ví dụ, :math:`\mathsf{X}`,
:math:`\mathsf{Y}`, và :math:`\mathsf{Z}`) và cơ chế lập chỉ mục của
chúng (ví dụ, :math:`x_{ijk}` và :math:`[\mathsf{X}]_{1, 2i-1, 3}`)
tương tự như của ma trận.
Tensors sẽ trở nên quan trọng hơn khi chúng ta bắt đầu làm việc với hình
ảnh, đến các mảng :math:`n` chiều với 3 trục tương ứng với chiều cao,
chiều rộng và trục \* kênh\* để xếp các kênh màu (đỏ, xanh lá cây và
xanh dương). Hiện tại, chúng ta sẽ bỏ qua hàng chục bậc cao hơn và tập
trung vào những điều cơ bản.
.. raw:: html
.. raw:: html
.. code:: python
X = np.arange(24).reshape(2, 3, 4)
X
.. parsed-literal::
:class: output
array([[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]],
[[12., 13., 14., 15.],
[16., 17., 18., 19.],
[20., 21., 22., 23.]]])
.. raw:: html
.. raw:: html
.. code:: python
X = torch.arange(24).reshape(2, 3, 4)
X
.. parsed-literal::
:class: output
tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
.. raw:: html
.. raw:: html
.. code:: python
X = tf.reshape(tf.range(24), (2, 3, 4))
X
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Tính chất cơ bản của Tensor Arithmetic
--------------------------------------
Vô hướng, vectơ, ma trận, và hàng chục (“tensors” trong tiểu mục này đề
cập đến các đối tượng đại số) của một số trục tùy ý có một số tính chất
tốt đẹp thường có ích. Ví dụ, bạn có thể nhận thấy từ định nghĩa của một
phép toán elementwise rằng bất kỳ hoạt động đơn nguyên tố nào không thay
đổi hình dạng của toán hạng của nó. Tương tự như vậy, với bất kỳ hai
hàng chục có cùng hình dạng, kết quả của bất kỳ phép toán phần tử nhị
phân nào sẽ là một tensor của cùng một hình dạng đó Ví dụ, thêm hai ma
trận có cùng hình dạng thực hiện phép cộng elementwise trên hai ma trận
này.
.. raw:: html
.. raw:: html
.. code:: python
A = np.arange(20).reshape(5, 4)
B = A.copy() # Assign a copy of `A` to `B` by allocating new memory
A, A + B
.. parsed-literal::
:class: output
(array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
array([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.],
[32., 34., 36., 38.]]))
.. raw:: html
.. raw:: html
.. code:: python
A = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = A.clone() # Assign a copy of `A` to `B` by allocating new memory
A, A + B
.. parsed-literal::
:class: output
(tensor([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.],
[16., 17., 18., 19.]]),
tensor([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.],
[32., 34., 36., 38.]]))
.. raw:: html
.. raw:: html
.. code:: python
A = tf.reshape(tf.range(20, dtype=tf.float32), (5, 4))
B = A # No cloning of `A` to `B` by allocating new memory
A, A + B
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
Cụ thể, elementwise phép nhân của hai ma trận được gọi là sản phẩm \*
Hadamard\* của họ (ký hiệu toán :math:`\odot`). Xem xét ma trận
:math:`\mathbf{B} \in \mathbb{R}^{m \times n}` có phần tử của hàng
:math:`i` và cột :math:`j` là :math:`b_{ij}`. Sản phẩm Hadamard của ma
trận :math:`\mathbf{A}` (được định nghĩa trong :eq:`eq_matrix_def`)
và :math:`\mathbf{B}`
.. math::
\mathbf{A} \odot \mathbf{B} =
\begin{bmatrix}
a_{11} b_{11} & a_{12} b_{12} & \dots & a_{1n} b_{1n} \\
a_{21} b_{21} & a_{22} b_{22} & \dots & a_{2n} b_{2n} \\
\vdots & \vdots & \ddots & \vdots \\
a_{m1} b_{m1} & a_{m2} b_{m2} & \dots & a_{mn} b_{mn}
\end{bmatrix}.
.. raw:: html
.. raw:: html
.. code:: python
A * B
.. parsed-literal::
:class: output
array([[ 0., 1., 4., 9.],
[ 16., 25., 36., 49.],
[ 64., 81., 100., 121.],
[144., 169., 196., 225.],
[256., 289., 324., 361.]])
.. raw:: html
.. raw:: html
.. code:: python
A * B
.. parsed-literal::
:class: output
tensor([[ 0., 1., 4., 9.],
[ 16., 25., 36., 49.],
[ 64., 81., 100., 121.],
[144., 169., 196., 225.],
[256., 289., 324., 361.]])
.. raw:: html
.. raw:: html
.. code:: python
A * B
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Nhân hoặc thêm một tensor với vô hướng cũng không thay đổi hình dạng của
tensor, trong đó mỗi phần tử của tensor toán hạng sẽ được thêm hoặc nhân
với vô hướng.
.. raw:: html
.. raw:: html
.. code:: python
a = 2
X = np.arange(24).reshape(2, 3, 4)
a + X, (a * X).shape
.. parsed-literal::
:class: output
(array([[[ 2., 3., 4., 5.],
[ 6., 7., 8., 9.],
[10., 11., 12., 13.]],
[[14., 15., 16., 17.],
[18., 19., 20., 21.],
[22., 23., 24., 25.]]]),
(2, 3, 4))
.. raw:: html
.. raw:: html
.. code:: python
a = 2
X = torch.arange(24).reshape(2, 3, 4)
a + X, (a * X).shape
.. parsed-literal::
:class: output
(tensor([[[ 2, 3, 4, 5],
[ 6, 7, 8, 9],
[10, 11, 12, 13]],
[[14, 15, 16, 17],
[18, 19, 20, 21],
[22, 23, 24, 25]]]),
torch.Size([2, 3, 4]))
.. raw:: html
.. raw:: html
.. code:: python
a = 2
X = tf.reshape(tf.range(24), (2, 3, 4))
a + X, (a * X).shape
.. parsed-literal::
:class: output
(,
TensorShape([2, 3, 4]))
.. raw:: html
.. raw:: html
.. _subseq_lin-alg-reduction:
Giảm
----
Một thao tác hữu ích mà chúng ta có thể thực hiện với các hàng chục tùy
ý là tính toán tổng các phần tử của chúng. Trong ký hiệu toán học, chúng
ta thể hiện các khoản tiền bằng ký hiệu :math:`\sum`. Để thể hiện tổng
của các phần tử trong một vector :math:`\mathbf{x}` chiều dài :math:`d`,
chúng tôi viết :math:`\sum_{i=1}^d x_i`. Trong code, chúng ta chỉ có thể
gọi hàm để tính tổng.
.. raw:: html
.. raw:: html
.. code:: python
x = np.arange(4)
x, x.sum()
.. parsed-literal::
:class: output
(array([0., 1., 2., 3.]), array(6.))
.. raw:: html
.. raw:: html
.. code:: python
x = torch.arange(4, dtype=torch.float32)
x, x.sum()
.. parsed-literal::
:class: output
(tensor([0., 1., 2., 3.]), tensor(6.))
.. raw:: html
.. raw:: html
.. code:: python
x = tf.range(4, dtype=tf.float32)
x, tf.reduce_sum(x)
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
Chúng ta có thể diễn đạt tổng trên các phần tử của hàng chục hình dạng
tùy ý. Ví dụ, tổng các phần tử của ma trận :math:`m \times n`
:math:`\mathbf{A}` có thể được viết
:math:`\sum_{i=1}^{m} \sum_{j=1}^{n} a_{ij}`.
.. raw:: html
.. raw:: html
.. code:: python
A.shape, A.sum()
.. parsed-literal::
:class: output
((5, 4), array(190.))
.. raw:: html
.. raw:: html
.. code:: python
A.shape, A.sum()
.. parsed-literal::
:class: output
(torch.Size([5, 4]), tensor(190.))
.. raw:: html
.. raw:: html
.. code:: python
A.shape, tf.reduce_sum(A)
.. parsed-literal::
:class: output
(TensorShape([5, 4]), )
.. raw:: html
.. raw:: html
Theo mặc định, gọi hàm để tính tổng *giảm* một tensor dọc theo tất cả
các trục của nó đến một vô hướng. Chúng ta cũng có thể chỉ định các trục
dọc theo đó tensor được giảm thông qua tổng hợp. Lấy ma trận làm ví dụ.
Để giảm kích thước hàng (trục 0) bằng cách tổng hợp các phần tử của tất
cả các hàng, chúng tôi chỉ định ``axis=0`` khi gọi hàm. Vì ma trận đầu
vào giảm dọc theo trục 0 để tạo ra vectơ đầu ra, kích thước của trục 0
của đầu vào bị mất trong hình dạng đầu ra.
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape
.. parsed-literal::
:class: output
(array([40., 45., 50., 55.]), (4,))
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape
.. parsed-literal::
:class: output
(tensor([40., 45., 50., 55.]), torch.Size([4]))
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis0 = tf.reduce_sum(A, axis=0)
A_sum_axis0, A_sum_axis0.shape
.. parsed-literal::
:class: output
(,
TensorShape([4]))
.. raw:: html
.. raw:: html
Chỉ định ``axis=1`` sẽ giảm kích thước cột (trục 1) bằng cách tổng hợp
các phần tử của tất cả các cột. Do đó, kích thước của trục 1 của đầu vào
bị mất trong hình dạng đầu ra.
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis1 = A.sum(axis=1)
A_sum_axis1, A_sum_axis1.shape
.. parsed-literal::
:class: output
(array([ 6., 22., 38., 54., 70.]), (5,))
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis1 = A.sum(axis=1)
A_sum_axis1, A_sum_axis1.shape
.. parsed-literal::
:class: output
(tensor([ 6., 22., 38., 54., 70.]), torch.Size([5]))
.. raw:: html
.. raw:: html
.. code:: python
A_sum_axis1 = tf.reduce_sum(A, axis=1)
A_sum_axis1, A_sum_axis1.shape
.. parsed-literal::
:class: output
(,
TensorShape([5]))
.. raw:: html
.. raw:: html
Giảm một ma trận dọc theo cả hàng và cột thông qua tổng tương đương với
việc tổng hợp tất cả các phần tử của ma trận.
.. raw:: html
.. raw:: html
.. code:: python
A.sum(axis=[0, 1]) # Same as `A.sum()`
.. parsed-literal::
:class: output
array(190.)
.. raw:: html
.. raw:: html
.. code:: python
A.sum(axis=[0, 1]) # Same as `A.sum()`
.. parsed-literal::
:class: output
tensor(190.)
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_sum(A, axis=[0, 1]) # Same as `tf.reduce_sum(A)`
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Một số lượng liên quan là *mean*, còn được gọi là *trung bình*. Chúng
tôi tính trung bình bằng cách chia tổng cho tổng số phần tử. Trong mã,
chúng ta chỉ có thể gọi hàm để tính toán trung bình trên hàng chục hình
dạng tùy ý.
.. raw:: html
.. raw:: html
.. code:: python
A.mean(), A.sum() / A.size
.. parsed-literal::
:class: output
(array(9.5), array(9.5))
.. raw:: html
.. raw:: html
.. code:: python
A.mean(), A.sum() / A.numel()
.. parsed-literal::
:class: output
(tensor(9.5000), tensor(9.5000))
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_mean(A), tf.reduce_sum(A) / tf.size(A).numpy()
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
Tương tự như vậy, chức năng tính trung bình cũng có thể làm giảm tensor
dọc theo các trục được chỉ định.
.. raw:: html
.. raw:: html
.. code:: python
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
.. parsed-literal::
:class: output
(array([ 8., 9., 10., 11.]), array([ 8., 9., 10., 11.]))
.. raw:: html
.. raw:: html
.. code:: python
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
.. parsed-literal::
:class: output
(tensor([ 8., 9., 10., 11.]), tensor([ 8., 9., 10., 11.]))
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_mean(A, axis=0), tf.reduce_sum(A, axis=0) / A.shape[0]
.. parsed-literal::
:class: output
(,
)
.. raw:: html
.. raw:: html
.. _subseq_lin-alg-non-reduction:
Tổng không giảm
~~~~~~~~~~~~~~~
Tuy nhiên, đôi khi có thể hữu ích khi giữ số trục không thay đổi khi gọi
hàm tính tổng hoặc trung bình.
.. raw:: html
.. raw:: html
.. code:: python
sum_A = A.sum(axis=1, keepdims=True)
sum_A
.. parsed-literal::
:class: output
array([[ 6.],
[22.],
[38.],
[54.],
[70.]])
.. raw:: html
.. raw:: html
.. code:: python
sum_A = A.sum(axis=1, keepdims=True)
sum_A
.. parsed-literal::
:class: output
tensor([[ 6.],
[22.],
[38.],
[54.],
[70.]])
.. raw:: html
.. raw:: html
.. code:: python
sum_A = tf.reduce_sum(A, axis=1, keepdims=True)
sum_A
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Ví dụ, vì ``sum_A`` vẫn giữ hai trục của nó sau khi tổng hợp mỗi hàng,
chúng ta có thể chia ``A`` cho ``sum_A`` với phát sóng.
.. raw:: html
.. raw:: html
.. code:: python
A / sum_A
.. parsed-literal::
:class: output
array([[0. , 0.16666667, 0.33333334, 0.5 ],
[0.18181819, 0.22727273, 0.27272728, 0.3181818 ],
[0.21052632, 0.23684211, 0.2631579 , 0.28947368],
[0.22222222, 0.24074075, 0.25925925, 0.2777778 ],
[0.22857143, 0.24285714, 0.25714287, 0.27142859]])
.. raw:: html
.. raw:: html
.. code:: python
A / sum_A
.. parsed-literal::
:class: output
tensor([[0.0000, 0.1667, 0.3333, 0.5000],
[0.1818, 0.2273, 0.2727, 0.3182],
[0.2105, 0.2368, 0.2632, 0.2895],
[0.2222, 0.2407, 0.2593, 0.2778],
[0.2286, 0.2429, 0.2571, 0.2714]])
.. raw:: html
.. raw:: html
.. code:: python
A / sum_A
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Nếu chúng ta muốn tính toán tổng tích lũy của các phần tử của ``A`` dọc
theo một số trục , giả sử ``axis=0`` (từng hàng), chúng ta có thể gọi
hàm ``cumsum``. Chức năng này sẽ không làm giảm tensor đầu vào dọc theo
bất kỳ trục nào.
.. raw:: html
.. raw:: html
.. code:: python
A.cumsum(axis=0)
.. parsed-literal::
:class: output
array([[ 0., 1., 2., 3.],
[ 4., 6., 8., 10.],
[12., 15., 18., 21.],
[24., 28., 32., 36.],
[40., 45., 50., 55.]])
.. raw:: html
.. raw:: html
.. code:: python
A.cumsum(axis=0)
.. parsed-literal::
:class: output
tensor([[ 0., 1., 2., 3.],
[ 4., 6., 8., 10.],
[12., 15., 18., 21.],
[24., 28., 32., 36.],
[40., 45., 50., 55.]])
.. raw:: html
.. raw:: html
.. code:: python
tf.cumsum(A, axis=0)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Sản phẩm Dot
------------
Cho đến nay, chúng tôi chỉ thực hiện các hoạt động elementwise, tổng và
trung bình. Và nếu đây là tất cả những gì chúng ta có thể làm, đại số
tuyến tính có lẽ sẽ không xứng đáng với phần riêng của nó. Tuy nhiên,
một trong những hoạt động cơ bản nhất là sản phẩm chấm. Với hai vectơ
:math:`\mathbf{x}, \mathbf{y} \in \mathbb{R}^d`, sản phẩm *dot của họ*
:math:`\mathbf{x}^\top \mathbf{y}` (hoặc
:math:`\langle \mathbf{x}, \mathbf{y} \rangle`) là một tổng so với các
sản phẩm của các phần tử ở cùng một vị trí:
:math:`\mathbf{x}^\top \mathbf{y} = \sum_{i=1}^{d} x_i y_i`.
.. raw:: html
.. raw:: html
.. code:: python
y = np.ones(4)
x, y, np.dot(x, y)
.. parsed-literal::
:class: output
(array([0., 1., 2., 3.]), array([1., 1., 1., 1.]), array(6.))
.. raw:: html
.. raw:: html
.. code:: python
y = torch.ones(4, dtype = torch.float32)
x, y, torch.dot(x, y)
.. parsed-literal::
:class: output
(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))
.. raw:: html
.. raw:: html
.. code:: python
y = tf.ones(4, dtype=tf.float32)
x, y, tf.tensordot(x, y, axes=1)
.. parsed-literal::
:class: output
(,
,
)
.. raw:: html
.. raw:: html
Lưu ý rằng chúng ta có thể diễn đạt tích chấm của hai vectơ tương đương
bằng cách thực hiện phép nhân elementwise và sau đó là tổng:
.. raw:: html
.. raw:: html
.. code:: python
np.sum(x * y)
.. parsed-literal::
:class: output
array(6.)
.. raw:: html
.. raw:: html
.. code:: python
torch.sum(x * y)
.. parsed-literal::
:class: output
tensor(6.)
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_sum(x * y)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Các sản phẩm Dot rất hữu ích trong một loạt các bối cảnh. Ví dụ, cho một
số tập hợp các giá trị, được biểu thị bằng một vectơ
:math:`\mathbf{x} \in \mathbb{R}^d` và một tập hợp trọng số được ký hiệu
bởi :math:`\mathbf{w} \in \mathbb{R}^d`, tổng trọng số của các giá trị
trong :math:`\mathbf{x}` theo trọng lượng :math:`\mathbf{w}` có thể được
biểu thị dưới dạng sản phẩm chấm :math:`\mathbf{x}^\top \mathbf{w}`. Khi
trọng lượng không âm và tổng thành một (tức là
:math:`\left(\sum_{i=1}^{d} {w_i} = 1\right)`), sản phẩm chấm biểu thị
trung bình \* có trọng lự\ *. Sau khi bình thường hóa hai vectơ để có
chiều dài đơn vị, các sản phẩm chấm thể hiện cosin của góc giữa chúng.
Chúng tôi sẽ chính thức giới thiệu khái niệm này là * chiều dài\* sau
trong phần này.
Matrix-Vector Sản phẩm
----------------------
Bây giờ chúng ta đã biết cách tính toán các sản phẩm chấm, chúng ta có
thể bắt đầu hiểu các sản phẩm *ma thuật-vectơ *. Nhớ lại ma trận
:math:`\mathbf{A} \in \mathbb{R}^{m \times n}` và vector
:math:`\mathbf{x} \in \mathbb{R}^n` được xác định và hình dung trong
:eq:`eq_matrix_def` và :eq:`eq_vec_def` tương ứng. Hãy để
chúng tôi bắt đầu bằng cách hình dung ma trận :math:`\mathbf{A}` về
vectơ hàng của nó
.. math::
\mathbf{A}=
\begin{bmatrix}
\mathbf{a}^\top_{1} \\
\mathbf{a}^\top_{2} \\
\vdots \\
\mathbf{a}^\top_m \\
\end{bmatrix},
trong đó mỗi :math:`\mathbf{a}^\top_{i} \in \mathbb{R}^n` là một vectơ
hàng đại diện cho hàng :math:`i^\mathrm{th}` của ma trận
:math:`\mathbf{A}`.
Sản phẩm ma trận-vector :math:`\mathbf{A}\mathbf{x}` chỉ đơn giản là một
vector cột có chiều dài :math:`m`, có :math:`i^\mathrm{th}` phần tử là
sản phẩm chấm :math:`\mathbf{a}^\top_i \mathbf{x}`:
.. math::
\mathbf{A}\mathbf{x}
= \begin{bmatrix}
\mathbf{a}^\top_{1} \\
\mathbf{a}^\top_{2} \\
\vdots \\
\mathbf{a}^\top_m \\
\end{bmatrix}\mathbf{x}
= \begin{bmatrix}
\mathbf{a}^\top_{1} \mathbf{x} \\
\mathbf{a}^\top_{2} \mathbf{x} \\
\vdots\\
\mathbf{a}^\top_{m} \mathbf{x}\\
\end{bmatrix}.
Chúng ta có thể nghĩ đến phép nhân của một ma trận
:math:`\mathbf{A}\in \mathbb{R}^{m \times n}` như một biến đổi dự án
vectơ từ :math:`\mathbb{R}^{n}` đến :math:`\mathbb{R}^{m}`. Những biến
đổi này trở nên hữu ích đáng kể. Ví dụ, chúng ta có thể biểu diễn các
vòng quay dưới dạng phép nhân bằng một ma trận vuông. Như chúng ta sẽ
thấy trong các chương tiếp theo, chúng ta cũng có thể sử dụng các sản
phẩm ma thuật-vector để mô tả các phép tính chuyên sâu nhất cần thiết
khi tính toán từng lớp trong mạng thần kinh với các giá trị của lớp
trước đó.
.. raw:: html
.. raw:: html
Thể hiện các sản phẩm ma thuật-vector trong mã với hàng chục, chúng tôi
sử dụng chức năng ``dot`` tương tự như đối với các sản phẩm chấm. Khi
chúng ta gọi ``np.dot(A, x)`` với ma trận ``A`` và một vector ``x``, sản
phẩm ma thuật-vector được thực hiện. Lưu ý rằng kích thước cột ``A``
(chiều dài của nó dọc theo trục 1) phải giống với kích thước ``x``
(chiều dài của nó).
.. code:: python
A.shape, x.shape, np.dot(A, x)
.. parsed-literal::
:class: output
((5, 4), (4,), array([ 14., 38., 62., 86., 110.]))
.. raw:: html
.. raw:: html
Thể hiện các sản phẩm ma thuật-vector trong mã với hàng chục, chúng tôi
sử dụng hàm ``mv``. Khi chúng ta gọi ``torch.mv(A, x)`` với ma trận
``A`` và một vector ``x``, sản phẩm ma thuật-vector được thực hiện. Lưu
ý rằng kích thước cột của ``A`` (chiều dài của nó dọc theo trục 1) phải
giống với kích thước ``x`` (chiều dài của nó).
.. code:: python
A.shape, x.shape, torch.mv(A, x)
.. parsed-literal::
:class: output
(torch.Size([5, 4]), torch.Size([4]), tensor([ 14., 38., 62., 86., 110.]))
.. raw:: html
.. raw:: html
Thể hiện các sản phẩm ma thuật-vector trong mã với hàng chục, chúng tôi
sử dụng hàm ``matvec``. Khi chúng ta gọi ``tf.linalg.matvec(A, x)`` với
ma trận ``A`` và một vector ``x``, sản phẩm ma thuật-vector được thực
hiện. Lưu ý rằng kích thước cột ``A`` (chiều dài của nó dọc theo trục 1)
phải giống với kích thước ``x`` (chiều dài của nó).
.. code:: python
A.shape, x.shape, tf.linalg.matvec(A, x)
.. parsed-literal::
:class: output
(TensorShape([5, 4]),
TensorShape([4]),
)
.. raw:: html
.. raw:: html
Phép nhân ma trận ma trận
-------------------------
Nếu bạn đã nhận được sự treo của các sản phẩm chấm và các sản phẩm ma
thuật-vector, thì nhân \* ma trận ma trận \* phải đơn giản.
Nói rằng chúng ta có hai ma trận
:math:`\mathbf{A} \in \mathbb{R}^{n \times k}` và
:math:`\mathbf{B} \in \mathbb{R}^{k \times m}`:
.. math::
\mathbf{A}=\begin{bmatrix}
a_{11} & a_{12} & \cdots & a_{1k} \\
a_{21} & a_{22} & \cdots & a_{2k} \\
\vdots & \vdots & \ddots & \vdots \\
a_{n1} & a_{n2} & \cdots & a_{nk} \\
\end{bmatrix},\quad
\mathbf{B}=\begin{bmatrix}
b_{11} & b_{12} & \cdots & b_{1m} \\
b_{21} & b_{22} & \cdots & b_{2m} \\
\vdots & \vdots & \ddots & \vdots \\
b_{k1} & b_{k2} & \cdots & b_{km} \\
\end{bmatrix}.
Biểu thị bằng :math:`\mathbf{a}^\top_{i} \in \mathbb{R}^k` vector hàng
đại diện cho hàng :math:`i^\mathrm{th}` của ma trận :math:`\mathbf{A}`,
và để cho :math:`\mathbf{b}_{j} \in \mathbb{R}^k` là vectơ cột từ cột
:math:`j^\mathrm{th}` của ma trận :math:`\mathbf{B}`. Để sản xuất sản
phẩm ma trận :math:`\mathbf{C} = \mathbf{A}\mathbf{B}`, dễ nhất là nghĩ
đến :math:`\mathbf{A}` về vectơ hàng và :math:`\mathbf{B}` về vectơ cột
của nó:
.. math::
\mathbf{A}=
\begin{bmatrix}
\mathbf{a}^\top_{1} \\
\mathbf{a}^\top_{2} \\
\vdots \\
\mathbf{a}^\top_n \\
\end{bmatrix},
\quad \mathbf{B}=\begin{bmatrix}
\mathbf{b}_{1} & \mathbf{b}_{2} & \cdots & \mathbf{b}_{m} \\
\end{bmatrix}.
Sau đó, sản phẩm ma trận :math:`\mathbf{C} \in \mathbb{R}^{n \times m}`
được sản xuất như chúng ta chỉ đơn giản là tính toán từng phần tử
:math:`c_{ij}` như là sản phẩm chấm
:math:`\mathbf{a}^\top_i \mathbf{b}_j`:
.. math::
\mathbf{C} = \mathbf{AB} = \begin{bmatrix}
\mathbf{a}^\top_{1} \\
\mathbf{a}^\top_{2} \\
\vdots \\
\mathbf{a}^\top_n \\
\end{bmatrix}
\begin{bmatrix}
\mathbf{b}_{1} & \mathbf{b}_{2} & \cdots & \mathbf{b}_{m} \\
\end{bmatrix}
= \begin{bmatrix}
\mathbf{a}^\top_{1} \mathbf{b}_1 & \mathbf{a}^\top_{1}\mathbf{b}_2& \cdots & \mathbf{a}^\top_{1} \mathbf{b}_m \\
\mathbf{a}^\top_{2}\mathbf{b}_1 & \mathbf{a}^\top_{2} \mathbf{b}_2 & \cdots & \mathbf{a}^\top_{2} \mathbf{b}_m \\
\vdots & \vdots & \ddots &\vdots\\
\mathbf{a}^\top_{n} \mathbf{b}_1 & \mathbf{a}^\top_{n}\mathbf{b}_2& \cdots& \mathbf{a}^\top_{n} \mathbf{b}_m
\end{bmatrix}.
Chúng ta có thể nghĩ đến phép nhân ma trận ma trận :math:`\mathbf{AB}`
chỉ đơn giản là thực hiện :math:`m` các sản phẩm ma trận vector và khâu
kết quả lại với nhau để tạo thành ma trận :math:`n \times m` Trong đoạn
mã sau, chúng tôi thực hiện phép nhân ma trận trên ``A`` và ``B``. Ở
đây, ``A`` là một ma trận với 5 hàng và 4 cột, và ``B`` là một ma trận
với 4 hàng và 3 cột. Sau khi nhân, chúng ta có được một ma trận với 5
hàng và 3 cột.
.. raw:: html
.. raw:: html
.. code:: python
B = np.ones(shape=(4, 3))
np.dot(A, B)
.. parsed-literal::
:class: output
array([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]])
.. raw:: html
.. raw:: html
.. code:: python
B = torch.ones(4, 3)
torch.mm(A, B)
.. parsed-literal::
:class: output
tensor([[ 6., 6., 6.],
[22., 22., 22.],
[38., 38., 38.],
[54., 54., 54.],
[70., 70., 70.]])
.. raw:: html
.. raw:: html
.. code:: python
B = tf.ones((4, 3), tf.float32)
tf.matmul(A, B)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Phép nhân ma trận ma trận có thể được gọi đơn giản là nhân *ma trận *,
và không nên nhầm lẫn với sản phẩm Hadamard.
.. _subsec_lin-algebra-norms:
Định mức
--------
Một số toán tử hữu ích nhất trong đại số tuyến tính là \* chỉ tiêu *.
Một cách không chính thức, định mức của một vector cho chúng ta biết
cách * lớn\* một vectơ là. Khái niệm về kích thước\* đang được xem xét ở
đây không liên quan đến chiều mà là độ lớn của các thành phần.
Trong đại số tuyến tính, một định mức vectơ là một hàm :math:`f` ánh xạ
một vectơ đến vô hướng, thỏa mãn một số ít các thuộc tính. Với bất kỳ
vector :math:`\mathbf{x}` nào, thuộc tính đầu tiên nói rằng nếu chúng ta
quy mô tất cả các phần tử của một vectơ bằng một hệ số không đổi
:math:`\alpha`, định mức của nó cũng quy mô theo giá trị \* tuyệt đối \*
của cùng một yếu tố không đổi:
.. math:: f(\alpha \mathbf{x}) = |\alpha| f(\mathbf{x}).
Tính chất thứ hai là bất đẳng thức tam giác quen thuộc:
.. math:: f(\mathbf{x} + \mathbf{y}) \leq f(\mathbf{x}) + f(\mathbf{y}).
Tài sản thứ ba chỉ đơn giản nói rằng định mức phải không tiêu cực:
.. math:: f(\mathbf{x}) \geq 0.
Điều đó có ý nghĩa, như trong hầu hết các bối cảnh, \* kích thước\* nhỏ
nhất cho bất cứ điều gì là 0. Thuộc tính cuối cùng yêu cầu định mức nhỏ
nhất đạt được và chỉ đạt được bằng một vectơ bao gồm tất cả các số
không.
.. math:: \forall i, [\mathbf{x}]_i = 0 \Leftrightarrow f(\mathbf{x})=0.
Bạn có thể nhận thấy rằng các định mức âm thanh rất giống với các biện
pháp khoảng cách. Và nếu bạn nhớ khoảng cách Euclide (nghĩ rằng định lý
Pythagoras) từ trường lớp, thì các khái niệm về không tiêu cực và bất
bình đẳng tam giác có thể rung chuông. Trên thực tế, khoảng cách Euclide
là một tiêu chuẩn: cụ thể nó là định mức :math:`L_2`. Giả sử rằng các
yếu tố trong vector :math:`n` chiều :math:`\mathbf{x}` là
:math:`x_1, \ldots, x_n`.
:math:`L_2` *norm* của :math:`\mathbf{x}` là căn bậc hai của tổng các ô
vuông của các phần tử vectơ:
.. math:: \|\mathbf{x}\|_2 = \sqrt{\sum_{i=1}^n x_i^2},
trong đó chỉ số dưới :math:`2` thường bị bỏ qua trong :math:`L_2` chỉ
tiêu, tức là :math:`\|\mathbf{x}\|` tương đương với
:math:`\|\mathbf{x}\|_2`. Trong mã, chúng ta có thể tính định mức
:math:`L_2` của một vectơ như sau.
.. raw:: html
.. raw:: html
.. code:: python
u = np.array([3, -4])
np.linalg.norm(u)
.. parsed-literal::
:class: output
array(5.)
.. raw:: html
.. raw:: html
.. code:: python
u = torch.tensor([3.0, -4.0])
torch.norm(u)
.. parsed-literal::
:class: output
tensor(5.)
.. raw:: html
.. raw:: html
.. code:: python
u = tf.constant([3.0, -4.0])
tf.norm(u)
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Trong học sâu, chúng tôi làm việc thường xuyên hơn với định mức
:math:`L_2` bình phương.
Bạn cũng sẽ thường xuyên gặp phải the :math:`L_1` *norm*, được biểu thị
dưới dạng tổng các giá trị tuyệt đối của các phần tử vectơ:
.. math:: \|\mathbf{x}\|_1 = \sum_{i=1}^n \left|x_i \right|.
So với định mức :math:`L_2`, nó ít bị ảnh hưởng bởi outliers. Để tính
định mức :math:`L_1`, ta soạn hàm giá trị tuyệt đối với một tổng trên
các phần tử.
.. raw:: html
.. raw:: html
.. code:: python
np.abs(u).sum()
.. parsed-literal::
:class: output
array(7.)
.. raw:: html
.. raw:: html
.. code:: python
torch.abs(u).sum()
.. parsed-literal::
:class: output
tensor(7.)
.. raw:: html
.. raw:: html
.. code:: python
tf.reduce_sum(tf.abs(u))
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
Cả định mức :math:`L_2` và định mức :math:`L_1` đều là những trường hợp
đặc biệt của :math:`L_p` \* tiêu chuẩn\* chung hơn:
.. math:: \|\mathbf{x}\|_p = \left(\sum_{i=1}^n \left|x_i \right|^p \right)^{1/p}.
Tương tự như định mức :math:`L_2` của vectơ, chuẩn *Frobenius* của ma
trận :math:`\mathbf{X} \in \mathbb{R}^{m \times n}` là căn bậc hai của
tổng bình phương của các phần tử ma trận:
.. math:: \|\mathbf{X}\|_F = \sqrt{\sum_{i=1}^m \sum_{j=1}^n x_{ij}^2}.
Định mức Frobenius thỏa mãn tất cả các thuộc tính của các chỉ tiêu
vector. Nó hoạt động như thể nó là một định mức :math:`L_2` của một
vectơ hình ma trận. Gọi hàm sau sẽ tính định mức Frobenius của một ma
trận.
.. raw:: html
.. raw:: html
.. code:: python
np.linalg.norm(np.ones((4, 9)))
.. parsed-literal::
:class: output
array(6.)
.. raw:: html
.. raw:: html
.. code:: python
torch.norm(torch.ones((4, 9)))
.. parsed-literal::
:class: output
tensor(6.)
.. raw:: html
.. raw:: html
.. code:: python
tf.norm(tf.ones((4, 9)))
.. parsed-literal::
:class: output
.. raw:: html
.. raw:: html
.. _subsec_norms_and_objectives:
Định mức và mục tiêu
~~~~~~~~~~~~~~~~~~~~
Mặc dù chúng ta không muốn vượt quá xa bản thân, chúng ta có thể trồng
một số trực giác về lý do tại sao những khái niệm này hữu ích. Trong học
sâu, chúng ta thường cố gắng giải quyết các vấn đề tối ưu hóa: *tối đa
hóa* xác suất được gán cho dữ liệu quan sát; *giảm xuống* khoảng cách
giữa các dự đoán and the ground-truth đất sự thật observations quan sát.
Gán biểu diễn vector cho các mục (như từ, sản phẩm hoặc bài báo tin tức)
sao cho khoảng cách giữa các mục tương tự được giảm thiểu và khoảng cách
giữa các mục khác nhau được tối đa hóa. Thông thường, các mục tiêu, có
lẽ là các thành phần quan trọng nhất của các thuật toán học sâu (bên
cạnh dữ liệu), được thể hiện dưới dạng định mức.
Tìm hiểu thêm về Linear Algebra
-------------------------------
Chỉ trong phần này, chúng tôi đã dạy bạn tất cả các đại số tuyến tính mà
bạn sẽ cần phải hiểu một phần đáng chú ý của học sâu hiện đại. Có rất
nhiều hơn để đại số tuyến tính và rất nhiều toán học đó rất hữu ích cho
việc học máy. Ví dụ, ma trận có thể bị phân hủy thành các yếu tố, và
những phân hủy này có thể tiết lộ cấu trúc chiều thấp trong các bộ dữ
liệu thế giới thực. Có toàn bộ trường con của machine learning tập trung
vào việc sử dụng các phân hủy ma trận và khái quát hóa của chúng cho các
hàng chục bậc cao để khám phá cấu trúc trong bộ dữ liệu và giải quyết
các vấn đề dự đoán. Nhưng cuốn sách này tập trung vào việc học sâu. Và
chúng tôi tin rằng bạn sẽ có xu hướng tìm hiểu thêm toán học hơn một khi
bạn đã nhận được bàn tay của bạn bẩn triển khai các mô hình máy học hữu
ích trên các bộ dữ liệu thực. Vì vậy, trong khi chúng tôi có quyền giới
thiệu nhiều toán học hơn nhiều sau này, chúng tôi sẽ kết thúc phần này ở
đây.
Nếu bạn muốn tìm hiểu thêm về đại số tuyến tính, bạn có thể tham khảo
`online appendix on linear algebraic
operations `__
hoặc các tài nguyên tuyệt vời khác
:cite:`Strang.1993,Kolter.2008,Petersen.Pedersen.ea.2008`.
Tóm tắt
-------
- Vô hướng, vectơ, ma trận, và hàng chục là các đối tượng toán học cơ
bản trong đại số tuyến tính.
- Vectơ tổng quát hóa vô hướng, và ma trận tổng quát hóa vectơ.
- Vô hướng, vectơ, ma trận và hàng chục có số không, một, hai và một số
trục tùy ý, tương ứng.
- Một tensor có thể được giảm dọc theo các trục được chỉ định bởi
``sum`` và ``mean``.
- Nhân Elementwise của hai ma trận được gọi là sản phẩm Hadamard của
họ. Nó khác với phép nhân ma trận.
- Trong học sâu, chúng ta thường làm việc với các tiêu chuẩn như định
mức :math:`L_1`, định mức :math:`L_2` và định mức Frobenius.
- Chúng ta có thể thực hiện một loạt các hoạt động trên vô hướng,
vectơ, ma trận và hàng chục.
Bài tập
-------
1. Chứng minh rằng sự chuyển vị của một ma trận :math:`\mathbf{A}`
transpose là
:math:`\mathbf{A}`::math:`(\mathbf{A}^\top)^\top = \mathbf{A}`.
2. Cho hai ma trận :math:`\mathbf{A}` và :math:`\mathbf{B}`, cho thấy
tổng các transposes bằng chuyển vị của một tổng:
:math:`\mathbf{A}^\top + \mathbf{B}^\top = (\mathbf{A} + \mathbf{B})^\top`.
3. Cho bất kỳ ma trận vuông :math:`\mathbf{A}`, là
:math:`\mathbf{A} + \mathbf{A}^\top` luôn đối xứng? Tại sao?
4. Chúng tôi xác định tensor ``X`` của hình dạng (2, 3, 4) trong phần
này. Sản lượng của ``len(X)`` là gì?
5. Đối với một tensor ``X`` có hình dạng tùy ý, liệu ``len(X)`` luôn
tương ứng với chiều dài của một trục nhất định là ``X`` không? Trục
đó là gì?
6. Chạy ``A / A.sum(axis=1)`` và xem những gì sẽ xảy ra. Bạn có thể phân
tích lý do?
7. Khi đi du lịch giữa hai điểm ở Manhattan, khoảng cách mà bạn cần bao
gồm về tọa độ, tức là về con đường và đường phố là bao nhiêu? Bạn có
thể đi du lịch theo đường chéo?
8. Xem xét một tensor với hình dạng (2, 3, 4). Các hình dạng của đầu ra
tổng kết dọc theo trục 0, 1 và 2 là gì?
9. Nạp một tensor với 3 trục trở lên đến chức năng ``linalg.norm`` và
quan sát đầu ra của nó. Chức năng này tính toán gì cho hàng chục hình
dạng tùy ý?
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html
`Discussions `__
.. raw:: html
.. raw:: html