Skip to content

Commit cb10145

Browse files
author
pengcheng888
committed
issue/896 - 为c++和python中的tensor添加打印函数
1 parent 148b475 commit cb10145

14 files changed

Lines changed: 1196 additions & 15 deletions

File tree

include/infinicore.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "infinicore/device_event.hpp"
4+
#include "infinicore/io.hpp"
45
#include "infinicore/nn.hpp"
56
#include "infinicore/ops.hpp"
6-
#include "infinicore/tensor.hpp"
7+
#include "infinicore/tensor.hpp"

include/infinicore/io.hpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#pragma once
2+
3+
#include <iostream>
4+
5+
namespace infinicore::print_options {
6+
7+
/**
8+
* @brief Sets the line width. After \a line_width chars, a new line is added.
9+
* @param line_width The line width
10+
*/
11+
void set_line_width(int line_width);
12+
13+
/**
14+
* @brief Sets the threshold after which summarization is triggered (default: 1000).
15+
* @param threshold The number of elements in the tensor that triggers summarization in the output
16+
*/
17+
void set_threshold(int threshold);
18+
19+
/**
20+
* @brief Sets the number of edge items.
21+
* If the summarization is triggered, this value defines how many items of each dimension are printed.
22+
* @param edge_items The number of edge items
23+
*/
24+
void set_edge_items(int edge_items);
25+
26+
/**
27+
* @brief Sets the precision for printing floating point values.
28+
* @param precision The number of digits for floating point output
29+
*/
30+
31+
void set_precision(int precision);
32+
33+
/**
34+
* @brief Sets the sci mode of the floating point values when printing an Tensor.
35+
* @param sci_mode The sci mode: -1 for auto decision, 0 to disable, 1 to enable
36+
*/
37+
38+
void set_sci_mode(int sci_mode); // -1: auto, 0: disable, 1: enable
39+
40+
#define DEFINE_LOCAL_PRINT_OPTION(NAME) \
41+
class NAME { \
42+
public: \
43+
NAME(int value) : m_value(value) { id(); } \
44+
static int id() { \
45+
static int id = std::ios_base::xalloc(); \
46+
return id; \
47+
} \
48+
int value() const { return m_value; } \
49+
\
50+
private: \
51+
int m_value; \
52+
}; \
53+
\
54+
inline std::ostream &operator<<(std::ostream &out, const NAME &n) { \
55+
out.iword(NAME::id()) = n.value(); \
56+
return out; \
57+
}
58+
59+
/**
60+
* @class line_width
61+
* io manipulator used to set the width of the lines when printing an Tensor.
62+
*
63+
* @code{.cpp}
64+
* using po = infinicore::print_options;
65+
* std::cout << po::line_width(100) << tensor << std::endl;
66+
* @endcode
67+
*/
68+
DEFINE_LOCAL_PRINT_OPTION(line_width)
69+
70+
/**
71+
* io manipulator used to set the threshold after which summarization is triggered.
72+
*/
73+
DEFINE_LOCAL_PRINT_OPTION(threshold)
74+
75+
/**
76+
* io manipulator used to set the number of egde items if the summarization is triggered.
77+
*/
78+
DEFINE_LOCAL_PRINT_OPTION(edge_items)
79+
80+
/**
81+
* io manipulator used to set the precision of the floating point values when printing an Tensor.
82+
*/
83+
DEFINE_LOCAL_PRINT_OPTION(precision)
84+
85+
} // namespace infinicore::print_options

include/infinicore/tensor.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <algorithm>
88
#include <cassert>
99
#include <functional>
10+
#include <iostream>
1011
#include <memory>
1112
#include <vector>
1213

@@ -92,6 +93,8 @@ class Tensor {
9293
friend class TensorImpl;
9394

9495
void resume_from_blob_() const;
96+
97+
friend std::ostream &operator<<(std::ostream &os, const Tensor &tensor);
9598
};
9699

97100
class TensorImpl : public std::enable_shared_from_this<TensorImpl> {
@@ -303,4 +306,4 @@ class TensorImpl : public std::enable_shared_from_this<TensorImpl> {
303306
TensorData data_;
304307
};
305308

306-
} // namespace infinicore
309+
} // namespace infinicore

python/infinicore/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import infinicore.context as context
44
import infinicore.nn as nn
5+
from infinicore._tensor_str import printoptions, set_printoptions
56

67
# Import context functions
78
from infinicore.context import (
@@ -134,6 +135,8 @@
134135
"strided_empty",
135136
"strided_from_blob",
136137
"zeros",
138+
"set_printoptions",
139+
"printoptions",
137140
]
138141

139142
use_ntops = False

python/infinicore/_tensor_str.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import contextlib
2+
import dataclasses
3+
from typing import Any, Optional
4+
5+
from infinicore.lib import _infinicore
6+
7+
8+
@dataclasses.dataclass
9+
class __PrinterOptions:
10+
precision: int = 4
11+
threshold: float = 1000
12+
edgeitems: int = 3
13+
linewidth: int = 80
14+
sci_mode: Optional[bool] = None
15+
16+
17+
PRINT_OPTS = __PrinterOptions()
18+
19+
20+
def set_printoptions(
21+
precision=None,
22+
threshold=None,
23+
edgeitems=None,
24+
linewidth=None,
25+
profile=None,
26+
sci_mode=None,
27+
):
28+
r"""Set options for printing.
29+
30+
Args:
31+
precision: Number of digits of precision for floating point output (default = 4).
32+
threshold: Total number of array elements which trigger summarization rather than full `repr` (default = 1000).
33+
edgeitems: Number of array items in summary at beginning and end of each dimension (default = 3).
34+
linewidth: The number of characters per line (default = 80).
35+
profile: Sane defaults for pretty printing. Can override with any of the above options. (any one of `default`, `short`, `full`)
36+
sci_mode: Enable (True) or disable (False) scientific notation.
37+
If None (default) is specified, the value is automatically chosen by the framework.
38+
39+
Example::
40+
>>> # Limit the precision of elements
41+
>>> torch.set_printoptions(precision=2)
42+
>>> torch.tensor([1.12345])
43+
tensor([1.12])
44+
45+
"""
46+
if profile is not None:
47+
if profile == "default":
48+
PRINT_OPTS.precision = 4
49+
PRINT_OPTS.threshold = 1000
50+
PRINT_OPTS.edgeitems = 3
51+
PRINT_OPTS.linewidth = 80
52+
elif profile == "short":
53+
PRINT_OPTS.precision = 2
54+
PRINT_OPTS.threshold = 1000
55+
PRINT_OPTS.edgeitems = 2
56+
PRINT_OPTS.linewidth = 80
57+
elif profile == "full":
58+
PRINT_OPTS.precision = 4
59+
PRINT_OPTS.threshold = 2147483647 # CPP_INT32_MAX
60+
PRINT_OPTS.edgeitems = 3
61+
PRINT_OPTS.linewidth = 80
62+
else:
63+
raise ValueError(
64+
f"Invalid profile: {profile}. the profile must be one of 'default', 'short', 'full'"
65+
)
66+
67+
if precision is not None:
68+
PRINT_OPTS.precision = precision
69+
if threshold is not None:
70+
PRINT_OPTS.threshold = threshold
71+
if edgeitems is not None:
72+
PRINT_OPTS.edgeitems = edgeitems
73+
if linewidth is not None:
74+
PRINT_OPTS.linewidth = linewidth
75+
PRINT_OPTS.sci_mode = sci_mode
76+
77+
_infinicore.set_printoptions(
78+
PRINT_OPTS.precision,
79+
PRINT_OPTS.threshold,
80+
PRINT_OPTS.edgeitems,
81+
PRINT_OPTS.linewidth,
82+
PRINT_OPTS.sci_mode,
83+
)
84+
85+
86+
def get_printoptions() -> dict[str, Any]:
87+
r"""Gets the current options for printing, as a dictionary that
88+
can be passed as ``**kwargs`` to set_printoptions().
89+
"""
90+
return dataclasses.asdict(PRINT_OPTS)
91+
92+
93+
@contextlib.contextmanager
94+
def printoptions(
95+
precision=None, threshold=None, edgeitems=None, linewidth=None, sci_mode=None
96+
):
97+
r"""Context manager that temporarily changes the print options."""
98+
old_kwargs = get_printoptions()
99+
100+
set_printoptions(
101+
precision=precision,
102+
threshold=threshold,
103+
edgeitems=edgeitems,
104+
linewidth=linewidth,
105+
sci_mode=sci_mode,
106+
)
107+
try:
108+
yield
109+
finally:
110+
set_printoptions(**old_kwargs)
111+
112+
113+
def _str(self):
114+
cpp_tensor_str = self._underlying.__str__()
115+
py_dtype_str = "dtype=" + self.dtype.__repr__()
116+
return cpp_tensor_str.split("dtype=INFINI.")[0] + py_dtype_str + ")\n"

python/infinicore/tensor.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import infinicore.dtype
77
from infinicore.lib import _infinicore
88

9+
from ._tensor_str import _str
910
from .utils import (
1011
infinicore_to_numpy_dtype,
1112
numpy_to_infinicore_dtype,
@@ -130,6 +131,9 @@ def __mul__(self, other):
130131
def narrow(self, dim, start, length):
131132
return infinicore.narrow(self, dim, start, length)
132133

134+
def __repr__(self):
135+
return _str(self)
136+
133137

134138
def empty(size, *, dtype=None, device=None, pin_memory=False):
135139
return Tensor(

python/infinicore/utils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ def to_torch_dtype(infini_dtype):
1111
return torch.float16
1212
elif infini_dtype == infinicore.float32:
1313
return torch.float32
14+
elif infini_dtype == infinicore.float64:
15+
return torch.float64
1416
elif infini_dtype == infinicore.bfloat16:
1517
return torch.bfloat16
1618
elif infini_dtype == infinicore.int8:
@@ -23,6 +25,8 @@ def to_torch_dtype(infini_dtype):
2325
return torch.int64
2426
elif infini_dtype == infinicore.uint8:
2527
return torch.uint8
28+
elif infini_dtype == infinicore.bool:
29+
return torch.bool
2630
else:
2731
raise ValueError(f"Unsupported infinicore dtype: {infini_dtype}")
2832

@@ -93,5 +97,7 @@ def infinicore_to_numpy_dtype(infini_dtype):
9397
return np.int64
9498
elif infini_dtype == infinicore.uint8:
9599
return np.uint8
100+
elif infini_dtype == infinicore.bool:
101+
return np.bool_
96102
else:
97103
raise ValueError(f"Unsupported infinicore dtype: {infini_dtype}")

src/infinicore-test/test_nn_module.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -898,8 +898,8 @@ TestResult NNModuleTest::testModuleLinear() {
898898

899899
// Test forward with residual connection
900900
spdlog::info("Testing Linear forward with residual connection");
901-
auto residual = infinicore::Tensor::ones({2, 4}, infinicore::DataType::F32, infinicore::Device());
902-
auto output_with_residual = m1.forward(input1, residual);
901+
// auto residual = infinicore::Tensor::ones({2, 4}, infinicore::DataType::F32, infinicore::Device());
902+
auto output_with_residual = m1.forward(input1);
903903
if (output_with_residual->shape() != std::vector<size_t>({2, 4})) {
904904
spdlog::error("Linear output with residual shape mismatch. Expected {{2, 4}}, got different shape");
905905
return false;
@@ -911,10 +911,10 @@ TestResult NNModuleTest::testModuleLinear() {
911911

912912
// Create test data with known values for verification
913913
auto test_input = infinicore::Tensor::ones({2, 8}, infinicore::DataType::F32, infinicore::Device());
914-
auto test_residual = infinicore::Tensor::ones({2, 4}, infinicore::DataType::F32, infinicore::Device());
914+
// auto test_residual = infinicore::Tensor::ones({2, 4}, infinicore::DataType::F32, infinicore::Device());
915915

916916
// Get InfiniCore result
917-
auto infinicore_output = m1.forward(test_input, test_residual);
917+
auto infinicore_output = m1.forward(test_input);
918918

919919
// Compute naive result: output = input @ weight.T + bias + residual
920920
auto naive_output = infinicore::Tensor::empty({2, 4}, infinicore::DataType::F32, infinicore::Device());
@@ -935,7 +935,7 @@ TestResult NNModuleTest::testModuleLinear() {
935935
infinicore::op::add_(naive_output, matmul_result, bias_view);
936936

937937
// Add residual
938-
infinicore::op::add_(naive_output, naive_output, test_residual);
938+
// infinicore::op::add_(naive_output, naive_output, test_residual);
939939

940940
// Compare results with actual value checking
941941
if (infinicore_output->shape() != naive_output->shape()) {
@@ -956,10 +956,10 @@ TestResult NNModuleTest::testModuleLinear() {
956956
// Test computation correctness without bias (using m2)
957957
spdlog::info("Testing computation correctness without bias");
958958
auto test_input_no_bias = infinicore::Tensor::ones({1, 16}, infinicore::DataType::F32, infinicore::Device());
959-
auto test_residual_no_bias = infinicore::Tensor::ones({1, 3}, infinicore::DataType::F32, infinicore::Device());
959+
// auto test_residual_no_bias = infinicore::Tensor::ones({1, 3}, infinicore::DataType::F32, infinicore::Device());
960960

961961
// Get InfiniCore result (no bias)
962-
auto infinicore_output_no_bias = m2.forward(test_input_no_bias, test_residual_no_bias);
962+
auto infinicore_output_no_bias = m2.forward(test_input_no_bias);
963963

964964
// Compute naive result without bias: output = input @ weight.T + residual
965965
auto naive_output_no_bias = infinicore::Tensor::empty({1, 3}, infinicore::DataType::F32, infinicore::Device());
@@ -970,7 +970,7 @@ TestResult NNModuleTest::testModuleLinear() {
970970
auto matmul_result_no_bias = infinicore::op::matmul(test_input_no_bias, weight_t_no_bias); // [1, 3]
971971

972972
// Add residual
973-
infinicore::op::add_(naive_output_no_bias, matmul_result_no_bias, test_residual_no_bias);
973+
// infinicore::op::add_(naive_output_no_bias, matmul_result_no_bias, test_residual_no_bias);
974974

975975
// Compare results with actual value checking
976976
if (infinicore_output_no_bias->shape() != naive_output_no_bias->shape()) {

0 commit comments

Comments
 (0)