Harnessing Genetic Algorithms to Enhance Neural Networks
Written on
Chapter 1: Introduction to Neural Networks and Genetic Algorithms
In the realm of advancing machine learning techniques, particularly with neural networks, experts are continually searching for innovative ways to boost prediction accuracy and improve computational efficiency. One intriguing approach is utilizing genetic algorithms to refine neural network structures, particularly in complex tasks such as forecasting housing prices in Boston. But what does this entail, and how can we explain it in simpler terms?
Understanding the Fundamental Concepts
Neural Networks: Essentially, neural networks are algorithms inspired by the human brain's architecture, designed to detect patterns. They process sensory information through a method akin to machine perception, categorizing or clustering raw data. The patterns they identify are numerical and organized in vectors, which serve as the foundation for translating all real-world data—be it images, sounds, texts, or time series.
Genetic Algorithms (GAs): These algorithms belong to the category of evolutionary computing, a family of strategies for global optimization that draw inspiration from Darwinian natural selection. In basic terms, genetic algorithms imitate the evolutionary process to discover solutions to problems by applying principles of selection, crossover (or breeding), and mutation.
Bridging Neural Networks with Genetic Algorithms
Applying genetic algorithms to neural networks is akin to refining an architectural design by selecting optimal parameters through a series of evolutionary adjustments. Just as an architect iterates through numerous designs to achieve the most stable and visually appealing structure, genetic algorithms explore various neural network configurations to identify the most effective architecture for a specific task—like predicting housing prices in Boston.
Starting Simple
We begin with a dataset—the Boston Housing dataset—which includes vital information such as crime rates, property taxes, and the number of rooms per property. This dataset acts as our foundational element, similar to land designated for constructing a building (the neural network model).
Preprocessing
Before any construction starts, the land must be assessed and prepared. Likewise, we preprocess our data by dividing it into training and testing sets, standardizing features for consistency, and converting the data into a format digestible for our neural network.
Constructing the Neural Network
With our groundwork laid, we proceed to build the structure. This step involves defining the neural network's architecture—deciding on the number of layers (floors) and the number of neurons (rooms) on each layer, all aimed at ensuring optimal functionality for its users (predictions).
Optimization Using Genetic Algorithms
Similar to how architects revise designs for enhanced stability and functionality, we apply genetic algorithms to refine our neural network's architecture. Through selection (choosing the best designs), crossover (merging features from different designs), and mutation (making slight adjustments), we iteratively evolve our network to improve its prediction accuracy.
Simplifying Complexity
This technique embodies the fusion of two powerful concepts in machine learning: the pattern recognition abilities of neural networks and the optimization strengths of genetic algorithms. By merging these approaches, we can navigate the expansive array of potential models more effectively, akin to discovering the best architectural design through iterative evolution.
In summary, while the merger of neural networks and genetic algorithms may initially appear complex, framing it in the context of architectural design simplifies the understanding. Essentially, we are employing a series of evolutionary steps to refine our model, ensuring it can accurately predict housing prices based on the diverse features of the Boston Housing dataset.
With this foundational knowledge, we can delve deeper into the specifics of implementing and optimizing our model, ready to explore technical details with a clearer grasp of the overarching objectives and methodologies.
Now let's start coding:
#### Data: Boston Housing Prices
Keras Built-in function — [link]
Excel file from Kaggle — [link]
The Boston house-price dataset by Harrison, D. and Rubinfeld, D.L., titled 'Hedonic prices and the demand for clean air,' offers 14 attributes for each case:
- CRIM: per capita crime rate by town
- ZN: proportion of residential land zoned for lots over 25,000 sq.ft.
- INDUS: proportion of non-retail business acres per town
- CHAS: Charles River dummy variable (1 if tract bounds river; 0 otherwise)
- NOX: nitric oxides concentration (parts per 10 million)
- RM: average number of rooms per dwelling
- AGE: proportion of owner-occupied units built prior to 1940
- DIS: weighted distances to five Boston employment centers
- RAD: index of accessibility to radial highways
- TAX: full-value property-tax rate per USD 10,000
- PTRATIO: pupil-teacher ratio by town
- B: 1000*(Bk — 0.63)² where Bk is the proportion of blacks by town
- LSTAT: % lower status of the population
- MEDV: Median value of owner-occupied homes in $1000's
Original Data — http://lib.stat.cmu.edu/datasets/boston
Step 1: Include Required Libraries
Import necessary libraries for machine learning.
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
import random
import math
import time
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
This process involves establishing an environment to build a neural network model by importing essential libraries and modules, such as NumPy, Pandas, TensorFlow, and others.
Step 2: Importing Data
Upload files in Google Colab.
from google.colab import files
uploaded = files.upload()
This prompts a file upload dialog, allowing you to select files from your local machine for the Colab runtime environment. The uploaded files can be accessed in subsequent code cells.
Step 3: Define Variables for Training
Split, preprocess, and convert data arrays.
RANDOM_SEED = 27
X_train, X_test = train_test_split(df, test_size=0.2, random_state=RANDOM_SEED)
y_train = X_train['MEDV']
X_train = X_train.drop(['MEDV'], axis=1)
y_test = X_test['MEDV']
X_test = X_test.drop(['MEDV'], axis=1)
mean = X_train.mean(axis=0)
std = X_train.std(axis=0)
X_train = (X_train - mean) / std
X_test = (X_test - mean) / std
X_train = X_train.to_numpy()
y_train = y_train.to_numpy()
X_test = X_test.to_numpy()
y_test = y_test.to_numpy()
This preprocessing step is critical before training a machine learning model, ensuring that the data is clean and well-prepared.
Step 5: Create and Compile the Neural Network
def network(nn_in, nn_hidden1, nn_hidden2, nn_out):
model = Sequential()
model.add(Dense(nn_hidden1, input_dim=nn_in, activation='relu'))
model.add(Dense(nn_hidden2, activation='relu'))
model.add(Dense(nn_out, activation='linear'))
model.compile(loss='mse', optimizer='adam', metrics=['mae'])
return model
This function simplifies the creation of a neural network model for regression tasks.
Step 6: Execute a Single Episode
def run_episode(X_train,y_train,X_test,y_test,nn_in,nn_out, policy):
nn_hidden1,nn_hidden2 = policy
model = network(nn_in, nn_hidden1, nn_hidden2, nn_out)
model.fit(X_train, y_train, epochs=100, verbose=0, validation_split=0.05)
_, accuracy = model.evaluate(X_test, y_test)
return accuracy
This function streamlines the training and evaluation of the neural network model.
Genetic Algorithms in Action
#### Evaluate Policy Using a Neural Network
def evaluate_policy(X_train,y_train,X_test,y_test,nn_in,nn_out, policy, n_episodes=1):
total_rewards = 0.0
for _ in range(n_episodes):
total_rewards += 1/run_episode(X_train,y_train,X_test,y_test,nn_in,nn_out, policy)return total_rewards / n_episodes
This function assesses the effectiveness of a policy by running multiple episodes.
#### Generating Random Policy
def gen_random_policy(max_node,num_hiddenlayers):
return np.random.choice(max_node+1, size=((num_hiddenlayers)))
This function creates a random policy for the neural network based on specified parameters.
#### Crossover and Mutation Functions
def crossover(policy1, policy2,num_hiddenlayers):
new_policy = policy1.copy()
for i in range(num_hiddenlayers):
rand = np.random.uniform()
if rand > 0.5:
new_policy[i] = policy2[i]return new_policy
def mutation(policy,num_hiddenlayers,max_node, p=0.05):
new_policy = policy.copy()
for i in range(num_hiddenlayers):
rand = np.random.uniform()
if rand < p:
new_policy[i] = np.random.choice(max_node+1)return new_policy
These functions introduce genetic operations to evolve the policies used in the neural network.
Evolutionary Algorithm to Find the Best Policy
if __name__ == '__main__':
random.seed(1234)
np.random.seed(1234)
n_policy = 10
n_steps = 5
start = time.time()
policy_pop = [gen_random_policy(max_node,num_hiddenlayers) for _ in range(n_policy)]
for idx in range(n_steps):
policy_scores = [evaluate_policy(X_train,y_train,X_test,y_test,nn_in,nn_out, p) for p in policy_pop]
print('Generation %d : MaxScore=%0.2f & AvgScore=%0.3f' %(idx+1, max(policy_scores), sum(policy_scores)/len(policy_scores)))
policy_ranks = list(reversed(np.argsort(policy_scores)))
elite_set = [policy_pop[x] for x in policy_ranks[:5]]
select_probs = np.array(policy_scores) / np.sum(policy_scores)
if np.sum(policy_scores)==0:
pp = 1/np.array(policy_scores).size
select_probs = pp*np.ones(np.array(policy_scores).size)
child_set = [crossover(
policy_pop[np.random.choice(range(n_policy), p=select_probs)],
policy_pop[np.random.choice(range(n_policy), p=select_probs)],num_hiddenlayers)
for _ in range(n_policy - 5)]
mutated_list = [mutation(p,num_hiddenlayers,max_node) for p in child_set]
policy_pop = elite_set
policy_pop += mutated_list
policy_score = [evaluate_policy(X_train,y_train,X_test,y_test,nn_in,nn_out, p) for p in policy_pop]
best_policy = policy_pop[np.argmax(policy_score)]
end = time.time()
print('Best policy score=%0.2f Time taken(seconds)=%4.4f Average Score=%0.3f'
%(np.max(policy_score), (end-start), sum(policy_score)/len(policy_score)))print("Best Policy is:", best_policy)
This code employs a genetic algorithm to optimize the hyperparameters of the neural network model, enhancing its performance and efficiency.
Video Description: This video delves into how genetic algorithms can be integrated with machine learning to facilitate materials exploration effectively.
Video Description: Watch this tutorial on how to train a neural network using genetic algorithms, providing insights into optimization techniques for enhanced model performance.