Skip to content

Commit 84afdd3

Browse files
authored
Merge pull request #257 from SURGroup/Development
Development - SciML
2 parents bd510fb + 943a650 commit 84afdd3

File tree

180 files changed

+10623
-47
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

180 files changed

+10623
-47
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ venv/
216216
ENV/
217217
env.bak/
218218
venv.bak/
219+
.vscode/
219220

220221
# Spyder project settings
221222
.spyderproject

azure-pipelines.yml

+6-37
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pr:
2323

2424
jobs:
2525
- job: "Build_UQpy_and_run_tests"
26+
timeoutInMinutes: 0
2627
pool:
2728
vmImage: "macOS-latest"
2829

@@ -48,7 +49,7 @@ jobs:
4849
displayName: Shows currently compiling version
4950
5051
- task: SonarCloudPrepare@1
51-
condition: or(eq(variables['Build.SourceBranch'], 'refs/heads/master'),eq(variables['Build.SourceBranch'], 'refs/heads/Development'),eq(variables['Build.Reason'], 'PullRequest'))
52+
condition: or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['System.PullRequest.TargetBranch'], 'master'))
5253
inputs:
5354
SonarCloud: 'SonarCloud.UQpy'
5455
organization: 'jhusurg'
@@ -67,13 +68,12 @@ jobs:
6768
6869
- script: |
6970
pip install pylint
70-
pylint --ignored-modules=numpy,scipy,matplotlib,sklearn --disable=E0202,E1136,E1120,E0401,E0213 --disable=R,C,W src/UQpy
71+
pylint --ignored-modules=numpy,scipy,matplotlib,sklearn,torch --disable=E0202,E1136,E1120,E0401,E0213,E1102 --disable=R,C,W src/UQpy
7172
displayName: "Running Pylint"
7273
7374
- script: |
74-
pip install pytest pytest-cov
75+
pip install pytest pytest-cov hypothesis
7576
PYTHONPATH=src pytest --cov=src tests/ --junitxml=junit/test-results.xml --cov-report=xml --cov-report=html
76-
# PYTHONPATH=src pytest tests/unit_test/*.py --cov=src tests/ --junitxml=junit/test-results.xml --cov-report=xml --cov-report=html
7777
workingDirectory: $(Build.SourcesDirectory)
7878
displayName: 'Test with pytest'
7979
@@ -91,10 +91,10 @@ jobs:
9191
additionalCodeCoverageFiles: '$(System.DefaultWorkingDirectory)/ **'
9292

9393
- task: SonarCloudAnalyze@1
94-
condition: or(eq(variables['Build.SourceBranch'], 'refs/heads/master'),eq(variables['Build.SourceBranch'], 'refs/heads/Development'),eq(variables['Build.Reason'], 'PullRequest'))
94+
condition: or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['System.PullRequest.TargetBranch'], 'master'))
9595

9696
- task: SonarCloudPublish@1
97-
condition: or(eq(variables['Build.SourceBranch'], 'refs/heads/master'),eq(variables['Build.SourceBranch'], 'refs/heads/Development'),eq(variables['Build.Reason'], 'PullRequest'))
97+
condition: or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['System.PullRequest.TargetBranch'], 'master'))
9898
inputs:
9999
pollingTimeoutSec: '300'
100100

@@ -134,37 +134,6 @@ jobs:
134134
changeLogCompareToRelease: 'lastFullRelease'
135135
changeLogType: 'commitBased'
136136

137-
- bash: echo "##vso[task.prependpath]$CONDA/bin"
138-
displayName: Add conda to PATH
139-
condition: eq(variables['Build.SourceBranch'], 'refs/heads/master')
140-
141-
- bash: sudo chown -R $USER $CONDA
142-
displayName: Take ownership of conda installation
143-
condition: eq(variables['Build.SourceBranch'], 'refs/heads/master')
144-
145-
- bash: conda create --yes --quiet --name myEnvironment
146-
displayName: Create Anaconda environment
147-
condition: eq(variables['Build.SourceBranch'], 'refs/heads/master')
148-
149-
- bash: |
150-
source activate myEnvironment
151-
conda install --yes --quiet --name myEnvironment python=$(pythonVersion) conda-build anaconda-client
152-
displayName: Install Anaconda packages
153-
condition: eq(variables['Build.SourceBranch'], 'refs/heads/master')
154-
155-
# - bash: |
156-
# source activate myEnvironment
157-
# conda build . recipe --variants "{'version': ['$(GitVersion.SemVer)']}"
158-
# displayName: Build Noarch conda packages
159-
# condition: eq(variables['Build.SourceBranch'], 'refs/heads/master')
160-
#
161-
# - bash: |
162-
# source activate myEnvironment
163-
# anaconda login --username $(ANACONDAUSER) --password $(ANACONDAPW)
164-
# anaconda upload /usr/local/miniconda/envs/myEnvironment/conda-bld/noarch/*.tar.bz2
165-
# displayName: Upload conda packages
166-
# condition: eq(variables['Build.SourceBranch'], 'refs/heads/master')
167-
168137
- job: "Create_Docker_images"
169138
dependsOn: Build_UQpy_and_run_tests
170139
pool:

docs/code/reliability/form/FORM_linear function_2d.py renamed to docs/code/reliability/form/FORM_linear_function_2d.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,25 @@
55
66
In the second example we have the limit state to be a linear function of two (:math:`d=2`) independent Gaussian random
77
variables
8+
89
"""
910

10-
#%% md
11+
# %% md
1112
#
1213
# :math:`g(U) = -\frac{1}{\sqrt{d}}\sum_{i=1}^{d} u_i + \beta`
1314
#
1415
# The probability of failure in this case is :math:`P(F) ≈ 10^{−3}` for :math:`β = 3.0902`
1516
#
1617
# Initially we have to import the necessary modules.
1718

18-
#%%
19+
# %%
1920

2021
from UQpy.distributions import Normal
2122
from UQpy.reliability import FORM
2223
from UQpy.run_model.RunModel import RunModel
2324
from UQpy.run_model.model_execution.PythonModel import PythonModel
2425

26+
2527
dist1 = Normal(loc=0., scale=1.)
2628
dist2 = Normal(loc=0., scale=1.)
2729

docs/code/sampling/adaptive_kriging/adaptive_kriging_branin_hoo.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@
7373
# :class:`.Kriging` class defines an object to generate a surrogate model for a given set of data.
7474

7575
# %%
76-
7776
from UQpy.surrogates.gaussian_process.regression_models import LinearRegression
78-
from UQpy.surrogates.gaussian_process.kernels import RBF
77+
# /Users/george/Documents/Main_Files/Scripts/UQpy/src/UQpy/utilities/kernels/euclidean_kernels/RBF.py
78+
from UQpy.utilities.kernels.euclidean_kernels import RBF
7979

8080
bounds = [[10**(-3), 10**3], [10**(-3), 10**2], [10**(-3), 10**2]]
8181
optimizer = MinimizeOptimizer(method="L-BFGS-B", bounds=bounds)
@@ -132,3 +132,5 @@
132132
plt.scatter(x.samples[:nd, 0], x.samples[:nd, 1], color='Red', label='Initial samples')
133133
plt.title('Branin-Hoo function');
134134
plt.legend()
135+
136+
# %%
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Scientific Machine Learning Examples
2+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Bayesian Quickstart
2+
^^^^^^^^^^^^^^^^^^^
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
"""
2+
Bayesian Quickstart Testing
3+
===========================
4+
"""
5+
6+
# %% md
7+
# This is the second half of a Bayesian version of the classification problem from this Pytorch Quickstart tutorial:
8+
# https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html
9+
#
10+
# This script assumes you have already run the Bayesian Quickstart Testing script and saved the optimized model
11+
# to a file named ``bayesian_model.pth``. This script
12+
#
13+
# - Loads a trained model from the file ``bayesian_model.pt``
14+
# - Makes deterministic predictions
15+
# - Makes probabilistic predictions
16+
# - Plots probabilistic predictions
17+
#
18+
# First, we import the necessary modules and define the BayesianNeuralNetwork class, so we can load the model state
19+
# dictionary saved in ``bayesian_model.pth``.
20+
21+
# %%
22+
import torch
23+
import torch.nn as nn
24+
from torchvision import datasets
25+
from torchvision.transforms import ToTensor
26+
import matplotlib.pyplot as plt
27+
import UQpy.scientific_machine_learning as sml
28+
29+
plt.style.use("ggplot")
30+
31+
32+
class BayesianNeuralNetwork(nn.Module):
33+
"""UQpy: Replace torch's nn.Linear with UQpy's sml.BayesianLinear"""
34+
35+
def __init__(self):
36+
super().__init__()
37+
self.flatten = nn.Flatten()
38+
self.linear_relu_stack = nn.Sequential(
39+
sml.BayesianLinear(28 * 28, 512), # nn.Linear(28 * 28, 512)
40+
nn.ReLU(),
41+
sml.BayesianLinear(512, 512), # nn.Linear(512, 512)
42+
nn.ReLU(),
43+
sml.BayesianLinear(512, 512), # nn.Linear(512, 512)
44+
nn.ReLU(),
45+
sml.BayesianLinear(512, 10), # nn.Linear(512, 10)
46+
)
47+
48+
def forward(self, x):
49+
x = self.flatten(x)
50+
logits = self.linear_relu_stack(x)
51+
return logits
52+
53+
54+
# %% md
55+
# Since the model is already trained, we only need to load test data and can ignore the training data.
56+
# Then we use Pytorch's framework for loading a model from a state dictionary.
57+
58+
# %%
59+
60+
# Download test data from open datasets.
61+
test_data = datasets.FashionMNIST(
62+
root="data",
63+
train=False,
64+
download=False,
65+
transform=ToTensor(),
66+
)
67+
68+
device = "cpu"
69+
network = BayesianNeuralNetwork().to(device)
70+
model = sml.FeedForwardNeuralNetwork(network).to(device)
71+
model.load_state_dict(torch.load("bayesian_model.pt"))
72+
73+
# %% md
74+
# Here we make the deterministic prediction. We set the sample mode to ``False`` and evaluate our model on the first
75+
# image in ``test_data``.
76+
77+
# %%
78+
79+
classes = [
80+
"T-shirt/top",
81+
"Trouser",
82+
"Pullover",
83+
"Dress",
84+
"Coat",
85+
"Sandal",
86+
"Shirt",
87+
"Sneaker",
88+
"Bag",
89+
"Ankle boot",
90+
]
91+
model.eval()
92+
model.sample(False) # UQpy: Set sample mode to False
93+
x, y = test_data[0][0], test_data[0][1]
94+
with torch.no_grad():
95+
x = x.to(device)
96+
pred = model(x)
97+
predicted, actual = classes[pred[0].argmax(0)], classes[y]
98+
print("----- Deterministic Prediction")
99+
print(f"Predicted: {predicted}, Actual: {actual}")
100+
print(f"{'Class'.ljust(11)} {'Logits'.rjust(7)} {'softmax(Logits)'}")
101+
for i, c in enumerate(classes):
102+
print(f"{c.ljust(12)} {pred[0, i]: 6.2f} {torch.softmax(pred, 1)[0, i]: 15.2e}")
103+
104+
# %% md
105+
# Just like the torch tutorial, our model correctly identifies this image as an ankle boot.
106+
# Next, we show how to make probabilistic predictions by turning on our model's ``sampling`` mode.
107+
# We feed the same image of an ankle boot into our model 1,000 times and each time the weights and biases
108+
# are sampled from the distributions that were learned during training.
109+
# Rather than one static output, we get a distribution of 1,000 predictions!
110+
111+
# %%
112+
113+
model.sample()
114+
n_samples = 1_000
115+
logits = torch.empty((n_samples, len(classes)))
116+
with torch.no_grad():
117+
for i in range(n_samples):
118+
logits[i] = model(x)
119+
120+
# %% md
121+
# Those few lines are all it takes to make Bayesian predictions.
122+
# The rest of this example converts the predicted logits into class predictions.
123+
# The predicted distribution is visualized in the histogram below, which
124+
# shows the majority of predictions classify the image as an ankle boot.
125+
# Interestingly, the two other shoe classes (sneaker and sandal) are also common predictions.
126+
127+
# %%
128+
129+
predicted_classes = torch.argmax(logits, dim=1)
130+
predicted_counts = torch.bincount(predicted_classes)
131+
predictions = {c: int(i) for c, i in zip(classes, predicted_counts)}
132+
i = torch.argmax(predicted_counts)
133+
134+
print("----- Probabilistic Predictions")
135+
print("Most Commonly Predicted:", classes[i], "Actual:", actual)
136+
print(f"{'Class'.ljust(11)} Probability")
137+
for c in classes:
138+
print(f"{c.ljust(11)} {predictions[c] / n_samples: 11.3f}")
139+
140+
# Plot probabilistic class predictions
141+
fig, ax = plt.subplots()
142+
colors = plt.cm.tab10_r(torch.linspace(0, 1, 10))
143+
b = ax.bar(classes, predicted_counts, label=predicted_counts, color=colors)
144+
ax.bar_label(b)
145+
ax.set_title("Bayesian NN Predictions", loc="left")
146+
ax.set(xlabel="Classes", ylabel="Counts")
147+
ax.set_xticklabels(classes, rotation=45)
148+
fig.tight_layout()
149+
150+
# %% md
151+
# In addition to visualizing the class predictions, we can look at the logit values output by our Bayesian model.
152+
# Below we plot a histogram of the logits for Sandal, Sneaker, Bag, and Ankle Boot.
153+
# The other classes are omitted since they were never predicted by our model.
154+
#
155+
# Notice that for Bag, the histogram peaks near zero.
156+
# This aligns with the fact that Bag is a very unlikely prediction from our model.
157+
# Contrast that histogram with the one for Ankle Boot, which is very likely to take on a high value.
158+
# We interpret this as our model being very likely to predict Ankle Boot.
159+
160+
# %%
161+
162+
# Plot probabilistic logit predictions
163+
softmax_logits = torch.softmax(logits, 1)
164+
fig, ax = plt.subplots()
165+
ax.hist(softmax_logits[:, 9], label="Ankle Boot", bins=20, facecolor=colors[9])
166+
for i in (5, 7, 8): # loop over Sandal, Sneaker, Bag
167+
ax.hist(
168+
softmax_logits[:, i],
169+
label=classes[i],
170+
bins=20,
171+
edgecolor=colors[i],
172+
facecolor="none",
173+
linewidth=2,
174+
)
175+
ax.set_title("Bayesian NN softmax(logits)", loc="left")
176+
ax.set(xlabel="softmax(logit) Value", ylabel="Log(Counts)")
177+
ax.legend()
178+
ax.set_yscale("log")
179+
fig.tight_layout()
180+
181+
182+
# %% md
183+
# We can also visualize these distributions and how they correlate with one another with a pair plot.
184+
185+
# %%
186+
187+
# Use pandas and seaborn for easy pair plots
188+
import seaborn
189+
import pandas as pd
190+
191+
df = pd.DataFrame({classes[i]: softmax_logits[:, i] for i in (5, 7, 8, 9)})
192+
seaborn.pairplot(df, corner=True, plot_kws={"alpha": 0.2, "edgecolor": None})
193+
194+
plt.show()

0 commit comments

Comments
 (0)