学习目标:
学习使用tensorflow来对文本进行感情分类
学习内容:
先学习基础的知识
文本数据预处理
学习文本数据的预处理
官方文本处理教程
#%%
import tensorflow as tf
import tensorflow_datasets as tfds
import os
#%%
#原始数据的加载和标记
#TextLineDataset来读取一行一行是数据,并进行编码标记
#主要使用TextLineDataset这个类型的数据,内部的方法map、shuffle、concatenate(水平链接)、zip(竖着切一刀后链接)
def labeler(example, index):
return example, tf.cast(index, tf.int64)
labeled_data_sets = []
FILE_NAMES = ['cowper.txt', 'derby.txt', 'butler.txt']
parent_dir = "./"
for i, file_name in enumerate(FILE_NAMES):
#TextLineDataset将指定的文件按行读取形成一个列表,一行为一个元素。
lines_dataset = tf.data.TextLineDataset(os.path.join(parent_dir, file_name))
#调用map方法,可以传入一个函数,使用lambda表达式,可以将所有数据依次加工返回新的数据格式
labeled_dataset = lines_dataset.map(lambda ex: labeler(ex, i))
labeled_data_sets.append(labeled_dataset)
#%%
#进行数据混淆
# 将所有的标记好的数据((),())弄成这个格式后,进行混淆形成训练集合和测试集
BUFFER_SIZE = 50000
BATCH_SIZE = 64
TAKE_SIZE = 5000
all_labeled_data = labeled_data_sets[0]
for labeled_dataset in labeled_data_sets[1:]:
all_labeled_data = all_labeled_data.concatenate(labeled_dataset)
print(all_labeled_data)
all_labeled_data = all_labeled_data.shuffle(
BUFFER_SIZE, reshuffle_each_iteration=False)
#%%
#数据打印
for ex in all_labeled_data.take(5):
print(ex)
#%%
#一个读取一个TextLineDataset里的数据
# example_text = next(iter(all_labeled_data))[0].numpy()#使用一个迭代器来对数据进行编码
# print(example_text)
# GB = (tf.data.Dataset.range(1, 5, output_type=tf.int32)
# .map(lambda x: tf.fill([x], x)))
# for element in GB.as_numpy_iterator():
# print(element)
#%%
# tokenizer.tokenize一个分词工具,将句子分成一个个的单词,使用set无重复的集合将单词存放
tokenizer = tfds.features.text.Tokenizer()
vocabulary_set = set()
for text_tensor, _ in all_labeled_data:
some_tokens = tokenizer.tokenize(text_tensor.numpy())
vocabulary_set.update(some_tokens)
vocab_size = len(vocabulary_set)
vocab_size
#%%
#进行样本编码
encoder = tfds.features.text.TokenTextEncoder(vocabulary_set)
def encode(text_tensor, label):
encoded_text = encoder.encode(text_tensor.numpy())
return encoded_text, label
def encode_map_fn(text, label):
# py_func doesn't set the shape of the returned tensors.
encoded_text, label = tf.py_function(encode,
inp=[text, label],
Tout=(tf.int64, tf.int64))
# `tf.data.Datasets` work best if all components have a shape set
# so set the shapes manually
# shape值(2,),意思是一维数组,数组中有2个元素。:
encoded_text.set_shape([None])
# shape=(),单个数据,进入数组
label.set_shape([])
return encoded_text, label
all_encoded_data = all_labeled_data.map(encode_map_fn)
next(iter(all_encoded_data))
#%%
#对数据集划分
train_data = all_encoded_data.skip(TAKE_SIZE).shuffle(BUFFER_SIZE)
# 根据最大的长度自动填充或者指定长度来填充,bathcsize填充完后自动进行batch分组
train_data = train_data.padded_batch(BATCH_SIZE)
test_data = all_encoded_data.take(TAKE_SIZE)
test_data = test_data.padded_batch(BATCH_SIZE)
#%%
sample_text, sample_labels = next(iter(test_data))
sample_text.shape
具体的代码都配有注释进行解释,总结来说就是将所有的句子都读入内存,然后提取所有的不重复单词进行编码,编码完后对原来的句子使用编码进行重塑,让每个句子都用数字表示出来。然后将所有的句子长度对齐后随机打乱,形成bathcsize个数据集合(细分为测试集验证集合)。
有了这个例子,以后我们就可以将自己的数据集按照这个步骤进行自己的数据集处理啦哈哈
模型的构建
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
physical_devices = tf.config.experimental.list_physical_devices('GPU')
assert len(physical_devices) > 0, "Not enough GPU hardware devices available"
tf.config.experimental.set_memory_growth(physical_devices[0], True)
model = keras.Sequential()
model.add(layers.Embedding(input_dim=1000, output_dim=64))
# Add a LSTM layer with 128 internal units.
model.add(layers.LSTM(128))
# Add a Dense layer with 10 units.
model.add(layers.Dense(10))
model.summary()
模型代码虽然简单但是模型参数和结构不好理解
- embedding层的解释
- embeding层可以随机生成一个指定大小的矩阵,这个矩阵input_dim代表的是你的数据里面一共有的词的个数,output_dim代表你想让几维的矩阵来表示一个词一般是50,100。
- embeding层放第一层,感觉和输入的数据没啥关系。其实embeding层会根据上面你编码好的句子来自动匹配对应序号的向量。比如你句子编号为【2,3,4.,0,0】那么输入到embeding层后数据就会生成为
【
【0.2,0.6,0.7】
【0.4,0.6,0.7】
【0.3,0.6,0.7】
【0.1,0.6,0.7】
【0.2,0.8,0.7】
】
分别对应了embeding层的 2行,3行,4行,0行的矩阵。
然后数据这样就算被过滤了,被重新编码形成矩阵表示的句子,被挨批输入到LSTM里面了
- layers.LSTM(128)的解释:
- 括号里的默认参数是units:是输出的维度。 在下图中,中间的绿色cell 里面有四个黄色小框,每一个小黄框代表一个前馈网络层,对,就是经典的神经网络的结构,num_units就是这个层的隐藏神经元个数,就这么简单。其中1、2、4的激活函数是 sigmoid,第三个的激活函数是 tanh。
- return_sequences: 如果为True的话,只返回最后一个状态的输出,是一个(samples,output_dim)2D张量,如果是False,则是返回所有序列状态的输出,是一个(samples,timesteps,output_dim)3D张量。
- input_shape:形如(samples,timesteps,input_dim)的3D张量,其中samples是样本个数,timesteps是每个样本的状态序列个数,input_dim是每个状态下的特征数,在实体标注任务当中,假如有10000个句子,每个句子由10个词组成,每个词被映射为100维的词向量。那么输出的格式就为(10000,10,100)。也就是说每个样本中的10个词就是一组序列,每个词都和前后的词有关系。
根据这个实例可以看出不用指定也可以自动识别出数据的格式
学习文本感情分类
官方感情分类实例
windwos电脑下用GPU运行可以出现内存分配用完的情况,查了半天没找到办法呀,GPU的CUDA配置都没问题可以用,网上的解决方案不行都,最后打算重装tf试试? 算了以后再说先用colab吧.这个真香,有免费GPU用就用了这个,顺利运行了代码.
import tensorflow as tf
from tensorflow.python.client import device_lib
print(device_lib.list_local_devices())
import tensorflow_datasets as tfds
dataset, info = tfds.load('imdb_reviews/subwords8k', with_info=True,as_supervised=True)
train_dataset, test_dataset = dataset['train'], dataset['test']
BUFFER_SIZE = 10000
BATCH_SIZE = 64
encoder = info.features['text'].encoder
train_dataset = train_dataset.shuffle(BUFFER_SIZE)
train_dataset = train_dataset.padded_batch(BATCH_SIZE)
test_dataset = test_dataset.padded_batch(BATCH_SIZE)
encoder = info.features['text'].encoder
model = tf.keras.Sequential([
tf.keras.layers.Embedding(encoder.vocab_size, 64),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64, return_sequences=True)),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(1)
])
model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
optimizer=tf.keras.optimizers.Adam(1e-4),
metrics=['accuracy'])
history = model.fit(train_dataset, epochs=5,
validation_data=test_dataset,
validation_steps=30)
test_loss, test_acc = model.evaluate(test_dataset)
print('Test Loss: {}'.format(test_loss))
print('Test Accuracy: {}'.format(test_acc))
数据处理方面根据预处理步骤我们已经知道了如何做了,这里官方已经将数据进行了编码我们只需要进行打包形成batch数据格式就可以了
模型方面很重要:1.一个是嵌入层,依然了解到了,第一个参数是编码的数据集大小,第二个参数是自己想要的数据大小
2.重点是LSTM层。
- LSTM层的输入是每一个时间步的数据,输出一个对应的矩阵向量。关于tf.keras.layers.LSTM的使用参考官方说明如下:
pythoninputs = tf.random.normal([32, 10, 8])
lstm = tf.keras.layers.LSTM(4)
output = lstm(inputs)
print(output.shape)
lstm = tf.keras.layers.LSTM(4, return_sequences=True, return_state=True)
whole_seq_output, final_memory_state, final_carry_state = lstm(inputs)
print(whole_seq_output.shape)
print(final_memory_state.shape)
print(final_carry_state.shape)
- 根据官方教程可以知道LSTM(N)里面的N代表了输出参数的维度
- inputs: A 3D tensor with shape [batch, timesteps, feature] 输入数据格式为时间步骤为行数就是句子单词个数,列表示特征个数,会按行进行输入的.
- return_sequences=true表示返回了所有的时间步骤返回的结果H(参数命名参考上图),而final_memory_state代表了最后一个返回矩阵,final_carry_state代表了最后一个返回的状态值S
3.关于分类问题,这里是二分类使用的一个神经元用sigmoal进行了激活达到二分类问题,可以考虑使用softmax来进行分析.注意使用softmax要更改一下我们的损失函数
model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), optimizer=tf.keras.optimizers.Adam(1e-4), metrics=['accuracy'])
总结
数据处理形成测试集和训练集合
- 对于文本数据使用tensorflow_datasets 这样一个数据结构来吧数据存起来,按元组村((data),(label))
- 使用encoder进行编码data
- 使用skip,map,shuffle,padded_batch来操作数据形成训练数据具体请见官方API
构建模型
- 明白LSTM的这个函数的各种参数
- softmax和单一节点进行训练时候要选用不同的激活函数奥
学习时间:
1、2020-10-31:周六晚上8点
2、2020-10-31:周六晚上7点