Navigation

Introduction to AI

Machine Learning

Deep Learning

Generative AI

Tools & Frameworks

General

Bee Algorithm and Swarm Intelligence in AI

Nature has evolved remarkably efficient problem-solving systems over millions of years. Honeybee colonies, for example, solve the problem of finding and exploiting food sources across vast areas using distributed, decentralized search — no central coordinator, no global knowledge, yet the colony reliably discovers and allocates foragers to the richest nectar sources with near-optimal efficiency.

Swarm intelligence is the field that distills such biological collective behaviors into computational optimization algorithms. The Bee Algorithm (BA) and Artificial Bee Colony (ABC) algorithm are among the most successful swarm-based optimization methods, finding applications from neural network training to robotic path planning.

The Biology of Honeybee Foraging

To understand the Bee Algorithm, we need to understand honeybee foraging:

  1. Scout bees explore the environment randomly, searching for food sources
  2. When a scout finds a rich source, it returns to the hive and performs the waggle dance — a figure-8 movement whose duration and direction encode the distance and direction of the food source
  3. Onlooker bees (unemployed foragers watching dances in the hive) probabilistically choose which food source to visit based on dance quality — more energetic dances for richer sources attract more followers
  4. Employed bees exploit known food sources, performing local searches around them
  5. When a source is exhausted, its employed bees abandon it and become scouts again

This system naturally balances exploration (scouts searching randomly) with exploitation (employed bees intensifying around good sources), and it dynamically reallocates resources from poor sources to rich ones.

The Artificial Bee Colony (ABC) Algorithm

The ABC algorithm (Karaboga, 2005) formalizes this behavior as an optimization framework:

Problem: Minimize $f(x)$ where $x \in \mathbb{R}^D$ is the search solution.

Population: $N$ food source positions ${x_1, \dots, x_N}$ (potential solutions).

Three phases:

Phase 1: Employed Bee Phase

Each employed bee modifies its current solution by moving toward or away from a randomly selected neighbor:

$$v_{ij} = x_{ij} + \phi_{ij}(x_{ij} - x_{kj})$$

Where:

  • $i$ is the current solution index
  • $j$ is a randomly chosen dimension
  • $k \neq i$ is a randomly chosen neighbor solution
  • $\phi_{ij} \in [-1, 1]$ is a random perturbation factor

If the new solution $v_i$ is better than $x_i$, replace $x_i$ with $v_i$ (greedy selection).

Phase 2: Onlooker Bee Phase

Onlooker bees select food sources proportionally to their fitness. Better solutions attract more onlookers for additional local search:

$$P_i = \frac{f_i^{-1}}{\sum_{n=1}^{N} f_n^{-1}}$$

(For minimization, where lower fitness values are better)

Each onlooker bee selected for source $i$ performs the same modification step as employed bees.

Phase 3: Scout Bee Phase

If a solution $x_i$ has not improved for more than limit cycles, it is abandoned and replaced by a new randomly generated solution:

$$x_{ij} = x_j^{\min} + \text{rand}(0,1) \cdot (x_j^{\max} - x_j^{\min})$$

This prevents premature convergence by injecting fresh exploration.

Python Implementation

import numpy as np
from typing import Callable

class ArtificialBeeColony:
    def __init__(
        self,
        objective_func: Callable,
        n_dim: int,
        bounds: list[tuple[float, float]],
        n_bees: int = 50,
        limit: int = 100,
        max_iterations: int = 1000,
    ):
        self.f = objective_func
        self.n_dim = n_dim
        self.bounds = np.array(bounds)  # (n_dim, 2)
        self.n_bees = n_bees  # Also number of food sources
        self.limit = limit
        self.max_iter = max_iterations

    def _random_solution(self) -> np.ndarray:
        lb, ub = self.bounds[:, 0], self.bounds[:, 1]
        return lb + np.random.rand(self.n_dim) * (ub - lb)

    def _clamp(self, x: np.ndarray) -> np.ndarray:
        return np.clip(x, self.bounds[:, 0], self.bounds[:, 1])

    def optimize(self) -> tuple[np.ndarray, float]:
        # Initialize food sources
        population = np.array([self._random_solution() for _ in range(self.n_bees)])
        fitness = np.array([self.f(x) for x in population])
        trial = np.zeros(self.n_bees, dtype=int)  # Trial counter per source

        best_solution = population[fitness.argmin()].copy()
        best_fitness = fitness.min()

        for iteration in range(self.max_iter):
            # --- Employed Bee Phase ---
            for i in range(self.n_bees):
                j = np.random.randint(self.n_dim)  # Random dimension
                k = np.random.choice([x for x in range(self.n_bees) if x != i])
                phi = np.random.uniform(-1, 1)

                candidate = population[i].copy()
                candidate[j] = population[i][j] + phi * (population[i][j] - population[k][j])
                candidate = self._clamp(candidate)

                candidate_fitness = self.f(candidate)
                if candidate_fitness < fitness[i]:
                    population[i] = candidate
                    fitness[i] = candidate_fitness
                    trial[i] = 0
                else:
                    trial[i] += 1

            # --- Onlooker Bee Phase ---
            # Compute selection probabilities
            inv_fitness = 1.0 / (fitness + 1e-10)
            probs = inv_fitness / inv_fitness.sum()

            for _ in range(self.n_bees):
                i = np.random.choice(self.n_bees, p=probs)
                j = np.random.randint(self.n_dim)
                k = np.random.choice([x for x in range(self.n_bees) if x != i])
                phi = np.random.uniform(-1, 1)

                candidate = population[i].copy()
                candidate[j] = population[i][j] + phi * (population[i][j] - population[k][j])
                candidate = self._clamp(candidate)

                candidate_fitness = self.f(candidate)
                if candidate_fitness < fitness[i]:
                    population[i] = candidate
                    fitness[i] = candidate_fitness
                    trial[i] = 0
                else:
                    trial[i] += 1

            # --- Scout Bee Phase ---
            for i in range(self.n_bees):
                if trial[i] >= self.limit:
                    population[i] = self._random_solution()
                    fitness[i] = self.f(population[i])
                    trial[i] = 0

            # Track best
            current_best_idx = fitness.argmin()
            if fitness[current_best_idx] < best_fitness:
                best_fitness = fitness[current_best_idx]
                best_solution = population[current_best_idx].copy()

        return best_solution, best_fitness


# Example: optimize the Rosenbrock function
def rosenbrock(x):
    return sum(100*(x[i+1] - x[i]**2)**2 + (1 - x[i])**2 for i in range(len(x)-1))

abc = ArtificialBeeColony(
    objective_func=rosenbrock,
    n_dim=5,
    bounds=[(-5, 5)] * 5,
    n_bees=50,
    limit=100,
    max_iterations=2000
)
solution, fitness = abc.optimize()
print(f"Best solution: {solution}")
print(f"Best fitness: {fitness:.6f}")  # Should be near 0.0

The Original Bee Algorithm (BA)

The BA (Pham et al., 2005) differs slightly from ABC, distinguishing between elite sites (best solutions) and selected sites (moderately good solutions), with more foragers allocated to elite sites:

1. Initialize: Randomly place n scout bees and evaluate fitness
2. Select m best sites (elite + selected)
3. Recruit e > m foragers for the top e (elite) sites
4. Recruit fewer foragers for the remaining selected sites
5. Perform neighborhood search around each selected site
6. Replace abandoned sites with new random scouts
7. Update the best solution
8. Repeat from step 2

The key tuning parameters are:

  • n: total scout bees per iteration
  • m: selected sites (m < n)
  • e: elite sites (e < m)
  • Neighborhood size (shrinks over iterations as local exploitation deepens)

Swarm Intelligence: The Broader Family

The Bee Algorithm belongs to a rich family of swarm intelligence methods:

AlgorithmInspired ByKey MechanismBest For
Ant Colony Optimization (ACO)Ant pheromone trailsStigmergy (indirect communication)Discrete combinatorial problems (TSP, routing)
Particle Swarm Optimization (PSO)Bird flockingVelocity updates toward personal and global bestsContinuous optimization
ABC / Bee AlgorithmHoneybee foragingEmployed/onlooker/scout rolesContinuous and mixed optimization
Firefly AlgorithmFirefly bioluminescenceAttraction by brightnessMulti-modal continuous optimization
Grey Wolf Optimizer (GWO)Wolf pack hierarchyAlpha/beta/delta leadershipConstrained optimization
Whale OptimizationHumpback whale bubble-net feedingSpiral position updateContinuous optimization
Fish School SearchFish schoolingWeight-based collective movementMulti-dimensional optimization

All of these share the same fundamental pattern: a population of simple agents that collectively explore a search space through local interactions and communication, without any agent needing global knowledge.

Applications in AI and Machine Learning

Hyperparameter Optimization

ABC and BA can optimize neural network hyperparameters (learning rate, layer sizes, dropout rates) in the same way they optimize mathematical functions — each “food source” is a hyperparameter configuration, and fitness is validation loss:

def hyperparameter_fitness(params):
    """
    params: [learning_rate, n_hidden, dropout_rate, batch_size_log2]
    Returns validation loss (to minimize)
    """
    lr = 10 ** (-params[0] * 5)  # Map [0,1] → [10^-5, 10^0]
    n_hidden = int(params[1] * 500 + 50)  # [50, 550]
    dropout = params[2]  # [0, 1]
    batch_size = int(2 ** (params[3] * 4 + 3))  # [8, 128]

    model = build_model(n_hidden=n_hidden, dropout=dropout)
    return train_and_evaluate(model, lr=lr, batch_size=batch_size)

abc_hpo = ArtificialBeeColony(
    objective_func=hyperparameter_fitness,
    n_dim=4,
    bounds=[(0,1)] * 4,
    n_bees=30,
    max_iterations=500
)
best_params, best_val_loss = abc_hpo.optimize()

Neural Architecture Search (NAS)

Swarm algorithms have been applied to NAS by encoding architectures as vectors (number of layers, filter sizes, skip connections). Each bee represents an architecture configuration and fitness is the model’s task performance.

Feature Selection

In high-dimensional datasets, swarm algorithms can efficiently search the binary space of included/excluded features. Each bee represents a feature subset, and fitness is model accuracy using only those features:

def feature_subset_fitness(binary_mask):
    """Select features based on a (continuous → thresholded) mask."""
    selected = binary_mask > 0.5
    if selected.sum() == 0:
        return float('inf')  # No features selected = invalid
    X_subset = X_train[:, selected]
    return cross_val_error(classifier, X_subset, y_train)

Robot Path Planning

Swarm algorithms are widely used in robotics for path planning in complex environments, where the search space is high-dimensional and discontinuous. The exploration-exploitation balance of bee-inspired algorithms maps naturally to path planning: scouts explore new routes while employed bees exploit and refine promising paths.

Clustering and Unsupervised Learning

ABC-based clustering algorithms (using cluster centroids as food sources and cluster quality metrics as fitness) have been shown to outperform k-means on non-convex and multi-scale cluster structures.

Strengths and Limitations

Strengths:

  • Simple to implement, few hyperparameters
  • Good balance of exploration and exploitation (limits premature convergence)
  • Effective on multi-modal landscapes with many local optima
  • Parallelizable (bees are independent between fitness evaluations)

Limitations:

  • Slower convergence than gradient-based methods when gradients are available
  • Does not scale well to very high dimensions (>100D) without modification
  • Requires many function evaluations, which is prohibitive for expensive objectives
  • No convergence guarantees for noisy or non-stationary objectives

When to Choose Swarm Intelligence

Swarm intelligence methods are best suited for:

  • Black-box optimization: No gradient information available
  • Non-differentiable objectives: Discrete choices, simulation-based evaluation
  • Multi-modal landscapes: Many local optima that trap gradient-based methods
  • Constrained optimization: With penalty functions for constraint violations
  • Moderate dimensionality (5–100D): Where population-based search is feasible

For high-dimensional continuous optimization with available gradients, Adam, LBFGS, or Bayesian optimization typically outperform swarm methods.

Swarm intelligence represents a fascinating cross-disciplinary convergence of evolutionary biology, complex systems theory, and machine learning — a reminder that nature’s solutions to hard optimization problems often translate powerfully into computational algorithms.