详解keras代码(1)——二分类问题

下载IMDB数据集

IMDB是内置于keras库的电影数据库,里面包含了50 000条严重两极分化的评论。已经过预处理:评论的单词序列已经被转化为整数序列,即每个整数代表字典中的某个单词。25 000条用于训练,25 000条用于测试。下面对数据集通过代码进行分析:

  • 导入keras数据包
from keras.datasets import imdb
  • 通过imdb.load_data方法导入数据,其中num_words=10000表示仅保留数据中前10000个常见出现的单词,低频出现的单词被舍弃。方法返回类型为(train_data, train_labels), (test_data, test_labels),其中train_data是训练用的评论数据,train_labels是对应训练用评论的分类(0表示负面,1表示正面),test_data是测试的评论数据,test_labels是测试的评论数据的分类。
(train_data, train_labels), (test_data,
                             test_labels) = imdb.load_data(num_words=10000)

我们用print函数将train_data和train_labels打印出来。结果如下:

[list([1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65, 458, 4468, 66, 3941, 4, 173, 36, 256, 5, 25, 100, 43, 838, 112, 50, 670, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 4536, 1111, 17, 546, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2025, 19, 14, 22, 4, 1920, 4613, 469, 4, 22, 71, 87, 12, 16, 43, 530, 38, 76, 15, 13, 1247, 4, 22, 17, 515, 17, 12, 16, 626, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2223, 5244, 16, 480, 66, 3785, 33, 4, 130, 12, 16, 38, 619, 5, 25, 124, 51, 36, 135, 48, 25, 1415, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 5952, 15, 256, 4, 2, 7, 3766, 5, 723, 36, 71, 43, 530, 476, 26, 400, 317, 46, 7, 4, 2, 1029, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2071, 56, 26, 141, 6, 194, 7486, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 5535, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 1334, 88, 12, 16, 283, 5, 16, 4472, 113, 103, 32, 15, 16, 5345, 19, 178, 32])...
[1 0 0 ... 0 1 0]

因为数据已经通过预处理,我们可以看到,打印出来的数据是一组整数序列。

下面我们将数字映射到字符,看看每个整数分别代表什么单词。

word_index = imdb.get_word_index()
reversed_word_index = dict([value, key] for (key, value) in word_index.items())
decoded_review = ' '.join(
    [reversed_word_index.get(i - 3, '?') for i in train_data[0]])

imdb.get_word_index方法返回一个从单词映射到整数索引的字典。将word_index打印出来后的数据:

{...., 'ev': 88575, 'chicatillo': 88576, 'transacting': 88577, "'la": 27630, 'percent': 8925, 'oprah': 7996, 'sics': 88578, 'illinois': 11925, 'dogtown': 40828, 'roars': 20595, 'branch': 9456, 'kerouac': 52002, 'wheelers': 88579, 'sica': 20596, 'lance': 6435, "pipe's": 88580, 'discretionary': 64179, 'contends': 40829, 'copywrite': 88581, 'geysers': 52003, 'artbox': 88582, 'cronyn': 52004, 'hardboiled': 52005, "voorhees'": 88583, '35mm': 16815, "'l'": 88584, 'paget': 18509, 'expands': 20597,...}

reversed_word_index 是一个字典,将word_index当中{字符:数字}的数据格式,转化为{数字:字符}的数据格式。之所以做这样的转化,是因为,我们读取的数据是处理好的(整数的形式),所以,需要以数字作为检索项,来检索字符。

reversed_word_index .get(i - 3, '?'),i-3是键值,‘?’是键值不存在的时候返回的值,也就是默认标点符号是问号(?)。这里取了train_data[0],即训练数据里面的第一组数据。’ ‘.join([char])是在字符串后面加空格并将char插入到字符串后面。我们把decoded_review打印出来:

? this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert ? is an amazing actor and now the same being director ? father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for ? and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also ? to the two little boy's that played the ? of norman and paul they were just brilliant children are often left out of the ? list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all

这样我们就看到了从整数反向转化成评论的效果了。当然,读者需要注意的是,做反向的转化,对进行二分类而言并没有意义,我只是想通过这个过程告诉大家,整数和字符之间是一一对应的。神经网络只能对数进行操作,而无法对字符进行运算,所以我们需要将字符处理成数字的形式。当然,字符编码成数字的方法有很多种,后面的章节里我们还会有介绍。

将整数序列编码为二进制矩阵

上面一节,我们把数据下载并读取出来,现在我们要对数据进行处理。处理的目的是:将整数序列编码为二进制矩阵。

  • 实现编码函数
import numpy as np


def vectorize_sequences(sequences, dimension=10000):
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.
    return results

numpy.zeros(shape,dtype=float,order = 'C'),其中shape是矩阵形状,即矩阵是几行几列,dtype默认值为float,order是数据存储方式,‘C’表示以行的形式存储,’F‘是以列的形式存储。所以np.zeros((len(sequences), dimension))方法的意思是,以sequences的长度为矩阵行数,以10000为矩阵列数,生成一个0矩阵。

enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标。举例说明

seasons = ['Spring', 'Summer', 'Fall', 'Winter']
list(enumerate(seasons))

输出的结果为:

[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]

那么我们举例来说明

    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.

这两行代码的含义是:

假如sequences = [1,3,2,3],results是4行4列的0矩阵。那么enumerate之后的数据为[(0,1), (1,3), (2,2), (3,3)],那么:

results[0,1] = 1.

results[1,3] = 1.

results[2,2] = 1.

resluts[3,3] = 1.

那么矩阵results可表示为

0 1 0 0

0 0 0 1

0 0 1 0

0 0 0 1

也就是说矩阵当中的每一行都能够以二进制的形式唯一的表示sequences 当中的一个数据,并且,每一行只有一位被置位,我们把这种方法叫做ONE-HOT编码

因为我们在上面一节中获取数据的时候,只获取的前10000个常用词,所以矩阵的列数不会超过10000,所以我们定义的vectorize_sequences方法,dimension=10000。

  • 对train_data和test_data进行向量化编码
x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)
  • 对train_labels和test_labels进行向量化
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')

asarray方法可以将结构数据转化为ndarray(矩阵向量)。举例说明:

data1=[[1,1,1],[1,1,1],[1,1,1]] 
arr3=np.asarray(data1) 

arr3的结果为:

arr3: 
[[1 1 1] 
 [1 1 1] 
 [1 1 1]]

建立keras二分类模型

通过上面的处理,我们已经把数据处理成矩阵向量的形式,接下来,要进入我们核心的内容了:利用keras建立二分类模型:

from keras import models
from keras import layers

model = models.Sequential() #采用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'))

keras有两种建立模型的方式,一种是采用keras内置的Sequential模型的方式,另外一种是采用函数式API的方式,两种模式各自有其优缺点,从入门和易用性的角度上讲,Sequential模型使用更简单;但是函数式API的方式,使用更灵活,可以根据自身需求实现不同的网络模型,达到网络最优化的目的。一般而言,如果不是自己研究一种网络模型,Sequential模型的方式足够满足日常需求。这里我们采用的就是Sequential模型的方式。

model.add方法的作用是增加一层,layers.Dense方法的作用是增加全连接层,所谓全连接的概念指的是,前一层的每一个输出,都是该层任意神经元的输入。如下图所示

dense.PNG
layers.Dense(16, activation='relu', input_shape=(10000, ))

其中,16表示神经单元个数,relu是激活函数,input_shape是输入矩阵的形状。神经单元个数,也就是该层网络的输出个数。relu是激活函数,keras提供了很多的内置激活函数,详情可参考keras官方手册了解。也就是说,通过本行代码,增加一层单元个数为16,输入为10000,激活函数为relu的全连接层。

后面两层的增加类似,只不过,除了第一层外,其他网络层不涉及输入形状的问题,因为其输入数据的个数由前一层决定。

编译网络模型

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])

编译网络模型方法中,指定了模型的优化函数、损失函数以及评估函数。简单的讲,损失函数用来评估网络计算值和实际值之间的误差,优化函数通过方向传播误差的方法优化网络的权重,评估函数同损失函数类似,只不过它是用来评估网络性能的方法。一般而言,二分类问题我们选用binary_crossentropy作为损失函数。

训练网络

model.fit(x_train, y_train, epochs=20, batch_size=512)

在训练网络的方法中,epochs表示训练的次数,batch_size表示小批量随机梯度下降方法当中的批量值,也就是每512组数据计算一次平均的随机梯度下降值。

到此为止,关于二分类问题的基础代码讲解完毕,下面我们通过执行model.predict(x_test)函数来看一下,测试数据的输出结果:

[[0.01034644]
 [0.9999963 ]
 [0.9942436 ]
 ...
 [0.03826523]
 [0.00732365]
 [0.97382474]]

我们可以发现,网络的输出结果实际上概率值,比如第一个值0.01034644,我们可以认为这条评论大概率是负面的,第二个值0.9999963,则大概率的是正面的评论。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350