├── main_eval.py ├── tests ├── __init__.py ├── core │ ├── __init__.py │ ├── eval2 │ │ ├── __init__.py │ │ ├── test_run_topology.py │ │ └── test_measurement_manager_new.py │ ├── graph │ │ ├── __init__.py │ │ ├── test_unit.py │ │ └── node_stub.py │ ├── gui │ │ ├── __init__.py │ │ └── observers │ │ │ └── __init__.py │ ├── nodes │ │ ├── __init__.py │ │ ├── test_pass_node.py │ │ ├── test_lambda_node.py │ │ ├── test_grayscale_node.py │ │ ├── test_grid_world.py │ │ ├── test_salient_region_node.py │ │ ├── test_constant_node.py │ │ ├── test_unsqueeze_node.py │ │ ├── test_inverse_projection.py │ │ ├── test_dataset_simple_point_gravity.py │ │ ├── test_random_noise_node.py │ │ ├── test_multi_dataset_alphabet.py │ │ ├── test_convSpatialPoolerFlockNode.py │ │ ├── test_visited_area_node.py │ │ └── test_periodic_update_node_group.py │ ├── utils │ │ ├── __init__.py │ │ ├── test_space_engineers_connector.py │ │ ├── test_param_utils.py │ │ ├── test_inverse_projection_utils.py │ │ └── list_list_utils.py │ ├── datasets │ │ ├── __init__.py │ │ ├── alphabet │ │ │ ├── __init__.py │ │ │ └── test_alphabet_generator.py │ │ ├── test_sequence.py │ │ └── test_mnist.py │ ├── memory │ │ └── __init__.py │ ├── models │ │ ├── __init__.py │ │ ├── flock │ │ │ └── __init__.py │ │ ├── receptive_field │ │ │ └── __init__.py │ │ ├── spatial_pooler │ │ │ └── __init__.py │ │ ├── temporal_pooler │ │ │ └── __init__.py │ │ ├── test_expert_params.py │ │ └── integration_test_utils.py │ ├── eval │ │ ├── test_image.png │ │ ├── test_cluster_agreement.py │ │ ├── test_entropy.py │ │ └── test_doc_generator.py │ ├── node_accessors │ │ ├── test_random_number_node_accessor.py │ │ ├── test_se_dataset_navigation_accessor.py │ │ └── test_mnist_node_accessor.py │ ├── test_global_settings.py │ └── test_seed_utils.py ├── gui │ ├── __init__.py │ ├── server │ │ ├── __init__.py │ │ ├── test_ui_server_connector.py │ │ └── test_ui_api.py │ └── test_observer_view.py ├── utils │ ├── __init__.py │ ├── test_os_utils.py │ └── test_cache_utils.py ├── topologies │ ├── __init__.py │ └── test_dataclass.py ├── research │ ├── se_tasks2 │ │ └── __init__.py │ └── rt_2_1_3 │ │ └── test_l3_conv_topology.py ├── templates │ ├── docs │ │ ├── Stub_Experiment__2019-01-07_08-50-30.html │ │ └── Stub_Experiment__2019-01-07_08-54-26.html │ └── random_number_topology_adapter.py ├── data │ └── datasets │ │ └── testing_dataset │ │ ├── image1.png │ │ ├── image2.bmp │ │ └── image3.jpg ├── test_circular_import_b.py ├── test_circular_import_a.py ├── test_imports.py ├── test_circular_import.py ├── conftest.py ├── benchmarks.py ├── test_testing_utils.py └── test_multiple_inheritance.py ├── torchsim ├── gui │ ├── __init__.py │ ├── observers │ │ └── __init__.py │ └── ui_utils.py ├── utils │ ├── __init__.py │ ├── template_utils │ │ ├── __init__.py │ │ └── train_test_topology_saver.py │ ├── param_utils.py │ ├── os_utils.py │ └── list_utils.py ├── core │ ├── eval │ │ ├── __init__.py │ │ ├── doc_generator │ │ │ ├── __init__.py │ │ │ ├── heading.py │ │ │ ├── document.py │ │ │ └── figure.py │ │ ├── node_accessors │ │ │ ├── __init__.py │ │ │ ├── random_number_accessor.py │ │ │ ├── mnist_node_accessor.py │ │ │ ├── se_node_accessor.py │ │ │ ├── sp_node_accessor.py │ │ │ └── flock_node_accessor.py │ │ ├── metrics │ │ │ ├── mean_squared_error.py │ │ │ ├── cluster_agreement.py │ │ │ ├── entropy.py │ │ │ └── sp_convergence_metrics.py │ │ ├── sliding_window.py │ │ └── topology_adapter_base.py │ ├── eval2 │ │ ├── __init__.py │ │ ├── train_test_switchable.py │ │ ├── experiment_runner_params.py │ │ └── basic_experiment_template.py │ ├── memory │ │ └── __init__.py │ ├── models │ │ ├── __init__.py │ │ ├── receptive_field │ │ │ └── __init__.py │ │ ├── flock │ │ │ ├── __init__.py │ │ │ ├── kernels │ │ │ │ ├── __init__.py │ │ │ │ └── buffer_store.cpp │ │ │ └── flock.py │ │ ├── spatial_pooler │ │ │ ├── __init__.py │ │ │ └── kernels │ │ │ │ ├── __init__.py │ │ │ │ └── sp_processes.cpp │ │ └── temporal_pooler │ │ │ ├── __init__.py │ │ │ ├── process.py │ │ │ ├── kernels │ │ │ └── __init__.py │ │ │ └── buffer.py │ ├── utils │ │ ├── __init__.py │ │ └── image_processing_utilities.py │ ├── datasets │ │ ├── __init__.py │ │ ├── alphabet │ │ │ ├── __init__.py │ │ │ └── 5x5.ttf │ │ └── mnist.py │ ├── persistence │ │ ├── __init__.py │ │ ├── persistable.py │ │ ├── loader.py │ │ ├── persistor.py │ │ └── saver.py │ ├── nodes │ │ ├── internals │ │ │ ├── __init__.py │ │ │ ├── learning_switchable.py │ │ │ └── actions_observable.py │ │ ├── flock_networks │ │ │ ├── __init__.py │ │ │ └── network_factory.py │ │ ├── agent_actions_parser_node.py │ │ ├── constant_node.py │ │ └── periodic_update_node_group.py │ ├── graph │ │ ├── __init__.py │ │ ├── id_generator.py │ │ ├── hierarchical_observable_node.py │ │ ├── inverse_pass_packet.py │ │ └── slot_container.py │ ├── kernels │ │ ├── check_cuda_errors.cu │ │ ├── check_cuda_errors.cpp │ │ ├── kernel_helpers.cpp │ │ └── __init__.py │ ├── physics_model │ │ ├── latent_world.py │ │ └── rendered_world.py │ ├── logging │ │ ├── ui_log_handler.py │ │ ├── log_observable.py │ │ ├── ui │ │ │ └── __init__.py │ │ └── __init__.py │ ├── test_optimizations.py │ ├── exceptions.py │ ├── __init__.py │ ├── model.py │ └── actions.py ├── research │ ├── __init__.py │ ├── se_tasks │ │ ├── __init__.py │ │ ├── adapters │ │ │ ├── __init__.py │ │ │ ├── task_stats_adapter.py │ │ │ ├── task_0_stats_basic_adapter.py │ │ │ └── task_1_stats_basic_adapter.py │ │ ├── experiments │ │ │ ├── __init__.py │ │ │ ├── task_1_experiment_template.py │ │ │ └── all_tasks_experiment.py │ │ └── topologies │ │ │ ├── __init__.py │ │ │ ├── se_io │ │ │ ├── __init__.py │ │ │ └── se_io_task0_dataset_phased.py │ │ │ ├── se_task_topology.py │ │ │ └── se_task0_basic_topology.py │ ├── baselines │ │ └── __init__.py │ ├── se_tasks2 │ │ └── __init__.py │ ├── research_topics │ │ ├── __init__.py │ │ ├── rt_4_2_1_actions │ │ │ ├── __init__.py │ │ │ ├── templates │ │ │ │ └── __init__.py │ │ │ ├── topologies │ │ │ │ └── __init__.py │ │ │ ├── experiments │ │ │ │ └── __init__.py │ │ │ └── node_groups │ │ │ │ ├── __init__.py │ │ │ │ └── single_expert_group.py │ │ ├── rt_1_1_1_one_expert_sp │ │ │ ├── __init__.py │ │ │ ├── adapters │ │ │ │ └── __init__.py │ │ │ ├── experiments │ │ │ │ └── __init__.py │ │ │ └── topologies │ │ │ │ └── __init__.py │ │ ├── rt_2_1_2_learning_rate │ │ │ ├── __init__.py │ │ │ ├── adapters │ │ │ │ ├── __init__.py │ │ │ │ └── modular │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── model_classification_adapter_base.py │ │ │ ├── utils │ │ │ │ └── __init__.py │ │ │ ├── node_groups │ │ │ │ └── __init__.py │ │ │ └── topologies │ │ │ │ └── __init__.py │ │ ├── rt_3_1_lr_subfields │ │ │ ├── __init__.py │ │ │ ├── experiments │ │ │ │ └── __init__.py │ │ │ ├── node_groups │ │ │ │ ├── __init__.py │ │ │ │ └── SFCN_C1_R1.py │ │ │ └── topologies │ │ │ │ └── __init__.py │ │ ├── rt_4_3_1_gradual_world │ │ │ ├── __init__.py │ │ │ ├── nodes │ │ │ │ └── __init__.py │ │ │ └── topologies │ │ │ │ └── __init__.py │ │ ├── rt_1_1_2_one_expert_lrf │ │ │ ├── __init__.py │ │ │ ├── experiments │ │ │ │ └── __init__.py │ │ │ └── topologies │ │ │ │ └── __init__.py │ │ ├── rt_1_1_3_space_benchmarks │ │ │ ├── __init__.py │ │ │ ├── debug │ │ │ │ ├── __init__.py │ │ │ │ └── debug_lrf_runner.py │ │ │ ├── topologies │ │ │ │ ├── __init__.py │ │ │ │ └── se_dataset_sp_lrf.py │ │ │ └── adapters │ │ │ │ ├── se_dataset_ta_running_stats_adapter.py │ │ │ │ └── se_ta_running_stats_adapter.py │ │ ├── rt_1_1_4_task0_experiments │ │ │ ├── __init__.py │ │ │ ├── topologies │ │ │ │ └── __init__.py │ │ │ ├── adapters │ │ │ │ ├── task0_narrow_adapter.py │ │ │ │ ├── task0_basic_adapter.py │ │ │ │ └── task0_conv_wide_adapter.py │ │ │ └── experiments │ │ │ │ └── task_0_conv_more_labels.py │ │ ├── rt_2_1_2_learning_rate2 │ │ │ ├── __init__.py │ │ │ ├── experiments │ │ │ │ └── __init__.py │ │ │ ├── node_groups │ │ │ │ ├── __init__.py │ │ │ │ └── classification_model_group.py │ │ │ └── topologies │ │ │ │ └── __init__.py │ │ ├── rt_2_1_1_relearning │ │ │ └── topologies │ │ │ │ └── __init__.py │ │ ├── rt_3_6_1_inductive_bias_attention │ │ │ ├── __init__.py │ │ │ ├── experiments │ │ │ │ └── __init__.py │ │ │ └── node_groups │ │ │ │ └── __init__.py │ │ ├── rt_3_7_1_task0_analysis │ │ │ ├── experiments │ │ │ │ ├── __init__.py │ │ │ │ └── bat_test.py │ │ │ ├── node_groups │ │ │ │ └── __init__.py │ │ │ └── topologies │ │ │ │ ├── __init__.py │ │ │ │ └── task0_dummy_model_topology.py │ │ ├── rt_3_2_1_symbolic_input_words │ │ │ ├── topologies │ │ │ │ └── __init__.py │ │ │ ├── experiments │ │ │ │ └── ta_symbolic_input_words.py │ │ │ └── templates │ │ │ │ └── symbolic_input_template.py │ │ ├── rt_4_1_1_gradual_learning_basic │ │ │ └── topologies │ │ │ │ └── __init__.py │ │ └── rt_2_1_3_conv_temporal_compression │ │ │ └── topologies │ │ │ ├── __init__.py │ │ │ ├── watch_l_1_topology.py │ │ │ └── watch_l_3_conv_topology.py │ ├── experiment_templates │ │ └── __init__.py │ ├── experiment_templates2 │ │ └── __init__.py │ └── figure_viewer.py ├── topologies │ ├── __init__.py │ ├── random_number_topology.py │ ├── mnist_topology.py │ ├── bouncing_ball_topology.py │ ├── sequence_mnist_topology.py │ ├── sequence_topology.py │ ├── multi_dataset_alphabet_topology.py │ ├── SeDatasetObjectsTopology.py │ ├── toyarch_groups │ │ ├── ncm_group.py │ │ └── r1ncm_group.py │ ├── mse_demo_topology.py │ ├── noise_topology.py │ ├── grid_world_topology.py │ ├── bottom_up_attention_topology.py │ └── switch_topology.py ├── playground │ ├── .ipynb_checkpoints │ │ ├── __init__-checkpoint.py │ │ └── decorator-checkpoint.py │ └── jupyter │ │ └── .ipynb_checkpoints │ │ └── pca-checkpoint.ipynb ├── __init__.py └── significant_nodes │ ├── __init__.py │ ├── reconstruction_interface.py │ └── environment_base.py ├── js ├── src │ ├── wm │ │ └── index.js │ ├── torchsim │ │ ├── exceptions.ts │ │ ├── observers │ │ │ ├── ClusterObserver │ │ │ │ ├── PositionCalculators │ │ │ │ │ └── PositionCalculator.ts │ │ │ │ └── SceneSubjects │ │ │ │ │ ├── SceneSubject.ts │ │ │ │ │ └── AxesHelper.ts │ │ │ ├── TextObserver.tsx │ │ │ ├── ImageObserver.tsx │ │ │ ├── PropertiesObserver.tsx │ │ │ └── Observer.ts │ │ ├── LocalStorageDb.ts │ │ └── components │ │ │ ├── PopupMenu.tsx │ │ │ ├── PopupMenuToggle.tsx │ │ │ ├── ColorTest.tsx │ │ │ └── CheckBox.tsx │ ├── index.tsx │ └── index.html ├── .babelrc ├── README.md ├── build │ ├── e18bbf611f2a2e43afc071aa2f4e1512.ttf │ ├── f4769f9bdb7466be65088239c12046d1.eot │ ├── fa2772327f55d8198301fdb8bcfc8158.woff │ ├── 448c34a56d699c29117adc64c43affeb.woff2 │ └── index.html ├── tsconfig.json └── types.d.ts ├── ui_server.py ├── requirements.txt ├── torch └── cuda │ └── __init__.pyi ├── 3rd-party-licenses └── reactwm-license.txt ├── .gitignore ├── NOTICE └── run_experiment.bat /main_eval.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/gui/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/eval2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/graph/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/gui/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/nodes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/gui/server/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/gui/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/memory/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/eval/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/eval2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/memory/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/gui/observers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/models/flock/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/research/se_tasks2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/persistence/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/gui/observers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/datasets/alphabet/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/datasets/alphabet/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/nodes/internals/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/baselines/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/utils/template_utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/models/receptive_field/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/models/spatial_pooler/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/models/temporal_pooler/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/eval/doc_generator/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/eval/node_accessors/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/models/receptive_field/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/nodes/flock_networks/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/adapters/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/experiment_templates/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/experiment_templates2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/topologies/se_io/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/templates/docs/Stub_Experiment__2019-01-07_08-50-30.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/core/graph/__init__.py: -------------------------------------------------------------------------------- 1 | from .topology import * 2 | -------------------------------------------------------------------------------- /torchsim/core/models/flock/__init__.py: -------------------------------------------------------------------------------- 1 | from .flock import * 2 | -------------------------------------------------------------------------------- /torchsim/playground/.ipynb_checkpoints/__init__-checkpoint.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_2_1_actions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /js/src/wm/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./views/manager'); 2 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_1_one_expert_sp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_1_lr_subfields/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_3_1_gradual_world/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_2_one_expert_lrf/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_3_space_benchmarks/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_4_task0_experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate2/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_2_1_actions/templates/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_2_1_actions/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_1_one_expert_sp/adapters/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_3_space_benchmarks/debug/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_1_relearning/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate/adapters/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_1_lr_subfields/experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_1_lr_subfields/node_groups/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_1_lr_subfields/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_2_1_actions/experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_2_1_actions/node_groups/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_3_1_gradual_world/nodes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /js/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"] 3 | } -------------------------------------------------------------------------------- /js/README.md: -------------------------------------------------------------------------------- 1 | Types file override for ml-matrix https://stackoverflow.com/a/50794250 -------------------------------------------------------------------------------- /torchsim/core/models/spatial_pooler/__init__.py: -------------------------------------------------------------------------------- 1 | from .spatial_pooler import * 2 | -------------------------------------------------------------------------------- /torchsim/core/models/temporal_pooler/__init__.py: -------------------------------------------------------------------------------- 1 | from .temporal_pooler import * 2 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_1_one_expert_sp/experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_1_one_expert_sp/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_2_one_expert_lrf/experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_2_one_expert_lrf/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_3_space_benchmarks/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_4_task0_experiments/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate/node_groups/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate2/experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate2/node_groups/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate2/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_6_1_inductive_bias_attention/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_7_1_task0_analysis/experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_7_1_task0_analysis/node_groups/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_7_1_task0_analysis/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_3_1_gradual_world/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate/adapters/modular/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_2_1_symbolic_input_words/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_1_1_gradual_learning_basic/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_3_conv_temporal_compression/topologies/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_6_1_inductive_bias_attention/experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_6_1_inductive_bias_attention/node_groups/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/core/eval/test_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodAI/torchsim/HEAD/tests/core/eval/test_image.png -------------------------------------------------------------------------------- /torchsim/__init__.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.logging import setup_logging_no_ui 2 | 3 | setup_logging_no_ui() 4 | -------------------------------------------------------------------------------- /torchsim/core/datasets/alphabet/5x5.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodAI/torchsim/HEAD/torchsim/core/datasets/alphabet/5x5.ttf -------------------------------------------------------------------------------- /ui_server.py: -------------------------------------------------------------------------------- 1 | from torchsim.gui.server.server import run_ui_server 2 | 3 | if __name__ == "__main__": 4 | run_ui_server() 5 | -------------------------------------------------------------------------------- /js/build/e18bbf611f2a2e43afc071aa2f4e1512.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodAI/torchsim/HEAD/js/build/e18bbf611f2a2e43afc071aa2f4e1512.ttf -------------------------------------------------------------------------------- /js/build/f4769f9bdb7466be65088239c12046d1.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodAI/torchsim/HEAD/js/build/f4769f9bdb7466be65088239c12046d1.eot -------------------------------------------------------------------------------- /js/build/fa2772327f55d8198301fdb8bcfc8158.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodAI/torchsim/HEAD/js/build/fa2772327f55d8198301fdb8bcfc8158.woff -------------------------------------------------------------------------------- /tests/data/datasets/testing_dataset/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodAI/torchsim/HEAD/tests/data/datasets/testing_dataset/image1.png -------------------------------------------------------------------------------- /tests/data/datasets/testing_dataset/image2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodAI/torchsim/HEAD/tests/data/datasets/testing_dataset/image2.bmp -------------------------------------------------------------------------------- /tests/data/datasets/testing_dataset/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodAI/torchsim/HEAD/tests/data/datasets/testing_dataset/image3.jpg -------------------------------------------------------------------------------- /js/build/448c34a56d699c29117adc64c43affeb.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoodAI/torchsim/HEAD/js/build/448c34a56d699c29117adc64c43affeb.woff2 -------------------------------------------------------------------------------- /js/src/torchsim/exceptions.ts: -------------------------------------------------------------------------------- 1 | export class InvalidStateException extends Error { 2 | } 3 | export class InvalidArgumentException extends Error { 4 | } 5 | 6 | -------------------------------------------------------------------------------- /torchsim/core/kernels/check_cuda_errors.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int get_cuda_error_code() 5 | { 6 | return (int) cudaGetLastError(); 7 | } 8 | -------------------------------------------------------------------------------- /torchsim/core/graph/id_generator.py: -------------------------------------------------------------------------------- 1 | class IdGenerator: 2 | _last_node_id: int = 0 3 | 4 | def next_node_id(self): 5 | self._last_node_id += 1 6 | return self._last_node_id 7 | -------------------------------------------------------------------------------- /tests/test_circular_import_b.py: -------------------------------------------------------------------------------- 1 | import tests.test_circular_import_a 2 | 3 | 4 | class Circular_B: 5 | def is_a(self, obj): 6 | return isinstance(obj, tests.test_circular_import_a.Circular_A) 7 | -------------------------------------------------------------------------------- /torchsim/core/kernels/check_cuda_errors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int get_cuda_error_code(); 4 | 5 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) 6 | { 7 | m.def("get_cuda_error_code", &get_cuda_error_code, "Get last CUDA error"); 8 | } 9 | -------------------------------------------------------------------------------- /torchsim/core/models/flock/kernels/__init__.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.kernels import load_kernels 2 | 3 | buffer_kernels = load_kernels(__file__, 'buffer_store', ['buffer_store.cpp', 4 | 'buffer_store.cu']) 5 | -------------------------------------------------------------------------------- /tests/research/rt_2_1_3/test_l3_conv_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.research_topics.rt_2_1_3_conv_temporal_compression.topologies.l3_conv_topology import L3ConvTopology 2 | 3 | 4 | def test_l3_conv_topology(): 5 | t = L3ConvTopology() 6 | t.step() 7 | -------------------------------------------------------------------------------- /torchsim/core/eval/metrics/mean_squared_error.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | def mse_loss(input: torch.Tensor, reconstruction: torch.Tensor) -> torch.Tensor: 5 | # noinspection PyUnresolvedReferences 6 | return torch.nn.functional.mse_loss(input, reconstruction) 7 | -------------------------------------------------------------------------------- /js/src/torchsim/observers/ClusterObserver/PositionCalculators/PositionCalculator.ts: -------------------------------------------------------------------------------- 1 | import { Vector3 } from 'three'; 2 | import { DataProvider } from '../Helpers/DataProvider'; 3 | 4 | export interface PositionCalculator { 5 | update(dataProvider: DataProvider): Vector3[]; 6 | } -------------------------------------------------------------------------------- /torchsim/core/models/temporal_pooler/process.py: -------------------------------------------------------------------------------- 1 | from abc import ABC 2 | 3 | from torchsim.core.models.flock.process import Process 4 | 5 | 6 | class TPProcess(Process, ABC): 7 | """This is here only for code organization purposes (to match the structure of SPProcess-es).""" 8 | pass 9 | -------------------------------------------------------------------------------- /torchsim/utils/param_utils.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import NamedTuple 3 | 4 | 5 | # TODO convert to @dataclass 6 | class Size2D(NamedTuple): 7 | height: int 8 | width: int 9 | 10 | 11 | @dataclass 12 | class Point2D: 13 | y: int 14 | x: int 15 | -------------------------------------------------------------------------------- /torchsim/core/kernels/kernel_helpers.cpp: -------------------------------------------------------------------------------- 1 | #include "kernel_helpers.h" 2 | 3 | #include 4 | 5 | 6 | cudaStream_t set_device_get_cuda_stream(int device) { 7 | at::cuda::set_device(device); 8 | return at::cuda::getCurrentCUDAStream(device).stream(); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tests/test_circular_import_a.py: -------------------------------------------------------------------------------- 1 | # import tests.test_circular_import_b 2 | from tests.test_circular_import_b import Circular_B 3 | 4 | 5 | class Circular_A: 6 | def is_b(self, obj): 7 | return isinstance(obj, Circular_B) 8 | # return isinstance(obj, tests.test_circular_import_b.Circular_B) 9 | -------------------------------------------------------------------------------- /torchsim/core/models/spatial_pooler/kernels/__init__.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.kernels import load_kernels 2 | 3 | 4 | sp_process_kernels = load_kernels(__file__, 'sp_processes_kernels', ['sp_processes.cpp', 5 | 'compute_squared_distances.cu']) 6 | -------------------------------------------------------------------------------- /tests/test_imports.py: -------------------------------------------------------------------------------- 1 | from importlib import import_module 2 | 3 | 4 | def test_main_py(): 5 | import_module('main') 6 | 7 | def test_main_expert_flock_profiling_py(): 8 | import_module('main_expert_flock_profiling') 9 | 10 | 11 | # TODO add imports of files under research_topics/*/experiments/* 12 | 13 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/experiments/task_1_experiment_template.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.se_tasks.experiments.task_0_experiment_template import Task0ExperimentTemplate 2 | 3 | 4 | class Task1ExperimentTemplate(Task0ExperimentTemplate): 5 | """Just inherits all the behavior from Task0ExperimentTemplate.""" 6 | pass 7 | -------------------------------------------------------------------------------- /torchsim/core/physics_model/latent_world.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | class LatentWorld: 5 | def __init__(self, **kwargs): 6 | pass 7 | 8 | @staticmethod 9 | def to_tensor(instances): 10 | instances = [instance.to_tensor() for instance in instances] 11 | return torch.stack(instances) 12 | -------------------------------------------------------------------------------- /torchsim/core/nodes/internals/learning_switchable.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod, ABC 2 | 3 | 4 | class LearningSwitchable(ABC): 5 | @abstractmethod 6 | def switch_learning(self, learning_on: bool): 7 | pass 8 | 9 | 10 | class TestingSwitcher(ABC): 11 | @abstractmethod 12 | def is_learning(self) -> bool: 13 | pass 14 | -------------------------------------------------------------------------------- /torchsim/core/eval/doc_generator/heading.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.eval.doc_generator.element import XmlElement 2 | 3 | 4 | class Heading(XmlElement): 5 | _text: str 6 | 7 | def __init__(self, text: str, level: int = 1): 8 | super().__init__(f'h{level}') 9 | self._text = text 10 | 11 | def text(self): 12 | return self._text 13 | -------------------------------------------------------------------------------- /js/src/index.tsx: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import * as React from "react"; 3 | import * as ReactDOM from "react-dom"; 4 | 5 | import {App} from "./torchsim/App"; 6 | 7 | import '../css/wm.scss' 8 | import '../css/styles.scss' 9 | 10 | const wrapper = document.getElementById("app"); 11 | wrapper ? ReactDOM.render(, wrapper) : false; 12 | 13 | console.log("UI App started"); 14 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | websocket-client 2 | six 3 | Pillow 4 | tornado 5 | PyQt5 6 | numpy 7 | torchvision 8 | matplotlib 9 | scikit-learn 10 | scikit-image 11 | pytest 12 | pytest-mock 13 | scipy 14 | ninja 15 | typing_inspect 16 | tqdm 17 | ruamel.yaml 18 | zmq 19 | gym 20 | networkx 21 | opencv-python 22 | pytest-rerunfailures 23 | prettytable 24 | dacite 25 | pygame 26 | pymunk 27 | colour -------------------------------------------------------------------------------- /torchsim/core/eval/sliding_window.py: -------------------------------------------------------------------------------- 1 | from itertools import islice 2 | 3 | 4 | def sliding_window(seq, n=2): 5 | """Returns a sliding window (of width n) over data.""" 6 | it = iter(seq) 7 | result = tuple(islice(it, n)) 8 | if len(result) == n: 9 | yield result 10 | for elem in it: 11 | result = result[1:] + (elem,) 12 | yield result 13 | -------------------------------------------------------------------------------- /js/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | TorchSim 8 | 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /js/src/torchsim/observers/ClusterObserver/SceneSubjects/SceneSubject.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three'; 2 | import { ClusterObserverData } from '../../ClusterObserver'; 3 | import { DataProvider } from '../Helpers/DataProvider'; 4 | 5 | export interface SceneSubject { 6 | readonly sceneObject: THREE.Object3D; 7 | update(clusterPositions: THREE.Vector3[], dataProvider: DataProvider); 8 | } -------------------------------------------------------------------------------- /torchsim/significant_nodes/__init__.py: -------------------------------------------------------------------------------- 1 | from torchsim.significant_nodes.ball_env import BallEnvironment, BallEnvironmentParams 2 | from torchsim.significant_nodes.space_engineers_env import SEEnvironment, SeEnvironmentParams 3 | from torchsim.significant_nodes.conv_layer import ConvLayer, SpConvLayer 4 | from torchsim.significant_nodes.sp_reconstruction_layer import SpReconstructionLayer 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/core/eval/test_cluster_agreement.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import torch 3 | 4 | from torchsim.core.eval.metrics.cluster_agreement import cluster_agreement 5 | 6 | 7 | def test_cluster_agreement(): 8 | cluster_ids_1 = torch.tensor([0, 0, 1, 1, 0, 3, 5, 3, 2, 9]) 9 | cluster_ids_2 = torch.tensor([0, 23, 33, 1, 3, 3, 0, 3, 9, 0]) 10 | assert cluster_agreement(cluster_ids_1, cluster_ids_2) == .4 11 | -------------------------------------------------------------------------------- /torchsim/core/persistence/persistable.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | from torchsim.core.persistence.loader import Loader 4 | from torchsim.core.persistence.saver import Saver 5 | 6 | 7 | class Persistable(ABC): 8 | @abstractmethod 9 | def save(self, parent_saver: Saver): 10 | pass 11 | 12 | @abstractmethod 13 | def load(self, parent_loader: Loader): 14 | pass 15 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_7_1_task0_analysis/experiments/bat_test.py: -------------------------------------------------------------------------------- 1 | import random 2 | import sys 3 | 4 | from eval_utils import parse_test_args 5 | 6 | if __name__ == '__main__': 7 | arg = parse_test_args() 8 | 9 | print(f'---------------- arguments are {arg}') 10 | 11 | return_val = random.randint(0, 10) 12 | print(f'return value {return_val}') 13 | 14 | sys.exit(return_val) 15 | 16 | -------------------------------------------------------------------------------- /tests/test_circular_import.py: -------------------------------------------------------------------------------- 1 | from tests.test_circular_import_a import Circular_A 2 | from tests.test_circular_import_b import Circular_B 3 | 4 | 5 | class TestCircularImport: 6 | def test_circular_import(self): 7 | a = Circular_A() 8 | b = Circular_B() 9 | assert True is a.is_b(b) 10 | assert True is b.is_a(a) 11 | assert False is b.is_a(b) 12 | assert False is a.is_b(a) 13 | -------------------------------------------------------------------------------- /torchsim/topologies/random_number_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.nodes.random_number_node import RandomNumberNode 2 | from torchsim.core.graph import Topology 3 | 4 | 5 | class RandomNumberTopology(Topology): 6 | 7 | def __init__(self): 8 | super().__init__(device='cuda') 9 | 10 | self.random_number_node = RandomNumberNode(upper_bound=10, seed=None) 11 | self.add_node(self.random_number_node) 12 | 13 | -------------------------------------------------------------------------------- /js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "sourceMap": true, 5 | "noImplicitAny": false, 6 | "module": "commonjs", 7 | "target": "es5", 8 | "jsx": "react", 9 | "lib": ["es5", "es6", "dom","es2015", "es2017", "es2015.promise", "scripthost"], 10 | "types": [ 11 | "webpack-env" 12 | ] 13 | }, 14 | "include": [ 15 | "./src/**/*", 16 | "types.d.ts" 17 | ] 18 | } -------------------------------------------------------------------------------- /torchsim/core/logging/ui_log_handler.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from torchsim.core.logging.log_observable import LogObservable 4 | 5 | 6 | class UILogHandler(logging.Handler): 7 | def __init__(self, log_observable: LogObservable, level=logging.NOTSET): 8 | super().__init__(level) 9 | self._log_observable = log_observable 10 | 11 | def emit(self, record): 12 | self._log_observable.log(self.format(record)) 13 | -------------------------------------------------------------------------------- /torchsim/topologies/mnist_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.nodes.dataset_mnist_node import DatasetMNISTParams, DatasetMNISTNode 2 | from torchsim.core.graph import Topology 3 | 4 | 5 | class MnistTopology(Topology): 6 | 7 | _params: DatasetMNISTParams = DatasetMNISTParams() 8 | 9 | def __init__(self): 10 | super().__init__(device='cpu') 11 | 12 | node = DatasetMNISTNode(params=self._params) 13 | self.add_node(node) 14 | -------------------------------------------------------------------------------- /torchsim/core/eval2/train_test_switchable.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | 3 | from torchsim.core.persistence.persistable import Persistable 4 | 5 | 6 | class TrainTestSwitchable(Persistable): 7 | """A base class for topological topologies which allow for train/test mode switching.""" 8 | @abstractmethod 9 | def switch_to_training(self): 10 | pass 11 | 12 | @abstractmethod 13 | def switch_to_testing(self): 14 | pass 15 | -------------------------------------------------------------------------------- /js/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | TorchSim 8 | 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /torchsim/core/eval/node_accessors/random_number_accessor.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.nodes.random_number_node import RandomNumberNode 4 | 5 | 6 | class RandomNumberNodeAccessor: 7 | 8 | @staticmethod 9 | def get_output_id(node: RandomNumberNode) -> int: 10 | return node._unit._current_value.item() 11 | 12 | @staticmethod 13 | def get_output_tensor(node: RandomNumberNode) -> torch.Tensor: 14 | return node.outputs.one_hot_output.tensor 15 | -------------------------------------------------------------------------------- /torchsim/playground/jupyter/.ipynb_checkpoints/pca-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [] 9 | } 10 | ], 11 | "metadata": { 12 | "kernelspec": { 13 | "display_name": "Python 3", 14 | "language": "python", 15 | "name": "python3" 16 | }, 17 | "language_info": { 18 | "name": "" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2 23 | } 24 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_4_task0_experiments/adapters/task0_narrow_adapter.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.research_topics.rt_1_1_4_task0_experiments.adapters.task0_adapter_base import Task0AdapterBase 2 | 3 | 4 | class Task0NarrowAdapter(Task0AdapterBase): 5 | 6 | def is_output_id_available_for(self, layer_id: int) -> bool: 7 | """All the topology has flock_size=1""" 8 | return True 9 | 10 | def get_title(self) -> str: 11 | return 'T0 - Narrow hierarchy' 12 | 13 | -------------------------------------------------------------------------------- /js/src/torchsim/observers/TextObserver.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | export interface TextObserverProps { 4 | data: string; 5 | } 6 | 7 | 8 | export class TextObserver extends React.Component { 9 | constructor(props: TextObserverProps) { 10 | super(props); 11 | } 12 | 13 | render() { 14 | const content = this.props.data; 15 | return ( 16 |
17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /torchsim/core/test_optimizations.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | 5 | def small_dataset_for_tests_allowed(): 6 | use_small_datasets_string = 'USE_SMALL_DATASETS' 7 | if use_small_datasets_string not in os.environ: 8 | return False 9 | 10 | if os.environ[use_small_datasets_string] and 'pytest' not in sys.modules.keys(): 11 | raise AssertionError('USE_SMALL_DATASETS is set in non-testing setting') 12 | 13 | return True if os.environ[use_small_datasets_string] != '0' else False 14 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_4_task0_experiments/adapters/task0_basic_adapter.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.research_topics.rt_1_1_4_task0_experiments.adapters.task0_adapter_base import Task0AdapterBase 2 | 3 | 4 | class Task0BasicAdapter(Task0AdapterBase): 5 | 6 | def get_title(self) -> str: 7 | return 'T0 - Basic topology' 8 | 9 | def is_output_id_available_for(self, layer_id: int) -> bool: 10 | """Expects that all expert flocks have flock_size=1""" 11 | return True 12 | -------------------------------------------------------------------------------- /torchsim/significant_nodes/reconstruction_interface.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.graph.node_group import GroupInputs, GroupOutputs 2 | 3 | 4 | class ClassificationInputs(GroupInputs): 5 | def __init__(self, owner): 6 | super().__init__(owner) 7 | self.data = self.create("Data") 8 | self.label = self.create("Label") 9 | 10 | 11 | class ClassificationOutputs(GroupOutputs): 12 | def __init__(self, owner): 13 | super().__init__(owner) 14 | self.label = self.create("Label") 15 | -------------------------------------------------------------------------------- /torchsim/gui/ui_utils.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | import torch 4 | from PIL import Image 5 | from six import BytesIO 6 | import base64 as b64 7 | 8 | 9 | def parse_bool(value: Union[str, bool]): 10 | return value == 'True' or value is True 11 | 12 | 13 | def encode_image(tensor: torch.Tensor): 14 | image = (tensor * 255).byte().to("cpu").numpy() 15 | im = Image.fromarray(image) 16 | buf = BytesIO() 17 | im.save(buf, format='PNG') 18 | return b64.b64encode(buf.getvalue()).decode('utf-8') 19 | -------------------------------------------------------------------------------- /tests/utils/test_os_utils.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from torchsim.utils.os_utils import project_root_dir 4 | 5 | 6 | def test_project_root_dir(): 7 | path = Path(project_root_dir()) 8 | main = path / 'main.py' 9 | torchsim = path / 'torchsim' 10 | tests = path / 'tests' 11 | assert True is main.exists() 12 | assert True is main.is_file() 13 | assert True is torchsim.exists() 14 | assert True is torchsim.is_dir() 15 | assert True is tests.exists() 16 | assert True is tests.is_dir() 17 | -------------------------------------------------------------------------------- /torchsim/topologies/bouncing_ball_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.nodes import SimpleBouncingBallNode 2 | from torchsim.core.graph import Topology 3 | from torchsim.core.nodes.simple_bouncing_ball_node import SimpleBouncingBallNodeParams 4 | 5 | 6 | class BouncingBallTopology(Topology): 7 | 8 | def __init__(self): 9 | super().__init__(device='cpu') 10 | 11 | # Just the Bouncing ball node 12 | params = SimpleBouncingBallNodeParams() 13 | self.add_node(SimpleBouncingBallNode(params=params)) 14 | 15 | -------------------------------------------------------------------------------- /js/types.d.ts: -------------------------------------------------------------------------------- 1 | // Temporary workaround to load untyped JS libraries (https://stackoverflow.com/a/50516783/2203164) 2 | // declare module '*'; 3 | 4 | interface Collection { } 5 | 6 | interface List extends Collection { 7 | [index: number]: T; 8 | length: number; 9 | } 10 | 11 | interface Dictionary extends Collection { 12 | [index: string]: T; 13 | } 14 | 15 | declare module 'worker-loader!*' { 16 | class WebpackWorker extends Worker { 17 | constructor(); 18 | } 19 | 20 | export = WebpackWorker; 21 | } -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def pytest_addoption(parser): 5 | parser.addoption( 6 | '--skip-slow', action='store', default=False 7 | ) 8 | 9 | 10 | def pytest_collection_modifyitems(config, items): 11 | if not config.getoption('--skip-slow'): 12 | return 13 | 14 | skip_slow = pytest.mark.skip(reason='This test is slow, run the tests with --skip-slow if you want to skip it') 15 | for item in items: 16 | if 'slow' in item.keywords: 17 | item.add_marker(skip_slow) 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/core/datasets/alphabet/test_alphabet_generator.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.datasets.alphabet.alphabet import AlphabetGenerator 2 | 3 | 4 | class TestAlphabetGenerator: 5 | def test_create_symbols(self): 6 | generator = AlphabetGenerator() 7 | result = generator.create_symbols('A:"') 8 | assert [3, 7, 5] == list(result.shape) 9 | # Check that result is composed just of zeros and ones 10 | zeros = (result == 0).nonzero().shape[0] 11 | ones = (result == 1).nonzero().shape[0] 12 | assert result.numel() == zeros + ones 13 | -------------------------------------------------------------------------------- /torchsim/core/eval/node_accessors/mnist_node_accessor.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.nodes.dataset_mnist_node import DatasetMNISTNode 4 | 5 | 6 | class MnistNodeAccessor: 7 | """Adaptor for the MNIST Node allowing access to the basic measurable values.""" 8 | 9 | @staticmethod 10 | def get_data(node: DatasetMNISTNode) -> torch.Tensor: 11 | return node.outputs.data.tensor.clone() 12 | 13 | @staticmethod 14 | def get_label_id(node: DatasetMNISTNode) -> int: 15 | """Get the label id of the current bitmap.""" 16 | return node._unit.label_tensor.to('cpu').item() 17 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/experiments/all_tasks_experiment.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.se_tasks.experiments.task_0_experiment import run_measurements_for_task0 2 | from torchsim.research.se_tasks.experiments.task_1_experiment import run_measurements_for_task1 3 | 4 | if __name__ == '__main__': 5 | """Runs the listed experiments.""" 6 | 7 | custom_task_durations = True 8 | 9 | # ######### TASK 0 ########### 10 | run_measurements_for_task0(custom_durations=custom_task_durations) 11 | 12 | # ######### TASK 1 ########### 13 | run_measurements_for_task1(custom_durations=custom_task_durations) 14 | -------------------------------------------------------------------------------- /torchsim/topologies/sequence_mnist_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.nodes import DatasetMNISTParams, DatasetSequenceMNISTNodeParams, DatasetSequenceMNISTNode 2 | from torchsim.core.graph import Topology 3 | 4 | 5 | class SequenceMnistTopology(Topology): 6 | 7 | _seq_params: DatasetSequenceMNISTNodeParams = DatasetSequenceMNISTNodeParams([[1, 2, 3]]) 8 | _params: DatasetMNISTParams = DatasetMNISTParams() 9 | 10 | def __init__(self): 11 | super().__init__('cpu') 12 | 13 | node = DatasetSequenceMNISTNode(params=self._params, seq_params=self._seq_params) 14 | self.add_node(node) 15 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_3_conv_temporal_compression/topologies/watch_l_1_topology.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from eval_utils import run_just_model 4 | from torchsim.research.research_topics.rt_2_1_3_conv_temporal_compression.topologies.l1_topology import L1Topology 5 | 6 | if __name__ == "__main__": 7 | parser = ArgumentParser() 8 | parser.add_argument("--persisting-observer-system", default=False, action='store_true') 9 | args = parser.parse_args() 10 | t = L1Topology() 11 | run_just_model(model=t, gui=True, persisting_observer_system=args.persisting_observer_system) 12 | -------------------------------------------------------------------------------- /torchsim/topologies/sequence_topology.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from torchsim.core.nodes import SequenceNode 4 | from torchsim.core.graph import Topology 5 | from torchsim.core.utils.sequence_generator import SequenceGenerator 6 | 7 | 8 | class SequenceTopology(Topology): 9 | """Super simple model for testing seqs. 10 | 11 | A minimal model for testing seqs. 12 | """ 13 | def __init__(self): 14 | super().__init__(device='cpu') 15 | generator = SequenceGenerator([[1, 2, 3], [4, 5, 6]], np.array([0.5, 0.5])) 16 | seq_node = SequenceNode(generator) 17 | 18 | self.add_node(seq_node) 19 | -------------------------------------------------------------------------------- /tests/core/eval/test_entropy.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | import torch 4 | 5 | from torchsim.core.eval.metrics.entropy import one_hot_entropy 6 | 7 | 8 | def test_one_hot_entropy(): 9 | n_samples, n_components, n_elements = 10, 5, 8 10 | data = torch.zeros(n_samples, n_components, n_elements) 11 | for sample in range(n_samples): 12 | for component in range(n_components): 13 | if 0 <= component <= 1: # entropy == 0 14 | data[sample, component, 0] = 1 15 | else: # entropy == 1 16 | data[sample, component, sample % 2] = 1 17 | assert one_hot_entropy(data) == 3 18 | 19 | -------------------------------------------------------------------------------- /js/src/torchsim/observers/ClusterObserver/SceneSubjects/AxesHelper.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three'; 2 | import { DataProvider } from '../Helpers/DataProvider'; 3 | import { SceneSubject } from './SceneSubject'; 4 | 5 | export class AxesHelper implements SceneSubject { 6 | private axesHelper: THREE.AxesHelper; 7 | 8 | constructor() { 9 | const size = 10; 10 | this.axesHelper = new THREE.AxesHelper(size); 11 | } 12 | 13 | public get sceneObject(): THREE.Object3D { 14 | return this.axesHelper; 15 | } 16 | 17 | public update = (clusterPositions: THREE.Vector3[], dataProvider: DataProvider) => { 18 | }; 19 | } -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_4_task0_experiments/adapters/task0_conv_wide_adapter.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.research_topics.rt_1_1_4_task0_experiments.adapters.task0_adapter_base import Task0AdapterBase 2 | 3 | 4 | class Task0ConvWideAdapter(Task0AdapterBase): 5 | 6 | def is_output_id_available_for(self, layer_id: int) -> bool: 7 | """Means that we cannot obtain SPOutput id from the layer 0 (since it has flock_size>1)""" 8 | # TODO template design drawback (topology not instantiated during call of this method) 9 | return layer_id > 0 10 | 11 | def get_title(self) -> str: 12 | return 'T0 - conv wide hierarchy' 13 | 14 | -------------------------------------------------------------------------------- /torchsim/core/logging/log_observable.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | 3 | from torchsim.gui.observer_system import TextObservable 4 | 5 | 6 | class LogObservable(TextObservable): 7 | text: str = "" 8 | 9 | def get_data(self): 10 | return self.text 11 | 12 | def log(self, line: str): 13 | self.text += line + '
' # os.linesep 14 | 15 | def log_last_exception(self): 16 | message = traceback.format_exc() 17 | html = f""" 18 |
19 |

Exception thrown:

20 |
{message}
21 |
22 | """ 23 | self.log(html) 24 | -------------------------------------------------------------------------------- /torchsim/core/models/flock/kernels/buffer_store.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // forward declaration for func in .cu file 4 | void buffer_store(at::Tensor destination, 5 | at::Tensor flock_indices, 6 | at::Tensor buffer_ptr_indices, 7 | at::Tensor src, 8 | int data_size, 9 | int flock_size); 10 | 11 | 12 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) 13 | { 14 | m.doc() = "Buffer store kernel"; // optional module docstring 15 | m.def("buffer_store", &buffer_store, "Scatters inputs to the destination buffers at destination[flock_indices, buffer_ptr_indices]"); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /torchsim/core/utils/image_processing_utilities.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | class ImageProcessingUtilities: 5 | 6 | @staticmethod 7 | def rgb_to_grayscale(tensor: torch.Tensor, squeeze_channel: bool): 8 | """conversion to luminance from RGB 9 | 10 | https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color """ 11 | (r, g, b) = torch.chunk(tensor, 3, -1) # chunk to 3 channels along the last dimension 12 | luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b 13 | if squeeze_channel: 14 | luminance = luminance.squeeze(-1) # remove the last dimension, which is just a 1 15 | 16 | return luminance 17 | -------------------------------------------------------------------------------- /torchsim/core/exceptions.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar, Generic 2 | 3 | 4 | class NetworkProtocolException(Exception): 5 | pass 6 | 7 | 8 | class IllegalArgumentException(Exception): 9 | pass 10 | 11 | 12 | class FailedValidationException(IllegalArgumentException): 13 | pass 14 | 15 | 16 | class IllegalStateException(Exception): 17 | pass 18 | 19 | 20 | class ShouldNotBeCalledException(Exception): 21 | pass 22 | 23 | 24 | class TensorNotSetException(Exception): 25 | pass 26 | 27 | 28 | T = TypeVar('T') 29 | 30 | 31 | class PrivateConstructorException(Exception, Generic[T]): 32 | instance: T 33 | 34 | def __init__(self, instance: T): 35 | self.instance = instance 36 | -------------------------------------------------------------------------------- /torchsim/core/models/temporal_pooler/kernels/__init__.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.kernels import load_kernels 2 | 3 | 4 | tp_process_kernels = load_kernels(__file__, 'tp_processes_kernels', ['tp_processes.cpp', 5 | 'count_batch_seq_occurrences.cu', 6 | 'identify_new_seqs.cu', 7 | 'count_unique_seqs.cu', 8 | 'compute_seq_likelihoods_clusters_only.cu', 9 | 'discount_rewards_iterative.cu']) 10 | -------------------------------------------------------------------------------- /js/src/torchsim/LocalStorageDb.ts: -------------------------------------------------------------------------------- 1 | import {WindowPosition} from "./ServerConnector"; 2 | 3 | export class LocalStorageDb { 4 | private static getObject(id: string): Object { 5 | return JSON.parse(localStorage.getItem(id) || '{}'); 6 | } 7 | 8 | static getWindowPosition(win_id: string): WindowPosition | undefined { 9 | let positions = this.getObject('positions'); 10 | return positions[win_id]; 11 | } 12 | 13 | static setWindowPosition(win_id: string, position: WindowPosition) { 14 | let positions = JSON.parse(localStorage.getItem('positions') || '{}'); 15 | positions[win_id] = position; 16 | localStorage.setItem('positions', JSON.stringify(positions)); 17 | } 18 | } -------------------------------------------------------------------------------- /js/src/torchsim/observers/ImageObserver.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import {ObserverProps, ObserverUtils} from "./Observer"; 3 | 4 | export interface ImageObserverProps extends ObserverProps { 5 | data: { 6 | src: string 7 | } 8 | } 9 | 10 | export class ImageObserver extends React.Component { 11 | observerUtils = new ObserverUtils(this); 12 | 13 | constructor(props: ImageObserverProps) { 14 | super(props); 15 | } 16 | 17 | render() { 18 | this.observerUtils.onRender(); 19 | return ( 20 | this.observerUtils.setContentRef(element)} 22 | /> 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/templates/docs/Stub_Experiment__2019-01-07_08-54-26.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Template: DocumentPublisher
5 | topology: TopologyStub
6 | Experiment_name: Stub Experiment
7 | Date: 2019-01-07_08-54-26

8 | List of common parameters:
Param nameParam value
device
param42
9 |
Template configuration:
Param nameParam value
max_steps3
10 | 11 | -------------------------------------------------------------------------------- /js/src/torchsim/components/PopupMenu.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as classNames from 'classnames'; 3 | 4 | 5 | interface PopupMenuProps { 6 | bsRole: string; 7 | className?: string; 8 | } 9 | 10 | interface PopupMenuState { 11 | } 12 | 13 | export class PopupMenu extends React.Component { 14 | state: PopupMenuState; 15 | 16 | constructor(props: PopupMenuProps) { 17 | super(props); 18 | this.state = { 19 | }; 20 | } 21 | 22 | render() { 23 | let classes = classNames("dropdown-menu open", this.props.className); 24 | return ( 25 |
    26 | {this.props.children} 27 |
28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /js/src/torchsim/components/PopupMenuToggle.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from 'react-dom'; 3 | 4 | 5 | interface PopupMenuToggleProps { 6 | bsRole: string; 7 | className?: string; 8 | onClick?: () => void; 9 | } 10 | 11 | interface PopupMenuToggleState { 12 | } 13 | 14 | export class PopupMenuToggle extends React.Component { 15 | state: PopupMenuToggleState; 16 | 17 | constructor(props: PopupMenuToggleProps) { 18 | super(props); 19 | this.state = { 20 | }; 21 | } 22 | 23 | render() { 24 | return ( 25 | this.props.onClick()}> 26 | {this.props.children} 27 | 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /torchsim/core/logging/ui/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from torchsim.core.logging.ui_log_handler import UILogHandler 3 | from torchsim.core.logging.log_observable import LogObservable 4 | 5 | from torchsim.core.logging import _default_log_file, _get_file_handler, _get_console_handler, _setup_logging 6 | from torchsim.gui.observer_system import ObserverSystem 7 | 8 | 9 | def setup_logging_ui(observable: LogObservable, observer_system: ObserverSystem, filename: Optional[str] = None): 10 | filename = filename or _default_log_file 11 | file_handler = _get_file_handler(filename) 12 | console_handler = _get_console_handler() 13 | _setup_logging([UILogHandler(observable), file_handler, console_handler]) 14 | observer_system.register_observer('Log', observable) -------------------------------------------------------------------------------- /tests/core/graph/test_unit.py: -------------------------------------------------------------------------------- 1 | from tempfile import TemporaryDirectory 2 | 3 | from torchsim.core.memory.tensor_creator import AllocatingCreator 4 | from torchsim.core.persistence.loader import Loader 5 | from torchsim.core.persistence.saver import Saver 6 | from torchsim.core.utils.tensor_utils import same 7 | from tests.core.graph.node_stub import RandomUnitStub 8 | 9 | 10 | def test_save_load(): 11 | creator = AllocatingCreator('cpu') 12 | 13 | unit = RandomUnitStub(creator) 14 | unit2 = RandomUnitStub(creator) 15 | 16 | with TemporaryDirectory() as folder: 17 | saver = Saver(folder) 18 | unit.save(saver) 19 | saver.save() 20 | 21 | loader = Loader(folder) 22 | unit2.load(loader) 23 | 24 | assert same(unit.output, unit2.output) 25 | -------------------------------------------------------------------------------- /tests/gui/test_observer_view.py: -------------------------------------------------------------------------------- 1 | 2 | import pytest 3 | 4 | from torchsim.gui.observer_system import Observable 5 | from torchsim.gui.observer_view import ObserverView 6 | from unittest.mock import MagicMock 7 | 8 | 9 | @pytest.mark.parametrize("name, expected_name", [ 10 | ('pref.header.one', 'one'), 11 | ('header.two', 'two'), 12 | ('name.header.pref.', 'header.pref.'), 13 | ]) 14 | def test_strip_observer_name_prefix(mocker, name: str, expected_name: str): 15 | observer_system: MagicMock = mocker.Mock() 16 | observer_view = ObserverView("test view", observer_system, "pref.") 17 | observer_view.set_observables({ 18 | name: Observable(), 19 | }) 20 | names = list(map(lambda i: i.name, observer_view.get_properties())) 21 | assert expected_name in names 22 | -------------------------------------------------------------------------------- /torchsim/utils/os_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | import traceback 4 | from pathlib import Path 5 | 6 | 7 | def create_dir(path): 8 | if os.path.isdir(path): 9 | return 10 | 11 | os.makedirs(path) 12 | 13 | 14 | def create_temp_dir(subdir: str): 15 | new_dir = os.path.join(tempfile.gettempdir(), subdir) 16 | create_dir(new_dir) 17 | return new_dir 18 | 19 | 20 | def last_exception_as_html(): 21 | message = traceback.format_exc() 22 | html = f""" 23 |
24 |

Exception thrown:

25 |
{message}
26 |
27 | """ 28 | return html 29 | 30 | 31 | def project_root_dir() -> str: 32 | return str(Path(__file__).parent.parent.parent.absolute()) 33 | -------------------------------------------------------------------------------- /torchsim/core/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | import numpy 5 | import torch 6 | 7 | FLOAT_TYPE_CUDA = torch.float32 8 | FLOAT_TYPE_CPU = torch.float32 9 | FLOAT_TYPE_NUMPY = numpy.float32 10 | 11 | # For use with half precision floats, 1e-4 would be too small 12 | if FLOAT_TYPE_CUDA == torch.float16: 13 | SMALL_CONSTANT = 1e-3 14 | else: 15 | SMALL_CONSTANT = 1e-4 16 | 17 | FLOAT_NAN = float('nan') 18 | FLOAT_INF = float('inf') 19 | FLOAT_NEG_INF = float('-inf') 20 | 21 | on_windows = sys.platform == "Windows" or sys.platform == "win32" 22 | SHARED_DRIVE = '\\\\goodai.com/GoodAI/' if on_windows else os.path.expanduser("~/goodai.com/") 23 | 24 | 25 | def get_float(device) -> torch.dtype: 26 | if device == 'cuda': 27 | return FLOAT_TYPE_CUDA 28 | return FLOAT_TYPE_CPU 29 | -------------------------------------------------------------------------------- /torchsim/core/models/spatial_pooler/kernels/sp_processes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // forward declaration for func in .cu file 4 | void compute_squared_distances(at::Tensor data, 5 | at::Tensor cluster_centers, 6 | at::Tensor distances, 7 | int n_cluster_centers, 8 | int batch_size, 9 | int input_size, 10 | int flock_size); 11 | 12 | 13 | 14 | 15 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) 16 | { 17 | m.doc() = "Spatial pooler process kernels"; // optional module docstring 18 | m.def("compute_squared_distances", &compute_squared_distances, "Compute square distances between inputs and clusters"); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tests/core/utils/test_space_engineers_connector.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from typing import List 3 | 4 | import numpy as np 5 | 6 | from torchsim.utils.space_engineers_connector import SpaceEngineersConnector 7 | 8 | 9 | class TestSpaceEngineersConnector(unittest.TestCase): 10 | 11 | def test_list_of_bools_to_bitmap(self): 12 | def do(list: List[bool]) -> int: 13 | return SpaceEngineersConnector.list_of_bools_to_bitmap(list) 14 | 15 | self.assertEqual(0x0005, do([True, False, True])) 16 | self.assertEqual(0x0001, do([True])) 17 | self.assertEqual(0x0003, do([True, True])) 18 | self.assertEqual(0x0006, do([False, True, True])) 19 | self.assertEqual(0x000c, do([False, False, True, True])) 20 | self.assertEqual(0x0018, do([False, False, False, True, True])) 21 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_3_conv_temporal_compression/topologies/watch_l_3_conv_topology.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from eval_utils import run_just_model 4 | from torchsim.research.research_topics.rt_2_1_3_conv_temporal_compression.topologies.l3_conv_topology import \ 5 | L3ConvTopology, L3SpConvTopology 6 | 7 | if __name__ == "__main__": 8 | parser = ArgumentParser() 9 | parser.add_argument("--sp-only", default=False, action='store_true') 10 | parser.add_argument("--persisting-observer-system", default=False, action='store_true') 11 | args = parser.parse_args() 12 | 13 | if args.sp_only: 14 | t = L3SpConvTopology() 15 | else: 16 | t = L3ConvTopology() 17 | run_just_model(model=t, gui=True, persisting_observer_system=args.persisting_observer_system) 18 | -------------------------------------------------------------------------------- /torchsim/core/nodes/flock_networks/network_factory.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.memory.tensor_creator import TensorCreator 2 | from torchsim.core.nodes.flock_networks.multi_layer_perceptron_flock import MultilayerPerceptronFlock 3 | from torchsim.core.nodes.flock_networks.neural_network_flock import NeuralNetworkFlockParams, NeuralNetworkFlockTypes, \ 4 | NeuralNetworkFlock 5 | 6 | 7 | def create_networks(network_params: NeuralNetworkFlockParams, 8 | creator: TensorCreator, 9 | network_type: NeuralNetworkFlockTypes) -> NeuralNetworkFlock: 10 | """Create a network of selected type""" 11 | 12 | if network_type == NeuralNetworkFlockTypes.MLP: 13 | return MultilayerPerceptronFlock(network_params, creator.device) 14 | else: 15 | raise ValueError("Unknown NeuralNetworkFlockType") 16 | -------------------------------------------------------------------------------- /tests/gui/server/test_ui_server_connector.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from torchsim.gui.server.ui_server_connector import EventParser, EventDataPropertyUpdated, EventData 4 | 5 | 6 | class TestEventParser: 7 | # noinspection PyArgumentList 8 | @pytest.mark.parametrize('packet, expected_object', [ 9 | ({ 10 | 'win_id': 'win1', 11 | 'event_type': 'property_updated', 12 | 'property_id': 1, 13 | 'value': 'val1', 14 | }, EventDataPropertyUpdated('win1', 'property_updated', 1, 'val1')), 15 | ({ 16 | 'win_id': 'win1', 17 | 'event_type': 'window_closed', 18 | }, EventData('win1', 'window_closed')) 19 | ]) 20 | def test_parse_property_updated(self, packet, expected_object): 21 | assert expected_object == EventParser.parse(packet) 22 | -------------------------------------------------------------------------------- /torchsim/core/model.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | from typing import Dict, List 3 | 4 | from torchsim.gui.observables import Observable, ObserverPropertiesItem 5 | 6 | 7 | class PropertiesProvider: 8 | """A node which has properties that can be adjusted from the UI.""" 9 | @abstractmethod 10 | def get_properties(self) -> List[ObserverPropertiesItem]: 11 | raise NotImplementedError 12 | 13 | 14 | class ObservableProvider: 15 | """A node which has observables (which can be observed from the UI).""" 16 | @abstractmethod 17 | def get_observables(self) -> Dict[str, Observable]: 18 | raise NotImplementedError 19 | 20 | 21 | class Model(PropertiesProvider): 22 | """A model which can be simulated.""" 23 | @abstractmethod 24 | def step(self): 25 | raise NotImplementedError 26 | 27 | -------------------------------------------------------------------------------- /tests/core/node_accessors/test_random_number_node_accessor.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from torchsim.core.eval.node_accessors.random_number_accessor import RandomNumberNodeAccessor 4 | from torchsim.core.memory.tensor_creator import AllocatingCreator 5 | from torchsim.core.nodes.random_number_node import RandomNumberNode 6 | 7 | 8 | @pytest.mark.parametrize('device', ['cpu', 'cuda']) 9 | def test_rnd_node_accessor_return_type(device): 10 | 11 | lower_bound = 50 12 | upper_bound = 100 13 | 14 | node = RandomNumberNode(lower_bound=lower_bound, upper_bound=upper_bound) 15 | node.allocate_memory_blocks(AllocatingCreator(device=device)) 16 | node._step() 17 | 18 | random_number = RandomNumberNodeAccessor.get_output_id(node) 19 | 20 | assert type(random_number) is int 21 | assert lower_bound <= random_number < upper_bound 22 | 23 | -------------------------------------------------------------------------------- /js/src/torchsim/components/ColorTest.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { TextBox } from "./TextBox"; 3 | import { DataProvider } from "../observers/ClusterObserver/Helpers/DataProvider"; 4 | 5 | export class ColorTest extends React.Component { 6 | state = { 7 | number: 100 8 | }; 9 | 10 | render() { 11 | let size = 20; 12 | let colors = DataProvider.generateColors(this.state.number).map(c => c.getHexString()); 13 | return
14 | this.setState({number: parseInt(v)})}/> 15 |
16 | {colors.map((c, i) => 17 |
18 | )} 19 |
20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/core/nodes/test_pass_node.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.graph.connection import Connector 4 | from torchsim.core.graph.slots import MemoryBlock 5 | from torchsim.core.memory.tensor_creator import AllocatingCreator 6 | from torchsim.core.nodes.pass_node import PassNode 7 | from torchsim.core.utils.tensor_utils import same 8 | 9 | 10 | def test_pass_node(): 11 | device = 'cpu' 12 | dtype = torch.float32 13 | 14 | input_tensor = torch.tensor([[0, 1, -1], [1, 2, 3]], device=device, dtype=dtype) 15 | 16 | expected_tensor = input_tensor 17 | 18 | mb0 = MemoryBlock() 19 | mb0.tensor = input_tensor 20 | 21 | pn = PassNode((2, 3)) 22 | pn.allocate_memory_blocks(AllocatingCreator(device)) 23 | Connector.connect(mb0, pn.inputs.input) 24 | pn._step() 25 | 26 | assert same(pn.outputs.output.tensor, expected_tensor) 27 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/topologies/se_io/se_io_task0_dataset_phased.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.nodes.dataset_phased_se_objects_task_node import PhasedSeObjectsTaskNode, PhasedSeObjectsTaskParams 2 | from torchsim.research.se_tasks.topologies.se_io.se_io_task0_dataset import SeIoTask0Dataset 3 | 4 | 5 | class SeIoTask0DatasetPhased(SeIoTask0Dataset): 6 | """Access to the Task0 dataset.""" 7 | 8 | _params: PhasedSeObjectsTaskParams 9 | node_se_dataset: PhasedSeObjectsTaskNode 10 | 11 | def __init__(self, params: PhasedSeObjectsTaskParams): 12 | super().__init__(params.dataset_params) 13 | self._phased_params = params 14 | 15 | def _create_and_add_nodes(self): 16 | self.node_se_dataset = PhasedSeObjectsTaskNode(self._phased_params) 17 | 18 | # common IO 19 | self.outputs = self.node_se_dataset.outputs 20 | self.inputs = self.node_se_dataset.inputs 21 | -------------------------------------------------------------------------------- /torchsim/topologies/multi_dataset_alphabet_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.graph import Topology 2 | from torchsim.core.nodes.dataset_alphabet_node import DatasetAlphabetParams, DatasetAlphabetSequenceProbsModeParams 3 | from torchsim.core.nodes.multi_dataset_alphabet_node import MultiDatasetAlphabetNode 4 | 5 | 6 | class MultiDatasetAlphabetTopology(Topology): 7 | 8 | def __init__(self): 9 | super().__init__(device = 'cuda') 10 | 11 | dataset_params = DatasetAlphabetParams(symbols="abcd123456789", padding_right=1, 12 | sequence_probs=DatasetAlphabetSequenceProbsModeParams( 13 | seqs=['abc', '123', '456'], 14 | )) 15 | 16 | dataset = MultiDatasetAlphabetNode(dataset_params, n_worlds=4) 17 | 18 | self.add_node(dataset) 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /torchsim/core/eval/topology_adapter_base.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod, ABC 2 | 3 | from torchsim.core.graph import Topology 4 | 5 | 6 | class TopologyAdapterBase(ABC): 7 | """A subject of the experiment (something like an adapter for the model for the particular experiment).""" 8 | 9 | @abstractmethod 10 | def get_topology(self) -> Topology: 11 | pass 12 | 13 | @abstractmethod 14 | def set_topology(self, topology: Topology): 15 | pass 16 | 17 | 18 | class TestableTopologyAdapterBase(TopologyAdapterBase, ABC): 19 | """TopologyAdapterBase with switch_to_training() and switch_to_testing() methods.""" 20 | 21 | @abstractmethod 22 | def is_in_training_phase(self, **kwargs) -> bool: 23 | pass 24 | 25 | @abstractmethod 26 | def switch_to_training(self): 27 | pass 28 | 29 | @abstractmethod 30 | def switch_to_testing(self): 31 | pass 32 | -------------------------------------------------------------------------------- /torch/cuda/__init__.pyi: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | from torch import Tensor 4 | 5 | class Stream: ... 6 | 7 | class Device: ... 8 | 9 | def synchronize() -> None: ... 10 | 11 | def stream(stream: Stream) -> None: ... 12 | 13 | def current_stream() -> Stream: ... 14 | 15 | def empty_cache() -> None: ... 16 | 17 | def memory_allocated() -> float: ... 18 | 19 | def max_memory_allocated() -> float: ... 20 | 21 | def manual_seed(seed: int) -> None: ... 22 | 23 | def manual_seed_all(seed: int) -> None: ... 24 | 25 | def is_available() -> bool: ... 26 | 27 | def device_count() -> int: ... 28 | 29 | def device_of(tensor: Tensor) -> int: ... 30 | 31 | def get_device_capability(device: int) -> Tuple[int, int]: ... 32 | 33 | def memory_cached(device: int = None) -> int: ... 34 | 35 | def max_memory_cached(device: int = None) -> int: ... 36 | 37 | class cudaStatus(object): ... 38 | 39 | def check_error(res: cudaStatus): ... -------------------------------------------------------------------------------- /torchsim/core/graph/hierarchical_observable_node.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import torch 4 | from abc import ABC, abstractmethod 5 | 6 | from torchsim.core.graph.node_base import TInputs, TOutputs, TInternals 7 | from torchsim.core.graph.slots import InputSlot 8 | from torchsim.core.graph.worker_node_base import InvertibleWorkerNodeWithInternalsBase 9 | 10 | 11 | class HierarchicalObservableNode(InvertibleWorkerNodeWithInternalsBase[TInputs, TInternals, TOutputs], ABC): 12 | """An InvertibleWorkerNodeWithInternalsBase which can be observable with the hierarchical observer. 13 | 14 | TODO (Refactor): This should be just an interface, not a base class. 15 | """ 16 | 17 | @property 18 | @abstractmethod 19 | def projected_values(self) -> Optional[torch.Tensor]: 20 | pass 21 | 22 | @property 23 | @abstractmethod 24 | def projection_input(self) -> InputSlot: 25 | pass 26 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_4_task0_experiments/experiments/task_0_conv_more_labels.py: -------------------------------------------------------------------------------- 1 | from eval_utils import parse_test_args, run_just_model 2 | from torchsim.research.research_topics.rt_1_1_4_task0_experiments.topologies.task0_conv_wide_topology_more_labels import \ 3 | Task0ConvWideTopologyMoreLabels 4 | 5 | if __name__ == '__main__': 6 | arg = parse_test_args() 7 | 8 | params = [ 9 | {'num_cc': [170, 400, 400], 10 | 'lr': [0.1, 0.3, 0.3], 11 | 'batch_s': [4000, 1500, 1500], 12 | 'buffer_s': [4500, 2000, 2000], 13 | 'label_scale': 1}, 14 | 15 | ] 16 | 17 | params2 = [ 18 | {'num_cc': [100, 200, 200], 19 | 'lr': [0.4, 0.4, 0.4], 20 | 'batch_s': [1500, 1000, 1000], 21 | 'buffer_s': [3000, 1500, 1100], 22 | 'label_scale': 1} 23 | ] 24 | 25 | run_just_model(Task0ConvWideTopologyMoreLabels(**params2[0]), gui=True) 26 | -------------------------------------------------------------------------------- /tests/core/test_global_settings.py: -------------------------------------------------------------------------------- 1 | from pytest import raises 2 | 3 | from torchsim.core.exceptions import PrivateConstructorException 4 | from torchsim.core.global_settings import GlobalSettings 5 | 6 | 7 | def test_is_singleton(): 8 | s1 = GlobalSettings.instance() 9 | s2 = GlobalSettings.instance() 10 | assert s1 == s2 11 | 12 | 13 | def test_constructor_raises_exception(): 14 | with raises(PrivateConstructorException): 15 | GlobalSettings() 16 | 17 | 18 | def test_no_direct_access(): 19 | with raises(AttributeError): 20 | _ = GlobalSettings.observer_memory_block_minimal_size 21 | 22 | 23 | def test_instance_read_access(): 24 | assert 50 == GlobalSettings.instance().observer_memory_block_minimal_size 25 | 26 | 27 | def test_instance_write_access(): 28 | GlobalSettings.instance().observer_memory_block_minimal_size = 20 29 | assert 20 == GlobalSettings.instance().observer_memory_block_minimal_size 30 | -------------------------------------------------------------------------------- /tests/core/test_seed_utils.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import torch 3 | 4 | from torchsim.core.utils.tensor_utils import same 5 | from torchsim.utils.seed_utils import set_global_seeds, generate_seed 6 | 7 | 8 | @pytest.mark.slow 9 | @pytest.mark.parametrize("device", ["cpu", "cuda"]) 10 | def test_global_seeds(device): 11 | seed = 345 12 | 13 | set_global_seeds(seed) 14 | tensor1 = torch.rand([5, 2], device=device) 15 | 16 | set_global_seeds(seed) 17 | tensor2 = torch.rand([5, 2], device=device) 18 | 19 | assert same(tensor1, tensor2) 20 | 21 | seed = None 22 | 23 | set_global_seeds(seed) 24 | tensor1 = torch.rand([5, 2], device=device) 25 | 26 | set_global_seeds(seed) 27 | tensor2 = torch.rand([5, 2], device=device) 28 | 29 | assert not same(tensor1, tensor2) 30 | 31 | 32 | def test_generate_seed(): 33 | 34 | seed1 = generate_seed() 35 | seed2 = generate_seed() 36 | 37 | assert seed1 != seed2 38 | -------------------------------------------------------------------------------- /torchsim/topologies/SeDatasetObjectsTopology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.datasets.dataset_se_base import SeDatasetSize 2 | from torchsim.core.graph import Topology 3 | from torchsim.core.nodes import ActionMonitorNode 4 | from torchsim.core.nodes import DatasetSeObjectsNode, DatasetSeObjectsParams, DatasetConfig 5 | 6 | 7 | class SeDatasetObjectsTopology(Topology): 8 | _node_se_dataset: DatasetSeObjectsNode 9 | _node_action_monitor: ActionMonitorNode 10 | 11 | def __init__(self, params: DatasetSeObjectsParams = None): 12 | super().__init__(device='cuda') 13 | if params is None: 14 | self._params = DatasetSeObjectsParams(dataset_config=DatasetConfig.TRAIN_TEST, 15 | dataset_size=SeDatasetSize.SIZE_32) 16 | else: 17 | self._params = params 18 | 19 | self._node_se_dataset = DatasetSeObjectsNode(self._params) 20 | 21 | self.add_node(self._node_se_dataset) 22 | -------------------------------------------------------------------------------- /tests/core/utils/test_param_utils.py: -------------------------------------------------------------------------------- 1 | from typing import NamedTuple, List 2 | 3 | from torchsim.utils.dict_utils import to_nested_dict 4 | 5 | 6 | class NestedParams(NamedTuple): 7 | width: int 8 | items: List[int] 9 | 10 | 11 | class Params(NamedTuple): 12 | name: str 13 | projection: NestedParams 14 | 15 | 16 | def test_namedtuple_to_dict_simple(): 17 | nested = NestedParams(10, [1, 2, 3]) 18 | result = to_nested_dict(nested) 19 | assert { 20 | 'width': 10, 21 | 'items': [1, 2, 3] 22 | } == result 23 | 24 | 25 | def test_namedtuple_to_dict_nested(): 26 | nested = NestedParams(10, [1, 2, 3]) 27 | params = Params('first', nested) 28 | 29 | result = to_nested_dict(params) 30 | assert { 31 | 'name': 'first', 32 | 'projection': { 33 | 'width': 10, 34 | 'items': [1, 2, 3] 35 | } 36 | } == result 37 | -------------------------------------------------------------------------------- /torchsim/core/eval/metrics/cluster_agreement.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | def cluster_agreement(cluster_ids_1: torch.Tensor, cluster_ids_2: torch.Tensor) -> float: 5 | """Given two series of cluster assignments, returns the fraction of identical assignments. 6 | 7 | This is a measure of representation stability. A series of data points get assigned to a corresponding series 8 | of clusters. We then allow the expert to continue learning. Then we classify the same points again and compute 9 | the fraction of points that get assigned to the same clusters. 10 | """ 11 | assert cluster_ids_1.dtype == torch.long 12 | assert cluster_ids_2.dtype == torch.long 13 | assert cluster_ids_1.numel() == cluster_ids_2.numel() 14 | assert cluster_ids_1.dim() == cluster_ids_2.dim() == 1 15 | 16 | series_length = cluster_ids_1.numel() 17 | n_same_cluster = cluster_ids_1.eq(cluster_ids_2).sum().item() 18 | return n_same_cluster / series_length 19 | 20 | -------------------------------------------------------------------------------- /tests/benchmarks.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import torch 3 | import time 4 | 5 | 6 | @pytest.mark.skip(reason="benchmarking purposes only") 7 | def test_indexing(): 8 | data = torch.rand((10000, 500, 4)).to('cuda') 9 | indices = torch.rand((10000, 500)).to('cuda') 10 | 11 | indices[indices < 0.5] = 0 12 | 13 | torch.cuda.synchronize() 14 | start = time.clock() 15 | data[indices == 0] = -1 16 | duration = time.clock() - start 17 | torch.cuda.synchronize() 18 | 19 | print(duration) 20 | 21 | 22 | @pytest.mark.skip(reason="benchmarking purposes only") 23 | def test_indexing_2(): 24 | 25 | data = torch.rand((10000, 500, 4)).to('cuda') 26 | indices = torch.rand((10000, 500)).to('cuda') 27 | 28 | indices[indices < 0.5] = 0 29 | 30 | torch.cuda.synchronize() 31 | start = time.clock() 32 | data *= indices.unsqueeze(dim=2) 33 | torch.cuda.synchronize() 34 | duration = time.clock() - start 35 | 36 | print(duration) 37 | -------------------------------------------------------------------------------- /torchsim/research/figure_viewer.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import glob 3 | import os 4 | import pickle 5 | from os import path 6 | from matplotlib import pyplot 7 | 8 | 9 | def _load_and_view_figures(figure_path: str): 10 | print(f"Loading and visualizing figures in {path}...") 11 | if os.path.isdir(figure_path): 12 | figures_paths = list(glob.iglob(path.join(figure_path, '*.fpk'))) 13 | 14 | else: 15 | figures_paths = [figure_path] 16 | 17 | for idx, fig_path in enumerate(figures_paths): 18 | print(f"Loading figure {idx} / {len(figures_paths)}") 19 | with open(fig_path, 'rb') as file: 20 | figure = pickle.load(file) 21 | figure.show() 22 | 23 | pyplot.show() 24 | 25 | print(f"...finished") 26 | 27 | 28 | if __name__ == '__main__': 29 | parser = argparse.ArgumentParser() 30 | parser.add_argument("--path", default=None) 31 | args = parser.parse_args() 32 | _load_and_view_figures(args.path) 33 | -------------------------------------------------------------------------------- /torchsim/core/persistence/loader.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from ruamel.yaml import YAML 4 | 5 | from torchsim.core.persistence.persistor import Persistor 6 | 7 | 8 | class Loader(Persistor): 9 | def __init__(self, folder_name: str, parent: 'Loader' = None): 10 | super().__init__(folder_name, parent) 11 | 12 | self._load() 13 | 14 | def load_child(self, folder_name: str) -> 'Loader': 15 | """Initialize a sub-loader. 16 | 17 | Args: 18 | folder_name: The folder name of the child loader relative to this loader's folder. 19 | """ 20 | return Loader(folder_name, self) 21 | 22 | def _load(self): 23 | self._load_description() 24 | 25 | def _load_description(self): 26 | yaml = YAML() 27 | description_path = self._get_description_path() 28 | if os.path.exists(description_path): 29 | with open(description_path, 'r') as f: 30 | self._description = yaml.load(f) 31 | -------------------------------------------------------------------------------- /js/src/torchsim/observers/PropertiesObserver.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import {ObserverProps, ObserverUtils} from "./Observer"; 3 | import {PropertiesTable, PropertiesTablePropertyItem} from "../components/PropertiesTable"; 4 | 5 | 6 | export interface PropertiesObserverProps extends ObserverProps { 7 | data: PropertiesTablePropertyItem[] 8 | } 9 | 10 | export class PropertiesObserver extends React.Component { 11 | observerUtils = new ObserverUtils(this); 12 | 13 | constructor(props: PropertiesObserverProps) { 14 | super(props); 15 | 16 | } 17 | render() { 18 | this.observerUtils.onRender(); 19 | return ( 20 |
this.observerUtils.setContentRef(element)} 22 | > 23 | 24 |
25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/gui/server/test_ui_api.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import torch 3 | import numpy as np 4 | from torchsim.core import get_float 5 | from torchsim.gui.server.ui_api import UIApi 6 | 7 | 8 | @pytest.mark.skip('Just used for manual checks of UI') 9 | @pytest.mark.parametrize('device', ['cpu']) 10 | class TestUIApi: 11 | 12 | @pytest.fixture() 13 | def connector(self): 14 | return UIApi(server='ws://localhost', port=5000) 15 | 16 | def test_image(self, connector, device): 17 | image = torch.rand((128, 64, 3), dtype=get_float(device)) 18 | connector.image(image, f'Image {device}') 19 | 20 | def test_matplot(self, connector, device): 21 | import matplotlib.pyplot as plt 22 | plt.plot(np.random.randint(-10, 10, 20)) 23 | plt.ylabel('some numbers') 24 | connector.matplot(plt, win=f'Matplot {device}') 25 | 26 | def test_text(self, connector, device): 27 | connector.text("Text to be displayed
New line", win='Text') 28 | -------------------------------------------------------------------------------- /torchsim/core/eval/node_accessors/se_node_accessor.py: -------------------------------------------------------------------------------- 1 | # import torch 2 | # from torchsim.core import FLOAT_TYPE_CPU 3 | # 4 | # from torchsim.core.nodes.dataset_mnist_node import DatasetMNISTNode 5 | # 6 | 7 | # Not used anywhere and a lot of noise, commented out. 8 | 9 | # class SeNodeAccessor: 10 | # """Accessor for the SE Node allowing access to the basic measurable values.""" 11 | # @staticmethod 12 | # def get_data(node: DatasetMNISTNode) -> torch.Tensor: 13 | # return node.get_data().to('cpu').type(FLOAT_TYPE_CPU) 14 | # 15 | # # for the beginning, we can just convert XY coords to unique int and use this one (I'll just improve this tommorrow) 16 | # @staticmethod 17 | # def get_label_id(node: DatasetMNISTNode) -> int: 18 | # """Get the label id of the current bitmap.""" 19 | # return node.get_current_label_id() 20 | # 21 | # @staticmethod 22 | # def reset(node: DatasetMNISTNode, seed: int): 23 | # print('reset is called on the SE!') 24 | # node.reset(seed) -------------------------------------------------------------------------------- /torchsim/core/nodes/internals/actions_observable.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | 3 | import numpy as np 4 | 5 | from torchsim.core.actions import AgentActionsDescriptor 6 | from torchsim.gui.observer_system import TextObservable 7 | 8 | 9 | class ActionsDescriptorProvider: 10 | @abstractmethod 11 | def get_actions_descriptor(self) -> AgentActionsDescriptor: 12 | raise NotImplementedError 13 | 14 | 15 | class ActionsObservable(TextObservable): 16 | actions_descriptor: AgentActionsDescriptor 17 | _data: str = '' 18 | 19 | def __init__(self, node: ActionsDescriptorProvider): 20 | self.actions_descriptor = node.get_actions_descriptor() 21 | 22 | def set_data(self, data: np.array): 23 | self._data = data 24 | 25 | def get_data(self) -> str: 26 | action_values = self.actions_descriptor.parse_actions(self._data) 27 | return "
".join( 28 | (f'{name}: {value}' for name, value in zip(self.actions_descriptor.action_names(), action_values))) 29 | -------------------------------------------------------------------------------- /torchsim/topologies/toyarch_groups/ncm_group.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Tuple, Optional 3 | 4 | from torchsim.core.graph.node_base import EmptyOutputs 5 | from torchsim.research.research_topics.rt_2_1_2_learning_rate.node_groups.ta_multilayer_node_group_params import \ 6 | MultipleLayersParams 7 | from torchsim.topologies.toyarch_groups.ncm_group_base import NCMGroupInputs, NCMGroupBase 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | class NCMGroup(NCMGroupBase[NCMGroupInputs, EmptyOutputs]): 13 | def __init__(self, 14 | conv_layers_params: MultipleLayersParams, 15 | model_seed: Optional[int] = 321, 16 | image_size: Tuple[int, int, int] = (24, 24, 3), 17 | name: str = "TA Model"): 18 | super().__init__(NCMGroupInputs(self), 19 | EmptyOutputs(self), 20 | conv_layers_params, 21 | model_seed, 22 | image_size, 23 | name) 24 | -------------------------------------------------------------------------------- /torchsim/core/graph/inverse_pass_packet.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.graph.slots import InputSlot, OutputSlotBase 4 | 5 | 6 | class InversePassOutputPacket: 7 | """A class for holding data associated with a given output memory block to be used in the inverse projection. 8 | 9 | The data is a tensor of the same size as the tensor stored in memory_block, and it is the output that is going to be 10 | projected back into the input space of the node that memory_block belongs to. 11 | 12 | 'data' is therefore something that could have come from the memory_block. 13 | """ 14 | tensor: torch.Tensor 15 | slot: OutputSlotBase 16 | 17 | def __init__(self, data: torch.Tensor, output_slot: OutputSlotBase): 18 | self.tensor = data 19 | self.slot = output_slot 20 | 21 | 22 | class InversePassInputPacket: 23 | tensor: torch.Tensor 24 | slot: InputSlot 25 | 26 | def __init__(self, data: torch.Tensor, input_slot: InputSlot): 27 | self.tensor = data 28 | self.slot = input_slot 29 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_1_lr_subfields/node_groups/SFCN_C1_R1.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.research_topics.rt_3_1_lr_subfields.node_groups import CN_C1_R1 2 | from torchsim.research.research_topics.rt_3_1_lr_subfields.conv_subfield_layer import SubLrfSpConvLayer, SubLrfConvLayer 3 | 4 | 5 | class SFCN_C1_R1(CN_C1_R1): 6 | conv_layer_class = SubLrfConvLayer 7 | 8 | def __init__(self, name: str = None, bottom_layer_size=5, l_0_cluster_centers=10, 9 | l_1_cluster_centers=20, l_0_rf_dims=(3, 3), l_0_rf_stride=None, l_1_rf_dims=(2, 2), env_size=(24, 24), 10 | label_length=3, sp_n_cluster_centers=10, l_0_sub_field_size=6): 11 | super().__init__(name, bottom_layer_size, l_0_cluster_centers, l_1_cluster_centers, l_0_rf_dims, 12 | l_0_rf_stride, l_1_rf_dims, env_size, label_length, sp_n_cluster_centers, 13 | l_0_custom_args={'sub_field_size': l_0_sub_field_size}) 14 | 15 | 16 | class SFSCN_SC1_R1(SFCN_C1_R1): 17 | conv_layer_class = SubLrfSpConvLayer 18 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/adapters/task_stats_adapter.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | 3 | from torchsim.research.experiment_templates.dataset_simulation_running_stats_template import \ 4 | DatasetSeTaSimulationRunningStatsAdapter 5 | 6 | 7 | class TaskStatsAdapter(DatasetSeTaSimulationRunningStatsAdapter): 8 | """A general subject for the experiment, but this one logs also SE aux data.""" 9 | 10 | @abstractmethod 11 | def get_task_id(self) -> float: 12 | pass 13 | 14 | @abstractmethod 15 | def get_task_instance_id(self) -> float: 16 | pass 17 | 18 | @abstractmethod 19 | def get_task_status(self) -> float: 20 | pass 21 | 22 | @abstractmethod 23 | def get_task_instance_status(self) -> float: 24 | pass 25 | 26 | @abstractmethod 27 | def get_reward(self) -> float: 28 | pass 29 | 30 | @abstractmethod 31 | def get_testing_phase(self) -> float: 32 | pass 33 | 34 | @abstractmethod 35 | def switch_learning(self, learning_on: bool): 36 | pass 37 | -------------------------------------------------------------------------------- /js/src/torchsim/observers/Observer.ts: -------------------------------------------------------------------------------- 1 | import {AppApi} from "../App"; 2 | import {ElementResizeWatcher, Size} from "../../wm/GuiUtils"; 3 | 4 | export interface ObserverProps { 5 | id: string; // Window id 6 | name: string; // Observer name 7 | onFocus: (string, VoidCallback) => void; 8 | onResize: (rect: Size) => void; 9 | appApi: AppApi, 10 | } 11 | 12 | export class ObserverUtils { 13 | component: React.Component; 14 | 15 | resizeWatcher = new ElementResizeWatcher(); 16 | 17 | 18 | constructor(component: React.Component) { 19 | this.component = component; 20 | 21 | this.resizeWatcher.signals.resized.connect((rect) => { 22 | if( component.props.onResize !== undefined) { 23 | component.props.onResize(rect); 24 | } 25 | }) 26 | 27 | } 28 | 29 | onRender() { 30 | this.resizeWatcher.update(); 31 | } 32 | 33 | setContentRef(element: HTMLElement) { 34 | this.resizeWatcher.setElement(element); 35 | } 36 | } -------------------------------------------------------------------------------- /torchsim/core/nodes/agent_actions_parser_node.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from torchsim.core.actions import AgentActionsDescriptor 4 | from torchsim.core.nodes.scatter_node import ScatterNode 5 | 6 | 7 | class AgentActionsParserNode(ScatterNode): 8 | """Scatters input values to output according to input_actions and action_descriptor. 9 | 10 | Input actions can be subset of all actions or have different order. 11 | Unset values are set to zero. 12 | 13 | Example: 14 | action_descriptor: ['right', 'left', 'up', down'] 15 | input_actions: ['up', 'left'] 16 | 17 | input = [1, .5] 18 | output = [0, .5, 1, 0] 19 | """ 20 | 21 | def __init__(self, action_descriptor: AgentActionsDescriptor, input_actions: List[str], name="ActionParser", 22 | device="cuda"): 23 | names = action_descriptor.action_names() 24 | mapping = [names.index(name) for name in input_actions] 25 | super().__init__(mapping=mapping, output_shape=(action_descriptor.ACTION_COUNT,), device=device, name=name) 26 | -------------------------------------------------------------------------------- /torchsim/core/actions.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | from typing import List 3 | import numpy as np 4 | 5 | 6 | class AgentActionsDescriptor: 7 | ACTION_COUNT: int 8 | 9 | @abstractmethod 10 | def action_names(self) -> List[str]: 11 | pass 12 | 13 | @abstractmethod 14 | def parse_actions(self, actions: np.array) -> List[bool]: 15 | pass 16 | 17 | 18 | class SpaceEngineersActionsDescriptor(AgentActionsDescriptor): 19 | 20 | def __init__(self): 21 | self._action_names = [ 22 | 'UP', 23 | 'DOWN', 24 | 'FORWARD', 25 | 'BACKWARD', 26 | 'LEFT', 27 | 'RIGHT', 28 | 'JUMP', 29 | 'CROUCH', 30 | 'USE', 31 | 'TURN_LIGHTS', 32 | ] 33 | SpaceEngineersActionsDescriptor.ACTION_COUNT = len(self._action_names) 34 | 35 | def action_names(self) -> List[str]: 36 | return self._action_names 37 | 38 | def parse_actions(self, actions: np.array) -> List[bool]: 39 | return [val > 0 for val in actions] 40 | -------------------------------------------------------------------------------- /torchsim/topologies/mse_demo_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.graph.connection import Connector 2 | from torchsim.core.nodes.random_number_node import RandomNumberNode 3 | from torchsim.core.graph import Topology 4 | from torchsim.core.nodes.mse_node import MseNode 5 | 6 | 7 | class MseDemoTopology(Topology): 8 | 9 | def __init__(self): 10 | super().__init__(device='cuda') 11 | 12 | bound = 30 13 | buffer_size = 100 14 | 15 | random_number_node_a = RandomNumberNode(upper_bound=bound, seed=None) 16 | random_number_node_b = RandomNumberNode(upper_bound=bound, seed=None) 17 | 18 | mse_node = MseNode(buffer_size) 19 | 20 | self.add_node(random_number_node_a) 21 | self.add_node(random_number_node_b) 22 | self.add_node(mse_node) 23 | 24 | Connector.connect( 25 | random_number_node_a.outputs.one_hot_output, 26 | mse_node.inputs.input_a 27 | ) 28 | 29 | Connector.connect( 30 | random_number_node_b.outputs.one_hot_output, 31 | mse_node.inputs.input_b 32 | ) 33 | -------------------------------------------------------------------------------- /js/src/torchsim/components/CheckBox.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import {MyRef} from "./TextBox"; 3 | 4 | interface CheckProps { 5 | value: boolean; 6 | submitHandler: (string) => void 7 | readOnly?: boolean 8 | disabled?: boolean 9 | className?: string; 10 | } 11 | 12 | interface CheckState { 13 | } 14 | 15 | export class CheckBox extends React.Component { 16 | private input: MyRef; 17 | state: CheckState; 18 | 19 | constructor(props: CheckProps) { 20 | super(props); 21 | this.input = new MyRef(); 22 | this.state = {}; 23 | } 24 | 25 | handleChange = (event) => { 26 | event.preventDefault(); 27 | event.stopPropagation(); 28 | 29 | this.props.submitHandler(event.target.checked); 30 | }; 31 | 32 | render() { 33 | return ( 34 | 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/test_testing_utils.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod, ABC 2 | 3 | from tests.testing_utils import get_subclasses_recursive, remove_abstract_classes 4 | 5 | 6 | class Base: 7 | pass 8 | 9 | 10 | class Subclass(Base): 11 | pass 12 | 13 | 14 | class Grandson(Subclass): 15 | pass 16 | 17 | 18 | class AbstractClass(ABC, Base): 19 | @abstractmethod 20 | def abstract_method(self): 21 | pass 22 | 23 | 24 | class AbstractClassChild(AbstractClass): 25 | 26 | def abstract_method(self): 27 | pass 28 | 29 | 30 | def test_recursive_subclass_search(): 31 | subclasses = get_subclasses_recursive(Base) 32 | assert Subclass in subclasses 33 | assert Grandson in subclasses 34 | assert AbstractClass in subclasses 35 | 36 | 37 | def test_remove_abstract_class(): 38 | subclasses = remove_abstract_classes([Base, Subclass, Grandson, AbstractClass, AbstractClassChild]) 39 | assert Base in subclasses 40 | assert Subclass in subclasses 41 | assert Grandson in subclasses 42 | assert AbstractClass not in subclasses 43 | assert AbstractClassChild in subclasses 44 | -------------------------------------------------------------------------------- /tests/core/utils/test_inverse_projection_utils.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | import pytest 4 | 5 | from torchsim.core import FLOAT_NAN 6 | from torchsim.core.utils.inverse_projection_utils import replace_cluster_ids_with_projections 7 | from torchsim.core.utils.tensor_utils import same 8 | 9 | 10 | class TestInverseProjectionUtils: 11 | @pytest.mark.parametrize('source, projections, expected_result', [ 12 | ([[0, 1], [2, -1]], 13 | [[1, 2], [3, 4], [5, 6]], 14 | [ 15 | [[1, 2], [3, 4]], 16 | [[5, 6], [FLOAT_NAN, FLOAT_NAN]], 17 | ] 18 | ) 19 | ]) 20 | @pytest.mark.parametrize('device', ['cpu', pytest.param('cuda', marks=pytest.mark.slow)]) 21 | def test_replace_cluster_ids_with_projections(self, source, projections, expected_result, device): 22 | t_source = torch.Tensor(source).long().to(device) 23 | t_projections = torch.Tensor(projections).float().to(device) 24 | t_expected = torch.Tensor(expected_result).to(device) 25 | t_result = replace_cluster_ids_with_projections(t_source, t_projections) 26 | assert same(t_expected, t_result) 27 | -------------------------------------------------------------------------------- /tests/core/graph/node_stub.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.graph.slot_container import MemoryBlocks 2 | from torchsim.core.graph.unit import Unit 3 | from torchsim.core.graph.worker_node_base import WorkerNodeBase 4 | from torchsim.core.memory.tensor_creator import TensorCreator 5 | 6 | 7 | class RandomUnitStub(Unit): 8 | def __init__(self, creator: TensorCreator): 9 | super().__init__('cpu') 10 | self.output = creator.randn((1,)) 11 | 12 | def step(self): 13 | self.output.random_() 14 | 15 | 16 | class RandomNodeOutputs(MemoryBlocks): 17 | def __init__(self, owner): 18 | super().__init__(owner) 19 | self.output = self.create('output') 20 | 21 | def prepare_slots(self, unit: RandomUnitStub): 22 | self.output.tensor = unit.output 23 | 24 | 25 | class RandomNodeStub(WorkerNodeBase): 26 | outputs: RandomNodeOutputs 27 | _unit: RandomUnitStub 28 | 29 | def __init__(self): 30 | super().__init__(outputs=RandomNodeOutputs(self)) 31 | 32 | def _create_unit(self, creator: TensorCreator) -> Unit: 33 | return RandomUnitStub(creator) 34 | 35 | def _step(self): 36 | self._unit.step() 37 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_3_space_benchmarks/topologies/se_dataset_sp_lrf.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.research_topics.rt_1_1_3_space_benchmarks.topologies.se_dataset_ta_lrf import SeDatasetTaLrf 2 | 3 | 4 | class SeDatasetSpLrf(SeDatasetTaLrf): 5 | """ 6 | A model which receives data from the SE dataset and learns spatial representation from this. 7 | """ 8 | def __init__(self, 9 | seed: int=None, 10 | device: str='cuda', 11 | eox: int=2, 12 | eoy: int=2, 13 | num_cc: int = 100, 14 | batch_s=300, 15 | tp_learn_period=50, 16 | tp_max_enc_seq=1000): 17 | 18 | super().__init__(run_just_sp=True, # the only change compared to SeDatasetTaLrf is here 19 | seed=seed, 20 | device=device, 21 | eox=eox, 22 | eoy=eoy, 23 | num_cc=num_cc, 24 | batch_s=batch_s, 25 | tp_learn_period=tp_learn_period, 26 | tp_max_enc_seq=tp_max_enc_seq) -------------------------------------------------------------------------------- /3rd-party-licenses/reactwm-license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 George Czabania 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | !.idea/inspectionProfiles/Project_Default.xml 3 | .pytest_cache 4 | .cache 5 | observers.yaml 6 | 7 | *.pyc 8 | *.crm 9 | *.drm 10 | *.pt 11 | *.pkl 12 | *.set 13 | *.log 14 | 15 | data/* 16 | 17 | se_school/se_school_mod/SchoolMod/*.suo 18 | se_school/se_school_mod/SchoolMod/bin/ 19 | se_school/se_school_mod/SchoolMod/obj/ 20 | se_school/se_school_mod/SchoolMod/packages/ 21 | se_school/se_school_mod/SchoolModTests/bin/ 22 | se_school/se_school_mod/SchoolModTests/obj/ 23 | se_school/se_school_mod/SchoolModTests/packages/ 24 | 25 | se_school/se_school_comm/SchoolServer/SchoolServer/bin/ 26 | se_school/se_school_comm/SchoolServer/SchoolServer/obj/ 27 | se_school/se_school_comm/SchoolServer/SchoolServer/Properties/ 28 | se_school/se_school_comm/SchoolServer/.vs 29 | se_school/se_school_comm/SchoolServer/packages/ 30 | 31 | trained_models/ 32 | /torchsim/research/se_tasks/experiments/results 33 | 34 | *.nvvp 35 | 36 | .mypy_cache 37 | 38 | torchsim/research/research_topics/**/results/ 39 | torchsim/research/baselines/experiments/results 40 | 41 | main\.log 42 | 43 | tests/temp/* 44 | 45 | 46 | *.temp 47 | 48 | # Frontend rules 49 | /js/package-lock.json 50 | /js/node_modules -------------------------------------------------------------------------------- /torchsim/topologies/noise_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.nodes.dataset_mnist_node import DatasetMNISTParams, DatasetMNISTNode 2 | from torchsim.core.nodes.random_noise_node import RandomNoiseNode, RandomNoiseParams 3 | from torchsim.core.graph import Topology 4 | from torchsim.core.graph.connection import Connector 5 | 6 | 7 | class RandomNoiseTopology(Topology): 8 | _mnist_params: DatasetMNISTParams = DatasetMNISTParams() 9 | _noise_params: RandomNoiseParams = RandomNoiseParams() 10 | 11 | def __init__(self): 12 | super().__init__(device='cuda') 13 | 14 | mnist_node = DatasetMNISTNode(params=self._mnist_params) 15 | self.add_node(mnist_node) 16 | 17 | noise_node = RandomNoiseNode() 18 | self.add_node(noise_node) 19 | 20 | Connector.connect(mnist_node.outputs.data, noise_node.inputs.input) 21 | 22 | 23 | class RandomNoiseOnlyTopology(Topology): 24 | _noise_params: RandomNoiseParams = RandomNoiseParams((32, 32), distribution='Normal', amplitude=.3) 25 | 26 | def __init__(self): 27 | super().__init__(device='cpu') 28 | 29 | noise_node = RandomNoiseNode(params=self._noise_params) 30 | self.add_node(noise_node) 31 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | GoodAI TorchSim 2 | Copyright (c) 2018-2019, GoodAI Research 3 | 4 | This software was developed at GoodAI Research, a Keen Software House company 5 | (http://www.keenswh.com/ and http://www.goodai.com/). 6 | 7 | GoodAI TorchSim, its source code, binaries, assets, modules 8 | and project files are licensed under the Apache License, Version 2.0, 9 | and may be used only for non-evil purposes. 10 | 11 | If you plan otherwise, contact us at info@goodai.com !-) 12 | 13 | You may not use this software except in compliance with the License. 14 | You may obtain a copy of the License at 15 | 16 | http://www.apache.org/licenses/LICENSE-2.0 17 | 18 | Unless required by applicable law or agreed to in writing, software 19 | distributed under the License is distributed on an "AS IS" BASIS, 20 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | See the License for the specific language governing permissions and 22 | limitations under the License. 23 | 24 | A copy of the License is also included in the LICENSE file in the directory 25 | where this file is. 26 | 27 | This codebase includes some copyrighted 3rd-party code. The licenses are 28 | in the '3rd-party-licenses' directory. 29 | 30 | 31 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate/adapters/modular/model_classification_adapter_base.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | import torch 4 | 5 | 6 | class ModelClassificationAdapterBase(ABC): 7 | """ This should be implemented by your model in order to support the classification accuracy measurement. 8 | """ 9 | 10 | @abstractmethod 11 | def get_average_log_delta_for(self, layer_id: int) -> float: 12 | """Average log delta across all dimensions and all the cluster centers. If delta==0, return 0.""" 13 | pass 14 | 15 | @abstractmethod 16 | def clone_predicted_label_tensor_output(self) -> torch.Tensor: 17 | """Returns a tensor representing the class label predicted by the architecture.""" 18 | pass 19 | 20 | @abstractmethod 21 | def model_switch_to_training(self): 22 | """Switch experts (NN) to training""" 23 | pass 24 | 25 | @abstractmethod 26 | def model_switch_to_testing(self): 27 | """Switch experts (NN) to testing""" 28 | pass 29 | 30 | @abstractmethod 31 | def model_is_learning(self): 32 | """Return true if the model is learning (debug purposes)""" 33 | pass 34 | -------------------------------------------------------------------------------- /tests/core/nodes/test_lambda_node.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.graph.connection import Connector 4 | from torchsim.core.graph.slots import MemoryBlock 5 | from torchsim.core.memory.tensor_creator import AllocatingCreator 6 | from torchsim.core.nodes.lambda_node import LambdaNode 7 | from torchsim.core.utils.tensor_utils import same 8 | 9 | 10 | def test_lambda_node(): 11 | device = 'cpu' 12 | dtype = torch.float32 13 | 14 | input_tensor_0 = torch.tensor([0, 1, -1], device=device, dtype=dtype) 15 | input_tensor_1 = torch.tensor([1, 1, -1], device=device, dtype=dtype) 16 | 17 | expected_tensor = input_tensor_0 + input_tensor_1 18 | 19 | mb0, mb1 = MemoryBlock(), MemoryBlock() 20 | mb0.tensor, mb1.tensor = input_tensor_0, input_tensor_1 21 | 22 | def add_f(inputs, outputs): 23 | outputs[0][:] = 0 24 | outputs[0].add_(inputs[0]) 25 | outputs[0].add_(inputs[1]) 26 | 27 | ln = LambdaNode(add_f, 2, [input_tensor_0.shape]) 28 | ln.allocate_memory_blocks(AllocatingCreator(device=device)) 29 | Connector.connect(mb0, ln.inputs[0]) 30 | Connector.connect(mb1, ln.inputs[1]) 31 | ln._step() 32 | 33 | assert same(ln.outputs[0].tensor, expected_tensor) 34 | -------------------------------------------------------------------------------- /torchsim/core/persistence/persistor.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import Dict, Any 3 | 4 | 5 | class Persistor: 6 | _description_file_name = 'description.yaml' 7 | _folder: str 8 | _description: Dict[str, Any] 9 | _parent: 'Persistor' 10 | 11 | @property 12 | def description(self) -> Dict[str, Any]: 13 | return self._description 14 | 15 | def __init__(self, folder: str, parent: 'Persistor'): 16 | """Initialize the persistor. 17 | 18 | Args: 19 | folder: The folder name relative to the parent. If this is the root, it should be the absolute path. 20 | parent: The parent of this persistor. If it's None, this is the root persistor. 21 | """ 22 | self._parent = parent 23 | self._folder = folder 24 | self._description = {} 25 | 26 | def get_full_folder_path(self) -> str: 27 | """Gets the absolute path of this persistor.""" 28 | if self._parent is None: 29 | return self._folder 30 | 31 | return os.path.join(self._parent.get_full_folder_path(), self._folder) 32 | 33 | def _get_description_path(self): 34 | return os.path.join(self.get_full_folder_path(), self._description_file_name) 35 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_7_1_task0_analysis/topologies/task0_dummy_model_topology.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from eval_utils import run_just_model 4 | from torchsim.core.eval2.scaffolding import TopologyScaffoldingFactory 5 | from torchsim.research.research_topics.rt_2_1_2_learning_rate.node_groups.se_node_group import SeNodeGroup 6 | from torchsim.research.research_topics.rt_3_7_1_task0_analysis.node_groups.dummy_model_group import DummyModelGroup 7 | from torchsim.research.research_topics.rt_3_7_1_task0_analysis.topologies.task0_ta_analysis_topology import \ 8 | Task0TaAnalysisTopology 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | 13 | if __name__ == '__main__': 14 | 15 | num_conv_layers = 1 16 | use_top_layer = True 17 | 18 | cf_easy = [1, 2, 3, 4] 19 | 20 | params = [ 21 | {'se_group': {'class_filter': cf_easy}, 22 | 'model': {}}, 23 | {'se_group': {'class_filter': cf_easy}, 24 | 'model': {} 25 | } 26 | ] 27 | 28 | scaffolding = TopologyScaffoldingFactory(Task0TaAnalysisTopology, se_group=SeNodeGroup, model=DummyModelGroup) 29 | 30 | run_just_model(scaffolding.create_topology(**params[0]), gui=True, persisting_observer_system=True) 31 | 32 | -------------------------------------------------------------------------------- /torchsim/core/eval2/experiment_runner_params.py: -------------------------------------------------------------------------------- 1 | from typing import NamedTuple 2 | 3 | 4 | class SingleExperimentRunParams(NamedTuple): 5 | """Parameters for a single experiment run. This is a subset of the ExperimentRunnerParams.""" 6 | load_cache: bool 7 | save_cache: bool 8 | calculate_statistics: bool 9 | max_steps: int 10 | save_model_after_run: bool 11 | 12 | 13 | class ExperimentParams(NamedTuple): 14 | """Parameters for the set of experiment runs which comprise the whole experiment run.""" 15 | max_steps: int # If this is set to 0, the simulation will run until a component says it should stop. 16 | seed: int = None 17 | calculate_statistics: bool = True 18 | save_cache: bool = False 19 | load_cache: bool = False 20 | clear_cache: bool = False 21 | experiment_folder: str = None 22 | docs_folder: str = None 23 | delete_cache_after_each_run: bool = False 24 | zip_cache: bool = False 25 | save_models_after_run: bool = True 26 | 27 | def create_run_params(self) -> SingleExperimentRunParams: 28 | return SingleExperimentRunParams(self.load_cache, self.save_cache, self.calculate_statistics, self.max_steps, 29 | self.save_models_after_run) 30 | -------------------------------------------------------------------------------- /tests/core/models/test_expert_params.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from torchsim.core.models.expert_params import ExpertParams 4 | 5 | 6 | def test_max_new_seqs_default_autocalculate(): 7 | params = ExpertParams() 8 | 9 | expected_max_new_seqs = params.temporal.batch_size - (params.temporal.seq_length - 1) 10 | 11 | assert expected_max_new_seqs == params.temporal.max_new_seqs 12 | 13 | 14 | @pytest.mark.parametrize("new_batch_size, new_seq_length", 15 | [(400, 20), (800, 73), (10, 3), (20, 4)]) 16 | def test_max_new_seqs_modified_autocalculate(new_batch_size, new_seq_length): 17 | params = ExpertParams() 18 | params.temporal.batch_size = new_batch_size 19 | params.temporal.seq_length = new_seq_length 20 | 21 | expected_max_new_seqs = params.temporal.batch_size - (params.temporal.seq_length - 1) 22 | 23 | assert expected_max_new_seqs == params.temporal.max_new_seqs 24 | 25 | 26 | @pytest.mark.parametrize("desired_max_new_seqs", 27 | [20, 73, 3, 4, 100, 34]) 28 | def test_max_new_seqs_overridden(desired_max_new_seqs): 29 | params = ExpertParams() 30 | 31 | params.temporal.max_new_seqs = desired_max_new_seqs 32 | 33 | assert desired_max_new_seqs == params.temporal.max_new_seqs 34 | -------------------------------------------------------------------------------- /tests/topologies/test_dataclass.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, field 2 | from pytest import raises 3 | from typing import List 4 | 5 | from torchsim.core.models.expert_params import ParamsBase 6 | 7 | 8 | @dataclass 9 | class NameParams: 10 | name: str = 'Not set' 11 | 12 | 13 | @dataclass 14 | class DataParams(ParamsBase): 15 | i: int = 0 16 | name: NameParams = NameParams('default name') 17 | l_fac: List[int] = field(default_factory=list) 18 | name_fac: NameParams = field(default_factory=NameParams) 19 | 20 | 21 | class TestDataClass: 22 | def test_factory(self): 23 | d1 = DataParams() 24 | d2 = DataParams() 25 | d1.name.name = "d1" 26 | d1.l_fac.append(2) 27 | d1.name_fac.name = "f1" 28 | assert "f1" == d1.name_fac.name 29 | assert "Not set" == d2.name_fac.name # factory creates independent instances 30 | assert "d1" == d1.name.name 31 | assert "d1" == d2.name.name # shared instance 32 | 33 | def test_access_to_not_existing_fields(self): 34 | d1 = DataParams() 35 | d1.i = 1 36 | assert 1 == d1.i 37 | with raises(AttributeError): 38 | d1.name_missing = "abc" 39 | assert False is hasattr(d1, 'name_missing') 40 | -------------------------------------------------------------------------------- /tests/utils/test_cache_utils.py: -------------------------------------------------------------------------------- 1 | from torchsim.utils.cache_utils import ResettableCache, SimpleResettableCache 2 | 3 | 4 | class TestResettableCache: 5 | 6 | def test_basic_usage(self): 7 | counter = [0] 8 | 9 | def data_provider() -> int: 10 | counter[0] += 1 11 | return counter[0] 12 | 13 | scope: ResettableCache[str] = ResettableCache() 14 | key = 'value1' 15 | scope.add(key, data_provider) 16 | assert 1 == scope.get(key) 17 | assert 1 == scope.get(key) 18 | scope.reset() 19 | assert 2 == scope.get(key) 20 | assert 2 == scope.get(key) 21 | scope.reset() 22 | assert 3 == scope.get(key) 23 | 24 | 25 | class TestSimpleResettableCache: 26 | def test_create(self): 27 | counter = [0] 28 | 29 | def data_provider() -> int: 30 | counter[0] += 1 31 | return counter[0] 32 | 33 | scope = SimpleResettableCache() 34 | getter = scope.create(data_provider) 35 | assert 0 == counter[0] 36 | assert 1 == getter() 37 | assert 1 == getter() 38 | scope.reset() 39 | assert 2 == getter() 40 | assert 2 == getter() 41 | scope.reset() 42 | assert 3 == getter() 43 | -------------------------------------------------------------------------------- /torchsim/core/eval2/basic_experiment_template.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict, Any, Callable 2 | 3 | from torchsim.core.eval.doc_generator.document import Document 4 | from torchsim.core.eval2.experiment_controller import ExperimentController 5 | from torchsim.core.eval2.experiment_template_base import ExperimentTemplateBase, TTopology, TopologyFactory 6 | from torchsim.core.eval2.measurement_manager import MeasurementManager, RunMeasurementManager 7 | 8 | 9 | class BasicExperimentTemplate(ExperimentTemplateBase[TTopology]): 10 | def setup_controller(self, topology: TTopology, controller: ExperimentController, 11 | run_measurement_manager: RunMeasurementManager): 12 | pass 13 | 14 | def publish_results(self, document: Document, docs_folder: str, measurement_manager: MeasurementManager, 15 | topology_parameters: List[str]): 16 | pass 17 | 18 | 19 | class BasicTopologyFactory(TopologyFactory[TTopology]): 20 | def __init__(self, topology: Callable[..., TTopology]): 21 | self._factory_method = topology 22 | 23 | def get_default_parameters(self) -> Dict[str, Any]: 24 | return {} 25 | 26 | def create_topology(self, **kwargs) -> TTopology: 27 | return self._factory_method(**kwargs) 28 | -------------------------------------------------------------------------------- /tests/templates/random_number_topology_adapter.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.eval.node_accessors.random_number_accessor import RandomNumberNodeAccessor 2 | from torchsim.core.eval.topology_adapter_base import TestableTopologyAdapterBase 3 | from torchsim.core.graph import Topology 4 | from torchsim.core.nodes.random_number_node import RandomNumberNode 5 | from torchsim.topologies.random_number_topology import RandomNumberTopology 6 | 7 | 8 | class RandomNumberTopologyTrainTestAdapter(TestableTopologyAdapterBase): 9 | _is_training: bool = True 10 | _topology: RandomNumberTopology 11 | _node: RandomNumberNode 12 | 13 | # def __init__(self): 14 | # self._is_training = True 15 | 16 | def is_in_training_phase(self, **kwargs) -> bool: 17 | return self._is_training 18 | 19 | def switch_to_training(self): 20 | self._is_training = True 21 | 22 | def switch_to_testing(self): 23 | self._is_training = False 24 | 25 | def get_topology(self) -> Topology: 26 | return self._topology 27 | 28 | def set_topology(self, topology: RandomNumberTopology): 29 | self._topology = topology 30 | self._node = topology.random_number_node 31 | 32 | def get_output_id(self): 33 | return RandomNumberNodeAccessor.get_output_id(self._node) -------------------------------------------------------------------------------- /torchsim/core/eval/metrics/entropy.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | 4 | def one_hot_entropy(codes: torch.Tensor): 5 | """Compute the entropy of a representation (code) using one-hot vectors. 6 | 7 | The entropy is computed under the following assumptions: 8 | 1. The code consists of a number of one-hot vectors 9 | 2. The component (one-hot) vectors have different distributions 10 | 3. The component vectors are considered independent 11 | 12 | The entropy is computed separately for each component vector. The total entropy is then computed as the sum of the 13 | entropies of the component codes. 14 | 15 | In TA experiments, a component vector corresponds to the SP output of an expert and an element in the one-hot 16 | component vector to a cluster center. 17 | 18 | Args: 19 | codes: A tensor containing the codes with dimensions (sample, component, element) 20 | 21 | Returns: 22 | The entropy of the code (sum of component entropies) 23 | """ 24 | probabilities = codes.sum(0) / codes.shape[0] # Sum over samples / number of samples 25 | probabilities[probabilities == 0] = 1 # Handle zero probabilities (log(1) == 0) 26 | entropy = -(probabilities * probabilities.log2()).sum() # Sum component entropies 27 | return entropy 28 | -------------------------------------------------------------------------------- /torchsim/core/models/flock/flock.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import torch 4 | from abc import ABC, abstractmethod 5 | 6 | from torchsim.core.memory.on_device import OnDevice 7 | from torchsim.core.models.expert_params import ParamsBase, ExpertParams 8 | from torchsim.core.models.flock.process import Process 9 | 10 | 11 | class Flock(OnDevice, ABC): 12 | 13 | _params: ExpertParams 14 | 15 | """A base class for a flock.""" 16 | def __init__(self, params, device): 17 | super().__init__(device) 18 | self.validate_params(params) 19 | 20 | self.buffer = None 21 | self._params = params 22 | 23 | def _determine_forward_pass(self, data: torch.Tensor, mask: Optional[torch.Tensor]): 24 | pass 25 | 26 | def _determine_learning(self, forward_mask): 27 | pass 28 | 29 | @staticmethod 30 | def _run_process(process: Process): 31 | """Runs and integrates a process, doing nothing if None is received.""" 32 | if process is None: 33 | return 34 | 35 | process.run_and_integrate() 36 | 37 | @abstractmethod 38 | def validate_params(self, params: ParamsBase): 39 | """Validate the params. Potentially also with respect to the state of the object. 40 | (Maybe we will not need it?).""" 41 | -------------------------------------------------------------------------------- /tests/core/eval2/test_run_topology.py: -------------------------------------------------------------------------------- 1 | from eval_utils import run_topology_with_ui, run_topology 2 | from torchsim.core.graph import Topology 3 | from torchsim.core.nodes import LambdaNode 4 | from torchsim.gui.observer_system import ObserverSystem 5 | from torchsim.gui.observer_system_void import ObserverSystemVoid 6 | 7 | 8 | class TopologyStub(Topology): 9 | def __init__(self, step_callback): 10 | super().__init__('cpu') 11 | 12 | self.add_node(LambdaNode(lambda inputs, outputs: step_callback(), 0, [])) 13 | 14 | 15 | class TestBasicExperimentTemplate: 16 | def test_run_topology(self): 17 | def callback(): 18 | callback.called = True 19 | 20 | callback.called = False 21 | ObserverSystem.initialized = False 22 | 23 | run_topology(TopologyStub(callback), max_steps=1, save_model_after_run=False) 24 | 25 | assert callback.called 26 | 27 | def test_run_topology_in_ui(self): 28 | def callback(): 29 | callback.called = True 30 | 31 | callback.called = False 32 | ObserverSystem.initialized = False 33 | observer_system = ObserverSystemVoid(None) 34 | 35 | run_topology_with_ui(TopologyStub(callback), max_steps=1, observer_system=observer_system) 36 | 37 | assert callback.called 38 | -------------------------------------------------------------------------------- /tests/core/node_accessors/test_se_dataset_navigation_accessor.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import torch 3 | 4 | from torchsim.core.datasets.dataset_se_base import SeDatasetSize 5 | from torchsim.core.eval.node_accessors.se_io_accessor import SeIoAccessor 6 | from torchsim.core.memory.tensor_creator import AllocatingCreator 7 | from torchsim.core.nodes.dataset_se_navigation_node import SamplingMethod, DatasetSENavigationParams, \ 8 | DatasetSeNavigationNode 9 | 10 | 11 | @pytest.mark.parametrize('device', ['cpu', 'cuda']) 12 | @pytest.mark.parametrize('sampling_method', [e for e in SamplingMethod]) 13 | def test_dataset_accessor_return_type(device, sampling_method): 14 | """Should produce identical sequences, only if seed is None and random order is required, they should be unique.""" 15 | params = DatasetSENavigationParams(SeDatasetSize.SIZE_24) 16 | 17 | # parametrized: 18 | params.sampling_method = sampling_method 19 | 20 | node = DatasetSeNavigationNode(params) 21 | node.allocate_memory_blocks(AllocatingCreator(device=device)) 22 | 23 | node._step() 24 | 25 | # note: the actual node accessor has been deleted in favor of SeIoAccessor, the functionality remains worth testing 26 | landmark_id = SeIoAccessor.get_landmark_id_int(node.outputs) 27 | 28 | assert type(landmark_id) is int 29 | 30 | 31 | -------------------------------------------------------------------------------- /run_experiment.bat: -------------------------------------------------------------------------------- 1 | echo HELP: takes the following parameters: 1) path to script (relative to torchsim) and 2) results folder, 3) the following arguments are passed to the python experiment sctipt and parsed by the parse_test_args(). 2 | 3 | if [%~1]==[] ( 4 | SET SCRIPT_NAME=torchsim\research\research_topics\rt_3_7_1_task0_analysis\experiments\task0_analysis_experiment.py 5 | ) else ( 6 | SET SCRIPT_NAME=%1 7 | ) 8 | 9 | if [%~2]==[] ( 10 | SET RESULTS_FOLDER=D:\torchsim\experiments-results\3_7_1-task0-analysis 11 | ) else ( 12 | SET RESULTS_FOLDER=%2 13 | ) 14 | 15 | echo /////////////////////////////////////////////////////////////////////////// preparing the environment 16 | set root=%AppData%\..\Local\Continuum\anaconda3 17 | call %root%/Scripts/activate.bat %root% 18 | call activate torchsim 19 | call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" 20 | setlocal 21 | set PYTHONPATH=%~dp0 22 | 23 | 24 | :repeat 25 | echo /////////////////////////////////////////////////////////////////////////// calling the script 26 | call python %SCRIPT_NAME% --save --load --alternative-results-folder=%RESULTS_FOLDER% %3 %4 %5 %6 27 | 28 | IF %ERRORLEVEL% NEQ 0 ( 29 | GOTO :repeat 30 | ) 31 | 32 | echo /////////////////////////////////////////////////////////////////////////// done 33 | endlocal 34 | pause 35 | -------------------------------------------------------------------------------- /torchsim/core/physics_model/rendered_world.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, List 2 | 3 | import torch 4 | from torchsim.core.nodes import BallShapes 5 | from torchsim.core.nodes.simple_bouncing_ball_node import BallRenderer 6 | from torchsim.core.physics_model.pymunk_physics import InstanceShape, Instance, PymunkParams 7 | 8 | 9 | class RenderWorld: 10 | def __init__(self, world_size: Tuple[int, int], radius: int = 9): 11 | self.world_size = world_size 12 | self.shapes_renderer_mapping = {InstanceShape.CIRCLE: BallRenderer(radius, BallShapes.DISC), 13 | InstanceShape.SQUARE: BallRenderer(radius, BallShapes.SQUARE), 14 | InstanceShape.TRIANGLE: BallRenderer(radius, BallShapes.TRIANGLE)} 15 | 16 | def to_tensor(self, tensors: List[torch.Tensor], params: PymunkParams): 17 | scene = torch.zeros(tuple(self.world_size) + (3,)) 18 | for tensor in tensors: 19 | instance = Instance.from_tensor(tensor, params) 20 | channel = torch.zeros(tuple(self.world_size)) 21 | self.shapes_renderer_mapping[instance.shape].render_ball_to(instance.init_position, channel) 22 | rgb = instance.color.to_color().get_rgb() 23 | for c in range(3): 24 | scene[:, :, c] += channel * rgb[c] 25 | return scene 26 | -------------------------------------------------------------------------------- /torchsim/playground/.ipynb_checkpoints/decorator-checkpoint.py: -------------------------------------------------------------------------------- 1 | def decorate(func): 2 | def func_wrapper(name): 3 | return f'called {func}({name})' 4 | 5 | return func_wrapper 6 | 7 | 8 | def decorate_class(cls): 9 | class Wrapper(object): 10 | def __init__(self, *args): 11 | self.wrapped = cls(*args) 12 | 13 | def __getattr__(self, name): 14 | print(f'Getting the {name} of {self.wrapped}') 15 | return getattr(self.wrapped, name) 16 | 17 | def __str__(self): 18 | return self.wrapped.__str__() 19 | 20 | return Wrapper 21 | 22 | 23 | def decorate_field(cls): 24 | def func_wrapper(*args): 25 | return f'field {cls} {args}' 26 | 27 | return func_wrapper 28 | 29 | 30 | @decorate 31 | def get_text(name): 32 | return "lorem ipsum, {0} dolor sit amet".format(name) 33 | 34 | 35 | @decorate_class 36 | class A: 37 | data: int 38 | 39 | def __init__(self, data): 40 | self.data = data 41 | 42 | def __str__(self) -> str: 43 | return f'A({self.data})' 44 | 45 | 46 | class B(A): 47 | 48 | def __init__(self): 49 | super().__init__(3) 50 | 51 | 52 | # def __init__(self): 53 | # super.__init__(3) 54 | 55 | 56 | print(get_text("John")) 57 | 58 | a = A(5) 59 | print(a) 60 | print(a.data) 61 | 62 | b = B() 63 | print(b) 64 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_3_space_benchmarks/adapters/se_dataset_ta_running_stats_adapter.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.graph import Topology 4 | from torchsim.core.model import Model 5 | from torchsim.research.experiment_templates.dataset_simulation_running_stats_template import \ 6 | DatasetSeTaSimulationRunningStatsAdapter 7 | 8 | 9 | class SeDatasetTaRunningStatsAdapter(DatasetSeTaSimulationRunningStatsAdapter): 10 | """ 11 | a thing which can provide memory/fps stats 12 | """ 13 | 14 | _last_step_duration: float = 0.001 15 | 16 | def set_topology(self, topology) -> Topology: 17 | self._topology = topology 18 | return self._topology 19 | 20 | def get_topology(self) -> Model: 21 | return self._topology 22 | 23 | def get_memory_allocated(self) -> float: 24 | return torch.cuda.memory_allocated() / (1024 ** 2) 25 | 26 | def get_title(self) -> str: 27 | return 'FPS and memory requirements for different Flock params' 28 | 29 | def get_max_memory_allocated(self) -> float: 30 | return torch.cuda.max_memory_allocated() / (1024 ** 2) 31 | 32 | def get_max_memory_cached(self) -> float: 33 | return torch.cuda.max_memory_cached() / (1024 ** 2) 34 | 35 | def get_memory_cached(self) -> float: 36 | return torch.cuda.memory_cached() / (1024 ** 2) 37 | -------------------------------------------------------------------------------- /torchsim/topologies/grid_world_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.graph import Topology 2 | from torchsim.core.graph.connection import Connector 3 | from torchsim.core.nodes.internals.grid_world import GridWorldActionDescriptor, GridWorldParams 4 | from torchsim.core.nodes import ActionMonitorNode 5 | from torchsim.core.nodes import GridWorldNode 6 | from torchsim.core.nodes import RandomNumberNode 7 | 8 | 9 | class GridWorldTopology(Topology): 10 | _node_grid_world: GridWorldNode 11 | _node_action_monitor: ActionMonitorNode 12 | 13 | def __init__(self): 14 | super().__init__(device='cuda') 15 | actions_descriptor = GridWorldActionDescriptor() 16 | node_action_monitor = ActionMonitorNode(actions_descriptor) 17 | 18 | params = GridWorldParams() 19 | node_grid_world = GridWorldNode(params) 20 | 21 | random_action_generator = RandomNumberNode(upper_bound=len(actions_descriptor.action_names())) 22 | 23 | self.add_node(node_grid_world) 24 | self.add_node(node_action_monitor) 25 | self.add_node(random_action_generator) 26 | 27 | Connector.connect(random_action_generator.outputs.one_hot_output, 28 | node_action_monitor.inputs.action_in) 29 | Connector.connect(node_action_monitor.outputs.action_out, 30 | node_grid_world.inputs.agent_action) 31 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/adapters/task_0_stats_basic_adapter.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.research_topics.rt_1_1_3_space_benchmarks.adapters.se_dataset_ta_running_stats_adapter import \ 2 | SeDatasetTaRunningStatsAdapter 3 | from torchsim.research.se_tasks.adapters.task_stats_adapter import TaskStatsAdapter 4 | from torchsim.research.se_tasks.topologies.se_task0_basic_topology import SeT0BasicTopology 5 | 6 | 7 | class Task0StatsBasicAdapter(TaskStatsAdapter, SeDatasetTaRunningStatsAdapter): 8 | """The same as the base class, but also provides aux SE stats.""" 9 | 10 | _topology: SeT0BasicTopology 11 | 12 | def get_task_id(self) -> float: 13 | return self._topology.se_io.get_task_id() 14 | 15 | def get_task_instance_id(self) -> float: 16 | return self._topology.se_io.get_task_instance_id() 17 | 18 | def get_task_status(self) -> float: 19 | return self._topology.se_io.get_task_status() 20 | 21 | def get_task_instance_status(self) -> float: 22 | return self._topology.se_io.get_task_instance_status() 23 | 24 | def get_reward(self) -> float: 25 | return self._topology.se_io.get_reward() 26 | 27 | def get_testing_phase(self) -> float: 28 | return self._topology.se_io.get_testing_phase() 29 | 30 | def switch_learning(self, learning_on: bool): 31 | self._topology.switch_learning(learning_on) 32 | -------------------------------------------------------------------------------- /tests/core/nodes/test_grayscale_node.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | import torch 4 | 5 | from torchsim.core.graph.connection import Connector 6 | from torchsim.core.graph.slots import MemoryBlock 7 | from torchsim.core.memory.tensor_creator import AllocatingCreator 8 | from torchsim.core.nodes.grayscale_node import GrayscaleNode 9 | from torchsim.core.utils.tensor_utils import same 10 | 11 | 12 | class TestGrayscaleNode: 13 | 14 | @pytest.mark.parametrize('squeeze_channel, tensor_data', [(True, [1, 0, 0.2126, 0.7152, 0.0722]), 15 | (False, [[1], [0], [0.2126], [0.7152], [0.0722]])]) 16 | def test_grayscale_node(self, squeeze_channel, tensor_data): 17 | device = 'cpu' 18 | dtype = torch.float32 19 | 20 | input_tensor = torch.tensor([[1, 1, 1], [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]], device=device, dtype=dtype) 21 | expected_tensor = torch.tensor(tensor_data, device=device, dtype=dtype) 22 | 23 | mb0 = MemoryBlock() 24 | mb0.tensor = input_tensor 25 | 26 | gn = GrayscaleNode(squeeze_channel=squeeze_channel) 27 | Connector.connect(mb0, gn.inputs.input) 28 | gn.allocate_memory_blocks(AllocatingCreator(device)) 29 | gn._step() 30 | 31 | assert same(gn.outputs.output.tensor, expected_tensor, 0.000001) # allow small epsilon differences 32 | -------------------------------------------------------------------------------- /tests/core/eval/test_doc_generator.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import tempfile 3 | import torch 4 | 5 | from torchsim.core.eval.doc_generator.document import Document 6 | from torchsim.core.eval.doc_generator.figure import Figure 7 | from torchsim.core.eval.doc_generator.heading import Heading 8 | from torchsim.core.eval.doc_generator.matrix import Matrix 9 | 10 | 11 | def test_doc_creation(): 12 | document = Document().\ 13 | add(Heading("Look at his heading")). \ 14 | add("This is a very nice document.

").\ 15 | add(Figure.from_params('test_image.png', 16 | "Behold our powerful visualization", 17 | height=200, 18 | width=400)).\ 19 | add(Matrix(torch.rand((2, 3)), m_labels=['a', 'b'], n_labels=['10', '20', '30'], 20 | format_func=lambda x: "%.5f" % x)) 21 | 22 | # The following line will write to a non-temporary file. 23 | # Uncomment if you want to see what the html file looks like. 24 | # document.write_file("test_file.html") 25 | 26 | with tempfile.TemporaryFile() as document_file: 27 | doc_text = document.as_text() 28 | document_file.write(doc_text.encode('UTF-8')) 29 | document_file.seek(0) 30 | read_text = document_file.readline() 31 | 32 | assert read_text.startswith(b"") 33 | -------------------------------------------------------------------------------- /torchsim/topologies/toyarch_groups/r1ncm_group.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Tuple 2 | 3 | from torchsim.core.graph.connection import Connector 4 | from torchsim.research.research_topics.rt_2_1_2_learning_rate.node_groups.ta_multilayer_node_group_params import \ 5 | MultipleLayersParams 6 | from torchsim.topologies.toyarch_groups.ncmr1_group import ActionTaskOutputs 7 | from torchsim.topologies.toyarch_groups.ncm_group import NCMGroupInputs, NCMGroupBase 8 | 9 | 10 | class R1NCMGroup(NCMGroupBase[NCMGroupInputs, ActionTaskOutputs]): 11 | """N layers of flocks, where the first one takes and input and returns its reconstructed prediction - 12 | used for example for actions.""" 13 | 14 | def __init__(self, 15 | conv_layers_params: MultipleLayersParams, 16 | model_seed: Optional[int] = 321, 17 | image_size: Tuple[int, int, int] = (24, 24, 3)): 18 | super().__init__( 19 | inputs=NCMGroupInputs(self), 20 | outputs=ActionTaskOutputs(self), 21 | conv_layers_params=conv_layers_params, 22 | model_seed=model_seed, 23 | image_size=image_size, 24 | name="R1NCMGroup") 25 | 26 | Connector.connect( 27 | self.conv_layers[0].expert_flock_nodes[0].outputs.sp.predicted_reconstructed_input, 28 | self.outputs.predicted_reconstructed_input.input 29 | ) 30 | -------------------------------------------------------------------------------- /torchsim/core/graph/slot_container.py: -------------------------------------------------------------------------------- 1 | from typing import Generic 2 | 3 | from abc import abstractmethod 4 | 5 | from torchsim.core.graph.node_base import NodeBase 6 | from torchsim.core.graph.slot_container_base import GenericInputsBase, TSlotContainerBase, GenericMemoryBlocks, TSlot 7 | from torchsim.core.graph.slots import BufferMemoryBlock 8 | from torchsim.core.graph.unit import Unit 9 | 10 | 11 | class MemoryBlocks(GenericMemoryBlocks[NodeBase]): 12 | @abstractmethod 13 | def prepare_slots(self, unit: Unit): 14 | """Connect tensors from the unit with the memory blocks here.""" 15 | pass 16 | 17 | 18 | class Inputs(GenericInputsBase[NodeBase]): 19 | pass 20 | 21 | 22 | class SlotSection(Generic[TSlotContainerBase]): 23 | _container: TSlotContainerBase 24 | 25 | def __init__(self, container: TSlotContainerBase): 26 | # This init is important for multiple inheritance to work (when not present, not all init methods in hierarchy 27 | # are called 28 | self._container = container 29 | 30 | def create(self, name: str) -> TSlot: 31 | return self._container.create(name) 32 | 33 | 34 | class MemoryBlocksSection(SlotSection[GenericMemoryBlocks[NodeBase]]): 35 | 36 | def create_buffer(self, name: str) -> BufferMemoryBlock: 37 | return self._container.create_buffer(name) 38 | 39 | 40 | class InputsSection(SlotSection[Inputs]): 41 | pass 42 | -------------------------------------------------------------------------------- /tests/core/nodes/test_grid_world.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.nodes.internals.grid_world import GridWorldParams 2 | from torchsim.core.nodes.grid_world_node import GridWorldNode 3 | from tests.core.nodes.node_unit_test_base import NodeTestBase 4 | 5 | 6 | class TestGridWorld(NodeTestBase): 7 | params = GridWorldParams('MapA') 8 | 9 | input_values = [[1, 0, 0, 0], 10 | [0, 1, 0, 0], 11 | [0, 0, 1, 0], 12 | [0, 0, 0, 1]] 13 | 14 | pos = params.agent_pos 15 | expected_results = [[pos[1] + 0, pos[0] - 1], 16 | [pos[1] + 0, pos[0] + 0], 17 | [pos[1] + 1, pos[0] + 0], 18 | [pos[1] + 0, pos[0] + 0]] 19 | 20 | @classmethod 21 | def setup_class(cls, device: str = 'cuda'): 22 | super().setup_class(device) 23 | cls._dim = 1 24 | 25 | def _generate_input_tensors(self): 26 | for values in self.input_values: 27 | yield [self._creator.tensor(values, dtype=self._dtype, device=self._device)] 28 | 29 | def _generate_expected_results(self): 30 | for values in self.expected_results: 31 | yield [self._creator.tensor(values, dtype=self._dtype, device=self._device)] 32 | 33 | def _create_node(self): 34 | return GridWorldNode(self.params) 35 | 36 | def _extract_results(self, node): 37 | return [node._unit.pos.clone()] 38 | -------------------------------------------------------------------------------- /torchsim/significant_nodes/environment_base.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import Tuple 3 | 4 | from torchsim.core.graph.node_base import EmptyInputs 5 | from torchsim.core.graph.node_group import NodeGroupBase, GroupOutputs 6 | from torchsim.core.models.expert_params import ParamsBase 7 | 8 | 9 | class CommonEnvironmentOutputs(GroupOutputs): 10 | def __init__(self, owner): 11 | super().__init__(owner) 12 | self.data = self.create("Data") 13 | self.label = self.create("Label") 14 | 15 | 16 | class EnvironmentParamsBase(ParamsBase, ABC): 17 | env_size: Tuple[int, int, int] 18 | n_shapes: int 19 | 20 | def __str__(self): 21 | return str(self.__dict__) 22 | 23 | def __repr__(self): 24 | return self.__str__() 25 | 26 | 27 | class EnvironmentBase(NodeGroupBase[EmptyInputs, CommonEnvironmentOutputs], ABC): 28 | 29 | def __init__(self, params: EnvironmentParamsBase, name: str): 30 | super().__init__(name, outputs=CommonEnvironmentOutputs(self)) 31 | 32 | self.validate_params(params) 33 | 34 | self.params = params 35 | 36 | def __str__(self): 37 | return self._name 38 | 39 | @abstractmethod 40 | def get_correct_label_memory_block(self): 41 | pass 42 | 43 | @staticmethod 44 | @abstractmethod 45 | def validate_params(params: EnvironmentParamsBase): 46 | """Check if the params are valid.""" 47 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_3_space_benchmarks/adapters/se_ta_running_stats_adapter.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.experiment_templates.simulation_running_stats_template import SeTaSimulationRunningStatsAdapter 2 | from torchsim.research.research_topics.rt_1_1_3_space_benchmarks.adapters.se_dataset_ta_running_stats_adapter import \ 3 | SeDatasetTaRunningStatsAdapter 4 | 5 | 6 | class SeTaRunningStatsAdapter(SeDatasetTaRunningStatsAdapter, SeTaSimulationRunningStatsAdapter): 7 | """ 8 | the same as the base class, but also provides aux SE stats 9 | """ 10 | 11 | def get_task_id(self) -> float: 12 | return self._topology._node_se_connector.outputs.metadata_task_id.tensor.cpu().item() 13 | 14 | def get_task_instance_id(self) -> float: 15 | return self._topology._node_se_connector.outputs.metadata_task_instance_id.tensor.cpu().item() 16 | 17 | def get_task_status(self) -> float: 18 | return self._topology._node_se_connector.outputs.metadata_task_status.tensor.cpu().item() 19 | 20 | def get_task_instance_status(self) -> float: 21 | return self._topology._node_se_connector.outputs.metadata_task_instance_status.tensor.cpu().item() 22 | 23 | def get_reward(self) -> float: 24 | return self._topology._node_se_connector.outputs.reward.tensor.cpu().item() 25 | 26 | def get_testing_phase(self) -> float: 27 | return self._topology._node_se_connector.outputs.metadata_testing_phase.tensor.cpu().item() 28 | # -------------------------------------------------------------------------------- /tests/core/datasets/test_sequence.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.memory.tensor_creator import AllocatingCreator 2 | from torchsim.core.utils.sequence_generator import SequenceGenerator 3 | from torchsim.core.nodes.sequence_node import SequenceNode 4 | import numpy as np 5 | 6 | 7 | # Test a range sequence 8 | def test_range_seq(): 9 | seq = [1, 2, 3] 10 | iterator = SequenceGenerator.from_list(range(1, 4)) 11 | for element in seq * 2: 12 | assert element == next(iterator) 13 | 14 | 15 | # Test a deterministic sequence 16 | def test_seq(): 17 | seq = [1, 2, 3, 4, 5, 10, 2, 2] 18 | iterator = SequenceGenerator.from_list(seq) 19 | for element in seq * 2: 20 | assert element == next(iterator) 21 | 22 | 23 | # Test a sequence node 24 | def test_seq_node(): 25 | seq = [1, 2, 3, 4, 5, 10, 2, 2] 26 | iterator = SequenceGenerator.from_list(seq) 27 | node = SequenceNode(seq=iterator) 28 | node._prepare_unit(AllocatingCreator(device='cpu')) 29 | for element in seq * 2: 30 | node.step() 31 | assert element == node.outputs.output.tensor.item() 32 | 33 | 34 | # Test multiple seqs with deterministic transitions 35 | def test_multiple(): 36 | seq_1 = [1, 2, 3] 37 | seq_2 = [9, 8] 38 | transitions = np.matrix([[0., 1.], [1., 0.]]) 39 | combined_seq = seq_1 + seq_2 40 | iterator = SequenceGenerator.from_multiple([seq_1, seq_2], transitions) 41 | for expected, actual in zip(combined_seq, iterator): 42 | assert expected == actual 43 | 44 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_1_1_3_space_benchmarks/debug/debug_lrf_runner.py: -------------------------------------------------------------------------------- 1 | 2 | from eval_utils import run_just_model, parse_test_args 3 | from torchsim.research.research_topics.rt_1_1_3_space_benchmarks.topologies.se_dataset_sp_lrf_debug import \ 4 | SeDatasetSpLrfDebug 5 | 6 | 7 | 8 | def run_experiment(use_gui: bool, save: bool, load: bool, clear: bool): 9 | # specify the sets of params to be used in the consecutive runs inside the experiment.run() 10 | params = [ 11 | {'eox': 2, 'eoy': 2, 'num_cc': 10}, 12 | {'eox': 2, 'eoy': 2, 'num_cc': 25}, 13 | {'eox': 2, 'eoy': 2, 'num_cc': 50}, 14 | {'eox': 2, 'eoy': 2, 'num_cc': 100}, 15 | {'eox': 2, 'eoy': 2, 'num_cc': 250}, 16 | {'eox': 2, 'eoy': 2, 'num_cc': 350}, 17 | {'eox': 2, 'eoy': 2, 'num_cc': 550}, 18 | ] 19 | 20 | # NOT supported 21 | # experiment = SpLearningConvergenceExperimentTemplate( 22 | # MnistSpLearningConvergenceTopologyAdapter(), 23 | # MnistSpTopology, 24 | # params, 25 | # max_steps=100, 26 | # measurement_period=1, 27 | # evaluation_period=15) 28 | 29 | if use_gui: 30 | # run_just_model(SeDatasetSpLrfDebug(**params[0]), gui=True) 31 | run_just_model(SeDatasetSpLrfDebug(**params[0]), gui=True) 32 | else: 33 | # experiment.run() 34 | pass 35 | 36 | 37 | if __name__ == '__main__': 38 | args = parse_test_args() 39 | run_experiment(args.run_gui, args.save, args.load, args.clear) -------------------------------------------------------------------------------- /tests/core/utils/list_list_utils.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import torch 3 | 4 | from torchsim.core.utils.tensor_utils import same 5 | from torchsim.utils.list_utils import flatten_list, same_lists 6 | 7 | 8 | def test_flatten_list(): 9 | list_of_lists = [[], [1, 2, 3], [0, 0], [], [], [5, 6, 7, 8], []] 10 | 11 | result = flatten_list(list_of_lists) 12 | expected_result = [1, 2, 3, 0, 0, 5, 6, 7, 8] 13 | 14 | assert result == expected_result 15 | 16 | 17 | @pytest.mark.parametrize('list1, list2, eps, expected_result', [ 18 | ([1, 1.3, -15, 0], [1, 1.3, -15, 0], None, True), 19 | ([1, 1.3, -15, float('nan')], [1, 1.3, -15, 0], None, False), 20 | ([float('nan'), 0], [float('nan'), 0], None, True), 21 | ([0, float('nan')], [float('nan'), 0], None, False), 22 | ([], [], None, True), 23 | ([0.9999, 1.39, -15.356], [1, 1.3, -15.356], 0.01, False), 24 | ([0.9999, 1.39, -15.356], [1, 1.3, -15.356], 0.1, True) 25 | ]) 26 | @pytest.mark.parametrize('comparison_method', ([same_lists, same])) 27 | def test_same_list(comparison_method, list1, list2, eps, expected_result): 28 | """This test tst together two util methods for comparing: same() for tensors and same_lists for lists.""" 29 | 30 | if comparison_method == same_lists: 31 | input1 = list1 32 | input2 = list2 33 | else: 34 | input1 = torch.tensor(list1) 35 | input2 = torch.tensor(list2) 36 | 37 | result = comparison_method(input1, input2, eps=eps) 38 | 39 | assert expected_result == result 40 | -------------------------------------------------------------------------------- /tests/core/datasets/test_mnist.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.datasets.mnist import DatasetMNIST 2 | from torchsim.core.test_optimizations import small_dataset_for_tests_allowed 3 | 4 | 5 | def test_load_all(): 6 | data, labels = DatasetMNIST().get_all() 7 | s = data.size() 8 | # self.assertEqual(data.size(), torch.Size((60000, 28, 28))) 9 | # self.assertEqual(labels.size(), torch.Size((60000, 28, 28))) 10 | if small_dataset_for_tests_allowed(): 11 | assert data.size() == (2000, 28, 28) 12 | assert labels.size() == (2000,) 13 | else: 14 | assert data.size() == (60000, 28, 28) 15 | assert labels.size() == (60000,) 16 | 17 | 18 | def test_get_filtered_0(): 19 | data, labels = DatasetMNIST().get_filtered([0]) 20 | if small_dataset_for_tests_allowed(): 21 | assert data.size() == (191, 28, 28) 22 | assert labels.size() == (191,) 23 | else: 24 | assert data.size() == (5923, 28, 28) 25 | assert labels.size() == (5923,) 26 | 27 | 28 | def test_get_filtered_sum_all(): 29 | count = sum([DatasetMNIST().get_filtered([i]).labels.size(0) for i in range(10)]) 30 | if small_dataset_for_tests_allowed(): 31 | assert 2000 == count 32 | else: 33 | assert 60000 == count 34 | 35 | 36 | def test_get_filtered_sum_first_three(): 37 | count_0_1_2 = sum([DatasetMNIST().get_filtered([i]).labels.size(0) for i in range(3)]) 38 | count_012 = DatasetMNIST().get_filtered([0, 1, 2]).labels.size(0) 39 | assert count_012 == count_0_1_2 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/core/nodes/test_salient_region_node.py: -------------------------------------------------------------------------------- 1 | from typing import Generator, List, Any 2 | 3 | import torch 4 | from torchsim.core.graph.worker_node_base import WorkerNodeBase 5 | from torchsim.core.nodes.salient_region_node import SalientRegionNode, SalientRegionParams 6 | from tests.core.nodes.node_unit_test_base import NodeTestBase 7 | 8 | 9 | class TestSalientRegionNode(NodeTestBase): 10 | def _generate_input_tensors(self) -> Generator[List[torch.Tensor], None, None]: 11 | input_size = 10 12 | saliency_map = self._creator.zeros(input_size, input_size, dtype=torch.float) 13 | saliency_map[4, 4] = 1 14 | yield [saliency_map] 15 | 16 | def _generate_expected_results(self) -> Generator[List[Any], None, None]: 17 | y, x, height, width = 4, 4, 1, 1 18 | yield [self._creator.tensor([y, x, height, width], dtype=torch.float)] 19 | 20 | def _create_node(self) -> WorkerNodeBase: 21 | return SalientRegionNode() 22 | 23 | 24 | class TestFixedSizeSalientRegionNode(TestSalientRegionNode): 25 | _fixed_region_size = 2 26 | 27 | def _generate_expected_results(self) -> Generator[List[Any], None, None]: 28 | y, x, height, width = 4, 4, self._fixed_region_size, self._fixed_region_size 29 | yield [self._creator.tensor([y, x, height, width], dtype=torch.float)] 30 | 31 | def _create_node(self) -> WorkerNodeBase: 32 | params = SalientRegionParams(use_fixed_fixed_region_size=True, fixed_region_size=self._fixed_region_size) 33 | return SalientRegionNode(params) 34 | -------------------------------------------------------------------------------- /torchsim/core/persistence/saver.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from ruamel.yaml import YAML 4 | 5 | from torchsim.core.persistence.persistor import Persistor 6 | from torchsim.utils.os_utils import create_dir 7 | 8 | 9 | class Saver(Persistor): 10 | _children: List['Saver'] 11 | 12 | def __init__(self, folder_name: str, parent: 'Saver' = None): 13 | """See Persistor.__init__. 14 | 15 | Note that this also creates the folder so that any custom data can be stored in there. 16 | """ 17 | super().__init__(folder_name, parent) 18 | 19 | self._children = [] 20 | self._create_folder() 21 | 22 | def create_child(self, folder_name: str) -> 'Saver': 23 | """Initialize a sub-saver. 24 | 25 | Args: 26 | folder_name: The folder name of the child saver relative to this saver's folder. 27 | """ 28 | child = Saver(folder_name, self) 29 | self._children.append(child) 30 | return child 31 | 32 | def save(self): 33 | """Saves the saver and its children on the disk.""" 34 | for child in self._children: 35 | child.save() 36 | 37 | self._save_description() 38 | 39 | def _create_folder(self): 40 | full_path = self.get_full_folder_path() 41 | create_dir(full_path) 42 | 43 | def _save_description(self): 44 | if len(self._description) > 0: 45 | yaml = YAML() 46 | with open(self._get_description_path(), 'w') as f: 47 | yaml.dump(self._description, f) 48 | -------------------------------------------------------------------------------- /torchsim/topologies/bottom_up_attention_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.datasets.dataset_se_base import SeDatasetSize 2 | from torchsim.core.graph import Topology 3 | from torchsim.core.graph.connection import Connector 4 | from torchsim.core.nodes import ActionMonitorNode 5 | from torchsim.core.nodes import DatasetSeObjectsNode, DatasetSeObjectsParams, DatasetConfig 6 | from torchsim.core.nodes.bottom_up_attention_group import BottomUpAttentionGroup 7 | 8 | 9 | class BottomUpAttentionTopology(Topology): 10 | """An example of use of the bottom up attention. 11 | 12 | Connects the dataset to the BottomUpAttentionGroup which focuses on moving areas of the input. 13 | """ 14 | _node_se_dataset: DatasetSeObjectsNode 15 | _node_action_monitor: ActionMonitorNode 16 | 17 | def __init__(self, params: DatasetSeObjectsParams = None): 18 | super().__init__(device='cuda') 19 | if params is None: 20 | self._params = DatasetSeObjectsParams(dataset_config=DatasetConfig.TRAIN_TEST, 21 | dataset_size=SeDatasetSize.SIZE_32) 22 | else: 23 | self._params = params 24 | 25 | self._node_se_dataset = DatasetSeObjectsNode(self._params) 26 | self.add_node(self._node_se_dataset) 27 | 28 | self._attention_group = BottomUpAttentionGroup() 29 | self.add_node(self._attention_group) 30 | 31 | Connector.connect(self._node_se_dataset.outputs.image_output, 32 | self._attention_group.inputs.image) 33 | 34 | 35 | -------------------------------------------------------------------------------- /torchsim/core/eval/metrics/sp_convergence_metrics.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.utils.tensor_utils import average_abs_values_to_float 4 | 5 | 6 | def average_sp_delta(cluster_center_deltas: torch.Tensor) -> float: 7 | """Should converge towards 0. 8 | 9 | Args: 10 | cluster_center_deltas: [flock_size, n_cluster_centers, input_size] 11 | 12 | Returns: 13 | Average delta in one dimension (sum of deltas divided by flock_size, n_cluster_centers, input_size). 14 | """ 15 | return average_abs_values_to_float(cluster_center_deltas) 16 | 17 | 18 | def average_boosting_duration(cluster_boosting_durations: torch.Tensor) -> float: 19 | """Should be 0 in case nothing is boosted. 20 | 21 | Args: 22 | cluster_boosting_durations: [flock_size, n_cluster_centers]: how many steps is each cluster boosted 23 | 24 | Returns: 25 | Sum of cluster_boosting_durations divided by total num of cluster centers in the flock. 26 | """ 27 | return average_abs_values_to_float(cluster_boosting_durations) 28 | 29 | 30 | def num_boosted_clusters(cluster_boosting_durations: torch.Tensor) -> float: 31 | """Returns number of boosted clusters (boosting_duration > 0) divided by total num. of clusters in the flock. 32 | Args: 33 | cluster_boosting_durations: tensor in the flock 34 | Returns: value between 0 (no boosting) and 1 (all clusters boosted) 35 | """ 36 | 37 | nonzeros = float(cluster_boosting_durations.nonzero().size(0)) 38 | return nonzeros / cluster_boosting_durations.numel() 39 | -------------------------------------------------------------------------------- /torchsim/topologies/switch_topology.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.graph import Topology 4 | from torchsim.core.graph.connection import Connector 5 | from torchsim.core.nodes import DatasetMNISTParams, DatasetMNISTNode 6 | from torchsim.core.nodes import RandomNoiseParams, RandomNoiseNode 7 | from torchsim.core.nodes import SwitchNode 8 | 9 | 10 | class SwitchTopology(Topology): 11 | """Topology for testing the SwitchNode. 12 | 13 | The topology connects the MNIST label (1 or 2, to pick input), MNIST digits, and noise as inputs to the 14 | SwitchNode. The node's output will be a MNIST '1' digit or noise depending on the input label. 15 | """ 16 | _mnist_params: DatasetMNISTParams = DatasetMNISTParams(class_filter=[1, 2], one_hot_labels=False) 17 | _noise_params: RandomNoiseParams = RandomNoiseParams(torch.Size((28, 28)), distribution='Normal', amplitude=.3) 18 | 19 | def __init__(self): 20 | super().__init__(device='cuda') 21 | 22 | noise_node = RandomNoiseNode(params=self._noise_params) 23 | self.add_node(noise_node) 24 | 25 | mnist_node = DatasetMNISTNode(params=self._mnist_params) 26 | self.add_node(mnist_node) 27 | 28 | switch_node = SwitchNode(n_inputs=2, get_index_from_input=True) 29 | self.add_node(switch_node) 30 | 31 | Connector.connect(mnist_node.outputs.label, switch_node.inputs.switch_signal) 32 | Connector.connect(mnist_node.outputs.data, switch_node.inputs[0]) 33 | Connector.connect(noise_node.outputs.output, switch_node.inputs[1]) 34 | 35 | -------------------------------------------------------------------------------- /tests/core/nodes/test_constant_node.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.nodes.constant_node import ConstantNode 2 | from tests.core.nodes.node_unit_test_base import NodeTestBase 3 | 4 | 5 | class TestConstantNode: 6 | 7 | class TestConstantNode1(NodeTestBase): 8 | @classmethod 9 | def setup_class(cls, device: str = 'cuda'): 10 | super().setup_class() 11 | cls._dim = [1, 2, 3] 12 | cls._const = 10 13 | 14 | def _generate_input_tensors(self): 15 | yield [] 16 | 17 | def _generate_expected_results(self): 18 | yield [self._creator.full(self._dim, fill_value=self._const, device=self._device, dtype=self._dtype)] 19 | 20 | def _create_node(self): 21 | return ConstantNode(shape=self._dim, constant=self._const) 22 | 23 | class TestConstantNode2(NodeTestBase): 24 | @classmethod 25 | def setup_class(cls, device: str = 'cuda'): 26 | super().setup_class() 27 | cls._dim = [5, 5] 28 | cls._const = 7 29 | 30 | def _generate_input_tensors(self): 31 | yield [] 32 | 33 | def _generate_expected_results(self): 34 | yield [self._creator.full(self._dim, fill_value=self._const, device=self._device, dtype=self._dtype)] 35 | 36 | def _create_node(self): 37 | return ConstantNode(shape=self._dim, constant=self._const) 38 | 39 | def test_int_shape(self): 40 | node1 = ConstantNode((1,)) 41 | node2 = ConstantNode(1) 42 | 43 | assert node1._shape == node2._shape 44 | -------------------------------------------------------------------------------- /tests/core/nodes/test_unsqueeze_node.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from typing import Generator, List, Any 3 | 4 | from torchsim.core.graph.worker_node_base import WorkerNodeBase 5 | from torchsim.core.nodes import UnsqueezeNode 6 | from tests.core.nodes.node_unit_test_base import NodeTestBase 7 | 8 | 9 | class TestUnsqueezeNode0(NodeTestBase): 10 | def _generate_input_tensors(self) -> Generator[List[torch.Tensor], None, None]: 11 | yield [ 12 | self._creator.zeros((2, 1, 3), device=self._device, dtype=self._dtype) 13 | ] 14 | 15 | def _generate_expected_results(self) -> Generator[List[Any], None, None]: 16 | yield [ 17 | self._creator.zeros((1, 2, 1, 3), device=self._device, dtype=self._dtype) 18 | ] 19 | 20 | def _create_node(self) -> WorkerNodeBase: 21 | return UnsqueezeNode(dim=0) 22 | 23 | 24 | class TestUnsqueezeNode1(NodeTestBase): 25 | def _generate_input_tensors(self) -> Generator[List[torch.Tensor], None, None]: 26 | yield [ 27 | self._creator.zeros((2, 1, 3), device=self._device, dtype=self._dtype), 28 | self._creator.zeros(2, device=self._device, dtype=self._dtype) 29 | ] 30 | 31 | def _generate_expected_results(self) -> Generator[List[Any], None, None]: 32 | yield [ 33 | self._creator.zeros((2, 1, 1, 3), device=self._device, dtype=self._dtype), 34 | self._creator.zeros((2, 1), device=self._device, dtype=self._dtype) 35 | ] 36 | 37 | def _create_node(self) -> WorkerNodeBase: 38 | return UnsqueezeNode(dim=1) 39 | -------------------------------------------------------------------------------- /tests/core/nodes/test_inverse_projection.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.graph import Topology 4 | from torchsim.core.graph.connection import Connector 5 | from torchsim.core.graph.invertible_node import InversePassOutputPacket 6 | from torchsim.core.nodes.fork_node import ForkNode 7 | from torchsim.core.nodes.join_node import JoinNode 8 | from torchsim.core.nodes.constant_node import ConstantNode 9 | from torchsim.core.utils.tensor_utils import same 10 | 11 | 12 | def test_inverse_fork_join(): 13 | """Checks that if you fork and join, the inverse projection will only have one tensor result.""" 14 | 15 | device = 'cpu' 16 | dtype = torch.float32 17 | 18 | graph = Topology(device) 19 | 20 | source_node = ConstantNode(shape=(2, 4), constant=0) 21 | fork_node = ForkNode(dim=1, split_sizes=[1, 3]) 22 | join_node = JoinNode(dim=1, n_inputs=2) 23 | 24 | graph.add_node(source_node) 25 | graph.add_node(fork_node) 26 | graph.add_node(join_node) 27 | 28 | Connector.connect(source_node.outputs.output, fork_node.inputs.input) 29 | Connector.connect(fork_node.outputs[0], join_node.inputs[0]) 30 | Connector.connect(fork_node.outputs[1], join_node.inputs[1]) 31 | 32 | graph.step() 33 | 34 | output_tensor = torch.rand((2, 4), device=device, dtype=dtype) 35 | inverse_pass_packet = InversePassOutputPacket(output_tensor, join_node.outputs.output) 36 | results = join_node.recursive_inverse_projection_from_output(inverse_pass_packet) 37 | 38 | assert 1 == len(results) 39 | assert same(results[0].tensor, output_tensor) 40 | -------------------------------------------------------------------------------- /torchsim/core/eval/node_accessors/sp_node_accessor.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.nodes.spatial_pooler_node import SpatialPoolerFlockNode 4 | 5 | 6 | class SpatialPoolerFlockNodeAccessor: 7 | """Adaptor for the SpatialPoolerFlockNode allowing access to the basic measurable values.""" 8 | 9 | @staticmethod 10 | def get_output_id(node: SpatialPoolerFlockNode) -> int: 11 | """Get argmax of the output of the spatial pooler. 12 | 13 | Args: 14 | node: target node 15 | 16 | Returns: 17 | Scalar from the range <0, sp_size). 18 | """ 19 | assert node.params.flock_size == 1 20 | max_id = torch.argmax(node.outputs.sp.forward_clusters.tensor) 21 | return max_id.to('cpu').data.item() 22 | 23 | @staticmethod 24 | def get_output_tensor(node: SpatialPoolerFlockNode) -> torch.Tensor: 25 | """ 26 | Args: 27 | node: 28 | Returns: tensor containing the output of the SP 29 | """ 30 | return node.outputs.sp.forward_clusters.tensor 31 | 32 | @staticmethod 33 | def get_reconstruction(node: SpatialPoolerFlockNode) -> torch.Tensor: 34 | return node.outputs.sp.current_reconstructed_input.tensor 35 | 36 | @staticmethod 37 | def get_sp_deltas(node: SpatialPoolerFlockNode) -> torch.Tensor: 38 | return node.memory_blocks.sp.cluster_center_deltas.tensor 39 | 40 | @staticmethod 41 | def get_sp_boosting_durations(node: SpatialPoolerFlockNode) -> torch.Tensor: 42 | return node.memory_blocks.sp.cluster_boosting_durations.tensor 43 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/adapters/task_1_stats_basic_adapter.py: -------------------------------------------------------------------------------- 1 | from torchsim.research.research_topics.rt_1_1_3_space_benchmarks.adapters.se_dataset_ta_running_stats_adapter import \ 2 | SeDatasetTaRunningStatsAdapter 3 | from torchsim.research.se_tasks.adapters.task_stats_adapter import TaskStatsAdapter 4 | from torchsim.research.se_tasks.topologies.se_task1_basic_topology import SeT1Bt 5 | 6 | 7 | class Task1StatsBasicAdapter(TaskStatsAdapter, SeDatasetTaRunningStatsAdapter): 8 | """Duplicates code from Task0StatsBasicAdapter.""" 9 | # TODO DRY 10 | 11 | _topology: SeT1Bt 12 | 13 | def get_task_id(self) -> float: 14 | return self._topology.node_se_connector.outputs.metadata_task_id.tensor.cpu().item() 15 | 16 | def get_task_instance_id(self) -> float: 17 | return self._topology.node_se_connector.outputs.metadata_task_instance_id.tensor.cpu().item() 18 | 19 | def get_task_status(self) -> float: 20 | return self._topology.node_se_connector.outputs.metadata_task_status.tensor.cpu().item() 21 | 22 | def get_task_instance_status(self) -> float: 23 | return self._topology.node_se_connector.outputs.metadata_task_instance_status.tensor.cpu().item() 24 | 25 | def get_reward(self) -> float: 26 | return self._topology.node_se_connector.outputs.reward_output.tensor.cpu().item() 27 | 28 | def get_testing_phase(self) -> float: 29 | return self._topology.node_se_connector.outputs.metadata_testing_phase.tensor.cpu().item() 30 | 31 | def switch_learning(self, learning_on: bool): 32 | self._topology.switch_learning(learning_on) 33 | -------------------------------------------------------------------------------- /torchsim/core/logging/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import sys 4 | from typing import Optional 5 | 6 | 7 | def _get_file_handler(filename): 8 | return logging.FileHandler(filename, mode='w') 9 | 10 | 11 | def _get_console_handler(): 12 | return logging.StreamHandler(sys.stdout) 13 | 14 | 15 | _default_log_file = 'main.log' 16 | 17 | 18 | def setup_logging_no_ui(filename: Optional[str] = None): 19 | filename = filename or _default_log_file 20 | _setup_logging([_get_file_handler(filename), _get_console_handler()]) 21 | 22 | 23 | class LoggerNameFormatter(logging.Formatter): 24 | def format(self, record): 25 | record.loggername = record.name.split('.')[-1] 26 | return super().format(record) 27 | 28 | 29 | def _setup_logging(handlers): 30 | logger = logging.getLogger() 31 | for f in list(logger.filters): 32 | logger.removeFilter(f) 33 | 34 | for handler in list(logger.handlers): 35 | logger.removeHandler(handler) 36 | 37 | formatter = LoggerNameFormatter('[%(thread)d] %(asctime)s - %(levelname).4s - %(loggername)s - %(message)s') 38 | 39 | # Change this when it makes sense, now we need all logging to be visible. 40 | if os.environ.get('LOG_DEBUG', False): 41 | log_level = logging.DEBUG 42 | else: 43 | log_level = logging.INFO 44 | logger.setLevel(log_level) 45 | 46 | for handler in handlers: 47 | handler.setFormatter(formatter) 48 | logger.addHandler(handler) 49 | 50 | 51 | def flush_logs(): 52 | logger = logging.getLogger() 53 | for handler in logger.handlers: 54 | handler.flush() 55 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/topologies/se_task_topology.py: -------------------------------------------------------------------------------- 1 | from abc import ABC 2 | 3 | from torchsim.core.graph import Topology 4 | from torchsim.core.nodes.internals.learning_switchable import LearningSwitchable, TestingSwitcher 5 | 6 | 7 | class TestableTopology(Topology, ABC): 8 | _is_testing: bool = False 9 | 10 | def __init__(self): 11 | Topology.__init__(self, device='cuda') 12 | 13 | def is_in_testing_phase(self) -> bool: 14 | """Finds first TestableSwitch or is_learning method on node and pass the value returned by is_learning. 15 | 16 | Returns: 17 | True if in testing phase. 18 | """ 19 | for switch_node in (x for x in self.nodes 20 | if isinstance(x, TestingSwitcher) or hasattr(x, 'is_learning')): 21 | return not switch_node.is_learning() 22 | 23 | def before_step(self): 24 | if self.is_in_testing_phase() and not self._is_testing: 25 | # switch to testing -- switch learning off 26 | self.switch_learning(learning_on=False) 27 | self._is_testing = True 28 | elif not self.is_in_testing_phase() and self._is_testing: 29 | # back to learning 30 | self.switch_learning(learning_on=True) 31 | self._is_testing = False 32 | 33 | def switch_learning(self, learning_on: bool): 34 | for switchable_node in (x for x in self.nodes 35 | if isinstance(x, LearningSwitchable) or hasattr(x, 'switch_learning')): 36 | switchable_node.switch_learning(learning_on) 37 | 38 | self._is_testing = not learning_on 39 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_2_1_symbolic_input_words/experiments/ta_symbolic_input_words.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from eval_utils import parse_test_args, create_observer_system, run_experiment_with_ui 4 | 5 | from torchsim.core.eval2.experiment import Experiment 6 | from torchsim.core.eval2.experiment_runner_params import ExperimentParams 7 | from torchsim.core.eval2.scaffolding import TopologyScaffoldingFactory 8 | from torchsim.core.experiment_runner import UiExperimentRunner 9 | from torchsim.research.research_topics.rt_3_2_1_symbolic_input_words.templates.symbolic_input_template import \ 10 | SymbolicInputTemplate 11 | from torchsim.research.research_topics.rt_3_2_1_symbolic_input_words.topologies.symbolic_input_words_topology import \ 12 | SymbolicInputWordsTopology 13 | 14 | logger = logging.getLogger(__name__) 15 | 16 | 17 | def run_measurement(name, topology_parameters, args, debug: bool = False): 18 | """"Runs the experiment with specified params, see the parse_test_args method for arguments""" 19 | 20 | # exp_params = Params 21 | 22 | scaffolding = TopologyScaffoldingFactory(SymbolicInputWordsTopology) 23 | template = SymbolicInputTemplate("Symbolic input test") 24 | experiment_params = ExperimentParams(max_steps=0) 25 | experiment = Experiment(template, scaffolding, topology_parameters, experiment_params) 26 | 27 | run_experiment_with_ui(experiment) 28 | 29 | 30 | def run_words(args): 31 | name = "Words" 32 | params = [ 33 | {} 34 | ] 35 | run_measurement(name, params, args) 36 | 37 | 38 | if __name__ == '__main__': 39 | arg = parse_test_args() 40 | run_words(arg) 41 | -------------------------------------------------------------------------------- /tests/core/nodes/test_dataset_simple_point_gravity.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import numpy as np 3 | from dataclasses import astuple 4 | 5 | from torchsim.core.memory.tensor_creator import AllocatingCreator 6 | from torchsim.core.nodes.dataset_simple_point_gravity_node import DatasetSimplePointGravityUnit, \ 7 | DatasetSimplePointGravityParams, MoveStrategy 8 | from torchsim.utils.param_utils import Point2D, Size2D 9 | 10 | 11 | class TestDatasetSimplePointGravityUnit: 12 | def test_point2D_dataclass(self): 13 | p = Point2D(10, 5) 14 | assert (10, 5) == astuple(p) 15 | 16 | @pytest.mark.parametrize('move_strategy, vector, point, expected', [ 17 | (MoveStrategy.DIRECT_TO_POINT, (-1, -1), (1, 1), (0, 0)), 18 | (MoveStrategy.DIRECT_TO_POINT, (-1, 0), (1, 1), (0, 1)), 19 | (MoveStrategy.DIRECT_TO_POINT, (-1, 1), (1, 1), (0, 2)), 20 | (MoveStrategy.DIRECT_TO_POINT, (1, 0), (0, 2), (1, 2)), 21 | (MoveStrategy.LIMITED_TO_LEFT_DOWN_QUADRANT, (-1, -1), (1, 1), (1, 0)), 22 | (MoveStrategy.LIMITED_TO_LEFT_DOWN_QUADRANT, (-1, 1), (1, 1), (1, 2)), 23 | (MoveStrategy.LIMITED_TO_LEFT_DOWN_QUADRANT, (1, -1), (1, 1), (2, 0)), 24 | (MoveStrategy.LIMITED_TO_LEFT_DOWN_QUADRANT, (1, 1), (1, 1), (2, 1)), 25 | ]) 26 | def test_move_point(self, move_strategy, vector, point, expected): 27 | params = DatasetSimplePointGravityParams(Size2D(3, 3), Point2D(1, 1), 1, move_strategy) 28 | unit = DatasetSimplePointGravityUnit(AllocatingCreator(device='cpu'), params, random=None) 29 | result = unit._move_point(np.array(vector), Point2D(*point)) 30 | assert Point2D(*expected) == result 31 | -------------------------------------------------------------------------------- /torchsim/core/eval/node_accessors/flock_node_accessor.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from torchsim.core.nodes import SpatialPoolerFlockNode 4 | from torchsim.core.nodes.expert_node import ExpertFlockNode 5 | 6 | 7 | class FlockNodeAccessor: 8 | 9 | # TODO unit tests 10 | 11 | @staticmethod 12 | def get_sp_output_tensor(node: ExpertFlockNode) -> torch.Tensor: 13 | """Return output of the SP for entire flock. Tensor should be cloned somewhere so that it can be used later.""" 14 | return node.memory_blocks.sp.forward_clusters.tensor 15 | 16 | @staticmethod 17 | def get_sp_output_id(node: ExpertFlockNode) -> int: 18 | assert node.params.flock_size == 1 19 | 20 | if isinstance(node, SpatialPoolerFlockNode): 21 | tensor = node.outputs.sp.forward_clusters.tensor 22 | else: 23 | tensor = node.memory_blocks.sp.forward_clusters.tensor 24 | 25 | max_id = torch.argmax(tensor) 26 | 27 | return max_id.to('cpu').data.item() 28 | 29 | @staticmethod 30 | def get_sp_deltas(node: ExpertFlockNode) -> torch.Tensor: 31 | return node.memory_blocks.sp.cluster_center_deltas.tensor 32 | 33 | @staticmethod 34 | def get_sp_boosting_durations(node: ExpertFlockNode) -> torch.Tensor: 35 | return node.memory_blocks.sp.cluster_boosting_durations.tensor 36 | 37 | @staticmethod 38 | def get_sp_output_size(node: ExpertFlockNode) -> int: 39 | """Return number of elements in the SP output - for entire flock together!""" 40 | return node.params.flock_size * node.params.n_cluster_centers 41 | # return node.memory_blocks.sp.forward_clusters.numel() 42 | 43 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_2_1_2_learning_rate2/node_groups/classification_model_group.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod 2 | 3 | import torch 4 | from torchsim.core.graph.node_base import EmptyOutputs 5 | from torchsim.core.graph.node_group import GenericGroupInputs, NodeGroupBase 6 | 7 | 8 | class ClassificationModelGroupInputs(GenericGroupInputs['ClassificationModelGroup']): 9 | """Inputs of the group required by the experiment.""" 10 | 11 | def __init__(self, owner): 12 | super().__init__(owner) 13 | self.image = self.create('Image') 14 | self.label = self.create('Label') 15 | 16 | 17 | class ClassificationModelGroup(NodeGroupBase[ClassificationModelGroupInputs, EmptyOutputs]): 18 | """ This should be implemented by your model in order to support the classification accuracy measurement.""" 19 | def __init__(self, name: str): 20 | super().__init__(name, inputs=ClassificationModelGroupInputs(self)) 21 | 22 | @abstractmethod 23 | def get_average_log_delta_for(self, layer_id: int) -> float: 24 | """Average log delta across all dimensions and all the cluster centers. If delta==0, return 0.""" 25 | pass 26 | 27 | @abstractmethod 28 | def clone_predicted_label_tensor_output(self) -> torch.Tensor: 29 | """Returns a tensor representing the class label predicted by the architecture.""" 30 | pass 31 | 32 | @abstractmethod 33 | def model_switch_to_training(self): 34 | """Switch experts (NN) to training""" 35 | pass 36 | 37 | @abstractmethod 38 | def model_switch_to_testing(self): 39 | """Switch experts (NN) to testing""" 40 | pass 41 | -------------------------------------------------------------------------------- /tests/core/node_accessors/test_mnist_node_accessor.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import pytest 4 | import torch 5 | 6 | from torchsim.core.eval.node_accessors.mnist_node_accessor import MnistNodeAccessor 7 | from torchsim.core.memory.tensor_creator import AllocatingCreator 8 | from torchsim.core.nodes.dataset_mnist_node import DatasetMNISTParams, DatasetMNISTNode, DatasetSequenceMNISTNodeParams 9 | from torchsim.core.nodes.dataset_sequence_mnist_node import DatasetSequenceMNISTNode 10 | from tests.core.nodes.test_dataset_mnist_node import get_dataset, sequences_equal 11 | 12 | 13 | @pytest.mark.parametrize('device', ['cpu', 'cuda']) 14 | @pytest.mark.parametrize('generator', [[0, 1, 2], 0, 1]) 15 | def test_node_accessor(generator, device): 16 | """Validate the accessor properties.""" 17 | # common params 18 | params = DatasetMNISTParams() 19 | params.one_hot_labels = False 20 | 21 | seq = None 22 | 23 | # different iterators might result in different behavior here 24 | if type(generator) is List: 25 | seq = DatasetSequenceMNISTNodeParams(seqs=generator) 26 | elif generator == 0: 27 | params.random_order = True 28 | else: 29 | params.random_order = False 30 | 31 | node = DatasetSequenceMNISTNode(params, seq_params=seq, dataset=get_dataset(), seed=123) 32 | node.allocate_memory_blocks(AllocatingCreator(device=device)) 33 | 34 | node.step() 35 | bitmap = MnistNodeAccessor.get_data(node) 36 | label = MnistNodeAccessor.get_label_id(node) 37 | 38 | assert type(label) is int 39 | assert type(bitmap) is torch.Tensor 40 | assert sequences_equal(bitmap.shape, [28, 28]) 41 | 42 | assert 0 <= label < 10 -------------------------------------------------------------------------------- /tests/core/nodes/test_random_noise_node.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import torch 3 | from torchsim.core.memory.tensor_creator import AllocatingCreator 4 | from torchsim.core.nodes.random_noise_node import RandomNoiseUnit, RandomNoiseNode, RandomNoiseParams 5 | from tests.core.nodes.node_unit_test_base import NodeTestBase 6 | 7 | 8 | @pytest.mark.parametrize('device', ['cpu', 'cuda']) 9 | def test_random_noise_unit(device: str): 10 | shape = [5, 5] 11 | TestRandomNoise.fix_random_seed() 12 | creator = AllocatingCreator(device) 13 | unit = RandomNoiseUnit(creator, shape) 14 | assert unit.output[0, 0] == 0 15 | unit.step([]) 16 | assert 0 < unit.output[0, 0] < 1 17 | big_number = 1000 18 | added_tensor = creator.ones(shape) * big_number 19 | unit.step([added_tensor]) 20 | assert big_number < unit.output[0, 0] < big_number + 1 21 | 22 | 23 | class TestRandomNoise(NodeTestBase): 24 | """Tests node. 25 | 26 | A minimal test exercising the node. 27 | """ 28 | 29 | _shape: torch.Size = torch.Size((1, 2)) 30 | 31 | def _generate_input_tensors(self): 32 | yield [self._creator.zeros(self._shape, device=self._device, dtype=self._dtype)] 33 | 34 | def _generate_expected_results(self): 35 | yield [] 36 | 37 | def _create_node(self): 38 | self.fix_random_seed() 39 | return RandomNoiseNode(params=RandomNoiseParams(list(self._shape))) 40 | 41 | def _check_results(self, expected, results, step): 42 | for result in results: 43 | assert 0 < result[0, 0] < 1 44 | 45 | @staticmethod 46 | def fix_random_seed(): 47 | torch.cuda.manual_seed_all(0) 48 | torch.manual_seed(0) 49 | -------------------------------------------------------------------------------- /torchsim/utils/list_utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | import torch 4 | import warnings 5 | from typing import List, TypeVar 6 | 7 | T = TypeVar('T') 8 | 9 | 10 | def flatten_list(list_of_lists: List[List[T]]) -> List[T]: 11 | """Merges all sub-lists of the list `list_of_lists` into one list.""" 12 | return [item 13 | for sublist in list_of_lists 14 | for item in sublist] 15 | 16 | 17 | def same_lists(list1: List, list2: List, eps=None): 18 | """Compares if two lists are same. If it fails, it tries if they are same up to the eps difference.""" 19 | 20 | # Check sizes. 21 | if len(list1) != len(list2): 22 | return False 23 | 24 | if list1 == list2: 25 | return True 26 | 27 | nans1 = [math.isnan(x) for x in list1] 28 | nans2 = [math.isnan(x) for x in list2] 29 | 30 | # Check nans. 31 | if nans1 != nans2: 32 | return False 33 | 34 | list1_without_nans = [x for x in list1 if not math.isnan(x)] 35 | list2_without_nans = [x for x in list2 if not math.isnan(x)] 36 | 37 | if eps is None: 38 | return list1_without_nans == list2_without_nans 39 | else: 40 | if eps > 1: 41 | warnings.warn("eps is intended to be a small number in the form '1e-n'.", stacklevel=2) 42 | return all(x - y < eps for x, y in zip(list1_without_nans, list2_without_nans)) 43 | 44 | 45 | def dim_prod(dimensions, start_dim=0, end_dim=-1) -> int: 46 | if not isinstance(dimensions, torch.Tensor): 47 | dimensions = torch.tensor(dimensions) 48 | 49 | if end_dim == -1: 50 | end_dim = len(dimensions) - 1 51 | 52 | return int(torch.prod(dimensions[start_dim:end_dim+1]).item()) 53 | -------------------------------------------------------------------------------- /tests/core/eval2/test_measurement_manager_new.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.eval2.measurement_manager import RunMeasurementManager, MeasurementManager, MeasurementManagerParams 2 | 3 | 4 | def get_something(): 5 | return 42 6 | 7 | 8 | def get_odd(): 9 | def odd(): 10 | odd.value = not odd.value 11 | return odd.value 12 | odd.value = True 13 | 14 | return odd 15 | 16 | 17 | def test_measurement_functions(): 18 | run_manager = RunMeasurementManager('foo topology', {}) 19 | 20 | run_manager.add_measurement_f('foo 1', get_something) 21 | run_manager.add_measurement_f('foo 2', get_something, period=2) 22 | run_manager.add_measurement_f('foo odd', get_something, predicate=get_odd()) 23 | run_manager.add_measurement_f_once('foo once', get_something, step=2) 24 | 25 | for step in range(0, 3): 26 | run_manager.step(step) 27 | 28 | measurements = run_manager.measurements 29 | 30 | assert [(0, 0), (1, 1), (2, 2)] == measurements.get_step_item_tuples('current_step') 31 | assert [(0, 42), (1, 42), (2, 42)] == measurements.get_step_item_tuples('foo 1') 32 | assert [(0, 42), (2, 42)] == measurements.get_step_item_tuples('foo 2') 33 | assert [(2, 42)] == measurements.get_step_item_tuples('foo once') 34 | assert [(1, 42)] == measurements.get_step_item_tuples('foo odd') 35 | 36 | 37 | def test_measurement_manager(): 38 | manager = MeasurementManager(None, MeasurementManagerParams()) 39 | 40 | run = manager.create_new_run('foo model', {'param': 'value'}) 41 | run._measurements.add(1, 'measurement', 42) 42 | 43 | manager.add_results(run) 44 | 45 | assert 42 == manager.single_run_measurements[0].get_item('measurement', step=1) 46 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_4_2_1_actions/node_groups/single_expert_group.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.graph.connection import Connector 2 | from torchsim.core.models.expert_params import ExpertParams 3 | from torchsim.core.nodes import ExpertFlockNode 4 | from torchsim.research.research_topics.rt_4_2_1_actions.topologies.goal_directed_template_topology import \ 5 | GoalDirectedExpertGroupBase 6 | 7 | 8 | class SingleExpertGroup(GoalDirectedExpertGroupBase): 9 | def __init__(self): 10 | super().__init__("Single Expert") 11 | 12 | expert_params = ExpertParams() 13 | 14 | expert_params.flock_size = 1 15 | expert_params.n_cluster_centers = 24 16 | expert_params.produce_actions = True 17 | expert_params.temporal.seq_length = 9 18 | expert_params.temporal.seq_lookahead = 7 19 | expert_params.temporal.n_frequent_seqs = 700 20 | expert_params.temporal.max_encountered_seqs = 1000 21 | expert_params.temporal.exploration_probability = 0.01 22 | expert_params.temporal.batch_size = 200 23 | expert_params.temporal.own_rewards_weight = 20 24 | expert_params.temporal.compute_backward_pass = True 25 | 26 | expert_params.compute_reconstruction = True 27 | 28 | expert_node = ExpertFlockNode(expert_params) 29 | 30 | self.add_node(expert_node) 31 | 32 | Connector.connect(self.inputs.data.output, expert_node.inputs.sp.data_input) 33 | Connector.connect(self.inputs.reward.output, expert_node.inputs.tp.reward_input) 34 | 35 | Connector.connect(expert_node.outputs.sp.predicted_reconstructed_input, 36 | self.outputs.predicted_reconstructed_input.input) 37 | -------------------------------------------------------------------------------- /torchsim/core/eval/doc_generator/document.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.eval.doc_generator.element import XmlElement 2 | from typing import List, Any, Iterable, Dict, Optional 3 | 4 | 5 | class Document: 6 | """An HTML document used to record experiment output.""" 7 | _doc_header: str 8 | _html: XmlElement 9 | _body: XmlElement 10 | _elements: List[XmlElement] 11 | 12 | def __init__(self): 13 | self._doc_header = "" 14 | self._body = XmlElement('body') 15 | self._html = XmlElement('html') 16 | self._elements = [self._html.add(self._body)] 17 | 18 | def add(self, element: XmlElement): 19 | """Adds an XML element or string to the document.""" 20 | self._body.add(element) 21 | return self 22 | 23 | def as_text(self): 24 | return '\n'.join([self._doc_header, self._html.as_text()]) 25 | 26 | def write_file(self, path: str): 27 | with open(path, 'w') as document_file: 28 | document_file.write(self.as_text()) 29 | 30 | def add_table(self, headers: Iterable[str], values: Iterable[Iterable[Any]], attribs: Optional[Dict[str, str]] = None): 31 | table = XmlElement('table', attribs) 32 | # header 33 | header = XmlElement('tr') 34 | for h in headers: 35 | header.add(XmlElement('th', text=h)) 36 | table.add(header) 37 | 38 | # rows 39 | for row_values in values: 40 | row = XmlElement('tr') 41 | for cell in row_values: 42 | str_value = str(cell) 43 | row.add(XmlElement('td', {'style': 'text-align: right;'}, text=str_value)) 44 | table.add(row) 45 | 46 | self.add(table) 47 | -------------------------------------------------------------------------------- /torchsim/core/eval/doc_generator/figure.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.eval.doc_generator.element import XmlElement 2 | 3 | 4 | class Row(XmlElement): 5 | def __init__(self, attr=None): 6 | super().__init__('tr', attr) 7 | 8 | 9 | class Cell(XmlElement): 10 | def __init__(self, attr=None): 11 | super().__init__('td', attr) 12 | 13 | 14 | class Image(XmlElement): 15 | def __init__(self, path, height: int = None, width: int = None): 16 | attributes = {'src': path} 17 | if height is not None: 18 | attributes['height'] = f"{height}" 19 | if width is not None: 20 | attributes['width'] = f"{width}" 21 | super().__init__('img', attributes) 22 | 23 | 24 | class Caption(XmlElement): 25 | _text: str 26 | 27 | def __init__(self, text: str): 28 | super().__init__('caption', {'align': 'bottom'}) 29 | self._text = text 30 | 31 | def text(self): 32 | return self._text 33 | 34 | 35 | class Figure(XmlElement): 36 | """XML element representing an image with a caption. 37 | 38 | The element is a table with a single cell. The table caption is used as the caption for the figure. 39 | """ 40 | def __init__(self, image: Image, caption: Caption): 41 | super().__init__('table', {'class': 'image'}) 42 | self.add(caption) 43 | row = Row().add(Cell().add(image)) 44 | self.add(row) 45 | 46 | @classmethod 47 | def from_params(cls, image_path: str, caption: str, height: int = None, width: int = None): 48 | return cls(Image(image_path, height, width), Caption(caption)) 49 | 50 | @classmethod 51 | def from_elements(cls, image: Image, caption: Caption): 52 | return cls(image, caption) 53 | -------------------------------------------------------------------------------- /torchsim/core/models/temporal_pooler/buffer.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.models.flock.buffer import Buffer, BufferStorage 2 | 3 | 4 | class TPFlockBuffer(Buffer): 5 | """A buffer for Temporal pooler. 6 | 7 | The buffer tracks input clusters (e.g. the output of spatial pooler) and input contexts, sequence probabilities 8 | and output projections. 9 | """ 10 | 11 | clusters: BufferStorage 12 | seq_probs: BufferStorage 13 | outputs: BufferStorage 14 | contexts: BufferStorage 15 | actions: BufferStorage 16 | exploring: BufferStorage 17 | rewards_punishments: BufferStorage 18 | 19 | def __init__(self, creator, flock_size, buffer_size, n_cluster_centers, n_frequent_seqs, context_size, n_providers): 20 | super().__init__(creator, flock_size, buffer_size) 21 | 22 | self.outputs = self._create_storage("outputs", (flock_size, buffer_size, n_cluster_centers)) 23 | self.seq_probs = self._create_storage("seq_probs", (flock_size, buffer_size, n_frequent_seqs)) 24 | self.clusters = self._create_storage("clusters", (flock_size, buffer_size, n_cluster_centers)) 25 | # Two contexts are passed from parent - where the parent is, and where the parent wants to be 26 | self.contexts = self._create_storage("contexts", (flock_size, buffer_size, n_providers, context_size)) 27 | self.actions = self._create_storage("actions", (flock_size, buffer_size, n_cluster_centers)) 28 | self.exploring = self._create_storage("exploring", (flock_size, buffer_size, 1)) # marks steps when the expert 29 | # was exploring, the last singleton dimension has to be here so that the buffer 30 | self.rewards_punishments = self._create_storage("rewards_punishments", (flock_size, buffer_size, 2)) 31 | 32 | -------------------------------------------------------------------------------- /torchsim/core/nodes/constant_node.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.graph.slot_container import MemoryBlocks 2 | from torchsim.core.graph.node_base import EmptyInputs 3 | from torchsim.core.graph.unit import Unit 4 | from torchsim.core.graph.worker_node_base import WorkerNodeBase 5 | from torchsim.core.memory.tensor_creator import TensorCreator 6 | 7 | 8 | class ConstantNodeUnit(Unit): 9 | def __init__(self, creator: TensorCreator, shape, constant): 10 | super().__init__(creator.device) 11 | self.output = creator.full(shape, fill_value=constant, dtype=self._float_dtype, device=creator.device) 12 | 13 | def step(self): 14 | pass 15 | 16 | 17 | class ConstantNodeOutputs(MemoryBlocks): 18 | 19 | def __init__(self, owner): 20 | super().__init__(owner) 21 | self.output = self.create("Output") 22 | 23 | def prepare_slots(self, unit: ConstantNodeUnit): 24 | self.output.tensor = unit.output 25 | 26 | 27 | class ConstantNode(WorkerNodeBase[EmptyInputs, ConstantNodeOutputs]): 28 | """ ConstantNode outputs tensor filled with one value. 29 | 30 | Dimension of output tensor must be specified on creation. 31 | Constant can be a non-number like ``float('nan')``. 32 | """ 33 | 34 | outputs: ConstantNodeOutputs 35 | 36 | def __init__(self, shape, constant=0, name="Const"): 37 | if type(shape) is int: 38 | shape = (shape,) 39 | super().__init__(name=f"{name} {constant} [{tuple(shape)}]", outputs=ConstantNodeOutputs(self)) 40 | self._constant = constant 41 | 42 | self._shape = shape 43 | 44 | def _create_unit(self, creator: TensorCreator): 45 | return ConstantNodeUnit(creator, self._shape, self._constant) 46 | 47 | def _step(self): 48 | self._unit.step() 49 | -------------------------------------------------------------------------------- /tests/core/nodes/test_multi_dataset_alphabet.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest import raises 3 | 4 | from torchsim.core.graph.node_base import NodeValidationException 5 | from torchsim.core.memory.tensor_creator import AllocatingCreator 6 | from torchsim.core.nodes.dataset_alphabet_node import DatasetAlphabetParams, DatasetAlphabetSequenceProbsModeParams 7 | from torchsim.core.nodes.multi_dataset_alphabet_node import MultiDatasetAlphabetUnit, MultiDatasetAlphabetNode 8 | 9 | 10 | class TestMultiDatasetAlphabetUnit: 11 | 12 | n_worlds = 3 13 | 14 | @pytest.mark.parametrize('device', ['cpu', pytest.param('cuda', marks=pytest.mark.slow)]) 15 | def test_create_node(self, device): 16 | unit = MultiDatasetAlphabetUnit(AllocatingCreator(device), DatasetAlphabetParams( 17 | symbols="abcd", 18 | sequence_probs=DatasetAlphabetSequenceProbsModeParams(seqs=['abcd']) 19 | ), n_worlds=self.n_worlds) 20 | assert [self.n_worlds, 7, 5] == list(unit.output_data.shape) 21 | 22 | 23 | class TestMultiDatasetAlphabetNode: 24 | @pytest.mark.parametrize('params, should_pass', [ 25 | (DatasetAlphabetParams( 26 | symbols="abcd", 27 | sequence_probs=DatasetAlphabetSequenceProbsModeParams(seqs=['abc']) 28 | ), True), 29 | (DatasetAlphabetParams( 30 | symbols="abcd", 31 | sequence_probs=DatasetAlphabetSequenceProbsModeParams(seqs=['abc', 'ae']) 32 | ), False) 33 | ]) 34 | def test_validate_params_sequence_probs_validate_throws(self, params, should_pass): 35 | node = MultiDatasetAlphabetNode(params) 36 | if should_pass: 37 | node.validate() 38 | else: 39 | with raises(NodeValidationException): 40 | node.validate() 41 | -------------------------------------------------------------------------------- /torchsim/core/nodes/periodic_update_node_group.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from torchsim.core.graph.node_base import TInputs, TOutputs, TInternals 4 | from torchsim.core.graph.node_group import NodeGroupWithInternalsBase 5 | from torchsim.gui.observables import ObserverPropertiesItem, disable_on_runtime 6 | from torchsim.gui.validators import validate_positive_int 7 | 8 | 9 | class PeriodicUpdateNodeGroup(NodeGroupWithInternalsBase[TInputs, TInternals, TOutputs]): 10 | """Node group that runs every n steps. 11 | 12 | Sometimes we want nodes to execute not every step but every n steps. For example, we may want the input data 13 | to change every five steps to allow multiple iterations of processing of a single frame. The PeriodicUpdateNodeGroup 14 | provides this functionality, executing with the specified frequency. 15 | """ 16 | def __init__(self, name: str, update_period: int = 1, inputs: TInputs = None, internals: TInternals = None, 17 | outputs: TOutputs = None): 18 | super().__init__(name, inputs, internals, outputs) 19 | self._update_period = update_period 20 | self._step_count = 0 21 | 22 | def step(self): 23 | if self._step_count % self._update_period == 0: 24 | super().step() 25 | self._step_count += 1 26 | 27 | @property 28 | def update_period(self) -> int: 29 | return self._update_period 30 | 31 | @update_period.setter 32 | def update_period(self, value: int): 33 | validate_positive_int(value) 34 | self._update_period = value 35 | 36 | def get_properties(self) -> List[ObserverPropertiesItem]: 37 | return [ 38 | self._prop_builder.auto('Update period', type(self).update_period, edit_strategy=disable_on_runtime) 39 | ] 40 | -------------------------------------------------------------------------------- /tests/core/nodes/test_convSpatialPoolerFlockNode.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.models.expert_params import ExpertParams 2 | from torchsim.core.nodes import ConvSpatialPoolerFlockNode 3 | from tests.core.nodes.node_unit_test_base import NodeTestBase, AnyResult 4 | 5 | 6 | class TestConvSpatialPoolerFlockNode(NodeTestBase): 7 | """Check that the flock learns to recognize 3 clusters""" 8 | experts_grid = (1, 2) 9 | image_size = (3,) 10 | params = ExpertParams() 11 | params.n_cluster_centers = 3 12 | params.flock_size = experts_grid[0] * experts_grid[1] 13 | params.spatial.batch_size = 2 14 | params.spatial.learning_period = 1 15 | step_pairs_not_comparing = 4 16 | 17 | @classmethod 18 | def setup_class(cls, device: str = 'cuda'): 19 | super().setup_class() 20 | 21 | cls.inputs = cls._creator.tensor([[[[3.7, 14, 56], [-12, -11, 0]]], 22 | [[[-12, -11, 0], [1, 2, 3]]]], device=cls._device, dtype=cls._dtype) 23 | cls.expected_results = cls._creator.tensor([[[[1, 0, 0], [0, 1, 0]]], 24 | [[[0, 1, 0], [0, 0, 1]]]], device=cls._device, dtype=cls._dtype) 25 | cls.n_inputs = 2 26 | 27 | def _generate_input_tensors(self): 28 | for step in range(self.step_pairs_not_comparing + 1): 29 | yield [self.inputs[0]] 30 | yield [self.inputs[1]] 31 | 32 | def _generate_expected_results(self): 33 | for step in range(self.step_pairs_not_comparing): 34 | yield [AnyResult, AnyResult] 35 | 36 | yield [self.expected_results[0], AnyResult] 37 | yield [self.expected_results[1], AnyResult] 38 | 39 | def _create_node(self): 40 | 41 | return ConvSpatialPoolerFlockNode(params=self.params, seed=8) 42 | -------------------------------------------------------------------------------- /tests/test_multiple_inheritance.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | 4 | class Base: 5 | list: List[int] 6 | 7 | def __init__(self, collector): 8 | collector.append("Base") 9 | self.list = ['base'] 10 | 11 | def add(self, item, collector): 12 | collector.append("Base") 13 | self.list.append(item) 14 | 15 | 16 | class A(Base): 17 | def __init__(self, collector): 18 | collector.append("A") 19 | super().__init__(collector) 20 | 21 | def add(self, item, collector): 22 | collector.append("A") 23 | super().add(f'a_{item}_A', collector) 24 | 25 | 26 | class C(A): 27 | def __init__(self, collector): 28 | collector.append("C") 29 | super().__init__(collector) 30 | 31 | def add(self, item, collector): 32 | collector.append("C") 33 | super().add(f'c_{item}_C', collector) 34 | 35 | 36 | class B(Base): 37 | def __init__(self, collector): 38 | collector.append("B") 39 | super().__init__(collector) 40 | 41 | def add(self, item, collector): 42 | collector.append("B") 43 | super().add(f'b_{item}_B', collector) 44 | 45 | 46 | class D(B): 47 | def __init__(self, collector): 48 | collector.append("D") 49 | super().__init__(collector) 50 | 51 | def add(self, item, collector): 52 | collector.append("D") 53 | super().add(f'd_{item}_D', collector) 54 | 55 | 56 | class E(C, D): 57 | pass 58 | 59 | 60 | def test_base_class_method_is_called_only_once(): 61 | call_order_init = [] 62 | call_order = [] 63 | e = E(call_order_init) 64 | e.add("X", call_order) 65 | assert ['base', 'b_d_a_c_X_C_A_D_B'] == e.list 66 | assert ['C', 'A', 'D', 'B', 'Base'] == call_order 67 | assert ['C', 'A', 'D', 'B', 'Base'] == call_order_init 68 | -------------------------------------------------------------------------------- /tests/core/models/integration_test_utils.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | 3 | import torch 4 | from itertools import chain 5 | 6 | from torchsim.core.utils.tensor_utils import same 7 | 8 | 9 | def randomize_subflock(should_update, should_not_update): 10 | for flock_tensor, subflock_tensor in chain(should_update, should_not_update): 11 | subflock_tensor.random_() 12 | 13 | 14 | def calculate_expected_results(should_update, should_not_update, flock_size, indices_np): 15 | expected_results_updated = [[] for _ in should_update] 16 | expected_results_not_updated = [[] for _ in should_not_update] 17 | 18 | subflock_ptr = 0 19 | for k in range(flock_size): 20 | for i, (original, subflock) in enumerate(should_update): 21 | if k in indices_np: 22 | # The expert is in the subflock. 23 | expected_results_updated[i].append(subflock[subflock_ptr]) 24 | else: 25 | # The expert is not in the subflock. 26 | expected_results_updated[i].append(original[k]) 27 | 28 | if k in indices_np: 29 | subflock_ptr += 1 30 | 31 | for i, (original, subflock) in enumerate(should_not_update): 32 | expected_results_not_updated[i].append(original[k]) 33 | 34 | return [torch.stack(expected) for expected in expected_results_updated + expected_results_not_updated] 35 | 36 | 37 | def check_integration_results( 38 | expected_results: List[torch.Tensor], 39 | should_update: List[Tuple[torch.Tensor, torch.Tensor]], 40 | should_not_update: List[Tuple[torch.Tensor, torch.Tensor]]): 41 | flock_tensors = map(lambda x: x[0], chain(should_update, should_not_update)) 42 | for expected, original in zip(expected_results, flock_tensors): 43 | assert same(expected, original) 44 | -------------------------------------------------------------------------------- /torchsim/research/research_topics/rt_3_2_1_symbolic_input_words/templates/symbolic_input_template.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import List 3 | 4 | from torchsim.core.eval.doc_generator.document import Document 5 | from torchsim.core.eval2.experiment_controller import ExperimentController, ExperimentComponent 6 | from torchsim.core.eval2.experiment_template_base import ExperimentTemplateBase, TTopology 7 | from torchsim.core.eval2.measurement_manager import MeasurementManager, RunMeasurementManager 8 | from torchsim.core.graph import Topology 9 | from torchsim.research.research_topics.rt_3_2_1_symbolic_input_words.topologies.symbolic_input_words_topology import \ 10 | SymbolicInputWordsTopology 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | 15 | class SpatialPoolerClusterForceSetter(ExperimentComponent): 16 | step_count: int = 0 17 | 18 | def __init__(self, topology: SymbolicInputWordsTopology): 19 | super().__init__() 20 | self.topology = topology 21 | 22 | def after_topology_step(self): 23 | self.step_count += 1 24 | # logger.info(f'Step {self.step_count}') 25 | if self.step_count == 1: 26 | logger.info(f'Setting SP clusters') 27 | self.topology.init_sp_clusters() 28 | 29 | 30 | class SymbolicInputTemplate(ExperimentTemplateBase[SymbolicInputWordsTopology]): 31 | def setup_controller(self, topology: SymbolicInputWordsTopology, controller: ExperimentController, 32 | run_measurement_manager: RunMeasurementManager): 33 | sp_cluster_setter = SpatialPoolerClusterForceSetter(topology) 34 | controller.register(sp_cluster_setter) 35 | 36 | def publish_results(self, document: Document, docs_folder: str, measurement_manager: MeasurementManager, 37 | topology_parameters: List[str]): 38 | pass 39 | -------------------------------------------------------------------------------- /tests/core/nodes/test_visited_area_node.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | from typing import Generator, List, Any 4 | from torchsim.core.graph.worker_node_base import WorkerNodeBase 5 | from torchsim.core.nodes.visited_area_node import VisitedAreaNode 6 | from tests.core.nodes.node_unit_test_base import NodeTestBase 7 | 8 | 9 | class TestVisitedAreaNode(NodeTestBase): 10 | def setup_class(cls, device: str = 'cuda'): 11 | super().setup_class() 12 | 13 | node_input = [[[1, 0], 14 | [0, 0]], 15 | 16 | [[0, 1], 17 | [0, 0]], 18 | 19 | [[0, 0], 20 | [1, 0]], 21 | 22 | [[0, 0], 23 | [0, 1]]] 24 | 25 | node_output = [[[1., .0], 26 | [.0, .0]], 27 | 28 | [[.9, 1.], 29 | [.0, .0]], 30 | 31 | [[.81, .9], 32 | [1., .0]], 33 | 34 | [[.729, .81], 35 | [.9, 1.]]] 36 | 37 | def _generate_input_tensors(self) -> Generator[List[torch.Tensor], None, None]: 38 | for step in range(len(self.node_input)): 39 | yield [self._creator.tensor(self.node_input[step], dtype=self._dtype, device=self._device).unsqueeze(-1)] 40 | 41 | def _generate_expected_results(self) -> Generator[List[Any], None, None]: 42 | for step in range(len(self.node_output)): 43 | yield [self._creator.tensor(self.node_output[step], dtype=self._dtype, device=self._device).unsqueeze(-1)] 44 | 45 | def _create_node(self) -> WorkerNodeBase: 46 | return VisitedAreaNode() 47 | 48 | def _check_results(self, expected, results, step): 49 | for expected_tensor, result_tensor in zip(expected, results): 50 | assert self._same(expected_tensor, result_tensor, eps=0.0001) 51 | -------------------------------------------------------------------------------- /torchsim/utils/template_utils/train_test_topology_saver.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | from torchsim.core.persistence.loader import Loader 5 | from torchsim.core.persistence.persistable import Persistable 6 | from torchsim.core.persistence.saver import Saver 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | class PersistableSaver: 12 | """Saves and loads the persistable for purpose of train/test splitting ExperimentTemplate""" 13 | 14 | _saver: Saver 15 | _loader: Loader 16 | 17 | def __init__(self, adapter_name: str): 18 | persistence_path = self._get_persistence_location(adapter_name) 19 | 20 | self._saver = Saver(persistence_path) 21 | 22 | if not os.path.exists(persistence_path): 23 | logger.error(f"There is no saved model at location {persistence_path}") 24 | 25 | self._loader = Loader(persistence_path) 26 | 27 | def save_data_of(self, persistable: Persistable): 28 | """ 29 | Saves a switchable to a default location 30 | Args: 31 | persistable: the switchable to be saved 32 | """ 33 | persistable.save(self._saver) 34 | self._saver.save() 35 | logger.info('Persistable saved') 36 | 37 | def load_data_into(self, persistable: Persistable): 38 | """ 39 | Loads a persistable from a default location 40 | Args: 41 | persistable: the persistable into which the data will be loaded 42 | """ 43 | try: 44 | persistable.load(self._loader) 45 | except FileNotFoundError: 46 | logger.exception(f"Loading of persistable failed") 47 | 48 | logger.info('Persistable loaded') 49 | 50 | @staticmethod 51 | def _get_persistence_location(adapter_name: str): 52 | return os.path.join(os.getcwd(), 'data', 'stored', adapter_name) 53 | -------------------------------------------------------------------------------- /tests/core/nodes/test_periodic_update_node_group.py: -------------------------------------------------------------------------------- 1 | from typing import Generator, List, Any 2 | 3 | import torch 4 | from torchsim.core.graph.connection import Connector 5 | from torchsim.core.graph.node_base import NodeBase 6 | from torchsim.core.graph.node_group import SimpleGroupInputs, SimpleGroupOutputs, NodeGroupWithInternalsBase 7 | from torchsim.core.nodes import JoinNode 8 | from torchsim.core.nodes.periodic_update_node_group import PeriodicUpdateNodeGroup 9 | from tests.core.nodes.node_unit_test_base import NodeTestBase 10 | 11 | 12 | class ExamplePeriodicUpdateGroup(PeriodicUpdateNodeGroup): 13 | inputs: SimpleGroupInputs 14 | outputs: SimpleGroupOutputs 15 | 16 | def __init__(self, name: str, update_period: int): 17 | super().__init__(name, update_period, inputs=SimpleGroupInputs(self, n_inputs=1), 18 | outputs=SimpleGroupOutputs(self, n_outputs=1)) 19 | 20 | join_node = JoinNode(n_inputs=1) 21 | self.add_node(join_node) 22 | Connector.connect(self.inputs[0].output, join_node.inputs[0]) 23 | Connector.connect(join_node.outputs.output, self.outputs[0].input) 24 | self.order_nodes() 25 | 26 | 27 | class TestPeriodicUpdateNodeGroup(NodeTestBase): 28 | UPDATE_PERIOD: int = 4 29 | N_STEPS: int = UPDATE_PERIOD * 3 30 | 31 | def _generate_input_tensors(self) -> Generator[List[torch.Tensor], None, None]: 32 | for step in range(self.N_STEPS): 33 | yield [torch.tensor([step], device='cuda')] 34 | 35 | def _generate_expected_results(self) -> Generator[List[Any], None, None]: 36 | for step in range(self.N_STEPS): 37 | yield [torch.tensor([self.UPDATE_PERIOD * (step // self.UPDATE_PERIOD)], device='cuda')] 38 | 39 | def _create_node(self) -> NodeBase: 40 | return ExamplePeriodicUpdateGroup("Something", self.UPDATE_PERIOD) 41 | -------------------------------------------------------------------------------- /torchsim/research/se_tasks/topologies/se_task0_basic_topology.py: -------------------------------------------------------------------------------- 1 | from torchsim.core.graph.connection import Connector 2 | from torchsim.core.models.expert_params import ExpertParams 3 | from torchsim.core.nodes import UnsqueezeNode, SpatialPoolerFlockNode 4 | from torchsim.research.se_tasks.topologies.se_task0_topology import SeT0TopologicalGraph 5 | 6 | 7 | class SeT0BasicTopology(SeT0TopologicalGraph): 8 | """A model which receives data from the 0th SE task and learns spatial and temporal patterns (task0).""" 9 | def _install_experts(self): 10 | self._top_level_flock_node = SpatialPoolerFlockNode(self._create_expert_params()) 11 | self.add_node(self._top_level_flock_node) 12 | self.unsqueeze_node = UnsqueezeNode(0) 13 | self.add_node(self.unsqueeze_node) 14 | Connector.connect(self.se_io.outputs.image_output, self._join_node.inputs[0]) 15 | Connector.connect(self.se_io.outputs.task_to_agent_label, self._join_node.inputs[1]) 16 | Connector.connect(self._join_node.outputs[0], self.unsqueeze_node.inputs.input) 17 | Connector.connect(self.unsqueeze_node.outputs.output, self._top_level_flock_node.inputs.sp.data_input) 18 | 19 | def _get_agent_output(self): 20 | return self._top_level_flock_node.outputs.sp.current_reconstructed_input 21 | 22 | def _top_level_expert_output_size(self): 23 | return self.se_io.get_image_numel() 24 | 25 | @staticmethod 26 | def _create_expert_params() -> ExpertParams: 27 | expert_params = ExpertParams() 28 | expert_params.flock_size = 1 29 | expert_params.n_cluster_centers = 200 30 | expert_params.compute_reconstruction = True 31 | expert_params.spatial.batch_size = 1000 32 | expert_params.spatial.buffer_size = 1010 33 | expert_params.spatial.cluster_boost_threshold = 200 34 | return expert_params 35 | -------------------------------------------------------------------------------- /torchsim/core/kernels/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from torch.utils.cpp_extension import load 4 | import torch 5 | 6 | logger = logging.getLogger('load_kernels') 7 | 8 | 9 | def load_kernels(folder, 10 | name, 11 | sources, 12 | extra_cflags=None, 13 | extra_cuda_cflags=None, 14 | extra_ldflags=None, 15 | extra_include_paths=None, 16 | build_directory=None, 17 | verbose=True): 18 | logger.info(f"Loading kernels started: {name}") 19 | 20 | include_paths = ['torchsim/core/kernels/'] 21 | cuda_cflags = ["-Xptxas -dlcm=ca"] 22 | 23 | if extra_include_paths is not None: 24 | include_paths += extra_include_paths 25 | 26 | if extra_cuda_cflags is not None: 27 | cuda_cflags += extra_cuda_cflags 28 | 29 | path = os.path.dirname(os.path.abspath(folder)) 30 | 31 | def abspath(file): 32 | return os.path.join(path, file) 33 | 34 | sources = [abspath(source) for source in sources] 35 | 36 | sources.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'kernel_helpers.cpp')) 37 | 38 | result = load(name, 39 | sources, 40 | extra_cflags, 41 | cuda_cflags, 42 | extra_ldflags, 43 | include_paths, 44 | build_directory, 45 | verbose) 46 | 47 | logger.info("Loading kernels finished") 48 | 49 | return result 50 | 51 | 52 | _get_cuda_error_code = load_kernels(__file__, 'check_cuda_errors', ['check_cuda_errors.cpp', 53 | 'check_cuda_errors.cu']).get_cuda_error_code 54 | 55 | 56 | def check_cuda_errors(): 57 | error = _get_cuda_error_code() 58 | torch.cuda.check_error(error) 59 | -------------------------------------------------------------------------------- /torchsim/core/datasets/mnist.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from typing import NamedTuple, List 3 | 4 | import torchvision 5 | from torchvision.transforms import transforms 6 | 7 | from torchsim.core.test_optimizations import small_dataset_for_tests_allowed 8 | 9 | 10 | class DatasetResult(NamedTuple): 11 | data: torch.Tensor 12 | labels: torch.Tensor 13 | 14 | 15 | class DatasetMNIST: 16 | 17 | def __init__(self): 18 | self._dataset = torchvision.datasets.MNIST(root='./data', train=True, download=True, 19 | transform=transforms.Compose([ 20 | transforms.ToTensor(), 21 | transforms.Normalize((0.1307,), (0.3081,))])) 22 | 23 | def get_all(self): 24 | if small_dataset_for_tests_allowed(): 25 | return DatasetResult(self._dataset.train_data[:2000], self._dataset.train_labels[:2000]) 26 | return DatasetResult(self._dataset.train_data, self._dataset.train_labels) 27 | 28 | def get_filtered(self, include: List[int]): 29 | data, labels = self.get_all() 30 | indices = labels.clone().apply_(lambda x: x in include).nonzero().squeeze().long() 31 | lm = labels.index_select(0, indices) 32 | dm = data.index_select(0, indices) 33 | return DatasetResult(dm, lm) 34 | 35 | 36 | class LimitedDatasetMNIST(DatasetMNIST): 37 | """Load just a limited number of samples to save time during unit testing.""" 38 | 39 | _sample_limit: int 40 | 41 | def __init__(self, sample_limit: int): 42 | super().__init__() 43 | 44 | self._sample_limit = sample_limit 45 | 46 | def get_all(self): 47 | return DatasetResult(self._dataset.train_data[0:self._sample_limit], 48 | self._dataset.train_labels[0:self._sample_limit]) 49 | 50 | 51 | --------------------------------------------------------------------------------