一、MicroGrad

MicroGrad是大牛Andrej Karpathy写的一个非常轻量级别的神经网络库(框架),其基本构成为一个90行python代码的标量反向传播(自动微分)引擎,以及在此基础上实现的神经网络层。

其介绍如下:

A tiny scalar-valued autograd engine and a neural net library on top of it with PyTorch-like API

Andrej Karpathy时长2.5小时的通俗易懂的讲解,一步一步教你构建MicroGrad。学习完视频,相信可以一窥现代深度学习框架的底层实现。Bili视频链接:https://www.bilibili.com/video/BV1aB4y13761/?vd_source=e5f3442199b63a8df006d57974ad4e23

Github链接:https://github.com/karpathy/micrograd



项目除了框架源码外,给出了基于该库在一个二分类数据集上训练了一个2层MLP,源码为demo.ipynb

此外,给出了基于graphviz库的神经网络计算图可视化notebooktrace_graph.ipynb,可以形象地观察前向和反向传播过程。

接下来将简要介绍一下其标量反向传播引擎engine.py和神经网络层nn.py

二、标量反向传播引擎Engine

2.1 反向传播与自动微分

反向传播的核心就是链式法则,而深度神经网络的反向传播最多再加一个矩阵求导。

在反向传播的过程,本质是求网络的每个参数关于最终损失函数的梯度,而该梯度可以成是回传的全局梯度和局部梯度之乘。

形象地说,梯度代表了当前层参数的变化,对最终预测损失的影响(变化率),而该变化率实际取决于当前层参数对下一层输入的影响,以及下一层输入对最终预测损失的影响。两个变化一乘,不就是当前层参数对对最终预测损失的影响。

神经网络本质上可视为一个复杂函数,而该函数的计算公式无论多复杂,都可分解为一系列基本的算数运算(加减乘除等)和基本函数(exp,log,sin,cos,等)等。对相关操作进行分解,同时应用链式求导法则,就可以实现自动微分。

形如:c = 3a + b, o = 2 * c。直观的说,每个参与运行的变量以及运算符都要建模成一个节点,从而构成计算图。

2.2 标量Value类

为了实现自动微分,作者具体实现了一个Engine引擎。

Engine的核心其实就是实现了一个标量Value类,其关键就是在标量值的基础上实现基础运算和其它复杂运算(算子)的前向和反向传播(对基本运行进行了重写)。

为了构建计算图,并在其基础上执行从输出到各个运算节点的梯度反向回传,它绑定了相应的运算关系。为此,每个最基本的计算操作都会生成一个标量Value对象,同时记录产生该对象的运算类型以及参与运算的对象(children)。

每个Value对象都可以视为一个计算节点,在每次计算过程中,中间变量也会被建模成一个计算节点。

class Value:
""" stores a single scalar value and its gradient """ def __init__(self, data, _children=(), _op=''):
self.data = data # 标量数据
self.grad = 0 # 对应梯度值,初始为0 # 用于构建自动微分图的内部变量
self._backward = lambda: None # 计算梯度的函数
self._prev = set(_children) # 前向节点(参与该运算的Value对象集合),将用于反向传播
self._op = _op # 产生这个计算节点的运算类型

例如对于如下的+运算:

x = Value(1.0)
y = x + 2

首先,构建Value对象x, 然后在执行+的过程中,调用x.add(self, other)方法。此时,2也被构建为一个Value对象。然后执行如下操作:

out = Value(self.data + other.data, (self, other), '+')

最终,返回一个代表计算结果(记录了前向节点)的新Value对象y。

废话不多说,直接上完整源码。

class Value:
""" stores a single scalar value and its gradient """ def __init__(self, data, _children=(), _op=''):
self.data = data
self.grad = 0
# internal variables used for autograd graph construction
self._backward = lambda: None
self._prev = set(_children)
self._op = _op # the op that produced this node, for graphviz / debugging / etc def __add__(self, other):
other = other if isinstance(other, Value) else Value(other)
out = Value(self.data + other.data, (self, other), '+') def _backward():
self.grad += out.grad
other.grad += out.grad
out._backward = _backward return out def __mul__(self, other):
other = other if isinstance(other, Value) else Value(other)
out = Value(self.data * other.data, (self, other), '*') def _backward():
self.grad += other.data * out.grad
other.grad += self.data * out.grad
out._backward = _backward return out def __pow__(self, other):
assert isinstance(other, (int, float)), "only supporting int/float powers for now"
out = Value(self.data**other, (self,), f'**{other}') def _backward():
self.grad += (other * self.data**(other-1)) * out.grad
out._backward = _backward return out def relu(self):
out = Value(0 if self.data < 0 else self.data, (self,), 'ReLU') def _backward():
self.grad += (out.data > 0) * out.grad
out._backward = _backward return out def backward(self): # topological order all of the children in the graph
topo = []
visited = set()
def build_topo(v):
if v not in visited:
visited.add(v)
for child in v._prev:
build_topo(child)
topo.append(v)
build_topo(self) # go one variable at a time and apply the chain rule to get its gradient
self.grad = 1
for v in reversed(topo):
v._backward() def __neg__(self): # -self
return self * -1 def __radd__(self, other): # other + self
return self + other def __sub__(self, other): # self - other
return self + (-other) def __rsub__(self, other): # other - self
return other + (-self) def __rmul__(self, other): # other * self
return self * other def __truediv__(self, other): # self / other
return self * other**-1 def __rtruediv__(self, other): # other / self
return other * self**-1 def __repr__(self):
return f"Value(data={self.data}, grad={self.grad})"

有了该框架后,就可构建出计算图。然后,通过基于拓扑排序的backward(self)方法,来进行反向传播。

Value类其实很类似于Pytorh中的Variable类,基于它就可构造复杂的神经网络,而不必手动的计算梯度。

三、简易网络

import random
from micrograd.engine import Value class Module: def zero_grad(self):
for p in self.parameters():
p.grad = 0 def parameters(self):
return [] class Neuron(Module): def __init__(self, nin, nonlin=True):
self.w = [Value(random.uniform(-1,1)) for _ in range(nin)]
self.b = Value(0)
self.nonlin = nonlin def __call__(self, x):
act = sum((wi*xi for wi,xi in zip(self.w, x)), self.b)
return act.relu() if self.nonlin else act def parameters(self):
return self.w + [self.b] def __repr__(self):
return f"{'ReLU' if self.nonlin else 'Linear'}Neuron({len(self.w)})" class Layer(Module): def __init__(self, nin, nout, **kwargs):
self.neurons = [Neuron(nin, **kwargs) for _ in range(nout)] def __call__(self, x):
out = [n(x) for n in self.neurons]
return out[0] if len(out) == 1 else out def parameters(self):
return [p for n in self.neurons for p in n.parameters()] def __repr__(self):
return f"Layer of [{', '.join(str(n) for n in self.neurons)}]" class MLP(Module): def __init__(self, nin, nouts):
sz = [nin] + nouts
self.layers = [Layer(sz[i], sz[i+1], nonlin=i!=len(nouts)-1) for i in range(len(nouts))] def __call__(self, x):
for layer in self.layers:
x = layer(x)
return x def parameters(self):
return [p for layer in self.layers for p in layer.parameters()] def __repr__(self):
return f"MLP of [{', '.join(str(layer) for layer in self.layers)}]"

未完待续

微型神经网络库MicroGrad-基于标量自动微分的类pytorch接口的深度学习框架的更多相关文章

  1. 开源脉冲神经网络深度学习框架——惊蛰(SpikingJelly)

    开源脉冲神经网络深度学习框架--惊蛰(SpikingJelly) 背景 近年来神经形态计算芯片发展迅速,大量高校企业团队跟进,这样的芯片运行SNN的能效比与速度都超越了传统的通用计算设备.相应的,神经 ...

  2. 分享《机器学习实战基于Scikit-Learn和TensorFlow》中英文PDF源代码+《深度学习之TensorFlow入门原理与进阶实战》PDF+源代码

    下载:https://pan.baidu.com/s/1qKaDd9PSUUGbBQNB3tkDzw <机器学习实战:基于Scikit-Learn和TensorFlow>高清中文版PDF+ ...

  3. 人工智能深度学习框架MXNet实战:深度神经网络的交通标志识别训练

    人工智能深度学习框架MXNet实战:深度神经网络的交通标志识别训练 MXNet 是一个轻量级.可移植.灵活的分布式深度学习框架,2017 年 1 月 23 日,该项目进入 Apache 基金会,成为 ...

  4. 基于Theano的深度学习框架keras及配合SVM训练模型

    https://blog.csdn.net/a819825294/article/details/51334397 1.介绍 Keras是基于Theano的一个深度学习框架,它的设计参考了Torch, ...

  5. 解析基于keras深度学习框架下yolov3的算法

    一.前言 由于前一段时间以及实现了基于keras深度学习框架下yolov3的算法,本来想趁着余热将自己的心得体会进行总结,但由于前几天有点事就没有完成计划,现在趁午休时间整理一下. 二.Keras框架 ...

  6. 深度学习框架如何自动选择最快的算法?Fast Run 让你收获最好的性能!

    作者:王博文 | 旷视 MegEngine 架构师 一.背景 对于深度学习框架来说,网络的训练/推理时间是用户非常看中的.在实际生产条件下,用户设计的 NN 网络是千差万别,即使是同一类数学计算,参数 ...

  7. TensorFlow+实战Google深度学习框架学习笔记(5)----神经网络训练步骤

    一.TensorFlow实战Google深度学习框架学习 1.步骤: 1.定义神经网络的结构和前向传播的输出结果. 2.定义损失函数以及选择反向传播优化的算法. 3.生成会话(session)并且在训 ...

  8. 深度学习框架之TensorFlow的概念及安装(ubuntu下基于pip的安装,IDE为Pycharm)

    2015年11月9日,Google发布人工智能系统TensorFlow并宣布开源. 1.TensorFlow的概念 TensorFlow 是使用数据流图进行数值计算的开源软件库.也就是说,Tensor ...

  9. 基于C#的机器学习--c# .NET中直观的深度学习

    在本章中,将会学到: l  如何使用Kelp.Net来执行自己的测试 l  如何编写测试 l  如何对函数进行基准测试 Kelp.Net是一个用c#编写的深度学习库.由于能够将函数链到函数堆栈中,它在 ...

  10. PyTorch中使用深度学习(CNN和LSTM)的自动图像标题

    介绍 深度学习现在是一个非常猖獗的领域 - 有如此多的应用程序日复一日地出现.深入了解深度学习的最佳方法是亲自动手.尽可能多地参与项目,并尝试自己完成.这将帮助您更深入地掌握主题,并帮助您成为更好的深 ...

随机推荐

  1. python之PySimpleGUI(一)元素

    1themesg.theme_previewer()获取所有主题颜色sg.preview_all_look_and_feel_themes()同上theme_name_list = sg.theme_ ...

  2. [Linux]RabbitMQ - 解决Error: unable to connect to node rabbit@localhost: nodedown

    1 问题 环境: CentOS7.8.2003 (x86 / 64bit) 版本: RabbitMQ 3.6.15 (Erlang 19.3) 安装方式: 二进制源码压缩安装 2 解决思路 2.1 思 ...

  3. Nvidia Tensor Core-WMMA API编程入门

    1 WMMA (Warp-level Matrix Multiply Accumulate) API 对于计算能力在7.0及以上的CUDA设备,可以使用CUDA C++ API调用Tensor Cor ...

  4. 【SpringMVC】(一)

    SpringMVC简介 SpringMVC是Spring的一个后续产品,是Spring的一个子项目 基于原生的Servlet,通过了功能强大的DispatcherServlet,对请求和响应进行统一处 ...

  5. 安装Zookeeper和Kafka集群

    安装Zookeeper和Kafka集群 本文介绍如何安装Zookeeper和Kafka集群.为了方便,介绍的是在一台服务器上的安装,实际应该安装在多台服务器上,但步骤是一样的. 安装Zookeeper ...

  6. C#中使用CAS实现无锁算法

    CAS 的基本概念 CAS(Compare-and-Swap)是一种多线程并发编程中常用的原子操作,用于实现多线程间的同步和互斥访问. 它操作通常包含三个参数:一个内存地址(通常是一个共享变量的地址) ...

  7. 【GPT开发】人人都能用ChatGPT4.0做Avatar虚拟人直播

    0 前言 最近朋友圈以及身边很多朋友都在研究GPT开发,做了各种各样的小工具小Demo,AI工具用起来是真的香!在他们的影响下,我也继续捣鼓GPT Demo,希望更多的开发者加入一起多多交流. 上一篇 ...

  8. Python LOG-日志

    LOG https://www.cnblogs.com/yyds/p/6901864.html logging logging模块提供模块级别的函数记录日志 包括四大组件 1. 日志相关概念 日志 日 ...

  9. GPT护理机器人 - 让护士的工作变简单

    引子 书接上文<GPT接入企微应用 - 让工作快乐起来>,我把GPT接入了企微应用,不少同事都开始尝试起来了.有的浅尝辄止,有的刨根问底,五花八门,无所不有.这里摘抄几份: "帮 ...

  10. 聊一聊 dotnet-trace 调查 lock锁竞争

    一:背景 1. 讲故事 最近在分析一个 linux 上的 dump,最后的诱因是大量的lock锁诱发的高频上下文切换,虽然问题告一段落,但我还想知道一点信息,所谓的高频到底有多高频?锁竞争到底是一个怎 ...