Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

Autograd – C、Zig、Rust 和 PyCodon 语言

Posted on 2024-11-28

介绍

所以……我应该在我的 DevOps 弧上,但在这里我正在写一篇关于低级编程的文章!这条道路的吸引力太强了,我无法抗拒。我保证,我会在本周末回到 DevOps!

自动梯度

关于 Autograd 有很好的参考:

  • Pytorch Autograd:文本和视频。
  • 中等文章

摘自 Pytorch 网站:

PyTorch 的 Autograd 功能是 PyTorch 灵活快速地构建机器学习项目的一部分。它允许在复杂的计算中快速、轻松地计算多个偏导数(也称为梯度)。此操作是基于反向传播的神经网络学习的核心。

一般用例中的机器学习。

机器学习已被证明在各个领域都非常有用:

  • 医疗保健:促进新型和先进药物的制造进步。在我读过的一篇文章(但未能找到)中,机器学习能够实现快速药物发现:原本需要数十年的研发过程,现在可以在一年内完成。

  • 物流:仓库管理、路线优化、供需预测等。

  • 金融:信用风险评估、欺诈检测、宏观经济预测等。

  • …

股票投资组合管理中的机器学习

我想指出机器学习在我的主要领域的使用:资金管理。让我为您提供基于机器学习的投资组合(也称为量化投资组合)的历史表现图表:

  • 截至 2024 年 10 月的年初至今。
    性能最低的之一。金-1

  • 与其他策略相比 5 年。
    5 年 CAR(复合年利率)远远落后于 HF 综合指数和股票。金-2

  • 10 年绩效比较。
    从长远来看(5-10年),性能非常差。金-3

所以,是的,你可以得出自己的结论,下次有人试图炒作或向你推销复杂的量化基金投资组合时,你可以做出更好的判断,而不是被误导。

我想说的一点是:到目前为止,与基于机器学习的量化基金相比,传统基金管理仍然占据上风。您不必相信我,您可以在这里下载 PDF 报告。

我可以写更多关于量化基金低于平均水平的表现,以及看看它们在 Covid-19 大流行爆发时的表现是多么有趣(剧透:这是最糟糕的基金之一!)。

回到代码!

好了,财务方面的事情已经讲完了,我们在这里讨论 Autograd 基准!我习惯于提供性能最好的语言的代码,因为如果我包含 4 种语言的所有代码,帖子就会变得太长。

我会将所有代码发布到代码存储库中,但同时..性能最高的是 Zig。

[更新]:您可以在pastebin中找到代码:

  • C
  • 之字形
  • 锈

#1 缺点

和往常一样,在编写 Zig 时,我不喜欢 Zig 的冗长,因此这里的 const 是我为减少冗长而做出的努力。

 const std = @import("std"); const testing = std.testing; const print = std.debug.print; const time = std.time.milliTimestamp; const Allocator = std.mem.Allocator; const ArenaAlloc = std.heap.ArenaAllocator; const pageAlloc = std.heap.page_allocator;

#2 枚举和结构

  • OpType 枚举和 NaiveTape 结构是不言自明的。
  • 操作结构:表示具有 OpType、两个输入变量和一个输出变量的操作。
 const OpType = enum(u2) { Sum, Prod, Softplus, }; const NaiveVar = struct { val: f64, grad: f64, pub fn init(val: f64) NaiveVar { return .{ .val = val, .grad = 0.0 }; } }; const Operation = struct { op_type: OpType, inputs: [2]*NaiveVar, output: NaiveVar, };

#3 NaiveTape 结构

  • init:创建新实例。
  • deinit:释放分配的内存。
 const NaiveTape = struct { ops: []Operation, allocator: Allocator, pub fn init(allocator: Allocator) NaiveTape { return .{ .ops = &[_]Operation{}, .allocator = allocator, }; } pub fn deinit(self: *NaiveTape) void { self.allocator.free(self.ops); } // ---Place the various methods here--- // // ---Place the various methods here--- // };

以下是 NaiveTape 结构体上的方法

#3a 求和方法

添加两个输入变量并将结果作为新变量返回。

 pub fn sum(self: *NaiveTape, input1: *NaiveVar, input2: *NaiveVar) !*NaiveVar { const sum_val = input1.val + input2.val; const sum_var = NaiveVar.init(sum_val); const op = Operation{ .op_type = .Sum, .inputs = [_]*NaiveVar{ input1, input2 }, .output = sum_var, }; self.ops = try self.allocator.realloc(self.ops, self.ops.len + 1); self.ops[self.ops.len - 1] = op; return &self.ops[self.ops.len - 1].output; }

#3b 生产方法

将两个输入变量相乘并将结果作为新变量返回。

 pub fn prod(self: *NaiveTape, var1: *NaiveVar, var2: *NaiveVar) !*NaiveVar { const prod_val = var1.val * var2.val; const prod_var = NaiveVar.init(prod_val); const op = Operation{ .op_type = .Prod, .inputs = [_]*NaiveVar{ var1, var2 }, .output = prod_var, }; self.ops = try self.allocator.realloc(self.ops, self.ops.len + 1); self.ops[self.ops.len - 1] = op; return &self.ops[self.ops.len - 1].output; }

#3c Softplus方法

将 softplus 激活函数应用于单个输入变量,并将结果作为新变量返回。

 pub fn softplus(self: *NaiveTape, nvar: *NaiveVar) !*NaiveVar { const softplus_val = std.math.log1p(std.math.exp(nvar.val)); const softplus_var = NaiveVar.init(softplus_val); const op = Operation{ .op_type = .Softplus, .inputs = [_]*NaiveVar{nvar, undefined}, // Only one input needed, second is unused .output = softplus_var, }; self.ops = try self.allocator.realloc(self.ops, self.ops.len + 1); self.ops[self.ops.len - 1] = op; return &self.ops[self.ops.len - 1].output; }

#3d 后向法

  • 该方法以与执行相反的顺序迭代操作(即从输出到输入)。
 pub fn backward(self: *NaiveTape, nvar: *NaiveVar) void { nvar.grad += 1.0; var i = self.ops.len; while (i > 0) { i -= 1; const op = self.ops[i]; switch (op.op_type) { .Sum => { const output_grad = op.output.grad; op.inputs[0].grad += output_grad; op.inputs[1].grad += output_grad; }, .Prod => { const output_grad = op.output.grad; const input1_val = op.inputs[0].val; const input2_val = op.inputs[1].val; op.inputs[0].grad += input2_val * output_grad; op.inputs[1].grad += input1_val * output_grad; }, .Softplus => { const output_grad = op.output.grad; const input_val = op.inputs[0].val; op.inputs[0].grad += output_grad / (1.0 + std.math.exp(-input_val)); }, } } }

#5 主要

主要功能:

  1. 循环该过程 100 万次。
  2. 计算输入变量的总和、乘积和 softplus。
  3. 计算输出变量相对于输入变量的梯度。
  4. 打印运行循环的值、梯度和经过的时间。
 pub fn main() !void { var arena = ArenaAlloc.init(pageAlloc); defer arena.deinit(); const allocator = arena.allocator(); const iterations: usize = 1000000; const start_time = time(); var i: usize = 0; while (i < iterations) : (i += 1) { var var1 = NaiveVar.init(1.0); var var2 = NaiveVar.init(2.0); var tape = NaiveTape.init(allocator); defer tape.deinit(); const sum_var = try tape.sum(&var1, &var2); const prod_var = try tape.prod(sum_var, sum_var); const softplus_var = try tape.softplus(prod_var); tape.backward(softplus_var); if (i == iterations - 1) { print("sum_var val: {d:}\n", .{sum_var.val}); print("prod_var val: {d:}\n", .{prod_var.val}); print("softplus_var val: {d:}\n", .{softplus_var.val}); print("sum_var grad: {d:}\n", .{sum_var.grad}); print("var1 grad: {d:}\n", .{var1.grad}); print("var2 grad: {d:}\n", .{var2.grad}); } } const end_time = time(); const elapsed_time = @as(f64, @floatFromInt(end_time - start_time)); print("\nElapsed time: {d:.3} ms\n", .{elapsed_time}); }

基准结果

autograd-opt-01

==注意== ==:我在所有语言中应用了相同级别的代码优化==。目前我成功地将01优化迭代应用于 4 个语言。

我实际上已经完成了02优化,但仅针对 C,结果令人震惊:经过的时间下降到 0.3 毫秒。不过我还没有时间去实现02版本的其余部分,一旦完成就会更新帖子。

接下来怎么办?

当我完成下一次优化迭代时,我将继续更新这篇文章。另外,我可能会写一些关于我所做的优化的系列文章,特别是在 C、Zig 和 Rust 中。

预览一下我所做的迭代:

  • 00级:不启动优化,只是让程序正确运行。 (完毕)
  • 01 级:优化的第一次迭代。 (完毕)
  • 级别 02:第二次迭代。 (在 Zig 和 Rust 的 C.WIP 中完成)。
  • 0x 级:x 次迭代…您明白了要点。

原文: https://hwisnu.bearblog.dev/autograd-in-c-zig-rust-and-pycodon/

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Lou Plummer
  • Luke Wroblewski
  • Matt Stoller
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme