Source code for hashtron.net.feedforward.feedforward_network
from hashtron.classifier.constructor import Hashtron
from hashtron.layer.layer import Layer
from hashtron.hash.hash import Hash
from hashtron.net.single_value import SingleValue
from hashtron.net.input import Input
[docs]
class FeedforwardNetwork:
def __init__(self, net):
self.net = net
self.layers = []
self.mapping = []
self.combiners = []
self.premodulo = []
[docs]
def new_layer(self, n: int, bits: int, premodulo: int = 0) -> None:
layer = [Hashtron.new(None, bits) for _ in range(n)]
self.layers.append(layer)
self.mapping.append(bits)
self.combiners.append(None)
self.premodulo.append(premodulo)
[docs]
def new_combiner(self, layer: Layer) -> None:
self.layers.append([])
self.mapping.append(0)
self.combiners.append(layer)
self.premodulo.append(0)
[docs]
def len_layers(self) -> int:
"""
Get the number of layers in the network.
:return: The number of layers.
"""
return len(self.layers)
[docs]
def infer(self, in_val) -> int:
"""
Infer the network output based on input.
:param in_val: The input to the network.
:return: The output of the network.
"""
if (not hasattr(in_val, 'feature') or not callable(in_val.feature)) and in_val is not Input and in_val is not SingleValue:
in_val = SingleValue(in_val)
if (not hasattr(in_val, 'parity') or not callable(in_val.parity)) and in_val is not Input:
in_val = Input(in_val)
output = in_val
for l_prev in range(0, self.len_layers(), 2):
output, _ = self.forward(output, l_prev, -1, 0)
return output.feature(0) ^ in_val.parity() & (self.get_classes() - 1)
[docs]
def forward(self, in_val, l: int, worst: int, neg: int) -> (Input, bool):
"""
Forward pass through the network.
:param in_val: The input to the layer.
:param l: The layer index.
:param worst: The index of the worst hashtron.
:param neg: Whether to negate the worst hashtron's output.
:return: The intermediate output and a boolean indicating if the worst hashtron's output was computed.
"""
if len(self.combiners) > l + 1 and self.combiners[l + 1] is not None:
combiner = self.combiners[l + 1].lay()
computed = False
for i in range(len(self.layers[l])):
feat = in_val.feature(i)
if self.premodulo[l] != 0:
feat = Hash.hash(feat, i, self.premodulo[l])
bit = self.layers[l][i].forward.forward(feat, (i == worst) and (neg == 1))
combiner.put(i, (bit & 1) != 0)
if i == worst:
computed = (bit & 1) != 0
return combiner, computed
elif len(self.mapping) > l and self.mapping[l] > 0:
if self.premodulo[l] != 0:
in_val = SingleValue(Hash.hash(in_val.feature(0), 0, self.premodulo[l]))
val = self.layers[l][0].forward.forward(in_val.feature(0), (0 == worst) and (neg == 1))
return SingleValue(val), False
else:
if self.premodulo[l] != 0:
in_val = SingleValue(Hash.hash(in_val.feature(0), 0, self.premodulo[l]))
bit = self.layers[l][0].forward.forward(in_val.feature(0), (0 == worst) and (neg == 1))
return SingleValue(bit & 1), (bit & 1) != 0
[docs]
def get_bits(self) -> int:
if len(self.mapping) == 0:
return 1
ret = self.mapping[len(self.mapping)-1]
if ret == 0:
return 1
return ret
[docs]
def get_classes(self) -> int:
return 1 << self.get_bits()