ng灵魂画手镇楼(感谢炎蓉分享)
image.png

1 问题背景

210607周一,刚跟炎蓉交流了下,她已经自己用numpy手撸写了一个神经网络,尝试求解a+b+c(1<=a,b,c<=10)结果奇偶性问题,也就是二分类。

跑出来大概50%,跟蒙的一样,这个问题其实神经网络是做不好的,大家可以思考一下为什么,晚点再解释。

2 模型代码

但是求和后,判断值区间这类问题是能做好的,比如和是否大于15,这个我随便撸了个nn能做到99%。
或者更难一点,判断是否在10~20之间,这段代码可以做到 83%:

  1. from pyxllib.xl import *
  2. import torch
  3. from torch import nn, optim
  4. class ParityModel(nn.Module):
  5. def __init__(self):
  6. super().__init__()
  7. self.classifier = nn.Sequential(
  8. nn.Linear(in_features=3, out_features=2),
  9. nn.Sigmoid(),
  10. nn.Linear(in_features=2, out_features=2),
  11. nn.Sigmoid(),
  12. nn.Linear(in_features=2, out_features=1),
  13. nn.Sigmoid(),
  14. )
  15. def forward(self, x):
  16. return self.classifier(x)
  17. def train(epoch=10):
  18. n = 5000 # 数据量
  19. data = np.random.randint(1, 10, [n, 3]) # 数据
  20. model = ParityModel() # 模型
  21. criteon = nn.BCELoss() # 二分类交叉熵损失
  22. optimizer = optim.Adam(model.parameters(), lr=0.01) # 学习器
  23. for e in range(epoch):
  24. acc = 0
  25. for x in data:
  26. y = 10 < sum(x) < 20
  27. logits = model(torch.Tensor(x))
  28. y_hat = 0 if logits < 0.5 else 1
  29. acc += (y == y_hat) # 这里为了代码简洁方便,直接在训练中计算精度
  30. loss = criteon(logits, torch.Tensor([y]))
  31. # 清空之前梯度;进行该轮梯度反传;梯度更新
  32. optimizer.zero_grad()
  33. loss.backward()
  34. optimizer.step()
  35. get_xllog().info(f'第{e}轮精度:{acc / n:.2%}')
  36. if __name__ == '__main__':
  37. train()

如果群里有python、numpy等基础比较薄弱的,建议可以提前接触、安装pytorch,用框架来实现一个nn,有兴趣的再深入自己把细节实现一遍。
安装pytorch: https://www.yuque.com/xlpr/pyxllib/install-pytorch

3 解释为什么做不好分类问题

image.png

二维情况下,决策函数是这样的
image.png

这里求和后,相当于数据特征只有一维
但严谨的说,这里是三个数字相加,真要画出来,其实是一个立体空间中的多个气泡

二维情况更复杂的,比如玫瑰图,决策函数是这样的
image.png
如果设计的模型太简单,比如是线性模型,就很可能变成这样,效果不好
image.png

奇偶数问题类比到二维的玫瑰图情况,就好比这里叶子数不只上面8片了,而是沿中心每旋转1个角度的直线,都在不断的0、1类别间切换,这样问题就太难了,远超玫瑰图。

炎蓉说这个更好理解,非要展现我灵魂画手的实力
image.png