Spaces:
Sleeping
Sleeping
import streamlit as st | |
import numpy as np | |
import torch | |
import torch.nn as nn | |
import random | |
from sklearn.datasets import make_classification | |
from sklearn.model_selection import train_test_split | |
from sklearn.metrics import accuracy_score | |
# Define a function to generate a dataset | |
def generate_dataset(task_id): | |
X, y = make_classification(n_samples=100, n_features=10, n_informative=5, n_redundant=3, n_repeated=2, random_state=task_id) | |
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=task_id) | |
return X_train, X_test, y_train, y_test | |
# Define a neural network class | |
class Net(nn.Module): | |
def __init__(self): | |
super(Net, self).__init__() | |
self.fc1 = nn.Linear(10, 20) | |
self.fc2 = nn.Linear(20, 10) | |
self.fc3 = nn.Linear(10, 2) | |
def forward(self, x): | |
x = torch.relu(self.fc1(x)) | |
x = torch.relu(self.fc2(x)) | |
x = self.fc3(x) | |
return x | |
# Define a genetic algorithm class | |
class GeneticAlgorithm: | |
def __init__(self, population_size): | |
self.population_size = population_size | |
self.population = [Net() for _ in range(population_size)] | |
def selection(self, task_id): | |
X_train, X_test, y_train, y_test = generate_dataset(task_id) | |
fitness = [] | |
for net in self.population: | |
criterion = nn.CrossEntropyLoss() | |
optimizer = torch.optim.Adam(net.parameters(), lr=0.01) | |
for epoch in range(10): | |
optimizer.zero_grad() | |
inputs = torch.tensor(X_train, dtype=torch.float32) | |
labels = torch.tensor(y_train, dtype=torch.long) | |
outputs = net(inputs) | |
loss = criterion(outputs, labels) | |
loss.backward() | |
optimizer.step() | |
inputs = torch.tensor(X_test, dtype=torch.float32) | |
labels = torch.tensor(y_test, dtype=torch.long) | |
outputs = net(inputs) | |
_, predicted = torch.max(outputs, 1) | |
accuracy = accuracy_score(labels, predicted) | |
fitness.append(accuracy) | |
self.population = [self.population[i] for i in np.argsort(fitness)[-self.population_size//2:]] | |
def crossover(self): | |
offspring = [] | |
for _ in range(self.population_size//2): | |
parent1, parent2 = random.sample(self.population, 2) | |
child = Net() | |
child.fc1.weight.data = (parent1.fc1.weight.data + parent2.fc1.weight.data) / 2 | |
child.fc2.weight.data = (parent1.fc2.weight.data + parent2.fc2.weight.data) / 2 | |
child.fc3.weight.data = (parent1.fc3.weight.data + parent2.fc3.weight.data) / 2 | |
offspring.append(child) | |
self.population += offspring | |
def mutation(self): | |
for net in self.population: | |
if random.random() < 0.1: | |
net.fc1.weight.data += torch.randn_like(net.fc1.weight.data) * 0.1 | |
net.fc2.weight.data += torch.randn_like(net.fc2.weight.data) * 0.1 | |
net.fc3.weight.data += torch.randn_like(net.fc3.weight.data) * 0.1 | |
# Streamlit app | |
st.title("Evolution of Sub-Models") | |
# Parameters | |
st.sidebar.header("Parameters") | |
population_size = st.sidebar.slider("Population size", 10, 100, 50) | |
num_tasks = st.sidebar.slider("Number of tasks", 1, 10, 5) | |
num_generations = st.sidebar.slider("Number of generations", 1, 100, 10) | |
# Run the evolution | |
if st.button("Run evolution"): | |
ga = GeneticAlgorithm(population_size) | |
for generation in range(num_generations): | |
for task_id in range(num_tasks): | |
ga.selection(task_id) | |
ga.crossover() | |
ga.mutation() | |
st.write(f"Generation {generation+1} complete") | |
# Evaluate the final population | |
final_accuracy = [] | |
for task_id in range(num_tasks): | |
X_train, X_test, y_train, y_test = generate_dataset(task_id) | |
accuracy = [] | |
for net in ga.population: | |
criterion = nn.CrossEntropyLoss() | |
optimizer = torch.optim.Adam(net.parameters(), lr=0.01) | |
for epoch in range(10): | |
optimizer.zero_grad() | |
inputs = torch.tensor(X_train, dtype=torch.float32) | |
labels = torch.tensor(y_train, dtype=torch.long) | |
outputs = net(inputs) | |
loss = criterion(outputs, labels) | |
loss.backward() | |
optimizer.step() |