1. 为什么打印矩阵这件小事值得单独拿出来说但凡用过 PyTorch 的人几乎都写过print(tensor)这行代码。看起来再简单不过但真正在调试模型、检查数据管道、对比中间层输出的时候你会发现默认的打印格式有时候让人抓狂元素太多被省略号截断、浮点数精度长得像电话号码、科学计数法满天飞、GPU 上的张量和 CPU 上的张量打印出来还不一样。这些问题单个看起来不大但累积起来会严重拖慢调试效率。我自己在做一个图像分割项目的时候就吃过这个亏。当时需要检查数据增强后的 mask 张量结果print出来全是...关键区域的像素值根本看不到。后来花了不少时间才搞清楚torch.set_printoptions这个接口的完整用法。从那以后我养成了一个习惯每个新项目启动时先把打印选项配置好后面调试会省很多事。这篇文章就是把我这些年关于 PyTorch 矩阵打印格式控制的经验做一个系统整理。从最基础的set_printoptions参数讲起到不同场景下的配置方案再到和 NumPy 打印的对比、Jupyter 环境下的特殊处理、以及一些官方文档里不会写的坑。不管你是刚接触 PyTorch 的新手还是已经用了几年但一直用默认配置的老手应该都能从里面找到有用的东西。核心关键词就一个PyTorch 控制打印矩阵的格式。围绕这个点我会把相关的参数、原理、实操、避坑全部展开讲透。2. torch.set_printoptions 全参数拆解2.1 这个函数到底控制了什么torch.set_printoptions是 PyTorch 提供的一个全局打印配置接口。所谓“全局”意思是你在代码任何地方调用它之后所有print(tensor)的行为都会受到影响直到你再次修改或者程序结束。它不针对某一个张量生效而是改变整个进程的打印行为。这个函数接受的参数和 NumPy 的numpy.set_printoptions高度相似但也有一些 PyTorch 特有的选项。先看完整的参数列表torch.set_printoptions( precisionNone, thresholdNone, edgeitemsNone, linewidthNone, profileNone, sci_modeNone )每个参数都有默认值传None表示保持当前设置不变。下面逐个拆解。2.2 precision控制浮点数显示几位precision控制的是浮点数打印时小数点后保留几位默认值是 4。这个参数只影响显示不影响张量实际存储的数值。import torch x torch.tensor([1.23456789, 2.34567891, 3.45678912]) print(x) # 默认输出: tensor([1.2346, 2.3457, 3.4568]) torch.set_printoptions(precision2) print(x) # 输出: tensor([1.23, 2.35, 3.46]) torch.set_printoptions(precision8) print(x) # 输出: tensor([1.23456789, 2.34567891, 3.45678912])这里有个细节值得注意precision控制的是“显示精度”不是“四舍五入后的存储值”。张量内部依然是完整的浮点数只是打印时按指定精度截断显示。我做数值对比调试的时候经常把 precision 调到 6 或 8这样能看出微小的数值差异而日常查看时用默认的 4 就够了太长的数字反而影响阅读。还有一个容易踩的坑precision对整数张量没有影响。整数该显示多少位还是多少位不会因为 precision 设置而变化。2.3 threshold决定什么时候用省略号threshold是最容易被忽视但实际最影响调试体验的参数。它控制的是当一个张量的元素总数超过这个阈值时PyTorch 会用省略号...来省略中间部分只显示头尾若干元素。默认值是 1000。torch.set_printoptions(threshold10) x torch.arange(20) print(x) # 输出: tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...])看到那个...了吗这就是 threshold 在起作用。当元素数量超过阈值时PyTorch 只显示前面一部分和后面一部分中间用省略号代替。这里有个非常实用的技巧把threshold设成一个很大的数比如float(inf)就能强制打印完整张量不省略任何元素。torch.set_printoptions(thresholdfloat(inf)) x torch.arange(20) print(x) # 输出: tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])但要注意如果你打印的是一个百万级别元素的张量设成inf会让终端瞬间被刷屏甚至可能卡住。所以这个技巧适合中小规模张量的调试大张量还是老老实实用默认阈值或者先切片再打印。2.4 edgeitems省略时头尾各显示几个edgeitems和threshold是配合使用的。当触发省略时edgeitems决定每个维度开头和结尾各显示多少个元素。默认值是 3。torch.set_printoptions(threshold10, edgeitems2) x torch.arange(20) print(x) # 输出: tensor([0, 1, ..., 18, 19]) torch.set_printoptions(threshold10, edgeitems5) print(x) # 输出: tensor([0, 1, 2, 3, 4, ..., 15, 16, 17, 18, 19])对于多维张量edgeitems会在每个维度上都生效。比如一个 10x10 的矩阵设置edgeitems2后行和列都会只显示头尾各 2 个中间用省略号。torch.set_printoptions(threshold10, edgeitems2) x torch.arange(100).reshape(10, 10) print(x) # 输出: # tensor([[ 0, 1, ..., 8, 9], # [10, 11, ..., 18, 19], # ..., # [80, 81, ..., 88, 89], # [90, 91, ..., 98, 99]])这个格式在查看大矩阵的“轮廓”时特别有用既能看出数据的大致分布又不会刷屏。2.5 linewidth每行最多显示多少字符linewidth控制的是打印时每行的字符宽度上限默认值是 80。当一行内容超过这个宽度时PyTorch 会自动换行。torch.set_printoptions(linewidth40) x torch.arange(20) print(x) # 输出会折成多行这个参数在窄终端或者需要把输出贴到文档里的时候很有用。我一般会根据实际显示环境来调整宽屏终端可以设大一点比如 120写文档或者代码注释里贴输出时设成 60 到 80 比较合适。2.6 profile一键切换预设方案profile是一个快捷参数它提供了一组预设的打印配置。目前支持的值有default、short、full。default恢复默认设置short精简模式precision2, threshold1000, edgeitems2, linewidth80full完整模式precision4, thresholdinf, edgeitems3, linewidth80torch.set_printoptions(profileshort) x torch.randn(5, 5) print(x) # 精度为2显示更紧凑 torch.set_printoptions(profilefull) print(x) # 完整显示不省略profile的好处是省事不用一个个参数去设。但它也有局限预设的组合不一定完全符合你的需求。比如你想要 full 的完整显示但又想要 short 的低精度那就得手动设置各个参数而不能直接用 profile。2.7 sci_mode科学计数法的开关sci_mode控制是否使用科学计数法显示浮点数。默认值是None表示由 PyTorch 自动决定。当数值特别大或特别小的时候PyTorch 会自动切换到科学计数法。x torch.tensor([1e-10, 1e10, 1.5, 0.001]) print(x) # 可能输出: tensor([1.0000e-10, 1.0000e10, 1.5000e00, 1.0000e-03]) torch.set_printoptions(sci_modeFalse) print(x) # 输出: tensor([0.0000, 10000000000.0000, 1.5000, 0.0010])强制关闭科学计数法在查看接近零的小数值时比较有用但要注意如果数值太小关闭科学计数法后会显示成一堆 0反而丢失信息。所以这个参数要根据实际数据的量级来决定。3. 不同场景下的打印配置方案3.1 日常调试平衡可读性和信息量日常开发中大部分时候我们只需要快速看一眼张量的形状和大致数值范围。这时候推荐这样配置torch.set_printoptions( precision4, threshold1000, edgeitems3, linewidth80, sci_modeNone )这基本就是默认配置但明确写出来有个好处团队协作时大家用同一套配置看到的输出格式一致沟通成本更低。我习惯在项目的utils.py或者config.py里放一个setup_print_options()函数在入口处调用一次。3.2 精细数值对比高精度加完整显示做数值验证、梯度检查、或者对比两个模型输出差异的时候需要看到完整的数值和高精度torch.set_printoptions( precision8, thresholdfloat(inf), edgeitems10, linewidth200, sci_modeFalse )这套配置适合中小规模张量元素数在几千以内。如果张量太大thresholdinf会导致输出爆炸这时候更好的做法是先切片# 只打印关心的区域 print(large_tensor[:5, :5]) print(large_tensor[100:105, 200:205])3.3 大张量概览只看轮廓不看细节处理大张量时我们往往只想知道它的形状、数据类型、数值范围不需要看具体每个元素。这时候用精简配置torch.set_printoptions( precision2, threshold100, edgeitems2, linewidth60 )配合torch.min()、torch.max()、torch.mean()这些统计函数一起用能快速掌握张量的整体情况。3.4 输出到日志文件避免换行混乱把张量打印到日志文件时最怕的就是格式混乱、换行不可控。这时候建议torch.set_printoptions( precision4, threshold500, edgeitems3, linewidth120, sci_modeFalse )linewidth设大一点减少不必要的换行sci_modeFalse避免日志里出现e10这种不好搜索的格式。另外写日志时建议用str(tensor)而不是直接print这样能更灵活地控制输出目标。3.5 配置方案速查表场景precisionthresholdedgeitemslinewidthsci_mode日常调试41000380None精细对比8inf10200False大张量概览2100260None日志输出45003120False极简模式220140False4. 实操过程中容易踩的坑4.1 全局设置会影响所有张量torch.set_printoptions是全局生效的这意味着你在代码任何地方改了设置后面所有打印都会变。这在多人协作或者大型项目里可能造成困扰A 模块改了打印精度B 模块的调试输出就跟着变了。我的做法是在需要临时修改打印格式的地方用上下文管理器或者手动保存恢复的方式old_options { precision: 4, threshold: 1000, edgeitems: 3, linewidth: 80 } torch.set_printoptions(precision8, thresholdfloat(inf)) print(debug_tensor) # 恢复 torch.set_printoptions(**old_options)PyTorch 目前没有提供官方的printoptions上下文管理器NumPy 有np.printoptions所以只能手动管理。如果你经常需要临时切换可以自己封装一个from contextlib import contextmanager contextmanager def print_options(**kwargs): # 保存当前设置这里简化处理实际需要记录所有参数 torch.set_printoptions(**kwargs) try: yield finally: torch.set_printoptions(profiledefault)4.2 GPU 张量和 CPU 张量打印格式的差异GPU 上的张量打印时PyTorch 会先把它同步到 CPU 再格式化输出。这个过程在大多数情况下是透明的但有两个细节需要注意第一如果 GPU 显存紧张打印一个超大张量可能会触发显存同步导致短暂的卡顿。第二在某些分布式训练场景下不同进程打印出来的格式可能因为设备不同而有细微差异。实测下来最稳妥的做法是调试打印前先.cpu()既避免设备同步问题也让输出更可控。print(tensor.cpu())4.3 省略号导致的误判threshold触发的省略号有时候会让人误判张量的实际内容。比如你看到tensor([0, 1, 2, ..., 7, 8, 9])以为中间就是 3 到 6但实际上中间可能有几百个元素。这种误判在调试数据管道时特别危险。我的经验是只要看到省略号就说明当前张量元素数超过了 threshold需要进一步确认。要么调大 threshold要么用切片查看具体区域。千万不要凭省略号前后的值去推断中间的内容。4.4 科学计数法的自动切换sci_modeNone时PyTorch 会根据数值范围自动决定是否用科学计数法。这个“自动”的规则并不总是符合直觉有时候同一个张量里一部分元素用科学计数法另一部分不用看起来很不统一。x torch.tensor([0.0001, 0.001, 0.01, 0.1, 1.0, 10.0]) print(x) # 可能输出: tensor([1.0000e-04, 1.0000e-03, 1.0000e-02, 1.0000e-01, 1.0000e00, 1.0000e01])如果你希望输出格式统一建议显式设置sci_modeTrue或sci_modeFalse不要依赖自动模式。4.5 Jupyter Notebook 里的显示差异在 Jupyter Notebook 里张量的显示走的是_repr_html_或者__repr__和终端里的print行为不完全一样。Notebook 会自动把张量渲染成更美观的 HTML 表格但set_printoptions的设置依然生效。有个细节Notebook 里如果单元格最后一行是一个张量它会用富文本方式显示这时候省略号的样式和终端不同。如果你想要和终端一致的纯文本输出需要显式用print()。# Notebook 单元格 x torch.randn(100, 100) x # 富文本显示可能带滚动条 print(x) # 纯文本显示受 set_printoptions 控制5. 进阶技巧与常见问题排查5.1 自定义张量打印格式除了set_printoptionsPyTorch 还允许通过torch.Tensor.__repr__的自定义来改变打印行为但这种方式不推荐因为它会破坏默认的调试体验。更实用的做法是写一个自己的格式化函数def format_tensor(t, precision4, max_elements20): 按指定格式输出张量摘要 flat t.flatten() if flat.numel() max_elements: return fTensor(shape{list(t.shape)}, values{flat.tolist()}) else: return (fTensor(shape{list(t.shape)}, fmin{flat.min().item():.{precision}f}, fmax{flat.max().item():.{precision}f}, fmean{flat.mean().item():.{precision}f}))这种自定义函数在需要把张量信息写入结构化日志时特别有用比直接print更可控。5.2 和 NumPy 打印格式的对比PyTorch 的打印选项设计明显参考了 NumPy但两者并不完全一致。主要差异有特性PyTorchNumPy全局设置函数torch.set_printoptionsnumpy.set_printoptions上下文管理器无官方支持numpy.printoptions默认 precision48默认 threshold10001000默认 edgeitems33默认 linewidth8075profile 参数支持不支持如果你同时用 PyTorch 和 NumPy建议分别设置不要指望一套配置两边通用。我一般会在项目初始化时分别调用两个库的设置函数。5.3 常见问题速查表问题现象可能原因解决方法输出全是省略号threshold 太小调大 threshold 或设 inf浮点数太长precision 太大调小 precision科学计数法混乱sci_mode 自动显式设 True 或 False输出换行混乱linewidth 不合适根据终端宽度调整设置不生效被后续代码覆盖检查是否有其他地方调用了 set_printoptionsGPU 张量打印卡顿设备同步先 .cpu() 再打印Notebook 显示不一致富文本渲染用 print() 强制纯文本5.4 几个我踩过的坑第一个坑在循环里反复调用set_printoptions。这个函数虽然不慢但频繁调用没必要。更好的做法是在循环外设置一次循环内只管打印。第二个坑以为precision会影响计算结果。实际上它只影响显示不影响任何数值运算。我见过有同学为了“提高精度”把 precision 调到 10结果只是打印变长了计算精度一点没变。第三个坑在多进程环境里每个进程的打印设置是独立的。如果你用 DataLoader 的num_workers0子进程里的打印设置不会继承主进程的。需要在子进程的初始化函数里单独设置。第四个坑thresholdfloat(inf)在打印超大张量时可能导致内存问题。因为格式化输出需要构建完整的字符串百万级元素的张量会生成一个巨大的字符串可能撑爆内存。大张量还是老老实实用切片。5.5 一个实用的调试封装最后分享一个我常用的调试打印封装结合了上面提到的各种技巧def debug_print(tensor, nametensor, fullFalse): 调试用张量打印自动处理设备和大张量 if not isinstance(tensor, torch.Tensor): print(f{name}: {tensor}) return # 转到 CPU 避免设备同步 t tensor.detach().cpu() # 根据张量大小决定打印策略 if full or t.numel() 100: torch.set_printoptions(precision6, thresholdfloat(inf), linewidth120, sci_modeFalse) print(f{name} (shape{list(t.shape)}, dtype{t.dtype}):) print(t) else: torch.set_printoptions(precision4, threshold100, edgeitems3, linewidth100) print(f{name} (shape{list(t.shape)}, dtype{t.dtype}):) print(t) print(f min{t.min().item():.6f}, max{t.max().item():.6f}, fmean{t.mean().item():.6f}, std{t.std().item():.6f}) # 恢复默认 torch.set_printoptions(profiledefault)这个函数的好处是自动处理设备、根据张量大小选择策略、附带统计信息、用完自动恢复默认设置。在实际项目里用起来很顺手推荐你也试试。关于打印格式这块其实还有很多细节可以挖比如不同 PyTorch 版本之间的行为差异、和 TensorBoard 等可视化工具的配合、以及在分布式训练中的日志格式统一问题。但上面这些已经覆盖了日常开发中 90% 以上的场景。把set_printoptions的六个参数搞清楚再结合具体场景选一套配置调试效率会有明显提升。 SEO 优化官网定制响应式建站教育培训建站