Hồi quy Softmax Python từ đầu

Một thẻ đã tồn tại với tên chi nhánh được cung cấp. Nhiều lệnh Git chấp nhận cả tên thẻ và tên nhánh, vì vậy việc tạo nhánh này có thể gây ra hành vi không mong muốn. Bạn có chắc chắn muốn tạo nhánh này không?

Vì hồi quy softmax rất cơ bản nên chúng tôi tin rằng bạn nên biết cách tự thực hiện nó. Ở đây, chúng tôi giới hạn bản thân trong việc xác định các khía cạnh dành riêng cho softmax của mô hình và sử dụng lại các thành phần khác từ phần hồi quy tuyến tính của chúng tôi, bao gồm cả vòng đào tạo

import torch
from d2l import torch as d2l

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)

import tensorflow as tf
from d2l import tensorflow as d2l

4. 4. 1. Softmax

Hãy bắt đầu với phần quan trọng nhất. ánh xạ từ vô hướng sang xác suất. Để ôn lại, hãy nhớ lại hoạt động của toán tử tổng theo các thứ nguyên cụ thể trong một tenxơ, như đã thảo luận trong và. Cho một ma trận

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
9, chúng ta có thể tính tổng trên tất cả các phần tử (theo mặc định) hoặc chỉ trên các phần tử trong cùng một trục. Biến
X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
0 cho phép chúng ta tính tổng hàng và cột

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))

X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)

(array([[5., 7., 9.]]),
 array([[ 6.],
        [15.]]))

X = jnp.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
0

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
1

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
2

Tính toán softmax yêu cầu ba bước. (i) lũy thừa của mỗi số hạng;

(4. 4. 1) \[\mathrm{softmax}(\mathbf{X})_{ij} = \frac{\exp(\mathbf{X}_{ij})}{\sum_k . \]

Mẫu số (logarit của) được gọi là hàm phân hoạch (log). Nó được giới thiệu trong vật lý thống kê để tổng hợp tất cả các trạng thái có thể có trong một quần thể nhiệt động lực học. Việc thực hiện là đơn giản

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
3

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
4

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
5

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
6

Đối với bất kỳ đầu vào

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
9 nào, chúng tôi biến từng phần tử thành một số không âm. Mỗi hàng có tổng bằng 1, theo yêu cầu đối với xác suất. thận trọng. đoạn mã trên không mạnh đối với các đối số rất lớn hoặc rất nhỏ. Mặc dù điều này đủ để minh họa những gì đang xảy ra, nhưng bạn không nên sử dụng nguyên văn mã này cho bất kỳ mục đích nghiêm trọng nào. Các khung học sâu có tích hợp các biện pháp bảo vệ như vậy và chúng tôi sẽ sử dụng softmax tích hợp trong tương lai

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
7

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
8

from mxnet import autograd, gluon, np, npx
from d2l import mxnet as d2l

npx.set_np()
9

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
0

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
1

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
2

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
3

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
4

4. 4. 2. Mô hình

Bây giờ chúng ta có mọi thứ cần thiết để triển khai mô hình hồi quy softmax. Như trong ví dụ hồi quy tuyến tính của chúng tôi, mỗi trường hợp sẽ được biểu thị bằng một vectơ có độ dài cố định. Vì dữ liệu thô ở đây bao gồm \(28 \times 28\) ảnh pixel nên chúng tôi làm phẳng từng ảnh, coi chúng là các vectơ có độ dài 784. Trong các chương sau, chúng tôi sẽ giới thiệu các mạng thần kinh tích chập, khai thác cấu trúc không gian theo cách thỏa mãn hơn.

Trong hồi quy softmax, số lượng đầu ra từ mạng của chúng tôi phải bằng số lượng lớp. Vì tập dữ liệu của chúng tôi có 10 lớp nên mạng của chúng tôi có kích thước đầu ra là 10. Do đó, các trọng số của chúng ta tạo thành một ma trận \(784 \times 10\) cộng với một \(1 \times 10 . Như với hồi quy tuyến tính, chúng tôi khởi tạo các trọng số

X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
2 với nhiễu Gaussian. Các thành kiến ​​​​được khởi tạo là số không. dimensional row vector for the biases. As with linear regression, we initialize the weights
X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
2 with Gaussian noise. The biases are initialized as zeros.

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
5

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
6

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
7

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
8

Mã bên dưới xác định cách mạng ánh xạ từng đầu vào thành đầu ra. Lưu ý rằng chúng tôi làm phẳng từng \(28 \times 28\) ảnh pixel trong lô thành một vectơ bằng cách sử dụng

X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
3 trước khi chuyển dữ liệu qua mô hình của chúng tôi.

from functools import partial
import jax
from flax import linen as nn
from jax import numpy as jnp
from d2l import jax as d2l
9

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
0

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
1

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
2

4. 4. 3. Mất Entropy chéo

Tiếp theo, chúng ta cần triển khai hàm mất entropy chéo (được giới thiệu trong ). Đây có thể là hàm mất mát phổ biến nhất trong tất cả các phương pháp học sâu. Hiện tại, các ứng dụng của học sâu dễ dàng tạo ra các vấn đề phân loại vượt xa những vấn đề được coi là vấn đề hồi quy tốt hơn

Hãy nhớ lại rằng entropy chéo có khả năng ghi nhật ký âm của xác suất dự đoán được gán cho nhãn thực. Để đạt hiệu quả, chúng tôi tránh các vòng lặp Python và thay vào đó sử dụng lập chỉ mục. Cụ thể, mã hóa một lần nóng trong \(\mathbf{y}\) cho phép chúng tôi chọn các thuật ngữ phù hợp trong \(\hat{\mathbf{y}}\).

Để thấy điều này trong thực tế, chúng tôi tạo dữ liệu mẫu

X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
4 với 2 ví dụ về xác suất dự đoán trên 3 lớp và nhãn tương ứng của chúng
X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
5. Các nhãn chính xác là \(0\)\(2\) respectively (i.e., the first and third class). Using
X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
5 as the indices of the probabilities in
X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
4, we can pick out terms efficiently.

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
3

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
4

Bây giờ chúng ta có thể triển khai hàm mất entropy chéo bằng cách lấy trung bình trên logarit của các xác suất đã chọn

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
5

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
6

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
7

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
8

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
9

Bây giờ chúng ta có thể triển khai hàm mất entropy chéo bằng cách lấy trung bình trên logarit của các xác suất đã chọn

import tensorflow as tf
from d2l import tensorflow as d2l
0

import tensorflow as tf
from d2l import tensorflow as d2l
1

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
7

import tensorflow as tf
from d2l import tensorflow as d2l
3

import tensorflow as tf
from d2l import tensorflow as d2l
4

Bây giờ chúng ta có thể triển khai hàm mất entropy chéo bằng cách lấy trung bình trên logarit của các xác suất đã chọn

Lưu ý rằng để sử dụng

X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
8 nhằm tăng tốc độ triển khai JAX và để đảm bảo rằng
X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
9 là một hàm thuần túy, thì hàm
(array([[5., 7., 9.]]),
 array([[ 6.],
        [15.]]))
0 được xác định lại bên trong
X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
9 để tránh việc sử dụng bất kỳ biến hoặc hàm toàn cục nào có thể khiến hàm
X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
9 không thuần túy. Chúng tôi giới thiệu những độc giả quan tâm đến trên
X = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
8 và các hàm thuần túy

import tensorflow as tf
from d2l import tensorflow as d2l
5

import tensorflow as tf
from d2l import tensorflow as d2l
6

import tensorflow as tf
from d2l import tensorflow as d2l
7

import tensorflow as tf
from d2l import tensorflow as d2l
8

import tensorflow as tf
from d2l import tensorflow as d2l
9

Bây giờ chúng ta có thể triển khai hàm mất entropy chéo bằng cách lấy trung bình trên logarit của các xác suất đã chọn

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
0

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
1

No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
7

4. 4. 4. Đào tạo

Chúng tôi sử dụng lại phương pháp

(array([[5., 7., 9.]]),
 array([[ 6.],
        [15.]]))
4 được xác định trong để đào tạo mô hình với 10 kỷ nguyên. Lưu ý rằng cả số lượng kỷ nguyên (
(array([[5., 7., 9.]]),
 array([[ 6.],
        [15.]]))
5), kích thước lô nhỏ (
(array([[5., 7., 9.]]),
 array([[ 6.],
        [15.]]))
6) và tốc độ học tập (
(array([[5., 7., 9.]]),
 array([[ 6.],
        [15.]]))
7) đều là các siêu tham số có thể điều chỉnh. Điều đó có nghĩa là mặc dù các giá trị này không được học trong vòng đào tạo chính của chúng tôi, nhưng chúng vẫn ảnh hưởng đến hiệu suất của mô hình, đào tạo bot trực quan và hiệu suất tổng quát hóa. Trong thực tế, bạn sẽ muốn chọn các giá trị này dựa trên phân tách xác thực của dữ liệu và sau đó để đánh giá cuối cùng mô hình cuối cùng của bạn trên phân tách thử nghiệm. Như đã thảo luận trong phần , chúng tôi sẽ coi dữ liệu thử nghiệm của Fashion-MNIST là bộ xác thực, do đó báo cáo độ chính xác của việc mất xác thực và độ chính xác của quá trình xác thực trong lần phân chia này

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
3

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
3

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
3

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
3

4. 4. 5. Dự đoán

Bây giờ quá trình đào tạo đã hoàn tất, mô hình của chúng tôi đã sẵn sàng để phân loại một số hình ảnh

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
7

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
8

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdims=True), X.sum(1, keepdims=True)
7

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
0

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
1

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
0

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
3

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
4

Chúng tôi quan tâm nhiều hơn đến những hình ảnh chúng tôi dán nhãn không chính xác. Chúng tôi trực quan hóa chúng bằng cách so sánh nhãn thực tế của chúng (dòng đầu tiên của văn bản đầu ra) với các dự đoán từ mô hình (dòng đầu ra văn bản thứ hai)

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
5

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
6

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
6

(tensor([[5., 7., 9.]]),
 tensor([[ 6.],
         [15.]]))
8

4. 4. 6. Tóm tắt

Bây giờ chúng ta bắt đầu có một số kinh nghiệm với việc giải các bài toán phân loại và hồi quy tuyến tính. Với nó, chúng tôi đã đạt được thứ được cho là đỉnh cao của nghệ thuật mô hình thống kê những năm 1960-1970. Trong phần tiếp theo, chúng tôi sẽ chỉ cho bạn cách tận dụng các framework deep learning để triển khai mô hình này hiệu quả hơn nhiều

4. 4. 7. Bài tập

  1. Trong phần này, chúng tôi trực tiếp triển khai hàm softmax dựa trên định nghĩa toán học của phép toán softmax. Như đã thảo luận trong điều này có thể gây ra sự mất ổn định về số

    1. Kiểm tra xem

      (array([[5., 7., 9.]]),
       array([[ 6.],
              [15.]]))
      
      8 có còn hoạt động chính xác hay không nếu đầu vào có giá trị \(100\) ?

    2. Kiểm tra xem

      (array([[5., 7., 9.]]),
       array([[ 6.],
              [15.]]))
      
      8 có còn hoạt động chính xác hay không nếu giá trị đầu vào lớn nhất trong số tất cả đầu vào nhỏ hơn \(-100\) ?

    3. Thực hiện sửa lỗi bằng cách xem giá trị liên quan đến mục nhập lớn nhất trong đối số

  2. Triển khai hàm

    (array([[5., 7., 9.]]),
     array([[ 6.],
            [15.]]))
    
    0 tuân theo định nghĩa của hàm mất entropy chéo \(\sum_i y_i \log \hat{y}_i\).

    1. Hãy dùng thử trong ví dụ mã ở trên

    2. Tại sao bạn nghĩ rằng nó chạy chậm hơn?

    3. Bạn có nên sử dụng nó?

    4. Bạn cần cẩn thận điều gì? . xét miền của logarit

  3. Có phải lúc nào cũng nên trả lại nhãn có khả năng nhất không?

  4. Giả sử rằng chúng tôi muốn sử dụng hồi quy softmax để dự đoán từ tiếp theo dựa trên một số tính năng. Một số vấn đề có thể phát sinh từ một vốn từ vựng lớn là gì?

  5. Thử nghiệm với các siêu tham số của đoạn mã trên. Đặc biệt

    1. Biểu đồ cách mất xác thực thay đổi khi bạn thay đổi tốc độ học tập

    2. Việc xác nhận và mất mát đào tạo có thay đổi khi bạn thay đổi kích thước minibatch không?