From 9a8434df615fe95ce9ab5058d0f31ba295d3d4bb Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 5 Jun 2025 13:17:01 +0800 Subject: [PATCH] Update demo and readme. --- binary/loss.py | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ binary/readme.md | 34 ++++++++++++++++++++++--- 2 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 binary/loss.py diff --git a/binary/loss.py b/binary/loss.py new file mode 100644 index 0000000..8e403a0 --- /dev/null +++ b/binary/loss.py @@ -0,0 +1,65 @@ +import torch + +data_size = 20 + + +torch.manual_seed(1234) +x_data = torch.abs(torch.randn((data_size))) +y_data = 10 * x_data + + +class MUL(torch.autograd.Function): + @staticmethod + def forward(ctx, input, weight): + ctx.save_for_backward(input, weight) + return input * weight + + @staticmethod + def backward(ctx, grad_output): + input, weight = ctx.saved_tensors + grad_weight = input * grad_output + grad_input = weight * grad_output + print(f"grad_output:{grad_output.item():.4f}") + return grad_input, grad_weight + + +class LinearModel(torch.nn.Module): + def __init__(self): + super().__init__() + self.weight = torch.nn.Parameter(torch.tensor([[1.0]]), requires_grad=True) + + def forward(self, x): + return MUL.apply(x, self.weight) + return x * self.weight + + +model = LinearModel() +criterion = torch.nn.MSELoss() +optimizer = torch.optim.SGD(model.parameters(), lr=1.0) +loss_history = [] + + +for step in range(data_size): + y_pred = model(x_data[step]) + + # loss = criterion(y_pred, y_data[step]) + # loss = y_data[step] / y_pred - 1.0 + # loss = torch.abs(y_data[step] - y_pred) + # loss = y_data[step] - y_pred + loss = (y_data[step] - y_pred) * (y_data[step] - y_pred) + + loss_history.append(loss.item()) + + optimizer.zero_grad() + loss.backward() + + if (step + 1) % 1 == 0: + w = model.weight.item() + print( + f"Step {step+1}: w={w:.4f} loss={loss.item():.6f} input:{x_data[step]:.4f} output:{y_pred.item():.4f} label:{y_data[step].item():.4f} w_grad:{model.weight.grad.item():.4f}" + ) + + optimizer.step() # w = w - lr * ∇w[5](@ref) + +test_x = torch.tensor([[5.0]]) +print(f"\n预测结果: x=5 → y={model(test_x).item():.2f}") diff --git a/binary/readme.md b/binary/readme.md index bca99fc..e6e4432 100644 --- a/binary/readme.md +++ b/binary/readme.md @@ -1,13 +1,39 @@ +## 定义 + +### 梯度 + 1. 预测变化对整体损失 L 的影响程度, 参数θ在当前点的变化对损失值的影响方向和幅度 + 2. grad物理含义:loss L = 0 的时候,需要的变化量 + 3. w = w - grad * lr 若梯度为正,权重应该减小 + 4. w_grad = output_grad * input, input越大,grad越大,w调整的量越大 + 1. input越大->对weight的放大倍数越大->才能达到loss=0的调整量 + 2. 所以,weight的调整比例应该越大,才能弥补小input的loss=0 + 5. 梯度的大小反应了影响损失的“快慢” + 1. 梯度大​​ → 损失曲面陡峭 → 微小变化导致损失剧烈波动 + 2. 梯度大,微小变化就可以使得loss变化一个单位 + 2. 梯度大,和loss的关系越相关 ## 问题 -1. 在一串的binary lut网络中 +* 在一串的binary lut网络中 1. 如果每个卷积的channel相互之间没有关系 2. 中间插入一层,交换各个channel之间的数据,生成新的相同数量的channel 3. 方法2的效果很差 - 1. 好像是破坏了训练,可能是训练的方法不对 + 1. 好像是破坏了训练,可能是训练的方法不对,梯度下降不适合这种模型 2. 最终分类是10,10个输出之间有关系就会很差? -2. unfold输出的维度不对 +* LUT层梯度计算的问题 + 1. 发现LUT的反向计算grad_weight没有考虑weight本来的正负符号,grad表示的是>0的置信度 + 1. 考虑梯度符号之后,由于整个选择的梯度是一个,没有机会变换到别的 + 2. weight_grad:后面一级计算的grad_input,对于当前weight的grad是一样的,没有机会变换到别的 + 3. 当前的选择不可信后的grad会导致直接0/1整体取反,而不会改变分布 + 2. 输出级别用于criterion的LUT的梯度计算和基于Binary的输出1概率的梯度的计算方式不一样 + 1. LUT的是输出1的概率,不能直接和criterion的梯度进行下降 + 3. grad input的目标是,要不要更换别的index + 1. 梯度的大小表示更换别的index的程度 + 2. 梯度正负无所谓,需要随机? + +* unfold输出的维度不对 1. LUT不是对卷积核进行计算,更容易收敛,但是精度没有更高 - 2. LUT不是对卷积核进行计算,不容易收敛,精度差不多 \ No newline at end of file + 2. LUT不是对卷积核进行计算,不容易收敛,精度差不多 +* 好像只有AdamW优化器可以优化参数,明显收敛 +* LUT的输出进行二值化对精度有影响,大概94->81 \ No newline at end of file