building micrograd
从零搭建 micrograd:神经元、权重、bias、激活函数(ReLU)与反向传播的直观解释,配可交互函数图像。
micrograd 是 andrej karpathy 所开源的一个Github学习项目,项目的初衷是让读者可以更好的学习back propagation.andrej karpathy 本人也录制过一段 Youtube 视频来进行讲解 (url:https://youtu.be/VMj-3S1tku0?si=6qfc4FQkdIn_WmnL)。那么为了理解 micrograd. 我们需要先从最基础的神经网络开始讲起.
神经元就是一个 $f(x_1,x_2,x_3,...)$ 一个函数 输入了一堆数字
然后每个input 都会跟着一个weight 权重 就是 最主要是一个常数
高就代表这个输入很重要
低就代表没那么重要
当然也要看正负 可以看出是负影响 还是 正影响
基本结构:
$f(x_1,x_2,x_3,...) = Activation_function(w_1 \times x_1 + w_2\times x_2 + ... + bias)$
这里可以看到在刚刚输入×权重后 还要加一个bias
而bias的作用是什么 为什么 + 一个bias呢
bias 从几何意义上来理解
y = mx + c
c 也就是代表着这条线可以在整个空间里面平移
机器学习 最主要是学习数据关系
也就是 输入 和 输出的对应关系
如果不允许平移 那么 如果真实数据里面是 y= 2x + 100
在 输入永远 = 0 的时候
如果没有bias 永远拟合不了线性的真实数据
而我们最终的目的也就是 确保 x轴上 每一个x 只要调整 w 和 bias 可以触及 任意的y
因为我们要拟合 世界上 任意的对应关系 任何的数据形态
但是单单只有一条 直线 是不够的
所以我们要引入 非线性
也就是 Activation function(激活函数)
我们先介绍第一种 Activation function
ReLU:
其实也就是创造一个折点 在几何意义上
那我们现在画一个最简单的神经网络 长这样(2个输入 3个隐藏神经元 1个输出):
每条连线就是一个权重w 每个神经元做的是 加权求和 再过一个Activation function
为什么一定要非线性?
如果每个神经元都只是线性加权求和 那不管叠多少层 组合起来还是一条直线:
拖动左边m b的滑条 怎么调都只是一条直线 永远拟合不了sin(x)
但是只要加上ReLU这种非线性 把几个ReLU加起来 曲线就开始拐弯了:
拖动c₁到c₄的滑条 可以看到分段线性的曲线可以一点点逼近sin(x)
神经元的数量越多 拐弯的点越多 就能逼近越复杂的函数
这就是为什么神经网络一定要加Activation function
简单介绍完基本的神经网络结构就可以来说一下 micrograd 了
micrograd 是一个 autograd engine 就是自动梯度的机器
- 也就是Implement backpropagation 向后传播
backpropagation 向后传播解释
整个Neural Network的目的例如说 我们想要这个神经网络去拟合一种数据分布对吧
首先整个的流程就是
Feed input -> Process -> Output
然后看看结果如何
那如何衡量结果 我们就需要loss function
有了 loss function 之后 知道做的好不好了
我们就需要去改良 (也就是去调整权重和bias)
举出一个简单的例子
Mean Squared Error - MSE
$$
MSE = \frac{1}{n} \sum_{i=1}^{n}(y_i-\hat{y}_i)^2
$$
有了Loss function 之后 我们的步骤就到了如何改进
那么改进 需要 gradient (梯度)
梯度的意思就是在 那一变量的对整个函数的影响 就是 如果增加一个无穷小量 dx 如何影响整个函数
让L 作为 Loss function
dL/dL 是1
L = tanh(wx + c)
dL/dw = dL/d(wx+c) d(wx +c)/dw
只要用微积分的法则 例如多变量微积分是将其他的变量当成常熟,嵌套函数就是chain rule 就可以算出 某个具体变量的梯度
知道梯度是 x 增加一个dx y的上涨
那么为了最小化L 可以学习率乘一个负导数
因为x 如果+dx是增加 L 那么 -dx 就是减少L 这样可以让Loss function 变小
而学习率就是变小多少 防止直接跳过了minimum