Coursera ML - Việc lựa chọn thuật toán tối ưu hóa có ảnh hưởng đến độ chính xác của hồi quy logistic đa giác không?


7

Gần đây tôi đã hoàn thành bài tập 3 của Andrew Ng's Machine Learning trên Coursera bằng Python .

Khi ban đầu hoàn thành các phần 1.4 đến 1.4.1 của bài tập, tôi gặp khó khăn khi đảm bảo rằng mô hình được đào tạo của tôi có độ chính xác phù hợp với 94,9% dự kiến. Ngay cả sau khi gỡ lỗi và đảm bảo rằng các hàm chi phí và độ dốc của tôi không có lỗi và mã dự đoán của tôi hoạt động chính xác, tôi vẫn chỉ nhận được độ chính xác 90,3%. Tôi đã sử dụng thuật toán gradient liên hợp (CG) trong scipy.optimize.minimize.

Vì tò mò, tôi quyết định thử một thuật toán khác và sử dụng BroydenTHER FletcherTHER GoldfarbTHER Shannon (BFGS). Thật ngạc nhiên, độ chính xác được cải thiện mạnh mẽ đến 96,5% và do đó vượt quá mong đợi. Việc so sánh hai kết quả khác nhau giữa CG và BFGS có thể được xem trong sổ ghi chép của tôi dưới tiêu đề Sự khác biệt về độ chính xác do các thuật toán tối ưu hóa khác nhau .

Là lý do cho sự khác biệt về độ chính xác này do sự lựa chọn khác nhau của thuật toán tối ưu hóa? Nếu có, sau đó ai đó có thể giải thích tại sao?

Ngoài ra, tôi sẽ đánh giá rất cao bất kỳ đánh giá nào về mã của tôi chỉ để đảm bảo rằng không có lỗi trong bất kỳ chức năng nào của tôi gây ra điều này.

Cảm ơn bạn.

EDIT: Ở đây bên dưới tôi đã thêm mã liên quan đến câu hỏi, theo yêu cầu trong các bình luận mà tôi làm như vậy trong trang này thay vì giới thiệu người đọc đến các liên kết đến sổ ghi chép Jupyter của tôi.

Mô hình hàm chi phí:

def sigmoid(z):
    return 1 / (1 + np.exp(-z))

def compute_cost_regularized(theta, X, y, lda):
    reg =lda/(2*len(y)) * np.sum(theta[1:]**2) 
    return 1/len(y) * np.sum(-y @ np.log(sigmoid(X@theta)) 
                             - (1-y) @ np.log(1-sigmoid(X@theta))) + reg

def compute_gradient_regularized(theta, X, y, lda):
    gradient = np.zeros(len(theta))
    XT = X.T
    beta = sigmoid(X@theta) - y
    regterm = lda/len(y) * theta
    # theta_0 does not get regularized, so a 0 is substituted in its place
    regterm[0] = 0 
    gradient = (1/len(y) * XT@beta).T + regterm
    return gradient

Chức năng thực hiện đào tạo phân loại một-tất cả:

from scipy.optimize import minimize

def train_one_vs_all(X, y, opt_method):
    theta_all = np.zeros((y.max()-y.min()+1, X.shape[1]))
    for k in range(y.min(),y.max()+1):
        grdtruth = np.where(y==k, 1,0)
        results = minimize(compute_cost_regularized, theta_all[k-1,:], 
                           args = (X,grdtruth,0.1),
                           method = opt_method, 
                           jac = compute_gradient_regularized)
        # optimized parameters are accessible through the x attribute
        theta_optimized = results.x
        # Assign thetheta_optimized vector to the appropriate row in the 
        # theta_all matrix
        theta_all[k-1,:] = theta_optimized
    return theta_all

Được gọi là hàm để huấn luyện mô hình với các phương thức tối ưu hóa khác nhau:

theta_all_optimized_cg = train_one_vs_all(X_bias, y, 'CG')  # Optimization performed using Conjugate Gradient
theta_all_optimized_bfgs = train_one_vs_all(X_bias, y, 'BFGS') # optimization performed using Broyden–Fletcher–Goldfarb–Shanno

Chúng tôi thấy rằng kết quả dự đoán khác nhau dựa trên thuật toán được sử dụng:

def predict_one_vs_all(X, theta):
    return np.mean(np.argmax(sigmoid(X@theta.T), axis=1)+1 == y)*100

In[16]: predict_one_vs_all(X_bias, theta_all_optimized_cg)
Out[16]: 90.319999999999993

In[17]: predict_one_vs_all(X_bias, theta_all_optimized_bfgs)
Out[17]: 96.480000000000004

Đối với bất kỳ ai muốn lấy bất kỳ dữ liệu nào để thử mã, họ có thể tìm thấy nó trong Github của tôi như được liên kết trong bài đăng này.


1
Hồi quy logistic nên có một mức tối thiểu ổn định duy nhất (như hồi quy tuyến tính), vì vậy có khả năng điều gì đó gây ra điều này mà bạn không nhận thấy
Neil Slater

Vậy phải đảm bảo hội tụ đến chi phí tối thiểu? Bạn có thể làm một bài đánh giá mã cho tôi không?
AKKA

1
Nếu có nhiều mã bạn cần xem xét, có thể đăng nó lên codereview.stackexchange.com - nếu chỉ cần một lượng nhỏ để sao chép vấn đề, bạn có thể thêm nó vào câu hỏi của mình tại đây (chỉnh sửa nó dưới dạng khối mã, vui lòng bao gồm đủ để nhân rộng hoàn toàn vấn đề).
Neil Slater

trong khi sự thật là việc đảm bảo mức tối thiểu toàn cầu sẽ mang lại cho bạn kết quả tương tự bất kể thuật toán tối ưu hóa, có thể có sự tinh tế trong việc thực hiện thuật toán (tức là các phương pháp xử lý ổn định số, v.v.) có thể dẫn đến các giải pháp hơi khác nhau. Những khác biệt nhỏ trong các giải pháp có thể dẫn đến chênh lệch hiệu suất lớn hơn khi được đánh giá trên bộ thử nghiệm nhỏ. Có thể đó là gây ra một sự khác biệt hiệu suất lớn như vậy trong trường hợp của bạn. Và vâng, nói chung, các thuật toán tối ưu hóa phần lớn có thể ảnh hưởng đến kết quả học tập. Btw, tôi đã nhận được kết quả mong muốn trong MATLAB.
Sal

1
@NeilSlater: ok, tôi vừa thêm mã trực tiếp vào câu hỏi dưới dạng chỉnh sửa. Trông ổn chứ?
AKKA

Câu trả lời:


3

Giới hạn của độ chính xác và ổn định bằng số đang khiến các thói quen tối ưu hóa phải vật lộn.

Bạn có thể thấy điều này dễ dàng nhất bằng cách thay đổi thuật ngữ chính quy thành 0,0 - không có lý do gì nguyên tắc này không hoạt động và bạn không sử dụng bất kỳ kỹ thuật tính năng nào đặc biệt cần nó. Với chính quy được đặt thành 0,0, sau đó bạn sẽ thấy giới hạn độ chính xác đạt được và cố gắng lấy nhật ký bằng 0 khi tính hàm chi phí. Hai thói quen tối ưu hóa khác nhau bị ảnh hưởng khác nhau, do lấy các điểm mẫu khác nhau trên tuyến đến mức tối thiểu.

Tôi nghĩ rằng với thuật ngữ chính quy được đặt ở mức cao, bạn loại bỏ tính không ổn định về số, nhưng với chi phí không nhìn thấy những gì đang thực sự xảy ra với các tính toán - thực tế, các thuật ngữ chính quy trở thành ưu thế cho các ví dụ đào tạo khó khăn.

Bạn có thể bù một số vấn đề về độ chính xác bằng cách sửa đổi hàm chi phí:

def compute_cost_regularized(theta, X, y, lda):
    reg =lda/(2*len(y)) * np.sum(theta[1:]**2) 
    return reg - 1/len(y) * np.sum(
      y @ np.log( np.maximum(sigmoid(X@theta), 1e-10) ) 
      + (1-y) @ np.log( np.maximum(1-sigmoid(X@theta), 1e-10) ) )

Ngoài ra để có được một số phản hồi trong quá trình đào tạo, bạn có thể thêm

                       options = {
                           'disp': True
                       }

Để gọi đến minimize.

Với thay đổi này, bạn có thể thử với thuật ngữ chính quy được đặt thành không. Khi tôi làm điều này, tôi nhận được:

predict_one_vs_all(X_bias, theta_all_optimized_cg)
Out[156]:
94.760000000000005
In [157]:

predict_one_vs_all(X_bias, theta_all_optimized_bfgs)
/usr/local/lib/python3.6/site-packages/ipykernel/__main__.py:2: RuntimeWarning: overflow encountered in exp
  from ipykernel import kernelapp as app
Out[157]:
98.839999999999989

Giá trị CG của 94,76 dường như khớp với kết quả mong đợi độc đáo - vì vậy tôi tự hỏi liệu điều này có được thực hiện mà không cần chính quy không. Giá trị BFGS vẫn "tốt hơn" mặc dù tôi không chắc mình tin tưởng bao nhiêu vào các thông điệp cảnh báo trong quá trình đào tạo và đánh giá. Để biết liệu kết quả đào tạo rõ ràng tốt hơn này có thực sự chuyển thành phát hiện chữ số tốt hơn hay không, bạn sẽ cần phải đo kết quả trên một bộ kiểm tra giữ.


Thực sự đánh giá cao phân tích bạn đã cung cấp trong câu trả lời của bạn. Tôi vẫn có một câu hỏi về sửa đổi bạn đã thực hiện cho hàm chi phí, như với np.maximum(sigmoid(X@theta), 1e-10), làm thế nào bạn biết sử dụng 1e-10làm giá trị ngưỡng? Ngoài ra, tôi nhận thấy rằng bạn đã thay đổi mặt đăng xuất âm của các điều khoản riêng lẻ của tổng và đưa nó ra để bây giờ reg - thuật ngữ chính quy trừ đi số hạng tổng. Điều này cũng có vấn đề?
AKKA

Như bạn đề xuất, tôi cũng đã thử đặt thuật ngữ chính quy thành 0,0 và tôi không chỉ nhận được số chia cho sai số 0 mà thời gian chạy cũng trở nên dài hơn nhiều! Về việc chia cho số không, tôi không hiểu tại sao. Nó đã xảy ra như thế nào? Điều này có liên quan gì đến các chi tiết triển khai của các thuật toán không? Xin thứ lỗi cho tôi vì tôi không quen thuộc với các phương pháp số ...
AKKA

@AKKA: Tôi chỉ chọn 1e-10 một cách tùy tiện và việc xáo trộn các thuật ngữ xung quanh là tác dụng phụ của việc tôi kiểm tra và hiểu mã. Tôi không nghĩ sẽ tạo ra sự khác biệt lớn. Về mặt kỹ thuật, nó không phải là một số chia cho 0, mà là một sự np.log( array_containing_a_zero )kiện đã xảy ra do một số tiền âm hoặc dương lớn trong một ví dụ khác trong quá trình tìm kiếm tối ưu hóa.
Neil Slater

Bởi vì mã lũy thừa sau đó lấy nhật ký, các số bạn nhìn thấy có thể nằm trong giới hạn hợp lý, nhưng các phép tính tạm thời có thể cực kỳ. Một số khung có thể giải quyết các biểu thức sao cho lũy thừa và nhật ký không thực sự xảy ra - nhưng toán học cho điều đó nằm ngoài tôi.
Neil Slater

Tôi hiểu rồi. Bạn có nghĩ rằng kết quả tốt hơn bạn đạt được có thể là quá phù hợp không? Tôi đoán đó là lý do tại sao bạn nói cuối cùng phải có một bộ kiểm tra để xác thực điều này ...
AKKA

2

CG không hội tụ đến mức tối thiểu cũng như BFGS

Nếu tôi cũng có thể thêm câu trả lời vào câu hỏi của mình, các khoản tín dụng dành cho một người bạn tốt tình nguyện xem mã của tôi. Anh ấy không tham gia chương trình trao đổi dữ liệu khoa học dữ liệu và không cảm thấy cần phải tạo một tài khoản chỉ để đăng câu trả lời, vì vậy anh ấy đã trao cơ hội này để gửi cho tôi.

Tôi cũng sẽ tham khảo @Neil Slater, vì có khả năng phân tích của anh ấy về vấn đề ổn định số có thể giải thích cho điều này.

Vì vậy, tiền đề chính đằng sau giải pháp của tôi là:

Chúng tôi biết rằng hàm chi phí là lồi, có nghĩa là nó không có địa phương và chỉ có mức tối thiểu toàn cầu. Vì dự đoán sử dụng các tham số được đào tạo với BFGS tốt hơn so với dự đoán được đào tạo sử dụng CG, điều này ngụ ý rằng BFGS hội tụ gần với mức tối thiểu hơn CG đã làm. Dù BFGS có hội tụ đến mức tối thiểu toàn cầu hay không, chúng tôi không thể nói chắc chắn, nhưng chúng tôi chắc chắn có thể nói rằng nó gần hơn CG.

Vì vậy, nếu chúng ta lấy các tham số đã được đào tạo bằng CG và chuyển chúng qua quy trình tối ưu hóa bằng BFGS, chúng ta sẽ thấy các tham số này được tối ưu hóa hơn nữa, vì BFGS mang mọi thứ đến gần mức tối thiểu. Điều này sẽ cải thiện độ chính xác dự đoán và đưa nó đến gần hơn với độ chính xác thu được bằng cách sử dụng đào tạo BFGS đơn giản.

Dưới đây là mã xác minh điều này, các tên biến tuân theo như trong câu hỏi:

# Copy the old array over, else only a reference is copied, and the 
# original vector gets modified
theta_all_optimized_bfgs_from_cg = np.copy(theta_all_optimized_cg)

for k in range(y.min(),y.max()+1):
    grdtruth = np.where(y==k, 1,0)
    results = minimize(compute_cost_regularized,theta_all_optimized_bfgs_from_cg[k-1,:], 
                       args = (X_bias,grdtruth,0.1),
                       method = "BFGS", 
                       jac = compute_gradient_regularized, options={"disp":True})
    # optimized parameters are accessible through the x attribute
    theta_optimized = results.x
    # Assign thetheta_optimized vector to the appropriate row in the 
    # theta_all matrix
    theta_all_optimized_bfgs_from_cg[k-1,:] = theta_optimized

Trong quá trình thực hiện vòng lặp, chỉ một trong số các lần lặp tạo ra một thông báo cho thấy số lần lặp lại thường xuyên tối ưu hóa khác không, nghĩa là tối ưu hóa được thực hiện thêm:

Optimization terminated successfully.
         Current function value: 0.078457
         Iterations: 453
         Function evaluations: 455
         Gradient evaluations: 455

Và kết quả đã được cải thiện:

In[19]:  predict_one_vs_all(X_bias, theta_all_optimized_bfgs_from_cg)
Out[19]:  96.439999999999998

Bằng cách đào tạo thêm các tham số ban đầu thu được từ CG, thông qua một lần chạy BFGS bổ sung, chúng tôi đã tối ưu hóa chúng thêm để đưa ra độ chính xác dự đoán 96.44%rất gần với 96.48%chỉ thu được bằng cách chỉ sử dụng BFGS!

Tôi đã cập nhật máy tính xách tay của tôi với lời giải thích này.

Tất nhiên điều này đặt ra nhiều câu hỏi hơn, chẳng hạn như tại sao CG không hoạt động tốt như BFGS đã làm với chức năng chi phí này, nhưng tôi đoán đó là những câu hỏi dành cho một bài đăng khác.


Tôi nghĩ rằng bạn vẫn nên kiểm tra điều này trên một bộ kiểm tra giữ, để loại trừ BFGS bị hỏng thay thế. Tuy nhiên, tôi đã tự hỏi từ khi trả lời, liệu việc thêm chính quy có làm cho bề mặt mất mát trở nên đơn giản hơn không. . . có nghĩa là kết quả BFGS hoàn toàn tốt hơn trong tình huống đó, nhưng trở nên không ổn định nếu không được chính quy hóa trên tập dữ liệu này.
Neil Slater

@NeilSlater: Đúng, tôi đồng ý rằng việc xác thực và thực hành tiêu chuẩn tốt nhất là chạy nó trên một tập dữ liệu thử nghiệm. Tuy nhiên, việc thực hiện một bộ thử nghiệm không phải là một phần của nhiệm vụ Coursera, vì vậy không có bộ thử nghiệm nào được cung cấp cho chúng tôi. Tôi sẽ phải lấy một đoạn ra khỏi MNIST ban đầu. Những gì bạn nói có vẻ hợp lý, vì không cần chính quy, độ dốc liên hợp sẽ cải thiện. Tuy nhiên, nếu bề mặt mất mát thực sự đơn giản hơn, thì tại sao CG vẫn hoạt động kém hơn BFGS, thay vì giống nhau?
AKKA
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.