主要使用tensorflow.keras.preprocessing这个库中的(image, text,sequence)这三个模块。
text: 能够用来 (统计词频,分字,word_2_id, id_2_word等操做。)
sequence 能够(给句子作结构化操做(填充0,裁剪长度))git
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也写出来。github
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 # 同上 )
语言不一样,那么咱们能够搭建桥梁。 即便咱们表面上不相同。 可是咱们映射到这个桥梁上的结果是几乎相似的。
为何每一个句子的长度须要统一?算法
由于,每一个句子for循环操做会很耗算力, 而转化为矩阵/向量化操做,会节约太多算力。 由于矩阵运算严格要求样本的形状,因此每一个句子的长度须要一致
如何作到句子长度统一?函数
填0, 对应TF操做就是padding, 不过TF20 的keras预处理包中已经有 成品的数据统一化操做。 而且还具备 word_2_id,词向量编码操做。
其中解码器部分的输出y会用 softmax 对 词库(词典)求多分类几率。
而后求损失(MSE或者CrossEntropy)
注意了: softmax求出的几率该如何选择,这是个问题:post
假如: 每一个单元的输出y的几率都取最大值, 那么可能一步错,步步错。 太极端了(贪心搜索) 接下来,聊一聊一周 集束搜索的算法 BeamSearch
因为贪心搜索(只取几率的一个最大值,的结果不尽人意。因此 BeamSearch来啦)
BeamSearch的主要思想:编码
只取一个太冒险了,因此: BeamSearch 取每一个通过softmax输出几率集合的 Top-N个 Top-N: 的 N 表明你保留几个几率 (触类旁通理解: 贪心算法就是 Top-1) 假如咱们取Top-3个 那么你一个RNN节点的预测y将会保留3个几率值, 并将这3个几率值做为 下一个节点的输入。 具体流程看:下图 (可能有点丑) 而后,咱们会选择出: 3 个 "红线" 最优路径。 最终: 咱们经过单独的语言模型,来从这 3 个 "红线" 较优路径中,选出一个 最优路径。
Seq2Seq 的 Encoder部分虽然用的是 高效的 LSTM,而且也很好的解决了,记忆的问题。
可是他不能很好的解决每一个单词的权重分配问题。spa
虽然: Encoder的全部单元都会经过LSTM的记忆传递, 输入进“中间桥梁向量”。 可是: 仍是有"偏爱"成分, 最后一个LSTM单元信息必定是最浓的。 (新鲜的,热乎的) 因此: 你第1个LSTM单元的信息,或者说前面的LSTM单元的信息,这些记忆到最后可能会被稀释。
为了解决上面的问题, Attention就出来帮忙了~~~3d
我以为墨迹半天不如本身画一张图~~~ (只会mspaint画图)
上图中计算权重那里"经过一个函数,能够是求类似度", 我简写了。 其实有两种经常使用的方式:rest
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 )
第一印象挑明: 他是一种无RNN的一种特殊的 Seq2Seq 模型。code
RNN-LSTM-GRU虽然这些NN的主要特点就是"时间序列"。(缺点:慢,记忆弥散)
可是咱们上面说了,要想取得好的效果。那么须要加Attention。
因而有人想到了,既然Attention效果这么好,为何不直接用Attention呢?
Attention效果虽好,关联性强,可是它不能保证时间序列模式。
因而后来出现了 Transformer。(既能保证记忆注意力,又能保证时间序列)。具体以下!
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 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] 可理解为,多个卷积核的意思能提取不一样特征的意思。
上述的self-attention有个问题, 咱们没有用到RNN等序列NN,那么矩阵相乘的过程当中。
单词的计算顺序多是不一样的。
那么如何保证让他们位置有条不紊?
可使用位置编码,融入到Embedding,造成带有时间序列性质的模型。
可自行查找计算位置编码的博文。
至于Transformer,如今官方已经有TF20和Pytorch的库了。
传送门以下。
https://github.com/huggingface/transformers
Transformer延申的各类模型,像Bert等也有可调用的API
https://huggingface.co/transformers/