Skip to content

ND tensor printing#509

Merged
mratsim merged 11 commits intomratsim:masterfrom
Vindaar:NDprinting
Jul 4, 2021
Merged

ND tensor printing#509
mratsim merged 11 commits intomratsim:masterfrom
Vindaar:NDprinting

Conversation

@Vindaar
Copy link
Copy Markdown
Collaborator

@Vindaar Vindaar commented Jun 30, 2021

(will write in a few min)

edit:

Well, a few minutes quickly turn into an hour, haha.

This finally improves the pretty printing of an ND tensors. Instead of special casing each dimension, this is a generic approach that should scale to N dimensions. I've only tested to 5D (see tests), but that works fine. At even higher dimensions the algorithm should work correctly, but it's possible that the layouting of separator lines might not look perfectly.

The idea is simple:

  • start with an ND tensor
  • if N > 2 take axis 0 and iterate over that axis. Recurse on the tensor slice
    • if current slice is of odd rank, stack the result horizontally (next to each other)
    • if current slice is of even rank, stack the result vertically (on top of each other)
  • once N = 2, use the existing (slightly modified) 2D pretty printing code

In addition we add separators between the vertical / horizontal splits based on the current rank. On the outside of each printed block, the current index of that axis is printed.
The required alignment of the fields is performed by an initial string conversion of all elements and picking the largest string as a reference. If one stores a novel in a Tensor[string] it'll thus be ugly. :P This leads to perfect alignment independent of the scale of numbers stored. If very large and very small numbers appear it leads to a lot of whitespace between the smalll numbers. I preferred that to aligning only sub tensors.

There remains one question: the Haskell implementation referenced by @mratsim in #5 and #500 prints the number of the axis instead of the index along that axis on the outside. I personally prefer the approach I implemented as it allows to read off the exact index even in large outputs rather easily without manual counting. It does require one to think about which number corresponds to what axis though.

A note on performance: pretty printing a tensor is slow. I did not make (nor did the existing code) make any attempts at making sure all the string operations are particularly fast!

An example:

let t1 = toSeq(1..144).toTensor().reshape(2,3,4,3,2)
echo t1
# Tensor[system.int] of shape "[2, 3, 4, 3, 2]" on backend "Cpu"
#                           0                            |                            1
#        0            1            2            3        |         0            1            2            3
#   |1        2| |7        8| |13      14| |19      20|  |    |73      74| |79      80| |85      86| |91      92|
# 0 |3        4| |9       10| |15      16| |21      22|  |  0 |75      76| |81      82| |87      88| |93      94|
#   |5        6| |11      12| |17      18| |23      24|  |    |77      78| |83      84| |89      90| |95      96|
#   ---------------------------------------------------  |    ---------------------------------------------------
#        0            1            2            3        |         0            1            2            3
#   |25      26| |31      32| |37      38| |43      44|  |    |97      98| |103    104| |109    110| |115    116|
# 1 |27      28| |33      34| |39      40| |45      46|  |  1 |99     100| |105    106| |111    112| |117    118|
#   |29      30| |35      36| |41      42| |47      48|  |    |101    102| |107    108| |113    114| |119    120|
#   ---------------------------------------------------  |    ---------------------------------------------------
#        0            1            2            3        |         0            1            2            3
#   |49      50| |55      56| |61      62| |67      68|  |    |121    122| |127    128| |133    134| |139    140|
# 2 |51      52| |57      58| |63      64| |69      70|  |  2 |123    124| |129    130| |135    136| |141    142|
#   |53      54| |59      60| |65      66| |71      72|  |    |125    126| |131    132| |137    138| |143    144|
#   ---------------------------------------------------  |    ---------------------------------------------------

edit2:

As the CI is still failing, maybe it's a good idea to make another PR to fix it first and then rebase.
Aside from that I should probably add a pretty printing Tensor[float] example as well.

edit3:

Ah, another thing I forgot to mention: If we consider merging this, should I remove the existing disp3d and disp4d procedures?

@Vindaar
Copy link
Copy Markdown
Collaborator Author

Vindaar commented Jul 3, 2021

Ok, I've cleaned it up a bit now. Removed the disp3d and disp4d proc, added a custom precision argument for floating point tensors and restructured the $ to use pretty.

Also applied the changes to CUDA tensors. From my side this seems done for now.

One idea I have that could improve it further: Allow coloring the separators | and - for better visibility. But I'm not sure if it's a good idea to apply color to these always.

@Vindaar
Copy link
Copy Markdown
Collaborator Author

Vindaar commented Jul 3, 2021

And now I've added a tutorial section explaining the pretty printing. now I'm actually done.

@Vindaar
Copy link
Copy Markdown
Collaborator Author

Vindaar commented Jul 3, 2021

Ah, and of course we immediately run into regressions of float printing between Nim version 1.0 and current devel. I'll put the float printing tests behind a nim version check.

@Vindaar
Copy link
Copy Markdown
Collaborator Author

Vindaar commented Jul 3, 2021

Rebased onto current master to resolve merge conflict about slicing tutorial.

@Vindaar Vindaar closed this Jul 3, 2021
@Vindaar Vindaar reopened this Jul 3, 2021
@mratsim
Copy link
Copy Markdown
Owner

mratsim commented Jul 4, 2021

Thanks, that' awesome!

@mratsim mratsim merged commit 151de6d into mratsim:master Jul 4, 2021
@Vindaar Vindaar mentioned this pull request Oct 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants