import tensorflow as tf
import tensorflow_datasets as tfds
import os
DIRECTORY_URL = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/'
FILE_NAMES = ['cowper.txt', 'derby.txt', 'butler.txt']
for name in FILE_NAMES:
text_dir = tf.keras.utils.get_file('E:/.keras/datasets/'+name,origin=DIRECTORY_URL+name)
parent_dir = os.path.dirname(text_dir)
print(parent_dir)
# 将文本加载到数据集中
def labeler(example, index):
return example, tf.cast(index, tf.int64)
labeled_data_sets = []
for i, file_name in enumerate(FILE_NAMES):
lines_dataset = tf.data.TextLineDataset(os.path.join(parent_dir,file_name))
labeled_datset = lines_dataset.map(lambda ex:labeler(ex, i))
labeled_data_sets.append(labeled_datset)
# 将这些标记的数据集合并到一个数据集中,然后对其进行随机化操作
BUFFER_SIZE = 50000
BATCH_SIZE = 64
TAKE_SIZE = 5000
all_labeled_data = labeled_data_sets[0]
for labeled_datset in labeled_data_sets[1:]:
all_labeled_data = all_labeled_data.concatenate(labeled_datset)
all_labeled_data = all_labeled_data.shuffle(
BUFFER_SIZE,reshuffle_each_iteration=False
)
for ex in all_labeled_data.take(5):
print(ex)
# 将文本编码成数字
# 机器学习基于的是数字而非文本,所以字符串需要被转化成数字列表
# 为了达到此目的,我们需要构建文本与整数的一一映射。
# 建立词汇表:首先,通过将文本标记为单独的单词集合来构建词汇表。
tokenizer = tfds.deprecated.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)
print(vocab_size)
# 样本编码:通过传递 vocabulary_set 到 tfds.features.text.TokenTextEncoder 来构建一个编码器。
# 编码器的 encode 方法传入一行文本,返回一个整数列表。
encoder = tfds.deprecated.text.TokenTextEncoder(vocabulary_set)
example_text = next(iter(all_labeled_data))[0].numpy()
print(example_text)
encoded_example = encoder.encode(example_text)
print(encoded_example)
# 现在,在数据集上运行编码器(通过将编码器打包到 tf.py_function 并且传参至数据集的 map 方法的方式来运行)。
def encode(text_tensor, label):
encoded_text = encoder.encode(text_tensor.numpy())
return encoded_text, label
def encode_map_fn(text, label):
encode_text, label = tf.py_function(
encode,
inp=[text, label],
Tout=(tf.int64, tf.int64)
)
encode_text.set_shape([None])
label.set_shape([])
return encode_text, label
all_encoded_data = all_labeled_data.map(encode_map_fn)
# 将数据集分割为测试集和训练集且进行分支
# 使用 tf.data.Dataset.take 和 tf.data.Dataset.skip 来建立一个小一些的测试数据集和稍大一些的训练数据集
train_data = all_encoded_data.skip(TAKE_SIZE).shuffle(BUFFER_SIZE)
train_data = train_data.padded_batch(BATCH_SIZE)
test_data = all_encoded_data.take(TAKE_SIZE)
test_data = test_data.padded_batch(BATCH_SIZE)
# test_data 和 train_data 不是( example, label )对的集合,而是批次的集合。每个批次都是一对(多样本, 多标签 ),表示为数组。
sample_text, sample_labels = next(iter(test_data))
print(sample_text[0], sample_labels[0])
# 引入了一个新的 token 来编码(填充零),因此词汇表大小增加了一个
vocab_size+=1
# 建立模型
model = tf.keras.Sequential()
# 第一层将整数表示转换为密集矢量嵌入
model.add(tf.keras.layers.Embedding(vocab_size, 64))
# 下一层是 LSTM 层,它允许模型利用上下文中理解单词含义。
# LSTM 上的双向包装器有助于模型理解当前数据点与其之前和之后的数据点的关系
model.add(tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)))
# 最后,我们将获得一个或多个紧密连接的层,其中最后一层是输出层。
# 输出层输出样本属于各个标签的概率,最后具有最高概率的分类标签即为最终预测结果。
for units in [64,64]:# 编辑‘for’行的列表去检测层的大小
model.add(tf.keras.layers.Dense(units, activation='relu'))
# 输出层。第一个参数是标签个数
model.add(tf.keras.layers.Dense(3, activation='softmax'))
# 编译模型:对于一个 softmax 分类模型来说,通常使用 sparse_categorical_crossentropy 作为其损失函数。
# 可以尝试其他的优化器,但是 adam 是最常用的。
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
# 训练模型
model.fit(train_data, epochs=3, validation_data=test_data)
eval_loss, eval_acc = model.evaluate(test_data)
print('\nEval loss:{}, Eval accuracy:{}'.format(eval_loss, eval_acc))
因为tensorflow_daatasets中的features库被禁用,所以要使用deprecated库进行操作。