Skip to content
Snippets Groups Projects
Commit fb72a985 authored by Adam Fekete's avatar Adam Fekete
Browse files

tutorials

parent 7fee8dfa
No related branches found
No related tags found
No related merge requests found
Pipeline #167710 passed
%% Cell type:markdown id:428595f4 tags:
This notebook provides a step-by-step guide on how to use AI-STEM for analyzing experimental images.
The accompanying paper can be found [here](https://doi.org/10.48550/arXiv.2303.12702).
%% Cell type:code id:85483591 tags:
``` python
! pip install 'git+https://github.com/AndreasLeitherer/ai4stem.git'
! pip install tensorflow
! pip install opencv-python
```
%% Cell type:code id:7809904c tags:
``` python
# Import packages
import os
# tensorflow info/warnings switched off
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import numpy as np
import cv2
from collections import defaultdict
from copy import deepcopy
import matplotlib
matplotlib.rcParams.update({'font.size': 10})
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from ai4stem.utils.utils_data import load_pretrained_model, load_example_image, load_class_dicts
from ai4stem.utils.utils_prediction import predict
from ai4stem.utils.utils_nn import predict_with_uncertainty
from ai4stem.utils.utils_fft import calc_fft
from ai4stem.utils.utils_prediction import localwindow
numerical_to_text_labels, text_to_numerical_labels = load_class_dicts()
# Set logger
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
```
%% Cell type:markdown id:46eea44c tags:
# Quick start
After specifying an input image (here, Fe bcc [100] alongside the pixel/Angstrom relation), the following code can be used to analyze it via AI-STEM, employing a pretrained model (which is also used in the [the AI-STEM paper](https://doi.org/10.48550/arXiv.2303.12702)).
%% Cell type:code id:dff60803 tags:
``` python
# Load image
input_image = load_example_image()
pixel_to_angstrom = 0.1245 # 1 pixel = 0.1245 Angstrom
# Load pretrained model
model = load_pretrained_model()
# Define window size
window_size = int(12. / pixel_to_angstrom)
# Analyze image:
# return slices of images (fragmentation step, 2D array 'sliced_images'),
# calcualted FFT-HAADF descriptors (2D arrray 'fft_descriptors')
# neural-network classification propabilities (2D array 'prediction'),
# and uncertainty quantification (dictionary 'uncertainty', containing mutual information)
sliced_images, fft_descriptors, prediction, uncertainty = predict(input_image, model,
window_size=window_size)
```
%% Cell type:markdown id:4e41e625 tags:
***Note 1***: The neural-network classifier is a *Bayesian* neural network, i.e., its predictions are not deterministic but rather probabilistic - modelling the uncertainty in the predictions, which may arise due to experimental noise and/or insufficiency of the model parameters. In particular, we employ [Monte Carlo dropout](https://proceedings.mlr.press/v48/gal16.html?trk=public_post_comment-text) to obtain an uncertainty estimate. In practice, several forward passes (here T=100) are calculated to estimate the uncertainty in the predictions (referred to as 'Performing forward pass n/100' in the cell below). In particular, this suffices to identify the expected bulk symmetry and detect the interface as regions of high uncertainty (as quantified by mutual information). We refer to [the AI-STEM paper](https://doi.org/10.48550/arXiv.2303.12702) for more details (in particular the section 'The Bayesian classification model' and Supplementary Figure S4 for more details on how to choose the number of forward passes).
***Note 2***: The model is trained on a specific pixel/angstrom relation. Specifically, the model is trained to classify local windows of size 12 Angstrom, where 1 pixel corresponds to 0.12 angstrom. Thus a window size of 12 Angstrom corresponds to 100 pixels in the simulation settings that we employed for creating the training set. If a different resolution is employed, we recommend to adapt the window size (and this is also done in the above code): given the pixel-to-Angstrom relation, calculate how much pixels correspond to 12 Angstrom and use this as window size. Alternatively, you may rescale the whole image (up/downsampling, e.g., via cv2.resize) such that the resolutions of your input image match the training resolution and then simply use a 100 pixels window size.
%% Cell type:markdown id:8dd3a391 tags:
Now we can visualize the results:
%% Cell type:code id:b17acafd tags:
``` python
fig, axs = plt.subplots(1, 3, figsize=(15, 15))
# Input image
im1 = axs[0].imshow(input_image, cmap='gray')
fig.colorbar(im1, ax=axs[0], orientation='vertical', fraction=0.05)
axs[0].set_title('Input image')
# Assignments:
# Get assigned label which corresponds to
# most likely class
assignments = prediction.argmax(axis=-1)
im2 = axs[1].imshow(assignments, cmap='tab10')
axs[1].set_title('Assigned label')
# Mutual informatoin
im3 = axs[2].imshow(uncertainty, cmap='hot', vmin=0.0)
fig.colorbar(im3, ax=axs[2], orientation='vertical', fraction=0.05)
axs[2].set_title('Bayesian uncertainty \n (mutual information)')
# add nice legend for assignments
all_colors = plt.cm.tab10.colors
unique_assignments = np.unique(assignments.flatten())
my_colors = [all_colors[idx] for idx in unique_assignments]
patches = [mpatches.Patch(facecolor=c, edgecolor=c) for c in my_colors]
axs[1].legend(patches, sorted(text_to_numerical_labels.keys()), handlelength=0.8, loc='lower right')
plt.show()
```
%% Cell type:markdown id:1cd43799 tags:
The above calculations provide a quickstart, hiding the individual steps performed in the function 'predict'in from ai4stem.utils.utils_prediction. More detailed explanations are provided in the following.
%% Cell type:markdown id:f6acc9fa tags:
# Step-by-step explanations
%% Cell type:markdown id:6b6793cb tags:
First we load the image:
%% Cell type:code id:6c93d963 tags:
``` python
input_image = load_example_image()
image_name = 'Fe_bcc'
plt.imshow(input_image, cmap='gray')
plt.show()
```
%% Cell type:markdown id:826aebaa tags:
Next, we need the pixel/Anstrom relation. Moreover, the window size and stride employed in the AI-STEM algorithm has to be specified - here the stride is set to a rather coarse value, while more detailed resolution of structural transitions across defects (such as interfaces) may be achieved by decreasing the stride:
%% Cell type:code id:e33deed8 tags:
``` python
pixel_to_angstrom = 0.1245
window_size = 12.
stride_size = [36, 36]
```
%% Cell type:markdown id:f114b1f2 tags:
As remarked in the quickstart section, the model is trained on a specific pixel/angstrom relation and window size, so we need to take this into account - where here we do not rescale the image but adapt the window size such that a 12 Angstrom size is obtained:
%% Cell type:code id:4c0bfdb5 tags:
``` python
adapted_window_size = int(window_size * (1. / pixel_to_angstrom))
print(adapted_window_size)
```
%% Cell type:markdown id:cd79b07f tags:
Now we can proceed to the first step in the AI-STEM workflow, the fragmentation.
%% Cell type:code id:3650b396 tags:
``` python
sliced_images, _, ni, nj = localwindow(input_image, stride_size=stride_size,
pixel_max=adapted_window_size)
```
%% Cell type:markdown id:8bd14c20 tags:
We may visualize some of the fragments:
%% Cell type:code id:dffe0fad tags:
``` python
selection_size = 10
fig, axs = plt.subplots(1, 10, figsize=(25, 10))
for idx, local_image in enumerate(sliced_images[:selection_size]):
axs[idx].imshow(local_image, cmap='gray')
```
%% Cell type:markdown id:55aeef16 tags:
Next, we calculate the FFT-HAADF descriptor for each of the local images, where one particular setting, the application of a threshold to the calculated FFT is discussed:
%% Cell type:code id:2122b419 tags:
``` python
# FFT HAADF descriptor settings
# Threshold parameter; given FFT spectrum normalized
# to [0, 1], cut off at 0.1 to reduce low-frequency
# contributions; default is is to use this setting.
thresholding = True # very important
fft_descriptors = []
for im in sliced_images:
fft_desc = calc_fft(im, thresholding=thresholding)
fft_descriptors.append(fft_desc)
```
%% Cell type:markdown id:dc9b3c2d tags:
We may again visualize local fragments and their corresponding 64x64 FFT-HAADF descriptor:
%% Cell type:code id:d668c9e8 tags:
``` python
selection_size = 10
fig, axs = plt.subplots(2, 10, figsize=(25, 5))
for idx, local_image in enumerate(sliced_images[:selection_size]):
axs[0, idx].imshow(local_image, cmap='gray')
axs[1, idx].imshow(fft_descriptors[idx], cmap='gray', vmax=0.5)
# vmax=0.5, to enhance visibility of high-freq. peaks
```
%% Cell type:markdown id:827bb9ff tags:
Next we load the pretrained neural-network model and visualize its architecture:
%% Cell type:code id:3c9f141c tags:
``` python
model = load_pretrained_model()
model_name = 'pretrained_model'
model.summary()
```
%% Cell type:markdown id:db70ad50 tags:
The above FFT-HAADF descriptors serve as input to the neural-network classifier. We first adapt the
above calculated descriptors such that they fit the model input:
%% Cell type:code id:9dc71ca2 tags:
``` python
input_shape_from_model = model.layers[0].get_input_at(0).get_shape().as_list()[1:]
target_shape = tuple([-1] + input_shape_from_model)
nn_input = np.reshape(fft_descriptors, target_shape)
```
%% Cell type:markdown id:8531f30a tags:
Then, we calculate the neural-network predictions and uncertainty:
%% Cell type:code id:8110067f tags:
``` python
prediction, uncertainty = predict_with_uncertainty(nn_input, model)
```
%% Cell type:markdown id:a6a01ae0 tags:
In the function 'predict_with_uncertainty', other uncertainty quantifiers are calculated as well, while in this work, we explored the use of mutual information.
Predictions and uncertainty estimates are not yet in the right shape, they are simply a 1D array and thus we reshape:
%% Cell type:code id:ed50c238 tags:
``` python
prediction = np.reshape(prediction, (ni, nj, prediction.shape[-1]))
mutual_information = np.reshape(uncertainty['mutual_information'], (ni, nj))
```
%% Cell type:markdown id:6e5aa756 tags:
Finally, we can visualize the results:
%% Cell type:code id:ed0b8aac tags:
``` python
fig, axs = plt.subplots(1, 3, figsize=(15, 15))
# Input image
im1 = axs[0].imshow(input_image, cmap='gray')
fig.colorbar(im1, ax=axs[0], orientation='vertical', fraction=0.05)
axs[0].set_title('Input image')
# Assignments:
# Get assigned label which corresponds to
# most likely class
assignments = prediction.argmax(axis=-1)
im2 = axs[1].imshow(assignments, cmap='tab10')
axs[1].set_title('Assigned label')
# Mutual information
im3 = axs[2].imshow(mutual_information, cmap='hot', vmin=0.0)
fig.colorbar(im3, ax=axs[2], orientation='vertical', fraction=0.05)
axs[2].set_title('Bayesian uncertainty \n (mutual information)')
# add nice legend for assignments
all_colors = plt.cm.tab10.colors
unique_assignments = np.unique(assignments.flatten())
my_colors = [all_colors[idx] for idx in unique_assignments]
patches = [mpatches.Patch(facecolor=c, edgecolor=c) for c in my_colors]
axs[1].legend(patches, sorted(text_to_numerical_labels.keys()), handlelength=0.8, loc='lower right')
plt.show()
```
%% Cell type:code id:c01a8bc1 tags:
``` python
```
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment