Reputation: 2161
I'm trying to learn MyHDL and for that I was trying to create a very simple artificial neuron that could later be used in a simple artificial neural network. First I designed an artificial neuron that could only handle a single input and weight signal and returned an output signal.
@block
def input_perceptron(clk, max_res, in_signal, w_signal, out_signal):
'''a hidden layer neuron
out_signal is the result of: transfer_function( input_i x weight_i )
'''
@always(clk.posedge)
def logic():
# Multiply inputs and scale down with the shift
weighted_signal = (in_signal * w_signal) >> max_res+1
# Perform desired transfer function
tf_result = rect_transfer_func( weighted_signal, max_res )
# Assign new result
out_signal.next = tf_result
# The perceptron block must return this - MyHDL syntax
return instances()
To convert it to Verilog I used another function:
def converter(max_res=16, hdl='Verilog'):
# Initialize Signals
max_val = 1 << max_res + 1
clk = Signal( bool(0) )
in_signal = Signal( intbv( randrange(max_val), min=0, max=max_val ) )
w_signal = Signal( intbv( randrange(max_val), min=0, max=max_val ) )
out_signal = Signal( intbv( 0, min=0, max=max_val ) )
# Instantiate component
perceptron_inst = input_perceptron(clk, max_res, in_signal, w_signal, out_signal)
# Convert component to desired HDL language
perceptron_inst.convert(hdl=hdl)
Everything was going great so far. Not only were the simulations showing me what I expected, but also the converted code was correct and I was able to synthesize it in Vivado. However, in a neural network, the hidden and output layer neurons must be able to handle information coming from multiple sources, a.k.a a list or bus of signals, and this is where I'm having trouble.
By using MyHDL's and Python's amazing functions for running simulations I was able to correctly simulate a simple perceptron with the following code by using lists of signals for the inputs and weights:
@block
def perceptron(clk, max_val, max_res, in_bus, w_bus, out_signal):
''' Perceptron
out_signal is the result of: transfer_function( sum( input_i x weight_i ) )
'''
@always(clk.posedge)
def logic():
# Multiply inputs and scale down
sum_weighted_inputs = 0
for i in range(len(in_bus)):
weighted_input = in_bus[i] * w_bus[i] >> max_res+1
sum_weighted_inputs += weighted_input
# Perform desired transfer function
tf = step_transfer_func(sum_weighted_inputs, max_res, max_val)
# Assign new result to ouput port
out_signal.next = tf
return instances()
After going through the docs (docs) I understood that in MyHDL a block can't use a list of signals as a port, and that according to this chapter I should convert my list of signals into a ConcatSignal, which I did like so:
def converter(max_res, num_inputs, hdl='Verilog'):
# Clock parameters
clk = Signal( bool(0) )
# Signal parameters: inputs, weights and outputs
max_val = 1 << max_res + 1
out_signal = Signal( intbv( 0, min=0, max=max_val )[max_res+1:] )
in_list = [Signal( intbv( randrange(max_val), min=0, max=max_val )[max_res+1:] ) for i in range(num_inputs)]
w_list = [Signal( intbv( randrange(max_val), min=0, max=max_val )[max_res+1:] ) for i in range(num_inputs)]
# Converting to a bus in HDL
input_bus = ConcatSignal(*reversed(in_list))
weight_bus = ConcatSignal(*reversed(w_list))
# Instantiate component
perceptron_inst = perceptron(clk, max_val, max_res, input_bus, weight_bus, out_signal)
# Convert component to desired HDL language
perceptron_inst.convert(hdl=hdl)
When I try to simulate the design everything works as expected, however when converting there is a small error: the in_bus
and w_bus
inputs to the perceptron are defined in Verilog as output
ports instead of input
ports. As a consequence of this 2 wires
for those ports are also generated and they're assigned a value of None
.
The interesting bit is that the rest of the Verilog code is correct and if I simply delete the generated wires
and None
assignment, and if I manually change output
to input
for the in_bus
and w_bus
in the Verilog file then the code is synthesizable. If I look at the elaborated design by Vivado after these changes the module seems to be exactly what I intended.
Although I could manually fix this problem in the Verilog files I feel this problem comes from a wrong use/lack of understanding of MyHDL on my part. I cannot understand why the use of a ConcatSignal
suddenly turns the input
ports into output
ports.
Any idea on what I'm missing here?
Upvotes: 2
Views: 310
Reputation: 420
You cannot use list-of-signals as a top-level port, you will want to create a wrapper that has a single input, creates your list-of-signals, then it can be passed to the generic.
Upvotes: 1