美文网首页AI
好还是坏:人工智能二分类问题

好还是坏:人工智能二分类问题

作者: 我是任玉琢 | 来源:发表于2020-01-10 23:49 被阅读0次

    上一篇文章我们介绍了深度学习的 Hello World,代码写起来相比其他语言的 Hello World 有点多,且其背后的很多原理你可能还没有完全弄懂,但从宏观上来看,整体的思想是很好理解的。接下包括本篇在内的三篇文章,我们来用深度学习解决三个实际问题,也是非常经典的三个问题,分别是:

    1. 二分类问题(电影评论的好坏偏向性判断)
    2. 多分类问题(将新闻按照主题分类)
    3. 回归问题(根据房地产数据估算房地产价格)

    我们解决这三个问题用到的训练模型为:

    image

    今天是第一篇,我们关注他们其中比较简单的二分类问题,代码在最后。

    实际背景是 IMDB(互联网电影资料库,你可以理解为国外的豆瓣)有大量的关于电影的评论,但是由于数据量的问题,很难去人工手动判断一条评定是对电影的夸奖还是批评,这需要借助人工智能的帮助,根据用户评论的内容去判断用户的评论是积极的还是消极的(为使问题简化,我们取的数据是倾向性很明显的数据),数据集来自 IMDB,Numpy 数据格式:每一个单词对应一个索引数字,这样每一条评论就可以对应一个索引数字的序列,组成一维数组,也是一个一维向量,这样的多个一维向量组成二维数组,就对应对条评论。

    背景介绍完了,整个过程分为如下几步,同时思考几个问题:

    1. 由于每一条评论的长度不一样,每个一维向量长度不一致,这样的数据不好处理,因此需要将数据进行预处理,这里采用 one-hot 方法(one-hot 是一个常用的方法,后面会有专门的文章介绍),简单点来 one-hot 做的事情就是:假如一个数组是[1, 3, 5, 3],需要处理成 10 维数据就是[0, 1, 0, 1, 0, 1, 0, 0, 0, 0],对应数数组索引处的数字是 1,其他数字是 0,本实际问题中,评论处理后的数据是一个向量(25000,10000)。

    2. 针对这种 one-hot 处理过的数据(0-1 类型的训练数据集),用带有 relu 激活的以 Dense 为中间层的网络进行深度学习表现很好(为什么这个表现的好,为什么 Dense 第一个参数即隐藏层的个数是 16 都是很复杂的问题,后续深入研究,这里只下结论将数据投影到 16 维空间中且是两个中间层的网络可以满足要求),随后一层是将输出格式化为 0-1 概率判断的结果。

    3. 针对损失函数,因为最后输出的结果是这条评论倾向性的概率值,所以选择交叉熵作为损失函数(binary_crossentropy,二元交叉熵对于这种情况的判断训练效果表现较好)。

    4. 最后,因为我们的模型是要做拟合,是一个有反馈的网络,从上图中可以看出来,因此这里选择部分数据用于提供反馈数据(反馈的意思是说先训练出一个模型,然后用另外一些数据进行测试,计算偏差,将偏差结果反馈给网络,网络进行参数调整,再一轮训练)且提供反馈的数据不应该用于训练,因此从训练集中取出一部分数据用于提供反馈。这里选择训练数据集中前一万条数据用于提供反馈数据,后一万五千条数据用于训练。

    5. 最后一步是启动 fit 训练模型,fit 中 validation_data 参数是用于提供验证数据的。最后我们从训练的过程中,提取出每一轮循环得到的数据画图直观看看训练损失、验证损失、训练精度和验证精度的具体变化:

    image image

    我们从图中可以看出,随着训练网络迭代的次数越来越多,训练精度越来越大,训练损失越来越小,这是我们期望的;但是同时差不多在第四次迭代后,验证损失越来越大,验证精度越来越小,这就跟期望不相符了,这不科学,那这是为什么?

    这是因为由于迭代次数过多,出现了过拟合。

    随着训练数据迭代次数过多,训练出的模型为了更好的拟合训练集的数据,导致一些参数设置的会过于绝对,出现了过拟合,这是我们在训练网络中经常会遇到的问题,因此我们认为在迭代四次是比较好的,类似于数学概念上的极值,更多更少的迭代次数都不够好,因此我们将 fit 中的迭代次数改为 4,再次训练网络。

    最后在另外的两万五千条测试集上进行验证,效果还可以,基本满足要求,问题得到解答。更多的细节已经写在了下面代码相关注释内容部分了,有兴趣请自行阅读。

    #!/usr/bin/env python3
    ​
    import matplotlib.pyplot as plt
    import numpy as np
    from keras import layers
    from keras import models
    from keras.datasets import imdb
    ​
    ​
    # IMDB 数据集,分类一个评论是正面的还是反面的
    def comment():
        # num_words = 10000 代表取前一万高频词,加入低频词数据量会过大且作用较小,暂不考虑
        # 25000 条训练数据,25000 条测试数据
        (train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
    ​
        # 训练集被处理成整数数列,每条数据表示一条评论中单词出现的次数(如 good 出现次数是 5 次)
        # [1, 14, 22, ... 19, 178, 32]
        # print(train_data[0])
    ​
        # 用 0 代表负面评论,1 代表正面评论
        # print(train_labels[0])
        # print(max([max(sequence) for sequence in train_data]))
    ​
        # 单词与索引对照表
        # word_index = imdb.get_word_index()
        # reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
        # decoded_review = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])
    ​
        # 将评论翻译成可读语言
        # this film was just brilliant casting location scenery story direction everyone's really suited the part they
        # print(decoded_review)
    ​
        # one-hot 方法预处理数据为向量
        x_train = vectorize_sequences(train_data)
        x_test = vectorize_sequences(test_data)
        y_train = np.asarray(train_labels).astype('float32')
        y_test = np.asarray(test_labels).astype('float32')
    ​
        # 构造网络
        model = models.Sequential()
        model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
        model.add(layers.Dense(16, activation='relu'))
        model.add(layers.Dense(1, activation='sigmoid'))
        # 创建编译模型
        model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
        model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
        # model.compile(optimizer=optimizers.RMSprop(lr=0.001), loss='binary_crossentropy', metrics=['accuracy'])
        # model.compile(optimizer=optimizers.RMSprop(lr=0.001), loss=losses.binary_crossentropy,
        #               metrics=[metrics.binary_accuracy])
    ​
        # 由于这里有反馈,因此需要有一定的数据进行数据进行验证,这里取前一万个数据进行验证操作
        x_val = x_train[:10000]
        partial_x_train = x_train[10000:]
        y_val = y_train[:10000]
        partial_y_train = y_train[10000:]
    ​
        # validation_data 用于传递验证数据
        history = model.fit(partial_x_train, partial_y_train, epochs=4, batch_size=512, validation_data=(x_val, y_val))
    ​
        # History 是训练过程中的所有数据
        history_dict = history.history
        print(history_dict.keys())
        history_dict = history.history
        loss_values = history_dict['loss']
        val_loss_values = history_dict['val_loss']
        epochs = range(1, len(loss_values) + 1)
    ​
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.plot(epochs, loss_values, 'bo', label='训练损失')
        plt.plot(epochs, val_loss_values, 'b', label='验证损失')
        plt.title('训练和验证损失')
        plt.xlabel('迭代')
        plt.ylabel('损失')
        plt.legend()
        plt.show()
    ​
        plt.clf()
        acc = history_dict['acc']
        val_acc = history_dict['val_acc']
        plt.plot(epochs, acc, 'bo', label='训练精度')
        plt.plot(epochs, val_acc, 'b', label='验证精度')
        plt.title('训练和验证精度')
        plt.xlabel('迭代')
        plt.ylabel('精度')
        plt.legend()
        plt.show()
    ​
        results = model.evaluate(x_test, y_test)
        # [0.3329389461231232, 0.8639600276947021]
        print(results)
        # [[0.1754326], [0.9990357], [0.855113]...]
        print(model.predict(x_test))
    ​
    ​
    def vectorize_sequences(sequences, dimension=10000):
        results = np.zeros((len(sequences), dimension))
        for i, sequence in enumerate(sequences):
            results[i, sequence] = 1.
        return results
    ​
    ​
    if __name__ == "__main__":
        comment()
    

    相关文章

      网友评论

        本文标题:好还是坏:人工智能二分类问题

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