ng灵魂画手镇楼(感谢炎蓉分享)
1 问题背景
210607周一,刚跟炎蓉交流了下,她已经自己用numpy手撸写了一个神经网络,尝试求解a+b+c(1<=a,b,c<=10)结果奇偶性问题,也就是二分类。
跑出来大概50%,跟蒙的一样,这个问题其实神经网络是做不好的,大家可以思考一下为什么,晚点再解释。
2 模型代码
但是求和后,判断值区间这类问题是能做好的,比如和是否大于15,这个我随便撸了个nn能做到99%。
或者更难一点,判断是否在10~20之间,这段代码可以做到 83%:
from pyxllib.xl import *
import torch
from torch import nn, optim
class ParityModel(nn.Module):
def __init__(self):
super().__init__()
self.classifier = nn.Sequential(
nn.Linear(in_features=3, out_features=2),
nn.Sigmoid(),
nn.Linear(in_features=2, out_features=2),
nn.Sigmoid(),
nn.Linear(in_features=2, out_features=1),
nn.Sigmoid(),
)
def forward(self, x):
return self.classifier(x)
def train(epoch=10):
n = 5000 # 数据量
data = np.random.randint(1, 10, [n, 3]) # 数据
model = ParityModel() # 模型
criteon = nn.BCELoss() # 二分类交叉熵损失
optimizer = optim.Adam(model.parameters(), lr=0.01) # 学习器
for e in range(epoch):
acc = 0
for x in data:
y = 10 < sum(x) < 20
logits = model(torch.Tensor(x))
y_hat = 0 if logits < 0.5 else 1
acc += (y == y_hat) # 这里为了代码简洁方便,直接在训练中计算精度
loss = criteon(logits, torch.Tensor([y]))
# 清空之前梯度;进行该轮梯度反传;梯度更新
optimizer.zero_grad()
loss.backward()
optimizer.step()
get_xllog().info(f'第{e}轮精度:{acc / n:.2%}')
if __name__ == '__main__':
train()
如果群里有python、numpy等基础比较薄弱的,建议可以提前接触、安装pytorch,用框架来实现一个nn,有兴趣的再深入自己把细节实现一遍。
安装pytorch: https://www.yuque.com/xlpr/pyxllib/install-pytorch
3 解释为什么做不好分类问题
二维情况下,决策函数是这样的
这里求和后,相当于数据特征只有一维
但严谨的说,这里是三个数字相加,真要画出来,其实是一个立体空间中的多个气泡
二维情况更复杂的,比如玫瑰图,决策函数是这样的
如果设计的模型太简单,比如是线性模型,就很可能变成这样,效果不好
奇偶数问题类比到二维的玫瑰图情况,就好比这里叶子数不只上面8片了,而是沿中心每旋转1个角度的直线,都在不断的0、1类别间切换,这样问题就太难了,远超玫瑰图。
炎蓉说这个更好理解,非要展现我灵魂画手的实力