Skip to content

Commit ab670a1

Browse files
authored
Merge pull request #150 from NeuroDiffGym/v0.5.0
fix bug in H1 and H1-semi loss
2 parents 7bb802a + 9eae9ec commit ab670a1

File tree

4 files changed

+106
-14
lines changed

4 files changed

+106
-14
lines changed

neurodiffeq/losses.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ def _infinity_norm(residual, funcs, coords):
1616

1717
def _h1_norm(residual, funcs, coords):
1818
g = grad(residual, *coords)
19-
rg = torch.cat([residual, *g])
19+
rg = torch.cat([residual, *g], dim=1)
2020
return (rg ** 2).mean()
2121

2222

2323
def _h1_semi_norm(residual, funcs, coords):
2424
g = grad(residual, *coords)
25-
g = torch.cat(g)
25+
g = torch.cat(g, dim=1)
2626
return (g ** 2).mean()
2727

2828

neurodiffeq/solvers.py

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,19 @@ class BaseSolver(ABC, PretrainedSolver):
5757
The optimizer to be used for training.
5858
:type optimizer: `torch.nn.optim.Optimizer`, optional
5959
:param criterion:
60-
A function that maps a PDE residual vector (torch tensor with shape (-1, 1)) to a scalar loss.
61-
:type criterion: callable, optional
60+
The loss function used for training.
61+
62+
- If a str, must be present in the keys of `neurodiffeq.losses._losses`.
63+
- If a `torch.nn.modules.loss._Loss` instance, just pass the instance.
64+
- If any other callable, it must map
65+
A) a residual tensor (shape `(n_points, n_equations)`),
66+
B) a function values tuple (length `n_funcs`, each element a tensor of shape `(n_points, 1)`), and
67+
C) a coordinate values tuple (length `n_coords`, each element a tensor of shape `(n_coords, 1)`
68+
to a tensor of empty shape (i.e. a scalar). The returned tensor must be connected to the computational graph,
69+
so that backpropagation can be performed.
70+
71+
:type criterion:
72+
str or `torch.nn.moduesl.loss._Loss` or callable
6273
:param n_batches_train:
6374
Number of batches to train in every epoch, where batch-size equals ``train_generator.size``.
6475
Defaults to 1.
@@ -687,8 +698,19 @@ class SolverSpherical(BaseSolver):
687698
Defaults to a ``torch.optim.Adam`` instance that trains on all parameters of ``nets``.
688699
:type optimizer: ``torch.nn.optim.Optimizer``, optional
689700
:param criterion:
690-
Function that maps a PDE residual tensor (of shape (-1, 1)) to a scalar loss.
691-
:type criterion: callable, optional
701+
The loss function used for training.
702+
703+
- If a str, must be present in the keys of `neurodiffeq.losses._losses`.
704+
- If a `torch.nn.modules.loss._Loss` instance, just pass the instance.
705+
- If any other callable, it must map
706+
A) a residual tensor (shape `(n_points, n_equations)`),
707+
B) a function values tuple (length `n_funcs`, each element a tensor of shape `(n_points, 1)`), and
708+
C) a coordinate values tuple (length `n_coords`, each element a tensor of shape `(n_coords, 1)`
709+
to a tensor of empty shape (i.e. a scalar). The returned tensor must be connected to the computational graph,
710+
so that backpropagation can be performed.
711+
712+
:type criterion:
713+
str or `torch.nn.moduesl.loss._Loss` or callable
692714
:param n_batches_train:
693715
Number of batches to train in every epoch, where batch-size equals ``train_generator.size``.
694716
Defaults to 1.
@@ -935,8 +957,19 @@ class Solver1D(BaseSolver):
935957
Defaults to a ``torch.optim.Adam`` instance that trains on all parameters of ``nets``.
936958
:type optimizer: ``torch.nn.optim.Optimizer``, optional
937959
:param criterion:
938-
Function that maps a ODE residual tensor (of shape (-1, 1)) to a scalar loss.
939-
:type criterion: callable, optional
960+
The loss function used for training.
961+
962+
- If a str, must be present in the keys of `neurodiffeq.losses._losses`.
963+
- If a `torch.nn.modules.loss._Loss` instance, just pass the instance.
964+
- If any other callable, it must map
965+
A) a residual tensor (shape `(n_points, n_equations)`),
966+
B) a function values tuple (length `n_funcs`, each element a tensor of shape `(n_points, 1)`), and
967+
C) a coordinate values tuple (length `n_coords`, each element a tensor of shape `(n_coords, 1)`
968+
to a tensor of empty shape (i.e. a scalar). The returned tensor must be connected to the computational graph,
969+
so that backpropagation can be performed.
970+
971+
:type criterion:
972+
str or `torch.nn.moduesl.loss._Loss` or callable
940973
:param n_batches_train:
941974
Number of batches to train in every epoch, where batch-size equals ``train_generator.size``.
942975
Defaults to 1.
@@ -1108,8 +1141,19 @@ class BundleSolver1D(BaseSolver):
11081141
Defaults to a ``torch.optim.Adam`` instance that trains on all parameters of ``nets``.
11091142
:type optimizer: ``torch.nn.optim.Optimizer``, optional
11101143
:param criterion:
1111-
Function that maps a ODE residual tensor (of shape (-1, 1)) to a scalar loss.
1112-
:type criterion: callable, optional
1144+
The loss function used for training.
1145+
1146+
- If a str, must be present in the keys of `neurodiffeq.losses._losses`.
1147+
- If a `torch.nn.modules.loss._Loss` instance, just pass the instance.
1148+
- If any other callable, it must map
1149+
A) a residual tensor (shape `(n_points, n_equations)`),
1150+
B) a function values tuple (length `n_funcs`, each element a tensor of shape `(n_points, 1)`), and
1151+
C) a coordinate values tuple (length `n_coords`, each element a tensor of shape `(n_coords, 1)`
1152+
to a tensor of empty shape (i.e. a scalar). The returned tensor must be connected to the computational graph,
1153+
so that backpropagation can be performed.
1154+
1155+
:type criterion:
1156+
str or `torch.nn.moduesl.loss._Loss` or callable
11131157
:param n_batches_train:
11141158
Number of batches to train in every epoch, where batch-size equals ``train_generator.size``.
11151159
Defaults to 1.
@@ -1308,8 +1352,19 @@ class Solver2D(BaseSolver):
13081352
Defaults to a ``torch.optim.Adam`` instance that trains on all parameters of ``nets``.
13091353
:type optimizer: ``torch.nn.optim.Optimizer``, optional
13101354
:param criterion:
1311-
Function that maps a PDE residual tensor (of shape (-1, 1)) to a scalar loss.
1312-
:type criterion: callable, optional
1355+
The loss function used for training.
1356+
1357+
- If a str, must be present in the keys of `neurodiffeq.losses._losses`.
1358+
- If a `torch.nn.modules.loss._Loss` instance, just pass the instance.
1359+
- If any other callable, it must map
1360+
A) a residual tensor (shape `(n_points, n_equations)`),
1361+
B) a function values tuple (length `n_funcs`, each element a tensor of shape `(n_points, 1)`), and
1362+
C) a coordinate values tuple (length `n_coords`, each element a tensor of shape `(n_coords, 1)`
1363+
to a tensor of empty shape (i.e. a scalar). The returned tensor must be connected to the computational graph,
1364+
so that backpropagation can be performed.
1365+
1366+
:type criterion:
1367+
str or `torch.nn.moduesl.loss._Loss` or callable
13131368
:param n_batches_train:
13141369
Number of batches to train in every epoch, where batch-size equals ``train_generator.size``.
13151370
Defaults to 1.

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ def func(m):
1717

1818
setuptools.setup(
1919
name="neurodiffeq",
20-
version="0.4.0",
20+
version="0.5.0",
2121
author="neurodiffgym",
2222
author_email="shuheng_liu@g.harvard.edu",
2323
description="A light-weight & flexible library for solving differential equations using neural networks based on PyTorch. ",
2424
long_description=long_description,
2525
long_description_content_type="text/markdown",
2626
url="https://github.com/NeuroDiffGym/neurodiffeq",
27-
download_url="https://github.com/NeuroDiffGym/neurodiffeq/archive/v0.4.0.tar.gz",
27+
download_url="https://github.com/NeuroDiffGym/neurodiffeq/archive/v0.5.0.tar.gz",
2828
keywords=[
2929
"neural network",
3030
"deep learning",

tests/test_losses.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import pytest
2+
import torch
3+
from neurodiffeq import diff
4+
from neurodiffeq.losses import _losses as losses
5+
6+
N = 100
7+
8+
9+
def pde_system(u, v, w, x, y):
10+
return [
11+
diff(u, x, order=2) + diff(u, y, order=2),
12+
diff(v, x, order=2) + diff(v, y, order=2),
13+
diff(w, x, order=2) + diff(w, y, order=2),
14+
]
15+
16+
17+
def get_rfx(n_input, n_output, n_equation):
18+
coords = [torch.rand((N, 1), requires_grad=True) for _ in range(n_input)]
19+
coords_tensor = torch.cat(coords, dim=1)
20+
funcs = [torch.sigmoid(torch.sum(coords_tensor, dim=1, keepdim=True)) for _ in range(n_output)]
21+
residual = [diff(funcs[0], coords[0]) + funcs[0] for _ in range(n_equation)]
22+
residual = torch.cat(residual, dim=1)
23+
return residual, funcs, coords
24+
25+
26+
@pytest.mark.parametrize(argnames='n_input', argvalues=[1, 3])
27+
@pytest.mark.parametrize(argnames='n_output', argvalues=[1, 3])
28+
@pytest.mark.parametrize(argnames='n_equation', argvalues=[1, 3])
29+
@pytest.mark.parametrize(
30+
argnames=('loss_name', 'loss_fn'),
31+
argvalues=losses.items(),
32+
)
33+
def test_losses(n_input, n_output, n_equation, loss_name, loss_fn):
34+
r, f, x = get_rfx(n_input, n_output, n_equation)
35+
loss = loss_fn(r, f, x)
36+
assert loss.shape == (), f"{loss_name} doesn't output scalar"
37+
assert loss.requires_grad, f"{loss_name} doesn't require gradient"

0 commit comments

Comments
 (0)