رویکرد هوش ازدحامی با استفاده از کلونی زنبور عسل مصنوعی برای حل مسائل بهینه‌سازی

۲۲۷۲ بازدید
آخرین به‌روزرسانی: ۱۹ تیر ۱۴۰۲
زمان مطالعه: ۸ دقیقه
رویکرد هوش ازدحامی با استفاده از کلونی زنبور عسل مصنوعی برای حل مسائل بهینه‌سازی

«هوش ازدحامی» (Swarm Intelligence - SI)، یک زمینه از «هوش محاسباتی» (Computational Intelligence - CI) است که برای ساخت و توسعه سیستم‌های هوشمند چندعامله الهام گرفته از زیست، استفاده می‌شود. این رویکرد از رفتار تجمعی عامل‌های طبیعی مانند دسته پرندگان و ماهی‌ها برای ساخت الگوریتم‌ها الگوبرداری کرده است.

اثبات شده که چنین الگوریتم‌هایی در حل مسائل جهان واقعی عملکرد بسیار موثری دارند. از جمله مسائلی که با استفاده از الگوریتم‌های هوش ازدحامی قابل حل هستند می‌توان به خوشه‌بندی، نگاشت سیاره‌ای، کنترل نانو ربات‌ها و گستره‌ای از مسائل داده‌کاوی مانند انتخاب ویژگی و دسته‌بندی اشاره کرد.

به بیان ریاضی، برای حل مسائل بهینه‌سازی جهان واقعی با استفاده از الگوریتم‌های محاسباتی هوشمند، نیاز به یک ارائه ریاضی‌وار از مساله وجود دارد که به آن «تابع هدف» (Objective Function) گفته می‌شود. تابع هدف در واقع قواعد ریاضی است که مساله و همه متغیرهای تصمیم آن را تشریح می‌کند.

به‌طور خلاصه، یک مساله بهینه‌سازی در فضای جست و جو تعریف می‌شود. این فضا در واقع ناحیه‌ای است که در آن به‌دنبال راهکار گشته می‌شود و شامل یک مجموعه از متغیرهای تصمیم است که خود حاوی همه پارامترهایی هستند که مساله و به‌ویژه تابع هدف را تحت تاثیر قرار می‌دهند. تابع هدف، با ریاضیات مساله را قاعده‌گذاری کرده و حجم خوبی از راهکارهای کاندید برای آن را ارائه می‌کند.

هدف یک مساله بهینه‌سازی، پیدا کردن بهترین راهکار از میان کلیه راه حل‌های امکان‌پذیر است. این یعنی در مساله بهینه‌سازی هدف یافتن کمینه یا بیشینه برای تابع هدف است. به عبارت دیگر، هدف پیدا کردن یک مجموعه از متغیرهای تصمیم ورودی محسوب می‌شود که برابر با کمینه یا بیشینه مقدار تابع هدف است و به آن «مقدار تناسب» نیز می‌گویند.

الگوریتم کلونی زنبور عسل مصنوعی

الگوریتم کلونی زنبور عسل مصنوعی (ABC)، یک راهکار بهینه‌سازی است که رفتار یک کلونی زنبور عسل را شبیه‌سازی می‌کند و برای اولین بار در سال ۲۰۰۵ توسط «کارابوگا» (Karaboga)، برای بهینه‌سازی پارامتر واقعی ارائه شد.

در این مدل ریاضی، کلونی زنبور عسل مصنوعی دارای سه نوع زنبور است. زنبورهای کارگر روی گردآوری غذا و آوردن آن به کندو از یک منبع غذایی خاص کار می‌کنند. زنبورهای ناظر در میان کارگرها گشت می‌زنند تا تشخیص دهند یک منبع غذایی همچنان ارزش استفاده دارد یا خیر و در نهایت زنبورهای دیده‌بان که به‌دنبال کشف منابع غذایی جدید هستند.

در الگوریتم ABC، یک منبع غذایی به عنوان حالتی در فضای جست‌و‌جو تعریف می‌شود (یک راهکار برای مساله بهینه‌سازی)، و تعداد منابع غذایی در ابتدا برابر با تعداد زنبورهای موجود در کندو است. کیفیت منابع غذایی توسط مقدار تابع هدف در آن موقعیت (مقدار تناسب) تعیین می‌شود.

رفتار هوشمند ناپایدار زنبورهای عسل را می‌توان در چند گام زیر خلاصه کرد:

  • زنبورها تلاش می‌کنند تا به صورت تصادفی در محیط به‌دنبال منابع غذایی خوب بگردند (مقدار تناسب).
  • پس از یافتن یک منبع غذایی، آن‌ها تبدیل به زنبورهای کارگر می‌شوند و شروع به استخراج غذا از منبع یافت شده می‌کنند.
  • زنبور کارگر با شهد به کندو باز می‌گردد و بار شهد خود را خالی می‌کند. پس از خالی کردن آن، می‌تواند مستقیما به منبع کشف شده خود باز گردد یا اطلاعاتی که درباره منبع غذاییش دارد را با اجرای یک رقص گردون در ناحیه رقص به اشتراک بگذارد.
  • اگر یک منبع غذایی خالی شد، زنبوران کارگر به دیده‌بان مبدل شده و به جست و جوی تصادفی برای منابع غذایی می‌پردازند.
  • زنبورهای ناظر در کندو منتظر مانده و زنبورهای کارگر را در منابع غذایی گردآوری کرده‌شان مورد نظارت قرار می‌دهند و از میان منابع غذایی موجود با بیشترین سود، یک منبع را انتخاب می‌کنند.
  • انتخاب منابع غذایی متناسب با کیفیت آن منبع (مقدار تناسب) است.

با اینکه سه نوع از زنبورهای عسل موجود در کلونی معرفی شدند، در مرحله پیاده‌سازی تنها دو نوع زنبور وجود دارد که زنبورهای کارگر و ناظر هستند. در واقع زنبور دیده‌بان یک رفتار اکتشافی است که می‌تواند توسط زنبورهای کارگر و ناظر انجام شود.

در این مقاله، از زبان پایتون برای پیاده‌سازی استفاده می‌شود زیرا در محاسبات عددی بسیار موثر عمل کرده و پیاده‌سازی یک مجموعه از بنچ‌مارک‌های هدف را برای استفاده مجدد در الگوریتم‌های هوش ازدحامی آسان‌تر می‌سازد.

1import numpy as np
2
3from scipy import optimize
4from deap.benchmarks import schwefel
5
6from abc import ABCMeta
7from abc import abstractmethod
8from six import add_metaclass
9
10
11@add_metaclass(ABCMeta)
12class ObjectiveFunction(object):
13
14    def __init__(self, name, dim, minf, maxf):
15        self.name = name
16        self.dim = dim
17        self.minf = minf
18        self.maxf = maxf
19
20    def sample(self):
21        return np.random.uniform(low=self.minf, high=self.maxf, size=self.dim)
22
23    def custom_sample(self):
24        return np.repeat(self.minf, repeats=self.dim) \
25               + np.random.uniform(low=0, high=1, size=self.dim) *\
26               np.repeat(self.maxf - self.minf, repeats=self.dim)
27
28    @abstractmethod
29    def evaluate(self, x):
30        pass
31
32
33class Sphere(ObjectiveFunction):
34
35    def __init__(self, dim):
36        super(Sphere, self).__init__('Sphere', dim, -100.0, 100.0)
37
38    def evaluate(self, x):
39        return sum(np.power(x, 2))
40
41
42class Rosenbrock(ObjectiveFunction):
43
44    def __init__(self, dim):
45        super(Rosenbrock, self).__init__('Rosenbrock', dim, -30.0, 30.0)
46
47    def evaluate(self, x):
48        return optimize.rosen(x)
49
50
51class Rastrigin(ObjectiveFunction):
52
53    def __init__(self, dim):
54        super(Rastrigin, self).__init__('Rastrigin', dim, -5.12, 5.12)
55
56    def evaluate(self, x):
57        return 10 * len(x)\
58               + np.sum(np.power(x, 2) - 10 * np.cos(2 * np.pi * np.array(x)))
59
60
61class Schwefel(ObjectiveFunction):
62
63    def __init__(self, dim):
64        super(Schwefel, self).__init__('Schwefel', dim, -500.0, 500.0)
65
66    def evaluate(self, x):
67        return schwefel(x)[0]

بسته deap را می‌توان از این مسیر دریافت کرد.

زنبورهای مصنوعی

به منظور آغاز ساخت الگوریتم، ابتدا باید راهکاری برای ارائه عامل زنبور در کد پایتون وجود داشته باشد. سه کارکرد اصلی وجود دارد که هر زنبوری باید دارای آن‌ها باشد. نخست اینکه اگر زنبوری به دلیل رفتار اکتشافی به خارج از ناحیه تصمیم می‌رود باید توانایی بازگشت به کندو را داشته باشد.

دومین کارکرد، توانایی به روز رسانی وضعیت منبع غذایی کنونی که زنبور روی آن کار می‌کند و ارزیابی اینکه آیا در همسایگی، ناحیه‌ای با منبع غذایی بهتر وجود دارد یا خیر است. و در نهایت آخرین مورد تشخیص این است که یک منبع غذایی خالی شده و اکنون زنبور باید به یک دیده‌بان مبدل شود و به دنبال منابع غذایی جدید بگردد.

با در نظر گرفتن این مسائل، اکنون می‌توان کلاس ArtificialBee را در پایتون به صورت زیر پیاده کرد:

1import numpy as np
2
3from copy import deepcopy
4from abc import ABCMeta
5from six import add_metaclass
6
7
8@add_metaclass(ABCMeta)
9class ArtificialBee(object):
10
11    TRIAL_INITIAL_DEFAULT_VALUE = 0
12    INITIAL_DEFAULT_PROBABILITY = 0.0
13
14    def __init__(self, obj_function):
15        self.pos = obj_function.custom_sample()
16        self.obj_function = obj_function
17        self.minf = obj_function.minf
18        self.maxf = obj_function.maxf
19        self.fitness = obj_function.evaluate(self.pos)
20        self.trial = ArtificialBee.TRIAL_INITIAL_DEFAULT_VALUE
21        self.prob = ArtificialBee.INITIAL_DEFAULT_PROBABILITY
22
23    def evaluate_boundaries(self, pos):
24        if (pos < self.minf).any() or (pos > self.maxf).any():
25            pos[pos > self.maxf] = self.maxf
26            pos[pos < self.minf] = self.minf
27        return pos
28
29    def update_bee(self, pos, fitness):
30        if fitness <= self.fitness:
31            self.pos = pos
32            self.fitness = fitness
33            self.trial = 0
34        else:
35            self.trial += 1
36
37    def reset_bee(self, max_trials):
38        if self.trial >= max_trials:
39            self.__reset_bee()
40
41    def __reset_bee(self):
42        self.pos = self.obj_function.custom_sample()
43        self.fitness = self.obj_function.evaluate(self.pos)
44        self.trial = ArtificialBee.TRIAL_INITIAL_DEFAULT_VALUE
45        self.prob = ArtificialBee.INITIAL_DEFAULT_PROBABILITY

زنبور کارگر

رفتار اصلی زنبور کارگر استخراج غذا از یک منبع غذایی است که در آن کارگران تا مرحله خالی شدن منبع کار می‌کنند. در مرحله پیاده‌سازی، این رفتار را می‌توان به عنوان ساخت موقعیت‌های جدید در نزدیکی جایی که زنبورهای کارگر مشغول کار هستند دید و ارزیابی کرد که آیا این موقعیت جدید مقدار بهتری غذا فراهم می‌کند؟ زنبورهای کارگر همیشه موقعیت بهترین منابع غذایی که به دست آورده‌اند را تا پیش از خالی شدن آن، به خاطر می‌سپارند.

کلاس EmployeeBee را می‌توان به صورت زیر پیاده کرد:

1class EmployeeBee(ArtificialBee):
2
3    def explore(self, max_trials):
4        if self.trial <= max_trials:
5            component = np.random.choice(self.pos)
6            phi = np.random.uniform(low=-1, high=1, size=len(self.pos))
7            n_pos = self.pos + (self.pos - component) * phi
8            n_pos = self.evaluate_boundaries(n_pos)
9            n_fitness = self.obj_function.evaluate(n_pos)
10            self.update_bee(n_pos, n_fitness)
11
12    def get_fitness(self):
13        return 1 / (1 + self.fitness) if self.fitness >= 0 else 1 + np.abs(self.fitness)
14
15    def compute_prob(self, max_fitness):
16        self.prob = self.get_fitness() / max_fitness

زنبورهای ناظر

زنبورهای ناظر از عملکرد زنبورهای کارگر پاسداری می‌کنند. آن‌ها بر فراز کندو پرواز کرده، پیشرفت کار زنبورهای کارگر را مورد بررسی قرار داده و ارزیابی می‌کنند که کدام کارگرها در گردآوری غذا موفق‌تر عمل کرده‌اند.

زنبورهای ناظر همیشه بهترین کارگران را هدف می‌گیرند و از یک رویکرد احتمالی، با عنوان «محل ملاقات»، استفاده می‌کنند که بر اساس آن دیگر زنبورها نیز با این امید که غذای بیشتری گردآوری کنند باید به این موقعیت موفقیت بیایند.

کلاس OnlookerBee را می‌توان به صورت زیر پیاده‌سازی کرد:

1class OnLookerBee(ArtificialBee):
2
3    def onlook(self, best_food_sources, max_trials):
4        candidate = np.random.choice(best_food_sources)
5        self.__exploit(candidate.pos, candidate.fitness, max_trials)
6
7    def __exploit(self, candidate, fitness, max_trials):
8        if self.trial <= max_trials:
9            component = np.random.choice(candidate)
10            phi = np.random.uniform(low=-1, high=1, size=len(candidate))
11            n_pos = candidate + (candidate - component) * phi
12            n_pos = self.evaluate_boundaries(n_pos)
13            n_fitness = self.obj_function.evaluate(n_pos)
14
15            if n_fitness <= fitness:
16                self.pos = n_pos
17                self.fitness = n_fitness
18                self.trial = 0
19            else:
20                self.trial += 1

الگوریتم کامل کلونی زنبور عسل مصنوعی

پس از پیاده‌سازی عامل‌های اصلی که قرار است در الگوریتم از آن‌ها استفاده شود، اکنون زمان آن فرا رسیده تا کلیه مراحلی که پیش از این تشریح شد با کد پایتون پیاده‌سازی شود.

توجه به این نکته لازم است که هر یک از گام‌های الگوریتم در یک متد جدا پیاده‌سازی شده‌اند. در ابتدا، پارامترهای داخلی الگوریتم ABC پیاده‌سازی شده و زنبورهای کارگر و ناظر در موقعیت‌های تصادفی قرار گرفته‌اند. یک استراتژی پیش‌فرض که در مسائل جهان واقعی موفق عمل کرده این است که نیمی از کندو به عنوان زنبورهای کارگر و نیمی دیگر به عنوان زنبور ناظر در نظر گرفته شوند.

پس از آن، زنبورهای کارگر برای گردآوری غذا به منابع غذایی اولیه مخصوص خودشان فرستاده می‌شوند و در عین حال همواره به دنبال مناطق دارای غذای بهتر در اطراف منبع کنونیشان هستند. هنگامی که این فاز تمام شد، زنبورهای عسل ناظر برای گشت‌زنی و ارزیابی اینکه فرآیند استخراج غذا از هر منبع غذایی چقدر خوب پیش رفته ارسال می‌شوند. در نهایت، زمان آن رسیده که بررسی شود آیا یک منبع غذایی خالی شده یا خیر، در این مرحله هم زنبورهای کارگر و هم ناظرها می‌توانند به زنبور دیده‌بان مبدل شوند و فرآیند اکتشافی برای جست‌و‌جوی منابع غذایی جدید را آغاز کنند.

الگوریتم ABC کامل را می‌توان به صورت زیر پیاده‌سازی کرد:

1class ABC(object):
2
3    def __init__(self, obj_function, colony_size=30, n_iter=5000, max_trials=100):
4        self.colony_size = colony_size
5        self.obj_function = obj_function
6
7        self.n_iter = n_iter
8        self.max_trials = max_trials
9
10        self.optimal_solution = None
11        self.optimality_tracking = []
12
13    def __reset_algorithm(self):
14        self.optimal_solution = None
15        self.optimality_tracking = []
16
17    def __update_optimality_tracking(self):
18        self.optimality_tracking.append(self.optimal_solution.fitness)
19
20    def __update_optimal_solution(self):
21        n_optimal_solution = \
22            min(self.onlokeer_bees + self.employee_bees,
23                key=lambda bee: bee.fitness)
24        if not self.optimal_solution:
25            self.optimal_solution = deepcopy(n_optimal_solution)
26        else:
27            if n_optimal_solution.fitness < self.optimal_solution.fitness:
28                self.optimal_solution = deepcopy(n_optimal_solution)
29
30    def __initialize_employees(self):
31        self.employee_bees = []
32        for itr in range(self.colony_size // 2):
33            self.employee_bees.append(EmployeeBee(self.obj_function))
34
35    def __initialize_onlookers(self):
36        self.onlokeer_bees = []
37        for itr in range(self.colony_size // 2):
38            self.onlokeer_bees.append(OnLookerBee(self.obj_function))
39
40    def __employee_bees_phase(self):
41        map(lambda bee: bee.explore(self.max_trials), self.employee_bees)
42
43    def __calculate_probabilities(self):
44        sum_fitness = sum(map(lambda bee: bee.get_fitness(), self.employee_bees))
45        map(lambda bee: bee.compute_prob(sum_fitness), self.employee_bees)
46
47    def __select_best_food_sources(self):
48        self.best_food_sources =\
49            filter(lambda bee: bee.prob > np.random.uniform(low=0, high=1),
50                   self.employee_bees)
51        while not self.best_food_sources:
52            self.best_food_sources = \
53                filter(lambda bee: bee.prob > np.random.uniform(low=0, high=1),
54                       self.employee_bees)
55
56    def __onlooker_bees_phase(self):
57        map(lambda bee: bee.onlook(self.best_food_sources, self.max_trials),
58            self.onlokeer_bees)
59
60    def __scout_bees_phase(self):
61        map(lambda bee: bee.reset_bee(self.max_trials),
62            self.onlokeer_bees + self.employee_bees)
63
64    def optimize(self):
65        self.__reset_algorithm()
66        self.__initialize_employees()
67        self.__initialize_onlookers()
68        for itr in range(self.n_iter):
69            self.__employee_bees_phase()
70            self.__update_optimal_solution()
71
72            self.__calculate_probabilities()
73            self.__select_best_food_sources()
74
75            self.__onlooker_bees_phase()
76            self.__scout_bees_phase()
77
78            self.__update_optimal_solution()
79            self.__update_optimality_tracking()
80            print("iter: {} = cost: {}"
81                  .format(itr, "%04.03e" % self.optimal_solution.fitness))

ارزیابی روی تابع بنچ‌مارک

مزیتی که الگوریتم‌های هوش ازدحامی نسبت به الگوریتم‌های کلاسیک و روش‌های مبتنی بر گرادیان دارند، توانایی اجرای خیلی خوب روی توابع غیر مشتق‌پذیر و توابع چند مدله است.

از آنجا که مسائل بهینه‌سازی بسیار مهم هستند، چندین تابع بنچ‌مارک خیلی خوب برای ارزیابی کارایی الگوریتم‌های بهینه‌سازی ارائه شده است. برخی از این توابع روی objective_function.py که پیش‌تر نوشته شده پیاده‌سازی می‌شوند و فرمول‌های آن‌ها در جدول یک قابل مشاهده است.

جدول ۱: لیست برخی توابع هدفی که به‌عنوان بنچ‌مارک برای سنجش کارایی الگوریتم‌های بهینه‌سازی مورد استفاده قرار می‌گیرند.

برای آزمودن چارچوب ارائه شده در این مطلب و بررسی اینکه آیا الگوریتم ABC در حد انتظار عمل می‌کند یا خیر، می‌توان کد آزمون زیر را اجرا، مقدار تناسب را روی نمودار رسم و ارزیابی کرد که فرآیند کمینه‌سازی برای این توابع چقدر خوب پیش رفته است.

1import numpy as np
2import matplotlib.pyplot as plt
3
4from algorithm.abc import ABC
5
6from matplotlib.style import use
7
8from objection_function import Rastrigin
9from objection_function import Rosenbrock
10from objection_function import Sphere
11from objection_function import Schwefel
12
13
14use('classic')
15
16
17def get_objective(objective, dimension=30):
18    objectives = {'Sphere': Sphere(dimension),
19                  'Rastrigin': Rastrigin(dimension),
20                  'Rosenbrock': Rosenbrock(dimension),
21                  'Schwefel': Schwefel(dimension)}
22    return objectives[objective]
23
24
25def simulate(obj_function, colony_size=30, n_iter=5000,
26             max_trials=100, simulations=30):
27    itr = range(n_iter)
28    values = np.zeros(n_iter)
29    box_optimal = []
30    for _ in range(simulations):
31        optimizer = ABC(obj_function=get_objective(obj_function),
32                        colony_size=colony_size, n_iter=n_iter,
33                        max_trials=max_trials)
34        optimizer.optimize()
35        values += np.array(optimizer.optimality_tracking)
36        box_optimal.append(optimizer.optimal_solution.fitness)
37        print(optimizer.optimal_solution.pos)
38    values /= simulations
39
40    plt.plot(itr, values, lw=0.5, label=obj_function)
41    plt.legend(loc='upper right')
42
43
44def main():
45    plt.figure(figsize=(10, 7))
46    simulate('Rastrigin')
47    plt.ticklabel_format(axis='y', style='sci', scilimits=(-2, 2))
48    plt.xticks(rotation=45)
49    plt.show()
50
51
52if __name__ == '__main__':
53    main()

نتایج را می‌توان با تحلیل نمودار مقدار تناسب-تعداد تکرارها برای هر یک از توابع بنچ‌مارک‌های بیان شده ارزیابی کرد. همچنین می‌توان خروجی optimizer.optimal_solution.pos را بررسی کرد که آیا الگوریتم ABC مقدار تخمینی خوبی نسبت به نقطه بهینه برای توابع بنچ‌مارک داشته است یا خیر.

با توجه به نمودار یک، به نظر می‌رسد الگوریتم ABC برای تابع Sphere عملکرد خوبی داشته است.

نمودار ۱

چنانکه در نمودار شماره دو نشان داده شده، عملکرد الگوریتم برای تابع Rosenbrock به میزانی سریع بوده که به سختی می‌توان نمودار آن را مشاهده کرد.

نمودار ۲

چنانکه از نمودار سه مشهود است، الگوریتم ABC عملکرد خوبی برای تابع Rastrigin نیز داشته است.

نمودار ۳

گام بعدی چیست؟

اکنون که چگونگی کارکرد و روش پیاده‌سازی الگوریتم ABC ارائه شد، می‌توان از آن برای حل مسائل جالب مانند خوشه‌بندی و بخش‌بندی تصویر (قطعه‌بندی تصویر | image segmentation) استفاده کرد.

برای این امر تنها کافیست تغییرات ریزی روی الگوریتم اعمال و فهمید که چگونه می‌توان آن مسائل را به مساله بهینه‌سازی تبدیل کرد.

اگر نوشته بالا برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شود:

^^

بر اساس رای ۱۷ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
medium
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *