在学习像PyTorch或Numpy这样的张量编程语言时,很容易依赖标准库(或者更诚实地说,依赖StackOverflow)来寻找各种神奇的函数。但实际上,张量语言非常强大,你可以通过基本原理和巧妙运用广播机制来完成大多数任务。
这是一个包含21个张量谜题的集合。就像国际象棋谜题一样,这些谜题并不是为了模拟真实程序的复杂性,而是为了在简化的环境中进行练习。每个谜题都要求你在不使用魔法的情况下重新实现NumPy标准库中的一个函数。
我建议在Colab中运行。点击这里并复制笔记本以开始。
如果你感兴趣,这里还有一个解答谜题的YouTube视频教程
!pip install -qqq torchtyping hypothesis pytest git+https://github.com/danoneata/chalk@srush-patch-1 !wget -q https://github.com/srush/Tensor-Puzzles/raw/main/lib.py
from lib import draw_examples, make_test, run_test import torch import numpy as np from torchtyping import TensorType as TT tensor = torch.tensor
每个谜题需要用1行代码(<80列)解决。
你可以使用@、算术运算、比较运算、shape
、任何索引(如a[:j]
、a[:, None]
、a[arange(10)]
)以及之前谜题中的函数。
你不能使用其他任何东西。不允许使用view
、sum
、take
、squeeze
、tensor
。
你可以从这两个函数开始:
def arange(i: int): "使用此函数来替代for循环。" return torch.tensor(range(i)) draw_examples("arange", [{"" : arange(i)} for i in [5, 3, 9]])
# 广播示例 examples = [(arange(4), arange(5)[:, None]) , (arange(3)[:, None], arange(2))] draw_examples("broadcast", [{"a": a, "b":b, "ret": a + b} for a, b in examples])
def where(q, a, b): "使用此函数来替代if语句。" return (q * a) + (~q) * b # 在图表中,橙色表示正/真,白色表示零/假,蓝色表示负。 examples = [(tensor([False]), tensor([10]), tensor([0])), (tensor([False, True]), tensor([1, 1]), tensor([-10, 0])), (tensor([False, True]), tensor([1]), tensor([-10, 0])), (tensor([[False, True], [True, False]]), tensor([1]), tensor([-10, 0])), (tensor([[False, True], [True, False]]), tensor([[0], [10]]), tensor([-10, 0])), ] draw_examples("where", [{"q": q, "a":a, "b":b, "ret": where(q, a, b)} for q, a, b in examples])
计算ones - 全为1的向量。
def ones_spec(out): for i in range(len(out)): out[i] = 1 def ones(i: int) -> TT["i"]: raise NotImplementedError test_ones = make_test("one", ones, ones_spec, add_sizes=["i"])
# run_test(test_ones)
计算sum - 向量的和。
def sum_spec(a, out): out[0] = 0 for i in range(len(a)): out[0] += a[i] def sum(a: TT["i"]) -> TT[1]: raise NotImplementedError test_sum = make_test("sum", sum, sum_spec)
# run_test(test_sum)
计算outer - 两个向量的外积。
def outer_spec(a, b, out): for i in range(len(out)): for j in range(len(out[0])): out[i][j] = a[i] * b[j] def outer(a: TT["i"], b: TT["j"]) -> TT["i", "j"]: raise NotImplementedError test_outer = make_test("outer", outer, outer_spec)
# run_test(test_outer)
计算diag - 方阵的对角线向量。
def diag_spec(a, out): for i in range(len(a)): out[i] = a[i][i] def diag(a: TT["i", "i"]) -> TT["i"]: raise NotImplementedError test_diag = make_test("diag", diag, diag_spec)
# run_test(test_diag)
计算eye - 单位矩阵。
def eye_spec(out): for i in range(len(out)): out[i][i] = 1 def eye(j: int) -> TT["j", "j"]: raise NotImplementedError test_eye = make_test("eye", eye, eye_spec, add_sizes=["j"])
# run_test(test_eye)
计算triu - 上三角矩阵。
def triu_spec(out): for i in range(len(out)): for j in range(len(out)): if i <= j: out[i][j] = 1 else: out[i][j] = 0 def triu(j: int) -> TT["j", "j"]: raise NotImplementedError test_triu = make_test("triu", triu, triu_spec, add_sizes=["j"])
# run_test(test_triu)
计算cumsum - 累积和。
def cumsum_spec(a, out): total = 0 for i in range(len(out)): out[i] = total + a[i] total += a[i] def cumsum(a: TT["i"]) -> TT["i"]: raise NotImplementedError test_cumsum = make_test("cumsum", cumsum, cumsum_spec)
# run_test(test_cumsum)
计算diff - 运行差值。
def diff_spec(a, out): out[0] = a[0] for i in range(1, len(out)): out[i] = a[i] - a[i - 1] def diff(a: TT["i"], i: int) -> TT["i"]: raise NotImplementedError test_diff = make_test("diff", diff, diff_spec, add_sizes=["i"])
# run_test(test_diff)
计算vstack - 两个向量的矩阵
def vstack_spec(a, b, out): for i in range(len(out[0])): out[0][i] = a[i] out[1][i] = b[i] def vstack(a: TT["i"], b: TT["i"]) -> TT[2, "i"]: raise NotImplementedError test_vstack = make_test("vstack", vstack, vstack_spec)
# run_test(test_vstack)
计算roll - 循环移动1个位置的向量。
def roll_spec(a, out): for i in range(len(out)): if i + 1 < len(out): out[i] = a[i + 1] else: out[i] = a[i + 1 - len(out)] def roll(a: TT["i"], i: int) -> TT["i"]: raise NotImplementedError test_roll = make_test("roll", roll, roll_spec, add_sizes=["i"])
# run_test(test_roll)
计算flip - 反转的向量
def flip_spec(a, out): for i in range(len(out)): out[i] = a[len(out) - i - 1] def flip(a: TT["i"], i: int) -> TT["i"]: raise NotImplementedError test_flip = make_test("flip", flip, flip_spec, add_sizes=["i"])
# run_test(test_flip)
计算compress - 只保留掩码条目(左对齐)。
def compress_spec(g, v, out): j = 0 for i in range(len(g)): if g[i]: out[j] = v[i] j += 1 def compress(g: TT["i", bool], v: TT["i"], i:int) -> TT["i"]: raise NotImplementedError test_compress = make_test("compress", compress, compress_spec, add_sizes=["i"])
# run_test(test_compress)
计算pad_to - 通过消除或添加0来改变向量的大小。
def pad_to_spec(a, out): for i in range(min(len(out), len(a))): out[i] = a[i] def pad_to(a: TT["i"], i: int, j: int) -> TT["j"]: raise NotImplementedError test_pad_to = make_test("pad_to", pad_to, pad_to_spec, add_sizes=["i", "j"])
# run_test(test_pad_to)
计算sequence_mask - 每批填充到指定长度。
def sequence_mask_spec(values, length, out): for i in range(len(out)): for j in range(len(out[0])): if j < length[i]: out[i][j] = values[i][j] else: out[i][j] = 0 def sequence_mask(values: TT["i", "j"], length: TT["i", int]) -> TT["i", "j"]: raise NotImplementedError def constraint_set_length(d): d["length"] = d["length"] % d["values"].shape[1] return d test_sequence = make_test("sequence_mask", sequence_mask, sequence_mask_spec, constraint=constraint_set_length )
# run_test(test_sequence)
计算bincount - 统计每个元素出现的次数。
def bincount_spec(a, out): for i in range(len(a)): out[a[i]] += 1 def bincount(a: TT["i"], j: int) -> TT["j"]: raise NotImplementedError def constraint_set_max(d): d["a"] = d["a"] % d["return"].shape[0] return d test_bincount = make_test("bincount", bincount, bincount_spec, add_sizes=["j"], constraint=constraint_set_max )
# run_test(test_bincount)
计算scatter_add - 将链接到同一位置的值相加。
def scatter_add_spec(values, link, out): for j in range(len(values)): out[link[j]] += values[j] def scatter_add(values: TT["i"], link: TT["i"], j: int) -> TT["j"]: raise NotImplementedError def constraint_set_max(d): d["link"] = d["link"] % d["return"].shape[0] return d test_scatter_add = make_test("scatter_add", scatter_add, scatter_add_spec, add_sizes=["j"], constraint=constraint_set_max )
# run_test(test_scatter_add)
计算flatten
def flatten_spec(a, out): k = 0 for i in range(len(a)): for j in range(len(a[0])): out[k] = a[i][j] k += 1 def flatten(a: TT["i", "j"], i:int, j:int) -> TT["i * j"]: raise NotImplementedError test_flatten = make_test("flatten", flatten, flatten_spec, add_sizes=["i", "j"])
# run_test(test_flatten)
计算linspace
def linspace_spec(i, j, out): for k in range(len(out)): out[k] = float(i + (j - i) * k / max(1, len(out) - 1)) def linspace(i: TT[1], j: TT[1], n: int) -> TT["n", float]: raise NotImplementedError test_linspace = make_test("linspace", linspace, linspace_spec, add_sizes=["n"])
# run_test(test_linspace)
def heaviside_spec(a, b, out): for k in range(len(out)): if a[k] == 0: out[k] = b[k] else: out[k] = int(a[k] > 0) def heaviside(a: TT["i"], b: TT["i"]) -> TT["i"]: raise NotImplementedError test_heaviside = make_test("heaviside", heaviside, heaviside_spec)
# run_test(test_heaviside)
计算repeat
def repeat_spec(a, d, out): for i in range(d[0]): for k in range(len(a)): out[i][k] = a[k] def constraint_set(d): d["d"][0] = d["return"].shape[0] return d def repeat(a: TT["i"], d: TT[1]) -> TT["d", "i"]: raise NotImplementedError test_repeat = make_test("repeat", repeat, repeat_spec, constraint=constraint_set)
def bucketize_spec(v, boundaries, out): for i, val in enumerate(v): out[i] = 0 for j in range(len(boundaries)-1): if val >= boundaries[j]: out[i] = j + 1 if val >= boundaries[-1]: out[i] = len(boundaries) def constraint_set(d): d["boundaries"] = np.abs(d["boundaries"]).cumsum() return d def bucketize(v: TT["i"], boundaries: TT["j"]) -> TT["i"]: raise NotImplementedError test_bucketize = make_test("bucketize", bucketize, bucketize_spec, constraint=constraint_set)
你能将每个函数尽可能缩短到多少?
import inspect fns = (ones, sum, outer, diag, eye, triu, cumsum, diff, vstack, roll, flip, compress, pad_to, sequence_mask, bincount, scatter_add) for fn in fns: lines = [l for l in inspect.getsource(fn).split("\n") if not l.strip().startswith("#")] if len(lines) > 3: print(fn.__name__, len(lines[2]), "(超过1行)") else: print(fn.__name__, len(lines[1]))
ones 29
sum 29
outer 29
diag 29
eye 29
triu 29
cumsum 29
diff 29
vstack 29
roll 29
flip 29
compress 29
pad_to 29
sequence_mask 29
bincount 29
scatter_add 29
字节跳动发布的AI编程神器IDE
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。
全能AI智能助手,随时解答生活与工作的多样问题
问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。
实时语音翻译/同声传译工具
Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。
一键生成PPT和Word,让学习生活更轻松
讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或 是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。
深度推理能力全新升级,全面对标OpenAI o1
科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。
一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型
Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。
AI助力,做PPT更简单!
咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。
选题、配图、成文,一站式创作,让内容运营更高效
讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。
专业的AI公文写作平台,公文写作神器
AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。
OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。
openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。
最新AI工具、AI资讯
独家AI资源、AI项目落地
微信扫一扫关注公众号