Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11,900 changes: 11,900 additions & 0 deletions Datasets/Experimental/Fm-3m/Cs2I6Sn.xy

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions Datasets/test/label_theo_test.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
0,Fm-3m
1,Fm-3m
2,I41mcm
3,I41mcm
4,P21a
5,P21a
6,P3m1
7,P3m1
8,P61mmc
9,P61mmc
10,Pc
11,Pc
12,Pm-3m
13,Pm-3m
2,127 changes: 2,127 additions & 0 deletions Datasets/test/theor_test.csv

Large diffs are not rendered by default.

Binary file added __pycache__/autoXRD.cpython-311.pyc
Binary file not shown.
Binary file added __pycache__/autoXRD_vis.cpython-311.pyc
Binary file not shown.
Binary file added __pycache__/plotting.cpython-311.pyc
Binary file not shown.
104 changes: 83 additions & 21 deletions autoXRD_vis.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,32 @@
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import os

# Function to extract CAM of a certain model, subset of test elements, and spectra array with all experimental data (non-augmented)
def get_cam(model_name, elements, spectra):

model = load_model(model_name)
model = load_model(model_name)

# Get the input layer explicitly (as before)
input_layer = model.get_layer(index=0)

# Dummy input with expected shape (as before)
dummy_input = np.zeros((1, spectra[elements].shape[1], 1))
_ = model(dummy_input)

gap_weights = model.layers[-1].get_weights()[0]
cam_model = Model(inputs=model.input,

# Create the cam_model (as before)
cam_model = Model(inputs=input_layer.input,
outputs=(model.layers[-3].output, model.layers[-1].output))

features, results = cam_model.predict(spectra[elements].reshape(spectra[elements].shape[0],1200,1))
cam_outputs=np.zeros([10,1])

# Extract Class Activation MAPS
for idx,element in enumerate(elements):

# This is the key change: move cam_model.predict outside the loop
features, results = cam_model.predict(spectra[elements].reshape(spectra[elements].shape[0], 1200, 1))

cam_outputs = np.zeros([10, 1])

# Extract Class Activation MAPS
for idx, element in enumerate(elements):
# get the feature map of the test image
features_for_one_img = features[idx, :, :]

Expand All @@ -54,37 +65,45 @@ def get_cam(model_name, elements, spectra):
# create the class activation map
cam_output = np.dot(cam_features, cam_weights)
cam_output = abs(cam_output)
cam_outputs=np.append(cam_outputs, cam_output.reshape(cam_output.shape[0],1), axis=1)
cam_outputs = np.append(cam_outputs, cam_output.reshape(cam_output.shape[0], 1), axis=1)

return cam_outputs.T

# Plot CLass Activation Map of both an individual CAM and an average CAM
def plot_cam(cam_output, title, *args):

#*arg is here a vector with the actual spectra
x = np.linspace(10,69.96,cam_output.shape[0])
if cam_output.size == 0: # Check if cam_output is empty
print("Error: cam_output is empty. Unable to plot.")
return # Exit the function to prevent further errors

x = np.linspace(10, 69.96, cam_output.shape[0])
y = cam_output
y2=[]
y2 = []
for arg in args:
y2.append(arg)
if len(y2) != 0:
y2=np.array(y2).reshape(1200,)
y2 = np.array(y2).reshape(1200,)

fig, (ax,ax2) = plt.subplots(nrows=2, sharex=True)
fig, (ax, ax2) = plt.subplots(nrows=2, sharex=True)

extent = [x[0]-(x[1]-x[0])/2., x[-1]+(x[1]-x[0])/2.,0,1]
ax.imshow(y[np.newaxis,:], cmap="plasma", aspect="auto", extent=extent, interpolation='gaussian')
extent = [x[0] - (x[1] - x[0]) / 2., x[-1] + (x[1] - x[0]) / 2., 0, 1]
ax.imshow(y.to_numpy()[np.newaxis, :], cmap="plasma", aspect="auto", extent=extent, interpolation='gaussian')
ax.set_yticks([])
ax.set_xlim(extent[0], extent[1])

if len(y2) != 0:
ax2.plot(np.linspace(10,69.96,1200),y2)
ax2.plot(np.linspace(10, 69.96, 1200), y2)
ax2.set_xlabel(r"$2 \theta$ (Degrees)")
ax2.set_title("Pattern")


fig.suptitle(title, fontsize=16)

dirname3 = "/content/drive/MyDrive/DLP/DLP_autoXRD/plots"

file_path = os.path.join(dirname3, title + ".png") # Customize file name
plt.savefig(file_path)

# Optional: Close the figure to release resources
plt.close()

#Find corrects and incorrects in all models ran, and compare them to ground-truth
def find_incorrects(ground_truth,predictions_ord):
Expand All @@ -101,7 +120,7 @@ def find_incorrects(ground_truth,predictions_ord):
#Join predictions and ground truth and convert to dataframe
comparision_array=np.concatenate([truth,temp],axis=1)
comparision_df=pd.DataFrame(data=comparision_array[:,1:], index=comparision_array[:,0], columns=['Truth','Prediction'])
comparision_df['Model']='keras_model'+str(k)+'.h5'
comparision_df['Model']='keras_model'+str(k)+'.keras'

#Find incorrects and save dataframe
incorrect_df=comparision_df[comparision_df.Truth != comparision_df.Prediction]
Expand All @@ -113,3 +132,46 @@ def find_incorrects(ground_truth,predictions_ord):

#Return list of dataframe with comparision between resuls, and list of dataframes of incorrects
return corrects, incorrects

def generate_cam(model, image, class_index):
"""Generates a class activation map for a given image and class index.

Args:
model: The trained Keras model.
image: The input image as a NumPy array.
class_index: The index of the target class.

Returns:
A NumPy array representing the class activation map.
"""

# Get the output of the last convolutional layer
last_conv_layer = model.get_layer('last_conv_layer') # Replace with the actual name
last_conv_layer_model = tf.keras.Model(model.inputs, last_conv_layer.output)

# Get the weights of the classification layer
classifier_layer = model.get_layer('classifier') # Replace with the actual name
classifier_weights = classifier_layer.get_weights()[0]

# Generate the CAM
with tf.GradientTape() as tape:
last_conv_layer_output = last_conv_layer_model(np.expand_dims(image, axis=0))
tape.watch(last_conv_layer_output)
preds = model(np.expand_dims(image, axis=0))
top_class_channel = preds[:, class_index]

grads = tape.gradient(top_class_channel, last_conv_layer_output)
pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))

heatmap = tf.reduce_mean(tf.multiply(pooled_grads, last_conv_layer_output), axis=-1)
heatmap = np.maximum(heatmap, 0)
heatmap /= np.max(heatmap)

plt.figure() # Create a new figure to avoid overwriting previous plots
plt.imshow(image)
plt.imshow(cam, alpha=0.5, cmap='jet')
plt.axis('off') # Remove axes for a cleaner image
plt.savefig(output_path)
plt.close()

return heatmap.numpy()[0]
Binary file added keras_model0.keras
Binary file not shown.
Binary file added keras_model1.keras
Binary file not shown.
Binary file added keras_model2.keras
Binary file not shown.
Binary file added keras_model3.keras
Binary file not shown.
Binary file added keras_model4.keras
Binary file not shown.
Binary file added keras_model_batch_norm0.keras
Binary file not shown.
Binary file added keras_model_batch_norm1.keras
Binary file not shown.
Binary file added keras_model_batch_norm2.keras
Binary file not shown.
Binary file added keras_model_batch_norm3.keras
Binary file not shown.
Binary file added keras_model_batch_norm4.keras
Binary file not shown.
Binary file added keras_model_dropout0.keras
Binary file not shown.
Binary file added keras_model_dropout1.keras
Binary file not shown.
Binary file added keras_model_dropout2.keras
Binary file not shown.
Binary file added keras_model_dropout3.keras
Binary file not shown.
Binary file added keras_model_dropout4.keras
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_0_L1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_0_batch_norm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_0_dropout.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_1_L1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_1_batch_norm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_1_dropout.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_2_L1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_2_batch_norm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_2_dropout.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_3_L1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_3_batch_norm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_3_dropout.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/training_validation_plots_4_L1.png
Binary file added plots/training_validation_plots_4_batch_norm.png
Binary file added plots/training_validation_plots_4_dropout.png
90 changes: 68 additions & 22 deletions space_group_a_CNN.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@
in the README.rst file, in the GitHub repository.

"""

#################################################################
#Libraries and dependencies
#################################################################

# Loads series of functions for preprocessing and data augmentation
from autoXRD import *
# Loads CAMs visualizations for a-CNN
Expand All @@ -37,19 +35,23 @@
from sklearn.preprocessing import OneHotEncoder
from sklearn import metrics
from sklearn.model_selection import KFold
from sklearn.metrics import precision_score

# Neural networks uses Keran with TF background
import keras as K
from keras.models import Model
from keras.models import Sequential
from keras.callbacks import ReduceLROnPlateau
from keras.callbacks import EarlyStopping
from keras.layers import GlobalAveragePooling1D
from keras.models import load_model

import tensorflow as tf
from tensorflow import keras

# Clear Keras and TF session, if run previously
K.backend.clear_session()
tf.reset_default_graph()
#tf.reset_default_graph()

# Training Parameters

Expand Down Expand Up @@ -188,20 +190,20 @@
filter_size = 2
kernel_size = 10

enc = OneHotEncoder(sparse=False)
enc = OneHotEncoder()

train_dim = train_combine.reshape(train_combine.shape[0],1200,1)
train_y = np.concatenate((y_th,exp_train_y))
trains_y.append(train_y)
train_y_hot = enc.fit_transform(train_y.reshape(-1,1))
train_y_hot = enc.fit_transform(train_y.reshape(-1,1)).toarray() # Convert to dense array

# Define network structure
model = Sequential()

model.add(K.layers.Conv1D(32, 8,strides=8, padding='same',input_shape=(1200,1), activation='relu'))
model.add(K.layers.Conv1D(32, 5,strides=5, padding='same', activation='relu'))
model.add(K.layers.Conv1D(32, 3,strides=3, padding='same', activation='relu'))
model.add(K.layers.pooling.GlobalAveragePooling1D())
model.add(GlobalAveragePooling1D())
model.add(K.layers.Dense(n_classes, activation='softmax'))

#Define optimizer
Expand All @@ -211,7 +213,7 @@
model.compile(loss='binary_crossentropy',
optimizer=optimizer,
metrics=['categorical_accuracy'])

model.summary()
# Choose early stop
#early_stop = EarlyStopping(monitor='val_loss', patience=50, verbose=1, restore_best_weights=True)

Expand All @@ -222,17 +224,50 @@
# Define test data
test_x = X_exp[test]
test_x = test_x.reshape(test_x.shape[0],1200,1)
test_y = enc.fit_transform(y_exp.reshape(-1,1))[test]

test_y = enc.fit_transform(y_exp.reshape(-1,1)).toarray()[test]

if isinstance(train_y_hot, tf.sparse.SparseTensor):
train_y_hot = tf.sparse.to_dense(train_y_hot)

# Fit model
hist = model.fit(train_dim, train_y_hot, batch_size=BATCH_SIZE, nb_epoch=100,
hist = model.fit(train_dim, train_y_hot, batch_size=BATCH_SIZE, epochs=50,
verbose=1, validation_data=(test_x, test_y))
# hist = model.fit(train_dim, train_y_hot, batch_size=BATCH_SIZE, nb_epoch=100,
# hist = model.fit(train_dim, train_y_hot, batch_size=BATCH_SIZE, epochs=100,
# verbose=1, validation_data=(test_x, test_y), callbacks = [early_stop])
#

#print(hist.history.keys())

plt.figure(figsize=(12, 6))

# Loss plot
plt.subplot(1, 2, 1)
plt.plot(hist.history['loss'], label='Training Loss')
plt.plot(hist.history['val_loss'], label='Validation Loss')
plt.title('Loss over Epochs')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

# Accuracy plot
plt.subplot(1, 2, 2)
plt.plot(hist.history['categorical_accuracy'], label='Training Accuracy')
plt.plot(hist.history['val_categorical_accuracy'], label='Validation Accuracy')
plt.title('Accuracy over Epochs')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()

plt.tight_layout()

# Ensure the plot is displayed
dirname2 = "/content/drive/MyDrive/DLP/DLP_autoXRD/plots"

plot_filename = os.path.join(dirname2, f'training_validation_plots_{k}.png')
plt.savefig(plot_filename)

#Compute model predictions
prediction=model.predict(test_x)

#Go from one-hot to ordinal...
prediction_ord=[np.argmax(element) for element in prediction]
predictions_ord.append(prediction_ord)
Expand All @@ -241,8 +276,8 @@
accuracy_exp[k] = metrics.accuracy_score(y_exp[test], prediction_ord)
accuracy_exp_r1[k] = metrics.recall_score(y_exp[test], prediction_ord, average='macro')
accuracy_exp_r2[k] = metrics.recall_score(y_exp[test], prediction_ord, average='micro')
accuracy_exp_p1[k] = metrics.precision_score(y_exp[test], prediction_ord, average='macro')
accuracy_exp_p2[k] = metrics.precision_score(y_exp[test], prediction_ord, average='micro')
accuracy_exp_p1[k] = metrics.precision_score(y_exp[test], prediction_ord, average='macro', zero_division=1)
accuracy_exp_p2[k] = metrics.precision_score(y_exp[test], prediction_ord, average='micro', zero_division=1)
f1[k]=metrics.f1_score(y_exp[test], prediction_ord, average='micro')
f1_m[k]=metrics.f1_score(y_exp[test], prediction_ord, average='macro')

Expand All @@ -257,7 +292,8 @@
logs.append(log)

#Save models on current folder with names subscripts 0 to 4
model.save(os.path.join(dirname, 'keras_model')+str(k)+'.h5')
#model.save(os.path.join(dirname, 'keras_model')+str(k)+'.h5')
model.save(os.path.join(dirname, 'keras_model') + str(k) + '.keras')

#
accuracy = np.array(accuracy)
Expand All @@ -272,6 +308,13 @@
# Compute correctly classified and incorrectly classified cases
corrects, incorrects = find_incorrects(ground_truth,predictions_ord)

#def get_cam(model_path, trains, X_exp):
# Load the model using keras.models.load_model
# model = keras.models.load_model(model_path, compile=False)

# Compile the loaded model, ensure it's ready for use
# model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# Get dataframe of all incorrects and dataframe of all corrects
corrects_df = pd.concat([r for r in corrects], ignore_index=False, axis=0)
incorrects_df = pd.concat([r for r in incorrects], ignore_index=False, axis=0)
Expand All @@ -280,23 +323,24 @@
# Trains refers to the elements in X_exp used for training
# Choose the model in cross validation as output, in this case we plot number 5

cam_outputs=get_cam('keras_model4.h5', trains[4], X_exp)
cam_outputs=get_cam('keras_model4.keras', trains[4], X_exp)
#print(f"this is the cam_outputs",cam_outputs)
cam_df=pd.DataFrame(cam_outputs)
cam_df=cam_df.iloc[1:]
cam_df['Label']=y_exp[trains[4]]

# CAM with all augmented training data
rng=range(0,7000)
cam_outputs2=get_cam('keras_model4.h5', rng, train_combine)
cam_outputs2=get_cam('keras_model4.keras', rng, train_combine)
cam_df2=pd.DataFrame(cam_outputs2)
cam_df2=cam_df2.iloc[1:]
cam_df2['Label']=train_y

# Now we focus on the incorrectly labelled cam's
incorrects_filtered=incorrects_df[incorrects_df.Model=='keras_model4.h5']
incorrects_filtered=incorrects_df[incorrects_df.Model=='keras_model4.keras']

# Get CAM of incorrectly classified cases
cam_inc=get_cam('keras_model4.h5', [int(element) for element in incorrects_filtered.index], X_exp)
cam_inc=get_cam('keras_model4.keras', [int(element) for element in incorrects_filtered.index], X_exp)
cam_inc=pd.DataFrame(cam_inc)
cam_inc=cam_inc.iloc[1:]

Expand All @@ -309,12 +353,14 @@
means_6=cam_filtered.mean()
means_6=means_6.iloc[:-1]

#print(f"this is the input to the plot_cam",means_6) #check if the input is empty

#Plot the average class map for class 6
plot_cam(means_6,'Average CAM for Class 6, trained model4.h5')

#Plot correctly classified CAMs and patterns, no need to change this
corrects_filtered=corrects_df[corrects_df.Model=='keras_model4.h5']
cam_cor=get_cam('keras_model4.h5', [int(element) for element in corrects_filtered.index], X_exp)
corrects_filtered=corrects_df[corrects_df.Model=='keras_model4.keras']
cam_cor=get_cam('keras_model4.keras', [int(element) for element in corrects_filtered.index], X_exp)
cam_cor=pd.DataFrame(cam_cor)
cam_cor=cam_cor.iloc[1:]

Expand Down
Loading