Định train ML/DL model nhưng không biết chọn tham số? Bayesian Optimization!

Tram Ho

Giới thiệu

Trong quá trình training model ML hay mạng neural, một bước cực kỳ quan trọng và không thể thiếu là lựa chọn giá trị cho các tham số như learning rate, epochs, số layers, hidden units,… Việc lựa chọn các tham số hợp lý thường dựa trên kinh nghiệm và với mỗi bộ tham số như vậy ta phải huấn luyện model, quan sát kết quả đạt được, đánh giá kết quả, điều chỉnh tham số và lặp lại. Để tự động hóa quy trình trên, các thuật toán tìm kiếm như Grid Search hay Random Search được sử dụng. Tuy nhiên các thuật toán này chỉ hoạt động hiệu quả với số lượng tham số ít, thường là nhỏ hơn 5 vì không gian tìm kiếm sẽ tăng nhanh khi số lượng tham số lớn khiến cho thời gian tìm kiếm trở nên rất lâu. Bayesian Optimization (BO) là một thuật toán giúp tối ưu hiệu quả những hàm mục tiêu có chi phí evaluation lớn (như training 1 mạng neural) dựa trên định lý Bayesian. BO làm giảm đáng kể số lần thử sai khi tune tham số so với Grid Search hay Random Search, điều mà với một mạng deep learning lớn (ResNet, Inception, Xception,..) cùng bộ data khổng lồ (ImageNet) sẽ tốn hàng giờ thậm chí hàng ngày liền. Trong bài này, chúng ta sẽ tìm hiểu cách BO hoạt động và ứng dụng nó tối ưu tham số training model CNN cho bài toán MNIST nhé.

Tổng quan thuật toán

BO tối ưu hàm mục tiêu dựa trên học máy. Viết dưới dạng công thức:

max⁡x∈Af(x)max _{x in A} f(x)
xAmaxf(x)

Trong đó A là tập các tham số cần tune, và số lượng tham số không nên nhiều hơn 20 để đảm bảo thuật toán học tốt nhất; f(x)f(x)f(x) là hàm mục tiêu để tối ưu lớn nhất/nhỏ nhất (ví dụ: accuracy, loss,…), f(x)f(x)f(x) có một vài đặc điểm sau:

  • fff là hàm liên tục
  • Chi phí evaluation của fff lớn
  • fff là một black box, ta không hề biết các tính chất của fff như tính tuyến tính, hàm lồi, hàm lõm,…
  • fff là một black box, khi thực hiện evaluate fff chỉ lấy ra giá trị f(x)f(x)f(x), các phương pháp liên quan đến đạo hàm như gradient descent sẽ không khả thi và không được sử dụng.

BO xây dựng một hàm surrogate (hàm thay thế) để model fff, mục tiêu là tối ưu surrogate càng giống fff càng tốt, từ đó có thể tìm ra global minimum/maximum của fff dễ dàng bằng cách lấy minimum/maximum của surrogate. Surrogate này là một Gaussian Process với prior distribution và likelihood được định nghĩa từ đầu. Mỗi khi evaluate fff của điểm x mới, ta sẽ tính được posterior của surrogate bằng quy tắc Bayes. Dựa trên posterior này, một Acquisition function tìm ra điểm x’ có tiềm năng mang lại giá trị fff lớn nhất, x’ tiếp tục được evaluate và update posterior. Cứ lặp như vậy cho đến khi ta đạt được kết quả f(x)f(x)f(x) mong muốn.

Pseudo-code cho thuật toán BO:

Bước chuẩn bị

Trong bài này mình sẽ sử dụng GPyTorch để implement phần chính của BO là Gaussian Process Regression, mục đích là cung cấp cái nhìn rõ hơn về các thành phần bên trong của GP Regression. Ngoài ra bạn cũng có thể sử dụng luôn model GaussianProcessRegressor của scikit-learn nhé.
Cài đặt các thư viện liên quan:

Import thư viện:

Tiếp đến là hàm để train CNN model trên tập MNIST. Hàm này nhận 1 dict các tham số và giá trị tương ứng và train model bằng các tham số đó, hàm trả về model đã được train. Ở đây mình sẽ chỉ tune 1 tham số duy nhất là learning rate.

Load MNIST data:

Hàm sample_lr generate các giá trị learning rate khác nhau trong khoảng 1e-6 đến 0.2

Cuối cùng, ta định nghĩa hàm objective chính là hàm số mà ta muốn tối ưu. Cụ thể, hàm này lấy vào x là hyperparameter (learning rate), thực hiện train, evaluate CNN model và trả về giá trị accuracy.

Gaussian Process Regression

Gausian Process (GP) Regression là một phương pháp thống kê Bayesian để model các hàm số. GP regression hoạt động hiệu quả trên những tập dataset nhỏ nhờ vào giả định các điểm dữ liệu nằm trên một phân phối nhiều chiều (Multivariate Normal). Đầu tiên ta định nghĩa một GP model, chính là prior distribution trên hàm số. Với một biến ngẫu nhiên X, phân bố của nó được xác định bằng hàm mật độ xác suất (probability distribution function – pdf):

f(x∣μ,σ2)=12πσ2e−(x−μ)22σ2fleft(x mid mu, sigma^{2}right)=frac{1}{sqrt{2 pi sigma^{2}}} e^{-frac{(x-mu)^{2}}{2 sigma^{2}}}
f(xμ,σ2)=2πσ21e2σ2(xμ)2

với μ,σmu, sigmaμ,σ lần lượt là mean và variance. Khi có nhiều hơn một biến ngẫu nhiên, mean sẽ được biểu diễn dưới dạng 1 vector và variance được biểu diễn dưới dạng ma trận, gọi là covariance matrix. Covariance matrix được xây dựng bằng cách evaluate một hàm covariance hay kernel Σ0Σ_0Σ0 trên từng cặp giá trị xi,xjx_i, x_jxi,xj của các biến ngẫu nhiên. Kernel được chọn để các điểm xi,xjx_i, x_jxi,xj càng gần nhau trong không gian đầu vào càng có giá trị lớn. Các kernel khác nhau biểu diễn prior khác nhau, dẫn đến hàm số kết quả khác nhau.

Để xây dựng một prior (GP model) bằng GPyTorch, mình sẽ kế thừa class ExactGP và custom mean cũng như covariance modules. Cụ thể, mình sử dụng ConstantMeanRBFKernel:

Class Regressor là một GP Regression bao gồm GP model và gaussian likelihood.

Acquisition Function

Khi đã có posterior từ GP, câu hỏi tiếp theo là làm thế nào để chọn được candidate tiềm năng cho ra kết quả (mean) tốt nhất? Cách đơn giản nhất là lựa chọn vị trí maximum của mean, nhưng còn những vùng có uncertainty lớn (standard deviation lớn) cũng rất tiềm năng cho ra kết quả tốt chứ. Acquisition function dựa trên cả 2 yếu tố là cực trị hiện tại và uncertainty của posterior để đưa ra candidate tiềm năng nhất. Một trong những hàm acquisition hay được sử dụng là Expected Improvement (EI) được tính bằng công thuwcs:

EI(x)={(μ(x)−f(x+)−ξ)Φ(Z)+σ(x)ϕ(Z) , neˆˊu σ(x)>00 , neˆˊu σ(x)=0mathrm{EI}(mathbf{x})=left{begin{array}{ll}
left(mu(mathbf{x})-fleft(mathbf{x}^{+}right)-xiright) Phi(Z)+sigma(mathbf{x}) phi(Z) & text { , nếu } sigma(mathbf{x})>0 \
0 & text { , nếu } sigma(mathbf{x})=0
end{array}right.
EI(x)={(μ(x)f(x+)ξ)Φ(Z)+σ(x)ϕ(Z)0 , neˆˊσ(x)>0 , neˆˊσ(x)=0

Trong đó x+mathbf{x}^{+}x+ là điểm dữ liệu tốt nhất hiện tại; μ(x)mu(mathbf{x})μ(x)σ(x)sigma(mathbf{x})σ(x) lần lượt là mean và variance của xxx; Φ(Z)Phi(Z)Φ(Z)ϕ(Z)phi(Z)ϕ(Z) lần lượt là CDF và PDF của phân phối Z:

Z={μ(x)−f(x+)−ξσ(x) , neˆˊu σ(x)>00 , neˆˊu σ(x)=0Z=left{begin{array}{ll}
frac{mu(mathbf{x})-fleft(mathbf{x}^{+}right)-xi}{sigma(mathbf{x})} & text { , nếu } sigma(mathbf{x})>0 \
0 & text { , nếu } sigma(mathbf{x})=0
end{array}right.
Z={σ(x)μ(x)f(x+)ξ0 , neˆˊσ(x)>0 , neˆˊσ(x)=0

Số hạng (μ(x)−f(x+)−ξ)Φ(Z)left(mu(mathbf{x})-fleft(mathbf{x}^{+}right)-xiright) Phi(Z)(μ(x)f(x+)ξ)Φ(Z) cho biết “improvement” của xmathbf{x}x so với x+mathbf{x}^{+}x+, thể hiện sự exploitation trong khi σ(x)ϕ(Z)sigma(mathbf{x}) phi(Z)σ(x)ϕ(Z) “khám phá” những nơi có uncertainty (variance) cao, thể hiện sự exploration. Tham số ξxiξ điều khiển trade-off giữa exploration và exploitation. Nhìn công thức có vẻ phức tạp nhưng implement nó lại khá dễ dàng như sau:

Sau khi đã có hàm tính EI cho một điểm x bất kỳ, ta sẽ phải sample rất nhiều x và chọn ra điểm có EI lớn nhất. Tuy hàm EI đã có 2 yếu tố exploration và exploitation, người ta cho rằng nhiều khi nó vẫn hơi “tham lam” nghiêng về expoitation. Vậy nên thay vì chọn điểm EI cao nhất, mình sẽ chọn theo ϵepsilonϵ-greedy: chọn điểm tốt nhất với xác suất (1-ϵepsilonϵ) và chọn một điểm bất kỳ với xác suất ϵepsilonϵ, và ϵepsilonϵ sẽ giảm dần theo từng vòng lặp.

Main loop

Vòng lặp này theo đúng thuật toán:

  1. Train GP regression bằng initial data .
  2. Sử dụng acquisition function chọn candidate (learning rate) tiềm năng nhất.
  3. Evaluate candidate: train lại CNN model bằng candidate đó
  4. Append candidate và giá trị (accuracy) của nó vào tập dữ liệu ban đầu và lặp lại bước 1.

Chạy thuật toán (sẽ mất một chút thời gian đó):


Qua 10 vòng lặp, kết quả là giá trị learning rate tốt nhất là 0.012973 với accuracy bằng 0.9823

Visualize posterior

Ta sẽ visualize posterior của GP regression để có cái nhìn trực quan về cách mà BO lựa chọn candidate.

Và đây là kết qủa. Có thể thấy BO hầu như chọn điểm xung quanh vùng mang lại giá trị accuracy cao nhất nhưng đôi khi nó cũng chọn những vùng khác có uncertainty (variance) cao (vùng màu xám thể hiện variance của posterior).

Kết luận

Bài này mình đã giới thiệu và implement với bạn thuật toán tối ưu Bayesian Optimization. Đây là một thuật toán khá hay và hữu dụng trong việc tối ưu, đặc biệt là tối ưu tham số model deep learning. Nếu bài viết có gì sai sót, hãy comment cho mình biết nhé; còn nếu thấy hay thì ngại gì mà không upvote/clip.

Tài liệu tham khảo:

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo