Necessary ResourcesTo Compile, Use These Commands:g++ -o -g NeuralNet.cpp g++ -o neuralnet EasyBMP.o NeuralNet.o neuralnet With Large L, Segmentation Faults Can Be Avoided Using:limit stacksize unlimited #include <stdio.h> // #include <stdlib.h> // #include <ctime> // needed for compatible sleep function #include <sstream> // needed for incorporation of variables into file names #include "EasyBMP.h" // needed for BMP input/output #include <iostream> // #include <string> // #include <vector> // #include <math.h> // needed for floor() #include <fstream> //#include <windows.h> // needed for Sleep() using namespace std; using std::cout; using std::endl; ofstream hammergy("hammergy.dat", ios::app); ofstream flips("flips.dat"); // Changeable parameters float Tstart = 0.0; // Start temperature for annealing (put 0 for no annealing) int const L = 40; // Size of neural net int const MC_Steps = 1000; // Number of MC-steps float const RN_seed = 0.4f; // RNG seed float spindmg = 0.2; // Initial spin damage int teachOrtho = 0; // Number of pseudoorthogonal images teached bool restrictJbool = false; // If true restricts J-elements to 1 and -1 float bdamage = 0.0f; // Amount of random braindamage 0 for no braindamage; char* initname = "A_40"; // Name of initial image float J_lifetime = 0.0; BMP current_BMP; int Step = 0; char image_directory[] = "Letter Images/"; char output_directory[] = "Run Output/"; void MonteCarloStep(int [L][L], float [L][L][L][L], float T, int[L][L]); float CalculateEnergy(int [L][L], float [L][L][L][L]); float CalculateEnergyChange_SN (int [L][L], float [L][L][L][L], int, int); void InitializeSpins(int [L][L]); void InitializeSpins(int [L][L], char []); void InitializeJ(int, float [L][L][L][L]); void TeachJ(float [L][L][L][L], float, int*); void TeachJ(float [L][L][L][L], float, char []); void InputImage(char*, int[L][L]); void PrintSpins(int [L][L]); void PrintSpins_Linux(int [L][L]); int* loadImage(char []); void outputBMP(int [L][L], char []); void restrictJ(float [L][L][L][L]); void brainDamageRec(int, int, int, int, float [L][L][L][L],int [L][L]); void brainDamageRan(float, float [L][L][L][L]); void createOrthogonal(int, float [L][L][L][L]); void flipS(float spindmg, int S[L][L]); float Hamming(int [L][L], int [L][L]); //void sleep(unsigned int); int main(void) { float T; // Seed Random Numbers srand((int)(RAND_MAX * RN_seed)); // Create Spin State and J Matrices // x y int S[L][L] = {0}; // x y int refS[L][L] = {0}; // ix iy jx jy float J[L][L][L][L] = {0.0}; // Initialize Spin State and J Matrices InitializeSpins(refS, "black"); // Initializes Reference Spin State InitializeSpins(S, initname); // Initializes Spins to an "A" in italics in a different, serif font //InitializeSpins(S); // Initializes Spins Randomly //InitializeJ(2, J); // Initializes J-elements randomly // "Teach" J new letters, to increase the weight of the letter, increase parameter 2 TeachJ(J, 1.0f, "A"); TeachJ(J, 1.0f, "B"); TeachJ(J, 1.0f, "C"); TeachJ(J, 1.0f, "D"); TeachJ(J, 1.0f, "E"); TeachJ(J, 1.0f, "F"); //TeachJ(J, 1.0f, "G"); //TeachJ(J, 1.0f, "H"); //TeachJ(J, 1.0f, "I"); //TeachJ(J, 1.0f, "J"); createOrthogonal(teachOrtho,J); // randomize initial spin state flipS(spindmg, S); // Restrict J if(restrictJbool) restrictJ(J); brainDamageRan(bdamage,J); // MC Run // Print Initial Spin State PrintSpins_Linux(S); // Perform MC Steps and Print Spin State for (Step = 0; Step < MC_Steps; Step++) { PrintSpins_Linux(S); // <-- In windows, use PrintSpins(), in linux use PrintSpins_Linux() T = (Tstart/MC_Steps)*(MC_Steps - Step); MonteCarloStep(S, J, T, refS); outputBMP(S, "Trial1"); } return 0; } // Chooses LxL random neurons to switch // If the energy decreases, the neuron is switched, if not it stays // <param S> Spin state of neurons // <param J> J matrix for neuron interactions void MonteCarloStep(int S[L][L], float J[L][L][L][L], float T, int refS[L][L]) { int x, y; float dE; int counter; counter = 0; for (int i = 0; i < L*L; i++) { // Choose Random Neuron to Switch x = (int)(L * (rand() / (RAND_MAX + 1.0))); y = (int)(L * (rand() / (RAND_MAX + 1.0))); // Calculate Energy Change dE = CalculateEnergyChange_SN(S, J, x, y); if (dE < 0.0) { S[x][y] = -S[x][y]; counter ++; } else { if (exp(-dE/T) > (rand() / (RAND_MAX + 1.0))) { S[x][y] = -S[x][y]; counter ++; } } } hammergy << Hamming(S, refS) << ' ' << CalculateEnergy(S, J) << endl; flips << counter << "\n" << endl; } // Calculates the total instantaneous energy // <param S> Spin states of neurons // <param J> J matrix for neuron interactions // <return> Returns the energy, E float CalculateEnergy(int S[L][L], float J[L][L][L][L]) { int i, j; float E = 0; for (i = 0; i < L*L; i++) { for (j = i + 1; j < L*L; j++) { if (!(i%L == j%L && (int)floor(1.0*i/L) == (int)floor(1.0*j/L))) { E -= J[i%L][(int)floor(1.0*i/L)][j%L][(int)floor(1.0*j/L)] * S[i%L][(int)floor(1.0*i/L)] * S[j%L][(int)floor(1.0*j/L)]; } } } return E; } // Calculates the Change in Energy for a Single Neuron Switch // <param S> Spin states of neurons // <param J> J matrix for neuron interactions // <param x> x coordinate for neuron to switch // <param y> y coordinate for neuron to switch // <return> Returns the change in energy, dE float CalculateEnergyChange_SN (int S[L][L], float J[L][L][L][L], int x, int y) { int j; float dE = 0; for (j = 0; j < L*L; j++) { if (!(x == j%L && y == (int)floor(1.0*j/L))) { dE -= (float)J[x][y][j%L][(int)floor(1.0*j/L)] * (float)-S[x][y] * (float)S[j%L][(int)floor(1.0*j/L)]; } } return dE; } // Initializes the Spins // <param S> Spin states of neurons void InitializeSpins(int S[L][L]) { for (int x = 0; x < L; x++) { for (int y = 0; y < L; y++) { S[x][y] = (int)floor(rand() / (RAND_MAX + 1.0) + 0.5); if (S[x][y] == 0) S[x][y] = -1; } } } // Initializes the Spins // <param S> Spin states of neurons // <param name> File name in the image directory to load void InitializeSpins(int S[L][L], char name[]) { std::string filename; std::stringstream filename_out; filename_out << image_directory << name << ".bmp"; filename = filename_out.str(); int* image = loadImage((char*)filename.c_str()); for (int i = 0; i < L*L; i++) { S[i%L][(int)floor(1.0*i/L)] = image[i]; } } // Initializes the J Matrix // <param selection> Chooses how to initialize J // case 1 - All values 0 // case 2 - Random Initialization // <param J> J matrix for neuron interactions void InitializeJ(int selection, float J[L][L][L][L]) { int ix, iy, jx, jy; switch (selection) { // Blank case 1: break; // Random Initialization between -5 and 5 case 2: for (ix = 0; ix < L; ix++) { for (iy = 0; iy < L; iy++) { for (jx = 0; jx < L; jx++) { for (jy = 0; jy < L; jy++) { J[ix][iy][jx][jy] = (float)(rand() / (RAND_MAX + 1.0) * 10.0 - 5.0); } } } } break; } } // "Teaches" new J values based on an input image // <param exposure_time> the weight of the image on the J matrix // <param image> the image to affect the J matrix void TeachJ(float J[L][L][L][L], float exposure_time, int* image) { for (int ix = 0; ix < L; ix++) { for (int iy = 0; iy < L; iy++) { for (int jx = 0; jx < L; jx++) { for (int jy = 0; jy < L; jy++) { J[ix][iy][jx][jy] = J_lifetime / (J_lifetime + exposure_time) * J[ix][iy][jx][jy] + exposure_time / (J_lifetime + exposure_time) * image[ix + iy * L] * image[jx + jy * L]; } } } } J_lifetime += exposure_time; } // "Teaches" new J values based on a bmp image // <param exposure_time> the weight of the image on the J matrix // <param name> The name of the file to be opened in the image_directory (e.g. "A" // with L=10 would open the file at "Letter Images/A_10.bmp" void TeachJ(float J[L][L][L][L], float exposure_time, char name[]) { std::string filename; std::stringstream filename_out; filename_out << image_directory << name << "_" << L << ".bmp"; filename = filename_out.str(); int* image = loadImage((char*)filename.c_str()); for (int ix = 0; ix < L; ix++) { for (int iy = 0; iy < L; iy++) { for (int jx = 0; jx < L; jx++) { for (int jy = 0; jy < L; jy++) { J[ix][iy][jx][jy] = (J_lifetime / (J_lifetime + exposure_time)) * J[ix][iy][jx][jy] + (exposure_time / (J_lifetime + exposure_time)) * image[ix + iy * L] * image[jx + jy * L]; } } } } J_lifetime += exposure_time; } // Prints the spin states to the terminal // <param S> Spin states of neurons void PrintSpins(int S[L][L]) { system("cls"); for (int x = 0; x < L; x++) { for (int y = 0; y < L; y++) { if (S[x][y] == -1) { cout << " "; } else { cout << "#"; } } cout << endl; } } // Prints the current spin matrix void PrintSpins_Linux(int S[L][L]) { system("clear"); for (int x = 0; x < L; x++) { for (int y = 0; y < L; y++) { if (S[x][y] == -1) { cout << " "; } else { cout << "#"; } } cout << endl; } } // Loads an image from the given filename and returns a binary 2D array // <param filename> Relative path of image int* loadImage(char filename[]) { BMP image; image.ReadFromFile(filename); int* S_image = new int[L*L]; for(int i = 0; i < L*L; i++) { if(image((int)floor(1.0*i/L),i%L)->Red + image((int)floor(1.0*i/L),i%L)->Blue + image((int)floor(1.0*i/L),i%L)->Green < 382) S_image[i] = 1; else S_image[i] = -1; } return S_image; } // Prints the current spin state to a .bmp image file in the output directory // <param S> Spin states of neurons // <param name> File name of current run (e.g. "test" in monte carlo step 1 // will produce the file "Run Output/test_1.bmp" void outputBMP(int S[L][L], char name[]) { std::string filename; std::stringstream filename_out; filename_out << output_directory << "TEMP" << "_" << Step << ".bmp"; filename = filename_out.str(); current_BMP.SetSize(L,L); for(int x = 0; x < L; x++) { for(int y = 0; y < L; y++) { if(S[x][y] == -1) { current_BMP(y,x)->Red = 255; current_BMP(y,x)->Green = 255; current_BMP(y,x)->Blue = 255; } else { current_BMP(y,x)->Red = 0; current_BMP(y,x)->Green = 0; current_BMP(y,x)->Blue = 0; } } } current_BMP.WriteToFile((char*)filename.c_str()); } // Restricts elements in J to +1 or -1 void restrictJ(float J[L][L][L][L]){ for (int ix = 0; ix < L; ix++) { for (int iy = 0; iy < L; iy++) { for (int jx = 0; jx < L; jx++) { for (int jy = 0; jy < L; jy++) { if(J[ix][iy][jx][jy]>=0) J[ix][iy][jx][jy]=1; else J[ix][iy][jx][jy]=-1; } } } } } // Simulates killing neurons in rectangle starting at (sx,sy) and extending dx and dy void brainDamageRec(int sx, int sy, int dx, int dy, float J[L][L][L][L], int S[L][L]){ for (int x = sx; x < sx+dx; x++) { for (int y = sy; y < sy+dy; y++) { S[y][x] = 1; for (int ix = 0; ix < L; ix++) { for (int iy = 0; iy < L; iy++) { J[y][x][iy][ix] = 0; J[iy][ix][y][x] = 0; } } } } } // Sets elements of J to 0 with a probability of rate void brainDamageRan(float rate, float J[L][L][L][L]){ if(rate != 0){ for (int ix = 0; ix < L; ix++) { for (int iy = 0; iy < L; iy++) { for (int jx = 0; jx < L; jx++) { for (int jy = 0; jy < L; jy++) { if((rand() / (RAND_MAX + 1.0))<rate) J[ix][iy][jx][jy]=0; } } } } } } // Creates and teaches pseudoorthogonal images void createOrthogonal(int n,float J[L][L][L][L]){ int * S1; S1 = new int [L*L]; for(int i=0; i<n; i++){ for (int x = 0; x < L*L; x++) { if((rand() / (RAND_MAX + 1.0)) < 0.5) S1[x] = 1; else S1[x] = -1; } TeachJ(J,1.0f,S1); } } // Sets initial spindamage void flipS(float spindmg, int S[L][L]) { if(spindmg != 0){ for (int x = 0; x < L; x++) { for (int y = 0; y < L; y++) { if((rand() / (RAND_MAX + 1.0))<spindmg) S[x][y] = int(((rand() % 2)-0.5)*2); } } } } // Calculates Hamming Distance float Hamming(int S[L][L], int refS[L][L]) { float hamming = 0.0f; for (int x = 0; x < L; x++) { for (int y = 0; y < L; y++) { hamming += (1.0 / L*L) * pow(refS[x][y] - S[x][y], 2.0); } } return hamming; } |