![]() |
![]() |
![]() |
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;
}
|


