美文网首页
将AI拉下神坛(二):重复的学习居然真的有效!来来,先将课文抄写

将AI拉下神坛(二):重复的学习居然真的有效!来来,先将课文抄写

作者: Chriszzzz | 来源:发表于2020-05-24 17:06 被阅读0次

    1 历经30年的阿拉伯数字学习

    爸爸妈妈拿出 0 ~ 910张数字图片……
    爸爸妈妈: 这是0,这是1,这是2……这是9

    爸爸妈妈又紧接着测试我……
    爸爸妈妈: 宝宝这10个数字你都认识了么?

    我感觉那个 0 似乎和大苹果有点像,圆圆的,其他的……¥#@@#¥……都是什么玩意儿!
    宝宝(我): 0、#¥%@。

    爸爸妈妈很有耐心,又教了宝宝一遍。
    再次测试
    这次宝宝认出了2个数字!
    日复一日,年复一年……
    爸爸妈妈无数次地重复教我这10个数字……

    30年后……
    笔者终于可以分辨 0~910 个数字了!😶
    耶!😄

    这个故事再次告诉我们:

    重复的学习是有效的!(呃……即便要30年……)

    所以,当老师再让我们将背不会的课文抄写100遍的时候,不要再反抗了哦!

    2 算法是重复学习的成果

    将AI拉下神坛(一):黑白纸片摆出的神经网络

    上一篇当中👆 有小伙伴就产生了疑问👇

    image.png

    我们提到的算法由 网络权重(连线) 组成👇

    所谓的算法

    然而:
    网络,未说明为什么网络是这样;
    权重,未说明值是怎么来的……
    呃……说起来这算法来的确实有点突兀……

    但同样的问题如果你问机器,ta会告诉你说:算法是重复学习的成果

    先给权重赋一些随机值,然后不停地将训练集(那10张标准数字)输入给算法。算法正确识别正确了,我们告诉算法这是对的,要继续这么做;算法识别错误了,我们告诉算法识别错误了,然后给出正确的答案,让算法后续改正。

    貌似……机器真的可以像人一样……学习?

    3 让机器学习

    我们只需要4步,即可让机器自行学习。

    3.1 定义并加载网络

    比如上篇我们提到的 FullConnect 操作,我们用 pytorch 中的 Linear 操作来模拟它,并将它作为网络的唯一操作。

    nn.Linear(25, 10, bias=False)
    

    25:即输入25个值(5x5个小纸片)
    10:即输出10个值(输入为0~9这10个数字的可能性)
    bias=False:不需要偏置参数,可暂时不关注。

    pytroch 的 Linear官方算法说明
    感兴趣的小伙伴可以参考哦👆👇

    image.png

    3.2 构造并加载数据

    我们选择的训练集、测试集数据如下👇

    训练集 测试集

    上篇一致,这次就不解释咯~

    3.3 设置训练策略

    诸如 学习率损失函数 的选择配置,此篇我们暂不详细说明(以后再讲),目前知道有这个东西就好啦。

    3.4 训练

    来来,大训 300 回合!

    训练 300轮
    即:epoch = 300
    即:让算法学习训练集的每个数字 300次
    即:训练过程要执行算法 10 * 300 = 3000次

    以上4步即可完成一个我们数字识别模型的训练。

    4 训练结果

    4.1 训练集10张图、测试集3张图、训练30000轮

    训练集、测试集的准确率随着训练轮数的变换如下:

    训练到59轮,训练集完全识别 训练到300轮,测试集识别率66.7% 训练到3000轮,测试集识别率66.7% 训练到30000轮,测试集识别率66.7%

    我们发现,训练到第 59轮 时,我们的算法识别率对训练集、测试集已达到是 100%、66.7%,但训练到第 300轮3000轮30000轮时……准确率依然如此,测试集的识别率始终无法提升到100%

    5.2 训练集13张图,训练300轮

    但如果我们将 3张 测试集的数据也交给机器学习呢?即 训练13张图片

    第209轮达到100%的识别率

    我们发现,在进行到第 209轮 的时候,所有 13张 图片已经可以完全被机器识别了。
    我们来看看机器学到的权重数据。

    13张图片训练300轮的权重数据

    再看看笔者上篇给出的权重数据:

    笔者上篇直接赋值的权重数据

    复杂度不在一个层面上……

    5 代码

    那么,这样一个包含 网络定义、训练集、测试集、训练、模型准确率计算 的完整训练代码,一定很复杂吧?不,它不到 150行!而且只依赖 python环境pytorch、numpy 两个 python工具包,嗯……值得亲自跑跑看!👇

    # coding: UTF-8
    
    import torch
    import torch.nn as nn
    import numpy as np
    
    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.full_connect = nn.Linear(25, 10, bias=False)
    
        def forward(self, x):
            out = self.full_connect(x);
            return out;
    
    def load_train_data():
        tdatas_tensor = torch.from_numpy(train_array).float()
        tlabels_tensor = torch.from_numpy(train_label).long()
        return tdatas_tensor, tlabels_tensor
    
    
    def load_test_data():
        tdatas_tensor = torch.from_numpy(test_array).float()
        tlabels_tensor = torch.from_numpy(test_label).long()
        return tdatas_tensor, tlabels_tensor
    
    
    def batch_train_one_epock(model, batch_num, train_data, train_label, loss_func, optimizer):
        model.train()
    
        train_loss = 0.
        train_acc = 0.
        loop_num = int(len(train_data) / batch_num)
    
        for i in range(loop_num):
            # 1 获取 训练数据 & 训练Label
            batch_input = train_data[i * batch_num: ((i + 1) * batch_num)]
            batch_label = train_label[i * batch_num: ((i + 1) * batch_num)]
    
            # 2 执行推理
            batch_out = model(batch_input)
    
            # 3 计算模型损失
            batch_loss = loss_func(batch_out, batch_label)
            train_loss += batch_loss.data
    
            # 4 模型推理准确值累加(用以计算准确率)
            pred = torch.max(batch_out, 1)[1]
            train_correct = (pred == batch_label).sum()
            train_acc += train_correct.data
    
            # 5 适时打印信息
            # print("第", epoch + 1, "轮,已训练", i * batch_num, "项,该批Loss:", np.around(batch_loss.data.numpy(), decimals=6));
    
            # 6 反馈更新权重
            optimizer.zero_grad()
            batch_loss.backward()
            optimizer.step()
    
        train_num = loop_num * batch_num
        return train_loss, train_acc, train_num
    
    
    def batch_test(model, batch_num, test_data, test_label, loss_func, optimizer):
        model.eval()
    
        eval_loss = 0.
        eval_acc = 0.
        loop_num = int(len(test_data) / batch_num)
    
        for i in range(loop_num):
            # 1 获取 训练数据 & 训练Label
            batch_input = test_data[i * batch_num: ((i + 1) * batch_num)]
            batch_label = test_label[i * batch_num: ((i + 1) * batch_num)]
    
            # 2 执行推理
            batch_out = model(batch_input)
    
            # 3 计算模型损失
            batch_loss = loss_func(batch_out, batch_label)
            eval_loss += batch_loss.data
            # print(np.around(eval_loss.data.numpy(), decimals=3));
    
            # 4 模型推理准确值累加(用以计算准确率)
            pred = torch.max(batch_out, 1)[1]
            num_correct = (pred == batch_label).sum()
            eval_acc += num_correct.data
    
        test_num = loop_num * batch_num
        return eval_loss, eval_acc, test_num
    
    # 训练集
    train_array = np.array( \
        [[0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0], \
         [0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0], \
         [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0], \
         [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0], \
         [0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \
         [0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0], \
         [0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0], \
         [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \
         [0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0], \
         [0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0], \
         [1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0], \
         [0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0], \
         [0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0] \
         ])
    
    # 训练集标注
    train_label = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9 \
                               , 5, 5, 5
                           ])
    
    # 测试集
    test_array = np.array( \
        [[1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0], \
         [0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0], \
         [0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0]])
    
    # 测试集标注
    test_label = np.array([5, 5, 5]);
    
    # 1 加载模型
    model = Net();
    
    # 2 加载训练数据
    train_data = torch.from_numpy(train_array).float()
    train_label = torch.from_numpy(train_label).long()
    
    # 3 加载测试数据
    test_data = torch.from_numpy(test_array).float()
    test_label = torch.from_numpy(test_label).long()
    
    # 4 设置训练策略
    optimizer = torch.optim.Adam(model.parameters())
    loss_func = torch.nn.CrossEntropyLoss()
    
    # 5 训练300轮
    for epoch in range(300):
    
        # 单轮训练
        train_loss, train_acc, train_num = batch_train_one_epock(model, 1, train_data, train_label, loss_func, optimizer)
        print('第', epoch + 1, '轮 ', 'Train Loss: {:.6f}, Acc: {:.6f}'.format(train_loss / train_num, train_acc.float() / train_num))
    
        # 每轮测试准确率
        test_loss, test_acc, test_num = batch_test(model, 1, test_data, test_label, loss_func, optimizer)
        print('第', epoch + 1, '轮 ', 'Test Loss: {:.6f}, Acc: {:.6f}'.format(test_loss / test_num, test_acc.float() / test_num))
    
        # print(model.state_dict());
    

    6 结束 or 开始?

    我们已经可以训练模型了哎!那么AI灭神计划是不是已经到尾声了呢?不,我们没有解释的问题还很多很多!将AI拉下神坛,才刚刚开始!

    相关文章

      网友评论

          本文标题:将AI拉下神坛(二):重复的学习居然真的有效!来来,先将课文抄写

          本文链接:https://www.haomeiwen.com/subject/grptahtx.html