日萌社
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)
1.接下来我们将介绍一种新的技巧,取代之前我们熟悉的使用贪心算法从结果分布中获得最有可能的预测ID。
而此处的案例中贪心算法也即取出65个不重复字符维度中的最大概率值的索引值,该索引值便对应的字符。
2.tf.random.categorical
从理论上来讲,如果模型足够准确,我们只需要从概率分布中选择概率最大的值的索引即可,这就是贪心算法。
但在实际中,模型的预测效果很难确定,一直按照最大概率选取很容易陷入重复的循环中,
因此会将分布的概率值作为其被选中的概率值,这样每个分布中的值都有可能被选中,
tensorflow中使用tf.random.categorical方法来实现.
3.tf.random.categorical(logits, num_samples, dtype=None, seed=None, name=None)
参数:
logits:具有形状的二维张量[批量大小,类别数] 即[batch_size, num_classes]。每个切片[i,:]表示所有类别的非归一化的记录概率。
num_samples:代表数量样本,值为0维,即单个数值,该数值代表每行切片中绘制的独立样本数
返回值:所绘制的形状样本[batch_size, num_samples] 即 [批量大小,数量样本]。
>>> tf.math.log([[0.5, 0.5]])
<tf.Tensor: id=11, shape=(1, 2), dtype=float32, numpy=array([[-0.6931472, -0.6931472]], dtype=float32)>
>>> #返回值具有形状[1,5],即[批量大小batch_size, num_samples数量样本],其中每个值以相等的概率为0或1
>>> samples = tf.random.categorical(tf.math.log([[0.5, 0.5]]), 5)
>>> samples
<tf.Tensor: id=3, shape=(1, 5), dtype=int64, numpy=array([[0, 0, 1, 0, 0]], dtype=int64)>
>>> #返回值具有形状[1,1],即[批量大小batch_size, num_samples数量样本],其中每个值以相等的概率为0或1
>>> samples = tf.random.categorical(tf.math.log([[0.5, 0.5]]), 1)
>>> samples
<tf.Tensor: id=7, shape=(1, 1), dtype=int64, numpy=array([[1]], dtype=int64)>
sampled_indices = tf.random.categorical(example_batch_predictions[0], num_samples=1)
1.即把 [句子长度(句子单词数), 65个不重复字符的概率值的维度]的输入 转换为 [句子长度(句子单词数), 1]的输出。
65个类别字符的概率值取出一个类别字符的索引值。
2.example_batch_predictions:(64, 100, 65) 即[批量大小, 句子长度(句子单词数), 65个不重复字符的概率值的维度]
example_batch_predictions[0]:表示取第一个样本句子,即(100, 65) 即[句子长度(句子单词数), 65个不重复字符的概率值的维度]
num_samples=1:代表数量样本,值为0维,即单个数值,该数值代表每行切片中绘制的独立样本数
print(example_batch_predictions[0].shape) #(100, 65) 即[句子长度(句子单词数), 65个不重复字符的概率值的维度],65即为类别数
# 使用random categorical
sampled_indices = tf.random.categorical(example_batch_predictions[0], num_samples=1)
print(sampled_indices.shape) #(100, 1) 即[句子长度(句子单词数), 1]
# squeeze表示消减一个维度
sampled_indices = tf.squeeze(sampled_indices, axis=-1).numpy()
print(sampled_indices)
# [32 21 30 26 57 6 38 58 14 35 9 22 18 3 0 50 47 10 52 10 23 41 23 4
# 29 6 61 35 25 9 41 35 56 34 9 37 11 29 20 49 13 60 36 1 1 38 61 51
# 5 47 55 10 54 29 46 18 22 1 36 28 17 52 57 27 9 43 62 0 10 9 14 60
# 4 62 64 6 55 57 23 43 24 41 46 14 28 17 38 60 62 64 34 58 24 8 61 12
# 60 16 21 38]
# 要生成的字符个数
num_generate = 1000
# 将起始字符串转换为数字(向量化)
input_eval = [char2idx[s] for s in start_string]
print("len(input_eval)", len(input_eval)) #7 。输入的为7个字符。
# 扩展维度满足模型输入要求
input_eval = tf.expand_dims(input_eval, 0)
print("input_eval.shape", input_eval.shape) # (1, 1)
# 空列表用于存储结果
text_generated = []
# 设定“温度参数”,根据tf.random_categorical方法特点,
# 温度参数能够调节该方法的输入分布中概率的差距,以便控制随机被选中的概率大小
temperature = 1.0
# 初始化模型参数
model.reset_states()
# 开始循环生成
for i in range(num_generate):
# 使用模型获得输出
predictions = model(input_eval)
# print("predictions.shape", predictions.shape) #(1, 1, 65) 即 [批量大小, 句子长度(句子单词数), 65个不重复字符的概率值的维度]
# 删除批次的维度
predictions = tf.squeeze(predictions, 0)
# print("predictions.shape", predictions.shape) #(1, 65) 即 [句子长度(句子单词数), 65个不重复字符的概率值的维度]
# 使用“温度参数”和tf.random.categorical方法生成最终的预测字符索引
#temperature = 1.0 的话,predictions / temperature 相当于 结果没有变
predictions = predictions / temperature
predicted_ids = tf.random.categorical(predictions, num_samples=1)
predicted_id = predicted_ids[-1, 0].numpy()
# print("predicted_ids.shape", predicted_ids.shape) #(1, 1)
# print("predicted_id.shape", predicted_id.shape) #() 即0维的单个数值
# print("predicted_ids", predicted_ids) #tf.Tensor([[21]], shape=(1, 1), dtype=int64) 即[[65个不重复字符中的所预测的一个字符的索引值]]
# print("predicted_id", predicted_id) #21 即取出 [[65个不重复字符中的所预测的一个字符的索引值]] 中的 索引值
# 将预测的输出再扩展维度作为下一次的模型输入
input_eval = tf.expand_dims([predicted_id], 0)
# print("input_eval.shape", input_eval.shape) #(1, 1)
# 将该次输出映射成字符存到列表中
# 将65个不重复字符中的所预测的一个字符的索引值 映射转换为 对应的 字符
text_generated.append(idx2char[predicted_id])