def test_to_one_hot_speed(self, capsys): @measure_time(iterations=100, function_repetitions=100) def measured_step(): mb.tensor.copy_( torch.rand(input_shape, dtype=get_float(device), device=device)) to_one_hot.step() input_shape = (150, ) device = 'cuda' vector = torch.zeros(input_shape, dtype=get_float(device), device=device) mb = MemoryBlock() mb.tensor = torch.tensor(vector, device=device, dtype=get_float(device)) to_one_hot = ToOneHotNode(mode=ToOneHotMode.RANDOM) Connector.connect(mb, to_one_hot.inputs.input) to_one_hot.allocate_memory_blocks(AllocatingCreator(device)) with capsys.disabled(): measured_step()
def test_join_node_inverse_flatten(): device = 'cpu' creator = AllocatingCreator(device) dtype = creator.float32 # The result of the inverse projection should only be one tensor. expected_results = [ creator.tensor([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=dtype, device=device), creator.tensor([9, 10], dtype=dtype, device=device) ] input_memory_blocks = [MemoryBlock(), MemoryBlock()] input_memory_blocks[0].tensor = creator.zeros((2, 4)) input_memory_blocks[1].tensor = creator.zeros((2, )) output_tensor = creator.tensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=dtype, device=device) join_node = JoinNode(flatten=True) Connector.connect(input_memory_blocks[0], join_node.inputs[0]) Connector.connect(input_memory_blocks[1], join_node.inputs[1]) output_inverse_packet = InversePassOutputPacket(output_tensor, join_node.outputs.output) join_node.allocate_memory_blocks(creator) results = join_node.recursive_inverse_projection_from_output( output_inverse_packet) for expected, result in zip(expected_results, results): assert same(expected, result.tensor)
def test_fork_node_inverse_0(): # TODO (Test): add for dim = 1, then refactor. creator = AllocatingCreator(device='cpu') dtype = creator.float32 dim = 0 expected_results = [ creator.tensor( [[1, 2, 3, 4], [5, 6, 7, 8], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=dtype, device=creator.device) ] input_memory_block = MemoryBlock() input_memory_block.tensor = creator.zeros((4, 4)) output_tensor = creator.tensor([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=dtype, device=creator.device) fork_node = ForkNode(dim, split_sizes=[2, 2]) Connector.connect(input_memory_block, fork_node.inputs.input) output_inverse_packet = InversePassOutputPacket(output_tensor, fork_node.outputs[0]) fork_node.allocate_memory_blocks(creator) results = fork_node.recursive_inverse_projection_from_output( output_inverse_packet) for expected, result in zip(expected_results, results): assert same(expected, result.tensor)
def test_expert_dimensions(self): """Tests multi-dimensional expert indexes.""" device = 'cpu' parent_rf_size_x = parent_rf_size_y = 4 n_channels = 4 image_grid_size_x = image_grid_size_y = 16 input_dimensions = (image_grid_size_y, image_grid_size_x, n_channels) parent_rf_dims = Size2D(parent_rf_size_x, parent_rf_size_y) parent_grid_dimensions = (4, 4) graph = Topology(device) node = ReceptiveFieldNode(input_dimensions, parent_rf_dims) graph.add_node(node) memory_block = MemoryBlock() memory_block.tensor = torch.zeros(image_grid_size_y, image_grid_size_x, n_channels, device=device) memory_block.tensor[0, parent_rf_size_x, 0] = 1 Connector.connect(memory_block, node.inputs.input) graph.prepare() graph.step() node_output = node.outputs.output.tensor assert node_output.shape == torch.Size(parent_grid_dimensions + (parent_rf_size_y, parent_rf_size_x, n_channels)) assert node_output[0, 1, 0, 0, 0] == 1
def test_owner(): dummy_node = DummyNode() tensor = torch.zeros([1, 2]) mb = MemoryBlock(dummy_node) mb.tensor = tensor assert mb.owner == dummy_node
def create_network_inputs(net1: NNetNode, net2: NNetNode): """Create two identical networks, connect to the same inputs""" # generate input memory blocks input_tensor = _random_image(net1._params.input_shape) input_memory_block = MemoryBlock('input') input_memory_block.tensor = input_tensor input_label = _random_label(net1._params.output_size) label_memory_block = MemoryBlock('input_label') label_memory_block.tensor = input_label is_testing_tensor = torch.tensor([0]) is_testing_memory_block = MemoryBlock('is_testing') is_testing_memory_block.tensor = is_testing_tensor # connect inputs to the network Connector.connect(input_memory_block, net1.inputs.input) Connector.connect(label_memory_block, net1.inputs.label) Connector.connect(is_testing_memory_block, net1.inputs.testing_phase) Connector.connect(input_memory_block, net2.inputs.input) Connector.connect(label_memory_block, net2.inputs.label) Connector.connect(is_testing_memory_block, net2.inputs.testing_phase) return input_tensor, input_label, is_testing_tensor
def test_add_interpretation(tensor_shape, interpreted_dim, interpretation, expected_interpret_shape): dummy_node = DummyNode() tensor = torch.zeros(tensor_shape) mb = MemoryBlock(dummy_node, 'mb') mb.tensor = tensor mb.reshape_tensor(interpretation, interpreted_dim) assert list(mb.shape) == expected_interpret_shape
def test_scatter_node(self, device, input, mask, output_shape, dimension, expected_result): float_dtype = get_float(device) input_mb = MemoryBlock() input_mb.tensor = torch.tensor(input, device=device, dtype=float_dtype) expected = torch.tensor(expected_result, device=device, dtype=float_dtype) sn = ScatterNode(mapping=mask, output_shape=output_shape, dimension=dimension, device=device) Connector.connect(input_mb, sn.inputs.input) sn.allocate_memory_blocks(AllocatingCreator(device)) sn.step() assert same(sn.outputs.output.tensor, expected)
def test_inverse_projection(self, device): dtype = get_float(device) params = ExpertParams() params.flock_size = 2 params.n_cluster_centers = 4 params.spatial.input_size = 6 params.spatial.buffer_size = 7 params.spatial.batch_size = 3 params.temporal.n_frequent_seqs = 2 params.temporal.seq_length = 3 input_size = (3, 2) graph = Topology(device) node = ExpertFlockNode(params=params) graph.add_node(node) input_block = MemoryBlock() input_block.tensor = torch.rand((params.flock_size, ) + input_size, dtype=dtype, device=device) Connector.connect(input_block, node.inputs.sp.data_input) graph.prepare() node._unit.flock.sp_flock.cluster_centers = torch.tensor( [[[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0.5, 0.5, 0, 0], [0, 0, 0.5, 0, 0.5, 0]], [[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0]]], dtype=dtype, device=device) # Just SP inverse projection data = torch.tensor([[0, 0, 1, 0], [0.2, 0.3, 0.4, 0.1]], dtype=dtype, device=device) packet = InversePassOutputPacket(data, node.outputs.tp.projection_outputs) projected = node.recursive_inverse_projection_from_output(packet) # The result of the projection itself would be [[0, 0, 0.5, 0.5, 0, 0], ...], and it should be viewed as (2, 3, 2). expected_projection = torch.tensor( [[[0, 0], [0.5, 0.5], [0, 0]], [[0.2, 0.3], [0.4, 0.1], [0, 0]]], dtype=dtype, device=device) assert same(expected_projection, projected[0].tensor)
def test_pass_node(): device = 'cpu' dtype = torch.float32 input_tensor = torch.tensor([[0, 1, -1], [1, 2, 3]], device=device, dtype=dtype) expected_tensor = input_tensor mb0 = MemoryBlock() mb0.tensor = input_tensor pn = PassNode((2, 3)) pn.allocate_memory_blocks(AllocatingCreator(device)) Connector.connect(mb0, pn.inputs.input) pn._step() assert same(pn.outputs.output.tensor, expected_tensor)
def test_actions_parser_node(device): float_dtype = get_float(device) sed = SpaceEngineersActionsDescriptor() input_mb = MemoryBlock() input_mb.tensor = torch.tensor([1, 0.5], device=device, dtype=float_dtype) expected = torch.tensor([1, 0, 0.5, 0, 0, 0, 0, 0, 0, 0], device=device, dtype=float_dtype) sn = AgentActionsParserNode(sed, ['UP', 'FORWARD'], device=device) Connector.connect(input_mb, sn.inputs.input) sn.allocate_memory_blocks(AllocatingCreator(device)) sn.step() assert same(sn.outputs.output.tensor, expected)
def test_rf_node(self, device): float_dtype = get_float(device) parent_rf_size_x = parent_rf_size_y = 4 n_channels = 4 image_grid_size_x = image_grid_size_y = 16 dimensions = (image_grid_size_y, image_grid_size_x, n_channels) parent_rf_dims = Size2D(parent_rf_size_y, parent_rf_size_x) graph = Topology(device) node = ReceptiveFieldNode(dimensions, parent_rf_dims, flatten_output_grid_dimensions=True) graph.add_node(node) memory_block = MemoryBlock() memory_block.tensor = torch.zeros(image_grid_size_y, image_grid_size_x, n_channels, dtype=float_dtype, device=device) memory_block.tensor[0, parent_rf_size_x, 0] = 1 Connector.connect(memory_block, node.inputs.input) graph.prepare() graph.step() node_output = node.outputs.output.tensor n_parent_rfs = (image_grid_size_y // parent_rf_size_y) * ( image_grid_size_x // parent_rf_size_x) assert node_output.shape == torch.Size( [n_parent_rfs, parent_rf_size_y, parent_rf_size_x, n_channels]) assert node_output[1, 0, 0, 0] == 1 back_projection = node.recursive_inverse_projection_from_output( InversePassOutputPacket(node_output, node.outputs.output)) # assert back_projection.interpret_shape == input_image.shape assert same(back_projection[0].tensor, memory_block.tensor)
def test_grayscale_node(self, squeeze_channel, tensor_data): device = 'cpu' dtype = torch.float32 input_tensor = torch.tensor( [[1, 1, 1], [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]], device=device, dtype=dtype) expected_tensor = torch.tensor(tensor_data, device=device, dtype=dtype) mb0 = MemoryBlock() mb0.tensor = input_tensor gn = GrayscaleNode(squeeze_channel=squeeze_channel) Connector.connect(mb0, gn.inputs.input) gn.allocate_memory_blocks(AllocatingCreator(device)) gn._step() assert same(gn.outputs.output.tensor, expected_tensor, 0.000001) # allow small epsilon differences
def test_to_one_hot_test(self, mode, vector, expected_indexes, device): mb = MemoryBlock() mb.tensor = torch.tensor(vector, device=device, dtype=get_float(device)) t_expected_indexes = torch.tensor(expected_indexes, device=device, dtype=torch.uint8) to_one_hot = ToOneHotNode(mode=mode) Connector.connect(mb, to_one_hot.inputs.input) to_one_hot.allocate_memory_blocks(AllocatingCreator(device)) to_one_hot.step() last_dim = mb.tensor.shape[-1] output_tensor = to_one_hot.outputs.output.tensor.view(-1, last_dim) expected_idxs = t_expected_indexes.view(-1, last_dim) for output, idxs in zip(output_tensor, expected_idxs): assert (output[idxs] == 1).any() assert (output[~idxs] == 0).all()
def test_join_node_inverse_0(): # TODO (Test): Make a dim = 1 variant # TODO (Test): Then, refactor tests here, maybe something to match the test class above, but for the backward projection. creator = AllocatingCreator(device='cpu') dtype = creator.float32 dim = 0 # The result of the inverse projection should only be one tensor. expected_results = [ creator.tensor([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=dtype, device=creator.device), creator.tensor([[9, 10, 11, 12], [13, 14, 15, 16]], dtype=dtype, device=creator.device) ] input_memory_blocks = [MemoryBlock(), MemoryBlock()] input_memory_blocks[0].tensor = creator.zeros((2, 4)) input_memory_blocks[1].tensor = creator.zeros((2, 4)) output_tensor = creator.tensor( [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]], dtype=dtype, device=creator.device) join_node = JoinNode(dim, n_inputs=2) Connector.connect(input_memory_blocks[0], join_node.inputs[0]) Connector.connect(input_memory_blocks[1], join_node.inputs[1]) output_inverse_packet = InversePassOutputPacket(output_tensor, join_node.outputs.output) join_node.allocate_memory_blocks(creator) results = join_node.recursive_inverse_projection_from_output( output_inverse_packet) for expected, result in zip(expected_results, results): assert same(expected, result.tensor)
def test_tensor_reference(): device = 'cpu' node = DummyNode() tens = torch.zeros([10, 12]).to(device).random_() tens_copy = tens another_tensor = torch.zeros([10, 12]).to(device).random_() mem = MemoryBlock(node) mem.tensor = tens assert mem.tensor is tens assert mem.tensor is tens_copy assert mem.tensor is not another_tensor assert same(mem.tensor, tens) assert not same(mem.tensor, another_tensor) tens.random_() assert mem.tensor is tens assert mem.tensor is tens_copy assert same(mem.tensor, tens)
def test_action_monitor_node(action_in, override, override_action, device): float_dtype = get_float(device) action_in = action_in.type(float_dtype).to(device) node = ActionMonitorNode(descriptor) node.allocate_memory_blocks(AllocatingCreator(device=device)) block = MemoryBlock() block.tensor = action_in Connector.connect(block, node.inputs.action_in) node._override_checked = override node._actions_values = override_action node.step() output = node.outputs.action_out.tensor expected_output = torch.tensor(override_action, dtype=float_dtype, device=device) if override else action_in assert same(expected_output, output)
def test_lambda_node(): device = 'cpu' dtype = torch.float32 input_tensor_0 = torch.tensor([0, 1, -1], device=device, dtype=dtype) input_tensor_1 = torch.tensor([1, 1, -1], device=device, dtype=dtype) expected_tensor = input_tensor_0 + input_tensor_1 mb0, mb1 = MemoryBlock(), MemoryBlock() mb0.tensor, mb1.tensor = input_tensor_0, input_tensor_1 def add_f(inputs, outputs): outputs[0][:] = 0 outputs[0].add_(inputs[0]) outputs[0].add_(inputs[1]) ln = LambdaNode(add_f, 2, [input_tensor_0.shape]) ln.allocate_memory_blocks(AllocatingCreator(device=device)) Connector.connect(mb0, ln.inputs[0]) Connector.connect(mb1, ln.inputs[1]) ln._step() assert same(ln.outputs[0].tensor, expected_tensor)
def test_output_tensor_shapes(self): # Although the experts internally only work with all the input dimensions squashed into one, some memory blocks # should provide a view of the internal tensors in the same shape as the input that the node received. params = ExpertParams() input_size = (28, 28) node = ExpertFlockNode(params=params) input_block = MemoryBlock() input_block.tensor = TensorSurrogate(dims=(params.flock_size, ) + input_size) Connector.connect(input_block, node.inputs.sp.data_input) tensor_creator = MeasuringCreator() node.allocate_memory_blocks(tensor_creator) assert input_size == tuple( node.memory_blocks.sp.buffer_inputs.shape[-2:]) assert input_size == tuple( node.memory_blocks.sp.cluster_centers.shape[-2:]) assert input_size == tuple( node.memory_blocks.sp.cluster_center_targets.shape[-2:]) assert input_size == tuple( node.memory_blocks.sp.cluster_center_deltas.shape[-2:])
def _create_slot_instance(self, name) -> MemoryBlock: return MemoryBlock(self._owner, name)
def memory_block(tensor: torch.Tensor) -> MemoryBlock: memory_block = MemoryBlock() memory_block.tensor = tensor return memory_block
def _inputs_to_sources(inputs): outputs = [MemoryBlock(None, f'output{i}') for i in range(len(inputs))] for output, tensor in zip(outputs, inputs): output.tensor = tensor return outputs