【2019-08-04】深度学习用于文本和序列

用于处理序列(将文本理解为单词序列或字符序列)的两种基本的深度学习算法分别是循环神经网络(recurrent neural network)和一维卷积神经网络(1D convnet)。

处理文本数据
深度学习模型不会接收原始文本作为输入,它只能处理数值张量。
文本向量化(vectorize)是指将文本转换为数值张量的过程。

文本向量化:
将文本分割为单词,并将每个单词转换为一个向量。
将文本分割为字符,并将每个字符转换为一个向量。
提取单词或字符的 n-gram,并将每个 n-gram 转换为一个向量。n-gram 是多个连续单词或字符的集合(n-gram 之间可重叠)。

从文本到标记再到向量

单词和字符的 one-hot 编码

#单词级的 one-hot 编码(简单示例)
import numpy as np
samples = ['The cat sat on the mat.', 'The dog ate my homework.']
token_index = {}
for sample in samples:
    for word in sample.split():
        if word not in token_index:
            token_index[word] = len(token_index) + 1
max_length = 10
results = np.zeros(shape=(len(samples), 
                          max_length,
                          max(token_index.values()) + 1))
for i, sample in enumerate(samples):
    for j, word in list(enumerate(sample.split()))[:max_length]:
        index = token_index.get(word) 
        results[i, j, index] = 1.#保存结果
单词级one-hot results
#字符级的 one-hot 编码(简单示例)
import string
samples = ['The cat sat on the mat.', 'The dog ate my homework.'] 
characters = string.printable
token_index = dict(zip(range(1, len(characters) + 1), characters))
max_length = 50
results = np.zeros((len(samples), 
                    max_length, 
                    max(token_index.keys()) + 1)) 
for i, sample in enumerate(samples):
    for j, character in enumerate(sample): 
        index = token_index.get(character) 
        results[i, j, index] = 1.
字符级one-hot results
#用 Keras 实现单词级的 one-hot 编码
from keras.preprocessing.text import Tokenizer
samples = ['The cat sat on the mat.', 'The dog ate my homework.']
tokenizer = Tokenizer(num_words=1000) #创建一个分词器(tokenizer),设置 为只考虑前 1000 个最常见的单词
tokenizer.fit_on_texts(samples) #构建单词索引
sequences = tokenizer.texts_to_sequences(samples) #将字符串转换为整数索引组成的列表 
one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary')
#也可以直接得到 one-hot 二进制表示。 这个分词器也支持除 one-hot 编码外 的其他向量化模式

word_index = tokenizer.word_index #找回单词索引 
print('Found %s unique tokens.' % len(word_index)) # 9
word_index

如果 散列空间的维度远大于需要散列的唯一标记的个数,散列冲突的可能性会减小。

#使用散列技巧的单词级的 one-hot 编码(简单示例)
samples = ['The cat sat on the mat.', 'The dog ate my homework.']
dimensionality = 1000 
max_length = 10
results = np.zeros((len(samples), max_length, dimensionality)) 
for i, sample in enumerate(samples):
    for j, word in list(enumerate(sample.split()))[:max_length]:
        index = abs(hash(word)) % dimensionality 
        results[i, j, index] = 1.
散列技巧的单词级的 one-hot results

使用词嵌入
将单词与向量相关联还有另一种常用的强大方法,就是使用密集的词向量(word vector),也叫词嵌入(word embedding)。


one-hot 编码或 one-hot 散列得到的词表示是稀疏的、高维的、硬编码的, 8 而词嵌入是密集的、相对低维的,而且是从数据中学习得到的

获取词嵌入的两种方法:
在完成主任务(比如文档分类或情感预测)的同时学习词嵌入。在这种情况下,一开始
是随机的词向量,然后对这些词向量进行学习,其学习方式与学习神经网络的权重相同。
在不同于待解决问题的机器学习任务上预计算好词嵌入,然后将其加载到模型中。这些 词嵌入叫作预训练词嵌入(pretrained word embedding)。

  1. 利用 Embedding 层学习词嵌入
    每个新任务都学习一个新的嵌入空间。
    Embedding 层实际上是一种字典查找:


    Embedding 层
#将一个Embedding 层实例化
from keras.layers import Embedding
embedding_layer = Embedding(1000, 64)#Embedding 层至少需要两个参数: 标记的个数(这里是 1000,即最 大单词索引 +1)和嵌入的维度(这里是 64)
#加载 IMDB 数据,准备用于 Embedding 层
from keras.datasets import imdb
import keras.preprocessing as preprocessing
max_features = 10000 
maxlen = 20
(x_train, y_train), (x_test, y_test) = imdb.load_data( num_words=max_features) 
x_train = preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen) 
x_test = preprocessing.sequence.pad_sequences(x_test, maxlen=maxlen)

#在 IMDB 数据上使用 Embedding 层和分类器
from keras.models import Sequential
from keras.layers import Flatten, Dense, Embedding
model = Sequential()
model.add(Embedding(10000, 8, input_length=maxlen))
model.add(Flatten()) #将三维的嵌入张量展平成形状为 (samples, maxlen * 8) 的二维张量
model.add(Dense(1, activation='sigmoid')) #在上面添加分类器 
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
model.summary()
history = model.fit(x_train, y_train, epochs=10,batch_size=32, validation_split=0.2)

model.summary()

使用预训练的词嵌入

#处理 IMDB 原始数据的标签
#处理原始数据标签
import os
imdb_dir = '/Users/***/Desktop/learning_log/net_work/aclImdb' 
train_dir = os.path.join(imdb_dir, 'train')
labels = []
texts = []
for label_type in ['neg', 'pos']:
    dir_name = os.path.join(train_dir, label_type) 
    for fname in os.listdir(dir_name):
        if fname[-4:] == '.txt':
            f = open(os.path.join(dir_name, fname)) 
            texts.append(f.read())
            f.close()
            if label_type == 'neg':
                labels.append(0) 
            else:
                labels.append(1)
#对原始数据的文本进行分词
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences 
import numpy as np
maxlen = 100 #在 100 个单词后截断评论 
training_samples = 200 #在 200 个样本上训练 
validation_samples = 10000 #在 10 000 个样本上验证 
max_words = 10000 #只考虑数据集中前 10 000 个最常见的单词
tokenizer = Tokenizer(num_words=max_words) 
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)
word_index = tokenizer.word_index
print('Found %s unique tokens.' % len(word_index))
data = pad_sequences(sequences, maxlen=maxlen)
labels = np.asarray(labels)
print('Shape of data tensor:', data.shape) 
print('Shape of label tensor:', labels.shape)
indices = np.arange(data.shape[0]) 
np.random.shuffle(indices)
data = data[indices]
labels = labels[indices]
x_train = data[:training_samples]
y_train = labels[:training_samples]
x_val = data[training_samples: training_samples + validation_samples] 
y_val = labels[training_samples: training_samples + validation_samples]
print

#GloVe 词嵌入  2014 年英文维基百科的预计算嵌入
#对嵌入进行预处理

#解析 GloVe 词嵌入文件
glove_dir = '/Users/fanhua/Desktop/learning_log/net_work/glove.6B'
embeddings_index = {}
f = open(os.path.join(glove_dir, 'glove.6B.100d.txt')) 
for line in f:
    values = line.split()
    word = values[0]
    coefs = np.asarray(values[1:], dtype='float32')
    embeddings_index[word] = coefs 
f.close()
print('Found %s word vectors.' % len(embeddings_index))

#准备 GloVe 词嵌入矩阵
embedding_dim = 100
embedding_matrix = np.zeros((max_words, embedding_dim)) 
for word, i in word_index.items():
    if i < max_words:
        embedding_vector = embeddings_index.get(word) 
        if embedding_vector is not None:
            embedding_matrix[i] = embedding_vector
found
#定义模型
from keras.models import Sequential
from keras.layers import Embedding, Flatten, Dense 
model = Sequential()
model.add(Embedding(max_words, embedding_dim, input_length=maxlen)) 
model.add(Flatten())
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.summary()
model
#在模型中加载 GloVe 嵌入
#将预训练的词嵌入加载到 Embedding 层中
model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable = False


#训练和评估
model.compile(optimizer='rmsprop', loss='binary_crossentropy',metrics=['acc']) 
history = model.fit(x_train, y_train,epochs=10,batch_size=32, validation_data=(x_val, y_val))
model.save_weights('pre_trained_glove_model.h5')
train
#绘制结果
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)
plt.plot(epochs, acc, 'bo', label='Training acc') 
plt.plot(epochs, val_acc, 'b', label='Validation acc') 
plt.title('Training and validation accuracy') 
plt.legend()

使用预训练词嵌入的精度和损失
#在不使用预训练词嵌入的情况下,训练相同的模型
from keras.models import Sequential
from keras.layers import Embedding, Flatten, Dense
model = Sequential()
model.add(Embedding(max_words, embedding_dim, input_length=maxlen)) 
model.add(Flatten())
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.summary()
model.compile(optimizer='rmsprop', loss='binary_crossentropy',
metrics=['acc']) 
history = model.fit(x_train, y_train,epochs=10,batch_size=32, validation_data=(x_val, y_val))
model

train
不使用预训练的精度和损失
#对测试集数据进行分词
test_dir = os.path.join(imdb_dir, 'test')
labels = []
texts = []
for label_type in ['neg', 'pos']:
    dir_name = os.path.join(test_dir, label_type)
    for fname in sorted(os.listdir(dir_name)): 
        if fname[-4:] == '.txt':
            f = open(os.path.join(dir_name, fname)) 
            texts.append(f.read())
            f.close()
            if label_type == 'neg':
                labels.append(0) 
            else:
                labels.append(1)
sequences =tokenizer.texts_to_sequences(texts)
x_test = pad_sequences(sequences, maxlen=maxlen) 
y_test = np.asarray(labels)
model.load_weights('pre_trained_glove_model.h5')
model.evaluate(x_test, y_test)
测试集模型评估

循环神经网络

循环网络

循环神经网络(RNN,recurrent neural network)处理序列的方式是,遍历所有序列元素,并保存一个状态(state),其中包含与已查看内容相关的信息。实际上,RNN 是一类具有内部环的神经网络。在处理两个不同的独立序列(比如两条不同的 IMDB 评论)之间,RNN 状态会被重置,因此,你仍可以将一个序 列看作单个数据点,即网络的单个输入。真正改变的是,数据点不再是在单个步骤中进行处理, 相反,网络内部会对序列元素进行遍历。

#简单 RNN 的 Numpy 实现
import numpy as np
timesteps=100 #输入序列的时间步数
input_features=32 #输入特征空间维度
output_features=64 #输出特征空间维度
inputs=np.random.random((timesteps,input_features))#随机噪声
state_t=np.zeros((output_features,))#初始状态,全0向量

#随机变量权重矩阵
W=np.random.random((output_features,input_features))
U=np.random.random((output_features,output_features))
b=np.random.random((output_features,))

successive_outputs=[]
for input_t in inputs:
    #由输入和当前状态(前一个输出)计算得到当前输出
    output_t=np.tanh(np.dot(W,input_t)+np.dot(U,state_t)+b)
    
    successive_outputs.append(output_t)#存储输出
    state_t=output_t #更新网络状态,用于下一个时间步

    
#输出(timesteos,output_features)的二维向量
final_output_sequence=np.stack(successive_outputs,axis=0)

RNN,沿时间展开

keras中的循环层

from keras import Sequential
from keras.layers  import Embedding
from keras.layers.recurrent import SimpleRNN
model=Sequential()
model.add(Embedding(1000,32))
model.add(SimpleRNN(32))
model.summary()
SimpleRNN,只返回最后一个时间步的输出
#返回完整的序列状态

model=Sequential()
model.add(Embedding(1000,32))
model.add(SimpleRNN(32,return_sequences=True))
model.summary()
完整的序列状态
#所有中间层都返回完整输出序列
model=Sequential()
model.add(Embedding(1000,32))
model.add(SimpleRNN(32,return_sequences=True))
model.add(SimpleRNN(32,return_sequences=True))
model.add(SimpleRNN(32,return_sequences=True))
model.add(SimpleRNN(32))
model.summary()
所有中间层都返回完整输出序列

将这个模型应用于IMDB电影评分模型

#准备IMDB数据
from keras.datasets import imdb
from keras.preprocessing import sequence
max_features=10000
maxlen=500
batch_size=32
print('loading data ……')
(input_train,y_train),(input_test,y_test)=imdb.load_data(num_words=max_features)
print(len(input_train),'train_sequences')
print(len(input_test),'test_sequences')
print('Pad sequences (samples x time)')
input_train = sequence.pad_sequences(input_train, maxlen=maxlen) 
input_test = sequence.pad_sequences(input_test, maxlen=maxlen) 
print('input_train shape:', input_train.shape) 
print('input_test shape:', input_test.shape)
准备数据
#用Embedding层和SimpleRNN训练网络
from keras.layers import Dense
model = Sequential() 
model.add(Embedding(max_features, 32)) 
model.add(SimpleRNN(32)) 
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', 
              loss='binary_crossentropy', 
              metrics=['acc']) 
history = model.fit(input_train,
                    y_train,
                    epochs=10, 
                    batch_size=128, 
                    validation_split=0.2)
训练
#绘制结果
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)
plt.plot(epochs, acc, 'bo', label='Training acc') 
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy') 
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss') 
plt.plot(epochs, val_loss, 'b', label='Validation loss') 
plt.title('Training and validation loss')
plt.legend()
plt.show()
精度和损失图

理解LSTM和GRU层
SimpleRNN的问题:梯度消失问题。
在时刻 t,理论上来说,它应该能够记住许多时间步之前见过的信息,但实际上它是不可能学 到这种长期依赖的。
LSTM层,长短期记忆,是SimpleRNN层的一种变体,它增加了一种携带信息跨越多个时间步的方法。它保存信息以便后面使用,从而防止较早期的信号在处理过程中逐渐消失。


讨论 LSTM 层的出发点:SimpleRNN 层

从 SimpleRNN 到 LSTM:添加一个携带轨道

剖析 LSTM
#使用keras中的LSTM
from keras.layers import LSTM
model = Sequential() 
model.add(Embedding(max_features, 32))
model.add(LSTM(32))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy',metrics=['acc'])
history = model.fit(input_train, y_train,epochs=10, batch_size=128, validation_split=0.2)
将 LSTM 应用于 IMDB 的精度和损失

循环神经网络的高级用法
循环 dropout(recurrent dropout)。在循环层中使用 dropout来降低过拟合。
堆叠循环层(stacking recurrent layers)。这会提高网络的表示能力(代价是更高的计算负荷)。
双向循环层(bidirectional recurrent layer)。将相同的信息以不同的方式呈现给循环网络,可以提高精度并缓解遗忘问题。

温度预测问题

#观察耶拿天气数据集的数据
import os
data_dir = '/users/fanhua/Downloads/jena_climate'
fname = os.path.join(data_dir, 'jena_climate_2009_2016.csv')
f = open(fname) 
data = f.read() 
f.close()
lines = data.split('\n') 
header = lines[0].split(',') 
lines = lines[1:]
print(header) 
print(len(lines))
数据
#解析数据
import numpy as np
float_data = np.zeros((len(lines), len(header) - 1)) 
for i, line in enumerate(lines):
    values = [float(x) for x in line.split(',')[1:]] 
    float_data[i, :] = values

#绘制温度时间序列
from matplotlib import pyplot as plt
temp = float_data[:, 1] # 温度(单位:摄氏度) 
plt.plot(range(len(temp)), temp)
plt.show()
绘制温度时间序列
#绘制前 10 天的温度时间序列
plt.plot(range(1440), temp[:1440])
前10天的温度
#准备数据
#数据标准化
mean = float_data[:200000].mean(axis=0) 
float_data -= mean
std = float_data[:200000].std(axis=0) 
float_data /= std
#生成时间序列样本及其目标的生成器
#python中把一边循环一边计算的机制叫做生成器(generator)。
def generator(data, lookback, delay, min_index, max_index, shuffle=False, batch_size=128, step=6):
    if max_index is None:
        max_index = len(data)-delay-1
        
    i = min_index +lookback
    while 1:
    if shuffle:  #乱序抽样
        rows = np.random.randint( min_index + lookback,max_index, size=batch_size)
    else:
        if i + batch_size >= max_index:
            i = min_index + lookback
        rows = np.arange(i, min(i + batch_size, max_index)) 
        i += len(rows)
    samples = np.zeros((len(rows), lookback // step,data.shape[-1])) #shape[-1]返回列数
    targets = np.zeros((len(rows),))
    for j, row in enumerate(rows):
        indices = range(rows[j] - lookback, rows[j], step) 
        samples[j] = data[indices]
        targets[j] = data[rows[j] + delay][1]
    yield samples, targets #yield 生成器
#准备训练生成器、验证生成器和测试生成器
lookback = 1440 step = 6
delay = 144 batch_size = 128
train_gen = generator(float_data, 
                      lookback=lookback,
                      delay=delay,
                      min_index=0, 
                      max_index=200000, 
                      shuffle=True, 
                      step=step, 
                      batch_size=batch_size)
val_gen = generator(float_data, 
                    lookback=lookback,
                    delay=delay, 
                    min_index=200001, 
                    max_index=300000, 
                    step=step, 
                    batch_size=batch_size)
test_gen = generator(float_data, 
                     lookback=lookback,
                     delay=delay,
                     min_index=300001, 
                     max_index=None, 
                     step=step, 
                     batch_size=batch_size)
val_steps = (300000 - 200001 - lookback) //batch_size#为了查看整个验证集,需要 从 val_gen 中抽取多少次
test_steps = (len(float_data) - 300001 - lookback) //batch_size#为了查看整个测试集,需要从 test_gen 中抽取多少次
steps

评估:

#平均绝对误差
#平均绝对误差MAE
def evaluate_naive_method(): 
    batch_maes = []
    for step in range(val_steps):
        samples, targets = next(val_gen) 
        preds = samples[:, -1, 1]
        mae = np.mean(np.abs(preds - targets)) 
        batch_maes.append(mae)
    print(np.mean(batch_maes))
evaluate_naive_method()
#0.2897359729905486
#将 MAE 转换成摄氏温度误差
celsius_mae = 0.29 * std[1]
#2.5672247338393395 误差较大

一种基本的机器学习方法

#训练并评估一个密集连接模型
from keras.models import Sequential 
from keras import layers
from keras.optimizers import RMSprop
model = Sequential()
model.add(layers.Flatten(input_shape=(lookback // step, float_data.shape[-1])))
model.add(layers.Dense(32, activation='relu'))
model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae') 
history = model.fit_generator(train_gen,
                              steps_per_epoch=500, 
                              epochs=20, 
                              validation_data=val_gen, 
                              validation_steps=val_steps)

绘制结果

import matplotlib.pyplot as plt
loss = history.history['loss'] 
val_loss = history.history['val_loss']
epochs = range(1, len(loss) + 1) 
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss') 
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
简单的密集连接网络在耶拿温度预测任务上的训练损失和验证损失

第一个循环网络基准

#训练并评估一个基于 GRU(门控循环单元gated recurrent unit) 的模型
from keras.models import Sequential 
from keras import layers
from keras.optimizers import RMSprop
model = Sequential()
model.add(layers.GRU(32, input_shape=(None, float_data.shape[-1]))) 
model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae') 
history = model.fit_generator(train_gen,
                              steps_per_epoch=500,
                              epochs=20, 
                              validation_data=val_gen, 
                              validation_steps=val_steps)
使用 GRU 在耶拿温度预测任务上的训练损失和验证损失

使用循环dropout降低过拟合

from keras.models import Sequential 
from keras import layers
from keras.optimizers import RMSprop
model = Sequential() 
model.add(layers.GRU(32,dropout=0.2,recurrent_dropout=0.2,input_shape=(None, float_data.shape[-1])))
model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae') 
history = model.fit_generator(train_gen,
                              steps_per_epoch=500, 
                              epochs=40, 
                              validation_data=val_gen, 
                              validation_steps=val_steps)
使用 dropout 正则化的 GRU 在耶拿温度预测任务上的训练损失和验证损失

循环层堆叠
增加网络容量的通常做法是增加每层单元数或增加层数。循环层堆叠(recurrent layer stacking)是构建更加强大的循环网络的经典方法。

#训练并评估一个使用 dropout 正则化的堆叠 GRU 模型
from keras.models import Sequential 
from keras import layers
from keras.optimizers import RMSprop
model = Sequential() 
model.add(layers.GRU(32,dropout=0.1,
                     recurrent_dropout=0.5, 
                     return_sequences=True,
                     input_shape=(None, float_data.shape[-1])))
model.add(layers.GRU(64, activation='relu', dropout=0.1,recurrent_dropout=0.5)) 
model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae') 
history = model.fit_generator(train_gen,
                              steps_per_epoch=500,
                              epochs=40, 
                              validation_data=val_gen, 
                              validation_steps=val_steps)
堆叠 GRU 网络在耶拿温度预测任务上的训练损失和验证损

使用双向RNN
RNN 特别依赖于顺序或时间,RNN 按顺序处理输入序列的时间步,而打乱时间步或反转 时间步会完全改变 RNN 从序列中提取的表示。


双向 RNN 层的工作原理
#使用逆序序列训练并评估一个 LSTM
from keras.datasets import imdb
from keras.preprocessing import sequence 
from keras import layers
from keras.models import Sequential
max_features = 10000 
maxlen = 500
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
x_train = [x[::-1] for x in x_train] #逆序
x_test = [x[::-1] for x in x_test]
x_train = sequence.pad_sequences(x_train, maxlen=maxlen) 
x_test = sequence.pad_sequences(x_test, maxlen=maxlen)
model = Sequential() 
model.add(layers.Embedding(max_features, 128)) 
model.add(layers.LSTM(32)) 
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy',metrics=['acc'])
history = model.fit(x_train, y_train, epochs=10,batch_size=128, validation_split=0.2)
使用逆序序列训练并评估一个 LSTM
#训练并评估一个双向 LSTM
model = Sequential() 
model.add(layers.Embedding(max_features, 32)) 
model.add(layers.Bidirectional(layers.LSTM(32))) 
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc']) 
history = model.fit(x_train, y_train,epochs=10, batch_size=128, validation_split=0.2)
训练并评估一个双向 LSTM
#训练一个双向 GRU
from keras.models import Sequential 
from keras import layers
from keras.optimizers import RMSprop
model = Sequential() 
model.add(layers.Bidirectional(layers.GRU(32), 
                               input_shape=(None, float_data.shape[-1]))) 
model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae')
history =model.fit_generator(train_gen, 
                             steps_per_epoch=500,
                             epochs=40, 
                             validation_data=val_gen,
                             validation_steps=val_steps)
训练一个双向 GRU

用卷积神经网络处理序列
使用一维卷积,从序列中提取局部一维序列段(即子序列),一维卷积层可以识别序列中的局部模式。

一维卷积神经网络的工作原理:每个输出时间步都是利用输入序列 在时间维度上的一小段得到的

一维可以做池化运算:从输入中提取一维序列段(即子序列), 然后输出其最大值(最大池化)或平均值(平均池化)。与二维卷积神经网络一样,该运算也是用于降低一维输入的长度(子采样)。

实现一维卷积神经网络
Keras 中的一维卷积神经网络是 Conv1D 层,其接口类似于 Conv2D。它接收的输入是形状 为 (samples, time, features) 的三维张量,并返回类似形状的三维张量。卷积窗口是时 间轴上的一维窗口(时间轴是输入张量的第二个轴)。

IMDB 情感分类任务

#准备数据
from keras.datasets import imdb
from keras.preprocessing import sequence
max_features = 10000 
max_len = 500
print('Loading data...')
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features) 
print(len(x_train), 'train sequences')
print(len(x_test), 'test sequences')
print('Pad sequences (samples x time)')
x_train = sequence.pad_sequences(x_train, maxlen=max_len) 
x_test = sequence.pad_sequences(x_test, maxlen=max_len) 
print('x_train shape:', x_train.shape)
print('x_test shape:', x_test.shape)
准备数据
#在 IMDB 数据上训练并评估一个简单的一维卷积神经网络
from keras.models import Sequential
from keras import layers
from keras.optimizers import RMSprop
model = Sequential()
model.add(layers.Embedding(max_features, 128, input_length=max_len)) 
model.add(layers.Conv1D(32, 7, activation='relu')) 
model.add(layers.MaxPooling1D(5))
model.add(layers.Conv1D(32, 7, activation='relu')) 
model.add(layers.GlobalMaxPooling1D())
model.add(layers.Dense(1))
model.summary()
model.compile(optimizer=RMSprop(lr=1e-4),
              loss='binary_crossentropy',
              metrics=['acc']) 
history = model.fit(x_train, y_train,
                    epochs=10,
                    batch_size=128, 
                    validation_split=0.2)
在 IMDB 数据上训练并评估一个简单的一维卷积神经网络
#结合 CNN 和 RNN 来处理长序列
#在耶拿数据上训练并评估一个简单的一维卷积神经网络
#效果较差
from keras.models import Sequential 
from keras import layers
from keras.optimizers import RMSprop
model = Sequential()
model.add(layers.Conv1D(32, 5, activation='relu',input_shape=(None, float_data.shape[-1]))) 
model.add(layers.MaxPooling1D(3))
model.add(layers.Conv1D(32, 5, activation='relu'))
model.add(layers.MaxPooling1D(3)) 
model.add(layers.Conv1D(32, 5, activation='relu')) 
model.add(layers.GlobalMaxPooling1D()) 
model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss='mae') 
history = model.fit_generator(train_gen,
                              steps_per_epoch=500, 
                              epochs=20, 
                              validation_data=val_gen, 
                              validation_steps=val_steps)
在耶拿数据上训练并评估一个简单的一维卷积神经网络
结合一维 CNN 和 RNN 来处理长序列
#为耶拿数据集准备更高分辨率的数据生成器
step = 3 
lookback = 720 
delay = 144
train_gen = generator(float_data, 
                      lookback=lookback,
                      delay=delay, 
                      min_index=0, 
                      max_index=200000,
                      shuffle=True,
                      step=step)
val_gen = generator(float_data, 
                    lookback=lookback,
                    delay=delay, 
                    min_index=200001, 
                    max_index=300000, 
                    step=step)
test_gen = generator(float_data, 
                     lookback=lookback,
                     delay=delay,
                     min_index=300001, 
                     max_index=None, 
                     step=step)
val_steps = (300000 - 200001 - lookback) //128   #为了查看整个验证集,需要 从 val_gen 中抽取多少次
test_steps = (len(float_data) - 300001 - lookback) //128   #为了查看整个测试集,需要从 test_gen 中抽取多少次
step
#结合一维卷积基和 GRU 层的模型
from keras.models import Sequential
from keras import layers
from keras.optimizers import RMSprop
model = Sequential()
model.add(layers.Conv1D(32, 5, 
                        activation='relu',
                        input_shape=(None, float_data.shape[-1]))) 
model.add(layers.MaxPooling1D(3))
model.add(layers.Conv1D(32, 5, activation='relu')) 
model.add(layers.GRU(32, dropout=0.1, recurrent_dropout=0.5)) 
model.add(layers.Dense(1))
model.summary()
model.compile(optimizer=RMSprop(), loss='mae') 
history = model.fit_generator(train_gen,
                              steps_per_epoch=500, 
                              epochs=20, 
                              validation_data=val_gen,
                              validation_steps=val_steps)
model.summary()

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

推荐阅读更多精彩内容