#!/usr/bin/env python # coding: utf-8 # # Exercise 8.1 - Solution # ### Classification of magnetic phases using CNNs # # Imagine a 2-dimensional lattice arrangement of $n \times n$ magnetic dipole moments (spins) that can be in one of two states ($+1$ or $−1$, Ising model). # With interactions between spins being short ranged, each spin interacts only with its four neighbors. # The probability to find a spin in one of the orientations is a function of temperature $T$ according to $p \sim e^{−a/T},\;a = \mathrm{const.}$). # # At extremely low temperatures $T \rightarrow 0$, neighboring spins have a very low probability of different orientations, so that a uniform overall state (ferromagnetic state) is adopted, characterized by $+1$ or $−1$. # At very high temperatures $T \rightarrow \infty$, a paramagnetic phase with random spin alignment results, yielding $50\%$ of $+1$ and $0%$ of $−1$ orientations. # Below a critical temperature $0 < T < T_c$, stable ferromagnetic domains emerge, with both orientations being equally probable in the absence of an external magnetic field. # The spin-spin correlation function diverges at $T_c$, whereas the correlation decays for $T > T_c$. # # The data for this task contain the $n \times n$ dipole orientations on the lattice for different temperatures $T$. # Classify the two magnetic phases (paramagnetic/ferromagnetic) using a convolutional neural network! # In[12]: from tensorflow import keras import numpy as np callbacks = keras.callbacks layers = keras.layers # ### Load and prepare dataset # See https://doi.org/10.1038/nphys4035 for more information # In[2]: import gdown url = "https://drive.google.com/u/0/uc?export=download&confirm=HgGH&id=1Ihxt1hb3Kyv0IrjHlsYb9x9QY7l7n2Sl" output = 'ising_data.npz' gdown.download(url, output, quiet=True) f = np.load(output) n_train = 20000 x_train, x_test = f["C"][:n_train], f["C"][n_train:] T_train, T_test = f["T"][:n_train], f["T"][n_train:] # ### Plot data # In[3]: import matplotlib.pyplot as plt for i,j in enumerate(np.random.choice(n_train, 6)): plt.subplot(2,3,i+1) image = x_train[j] plot = plt.imshow(image) plt.title("T: %.2f" % T_train[j]) plt.tight_layout() plt.show() # In[4]: plt.hist(T_test) plt.xlabel("T") plt.ylabel("frequency") # #### Set up training data - define magnetic phases # In[5]: Tc = 2.27 y_train, y_test = T_train > Tc, T_test > Tc # ### Task # # - evaluate the test accuracy for a convolutional network, # - plot the test accuracy vs. temperature. # - compare to the results obtained using a fully-connected network (Exercise 7.1) # In[6]: model = keras.models.Sequential() model.add(layers.InputLayer(input_shape=(32, 32))) model.add(layers.Reshape((32, 32,1))) model.add(layers.Convolution2D(16, (3, 3), padding='same', activation='relu')) model.add(layers.Convolution2D(16, (3, 3), padding='same', activation='relu')) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Convolution2D(32, (3, 3), padding='same', activation='relu')) model.add(layers.Convolution2D(32, (3, 3), padding='same', activation='relu')) model.add(layers.GlobalAveragePooling2D()) model.add(layers.Dropout(0.25)) model.add(layers.Dense(1, activation='sigmoid')) model.summary() # ### prepare model for training # In[7]: model.compile( loss='binary_crossentropy', optimizer=keras.optimizers.Adam(0.001), metrics=['accuracy']) # In[8]: results = model.fit(x_train, y_train, batch_size=64, epochs=50, verbose=2, validation_split=0.1, callbacks=[ callbacks.EarlyStopping(patience=5, verbose=1), callbacks.ReduceLROnPlateau(factor=0.67, patience=2, verbose=1)] ) # In[9]: plt.figure(1, (12, 4)) plt.subplot(1, 2, 1) plt.plot(results.history['loss']) plt.plot(results.history['val_loss']) plt.ylabel('loss') plt.xlabel('epoch') plt.legend(['train', 'val'], loc='upper right') # In[10]: plt.figure(1, (12, 4)) plt.subplot(1, 2, 1) plt.plot(results.history['accuracy']) plt.plot(results.history['val_accuracy']) plt.ylabel('accuracy') plt.xlabel('epoch') plt.legend(['train', 'val'], loc='upper right') # ### Evaluate training # In[11]: import seaborn as sns preds = model.predict(x_test).round().squeeze() acc = (preds == y_test).astype(np.float) ax = sns.regplot(x=T_test, y=acc, x_estimator= np.mean, fit_reg=False) ax.set_ylabel("accuracy") ax.set_xlabel("T") plt.axvline(x=Tc, color='k', linestyle='--', label='Tc')