ahmedfgad / TorchGA

Train PyTorch Models using the Genetic Algorithm with PyGAD
https://pygad.readthedocs.io
93 stars 15 forks source link

how to train physics-informed neural network with TorchGA? #4

Open xgxg1314 opened 2 years ago

xgxg1314 commented 2 years ago

Hi, thank you for your nice repository! I am trying recently to use TorchGA for training physics-informed neural network but failed. My code is as follows. `

!pip install pygad

!pip install pyDOE

import torch

import numpy as np import pygad.torchga import pygad

import time import scipy.io import math

from pyDOE import lhs

CUDA support

if torch.cuda.is_available(): device = torch.device('cuda') else: device = torch.device('cpu')

"""# neural network"""

the deep neural network

import torch

import torch.nn as nn from collections import OrderedDict

class FNN(torch.nn.Module): def init(self, layers): super(FNN, self).init()

parameters

  self.depth = len(layers) - 1
  self.activation = torch.nn.Tanh
  layer_list = list()
  for i in range(self.depth - 1): 
      layer_list.append(
          ('layer_%d' % i, torch.nn.Linear(layers[i], layers[i+1]))
      )
      layer_list.append(('activation_%d' % i, self.activation())) 
  layer_list.append(
      ('layer_%d' % (self.depth - 1), torch.nn.Linear(layers[-2], layers[-1]))
  )
  layerDict = OrderedDict(layer_list)
  # deploy layers
  self.layers = torch.nn.Sequential(layerDict)

def forward(self, x): out = self.layers(x) return out

"""# Res_func"""

predictions = pygad.torchga.predict(model=model,

solution=solution,

data=data_inputs)

def net_f(model, inputs, solution):

u = model(inputs) x = inputs[:,0:1] t = inputs[:,1:2]

u_x = torch.autograd.grad( u, x, grad_outputs=torch.ones_like(u), retain_graph=True, create_graph=True, allow_unused=True )[0]

u_xx = torch.autograd.grad( u_x, x, grad_outputs=torch.ones_like(u), retain_graph=True, create_graph=True, allow_unused=True )[0]

u_t = torch.autograd.grad( u, t, grad_outputs=torch.ones_like(u), retain_graph=True, create_graph=True, allow_unused=True )[0]

f_u = u_t + uu_x - (0.01/torch.tensor(math.pi))u_xx

return f_u

"""# forword pass"""

Forward pass for stream-pressure formulation

def net_u(model, inputs):

u = model(inputs)

return u

def net_u_x(model, inputs):

u = model(inputs) x = inputs[:,0:1] t = inputs[:,1:2]

u_x = torch.autograd.grad( u, x, grad_outputs=torch.ones_like(u), retain_graph=True, create_graph=True, allow_unused=True )[0]

return u, u_x

"""# loss_func"""

def loss_fn(model, input_f, input_xt_0, ouptput_u_0, input_xt_lb, input_xt_ub, solution):

f_u_pred = net_f(model, input_f, solution) u0_pred = net_u(model, input_xt_0, solution) u_lbpred, = net_u_x(model, input_xt_lb, solution) u_ubpred, = net_u_x(model, input_xt_ub, solution)

mse_0_u = torch.mean(torch.square(1.0*(ouptput_u_0 - u0_pred)))

mse_b_u = torch.mean(torch.square(u_lb_pred - 0)) + \ torch.mean(torch.square(u_ub_pred - 0)) #since ub/lb is 0

mse_f_u = torch.mean(torch.square(1.0*f_u_pred))

Total loss

loss_bic = mse_0_u + mse_b_u loss_res = mse_f_u loss = loss_bic + loss_res

return loss

构建适应度函数,类似于损失函数

def fitness_func(solution, sol_idx):

global input_f, input_xt_0, ouptput_u_0, input_xt_lb, input_xt_ub, model

# 这里的预测是否可以换成model直接前向传播????
# ========================================================
loss_total = loss_fn(model, input_f, input_xt_0, ouptput_u_0, input_xt_lb, input_xt_ub, solution)

loss_total_numpy = loss_total.detach().numpy() + 0.00000001

solution_fitness = 1.0 / loss_total_numpy

return solution_fitness

构建打印函数

def callback_generation(ga_instance): print("Generation = {generation}".format(generation=ga_instance.generations_completed)) print("Fitness = {fitness}".format(fitness=ga_instance.best_solution()[1]))

layers = [2] + [20]*5 + [1]

model = FNN(layers)

print(model)

print(model.state_dict)

lb = np.array([-1.0]) #x upper boundary ub = np.array([1.0]) #x lower boundary

N0 = 100 N_b = 25 #25 per upper and lower boundary, so 50 total N_f = 10000

load data, from Raissi et. al

data = scipy.io.loadmat('burgers_shock.mat')

t = data['t'].flatten()[:,None] x = data['x'].flatten()[:,None] Exact = data['usol'] Exact_u = np.real(Exact)

grab random points off the initial condition

idx_x = np.random.choice(x.shape[0], N0, replace=False)

x0 = x[idx_x,:] u0 = Exact_u[idx_x,0:1]

idx_t = np.random.choice(t.shape[0], N_b, replace=False) tb = t[idx_t,:]

=========== 残差采样点 =====================

X_f = lb + (ub-lb)*lhs(2, N_f)

时间不能为负数:细节

x_f = X_f[:,0:1] t_f = np.abs(X_f[:,1:2])

generate point vectors for training

X0 = np.concatenate((x0, 0x0), 1) # (x0, 0) X_lb = np.concatenate((0tb + lb[0], tb), 1) # (lb[0], tb) X_ub = np.concatenate((0*tb + ub[0], tb), 1) # (ub[0], tb)

seperate point vectors

x0 = X0[:,0:1] t0 = X0[:,1:2]

x_lb = X_lb[:,0:1] t_lb = X_lb[:,1:2]

x_ub = X_ub[:,0:1] t_ub = X_ub[:,1:2]

x_f_tf = torch.tensor(x_f, requires_grad=True).float() t_f_tf = torch.tensor(t_f, requires_grad=True).float()

x_0_tf = torch.tensor(x0).float() t_0_tf = torch.tensor(t0).float() u_0_tf = torch.tensor(u0).float()

x_lb_tf = torch.tensor(x_lb, requires_grad=True).float() t_lb_tf = torch.tensor(t_lb, requires_grad=True).float()

x_ub_tf = torch.tensor(x_ub, requires_grad=True).float() t_ub_tf = torch.tensor(t_ub, requires_grad=True).float()

input_f = torch.cat([x_f_tf, t_f_tf], 1)

input_xt_0 = torch.cat([x_0_tf, t_0_tf], 1) ouptput_u_0 = u_0_tf

input_xt_lb = torch.cat([x_lb_tf, t_lb_tf], 1) input_xt_ub = torch.cat([x_ub_tf, t_ub_tf], 1)

Create an instance of the pygad.torchga.TorchGA class to build the initial population.

torch_ga = pygad.torchga.TorchGA(model=model, num_solutions=10)

Prepare the PyGAD parameters. Check the documentation for more information: https://pygad.readthedocs.io/en/latest/README_pygad_ReadTheDocs.html#pygad-ga-class

num_generations = 250 # Number of generations. num_parents_mating = 5 # Number of solutions to be selected as parents in the mating pool. initial_population = torch_ga.population_weights # Initial population of network weights

ga_instance = pygad.GA(num_generations=num_generations, num_parents_mating=num_parents_mating, initial_population=initial_population, fitness_func=fitness_func, on_generation=callback_generation)

ga_instance.run()

`

then i get an error like this, but i have no idea how to fix it. Could you please give some advice about it?Thank you in advance ` TypeError Traceback (most recent call last) in () ----> 1 ga_instance.run() 2

5 frames /usr/local/lib/python3.7/dist-packages/pygad/pygad.py in run(self) 1190 1191 # Measuring the fitness of each chromosome in the population. Save the fitness in the last_generation_fitness attribute. -> 1192 self.last_generation_fitness = self.cal_pop_fitness() 1193 1194 best_solution, best_solution_fitness, best_match_idx = self.best_solution(pop_fitness=self.last_generation_fitness)

/usr/local/lib/python3.7/dist-packages/pygad/pygad.py in cal_pop_fitness(self) 1157 fitness = self.previous_generation_fitness[parent_idx] 1158 else: -> 1159 fitness = self.fitness_func(sol, sol_idx) 1160 if type(fitness) in GA.supported_int_float_types: 1161 pass

in fitness_func(solution, sol_idx) 8 # 这里的预测是否可以换成model直接前向传播???? 9 # ======================================================== ---> 10 loss_total = loss_fn(model, input_f, input_xt_0, ouptput_u_0, input_xt_lb, input_xt_ub, solution) 11 12 loss_total_numpy = loss_total.detach().numpy() + 0.00000001

in loss_fn(model, input_f, input_xt_0, ouptput_u_0, input_xt_lb, input_xt_ub, solution) 2 def loss_fn(model, input_f, input_xt_0, ouptput_u_0, input_xt_lb, input_xt_ub, solution): 3 ----> 4 f_u_pred = net_f(model, input_f, solution) 5 u0_pred = net_u(model, input_xt_0, solution) 6 u_lbpred, = net_u_x(model, input_xt_lb, solution)

in net_f(model, inputs, solution) 25 retain_graph=True, 26 create_graph=True, ---> 27 allow_unused=True 28 )[0] 29

/usr/local/lib/python3.7/dist-packages/torch/autograd/init.py in grad(outputs, inputs, grad_outputs, retain_graph, create_graph, only_inputs, allow_unused, is_grads_batched) 236 for your use case. Defaults to False. 237 """ --> 238 outputs = (outputs,) if isinstance(outputs, torch.Tensor) else tuple(outputs) 239 inputs = (inputs,) if isinstance(inputs, torch.Tensor) else tuple(inputs) 240 overridable_args = outputs + inputs

TypeError: 'NoneType' object is not iterable `