Quay lại danh sách thử thách
Trung bình 0 đã giải Tỷ lệ chấp nhận 0%

Chuẩn hóa theo lớp (layer normalization)

Chuẩn hóa mỗi hàng về trung bình 0 và phương sai 1, rồi co giãn và dịch chuyển, như mọi khối Transformer.

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

  • Chuẩn hóa mỗi hàng về trung bình 0 và phương sai 1
  • Co giãn và dịch bằng gamma và beta
  • Hiểu vì sao cần epsilon

Đề bài

Xem bản gốc (English)

Layer normalization giữ các giá trị kích hoạt của mỗi token ở một thang đo ổn định. Với mỗi hàng x của ma trận:

  1. mean = Σ x / d và var = Σ (x - mean)² / d (phương sai tổng thể trên d giá trị của hàng)
  2. x̂ = (x - mean) / √(var + epsilon)
  3. đầu ra = gamma × x̂ + beta (theo từng phần tử: cột j dùng gamma[j] và beta[j])

Hãy cài đặt layer_norm(x, gamma, beta, epsilon).

Đầu vào

x: Ma trận có mỗi token một hàng và d cột.

gamma, beta: Hệ số co giãn và dịch chuyển đã học, mỗi cái d giá trị.

epsilon: Một số nhỏ để tránh chia cho 0.

Đầu ra

Trả về ma trận đã chuẩn hóa, cùng kích thước với x.

Ràng buộc

1 ≤ số hàng ≤ 100, 1 ≤ d ≤ 128

-100 ≤ mỗi giá trị ≤ 100, 0 < epsilon ≤ 0.001

Ví dụ

Ví dụ 1
Đầu vào:
x = [
    [1.0, 2.0, 3.0]
]
beta = [0.0, 0.0, 0.0]
gamma = [1.0, 1.0, 1.0]
epsilon = 1.0e-05

Kết quả mong đợi:
expected = [
    [-1.224736, 0.0, 1.224736]
]
Đầu vào:
std::vector<std::vector<double>> x = {
    {1.0, 2.0, 3.0}
};
std::vector<double> beta = {0.0, 0.0, 0.0};
std::vector<double> gamma = {1.0, 1.0, 1.0};
double epsilon = 1.0e-05;

Kết quả mong đợi:
std::vector<std::vector<double>> expected = {
    {-1.224736, 0.0, 1.224736}
};
Đầu vào:
double[][] x = new double[][] {
    new double[] {1.0, 2.0, 3.0}
};
double[] beta = new double[] {0.0, 0.0, 0.0};
double[] gamma = new double[] {1.0, 1.0, 1.0};
double epsilon = 1.0e-05;

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

Giải thích

mean = 2 và var = (1 + 0 + 1) / 3 ≈ 0.666667, nên √(var + epsilon) ≈ 0.816503. Hàng trở thành khoảng [-1.224736, 0, 1.224736]: tâm tại 0 với phương sai 1.

Ví dụ 2
Đầu vào:
x = [
    [5.0, 5.0]
]
beta = [1.0, -1.0]
gamma = [2.0, 3.0]
epsilon = 1.0e-05

Kết quả mong đợi:
expected = [
    [1.0, -1.0]
]
Đầu vào:
std::vector<std::vector<double>> x = {
    {5.0, 5.0}
};
std::vector<double> beta = {1.0, -1.0};
std::vector<double> gamma = {2.0, 3.0};
double epsilon = 1.0e-05;

Kết quả mong đợi:
std::vector<std::vector<double>> expected = {
    {1.0, -1.0}
};
Đầu vào:
double[][] x = new double[][] {
    new double[] {5.0, 5.0}
};
double[] beta = new double[] {1.0, -1.0};
double[] gamma = new double[] {2.0, 3.0};
double epsilon = 1.0e-05;

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

Giải thích

Cả hai giá trị bằng trung bình, nên x̂ = [0, 0] và đầu ra chỉ là beta: [1, -1]. Epsilon giúp tránh chia cho 0.

Hướng tiếp cận

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

Gợi ý 1

Normalize từng row độc lập bằng mean và variance riêng của row đó, không phải thống kê trên toàn ma trận.

Gợi ý 2

Sau khi chuẩn hóa một row, áp dụng scale và shift học được theo từng phần tử với gamma và beta.

Gợi ý 3

Dùng population variance và thêm epsilon trước khi lấy căn để tránh chia cho 0 ở những row hằng.

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

thời gian O(rows * d), 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.