2013-07-02 22 views
7

Làm cách nào để tôi có thể làm cho một số chức năng trả về costgradient làm bộ tảo? Vấn đề với việc có f cho chi phí và fprime cho độ dốc, là tôi có thể phải thực hiện một thao tác hai lần (rất tốn kém) mà theo đó, gradcost được tính toán. Ngoài ra, việc chia sẻ các biến giữa chúng có thể gây rắc rối.Làm cách nào để trả lại chi phí, được phân loại như là một phần của hàm fmin_cg của scipy

Tuy nhiên, trong Matlab, fmin_cg hoạt động với một hàm trả về chi phí và độ dốc làm bộ tuple. Tôi không thấy lý do tại sao số điện thoại fmin_cg của scipy không thể cung cấp sự tiện lợi như vậy.

Cảm ơn trước ...

Trả lời

6

Bạn có thể sử dụng scipy.optimize.minimize với jac=True. Nếu đó không phải là một lựa chọn cho một số lý do, sau đó bạn có thể nhìn vào how it handles this situation:

class MemoizeJac(object): 
    """ Decorator that caches the value gradient of function each time it 
    is called. """ 
    def __init__(self, fun): 
     self.fun = fun 
     self.jac = None 
     self.x = None 

    def __call__(self, x, *args): 
     self.x = numpy.asarray(x).copy() 
     fg = self.fun(x, *args) 
     self.jac = fg[1] 
     return fg[0] 

    def derivative(self, x, *args): 
     if self.jac is not None and numpy.alltrue(x == self.x): 
      return self.jac 
     else: 
      self(x, *args) 
      return self.jac 

Lớp này kết thúc tốt đẹp một hàm trả về giá trị chức năng và gradient, giữ một bộ nhớ cache một phần tử và kiểm tra mà để xem nếu nó đã biết kết quả của nó. Cách sử dụng:

fmemo = MemoizeJac(f, fprime) 
xopt = fmin_cg(fmemo, x0, fmemo.derivative) 

Điều kỳ lạ về mã này là nó giả định f luôn gọi trước khi fprime (nhưng không phải mọi f gọi Tiếp theo là một cuộc gọi fprime). Tôi không chắc chắn nếu scipy.optimize thực sự đảm bảo rằng, nhưng mã có thể dễ dàng thích nghi để không làm cho rằng giả định, mặc dù. Phiên bản mạnh mẽ của các bên trên (chưa được kiểm tra ):

class MemoizeJac(object): 
    def __init__(self, fun): 
     self.fun = fun 
     self.value, self.jac = None, None 
     self.x = None 

    def _compute(self, x, *args): 
     self.x = numpy.asarray(x).copy() 
     self.value, self.jac = self.fun(x, *args) 

    def __call__(self, x, *args): 
     if self.value is not None and numpy.alltrue(x == self.x): 
      return self.value 
     else: 
      self._compute(x, *args) 
      return self.value 

    def derivative(self, x, *args): 
     if self.jac is not None and numpy.alltrue(x == self.x): 
      return self.jac 
     else: 
      self._compute(x, *args) 
      return self.jac 
+1

+1 đẹp cách của bộ nhớ đệm trở lại cuộc gọi ngoái! Sẽ không quá khó để vượt qua giới hạn tiềm năng cuối cùng đó ('f' được gọi trước' fprime'), đúng không? – Jaime

+0

@Jaime: không, chỉ cần lặp lại mẹo được sử dụng trong 'đạo hàm'. Xem câu trả lời được cập nhật. –

+0

Waw, đây là một giải pháp tuyệt vời, tôi chỉ thử nghiệm mã của tôi với một cái gì đó như 'minim (fun = self._cost_grad, x0 = initial_theta, method = 'Newton-CG', tùy chọn = {'maxiter': 20, 'disp ': True}, jac = True, args = (X, n_features, n_samples)) ', và tôi có kết quả tuyệt vời. Tham số 'fun' mong đợi một hàm trả về (cost, grad) như tuple và' method' có thể được thay đổi đơn giản để thực hiện 'l_bfgs',' bfgs', 'cg' hoặc bất kỳ trình tối ưu hóa nào có trong scipy. Cảm ơn rất nhiều! Tôi ngạc nhiên câu trả lời này không phổ biến. – Curious

Các vấn đề liên quan