Vanilla GD trong Python
Trong các bài trước, chúng ta đã thảo luận các đặc điểm cơ bản của Gradient Descent, chúng ta trong bài này sẽ thực thi chúng trong Python và sử dụng chúng để phân loại dữ liệu. Cùng định nghĩa script gradient_descent.py
from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from sklearn.datasets import make_blobs import matplotlib.pyplot as plt import numpy as np import argparse def sigmoid_activation(x): return 1.0 / (1 + np.exp(-x)) def sigmoid_deriv(x): return x * (1 - x)
Chungs ta nhập các gói Python cần thiết. Chúng ta đã thấy tất cả những gois này trước đây, với ngoại lệ của make_blobs, một hàm được sử dụng để tạo các blobs màu các điểm dữ liệu được phân phối thông thường - đây là một chức năng tiện dụng khi thử nghiệm hoặc triển khai các mô hình của chúng ta từ đầu. Sau đó, chúng tôi xác định hàm sigmoid_activation. Khi được vẽ, hàm này sẽ giống như một đường cong hình chữ nhật của Snhư hình dưới. Chúng ta gọi nó là một hàm kích hoạt bởi vì hàm sẽ kích hoạt tính năng trên mạng ON (giá trị đầu ra> 0: 5) hoặc OF (giá trị đầu ra <= 0: 5) dựa trên đầu vào x.
Tiếp theo, chúng ta xác định đạo hàm của hàm sigmoid. Chúng ta cần tính đạo hàm của hàm này để lấy độ dốc thực tế. Độ dốc là những gì cho phép chúng ta đi xuống độ dốc của bề mặt tối ưu hóa. Chúng ta sẽ thảo luận về chủ đề này nhiều hơn trong các bài kế, vì vậy nếu bạn là người mới để tính toán đạo hàm của một hàm kích hoạt, đừng lo lắng - đây đơn giản là một ví dụ.
Hàm dự đoán áp dụng hàm kích hoạt sigmoid của chúng ta và sau đó đặt ngưỡng nó dựa trên liệu nẻuon có xuất ra (1) hay không (0):
def predict(X, W): preds = sigmoid_activation(X.dot(W)) preds[preds <= 0.5] = 0 preds[preds > 0] = 1 return preds
Cho một tập hợp các điểm dữ liệu đầu vào X và trọng số W, chúng ta gọi hàm sigmoid_activation trên đó để có được một bộ dự đoán. Sau đó, chúng ta đặt ngưỡng các dự đoán: mọi dự đoán có giá trị <= 0: 5 được đặt thành 0 trong khi mọi dự đoán có giá trị> 0: 5 được đặt thành 1. Các dự đoán sau đó được trả về hàm gọi.
Mặc dù có các lựa chọn thay thế (tốt hơn) khác cho hàm kích hoạt sigmoid, nhưng nó tạo ra một điểm khởi đầu tuyệt vời trong cuộc thảo luận của chúng ta về mạng lưới thần kinh, học tập sâu và tối ưu hóa dựa trên độ dốc. Chúng ta sẽ thảo luận về các hàm kích hoạt khác trong các bà kế, nhưng hiện tại, ta chỉ cần nhớ rằng sigmoid là một hàm kích hoạt phi tuyến tính mà chúng ta có thể sử dụng để vượt qua dự đoán của mình.
Tiếp theo, hãy để phân tích các đối số dòng lệnh của chúng ta:
ap = argparse.ArgumentParser() ap.add_argument("-e", "--epochs", type=float, default=100, help="# of epochs") ap.add_argument("-a", "--alpha", type=float, default=0.01, help="learning rate") args = vars(ap.parse_args())
Chúng ta có thể cung cấp hai đối số dòng lệnh (tùy chọn) cho tập lệnh của mình:
--epochs: Số lượng epoch mà chúng ta sẽ sử dụng khi đào tạo trình phân loại của chúng ta bằng cách sử dụng gradient descent.
--alpha: Tốc độ học tập cho độ dốc giảm dần. Chúng ta thường thấy 0,1, 0,01 và 0,001 là giá trị tốc độ học tập ban đầu, nhưng một lần nữa, đây là một siêu tham số mà bạn sẽ cần điều chỉnh cho riêng mình vấn đề phân loại.
Bây giờ, các đối số dòng lệnh của chúng tôi đã được phân tích cú pháp, hãy để tạo một số dữ liệu để phân loại:
(X, y) = make_blobs(n_samples=1000, n_features=2, centers=2,\ cluster_std=1.5, random_state=1) y = y.reshape((y.shape[0], 1)) X = np.c_[X, np.ones((X.shape[0]))] (trainX, testX, trainY, testY) = train_test_split(X, y,\ test_size=0.5, random_state=42)
Chúng ta thực hiện goij tới make_blobs tạo 1.000 điểm dữ liệu được phân tách thành hai lớp. Các điểm dữ liệu này là 2D, ngụ ý rằng các vectơ đặc trưng có chiều dài 2. Nhãn cho mỗi điểm dữ liệu này là 0 hoặc 1. Mục tiêu của chúng ta là đào tạo một trình phân loại chính xác dự đoán nhãn lớp cho từng điểm dữ liệu.
Chúng ta áp dụng vecto thiên vị, cho phép chúng tôi bỏ qua việc theo dõi rõ ràng của vectơ thiên vị b của chúng ta, bằng cách chèn một cột hoàn toàn mới 1s làm mục cuối cùng trong ma trận thiết kế X.
Thêm một cột chứa giá trị không đổi trên tất cả các vectơ đặc trưng cho phép chúng ta coi thiên vị của mình là một tham số có thể huấn luyện trong ma trận trọng số W chứ không phải là một biến hoàn toàn riêng biệt. Khi chúng tôi đã chèn cột của các cột, chúng ta phân vùng dữ liệu vào đào tạo và thử nghiệm của chúng ta chia tách, sử dụng 50% dữ liệu cho đào tạo và 50% cho thử nghiệm.
W = np.random.randn(X.shape[1], 1) losses = [] for epoch in np.arange(0, args["epochs"]): preds = sigmoid_activation(trainX.dot(W)) error = preds - trainY loss = np.sum(error ** 2) losses.append(loss) d = error * sigmoid_deriv(preds) gradient = trainX.T.dot(d) W += -args["alpha"] * gradient preds = predict(testX, W) print(classification_report(testY, preds))
Nó rất quan trọng để ghi nhớ cách hoạt động của thuật toán vanilla gradient descent. Độ dốc của vanilla chỉ thực hiện cập nhật trọng lượng một lần cho mỗi epoch - trong ví dụ này, chúng ta đã đào tạo mô hình của chúng tôi cho 100 epochs, vì vậy chỉ có 100 cập nhật diễn ra. Tùy thuộc vào việc khởi tạo về ma trận trọng số và quy mô của tỷ lệ học tập, có thể chúng ta không thể học được một mô hình có thể phân tách các điểm (mặc dù chúng có thể phân tách tuyến tính).
Đối với việc giảm độ dốc đơn giản, bạn nên tập luyện nhiều kỷ nguyên hơn với việc học nhỏ hơn tỷ lệ để giúp khắc phục vấn đề này. Tuy nhiên, như chúng ta sẽ thấy trong phần tiếp theo, một biến thể của gradient descent được gọi là Stochastic Gradient Descent thực hiện cập nhật trọng lượng cho mỗi đợt tập luyện dữ liệu, ngụ ý có nhiều cập nhật trọng lượng mỗi epoch. Cách tiếp cận này dẫn đến hội tụ nhanh hơn, nhiều hơn.
Chúc bạn thành đạt trong công việc và hạnh phúc trong cuộc sống !
Hotline / Zalo: 0903 666 014
Website: https://uniduc.com/vi
-------------////--------------------------------------------////------------
HUMANOID ROBOT CỦA CÔNG TY UNIDUC SẢN XUẤT PHÁT TRIỂN.