Tính toán Đạo hàm và Ma trận Hessian với Zygote.jl trong Julia

Zygote.jl là thư viện vi phân nguồn-tới-nguồn (source-to-source automatic differentiation) dành cho ngôn ngữ Julia. Nó đóng vai trò là backend tính toán cho Flux.jl, xử lý các tác vụ liên quan đến gradient, ma trận Jacobi và các quy trình tối ưu hóa trong huấn luyện mô hình học máy.

Để bắt đầu, người dùng cần cài đặt gói thông qua trình quản lý gói của Julia:

using Pkg
Pkg.add("Zygote")

Tính toán Gradient cơ bản

Để tính đạo hàm của hàm số $f(x) = 3x^3 + 2x$ tại điểm $x = 2$:

using Zygote
gradient(x -> 3*x^3 + 2*x, 2)

Kết quả trả về là một tuple chứa giá trị đạo hàm: (38.0,).

Đối với hàm nhiều biến $f(u, v) = u^2 + v^2$, ta có thể truyền các tham số trực tiếp:

gradient((u, v) -> u^2 + v^2, 3.0, 4.0)

Đầu ra sẽ là (6.0, 8.0), tương ứng với các phần tử của vector gradient.

Zygote cũng hỗ trợ các phép toán trên ma trận. Giả sử bạn có ma trận trọng số $W$ và vector đầu vào $x$:

W = rand(3, 4)
x = rand(4)

# Hàm tính toán mất mát đơn giản
compute_loss(W) = sum((W * x) .^ 2)

# Tính gradient theo W
gradient(compute_loss, W)[1]

Lệnh trên trả về một ma trận kích thước $3 \times 4$ chứa các giá trị đạo hàm riêng.

Xử lý cấu trúc điều khiển

Thư viện có khả năng phân tích gradient qua các vòng lặp. Xét hàm tính tổng cộng dồn:

function accumulate_value(val, n)
    total = 0
    for i = 1:n
        total += val
    end
    return total
end

gradient(v -> accumulate_value(v, 5), 10)

Kết quả là (5.0,) vì hàm thực hiện phép cộng biến số 5 lần.

Sử dụng Dictionary

Gradient cũng có thể được tính toán trong các khối lệnh sử dụng Dict:

data_store = Dict()

gradient(5) do input
    data_store[:key] = input
    data_store[:key] * 3
end

Kết quả trả về là (3.0,).

Định nghĩa kiểu dữ liệu tùy chỉnh (Custom Types)

Dưới đây là ví dụ định nghĩa cấu trúc Vector2D và nạp chồng các toán tử:

import Base: +, -

struct Vector2D
    u::Float64
    v::Float64
end

+(a::Vector2D, b::Vector2D) = Vector2D(a.u + b.u, a.v + b.v)
-(a::Vector2D, b::Vector2D) = Vector2D(a.u - b.u, a.v - b.v)
calc_norm(p::Vector2D) = sqrt(p.u^2 + p.v^2)

p1 = Vector2D(1.0, 2.0)
p2 = Vector2D(3.0, 4.0)

# Tính gradient của hàm chuẩn vector
gradient(p -> calc_norm(p + p2), p1)[1]

Ma trận Jacobi

Đối với các ánh xạ từ $\mathbb{R}^n \to \mathbb{R}^m$, hàm jacobian được sử dụng. Ví dụ với ánh xạ $f(z) = [z_1^2, z_2^2]$:

jacobian(z -> [z[1]^2, z[2]^2], [2, 3])[1]

Kết quả là ma trận $2 \times 2$:
2.0 0.0
0.0 6.0

Ma trận Hessian

Để tính toán ma trận Hessian của hàm hai biến $f(x, y) = x^2 + y^2$:

hessian(v -> v[1]^2 + v[2]^2, randn(2))

Kết quả trả về ma trận đơn vị nhân với 2:
2.0 0.0
0.0 2.0

Lưu ý: Zygote được tối ưu hóa cho các kiểu dữ liệu số và mảng. Việc tính toán vi phân trên các kiểu dữ liệu khác như String hoặc Tuple sẽ thường xuyên trả về kết quả là Nothing.

Thẻ: Julia Zygote AutomaticDifferentiation MachineLearning Flux

Đăng vào ngày 6 tháng 6 lúc 22:33