To fix that we changed the model to take external inputs (as with the Afferent model) in the form of a moving dot where the value of 1.0 is moving forward each iteration down an array of zeros, and the value of 0.25 - moving backwards. For instance, on the second iteration the 3 by 3 input matrix would be:
0.0 1.0 0.0
0.0 0.0 0.0
0.0 0.25 0.0
on the fourth:
0.0 0.0 0.0
1.0 0.0 0.25
0.0 0.0 0.0
Despite using external inputs, the outputs of previous iterations are still taken into account: after the new activity matrix has been computed using dot-product response function, a hysteresis function is applied to it the following way(TC is a pre-defined time constant):
new_activity = old_activity + (new_activity - old_activity)*TC
Now the output activity values do change after each iteration, which allows us a fairly reliable test case. I also modified the python script to use the optimised (in C) version of dot-product response function, the difference in performance is quite noticeable and gets bigger for bigger matrix sizes (optimised is the first one):
[jupiter3]sXXXXXX: ./c_vs_python.sh -m 100 -i 40
Serial: 7.49869203568
[jupiter3]sXXXXXXX: ./c_vs_python.sh -m 100 -i 40
Serial: 10.6240258217
Here are the results of C vs Python runs with different densities and numbers of iterations:
[jupiter3]sXXXXXXX: ./c_vs_python.sh -m 50 -i 50
Serial: 0.688660860062
=== Sequential Time ===
Dot Product: 0.471745
-----------------------
Total: 0.472502
[jupiter3]sXXXXXXX: ./c_vs_python.sh -m 50 -i 200
Serial: 2.88342404366
=== Sequential Time ===
Dot Product: 1.92014
-----------------------
Total: 1.92326
[jupiter3]sXXXXXXX: ./c_vs_python.sh -m 100 -i 50
Serial: 9.23764681816
=== Sequential Time ===
Dot Product: 7.99027
-----------------------
Total: 7.99298
[jupiter3]sXXXXXXX: ./c_vs_python.sh -m 100 -i 100
Serial: 18.9039599895
=== Sequential Time ===
Dot Product: 16.5311
-----------------------
Total: 16.5367
[jupiter3]sXXXXXXX: ./c_vs_python.sh -m 150 -i 20
Serial: 17.1115911007
=== Sequential Time ===
Dot Product: 15.8554
-----------------------
Total: 15.858
[jupiter3]sXXXXXXX: ./c_vs_python.sh -m 150 -i 40
Serial: 34.4383950233
=== Sequential Time ===
Dot Product: 32.8897
-----------------------
Total: 32.8947
[jupiter3]sXXXXXXX: ./c_vs_python.sh -m 170 -i 20
Serial: 28.8636169434
=== Sequential Time ===
Dot Product: 26.6929
-----------------------
Total: 26.6962
[jupiter3]sXXXXXXX: ./c_vs_python.sh -m 170 -i 40
Serial: 59.0316541195
=== Sequential Time ===
Dot Product: 53.9727
-----------------------
Total: 53.9792
Notice that the timings for both versions of the code are very close with some amount of relatively static overhead to the Python code which decreases for bigger problem sizes: ~50% for m=50, ~10% for m=170
This looks like a very good starting base for my comparative performance investigations.
That looks like about what we expect, thanks! But shouldn't it be printing an explicit statement of correctness, i.e. "C result matches Topographica to 7 DPs"? Also, I'm not sure how to interpret the output; is Serial the Topographica time, and Sequential Total the C time? Also, if the timings are wallclock time, then it should be printing some measure of CPU utilization so that you can verify that the machine was unloaded.
ReplyDelete