Trung bình 0 đã giải Tỷ lệ chấp nhận 0%

Hạ gradient theo mini-batch

Huấn luyện mô hình tuyến tính bằng cách cập nhật trọng số sau mỗi lô nhỏ thay vì sau toàn bộ dữ liệu.

Bạn sẽ học được gì

  • Chia dữ liệu thành các batch
  • Cập nhật trọng số sau mỗi batch
  • So sánh huấn luyện batch, mini-batch và ngẫu nhiên

Đề bài

Xem bản gốc (English)

Hạ gradient theo mini-batch là cách huấn luyện gần như mọi mạng nơ-ron: chia dữ liệu thành các lô nhỏ và cập nhật trọng số sau mỗi lô.

Huấn luyện y = w × x + b trên sai số bình phương trung bình, bắt đầu từ w = 0 và b = 0. Ở mỗi epoch, chia các mẫu theo thứ tự thành các lô gồm batch_size mẫu (lô cuối có thể ít hơn). Với mỗi lô có n mẫu:

  1. errorᵢ = w × xᵢ + b - yᵢ cho từng mẫu trong lô
  2. dw = (2 / n) × Σ errorᵢ × xᵢ và db = (2 / n) × Σ errorᵢ
  3. w ← w - learning_rate × dw và b ← b - learning_rate × db

Hãy cài đặt train_mini_batch(xs, ys, batch_size, learning_rate, epochs).

Đầu vào

xs, ys: Các điểm dữ liệu (cùng độ dài).

batch_size: Số mẫu mỗi lô.

learning_rate, epochs: Bước nhảy và số lượt duyệt qua dữ liệu.

Đầu ra

Trả về [w, b] sau khi huấn luyện.

Ràng buộc

1 ≤ số điểm ≤ 1.000, 1 ≤ batch_size ≤ số điểm, 0 ≤ epochs ≤ 1.000

0 < learning_rate ≤ 1

-100 ≤ mỗi giá trị ≤ 100

Ví dụ

Ví dụ 1
Đầu vào:
xs = [1.0, 2.0, 3.0]
ys = [2.0, 4.0, 6.0]
epochs = 1
batch_size = 2
learning_rate = 0.1

Kết quả mong đợi:
expected = [2.44, 1.08]
Đầu vào:
std::vector<double> xs = {1.0, 2.0, 3.0};
std::vector<double> ys = {2.0, 4.0, 6.0};
long long epochs = 1;
long long batch_size = 2;
double learning_rate = 0.1;

Kết quả mong đợi:
std::vector<double> expected = {2.44, 1.08};
Đầu vào:
double[] xs = new double[] {1.0, 2.0, 3.0};
double[] ys = new double[] {2.0, 4.0, 6.0};
long epochs = 1;
long batch_size = 2;
double learning_rate = 0.1;

Kết quả mong đợi:
double[] expected = new double[] {2.44, 1.08};

Giải thích

Lô 1 là x = [1, 2]: sai số -2 và -4, dw = -10, db = -6, nên w = 1 và b = 0.6. Lô 2 chỉ có x = [3]: sai số 1×3 + 0.6 - 6 = -2.4, dw = 2 × (-2.4) × 3 = -14.4 và db = -4.8, nên w = 2.44 và b = 1.08. Kết quả: [2.44, 1.08].

Ví dụ 2
Đầu vào:
xs = [1.0, 2.0, 3.0, 4.0]
ys = [3.0, 5.0, 7.0, 9.0]
epochs = 1
batch_size = 4
learning_rate = 0.05

Kết quả mong đợi:
expected = [1.75, 0.6]
Đầu vào:
std::vector<double> xs = {1.0, 2.0, 3.0, 4.0};
std::vector<double> ys = {3.0, 5.0, 7.0, 9.0};
long long epochs = 1;
long long batch_size = 4;
double learning_rate = 0.05;

Kết quả mong đợi:
std::vector<double> expected = {1.75, 0.6};
Đầu vào:
double[] xs = new double[] {1.0, 2.0, 3.0, 4.0};
double[] ys = new double[] {3.0, 5.0, 7.0, 9.0};
long epochs = 1;
long batch_size = 4;
double learning_rate = 0.05;

Kết quả mong đợi:
double[] expected = new double[] {1.75, 0.6};

Giải thích

Một lô lớn bằng cả tập dữ liệu chính là hạ gradient theo lô thông thường: mỗi epoch một lần cập nhật. Kết quả: [1.75, 0.6].

Hướng tiếp cận

Hãy tự thử trước, sau đó mở từng gợi ý một.

Gợi ý 1

Xử lý các mẫu theo đúng thứ tự đã cho, cập nhật tham số sau mỗi batch thay vì sau từng điểm riêng lẻ.

Gợi ý 2

Với mỗi batch, tính prediction error trước, rồi dùng trung bình của chúng với giá trị x để lấy hai gradient.

Gợi ý 3

Batch cuối có thể nhỏ hơn các batch khác, nên việc scale gradient phải dùng kích thước của chính batch đó.

Độ phức tạp mong đợi

thời gian O(epochs × n), bộ nhớ phụ O(1)

Tham khảo

Thử thách này đã được điều chỉnh cho CodeUtility. Hãy làm theo đề bài và các ràng buộc ở trên.

Học hỏi từ người khác

Giải pháp cộng đồng

Chưa có giải pháp nào được chia sẻ. Hãy giải thử thách này để đăng giải pháp đầu tiên.