private void testNeuron_Click(object sender, EventArgs e) { Port[] neuronPorts = new Port[2]; neuronPorts[0] = new Port(Port.portDirection.IN, "in_0", Utilities.VHDLDataType.SIGNED_FIXED_POINT, 3, -4); neuronPorts[1] = new Port(Port.portDirection.IN, "in_1", Utilities.VHDLDataType.SIGNED_FIXED_POINT, 3, -4); AsyncNeuron n = new AsyncNeuron(neuronPorts, 4, 4, 4, AsyncNeuron.NeuronActivationType.SIGMOID_POLY_APPROX, "neuron_intfrac"); if (!n.writeVHDL("neuron_intfrac.vhd")) { MessageBox.Show("Problem in writing neuron_intfrac.vhd"); return; } MessageBox.Show("Files successfully written."); return; }
/// <summary> /// Determines if two neurons are equal /// </summary> /// <param name="obj">Object to compare to this neuron</param> /// <returns>True if the objects are equal, false otherwise</returns> public override bool Equals(object obj) { if (obj == null) { return(false); } AsyncNeuron n_obj = obj as AsyncNeuron; if (n_obj == null) { return(false); } var n_obj_inputPorts = n_obj.getInputPorts(); var n_obj_internalSignals = n_obj.getInternalSignals(); var n_obj_outputs = n_obj.getOutputPorts(); var n_obj_activation = n_obj.activationType; if (n_obj.activationType != this.activationType) { return(false); } if (n_obj_inputPorts.Length != this.neuronInputs.Length || n_obj_internalSignals.Length != this.getInternalSignals().Length) { return(false); } /*TODO: Handle zero edge cases*/ if (n_obj_inputPorts[0].top != this.neuronInputs[0].top || n_obj_inputPorts[0].bottom != this.neuronInputs[0].bottom || n_obj_inputPorts[0].type != this.neuronInputs[0].type) { return(false); } if (n_obj_outputs[0].top != this.neuronOutput.top || n_obj_outputs[0].bottom != this.neuronOutput.bottom || n_obj_outputs[0].type != this.neuronOutput.type) { return(false); } if (n_obj.numOutputIntBits != this.numOutputIntBits || n_obj.numOutputFracBits != this.numOutputFracBits) { return(false); } return(true); }
/// <summary> /// Writes the .vhd files necessary to compile this entity. /// All other necessary entities (i.e. neurons, thresholding functions, etc.) will also be written /// when this function returns /// </summary> /// <param name="file">The file path in which to write the files (do NOT include "...name.vhd"</param> /// <returns>true if the files were written successfully, false otherwise</returns> public override bool writeVHDL(string file) { bool successfulWrite = false; string entityFile = file + this.name + ".vhd"; using (StreamWriter sw = new StreamWriter(entityFile)) { /*Compile all of the entities into one list*/ List <Entity> uniqueEntities = new List <Entity>(); uniqueEntities.Add(this.wm); for (int i = 0; i < this.uniqueNeuronEntities.Count; i++) { uniqueEntities.Add(this.uniqueNeuronEntities[i]); } /*Write header*/ if (!((this.writeVHDLIncludes(sw)) && (this.writeVHDLEntity(sw)) && (this.writeArchitectureStatement(sw)) && (this.writeVHDLDependencies(sw, uniqueEntities)) && (this.writeVHDLSignals(sw)))) { return(false); } sw.WriteLine(String.Format("\t{0} <= {1};", this.ready.portName, this.ready_signal.name)); /*Write the memory signals*/ sw.WriteLine(String.Format("\twm: {0} port map", this.wm.name)); sw.WriteLine(String.Format("\t(")); sw.WriteLine(String.Format("\t\t{0} => std_logic_vector({1}),", this.wm.addr.portName, this.addrCounter.name)); sw.WriteLine(String.Format("\t\t{0} => {1},", this.wm.clk.portName, this.clk.portName)); sw.WriteLine(String.Format("\t\t{0} => {1}", this.wm.data.portName, this.loadValConv.name)); sw.WriteLine(String.Format("\t);")); sw.WriteLine(String.Format("")); sw.WriteLine(String.Format("\t{0} <= to_sfixed({1}, {0}'high, {0}'low);", this.loadVal.name, this.loadValConv.name)); sw.WriteLine(""); /*Write the neural network connections*/ int currentNeuron = 0; int previousLayerStartingPoint = 0; for (int i = 1; i < this.neuronCounts.Length; i++) { for (int j = 0; j < this.neuronCounts[i]; j++) { AsyncNeuron n = this.neuronEntities[currentNeuron]; sw.WriteLine(String.Format("\tNeuron_{0}_{1} : {2} port map", i, j, n.name)); sw.WriteLine(String.Format("\t(")); /*INPUT STATEMENTS*/ /*First row - use inputs*/ if (i == 1) { for (int k = 0; k < this.nnInputPorts.Length; k++) { sw.WriteLine(String.Format("\t\t{0} => {1},", n.neuronInputs[k].portName, this.nnInputPorts[k].portName)); } } /*Later row - use previous rows outputs*/ else { for (int k = 0; k < this.neuronEntities[currentNeuron].neuronInputs.Length; k++) { sw.WriteLine(String.Format("\t\t{0} => {1},", n.neuronInputs[k].portName, this.neuron_outputs[previousLayerStartingPoint + k].name)); } } sw.WriteLine(String.Format("\t\t{0} => {1}({2}),", n.loadEnablePort.portName, this.load_sig.name, currentNeuron)); //Load signal sw.WriteLine(String.Format("\t\t{0} => {1},", n.loadValuePort.portName, this.loadVal.name)); //LoadVal signal sw.WriteLine(String.Format("\t\t{0} => {1}({2} downto 0),", n.loadOffsetPort.portName, this.loadOffset.name, n.loadOffsetPort.top)); //LoadOff signal sw.WriteLine(String.Format("\t\t{0} => {1},", n.finalLoadPort.portName, this.finalLoadSignals[currentNeuron].name)); //FinalLoad signal sw.WriteLine(String.Format("\t\t{0} => {1},", n.loadClkPort.portName, this.clk.portName)); //Clk signal sw.WriteLine(String.Format("\t\t{0} => {1}", n.neuronOutput.portName, this.neuron_outputs[currentNeuron].name)); //Output signal sw.WriteLine("\t);"); sw.WriteLine(""); currentNeuron++; } if (i != 1) { previousLayerStartingPoint += this.neuronCounts[i - 1]; } } /*Load process*/ sw.WriteLine(String.Format("\tprocess ({0})", this.clk.portName)); sw.WriteLine(String.Format("\tbegin")); sw.WriteLine(String.Format("\t\tif (rising_edge({0}) and ( ({1} = '1') or ({2} = '0') ) ) then", this.clk.portName, this.reset.portName, this.ready_signal.name)); sw.WriteLine(String.Format("\t\t\tif ({0} = '1') then", this.reset.portName)); sw.WriteLine(String.Format("\t\t\t\t{0} <= '0';", this.ready_signal.name)); sw.WriteLine(String.Format("\t\t\t\t{0} <= (others => '0');", this.loadOffset.name)); sw.WriteLine(String.Format("\t\t\t\t{0} <= (others => '0');", this.addrCounter.name)); sw.WriteLine(String.Format("\t\t\t\t{0} <= (0 => '1', others => '0');", this.load_sig.name)); for (int i = 0; i < this.finalLoadSignals.Length; i++) { sw.WriteLine(String.Format("\t\t\telsif ({0} = '1') then", this.finalLoadSignals[i].name)); if (i != this.finalLoadSignals.Length - 1) { sw.WriteLine(String.Format("\t\t\t\t{0} <= ({1} => '1', others => '0');", this.load_sig.name, i + 1)); } else { sw.WriteLine(String.Format("\t\t\t\t{0} <= (others => '0');", this.load_sig.name)); } sw.WriteLine(String.Format("\t\t\t\t{0} <= (others => '0');", this.loadOffset.name)); } sw.WriteLine(String.Format("\t\t\telse")); sw.WriteLine(String.Format("\t\t\t\t{0} <= {0} + 1;", this.loadOffset.name)); sw.WriteLine(String.Format("\t\t\t\t{0} <= {0} + 1;", this.addrCounter.name)); sw.WriteLine(String.Format("\t\t\tend if;")); sw.WriteLine(String.Format("")); sw.WriteLine(String.Format("\t\t\tif ({0} = {1}) then", this.addrCounter.name, wm.weights_str.Count)); sw.WriteLine(String.Format("\t\t\t\t{0} <= '1';", this.ready_signal.name)); sw.WriteLine(String.Format("\t\t\tend if;")); sw.WriteLine(String.Format("\t\tend if;")); sw.WriteLine(String.Format("\tend process;")); sw.WriteLine(""); /*Write the comparitors for classification problems*/ if (this.isClassifier) { int currentOutputNeuronIndex = this.neuronEntities.Length - this.neuronCounts[this.neuronCounts.Length - 1]; int outputIndex = 0; while (currentOutputNeuronIndex < this.neuronEntities.Length) { Signal current_out = this.neuron_outputs[currentOutputNeuronIndex]; sw.WriteLine(String.Format("\tprocess ({0})", current_out.name)); sw.WriteLine(String.Format("\tbegin")); sw.WriteLine(String.Format("\t\tif ({0} > to_sfixed({1}, {0})) then", current_out.name, this.classifierThresholds[outputIndex])); sw.WriteLine(String.Format("\t\t\t{0} <= '1';", this.nnOutputPorts[outputIndex].portName)); sw.WriteLine(String.Format("\t\telse")); sw.WriteLine(String.Format("\t\t\t{0} <= '0';", this.nnOutputPorts[outputIndex].portName)); sw.WriteLine(String.Format("\t\tend if;")); sw.WriteLine(String.Format("\tend process;")); currentOutputNeuronIndex++; outputIndex++; } } /*Write the raw signal outputs for regression problems*/ else { int currentOutputNeuronIndex = this.neuronEntities.Length - this.neuronCounts[this.neuronCounts.Length - 1]; int outputIndex = 0; while (currentOutputNeuronIndex < this.neuronEntities.Length) { Signal current_out = this.neuron_outputs[currentOutputNeuronIndex]; sw.WriteLine(String.Format("\t{0} <= {1}", this.nnOutputPorts[outputIndex].portName, current_out.name)); sw.WriteLine(""); currentOutputNeuronIndex++; outputIndex++; } } /*Write dependent entities*/ foreach (Entity e in uniqueEntities) { if (!e.writeVHDL(file)) { return(false); } } successfulWrite = this.writeVHDLFooter(sw); } return(successfulWrite); }
/// <summary> /// The constructor for a neural network object. Calling this method's write() function will write the entire network. /// </summary> /// <param name="_neuronCounts">The number of neurons in each layer, excluding the bias node.</param> /// <param name="_biasValues">The bias value feeding forward into the next layer. </param> /// <param name="_activationTypes">The activation types for the neurons in each layer</param> /// <param name="_numIntBits">The number of integer bits to use for the inputs for each neuron (Sigmoid activated neurons automatically get this set to zero)</param> /// <param name="_numFracBits">The number of fractional bits to use for the inputs for each neuron</param> /// <param name="_numWeightUpperBits">The number of integer bits used for the weights for each neuron.</param> /// <param name="_isClassifier">If true, a comparitor will be instantiatated at the output to each node, comparing the output layer nodes to the threshold value.</param> /// <param name="_classifierThresholds">The threshold values for the output comparitors</param> /// <param name="_weights">The list of weights read in for the neurons from WeightReader.readWeightsFromFile()</param> /// <remark> For example, to intialize a classification neural network with three inputs, two hidden sigmoid-activated nodes, and one linear output node, use the following line:</remark> /// <remarks> NeuralNetwork nn = new NeuralNetwork([3, 2, 1], [-1, -1], [..SIGMOID_POLY_APPROX, ..LINEAR], 4, 4, 4, true, [0.5], _weights);</remarks> public AsyncNeuralNetwork(int[] _neuronCounts, double[] _biasValues, AsyncNeuron.NeuronActivationType[] _activationTypes, int _numIntBits, int _numFracBits, int _numWeightUpperBits, bool _isClassifier, double[] _classifierThresholds, List <double> _weights) { /*Copy member variables*/ this.neuronCounts = _neuronCounts; this.biasValues = _biasValues; this.activationTypes = _activationTypes; this.numIntBits = _numIntBits; this.numFracBits = _numFracBits; this.numWeightUpperBits = _numWeightUpperBits; this.classifierThresholds = _classifierThresholds; this.isClassifier = _isClassifier; /*Some useful variables for computing the signals*/ int numNeurons = 0; int maxWeights = neuronCounts[0]; for (int i = 1; i < neuronCounts.Length; i++) { numNeurons += neuronCounts[i]; if (maxWeights < neuronCounts[i]) { maxWeights = neuronCounts[i]; } } int offsetWidth = Utilities.getNumUnsignedBits(maxWeights); int addrCounterWidth = Utilities.getNumUnsignedBits(_weights.Count); /*Initialize memory signals and entities*/ this.wm = new WeightMemory(_numWeightUpperBits, _numFracBits, _weights); this.load_sig = new Signal("load_sig", Utilities.VHDLDataType.STD_LOGIC_VECTOR, new String('0', numNeurons), numNeurons - 1, 0); this.loadVal = new Signal("loadVal", Utilities.VHDLDataType.SIGNED_FIXED_POINT, null, numWeightUpperBits, -1 * numFracBits); //NOT -1 => signed this.loadOffset = new Signal("loadOff", Utilities.VHDLDataType.UNSIGNED, new String('0', offsetWidth), offsetWidth - 1, 0); this.addrCounter = new Signal("addrCounter", Utilities.VHDLDataType.UNSIGNED, new String('0', addrCounterWidth), addrCounterWidth - 1, 0); this.ready_signal = new Signal("ready_sig", Utilities.VHDLDataType.STD_LOGIC, null, 0, 0); this.finalLoadSignals = new Signal[numNeurons]; int arrCounter = 0; for (int i = 1; i < neuronCounts.Length; i++) { for (int j = 0; j < neuronCounts[i]; j++) { this.finalLoadSignals[arrCounter] = new Signal(String.Format("finalLoad_{0}_{1}", i - 1, j), Utilities.VHDLDataType.STD_LOGIC, null, 0, 0); arrCounter++; } } this.loadValConv = new Signal("loadValConv", Utilities.VHDLDataType.STD_LOGIC_VECTOR, null, _numWeightUpperBits + _numFracBits, 0); /*Compute the bus widths between neurons*/ int maxNeuronInput = Convert.ToInt32(Math.Pow(2, this.numIntBits)) - 1; int currentNeuronInput = Convert.ToInt32(Math.Pow(2, this.numIntBits)) - 1; this.intBusWidths = new int[numNeurons + this.neuronCounts[0]]; double[] maxValues = new double[numNeurons + this.neuronCounts[0]]; int neuronStart = 0; int weightCounter = 0; for (neuronStart = 0; neuronStart < this.neuronCounts[0]; neuronStart++) { maxValues[neuronStart] = (double)maxNeuronInput; this.intBusWidths[neuronStart] = Utilities.getNumUnsignedBits(Convert.ToInt32(Math.Ceiling((double)maxNeuronInput))); } neuronStart = 0; for (int i = 1; i < this.neuronCounts.Length; i++) { int[] currentNeuronMaxIntWidths = new int[this.neuronCounts[i]]; if (this.activationTypes[i - 1] == AsyncNeuron.NeuronActivationType.SIGMOID_POLY_APPROX) { for (int j = 0; j < this.neuronCounts[i]; j++) { maxValues[neuronStart + this.neuronCounts[i - 1]] = 0.9999; this.intBusWidths[neuronStart + this.neuronCounts[i - 1]] = 0; neuronStart++; } } else if (this.activationTypes[i - 1] == AsyncNeuron.NeuronActivationType.NONE) { throw new Exception("YOU DUN F****D UP HERE TOO"); //debugging } else if (this.activationTypes[i - 1] == AsyncNeuron.NeuronActivationType.LINEAR) { for (int j = 0; j < this.neuronCounts[i]; j++) { double currentMax = 0; int neuronIndex = neuronStart; for (int k = 0; k < this.neuronCounts[i - 1]; k++) { currentMax += _weights[weightCounter] * maxValues[neuronIndex]; weightCounter++; neuronIndex++; } maxValues[j + neuronStart + this.neuronCounts[i - 1]] = currentMax; this.intBusWidths[j + neuronStart + this.neuronCounts[i - 1]] = Utilities.getNumUnsignedBits(Convert.ToInt32(Math.Ceiling(currentMax))); } neuronStart += this.neuronCounts[i - 1]; } } if (this.isClassifier) { for (int i = this.intBusWidths.Length - 1; (this.intBusWidths.Length - i) <= this.neuronCounts[this.neuronCounts.Length - 1]; i--) { this.intBusWidths[i] = 1; } } /*Initialize neurons and their connectivities*/ this.neuronEntities = new AsyncNeuron[numNeurons]; this.neuron_outputs = new Signal[numNeurons]; this.uniqueNeuronEntities = new List <AsyncNeuron>(); var currentPorts = new List <Port>(); this.nnInputPorts = new Port[this.neuronCounts[0]]; neuronStart = 0; for (int i = 0; i < this.neuronCounts[0]; i++) { this.nnInputPorts[i] = new Port(Port.portDirection.IN, String.Format("nnIn_{0}", i), Utilities.VHDLDataType.SIGNED_FIXED_POINT, this.intBusWidths[neuronStart], this.numFracBits * -1); neuronStart++; } for (int i = 0; i < this.nnInputPorts.Length; i++) { Port P = this.nnInputPorts[i].copy(); P.rename(String.Format("in_{0}", i)); currentPorts.Add(P); } arrCounter = 0; for (int i = 1; i < this.neuronCounts.Length; i++) { var lastPorts = currentPorts.ToArray(); currentPorts = new List <Port>(); if (this.activationTypes[i - 1] == AsyncNeuron.NeuronActivationType.SIGMOID_POLY_APPROX) { for (int j = 0; j < this.neuronCounts[i]; j++) { AsyncNeuron n = new AsyncNeuron(lastPorts, this.intBusWidths[neuronStart], this.numFracBits, this.numWeightUpperBits, AsyncNeuron.NeuronActivationType.SIGMOID_POLY_APPROX, String.Format("sig_poly_approx_neuron_{0}_{1}", i, 0)); neuronStart++; if (j == 0) { /*Check for uniqueness*/ if (!this.uniqueNeuronEntities.Contains(n)) { this.uniqueNeuronEntities.Add(n); } } this.neuronEntities[arrCounter] = n; Signal currentNeuronOutput = n.neuronOutput.toSignal(String.Format("out_{0}_{1}", i, j)); this.neuron_outputs[arrCounter] = currentNeuronOutput; Port tempOut = n.neuronOutput.copy(); tempOut.rename(String.Format("in_{0}", j)); tempOut.setDirection(Port.portDirection.IN); currentPorts.Add(tempOut); arrCounter++; } } else if (this.activationTypes[i - 1] == AsyncNeuron.NeuronActivationType.LINEAR) { for (int j = 0; j < this.neuronCounts[i]; j++) { AsyncNeuron n = new AsyncNeuron(lastPorts, this.intBusWidths[neuronStart], this.numFracBits, this.numWeightUpperBits, AsyncNeuron.NeuronActivationType.LINEAR, String.Format("linear_neuron_{0}_{1}", i, 0)); neuronStart++; if (j == 0) { if (!this.uniqueNeuronEntities.Contains(n)) { this.uniqueNeuronEntities.Add(n); } } this.neuronEntities[arrCounter] = n; Signal currentNeuronOutput = n.neuronOutput.toSignal(String.Format("out_{0}_{1}", i, j)); this.neuron_outputs[arrCounter] = currentNeuronOutput; Port tempOut = n.neuronOutput.copy(); tempOut.rename(String.Format("in_{0}", j)); tempOut.setDirection(Port.portDirection.IN); currentPorts.Add(tempOut); arrCounter++; } } } /*Initialize outputs*/ this.nnOutputPorts = new Port[this.neuronCounts[this.neuronCounts.Length - 1]]; if (this.isClassifier) { for (int i = 0; i < this.neuronCounts[this.neuronCounts.Length - 1]; i++) { this.nnOutputPorts[i] = new Port(Port.portDirection.OUT, String.Format("out_{0}", i), Utilities.VHDLDataType.STD_LOGIC, 0, 0); } } else { neuronStart -= this.neuronCounts[this.neuronCounts.Length - 1]; for (int i = 0; i < this.neuronCounts[this.neuronCounts.Length - 1]; i++) { this.nnOutputPorts[i] = new Port(Port.portDirection.OUT, String.Format("out{0}", i), Utilities.VHDLDataType.SIGNED_FIXED_POINT, this.intBusWidths[neuronStart], this.numFracBits); neuronStart++; } } /*Initialize other signals*/ this.ready = new Port(Port.portDirection.OUT, "ready", Utilities.VHDLDataType.STD_LOGIC, 0, 0); this.reset = new Port(Port.portDirection.IN, "reset", Utilities.VHDLDataType.STD_LOGIC, 0, 0); this.clk = new Port(Port.portDirection.IN, "clk", Utilities.VHDLDataType.STD_LOGIC, 0, 0); return; }