SciPy ، التحسين


SciPy (وضوح sai pie) عبارة عن حزمة تطبيق رياضية تستند إلى ملحق Numpy Python. باستخدام SciPy ، تتحول جلسة Python التفاعلية إلى نفس بيئة معالجة البيانات والنماذج الأولية الكاملة للأنظمة المعقدة مثل MATLAB و IDL و Octave و R-Lab و SciLab. أريد اليوم أن أتحدث باختصار عن كيفية استخدام بعض خوارزميات التحسين المعروفة في الحزمة. يمكن دائمًا الحصول على مساعدة أكثر تفصيلًا وحداثة حول استخدام الوظائف باستخدام الأمر help () أو باستخدام Shift + Tab.


مقدمة


من أجل إنقاذ نفسك والقراء من البحث وقراءة المصدر ، ستكون الروابط إلى أوصاف الطرق بشكل رئيسي على ويكيبيديا. كقاعدة عامة ، هذه المعلومات كافية لفهم الأساليب بشكل عام وشروط تطبيقها. لفهم جوهر الأساليب الرياضية ، نتبع الروابط الخاصة بالمنشورات الأكثر موثوقية ، والتي يمكن العثور عليها في نهاية كل مقالة أو في محرك البحث المفضل لديك.


لذلك ، تتضمن الوحدة النمطية scipy.optimize تنفيذ الإجراءات التالية:


  1. التقليل الشرطي وغير المشروط للوظائف العددية للعديد من المتغيرات (minim) باستخدام خوارزميات مختلفة (Nelder-Mead simplex و BFGS وتدرجات نيوتن المتقاربة و COBYLA و SLSQP )
  2. التحسين العالمي (على سبيل المثال: basinhopping ، diff_evolution )
  3. التقليل من بقايا المربعات الصغرى (المربعة الصغرى ) وخوارزميات تركيب المنحنيات إلى المربعات الصغرى غير الخطية (curve_fit)
  4. تقليل وظائف العددية لمتغير واحد (minim_scalar) وإيجاد الجذور (root_scalar)
  5. المذيبات متعددة الأبعاد لنظام المعادلات (الجذر) باستخدام خوارزميات مختلفة (هجين باول ، ليفنبرغ ماركوارت أو أساليب واسعة النطاق ، مثل نيوتن-كريلوف ).

في هذه المقالة سننظر في العنصر الأول فقط من هذه القائمة بأكملها.


التقليل غير المشروط للوظيفة العددية للعديد من المتغيرات


توفر الدالة minim من الحزمة scipy.optimize واجهة مشتركة لحل مشاكل التقليل الشرطي وغير المشروط للوظائف العددية للعديد من المتغيرات. لإثبات عملها ، سنحتاج إلى وظيفة مناسبة للعديد من المتغيرات ، والتي سوف نقوم بتقليلها بطرق مختلفة.


لهذه الأغراض ، تكون دالة Rosenbrock للمتغيرات N مثالية ، والتي لها الشكل:


f l e f t ( m a t h b f x r i g h t ) = s u m N - 1 i = 1 [ 100 l e f t ( x i + 1 - x 2 i r i g h t ) 2 + l e f t ( 1 - x i        right)2]


على الرغم من حقيقة أن وظيفة Rosenbrock ومصفوفاتها Jacobi و Hessian (المشتقات الأولى والثانية ، على التوالي) محددة بالفعل في حزمة scipy.optimize ، فإننا نعرّفها بأنفسنا.


import numpy as np def rosen(x): """The Rosenbrock function""" return np.sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0, axis=0) 

من أجل الوضوح ، نرسم في 3D قيم وظيفة Rosenbrock لمتغيرين.


رمز التقديم
 from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from matplotlib import cm from matplotlib.ticker import LinearLocator, FormatStrFormatter #  3D  fig = plt.figure(figsize=[15, 10]) ax = fig.gca(projection='3d') #    ax.view_init(45, 30) #     X = np.arange(-2, 2, 0.1) Y = np.arange(-1, 3, 0.1) X, Y = np.meshgrid(X, Y) Z = rosen(np.array([X,Y])) #   surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm) plt.show() 


مع العلم مقدما أن الحد الأدنى هو 0 ل xi=1دولادولا ، خذ بعين الاعتبار أمثلة حول كيفية تحديد الحد الأدنى لقيمة الدالة Rosenbrock باستخدام مختلف الإجراءات scipy.optimize.


طريقة Nelder-Mead Simplex (Nelder-Mead)


فليكن هناك نقطة أولية x0 في الفضاء ذي الأبعاد الخمسة. ابحث عن النقطة الدنيا لوظيفة Rosenbrock الأقرب إليها باستخدام خوارزمية simplex Nelder-Mead (يتم تحديد الخوارزمية كقيمة لمعلمة الطريقة):


 from scipy.optimize import minimize x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2]) res = minimize(rosen, x0, method='nelder-mead', options={'xtol': 1e-8, 'disp': True}) print(res.x) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 339 Function evaluations: 571 [1. 1. 1. 1. 1.] 

طريقة simplex هي أسهل طريقة لتقليل وظيفة محددة بوضوح وسلسة إلى حد ما. لا يتطلب حساب مشتقات دالة ؛ يكفي لتحديد قيمها فقط. طريقة Nelder-Mead هي اختيار جيد لمشاكل التقليل البسيطة. ومع ذلك ، نظرًا لأنه لا يستخدم تقديرات التدرج ، فقد يستغرق الأمر وقتًا طويلاً للعثور على الحد الأدنى.


طريقة باول


خوارزمية التحسين الأخرى التي يتم فيها احتساب قيم الوظيفة فقط هي طريقة Powell . لاستخدامها ، تحتاج إلى ضبط method = 'powell' في الدالة minim.


 x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2]) res = minimize(rosen, x0, method='powell', options={'xtol': 1e-8, 'disp': True}) print(res.x) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 19 Function evaluations: 1622 [1. 1. 1. 1. 1.] 

خوارزمية Broyden-Fletcher-Goldfarb-Channo (BFGS)


للحصول على تقارب أسرع مع الحل ، يستخدم الإجراء BFGS تدرج الدالة الهدف. يمكن تحديد التدرج كدالة أو حساب باستخدام اختلافات من الدرجة الأولى. في أي حال ، عادةً ما يتطلب أسلوب BFGS استدعاءات دالة أقل من أسلوب simplex.


نجد مشتق وظيفة Rosenbrock في الشكل التحليلي:


 frac جزئيةf جزئيةxj= sum limitNi=1200(xix2i1)( deltai،j2xi1،j)2(1xi1) deltai1،j=

جزئيةجزئية،،،


=200(xjx2j1)400xj(xj+1x2j)2(1xj)


هذا التعبير صالح للمشتقات من جميع المتغيرات باستثناء الأولى والأخيرة ، والتي يتم تعريفها على النحو التالي:


 frac جزئيةf جزئيةx0=400x0(x1x20)2(1x0)،

جزئيةجزئية،


 frac جزئيةf جزئيةxN1=200(xN1x2N2).

جزئيةجزئية


دعونا نلقي نظرة على وظيفة بيثون التي تحسب هذا التدرج:


 def rosen_der (x): xm = x [1: -1] xm_m1 = x [: - 2] xm_p1 = x [2:] der = np.zeros_like (x) der [1: -1] = 200 * (xm-xm_m1 ** 2) - 400 * (xm_p1 - xm ** 2) * xm - 2 * (1-xm) der [0] = -400 * x [0] * (x [1] -x [0] ** 2) - 2 * (1-x [0]) der [-1] = 200 * (x [-1] -x [-2] ** 2) return der 

يتم تحديد وظيفة حساب التدرج اللوني كقيمة معلمة jac لوظيفة minim ، كما هو موضح أدناه.


 res = minimize(rosen, x0, method='BFGS', jac=rosen_der, options={'disp': True}) print(res.x) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 25 Function evaluations: 30 Gradient evaluations: 30 [1.00000004 1.0000001 1.00000021 1.00000044 1.00000092] 

خوارزمية التدرج المترافق (نيوتن)


تعد خوارزمية التدرج المتزامن لـ Newton طريقة نيوتن معدلة.
تعتمد طريقة نيوتن على تقريب وظيفة في منطقة محلية من خلال كثير الحدود من الدرجة الثانية:


f left( mathbfx right) approxf left( mathbfx0 right)+ nablaf left( mathbfx0 right) cdot left( mathbfx mathbfx0 right)+ frac12 left( mathbfx mathbfx0 right)T mathbfH left( mathbfx0 right) left( mathbfx mathbfx0 right)


اين  mathbfH left( mathbfx0 right) هي مصفوفة من المشتقات الثانية (مصفوفة هسي ، هسيان).
إذا كان Hessian محددًا بشكل إيجابي ، يمكن العثور على الحد الأدنى المحلي لهذه الوظيفة عن طريق مساواة التدرج الصفري للشكل التربيعي على الصفر. والنتيجة هي تعبير:


 mathbfx textrmopt= mathbfx0 mathbfH1 nablaf


يتم حساب معكوس هسه باستخدام طريقة التدرج المتقارن. فيما يلي مثال لاستخدام هذه الطريقة لتقليل وظيفة Rosenbrock. لاستخدام طريقة Newton-CG ، يجب عليك تحديد دالة تقوم بتقييم Hessian.
تساوي وظيفة Hessian of the Rosenbrock في الشكل التحليلي:


Hi،j= frac جزئية2f جزئيةxixj=200( deltai،j2xi1 deltai1،j400xi( deltai+1،j2xi deltai،j)400 deltai،j(xi+1x2i)+2 deltai،j=


=(202+1200x2i400xi+1) deltai،j400xi deltai+1،j400xi1 deltai1،j


اين i،j in left[1،N2 right] و i،j in left[0،N1 right] تحديد المصفوفة N مرةN .


العناصر غير الصفرية المتبقية في المصفوفة تساوي:


 frac جزئية2f جزئيةx20=1200x20400x1+2


 frac جزئية2f جزئيةx0x1= frac جزئية2f جزئيةx1x0=400x0


 frac جزئية2f جزئيةxN1xN2= frac جزئية2f جزئيةxN2xN1=400xN2


 frac جزئية2f جزئيةx2N1=200x


على سبيل المثال ، في الفضاء ثلاثي الأبعاد N = 5 ، تحتوي مصفوفة Hessian لوظيفة Rosenbrock على شكل شريط:


\ tiny \ mathbf {H} = \ تبدأ {bmatrix} 1200 × _ {0} ^ {2} -400x_ {1} +2 & -400x_ {0} & 0 & 0 & 0 \\ -400x_ {0} & 202 + 1200x_ {1} ^ {2} -400x_ {2} & -400x_ {1} & 0 & 0 \\ 0 & -400x_ {1} & 202 + 1200x_ {2} ^ {2} -400x_ {3} & -400x_ {2} & 0 \\ 0 & & -400x_ {2} & 202 + 1200x_ {3} ^ {2} -400x_ {4} & -400x_ {3} \\ 0 & 0 & 0 & -400x_ { 3} & 200 \ end {bmatrix}


الكود الذي يحسب هذا Hessian مع الكود لتقليل وظيفة Rosenbrock باستخدام طريقة التدرج المترافق (Newton):


 def rosen_hess(x): x = np.asarray(x) H = np.diag(-400*x[:-1],1) - np.diag(400*x[:-1],-1) diagonal = np.zeros_like(x) diagonal[0] = 1200*x[0]**2-400*x[1]+2 diagonal[-1] = 200 diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:] H = H + np.diag(diagonal) return H res = minimize(rosen, x0, method='Newton-CG', jac=rosen_der, hess=rosen_hess, options={'xtol': 1e-8, 'disp': True}) print(res.x) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 24 Function evaluations: 33 Gradient evaluations: 56 Hessian evaluations: 24 [1. 1. 1. 0.99999999 0.99999999] 

مثال مع تعريف وظيفة منتج Hessian وناقلات تعسفية


في مشاكل العالم الحقيقي ، قد يتطلب حساب وتخزين مصفوفة Hessian بأكملها موارد كبيرة من الوقت والذاكرة. علاوة على ذلك ، في الواقع ، ليست هناك حاجة لتحديد مصفوفة هسي نفسها ، منذ ذلك الحين لا يتطلب إجراء التقليل إلى الحد الأدنى سوى متجه يساوي منتج Hessian مع متجه تعسفي آخر. وبالتالي ، من وجهة نظر حسابية ، من الأفضل بكثير تحديد الوظيفة التي تُرجع نتيجة منتج Hessian باستخدام متجه تعسفي على الفور.


النظر في وظيفة hess ، والتي تأخذ ناقلات التقليل إلى الحد الأدنى كوسيطة الأولى ، وناقلات تعسفية كالوسيطة الثانية (جنبًا إلى جنب مع وسائط أخرى من الدالة المصغرة). في حالتنا ، ليس من الصعب جدًا حساب ناتج دالة Hessian of the Rosenbrock باستخدام ناقل تعسفي. إذا كان p هو ناقل تعسفي ، ثم المنتج H(x) cdotp لديه النموذج:


 mathbfH left( mathbfx right) mathbfp= تبدأbmatrix left(1200x20400x1+2 right)p0400x0p1 vdots400xi1pi1+ left(202+1200x2i400xi+1 right)pi400xipi+1 vdots400xN2pN2+200pN1 endbmatrix.


يتم تمرير الدالة التي تحسب منتج Hessian والناقل التعسفي كقيمة وسيطة hessp لتقليل الدالة:


 def rosen_hess_p(x, p): x = np.asarray(x) Hp = np.zeros_like(x) Hp[0] = (1200*x[0]**2 - 400*x[1] + 2)*p[0] - 400*x[0]*p[1] Hp[1:-1] = -400*x[:-2]*p[:-2]+(202+1200*x[1:-1]**2-400*x[2:])*p[1:-1] \ -400*x[1:-1]*p[2:] Hp[-1] = -400*x[-2]*p[-2] + 200*p[-1] return Hp res = minimize(rosen, x0, method='Newton-CG', jac=rosen_der, hessp=rosen_hess_p, options={'xtol': 1e-8, 'disp': True}) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 24 Function evaluations: 33 Gradient evaluations: 56 Hessian evaluations: 66 

خوارزمية منطقة الثقة للتدرجات المترافقة (نيوتن)


يمكن أن يؤدي ضعف شروط مصفوفة هيس واتجاهات البحث غير الصحيحة إلى حقيقة أن خوارزمية تدرجات نيوتن المترافقة يمكن أن تكون غير فعالة. في مثل هذه الحالات ، يتم إعطاء الأفضلية لطريقة منطقة الثقة لتدرجات نيوتن المترافقة.


مثال تعريف مصفوفة هسه:


 res = minimize(rosen, x0, method='trust-ncg', jac=rosen_der, hess=rosen_hess, options={'gtol': 1e-8, 'disp': True}) print(res.x) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 20 Function evaluations: 21 Gradient evaluations: 20 Hessian evaluations: 19 [1. 1. 1. 1. 1.] 

مثال مع وظيفة المنتج من هسي وناقلات تعسفي:


 res = minimize(rosen, x0, method='trust-ncg', jac=rosen_der, hessp=rosen_hess_p, options={'gtol': 1e-8, 'disp': True}) print(res.x) 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 20 Function evaluations: 21 Gradient evaluations: 20 Hessian evaluations: 0 [1. 1. 1. 1. 1.] 

طرق نوع كريلوفسكي


مثل طريقة الثقة في ncg ، تعتبر طرق Krylovsky من النوع المناسب تمامًا لحل المشكلات واسعة النطاق ، لأنها تستخدم فقط منتجات ناقلات المصفوفات. جوهرها هو في حل المشكلة في المجال السري المحدود بمساحة Krylov الفرعية المقطوعة. بالنسبة للمهام غير المؤكدة ، من الأفضل استخدام هذه الطريقة ، لأنها تستخدم عددًا أقل من التكرارات غير الخطية نظرًا لوجود عدد أقل من منتجات ناقلات المصفوفات في كل مهمة فرعية ، مقارنةً بأسلوب ثقة ncg. بالإضافة إلى ذلك ، فإن حل المهمة الفرعية التربيعية هو أكثر دقة من طريقة trust-ncg.
مثال تعريف مصفوفة هسه:


 res = minimize(rosen, x0, method='trust-krylov', jac=rosen_der, hess=rosen_hess, options={'gtol': 1e-8, 'disp': True}) Optimization terminated successfully. Current function value: 0.000000 Iterations: 19 Function evaluations: 20 Gradient evaluations: 20 Hessian evaluations: 18 print(res.x) [1. 1. 1. 1. 1.] 

مثال مع وظيفة المنتج من هسي وناقلات تعسفي:


 res = minimize(rosen, x0, method='trust-krylov', jac=rosen_der, hessp=rosen_hess_p, options={'gtol': 1e-8, 'disp': True}) Optimization terminated successfully. Current function value: 0.000000 Iterations: 19 Function evaluations: 20 Gradient evaluations: 20 Hessian evaluations: 0 print(res.x) [1. 1. 1. 1. 1.] 

الخوارزمية التقريبية المستندة إلى الثقة


جميع الطرق (Newton-CG و trust-ncg و trust-krylov) مناسبة تمامًا لحل المهام واسعة النطاق (بآلاف المتغيرات). ويرجع ذلك إلى حقيقة أن الخوارزمية الكامنة وراء التدرجات المترافقة تتضمن تحديدًا تقريبيًا لمصفوفة Hessian العكسية. الحل تكراري ، دون تحلل صريح لهيسيان. نظرًا لأنه من الضروري تحديد وظيفة منتج Hessian والناقل التعسفي ، تعد هذه الخوارزمية مفيدة بشكل خاص للعمل مع مصفوفات متفرق (شريط قطري). هذا يوفر تكاليف ذاكرة منخفضة وتوفير كبير في الوقت.


في المشكلات متوسطة الحجم ، لا تعد تكاليف تخزين Hessian ومعالجتها مهمة. هذا يعني أنه يمكن الحصول على حل بتكرار أقل ، مما يؤدي إلى حل المهام الفرعية لمنطقة الثقة تمامًا تقريبًا. لهذا ، يتم حل بعض المعادلات غير الخطية بشكل متكرر لكل مهمة فرعية من الدرجة الثانية. مثل هذا الحل عادة ما يتطلب 3 أو 4 تحلل من مصفوفة هيتس هولتس. نتيجة لذلك ، تتقارب الطريقة في عدد أقل من التكرارات وتتطلب حسابًا أقل للدالة الموضوعية مقارنة بالطرق الأخرى المطبقة في مجال الثقة. هذه الخوارزمية تعني فقط تحديد مصفوفة هيسان الكاملة ولا تدعم القدرة على استخدام وظيفة منتج هسيا وناقلات تعسفية.


مثال لتقليل وظيفة Rosenbrock:


 res = minimize(rosen, x0, method='trust-exact', jac=rosen_der, hess=rosen_hess, options={'gtol': 1e-8, 'disp': True}) res.x 

 Optimization terminated successfully. Current function value: 0.000000 Iterations: 13 Function evaluations: 14 Gradient evaluations: 13 Hessian evaluations: 14 array([1., 1., 1., 1., 1.]) 

هذا ، ربما ، يسكن. في المقالة التالية سأحاول أن أقول الأكثر إثارة للاهتمام حول التقليل الشرطي ، وتطبيق التقليل إلى أدنى حد في حل مشاكل التقريب ، والتقليل إلى أدنى حد من وظيفة متغير واحد ، minimizers التعسفي ، وإيجاد جذور نظام المعادلات باستخدام حزمة scipy.optimize.


المصدر: https://docs.scipy.org/doc/scipy/reference/

Source: https://habr.com/ru/post/ar439288/


All Articles