2019-05-12 21:31:05 qq_35164554 阅读数 259
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    39692 人正在学习 去看看 唐宇迪

本文中我希望用IMDB数据集和神经网络对数据集中的影评内容进行“正面影评”和“负面影评”的二分类。

IMDB

IMDB数据集是Tensorflow中带有的数据集,其中包含来自互联网电影库的50000条影评文本,首先来下载该数据集并且查看一下:

加载数据(如果缓存中没有回自动下载该数据):

import tensorflow as tf
from tensorflow import keras
import numpy as np

imdb = keras.datasets.imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)

查看数据:

print("Trraining entries:{},labels:{}".format(len(train_data),len(train_labels)))

输出中可以看到我们训练集的样本量为25000

查看数据中的其中一个样本是什么:

print(train_data[0])

可以看书虽然是影评,在我们的数据集中译英转换为了数值类型而不是字符型,其中每一个数字都代表一个词语,后续会用其他的方法将数值型转换为字符型。

我们知道在神经网络的输入中必须要有相同的长度,所以我们先查看几条数据的长度是不是相同的:

print(len(train_data[0]),len(train_data[10]),len(train_data[100]))

由这个输出结果可以看出,每条影评的长度是不相同的所以我们要想办法处理这个问题,在这里我的办法设置一个最长值得限制,并将短的数据用零来填充:

train_data = keras.preprocessing.sequence.pad_sequences(train_data,
                                                        value=0,
                                                        padding='post',
                                                        maxlen=256)

test_data = keras.preprocessing.sequence.pad_sequences(test_data,
                                                       value=0,
                                                       padding='post',
                                                       maxlen=256)
print(len(train_data[0]),len(train_data[10]),len(train_data[100]))

输出结果如下,此时我们可以看出每一条数据的长度都是相同的:

keras.preprocessing.sequence.pad_sequences(sequences, maxlen=None, dtype=’int32’, padding=’pre’, truncating=’pre’, value=0.) 

函数说明: 
将长为nb_samples的序列(标量序列)转化为形如(nb_samples,nb_timesteps)2D numpy array。如果提供了参数maxlen,nb_timesteps=maxlen,否则其值为最长序列的长度。其他短于该长度的序列都会在后部填充0以达到该长度。长于nb_timesteps的序列将会被截断,以使其匹配目标长度。padding和截断发生的位置分别取决于padding和truncating. 
参数:

sequences:浮点数或整数构成的两层嵌套列表

maxlen:None或整数,为序列的最大长度。大于此长度的序列将被截短,小于此长度的序列将在后部填0.

dtype:返回的numpy array的数据类型

padding:‘pre’或‘post’,确定当需要补0时,在序列的起始还是结尾补

truncating:‘pre’或‘post’,确定当需要截断序列时,从起始还是结尾截断

value:浮点数,此值将在填充时代替默认的填充值0


构建模型

神经网络通过层数的堆叠创建成,下面先说一下每一层的作用。

示例中,输入数据由字词-索引数组构成,要预测的标签是0或1(正面影评和负面影评)

第一层:Embedding层,该层会在整数编码的词汇表中查找每个字词-索引的嵌入向量,模型在接受训练时会学习这些向量,这些向量会向输出数组中添加一个维度,添加后的维度是(batch,sequence,embedding);

第二层:一个 GlobalAveragePooling1D 层通过对序列维度求平均值,针对每个样本返回一个长度固定的输出向量。这样,模型便能够以尽可能简单的方式处理各种长度的输入。

第三层:该长度固定的输出向量会传入一个全连接 (Dense) 层(包含 16 个隐藏单元)。

第四层:最后一层与单个输出节点密集连接。应用 sigmoid 激活函数后,结果是介于 0 到 1 之间的浮点值,表示概率或置信水平。

vocab_size = 10000

model = keras.Sequential()
model.add(keras.layers.Embedding(vocab_size, 16))
model.add(keras.layers.GlobalAveragePooling1D())
model.add(keras.layers.Dense(16, activation=tf.nn.relu))
model.add(keras.layers.Dense(1, activation=tf.nn.sigmoid))

model.summary()

输出如下:

损失函数和优化器

构建完了神经网络下面我们来定义一个损失函数和优化器

model.compile(optimizer=tf.train.AdamOptimizer(),
              loss='binary_crossentropy',
              metrics=['accuracy'])

创建验证集

创建数据集的目的是为了检测模型处理未见过的数据时的准确率,我们取总数据的20%也就是10000条数据来创建验证集。

x_val = train_data[:10000]
partial_x_train = train_data[10000:]

y_val = train_labels[:10000]
partial_y_train = train_labels[10000:]

训练模型并且评估模型

用有 512 个样本的小批次训练模型 40 个周期。这将对 x_train 和 y_train 张量中的所有样本进行 40 次迭代。在训练期间,监控模型在验证集的 10000 个样本上的损失和准确率,最后我们使用evaluate来查看模型的误差和准确率:

history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=40,
                    batch_size=512,
                    validation_data=(x_val, y_val),
                    verbose=1)
results = model.evaluate(test_data, test_labels)

print(results)

最后的输出结果如下:

由此可见我们的模型准确率为0.87,并不是很完美,如果采用更好的方法可能会对准确率有更大的提高。

 

2018-12-10 17:37:08 xiaosongshine 阅读数 337
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    39692 人正在学习 去看看 唐宇迪

[Keras深度学习浅尝]实战四· Embedding实现 IMDB数据集影评文本分类

此实战来源于TensorFlow Keras官方教程

先更新代码在这里,后面找时间理解注释一下。

# TensorFlow and tf.keras
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
import tensorflow as tf
from tensorflow import keras

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)
1.12.0
imdb = keras.datasets.imdb

(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)

Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz
17465344/17464789 [==============================] - 12s 1us/step
print("Training entries: {}, labels: {}".format(len(train_data), len(train_labels)))
Training entries: 25000, labels: 25000
print(train_data[0])
len(train_data[0]), len(train_data[1])
[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]





(218, 189)
# A dictionary mapping words to an integer index
word_index = imdb.get_word_index()

# The first indices are reserved
word_index = {k:(v+3) for k,v in word_index.items()}
word_index["<PAD>"] = 0
word_index["<START>"] = 1
word_index["<UNK>"] = 2  # unknown
word_index["<UNUSED>"] = 3

reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])

def decode_review(text):
    return ' '.join([reverse_word_index.get(i, '?') for i in text])
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb_word_index.json
1646592/1641221 [==============================] - 2s 1us/step
decode_review(train_data[0])
"<START> 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 <UNK> is an amazing actor and now the same being director <UNK> 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 <UNK> 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 <UNK> to the two little boy's that played the <UNK> of norman and paul they were just brilliant children are often left out of the <UNK> 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"
train_data = keras.preprocessing.sequence.pad_sequences(train_data,
                                                        value=word_index["<PAD>"],
                                                        padding='post',
                                                        maxlen=256)

test_data = keras.preprocessing.sequence.pad_sequences(test_data,
                                                       value=word_index["<PAD>"],
                                                       padding='post',
                                                       maxlen=256)

len(train_data[0]), len(train_data[1])
(256, 256)
print(train_data[0])
[   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    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0    0    0    0    0    0    0    0    0    0    0
    0    0    0    0]

网络模型的介绍:
1,输入网络的形状为(-1,256)
2,Embedding后为(-1,256,16)网络参数为(10000,16)
3,GlobalAveragePooling1D后为(-1,16)详细介绍见此
4,Dense1后(-1,16)网络参数为w:1616 + b:116 共计272
4,Dense2后(-1,1)网络参数为w:161 + b:11 共计17个参数

vocab_size = 10000

model = keras.Sequential()
model.add(keras.layers.Embedding(vocab_size, 16))
model.add(keras.layers.GlobalAveragePooling1D())
model.add(keras.layers.Dense(16, activation=tf.nn.relu))
model.add(keras.layers.Dense(1, activation=tf.nn.sigmoid))

model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 16)          160000    
_________________________________________________________________
global_average_pooling1d (Gl (None, 16)                0         
_________________________________________________________________
dense (Dense)                (None, 16)                272       
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 17        
=================================================================
Total params: 160,289
Trainable params: 160,289
Non-trainable params: 0
_________________________________________________________________
model.compile(optimizer=tf.train.AdamOptimizer(),
              loss='binary_crossentropy',
              metrics=['accuracy'])
x_val = train_data[:10000]
partial_x_train = train_data[10000:]

y_val = train_labels[:10000]
partial_y_train = train_labels[10000:]
history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=20,
                    batch_size=512,
                    validation_data=(x_val, y_val),
                    verbose=1)
Train on 15000 samples, validate on 10000 samples
Epoch 1/20
15000/15000 [==============================] - 3s 215us/step - loss: 0.6919 - acc: 0.5925 - val_loss: 0.6899 - val_acc: 0.6360
Epoch 2/20
15000/15000 [==============================] - 2s 159us/step - loss: 0.6863 - acc: 0.7131 - val_loss: 0.6824 - val_acc: 0.7418
Epoch 3/20
15000/15000 [==============================] - 2s 155us/step - loss: 0.6746 - acc: 0.7652 - val_loss: 0.6676 - val_acc: 0.7583
Epoch 4/20
15000/15000 [==============================] - 2s 153us/step - loss: 0.6534 - acc: 0.7707 - val_loss: 0.6440 - val_acc: 0.7636
Epoch 5/20
15000/15000 [==============================] - 2s 153us/step - loss: 0.6221 - acc: 0.7933 - val_loss: 0.6104 - val_acc: 0.7872
Epoch 6/20
15000/15000 [==============================] - 2s 153us/step - loss: 0.5820 - acc: 0.8095 - val_loss: 0.5713 - val_acc: 0.7985
Epoch 7/20
15000/15000 [==============================] - 2s 154us/step - loss: 0.5368 - acc: 0.8271 - val_loss: 0.5297 - val_acc: 0.8163
Epoch 8/20
15000/15000 [==============================] - 2s 159us/step - loss: 0.4907 - acc: 0.8427 - val_loss: 0.4891 - val_acc: 0.8306
Epoch 9/20
15000/15000 [==============================] - 3s 170us/step - loss: 0.4478 - acc: 0.8557 - val_loss: 0.4525 - val_acc: 0.8405
Epoch 10/20
15000/15000 [==============================] - 2s 165us/step - loss: 0.4089 - acc: 0.8692 - val_loss: 0.4213 - val_acc: 0.8482
Epoch 11/20
15000/15000 [==============================] - 2s 156us/step - loss: 0.3760 - acc: 0.8791 - val_loss: 0.3977 - val_acc: 0.8541
Epoch 12/20
15000/15000 [==============================] - 2s 153us/step - loss: 0.3483 - acc: 0.8852 - val_loss: 0.3745 - val_acc: 0.8616
Epoch 13/20
15000/15000 [==============================] - 3s 171us/step - loss: 0.3236 - acc: 0.8929 - val_loss: 0.3581 - val_acc: 0.8661
Epoch 14/20
15000/15000 [==============================] - 3s 171us/step - loss: 0.3031 - acc: 0.8981 - val_loss: 0.3436 - val_acc: 0.8711
Epoch 15/20
15000/15000 [==============================] - 3s 178us/step - loss: 0.2854 - acc: 0.9033 - val_loss: 0.3322 - val_acc: 0.8732
Epoch 16/20
15000/15000 [==============================] - 3s 173us/step - loss: 0.2702 - acc: 0.9057 - val_loss: 0.3230 - val_acc: 0.8755
Epoch 17/20
15000/15000 [==============================] - 2s 165us/step - loss: 0.2557 - acc: 0.9131 - val_loss: 0.3152 - val_acc: 0.8771
Epoch 18/20
15000/15000 [==============================] - 2s 155us/step - loss: 0.2431 - acc: 0.9171 - val_loss: 0.3087 - val_acc: 0.8799
Epoch 19/20
15000/15000 [==============================] - 2s 155us/step - loss: 0.2315 - acc: 0.9213 - val_loss: 0.3033 - val_acc: 0.8812
Epoch 20/20
15000/15000 [==============================] - 2s 164us/step - loss: 0.2213 - acc: 0.9236 - val_loss: 0.2991 - val_acc: 0.8821
results = model.evaluate(test_data, test_labels)

print(results)
25000/25000 [==============================] - 1s 38us/step
[0.3124048164367676, 0.87232]
history_dict = history.history
history_dict.keys()
dict_keys(['val_loss', 'val_acc', 'loss', 'acc'])
import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" is for "blue dot"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()

png

plt.clf()   # clear figure
acc_values = history_dict['acc']
val_acc_values = history_dict['val_acc']

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()

plt.show()

png

2018-08-13 23:35:26 suredied 阅读数 4774
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    39692 人正在学习 去看看 唐宇迪

前面几节叙述了卷积神经网络在图像分类中的应用,本节将描述深度学习网络在诸如回归预测、自然语言处理等领域的应用。主要内容如下:

  • Drop Out策略,以及Fast.AI附加层架构分析。
  • 结构化时间序列的处理与预测。
  • IMDB影评倾向性分析。

Drop Out策略,以及Fast.AI附加层架构分析

Drop Out策略是一种避免过拟合的有效手段。在Fast.AI框架下,通过设置分类器构造函数的ps参数,来启用Drop Out功能:

learn = ConvLearner.pretrained(arch, data, ps=0.5, precompute=True)
learn

第二条语句会输出Fast.AI在已有的网络结构的基础上添加的网络层:

Sequential(
    (0): BatchNorm1d(1024, eps=1e-05, momentum=0.1, affine=True)
    (1): Dropout(p=0.5)
    (2): Linear(in_features=1024, out_features=512)
    (3): ReLU()
    (4): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True)
    (5): Dropout(p=0.5)
    (6): Linear(in_features=512, out_features=120)
    (7): LogSoftmax()
)

其中(0)和(4)BatchNorm层的功能将在第七课中叙述。(1)和(5)为Drop Out层,参数为p=0.5,(2)(3)层构成一个全连接层后接ReLU非线性输出的结构,(6)(7)层构成一个全连接层后接LogSoftmax的输出层结构(之所以对Softmax取对数,是出于精度的考虑)。

Drop Out层的参数p的作用是:对上一层产生的数值,以概率p随机丢弃。如果丢弃的这些值和用于分类的特征非常相关,这样操作就会使得网络继续深究用于分类的其他特征,从而获取更为全面的信息,提高泛化能力。在进行丢弃的同时,保留下来的值要做相应倍数的放大,以保证不会因为丢弃一定比例的值而出现加权结果的系统性偏差。

Fast.AI框架中默认的设置为:第一个Drop Out层的p值为0.25,第二个Drop Out层的p值为0.5。这也是为什么验证数据集上的损失函数要小于训练数据集上的损失函数的原因,因为Fast.AI在训练时启用了Drop Out,而在验证时则未做Drop Out操作,这反应了Drop Out在提高网络泛化能力方面的效果。

若要改变默认设置,可在学习器生成函数中传入二元数组ps。若要禁用Drop Out,可设置ps=0.,此时附加层的结构为:

Sequential(
    (0): BatchNorm1d(4096, eps=1e-05, momentum=0.1, affine=True)
    (1): Linear(in_features=4096, out_features=512)
    (2): ReLU()
    (3): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True)
    (4): Linear(in_features=512, out_features=120)
    (5): LogSoftmax()
)

事实上,附加层的结构还可简化,设置xtra_fc=[],可得到如下结构:

   Sequential(
    (0): BatchNorm1d(1024, eps=1e-05, momentum=0.1, affine=True)
    (1): Linear(in_features=1024, out_features=120)
    (2): LogSoftmax()
)

通过xtra_fc还能添加其他结构的网络层,如xtra_fc=[700, 300],可以得到如下附加层:

Sequential(
    (0): BatchNorm1d(1024, eps=1e-05, momentum=0.1, affine=True)
    (1): Linear(in_features=1024, out_features=700)
    (2): ReLU()
    (3): BatchNorm1d(700, eps=1e-05, momentum=0.1, affine=True)
    (4): Linear(in_features=700, out_features=300)
    (5): ReLU()
    (6): BatchNorm1d(300, eps=1e-05, momentum=0.1, affine=True)
    (7): Linear(in_features=300, out_features=120)
    (8): LogSoftmax()
)

结构化时间序列的处理与预测

结构化数据是指那些以数据表形式存在的数据,如公司的财务报表、Facebook的用户信息等。其处理方式区别于诸如音频、图像、语言文本等非结构化的数据。

本节课程将基于Kaggle竞赛中的Rossmann数据集构建能够进行回归预测的深度学习网络。数据可在Fast.AI数据集中下载。

Rossmann是德国的一家日用品连锁超市。现需要预测超市两周内的销售情况,可利用的信息有产品推广情况、竞争对手信息、学校及地方假期、地理位置等。

1. 数据预处理

从Fast.AI下载的数据比Kaggle官网下载的数据多了一些,如googletrend.csv等。这是由于课程所用数据已经按照当年该比赛中第三名的预处理流程清洗了一遍,并补充了一些诸如谷歌搜索趋势等的辅助数据。此外,还需做的工作是:修改各表中不是理想数据类型的字段,如布尔值要做0-1转换;通过Fast.AI的add_datepart()函数处理日期,即标定每天是一周、一个月、一年的第几天等;把关联表联接在一起;填充未能获取的字段;等等。这部分内容可参看Fast.AI的Machine Learning课程。最终数据存储为feather格式,这种格式可以使数据存储在RAM中,从而提高读写效率。

2. 字段划分

最终形成的数据表中包含多种字段,如商店编号、日期、一周中第几天、是否是假期、距离上次假期多少天、距离下次假期多少天、竞争店铺距离、谷歌趋势值、天气参数等。其中像竞争店铺距离、谷歌趋势值等属于连续变量;而像商店编号、一周中第几天则属于类型变量(Categorical Parameters),其只能取若干阶值(levels)。另外像年份这样的变量,虽然是一年一年连续变化,但若看成类型变量,则可以针对不同年份区别对待。而像气温这样的连续变化的变量,也可以通过划分区段转换成类型变量(尽管课程中并没有这样做)。划分字段后,调用pandas相关函数,将其转化为对应的数据类型:joined[<category_field>].astype('category'),joined[<continuous_field>].astype('float32')
个人看法:类型变量和连续变量的划分更多体现的是对所建模型与实际应用场景是否契合的考量,也没有一定之规。

3. 进一步将数据整理为网络所需形式

调用如下语句:

df, y, nas, mapper = proc_df(joined_samp, 'Sales', do_scale=True)

其中proc_df表示process data frame。“Sales”指定了作为输出的字段,用于生成y,并会被从表中删除;do_scale表示将对数据进行归一化,即使之变成均值为0、方差为1的数据,所做的变换被记录在mapper中,用于对测试数据做同样变换。proc_df()还将处理缺失值,对于类型变量缺失值将会替换为0,对于连续变量,缺失值将会被替换为中值。

4. 基于上述数据格式构建网络

经过上述步骤之后,就可调用Fast.AI的接口,获取满足网络输入要求的数据:

md = ColumnarModelData.from_data_frame(PATH, val_idx, df, 
         yl.astype(np.float32), cat_flds=cat_vars, bs=128, 
         test_df=df_test)

其中yl为销售量(归一化处理后)的对数;cat_flds指定了哪些字段是类型变量。

然后获取预测器:

m = md.get_learner(emb_szs, len(df.columns)-len(cat_vars),
                   0.04, 1, [1000,500], [0.001,0.01], 
                   y_range=y_range)

其中emb_szs是针对类型变量的一个关键参数,标明了内置矩阵的维度;内置矩阵的原理后面会详述;0.04指定了和内置矩阵相关的丢弃概率;1为输出的尺寸;[1000, 500][0.001, 0.01]分别为两个附加层的尺寸和丢弃率(参见上节课的博文);y_range限定了最终输出结果的数值范围。

5. 类型变量的处理

神经网络的训练会采用反向传播算法,其涉及求导,因此,对于类型变量这样取值离散的输入,得做进一步的处理。一种策略就是使用向量替换类型变量,而向量的每个元素取值连续。例如,可采用7个长度相同的向量表示周一到周日。这里引入了超参数——向量长度,一个设置参考是,取类型变量取值个数的一半,但当类型变量取值太多时,可设置一个上限。比如表征一周七天的向量的维度就可设置为4。这一超参数对应于get_learner()中的emb_szs参数,而由类型参数的值所对应的向量组成的矩阵称为内置矩阵(Embedding Matrix)。

图 1. 标识周几的内嵌矩阵

之所以用向量而不是用单一数值代替类型变量,是因为使用向量可以提供更多的语义信息。以预测商品销量为例,周末和工作日可能是影响销量的一个因素,这一因素关联所有商品;另一方面,一周的某一天可能和特定商品关联紧密,比如,周五可能啤酒的销量会高。考量这两类因素的作用,使用单一值替换周几,表述力就会不足。

事实上,内置矩阵方法和一位有效编码(one-hot)方法相互等效,但后者涉及了矩阵相乘,远没有查表取出对应向量的做法高效。

图 2. one-hot编码
6. 训练网络

按照第二课中的通用步骤训练网络即可。

基于语言模型的IMDB影评分析

本节将介绍如何利用深度学习网络对IMDB的影评进行分析,判断好评差评。类似的应用场景还有:对冲基金舆情分析,即分析文章消息、Twiiter内容是否会导致市场波动;用户服务咨询,用以判断用户是否会接受相关服务协定;等。

我们首先需要一个能够读懂英文的语言模型。所谓语言模型,就是在输入若干字词后,能够输出一个接下来的字词。课程中将使用IMDB影评数据,训练一个网络,该网络能够在输入一小段前置语句后,生成段落。

1. IMDB影评数据预处理,生成模型所需的数据

所用数据为Large Movie Review Dataset,(注意,Fast.AI提供的数据和IMDB提供的数据略有不同,Fast.AI提供的数据将所有影评数据置入all子目录下),下载解压后,其目录结构如下

imdbEr.txt imdb.vocab models/ README test/ tmp/ train/

在train文件夹下,以posnegunsup目录区分了影评类别,每个影评文档是以独立的txt格式存储的;all中包含了所有文件,总共约5万篇,1700万词。影评得分为10分制,不低于于7分的判定为好评,不高于4分的判定为差评,其余为判定为中立。本例中不考虑中立的数据。

首先将影评文档进行分词,这会用到自然语言处理的一个第三方库spacy,并需要其内置的模型en

pip install spacy
python -m spacy download en

以下是生成模型所需类型的数据的语句:

bs=64; bptt=70
TEXT = data.Field(lower=True, tokenize="spacy")
FILES = dict(train=TRN_PATH, validation=VAL_PATH, test=VAL_PATH)
md = LanguageModelData.from_text_files(PATH, TEXT, **FILES, bs=bs, bptt=bptt, min_freq=10)

参数bs为数据块大小,bpttBackProp Through Time的缩写,限定了一次处理的词数,也决定了后向传播的所作用的层数(本节所用的网络是循环神经网络),具体原理后续课程会介绍。
第二条语句生成一个torchtextfield对象,指定对其中的数据进行小写转换,并用spacy进行分词。第三条语句生成训练集、验证集、测试集的路径字典,本例中并未划分验证集,将使用测试集作为验证集。第四条语句则是生成模型所需的数据,这一步之后,TEXT对象将会携带一个词库TEXT.vocab,该词库包含了分词结果中所有词频不低于min_freq的不同的词,每个词会有一个对应的整数索引。而md中的数据的组织形式如图3所示,具体描述如下:将所有影评文档连接为词的长向量,然后划分为bs段,将这bs段堆积转置得到一个词矩阵,这个词矩阵中每一行的词都是上一行的词的下一个。而每次取出用于做训练的块的大小则由bptt约定。每次迭代,torchtext会在bptt附近选择一个随机值,这种机制是为了实现像图片网络中那种数据随机化(shuffle)的效果;但由于词与词之间的顺序关系是本节的应用场景所要处理事项,因此采用随机化块大小的策略。

图 3. ModelData中数据组织形式
2. 生成网络模型,进行训练

本例中获取网络模型的代码如下:

earner = md.get_model(opt_fn, em_sz, nh, nl,
               dropouti=0.05, dropout=0.05, wdrop=0.1, dropoute=0.02, dropouth=0.05)
learner.reg_fn = partial(seq2seq_reg, alpha=2, beta=1)
learner.clip=0.3

其中opt_fn = partial(optim.Adam, betas=(0.7, 0.99)),即采用的优化方法为Adam,后续课程会介绍相关原理以及后面参数的意义。em_sz=200是内置矩阵的尺寸,即每个词将会被一个200维的向量表示;nh=500是隐含层的大小;nl=3是网络层数。在此,Fast.AI采用的模型是Stephen Merity的LSTM语言模型get_model()中的后面几个drop out值都是该模型中与避免过拟合有关的参数,具体原理将在本系列课程的第七课中交代。learner.reg_fn同样起到抑制过拟合现象的作用,其原理也会在第七课中有所论述。learn.clip限定了梯度下降算法的步长。

训练模型后,调用learner.save_encoder()存储模型,以用于后面的影评分类。

3. 测试

Fast.AI尚未提供较为便捷的相关接口,课程中给出的测试代码及说明如下:

# Set batch size to 1
m[0].bs=1
# Turn off dropout
m.eval()
# Reset hidden state
m.reset()
# Get predictions from model
res,*_ = m(t)
# Put the batch size back to what it was
m[0].bs=bs

其中m=learner.modelt为分词后、并用字词索引值表示的向量。最终达到的效果是输入"So, it wasn't quite was I was expecting, but I really liked it anyway! The best"后,输出"film ever ! <eos> i saw this movie at the toronto international film festival . i was very impressed . i was very impressed with the acting . i was very impressed with the acting . i was surprised to see that the actors were not in the movie ."

4. 影评分析

数据整理:

IMDB_LABEL = data.Field(sequential=False)
splits = torchtext.datasets.IMDB.splits(TEXT, IMDB_LABEL, 'data/')

第一条语句表明IMDB_LABEL是一个没有序列关系的向量,用于存储每篇影评的标签。第二条语句使用torchtextsplits()函数来分割数据集,产生训练数据、测试数据、验证数据。torchtext内置了针对IMDB影评数据的一些接口。

获取满足输入要求的数据对象:

md2 = TextData.from_splits(PATH, splits, bs)

其中Fast.AI的TextData模块可以从torchtext.splits()的输出结果中构建满足输入要求的数据对象。

获取网络模型,进行训练:
获取模型的代码如下:

m3 = md2.get_model(opt_fn, 1500, bptt, emb_sz=em_sz, n_hid=nh, n_layers=nl, 
           dropout=0.1, dropouti=0.4, wdrop=0.5, dropoute=0.05, dropouth=0.3)
m3.reg_fn = partial(seq2seq_reg, alpha=2, beta=1)
m3.load_encoder(f'adam3_20_enc')

其中adam3_20_enc即是前面所得到的语言模型。训练步骤与前面课程中的图像网络的训练过程大体相似。

备注

  • 注意采用add_datepart()对日期进行处理,提取其在一周中、一月内、一年里的索引,否则不能发现数据中的周期性、季节性。
  • 评判指标设置:在销量预测中使用的评判指标是平均相对误差平方根,假设函数rmspe()实现了该值的计算,则在训练网络时,传入该函数的引用:learn.fit(lr, 3, metrics=[rmspe])
  • 注意lesson4-imdb.ipynb中,在执行learner.load_cycle('adam3_10',2)可能会提示模型找不到,这是由于这个notebook里的某些cells可能是课上加上的,并不是顺序执行的。可以先把这一句跳过。
  • lang_model-arxiv.ipynb展示了如何组织符合Fast.AI/torchtext规范的数据。

一些有用的链接

2017-06-04 09:32:12 weixin_38776853 阅读数 705
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    39692 人正在学习 去看看 唐宇迪

序列分类,预测整个输入序列的类别标签。情绪分析,预测用户撰写文字话题态度。预测选举结果或产品、电影评分。

国际电影数据库(International Movie Database)影评数据集。目标值二元,正面或负面。语言大量否定、反语、模糊,不能只看单词是否出现。构建词向量循环网络,逐个单词查看每条评论,最后单词话性值训练预测整条评论情绪分类器。

斯担福大学人工智能实验室的IMDB影评数据集: http://ai.stanford.edu/~amaas/data/sentiment/ 。压缩tar文档,正面负面评论从两个文件夹文本文件获取。利用正则表达式提取纯文本,字母全部转小写。

词向量嵌入表示,比独热编码词语语义更丰富。词汇表确定单词索引,找到正确词向量。序列填充相同长度,多个影评数据批量送入网络。

序列标注模型,传入两个占位符,一输入数据data或序列,二目标值target或情绪。传入配置参数params对象,优化器。

动态计算当前批数据序列长度。数据单个张量形式,各序列以最长影评长度补0。绝对值最大值缩减词向量。零向量,标量0。实型词向量,标量大于0实数。tf.sign()离散为0或1。结果沿时间步相加,得到序列长度。张量长度与批数据容量相同,标量表示序列长度。

使用params对象定义单元类型和单元数量。length属性指定向RNN提供批数据最多行数。获取每个序列最后活性值,送入softmax层。因每条影评长度不同,批数据每个序列RNN最后相关输出活性值有不同索引。在时间步维度(批数据形状sequences*time_steps*word_vectors)建立索引。tf.gather()沿第1维建立索引。输出活性值形状sequences*time_steps*word_vectors前两维扁平化(flatten),添加序列长度。添加length-1,选择最后有效时间步。

梯度裁剪,梯度值限制在合理范围内。可用任何中分类有意义代价函数,模型输出可用所有类别概率分布。增加梯度裁剪(gradient clipping)改善学习结果,限制最大权值更新。RNN训练难度大,不同超参数搭配不当,权值极易发散。

TensorFlow支持优化器实例compute_gradients函数推演,修改梯度,apply_gradients函数应用权值变化。梯度分量小于-limit,设置-limit;梯度分量在于limit,设置limit。TensorFlow导数可取None,表示某个变量与代价函数没有关系,数学上应为零向量但None利于内部性能优化,只需传回None值。

影评逐个单词送入循环神经网络,每个时间步由词向量构成批数据。batched函数查找词向量,所有序列长度补齐。训练模型,定义超参数、加载数据集和词向量、经过预处理训练批数据运行模型。模型成功训练,取决网络结构、超参数、词向量质量。可从skip-gram模型word2vec项目(https://code.google.com/archive/p/word2vec/ )、斯坦福NLP研究组Glove模型(https://nlp.stanford.edu/projects/glove ),加载预训练词向量。

Kaggle 开放学习竞赛(https://kaggle.com/c/word2vec-nlp-tutorial ),IMDB影评数据,与他人比较预测结果。

import tarfile
import re

from helpers import download


class ImdbMovieReviews:

    DEFAULT_URL = \
    'http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz'
    TOKEN_REGEX = re.compile(r'[A-Za-z]+|[!?.:,()]')

def __init__(self, cache_dir, url=None):
    self._cache_dir = cache_dir
    self._url = url or type(self).DEFAULT_URL

    def __iter__(self):
        filepath = download(self._url, self._cache_dir)
        with tarfile.open(filepath) as archive:
            for filename in archive.getnames():
                if filename.startswith('aclImdb/train/pos/'):
                    yield self._read(archive, filename), True
                elif filename.startswith('aclImdb/train/neg/'):
                    yield self._read(archive, filename), False

    def _read(self, archive, filename):
        with archive.extractfile(filename) as file_:
            data = file_.read().decode('utf-8')
            data = type(self).TOKEN_REGEX.findall(data)
            data = [x.lower() for x in data]
            return data

import bz2
import numpy as np


class Embedding:

    def __init__(self, vocabulary_path, embedding_path, length):
        self._embedding = np.load(embedding_path)
        with bz2.open(vocabulary_path, 'rt') as file_:
            self._vocabulary = {k.strip(): i for i, k in enumerate(file_)}
        self._length = length

    def __call__(self, sequence):
        data = np.zeros((self._length, self._embedding.shape[1]))
        indices = [self._vocabulary.get(x, 0) for x in sequence]
        embedded = self._embedding[indices]
        data[:len(sequence)] = embedded
        return data

    @property
    def dimensions(self):
        return self._embedding.shape[1]

import tensorflow as tf

from helpers import lazy_property


class SequenceClassificationModel:

    def __init__(self, data, target, params):
        self.data = data
        self.target = target
        self.params = params
        self.prediction
        self.cost
        self.error
        self.optimize

    @lazy_property
    def length(self):
        used = tf.sign(tf.reduce_max(tf.abs(self.data), reduction_indices=2))
        length = tf.reduce_sum(used, reduction_indices=1)
        length = tf.cast(length, tf.int32)
        return length

    @lazy_property
    def prediction(self):
        # Recurrent network.
        output, _ = tf.nn.dynamic_rnn(
            self.params.rnn_cell(self.params.rnn_hidden),
            self.data,
            dtype=tf.float32,
            sequence_length=self.length,
        )
        last = self._last_relevant(output, self.length)
        # Softmax layer.
        num_classes = int(self.target.get_shape()[1])
        weight = tf.Variable(tf.truncated_normal(
            [self.params.rnn_hidden, num_classes], stddev=0.01))
        bias = tf.Variable(tf.constant(0.1, shape=[num_classes]))
        prediction = tf.nn.softmax(tf.matmul(last, weight) + bias)
        return prediction

    @lazy_property
    def cost(self):
        cross_entropy = -tf.reduce_sum(self.target * tf.log(self.prediction))
        return cross_entropy

    @lazy_property
    def error(self):
        mistakes = tf.not_equal(
            tf.argmax(self.target, 1), tf.argmax(self.prediction, 1))
        return tf.reduce_mean(tf.cast(mistakes, tf.float32))

    @lazy_property
    def optimize(self):
        gradient = self.params.optimizer.compute_gradients(self.cost)
        try:
            limit = self.params.gradient_clipping
            gradient = [
                (tf.clip_by_value(g, -limit, limit), v)
                if g is not None else (None, v)
                for g, v in gradient]
        except AttributeError:
            print('No gradient clipping parameter specified.')
        optimize = self.params.optimizer.apply_gradients(gradient)
        return optimize

    @staticmethod
    def _last_relevant(output, length):
        batch_size = tf.shape(output)[0]
        max_length = int(output.get_shape()[1])
        output_size = int(output.get_shape()[2])
        index = tf.range(0, batch_size) * max_length + (length - 1)
        flat = tf.reshape(output, [-1, output_size])
        relevant = tf.gather(flat, index)
        return relevant

import tensorflow as tf

from helpers import AttrDict

from Embedding import Embedding
from ImdbMovieReviews import ImdbMovieReviews
from preprocess_batched import preprocess_batched
from SequenceClassificationModel import SequenceClassificationModel

IMDB_DOWNLOAD_DIR = './imdb'
WIKI_VOCAB_DIR = '../01_wikipedia/wikipedia'
WIKI_EMBED_DIR = '../01_wikipedia/wikipedia'


params = AttrDict(
    rnn_cell=tf.contrib.rnn.GRUCell,
    rnn_hidden=300,
    optimizer=tf.train.RMSPropOptimizer(0.002),
    batch_size=20,
)

reviews = ImdbMovieReviews(IMDB_DOWNLOAD_DIR)
length = max(len(x[0]) for x in reviews)

embedding = Embedding(
    WIKI_VOCAB_DIR + '/vocabulary.bz2',
    WIKI_EMBED_DIR + '/embeddings.npy', length)
batches = preprocess_batched(reviews, length, embedding, params.batch_size)

data = tf.placeholder(tf.float32, [None, length, embedding.dimensions])
target = tf.placeholder(tf.float32, [None, 2])
model = SequenceClassificationModel(data, target, params)

sess = tf.Session()
sess.run(tf.initialize_all_variables())
for index, batch in enumerate(batches):
    feed = {data: batch[0], target: batch[1]}
    error, _ = sess.run([model.error, model.optimize], feed)
    print('{}: {:3.1f}%'.format(index + 1, 100 * error))

参考资料:
《面向机器智能的TensorFlow实践》

欢迎加我微信交流:qingxingfengzi
我的微信公众号:qingxingfengzigz
我老婆张幸清的微信公众号:qingqingfeifangz

2019-10-11 03:01:17 LEEANG121 阅读数 83
  • 机器学习&深度学习系统实战!

    购买课程后,可扫码进入学习群,获取唐宇迪老师答疑 数学原理推导与案例实战紧密结合,由机器学习经典算法过度到深度学习的世界,结合深度学习两大主流框架Caffe与Tensorflow,选择经典项目实战人脸检测与验证码识别。原理推导,形象解读,案例实战缺一不可!具体课程内容涉及回归算法原理推导、决策树与随机森林、实战样本不均衡数据解决方案、支持向量机、Xgboost集成算法、神经网络基础、神经网络整体架构、卷积神经网络、深度学习框架--Tensorflow实战、案例实战--验证码识别、案例实战--人脸检测。 专属会员卡优惠链接:http://edu.csdn.net/lecturer/1079

    39692 人正在学习 去看看 唐宇迪

深度学习入坑笔记之四---电影评论文本分类问题


电影的影评一般分为正面(positive)或负面(nagetive)两类。这是一个二元(binary)或者二分类问题,一种重要且应用广泛的机器学习问题。
我们将使用来源于网络电影数据库(Internet Movie Database)的 IMDB 数据集(IMDB dataset),其包含 50,000 条影评文本。从该数据集切割出的25,000条评论用作训练,另外 25,000 条用作测试。训练集与测试集是平衡的(balanced),意味着它们包含相等数量的积极和消极评论。
本文的代码来自tensorflow教程官网

数据下载

和之前项目一样,首先配置环境参数 具体代码如下:

from __future__ import absolute_import, division, print_function, unicode_literals#该行要放在第一行位置
import warnings#忽略系统警告提示
warnings.filterwarnings('ignore')
import tensorflow as tf
from tensorflow import keras

import numpy as np
print(tf.__version__)
2.0.0

基本配置设定完毕后,可以下载数据集。IMDB 数据集已经打包在 Tensorflow 中。该数据集已经经过预处理,评论(单词序列)已经被转换为整数序列,其中每个整数表示字典中的特定单词。具体代码如下:

imdb = keras.datasets.imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)#参数 num_words=10000 保留了训练数据中最常出现的 10,000 个单词。为了保持数据规模的可管理性,低频词将被丢弃。

参数 num_words=10000 保留了训练数据中最常出现的 10,000 个单词,注意10000是指常用单词数量,并非下载的样本数量。为了保持数据规模的可管理性,低频词将被丢弃。
这里如果您已经下载过该数据集,则会直接从缓存中复制。

了解数据
让我们花一点时间来了解数据格式。该数据集是经过预处理的:每个样本都是一个表示影评中词汇的整数数组。每个标签都是一个值为 0 或 1 的整数值,其中 0 代表消极评论,1 代表积极评论。

print('Training entries: {}, labels: {}'.format(len(train_data), len(train_labels)))
Training entries: 25000, labels: 25000#25000个样本和25000个标签

评论文本被转换为整数值,其中每个整数代表词典中的一个单词。(注意:这里我本来以为每个数字代表的是26个字母中的一个。。。这里就是字面意思,一个单词,具体我会在下面详细说明)我们以第一条评论为例:

print(train_data[0]) #这里一定要注意,每个数字代表的是单词,不是字母。
[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]

电影评论可能具有不同的长度。以下代码显示了第一条和第二条评论的中单词数量。由于神经网络的输入必须是统一的长度,我们稍后需要解决这个问题。

len(train_data[0]), len(train_data[1])
(218, 189)

将整数转换回单词
对于上面一串数字代表的具体含义,大家肯定很好奇。了解如何将整数转换回文本对您可能是有帮助的。这里我们将创建一个辅助函数来查询一个包含了整数到字符串映射的字典对象:

#一个映射单词到整数索引的词典
word_index = imdb.get_word_index()#建立词典索引
#保留第一个索引
word_index = {k:(v+3) for k,v in word_index.items()}
word_index["<PAD>"] = 0#这里0代表<PAD>
word_index["<START>"] = 1#这里1代表<START>
word_index["<UNK>"] = 2#这里2代表<UNK>(unknown)
word_index["<UNUSED>"] = 3#这里3代表<UNUSED>

reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
def decode_review(text):
    return ' '.join([reverse_word_index.get(i, '?') for i in text])

字典建立完毕后,我们可以使用 decode_review 函数来显示首条评论的文本:

decode_review(train_data[0])
"<START> 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 <UNK> is an amazing actor and now the same being director <UNK> 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 <UNK> 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 <UNK> to the two little boy's that played the <UNK> of norman and paul they were just brilliant children are often left out of the <UNK> 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"

数据处理

准备数据
由于神经网络的输入必须是张量形式,因此影评需要首先转换为张量,然后才可以进行学习,转换的方式有两种:
1 将数组转换为表示单词出现与否的由 0 和 1 组成的向量,类似于 one-hot 编码。例如,序列[3, 5]将转换为一个 10,000 维的向量,该向量除了索引为 3 和 5 的位置是 1 以外,其他都为 0。然后,将其作为网络的首层——一个可以处理浮点型向量数据的稠密层。不过,这种方法需要大量的内存,需要一个大小为 num_words * num_reviews 的矩阵。
2 我们可以填充数组来保证输入数据具有相同的长度,然后创建一个大小为 max_length * num_reviews 的整型张量。我们可以使用能够处理此形状数据的嵌入层作为网络中的第一层。

在本示例中,我们将使用第二种方法。
由于电影评论长度必须相同,我们将使用 pad_sequences 函数来使长度标准化:

#训练数据长度设置为256
train_data = keras.preprocessing.sequence.pad_sequences(train_data,
                                                        value=word_index["<PAD>"],
                                                        padding='post',
                                                         maxlen=256)
#测试数据长度设置为256
test_data = keras.preprocessing.sequence.pad_sequences(test_data,
                                                       value=word_index["<PAD>"],
                                                       padding='post',
                                                        maxlen=256)

现在让我们看下样本的长度:

len(train_data[0]), len(train_data[1])
(256, 256)

我们再检查一下首条评论(当前已经填充)

print(train_data[0])
[   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    0    0    0    0    0    0
0    0    0    0    0    0    0    0    0    0    0    0    0    0
0    0    0    0    0    0    0    0    0    0    0    0    0    0
0    0    0    0]

可以看到现在数据长度均为256。

模型搭建

模型网络架构
接下来进行模型的搭建,神经网络由堆叠的层来构建,这需要从两个主要方面来进行体系结构决策:
模型里有多少层?
每个层里有多少隐层单元(hidden units)?
在此样本中,输入数据包含一个单词索引的数组。要预测的标签为 0 或 1。让我们来为该问题构建一个模型,首先我们利用keras.Sequential进行层的序列化添加,具体代码如下:

# 输入形状是用于电影评论的词汇数目(10,000 词)
vocab_size = 10000
model = keras.sequential()#搭建层
model.add(keras.layers.Embedding(vocab_size, 16))#embedding 是一个将单词向量化的函数,嵌入(embeddings)输出的形状都是:(num_examples, embedding_dimension)
model.add(keras.layers.GloabAveragePooling1D())#添加全局平均池化层
model.add(keras.layers.Dense(16, activation = 'relu'))
model.add(keras.layers.Dense(1, activation = 'sigmoid'))

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 16)          160000    
_________________________________________________________________
global_average_pooling1d (Gl (None, 16)                0         
_________________________________________________________________
dense (Dense)                (None, 16)                272       
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 17        
=================================================================
Total params: 160,289
Trainable params: 160,289
Non-trainable params: 0

层按顺序堆叠以构建分类器:

第一层是嵌入(Embedding)层。该层采用整数编码的词汇表,并查找每个词索引的嵌入向量(embedding vector)。这些向量是通过模型训练学习到的。向量向输出数组增加了一个维度。得到的维度为:(batch, sequence, embedding)。
embedding 是一个将单词向量化的函数,嵌入(embeddings)输出的形状都是:(num_examples, embedding_dimension)

接下来,GlobalAveragePooling1D 将通过对序列维度求平均值来为每个样本返回一个定长输出向量。这允许模型以尽可能最简单的方式处理变长输入。

该定长输出向量通过一个有 16 个隐层单元的全连接(Dense)层传输。

最后一层与单个输出结点密集连接。使用 Sigmoid 激活函数,其函数值为介于 0 与 1 之间的浮点数,表示概率或置信度。
模型编译

model.compile(optimize = 'adam',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])

模型评估

验证模型

x_val = train_data[:10000]#取训练数据集前10000个进行训练和验证
partial_x_train = train_data[10000:]
y_val = train_labels[:10000]#同理取前10000个标签
partial_y_train = train_labels[10000:]

模型训练

#以 512 个样本的 mini-batch 大小迭代 40 个 epoch 来训练模型。这是指对 x_train 和 y_train 张量中所有样本的的 40 次迭代。在训练过程中,监测来自验证集的 10,000 个样本上的损失值(loss)和准确率(accuracy):
history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=40,
                    batch_size=512,
                    validation_data=(x_val, y_val),
                    verbose=1)
Train on 15000 samples, validate on 10000 samples
Epoch 1/40
15000/15000 [==============================] - 1s 88us/sample - loss: 0.6924 - accuracy: 0.6045 - val_loss: 0.6910 - val_accuracy: 0.6819
Epoch 2/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.6885 - accuracy: 0.6392 - val_loss: 0.6856 - val_accuracy: 0.7129
Epoch 3/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.6798 - accuracy: 0.7371 - val_loss: 0.6747 - val_accuracy: 0.7141
Epoch 4/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.6629 - accuracy: 0.7648 - val_loss: 0.6539 - val_accuracy: 0.7597
Epoch 5/40
15000/15000 [==============================] - 0s 21us/sample - loss: 0.6356 - accuracy: 0.7860 - val_loss: 0.6239 - val_accuracy: 0.7783
Epoch 6/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.5975 - accuracy: 0.8036 - val_loss: 0.5849 - val_accuracy: 0.7931
Epoch 7/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.5525 - accuracy: 0.8195 - val_loss: 0.5421 - val_accuracy: 0.8076
Epoch 8/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.5025 - accuracy: 0.8357 - val_loss: 0.4961 - val_accuracy: 0.8245
Epoch 9/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.4541 - accuracy: 0.8537 - val_loss: 0.4555 - val_accuracy: 0.8392
Epoch 10/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.4114 - accuracy: 0.8672 - val_loss: 0.4211 - val_accuracy: 0.8469
Epoch 11/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.3753 - accuracy: 0.8775 - val_loss: 0.3938 - val_accuracy: 0.8531
Epoch 12/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.3451 - accuracy: 0.8859 - val_loss: 0.3713 - val_accuracy: 0.8600
Epoch 13/40
15000/15000 [==============================] - 0s 21us/sample - loss: 0.3201 - accuracy: 0.8924 - val_loss: 0.3540 - val_accuracy: 0.8665
Epoch 14/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.2990 - accuracy: 0.8983 - val_loss: 0.3397 - val_accuracy: 0.8712
Epoch 15/40
15000/15000 [==============================] - 0s 23us/sample - loss: 0.2809 - accuracy: 0.9037 - val_loss: 0.3290 - val_accuracy: 0.8735
Epoch 16/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.2649 - accuracy: 0.9095 - val_loss: 0.3197 - val_accuracy: 0.8766
Epoch 17/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.2508 - accuracy: 0.9131 - val_loss: 0.3121 - val_accuracy: 0.8792
Epoch 18/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.2379 -               accuracy: 0.9183 - val_loss: 0.3063 - val_accuracy: 0.8797
Epoch 19/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.2262 - accuracy: 0.9216 - val_loss: 0.3013 - val_accuracy: 0.8806
Epoch 20/40
15000/15000 [==============================] - 0s 21us/sample - loss: 0.2156 -   accuracy: 0.9261 - val_loss: 0.2972 - val_accuracy: 0.8828
Epoch 21/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.2061 - accuracy: 0.9292 - val_loss: 0.2939 - val_accuracy: 0.8827
Epoch 22/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.1966 - accuracy: 0.9329 - val_loss: 0.2918 - val_accuracy: 0.8833
Epoch 23/40
15000/15000 [==============================] - 0s 21us/sample - loss: 0.1881 - accuracy: 0.9368 - val_loss: 0.2892 - val_accuracy: 0.8837
Epoch 24/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.1802 - accuracy: 0.9408 - val_loss: 0.2884 - val_accuracy: 0.8841
Epoch 25/40
15000/15000 [==============================] - 0s 21us/sample - loss: 0.1725 - accuracy: 0.9436 - val_loss: 0.2871 - val_accuracy: 0.8845
Epoch 26/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.1656 - accuracy: 0.9468 - val_loss: 0.2863 - val_accuracy: 0.8856
Epoch 27/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.1592 - accuracy: 0.9494 - val_loss: 0.2863 - val_accuracy: 0.8862
Epoch 28/40
15000/15000 [==============================] - 0s 21us/sample - loss: 0.1529 - accuracy: 0.9516 - val_loss: 0.2868 - val_accuracy: 0.8851
Epoch 29/40
15000/15000 [==============================] - 0s 21us/sample - loss: 0.1465 - accuracy: 0.9555 - val_loss: 0.2871 - val_accuracy: 0.8860
Epoch 30/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.1410 - accuracy: 0.9568 - val_loss: 0.2882 - val_accuracy: 0.8858
Epoch 31/40
15000/15000 [==============================] - 0s 22us/sample - loss: 0.1354 - accuracy: 0.9591 - val_loss: 0.2896 - val_accuracy: 0.8858
Epoch 32/40
15000/15000 [==============================] - 0s 24us/sample - loss: 0.1303 - accuracy: 0.9618 - val_loss: 0.2906 - val_accuracy: 0.8865
Epoch 33/40
15000/15000 [==============================] - 0s 24us/sample - loss: 0.1251 - accuracy: 0.9639 - val_loss: 0.2923 - val_accuracy: 0.8858
Epoch 34/40
15000/15000 [==============================] - 0s 23us/sample - loss: 0.1206 - accuracy: 0.9658 - val_loss: 0.2941 - val_accuracy: 0.8858
Epoch 35/40
15000/15000 [==============================] - 0s 23us/sample - loss: 0.1164 - accuracy: 0.9668 - val_loss: 0.2972 - val_accuracy: 0.8849
Epoch 36/40
15000/15000 [==============================] - 0s 24us/sample - loss: 0.1116 - accuracy: 0.9683 - val_loss: 0.2992 - val_accuracy: 0.8845
Epoch 37/40
15000/15000 [==============================] - 0s 23us/sample - loss: 0.1075 - accuracy: 0.9709 - val_loss: 0.3010 - val_accuracy: 0.8842
Epoch 38/40
15000/15000 [==============================] - 0s 24us/sample - loss: 0.1036 - accuracy:   0.9715 - val_loss: 0.3067 - val_accuracy: 0.8807
Epoch 39/40
15000/15000 [==============================] - 0s 24us/sample - loss: 0.0996 - accuracy: 0.9724 - val_loss: 0.3068 - val_accuracy: 0.8830
Epoch 40/40
15000/15000 [==============================] - 0s 24us/sample - loss: 0.0956 - accuracy: 0.9749 - val_loss: 0.3109 - val_accuracy: 0.8823

评估模型
我们来看一下模型的性能如何。将返回两个值。损失值(loss)(一个表示误差的数字,值越低越好)与准确率(accuracy)。

results = model.evaluate(test_data,  test_labels, verbose=2)
print(results)
25000/1 - 2s - loss: 0.3454 - accuracy: 0.8732
[0.32927662477493286, 0.8732]

这种十分朴素的方法得到了约 87% 的准确率(accuracy)。若采用更好的方法,模型的准确率应当接近 95%。更优化的方法我会另行介绍。

创建一个准确率(accuracy)和损失值(loss)随时间变化的图表
model.fit() 返回一个 History 对象,该对象包含一个字典,其中包含训练阶段所发生的一切事件:

history_dict = history.history
history_dict.keys()
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])#注意这里返回的值,这里需要与下面的代码完全对应否则运算报错。

有四个条目:在训练和验证期间,每个条目对应一个监控指标。我们可以使用这些条目来绘制训练与验证过程的损失值(loss)和准确率(accuracy),以便进行比较。根据原教程的代码,在tensorflow1.1.14版本会有报错现象发生,下面我会详细指出。

import matplotlib.pyplot as plt
acc = history_dict['accuracy']#这里应改为acc
val_acc = history_dict['val_accuracy']#这里应该改为val_acc
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)
# “bo”代表 "蓝点"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b代表“蓝色实线”
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()

在这里插入图片描述

plt.clf()   # 清除数字
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

在这里插入图片描述

在该图中,点代表训练损失值(loss)与准确率(accuracy),实线代表验证损失值(loss)与准确率(accuracy)。

注意训练损失值随每一个 epoch 下降而训练准确率(accuracy)随每一个 epoch 上升。这在使用梯度下降优化时是可预期的——理应在每次迭代中最小化期望值。

验证过程的损失值(loss)与准确率(accuracy)的情况却并非如此——它们似乎在 20 个 epoch 后达到峰值。这是过拟合的一个实例:模型在训练数据上的表现比在以前从未见过的数据上的表现要更好。在此之后,模型过度优化并学习特定于训练数据的表示,而不能够泛化到测试数据。

对于这种特殊情况,我们可以通过在 20 个左右的 epoch 后停止训练来避免过拟合。

总结

对于keras深度学习的网络架构而言,主要分为如下几个步骤:
1,载入数据
2,预处理数据
3,定义模型
4,编译模型
5,训练模型
6,评估模型
7,预测
8,保存模型
对于如何保存模型,如何将训练好的模型直接拿来对我们自己的数据进行预测,我会在其他版块加以说明。

没有更多推荐了,返回首页