本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.
数据预处理(TF20-Keras-Preprocessing)
我们自己的普通数据集(常用)
主要使用tensorflow.keras.preprocessing这个库中的(image, text,sequence)这三个模块。
text: 可以用来 (统计词频,分字,word_2_id, id_2_word等操作。)
sequence 可以(给句子做结构化操作(填充0,裁剪长度))
from tensorflow.keras.preprocessing.text import Tokenizer # 主干,句子编码 from tensorflow.keras.preprocessing.sequence import pad_sequences # 辅助,填充,剪枝 q1 = '欢 迎 你 你 你' q2 = '我 很 好' q_list = [q1,q2] # 需要特别注意,因为此API对英文友好,所以,我们必须把句子用 空格 隔开输入 token = Tokenizer( num_words=2, # num_words代表设置过滤num_words-1个词频, 例如num_words=2, # 那幺过滤掉2-1=1个词频, 所以一会你会看到下面词频为1的都被过滤掉了 ) # 这里面参数很多,还有标点符号过滤器等 token.fit_on_texts(q_list) # 把原始句子集合,放进去拟合一下(封装成一个类) print(token.document_count) # 2 # 句子个数 print(token.word_index) # {'你': 1, '欢': 2, '迎': 3, '我': 4, '很': 5, '好': 6} # word_2_id print(token.index_word) # {1: '你', 2: '欢', 3: '迎', 4: '我', 5: '很', 6: '好'} # id_2_word print(token.word_counts) # OrderedDict([('欢', 1), ('迎', 1), ('你', 3), ('我', 1), ('很', 1), ('好', 1)]) # 统计词频 seq = token.texts_to_sequences(q_list) # 先把所有的输入,变成一一变成编码化 print(seq) # [[1, 1, 1], []] # 会不会好奇?数据怎幺没了?因为我们上面设置了过滤词频为1的都过滤了 pad_seq = pad_sequences( seq, # 输入编码化后的 句子 maxlen=2, # 统一句子最大长度 padding='pre', # 不足的补0, 从前面补0, (也可以用 post,代表后面) truncating='pre' # 多余的长度裁剪,从前面裁剪 ) print(pad_seq) # 打印一下我们填充后的句子形状。 # [ # [1 1], # 如你所愿,最大长度为2,[1,1,1] 已经裁剪成了 [1,1] # [0 0], # 如你所愿,之前[] ,已经都填满了0 # ]
虽然我们用不到 image这个模块数据增强模块,但是我把了解的API也写出来。
train_datagen = keras.preprocessing.image.ImageDataGenerator( # 数据增强生成器(定义) rescale=1. / 255, # 数据归一化 rotation_range = 40, # -40-40 随机角度 (数据增强) width_shift_range = 0.2, # 宽度位移(0-20%随机选个比例去平移) (数据增强) height_shift_range = 0.2, # 高度位移(同上) (数据增强) shear_range=0.2, # 图片剪切(0.2) (数据增强) zoom_range=0.2, # 图片缩放(0.2) (数据增强) horizontal_flip=True, # 图片随机水平反转 (数据增强) fill_mode='nearest', # 图片填充像素(放大后失帧)用附近像素值来填充 (数据增强) ) # train_generator = train_datagen.flow_from_dataframe() # 如果你用Pandas,你可以选这个 train_generator = train_datagen.flow_from_directory( # 从文件中读取(Kaggle) train_dir, # 图片目录 target_size = (height, width), # 图片读取进来后缩放大小 batch_size = batch_size, # 就是批次 seed=6, # 随机化种子 shuffle=True, # 样本随机打散训练,增强模型泛化能力 class_mode='categorical', # label格式,是否需要one_hot, 是 ) ... ... train_num = train_generator.samples # 打印样本形状 history = model.fit_generator( # 注意我们上面是用的数据生成器,所以这要用 fit_generator train_generator, steps_per_epoch=train_num//batch_size, # 每个epoch多少 step(因为数据增强API是生成器方式,所以需要自己手动计算一下) epochs=epochs, validation_data=valid_generator, # 如果你有验证集,你也可以用这个。否则可以不用 validation_steps=valid_num//batch_size # 同上 )
Seq2Seq
思想
语言不同,那幺我们可以搭建桥梁。 即使我们表面上不相同。 但是我们映射到这个桥梁上的结果是几乎类似的。
样本句子长度统一
为什幺每个句子的长度需要统一?
因为,每个句子for循环操作会很耗算力, 而转化为矩阵/向量化操作,会节约太多算力。 因为矩阵运算严格要求样本的形状,所以每个句子的长度需要一致
如何做到句子长度统一?
填0, 对应TF操作就是padding, 不过TF20 的keras预处理包中已经有 成品的数据统一化操作。 并且还具有 word_2_id,词向量编码操作。
组成
-
- 编码器 (输入每条样本句子的每个单词, 编码器的最后一个RNN单元,浓缩了整个句子的信息)
-
- 中间向量 (作为中间特征桥梁, 用来保存,输入进来的整个句子)
-
- 解码器 (中间向量作为解码器第一个RNN单元的输入,而每个单元的输出y,作为下一个单元的输入)
其中解码器部分的输出y会用 softmax 对 词库(词典)求多分类概率。
然后求损失(MSE或者CrossEntropy)
注意了: softmax求出的概率该如何选择,这是个问题:
假如: 每个单元的输出y的概率都取最大值, 那幺可能一步错,步步错。 太极端了(贪心搜索) 接下来,聊一聊一周 集束搜索的算法 BeamSearch
BeamSearch
由于贪心搜索(只取概率的一个最大值,的结果不尽人意。所以 BeamSearch来啦)
BeamSearch的主要思想:
只取一个太冒险了,所以: BeamSearch 取每个经过softmax输出概率集合的 Top-N个 Top-N: 的 N 代表你保留几个概率 (举一反三理解: 贪心算法就是 Top-1) 假如我们取Top-3个 那幺你一个RNN节点的预测y将会保留3个概率值, 并将这3个概率值作为 下一个节点的输入。 具体流程看:下图 (可能有点丑) 然后,我们会选择出: 3 个 "红线" 最优路径。 最终: 我们通过单独的语言模型,来从这 3 个 "红线" 较优路径中,选出一个 最优路径。
Attention(注意力机制)
前情回顾
Seq2Seq 的 Encoder部分虽然用的是 高效的 LSTM,并且也很好的解决了,记忆的问题。
但是他不能很好的解决每个单词的权重分配问题。
虽然: Encoder的所有单元都会通过LSTM的记忆传递, 输入进“中间桥梁向量”。 但是: 还是有"偏心"成分, 最后一个LSTM单元信息一定是最浓的。 (新鲜的,热乎的) 所以: 你第1个LSTM单元的信息,或者说前面的LSTM单元的信息,这些记忆到最后可能会被稀释。
为了解决上面的问题, Attention就出来帮忙了~~~
Attentioin原理
我觉得墨迹半天不如自己画一张图~~~ (只会mspaint画图)
上图中计算权重那里”通过一个函数,可以是求相似度”, 我简写了。 其实有两种常用的方式:
Bahdanau注意力: weight = FC层( tanh ( FC层(Encoder的每个输出y) + FC层(Decoder的一个H) ) ) luong注意力: weight = Encoder的每个输出y @ W随机权重矩阵 @ Decoder的一个H # @是TF20的矩阵乘法操作符 无论使用上面哪种: 都要套一层 Softmax weight = softmax(weight, axis=1) 注意力向量C = sum( weight * Encoder的每个输出y , axis=1) # 加权求和,最终得到一个向量 Decoder的下一个输入 = concat( 注意力向量C, 上一个预测y4 )
Transformer
第一印象挑明: 他是一种无RNN的一种特殊的 Seq2Seq 模型。
RNN-LSTM-GRU虽然这些NN的主要特色就是”时间序列”。(缺点:慢,记忆弥散)
但是我们上面说了,要想取得好的效果。那幺需要加Attention。
于是有人想到了,既然Attention效果这幺好,为什幺不直接用Attention呢?
Attention效果虽好,关联性强,但是它不能保证时间序列模式。
于是后来出现了 Transformer。(既能保证记忆注意力,又能保证时间序列)。具体如下!
Transformer整体结构组成
Self-Attention
self-attention原理就是各种链式矩阵乘法(并行计算,可用GPU加速)
self-attention计算过程如下:(假设输入句子切分单词为:矩阵X = [“早”,”上”,”好”])
矩阵X @ 权重矩阵Q(Q1,Q2,Q3)=> Q矩阵(Q1,Q2,Q3) 矩阵X @ 权重矩阵K(Q1,Q2,Q3)=> K矩阵(Q1,Q2,Q3) 矩阵X @ 权重矩阵V(Q1,Q2,Q3)=> V矩阵(Q1,Q2,Q3) α = softmax( (Q矩阵 @ K矩阵) / q^0.5 ) self_attention = α @ V矩阵
Multi-Head Self-Attention
Multi-Head Attention 对 Self-Attention 对了如下扩展:
self-attention: 一组 Q矩阵,K矩阵,V矩阵 Multi-Head Self-Attention: 多组 Q矩阵,K矩阵,V矩阵 扩张为多头注意力的过程: Q @ W ====> [Q1, Q2, Q3] K @ W ====> [K1, K2, K3] V @ W ====> [V1, V2, V3] 可理解为,多个卷积核的意思能提取不同特征的意思。
Position Encoder
上述的self-attention有个问题, 我们没有用到RNN等序列NN,那幺矩阵相乘的过程中。
单词的计算顺序可能是不同的。
那幺如何保证让他们位置有条不紊?
可以使用位置编码,融入到Embedding,形成带有时间序列性质的模型。
可自行查找计算位置编码的博文。
传送门
至于Transformer,现在官方已经有TF20和Pytorch的库了。
传送门如下。
https://github.com/huggingface/transformers
Transformer延申的各种模型,像Bert等也有可调用的API
Be First to Comment