<?xml version="1.0" encoding="utf-8"?>
<search>
  <entry>
    <title><![CDATA[AUC]]></title>
    <url>%2F2021%2F10%2F20%2FAUC%2F</url>
    <content type="text"><![CDATA[AUC基础AUC定义 百度百科 https://baike.baidu.com/item/AUC/19282953 AUC（Area Under Curve）被定义为ROC曲线下与坐标轴围成的面积，显然这个面积的数值不会大于1。又由于ROC曲线一般都处于y=x这条直线的上方，所以AUC的取值范围在0.5和1之间。AUC越接近1.0，检测方法真实性越高;等于0.5时，则真实性最低，无应用价值。 AUC常用的定义：随机从正样本和负样本中各选一个，分类器对于该正样本打分大于该负样本打分的概率。 从AUC 判断分类器（预测模型）优劣的标准：AUC = 1，是完美分类器。AUC = [0.85, 0.95], 效果很好AUC = [0.7, 0.85], 效果一般AUC = [0.5, 0.7],效果较低，但用于预测股票已经很不错了AUC = 0.5，跟随机猜测一样（例：丢铜板），模型没有预测价值。AUC &lt; 0.5，比随机猜测还差；但只要总是反预测而行，就优于随机猜测 AUC的计算 来自 https://zhuanlan.zhihu.com/p/360765777 label = [0, 1, 1, 0, 0, 1, 1, 1]pred = [0.3, 0.4, 0.5, 0.5, 0.5, 0.5, 0.8, 0.9] 1234567891011121314151617181920212223242526272829# -*- coding: utf-8 -*-import sys# auc count# input data: logit, label# logit and label are separated by \t, logit is sorted from small to large# Custom function: is_pospos_num = 0neg_num = 0rank = 0pos_total_rank = 0def is_pos(label): return float(label) != 0.0for line in sys.stdin: rank += 1 items = line.strip().split("\t") if len(items) != 2: continue logit, label = items if is_pos(label): pos_num += 1 pos_total_rank += rank else: neg_num += 1 print((pos_total_rank-(1+pos_num)*pos_num/2)/(pos_num*neg_num)) AUC问题拓展如果单机内存无法装下计算AUC所需的数据，请问如何解决？知道问题答案的可以与我交流，哈哈哈。 AUC的优点：“稳定性”AUC为啥对正负样本比例不敏感？AUC表示ROC曲线下方面积，而ROC横轴FPR只关注负样本，与正样本无关；纵轴TPR只关注正样本，与负样本无关。所以横纵轴都不受正负样本比例影响，积分当然也不受其影响。 AUC对均匀正负样本采样不敏感正由于AUC对分值本身不敏感，故常见的正负样本采样，并不会导致auc的变化。比如在点击率预估中，处于计算资源的考虑，有时候会对负样本做负采样，但由于采样完后并不影响正负样本的顺序分布。即假设采样是随机的，采样完成后，给定一条正样本，模型预测为score1，由于采样随机，则大于score1的负样本和小于score1的负样本的比例不会发生变化。但如果采样不是均匀的，比如采用word2vec的negative sample，其负样本更偏向于从热门样本中采样，则会发现auc值发生剧烈变化。 AUC与准确率的关系 在机器学习中AUC和accuracy有什么内在关系？AUC衡量的是一个模型的好坏，是它给所有sample排序的合理程度（是不是正确地把负例排在了正例的前面）；而accuracy衡量的是一个模型在一个特定threshold（比如，logistic regression模型在阈值1/2）下的预测准确度（是不是正确地把负例排在了阈值之前，正例排在了阈值之后）。 模型大最大值AUC 来自：多高的AUC才算高？ 结论： Max AUC的高低只和特征取值的多样性有关。 贝叶斯错误率与Max AUC有着密切的关系。由于这两个指标衡量的都是数据集中不可约错误（irreducible error），所以他们在数值上表现出了很强的相关性。 更高的Max AUC并不代表更高的真实模型AUC。虽然更高的Max AUC代表了更多的特征取值可能性，但是影响真实AUC的，还有特征的具体区分度，也就是泛化能力。 来自：乱弹机器学习评估指标AUC-AUC值本身的理论上线 启发：假设我们拥有一个无比强大的模型，可以准确预测每一条样本的概率，那么该模型的AUC是否为1呢？现实常常很残酷，样本数据中本身就会存在大量的歧义样本，即特征集合完全一致，但label却不同。因此就算拥有如此强大的模型，也不能让AUC为1.因此，当我们拿到样本数据时，第一步应该看看有多少样本是特征重复，但label不同，这部分的比率越大，代表其“必须犯的错误”越多。学术上称它们为Bayes Error Rate，也可以从不可优化的角度去理解。我们花了大量精力做的特征工程，很大程度上在缓解这个问题。当增加一个特征时，观察下时候减少样本中的BER，可作为特征构建的一个参考指标。 AUC与模型AUC提升没有带来线上效果提升原因 线下AUC提升为什么不能带来线上效果提升? 在推荐系统实践中，我们往往会遇到一个问题：线下AUC提升并不能带来线上效果提升，这个问题在推荐系统迭代的后期往往会更加普遍。在排除了低级失误bug以后，造成这个问题可能有下面几点原因： 样本 线下评测基于历史出现样本，而线上测试存在新样本。因此线下AUC提升可能只是在历史出现样本上有提升，但是对于线上新样本可能并没有效果。 历史数据本身由老模型产生，本身也是存在偏置的。 线上和线下特征不一致。例如包含时间相关特征，存在特征穿越。或者线上部分特征缺失等等。评估目标 AUC计算的时候，不仅会涉及同一个用户的不同item，也会涉及不同用户的不同item，而线上排序系统每次排序只针对同一个用户的不同item进行打分。 线上效果只跟相关性有关，是和position等偏置因素无关的。而线下一般是不同position的样本混合训练，因此线上和线下评估不对等。分布变化DNN模型相比传统模型，一般得分分布会更平滑，和传统模型相比打分布不一致。而线上有些出价策略依赖了打分分布，例如有一些相关阈值，那么就可能产生影响。这个可以绘制CTR概率分布图来检查。 那么如何解决呢？可以考虑下面的办法： 使用无偏样本作为测试集。随机样本最好，不行的话，最好不要是基于老模型产生的线上样本。 使用gauc等指标，同时从测试集中去除无点击的用户。gauc基于session进行分组。例如对于搜索业务，把一次搜索query对应的一次用户的曝光点击行为作为一个session进行计算。 相关论文An introduction to ROC analysis 相关解析 模型评价——准确率、精确率与召回率与F值、宏平均与微平均、ROC曲线与AUC值 如何理解机器学习和统计中的AUC？ AUC计算方法总结]]></content>
      <categories>
        <category>机器学习</category>
        <category>AUC</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[程序员必知：计算机是如何处理字符的？]]></title>
    <url>%2F2020%2F06%2F12%2F%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%98%AF%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%AD%97%E7%AC%A6%E7%9A%84%2F</url>
    <content type="text"><![CDATA[对于计算机是如何字符的理解难度主要来源于不同文献对字符编码概念的混淆，本文就是为了厘清字符相关概念，解决困扰程序员的字符编码、解码和乱码问题。 上图展示计算机中字符和字节的转换过程，字符在计算中有字符对应的形状、字符对应的整数值和字符对应的字节形式三种表示方法。本文讲述计算机是如何处理字符的问题，即字符这三种表示的转换过程，特别是字符的编码问题。 基本概念字符、字符表、和编码字符表以及代码点的概念如下： 字符（Character）是各种文字和符号的总称，包括各国家文字、标点符号、图形符号、数字等。 字符表（character repertoire），也称为字符集、字符库和字符列表等等，是由一个或多个确定的字符所构成的整体，即字符的集合。 【编码】字符集（Character set）是多个字符的集合，字符集种类较多，每个字符集包含的字符个数不同，常见字符集名称：ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。其实准确的应该称这些字符集为编码字符集（coded character set），因为这些字符集给其包含的每一个字符都对应了唯一确定的一个整数值，这个整数值称为代码点（code point）。 这些概念示意图如下所示： 到此你可能产生疑问，如果有了编码字符表，那么每个字符都有对应的代码点（整数值），那么计算机直接把这个代码点存起来不就行了（整数如何在计算机中存储不是本文讨论的话题），为什么还要讨论字符编码问题。原因如下： 历史遗留问题。伴随着计算机的发展不同的编码字符集相继被推出，同时期不同的国家往往产生了互不兼容的编码字符表，比如对同一个字符不同的编码字符表的代码点不一样，那么根据这些不兼容编码字符表存储的文件信息不能交互；不同时期的编码字符表虽然会考虑兼容性问题，甚至如今有了统一全世界所有字符的编码字符表Unicode，但实际使用过程中会发现每个国家真正用的上的字符相对整个编码字符表来说比例非常低，所以至今仍然有许多编码字符表在广泛的使用中，我们需要考虑不同编码表的转换问题。 如何存储代码点问题。如今全球统一的编码字符表Unicode用数字 0x0~0x10FFFF（这是整数的十六进制表示） 表示所有字符，所以最多可以容纳1114112个字符。即使有了全球统一的编码字符表，也要考虑用多少字节来存储每一个字符对应的代码点，比如为了让存储的效率更高（显然让常用字符对应的代码点小，这样用少量的字节就能存储该字符，参见哈夫曼编码），当然还有其它的编码方式，所以目前编码字符表Unicode中的字符对应的代码点有UTF-8，UTF-16和UTF-32三种不同的存储代码点的方法。 字符编码 对于字符编码理解的难度主要来源于不同文献对字符编码概念的混淆。 首先来看百度百科对字符编码的定义：字符编码（Character encoding）也称字集码，是把字符集中的字符编码为指定集合中某一对象（例如：比特模式、自然数序列、8位组或者电脉冲），以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。其中，ASCII将字母、数字和其它符号编号，并用7比特的二进制来表示这个整数。通常会额外使用一个扩充的比特，以便于以1个字节的方式存储。 根据以上字符编码的定义，就可以认为编码字符集已经对字符进行了编码（广义的编码，从编码字符表的名字也可以看出），因为每一个字符都被编码字符表编码为了唯一的整数值——代码点。而实际上我们需要解决的问题是，代码点如何转换成字节的编码问题，所以提出一个新的概念——字符编码方式（character encoding form）也称为字符编码方案（Character encoding schema），它是指将字符对应代码点转换成字节的方式或方案。很多文献将字符编码方式（character encoding form）或字符编码方案（Character encoding schema）简称为“编码”，这里的“编码”是狭义的编码。 注意：有的文献中字符集概念是指编码字符集概念，有的文件中编码字符集概念包含了字符编码方式的概念，需要根据上下文来理解，也正是这些概念的相互指代，以及混乱的简称，提高了程序员的理解难度！ 计算机处理字符的原理 上图展示了计算机处理字符的基本原理： 通过输入设备比如键盘可以将字符输入到电脑的内存中，比如输入字符C，那么通过编码字符表其实在内存中存的就是该字符对应的代码点； 内存中的字符可以通过编码字符表转换成对应的字符，然后再根据字体库输出格式化的字符（比如调整字符的大小和颜色等）； 一般本文献中所谓的字符的编码和解码其实就是指内存中的代码点与文本文件交互时的两个过程，可以按照某种编码方式把代码点编码成对应的字节也可以反过来把字节解码成对应的代码点。如果字符解码和编码的方式不兼容，那么就可能会出现乱码问题。 注意： 编码字符表的每种编码方式的具体实现都有其对应的解码方式，只要使用了兼容（放宽了要求，不一定要一一对应，因为有些编码字符表是兼容的）的编码和解码方式就可以保证代码点和字节的转换是正确的。 在不知道文件的编码方式的情况下可以通过一些字符编码检测器（比如chardet）来检测文件的文件的编码方式，进而使用其对应的解码方式正确来解码文件。 常见字符集与编码方式 常见字符集：ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。Utf-8、Utf-16等Unicode字符集的编码方式。 具体了解上述的字符集和字符编码 针对不同编程语言的字符编码问题 对于代码源文件本身也要考虑字符编码问题，比如Python可以选择Unicode字符存储为UCS-2还是UCS-4。 Java: Java字符的编码解码与乱码问题 C++: C++ 编码、字符和字符串 Python: Python字符串和编码 杂项问题Unicode字符集问题 Unicode官网 UCS-2和UCS-4]]></content>
      <categories>
        <category>编程语言</category>
      </categories>
      <tags>
        <tag>字符</tag>
        <tag>编码</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[C++编程语言基础（C++知识树）]]></title>
    <url>%2F2020%2F05%2F31%2FCPlusPlus%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80%2F</url>
    <content type="text"><![CDATA[《CPlusPlus编程语言基础》又称为“C加加知识树”、“C++知识树”，用树状思维导图的形式展现C++从业人员必备的所有C++基础知识。该资源主要参考了C++编程语言巨著《C++ Primer》、《C++ Primer Plus》以及《C++ 参考手册》的内容，并且具有学习高效、格式丰富和内容权威的优点，供C++初学者入门和C++技术人员参考。 CPlusPlus编程语言基础（C加加知识树）注释： C++是在C语言基础上开发的一种集面向对象编程、泛型编程和过程化编程于一体的编程语言，是C语言的超集。 若读者发现该作品的错误或者有自己的建议，欢迎联系作者袁宵 wangzichaochaochao@gmail.com 资源阅读/下载 本资源已经同步至GitHub，资源名：CPlusPlus-Programming-Language-Foundation，方便打包下载，欢迎Star和Fork。 在线阅读 下载 CPlusPlus编程语言基础.svg 下载svg图片版 CPlusPlus编程语言基础.emmx 下载思维导图版 CPlusPlus编程语言基础其它格式： 下载word版 下载PDF版 下载PPT版 下载Excel版 资源特色 学习高效。相比于书本以线性章节的形式，以二维图形结构式的树状思维导图的方式展示C++的知识更加生动形象，使用者更容易把握C++基础知识的宏观结构和内容，更加容易理解不同C++知识的联系和区别，更加方便使用者学习、理解和记忆C++知识。 格式丰富。《CPlusPlus编程语言基础》资源以CPlusPlus编程语言基础思维导图为核心，还辅以了相应的PDF、word、PPT和Excel版本的内容，适应于不同的使用方式。 内容权威。本资源内容主要来自C++编程语言巨著《C++ Primer》、《C++ Primer Plus》以及《C++ 参考手册》，其它参考和引用的内容都标注有出处。 资源展示思维导图版截图 word版截图 PDF版截图 PPT版截图 Excel版截图 更多资源 《C++ Primer Plus英文版（第六版）》 《CPlusPlus入门》思维导图 浏览 | 下载]]></content>
      <categories>
        <category>编程语言</category>
        <category>C++</category>
      </categories>
      <tags>
        <tag>C++</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[HuggingFace-Transformers手册]]></title>
    <url>%2F2019%2F12%2F30%2FHuggingFace-Transformers%E6%89%8B%E5%86%8C%2F</url>
    <content type="text"><![CDATA[HuggingFace-Transformers手册 = 官方链接 + 设计结构 + 使用教程 + 代码解析Transformers（以前称为pytorch Transformers和pytorch pretrained bert）为自然语言理解（NLU）和自然语言生成（NLG）提供了最先进的通用架构（bert、GPT-2、RoBERTa、XLM、DistilBert、XLNet、CTRL…），其中有超过32个100多种语言的预训练模型并同时支持TensorFlow 2.0和Pythorch两大深度学习框架。 HuggingFace-Transformers官方链接 transformers GitHub transformers Doc transformers Online Demo Paper HuggingFace’s Transformers: State-of-the-art Natural Language Processing 设计结构预训练模型（TFPreTrainedModel）、模型配置（PretrainedConfig）、分词器（PreTrainedTokenizer）就是整个HuggingFace-Transformers的核心，它们分别负责模型结构和权重、模型的超参数、模型的输入预处理。 使用教程使用BERT解决GLUE任务MRPC数据集的分类任务微调模型 1234import osimport tensorflow as tfimport tensorflow_datasetsfrom transformers import BertTokenizer, TFBertForSequenceClassification, BertConfig, glue_convert_examples_to_features, glue_processors 12345678910111213# script parametersBATCH_SIZE = 32EVAL_BATCH_SIZE = BATCH_SIZE * 2EPOCHS = 3TASK = "mrpc"if TASK == "sst-2": TFDS_TASK = "sst2"elif TASK == "sts-b": TFDS_TASK = "stsb"else: TFDS_TASK = TASK 12num_labels = len(glue_processors[TASK]().get_labels())print(num_labels) 2 1234# Load tokenizer and model from pretrained model/vocabulary. Specify the number of labels to classify (2+: classification, 1: regression)config = BertConfig.from_pretrained("bert-base-cased", num_labels=num_labels)tokenizer = BertTokenizer.from_pretrained('bert-base-cased')model = TFBertForSequenceClassification.from_pretrained('bert-base-cased', config=config) 123# Load dataset via TensorFlow Datasetsdata, info = tensorflow_datasets.load(f'glue/&#123;TFDS_TASK&#125;', with_info=True)train_examples = info.splits['train'].num_examples 12# MNLI expects either validation_matched or validation_mismatchedvalid_examples = info.splits['validation'].num_examples 12# Prepare dataset for GLUE as a tf.data.Dataset instancetrain_dataset = glue_convert_examples_to_features(data['train'], tokenizer, 128, TASK) 1234# MNLI expects either validation_matched or validation_mismatchedvalid_dataset = glue_convert_examples_to_features(data['validation'], tokenizer, 128, TASK)train_dataset = train_dataset.shuffle(128).batch(BATCH_SIZE).repeat(-1)valid_dataset = valid_dataset.batch(EVAL_BATCH_SIZE) 12345# Prepare training: Compile tf.keras model with optimizer, loss and learning rate scheduleopt = tf.keras.optimizers.Adam(learning_rate=3e-5, epsilon=1e-08)if USE_AMP: # loss scaling is currently required when using mixed precision opt = tf.keras.mixed_precision.experimental.LossScaleOptimizer(opt, 'dynamic') 1234if num_labels == 1: loss = tf.keras.losses.MeanSquaredError()else: loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) 12metric = tf.keras.metrics.SparseCategoricalAccuracy('accuracy')model.compile(optimizer=opt, loss=loss, metrics=[metric]) 123# Train and evaluate using tf.keras.Model.fit()train_steps = train_examples//BATCH_SIZEvalid_steps = valid_examples//EVAL_BATCH_SIZE 12history = model.fit(train_dataset, epochs=EPOCHS, steps_per_epoch=train_steps, validation_data=valid_dataset, validation_steps=valid_steps) Train for 114 steps, validate for 6 steps Epoch 1/3 114/114 [==============================] - 840s 7s/step - loss: 0.5896 - accuracy: 0.6883 - val_loss: 0.4735 - val_accuracy: 0.7578 Epoch 2/3 114/114 [==============================] - 763s 7s/step - loss: 0.3810 - accuracy: 0.8303 - val_loss: 0.3895 - val_accuracy: 0.8359 Epoch 3/3 114/114 [==============================] - 756s 7s/step - loss: 0.1856 - accuracy: 0.9334 - val_loss: 0.5333 - val_accuracy: 0.8125 123# Save TF2 modelos.makedirs('./glue_mrpc_save/', exist_ok=True)model.save_pretrained('./glue_mrpc_save/') 1tokenizer.save_pretrained('./glue_mrpc_save/') (&#39;./glue_mrpc_save/vocab.txt&#39;, &#39;./glue_mrpc_save/special_tokens_map.json&#39;, &#39;./glue_mrpc_save/added_tokens.json&#39;) 加载模型和评估模型 123import tensorflow as tfimport tensorflow_datasetsfrom transformers import BertTokenizer, TFBertForSequenceClassification, BertConfig, glue_convert_examples_to_features 123# Load dataset, tokenizer, model from pretrained model/vocabularytokenizer = BertTokenizer.from_pretrained('glue_mrpc_save')model = TFBertForSequenceClassification.from_pretrained('glue_mrpc_save') 123TFDS_TASK = "mrpc"# Load dataset via TensorFlow Datasetsdata, info = tensorflow_datasets.load(f'glue/&#123;TFDS_TASK&#125;', with_info=True) INFO:absl:Overwrite dataset info from restored data version. INFO:absl:Reusing dataset glue (/home/b418a/tensorflow_datasets/glue/mrpc/0.0.2) INFO:absl:Constructing tf.data.Dataset for split None, from /home/b418a/tensorflow_datasets/glue/mrpc/0.0.2 12# MNLI expects either validation_matched or validation_mismatchedvalid_examples = info.splits['validation'].num_examples 123# MNLI expects either validation_matched or validation_mismatchedvalid_dataset = glue_convert_examples_to_features(data['validation'], tokenizer, 128, TFDS_TASK)valid_dataset = valid_dataset.batch(64) 123456# Prepare training: Compile tf.keras model with optimizer, loss and learning rate scheduleopt = tf.keras.optimizers.Adam(learning_rate=3e-5, epsilon=1e-08)loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)metric = tf.keras.metrics.SparseCategoricalAccuracy('accuracy')model.compile(optimizer=opt, loss=loss, metrics=[metric]) 1model.evaluate(valid_dataset) [0.5068637558392116, 0.8137255] 代码解析待完成… 有关类图的说明请参考：UML 类图详解 与 UML类图与类的关系详解]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>transformer</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[机器学习相关的概率论和信息论基础知识]]></title>
    <url>%2F2019%2F12%2F25%2F%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E7%9B%B8%E5%85%B3%E7%9A%84%E6%A6%82%E7%8E%87%E8%AE%BA%E5%92%8C%E4%BF%A1%E6%81%AF%E8%AE%BA%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%2F</url>
    <content type="text"><![CDATA[本文系统性总结了学习机器学习所需的概率论和信息论基础知识。通过使用概率论，可以计算事件$Y$在事件$X$发生时的概率，这是很多机器学习的算法的构建模型的基础，比如建模$Y=f(X)$。通过使用信息论，可以描述随机事件的信息量也可以计算两种概率分布的差异，而后者是机器学习模型通常要优化的目标，比如度量模型预测分布$\hat Y$和数据分布$Y$的差异$g(\hat Y, Y)$。 概率论概率论是研究随机现象数量规律的数学分支。随机现象是相对于决定性现象而言的。在一定条件下必然发生某一结果的现象称为决定性现象。例如在标准大气压下，纯水加热到100℃时水必然会沸腾等。随机现象则是指在基本条件不变的情况下，每一次试验或观察前，不能肯定会出现哪种结果，呈现出偶然性。例如，掷一硬币，可能出现正面或反面。随机现象的实现和对它的观察称为随机试验。随机试验的每一可能结果称为一个基本事件，一个或一组基本事件统称随机事件，或简称事件。典型的随机试验有掷骰子、扔硬币、抽扑克牌以及轮盘游戏等。 事件的概率是衡量该事件发生的可能性的量度。虽然在一次随机试验中某个事件的发生是带有偶然性的，但那些可在相同条件下大量重复的随机试验却往往呈现出明显的数量规律。 概率概率亦称“或然率”。它反映随机事件出现的可能性大小的量度。 随机事件随机事件是在随机试验中，可能出现也可能不出现，而在大量重复试验中具有某种规律性的事件叫做随机事件(简称事件)。随机事件通常用大写英文字母表示，比如$X$。随机试验中的每一个可能出现的试验结果称为这个试验的一个样本点，记作$x_i$。全体样本点组成的集合称为这个试验的样本空间，记作$\Omega$．即$\Omega=\{x_1, x_2,…,x_n \}$。仅含一个样本点的随机事件称为基本事件，含有多个样本点的随机事件称为复合事件。 随机变量一个随机试验的可能结果（称为基本事件）的全体组成一个基本空间$\Omega$。 随机变量$X$是定义在基本空间$\Omega$上的取值为实数的函数，即基本空间$\Omega$中每一个点，也就是每个基本事件都有实轴上的点与之对应。例如，随机投掷一枚硬币，可能的结果有正面朝上，反面朝上两种，若定义$X$为投掷一枚硬币时正面朝上的次数，则X为一随机变量，当正面朝上时，X取值1；当反面朝上时，X取值0。又如，掷一颗六面骰子，它的所有可能结果是出现1点、2点、3点、4点、5点和6点 ，若定义$X$为掷一颗骰子时出现的点数，则$X$为一随机变量，出现1，2，3，4，5，6点时$X$分别取值1，2，3，4，5，6。 概率密度函数 和 概率质量函数随机变量可以是离散的，这意味着它具有有限数量的值。 对于离散随机变量，我们用概率质量函数（PMF, probability mass function）（通常表示为$P$）定义其概率分布。概率质量函数将随机变量的值映射到随机变量等于该值的概率。$P(X=x_1)$因此表示$X$取值$x_1$的概率。如果一个事件属于哪个随机变量是明确的，我们将改用$P(x_1)$。每个事件$x \in X$的概率为$0 \le P(x) \le 1 $。不可能的事件的概率为0，而确定发生的事件的概率为1。 如果随机变量能够在一个间隔中取任意值，则该变量被认为是连续的，我们使用概率密度函数（PDF，probability density function）（通常指定为$p$来指定其概率分布）。与概率质量函数相比，概率密度函数不提供特定事件的可能性。实际上，该区间内任何特定点的概率为0。我们通过$p(x)$和无限小体积$\delta x$ 的乘积 $p(x) \delta x$作为概率。 概率分布函数在实际问题中，常常要研究一个随机变量$X$取值小于某一数值$x$的概率，这概率是$X$的函数，称这种函数为随机变量$X$的分布函数，简称分布函数，记作$F(X)$，即$F(X)=P(X &lt; x) (-∞ &lt; x &lt; +∞)$。分布函数（CDF， Cumulative Distribution Function），是概率统计中重要的函数，正是通过它，可用数学分析的方法来研究随机变量。分布函数是随机变量最重要的概率特征，分布函数可以完整地描述随机变量的统计规律，并且决定随机变量的一切其他概率特征。 联合分布、边缘分布和条件分布联合概率分布（joint probability distribution）是同时在多个随机变量上的概率分布。 对于事件$x \in X$和$y \in Y$，$P(X = x，Y = y)$表示两个事件同时发生的概率。为了简洁起见，我们通常将$P(X = x，Y = y)$写为$P(x, y)$。 给定联合概率分布，边缘概率分布（marginal probability distribution）是随机变量子集上的概率分布。 对于离散变量，给定$P(X, Y)$，我们可以用概率加和规则为所有$x \in X$计算$P(x)$：$P(x)=\sum\limits_{y} P(x, y) $ 对于连续变量，给定$p(X, Y)$，我们可以用概率加和规则为所有$x \in X$计算$p(x)$：$p(x)=\int_{y} p(x, y)dy $ 为了对事件进行预测（这是机器学习中模型的关键），我们需要在已发生其他事件的情况下计算事件的概率，也称为条件概率。 我们将给定事件$x$的事件$y$的条件概率表示为$P(y | x)$。我们可以将此条件概率（conditional probability）定义为事件的联合概率除以已经发生的事件的边缘概率：$P(y|x)=\dfrac{P(x, y)}{P(x)}$ 全概率公式全概率公式表示若事件$A_1, A_2,…,A_n$构成一个完备事件组且都有正概率，则对任意一个事件$B$都有公式成立: P(B) = \sum \limits_{i=1}^n P(A_i)P(B|A_i)特别的，对于任意两随机事件$A$和$B$，有如下成立： P(B) = P(B|A)P(A) + P(B | \overline A)P(\overline A)概率乘法定理概率乘法定理(multiplication theorem of probability)，亦称概率乘法规则，即两事件积的概率，概率论的重要定理之一，等于其中一事件的概率与另一事件在前一事件已发生时的条件概率的乘积。 P(x_1,...,x_n) = P(x_1) \sum_{i=2}^n P(x_2|x_1,...,x_{i-1})最简单的一种情况就是： P(A, B) = P(A)P(B|A)独立要有两随机事件$A$和$B$。$A$和$B$发生的概率分别为$P(A)$和$P(B)$，$AB$事件同时发生的概率为$P(AB)$若$P(A) \times P(B)=P(AB)$，则$A$和$B$相互独立。事件$A$发生的概率不影响事件$B$发生的概率，反之亦然。 条件独立如果$P(X,Y|Z)=P(X|Z)P(Y|Z)$，或等价地$P(X|Y,Z)=P(X|Z)$，则称事件$X,Y$对于给定事件$Z$是条件独立的，也就是说，当$Z$发生时，$X$发生与否与$Y$发生与否是无关的。 贝叶斯公式贝叶斯定理由英国数学家贝叶斯 ( Thomas Bayes 1702-1761 ) 发展，用来描述两个条件概率之间的关系，比如$P(A|B)$和$P(B|A)$。按照乘法法则，可以立刻导出： P(A | B) = \dfrac {P(B|A) P(A)}{P(B)}期望数学期望(mean)（或均值，亦简称期望）是试验中每次可能结果的概率乘以其结果的总和，是最基本的数学特征之一。它反映随机变量平均取值的大小。函数$f(x)$相对于$P(X)$的平均值为$\mu$，其中$x$来自分布$P(X)$，该平均值也称为期望值。对于离散变量，我们可以通过求和来计算期望值： \mathbb E_{x \sim P}[f(x)] = \sum \limits_{x}P(x)f(x)其中$x \sim P$表示$x$是从$P$中抽取的。本质上，期望是函数的所有值的平均值，并以其概率加权。对于离散变量，我们可以通过求积分来计算期望值： \mathbb E_{x \sim P}[f(x)] = \int p(x)f(x)dx期望具有线性性质，即随机变量之和的期望等于其各个期望的总和： \mathbb E_x[af(x) + bg(x)]= a\mathbb E_x[f(x)] + b\mathbb E_x[g(x)]如果我们从$P(X)$中采样$x$ $n$次，则样本均值$s_n$是平均值： s_n= \dfrac{1}{n} \sum_{i=1}^n x_i方差方差用来度量随机变量和其数学期望（即均值）之间的偏离程度。$x$采样自分布$P$，$f(x)$与其均值的平方差的期望值为$f(x)$的方差： Var(f(x))=E[(f(x) - E[f(x)])^2]上式的另一种形式是： Var(f(x))=E[f(x)^2] - E[f(x)]^2标准偏差只是方差的平方根，通常表示为$\sigma$，而方差指定为$\sigma ^2$。作为平方的期望，方差始终为正。均值和方差分别称为概率分布的第一矩和第二矩。 协方差协方差（Covariance）在概率论和统计学中用于衡量两个变量的总体误差。而方差是协方差的一种特殊情况，即当两个变量是相同的情况。两个随机变量$X$和$Y$的协方差计算式如下： Cov(X, Y)=E[(X - E[X])(Y - E[Y])]两个独立的变量的协方差为零，而两个非独立变量的协变量不为零。 Pearson相关系数Pearson相关系数（Pearson correlation coeﬃcient）是用来衡量两个数据集合是否在一条线上面，它用来衡量定距变量间的线性关系。两个随机变量$X$和$Y$的Pearson相关系数计算式如下： \rho(X, Y) = \dfrac {Cov(X, Y)}{\sigma X \sigma Y}大数定律大数定律(law of large numbers)，是一种描述当试验次数很大时所呈现的概率性质的定律。但是注意到，大数定律并不是经验规律，而是在一些附加条件上经严格证明了的定理，它是一种自然规律因而通常不叫定理而是大数“定律”。而我们说的大数定理通常是经数学家证明并以数学家名字命名的大数定理，如伯努利大数定理。 大数定律有若干个表现形式。这里仅介绍高等数学概率论要求的常用的三个重要定律： 切比雪夫大数定理设$X_1,X_2,..,X_n$是一列相互独立的随机变量(或者两两不相关)，且期望$E(X_k)=\mu_k$和方差$D(x_k)=\sigma^2$。若存在常数$C$使得$D(X_k) \le C (k=1,2,…,n)$，则： \forall \epsilon > 0 , \lim_{n \to \infty}P\{|\frac{1}{n} \sum_{k=1}^n X_k - \frac{1}{n} \sum_{k=1}^n \mu_k | < \epsilon \}=1将该公式应用于抽样调查，就会有如下结论：随着样本容量n的增加，样本平均数将接近于总体平均数。从而为统计推断中依据样本平均数估计总体平均数提供了理论依据。 特别需要注意的是，切比雪夫大数定理并未要求$X_1,X_2,..,X_n$同分布，相较于伯努利大数定律和辛钦大数定律更具一般性。 伯努利大数定律设$\mu$是$n$次独立试验中事件$A$发生的次数，且事件$A$在每次试验中发生的概率为$p$，则： \forall \epsilon > 0 , \lim_{n \to \infty}P\{|\frac{\mu_n}{n} - p | < \epsilon \}=1该定律是切比雪夫大数定律的特例，其含义是，当n足够大时，事件A出现的频率将几乎接近于其发生的概率，即频率的稳定性。 在抽样调查中，用样本成数去估计总体成数，其理论依据即在于此 辛钦大数定律设$X_1,X_2,..,X_n$是独立同分布的随机变量序列，且期望$E(X_k)=\mu_k$，则： \forall \epsilon > 0 , \lim_{n \to \infty}P\{|\frac{1}{n} \sum_{k=1}^n X_k - \frac{1}{n} \sum_{k=1}^n \mu_k | < \epsilon \}=1辛钦大数定律从理论上指出：用算术平均值来近似实际真值是合理的，而在数理统计中，用算术平均值来估计数学期望就是根据此定律，这一定律使算术平均值的法则有了理论依据。 中心极限定理中心极限定理，是指概率论中讨论随机变量序列部分和分布渐近于正态分布的一类定理。这组定理是数理统计学和误差分析的理论基础，指出了大量随机变量近似服从正态分布的条件。它是概率论中最重要的一类定理，有广泛的实际应用背景。在自然界与生产中，一些现象受到许多相互独立的随机因素的影响，如果每个因素所产生的影响都很微小时，总的影响可以看作是服从正态分布的。中心极限定理就是从数学上证明了这一现象。 独立同分布的中心极限定理设$X_1,X_2,..,X_n$是独立同分布的随机变量序列，并且具有有限期望$E(X_k)=\mu_k$和方差$D(X_k)=\sigma^2$ ，则对于任意$X$，分布函数： F_n(x)=P\{ \dfrac{\sum_{i=1}^n X_i - n \mu}{\sigma \sqrt {n}} \le x \}满足 \lim_{n \to \infty}F_n(x)\{\dfrac{\sum_{i=1}^n X_i - n \mu}{\sigma \sqrt {n}} \le x \}= \dfrac{1}{\sqrt {2\pi}} \int_{- \infty}^x e^{- \frac{t^2}{2}}dt该定理说明，当$n$很大时，随机变量$Y_n = \dfrac{\sum_{i=1}^n X_i - n \mu}{\sigma \sqrt {n}}$近似地服从标准正态分布$N(0, 1)$。 棣莫佛－拉普拉斯定理棣莫弗—拉普拉斯中心极限定理，即二项分布以正态分布为其极限分布定律。 设随机变量$X_1,X_2,..,X_n$是服从参数为$n, p(0&lt;p&lt;1)$的二项分布，则对于任意有限区间$(a, b)$有： \lim_{n \to \infty}P\{a < \dfrac{X_n - n p}{\sqrt {np(1-p)}} \le b \}= \int_{a}^b \dfrac{1}{\sqrt {2\pi}} e^{- \frac{t^2}{2}}dt该定理表明，正态分布是二项分布的极限分布，当数充分大时，我们可以利用上式来计算二项分布的概率。 不同分布的中心极限定理该定理说明：所研究的随机变量如果是有大量独立的而且均匀的随机变量相加而成，那么它的分布将近似于正态分布。 最大似然估计最大似然法明确地使用概率模型，其目标是寻找能够以较高概率产生观察数据的系统发生树。 概率分布概率分布，是指用于表述随机变量取值的概率规律。如果试验结果用变量$X$的取值来表示，则随机试验的概率分布就是随机变量的概率分布，即随机变量的可能取值及取得对应值的概率。 伯努利分布在机器学习中，我们经常会使用一些常见的概率分布。最简单的概率分布是伯努利分布，它是单个二进制随机变量上的离散分布。它由参数$\phi \in [0, 1]$定义，该参数控制随机变量$X$等于1的概率：$P(x=1) = \phi$。 相反，$P(x=0) = 1 - \phi$。由此得出伯努利分布的概率质量函数： P(X=x) = \phi ^x(1 - \phi )^{1-x}二项分布二项分布是$n$个独立的是/非试验中成功的次数的离散概率分布，其中每次试验的成功概率为$\phi$。这样的单次成功/失败试验又称为伯努利试验。 正态分布正态分布（Normal distribution），也称“常态分布”，又名高斯分布（Gaussian distribution）。 一维正态分布若随机变量$X$服从一个位置参数为$\mu$、尺度参数为$\sigma$的概率分布，且其概率密度函数为： N(x; \mu, \sigma ^2)= \sqrt {\dfrac{1}{2 \pi \sigma ^2}} exp(- \dfrac {(x- \mu)^2}{2 \sigma ^2})则这个随机变量$X$就称为正态随机变量，正态随机变量服从的分布就称为正态分布，记作 $X \sim N(\mu , \sigma ^2) $，读作$X$服从$X \sim N(\mu , \sigma ^2) $，或$X$服从正态分布。 标准正态分布当$\mu = 0, \sigma = 1$时，正态分布就成为标准正态分布： N(x; 0, 1)= \dfrac{1}{\sqrt {2 \pi}} exp(- \dfrac {x^2}{2})经验分布通常，我们将使用经验分布（empirical distribution）或数据生成分布（data generating distribution）来近似我们想要学习的真实基础分布。 如果数据是离散的，那么我们可以简单地使用多元分布，其中每个数据点的概率就是训练过程中其频率，其经验分布是： \hat P(\boldsymbol x) = \frac{1}{n} \sum_{k=1}^n \boldsymbol 1_{\boldsymbol x_i = \boldsymbol x}其中$\boldsymbol 1$是一个指示函数，如果$\boldsymbol x_i = \boldsymbol x$则它的值为1，否则为0。 如果数据是连续的，其经验分布是： \hat p(\boldsymbol x) = \frac{1}{n} \sum_{k=1}^n \delta ({\boldsymbol x - \boldsymbol x_i})其中$\delta(X)$是狄拉克增量函数（Dirac delta function），其满足以下定义即可：$\int_{- \infty}^{\infty} \delta (x) dx=1, \delta(X=0) = \infty$ ，其它$\delta(X)=0$。 信息论信息论是运用概率论与数理统计的方法研究信息、信息熵、通信系统、数据传输、密码学、数据压缩等问题的应用数学学科。 在机器学习中，将使用信息论中的度量来根据两个概率分布所编码的信息来表征两个概率分布之间的差异。与数据的经验分布相比，这将为我们提供模型正在学习的概率分布的“良好”度量。 自信息 / 信息量信息论的基本量度是自信息（Self-information），又称信息量，它使我们能够确定事件$x \in X$的含有的信息的多寡： I(x) = - logP(x)如果$log$的底为2，那么信息量的单位是bit；如果底为$e$，那么信息量的单位是nats。 香农熵 / 信息熵香农熵，又称信息熵，表示来自概率分布$P$的所有事件$x$含有的信息量的期望值，香农熵有效地衡量了概率分布中包含的不确定性。 H(x) = \mathbb E_{x \sim P}[I(x)] = - \mathbb E_{x \sim P} [logP(x)]相对熵 / KL散度我们可以将熵的概念扩展到两个分布，相对熵，又被称为KL散度（Kullback-Leibler divergence）或信息增益，是两个概率分布间差异的非对称性度量。在在信息理论中，相对熵等价于两个概率分布的信息熵的差值： D_{KL}(P||Q)=KL(Q||P) = - \mathbb E_{x \sim P} [log \dfrac{P(x)}{Q(x)}] = - \mathbb E_{x \sim P} [logP(x) - logQ(X)]JS散度JS散度（Jensen-Shannon divergence），度量两个概率分布之间的差异性的定义： JSD(P||Q) = \dfrac{1}{2} D_{KL}(P||M) + \dfrac{1}{2} D_{KL}(Q||M)其中$M = \dfrac{1}{2}(P + Q)$。 交叉熵交叉熵（cross-entropy）主要用于度量两个概率分布间的差异性信息，其定义是： H(P, Q) = - \mathbb E_{x \sim P} [logQ(X)]给交叉熵加减$\mathbb E_{x \sim P} [logP(x)]$，得到： \begin{aligned} H(P, Q) &= -\mathbb E_{x \sim P} [logP(x)] + \mathbb E_{x \sim P} [logP(x)] - \mathbb E_{x \sim P} [logQ(X)] \\ &= -\mathbb E_{x \sim P} [logP(x)] + \mathbb E_{x \sim P} [logP(x) - logQ(X)] \\ &= H(P) + D_{KL}(P||Q) \end{aligned}即： H(P, Q) = H(P) + D_{KL}(P||Q)概率分布$P$和$Q$的交叉熵等于概率分布$P$的熵与概率分布$P$和$Q$的散度。 逐点相互信息点向互信息（PMI，Pointwise mutual information）是两个离散随机变量$X$和$Y$的结果之间关联的一种度量。具体来说，它衡量了随机变量$X$和$Y$联合与其各自概率的乘积之间的差异： PMI(x, y) = log \dfrac{P(x, y)}{P(x)P(y)}自然语言处理中的一种经典方法是计算语料库中每对单词之间的PMI，该PMI存储在互信息矩阵MI中。潜在的语义分析可以用来分解这样的矩阵。互信息（MI）是PMI的期望值： I(X; Y) = \sum_{y \in Y} \sum_{x \in X} PMI(x, y)我们将使用互信息矩阵MI来表征学习出的表示（learned representations）和输出标签（output labels）之间的关联。 相关资源《可视化统计概率入门书》 学习概率论 注意重点利用该书的目录结构顺序和可视化效果学习，但不可全信该书，该书的中文翻译有少许错误存在，多查资料！ 该书籍介绍 书籍首页 GitHub Distribution is all you need 深度学习研究人员的基本分布概率教程，涵盖以下图中的12种常见分布。 Neural Transfer Learning for Natural Language ProcessingRuder S. Neural Transfer Learning for Natural Language Processing[D]. NATIONAL UNIVERSITY OF IRELAND, GALWAY, 2019. 该论文 2.1 概率论和信息论 系统性地讲解了与自然语言处理相关的概率论和信息论知识。 待整理资料常见分布的期望与方差 Wasserstein距离 切比雪夫定理切比雪夫定理 百度百科切比雪夫不等式到底是个什么概念? 统计推断统计推断是通过样本推断总体的统计方法。总体是通过总体分布的数量特征即参数 (如期望和方差) 来反映的。因此，统计推断包括： 对总体的未知参数进行估计;对关于参数的假设进行检查; 对总体进行预测预报等。科学的统计推断所使用的样本，通常通过随机抽样方法得到。统计推断的理论和方法论基础，是概率论和数理统计学。统计推断：频率学派频率学派通过观察数据来确定背后的概率分布。统计推断：贝叶斯学派贝叶斯学派的思想是用数据来更新特定假设的概率。 似然函数似然函数 $P(X|\theta)$ 表达了在不同的参数 $\theta$ 下，观测数据出现的可能性的大小。注意，似然函数不是参数 $\theta$ 的概率分布，并且似然函数关于参数 $\theta$ 的积分并不（一定）等于1。 似然与概率的区别 补充：L($\theta$|x)=f(x|$\theta$)这个等式表示的是对于事件发生的两种角度的看法。其实等式两遍都是表示的这个事件发生的概率或者说可能性。再给定一个样本x后，我们去想这个样本出现的可能性到底是多大。统计学的观点始终是认为样本的出现是基于一个分布的。那么我们去假设这个分布为f，里面有参数 $\theta$。对于不同的$\theta$，样本的分布不一样。f(x|$\theta$)表示的就是在给定参数$\theta$的情况下，x出现的可能性多大。L($\theta$|x)表示的是在给定样本x的时候，哪个参数$\theta$使得x出现的可能性多大。所以其实这个等式要表示的核心意思都是在给一个$\theta$和一个样本x的时候，整个事件发生的可能性多大。 似然与概率的联系 最大似然估计如何通俗地理解“最大似然估计法”? 共轭先验分布在贝叶斯统计中，如果后验分布与先验分布属于同类，则先验分布与后验分布被称为共轭分布，而先验分布被称为似然函数的共轭先验。比如，高斯分布家族在高斯似然函数下与其自身共轭(自共轭)。这个概念，以及”共轭先验”这个说法，由霍华德·拉法拉和罗伯特·施莱弗尔在他们关于贝叶斯决策理论的工作中提出。类似的概念也曾由乔治·阿尔弗雷德·巴纳德独立提出。 具体地说，就是给定贝叶斯公式 $p(\theta|x)=\dfrac{p(x|\theta)p(\theta)}{\int p(x|\theta’)d(\theta’)}$，假定似然函数 $p(x|\theta)$ 是已知的，问题就是选取什么样的先验分布 $p(\theta)$ 会让后验分布与先验分布具有相同的数学形式。 共轭先验的好处主要在于代数上的方便性，可以直接给出后验分布的封闭形式，否则的话只能数值计算。共轭先验也有助于获得关于似然函数如何更新先验分布的直观印象。所有指数家族的分布都有共轭先验。]]></content>
      <categories>
        <category>数学</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[深度学习框架自动求导和梯度下降的原理]]></title>
    <url>%2F2019%2F11%2F29%2F%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E6%A1%86%E6%9E%B6%E8%87%AA%E5%8A%A8%E6%B1%82%E5%AF%BC%E5%92%8C%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E7%9A%84%E5%8E%9F%E7%90%86%2F</url>
    <content type="text"><![CDATA[本文以华氏温度转换为摄氏温度（一元线性回归模型）为例子，讲解了深度学习框架（PyTorch和TensorFlow）自动求导和梯度下降的原理。文章内容分为三节，层层递进，分别是： 手动反向传播求导、手动梯度下降 自动求导，手动梯度下降 自动求导，自动梯度下降 PyTorch自动求导和梯度下降原理 点击PyTorch自动求导和梯度下降原理.ipynb 动手学习 123456%matplotlib inlineimport torchimport torch.optim as optimimport numpy as npfrom matplotlib import pyplot as plttorch.set_printoptions(edgeitems=2) 123# 数据Y = [0.5, 14.0, 15.0, 28.0, 11.0, 8.0, 3.0, -4.0, 6.0, 13.0, 21.0] # 摄氏度 CelsiusX = [35.7, 55.9, 58.2, 81.9, 56.3, 48.9, 33.9, 21.8, 48.4, 60.4, 68.4] # 华氏度 Fahrenheit 1234# 转化成张量Y = torch.tensor(Y, requires_grad=False)X = torch.tensor(X, requires_grad=False)X, Y (tensor([35.7000, 55.9000, 58.2000, 81.9000, 56.3000, 48.9000, 33.9000, 21.8000, 48.4000, 60.4000, 68.4000]), tensor([ 0.5000, 14.0000, 15.0000, 28.0000, 11.0000, 8.0000, 3.0000, -4.0000, 6.0000, 13.0000, 21.0000])) 模型与损失函数。这里使用最简单的一元线性回归模型和均方根损失函数 12def model(X, w, b): return w * X + b 123def loss_fn(Y_hat, Y): squared_diffs = (Y_hat - Y)**2 return squared_diffs.mean() 手动反向传播求导、手动梯度下降123# 模型参数w = torch.ones(1)b = torch.zeros(1) 123# 模型预测输出Y_hat = model(X, w, b)Y_hat tensor([35.7000, 55.9000, 58.2000, 81.9000, 56.3000, 48.9000, 33.9000, 21.8000, 48.4000, 60.4000, 68.4000]) 123# 模型损失loss = loss_fn(Y_hat, Y)loss tensor(1763.8846) 123456789101112131415# 手动编写反向传播算法求解模型损失对模型参数的梯度def dloss_fn(Y_hat, Y): dsq_diffs = 2 * (Y_hat - Y) return dsq_diffsdef dmodel_dw(X, w, b): return Xdef dmodel_db(X, w, b): return 1.0def grad_fn(X, Y, Y_hat, w, b): dloss_dw = dloss_fn(Y_hat, Y) * dmodel_dw(X, w, b) dloss_db = dloss_fn(Y_hat, Y) * dmodel_db(X, w, b) return torch.stack([dloss_dw.mean(), dloss_db.mean()]) 1234567891011121314151617181920def training_loop(n_epochs, learning_rate, params, X, Y, print_params=True): for epoch in range(1, n_epochs + 1): w, b = params Y_hat = model(X, w, b) # &lt;1&gt; loss = loss_fn(Y_hat, Y) grad = grad_fn(X, Y, Y_hat, w, b) # &lt;2&gt; params = params - learning_rate * grad # 手动梯度下降 if epoch % 30000 == 0: # &lt;3&gt; print('Epoch %d, Loss %f' % (epoch, float(loss))) if print_params: print(' Params:', params) print(' Grad: ', grad) if not torch.isfinite(loss).all(): break # &lt;3&gt; return params 123456789params = training_loop( n_epochs = 330000, learning_rate = 1e-4, params = torch.tensor([1.00, 0.01]), X = X, Y = Y, print_params = False)params Epoch 30000, Loss 12.095908 Epoch 60000, Loss 6.133891 Epoch 90000, Loss 4.048903 Epoch 120000, Loss 3.319792 Epoch 150000, Loss 3.064586 Epoch 180000, Loss 2.975681 Epoch 210000, Loss 2.944574 Epoch 240000, Loss 2.933552 Epoch 270000, Loss 2.929731 Epoch 300000, Loss 2.928472 Epoch 330000, Loss 2.927906 tensor([ 0.5358, -17.2503]) 12# 模型预测。根据训练后的参数进行模型预测。Y_hat = model(X, *params) 123456# 比较预测结果（直线）与标准答案（圆点）fig = plt.figure()plt.xlabel("X")plt.ylabel("Y")plt.plot(X.numpy(), Y_hat.detach().numpy()) # &lt;2&gt;plt.plot(X.numpy(), Y.numpy(), 'o') [&lt;matplotlib.lines.Line2D at 0x7fd51c48c490&gt;] 自动求导，手动梯度下降12# 定义模型参数params = torch.tensor([1.0, 0.0], requires_grad=True) 12# 模型参数没有梯度这个属性params.grad is None True 1234# 正向传播，求出模型预测和损失值Y_hat = model(X, *params)loss = loss_fn(Y_hat, Y)Y_hat, loss (tensor([35.7000, 55.9000, 58.2000, 81.9000, 56.3000, 48.9000, 33.9000, 21.8000, 48.4000, 60.4000, 68.4000], grad_fn=&lt;AddBackward0&gt;), tensor(1763.8846, grad_fn=&lt;MeanBackward0&gt;)) 12# 自动反向传播求导loss.backward() 12# 查看导数值params.grad tensor([4517.2969, 82.6000]) 12345# 将上一次的梯度记录清空（导数值恢复初始状态）if params.grad is not None: params.grad.zero_()params.grad tensor([0., 0.]) 123456789101112131415def training_loop(n_epochs, learning_rate, params, X, Y): for epoch in range(1, n_epochs + 1): if params.grad is not None: # &lt;1&gt; params.grad.zero_() Y_hat = model(X, *params) loss = loss_fn(Y_hat, Y) loss.backward() params = (params - learning_rate * params.grad).detach().requires_grad_() if epoch % 30000 == 0: print('Epoch %d, Loss %f' % (epoch, float(loss))) return params 123456training_loop( n_epochs = 330000, learning_rate = 1e-4, params = torch.tensor([1.00, 0.01], requires_grad=True), # &lt;1&gt; X = X, # &lt;2&gt; Y = Y) Epoch 30000, Loss 12.095908 Epoch 60000, Loss 6.133891 Epoch 90000, Loss 4.048903 Epoch 120000, Loss 3.319792 Epoch 150000, Loss 3.064586 Epoch 180000, Loss 2.975681 Epoch 210000, Loss 2.944574 Epoch 240000, Loss 2.933552 Epoch 270000, Loss 2.929731 Epoch 300000, Loss 2.928472 Epoch 330000, Loss 2.927906 tensor([ 0.5358, -17.2503], requires_grad=True) 自动求导，自动梯度下降12# 定义模型参数params = torch.tensor([1.00, 0.01], requires_grad=True) 12# 定义模型优化器optimizer = optim.SGD([params], lr=1e-4) 1234# 正向传播，求出模型预测和损失值Y_hat = model(X, *params)loss = loss_fn(Y_hat, Y)Y_hat, loss (tensor([35.7100, 55.9100, 58.2100, 81.9100, 56.3100, 48.9100, 33.9100, 21.8100, 48.4100, 60.4100, 68.4100], grad_fn=&lt;AddBackward0&gt;), tensor(1764.7108, grad_fn=&lt;MeanBackward0&gt;)) 12# 自动反向传播求导loss.backward() 1params.grad tensor([4518.3325, 82.6200]) 12# 自动梯度下降optimizer.step() 12# 更新后的参数值params tensor([0.5482, 0.0017], requires_grad=True) 12345678910111213def training_loop(n_epochs, optimizer, params, X, Y): for epoch in range(1, n_epochs + 1): Y_hat = model(X, *params) loss = loss_fn(Y_hat, Y) optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 30000 == 0: print('Epoch %d, Loss %f' % (epoch, float(loss))) return params 12345678910params = torch.tensor([1.0, 0.01], requires_grad=True)learning_rate = 1e-4optimizer = optim.SGD([params], lr=learning_rate) # &lt;1&gt;training_loop( n_epochs = 330000, optimizer = optimizer, params = params, # &lt;1&gt; X = X, Y = Y) Epoch 30000, Loss 12.095908 Epoch 60000, Loss 6.133891 Epoch 90000, Loss 4.048905 Epoch 120000, Loss 3.319792 Epoch 150000, Loss 3.064586 Epoch 180000, Loss 2.975681 Epoch 210000, Loss 2.944574 Epoch 240000, Loss 2.933552 Epoch 270000, Loss 2.929731 Epoch 300000, Loss 2.928472 Epoch 330000, Loss 2.927906 tensor([ 0.5358, -17.2503], requires_grad=True) TensorFlow自动求导和梯度下降原理 点击TensorFlow自动求导和梯度下降原理.ipynb 动手学习 本文以华氏温度转换为摄氏温度（一元线性回归模型）为例子，讲解了深度学习框架（TensorFlow）自动求导和梯度下降的原理。文章内容分为三节，层层递进，分别是： 手动反向传播求导、手动梯度下降 自动求导，手动梯度下降 自动求导，自动梯度下降 123%matplotlib inlineimport tensorflow as tffrom matplotlib import pyplot as plt 123# 数据Y = [0.5, 14.0, 15.0, 28.0, 11.0, 8.0, 3.0, -4.0, 6.0, 13.0, 21.0] # 摄氏度 CelsiusX = [35.7, 55.9, 58.2, 81.9, 56.3, 48.9, 33.9, 21.8, 48.4, 60.4, 68.4] # 华氏度 Fahrenheit 1234# 转化成张量Y = tf.constant(Y)X = tf.constant(X)X, Y (&lt;tf.Tensor: shape=(11,), dtype=float32, numpy= array([35.7, 55.9, 58.2, 81.9, 56.3, 48.9, 33.9, 21.8, 48.4, 60.4, 68.4], dtype=float32)&gt;, &lt;tf.Tensor: shape=(11,), dtype=float32, numpy= array([ 0.5, 14. , 15. , 28. , 11. , 8. , 3. , -4. , 6. , 13. , 21. ], dtype=float32)&gt;) 模型与损失函数。这里使用最简单的一元线性回归模型和均方根损失函数 12def model(X, w, b): return w * X + b 123def loss_fn(Y_hat, Y): squared_diffs = (Y_hat - Y)**2 return tf.reduce_mean(squared_diffs) 动反向传播求导、手动梯度下降123# 模型参数w = tf.ones(1)b = tf.zeros(1) 123# 模型预测输出Y_hat = model(X, w, b)Y_hat &lt;tf.Tensor: shape=(11,), dtype=float32, numpy= array([35.7, 55.9, 58.2, 81.9, 56.3, 48.9, 33.9, 21.8, 48.4, 60.4, 68.4], dtype=float32)&gt; 123# 模型损失loss = loss_fn(Y_hat, Y)loss &lt;tf.Tensor: shape=(), dtype=float32, numpy=1763.8848&gt; 手动反向传播求导123def dloss_fn(Y_hat, Y): dsq_diffs = 2 * (Y_hat - Y) return dsq_diffs 12def dmodel_dw(X, w, b): return X 12def dmodel_db(X, w, b): return 1.0 1234def grad_fn(X, Y, Y_hat, w, b): dloss_dw = dloss_fn(Y_hat, Y) * dmodel_dw(X, w, b) dloss_db = dloss_fn(Y_hat, Y) * dmodel_db(X, w, b) return tf.stack([tf.reduce_mean(dloss_dw), tf.reduce_mean(dloss_db)]) 1234567891011121314151617181920def training_loop(n_epochs, learning_rate, params, X, Y, print_params=True): for epoch in range(1, n_epochs + 1): w, b = params Y_hat = model(X, w, b) # &lt;1&gt; loss = loss_fn(Y_hat, Y) grad = grad_fn(X, Y, Y_hat, w, b) # &lt;2&gt; params = params - learning_rate * grad # 手动梯度下降 if epoch % 30000 == 0: # &lt;3&gt; print('Epoch %d, Loss %f' % (epoch, float(loss))) if print_params: print(' Params:', params) print(' Grad: ', grad) if tf.math.is_inf(loss): break # &lt;3&gt; return params 123456789params = training_loop( n_epochs = 330000, learning_rate = 1e-4, params = tf.constant([1.00, 0.01]), X = X, Y = Y, print_params = False)params Epoch 30000, Loss 12.095908 Epoch 60000, Loss 6.133891 Epoch 90000, Loss 4.048903 Epoch 120000, Loss 3.319792 Epoch 150000, Loss 3.064586 Epoch 180000, Loss 2.975681 Epoch 210000, Loss 2.944574 Epoch 240000, Loss 2.933552 Epoch 270000, Loss 2.929731 Epoch 300000, Loss 2.928472 Epoch 330000, Loss 2.927906 &lt;tf.Tensor: shape=(2,), dtype=float32, numpy=array([ 0.5358124, -17.250313 ], dtype=float32)&gt; 12# 模型预测。根据训练后的参数进行模型预测。Y_hat = model(X, *params) 123456# 比较预测结果（直线）与标准答案（圆点）fig = plt.figure()plt.xlabel("X")plt.ylabel("Y")plt.plot(X.numpy(), Y_hat.numpy()) # &lt;2&gt;plt.plot(X.numpy(), Y.numpy(), 'o') [&lt;matplotlib.lines.Line2D at 0x7fc38cc7dfd0&gt;] 自动求导，手动梯度下降12# 定义模型参数params = tf.constant([1.00, 0.01]) 12# 定义模型损失函数loss_object = tf.keras.losses.MeanSquaredError() 1234with tf.GradientTape() as tape: tape.watch(params) # 指定要求导的对象 Y_hat = model(X, *params) loss = loss_object(Y_hat, Y) 12# 自动反向传播求导gradients = tape.gradient(loss, params) 12# 查看导数值gradients &lt;tf.Tensor: shape=(2,), dtype=float32, numpy=array([4518.333, 82.62 ], dtype=float32)&gt; 123456789101112def training_loop(n_epochs, learning_rate, params, X, Y): for epoch in range(1, n_epochs + 1): with tf.GradientTape() as tape: tape.watch(params) Y_hat = model(X, *params) loss = loss_object(Y_hat, Y) gradients = tape.gradient(loss, params) params = params - learning_rate * gradients if epoch % 30000 == 0: print('Epoch %d, Loss %f' % (epoch, float(loss))) return params 123456training_loop( n_epochs = 330000, learning_rate = 1e-4, params = tf.constant([1.00, 0.01]), X = X, Y = Y) Epoch 30000, Loss 12.095908 Epoch 60000, Loss 6.133891 Epoch 90000, Loss 4.048903 Epoch 120000, Loss 3.319792 Epoch 150000, Loss 3.064586 Epoch 180000, Loss 2.975681 Epoch 210000, Loss 2.944574 Epoch 240000, Loss 2.933552 Epoch 270000, Loss 2.929731 Epoch 300000, Loss 2.928472 Epoch 330000, Loss 2.927906 &lt;tf.Tensor: shape=(2,), dtype=float32, numpy=array([ 0.5358124, -17.250313 ], dtype=float32)&gt; 自动求导，自动梯度下降12def model(X, params): return params[0] * X + params[1] 123def loss_fn(Y_hat, Y): squared_diffs = (Y_hat - Y)**2 return tf.reduce_mean(squared_diffs) 1234# 定义模型参数、损失函数、优化器params = tf.Variable([1.00, 0.01])loss_object = tf.keras.losses.MeanSquaredError()optimizer = tf.keras.optimizers.SGD(learning_rate=1e-4) 1234with tf.GradientTape() as tape: tape.watch(params) Y_hat = model(X, params) loss = loss_object(Y_hat, Y) 12# 自动反向传播求导gradients = tape.gradient(loss, params) 12# 查看导数值gradients &lt;tf.Tensor: shape=(2,), dtype=float32, numpy=array([4518.333, 82.62 ], dtype=float32)&gt; 12# 查看参数值params &lt;tf.Variable &#39;Variable:0&#39; shape=(2,) dtype=float32, numpy=array([1. , 0.01], dtype=float32)&gt; 12# 自动梯度下降optimizer.apply_gradients(zip([gradients], [params])) &lt;tf.Variable &#39;UnreadVariable&#39; shape=() dtype=int64, numpy=1&gt; 12# 查看自动梯度下降后的参数值params &lt;tf.Variable &#39;Variable:0&#39; shape=(2,) dtype=float32, numpy=array([0.54816675, 0.001738 ], dtype=float32)&gt; 123456789101112def training_loop(n_epochs, params, X, Y): for epoch in range(1, n_epochs + 1): with tf.GradientTape() as tape: tape.watch(params) Y_hat = model(X, params) loss = loss_object(Y_hat, Y) gradients = tape.gradient(loss, params) optimizer.apply_gradients(zip([gradients], [params])) if epoch % 30000 == 0: print('Epoch %d, Loss %f' % (epoch, float(loss))) return params 12345training_loop( n_epochs = 330000, params = tf.Variable([1.00, 0.01]), X = X, Y = Y) Epoch 30000, Loss 12.095908 Epoch 60000, Loss 6.133891 Epoch 90000, Loss 4.048903 Epoch 120000, Loss 3.319792 Epoch 150000, Loss 3.064586 Epoch 180000, Loss 2.975681 Epoch 210000, Loss 2.944574 Epoch 240000, Loss 2.933552 Epoch 270000, Loss 2.929731 Epoch 300000, Loss 2.928472 Epoch 330000, Loss 2.927906 &lt;tf.Variable &#39;Variable:0&#39; shape=(2,) dtype=float32, numpy=array([ 0.5358124, -17.250313 ], dtype=float32)&gt;]]></content>
      <categories>
        <category>Artificial Intelligence Navigation</category>
      </categories>
      <tags>
        <tag>自动求导</tag>
        <tag>反向传播</tag>
        <tag>梯度下降</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[理解张量]]></title>
    <url>%2F2019%2F11%2F28%2F%E7%90%86%E8%A7%A3%E5%BC%A0%E9%87%8F%2F</url>
    <content type="text"><![CDATA[神经网络的输入、输出、权重都是张量，神经网络中的各种计算和变换就是对张量操作，张量这种数据结构是神经网络的基石，可以说没有理解张量就没有真正理解神经网络和人工智能。本文由浅入深地详细讲解分析张量，望能给予读者启发——袁宵。 背景知识连续值、有序值和分类值在尝试理解数据时，应注意三种数值。 第一种是连续值。当以数字表示时，这些值是最直观的。它们是严格排序的，各个值之间的差异具有严格的含义。说明包装A比包装B重2公斤，或者包装B比包装A远100英里，这是有固定含义的，无论包装A重3公斤还是10公斤，或者包装B是从200英里还是2,000公斤。如果您要以单位进行计数或测量，则该值可能是连续值。接下来是有序值。连续值的严格排序仍然保留，但是值之间的固定关系不再适用。一个很好的例子是订购小，中或大型饮料，将小号映射为值1，将中号映射为2，将大号映射为3。大号饮料大于中号，相同的方式是3大于2。但它并没有告诉您有关尺寸的任何信息。如果要将1、2和3转换为实际体积（例如8、12和24液体盎司），则这些值将切换为间隔值。重要的是要记住，除了对值进行排序外，您无法对它们进行数学运算；尝试平均大= 3和小= 1不会导致喝中杯！最后，分类值既没有顺序也没有数字含义。这些值通常是可能性的枚举，并分配有任意数字。将水分配给1，将咖啡分配给2，将苏打分配给3，将牛奶分配给4是一个很好的例子。首先放水，最后放牛奶没有逻辑。您只需要不同的值就可以区分它们。您可以将咖啡分配给10，将牛奶分配给–3，而没有明显变化（尽管分配值的范围是0..N-1在稍后讨论一键编码时会很有优势）。 总结：连续值严格排序，各个值之间的差异具有严格的含义，可以进行数学运算；有序值严格排序，不可以进行数学运算；分类值仅有逻辑上的区别，排序和数学运算都没有意义。 张量的定义张量（tensor）是一个多维数组（multidimensional arrays），即一种存储数字集合的数据结构，这些数字可通过索引（index）单独访问，并可通过多个索引进行索引。 张量是将向量和矩阵推广到任意维数。如下图所示，一个张量的维数与张量中用来表示标量值的索引的数量一致。 张量示意图新张量 = 张量[索引] 张量的视图与存储结合该文件理解以下内容：张量的存储.ipynb ，下面是该文件的主要内容： 张量，PyTorch中的基本数据结构 索引并在PyTorch张量上进行操作以探索和处理数据 与NumPy多维数组互操作 将计算移至GPU以提高速度 张量的视图与存储的定义存储（Storage）是一维的数字数据数组，例如包含给定类型的数字(可能是float或int32)的连续内存块。张量是这样一个存储的视图，它能够通过使用偏移量（offset）和每一维度的步长（per-dimension strides）索引（index）到该存储中。存储的布局总是一维的，而与可能涉及到它的任何张量的维数无关。 多个张量可以对相同的存储进行索引，即使它们对数据的索引是不同的。但是，底层内存只分配一次，因此不管存储实例管理的数据有多大，都可以快速地创建数据上的替代张量视图。 张量是存储实例上的视图张量视图的多维性意义张量的视图就是我们理解张量的方式，比如 shape 为[2,4,4,3]的张量 A，我们从逻辑上可以理解 为 2 张图片，每张图片 4 行 4 列，每个位置有 RGB 3 个通道的数据；张量的存储体现在张 量在内存上保存为一段连续的内存区域，对于同样的存储，我们可以有不同的理解方式， 比如上述 A，我们可以在不改变张量的存储下，将张量 A 理解为 2 个样本，每个样本的特征为长度 48 的向量。 张量存储的一维性在存储数据时，内存并不支持这个维度层级概念，只能以平铺方式按序写入内存，因此这 种层级关系需要人为管理，也就是说，每个张量的存储顺序需要人为跟踪。为了方便表达，我们把张量 shape 中相对靠左侧的维度叫做大维度，shape 中相对靠右侧的维度叫做小维度，比如[2,4,4,3]的张量中，图片数量维度与通道数量相比，图片数量叫做大维度，通道 数叫做小维度。在优先写入小维度的设定下，形状（2, 3）张量的内存布局为： 123456&lt;Tensor: shape=(3, 2), dtype=float32, numpy=array([[1., 4.], [2., 1.], [3., 5.]], dtype=float32)&gt;[1., 4., 2., 1., 3., 5.] 数据在创建时按着初始的维度顺序写入，改变张量的视图仅仅是改变了张量的理解方 式，并不会改变张量的存储顺序，这在一定程度上是从计算效率考虑的，大量数据的写入 操作会消耗较多的计算资源。 张量存储的形状（大小）、存储偏移量和步长为了索引到存储中，张量依赖于一些信息，这些信息连同它们的存储一起明确地定义了它们：大小、存储偏移量和步长（下图）。 中文 英文 意义 形状 shape 是一个元组，表示张量表示的每个维度上有多少个元素。注意张量的形状（shape）与存储的大小（size）等价。 步长 stride 是一个元组，表示当索引在每个维度上增加1时，必须跳过的存储中的元素数量。 存储偏移量 storage offset 存储中对应于张量中第一个元素的index。 张量偏移、形状（大小）和步长上图例子中，在二维张量中访问元素$(i, j)$的结果是访问存储中元素的索引如下计算： index((i, j)) = storage\_offset + stride[0] * i + stride[1] * j更加广义的：对于形状为$shape(d1, d2,.., dn)$的张量的视图中的元素$E(e1, e2,…,en)$，如果该张量的存储的步长为 $stride(s1, s2,…,sn)$ 、存储偏移量为 $s_o$，那么元素$E$的存储位置$index$是： index(E(e1, e2,...,en)) = s\_o + s1 * e1 + s2 * e2 + ... + sn *en由此我们看出张量视图中的元素由受以下因素影响： 张量视图 = f(张量存储, 张量形状, 张量步长, 张量偏移)张量存储对张量操作的影响这种张量和存储之间的间接性导致了一些操作，比如转置一个张量或者提取一个次张量，这些操作是便宜的（消耗很少资源），因为它们不会导致内存的重新分配；而是，它们包括分配一个新的张量对象，这个张量对象的形状、存储偏移量或步长有不同的值。 子张量的维数变少，而索引的存储空间仍然和原来的点张量一样。改变子张量会对原张量产生副作用（对子张量的修改会影响原张量）。但是这种效果可能并不总是存在，因为可以把子张量克隆成一个新的张量。 没有分配新的内存：只有通过创建一个新的张量实例来获得转置（transpose），这个张量实例的步长与原来的张量不同。可以通过张量的重新布局函数，比如PyTorch中的contiguous()函数，来强制拷贝一份张量，让它的布局和从新创建的张量一样。 张量的转置操作张量的视图与存储的区别与联系联系 对于形状为$shape(d1, d2,.., dn)$的张量的视图中的元素$E(e1, e2,…,en)$，如果该张量的存储的步长为 $stride(s1, s2,…,sn)$ 、存储偏移量为 $s_o$，那么元素$E$的存储位置$index$是： index(E(e1, e2,...,en)) = s\_o + s1 * e1 + s2 * e2 + ... + sn *en张量视图中的元素由受以下因素影响： 张量视图 = f(张量存储, 张量形状, 张量步长, 张量偏移)区别 相同存储可以有不同的视图：tensor_B.storage() 与 tensor_B_transpose.storage() 相同，但是 tensor_B 与 tensor_B_transpose 不同。 相同的视图可以有不同的存储：tensor_A 与 tensor_B_transpose 相同，但是 tensor_A.storage() 与 tensor_B_transpose.storage() 不同。 总结：张量的视图与存储通过索引来建立关系，它们之间没有必然性，即相同存储可以有不同的视图，相同的视图可以有不同的存储。 张量的数据类型和操作结合该文件理解以下内容：TensorFlow张量的常用操作.ipynb ，下面是该文件的主要内容： 数据类型：dtype=int32, float32, string, bool 创建张量：tf.convert_to_tensor, tf.constant, tf.zeros, tf.ones, tf.zeros_like, tf.fill, tf.random.normal, tf.random.uniform, tf.range 索引与切片：A[1][2][1], A[1, 2, 1], A[ :, :, 0:3:2], A[..., 0:3:2] 维度变换：tf.reshape, tf.expand_dims, tf.squeeze, tf.transpose 数据复制：tf.tile 数学运算：+, -, *, /, //, %, **, tf.pow, tf.square, tf.sqrt, tf.math.log, tf.matmul, @ 合并与分割：tf.concat, tf.stack, tf.split, tf.unstack 统计量：tf.norm, tf.reduce_max min mean sum, tf.argmax, tf.argmin 张量比较：tf.equal 填充与复制：tf.pad, tf.keras.preprocessing.sequence.pad_sequences, tf.tile 数据限幅：tf.maximum, tf.minimum, tf.clip_by_value 数据收集：tf.gather, tf.gather_nd 掩码：tf.boolean_mask 条件：tf.where 数据刷新：tf.scatter_nd 采样：tf.meshgrid TODO：增加PyTorch版本张量的操作 数值类型 标量，0维张量，主要用于模型损失和各种测量指标的表示，比如准确率、精度等； 向量，1维张量，主要用于表示模型权重中的偏置b； 矩阵，2维张量，主要用于表示线性模型Dense中的权重矩阵W； 张量，3维张量主要用于序列数据，它的格式是 [batch_size, sequence length, feature length]，比如自然语言处理中句子的嵌入表示 [批量大小，句子长度，词嵌入维度]。4维张量主要用于图像数据，它的格式是 [batch_size, length, width, channel]。更高维度张量较少使用。 张量操作的意义神经网络为什么要使用使用偏置b？感性认识： 神经网络中的偏置（bias）究竟有这么用？ 神经网络中的偏置项b到底是什么？ 进一步认识：简单来说，“仿射变换”就是：“线性变换”+“平移”。 神经网络需要仿射变换（常常再仿射变换后加上一个非线性的激活函数），所以可以巧妙地在输入时增加一个维度（通常设置为1），把仿射变换转换成了线性变换，从而简化了计算。 阅读： 仿射变换 旋转变换（一）旋转矩阵 内积（点积、数量积）内积-百度百科点积在数学中，又称数量积（dot product; scalar product），是指接受在实数R上的两个向量并返回一个实数值标量的二元运算。它是欧几里得空间的标准内积。两个向量$a = [a_1, a_2,…, a_n]$和$b = [b_1, b_2,…, b_n]$的点积定义为：$a \cdot b = a_1b_1 + a_2b_2 + … + a_nb_n$。使用矩阵乘法并把（纵列）向量当作n×1 矩阵，点积还可以写为：$a \cdot b = (a^T) * b$，这里的$a^T$指示矩阵a的转置。 外积（向量积）外积-百度百科外积一般指两个向量的向量积；或在几何代数中，指有类似势的运算如楔积。这些运算的势是笛卡尔积的势。这个名字与内积相对，它是有相反次序的积。这里写的是外积，但是下面的写的是矢量积。 定义把向量外积定义为：符号表示：$a \times b$大小：$|a|·|b|·sin$.方向：右手定则：若坐标系是满足右手定则的，设 $z=x \times y, |z|=|x||y| * sin$；则x,y,z构成右手系，伸开右手手掌，四个手指从x轴正方向方向转到y轴正方面，则大拇指方向即为z正轴方向。外积的坐标表示：$(x_1,y_1,z_1) \times (x_2,y_2,z_2)=(y_1z_2-y_2z_1,z_1x_2-z_2x_1,x_1y_2-x_2y_1)$ 张量与现实数据的转换结合该文件理解以下内容：用张量来表示现实世界的数据.ipynb，下面是该文件的主要内容： 将不同类型的实际数据表示为PyTorch张量 处理各种数据类型，包括电子表格、时间序列、文本、图像、医疗成像、视频、音频 从文件中加载数据 将数据转换为张量 对张量进行整形（shaping），使其可以用作神经网络模型的输入]]></content>
      <categories>
        <category>数学</category>
        <category>张量</category>
      </categories>
      <tags>
        <tag>张量</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[科学上网与内网穿透]]></title>
    <url>%2F2019%2F11%2F13%2F%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91%E4%B8%8E%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%2F</url>
    <content type="text"><![CDATA[请遵守当地法律，科学上网与内网穿透仅作为个人学习科研之用。谨记：没有任何技术可以突破法律的约束，要想人不知，除非己莫为。本文内容：科学上网与内网穿透理论 + 实践 + 常用资源 + 常见问题科学上网与内网穿透理论 科学上网 百度百科：科学上网，网络流行语，某种通过科学的方法绕过上网限制访问。 内网穿透 百度百科：让外网（拥有公共IP）的电脑与处于内部局域网（没有公共IP）的电脑通信。 科学上网原理示意图 电脑PC通过一种科学上网工具SS访问Google/Twitter/Facebook的示意图，核心要点是SS科学上网工具在GFW之间架起一条虚拟通道，网络流量通过SS代理转发，从而绕过GFW审查。 内网穿透原理示意图 外部访问通过一种内网穿透工具frp访问内部局域网的电脑，核心要点是：外部访问与VPS（Virtual Private Server 虚拟专用服务器）上的frps（frp的服务端）交互，frps通过互联网与frpc（frp的客户端）交互，frpc最后与内部局域网电脑交互，好似外部访问可以通过一条frp虚拟连接直接访问内网的内容。 互联网的组成互联网 = 明网 + 深网 + 暗网 整个互联网可以分为明网和深网，区别在于内容能否被普通的搜索引擎检索到，其中占了 96% 份额的深网中还有一小部分被称为暗网，需要特定的浏览器、特殊授权或是特殊设置才能访问，隐秘性强且大部分都是非法的内容。科研人员科学上网的主要目的是访问互联网中明网的内容。 科学上网原理 加密，让审查系统无法判断你在浏览什么内容。 代理，与第三方能正常访问被封锁的信息的代理服务器创建连接，以连接到未经审查地区的计算机，以间接的形式绕过审查设备访问互联网 伪装，将真实的信息混淆在其他信息当中，实现网络流量的伪装。 加密算法对比 SS加密方式浅析 详解 HTTPS 移动端对称加密套件优化 更多理论知识见 科学上网原理 或者 scientific_network_summary 科学上网实践谷歌镜像http://scholar.hedasudi.com/ 蓝灯 蓝灯（Lantern）是一款开源网络代理软件。 蓝灯 发布页面 shadowsocks A secure socks5 proxy,designed to protect your Internet traffic. shadowsocks 官网shadowsocks-windows 发布页面；使用说明shadowsocks-android 发布页面 shadowsocks Server https://github.com/ziggear/shadowsocks Install. pip install shadowsocks Usage. To run in the background: sudo ssserver -p 443 -k password -m aes-256-cfb --user nobody -d start To stop: sudo ssserver -d stop 另外一种方法就是通过配置文件启动，先在 /etc/shadowsocks/ 目录下新建一个config.json文件，写入如下的配置： 12345678910&#123; "server":"my_server_ip", "server_port":8388, "local_address": "127.0.0.1", "local_port":1080, "password":"mypassword", "timeout":300, "method":"aes-256-cfb", "fast_open": false&#125; 如果你想在后台运行ss服务，需要输入如下命令 ssserver -c conf.json -d start v2ray Project V 是一个工具集合，它可以帮助你打造专属的基础通信网络。Project V 的核心工具称为V2Ray，其主要负责网络协议和功能的实现，与其它 Project V 通信。V2Ray 可以单独运行，也可以和其它工具配合，以提供简便的操作流程。 Project V GitHub v2ray-core 软件发布页面 V2Ray 配置指南 Linux 安装脚本 来自 https://www.v2ray.com/ 1bash &lt;(curl -L -s https://install.direct/go.sh) 脚本运行完成后，你需要： 编辑 /etc/v2ray/config.json 文件来配置你需要的代理方式； 运行 service v2ray start 来启动 V2Ray 进程； 之后可以使用 service v2ray start|stop|status|reload|restart|force-reload 控制 V2Ray 的运行。 Blook Brook is a cross-platform(Linux/MacOS/Windows/Android/iOS) proxy/vpn software txthinking/brook outline Outline 可让新闻机构轻松地为自己的网络提供更安全的访问开放式互联网的方式，旨在让新闻发布变得更安全。 outline 官网 | outline github Tor 匿名网络浏览器 Tor 官网 SwitchyOmega SwitchyOmega 作用：快速轻松地管理和切换多个代理。 下载SwitchyOmega GitHub备用下载地址；在谷歌应用商店安装SwitchyOmega。 使用SwitchyOmega设置Chrome代理。 查看更多科学上网内容 对于懒人党直接推荐使用 ToyoDAdoubi/doubi，简单便捷 科学上网工具使用教程 《这本书能让你连接互联网》 内网穿透实践frp A fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet. frp 英文文档 和 frp 中文文档 frp 软件发布页面 frp搭建过程可以参考 frp内网穿透神器搭建 萌新也看得懂的教程系列 SSH端口转发方式一：直接使用命令行 ssh -fND localhost:8888 root@remote_ip -p=remote_port，意思是通过ssh协议与IP为remote_ip、SHH端口为remote_port、用户名为root的服务器建立一个socks5代理，把本地发往8888的数据都转交给该代理。-N 不执行任何指令 (只连接主机不打开shell)、-f 在后台执行、-D 建 socks5 的 proxy。参见SSH Tunnel绕过防火墙穿透内网 方式二：使用bitvise软件，bitvise 官网。参见Bitvise_SSH_Client 常用资源 GFWList地址：https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt 谷歌扩展程序下载：https://chrome-extension-downloader.com 常见问题 怎样设置应用程序开机启动 crx插件怎样安装到goole浏览器？ chrome 73 版本上安装crx插件出现「程序包无效 CRX_HEADER_INVALID」的报错解决办法 Ubuntu 终端临时设置代理 $ export https_proxy=https://用户名:密码@代理地址:代理端口 比如 export https_proxy=http://192.168.1.197:1080]]></content>
      <categories>
        <category>技能</category>
        <category>科学上网与内网穿透</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[有趣好玩的网站]]></title>
    <url>%2F2019%2F11%2F08%2F%E6%9C%89%E8%B6%A3%E5%A5%BD%E7%8E%A9%E7%9A%84%E7%BD%91%E7%AB%99%2F</url>
    <content type="text"><![CDATA[工具区看女装：Dress 面向可爱的穿女装的蓝孩子 | https://drsrel.github.io/photos | https://satori.mycard.moe/ Github地址：https://github.com/komeiji-satori/Dress 取网名：600万网名参考 【何同学】我拍了一张600万人的合影… 点击查看600万网名合影 选名字的方法 upfox 看电影、剧集、动漫、节目… 写文章：文章生成器 输入主题，瞬间生成万字长文。 放大图片：Bigjpg 图片放大 | https://bigjpg.com/ Github地址：https://github.com/nagadomi/waifu2x 制作表情：表情锅 在线制作表情包gif | https://app.xuty.tk/static/app/index.html Github地址：https://github.com/xtyxtyx/sorry 生成图像：Image-to-Image-technology 基于GAN的在线图片生成 | https://github.com/yuanxiaosc/DeepNude-an-Image-to-Image-technology 每次刷新网页都会生成一张独一无二的假图像，注意保存！ 生成假人图像 生成假猫图像 生成假老婆图像 自己动手操作： 移除图像的背景：remove 移除图像的背景 | https://www.remove.bg/ Pornhub风格Logo生成器：Logoly Pornhub风格Logo生成器 | https://logoly.pro/#/ Github地址：https://github.com/bestony/logoly 在线钢琴：自由钢琴 简约优雅的在线钢琴 | https://www.autopiano.cn/ Github地址：https://github.com/WarpPrism/AutoPiano 百科全书：wikihow 知道如何做任何事情的百科全书 | https://zh.wikihow.com/首页 电子书：Gutenberg 6万本免费电子书籍 | http://www.gutenberg.org/ 对联：seq2seq-couplet 用深度学习对对联。 搜索：虫部落资源搜索 整合各种网站网盘资源，聚合资源结果，只用一篇来推荐，一网打尽 | http://magnet.chongbuluo.com/ 搜索：Magi 您可以在搜索框中输入任何您感兴趣的内容，或者直接在搜索框中提问 | https://magi.com/ 更多在线工具：在线工具 支持本文研究 如果你阅读本文后有所收获，十分欢迎点击下面的广告，您对下面广告的每一次点击和免费试用都是对本项目的大力支持，谢谢！]]></content>
  </entry>
  <entry>
    <title><![CDATA[Git手册]]></title>
    <url>%2F2019%2F11%2F04%2FGit%E6%89%8B%E5%86%8C%2F</url>
    <content type="text"><![CDATA[Git手册使用方法： 首先速览本文第一章和第二章内容； 跟着廖雪峰 Git教程操作一遍，然后再仔细阅读本文内容； 如果已经熟悉，直接看阅读更多中的内容即可。 第一章创建版本库初始化一个Git仓库，使用git init命令。 添加文件到Git仓库，分两步： 使用命令 git add &lt;file&gt; ，注意，可反复多次使用，添加多个文件； 使用命令 git commit -m &lt;message&gt; ，完成。 版本回退HEAD指向的版本就是当前版本，因此，Git允许我们在版本的历史之间穿梭，使用命令 git reset --hard commit_id 。 穿梭前，用 git log 可以查看提交历史，以便确定要回退到哪个版本。 要重返未来，用 git reflog 查看命令历史，以便确定要回到未来的哪个版本。 撤销更改场景1：当你改乱了工作区某个文件的内容，想直接丢弃工作区的修改时，用命令 git checkout -- readme.txt 意思就是，把readme.txt文件在工作区的修改全部撤销，这里有两种情况（git checkout . 本地所有修改的。没有的提交的，都返回到原来的状态）： 一种是readme.txt自修改后还没有被放到暂存区，现在，撤销修改就回到和版本库一模一样的状态； 一种是readme.txt已经添加到暂存区后，又作了修改，现在，撤销修改就回到添加到暂存区后的状态。 总之，就是让这个文件回到最近一次git commit或git add时的状态。 场景2：当你不但改乱了工作区某个文件的内容，还添加到了暂存区时，想丢弃修改，分两步，第一步用命令 git reset HEAD &lt;file&gt; ，就回到了场景1，第二步按场景1操作。 场景3：已经提交了不合适的修改到版本库时，想要撤销本次提交，参考版本回退一节（使用命令 git reset --hard commit_id ），不过前提是没有推送到远程库。 删除文件当你要删除文件的时候，可以采用命令： rm test.txt 这个时候（也就是说这个时候只执行了rm test.txt）有两种情况 第一种情况:的确要把test.txt删掉，那么可以执行 git rm test.txt git commit -m &quot;remove test.txt&quot; 然后文件就被删掉了 第二种情况:删错文件了，参考撤销更改一节。 第二章远程仓库添加远程仓库 要关联一个远程库，使用命令git remote add origin git@server-name:path/repo-name.git； 关联后，使用命令git push -u origin master第一次推送master分支的所有内容； 此后，每次本地提交后，只要有必要，就可以使用命令git push origin master推送最新修改； 从远程仓库克隆 要克隆一个仓库，首先必须知道仓库的地址，然后使用git clone命令克隆。 Git支持多种协议，包括https，但通过ssh支持的原生git协议速度最快。 创建与合并分支 查看分支：git branch 创建分支：git branch &lt;name&gt; 切换分支：git checkout &lt;name&gt; 或者 git switch &lt;name&gt; 创建+切换分支：git checkout -b &lt;name&gt; 或者 git switch -c &lt;name&gt; 合并某分支到当前分支：git merge &lt;name&gt; 删除分支：git branch -d &lt;name&gt; 解决冲突当Git无法自动合并分支时，就必须首先解决冲突。解决冲突后，再提交，合并完成。解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容，再提交。用 git log --graph 命令可以看到分支合并图（用 git log --graph --pretty=oneline --abbrev-commit 可以查看简化形式的分支合并图）。 分支管理在实际开发中，我们应该按照几个基本原则进行分支管理：首先，master分支应该是非常稳定的，也就是仅用来发布新版本，平时不能在上面干活；那在哪干活呢？干活都在dev分支上，也就是说，dev分支是不稳定的，到某个时候，比如1.0版本发布时，再把dev分支合并到master上，在master分支发布1.0版本；你和你的小伙伴们每个人都在dev分支上干活，每个人都有自己的分支，时不时地往dev分支上合并就可以了。所以，团队合作的分支看起来就像这样： 合并分支时，加上—no-ff参数就可以用普通模式合并，合并后的历史有分支，能看出来曾经做过合并，而fast forward合并就看不出来曾经做过合并（通常，合并分支时，如果可能，Git会用Fast forward模式，但这种模式下，删除分支后，会丢掉分支信息。如果要强制禁用Fast forward模式，Git就会在merge时生成一个新的commit，这样，从分支历史上就可以看出分支信息。）。 git多人协作式开发时分支管理策略 Bug分支 修复bug时，我们会通过创建新的bug分支进行修复，然后合并，最后删除； 当手头工作没有完成时，先把工作现场 git stash 一下，然后去修复bug，修复后，再 git stash pop，回到工作现场； 在master分支上修复的bug，想要合并到当前dev分支，可以用 git cherry-pick &lt;commit&gt; 命令，把bug提交的修改“复制”到当前分支，避免重复劳动。 注释：总的来说，就是，在分支下进行的工作，如果不commit的话，回到master，就会显示出你在分支下你添加的工作。这个时候，你在master下修改完bug提交后，正在分支进行的工作也会提交了。为了避免这个情况，你就在分支下，git stash将工作隐藏，这个时候，切换到master时候，修改了bug，提交。分支的内容不会被提交上去。 Feature分支开发一个新feature，最好新建一个分支；如果要丢弃一个没有被合并过的分支，可以通过 git branch -D &lt;name&gt; 强行删除。 多人协作当你从远程仓库克隆时，实际上Git自动把本地的master分支和远程的master分支对应起来了，并且，远程仓库的默认名称是origin。要查看远程库的信息，用 git remote -v： 推送分支，就是把该分支上的所有本地提交推送到远程库。推送时，要指定本地分支，这样，Git就会把该分支推送到远程库对应的远程分支上：git push origin master 如果要推送其他分支，比如dev，就改成：git push origin dev 但是，并不是一定要把本地分支往远程推送，那么，哪些分支需要推送，哪些不需要呢？ master分支是主分支，因此要时刻与远程同步； dev分支是开发分支，团队所有成员都需要在上面工作，所以也需要与远程同步； bug分支只用于在本地修复bug，就没必要推到远程了，除非老板要看看你每周到底修复了几个bug； feature分支是否推到远程，取决于你是否和你的小伙伴合作在上面开发。 多人协作的工作模式通常是这样： 首先，可以试图用 git push origin &lt;branch-name&gt; 推送自己的修改； 如果推送失败，则因为远程分支比你的本地更新，需要先用 git pull 试图合并； 如果合并有冲突，则解决冲突，并在本地提交； 没有冲突或者解决掉冲突后，再用 git push origin &lt;branch-name&gt; 推送就能成功！ 如果 git pull 提示 no tracking information，则说明本地分支和远程分支的链接关系没有创建，用命令 git branch --set-upstream-to &lt;branch-name&gt; origin/&lt;branch-name&gt; 。 第三章搭建Git服务器 安装git：sudo apt-get install git 创建一个git用户，用来运行git服务：sudo adduser git 创建证书登录：收集所有需要登录的用户的公钥，就是他们自己的id_rsa.pub文件，把所有公钥导入到 /home/git/.ssh/authorized_keys 文件里，一行一个。 初始化Git仓库：先选定一个目录作为Git仓库，假定是 /srv/sample.git，在/srv目录下输入命令：sudo git init --bare sample.git Git就会创建一个裸仓库，裸仓库没有工作区，因为服务器上的Git仓库纯粹是为了共享，所以不让用户直接登录到服务器上去改工作区，并且服务器上的Git仓库通常都以.git结尾。然后，把owner改为git：sudo chown -R git:git sample.git 禁用shell登录：出于安全考虑，第二步创建的git用户不允许登录shell，这可以通过编辑/etc/passwd文件完成。找到类似下面的一行：git:x:1001:1001:,,,:/home/git:/bin/bash 改为：git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell 这样，git用户可以正常通过ssh使用git，但无法登录shell，因为我们为git用户指定的git-shell每次一登录就自动退出。 克隆远程仓库：现在，可以通过git clone命令克隆远程仓库了，在各自的电脑上运行：git clone git@server:/srv/sample.git 。我们的ssh端口可能不是22，那么在填写url的时候就要做出一定的改变的：git clone ssh://用户名@主机IP(或域名):端口号/git目录地址 管理公钥：如果团队很小，把每个人的公钥收集起来放到服务器的 /home/git/.ssh/authorized_keys 文件里就是可行的。如果团队有几百号人，这时，可以用Gitosis来管理公钥。 管理权限：可以在服务器端编写一系列脚本来控制提交等操作，达到权限控制的目的。Gitolite就是这个工具。 Git使用中的问题使用git pull之后出现冲突error: Your local changes to the following files would be overwritten by merge:原因：其他人修改了A文件并提交到版本库中去了，而你本地也修改了A文件，这时候你进行 git pull 操作就好出现冲突了。 解决办法： 方法一：服务器代码合并本地代码（推荐）123$ git stash //暂存当前正在进行的工作。$ git pull origin master //拉取服务器的代码$ git stash pop //合并暂存的代码 方法二：服务器代码覆盖本地代码12$git reset --hard //回滚到上一个版本$git pull origin master 阅读更多 git-scm 官网 Pro Git book 中文版 廖雪峰 Git教程 Git Cheat Sheet GitHub Cheat Sheet Pycharm中使用Git 带着梦想飞翔]]></content>
      <categories>
        <category>技能</category>
        <category>Git</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[百度艾尼ERNIE]]></title>
    <url>%2F2019%2F10%2F22%2F%E7%99%BE%E5%BA%A6%E8%89%BE%E5%B0%BCERNIE%2F</url>
    <content type="text"><![CDATA[本文计划内容：ERNIE核心资源+论文解析+实战飞桨-ERNIE 核心资源 飞桨-ERNIE 官网 ERNIE GitHub 英文文档 中文文档 ERNIE 2.0 是基于持续学习的语义理解预训练框架，使用多任务学习增量式构建预训练任务。ERNIE 2.0 中，新构建的预训练任务类型可以无缝的加入训练框架，持续的进行语义理解学习。 通过新增的实体预测、句子因果关系判断、文章句子结构重建等语义任务，ERNIE 2.0 语义理解预训练模型从训练数据中获取了词法、句法、语义等多个维度的自然语言信息，极大地增强了通用语义表示能力。 我们对 ERNIE 2.0 模型和现有 SOTA 预训练模型在 9 个中文数据集、以及英文数据集合 GLUE 上进行效果比较。结果表明：ERNIE 2.0 模型在英语任务上几乎全面优于 BERT 和 XLNet，在 7 个 GLUE 任务上取得了最好的结果；中文任务上，ERNIE 2.0 模型在所有 9 个中文 NLP 任务上全面优于 BERT。 Pre-training Tasks ERNIE 解读最新NLP架构的直观解释：多任务学习– ERNIE 2.0（附链接） FAQ飞桨ERNIE常用FAQ 五、其它问题 Q1. BERT与ERNIE谁更强？从效果来看，ERNIE的效果领先于BERT。BERT、XLNet等主流方法都强调通过强力的 Transformer 直接构建语言模型，而 ERNIE 2.0 通过多任务预训练的方法加强模型学到的语言知识。ERNIE 2.0 通过增量学习的方式更新，也就是说可以通过自定义的 NLP 任务微调已训练模型，加强预训练效果。ERNIE2.0 模型在英语任务上很多都优于 BERT 和XLNet，在 7 个GLUE 任务上取得了最好的结果；中文任务上，ERNIE 2.0 模型在所有9 个中文NLP 任务上全面优于 BERT。 Q2. ERNIE效果领先BERT是否得益于更多数据?否。我们对比了不同模型公布的数据量，BERT: 3.3B (tokens), ERNIE:7.9 B (tokens), XLNet: 32.8B (tokens)，目前版本的数据规模是XLNet的1/4，同时ERNIE 没有使用人工直接标注的数据，所有数据可以通过无监督或者弱监督的方式大量得到。 Q3. ERNIE可以理解为是知识图谱+BERT吗？不是，ERNIE没有利用图谱信息，而是直接从文本中学习知识。 Q4. ERNIE的多任务持续学习是怎么实现的？ERNIE2.0 的预训练任务是一个逐步增加的过程，先训练 Task1, 然后逐步增加到多个 TaskN，多个 Task 的训练是按照一定的概率分布对 Task 进行采样，比如: 第一个 batch 训练Task1, 第2个batch 训练 Task2 。训练过程中是通过多机多卡训练，有些卡去训练任务1，有些卡训练任务2。由于目前预训练代码还未开源，用户暂时无法添加新任务做预训练。 待实验完成后更新…]]></content>
      <categories>
        <category>论文</category>
        <category>语言模型</category>
      </categories>
      <tags>
        <tag>ERNIE</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[正则表达式]]></title>
    <url>%2F2019%2F10%2F02%2F%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%2F</url>
    <content type="text"><![CDATA[正则表达式是一组由字母和符号组成的特殊文本, 它可以用来从文本中找出满足你想要的格式的句子.一个正则表达式是在一个主体字符串中从左到右匹配字符串时的一种样式. “Regular expression”这个词比较拗口, 我们常使用缩写的术语”regex”或”regexp”. 正则表达式可以从一个基础字符串中根据一定的匹配模式替换文本中的字符串、验证表单、提取字符串等等. 想象你正在写一个应用, 然后你想设定一个用户命名的规则, 让用户名包含字符,数字,下划线和连字符,以及限制字符的个数,好让名字看起来没那么丑. 我们使用以下正则表达式来验证一个用户名: 正则表达式学习资料 学习正则表达式的简单方法 learn-regex Python 标准库 » 文本处理服务 » re —- 正则表达式操作 正则表达式-教程 正则表达式 廖雪峰 Python RegEx Cheat Sheet 正则表达式应用正则表达式的应用]]></content>
  </entry>
  <entry>
    <title><![CDATA[XGBoost的工程师手册]]></title>
    <url>%2F2019%2F09%2F30%2FXGBoost%E7%9A%84%E5%B7%A5%E7%A8%8B%E5%B8%88%E6%89%8B%E5%86%8C%2F</url>
    <content type="text"><![CDATA[XGBoost的工程师手册 = XGBoost论文理论解析 + XGBoost实战 + XGBoost面试题编者：袁宵XGBoost: A Scalable Tree Boosting System树提升（Tree boosting）算法是一种非常有效且被广泛使用的机器学习方法。 在本文中，我们描述了一个名为 XGBoost （Extreme Gradient Boosting 极限提升树）的有扩展性的端到端的树提升系统，数据科学家们广泛使用该系统来实现许多机器学习挑战的最新成果。我们提出了一种新颖的稀疏数据感知算法（sparsity-aware algorithm）用于稀疏数据，一种带权值的分位数略图(weighted quantile sketch) 来近似实现树的学习。更重要的是，我们提供有关缓存访问模式（cache access patterns），数据压缩和分片（data compression and sharding）的见解，以构建有延展性的提升树系统。通过结合这些见解，XGBoost可用比现系统少得多的资源来处理数十亿规模的数据。 XGBoost极限梯度提升树的三要素 XGBoost模型 给定一个拥有 $n$ 个样例，每个样例有 $m$ 个特征的数据集 $D = \{( \textbf{x}_i, y_i) \} (|D| = n, \textbf{x}_i \in \mathbb R^m, y_i \in \mathbb R)$，一个树集成模型使用 $K$ 个相加的函数去预测输出（如图 1 所示）。 符号 说明 $F$ 函数的假设空间，这里指回归树空间，比如CART树 $q(\textbf{x})$ 表示树结构，作用是把样例 $\textbf{x}$ 映射至对应的树的叶子节点 index $T$ 树的叶子节点个数 $f_k$ 第 $k$ 颗树，每颗树对应独立的树结构 $q$ 和叶子节点权重 $w$ $w_i$ 第 $i$ 个叶子节点的权重 score 预测过程：对于给定的样例，使用决策树的规则（由 $q(x)$ 树结构决定）把样例映射至每棵树的叶子节点，然后相应叶节点得分score相加（由 $w$ 决定分数score）为最终预测结果。 XGBoost策略为了学习一系列XGBoost模型中的树，最小化以下带正则化的目标函数： 符号 说明 $l(\hat y_i, y_i)$ 一个可微分的凸损失函数，用来度量预测值 $\hat y_i$ 与 目标值 $y_i$ 之间的差异 $\Omega(f_k)$ 正则项，用来惩罚模型（回归树函数）的复杂性 目标函数 2 表达的是： XGBoost优化算法 由于XGBoost中的树集成模型的目标函数（式子2）不能使用传统的在欧几里得空间中的优化算法，而是用以一种相加的方式进行训练的。让 $\hat y_i^{(i)}$ 表示在第 $t$ 次迭代中第 $i$ 个示例的预测值，我们需要加上 $f_t$ 来最小化下面的目标函数： 上式意味着我们使用贪心算法（根据）来添加最能提升模型效果的（上述的带正则化的目标函数）函数 $f_t$ 。在一般情况下，二阶近似可用于快速优化目标。 我们可以移除常数项来获得简化形式的第 $t$ 步目标函数。 定义： $I_j = \{ i | q(\textbf{x}) = j \}$ 为叶子 $j$ 的实例集。我们可以重写式子3： 对于一个固定结构的树结构 $q(\textbf{x})$，我们可以计算出树的叶子节点 $j$ 的最优权重 $w^{\star}_j$： 并且可以计算出对应的目标函数最优值： 式子6可以作为一个评分函数来衡量一个树结构 $q$ 的质量，这个分数类似于评价决策树的杂质分数，只是它是针对更大范围的目标函数推导出来的。图2说明了如何计算这个分数。 通常不可能枚举所有可能的树结构 $q$。取而代之的是一个贪婪算法，它从一片叶子开始，迭代地向树中添加分支。假设 $I_L$ 和 $I_R$ 是左边的实例集以及分裂后的右结点。令 $I = I_L \cup IR$ 分拆后的损失减少量（也成为增益）为： 在实践中通常使用式子7来评估候选的数结构（选取增益最大的树）。 （补充推导过程开始） 式子2-&gt;式子3： 在式子2中提到，XGBoost 是一个加法模型，假设我们第 $t$ 次迭代要训练的树模型是 $f_t$，则有： 将上式代入2中，注意上式中，只有一个变量，那就是第 $t$ 次迭代要训练的树模型 $f_t$： 这里我们将正则化项进行了拆分，由于前 $t-1$ 棵树的结构已经确定，因此，前 $t-1$ 棵树的复杂度之和可以用一个常量表示： 已知泰勒公式： 令 $\Delta x = x - x_0$，则 $x = x_0 + \Delta x$，那么泰勒公式的二阶展开形式如下： 定义损失函数关于 $\hat y ^{(t-1)}$ 的一阶偏导数和二阶偏导数： 那么，我们的损失函数就可以转化为下式： 将上述二阶展开式，带入到的目标函数 Obj 中，可以得到目标函数 Obj 的近似值： 去掉全部常数项，得到目标函数： 即式子3： 为了便于理解和记忆，归纳上述推导思路如下： （补充推导过程结束） 收缩和列采样（Shrinkage and Column Subsampling）除了第二节中提到的正规化目标。另外两种技术被用来进一步防止过度拟合。 第一项技术是收缩（Shrinkage）。 在树木生长的每个步骤之后，收缩率将新增加的权重按因子 $\eta$ 缩放。 与随机优化中的学习率相似，收缩可以减少每棵树的影响，并为将来的树留出空间来改进模型。 第二种技术是列（特征）子采样（Column Subsampling）。 该技术用于RandomForest中，在用于梯度增强的商业软件TreeNet 4中实现，但在现有的开源软件包中未实现。 根据用户反馈，使用列子采样比传统的行子采样（也受支持）可以防止过度拟合。 列子样本的使用也加快了稍后描述的并行算法的计算。 树分裂算法 此处仅仅介绍树分裂算法的原理，深入证明请看陈天齐的论文 XGBoost: A Scalable Tree Boosting System。 精确贪婪算法（Basic Exact Greedy Algorithm） 树学习的关键问题之一是找到由式(7)所示的最佳分割。为了做到这一点，一个分割查找算法列举了所有特性的所有可能的分割。我们称之为精确贪婪算法（Basic Exact Greedy Algorithm），如算法图1所示。枚举连续特性的所有可能的分割是计算上的要求。为了提高效率，算法必须先根据特征值对数据进行排序，然后访问排序后的数据，累积式(7)中结构得分的梯度统计量。 近似算法（Approximate Algorithm） 精确的贪心算法是非常强大的，因为它贪婪地遍历所有可能的分裂点。然而，当数据不能完全装入内存时，就不可能有效地这样做。同样的问题也会出现在分布式设置中。为了在这两种情况下支持有效的梯度树提升（gradient tree boosting），需要一种近似算法。 我们总结了一个近似的框架，该首先根据特征分布的百分位数提出候选分割点。 然后，该算法将连续特征映射到按这些候选点划分的存储桶中，汇总统计信息，并根据汇总的统计信息找到建议（proposal）中的最佳解决方案。 该算法有两种变体，具体取决于何时给出建议（proposal）。 全局变量建议（ global variant proposes ）在树构建的初始阶段提出所有候选分割，并在所有级别使用相同的分割发现建议。 局部变量建议（local variant re-proposes）每次拆分后都会重新提出局部变量。 全局方法比本地方法需要更少的建议步骤。 但是，对于全局提案，通常需要更多的候选点，因为在每次拆分后都不会重新定义候选。 本地提案对拆分后的候选者进行了筛选，可能更适合于较深的树木。 图3给出了希格斯玻色子数据集上不同算法的比较。我们发现，本地提议确实需要较少的候选者。 如果有足够的候选项，全球提案可能与本地提案一样准确。 归纳： 全局变量建议（ global variant proposes ）需要更多数据点，速度更快。 局部变量建议（local variant re-proposes）适合更深的树木，更准确。 如果有足够的候选项，全球提案可能与本地提案一样准确。 加权分位数略图（Weighted Quantile Sketch） 怎样理解weighted quantile sketch？ 知乎 分布式加权直方图算法是XGBoost提出的一种可并行的算法，树节点在进行分裂时，需要计算特征的信息增益，该算法用于高效地生成候选分裂点，对于大型的数据集，如果每个实例具有相等权重时，quantile sketch算法可以解决，但对于加权数据集来说，则不适用，为了解决该问题，XGBoost提出了分布式加权分位数略图（Weighted Quantile Sketch）算法。 稀疏感知算法（sparsity-aware algorithm）稀疏感知分裂发现，在现实生活中，特征往往都是稀疏的，有几种可能的原因导致特征稀疏： 1）presence of missing values in the data;2）frequent zero entries in the statistics;3）artifacts of feature engineering such as one-hot encoding XGBoost以统一的方式处理缺失的情况，分裂中只选择没有缺失的数据去进行节点分支，然后缺失情况默认指定一个方向。 XGBoost的系统设计TODO：完善内容 Column Block for Parallel Learning 即按列分块并行化学习，XGBoost会对每个特征的值进行排序，使用CSC结构存储到块（block）中，训练过程对特征分枝点计算采用并行处理，寻找合适的分裂点。所以我们常说的XGBoost的并行计算指的是不是树的学习上，而是在特征上的并行处理。 所以，这里XGBoost在设计系统的时候，预留额外的空间（Block）赖储存排序好的数据，这里的排序，是按照每列的值排序，所以索引在不同特征之间是不一样的。 所以，特征预排序只需要在开始的时候做一次即可，后续可以重复调用，大大减少了每次排序的耗时，所以也可以实现并行化学习，计算每个特征的信息增益。 Cache-aware Access缓存感知访问，对于有大量数据或者说分布式系统来说，我们不可能将所有的数据都放进内存里面。因此我们都需要将其放在外存上或者分布式存储。但是这有一个问题，这样做每次都要从外存上读取数据到内存，这将会是十分耗时的操作。 因此我们使用预读取（prefetching）将下一块将要读取的数据预先放进内存里面。其实就是多开一个线程，该线程与训练的线程独立并负责数据读取。此外，还要考虑Block的大小问题。如果我们设置最大的block来存储所有样本在k特征上的值和梯度的话，cache未必能一次性处理如此多的梯度做统计。如果我们设置过少block size，这样不能充分利用的多线程的优势，也就是训练线程已经训练完数据，但是prefetching thread还没把数据放入内存或者cache中。 经过测试，作者发现block size设置为2^16个examples最好。 Blocks for Out-of-core Computation因为XGBoost是要设计一个高效使用资源的系统，所以各种机器资源都要用上，除了CPU和内存之外，磁盘空间也可以利用来处理数据。为了实现这个功能，我们可以将数据分成多个块并将每个块储存在磁盘上。 在计算过程中，使用独立的线程将Block预提取到主内存缓冲区，这样子数据计算和磁盘读取可以同步进行，但由于IO非常耗时，所以还有2种技术来改善这种核外计算： Block Compression： 块压缩，并当加载到主内存时由独立线程动态解压缩；Block Sharding： 块分片，即将数据分片到多个磁盘，为每个磁盘分配一个线程，将数据提取到内存缓冲区，然后每次训练线程的时候交替地从每个缓冲区读取数据，有助于在多个磁盘可用时，增加读取的吞吐量。 XGBoost相关证明TODO：完善内容 XGBoost应用实战TODO：完善内容 调参Complete Guide to Parameter Tuning in XGBoost with codes in Python Xgboost参数调优的完整指南及实战 XGBoost面试题 简单介绍一下XGB XGBoost为什么使用泰勒二阶展开？为什么用二阶信息不用一阶？ XGBoost在什么地方做的剪枝，怎么做的？ XGBoost如何分布式？特征分布式和数据分布式？ 各有什么存在的问题？ XGBoost里处理缺失值的方法？ XGBoost有那些优化？ XGBoost如何寻找最优特征？是又放回还是无放回的呢？ GBDT和XGBoost的区别是什么？ lightgbm和xgboost有什么区别？他们的loss一样么？ 算法层面有什么区别？ 比较一下LR和GBDT？GBDT在什么情况下比逻辑回归算法要差？ RF和GBDT的区别；RF怎么解决的过拟合问题； 怎么理解决策树、xgboost能处理缺失值？而有的模型(svm)对缺失值比较敏感？ 随机森林是怎样避免ID3算法信息增益的缺点的？ gbdt对标量特征要不要onehot编码？ CART为什么选择基尼系数作为特征选择标准 ？ 如何解决类别不平衡问题？ GBDT 如何用于分类 ？ 参考答案 参考文献 理解XGBoost原理，查看陈天齐的PPT Introduction to Boosted Trees 和论文 XGBoost: A Scalable Tree Boosting System。 使用XGBoost，查看GitHub 可扩展，可移植和分布式梯度提升（GBDT，GBRT或GBM）库 xgboost。 阅读：XGBoost超详细推导，终于有人讲明白了！ / 珍藏版 | 20道XGBoost面试题，你会几个？(上篇) / 珍藏版 | 20道XGBoost面试题，你会几个？(下篇) 带你撸一遍 XGBoost论文]]></content>
      <categories>
        <category>Artificial Intelligence Navigation</category>
        <category>XGBoost的工程师手册</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[深度学习算法的商业应用案例]]></title>
    <url>%2F2019%2F09%2F11%2F%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E7%AE%97%E6%B3%95%E7%9A%84%E5%95%86%E4%B8%9A%E5%BA%94%E7%94%A8%E6%A1%88%E4%BE%8B%2F</url>
    <content type="text"><![CDATA[本文宗旨：持续追踪深度学习算法在商业的实际应用，提升对算法的理解和算法的商业应用能力。编者：袁宵导言：模型（算法）仅仅是5%的代码量 更多内容参见 Production-Level-Deep-Learning 模型在一个生产级深度学习系统中的位置和重要性比例如下图所示： 下图是生产级深度学习系统中不同组件的高级概述： 由上可知模型（算法）只是深度学习系统或者说产品中的一个重要组成部分，但我们不能过度关注模型而忽视了其它组成部分，后文便是从模型（算法）到商业产品的具体案例，望能启发读者。 知乎 推荐算法知乎CTO李大海：知识内容平台 AI 技术应用思考 | 李大海 | 20190430 这几年随着移动互联网的发展，内容平台迎来了黄金时代。但也不可避免的，出现了很多问题和挑战。知乎合伙人、CTO 李大海在 ArchSummit 架构师峰会上演讲，并总结这些问题主要体现在两个方面：第一，信息过载问题。第二，是用户的内容消费升级。 该文主要内容： 一、内容市场背景介绍：1、信息过载2、用户内容需求升级3、知乎的使命 二、知乎如何连接「人与内容」： 2013 Edge Rank -&gt; 2016 GBDT 算法 -&gt; 2017 word2vec 和 ANN 算法（Approximate Nearest Neighbor）-&gt; 多目标学习 和 seq2seq 1、首页个性化推荐技术的架构与应用2、知乎搜索技术的架构与应用3、问题路由技术的架构与应用4、算法机器人「瓦力」的应用5、视频理解技术的应用 三、知乎如何连接「人与人」： Graph Embedding 模型 1、基于用户行为的 Embeeding 表示模型（主要使用用户搜索内容、关注、收藏、点赞、阅读的回答、文章等对应的话题，作为用户的特征，整理成 0-1 的向量。使用变分自编码器（Variational Auto-Encoder，VAE），使样本对应到正态分布，计算此正态分布和标准正态分布的 KL 散度距离作为额外的 loss，最终为得到用户的 Embedding 表示。）2、基于用户社交关系的 Embeeding 表示模型（主要使用 skip-gram 模型，得到用户的特征表示，从用户关注优秀回答者的关注关系网络中抽取数据集，采用 Randomwalk 方法抽样有序的节点，从而将社交网络转化为有序节点进行学习。） 四、知乎如何连接「内容与内容」：1、知识图谱2、其他 五、后续计划：构建 AI 驱动的「智能社区」 NAVER 商品分类算法使用TensorFlow自动分类NAVER购物产品类别 | TensorFlow | 20190521 NAVER Shopping是NAVER提供的购物门户服务。 NAVER Shopping将产品与类别相匹配，以便系统地组织产品并允许更轻松地搜索用户。 当然，每天将超过2000万个新注册产品与大约5,000个类别相匹配的任务是不可能手动完成的。本文介绍了使用TensorFlow自动匹配NAVER购物产品类别的过程，并解释了我们如何解决在将机器学习应用于我们的服务所使用的实际数据的过程中出现的一些问题。 爱奇艺、快手 、美图 短视频分类算法短视频分类技术| 袁宵 | 20190711 近年来，短视频领域一直广受关注，且发展迅速。每天有大量UGC短视频被生产、分发和消费，为生产系统带来了巨大的压力，其中的难点之一就是为每个短视频快速、准确地打上标签。为了解决人工编辑的时效和积压问题，自动化标签技术成为各大内容领域公司都非常关注的关键课题。短视频大规模层次分类作为内容理解技术的一个重要方向，为爱奇艺的短视频智能分发业务提供着强力支持，其输出被称为“类型标签”。 美图 推荐算法人均关注和时长均增长 50%，你的机器学习平台是这么做的吗？ | 汤斌 | 20190909 在美图公司社交战略部署下，推荐算法存在多方面的挑战，为了解决这些挑战，我们团队从工具和算法两个方面分别开展了工作。在工具上，我们开发了 MML 机器学习平台，提供从数据分析到模型在线服务的全流程开发及部署支持。基于 Tensorflow ，我们内部自研了 Bamboo 建模框架，提供了丰富的 SOTA 模型，常用 Layers 以及其它建模所需的组件，模型离线评估等，让算法工程师专注网络结构的设计。在算法上，我们将推荐排序的演进划分成四个阶段，从线性模型 + 大规模人工组合特征，到非线性模型 + 少量人工特征，再到深度学习模型 + 用户行为序列特征，最后是从单目标优化到多目标优化。推荐排序四个阶段的演进，又可以归纳为三个方面的工作，分别是模型优化、特征工程，以及多目标优化。在过去的一年，我们在美拍，累计提升人均关注 65.06%，人均时长 56.07%。美图秀秀，累计提升人均关注 14.93%，人均时长 10.33%。在这一年的实践中，我们进行了很多的尝试，在这里也和大家分享我们过去的一些尝试和踩过的一些坑，希望能让大家有所收获。 百度 百度机器学习课程百度机器学习课程 (四)：跨上大数据的战车 | 毕然 | 20190910 从商业和应用的角度阐述，为什么各行各业的企业都想跨上大数据的战车，大数据可以为业务带来哪些好处，以及如何利用这些好处改造业务？ 百度机器学习课程系列课程： 百度机器学习课程 （一）：机器学习可能吗？ 百度机器学习课程（二）：机器学习如何做？ 百度机器学习课程 （三）：大数据的价值 （从一线工作者的角度，谈一谈大数据对机器学习和人工智能意味着什么。） 百度机器学习课程 (四)：跨上大数据的战车 大数据的常见应用场景： 个性化匹配：在长尾经济与共享经济下的全新业务模式。信息、商品、服务、资源的个性化匹配，如：搜索，新闻 APP，电商，找工作/对象，打车 APP，信贷等。 代替人工：业务中的人工环节，引入智能模型，提升效率。基于大数据的智能学习，替代机械性的人工服务，如：机器翻译，人脸检测的安保系统，电商的自动客服，无人车等。 大数据不仅仅是数据技术，还需要完整的产业链： 数据 -&gt; 模型 -&gt; 业务 -&gt; 需求 只有这些链条能够全部串联起来的时候，才能说我们真正利用了大数据技术解决了我们的业务问题。以买鞋的案例来说，首先我们需要有很多顾客购买各种各样鞋子的数据，然后建立一个个性化推荐的模型，而我们的业务是鞋厂可以根据用户个性化的需求，来规模化的生产各种各样的鞋子，最后的需求，我们需要确认顾客个性化的喜好和风格。只有数据、模型、业务和需求，这四方面全部 OK 的时候，才能真正的建立一个完整的基于数据技术的产业链条，而不仅仅是招来几个做机器学习的人，搞一些机器学习的技术，却没有对用户需求和业务进行深刻认知。 华为 文本情感分类算法一文看懂 NLP 中的文本情感分析任务 | 李明磊 | 20190921 本文介绍了情感分析的概念以及华为云在情感分析方面的实践和进展，部分服务已经可以在我们的“EI 体验空间”小程序体验，欢迎大家体验并提出宝贵的意见。情感分析服务可以用于商品评价智能化分析、智能评分等，欢迎大家体验。 阅读更多：InfoQ 促进软件开发领域知识与创新的传播-极客邦]]></content>
      <categories>
        <category>Artificial Intelligence 商业实践</category>
      </categories>
      <tags>
        <tag>TensorFlow</tag>
        <tag>分类</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[数据结构与算法题解]]></title>
    <url>%2F2019%2F08%2F29%2F%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%AE%97%E6%B3%95%E9%A2%98%E8%A7%A3%2F</url>
    <content type="text"><![CDATA[数据结构与算法题解：旨在使用Python语言解决面试中常见的算法编程题（持续更新）。更多用Python实现的算法参见 TheAlgorithms/Python编者：袁宵1人生苦短，我用 Python算法题 在 m*n 的乘法表中找到第k小的数的值1234567891011121314151617181920212223242526272829303132333435def find_Kth_Number(m, n, k): """ 在 m*n 的乘法表中找到第k小的数的值 :param m: 乘法表行数 :param n: 乘法表列数 :param k: 第k小的数 :return: 第k小的数的值 输入: m = 3, n = 3, k = 5 输出: 3 解释: 乘法表: 1 2 3 2 4 6 3 6 9 第5小的数字是 3 (1, 2, 2, 3, 3). """ left = 1 right = m * n while left &lt; right: count = 0 mid = left + (right - left) // 2 for i in range(1, m + 1): if mid &gt; n * i: # mid大于n*i，那么这一行的数都算进去 count += n else: count += mid // i # mid在第i行排的次序 if count &lt; k: left = mid + 1 else: right = mid return leftif __name__ == "__main__": m, n, k = list(map(int, input().split(" "))) print(find_Kth_Number(m, n, k)) 查找数组中元素的最大值与最小值123456789101112131415161718192021222324252627282930313233343536def GetMaxAndMin(array): """ 查找数组中元素的最大值与最小值 :param array: 数组 :return: 数组中的最大值和最小值 使用二分查找思想 时间复杂度 3n/2 - 2，空间复杂度 1 """ array_len = len(array) if array is None or array_len == 0: return None array_max = array[0] array_min = array[0] # 两两分组，把较小的数放在左半部分，较大的数放在右半部分 for i in range(0, array_len - 1, 2): if array[i] &gt; array[i+1]: array[i], array[i+1] = array[i+1], array[i] # 在各个分组中的左半部分找最小值 for i in range(0, array_len, 2): if array_min &gt; array[i]: array_min = array[i] # 在各个分组中的右半部分找最大值 for i in range(1, array_len, 2): if array_max &lt; array[i]: array_max = array[i] # 如果数组元素个数是奇数个，最后一个元素被分为一组，需要特殊处理 if array_len % 2 == 1: if array_min &gt; array[-1]: array_min = array[-1] elif array_max &lt; array[-1]: array_max = array[-1] return (array_min, array_max)if __name__ == "__main__": array = list(map(int, input().strip().split())) print(GetMaxAndMin(array)) 123456789101112131415161718192021222324252627282930313233343536def GetMaxAndMin(array): """ 查找数组中元素的最大值与最小值 :param array: 数组 :return: (最小值,最大值) 元组 使用二分查找思想 时间复杂度 3n/2 - 2 """ array_len = len(array) if array is None or array_len == 0: return None def _recursive_operation(array, left, right): mid = (left + right) // 2 # 求中点 if left == right: # left 和 right 间只有一个元素 return (array[mid], array[mid]) if left + 1 == right: # left 和 right 间只有两个个元素 if array[left] &gt; array[right]: return (array[right], array[left]) else: return (array[left], array[right]) # 递归计算左半部分 left_array = _recursive_operation(array, left, mid) # 递归计算右半部分 right_array = _recursive_operation(array, mid+1, right) # 总的最小值 array_min = left_array[0] if left_array[0] &lt; right_array[0] else right_array[0] # 总的最大值 array_max = left_array[1] if left_array[1] &gt; right_array[1] else right_array[1] return (array_min, array_max) return _recursive_operation(array, 0, array_len-1)if __name__ == "__main__": array = list(map(int, input().strip().split())) print(GetMaxAndMin(array)) 查找旋转数组中的最小元素1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556"""有一个数组X[0...n-1]，现在把它分为两个子数组：X1[0...m] 和 X2[m+1...n-1]，交换者两个子数组，使数组X由X1X2变成X2X1，求变换后数组X的最小值。例如 X=[1,2,3,4,5,6,7,8,9]，X1=[1,2,3,4,5]，X2=[6,7,8,9]，交换后，X=[6,7,8,9,1,2,3,4,5]"""def GetMin(array): """ 查找旋转数组中的最小元素 :param array: 旋转数组 :return: 最小值 时间复杂度 :大部分情况 log2N，极端情况 N 最容易想到的是直接遍历法，但是没有用到旋转数组的特性，时间复杂度为N。 可以用二分法解决。 """ array_len = len(array) if array is None or array_len == 0: return None left = 0 right = array_len - 1 def _recursive_operation(array, left, right): mid = (left + right) // 2 # 求中点 # 判断 array[mid] 是否为最小值 if (mid - 1) &gt;= left and array[mid] &lt; array[mid - 1]: return array[mid] # 判断 array[mid + 1] 是否为最小值 elif (mid + 1) &lt;= right and array[mid + 1] &lt; array[mid]: return array[mid + 1] # left 和 right 间只有一个元素 elif left == right: return array[mid] # left 和 right 间只有两个个元素 elif left + 1 == right: return array[left] if array[right] &gt; array[left] else array[right] # 如果 array[right] &gt; array[mid]，则最小值一定在数组左半部分 elif array[right] &gt; array[mid]: return _recursive_operation(array, left, mid) # 如果 array[mid] &gt; array[left]，则最小值一定在数组右半部分 elif array[mid] &gt; array[left]: return _recursive_operation(array, mid, right) else: # array[right] == array[mid] 且 array[mid] == array[left]， # 无法确定最小值所在位置，只能对左右两部分分别查找 # 递归计算左半部分 left_min = _recursive_operation(array, left, mid) # 递归计算右半部分 right_min = _recursive_operation(array, mid+1, right) # 总的最小值 array_min = left_min if left_min &lt; right_min else right_min return array_min return _recursive_operation(array, left, right)if __name__ == "__main__": array = list(map(int, input().strip().split())) print(GetMaxAndMin(array)) 生成旋转数组 12345678910111213141516171819202122232425def swap(array, left, right): while left &lt; right: array[right], array[left] = array[left], array[right] left += 1 right -= 1def rotateArray(array, division_location): """ 生成旋转数组 :param array: 顺序数组 :param division_location: 旋转的位置 :return: 旋转数组 先分别把两个子数组内容交换，然后再把整个数组内容交换。 """ if len(array) &lt;= 1: return array swap(array, 0, division_location) swap(array, division_location+1, len(array) - 1) swap(array, 0, len(array) - 1)if __name__ == "__main__": division_location = int(input()) array = list(map(int, input().strip().split())) rotateArray(array, division_location) print(array) 找出数组中第k小的数1234567891011121314151617181920212223242526272829303132333435363738394041def find_small_k_number(array, k): """ 找出数组中第k小的数 :param array: 整数数组 :return: 第k小的数 部分快速排序方法 """ def quick_sort_operation(array, left, right, k): i = left j = right split_elem = array[i] # 把大于等于split_elem的数放在数组右边，把小于split_elem的数放在数组左边 while i &lt; j: while i &lt; j and array[j] &gt;= split_elem: j -= 1 array[i] = array[j] while i &lt; j and array[i] &lt; split_elem: i += 1 array[j] = array[i] # 当i=j时，i就是split_elem插入数组的位置，且表示该split_elem就是数组中排行第i的数 array[i] = split_elem # 小于split_elem的数字个数 left_sub_array_item_number = i - left # 如果小于split_elem的数字个数恰好为 k-1，那么 i 对应的位置就是第k小数字的位置 if left_sub_array_item_number == k - 1: return array[i] # 如果小于split_elem的数字个数大于 k-1，那么只需在array[low, i-1] 中继续寻找 elif left_sub_array_item_number &gt; k - 1: return quick_sort_operation(array, left, i - 1, k) # 在array[i+1, high]中寻找第 k - left_sub_array_item_number - 1 的数字 else: return quick_sort_operation(array, i + 1, right, k - left_sub_array_item_number - 1) return quick_sort_operation(array, 0, len(array) - 1, k)if __name__ == "__main__": k = int(input()) array = list(map(int, input().strip().split())) print(find_small_k_number(array, k)) 找出数组前3大的数12345678910111213141516171819202122232425def findTop3(array): """ 查找数组中前三大的数 :param array: 长度不小于3的数组 :return: (num1, num2, num3) 数组中值最大的3个数组成的元组 时间复杂度: O(N) """ if len(array) &lt; 3: return -1 r1 = r2 = r3 = - 2**31 for item in array: if item &gt; r1: r3 = r2 r2 = r1 r1 = item elif item &gt; r2: r3 = r2 r2 = item elif item &gt; r1: r3 = item return (r1, r2, r3)if __name__=="__main__": array = list(map(int, input().strip().split(" "))) print(findTop3(array)) 找出数组前K大的数123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051def heap_adjust(array, start, end): """调整堆为小顶堆""" temp = array[start] child = 2 * start while child &lt;= end: if child &lt; end and array[child] &gt; array[child + 1]: child += 1 if temp &lt;= array[child]: break array[start] = array[child] start = child child = start * 2 array[start] = tempdef findTopK(array, K): """ 找出数组中前K大的数 :param array: 数组 :param K: 前K大的数 :return: (num1,..,numK) 前K大的数组成的元组 当K和数组长度比较大的时候，适合用“堆”方法找出数组中前K大的数 时间复杂度 O(N*log_2 K) """ if len(array) &lt; K: return -1 top_k_heap = [0] + array[0:K] # 添加辅助位置0 top_k_heap_len = K # 现在的待排序序列构建成一个小顶堆 for start in range(top_k_heap_len // 2, 0, -1): # 对 input_list_len // 2 个父亲节点处理 heap_adjust(top_k_heap, start, top_k_heap_len) for item in array[K:]: if item &gt; top_k_heap[1]: top_k_heap[1] = item heap_adjust(top_k_heap, 1, top_k_heap_len) # 逐步将堆结构转换为排序好的数列 # 逐步将每个最小值的根结点与末尾元素交换，并且再调整其成为小顶堆 for end in range(top_k_heap_len, 1, -1): # 遍历次数，需要找到 input_list_len - 1 次最值来交换 top_k_heap[1], top_k_heap[end] = top_k_heap[end], top_k_heap[1] # 交换最值 heap_adjust(top_k_heap, 1, end - 1) # 重新调整堆 del top_k_heap[0] # 删除辅助位置0 return tuple(top_k_heap)if __name__=="__main__": K = int(input()) array = list(map(int, input().strip().split(" "))) print(findTopK(array, K)) 找三个有序数组的公共元素12345678910111213141516171819202122232425def find_common(ar1, ar2, ar3): """ 找三个有序数组的公共元素 """ i, j, k = 0, 0, 0 n1, n2, n3 = len(ar1), len(ar2), len(ar3) while i &lt; n1 and j &lt; n2 and k &lt; n3: if ar1[i] == ar2[j] and ar2[j] == ar3[k]: print(ar1[i]) i += 1 j += 1 k += 1 elif ar1[i] &lt; ar2[j]: i += 1 elif ar2[j] &lt; ar3[k]: j += 1 else: k += 1if __name__ == '__main__': ar1 = list(map(int, input().split())) # 2 5 12 20 45 85 ar2 = list(map(int, input().split())) # 16 19 20 85 200 ar3 = list(map(int, input().split())) # 3 4 15 20 39 72 85 190 find_common(ar1, ar2, ar3) # 20 85 求数组中两个元素的最小距离12345678910111213141516171819202122232425262728293031323334def min_distance(array, num1, num2): """ 求数组中两个元素的最小距离 :param array: 数组 :param num1: 元素1 :param num2: 元素2 :return: 最小距离 时间复杂度 O(N) 动态规划方法，把每次遍历的结果都记录下来。 这里利用了最小距离一定是依次遍历数组时最近访问的两个位置（局部性）。 """ if len(array) &lt; 2 or num1 not in array or num2 not in array: return -1 min_d = 2 ** 31 last_position_1 = -1 last_position_2 = -1 for idx, item in enumerate(array): if num1 == item: last_position_1 = idx if last_position_2 &gt;= 0: min_d = min(min_d, last_position_1 - last_position_2) if num2 == item: last_position_2 = idx if last_position_1 &gt;= 0: min_d = min(min_d, last_position_2 - last_position_1) return min_dif __name__ == "__main__": num1, num2 = list(map(int, input().strip().split(" "))) array = list(map(int, input().strip().split(" "))) print(min_distance(array, num1, num2)) 异或法1234567891011121314def swapTwoInteger(a, b): """ 使用异或操作交换整数值 :param a: int :param b: int :return: (b, a) """ a = a ^ b b = a ^ b a = a ^ b return a, bif __name__ == "__main__": a, b = list(map(int, input().strip().split(" "))) print(swapTwoInteger(a, b)) 123456789101112131415161718192021222324252627def findDuplicateNumber(array): """ 查找数组中重复的整数 :param array: n-1 个整数组成的未排序的数组序列，其元素是1到n中不同的整数。 :return: 数组序列中重复的整数 时间复杂度：n，空间复杂度 1 """ array_len = len(array) # a = 1^2^3..(m)^(m)..^n a = array[0] i = 1 while i &lt; array_len: a = a ^ array[i] i += 1 # b = 1^2^3..^n b = 1 i = 2 while i &lt; array_len: b = b ^ i i += 1 # a ^ b = (1^1)^(2^2)...(m^m^m)...^(n^n) = m return a ^ bif __name__ == "__main__": array = list(map(int, input().strip().split())) print(findDuplicateNumber(array)) 123456789101112131415161718192021222324252627def findMissedNumber(array): """ 查找数组中丢失的整数 :param array: n-1 个整数组成的未排序的数组序列，其元素是1到n中不同的整数。 :return: 数组序列中缺失的整数 时间复杂度：n，空间复杂度 1 """ array_len = len(array) # a = 1^2^3..(m-1)^(m+1)..^n a = array[0] i = 1 while i &lt; array_len: a = a ^ array[i] i += 1 # b = 1^2^3..^n b = 1 i = 2 while i &lt; array_len + 2: b = b ^ i i += 1 # a ^ b = (1^1)^(2^2)...(m-1)^(m-1)^m^(m+1)^(m+1)^...^(n^n) = m return a ^ bif __name__ == "__main__": array = list(map(int, input().strip().split())) print(findMissedNumber(array)) 1234567891011121314151617181920212223242526272829def find_single(array): """ 找出特殊数组中的任意一个特殊的数 :param array: 一个数组，除了三个数是唯一的，其余的数出现偶数次 :return: 任意一个特殊的数 """ i = 0 # 遍历数字二进制位的每一位 while i &lt; 32: result1 = result2 = count1 = count2 = 0 # 遍历数组的每个数字，并根据数字的第i为是否为1进行分类 for item in array: if (item &gt;&gt; i) &amp; 1 == 1: result1 ^= item count1 += 1 else: result2 ^= item count2 += 1 # 如果result1某次计数count1为奇数且result2的结果不为零 # 说明result1结果里面只包含了一个出现次数为1的数 if count1 % 2 == 1 and result2 != 0: return result1 if count2 % 2 == 1 and result1 != 0: return result2 return -1if __name__ == "__main__": array = list(map(int, input().strip().split(" "))) print(find_single(array)) 求数组连续最大和1234567891011121314151617181920def max_sub_array(array): """ 求数组连续最大和 :param array: 数组 :return: 数组连续最大和 时间复杂度 O(N) 空间复杂度 O(1) """ n = len(array) n_sum= array[0] # 到第i个数的最大累加和 sub_max = array[0] # 累加和end中的最大值 i = 1 while i &lt; n: n_sum = array[i] if n_sum &lt;= 0 else array[i] + n_sum sub_max = n_sum if n_sum &gt; sub_max else sub_max i += 1 return sub_maxif __name__ == "__main__": array = list(map(int, input().strip().split(" "))) print(max_sub_array(array)) 求数组连续最大和，以及最大子数组的位置1234567891011121314151617181920212223242526272829303132def max_sub_array_location(array): """ 求数组连续最大和 :param array: 数组 :return: 数组连续最大和，最大子数组的位置 时间复杂度 O(N) 空间复杂度 O(1) """ n = len(array) n_sum = 0 sub_max = -2 ** 31 start_location = 0 end_location = 0 i = 0 while i &lt; n: # 到第i个数的最大累加和 if n_sum &lt;= 0: n_sum = array[i] start_location = i else: n_sum = array[i] + n_sum # 累加和end中的最大值 if n_sum &gt; sub_max: sub_max = n_sum end_location = i i += 1 return (sub_max, start_location, end_location)if __name__ == "__main__": array = list(map(int, input().strip().split(" "))) print(max_sub_array_location(array)) 数组旋转1234567891011121314151617181920212223242526272829303132333435def rotateArray(array): """ 逆时针旋转n*n矩阵45度 """ lens = len(array[0]) # 打印二维数组的上半部分 i = lens - 1 while i &gt; 0: row = 0 col = i while col &lt; lens: print(array[row][col], end=" ") row += 1 col += 1 print("") i -= 1 # 打印二维数组下半部分（包括对角线） i = 0 while i &lt; lens: row = i col = 0 while row &lt; lens: print(array[row][col], end=" ") row += 1 col += 1 print("") i += 1if __name__ == "__main__": array_row = int(input()) array = [] for i in range(array_row): array.append(list(map(int, input().strip().split(" ")))) rotateArray(array) 判断区间[a, b]与[c, d]是否相交，如果相交那么相交部分的长度L是多少？如果区间相交，那么区间最大的开始端一定小于最小的结束端，且相交的长度就是最小结束端减去最大开始端的值。 L = min(b, d) - max(a, c)找出数组中和为S的两个数字 首先对数组进行排序，时间复杂度为（N*log2N）。 然后令i = 0，j = n-1，看arr[i] + arr[j] 是否等于Sum，如果是，则结束。如果小于Sum，则i = i + 1；如果大于Sum，则 j = j – 1。这样只需要在排好序的数组上遍历一次，就可以得到最后的结果，时间复杂度为O（N）。两步加起来总的时间复杂度O（N*log2N） 找出数组中和为S的三个数字：首先还是先对数组进行排序，然后遍历数组元素arr[i]，找到和为S-arr[i]的两个数即可。 1234567891011121314151617def getSumNumFromSortedList(sorted_list, target): left = 0 right = len(sorted_list) - 1 while left &lt;= right: temp_sum = sorted_list[left] + sorted_list[right] if temp_sum == target: return [left, right] elif temp_sum &lt; target: left += 1 else: right -= 1 raise ValueError("Non-existent!")if __name__ == "__main__": nums = list(map(int, input().strip().split())) target = int(input()) print(getSumNumFromSortedList(nums, target)) 注意与“两数字和”区分： 1234567891011121314151617181920212223"""LeetCode 第 1 号问题：两数之和给定一个整数数组 nums 和一个目标值 target，请你在该数组中找出和为目标值的那 两个 整数，并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是，你不能重复利用这个数组中同样的元素。示例:给定 nums = [2, 7, 11, 15], target = 9因为 nums[0] + nums[1] = 2 + 7 = 9所以返回 [0, 1]时间复杂度 O(n) 空间复杂度 O(n)"""def twosum(num_list, target): record = dict() for i, item in enumerate(num_list): complement = target - item if complement in record: return [record[complement], i] record[item] = iif __name__ == "__main__": nums = list(map(int, input().strip().split())) target = int(input()) print(twosum(nums, target)) 1234567891011121314151617181920212223242526272829303132def find_two_odd_numbers_of_elements(array): """ 找出数组中两个出现次数为奇数个数的数(这两个数不相等) :param array: 整数数组 :return: (num1, num2) 数组中两个出现次数为奇数个数的元素 """ # (item0 ^ item0)...a^b...(itemN^itemN) = a^b a_xor_b = 0 for item in array: a_xor_b ^= item i = a_xor_b # 找到a和b二进制表示首次不相同的位置（从右往左），该位置的异或值为1 # 异或值中一定存在1的证明：a!=b -&gt; a^b!=0 -&gt; 1 in bin(a_xor_b) position = 0 while i &amp; 1 == 0: position += 1 i = i &gt;&gt; 1 # 选取position位置都为1的元素来异或求值，这样a和b只会取到其中一个， # 其它数只会取到偶数个，而偶数个数的相同数异或值为0，0与x异或为x, # 故最终的异或值为 a 或 b a_item = 0 for item in array: item_positon = item &gt;&gt; position if (item_positon &amp; 1) == 1: a_item ^= item # b = a ^ (a ^ b) b_item = a_item ^ a_xor_b return (a_item, b_item)if __name__ == "__main__": array = list(map(int, input().strip().split())) print(find_two_odd_numbers_of_elements(array)) 寻找最多的覆盖点123456789101112131415161718192021222324252627282930313233343536def max_cover(a, L): """ 寻找最多的覆盖点 :param a: 长度为n的数组，表示坐标轴上从左到右的点a[0],a[1],...,a[n-1] :param L: 木棒长度L :return: 木棒最多能覆盖的坐标轴点的个数 """ count = 2 max_count = 1 start = 0 n = len(a) i = 0 j = 1 while i &lt; n and j &lt; n: while (j &lt; n) and (a[j] - a[i] &lt;= L): j += 1 count += 1 j -= 1 count -= 1 if count &gt; max_count: start = i max_count = count i += 1 j += 1 # 输出覆盖的节点 # i = start # while i &lt; start + max_count: # print(a[i]) # i += 1 return max_countif __name__ == '__main__': a = list(map(int, input().split())) # 7 8 10 11 12 13 15 16 17 19 25 L = int(input()) # 8 print(max_cover(a, L)) # 7 字符串匹配之KMP算法字符串匹配的KMP算法 图解kmp算法-通俗易懂kmp算法 1234567891011121314151617181920212223242526272829303132333435363738def kmp(S, P): """ knut-Morris-Pratt String Matching Algorithms :param S: Source string :param P: Pattern string :return: Matching position 时间复杂度 O(len(S)+len(P)) """ def _next(P, P_length): k = 0 next_list = [0 for _ in range(P_length)] next_list[0] = k for i in range(1, P_length): while k &gt; 0 and P[k] != P[i]: k = next_list[k - 1] if P[k] == P[i]: k += 1 next_list[i] = k return next_list S_len = len(S) P_len = len(P) k = 0 next_list = _next(P, P_len) for i in range(S_len): while k &gt; 0 and P[k] != S[i]: k = next_list[k - 1] if P[k] == S[i]: k += 1 if k == P_len: return i - k + 1 return - 1if __name__ == "__main__": S = "dabxabxababxabwabxad" P = "abxabwabxad" location = kmp(S, P) print(location) 编辑距离算法动态规划-用编辑距离解释 12345678910111213141516171819202122232425def editorial_distance(strA, strB): strA_length = len(strA) strB_length = len(strB) distance_array = [[0] * (strB_length+1) for _ in range(strA_length+1)] for i in range(strA_length+1): distance_array[i][0] = i for j in range(strB_length+1): distance_array[0][j] = j for i in range(1, strA_length+1): for j in range(1, strB_length+1): if strA[i-1] == strB[j-1]: distance_array[i][j] = distance_array[i-1][j-1] else: # 在插入、删除、替换操作中保留最优解 distance_array[i][j] = min([distance_array[i-1][j]+1, distance_array[i][j-1]+1, distance_array[i-1][j-1]+1]) return distance_array[-1][-1]if __name__=='__main__': strA = "mouuse" strB = "mouse" print(editorial_distance(strA, strB)) Leetcode 583. 两个字符串的删除操作 为了求得最少删除次数，我们可以求出串 s1 和串 s2 最长公共子序列，我们记为 lcs。如果我们能求得 lcs 的值，我们可以轻易地求出答案，为 m + n - 2*lcs。这里 m 和 n 分别是给定字符串 s1s1 和 s2s2 的长度。 1234567891011121314151617class Solution: """ 时间复杂度：O(m*n)。我们需要填充大小为m * n的数组dp。m和n分别是s1和s2字符串的长度。 空间复杂度：O(m*n)。使用了大小为m∗n的dp数组。 """ def minDistance(self, word1: str, word2: str) -&gt; int: word1 = "#" + word1 word2 = "#" + word2 dp_matrix = [[0] * len(word2) for i in range(len(word1))] for i in range(1, len(word1)): for j in range(1, len(word2)): if word1[i] == word2[j]: dp_matrix[i][j] = dp_matrix[i - 1][j - 1] + 1 else: dp_matrix[i][j] = max(dp_matrix[i - 1][j], dp_matrix[i][j - 1]) longest_common_sequence_length = dp_matrix[-1][-1] return len(word1) + len(word2) - 2 * longest_common_sequence_length - 2 最长公共子序列 动态规划解最长公共子序列(LCS)(附详细填表过程) 算法导论——-最长公共子序列LCS（动态规划） 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748def get_longest_common_sequence_path(path_matrix, X_list): """ :param path_matrix: 动态规划矩阵 :param X_list: 其中一个字符串 :return: 最长公共子序列路径 """ result_list = list() i = len(path_matrix) - 1 j = len(path_matrix[0]) - 1 while path_matrix[i][j] != "0": if path_matrix[i][j] == "left_upper": result_list.append(X_list[i]) i -= 1 j -= 1 elif path_matrix[i][j] == "upper": i -= 1 else: j -= 1 result_list.reverse() return result_listdef longest_common_sequence(X_list, Y_list): X_list.insert(0, "") Y_list.insert(0, "") dp_matrix = [[0] * len(Y_list) for i in range(len(X_list))] path_matrix = [["0"] * len(Y_list) for i in range(len(X_list))] for i in range(1, len(X_list)): for j in range(1, len(Y_list)): if X_list[i] == Y_list[j]: dp_matrix[i][j] = dp_matrix[i - 1][j - 1] + 1 path_matrix[i][j] = "left_upper" elif dp_matrix[i - 1][j] &gt;= dp_matrix[i][j - 1]: dp_matrix[i][j] = dp_matrix[i - 1][j] path_matrix[i][j] = "upper" else: dp_matrix[i][j] = dp_matrix[i][j - 1] path_matrix[i][j] = "left" longest_common_sequence_length = dp_matrix[-1][-1] longest_common_sequence_path = get_longest_common_sequence_path(path_matrix, X_list) return longest_common_sequence_pathif __name__=='__main__': X_list = list("ACCGGTCGAGTGCGCGGAAGCCGGCCGAA") Y_list = list("GTCGTTCGGAATGCCGTTGCTCTGTAAA") longest_common_sequence_path = longest_common_sequence(X_list,Y_list) # "G,T,C,G,T,C,G,G,A,A,G,C,C,G,G,C,C,G,A,A" print(",".join(longest_common_sequence_path)) Leetcode 718. 最长重复子数组12345678910111213class Solution: def findLength(self, A: List[int], B: List[int]) -&gt; int: A.insert(0, "") B.insert(0, "") A_len = len(A) B_len = len(B) dp_matrix = [[0] * (B_len) for _ in range(A_len)] for i in range(1, A_len): for j in range(1, B_len): if A[i] == B[j]: dp_matrix[i][j] = dp_matrix[i-1][j-1]+1 return max(max(row) for row in dp_matrix) 最长公共连续子字符串12345678910111213141516171819202122232425262728293031def longest_common_continuous_substring(A_str, B_str): """ 最长公共连续子字符串 :param A_str: 字符串A，长度为m :param B_str: 字符串B，长度为n :return: 字符串A和字符串B公共的连续最长的字符串列表 时间复杂度：O(m*n) 空间复杂度：O(m*n) """ A_str = "#" + A_str B_str = "#" + B_str A_str_len = len(A_str) B_str_len = len(B_str) dp_matrix = [[0] * (B_str_len) for _ in range(A_str_len)] for i in range(1, A_str_len): for j in range(1, B_str_len): if A_str[i] == B_str[j]: dp_matrix[i][j] = dp_matrix[i-1][j-1]+1 substring_max_length_list = [max(row) for row in dp_matrix] substring_max_length = max(substring_max_length_list) result = [] for idx, num in enumerate(substring_max_length_list): if num == substring_max_length: result.append(A_str[idx - num + 1:idx + 1]) return resultif __name__=='__main__': A_str = "ABCBDEFBWD" B_str = "BCBWD" # ['BCB', 'BWD'] print(longest_common_continuous_substring(A_str, B_str)) Trie树（字典树，单词查找树） Trie树实现 https://github.com/hankcs/pyhanlp/blob/master/tests/book/ch02/trie.py Trie树理论知识 数据结构与算法—Trie树 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556class Node(object): def __init__(self, value) -&gt; None: self._children = &#123;&#125; self._value = value def _add_child(self, char, value, overwrite=False): child = self._children.get(char) if child is None: child = Node(value) self._children[char] = child elif overwrite: child._value = value return childclass Trie(Node): def __init__(self) -&gt; None: super().__init__(None) def __contains__(self, key): return self[key] is not None def __getitem__(self, key): state = self for char in key: state = state._children.get(char) if state is None: return None return state._value def __setitem__(self, key, value): state = self for i, char in enumerate(key): if i &lt; len(key) - 1: state = state._add_child(char, None, False) else: state = state._add_child(char, value, True)if __name__ == '__main__': trie = Trie() # 增 trie['自然'] = 'nature' trie['自然人'] = 'human' trie['自然语言'] = 'language' trie['自语'] = 'talk to oneself' trie['入门'] = 'introduction' assert '自然' in trie # 删 trie['自然'] = None assert '自然' not in trie # 改 trie['自然语言'] = 'human language' assert trie['自然语言'] == 'human language' # 查 assert trie['入门'] == 'introduction' 并查集并查集是一种树型的数据结构，用于处理一些不相交集合（Disjoint Sets）的合并及查询问题。常常在使用中以森林来表示。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061"""输入：第一行表示表示用户互动矩阵的行数（用户个数）矩阵（i, j）的每一个值表示用户i与j互动的次数，当次数大于3时互为豆油瓶。输出：矩阵对应的豆油瓶个数。例子1：输入：30 4 04 0 00 0 0输出：（用户1和2互动次数超过3次，互为豆油瓶，用户3没有互动，自成一个豆油瓶）2"""class Solution: """ 并查集解法 """ def findDouYouNum(self, array): if not array: return 0 n = len(array[0]) self.count = n self.father_list = [i for i in range(n)] self.size_list = [1 for _ in range(n)] for i in range(0, n - 1): for j in range(i+1, n): if array[i][j] &gt;= 3: self.union(i, j) return self.count def find(self, i): while(i != self.father_list[i]): i = self.father_list[i] return i def union(self, i, j): p = self.find(i) q = self.find(j) if p == q: return if self.size_list[p] &lt; self.size_list[q]: self.father_list[p] = q self.size_list[q] += self.size_list[p] else: self.father_list[q] = p self.size_list[p] += self.size_list[q] self.count -= 1if __name__=="__main__": n = int(input()) array = [[] for _ in range(n)] for i in range(n): array[i] = list(map(int, input().strip().split(" "))) s = Solution() print(s.findDouYouNum(array)) 2048小游戏123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105"""2048合并规则：1. 相邻会碰撞的两个相同数字合并且只会触发一次合并；2. 优先合并移动方向顶部的位置，比如 [2, 2 ,2 , 2] 行向右合并为 [0, 0, 4, 4]输入：第1行是2048块的滑动方向键。1：上、2：下、3：左、4：右。接下来4 x 4的数字矩阵用空格分割，0表示该位置没有数字。输出：用户按下房间键红后的矩阵值。示例输入：10 0 0 20 0 0 20 0 4 80 0 4 8输出：0 0 8 40 0 0 160 0 0 00 0 0 0"""def MoveUp(): for j in range(0, 4): for i in range(0, 3): if Num[i][j] != 0: continue for k in range(i+1, 4): if Num[k][j] != 0: Num[i][j], Num[k][j] = Num[k][j], Num[i][j] breakdef MoveDown(): for j in range(0, 4): for i in range(3, 0, -1): if Num[i][j] != 0: continue for k in range(i-1, -1, -1): if Num[k][j] != 0: Num[i][j], Num[k][j] = Num[k][j], Num[i][j] breakdef MoveLeft(): for i in range(0, 4): for j in range(0, 3): if Num[i][j] != 0: continue for k in range(j+1, 4): if Num[i][k] != 0: Num[i][j], Num[i][k] = Num[i][k], Num[i][j] breakdef MoveRight(): for i in range(0, 4): for j in range(3, 0, -1): if Num[i][j] != 0: continue for k in range(j-1, -1, -1): if Num[i][k] != 0: Num[i][j], Num[i][k] = Num[i][k], Num[i][j] breakdef move(direction): if direction == 1: MoveUp() for i in range(0, 3): for j in range(0, 4): if Num[i][j] == Num[i + 1][j]: Num[i][j] &lt;&lt;= 1 Num[i + 1][j] = 0 MoveUp() elif direction == 2: MoveDown() for i in range(3, 0, -1): for j in range(0, 4): if Num[i][j] == Num[i - 1][j]: Num[i][j] &lt;&lt;= 1 Num[i - 1][j] = 0 MoveDown() elif direction == 3: MoveRight() for i in range(0, 4): for j in range(3, 0, -1): if Num[i][j] == Num[i][j - 1]: Num[i][j] &lt;&lt;= 1 Num[i][j - 1] = 0 MoveRight() else: MoveLeft() for i in range(0, 4): for j in range(0, 3): if Num[i][j] == Num[i][j - 1]: Num[i][j] &lt;&lt;= 1 Num[i][j - 1] = 0 MoveLeft()if __name__=="__main__": direction = int(input()) Num = [[] for i in range(4)] for i in range(4): Num[i] = list(map(int, input().strip().split())) move(direction) print(Num) 单调栈123456789101112131415161718192021222324252627def largestRectangleArea(heights): """ Leetcode 84：柱状图中最大的矩形 :type heights: List[int] :rtype: int """ stack = list() res, i = 0, 0 while i &lt; len(heights): if not stack or heights[i] &gt;= heights[stack[-1]]: stack.append(i) i += 1 else: k = stack.pop() current_s = heights[k] * ((i - stack[-1] - 1) if stack else i) res = max(res, current_s) while stack: k = stack.pop() current_s = heights[k] * ((i - stack[-1] - 1) if stack else i) res = max(res, current_s) return resif __name__ == '__main__': heights = list(map(int, input().split(" "))) print(largestRectangleArea(heights)) 迷宫1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162class Maze: """ 给定N*M的迷宫，需要走左上角走到右下角，只能向右或者向下移动。 在迷宫中0表示没有路，1表示有路。是否存在一条可行的路径？ 例子： 迷宫行数（列数）4 迷宫 1 0 0 0 1 1 0 1 0 1 0 0 1 1 1 1 解法 1 0 0 0 1 1 0 0 0 1 0 0 0 1 1 1 """ def __init__(self, maze): self.maze = maze # 迷宫 self.N = len(maze) self.sol = [[0] * self.N for _ in range(self.N)] # 存储结果 # 打印从起点到终点的路线 def print_solution_matrix(self): for i in range(self.N): print(" ".join(map(str, self.sol[i]))) # 判断x和y是否是一个合理的单元 def is_safe(self, x, y): return x &gt;= 0 and x &lt; self.N and y &gt;= 0 and y &lt; self.N \ and self.maze[x][y] == 1 # 使用回溯的方法找到一条从左上角到右下角的路径 def get_path(self, x, y): # 达到目的地 if x == self.N - 1 and y == self.N - 1: self.sol[x][y] = 1 return True # 判断maze[x][y]是否是一个可走的单元 if self.is_safe(x, y): # 标记当前单元为1，表示可走 self.sol[x][y] = 1 # 向右走一步 if self.get_path(x + 1, y): return True # 向下走一步 if self.get_path(x, y + 1): return True # 标记当前单元为0，表示这条路不可行，然后回溯 self.sol[x][y] = 0 return False return Falseif __name__ == '__main__': n = int(input()) maze = list() for _ in range(n): maze.append(list(map(int, input().split()))) rat = Maze(maze) if rat.get_path(0, 0): rat.print_solution_matrix() else: print("不存在可达路径") 杂项1234567891011121314151617181920212223242526272829303132def schedule(R, O, M): """ 给定一台有M个存储空间的机器，有n个请求需要在这台机器上运行， 第i个请求计算需要占用R[i]的空间，计算结果需要占O[i]个空间（O[i]&lt;R[i]）。 判断这n个请求是否能全部完成？若能，给出这个n个请求的按排顺序。 """ # 按照 R[i] - O[i] 由大到小进行排序 # 可以使用归纳法证明，按照这个顺序执行的成功可能性最大。 R_O = list(zip(R, O)) R_O.sort(key=lambda item: -(item[0] - item[1])) R = [item[0] for item in R_O] O = [item[1] for item in R_O] left = M # 剩余可用的空间数 lens = len(R) i = 0 while i &lt; lens: if left &lt; R[i]: # 剩余的空间无法继续处理第i个请求 return False else: # 剩余的空间能继续处理第i个请求，处理完后将占用O[i]个空间 left -= O[i] i += 1 print("按照如下请求序列可以完成：") print(R_O) return Trueif __name__ == '__main__': n = int(input()) # 8 M = int(input()) # 50 R = list(map(int, input().split())) # 10 15 23 20 6 9 7 16 O = list(map(int, input().split())) # 2 7 8 4 5 8 6 8 print(schedule(R, O, M)) # True leetcode873. 最长的斐波那契子序列的长度 https://coordinate.wang/index.php/archives/2098/ https://blog.csdn.net/weixin_37373020/article/details/81559842 背包问题背包问题九讲 催添翼 123456789101112131415161718192021222324252627282930313233def zero_one_bag_problem(bag_v, n_weight, n_vol): """ 零一背包问题 :param bag_v: 背包体积 :param n_weight: 物品价值 :param n_vol: 物品体积 :return: 包能装的物品最大总价值 时间复杂度 O(NV)，空间复杂度O(NV) """ # 填充没有价值的物品 n_weight.insert(0, 0) n_vol.insert(0, 0) array = [[0] * (bag_v + 1) for _ in range(len(n_weight))] # 遍历物品N for i in range(1, len(n_weight)): # 遍历不同被包容量V for j in range(1, bag_v + 1): # 如果当前背包容量不能够装下第i件物品 if j &lt; n_vol[i]: array[i][j] = array[i - 1][j] else: array[i][j] = max(array[i - 1][j], array[i - 1][j - n_vol[i]] + n_weight[i]) # 打印运算过程 # for i in range(len(n_weight)): # print(array[i]) return array[-1][-1]if __name__ == '__main__': bag_v = int(input()) # 12 n_vol = list(map(int, input().strip().split(" "))) # 1 3 2 6 2 n_weight = list(map(int, input().strip().split(" "))) # 2 5 3 10 4 print(zero_one_bag_problem(bag_v, n_weight, n_vol)) # 21 123456789101112131415161718192021222324def zero_one_bag_problem(bag_v, n_weight, n_vol): """ 零一背包问题 :param bag_v: 背包体积 :param n_weight: 物品价值 :param n_vol: 物品体积 :return: 包能装的物品最大总价值 时间复杂度 O(NV)，空间复杂度O(V) """ array = [0] * (bag_v + 1) # 填充0，方便表示 # 依次遍历每个物品N for i in range(len(n_vol)): # 从大到小遍历遍历背包容量V（当背包容量小于物品容量时直接跳过） for j in range(bag_v, n_vol[i] - 1, -1): array[j] = max(array[j], array[j-n_vol[i]] + n_weight[i]) return array[-1]if __name__ == '__main__': bag_v = int(input()) # 12 n_vol = list(map(int, input().strip().split(" "))) # 1 3 2 6 2 n_weight = list(map(int, input().strip().split(" "))) # 2 5 3 10 4 print(zero_one_bag_problem(bag_v, n_weight, n_vol)) # 21 123456789101112131415161718192021222324def full_bag_problem(bag_v, n_weight, n_vol): """ 完全背包问题 :param bag_v: 背包体积 :param n_weight: 物品价值 :param n_vol: 物品体积 :return: 包能装的物品最大总价值 时间复杂度 O(NV)，空间复杂度O(V) """ array = [0] * (bag_v + 1) # 填充0，方便表示 # 依次遍历每个物品N for i in range(len(n_vol)): # 从大到小遍历遍历背包容量V（当背包容量小于物品容量时直接跳过） for j in range(n_vol[i], bag_v + 1): array[j] = max(array[j], array[j-n_vol[i]] + n_weight[i]) return array[-1]if __name__ == '__main__': bag_v = int(input()) # 15 n_vol = list(map(int, input().strip().split(" "))) # 5 4 7 2 6 n_weight = list(map(int, input().strip().split(" "))) # 12 3 10 3 6 print(complete_bag_problem(bag_v, n_weight, n_vol)) # 36 Leetcode 416：分割等和子集12345678910111213141516171819202122232425262728293031323334from typing import Listclass Solution: def canPartition(self, nums: List[int]) -&gt; bool: size = len(nums) # 特判，如果整个数组的和都不是偶数，就无法平分 s = sum(nums) if s &amp; 1 == 1: return False # 二维 dp 问题：背包的容量 target = s // 2 dp = [[False for _ in range(target + 1)] for _ in range(size)] # 先写第 1 行：看看第 1 个数是不是能够刚好填满容量为 target for i in range(target + 1): dp[0][i] = False if nums[0] != i else True # i 表示物品索引 for i in range(1, size): # j 表示容量 for j in range(target + 1): if j &gt;= nums[i]: dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i]] else: dp[i][j] = dp[i - 1][j] return dp[-1][-1]if __name__ == '__main__': nums = [1, 5, 11, 5] print(Solution().canPartition(nums)) 二分查找当数组“有序”时，考虑用二分查找。 123456789101112131415161718192021222324def binary_search_recursion(lst, val, start, end): #递归二分查找 if start &gt; end: return None mid = (start + end) // 2 if lst[mid] &lt; val: return binary_search_recursion(lst, val, mid + 1, end) if lst[mid] &gt; val: return binary_search_recursion(lst, val, start, mid - 1) return middef binary_search_loop(lst, val): #循环二分查找 start, end = 0, len(lst) - 1 while start &lt;= end: mid = (start + end) // 2 if lst[mid] &lt; val: start = mid + 1 elif lst[mid] &gt; val: end = mid - 1 else: return mid return None 二分插入和查询算法（Python源码）结论：二分查找最大比较次数为$\lfloor log_2(len(array)) \rfloor + 1$ 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788import bisect"""Bisection algorithms."""def insort_right(a, x, lo=0, hi=None): """Insert item x in list a, and keep it sorted assuming a is sorted. If x is already in a, insert it to the right of the rightmost x. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. """ if lo &lt; 0: raise ValueError('lo must be non-negative') if hi is None: hi = len(a) while lo &lt; hi: mid = (lo+hi)//2 if x &lt; a[mid]: hi = mid # Limit high-end else: lo = mid+1 a.insert(lo, x)insort = insort_right # backward compatibilitydef bisect_right(a, x, lo=0, hi=None): """Return the index where to insert item x in list a, assuming a is sorted. The return value i is such that all e in a[:i] have e &lt;= x, and all e in a[i:] have e &gt; x. So if x already appears in the list, a.insert(x) will insert just after the rightmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. """ if lo &lt; 0: raise ValueError('lo must be non-negative') if hi is None: hi = len(a) while lo &lt; hi: mid = (lo+hi)//2 if x &lt; a[mid]: hi = mid # Limit high-end else: lo = mid+1 return lobisect = bisect_right # backward compatibilitydef insort_left(a, x, lo=0, hi=None): """Insert item x in list a, and keep it sorted assuming a is sorted. If x is already in a, insert it to the left of the leftmost x. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. """ if lo &lt; 0: raise ValueError('lo must be non-negative') if hi is None: hi = len(a) while lo &lt; hi: mid = (lo+hi)//2 if a[mid] &lt; x: lo = mid+1 # Limit the low end else: hi = mid a.insert(lo, x)def bisect_left(a, x, lo=0, hi=None): """Return the index where to insert item x in list a, assuming a is sorted. The return value i is such that all e in a[:i] have e &lt; x, and all e in a[i:] have e &gt;= x. So if x already appears in the list, a.insert(x) will insert just before the leftmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. """ if lo &lt; 0: raise ValueError('lo must be non-negative') if hi is None: hi = len(a) while lo &lt; hi: mid = (lo+hi)//2 if a[mid] &lt; x: lo = mid+1 # Limit the low end else: hi = mid return lo 从 递归 到 动态规划 数据结构双向列表deque是为了高效实现插入和删除操作的双向列表，适合用于队列和栈 1234from collections import deque'append', 'appendleft', 'clear', 'copy', 'count', 'extend', 'extendleft', 'index', 'insert', 'maxlen', 'pop', 'popleft', 'remove', 'reverse', 'rotate' 计数器（Python源码）当需要对 list 中的大量数据进行计数时，可以直接使用 Counter ，而不用新建字典来计数。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546from collections import Counterclass Counter(dict): '''Dict subclass for counting hashable items. Sometimes called a bag or multiset. Elements are stored as dictionary keys and their counts are stored as dictionary values. &gt;&gt;&gt; c = Counter('abcdeabcdabcaba') # count elements from a string &gt;&gt;&gt; c.most_common(3) # three most common elements [('a', 5), ('b', 4), ('c', 3)] &gt;&gt;&gt; sorted(c) # list all unique elements ['a', 'b', 'c', 'd', 'e'] &gt;&gt;&gt; ''.join(sorted(c.elements())) # list elements with repetitions 'aaaaabbbbcccdde' &gt;&gt;&gt; sum(c.values()) # total of all counts 15 &gt;&gt;&gt; c['a'] # count of letter 'a' 5 &gt;&gt;&gt; for elem in 'shazam': # update counts from an iterable ... c[elem] += 1 # by adding 1 to each element's count &gt;&gt;&gt; c['a'] # now there are seven 'a' 7 &gt;&gt;&gt; del c['b'] # remove all 'b' &gt;&gt;&gt; c['b'] # now there are zero 'b' 0 &gt;&gt;&gt; d = Counter('simsalabim') # make another counter &gt;&gt;&gt; c.update(d) # add in the second counter &gt;&gt;&gt; c['a'] # now there are nine 'a' 9 &gt;&gt;&gt; c.clear() # empty the counter &gt;&gt;&gt; c Counter() Note: If a count is set to zero or reduced to zero, it will remain in the counter until the entry is deleted or the counter is cleared: &gt;&gt;&gt; c = Counter('aaabbc') &gt;&gt;&gt; c['b'] -= 2 # reduce the count of 'b' by two &gt;&gt;&gt; c.most_common() # 'b' is still in, but its count is zero [('a', 3), ('c', 1), ('b', 0)] ''' 链表与数组相互转换123456789101112131415161718192021222324252627282930313233343536373839class Linked_list_node: def __init__(self, x): self.val = x self.next = Nonedef linked_list_to_array(head): array = [] while head: array.append(head.val) head = head.next return arraydef array_to_linked_list(array): ans = Linked_list_node(0) t = ans for item in array: t.next = Linked_list_node(item) t = t.next return ans.nextdef print_linked_list(head): while head: print(head.val, end=" ") head = head.next print("")if __name__=='__main__': array = [1, 3, 5, 7, 9] print("array: ", array) head = array_to_linked_list(array) print("print_linked_list: ") print_linked_list(head) array2 = linked_list_to_array(head) print("array2: ", array2) Leetcode 206:反转链表Leetcode 206:反转链表（最详细解决方案！！！） 123456789101112131415161718192021222324252627282930313233343536# Definition for singly-linked list.class ListNode: def __init__(self, x): self.val = x self.next = Nonedef reverseList_1(head): pre = None cur = head while cur != None: lat = cur.next cur.next = pre pre = cur cur = lat return predef reverseList_2(head): if not head or not head.next: # 如果输入结点是空，或只有一个结点，返回即可 return head else: newHead = reverseList_2(head.next) # 将下一个结点之后的部分逆序 head.next.next = head # 反转当前结点 head.next = None # 设置当前结点的下一个结点为None return newHeaddef reverseList_3(head): if not head or not head.next: # 如果输入结点是空，或只有一个结点，返回即可 return head temp = ListNode(0) current_p = head while current_p: c = current_p.next current_p.next = temp.next temp.next = current_p current_p = c return temp.next]]></content>
      <categories>
        <category>数学</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[使用语言模型GPT2来解决文本生成任务]]></title>
    <url>%2F2019%2F08%2F27%2Ftext-generation%2F</url>
    <content type="text"><![CDATA[The first part of this resource pool summarizes the resources used to solve text generation tasks using the language model GPT2, including papers, code, demo demos, and hands-on tutorials. The second part shows the application of GPT2 in the text generation tasks of machine translation, automatic summary generation, migration learning and music generation. Finally, the 15 major language models based on Transformer between 2018 and 2019 are compared. 本资源汇第一部分汇总了使用语言模型GPT2来解决文本生成任务的资源，包括论文、代码、展示demo和动手教程。第二部展示了GPT2在机器翻译、自动摘要生成、迁移学习和音乐生成这些文本生成任务上的应用。最后对比了2018-2019年间重要的基于Transformer的15个语言模型 GPT-2GPT-2 is a large transformer-based language model released by OpenAI in February 2019. It contains 1.5 billion parameters and is trained on a 8 million web dataset. According to reports, the model is a direct extension of the GPT model, training on more than 10 times the amount of data, the parameter amount is also 10 times more. In terms of performance, the model is capable of producing coherent text paragraphs and achieves SOTA performance on many language modeling benchmarks. Moreover, the model can perform preliminary reading comprehension, machine translation, question and answer and automatic summarization without task-specific training. GPT-2是OpenAI于2019年2月发布的基于 transformer 的大型语言模型，包含 15 亿参数、在一个 800 万网页数据集上训练而成。据介绍，该模型是对 GPT 模型的直接扩展，在超出 10 倍的数据量上进行训练，参数量也多出了 10 倍。在性能方面，该模型能够生产连贯的文本段落，在许多语言建模基准上取得了 SOTA 表现。而且该模型在没有任务特定训练的情况下，能够做到初步的阅读理解、机器翻译、问答和自动摘要。 主页 OpenAI Homepage : Better Language Models and Their Implications 代码 Code : gpt-2 论文 OpenAI 2019 Paper : Language Models are Unsupervised Multitask Learners GPT-2 DemoGPT-2_Explorer Demo It can give the next ten words of the possibility ranking and their corresponding probabilities according to the currently input text. You can select one of the words, then see the list of the next possible word, and so on, and finally complete one. Article. GPT-2_Explorer Demo 它可以根据当前输入的文本给出可能性排名前十的下一个单词及其对应概率，你可以选择其中一个单词，然后看到下一个可能单词的列表，如此往复，最终完成一篇文章。 点击体验 Click to GPT-2 Explorer Demo Write With Transformer Demo Write With Transformer GPT-2 elevant articles 效果惊人的GPT 2.0模型：它告诉了我们什么 张俊林 完全图解GPT-2：看完这篇就够了（一） 完全图解GPT-2：看完这篇就够了（二） The Illustrated GPT-2 (Visualizing Transformer Language Models) hands-on GPT-2 GPT-2 试用总结及感想 GPT-2-simpleGPT-2-simple Python package to easily retrain OpenAI’s GPT-2 text-generating model on new texts. GPT-2-simple Python包可以轻松地在新文本上重新训练OpenAI的GPT-2文本生成模型。 代码 Code : gpt-2-simple GPT-2-simple DemoGPT-2-simple Demo Writes a follow-up story based on the current input text.GPT-2-simple Demo 根据当前输入文本编写后续的故事。 点击体验 Click to gpt-2-simple Demo grover: OpenGPT-2Grover is a model for Neural Fake News — both generation and detection.Grover是神经虚假新闻的模型 - 生成和检测。 项目主页 Project Home : Grover: A State-of-the-Art Defense against Neural Fake News 代码 Code : grover 论文 2019 Paper : Defending Against Neural Fake News grover demoGenerate articles based on information such as title, author, and more. Grover can also detect if text is generated by the machine. 根据标题、作者等信息生成文章。grover 还可以检测文本是否由机器生成。 点击体验 Click to GROVER grover elevant articles OpenGPT-2: We Replicated GPT-2 Because You Can Too Counteracting neural disinformation with Grover 15亿参数的GPT-2被两个CS硕士复制出来了，没有语言建模经验，花了5万美元 语言建模之外 Beyond Language ModelingClick to read the English version 只包含解码器的 transformer （比如GPT2）不断地表现出在语言建模之外的应用前景。在许多应用程序中，这类模型已经取得了成功：机器翻译、自动摘要生成、迁移学习和音乐生成。让我们一起来回顾一下其中的一些应用。 机器翻译进行翻译时，模型不需要编码器。同样的任务可以通过一个只有解码器的 transformer 来解决： 自动摘要生成这是第一个训练只包含解码器的 transformer 的任务。也就是说，该模型被训练来阅读维基百科的文章（没有目录前的开头部分），然后生成摘要。文章实际的开头部分被用作训练数据集的标签： 论文使用维基百科的文章对模型进行了训练，训练好的模型能够生成文章的摘要： 迁移学习在论文 Sample Efficient Text Summarization Using a Single Pre-Trained Transformer中，首先使用只包含解码器的 transformer 在语言建模任务中进行预训练，然后通过调优来完成摘要生成任务。结果表明，在数据有限的情况下，该方案比预训练好的编码器-解码器 transformer 得到了更好的效果。GPT2 的论文也展示了对语言建模模型进行预训练后取得的摘要生成效果。 音乐生成音乐 transformer 采用了只包含解码器的 transformer 来生成具有丰富节奏和动感的音乐。和语言建模相似，「音乐建模」就是让模型以一种无监督的方式学习音乐，然后让它输出样本（我们此前称之为「随机工作」）。 了解更多基于 Transformer 的模型GPT2只是基于 Transformer 的模型的沧海一粟，2018-2019年的15个重要的基于Transformer 的模型的对比可以参见 后BERT时代：15个预训练模型对比分析与关键点探索]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>文本生成</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[中文文本纠错]]></title>
    <url>%2F2019%2F08%2F18%2F%E4%B8%AD%E6%96%87%E6%96%87%E6%9C%AC%E7%BA%A0%E9%94%99%2F</url>
    <content type="text"><![CDATA[中英文本纠错的差异英文的拼写错误，大致可以分为两类：一类是英文单词拼写不合法（Non-Word Errors），造成错误的“词”在词典里没有对应的单词（Word），比如把artificial拼成artificel；还有一类是单词拼写合法，但在语境中错误（Real-Word Errors），比如把be interested in写成be interest in。与拼写不合法相比，这类错误更难被纠正。前者一般使用上下文无关（Context-Independent Methods）的方法解决，后者则通常使用上下文相关（Context-Dependent Methods）的方法识别。 在中文领域，纠错仍然是一道险关，因为很多中文的错误情况并不会在英文语境中发生。这是因为，英文是输入单个字母，组成词汇和句子，没有“输入法”的概念，最小处理单元是一个“单词”；而对于中文而言，我们依赖输入法来打字，而计算机显示的汉字字形都是预先设置好的，不会存在字形“无中生有”的情况，因此纠错处理单元针对的中文“词”，相当于英语的“词组（Phrase）”。中文语境出现的错误，错法往往千奇百怪：有输入法联想错误导致输入其他同音词，由此出现的搭配不当；有发音不准导致拼音输错；还有形近字、几乎约定俗成的错字等等，很难有成熟的规律一网打尽。汉语的表达主观且多样，如果没有海量语料来训练模型，则试验很难取得成效。因此，可以说，汉语的文本纠错难度要大大高于英语。 开源文本纠错工具pycorrectorpycorrector GitHub 中文文本纠错工具。音似、形似错字（或变体字）纠正，可用于中文拼音、笔画输入法的错误纠正。python3开发。pycorrector依据语言模型检测错别字位置，通过拼音音似特征、笔画五笔编辑距离特征及语言模型困惑度特征纠正错别字。 问题中文文本纠错任务，常见错误类型包括： 谐音字词，如 配副眼睛-配副眼镜 混淆音字词，如 流浪织女-牛郎织女 字词顺序颠倒，如 伍迪艾伦-艾伦伍迪 字词补全，如 爱有天意-假如爱有天意 形似字错误，如 高梁-高粱 中文拼音全拼，如 xingfu-幸福 中文拼音缩写，如 sz-深圳 语法错误，如 想象难以-难以想象 当然，针对不同业务场景，这些问题并不一定全部存在，比如输入法中需要处理前四种，搜索引擎需要处理所有类型，语音识别后文本纠错只需要处理前两种， 其中’形似字错误’主要针对五笔或者笔画手写输入等。 解决方案规则的解决思路 中文纠错分为两步走，第一步是错误检测，第二步是错误纠正； 错误检测部分先通过结巴中文分词器切词，由于句子中含有错别字，所以切词结果往往会有切分错误的情况，这样从字粒度和词粒度两方面检测错误， 整合这两种粒度的疑似错误结果，形成疑似错误位置候选集； 错误纠正部分，是遍历所有的疑似错误位置，并使用音似、形似词典替换错误位置的词，然后通过语言模型计算句子困惑度，对所有候选集结果比较并排序，得到最优纠正词。 深度模型的解决思路 端到端的深度模型可以避免人工提取特征，减少人工工作量，RNN序列模型对文本任务拟合能力强，rnn_attention在英文文本纠错比赛中取得第一名成绩，证明应用效果不错； CRF会计算全局最优输出节点的条件概率，对句子中特定错误类型的检测，会根据整句话判定该错误，阿里参赛2016中文语法纠错任务并取得第一名，证明应用效果不错； seq2seq模型是使用encoder-decoder结构解决序列转换问题，目前在序列转换任务中（如机器翻译、对话生成、文本摘要、图像描述）使用最广泛、效果最好的模型之一。 pycorrector文本纠错库中含有的神经网络模型举例 kenlm：kenlm统计语言模型工具 rnn_lm：TensorFlow、PaddlePaddle均有实现栈式双向LSTM的语言模型 rnn_attention模型：参考Stanford University的nlc模型，该模型是参加2014英文文本纠错比赛并取得第一名的方法 rnn_crf模型：参考阿里巴巴2016参赛中文语法纠错比赛CGED2018并取得第一名的方法 seq2seq_attention模型：在seq2seq模型加上attention机制，对于长文本效果更好，模型更容易收敛，但容易过拟合 transformer模型：全attention的结构代替了lstm用于解决sequence to sequence问题，语义特征提取效果更好 bert模型：中文fine-tuned模型，使用MASK特征纠正错字 conv_seq2seq模型：基于Facebook出品的fairseq，北京语言大学团队改进ConvS2S模型用于中文纠错，在NLPCC-2018的中文语法纠错比赛中，是唯一使用单模型并取得第三名的成绩 中文文本纠错方法举例参见 中文汉字错别字纠错方法 CSDN使用语言模型计算句子合法的概率，当概率值小于指定阈值时认为句子非法，即句子可能存在错误。中文文本的错别字存在局部性，即我们只需要选取合理的滑动窗口来检查是否存在错别字，下面举一个例子： 现实生活中也存在汉字拼音没打错，是词语选错了；或者n-gram检查合理但词语不存在。例如： 这时就用到最短编辑距离了，对于这种热搜词，我们仅需记录n-Top，然后用最短编辑距离计算相似度，提供相似度最高的那个候选项就可以了。编辑距离，又称Levenshtein距离，是指两个字串之间，由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符，插入一个字符，删除一个字符。 现有商用文本纠错技术探究参见 中文文本纠错算法走到多远了？ CSDN 体验： 百度文本纠错 腾讯文本纠错API 云查错]]></content>
      <categories>
        <category>机器学习</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[机器学习中的常识性问题]]></title>
    <url>%2F2019%2F08%2F16%2F%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E4%B8%AD%E7%9A%84%E5%B8%B8%E8%AF%86%E6%80%A7%E9%97%AE%E9%A2%98%2F</url>
    <content type="text"><![CDATA[网页版是最新的，PDF版不定期更新，建议直接从网页版导出PDF 《机器学习中的常识性问题》 手机扫码阅读 机器学习中的常识性问题定义：作为一名合格的机器学习从业人员必须理解和熟练掌握的机器学习领域的问题。 1. 网页版：https://yuanxiaosc.github.io/2019/08/16/机器学习中的常识性问题/ 2. 百度网盘 链接：https://pan.baidu.com/s/1NG-xnDm0_4OYkpvMfBDKIw, 提取码：5kra 3. 《机器学习宝典》（涵盖本文及扩展内容）： https://github.com/yuanxiaosc/Machine-Learning-Book 欢迎Star和分享 4. 编者：袁宵 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 机器学习的预备知识概率论和信息论 《机器学习相关的概率论和信息论基础知识》 系统性总结了学习机器学习所需的概率论和信息论基础知识。 通过使用概率论，可以计算事件Y在事件X发生时的概率，这是很多机器学习的算法的构建模型的基础，比如建模Y=f(X)。通过使用信息论，可以描述随机事件的信息量也可以计算两种概率分布的差异，而后者是机器学习模型通常要优化的目标，比如度量模型预测分布和数据分布的差异。 张量 神经网络的输入、输出、权重都是张量，神经网络中的各种计算和变换就是对张量操作，张量这种数据结构是神经网络的基石，可以说没有理解张量就没有真正理解神经网络和人工智能。《理解张量》系统性总结了学习机器学习所需的张量知识。 张量（tensor）是一个多维数组（multidimensional arrays），即一种存储数字集合的数据结构，这些数字可通过索引（index）单独访问，并可通过多个索引进行索引。 机器学习知识点（彩图版） 机器学习知识点（彩图版）以生动形象的图片描述机器学习中的知识点，是入门机器学习的好资源也是本文内容的补充。 例子：机器学习彩图版-偏差和方差的权衡 机器学习和深度学习的概念机器学习是一门多领域交叉学科，涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为，以获取新的知识或技能，重新组织已有的知识结构使之不断改善自身的性能。它是人工智能的核心，是使计算机具有智能的根本途径。 （图片来自论文 Deep Reinforcement Learning） 机器学习和深度学习的关系 参见《动手学深度学习》 阿斯顿·张（Aston Zhang） / 李沐（Mu Li）第一章 深度学习简介 机器学习研究如何使计算机系统利用经验改善性能。它是人工智能领域的分支，也是实现人工智能的一种手段。在机器学习的众多研究方向中，表征学习关注如何自动找出表示数据的合适方式，以便更好地将输入变换为正确的输出。在每一级（从原始数据开始），深度学习通过简单的函数将该级的表示变换为更高级的表示。因此，深度学习模型也可以看作是由许多简单函数复合而成的函数。当这些复合的函数足够多时，深度学习模型就可以表达非常复杂的变换。 深度学习可以逐级表示越来越抽象的概念或模式。以图像为例，它的输入是一堆原始像素值。深度学习模型中，图像可以逐级表示为特定位置和角度的边缘、由边缘组合得出的花纹、由多种花纹进一步汇合得到的特定部位的模式等。最终，模型能够较容易根据更高级的表示完成给定的任务，如识别图像中的物体。值得一提的是，作为表征学习的一种，深度学习将自动找出每一级表示数据的合适方式。 深度学习的一个外在特点是端到端的训练。也就是说，并不是将单独调试的部分拼凑起来组成一个系统，而是将整个系统组建好之后一起训练。比如说，计算机视觉科学家之前曾一度将特征抽取与机器学习模型的构建分开处理，像是Canny边缘探测和SIFT特征提取曾占据统治性地位达10年以上，但这也就是人类能找到的最好方法了。当深度学习进入这个领域后，这些特征提取方法就被性能更强的自动优化的逐级过滤器替代了。 相似地，在自然语言处理领域，词袋模型多年来都被认为是不二之选。词袋模型是将一个句子映射到一个词频向量的模型，但这样的做法完全忽视了单词的排列顺序或者句中的标点符号。不幸的是，我们也没有能力来手工抽取更好的特征。但是自动化的算法反而可以从所有可能的特征中搜寻最好的那个，这也带来了极大的进步。例如，语义相关的词嵌入能够在向量空间中完成如下推理：“柏林 - 德国 + 中国 = 北京”。可以看出，这些都是端到端训练整个系统带来的效果。 相对其它经典的机器学习方法而言，深度学习的不同在于：对非最优解的包容、对非凸非线性优化的使用，以及勇于尝试没有被证明过的方法。这种在处理统计问题上的新经验主义吸引了大量人才的涌入，使得大量实际问题有了更好的解决方案。尽管大部分情况下需要为深度学习修改甚至重新发明已经存在数十年的工具，但是这绝对是一件非常有意义并令人兴奋的事。 统计机器学习三要素：模型、策略与算法的区别与联系 参见李航《统计学习方法》第1章 统计学习方法概论 统计机器学习是关于计算机基于数据构建概率统计模型并运用模型对数据进行预测与分析的一门学科。统计机器学习方法的三要素就是：模型、策略和算法。 模型。在监督学习过程中，模型就是所要学习的条件概率分布或决策函数。数据构成假设空间，在这个假设空间中包含所有可能的条件概率分布或者决策函数，每一个条件概率分布或者决策函数对应一个模型，那么这个样本空间中的模型个数有无数个。 策略。策略即从假设空间中挑选出参数最优的模型的准则。模型的分类或预测结果与实际情况的误差(损失函数)越小，模型就越好。 算法。算法是指学习模型的具体计算方法，也就是如何求解全局最优解，并使得这个过程高效而且准确，本质上就是计算机算法，怎么去求数学问题的最优化解。 统计机器学习基于训练数据集，根据学习策略，从假设空间中选择最优模型、最后需要考虑用什么样的计算方法（算法）求解最优模型，所以我们可以认为统计机器学习都是由模型、策略和算法构成的。统计学习方法之间的不同，主要来自其模型、策略、算法的不同。确定了模型、策略、算法，统计学习的方法也就确定了。 在深度学习中，可以更加狭隘地理解为：模型就是模型结构（DNN、CNN、LSTM、Transformer），策略就是损失函数（均方差、交叉熵），算法就是优化算法（SGD、Adam）。 模型训练、预测与评估的关系 以文本分类为例说明解决机器学习问题的工作流程 更多内容参见 文本分类_谷歌机器学习指南 以下是用于解决机器学习问题的工作流程的高度概述： Step 1: Gather Data 获取数据 Step 2: Explore Your Data 探索数据 Step 2.5: Choose a Model* 选择模型 Step 3: Prepare Your Data 准备数据 Step 4: Build, Train, and Evaluate Your Model 构建、训练和评估模型 Step 5: Tune Hyperparameters 调参 Step 6: Deploy Your Model 发布模型 归纳偏置：奥卡姆剃刀 更多内容参见 归纳偏置 百度百科 和 Mitchell, T.M. (1980). The need for biases in learning generalizations. CBM-TR 5-110, Rutgers University, New Brunswick, NJ. 当学习器去预测其未遇到过的输入的结果时，会做一些假设（Mitchell, 1980）。而学习算法中归纳偏置则是这些假设的集合。 一个典型的归纳偏置例子是奥卡姆剃刀。奥卡姆剃刀（英语：Occam’s Razor, Ockham’s Razor），又称“奥坎的剃刀”，拉丁文为lex parsimoniae，意思是简约之法则，是由14世纪逻辑学家、圣方济各会修士奥卡姆的威廉提出的一个解决问题的法则，他在《箴言书注》2卷15题说“切勿浪费较多东西，去做‘用较少的东西，同样可以做好的事情’。”换一种说法，如果关于同一个问题有许多种理论，每一种都能作出同样准确的预言，那么应该挑选其中使用假定最少的。尽管越复杂的方法通常能做出越好的预言，但是在不考虑预言能力（即结果大致相同）的情况下，假设越少越好。 所罗门诺夫的归纳推理理论是奥卡姆剃刀的数学公式化：在所有能够完美描述已有观测的可计算理论中，较短的可计算理论在估计下一次观测结果的概率时具有较大权重。 在自然科学中，奥卡姆剃刀被作为启发法技巧来使用，更多地作为帮助科学家发展理论模型的工具，而不是在已经发表的理论之间充当裁判角色。在科学方法中，奥卡姆剃刀并没有被当做逻辑上不可辩驳的定理或者科学结论。在科学方法中对简单性的偏好，是基于可证伪性的标准。对于某个现象的所有可接受的解释，都存在无数个可能的、更为复杂的变体：因为你可以把任何解释中的错误归结于特例假设，从而避免该错误的发生。所以，较简单的理论比复杂的理论更好，因为它们更加可检验。 机器学习试图去建造一个可以学习的算法，用来预测某个目标的结果。要达到此目的，要给于学习算法一些训练样本，样本说明输入与输出之间的预期关系。然后假设学习器在预测中逼近正确的结果，其中包括在训练中未出现的样本。既然未知状况可以是任意的结果，若没有其它额外的假设，这任务就无法解决。这种关于目标函数的必要假设就称为归纳偏置。 以下是机器学习中常见的归纳偏置列表： 最大条件独立性（conditional independence）：如果假说能转成贝叶斯模型架构，则试着使用最大化条件独立性。这是用于朴素贝叶斯分类器（Naive Bayes classifier）的偏置。 最小交叉验证误差：当试图在假说中做选择时，挑选那个具有最低交叉验证误差的假说，虽然交叉验证看起来可能无关偏置，但天下没有免费的午餐理论显示交叉验证已是偏置的。 最大边界：当要在两个类别间画一道分界线时，试图去最大化边界的宽度。这是用于支持向量机的偏置,它假设不同的类别是由宽界线来区分。 最小描述长度（Minimum description length）：当构成一个假设时，试图去最小化其假设的描述长度。假设越简单，越可能为真的。见奥卡姆剃刀。 最少特征数（Minimum features）：除非有充分的证据显示一个特征是有效用的，否则它应当被删除。这是特征选择（feature selection）算法背后所使用的假设。 最近邻居：假设在特征空间（feature space）中一小区域内大部分的样本是同属一类。给一个未知类别的样本，猜测它与它最紧接的大部分邻居是同属一类。这是用于最近邻居法的偏置。这个假设是相近的样本应倾向同属于一类别。 以下是深度学习中常见的归纳偏置列表： 还需要根据 Relational inductive biases, deep learning, and graph network 完善 CNN的归纳偏置应该是locality和spatial invariance，即空间相近的grid elements有联系而远的没有，和空间不变性（kernel权重共享） RNN的归纳偏置是sequentiality和time invariance，即序列顺序上的timesteps有联系，和时间变换的不变性（rnn权重共享） 输入空间、输出空间与特征空间的关系 概念 解释 输入空间 输入X可能取值的空间 输出空间 输出Y可能取值的空间 特征空间 输入的具体实例通常由特征向量来表示,这是所有特征向量存在的空间称为特征空间 注释： 输入与输出空间可以是有限元的集合,也可以是整个欧式空间 输入与输出空间可以是同一个空间,也可以是不同空间,通常输出空间远小于输入空间 输入与输出又称为样本或者样本点 特征空间的每一维对应一个特征 有时可以假设输入空间与特征空间为相同的空间,不做区分 有时假设输入空间与特征空间为不同空间,并将实例从输出空间映射到特征空间 模型实际上都是定义在特征空间上的 比如，SVM的核函数，将输入从输入空间映射到特征空间得到特征向量之间的内积。通过在这个特征空间上学习线性支持向量机，实现了在输入空间中对非线性支持向量机的学习。（摘自《统计学习方法》李航，第95页） 机器学习十大经典算法 本节介绍了 10 大常用机器学习算法，包括线性回归、Logistic 回归、线性判别分析、朴素贝叶斯、KNN、随机森林。 注意，这里“算法”一词是广义上的算法，注意与统计机器学习三要素（模型、策略与算法）中的算法概念区分。 机器学习必学10大算法 机器学习算法优缺点对比及选择（汇总篇） 机器学习算法选择 逻辑回归下面只列出几个重要的知识点，逻辑回归的系统介绍可以参看【机器学习】逻辑回归（非常详细） 概率与logit（几率）的关系Logit 维基百科 Logit模型和Logistic模型的区别与联系？ Logistic回归中的Logit函数和sigmoid函数的关系？ 逻辑回归与线性回归的区别与联系？本质区别：逻辑回归处理的是分类问题，线性回归处理的是回归问题。联系：如果把一个事件的几率（odd）定义为该事件发生的概率与该事件不发生的概率的比值$\dfrac {p}{1-p}$，那么逻辑回归可以看作是对于“y=1|x”（将输入x预测为正样本的概率）这一事件的对数几率的线性回归。 支持向量机 支持向量机系统性总结看July的著名博文支持向量机通俗导论（理解SVM的三层境界） 深度学习中的基础模型结构TODO：完善CV和NLP中的基础模型结构 画出循环神经网络中的RNN_cell、GRU、LSTM的结构图，并说明图中各部分的作用 更多内容参见 TensorFlow_rnn_cell_impl源码阅读 基本常用的RNN单元，如LSTM（长短期记忆）或GRU（门控循环单元）的基本计算公式是：(output, next_state) = call(input, state) RNN_cell LSTM GRU 画出Transformer的模型结构图，并说明图中各部分的作用 更多内容参见 Attention is All You Need 解析并结合 Transformer 代码实现 模型结构相关的计算题 更多内容参见 深度学习中的计算题 机器学习中的损失函数 更多内容参见 常用损失函数小结 通常机器学习每一个算法中都会有一个目标函数，算法的求解过程是通过对这个目标函数优化的过程。在分类或者回归问题中，通常使用损失函数（代价函数）作为其目标函数。损失函数用来评价模型的预测值和真实值不一样的程度，在测试集上损失函数值越小，通常模型的性能越好。不同的算法使用的损失函数不一样。损失函数分为经验风险损失函数和结构风险损失函数。经验风险损失函数指预测结果和实际结果的差别，结构风险损失函数是指经验风险损失函数加上正则项。 交叉熵损失函数 分开定义softmax运算和交叉熵损失函数可能会造成数值不稳定。 sigmoid和softmax后面接的两种不同交叉熵损失函数的比较 两种形式的二分类交叉熵损失函数的推导 更多内容参见 简单的交叉熵损失函数，你真的懂了吗？ 对于类别标签为0和1的二分类交叉熵损失函数是： Loss=-y log \hat y - (1-y) log (1 - \hat y)对于类别标签为1和-1的二分类交叉熵损失函数是： Loss=log (1 + e^{-y \hat y})为什么结合sigmoid激活函数和交叉熵损失函数能保证数值稳定？ 更多内容参见TensorFlow源码 nn.sigmoid_cross_entropy_with_logits 1234567891011121314For brevity, let `x = logits`, `z = labels`. The logistic loss is z * -log(sigmoid(x)) + (1 - z) * -log(1 - sigmoid(x)) = z * -log(1 / (1 + exp(-x))) + (1 - z) * -log(exp(-x) / (1 + exp(-x))) = z * log(1 + exp(-x)) + (1 - z) * (-log(exp(-x)) + log(1 + exp(-x))) = z * log(1 + exp(-x)) + (1 - z) * (x + log(1 + exp(-x)) = (1 - z) * x + log(1 + exp(-x)) = x - x * z + log(1 + exp(-x))For x &lt; 0, to avoid overflow in exp(-x), we reformulate the above x - x * z + log(1 + exp(-x)) = log(exp(x)) - x * z + log(1 + exp(-x)) = - x * z + log(1 + exp(x))Hence, to ensure stability and avoid overflow, the implementation uses thisequivalent formulation max(x, 0) - x * z + log(1 + exp(-abs(x))) 机器学习中的优化算法在训练模型时，我们会使用优化算法不断迭代模型参数以降低模型损失函数的值。当迭代终止时，模型的训练随之终止，此时的模型参数就是模型通过训练所学习到的参数。 优化算法对于深度学习十分重要。一方面，训练一个复杂的深度学习模型可能需要数小时、数日，甚至数周时间，而优化算法的表现直接影响模型的训练效率；另一方面，理解各种优化算法的原理以及其中超参数的意义将有助于我们更有针对性地调参，从而使深度学习模型表现更好。 优化与深度学习的关系由于优化算法的目标函数通常是一个基于训练数据集的损失函数，优化的目标在于降低训练误差。 而深度学习的目标在于降低泛化误差。为了降低泛化误差，除了使用优化算法降低训练误差以外，还需要注意应对过拟合。本章中，我们只关注优化算法在最小化目标函数上的表现，而不关注模型的泛化误差。 反向传播算法反向传播（英语：Backpropagation，缩写为BP）是“误差反向传播”的简称，是一种与最优化方法（如梯度下降法）结合使用的，用来训练人工神经网络的常见方法。该方法计算对网络中所有权重计算损失函数的梯度。这个梯度会反馈给最优化方法，用来更新权值以最小化损失函数。 在神经网络上执行梯度下降法的主要算法。该算法会先按前向传播方式计算（并缓存）每个节点的输出值，然后再按反向传播遍历图的方式计算损失函数值相对于每个参数的偏导数。 BP算法的学习过程由正向传播过程和反向传播过程组成。在正向传播过程中，输入信息通过输入层经隐含层，逐层处理并传向输出层。如果在输出层得不到期望的输出值，则取输出与期望的误差的平方和作为目标函数，转入反向传播，逐层求出目标函数对各神经元权值的偏导数，构成目标函数对权值向量的梯量，作为修改权值的依据，网络的学习在权值修改过程中完成。误差达到所期望值时，网络学习结束。 反向传播算法的四个基本方程如下，详细证明过程可参看《反向传播算法-by袁宵》 梯度下降算法 深度学习中的梯度消失、爆炸原因及其解决方法 参见 详解深度学习中的梯度消失、爆炸原因及其解决方法 和 出现梯度消失与梯度爆炸的原因以及解决方案 梯度消失、爆炸和不稳定的概念 梯度不稳定：在深度神经网络中的梯度是不稳定的，在靠近输入层的隐藏层中或会消失，或会爆炸。这种不稳定性才是深度神经网络中基于梯度学习的根本问题。产生梯度不稳定的根本原因：前面层上的梯度是来自后面层上梯度的乘积。当存在过多的层时，就会出现梯度不稳定场景，比如梯度消失和梯度爆炸。 梯度消失：在神经网络中，当前面隐藏层的学习速率低于后面隐藏层的学习速率，即随着隐藏层数目的增加，分类准确率反而下降了。这种现象叫梯度消失。 梯度爆炸：在神经网络中，当前面隐藏层的学习速率低于后面隐藏层的学习速率，即随着隐藏层数目的增加，分类准确率反而下降了。这种现象叫梯度爆炸。 梯度消失与梯度爆炸的产生原因 梯度消失：（1）隐藏层的层数过多；（2）采用了不合适的激活函数(更容易产生梯度消失，但是也有可能产生梯度爆炸) 梯度爆炸：（1）隐藏层的层数过多；（2）权重的初始化值过大 梯度消失与梯度爆炸的解决方案梯度消失和梯度爆炸问题都是因为网络太深，网络权值更新不稳定造成的，本质上是因为梯度反向传播中的连乘效应。对于更普遍的梯度消失问题，可以考虑一下三种方案解决： 从激活函数的角度。用ReLU、Leaky-ReLU、P-ReLU、R-ReLU、Maxout等替代sigmoid函数。 从模型结构的角度。用Batch Normalization和残差连接，LSTM的结构设计也可以改善RNN中的梯度消失问题。 从梯度值本身的角度。梯度剪切、正则。这个方案主要是针对梯度爆炸提出的，其思想是设值一个剪切阈值，如果更新梯度时，梯度超过了这个阈值，那么就将其强制限制在这个范围之内。这样可以防止梯度爆炸。另一种防止梯度爆炸的手段是采用权重正则化，正则化主要是通过对网络权重做正则来限制过拟合，但是根据正则项在损失函数中的形式可以看出，如果发生梯度爆炸，那么权值的范数就会变的非常大，反过来，通过限制正则化项的大小，也可以在一定程度上限制梯度爆炸的发生。 指数加权移动平均与动量法 目标函数有关自变量的梯度代表了目标函数在自变量当前位置下降最快的方向。因此，梯度下降也叫作最陡下降（steepest descent）。在每次迭代中，梯度下降根据自变量当前位置，沿着当前位置的梯度更新自变量。然而，如果自变量的迭代方向仅仅取决于自变量当前位置，这可能会带来一些问题。 同一位置上，目标函数在竖直方向（ x2 轴方向）比在水平方向（ x1 轴方向）的斜率的绝对值更大。因此，给定学习率，梯度下降迭代自变量时会使自变量在竖直方向比在水平方向移动幅度更大。那么，我们需要一个较小的学习率从而避免自变量在竖直方向上越过目标函数最优解。然而，这会造成自变量在水平方向上朝最优解移动变慢。 下面我们试着将学习率调得稍大一点，此时自变量在竖直方向不断越过最优解并逐渐发散。 动量法使用了指数加权移动平均的思想。它将过去时间步的梯度做了加权平均，且权重按时间步指数衰减。动量法使得相邻时间步的自变量更新在方向上更加一致。 SGD、AdaGrad、RMSProp、AdaDelta和Adam基于梯度的优化算法关系 AdaGrad算法AdaGrad算法，它根据自变量在每个维度的梯度值的大小来调整各个维度上的学习率，从而避免统一的学习率难以适应所有维度的问题。 RMSProp算法我们在“AdaGrad算法”一节中提到，因为调整学习率时分母上的变量 $s_t$ 一直在累加按元素平方的小批量随机梯度，所以目标函数自变量每个元素的学习率在迭代过程中一直在降低（或不变）。因此，当学习率在迭代早期降得较快且当前解依然不佳时，AdaGrad算法在迭代后期由于学习率过小，可能较难找到一个有用的解。为了解决这一问题，RMSProp算法对AdaGrad算法做了一点小小的修改。 AdaDelta算法除了RMSProp算法以外，另一个常用优化算法AdaDelta算法也针对AdaGrad算法在迭代后期可能较难找到有用解的问题做了改进。AdaDelta算法没有学习率超参数，它通过使用有关自变量更新量平方的指数加权移动平均的项来替代RMSProp算法中的学习率。 Adam算法Adam算法在RMSProp算法基础上对小批量随机梯度也做了指数加权移动平均。 在小批量梯度下降算法使用中的注意事项以下仅为经验结论，一切以具体实验结果为准： 批量大小一般选取2的正数次幂，例如32、64、128、256等。这样能充分利用矩阵运算操作。 挑选的批量数据要具有随机性，避免数据的特定顺序给算法收敛带来不良影响。 选取较优的学习速度，为了加快收敛速度，同时提高求解精度，通常会采用衰减学习速率的方案：一开始算法采用较大的学习速率，当误差曲线进入平台期后，减小学习速率做更精细的调整。 锯齿现象（zig-zagging）梯度下降方法得到的是局部最优解，如果目标函数是一个凸优化问题，那么局部最优解就是全局最优解，理想的优化效果如下图，值得注意一点的是，每一次迭代的移动方向都与出发点的等高线垂直： 需要指出的是，在某些情况下，最速下降法存在锯齿现象（ zig-zagging）将会导致收敛速度变慢（可以使用特征归一化来解决锯齿现象）: 粗略来讲，在二次函数中，椭球面的形状受 hesse 矩阵的条件数影响，长轴与短轴对应矩阵的最小特征值和最大特征值的方向，其大小与特征值的平方根成反比，最大特征值与最小特征值相差越大，椭球面越扁，那么优化路径需要走很大的弯路，计算效率很低。 经典机器学习中的优化问题泰勒公式 牛顿法与拟牛顿法 更多内容参见 无约束优化算法——牛顿法与拟牛顿法（DFP，BFGS，LBFGS） 牛顿法、梯度下降与最速下降法对比 牛顿法提供了对函数的二阶近似，并在每一步都对函数进行优化。其最大的问题在于，在优化过程中需要进行矩阵转换，对于多变量情形花销过高（尤其是向量的特征较多的时候）。 梯度下降是最常用的优化算法。由于该算法在每步只对导数进行计算，其花销较低，速度更快。但是在使用该算法时，需要对步长的超参数进行多次的猜测和尝试。 最速下降法在每步都对函数的梯度向量寻找最优步长。它的问题在于，在每次迭代中需要对相关的函数进行优化，这会带来很多花销。 最小二乘法最小二乘法（又称最小平方法）是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。利用最小二乘法可以简便地求得未知的数据，并使得这些求得的数据与实际数据之间误差的平方和为最小。最小二乘法还可用于曲线拟合。其他一些优化问题也可通过最小化能量或最大化熵用最小二乘法来表达。 机器学习中的激活函数为什么引入非线性激励函数？如果不用激励函数（其实相当于激励函数是f(x) = x），在这种情况下你每一层输出都是上层输入的线性函数，很容易验证，无论你神经网络有多少层，输出都是输入的线性组合，与没有隐藏层效果相当，这种情况就是最原始的感知机（Perceptron）了。正因为上面的原因，我们决定引入非线性函数作为激励函数，这样深层神经网络就有意义了（不再是输入的线性组合，可以逼近任意函数）。最早的想法是sigmoid函数或者tanh函数，输出有界，很容易充当下一层输入（以及一些人的生物解释）。 为什么引入Relu呢？第一，采用sigmoid等函数，算激活函数时（指数运算），计算量大，反向传播求误差梯度时，求导涉及除法，计算量相对大，而采用Relu激活函数，整个过程的计算量节省很多。第二，对于深层网络，sigmoid函数反向传播时，很容易就会出现梯度消失的情况（在sigmoid接近饱和区时，变换太缓慢，导数趋于0，这种情况会造成信息丢失，从而无法完成深层网络的训练。第三，Relu会使一部分神经元的输出为0，这样就造成了网络的稀疏性，并且减少了参数的相互依存关系，缓解了过拟合问题的发生（以及一些人的生物解释）。当然现在也有一些对relu的改进，比如prelu，random relu等。 激活函数优劣对比 Sigmoid$sigmoid(x)=\frac{1}{1+e^{-x}}$$f’(z)=f(x)(1-f(x))$ Sigmoid的一个优良特性就是能够把𝑥 ∈ 𝑅的输入“压缩”到𝑥 ∈ [0,1]区间，这个区间的数值在机 器学习常用来表示以下意义： 概率分布。 [0,1]区间的输出和概率的分布范围契合，可以通过 Sigmoid 函数将输出转译为概率输出 信号强度。 一般可以将 0~1 理解为某种信号的强度，如像素的颜色强度，1 代表当前通 道颜色最强，0 代表当前通道无颜色；抑或代表门控值(Gate)的强度，1 代表当前门控 全部开放，0 代表门控关闭。 tanh$tanh(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}}$$f’(x)=1 - f^(x)$ 更多内容参见 RNN中为什么要采用tanh而不是ReLu作为激活函数？ ReLU线性整流函数（Rectified Linear Unit, ReLU），又称修正线性单元，是一种人工神经网络中常用的激活函数，通常指代以斜坡函数及其变种为代表的非线性函数。 $Relu=max(0, x)$ Dead ReluReLU神经元对于所有的data point input，输出都是0，这是我们就说这个ReLU死掉了。 更多内容参见 由dead relu引发的思考——正则化算法漫谈 Leaky ReLU$f(x)=max(\alpha x, x)$ ELU$f(x)= \begin{cases}x,&amp; \text{if } x &gt; 0\\ \alpha(e^x - 1), &amp; \text{otherwise}\end{cases}$ gelu 更多内容参见深度学习中的gelu激活函数详解 f(x) = \Phi(x) * I(x) + (1 - \Phi(x)) * 0x = x\Phi(x)近似的计算式是： f(x) = 0.5x(1 + tanh[\sqrt{2/\pi} (x + 0.044715x^3)])gelu（gaussian error linear units）就是我们常说的高斯误差线性单元，它是一种高性能的神经网络激活函数，因为gelu的非线性变化是一种符合预期的随机正则变换方式。原始论文：https://arxiv.org/abs/1606.08415 Softmax$a_i=\frac{e^{z_i}}{\sum_k e^{z_k}}$ Softmax运算 扩展阅读：激活函数(ReLU, Swish, Maxout) 机器学习中的正则化方法 更多内容参见 正则化 Poll的笔记 L1 NormalizationL1 正则化使得模型参数具有稀疏性的原理是什么？回答角度如下： 解空间形状 函数叠加 贝叶斯先验 L2 NormalizationBatch Normalization 更多内容参见 深度学习中 Batch Normalization为什么效果好？ batch normalization有效地加快了模型的收敛速度，在一定程度缓解了深层网络中“梯度弥散”的问题，从而使得训练深层网络模型更加容易和稳定。batch normalization的算法过程如下： 12341.求当前batch的数据的均值u和方差sigma2.将当前的所有数据减去均值u3.将当前的所有数据除以方差的平方根sqrt(sigma)4.将经过前三步之后得到的数据乘以gamma，再加上betta，这里的gamma和betta是可学习的参数 前三步很好理解，将数据减去均值，再除以方差，可以将数据归一到正态分布。那第四步该如何理解呢，又有什么作用呢？从公式上看，第四步相当于把已处于正态分布的数据乘以了一个尺度因子gamma，再加上了一个平移因子betta，这不是又逆向回原来的分布了吗？当然不是，第四步的gamma和betta是可学习的参数，网络会通过权重更新自己去调节这两个参数，使得它拟合现有的模型参数。如果取消了第四步，那相当于经过了bn层之后的数据都变成了正态分布，这样不利于网络去表达数据的差异性，会降低网络的性能，加上了第四步之后，网络会根据模型的特点自动地去调整数据的分布，更有利于模型的表达能力。 Group NormalizationBatch Normalization的效果虽好，但是它也有一些缺陷，当batch_size较小的时候，bn算法的效果就会下降，这是因为在较小的batch_size中，bn层难以学习到正确的样本分布，导致gamma和betta参数学习的不好。为了解决这一问题，Facebook AI Research提出了Group Normalization。 从上图可以看出，随着batch_size的减小，batch norm的error率逐渐上升，而group norm的error率几乎不变。在一些目标检测方面的模型中，例如faster-rcnn或mask-rcnn，当你只拥有一个GPU时，要求的batch_size通常为1或2张图片，这种情况下batch norm的效果就会大打折扣。那么group norm是如何改进这一点的呢？下面来看下group norm的算法流程： 12341.将当前层的数据在通道的维度上划分为多个group2.求出每个group中的数据的均值和方差3.将每个group中的数据减去它们相应的均值再除以方差的平方根4.将经过前三步之后得到的数据乘以gamma，再加上betta 可以看出，group normalization和batch normalization的算法过程极为相似，仅仅通过划分group这样的简单操作就改善了batch norm所面临的问题，在实际应用中取得了非常好的效果。 对比BatchNorm、LayerNorm、InstanceNorm、GroupNorm 上图的N就是 batch，形状为 [batch, height, width, channel] 的特征图经过正则化时的计算轴和计算后的均值、方差的张量形状： BatchNorm LayerNorm InstanceNorm GroupNorm batch, height, width height, width, channel height, width height, width, channel // Group [1, 1, 1, channel] [batch, 1, 1, 1] [batch, 1, 1, channel] [batch, 1, 1, Group, 1] 注：GroupNorm时首先会将输入[batch, height, width, channel]根据设定的组数Group分组得到 [batch, height, width, Group, channel // Group]，然后在对[1, 2, 4]轴上的数据计算均值和方差。 BatchNormalization、LayerNormalization、InstanceNorm、GroupNorm的通俗理解BatchNormalization、LayerNormalization、InstanceNorm、GroupNorm、SwitchableNorm的相关论文、计算公式和代码总结 BatchNorm：batch方向做归一化，算NHW的均值，对小batchsize效果不好；BN主要缺点是对batchsize的大小比较敏感，由于每次计算均值和方差是在一个batch上，所以如果batchsize太小，则计算的均值、方差不足以代表整个数据分布 LayerNorm：channel方向做归一化，算CHW的均值，主要对RNN作用明显； InstanceNorm：一个channel内做归一化，算H*W的均值，用在风格化迁移；因为在图像风格化中，生成结果主要依赖于某个图像实例，所以对整个batch归一化不适合图像风格化中，因而对HW做归一化。可以加速模型收敛，并且保持每个图像实例之间的独立。 GroupNorm：将channel方向分group，然后每个group内做归一化，算(C//G)HW的均值；这样与batchsize无关，不受其约束。 SwitchableNorm是将BN、LN、IN结合，赋予权重，让网络自己去学习归一化层应该使用什么方法。 Dropout 机器学习中的模型训练技巧TODO：丰富内容 A Recipe for Training Neural Networks Must Know Tips/Tricks in Deep Neural Networks (by Xiu-Shen Wei) 机器学习中的评价指标TODO：图片相关的评价指标 混淆矩阵混淆矩阵 百度百科混淆矩阵 维基百科 混淆矩阵也称误差矩阵，是表示精度评价的一种标准格式，用n行n列的矩阵形式来表示。具体评价指标有总体精度、制图精度、用户精度等，这些精度指标从不同的侧面反映了图像分类的精度。混淆矩阵的每一列代表了预测类别，每一列的总数表示预测为该类别的数据的数目；每一行代表了数据的真实归属类别，每一行的数据总数表示该类别的数据实例的数目。 二分类评价指标正例（Positives）：你所关注的识别目标就是正例。负例（Negatives）：正例以外的就是负例。 多分类评价指标多分类评价指标：一种方法是将多分类问题转化为多个二分类问题（在计算某个类别的统计值时，把关注的类当作二分类中的正例，其它类别都当作负例。）进行讨论。另一种方法直接定义的多分类指标。 将多分类评价指标转换成二分类指标这里只介绍多分类的F1值计算方法，其它评价指标类似。 首先回顾的二分类情况下的准确率、精确率（Precision）、召回率（Recall）和F1值的计算方法。如图二分类的混淆矩阵，TP、TN、FP和FN分别表示真负、真正、假正和假负的样本个数，那么： Accuracy = \dfrac{TP+TN}{TP+TN+FP+FN}Precision = \dfrac{TP}{TP+FP}Recall = \dfrac{TP}{TP+FN}F1 = \dfrac{Precision \times Recall}{Precision + Recall}准确率表示模型预测正确的结果所占的比例，精确率表示在被识别为正类别的样本中，确实为正类别的比例，召回率表示在所有正类别样本中，被正确识别为正类别的比例，F1值表示Precision和Recall调和均值的2倍。 宏F1（F1_macro）值、加权F1（F1_weighted）值和微F1（F1_micro）值。宏F1值就是把多分类任务种的每一类作为一个二分类任务，算出其F1值，然后把这些F1值直接求平均数。加权F1值就是把多分类任务种的每一类作为一个二分类任务，算出其F1值，然后求这些F1值的加权平均，每个F1值对应的权重为该类别样本个数占总测试样本个数的比例。微F1值就是把多分类任务种的每一类作为一个二分类任务，然后依次累加这些二分类任务中对应的真负、真正、假正和假负的样本个数，最后根据这些累计量直接计算F1值。 F1_{macro} = \dfrac{1}{M} \sum_{j=1}^M F1_iF1_{weighted} = \sum_{j=1}^M \zeta_i F1_i, \zeta_{i} = \dfrac{\mathop{count}(l_i)}{\sum_{j=1}^M \mathop{count}(l_j)}上面式子的权重$\zeta$的计算式子如下，其中$M$是总的类别个数，$l_i$表示多分类任务中第$i$类标签，$\mathop{count}(\cdot)$是计数函数，统计对象是多分类任务的测试集。 F1_{micro} = \dfrac{Precision_{micro} \times Recall_{micro}}{Precision _{micro}+ Recall_{micro}}上面式子中$Precision_{micro}$和$Recall_{micro}$与二分类的计算类似，只是把多分类任务种的每一类作为一个二分类任务，然后依次累加这些二分类任务中对应的真负、真正、假正和假负的样本个数，再计算累加量$Precision_{micro}$和$Recall_{micro}$。 直接定义多分类的评价指标 AUC定义 百度百科 https://baike.baidu.com/item/AUC/19282953 更多内容参见 AUC AUC（Area Under Curve）被定义为ROC曲线下与坐标轴围成的面积，显然这个面积的数值不会大于1。又由于ROC曲线一般都处于y=x这条直线的上方，所以AUC的取值范围在0.5和1之间。AUC越接近1.0，检测方法真实性越高;等于0.5时，则真实性最低，无应用价值。 机器翻译（文本生成）评价指标 更多内容参见 BLEU，ROUGE，METEOR，ROUGE-浅述自然语言处理机器翻译常用评价度量 CSDN 机器翻译常用评价度量： 客观评价指标：BLEU、ROUGE、METEOR、CIDEr 主观评价指标 ：流畅度、相关性、助盲性 注意这些指标不是完全独立，而是有相互的联系。比如客观评价指标BLEU采用了N-gram的匹配规则，通过它能够算出比较译文和参考译文之间n组词的相似的一个占比。一般情况1-gram可以代表原文有多少词被单独翻译出来，可以反映译文的充分性，2-gram以上可以反映译文的流畅性，它的值越高说明可读性越好。这两个指标是能够跟人工评价对应的。 BLEU (Bilingual Evaluation Understudy) 的内容、存在的问题、以及如何在工作中最大限度地减少这些问题？ BLEU内容见 机器翻译质量评测算法-BLEU CSDN BLEU存在问题和解决方法见 Evaluating Text Output in NLP: BLEU at your own risk 或者 NLP输出文本评估：使用BLEU需要承担哪些风险？ 目标检测的评价指标IoUIoU（Intersection-over-Union）交并比，顾名思义数学中交集与并集的比例。假设有两个集合A与B, IoU即等于A与B的交集除以A与B的并集，表达式如下： IoU = \frac {A \cap B}{A \cup B}在目标检测中，IoU为预测框(Prediction)和真实框(Ground truth)的交并比。如下图所示，在关于小猫的目标检测中，紫线边框为预测框(Prediction)，红线边框为真实框(Ground truth)。 将预测框与真实框提取如下图，两者的交集区域为左下图斜线填充的部分，两者的并集区域为右下图蓝色填充的区域。IoU即为：左边斜线填充的面积/右边蓝色填充的总面积。 在目标检测任务中，通常取IoU≥0.5，认为召回。如果IoU阈值设置更高，召回率将会降低，但定位框则更加精确。理想的情况，当然是预测框与真实框重叠越多越好，如果两者完全重叠，则交集与并集面积相同，此时IoU等于1。 图像分类评价指标TopK Top1：对一张图片，模型给出的识别概率中（即置信度分数），分数最高的为正确目标，则认为正确。这里的目标也就是我们说的正例。 TopK: 对一张图片，模型给出的识别概率中（即置信度分数），分数排名前K位中包含有正确目标（正确的正例），则认为正确。K的取值一般可在100以内的量级，当然越小越实用。比如较常见的，K取值为5，则表示为Top5，代表置信度分数排名前5当中有一个是正确目标即可；如果K取值100，则表示为Top100，代表置信度分数排名前100当中有一个是正确目标（正确的正例）即可。可见，随着K增大，难度下降。 机器学习中的模型选择两种常见的模型选择方法：正则化与交叉验证。 正则化的作用是选择经验风险与模型复杂度同时较小的模型。当数据充足时，将数据集划分为训练集、验证集和测试集，通过验证集来选择模型。当数据不充足时，采用交叉验证的方法。 交叉验证 简单交叉验证。首先随机将已给数据部分分为两部分，一部分作为训练集，另一部分作为测试集；然后用训练集在各种条件下（例如，不同的参数个数）训练模型，从而得到不同的模型；在测试集上评价各个模型的测试误差，选出测试误差最小的模型。 S折交叉验证。首先随机地将已给数据且分为S个不互相交的大小相同的子集；然后利用S-1个子集的数据训练模型，利用余下的子集测试模型；将这一过程对可能的S种选择重复进行；最后选出S次测评中平均测试误差最小的模型。 留一交叉验证。当S=N，N为数据集大小，称为留一交叉验证。 机器学习中的集成方法 更多内容参见 常用的模型集成方法介绍：bagging、boosting 、stacking。 TODO: 补充目前经典的集成学习方法 集成学习就是组合这里的多个弱监督模型以期得到一个更好更全面的强监督模型，集成学习潜在的思想是即便某一个弱分类器得到了错误的预测，其他的弱分类器也可以将错误纠正回来。集成方法是将几种机器学习技术组合成一个预测模型的元算法，以达到减小方差（bagging）、偏差（boosting）或改进预测（stacking）的效果。 集成学习在各个规模的数据集上都有很好的策略。 数据集大：划分成多个小数据集，学习多个模型进行组合。 数据集小：利用Bootstrap方法进行抽样，得到多个数据集，分别训练多个模型再进行组合。 机器学习中的著名的集成方法：Bagging，Boosting以及Stacking。 Bagging（bootstrap aggregating，装袋）Bagging即套袋法，先说一下bootstrap，bootstrap也称为自助法，它是一种有放回的抽样方法，目的为了得到统计量的分布以及置信区间，其算法过程如下： 从原始样本集中抽取训练集。每轮从原始样本集中使用Bootstraping的方法抽取n个训练样本。共进行k轮抽取，得到k个训练集。（k个训练集之间是相互独立的） 每次使用一个训练集得到一个模型，k个训练集共得到k个模型。（注：这里并没有具体的分类算法或回归方法，我们可以根据具体问题采用不同的分类或回归方法，如决策树、感知器等） 对分类问题：将上步得到的k个模型采用投票的方式得到分类结果；对回归问题，计算上述模型的均值作为最后的结果。（所有模型的重要性相同） Boosting 更多内容参见 机器学习—集成学习（Ensemble Learning） 其主要思想是将弱分类器组装成一个强分类器。通过提高那些在前一轮被弱分类器分错样例的权值，减小前一轮分对样例的权值，来使得分类器对误分的数据有较好的效果。通过加法模型将弱分类器进行线性组合，比如： AdaBoost（Adaptive boosting）算法：刚开始训练时对每一个训练例赋相等的权重，然后用该算法对训练集训练t轮，每次训练后，对训练失败的训练例赋以较大的权重，也就是让学习算法在每次学习以后更注意学错的样本，从而得到多个预测函数。通过拟合残差的方式逐步减小残差，将每一步生成的模型叠加得到最终模型。 GBDT（Gradient Boost Decision Tree)，每一次的计算是为了减少上一次的残差，GBDT在残差减少（负梯度）的方向上建立一个新的模型。 AdaBoostAdaBoost原理详解 从基于树的算法的演变过程看集成学习 上述图片的直观解释：假设你是面试官，要面试几名资历非常优秀的求职者。基于树的算法演变过程的每一步都可以类比为不同版本的面试场景。 决策树：每一名面试官都有一套自己的面试标准，比如教育水平、工作经验以及面试表现等。决策树类似于面试官根据他（她）自己的标准面试求职者。 袋装法（Bagging）：现在面试官不只有一个人，而是一整个面试小组，小组中的每位面试官都有投票权。Bagging（Boostrap Aggregating）就是通过民主投票过程，综合所有面试官的投票，然后做出最终决定。 随机森林（Random Forest）：这是基于 Bagging 的算法，但与 Bagging 有明显区别——它随机选择特征子集。也就是，每位面试官只会随机选择一些侧面来对求职者进行面试（比如测试编程技能的技术面或者是评估非技术技能的行为面试）。 Boosting：这是一种替代方法，每位面试官根据前一位面试官的反馈来调整评估标准。通过部署更动态的评估流程来「提升」面试效率。 梯度提升（Gradient Boosting）：这是 Boosting 的特例，这种算法通过梯度下降算法来最小化误差。用面试类比的话，就是战略咨询公司用案例面试来剔除那些不符合要求的求职者； XGBoost：将 XGBoost 视为极限的梯度提升。这是软硬件优化技术的完美结合，它可以在最短时间内用更少的计算资源得到更好的结果。 更多内容参见 决策树、随机森林、bagging、boosting、Adaboost、GBDT、XGBoost总结 知乎 XGBoost 更多内容参见 XGBoost的工程师手册 下图来自 XGBoost超详细推导，终于有人讲明白了！ 降维TODO: 完善内容 主成成分分析、自编码器和变分自编码器解析 主成分分析（PCA） 更多内容参见 主成分分析（PCA）原理详解 PCA的概念PCA(Principal Component Analysis)，即主成分分析方法，是一种使用最广泛的数据降维算法。PCA的主要思想是将n维特征映射到k维上，这k维是全新的正交特征也被称为主成分，是在原有n维特征的基础上重新构造出来的k维特征。PCA的工作就是从原始的空间中顺序地找一组相互正交的坐标轴，新的坐标轴的选择与数据本身是密切相关的。其中，第一个新坐标轴选择是原始数据中方差最大的方向，第二个新坐标轴选取是与第一个坐标轴正交的平面中使得方差最大的，第三个轴是与第1,2个轴正交的平面中方差最大的。依次类推，可以得到n个这样的坐标轴。通过这种方式获得的新的坐标轴，我们发现，大部分方差都包含在前面k个坐标轴中，后面的坐标轴所含的方差几乎为0。于是，我们可以忽略余下的坐标轴，只保留前面k个含有绝大部分方差的坐标轴。事实上，这相当于只保留包含绝大部分方差的维度特征，而忽略包含方差几乎为0的特征维度，实现对数据特征的降维处理。 思考：我们如何得到这些包含最大差异性的主成分方向呢？ 答案：事实上，通过计算数据矩阵的协方差矩阵，然后得到协方差矩阵的特征值特征向量，选择特征值最大(即方差最大)的k个特征所对应的特征向量组成的矩阵。这样就可以将数据矩阵转换到新的空间当中，实现数据特征的降维。 由于得到协方差矩阵的特征值特征向量有两种方法：特征值分解协方差矩阵、奇异值分解协方差矩阵，所以PCA算法有两种实现方法：基于特征值分解协方差矩阵实现PCA算法、基于SVD分解协方差矩阵实现PCA算法。 线性判别分析（LDA）LDA是一种监督学习的降维技术，也就是说它的数据集的每个样本是有类别输出的。这点和PCA不同。PCA是不考虑样本类别输出的无监督降维技术。LDA的思想可以用一句话概括，就是“投影后类内方差最小，类间方差最大”。 主成分分析（PCA）与线性判别分析（LDA）区别与联系 更多内容参见线性判别分析LDA原理总结 LDA用于降维，和PCA有很多相同，也有很多不同的地方，因此值得好好的比较一下两者的降维异同点。 首先我们看看相同点：1）两者均可以对数据进行降维。2）两者在降维时均使用了矩阵特征分解的思想。3）两者都假设数据符合高斯分布。 我们接着看看不同点：1）LDA是有监督的降维方法，而PCA是无监督的降维方法2）LDA降维最多降到类别数k-1的维数，而PCA没有这个限制。3）LDA除了可以用于降维，还可以用于分类。4）LDA选择分类性能最好的投影方向，而PCA选择样本点投影具有最大方差的方向。 LDA主题模型 通俗理解LDA主题模型 一文详解LDA主题模型 LDA数学八卦 LDA主题模型原始论文 Latent Dirichlet Allocation 语言模型语言模型 百度百科语言模型是根据语言客观事实而进行的语言抽象数学建模，是一种对应关系。语言模型与语言客观事实之间的关系，如同数学上的抽象直线与具体直线之间的关系。 斯坦福公开课的自然语言处理 统计语言模型详解 神经语言模型 百度百科神经语言模型（Neural Language Model，NLM）是一类用来克服维数灾难的语言模型，它使用词的分布式表示对自然语言序列建模。不同于基于类的n-gram模型，神经语言模型在能够识别两个相似的词，并且不丧失将每个词编码为彼此不同的能力。神经语言模型共享一个词（及其上下文）和其他类似词。语言模型（language model）定义了自然语言中标记序列的概率分布。根据模型的设计，标记可以是词、字符、甚至是字节。标记总是离散的实体。最早成功的语言模型基于固定长度序列的标记模型，称为n-gram。一个n-gram 是一个包含n个标记的序列。基于n-gram 的模型定义一个条件概率——给定前n−1个标记后的第n个标记的条件概率。神经语言模型是由Bengio等人在2003年提出的，共享一个词（及其上下文）和其他类似词和上下文之间的统计强度。模型为每个词学习的分布式表示，允许模型处理具有类似共同特征的词来实现这种共享。 词向量、词嵌入与语言模型的关系？词向量通常指通过语言模型学习得到的词的分布式特征表示，也被称为词编码，可以非稀疏的表示大规模语料中复杂的上下文信息。分布式词向量可以表示为多维空间中的一个点，而具有多个词向量的单词在空间上表示为数个点的集合，也可以看作在一个椭球分布上采集的数个样本 。词嵌入是自然语言处理（NLP）中语言模型与表征学习技术的统称。概念上而言，它是指把一个维数为所有词的数量的高维空间嵌入到一个维数低得多的连续向量空间中，每个单词或词组被映射为实数域上的向量。词嵌入的方法包括人工神经网络、对词语同现矩阵降维、概率模型以及单词所在上下文的显式表示等。在底层输入中，使用词嵌入来表示词组的方法极大提升了NLP中语法分析器和文本情感分析等的效果。 神经语言模型和统计语言模型有啥异同点？ 更多内容参见 神经语言模型和统计语言模型有啥异同点？ 知乎 nlp中的传统语言模型与神经语言模型 简书 语言模型的评价指标-困惑度？困惑度 百度百科在信息论中，perplexity(困惑度)用来度量一个概率分布或概率模型预测样本的好坏程度。它也可以用来比较两个概率分布或概率模型。（译者：应该是比较两者在预测样本上的优劣）低困惑度的概率分布模型或概率模型能更好地预测样本。 预训练语言模型的相关论文必须阅读有关预训练语言模型的论文。 词向量 推荐阅读Embedding 和语言模型 LanguageModel word2vector核心知识点： CBOW和Skip-gram两个语言模型 层次softmax 和负采样两个技术 首先初读：word2vec是如何得到词向量的？ 知乎 然后深入读和实践： word2vec 中的数学原理详解（作者：peghoty 完整看完对理解w2v很有帮助） 附带注释的 word2vec 源码（作者：chenbjin） word2vec源码解析（作者：google19890102） 卷积CNN中的局部连接(Sparse Connectivity)和权值共享 左边是全连接，右边是局部连接。对于一个1000 × 1000的输入图像而言，如果下一个隐藏层的神经元数目为10^6个，采用全连接则有1000 × 1000 × 10^6 = 10^12个权值参数，如此数目巨大的参数几乎难以训练；而采用局部连接，隐藏层的每个神经元仅与图像中10 × 10的局部图像相连接，那么此时的权值参数数量为10 × 10 × 10^6 = 10^8，将直接减少4个数量级。 尽管减少了几个数量级，但参数数量依然较多。能不能再进一步减少呢？能！方法就是权值共享。具体做法是，在局部连接中隐藏层的每一个神经元连接的是一个10 × 10的局部图像，因此有10 × 10个权值参数，将这10 × 10个权值参数共享给剩下的神经元，也就是说隐藏层中10^6个神经元的权值参数相同，那么此时不管隐藏层神经元的数目是多少，需要训练的参数就是这 10 × 10个权值参数（也就是卷积核(也称滤波器)的大小），如下图。 但是，这样仅提取了图像的一种特征，如果要多提取出一些特征，可以增加多个卷积核，不同的卷积核能够得到图像的不同映射下的特征，称之为Feature Map。如果有100个卷积核，最终的权值参数也仅为100 × 100 = 10^4个而已。另外，偏置参数也是共享的，同一种滤波器共享一个。 卷积神经网络的核心思想是：局部感受野(local field)，权值共享以及时间或空间亚采样这三种思想结合起来，获得了某种程度的位移、尺度、形变不变性 使用更小卷积核的作用在VGG16中，使用了3个3x3卷积核来代替7x7卷积核，使用了2个3x3卷积核来代替5x5卷积核，这样做的主要目的是在保证具有相同感知野的条件下，提升了网络的深度，在一定程度上提升了神经网络的效果。 以下简单地说明一下小卷积(3*3)对于5×5网络感知野相同的替代性。 机器学习中的杂项问题一名合格的算法工程师是怎样的 具体内容参见王喆的如何准备算法工程师面试，斩获一线互联网公司机器学习岗offer？ 算法工程师的能力要求是相对全面的。作为算法模型的实现者和应用者，算法工程师在机器学习知识扎实的基础上，还应该具有算法的改进和实现的能力，因此工具和业务层面的要求也稍高。具体的内容来描述一下算法工程师的四个技能点： 知识：主要是指你对machine learning相关知识和理论的储备 工具：将你的machine learning知识应用于实际业务的工具 逻辑：你的举一反三的能力，解决问题的条理性，发散思维的能力，你的聪明程度 业务：深入理解所在行业的商业模式，从业务中发现motivation并进而改进模型算法的能力 那么如何找一份算法（机器学习）工程师的工作呢？请看找一份机器学习工作 真算法工程师与调包侠的区别与联系？ 更多内容参见 现在的计算机专业（比如机器学习）已经沦为调包专业了吗？ 区别：“轮子造了就是用来造车的。但是车好不好, 还是要看造车的人懂不懂轮子。”也就是说真算法工程师造出来的产物优于只会调包的人。联系：进阶路线，普通的调包侠 -&gt; 熟练的调包侠 -&gt; 修包侠 -&gt; 造轮子 -&gt; 真算法工程师 进一步引用霍华德的回答： 虚假的AI有以下特点： 从不自己收集、处理、清洗、标注数据，而是找一个现有的数据集，疯狂 过拟合数据集。 科研idea主要来自于各种模块的花式排列组合，包含但不限于：各种CNN，各种RNN，各种attention，各种transformer，各种dropout，各种batchNorm，各种激活函数，各种loss function 而不是从实际问题和自然语言的现有挑战出发来思考idea 总是指望靠一个算法、一个模型可以解决所有问题 想做好真实AI，必须： 不断反馈，分析，改进。据说谷歌的搜索质量负责人Amit Singhal博士每天要看20个以上的不好搜索结果，然后持续不断的迭代改进。 面对真实环境中获取数据难，数据标注成本高，数据脏难清洗等问题 从实际问题和自然语言的现有挑战出发，设计针对问题最适合合理有效的模型 从不指望一个算法和问题可以解决所有问题，所有遇到的问题会做出合理的分析和拆解，针对各个难点设计最优解决算法，各个击破。 自然语言处理与机器学习的关系点击下载自然语言处理与机器学习的双生树图。该图来自面向生产环境的自然语言处理工具包 HanLP 举例说明深度学习、机器学习在商业中的实际应用？ 更多内容参见 深度学习算法的商业应用案例 机器学习“判定模型”和“生成模型”有什么区别？ 更多内容参见 机器学习“判定模型”和“生成模型”有什么区别？ 知乎详解 第一层理解其实机器学习的任务是从属性X预测标记Y，即求概率P(Y|X)；对于判别式模型来说求得P(Y|X)，对未见示例X，根据P(Y|X)可以求得标记Y，即可以直接判别出来，如上图的左边所示，实际是就是直接得到了判别边界，所以传统的、耳熟能详的机器学习算法如线性回归模型、支持向量机SVM等都是判别式模型，这些模型的特点都是输入属性X可以直接得到Y（对于二分类任务来说，实际得到一个score，当score大于threshold时则为正类，否则为反类） 而生成式模型求得P(Y,X)，对于未见示例X，你要求出X与不同标记之间的联合概率分布，然后大的获胜，如上图右边所示，并没有什么边界存在，对于未见示例（红三角），求两个联合概率分布（有两个类），比较一下，取那个大的。 在机器学习中任务是从属性X预测标记Y，判别模型求的是P(Y|X)，即后验概率；而生成模型最后求的是P(X,Y)，即联合概率。从本质上来说：判别模型之所以称为“判别”模型，是因为其根据X“判别”Y；而生成模型之所以称为“生成”模型，是因为其预测的根据是联合概率P(X,Y)，而联合概率可以理解为“生成”(X,Y)样本的概率分布（或称为 依据）；具体来说，机器学习已知X，从Y的候选集合中选出一个来，可能的样本有(X,Y_1), (X,Y_2), (X,Y_3),……，(X,Y_n),实际数据是如何“生成”的依赖于P(X,Y)，那么最后的预测结果选哪一个Y呢？那就选“生成”概率最大的那个吧~ 第二层理解 第三层理解首先区分生成/判别方法和生成/判别模型。有监督机器学习方法可以分为生成方法和判别方法（常见的生成方法有LDA主题模型、朴素贝叶斯算法和隐式马尔科夫模型等，常见的判别方法有SVM、LR等），生成方法学习出的是生成模型，判别方法学习出的是判别模型。 模型在验证集的测试指标优于在训练集的指标的原因是什么？主要因素是因为像 BatchNormalization 和 Dropout 这样的层会影响训练期间的准确性。在计算验证损失时，它们会被关闭。 在较小程度上，这也是因为训练指标报告了一个周期的平均值，而验证指标是在周期之后进行评估的，因此验证指标体现的是已经训练稍长一些的模型。 计算机视觉迁移学习中的特征提取和微调的区别和联系特征提取：使用先前网络学习的表示从新样本中提取有意义的特征。您只需在预训练模型的基础上添加一个新的分类器（将从头开始训练），以便您可以重新调整先前为我们的数据集学习的特征映射。您不需要（重新）训练整个模型。基本卷积网络已经包含通常用于分类图片的功能。然而，预训练模型的最终分类部分特定于原始分类任务，并且随后特定于训练模型的类集。 微调：冻结冻结模型库的一些顶层，并共同训练新添加的分类器层和基础模型的最后一层。这允许我们“微调”基础模型中的高阶特征表示，以使它们与特定任务更相关。 使用预先训练的模型进行特征提取：使用小型数据集时，通常会利用在同一域中的较大数据集上训练的模型所学习的特征。这是通过实例化预先训练的模型并在顶部添加完全连接的分类器来完成的。预训练的模型被“冻结”并且仅在训练期间更新分类器的权重。在这种情况下，卷积基础提取了与每个图像相关的所有特征，并且您刚刚训练了一个分类器，该分类器根据提取的特征集确定图像类。 微调预先训练的模型：为了进一步提高性能，可能需要通过微调将预训练模型的顶层重新调整为新数据集。在这种情况下，您调整了权重，以便模型学习特定于数据集的高级特征。当训练数据集很大并且非常类似于训练预训练模型的原始数据集时，通常建议使用此技术。 TF-IDF的定义、计算公式、应用和优缺点分别是什么？TF-IDF有两层意思，一层是”词频”（Term Frequency，缩写为TF），另一层是”逆文档频率”（Inverse Document Frequency，缩写为IDF）。TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术，常用于挖掘文章中的关键词，而且算法简单高效，常被工业用于最开始的文本数据清洗。 TF-IDF提取文档关键词的优缺点：TF-IDF的优点是简单快速，而且容易理解。缺点是有时候用词频来衡量文章中的一个词的重要性不够全面，有时候重要的词出现的可能不够多，而且这种计算无法体现位置信息，无法体现词在上下文的重要性。 TF-IDF的应用（后文一一举例说明）： 提取文章关键词 确定文章相似性（结合余弦相似性） 自动摘要 TF-IDF与余弦相似性的应用（一）：自动提取关键词 TF-IDF与余弦相似性的应用（二）：找出相似文章（1）使用TF-IDF算法，找出两篇文章的关键词；（2）每篇文章各取出若干个关键词（比如20个），合并成一个集合，计算每篇文章对于这个集合中的词的词频（为了避免文章长度的差异，可以使用相对词频）；（3）生成两篇文章各自的词频向量；（4）计算两个向量的余弦相似度，值越大就表示越相似。 TF-IDF与余弦相似性的应用（三）：自动摘要如果能从3000字的文章，提炼出150字的摘要，就可以为读者节省大量阅读时间。由人完成的摘要叫”人工摘要”，由机器完成的就叫”自动摘要”。其中，很重要的一种自动摘要技术就是词频统计。其实一种方法就是抽取文章中含有一定量关键词的句子。 BM25的定义、计算公式、应用和优缺点分别是什么？自然语言处理-BM25相关度打分 如何提取文本关键词？文本关键词提取算法总结和Python实现文本关键词提取算法大致分为有监督和无监督两种： 有监督算法将关键词抽取问题转换为判断每个候选关键词是否为关键词的二分类问题，它需要一个已经标注关键词的文档集合训练分类模型。 无监督算法不需要人工标注的训练集，利用某些方法发现文本中比较重要的词作为关键词，进行关键词抽取。词重要性的衡量有多种方式：基于文本统计特征、基于词图模型和基于主题模型，TF-IDF、TextRank和LDA分别是这几种不同方式的代表 TF-IDF关键词提取 TextRank关键词抽取PageRank算法将整个互联网看作一张有向图，网页是图中的节点，而网页之间的链接就是途中的边。根据重要性传递的思想，如果一个网页A含有一个指向网页B的链接，那么网页B的重要性排名会根据A的重要行来提升。在PageRank算法中，对于网页初始重要值（PR值）的计算非常关键，但是这个值无法预知，于是PageRank论文中给出了一种迭代算法求出这个PR值：为每个网页随机给一个初始值，然后迭代得到收敛值，作为网页重要性的度量。 LDA（Latent Dirichlet Allocation）关键词抽取LDA的这三位作者在原始论文 Latent Dirichlet Allocation 中给了一个简单的例子。比如假设事先给定了这几个主题：Arts、Budgets、Children、Education，然后通过学习的方式，获取每个主题Topic对应的词语（我们可以认为这些主题词语就是关键词）。如下图所示： 然后以一定的概率选取上述某个主题，再以一定的概率生成选取主题下的某个单词，不断的重复这两步，最终生成如下图所示的一篇文章（其中不同颜色的词语分别对应上图中不同主题下的词）： 而当我们看到一篇文章后，往往喜欢推测这篇文章是如何生成的，我们可能会认为作者先确定这篇文章的几个主题，然后围绕这几个主题遣词造句，表达成文。LDA就是要干这事：根据给定的一篇文档，推测其主题分布。 如何处理数据类别不平衡问题当一个分类任务的数据集中来自不同类别的样本数目相差悬殊时，我们通常称该数据集为“类别不平衡”的。以一个现实任务为例：在点击率预估（click-through rate prediction）任务中，每条展示给用户的广告都产生一条新样本，而用户最终是否点击了这条广告决定了样本的标签。显然，只有很少一部分的用户会去点击网页里的嵌入广告，这就导致最终得到的训练数据集中正/负例样本的数量差距悬殊。同样的情况也发生在很多实际应用场景中，如金融欺诈检测（正常/欺诈），医疗辅助诊断（正常/患病），网络入侵检测（正常连接/攻击连接）等等。 需要注意的是，尽管少数类的样本个数更少，表示的质量也更差，但其通常会携带更重要的信息，因此一般我们更关注模型正确分类少数类样本的能力。 分类问题的一个underlying assumption是各个类别的数据都有自己的分布，当某类数据少到难以观察结构的时候，我们可以考虑抛弃该类数据，转而学习更为明显的多数类模式，而后将不符合多数类模式的样本判断为异常/少数类，某些时候会有更好的效果。此时该问题退化为异常检测（anomaly detection）问题。 我将已有的不平衡学习算法划分为3类：数据级方法，算法级方法以及集成方法（参考极端类别不平衡数据下的分类问题研究综述）。 数据级方法数据级方法是不平衡学习领域发展最早、影响力最大、使用最广泛的一类方法，也可称为重采样方法。该类方法关注于通过修改训练数据集以使得标准学习算法也能在其上有效训练。根据实现方式的不同，数据级方法可被进一步分类为： 从多数类别中删除样本的方法（欠采样） 为少数类别生成新样本的方法（过采样） 结合上述两种方案的混合类方法（过采样+欠采样去噪） 标准的随机重采样方法使用随机方法来选择用于预处理的目标样本。然而随机方法可能会导致丢弃含有重要信息的样本（随机欠采样）或者引入无意义的甚至有害的新样本（随机过采样），因此有一系列更高级的方法，试图根据根据数据的分布信息来在进行重采样的同时保持原有的数据结构。 数据级方法Strength 该类方法能够去除噪声/平衡类别分布：在重采样后的数据集上训练可以提高某些分类器的分类性能。 欠采样方法减小数据集规模：欠采样方法会去除一些多数类样本，从而可能降低模型训练时的计算开销。 数据级方法Weakness 采样过程计算效率低下：这一系列的“高级”重采样方法通常使用基于距离的邻域关系（通常是k-最近邻方法）来提取数据分布信息。该方式的缺点是需要计算每个数据样本之间的距离，而计算距离需要的计算量随着数据集的大小呈平方级增长，因此在大规模数据集上应用这些方法可能会带来极低的计算效率。 易被噪声影响：此外在具有高不平衡比且包含大量噪声的工业数据集中，少数类的结构可能并不能被样本的分布很好地表示。而被这些重采样方法用来提取分布信息的最近邻算法很容易被噪声干扰，因此可能无法得到准确的分布信息，从而导致不合理的重采样策略。 过采样方法生成过多数据：当应用于大规模且高度不平衡的数据集时，过采样类的方法可能会生成大量的少数类样本以平衡数据集。这会进一步增大训练集的样本数量，增大计算开销，减慢训练速度，并可能导致过拟合。 不适用于无法计算距离的复杂数据集：最重要的一点是这些重采样方法依赖于明确定义的距离度量，使得它们在某些数据集上不可用。在实际应用中，工业数据集经常会含有类别特征（即不分布在连续空间上的特征，如用户ID）或者缺失值，此外不同特征的取值范围可能会有巨大的差别。在这些数据集上定义合理的距离度量十分困难。 算法级方法算法级方法专注于修改现有的标准机器学习算法以修正他们对多数类的偏好。在这类方法中最流行的分支是代价敏感学习（cost-sensitive learning），我们在此也只讨论该类算法。代价敏感学习给少数类样本分配较高的误分类代价，而给多数类样本分配较小的误分类代价。通过这种方式代价敏感学习在学习器的训练过程中人为提高了少数类别样本的重要性，以此减轻分类器对多数类的偏好。 算法级方法Strength 不增加训练复杂度：使用该类算法改进后的算法通常会有更好的表现，并且没有增加训练的计算复杂度。 可直接用于多分类问题：该类算法通常只修改误分类代价，因此可直接扩展到多分类问题上。 算法级方法Weakness 需要领域先验知识：必须注意的是，代价敏感学习中的代价矩阵（cost matrix）需要由领域专家根据任务的先验知识提供，这在许多现实问题中显然是不可用的。因此在实际应用时代价矩阵通常被直接设置为归一化的不同类别样本数量比。由于缺乏领域知识的指导，这种擅自设置的代价矩阵并不能保证得到最优的分类性能。 不能泛化到不同任务：对于特定问题设计的代价矩阵只能用于该特定任务，在其他任务上使用时并不能保证良好的性能表现。 依赖于特定分类器：另一方面，对于诸如神经网络的需要以批次训练（mini-batch training）方法训练的模型，少数类样本仅仅存在于在很少的批次中，而大部分批次中只含有多数类样本，这会给神经网络训练带来灾难性的后果：使用梯度下降更新的非凸优化过程会很快陷入局部极值点/鞍点（梯度为0），导致网络无法进行有效学习。使用敏感代价学习来给样本加权并不能解决这个问题。 集成学习的方法集成学习类方法专注于将一种数据级或算法级方法与集成学习相结合，以获得强大的集成分类器。由于其在类别不平衡任务中表现出色，在实际应用中集成学习越来越受欢迎。 处理数据类别不平衡问题的工具：imbalanced-learn A Python Package to Tackle the Curse of Imbalanced Datasets in Machine Learning 附加阅读 机器学习中如何处理不平衡数据？ 深度学习训练数据不平衡问题，怎么解决？ 机器不学习：如何处理数据中的「类别不平衡」？ 深度 | 解决真实世界问题：如何在不平衡类上使用机器学习？ 如何计算文本之间的相似度？TODO: 完善内容 计算文本相似度的算法 一级分类 二级分类 基于词向量 欧几里德距离、曼哈顿距离和余弦距离、明式距离、切比雪夫距离等 基于具体字符 共有字符数、汉明距离、编辑距离、SimHash 基于概率统计 杰卡德相似系数 基于统计学习模型的 主题模型（潜在语义分析LSA、潜在狄利克雷分布LDA） 基于深度学习模型的 doc2vec,word2vec NLP点滴——文本相似度，计算文本间的距离 短文本之间的相似度短文本相似度度量 如何设计一个比较海量文章相似度的算法？ simhash算法及原理简介 simhash海量文本去重的工程化 SimHash是Google在2007年发表的论文《Detecting Near-Duplicates for Web Crawling 》中提到的一种指纹生成算法或者叫指纹提取算法，被Google广泛应用在亿级的网页去重的Job中，作为locality sensitive hash（局部敏感哈希）的一种。其主要思想是降维，将高维的特征向量映射成低维的特征向量，通过两个向量的Hamming Distance来确定文章是否重复或者高度近似。其中，Hamming Distance，又称汉明距离，在信息论中，两个等长字符串之间的汉明距离是两个字符串对应位置的不同字符的个数。也就是说，它就是将一个字符串变换成另外一个字符串所需要替换的字符个数。例如：1011101 与 1001001 之间的汉明距离是 2。至于我们常说的字符串编辑距离则是一般形式的汉明距离。 机器学习中距离和相似性度量方法漫谈：机器学习中距离和相似性度量方法 参见度量 百度百科。距离函数（度量）需要满足三条性质：正定性、对称性和三角不等式。 如何解决冷启动问题如何用主题模型解决推荐系统中的冷启动问题？ 下一步学习，终生学习机器学习中的500问系统性学习机器学习中的问题，参见 《深度学习500问》。 机器学习、深度学习框架速览TensorFlow 基本概念 《Tensorflow-Cookbook》 自然语言处理的技术路线详细内容见 nlp-roadmap 自然语言处理路线图详解，从数学基础、语言基础到模型和算法，这是你该了解的知识领域。 其它主题机器翻译《机器翻译：统计建模与深度学习方法》 深度学习《神经网络与深度学习》 迁移学习《迁移学习简明手册》Transfer Learning - Machine Learning’s Next FrontierNeural Transfer Learning for Natural Language Processing (PhD thesis)jindongwang/transferlearning 多任务学习《An Overview of Multi-Task Learning in Deep Neural Networks》]]></content>
  </entry>
  <entry>
    <title><![CDATA[异常检测]]></title>
    <url>%2F2019%2F08%2F05%2F%E5%BC%82%E5%B8%B8%E6%A3%80%E6%B5%8B%2F</url>
    <content type="text"><![CDATA[异常检测异常检测 百度百科异常检测(Anomaly detection) 的假设是入侵者活动异常于正常主体的活动。根据这一理念建立主体正常活动的“活动简档”，将当前主体的活动状况与“活动简档”相比较，当违反其统计规律时，认为该活动可能是“入侵”行为。异常检测的难题在于如何建立“活动简档”以及如何设计统计算法，从而不把正常的操作作为“入侵”或忽略真正的“入侵”行为。 异常检测（Anomaly-based detection）方法首先定义一组系统处于“正常”情况时的数据，如CPU利用率、内存利用率、文件校验和等然后进行分析确定是否出现异常。 开发和评价一个异常检测系统异常检测算法是一个非监督学习算法，意味着我们无法根据结果变量y的值来告诉我们数据是否真的是异常的。我们需要另一种方法来帮助检验算法是否有效。当我们开发一个异常检测系统时，我们从带标记（异常或正常）的数据着手，我们从其中选择一部分正常数据用于构建训练集，然后用剩下的正常数据和异常数据混合的数据构成交叉检验集和测试集。 例如：我们有10000台正常引擎的数据，有20台异常引擎的数据。我们这样分配数据： 6000台正常引擎的数据作为训练集 2000台正常引擎和10台异常引擎的数据作为交叉检验集 2000台正常引擎和10台异常引擎的数据作为测试集 具体的评价方法如下： 根据测试集数据，我们估计特征的平均值和方差并构建P(x)函数 对交叉检验集，我们尝试使用不同的ε值作为阀值，并预测数据是否异常，根据F1值或者查准率与查全率的比例来选择ε 选出ε后，针对测试集进行预测，计算异常检验系统的F1值，或者查准率与查全率之比 异常检测与监督学习对比之前我们构建的异常检测系统也使用了带标记的数据，与监督学习有些相似，下面的对比有助于选择采用监督学习还是异常检测： 对于很多技术公司可能会遇到的一些问题，通常来说，正样本的数量很少，甚至有时候是0，也就是说，出现了太多没见过的不同的异常类型，那么对于这些问题，通常应该使用的算法就是异常检测算法。 异常检查与不平衡分类的关系一般情况下，可以把异常检测看成是数据不平衡下的分类问题。因此，如果数据条件允许，优先使用有监督的异常检测。实验结果发现直接用XGBOOST进行有监督异常检测往往也能得到不错的结果，没有思路时不妨一试。而在仅有少量标签的情况下，也可采用半监督异常检测模型。比如把无监督学习作为一种特征抽取方式来辅助监督学习，和stacking比较类似。这种方法也可以理解成通过无监督的特征工程对数据进行预处理后，喂给有监督的分类模型。但在现实情况中，异常检测问题往往是没有标签的，训练数据中并未标出哪些是异常点，因此必须使用无监督学习。 异常检测的应用场景 数据预处理 病毒木马检测 工业制造产品检测 网络流量检测 由于在以上场景中，异常的数据量都是很少的一部分，因此诸如：SVM、逻辑回归等分类算法，都不适用，因为：监督学习算法适用于有大量的正向样本，也有大量的负向样本，有足够的样本让算法去学习其特征，且未来新出现的样本与训练样本分布一致。 异常检测的相关算法数据挖掘中常见的「异常检测」算法有哪些？ 知乎 异常值检测的常见四种方法，分别为 Numeric Outlier、Z-Score、DBSCAN以及Isolation Forest 异常检查相关软件knime 异常检测 pyod A Python Toolbox for Scalable Outlier Detection (Anomaly Detection)]]></content>
      <categories>
        <category>论文</category>
        <category>异常检测</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[机器学习中的微积分]]></title>
    <url>%2F2019%2F08%2F04%2F%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E4%B8%AD%E7%9A%84%E5%BE%AE%E7%A7%AF%E5%88%86%2F</url>
    <content type="text"><![CDATA[极限极限 百度百科“极限”是数学中的分支——微积分的基础概念，广义的“极限”是指“无限靠近而永远不能到达”的意思。数学中的“极限”指：某一个函数中的某一个变量，此变量在变大（或者变小）的永远变化的过程中，逐渐向某一个确定的数值A不断地逼近而“永远不能够重合到A”（“永远不能够等于A，但是取等于A‘已经足够取得高精度计算结果）的过程中，此变量的变化，被人为规定为“永远靠近而不停止”、其有一个“不断地极为靠近A点的趋势”。极限是一种“变化状态”的描述。此变量永远趋近的值A叫做“极限值”（当然也可以用其他符号表示）。 以上是属于“极限”内涵通俗的描述，“极限”的严格概念最终由柯西和魏尔斯特拉斯等人严格阐述。 极限思想极限思想 百度百科 极限、连续、可微、可到、可积之间的关系高数精髓——极限存在、连续、可导、可微和可积之间的联系 对于一元函数有，可微&lt;=&gt;可导=&gt;连续=&gt;可积 对于多元函数，不存在可导的概念，只有偏导数存在。函数在某处可微等价于在该处沿所有方向的方向导数存在，仅仅保证偏导数存在不一定可微，因此有：可微=&gt;偏导数存在=&gt;连续=&gt;可积。 方向导数方向导数 百度百科 梯度 梯度 百度百科 方向导数与梯度 定义与习题 如何直观形象的理解方向导数与梯度以及它们之间的关系？ 方向导数的存在性及其与偏导数和全微分的关系 梯度的本意是一个向量（矢量），表示某一函数在该点处的方向导数沿着该方向取得最大值，即函数在该点处沿着该方向（此梯度的方向）变化最快，变化率最大（为该梯度的模）。 梯度下降算法梯度下降算法 百度百科 梯度下降是迭代法的一种,可以用于求解最小二乘问题(线性和非线性都可以)。在求解机器学习算法的模型参数，即无约束优化问题时，梯度下降（Gradient Descent）是最常采用的方法之一，另一种常用的方法是最小二乘法。在求解损失函数的最小值时，可以通过梯度下降法来一步步的迭代求解，得到最小化的损失函数和模型参数值。反过来，如果我们需要求解损失函数的最大值，这时就需要用梯度上升法来迭代了。在机器学习中，基于基本的梯度下降法发展了两种梯度下降方法，分别为随机梯度下降法和批量梯度下降法。 梯度下降算法的缺点：靠近极小值时收敛速度减慢、直线搜索时可能会产生一些问题、可能会“之字形”地下降。]]></content>
      <categories>
        <category>数学</category>
      </categories>
      <tags>
        <tag>微积分</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[深度学习中的计算题]]></title>
    <url>%2F2019%2F08%2F01%2F%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E4%B8%AD%E7%9A%84%E8%AE%A1%E7%AE%97%E9%A2%98%2F</url>
    <content type="text"><![CDATA[感受视野在卷积神经网络中，感受野（Receptive Field）的定义是卷积神经网络每一层输出的特征图（feature map）上的像素点在输入图片上映射的区域大小。通俗点的解释是，特征图上的一个点对应输入图上的区域，如下图所示。 感受野计算时有下面几个知识点需要知道： 最后一层（卷积层或池化层）输出特征图感受野的大小等于卷积核的大小。 第i层卷积层的感受野大小和第i层的卷积核大小和步长有关系，同时也与第（i+1）层感受野大小有关。 计算感受野的大小时忽略了图像边缘的影响，即不考虑padding的大小。 关于感受野大小的计算方式是采用从最后一层往下计算的方法，即先计算最深层在前一层上的感受野，然后逐层传递到第一层，使用的公式可以表示如下： RF_i=(RF_{i+1} - 1) \times stride_i + Ksize其中,$RF_i$和$RF_{i+1}$分别是是第i层和第i+1层卷积层的感受视野，stride是卷积的步长，Ksize是本层卷积核的大小。 注意，由于没有考虑padding的影响，最终算出的感受视野可能会大于原图。 感受视野例题 理解原理卷积神经网络中感受野的理解和计算 维度变化conv2d的卷积操作后维度变化输入维度：$W_1 \times H_1 \times D_1$，分别代表输入样本的长宽高 卷积操作的超参数 卷积核个数：$K$ 卷积核大小：$F \times F$ 滑动步长（Stride）：$S$ 填充（Padding）：$P$ 则输出的维度为$W_2 \times H_2 \times D_2$，其中 $W_2=\lceil (W_1 - F + 2P)/S \rceil + 1$ $H_2=\lceil (W_1 - F + 2P)/S \rceil + 1$ $D_2=K$ 由于CNN的参数共享机制，每个卷积核的参数个数为$F \times F \times D_1$，共有$(F \times F \times D_1) \times K$个权重和$K$个偏置。 若想要卷积后得到的矩阵长宽与卷积前保持一致，则当$S=1$时 卷积核为3时 padding 选择1 卷积核为5时 padding 选择2 卷积核为7时 padding 选择3 例题100×100×3，3×3 卷积核，输出是 50×50×10，算进行了多少次乘-加操作？ 卷积运算次数 = 输出元素个数 x 输入通道数= 50×50×10x3 = 75000 乘法运算次数 = 卷积运算次数 x 卷积和元素个数 = 75000 x 3 x 3 加法运算次数 = 卷积运算次数 x (卷积核元素个数 + 偏置个数 - 1) = 75000 x ( 3 x 3 + 1 - 1) = 225000 conv2d的卷积操作后维度变化（”VALID” or “SAME”）注意，在使用神经网络框架时常常会使用padding这个参数，计算方式会有所不同。 1padding: A string, either &quot;VALID&quot; or &quot;SAME&quot;. The padding algorithm. Valid: 用过滤器在输入的矩阵中按步长移动时候，会把最后的不足部分的列和行抛弃；Same: 先在输入矩阵上下各加个值为0的行，在左右各加个个值为0的列，也就是用0把原先的矩阵包裹一层，然后在移动的时候如果输入矩阵的列或者行长度不够，就用0来补齐 计算方法SAME: out_height = ceil(float(in_height) / float(strides[1])) out_width = ceil(float(in_width) / float(strides[2])) VALID: out_height = ceil(float(in_height - filter_height + 1) / float(strides1)) out_width = ceil(float(in_width - filter_width + 1) / float(strides[2])) 例题 max_pool2d的池化操作后维度变化输入维度：$W_1 \times H_1 \times D_1$，分别代表输入样本的长宽高 池化操作的超参数 池化层大小：$F \times F$ 滑动步长（Stride）：$S$ 填充（Padding）：$P$ 则输出的维度为$W_2 \times H_2 \times D_2$，其中 $W_2=\lceil (W_1 - F + 2P)/S \rceil + 1$ $H_2=\lceil (W_1 - F + 2P)/S \rceil + 1$ $D_2=D_1$ 神经网络的参数量计算方法Embedding Neural network structure Parameter quantity input_shape [batch_size, input_length] Dense(input_dim, output_dim) input_dim * output_dim output_shape [batch_size, input_length, output_dim] Dense Neural network structure Parameter quantity input_shape [batch_size, input_dim] Dense(units) input_dim * units + units output_shape [batch_size, units] Conv2D Neural network structure Parameter quantity input_shape [batch_size, rows, cols, input_dim] Conv2D(filters, kernel_size) kernel_size kernel_size filters + filters output_shape [batch_size, new_rows, new_cols, filters] LSTM123456789h_depth = self._num_units if self._num_proj is None else self._num_projself._kernel = self.add_variable( _WEIGHTS_VARIABLE_NAME, shape=[input_depth + h_depth, 4 * self._num_units])self._bias = self.add_variable( _BIAS_VARIABLE_NAME, shape=[4 * self._num_units], initializer=init_ops.zeros_initializer(dtype=self.dtype)) Neural network structure Parameter quantity input_shape [batch_size, input_length, input_depth] LSTM(num_units) (input_depth + num_units) (4 num_units) + 4 * num_units output_shape [batch_size, input_length, num_units]]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[基于Python实现的排序算法]]></title>
    <url>%2F2019%2F07%2F22%2F%E5%9F%BA%E4%BA%8EPython%E5%AE%9E%E7%8E%B0%E7%9A%84%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%2F</url>
    <content type="text"><![CDATA[所谓排序算法，即通过特定的算法因式将一组或多组数据按照既定模式进行重新排序。这种新序列遵循着一定的规则，体现出一定的规律，因此，经处理后的数据便于筛选和计算，大大提高了计算效率。对于排序，我们首先要求其具有一定的稳定性，即当两个相同的元素同时出现在某个序列之中，则经过一定的排序算法之后，两者在排序前后的相对位置不发生变化。换言之，即便是两个完全相同的元素，它们在排序过程中也是各有区别的，不允许混淆不清。 排序算法的时间复杂度与空间复杂度 比较排序和非比较排序时间复杂度分析常见的排序算法都是比较排序，非比较排序包括计数排序、桶排序和基数排序，非比较排序对数据有要求，因为数据本身包含了定位特征，所有才能不通过比较来确定元素的位置。 比较排序的时间复杂度通常为O(n2)或者O(nlogn)，比较排序的时间复杂度下界就是O(nlogn)，而非比较排序的时间复杂度可以达到O(n)，但是都需要额外的空间开销。 基于比较的排序，时间复杂度下界是o(nlogn)的分析： 对于n个待排序元素，在未比较时，可能的正确结果有n!种。 在经过一次比较后，其中两个元素的顺序被确定，所以可能的正确结果剩余n!/2种。 依次类推，直到经过m次比较，剩余可能性n!/(2^m)种。 直到n!/(2^m)&lt;=1时，结果只剩余一种。此时的比较次数m为o(nlogn)次。 所以基于排序的比较算法，最优情况下，复杂度是o(nlogn)的。 比较排序时间复杂度为O(nlogn)的证明：a1,a2,a3……an序列的所有排序有n!种，所以满足要求的排序a1’,a2’,a3’……an’（其中a1’&lt;=a2’&lt;=a3’……&lt;=an’）的概率为1/n!。基于输入元素的比较排序，每一次比较的返回不是0就是1，这恰好可以作为决策树的一个决策将一个事件分成两个分支。比如冒泡排序时通过比较a1和a2两个数的大小可以把序列分成a1,a2……an与a2,a1……an（气泡a2上升一个身位）两种不同的结果，因此比较排序也可以构造决策树。根节点代表原始序列a1,a2,a3……an，所有叶子节点都是这个序列的重排（共有n!个，其中有一个就是我们排序的结果a1’,a2’,a3’……an’）。如果每次比较的结果都是等概率的话（恰好划分为概率空间相等的两个事件），那么二叉树就是高度平衡的，深度至少是log(n!)。 又因为: n! &lt; nn ,两边取对数就得到log(n!)&lt;nlog(n)，所以log(n!) = O(nlogn) n!=n(n-1)(n-2)(n-3)…1 &gt; (n/2)^(n/2) 两边取对数得到 log(n!) &gt; (n/2)log(n/2) = Ω(nlogn)，所以 log(n!) = Ω(nlogn) 因此log(n!)的增长速度与 nlogn 相同,即 log(n!)=Θ(nlogn)，这就是通用排序算法的最低时间复杂度O(nlogn)的依据。 如何证明快速排序法的平均复杂度为 O(nlogn)？ 基于Python实现排序算法123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503import sysimport random# Code Reference https://github.com/TheAlgorithms/Python/tree/master/sorts"""排序算法 https://baike.baidu.com/item/排序算法/5399605排序算法，即通过特定的算法因式将一组或多组数据按照既定模式进行重新排序。这种新序列遵循着一定的规则，体现出一定的规律，因此，经处理后的数据便于筛选和计算，大大提高了计算效率。对于排序，我们首先要求其具有一定的稳定性，即当两个相同的元素同时出现在某个序列之中，则经过一定的排序算法之后，两者在排序前后的相对位置不发生变化。换言之，即便是两个完全相同的元素，它们在排序过程中也是各有区别的，不允许混淆不清。排序(Sorting) 是计算机程序设计中的一种重要操作，它的功能是将一个数据元素（或记录）的任意序列，重新排列成一个关键字有序的序列。排序就是把集合中的元素按照一定的次序排序在一起。一般来说有升序排列和降序排列2种排序，在算法中有8中基本排序：(1)冒泡排序；(2)选择排序；(3)插入排序；(4)希尔排序；(5)归并排序；(6)快速排序；(7)基数排序；(8)堆排序。"""def bubble_sort(input_list): """ 冒泡排序 冒泡排序算法是把较小的元素往前调或者把较大的元素往后调。这种方法主要是通过对相邻两个元素进行大小的比较， 根据比较结果和算法规则对该二元素的位置进行交换，这样逐个依次进行比较和交换，就能达到排序目的。 冒泡排序的基本思想是，首先将第1个和第2个记录的关键字比较大小，如果是逆序的，就将这两个记录进行交换， 再对第2个和第3个记录的关键字进行比较，依次类推，重复进行上述计算，直至完成第(n一1)个和第n个记录的关键字之间的比较， 此后，再按照上述过程进行第2次、第3次排序，直至整个序列有序为止。排序过程中要特别注意的是， 当相邻两个元素大小一致时，这一步操作就不需要交换位置，因此也说明冒泡排序是一种严格的稳定排序算法， 它不改变序列中相同元素之间的相对位置关系。 """ output_list = input_list.copy() input_list_len = len(input_list) for ordered_item_num in range(input_list_len - 1): # 遍历次数 flag = True # 设定一个标记，若为true，则表示此次循环没有进行交换，也就是待排序列已经有序，排序已经完成。 for idx in range(input_list_len - ordered_item_num - 1): # 每次遍历处理的范围 if output_list[idx] &gt; output_list[idx + 1]: output_list[idx], output_list[idx + 1] = output_list[idx + 1], output_list[idx] flag = False if flag: break return output_listdef select_sort(input_list): """ 选择排序 选择排序算法的基本思路是为每一个位置选择当前最小的元素。 选择排序的基本思想是，基于直接选择排序和堆排序这两种基本的简单排序方法。 首先从第1个位置开始对全部元素进行选择，选出全部元素中最小的给该位置， 再对第2个位置进行选择，在剩余元素中选择最小的给该位置即可； 以此类推，重复进行“最小元素”的选择，直至完成第(n-1)个位置的元素选择， 则第厅个位置就只剩唯一的最大元素，此时不需再进行选择。 使用这种排序时，要注意其中一个不同于冒泡法的细节。 举例说明：序列58539．我们知道第一遍选择第1个元素“5”会和元素“3”交换， 那么原序列中的两个相同元素“5”之间的前后相对顺序就发生了改变。 因此，我们说选择排序不是稳定的排序算法，它在计算过程中会破坏稳定性。 """ output_list = input_list.copy() input_list_len = len(input_list) for ordered_item_num in range(input_list_len - 1): # 遍历次数 min_number_idx = ordered_item_num for idx in range(ordered_item_num + 1, input_list_len): # 每次遍历处理的范围 if output_list[idx] &lt; output_list[min_number_idx]: min_number_idx = idx output_list[ordered_item_num], output_list[min_number_idx] = \ output_list[min_number_idx], output_list[ordered_item_num] return output_listdef insert_sort(input_list): """ 插入排序 插入排序算法是基于某序列已经有序排列的情况下，通过一次插入一个元素的方式按照原有排序方式增加元素。 这种比较是从该有序序列的最末端开始执行，即要插入序列中的元素最先和有序序列中最大的元素比较， 若其大于该最大元素，则可直接插入最大元素的后面即可，否则再向前一位比较查找直至找到应该插入的位置为止。 插入排序的基本思想是，每次将1个待排序的记录按其关键字大小插入到前面已经排好序的子序列中，寻找最适当的位置， 直至全部记录插入完毕。执行过程中，若遇到和插入元素相等的位置，则将要插人的元素放在该相等元素的后面， 因此插入该元素后并未改变原序列的前后顺序。我们认为插入排序也是一种稳定的排序方法。 插入排序分直接插入排序、折半插入排序和希尔排序3类。 """ output_list = list() output_list.append(input_list[0]) input_list_len = len(input_list) for item_idx in range(1, input_list_len): # 遍历次数 insert_number_value = input_list[item_idx] insert_location = len(output_list) for ordered_number_value in output_list[::-1]: if insert_number_value &lt; ordered_number_value: insert_location = insert_location - 1 else: break output_list.insert(insert_location, insert_number_value) return output_listdef shell_sort(input_list): """ 希尔排序 选择一个增量序列 t1，t2，……，tk，其中 ti &gt; tj, tk = 1； 按增量序列个数 k，对序列进行 k 趟排序； 每趟排序，根据对应的增量 ti，将待排序列分割成若干长度为 m 的子序列，分别对各子表进行直接插入排序。仅增量因子为 1 时，整个序列作为一个表来处理，表长度即为整个序列的长度。 """ output_list = input_list.copy() input_list_len = len(input_list) # 初始间隔 gap = input_list_len // 2 while gap &gt; 0: for i in range(gap, input_list_len): # 类似插入排序, 当前值与指定步长之前的值比较, 符合条件则交换位置 while i &gt;= gap and output_list[i - gap] &gt; output_list[i]: output_list[i], output_list[i - gap] = output_list[i - gap], output_list[i] i = i - gap gap = gap // 2 return output_listdef shell_sort_2(input_list): """ 希尔排序 """ output_list = input_list.copy() input_list_len = len(input_list) # 初始间隔 gap = input_list_len // 2 while gap &gt; 0: for i in range(gap, input_list_len): for j in range(i, gap - 1, -gap): # j 最小可以取到 gap, 也就保证了 j - gap &gt;=0 不会越界 if output_list[j] &lt; output_list[j - gap]: output_list[j], output_list[j - gap] = output_list[j - gap], output_list[j] else: break gap = gap // 2 return output_listdef merge_sort(input_list): """ 归并排序 归并排序算法就是把序列递归划分成为一个个短序列， 以其中只有1个元素的直接序列或者只有2个元素的序列作为短序列的递归出口， 再将全部有序的短序列按照一定的规则进行排序为长序列。 归并排序融合了分治策略，即将含有n个记录的初始序列中的每个记录均视为长度为1的子序列， 再将这n个子序列两两合并得到n/2个长度为2(当凡为奇数时会出现长度为l的情况)的有序子序列； 将上述步骤重复操作，直至得到1个长度为n的有序长序列。需要注意的是，在进行元素比较和交换时， 若两个元素大小相等则不必刻意交换位置，因此该算法不会破坏序列的稳定性，即归并排序也是稳定的排序算法。 """ def _merge_operation_of_merge_sort(input_list_A, input_list_B): output_list = list() list_A_len = len(input_list_A) list_B_len = len(input_list_B) i, j = 0, 0 while i &lt; list_A_len and j &lt; list_B_len: a = input_list_A[i] b = input_list_B[j] if a &lt;= b: output_list.append(a) i += 1 else: output_list.append(b) j += 1 if i == list_A_len: output_list.extend(input_list_B[j:]) else: output_list.extend(input_list_A[i:]) return output_list input_list_len = len(input_list) if input_list_len &lt;= 1: return input_list middle = input_list_len // 2 left_list = merge_sort(input_list[:middle]) right_list = merge_sort(input_list[middle:]) return _merge_operation_of_merge_sort(left_list, right_list)def quick_sort(input_list): """ 快速排序 从数列中挑出一个元素，称为 “基准”（pivot）; 重新排序数列，所有元素比基准值小的摆放在基准前面，所有元素比基准值大的摆在基准的后面（相同的数可以到任一边）。在这个分区退出之后，该基准就处于数列的中间位置。这个称为分区（partition）操作； 递归地（recursive）把小于基准值元素的子数列和大于基准值元素的子数列排序； https://www.jianshu.com/p/2b2f1f79984e """ def _partition(input_list, left, right): """ 返回基准pivot值的位置，并且满足input_list[left, right]这段区间内， 大于基准值的数值都在基准值的右侧，小于基准值的数值都在基准值左侧。 :param input_list: 待处理的列表 :param left: 列表起始位置left :param right: 列表结束位置right :return: 基准pivot值的位置 1. 最初left所指位置的值被选做基准pivot 当 left &lt; right 时（说明[left, right]区间的值还未处理）执行： 2. 然后left所指位置被当做交换区，right所指位置被当做判断区。 当满足要求（left &lt; right 且 right所指的值大于基准pivot）时，一直执行right所指位置向左推进一位。 当不满足要求时则将right所指位置的值移动到left所指交换区。 3. 然后right所指位置被当做交换区，left所指位置被当做判断区。 当满足要求（left &lt; right 且 left所指的值小于基准pivot）时，一直执行left所指位置向右推进一位。 当不满足要求时则将left所指位置的值移动到right所指的交换区。 当 left == right时（说明只剩下left所指位置没有处理）： 此时已经满足left所指位置的左侧值小于基准pivot，left所指位置的右侧值大于基准pivot。 直接将基准值放入left所指位置即可。 4. 返回基准值所在的位置 left """ pivot_value = input_list[left] while left &lt; right: while left &lt; right and input_list[right] &gt;= pivot_value: right -= 1 input_list[left] = input_list[right] while left &lt; right and input_list[left] &lt; pivot_value: left += 1 input_list[right] = input_list[left] input_list[left] = pivot_value return left def _quick_sort(input_list, left, right): if left &lt; right: # 当区间有两个及以上的值时进行递归操作 pivot = _partition(input_list, left, right) _quick_sort(input_list, left, pivot - 1) _quick_sort(input_list, pivot + 1, right) return input_list input_list_len = len(input_list) return _quick_sort(input_list, 0, input_list_len - 1)def quick_sort_2(input_list): """ 快速排序 快速排序的基本思想是:通过一趟排序算法把所需要排序的序列的元素分割成两大块， 其中，一部分的元素都要小于或等于另外一部分的序列元素， 然后仍根据该种方法对划分后的这两块序列的元素分别再次实行快速排序算法， 排序实现的整个过程可以是递归的来进行调用，最终能够实现将所需排序的无序序列元素变为一个有序的序列。 """ length = len(input_list) if length &lt;= 1: return input_list else: # Use the last element as the first pivot pivot = input_list.pop() # Put elements greater than pivot in greater list # Put elements lesser than pivot in lesser list greater, lesser = [], [] for element in input_list: if element &gt; pivot: greater.append(element) else: lesser.append(element) return quick_sort_2(lesser) + [pivot] + quick_sort_2(greater)def heap_sort(input_list): """ 堆排序 https://www.cnblogs.com/cj723/archive/2011/04/22/2024269.html https://www.jianshu.com/p/d174f1862601 """ def _heap_adjust(array, start, end): """ 调整列表array满足堆性质 :param array: 待调整为满足堆性质的列表 :param start: 要调整的堆的根节点位置 :param end: 列表要处理数值的最大位置 :return: 调整为满足堆性质的列表 1. 取出根节点的位置start对应的数值temp，计算出该根节点的左孩子位置child 当 child &lt;= end（孩子位置没有超过列表要处理数值的最大位置时）： 2. 如果有两个孩子（child &lt;= end） 且左孩子的值小于右孩子的值（array[child] &lt; array[child + 1]） ，那么把孩子位置移动到右孩子位置； 3. 如果根节点temp值大于等于它所有孩子的值，则退出循环； 4. 将根节点的值调整为最大孩子的值 array[start] = array[child] 根节点位置调整为原来最大孩子的位置 start = child 更新该新的根节点对应的左孩子的位置 child = start * 2 5. 确定出temp最终所处的位置start，然后赋值array[start] = temp """ temp = array[start] child = start * 2 while child &lt;= end: if child &lt; end and array[child] &lt; array[child + 1]: child += 1 if temp &gt;= array[child]: break array[start] = array[child] start = child child = start * 2 array[start] = temp output_list = [0] + list(input_list) # 添加辅助位置0 input_list_len = len(input_list) # 现在的待排序序列构建成一个大顶堆 for start in range(input_list_len // 2, 0, -1): # 对 input_list_len // 2 个父亲节点处理 _heap_adjust(output_list, start, input_list_len) # 逐步将堆结构转换为排序好的数列 # 逐步将每个最大值的根结点与末尾元素交换，并且再调整其成为大顶堆 for end in range(input_list_len, 1, -1): # 遍历次数，需要找到 input_list_len - 1 次最值来交换 output_list[1], output_list[end] = output_list[end], output_list[1] # 交换最值 _heap_adjust(output_list, 1, end - 1) # 重新调整堆 del output_list[0] # 删除辅助位置0 return output_listdef count_sort(input_list): """ 计数排序 什么时候不用计数排序？ 当数组最大最小值差距过大时，并不适用计数排序 当数组元素不是整数，并不适用计数排序 所以当数组最大最小值差远小于数组长度时，使用计数排序更快，比如年龄。 """ if not isinstance(input_list[0], int): raise ValueError("This count_sort code only handles integers!") max, min = input_list[0], input_list[0] for i in input_list: if i &gt; max: max = i if i &lt; min: min = i nums = [0 for _ in range(max - min + 1)] for i in input_list: nums[i - min] += 1 output_list = [] for i in range(len(nums)): output_list += [min + i] * nums[i] return output_listdef bucket_sort(input_list, bucket_size=5): """ 桶排序 https://github.com/TheAlgorithms/Python/blob/master/sorts/bucket_sort.py """ min_value, max_value = (min(input_list), max(input_list)) bucket_count = ((max_value - min_value) // bucket_size + 1) buckets = [[] for _ in range(int(bucket_count))] for i in range(len(input_list)): buckets[int((input_list[i] - min_value) // bucket_size) ].append(input_list[i]) return sorted([buckets[i][j] for i in range(len(buckets)) for j in range(len(buckets[i]))])def bucket_sort_2(input_list, bucket_size=5): """ 桶排序 https://blog.csdn.net/sty945/article/details/81530774 设置固定数量的空桶。 把数据放到对应的桶中。 对每个不为空的桶中数据进行排序。 拼接不为空的桶中数据，得到结果。 """ min_value, max_value = (min(input_list), max(input_list)) # 创建空桶 bucket_count = int(((max_value - min_value) // bucket_size + 1)) buckets = [[] for _ in range(bucket_count)] # 把待排序列表数值放入对应的桶中 for item in input_list: item_buckets_idx = int((item - min_value) // bucket_size) buckets[item_buckets_idx].append(item) # 桶内排序 for i in range(bucket_count): buckets[i].sort() # 产生新的排序后的列表 output_list = [item for bucket in buckets for item in bucket] return output_listdef radix_sort(input_list): """ 基数排序 这个代码仅仅能处理整数 https://github.com/TheAlgorithms/Python/blob/master/sorts/radix_sort.py """ if not isinstance(input_list[0], int): raise ValueError("This radix sorting code only handles integers!") RADIX = 10 placement = 1 min_int_digit = int(min(input_list)) - 1 normal_lst = [item - min_int_digit for item in input_list] # get the maximum number max_digit = max(normal_lst) print(normal_lst) while placement &lt; max_digit: # declare and initialize buckets buckets = [list() for _ in range(RADIX)] # split lst between lists for item in normal_lst: tmp = int((item / placement) % RADIX) buckets[tmp].append(item) # empty lists into lst array a = 0 for b in range(RADIX): buck = buckets[b] for i in buck: normal_lst[a] = i a += 1 print(normal_lst) # move to next placement *= RADIX output_list = [item + min_int_digit for item in normal_lst] return output_listdef produce_random_int_list(number=1000, start=-100, stop=1000): input_list = [random.randint(start, stop) for _ in range(number)] return input_listdef produce_random_float_list(number=1000, start=-100.0, stop=1000.0): input_list = [random.uniform(start, stop) for _ in range(number)] return input_listdef fack_sort(input_list): return input_listdef check_sort_function(sort_function, number=1000): for i in range(100): if i % 2 == 0: input_list = produce_random_int_list(number) else: input_list = produce_random_float_list(number) stand_sort_out = sorted(input_list) custom_sort_medthod_out = sort_function(input_list) for a, b in zip(custom_sort_medthod_out, stand_sort_out): if a != b: print(f"stand &#123;a&#125; != custom &#123;b&#125;") print("stand_sort_out:\t", stand_sort_out) print("custom_sort_medthod_out:\t", custom_sort_medthod_out) raise ValueError("sort_function error!") return Truedef check_sort_process(sort_function): input_list = produce_random_int_list(number=5, start=-100, stop=1000) print("---input_list---", input_list) output_list = sort_function(input_list) print("---output_list---", output_list) print()if __name__ == "__main__": # 排序函数列表 sort_function_list = [bubble_sort, select_sort, insert_sort, shell_sort, shell_sort_2, merge_sort, quick_sort, quick_sort_2, heap_sort, bubble_sort, bucket_sort_2] sort_int_fuction_list = [count_sort, radix_sort] # 排序函数序号 sort_function_index = None if len(sys.argv) == 2: sort_function_index = int(sys.argv[1]) # 检查排序过程 # if sort_function_index is None: # for sort_f in sort_function_list: # check_sort_process(sort_f) # else: # check_sort_process(sort_function_list[sort_function_index]) # 检查排序函数 if sort_function_index is None: for sort_f in sort_function_list: print(f"check &#123;str(sort_f)&#125;...") check_sort_function(sort_f, 1000) else: check_sort_process(sort_function_list[sort_function_index])]]></content>
      <categories>
        <category>数学</category>
      </categories>
      <tags>
        <tag>排序</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Python手册]]></title>
    <url>%2F2019%2F07%2F17%2FPython%E6%89%8B%E5%86%8C%2F</url>
    <content type="text"><![CDATA[Python 语言本身 标题 说明 Python教程 廖雪峰 Python 初学者的首选课程 Python-100-Days Python - 100天从新手到大师 《Python Cookbook》 3rd Edition Translation 《Python Cookbook》 在线阅读地址；Code samples from the “Python Cookbook, 3rd Edition” 《Python进阶》（Intermediate Python 中文版） 英文原版 python-cheatsheet python速查表 Python 语言使用 标题 说明 时间 《统计学习方法》的代码实现 《统计学习方法》可以说是机器学习的入门宝典，许多机器学习培训班、互联网企业的面试、笔试题目，很多都参考这本书。本站根据网上资料用Python复现了课程内容，并提供本书的代码实现、课件下载。 20181217 《The Hitchhiker’s Guide to Python》 Python best practices guidebook, written for humans. python-patterns Python中的一系列设计模式/习语 system-design-primer 了解如何设计大型系统。准备系统设计面试。包括Anki抽认卡。 free-programming-books-zh_CN 免费的计算机编程类中文书籍，欢迎投稿 http://weibo.com/justjavac All Algorithms implemented in Python These implementations are for demonstration purposes. They are less efficient than the implementations in the Python standard library. 机器学习算法Python实现 机器学习实战（Python3） 机器学习实战（Python3）：kNN、决策树、贝叶斯、逻辑回归、SVM、线性回归、树回归 COMS W4995 Applied Machine Learning - Spring 19 机器学习应用课程COMS W4995 Applied Machine Learning Spring 2019 - Schedule 2019 Python 库与项目 类别 标题 说明 时间 人脸识别 face_recognition The world’s simplest facial recognition api for Python and the command line. 数据科学伴侣JupyterBringing the best out of Jupyter Notebooks for Data ScienceTable of Contents Executing Shell Commands Jupyter Themes Notebook Extensions Jupyter Widgets Qgrid Slideshow Embedding URLs, PDFs, and Youtube Videos data-science-ipython-notebooksData science Python notebooks: Deep learning (TensorFlow, Theano, Caffe, Keras), scikit-learn, Kaggle, big data (Spark, Hadoop MapReduce, HDFS), matplotlib, pandas, NumPy, SciPy, Python essentials, AWS, and various command lines.]]></content>
      <categories>
        <category>Artificial Intelligence Navigation</category>
        <category>Python手册</category>
      </categories>
      <tags>
        <tag>Python</tag>
        <tag>Python基础知识</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[使用TensorFlow自动分类NAVER购物产品类别]]></title>
    <url>%2F2019%2F07%2F13%2F%E4%BD%BF%E7%94%A8TensorFlow%E8%87%AA%E5%8A%A8%E5%88%86%E7%B1%BBNAVER%E8%B4%AD%E7%89%A9%E4%BA%A7%E5%93%81%E7%B1%BB%E5%88%AB%2F</url>
    <content type="text"><![CDATA[原文 Auto-classification of NAVER Shopping Product Categories using TensorFlow 背景NAVER Shopping是NAVER提供的购物门户服务。 NAVER Shopping将产品与类别相匹配，以便系统地组织产品并允许更轻松地搜索用户。 当然，每天将超过2000万个新注册产品与大约5,000个类别相匹配的任务是不可能手动完成的。 本文介绍了使用TensorFlow自动匹配NAVER购物产品类别的过程，并解释了我们如何解决在将机器学习应用于我们的服务所使用的实际数据的过程中出现的一些问题。 NAVER购物和产品类别NAVER Shopping是一个购物门户服务，提供产品搜索，类别分类，价格比较和购物内容，以便用户可以轻松访问在NAVER Shopping上注册的卖家以及NAVER Smart Store中的产品。 NAVER Shopping系统地组织产品并将产品分类，以便更轻松地搜索用户。类别分为上类&gt;中类&gt;下类，例如时尚商品&gt;女鞋&gt;平底鞋&gt;休闲鞋。 目前，NAVER Shopping管理的大约5,000个类别。当用户输入关键字以在NAVER Shopping上搜索产品时，它识别输入的关键字的类别，然后根据搜索逻辑列出与关键字类别匹配的产品。为了使用户能够快速找到产品并获得所需的搜索结果，产品应与相应的类别相匹配。 在NAVER Shopping上注册的卖家在测试文件中创建各种产品信息，包括根据EP（引擎页面）指南的卖家类别信息，这是NAVER Shopping上产品注册的数据表格，并将其发送给NAVER Shopping。在发送给NAVER Shopping的各种产品信息中，卖家使用的类别系统可能会有所不同。因此，如上面的类别匹配示例所示，相同的服装可以具有非常不同的类别信息。 为了通过提高搜索准确度来提高购物搜索质量，有必要将卖家使用的类别与适合NAVER购物的类别相匹配。问题是，一个人不可能逐个将新产品与500个NAVER购物类别相匹配。 虽然我们还使用了基于规则的类别匹配，例如卖家的“桌面硬盘”类别如何映射到NAVER Shopping的“HDD”类别，但随着卖家和产品数量的增加，我们再也无法使用基于规则的类别，并且因为NAVER Shopping中的类别经常被重组。相反，可以通过应用自然语言处理（NLP）和计算机视觉等技术来自动化类别匹配。 在为Naver购物服务调整NLP时，很少有事情需要考虑。在大多数情况下，当使用现成的软件时，产品的属性（例如300ml / 500GB）或代码名称（例如SL-M2029，PIXMA-MX922）被归类为停用词并在此过程中被忽略。但是，这些术语对商业服务有意义。为了分析这些词，应该定制NLP过程以满足服务的需要。 类别自动匹配系统架构目前，NAVER Shopping在类别自动匹配系统中使用如下架构进行学习和分类。 关系数据库中大约15亿条产品信息作为搜索结果集提供给用户。监控中心在搜索结果中查找与错误类别匹配的产品，并将其与正确的类别相匹配。由于监控中心匹配的产品的数据由人检查，因此将其视为精炼数据，然后从分布式数据库中提取为学习数据。除了精炼数据之外，还通过考虑产品的各种特征来提取学习数据。 训练服务器通过从分布式数据库读取数据来训练模型，并将增强模型分发到推理服务器。推理服务器每天读取大约2000万个产品的信息（尚未与NAVER类别匹配的产品）以匹配类别，然后更新到数据库。 类别自动匹配模型NAVER Shopping的类别自动匹配模型分析产品数据的特征并通过以下过程训练模型。 发现产品的特征：从产品信息中寻找有用的特征。 形态分析：从产品信息中分析和提取术语。 Word嵌入：将产品功能转换为矢量。 CNN-LSTM 模型 - 产品名称：将CNN-LSTM型号应用于产品名称。 MobileNetV2 - 产品图片：将MobileNetV2模型应用于产品图片。 多输入模型：通过产品中的各种数据连接模型以提高准确性。 产品特征下图中标记的部分是用于自动匹配类别的特征。 从上面的例子中，产品名称没有提到它是女性的T恤还是其他类别的T恤。但是，通过查看图像很容易看到，“产品名称”和“图像”是用户在购买产品时首先看到的元素。当从搜索结果中找到具有不正确类别匹配的产品时，监控中心应仔细查看产品名称和图像，以将产品移动到正确的类别。 因此，产品名称和图像也用作类别自动匹配的主要特征。不仅产品名称和图像，而且卖家使用的类别，产品的最低价格，品牌，制造商，原始图像比例也被用作卖家提供的数十条产品信息中的附加特征。 形态分析用作主要特征的产品名称具有以下特征。 产品名称由名词组成； 混合韩语和英语的产品名称； 包含组合字母和数字的产品/型号代码的产品名称； 产品名称包含用于描述产品概念的词语（例如宽松合体）； 没有空格分隔的产品名称。由于韩国人的特点，即使没有空格分隔也可以理解意义（汉语也具体有该特点）。 为了使产品名称具有适合购物领域的含义，描述概念的单词、模型代码和产品属性不应分开，而不带空格的产品名称则以术语单位提取。 词嵌入我们尝试使用带有维基百科内容的预训练矢量，但认为产品数据的特征没有用于构建词嵌入。 因此，我们使用Word2vec方法直接构建了包含产品数据特征的字嵌入。是否正确构建嵌入向量（Word2vec的结果）可以使用TensorFlow的可视化工具TensorBoard进行探索。 CNN-LSTM Model — 产品名称通过按以下顺序应用CNN-LSTM模型来解析产品名称，即文本数据。 CNN模型：从产品名称中提取特定文本区域的功能。 LSTM模型：根据长产品名称中的附近单词识别当前单词的含义。 CNN-LSTM模型：CNN提取的局部特征依次集成在LSTM中。 Dimensional Sentiment Analysis Using a Regional CNN-LSTM Model CNN滤波器可以在图像处理中提取特定图像区域的特征，并在文本处理中提取特定文本区域的特征。在NAVER Shopping的产品名称中，您可以看到出现的产品的主要关键字，无论位置如何。 通常，文本中的单词的含义（例如，反讽）基于附近的单词（单词之前和之后）来理解。既然如此，LSTM模型被称为适合于数据处理的模型，如本文中那样顺序出现。在NAVER Shopping的产品名称中，您可以看到仅在查看周围的关键字时才能进行分类的产品名称。 CNN-LSTM模型表现出更优越的性能。这是一种通过输入字嵌入（矢量）来提取局部特征然后使用LSTM模型顺序地集成特征来通过卷积层和最大池层的方法。 CNN模型可以通过将输入数据划分为多个区域来提取特定的本地信息，但是不能确定长句中的单词之间的依赖性。通过将CNN模型与LSTM模型组合以在句子中顺序地整合本地信息，可以解决这些限制。 MobileNetV2 - 产品图片MobileNet是一种可用于图像分类和对象检测的模型。 与VGG相比，MobileNet的准确性相似。但是，与VGG相比，MobileNet的计算和参数数量为1/10，因此适用于没有GPU设备或需要实时性能的服务的服务器。 多输入模型 - 产品混合信息对于类别的自动匹配，可以单独训练使用产品名称的模型和使用产品图像的模型。但是，由于产品名称和图像是单一产品的属性，因此集成训练实际上提高了模型的准确性。 如果您不仅对产品名称和图像进行综合培训，还要对品牌，制造商，原始图像比例，业务运营中使用的类别以及产品的最低价格进行综合培训，如下图所示，然后可以训练与产品相关的属性的相关性。 类别自动匹配和解决方案中发现的问题将类别自动匹配应用于实际服务数据时发现了一些问题。 特征可视化在应用类别自动匹配之前，必须有一种方法来验证匹配结果是否已正确分配。如果您上传适合的特征向量和标签到TensorFlow’s embedding projector，则可以轻松检查类别分布和类别之间的距离。通过单击一个点（类别），您可以看到该点附近的点（类似类别）是什么。如果该点位于可视化结果中的附近，但根本不在相关类别中，则表示它是具有错误匹配概率的类别。 数据规范化时装&gt;女装&gt;连衣裙的产品数量比率，NAVER购物的热门类别，生活/健康&gt; DVD&gt;文化/纪录片，不是一个流行的类别约1000：1，使数据高度不平衡。如果使用像这样的不平衡产品分布中的学习数据进行训练，则可能导致问题，其中适当的结果偏向具有更多产品的类别以提高整体准确性。左下图是应用数据标准化之前，按类别的产品分布显示索引函数的形状。因此，我们将以下日志函数应用于数据规范化的学习数据： 通过应用数据规范化，产品数量按类别均匀分布，如右图所示，并且已经解决了偏向流行类别的适当结果的问题。 反映趋势在线购物中心的产品寿命很短，对趋势非常敏感。特别是，由于每个季节都会生产服装等产品，因此存在产品不断被删除和创造的趋势。例如，仅使用文本学习的模型将发现仅在添加新趋势产品时读取单词时难以理解其类别，例如“Anorak”。学习文本和图像的模型可以通过使用图像添加一个名为“Anorak”的新产品时将其分类为夹克。 在这种情况下，我们应该分析长期准确性，如下图所示，以验证模型是否能够继续准确地预测，并让它跟随产品的趋势，同时不断更新学习数据和模型以满足趋势。 训练数据管道通常，为了更新学习数据，我们必须从HDFS中提取SQL语法，将其保存为学习服务器中的文件，然后在代码中加载数据并重新训练模型。在这种通用方法中，随着学习数据变大，保存为文件和加载所花费的时间变得更长，以及占用服务的大量磁盘空间，使其效率低下。 TensorFlow提供了一种使用tf.data管道直接从HDFS读取学习数据的方法。当使用该Dataset.prefetch()方法时，如下面的示例所使用的那样，由于它以块的形式读取数据，因此它可以在学习GPU中的第一个数据的同时在CPU中准备第二个数据，从而减少资源的空闲状态。 模棱两可的分类NAVER Shopping的类别是为了方便用户而构建的，由于同名的许多较低类别，很难区分上层类别。由于允许模型学习并不是一个好的结构，因此有必要选择需要额外学习的类别来改变模型易于学习的结构，或管理标准类别（例如UNSPSC，联合国标准产品和服务代码）在商业环境中分开并让它学习。 卖家提供的信息不正确在某些情况下，卖方通过将产品类别与NAVER购物类别进行第一手匹配来发送产品信息。该信息也是用于学习数据的条件，因为它是由人匹配的数据。但是，有时用于学习的主要产品元素包含错误。为了从学习数据中删除错误数据，我们应该使用诸如通过选择发送高质量产品信息的卖家来增加学习重量的方法。 总结我们已经讨论了在NAVER Shopping中运行的类别自动匹配模型以及相关问题和解决方案。首先，我们从产品中发现了有用的特征，在文本数据的情况下分析了语素，并使用了CNN和LSTM模型。对于图像数据，我们使用MobileNet模型开发了类别自动匹配模型。 此外，我们还研究了使用TensorBoard的数据可视化，以及如何使用数据规范化和TensorFlow管道。 在提供这个项目的过程中，我们能够更全面地理解机器学习和深度学习的问题，在识别存在的其他问题的过程中，而不是仅仅考虑模型的准确性，将模型应用于实际服务环境。 目前，自动匹配的准确率约为85％。我们的目标是通过使用各种方法继续改进模型以实现更高的准确性，例如产品名称的日期细化，图像特征提取的效率和精确的验证集构建。]]></content>
      <categories>
        <category>Artificial Intelligence 商业实践</category>
      </categories>
      <tags>
        <tag>TensorFlow</tag>
        <tag>分类</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[短视频分类技术]]></title>
    <url>%2F2019%2F07%2F11%2F%E7%9F%AD%E8%A7%86%E9%A2%91%E5%88%86%E7%B1%BB%E6%8A%80%E6%9C%AF%2F</url>
    <content type="text"><![CDATA[视频分类理论和实践研究 标题 内容 时间 基于视觉的视频分类入门 20180408 爱奇艺“多模态视频人物识别”课程分享学习总结 20181005 Five video classification methods implemented in Keras and TensorFlow 对应的代码 five-video-classification-methods 20190504 HHTseng/video-classification Tutorial for video classification/ action recognition using 3D CNN/ CNN+RNN on UCF101 20190601 实战项目Multimodal-short-video-dataset-and-baseline-classification-model 500,000 multimodal short video data and baseline models. 50万条多模态短视频数据集和基线模型（TensorFlow2.0）。 论文和数据集资源 iQIYI-VID: A Large Dataset for Multi-modal Person Identification 2019 爱奇艺短视频分类技术解析简介近年来，短视频领域一直广受关注，且发展迅速。每天有大量UGC短视频被生产、分发和消费，为生产系统带来了巨大的压力，其中的难点之一就是为每个短视频快速、准确地打上标签。为了解决人工编辑的时效和积压问题，自动化标签技术成为各大内容领域公司都非常关注的关键课题。短视频大规模层次分类作为内容理解技术的一个重要方向，为爱奇艺的短视频智能分发业务提供着强力支持，其输出被称为“类型标签”。 技术难点分类体系复杂。短视频分类体系是一棵人工精心制定的层次结构，体系和规则都比较复杂：层级最少有3级，最多有5级，总计近800个有效类别，类别间有互斥和共同出现的需求。 需要文本、图像、生态信息等多模态特征综合判断。短视频具有标题、描述、封面图、视频、音频等媒体信息。同时，一个短视频也不一定是独立存在的，它可能来自一个影视、综艺片段，它的上传者可能是一个垂直领域的内容贡献者，所以，关联正片、视频来源、上传者等信息对分类也可能有帮助。 解决方案短视频分类可以分为特征表示(Feature Representation) 和层次分类(Hierarchical Classification) 两个模块，前者基于多模态特征建模短视频的整体表达（在我们的模型中通过Feature Representation和Representation Fusion两个子网络级联建模完成），后者基于前者完成分类任务。我们模型的整体结构如下图： PRCV2018 美图短视频实时分类挑战赛第一名解决方案介绍视频解码因为时间是一个很重要的因素，而视频解码又是一个很费时间的过程，所以如何设计解码模块是本次竞赛中的一个关键。我们采用了多线程软解提取关键帧的方法。 主流的视频编码方式中，每个视频主要包含三种图片帧，分别叫做：Intra-coded frame（I 帧），Predictive frame（P 帧）和 Bi-Predictive frame（B 帧）。其中 I 帧是一张完整的图片。P 帧记录了与之前的帧的差别，所以在解码 P 帧时必须要参考之前的图片帧。而 B 帧不仅需要参考之前的图片帧，还需要参考之后的图片帧才能完整解码。图片 4 阐明了这三个概念 [2]。显而易见，P 帧和 B 帧的解码是相对较慢的，而直接解码 I 帧则可以获得更快的速度。同时，由于我们需要解码不止一帧，所以我们采用了多线程的方式，每一个线程负责解码一个关键帧。整个解码过程使用 FFmpeg 实现。 模型设计解决了解码问题后，接下来的问题在于如何用所得的多帧来进行分类。 主流方法目前主流的视频分类的方法有三大类：基于 LSTM 的方法，基于 3D 卷积的方法和基于双流的方法。图片 5 展示了这三种框架的大体结构 [3]。 基于 LSTM 的方法将视频的每一帧用卷积网络提取出每一帧的特征，然后将每一个特征作为一个时间点，依次输入到 LSTM 中。由于 LSTM 并不限制序列的长度，所以这种方法可以处理任意长度的视频。但同时，因为 LSTM 本身有梯度消失和爆炸的问题，往往难以训练出令人满意的效果。而且，由于 LSTM 需要一帧一帧得进行输入，所以速度也比不上其他的方法。 基于 3D 卷积的方法将原始的 2D 卷积核扩展到 3D。类似于 2D 卷积在空间维度的作用方式，它可以在时间维度自底向上地提取特征。基于 3D 卷积的方法往往能得到不错的分类精度。但是，由于卷积核由 2D 扩展到了 3D，其参数量也成倍得增加了，所以网络的速度也会相应下降。 基于双流网络的方法会将网络分成两支。其中一支使用 2D 卷积网络来对稀疏采样的图片帧进行分类，另一支会提取采样点周围帧的光流场信息，然后使用一个光流网络来对其进行分类。两支网络的结果会进行融合从而得到最终的类标。基于双流的方法可以很好地利用已有的 2D 卷积网络来进行预训练，同时光流又可以建模运动信息，所以精度往往也很高。但是由于光流的提取过程很慢，所以整体上制约了这一方法的速度。综上所述，主流的方法都不太适用于短视频实时分类的任务，所以我们特别设计了一个适用于短视频实时分类的框架。 我们的方法图片 4 展示了我们的解决方案的整体框架：给定一个视频，我们首先会从中稀疏采样固定数量的图片帧，然后将这些帧组成一个 batch，送入到一个 BaseNet 中。这个 BaseNet 是在已有的 2D 卷积网络基础上优化改进得到的，具有较强的特征提取能力。BaseNet 输出的高层的特征往往具有很强的语义信息，但是却没有时间上的融合。所以我们特别设计了一个基于帧间注意力机制的融合模型，将 BaseNet 提取的不同帧的特征作为一个输入送入融合模型中，最终由融合模型得到预测的结果。由于融合模型比较小，推理速度很快，而且参数量较少，也比较容易训练。整个模型在 mxnet 上进行构建和训练。基于这样的设计，我们的模型可以得到很快的推理速度，同时又不会损失太多精度。 2019 重新认识快手：人工智能的从 0 到 1多模态理解的挑战过去几年，单模态内容理解能力在学术界还不够成熟，加上学术界对视频理解没有强烈的研究需求，导致始终没有形成一套针对视频理解的求解方案。在工业界，即使是全球最大的视频平台 YouTube，也因为其视频带有丰富的文本信息—标题、简介、标签，可以一定程度上绕开视频理解。 但快手不同。作为一款移动互联网时代兴起的短视频应用，快手给用户提供轻便新颖的拍视频体验，用户喜欢拍完就传，不爱文字编辑，描述视频的文字信息严重缺失。快手又需要理解内容来做推荐算法，视频理解成了一个绕不开的坎。李岩说，快手是较早对视频内容分析产生强烈刚需的公司。 复杂的应用场景和多元的用户分布给 MMU 带来了另一个维度的挑战。负责视频理解方向的朝旭是 MMU 组的老员工，他给机器之心举了一个例子：快手上有很多景色的视频内容，有些景色很美、有空灵感的画面犹如「仙境」，那么快手的标签里就需要描述「仙境」这类景色；但是在学术界的数据集里面，你是不会看到这种「诡异」的标签。 「这不再是一个具体的分类算法问题，而是说你怎么去定义一个合理的标签体系。」 语音组最直观的问题是方言口音。MMU 语音组的月朗介绍说，快手用户的地域分布结构和中国移动互联网的人群分布结构基本一致：一线城市人口占比只有 7% 左右，另外 93% 的人都生活在非一线城市，特别是许多小镇青年、或者是三四线以下的人们说话，都带有很强的口音，这就需要快手收集特定方言区域的语音和文本数据。 音乐组面临的一个难题是给用户唱歌打分。传统的歌唱打分是将用户所唱的歌曲和原唱音频做对比，匹配度越高分数越高。但在快手，许多用户是来自偏远地区的少数民族，他们所唱的民歌山歌在快手的检索库里根本找不到。 「我们现在要求解的不是 1+1 等于 2 的这个问题，而是你在算 1+1 的时候，你发现连纸和笔都没有，」朝旭说。 经过两年的摸索，MMU 组基于多模态技术，逐渐形成了两大业务体系：信息分发和人机交互。前者利用多模态实现精准地视频内容理解，后者利用多模态来辅助人们更好地记录生活。 为了更好地理解这两个方向，我们各举一例：冷启动项目属于内容分发，指的是在用户在刚打开快手 app 时，除了内容和视频中的人物，算法无法获得任何行为数据，因为用户打开快手的一个页面是「发现」而非「关注」，所以快手在冷启动阶段就要提供个性化的内容推荐。MMU 组在 2018 年参与了优化冷启动的项目。 人机交互上，视频配乐是一个典型的多模态理解场景。MMU 音乐组的水寒告诉机器之心，快手需要首先理解视频，包括人脸识别、年龄性别、动作时间地点场景的识别，然后对音乐的风格情感、节奏、主题、以及适合度做场景理解，这个过程涉及到多部门之间的协作，包括视频理解方面、人脸识别、自然语言处理、视频检索、音乐检索、以及最后的推荐算法。]]></content>
      <categories>
        <category>Artificial Intelligence 商业实践</category>
      </categories>
      <tags>
        <tag>分类</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[XLNet Generalized Autoregressive Pretraining for Language Understanding]]></title>
    <url>%2F2019%2F07%2F03%2FXLNet_Generalized_Autoregressive_Pretraining_for_Language_Understanding%2F</url>
    <content type="text"><![CDATA[XLNet是一种基于新型广义排列语言建模目标的新型无监督语言表示学习方法。 此外，XLNet采用Transformer-XL作为骨干模型，为涉及长时间环境的语言任务展示了出色的性能。 总体而言，XLNet在各种下游语言任务上实现了最先进的（SOTA）结果，包括问答，自然语言推理，情感分析和文档排名。 推荐阅读：XLNet论文 全文中译 2019 XLNet: Generalized Autoregressive Pretraining for Language Understanding With the capability of modeling bidirectional contexts, denoising autoencoding based pretraining like BERT achieves better performance than pretraining approaches based on autoregressive language modeling. However, relying on corrupting the input with masks, BERT neglects dependency between the masked positions and suffers from a pretrain-finetune discrepancy. In light of these pros and cons, we propose XLNet, a generalized autoregressive pretraining method that (1) enables learning bidirectional contexts by maximizing the expected likelihood over all permutations of the factorization order and (2) overcomes the limitations of BERT thanks to its autoregressive formulation. Furthermore, XLNet integrates ideas from Transformer-XL, the state-of-the-art autoregressive model, into pretraining. Empirically, XLNet outperforms BERT on 20 tasks, often by a large margin, and achieves state-of-the-art results on 18 tasks including question answering, natural language inference, sentiment analysis, and document ranking. 由于具有双向上下文建模的能力，像BERT这样基于自动去噪的预训练语言模型比基于自回归的预训练语言模型的性能更好。然而，依赖于使用带掩码损坏的输入，BERT忽略了掩码位置之间的依赖性，进而受到了预训练-微调不一致的影响。根据这些优点和缺点，我们提出了XLNet，一种广义自回归预训练方法，它（1）通过最大化输入序列的因式分解的所有排列的似然函数的期望来学习双向上下文，并且（2）由于其自回归方法，克服了BERT的局限性。此外，XLNet将最先进的自回归模型Transformer-XL的思想整合到预训练中。实验表明，XLNet在20个任务上常大幅度优于BERT的表现，并在18个任务中实现最先进的结果，包括问答、自然语言推理、情感分析和文档排名。 标题 说明 时间 XLNet: Generalized Autoregressive Pretraining for Language Understanding 原始论文 20190619 xlnet 官方实现 持续更新 他们创造了横扫NLP的XLNet：专访CMU博士杨植麟 原作者解读 20190802 拆解XLNet模型设计，回顾语言表征学习的思想演进 追一科技 Tony 20190629 XLNet:运行机制及和Bert的异同比较 张俊林，知乎专栏 20190622 从语言模型到Seq2Seq：Transformer如戏，全靠Mask 张俊林 解读 20190918 GitHub XLNet_Paper_Chinese_Translation XLNet 中文翻译 20191011 XLNet 的思考与做法 如上所示分别为自回归模型与自编码模型，其中黄色块为输入字符，蓝色块为字符的位置。对于自回归语言模型，它希望通过已知的前半句预测后面的词或字。对于自编码语言模型，它希望通过一句话预测被 Mask 掉的字或词，如上所示第 2 个位置的词希望通过第 1、3、5 个词进行预测。 我们需要更好的语言建模任务 以前，最常见的语言模型就是自回归式的了，它的计算效率比较高，且明确地建模了概率密度。但是自回归语言模型有一个缺陷，它只能编码单向语义，不论是从左到右还是从右到左都只是单向语义。这对于下游 NLP 任务来说是致命的，因此也就有了 BERT 那种自编码语言模型。 BERT 通过预测被 Mask 掉的字或词，从而学习到双向语义信息。但这种任务又带来了新问题，它只是建模了近似的概率密度，因为 BERT 假设要预测的词之间是相互独立的，即 Mask 之间相互不影响。此外，自编码语言模型在预训练过程中会使用 MASK 符号，但在下游 NLP 任务中并不会使用，因此这也会造成一定的误差。 为此，杨植麟表示我们需要一种更好的预训练语言任务，从而将上面两类模型的优点结合起来。XLNet 采用了一种新型语言建模任务，它通过随机排列自然语言而预测某个位置可能出现的词。如下图所示为排列语言模型的预测方式： 如上排列语言示例，因为随机排列是带有位置信息的，所以扰乱顺序并不影响建模效果。随机排列语言后，模型就开始依次预测不同位置的词。 如果我们知道所有词的内容及位置，那么是不是顺序地分解句子并不太重要。相反这种随机的分解顺序还能构建双向语义，因为如上利用「语言」和「喜欢」预测「处理」就利用了上下文的词。如下原论文展示了不同分解顺序预测同一词的差别，如果第一个分解的词的「3」，那么它就只能利用之前的隐藏状态 mem 进行预测。 这理解起来其实也非常直观，如果我们知道某些词及词的位置，那么完形填空式地猜某个位置可能出现哪些词也是没问题的。此外，我们可以发现，这种排列语言模型就是传统自回归语言模型的推广，它将自然语言的顺序拆解推广到随机拆解。当然这种随机拆解要保留每个词的原始位置信息，不然就和词袋模型没什么差别了。 我们需要更好的结构 前面我们为预训练语言模型构建了新的任务目标，这里就需要调整 Transformer 以适应任务。如果读者了解一些 Transformer，那么就会知道某个 Token 的内容和位置向量在输入到模型前就已经加在一起了，后续的隐向量同时具有内容和位置的信息。但杨植麟说：「新任务希望在预测下一个词时只能提供位置信息，不能提供内容相关的信息。因此模型希望同时做两件事，首先它希望预测自己到底是哪个字符，其次还要能预测后面的字符是哪个。」 这两件事是有冲突的，如果模型需要预测位置 2 的「喜欢」，那么肯定不能用该位置的内容向量。但与此同时，位置 2 的完整向量还需要参与位置 5 的预测，且同时不能使用位置 5 的内容向量。 这类似于条件句：如果模型预测当前词，则只能使用位置向量；如果模型预测后续的词，那么使用位置加内容向量。因此这就像我们既需要标准 Transformer 提供内容向量，又要另一个网络提供对应的位置向量。 针对这种特性，研究者提出了 Two-Stream Self-Attention，它通过构建两条路径解决这个条件句。如下所示为 Two-Stream 的结构，其中左上角的 a 为 Content 流，左下角的 b 为 Query 流，右边的 c 为排列语言模型的整体建模过程。注：这只是解决“内容-位置”冲突的其中一种方法。 在 Content 流中，它和标准的 Transformer 是一样的，第 1 个位置的隐藏向量 h_1 同时编码了内容与位置。在 Query 流中，第 1 个位置的隐向量 g_1 只编码了位置信息，但它同时还需要利用其它 Token 的内容隐向量 h_2、h_3 和 h_4，它们都通过 Content 流计算得出。因此，我们可以直观理解为，Query 流就是为了预测当前词，而 Content 流主要为 Query 流提供其它词的内容向量。 上图 c 展示了 XLNet 的完整计算过程，e 和 w 分别是初始化的词向量的 Query 向量。注意排列语言模型的分解顺序是 3、2、4、1，因此 Content 流的 Mask 第一行全都是红色、第二行中间两个是红色，这表明 h_1 需要用所有词信息、h_2 需要用第 2 和 3 个词的信息。此外，Query 流的对角线都是空的，表示它们不能使用自己的内容向量 h。]]></content>
      <categories>
        <category>论文</category>
        <category>语言模型</category>
      </categories>
      <tags>
        <tag>XLNet</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[XLNet Generalized Autoregressive Pretraining for Language Understanding 翻译]]></title>
    <url>%2F2019%2F07%2F03%2FXLNet_Generalized_Autoregressive_Pretraining_for_Language_Understanding%E7%BF%BB%E8%AF%91%2F</url>
    <content type="text"><![CDATA[本文是XLNet论文的全文翻译，转载注明出处和译者。 原文 XLNet: Generalized Autoregressive Pretraining for Language Understanding PDF版翻译以及相关资源链接 GitHub XLNet_Paper_Chinese_Translation 译者：袁宵 说明：1. 对于没有标准译法的词语保留了原单词；2. 以准确翻译为第一目标，力求保持原意；3. 欢迎读者参与到翻译中来，提出修改意见。 手机扫码阅读： 目前博客版没有正确渲染部分公式，建议看 PDF版翻译。 XLNet：用于语言理解的广义自回归预训练模型 摘要由于具有双向上下文建模的能力，像BERT这样基于自动去噪的预训练语言模型比基于自回归的预训练语言模型的性能更好。然而，依赖于使用带掩码（masks）损坏的输入，BERT忽略了掩码位置之间的依赖性，由此受到了预训练-微调阶段不一致的影响。针对这些优点和缺点，我们提出了XLNet，一种广义自回归预训练方法，它（1）通过最大化输入序列的因式分解的所有排列的似然函数的期望来学习双向上下文，并且（2）并且通过其自回归方法，克服了BERT的局限性。此外，XLNet将最先进的自回归模型Transformer-XL的思想整合到预训练中。实验表明，XLNet在20个任务上常大幅度优于BERT的表现，并在18个任务中实现最先进的结果，包括问答、自然语言推理、情感分析和文档排名（注1：预训练的模型和代码可在 https://github.com/zihangdai/xlnet 获得）。 1 介绍无监督表示学习在自然语言处理领域非常成功[7,19,24,25,10]。通常，这些方法首先在大规模的未标记文本语料库上预训练神经网络，然后在下游任务中微调模型或对模型输出的表示进行优化。在上述这种共同的指导思想下，文献中探索了不同的无监督预训练目标。其中，自回归autoregressive（AR）和自编码autoencoding（AE）语言模型是两个最成功的预训练目标。 AR语言模型试图用自回归模型估计文本语料库的概率分布[7,24,25]。具体而言，给定文本序列 $\textbf{x}=(x_1,…,x_T)$，AR语言模型将似然函数因式分解为一个向前的乘积 $p(\textbf{x})=\prod_{t=1}^Tp(x_t|\textbf{x}_{t})$ 。训练参数模型（例如，神经网络）来拟合每个条件概率分布。由于AR语言模型仅经过训练来编码单方向内容（向前或向后），因此无法有效建模深度双向上下文。然而，下游语言理解任务通常需要双向上下文信息。这导致AR语言建模与有效预训练之间存在差距。 相比之下，基于AE的预训练模型不执行显式密度估计，而是旨在从损坏的输入重建原始数据。一个值得注意的例子是BERT[10]，它是最先进的预训练方法。给定输入tokens序列，tokens的某一部分被特殊符号[MASK]替换，并且训练该模型来从损坏的版本输入序列中恢复原始tokens。由于密度估计不是训练目标的一部分，因此允许BERT利用双向上下文来重建原始输入。作为一个直接的好处，这将弥补前面提到的AR语言建模与有效预训练之间存在差距，从而提高了性能。 然而，在训练期间，BERT在预训练时使用的[MASK]等人造符号在实际数据中不存在，从而导致预训练-微调的不一致。 此外，由于预测的tokens在输入中被遮蔽，因此BERT不能像在AR语言模型中那样使用乘积规则来建模联合概率。换言之，BERT假设要预测的tokens在给定未遮蔽的tokens的条件下彼此独立，由于自然语言高度有序且长距离依赖广泛存在于自然语言中，因此该假设简化过度了[9]。 面对现有预训练语言模型目标的优缺点，在本工作中，我们提出了XLNet，这是一种广义的自回归方法，它充分利用了AR和AE语言模型的优点，同时避免了它们的局限性。 第一，不是像传统的AR模型那样使用固定的前向或后向序列因式分解顺序，XLNet最大化有关序列所有可能的因式分解的排列的对数似然函数的期望。由于排列操作，每个位置的上下文可以包括来自左侧和右侧的tokens。可以预计，每个位置都要学会利用来自所有位置的上下文信息，即捕获双向上下文。 第二，作为一种通用的AR语言模型，XLNet不依赖于数据损坏。因此，XLNet不会遭受BERT中存在的预训练-微调差异的影响。同时，自回归目标还提供了一种自然的方式来使用乘积规则来分解预测的tokens的联合概率，从而消除了在BERT中做出的独立性假设。 除了新的预训练目标外，XLNet还改进了预训练的模型结构设计。 受到AR语言模型的最新进展的启发，XLNet集成了分段循环机制（segmentrecurrence mechanism）和相关的Transformer-XL编码模式到预训练中，这在实验中改善了性能，特别是对于涉及较长文本序列的任务。 直接地将Transformer（-XL）结构应用于基于排列的语言模型不起作用，因为分解顺序是任意的并且目标是不明确的。为了解决这个问题，我们提出重新参数化Transformer（-XL）网络来消除歧义。 实验中，XLNet在18个任务上实现了最先进的结果，即7个GLUE语言理解任务，3个阅读理解任务，包括SQUAD和RACE，7个文本分类任务，包括Yelp和IMDB，以及ClueWeb09-B文档排名任务。在一系列公平的比较实验中，XLNet在多个基准测试中始终优于BERT[10]。 相关工作 在[32,11]中已经探讨了基于排列的AR建模的想法，但是存在几个关键的差异。以前的模型是无序的，而XLNet本质上在位置编码上顺序敏感的。 这对于语言理解很重要，因为无序模型退化为次袋模型，缺乏基本的表达能力。上述差异源于动机的根本不同——之前的模型旨在通过在模型中加入“无序”归纳偏置来改进密度估计，而XLNet的动机是让AR语言模型来学习双向上下文。 2 提出的方法2.1 背景在本节中，我们首先回顾并比较传统的AR语言模型和BERT语言模型的预训练过程。给定一个文本序列 $\textbf{x}=[x_1,…,x_T]$，AR语言模型通过最大化前向自回归因式分解的似然函数来进行预训练： 其中$h_{\theta}(\textbf{x}_{1:t-1})$是一个由神经模型产生的上下文表示，例如RNNs或者Transformers，$e(x)$表示$x$的嵌入。相比之下，BERT基于去噪自动编码（denoising auto-encodin）。具体地说，对于文本序列$\textbf{x}$，BERT首先通过将$\textbf{x}$中的一部分（例如15％）tokens随机设置为特殊符号[MASK]来构造损坏版本$\hat \textbf{x}$。用$\overline \textbf{x}$表示遮蔽的tokens。训练目标是从$\hat \textbf{x}$中重建$\overline \textbf{x}$： 其中$m_t=1$表示$x_t$被遮蔽了，$H_{\theta}$是一个Transformer，它把一个长度为$T$的文本序列映射为一个隐藏向量序列$H_{\theta}=[H_{\theta}(x)_1,H_{\theta}(x)_2,…,H_{\theta}(x)_T]$。两个预训练目标的优缺点在以下几个方面进行了比较： 独立性假设：正如公式（2）$\approx$ 符号后所强调的那样，BERT基于所有被遮蔽tokens $\overline \textbf{x}$的独立性假设单独重建每一个被遮蔽token，来对联合条件概率$p(\overline \textbf{x}|\hat \textbf{x})$进行因式分解。相比之下，AR语言模型目标（1）在没有这种独立性假设的情况下使用一般的乘积规则进行因式分解。 输入噪音：BERT的输入包含[MASK]等人造符号，这些符号从未出现在下游任务中，从而产生预训练-微调差异。在[10]中用原始tokens替换[MASK]的方法并不能解决问题，因为原始tokens只能以很小的概率使用——否则公式（2）将是微不足道的优化。相比之下，AR语言模型不依赖于任何输入损坏，也不会遇到此问题。 上下文依赖：AR表示$h_{\theta}(\textbf{x}_{1:t-1})$仅以到tokens $t$前一个位置为条件（即，左边的tokens），而BERT表示$H_\theta(\textbf{x})_t$可以访问两侧的上下文信息。 因此，BERT目标允许预训练模型以更好地捕获双向上下文。 2.2 目标：排列语言模型（Permutation Language Modeling） 图 1：给定同一个输入序列$\textbf{x}$但是不同的因式分解顺序的情况下，排序语言模型预测目标是$x_3$的图解。 根据上面的比较，AR语言模型和BERT都具有独特的优势。 一个自然要问的问题是，是否存在一个预训练目标，即在避免其两者弱点的同时具有两者的优势。 借鉴来自无序NADE [32]的思想，我们提出了排列语言模型的目标，它不仅保留了AR模型的优点，而且还允许模型捕获双向上下文。具体来说，对于长度为$T$的序列$\textbf{x}$，有$T!$种不同顺序去执行一个有效的自回归因式分解。直觉上，如果模型参数在所有因式分解顺序中共享，可以预计，模型将学会从双方向的所有位置收集信息。 为了形式化这个思想，用$Z_T$表示长度为$T$索引序列的所有可能排序的集合。我们使用$z_t$和$\textbf{z}_{&lt;t}$分别表示索引排序的第$t$个元素和前$t-1$个元素，$\textbf{z} \in Z_T$。然后，我们提出的排列语言模型目标函数可以表示如下： 本质上，对于文本序列$\textbf{x}$，我们对因式分解顺序$\textbf{z}$进行一次采样，并根据因式分解顺序分解似然函数$p_\theta(\textbf{x})$。 由于在训练期间在所有因子分解顺序中共享相同的模型参数$\theta$，可以预计，$x_t$已经看到序列中的每个可能元素$x_i \neq x_t$，因此能够捕获双向上下文。 此外，由于这个预训练目标满足AR框架，它自然地避免了2.1节中讨论的独立性假设以及预训练-微调不一致问题。 关于排列的备注 提出的预训练目标只会排列因式分解索引的顺序，而不会改变输入序列的顺序。换句话说，我们保持原始序列顺序，使用对应于原始序列的位置编码，并依赖Transformer中的适当注意掩码来实现因式分解索引顺序的排列。 请注意，此选择是必要的，因为模型在微调期间只会遇到具有自然顺序的文本序列。 为了提供一个完整的视角，在图1中，我们举了一个在给定同一个输入序列$\textbf{x}$但是不同的因式分解顺序情况下预测token $x_3$的例子。 2.3 结构：用于目标敏感表示（Target-Aware Representations）的双流自注意力（Two-Stream Self-Attention） 图2：（a）：内容流注意力（Content stream attention），这与标准的自注意力（self-attention）是一样的。（b）：查询流注意力（Query stream attention），它没有关于内容$x_{z_t}$的访问信息。（c）：具有双流注意的排序语言模型的训练概述。 虽然排序语言模型目标具有所需的属性，但使用标准的Transformer参数设定可能不起作用。看看问题所在，假设我们使用标准的Softmax公式参数化下一个token的分布$p_{\theta}(X_{z_t}|\textbf{x}_{\textbf{z}&lt;t})$，即，$p_{\theta}(X_{z_t}=x|\textbf{x}_{\textbf{z}&lt;t})=\dfrac{\exp(e(x)^Th_{\theta}(\textbf{x}_{\textbf{z}&lt;t})}{\sum_{x’}\exp(\exp(e(x’)^Th_{\theta}(\textbf{x}_{\textbf{z}&lt;t})}$，其中$h_{\theta}(\textbf{x}_{\textbf{z}&lt;t})$代表$\textbf{x}_{\textbf{z}&lt;t}$经过共享的Transformer神经网络在适当遮蔽后产生的隐藏表示。现在注意到隐藏表示$h_{\theta}(\textbf{x}_{\textbf{z}&lt;t})$与它将要预测的位置无关，也就是$z_t$的值。因此同样的分布用来预测而不管预测的位置，这将不能学到有用的表示（具体示例见附录A.1）。为了避免这个问题，我们提出重新参数化下一个token分布，以实现对目标位置敏感： 其中$g_{\theta}(x_{\textbf{z}&lt;t, z_t})$代表一种新类型的表示，它把目标位置$z_t$作为输入添加进去。 双流自注意力 虽然目标敏感表示的想法消除了目标预测中的模糊性，但是如何形式化$g_{\theta}(x_{\textbf{z}]]></content>
      <categories>
        <category>论文</category>
        <category>论文写作</category>
      </categories>
      <tags>
        <tag>XLNet</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[图像风格迁移]]></title>
    <url>%2F2019%2F07%2F01%2F%E5%9B%BE%E5%83%8F%E9%A3%8E%E6%A0%BC%E8%BF%81%E7%A7%BB%2F</url>
    <content type="text"><![CDATA[图像风格迁移的现实应用Prisma修图APPBuilding the future of photo and video editing.实验 Image-Captioning CNN-Encoder and RNN-Decoder (Bahdanau Attention) for image caption or image to text on MS-COCO dataset. Image_to_TextTaking the image description task on the MS-COCO data set as an example, the template code of Image_to_Text is shown. 图像风格转移 阅读资料 标题 内容 时间 图像风格迁移(Neural Style)简史 总结1960-2015图像风格迁移历史 20180104 寻找下一款Prisma APP：深度学习在图像处理中的应用探讨 主要内容包括：传统的图像处理：如超分辨、灰度图彩色化、2D/3D转换等；图像/视频风格化；图像生成。 20190526 图像风格迁移研究进展 more info see Neural-Style-Transfer-Papers 2015 Paper A Neural Algorithm of Artistic Style In fine art, especially painting, humans have mastered the skill to create unique visual experiences through composing a complex interplay between the content and style of an image. Thus far the algorithmic basis of this process is unknown and there exists no artificial system with similar capabilities. However, in other key areas of visual perception such as object and face recognition near-human performance was recently demonstrated by a class of biologically inspired vision models called Deep Neural Networks. Here we introduce an artificial system based on a Deep Neural Network that creates artistic images of high perceptual quality. The system uses neural representations to separate and recombine content and style of arbitrary images, providing a neural algorithm for the creation of artistic images. Moreover, in light of the striking similarities between performance-optimised artificial neural networks and biological vision, our work offers a path forward to an algorithmic understanding of how humans create and perceive artistic imagery. 在美术，尤其是绘画中，人类通过在图像的内容和风格之间构成复杂的相互作用，掌握了创造独特视觉体验的技能。到目前为止，该过程的算法基础是未知的，并且不存在具有类似能力的人工系统。然而，在视觉感知的其他关键领域，例如物体和人脸识别，近乎人类表现最近由一类被称为深度神经网络的生物学启发的视觉模型证明。在这里，我们介绍一个基于深度神经网络的人工系统，创建高感知质量的艺术图像。该系统使用神经表示来分离和重新组合任意图像的内容和风格，为艺术图像的创建提供神经算法。此外，鉴于性能优化的人工神经网络与生物视觉之间惊人的相似性，我们的工作为算法理解人类如何创造和感知艺术图像提供了一条前进的道路。 相关资源 标题 说明 一个艺术风格化的神经网络算法 论文中文翻译 Neural-Style-Transfer Keras Implementation of Neural Style Transfer from the paper “A Neural Algorithm of Artistic Style” (http://arxiv.org/abs/1508.06576) in Keras 2.0+ 2017 GitHub deep-photo-styletransferCode and data for paper Deep Photo Style Transfer This paper introduces a deep-learning approach to photographic style transfer that handles a large variety of image content while faithfully transferring the reference style. Our approach builds upon the recent work on painterly transfer that separates style from the content of an image by considering different layers of a neural network. However, as is, this approach is not suitable for photorealistic style transfer. Even when both the input and reference images are photographs, the output still exhibits distortions reminiscent of a painting. Our contribution is to constrain the transformation from the input to the output to be locally affine in colorspace, and to express this constraint as a custom fully differentiable energy term. We show that this approach successfully suppresses distortion and yields satisfying photorealistic style transfers in a broad variety of scenarios, including transfer of the time of day, weather, season, and artistic edits. 本文介绍了一种深度学习的摄影风格转换方法，可以处理各种图像内容，同时忠实地传递参考风格。 我们的方法建立在最近的绘画转移工作的基础上，通过考虑神经网络的不同层，将风格与图像内容分开。 但是，这种方法不适合照片般逼真的风格转换。 即使输入和参考图像都是照片，输出仍然会呈现出与绘画相似的扭曲。 我们的贡献是限制从输入到输出的转换在颜色空间中局部仿射，并将该约束表达为定制的完全可微分的能量项。 我们表明，这种方法成功地抑制了失真，并在各种场景中产生令人满意的逼真风格转换，包括时间，天气，季节和艺术编辑的转移。 ExamplesHere are some results from our algorithm (from left to right are input, style and our output): 2018 GitHub deep-painterly-harmonizationCode and data for paper Deep Painterly Harmonization Here are some results from our algorithm (from left to right are original painting, naive composite and our output): 2018 GitHub stroke-controllable-fast-style-transfercode for papaer Stroke Controllable Fast Style Transfer with Adaptive Receptive Fields hotograph to an artistic style in real-time. This task involves controlling the stroke size in the stylized results, which remains an open challenge. In this paper, we present a stroke controllable style transfer network that can achieve continuous and spatial stroke size control. By analyzing the factors that influence the stroke size, we propose to explicitly account for the receptive field and the style image scales. We propose a StrokePyramid module to endow the network with adaptive receptive fields, and two training strategies to achieve faster convergence and augment new stroke sizes upon a trained model respectively. By combining the proposed runtime control strategies, our network can achieve continuous changes in stroke sizes and produce distinct stroke sizes in different spatial regions within the same output image. 最近提出了快速风格转移方法以实时地将照片转换为艺术风格。 该任务涉及控制程式化结果中的笔划大小，这仍然是一个开放的挑战。 在本文中，我们提出了一种可以实现连续和空间行程尺寸控制的笔画可控式传送网络。 通过分析影响笔画大小的因素，我们建议明确考虑感受野和风格图像尺度。 我们提出了一个StrokePyramid模块，为网络赋予了自适应感受域，以及两种训练策略，分别在训练模型上实现更快的收敛和增加新的笔画大小。 通过组合所提出的运行时控制策略，我们的网络可以实现笔划大小的连续变化，并在同一输出图像内的不同空间区域中产生不同的笔划大小。 examplesFrom left to right are content, style, 256-stroke-size result, 512-stroke-size result, 768-stroke-size result.]]></content>
      <categories>
        <category>论文</category>
        <category>图像风格迁移</category>
      </categories>
      <tags>
        <tag>图像风格迁移</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Transformer 代码实现及应用]]></title>
    <url>%2F2019%2F06%2F29%2FTransformer%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%2F</url>
    <content type="text"><![CDATA[Transformer 代码实现及应用Transformer_implementation_and_application 该资源仅仅用300行代码（Tensorflow 2）完整复现了Transformer模型，并且应用在神经机器翻译任务和聊天机器人上。 Attention Is All You NeedAshish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Lukasz Kaiser, Illia Polosukhin(Submitted on 12 Jun 2017 (v1), last revised 6 Dec 2017 (this version, v5)) The dominant sequence transduction models are based on complex recurrent or convolutional neural networks in an encoder-decoder configuration. The best performing models also connect the encoder and decoder through an attention mechanism. We propose a new simple network architecture, the Transformer, based solely on attention mechanisms, dispensing with recurrence and convolutions entirely. Experiments on two machine translation tasks show these models to be superior in quality while being more parallelizable and requiring significantly less time to train. Our model achieves 28.4 BLEU on the WMT 2014 English-to-German translation task, improving over the existing best results, including ensembles by over 2 BLEU. On the WMT 2014 English-to-French translation task, our model establishes a new single-model state-of-the-art BLEU score of 41.8 after training for 3.5 days on eight GPUs, a small fraction of the training costs of the best models from the literature. We show that the Transformer generalizes well to other tasks by applying it successfully to English constituency parsing both with large and limited training data. Comments: 15 pages, 5 figuresSubjects: Computation and Language (cs.CL); Machine Learning (cs.LG)Cite as: arXiv:1706.03762 [cs.CL] (or arXiv:1706.03762v5 [cs.CL] for this version) Transformer 模型结构图 标题 说明 附加 Attention Is All You Need 原始论文 20170612 The Illustrated Transformer Transformer基础解读 代码实现列表 名字 说明 时间 transformer.ipynb Tensorflow官方实现 持续更新 bert_language_understanding Pre-training of Deep Bidirectional Transformers for Language Understanding: pre-train TextCNN 20181116 tensorflow/tensor2tensor/tensor2tensor/models/transformer.py tensor2tensor官方实现 持续更新 google-research/bert/modeling.py BERT官方实现，This is almost an exact implementation of the original Transformer encoder. In practice, the multi-headed attention are done with transposes and reshapes rather than actual separate tensors. 持续更新 Baidu transformer 百度实现，解析 持续更新]]></content>
      <categories>
        <category>深度学习</category>
        <category>Transformer</category>
      </categories>
      <tags>
        <tag>Attention</tag>
        <tag>Transformer</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[生成式对抗网络 Generative Adversarial Network (GAN)]]></title>
    <url>%2F2019%2F06%2F29%2F%E7%94%9F%E6%88%90%E5%BC%8F%E5%AF%B9%E6%8A%97%E7%BD%91%E7%BB%9C%2F</url>
    <content type="text"><![CDATA[生成式对抗网络基础知识生成式对抗网络定义生成式对抗网络（GAN, Generative Adversarial Networks ）是一种深度学习模型，是近年来复杂分布上无监督学习最具前景的方法之一。模型通过框架中（至少）两个模块：生成模型（Generative Model）和判别模型（Discriminative Model）的互相博弈学习产生相当好的输出。原始 GAN 理论中，并不要求 G 和 D 都是神经网络，只需要是能拟合相应生成和判别的函数即可。但实用中一般均使用深度神经网络作为 G 和 D 。一个优秀的GAN应用需要有良好的训练方法，否则可能由于神经网络模型的自由性而导致输出不理想。 相关阅读 换个角度看GAN：另一种损失函数 什么是生成对抗网络GAN?生成对抗网络GANs是当今计算机科学中最有趣的思想之一。 通过对抗过程同时训练两个模型。 生成器（“艺术家”）学会创造看起来真实的图像，而鉴别器（“艺术评论家”）学会区分由生成器生成的假的图片和真实存在的图片。 在训练期间，发生器逐渐变得更好地创建看起来真实的图像，而鉴别器变得更好地区分它们。 当鉴别器不能再将真实图像与假货区分开时，该过程达到平衡。 这个GitHUb 资源在MNIST数据集上演示了这个过程。 以下动画显示了生成器生成的一系列图像，因为它已经过50个历元的训练。 图像以随机噪声开始，随着时间的推移越来越像手写数字。 要了解有关GAN的更多信息，我们建议麻省理工学院的深度学习入门课程。 生成对抗网络的演进图谱 注释： 该图内容参考了《一文看懂GAN演进图谱》 如果你想先动手尝试一下使用GAN来生成图片，可以查看GitHub项目DeepNude-an-Image-to-Image-technology 支持本文研究 您对下面广告的每一次点击都是对本文研究的大力支持，谢谢！ 生成式对抗网络经典论文2014 GAN《Generative Adversarial Networks》Ian J. Goodfellow, Jean Pouget-Abadie, Mehdi Mirza, Bing Xu, David Warde-Farley, Sherjil Ozair, Aaron Courville, Yoshua Bengio We propose a new framework for estimating generative models via an adversarial process, in which we simultaneously train two models: a generative model G that captures the data distribution, and a discriminative model D that estimates the probability that a sample came from the training data rather than G. The training procedure for G is to maximize the probability of D making a mistake. This framework corresponds to a minimax two-player game. In the space of arbitrary functions G and D, a unique solution exists, with G recovering the training data distribution and D equal to 1/2 everywhere. In the case where G and D are defined by multilayer perceptrons, the entire system can be trained with backpropagation. There is no need for any Markov chains or unrolled approximate inference networks during either training or generation of samples. Experiments demonstrate the potential of the framework through qualitative and quantitative evaluation of the generated samples. Subjects: Machine Learning (stat.ML); Machine Learning (cs.LG)Cite as: arXiv:1406.2661 [stat.ML] (or arXiv:1406.2661v1 [stat.ML] for this version) GAN 极大极小博弈精髓 2016《NIPS 2016 Tutorial: Generative Adversarial Networks》Ian Goodfellow(Submitted on 31 Dec 2016 (v1), last revised 3 Apr 2017 (this version, v4)) This report summarizes the tutorial presented by the author at NIPS 2016 on generative adversarial networks (GANs). The tutorial describes: (1) Why generative modeling is a topic worth studying, (2) how generative models work, and how GANs compare to other generative models, (3) the details of how GANs work, (4) research frontiers in GANs, and (5) state-of-the-art image models that combine GANs with other methods. Finally, the tutorial contains three exercises for readers to complete, and the solutions to these exercises. Comments: v2-v4 are all typo fixes. No substantive changes relative to v1Subjects: Machine Learning (cs.LG)Cite as: arXiv:1701.00160 [cs.LG] (or arXiv:1701.00160v4 [cs.LG] for this version) 2016 ACGAN 《Conditional Image Synthesis With Auxiliary Classifier GANs》Conditional Image Synthesis With Auxiliary Classifier GANsAugustus Odena, Christopher Olah, Jonathon Shlens(Submitted on 30 Oct 2016 (v1), last revised 20 Jul 2017 (this version, v4)) Synthesizing high resolution photorealistic images has been a long-standing challenge in machine learning. In this paper we introduce new methods for the improved training of generative adversarial networks (GANs) for image synthesis. We construct a variant of GANs employing label conditioning that results in 128x128 resolution image samples exhibiting global coherence. We expand on previous work for image quality assessment to provide two new analyses for assessing the discriminability and diversity of samples from class-conditional image synthesis models. These analyses demonstrate that high resolution samples provide class information not present in low resolution samples. Across 1000 ImageNet classes, 128x128 samples are more than twice as discriminable as artificially resized 32x32 samples. In addition, 84.7% of the classes have samples exhibiting diversity comparable to real ImageNet data. 合成高分辨率照片级真实感图像一直是机器学习中的长期挑战。 在本文中，我们介绍了用于图像合成的改进生成对抗网络（GAN）训练的新方法。 我们构建了采用标签调节的GAN变体，其产生128x128分辨率的图像样本，表现出全局一致性。 我们扩展了以前的图像质量评估工作，为评估类条件图像合成模型中样本的可辨性和多样性提供了两个新的分析。 这些分析表明，高分辨率样品提供了低分辨率样品中不存在的类信息。 在1000个ImageNet类中，128x128样本的差异是人工调整大小的32x32样本的两倍多。 此外，84.7％的类别的样本具有与真实ImageNet数据相当的多样性。 Subjects: Machine Learning (stat.ML); Computer Vision and Pattern Recognition (cs.CV)Cite as: arXiv:1610.09585 [stat.ML] (or arXiv:1610.09585v4 [stat.ML] for this version) 2019 BigGAN 《LARGE SCALE GAN TRAINING FOR HIGH FIDELITY NATURAL IMAGE SYNTHESIS》 尽管近期由于生成图像建模的研究进展，从复杂数据集例如 ImageNet 中生成高分辨率、多样性的样本仍然是很大的挑战。为此，在这篇提交到 ICLR 2019 的论文中，研究者尝试在最大规模的数据集中训练生成对抗网络，并研究在这种规模的训练下的不稳定性。研究者发现应用垂直正则化（orthogonal regularization）到生成器可以使其服从简单的「截断技巧」（truncation trick），从而允许通过截断隐空间来精调样本保真度和多样性的权衡。这种修改方法可以让模型在类条件的图像合成中达到当前最佳性能。当在 128x128 分辨率的 ImageNet 上训练时，本文提出的模型—BigGAN—可以达到 166.3 的 Inception 分数（IS），以及 9.6 的 Frechet Inception 距离（FID），而之前的最佳 IS 和 FID 仅为 52.52 和 18.65。]]></content>
      <categories>
        <category>深度学习</category>
        <category>生成对抗网络</category>
      </categories>
      <tags>
        <tag>GAN</tag>
        <tag>生成式对抗网络</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[TensorFlow手册]]></title>
    <url>%2F2019%2F06%2F19%2FTensorFlow%E6%89%8B%E5%86%8C%2F</url>
    <content type="text"><![CDATA[TensorFlows手册 = TensorFlow 语言学习 + 张量的常用操作 + TensorFlow Hub使用 + TensorFlow Estimator使用 + Tensorflow Seq2Seq使用 TensorFlow 语言学习 标题 说明 TensorFlow 官方教程 TensorFlow 官方指南 TensorFlow 官方API TensorFlow-Examples TensorFlow Tutorial and Examples for Beginners Deep-Learning-with-TensorFlow-book 深度学习开源书，基于TensorFlow 2.0实战。http://www.ai101edu.com/ TensorFlow-2.x-Tutorials TF 2.0版入门实例代码，实战教程。 TensorFlow 张量的常用操作 点击TensorFlow张量的常用操作.ipynb深入学习 下面是该文件的主要内容。 数据类型：dtype=int32, float32, string, bool 创建张量：tf.convert_to_tensor, tf.constant, tf.zeros, tf.ones, tf.zeros_like, tf.fill, tf.random.normal, tf.random.uniform, tf.range 索引与切片：A[1][2][1], A[1, 2, 1], A[ :, :, 0:3:2], A[..., 0:3:2] 维度变换：tf.reshape, tf.expand_dims, tf.squeeze, tf.transpose 数据复制：tf.tile 数学运算：+, -, *, /, //, %, **, tf.pow, tf.square, tf.sqrt, tf.math.log, tf.matmul, @ 合并与分割：tf.concat, tf.stack, tf.split, tf.unstack 统计量：tf.norm, tf.reduce_max min mean sum, tf.argmax, tf.argmin 张量比较：tf.equal 填充与复制：tf.pad, tf.keras.preprocessing.sequence.pad_sequences, tf.tile 数据限幅：tf.maximum, tf.minimum, tf.clip_by_value 数据收集：tf.gather, tf.gather_nd 掩码：tf.boolean_mask 条件：tf.where 数据刷新：tf.scatter_nd 采样：tf.meshgrid TensorFlow Hub使用文章 Building a text classification model with TensorFlow Hub and Estimators | 代码 tfhub-text Code TensorFlow Estimator使用 标题 说明 附加 tf-estimator-tutorials Google Cloud Platform 官方教程 TensorFlow Estimator TensorFlow Estimator 源代码 tf_ner 使用tf.estimator和tf.data的简单高效的NER模型的Tensorflow实现 nlp_estimator_tutorial 关于使用TensorFlow Estimator框架进行文本分类的教育材料 My Code TensorFlow_iris_tfrecord_estimator This resource takes iris data set as an example to explain how to producte tfrecord files and use them in the customize Estimator! Tensorflow Seq2Seq使用Medium Park Chansung blog 基于TensorFlow框架的Seq2Seq英法机器翻译模型 代码 EN-FR-MLT-tensorflow 讲解 Seq2Seq model in TensorFlow 部分摘录 EN-FR-MLT-tensorflow/README.md/Build modelIn short, this section will show how to define the Seq2Seq model in TensorFlow. The below steps (implementation) will be covered. (1) define input parameters to the encoder model enc_dec_model_inputs (2) build encoder model encoding_layer (3) define input parameters to the decoder model enc_dec_model_inputs, process_decoder_input, decoding_layer (4) build decoder model for training decoding_layer_train (5) build decoder model for inference decoding_layer_infer (6) put (4) and (5) together decoding_layer (7) connect encoder and decoder models seq2seq_model (8) train and estimate loss and accuracy 知乎 天雨粟 的博客 与 Park Chansung 内容基本一致，不过使用中文进行讲解。 讲解 基于TensorFlow框架的Seq2Seq英法机器翻译模型 代码 machine_translation_seq2seq 我改写后的 代码]]></content>
      <categories>
        <category>Artificial Intelligence Navigation</category>
        <category>TensorFlow手册</category>
      </categories>
      <tags>
        <tag>深度学习框架</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[希尔伯特空间]]></title>
    <url>%2F2019%2F06%2F13%2F%E5%B8%8C%E5%B0%94%E4%BC%AF%E7%89%B9%E7%A9%BA%E9%97%B4%2F</url>
    <content type="text"><![CDATA[什么是赋范线性空间、内积空间，度量空间，希尔伯特空间 ？qang pan 的解释现代数学的一个特点就是以集合为研究对象，这样的好处就是可以将很多不同问题的本质抽象出来，变成同一个问题，当然这样的坏处就是描述起来比较抽象，很多人就难以理解了。既然是研究集合，每个人感兴趣的角度不同，研究的方向也就不同。为了能有效地研究集合，必须给集合赋予一些“结构”（从一些具体问题抽象出来的结构）。从数学的本质来看，最基本的集合有两类：线性空间（有线性结构的集合）、度量空间（有度量结构的集合）。对线性空间而言，主要研究集合的描述，直观地说就是如何清楚地告诉地别人这个集合是什么样子。为了描述清楚，就引入了基（相当于三维空间中的坐标系）的概念，所以对于一个线性空间来说，只要知道其基即可，集合中的元素只要知道其在给定基下的坐标即可。但线性空间中的元素没有“长度”（相当于三维空间中线段的长度），为了量化线性空间中的元素，所以又在线性空间引入特殊的“长度”，即范数。赋予了范数的线性空间即称为赋犯线性空间。但赋范线性空间中两个元素之间没有角度的概念，为了解决该问题，所以在线性空间中又引入了内积的概念。因为有度量，所以可以在度量空间、赋范线性空间以及内积空间中引入极限，但抽象空间中的极限与实数上的极限有一个很大的不同就是，极限点可能不在原来给定的集合中，所以又引入了完备的概念，完备的内积空间就称为Hilbert空间。这几个空间之间的关系是：线性空间与度量空间是两个不同的概念，没有交集。赋范线性空间就是赋予了范数的线性空间，也是度量空间（具有线性结构的度量空间）内积空间是赋范线性空间希尔伯特空间就是完备的内积空间。 TimXP 的解释我们一般接触的是线性空间（向量空间） ，首先看线性空间和各种空间之间的关系： Linear Space 线性空间（向量空间）。线性空间又称作向量空间，关注的是向量的位置，对于一个线性空间，知道基（相当于三维空间中的坐标系）便可确定空间中元素的坐标（即位置）；线性空间只定义了加法和数乘运算。如果我们想知道向量的长度怎么办？—-定义范数，引入赋范线性空间 Normed Linear Space 赋范线性空间定义了范数的线性空间！如果我们想知道向量的夹角怎么办？—-定义内积，引入内积空间 Inner Product Space 内积空间定义了内积的线性空间！ Euclid Space 欧式空间定义了内积的有限维实线性空间！！如果我们想研究收敛性（极限）怎么办？—-定义完备 Banach Space 巴纳赫空间，完备的赋范线性空间！ Hilbert Space 希尔伯特空间完备的内积空间！（极限运算中不能跑出度量的范围） 他们之间的关系可以用下图表示： 相关资料 说明 如何理解希尔伯特空间？ 知乎问答]]></content>
      <categories>
        <category>数学</category>
      </categories>
      <tags>
        <tag>希尔伯特空间</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[文本分类_谷歌机器学习指南]]></title>
    <url>%2F2019%2F06%2F11%2F%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB_%E8%B0%B7%E6%AD%8C%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E6%8C%87%E5%8D%97%2F</url>
    <content type="text"><![CDATA[介绍文本分类算法是大规模处理文本数据的各种软件系统的核心。 电子邮件软件使用文本分类来确定传入邮件是发送到收件箱还是过滤到垃圾邮件文件夹中。 讨论论坛使用文本分类来确定是否应将评论标记为不合适。这是主题分类的两个示例，将文本文档分类为预定义的一组主题。 在许多主题分类问题中，此分类主要基于文本中的关键字。 图 1: 主题分类用于标记传入的垃圾邮件，这些邮件被过滤到垃圾邮件文件夹中。 另一种常见的文本分类类型是情感分析，其目标是识别文本内容的极性：文本表达的意见类型。 这可以采取二进制喜欢/不喜欢评级的形式，或更精细的选项集，例如1到5的星级评级。情绪分析的示例包括分析Twitter帖子以确定人们是否喜欢黑豹电影，或者从沃尔玛评论中推断出公众对耐克新品牌鞋的看法。 本指南将教您一些解决文本分类问题的关键机器学习最佳实践。这是你将学到的东西： 使用机器学习解决文本分类问题的高级的、端到端的工作流程 如何为文本分类问题选择正确的模型 如何使用TensorFlow实现您的选择模型 文本分类工作流程以下是用于解决机器学习问题的工作流程的高度概述： Step 1: Gather Data Step 2: Explore Your Data Step 2.5: Choose a Model* Step 3: Prepare Your Data Step 4: Build, Train, and Evaluate Your Model Step 5: Tune Hyperparameters Step 6: Deploy Your Model 图2：解决机器学习问题的工作流程 “选择模型”不是传统机器学习工作流程的正式步骤;但是，为您的问题选择合适的模型是一项关键任务，可以明确并简化后续步骤中的工作。 以下部分详细介绍了每个步骤，以及如何为文本数据实现它们。 第1步：收集数据收集数据是解决任何监督机器学习问题的最重要步骤，您的文本分类器只能与构建它的数据集一样好。 如果您没有想要解决的特定问题并且只对一般的文本分类感兴趣，那么可以使用大量开源数据集。 您可以在我们的GitHub仓库中找到其中一些链接。 另一方面，如果您正在解决特定问题，则需要收集必要的数据。 许多组织提供用于访问其数据的公共API。例如，Twitter API或NY Times API。 您可以利用这些来解决您要解决的问题。 以下是收集数据时需要记住的一些重要事项： 如果您使用的是公共API，请在使用之前了解API的限制。 例如，某些API会对您进行查询的速率设置限制。 你拥有的训练样例（在本指南的其余部分称为样本）越多越好。 这将有助于您的模型更好地概括。 确保每个类或主题的样本数量不会过度失衡。 也就是说，每个类中应该有相当数量的样本。 确保您的样品充分覆盖可能的输入空间，而不仅仅是常见情况。 在本指南中，我们将使用Internet电影数据库（IMDb）电影评论数据集来说明工作流程。 该数据集包含人们在IMDb网站上发布的电影评论，以及指示评论者是否喜欢该电影的相应标签（“正面”或“否定”）。 这是情绪分析问题的典型例子。 第2步：探索您的数据构建和训练模型只是工作流程的一部分。事先了解数据的特征将使您能够构建更好的模型。这可能只是意味着获得更高的准确性。它还可能意味着需要更少的数据用于训练或更少的计算资源。 加载数据首先，让我们将数据集加载到Python中。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051def load_imdb_sentiment_analysis_dataset(data_path, seed=123): """Loads the IMDb movie reviews sentiment analysis dataset. # Arguments data_path: string, path to the data directory. seed: int, seed for randomizer. # Returns A tuple of training and validation data. Number of training samples: 25000 Number of test samples: 25000 Number of categories: 2 (0 - negative, 1 - positive) # References Mass et al., http://www.aclweb.org/anthology/P11-1015 Download and uncompress archive from: http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz """ imdb_data_path = os.path.join(data_path, 'aclImdb') # Load the training data train_texts = [] train_labels = [] for category in ['pos', 'neg']: train_path = os.path.join(imdb_data_path, 'train', category) for fname in sorted(os.listdir(train_path)): if fname.endswith('.txt'): with open(os.path.join(train_path, fname)) as f: train_texts.append(f.read()) train_labels.append(0 if category == 'neg' else 1) # Load the validation data. test_texts = [] test_labels = [] for category in ['pos', 'neg']: test_path = os.path.join(imdb_data_path, 'test', category) for fname in sorted(os.listdir(test_path)): if fname.endswith('.txt'): with open(os.path.join(test_path, fname)) as f: test_texts.append(f.read()) test_labels.append(0 if category == 'neg' else 1) # Shuffle the training data and labels. random.seed(seed) random.shuffle(train_texts) random.seed(seed) random.shuffle(train_labels) return ((train_texts, np.array(train_labels)), (test_texts, np.array(test_labels))) 检查数据加载数据后，最好对其进行一些检查：选择一些样本并手动检查它们是否符合您的预期。 例如，打印一些随机样本以查看情绪标签是否与评论的情绪相对应。以下是我们从IMDb数据集中随机选取的评论：“Ten minutes worth of story stretched out into the better part of two hours. When nothing of any significance had happened at the halfway point I should have left.”预期的情绪（负面）与样本的标签相匹配。 收集关键指标验证数据后，请收集以下有助于表征文本分类问题的重要指标： 样本数（Number of samples）：数据中的示例总数。 类别数量（Number of classes）：数据中的主题或类别总数。 每个类的样本数（Number of samples per class）：每个类的样本数（主题/类别）。 在平衡数据集中，所有类都将具有相似数量的样本; 在不平衡的数据集中，每个类中的样本数量会有很大差异。 每个样本的单词数（Number of words per sample）：样本中单词数量的中位数。 单词的频率分布（Frequency distribution of words）：显示数据集中每个单词的频率（出现次数）的分布。 样本长度分布（Distribution of sample length）：分布显示数据集中每个样本的单词数。 让我们看看这些指标的值对于IMDb评论数据集是什么（有关字频和样本长度分布的图，请参见图3和图4）。 Metric name Metric value Number of samples 25000 Number of classes 2 Number of samples per class 12500 Number of words per sample 174 表1：IMDb审查数据集指标 explore_data.py包含用于计算和分析这些指标的函数。以下是几个例子： 1234567891011121314151617181920212223242526import numpy as npimport matplotlib.pyplot as pltdef get_num_words_per_sample(sample_texts): """Returns the median number of words per sample given corpus. # Arguments sample_texts: list, sample texts. # Returns int, median number of words per sample. """ num_words = [len(s.split()) for s in sample_texts] return np.median(num_words)def plot_sample_length_distribution(sample_texts): """Plots the sample length distribution. # Arguments samples_texts: list, sample texts. """ plt.hist([len(s) for s in sample_texts], 50) plt.xlabel('Length of a sample') plt.ylabel('Number of samples') plt.title('Sample length distribution') plt.show() 图3：IMDb的词的频率分布 图4：IMDb的样本长度分布 步骤2.5：选择一个模型此时，我们已经汇总了数据集，并深入了解了数据的关键特征。接下来，根据我们在第2步中收集的指标，我们应该考虑应该使用哪种分类模型。这意味着/提出问题，例如“我们如何将文本数据呈现给期望数字输入的算法？”（这称为数据预处理和矢量化），“我们应该使用什么类型的模型？”，“什么配置参数我们应该使用我们的模型吗？”等。 经过数十年的研究，我们可以访问大量的数据预处理和模型配置选项。然而，可供选择的大量可行选项的可用性极大地增加了手头的特定问题的复杂性和范围。鉴于最佳选择可能并不明显，一个天真的解决方案是尽力尝试每一种可能的选择，通过直觉修剪一些选择。然而，这将是非常昂贵的。 在本指南中，我们尝试显着简化选择文本分类模型的过程。对于给定的数据集，我们的目标是找到实现接近最大精度的算法，同时最小化训练所需的计算时间。我们针对不同类型的问题（特别是情感分析和主题分类问题）运行了大量（~450K）实验，使用12个数据集，交替用于不同数据预处理技术和不同模型体系结构之间的每个数据集。这有助于我们识别影响最佳选择的数据集参数。 下面的模型选择算法和流程图是我们实验的总结。如果您还不理解其中使用的所有术语，请不要担心，本指南的以下部分将对其进行深入解释。 数据准备与模型构建算法 计算样本数量/每个样本的单词数的比率（the number of samples/number of words per sample）。 如果此比率小于1500，则将文本标记为n-gram并使用简单的多层感知器（MLP）模型对它们进行分类（下面的流程图中的左分支）：a. 将样本分成单词n-gram，将n-gram转换为向量。b. 评分向量的重要性，然后使用分数选择前20K。c. 建立MLP模型。 如果比率大于1500，则将文本标记为序列并使用sepCNN模型对它们进行分类（下面的流程图中的右分支）：a. 将样本分成单词，根据频率选择前20K词。b. 将样本转换为单词序列向量。c. 如果原始样本数/每个样本比率的单词数小于15K，则使用sepCNN模型的微调预训练嵌入可能会提供最佳结果。 使用不同的超参数值测量模型性能，以找到数据集的最佳模型配置。 图5：文本分类流程图 此流程图回答了两个关键问题： 我们应该使用哪种学习算法或模型？ 我们应该如何准备数据以有效地学习文本和标签之间的关系？ 第二个问题的答案取决于第一个问题的答案，我们预先处理数据的方式将取决于我们选择的模型。 模型可以大致分为两类：使用单词排序信息的那些（序列模型），以及仅将文本视为“bags”（sets）单词（n-gram模型）的模型。 序列模型的类型包括卷积神经网络（CNN），递归神经网络（RNN）及其变体。 n-gram模型的类型包括逻辑回归，简单的多层感知器（MLP或完全连接的神经网络），梯度增强树和支持向量机。 从我们的实验中，我们观察到“样本数”（S）与“每个样本的单词数”（W）的比率与哪个模型表现良好相关。 当该比率的值很小（小于1500）时，以n-gram为输入的小型多层感知器（我们称之为选项A）表现得更好或至少与序列模型一样好。 MLP很容易定义和理解，并且它们比序列模型花费更少的计算时间。当此比率的值很大（大于等于1500）时，使用序列模型（选项B）。 在接下来的步骤中，您可以根据样本/单词样本比率跳过所选模型类型的相关小节（标记为A或B）。 在我们的IMDb审查数据集的情况下，样本/每个样本的单词比率是~144。 这意味着我们将创建一个MLP模型。 使用上述流程图时，请注意，由于以下几个原因，它可能不一定会使您获得问题的最佳结果： 你的目标可能不同。 我们针对可在尽可能短的计算时间内实现的最佳准确率（accuracy）进行了优化。 替代流程可以产生更好的结果，例如，在优化曲线下面积（AUC）时。 我们选择了典型和常见的算法选择。 随着该领域的不断发展，新的前言算法和增强功能可能与您的数据相关，并且可能表现更好。 虽然我们使用多个数据集来推导和验证流程图，但您的数据集可能有一些特定的特征，这些特征有利于使用备用流程。 第3步：准备数据在将数据提供给模型之前，需要将其转换为模型可以理解的格式。 首先，我们收集的数据样本可能是特定的顺序。 我们不希望任何与样本排序相关的信息影响文本和标签之间的关系。 例如，如果数据集按类排序，然后分成训练/验证集，则这些集将不能代表整体数据分布。 确保模型不受数据顺序影响的简单最佳实践是在执行任何其他操作之前始终对数据进行混洗。 如果您的数据已经拆分为训练和验证集，请确保转换验证数据的方式与转换训练数据的方式相同。 如果您还没有单独的训练和验证集，您可以在洗牌后拆分样本; 通常使用80％的样本进行训练，20％进行验证。 其次，机器学习算法将数字作为输入。 这意味着我们需要将文本转换为数字向量。 此过程有两个步骤： 标记化（Tokenization，广义上的“分词”）：将文本分为单词或较小的子文本，这样可以很好地概括文本和标签之间的关系。 这决定了数据集的“词汇表”，一组唯一的令牌集（unique tokens，令牌集就是储存令牌token和数字之间映射的字典）。 矢量化：定义一个很好的数值度量来表征这些文本。 让我们看看如何对n-gram向量和序列向量执行这两个步骤，以及如何使用特征选择和归一化技术优化向量表示。 N-gram向量[选项A]在随后的段落中，我们将看到如何对n-gram模型进行标记化和矢量化。我们还将介绍如何使用特征选择和规范化技术优化n-gram表示。 在n-gram向量中，文本被表示为唯一n-gram的集合：n个相邻令牌的组（通常是单词）。 考虑一下文本“The mouse ran up the clock”。 在这里，单词unigrams（n = 1）是 [‘the’，’mouse’，’ran’，’up’，’clock’]，bigrams这个词（n = 2）是 [‘the mouse’, ‘mouse ran’, ‘ran up’, ‘up the’, ‘the clock’]，等等。 标记化 Tokenization我们发现，将单词unigrams + bigrams标记为提供良好的准确性，同时减少计算时间。 矢量化 Vectorization一旦我们将文本样本分成n-gram，我们需要将这些n-gram转换为我们的机器学习模型可以处理的数值向量。下面的示例显示了为两个文本生成的unigrams和bigrams分配的索引。 1234Texts: &apos;The mouse ran up the clock&apos; and &apos;The mouse ran down&apos;Index assigned for every token: &#123;&apos;the&apos;: 7, &apos;mouse&apos;: 2, &apos;ran&apos;: 4, &apos;up&apos;: 10, &apos;clock&apos;: 0, &apos;the mouse&apos;: 9, &apos;mouse ran&apos;: 3, &apos;ran up&apos;: 6, &apos;up the&apos;: 11, &apos;theclock&apos;: 8, &apos;down&apos;: 1, &apos;ran down&apos;: 5&#125; 将索引（indexes）分配给n-gram后，我们通常使用以下选项之一进行矢量化。 矢量化方法名称 说明 例子 One-hot encoding 每个示例文本都表示为一个向量，表示文本中是否存在令牌（token）。 ‘The mouse ran up the clock’ = [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1] Count encoding 每个示例文本都表示为一个向量，指示文本中令牌的计数。请注意，对应于unigrams (n = 1) ，’the’对应的元素现在表示为2，因为单词“the”在文本中出现两次。 ‘The mouse ran up the clock’ = [1, 0, 1, 1, 1, 0, 1, 2, 1, 1, 1, 1] tf-idf encoding 上述两种方法的问题在于，在所有文档中以相似频率出现的常用词（即，对数据集中的文本样本不是特别独特的词）不会受到惩罚。 例如，像“a”这样的单词将在所有文本中频繁出现。 因此，对于“the”而言，比其他更有意义的单词更高的令牌数量并不是非常有用。 ‘The mouse ran up the clock’ = [0.33, 0, 0.23, 0.23, 0.23, 0, 0.33, 0.47, 0.33, 0.23, 0.33, 0.33] (See Scikit-learn TdidfTransformer) 还有许多其他矢量表示，但以上三种是最常用的。 我们观察到tf-idf编码在准确性方面略优于其他两个（平均：高出0.25-15％），并建议使用此方法对n-gram进行矢量化。 但是，请记住它占用更多内存（因为它使用浮点表示）并且需要更多时间来计算，特别是对于大型数据集（在某些情况下可能需要两倍的时间）。 特征选择 Feature selection当我们将数据集中的所有文本转换为单词uni + bigram标记时，我们最终可能会有数万个标记。 并非所有这些令牌/特征都有助于标签预测。 因此我们可以删除某些令牌，例如在数据集中极少发生的令牌。 我们还可以度量特征重要性（每个标记对标签预测的贡献程度），并且仅包括信息量最大的标记。 有许多统计函数可以获取特征和相应的标签并输出特征重要性分数。 两个常用的函数是f_classif和chi2。 我们的实验表明，这两个功能同样表现良好。 更重要的是，我们发现许多数据集的精度达到了大约20,000个特征（见图6）。 在此阈值上添加更多特征的贡献非常小，有时甚至会导致过度拟合并降低性能。 图6：Top K 特征与准确率。在整个数据集中，精确度达到20K左右的特征。 标准化 Normalization标准化将所有要素/样本值转换为小值和类似值。 这简化了学习算法中的梯度下降收敛。 从我们所看到的情况来看，数据预处理期间的规范化似乎并没有在文本分类问题中增加太多价值，我们建议您跳过此步骤。 以下代码汇总了上述所有步骤： 将文本样本标记为单词uni + bigrams， 使用tf-idf编码进行矢量化， 通过丢弃出现少于2次的标记并使用f_classif计算特征重要性，仅从标记向量中选择前20,000个特征。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354from sklearn.feature_extraction.text import TfidfVectorizerfrom sklearn.feature_selection import SelectKBestfrom sklearn.feature_selection import f_classif# Vectorization parameters# Range (inclusive) of n-gram sizes for tokenizing text.NGRAM_RANGE = (1, 2)# Limit on the number of features. We use the top 20K features.TOP_K = 20000# Whether text should be split into word or character n-grams.# One of 'word', 'char'.TOKEN_MODE = 'word'# Minimum document/corpus frequency below which a token will be discarded.MIN_DOCUMENT_FREQUENCY = 2def ngram_vectorize(train_texts, train_labels, val_texts): """Vectorizes texts as n-gram vectors. 1 text = 1 tf-idf vector the length of vocabulary of unigrams + bigrams. # Arguments train_texts: list, training text strings. train_labels: np.ndarray, training labels. val_texts: list, validation text strings. # Returns x_train, x_val: vectorized training and validation texts """ # Create keyword arguments to pass to the 'tf-idf' vectorizer. kwargs = &#123; 'ngram_range': NGRAM_RANGE, # Use 1-grams + 2-grams. 'dtype': 'int32', 'strip_accents': 'unicode', 'decode_error': 'replace', 'analyzer': TOKEN_MODE, # Split text into word tokens. 'min_df': MIN_DOCUMENT_FREQUENCY, &#125; vectorizer = TfidfVectorizer(**kwargs) # Learn vocabulary from training texts and vectorize training texts. x_train = vectorizer.fit_transform(train_texts) # Vectorize validation texts. x_val = vectorizer.transform(val_texts) # Select top 'k' of the vectorized features. selector = SelectKBest(f_classif, k=min(TOP_K, x_train.shape[1])) selector.fit(x_train, train_labels) x_train = selector.transform(x_train).astype('float32') x_val = selector.transform(x_val).astype('float32') return x_train, x_val 使用n-gram向量表示，我们丢弃了大量关于单词顺序和语法的信息（当n&gt; 1时，我们可以保留一些部分排序信息）。 这被称为词袋方法。 该表示与不考虑排序的模型结合使用，例如逻辑回归，多层感知器，梯度增强机器，支持向量机。 序列向量 [选项B]在随后的段落中，我们将看到如何对序列模型进行标记化和矢量化。 我们还将介绍如何使用特征选择和标准化技术优化序列表示。 对于某些文本示例，单词顺序对于文本的含义至关重要。 例如，句子，“I used to hate my commute. My new bike changed that completely”只有在按顺序阅读时才能理解。 诸如CNN / RNN之类的模型可以从样本中的单词顺序推断出含义。 对于这些模型，我们将文本表示为一系列标记，保留顺序。 标记化 Tokenization文本可以表示为字符序列或单词序列。 我们发现使用单词级表示比字符标记提供更好的性能。 这也是工业界遵循的一般规范。 只有当文本有很多拼写错误时才使用字符标记，这通常不是这种情况。 矢量化 Vectorization一旦我们将文本样本转换为单词序列，我们需要将这些序列转换为数字向量。 下面的示例显示分配给为两个文本生成的unigrams的索引，然后显示转换第一个文本的令牌索引序列。 12345Texts: &apos;The mouse ran up the clock&apos; and &apos;The mouse ran down&apos;Index assigned for every token: &#123;&apos;clock&apos;: 5, &apos;ran&apos;: 3, &apos;up&apos;: 4, &apos;down&apos;: 6, &apos;the&apos;: 1, &apos;mouse&apos;: 2&#125;.NOTE: &apos;the&apos; occurs most frequently, so the index value of 1 is assigned to it.Some libraries reserve index 0 for unknown tokens, as is the case here.Sequence of token indexes: &apos;The mouse ran up the clock&apos; = [1, 2, 3, 4, 1, 5] 有两个选项可用于矢量化标记序列：One-hot encoding 在n维空间中使用单词向量表示序列，其中n =词汇量的大小。 当我们使用字符级标记化时，这种表示很有效，因为字符词汇量很小。 当我们将其标记为单词时，词汇表通常会有数万个标记，使得单热的向量非常稀疏且效率低下。 例： 12345678&apos;The mouse ran up the clock&apos; = [ [0, 1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0]] Word embeddings单词之间具有相关的含义。 因此，我们可以在密集的向量空间（〜几百个实数）中表示单词标记，其中单词之间的位置和距离表示它们在语义上有多相似（参见图7）。 这种表示称为单词嵌入（Word embeddings）。 图7：词嵌入 Word embeddings 序列模型通常具有这样的嵌入层作为它们的第一层。 该层学习在训练过程中将单词索引序列转换为单词嵌入向量，使得每个单词索引被映射到表示该单词在语义空间中的位置的实数值的密集向量（参见图8）。 图8：嵌入层 Embedding layer 特征选择并非我们数据中的所有单词都有助于标签预测。 我们可以通过从词汇表中丢弃罕见或不相关的单词来优化我们的学习过程。 事实上，我们观察到使用最常见的20,000个特征通常就足够了。 对于n-gram模型也是如此（参见图6）。 让我们将所有上述步骤放在序列矢量化中。 以下代码执行以下任务： 将文本标记为单词 使用前20,000个令牌创建词汇表 将标记转换为序列向量 将序列填充到固定的序列长度 12345678910111213141516171819202122232425262728293031323334353637383940414243from tensorflow.python.keras.preprocessing import sequencefrom tensorflow.python.keras.preprocessing import text# Vectorization parameters# Limit on the number of features. We use the top 20K features.TOP_K = 20000# Limit on the length of text sequences. Sequences longer than this# will be truncated.MAX_SEQUENCE_LENGTH = 500def sequence_vectorize(train_texts, val_texts): """Vectorizes texts as sequence vectors. 1 text = 1 sequence vector with fixed length. # Arguments train_texts: list, training text strings. val_texts: list, validation text strings. # Returns x_train, x_val, word_index: vectorized training and validation texts and word index dictionary. """ # Create vocabulary with training texts. tokenizer = text.Tokenizer(num_words=TOP_K) tokenizer.fit_on_texts(train_texts) # Vectorize training and validation texts. x_train = tokenizer.texts_to_sequences(train_texts) x_val = tokenizer.texts_to_sequences(val_texts) # Get max sequence length. max_length = len(max(x_train, key=len)) if max_length &gt; MAX_SEQUENCE_LENGTH: max_length = MAX_SEQUENCE_LENGTH # Fix sequence length to max value. Sequences shorter than the length are # padded in the beginning and sequences longer are truncated # at the beginning. x_train = sequence.pad_sequences(x_train, maxlen=max_length) x_val = sequence.pad_sequences(x_val, maxlen=max_length) return x_train, x_val, tokenizer.word_index 标签矢量化 Label vectorization我们看到了如何将示例文本数据转换为数字向量。必须对标签应用类似的过程。我们可以简单地将标签转换为范围[0，num_classes - 1]中的值。 例如，如果有3个类，我们可以使用值0,1和2来表示它们。 在内部，网络将使用one-hot来表示这些值（以避免推断标签之间的错误关系）。 这种表示取决于我们在神经网络中使用的损失函数和最后一层激活函数。 我们将在下一节中详细了解这些内容。 第4步：构建，训练和评估您的模型在本节中，我们将致力于构建，训练和评估我们的模型。在第3步中，我们选择使用n-gram模型或序列模型，使用我们的S/W比率。现在，是时候编写我们的分类算法并对其进行训练。我们将使用TensorFlow与tf.keras API进行此操作。 使用Keras构建机器学习模型就是将层，数据处理构建块组装在一起，就像我们组装乐高积木一样。 这些层允许我们指定我们想要对输入执行的转换序列。 由于我们的学习算法采用单个文本输入并输出单个分类，因此我们可以使用Sequential模型API创建线性图层堆栈。 图9：线性堆叠层 根据我们是在构建n-gram还是序列模型，输入层和中间层的构造将不同。但无论模型类型如何，最后一层对于给定问题都是相同的。 构建最后一层当我们只有2个类（二进制分类）时，我们的模型应输出单个概率分数。 例如，对于给定的输入样本输出0.2意味着“该样本在0级中的20％置信度，在类1中的80％。”为了输出这样的概率分数，最后一层的激活函数应该是 sigmoid函数，用于训练模型的损失函数应该是二元交叉熵（见图10，左）。 当有超过2个类（多类分类）时，我们的模型应该为每个类输出一个概率分数。 这些分数的总和应为1.例如，输出{0：0.2,1：0.7,2：0.1}意味着“该样本在0级中的20％置信度，在1级中的70％，以及10 为了输出这些分数，最后一层的激活函数应该是softmax，用于训练模型的损失函数应该是分类交叉熵。 （见图10，右）。 图10：最后一层 下面的代码定义了一个函数，它将类的数量作为输入，并输出适当数量的层单元（1个单元用于二进制分类;否则每个类1个单元）和相应的激活函数： 12345678910111213141516def _get_last_layer_units_and_activation(num_classes): """Gets the # units and activation function for the last network layer. # Arguments num_classes: int, number of classes. # Returns units, activation values. """ if num_classes == 2: activation = 'sigmoid' units = 1 else: activation = 'softmax' units = num_classes return units, activation 以下两节介绍了n-gram模型和序列模型的剩余模型层的创建。 当S / W比率很小时，我们发现n-gram模型比序列模型表现更好。当存在大量小的密集向量时，序列模型更好。 这是因为在密集空间中学习嵌入关系，这在许多样本中都是最好的。 构建n-gram模型[选项A]我们将独立处理令牌（不考虑词序）的模型称为n-gram模型。 简单的多层感知器（包括逻辑回归），梯度增强机器和支持向量机模型都属于这一类; 他们无法利用任何有关文本排序的信息。 我们比较了上面提到的一些n-gram模型的性能，并观察到多层感知器（MLP）通常比其他选项表现更好。MLP易于定义和理解，提供良好的准确性，并且需要相对较少的计算。 以下代码定义了tf.keras中的两层MLP模型，添加了几个Dropout层用于正则化（以防止过度拟合训练样本）。 123456789101112131415161718192021222324252627from tensorflow.python.keras import modelsfrom tensorflow.python.keras.layers import Densefrom tensorflow.python.keras.layers import Dropoutdef mlp_model(layers, units, dropout_rate, input_shape, num_classes): """Creates an instance of a multi-layer perceptron model. # Arguments layers: int, number of `Dense` layers in the model. units: int, output dimension of the layers. dropout_rate: float, percentage of input to drop at Dropout layers. input_shape: tuple, shape of input to the model. num_classes: int, number of output classes. # Returns An MLP model instance. """ op_units, op_activation = _get_last_layer_units_and_activation(num_classes) model = models.Sequential() model.add(Dropout(rate=dropout_rate, input_shape=input_shape)) for _ in range(layers-1): model.add(Dense(units=units, activation='relu')) model.add(Dropout(rate=dropout_rate)) model.add(Dense(units=op_units, activation=op_activation)) return model 构建序列模型[选项B]我们将可以从令牌相邻关系中学习的模型称为序列模型。这包括CNN和RNN类型的模型。数据被预处理为这些模型的序列向量。 序列模型通常具有大量要学习的参数。这些模型中的第一层是嵌入层，它可以学习密集向量空间中单词之间的关系。学习单词关系最适合许多样本。 给定数据集中的单词很可能不是该数据集唯一的。因此，我们可以使用其他数据集来学习数据集中的单词之间的关系。为此，我们可以将从另一个数据集中学习的嵌入转移到我们的嵌入层中。这些嵌入被称为预训练嵌入。使用预先训练的嵌入使模型在学习过程中处于领先地位。 有预先训练好的嵌入可以使用大型语料库训练，例如GloVe。 GloVe已经在多个语料库（主要是维基百科）上接受过训练。我们使用GloVe嵌入版本测试了我们的序列模型的训练，并观察到如果我们冻结预训练嵌入的权重并仅训练网络的其余部分，则模型表现不佳。这可能是因为嵌入层被训练的上下文可能与我们使用它的上下文不同。 在维基百科数据上训练的GloVe嵌入可能与我们的IMDb数据集中的语言模式不一致。 推断的关系可能需要一些更新 - 即，嵌入权重可能需要上下文调整。 我们分两个阶段完成： 微调嵌入。在第一次运行中，嵌入层权重被冻结，我们允许网络的其余部分学习。 在此运行结束时，模型权重达到比未初始化值更好的状态。 对于第二次运行，我们允许嵌入层也学习，对网络中的所有权重进行微调。 我们将此过程称为使用微调嵌入。 从新学习嵌入。微调嵌入可以提高精度。 然而，这是以增加训练网络所需的计算能力为代价的。 给定足够数量的样本，我们也可以从头开始学习嵌入。 我们观察到，对于S / W&gt; 15K，从头开始有效地产生与使用微调嵌入相同的精度。 我们比较了不同的序列模型，如CNN，sepCNN（深度可分离卷积网络），RNN（LSTM和GRU），CNN-RNN和堆叠RNN，改变了模型架构。 我们发现sepCNNs是一种卷积网络变体，通常更具数据效率和计算效率，其性能优于其他模型。 RNN仅与一小部分用例相关。我们没有尝试使用具有注意力的QRNN或RNN等模型，因为它们的准确性改进将被更高的计算成本所抵消。 以下代码构造了一个四层sepCNN模型： 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990from tensorflow.python.keras import modelsfrom tensorflow.python.keras import initializersfrom tensorflow.python.keras import regularizersfrom tensorflow.python.keras.layers import Densefrom tensorflow.python.keras.layers import Dropoutfrom tensorflow.python.keras.layers import Embeddingfrom tensorflow.python.keras.layers import SeparableConv1Dfrom tensorflow.python.keras.layers import MaxPooling1Dfrom tensorflow.python.keras.layers import GlobalAveragePooling1Ddef sepcnn_model(blocks, filters, kernel_size, embedding_dim, dropout_rate, pool_size, input_shape, num_classes, num_features, use_pretrained_embedding=False, is_embedding_trainable=False, embedding_matrix=None): """Creates an instance of a separable CNN model. # Arguments blocks: int, number of pairs of sepCNN and pooling blocks in the model. filters: int, output dimension of the layers. kernel_size: int, length of the convolution window. embedding_dim: int, dimension of the embedding vectors. dropout_rate: float, percentage of input to drop at Dropout layers. pool_size: int, factor by which to downscale input at MaxPooling layer. input_shape: tuple, shape of input to the model. num_classes: int, number of output classes. num_features: int, number of words (embedding input dimension). use_pretrained_embedding: bool, true if pre-trained embedding is on. is_embedding_trainable: bool, true if embedding layer is trainable. embedding_matrix: dict, dictionary with embedding coefficients. # Returns A sepCNN model instance. """ op_units, op_activation = _get_last_layer_units_and_activation(num_classes) model = models.Sequential() # Add embedding layer. If pre-trained embedding is used add weights to the # embeddings layer and set trainable to input is_embedding_trainable flag. if use_pretrained_embedding: model.add(Embedding(input_dim=num_features, output_dim=embedding_dim, input_length=input_shape[0], weights=[embedding_matrix], trainable=is_embedding_trainable)) else: model.add(Embedding(input_dim=num_features, output_dim=embedding_dim, input_length=input_shape[0])) for _ in range(blocks-1): model.add(Dropout(rate=dropout_rate)) model.add(SeparableConv1D(filters=filters, kernel_size=kernel_size, activation='relu', bias_initializer='random_uniform', depthwise_initializer='random_uniform', padding='same')) model.add(SeparableConv1D(filters=filters, kernel_size=kernel_size, activation='relu', bias_initializer='random_uniform', depthwise_initializer='random_uniform', padding='same')) model.add(MaxPooling1D(pool_size=pool_size)) model.add(SeparableConv1D(filters=filters * 2, kernel_size=kernel_size, activation='relu', bias_initializer='random_uniform', depthwise_initializer='random_uniform', padding='same')) model.add(SeparableConv1D(filters=filters * 2, kernel_size=kernel_size, activation='relu', bias_initializer='random_uniform', depthwise_initializer='random_uniform', padding='same')) model.add(GlobalAveragePooling1D()) model.add(Dropout(rate=dropout_rate)) model.add(Dense(op_units, activation=op_activation)) return model 训练你的模型现在我们已经构建了模型架构，我们需要训练模型。训练涉及基于模型的当前状态进行预测，计算预测的不正确程度，以及更新网络的权重或参数以最小化该误差并使模型更好地预测。我们重复这个过程，直到我们的模型融合并且无法再学习。该过程有三个关键参数（见表2）。 度量标准 Metric：如何使用度量标准衡量模型的性能。我们在实验中使用精度作为度量标准。 损失函数 Loss function：用于计算损失值的函数，训练过程然后通过调整网络权重来尝试最小化该损失值。对于分类问题，交叉熵损失效果很好。 优化器 Optimizer：一种函数，用于根据损失函数的输出决定如何更新网络权重。我们在实验中使用了流行的Adam优化器。 在Keras中，我们可以使用compile方法将这些学习参数传递给模型。 Learning parameter Value Metric accuracy Loss function - binary classification binary_crossentropy Loss function - multi class classification sparse_categorical_crossentropy Optimizer adam 表2：学习参数 使用fit方法进行实际训练。 根据数据集的大小，这是大多数计算周期将花费的方法。 在每次训练迭代中，使用来自训练数据的batch_size样本数来计算损失，并根据此值更新权重一次。 一旦模型看到整个训练数据集，训练过程就完成了一个时代。 在每个时代结束时，我们使用验证数据集来评估模型的学习效果。 我们使用数据集重复训练预定数量的时期。 我们可以通过提前停止来优化这一点，当验证准确度在连续的时期之间稳定时，表明模型不再训练。 Training hyperparameter Value Learning rate 1e-3 Epochs 1000 Batch size 512 Early stopping parameter: val_loss, patience: 1 表3：训练超参数 以下Keras代码使用上面表2和表3中选择的参数实现了训练过程： 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677def train_ngram_model(data, learning_rate=1e-3, epochs=1000, batch_size=128, layers=2, units=64, dropout_rate=0.2): """Trains n-gram model on the given dataset. # Arguments data: tuples of training and test texts and labels. learning_rate: float, learning rate for training model. epochs: int, number of epochs. batch_size: int, number of samples per batch. layers: int, number of `Dense` layers in the model. units: int, output dimension of Dense layers in the model. dropout_rate: float: percentage of input to drop at Dropout layers. # Raises ValueError: If validation data has label values which were not seen in the training data. """ # Get the data. (train_texts, train_labels), (val_texts, val_labels) = data # Verify that validation labels are in the same range as training labels. num_classes = explore_data.get_num_classes(train_labels) unexpected_labels = [v for v in val_labels if v not in range(num_classes)] if len(unexpected_labels): raise ValueError('Unexpected label values found in the validation set:' ' &#123;unexpected_labels&#125;. Please make sure that the ' 'labels in the validation set are in the same range ' 'as training labels.'.format( unexpected_labels=unexpected_labels)) # Vectorize texts. x_train, x_val = vectorize_data.ngram_vectorize( train_texts, train_labels, val_texts) # Create model instance. model = build_model.mlp_model(layers=layers, units=units, dropout_rate=dropout_rate, input_shape=x_train.shape[1:], num_classes=num_classes) # Compile model with learning parameters. if num_classes == 2: loss = 'binary_crossentropy' else: loss = 'sparse_categorical_crossentropy' optimizer = tf.keras.optimizers.Adam(lr=learning_rate) model.compile(optimizer=optimizer, loss=loss, metrics=['acc']) # Create callback for early stopping on validation loss. If the loss does # not decrease in two consecutive tries, stop training. callbacks = [tf.keras.callbacks.EarlyStopping( monitor='val_loss', patience=2)] # Train and validate model. history = model.fit( x_train, train_labels, epochs=epochs, callbacks=callbacks, validation_data=(x_val, val_labels), verbose=2, # Logs once per epoch. batch_size=batch_size) # Print results. history = history.history print('Validation accuracy: &#123;acc&#125;, loss: &#123;loss&#125;'.format( acc=history['val_acc'][-1], loss=history['val_loss'][-1])) # Save model. model.save('IMDb_mlp_model.h5') return history['val_acc'][-1], history['val_loss'][-1] 第5步：调整超参数我们必须选择一些超参数来定义和训练模型。我们依靠直觉，例子和最佳实践建议。但是，我们首选的超参数值可能无法产生最佳结果。它只为我们提供了良好的训练起点。每个问题都是不同的，调整这些超参数将有助于改进我们的模型，以更好地代表手头问题的特殊性。让我们来看看我们使用的一些超参数以及调整它们的含义： 模型中的层数 Number of layers in the model：神经网络中的层数是其复杂性的指标。我们在选择这个值时一定要小心。太多的图层将允许模型学习太多关于训练数据的信息，从而导致过度拟合。太少的图层会限制模型的学习能力，导致不合适。对于文本分类数据集，我们使用一层，两层和三层MLP进行了实验。具有两层的模型表现良好，并且在一些情况下优于三层模型。同样，我们尝试了四层和六层的sepCNNs，四层模型表现良好。 每层的单位数 Number of units per layer：图层中的单位必须包含图层执行的变换的信息。对于第一层，这是由功能的数量驱动的。在后续层中，单元的数量取决于从前一层扩展或收缩表示的选择。尽量减少图层之间的信息丢失。我们尝试了[8,16,32,64]范围内的单位值，并且32/64单位运行良好。 丢失率 Dropout rate：模型中使用辍学层进行正则化。它们定义要丢弃的输入分数作为过度拟合的预防措施。推荐范围：0.2-0.5。 学习率 Learning rate：这是神经网络权重在迭代之间变化的速率。较大的学习率可能会导致权重大幅波动，我们可能永远找不到最佳值。低学习率是好的，但该模型将需要更多迭代才能收敛。从1e-4开始，从低位开始是一个好主意。如果训练非常缓慢，请增加此值。如果您的模型没有学习，请尝试降低学习率。 我们调整了几个特定于我们的sepCNN模型的额外超参数： 卷积核大小 Kernel size：卷积窗口的大小。 推荐值：3或5。 嵌入维度 Embedding dimensions：我们想要用来表示字嵌入的维数，即每个单词向量的大小。 推荐值：50-300。 在我们的实验中，我们使用了具有200维度的GloVe嵌入和预先训练的嵌入层。 尝试这些超参数，看看什么效果最好。 一旦为您的用例选择了性能最佳的超参数，您的模型就可以部署了。 第6步：部署模型您可以在Google Cloud上训练，调整和部署机器学习模型。 有关将模型部署到生产的指导，请参阅以下资源： 有关如何使用TensorFlow服务部署Keras模型的教程。 TensorFlow服务文档。 在Google Cloud上训练和部署模型的指南。 部署模型时请记住以下关键事项： 确保您的生产数据遵循与训练和评估数据相同的分布。 通过收集更多训练数据定期重新评估。 如果您的数据分布发生变化，请重新训练模型。 结论文本分类是各种产品中应用程序的基本机器学习问题。在本指南中，我们将文本分类工作流分解为几个步骤。 对于每个步骤，我们都根据您的特定数据集的特征建议了一种自定义方法。特别是，使用样本数与每个样本的单词数的比率，我们建议一种模型类型，使您更快地接近最佳性能。其他步骤围绕这个选择而设计。我们希望遵循指南，随附的代码和流程图将帮助您学习，理解并快速获得有关文本分类问题的首要解决方案。 附录：批量训练非常大的数据集可能不适合分配给您的进程的内存。 在前面的步骤中，我们设置了一个管道，我们将整个数据集引入内存，准备数据，并将工作集传递给训练函数。 相反，Keras提供了另一种训练函数（fit_generator），可以批量提取数据。 这允许我们将数据管道中的转换仅应用于数据的一小部分（batch_size的一部分）。 在我们的实验中，我们使用批处理（GitHub中的代码）来处理数据集，例如DBPedia，Amazon评论，Ag新闻和Yelp评论。 以下代码说明了如何生成数据批并将其提供给fit_generator。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253def _data_generator(x, y, num_features, batch_size): """Generates batches of vectorized texts for training/validation. # Arguments x: np.matrix, feature matrix. y: np.ndarray, labels. num_features: int, number of features. batch_size: int, number of samples per batch. # Returns Yields feature and label data in batches. """ num_samples = x.shape[0] num_batches = num_samples // batch_size if num_samples % batch_size: num_batches += 1 while 1: for i in range(num_batches): start_idx = i * batch_size end_idx = (i + 1) * batch_size if end_idx &gt; num_samples: end_idx = num_samples x_batch = x[start_idx:end_idx] y_batch = y[start_idx:end_idx] yield x_batch, y_batch# Create training and validation generators.training_generator = _data_generator( x_train, train_labels, num_features, batch_size)validation_generator = _data_generator( x_val, val_labels, num_features, batch_size)# Get number of training steps. This indicated the number of steps it takes# to cover all samples in one epoch.steps_per_epoch = x_train.shape[0] // batch_sizeif x_train.shape[0] % batch_size: steps_per_epoch += 1# Get number of validation steps.validation_steps = x_val.shape[0] // batch_sizeif x_val.shape[0] % batch_size: validation_steps += 1# Train and validate model.history = model.fit_generator( generator=training_generator, steps_per_epoch=steps_per_epoch, validation_data=validation_generator, validation_steps=validation_steps, callbacks=callbacks, epochs=epochs, verbose=2) # Logs once per epoch. 相关内容 对应的代码 https://github.com/yuanxiaosc/Hands-on-deep-learning 英文版本指南 Google machine-learning 进一步学习文本分类的方法 标题 内容 时间 达观数据曾彦能：如何用深度学习做好长文本分类与法律文书智能化处理 文本分类领域走过路过不可错过的深度学习模型主要有FastText，TextCNN，HAN，DPCNN。本文试图在实践之后总结一下这些这些分类模型的理论框架，把这些模型相互联系起来，让大家在选择模型与调参的时候能有一些直觉与灵感。 20190901]]></content>
      <categories>
        <category>机器学习</category>
        <category>文本分类</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[Multi-Task Deep Neural Networks (MT-DNN)]]></title>
    <url>%2F2019%2F06%2F10%2FMulti-Task_Deep_Neural_Networks%2F</url>
    <content type="text"><![CDATA[本文介绍提出以及改进 Multi-Task Deep Neural Networks (MT-DNN) 的两篇论文 Multi-Task Deep Neural Networks for Natural Language Understanding 和 Improving Multi-Task Deep Neural Networks via Knowledge Distillation for Natural Language Understanding。第一篇论文提出了多任务模型MT-DNN，该模型是基于Transformer Encoder 的BERT模型，该模型将多任务学习和语言模型预训练结合起来，用于语言表达学习。第二篇论文使用知识蒸馏技术对MT-NDD模型进行了改进。 多任务学习 Multi-Task Learning (MTL) 不仅利用了大量的跨任务数据，而且还受益于正则化效应，这种效应导致更一般的表示，以适应新的任务和域。尽管集成学习可以提高模型性能，但是使用诸如MT-DNN的大型DNN的集合来工作可能非常昂贵。所以使用知识蒸馏技术确保模型效果的同时（单模型效果与集成模型效果相当）减小模型大小（参数量）。 Multi-Task Deep Neural Networks for Natural Language UnderstandingAbstract In this paper, we present a Multi-Task Deep Neural Network (MT-DNN) for learning representations across multiple natural language understanding (NLU) tasks. MT-DNN not only leverages large amounts of cross-task data, but also benefits from a regularization effect that leads to more general representations in order to adapt to new tasks and domains. MT-DNN extends the model proposed in Liu et al. (2015) by incorporating a pre-trained bidirectional transformer language model, known as BERT (Devlin et al., 2018). MT-DNN obtains new state-of-the-art results on ten NLU tasks, including SNLI, SciTail, and eight out of nine GLUE tasks, pushing the GLUE benchmark to 82.7% (2.2% absolute improvement). We also demonstrate using the SNLI and SciTail datasets that the representations learned by MT-DNN allow domain adaptation with substantially fewer in-domain labels than the pre-trained BERT representations. The code and pre-trained models are publicly available at this https URL. 摘要在本文中，我们提出了一个多任务深度神经网络（MT-DNN），用于跨多种自然语言理解（NLU）任务的学习表示。 MT-DNN不仅利用了大量的跨任务数据，而且还利用正则化效应带来的好处，从而产生更一般的表示，以帮助适应新的任务和领域。 MT-DNN扩展了Liu等人（2015）提出通过结合预先训练的双向Transformer语言模型，称为BERT（Devlin等，2018）。 MT-DNN在10个NLU任务中获得了最新的结果，包括SNLI，SciTail和9个GLUE任务中的8个，将GLUE基准推至82.7％（绝对改进2.2％）。我们还展示了在SNLI和SciTail数据集上，MT-DNN学习的表示允许域自适应，其域内标签比预训练的BERT表示少得多。代码和预先训练的模型可在https://github.com/namisan/mt-dnn上公开获取。 MT-DNN模型MT-DNN模型的训练算法 Improving Multi-Task Deep Neural Networks via Knowledge Distillation for Natural Language UnderstandingAbstract This paper explores the use of knowledge distillation to improve a Multi-Task Deep Neural Network (MT-DNN) (Liu et al., 2019) for learning text representations across multiple natural language understanding tasks. Although ensemble learning can improve model performance, serving an ensemble of large DNNs such as MT-DNN can be prohibitively expensive. Here we apply the knowledge distillation method (Hinton et al., 2015) in the multi-task learning setting. For each task, we train an ensemble of different MT-DNNs (teacher) that outperforms any single model, and then train a single MT-DNN (student) via multi-task learning to distill knowledge from these ensemble teachers. We show that the distilled MT-DNN significantly outperforms the original MT-DNN on 7 out of 9 GLUE tasks, pushing the GLUE benchmark (single model) to 83.7\% (1.5\% absolute improvement\footnote{ Based on the GLUE leaderboard at this https URL as of April 1, 2019.}). The code and pre-trained models will be made publicly available at this https URL. 摘要本文探讨了利用知识蒸馏改进多任务深度神经网络（MT-DNN）（Liu et al。，2019）来学习跨多种自然语言理解任务的文本表示。尽管集成学习可以提高模型性能，但是服务于诸如MT-DNN的大型DNN的集合可能非常昂贵。在这里，我们将知识蒸馏方法（Hinton等，2015）应用于多任务学习环境中。对于每项任务，我们培训不同MT-DNN（教师）的集合，其优于任何单一模型，然后通过多任务学习训练单个MT-DNN（学生）以从这些集合教师中提取知识。我们表明，蒸馏的MT-DNN在9个GLUE任务中的7个中明显优于原始MT-DNN，将GLUE基准（单个模型）推至83.7％（1.5％绝对改进\脚注{基于GLUE排行榜这个https网址截至2019年4月1日。}）。代码和预先训练的模型将在此https URL https://github.com/namisan/mt-dnn 公开发布。 MT-DNN模型的训练算法 MT-DNN知识蒸馏过程]]></content>
      <categories>
        <category>论文</category>
        <category>语言模型</category>
      </categories>
      <tags>
        <tag>MT-DNN</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[对抗训练（Adversarial Training）]]></title>
    <url>%2F2019%2F06%2F05%2F%E5%AF%B9%E6%8A%97%E8%AE%AD%E7%BB%83%2F</url>
    <content type="text"><![CDATA[对抗训练基础知识对抗样本定义对抗样本是使得机器学习的算法产生误判的样本，如上图所示，原有的模型以57.7%的置信度判定图片为熊猫，但添加微小的扰动后，模型以99.3%的置信度认为扰动后的图片是长臂猿。产生对抗样本的方法 基于梯度的方法$J(\theta;x;y)$是模型的损失函数，其中负梯度方向$-\nabla J_x(\theta;x;y)$是模型损失下降最快的方向，为了使$\hat x$对模型输出产生最大的改变，正梯度方向为扰动最大的方向，在该方向上进行扰动，可以快速产生对抗样本，该方法称为“快速符号梯度法”（fast gradient sign medthod，FGSM），见Ian J. Goodfellow 在2014发表的论文Explaining and Harnessing Adversarial Examples。 基于超平面分类Deepfool是基于超平面分类思想的一种对抗样本生成方法。众所周知，在二分类问题中，超平面是实现分类的基础 ，那么要改变某个样本 x 的分类，最小的扰动就是将 x 挪到超平面上，这个距离的代价最小。多分类的问题也是类似。 显然我们希望模型可以变得更加鲁棒。一个最简单的方法，就是生成这些数据，并且把这些数据加入到训练数据中。这样模型就会正视这些数据，并且尽可能地拟合这些数据，最终完成了模型拟合，这些盲区也就覆盖住了。将对抗样本和原有数据一起进行训练，对抗样本产生的损失作为原损失的一部分，即在不修改原模型结构的情况下增加模型的损失，产生正则化的效果。 对抗攻击对抗攻击指的是在模型原始输入上添加对抗扰动构建对抗样本从而使模型产生错误判断的过程。而在这一过程中，对抗扰动的选择和产生是关键。对抗扰动指的是在模型输入上添加能够误导模型输出的微小变。 虽然不同的文章对于对抗扰动的定义略有不同，但是一般来说对抗扰动具有两个特点： 扰动是微小的甚至是肉眼难以观测到的； 添加的扰动必须有能力使得模型产生错误的输出。 对抗攻击的分类 分类标准 名称 说明 按对原始模型的访问权限不同 黑盒攻击与白盒攻击 白盒攻击指的是攻击者可以完全访问目标模型，他们可以了解模型的架构，参数和权重。黑盒攻击指的是攻击者很少或根本没有关于目标模型的知识，他们无法对其进行探测。在这种情况下，攻击者通常训练自己的模型并利用对抗性样本的可转移性来进行攻击。当然，白盒和黑盒攻击都无法改变模型和训练数据。在实际应用中，这两者的区别体现为：通过模型A来生成对抗样本，进而攻击模型B。当模型A与模型B是一个模型时，为白盒攻击；当模型A与模型B不为一个模型时，则为黑盒攻击。 按攻击目的 目标攻击和非目标攻击 目标攻击指的是生成的对抗样本希望被模型错分到某个特定的类别上。非目标攻击指的是对抗样本只要能让模型分错就行，不论错分到哪个类别都可以。 常见对抗样本防御方法由于目前防御方法仍然没有一个权威的分类方式，故笔者将目前看到过的一些防御方法大致分为以下四类：对抗训练、梯度掩码、随机化、去噪等。 对抗训练：对抗训练旨在从随机初始化的权重中训练一个鲁棒的模型，其训练集由真实数据集和加入了对抗扰动的数据集组成，因此叫做对抗训练。 梯度掩码：由于当前的许多对抗样本生成方法都是基于梯度去生成的，所以如果将模型的原始梯度隐藏起来，就可以达到抵御对抗样本攻击的效果。 随机化：向原始模型引入随机层或者随机变量。使模型具有一定随机性，全面提高模型的鲁棒性，使其对噪声的容忍度变高。 去噪：在输入模型进行判定之前，先对当前对抗样本进行去噪，剔除其中造成扰动的信息，使其不能对模型造成攻击。 对抗训练对抗训练是 Ian J. Goodfellow 在 Explaining and Harnessing Adversarial Examples 最早提出来的一个对抗样本的防御方法。它的主要思想是：在模型训练过程中，训练样本不再只是原始样本，而是原始样本加上对抗样本，就相当于把产生的对抗样本当作新的训练样本加入到训练集中，对它们一视同仁，那么随着模型越来越多的训练，一方面原始图片的准确率会增加，另一方面，模型对对抗样本的鲁棒性也会增加。 Adversarial training for multi-context joint entity and relation extraction 内容：Adversarial training (AT) (Goodfellow et al., 2015) has been proposed to make classiﬁers more robust to input perturbations in the context of image recognition. In the context of NLP, several variants have been proposed for different tasks such as text classiﬁcation (Miyato et al., 2017), relation extraction (Wu et al., 2017) and POS tagging (Yasunaga et al., 2018). AT is considered as a regularization method. Unlike other regu- larization methods (i.e., dropout (Srivastava et al., 2014), word dropout (Iyyer et al., 2015)) that introduce random noise, AT generates perturbations that are variations of examples easily misclassiﬁed by the model. 对抗训练指的是在模型的训练过程中构建对抗样本并将对抗样本和原始样本混合一起训练模型的方法，换句话说就是在模型训练的过程中对模型进行对抗攻击从而提升模型对于对抗攻击的鲁棒性（也称为防御能力）。 对抗训练局限性对抗训练（以及集成对抗训练）确实是防御对抗样本攻击的有效方法，但是它也存在着局限性。对抗训练是通过不断输入新类型的对抗样本进行训练，从而不断提升模型的鲁棒性。为了保证有效性，该方法需要使用高强度的对抗样本，并且网络架构要有充足的表达能力。而且无论添加多少对抗样本，都存在新的对抗样本可以欺骗网络。 对抗攻击例子Black-box Generation of Adversarial Text Sequences to Evade Deep Learning Classifiers 中例子： part1 指的是原始的输入文本，part2 指的是对原始数据进行离散扰动后的文本，虽然只有少量字符被修改但是模型产生了完全不同的输出。在文本处理中，对抗扰动的特征 1 要求添加扰动后产生的对抗样本与原样本在语义上保持一致，即添加的扰动应该尽量不改变原始句子的语义。 MNIST 实验如下是在MNIST数据集上进行对抗训练的实验结果，红色线表示使用了对抗训练数据，蓝色表示没有使用。 结论： 在MNIST训练集上，使用对抗训练会的模型损失增大，但是可以保持准确率与不使用对抗训练模型一致； 在MNIST验证集上，使用对抗训练的模型损比不使用对抗训练的模型损失更小、准确率更高。 常见问题解答对模型正则化以后是不是仍然用原来的对抗样本来做实验？对模型正则化以后是不是仍然用原来的对抗样本来做实验，如果是那就没有意义，因为模型参数改变了，对抗样本应该重新生成；如果不是，那很难理解，因为模型的线性特性并没有改变，仍然可以找到对抗样本，没有理由错误率会降低。我觉得这里可以这么解释为什么重新生成对抗样本，错误率还是降低了。因为对于强正则化，模型的权重会变得比较小，输入扰动对模型的输出影响不仅取决于它本身，还与模型权重有关，既然加入了惩罚项对样本的扰动进行惩罚，那么模型就会降低权重来减小扰动带来的损失。 实验结果表明对抗训练确实大幅提升了模型对白盒攻击的鲁棒性，但是对于黑盒攻击，甚至出现了比原始模型更高的错误率？因为对抗训练是针对某一个模型产生的对抗样本进行学习，那么模型势必会更具有针对性，所以就可能在面对其他模型生成的对抗样本攻击时会出现比原始模型更高的错误率。另外，还可以通过实验结果发现各个模型普遍对于对抗模型产生的对抗样本具有好的鲁棒性。这个现象验证了作者提出的一个观点，即对抗训练不仅仅是拟合了对模型有影响的扰动，其同时弱化了单步攻击时需要依赖的模型的线性假设，因此造成了使用单步攻击时的效果变差。为了进一步提升模型对黑盒攻击的鲁棒性，作者将生成对抗样本的模型从单个变成了多个，增加了对抗样本的多样性，削弱对抗训练时对单个模型的过拟合。观察实验结果发现，集成对抗训练对于白盒攻击的鲁棒性不如对抗训练，这是由于对抗训练增强的数据集恰恰就是白盒攻击的数据集，所以对白盒攻击的鲁棒性会更强，如果集成对抗训练使用的模型越多，则对白盒攻击的鲁棒性越差。但是，在黑盒攻击中，集成对抗训练表现出了很强的鲁棒性。 对抗训练相关阅读资料 标题 说明 时间 对抗样本与对抗训练 科普浅析 20161207 ：对抗攻击基础知识 知乎专栏，讲解细致 这部分内容主要是有关对抗学习理论的研究 关于文本对抗性攻击和防御的必读文章 2014 Explaining and Harnessing Adversarial Examples Several machine learning models, including neural networks, consistently misclassify adversarial examples—-inputs formed by applying small but intentionally worst-case perturbations to examples from the dataset, such that the perturbed input results in the model outputting an incorrect answer with high confidence. Early attempts at explaining this phenomenon focused on nonlinearity and overfitting. We argue instead that the primary cause of neural networks’ vulnerability to adversarial perturbation is their linear nature. This explanation is supported by new quantitative results while giving the first explanation of the most intriguing fact about them: their generalization across architectures and training sets. Moreover, this view yields a simple and fast method of generating adversarial examples. Using this approach to provide examples for adversarial training, we reduce the test set error of a maxout network on the MNIST dataset. 包括神经网络在内的几种机器学习模型始终错误地分类对抗性示例 - 通过对数据集中的示例应用小但有意的最坏情况扰动而形成的输入，使得扰动的输入导致模型以高置信度输出不正确的答案。 早期解释这种现象的尝试集中在非线性和过度拟合上。 我们认为神经网络易受对抗性扰动的主要原因是它们的线性特性。 这个解释得到了新的定量结果的支持，同时首先解释了关于它们的最有趣的事实：它们跨架构和训练集的泛化。 此外，该视图产生了一种生成对抗性示例的简单快速的方法。 使用此方法为对抗训练提供示例，我们减少了MNIST数据集上maxout网络的测试集错误。 标题 说明 时间 Explaining and Harnessing Adversarial Examples 论文原文 20141220 论文阅读:Explaining and Harnessing Adversarial Examples(解释分析对抗样本) 论文解析 20180402 2015 Distributional Smoothing with Virtual Adversarial Training由于文本不同于图片，文本一般转化为Index，通过Embedding后输入到network中，无法对input进行直接的求导，Miyato3 等提出将扰动添加到Embedding层，经过扰动后的Embedding对扰动有更好的鲁棒性。其模型结构为 We propose local distributional smoothness (LDS), a new notion of smoothness for statistical model that can be used as a regularization term to promote the smoothness of the model distribution. We named the LDS based regularization as virtual adversarial training (VAT). The LDS of a model at an input datapoint is defined as the KL-divergence based robustness of the model distribution against local perturbation around the datapoint. VAT resembles adversarial training, but distinguishes itself in that it determines the adversarial direction from the model distribution alone without using the label information, making it applicable to semisupervised learning. The computational cost for VAT is relatively low. For neural network, the approximated gradient of the LDS can be computed with no more than three pairs of forward and back propagations. When we applied our technique to supervised and semi-supervised learning for the MNIST dataset, it outperformed all the training methods other than the current state of the art method, which is based on a highly advanced generative model. We also applied our method to SVHN and NORB, and confirmed our method’s superior performance over the current state of the art semi-supervised method applied to these datasets. 2017 Adversarial Dropout for Supervised and Semi-supervised Learning Recently, the training with adversarial examples, which are generated by adding a small but worst-case perturbation on input examples, has been proved to improve generalization performance of neural networks. In contrast to the individually biased inputs to enhance the generality, this paper introduces adversarial dropout, which is a minimal set of dropouts that maximize the divergence between the outputs from the network with the dropouts and the training supervisions. The identified adversarial dropout are used to reconfigure the neural network to train, and we demonstrated that training on the reconfigured sub-network improves the generalization performance of supervised and semi-supervised learning tasks on MNIST and CIFAR-10. We analyzed the trained model to reason the performance improvement, and we found that adversarial dropout increases the sparsity of neural networks more than the standard dropout does. 标题 说明 时间 Adversarial Dropout for Supervised and Semi-supervised Learning 论文原文 20170712 对抗训练-Adversarial Training for Supervised and Semi-Supervised Learning（对抗训练在监督和半监督学习上的应用） 论文解析 20181018 半监督文本分类的对抗训练 论文解析 20181231 2018 Certifying Some Distributional Robustness with Principled Adversarial Training 深度学习顶会“无冕之王”ICLR 2018评审结果出炉，斯坦福大学对抗训练研究得分第一。 Neural networks are vulnerable to adversarial examples and researchers have proposed many heuristic attack and defense mechanisms. We address this problem through the principled lens of distributionally robust optimization, which guarantees performance under adversarial input perturbations. By considering a Lagrangian penalty formulation of perturbing the underlying data distribution in a Wasserstein ball, we provide a training procedure that augments model parameter updates with worst-case perturbations of training data. For smooth losses, our procedure provably achieves moderate levels of robustness with little computational or statistical cost relative to empirical risk minimization. Furthermore, our statistical guarantees allow us to efficiently certify robustness for the population loss. For imperceptible perturbations, our method matches or outperforms heuristic approaches. 神经网络容易受到对抗性的影响，研究人员提出了许多启发式攻击和防御机制。 我们通过分布式鲁棒优化的原理镜头来解决这个问题，这保证了在对抗性输入扰动下的性能。 通过考虑拉格朗日惩罚公式扰乱 Wasserstein balls 的基础数据分布，我们提供了一个训练程序，增加了模型参数更新与最坏情况下的训练数据扰动。 对于平滑损失，我们的程序可证明实现了中等水平的稳健性，与经验风险最小化相比，计算或统计成本很低。 此外，我们的统计保证使我们能够有效地证明 population 损失的稳健性。 对于难以察觉的扰动，我们的方法匹配或优于启发式方法。 2019 Towards a Robust Deep Neural Network in Text Domain A Survey Deep neural networks (DNNs) have shown an inherent vulnerability to adversarial examples which are maliciously crafted on real examples by attackers, aiming at making target DNNs misbehave. The threats of adversarial examples are widely existed in image, voice, speech, and text recognition and classification. Inspired by the previous work, researches on adversarial attacks and defenses in text domain develop rapidly. In order to make people have a general understanding about the field, this article presents a comprehensive review on adversarial examples in text. We analyze the advantages and shortcomings of recent adversarial examples generation methods and elaborate the efficiency and limitations on countermeasures. Finally, we discuss the challenges in adversarial texts and provide a research direction of this aspect. 深度神经网络（DNN）已显示出对抗性示例的固有漏洞，这些示例是攻击者在真实示例中恶意制作的，旨在使目标DNN行为不端。 对抗性示例的威胁在图像，语音，语音，文本识别和分类中广泛存在。 受以往工作的启发，对文本域中的对抗性攻击和防御的研究迅速发展。 为了使人们对该领域有一个大致的了解，本文对文本中的对抗性例子进行了全面的回顾。 我们分析了近期对抗性实例生成方法的优缺点，并详细阐述了对策的效率和局限性。 最后，我们讨论对抗性文本中的挑战，并提供这方面的研究方向。 这部分内容是对抗训练应用于各个模型 2017 Multi-Domain Adversarial Learning for Slot Filling in Spoken Language Understanding 对抗训练应用槽填充任务，这里使用对抗训练主要是为了训练出一个通用表示的槽填充模型，然后将这个模型的表示与特定领域模型的表示结合起来做预测，作用是减少了特定领域标签数据和提升模型效果。 2018 Adversarial training for multi-context joint entity and relation extraction 本文是 Joint entity recognition and relation extraction as a multi-head selection problem 的姊妹篇，都是同一个多头选择实体关系抽取模型，只是增加了对抗训练这个神经网络正则化方法。]]></content>
      <categories>
        <category>论文</category>
        <category>对抗训练</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>对抗训练</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[EfficientNet Rethinking Model Scaling for Convolutional Neural Networks]]></title>
    <url>%2F2019%2F06%2F04%2FEfficientNet_Rethinking_Model_Scaling_for_Convolutional_Neural_Networks%2F</url>
    <content type="text"><![CDATA[EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks 在模型扩展时平衡好深度、宽度、分辨率，取得精度、效率、模型大小的最大化。借由此简单有效的模型扩展方法，作者在使用神经架构搜索得到的基模型上扩展出一系列EfficientNets模型，达到了更好的精度和效率的平衡。该文已被ICML 2019录用，这可能是一篇要改变整个深度卷积网络模型设计的论文了。 Convolutional Neural Networks (ConvNets) are commonly developed at a fixed resource budget, and then scaled up for better accuracy if more resources are available. In this paper, we systematically study model scaling and identify that carefully balancing network depth, width, and resolution can lead to better performance. Based on this observation, we propose a new scaling method that uniformly scales all dimensions of depth/width/resolution using a simple yet highly effective compound coefficient. We demonstrate the effectiveness of this method on scaling up MobileNets and ResNet.To go even further, we use neural architecture search to design a new baseline network and scale it up to obtain a family of models, called EfficientNets, which achieve much better accuracy and efficiency than previous ConvNets. In particular, our EfficientNet-B7 achieves state-of-the-art 84.4% top-1 / 97.1% top-5 accuracy on ImageNet, while being 8.4x smaller and 6.1x faster on inference than the best existing ConvNet. Our EfficientNets also transfer well and achieve state-of-the-art accuracy on CIFAR-100 (91.7%), Flowers (98.8%), and 3 other transfer learning datasets, with an order of magnitude fewer parameters. Source code is at this https URL. 卷积神经网络（ConvNets）通常是在固定资源预算下开发的，如果有更多可用资源，则可以按比例放大以获得更高的准确性。在本文中，我们系统地研究模型缩放并确定仔细平衡网络深度，宽度和分辨率可以带来更好的性能。基于这一观察，我们提出了一种新的缩放方法，该方法使用简单但高效的复合系数均匀地缩放深度/宽度/分辨率的所有尺寸。我们证明了这种方法在扩展MobileNets和ResNet方面的有效性。为了更进一步，我们使用神经架构搜索来设计新的基线网络并进行扩展以获得一系列模型，称为EfficientNets，它比以前的ConvNets具有更高的准确性和效率。特别是，我们的EfficientNet-B7在ImageNet上实现了最先进的84.4％前1 / 97.1％前5精度，同时比最好的现有ConvNet小了8.4倍，推理速度快6.1倍。我们的EfficientNets在CIFAR-100（91.7％），Flowers（98.8％）和其他3个传输学习数据集上也能很好地传输和实现最先进的精度，参数的数量级减少了一个数量级。源代码位于此https URL。 标题 说明 时间 EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks 原始论文 20190528 EfficientNets 官方实现 如何评价谷歌大脑的EfficientNet？ 知乎评价 CNN网络结构的发展：从LeNet到EfficientNet 知乎专栏 20190608]]></content>
      <categories>
        <category>论文</category>
      </categories>
      <tags>
        <tag>ImageNet</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[信息抽取任务相关论文发展脉络]]></title>
    <url>%2F2019%2F05%2F28%2F%E4%BF%A1%E6%81%AF%E6%8A%BD%E5%8F%96%E4%BB%BB%E5%8A%A1%E7%9B%B8%E5%85%B3%E8%AE%BA%E6%96%87%E5%8F%91%E5%B1%95%E8%84%89%E7%BB%9C%2F</url>
    <content type="text"><![CDATA[信息抽取引言2017-2018 基于神经网络的实体识别和关系抽取联合学习本文关注的任务是从无结构的文本中抽取实体以及实体之间的关系（实体1-关系-实体2，三元组），这里的关系是我们预定义好的关系类型。例如下图， Multiple relations extraction among multiple entities in unstructured text To the best of our knowledge, our proposed model is the ﬁrst one to extract multiple relations among multiple entities. Relations extraction is a widely researched topic in nature language processing. However, most of the work in the literature concentrate on the methods that are dealing with single relation between two named entities. In the task of multiple relations extraction, traditional statistic-based methods have difficulties in selecting features and improving the performance of extraction model. In this paper, we presented formal definitions of multiple entities and multiple relations and put forward three labeling methods which were used to label entity categories, relation categories and relation conditions. We also proposed a novel relation extraction model which is based on dynamic long short-term memory network. To train our model, entity feature, entity position feature and part of speech feature are used together. These features are used to describe complex relations and improve the performance of relation extraction model. In the experiments, we classified the corpus into three sets which are composed of 0–20 words, 20–35 words and 35+ words sentences. On conll04.corp, the final precision, recall rate and F-measure reached 72.9, 70.8 and 67.9% respectively. 关系提取是自然语言处理中广泛研究的主题。但是，文献中的大多数工作都集中在处理两个命名实体之间单一关系的方法上。在多关系提取的任务中，传统的基于统计的方法在选择特征和提高提取模型的性能方面存在困难。在本文中，我们提出了多个实体和多个关系的正式定义，并提出了三种标记方法，用于标记实体类别，关系类别和关系条件。我们还提出了一种基于动态长短期记忆网络的新型关系提取模型。为了训练我们的模型，实体特征，实体位置特征和词性特征一起使用。这些特征用于描述复杂关系并改善关系提取模型的性能。在实验中，我们将语料库分为三组，由0-20个单词，20-35个单词和35个单词组成。在conll04.corp上，最终的精确度，召回率和F-指数分别达到72.9％，70.8％和67.9％。 Joint entity recognition and relation extraction as a multi-head selection problemAbstract State-of-the-art models for joint entity recognition and relation extraction strongly rely on external natural language processing (NLP) tools such as POS (part-of-speech) taggers and dependency parsers. Thus, the performance of such joint models depends on the quality of the features obtained from these NLP tools. However, these features are not always accurate for various languages and contexts. In this paper, we propose a joint neural model which performs entity recognition and relation extraction simultaneously, without the need of any manually extracted features or the use of any external tool. Specifically, we model the entity recognition task using a CRF (Conditional Random Fields) layer and the relation extraction task as a multi-head selection problem (i.e., potentially identify multiple relations for each entity). We present an extensive experimental setup, to demonstrate the effectiveness of our method using datasets from various contexts (i.e., news, biomedical, real estate) and languages (i.e., English, Dutch). Our model outperforms the previous neural models that use automatically extracted features, while it performs within a reasonable margin of feature-based neural models, or even beats them. 摘要 用于联合实体识别和关系提取的最先进模型强烈依赖于外部自然语言处理（NLP）工具，例如POS（词性）标记器和依赖性解析器。因此，这种联合模型的性能取决于从这些NLP工具获得的特征的质量。但是，对于各种语言和上下文，这些功能并不总是准确的。在本文中，我们提出了一个联合神经模型，它同时执行实体识别和关系提取，无需任何手动提取的功能或使用任何外部工具。具体地，我们使用CRF（条件随机场）层和关系提取任务将实体识别任务建模为多头选择问题（即，潜在地识别每个实体的多个关系）。我们提出了一个广泛的实验设置，以证明我们的方法使用来自各种环境（即新闻，生物医学，房地产）和语言（即英语，荷兰语）的数据集的有效性。我们的模型优于以前使用自动提取特征的神经模型，同时它在基于特征的神经模型的合理范围内执行，甚至胜过它们。 标题 说明 时间 Joint entity recognition and relation extraction as a multi-head selection problem 论文原文 2018 multihead_joint_entity_relation_extraction 论文实现 20190429 对抗训练多头选择的实体识别和关系抽取的联合模型 论文解析 20181005 Adversarial training for multi-context joint entity and relation extraction 本文是 Joint entity recognition and relation extraction as a multi-head selection problem 的姊妹篇，都是同一个多头选择实体关系抽取模型，只是增加了对抗训练这个神经网络正则化方法。 Abstract Adversarial training (AT) is a regularization method that can be used to improve the robustness of neural network methods by adding small perturbations in the training data. We show how to use AT for the tasks of entity recognition and relation extraction. In particular, we demonstrate that applying AT to a general purpose baseline model for jointly extracting entities and relations, allows improving the state-of-the-art effectiveness on several datasets in different contexts (i.e., news, biomedical, and real estate data) and for different languages (English and Dutch). 摘要 对抗训练（AT）是一种正则化方法，可以通过在训练数据中添加小扰动来提高神经网络方法的鲁棒性。 我们展示了如何将AT用于实体识别和关系提取的任务。 特别是，我们证明将AT应用于通用基线模型以联合提取实体和关系，可以改善不同环境中几个数据集（即新闻，生物医学和房地产数据）的最新效果。 和不同的语言（英语和荷兰语）。 3.2 Adversarial traing (AT)We exploit the idea of AT (Goodfellow et al., 2015) as a regularization method to make our model robust to input perturbations. Speciﬁcally, we generate examples which are variations of the original ones by adding some noise at the level of the concatenated word representation (Miyato et al., 2017). This is similar to the concept introduced by Goodfellow et al. (2015) to improve the robustness of image recognition classiﬁers. We generate an adversarial example by adding the worst-case perturbation $\eta_{adv}$ to the original embedding w that maximizes the loss function: \eta_{adv}=argmaxLoss(w+\eta;\hat\theta),\Vert\eta\Vert\leq\epsilonwhere $\hat\theta$ is a copy of the current model parameters. Since Eq. (2) is intractable in neural networks, we use the approximation proposed in Goodfellow et al. (2015) deﬁned as: $\eta_{adv}=\epsilon g/\Vert g \Vert$, with $g=\nabla_wLoss(w;\hat\theta)$, where $\epsilon$ is a small bounded norm treated as a hyperparameter. Similar to Yasunaga et al. (2018), we set $\epsilon$ to be $\alpha\sqrt{D}$ (where $D$ is the dimension of the embeddings). We train on the mixture of original and adversarial examples, so the ﬁnal loss is computed as: $Loss(w;\hat\theta)+Loss(w+\eta;\hat\theta)$. \eta_{adv}=\epsilon g/\Vert g \Vert, g=\nabla_wLoss(w;\hat\theta),\epsilon=\alpha\sqrt{D} 标题 说明 时间 Adversarial training for multi-context joint entity and relation extraction 论文原文 2018 multihead_joint_entity_relation_extraction 论文实现 20190429 Simultaneously Self-Attending to All Mentions for Full-Abstract Biological Relation ExtractionAbstract Most work in relation extraction forms a prediction by looking at a short span of text within a single sentence containing a single entity pair mention. This approach often does not consider interactions across mentions, requires redundant computation for each mention pair, and ignores relationships expressed across sentence boundaries. These problems are exacerbated by the document- (rather than sentence-) level annotation common in biological text. In response, we propose a model which simultaneously predicts relationships between all mention pairs in a document. We form pairwise predictions over entire paper abstracts using an efficient self-attention encoder. All-pairs mention scores allow us to perform multi-instance learning by aggregating over mentions to form entity pair representations. We further adapt to settings without mention-level annotation by jointly training to predict named entities and adding a corpus of weakly labeled data. In experiments on two Biocreative benchmark datasets, we achieve state of the art performance on the Biocreative V Chemical Disease Relation dataset for models without external KB resources. We also introduce a new dataset an order of magnitude larger than existing human-annotated biological information extraction datasets and more accurate than distantly supervised alternatives. 摘要 关系提取中的大多数工作通过查看包含单个实体对提及的单个句子中的短文本来形成预测。这种方法通常不考虑提及的交互，需要对每个提及对进行冗余计算，并忽略跨句子边界表达的关系。生物文本中常见的文档（而不是句子）级别注释加剧了这些问题。作为回应，我们提出了一个模型，它同时预测文档中所有提及对之间的关​​系。我们使用有效的自我关注编码器在整个纸质摘要上形成成对预测。所有对提及分数允许我们通过聚合提及以形成实体对表示来执行多实例学习。我们通过联合训练来预测命名实体并添加弱标记数据的语料库，从而进一步适应没有提及级别注释的设置。在两个Biocreative基准数据集的实验中，我们在Biocreative V Chemical Disease Relation数据集上获得了没有外部KB资源的模型的最新性能。我们还引入了一个比现有的人类注释生物信息提取数据集大一个数量级的新数据集，并且比远程监督的替代方案更准确。 标题 说明 时间 Simultaneously Self-Attending to All Mentions for Full-Abstract Biological Relation Extraction 论文原文 2018 End-to-end neural relation extraction using deep biaffine attention We propose a neural network model for joint extraction of named entities and relations between them, without any hand-crafted features. The key contribution of our model is to extend a BiLSTM-CRF-based entity recognition model with a deep biaffine attention layer to model second-order interactions between latent features for relation classification, specifically attending to the role of an entity in a directional relationship. On the benchmark “relation and entity recognition” dataset CoNLL04, experimental results show that our model outperforms previous models, producing new state-of-the-art performances. 我们提出了一种神经网络模型，用于联合提取命名实体及其之间的关系，没有任何手工制作的特征。 我们模型的关键贡献是扩展基于BiLSTM-CRF的实体识别模型，该模型具有深的biaffine注意层，以模拟关系分类的潜在特征之间的二阶相互作用，特别是关注实体在方向关系中的角色。 在基准“关系和实体识别”数据集CoNLL04上，实验结果表明我们的模型优于以前的模型，产生了新的最先进的性能。 jointRE A Unified Model for Joint Chinese Word Segmentation and Dependency Parsing Chinese word segmentation and dependency parsing are two fundamental tasks for Chinese natural language processing. The dependency parsing is defined on word-level, therefore word segmentation is the precondition of dependency parsing, which makes dependency parsing suffers from error propagation. In this paper, we propose a unified model to integrate Chinese word segmentation and dependency parsing. Different from previous joint models, our proposed model is a graph-based model and more concise, which results in fewer efforts of feature engineering. Our joint model achieves better performance than previous joint models. Our joint model achieves the state-of-the-art results in both Chinese word segmentation and dependency parsing. 中文分词和依赖解析是中文自然语言处理的两个基本任务。 依赖性解析是在字级别定义的，因此分词是依赖性解析的前提条件，这使得依赖性解析受到错误传播的影响。 在本文中，我们提出了一个统一的模型来集成中文分词和依赖解析。 与以前的联合模型不同，我们提出的模型是基于图形的模型，更简洁，从而减少了特征工程的工作量。 我们的联合模型比以前的联合模型具有更好的性能。 我们的联合模型在中文分词和依赖分析中实现了最先进的结果。 标题 说明 时间 A Unified Model for Joint Chinese Word Segmentation and Dependency Parsing 论文原文 20190409 联合汉语分词和依存句法分析的统一模型：当前效果最佳 论文浅析 20190427 Extracting Multiple-Relations in One-Pass with Pre-Trained Transformers this work is the ﬁrst approach that can solve multi-relation extraction (MRE) task accurately to achieve state-of-the-art results and fast (in one-pass). Abstract Most approaches to extraction multiple relations from a paragraph require multiple passes over the paragraph. In practice, multiple passes are computationally expensive and this makes difficult to scale to longer paragraphs and larger text corpora. In this work, we focus on the task of multiple relation extraction by encoding the paragraph only once (one-pass). We build our solution on the pre-trained self-attentive (Transformer) models, where we first add a structured prediction layer to handle extraction between multiple entity pairs, then enhance the paragraph embedding to capture multiple relational information associated with each entity with an entity-aware attention technique. We show that our approach is not only scalable but can also perform state-of-the-art on the standard benchmark ACE 2005. 摘要 从段落中提取多个关系的大多数方法都要求在段落上多次传递。 在实践中，多次通过在计算上是昂贵的，并且这使得难以扩展到更长的段落和更大的文本语料库。 在这项工作中，我们通过仅对段落进行一次编码（一次通过）来专注于多关系提取的任务。 我们在预训练的自我关注（Transformer）模型上构建我们的解决方案，我们首先添加结构化预测层来处理多个实体对之间的提取，然后增强段落嵌入以捕获与每个实体关联的多个关系信息与实体 - 注意技术。 我们表明，我们的方法不仅可扩展，而且还可以在标准基准ACE 2005上执行最先进的技术。 标题 说明 时间 Extracting Multiple-Relations in One-Pass with Pre-Trained Transformers 论文原文]]></content>
      <categories>
        <category>论文</category>
        <category>信息抽取</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>实体识别</tag>
        <tag>关系抽取</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[多关系抽取研究]]></title>
    <url>%2F2019%2F05%2F17%2F%E5%A4%9A%E5%85%B3%E7%B3%BB%E6%8A%BD%E5%8F%96%E7%A0%94%E7%A9%B6%2F</url>
    <content type="text"><![CDATA[实体、关系和多关系的形式化定义 参考 Multiple relations extraction among multiple entities in unstructured text 实体种类表、关系种类表、后选关系表 实体是作为一个主体或一个客体存在的东西，实际上或潜在地，具体地或抽象地，物理上或不是，代词（你，我，他）也是一种实体形式。 根据ACE2008，实体可以分为五类：人，组织，地缘政治实体，位置和设施。 我们标记了这些实体类型，如表2所示。An entity is something that exists as itself, as a subject or as an object, actually or potentially, concretely or abstractly, physically or not, the pronoun (you, me, he) is also a form of entity. According to ACE2008, entities can be classiﬁed into ﬁve categories: Person, Organization, Geo-political entity, Location and Facility. We label these entity types as shown in Table 2. 两个实体之间的关系可以分为七类：物理，部分整体，个人社会，ORG-Af fi lation，Agent-Artifact，Gen-Affliation和NA.3我们将这些关系类型标记为表3所示。The relations between two entities can be classiﬁed into seven categories: Physical, Part-whole, Personal-Social, ORG-Afﬁliation, Agent-Artifact, Gen-Afﬁliation and NA.3 We label these relation types as shown in Table 3. 表4显示了双实体对需要满足的条件，以在它们之间形成某种类型的关系。Table 4 shows the conditions that a two-entity pair need to meet to form a certain type relation between them. 实体关系的形式化定义 相关连接多关系抽取实战 Multiple-Relations-Extraction-Only-Look-Once Entity-Relation-Extraction 关系抽取论文整理信息抽取任务相关论文发展脉络 相关任务命名实体识别CoNLL2003]]></content>
      <categories>
        <category>论文</category>
        <category>信息抽取</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>实体识别</tag>
        <tag>关系抽取</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Multiple-Relations-Extraction-Only-Look-Once理论与实践]]></title>
    <url>%2F2019%2F05%2F09%2FMultiple-Relations-Extraction-Only-Look-Once%2F</url>
    <content type="text"><![CDATA[模型训练和预测多关系抽取模型训练12345678910111213python run_multiple_relations_extraction.py \--task_name=SKE_2019 \--do_train=true \--do_eval=false \--data_dir=bin/standard_format_data \--vocab_file=pretrained_model/chinese_L-12_H-768_A-12/vocab.txt \--bert_config_file=pretrained_model/chinese_L-12_H-768_A-12/bert_config.json \--init_checkpoint=pretrained_model/chinese_L-12_H-768_A-12/bert_model.ckpt \--max_seq_length=128 \--train_batch_size=32 \--learning_rate=2e-5 \--num_train_epochs=6.0 \--output_dir=./output/multiple_relations_model/epochs6/ 关系分类模型预测123456789python run_multiple_relations_extraction.py \ --task_name=SKE_2019 \ --do_predict=true \ --data_dir=bin/standard_format_data \ --vocab_file=pretrained_model/chinese_L-12_H-768_A-12/vocab.txt \ --bert_config_file=pretrained_model/chinese_L-12_H-768_A-12/bert_config.json \ --init_checkpoint=output/multiple_relations_model/epochs6/model.ckpt-2000 \ --max_seq_length=128 \ --output_dir=./infer_out/epochs6/ckpt2000 实践数据变换过程raw_data 原始数据 删除了 raw_data 中 “postag”12&#123;&quot;text&quot;: &quot;《逐风行》是百度文学旗下纵横中文网签约作家清水秋风创作的一部东方玄幻小说，小说已于2014-04-28正式发布&quot;,&quot;spo_list&quot;: [&#123;&quot;predicate&quot;: &quot;连载网站&quot;, &quot;object_type&quot;: &quot;网站&quot;, &quot;subject_type&quot;: &quot;网络小说&quot;, &quot;object&quot;: &quot;纵横中文网&quot;, &quot;subject&quot;: &quot;逐风行&quot;&#125;, &#123;&quot;predicate&quot;: &quot;作者&quot;, &quot;object_type&quot;: &quot;人物&quot;, &quot;subject_type&quot;: &quot;图书作品&quot;, &quot;object&quot;: &quot;清水秋风&quot;, &quot;subject&quot;: &quot;逐风行&quot;&#125;]&#125; standard_format_data 格式化后的数据 把中文text数据按照字为单位分开，然后根据spo_list内容，使用BIO格式标注实体数据，使用关系的位置和值来标注实体之间关系。具体来说，predicte value 表示该实体头对应的整个实含有的关系，predicate location 表示与当前实体发生关系实体的头的位置。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455+-------+-------+------------+----------------------+--------------------+| index | token | label | predicate value | predicate location |+-------+-------+------------+----------------------+--------------------+| 0 | 《 | O | [&apos;N&apos;] | [0] || 1 | 逐 | B-图书作品 | [&apos;连载网站&apos;, &apos;作者&apos;] | [12, 21] || 2 | 风 | I-图书作品 | [&apos;N&apos;] | [2] || 3 | 行 | I-图书作品 | [&apos;N&apos;] | [3] || 4 | 》 | O | [&apos;N&apos;] | [4] || 5 | 是 | O | [&apos;N&apos;] | [5] || 6 | 百 | O | [&apos;N&apos;] | [6] || 7 | 度 | O | [&apos;N&apos;] | [7] || 8 | 文 | O | [&apos;N&apos;] | [8] || 9 | 学 | O | [&apos;N&apos;] | [9] || 10 | 旗 | O | [&apos;N&apos;] | [10] || 11 | 下 | O | [&apos;N&apos;] | [11] || 12 | 纵 | B-网站 | [&apos;N&apos;] | [12] || 13 | 横 | I-网站 | [&apos;N&apos;] | [13] || 14 | 中 | I-网站 | [&apos;N&apos;] | [14] || 15 | 文 | I-网站 | [&apos;N&apos;] | [15] || 16 | 网 | I-网站 | [&apos;N&apos;] | [16] || 17 | 签 | O | [&apos;N&apos;] | [17] || 18 | 约 | O | [&apos;N&apos;] | [18] || 19 | 作 | O | [&apos;N&apos;] | [19] || 20 | 家 | O | [&apos;N&apos;] | [20] || 21 | 清 | B-人物 | [&apos;N&apos;] | [21] || 22 | 水 | I-人物 | [&apos;N&apos;] | [22] || 23 | 秋 | I-人物 | [&apos;N&apos;] | [23] || 24 | 风 | I-人物 | [&apos;N&apos;] | [24] || 25 | 创 | O | [&apos;N&apos;] | [25] || 26 | 作 | O | [&apos;N&apos;] | [26] || 27 | 的 | O | [&apos;N&apos;] | [27] || 28 | 一 | O | [&apos;N&apos;] | [28] || 29 | 部 | O | [&apos;N&apos;] | [29] || 30 | 东 | O | [&apos;N&apos;] | [30] || 31 | 方 | O | [&apos;N&apos;] | [31] || 32 | 玄 | O | [&apos;N&apos;] | [32] || 33 | 幻 | O | [&apos;N&apos;] | [33] || 34 | 小 | O | [&apos;N&apos;] | [34] || 35 | 说 | O | [&apos;N&apos;] | [35] || 36 | ， | O | [&apos;N&apos;] | [36] || 37 | 小 | O | [&apos;N&apos;] | [37] || 38 | 说 | O | [&apos;N&apos;] | [38] || 39 | 已 | O | [&apos;N&apos;] | [39] || 40 | 于 | O | [&apos;N&apos;] | [40] || 41 | 2014 | O | [&apos;N&apos;] | [41] || 42 | - | O | [&apos;N&apos;] | [42] || 43 | 04 | O | [&apos;N&apos;] | [43] || 44 | - | O | [&apos;N&apos;] | [44] || 45 | 28 | O | [&apos;N&apos;] | [45] || 46 | 正 | O | [&apos;N&apos;] | [46] || 47 | 式 | O | [&apos;N&apos;] | [47] || 48 | 发 | O | [&apos;N&apos;] | [48] || 49 | 布 | O | [&apos;N&apos;] | [49] || | | | | |+-------+-------+------------+----------------------+--------------------+ input model data]]></content>
      <categories>
        <category>论文</category>
        <category>信息抽取</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>论文实现</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Joint entity recognition and relation extraction as a multi-head selection problem]]></title>
    <url>%2F2019%2F05%2F03%2FJoint%20entity%20recognition%20and%20relation%20extraction%20as%20a%20multi-head%20selection%20problem%2F</url>
    <content type="text"><![CDATA[Joint entity recognition and relation extraction as a multi-head selection problemAbstract State-of-the-art models for joint entity recognition and relation extraction strongly rely on external natural language processing (NLP) tools such as POS (part-of-speech) taggers and dependency parsers. Thus, the performance of such joint models depends on the quality of the features obtained from these NLP tools. However, these features are not always accurate for various languages and contexts. In this paper, we propose a joint neural model which performs entity recognition and relation extraction simultaneously, without the need of any manually extracted features or the use of any external tool. Specifically, we model the entity recognition task using a CRF (Conditional Random Fields) layer and the relation extraction task as a multi-head selection problem (i.e., potentially identify multiple relations for each entity). We present an extensive experimental setup, to demonstrate the effectiveness of our method using datasets from various contexts (i.e., news, biomedical, real estate) and languages (i.e., English, Dutch). Our model outperforms the previous neural models that use automatically extracted features, while it performs within a reasonable margin of feature-based neural models, or even beats them. 摘要 用于联合实体识别和关系提取的最先进模型强烈依赖于外部自然语言处理（NLP）工具，例如POS（词性）标记器和依赖性解析器。因此，这种联合模型的性能取决于从这些NLP工具获得的特征的质量。但是，对于各种语言和上下文，这些功能并不总是准确的。在本文中，我们提出了一个联合神经模型，它同时执行实体识别和关系提取，无需任何手动提取的功能或使用任何外部工具。具体地，我们使用CRF（条件随机场）层和关系提取任务将实体识别任务建模为多头选择问题（即，潜在地识别每个实体的多个关系）。我们提出了一个广泛的实验设置，以证明我们的方法使用来自各种环境（即新闻，生物医学，房地产）和语言（即英语，荷兰语）的数据集的有效性。我们的模型优于以前使用自动提取特征的神经模型，同时它在基于特征的神经模型的合理范围内执行，甚至胜过它们。 标题 说明 时间 Joint entity recognition and relation extraction as a multi-head selection problem 论文原文 2018 multihead_joint_entity_relation_extraction 论文实现 20190429 对抗训练多头选择的实体识别和关系抽取的联合模型 论文解析 20181005 数据处理流程1 train.txt12345678910111213141516171819202122232425262728#doc 20500 Mrs. B-Peop [&apos;N&apos;] [0]1 Rose I-Peop [&apos;N&apos;] [1]2 hired O [&apos;N&apos;] [2]3 Abebe B-Peop [&apos;N&apos;] [3]4 Worke I-Peop [&apos;Work_For&apos;, &apos;Live_In&apos;] [22, 8]5 , O [&apos;N&apos;] [5]6 one O [&apos;N&apos;] [6]7 of O [&apos;N&apos;] [7]8 Ethiopia B-Loc [&apos;N&apos;] [8]9 &apos;s O [&apos;N&apos;] [9]10 most O [&apos;N&apos;] [10]11 distinguished O [&apos;N&apos;] [11]12 lawyers O [&apos;N&apos;] [12]13 and O [&apos;N&apos;] [13]14 a O [&apos;N&apos;] [14]15 former O [&apos;N&apos;] [15]16 member O [&apos;N&apos;] [16]17 of O [&apos;N&apos;] [17]18 the O [&apos;N&apos;] [18]19 country O [&apos;N&apos;] [19]20 &apos;s O [&apos;N&apos;] [20]21 High B-Org [&apos;N&apos;] [21]22 Court I-Org [&apos;N&apos;] [22]23 , O [&apos;N&apos;] [23]24 to O [&apos;N&apos;] [24]25 investigate O [&apos;N&apos;] [25]26 . O [&apos;N&apos;] [26] 2 Input data12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061+--------------------------+---------------------------------------------------------------------------+| Input data | Value |+--------------------------+---------------------------------------------------------------------------+| dropout_embedding_keep | 1 || dropout_lstm_keep | 1 || dropout_lstm_output_keep | 1 || dropout_fcl_ner_keep | 1 || dropout_fcl_rel_keep | 1 || isTrain | True || charIds | [[[35 68 69 9 0 0 0 0 0 0 0 0 0] || | [40 65 69 55 0 0 0 0 0 0 0 0 0] || | [58 59 68 55 54 0 0 0 0 0 0 0 0] || | [23 52 55 52 55 0 0 0 0 0 0 0 0] || | [45 65 68 61 55 0 0 0 0 0 0 0 0] || | [ 7 0 0 0 0 0 0 0 0 0 0 0 0] || | [65 64 55 0 0 0 0 0 0 0 0 0 0] || | [65 56 0 0 0 0 0 0 0 0 0 0 0] || | [27 70 58 59 65 66 59 51 0 0 0 0 0] || | [ 4 69 0 0 0 0 0 0 0 0 0 0 0] || | [63 65 69 70 0 0 0 0 0 0 0 0 0] || | [54 59 69 70 59 64 57 71 59 69 58 55 54] || | [62 51 73 75 55 68 69 0 0 0 0 0 0] || | [51 64 54 0 0 0 0 0 0 0 0 0 0] || | [51 0 0 0 0 0 0 0 0 0 0 0 0] || | [56 65 68 63 55 68 0 0 0 0 0 0 0] || | [63 55 63 52 55 68 0 0 0 0 0 0 0] || | [65 56 0 0 0 0 0 0 0 0 0 0 0] || | [70 58 55 0 0 0 0 0 0 0 0 0 0] || | [53 65 71 64 70 68 75 0 0 0 0 0 0] || | [ 4 69 0 0 0 0 0 0 0 0 0 0 0] || | [30 59 57 58 0 0 0 0 0 0 0 0 0] || | [25 65 71 68 70 0 0 0 0 0 0 0 0] || | [ 7 0 0 0 0 0 0 0 0 0 0 0 0] || | [70 65 0 0 0 0 0 0 0 0 0 0 0] || | [59 64 72 55 69 70 59 57 51 70 55 0 0] || | [ 9 0 0 0 0 0 0 0 0 0 0 0 0]]] || tokensLens | [[ 4 4 5 5 5 1 3 2 8 2 4 13 7 3 1 6 6 2 3 7 2 4 5 1 || | 2 11 1]] || embeddingIds | [[ 3806 1984 4334 117254 11 5 69 10 7141 29 || | 155 3359 5857 13 18 360 402 10 6 207 || | 29 219 593 5 16 7011 8]] || entity_tags_ids | [[3 7 8 3 7 8 8 8 0 8 8 8 8 8 8 8 8 8 8 8 8 1 5 8 8 8 8]] || entity_tags | [[&apos;B-Peop&apos; &apos;I-Peop&apos; &apos;O&apos; &apos;B-Peop&apos; &apos;I-Peop&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;B-Loc&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; || | &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;B-Org&apos; &apos;I-Org&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos;]] || tokens | [[&apos;Mrs.&apos; &apos;Rose&apos; &apos;hired&apos; &apos;Abebe&apos; &apos;Worke&apos; &apos;,&apos; &apos;one&apos; &apos;of&apos; &apos;Ethiopia&apos; &quot;&apos;s&quot; || | &apos;most&apos; &apos;distinguished&apos; &apos;lawyers&apos; &apos;and&apos; &apos;a&apos; &apos;former&apos; &apos;member&apos; &apos;of&apos; &apos;the&apos; || | &apos;country&apos; &quot;&apos;s&quot; &apos;High&apos; &apos;Court&apos; &apos;,&apos; &apos;to&apos; &apos;investigate&apos; &apos;.&apos;]] || BIO | [[&apos;B-Peop&apos; &apos;I-Peop&apos; &apos;O&apos; &apos;B-Peop&apos; &apos;I-Peop&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;B-Loc&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; || | &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;B-Org&apos; &apos;I-Org&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos; &apos;O&apos;]] || tokenIds | [[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 || | 24 25 26]] || scoringMatrixGold | [[[0. 0. 0. ... 0. 0. 0.] || | [0. 0. 0. ... 0. 0. 0.] || | [0. 0. 0. ... 0. 0. 0.] || | ... || | [0. 0. 0. ... 0. 0. 0.] || | [0. 0. 0. ... 0. 0. 0.] || | [0. 0. 0. ... 1. 0. 0.]]] || seqlen | [27] || doc_ids | [&apos;#doc 2050&apos;] |+--------------------------+---------------------------------------------------------------------------+ 12relations = [&apos;Kill&apos;, &apos;Live_In&apos;, &apos;Located_In&apos;, &apos;N&apos;, &apos;OrgBased_In&apos;, &apos;Work_For&apos;]scoringMatrixGold.shape = (1, 27, 162) #(batch_size, sequence_length, sequence_length * relation_numbers) 由原始数据 4 Worke I-Peop [‘Work_For’, ‘Live_In’] [22, 8] 可以知道原始数据第4个token Worke 对应有两个关系分别是与第22个token的Work_For(对应ID是 5) 和第8个token的live_In(对应ID是 1)。如果把 123scoringMatrixGold.shape = (1, 27, 162) #(batch_size, sequence_length, sequence_length * relation_numbers)转换成scoringMatrixGold.shape = (1, 27, 27, 6) #(batch_size, sequence_length, sequence_length, relation_numbers) 那么 scoringMatrixGold 里面的这个 #doc 2050 数据 scoringMatrixGold[0] 的形状是 (27, 27, 6)，第4个token Worke就是 scoringMatrixGold[0][4] ，这是一个形状是 (27, 6) 的关系矩阵，这个矩阵的第8行第1列以及第22行第5列的数字是1，其余是0。这样就用one-hot形式的矩阵编码了实体之间的关系。矩阵的具体内容如下： 12345678910111213141516171819202122232425262728&quot;[&quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 1. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 1. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0. &quot; \&quot;0. 0. 0. 0. 0. 0.]&quot; 说明：由于我们假设基于令牌的编码，我们只考虑实体的最后一个令牌作为另一个令牌的头部，从而消除了冗余关系。 例如，实体“John Smith”和“Disease Control Center”之间存在关联工作。 我们不是连接实体的所有标记，而是仅将“Smith”与“Center”连接起来。 此外，对于没有关系的情况，我们引入“N”标签，我们将令牌本身预测为头部。 Since we assume token-based encoding, we consider only the last token of the entity as head of another token, eliminating redundant relations. For instance, there is a Works for relation between entities “John Smith” and “Disease Control Center”. Instead of connecting all tokens of the entities, we connect only “Smith” with “Center”. Also, for the case of no relation, we introduce the “N” label and we predict the token itself as the head.]]></content>
      <categories>
        <category>论文</category>
        <category>信息抽取</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>实体识别</tag>
        <tag>关系抽取</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Pytorch手册]]></title>
    <url>%2F2019%2F04%2F30%2FPytorch%E6%89%8B%E5%86%8C%2F</url>
    <content type="text"><![CDATA[Pytorch 标题 说明 Pytorch 官网 Pytorch API 文档 PyTorch GitHub pytorch-an-imperative-style-high-performance-deep-learning-library 官方论文 PyTorch 中文教程 Deep Learning with PyTorch PyTorch 官方书籍，代码下载GitHub dlwpt-code pytorch-handbook 开源中文Pytorch教程 pytorch-pretrained-BERT 非常好的使用 Pytorch 写BERT、GPT、Transformer 的范例代码 pytorch-styleguide PyTorch最佳实践，怎样才能写出一手风格优美的代码 PyTorch Cookbook（常用代码段整理合集）]]></content>
      <tags>
        <tag>Artificial Intelligence Navigation</tag>
        <tag>Pytorch手册</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[目标检测]]></title>
    <url>%2F2019%2F04%2F30%2F%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%2F</url>
    <content type="text"><![CDATA[目标检测基础知识目标检测定义目标检测，也叫目标提取，是一种基于目标几何和统计特征的图像分割，它将目标的分割和识别合二为一，其准确性和实时性是整个系统的一项重要能力。尤其是在复杂场景中，需要对多个目标进行实时处理时，目标自动提取和识别就显得特别重要。随着计算机技术的发展和计算机视觉原理的广泛应用，利用计算机图像处理技术对目标进行实时跟踪研究越来越热门，对目标进行动态实时跟踪定位在智能化交通系统、智能监控系统、军事目标检测及医学导航手术中手术器械定位等方面具有广泛的应用价值。 目标检测任务描述 一是分类（Classification），即是将图像结构化为某一类别的信息，用事先确定好的类别(string)或实例ID来描述图片。这一任务是最简单、最基础的图像理解任务，也是深度学习模型最先取得突破和实现大规模应用的任务。其中，ImageNet是最权威的评测集，每年的ILSVRC催生了大量的优秀深度网络结构，为其他任务提供了基础。在应用领域，人脸、场景的识别等都可以归为分类任务。 二是检测（Detection）。分类任务关心整体，给出的是整张图片的内容描述，而检测则关注特定的物体目标，要求同时获得这一目标的类别信息和位置信息。相比分类，检测给出的是对图片前景和背景的理解，我们需要从背景中分离出感兴趣的目标，并确定这一目标的描述（类别和位置），因而，检测模型的输出是一个列表，列表的每一项使用一个数据组给出检出目标的类别和位置（常用矩形检测框的坐标表示）。 三是分割（Segmentation）。分割包括语义分割（semantic segmentation）和实例分割（instance segmentation），前者是对前背景分离的拓展，要求分离开具有不同语义的图像部分，而后者是检测任务的拓展，要求描述出目标的轮廓（相比检测框更为精细）。分割是对图像的像素级描述，它赋予每个像素类别（实例）意义，适用于理解要求较高的场景，如无人驾驶中对道路和非道路的分割。 本系列文章关注的领域是目标检测，即图像理解的中层次。 目标检测论文跟踪 A paper list of object detection using deep learning. Paper list from 2014 to now(2019) 干货 | 目标检测入门，看这篇就够了（已更完）]]></content>
      <categories>
        <category>论文</category>
        <category>目标检测</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>目标检测</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[神经网络资源]]></title>
    <url>%2F2019%2F04%2F29%2F%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E8%B5%84%E6%BA%90%2F</url>
    <content type="text"><![CDATA[神经网络优化策略 标题 说明 时间 神经网络的奥秘之优化器的妙用 介绍了神经网络训练过程中的常见优化策略，并进行了分析和对比，包括梯度下降、小批量梯度下降、动量梯度下降、RMSProp、Adam 等。 20181125 自然语言处理 类型 标题 说明 时间 综述 How to solve 90% of NLP problems: a step-by-step guide 20180105 综述 Lessons Learned from Applying Deep Learning for NLP Without Big Data 小数据上使用深度学习 20181025 资源 Tensorflow实现的深度NLP模型集锦（附资源） 20190429]]></content>
      <categories>
        <category>机器学习</category>
        <category>神经网络</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[目标检测之Libra R-CNN]]></title>
    <url>%2F2019%2F04%2F29%2F%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%E4%B9%8BLibra%20R-CNN%2F</url>
    <content type="text"><![CDATA[Libra R-CNN: Towards Balanced Learning for Object Detection摘要 与模型体系结构相比，训练过程对于检测器的成功也是至关重要的，在对象检测中受到的关注相对较少。在这项工作中，我们仔细地重新审视了探测器的标准训练实践，发现探测性能通常受到训练过程中不平衡的限制，这通常包括三个层次 - 样本水平，特征水平和目标水平。为了减轻由此引起的不利影响，我们提出了Libra R-CNN，这是一个简单但有效的框架，用于物体检测的均衡学习。它集成了三个新颖的组件：IoU平衡采样，平衡特征金字塔和平衡L1损耗，分别用于减少样本，特征和客观水平的不平衡。得益于整体平衡设计，Libra R-CNN显着提高了检测性能。没有花里胡哨，它在MSCOCO上分别比FPN更快的R-CNN和RetinaNet高出2.5分和2.0分的平均精度（AP）。 Abstract Compared with model architectures, the training process, which is also crucial to the success of detectors, has received relatively less attention in object detection. In this work, we carefully revisit the standard training practice of detectors, and find that the detection performance is often limited by the imbalance during the training process, which generally consists in three levels - sample level, feature level, and objective level. To mitigate the adverse effects caused thereby, we propose Libra R-CNN, a simple but effective framework towards balanced learning for object detection. It integrates three novel components: IoU-balanced sampling, balanced feature pyramid, and balanced L1 loss, respectively for reducing the imbalance at sample, feature, and objective level. Benefitted from the overall balanced design, Libra R-CNN significantly improves the detection performance. Without bells and whistles, it achieves 2.5 points and 2.0 points higher Average Precision (AP) than FPN Faster R-CNN and RetinaNet respectively on MSCOCO. 标题 内容 时间 Libra R-CNN: Towards Balanced Learning for Object Detection 原始论文 20190404 mmdetection 论文实现 CVPR 2019 天秤座R-CNN：全面平衡的目标检测器]]></content>
      <categories>
        <category>论文</category>
        <category>目标检测</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>目标检测</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[预训练语言模型（ULMFiT、EMLo和BERT）的核心理论、工具使用、相关论文汇总]]></title>
    <url>%2F2019%2F04%2F22%2F%E9%A2%84%E8%AE%AD%E7%BB%83%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B%EF%BC%88ULMFiT%E3%80%81EMLo%E5%92%8CBERT%EF%BC%89%E7%9A%84%E6%A0%B8%E5%BF%83%E7%90%86%E8%AE%BA%E3%80%81%E5%B7%A5%E5%85%B7%E4%BD%BF%E7%94%A8%E3%80%81%E7%9B%B8%E5%85%B3%E8%AE%BA%E6%96%87%E6%B1%87%E6%80%BB%2F</url>
    <content type="text"><![CDATA[Significance: 预训练语言模型的意义 Instead of training the model from scratch, you can use another pre-trained model as the basis and only fine-tune it to solve the specific NLP task. Using pre-trained models allows you to achieve the same or even better performance much faster and with much less labeled data. Model: 2018 年三个最主要的语言模型 ULMFiT、EMLo和BERT ULMFiT, or Universal Language Model Fine-Tuning method, is likely the first effective approach to fine-tuning the language model. The authors demonstrate the importance of several novel techniques, including discriminative fine-tuning, slanted triangular learning rate, and gradual unfreezing, for retaining previous knowledge and avoiding catastrophic forgetting during fine-tuning. ELMo word representations, or Embeddings from Language Models, are generated in a way to take the entire context into consideration. In particular, they are created as a weighted sum of the internal states of a deep bi-directional language model (biLM), pre-trained on a large text corpus. Furthermore, ELMo representations are based on characters so that the network can understand even out-of-vocabulary tokens unseen in training. BERT, or Bidirectional Encoder Representations from Transformers, is a new cutting-edge model that considers the context from both the left and the right sides of each word. The two key success factors are (1) masking part of input tokens to avoid cycles where words indirectly “see themselves”, and (2) pre-training a sentence relationship model. Finally, BERT is also a very big model trained on a huge word corpus. Tool: 使用三大语言模型的工具 模型 工具 说明 ULMFiT fastai fastai NLP; fastai imdb 例子; Tutorial on Text Classification (NLP) using ULMFiT and fastai Library in Python ELMo allen-ELMo;Google-ELMo ELMo-use-example BERT Google-BERT BERT—use-example Summarie: ULMFiT、EMLo和BERTUNIVERSAL LANGUAGE MODEL FINE-TUNING FOR TEXT CLASSIFICATIONORIGINAL ABSTRACTInductive transfer learning has greatly impacted computer vision, but existing approaches in NLP still require task-specific modifications and training from scratch. We propose Universal Language Model Fine-tuning (ULMFiT), an effective transfer learning method that can be applied to any task in NLP, and introduce techniques that are key for fine-tuning a language model. Our method significantly outperforms the state-of-the-art on six text classification tasks, reducing the error by 18-24% on the majority of datasets. Furthermore, with only 100 labeled examples, it matches the performance of training from scratch on 100x more data. We open source our pretrained models and code. OUR SUMMARYHoward and Ruder suggest using pre-trained models for solving a wide range of NLP problems. With this approach, you don’t need to train your model from scratch, but only fine-tune the original model. Their method, called Universal Language Model Fine-Tuning (ULMFiT) outperforms state-of-the-art results, reducing the error by 18-24%. Even more, with only 100 labeled examples, ULMFiT matches the performance of models trained from scratch on 10K labeled examples. WHAT’S THE CORE IDEA OF THIS PAPER? To address the lack of labeled data and to make NLP classification easier and less time-consuming, the researchers suggest applying transfer learning to NLP problems. Thus, instead of training the model from scratch, you can use another model that has been trained to solve a similar problem as the basis, and then fine-tune the original model to solve your specific problem. However, to be successful, this fine-tuning should take into account several important considerations: Different layers should be fine-tuned to different extents as they capture different kinds of information. Adapting model’s parameters to task-specific features will be more efficient if the learning rate is firstly linearly increased and then linearly decayed. Fine-tuning all layers at once is likely to result in catastrophic forgetting; thus, it would be better to gradually unfreeze the model starting from the last layer. WHAT’S THE KEY ACHIEVEMENT? Significantly outperforming state-of-the-art: reducing the error by 18-24%.Much less labeled data needed: with only 100 labeled examples and 50K unlabeled, matching the performance of learning from scratch on 100x more data. DEEP CONTEXTUALIZED WORD REPRESENTATIONSORIGINAL ABSTRACTWe introduce a new type of deep contextualized word representation that models both (1) complex characteristics of word use (e.g., syntax and semantics), and (2) how these uses vary across linguistic contexts (i.e., to model polysemy). Our word vectors are learned functions of the internal states of a deep bidirectional language model (biLM), which is pre-trained on a large text corpus. We show that these representations can be easily added to existing models and significantly improve the state of the art across six challenging NLP problems, including question answering, textual entailment and sentiment analysis. We also present an analysis showing that exposing the deep internals of the pre-trained network is crucial, allowing downstream models to mix different types of semi-supervision signals. OUR SUMMARYThe team from the Allen Institute for Artificial Intelligence introduces a new type of deep contextualized word representation – Embeddings from Language Models (ELMo). In ELMO-enhanced models, each word is vectorized on the basis of the entire context in which it is used. Adding ELMo to the existing NLP systems results in 1) relative error reduction ranging from 6-20%, 2) a significantly lower number of epochs required to train the models and 3) a significantly reduced amount of training data needed to reach baseline performance. WHAT’S THE CORE IDEA OF THIS PAPER? To generate word embeddings as a weighted sum of the internal states of a deep bi-directional language model (biLM), pre-trained on a large text corpus. To include representations from all layers of a biLM as different layers represent different types of information. To base ELMo representations on characters so that the network can use morphological clues to “understand” out-of-vocabulary tokens unseen in training. WHAT’S THE KEY ACHIEVEMENT? Adding ELMo to the model leads to the new state-of-the-art results, with relative error reductions ranging from 6 – 20% across such NLP tasks as question answering, textual entailment, semantic role labeling, coreference resolution, named entity extraction, and sentiment analysis. Enhancing the model with ELMo results in a significantly lower number of updates required to reach state-of-the-art performance. Thus, the Semantic Role Labeling (SRL) model with ELMo needs only 10 epochs to exceed the baseline maximum reached after 486 epochs of training. Introducing ELMo to the model also significantly reduces the amount of training data needed to achieve the same level of performance. For example, for the SRL task, the ELMo-enhanced model needs only 1% of the training set to achieve the same performance as the baseline model with 10% of the training data. BERT: PRE-TRAINING OF DEEP BIDIRECTIONAL TRANSFORMERS FOR LANGUAGE UNDERSTANDINGORIGINAL ABSTRACTWe introduce a new language representation model called BERT, which stands for Bidirectional Encoder Representations from Transformers. Unlike recent language representation models, BERT is designed to pre-train deep bidirectional representations by jointly conditioning on both left and right context in all layers. As a result, the pre-trained BERT representations can be fine-tuned with just one additional output layer to create state-of-the-art models for a wide range of tasks, such as question answering and language inference, without substantial task-specific architecture modifications. BERT is conceptually simple and empirically powerful. It obtains new state-of-the-art results on eleven natural language processing tasks, including pushing the GLUE benchmark to 80.4% (7.6% absolute improvement), MultiNLI accuracy to 86.7 (5.6% absolute improvement) and the SQuAD v1.1 question answering Test F1 to 93.2 (1.5% absolute improvement), outperforming human performance by 2.0%. OUR SUMMARYA Google AI team presents a new cutting-edge model for Natural Language Processing (NLP) – BERT, or Bidirectional Encoder Representations from Transformers. Its design allows the model to consider the context from both the left and the right sides of each word. While being conceptually simple, BERT obtains new state-of-the-art results on eleven NLP tasks, including question answering, named entity recognition and other tasks related to general language understanding. WHAT’S THE CORE IDEA OF THIS PAPER? Training a deep bidirectional model by randomly masking a percentage of input tokens – thus, avoiding cycles where words can indirectly “see themselves”. Also pre-training a sentence relationship model by building a simple binary classification task to predict whether sentence B immediately follows sentence A, thus allowing BERT to better understand relationships between sentences. Training a very big model (24 Transformer blocks, 1024-hidden, 340M parameters) with lots of data (3.3 billion word corpus). WHAT’S THE KEY ACHIEVEMENT? Advancing the state-of-the-art for 11 NLP tasks, including: getting a GLUE score of 80.4%, which is 7.6% of absolute improvement from the previous best result; achieving 93.2% accuracy on SQuAD 1.1 and outperforming human performance by 2%. Suggesting a pre-trained model, which doesn’t require any substantial architecture modifications to be applied to specific NLP tasks. Paper: 相关论文汇总ULMFiT work was further extended and applied in the following papersImproving Language Understanding by Generative Pre-TrainingAbstract Natural language understanding comprises a wide range of diverse tasks such as textual entailment, question answering, semantic similarity assessment, and document classiﬁcation. Although large unlabeled text corpora are abundant, labeled data for learning these speciﬁc tasks is scarce, making it challenging for discriminatively trained models to perform adequately. We demonstrate that large gains on these tasks can be realized by generative pre-training of a language model on a diverse corpus of unlabeled text, followed by discriminative ﬁne-tuning on each speciﬁc task. In contrast to previous approaches, we make use of task-aware input transformations during ﬁne-tuning to achieve effective transfer while requiring minimal changes to the model architecture. We demonstrate the effectiveness of our approach on a wide range of benchmarks for natural language understanding. Our general task-agnostic model outperforms discriminatively trained models that use architectures speciﬁcally crafted for each task, signiﬁcantly improving upon the state of the art in 9 out of the 12 tasks studied. For instance, we achieve absolute improvements of 8.9% on commonsense reasoning (Stories Cloze Test), 5.7% on question answering (RACE), and 1.5% on textual entailment (MultiNLI). 摘要 自然语言理解包括各种各样的任务，如文本蕴涵，问答，语义相似性评估和文档分类。虽然大量未标记的文本语料库很丰富，但用于学习这些特定任务的标记数据很少，这使得经过充分理解的模式训练模型具有挑战性。我们证明，通过对多种未标记文本语料库中的语言模型进行生成预训练，然后对每个特定任务进行辨别性调整，可以实现这些任务的巨大收益。与以前的方法相比，我们在微调期间利用任务感知输入转换来实现有效传输，同时对模型架构进行最少的更改。我们证明了我们的方法在广泛的自然语言理解基准上的有效性。我们的一般任务不可知模型优于使用针对每项任务专门设计的架构的经过训练的训练模型，在所研究的12项任务中的9项中显着改进了现有技术水平。例如，我们在常识推理（Stories Cloze Test）上获得8.9％的绝对改善，在问答（RACE）上达到5.7％，在文本蕴涵（MultiNLI）上达到1.5％。 Universal Language Model Fine-Tuning with Subword Tokenization for PolishAbstract Universal Language Model for Fine-tuning [arXiv:1801.06146] (ULMFiT) is one of the first NLP methods for efficient inductive transfer learning. Unsupervised pretraining results in improvements on many NLP tasks for English. In this paper, we describe a new method that uses subword tokenization to adapt ULMFiT to languages with high inflection. Our approach results in a new state-of-the-art for the Polish language, taking first place in Task 3 of PolEval’18. After further training, our final model outperformed the second best model by 35%. We have open-sourced our pretrained models and code. 摘要 用于微调的通用语言模型[arXiv：1801.06146]（ULMFiT）是有效的归纳转移学习的第一种NLP方法之一。 无人监督的预训练可以改善英语的许多NLP任务。 在本文中，我们描述了一种新方法，该方法使用子词标记化来使ULMFiT适应具有高度变形的语言。 我们的方法为波兰语创造了一种新的先进技术，在PolEval’18的任务3中占据首位。 经过进一步培训，我们的最终模型比第二好的模型高出35％。 我们开源了我们的预训练模型和代码。 Universal Language Model Fine-tuning for Patent ClassificationAbstract This paper describes the methods used for the 2018 ALTA Shared Task. The task this year was to automatically classify Australian patents into their main International Patent Classiﬁcation section. Our ﬁnal submission used a Support Vector Machine (SVM) and Universal Language Model with Fine-tuning (ULMFiT). Our system achieved the best results in the student category. 摘要 本文介绍了2018年ALTA共享任务使用的方法。 今年的任务是自动将澳大利亚专利分类为其主要的国际专利分类部分。 我们的最终提交使用支持向量机（SVM）和具有微调的通用语言模型（ULMFiT）。 我们的系统在学生类别中取得了最佳成绩。 ELMo embeddings have been already used in a number of important research papers includingLinguistically-Informed Self-Attention for Semantic Role LabelingAbstract Current state-of-the-art semantic role labeling (SRL) uses a deep neural network with no explicit linguistic features. However, prior work has shown that gold syntax trees can dramatically improve SRL decoding, suggesting the possibility of increased accuracy from explicit modeling of syntax. In this work, we present linguistically-informed self-attention (LISA): a neural network model that combines multi-head self-attention with multi-task learning across dependency parsing, part-of-speech tagging, predicate detection and SRL. Unlike previous models which require significant pre-processing to prepare linguistic features, LISA can incorporate syntax using merely raw tokens as input, encoding the sequence only once to simultaneously perform parsing, predicate detection and role labeling for all predicates. Syntax is incorporated by training one attention head to attend to syntactic parents for each token. Moreover, if a high-quality syntactic parse is already available, it can be beneficially injected at test time without re-training our SRL model. In experiments on CoNLL-2005 SRL, LISA achieves new state-of-the-art performance for a model using predicted predicates and standard word embeddings, attaining 2.5 F1 absolute higher than the previous state-of-the-art on newswire and more than 3.5 F1 on out-of-domain data, nearly 10% reduction in error. On ConLL-2012 English SRL we also show an improvement of more than 2.5 F1. LISA also out-performs the state-of-the-art with contextually-encoded (ELMo) word representations, by nearly 1.0 F1 on news and more than 2.0 F1 on out-of-domain text. 摘要当前最先进的语义角色标记（SRL）使用深度神经网络，没有明确的语言特征。但是，之前的工作表明，黄金语法树可以显着改善SRL解码，这表明通过显式语法建模可以提高准确性。在这项工作中，我们提出了语言知情的自我关注（LISA）：一种神经网络模型，它将多头自我关注与多任务学习相结合，包括依赖解析，词性标注，谓词检测和SRL。与先前需要大量预处理来准备语言特征的模型不同，LISA可以仅使用原始令牌作为输入来合并语法，仅对序列编码一次以同时对所有谓词执行解析，谓词检测和角色标记。语法通过训练一个注意力头来参与每个令牌的句法父母。此外，如果已经有高质量的语法分析，则可以在测试时进行有益的注入，而无需重新训练我们的SRL模型。在CoNLL-2005 SRL的实验中，LISA使用预测谓词和标准字嵌入为模型实现了最新的最先进性能，比新闻专线上的先前技术水平高出2.5 F1绝对值3.5关于域外数据的F1，误差减少近10％。在ConLL-2012英语SRL上，我们也表现出超过2.5 F1的改进。 LISA还通过上下文编码（ELMo）单词表示超出了最新技术水平，在新闻上接近1.0 F1，在域外文本上超过2.0 F1。 Language Model Pre-training for Hierarchical Document RepresentationsAbstract Hierarchical neural architectures are often used to capture long-distance dependencies and have been applied to many document-level tasks such as summarization, document segmentation, and sentiment analysis. However, effective usage of such a large context can be difficult to learn, especially in the case where there is limited labeled data available. Building on the recent success of language model pretraining methods for learning flat representations of text, we propose algorithms for pre-training hierarchical document representations from unlabeled data. Unlike prior work, which has focused on pre-training contextual token representations or context-independent {sentence/paragraph} representations, our hierarchical document representations include fixed-length sentence/paragraph representations which integrate contextual information from the entire documents. Experiments on document segmentation, document-level question answering, and extractive document summarization demonstrate the effectiveness of the proposed pre-training algorithms. 摘要 分层神经架构通常用于捕获长距离依赖关系，并已应用于许多文档级任务，如摘要，文档分段和情感分析。然而，这种大的上下文的有效使用可能难以学习，尤其是在可用的标记数据有限的情况下。在最近成功学习用于学习文本平面表示的语言模型预训练方法的基础上，我们提出了用于从未标记数据预训练分层文档表示的算法。与先前的工作不同，后者专注于预训练上下文令牌表示或与上下文无关的{句子/段落}表示，我们的分层文档表示包括固定长度的句子/段落表示，其整合来自整个文档的上下文信息。文档分割，文档级问答和提取文档摘要的实验证明了所提出的预训练算法的有效性。 Deep Enhanced Representation for Implicit Discourse Relation RecognitionAbstract Implicit discourse relation recognition is a challenging task as the relation prediction without explicit connectives in discourse parsing needs understanding of text spans and cannot be easily derived from surface features from the input sentence pairs. Thus, properly representing the text is very crucial to this task. In this paper, we propose a model augmented with different grained text representations, including character, subword, word, sentence, and sentence pair levels. The proposed deeper model is evaluated on the benchmark treebank and achieves state-of-the-art accuracy with greater than 48% in 11-way and F1 score greater than 50% in 4-way classifications for the first time according to our best knowledge. 摘要 隐含话语关系识别是一项具有挑战性的任务，因为在话语分析中没有明确连接词的关系预测需要理解文本跨度，并且不能容易地从输入句子对的表面特征中导出。 因此，正确表示文本对于这项任务至关重要。 在本文中，我们提出了一个增加了不同粒度文本表示的模型，包括字符，子字，单词，句子和句子对等级。 根据我们的最佳知识，所提出的更深层次模型在基准树库上进行评估并达到最先进的准确度，11路方式超过48％，4路分类中F1分数首次超过50％。 BERT was introduced only in late 2018 but has been already a basis for some further research advancementsA BERT Baseline for the Natural QuestionsAbstract This technical note describes a new baseline for the Natural Questions. Our model is based on BERT and reduces the gap between the model F1 scores reported in the original dataset paper and the human upper bound by 30% and 50% relative for the long and short answer tasks respectively. This baseline has been submitted to the official NQ leaderboard at this http URL. Code, preprocessed data and pretrained model are available at this https URL. 摘要 本技术说明描述了自然问题的新基线。 我们的模型基于BERT，并且将原始数据集论文中报告的模型F1分数与人类上限之间的差距分别缩小了30％和50％相对于长期和短期答案任务。 此基线已通过此http URL提交给官方NQ排行榜。 此https URL提供代码，预处理数据和预训练模型。 SDNet: Contextualized Attention-based Deep Network for Conversational Question AnsweringAbstract Conversational question answering (CQA) is a novel QA task that requires understanding of dialogue context. Different from traditional single-turn machine reading comprehension (MRC) tasks, CQA includes passage comprehension, coreference resolution, and contextual understanding. In this paper, we propose an innovated contextualized attention-based deep neural network, SDNet, to fuse context into traditional MRC models. Our model leverages both inter-attention and self-attention to comprehend conversation context and extract relevant information from passage. Furthermore, we demonstrated a novel method to integrate the latest BERT contextual model. Empirical results show the effectiveness of our model, which sets the new state of the art result in CoQA leaderboard, outperforming the previous best model by 1.6% F1. Our ensemble model further improves the result by 2.7% F1. 摘要 会话问答（CQA）是一项新颖的QA任务，需要了解对话背景。 与传统的单圈机器阅读理解（MRC）任务不同，CQA包括段落理解，共指解析和情境理解。 在本文中，我们提出了一种创新的基于情境的注重深度神经网络SDNet，将背景融合到传统的MRC模型中。 我们的模型利用相互关注和自我关注来理解对话背景并从段落中提取相关信息。 此外，我们演示了一种集成最新BERT上下文模型的新方法。 实证结果显示我们的模型的有效性，它在CoQA排行榜中设定了新的最新状态，比之前的最佳模型优于1.6％的F1。 我们的整体模型进一步提高了2.7％的F1结果。 Extracting Multiple-Relations in One-Pass with Pre-Trained TransformersAbstract Most approaches to extraction multiple relations from a paragraph require multiple passes over the paragraph. In practice, multiple passes are computationally expensive and this makes difficult to scale to longer paragraphs and larger text corpora. In this work, we focus on the task of multiple relation extraction by encoding the paragraph only once (one-pass). We build our solution on the pre-trained self-attentive (Transformer) models, where we first add a structured prediction layer to handle extraction between multiple entity pairs, then enhance the paragraph embedding to capture multiple relational information associated with each entity with an entity-aware attention technique. We show that our approach is not only scalable but can also perform state-of-the-art on the standard benchmark ACE 2005. 摘要 从段落中提取多个关系的大多数方法都要求在段落上多次传递。 在实践中，多次通过在计算上是昂贵的，并且这使得难以扩展到更长的段落和更大的文本语料库。 在这项工作中，我们通过仅对段落进行一次编码（一次通过）来专注于多关系提取的任务。 我们在预训练的自我关注（Transformer）模型上构建我们的解决方案，我们首先添加结构化预测层来处理多个实体对之间的提取，然后增强段落嵌入以捕获与每个实体关联的多个关系信息与实体 - 注意技术。 我们表明，我们的方法不仅可扩展，而且还可以在标准基准ACE 2005上执行最先进的技术。 标题 说明 时间 WHAT EVERY NLP ENGINEER NEEDS TO KNOW ABOUT PRE-TRAINED LANGUAGE MODELS 本文主要内容基于该文 Feb 19, 2019]]></content>
      <categories>
        <category>论文</category>
        <category>语言模型</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>语言模型</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Robust Chinese Word Segmentation with Contextualized Word Representations]]></title>
    <url>%2F2019%2F04%2F22%2FRobust%20Chinese%20Word%20Segmentation%20with%20Contextualized%20Word%20Representations%2F</url>
    <content type="text"><![CDATA[标题 说明 时间 Robust Chinese Word Segmentation with Contextualized Word Representations 论文原文 20190117 pywordseg 论文实现 Open Source State-of-the-art Chinese Word Segmentation System with BiLSTM and ELMo. 20190120 Robust Chinese Word Segmentation with Contextualized Word Representations摘要In recent years, after the neural-network-based method was proposed, the accuracy of the Chinese word segmentation task has made great progress. However, when dealing with out-of-vocabulary words, there is still a large error rate. We used a simple bidirectional LSTM architecture and a large-scale pretrained language model to generate high-quality contextualize character representations, which successfully reduced the weakness of the ambiguous meanings of each Chinese character that widely appears in Chinese characters, and hence effectively reduced OOV error rate. State-of-the-art performance is achieved on many datasets. 摘要近年来，在提出基于神经网络的方法后，中文分词任务的准确性取得了很大进展。 但是，在处理词汇外单词时，仍然存在较大的错误率。 我们使用简单的双向LSTM架构和大规模预训练语言模型来生成高质量的语境化字符表示，成功地减少了汉字中广泛出现的每个汉字的歧义的弱点，从而有效地减少了OOV误差率。 在许多数据集上实现了最先进的性能。 模型结构]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>分词</tag>
        <tag>ELMo</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[目标检测之YOLO]]></title>
    <url>%2F2019%2F04%2F20%2F%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B%E4%B9%8BYOLO%2F</url>
    <content type="text"><![CDATA[YOLO: You Only Look OnceYOLOv3: An Incremental Improvement We present some updates to YOLO! We made a bunch of little design changes to make it better. We also trained this new network that’s pretty swell. It’s a little bigger than last time but more accurate. It’s still fast though, don’t worry. At 320x320 YOLOv3 runs in 22 ms at 28.2 mAP, as accurate as SSD but three times faster. When we look at the old .5 IOU mAP detection metric YOLOv3 is quite good. It achieves 57.9 mAP@50 in 51 ms on a Titan X, compared to 57.5 mAP@50 in 198 ms by RetinaNet, similar performance but 3.8x faster. As always, all the code is online at this https URL. Darknet Convolutional Neural Networks http://pjreddie.com/darknet/ Darknet is an open source neural network framework written in C and CUDA. It is fast, easy to install, and supports CPU and GPU computation. 标题 内容 时间 You Only Look Once: Unified, Real-Time Object Detection YOLOV1 20150608 stone: YOLO V1 V2 X-猪: YOLO v1 v2 v3 深入理解 20181113 目标检测网络之 YOLO]]></content>
      <categories>
        <category>论文</category>
        <category>目标检测</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>目标检测</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[论文世界]]></title>
    <url>%2F2019%2F04%2F19%2F%E8%AE%BA%E6%96%87%E4%B8%96%E7%95%8C%2F</url>
    <content type="text"><![CDATA[arxivopenreview最佳模型跟踪会议相关工具 标题 类型 补充 会伴：计算机最新国际会议和期刊列表 会议信息查询网站 自然语言处理会议和期刊 计算机科学各个方向有哪些顶刊和顶会？ CCF 推荐会议和期刊 标题 说明 补充 Transactions of the Association for Computational Linguistics 简称TACL，计算语言学协会(TACL)是美国计算机学会主办的期刊 论文实现目录 Paper with code 自然语言处理教程nlp-tutorial Natural Language Processing Tutorial for Deep Learning Researchers 自然语言处理进展NLP-progress用于跟踪自然语言处理（NLP）进度的存储库，包括数据集和最常见的NLP任务的当前最新技术。https://nlpprogress.com/NLP-progress 的中文翻译（翻译至20180624）自然语言处理全家福：纵览当前 NLP 中的任务、数据、模型与论文 Google seed bank 交互式机器学习示例的集合 我目前关注Dependency parsingSemi-Supervised Sequence Modeling with Cross-View Training codeword2vec和ELMo等无监督表示学习算法提高了许多有监督NLP模型的准确性，主要是因为它们可以利用大量的无标记文本。然而，监督模型只在主要训练阶段从特定于任务的标记数据中学习。因此，我们提出了交叉视图训练(CVT)，这是一种半监督学习算法，它使用标记和未标记数据的混合来改进双lstm语句编码器的表示。在标注的例子中，使用了标准监督学习。在没有标记的例子中，CVT教授助动词。 Adversarial Text Classification Cross-Target Stance Classification with Self-Attention Networks 在观点分类中，观点所基于的目标定义了任务的边界，通常训练分类器对同一目标进行预测。在这项工作中，我们探索了在不同目标之间泛化分类器的潜力，并提出了一个神经模型，可以将从源目标中学到的东西应用到目标目标。结果表明，该模型能够发现相关目标之间共享的有用信息，提高了模型的泛化能力。 论文中描述 CrossNet 这个模型的方法值得借鉴，一步一步描述很清晰。 An improved neural network model for joint POS tagging and dependency parsing 这个名字可以参考。]]></content>
      <categories>
        <category>论文</category>
      </categories>
      <tags>
        <tag>论文</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[如何做好文本分类]]></title>
    <url>%2F2019%2F04%2F10%2F%E5%A6%82%E4%BD%95%E5%81%9A%E5%A5%BD%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%2F</url>
    <content type="text"><![CDATA[Quora Insincere Questions Classification Detect toxic content to improve online conversations Rahul Agarwal: NLP Text classification series 标题 内容 Prat1 Text Preprocessing Methods for Deep Learning This one will be based on preprocessing techniques that work with Deep learning models and we will also talk about increasing embeddings coverage. Prat2 Conventional Methods for Text Classification In this post, I will try to take you through some basic conventional models like TFIDF, Count Vectorizer, Hashing etc. that have been used in text classification and try to access their performance to create a baseline. Prat3 Attention, CNN and what not for Text Classification In this post, I delve deeper into Deep learning models and the various architectures we could use to solve the text Classification problem. To make this post platform generic, I am going to code in both Keras and Pytorch. Prat4 Transfer Learning Intuition for Text Classification In this post, I will try to use ULMFit model which is a transfer learning approach for NLP. What Kagglers are using for Text Classification]]></content>
      <categories>
        <category>实验</category>
      </categories>
      <tags>
        <tag>文本分类</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[论文写作方法与工具]]></title>
    <url>%2F2019%2F04%2F08%2F%E8%AE%BA%E6%96%87%E5%86%99%E4%BD%9C%E6%96%B9%E6%B3%95%E4%B8%8E%E5%B7%A5%E5%85%B7%2F</url>
    <content type="text"><![CDATA[论文工具 标题 类型 补充 谷歌学术 百度学术 国内版谷歌学术 亿图图示 论文画图 亿图图示和Visio画流程图哪个更好用？ mendeley 文献管理工具 Mendeley初步使用说明 grammarly 语法检查工具 overleaf LATEX 写作 论文写作工具 overleaf写作，如何输入中文？ Texstudio 论文写作工具 latex编辑器 引文格式查询 论文写作工具 LetPub论文润色 论文润色网站 clarivate: Master Journal List 主流期刊查询 会伴：计算机最新国际会议和期刊列表 会议信息查询网站 中国计算机协会CCF 中国计算机学会推荐国际学术会议和期刊目录-2019 论文阅读 标题 类型 补充 一文教你如何快速高效阅读Paper（硕士生版） 论文写作 标题 补充 你发表第一篇英文 SCI 论文经历了怎样的过程？ 清华大学刘知远：如何写一篇合格的NLP论文 论文举例 Denoising Distantly Supervised Open-Domain Question Answering 刘洋:机器翻译学术论文写作方法和技巧 PPT 写作范文 标题 补充 Denoising Distantly Supervised Open-Domain Question Answering 清华大学刘知远：解读如何写这篇范文 A Self-Attentive Model with Gate Mechanism for Spoken Language Understanding 非常标准的一篇NLP论文 Slot-Gated Modeling for Joint Slot Filling and Intent Prediction 5页写出NAACL 论文写作笔记清华大学刘知远：如何写一篇合格的NLP论文 论文在 NLP 学术研究中的意义NLP 是一门重视实践和应用的领域，创新成果可以是新的算法、任务、应用、数据、发现等，务求一个「新」字，其影响力则取决于它对该领域发展的推动作用。如下图所示，学术研究是一项系统工程，包括多个环节，共同完成对「创新」的追求：问题务求挑战，模型务求创新，实现务求准确，实验务求深入。 学术研究是一项系统工程论文的作用是向学术界同行清晰准确地描述成果的创新点、技术思路、算法细节和验证结果。由于学术界的同行评审制度，贯穿全文的线索和目标就是要论证这份工作的创新价值，每个部分都要各司其职为这个目标而服务。 一篇 NLP 论文的典型结构 摘要：用 100-200 词简介研究任务与挑战、解决思路与方法、实验效果与结论。 介绍：用 1 页左右篇幅，比摘要更详细地介绍研究任务、已有方法、主要挑战、解决思路、具体方法、实验结果。 相关工作：用 0.5-1 页左右篇幅介绍研究任务的相关工作，说明本文工作与已有工作的异同。 方法：用 2-3 页篇幅介绍本文提出的方法模型细节。 实验：用 2-3 页篇幅介绍验证本文方法有效性的实验设置、数据集合、实验结果、分析讨论等。 结论：简单总结本文主要工作，展望未来研究方向。 写作习俗In this paper we follow the convention of using lowercase italic letters for scalars and indices, lowercase bold letters for vectors, uppercase italic letters for matrices, uppercase bold letters for higher order tensors. from]]></content>
      <categories>
        <category>论文</category>
        <category>论文写作</category>
      </categories>
      <tags>
        <tag>论文</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[槽填充和意图识别任务的基本概念]]></title>
    <url>%2F2019%2F03%2F18%2F%E6%A7%BD%E5%A1%AB%E5%85%85%E5%92%8C%E6%84%8F%E5%9B%BE%E8%AF%86%E5%88%AB%E4%BB%BB%E5%8A%A1%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5%2F</url>
    <content type="text"><![CDATA[槽填充和意图识别任务的基本概念 Their objective is to identify the intention of the user and the parameters of the query. The developer can then use this to determine the appropriate action or response. cite 以 snips-nlu 为例讲解开关灯和控制房间温度的例子 查询航班的例子 把上面的例子分析一下，可知道句子中词语与槽名称、实体名和意图之间的关系，如下图所示。 槽、意图、实体的基本信息和定义 把这些内容写成 yaml 文件的形式： 它们之间的关系是： 用图来表达它们之间的关系： 以论文 Snips Voice Platform: an embedded Spoken Language Understanding system for private-by-design voice interfaces 讲解基本概念口语理解、技能、意图、槽和语音助手基本概念The Snips ecosystem comprises a web console to build voice assistants and train the corresponding Spoken Language Understanding (SLU) engine, made of an Automatic Speech Recognition (ASR) engine and a Natural Language Understanding (NLU) engine. An assistant is composed of a set of skills – e.g. SmartLights, SmartThermostat, or SmartOven skills for a SmartHome assistant – that may be either selected from preexisting ones in a skill store or created from scratch on the web console. A given skill may contain several intents, or user intention – e.g. SwitchLightOn and SwitchLightOff for a SmartLights skill. Finally, a given intent is bound to a list of entities that must be extracted from the user’s query – e.g. room for the SwitchLightOn intent. We call slot the particular value of an entity in a query – e.g. kitchen for the entity room. When a user speaks to the assistant, the SLU engine trained on the different skills will handle the request by successively converting speech into text, classifying the user’s intent, and extracting the relevant slots. Once the user’s request has been processed and based on the information that has been extracted from the query and fed to the device, a dialog management component is responsible for providing a feedback to the user, or performing an action. It may take multiple forms, such as an audio response via speech synthesis or a direct action on a connected device – e.g. actually turning on the lights for a SmartLights skill. Figure 1 illustrates the typical interaction ﬂow. 口语理解引擎SLU engines are usually broken down into two parts: Automatic Speech Recognition (ASR) and Natural Language Understanding (NLU). The ASR engine translates a spoken utterance into text through an acoustic model, mapping raw audio to a phonetic representation, and a Language Model (LM), mapping this phonetic representation to text. The NLU then extracts intent and slots from the decoded query. As discussed in section 3, LM and NLU have to be mutually consistent in order to optimize the accuracy of the SLU engine. It is therefore useful to introduce a language modeling component composed of the LM and NLU. Figure 2 describes the building blocks of the SLU pipeline. 自然语言理解The Natural Language Understanding component of the Snips Voice Platform extracts structured data from queries written in natural language. Snips NLU – a Python library – can be used for training and inference, with a Rust implementation focusing solely on inference. Both have been recently open-sourced [50, 49]. Three tasks are successively performed. Intent Classiﬁcation consists in extracting the intent expressed in the query (e.g. SetTemperature or SwitchLightOn). Once the intent is known, Slot Filling aims to extract the slots, i.e. the values of the entities present in the query. Finally, Entity Resolution focuses on built-in entities, such as date and times, durations, temperatures, for which Snips provides an extra resolution step. It basically transforms entity values such as “tomorrow evening” into formatted values such as “2018-04-19 19:00:00 +00:00”. Snippet 1 illustrates a typical output of the NLU component. 更多内容见GitHub资源 槽填充、意图预测（口语理解）论文整理和中文翻译]]></content>
      <categories>
        <category>深度学习</category>
        <category>口语理解</category>
      </categories>
      <tags>
        <tag>意图识别</tag>
        <tag>槽填充</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[槽填充和意图识别任务相关论文发展脉络]]></title>
    <url>%2F2019%2F03%2F16%2F%E6%A7%BD%E5%A1%AB%E5%85%85%E5%92%8C%E6%84%8F%E5%9B%BE%E8%AF%86%E5%88%AB%E4%BB%BB%E5%8A%A1%E7%9B%B8%E5%85%B3%E8%AE%BA%E6%96%87%E5%8F%91%E5%B1%95%E8%84%89%E7%BB%9C%2F</url>
    <content type="text"><![CDATA[GitHub 槽填充和意图识别任务仓库slot-filling 标题 说明 时间 snips-nlu Snips NLU（自然语言理解）是一个Python库，允许解析用自然语言编写的句子并提取结构化信息。主要针对意图识别和槽填充任务，结合了深度学习和特征工程方法，且有对智能家居领域的应用示例 DeepPavlov 用于深度学习端到端对话系统和聊天机器人的开源库。 intent最新槽填充和意图识别任务相关论文https://paperswithcode.com/task/slot-fillinghttps://paperswithcode.com/task/intent-classificationhttps://github.com/AtmaHou/Task-Oriented-Dialogue-Dataset-Surveyhttps://github.com/sz128/slot_filling_and_intent_detection_of_SLU 论文任务信息汇总 论文标题 时间 领域预测 意图预测 槽填充 Deep belief nets for natural language call-routing 2011 √ Towards Deeper Understanding Deep Convex Networks for Semantic Utterance Classification 2012 √ Towards Deeper Understanding Deep Convex Networks for Semantic Utterance Classification 2012 √ Use of Kernel Deep Convex Networks and End-To-End Learning for Spoken Language Understanding 2012 √ Deep belief network based semantic taggers for spoken language understanding 2013 √ Recurrent Neural Networks for Language Understanding 2013 √ Investigation of Recurrent-Neural-Network Architectures and Learning Methods for Spoken Language Understanding 2013 √ Convolutional neural network based triangular crf for joint intent detection and slot filling 2013 √ √ Application of deep belief networks for natural language understanding 2014 √ Joint semantic utterance classification and slot filling with recursive neural networks 2014 √ √ Recurrent neural network and LSTM models for lexical utterance classification 2015 √ Multi-Domain Joint Semantic Frame Parsing using Bi-directional RNN-LSTM 2016 √ √ √ Attention-Based Recurrent Neural Network Models for Joint Intent Detection and Slot Filling 2016 √ √ Multi-Domain Joint Semantic Frame Parsing using Bi-directional RNN-LSTM 2016 √ √ Slot-Gated Modeling for Joint Slot Filling and Intent Prediction 2018 √ √ Unsupervised Transfer Learning for Spoken Language Understanding in Intelligent Agents 2018 √ √ Joint Slot Filling and Intent Detection via Capsule Neural Networks 2018 √ √ Improving Slot Filling in Spoken Language Understanding with Joint Pointer and Attention 2018 √ √ BERT for Joint Intent Classification and Slot Filling 2019 √ √ Multi-Task Networks With Universe, Group, and Task Feature Learning 2019 √ √ A Novel Bi-directional Interrelated Model for Joint Intent Detection and Slot Filling 2019 √ √ (Sarikaya, Ruhi et al., 2011) Deep belief nets for natural language call-routing评价deep belief networks (DBNs) with deep neural networks (DNNs) have first been employed for intent determination in call centers Deep belief nets for natural language call-routing 引用信息Sarikaya, Ruhi et al. “Deep belief nets for natural language call-routing.” 2011 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP) (2011): 5680-5683. 标题 说明 时间 Deep belief nets for natural language call-routing (Tür, Gökhan et al., 2012) Towards Deeper Understanding Deep Convex Networks for Semantic Utterance Classification引用信息Tür, Gökhan et al. “Towards deeper understanding: Deep convex networks for semantic utterance classification.” 2012 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP) (2012): 5045-5048. 标题 说明 时间 Towards Deeper Understanding Deep Convex Networks for Semantic Utterance Classification 201203 (Deng, Li et al., 2012) Use of Kernel Deep Convex Networks and End-To-End Learning for Spoken Language Understanding引用信息Deng, L., Tür, G., He, X. &amp; Hakkani-Tür, D. Z. (2012). Use of kernel deep convex networks and end-to-end learning for spoken language understanding.. SLT (p./pp. 210-215), : IEEE. ISBN: 978-1-4673-5125-6 标题 说明 时间 Use of Kernel Deep Convex Networks and End-To-End Learning for Spoken Language Understanding (P. Xu and R. Sarikaya, 2013) Convolutional neural network based triangular crf for joint intent detection and slot filling引用信息 P. Xu and R. Sarikaya, “Convolutional neural network based triangular crf for joint intent detection and slot filling,” in Au- tomatic Speech Recognition and Understanding (ASRU), 2013 IEEE Workshop on. IEEE, 2013, pp. 78–83 摘要 我们描述了基于卷积神经网络（CNN）的意图检测和槽填充的联合模型。所提出的架构可以被视为三角形CRF模型（TriCRF）的神经网络（NN）版本，其中内部标签和槽序列被联合建模并且它们的依赖性被利用。我们的槽填充组件是全局标准化的CRF样式模型，而不是最近基于NN的槽标记器中的从左到右模型。其功能通过CNN层自动提取并由意图模型共享。我们展示了我们的槽模型组件可以生成最先进的结果，显着优于CRF。对于意图和槽，我们的联合模型优于标准TriCRF 1％绝对值。在许多其他领域，我们的联合模型分别比意图和槽的独立建模方法实现0.7-1％和0.9-2.1％的绝对增益。 TriCRF 模型 标题 说明 时间 Convolutional neural network based triangular crf for joint intent detection and slot filling (Deoras, Anoop and Ruhi Sarikaya, 2013) Deep belief network based semantic taggers for spoken language understanding引用信息Deoras, Anoop and Ruhi Sarikaya. “Deep belief network based semantic taggers for spoken language understanding.” INTERSPEECH (2013).|标题|说明|时间||-|-|-||Deep belief network based semantic taggers for spoken language understanding||| (Yao, Kaisheng et al., 2013) Recurrent Neural Networks for Language Understanding引用信息Yao, Kaisheng et al. “Recurrent neural networks for language understanding.” INTERSPEECH (2013).|标题|说明|时间||-|-|-||Recurrent Neural Networks for Language Understanding||| (Mesnil, Grégoire et al., 2013) Investigation of Recurrent-Neural-Network Architectures and Learning Methods for Spoken Language Understanding引用信息Mesnil, Grégoire et al. “Investigation of recurrent-neural-network architectures and learning methods for spoken language understanding.” INTERSPEECH (2013).|标题|说明|时间||-|-|-||Investigation of Recurrent-Neural-Network Architectures and Learning Methods for Spoken Language Understanding||| (R. Sarikaya et al., 2014) Application of deep belief networks for natural language understanding引用信息R. Sarikaya, G. E. Hinton, and A. Deoras, “Application of deep belief networks for natural language understanding,” IEEE Trans- actions on Audio, Speech, and Language Processing, vol. 22, no. 4, April 2014. 标题 说明 时间 Application of deep belief networks for natural language understanding (D. Guo, 2014) Joint semantic utterance classification and slot filling with recursive neural networks引用信息D. Guo, G. Tur, W.-t. Yih, and G. Zweig, “Joint semantic ut- terance classification and slot filling with recursive neural net- works,” in Spoken Language Technology Workshop (SLT), 2014 IEEE. IEEE, 2014, pp. 554–559. 摘要 近年来，连续空间模型已被证明在从复述检测到语言建模的语言处理任务中非常有效。这些模型的独特之处在于它们通过连续空间表示实现泛化的能力，以及通过对这些表示进行算术运算的组合性。此类模型的示例包括前馈和反复神经网络语言模型。递归神经网络（RecNNs）通过提供一种优雅的机制来扩展这个框架，该机制将离散的句法结构和连续空间的单词和短语表示结合到一个强大的组合模型中。在本文中，我们展示了RecNNs可用于在一个联合训练的模型中，在口语对话系统中执行核心语言理解（SLU）任务，更具体的域和意图确定，与槽填充同时进行。我们发现一个非常简单的RecNN模型在基准ATIS任务以及Microsoft Cortana会话理解任务上实现了竞争性能。 标题 说明 时间 Joint semantic utterance classification and slot filling with recursive neural networks (Ravuri, Suman V. and Andreas Stolcke., 2015) Recurrent neural network and LSTM models for lexical utterance classification引用信息Ravuri, Suman V. and Andreas Stolcke. “Recurrent neural network and LSTM models for lexical utterance classification.” INTERSPEECH (2015). 标题 说明 时间 Recurrent neural network and LSTM models for lexical utterance classification Mining user intentions from medical queries: A neural network based heterogeneous jointly modeling approach 标题 说明 时间 Mining user intentions from medical queries: A neural network based heterogeneous jointly modeling approach (Liu and Lane, 2016) Attention-Based Recurrent Neural Network Models for Joint Intent Detection and Slot Filling Attention-based encoder-decoder neural network models have recently shown promising results in machine translation and speech recognition. In this work, we propose an attention-based neural network model for joint intent detection and slot filling, both of which are critical steps for many speech understanding and dialog systems. Unlike in machine translation and speech recognition, alignment is explicit in slot filling. We explore different strategies in incorporating this alignment information to the encoder-decoder framework. Learning from the attention mechanism in encoder-decoder model, we further propose introducing attention to the alignment-based RNN models. Such attentions provide additional information to the intent classification and slot label prediction. Our independent task models achieve state-of-the-art intent detection error rate and slot filling F1 score on the benchmark ATIS task. Our joint training model further obtains 0.56% absolute (23.8% relative) error reduction on intent detection and 0.23% absolute gain on slot filling over the independent task models. 摘要 基于注意力的编码器-解码器神经网络模型最近在机器翻译和语音识别方面显示出了良好的效果。在这项工作中，我们提出了一个基于注意力的神经网络模型，用于联合意图检测和槽填充，这两个都是许多语音理解和对话系统的关键步骤。与机器翻译和语音识别不同，槽填充中的对齐是显式的。我们探讨了在编码器-解码器框架中合并这种对齐信息的不同策略。从编码器-解码器模型的注意机制入手，进一步提出了基于对齐的RNN模型的注意问题。这些关注为分类正确率和槽标签预测提供了额外的信息。我们的独立任务模型在基准ATIS任务上实现了最先进的意图检测错误率和填槽F1分数。我们的联合训练模型在意图检测上进一步得到了0.56%的绝对误差(相对误差23.8%)，在独立任务模型上得到了0.23%的槽填充绝对误差。 IntroductionSpoken language understanding (SLU) system is a critical component in spoken dialogue systems. SLU system typically involves identifying speaker’s intent and extracting semantic constituents from the natural language query, two tasks that are often referred to as intent Detection and slot filling. Intent detection and slot filling are usually processed separately. Intent detection can be treated as a semantic utterance classification problem, and popular classifiers like support vector machines (SVMs) [1] and deep neural network methods [2] can be applied. Slot filling can be treated as a sequence labeling task. Popular approaches to solving sequence labeling problems include maximum entropy Markov models (MEMMs) [3], conditional random fields (CRFs) [4], and recurrent neural networks (RNNs) [5, 6, 7]. Joint model for intent detection and slot filling has also been proposed in literature [8, 9]. Such joint model simplifies the SLU system, as only one model needs to be trained and fine-tuned for the two tasks. Recently, encoder-decoder neural network models have been successfully applied in many sequence learning problems such as machine translation [10] and speech recognition [11]. The main idea behind the encoder-decoder model is to encode input sequence into a dense vector, and then use this vector to generate corresponding output sequence. The attention mechanism introduced in [12] enables the encoder-decoder architecture to learn to align and decode simultaneously. In this work, we investigate how an SLU model can benefit from the strong modeling capacity of the sequence models. Attention-based encoder-decoder model is capable of mapping sequences that are of different lengths when no alignment information is given. In slot filling, however, alignment is explicit, and thus alignment-based RNN models typically work well. We would like to investigate the combination of the attention-based and alignment-based methods. Specifically, we want to explore how the alignment information in slot filling can be best utilized in the encoder-decoder models, and on the other hand, whether the alignment-based RNN slot filling models can be further improved with the attention mechanism that introduced from the encoder-decoder architecture. Moreover, we want to investigate how slot filling and intent detection can be jointly modeled under such schemes. 介绍口语理解系统是口语对话系统的重要组成部分。SLU系统通常包括识别说话人的意图和从自然语言查询中提取语义成分，这两个任务通常被称为意图检测和槽填充。 意图检测和槽填充通常单独处理。意图检测可以被视为语义话语分类问题，并且可以应用流行的分类器，如支持向量机（SVM）[1]和深度神经网络方法[2]。槽填充可以被视为序列标记任务。解决序列标记问题的常用方法包括最大熵马尔可夫模型（MEMMs）[3]，条件随机场（CRFs）[4]和循环神经网络（RNNs）[5,6,7]。文献[8,9]也提出了意图检测和槽填充的联合模型。这种联合模型简化了SLU系统，因为只有一个模型需要针对这两个任务进行训练和调整。 最近，编码器-解码器神经网络模型已成功应用于许多序列学习问题，如机器翻译[10]和语音识别[11]。编码器-解码器模型背后的主要思想是将输入序列编码为密集矢量，然后使用该矢量生成相应的输出序列。[12]中介绍的注意机制使编码器-解码器架构能够学会同时对齐和解码。 在这项工作中，我们研究了SLU模型如何从序列模型强大的建模能力中获益。基于注意的编码器-解码器模型能够在不给出对齐信息的情况下映射不同长度的序列。然而，在槽配置中，对齐是明确的，因此基于对齐的RNN模型通常工作得很好。我们想研究基于注意和基于对齐的方法的组合。具体来说，我们想探讨如何在编码器-解码器模型中最好地利用槽配置中的对齐信息，另一方面，通过从编码器-解码器体系结构引入的注意机制，是否可以进一步验证基于对齐的RNN槽配置模型。此外，我们还想研究如何在这种方案的基础上联合建模时的槽填充和意图检测。 Attention-Encoder-Decoder-model 模型Attention-RNN-model 标题 说明 时间 Attention-Based Recurrent Neural Network Models for Joint Intent Detection and Slot Filling 原始论文 20160906 Attention-Based Recurrent Neural Network Models for Joint Intent Detection and Slot Filling 论文跟踪信息 RNN-for-Joint-NLU 官方实现 20170918 Joint-Slot-Filling 和 解析 论文实现和解析 20190127 (Hakkani-Tur et al., 2016) Multi-Domain Joint Semantic Frame Parsing using Bi-directional RNN-LSTM Sequence-to-sequence deep learning has recently emerged as a new paradigm in supervised learning for spoken language understanding. However, most of the previous studies explored this framework for building single domain models for each task, such as slot filling or domain classification, comparing deep learning based approaches with conventional ones like conditional random fields. This paper proposes a holistic multi-domain, multi-task (i.e. slot filling, domain and intent detection) modeling approach to estimate complete semantic frames for all user utterances addressed to a conversational system, demonstrating the distinctive power of deep learning methods, namely bi-directional recurrent neural network (RNN) with long-short term memory (LSTM) cells (RNN-LSTM) to handle such complexity. The contributions of the presented work are three-fold: (i) we propose an RNN-LSTM architecture for joint modeling of slot filling, intent determination, and domain classification; (ii) we build a joint multi-domain model enabling multi-task deep learning where the data from each domain reinforces each other; (iii) we investigate alternative architectures for modeling lexical context in spoken language understanding. In addition to the simplicity of the single model framework, experimental results show the power of such an approach on Microsoft Cortana real user data over alternative methods based on single domain/task deep learning. 摘要 最近，序列到序列的深度学习已经成为用于口语理解的监督学习的新范例。然而，大多数先前的研究探索了用于为每个任务构建单域模型的框架，例如槽填充或域分类，将基于深度学习的方法与诸如条件随机字段之类的传统方法进行比较。本文提出了一种整体的多域，多任务（即槽填充，域和意图检测）建模方法，用于估计针对会话系统的所有用户话语的完整语义框架，展示深度学习方法的独特能力，即双向具有长短期记忆（LSTM）细胞（RNN-LSTM）的循环神经网络（RNN）来处理这种复杂性。所提出工作的贡献有三方面：（i）我们提出了RNN-LSTM架构，用于槽填充，意图识别和域分类的联合建模; （ii）我们建立一个联合的多领域模型，支持多任务深度学习，每个领域的数据相互加强; （iii）我们研究了在口语理解中对词汇语境进行建模的替代架构。除了单一模型框架的简单性之外，实验结果还显示了基于单域/任务深度学习的替代方法，这种方法对Microsoft Cortana真实用户数据的强大作用。 IntroductionIn the last decade, a variety of practical goal-oriented conversation understanding systems have been built for a number of domains, such as the virtual personal assistants Microsoft’s Cortana and Apple’s Siri. Three key tasks in such targeted understanding applications are domain classification, intent determination and slot filling [1], aiming to form a semantic frame that captures the semantics of user utterances/queries. Domain classification is often completed first in spoken language understanding (SLU) systems, serving as a top-level triage for subsequent processing. Intent determination and slot filling are then run for each domain to fill a domain specific semantic template. An example semantic frame for a movie-related utterance, ”find recent comedies by James Cameron”, is shown in Figure 1. This modular design approach (i.e., modeling SLU as 3 tasks) has the advantage of fiexibility; specific modifications (e.g., insertions, deletions) to a domain can be implemented without requiring changes to other domains. Another advantage is that, in this approach, one can use task/domain specific features, which often significantly improve the accuracy of these task/domain specific models. Also, this approach often yields more focused understanding in each domain since the intent determination only needs to consider a relatively small set of intent and slot classes over a single (or limited set) of domains, and model parameters could be optimized for the specific set of intent and slots. However, this approach also has disadvantages: First of all, one needs to train these models for each domain. This is an error-prone process, requiring careful engineering to insure consistency in processing across domains. Also, during runtime, such pipelining of tasks results in transfer of errors from one task to the following tasks. Furthermore, there is no data or feature sharing between the individual domain models, resulting in data fragmentation, whereas, some semantic intents (such as, finding or buying a domain specific entity) and slots (such as, dates, times, and locations) could actually be common to many domains [2, 3]. Finally, the users may not know which domains are covered by the system and to what extent, so this issue results in interactions where the users do not know what to expect and hence resulting in user dissatisfaction [4, 5]. We propose a single recurrent neural network (RNN) architecture that integrates the three tasks of domain detection, intent detection and slot filling for multiple domains in a single SLU model. This model is trained using all available utterances from all domains, paired with their semantic frames. The input of this RNN is the input sequence of words (e.g., user queries) and the output is the full semantic frame, including domain, intent, and slots, as shown in Figure 1. Since the dependency between the words is important for SLU tasks, we investigate alternative architectures for integrating lexical context and dependencies. We compare the single model approach to alternative ways of building models for multi-task, multi-domain scenarios. The next section sets the baseline RNN-LSTM architecture based on the slot filling task [6], and explores various architectures for exploiting lexical contexts. In Section 3, we extend this architecture to model domains and intents of user utterances in addition to slot filling, and propose a multi-domain multi-task architecture for SLU. In the experiments, we first investigate the performance of alternative architectures on the benchmark ATIS data set [7], and then on the Microsoft Cortana muilti-domain data. We show that the single multi-domain, joint model approach is not only simpler, but also results in the best F-measure in experimental results. 介绍在过去十年中，已经为许多领域构建了各种实用的面向目标的会话理解系统，例如虚拟个人助理Microsoft的Cortana和Apple的Siri。这种有针对性的理解应用程序中的三个关键任务是域分类，意图确定和槽填充[1]，旨在形成捕获用户话语/查询的语义的语义框架。域分类通常首先在口语理解（SLU）系统中完成，作为后续处理的顶级分类。然后为每个域运行意图确定和槽填充以填充域特定语义模板。电影相关话语的一个示例语义框架，“找到James Cameron最近的喜剧”，如图1所示。 这种模块化设计方法（即将SLU建模为3个任务）具有灵活性的优点; 可以在不需要改变其他域的情况下实现对域的特定修改（例如，插入，删除）。另一个优点是，在这种方法中，可以使用任务/域特定功能，这通常显着提高这些任务/域特定模型的准确性。此外，这种方法通常在每个域中产生更集中的理解，因为意图确定仅需要在单个（或有限集）域上考虑相对较小的意图和槽类集，并且可以针对特定意图和槽集合优化模型参数。但是，这种方法也有缺点：首先，需要为每个域训练这些模型。这是一个容易出错的过程，需要仔细的工程设计以确保跨域处理的一致性。此外，在运行时期间，这种任务流水线操作会导致错误从一个任务转移到以下任务。此外，各个域模型之间没有数据或功能共享，导致数据碎片，而一些语义意图（例如，发现或购买域特定实体）和槽（例如，日期，时间和位置） 实际上可能是许多领域的共同点[2,3]。最后，用户可能不知道系统覆盖哪些域以及覆盖的程度，因此该问题导致用户不知道期望什么并因此导致用户不满的交互[4,5]。 我们提出了一种单一的循环神经网络（RNN）架构，它在单个SLU模型中集成了多个域的域检测，意图检测和槽填充这三项任务。使用来自所有域的所有可用话语训练该模型，并与其语义框架配对。该RNN的输入是单词的输入序列（例如，用户查询），输出是完整的语义框架，包括域，意图和槽，如图1所示。由于单词之间的依赖关系对SLU很重要 我们研究了用于集成词汇上下文和依赖关系的替代架构。我们将单一模型方法与为多任务，多域方案构建模型的替代方法进行比较。 下一节基于槽填充任务[6]设置基线RNN-LSTM架构，并探索各种用于利用词汇上下文的架构。在第3节中，我们将此体系结构扩展到模型域和用户话语的意图以及槽填充，并为SLU提出了多域多任务体系结构。在实验中，我们首先研究了基准ATIS数据集[7]上的替代架构的性能，然后是Microsoft Cortana muilti域数据。我们证明单一的多域，联合模型方法不仅更简单，而且在实验结果中得到最佳的F值评价指标。 Deep Learning for SLUA major task in spoken language understanding in goal-oriented human-machine conversational understanding systems is to automatically classify the domain of a user query along with domain specific intents and fill in a set of arguments or ”slots” to form a semantic frame. In this study, we follow the popular IOB (in-out-begin) format for representing the slot tags as shown in Figure 1. A detailed survey of pre-deep learning era approaches for domain detection, intent determination, and slot filling can be found in [1]. Basically, domain detection and intent determination tasks are framed as classification problems, for which researchers have employed support vector machines [8], maximum entropy classifiers [9], or boosting based classifiers [10, 11]. Similarly, slot filling is framed as a sequence classification problem and hidden Markov models [12] and conditional random fields [13, 14] have been employed. With the advances on deep learning, deep belief networks (DBNs) with deep neural networks (DNNs) have first been employed for intent determination in call centers [15], and later for domain classification in personal assistants [16, 17, 18]. More recently, an RNN architecture with LSTM cells have been employed for intent classification [19]. For slot filling, deep learning research has started as extensions of DNNs and DBNs (e.g., [20]) and is sometimes merged with CRFs [21]. One notable extension is the use of recursive neural networks, framing the problem as semantic parsing [22]. To the best of our knowledge RNNs have first been employed for slot filling by Yao et al. [23] and Mesnil et al. [24] concurrently. We have compiled a comprehensive review of RNN based slot filling approaches in [6]. Especially with the re-discovery of LSTM cells [25] for RNNs, this architecture has started to emerge [26]. LSTM cells are shown to have superior properties, such as faster convergence and elimination of the problem of vanishing or exploding gradients in sequence via self-regularization, as presented below. As a result, LSTM is more robust than RNN in capturing long-span dependencies. 相关工作面向目标的人机对话理解系统中口语理解的主要任务是自动将用户查询的域与域特定意图一起分类并填充在一组参数或“槽”中以形成语义框架。在本研究中，我们遵循流行的IOB（in-out-begin）格式来表示槽标签，如图1所示。 在[1]中可以找到关于域检测，意图确定和槽填充的预深度学习时代方法的详细调查。基本上，域检测和意图确定任务被定义为分类问题，研究人员使用支持向量机[8]，最大熵分类器[9]或基于增强的分类器[10,11]。类似地，槽填充被构造为序列分类问题，并且已经采用了隐马尔可夫模型[12]和条件随机场[13,14]。 随着深度学习的进步，深信网络（DBN）和深神经网络（DNN）首先被用于呼叫中心的意图确定[15]，然后被用于个人助理的领域分类[16，17，18]。最近，一个带有lstm单元的RNN架构被用于意图分类[19]。 对于槽填充，深度学习研究已经开始作为DNN和DBN的扩展（例如，[20]），并且有时与CRF合并[21]。一个值得注意的扩展是使用循环神经网络，将问题框定为语义解析[22]。据我们所知，RNN首先被姚明等人用于槽填充。[23]和Mesnil等人。[24]同时发生。我们在[6]中总结了基于RNN的槽填充方法的综合评述。 尤其是随着对RNN的LSTM单元[25]的重新发现，这种体系结构已经开始出现[26]。结果表明，LSTM单元具有收敛速度快、通过自正则化消除序列中的梯度消失或爆炸问题等优点。因此，LSTM在捕获长距离依赖项方面比RNN更为强大。 RNN-LSTM-model Joint, Multi-Domain Modeling of Domain, Intent and SlotsA commonly used approach to represent slot tags for slot filling is associating each input word wt of utterance k with an IOB-style tag as exemplified in Figure 1, hence the input se- quence X is w1 , …, wn and the output is the sequence of slot tags s1 , …, sn . We follow this approach and associate a slot tag with each word. For joint modeling of domain, intent, and slots, we assume an additional token at the end of each input utterance k, , and associate a combination of domain and intent tags dk and ik to this sentence final token by concatenating these tags. Hence, the new input and output sequence are : X=w1 , ..., wn , Y=s1 , ..., sn , dk\_ikThe main rationale of this idea is similar to the sequence-to-sequence modeling approach, as used in machine translation [34] or chit-chat [35] systems approaches. The last hidden layer of the query is supposed to contain a latent semantic representation of the whole input utterance, so that it can be utilized for domain and intent prediction (dk ik ). 域、意图和槽的联合、多域建模表示槽填充的槽标签的常用方法是将话语k的每个输入字wt与IOB样式标签相关联，如图1所示，因此输入序列X是w1，…，wn和输出 是槽标签s1，…，sn的序列。我们遵循这种方法并将槽标记与每个单词相关联。 对于域，意图和槽的联合建模，我们在每个输入话语k，的末尾假设一个额外的令牌，并通过连接这些标签将域和目标标签dk和ik的组合关联到这个句子的最终标记。。因此，新的输入和输出序列是： X=w1 , ..., wn , Y=s1 , ..., sn , dk\_ik这种想法的主要原理类似于机器翻译[34]或chit-chat [35]系统方法中使用的序列到序列建模方法。查询的最后隐藏层应该包含整个输入话语的潜在语义表示，以便它可以用于域和意图预测（dk_ik）。 标题 说明 时间 Multi-Domain Joint Semantic Frame Parsing using Bi-directional RNN-LSTM 原始论文 20160906 2017 Multi-Domain Adversarial Learning for Slot Filling in Spoken Language Understanding The goal of this paper is to learn cross-domain representations for slot filling task in spoken language understanding (SLU). Most of the recently published SLU models are domain-specific ones that work on individual task domains. Annotating data for each individual task domain is both financially costly and non-scalable. In this work, we propose an adversarial training method in learning common features and representations that can be shared across multiple domains. Model that produces such shared representations can be combined with models trained on individual domain SLU data to reduce the amount of training samples required for developing a new domain. In our experiments using data sets from multiple domains, we show that adversarial training helps in learning better domain-general SLU models, leading to improved slot filling F1 scores. We further show that applying adversarial learning on domain-general model also helps in achieving higher slot filling performance when the model is jointly optimized with domain-specific models. 摘要 本文的目的是学习口语理解（SLU）中的插槽填充任务的跨域表示。大多数最近发布的SLU模型都是针对各个任务域的特定于域的模型。为每个单独的任务域注释数据既昂贵又不可扩展。在这项工作中，我们提出了一种对抗性训练方法，用于学习可以跨多个域共享的共同特征和表示。产生这种共享表示的模型可以与在单个域SLU数据上训练的模型组合，以减少开发新域所需的训练样本量。在我们使用来自多个域的数据集的实验中，我们展示了对抗性训练有助于学习更好的领域通用SLU模型，从而改善了填充F1分数。我们进一步表明，当使用特定于域的模型联合优化模型时，在领域通用模型上应用对抗性学习也有助于实现更高的槽填充性能。 2018 Slot-Gated Modeling for Joint Slot Filling and Intent Prediction Attention-based recurrent neural network models for joint intent detection and slot filling have achieved the state-of-the-art performance, while they have independent attention weights. Considering that slot and intent have the strong relationship, this paper proposes a slot gate that focuses on learning the relationship between intent and slot attention vectors in order to obtain better semantic frame results by the global optimization. The experiments show that our proposed model significantly improves sentence-level semantic frame accuracy with 4.2% and 1.9% relative improvement compared to the attentional model on benchmark ATIS and Snips datasets respectively. 摘要 用于意图检测和槽填充的基于注意的循环神经网络模型已经实现了最先进的性能，同时它们具有独立的注意力。考虑到槽和意图具有很强的关系，本文提出了一种槽门，专注于学习意图和槽注意向量之间的关系，以便通过全局优化获得更好的语义框架结果。实验表明，与基准ATIS和Snips数据集的注意模型相比，我们提出的模型显着提高了句子级语义框架的准确性，相对改进了4.2％和1.9％。 IntroductionSpoken language understanding (SLU) is a critical component in spoken dialogue systems. SLU is aiming to form a semantic frame that captures the semantics of user utterances or queries. It typically involves two tasks: intent detection and slot filling (Tur and De Mori, 2011). These two tasks focus on predicting speakers intent and extracting semantic concepts as constraints for the natural language. Take a movie-related utterance as an example, ”find comedies by James Cameron”, as shown in Figure 1. There are different slot labels for each word in the utterance, and a specific intent for the whole utterance. Slot filling can be treated as a sequence labeling task that maps an input word sequence x to the corresponding slot label sequence y, and intent detection can be seen as a classification problem to decide the intent label y . Popular approaches for slot filling include conditional random fields (CRF) (Ray-mond and Riccardi, 2007) and recurrent neural network (RNN) (Yao et al., 2014), and different classification methods, such as support vector machine (SVM) and RNN, have been applied to intent prediction. Considering that pipelined approaches usually suffer from error propagation due to their independent models, the joint model for slot filling and intent detection has been proposed to improve sentence-level semantics via mutual enhancement between two tasks (Guo et al., 2014; Hakkani-Tur¨ et al., 2016; Chen et al., 2016). In addition, the attention mechanism (Bahdanau et al., 2014) was introduced and leveraged into the model in order to provide the precise focus, which allows the network to learn where to pay attention in the input sequence for each output label (Liu and Lane, 2015, 2016). The attentional model proposed by Liu and Lane (2016) achieved the state-of-the-art performance for joint slot filling and intent prediction, where the parameters for slot filling and intent prediction are learned in a single model with a shared objective. However, the prior work did not “explicitly” model the relationships between the intent and slots; instead, it applied a joint loss function to “implicitly” consider both cues. Because the slots often highly depend on the intent, this work focuses on how to model the explicit relationships between slots and intent vectors by introducing a slot-gated mechanism. The contributions are three-fold: 1) the proposed slot-gated approach achieves better performance than the attention-based models; 2) the experiments on two SLU datasets show the generalization and the effectiveness of the proposed slot gate; 3) the gating results help us analyze the slot-intent relations. 介绍口语理解（SLU）是口语对话系统中的关键组成部分。SLU旨在形成捕获用户话语或查询的语义的语义槽。它通常涉及两个任务：意图检测和槽填充（Tur和De Mori，2011）。这两项任务侧重于预测说话者意图和提取语义概念作为自然语言的约束。以电影相关的话语为例，“詹姆斯卡梅隆的喜剧”，如图1所示。话语中的每个单词都有不同的槽标签，以及整个话语的特定意图。 可以将槽填充视为将输入词序列x映射到对应的槽标签序列y的序列标记任务，并且可以将意图检测视为决定意图标签y的分类问题。流行填充的流行方法包括条件随机场（CRF）（Ray-mond和Riccardi，2007）和循环神经网络（RNN）（Yao等，2014），以及不同的分类方法，如支持向量机（SVM） 和RNN，已应用于意图预测。 考虑到流水线方法由于其独立模型而通常遭受误差传播，因此提出了用于槽填充和意图检测的联合模型，以通过两个任务之间的相互增强来改善句子级语义（Guo等人，2014; Hakkani-Tur） ¨等人，2016;陈等人，2016）。此外，引入了注意机制（Bahdanau et al。，2014）并将其用于模型中以提供精确的注意点，这使得网络可以在输入序列中了解每个输出标签的注意位置（Liu和 Lane，2015,2016）。Liu和Lane（2016）提出的注意模型实现了联合槽填充和意图预测的最先进性能，其中槽填充和意图预测的参数是在具有共享目标的单个模型中学习的。然而，先前的工作没有“明确地”模拟意图和槽之间的关系; 相反，它应用联合损失函数来“隐含地”考虑两个任务。由于槽通常高度依赖于意图，因此本工作重点介绍如何通过引入槽门控机制来模拟槽和意图向量之间的显式关系。贡献有三方面：1）提议的槽门控方法比基于注意力的模型实现更好的性能; 2）对两个SLU数据集的实验表明了所提出的槽门的泛化性和有效性; 3）门控结果有助于我们分析槽意图关系。 Slot-Gated-models 标题 说明 时间 Slot-Gated Modeling for Joint Slot Filling and Intent Prediction 论文原文 2018 论文实现 Code 原作者实现 2018 Slot-Gated Modeling for Joint Slot Filling and Intent Prediction Helic He 解读 20181203 『 论文阅读』Slot-Gated Modeling for Joint Slot Filling and Intent Prediction 立刻有 20181014 相关论文Attention-Based Recurrent Neural Network Models for Joint Intent Detection and Slot Filling解读 立刻有 20181014 【论文阅读】Slot-Gated Modeling for Joint Slot Filling and Intent Prediction iMayday_hui；代码解读 20181121 《用于槽填充和意图检测的slot-gates模型》阅读笔记 战先生 20181105 2018 Unsupervised Transfer Learning for Spoken Language Understanding in Intelligent Agents User interaction with voice-powered agents generates large amounts of unlabeled utterances. In this paper, we explore techniques to efficiently transfer the knowledge from these unlabeled utterances to improve model performance on Spoken Language Understanding (SLU) tasks. We use Embeddings from Language Model (ELMo) to take advantage of unlabeled data by learning contextualized word representations. Additionally, we propose ELMo-Light (ELMoL), a faster and simpler unsupervised pre-training method for SLU. Our findings suggest unsupervised pre-training on a large corpora of unlabeled utterances leads to significantly better SLU performance compared to training from scratch and it can even outperform conventional supervised transfer. Additionally, we show that the gains from unsupervised transfer techniques can be further improved by supervised transfer. The improvements are more pronounced in low resource settings and when using only 1000 labeled in-domain samples, our techniques match the performance of training from scratch on 10-15x more labeled in-domain data. 摘要 用户与语音代理的交互会产生大量未标记的话语。在本文中，我们探索了从这些未标记的话语中有效传递知识的技术，以提高口语理解（SLU）任务的模型性能。我们使用语言模型嵌入（ELMo）通过学习语境化的单词表示来利用未标记的数据。此外，我们提出ELMo-Light（ELMoL），这是一种更快速，更简单的无监督预训练方法，适用于SLU。我们的发现表明，对于大量无标记话语的无监督预训练，与从头开始训练相比，可以显着提高SLU性能，甚至可以胜过传统的监督传输。此外，我们表明，无监督传输技术可以通过监督传输进一步提高收益。这些改进在低资源设置中更为明显，并且当仅使用1000个标记的域内样本时，我们的技术从头开始匹配10-15倍标记的域内数据的训练性能。 IntroductionVoice-powered artificial virtual agents have become popular amongst consumer devices, as they enable their users to perform everyday tasks through intuitive and natural user interfaces. SLU tasks such as intent classification and entity tagging are critical functionalities of these agents. Fast expansion of these functionalities to new domains is important for achieving engaging and informative interactions, as it increases the range of capabilities that their users enjoy. For SLU tasks, most of the current methods use supervised learning, which relies on manually labeled data for building high quality models. The supervised learning paradigm is therefore costly, time-consuming and does not scale well for cases where the label space is continuously expanding as new functionality is added to an agent. Also, user interaction with voice-powered agents generates large amounts of unlabeled text, produced by the Automatic Speech Recognition (ASR) engine. This ASR output text is a large and valuable resource of conversational data that is available in practically unlimited quantities and could be used to improve the agent’s SLU accuracy. Thus, the ability to learn effectively from unlabeled text is crucial to alleviating the bottlenecks of supervised learning. The machine learning community is actively exploring transfer learning and unsupervised learning for low resource tasks. Goyal, Metallinou, and Matsoukas (2018) explored transfer learning from existing annotated SLU domains for building models for related, low-resource domains for artificial agents. However, such transfer learning techniques rely on large annotated resources from a related functionality. Recent work has used language modeling (LM) as a proxy task for learning context dependent word embeddings from large unlabeled text corpora (Peters et al. 2018). These embeddings allow for unsupervised knowledge transfer and have been shown to bring performance gains for various downstream natural language processing (NLP) tasks. In this work, we propose an unsupervised transfer learning technique inspired from ELMo and Universal Language Model Fine Tuning (ULMFiT) to leverage unlabeled text for building SLU models (Peters et al. 2018; Howard and Ruder 2018). We also explore the combination of unsupervised and supervised knowledge transfer for SLU. We evaluate our methods on various tasks and datasets, including data from a popular commercial intelligent agent. Our results show that unsupervised transfer using unlabeled utterances can outperform both training from scratch and supervised pre- training. Additionally, the gains from unsupervised transfer can further be improved by supervised transfer. These improvements are more pronounced in low resource setting and when only 1K labeled in-domain samples are available, the proposed techniques match the performance of training from scratch on 10-15x more labeled data. Concretely, our contributions are: We apply ELMo embeddings for unsupervised knowledge transfer from raw ASR text and show SLU accuracy gains. We propose ELMo-Light (ELMoL), a light-weight ELMo alternative that is well-suited for commercial settings, with comparable accuracy to ELMo for most SLU tasks. We combine unsupervised and supervised transfer learning, and show the additive effect of the two techniques. We extensively evaluate our methods on benchmark SLU datasets and data from a commercial agent, across various resource conditions. The rest of paper is organized as follows. To provide a bit of background, we discuss related work and neural architec- tures for SLU and then introduce the methods we use for un- supervised transfer including the proposed ELMoL. Finally, we describe the datasets, experimental setup, results and end with directions for future work. Table 1 summarizes some of the frequently used abbreviations throughout the paper. 介绍语音驱动的人工虚拟代理已经在消费者设备中变得流行，因为它们使用户能够通过直观和自然的用户界面执行日常任务。SLU任务（例如意图分类和实体标记）是这些代理的关键功能。将这些功能快速扩展到新域对于实现引人入胜和信息丰富的交互非常重要，因为它增加了用户所享受的功能范围。 对于SLU任务，大多数当前方法使用监督学习，其依赖于手动标记的数据来构建高质量模型。因此，监督学习范例是昂贵的，耗时的并且对于标签空间随着新功能被添加到代理而不断扩展的情况而言不能很好地扩展。此外，用户与语音代理的交互会产生大量未标记的文本，由自动语音识别（ASR）引擎生成。此ASR输出文本是一个庞大而有价值的会话数据资源，几乎可以无限量地提供，可用于提高代理的SLU准确性。因此，有效地从未标记的文本中学习的能力对于缓解监督学习的瓶颈至关重要。 机器学习社区正在积极探索低资源任务的迁移学习和无监督学习。Goyal，Metallinou和Matsoukas（2018）探索了现有注释SLU域的迁移学习，以便为人工代理建立相关的低资源域模型。然而，这种迁移学习技术依赖于来自相关功能的大注释资源。最近的工作使用语言建模（LM）作为代理任务，用于学习来自大型未标记文本语料库的上下文相关词嵌入（Peters等人，2018）。这些嵌入允许无监督的知识转移，并且已被证明可以为各种下游自然语言处理（NLP）任务带来性能提升。 在这项工作中，我们提出了一种灵感来自ELMo和通用语言模型微调（ULMFiT）的无监督迁移学习技术，以利用未标记的文本来构建SLU模型（Peters等人，2018; Howard和Ruder，2018）。我们还探索了SLU的无监督和监督知识转移的组合。我们评估各种任务和数据集的方法，包括来自流行的商业智能代理的数据。我们的研究结果表明，使用未标记的话语的无监督转移可以优于从头开始的训练和监督的预训练。另外，通过监督转移可以进一步改善无监督转移的收益。这些改进在低资源设置中更为明显，并且当仅有1K标记的域内样本可用时，所提出的技术从头开始匹配10-15倍更多标记数据的训练性能。具体而言，我们的贡献是： 我们将ELMo嵌入应用于来自原始ASR文本的无监督知识转移，并显示SLU准确度增益。 我们提出ELMo-Light（ELMoL），一种轻量级ELMo替代品，非常适合商业环境，与大多数SLU任务的ELMo精度相当。 我们将无监督和有监督的迁移学习结合起来，并展示了这两种技术的加性效应。 我们在各种资源条件下广泛评估基准SLU数据集和商业代理数据的方法。 其余论文的结构如下。为了提供一些背景知识，我们讨论了SLU的相关工作和神经结构，然后介绍了我们用于非监督传输的方法，包括提出的ELMoL。最后，我们描述了数据集，实验设置，结果并结束了未来工作的方向。表1总结了本文中一些常用的缩写。 Related WorkDeep learning models using CNNs and LSTMs are state of the art for many NLP tasks. Examples include applying LSTMs for sentence classification (Liu et al. 2015; Socher et al. 2013), LSTM with Conditional Random Field (CRF) decoder for sequence labeling (Chiu and Nichols 2016) and CNN-LSTM combinations for LM (Jozefowicz et al. 2016). LSTMs with attention have also been used for SLU tasks including Entity tagging (ET) and intent classification (IC) (Liu and Lane 2016). To enable robust training of deep learning models in low resource settings, the community is actively exploring semi-supervised, transfer and multi-task learning techniques. In the multi-task paradigm a network is jointly trained to optimize multiple related tasks, exploiting beneficial correlations across tasks (Liu and Lane 2016; Collobert and Weston 2008). Liu et al. (2018) used language models (LMs) as an auxiliary task in a multi-task setting to improve sequence labeling performance. Transfer learning addresses the transfer of knowledge from data-rich source tasks to under-resourced target tasks. Neural transfer learning has been successfully applied in computer vision where lower network layers are trained in high-resource supervised datasets like ImageNet to learn generic features (Krizhevsky, Sutskever, and Hinton 2012), and are then fine-tuned on target tasks, leading to impressive results for image classification and object detection (Donahue et al. 2014; Sharif Razavian et al. 2014). In NLP, such supervised transfer learning was successfully applied for SLU tasks, by learning IC and ET models on high resource SLU domains, and then fine-tuning the network on under resourced domains (Goyal, Metallinou, and Matsoukas 2018). Similar ideas have also been explored for POS tagging using for cross-lingual transfer learning (Kim et al. 2017). Unsupervised methods for knowledge transfer include computing word and phrase representations from large unlabeled text corpora. Examples include Word2Vec and Fast-Text, where context independent word representations are learnt based on LM-related objectives (Mikolov et al. 2013; Bojanowski et al. 2017). Unsupervised sentence representations have been computed via predicting sentence sequences like skip-thought (Kiros et al. 2015), and through a combination of auxiliary supervised and unsupervised tasks (Cer et al. 2018). Recent work has introduced LM-based word embeddings, ELMo, that are dependent on sentence context and are shown to lead to significant accuracy gains for various downstream NLP tasks (Peters et al. 2018). Unsupervised pre-training has also been used as a form of knowledge transfer by first training a network using an LM objective and then fine-tuning it on supervised NLP tasks. This has been shown to be efficient for sentence classification (Howard and Ruder 2018; Dai and Le 2015) and (Radford et al. 2018) for textual entailment and question answering. Our work, building upon transfer learning ideas such as supervised model pre-training (Goyal, Metallinou, and Matsoukas 2018), LM-fine tuning (Howard and Ruder 2018) and context dependent word embeddings (Peters et al. 2018), introduces a light-weight ELMo extension and combines those methods for improving SLU performance in a commercial agent. 相关工作使用CNN和LSTM的深度学习模型是许多NLP任务的最新技术。例子包括应用LSTM进行句子分类（Liu et al.2015; Socher et al.2013），LSTM with Conditional Random Field（CRF）解码器用于序列标记（Chiu和Nichols 2016）和CNN-LSTM组合用于LM（Jozefowicz等 。2016）。LSTM还被用于SLU任务，包括实体标记（ET）和意图分类（IC）（Liu和Lane 2016）。 为了在低资源环境中实现深度学习模型的强大训练，社区正在积极探索半监督，转移和多任务学习技术。在多任务范例中，联合训练网络以优化多个相关任务，利用跨任务的有益关联（Liu and Lane 2016; Collobert和Weston 2008） 刘等人（2018）使用语言模型（LM）作为多任务设置中的辅助任务以改善序列标记性能。迁移学习解决了从数据丰富的源任务到资源不足的目标任务的知识转移问题。神经迁移学习已成功应用于计算机视觉，其中较低的网络层在ImageNet等高资源监督数据集中进行训练，以学习通用特征（Krizhevsky，Sutskever和Hinton 2012），然后在目标任务上进行调整，从而获得令人印象深刻的图像分类和物体检测结果（Donahue等人2014; Sharif Razavian等人2014）。在NLP中，通过在高资源SLU域上学习意图分类和实体标签模型，然后在资源域下对网络进行微调（Goyal，Metallinou和Matsoukas，2018），这种有监督的迁移学习成功地应用于SLU任务。对于使用跨语言迁移学习的POS标记，也已经探索了类似的想法（Kim等人，2017）。 用于知识迁移的无监督方法包括计算来自大的未标记文本语料库的单词和短语表示。示例包括Word2Vec和Fast-Text，其中基于LM相关目标学习与上下文无关的单词表示（Mikolov等人2013; Bojanowski等人2017）。通过预测句子序列（例如Skip-thought（Kiros等人，2015））以及通过辅助监督和无监督任务的组合（Cer等人，2018），计算出无监督的句子表示。最近的工作引入了基于LM的单词嵌入，ELMo，它依赖于句子上下文，并且显示出导致各种下游NLP任务的显着准确性增益（Peters等人，2018）。无监督预训练也被用作知识转移的一种形式，首先使用LM物镜训练网络，然后在监督的NLP任务上对其进行微调。这已被证明对于句子分类（Howard和Ruder 2018; Dai和Le 2015）和（Radford等人2018）的文本蕴涵和问题回答是有效的。我们的工作建立在迁移学习思想的基础上，如监督模型预训练（Goyal，Metallinou和Matsoukas 2018），LM-fi调整（Howard和Ruder 2018）和依赖于上下文的单词嵌入（Peters et al.2018），轻量级ELMo扩展并结合这些方法来改善商业代理中的SLU性能。 Neural Architectures for SLUWe focus on SLU for voice powered artificial agents, specifically on intent classification (IC) and Entity tagging (ET) models which are essential for such agents. Given a user request like ‘how to make kadhai chicken’, the IC model classifies the intention of the user, such as ‘GetRecipe’ while the ET model tags the entities of interest in the utterance, such as ‘Dish’=‘kadhai chicken’. We use a multi-task deep neural network architecture for jointly learning the IC and ET models, hence exploring beneficial correlations between the two tasks. Our architecture is illustrated in Figure 1. It consists of a bottom shared bidirectional LSTM (bi-LSTM) layer on top of which we train a bi-LSTM-CRF for ET and a bi-LSTM for IC. The two top layers are optimized separately for ET and IC, while the common bottom layer is optimized for both tasks. The objective function for the multi-task network combines the IC and ET objectives. …Formula description as shown in figure, not translated for the time being… 用于口语理解的神经结构我们专注于语音驱动的人工智能代理SLU，特别是针对此类代理必不可少的意图分类（IC）和实体标记（ET）模型。鉴于用户请求如’如何制作kadhai鸡’，IC模型分类用户的意图，例如’GetRecipe’，而ET模型标记话语中感兴趣的实体，例如’Dish’=’kadhai chicken”。 我们使用多任务深度神经网络架构来共同学习IC和ET模型，从而探索两个任务之间的有益相关性。我们的架构如图1所示。它由底部共享双向LSTM（bi-LSTM）层组成，我们在其上训练用于ET的双LSTM-CRF和用于IC的双LSTM。两个顶层针对ET和IC分别进行了优化，而公共底层针对这两个任务进行了优化。多任务网络的目标函数结合了IC和ET目标。 …公式描述如图，暂时不翻译… 标题 说明 时间 Unsupervised Transfer Learning for Spoken Language Understanding in Intelligent Agents 论文原文 20181113 2018 Subword Semantic Hashing for Intent Classification on Small Datasetshttps://paperswithcode.com/paper/subword-semantic-hashing-for-intent-clas2 标题 说明 时间 Subword Semantic Hashing for Intent Classification on Small Datasets 论文原文 20181216 论文实现 Code 原作者实现 20190201 2018 Snips Voice Platform: an embedded Spoken Language Understanding system for private-by-design voice interfacesThis paper presents the machine learning architecture of the Snips Voice Platform, a software solution to perform Spoken Language Understanding on microprocessors typical of IoT devices. The embedded inference is fast and accurate while enforcing privacy by design, as no personal user data is ever collected. Focusing on Automatic Speech Recognition and Natural Language Understanding, we detail our approach to training high-performance Machine Learning models that are small enough to run in real-time on small devices. Additionally, we describe a data generation procedure that provides sufﬁcient, high-quality training data without compromising user privacy. 摘要本文介绍了Snips语音平台的机器学习架构，这是一种软件解决方案，用于在物联网设备的典型微处理器上执行语言管理。嵌入式推理快速准确，同时通过设计实施隐私，因为不会收集任何个人用户数据。我们专注于自动语音识别和自然语言理解，详细介绍了我们培训高性能机器学习模型的方法，这些模型足够小，可以在小型设备上实时运行。此外，我们还介绍了一种数据生成过程，该过程可提供足够的高质量培训数据，而不会影响用户隐私。 标题 说明 时间 Snips Voice Platform: an embedded Spoken Language Understanding system for private-by-design voice interfaces 论文原文 20181206 2018 Zero-shot User Intent Detection via Capsule Neural Networks User intent detection plays a critical role in question-answering and dialog systems. Most previous works treat intent detection as a classification problem where utterances are labeled with predefined intents. However, it is labor-intensive and time-consuming to label users’ utterances as intents are diversely expressed and novel intents will continually be involved. Instead, we study the zero-shot intent detection problem, which aims to detect emerging user intents where no labeled utterances are currently available. We propose two capsule-based architectures: INTENT-CAPSNET that extracts semantic features from utterances and aggregates them to discriminate existing intents, and INTENTCAPSNET-ZSL which gives INTENTCAPSNET the zero-shot learning ability to discriminate emerging intents via knowledge transfer from existing intents. Experiments on two real-world datasets show that our model not only can better discriminate diversely expressed existing intents, but is also able to discriminate emerging intents when no labeled utterances are available. 摘要 用户意图检测在问答和对话系统中起着关键作用。大多数先前的工作将意图检测视为分类问题，其中话语用预定义的意图标记。然而，标记用户的话语是劳动密集型和耗时的，因为意图的表达方式多种多样，并且不断涉及新的意图。相反，我们研究zero-shot意图检测问题，该问题旨在检测当前没有标记话语的新兴用户意图。我们提出了两种基于胶囊的体系结构：INTENT-CAPSNET从话语中提取语义特征并将它们聚合以区分现有意图，以及INTENTCAPSNET-ZSL，它为INTENTCAPSNET提供零射击学习能力，通过现有意图的知识转移来区分新兴意图。对两个真实世界数据集的实验表明，我们的模型不仅可以更好地区分不同表达的现有意图，而且还可以在没有标记话语时区分新出现的意图。 标题 说明 时间 Zero-shot User Intent Detection via Capsule Neural Networks 论文原文 20180902 ZeroShotCapsule 官方实现 20190409 2018 Joint Slot Filling and Intent Detection via Capsule Neural Networks Being able to recognize words as slots and detect the intent of an utterance has been a keen issue in natural language understanding. The existing works either treat slot filling and intent detection separately in a pipeline manner, or adopt joint models which sequentially label slots while summarizing the utterance-level intent without explicitly preserving the hierarchical relationship among words, slots, and intents. To exploit the semantic hierarchy for effective modeling, we propose a capsule-based neural network model which accomplishes slot filling and intent detection via a dynamic routing-by-agreement schema. A rerouting schema is proposed to further synergize the slot filling performance using the inferred intent representation. Experiments on two real-world datasets show the effectiveness of our model when compared with other alternative model architectures, as well as existing natural language understanding services. 摘要 能够将单词识别为语义槽并检测话语的意图一直是自然语言理解中的一个热门问题。现有的工作要么以流水线方式分别处理槽填充和意图检测，要么采用顺序标注词级槽并且同时总结话语级意图的联合模型，而不明确词语、槽和意图之间的层次关系。为了利用语义层次结构进行有效建模，我们提出了一种基于胶囊的神经网络模型，该模型通过动态路由协议模式完成槽填充和意图检测。提出了重新路由模式以使用推断的意图表示来进一步协调槽填充性能。在两个真实世界数据集的实验表明，与其他替代模型体系结构以及现有的自然语言理解服务相比，我们模型的有效性。 IntroductionWith the ever-increasing accuracy in speech recognition and complexity in user-generated utterances, it becomes a critical issue for mobile phones or smart speaker devices to understand the natural language in order to give informative responses. Slot filling and intent detection play important roles in Natural Language Understanding (NLU) systems. For example, given an utterance from the user, the slot filling annotates the utterance on a word-level, indicating the slot type mentioned by a certain word such as the slot artist mentioned by the word Sungmin, while the intent detection works on the utterance-level to give categorical intent label(s) to the whole utterance. Figure 1 illustrates this idea. To deal with diversely expressed utterances without additional feature engineering, deep neural network based user intent detection models (Hu et al., 2009; Xu and Sarikaya, 2013; Zhang et al., 2016; Liu and Lane, 2016; Zhang et al., 2017; Chen et al., 2016; Xia et al., 2018) are proposed to classify user intents given their utterances in the natural language. Currently, the slot filling is usually treated as a sequential labeling task. A neural network such as a recurrent neural network (RNN) or a convolution neural network (CNN) is used to learn contextaware word representations, along with sequence tagging methods such as conditional random field (CRF) (Lafferty et al., 2001) that infer the slot type for each word in the utterance. Word-level slot filling and utterance-level intent detection can be conducted simultaneously to achieve a synergistic effect. The recognized slots, which possess word-level signals, may give clues to the utterance-level intent of an utterance. For example, with a word Sungmin being recognized as a slot artist, the utterance is more likely to have an intent of AddToPlayList than other intents such as GetWeather or BookRestaurant. Some existing works learn to fill slots while detecting the intent of the utterance (Xu and Sarikaya, 2013; Hakkani-Tur et al. ¨ , 2016; Liu and Lane, 2016; Goo et al., 2018): a convolution layer or a recurrent layer is adopted to sequentially label word with their slot types: the last hidden state of the recurrent neural network, or an attention-weighted sum of all convolution outputs are used to train an utterance-level classification module for intent detection. Such approaches achieve decent performances but do not explicitly consider the hierarchical relationship between words, slots, and intents: intents are sequentially summarized from the word sequence. As the sequence becomes longer, it is risky to simply rely on the gate function of RNN to control the information fiow for intent detection given the utterance. In this work, we make the very first attempt to bridge the gap between word-level slot modeling and the utterance-level intent modeling via a hierarchical capsule neural network structure (Hinton et al., 2011; Sabour et al., 2017). A capsule houses a vector representation of a group of neurons. The capsule model learns a hierarchy of feature detectors via a routing-by-agreement mechanism: capsules for detecting low-level features send their outputs to high-level capsules only when there is a strong agreement of their predictions to high-level capsules. The aforementioned properties of capsule models are appealing for natural language understanding from a hierarchical perspective: words such as Sungmin are routed to concept-level slots such as artist, by learning how each word matches the slot representation. Concept-level slot features such as artist, playlist owner, and playlist collectively contribute to an utterance-level intent AddToPlaylist. The dynamic routing-by-agreement assigns a larger weight from a lower-level capsule to a higher-level when the low-level feature is more predictive to one high-level feature, than other high-level fea- tures. Figure 2 illustrates this idea. The inferred utterance-level intent is also helpful in refining the slot filling result. For example, once an AddToPlaylist intent representation is learned in IntentCaps, the slot filling may capitalize on the inferred intent representation and recognize slots that are otherwise neglected previously. To achieve this, we propose a re-routing schema for capsule neural networks, which allows high-level features to be actively engaged in the dynamic routing between WordCaps and Slot-Caps, which improves the slot filling performance. To summarize, the contributions of this work are as follows: Encapsulating the hierarchical relationship among word, slot, and intent in an utterance by a hierarchical capsule neural network structure. Proposing a dynamic routing schema with re-routing that achieves synergistic effects for joint slot filling and intent detection. Showing the effectiveness of our model on two real-world datasets, and comparing with existing models as well as commercial NLU services. 介绍随着语音识别的准确性不断提高以及用户生成的话语的复杂性，移动电话或智能扬声器设备理解用户自然语言以提供信息响应成为关键问题。槽填充和意图检测在自然语言理解（NLU）系统中起着重要作用。例如，给定来自用户的话语，槽填充在单词级别上注释话语，指示某个单词所提到的槽类型，例如单词Sungmin提到的槽类型是艺术家，而意图检测在话语级别上工作。为整个话语提供明确的意图标签。图1说明了这个想法。 为了处理各种表达的话语而无需额外的特征工程，基于深度神经网络的用户意图检测模型（Hu et al。，2009; Xu and Sarikaya，2013; Zhang et al。，2016; Liu and Lane，2016; Zhang et al。，2017; Chen等人，2016; Xia等人，2018）被提议用自然语言给出他们的话语来对用户意图进行分类。 目前，槽填充通常被视为顺序标记任务。诸如循环神经网络（RNN）或卷积神经网络（CNN）的神经网络用于学习上下文词语表示，以及诸如条件随机场（CRF）的序列标记方法（Lafferty等人，2001）。推断话语中每个单词的槽类型。 可以同时进行字级槽填充和话语级意图检测以实现协同效应。具有字级信号的识别的槽可以提供话语的话语级意图的线索。例如，通过将单词Sungmin识别为槽艺术家，话语比其他意图（例如GetWeather或BookRestaurant）更可能具有AddToPlayList的意图。 一些现有的工作在检测话语的意图时学习填充槽（Xu和Sarikaya，2013; Hakkani-Tur等人，2016; Liu和Lane，2016; Goo等，2018）：采用卷积层或循环层来顺序地标记单词对应的槽类型：循环神经网络的最后隐藏状态，或所有卷积输出的注意加权和，用于训练用于意图检测的话语级分类模块。这些方法实现了不错的性能，但没有明确考虑单词，槽和意图之间的层次关系：意图是从词序列中顺序汇总的。随着序列变得更长，仅仅依靠RNN的门函数来控制用于话语检测的信息流是有风险的。 在这项工作中，我们首次尝试通过分层的胶囊神经网络结构来弥合单词级槽建模和话语级意图建模之间的差距（Hinton等，2011; Sabour等，2017）。胶囊容纳一组神经元的矢量表示。胶囊模型通过逐个路由机制学习特征检测器的层次结构：用于检测低级特征的胶囊仅在其对高级别胶囊的预测强烈一致时才将其输出发送到高级别胶囊。 胶囊模型的上述特性从层级角度理解自然语言理解：通过学习每个单词如何匹配槽表示，诸如Sungmin之类的词被路由到诸如艺术家的概念级槽。诸如艺术家，播放列表所有者和播放列表之类的概念级槽功能共同促成了话语级别的意图AddToPlaylist。当低级别特征比一个高级别特征更能预测时，动态逐个路由协议将较低级别的权限分配给较高级别的权重，而不是其他高级别特征。图2说明了这个想法。 推断的话语级意图也有助于重新确定槽填充结果。例如，一旦在IntentCaps中学习了AddToPlaylist意图表示，则槽填充可以利用推断的意图表示并识别先前被忽略的槽。为此，我们提出了一种用于胶囊神经网络的重新路由模式，它允许高级功能主动参与WordCaps和Slot-Caps之间的动态路由，从而提高了槽填充性能。 总而言之，这项工作的贡献如下： 通过分层的胶囊神经网络结构封装话语中的单词，槽和意图之间的层次关系。 提出具有重新路由的动态路由模式，以实现关节槽填充和意图检测的协同效应。 显示我们的模型在两个真实世界数据集上的有效性，并与现有模型以及商业NLU服务进行比较。 Caspule_Neural_Networks_model Related WorksIntent Detection With recent developments in deep neural networks, user intent detection models (Hu et al., 2009; Xu and Sarikaya, 2013; Zhang et al., 2016; Liu and Lane, 2016; Zhang et al., 2017; Chen et Al., 2016; Xia et al., 2018) are proposed to classify user intents given their diversely utterances in the natural language. As a text classification task, the decent performance on utterance-level intent detection usually relies on hidden representations that are Learned in the intermediate layers via multiple non-linear transformations. Recently, various capsule based text classification models are proposed that aggregate word-level features for utterance-level classification via dynamic routing-by-aggre ment (Gong et al., 2018; Zhao et al., 2018; Xia et al., 2018). Among them, Xia et al. (2018) adopts self-attention to extract intermediate semantic features and uses a capsule-based neural network for intent detection. However, existing works do not study word-level supervisions for the slot filling task. In this work, we explicitly model the hierarchical relationship between words and slots on the word-level, as well as intents on the utterance-level via dynamic routing. Slot filling Slot filling annotates the utterance with finer granularity: it associates certain parts of the utterance, usually named entities, with predefined slot tags. Currently, the slot filling is usually treated as a sequential labeling task. A recurrent neural network such as Gated Recurrent Unit (GRU) or Long Short-term Memory Network (LSTM) is used to learn context-aware word representations, and Conditional Random Fields (CRF) are used to annotate each word based on its slot type. Recently, Shen et al. (2017); Tan et al. (2017) introduce the self-attention mechanism for CRF free sequential labeling. Joint Modeling via Sequence Labeling To overcome the error propagation in the word-level slot filling task and the utterance-level intent detection task in a pipeline, joint models are proposed to solve two tasks simultaneously in a unified framework. Xu and Sarikaya (2013) propose a Convolution Neural Network (CNN) based sequential labeling model for slot filling. The hidden states corresponding to each word are summed up in a classification module to predict the utterance intent. A Conditional Random Field module ensures the best slot tag sequence of the utterance from all possible tag sequences. Hakkani-Tur et al. ¨ (2016) adopt a Recurrent Neural Network (RNN) for slot filling and the last hidden state of the RNN is used to predict the utterance intent. Liu and Lane (2016) further introduce an RNN based encoder-decoder model for joint slot filling and intent detection. An attention weighted sum of all encoded hidden states is used to predict the utterance intent. Some specific mechanisms are designed for RNNs to explicitly encode the slot from the utterance. For example, Goo et al. (2018) utilize a slot-gated mechanism as a special gate function in Long Short-term Memory Network (LSTM) to improve slot filling by the learned intent context vector. However, as the sequence becomes longer it is risky to simply rely on the gate function to sequentially summarize and compress all slots and context information in a single vector (Cheng et al., 2016). In this paper, we harness the capsule neural network to learn a hierarchy of feature detectors and explicitly model the hierarchical relationships among word-level slots and utterance-level intent. Also, instead of doing sequence la- beling for slot filling, we use a dynamic routing-by-agreement schema between capsule layers to assign a proper slot type for each word in the utterance. 相关研究意图检测 随着深度神经网络的最新发展，用户意图检测模型（Hu et al。，2009; Xu and Sarikaya，2013; Zhang et al。，2016; Liu and Lane，2016; Zhang et al。，2017; Chen et Al。，2016; Xia et al。，2018）被提出根据自然语言中的不同话语对用户意图进行分类。作为文本分类任务，话语级意图检测的体面表现通常依赖于通过多个非线性变换在中间层中学习的隐藏表示。最近，提出了各种基于胶囊的文本分类模型，通过动态路由聚合来聚合话语级分类的词级特征（Gong等，2018; Zhao等，2018; Xia等，2018））。其中，夏等人（2018）采用自注意提取中间语义特征，并使用基于胶囊的神经网络进行意图检测。但是，现有的工作没有研究槽填充任务的字级监督。在这项工作中，我们明确地模拟了单词级别的单词和槽之间的层次关系，以及通过动态路由在话语级别上的意图。 槽填充 槽填充以更精细的粒度注释话语：它将话语的某些部分（通常称为实体）与预定义的槽标签相关联。目前，槽填充通常被视为顺序标记任务。诸如门控递归单元（GRU）或长短期记忆网络（LSTM）之类的循环神经网络用于学习上下文感知字表示，并且条件随机场（CRF）用于基于其槽类型来注释每个字。最近，沉等人（2017）; Tan等人（2017）介绍了CRF自由序列标签的自注意力机制。 通过序列标注的联合模型 为了克服管道式框架中词级槽填充任务和话语级意图检测任务之间的错误传播，提出了联合模型以在统一框架中同时解决两个任务。Xu和Sarikaya（2013）提出了一种基于卷积神经网络（CNN）的槽填充顺序标记模型。对应于每个单词的隐藏状态在分类模块中求和以预测话语意图。条件随机场模块确保来自所有可能标签序列的话语的最佳槽标签序列。Hakkani-Tur等人（2016）采用循环神经网络（RNN）进行槽填充，RNN的最后隐藏状态用于预测话语意图。Liu和Lane（2016）进一步介绍了一种基于RNN的编码器-解码器模型，用于关节槽填充和意图检测。所有编码的隐藏状态的注意加权总和用于预测话语内容。一些特定的机制被设计用于RNN以明确地对话语中的槽进行编码。例如，Goo等人。（2018）利用槽门控机制作为长短期存储网络（LSTM）中的特殊门功能，以通过所学习的意图上下文向量来改善槽填充。然而，随着序列变得更长，仅依靠门函数来顺序地汇总和压缩单个向量中的所有槽和上下文信息是有风险的（Cheng等人，2016）。在本文中，我们利用胶囊神经网络来学习特征检测器的层次结构，并明确地模拟单词级别槽和话语级别意图之间的层次关系。此外，我们使用胶囊层之间的协议模式来动态路由，而不是为插槽填充执行序列标记，以便为话语中的每个单词指定正确的插槽类型。 标题 说明 时间 Joint Slot Filling and Intent Detection via Capsule Neural Networks 论文原文 20181222 2018 A Self-Attentive Model with Gate Mechanism for Spoken Language UnderstandingSpoken Language Understanding (SLU), which typically involves intent determination and slot filling, is a core component of spoken dialogue systems. Joint learning has shown to be effective in SLU given that slot tags and intents are supposed to share knowledge with each other. However, most existing joint learning methods only consider joint learning by sharing parameters on surface level rather than semantic level. In this work, we propose a novel self-attentive model with gate mechanism to fully utilize the semantic correlation between slot and intent. Our model first obtains intent-augmented embeddings based on neural network with self-attention mechanism. And then the intent semantic representation is utilized as the gate for labelling slot tags. The objectives of both tasks are optimized simultaneously via joint learning in an end-to-end way. We conduct experiment on popular benchmark ATIS. The results show that our model achieves state-of-the-art and outperforms other popular methods by a large margin in terms of both intent detection error rate and slot filling F1-score. This paper gives a new perspective for research on SLU. 摘要口语理解（SLU）通常涉及意图确定和插槽填充，是口语对话系统的核心组成部分。鉴于插槽标签和意图应该彼此分享知识，联合学习已经证明在SLU中是有效的。然而，大多数现有的联合学习方法仅考虑通过在表面水平而不是语义水平上共享参数来进行联合学习。在这项工作中，我们提出了一种新的具有门机制的自注意力模型，以充分利用槽和意图之间的语义相关性。我们的模型首先基于具有自注意力机制的神经网络获得意图增强嵌入。然后将意图语义表示用作标记槽标签时的门。这两项任务的目标通过端到端的联合学习同时优化。我们在流行的基准ATIS上进行实验。结果表明，我们的模型在意图检测错误率和槽填充F1得分方面都达到了最先进的水平，并且在很大程度上优于其他流行方法。本文为SLU的研究提供了新的视角。 IntroductionOne long-term goal in artificial intelligence field is to build an intelligent human-machine dialogue system, which is capable of understanding human’s language and giving smooth and correct responses. A typical dialogue system is designed to execute the following components: (i) automatic speech recognition converts a spoken query into transcription, (ii) spoken language understanding component analyzes the transcription to extract semantic representations, (iii) dialogue manager interprets the semantic information and decides the best system action, according to which the system response is further generated either as a natural language output(Jurafsky, 2000). In this paper, we focus on spoken language understanding which is a core component of a spoken dialogue system. It typically involves two major tasks, intent determination and slot filling. Intent determination aims to automatically identify the intent of the user as expressed in natural language. Slot filling aims to extract relevant semantic constituents from the natural language sentence towards achieving a goal. Usually, intent detection and slot filling are carried out separately. However, separate modeling of these two tasks is constrained to take full advantage of all supervised signals. Joint learning of intent detection and slot filling is worthwhile for three reasons. Firstly, the two tasks usually appear simultaneously in SLU systems. Secondly, the information of one task can be utilized in the other task to promote each other and a joint prediction can be made (Zhang and Wang, 2016). For example, if the intent of a utterance is to find a fiight, it is likely to contain the departure and arrival cities, and vice versa. Lastly, slot tags and intents, as semantics representations of user behaviours, are supposed to share knowledge with each other. Recently, joint model for intent detection and slot filling has achieved much progress. (Xu and Sarikaya, 2013) proposed using CNN based triangular CRF for joint intent detection and slot filling. (Guo et al., 2014) proposed using a recursive neural network that learns hierarchical representations of the input text for the joint task. (Liu and Lane, 2016b) describes a recurrent neural network (RNN) model that jointly performs intent detection, slot filling and language modeling. The neural network models keep updating the intent prediction as word in the transcribed utterance arrives and uses it as contextual features in the joint model. In this work, we propose a novel model for joint intent determination and slot filling by introducing self-attention and gating mechanism. Our model can fully utilize the semantic correlation between slot and intent. To the best of our knowledge, this is the first attempt to utilize intent- augmented embedding as a gate to guide the learning of slot filling task. To fully evaluate the efficiency of our model, we conduct experiment on Airline Travel Information Systems (ATIS) dataset (Hemphill et al., 1990), which is popularly used as benchmark in related work. And empirical results show that our independent model outperforms the previous best result by 0.54% in terms of F1-score on slot filling task, and gives excellent performance on intent detection task. Our joint model further promotes the performance and achieves state-of-the-art results on both tasks.The rest of our paper is structured as follows: Section 2 discusses related work, Section 3 gives a detailed description of our model, Section 4 presents experiments results and analysis, and Section 5 summarizes this work and the future direction. 介绍人工智能领域的一个长期目标是建立一个智能的人机对话系统，它能够理解人类的语言，并提供顺畅和正确的反应。典型的对话系统被设计为执行以下组件：（i）自动语音识别将口头查询转换为录音文本，（ii）口语理解组件分析录音文本以提取语义表示，（iii）对话管理器解释语义信息和决定最佳系统动作，根据该动作，系统进一步生成自然语言相应（Jurafsky，2000）。 在本文中，我们关注口语理解，这是口语对话系统的核心组成部分。它通常涉及两个主要任务，即意图确定和槽填充。意图确定旨在自动识别用自然语言表达的用户意图。槽填充旨在从自然语言句子中提取相关的语义成分以实现目标。 通常，意图检测和槽填充是分开进行的。然而，这两个任务的单独建模受限于充分利用所有监督信号。意图检测和插槽填充的联合学习是值得的，原因有三个。首先，这两个任务通常同时出现在SLU系统中。其次，一个任务的信息可以用于另一个任务中以相互促进，并且可以进行联合预测（Zhang和Wang，2016）。例如，如果话语的意图是发现航班查询，则可能包含出发和到达城市，反之亦然。最后，作为用户行为的语义表示的槽标记和意图应该彼此共享知识。 最近，用于意图检测和槽填充的联合模型已经取得了很大进展。（Xu和Sarikaya，2013）提出使用基于CNN的三角形CRF进行关节意图检测和槽填充。（Guo et al。，2014）提出使用递归神经网络来学习联合任务的输入文本的层次表示。（Liu and Lane，2016b）描述了一种递归神经网络（RNN）模型，它共同执行意图检测，槽填充和语言建模。当语音文本中的单词到达时，神经网络模型不断更新意图预测，并将其用作联合模型中的上下文特征。 在这项工作中，我们通过引入自注意力机制和门控机制提出了一种新的联合意图确定和槽填充模型。我们的模型可以充分利用插槽和意图之间的语义关联。据我们所知，这是第一次尝试利用意图增强嵌入作为指导学习插槽填充任务的门。为了充分评估我们模型的效果，我们对航空旅行信息系统（ATIS）数据集（Hemphill等，1990）进行了实验，该数据集被广泛用作相关工作的基准。实证结果表明，我们的独立模型在插槽填充任务的F1得分方面优于先前的最佳结果0.54％，并且在意图检测任务方面表现出色。我们的联合模型进一步提升了性能，并在这两项任务中实现了最先进的结果。 本文的其余部分结构如下：第2节讨论相关工作，第3节详细描述了我们的模型，第4节介绍了实验结果和分析，第5节总结了这项工作和未来的方向。 Related WorkThere is a long research history for spoken dialogue understanding, which emerged in the 1990s from some call classification systems (Gorin et al., 1997) and the ATIS project. In this section, we describe some typical works on intent classification and slot-filling, which are both core tasks of SLU (De Mori, 2007). For intent detection task, the early traditional method is to employ n-grams as features with generic entities, such as locations and dates (Zhang and Wang, 2016). This type of method is restricted to the dimensionality of the input space. Another line of popular approaches is to train machine learning models on labeled training data (Young, 2002; Hahn et al., 2011). For example, SVM (Haffner et al., 2003) and Adaboost (Schapire and Singer, 2000) have been explored to improve intent detection. Approaches based on neural network architecture have shown good performance on intent detection task. Deep belief networks (DBNs) have been first used in call routing classification (Deoras and Sarikaya, 2013). More recently, RNNs have shown excellent performance on the intent classification task (Ravuri and Stol- cke, 2015). For slot-filling task, traditional approaches are based on conditional random fields (CRF) architecture, which has strong ability on sequence labelling (Raymond and Riccardi, 2007). Recently, models based on neural network and its extensions have shown excellent performance on the slot filling task and outperform traditional CRF models. For example, (Yao et al., 2013) proposed to take words as input in a standard recurrent neural network language model, and then to predict slot labels rather than words on the output side. (Yao et al., 2014b) improved RNNs by using transition features and the sequence-level optimization criterion of CRF to explicitly model dependencies of output labels. (Mesnil et al., 2013) tried bi-directional and hybrid RNN to investigate using RNN for slot filling. (Yao et al., 2014a) introduced LSTM architecture for this task and obtained a marginal improvement over RNN. Besides, following the success of attention based models in the NLP field, (Simonnet et al., 2015) applied the attention-based encoder-decoder to the slot filling task, but without LSTM cells. Recently, there has been some work on learning intent detection and slot filling jointly exploited by neural networks. Slot labels and intents, as semantics of user behaviors, are supposed to share knowledge with each other. (Guo et al., 2014) adapted recursive neural networks (RNNs) for joint training of intent detection and slot filling. (Xu and Sarikaya, 2013) described a joint model for intent detection and slot filling based on convolutional neural networks (CNN). The proposed architecture can be perceived as a neural network version of the triangular CRF model (Tri- CRF). (Hakkani-Tur et al. ¨ , 2016) proposed a single recurrent neural network architecture that integrates the three tasks (domain detection, intent detection and slot filling for multiple domains) in a model. (Liu and Lane, 2016a) proposed an attention-based neural network model for joint intent detection and slot filling. Their joint model got the best performance of 95.98% slot filling F1-score and 1.57% intent error rate in the ATIS dataset. Despite the great progress those methods have achieved, it is still a challenging and open task for intent detection and slot filling. Therefore, we are motivated to design a powerful model, which can improve the performance of SLU systems. 相关工作对于口语对话理解有着悠久的研究历史，在20世纪90年代由一些呼叫分类系统（Gorin等，1997）和ATIS项目出现。在本节中，我们描述了一些关于意图分类和槽填充的典型工作，它们都是SLU的核心任务（De Mori，2007）。 对于意图检测任务，早期的传统方法是使用n-gram作为通用实体的特征，例如位置和日期（Zhang和Wang，2016）。这种方法仅限于输入空间的维度。另一种流行的方法是在标记的训练数据上训练机器学习模型（Young，2002; Hahn等，2011）。例如，已经探索了SVM（Haffner等人，2003）和Adaboost（Schapire和Singer，2000）以改进意图检测。基于神经网络架构的方法已经在意图检测任务上表现出良好的性能。深度信任网络（DBN）首先被用于呼叫路由分类（Deoras和Sarikaya，2013）。最近，RNN在意图分类任务中表现出色（Ravuri和Stolke，2015）。 对于槽填充任务，传统方法基于条件随机场（CRF）架构，其具有强大的序列标记能力（Raymond和Riccardi，2007）。最近，基于神经网络及其扩展的模型在插槽填充任务中表现出优异的性能，并且优于传统的CRF模型。例如，（Yao et al。，2013）提出在标准递归神经网络语言模型中将单词作为输入，然后预测槽标签而不是输出侧的单词。（Yao等，2014b）通过使用录音文本和CRF的序列级优化标准来明确地模拟输出标签的依赖性来改进RNN。（Mesnil等，2013）尝试使用双向和混合RNN来研究使用RNN进行槽填充。（Yao et al。，2014a）为此任务引入了LSTM架构，并获得了对RNN的微小改进。此外，随着NLP领域基于注意力的模型的成功，（Simonnet等，2015）将基于注意力的编码器-解码器应用于槽填充任务，但没有LSTM单元。 最近，在神经网络共同利用的学习意图检测和槽填充方面已经有了一些工作。作为用户行为的语义，槽标签和意图应该彼此共享知识。（Guo et al。，2014）改进了递归神经网络（RNN），用于意图检测和槽填充的联合训练。（Xu和Sarikaya，2013）描述了基于卷积神经网络（CNN）的意图检测和槽填充的联合模型。所提出的架构可以被视为三角形CRF模型（Tri-CRF）的神经网络版本。（Hakkani-Tur等人，2016）提出了一种单一的递归神经网络架构，它将模型中的三个任务（域检测，意图检测和多个域的槽填充）集成在一起。（Liu and Lane，2016a）提出了一种基于注意力的神经网络模型，用于关节意图检测和槽填充。他们的联合模型在ATIS数据集中获得了95.98％槽位填充F1得分和1.57％意向错误率的最佳表现。 尽管这些方法已经取得了很大的进展，但对于意图检测和插槽查找仍然是一项具有挑战性和开放性的任务。因此，我们有动机设计一个强大的模型，以提高SLU系统的性能。 Self-Attention_with_Gate_Mechanism 标题 说明 时间 A Self-Attentive Model with Gate Mechanism for Spoken Language Understanding 论文原文 2018 Improving Slot Filling in Spoken Language Understanding with Joint Pointer and Attention We present a generative neural network model for slot filling based on a sequence- to-sequence (Seq2Seq) model together with a pointer network, in the situation where only sentence-level slot annotations are available in the spoken dialogue data. This model predicts slot values by jointly learning to copy a word which may be out-of-vocabulary (OOV) from an input utterance through a pointer network, or generate a word within the vocabulary through an attentional Seq2Seq model. Experimental results show the effectiveness of our slot filling model, especially at addressing the OOV problem. Additionally, we integrate the proposed model into a spoken language understanding system and achieve the state-of-the-art performance on the benchmark data. 标题 说明 时间 Improving Slot Filling in Spoken Language Understanding with Joint Pointer and Attention 论文原文 2019 BERT for Joint Intent Classification and Slot Filling Intent classification and slot filling are two essential tasks for natural language understanding. They often suffer from small-scale human-labeled training data, resulting in poor generalization capability, especially for rare words. Recently a new language representation model, BERT (Bidirectional Encoder Representations from Transformers), facilitates pre-training deep bidirectional representations on large-scale unlabeled corpora, and has created state-of-the-art models for a wide variety of natural language processing tasks after simple fine-tuning. However, there has not been much effort on exploring BERT for natural language understanding. In this work, we propose a joint intent classification and slot filling model based on BERT. Experimental results demonstrate that our proposed model achieves significant improvement on intent classification accuracy, slot filling F1, and sentence-level semantic frame accuracy on several public benchmark datasets, compared to the attention-based recurrent neural network models and slot-gated models. 意图分类和插槽填充是自然语言理解的两个基本任务。他们经常遭受小规模的人类标记训练数据，导致泛化能力差，特别是对于罕见的单词。最近，一种新的语言表示模型BERT（来自Transformer的双向编码器表示）有助于在大型无标签语料库上预训练深度双向表示，并为各种自然语言处理任务创建了最先进的模型。经过简单的微调。然而，在探索自然语言理解的BERT方面并没有太多的努力。在这项工作中，我们提出了一个基于BERT的联合意图分类和槽填充模型。实验结果表明，与基于注意力的递归神经网络模型和槽门控模型相比，我们提出的模型在几个公共基准数据集上实现了意图分类准确性，槽填充F1和句子级语义框架准确性的显着改善。 2019 A Novel Bi-directional Interrelated Model for Joint Intent Detection and Slot Filling A spoken language understanding (SLU) system includes two main tasks, slot filling (SF) and intent detection (ID). The joint model for the two tasks is becoming a tendency in SLU. But the bi-directional interrelated connections between the intent and slots are not established in the existing joint models. In this paper, we propose a novel bi-directional interrelated model for joint intent detection and slot filling. We introduce an SF-ID network to establish direct connections for the two tasks to help them promote each other mutually. Besides, we design an entirely new iteration mechanism inside the SF-ID network to enhance the bi-directional interrelated connections. The experimental results show that the relative improvement in the sentence-level semantic frame accuracy of our model is 3.79% and 5.42% on ATIS and Snips datasets, respectively, compared to the state-of-the-art model. 口语理解（SLU）系统包括两个主要任务，槽填充（SF）和意图检测（ID）。这两个任务的联合模型正在成为SLU中的一种趋势。但是，现有联合模型中未建立意图和槽之间的双向关联连接。在本文中，我们提出了一种新的双向关联模型，用于联合意图检测和槽填充。我们引入了SF-ID网络来为这两项任务建立直接连接，以帮助它们相互促进。此外，我们在SF-ID网络内部设计了一种全新的迭代机制，以增强双向相互关联的连接。实验结果表明，与最新模型相比，在ATIS和Snips数据集上，我们模型的句子级语义框架准确性分别提高了3.79％和5.42％。 代码：SF-ID-Network-For-NLU 2019 Multi-Task Networks With Universe, Group, and Task Feature Learning We present methods for multi-task learning that take advantage of natural groupings of related tasks. Task groups may be defined along known properties of the tasks, such as task domain or language. Such task groups represent supervised information at the inter-task level and can be encoded into the model. We investigate two variants of neural network architectures that accomplish this, learning different feature spaces at the levels of individual tasks, task groups, as well as the universe of all tasks: (1) parallel architectures encode each input simultaneously into feature spaces at different levels; (2) serial architectures encode each input successively into feature spaces at different levels in the task hierarchy. We demonstrate the methods on natural language understanding (NLU) tasks, where a grouping of tasks into different task domains leads to improved performance on ATIS, Snips, and a large inhouse dataset. ACL 2019 对话系统论文综述，一文带你纵览 16 篇前沿研究]]></content>
      <categories>
        <category>论文</category>
        <category>口语理解</category>
      </categories>
      <tags>
        <tag>论文</tag>
        <tag>意图识别</tag>
        <tag>槽填充</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[神经机器翻译 | Neural Machine Translation]]></title>
    <url>%2F2019%2F03%2F01%2F%E7%A5%9E%E7%BB%8F%E6%9C%BA%E5%99%A8%E7%BF%BB%E8%AF%91%2F</url>
    <content type="text"><![CDATA[标题 说明 时间 Transformer_implementation_and_application 完整复现了Transformer模型，并且应用在神经机器翻译任务和聊天机器人上。 持续更新 Tensor2Tensor TensorFlow 库，非常系统的神经机器翻译讲解 持续更新 Neural Machine Translation (seq2seq) Tutorial TensorFlow 库 持续更新 OpenNMT-tf 哈佛机器翻译库 持续更新 习翔宇 深度学习、传统机器学习、自然语言处理算法及实现 Visualizing A Neural Machine Translation Model (Mechanics of Seq2seq Models With Attention) 可视化神经机器翻译模型，动态图和视频结合讲解，十分透彻 Neural Machine Translation (seq2seq) TutorialWMT English-German &mdash; Full ComparisonThe first 2 rows are our models with GNMTattention:model 1 (4 layers),model 2 (8 layers). Systems newstest2014 newstest2015 Ours &mdash; NMT + GNMT attention (4 layers) 23.7 26.5 Ours &mdash; NMT + GNMT attention (8 layers) 24.4 27.6 WMT SOTA 20.6 24.9 OpenNMT (Klein et al., 2017) 19.3 - tf-seq2seq (Britz et al., 2017) 22.2 25.2 GNMT (Wu et al., 2016) 24.6 - The above results show our models are very competitive among models of similar architectures.\[Note that OpenNMT uses smaller models and the current best result (as of this writing) is 28.4 obtained by the Transformer network (Vaswani et al., 2017) which has a significantly different architecture.] Other details for better NMT modelsBidirectional RNNsBidirectionality on the encoder side generally gives better performance (withsome degradation in speed as more layers are used). Here, we give a simplifiedexample of how to build an encoder with a single bidirectional layer: 12345678# Construct forward and backward cellsforward_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units)backward_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units)bi_outputs, encoder_state = tf.nn.bidirectional_dynamic_rnn( forward_cell, backward_cell, encoder_emb_inp, sequence_length=source_sequence_length, time_major=True)encoder_outputs = tf.concat(bi_outputs, -1) The variables encoder_outputs and encoder_state can be used in the same wayas in Section Encoder. Note that, for multiple bidirectional layers, we need tomanipulate the encoder_state a bit, see model.py, method_build_bidirectional_rnn() for more details. Beam searchWhile greedy decoding can give us quite reasonable translation quality, a beamsearch decoder can further boost performance. The idea of beam search is tobetter explore the search space of all possible translations by keeping around asmall set of top candidates as we translate. The size of the beam is calledbeam width; a minimal beam width of, say size 10, is generally sufficient. Formore information, we refer readers to Section 7.2.3of Neubig, (2017). Here’s an example of howbeam search can be done: OpenNMT-tfOpenNMT-tf is a general purpose sequence learning toolkit using TensorFlow. While neural machine translation is the main target task, it has been designed to more generally support: sequence to sequence mapping sequence tagging sequence classification The project is production-oriented and comes with stability guarantees. Key featuresOpenNMT-tf focuses on modularity to support advanced modeling and training capabilities: arbitrarily complex encoder architecturese.g. mixing RNNs, CNNs, self-attention, etc. in parallel or in sequence. hybrid encoder-decoder modelse.g. self-attention encoder and RNN decoder or vice versa. neural source-target alignmenttrain with guided alignment to constrain attention vectors and output alignments as part of the translation API. multi-source traininge.g. source text and Moses translation as inputs for machine translation. multiple input formattext with support of mixed word/character embeddings or real vectors serialized in TFRecord files. on-the-fly tokenizationapply advanced tokenization dynamically during the training and detokenize the predictions during inference or evaluation. domain adaptationspecialize a model to a new domain in a few training steps by updating the word vocabularies in checkpoints. automatic evaluationsupport for saving evaluation predictions and running external evaluators (e.g. BLEU). mixed precision trainingtake advantage of the latest NVIDIA optimizations to train models with half-precision floating points. and all of the above can be used simultaneously to train novel and complex architectures. See the predefined models to discover how they are defined and the API documentation to customize them.]]></content>
      <categories>
        <category>论文</category>
        <category>神经机器翻译</category>
      </categories>
      <tags>
        <tag>神经机器翻译</tag>
        <tag>NMT</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[注意力机制]]></title>
    <url>%2F2019%2F02%2F28%2F%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6%2F</url>
    <content type="text"><![CDATA[Attention是一种用于提升基于RNN（LSTM或GRU）的Encoder + Decoder模型的效果的的机制（Mechanism），一般称为Attention Mechanism。Attention Mechanism目前非常流行，广泛应用于机器翻译、语音识别、图像标注（Image Caption）等很多领域，之所以它这么受欢迎，是因为Attention给模型赋予了区分辨别的能力，例如，在机器翻译、语音识别应用中，为句子中的每个词赋予不同的权重，使神经网络模型的学习变得更加灵活（soft），同时Attention本身可以做为一种对齐关系，解释翻译输入/输出句子之间的对齐关系，解释模型到底学到了什么知识，为我们打开深度学习的黑箱，提供了一个窗口。 注意，随着研究的深入，注意力的概念已经发生了变化，上述内容只是注意力中的一种而已。 Attention机制中的打分函数 相关资源 标题 说明 时间 注意力的动画解析（以机器翻译为例） 原文Attn: Illustrated Attention 20190208 模型汇总24 - 深度学习中Attention Mechanism详细介绍：原理、分类及应用 首推 知乎 2017 目前主流的attention方法都有哪些？ attention机制详解 知乎 2017 Neural Machine Translation (seq2seq) Tutorial GitHub 以机器翻译为例讲解注意力机制 长期更新 Attention_Network_With_Keras 注意力模型的代码的实现与分析 代码解析 简书 20180617 Attention_Network_With_Keras 代码实现 GitHub 2018 各种注意力机制窥探深度学习在NLP中的神威 综述 机器之心 20181008 Why Self-Attention? A Targeted Evaluation of Neural Machine Translation Architectures 为什么使用自注意力机制？ 实验结果证明：1）自注意力网络和 CNN 在建模长距离主谓一致时性能并不优于 RNN；2）自注意力网络在词义消歧方面显著优于 RNN 和 CNN。 20180827 各种注意力总结 本文主要是总结：注意力机制、注意力机制的变体、论文中常见的注意力 20180325 注意力机制分类全局注意力机制 局部注意力机制 自注意力机制 隐藏向量 $h_t$ 首先会传递到全连接层。然后校准系数 $a_t$ 会对比全连接层的输出 $u_t$ 和可训练上下文向量 u（随机初始化），并通过 Softmax 归一化而得出。注意力向量 s 最后可以为所有隐藏向量的加权和。上下文向量可以解释为在平均上表征的最优单词。但模型面临新的样本时，它会使用这一知识以决定哪一个词需要更加注意。在训练中，模型会通过反向传播更新上下文向量，即它会调整内部表征以确定最优词是什么。 Self Attention与传统的Attention机制非常的不同：传统的Attention是基于source端和target端的隐变量（hidden state）计算Attention的，得到的结果是源端的每个词与目标端每个词之间的依赖关系。但Self Attention不同，它分别在source端和target端进行，仅与source input或者target input自身相关的Self Attention，捕捉source端或target端自身的词与词之间的依赖关系；然后再把source端的得到的self Attention加入到target端得到的Attention中，捕捉source端和target端词与词之间的依赖关系。因此，self Attention Attention比传统的Attention mechanism效果要好，主要原因之一是，传统的Attention机制忽略了源端或目标端句子中词与词之间的依赖关系，相对比，self Attention可以不仅可以得到源端与目标端词与词之间的依赖关系，同时还可以有效获取源端或目标端自身词与词之间的依赖关系 层级注意力机制 在该架构中，自注意力机制共使用了两次：在词层面与在句子层面。该方法因为两个原因而非常重要，首先是它匹配文档的自然层级结构（词——句子——文档）。其次在计算文档编码的过程中，它允许模型首先确定哪些单词在句子中是非常重要的，然后再确定哪个句子在文档中是非常重要的。 相关论文以2014《Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation》抛砖引玉要介绍Attention Mechanism结构和原理，首先需要介绍下Seq2Seq模型的结构。基于RNN的Seq2Seq模型主要由两篇论文介绍，只是采用了不同的RNN模型。Ilya Sutskever等人与2014年在论文《Sequence to Sequence Learning with Neural Networks》中使用LSTM来搭建Seq2Seq模型。随后，2015年，Kyunghyun Cho等人在论文《Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation》提出了基于GRU的Seq2Seq模型。两篇文章所提出的Seq2Seq模型，想要解决的主要问题是，如何把机器翻译中，变长的输入X映射到一个变长输出Y的问题，其主要结构如图所示。 传统的Seq2Seq结构 其中，Encoder把一个变成的输入序列x1，x2，x3….xt编码成一个固定长度隐向量（背景向量，或上下文向量context）c，c有两个作用：1、做为初始向量初始化Decoder的模型，做为decoder模型预测y1的初始向量。2、做为背景向量，指导y序列中每一个step的y的产出。Decoder主要基于背景向量c和上一步的输出yt-1解码得到该时刻t的输出yt，直到碰到结束标志（$$）为止。 如上文所述，传统的Seq2Seq模型对输入序列X缺乏区分度，因此，2015年，Kyunghyun Cho等人在论文《Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation》中，引入了Attention Mechanism来解决这个问题，他们提出的模型结构如图所示。 Attention Mechanism模块图解 Neural Machine Translation by Jointly Learning to Align and Translate Effective Approaches to Attention-based Neural Machine Translation Effective Approaches to Attention-based Neural Machine Translation 中英文对照翻译 可视化神经机器翻译模型Visualizing A Neural Machine Translation Model (Mechanics of Seq2seq Models With Attention)]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>注意力机制</tag>
        <tag>Attention Mechanism</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[DiSAN Directional Self-Attention Network for RNN_CNN-Free Language Understanding]]></title>
    <url>%2F2019%2F02%2F18%2FDiSAN%20Directional%20Self-Attention%20Network%20for%20RNN_CNN-Free%20Language%20Understanding%2F</url>
    <content type="text"><![CDATA[标题 说明 时间 DiSAN: Directional Self-Attention Network for RNN/CNN-Free Language Understanding 原始论文 20171120 DiSAN: Directional Self-Attention Network for RNN/CNN-Free Language Understanding 官方实现 20180508 【Papernotes】DiSAN (有向自注意力网络) 论文详解 20180507 Paper AAAI’18 DiSAN: Directional Self-Attention Network for RNN/CNN-Free Language Understanding 论文浅析和相关评论 20180715]]></content>
      <categories>
        <category>论文</category>
        <category>语言理解</category>
      </categories>
      <tags>
        <tag>论文</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Deep Semantic Role Labeling with Self-Attention]]></title>
    <url>%2F2019%2F02%2F18%2FDeep%20Semantic%20Role%20Labeling%20with%20Self-Attention%2F</url>
    <content type="text"><![CDATA[标题 说明 时间 Deep Semantic Role Labeling with Self-Attentio 原始论文 20171205 Deep Semantic Role Labeling with Self-Attentio 官方实现 20180426 Deep Semantic Role Labeling with Self-Attention 阅读笔记 论文浅析 20180326]]></content>
      <categories>
        <category>论文</category>
        <category>语义角色标注</category>
      </categories>
      <tags>
        <tag>论文</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[聊天机器人]]></title>
    <url>%2F2019%2F01%2F24%2F%E8%81%8A%E5%A4%A9%E6%9C%BA%E5%99%A8%E4%BA%BA%2F</url>
    <content type="text"><![CDATA[Dialogue 任务描述、数据资源和相关论文 最新内容 to dialogue Dialogue众所周知，对话难以评估。过去的方法使用了人类评估。Dialogue act classification Dialogue act classification is the task of classifying an utterance with respect to the fuction it serves in a dialogue, i.e. the act the speaker is performing. Dialogue acts are a type of speech acts (for Speech Act Theory, see Austin (1975) and Searle (1969)). Switchboard corpusThe Switchboard-1 corpus is a telephone speech corpus, consisting of about 2,400 two-sided telephone conversation among 543 speakers with about 70 provided conversation topics. The dataset includes the audio files and the transcription files, as well as information about the speakers and the calls. The Switchboard Dialogue Act Corpus (SwDA) [download] extends the Switchboard-1 corpus with tags from the SWBD-DAMSL tagset, which is an augmentation to the Discourse Annotation and Markup System of Labeling (DAMSL) tagset. The 220 tags were reduced to 42 tags by clustering in order to improve the language model on the Switchboard corpus. A subset of the Switchboard-1 corpus consisting of 1155 conversations was used. The resulting tags include dialogue acts like statement-non-opinion, acknowledge, statement-opinion, agree/accept, etc.Annotated example:Speaker: A, Dialogue Act: Yes-No-Question, Utterance: So do you go to college right now? Model Accuracy Paper / Source Code CRF-ASN (Chen et al., 2018) 81.3 Dialogue Act Recognition via CRF-Attentive Structured Network Bi-LSTM-CRF (Kumar et al., 2017) 79.2 Dialogue Act Sequence Labeling using Hierarchical encoder with CRF Link RNN with 3 utterances in context (Bothe et al., 2018) 77.34 A Context-based Approach for Dialogue Act Recognition using Simple Recurrent Neural Networks ICSI Meeting Recorder Dialog Act (MRDA) corpusThe MRDA corpus [download] consists of about 75 hours of speech from 75 naturally-occurring meetings among 53 speakers. The tagset used for labeling is a modified version of the SWBD-DAMSL tagset. It is annotated with three types of information: marking of the dialogue act segment boundaries, marking of the dialogue acts and marking of correspondences between dialogue acts.Annotated example:Time: 2804-2810, Speaker: c6, Dialogue Act: s^bd, Transcript: i mean these are just discriminative.Multiple dialogue acts are separated by “^”. Model Accuracy Paper / Source Code CRF-ASN (Chen et al., 2018) 91.7 Dialogue Act Recognition via CRF-Attentive Structured Network Bi-LSTM-CRF (Kumar et al., 2017) 90.9 Dialogue Act Sequence Labeling using Hierarchical encoder with CRF Link Dialogue state trackingDialogue state tacking consists of determining at each turn of a dialogue thefull representation of what the user wants at that point in the dialogue,which contains a goal constraint, a set of requested slots, and the user’s dialogue act. Second dialogue state tracking challengeFor goal-oriented dialogue, the dataset of the second Dialogue Systems Technology Challenges(DSTC2) is a common evaluation dataset. The DSTC2 focuses on the restaurant search domain. Models areevaluated based on accuracy on both individual and joint slot tracking. Model Request Area Food Price Joint Paper / Source Zhong et al. (2018) 97.5 - - - 74.5 Global-locally Self-attentive Dialogue State Tracker Liu et al. (2018) - 90 84 92 72 Dialogue Learning with Human Teaching and Feedback in End-to-End Trainable Task-Oriented Dialogue Systems Neural belief tracker (Mrkšić et al., 2017) 96.5 90 84 94 73.4 Neural Belief Tracker: Data-Driven Dialogue State Tracking RNN (Henderson et al., 2014) 95.7 92 86 86 69 Robust dialog state tracking using delexicalised recurrent neural networks and unsupervised gate Wizard-of-OzThe WoZ 2.0 dataset is a newer dialogue state tracking dataset whose evaluation is detached from the noisy output of speech recognition systems. Similar to DSTC2, it covers the restaurant search domain and has identical evaluation. Model Request Joint Paper / Source Zhong et al. (2018) 97.1 88.1 Global-locally Self-attentive Dialogue State Tracker Neural belief tracker (Mrkšić et al., 2017) 96.5 84.4 Neural Belief Tracker: Data-Driven Dialogue State Tracking RNN (Henderson et al., 2014) 87.1 70.8 Robust dialog state tracking using delexicalised recurrent neural networks and unsupervised gate 聊天机器人框架资源 标题 说明 时间 Rasa 开源机器学习工具，供开发人员创建上下文AI助手和聊天机器人，不仅仅是回答简单的问题。官网 ChatterBot ChatterBot是一个机器学习，会话对话引擎，用于创建聊天机器人。 项目文档 DeepPavlov 用于深度学习端到端对话系统和聊天机器人的开源库。官网 我研究的聊天机器人 智能家居项目 我的代码 Hands-on-chat-robots 聊天机器人博客资源 类别 标题 说明 时间 demo Building a Simple Chatbot from Scratch in Python (using NLTK) 相关代码 20180917 APP Our experience building chatbots with Rasa — Tuning the NLU pipeline 基于 Rasa 的应用Neil - Personal Curator AI 20180710 任务型对话研究任务型对话介绍https://github.com/AtmaHou/Task-Oriented-Dialogue-Dataset-Survey 开源框架https://github.com/deepmipt/DeepPavlov Task-Oriented-Dialogue-Dataset-Survey 关于面向任务的对话的数据集调查，包括最近的数据集。 论文实现 Sequicity: Simplifying Task-oriented Dialogue Systems with Single Sequence-to-Sequence Architectures论文实现 Slot-Gated Modeling for Joint Slot Filling and Intent Prediction]]></content>
      <categories>
        <category>深度学习</category>
        <category>聊天机器人</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[Slot-Gated Modeling for Joint Slot Filling and Intent Prediction]]></title>
    <url>%2F2019%2F01%2F24%2FSlot-Gated_Modeling_for_Joint_Slot_Filling_and_Intent_Prediction%2F</url>
    <content type="text"><![CDATA[面向任务对话论文模型效果排行榜 https://github.com/AtmaHou/Task-Oriented-Dialogue-Dataset-Survey《Slot-Gated Modeling for Joint Slot Filling and Intent Prediction》 发表在NAACL HLT 2018，自然语言四大顶会之一。 Intruduction：基于Attention的RNN模型在联合意图识别(ID)和槽位填充(SF)上实现最好性能（其ID和SF的attention权重独立）。然而，其通过损失函数将两者关联只是隐式地关联。由于slot filling通常高度依赖于intent，因此本工作重点介绍如何通过引入插槽选通机制来模拟slot和intent向量之间的显式关系。本文提出slot gate结构，其关注于学习intent和slot attention向量之间的关系，通过全局优化获得更好的semantic frame。通过在ATIS和Snips数据集实验，相比于attention模型semantic frame准确率相对提升了4.2%。 创新点： 提出slot-gate方法实现了最好的性能表现。 通过数据集实验表明slot-gate的有效性。 slot-gate有助于分析槽位和意图的关系。 论文主要公式： 论文代码解析图： 更多内容见 yuanxiaosc/Slot-Gated-Modeling-for-Joint-Slot-Filling-and-Intent-Prediction 论文相关资源 标题 说明 时间 Slot-Gated Modeling for Joint Slot Filling and Intent Prediction 论文原文 2018 论文实现 Code 原作者实现 2018 Slot-Gated Modeling for Joint Slot Filling and Intent Prediction Helic He 解读 20181203 『 论文阅读』Slot-Gated Modeling for Joint Slot Filling and Intent Prediction 立刻有 20181014 相关论文Attention-Based Recurrent Neural Network Models for Joint Intent Detection and Slot Filling解读 立刻有 20181014 【论文阅读】Slot-Gated Modeling for Joint Slot Filling and Intent Prediction iMayday_hui；代码解读 20181121 《用于槽填充和意图检测的slot-gates模型》阅读笔记 战先生 20181105 论文改进：增加 CRF 输出层代码 Joint-NLU 实验结果 ATIS数据集 crf softmax Slot f1 val: 97.39 ; test: 95.15 val: 97.0; test:95.08 Intent Acc val: 98.2; test: 95.41 val: 97.6; test: 95.52 Semantic Acc val: 90.0; test: 83.42 val: 89.0 ; test: 83.53]]></content>
      <categories>
        <category>论文</category>
        <category>口语理解</category>
      </categories>
      <tags>
        <tag>Dialogue</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Pycharm]]></title>
    <url>%2F2019%2F01%2F22%2FPycharm%2F</url>
    <content type="text"><![CDATA[16步Pycharm连接远程服务器，开始远程代码编写注意有时需要在第3步后点击，Project Interpreter 前面的小三角通过以上 16 步，已经实现本地文件与服务器文件的同步，现在可以在本地写一个测试文件试试了！ 随时查看远程和本地文件在Pycharm 最上面一栏中依次选择 Tools &gt; deployment &gt; Brows Remote Host，然后看到：默认情况下，这里讲显示远程服务器根目录的文件，为了便于对比远程文件和本地文件，做如下设置：选择文件夹为 “16步Pycharm连接远程服务器，开始远程代码编写” 中第15步填写的那个文件夹。由于此时根目录改变了（Root path），注意同步修改，本地文件与服务器映射文件关系。]]></content>
      <categories>
        <category>技能</category>
        <category>Pycharm</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[flair]]></title>
    <url>%2F2019%2F01%2F18%2Fflair%2F</url>
    <content type="text"><![CDATA[flairA very simple framework for state-of-the-art Natural Language Processing (NLP)Flair is: A powerful NLP library. Flair allows you to apply our state-of-the-art natural language processing (NLP)models to your text, such as named entity recognition (NER), part-of-speech tagging (PoS),sense disambiguation and classification. Multilingual. Thanks to the Flair community, we support a rapidly growing number of languages. We also now include‘one model, many languages‘ taggers, i.e. single models that predict PoS or NER tags for input text in various languages. A text embedding library. Flair has simple interfaces that allow you to use and combine different word anddocument embeddings, including our proposed Flair embeddings, BERT embeddings and ELMo embeddings. A Pytorch NLP framework. Our framework builds directly on Pytorch, making it easy totrain your own models and experiment with new approaches using Flair embeddings and classes. Now at version 0.4.0! Comparison with State-of-the-Art复现论文结果 How to Reproduce Experiments Flair outperforms the previous best methods on a range of NLP tasks: Task Language Dataset Flair Previous best Named Entity Recognition English Conll-03 93.09 (F1) 92.22 (Peters et al., 2018) Named Entity Recognition English Ontonotes 89.71 (F1) 86.28 (Chiu et al., 2016) Emerging Entity Detection English WNUT-17 50.20 (F1) 45.55 (Aguilar et al., 2018) Part-of-Speech tagging English WSJ 97.85 97.64 (Choi, 2016) Chunking English Conll-2000 96.72 (F1) 96.36 (Peters et al., 2017) Named Entity Recognition German Conll-03 88.32 (F1) 78.76 (Lample et al., 2016) Named Entity Recognition German Germeval 84.65 (F1) 79.08 (Hänig et al, 2014) Named Entity Recognition Polish PolEval-2018 86.6 (F1) (Borchmann et al., 2018) 85.1 (PolDeepNer) flair 各种词嵌入的使用flair 包含普通的 Glove 词嵌入；字符嵌入；自带的 flair 嵌入；第三方嵌入： ELMo 嵌入、BERT嵌入。注意每一种嵌入又分为具体多种小种类可以使用，以下代码仅仅举例，更多用法见 flair 说明文档。 123456789101112131415161718192021222324252627282930313233343536from flair.embeddings import StackedEmbeddingsfrom flair.embeddings import WordEmbeddingsfrom flair.embeddings import CharacterEmbeddingsfrom flair.embeddings import FlairEmbeddingsfrom flair.embeddings import BertEmbeddingsfrom flair.embeddings import ELMoEmbeddings#Classic Word Embeddings# init embeddingglove_embedding = WordEmbeddings('glove')#Character Embeddings# init embeddingembedding = CharacterEmbeddings()#Flair Embeddings# init embeddingflair_embedding_forward = FlairEmbeddings('news-forward')flair_backward = FlairEmbeddings('news-backward')#Recommended Flair Usage# create a StackedEmbedding object that combines glove and forward/backward flair embeddingsstacked_embeddings = StackedEmbeddings([ WordEmbeddings('glove'), FlairEmbeddings('news-forward'), FlairEmbeddings('news-backward'), ])#BERT Embeddings# init embeddingbert_embedding = BertEmbeddings('bert-base-uncased')#ELMo Embeddings# init embeddingelmo_embedding = ELMoEmbeddings('original')]]></content>
      <tags>
        <tag>深度学习框架</tag>
        <tag>Pytorch</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Sequence_to_Sequence研究]]></title>
    <url>%2F2019%2F01%2F09%2FSequence_to_Sequence%E7%A0%94%E7%A9%B6%2F</url>
    <content type="text"><![CDATA[fairseqfairseq 是一个序列建模工具包，允许研究人员和开发人员为翻译、摘要、语言建模和其他文本生成任务培训自定义模型。它提供了各种序列到序列模型的参考实现。]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>seq2seq</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[机器翻译]]></title>
    <url>%2F2019%2F01%2F09%2F%E6%9C%BA%E5%99%A8%E7%BF%BB%E8%AF%91%2F</url>
    <content type="text"><![CDATA[Machine translationMachine translation is the task of translating a sentence in a source language to a different target language. Results with a * indicate that the mean test score over the the best window based on average dev-set BLEU score over21 consecutive evaluations is reported as in Chen et al. (2018). 以下数据来自 NLP-progress WMT 2014 EN-DEModels are evaluated on the English-German dataset of the Ninth Workshop on Statistical Machine Translation (WMT 2014) basedon BLEU. Model BLEU Paper / Source Transformer Big + BT (Edunov et al., 2018) 35.0 Understanding Back-Translation at Scale DeepL 33.3 DeepL Press release Transformer Big (Ott et al., 2018) 29.3 Scaling Neural Machine Translation RNMT+ (Chen et al., 2018) 28.5* The Best of Both Worlds: Combining Recent Advances in Neural Machine Translation Transformer Big (Vaswani et al., 2017) 28.4 Attention Is All You Need Transformer Base (Vaswani et al., 2017) 27.3 Attention Is All You Need MoE (Shazeer et al., 2017) 26.03 Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer ConvS2S (Gehring et al., 2017) 25.16 Convolutional Sequence to Sequence Learning WMT 2014 EN-FRSimilarly, models are evaluated on the English-French dataset of the Ninth Workshop on Statistical Machine Translation (WMT 2014) basedon BLEU. Model BLEU Paper / Source DeepL 45.9 DeepL Press release Transformer Big + BT (Edunov et al., 2018) 45.6 Understanding Back-Translation at Scale Transformer Big (Ott et al., 2018) 43.2 Scaling Neural Machine Translation RNMT+ (Chen et al., 2018) 41.0* The Best of Both Worlds: Combining Recent Advances in Neural Machine Translation Transformer Big (Vaswani et al., 2017) 41.0 Attention Is All You Need MoE (Shazeer et al., 2017) 40.56 Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer ConvS2S (Gehring et al., 2017) 40.46 Convolutional Sequence to Sequence Learning Transformer Base (Vaswani et al., 2017) 38.1 Attention Is All You Need 我的研究Facebook AI fairseq对应的论文 2017《Convolutional Sequence to Sequence Learning》 序列到序列学习的普遍方法通过递归神经网络将输入序列映射到可变长度输出序列。 我们介绍一种完全基于卷积神经网络的架构。 与循环模型相比，在训练期间可以完全并行化所有元素的计算，并且由于非线性的数量是固定的并且与输入长度无关，因此优化更容易。 我们使用门控线性单元简化了梯度传播，我们为每个解码器层配备了一个单独的注意模块。 我们的表现优于Wu等人的深LSTM设置的准确性。 （2016）关于WMT’14英语 - 德语和WMT’14英语 - 法语翻译，在GPU和CPU上的速度都快了一个数量级。 使用该框架预训练的模型，顺利跑完实验。官方提示使用方法：1234567891011121314$ curl https://s3.amazonaws.com/fairseq-py/models/wmt14.v2.en-fr.fconv-py.tar.bz2 | tar xvjf - -C data-bin$ curl https://s3.amazonaws.com/fairseq-py/data/wmt14.v2.en-fr.newstest2014.tar.bz2 | tar xvjf - -C data-bin$ python generate.py data-bin/wmt14.en-fr.newstest2014 \ --path data-bin/wmt14.en-fr.fconv-py/model.pt \ --beam 5 --batch-size 128 --remove-bpe | tee /tmp/gen.out...| Translated 3003 sentences (96311 tokens) in 166.0s (580.04 tokens/s)| Generate test with beam=5: BLEU4 = 40.83, 67.5/46.9/34.4/25.5 (BP=1.000, ratio=1.006, syslen=83262, reflen=82787)# Scoring with score.py:$ grep ^H /tmp/gen.out | cut -f3- &gt; /tmp/gen.out.sys$ grep ^T /tmp/gen.out | cut -f2- &gt; /tmp/gen.out.ref$ python score.py --sys /tmp/gen.out.sys --ref /tmp/gen.out.refBLEU4 = 40.83, 67.5/46.9/34.4/25.5 (BP=1.000, ratio=1.006, syslen=83262, reflen=82787) 翻译过来就是： 下载模型和语料并且解压； 设置超参数运行模型，python generate.py data-bin/wmt14.en-fr.newstest2014 \—path data-bin/wmt14.en-fr.fconv-py/model.pt \—beam 5 —batch-size 128 —remove-bpe | tee /tmp/gen.out 运行 score.py 评测模型效果； 自己运行结果与官方结果一致，除了我慢了300多倍，实验室只有一台CPU服务器还N多人一起用，伤不起！]]></content>
      <categories>
        <category>实验</category>
      </categories>
      <tags>
        <tag>机器翻译</tag>
        <tag>machine translation</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[主题模型 Topic Modeling with LSA, PLSA, LDA and lda2Vec]]></title>
    <url>%2F2019%2F01%2F07%2F%E4%B8%BB%E9%A2%98%E6%A8%A1%E5%9E%8B%2F</url>
    <content type="text"><![CDATA[Topic Modeling with LSA, PLSA, LDA &amp; lda2Vec本文是主题建模及其相关技术的综合概述。]]></content>
      <categories>
        <category>机器学习</category>
        <category>主题模型</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[Embedding 和语言模型 LanguageModel]]></title>
    <url>%2F2019%2F01%2F07%2F%E8%AF%8D%E5%B5%8C%E5%85%A5Embedding%E5%92%8C%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8BLanguageModel%2F</url>
    <content type="text"><![CDATA[必读语言模型推荐Github PLMpapers Must-read Papers on pre-trained language models. 词语嵌入和语言模型基本概念 动手体验词嵌入 http://projector.tensorflow.org/ 为什么要使用Word Embedding在信号处理领域，图像和音频信号的输入往往是表示成高维度、密集的向量形式，在图像和音频的应用系统中，如何对输入信息进行编码(Encoding)显得非常重要和关键，这将直接决定了系统的质量。然而，在自然语言处理领域中，传统的做法是将词表示成离散的符号，例如将 [cat] 表示为 [Id537]，而 [dog] 表示为 [Id143]。这样做的缺点在于，没有提供足够的信息来体现词语之间的某种关联，例如尽管cat和dog不是同一个词，但是却应该有着某种的联系（如都是属于动物种类）。由于这种一元表示法(One-hot Representation)使得词向量过于稀疏，所以往往需要大量的语料数据才能训练出一个令人满意的模型。而Word Embedding技术则可以解决上述传统方法带来的问题。 推荐阅读Word2vec的文章 The Illustrated Word2vec 对比表示文本的各种方法机器学习模型将矢量（数字数组）作为输入。在处理文本时，我们必须做的第一件事就是在将字符串转换为数字之前将字符串转换为数字（或“向量化”文本），然后再将其提供给模型。在本节中，我们将介绍这样做的三种策略。 One-hot encodings作为第一个想法，我们可能会“One-hot”地编码我们词汇表中的每个单词。考虑句子“The cat sat on the mat”。 这句话中的词汇（或唯一的单词）是（cat，mat，on，sat，the）。为了表示每个单词，我们将创建一个长度等于词汇表的零向量，然后在与该单词对应的索引中设置为一。 此方法如下图所示。为了创建包含句子编码的向量，我们可以连接每个单词的One-hot向量。 缺点：这种方法效率低下。 One-hot编码矢量是稀疏的（意味着，大多数indicices为零）。想象一下，我们在词汇表中有10,000个单词。为了对每个单词进行One-hot编码，我们将创建一个向量，其中99.99％的元素为零。 使用唯一编号对每个单词进行编码我们可能尝试的第二种方法是使用唯一编号对每个单词进行编码。继续上面的例子，我们可以将1分配给“cat”，将2分配给“mat”，依此类推。然后我们可以将句子“The cat sat on the mat”编码为像[5,1,4,3,5,2]这样的密集向量。这个应用程序是有效的。我们现在有一个密集的（所有元素都已满），而不是稀疏的向量。 但是，这种方法有两个缺点： 整数编码是任意的（它不捕获单词之间的任何关系）。 对于要解释的模型，整数编码可能具有挑战性。例如，线性分类器为每个特征学习单个权重。因为任何两个单词的相似性与其编码的相似性之间没有关系，所以这个特征-权重组合没有意义。 Word embeddings 词嵌入词嵌入为我们提供了一种使用高效，密集表示的方法，其中类似的单词具有相似的编码。 重要的是，我们不必手动指定此编码。 嵌入是浮点值的密集向量（向量的长度是您指定的参数）。它们不是手动指定嵌入的值，而是可训练的参数（在训练期间由模型学习的权重，与模型学习密集层的权重的方式相同）。通常会看到8维（对于小数据集）的单词嵌入，在处理大型数据集时最多可达1024维。 更高维度的嵌入可以捕获单词之间的细粒度关系，但需要更多的数据来学习。 缺点：词嵌入没有上下文的概念，一个词语与一个词嵌入向量一一对应，无法解决一词多义问题。 词嵌入资源 标题 说明 Tencent AI Lab Embedding Corpus for Chinese Words and Phrases This corpus provides 200-dimension vector representations, a.k.a. embeddings, for over 8 million Chinese words and phrases, which are pre-trained on large-scale high-quality data. These vectors, capturing semantic meanings for Chinese words and phrases, can be widely applied in many downstream Chinese processing tasks (e.g., named entity recognition and text classification) and in further research.腾讯AI Lab开源大规模高质量中文词向量数据，800万中文词随你用 awesome-embedding-models 精选的嵌入模型教程，项目和社区的精选列表。 向量空间模型向量空间模型(Vector space models, VSMs)将词语表示为一个连续的词向量，并且语义接近的词语对应的词向量在空间上也是接近的。VSMs在NLP中拥有很长的历史，但是所有的方法在某种程度上都是基于一种分布式假说，该假说的思想是如果两个词的上下文(context)相同，那么这两个词所表达的语义也是一样的；换言之，两个词的语义是否相同或相似，取决于两个词的上下文内容，上下文相同表示两个词是可以等价替换的。 基于分布式假说理论的词向量生成方法主要分两大类：计数法(count-based methods, e.g. Latent Semantic Analysis)和预测法(predictive methods, e.g. neural probabilistic language models)。Baroni等人详细论述了这两种方法的区别，简而言之，计数法是在大型语料中统计词语及邻近的词的共现频率，然后将之为每个词都映射为一个稠密的向量表示；预测法是直接利用词语的邻近词信息来得到预测词的词向量（词向量通常作为模型的训练参数）。 文本问题机器学习这样的技术比较喜欢被定义好的固定长度的输入和输出，因此不固定输入输出是文本建模的一个问题。 机器学习算法不能直接处理原始文本，文本必须转换成数字。具体来说，是数字的向量。 “在语言处理中，向量x是由文本数据派生而来的，以反映文本的各种语言属性。”在自然语言处理中神经网络方法,2017年。 这被称为特征提取或特征编码。这是一种流行的、简单的文本数据提取方法被称为文本的词汇模型。 词袋模型词袋模型下，像是句子或是文件这样的文字可以用一个袋子装着这些词的方式表现，这种表现方式不考虑文法以及词的顺序。最近词袋模型也被应用在电脑视觉领域 。词袋模型被广泛应用在文件分类，词出现的频率可以用来当作训练分类器的特征。 词向量模型词向量词向量具有良好的语义特性，是表示词语特征的常用方式。词向量每一维的值代表一个具有一定的语义和语法上解释的特征。所以，可以将词向量的每一维称为一个词语特征。词向量具有多种形式，distributed representation 是其中一种。一个 distributed representation 是一个稠密、低维的实值向量。distributed representation 的每一维表示词语的一个潜在特征，该特 征捕获了有用的句法和语义特性。可见 ，distributed representation 中的 distributed 一词体现了词向量这样一个特点：将词语的不同句法和语义特征分布到它的每一个维度去表示 。 自然语言是一套用来表达含义的复杂系统。在这套系统中，词是表义的基本单元。顾名思义，词向量是用来表示词的向量，也可被认为是词的特征向量。 这通常需要把维数为词典大小的高维空间嵌入到一个更低维数的连续向量空间。把词映射为实数域上向量的技术也叫词嵌入（word embedding）。近年来，词向量已逐渐成为自然语言处理的基础知识。 语言模型旨在为语句的联合概率函数P(w1,…,wT)建模, 其中wi表示句子中的第i个词。语言模型的目标是，希望模型对有意义的句子赋予大概率，对没意义的句子赋予小概率。 这样的模型可以应用于很多领域，如机器翻译、语音识别、信息检索、词性标注、手写识别等，它们都希望能得到一个连续序列的概率。 统计语言模型 基于神经网络的分布表示由于神经网络较为灵活,这类方法的最大优势在于可以表示复杂的上下文。更主要的原因是NNLM不再去老老实实地统计词频，而是通过模型拟合的方式逼近真实分布。在前面基于矩阵的分布表示方法中,最常用的上下文是词。如果使用包含词序信息的 n-gram 作为上下文,当 n 增加时,n-gram 的总数会呈指数级增长,此时会遇到维数灾难问题。而神经网络在表示 n-gram 时,可以通过一些组合方式对 n 个词进行组合,参数个数仅以线性速度增长。有了这一优势,神经网络模型可以对更复杂的上下文进行建模,在词向量中包含更丰富的语义信息。基于NN的所有训练方法都是在训练语言模型(LM)的同时，顺便得到词向量的。 Neural net language modelsword2vector 标题 说明 附加 Efficient Estimation of Word Representations in Vector Space word2vector 原文 20130116 models/tutorials/embedding/word2vec.py 官方实现 20171030 传统词嵌入的过程embedding_lookup()词嵌入的过程，注意其中的维度变化只是一种可能的方式。 123456789101112import tensorflow as tfimport numpy as npinput_ids = tf.placeholder(dtype=tf.int32, shape=[None])embedding = tf.Variable(np.identity(5, dtype=np.float32))input_embedding = tf.nn.embedding_lookup(embedding, input_ids)sess = tf.InteractiveSession()sess.run(tf.global_variables_initializer())print(embedding.eval())print(sess.run(input_embedding, feed_dict=&#123;input_ids:[1, 2, 3, 0, 3, 2, 1]&#125;)) 代码中先使用palceholder定义了一个未知变量input_ids用于存储索引，和一个已知变量embedding，是一个5*5的对角矩阵。运行结果为,123456789101112embedding = [[1. 0. 0. 0. 0.] [0. 1. 0. 0. 0.] [0. 0. 1. 0. 0.] [0. 0. 0. 1. 0.] [0. 0. 0. 0. 1.]]input_embedding = [[0. 1. 0. 0. 0.] [0. 0. 1. 0. 0.] [0. 0. 0. 1. 0.] [1. 0. 0. 0. 0.] [0. 0. 0. 1. 0.] [0. 0. 1. 0. 0.] [0. 1. 0. 0. 0.]] 简单的讲就是根据input_ids中的id，寻找embedding中的对应元素。比如，input_ids=[1,3,5]，则找出embedding中下标为1,3,5的向量组成一个矩阵返回。 如果将input_ids改写成下面的格式： 123456789101112import tensorflow as tfimport numpy as npinput_ids = tf.placeholder(dtype=tf.int32, shape=[None, None])embedding = tf.Variable(np.identity(5, dtype=np.float32))input_embedding = tf.nn.embedding_lookup(embedding, input_ids)sess = tf.InteractiveSession()sess.run(tf.global_variables_initializer())print(embedding.eval())print(sess.run(input_embedding, feed_dict=&#123;input_ids:[[1, 2], [2, 1], [3, 3]]&#125;)) 输出结果就会变成如下的格式：123456input_embedding = [[[0 1 0 0 0] [0 0 1 0 0]] [[0 0 1 0 0] [0 1 0 0 0]] [[0 0 0 1 0] [0 0 0 1 0]]] 对比上下两个结果不难发现，相当于在np.array中直接采用下标数组获取数据。需要注意的细节是返回的tensor的dtype和传入的被查询的tensor的dtype保持一致；和ids的dtype无关。 字符嵌入在NLP中，我们通常使用的过滤器会滑过整个矩阵(单词)。因此，过滤器的“宽度（width）”通常与输入矩阵的宽度相同。高度，或区域大小（region size），可能会有所不同，但是滑动窗口一次在2-5个字是典型的。 一个NLP上的卷积实例是下面这样：上图展示了CNN在文本分类的使用，使用了2种过滤器（卷积核），每个过滤器有3种高度（区域大小），即有6种卷积结构（左起第2列），所以会产生6中卷积后的结果（左起第3列），经过最大池化层（后面还会提到池化层），每个卷积的结果将变为1个值（左起第4列），最终生成一个向量（左起第5列），最终经过分类器得到一个二分类结果（最后一列）。来自：A Sensitivity Analysis of (and Practitioners’ Guide to) Convolutional Neural Networks for Sentence Classification。 对比Word2vec, Fasttext, Glove, Elmo, Bert, Flair pre-train Word EmbeddingWord2vec, Fasttext, Glove, Elmo, Bert, Flair pre-train Word Embedding 词嵌入-2018历史综述 BornsteinBeyond Word Embeddings Part 1Beyond Word Embeddings Part 2Beyond Word Embeddings Part 3Beyond Word Embeddings Part 4 语言模型词嵌入的过程参看 allennlp.org - elmo 标题 说明 附加 词向量技术-从word2vec到ELMo 20180724 NLP领域的ImageNet时代到来：词嵌入「已死」，语言模型当立 翻译自 NLP’s ImageNet moment has arrived 20180709 2018最好的词句嵌入技术概览：从无监督学习到监督、多任务学习 翻译自 The Current Best of Universal Word Embeddings and Sentence Embeddings 20180606 NLP的游戏规则从此改写？从word2vec, ELMo到BERT 夕小瑶 详细解读 神经语言模型的最新进展 卡内基梅隆大学博士杨植麟受邀至清华大学计算机系进行主题为「神经语言模型的最新进展」的演讲。 20181213 从word2vec开始，说下GPT庞大的家族系谱 本文从从老祖级别的 word2vec 开始，从头到尾梳理了 GPT 的 「家谱」 和 word2vec 领衔的庞大的 NLP「家族集团」。 20201004 自然语言处理中的语言模型预训练方法语言模型评价 语言模型构造完成后，如何确定好坏呢？ 目前主要有两种评价方法： 实用方法：通过查看该模型在实际应用（如拼写检查、机器翻译）中的表现来评价，优点是直观、实用，缺点是缺乏针对性、不够客观；理论方法：迷惑度/困惑度/混乱度（preplexity），其基本思想是给测试集的句子赋予较高概率值的语言模型较好,当语言模型训练完之后，测试集中的句子都是正常的句子，那么训练好的模型就是在测试集上的概率越高越好。 深度长文：NLP的巨人肩膀（上） 纵览2003-2018年自然语言处理中词语表示的发展史。 本质上，自然语言理解 NLU 的核心问题其实就是如何从语言文字的表象符号中抽取出来蕴含在文字背后的真实意义，并将其用计算机能够读懂的方式表征出来。当然这通常对应的是数学语言，表征是如此重要，以至于 2012 年的时候 Yoshua Bengio 作为第一作者发表了一篇表征学习的综述 Representation Learning: A Review and New Perspectives，并随后在 2013 年和深度学习三大巨头的另一位巨头 Yann LeCun 牵头创办 ICLR，这一会议至今才过去 5 年时间，如今已是 AI 领域最负盛名的顶级会议之一。可以说，探究 NLP 或 NLU 的历史，同样也是探究文本如何更有效表征的历史。 1954 年 Harris 提出分布假说（distributional hypothesis），这一假说认为：上下文相似的词，其语义也相似，1957 年 Firth 对分布假说进行了进一步阐述和明确：词的语义由其上下文决定（a word is characterized by the company it keeps），30 年后，深度学习 Hinton 也于 1986 年尝试过词的分布式表示。 时间 词语表示的特征 论文 解析 -2003 没有统一表示词语的方法，一般采取统计分析模式 NLP 中并没有一个统一的方法去表示一段文本，各位前辈和大师们发明了许多的方法：从 one-hot 表示一个词到用 bag-of-words 来表示一段文本，从 k-shingles 把一段文本切分成一些文字片段，到汉语中用各种序列标注方法将文本按语义进行分割，从 tf-idf 中用频率的手段来表征词语的重要性，到 text-rank 中借鉴 page-rank 的方法来表征词语的权重，从基于 SVD 纯数学分解词文档矩阵的 LSA，到 pLSA 中用概率手段来表征文档形成过程并将词文档矩阵的求解结果赋予概率含义，再到 LDA 中引入两个共轭分布从而完美引入先验…… 2003 词语的分布式表示 A Neural Probabilistic Language Model Bengio 在他的经典论文 A Neural Probabilistic Language Model 中，首次将深度学习的思想融入到语言模型中，并发现将训练得到的 NNLM（Neural Net Language Model，神经网络语言模型）模型的第一层参数当做词的分布式表征时，能够很好地获取词语之间的相似度。NNLM 的最主要贡献是非常有创见性地将模型的第一层特征映射矩阵当做词的分布式表示，从而可以将一个词表征为一个向量形式，这直接启发了后来的 word2vec 的工作。 2007 2007 年 Mnih 和 Hinton 提出的 LBL 以及后续的一系列相关模型，省去了 NNLM 中的激活函数，直接把模型变成了一个线性变换，尤其是后来将 Hierarchical Softmax 引入到 LBL 后，训练效率进一步增强，但是表达能力不如 NNLM 这种神经网络的结构。 2008 2008 年 Collobert 和 Weston 提出的 C&amp;W 模型不再利用语言模型的结构，而是将目标文本片段整体当做输入，然后预测这个片段是真实文本的概率，所以它的工作主要是改变了目标输出。由于输出只是一个概率大小，不再是词典大小，因此训练效率大大提升，但由于使用了这种比较“别致”的目标输出，使得它的词向量表征能力有限。 2010 2010 年 Mikolov 提出的 RNNLM 主要是为了解决长程依赖关系，时间复杂度问题依然存在。 2013 word2vec;CBOW 模型;Skip-gram 模型 Efficient estimation of word representations in vector space;Distributed Representations of Words and Phrases and their Compositionality 其实 word2vec 只是一个工具，背后的模型是 CBOW 或者 Skip-gram，并且使用了 Hierarchical Softmax 或 Negative Sampling 这些训练的优化方法。word2vec 对于前人的优化，主要是两方面的工作：模型的简化和训练技巧的优化。word2vec 的出现，极大促进了 NLP 的发展，尤其是促进了深度学习在 NLP 中的应用（不过有意思的是，word2vec 算法本身其实并不是一个深度模型，它只有两层全连接），利用预训练好的词向量来初始化网络结构的第一层几乎已经成了标配，尤其是在只有少量监督数据的情况下，如果不拿预训练的 embedding 初始化第一层，几乎可以被认为是在蛮干。 2014 Glove GloVe: Global Vectors for Word Representation 它整个的算法框架都是基于矩阵分解的做法来获取词向量的，本质上和诸如 LSA 这种基于 SVD 的矩阵分解方法没有什么不同，只不过 SVD 分解太过于耗时，运算量巨大，相同点是 LSA 也是输入共现矩阵，不过一般主要以词-文档共现矩阵为主，另外，LSA 中的共现矩阵没有做特殊处理，而 GloVe 考虑到了对距离较远的词对做相应的惩罚等等。然而，相比 word2vec，GloVe 却更加充分的利用了词的共现信息，word2vec 中则是直接粗暴的让两个向量的点乘相比其他词的点乘最大，至少在表面上看来似乎是没有用到词的共现信息，不像 GloVe 这里明确的就是拟合词对的共现频率。 2015 Skip-shoughts Skip-Thought Vectors 2015 年，多伦多大学的 Kiros 等人提出了一个很有意思的方法叫 Skip-thoughts。同样也是借鉴了 Skip-gram 的思想，但是和 PV-DBOW 中利用文档来预测词的做法不一样的是，Skip-thoughts 直接在句子间进行预测，也就是将 Skip-gram 中以词为基本单位，替换成了以句子为基本单位，具体做法就是选定一个窗口，遍历其中的句子，然后分别利用当前句子去预测和输出它的上一句和下一句。对于句子的建模利用的 RNN 的 sequence 结构，预测上一个和下一个句子时候，也是利用的一个 sequence 的 RNN 来生成句子中的每一个词，所以这个结构本质上就是一个 Encoder-Decoder 框架，只不过和普通框架不一样的是，Skip-thoughts 有两个 Decoder。 2016 fasttext FastText.zip: Compressing text classification models word2vec 和 GloVe 都不需要人工标记的监督数据，只需要语言内部存在的监督信号即可以完成训练。而与此相对应的，fastText 则是利用带有监督标记的文本分类数据完成训练。在输入数据上，CBOW 输入的是一段区间中除去目标词之外的所有其他词的向量加和或平均，而 fastText 为了利用更多的语序信息，将 bag-of-words 变成了 bag-of-features，也就是下图中的输入 x 不再仅仅是一个词，还可以加上 bigram 或者是 trigram 的信息等等。第二个不同在于，CBOW 预测目标是语境中的一个词，而 fastText 预测目标是当前这段输入文本的类别。fastText 最大的特点在于快。 2017 InferSent 框架 Supervised Learning of Universal Sentence Representations from Natural Language Inference Data 除了 Skip-thoughts 和 Quick-thoughts 这两种不需要人工标记数据的模型之外，还有一些从监督数据中学习句子表示的方法。比如 2017 年 Facebook 的研究人员 Conneau 等人提出的 InferSent 框架，它的思想特别简单，先设计一个模型在斯坦福的 SNLI（Stanford Natural Language Inference）数据集上训练，而后将训练好的模型当做特征提取器，以此来获得一个句子的向量表示，再将这个句子的表示应用在新的分类任务上，来评估句子向量的优劣。 2018_2 ELMo Deep contextualized word representations 该研究提出了一种新型深度语境化词表征，可对词使用的复杂特征（如句法和语义）和词使用在语言语境中的变化进行建模（即对多义词进行建模）。这些表征可以轻松添加至已有模型，并在 6 个 NLP 问题中显著提高当前最优性能。 2018_3 Quick thoughts An efficient framework for learning sentence representations 2018 年的时候，在 Skip-thoughts 的基础上，Google Brain 的 Logeswaran 等人将这一思想做了进一步改进，他们认为 Skip-thoughts 的 Decoder 效率太低，且无法在大规模语料上很好的训练（这是 RNN 结构的通病）。所以他们把 Skip-thoughts 的生成任务改进成为了一个分类任务，具体说来就是把同一个上下文窗口中的句子对标记为正例，把不是出现在同一个上下文窗口中的句子对标记为负例，并将这些句子对输入模型，让模型判断这些句子对是否是同一个上下文窗口中，很明显，这是一个分类任务。可以说，仅仅几个月之后的 BERT 正是利用的这种思路。而这些方法都和 Skip-thoughts 一脉相承。 2018_3 Learning General Purpose Distributed Sentence Representations via Large Scale Multi-task Learning 提出了利用四种不同的监督任务来联合学习句子的表征，这四种任务分别是：Natural Language Inference，Skip-thougts，Neural Machine Translation 以及 Constituency Parsing 等。 2018_3 Universal Sentence Encoder 谷歌的 Daniel Cer 等人在论文 Universal Sentence Encoder 中提出的思路基本和 General Purpose Sentence Representation 的工作一样，只不过作者提出了利用 Transformer 和 DAN（上文提到过的和 CBOW 与 fastText 都神似的 Deep Unordered Composition Rivals Syntactic Methods for Text Classification）两种框架作为句子的 Encoder。 2018_6 openai-GPT Improving Language Understanding by Generative Pre-Training OpenAI 最近通过一个与任务无关的可扩展系统在一系列语言任务中获得了当前最优的性能，目前他们已经发布了该系统。OpenAI 表示他们的方法主要结合了两个已存的研究，即 Transformer 和无监督预训练。实验结果提供了非常令人信服的证据，其表明联合监督学习方法和无监督预训练能够得到非常好的性能。这其实是很多研究者过去探索过的领域，OpenAI 也希望他们这次的实验结果能激发更加深入的研究，并在更大和更多的数据集上测试联合监督学习与无监督预训练的性能。 2018_10 Google-BERT BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding 论文介绍了一种新的语言表征模型 BERT，意为来自 Transformer 的双向编码器表征（Bidirectional Encoder Representations from Transformers）。与最近的语言表征模型（Peters et al., 2018; Radford et al., 2018）不同，BERT 旨在基于所有层的左、右语境来预训练深度双向表征。因此，预训练的 BERT 表征可以仅用一个额外的输出层进行微调，进而为很多任务（如问答和语言推断任务）创建当前最优模型，无需对任务特定架构做出大量修改。BERT 的概念很简单，但实验效果很强大。它刷新了 11 个 NLP 任务的当前最优结果，包括将 GLUE 基准提升至 80.4%（7.6% 的绝对改进）、将 MultiNLI 的准确率提高到 86.7%（5.6% 的绝对改进），以及将 SQuAD v1.1 的问答测试 F1 得分提高至 93.2 分（提高 1.5 分）——比人类表现还高出 2 分。 NLP 的巨人肩膀（下）：从 CoVe 到 BERT可视化分析词嵌入 标题 说明 时间 用scikit-learn学习主成分分析(PCA) 降维基础 sklearn中PCA的使用方法 降维基础 20180131 visualizing-elmo-contextual-vectors 可视化ELMo上下文向量 20190417]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>Embedding</tag>
        <tag>词嵌入</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[TensorFlow_Datasets基本使用]]></title>
    <url>%2F2019%2F01%2F06%2FTensorFlow_Datasets%E4%BD%BF%E7%94%A8%2F</url>
    <content type="text"><![CDATA[按顺序必读官方指引 TensorFlow Datasets and Estimators 标题 说明 时间 Introduction to TensorFlow Datasets and Estimators Google Develops Blog Part 1 2017-09-12 Introducing TensorFlow Feature Columns Google Develops Blog Part 2 2017-11-20 Creating Custom Estimators in TensorFlow Google Develops Blog Part 3 2017-12-19 Classifying text with TensorFlow Estimators Part 4 2018-03-07 tfrecord 详解示例代码 GenerateSimpleTFRecord.py12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758# Demonstration of creating TFRecord file with simple data types like int, float, stringimport tensorflow as tfimport numpy as npdata_arr = [ &#123; 'int_data': 108, 'float_data': 2.45, 'str_data': 'String 100', 'float_list_data': [256.78, 13.9], 'image_data': np.random.uniform(0, 255, size=(3, 4, 2)) &#125;, &#123; 'int_data': 37, 'float_data': 84.3, 'str_data': 'String 200', 'float_list_data': [1.34, 843.9, 65.22], 'image_data': np.random.uniform(0, 255, size=(3, 4, 2)) &#125;]tf.reset_default_graph()def get_example_object(data_record): # Convert individual data into a list of int64 or float or bytes int_list1 = tf.train.Int64List(value=[data_record['int_data']]) float_list1 = tf.train.FloatList(value=[data_record['float_data']]) # Convert string data into list of bytes str_list1 = tf.train.BytesList(value=[data_record['str_data'].encode('utf-8')]) float_list2 = tf.train.FloatList(value=data_record['float_list_data']) image_list = tf.train.BytesList(value=[data_record['image_data'].tostring()]) # Create a dictionary with above lists individually wrapped in Feature feature_key_value_pair = &#123; 'int_list1': tf.train.Feature(int64_list=int_list1), 'float_list1': tf.train.Feature(float_list=float_list1), 'str_list1': tf.train.Feature(bytes_list=str_list1), 'float_list2': tf.train.Feature(float_list=float_list2), 'image_list': tf.train.Feature(bytes_list=image_list) &#125; # Create Features object with above feature dictionary features = tf.train.Features(feature=feature_key_value_pair) # Create Example object with features example = tf.train.Example(features=features) return examplewith tf.python_io.TFRecordWriter('example.tfrecord') as tfwriter: # Iterate through all records for data_record in data_arr: example = get_example_object(data_record) # Append each example into tfrecord tfwriter.write(example.SerializeToString()) 示例代码 ExtractSimpleTFRecord.py12345678910111213141516171819202122232425262728293031323334353637# Demonstration of extracting TFRecord file with simple data types like int, float, stringimport tensorflow as tftf.reset_default_graph()def extract_fn(data_record): features = &#123; # Extract features using the keys set during creation 'int_list1': tf.FixedLenFeature([], tf.int64), 'float_list1': tf.FixedLenFeature([], tf.float32), 'str_list1': tf.FixedLenFeature([], tf.string), # If size is different of different records, use VarLenFeature 'float_list2': tf.VarLenFeature(tf.float32), 'image_list': tf.FixedLenFeature([], tf.string) &#125; sample = tf.parse_single_example(data_record, features) sample['float_list2'] = tf.sparse.to_dense(sample['float_list2']) sample['image_list'] = tf.decode_raw(sample['image_list'], tf.float64) sample['image_list'] = tf.reshape(sample['image_list'], (3, 4, 2)) return sample# Initialize all tfrecord pathsdataset = tf.data.TFRecordDataset(['example.tfrecord'])dataset = dataset.map(extract_fn)iterator = dataset.make_one_shot_iterator()next_element = iterator.get_next()with tf.Session() as sess: sess.run(tf.global_variables_initializer()) try: while True: data_record = sess.run(next_element) print(data_record) except: pass tfrecord basic explanation 方法总结 For example, see the code Producte tfrecord files1. Open TFRecordWriter1writer = tf.python_io.TFRecordWriter(tfrecord_store_path) 2. prepater to feature_dict1234567891011for index, row in pandas_datafram_data.iterrows(): dict_row = dict(row) feature_dict = &#123;&#125; # prepater to feature_dict for k,v in dict_row.items(): if k in [&apos;feature1&apos;, &apos;feature2&apos;,...,&apos;featureN&apos;]: feature_dict[k] = tf.train.Feature(float_list=tf.train.FloatList(value=[v])) elif k in [&apos;feature1&apos;, &apos;feature2&apos;,...,&apos;featureN&apos;]: feature_dict[k] = tf.train.Feature(int64_list=tf.train.Int64List(value=[v]) else: feature_dict[k] = tf.train.Feature(int64_list=tf.train.BytesList(value=[v)]) 3. producte data example1example = tf.train.Example(features=tf.train.Features(feature=feature_dict)) 4. serialize to string1serialized = example.SerializeToString() 5. write a example to tfrecord file1writer.write(serialized) 6. Close TFRecordWriter1writer.close() Using tfrecord files1. Open TFRecordDataset12filenames = [&apos;tfrecord_file_name1&apos;,&apos;tfrecord_file_name2&apos;]tf_dataset = tf.data.TFRecordDataset(filenames) 2. Parse dataset123456def _parse_function(record): features = &#123;&quot;feature1&quot;: tf.FixedLenFeature((), tf.float32, default_value=0.0), &quot;feature2&quot;: tf.FixedLenFeature((), tf.int64, default_value=0)&#125; parsed_features = tf.parse_single_example(record, features) return &#123;&quot;feature1&quot;: parsed_features[&quot;feature1&quot;]&#125;, parsed_features[&quot;Species&quot;]dataset = tf_dataset.map(_parse_function) 3. Shuffle, repeat, and batch the examples1tf_dataset = dataset.shuffle(1000).repeat().batch(batch_size) 4. Iterate dataset123456tf_iterator = tf_dataset.make_one_shot_iterator()next_element = tf_iterator.get_next()with tf.Session() as sess: for i in range(show_numbers): a_data = sess.run(next_element) print(a_data) TFRecord 相关博客 标题 说明 时间 convert_to_records.py tensorflow/tensorflow/examples/how_tos/reading_data/convert_to_records.py 20171201 fully_connected_reader.py tensorflow/tensorflow/examples/how_tos/reading_data/fully_connected_reader.py 20181203 导入数据 TensorFlow Guide 持续更新 TensorFlow中层API：Datasets+TFRecord的数据导入 对应代码TensorFlow Dataset + TFRecords.ipynb 20180126 Tensorflow-tf-estimator lanhong 20181103 TFRecord_Images Illustration of how to create TFRecord with images and pipelined into Datasets and Iterators 20180723]]></content>
      <categories>
        <category>Artificial Intelligence Navigation</category>
        <category>TensorFlow手册</category>
      </categories>
      <tags>
        <tag>TensorFlow</tag>
        <tag>TensorFlow Function Usage</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Learned in Translation Contextualized Word Vectors]]></title>
    <url>%2F2019%2F01%2F03%2FLearned_in_Translation_Contextualized_Word_Vectors%2F</url>
    <content type="text"><![CDATA[Learned in Translation: Contextualized Word VectorsBryan McCann, James Bradbury, Caiming Xiong, Richard Socher(Submitted on 1 Aug 2017 (v1), last revised 20 Jun 2018 (this version, v2)) Computer vision has benefited from initializing multiple deep layers with weights pretrained on large supervised training sets like ImageNet. Natural language processing (NLP) typically sees initialization of only the lowest layer of deep models with pretrained word vectors. In this paper, we use a deep LSTM encoder from an attentional sequence-to-sequence model trained for machine translation (MT) to contextualize word vectors. We show that adding these context vectors (CoVe) improves performance over using only unsupervised word and character vectors on a wide variety of common NLP tasks: sentiment analysis (SST, IMDb), question classification (TREC), entailment (SNLI), and question answering (SQuAD). For fine-grained sentiment analysis and entailment, CoVe improves performance of our baseline models to the state of the art. 计算机视觉从初始化多个深度层中受益，这些深度层的权重是在像ImageNet这样的大型监督训练集上预先训练的。自然语言处理(NLP)通常只使用经过预处理的词向量初始化深层模型的最低层。在本文中，我们使用一个深度LSTM编码器从一个注意序列到序列模型训练机器翻译(MT)上下文化词向量。我们证明，在各种常见的NLP任务中，添加这些上下文向量(CoVe)比仅使用无监督的单词和字符向量提高了性能。 Subjects: Computation and Language (cs.CL); Artificial Intelligence (cs.AI); Machine Learning (cs.LG)Cite as: arXiv:1708.00107 [cs.CL] (or arXiv:1708.00107v2 [cs.CL] for this version) Learned in Translation: Contextualized Word Vectors 翻译以下为翻译的部分内容 对于自然语言处理中的大多数问题而言，理解语境是很有必要的。为了生成一句英文的德语翻译，翻译模型需要理解英文句子中的单词是如何组织在一起的。为了知道哪些单词是最重要的，文本摘要模型也需要语境。执行语意情感分析的模型需要理解如何挑选出能够改变一句话的情感的关键词。问答模型依赖于对「问题中的词汇分布如何改变答案中的词汇分布」的理解。因为这些模型都需要理解语境是如何影响一个单词的意思的，所以，只要能够与一个学会了如何将单词语境化的模型相结合，上述每个模型都能够从中获益。 在自然语言处理（NLP）中模仿 IMAGENET-CNN 模式机器视觉在寻求可重用的表征方面比自然语言处理更加成功。在大型图像分类数据集 ImageNet 上训练的深度卷积神经网络（CNN）经常被用作其他模型的组成部分。为了将图像分类做得更好，卷积神经网络通过逐渐构建一个更加复杂模型，而去理解像素是如何与其他像素关联的。模型可以在这些表征的基础上去解决看图说话问题、人脸识别问题以及目标检测问题，而不是一切都从零开始。自然语言处理也应该做一些类似的表征去解决单词和语境之间的关联。 为了教会神经网络理解单词在语境中的含义，我们首先教它如何将英文翻译成德语。然后，我们展示了可以重用该翻译任务的神经网络就像模仿机器视觉中在 ImageNet 上训练卷积神经网络的方式那样。我们是这样来做的：通过将神经网络的输出（也就是我们所说的语境向量（CoVe））作为其它自然语言处理任务的神经网络的新输入。在我们的实验中，给这些网络提供 CoVe 的情况总会改善模型的性能，这十分令我们振奋，所以所以我们公布了这个能够生成 CoVe 的可训练神经网络，以进一步探索自然语言处理中的可重用表征。 机器翻译中的隐向量因为结果证明预训练的词向量对于很多自然语言处理任务来说都是很有用的表征，所以我们要预训练我们的编码器，这样的话，它就能够输出普遍有用的隐向量。为了预训练，我们选择机器翻译作为我们的第一个任务。较之于其他的自然语言处理任务，机器翻译拥有更大的数据集。并且，对于训练通用的语境向量而言，翻译任务的本质看上去更加吸引人。例如，与其他的类似于文本分类的任务相比，翻译貌似更需要那种能够理解语言的语感。 解码器我们通过教编码器如何将英文翻译成德文来教它生成有用的隐向量。解码器生成了针对英文句子的隐向量，另一个叫做解码器的神经网络就会在生成德语句子的时候参考这些隐向量。 正因为 LSTM 是我们编码器的基础，所以 LSTM 也在解码器中起着非常重要的作用。与编码器一样，我们在解码器中也使用两层的 LSTM。用编码器的最终状态来初始化解码器，读入一个德语词向量来启动解码器，然后就会生成解码状态向量。解码器使用一个单向的 LSTM 来从输入词向量创建解码器状态。 注意力机制为了决定下一步翻译英语句子中的哪一部分，注意力机制需要从隐向量向前回溯。它使用状态向量来判别每一个隐向量的重要性，为了记录它的观察值，注意力机制会生成一个新的向量，我们可以称之为语境调整状态（context-sdjusted state）。注意力机制使用隐状态和解码状态来生成语境调整状态。 生成模型然后，生成器会根据语境调整状态来决定要生成哪个德语单词，接下来语境调整状态会回传到解码器中，让解码器对其翻译的结果有一个准确的感知。解码器一直重复这个过程，直至它完成所有翻译。这就是一个标准的基于注意力机制的编码器-解码器结构，它被用来学习像机器翻译一样的序列到序列任务。 预训练的机器翻译—长短期记忆网络（MT-LSTM）中的语境向量当训练过程结束之后，我们可以将我们训练好的 LSTM 提取出来作为编码器用于机器翻译。我们将这个预训练的 LSTM 称作机器翻译 LSTM（MT-LSTM），并使用它生成新句子的隐向量。当我们把这些机器翻译隐向量用于其它的自然语言处理模型时，我们就把它们称作语境向量（CoVe）。]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>迁移学习</tag>
        <tag>词向量</tag>
        <tag>GoVe</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[待读Regularizing_and_Optimizing_LSTM_Language_Models]]></title>
    <url>%2F2019%2F01%2F03%2FRegularizing_and_Optimizing_LSTM_Language_Models%2F</url>
    <content type="text"><![CDATA[Regularizing and Optimizing LSTM Language ModelsStephen Merity, Nitish Shirish Keskar, Richard Socher(Submitted on 7 Aug 2017) Recurrent neural networks (RNNs), such as long short-term memory networks (LSTMs), serve as a fundamental building block for many sequence learning tasks, including machine translation, language modeling, and question answering. In this paper, we consider the specific problem of word-level language modeling and investigate strategies for regularizing and optimizing LSTM-based models. We propose the weight-dropped LSTM which uses DropConnect on hidden-to-hidden weights as a form of recurrent regularization. Further, we introduce NT-ASGD, a variant of the averaged stochastic gradient method, wherein the averaging trigger is determined using a non-monotonic condition as opposed to being tuned by the user. Using these and other regularization strategies, we achieve state-of-the-art word level perplexities on two data sets: 57.3 on Penn Treebank and 65.8 on WikiText-2. In exploring the effectiveness of a neural cache in conjunction with our proposed model, we achieve an even lower state-of-the-art perplexity of 52.8 on Penn Treebank and 52.0 on WikiText-2. Subjects: Computation and Language (cs.CL); Machine Learning (cs.LG); Neural and Evolutionary Computing (cs.NE)Cite as: arXiv:1708.02182 [cs.CL] (or arXiv:1708.02182v1 [cs.CL] for this version)]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Language Model</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Stanford Computer Science]]></title>
    <url>%2F2018%2F12%2F27%2FStanfordCS%2F</url>
    <content type="text"><![CDATA[CS229 Machine Learning 标题 说明 附加 CS229: Machine Learning 课程主页 Schedule and Syllabus 时间表和大纲 CS20 Tensorflow for Deep Learning Research 标题 说明 附加 stanford-tensorflow-tutorials GitHub资源 CS 20: Tensorflow for Deep Learning Research 课程主页 Schedule and Syllabus 时间表和大纲 CS224n Natural Language Processing with Deep Learning 标题 说明 附加 CS224n Natural Language Processing with Deep Learning 课程主页]]></content>
      <categories>
        <category>机器学习</category>
        <category>stanford</category>
      </categories>
      <tags>
        <tag>ML</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[GloVe Global Vectors for Word Representation]]></title>
    <url>%2F2018%2F12%2F27%2F%20GloVe_Global_Vectors_for_Word_Representation%2F</url>
    <content type="text"><![CDATA[标题 说明 GloVe Global Vectors for Word Representation 原始论文 GloVe 官方实现 GloVe详解 论文解读 理解GloVe模型（+总结） 论文解读 论文分享—&gt;GloVe: Global Vectors for Word Representation 论文和代码解读]]></content>
      <categories>
        <category>论文</category>
      </categories>
      <tags>
        <tag>Glove</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[命名实体识别CoNLL2003]]></title>
    <url>%2F2018%2F12%2F26%2F%E5%91%BD%E5%90%8D%E5%AE%9E%E4%BD%93%E8%AF%86%E5%88%ABCoNLL2003%2F</url>
    <content type="text"><![CDATA[CoNLL 2003 是最经典的命名实体识别（NER，Named Entity Recognition）任务数据集之一，有大量的研究者在上面进行研究。如果你对该领域（自然语言处理）有兴趣，不妨以此为任务入手。 我的 CoNLL 2003 解决方案 CoNLL 2003 data 数据 + 基于BERT的代码 BERT-for-Sequence-Labeling-and-Text-Classification 这是使用BERT进行序列标注和文本分类的模板代码（包含数据），方便大家将BERT用于更多任务。该代码已经在SNIPS（意图识别和槽填充任务）、ATIS（意图识别和槽填充任务）和conll-2003（命名实体识别任务）数据集上进行了实验。欢迎使用这个BERT模板解决更多NLP任务，然后在这里分享你的结果和代码。 该模板代码提供的基线模型在conll-2003上的实验结果是：{F1值 = 0.926， 精确率 = 0.925， 召回率 = 0.928} 相关内容 CoNLL 2003 data 数据说明https://www.clips.uantwerpen.be/conll2003/ner/ CoNLL 2003 论文 The CoNLL 2003 NER task consists of newswire text from the Reuters RCV1 corpus tagged with four different entity types (PER, LOC, ORG, MISC). Models are evaluated based on span-based F1 on the test set. 相关任务多关系抽取研究 CoNLL 2003 排行榜 最新进展 Model F1 Paper / Source Code Flair embeddings (Akbik et al., 2018) 93.09 Contextual String Embeddings for Sequence Labeling Flair framework BERT Large (Devlin et al., 2018) 92.8 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding CVT + Multi-Task (Clark et al., 2018) 92.61 Semi-Supervised Sequence Modeling with Cross-View Training Official BERT Base (Devlin et al., 2018) 92.4 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding BiLSTM-CRF+ELMo (Peters et al., 2018) 92.22 Deep contextualized word representations AllenNLP Project AllenNLP GitHub Peters et al. (2017) 91.93 Semi-supervised sequence tagging with bidirectional language models HSCRF (Ye and Ling, 2018) 91.38 Hybrid semi-Markov CRF for Neural Sequence Labeling HSCRF NCRF++ (Yang and Zhang, 2018) 91.35 NCRF++: An Open-source Neural Sequence Labeling Toolkit NCRF++ LM-LSTM-CRF (Liu et al., 2018) 91.24 Empowering Character-aware Sequence Labeling with Task-Aware Neural Language Model LM-LSTM-CRF Yang et al. (2017) 91.26 Transfer Learning for Sequence Tagging with Hierarchical Recurrent Networks Ma and Hovy (2016) 91.21 End-to-end Sequence Labeling via Bi-directional LSTM-CNNs-CRF LSTM-CRF (Lample et al., 2016) 90.94 Neural Architectures for Named Entity Recognition Guillaume Genthial 对CoNLL2003 代码及讲解 Sequence Tagging with Tensorflow 对应代码 sequence_tagging Intro to tf.estimator and tf.data 对应代码 lstm_crf 支持本文研究 如果你阅读本文后有所收获，十分欢迎点击下面的广告，您对下面广告的每一次点击都是对本文研究的大力支持，谢谢！]]></content>
      <categories>
        <category>论文</category>
      </categories>
      <tags>
        <tag>论文</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[BERT Pre-training of Deep Bidirectional Transformers for Language Understanding 翻译]]></title>
    <url>%2F2018%2F12%2F25%2FBidirectional_Encoder_Representations_Transformers%E7%BF%BB%E8%AF%91%2F</url>
    <content type="text"><![CDATA[本文是BERT论文的全文翻译，转载注明出处和译者。 原文 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding，这是BERT在2018年11月发布的版本，与2019年5月版本v2有稍许不同。 PDF版翻译以及相关资源链接 GitHub BERT_Paper_Chinese_Translation 译者：袁宵 说明：1. 对于没有标准译法的词语保留了原单词；2. 以准确翻译为第一目标，力求保持原意；3. 欢迎读者参与到翻译中来，提出修改意见。 手机扫码阅读： BERT：预训练的深度双向 Transformer 语言模型Jacob Devlin；Ming-Wei Chang；Kenton Lee；Kristina ToutanovaGoogle AI Language{jacobdevlin,mingweichang,kentonl,kristout}@google.com 摘要我们提出了一种新的称为 BERT 的语言表示模型，BERT 代表来自 Transformer 的双向编码器表示（Bidirectional Encoder Representations from Transformers）。不同于最近的语言表示模型（Peters et al., 2018，Radford et al., 2018）， BERT 旨在通过联合调节所有层中的左右上下文来预训练深度双向表示。因此，只需要一个额外的输出层，就可以对预训练的 BERT 表示进行微调，从而为广泛的任务（比如回答问题和语言推断任务）创建最先进的模型，而无需对特定于任务进行大量模型结构的修改。 BERT 的概念很简单，但实验效果很强大。它刷新了 11 个 NLP 任务的当前最优结果，包括将 GLUE 基准提升至 80.4%（7.6% 的绝对改进）、将 MultiNLI 的准确率提高到 86.7%（5.6% 的绝对改进），以及将 SQuAD v1.1 的问答测试 F1 得分提高至 93.2 分（提高 1.5 分）——比人类表现还高出 2 分。 1. 介绍语言模型预训练可以显著提高许多自然语言处理任务的效果（Dai and Le, 2015；Peters et al., 2018；Radford et al., 2018；Howard and Ruder, 2018）。这些任务包括句子级任务，如自然语言推理（Bow-man et al., 2015；Williams et al., 2018）和释义（Dolan and Brockett, 2005），目的是通过对句子的整体分析来预测句子之间的关系，以及标记级任务，如命名实体识别（Tjong Kim Sang and De Meulder, 2003）和 SQuAD 问答（Rajpurkar et al., 2016），模型需要在标记级生成细粒度的输出。 现有的两种方法可以将预训练好的语言模型表示应用到下游任务中：基于特征的和微调。基于特征的方法，如 ELMo （Peters et al., 2018)，使用特定于任务的模型结构，其中包含预训练的表示作为附加特特征。微调方法，如生成预训练 Transformer (OpenAI GPT) （Radford et al., 2018）模型，然后引入最小的特定于任务的参数，并通过简单地微调预训练模型的参数对下游任务进行训练。在之前的工作中，两种方法在预训练任务中都具有相同的目标函数，即使用单向的语言模型来学习通用的语言表达。 我们认为，当前的技术严重地限制了预训练表示的效果，特别是对于微调方法。主要的局限性是标准语言模型是单向的，这就限制了可以在预训练期间可以使用的模型结构的选择。例如，在 OpenAI GPT 中，作者使用了从左到右的模型结构，其中每个标记只能关注 Transformer 的自注意层中该标记前面的标记（Williams et al., 2018）。这些限制对于句子级别的任务来说是次优的（还可以接受），但当把基于微调的方法用来处理标记级别的任务（如 SQuAD 问答）时可能会造成不良的影响（Rajpurkar et al., 2016），因为在标记级别的任务下，从两个方向分析上下文是至关重要的。 在本文中，我们通过提出 BERT 改进了基于微调的方法：来自 Transformer 的双向编码器表示。受完形填空任务的启发，BERT 通过提出一个新的预训练任务来解决前面提到的单向约束：“遮蔽语言模型”（MLM masked language model）（Tay-lor, 1953）。遮蔽语言模型从输入中随机遮蔽一些标记，目的是仅根据被遮蔽标记的上下文来预测它对应的原始词汇的 id。与从左到右的语言模型预训练不同，MLM 目标允许表示融合左右上下文，这允许我们预训练一个深层双向 Transformer。除了遮蔽语言模型之外，我们还提出了一个联合预训练文本对来进行“下一个句子预测”的任务。 本文的贡献如下： 我们论证了双向预训练对语言表征的重要性。与 Radford et al., 2018 使用单向语言模型进行预训练不同，BERT 使用遮蔽语言模型来实现预训练深层双向表示。这也与 Peters et al., 2018 的研究形成了对比，他们使用了一个由左到右和由右到左的独立训练语言模型的浅层连接。 我们表明，预训练的表示消除了许多特定于任务的高度工程化的模型结构的需求。BERT 是第一个基于微调的表示模型，它在大量的句子级和标记级任务上实现了最先进的性能，优于许多特定于任务的结构的模型。 BERT 为 11 个 NLP 任务提供了最先进的技术。我们还进行大量的消融研究，证明了我们模型的双向本质是最重要的新贡献。代码和预训练模型将可在 goo.gl/language/bert 获取。 2 相关工作预训练通用语言表示有很长的历史，我们将在本节简要回顾最流行的方法。 2.1 基于特征的方法几十年来，学习广泛适用的词语表示一直是一个活跃的研究领域，包括非神经网络学领域（Brown et al., 1992;;Blitzer et al., 2006）和神经网络领域（Collobert and Weston, 2008；Mikolov et al., 2013；Pennington et al., 2014）方法。经过预训练的词嵌入被认为是现代 NLP 系统的一个不可分割的部分，词嵌入提供了比从头开始学习的显著改进（Turian et al., 2010）。 这些方法已被推广到更粗的粒度，如句子嵌入（Kiros et al., 2015；Logeswaran and Lee, 2018）或段落嵌入（Le and Mikolov, 2014）。与传统的单词嵌入一样，这些学习到的表示通常也用作下游模型的输入特征。 ELMo（Peters et al., 2017）从不同的维度对传统的词嵌入研究进行了概括。他们建议从语言模型中提取上下文敏感的特征。在将上下文嵌入与特定于任务的架构集成时，ELMo 为几个主要的 NLP 标准提供了最先进的技术（Peters et al., 2018)，包括在 SQuAD 上的问答（Rajpurkar et al., 2016），情感分析（Socher et al., 2013），和命名实体识别（jong Kim Sang and De Meul-der, 2003）。 2.2 基于微调的方法语言模型迁移学习（LMs）的一个最新趋势是，在对受监督的下游任务的模型进行微调之前，先对 LM 目标上的一些模型构造进行预训练（Dai and Le, 2015；Howard and Ruder, 2018；Radford et al., 2018）。这些方法的优点是只有很少的参数需要从头开始学习。至少部分得益于这一优势，OpenAI GPT （Radford et al., 2018）在 GLUE 基准测试的许多句子级任务上取得了此前最先进的结果（Wang et al.(2018))。 2.3 从有监督的数据中迁移学习虽然无监督预训练的优点是可用的数据量几乎是无限的，但也有研究表明，从具有大数据集的监督任务中可以进行有效的迁移，如自然语言推理（Con-neau et al., 2017）和机器翻译（McCann et al., 2017）。在NLP之外，计算机视觉研究也证明了从大型预训练模型中进行迁移学习的重要性，有一个有效的方法可以微调在 ImageNet 上预训练的模型（Deng et al., 2009；Yosinski et al., 2014） 3 BERT本节将介绍 BERT 及其具体实现。首先介绍了 BERT 模型结构和输入表示。然后我们在 3.3 节介绍本文的核心创新——预训练任务。在 3.4 和 3.5 节中分别详细介绍了预训练过程和微调模型过程。最后，在 3.6 节中讨论了 BERT 和 OpenAI GPT 之间的区别。 3.1 模型结构BERT 的模型结构是一个基于 Vaswani et al.(2017) 描述的原始实现的多层双向 Transformer 编码器，并且 Transformer 编码器发布在 tensor2tensor 代码库中。由于最近 Transformer 的使用已经非常普遍，而且我们的实现与最初的实现实际上是相同的，所以我们将省略对模型结构的详尽的背景描述，并向读者推荐 Vaswani et al.(2017) 以及优秀的指南，如“带注释的 Transformer”。 在这项工作中，我们表示层的数量(即，Transformer 块)为 $L$，隐藏尺寸为 $H$，自注意头的个数为 $A$。在所有例子中，我们将前馈/过滤器的大小设置为 $4H$，即当 $H = 768$ 时是 $3072$；当 $H = 1024$ 是 $4096$。我们主要分析两个模型大小的结果: $BERT_{BASE}: L=12, H=768, A=12, Total Parameters=110M$ $BERT_{LARGE}: L=24, H=1024, A=16, Total Parameters=340M$ 为了方便比较，$BERT_{BASE}$ 选择了与 OpenAI GPT 一样的模型大小。然而，重要的是，BERT Transformer 使用的是双向的自注意力，而 GPT Transformer 使用的是受限的自注意力，每个标记只能关注其左边的语境。我们注意到，在文献中，双向 Transformer 通常被称为“Transformer 编码器”，而只有标记左侧语境的版本由于可以用于文本生成而被重新定义为“Transformer 解码器”。BERT、OpenAI GPT 和 ELMo 之间的比较如图 1 所示。 图 1：预训练模型结构的不同。BERT 使用双向 Transformer。OpenAI GPT 使用 从左到右的 Transformer。ELMo 使用独立训练的从左到右和从右到左的 LSTM 的连接来为下游任务生成特征。其中，只有 BERT 表示在所有层中同时受到左右语境的制约。 3.2 输入表示我们的输入表示能够在一个标记序列中清楚地表示单个文本句子或一对文本句子(例如，[Question, Answer])。（注释：在整个工作中，“句子”可以是连续的任意跨度的文本，而不是实际语言意义上的句子。“序列”是指输入到 BERT 的标记序列，它可以是单个句子，也可以是两个句子组合在一起。）通过把给定标记对应的标记嵌入、句子嵌入和位置嵌入求和来构造其输入表示。图 2 给出了输入表示的可视化表示。细节是: 我们使用含 3 万个标记词语的 WordPiece 嵌入（Wu et al., 2016）。我们用 ## 表示拆分的单词片段。 我们使用学习到的位置嵌入，支持的序列长度最长可达 512 个标记。 每个序列的第一个标记始终是特殊分类嵌入（[CLS]）。该特殊标记对应的最终隐藏状态（即，Transformer 的输出）被用作分类任务中该序列的总表示。对于非分类任务，这个最终隐藏状态将被忽略。 句子对被打包在一起形成一个单独的序列。我们用两种方法区分这些句子。方法一，我们用一个特殊标记（[SEP]）将它们分开。方法二，我们给第一个句子的每个标记添加一个可训练的句子 A 嵌入，给第二个句子的每个标记添加一个可训练的句子 B 嵌入。 对于单句输入，我们只使用句子 A 嵌入。 图 2：BERT 的输入表示。输入嵌入是标记嵌入（词嵌入）、句子嵌入和位置嵌入的总和。 3.3.1 任务一#：遮蔽语言模型直觉上，我们有理由相信，深度双向模型严格来说比从左到右模型或从左到右模型结合从右到左模型的浅层连接更强大。不幸的是，标准条件语言模型只能从左到右或从右到左进行训练，因为双向条件作用将允许每个单词在多层上下文中间接地“看到自己”。 为了训练深度双向表示，我们采用了一种简单的方法，即随机遮蔽一定比例的输入标记，然后仅预测那些被遮蔽的标记。我们将这个过程称为“遮蔽语言模型”（MLM），尽管在文献中它通常被称为完形填词任务（Taylor, 1953）。在这种情况下，就像在标准语言模型中一样，与遮蔽标记相对应的最终隐藏向量被输入到与词汇表对应的输出 softmax 中（也就是要把被遮蔽的标记对应为词汇表中的一个词语）。在我们所有的实验中，我们在每个序列中随机遮蔽 15% 的标记。与去噪的自动编码器（Vincent et al., 2008）不同的是，我们只是让模型预测被遮蔽的标记，而不是要求模型重建整个输入。 虽然这确实允许我们获得一个双向预训练模型，但这种方法有两个缺点。第一个缺点是，我们在预训练和微调之间造成了不匹配，因为 [MASK] 标记在微调期间从未出现过。为了缓和这种情况，我们并不总是用真的用 [MASK] 标记替换被选择的单词。而是，训练数据生成器随机选择 15% 的标记，例如，在my dog is hairy 这句话中，它选择 hairy。然后执行以下步骤: 数据生成不会总是用 [MASK] 替换被选择的单词，而是执行以下操作: 80% 的情况下：用 [MASK] 替换被选择的单词，例如，my dog is hairy → my dog is [MASK] 10% 的情况下：用一个随机单词替换被选择的单词，例如，my dog is hairy → my dog is apple 10% 的情况下：保持被选择的单词不变，例如，my dog is hairy → my dog is hairy。这样做的目的是使表示偏向于实际观察到的词。 Transformer 编码器不知道它将被要求预测哪些单词，或者哪些单词已经被随机单词替换，因此它被迫保持每个输入标记的分布的上下文表示。另外，因为随机替换只发生在 1.5% 的标记（即，15% 的 10%）这似乎不会损害模型的语言理解能力。 第二个缺点是，使用 Transformer 的每批次数据中只有 15% 的标记被预测，这意味着模型可能需要更多的预训练步骤来收敛。在 5.3 节中，我们证明了 Transformer 确实比从左到右的模型（预测每个标记）稍微慢一点，但是 Transformer 模型的实验效果远远超过了它增加的预训练模型的成本。 3.3.2 任务2#：下一句预测许多重要的下游任务，如问题回答（QA）和自然语言推理（NLI），都是建立在理解两个文本句子之间的关系的基础上的，而这并不是语言建模直接捕捉到的。为了训练一个理解句子关系的模型，我们预训练了一个下一句预测的二元分类任务，这个任务可以从任何单语语料库中简单地归纳出来。具体来说，在为每个训练前的例子选择句子 A 和 B 时，50% 的情况下 B 是真的在 A 后面的下一个句子，50% 的情况下是来自语料库的随机句子。比如说: 我们完全随机选择不是下一句的句子，最终的预训练模型在这个任务中达到了 97%-98% 的准确率。尽管这个任务很简单，但是我们在 5.1 节中展示了针对此任务的预训练对 QA 和 NLI 都非常有益。 3.4 预训练过程预训练过程大体上遵循以往文献中语言模型预训练过程。对于预训练语料库，我们使用 BooksCorpus（800M 单词）（Zhu et al., 2015）和英语维基百科（2,500M 单词）。对于维基百科，我们只提取文本段落，而忽略列表、表格和标题。为了提取长的连续序列，使用文档级别的语料库，而不是使用像 Billion Word Benchmark （Chelba et al., 2013）那样使用打乱顺序的句子级别语料库是至关重要的。 为了生成每个训练输入序列，我们从语料库中采样两段文本，我们将其称为“句子”，尽管它们通常比单个句子长得多（但也可以短一些）。第一个句子添加 A 嵌入，第二个句子添加 B 嵌入。50% 的情况下 B 确实是 A 后面的实际下一句，50% 的情况下它是随机选取的一个的句子，这是为“下一句预测”任务所做的。两句话合起来的长度要小于等于 512 个标记。语言模型遮蔽过程是在使用 WordPiece 序列化句子后，以均匀的 15% 的概率遮蔽标记，不考虑部分词片的影响（那些含有被 WordPiece 拆分，以##为前缀的标记）。 我们使用 256 个序列（256 个序列 * 512 个标记= 128,000 个标记/批次）的批大小进行 1,000,000 步的训练，这大约是在 33 亿词的语料库中训练 40 个周期。我们用Adam 优化算法并设置其学习率为 $1e-4$，$β1 = 0.9,β2 = 0.999$，$L2$ 的权重衰减是 0.01，并且在前 10000 步学习率热身（learning rate warmup），然后学习率开始线性衰减。我们在所有层上使用 0.1 概率的 dropout。像 OpenAI GPT 一样，我们使用 gelu 激活（Hendrycks and Gimpel, 2016）而不是标准 relu。训练损失是遮蔽语言模型似然值与下一句预测似然值的平均值。 在 4 块 Cloud TPU（共含有 16 块 TPU）上训练 $BERT_{BASE}$。在 16 块 Cloud TPU（共含有 64 块 TPU）训练 $BERT_{LARGE}$。每次训练前需要 4 天的时间。 3.5 微调过程对于序列级别的分类任务，BERT 微调非常简单。为了获得输入序列的固定维度的表示，我们取特殊标记（[CLS]）构造相关的嵌入对应的最终的隐藏状态(即，为 Transformer 的输出)的池化后输出。我们把这个向量表示为 $C \in \mathbb{R}^H$，在微调期间唯一需要的新增加的参数是分类层的参数矩阵 $W \in \mathbb{R}^{K \times H}$，其中 $K$ 是要分类标签的数量。分类标签的概率$P \in \mathbb{R}^K$ 由一个标准的 softmax 来计算，$P=softmax(CW^T)$。对 BERT 的参数矩阵 $W$ 的所有参数进行了联合微调，使正确标签的对数概率最大化。对于区间级和标记级预测任务，必须以特定于任务的方式稍微修改上述过程。具体过程见第 4 节的相关内容。 对于微调，除了批量大小、学习率和训练次数外，大多数模型超参数与预训练期间相同。Dropout 概率总是使用 0.1。最优超参数值是特定于任务的，但我们发现以下可能值的范围可以很好地在所有任务中工作: Batch size: 16, 32 Learning rate (Adam): 5e-5, 3e-5, 2e-5 Number of epochs: 3, 4 我们还观察到大数据集（例如 100k+ 标记的训练集）对超参数选择的敏感性远远低于小数据集。微调通常非常快，因此只需对上述参数进行完全搜索，并选择在验证集上性能最好的模型即可。 3.6 BERT 和 OpenAI GPT 的比较在现有预训练方法中，与 BERT 最相似的是 OpenAI GPT，它在一个大的文本语料库中训练从左到右的 Transformer 语言模型。事实上，BERT 中的许多设计决策都是有意选择尽可能接近 GPT 的，这样两种方法就可以更加直接地进行比较。我们工作的核心论点是，在 3.3 节中提出的两项新的预训练语言模型任务占了实验效果改进的大部分，但是我们注意到 BERT 和 GPT 在如何训练方面还有其他几个不同之处: GPT 是在 BooksCorpus（800M 词）上训练出来的；BERT 是在 BooksCor-pus（800M 词）和 Wikipedia（2,500M 词）上训练出来的。 GPT 仅在微调时使用句子分隔符（[SEP]）和分类标记（[CLS]）；BERT 在预训练时使用 [SEP]， [CLS] 和 A/B 句嵌入。 GPT 在每批次含 32,000 词上训练了 1M 步；BERT 在每批次含 128,000 词上训练了 1M 步。 GPT 在所有微调实验中学习速率均为 5e-5；BERT 选择特定于任务的在验证集中表现最好的微调学习率。 为了分清楚这些差异的带来的影响，我们在 5.1 节中的进行每一种差异的消融实验表明，大多数的实验效果的改善实际上来自新的预训练任务（遮蔽语言模型和下一句预测任务）。 图 3：我们具体于特定任务的模型是通过给 BERT 加一个额外的输出层构成，所以仅需要从头学习最小数量的参数。其中（a）和（b）是序列级任务，（c）和（d）是标记级任务。图中 $E$ 表示嵌入的输入，$Ti$ 表示第 $i$ 个标记的上下文表示，[CLS] 是分类输出的特殊符号，[SEP] 是分离非连续标记（分离两个句子）序列的特殊符号。 4. 实验在这一节，我们将展示 BERT 在 11 项自然语言处理任务中的微调结果。 4.1 GLUE 数据集通用语言理解评价 (GLUE General Language Understanding Evaluation) 基准（Wang et al.(2018)）是对多种自然语言理解任务的集合。大多数 GLUE 数据集已经存在多年，但 GLUE 的用途是（1）以分离的训练集、验证集和测试集的标准形式发布这些数据集；并且（2）建立一个评估服务器来缓解评估不一致和过度拟合测试集的问题。GLUE 不发布测试集的标签，用户必须将他们的预测上传到 GLUE 服务器进行评估，并对提交的数量进行限制。 GLUE 基准包括以下数据集，其描述最初在 Wang et al.(2018)中总结: MNLI 多类型的自然语言推理（Multi-Genre Natural Language Inference）是一项大规模的、众包的蕴含分类任务（Williams et al.， 2018）。给定一对句子，目的是预测第二个句子相对于第一个句子是暗含的、矛盾的还是中立的关系。 QQP Quora问题对（Quora Question Pairs）是一个二元分类任务，目的是确定两个问题在Quora上问的语义是否相等 （Chen et al., 2018）。 QNLI 问题自然语言推理（Question Natural Language Inference）是斯坦福问题回答数据集（Rajpurkar et al., 2016）已经转换为二进制分类任务的一个版本 Wang et al.(2018)。正类的例子是（问题，句子）对，句子中包含正确的答案，和负类的例子是来自同一段的（问题，句子）对，句子中不包含正确的答案。 SST-2 斯坦福情感语义树（Stanford Sentiment Treebank）数据集是一个二元单句分类任务，数据由电影评论中提取的句子组成，并对由人工对这些句子进行标注（Socher et al., 2013）。 CoLA 语言可接受性单句二元分类任务语料库（Corpus of Linguistic Acceptability），它的目的是预测一个英语句子在语言学上是否 “可接受”（Warstadt et al., 2018）。 STS-B 文本语义相似度基准（Semantic Textual Similarity Bench-mark ）是从新闻标题中和其它来源里提取的句子对的集合（Cer et al., 2017）。他们用从 1 到 5 的分数标注，表示这两个句子在语义上是多么相似。 MRPC 微软研究释义语料库（Microsoft Research Paraphrase Corpus）从在线新闻中自动提取的句子对组成，并用人工注解来说明这两个句子在语义上是否相等（Dolan and Brockett, 2005.）。 RTE 识别文本蕴含（Recognizing Textual Entailment）是一个与 MNLI 相似的二元蕴含任务，只是 RTE 的训练数据更少 Bentivogli et al., 2009。 WNLI 威诺格拉德自然语言推理（Winograd NLI）是一个来自（Levesque et al., 2011) ）的小型自然语言推理数据集。GLUE网页提示到这个数据集的构造存在问题，每一个被提交给 GLUE 的经过训练的系统在预测多数类时都低于 65.1 这个基线准确度。因此，出于对 OpenAI GPT 的公平考虑，我们排除了这一数据集。对于我们的 GLUE 提交，我们总是预测多数类。 4.1.1 GLUE 结果为了在 GLUE 上微调模型，我们按照本文第 3 节中描述的那样表示输入的句子或者句子对，并且使用最后一层的隐藏向量 $C \in \mathbb{R}^H$ 中的第一个输入标记（[CLS]）作为句子总的表示。如图3 （a）和（b）所示。在微调期间唯一引入的新的参数是一个分类层参数矩阵 $W \in \mathbb{R}^{K \times H}$，其中 $K$ 是要分类的数量。我们用 $C$ 和 $W$ 计算一个标准的分类损失，换句话说是 $log(softmax(CW^T))$。 我们在 GLUE 所有的任务中使用 32 的批次大小和 3 个周期。对于每个任务我们使用 $5e-5, 4e-5, 3e-5, 2e-5$ 的学习率来微调，然后在验证集中选择表现最好的学习率。此外，对于 $BERT_{LARGE}$ 我们发现它有时在小数据集上微调时不稳定（换句话说是，有时运行时会使结果更差），因此，我们进行了几次随机重启，并选择了在验证集上表现最好的模型。对于随机重启，我们使用相同的预训练检查点，但执行不同的数据打乱和分类器层初始化来微调模型。我们注意到，GLUE 发布的数据集不包括测试的标签，所以我们分别将 $BERT_{BASE}$ 和 $BERT_{LARGE}$ 向 GLUE 评估服务器提交结果。 结果如表 1 所示。在所有的任务上，$BERT_{BASE}$ 和 $BERT_{LARGE}$ 都比现有的系统更加出色 ，与先进水平相比，分别取得 4.4% 及 6.7% 的平均改善。请注意，除了 $BERT_{BASE}$ 含有注意力屏蔽（attention masking），$BERT_{BASE}$ 和 OpenAI GPT 的模型结构方面几乎是相同的。对于最大和最广泛使用的 GLUE 任务 MNLI，BERT 比当前最优模型获得了 4.7% 的绝对提升。在 GLUE 官方的排行榜上， $BERT_{LARGE}$ 获得了 80.4 的分数，与原榜首的 OpenAI GPT 相比截止本文写作时只获得了 72.8 分。 有趣的是， $BERT_{LARGE}$ 在所有任务中都显著优于 $BERT_{BASE}$，即使是在那些只有很少训练数据的任务上。BERT 模型大小的影响在本文 5.2 节有更深入的探讨。 表 1：GLUE 测试结果，由 GLUE 评估服务器评分。每个任务下面的数字表示训练示例的数量。“Average”列与官方 GLUE 评分略有不同，因为我们排除了有问题的 WNLI 数据集。OpenAI GPT = (L=12, H=768, A=12); BERTBASE = (L=12, H=768, A=12); BERTLARGE = (L=24, H=1024, A=16)。BERT 和 OpenAI GPT 都是单模型，单任务。所有结果可以从 https://gluebenchmark.com/leaderboard 和 https://blog.openai.com/language-unsupervised/ 获得。 4.2 SQuAD v1.1斯坦福问答数据集（SQuAD Standford Question Answering Dataset）是一个由 100k 个众包的问题/答案对组成的集合（Rajpurkar et al., 2016）。给出一个问题和一段来自维基百科包含这个问题答案的段落，我们的任务是预测这段答案文字的区间。例如: 输入问题：Where do water droplets collide with ice crystals to form precipitation? 输入段落… Precipitation forms as smaller droplets coalesce via collision with other rain drops or ice crystals within a cloud. … 输出答案within a cloud 这种区间预测任务与 GLUE 的序列分类任务有很大的区别，但是我们能够让 BERT 以一种直接的方式在 SQuAD 上运行。就像在 GLUE 中，我们将输入问题和段落表示为一个单一打包序列（packed sequence），其中问题使用 A 嵌入，段落使用 B 嵌入。在微调模型期间唯一需要学习的新参数是区间开始向量 $S \in \mathbb{R}^H$ 和区间结束向量 $E \in \mathbb{R}^H$。让 BERT 模型最后一层的隐藏向量的第 $i^{th}$ 输入标记被表示为 $T_i \in \mathbb{R}^H$。如图 3（c）可视化的表示。然后，计算单词 $i$ 作为答案区间开始的概率，它是 $T_i$ 和 $S$ 之间的点积并除以该段落所有单词的结果之后再 softmax: P_i=\dfrac{e^{S \cdot T_i}}{\sum_j e^{S \cdot T_j}}同样的式子用来计算单词作为答案区间的结束的概率，并采用得分最高的区间作为预测结果。训练目标是正确的开始和结束位置的对数可能性。 我们使用 $5e-5$ 的学习率，32 的批次大小训练模型 3 个周期。在模型推断期间，因为结束位置与开始位置没有条件关系，我们增加了结束位置必须在开始位置之后的条件，但没有使用其他启发式。为了方便评估，把序列化后的标记区间对齐回原始未序列化的输入。 结果如表 2 中描述那样。SQuAD 使用一个高度严格的测试过程，其中提交者必须手动联系小组组织人员，然后在一个隐藏的测试集上运行他们的系统，所以我们只提交了最好的模型来测试。表中显示的结果是我们提交给小组的第一个也是唯一一个测试。我们注意到上面的结果在小组排行榜上没有最新的公共模型描述，并被允许在训练他们的模型时使用任何的公共数据。因此，我们在提交的模型中使用非常有限的数据增强，通过在 SQuAD 和 TriviaQA(Joshi et al., 2017) 联合训练。 我们表现最好的模型在集成模型排名中上比排名第一模型高出 1.5 个 F1 值，在一个单模型排行榜中比排名第一的模型高出 1.7（译者注：原文是 1.3） 个 F1 值。实际上，我们的单模型 BERT 就比最优的集成模型表现更优。即使只在 SQuAD 数据集上（不用 TriviaQA 数据集）我们只损失 0.1-0.4 个 F1 值，而且我们的模型输出结果仍然比现有模型的表现好很多。 表 2：SQuAD 结果。Ensemble BERT 是使用不同的预训练模型检查点和微调种子的 7x 模型。 4.3 命名实体识别为了评估标记任务的性能，我们在 CoNLL 2003 命名实体识别数据集（NER Named Entity Recognition）上微调 BERT 模型。该数据集由 200k 个训练单词组成，这些训练词被标注为人员、组织、地点、杂项或其他（无命名实体）。 为了微调，我们将最后一层每个单词的隐藏表示 $T_i \in \mathbb{R}^H$ 送入一个在 NER 标签集合的分类层。每个单词的分类不以周围预测为条件（换句话说，没有自回归和没有 CRF）。为了与词块（WordPiece）序列化相适应，我们把 CoNLI-序列化的（CoNLL-tokenized）的输入词输入我们的 WordPiece 序列化器，然后使用这些隐藏状态相对应的第一个块而不用预测标记为 X的块。例如： 由于单词块序列化边界是输入中已知的一部分，因此对训练和测试都要这样做。结果如表 3 所示。$BERT_{LARGE}$ 优于现存的最优模型，使用多任务学习的交叉视野训练 (Clark et al., 2018)，CoNLL-2003 命名实体识别测试集上高 0.2 F1 值。 表 3：CoNLL-2003 命名实体识别。模型超参数使用验证集进行选择，报告的验证集和测试分数使用这些超参数进行随机五次以上的实验然后取实验的平均结果。 4.4 SWAGAdversarial Generations（SWAG）数据集由 113k 个句子对组合而成，用于评估基于常识的推理 (Zellers et al., 2018)。 给出一个来自视频字幕数据集的句子，任务是在四个选项中选择最合理的延续。例如: 为 SWAG 数据集调整 BERT 模型的方式与为 GLUE 数据集调整的方式相似。对于每个例子，我们构造四个输入序列，每一个都连接给定的句子（句子A）和一个可能的延续（句子B）。唯一的特定于任务的参数是我们引入向量 $V \in \mathbb{R}^{H}$，然后它点乘最后层的句子总表示 $C_i \in \mathbb{R}^H$ 为每一个选择 $i$ 产生一个分数。概率分布为 softmax 这四个选择: P_i=\dfrac{e^{V \cdot C_i}}{\sum_j^4 e^{S \cdot C_j}}我们使用 $2e-5$ 的学习率，16 的批次大小训练模型 3 个周期。结果如表 4 所示。$BERT_{LARGE}$ 优于作者的 ESIM+ELMo 的基线标准模型的 27.1% 。 表 4：SWAG 验证集和测试集准确率。测试结果由 SWAG 作者对隐藏的标签进行评分。人类的表现是用 100 个样本来衡量的，正如 SWAG 论文中描述的那样。 5. 消融研究（Ablation Studies）虽然我们已经证明了非常强有力的实证结果，但到目前为止提出的结果并没有提现出 BERT 框架的每个部分具体的贡献。在本节中，我们对 BERT 的许多方面进行了消融实验，以便更好地理解每个部分的相对重要性。 5.1 预训练任务的影响我们的核心观点之一是，与之前的工作相比，BERT 的深层双向性（通过遮蔽语言模型预训练）是最重要的改进。为了证明这一观点，我们评估了两个新模型，它们使用与 $BERT_{BASE}$ 完全相同的预训练数据、微调方案和 Transformer 超参数： No NSP：模型使用“遮蔽语言模型”（MLM）但是没有“预测下一句任务”（NSP）。 LTR &amp; No NSP：模型使用一个从左到右（LTR）的语言模型，而不是遮蔽语言模型。在这种情况下，我们预测每个输入词，不应用任何遮蔽。在微调中也应用了仅限左的约束，因为我们发现使用仅限左的上下文进行预训练和使用双向上下文进行微调总是比较糟糕。此外，该模型未经预测下一句任务的预训练。这与OpenAI GPT有直接的可比性，但是使用更大的训练数据集、输入表示和微调方案。 结果如表 5 所示。我们首先分析了 NSP 任务所带来的影响。我们可以看到去除 NSP 对 QNLI、MNLI 和 SQuAD 的表现造成了显著的伤害。这些结果表明，我们的预训练方法对于获得先前提出的强有力的实证结果是至关重要的。 接着我们通过对比 “No NSP” 与 “LTR &amp; No NSP” 来评估训练双向表示的影响。LTR 模型在所有任务上的表现都比 MLM 模型差，在 MRPC 和 SQuAD 上的下降特别大。对于SQuAD来说，很明显 LTR 模型在区间和标记预测方面表现很差，因为标记级别的隐藏状态没有右侧上下文。因为 MRPC 不清楚性能差是由于小的数据大小还是任务的性质，但是我们发现这种性能差是在一个完全超参数扫描和许多次随机重启之间保持一致的。 为了增强 LTR 系统，我们尝试在其上添加一个随机初始化的 BiLSTM 来进行微调。这确实大大提高了 SQuAD 的成绩，但是结果仍然比预训练的双向模型表现差得多。它还会损害所有四个 GLUE 任务的性能。 我们注意到，也可以培训单独的 LTR 和 RTL 模型，并将每个标记表示为两个模型表示的连接，就像 ELMo 所做的那样。但是：（a）这是单个双向模型参数的两倍大小；（b）这对于像 QA 这样的任务来说是不直观的，因为 RTL 模型无法以问题为条件确定答案；（c）这比深层双向模型的功能要弱得多，因为深层双向模型可以选择使用左上下文或右上下文。 表 5：在预训练任务中使用 $BERT_{BASE}$ 模型进行消融实验。“No NSP”表示不进行下一句预测任务来训练模型。“LTR &amp; No NSP”表示就像 OpenAI GPT 一样，使用从左到右的语言模型不进行下一句预测任务来训练模型。“+ BiLSTM”表示在“LTR &amp; No NSP”模型微调时添加一个随机初始化的 BiLSTM 层。 5.2 模型大小的影响在本节中，我们将探讨模型大小对微调任务准确度的影响。我们用不同的层数、隐藏单位和注意力头个数训练了许多 BERT 模型，同时使用了与前面描述的相同的超参数和训练过程。 选定 GLUE 任务的结果如表 6 所示。在这个表中，我们报告了 5 次在验证集上的微调的随机重启的平均模型准确度。我们可以看到，更大的模型在所选 4 个数据集上都带来了明显的准确率上升，甚至对于只有 3600 个训练数据的 MRPC 来说也是如此，并且与预训练任务有很大的不同。也许令人惊讶的是，相对于现有文献，我们能够在现有的模型基础上实现如此显著的改进。例如，Vaswani et al.(2017) 研究的最大 Transformer 为(L=6, H=1024, A=16)，编码器参数为 100M，我们所知的文献中的最大 Transformer 为(L=64, H=512, A=2)，参数为235M（Al-Rfou et al., 2018）。相比之下，$BERT_{BASE}$ 含有 110M 参数而 $BERT_{LARGE}$ 含有 340M 参数。 多年来人们都知道，增加模型的大小将持续提升在大型任务(如机器转换和语言建模)上的的表现，表 6 所示的由留存训练数据（held-out traing data）计算的语言模型的困惑度（perplexity）。然而，我们相信，这是第一次证明，如果模型得到了足够的预训练，那么将模型扩展到极端的规模也可以在非常小的任务中带来巨大的改进。 表 6：调整 BERT 的模型大小。#L = 层数；#H = 隐藏维度大小；#A = 注意力头的个数。“LM (ppl)”表示遮蔽语言模型在预留训练数据上的困惑度。 5.3 训练步数的影响图 4 显示了经过 K 步预训练模型的检查点再模型微调之后在 MNLI 验证集上的准确率。这让我们能够回答下列问题: 问:BERT真的需要这么多的预训练 (128,000 words/batch * 1,000,000 steps) 来实现高的微调精度吗?答：是的，$BERT_{BASE}$ 在 MNLI 上进行 1M 步预训练时的准确率比 500k 步提高了近 1.0%。 问:遮蔽语言模型的预训练是否比 LTR 模型预训练训收敛得慢，因为每批只预测 15% 的单词，而不是每个单词?答：遮蔽语言模型的收敛速度确实比 LTR 模型稍慢。然而，在绝对准确性方面，遮蔽语言模型几乎在训练一开始就超越 LTR 模型。 图 4：调整模型的训练步数。图中展示了已经预训练了 k 步后的模型参数在 MNLI 数据集上的再经过微调后的准确率。x 轴的值就是 k。 5.4 使用 BERT 基于特征的方法到目前为止，所有的 BERT 结果都使用了微调方法，将一个简单的分类层添加到预训练的模型中，并在一个下行任务中对所有参数进行联合微调。然而，基于特征的方法，即从预训练模型中提取固定的特征，具有一定的优势。首先，并不是所有 NLP 任务都可以通过 Transformer 编码器体系结构轻松地表示，因此需要添加特定于任务的模型体系结构。其次，能够一次性耗费大量计算预先计算训练数据的表示，然后在这种表示的基础上使用更节省计算的模型进行许多实验，这有很大的计算优势。 在本节中，我们通过在 CoNLL-2003 命名实体识别任务上生成类似于 elmo 的预训练的上下文表示来评估基于特征的方法中的 BERT 表现有多好。为此，我们使用与第 4.3 节相同的输入表示，但是使用来自一个或多个层的激活输出，而不需要对BERT的任何参数进行微调。在分类层之前，这些上下文嵌入被用作对一个初始化的两层 768 维 Bi-LSTM 的输入。 结果如表 7 所示。最佳的执行方法是从预训练的转换器的前 4 个隐藏层串联符号表示，这只比整个模型的微调落后 0.3 F1 值。这说明 BERT 对于微调和基于特征的方法都是有效的。 表 7：在 CoNLL-2003 命名实体识别上使用基于特征的方法，并调整 BERT 层数。来自指定层的激活输出被组合起来，并被送到一个两层的 BiLSTM 中，而不需要反向传播到 BERT。 6. 结论最近，由于使用语言模型进行迁移学习而取得的实验提升表明，丰富的、无监督的预训练是许多语言理解系统不可或缺的组成部分。特别是，这些结果使得即使是低资源（少量标签的数据集）的任务也能从非常深的单向结构模型中受益。我们的主要贡献是将这些发现进一步推广到深层的双向结构，使同样的预训练模型能够成功地广泛地处理 NLP 任务。 虽然这些实证结果很有说服力，在某些情况下甚至超过了人类的表现，但未来重要的工作是研究 BERT 可能捕捉到的或不捕捉到的语言现象。 参考文献所有参考文献按论文各小节中引用顺序排列，多次引用会多次出现在下面的列表中。 Abstract 摘要中的参考文献 BERT 文中简写 原始标论文标题 其它 Peters et al., 2018 Deep contextualized word representations ELMo Radford et al., 2018 Improving Language Understanding with Unsupervised Learning OpenAI GPT 1. Introduction 介绍中的参考文献 BERT 文中简写 原始标论文标题 其它 Peters et al., 2018 Deep contextualized word representations ELMo Radford et al., 2018 Improving Language Understanding with Unsupervised Learning OpenAI GPT Dai and Le, 2015 Semi-supervised sequence learning. In Advances in neural information processing systems, pages 3079–3087 AndrewMDai and Quoc V Le. 2015 Howard and Ruder, 2018 Universal Language Model Fine-tuning for Text Classification ULMFiT；Jeremy Howard and Sebastian Ruder. Bow-man et al., 2015 A large annotated corpus for learning natural language inference Samuel R. Bowman, Gabor Angeli, Christopher Potts, and Christopher D. Manning. Williams et al., 2018 A Broad-Coverage Challenge Corpus for Sentence Understanding through Inference Adina Williams, Nikita Nangia, and Samuel R Bowman. Dolan and Brockett, 2005 Automatically constructing a corpus of sentential paraphrases William B Dolan and Chris Brockett. 2005. Tjong Kim Sang and De Meulder, 2003 Introduction to the CoNLL-2003 Shared Task: Language-Independent Named Entity Recognition Erik F Tjong Kim Sang and Fien De Meulder. 2003. Rajpurkar et al., 2016 SQuAD: 100,000+ Questions for Machine Comprehension of Text SQuAD Taylor, 1953 “Cloze Procedure”: A New Tool For Measuring Readability Wilson L Taylor. 1953. 2. Related Work 相关工作中的参考文献 BERT 文中简写 原始标论文标题 其它 Brown et al., 1992 Class-based n-gram models of natural language Peter F Brown, Peter V Desouza, Robert L Mercer, Vincent J Della Pietra, and Jenifer C Lai. 1992. Ando and Zhang, 2005 A Framework for Learning Predictive Structures from Multiple Tasks and Unlabeled Data Rie Kubota Ando and Tong Zhang. 2005. Blitzer et al., 2006 Domain adaptation with structural correspondence learning John Blitzer, Ryan McDonald, and Fernando Pereira.2006. Collobert and Weston, 2008 A Unified Architecture for Natural Language Processing Ronan Collobert and Jason Weston. 2008. Mikolov et al., 2013 Distributed Representations of Words and Phrases and their Compositionality CBOW Model；Skip-gram Model Pennington et al., 2014 GloVe: Global Vectors for Word Representation GloVe Turian et al., 2010 Word Representations: A Simple and General Method for Semi-Supervised Learning Joseph Turian, Lev Ratinov, and Yoshua Bengio. 2010. Kiros et al., 2015 Skip-Thought Vectors Skip-Thought Vectors Logeswaran and Lee, 2018 An efficient framework for learning sentence representations Lajanugen Logeswaran and Honglak Lee. 2018. Le and Mikolov, 2014 Distributed Representations of Sentences and Documents Quoc Le and Tomas Mikolov. 2014. Peters et al., 2017 Semi-supervised sequence tagging with bidirectional language models Matthew Peters, Waleed Ammar, Chandra Bhagavatula, and Russell Power. 2017. Peters et al., 2018 Deep contextualized word representations ELMo Rajpurkar et al., 2016 SQuAD: 100,000+ Questions for Machine Comprehension of Text SQuAD Socher et al., 2013 Deeply Moving: Deep Learning for Sentiment Analysis SST-2 Tjong Kim Sang and De Meulder, 2003 Introduction to the CoNLL-2003 Shared Task: Language-Independent Named Entity Recognition Erik F Tjong Kim Sang and Fien De Meulder. 2003. Dai and Le, 2015 Semi-supervised sequence learning. In Advances in neural information processing systems, pages 3079–3087 AndrewMDai and Quoc V Le. 2015 Howard and Ruder, 2018 Universal Language Model Fine-tuning for Text Classification ULMFiT；Jeremy Howard and Sebastian Ruder. Radford et al., 2018 Improving Language Understanding with Unsupervised Learning OpenAI GPT Wang et al.(2018) GLUE: A Multi-Task Benchmark and Analysis Platform for Natural Language Understanding GLUE Con-neau et al., 2017 Supervised Learning of Universal Sentence Representations from Natural Language Inference Data Alexis Conneau, Douwe Kiela, Holger Schwenk, Loic Barrault, and Antoine Bordes. 2017. McCann et al., 2017 Learned in Translation: Contextualized Word Vectors Bryan McCann, James Bradbury, Caiming Xiong, and Richard Socher. 2017. Deng et al. ImageNet: A large-scale hierarchical image database J. Deng,W. Dong, R. Socher, L.-J. Li, K. Li, and L. FeiFei. 2009. Yosinski et al., 2014 How transferable are features in deep neural networks? Jason Yosinski, Jeff Clune, Yoshua Bengio, and Hod Lipson. 2014. 3. BERT 中的参考文献 BERT 文中简写 原始标论文标题 其它 Vaswani et al. (2017) Attention Is All You Need Transformer Wu et al., 2016 Google’s Neural Machine Translation System: Bridging the Gap between Human and Machine Translation WordPiece Taylor, 1953 “Cloze Procedure”: A New Tool For Measuring Readability Wilson L Taylor. 1953. Vincent et al., 2008 Extracting and composing robust features with denoising autoencoders denoising auto-encoders Zhu et al., 2015 Aligning Books and Movies: Towards Story-like Visual Explanations by Watching Movies and Reading Books BooksCorpus (800M words) Chelba et al., 2013 One Billion Word Benchmark for Measuring Progress in Statistical Language Modeling Billion Word Benchmark corpus Hendrycks and Gimpel, 2016 Gaussian Error Linear Units (GELUs) GELUs 4. Experiments 实验中的参考文献 BERT 文中简写 原始标论文标题 其它 Wang et al.(2018) GLUE: A Multi-Task Benchmark and Analysis Platform for Natural Language Understanding GLUE Williams et al., 2018 A Broad-Coverage Challenge Corpus for Sentence Understanding through Inference MNLI Chen et al., 2018 First Quora Dataset Release: Question Pairs QQP Rajpurkar et al., 2016 SQuAD: 100,000+ Questions for Machine Comprehension of Text QNLI Socher et al., 2013 Deeply Moving: Deep Learning for Sentiment Analysis SST-2 Warstadt et al., 2018 The Corpus of Linguistic Acceptability CoLA Cer et al., 2017 SemEval-2017 Task 1: Semantic Textual Similarity - Multilingual and Cross-lingual Focused Evaluation STS-B Dolan and Brockett, 2005 Automatically constructing a corpus of sentential paraphrases MRPC Bentivogli et al., 2009 The fifth pascal recognizing textual entailment challenge RTE Levesque et al., 2011 The winograd schema challenge. In Aaai spring symposium: Logical formalizations of commonsense reasoning, volume 46, page 47. WNLI Rajpurkar et al., 2016 SQuAD: 100,000+ Questions for Machine Comprehension of Text SQuAD Joshi et al., 2017 TriviaQA: A Large Scale Distantly Supervised Challenge Dataset for Reading Comprehension TriviaQA Clark et al., 2018 Semi-Supervised Sequence Modeling with Cross-View Training Zellers et al., 2018 SWAG: A Large-Scale Adversarial Dataset for Grounded Commonsense Inference SWAG 5. Ablation Studies 消融研究中的参考文献 BERT 文中简写 原始标论文标题 其它 Vaswani et al. (2017) Attention Is All You Need Transformer Al-Rfou et al., 2018 Character-Level Language Modeling with Deeper Self-Attention]]></content>
      <categories>
        <category>论文</category>
        <category>论文写作</category>
      </categories>
      <tags>
        <tag>BERT</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[EM最大期望算法]]></title>
    <url>%2F2018%2F12%2F23%2FEM%E6%9C%80%E5%A4%A7%E6%9C%9F%E6%9C%9B%E7%AE%97%E6%B3%95%2F</url>
    <content type="text"><![CDATA[本文对最大期望算法的理解 来自—引入最大期望算法—最大期望算法 来自—最大期望算法实例—EM算法 对照理解李航《统计机器学习》P158 的 Q 函数定义9.1 （Q函数） 完全数据的对数似然函数 $logP(Y,Z|\theta)$ 关于在给定观测数据 $Y$ 和当前参数 $\theta^{(i)}$ 下对未观测数据 $Z$ 的条件概率分布 $P(Z|Y,\theta^{(i)})$ 的期望成为 $Q$ 函数，即， Q(\theta,\theta^{(i)})=E_Z[logP(Y,Z|\theta);Y,\theta^{(i)}] 完全数据的对数似然函数 $logP(Y,Z|\theta)$ —-&gt; $logPr(X=x,Y=y;\theta’)$定观测数据 $Y$ —-&gt; $x$当前参数 $\theta^{(i)}$ —-&gt; $\theta^{(i)}$未观测数据 $Z$ —-&gt; $y$条件概率分布 $P(Z|Y,\theta^{(i)})$ —-&gt; $Pr(Y=y|X=x)$的期望成为 $Q$ 函数 —-&gt; “上面的每行第3列和第4列相乘，最后再按行相加，就得到关于θ(i+1)的函数” 简易速推 Q 公式在不包含隐变量的情况下，我们求最大似然的时候只需要进行求导使导函数等于0，求出参数即可。但是包含隐变量，直接求导就变得异常复杂，此时需要EM算法，首先求出隐变量的期望值（E步），然后，把隐变量当中常数，按照不包含隐变量的求解最大似然的方法解出参数（M步），反复迭代，最终收敛到局部最优。下面给出EM算法的推导。我们有对数似然函数: L(\theta)=\log P(y|\theta) = \log\sum_zp(y,z|\theta)可以表示成包含隐变量z的形式，然后通过边缘化再消除z，效果是一样的。 由于是迭代，我们需要每次得到的新的似然结果比上一次的似然结果要大，于是我们的目标是下式: \theta = \arg\max_\theta L(\theta) - L(\theta')由于L(θ′) 是常量，所以，使得L(θ)最大化即可。下面看看如何最大化 L(θ) :至此，得到传说中的Q函数，然后求解出参数θ即可。 引入最大期望算法 标题 说明 时间 怎么通俗易懂地解释EM算法并且举个例子? 知乎 机器学习笔记（十）EM算法及实践（以混合高斯模型（GMM）为例来次完整的EM） 简单引入EM算法 20170324 最大期望算法 20121203 最大期望算法的应用 K-means 聚类算法 混合高斯模型 plsa(Probabilistic Latent Semantic Analysis) 概率隐语义分析 最大期望算法实例 标题 说明 时间 EM算法 本文试图用最简单的例子、最浅显的方式说明EM（Expectation Maximization）算法的应用场景和使用方法，而略去公式的推导和收敛性的证明。 What is the expectation maximization algorithm? 解释EM的论文 20080101 EM算法（Expectation - Maximization）通俗实例（What is the expectation maximization algorithm?） What is the expectation maximization algorithm?的翻译 20170920 最大期望算法的理论推导 标题 说明 时间 stanford cs229 The EM algorithm Andrew Ng 理论推导 （EM算法）The EM Algorithm stanford cs229 The EM algorithm 的中文翻译 20110406 最大期望算法的相关博客 标题 说明 时间 EM-最大期望算法 stanford cs229 The EM algorithm 的中文翻译 + 个人理解 20151202]]></content>
      <categories>
        <category>机器学习</category>
        <category>最大期望算法</category>
      </categories>
      <tags>
        <tag>最大期望算法</tag>
        <tag>混合高斯模型</tag>
        <tag>K-means算法</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[TensorFlow_rnn_cell_impl源码阅读]]></title>
    <url>%2F2018%2F12%2F18%2FTensorFlow_rnn_cell_impl%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%2F</url>
    <content type="text"><![CDATA[实现RNN单元的模块。该模块提供了一些基本常用的RNN单元，如LSTM（长短期记忆）或GRU（门控循环单元），以及一些允许为输入添加 dropout、投影连接或嵌入的操作。构建多层单元格由“MultiRNNCellL”类支持，或多次调用 RNN OPS。 LSTM与GRU结构介绍 https://blog.csdn.net/qq_28743951/article/details/78974058三次简化一张图：一招理解LSTM/GRU门控机制 https://www.jiqizhixin.com/articles/2018-12-18-12 虽然理论上 RNN 可以捕获长距离依赖，但实际应用中，RNN 将会面临两个挑战：梯度爆炸（gradient explosion）和梯度消失（vanishing gradient）。 梯度爆炸相对比较好处理，可以用梯度裁剪（gradient clipping）来解决:在 RNN 中，不管梯度回传的时候大到什么程度，设置一个梯度的阈值，梯度最多是这么大。 梯度消失现象解决起来困难很多，如何缓解梯度消失是 RNN 及几乎其他所有深度学习方法研究的关键所在。LSTM 和 GRU 通过门（gate）机制控制 RNN 中的信息流动，用来缓解梯度消失问题。其核心思想是有选择性的处理输入。 LSTM 处理梯度消失问题的例子，比如我们在看到一个商品的评论时 Amazing! This box of cereal gave me a perfectly balanced breakfast, as all things should be. In only ate half of it but will definitely be buying again! 我们会重点关注其中的一些词，对它们进行处理 Amazing! This box of cereal gave me a perfectly balanced breakfast, as all things should be. In only ate half of it but will definitely be buying again! LSTM 和 GRU 的关键是会选择性地忽略其中一些词，不让其参与到隐层状态向量的更新中，最后只保留相关的信息进行预测。 tensorflow/tensorflow/python/ops/rnn_cell_impl.py“””Module implementing RNN Cells.This module provides a number of basic commonly used RNN cells, such as LSTM(Long Short Term Memory) or GRU (Gated Recurrent Unit), and a number ofoperators that allow adding dropouts, projections, or embeddings for inputs.Constructing multi-layer cells is supported by the class MultiRNNCell, or bycalling the rnn ops several times.“”” class RNNCell(base_layer.Layer)重点： Every RNNCell must have the properties below and implement call with the signature (output, next_state) = call(input, state). An RNN cell, in the most abstract setting, is anything that hasa state and performs some operation that takes a matrix of inputs.This operation results in an output matrix with self.output_size columns. 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147@tf_export("nn.rnn_cell.RNNCell")class RNNCell(base_layer.Layer): """Abstract object representing an RNN cell. Every `RNNCell` must have the properties below and implement `call` with the signature `(output, next_state) = call(input, state)`. The optional third input argument, `scope`, is allowed for backwards compatibility purposes; but should be left off for new subclasses. This definition of cell differs from the definition used in the literature. In the literature, 'cell' refers to an object with a single scalar output. This definition refers to a horizontal array of such units. An RNN cell, in the most abstract setting, is anything that has a state and performs some operation that takes a matrix of inputs. This operation results in an output matrix with `self.output_size` columns. If `self.state_size` is an integer, this operation also results in a new state matrix with `self.state_size` columns. If `self.state_size` is a (possibly nested tuple of) TensorShape object(s), then it should return a matching structure of Tensors having shape `[batch_size].concatenate(s)` for each `s` in `self.batch_size`. """ def __init__(self, trainable=True, name=None, dtype=None, **kwargs): super(RNNCell, self).__init__( trainable=trainable, name=name, dtype=dtype, **kwargs) # Attribute that indicates whether the cell is a TF RNN cell, due the slight # difference between TF and Keras RNN cell. self._is_tf_rnn_cell = True def __call__(self, inputs, state, scope=None): """Run this RNN cell on inputs, starting from the given state. Args: inputs: `2-D` tensor with shape `[batch_size, input_size]`. state: if `self.state_size` is an integer, this should be a `2-D Tensor` with shape `[batch_size, self.state_size]`. Otherwise, if `self.state_size` is a tuple of integers, this should be a tuple with shapes `[batch_size, s] for s in self.state_size`. scope: VariableScope for the created subgraph; defaults to class name. Returns: A pair containing: - Output: A `2-D` tensor with shape `[batch_size, self.output_size]`. - New state: Either a single `2-D` tensor, or a tuple of tensors matching the arity and shapes of `state`. """ if scope is not None: with vs.variable_scope(scope, custom_getter=self._rnn_get_variable) as scope: return super(RNNCell, self).__call__(inputs, state, scope=scope) else: scope_attrname = "rnncell_scope" scope = getattr(self, scope_attrname, None) if scope is None: scope = vs.variable_scope(vs.get_variable_scope(), custom_getter=self._rnn_get_variable) setattr(self, scope_attrname, scope) with scope: return super(RNNCell, self).__call__(inputs, state) def _rnn_get_variable(self, getter, *args, **kwargs): variable = getter(*args, **kwargs) if context.executing_eagerly(): trainable = variable._trainable # pylint: disable=protected-access else: trainable = ( variable in tf_variables.trainable_variables() or (isinstance(variable, tf_variables.PartitionedVariable) and list(variable)[0] in tf_variables.trainable_variables())) if trainable and variable not in self._trainable_weights: self._trainable_weights.append(variable) elif not trainable and variable not in self._non_trainable_weights: self._non_trainable_weights.append(variable) return variable @property def state_size(self): """size(s) of state(s) used by this cell. It can be represented by an Integer, a TensorShape or a tuple of Integers or TensorShapes. """ raise NotImplementedError("Abstract method") @property def output_size(self): """Integer or TensorShape: size of outputs produced by this cell.""" raise NotImplementedError("Abstract method") def build(self, _): # This tells the parent Layer object that it's OK to call # self.add_variable() inside the call() method. pass def get_initial_state(self, inputs=None, batch_size=None, dtype=None): if inputs is not None: # Validate the given batch_size and dtype against inputs if provided. inputs = ops.convert_to_tensor(inputs, name="inputs") if batch_size is not None: if tensor_util.is_tensor(batch_size): static_batch_size = tensor_util.constant_value( batch_size, partial=True) else: static_batch_size = batch_size if inputs.shape.dims[0].value != static_batch_size: raise ValueError( "batch size from input tensor is different from the " "input param. Input tensor batch: &#123;&#125;, batch_size: &#123;&#125;".format( inputs.shape.dims[0].value, batch_size)) if dtype is not None and inputs.dtype != dtype: raise ValueError( "dtype from input tensor is different from the " "input param. Input tensor dtype: &#123;&#125;, dtype: &#123;&#125;".format( inputs.dtype, dtype)) batch_size = inputs.shape.dims[0].value or array_ops.shape(inputs)[0] dtype = inputs.dtype if None in [batch_size, dtype]: raise ValueError( "batch_size and dtype cannot be None while constructing initial " "state: batch_size=&#123;&#125;, dtype=&#123;&#125;".format(batch_size, dtype)) return self.zero_state(batch_size, dtype) def zero_state(self, batch_size, dtype): """Return zero-filled state tensor(s). Args: batch_size: int, float, or unit Tensor representing the batch size. dtype: the data type to use for the state. Returns: If `state_size` is an int or TensorShape, then the return value is a `N-D` tensor of shape `[batch_size, state_size]` filled with zeros. If `state_size` is a nested list or tuple, then the return value is a nested list or tuple (of the same structure) of `2-D` tensors with the shapes `[batch_size, s]` for each s in `state_size`. """ # Try to use the last cached zero_state. This is done to avoid recreating # zeros, especially when eager execution is enabled. state_size = self.state_size is_eager = context.executing_eagerly() if is_eager and hasattr(self, "_last_zero_state"): (last_state_size, last_batch_size, last_dtype, last_output) = getattr(self, "_last_zero_state") if (last_batch_size == batch_size and last_dtype == dtype and last_state_size == state_size): return last_output with ops.name_scope(type(self).__name__ + "ZeroState", values=[batch_size]): output = _zero_state_tensors(state_size, batch_size, dtype) if is_eager: self._last_zero_state = (state_size, batch_size, dtype, output) return output class LayerRNNCell(RNNCell)class BasicRNNCell(LayerRNNCell)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124class LayerRNNCell(RNNCell): """Subclass of RNNCells that act like proper `tf.Layer` objects. For backwards compatibility purposes, most `RNNCell` instances allow their `call` methods to instantiate variables via `tf.get_variable`. The underlying variable scope thus keeps track of any variables, and returning cached versions. This is atypical of `tf.layer` objects, which separate this part of layer building into a `build` method that is only called once. Here we provide a subclass for `RNNCell` objects that act exactly as `Layer` objects do. They must provide a `build` method and their `call` methods do not access Variables `tf.get_variable`. """ def __call__(self, inputs, state, scope=None, *args, **kwargs): """Run this RNN cell on inputs, starting from the given state. Args: inputs: `2-D` tensor with shape `[batch_size, input_size]`. state: if `self.state_size` is an integer, this should be a `2-D Tensor` with shape `[batch_size, self.state_size]`. Otherwise, if `self.state_size` is a tuple of integers, this should be a tuple with shapes `[batch_size, s] for s in self.state_size`. scope: optional cell scope. *args: Additional positional arguments. **kwargs: Additional keyword arguments. Returns: A pair containing: - Output: A `2-D` tensor with shape `[batch_size, self.output_size]`. - New state: Either a single `2-D` tensor, or a tuple of tensors matching the arity and shapes of `state`. """ # Bypass RNNCell's variable capturing semantics for LayerRNNCell. # Instead, it is up to subclasses to provide a proper build # method. See the class docstring for more details. return base_layer.Layer.__call__(self, inputs, state, scope=scope, *args, **kwargs)@tf_export(v1=["nn.rnn_cell.BasicRNNCell"])class BasicRNNCell(LayerRNNCell): """The most basic RNN cell. Note that this cell is not optimized for performance. Please use `tf.contrib.cudnn_rnn.CudnnRNNTanh` for better performance on GPU. Args: num_units: int, The number of units in the RNN cell. activation: Nonlinearity to use. Default: `tanh`. It could also be string that is within Keras activation function names. reuse: (optional) Python boolean describing whether to reuse variables in an existing scope. If not `True`, and the existing scope already has the given variables, an error is raised. name: String, the name of the layer. Layers with the same name will share weights, but to avoid mistakes we require reuse=True in such cases. dtype: Default dtype of the layer (default of `None` means use the type of the first input). Required when `build` is called before `call`. **kwargs: Dict, keyword named properties for common layer attributes, like `trainable` etc when constructing the cell from configs of get_config(). """ @deprecated(None, "This class is equivalent as tf.keras.layers.SimpleRNNCell," " and will be replaced by that in Tensorflow 2.0.") def __init__(self, num_units, activation=None, reuse=None, name=None, dtype=None, **kwargs): super(BasicRNNCell, self).__init__( _reuse=reuse, name=name, dtype=dtype, **kwargs) if context.executing_eagerly() and context.num_gpus() &gt; 0: logging.warn("%s: Note that this cell is not optimized for performance. " "Please use tf.contrib.cudnn_rnn.CudnnRNNTanh for better " "performance on GPU.", self) # Inputs must be 2-dimensional. self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units if activation: self._activation = activations.get(activation) else: self._activation = math_ops.tanh @property def state_size(self): return self._num_units @property def output_size(self): return self._num_units @tf_utils.shape_type_conversion def build(self, inputs_shape): if inputs_shape[-1] is None: raise ValueError("Expected inputs.shape[-1] to be known, saw shape: %s" % str(inputs_shape)) input_depth = inputs_shape[-1] self._kernel = self.add_variable( _WEIGHTS_VARIABLE_NAME, shape=[input_depth + self._num_units, self._num_units]) self._bias = self.add_variable( _BIAS_VARIABLE_NAME, shape=[self._num_units], initializer=init_ops.zeros_initializer(dtype=self.dtype)) self.built = True def call(self, inputs, state): """Most basic RNN: output = new_state = act(W * input + U * state + B).""" gate_inputs = math_ops.matmul( array_ops.concat([inputs, state], 1), self._kernel) gate_inputs = nn_ops.bias_add(gate_inputs, self._bias) output = self._activation(gate_inputs) return output, output def get_config(self): config = &#123; "num_units": self._num_units, "activation": activations.serialize(self._activation), "reuse": self._reuse, &#125; base_config = super(BasicRNNCell, self).get_config() return dict(list(base_config.items()) + list(config.items())) https://zh.diveintodeeplearning.org/chapter_recurrent-neural-networks/rnn.html 假设$\boldsymbol{X}_t \in \mathbb{R}^{n \times d}$是序列中时间步$t$的小批量输入，$\boldsymbol{H}_t \in \mathbb{R}^{n \times h}$是该时间步的隐藏层变量。跟多层感知机不同的是，这里我们保存上一时间步的隐藏变量$\boldsymbol{H}_{t-1}$，并引入一个新的权重参数$\boldsymbol{W}_{hh} \in \mathbb{R}^{h \times h}$，该参数用来描述在当前时间步如何使用上一时间步的隐藏变量。具体来说，当前时间步的隐藏变量的计算由当前时间步的输入和上一时间步的隐藏变量共同决定： \boldsymbol{H}_t = \phi(\boldsymbol{X}_t \boldsymbol{W}_{xh} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hh} + \boldsymbol{b}_h).与多层感知机相比，我们在这里添加了$\boldsymbol{H}_{t-1} \boldsymbol{W}_{hh}$一项。由上式中相邻时间步的隐藏变量$\boldsymbol{H}_t$和$\boldsymbol{H}_{t-1}$之间的关系可知，这里的隐藏变量捕捉了截至当前时间步的序列的历史信息，就像是神经网络当前时间步的状态或记忆一样。因此，该隐藏变量也称为隐藏状态。由于隐藏状态在当前时间步的定义使用了它在上一时间步相同的定义，上式的计算是循环的。使用循环计算的网络即循环神经网络。 下图展示了循环神经网络在三个相邻时间步的计算逻辑。在时间步$t$，隐藏状态的计算可以看成是将输入$\boldsymbol{X}_t$和前一时间步隐藏状态$\boldsymbol{H}_{t-1}$连结后输入一个激活函数为$\phi$的全连接层。该全连接层的输出就是当前时间步的隐藏状态$\boldsymbol{H}_t$，且模型参数为$\boldsymbol{W}_{xh}$与$\boldsymbol{W}_{hh}$的连结，偏差为$\boldsymbol{b}_h$。当前时间步$t$的隐藏状态$\boldsymbol{H}_t$将参与下一个时间步$t+1$的隐藏状态$\boldsymbol{H}_{t+1}$的计算，并输入到当前时间步的全连接输出层。 我们刚刚提到，隐藏状态中$\boldsymbol{X}_t \boldsymbol{W}_{xh} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hh}$的计算等价于$\boldsymbol{X}_t$与$\boldsymbol{H}_{t-1}$连结后的矩阵乘以$\boldsymbol{W}_{xh}$与$\boldsymbol{W}_{hh}$连结后的矩阵。class BasicRNNCell(LayerRNNCell) 中以及后文call中都是采用了这个技巧，这样可以增加神经网络的计算效率。 class GRUCell(LayerRNNCell)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123@tf_export(v1=["nn.rnn_cell.GRUCell"])class GRUCell(LayerRNNCell): """Gated Recurrent Unit cell (cf. http://arxiv.org/abs/1406.1078). Note that this cell is not optimized for performance. Please use `tf.contrib.cudnn_rnn.CudnnGRU` for better performance on GPU, or `tf.contrib.rnn.GRUBlockCellV2` for better performance on CPU. Args: num_units: int, The number of units in the GRU cell. activation: Nonlinearity to use. Default: `tanh`. reuse: (optional) Python boolean describing whether to reuse variables in an existing scope. If not `True`, and the existing scope already has the given variables, an error is raised. kernel_initializer: (optional) The initializer to use for the weight and projection matrices. bias_initializer: (optional) The initializer to use for the bias. name: String, the name of the layer. Layers with the same name will share weights, but to avoid mistakes we require reuse=True in such cases. dtype: Default dtype of the layer (default of `None` means use the type of the first input). Required when `build` is called before `call`. **kwargs: Dict, keyword named properties for common layer attributes, like `trainable` etc when constructing the cell from configs of get_config(). """ @deprecated(None, "This class is equivalent as tf.keras.layers.GRUCell," " and will be replaced by that in Tensorflow 2.0.") def __init__(self, num_units, activation=None, reuse=None, kernel_initializer=None, bias_initializer=None, name=None, dtype=None, **kwargs): super(GRUCell, self).__init__( _reuse=reuse, name=name, dtype=dtype, **kwargs) if context.executing_eagerly() and context.num_gpus() &gt; 0: logging.warn("%s: Note that this cell is not optimized for performance. " "Please use tf.contrib.cudnn_rnn.CudnnGRU for better " "performance on GPU.", self) # Inputs must be 2-dimensional. self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units if activation: self._activation = activations.get(activation) else: self._activation = math_ops.tanh self._kernel_initializer = initializers.get(kernel_initializer) self._bias_initializer = initializers.get(bias_initializer) @property def state_size(self): return self._num_units @property def output_size(self): return self._num_units @tf_utils.shape_type_conversion def build(self, inputs_shape): if inputs_shape[-1] is None: raise ValueError("Expected inputs.shape[-1] to be known, saw shape: %s" % str(inputs_shape)) input_depth = inputs_shape[-1] self._gate_kernel = self.add_variable( "gates/%s" % _WEIGHTS_VARIABLE_NAME, shape=[input_depth + self._num_units, 2 * self._num_units], initializer=self._kernel_initializer) self._gate_bias = self.add_variable( "gates/%s" % _BIAS_VARIABLE_NAME, shape=[2 * self._num_units], initializer=( self._bias_initializer if self._bias_initializer is not None else init_ops.constant_initializer(1.0, dtype=self.dtype))) self._candidate_kernel = self.add_variable( "candidate/%s" % _WEIGHTS_VARIABLE_NAME, shape=[input_depth + self._num_units, self._num_units], initializer=self._kernel_initializer) self._candidate_bias = self.add_variable( "candidate/%s" % _BIAS_VARIABLE_NAME, shape=[self._num_units], initializer=( self._bias_initializer if self._bias_initializer is not None else init_ops.zeros_initializer(dtype=self.dtype))) self.built = True def call(self, inputs, state): """Gated recurrent unit (GRU) with nunits cells.""" gate_inputs = math_ops.matmul( array_ops.concat([inputs, state], 1), self._gate_kernel) gate_inputs = nn_ops.bias_add(gate_inputs, self._gate_bias) value = math_ops.sigmoid(gate_inputs) r, u = array_ops.split(value=value, num_or_size_splits=2, axis=1) r_state = r * state candidate = math_ops.matmul( array_ops.concat([inputs, r_state], 1), self._candidate_kernel) candidate = nn_ops.bias_add(candidate, self._candidate_bias) c = self._activation(candidate) new_h = u * state + (1 - u) * c return new_h, new_h def get_config(self): config = &#123; "num_units": self._num_units, "kernel_initializer": initializers.serialize(self._kernel_initializer), "bias_initializer": initializers.serialize(self._bias_initializer), "activation": activations.serialize(self._activation), "reuse": self._reuse, &#125; base_config = super(GRUCell, self).get_config() return dict(list(base_config.items()) + list(config.items())) 门控循环单元（GRU）https://zh.diveintodeeplearning.org/chapter_recurrent-neural-networks/gru.html 门控循环单元（GRU）我们发现，当时间步数较大或者时间步较小时，循环神经网络的梯度较容易出现衰减或爆炸。虽然裁剪梯度可以应对梯度爆炸，但无法解决梯度衰减的问题。通常由于这个原因，循环神经网络在实际中较难捕捉时间序列中时间步距离较大的依赖关系。 门控循环神经网络（gated recurrent neural network）的提出，正是为了更好地捕捉时间序列中时间步距离较大的依赖关系。它通过可以学习的门来控制信息的流动。其中，门控循环单元（gated recurrent unit，简称GRU）是一种常用的门控循环神经网络。 门控循环单元下面将介绍门控循环单元的设计。它引入了重置门和更新门的概念，从而修改了循环神经网络中隐藏状态的计算方式。 重置门和更新门如图6.4所示，门控循环单元中的重置门（reset gate）和更新门（update gate）的输入均为当前时间步输入$\boldsymbol{X}_t$与上一时间步隐藏状态$\boldsymbol{H}_{t-1}$，输出由激活函数为sigmoid函数的全连接层计算得到。 具体来说，假设隐藏单元个数为$h$，给定时间步$t$的小批量输入$\boldsymbol{X}_t \in \mathbb{R}^{n \times d}$（样本数为$n$，输入个数为$d$）和上一时间步隐藏状态$\boldsymbol{H}_{t-1} \in \mathbb{R}^{n \times h}$。重置门$\boldsymbol{R}_t \in \mathbb{R}^{n \times h}$和更新门$\boldsymbol{Z}_t \in \mathbb{R}^{n \times h}$的计算如下： \begin{aligned} \boldsymbol{R}_t = \sigma(\boldsymbol{X}_t \boldsymbol{W}_{xr} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hr} + \boldsymbol{b}_r),\\ \boldsymbol{Z}_t = \sigma(\boldsymbol{X}_t \boldsymbol{W}_{xz} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hz} + \boldsymbol{b}_z), \end{aligned}其中$\boldsymbol{W}_{xr}, \boldsymbol{W}_{xz} \in \mathbb{R}^{d \times h}$和$\boldsymbol{W}_{hr}, \boldsymbol{W}_{hz} \in \mathbb{R}^{h \times h}$是权重参数，$\boldsymbol{b}_r, \boldsymbol{b}_z \in \mathbb{R}^{1 \times h}$是偏差参数。“多层感知机”一节中介绍过，sigmoid函数可以将元素的值变换到0和1之间。因此，重置门$\boldsymbol{R}_t$和更新门$\boldsymbol{Z}_t$中每个元素的值域都是$[0, 1]$。 候选隐藏状态接下来，门控循环单元将计算候选隐藏状态来辅助稍后的隐藏状态计算。如图所示，我们将当前时间步重置门的输出与上一时间步隐藏状态做按元素乘法（符号为$\odot$）。如果重置门中元素值接近0，那么意味着重置对应隐藏状态元素为0，即丢弃上一时间步的隐藏状态。如果元素值接近1，那么表示保留上一时间步的隐藏状态。然后，将按元素乘法的结果与当前时间步的输入连结，再通过含激活函数tanh的全连接层计算出候选隐藏状态，其所有元素的值域为$[-1, 1]$。 具体来说，时间步$t$的候选隐藏状态$\tilde{\boldsymbol{H}}_t \in \mathbb{R}^{n \times h}$的计算为 \tilde{\boldsymbol{H}}_t = \text{tanh}(\boldsymbol{X}_t \boldsymbol{W}_{xh} + \left(\boldsymbol{R}_t \odot \boldsymbol{H}_{t-1}\right) \boldsymbol{W}_{hh} + \boldsymbol{b}_h),其中$\boldsymbol{W}_{xh} \in \mathbb{R}^{d \times h}$和$\boldsymbol{W}_{hh} \in \mathbb{R}^{h \times h}$是权重参数，$\boldsymbol{b}_h \in \mathbb{R}^{1 \times h}$是偏差参数。从上面这个公式可以看出，重置门控制了上一时间步的隐藏状态如何流入当前时间步的候选隐藏状态。而上一时间步的隐藏状态可能包含了时间序列截至上一时间步的全部历史信息。因此，重置门可以用来丢弃与预测无关的历史信息。 隐藏状态最后，时间步$t$的隐藏状态$\boldsymbol{H}_t \in \mathbb{R}^{n \times h}$的计算使用当前时间步的更新门$\boldsymbol{Z}_t$来对上一时间步的隐藏状态$\boldsymbol{H}_{t-1}$和当前时间步的候选隐藏状态$\tilde{\boldsymbol{H}}_t$做组合： \boldsymbol{H}_t = \boldsymbol{Z}_t \odot \boldsymbol{H}_{t-1} + (1 - \boldsymbol{Z}_t) \odot \tilde{\boldsymbol{H}}_t. 值得注意的是，更新门可以控制隐藏状态应该如何被包含当前时间步信息的候选隐藏状态所更新，如图所示。假设更新门在时间步$t’$到$t$（$t’ &lt; t$）之间一直近似1。那么，在时间步$t’$到$t$之间的输入信息几乎没有流入时间步$t$的隐藏状态$\boldsymbol{H}_t$。实际上，这可以看作是较早时刻的隐藏状态$\boldsymbol{H}_{t’-1}$一直通过时间保存并传递至当前时间步$t$。这个设计可以应对循环神经网络中的梯度衰减问题，并更好地捕捉时间序列中时间步距离较大的依赖关系。 我们对门控循环单元的设计稍作总结： 重置门有助于捕捉时间序列里短期的依赖关系。 更新门有助于捕捉时间序列里长期的依赖关系。 class LSTMStateTuple123456789101112131415161718_LSTMStateTuple = collections.namedtuple("LSTMStateTuple", ("c", "h"))@tf_export("nn.rnn_cell.LSTMStateTuple")class LSTMStateTuple(_LSTMStateTuple): """Tuple used by LSTM Cells for `state_size`, `zero_state`, and output state. Stores two elements: `(c, h)`, in that order. Where `c` is the hidden state and `h` is the output. Only used when `state_is_tuple=True`. """ __slots__ = () @property def dtype(self): (c, h) = self if c.dtype != h.dtype: raise TypeError("Inconsistent internal state: %s vs %s" % (str(c.dtype), str(h.dtype))) return c.dtype class BasicLSTMCell(LayerRNNCell)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154@tf_export(v1=["nn.rnn_cell.BasicLSTMCell"])class BasicLSTMCell(LayerRNNCell): """DEPRECATED: Please use `tf.nn.rnn_cell.LSTMCell` instead. Basic LSTM recurrent network cell. The implementation is based on: http://arxiv.org/abs/1409.2329. We add forget_bias (default: 1) to the biases of the forget gate in order to reduce the scale of forgetting in the beginning of the training. It does not allow cell clipping, a projection layer, and does not use peep-hole connections: it is the basic baseline. For advanced models, please use the full `tf.nn.rnn_cell.LSTMCell` that follows. Note that this cell is not optimized for performance. Please use `tf.contrib.cudnn_rnn.CudnnLSTM` for better performance on GPU, or `tf.contrib.rnn.LSTMBlockCell` and `tf.contrib.rnn.LSTMBlockFusedCell` for better performance on CPU. """ @deprecated(None, "This class is equivalent as tf.keras.layers.LSTMCell," " and will be replaced by that in Tensorflow 2.0.") def __init__(self, num_units, forget_bias=1.0, state_is_tuple=True, activation=None, reuse=None, name=None, dtype=None, **kwargs): """Initialize the basic LSTM cell. Args: num_units: int, The number of units in the LSTM cell. forget_bias: float, The bias added to forget gates (see above). Must set to `0.0` manually when restoring from CudnnLSTM-trained checkpoints. state_is_tuple: If True, accepted and returned states are 2-tuples of the `c_state` and `m_state`. If False, they are concatenated along the column axis. The latter behavior will soon be deprecated. activation: Activation function of the inner states. Default: `tanh`. It could also be string that is within Keras activation function names. reuse: (optional) Python boolean describing whether to reuse variables in an existing scope. If not `True`, and the existing scope already has the given variables, an error is raised. name: String, the name of the layer. Layers with the same name will share weights, but to avoid mistakes we require reuse=True in such cases. dtype: Default dtype of the layer (default of `None` means use the type of the first input). Required when `build` is called before `call`. **kwargs: Dict, keyword named properties for common layer attributes, like `trainable` etc when constructing the cell from configs of get_config(). When restoring from CudnnLSTM-trained checkpoints, must use `CudnnCompatibleLSTMCell` instead. """ super(BasicLSTMCell, self).__init__( _reuse=reuse, name=name, dtype=dtype, **kwargs) if not state_is_tuple: logging.warn("%s: Using a concatenated state is slower and will soon be " "deprecated. Use state_is_tuple=True.", self) if context.executing_eagerly() and context.num_gpus() &gt; 0: logging.warn("%s: Note that this cell is not optimized for performance. " "Please use tf.contrib.cudnn_rnn.CudnnLSTM for better " "performance on GPU.", self) # Inputs must be 2-dimensional. self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units self._forget_bias = forget_bias self._state_is_tuple = state_is_tuple if activation: self._activation = activations.get(activation) else: self._activation = math_ops.tanh @property def state_size(self): return (LSTMStateTuple(self._num_units, self._num_units) if self._state_is_tuple else 2 * self._num_units) @property def output_size(self): return self._num_units @tf_utils.shape_type_conversion def build(self, inputs_shape): if inputs_shape[-1] is None: raise ValueError("Expected inputs.shape[-1] to be known, saw shape: %s" % str(inputs_shape)) input_depth = inputs_shape[-1] h_depth = self._num_units self._kernel = self.add_variable( _WEIGHTS_VARIABLE_NAME, shape=[input_depth + h_depth, 4 * self._num_units]) self._bias = self.add_variable( _BIAS_VARIABLE_NAME, shape=[4 * self._num_units], initializer=init_ops.zeros_initializer(dtype=self.dtype)) self.built = True def call(self, inputs, state): """Long short-term memory cell (LSTM). Args: inputs: `2-D` tensor with shape `[batch_size, input_size]`. state: An `LSTMStateTuple` of state tensors, each shaped `[batch_size, num_units]`, if `state_is_tuple` has been set to `True`. Otherwise, a `Tensor` shaped `[batch_size, 2 * num_units]`. Returns: A pair containing the new hidden state, and the new state (either a `LSTMStateTuple` or a concatenated state, depending on `state_is_tuple`). """ sigmoid = math_ops.sigmoid one = constant_op.constant(1, dtype=dtypes.int32) # Parameters of gates are concatenated into one multiply for efficiency. if self._state_is_tuple: c, h = state else: c, h = array_ops.split(value=state, num_or_size_splits=2, axis=one) gate_inputs = math_ops.matmul( array_ops.concat([inputs, h], 1), self._kernel) gate_inputs = nn_ops.bias_add(gate_inputs, self._bias) # i = input_gate, j = new_input, f = forget_gate, o = output_gate i, j, f, o = array_ops.split( value=gate_inputs, num_or_size_splits=4, axis=one) forget_bias_tensor = constant_op.constant(self._forget_bias, dtype=f.dtype) # Note that using `add` and `multiply` instead of `+` and `*` gives a # performance improvement. So using those at the cost of readability. add = math_ops.add multiply = math_ops.multiply new_c = add(multiply(c, sigmoid(add(f, forget_bias_tensor))), multiply(sigmoid(i), self._activation(j))) new_h = multiply(self._activation(new_c), sigmoid(o)) if self._state_is_tuple: new_state = LSTMStateTuple(new_c, new_h) else: new_state = array_ops.concat([new_c, new_h], 1) return new_h, new_state def get_config(self): config = &#123; "num_units": self._num_units, "forget_bias": self._forget_bias, "state_is_tuple": self._state_is_tuple, "activation": activations.serialize(self._activation), "reuse": self._reuse, &#125; base_config = super(BasicLSTMCell, self).get_config() return dict(list(base_config.items()) + list(config.items())) forget_bias 作用forget_bias: Biases of the forget gate are initialized by default to 1 in order to reduce the scale of forgetting at the beginning of the training. Must set it manually to 0.0 when restoring from CudnnLSTM trained checkpoints. 长短期记忆（LSTM） 本节将介绍另一种常用的门控循环神经网络：长短期记忆（long short-term memory，简称LSTM）。它比门控循环单元的结构稍微复杂一点。 长短期记忆LSTM 中引入了三个门：输入门（input gate）、遗忘门（forget gate）和输出门（output gate），以及与隐藏状态形状相同的记忆细胞（某些文献把记忆细胞当成一种特殊的隐藏状态），从而记录额外的信息。 输入门、遗忘门和输出门同门控循环单元中的重置门和更新门一样，如图所示，长短期记忆的门的输入均为当前时间步输入$\boldsymbol{X}_t$与上一时间步隐藏状态$\boldsymbol{H}_{t-1}$，输出由激活函数为sigmoid函数的全连接层计算得到。如此一来，这三个门元素的值域均为$[0,1]$。 具体来说，假设隐藏单元个数为$h$，给定时间步$t$的小批量输入$\boldsymbol{X}_t \in \mathbb{R}^{n \times d}$（样本数为$n$，输入个数为$d$）和上一时间步隐藏状态$\boldsymbol{H}_{t-1} \in \mathbb{R}^{n \times h}$。时间步$t$的输入门$\boldsymbol{I}_t \in \mathbb{R}^{n \times h}$、遗忘门$\boldsymbol{F}_t \in \mathbb{R}^{n \times h}$和输出门$\boldsymbol{O}_t \in \mathbb{R}^{n \times h}$分别计算如下： \begin{aligned} \boldsymbol{I}_t &= \sigma(\boldsymbol{X}_t \boldsymbol{W}_{xi} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hi} + \boldsymbol{b}_i),\\ \boldsymbol{F}_t &= \sigma(\boldsymbol{X}_t \boldsymbol{W}_{xf} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hf} + \boldsymbol{b}_f),\\ \boldsymbol{O}_t &= \sigma(\boldsymbol{X}_t \boldsymbol{W}_{xo} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{ho} + \boldsymbol{b}_o), \end{aligned}其中的$\boldsymbol{W}_{xi}, \boldsymbol{W}_{xf}, \boldsymbol{W}_{xo} \in \mathbb{R}^{d \times h}$和$\boldsymbol{W}_{hi}, \boldsymbol{W}_{hf}, \boldsymbol{W}_{ho} \in \mathbb{R}^{h \times h}$是权重参数，$\boldsymbol{b}_i, \boldsymbol{b}_f, \boldsymbol{b}_o \in \mathbb{R}^{1 \times h}$是偏差参数。 候选记忆细胞接下来，长短期记忆需要计算候选记忆细胞$\tilde{\boldsymbol{C}}_t$。它的计算同上面介绍的三个门类似，但使用了值域在$[-1, 1]$的tanh函数做激活函数，如图所示。 具体来说，时间步$t$的候选记忆细胞$\tilde{\boldsymbol{C}}_t \in \mathbb{R}^{n \times h}$的计算为 \tilde{\boldsymbol{C}}_t = \text{tanh}(\boldsymbol{X}_t \boldsymbol{W}_{xc} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hc} + \boldsymbol{b}_c),其中的$\boldsymbol{W}_{xc} \in \mathbb{R}^{d \times h}$和$\boldsymbol{W}_{hc} \in \mathbb{R}^{h \times h}$是权重参数，$\boldsymbol{b}_c \in \mathbb{R}^{1 \times h}$是偏差参数。 记忆细胞我们可以通过元素值域在$[0, 1]$的输入门、遗忘门和输出门来控制隐藏状态中信息的流动：这一般也是通过使用按元素乘法（符号为$\odot$）来实现。当前时间步记忆细胞$\boldsymbol{C}_t \in \mathbb{R}^{n \times h}$的计算组合了上一时间步记忆细胞和当前时间步候选记忆细胞的信息，并通过遗忘门和输入门来控制信息的流动： \boldsymbol{C}_t = \boldsymbol{F}_t \odot \boldsymbol{C}_{t-1} + \boldsymbol{I}_t \odot \tilde{\boldsymbol{C}}_t.如图所示，遗忘门控制上一时间步的记忆细胞$\boldsymbol{C}_{t-1}$中的信息是否传递到当前时间步，而输入门则可以控制当前时间步的输入$\boldsymbol{X}_t$通过候选记忆细胞$\tilde{\boldsymbol{C}}_t$如何流入当前时间步的记忆细胞。如果遗忘门一直近似1且输入门一直近似0，过去的记忆细胞将一直通过时间保存并传递至当前时间步。这个设计可以应对循环神经网络中的梯度衰减问题，并更好地捕捉时间序列中时间步距离较大的依赖关系。 隐藏状态有了记忆细胞以后，接下来我们还可以通过输出门来控制从记忆细胞到隐藏状态$\boldsymbol{H}_t \in \mathbb{R}^{n \times h}$的信息的流动： \boldsymbol{H}_t = \boldsymbol{O}_t \odot \text{tanh}(\boldsymbol{C}_t).这里的tanh函数确保隐藏状态元素值在-1到1之间。需要注意的是，当输出门近似1时，记忆细胞信息将传递到隐藏状态供输出层使用；当输出门近似0时，记忆细胞信息只自己保留。图6.10展示了长短期记忆中隐藏状态的计算。 class LSTMCell(LayerRNNCell)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271@tf_export(v1=["nn.rnn_cell.LSTMCell"])class LSTMCell(LayerRNNCell): """Long short-term memory unit (LSTM) recurrent network cell. The default non-peephole implementation is based on: https://pdfs.semanticscholar.org/1154/0131eae85b2e11d53df7f1360eeb6476e7f4.pdf Felix Gers, Jurgen Schmidhuber, and Fred Cummins. "Learning to forget: Continual prediction with LSTM." IET, 850-855, 1999. The peephole implementation is based on: https://research.google.com/pubs/archive/43905.pdf Hasim Sak, Andrew Senior, and Francoise Beaufays. "Long short-term memory recurrent neural network architectures for large scale acoustic modeling." INTERSPEECH, 2014. The class uses optional peep-hole connections, optional cell clipping, and an optional projection layer. Note that this cell is not optimized for performance. Please use `tf.contrib.cudnn_rnn.CudnnLSTM` for better performance on GPU, or `tf.contrib.rnn.LSTMBlockCell` and `tf.contrib.rnn.LSTMBlockFusedCell` for better performance on CPU. """ @deprecated(None, "This class is equivalent as tf.keras.layers.LSTMCell," " and will be replaced by that in Tensorflow 2.0.") def __init__(self, num_units, use_peepholes=False, cell_clip=None, initializer=None, num_proj=None, proj_clip=None, num_unit_shards=None, num_proj_shards=None, forget_bias=1.0, state_is_tuple=True, activation=None, reuse=None, name=None, dtype=None, **kwargs): """Initialize the parameters for an LSTM cell. Args: num_units: int, The number of units in the LSTM cell. use_peepholes: bool, set True to enable diagonal/peephole connections. cell_clip: (optional) A float value, if provided the cell state is clipped by this value prior to the cell output activation. initializer: (optional) The initializer to use for the weight and projection matrices. num_proj: (optional) int, The output dimensionality for the projection matrices. If None, no projection is performed. proj_clip: (optional) A float value. If `num_proj &gt; 0` and `proj_clip` is provided, then the projected values are clipped elementwise to within `[-proj_clip, proj_clip]`. num_unit_shards: Deprecated, will be removed by Jan. 2017. Use a variable_scope partitioner instead. num_proj_shards: Deprecated, will be removed by Jan. 2017. Use a variable_scope partitioner instead. forget_bias: Biases of the forget gate are initialized by default to 1 in order to reduce the scale of forgetting at the beginning of the training. Must set it manually to `0.0` when restoring from CudnnLSTM trained checkpoints. state_is_tuple: If True, accepted and returned states are 2-tuples of the `c_state` and `m_state`. If False, they are concatenated along the column axis. This latter behavior will soon be deprecated. activation: Activation function of the inner states. Default: `tanh`. It could also be string that is within Keras activation function names. reuse: (optional) Python boolean describing whether to reuse variables in an existing scope. If not `True`, and the existing scope already has the given variables, an error is raised. name: String, the name of the layer. Layers with the same name will share weights, but to avoid mistakes we require reuse=True in such cases. dtype: Default dtype of the layer (default of `None` means use the type of the first input). Required when `build` is called before `call`. **kwargs: Dict, keyword named properties for common layer attributes, like `trainable` etc when constructing the cell from configs of get_config(). When restoring from CudnnLSTM-trained checkpoints, use `CudnnCompatibleLSTMCell` instead. """ super(LSTMCell, self).__init__( _reuse=reuse, name=name, dtype=dtype, **kwargs) if not state_is_tuple: logging.warn("%s: Using a concatenated state is slower and will soon be " "deprecated. Use state_is_tuple=True.", self) if num_unit_shards is not None or num_proj_shards is not None: logging.warn( "%s: The num_unit_shards and proj_unit_shards parameters are " "deprecated and will be removed in Jan 2017. " "Use a variable scope with a partitioner instead.", self) if context.executing_eagerly() and context.num_gpus() &gt; 0: logging.warn("%s: Note that this cell is not optimized for performance. " "Please use tf.contrib.cudnn_rnn.CudnnLSTM for better " "performance on GPU.", self) # Inputs must be 2-dimensional. self.input_spec = input_spec.InputSpec(ndim=2) self._num_units = num_units self._use_peepholes = use_peepholes self._cell_clip = cell_clip self._initializer = initializers.get(initializer) self._num_proj = num_proj self._proj_clip = proj_clip self._num_unit_shards = num_unit_shards self._num_proj_shards = num_proj_shards self._forget_bias = forget_bias self._state_is_tuple = state_is_tuple if activation: self._activation = activations.get(activation) else: self._activation = math_ops.tanh if num_proj: self._state_size = ( LSTMStateTuple(num_units, num_proj) if state_is_tuple else num_units + num_proj) self._output_size = num_proj else: self._state_size = ( LSTMStateTuple(num_units, num_units) if state_is_tuple else 2 * num_units) self._output_size = num_units @property def state_size(self): return self._state_size @property def output_size(self): return self._output_size @tf_utils.shape_type_conversion def build(self, inputs_shape): if inputs_shape[-1] is None: raise ValueError("Expected inputs.shape[-1] to be known, saw shape: %s" % str(inputs_shape)) input_depth = inputs_shape[-1] h_depth = self._num_units if self._num_proj is None else self._num_proj maybe_partitioner = ( partitioned_variables.fixed_size_partitioner(self._num_unit_shards) if self._num_unit_shards is not None else None) self._kernel = self.add_variable( _WEIGHTS_VARIABLE_NAME, shape=[input_depth + h_depth, 4 * self._num_units], initializer=self._initializer, partitioner=maybe_partitioner) if self.dtype is None: initializer = init_ops.zeros_initializer else: initializer = init_ops.zeros_initializer(dtype=self.dtype) self._bias = self.add_variable( _BIAS_VARIABLE_NAME, shape=[4 * self._num_units], initializer=initializer) if self._use_peepholes: self._w_f_diag = self.add_variable("w_f_diag", shape=[self._num_units], initializer=self._initializer) self._w_i_diag = self.add_variable("w_i_diag", shape=[self._num_units], initializer=self._initializer) self._w_o_diag = self.add_variable("w_o_diag", shape=[self._num_units], initializer=self._initializer) if self._num_proj is not None: maybe_proj_partitioner = ( partitioned_variables.fixed_size_partitioner(self._num_proj_shards) if self._num_proj_shards is not None else None) self._proj_kernel = self.add_variable( "projection/%s" % _WEIGHTS_VARIABLE_NAME, shape=[self._num_units, self._num_proj], initializer=self._initializer, partitioner=maybe_proj_partitioner) self.built = True def call(self, inputs, state): """Run one step of LSTM. Args: inputs: input Tensor, must be 2-D, `[batch, input_size]`. state: if `state_is_tuple` is False, this must be a state Tensor, `2-D, [batch, state_size]`. If `state_is_tuple` is True, this must be a tuple of state Tensors, both `2-D`, with column sizes `c_state` and `m_state`. Returns: A tuple containing: - A `2-D, [batch, output_dim]`, Tensor representing the output of the LSTM after reading `inputs` when previous state was `state`. Here output_dim is: num_proj if num_proj was set, num_units otherwise. - Tensor(s) representing the new state of LSTM after reading `inputs` when the previous state was `state`. Same type and shape(s) as `state`. Raises: ValueError: If input size cannot be inferred from inputs via static shape inference. """ num_proj = self._num_units if self._num_proj is None else self._num_proj sigmoid = math_ops.sigmoid if self._state_is_tuple: (c_prev, m_prev) = state else: c_prev = array_ops.slice(state, [0, 0], [-1, self._num_units]) m_prev = array_ops.slice(state, [0, self._num_units], [-1, num_proj]) input_size = inputs.get_shape().with_rank(2).dims[1].value if input_size is None: raise ValueError("Could not infer input size from inputs.get_shape()[-1]") # i = input_gate, j = new_input, f = forget_gate, o = output_gate lstm_matrix = math_ops.matmul( array_ops.concat([inputs, m_prev], 1), self._kernel) lstm_matrix = nn_ops.bias_add(lstm_matrix, self._bias) i, j, f, o = array_ops.split( value=lstm_matrix, num_or_size_splits=4, axis=1) # Diagonal connections if self._use_peepholes: c = (sigmoid(f + self._forget_bias + self._w_f_diag * c_prev) * c_prev + sigmoid(i + self._w_i_diag * c_prev) * self._activation(j)) else: c = (sigmoid(f + self._forget_bias) * c_prev + sigmoid(i) * self._activation(j)) if self._cell_clip is not None: # pylint: disable=invalid-unary-operand-type c = clip_ops.clip_by_value(c, -self._cell_clip, self._cell_clip) # pylint: enable=invalid-unary-operand-type if self._use_peepholes: m = sigmoid(o + self._w_o_diag * c) * self._activation(c) else: m = sigmoid(o) * self._activation(c) if self._num_proj is not None: m = math_ops.matmul(m, self._proj_kernel) if self._proj_clip is not None: # pylint: disable=invalid-unary-operand-type m = clip_ops.clip_by_value(m, -self._proj_clip, self._proj_clip) # pylint: enable=invalid-unary-operand-type new_state = (LSTMStateTuple(c, m) if self._state_is_tuple else array_ops.concat([c, m], 1)) return m, new_state def get_config(self): config = &#123; "num_units": self._num_units, "use_peepholes": self._use_peepholes, "cell_clip": self._cell_clip, "initializer": initializers.serialize(self._initializer), "num_proj": self._num_proj, "proj_clip": self._proj_clip, "num_unit_shards": self._num_unit_shards, "num_proj_shards": self._num_proj_shards, "forget_bias": self._forget_bias, "state_is_tuple": self._state_is_tuple, "activation": activations.serialize(self._activation), "reuse": self._reuse, &#125; base_config = super(LSTMCell, self).get_config() return dict(list(base_config.items()) + list(config.items()))def _enumerated_map_structure_up_to(shallow_structure, map_fn, *args, **kwargs): ix = [0] def enumerated_fn(*inner_args, **inner_kwargs): r = map_fn(ix[0], *inner_args, **inner_kwargs) ix[0] += 1 return r return nest.map_structure_up_to(shallow_structure, enumerated_fn, *args, **kwargs)def _default_dropout_state_filter_visitor(substate): if isinstance(substate, LSTMStateTuple): # Do not perform dropout on the memory state. return LSTMStateTuple(c=False, h=True) elif isinstance(substate, tensor_array_ops.TensorArray): return False return True 与 BasicLSTMCell 区别The class uses optional peep-hole connections, optional cell clipping, andan optional projection layer. 其中一个流形的 LSTM 变体，就是由 Gers &amp; Schmidhuber (2000) 提出的，增加了 “peephole connection”。是说，我们让 门层 也会接受细胞状态的输入。 使用 peephole connection12345678910111213141516171819if self._use_peepholes: self._w_f_diag = self.add_variable("w_f_diag", shape=[self._num_units], initializer=self._initializer) self._w_i_diag = self.add_variable("w_i_diag", shape=[self._num_units], initializer=self._initializer) self._w_o_diag = self.add_variable("w_o_diag", shape=[self._num_units], initializer=self._initializer)if self._use_peepholes: c = (sigmoid(f + self._forget_bias + self._w_f_diag * c_prev) * c_prev + sigmoid(i + self._w_i_diag * c_prev) * self._activation(j))else: c = (sigmoid(f + self._forget_bias) * c_prev + sigmoid(i) * self._activation(j))if self._use_peepholes: m = sigmoid(o + self._w_o_diag * c) * self._activation(c)else: m = sigmoid(o) * self._activation(c) class MultiRNNCell(RNNCell)12345678@tf_export(v1=["nn.rnn_cell.MultiRNNCell"])class MultiRNNCell(RNNCell): """RNN cell composed sequentially of multiple simple cells. Example: ```python num_units = [128, 64] cells = [BasicLSTMCell(num_units=n) for n in num_units] stacked_rnn_cell = MultiRNNCell(cells) &quot;&quot;&quot; @deprecated(None, &quot;This class is equivalent as &quot; &quot;tf.keras.layers.StackedRNNCells, and will be replaced by &quot; &quot;that in Tensorflow 2.0.&quot;) def __init__(self, cells, state_is_tuple=True): &quot;&quot;&quot;Create a RNN cell composed sequentially of a number of RNNCells. Args: cells: list of RNNCells that will be composed in this order. state_is_tuple: If True, accepted and returned states are n-tuples, where `n = len(cells)`. If False, the states are all concatenated along the column axis. This latter behavior will soon be deprecated. Raises: ValueError: if cells is empty (not allowed), or at least one of the cells returns a state tuple but the flag `state_is_tuple` is `False`. &quot;&quot;&quot; super(MultiRNNCell, self).__init__() if not cells: raise ValueError(&quot;Must specify at least one cell for MultiRNNCell.&quot;) if not nest.is_sequence(cells): raise TypeError( &quot;cells must be a list or tuple, but saw: %s.&quot; % cells) if len(set([id(cell) for cell in cells])) &lt; len(cells): logging.log_first_n(logging.WARN, &quot;At least two cells provided to MultiRNNCell &quot; &quot;are the same object and will share weights.&quot;, 1) self._cells = cells for cell_number, cell in enumerate(self._cells): # Add Checkpointable dependencies on these cells so their variables get # saved with this object when using object-based saving. if isinstance(cell, checkpointable.CheckpointableBase): # TODO(allenl): Track down non-Checkpointable callers. self._track_checkpointable(cell, name=&quot;cell-%d&quot; % (cell_number,)) self._state_is_tuple = state_is_tuple if not state_is_tuple: if any(nest.is_sequence(c.state_size) for c in self._cells): raise ValueError(&quot;Some cells return tuples of states, but the flag &quot; &quot;state_is_tuple is not set. State sizes are: %s&quot; % str([c.state_size for c in self._cells])) @property def state_size(self): if self._state_is_tuple: return tuple(cell.state_size for cell in self._cells) else: return sum(cell.state_size for cell in self._cells) @property def output_size(self): return self._cells[-1].output_size def zero_state(self, batch_size, dtype): with ops.name_scope(type(self).__name__ + &quot;ZeroState&quot;, values=[batch_size]): if self._state_is_tuple: return tuple(cell.zero_state(batch_size, dtype) for cell in self._cells) else: # We know here that state_size of each cell is not a tuple and # presumably does not contain TensorArrays or anything else fancy return super(MultiRNNCell, self).zero_state(batch_size, dtype) @property def trainable_weights(self): if not self.trainable: return [] weights = [] for cell in self._cells: if isinstance(cell, base_layer.Layer): weights += cell.trainable_weights return weights @property def non_trainable_weights(self): weights = [] for cell in self._cells: if isinstance(cell, base_layer.Layer): weights += cell.non_trainable_weights if not self.trainable: trainable_weights = [] for cell in self._cells: if isinstance(cell, base_layer.Layer): trainable_weights += cell.trainable_weights return trainable_weights + weights return weights def call(self, inputs, state): &quot;&quot;&quot;Run this multi-layer cell on inputs, starting from state.&quot;&quot;&quot; cur_state_pos = 0 cur_inp = inputs new_states = [] for i, cell in enumerate(self._cells): with vs.variable_scope(&quot;cell_%d&quot; % i): if self._state_is_tuple: if not nest.is_sequence(state): raise ValueError( &quot;Expected state to be a tuple of length %d, but received: %s&quot; % (len(self.state_size), state)) cur_state = state[i] else: cur_state = array_ops.slice(state, [0, cur_state_pos], [-1, cell.state_size]) cur_state_pos += cell.state_size cur_inp, new_state = cell(cur_inp, cur_state) new_states.append(new_state) new_states = (tuple(new_states) if self._state_is_tuple else array_ops.concat(new_states, 1)) return cur_inp, new_states ```]]></content>
      <categories>
        <category>Artificial Intelligence Navigation</category>
        <category>TensorFlow手册</category>
      </categories>
      <tags>
        <tag>TensorFlow</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Universal Language Model Fine-tuning for Text Classification]]></title>
    <url>%2F2018%2F12%2F14%2FUniversal_Language_Model_Fine-tuning_for_Text_Classification%2F</url>
    <content type="text"><![CDATA[摘要：迁移学习为计算机视觉带来了巨大改变，但是现有的NLP技术仍需要针对具体任务改进模型，并且从零开始训练。我们提出了一种有效的迁移学习方法，可以应用到NLP领域的任何一种任务上，同时提出的技术对调整语言模型来说非常关键。我们的方法在六种文本分类任务上比现有的技术都要优秀，除此之外，这种方法仅用100个带有标签的样本进行训练，最终的性能就达到了从零开始、拥有上万个训练数据的模型性能。 Universal Language Model Fine-tuning for Text ClassificationJeremy Howard, Sebastian Ruder(Submitted on 18 Jan 2018 (v1), last revised 23 May 2018 (this version, v5)) Inductive transfer learning has greatly impacted computer vision, but existing approaches in NLP still require task-specific modifications and training from scratch. We propose Universal Language Model Fine-tuning (ULMFiT), an effective transfer learning method that can be applied to any task in NLP, and introduce techniques that are key for fine-tuning a language model. Our method significantly outperforms the state-of-the-art on six text classification tasks, reducing the error by 18-24% on the majority of datasets. Furthermore, with only 100 labeled examples, it matches the performance of training from scratch on 100x more data. We open-source our pretrained models and code. Comments: ACL 2018, fixed denominator in Equation 3, line 3Subjects: Computation and Language (cs.CL); Machine Learning (cs.LG); Machine Learning (stat.ML)Cite as: arXiv:1801.06146 [cs.CL] (or arXiv:1801.06146v5 [cs.CL] for this version) ULMFiT 相关资源 标题 说明 附加 Universal Language Model Fine-tuning for Text Classification 原始论文 20180118 比word2vec更好的ULMFiT 解读 20180801 【NLP】语言模型和迁移学习 本文主要对ELMo、ULMFiT以及OpenAI GPT三种预训练语言模型作简要介绍。 ULMFiT是一种有效的NLP迁移学习方法，核心思想是通过精调预训练的语言模型完成其他NLP任务。文中所用的语言模型参考了Merity et al. 2017a的AWD-LSTM模型，即没有attention或shortcut的三层LSTM模型。 ULMFiT的过程分为三步： General-domain LM pre-train在Wikitext-103上进行语言模型的预训练。预训练的语料要求：large &amp; capture general properties of language预训练对小数据集十分有效，之后仅有少量样本就可以使模型泛化。 Target task LM fine-tuning文中介绍了两种fine-tuning方法： Discriminative fine-tuning因为网络中不同层可以捕获不同类型的信息，因此在精调时也应该使用不同的learning rate。作者为每一层赋予一个学习率 $\eta^{l}$ ，实验后发现，首先通过精调模型的最后一层L确定学习率 $\eta^{L}$ ，再递推地选择上一层学习率进行精调的效果最好，递推公式为: $\eta^{l-1} = \eta^{l}/2.6$ Slanted triangular learning rates (STLR)为了针对特定任务选择参数，理想情况下需要在训练开始时让参数快速收敛到一个合适的区域，之后进行精调。为了达到这种效果，作者提出STLR方法，即让LR在训练初期短暂递增，在之后下降。如图b的右上角所示。具体的公式为： where T is the number of training iterations;cut frac is the fraction of iterations we increase the LR;p is the fraction of the number of iterations we have increased or will decrease the LR respectively, ratio specifies how much smaller the lowest LR is from the maximum LR ηmax, and ηt is the learning rate at iteration t.We generally use cut frac = 0:1, ratio = 32 and max = 0:01. 简单地说就是在一个训练周期内学习率以 cut 为界呈斜三角变化，在 cut 之前学习率快速升高，在 cut 之后学习率缓慢减小，如下图所示。 Target task classifier fine-tuning为了完成分类任务的精调，作者在最后一层添加了两个线性block，每个都有batch-norm和dropout，使用ReLU作为中间层激活函数，最后经过softmax输出分类的概率分布。最后的精调涉及的环节如下： Concat pooling第一个线性层的输入是最后一个隐层状态的池化。因为文本分类的关键信息可能在文本的任何地方，所以只是用最后时间步的输出是不够的。作者将最后时间步 h_{T} 与尽可能多的时间步 $H= {h_{1},… , h_{T}} $ 池化后拼接起来，以 $h_{c} = [h_{T}, maxpool(H), meanpool(H)] $ 作为输入。 Gradual unfreezing由于过度精调会导致模型遗忘之前预训练得到的信息，作者提出逐渐unfreez网络层的方法，从最后一层开始unfreez和精调，由后向前地unfreez并精调所有层。 BPTT for Text Classification (BPT3C)为了在large documents上进行模型精调，作者将文档分为固定长度为b的batches，并在每个batch训练时记录mean和max池化，梯度会被反向传播到对最终预测有贡献的batches。 Bidirectional language model在作者的实验中，分别独立地对前向和后向LM做了精调，并将两者的预测结果平均。两者结合后结果有0.5-0.7的提升。 使用 ULMFiThttps://github.com/fastai/fastai/tree/master/courses/dl2/imdb_scripts 更多参见 FAST.AI NLP http://nlp.fast.ai/category/classification.html fine-tuned language model with gradual unfreezing, discriminative fine-tuning, and slanted triangular learning rates. Instructions Preparing Wikipedia Tokenization Mapping tokens to ids Fine-tune the LM(download the pre-trained models) or Pretrain the Wikipedia language model(from scrach) Train the classifier Evaluate the classifier Try the classifier on text]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Language Model</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[SQuAD（Stanford Question Answering Dataset）]]></title>
    <url>%2F2018%2F12%2F10%2FSQuAD%2F</url>
    <content type="text"><![CDATA[SQuAD 论文摘要：我们展示了斯坦福问答数据集(SQuAD)，这是一个新的阅读理解数据集，由一组维基百科文章上的众筹工作者提出的10万个问题组成，每个问题的答案都是对应阅读文章的一段文字。我们分析数据集，以理解回答问题所需的推理类型，主要依赖依赖关系和选区树。我们建立了一个强逻辑回归模型，该模型的F1得分为51.0 QANet(To Do)A Tensorflow implementation of QANet for machine reading comprehensionhttps://github.com/NLPLearn/QANet SQuAD 数据地址SQuAD 相关文章PaperWeekly 第38期 SQuAD综述 SQuAD，斯坦福在自然语言处理的野心 SQUAD_traing 训练结果：{“exact_match”: 81.20151371807, “f1”: 88.56178500169332} SQUAD_DATA_处理解析源代码run_squad.py原始语料‘’’a paragraphs in original SQUAD DATA{‘paragraphs’:[{‘context’: ‘Architecturally, the school has a Catholic ‘ “character. Atop the Main Building’s gold dome is “ ‘a golden statue of the Virgin Mary. Immediately ‘ ‘in front of the Main Building and facing it, is a ‘ ‘copper statue of Christ with arms upraised with ‘ ‘the legend “Venite Ad Me Omnes”. Next to the Main ‘ ‘Building is the Basilica of the Sacred Heart. ‘ ‘Immediately behind the basilica is the Grotto, a ‘ ‘Marian place of prayer and reflection. It is a ‘ ‘replica of the grotto at Lourdes, France where ‘ ‘the Virgin Mary reputedly appeared to Saint ‘ ‘Bernadette Soubirous in 1858. At the end of the ‘ ‘main drive (and in a direct line that connects ‘ ‘through 3 statues and the Gold Dome), is a ‘ ‘simple, modern stone statue of Mary.’, ‘qas’: [{‘answers’: [{‘answer_start’: 515, ‘text’: ‘Saint Bernadette Soubirous’}], ‘id’: ‘5733be284776f41900661182’, ‘question’: ‘To whom did the Virgin Mary allegedly ‘ ‘appear in 1858 in Lourdes France?’}, {‘answers’: [{‘answer_start’: 188, ‘text’: ‘a copper statue of Christ’}], ‘id’: ‘5733be284776f4190066117f’, ‘question’: ‘What is in front of the Notre Dame Main ‘ ‘Building?’}, {‘answers’: [{‘answer_start’: 279, ‘text’: ‘the Main Building’}], ‘id’: ‘5733be284776f41900661180’, ‘question’: ‘The Basilica of the Sacred heart at ‘ ‘Notre Dame is beside to which ‘ ‘structure?’}, {‘answers’: [{‘answer_start’: 381, ‘text’: ‘a Marian place of prayer and ‘ ‘reflection’}], ‘id’: ‘5733be284776f41900661181’, ‘question’: ‘What is the Grotto at Notre Dame?’}, {‘answers’: [{‘answer_start’: 92, ‘text’: ‘a golden statue of the Virgin ‘ ‘Mary’}], ‘id’: ‘5733be284776f4190066117e’, ‘question’: ‘What sits on top of the Main Building ‘ ‘at Notre Dame?’}]},‘’’ 程序处理后的语料12345678910111213#INFO:tensorflow:*** Example ***#INFO:tensorflow:unique_id: 1000000005#INFO:tensorflow:example_index: 5#INFO:tensorflow:doc_span_index: 0#INFO:tensorflow:tokens: [CLS] what kind of topics began appearing more commonly in poetry and literature during the enlightenment ? [SEP] the influence of science also began appearing more commonly in poetry and literature during the enlightenment . some poetry became infused with scientific metaphor and imagery , while other poems were written directly about scientific topics . sir richard black ##more committed the newton ##ian system to verse in creation , a philosophical poem in seven books ( 1712 ) . after newton ' s death in 1727 , poems were composed in his honour for decades . james thomson ( 1700 – 1748 ) penned his " poem to the memory of newton , " which mo ##urne ##d the loss of newton , but also praised his science and legacy . [SEP]#INFO:tensorflow:token_to_orig_map: 18:0 19:1 20:2 21:3 22:4 23:5 24:6 25:7 26:8 27:9 28:10 29:11 30:12 31:13 32:14 33:15 34:15 35:16 36:17 37:18 38:19 39:20 40:21 41:22 42:23 43:24 44:24 45:25 46:26 47:27 48:28 49:29 50:30 51:31 52:32 53:33 54:33 55:34 56:35 57:36 58:36 59:37 60:38 61:39 62:39 63:40 64:41 65:42 66:43 67:44 68:44 69:45 70:46 71:47 72:48 73:49 74:50 75:51 76:51 77:51 78:51 79:52 80:53 81:53 82:53 83:54 84:55 85:56 86:56 87:57 88:58 89:59 90:60 91:61 92:62 93:63 94:64 95:64 96:65 97:66 98:67 99:67 100:67 101:67 102:67 103:68 104:69 105:70 106:70 107:71 108:72 109:73 110:74 111:75 112:75 113:75 114:76 115:77 116:77 117:77 118:78 119:79 120:80 121:81 122:81 123:82 124:83 125:84 126:85 127:86 128:87 129:88 130:88#INFO:tensorflow:token_is_max_context: 18:True 19:True 20:True 21:True 22:True 23:True 24:True 25:True 26:True 27:True 28:True 29:True 30:True 31:True 32:True 33:True 34:True 35:True 36:True 37:True 38:True 39:True 40:True 41:True 42:True 43:True 44:True 45:True 46:True 47:True 48:True 49:True 50:True 51:True 52:True 53:True 54:True 55:True 56:True 57:True 58:True 59:True 60:True 61:True 62:True 63:True 64:True 65:True 66:True 67:True 68:True 69:True 70:True 71:True 72:True 73:True 74:True 75:True 76:True 77:True 78:True 79:True 80:True 81:True 82:True 83:True 84:True 85:True 86:True 87:True 88:True 89:True 90:True 91:True 92:True 93:True 94:True 95:True 96:True 97:True 98:True 99:True 100:True 101:True 102:True 103:True 104:True 105:True 106:True 107:True 108:True 109:True 110:True 111:True 112:True 113:True 114:True 115:True 116:True 117:True 118:True 119:True 120:True 121:True 122:True 123:True 124:True 125:True 126:True 127:True 128:True 129:True 130:True#INFO:tensorflow:input_ids: 101 2054 2785 1997 7832 2211 6037 2062 4141 1999 4623 1998 3906 2076 1996 16724 1029 102 1996 3747 1997 2671 2036 2211 6037 2062 4141 1999 4623 1998 3906 2076 1996 16724 1012 2070 4623 2150 29592 2007 4045 19240 1998 13425 1010 2096 2060 5878 2020 2517 3495 2055 4045 7832 1012 2909 2957 2304 5974 5462 1996 8446 2937 2291 2000 7893 1999 4325 1010 1037 9569 5961 1999 2698 2808 1006 28460 1007 1012 2044 8446 1005 1055 2331 1999 25350 1010 5878 2020 3605 1999 2010 6225 2005 5109 1012 2508 11161 1006 16601 1516 24445 1007 17430 2010 1000 5961 2000 1996 3638 1997 8446 1010 1000 2029 9587 21737 2094 1996 3279 1997 8446 1010 2021 2036 5868 2010 2671 1998 8027 1012 102 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0#INFO:tensorflow:input_mask: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0#INFO:tensorflow:segment_ids: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0#INFO:tensorflow:start_position: 52#INFO:tensorflow:end_position: 53#INFO:tensorflow:answer: scientific topics 123456import tensorflow as tfimport numpy as npimport tokenizationimport jsonimport pprintimport collections 1234def is_whitespace(c): if c == " " or c == "\t" or c == "\r" or c == "\n" or ord(c) == 0x202F: return True return False 12345678910111213141516171819202122232425262728293031class SquadExample(object): """A single training/test example for simple sequence classification.""" def __init__(self, qas_id, question_text, doc_tokens, orig_answer_text=None, start_position=None, end_position=None): self.qas_id = qas_id self.question_text = question_text self.doc_tokens = doc_tokens self.orig_answer_text = orig_answer_text self.start_position = start_position self.end_position = end_position def __str__(self): return self.__repr__() def __repr__(self): s = "" s += "qas_id: %s" % (tokenization.printable_text(self.qas_id)) s += ", question_text: %s" % ( tokenization.printable_text(self.question_text)) s += ", doc_tokens: [%s]" % (" ".join(self.doc_tokens)) if self.start_position: s += ", start_position: %d" % (self.start_position) if self.start_position: s += ", end_position: %d" % (self.end_position) return s 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667def read_squad_examples(input_file, is_training): """Read a SQuAD json file into a list of SquadExample.""" with tf.gfile.Open(input_file, "r") as reader: input_data = json.load(reader)["data"] def is_whitespace(c): if c == " " or c == "\t" or c == "\r" or c == "\n" or ord(c) == 0x202F: return True return False examples = [] for entry in input_data: for paragraph in entry["paragraphs"]: paragraph_text = paragraph["context"] doc_tokens = [] char_to_word_offset = [] prev_is_whitespace = True for c in paragraph_text: if is_whitespace(c): prev_is_whitespace = True else: if prev_is_whitespace: doc_tokens.append(c) else: doc_tokens[-1] += c prev_is_whitespace = False char_to_word_offset.append(len(doc_tokens) - 1) for qa in paragraph["qas"]: qas_id = qa["id"] question_text = qa["question"] start_position = None end_position = None orig_answer_text = None if is_training: if len(qa["answers"]) != 1: raise ValueError( "For training, each question should have exactly 1 answer.") answer = qa["answers"][0] orig_answer_text = answer["text"] answer_offset = answer["answer_start"] answer_length = len(orig_answer_text) start_position = char_to_word_offset[answer_offset] end_position = char_to_word_offset[answer_offset + answer_length - 1] # Only add answers where the text can be exactly recovered from the # document. If this CAN'T happen it's likely due to weird Unicode # stuff so we will just skip the example. # # Note that this means for training mode, every example is NOT # guaranteed to be preserved. actual_text = " ".join(doc_tokens[start_position:(end_position + 1)]) cleaned_answer_text = " ".join( tokenization.whitespace_tokenize(orig_answer_text)) if actual_text.find(cleaned_answer_text) == -1: tf.logging.warning("Could not find answer: '%s' vs. '%s'", actual_text, cleaned_answer_text) continue example = SquadExample( qas_id=qas_id, question_text=question_text, doc_tokens=doc_tokens, orig_answer_text=orig_answer_text, start_position=start_position, end_position=end_position) examples.append(example) return examples 1234567891011121314151617181920212223242526272829303132333435def _check_is_max_context(doc_spans, cur_span_index, position): """Check if this is the 'max context' doc span for the token.""" # Because of the sliding window approach taken to scoring documents, a single # token can appear in multiple documents. E.g. # Doc: the man went to the store and bought a gallon of milk # Span A: the man went to the # Span B: to the store and bought # Span C: and bought a gallon of # ... # # Now the word 'bought' will have two scores from spans B and C. We only # want to consider the score with "maximum context", which we define as # the *minimum* of its left and right context (the *sum* of left and # right context will always be the same, of course). # # In the example the maximum context for 'bought' would be span C since # it has 1 left context and 3 right context, while span B has 4 left context # and 0 right context. best_score = None best_span_index = None for (span_index, doc_span) in enumerate(doc_spans): end = doc_span.start + doc_span.length - 1 if position &lt; doc_span.start: continue if position &gt; end: continue num_left_context = position - doc_span.start num_right_context = end - position score = min(num_left_context, num_right_context) + 0.01 * doc_span.length if best_score is None or score &gt; best_score: best_score = score best_span_index = span_index return cur_span_index == best_span_index 1vocab_file_path = "/home/b418/jupyter_workspace/B418_common/袁宵/model/BERT/uncased_L-12_H-768_A-12/vocab.txt" 1tokenizer = tokenization.FullTokenizer(vocab_file=vocab_file_path, do_lower_case=True) 1print(tokenizer.tokenize("To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?")) [&#39;to&#39;, &#39;whom&#39;, &#39;did&#39;, &#39;the&#39;, &#39;virgin&#39;, &#39;mary&#39;, &#39;allegedly&#39;, &#39;appear&#39;, &#39;in&#39;, &#39;1858&#39;, &#39;in&#39;, &#39;lou&#39;, &#39;##rdes&#39;, &#39;france&#39;, &#39;?&#39;] 1tokenizer.tokenize("Lourdes") [&#39;lou&#39;, &#39;##rdes&#39;] SQuAD_data/train-v1.1.json1input_file_path = "/home/b418/jupyter_workspace/B418_common/袁宵/data/SQuAD_data/train-v1.1.json" 12with tf.gfile.Open(input_file_path, "r") as reader: input_data = json.load(reader)["data"] 1a_input_data = input_data[0] paragraph123for paragraph in a_input_data["paragraphs"][:2]: print('-'*100) pprint.pprint(paragraph) ---------------------------------------------------------------------------------------------------- {&#39;context&#39;: &#39;Architecturally, the school has a Catholic character. Atop the &#39; &quot;Main Building&#39;s gold dome is a golden statue of the Virgin Mary. &quot; &#39;Immediately in front of the Main Building and facing it, is a &#39; &#39;copper statue of Christ with arms upraised with the legend &#39; &#39;&quot;Venite Ad Me Omnes&quot;. Next to the Main Building is the Basilica &#39; &#39;of the Sacred Heart. Immediately behind the basilica is the &#39; &#39;Grotto, a Marian place of prayer and reflection. It is a replica &#39; &#39;of the grotto at Lourdes, France where the Virgin Mary reputedly &#39; &#39;appeared to Saint Bernadette Soubirous in 1858. At the end of the &#39; &#39;main drive (and in a direct line that connects through 3 statues &#39; &#39;and the Gold Dome), is a simple, modern stone statue of Mary.&#39;, &#39;qas&#39;: [{&#39;answers&#39;: [{&#39;answer_start&#39;: 515, &#39;text&#39;: &#39;Saint Bernadette Soubirous&#39;}], &#39;id&#39;: &#39;5733be284776f41900661182&#39;, &#39;question&#39;: &#39;To whom did the Virgin Mary allegedly appear in 1858 in &#39; &#39;Lourdes France?&#39;}, {&#39;answers&#39;: [{&#39;answer_start&#39;: 188, &#39;text&#39;: &#39;a copper statue of Christ&#39;}], &#39;id&#39;: &#39;5733be284776f4190066117f&#39;, &#39;question&#39;: &#39;What is in front of the Notre Dame Main Building?&#39;}, {&#39;answers&#39;: [{&#39;answer_start&#39;: 279, &#39;text&#39;: &#39;the Main Building&#39;}], &#39;id&#39;: &#39;5733be284776f41900661180&#39;, &#39;question&#39;: &#39;The Basilica of the Sacred heart at Notre Dame is &#39; &#39;beside to which structure?&#39;}, {&#39;answers&#39;: [{&#39;answer_start&#39;: 381, &#39;text&#39;: &#39;a Marian place of prayer and reflection&#39;}], &#39;id&#39;: &#39;5733be284776f41900661181&#39;, &#39;question&#39;: &#39;What is the Grotto at Notre Dame?&#39;}, {&#39;answers&#39;: [{&#39;answer_start&#39;: 92, &#39;text&#39;: &#39;a golden statue of the Virgin Mary&#39;}], &#39;id&#39;: &#39;5733be284776f4190066117e&#39;, &#39;question&#39;: &#39;What sits on top of the Main Building at Notre Dame?&#39;}]} ---------------------------------------------------------------------------------------------------- {&#39;context&#39;: &quot;As at most other universities, Notre Dame&#39;s students run a number &quot; &#39;of news media outlets. The nine student-run outlets include three &#39; &#39;newspapers, both a radio and television station, and several &#39; &#39;magazines and journals. Begun as a one-page journal in September &#39; &#39;1876, the Scholastic magazine is issued twice monthly and claims &#39; &#39;to be the oldest continuous collegiate publication in the United &#39; &#39;States. The other magazine, The Juggler, is released twice a year &#39; &#39;and focuses on student literature and artwork. The Dome yearbook &#39; &#39;is published annually. The newspapers have varying publication &#39; &#39;interests, with The Observer published daily and mainly reporting &#39; &#39;university and other news, and staffed by students from both &#39; &quot;Notre Dame and Saint Mary&#39;s College. Unlike Scholastic and The &quot; &#39;Dome, The Observer is an independent publication and does not &#39; &#39;have a faculty advisor or any editorial oversight from the &#39; &#39;University. In 1987, when some students believed that The &#39; &#39;Observer began to show a conservative bias, a liberal newspaper, &#39; &#39;Common Sense was published. Likewise, in 2003, when other &#39; &#39;students believed that the paper showed a liberal bias, the &#39; &#39;conservative paper Irish Rover went into production. Neither &#39; &#39;paper is published as often as The Observer; however, all three &#39; &#39;are distributed to all students. Finally, in Spring 2008 an &#39; &#39;undergraduate journal for political science research, Beyond &#39; &#39;Politics, made its debut.&#39;, &#39;qas&#39;: [{&#39;answers&#39;: [{&#39;answer_start&#39;: 248, &#39;text&#39;: &#39;September 1876&#39;}], &#39;id&#39;: &#39;5733bf84d058e614000b61be&#39;, &#39;question&#39;: &#39;When did the Scholastic Magazine of Notre dame begin &#39; &#39;publishing?&#39;}, {&#39;answers&#39;: [{&#39;answer_start&#39;: 441, &#39;text&#39;: &#39;twice&#39;}], &#39;id&#39;: &#39;5733bf84d058e614000b61bf&#39;, &#39;question&#39;: &quot;How often is Notre Dame&#39;s the Juggler published?&quot;}, {&#39;answers&#39;: [{&#39;answer_start&#39;: 598, &#39;text&#39;: &#39;The Observer&#39;}], &#39;id&#39;: &#39;5733bf84d058e614000b61c0&#39;, &#39;question&#39;: &#39;What is the daily student paper at Notre Dame called?&#39;}, {&#39;answers&#39;: [{&#39;answer_start&#39;: 126, &#39;text&#39;: &#39;three&#39;}], &#39;id&#39;: &#39;5733bf84d058e614000b61bd&#39;, &#39;question&#39;: &#39;How many student news papers are found at Notre Dame?&#39;}, {&#39;answers&#39;: [{&#39;answer_start&#39;: 908, &#39;text&#39;: &#39;1987&#39;}], &#39;id&#39;: &#39;5733bf84d058e614000b61c1&#39;, &#39;question&#39;: &#39;In what year did the student paper Common Sense begin &#39; &#39;publication at Notre Dame?&#39;}]} 1examples = read_squad_examples(input_file_path, True) 1len(examples) 87599 read_squad_examplesexamples - doc_tokens1a_paragraph_text = a_input_data["paragraphs"][0]['context'] 1a_paragraph_text = '''Architecturally, the school has a Catholic character. Atop the Main Building's gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart.''' 12print(len(a_paragraph_text))print(a_paragraph_text) 333 Architecturally, the school has a Catholic character. Atop the Main Building&#39;s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend &quot;Venite Ad Me Omnes&quot;. Next to the Main Building is the Basilica of the Sacred Heart. 1234567891011121314doc_tokens = []char_to_word_offset = []prev_is_whitespace = True# for c in paragraph_text:for c in a_paragraph_text: if is_whitespace(c): prev_is_whitespace = True else: if prev_is_whitespace: doc_tokens.append(c) else: doc_tokens[-1] += c prev_is_whitespace = False char_to_word_offset.append(len(doc_tokens) - 1) 12print(len(doc_tokens))print(doc_tokens) 59 [&#39;Architecturally,&#39;, &#39;the&#39;, &#39;school&#39;, &#39;has&#39;, &#39;a&#39;, &#39;Catholic&#39;, &#39;character.&#39;, &#39;Atop&#39;, &#39;the&#39;, &#39;Main&#39;, &quot;Building&#39;s&quot;, &#39;gold&#39;, &#39;dome&#39;, &#39;is&#39;, &#39;a&#39;, &#39;golden&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Virgin&#39;, &#39;Mary.&#39;, &#39;Immediately&#39;, &#39;in&#39;, &#39;front&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Main&#39;, &#39;Building&#39;, &#39;and&#39;, &#39;facing&#39;, &#39;it,&#39;, &#39;is&#39;, &#39;a&#39;, &#39;copper&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;Christ&#39;, &#39;with&#39;, &#39;arms&#39;, &#39;upraised&#39;, &#39;with&#39;, &#39;the&#39;, &#39;legend&#39;, &#39;&quot;Venite&#39;, &#39;Ad&#39;, &#39;Me&#39;, &#39;Omnes&quot;.&#39;, &#39;Next&#39;, &#39;to&#39;, &#39;the&#39;, &#39;Main&#39;, &#39;Building&#39;, &#39;is&#39;, &#39;the&#39;, &#39;Basilica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Sacred&#39;, &#39;Heart.&#39;] 12print(len(char_to_word_offset))print(char_to_word_offset) 333 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 23, 23, 23, 23, 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 32, 32, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58] ‘Architecturally, the school has a Catholic character. Atop the ‘“Main Building’s gold dome is a golden statue of the Virgin Mary. “‘Immediately in front of the Main Building and facing it, is a ‘‘copper statue of Christ with arms upraised with the legend ‘‘“Venite Ad Me Omnes”. Next to the Main Building is the Basilica ‘‘of the Sacred Heart. Immediately behind the basilica is the ‘‘Grotto, a Marian place of prayer and reflection. It is a replica ‘‘of the grotto at Lourdes, France where the Virgin Mary reputedly ‘‘appeared to Saint Bernadette Soubirous in 1858. At the end of the ‘‘main drive (and in a direct line that connects through 3 statues ‘‘and the Gold Dome), is a simple, modern stone statue of Mary.’, [‘Architecturally,’, ‘the’, ‘school’, ‘has’, ‘a’, ‘Catholic’, ‘character.’, ‘Atop’, ‘the’, ‘Main’, “Building’s”, ‘gold’, ‘dome’, ‘is’, ‘a’, ‘golden’, ‘statue’, ‘of’, ‘the’, ‘Virgin’, ‘Mary.’, ‘Immediately’, ‘in’, ‘front’, ‘of’, ‘the’, ‘Main’, ‘Building’, ‘and’, ‘facing’, ‘it,’, ‘is’, ‘a’, ‘copper’, ‘statue’, ‘of’, ‘Christ’, ‘with’, ‘arms’, ‘upraised’, ‘with’, ‘the’, ‘legend’, ‘“Venite’, ‘Ad’, ‘Me’, ‘Omnes”.’, ‘Next’, ‘to’, ‘the’, ‘Main’, ‘Building’, ‘is’, ‘the’, ‘Basilica’, ‘of’, ‘the’, ‘Sacred’, ‘Heart.’, ‘Immediately’, ‘behind’, ‘the’, ‘basilica’, ‘is’, ‘the’, ‘Grotto,’, ‘a’, ‘Marian’, ‘place’, ‘of’, ‘prayer’, ‘and’, ‘reflection.’, ‘It’, ‘is’, ‘a’, ‘replica’, ‘of’, ‘the’, ‘grotto’, ‘at’, ‘Lourdes,’, ‘France’, ‘where’, ‘the’, ‘Virgin’, ‘Mary’, ‘reputedly’, ‘appeared’, ‘to’, ‘Saint’, ‘Bernadette’, ‘Soubirous’, ‘in’, ‘1858.’, ‘At’, ‘the’, ‘end’, ‘of’, ‘the’, ‘main’, ‘drive’, ‘(and’, ‘in’, ‘a’, ‘direct’, ‘line’, ‘that’, ‘connects’, ‘through’, ‘3’, ‘statues’, ‘and’, ‘the’, ‘Gold’, ‘Dome),’, ‘is’, ‘a’, ‘simple,’, ‘modern’, ‘stone’, ‘statue’, ‘of’, ‘Mary.’] 查看原始语料转换成的 examples 内容123456789101112a_example_doc_tokens = Nonefor i in range(2): example = examples[i] print(example.qas_id) n = 100 - len(example.question_text) - len(example.orig_answer_text,) print(example.question_text, '-'*n, example.orig_answer_text) print(example.start_position, '-'*n, example.end_position) print(example.doc_tokens) print(example.doc_tokens[90], example.doc_tokens[91], example.doc_tokens[92]) a_example_doc_tokens = example.doc_tokens print('\n') print('\n') 5733be284776f41900661182 To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? --- Saint Bernadette Soubirous 90 --- 92 [&#39;Architecturally,&#39;, &#39;the&#39;, &#39;school&#39;, &#39;has&#39;, &#39;a&#39;, &#39;Catholic&#39;, &#39;character.&#39;, &#39;Atop&#39;, &#39;the&#39;, &#39;Main&#39;, &quot;Building&#39;s&quot;, &#39;gold&#39;, &#39;dome&#39;, &#39;is&#39;, &#39;a&#39;, &#39;golden&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Virgin&#39;, &#39;Mary.&#39;, &#39;Immediately&#39;, &#39;in&#39;, &#39;front&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Main&#39;, &#39;Building&#39;, &#39;and&#39;, &#39;facing&#39;, &#39;it,&#39;, &#39;is&#39;, &#39;a&#39;, &#39;copper&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;Christ&#39;, &#39;with&#39;, &#39;arms&#39;, &#39;upraised&#39;, &#39;with&#39;, &#39;the&#39;, &#39;legend&#39;, &#39;&quot;Venite&#39;, &#39;Ad&#39;, &#39;Me&#39;, &#39;Omnes&quot;.&#39;, &#39;Next&#39;, &#39;to&#39;, &#39;the&#39;, &#39;Main&#39;, &#39;Building&#39;, &#39;is&#39;, &#39;the&#39;, &#39;Basilica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Sacred&#39;, &#39;Heart.&#39;, &#39;Immediately&#39;, &#39;behind&#39;, &#39;the&#39;, &#39;basilica&#39;, &#39;is&#39;, &#39;the&#39;, &#39;Grotto,&#39;, &#39;a&#39;, &#39;Marian&#39;, &#39;place&#39;, &#39;of&#39;, &#39;prayer&#39;, &#39;and&#39;, &#39;reflection.&#39;, &#39;It&#39;, &#39;is&#39;, &#39;a&#39;, &#39;replica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;grotto&#39;, &#39;at&#39;, &#39;Lourdes,&#39;, &#39;France&#39;, &#39;where&#39;, &#39;the&#39;, &#39;Virgin&#39;, &#39;Mary&#39;, &#39;reputedly&#39;, &#39;appeared&#39;, &#39;to&#39;, &#39;Saint&#39;, &#39;Bernadette&#39;, &#39;Soubirous&#39;, &#39;in&#39;, &#39;1858.&#39;, &#39;At&#39;, &#39;the&#39;, &#39;end&#39;, &#39;of&#39;, &#39;the&#39;, &#39;main&#39;, &#39;drive&#39;, &#39;(and&#39;, &#39;in&#39;, &#39;a&#39;, &#39;direct&#39;, &#39;line&#39;, &#39;that&#39;, &#39;connects&#39;, &#39;through&#39;, &#39;3&#39;, &#39;statues&#39;, &#39;and&#39;, &#39;the&#39;, &#39;Gold&#39;, &#39;Dome),&#39;, &#39;is&#39;, &#39;a&#39;, &#39;simple,&#39;, &#39;modern&#39;, &#39;stone&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;Mary.&#39;] Saint Bernadette Soubirous 5733be284776f4190066117f What is in front of the Notre Dame Main Building? -------------------------- a copper statue of Christ 32 -------------------------- 36 [&#39;Architecturally,&#39;, &#39;the&#39;, &#39;school&#39;, &#39;has&#39;, &#39;a&#39;, &#39;Catholic&#39;, &#39;character.&#39;, &#39;Atop&#39;, &#39;the&#39;, &#39;Main&#39;, &quot;Building&#39;s&quot;, &#39;gold&#39;, &#39;dome&#39;, &#39;is&#39;, &#39;a&#39;, &#39;golden&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Virgin&#39;, &#39;Mary.&#39;, &#39;Immediately&#39;, &#39;in&#39;, &#39;front&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Main&#39;, &#39;Building&#39;, &#39;and&#39;, &#39;facing&#39;, &#39;it,&#39;, &#39;is&#39;, &#39;a&#39;, &#39;copper&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;Christ&#39;, &#39;with&#39;, &#39;arms&#39;, &#39;upraised&#39;, &#39;with&#39;, &#39;the&#39;, &#39;legend&#39;, &#39;&quot;Venite&#39;, &#39;Ad&#39;, &#39;Me&#39;, &#39;Omnes&quot;.&#39;, &#39;Next&#39;, &#39;to&#39;, &#39;the&#39;, &#39;Main&#39;, &#39;Building&#39;, &#39;is&#39;, &#39;the&#39;, &#39;Basilica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Sacred&#39;, &#39;Heart.&#39;, &#39;Immediately&#39;, &#39;behind&#39;, &#39;the&#39;, &#39;basilica&#39;, &#39;is&#39;, &#39;the&#39;, &#39;Grotto,&#39;, &#39;a&#39;, &#39;Marian&#39;, &#39;place&#39;, &#39;of&#39;, &#39;prayer&#39;, &#39;and&#39;, &#39;reflection.&#39;, &#39;It&#39;, &#39;is&#39;, &#39;a&#39;, &#39;replica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;grotto&#39;, &#39;at&#39;, &#39;Lourdes,&#39;, &#39;France&#39;, &#39;where&#39;, &#39;the&#39;, &#39;Virgin&#39;, &#39;Mary&#39;, &#39;reputedly&#39;, &#39;appeared&#39;, &#39;to&#39;, &#39;Saint&#39;, &#39;Bernadette&#39;, &#39;Soubirous&#39;, &#39;in&#39;, &#39;1858.&#39;, &#39;At&#39;, &#39;the&#39;, &#39;end&#39;, &#39;of&#39;, &#39;the&#39;, &#39;main&#39;, &#39;drive&#39;, &#39;(and&#39;, &#39;in&#39;, &#39;a&#39;, &#39;direct&#39;, &#39;line&#39;, &#39;that&#39;, &#39;connects&#39;, &#39;through&#39;, &#39;3&#39;, &#39;statues&#39;, &#39;and&#39;, &#39;the&#39;, &#39;Gold&#39;, &#39;Dome),&#39;, &#39;is&#39;, &#39;a&#39;, &#39;simple,&#39;, &#39;modern&#39;, &#39;stone&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;Mary.&#39;] Saint Bernadette Soubirous convert_examples_to_featuresdoc_tokens 2 all_doc_tokens12print(len(a_example_doc_tokens))print(a_example_doc_tokens) 124 [&#39;Architecturally,&#39;, &#39;the&#39;, &#39;school&#39;, &#39;has&#39;, &#39;a&#39;, &#39;Catholic&#39;, &#39;character.&#39;, &#39;Atop&#39;, &#39;the&#39;, &#39;Main&#39;, &quot;Building&#39;s&quot;, &#39;gold&#39;, &#39;dome&#39;, &#39;is&#39;, &#39;a&#39;, &#39;golden&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Virgin&#39;, &#39;Mary.&#39;, &#39;Immediately&#39;, &#39;in&#39;, &#39;front&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Main&#39;, &#39;Building&#39;, &#39;and&#39;, &#39;facing&#39;, &#39;it,&#39;, &#39;is&#39;, &#39;a&#39;, &#39;copper&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;Christ&#39;, &#39;with&#39;, &#39;arms&#39;, &#39;upraised&#39;, &#39;with&#39;, &#39;the&#39;, &#39;legend&#39;, &#39;&quot;Venite&#39;, &#39;Ad&#39;, &#39;Me&#39;, &#39;Omnes&quot;.&#39;, &#39;Next&#39;, &#39;to&#39;, &#39;the&#39;, &#39;Main&#39;, &#39;Building&#39;, &#39;is&#39;, &#39;the&#39;, &#39;Basilica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;Sacred&#39;, &#39;Heart.&#39;, &#39;Immediately&#39;, &#39;behind&#39;, &#39;the&#39;, &#39;basilica&#39;, &#39;is&#39;, &#39;the&#39;, &#39;Grotto,&#39;, &#39;a&#39;, &#39;Marian&#39;, &#39;place&#39;, &#39;of&#39;, &#39;prayer&#39;, &#39;and&#39;, &#39;reflection.&#39;, &#39;It&#39;, &#39;is&#39;, &#39;a&#39;, &#39;replica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;grotto&#39;, &#39;at&#39;, &#39;Lourdes,&#39;, &#39;France&#39;, &#39;where&#39;, &#39;the&#39;, &#39;Virgin&#39;, &#39;Mary&#39;, &#39;reputedly&#39;, &#39;appeared&#39;, &#39;to&#39;, &#39;Saint&#39;, &#39;Bernadette&#39;, &#39;Soubirous&#39;, &#39;in&#39;, &#39;1858.&#39;, &#39;At&#39;, &#39;the&#39;, &#39;end&#39;, &#39;of&#39;, &#39;the&#39;, &#39;main&#39;, &#39;drive&#39;, &#39;(and&#39;, &#39;in&#39;, &#39;a&#39;, &#39;direct&#39;, &#39;line&#39;, &#39;that&#39;, &#39;connects&#39;, &#39;through&#39;, &#39;3&#39;, &#39;statues&#39;, &#39;and&#39;, &#39;the&#39;, &#39;Gold&#39;, &#39;Dome),&#39;, &#39;is&#39;, &#39;a&#39;, &#39;simple,&#39;, &#39;modern&#39;, &#39;stone&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;Mary.&#39;] 12345678910tok_to_orig_index = []orig_to_tok_index = []all_doc_tokens = []#for (i, token) in enumerate(example.doc_tokens):for (i, token) in enumerate(a_example_doc_tokens): orig_to_tok_index.append(len(all_doc_tokens)) sub_tokens = tokenizer.tokenize(token) for sub_token in sub_tokens: tok_to_orig_index.append(i) all_doc_tokens.append(sub_token) 12print(len(orig_to_tok_index))print(orig_to_tok_index) 124 [0, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 49, 50, 51, 52, 56, 57, 58, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 81, 84, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 100, 101, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114, 117, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 148, 149, 150, 152, 153, 154, 155, 156] 12print(len(tok_to_orig_index))print(tok_to_orig_index) 158 [0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 39, 39, 40, 41, 42, 43, 43, 43, 43, 44, 45, 46, 46, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 58, 59, 60, 61, 62, 63, 64, 65, 65, 65, 66, 67, 68, 69, 70, 71, 72, 72, 73, 74, 75, 76, 77, 78, 79, 79, 80, 81, 81, 81, 82, 83, 84, 85, 86, 87, 87, 88, 89, 90, 91, 91, 91, 92, 92, 92, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 115, 115, 116, 117, 118, 118, 119, 120, 121, 122, 123, 123] 12print(len(all_doc_tokens))print(all_doc_tokens) 158 [&#39;architectural&#39;, &#39;##ly&#39;, &#39;,&#39;, &#39;the&#39;, &#39;school&#39;, &#39;has&#39;, &#39;a&#39;, &#39;catholic&#39;, &#39;character&#39;, &#39;.&#39;, &#39;atop&#39;, &#39;the&#39;, &#39;main&#39;, &#39;building&#39;, &quot;&#39;&quot;, &#39;s&#39;, &#39;gold&#39;, &#39;dome&#39;, &#39;is&#39;, &#39;a&#39;, &#39;golden&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;the&#39;, &#39;virgin&#39;, &#39;mary&#39;, &#39;.&#39;, &#39;immediately&#39;, &#39;in&#39;, &#39;front&#39;, &#39;of&#39;, &#39;the&#39;, &#39;main&#39;, &#39;building&#39;, &#39;and&#39;, &#39;facing&#39;, &#39;it&#39;, &#39;,&#39;, &#39;is&#39;, &#39;a&#39;, &#39;copper&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;christ&#39;, &#39;with&#39;, &#39;arms&#39;, &#39;up&#39;, &#39;##rai&#39;, &#39;##sed&#39;, &#39;with&#39;, &#39;the&#39;, &#39;legend&#39;, &#39;&quot;&#39;, &#39;ve&#39;, &#39;##ni&#39;, &#39;##te&#39;, &#39;ad&#39;, &#39;me&#39;, &#39;om&#39;, &#39;##nes&#39;, &#39;&quot;&#39;, &#39;.&#39;, &#39;next&#39;, &#39;to&#39;, &#39;the&#39;, &#39;main&#39;, &#39;building&#39;, &#39;is&#39;, &#39;the&#39;, &#39;basilica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;sacred&#39;, &#39;heart&#39;, &#39;.&#39;, &#39;immediately&#39;, &#39;behind&#39;, &#39;the&#39;, &#39;basilica&#39;, &#39;is&#39;, &#39;the&#39;, &#39;gr&#39;, &#39;##otto&#39;, &#39;,&#39;, &#39;a&#39;, &#39;marian&#39;, &#39;place&#39;, &#39;of&#39;, &#39;prayer&#39;, &#39;and&#39;, &#39;reflection&#39;, &#39;.&#39;, &#39;it&#39;, &#39;is&#39;, &#39;a&#39;, &#39;replica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;gr&#39;, &#39;##otto&#39;, &#39;at&#39;, &#39;lou&#39;, &#39;##rdes&#39;, &#39;,&#39;, &#39;france&#39;, &#39;where&#39;, &#39;the&#39;, &#39;virgin&#39;, &#39;mary&#39;, &#39;reputed&#39;, &#39;##ly&#39;, &#39;appeared&#39;, &#39;to&#39;, &#39;saint&#39;, &#39;bern&#39;, &#39;##ade&#39;, &#39;##tte&#39;, &#39;so&#39;, &#39;##ub&#39;, &#39;##iro&#39;, &#39;##us&#39;, &#39;in&#39;, &#39;1858&#39;, &#39;.&#39;, &#39;at&#39;, &#39;the&#39;, &#39;end&#39;, &#39;of&#39;, &#39;the&#39;, &#39;main&#39;, &#39;drive&#39;, &#39;(&#39;, &#39;and&#39;, &#39;in&#39;, &#39;a&#39;, &#39;direct&#39;, &#39;line&#39;, &#39;that&#39;, &#39;connects&#39;, &#39;through&#39;, &#39;3&#39;, &#39;statues&#39;, &#39;and&#39;, &#39;the&#39;, &#39;gold&#39;, &#39;dome&#39;, &#39;)&#39;, &#39;,&#39;, &#39;is&#39;, &#39;a&#39;, &#39;simple&#39;, &#39;,&#39;, &#39;modern&#39;, &#39;stone&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;mary&#39;, &#39;.&#39;] 使用滑动窗口解决文档太长问题12345678910111213141516171819202122# The -3 accounts for [CLS], [SEP] and [SEP]#max_tokens_for_doc = max_seq_length - len(query_tokens) - 3max_tokens_for_doc = 100 - 20 -3doc_stride = 128# We can have documents that are longer than the maximum sequence length.# To deal with this we do a sliding window approach, where we take chunks# of the up to our max length with a stride of `doc_stride`._DocSpan = collections.namedtuple( # pylint: disable=invalid-name "DocSpan", ["start", "length"])doc_spans = []start_offset = 0while start_offset &lt; len(all_doc_tokens): length = len(all_doc_tokens) - start_offset if length &gt; max_tokens_for_doc: length = max_tokens_for_doc doc_spans.append(_DocSpan(start=start_offset, length=length)) if start_offset + length == len(all_doc_tokens): break start_offset += min(length, doc_stride)print("max_tokens_for_doc:\t",max_tokens_for_doc)print("doc_spans:\t",doc_spans) max_tokens_for_doc: 77 doc_spans: [DocSpan(start=0, length=77), DocSpan(start=77, length=77), DocSpan(start=154, length=4)] 12doc_span = doc_spans[0]doc_span DocSpan(start=0, length=77) 12print(doc_span.start)print(doc_span.length) 0 77 tokens = [], token_to_orig_map = {}, token_is_max_context = {}, segment_ids = []123example = examples[0]query_tokens = tokenizer.tokenize(example.question_text)print(query_tokens) [&#39;to&#39;, &#39;whom&#39;, &#39;did&#39;, &#39;the&#39;, &#39;virgin&#39;, &#39;mary&#39;, &#39;allegedly&#39;, &#39;appear&#39;, &#39;in&#39;, &#39;1858&#39;, &#39;in&#39;, &#39;lou&#39;, &#39;##rdes&#39;, &#39;france&#39;, &#39;?&#39;] 12345678910111213141516171819202122232425262728293031323334353637for (doc_span_index, doc_span) in enumerate(doc_spans): tokens = [] token_to_orig_map = &#123;&#125; token_is_max_context = &#123;&#125; segment_ids = [] tokens.append("[CLS]") segment_ids.append(0) for token in query_tokens: tokens.append(token) segment_ids.append(0) tokens.append("[SEP]") segment_ids.append(0) for i in range(doc_span.length): split_token_index = doc_span.start + i token_to_orig_map[len(tokens)] = tok_to_orig_index[split_token_index] is_max_context = _check_is_max_context(doc_spans, doc_span_index, split_token_index) token_is_max_context[len(tokens)] = is_max_context tokens.append(all_doc_tokens[split_token_index]) segment_ids.append(1) tokens.append("[SEP]") segment_ids.append(1) input_ids = tokenizer.convert_tokens_to_ids(tokens) print("tokens:",len(tokens),'\n',tokens) print('\n') print("input_ids:",len(input_ids),'\n',input_ids) print('\n') print("segment_ids:",len(segment_ids),'\n',segment_ids) print('\n') print("token_is_max_context:",len(token_is_max_context),'\n',token_is_max_context) print('\n') print("token_to_orig_maplen:",len(token_to_orig_map),'\n',token_to_orig_map) print('\n') print('-'*100) tokens: 95 [&#39;[CLS]&#39;, &#39;to&#39;, &#39;whom&#39;, &#39;did&#39;, &#39;the&#39;, &#39;virgin&#39;, &#39;mary&#39;, &#39;allegedly&#39;, &#39;appear&#39;, &#39;in&#39;, &#39;1858&#39;, &#39;in&#39;, &#39;lou&#39;, &#39;##rdes&#39;, &#39;france&#39;, &#39;?&#39;, &#39;[SEP]&#39;, &#39;architectural&#39;, &#39;##ly&#39;, &#39;,&#39;, &#39;the&#39;, &#39;school&#39;, &#39;has&#39;, &#39;a&#39;, &#39;catholic&#39;, &#39;character&#39;, &#39;.&#39;, &#39;atop&#39;, &#39;the&#39;, &#39;main&#39;, &#39;building&#39;, &quot;&#39;&quot;, &#39;s&#39;, &#39;gold&#39;, &#39;dome&#39;, &#39;is&#39;, &#39;a&#39;, &#39;golden&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;the&#39;, &#39;virgin&#39;, &#39;mary&#39;, &#39;.&#39;, &#39;immediately&#39;, &#39;in&#39;, &#39;front&#39;, &#39;of&#39;, &#39;the&#39;, &#39;main&#39;, &#39;building&#39;, &#39;and&#39;, &#39;facing&#39;, &#39;it&#39;, &#39;,&#39;, &#39;is&#39;, &#39;a&#39;, &#39;copper&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;christ&#39;, &#39;with&#39;, &#39;arms&#39;, &#39;up&#39;, &#39;##rai&#39;, &#39;##sed&#39;, &#39;with&#39;, &#39;the&#39;, &#39;legend&#39;, &#39;&quot;&#39;, &#39;ve&#39;, &#39;##ni&#39;, &#39;##te&#39;, &#39;ad&#39;, &#39;me&#39;, &#39;om&#39;, &#39;##nes&#39;, &#39;&quot;&#39;, &#39;.&#39;, &#39;next&#39;, &#39;to&#39;, &#39;the&#39;, &#39;main&#39;, &#39;building&#39;, &#39;is&#39;, &#39;the&#39;, &#39;basilica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;sacred&#39;, &#39;heart&#39;, &#39;.&#39;, &#39;immediately&#39;, &#39;behind&#39;, &#39;[SEP]&#39;] input_ids: 95 [101, 2000, 3183, 2106, 1996, 6261, 2984, 9382, 3711, 1999, 8517, 1999, 10223, 26371, 2605, 1029, 102, 6549, 2135, 1010, 1996, 2082, 2038, 1037, 3234, 2839, 1012, 10234, 1996, 2364, 2311, 1005, 1055, 2751, 8514, 2003, 1037, 3585, 6231, 1997, 1996, 6261, 2984, 1012, 3202, 1999, 2392, 1997, 1996, 2364, 2311, 1998, 5307, 2009, 1010, 2003, 1037, 6967, 6231, 1997, 4828, 2007, 2608, 2039, 14995, 6924, 2007, 1996, 5722, 1000, 2310, 3490, 2618, 4748, 2033, 18168, 5267, 1000, 1012, 2279, 2000, 1996, 2364, 2311, 2003, 1996, 13546, 1997, 1996, 6730, 2540, 1012, 3202, 2369, 102] segment_ids: 95 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] token_is_max_context: 77 {17: True, 18: True, 19: True, 20: True, 21: True, 22: True, 23: True, 24: True, 25: True, 26: True, 27: True, 28: True, 29: True, 30: True, 31: True, 32: True, 33: True, 34: True, 35: True, 36: True, 37: True, 38: True, 39: True, 40: True, 41: True, 42: True, 43: True, 44: True, 45: True, 46: True, 47: True, 48: True, 49: True, 50: True, 51: True, 52: True, 53: True, 54: True, 55: True, 56: True, 57: True, 58: True, 59: True, 60: True, 61: True, 62: True, 63: True, 64: True, 65: True, 66: True, 67: True, 68: True, 69: True, 70: True, 71: True, 72: True, 73: True, 74: True, 75: True, 76: True, 77: True, 78: True, 79: True, 80: True, 81: True, 82: True, 83: True, 84: True, 85: True, 86: True, 87: True, 88: True, 89: True, 90: True, 91: True, 92: True, 93: True} token_to_orig_maplen: 77 {17: 0, 18: 0, 19: 0, 20: 1, 21: 2, 22: 3, 23: 4, 24: 5, 25: 6, 26: 6, 27: 7, 28: 8, 29: 9, 30: 10, 31: 10, 32: 10, 33: 11, 34: 12, 35: 13, 36: 14, 37: 15, 38: 16, 39: 17, 40: 18, 41: 19, 42: 20, 43: 20, 44: 21, 45: 22, 46: 23, 47: 24, 48: 25, 49: 26, 50: 27, 51: 28, 52: 29, 53: 30, 54: 30, 55: 31, 56: 32, 57: 33, 58: 34, 59: 35, 60: 36, 61: 37, 62: 38, 63: 39, 64: 39, 65: 39, 66: 40, 67: 41, 68: 42, 69: 43, 70: 43, 71: 43, 72: 43, 73: 44, 74: 45, 75: 46, 76: 46, 77: 46, 78: 46, 79: 47, 80: 48, 81: 49, 82: 50, 83: 51, 84: 52, 85: 53, 86: 54, 87: 55, 88: 56, 89: 57, 90: 58, 91: 58, 92: 59, 93: 60} ---------------------------------------------------------------------------------------------------- tokens: 95 [&#39;[CLS]&#39;, &#39;to&#39;, &#39;whom&#39;, &#39;did&#39;, &#39;the&#39;, &#39;virgin&#39;, &#39;mary&#39;, &#39;allegedly&#39;, &#39;appear&#39;, &#39;in&#39;, &#39;1858&#39;, &#39;in&#39;, &#39;lou&#39;, &#39;##rdes&#39;, &#39;france&#39;, &#39;?&#39;, &#39;[SEP]&#39;, &#39;the&#39;, &#39;basilica&#39;, &#39;is&#39;, &#39;the&#39;, &#39;gr&#39;, &#39;##otto&#39;, &#39;,&#39;, &#39;a&#39;, &#39;marian&#39;, &#39;place&#39;, &#39;of&#39;, &#39;prayer&#39;, &#39;and&#39;, &#39;reflection&#39;, &#39;.&#39;, &#39;it&#39;, &#39;is&#39;, &#39;a&#39;, &#39;replica&#39;, &#39;of&#39;, &#39;the&#39;, &#39;gr&#39;, &#39;##otto&#39;, &#39;at&#39;, &#39;lou&#39;, &#39;##rdes&#39;, &#39;,&#39;, &#39;france&#39;, &#39;where&#39;, &#39;the&#39;, &#39;virgin&#39;, &#39;mary&#39;, &#39;reputed&#39;, &#39;##ly&#39;, &#39;appeared&#39;, &#39;to&#39;, &#39;saint&#39;, &#39;bern&#39;, &#39;##ade&#39;, &#39;##tte&#39;, &#39;so&#39;, &#39;##ub&#39;, &#39;##iro&#39;, &#39;##us&#39;, &#39;in&#39;, &#39;1858&#39;, &#39;.&#39;, &#39;at&#39;, &#39;the&#39;, &#39;end&#39;, &#39;of&#39;, &#39;the&#39;, &#39;main&#39;, &#39;drive&#39;, &#39;(&#39;, &#39;and&#39;, &#39;in&#39;, &#39;a&#39;, &#39;direct&#39;, &#39;line&#39;, &#39;that&#39;, &#39;connects&#39;, &#39;through&#39;, &#39;3&#39;, &#39;statues&#39;, &#39;and&#39;, &#39;the&#39;, &#39;gold&#39;, &#39;dome&#39;, &#39;)&#39;, &#39;,&#39;, &#39;is&#39;, &#39;a&#39;, &#39;simple&#39;, &#39;,&#39;, &#39;modern&#39;, &#39;stone&#39;, &#39;[SEP]&#39;] input_ids: 95 [101, 2000, 3183, 2106, 1996, 6261, 2984, 9382, 3711, 1999, 8517, 1999, 10223, 26371, 2605, 1029, 102, 1996, 13546, 2003, 1996, 24665, 23052, 1010, 1037, 14042, 2173, 1997, 7083, 1998, 9185, 1012, 2009, 2003, 1037, 15059, 1997, 1996, 24665, 23052, 2012, 10223, 26371, 1010, 2605, 2073, 1996, 6261, 2984, 22353, 2135, 2596, 2000, 3002, 16595, 9648, 4674, 2061, 12083, 9711, 2271, 1999, 8517, 1012, 2012, 1996, 2203, 1997, 1996, 2364, 3298, 1006, 1998, 1999, 1037, 3622, 2240, 2008, 8539, 2083, 1017, 11342, 1998, 1996, 2751, 8514, 1007, 1010, 2003, 1037, 3722, 1010, 2715, 2962, 102] segment_ids: 95 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] token_is_max_context: 77 {17: True, 18: True, 19: True, 20: True, 21: True, 22: True, 23: True, 24: True, 25: True, 26: True, 27: True, 28: True, 29: True, 30: True, 31: True, 32: True, 33: True, 34: True, 35: True, 36: True, 37: True, 38: True, 39: True, 40: True, 41: True, 42: True, 43: True, 44: True, 45: True, 46: True, 47: True, 48: True, 49: True, 50: True, 51: True, 52: True, 53: True, 54: True, 55: True, 56: True, 57: True, 58: True, 59: True, 60: True, 61: True, 62: True, 63: True, 64: True, 65: True, 66: True, 67: True, 68: True, 69: True, 70: True, 71: True, 72: True, 73: True, 74: True, 75: True, 76: True, 77: True, 78: True, 79: True, 80: True, 81: True, 82: True, 83: True, 84: True, 85: True, 86: True, 87: True, 88: True, 89: True, 90: True, 91: True, 92: True, 93: True} token_to_orig_maplen: 77 {17: 61, 18: 62, 19: 63, 20: 64, 21: 65, 22: 65, 23: 65, 24: 66, 25: 67, 26: 68, 27: 69, 28: 70, 29: 71, 30: 72, 31: 72, 32: 73, 33: 74, 34: 75, 35: 76, 36: 77, 37: 78, 38: 79, 39: 79, 40: 80, 41: 81, 42: 81, 43: 81, 44: 82, 45: 83, 46: 84, 47: 85, 48: 86, 49: 87, 50: 87, 51: 88, 52: 89, 53: 90, 54: 91, 55: 91, 56: 91, 57: 92, 58: 92, 59: 92, 60: 92, 61: 93, 62: 94, 63: 94, 64: 95, 65: 96, 66: 97, 67: 98, 68: 99, 69: 100, 70: 101, 71: 102, 72: 102, 73: 103, 74: 104, 75: 105, 76: 106, 77: 107, 78: 108, 79: 109, 80: 110, 81: 111, 82: 112, 83: 113, 84: 114, 85: 115, 86: 115, 87: 115, 88: 116, 89: 117, 90: 118, 91: 118, 92: 119, 93: 120} ---------------------------------------------------------------------------------------------------- tokens: 22 [&#39;[CLS]&#39;, &#39;to&#39;, &#39;whom&#39;, &#39;did&#39;, &#39;the&#39;, &#39;virgin&#39;, &#39;mary&#39;, &#39;allegedly&#39;, &#39;appear&#39;, &#39;in&#39;, &#39;1858&#39;, &#39;in&#39;, &#39;lou&#39;, &#39;##rdes&#39;, &#39;france&#39;, &#39;?&#39;, &#39;[SEP]&#39;, &#39;statue&#39;, &#39;of&#39;, &#39;mary&#39;, &#39;.&#39;, &#39;[SEP]&#39;] input_ids: 22 [101, 2000, 3183, 2106, 1996, 6261, 2984, 9382, 3711, 1999, 8517, 1999, 10223, 26371, 2605, 1029, 102, 6231, 1997, 2984, 1012, 102] segment_ids: 22 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1] token_is_max_context: 4 {17: True, 18: True, 19: True, 20: True} token_to_orig_maplen: 4 {17: 121, 18: 122, 19: 123, 20: 123} ------------------------------------------------------------------ 输入模型的一个样本例子]]></content>
      <categories>
        <category>论文</category>
        <category>论文实现</category>
      </categories>
      <tags>
        <tag>SQuAD</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[TensorFlow_seq2seq_attention_wrapper源码阅读]]></title>
    <url>%2F2018%2F12%2F10%2FTensorFlow_seq2seq_attention_wrapper%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%2F</url>
    <content type="text"><![CDATA[attention_wrappertensorflow/tensorflow/contrib/seq2seq/python/ops/attention_wrapper.pyhttps://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/seq2seq/python/ops/attention_wrapper.py def _luong_score(query, keys, scale):12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152def _luong_score(query, keys, scale): """Implements Luong-style (multiplicative) scoring function. This attention has two forms. The first is standard Luong attention, as described in: Minh-Thang Luong, Hieu Pham, Christopher D. Manning. "Effective Approaches to Attention-based Neural Machine Translation." EMNLP 2015. https://arxiv.org/abs/1508.04025 The second is the scaled form inspired partly by the normalized form of Bahdanau attention. To enable the second form, call this function with `scale=True`. Args: query: Tensor, shape `[batch_size, num_units]` to compare to keys. keys: Processed memory, shape `[batch_size, max_time, num_units]`. scale: Whether to apply a scale to the score function. Returns: A `[batch_size, max_time]` tensor of unnormalized score values. Raises: ValueError: If `key` and `query` depths do not match. """ depth = query.get_shape()[-1] key_units = keys.get_shape()[-1] if depth != key_units: raise ValueError( "Incompatible or unknown inner dimensions between query and keys. " "Query (%s) has units: %s. Keys (%s) have units: %s. " "Perhaps you need to set num_units to the keys' dimension (%s)?" % (query, depth, keys, key_units, key_units)) dtype = query.dtype # Reshape from [batch_size, depth] to [batch_size, 1, depth] # for matmul. query = array_ops.expand_dims(query, 1) # Inner product along the query units dimension. # matmul shapes: query is [batch_size, 1, depth] and # keys is [batch_size, max_time, depth]. # the inner product is asked to **transpose keys' inner shape** to get a # batched matmul on: # [batch_size, 1, depth] . [batch_size, depth, max_time] # resulting in an output shape of: # [batch_size, 1, max_time]. # we then squeeze out the center singleton dimension. score = math_ops.matmul(query, keys, transpose_b=True) score = array_ops.squeeze(score, [1]) if scale: # Scalar used in weight scaling g = variable_scope.get_variable( "attention_g", dtype=dtype, initializer=init_ops.ones_initializer, shape=()) score = g * score return score def _bahdanau_score(processed_query, keys, normalize):12345678910111213141516171819202122232425262728293031323334353637383940414243444546def _bahdanau_score(processed_query, keys, normalize): """Implements Bahdanau-style (additive) scoring function. This attention has two forms. The first is Bhandanau attention, as described in: Dzmitry Bahdanau, Kyunghyun Cho, Yoshua Bengio. "Neural Machine Translation by Jointly Learning to Align and Translate." ICLR 2015. https://arxiv.org/abs/1409.0473 The second is the normalized form. This form is inspired by the weight normalization article: Tim Salimans, Diederik P. Kingma. "Weight Normalization: A Simple Reparameterization to Accelerate Training of Deep Neural Networks." https://arxiv.org/abs/1602.07868 To enable the second form, set `normalize=True`. Args: processed_query: Tensor, shape `[batch_size, num_units]` to compare to keys. keys: Processed memory, shape `[batch_size, max_time, num_units]`. normalize: Whether to normalize the score function. Returns: A `[batch_size, max_time]` tensor of unnormalized score values. """ dtype = processed_query.dtype # Get the number of hidden units from the trailing dimension of keys num_units = tensor_shape.dimension_value( keys.shape[2]) or array_ops.shape(keys)[2] # Reshape from [batch_size, ...] to [batch_size, 1, ...] for broadcasting. processed_query = array_ops.expand_dims(processed_query, 1) v = variable_scope.get_variable( "attention_v", [num_units], dtype=dtype) if normalize: # Scalar used in weight normalization g = variable_scope.get_variable( "attention_g", dtype=dtype, initializer=init_ops.constant_initializer(math.sqrt((1. / num_units))), shape=()) # Bias added prior to the nonlinearity b = variable_scope.get_variable( "attention_b", [num_units], dtype=dtype, initializer=init_ops.zeros_initializer()) # normed_v = g * v / ||v|| normed_v = g * v * math_ops.rsqrt( math_ops.reduce_sum(math_ops.square(v))) return math_ops.reduce_sum( normed_v * math_ops.tanh(keys + processed_query + b), [2]) else: return math_ops.reduce_sum(v * math_ops.tanh(keys + processed_query), [2])]]></content>
      <categories>
        <category>Artificial Intelligence Navigation</category>
        <category>TensorFlow手册</category>
      </categories>
      <tags>
        <tag>TensorFlow</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Bag of Tricks for Image Classification with Convolutional Neural Networks]]></title>
    <url>%2F2018%2F12%2F10%2FBag_of_Tricks_for_Image_Classification_with_Convolutional_Neural_Networks%2F</url>
    <content type="text"><![CDATA[技巧只能源码找？李沐带你纵览卷积网络实战中的惊艳技艺 https://www.jiqizhixin.com/articles/120805 在这篇论文中，李沐等研究者研究了一系列训练过程和模型架构的改进方法。这些方法都能提升模型的准确率，且几乎不增加任何计算复杂度。它们大多数都是次要的「技巧」，例如修正卷积步幅大小或调整学习率策略等。总的来说，采用这些技巧会产生很大的不同。因此研究者希望在多个神经网络架构和数据集上评估它们，并研究它们对最终模型准确率的影响。 研究者的实验表明，一些技巧可以显著提升准确率，且将它们组合在一起能进一步提升模型的准确率。研究者还对比了基线 ResNet 、加了各种技巧的 ResNet、以及其它相关的神经网络，下表 1 展示了所有的准确率对比。这些技巧将 ResNet50 的 Top-1 验证准确率从 75.3％提高到 79.29％，还优于其他更新和改进的网络架构。此外，研究者还表示这些技巧很多都可以迁移到其它领域和数据集，例如目标检测和语义分割等。 Bag of Tricks for Image Classification with Convolutional Neural NetworksTong He, Zhi Zhang, Hang Zhang, Zhongyue Zhang, Junyuan Xie, Mu Li (Submitted on 4 Dec 2018 (v1), last revised 5 Dec 2018 (this version, v2)) Much of the recent progress made in image classification research can be credited to training procedure refinements, such as changes in data augmentations and optimization methods. In the literature, however, most refinements are either briefly mentioned as implementation details or only visible in source code. In this paper, we will examine a collection of such refinements and empirically evaluate their impact on the final model accuracy through ablation study. We will show that, by combining these refinements together, we are able to improve various CNN models significantly. For example, we raise ResNet-50’s top-1 validation accuracy from 75.3% to 79.29% on ImageNet. We will also demonstrate that improvement on image classification accuracy leads to better transfer learning performance in other application domains such as object detection and semantic segmentation. 摘要：图像分类研究近期的多数进展都可以归功于训练过程的调整，例如数据增强和优化方法的变化。然而，在这些文献中，大多数微调方法要么被简单地作为实现细节，或仅能在源代码中看到。在本文中，我们将测试一系列的微调方法，并通过控制变量实验评估它们对最终准确率的影响。我们将展示通过组合不同的微调方法，我们可以显著地改善多种 CNN 模型。例如，我们将 ImageNet 上训练的 ResNet-50 的 top-1 验证准确率从 75.3% 提升到 79.29。本研究还表明，图像分类准确率的提高可以在其他应用领域（如目标检测和语义分割）中实现更好的迁移学习性能。 Comments: 10 pages, 9 tables, 4 figuresSubjects: Computer Vision and Pattern Recognition (cs.CV)Cite as: arXiv:1812.01187 [cs.CV] (or arXiv:1812.01187v2 [cs.CV] for this version)]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>卷积神经网络</tag>
        <tag>Tricks</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[卷积神经网络 Convolutional Neural Networks]]></title>
    <url>%2F2018%2F12%2F07%2F%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%2F</url>
    <content type="text"><![CDATA[Convolutional Neural NetworksCIFAR-10 CNNIn this example, we will download the CIFAR-10 images and build a CNN model with dropout and regularization. CIFAR is composed ot 50k train and 10k test images that are 32x32. We start by loading the necessary libaries and resetting any default computational graph that already exists. 123456789import osimport sysimport tarfileimport matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom six.moves import urllibfrom tensorflow.python.framework import opsops.reset_default_graph() Next, start a new graph session and set the default parameters. List of defaults: batch_size: this is how many cifar examples to train on in one batch. data_dir: where to store data (check if data exists here, as to not have to download every time). output_every: output training accuracy/loss statistics every X generations/epochs. eval_every: output test accuracy/loss statistics every X generations/epochs. image_height: standardize images to this height. image_width: standardize images to this width. crop_height: random internal crop before training on image - height. crop_width: random internal crop before training on image - width. num_channels: number of color channels of image (greyscale = 1, color = 3). num_targets: number of different target categories. CIFAR-10 has 10. extract_folder: folder to extract downloaded images to. 12345678910111213141516# Start a graph sessionsess = tf.Session()# Set model parametersbatch_size = 128data_dir = 'temp'output_every = 50generations = 20000eval_every = 500image_height = 32image_width = 32crop_height = 24crop_width = 24num_channels = 3num_targets = 10extract_folder = 'cifar-10-batches-bin' Set the learning rate, learning rate decay parameters, and extract some of the image-model parameters. 12345678# Exponential Learning Rate Decay Paramslearning_rate = 0.1lr_decay = 0.1num_gens_to_wait = 250.# Extract model parametersimage_vec_length = image_height * image_width * num_channelsrecord_length = 1 + image_vec_length # ( + 1 for the 0-9 label) Load the CIFAR-10 data. 123456789101112131415161718# Load datadata_dir = 'temp'if not os.path.exists(data_dir): os.makedirs(data_dir)cifar10_url = 'http://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz'# Check if file exists, otherwise download itdata_file = os.path.join(data_dir, 'cifar-10-binary.tar.gz')if os.path.isfile(data_file): passelse: # Download file def progress(block_num, block_size, total_size): progress_info = [cifar10_url, float(block_num * block_size) / float(total_size) * 100.0] print('\r Downloading &#123;&#125; - &#123;:.2f&#125;%'.format(*progress_info), end="") filepath, _ = urllib.request.urlretrieve(cifar10_url, data_file, progress) # Extract file tarfile.open(filepath, 'r:gz').extractall(data_dir) Downloading http://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz - 100.00% Next, we define a reading function that will load (and optionally distort the images slightly) for training. 1234567891011121314151617181920212223242526# Define CIFAR readerdef read_cifar_files(filename_queue, distort_images = True): reader = tf.FixedLengthRecordReader(record_bytes=record_length) key, record_string = reader.read(filename_queue) record_bytes = tf.decode_raw(record_string, tf.uint8) image_label = tf.cast(tf.slice(record_bytes, [0], [1]), tf.int32) # Extract image image_extracted = tf.reshape(tf.slice(record_bytes, [1], [image_vec_length]), [num_channels, image_height, image_width]) # Reshape image image_uint8image = tf.transpose(image_extracted, [1, 2, 0]) reshaped_image = tf.cast(image_uint8image, tf.float32) # Randomly Crop image final_image = tf.image.resize_image_with_crop_or_pad(reshaped_image, crop_width, crop_height) if distort_images: # Randomly flip the image horizontally, change the brightness and contrast final_image = tf.image.random_flip_left_right(final_image) final_image = tf.image.random_brightness(final_image,max_delta=63) final_image = tf.image.random_contrast(final_image,lower=0.2, upper=1.8) # Normalize whitening final_image = tf.image.per_image_standardization(final_image) return final_image, image_label Use the above loading function in our image pipeline function below. 1234567891011121314151617181920212223# Create a CIFAR image pipeline from readerdef input_pipeline(batch_size, train_logical=True): if train_logical: files = [os.path.join(data_dir, extract_folder, 'data_batch_&#123;&#125;.bin'.format(i)) for i in range(1,6)] else: files = [os.path.join(data_dir, extract_folder, 'test_batch.bin')] filename_queue = tf.train.string_input_producer(files) image, label = read_cifar_files(filename_queue) # min_after_dequeue defines how big a buffer we will randomly sample # from -- bigger means better shuffling but slower start up and more # memory used. # capacity must be larger than min_after_dequeue and the amount larger # determines the maximum we will prefetch. Recommendation: # min_after_dequeue + (num_threads + a small safety margin) * batch_size min_after_dequeue = 5000 capacity = min_after_dequeue + 3 * batch_size example_batch, label_batch = tf.train.shuffle_batch([image, label], batch_size=batch_size, capacity=capacity, min_after_dequeue=min_after_dequeue) return example_batch, label_batch Create a function that returns our CIFAR-10 model architecture so that we can use it both for training and testing. 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970# Define the model architecture, this will return logits from imagesdef cifar_cnn_model(input_images, batch_size, train_logical=True): def truncated_normal_var(name, shape, dtype): return(tf.get_variable(name=name, shape=shape, dtype=dtype, initializer=tf.truncated_normal_initializer(stddev=0.05))) def zero_var(name, shape, dtype): return(tf.get_variable(name=name, shape=shape, dtype=dtype, initializer=tf.constant_initializer(0.0))) # First Convolutional Layer with tf.variable_scope('conv1') as scope: # Conv_kernel is 5x5 for all 3 colors and we will create 64 features conv1_kernel = truncated_normal_var(name='conv_kernel1', shape=[5, 5, 3, 64], dtype=tf.float32) # We convolve across the image with a stride size of 1 conv1 = tf.nn.conv2d(input_images, conv1_kernel, [1, 1, 1, 1], padding='SAME') # Initialize and add the bias term conv1_bias = zero_var(name='conv_bias1', shape=[64], dtype=tf.float32) conv1_add_bias = tf.nn.bias_add(conv1, conv1_bias) # ReLU element wise relu_conv1 = tf.nn.relu(conv1_add_bias) # Max Pooling pool1 = tf.nn.max_pool(relu_conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],padding='SAME', name='pool_layer1') # Local Response Normalization (parameters from paper) # paper: http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks norm1 = tf.nn.lrn(pool1, depth_radius=5, bias=2.0, alpha=1e-3, beta=0.75, name='norm1') # Second Convolutional Layer with tf.variable_scope('conv2') as scope: # Conv kernel is 5x5, across all prior 64 features and we create 64 more features conv2_kernel = truncated_normal_var(name='conv_kernel2', shape=[5, 5, 64, 64], dtype=tf.float32) # Convolve filter across prior output with stride size of 1 conv2 = tf.nn.conv2d(norm1, conv2_kernel, [1, 1, 1, 1], padding='SAME') # Initialize and add the bias conv2_bias = zero_var(name='conv_bias2', shape=[64], dtype=tf.float32) conv2_add_bias = tf.nn.bias_add(conv2, conv2_bias) # ReLU element wise relu_conv2 = tf.nn.relu(conv2_add_bias) # Max Pooling pool2 = tf.nn.max_pool(relu_conv2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool_layer2') # Local Response Normalization (parameters from paper) norm2 = tf.nn.lrn(pool2, depth_radius=5, bias=2.0, alpha=1e-3, beta=0.75, name='norm2') # Reshape output into a single matrix for multiplication for the fully connected layers reshaped_output = tf.reshape(norm2, [batch_size, -1]) reshaped_dim = reshaped_output.get_shape()[1].value # First Fully Connected Layer with tf.variable_scope('full1') as scope: # Fully connected layer will have 384 outputs. full_weight1 = truncated_normal_var(name='full_mult1', shape=[reshaped_dim, 384], dtype=tf.float32) full_bias1 = zero_var(name='full_bias1', shape=[384], dtype=tf.float32) full_layer1 = tf.nn.relu(tf.add(tf.matmul(reshaped_output, full_weight1), full_bias1)) # Second Fully Connected Layer with tf.variable_scope('full2') as scope: # Second fully connected layer has 192 outputs. full_weight2 = truncated_normal_var(name='full_mult2', shape=[384, 192], dtype=tf.float32) full_bias2 = zero_var(name='full_bias2', shape=[192], dtype=tf.float32) full_layer2 = tf.nn.relu(tf.add(tf.matmul(full_layer1, full_weight2), full_bias2)) # Final Fully Connected Layer -&gt; 10 categories for output (num_targets) with tf.variable_scope('full3') as scope: # Final fully connected layer has 10 (num_targets) outputs. full_weight3 = truncated_normal_var(name='full_mult3', shape=[192, num_targets], dtype=tf.float32) full_bias3 = zero_var(name='full_bias3', shape=[num_targets], dtype=tf.float32) final_output = tf.add(tf.matmul(full_layer2, full_weight3), full_bias3) return final_output Define our loss function. Our loss will be the average cross entropy loss (categorical loss). 123456789# Loss functiondef cifar_loss(logits, targets): # Get rid of extra dimensions and cast targets into integers targets = tf.squeeze(tf.cast(targets, tf.int32)) # Calculate cross entropy from logits and targets cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=targets) # Take the average loss across batch size cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entropy') return cross_entropy_mean Define our training step. Here we will use exponential decay of the learning rate, declare the optimizer and tell the training step to minimize the loss. 12345678910# Train stepdef train_step(loss_value, generation_num): # Our learning rate is an exponential decay after we wait a fair number of generations model_learning_rate = tf.train.exponential_decay(learning_rate, generation_num, num_gens_to_wait, lr_decay, staircase=True) # Create optimizer my_optimizer = tf.train.GradientDescentOptimizer(model_learning_rate) # Initialize train step train_step = my_optimizer.minimize(loss_value) return train_step Create an accuracy function that takes in the predicted logits from the model and the actual targets and returns the accuracy for recording statistics on the train/test sets. 1234567891011# Accuracy functiondef accuracy_of_batch(logits, targets): # Make sure targets are integers and drop extra dimensions targets = tf.squeeze(tf.cast(targets, tf.int32)) # Get predicted values by finding which logit is the greatest batch_predictions = tf.cast(tf.argmax(logits, 1), tf.int32) # Check if they are equal across the batch predicted_correctly = tf.equal(batch_predictions, targets) # Average the 1's and 0's (True's and False's) across the batch size accuracy = tf.reduce_mean(tf.cast(predicted_correctly, tf.float32)) return accuracy Now that we have all our functions we need, let’s use them to create our data pipeline our model the evaluations/accuracy/training operations. First our data pipeline: 123456# Get dataprint('Getting/Transforming Data.')# Initialize the data pipelineimages, targets = input_pipeline(batch_size, train_logical=True)# Get batch test images and targets from piplinetest_images, test_targets = input_pipeline(batch_size, train_logical=False) Getting/Transforming Data. Create our model. Note: Be careful not to accidentally run the following model-creation code twice without resetting the computational graph. If you do, you will end up with variable-sharing errors. If that is the case, re-run the whole script. 1234567891011# Declare Modelprint('Creating the CIFAR10 Model.')with tf.variable_scope('model_definition') as scope: # Declare the training network model model_output = cifar_cnn_model(images, batch_size) # This is very important!!! We must set the scope to REUSE the variables, # otherwise, when we set the test network model, it will create new random # variables. Otherwise we get random evaluations on the test batches. scope.reuse_variables() test_output = cifar_cnn_model(test_images, batch_size)print('Done.') Creating the CIFAR10 Model. Done. Loss and accuracy functions: 123456# Declare loss functionprint('Declare Loss Function.')loss = cifar_loss(model_output, targets)# Create accuracy functionaccuracy = accuracy_of_batch(test_output, test_targets) Declare Loss Function. Next, create the training operations and initialize our model variables. 123456789# Create training operationsprint('Creating the Training Operation.')generation_num = tf.Variable(0, trainable=False)train_op = train_step(loss, generation_num)# Initialize Variablesprint('Initializing the Variables.')init = tf.global_variables_initializer()sess.run(init) Creating the Training Operation. Initializing the Variables. Now, we initialize our data queue. This is an operation that will feed data into our model. Because of this _no placeholders are necessary_!! 12# Initialize queue (This queue will feed into the model, so no placeholders necessary)tf.train.start_queue_runners(sess=sess) [&lt;Thread(QueueRunnerThread-input_producer-input_producer/input_producer_EnqueueMany, started daemon 140554214045440)&gt;, &lt;Thread(QueueRunnerThread-shuffle_batch/random_shuffle_queue-shuffle_batch/random_shuffle_queue_enqueue, started daemon 140554205652736)&gt;, &lt;Thread(QueueRunnerThread-input_producer_1-input_producer_1/input_producer_1_EnqueueMany, started daemon 140554176296704)&gt;, &lt;Thread(QueueRunnerThread-shuffle_batch_1/random_shuffle_queue-shuffle_batch_1/random_shuffle_queue_enqueue, started daemon 140553878501120)&gt;] Training our CIFAR-10 model. 1234567891011121314151617# Train CIFAR Modelprint('Starting Training')train_loss = []test_accuracy = []for i in range(generations): _, loss_value = sess.run([train_op, loss]) if (i+1) % output_every == 0: train_loss.append(loss_value) output = 'Generation &#123;&#125;: Loss = &#123;:.5f&#125;'.format((i+1), loss_value) print(output) if (i+1) % eval_every == 0: [temp_accuracy] = sess.run([accuracy]) test_accuracy.append(temp_accuracy) acc_output = ' --- Test Accuracy = &#123;:.2f&#125;%.'.format(100.*temp_accuracy) print(acc_output) Starting Training Generation 50: Loss = 2.22219 ... Generation 19950: Loss = 0.02510 Generation 20000: Loss = 0.02570 --- Test Accuracy = 80.47%. Plot the loss and accuracy. 123456789101112131415161718# Print loss and accuracy# Matlotlib code to plot the loss and accuracieseval_indices = range(0, generations, eval_every)output_indices = range(0, generations, output_every)# Plot loss over timeplt.plot(output_indices, train_loss, 'k-')plt.title('Softmax Loss per Generation')plt.xlabel('Generation')plt.ylabel('Softmax Loss')plt.show()# Plot accuracy over timeplt.plot(eval_indices, test_accuracy, 'k-')plt.title('Test Accuracy')plt.xlabel('Generation')plt.ylabel('Accuracy')plt.show()]]></content>
      <categories>
        <category>深度学习</category>
        <category>卷积神经网络</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[TensorFlow_dynamic_rnn_AND_bidirectional_dynamic_rnn使用]]></title>
    <url>%2F2018%2F12%2F03%2FTensorFlow_dynamic_rnn_AND_bidirectional_dynamic_rnn%E4%BD%BF%E7%94%A8%2F</url>
    <content type="text"><![CDATA[dynamic_rnn 源码 https://github.com/tensorflow/tensorflow/blob/9590c4c32dd4346ea5c35673336f5912c6072bf2/tensorflow/contrib/recurrent/python/ops/functional_rnn.py lstm_dynamic_rnn1234567import tensorflow as tfimport numpy as npfrom tensorflow.python.framework import opsops.reset_default_graph()tf.__version__ &#39;1.12.0&#39; 1inputs_tensor = tf.constant(np.random.random(size=(3, 4, 5)), dtype=tf.float32) 1lstm_cell = tf.nn.rnn_cell.LSTMCell(num_units=6) 1output, state = tf.nn.dynamic_rnn(cell=lstm_cell, inputs=inputs_tensor, dtype=tf.float32) 1output &lt;tf.Tensor &#39;rnn/transpose_1:0&#39; shape=(3, 4, 6) dtype=float32&gt; 1state LSTMStateTuple(c=&lt;tf.Tensor &#39;rnn/while/Exit_3:0&#39; shape=(3, 6) dtype=float32&gt;, h=&lt;tf.Tensor &#39;rnn/while/Exit_4:0&#39; shape=(3, 6) dtype=float32&gt;) 12sess = tf.Session()sess.run(tf.global_variables_initializer()) 1sess.run(output) array([[[ 0.08616676, 0.00701726, 0.02770402, 0.06492911, 0.0510945 , 0.00969434], [ 0.1320394 , 0.00555411, 0.00191859, 0.08497527, 0.07742812, 0.05351048], [ 0.22318284, 0.00047223, 0.00479356, -0.07421347, 0.10626906, 0.04756515], [ 0.2620672 , 0.00858223, -0.00066401, -0.05911936, 0.12364249, 0.03462988]], [[ 0.06325776, -0.01175407, 0.04182662, 0.02187428, 0.07014529, -0.01354775], [ 0.1437409 , 0.01115061, 0.03309705, 0.00872881, 0.1256691 , -0.01869454], [ 0.1477679 , 0.0219029 , -0.00088758, -0.04972449, 0.10450882, -0.00912069], [ 0.24747844, -0.02095445, 0.08351423, -0.00707687, 0.0659603 , -0.01971625]], [[ 0.08307187, 0.00345412, 0.02962245, 0.06890179, 0.03142677, 0.01744366], [ 0.1346873 , -0.05403996, 0.08703925, -0.00265777, 0.04009543, -0.0071087 ], [ 0.14429979, -0.04602255, 0.04806704, -0.01820353, 0.09431574, 0.00280121], [ 0.22852188, -0.05865859, 0.04669214, -0.07948805, 0.06424228, 0.03090438]]], dtype=float32) 1sess.run(state.h) array([[ 0.2620672 , 0.00858223, -0.00066401, -0.05911936, 0.12364249, 0.03462988], [ 0.24747844, -0.02095445, 0.08351423, -0.00707687, 0.0659603 , -0.01971625], [ 0.22852188, -0.05865859, 0.04669214, -0.07948805, 0.06424228, 0.03090438]], dtype=float32) 1sess.run(state.c) array([[ 0.5363698 , 0.02536838, -0.00174306, -0.0865218 , 0.2190451 , 0.06242979], [ 0.45945585, -0.04819317, 0.1650849 , -0.01152224, 0.12156412, -0.03720763], [ 0.40406716, -0.15820494, 0.11020815, -0.12061047, 0.11127482, 0.0575163 ]], dtype=float32) gru_dynamic_rnn1234567import tensorflow as tfimport numpy as npfrom tensorflow.python.framework import opsops.reset_default_graph()tf.__version__ &#39;1.12.0&#39; 1inputs_tensor = tf.constant(np.random.random(size=(3, 4, 5)), dtype=tf.float32) 1gru_cell = tf.nn.rnn_cell.GRUCell(num_units=6) 1output, state = tf.nn.dynamic_rnn(cell=gru_cell, inputs=inputs_tensor, dtype=tf.float32) 1output &lt;tf.Tensor &#39;rnn/transpose_1:0&#39; shape=(3, 4, 6) dtype=float32&gt; 1state &lt;tf.Tensor &#39;rnn/while/Exit_3:0&#39; shape=(3, 6) dtype=float32&gt; 12sess = tf.Session()sess.run(tf.global_variables_initializer()) 1sess.run(output) array([[[ 0.10332259, -0.11011579, 0.02266729, 0.0007517 , 0.03512604, 0.04907914], [ 0.20385078, -0.23856235, 0.1248817 , -0.08083571, 0.11375216, 0.1124958 ], [ 0.3623113 , -0.32147223, 0.0005917 , 0.05736844, 0.19632787, 0.17149314], [ 0.3957892 , -0.25175768, 0.13963164, -0.01752499, 0.19986765, 0.20010342]], [[ 0.09015381, -0.01318468, 0.04039504, 0.00195809, -0.03166562, -0.00577726], [ 0.1832312 , -0.00861337, 0.07086013, -0.05410649, -0.11791474, -0.12356216], [ 0.262054 , -0.21013457, 0.05953048, 0.00513211, 0.00651281, -0.02495475], [ 0.37156823, -0.19515839, 0.18966836, -0.04400685, 0.0111442 , -0.03699975]], [[ 0.11565635, -0.11679434, -0.06442562, 0.05251991, -0.01245365, -0.00727599], [ 0.17201838, -0.24277222, -0.07361332, -0.03645991, 0.10429659, -0.00199607], [ 0.26178688, -0.21496084, -0.05825588, -0.05373647, 0.09104574, -0.04549351], [ 0.3539365 , -0.20948091, -0.02887814, -0.00197285, 0.06114171, -0.05429474]]], dtype=float32) 1sess.run(state) array([[ 0.3957892 , -0.25175768, 0.13963164, -0.01752499, 0.19986765, 0.20010342], [ 0.37156823, -0.19515839, 0.18966836, -0.04400685, 0.0111442 , -0.03699975], [ 0.3539365 , -0.20948091, -0.02887814, -0.00197285, 0.06114171, -0.05429474]], dtype=float32) Multi_lstm_dynamic_rnn 123456import tensorflow as tfimport numpy as npfrom tensorflow.python.framework import opsops.reset_default_graph()tf.__version__ &#39;1.12.0&#39; 1inputs_tensor = tf.constant(np.random.random(size=(3, 4, 5)), dtype=tf.float32) 123lstm_cell_units_list = [32,16,8]lstm_cells = [tf.nn.rnn_cell.LSTMCell(num_units=unit) for unit in lstm_cell_units_list]multi_lstm_cells = tf.nn.rnn_cell.MultiRNNCell(lstm_cells) 1outputs, states = tf.nn.dynamic_rnn(cell=multi_lstm_cells, inputs=inputs_tensor, dtype=tf.float32) 1outputs &lt;tf.Tensor &#39;rnn/transpose_1:0&#39; shape=(3, 4, 8) dtype=float32&gt; 1states (LSTMStateTuple(c=&lt;tf.Tensor &#39;rnn/while/Exit_3:0&#39; shape=(3, 32) dtype=float32&gt;, h=&lt;tf.Tensor &#39;rnn/while/Exit_4:0&#39; shape=(3, 32) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;rnn/while/Exit_5:0&#39; shape=(3, 16) dtype=float32&gt;, h=&lt;tf.Tensor &#39;rnn/while/Exit_6:0&#39; shape=(3, 16) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;rnn/while/Exit_7:0&#39; shape=(3, 8) dtype=float32&gt;, h=&lt;tf.Tensor &#39;rnn/while/Exit_8:0&#39; shape=(3, 8) dtype=float32&gt;)) 12sess = tf.Session()sess.run(tf.global_variables_initializer()) 1sess.run(outputs) array([[[-1.61404535e-03, -5.39962610e-04, 5.39611437e-06, 2.28725166e-05, 9.44484840e-04, -4.58947802e-03, 1.46846834e-03, -7.76402245e-04], [-3.09936469e-03, -4.27109393e-04, 1.62538933e-03, -3.19648359e-04, 1.73521251e-03, -1.22727510e-02, 4.70003067e-03, -2.35606125e-03], [-2.51045800e-03, -7.78585789e-04, 2.94276653e-03, 7.99274276e-05, 2.68396758e-03, -2.12856531e-02, 9.49617289e-03, -2.14548036e-03], [ 1.16307237e-04, -4.06709267e-04, 4.33099223e-03, 1.24737364e-03, 3.62196262e-03, -3.07264701e-02, 1.57848410e-02, -7.23684439e-04]], [[-3.23332497e-05, 2.67408788e-04, 7.24235782e-04, -2.50815327e-04, 2.83148460e-04, -2.27145315e-03, 1.13080570e-03, -1.57606765e-03], [ 2.05371980e-04, -1.17544514e-04, 7.81793962e-04, 1.08315377e-04, 1.33984850e-03, -7.61773949e-03, 3.80030414e-03, -2.82652606e-03], [ 8.20874877e-04, -1.12650392e-03, -8.80288571e-05, 1.86283619e-03, 2.56655412e-03, -1.47406263e-02, 7.87232257e-03, -2.76046596e-03], [ 2.21824460e-03, -2.74996134e-03, -1.48778886e-03, 5.04738186e-03, 3.63758323e-03, -2.35401765e-02, 1.35801937e-02, -2.54129106e-03]], [[-8.64092377e-04, -3.04833520e-04, -1.56841183e-04, -1.28708722e-04, 9.67342989e-04, -2.75324681e-03, 8.15562380e-04, -6.81574922e-04], [-2.73647415e-03, -1.36391085e-03, -5.19481488e-04, -4.36288465e-05, 2.77121575e-03, -9.15816333e-03, 2.90221907e-03, -5.05329692e-04], [-3.75988754e-03, -3.24360654e-03, -1.28453283e-03, 4.84427328e-05, 5.25222160e-03, -1.69832408e-02, 5.55129535e-03, -2.57142878e-04], [-4.63895453e-03, -5.13906591e-03, -1.28147972e-03, 4.88204561e-04, 7.37427827e-03, -2.69612260e-02, 9.37340409e-03, -1.25891145e-03]]], dtype=float32) 1sess.run(states[2].h) array([[ 0.00011631, -0.00040671, 0.00433099, 0.00124737, 0.00362196, -0.03072647, 0.01578484, -0.00072368], [ 0.00221824, -0.00274996, -0.00148779, 0.00504738, 0.00363758, -0.02354018, 0.01358019, -0.00254129], [-0.00463895, -0.00513907, -0.00128148, 0.0004882 , 0.00737428, -0.02696123, 0.0093734 , -0.00125891]], dtype=float32) 1sess.run(states[2].c) array([[ 0.00022726, -0.00082744, 0.00844097, 0.00248186, 0.00721051, -0.06110654, 0.03194349, -0.00143018], [ 0.00437538, -0.00561603, -0.00291193, 0.01000925, 0.00718385, -0.04696855, 0.02727731, -0.00508054], [-0.00914405, -0.01050362, -0.00249997, 0.00097318, 0.01467903, -0.05430028, 0.01892203, -0.00251437]], dtype=float32) Multi_gru_dynamic_rnn123456import tensorflow as tfimport numpy as npfrom tensorflow.python.framework import opsops.reset_default_graph()tf.__version__ &#39;1.12.0&#39; 1inputs_tensor = tf.constant(np.random.random(size=(3, 4, 5)), dtype=tf.float32) 123gru_cell_units_list = [32,16,8]gru_cells = [tf.nn.rnn_cell.GRUCell(num_units=unit) for unit in gru_cell_units_list]multi_gru_cells = tf.nn.rnn_cell.MultiRNNCell(gru_cells) 1outputs, states = tf.nn.dynamic_rnn(cell=multi_gru_cells, inputs=inputs_tensor, dtype=tf.float32) 1outputs &lt;tf.Tensor &#39;rnn/transpose_1:0&#39; shape=(3, 4, 8) dtype=float32&gt; 1states (&lt;tf.Tensor &#39;rnn/while/Exit_3:0&#39; shape=(3, 32) dtype=float32&gt;, &lt;tf.Tensor &#39;rnn/while/Exit_4:0&#39; shape=(3, 16) dtype=float32&gt;, &lt;tf.Tensor &#39;rnn/while/Exit_5:0&#39; shape=(3, 8) dtype=float32&gt;) 12sess = tf.Session()sess.run(tf.global_variables_initializer()) 1sess.run(outputs) array([[[-3.0689167e-03, 4.7762650e-03, -5.6350869e-03, 7.3930359e-04, 2.7776770e-03, 1.6547712e-03, 4.0468639e-03, -1.6071725e-03], [-9.6203415e-03, 1.0396119e-02, -1.2028635e-02, -7.5696781e-04, 9.5890947e-03, 3.0168635e-03, 9.1733877e-03, -6.7313079e-04], [-1.6855957e-02, 2.2866743e-02, -2.2569295e-02, -3.3538719e-03, 2.0547308e-02, -3.6199810e-05, 1.4878229e-02, 8.4475791e-03], [-2.5817569e-02, 4.0700834e-02, -3.5192616e-02, -8.7473392e-03, 3.5584368e-02, -9.0519777e-03, 2.4247481e-02, 2.3476347e-02]], [[-3.0218370e-03, 6.4162901e-03, -6.9783311e-03, 3.8428712e-04, 5.0610453e-03, -6.1881670e-04, 3.7080410e-04, 5.2686040e-03], [-1.0377670e-02, 1.5972832e-02, -1.6679505e-02, -9.3015225e-04, 1.7201036e-02, -1.5078825e-03, 1.3457731e-03, 1.2340306e-02], [-2.2288060e-02, 2.7055936e-02, -2.7431497e-02, -4.4479482e-03, 3.2678001e-02, -2.9535883e-03, 7.6549058e-03, 1.8373087e-02], [-3.6172852e-02, 4.3594681e-02, -4.2179834e-02, -3.7945234e-03, 4.7429617e-02, -2.6138786e-03, 1.7336009e-02, 2.5696296e-02]], [[-7.6424627e-04, 7.8961477e-03, -7.1330541e-03, 1.9744530e-03, 4.7649448e-03, -3.9919489e-04, -1.7578194e-04, 3.7013867e-03], [-1.6916599e-03, 2.1197245e-02, -1.7833594e-02, 1.4740386e-03, 1.3453390e-02, -5.6854654e-03, 1.9273567e-03, 1.2227280e-02], [-5.0865025e-03, 3.9313547e-02, -3.0530766e-02, -3.3563119e-05, 2.9243957e-02, -1.4064199e-02, 4.2982912e-03, 2.5105122e-02], [-1.1633213e-02, 6.1902620e-02, -4.5463178e-02, -2.4870001e-03, 5.1334824e-02, -2.5908694e-02, 7.0450706e-03, 4.3221094e-02]]], dtype=float32) 1sess.run(states[2]) array([[-0.02581757, 0.04070083, -0.03519262, -0.00874734, 0.03558437, -0.00905198, 0.02424748, 0.02347635], [-0.03617285, 0.04359468, -0.04217983, -0.00379452, 0.04742962, -0.00261388, 0.01733601, 0.0256963 ], [-0.01163321, 0.06190262, -0.04546318, -0.002487 , 0.05133482, -0.02590869, 0.00704507, 0.04322109]], dtype=float32) Multi_lstm_bidirectional_dynamic_rnn1234567import tensorflow as tfimport numpy as npfrom tensorflow.python.framework import opsops.reset_default_graph()tf.__version__ &#39;1.12.0&#39; 1inputs_tensor = tf.constant(np.random.random(size=(3, 4, 5)), dtype=tf.float32) 123456cell_fw_units_list = [32,16,8]cell_bw_units_list = [33,17,9]cell_fw = [tf.nn.rnn_cell.LSTMCell(num_units=unit) for unit in cell_fw_units_list]cell_bw = [tf.nn.rnn_cell.LSTMCell(num_units=unit) for unit in cell_bw_units_list]lstm_forward = tf.nn.rnn_cell.MultiRNNCell(cells=cell_fw)lstm_backword = tf.nn.rnn_cell.MultiRNNCell(cells=cell_bw) 12outputs, states = tf.nn.bidirectional_dynamic_rnn( cell_fw=lstm_forward,cell_bw=lstm_backword,inputs=inputs_tensor,dtype=tf.float32) 1outputs (&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/transpose_1:0&#39; shape=(3, 4, 8) dtype=float32&gt;, &lt;tf.Tensor &#39;ReverseV2:0&#39; shape=(3, 4, 9) dtype=float32&gt;) 1states ((LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_3:0&#39; shape=(3, 32) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_4:0&#39; shape=(3, 32) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_5:0&#39; shape=(3, 16) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_6:0&#39; shape=(3, 16) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_7:0&#39; shape=(3, 8) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_8:0&#39; shape=(3, 8) dtype=float32&gt;)), (LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_3:0&#39; shape=(3, 33) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_4:0&#39; shape=(3, 33) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_5:0&#39; shape=(3, 17) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_6:0&#39; shape=(3, 17) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_7:0&#39; shape=(3, 9) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_8:0&#39; shape=(3, 9) dtype=float32&gt;))) 1outputs[0] &lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/transpose_1:0&#39; shape=(3, 4, 8) dtype=float32&gt; 1outputs[1] &lt;tf.Tensor &#39;ReverseV2:0&#39; shape=(3, 4, 9) dtype=float32&gt; 1states[0] (LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_3:0&#39; shape=(3, 32) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_4:0&#39; shape=(3, 32) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_5:0&#39; shape=(3, 16) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_6:0&#39; shape=(3, 16) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_7:0&#39; shape=(3, 8) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_8:0&#39; shape=(3, 8) dtype=float32&gt;)) 1states[1] (LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_3:0&#39; shape=(3, 33) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_4:0&#39; shape=(3, 33) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_5:0&#39; shape=(3, 17) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_6:0&#39; shape=(3, 17) dtype=float32&gt;), LSTMStateTuple(c=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_7:0&#39; shape=(3, 9) dtype=float32&gt;, h=&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_8:0&#39; shape=(3, 9) dtype=float32&gt;)) 12sess = tf.Session()sess.run(tf.global_variables_initializer()) 1sess.run(outputs[0]) array([[[-0.00076688, -0.00200841, -0.00236855, 0.00039911, -0.00145523, -0.00153653, -0.00134254, 0.00106617], [-0.00454114, -0.00330769, -0.00736781, 0.00173002, -0.0032972 , -0.00345388, -0.00293425, 0.00292132], [-0.01027342, -0.00316362, -0.01381279, 0.00462259, -0.00577486, -0.00438865, -0.00475066, 0.00504041], [-0.01815201, -0.00150841, -0.0213333 , 0.00920272, -0.00753702, -0.0049286 , -0.00753725, 0.00764989]], [[-0.00051021, -0.00109504, -0.00235562, 0.00033509, -0.00184875, -0.00063042, -0.00011131, 0.00110563], [-0.00254402, -0.00287243, -0.00706615, 0.00204808, -0.00484681, -0.00206984, -0.0014233 , 0.00308458], [-0.00708036, -0.00366582, -0.01411008, 0.00544437, -0.0080783 , -0.0034703 , -0.00328208, 0.00583236], [-0.01305352, -0.00295205, -0.02222473, 0.01060574, -0.01145888, -0.00383543, -0.0055557 , 0.0088768 ]], [[-0.00123942, 0.00074371, -0.00094162, 0.00037477, -0.00032651, 0.0001554 , 0.00046975, 0.00046324], [-0.00429494, 0.00162228, -0.00351843, 0.00242352, -0.00078484, -0.00083089, -0.00064292, 0.00222571], [-0.00847503, 0.00332979, -0.00786664, 0.00663501, -0.00156324, -0.00165966, -0.00228085, 0.00515618], [-0.01371686, 0.00522377, -0.01415662, 0.01267656, -0.00229844, -0.00248059, -0.00501328, 0.00901466]]], dtype=float32) 1sess.run(states[0][2].h) array([[-0.01815201, -0.00150841, -0.0213333 , 0.00920272, -0.00753702, -0.0049286 , -0.00753725, 0.00764989], [-0.01305352, -0.00295205, -0.02222473, 0.01060574, -0.01145888, -0.00383543, -0.0055557 , 0.0088768 ], [-0.01371686, 0.00522377, -0.01415662, 0.01267656, -0.00229844, -0.00248059, -0.00501328, 0.00901466]], dtype=float32) 1sess.run(states[0][2].c) array([[-0.03619757, -0.00299038, -0.04237926, 0.01859355, -0.01471011, -0.00991257, -0.01535283, 0.01467649], [-0.02600891, -0.00582871, -0.04436516, 0.02145906, -0.0222083 , -0.00767388, -0.01128497, 0.01682222], [-0.02723665, 0.0103671 , -0.0282324 , 0.02551894, -0.00446999, -0.00497827, -0.01015829, 0.01708832]], dtype=float32) Multi_gru_bidirectional_dynamic_rnn1234567import tensorflow as tfimport numpy as npfrom tensorflow.python.framework import opsops.reset_default_graph()tf.__version__ &#39;1.12.0&#39; 1inputs_tensor = tf.constant(np.random.random(size=(3, 4, 5)), dtype=tf.float32) 123456cell_fw_units_list = [32,16,8]cell_bw_units_list = [33,17,9]cell_fw = [tf.nn.rnn_cell.GRUCell(num_units=unit) for unit in cell_fw_units_list]cell_bw = [tf.nn.rnn_cell.GRUCell(num_units=unit) for unit in cell_bw_units_list]gru_forward = tf.nn.rnn_cell.MultiRNNCell(cells=cell_fw)gru_backword = tf.nn.rnn_cell.MultiRNNCell(cells=cell_bw) 12outputs, states = tf.nn.bidirectional_dynamic_rnn( cell_fw=lstm_forward,cell_bw=lstm_backword,inputs=inputs_tensor,dtype=tf.float32) 1outputs (&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/transpose_1:0&#39; shape=(3, 4, 8) dtype=float32&gt;, &lt;tf.Tensor &#39;ReverseV2:0&#39; shape=(3, 4, 9) dtype=float32&gt;) 1states ((&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_3:0&#39; shape=(3, 32) dtype=float32&gt;, &lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_4:0&#39; shape=(3, 16) dtype=float32&gt;, &lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_5:0&#39; shape=(3, 8) dtype=float32&gt;), (&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_3:0&#39; shape=(3, 33) dtype=float32&gt;, &lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_4:0&#39; shape=(3, 17) dtype=float32&gt;, &lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_5:0&#39; shape=(3, 9) dtype=float32&gt;)) 1outputs[0] &lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/transpose_1:0&#39; shape=(3, 4, 8) dtype=float32&gt; 1outputs[1] &lt;tf.Tensor &#39;ReverseV2:0&#39; shape=(3, 4, 9) dtype=float32&gt; 1states[0] (&lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_3:0&#39; shape=(3, 32) dtype=float32&gt;, &lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_4:0&#39; shape=(3, 16) dtype=float32&gt;, &lt;tf.Tensor &#39;bidirectional_rnn/fw/fw/while/Exit_5:0&#39; shape=(3, 8) dtype=float32&gt;) 1states[1] (&lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_3:0&#39; shape=(3, 33) dtype=float32&gt;, &lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_4:0&#39; shape=(3, 17) dtype=float32&gt;, &lt;tf.Tensor &#39;bidirectional_rnn/bw/bw/while/Exit_5:0&#39; shape=(3, 9) dtype=float32&gt;) 12sess = tf.Session()sess.run(tf.global_variables_initializer()) 1sess.run(outputs[0]) array([[[-6.90058898e-03, -2.82262132e-04, 2.41189310e-03, -1.32219959e-03, -1.17578653e-04, -1.02065690e-03, -3.85798234e-03, -6.75282069e-03], [-1.89461559e-02, -1.18712685e-03, 8.09784234e-03, -5.38685592e-04, -2.89135100e-03, -5.51631721e-03, -1.24855377e-02, -1.74822416e-02], [-3.18835154e-02, -3.26077780e-03, 1.75229590e-02, 2.73799687e-03, -9.39253345e-03, -1.30872596e-02, -2.38550343e-02, -3.05617414e-02], [-4.67147976e-02, -6.17155526e-03, 2.97614653e-02, 6.51888642e-03, -1.87356286e-02, -2.50062142e-02, -3.67445275e-02, -4.68713641e-02]], [[-8.41161050e-03, -2.88979820e-04, 3.92245734e-03, 2.17063329e-03, -5.09262085e-04, -2.77552451e-03, -5.37689496e-03, -3.95025592e-03], [-2.47462429e-02, -1.29592582e-03, 1.10453246e-02, 8.48548859e-03, -2.65943818e-03, -1.01975258e-02, -1.82780307e-02, -1.22013604e-02], [-3.99502814e-02, -3.65575845e-03, 1.86709110e-02, 1.63780842e-02, -8.04547779e-03, -2.07924694e-02, -3.48701701e-02, -2.20657662e-02], [-5.38205951e-02, -7.08078314e-03, 2.95224246e-02, 2.77038664e-02, -1.74766369e-02, -3.49066183e-02, -5.22553027e-02, -3.21215130e-02]], [[-4.29279124e-03, -1.64932735e-05, 5.42476214e-03, 4.06091474e-03, -3.88002302e-03, -1.09710405e-03, -2.73891282e-03, -1.10962777e-03], [-1.24491388e-02, -5.43807575e-04, 1.43955573e-02, 8.08995403e-03, -1.06180515e-02, -3.86995194e-03, -8.71607196e-03, -7.86763430e-03], [-2.33881716e-02, -1.67222926e-03, 2.73847207e-02, 1.45246573e-02, -2.10378524e-02, -1.14183174e-02, -1.76941082e-02, -1.70471650e-02], [-3.55363414e-02, -3.23894341e-03, 4.07814831e-02, 2.15009488e-02, -3.38361487e-02, -2.32368447e-02, -3.00667081e-02, -2.97910050e-02]]], dtype=float32) 1sess.run(states[0][2]) array([[-0.0467148 , -0.00617156, 0.02976147, 0.00651889, -0.01873563, -0.02500621, -0.03674453, -0.04687136], [-0.0538206 , -0.00708078, 0.02952242, 0.02770387, -0.01747664, -0.03490662, -0.0522553 , -0.03212151], [-0.03553634, -0.00323894, 0.04078148, 0.02150095, -0.03383615, -0.02323684, -0.03006671, -0.029791 ]], dtype=float32)]]></content>
      <categories>
        <category>Artificial Intelligence Navigation</category>
        <category>TensorFlow手册</category>
      </categories>
      <tags>
        <tag>TensorFlow</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[动手学深度学习Gluon]]></title>
    <url>%2F2018%2F12%2F02%2F%E5%8A%A8%E6%89%8B%E5%AD%A6%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0Gluon%2F</url>
    <content type="text"><![CDATA[动手学深度学习Gluon 相关资源 标题 说明 《动手学深度学习》 官网 diveintodeeplearning/d2l-zh GitHub 《动手学深度学习》PDF PDF]]></content>
  </entry>
  <entry>
    <title><![CDATA[循环神经网络 Recurrent Neural Networks]]></title>
    <url>%2F2018%2F11%2F29%2F%E5%BE%AA%E7%8E%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%2F</url>
    <content type="text"><![CDATA[Recurrent Neural Networks Introduction We introduce Recurrent Neural Networks and how they are able to feed in a sequence and predict either a fixed target (categorical/numerical) or another sequence (sequence to sequence). Implementing an RNN Model for Spam Prediction We create an RNN model to improve on our spam/ham SMS text predictions. Implementing an LSTM Model for Text Generation We show how to implement a LSTM (Long Short Term Memory) RNN for Shakespeare language generation. (Word level vocabulary) Stacking Multiple LSTM Layers We stack multiple LSTM layers to improve on our Shakespeare language generation. (Character level vocabulary) Creating a Sequence to Sequence Translation Model (Seq2Seq) We show how to use TensorFlow’s sequence-to-sequence models to train an English-German translation model. Training a Siamese Similarity Measure Here, we implement a Siamese RNN to predict the similarity of addresses and use it for record matching. Using RNNs for record matching is very versatile, as we do not have a fixed set of target categories and can use the trained model to predict similarities across new addresses. Implementing an RNN in TensorFlowThis script implements an RNN in TensorFlow to predict spam/ham from texts. We start by loading the necessary libraries and initializing a computation graph in TensorFlow. 123456789101112import osimport reimport ioimport requestsimport numpy as npimport matplotlib.pyplot as pltimport tensorflow as tffrom zipfile import ZipFilefrom tensorflow.python.framework import opsops.reset_default_graph()# Start a graphsess = tf.Session() Next we set the parameters for the RNN model. 123456789# Set RNN parametersepochs = 50batch_size = 250max_sequence_length = 25rnn_size = 10embedding_size = 50min_word_frequency = 10learning_rate = 0.0005dropout_keep_prob = tf.placeholder(tf.float32) We download and save the data next. First we check if we have saved it before and load it locally, if not, we load it from the internet (UCI machine learning data repository). 123456789101112131415161718192021222324252627282930# Download or open datadata_dir = 'temp'data_file = 'text_data.txt'if not os.path.exists(data_dir): os.makedirs(data_dir)if not os.path.isfile(os.path.join(data_dir, data_file)): zip_url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/00228/smsspamcollection.zip' r = requests.get(zip_url) z = ZipFile(io.BytesIO(r.content)) file = z.read('SMSSpamCollection') # Format Data text_data = file.decode() text_data = text_data.encode('ascii', errors='ignore') text_data = text_data.decode().split('\n') # Save data to text file with open(os.path.join(data_dir, data_file), 'w') as file_conn: for text in text_data: file_conn.write("&#123;&#125;\n".format(text))else: # Open data from text file text_data = [] with open(os.path.join(data_dir, data_file), 'r') as file_conn: for row in file_conn: text_data.append(row) text_data = text_data[:-1]text_data = [x.split('\t') for x in text_data if len(x) &gt;= 1][text_data_target, text_data_train] = [list(x) for x in zip(*text_data)] Next, we process the texts and turn them into numeric representations (words —&gt; indices). 123456789101112131415# Create a text cleaning functiondef clean_text(text_string): text_string = re.sub(r'([^\s\w]|_|[0-9])+', '', text_string) text_string = " ".join(text_string.split()) text_string = text_string.lower() return text_string# Clean textstext_data_train = [clean_text(x) for x in text_data_train]# Change texts into numeric vectorsvocab_processor = tf.contrib.learn.preprocessing.VocabularyProcessor(max_sequence_length, min_frequency=min_word_frequency)text_processed = np.array(list(vocab_processor.fit_transform(text_data_train))) Now we shuffle and split the texts into train/tests (80% training, 20% testing). 1234567891011121314# Shuffle and split datatext_processed = np.array(text_processed)text_data_target = np.array([1 if x == 'ham' else 0 for x in text_data_target])shuffled_ix = np.random.permutation(np.arange(len(text_data_target)))x_shuffled = text_processed[shuffled_ix]y_shuffled = text_data_target[shuffled_ix]# Split train/test setix_cutoff = int(len(y_shuffled)*0.80)x_train, x_test = x_shuffled[:ix_cutoff], x_shuffled[ix_cutoff:]y_train, y_test = y_shuffled[:ix_cutoff], y_shuffled[ix_cutoff:]vocab_size = len(vocab_processor.vocabulary_)print("Vocabulary Size: &#123;:d&#125;".format(vocab_size))print("80-20 Train Test split: &#123;:d&#125; -- &#123;:d&#125;".format(len(y_train), len(y_test))) Vocabulary Size: 933 80-20 Train Test split: 4459 -- 1115 Here we can define our RNN model. We create the placeholders for the data, word embedding matrices (and embedding lookups), and define the rest of the model. The rest of the RNN model will create a dynamic RNN cell (regular RNN type), which will vary the number of RNNs needed for variable input length (different amount of words for input texts), and then output into a fully connected logistic layer to predict spam or ham as output. 123456789101112131415161718192021222324252627# Create placeholdersx_data = tf.placeholder(tf.int32, [None, max_sequence_length])y_output = tf.placeholder(tf.int32, [None])# Create embeddingembedding_mat = tf.Variable(tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0))embedding_output = tf.nn.embedding_lookup(embedding_mat, x_data)# Define the RNN cell# tensorflow change &gt;= 1.0, rnn is put into tensorflow.contrib directory. Prior version not test.if tf.__version__[0] &gt;= '1': cell = tf.contrib.rnn.BasicRNNCell(num_units=rnn_size)else: cell = tf.nn.rnn_cell.BasicRNNCell(num_units=rnn_size)output, state = tf.nn.dynamic_rnn(cell, embedding_output, dtype=tf.float32)output = tf.nn.dropout(output, dropout_keep_prob)# Get output of RNN sequence#output = tf.transpose(output, [1, 0, 2])#last = tf.gather(output, int(output.get_shape()[0]) - 1)last = output[:,-1,:]weight = tf.Variable(tf.truncated_normal([rnn_size, 2], stddev=0.1))bias = tf.Variable(tf.constant(0.1, shape=[2]))logits_out = tf.matmul(last, weight) + bias Next we declare the loss function (softmax cross entropy), an accuracy function, and optimization function (RMSProp). 12345678# Loss functionlosses = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits_out, labels=y_output)loss = tf.reduce_mean(losses)accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(logits_out, 1), tf.cast(y_output, tf.int64)), tf.float32))optimizer = tf.train.RMSPropOptimizer(learning_rate)train_step = optimizer.minimize(loss) You may ignore the warning, as the texts are small and our batch size is only 100. If you increase the batch size and/or have longer sequences of texts, this model may consume too much memory. Next we initialize the variables in the computational graph. 1234567init = tf.global_variables_initializer()sess.run(init)train_loss = []test_loss = []train_accuracy = []test_accuracy = [] Now we can start our training! 12345678910111213141516171819202122232425262728293031# Start trainingfor epoch in range(epochs): # Shuffle training data shuffled_ix = np.random.permutation(np.arange(len(x_train))) x_train = x_train[shuffled_ix] y_train = y_train[shuffled_ix] num_batches = int(len(x_train)/batch_size) + 1 # TO DO CALCULATE GENERATIONS ExACTLY for i in range(num_batches): # Select train data min_ix = i * batch_size max_ix = np.min([len(x_train), ((i+1) * batch_size)]) x_train_batch = x_train[min_ix:max_ix] y_train_batch = y_train[min_ix:max_ix] # Run train step train_dict = &#123;x_data: x_train_batch, y_output: y_train_batch, dropout_keep_prob:0.5&#125; sess.run(train_step, feed_dict=train_dict) # Run loss and accuracy for training temp_train_loss, temp_train_acc = sess.run([loss, accuracy], feed_dict=train_dict) train_loss.append(temp_train_loss) train_accuracy.append(temp_train_acc) # Run Eval Step test_dict = &#123;x_data: x_test, y_output: y_test, dropout_keep_prob:1.0&#125; temp_test_loss, temp_test_acc = sess.run([loss, accuracy], feed_dict=test_dict) test_loss.append(temp_test_loss) test_accuracy.append(temp_test_acc) print('Epoch: &#123;&#125;, Test Loss: &#123;:.2&#125;, Test Acc: &#123;:.2&#125;'.format(epoch+1, temp_test_loss, temp_test_acc)) Epoch: 1, Test Loss: 0.71, Test Acc: 0.17 Epoch: 2, Test Loss: 0.68, Test Acc: 0.82 ... Epoch: 50, Test Loss: 0.12, Test Acc: 0.96 Here is matplotlib code to plot the loss and accuracy over the training generations for both the train and test sets. 1234567891011121314151617181920%matplotlib inline# Plot loss over timeepoch_seq = np.arange(1, epochs+1)plt.plot(epoch_seq, train_loss, 'k--', label='Train Set')plt.plot(epoch_seq, test_loss, 'r-', label='Test Set')plt.title('Softmax Loss')plt.xlabel('Epochs')plt.ylabel('Softmax Loss')plt.legend(loc='upper left')plt.show()# Plot accuracy over timeplt.plot(epoch_seq, train_accuracy, 'k--', label='Train Set')plt.plot(epoch_seq, test_accuracy, 'r-', label='Test Set')plt.title('Test Accuracy')plt.xlabel('Epochs')plt.ylabel('Accuracy')plt.legend(loc='lower right')plt.show() Evaluating New TextsHere, we show how to use our trained model to evaluate new texts (which may or may not be spam/ham) 12345sample_texts = ['Hi, please respond 1111 asap to claim your change to win now!', 'Hey what are you doing for dinner tonight?', 'New offer, show this text for 50% off of our inagural sale!', 'Can you take the dog to the vet tomorrow?', 'Congratulations! You have been randomly selected to receive account credit!'] Now we clean our sample texts. 12clean_texts = [clean_text(text) for text in sample_texts]print(clean_texts) [&#39;hi please respond asap to claim your change to win now&#39;, &#39;hey what are you doing for dinner tonight&#39;, &#39;new offer show this text for off of our inagural sale&#39;, &#39;can you take the dog to the vet tomorrow&#39;, &#39;congratulations you have been randomly selected to receive account credit&#39;] Next, we transform each text as a sequence of words into a sequence of vocabulary indices. 12processed_texts = np.array(list(vocab_processor.transform(clean_texts)))print(processed_texts) [[ 93 99 0 0 1 114 13 524 1 178 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [121 52 20 3 151 12 332 208 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [ 92 376 483 39 69 12 203 15 86 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [ 28 3 104 5 0 1 5 0 143 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [701 3 17 98 0 420 1 318 301 738 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]] Now we can run each of the texts through our model and get the output logits. 12345# Remember to wrap the resulting logits in a softmax to get probabilitieseval_feed_dict = &#123;x_data: processed_texts, dropout_keep_prob: 1.0&#125;model_results = sess.run(tf.nn.softmax(logits_out), feed_dict=eval_feed_dict)print(model_results) [[0.86792374 0.13207628] [0.00838861 0.9916114 ] [0.00871871 0.99128133] [0.00838833 0.99161166] [0.6345383 0.36546162]] Now print results 123456categories = ['spam', 'ham']for ix, result in enumerate(model_results): prediction = categories[np.argmax(result)] print('Text: &#123;&#125;, \nPrediction: &#123;&#125;\n'.format(sample_texts[ix], prediction)) Text: Hi, please respond 1111 asap to claim your change to win now!, Prediction: spam Text: Hey what are you doing for dinner tonight?, Prediction: ham Text: New offer, show this text for 50% off of our inagural sale!, Prediction: ham Text: Can you take the dog to the vet tomorrow?, Prediction: ham Text: Congratulations! You have been randomly selected to receive account credit!, Prediction: spam Implementing an LSTM RNN ModelHere we implement an LSTM model on all a data set of Shakespeare works. We start by loading the necessary libraries and resetting the default computational graph. 123456789101112import osimport reimport stringimport requestsimport numpy as npimport collectionsimport randomimport pickleimport matplotlib.pyplot as pltimport tensorflow as tffrom tensorflow.python.framework import opsops.reset_default_graph() We start a computational graph session. 1sess = tf.Session() Next, it is important to set the algorithm and data processing parameters. Parameter : Descriptions min_word_freq: Only attempt to model words that appear at least 5 times. rnn_size: size of our RNN (equal to the embedding size) epochs: Number of epochs to cycle through the data batch_size: How many examples to train on at once learning_rate: The learning rate or the convergence paramter training_seq_len: The length of the surrounding word group (e.g. 10 = 5 on each side) embedding_size: Must be equal to the rnn_size save_every: How often to save the model eval_every: How often to evaluate the model prime_texts: List of test sentences 123456789101112131415161718192021222324252627282930# Set RNN Parametersmin_word_freq = 5 # Trim the less frequent words offrnn_size = 128 # RNN Model sizeembedding_size = 100 # Word embedding sizeepochs = 10 # Number of epochs to cycle through databatch_size = 100 # Train on this many examples at oncelearning_rate = 0.001 # Learning ratetraining_seq_len = 50 # how long of a word group to consider#embedding_size = rnn_sizesave_every = 500 # How often to save model checkpointseval_every = 50 # How often to evaluate the test sentencesprime_texts = ['thou art more', 'to be or not to', 'wherefore art thou']# Download/store Shakespeare datadata_dir = 'temp'data_file = 'shakespeare.txt'model_path = 'shakespeare_model'full_model_dir = os.path.join(data_dir, model_path)# Declare punctuation to remove, everything except hyphens and apostrophespunctuation = string.punctuationpunctuation = ''.join([x for x in punctuation if x not in ['-', "'"]])# Make Model Directoryif not os.path.exists(full_model_dir): os.makedirs(full_model_dir)# Make data directoryif not os.path.exists(data_dir): os.makedirs(data_dir) Download the data if we don’t have it saved already. The data comes from the Gutenberg Project 1234567891011121314151617181920212223242526272829print('Loading Shakespeare Data')# Check if file is downloaded.if not os.path.isfile(os.path.join(data_dir, data_file)): print('Not found, downloading Shakespeare texts from www.gutenberg.org') shakespeare_url = 'http://www.gutenberg.org/cache/epub/100/pg100.txt' # Get Shakespeare text response = requests.get(shakespeare_url) shakespeare_file = response.content # Decode binary into string s_text = shakespeare_file.decode('utf-8') # Drop first few descriptive paragraphs. s_text = s_text[7675:] # Remove newlines s_text = s_text.replace('\r\n', '') s_text = s_text.replace('\n', '') # Write to file with open(os.path.join(data_dir, data_file), 'w') as out_conn: out_conn.write(s_text)else: # If file has been saved, load from that file with open(os.path.join(data_dir, data_file), 'r') as file_conn: s_text = file_conn.read().replace('\n', '')# Clean textprint('Cleaning Text')s_text = re.sub(r'[&#123;&#125;]'.format(punctuation), ' ', s_text)s_text = re.sub('\s+', ' ', s_text ).strip().lower()print('Done loading/cleaning.') Loading Shakespeare Data Cleaning Text Done loading/cleaning. Define a function to build a word processing dictionary (word -&gt; ix) 1234567891011121314# Build word vocabulary functiondef build_vocab(text, min_word_freq): word_counts = collections.Counter(text.split(' ')) # limit word counts to those more frequent than cutoff word_counts = &#123;key:val for key, val in word_counts.items() if val&gt;min_word_freq&#125; # Create vocab --&gt; index mapping words = word_counts.keys() vocab_to_ix_dict = &#123;key:(ix+1) for ix, key in enumerate(words)&#125; # Add unknown key --&gt; 0 index vocab_to_ix_dict['unknown']=0 # Create index --&gt; vocab mapping ix_to_vocab_dict = &#123;val:key for key,val in vocab_to_ix_dict.items()&#125; return(ix_to_vocab_dict, vocab_to_ix_dict) Now we can build the index-vocabulary from the Shakespeare data. 1234567891011121314151617# Build Shakespeare vocabularyprint('Building Shakespeare Vocab')ix2vocab, vocab2ix = build_vocab(s_text, min_word_freq)vocab_size = len(ix2vocab) + 1print('Vocabulary Length = &#123;&#125;'.format(vocab_size))# Sanity Checkassert(len(ix2vocab) == len(vocab2ix))# Convert text to word vectorss_text_words = s_text.split(' ')s_text_ix = []for ix, x in enumerate(s_text_words): try: s_text_ix.append(vocab2ix[x]) except: s_text_ix.append(0)s_text_ix = np.array(s_text_ix) Building Shakespeare Vocab Vocabulary Length = 8009 We define the LSTM model. The methods of interest are the __init__() method, which defines all the model variables and operations, and the sample() method which takes in a sample word and loops through to generate text. 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990# Define LSTM RNN Modelclass LSTM_Model(): def __init__(self, embedding_size, rnn_size, batch_size, learning_rate, training_seq_len, vocab_size, infer_sample=False): self.embedding_size = embedding_size self.rnn_size = rnn_size self.vocab_size = vocab_size self.infer_sample = infer_sample self.learning_rate = learning_rate if infer_sample: self.batch_size = 1 self.training_seq_len = 1 else: self.batch_size = batch_size self.training_seq_len = training_seq_len self.lstm_cell = tf.nn.rnn_cell.LSTMCell(self.rnn_size) self.initial_state = self.lstm_cell.zero_state(self.batch_size, tf.float32) self.x_data = tf.placeholder(tf.int32, [self.batch_size, self.training_seq_len]) self.y_output = tf.placeholder(tf.int32, [self.batch_size, self.training_seq_len]) with tf.variable_scope('lstm_vars'): # Softmax Output Weights W = tf.get_variable('W', [self.rnn_size, self.vocab_size], tf.float32, tf.random_normal_initializer()) b = tf.get_variable('b', [self.vocab_size], tf.float32, tf.constant_initializer(0.0)) # Define Embedding embedding_mat = tf.get_variable('embedding_mat', [self.vocab_size, self.embedding_size], tf.float32, tf.random_normal_initializer()) embedding_output = tf.nn.embedding_lookup(embedding_mat, self.x_data) rnn_inputs = tf.split(axis=1, num_or_size_splits=self.training_seq_len, value=embedding_output) rnn_inputs_trimmed = [tf.squeeze(x, [1]) for x in rnn_inputs] # If we are inferring (generating text), we add a 'loop' function # Define how to get the i+1 th input from the i th output def inferred_loop(prev, count): # Apply hidden layer prev_transformed = tf.matmul(prev, W) + b # Get the index of the output (also don't run the gradient) prev_symbol = tf.stop_gradient(tf.argmax(prev_transformed, 1)) # Get embedded vector output = tf.nn.embedding_lookup(embedding_mat, prev_symbol) return(output) decoder = tf.contrib.legacy_seq2seq.rnn_decoder outputs, last_state = decoder(rnn_inputs_trimmed, self.initial_state, self.lstm_cell, loop_function=inferred_loop if infer_sample else None) # Non inferred outputs output = tf.reshape(tf.concat(axis=1, values=outputs), [-1, self.rnn_size]) # Logits and output self.logit_output = tf.matmul(output, W) + b self.model_output = tf.nn.softmax(self.logit_output) loss_fun = tf.contrib.legacy_seq2seq.sequence_loss_by_example loss = loss_fun([self.logit_output],[tf.reshape(self.y_output, [-1])], [tf.ones([self.batch_size * self.training_seq_len])], self.vocab_size) self.cost = tf.reduce_sum(loss) / (self.batch_size * self.training_seq_len) self.final_state = last_state gradients, _ = tf.clip_by_global_norm(tf.gradients(self.cost, tf.trainable_variables()), 4.5) optimizer = tf.train.AdamOptimizer(self.learning_rate) self.train_op = optimizer.apply_gradients(zip(gradients, tf.trainable_variables())) def sample(self, sess, words=ix2vocab, vocab=vocab2ix, num=10, prime_text='thou art'): state = sess.run(self.lstm_cell.zero_state(1, tf.float32)) word_list = prime_text.split() for word in word_list[:-1]: x = np.zeros((1, 1)) x[0, 0] = vocab[word] feed_dict = &#123;self.x_data: x, self.initial_state:state&#125; [state] = sess.run([self.final_state], feed_dict=feed_dict) out_sentence = prime_text word = word_list[-1] for n in range(num): x = np.zeros((1, 1)) x[0, 0] = vocab[word] feed_dict = &#123;self.x_data: x, self.initial_state:state&#125; [model_output, state] = sess.run([self.model_output, self.final_state], feed_dict=feed_dict) sample = np.argmax(model_output[0]) if sample == 0: break word = words[sample] out_sentence = out_sentence + ' ' + word return(out_sentence) In order to use the same model (with the same trained variables), we need to share the variable scope between the trained model and the test model. 12345678# Define LSTM Modellstm_model = LSTM_Model(embedding_size, rnn_size, batch_size, learning_rate, training_seq_len, vocab_size)# Tell TensorFlow we are reusing the scope for the testingwith tf.variable_scope(tf.get_variable_scope(), reuse=True): test_lstm_model = LSTM_Model(embedding_size, rnn_size, batch_size, learning_rate, training_seq_len, vocab_size, infer_sample=True) We need to save the model, so we create a model saving operation. 12# Create model saversaver = tf.train.Saver(tf.global_variables()) Let’s calculate how many batches are needed for each epoch and split up the data accordingly. 123456# Create batches for each epochnum_batches = int(len(s_text_ix)/(batch_size * training_seq_len)) + 1# Split up text indices into subarrays, of equal sizebatches = np.array_split(s_text_ix, num_batches)# Reshape each split into [batch_size, training_seq_len]batches = [np.resize(x, [batch_size, training_seq_len]) for x in batches] Initialize all the variables 123# Initialize all variablesinit = tf.global_variables_initializer()sess.run(init) Training the model! 12345678910111213141516171819202122232425262728293031323334353637383940414243# Train modeltrain_loss = []iteration_count = 1for epoch in range(epochs): # Shuffle word indices random.shuffle(batches) # Create targets from shuffled batches targets = [np.roll(x, -1, axis=1) for x in batches] # Run a through one epoch print('Starting Epoch #&#123;&#125; of &#123;&#125;.'.format(epoch+1, epochs)) # Reset initial LSTM state every epoch state = sess.run(lstm_model.initial_state) for ix, batch in enumerate(batches): training_dict = &#123;lstm_model.x_data: batch, lstm_model.y_output: targets[ix]&#125; c, h = lstm_model.initial_state training_dict[c] = state.c training_dict[h] = state.h temp_loss, state, _ = sess.run([lstm_model.cost, lstm_model.final_state, lstm_model.train_op], feed_dict=training_dict) train_loss.append(temp_loss) # Print status every 10 gens if iteration_count % 10 == 0: summary_nums = (iteration_count, epoch+1, ix+1, num_batches+1, temp_loss) print('Iteration: &#123;&#125;, Epoch: &#123;&#125;, Batch: &#123;&#125; out of &#123;&#125;, Loss: &#123;:.2f&#125;'.format(*summary_nums)) # Save the model and the vocab if iteration_count % save_every == 0: # Save model model_file_name = os.path.join(full_model_dir, 'model') saver.save(sess, model_file_name, global_step = iteration_count) print('Model Saved To: &#123;&#125;'.format(model_file_name)) # Save vocabulary dictionary_file = os.path.join(full_model_dir, 'vocab.pkl') with open(dictionary_file, 'wb') as dict_file_conn: pickle.dump([vocab2ix, ix2vocab], dict_file_conn) if iteration_count % eval_every == 0: for sample in prime_texts: print(test_lstm_model.sample(sess, ix2vocab, vocab2ix, num=10, prime_text=sample)) iteration_count += 1 Starting Epoch #1 of 10. Iteration: 10, Epoch: 1, Batch: 10 out of 182, Loss: 9.73 thou art more curtain show&#39;rs to the to be or not to the wherefore art thou art needs to the ... Iteration: 1800, Epoch: 10, Batch: 171 out of 182, Loss: 5.71 thou art more than a to be or not to be wherefore art thou dost wedded not make me a Iteration: 1810, Epoch: 10, Batch: 181 out of 182, Loss: 5.56 Here is a plot of the training loss across the iterations. 123456# Plot loss over timeplt.plot(train_loss, 'k-')plt.title('Sequence to Sequence Loss')plt.xlabel('Iterations')plt.ylabel('Loss')plt.show()]]></content>
      <categories>
        <category>深度学习</category>
        <category>循环神经网络</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[中文序列标注]]></title>
    <url>%2F2018%2F11%2F27%2F%E4%B8%AD%E6%96%87%E5%BA%8F%E5%88%97%E6%A0%87%E6%B3%A8%2F</url>
    <content type="text"><![CDATA[TensorFlow Bi-LSTM实现序列标注 BERT-for-Sequence-Labeling-and-Text-Classification]]></content>
      <categories>
        <category>实验</category>
      </categories>
      <tags>
        <tag>序列标注</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[BERT Pre-training of Deep Bidirectional Transformers for Language Understanding]]></title>
    <url>%2F2018%2F11%2F27%2FBidirectional_Encoder_Representations_Transformers%2F</url>
    <content type="text"><![CDATA[本文介绍了一种新的语言表征模型 BERT——来自 Transformer 的双向编码器表征。与最近的语言表征模型不同，BERT 旨在基于所有层的左、右语境来预训练深度双向表征。BERT 是首个在大批句子层面和 token 层面任务中取得当前最优性能的基于微调的表征模型，其性能超越许多使用任务特定架构的系统，刷新了 11 项 NLP 任务的当前（2018年）最优性能记录。 推荐动手实战 Entity-Relation-Extraction，基于TensorFlow和BERT的管道式实体及关系抽取，2019语言与智能技术竞赛信息抽取任务解决方案。 BERT 论文内容精要 推荐结合 BERT论文 全文中译 阅读 模型结构其中的主要模块 Transformer 来自 Attention Is All You Need 模型输入 预训练方法遮蔽语言模型（完形填空）和预测下一句任务。 实验 模型分析Effect of Pre-training Tasks Effect of Model Size Effect of Number of Training Steps Feature-based Approach with BERT 结论Recent empirical improvements due to transfer learning with language models have demonstrated that rich, unsupervised pre-training is an integral part of many language understanding systems. Inparticular, these results enable even low-resource tasks to benefit from very deep unidirectional architectures.Our major contribution is further generalizing these findings to deep bidirectional architectures, allowing the same pre-trained model to successfully tackle a broad set of NLP tasks. While the empirical results are strong, in some cases surpassing human performance, important future work is to investigate the linguistic phenomena that may or may not be captured by BERT. BERT 论文解析 标题 说明 附加 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding 原始论文 20181011 Reddit 讨论 作者讨论 BERT-pytorch Google AI 2018 BERT pytorch implementation 论文解读:BERT模型及fine-tuning 习翔宇 论文解读 最强NLP预训练模型！谷歌BERT横扫11项NLP任务记录 论文浅析 【NLP】Google BERT详解 李入魔 解读 如何评价 BERT 模型？ 解读论文思想点 NLP突破性成果 BERT 模型详细解读 章鱼小丸子 解读 谷歌最强 NLP 模型 BERT 解读 AI科技评论 预训练BERT，官方代码发布前他们是这样用TensorFlow解决的 论文复现说明 20181030 谷歌终于开源BERT代码：3 亿参数量，机器之心全面解读 20181101 为什么说 Bert 大力出奇迹？ 20181121 从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 张俊林 20181111 BERT fine-tune 实践终极教程 BERT在中文数据集上的fine tune全攻略 20181123 BERT在极小数据下带来显著提升的开源实现 张俊 20181127 Use google BERT to do CoNLL-2003 NER ! kyzhouhzau 201810 图解BERT模型：从零开始构建BERT 20190130 Why BERT has 3 Embedding Layers and Their Implementation Details 详解BERT的嵌入层输入构成，包括词Token 、Segment 和 Position 嵌入 20190219 BERT实战（源码分析+踩坑） 20190309 Bert时代的创新：Bert应用模式比较及其它 和 Bert时代的创新（应用篇）：Bert在NLP各领域的应用进展 张俊林，综述从BERT 诞生到20190609时的发展 20190609 一文读懂BERT(原理篇) 20191027 BERT: Pre-training of Deep Bidirectional Transformers for Language UnderstandingJacob Devlin, Ming-Wei Chang, Kenton Lee, Kristina Toutanova(Submitted on 11 Oct 2018) We introduce a new language representation model called BERT, which stands for Bidirectional Encoder Representations from Transformers. Unlike recent language representation models, BERT is designed to pre-train deep bidirectional representations by jointly conditioning on both left and right context in all layers. As a result, the pre-trained BERT representations can be fine-tuned with just one additional output layer to create state-of-the-art models for a wide range of tasks, such as question answering and language inference, without substantial task-specific architecture modifications.BERT is conceptually simple and empirically powerful. It obtains new state-of-the-art results on eleven natural language processing tasks, including pushing the GLUE benchmark to 80.4% (7.6% absolute improvement), MultiNLI accuracy to 86.7 (5.6% absolute improvement) and the SQuAD v1.1 question answering Test F1 to 93.2 (1.5% absolute improvement), outperforming human performance by 2.0%.Comments: 13 pages 摘要：本文介绍了一种新的语言表征模型 BERT，意为来自 Transformer 的双向编码器表征（Bidirectional Encoder Representations from Transformers）。与最近的语言表征模型（Peters et al., 2018; Radford et al., 2018）不同，BERT 旨在基于所有层的左、右语境来预训练深度双向表征。因此，预训练的 BERT 表征可以仅用一个额外的输出层进行微调，进而为很多任务（如问答和语言推断任务）创建当前最优模型，无需对任务特定架构做出大量修改。 BERT 的概念很简单，但实验效果很强大。它刷新了 11 个 NLP 任务的当前最优结果，包括将 GLUE 基准提升至 80.4%（7.6% 的绝对改进）、将 MultiNLI 的准确率提高到 86.7%（5.6% 的绝对改进），以及将 SQuAD v1.1 的问答测试 F1 得分提高至 93.2 分（提高 1.5 分）——比人类表现还高出 2 分。 Subjects: Computation and Language (cs.CL)Cite as: arXiv:1810.04805 [cs.CL] (or arXiv:1810.04805v1 [cs.CL] for this version)Bibliographic dataSelect data provider: Semantic Scholar [Disable Bibex(What is Bibex?)]No data available yetSubmission historyFrom: Jacob Devlin [view email][v1] Thu, 11 Oct 2018 00:50:01 GMT (227kb,D) Reddit 讨论 官方复现 google-research bert 最近谷歌发布了基于双向 Transformer 的大规模预训练语言模型，该预训练模型能高效抽取文本信息并应用于各种 NLP 任务，该研究凭借预训练模型刷新了 11 项 NLP 任务的当前最优性能记录。如果这种预训练方式能经得起实践的检验，那么各种 NLP 任务只需要少量数据进行微调就能实现非常好的效果，BERT 也将成为一种名副其实的骨干网络。 除了官方复现 google-research bert，就推荐更加方便易用的huggingface/transformers IntroductionBERT, or Bidirectional Encoder Representations fromTransformers, is a new method of pre-training language representations whichobtains state-of-the-art results on a wide array of Natural Language Processing(NLP) tasks. Our academic paper which describes BERT in detail and provides full results on anumber of tasks can be found here:https://arxiv.org/abs/1810.04805. To give a few numbers, here are the results on theSQuAD v1.1 question answeringtask: SQuAD v1.1 Leaderboard (Oct 8th 2018) Test EM Test F1 1st Place Ensemble - BERT 87.4 93.2 2nd Place Ensemble - nlnet 86.0 91.7 1st Place Single Model - BERT 85.1 91.8 2nd Place Single Model - nlnet 83.5 90.1 And several natural language inference tasks: System MultiNLI Question NLI SWAG BERT 86.7 91.1 86.3 OpenAI GPT (Prev. SOTA) 82.2 88.1 75.0 Plus many other tasks. Moreover, these results were all obtained with almost no task-specific neuralnetwork architecture design. If you already know what BERT is and you just want to get started, you candownload the pre-trained models andrun a state-of-the-art fine-tuning in only a fewminutes. BERT的数据集 GLUEGLUE 来自论文 GLUE: A Multi-Task Benchmark and Analysis Platform for Natural Language Understanding 摘要 For natural language understanding (NLU) technology to be maximally useful, both practically and as a scientific object of study, it must be general: it must be able to process language in a way that is not exclusively tailored to any one specific task or dataset. In pursuit of this objective, we introduce the General Language Understanding Evaluation benchmark (GLUE), a tool for evaluating and analyzing the performance of models across a diverse range of existing NLU tasks. GLUE is model-agnostic, but it incentivizes sharing knowledge across tasks because certain tasks have very limited training data. We further provide a hand-crafted diagnostic test suite that enables detailed linguistic analysis of NLU models. We evaluate baselines based on current methods for multi-task and transfer learning and find that they do not immediately give substantial improvements over the aggregate performance of training a separate model per task, indicating room for improvement in developing general and robust NLU systems. 解析BERT中的 Transformer 的注意力机制 标题 说明 时间 用可视化解构BERT，我们从上亿参数中提取出了6种直观模式 通过图解BERT中的注意力权重分析BERT的学习模式 20190121 Deconstructing BERT: Distilling 6 Patterns from 100 Million Parameters 用可视化解构BERT，我们从上亿参数中提取出了6种直观模式 原文 20181219 Deconstructing BERT, Part 2: Visualizing the Inner Workings of Attention 用可视化解构BERT，我们从上亿参数中提取出了6种直观模式 原文 20190108 Attention isn’t all you need！BERT的力量之源远不止注意力 本文尝试从自然语言理解的角度解释 BERT 的强大能力。作者指出Transformer不只有注意力（解析），还注重组合，而解析and组合正是自然语言理解的框架。 20190305 Tensor2Tensor有一个很好的工具，可用于可视化Transformer 模型中的注意力模式。因此我修改了一下，直接用在BERT的一个pytorch版本上。修改后的界面如下所示。你可以直接在这个 Colab notebook里运行，或在 Github 上找到源码。 一个新的可视化工具将展示BERT如何形成其独特的注意力模式。 注意力解释2-1 3-5 6-11 4-5 层数 注意力头 特征 2 1 关注句中下一个词语 3 5 关注句中上一个词语 4 5 关注句中短语结构 6 11 关注句中上一个词语 意外的是，我们发现了一个似乎在真正执行共指消解的注意力头（第六层的注意力头 #0）。此外，正如文章《Understanding BERT Part 2: BERT Specifics》中提到的，一些注意力头似乎为每个单词提供全局上下文（第 0 层的注意力头 #0）。第六层的注意力头 #0 中发生的共指消解。 每个单词都会关注该句中所有其它的单词。这可能为每个单词创建一个粗略的上下文语境。 BERT的未来发展BERT 在中文自然语言处理中应用https://github.com/yumath/bertNERhttps://github.com/Hoiy/berserkerhttps://github.com/GhibliField/Multiclass-Text-Classification-using-BERThttps://github.com/lonePatient/BERT-chinese-text-classification-pytorch 后BERT时代：15个预训练模型对比分析与关键点探索参见 nlp中的预训练语言模型总结(单向模型、BERT系列模型、XLNet) 除了官方复现 google-research bert，就推荐更加方便易用集成了BERT各种改进版本的huggingface/transformers。 BERT 新发展ACL 2020 用BERT解决表格问答任务 论文 TAPAS: Weakly Supervised Table Parsing via Pre-training 代码 https://github.com/google-research/tapas 解析 中文 英文]]></content>
      <categories>
        <category>论文</category>
        <category>语言模型</category>
      </categories>
      <tags>
        <tag>BERT</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[待读One Billion Word Benchmark for Measuring Progress in Statistical Language Modeling]]></title>
    <url>%2F2018%2F11%2F27%2FOne%20Billion%20Word%20Benchmark%20for%20Measuring%20Progress%20in%20Statistical%20Language%20Modeling%2F</url>
    <content type="text"><![CDATA[One Billion Word Benchmark for Measuring Progress in Statistical Language ModelingCiprian Chelba, Tomas Mikolov, Mike Schuster, Qi Ge, Thorsten Brants, Phillipp Koehn, Tony Robinson(Submitted on 11 Dec 2013 (v1), last revised 4 Mar 2014 (this version, v3)) We propose a new benchmark corpus to be used for measuring progress in statistical language modeling. With almost one billion words of training data, we hope this benchmark will be useful to quickly evaluate novel language modeling techniques, and to compare their contribution when combined with other advanced techniques. We show performance of several well-known types of language models, with the best results achieved with a recurrent neural network based language model. The baseline unpruned Kneser-Ney 5-gram model achieves perplexity 67.6; a combination of techniques leads to 35% reduction in perplexity, or 10% reduction in cross-entropy (bits), over that baseline.The benchmark is available as a code.google.com project; besides the scripts needed to rebuild the training/held-out data, it also makes available log-probability values for each word in each of ten held-out data sets, for each of the baseline n-gram models. Comments: Accompanied by a code.google.com project allowing anyone to generate the benchmark data, and use it to compare their language model against the ones described in the paperSubjects: Computation and Language (cs.CL)Cite as: arXiv:1312.3005 [cs.CL] (or arXiv:1312.3005v3 [cs.CL] for this version) Language Model on One Billion Word BenchmarkAuthors: Oriol Vinyals (vinyals@google.com, github: OriolVinyals),Xin Pan Paper Authors: Rafal Jozefowicz, Oriol Vinyals, Mike Schuster, Noam Shazeer, Yonghui Wu TL;DR This is a pretrained model on One Billion Word Benchmark.If you use this model in your publication, please cite the original paper: @article{jozefowicz2016exploring, title={Exploring the Limits of Language Modeling}, author={Jozefowicz, Rafal and Vinyals, Oriol and Schuster, Mike and Shazeer, Noam and Wu, Yonghui}, journal={arXiv preprint arXiv:1602.02410}, year={2016}} Introduction In this release, we open source a model trained on the One Billion WordBenchmark (http://arxiv.org/abs/1312.3005), a large language corpus in Englishwhich was released in 2013. This dataset contains about one billion words, andhas a vocabulary size of about 800K words. It contains mostly news data. Sincesentences in the training set are shuffled, models can ignore the context andfocus on sentence level language modeling. In the original release and subsequent work, people have used the same test setto train models on this dataset as a standard benchmark for language modeling.Recently, we wrote an article (http://arxiv.org/abs/1602.02410) describing amodel hybrid between character CNN, a large and deep LSTM, and a specificSoftmax architecture which allowed us to train the best model on this datasetthus far, almost halving the best perplexity previously obtained by others. Code Release The open-sourced components include: TensorFlow GraphDef proto buffer text file. TensorFlow pre-trained checkpoint shards. Code used to evaluate the pre-trained model. Vocabulary file. Test set from LM-1B evaluation. The code supports 4 evaluation modes: Given provided dataset, calculate the model’s perplexity. Given a prefix sentence, predict the next words. Dump the softmax embedding, character-level CNN word embeddings. Give a sentence, dump the embedding from the LSTM state. Results Model Test Perplexity Number of Params [billions] Sigmoid-RNN-2048 [Blackout] 68.3 4.1 Interpolated KN 5-gram, 1.1B n-grams [chelba2013one] 67.6 1.76 Sparse Non-Negative Matrix LM [shazeer2015sparse] 52.9 33 RNN-1024 + MaxEnt 9-gram features [chelba2013one] 51.3 20 LSTM-512-512 54.1 0.82 LSTM-1024-512 48.2 0.82 LSTM-2048-512 43.7 0.83 LSTM-8192-2048 (No Dropout) 37.9 3.3 LSTM-8192-2048 (50\% Dropout) 32.2 3.3 2-Layer LSTM-8192-1024 (BIG LSTM) 30.6 1.8 (THIS RELEASE) BIG LSTM+CNN Inputs 30.0 1.04 How To Run Prerequisites: Install TensorFlow. Install Bazel. Download the data files: Model GraphDef file:link Model Checkpoint sharded file:123456789101112 Vocabulary file:link test dataset: linklink It is recommended to run on a modern desktop instead of a laptop. 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091# 1. Clone the code to your workspace.# 2. Download the data to your workspace.# 3. Create an empty WORKSPACE file in your workspace.# 4. Create an empty output directory in your workspace.# Example directory structure below:$ ls -R.:data lm_1b output WORKSPACE./data:ckpt-base ckpt-lstm ckpt-softmax1 ckpt-softmax3 ckpt-softmax5ckpt-softmax7 graph-2016-09-10.pbtxt vocab-2016-09-10.txtckpt-char-embedding ckpt-softmax0 ckpt-softmax2 ckpt-softmax4 ckpt-softmax6ckpt-softmax8 news.en.heldout-00000-of-00050./lm_1b:BUILD data_utils.py lm_1b_eval.py README.md./output:# Build the codes.$ bazel build -c opt lm_1b/...# Run sample mode:$ bazel-bin/lm_1b/lm_1b_eval --mode sample \ --prefix "I love that I" \ --pbtxt data/graph-2016-09-10.pbtxt \ --vocab_file data/vocab-2016-09-10.txt \ --ckpt 'data/ckpt-*'...(omitted some TensorFlow output)I loveI love thatI love that II love that I findI love that I find thatI love that I find that amazing...(omitted)# Run eval mode:$ bazel-bin/lm_1b/lm_1b_eval --mode eval \ --pbtxt data/graph-2016-09-10.pbtxt \ --vocab_file data/vocab-2016-09-10.txt \ --input_data data/news.en.heldout-00000-of-00050 \ --ckpt 'data/ckpt-*'...(omitted some TensorFlow output)Loaded step 14108582.# perplexity is high initially because words without context are harder to# predict.Eval Step: 0, Average Perplexity: 2045.512297.Eval Step: 1, Average Perplexity: 229.478699.Eval Step: 2, Average Perplexity: 208.116787.Eval Step: 3, Average Perplexity: 338.870601.Eval Step: 4, Average Perplexity: 228.950107.Eval Step: 5, Average Perplexity: 197.685857.Eval Step: 6, Average Perplexity: 156.287063.Eval Step: 7, Average Perplexity: 124.866189.Eval Step: 8, Average Perplexity: 147.204975.Eval Step: 9, Average Perplexity: 90.124864.Eval Step: 10, Average Perplexity: 59.897914.Eval Step: 11, Average Perplexity: 42.591137....(omitted)Eval Step: 4529, Average Perplexity: 29.243668.Eval Step: 4530, Average Perplexity: 29.302362.Eval Step: 4531, Average Perplexity: 29.285674....(omitted. At convergence, it should be around 30.)# Run dump_emb mode:$ bazel-bin/lm_1b/lm_1b_eval --mode dump_emb \ --pbtxt data/graph-2016-09-10.pbtxt \ --vocab_file data/vocab-2016-09-10.txt \ --ckpt 'data/ckpt-*' \ --save_dir output...(omitted some TensorFlow output)Finished softmax weightsFinished word embedding 0/793471Finished word embedding 1/793471Finished word embedding 2/793471...(omitted)$ ls output/embeddings_softmax.npy ...# Run dump_lstm_emb mode:$ bazel-bin/lm_1b/lm_1b_eval --mode dump_lstm_emb \ --pbtxt data/graph-2016-09-10.pbtxt \ --vocab_file data/vocab-2016-09-10.txt \ --ckpt 'data/ckpt-*' \ --sentence "I love who I am ." \ --save_dir output$ ls output/lstm_emb_step_0.npy lstm_emb_step_2.npy lstm_emb_step_4.npylstm_emb_step_6.npy lstm_emb_step_1.npy lstm_emb_step_3.npylstm_emb_step_5.npy]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Language Modeling</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[待读Universal Transformers]]></title>
    <url>%2F2018%2F11%2F27%2FUniversal%20Transformers%2F</url>
    <content type="text"><![CDATA[腾讯AI Lab提出翻译改进模型Transformer的3个优化方法 2017 年，谷歌发布了机器学习模型 Transformer，该模型在机器翻译及其他语言理解任务上的表现远远超越了以往算法。今天 2018-08-16，谷歌发布该模型最新版本——Universal Transformer，弥补了在大规模语言理解任务上具有竞争力的实际序列模型与计算通用模型之间的差距，其 BLEU 值比去年的 Transformer 提高了 0.9。在多项有难度的语言理解任务上，Universal Transformer 的泛化效果明显更好，且它在 bAbI 语言推理任务和很有挑战性的 LAMBADA 语言建模任务上达到了新的当前最优性能。 Universal TransformersMostafa Dehghani, Stephan Gouws, Oriol Vinyals, Jakob Uszkoreit, Łukasz Kaiser(Submitted on 10 Jul 2018) Self-attentive feed-forward sequence models have been shown to achieve impressive results on sequence modeling tasks, thereby presenting a compelling alternative to recurrent neural networks (RNNs) which has remained the de-facto standard architecture for many sequence modeling problems to date. Despite these successes, however, feed-forward sequence models like the Transformer fail to generalize in many tasks that recurrent models handle with ease (e.g. copying when the string lengths exceed those observed at training time). Moreover, and in contrast to RNNs, the Transformer model is not computationally universal, limiting its theoretical expressivity. In this paper we propose the Universal Transformer which addresses these practical and theoretical shortcomings and we show that it leads to improved performance on several tasks. Instead of recurring over the individual symbols of sequences like RNNs, the Universal Transformer repeatedly revises its representations of all symbols in the sequence with each recurrent step. In order to combine information from different parts of a sequence, it employs a self-attention mechanism in every recurrent step. Assuming sufficient memory, its recurrence makes the Universal Transformer computationally universal. We further employ an adaptive computation time (ACT) mechanism to allow the model to dynamically adjust the number of times the representation of each position in a sequence is revised. Beyond saving computation, we show that ACT can improve the accuracy of the model. Our experiments show that on various algorithmic tasks and a diverse set of large-scale language understanding tasks the Universal Transformer generalizes significantly better and outperforms both a vanilla Transformer and an LSTM in machine translation, and achieves a new state of the art on the bAbI linguistic reasoning task and the challenging LAMBADA language modeling task. 自注意力前馈序列模型已被证明在序列建模任务上效果显著，这些任务包括机器翻译 [31]、图像生成 [30] 和 constituency parsing [18]，从而提供了可以替代循环神经网络（RNN）的令人信服的方案，尽管 RNN 至今仍是许多序列建模问题事实上的标准架构。然而，尽管取得了这些成功，像 Transformer [31] 这样的前馈序列模型却无法泛化至很多循环模型可以轻松处理的任务上（例如，在字符串或公式长度超过训练时模型观察到的类型时，复制字符串甚至简单的逻辑推断 [28]）。此外，与 RNN 相比，Transformer 模型在计算上不通用，这限制了其理论表达能力。本论文提出了 Universal Transformer，它可以解决这些实践和理论缺陷。我们展示了它可以在多项任务中实现性能提升。Universal Transformer 不像 RNN 那样使用对句中单个符号的循环，而是使用每个循环步骤重复修改句子中所有符号的表征。为了结合句子不同部分的信息，该模型在每个循环步中都使用了自注意力机制。假设有充足的记忆，则其循环会使 Universal Transformer 成为计算通用模型。我们进一步使用自适应计算时间（adaptive computation time，ACT）机制，使模型动态调整句子中每个位置的表征被修改的次数。除了节省计算量以外，ACT 还能够提高模型的准确率。我们的实验结果表明，在许多算法任务及大量大规模语言理解任务中，Universal Transformer 的泛化性能大大增强，在机器翻译中的表现超越了基础 Transformer 及 LSTM，在 bAbI 语言推理及富有挑战性的 LAMBADA 语言建模任务中达到了新的当前最优性能。 Subjects: Computation and Language (cs.CL); Machine Learning (cs.LG); Machine Learning (stat.ML)Cite as: arXiv:1807.03819 [cs.CL] (or arXiv:1807.03819v1 [cs.CL] for this version) 标题 说明 附加 Universal Transformers 论文原文 20180710 Universal Transformer 代码 谷歌的机器翻译模型 Transformer，现在可以用来做任何事了 20180816]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Transformers</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Efficient Estimation of Word Representations in Vector Space]]></title>
    <url>%2F2018%2F11%2F27%2FEfficient%20Estimation%20of%20Word%20Representations%20in%20Vector%20Space%2F</url>
    <content type="text"><![CDATA[Efficient Estimation of Word Representations in Vector SpaceTomas Mikolov, Kai Chen, Greg Corrado, Jeffrey Dean(Submitted on 16 Jan 2013 (v1), last revised 7 Sep 2013 (this version, v3)) We propose two novel model architectures for computing continuous vector representations of words from very large data sets. The quality of these representations is measured in a word similarity task, and the results are compared to the previously best performing techniques based on different types of neural networks. We observe large improvements in accuracy at much lower computational cost, i.e. it takes less than a day to learn high quality word vectors from a 1.6 billion words data set. Furthermore, we show that these vectors provide state-of-the-art performance on our test set for measuring syntactic and semantic word similarities. Subjects: Computation and Language (cs.CL)Cite as: arXiv:1301.3781 [cs.CL] (or arXiv:1301.3781v3 [cs.CL] for this version) 标题 说明 附加 Efficient Estimation of Word Representations in Vector Space 论文原文 20130116 TensorFlow学习笔记3：词向量 论文解读 20160316]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Embedding</tag>
        <tag>word2vector</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[tensorflow cookbook 自然语言处理]]></title>
    <url>%2F2018%2F11%2F26%2Ftensorflow_cookbook_%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86%2F</url>
    <content type="text"><![CDATA[Natural Language ProcessingUp to this point, we have only considered machine learning algorithms that mostly operate on numerical inputs. If we want to use text, we must find a way to convert the text into numbers. There are many ways to do this and we will explore a few common ways this is achieved.” If we consider the sentence “tensorflow makes machine learning easy”, we could convert the words to numbers in the order that we observe them. This would make the sentence become “1 2 3 4 5”. Then when we see a new sentence, “machine learning is easy”, we can translate this as “3 4 0 5”. Denoting words we haven’t seen bore with an index of zero. With these two examples, we have limited our vocabulary to 6 numbers. With large texts we can choose how many words we want to keep, and usually keep the most frequent words, labeling everything else with the index of zero. If the word “learning” has a numerical value of 4, and the word “makes” has a numerical value of 2, then it would be natural to assume that “learning” is twice “makes”. Since we do not want this type of numerical relationship between words, we assume these numbers represent categories and not relational numbers. Another problem is that these two sentences are of different size. Each observation we make (sentences in this case) need to have the same size input to a model we wish to create. To get around this, we create each sentence into a sparse vector that has that value of one in a specific index if that word occurs in that index. Natural Language Processing (NLP) IntroductionIn this chapter we cover the following topics: Working with Bag of Words Implementing TF-IDF Working with Skip-gram Embeddings Working with CBOW Embeddings Making Predictions with Word2vec Using Doc2vec for Sentiment Analysis Up to this point, we have only considered machine learning algorithms that mostly operate on numerical inputs. If we want to use text, we must find a way to convert the text into numbers. There are many ways to do this and we will explore a few common ways this is achieved. If we consider the sentence “tensorflow makes machine learning easy”, we could convert the words to numbers in the order that we observe them. This would make the sentence become “1 2 3 4 5”. Then when we see a new sentence, “machine learning is easy”, we can translate this as “3 4 0 5”. Denoting words we haven’t seen bore with an index of zero. With these two examples, we have limited our vocabulary to 6 numbers. With large texts we can choose how many words we want to keep, and usually keep the most frequent words, labeling everything else with the index of zero. If the word “learning” has a numerical value of 4, and the word “makes” has a numerical value of 2, then it would be natural to assume that “learning” is twice “makes”. Since we do not want this type of numerical relationship between words, we assume these numbers represent categories and not relational numbers.Another problem is that these two sentences are of different size. Each observation we make (sentences in this case) need to have the same size input to a model we wish to create. To get around this, we create each sentence into a sparse vector that has that value of one in a specific index if that word occurs in that index. word —&gt; tensorflow makes machine learning easy word index —&gt; 1 2 3 4 5 The occurrence vector would then be: sentence1 = [0, 1, 1, 1, 1, 1] This is a vector of length 6 because we have 5 words in our vocabulary and we reserve the 0-th index for unknown or rare words Now consider the sentence, ‘machine learning is easy’. word —&gt; machine learning is easy word index —&gt; 3 4 0 5 The occurrence vector for this sentence is now: sentence2 = [1, 0, 0, 1, 1, 1] Notice that we now have a procedure that converts any sentence to a fixed length numerical vector. A disadvantage to this method is that we lose any indication of word order. The two sentences “tensorflow makes machine learning easy” and “machine learning makes tensorflow easy” would result in the same sentence vector.It is also worthwhile to note that the length of these vectors is equal to the size of our vocabulary that we pick.It is common to pick a very large vocabulary, so these sentence vectors can be very sparse. This type of embedding that we have covered in this introduction is called “bag of words”. We will implement this in the next section. Another drawback is that the words “is” and “tensorflow” have the same numerical index value of one. We can imagine that the word “is” might be less important that the occurrence of the word “tensorflow”.We will explore different types of embeddings in this chapter that attempt to address these ideas, but first we start with an implementation of bag of words. Working with Bag of WordsIn this example, we will download and preprocess the ham/spam text data. We will then use a one-hot-encoding to make a bag of words set of features to use in logistic regression. We will use these one-hot-vectors for logistic regression to predict if a text is spam or ham. We start by loading the necessary libraries. 123456789101112import tensorflow as tfimport matplotlib.pyplot as pltimport osimport numpy as npimport csvimport stringimport requestsimport iofrom zipfile import ZipFilefrom tensorflow.contrib import learnfrom tensorflow.python.framework import opsops.reset_default_graph() We start a computation graph session. 12# Start a graph sessionsess = tf.Session() Check if data was downloaded, otherwise download it and save for future use 12345678910111213141516171819202122232425262728293031save_file_name = os.path.join('temp','temp_spam_data.csv')# Create directory if it doesn't existif not os.path.exists('temp'): os.makedirs('temp')if os.path.isfile(save_file_name): text_data = [] with open(save_file_name, 'r') as temp_output_file: reader = csv.reader(temp_output_file) for row in reader: if len(row)==2: text_data.append(row)else: zip_url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/00228/smsspamcollection.zip' r = requests.get(zip_url) z = ZipFile(io.BytesIO(r.content)) file = z.read('SMSSpamCollection') # Format Data text_data = file.decode() text_data = text_data.encode('ascii',errors='ignore') text_data = text_data.decode().split('\n') text_data = [x.split('\t') for x in text_data if len(x)&gt;=1] # And write to csv with open(save_file_name, 'w') as temp_output_file: writer = csv.writer(temp_output_file) writer.writerows(text_data)texts = [x[1] for x in text_data]target = [x[0] for x in text_data] To reduce the potential vocabulary size, we normalize the text. To do this, we remove the influence of capitalization and numbers in the text. 123456789101112131415# Relabel 'spam' as 1, 'ham' as 0target = [1 if x=='spam' else 0 for x in target]# Normalize text# Lower casetexts = [x.lower() for x in texts]# Remove punctuationtexts = [''.join(c for c in x if c not in string.punctuation) for x in texts]# Remove numberstexts = [''.join(c for c in x if c not in '0123456789') for x in texts]# Trim extra whitespacetexts = [' '.join(x.split()) for x in texts] To determine a good sentence length to pad/crop at, we plot a histogram of text lengths (in words). 1234567%matplotlib inline# Plot histogram of text lengthstext_lengths = [len(x.split()) for x in texts]text_lengths = [x for x in text_lengths if x &lt; 50]plt.hist(text_lengths, bins=25)plt.title('Histogram of # of Words in Texts')plt.show() We crop/pad all texts to be 25 words long. We also will filter out any words that do not appear at least 3 times. 123# Choose max text word length at 25sentence_size = 25min_word_freq = 3 TensorFlow has a built in text processing function called VocabularyProcessor(). We use this function to process the texts. 1234567# Setup vocabulary processorvocab_processor = learn.preprocessing.VocabularyProcessor(sentence_size, min_frequency=min_word_freq)# Have to fit transform to get length of unique words.vocab_processor.transform(texts)transformed_texts = np.array([x for x in vocab_processor.transform(texts)])embedding_size = len(np.unique(transformed_texts)) To test our logistic model (predicting spam/ham), we split the texts into a train and test set. 1234567# Split up data set into train/testtrain_indices = np.random.choice(len(texts), round(len(texts)*0.8), replace=False)test_indices = np.array(list(set(range(len(texts))) - set(train_indices)))texts_train = [x for ix, x in enumerate(texts) if ix in train_indices]texts_test = [x for ix, x in enumerate(texts) if ix in test_indices]target_train = [x for ix, x in enumerate(target) if ix in train_indices]target_test = [x for ix, x in enumerate(target) if ix in test_indices] For one-hot-encoding, we setup an identity matrix for the TensorFlow embedding lookup. We also create the variables and placeholders for the logistic regression we will perform. 12345678910# Setup Index Matrix for one-hot-encodingidentity_mat = tf.diag(tf.ones(shape=[embedding_size]))# Create variables for logistic regressionA = tf.Variable(tf.random_normal(shape=[embedding_size,1]))b = tf.Variable(tf.random_normal(shape=[1,1]))# Initialize placeholdersx_data = tf.placeholder(shape=[sentence_size], dtype=tf.int32)y_target = tf.placeholder(shape=[1, 1], dtype=tf.float32) Next, we create the text-word embedding lookup with the prior identity matrix. Our logistic regression will use the counts of the words as the input. The counts are created by summing the embedding output across the rows. Then we declare the logistic regression operations. Note that we do not wrap the logistic operations in the sigmoid function because this will be done in the loss function later on. 1234567# Text-Vocab Embeddingx_embed = tf.nn.embedding_lookup(identity_mat, x_data)x_col_sums = tf.reduce_sum(x_embed, 0)# Declare model operationsx_col_sums_2D = tf.expand_dims(x_col_sums, 0)model_output = tf.add(tf.matmul(x_col_sums_2D, A), b) Now we declare our loss function (which has the sigmoid built in), prediction operations, optimizer, and initialize the variables. 12345678910111213# Declare loss function (Cross Entropy loss)loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=model_output, labels=y_target))# Prediction operationprediction = tf.sigmoid(model_output)# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.001)train_step = my_opt.minimize(loss)# Intitialize Variablesinit = tf.global_variables_initializer()sess.run(init) Now we loop through the iterations and fit the logistic regression on wether or not the text is spam or ham. 123456789101112131415161718192021222324# Start Logistic Regressionprint('Starting Training Over &#123;&#125; Sentences.'.format(len(texts_train)))loss_vec = []train_acc_all = []train_acc_avg = []for ix, t in enumerate(vocab_processor.fit_transform(texts_train)): y_data = [[target_train[ix]]] sess.run(train_step, feed_dict=&#123;x_data: t, y_target: y_data&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: t, y_target: y_data&#125;) loss_vec.append(temp_loss) if (ix+1)%50==0: print('Training Observation #' + str(ix+1) + ': Loss = ' + str(temp_loss)) # Keep trailing average of past 50 observations accuracy # Get prediction of single observation [[temp_pred]] = sess.run(prediction, feed_dict=&#123;x_data:t, y_target:y_data&#125;) # Get True/False if prediction is accurate train_acc_temp = target_train[ix]==np.round(temp_pred) train_acc_all.append(train_acc_temp) if len(train_acc_all) &gt;= 50: train_acc_avg.append(np.mean(train_acc_all[-50:])) Starting Training Over 4459 Sentences. Training Observation #50: Loss = 4.7342416e-14 ... Training Observation #4450: Loss = 3.811978e-11 Now that we have a logistic model, we can evaluate the accuracy on the test dataset. 1234567891011121314151617# Get test set accuracyprint('Getting Test Set Accuracy For &#123;&#125; Sentences.'.format(len(texts_test)))test_acc_all = []for ix, t in enumerate(vocab_processor.fit_transform(texts_test)): y_data = [[target_test[ix]]] if (ix+1)%100==0: print('Test Observation #' + str(ix+1)) # Keep trailing average of past 50 observations accuracy # Get prediction of single observation [[temp_pred]] = sess.run(prediction, feed_dict=&#123;x_data:t, y_target:y_data&#125;) # Get True/False if prediction is accurate test_acc_temp = target_test[ix]==np.round(temp_pred) test_acc_all.append(test_acc_temp)print('\nOverall Test Accuracy: &#123;&#125;'.format(np.mean(test_acc_all))) Getting Test Set Accuracy For 1115 Sentences. Test Observation #100 Test Observation #200 Test Observation #300 Test Observation #400 Test Observation #500 Test Observation #600 Let’s look at the training accuracy over all the iterations. 123456# Plot training accuracy over timeplt.plot(range(len(train_acc_avg)), train_acc_avg, 'k-', label='Train Accuracy')plt.title('Avg Training Acc Over Past 50 Iterations')plt.xlabel('Iterations')plt.ylabel('Training Accuracy')plt.show() It is worthwhile to mention the motivation of limiting the sentence (or text) size. In this example we limited the text size to 25 words. This is a common practice with bag of words because it limits the effect of text length on the prediction. You can imagine that if we find a word, “meeting” for example, that is predictive of a text being ham (not spam), then a spam message might get through by putting in many occurrences of that word at the end. In fact, this is a common problem with imbalanced target data. Imbalanced data might occur in this situation, since spam may be hard to find and ham may be easy to find. Because of this fact, our vocabulary that we create might be heavily skewed toward words represented in the ham part of our data (more ham means more words are represented in ham than spam). If we allow unlimited length of texts, then spammers might take advantage of this and create very long texts, which have a higher probability of triggering non-spam word factors in our logistic model. In the next section, we attempt to tackle this problem in a better way using the frequency of word occurrence to determine the values of the word embeddings. Implementing TF-IDFTF-IDF is an acronym that stands for Text Frequency – Inverse Document Frequency. This term is essentially the product of text frequency and inverse document frequency for each word. In the prior recipe, we introduced the bag of words methodology, which assigned a value of one for every occurrence of a word in a sentence. This is probably not ideal as each category of sentence (spam and ham for the prior recipe example) most likely has the same frequency of “the”, “and” and other words, whereas words like “viagra” and “sale” probably should have increased importance in figuring out whether or not the text is spam. We first want to take into consideration the word frequency. Here we consider the frequency that a word occurs in an individual entry. The purpose of this part (TF), is to find terms that appear to be important in each entry. But words like “the” and “and” may appear very frequently in every entry. We want to down weight the importance of these words, so we can imagine that multiplying the above text frequency (TF) by the inverse of the whole document frequency might help find important words. But since a collection of texts (a corpus) may be quite large, it is common to take the logarithm of the inverse document frequency. This leaves us with the following formula for TF-IDF for each word in each document entry. w_{tf-idf}=w_{tf} \cdot \frac{1}{log(w_{df})}Where $w_{tf}$ is the word frequency by document, and $w_{df}$ is the total frequency of such word across all documents. We can imagine that high values of TF-IDF might indicate words that are very important to determining what a document is about. Here we implement TF-IDF, (Text Frequency - Inverse Document Frequency) for the spam-ham text data. We will use a hybrid approach of encoding the texts with sci-kit learn’s TFIDF vectorizer. Then we will use the regular TensorFlow logistic algorithm outline. Creating the TF-IDF vectors requires us to load all the text into memory and count the occurrences of each word before we can start training our model. Because of this, it is not implemented fully in Tensorflow, so we will use Scikit-learn for creating our TF-IDF embedding, but use Tensorflow to fit the logistic model. We start by loading the necessary libraries. 12345678910111213import tensorflow as tfimport matplotlib.pyplot as pltimport csvimport numpy as npimport osimport stringimport requestsimport ioimport nltkfrom zipfile import ZipFilefrom sklearn.feature_extraction.text import TfidfVectorizerfrom tensorflow.python.framework import opsops.reset_default_graph() Start a computational graph session. 1sess = tf.Session() We set two parameters, batch_size and max_features. batch_size is the size of the batch we will train our logistic model on, and max_features is the maximum number of tf-idf textual words we will use in our logistic regression. 12batch_size = 200max_features = 1000 Check if data was downloaded, otherwise download it and save for future use 12345678910111213141516171819202122save_file_name = 'temp_spam_data.csv'if os.path.isfile(save_file_name): text_data = [] with open(save_file_name, 'r') as temp_output_file: reader = csv.reader(temp_output_file) for row in reader: text_data.append(row)else: zip_url = 'http://archive.ics.uci.edu/ml/machine-learning-databases/00228/smsspamcollection.zip' r = requests.get(zip_url) z = ZipFile(io.BytesIO(r.content)) file = z.read('SMSSpamCollection') # Format Data text_data = file.decode() text_data = text_data.encode('ascii',errors='ignore') text_data = text_data.decode().split('\n') text_data = [x.split('\t') for x in text_data if len(x)&gt;=1] # And write to csv with open(save_file_name, 'w') as temp_output_file: writer = csv.writer(temp_output_file) writer.writerows(text_data) We now clean our texts. This will decrease our vocabulary size by converting everything to lower case, removing punctuation and getting rid of numbers. 123456789101112131415161718texts = [x[1] for x in text_data]target = [x[0] for x in text_data]# Relabel 'spam' as 1, 'ham' as 0target = [1. if x=='spam' else 0. for x in target]# Normalize text# Lower casetexts = [x.lower() for x in texts]# Remove punctuationtexts = [''.join(c for c in x if c not in string.punctuation) for x in texts]# Remove numberstexts = [''.join(c for c in x if c not in '0123456789') for x in texts]# Trim extra whitespacetexts = [' '.join(x.split()) for x in texts] Define tokenizer function and create the TF-IDF vectors with SciKit-Learn. 1234567def tokenizer(text): words = nltk.word_tokenize(text) return words# Create TF-IDF of textstfidf = TfidfVectorizer(tokenizer=tokenizer, stop_words='english', max_features=max_features)sparse_tfidf_texts = tfidf.fit_transform(texts) Split up data set into train/test. 1texts[:3] [&#39;go until jurong point crazy available only in bugis n great world la e buffet cine there got amore wat&#39;, &#39;ok lar joking wif u oni&#39;, &#39;free entry in a wkly comp to win fa cup final tkts st may text fa to to receive entry questionstd txt ratetcs apply overs&#39;] 1sparse_tfidf_texts[:3] &lt;3x1000 sparse matrix of type &#39;&lt;class &#39;numpy.float64&#39;&gt;&#39; with 26 stored elements in Compressed Sparse Row format&gt; 123456train_indices = np.random.choice(sparse_tfidf_texts.shape[0], round(0.8*sparse_tfidf_texts.shape[0]), replace=False)test_indices = np.array(list(set(range(sparse_tfidf_texts.shape[0])) - set(train_indices)))texts_train = sparse_tfidf_texts[train_indices]texts_test = sparse_tfidf_texts[test_indices]target_train = np.array([x for ix, x in enumerate(target) if ix in train_indices])target_test = np.array([x for ix, x in enumerate(target) if ix in test_indices]) Now we create the variables and placeholders necessary for logistic regression. After which, we declare our logistic regression operation. Remember that the sigmoid part of the logistic regression will be in the loss function. 12345678910# Create variables for logistic regressionA = tf.Variable(tf.random_normal(shape=[max_features,1]))b = tf.Variable(tf.random_normal(shape=[1,1]))# Initialize placeholdersx_data = tf.placeholder(shape=[None, max_features], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)# Declare logistic model (sigmoid in loss function)model_output = tf.add(tf.matmul(x_data, A), b) Next, we declare the loss function (which has the sigmoid in it), and the prediction function. The prediction function will have to have a sigmoid inside of it because it is not in the model output. 1234567# Declare loss function (Cross Entropy loss)loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=model_output, labels=y_target))# Predictionprediction = tf.round(tf.sigmoid(model_output))predictions_correct = tf.cast(tf.equal(prediction, y_target), tf.float32)accuracy = tf.reduce_mean(predictions_correct) Now we create the optimization function and initialize the model variables. 1234567# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.0025)train_step = my_opt.minimize(loss)# Intitialize Variablesinit = tf.global_variables_initializer()sess.run(init) Finally, we perform our logisitic regression on the 1000 TF-IDF features. 1234567891011121314151617181920212223242526272829train_loss = []test_loss = []train_acc = []test_acc = []i_data = []for i in range(10000): rand_index = np.random.choice(texts_train.shape[0], size=batch_size) rand_x = texts_train[rand_index].todense() rand_y = np.transpose([target_train[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) # Only record loss and accuracy every 100 generations if (i+1)%100==0: i_data.append(i+1) train_loss_temp = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) train_loss.append(train_loss_temp) test_loss_temp = sess.run(loss, feed_dict=&#123;x_data: texts_test.todense(), y_target: np.transpose([target_test])&#125;) test_loss.append(test_loss_temp) train_acc_temp = sess.run(accuracy, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) train_acc.append(train_acc_temp) test_acc_temp = sess.run(accuracy, feed_dict=&#123;x_data: texts_test.todense(), y_target: np.transpose([target_test])&#125;) test_acc.append(test_acc_temp) if (i+1)%500==0: acc_and_loss = [i+1, train_loss_temp, test_loss_temp, train_acc_temp, test_acc_temp] acc_and_loss = [np.round(x,2) for x in acc_and_loss] print('Generation # &#123;&#125;. Train Loss (Test Loss): &#123;:.2f&#125; (&#123;:.2f&#125;). Train Acc (Test Acc): &#123;:.2f&#125; (&#123;:.2f&#125;)'.format(*acc_and_loss)) Generation # 500. Train Loss (Test Loss): 1.07 (1.08). Train Acc (Test Acc): 0.36 (0.35) ... Generation # 9500. Train Loss (Test Loss): 0.39 (0.46). Train Acc (Test Acc): 0.88 (0.85) Generation # 10000. Train Loss (Test Loss): 0.52 (0.46). Train Acc (Test Acc): 0.80 (0.85) Here is matplotlib code to plot the loss and accuracies. 1234567891011121314151617# Plot loss over timeplt.plot(i_data, train_loss, 'k-', label='Train Loss')plt.plot(i_data, test_loss, 'r--', label='Test Loss', linewidth=4)plt.title('Cross Entropy Loss per Generation')plt.xlabel('Generation')plt.ylabel('Cross Entropy Loss')plt.legend(loc='upper right')plt.show()# Plot train and test accuracyplt.plot(i_data, train_acc, 'k-', label='Train Set Accuracy')plt.plot(i_data, test_acc, 'r--', label='Test Set Accuracy', linewidth=4)plt.title('Train and Test Accuracy')plt.xlabel('Generation')plt.ylabel('Accuracy')plt.legend(loc='lower right')plt.show() Word2Vec: Skipgram ModelWorking with Skip Gram Embeddings Prior to this recipe, we have not considered the order of words to be relevant in creating word embeddings. In early 2013, Tomas Mikolov and other researchers at Google authored a paper about creating word embeddings that address this issue (https://arxiv.org/abs/1301.3781), and they named their methods “word2vec”. The basic idea is to create word embeddings that capture a relational aspect of words. We seek to understand how various words are related to each other. Some examples of how these embeddings might behave are as follows. “king” – “man” + “woman” = “queen” “india pale ale” – “hops” + “malt” = “stout” We might achieve such numerical representation of words if we only consider their positional relationship to each other. If we could analyse a large enough source of coherent documents, we might find that the words “king”, “man”, and “queen” are mentioned closely to each other in our texts. If we also know that “man” and “woman” are related in a different way, then we might conclude that “man” is to “king” as “woman” is to “queen” and so on. To go about finding such an embedding, we will use a neural network that predicts surrounding words giving an input word. We could, just as easily, switched that and tried to predict a target word given a set of surrounding words, but we will start with the prior method. Both are variations of the word2vec procedure. But the prior method of predicting the surrounding words (the context) from a target word is called the skip-gram model. In the next recipe, we will implement the other method, predicting the target word from the context, which is called the continuous bag of words method (CBOW). See below figure for an illustration. In this example, we will download and preprocess the movie review data. From this data set we will compute/fit the skipgram model of the Word2Vec Algorithm Skipgram: based on predicting the surrounding words from the Ex sentence “the cat in the hat” context word: [“hat”] target words: [“the”, “cat”, “in”, “the”] context-target pairs: (“hat”, “the”), (“hat”, “cat”), (“hat”, “in”), (“hat”, “the”) We start by loading the necessary libraries. 1234567891011121314import tensorflow as tfimport matplotlib.pyplot as pltimport numpy as npimport randomimport osimport stringimport requestsimport collectionsimport ioimport tarfileimport gzipfrom nltk.corpus import stopwordsfrom tensorflow.python.framework import opsops.reset_default_graph() Start a computational graph session. 1sess = tf.Session() Declare model parameters 12345678batch_size = 100 # How many sets of words to train on at once.embedding_size = 100 # The embedding size of each word to train.vocabulary_size = 5000 # How many words we will consider for training.generations = 100000 # How many iterations we will perform the training on.print_loss_every = 500 # Print the loss every so many iterationsnum_sampled = int(batch_size/2) # Number of negative examples to sample.window_size = 2 # How many words to consider left and right. We will remove stop words and create a test validation set of words. 1234567# Declare stop wordsstops = stopwords.words('english')# We pick five test words. We are expecting synonyms to appearprint_valid_every = 10000valid_words = ['cliche', 'love', 'hate', 'silly', 'sad']# Later we will have to transform these into indices Next, we load the movie review data. We check if the data was downloaded, and not, download and save it. 12345678910111213141516171819202122232425262728293031323334353637383940414243def load_movie_data(): save_folder_name = 'temp' pos_file = os.path.join(save_folder_name, 'rt-polaritydata', 'rt-polarity.pos') neg_file = os.path.join(save_folder_name, 'rt-polaritydata', 'rt-polarity.neg') if not os.path.exists(save_folder_name): os.mkdir(save_folder_name) # Check if files are already downloaded if not os.path.exists(os.path.join(save_folder_name, 'rt-polaritydata')): movie_data_url = 'http://www.cs.cornell.edu/people/pabo/movie-review-data/rt-polaritydata.tar.gz' # Save tar.gz file req = requests.get(movie_data_url, stream=True) with open(os.path.join(save_folder_name,'temp_movie_review_temp.tar.gz'), 'wb') as f: for chunk in req.iter_content(chunk_size=1024): if chunk: f.write(chunk) f.flush() # Extract tar.gz file into temp folder tar = tarfile.open(os.path.join(save_folder_name,'temp_movie_review_temp.tar.gz'), "r:gz") tar.extractall(path='temp') tar.close() pos_data = [] with open(pos_file, 'r', encoding='latin-1') as f: for line in f: pos_data.append(line.encode('ascii',errors='ignore').decode()) f.close() pos_data = [x.rstrip() for x in pos_data] neg_data = [] with open(neg_file, 'r', encoding='latin-1') as f: for line in f: neg_data.append(line.encode('ascii',errors='ignore').decode()) f.close() neg_data = [x.rstrip() for x in neg_data] texts = pos_data + neg_data target = [1]*len(pos_data) + [0]*len(neg_data) return(texts, target)texts, target = load_movie_data() Now we create a function that normalizes/cleans the text. 123456789101112131415161718192021222324# Normalize textdef normalize_text(texts, stops): # Lower case texts = [x.lower() for x in texts] # Remove punctuation texts = [''.join(c for c in x if c not in string.punctuation) for x in texts] # Remove numbers texts = [''.join(c for c in x if c not in '0123456789') for x in texts] # Remove stopwords texts = [' '.join([word for word in x.split() if word not in (stops)]) for x in texts] # Trim extra whitespace texts = [' '.join(x.split()) for x in texts] return(texts)texts = normalize_text(texts, stops)# Texts must contain at least 3 wordstarget = [target[ix] for ix, x in enumerate(texts) if len(x.split()) &gt; 2]texts = [x for x in texts if len(x.split()) &gt; 2] With the normalized movie reviews, we now build a dictionary of words. 1234567891011121314151617181920# Build dictionary of wordsdef build_dictionary(sentences, vocabulary_size): # Turn sentences (list of strings) into lists of words split_sentences = [s.split() for s in sentences] words = [x for sublist in split_sentences for x in sublist] # Initialize list of [word, word_count] for each word, starting with unknown count = [['RARE', -1]] # Now add most frequent words, limited to the N-most frequent (N=vocabulary size) count.extend(collections.Counter(words).most_common(vocabulary_size-1)) # Now create the dictionary word_dict = &#123;&#125; # For each word, that we want in the dictionary, add it, then make it # the value of the prior dictionary length for word, word_count in count: word_dict[word] = len(word_dict) return(word_dict) With the above dictionary, we can turn text data into lists of integers from such dictionary. 12345678910111213141516171819202122def text_to_numbers(sentences, word_dict): # Initialize the returned data data = [] for sentence in sentences: sentence_data = [] # For each word, either use selected index or rare word index for word in sentence.split(' '): if word in word_dict: word_ix = word_dict[word] else: word_ix = 0 sentence_data.append(word_ix) data.append(sentence_data) return(data)# Build our data set and dictionariesword_dictionary = build_dictionary(texts, vocabulary_size)word_dictionary_rev = dict(zip(word_dictionary.values(), word_dictionary.keys()))text_data = text_to_numbers(texts, word_dictionary)# Get validation word keysvalid_examples = [word_dictionary[x] for x in valid_words] Let us now build a function that will generate random data points from our text and parameters. 1234567891011121314151617181920212223242526272829303132333435363738# Generate data randomly (N words behind, target, N words ahead)def generate_batch_data(sentences, batch_size, window_size, method='skip_gram'): # Fill up data batch batch_data = [] label_data = [] while len(batch_data) &lt; batch_size: # select random sentence to start rand_sentence = np.random.choice(sentences) # Generate consecutive windows to look at window_sequences = [rand_sentence[max((ix-window_size),0):(ix+window_size+1)] for ix, x in enumerate(rand_sentence)] # Denote which element of each window is the center word of interest label_indices = [ix if ix&lt;window_size else window_size for ix,x in enumerate(window_sequences)] # Pull out center word of interest for each window and create a tuple for each window if method=='skip_gram': batch_and_labels = [(x[y], x[:y] + x[(y+1):]) for x,y in zip(window_sequences, label_indices)] # Make it in to a big list of tuples (target word, surrounding word) tuple_data = [(x, y_) for x,y in batch_and_labels for y_ in y] elif method=='cbow': batch_and_labels = [(x[:y] + x[(y+1):], x[y]) for x,y in zip(window_sequences, label_indices)] # Make it in to a big list of tuples (target word, surrounding word) tuple_data = [(x_, y) for x,y in batch_and_labels for x_ in x] else: raise ValueError('Method &#123;&#125; not implemented yet.'.format(method)) # extract batch and labels batch, labels = [list(x) for x in zip(*tuple_data)] batch_data.extend(batch[:batch_size]) label_data.extend(labels[:batch_size]) # Trim batch and label at the end batch_data = batch_data[:batch_size] label_data = label_data[:batch_size] # Convert to numpy array batch_data = np.array(batch_data) label_data = np.transpose(np.array([label_data])) return(batch_data, label_data) Next we define our model and placeholders. 123456789101112131415# Define Embeddings:embeddings = tf.Variable(tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))# NCE loss parametersnce_weights = tf.Variable(tf.truncated_normal([vocabulary_size, embedding_size], stddev=1.0 / np.sqrt(embedding_size)))nce_biases = tf.Variable(tf.zeros([vocabulary_size]))# Create data/target placeholdersx_inputs = tf.placeholder(tf.int32, shape=[batch_size])y_target = tf.placeholder(tf.int32, shape=[batch_size, 1])valid_dataset = tf.constant(valid_examples, dtype=tf.int32)# Lookup the word embedding:embed = tf.nn.embedding_lookup(embeddings, x_inputs) 1embed &lt;tf.Tensor &#39;embedding_lookup/Identity:0&#39; shape=(100, 100) dtype=float32&gt; Here is our loss function, optimizer, cosine similarity, and initialization of the model variables. For the loss function we will minimize the average of the NCE loss (noise-contrastive estimation). 123456789101112131415161718192021# Get loss from predictionloss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_weights, biases=nce_biases, labels=y_target, inputs=embed, num_sampled=num_sampled, num_classes=vocabulary_size))# Create optimizeroptimizer = tf.train.GradientDescentOptimizer(learning_rate=1.0).minimize(loss)# Cosine similarity between wordsnorm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keepdims=True))normalized_embeddings = embeddings / normvalid_embeddings = tf.nn.embedding_lookup(normalized_embeddings, valid_dataset)similarity = tf.matmul(valid_embeddings, normalized_embeddings, transpose_b=True)#Add variable initializer.init = tf.global_variables_initializer()sess.run(init) WARNING:tensorflow:From &lt;ipython-input-18-90dede70073c&gt;:13: calling reduce_sum (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version. Instructions for updating: keep_dims is deprecated, use keepdims instead 1sim_init = sess.run(similarity) Now we can train our skip-gram model. Note that we have the line: nearest = (-sim[j, :]).argsort()[1:top_k+1] below. The negative of the similarity matrix is used because argsort() sorts the values from least to greatest. Since we want to take the greatest numbers, we sort in the opposite direction by taking the negative of the similarity matrix, then calling the argsort() method. 123456789101112131415161718192021222324252627282930# Run the skip gram model.loss_vec = []loss_x_vec = []for i in range(generations): batch_inputs, batch_labels = generate_batch_data(text_data, batch_size, window_size) feed_dict = &#123;x_inputs : batch_inputs, y_target : batch_labels&#125; # Run the train step sess.run(optimizer, feed_dict=feed_dict) # Return the loss if (i+1) % print_loss_every == 0: loss_val = sess.run(loss, feed_dict=feed_dict) loss_vec.append(loss_val) loss_x_vec.append(i+1) print("Loss at step &#123;&#125; : &#123;&#125;".format(i+1, loss_val)) # Validation: Print some random words and top 5 related words if (i+1) % print_valid_every == 0: sim = sess.run(similarity) for j in range(len(valid_words)): valid_word = word_dictionary_rev[valid_examples[j]] top_k = 5 # number of nearest neighbors nearest = (-sim[j, :]).argsort()[1:top_k+1] log_str = "Nearest to &#123;&#125;:".format(valid_word) for k in range(top_k): close_word = word_dictionary_rev[nearest[k]] score = sim[j,nearest[k]] log_str = "%s %s," % (log_str, close_word) print(log_str) Loss at step 500 : 19.154987335205078 ... Nearest to cliche: sparkling, chosen, duty, thoughtful, pile, Nearest to love: shimmering, transcend, economical, review, affable, Nearest to hate: tried, recycled, anybody, complexity, enthusiasm, Nearest to silly: denis, audacity, gutwrenching, irritating, callar, Nearest to sad: adequately, surreal, paint, human, exploitative, Loss at step 60500 : 3.153820514678955 Working with CBOW EmbeddingsIn this recipe we will implement the CBOW (continuous bag of words) method of word2vec. It is very similar to the skip-gram method, except we are predicting a single target word from a surrounding window of context words. In the prior example we treated each combination of window and target as a group of paired inputs and outputs, but with CBOW we will add the surrounding window embeddings together to get one embedding to predict the target word embedding. Most of the code will stay the same, except we will need to change how we create the embeddings and how we generate the data from the sentences. To make the code easier to read, we have moved all the major functions to a separate file, called ‘text_helpers.py’ in the same directory. This function holds the data loading, text normalization, dictionary creation, and batch generation functions. This functions are exactly as they appear in the prior recipe, “Working with Skip-gram Embeddings”, except where noted. See the following illustration of a CBOW example. 12345678910111213141516171819print('Creating Model')# Define Embeddings:embeddings = tf.Variable(tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))# NCE loss parametersnce_weights = tf.Variable(tf.truncated_normal([vocabulary_size, embedding_size], stddev=1.0 / np.sqrt(embedding_size)))nce_biases = tf.Variable(tf.zeros([vocabulary_size]))# Create data/target placeholdersx_inputs = tf.placeholder(tf.int32, shape=[batch_size, 2*window_size])y_target = tf.placeholder(tf.int32, shape=[batch_size, 1])valid_dataset = tf.constant(valid_examples, dtype=tf.int32)# Lookup the word embedding# Add together window embeddings:embed = tf.zeros([batch_size, embedding_size])for element in range(2*window_size): embed += tf.nn.embedding_lookup(embeddings, x_inputs[:, element]) 12345678910111213141516# Get loss from predictionloss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_weights, biases=nce_biases, labels=y_target, inputs=embed, num_sampled=num_sampled, num_classes=vocabulary_size))# Create optimizeroptimizer = tf.train.GradientDescentOptimizer(learning_rate=model_learning_rate).minimize(loss)# Cosine similarity between wordsnorm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))normalized_embeddings = embeddings / normvalid_embeddings = tf.nn.embedding_lookup(normalized_embeddings, valid_dataset)similarity = tf.matmul(valid_embeddings, normalized_embeddings, transpose_b=True)]]></content>
      <categories>
        <category>深度学习</category>
        <category>自然语言处理</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[神经网络 Neural Networks]]></title>
    <url>%2F2018%2F11%2F24%2F%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%2F</url>
    <content type="text"><![CDATA[神经网络Neural Network（人工）神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型，那时候研究者构想了「感知器（perceptron）」的想法。这一领域的研究者通常被称为「联结主义者（Connectionist）」，因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型，它们是前馈神经网络（主要是卷积神经网络-CNN）和循环神经网络（RNN），其中 RNN 又包含长短期记忆（LSTM）、门控循环单元（GRU）等子类。深度学习（deep learning）是一种主要应用于神经网络技术以帮助其取得更好结果的技术。尽管神经网络主要用于监督学习，但也有一些为无监督学习设计的变体，如自动编码器（AutoEncoder）和生成对抗网络（GAN）。 Introduction to Neural NetworksThere are more resources for learning about neural networks that are more in depth and detailed. Here are some following resources: The seminal paper describing back propagation is Efficient Back Prop by Yann LeCun et. al. The PDF is located here: http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf CS231, Convolutional Neural Networks for Visual Recognition, by Stanford University, class resources available here: http://cs231n.stanford.edu/ CS224d, Deep Learning for Natural Language Processing, by Stanford University, class resources available here: http://cs224d.stanford.edu/ Deep Learning, a book by the MIT Press. Goodfellow, et. al. 2016. Located: http://www.deeplearningbook.org There is an online book called Neural Networks and Deep Learning by Michael Nielsen, located here: http://neuralnetworksanddeeplearning.com/ For a more pragmatic approach and introduction to neural networks, Andrej Karpathy has written a great summary and JavaScript examples called A Hacker’s Guide to Neural Networks. The write up is located here: http://karpathy.github.io/neuralnets/ Another site that summarizes some good notes on deep learning is called Deep Learning for Beginners by Ian Goodfellow, Yoshua Bengio, and Aaron Courville. This web page can be found here: http://randomekek.github.io/deep/deeplearning.html Implementing GatesThis function shows how to implement various gates in TensorFlow. One gate will be one operation with a variable and a placeholder. We will ask TensorFlowto change the variable based on our loss function 123import tensorflow as tffrom tensorflow.python.framework import opsops.reset_default_graph() Gate 1 Create a multiplication gate: $f(x) = a * x$12345a -- | |---- (multiply) --&gt; output |x -- 12345678910111213141516171819202122232425262728# Start Graph Sessionsess = tf.Session()a = tf.Variable(tf.constant(4.))x_val = 5.x_data = tf.placeholder(dtype=tf.float32)multiplication = tf.multiply(a, x_data)# Declare the loss function as the difference between# the output and a target value, 50.loss = tf.square(tf.subtract(multiplication, 50.))# Initialize variablesinit = tf.global_variables_initializer()sess.run(init)# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.01)train_step = my_opt.minimize(loss)# Run loop across gateprint('Optimizing a Multiplication Gate Output to 50.')for i in range(10): sess.run(train_step, feed_dict=&#123;x_data: x_val&#125;) a_val = sess.run(a) mult_output = sess.run(multiplication, feed_dict=&#123;x_data: x_val&#125;) print(str(a_val) + ' * ' + str(x_val) + ' = ' + str(mult_output)) Optimizing a Multiplication Gate Output to 50. 7.0 * 5.0 = 35.0 8.5 * 5.0 = 42.5 9.25 * 5.0 = 46.25 9.625 * 5.0 = 48.125 9.8125 * 5.0 = 49.0625 9.90625 * 5.0 = 49.53125 9.953125 * 5.0 = 49.765625 9.9765625 * 5.0 = 49.882812 9.988281 * 5.0 = 49.941406 9.994141 * 5.0 = 49.970703 Gate 2 Create a nested gate: $f(x) = a * x + b$ 1234567a -- | |-- (multiply)-- | |x -- |-- (add) --&gt; output | b -- 123456789101112131415161718192021222324252627282930# Start a New Graph Sessionops.reset_default_graph()sess = tf.Session()a = tf.Variable(tf.constant(1.))b = tf.Variable(tf.constant(1.))x_val = 5.x_data = tf.placeholder(dtype=tf.float32)two_gate = tf.add(tf.multiply(a, x_data), b)# Declare the loss function as the difference between# the output and a target value, 50.loss = tf.square(tf.subtract(two_gate, 50.))# Initialize variablesinit = tf.global_variables_initializer()sess.run(init)# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.01)train_step = my_opt.minimize(loss)# Run loop across gateprint('\nOptimizing Two Gate Output to 50.')for i in range(10): sess.run(train_step, feed_dict=&#123;x_data: x_val&#125;) a_val, b_val = (sess.run(a), sess.run(b)) two_gate_output = sess.run(two_gate, feed_dict=&#123;x_data: x_val&#125;) print(str(a_val) + ' * ' + str(x_val) + ' + ' + str(b_val) + ' = ' + str(two_gate_output)) Optimizing Two Gate Output to 50. 5.4 * 5.0 + 1.88 = 28.88 7.512 * 5.0 + 2.3024 = 39.8624 8.52576 * 5.0 + 2.5051522 = 45.133953 9.012364 * 5.0 + 2.6024733 = 47.664295 9.2459345 * 5.0 + 2.6491873 = 48.87886 9.358048 * 5.0 + 2.67161 = 49.461853 9.411863 * 5.0 + 2.682373 = 49.74169 9.437695 * 5.0 + 2.687539 = 49.87601 9.450093 * 5.0 + 2.690019 = 49.940483 9.456045 * 5.0 + 2.6912093 = 49.971436 Combining Gates and Activation FunctionsThis function shows how to implement various gates with activation functions in TensorFlow. This function is an extension of the prior gates, but with various activation functions. 12345import tensorflow as tfimport numpy as npimport matplotlib.pyplot as pltfrom tensorflow.python.framework import opsops.reset_default_graph() 1234567891011121314151617# Start Graph Sessionsess = tf.Session()tf.set_random_seed(5)np.random.seed(42)batch_size = 50a1 = tf.Variable(tf.random_normal(shape=[1,1]))b1 = tf.Variable(tf.random_uniform(shape=[1,1]))a2 = tf.Variable(tf.random_normal(shape=[1,1]))b2 = tf.Variable(tf.random_uniform(shape=[1,1]))x = np.random.normal(2, 0.1, 500)x_data = tf.placeholder(shape=[None, 1], dtype=tf.float32)sigmoid_activation = tf.sigmoid(tf.add(tf.matmul(x_data, a1), b1))relu_activation = tf.nn.relu(tf.add(tf.matmul(x_data, a2), b2)) 1234# Declare the loss function as the difference between# the output and a target value, 0.75.loss1 = tf.reduce_mean(tf.square(tf.subtract(sigmoid_activation, 0.75)))loss2 = tf.reduce_mean(tf.square(tf.subtract(relu_activation, 0.75))) 123# Initialize variablesinit = tf.global_variables_initializer()sess.run(init) 1234# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.01)train_step_sigmoid = my_opt.minimize(loss1)train_step_relu = my_opt.minimize(loss2) 123456789101112131415161718# Run loop across gateprint('\nOptimizing Sigmoid AND Relu Output to 0.75')loss_vec_sigmoid = []loss_vec_relu = []for i in range(500): rand_indices = np.random.choice(len(x), size=batch_size) x_vals = np.transpose([x[rand_indices]]) sess.run(train_step_sigmoid, feed_dict=&#123;x_data: x_vals&#125;) sess.run(train_step_relu, feed_dict=&#123;x_data: x_vals&#125;) loss_vec_sigmoid.append(sess.run(loss1, feed_dict=&#123;x_data: x_vals&#125;)) loss_vec_relu.append(sess.run(loss2, feed_dict=&#123;x_data: x_vals&#125;)) sigmoid_output = np.mean(sess.run(sigmoid_activation, feed_dict=&#123;x_data: x_vals&#125;)) relu_output = np.mean(sess.run(relu_activation, feed_dict=&#123;x_data: x_vals&#125;)) if i%50==0: print('sigmoid = ' + str(np.mean(sigmoid_output)) + ' relu = ' + str(np.mean(relu_output))) Optimizing Sigmoid AND Relu Output to 0.75 sigmoid = 0.12655208 relu = 2.0227606 sigmoid = 0.17863758 relu = 0.7530296 sigmoid = 0.24769811 relu = 0.7492897 sigmoid = 0.3446748 relu = 0.7499546 sigmoid = 0.4400661 relu = 0.7539999 sigmoid = 0.5236898 relu = 0.754772 sigmoid = 0.58373857 relu = 0.7508698 sigmoid = 0.62733483 relu = 0.7470234 sigmoid = 0.6549499 relu = 0.75180537 sigmoid = 0.67452586 relu = 0.75470716 123456789# Plot the lossplt.plot(loss_vec_sigmoid, 'k-', label='Sigmoid Activation')plt.plot(loss_vec_relu, 'r--', label='Relu Activation')plt.ylim([0, 1.0])plt.title('Loss per Generation')plt.xlabel('Generation')plt.ylabel('Loss')plt.legend(loc='upper right')plt.show() Implementing a one-layer Neural NetworkModel The model will have one hidden layer. If the hidden layer has 10 nodes, then the model will look like the following: We will use the ReLU activation functions. For the loss function, we will use the average MSE across the batch.We will illustrate how to create a one hidden layer NN We will use the iris data for this exercise We will build a one-hidden layer neural network to predict the fourth attribute, Petal Width from the other three (Sepal length, Sepal width, Petal length). 12345import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import ops 1ops.reset_default_graph() 123iris = datasets.load_iris()x_vals = np.array([x[0:3] for x in iris.data])y_vals = np.array([x[3] for x in iris.data]) 12# Create graph sessionsess = tf.Session() 1234# make results reproducibleseed = 2tf.set_random_seed(seed)np.random.seed(seed) 1234567# Split data into train/test = 80%/20%train_indices = np.random.choice(len(x_vals), round(len(x_vals)*0.8), replace=False)test_indices = np.array(list(set(range(len(x_vals))) - set(train_indices)))x_vals_train = x_vals[train_indices]x_vals_test = x_vals[test_indices]y_vals_train = y_vals[train_indices]y_vals_test = y_vals[test_indices] 12345678# Normalize by column (min-max norm)def normalize_cols(m): col_max = m.max(axis=0) col_min = m.min(axis=0) return (m-col_min) / (col_max - col_min)x_vals_train = np.nan_to_num(normalize_cols(x_vals_train))x_vals_test = np.nan_to_num(normalize_cols(x_vals_test)) 123456# Declare batch sizebatch_size = 50# Initialize placeholdersx_data = tf.placeholder(shape=[None, 3], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32) 123456789101112131415161718# Create variables for both NN layershidden_layer_nodes = 10A1 = tf.Variable(tf.random_normal(shape=[3,hidden_layer_nodes])) # inputs -&gt; hidden nodesb1 = tf.Variable(tf.random_normal(shape=[hidden_layer_nodes])) # one biases for each hidden nodeA2 = tf.Variable(tf.random_normal(shape=[hidden_layer_nodes,1])) # hidden inputs -&gt; 1 outputb2 = tf.Variable(tf.random_normal(shape=[1])) # 1 bias for the output# Declare model operationshidden_output = tf.nn.relu(tf.add(tf.matmul(x_data, A1), b1))final_output = tf.nn.relu(tf.add(tf.matmul(hidden_output, A2), b2))# Declare loss function (MSE)loss = tf.reduce_mean(tf.square(y_target - final_output))# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.005)train_step = my_opt.minimize(loss) 1234567891011121314151617181920# Initialize variablesinit = tf.global_variables_initializer()sess.run(init)# Training looploss_vec = []test_loss = []for i in range(500): rand_index = np.random.choice(len(x_vals_train), size=batch_size) rand_x = x_vals_train[rand_index] rand_y = np.transpose([y_vals_train[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(np.sqrt(temp_loss)) test_temp_loss = sess.run(loss, feed_dict=&#123;x_data: x_vals_test, y_target: np.transpose([y_vals_test])&#125;) test_loss.append(np.sqrt(test_temp_loss)) if (i+1)%50==0: print('Generation: ' + str(i+1) + '. Loss = ' + str(temp_loss)) Generation: 50. Loss = 0.5279015 Generation: 100. Loss = 0.22871476 Generation: 150. Loss = 0.17977345 Generation: 200. Loss = 0.10849865 Generation: 250. Loss = 0.24002916 Generation: 300. Loss = 0.15323998 Generation: 350. Loss = 0.1659011 Generation: 400. Loss = 0.09752482 Generation: 450. Loss = 0.121614255 Generation: 500. Loss = 0.1300937 123456789%matplotlib inline# Plot loss (MSE) over timeplt.plot(loss_vec, 'k-', label='Train Loss')plt.plot(test_loss, 'r--', label='Test Loss')plt.title('Loss (MSE) per Generation')plt.legend(loc='upper right')plt.xlabel('Generation')plt.ylabel('Loss')plt.show() Implementing Different LayersWe will illustrate how to use different types of layers in TensorFlow The layers of interest are: Convolutional Layer Activation Layer Max-Pool Layer Fully Connected Layer We will generate two different data sets for this script, a 1-D data set (row of data) and a 2-D data set (similar to picture) 12345678import tensorflow as tfimport matplotlib.pyplot as pltimport csvimport osimport randomimport numpy as npimport randomfrom tensorflow.python.framework import ops 123#---------------------------------------------------|#-------------------1D-data-------------------------|#---------------------------------------------------| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788# Create graph sessionops.reset_default_graph()sess = tf.Session()# parameters for the rundata_size = 25conv_size = 5maxpool_size = 5stride_size = 1# ensure reproducibilityseed=13np.random.seed(seed)tf.set_random_seed(seed)# Generate 1D datadata_1d = np.random.normal(size=data_size)# Placeholderx_input_1d = tf.placeholder(dtype=tf.float32, shape=[data_size])#--------Convolution--------# both [batch#, width, height, channels] and [batch#, height, width, channels] are correct.Nut (input, filter, strides, padding) dimensional relations should keep correspondence.def conv_layer_1d(input_1d, my_filter,stride): # TensorFlow's 'conv2d()' function only works with 4D arrays: # [batch#, width, height, channels], we have 1 batch, and # width = 1, but height = the length of the input, and 1 channel. # So next we create the 4D array by inserting dimension 1's. input_2d = tf.expand_dims(input_1d, 0) input_3d = tf.expand_dims(input_2d, 0) input_4d = tf.expand_dims(input_3d, 3) # Perform convolution with stride = 1, if we wanted to increase the stride, # to say '2', then strides=[1,1,2,1] convolution_output = tf.nn.conv2d(input_4d, filter=my_filter, strides=[1,1,stride,1], padding="VALID") # Get rid of extra dimensions conv_output_1d = tf.squeeze(convolution_output) return(conv_output_1d)# Create filter for convolution.my_filter = tf.Variable(tf.random_normal(shape=[1,conv_size,1,1]))# Create convolution layermy_convolution_output = conv_layer_1d(x_input_1d, my_filter,stride=stride_size)#--------Activation--------def activation(input_1d): return(tf.nn.relu(input_1d))# Create activation layermy_activation_output = activation(my_convolution_output)#--------Max Pool--------def max_pool(input_1d, width,stride): # Just like 'conv2d()' above, max_pool() works with 4D arrays. # [batch_size=1, width=1, height=num_input, channels=1] input_2d = tf.expand_dims(input_1d, 0) input_3d = tf.expand_dims(input_2d, 0) input_4d = tf.expand_dims(input_3d, 3) # Perform the max pooling with strides = [1,1,1,1] # If we wanted to increase the stride on our data dimension, say by # a factor of '2', we put strides = [1, 1, 2, 1] # We will also need to specify the width of the max-window ('width') pool_output = tf.nn.max_pool(input_4d, ksize=[1, 1, width, 1], strides=[1, 1, stride, 1], padding='VALID') # Get rid of extra dimensions pool_output_1d = tf.squeeze(pool_output) return(pool_output_1d)my_maxpool_output = max_pool(my_activation_output, width=maxpool_size,stride=stride_size)#--------Fully Connected--------def fully_connected(input_layer, num_outputs): # First we find the needed shape of the multiplication weight matrix: # The dimension will be (length of input) by (num_outputs) weight_shape = tf.squeeze(tf.stack([tf.shape(input_layer),[num_outputs]])) # Initialize such weight weight = tf.random_normal(weight_shape, stddev=0.1) # Initialize the bias bias = tf.random_normal(shape=[num_outputs]) # Make the 1D input array into a 2D array for matrix multiplication input_layer_2d = tf.expand_dims(input_layer, 0) # Perform the matrix multiplication and add the bias full_output = tf.add(tf.matmul(input_layer_2d, weight), bias) # Get rid of extra dimensions full_output_1d = tf.squeeze(full_output) return(full_output_1d)my_full_output = fully_connected(my_maxpool_output, 5) 12345678910111213141516171819202122232425262728293031# Run graph# Initialize Variablesinit = tf.global_variables_initializer()sess.run(init)feed_dict = &#123;x_input_1d: data_1d&#125;print('&gt;&gt;&gt;&gt; 1D Data &lt;&lt;&lt;&lt;')# Convolution Outputprint('Input = array of length %d' % (x_input_1d.shape.as_list()[0]))print('Convolution w/ filter, length = %d, stride size = %d, results in an array of length %d:' % (conv_size,stride_size,my_convolution_output.shape.as_list()[0]))print(sess.run(my_convolution_output, feed_dict=feed_dict))# Activation Outputprint('\nInput = above array of length %d' % (my_convolution_output.shape.as_list()[0]))print('ReLU element wise returns an array of length %d:' % (my_activation_output.shape.as_list()[0]))print(sess.run(my_activation_output, feed_dict=feed_dict))# Max Pool Outputprint('\nInput = above array of length %d' % (my_activation_output.shape.as_list()[0]))print('MaxPool, window length = %d, stride size = %d, results in the array of length %d' % (maxpool_size,stride_size,my_maxpool_output.shape.as_list()[0]))print(sess.run(my_maxpool_output, feed_dict=feed_dict))# Fully Connected Outputprint('\nInput = above array of length %d' % (my_maxpool_output.shape.as_list()[0]))print('Fully connected layer on all 4 rows with %d outputs:' % (my_full_output.shape.as_list()[0]))print(sess.run(my_full_output, feed_dict=feed_dict)) &gt;&gt;&gt;&gt; 1D Data &lt;&lt;&lt;&lt; Input = array of length 25 Convolution w/ filter, length = 5, stride size = 1, results in an array of length 21: [-2.63576341 -1.11550486 -0.95571411 -1.69670296 -0.35699379 0.62266493 4.43316031 2.01364899 1.33044648 -2.30629659 -0.82916248 -2.63594174 0.76669347 -2.46465087 -2.2855041 1.49780679 1.6960566 1.48557389 -2.79799461 1.18149185 1.42146575] Input = above array of length 21 ReLU element wise returns an array of length 21: [ 0. 0. 0. 0. 0. 0.62266493 4.43316031 2.01364899 1.33044648 0. 0. 0. 0.76669347 0. 0. 1.49780679 1.6960566 1.48557389 0. 1.18149185 1.42146575] Input = above array of length 21 MaxPool, window length = 5, stride size = 1, results in the array of length 17 [ 0. 0.62266493 4.43316031 4.43316031 4.43316031 4.43316031 4.43316031 2.01364899 1.33044648 0.76669347 0.76669347 1.49780679 1.6960566 1.6960566 1.6960566 1.6960566 1.6960566 ] Input = above array of length 17 Fully connected layer on all 4 rows with 5 outputs: [ 1.71536076 -0.72340977 -1.22485089 -2.5412786 -0.16338301] 123#---------------------------------------------------|#-------------------2D-data-------------------------|#---------------------------------------------------| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495# Reset Graphops.reset_default_graph()sess = tf.Session()# parameters for the runrow_size = 10col_size = 10conv_size = 2conv_stride_size = 2maxpool_size = 2maxpool_stride_size = 1# ensure reproducibilityseed=13np.random.seed(seed)tf.set_random_seed(seed)#Generate 2D datadata_size = [row_size,col_size]data_2d = np.random.normal(size=data_size)#--------Placeholder--------x_input_2d = tf.placeholder(dtype=tf.float32, shape=data_size)# Convolutiondef conv_layer_2d(input_2d, my_filter,stride_size): # TensorFlow's 'conv2d()' function only works with 4D arrays: # [batch#, width, height, channels], we have 1 batch, and # 1 channel, but we do have width AND height this time. # So next we create the 4D array by inserting dimension 1's. input_3d = tf.expand_dims(input_2d, 0) input_4d = tf.expand_dims(input_3d, 3) # Note the stride difference below! convolution_output = tf.nn.conv2d(input_4d, filter=my_filter, strides=[1,stride_size,stride_size,1], padding="VALID") # Get rid of unnecessary dimensions conv_output_2d = tf.squeeze(convolution_output) return(conv_output_2d)# Create Convolutional Filtermy_filter = tf.Variable(tf.random_normal(shape=[conv_size,conv_size,1,1]))# Create Convolutional Layermy_convolution_output = conv_layer_2d(x_input_2d, my_filter,stride_size=conv_stride_size)#--------Activation--------def activation(input_1d): return(tf.nn.relu(input_1d))# Create Activation Layermy_activation_output = activation(my_convolution_output)#--------Max Pool--------def max_pool(input_2d, width, height,stride): # Just like 'conv2d()' above, max_pool() works with 4D arrays. # [batch_size=1, width=given, height=given, channels=1] input_3d = tf.expand_dims(input_2d, 0) input_4d = tf.expand_dims(input_3d, 3) # Perform the max pooling with strides = [1,1,1,1] # If we wanted to increase the stride on our data dimension, say by # a factor of '2', we put strides = [1, 2, 2, 1] pool_output = tf.nn.max_pool(input_4d, ksize=[1, height, width, 1], strides=[1, stride, stride, 1], padding='VALID') # Get rid of unnecessary dimensions pool_output_2d = tf.squeeze(pool_output) return(pool_output_2d)# Create Max-Pool Layermy_maxpool_output = max_pool(my_activation_output, width=maxpool_size, height=maxpool_size,stride=maxpool_stride_size)#--------Fully Connected--------def fully_connected(input_layer, num_outputs): # In order to connect our whole W byH 2d array, we first flatten it out to # a W times H 1D array. flat_input = tf.reshape(input_layer, [-1]) # We then find out how long it is, and create an array for the shape of # the multiplication weight = (WxH) by (num_outputs) weight_shape = tf.squeeze(tf.stack([tf.shape(flat_input),[num_outputs]])) # Initialize the weight weight = tf.random_normal(weight_shape, stddev=0.1) # Initialize the bias bias = tf.random_normal(shape=[num_outputs]) # Now make the flat 1D array into a 2D array for multiplication input_2d = tf.expand_dims(flat_input, 0) # Multiply and add the bias full_output = tf.add(tf.matmul(input_2d, weight), bias) # Get rid of extra dimension full_output_2d = tf.squeeze(full_output) return(full_output_2d)# Create Fully Connected Layermy_full_output = fully_connected(my_maxpool_output, 5) 12345678910111213141516171819202122232425262728293031# Run graph# Initialize Variablesinit = tf.global_variables_initializer()sess.run(init)feed_dict = &#123;x_input_2d: data_2d&#125;print('&gt;&gt;&gt;&gt; 2D Data &lt;&lt;&lt;&lt;')# Convolution Outputprint('Input = %s array' % (x_input_2d.shape.as_list()))print('%s Convolution, stride size = [%d, %d] , results in the %s array' % (my_filter.get_shape().as_list()[:2],conv_stride_size,conv_stride_size,my_convolution_output.shape.as_list()))print(sess.run(my_convolution_output, feed_dict=feed_dict))# Activation Outputprint('\nInput = the above %s array' % (my_convolution_output.shape.as_list()))print('ReLU element wise returns the %s array' % (my_activation_output.shape.as_list()))print(sess.run(my_activation_output, feed_dict=feed_dict))# Max Pool Outputprint('\nInput = the above %s array' % (my_activation_output.shape.as_list()))print('MaxPool, stride size = [%d, %d], results in %s array' % (maxpool_stride_size,maxpool_stride_size,my_maxpool_output.shape.as_list()))print(sess.run(my_maxpool_output, feed_dict=feed_dict))# Fully Connected Outputprint('\nInput = the above %s array' % (my_maxpool_output.shape.as_list()))print('Fully connected layer on all %d rows results in %s outputs:' % (my_maxpool_output.shape.as_list()[0],my_full_output.shape.as_list()[0]))print(sess.run(my_full_output, feed_dict=feed_dict)) &gt;&gt;&gt;&gt; 2D Data &lt;&lt;&lt;&lt; Input = [10, 10] array [2, 2] Convolution, stride size = [2, 2] , results in the [5, 5] array [[ 0.14431179 0.7278337 1.5114917 -1.2809976 1.7843919 ] [-2.5450306 0.76156765 -0.51650006 0.7713109 0.37542343] [ 0.4934591 0.01592223 0.38653135 -1.4799767 0.6952765 ] [-0.34617192 -2.5318975 -0.9525758 -1.4357065 0.6625736 ] [-1.9854026 0.34398788 2.5376048 -0.8678482 -0.3100495 ]] Input = the above [5, 5] array ReLU element wise returns the [5, 5] array [[0.14431179 0.7278337 1.5114917 0. 1.7843919 ] [0. 0.76156765 0. 0.7713109 0.37542343] [0.4934591 0.01592223 0.38653135 0. 0.6952765 ] [0. 0. 0. 0. 0.6625736 ] [0. 0.34398788 2.5376048 0. 0. ]] Input = the above [5, 5] array MaxPool, stride size = [1, 1], results in [4, 4] array [[0.76156765 1.5114917 1.5114917 1.7843919 ] [0.76156765 0.76156765 0.7713109 0.7713109 ] [0.4934591 0.38653135 0.38653135 0.6952765 ] [0.34398788 2.5376048 2.5376048 0.6625736 ]] Input = the above [4, 4] array Fully connected layer on all 4 rows results in 5 outputs: [ 0.08245847 -0.16351229 -0.55429065 -0.24322605 -0.99900764] Using a Multiple Layer NetworkWe will illustrate how to use a Multiple Layer Network in TensorFlow Low Birthrate data:12345678910111213#Columns Variable Abbreviation#---------------------------------------------------------------------# Low Birth Weight (0 = Birth Weight &gt;= 2500g, LOW# 1 = Birth Weight &lt; 2500g)# Age of the Mother in Years AGE# Weight in Pounds at the Last Menstrual Period LWT# Race (1 = White, 2 = Black, 3 = Other) RACE# Smoking Status During Pregnancy (1 = Yes, 0 = No) SMOKE# History of Premature Labor (0 = None 1 = One, etc.) PTL# History of Hypertension (1 = Yes, 0 = No) HT# Presence of Uterine Irritability (1 = Yes, 0 = No) UI# Birth Weight in Grams BWT#--------------------------------------------------------------------- The multiple neural network layer we will create will be composed of three fully connected hidden layers, with node sizes 50, 25, and 5 12345678910import tensorflow as tfimport matplotlib.pyplot as pltimport csvimport osimport os.pathimport randomimport numpy as npimport randomimport requestsfrom tensorflow.python.framework import ops Obtain the data 12345678910111213141516171819202122232425262728293031323334# name of data filebirth_weight_file = 'birth_weight.csv'# download data and create data file if file does not exist in current directoryif not os.path.exists(birth_weight_file): birthdata_url = 'https://github.com/nfmcclure/tensorflow_cookbook/raw/master/01_Introduction/07_Working_with_Data_Sources/birthweight_data/birthweight.dat' birth_file = requests.get(birthdata_url) birth_data = birth_file.text.split('\r\n') birth_header = birth_data[0].split('\t') birth_data = [[float(x) for x in y.split('\t') if len(x)&gt;=1] for y in birth_data[1:] if len(y)&gt;=1] with open(birth_weight_file, "w") as f: writer = csv.writer(f) writer.writerows([birth_header]) writer.writerows(birth_data) f.close()# read birth weight data into memorybirth_data = []with open(birth_weight_file, newline='') as csvfile: csv_reader = csv.reader(csvfile) birth_header = next(csv_reader) for row in csv_reader: birth_data.append(row)birth_data = [[float(x) for x in row] for row in birth_data]birth_data = [data for data in birth_data if len(data)==9]# Extract y-target (birth weight)y_vals = np.array([x[8] for x in birth_data])# Filter for features of interestcols_of_interest = ['AGE', 'LWT', 'RACE', 'SMOKE', 'PTL', 'HT', 'UI']x_vals = np.array([[x[ix] for ix, feature in enumerate(birth_header) if feature in cols_of_interest] for x in birth_data]) Train model Here we reset any graph in memory and then start to create our graph and vectors. 123456789101112131415161718192021# reset the graph for new runops.reset_default_graph()# Create graph sessionsess = tf.Session()# set batch size for trainingbatch_size = 150# make results reproducibleseed = 3np.random.seed(seed)tf.set_random_seed(seed)# Split data into train/test = 80%/20%train_indices = np.random.choice(len(x_vals), round(len(x_vals)*0.8), replace=False)test_indices = np.array(list(set(range(len(x_vals))) - set(train_indices)))x_vals_train = x_vals[train_indices]x_vals_test = x_vals[test_indices]y_vals_train = y_vals[train_indices]y_vals_test = y_vals[test_indices] Now we scale our dataset by the min/max of the _training set_. We start by recording the mins and maxs of the training set. (We use this on scaling the test set, and evaluation set later on). 12345678910# Record training column max and min for scaling of non-training datatrain_max = np.max(x_vals_train, axis=0)train_min = np.min(x_vals_train, axis=0)# Normalize by column (min-max norm to be between 0 and 1)def normalize_cols(mat, max_vals, min_vals): return (mat - min_vals) / (max_vals - min_vals)x_vals_train = np.nan_to_num(normalize_cols(x_vals_train, train_max, train_min))x_vals_test = np.nan_to_num(normalize_cols(x_vals_test, train_max, train_min)) Next, we define our varibles, bias, and placeholders. 1234567891011121314# Define Variable Functions (weights and bias)def init_weight(shape, st_dev): weight = tf.Variable(tf.random_normal(shape, stddev=st_dev)) return(weight)def init_bias(shape, st_dev): bias = tf.Variable(tf.random_normal(shape, stddev=st_dev)) return(bias)# Create Placeholdersx_data = tf.placeholder(shape=[None, 7], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32) Now we define our model! We start with a function that creates a fully connected later according to our variable specifications. 12345678910111213141516171819202122232425262728293031323334# Create a fully connected layer:def fully_connected(input_layer, weights, biases): layer = tf.add(tf.matmul(input_layer, weights), biases) return(tf.nn.relu(layer))#--------Create the first layer (50 hidden nodes)--------weight_1 = init_weight(shape=[7, 25], st_dev=10.0)bias_1 = init_bias(shape=[25], st_dev=10.0)layer_1 = fully_connected(x_data, weight_1, bias_1)#--------Create second layer (25 hidden nodes)--------weight_2 = init_weight(shape=[25, 10], st_dev=10.0)bias_2 = init_bias(shape=[10], st_dev=10.0)layer_2 = fully_connected(layer_1, weight_2, bias_2)#--------Create third layer (5 hidden nodes)--------weight_3 = init_weight(shape=[10, 3], st_dev=10.0)bias_3 = init_bias(shape=[3], st_dev=10.0)layer_3 = fully_connected(layer_2, weight_3, bias_3)#--------Create output layer (1 output value)--------weight_4 = init_weight(shape=[3, 1], st_dev=10.0)bias_4 = init_bias(shape=[1], st_dev=10.0)final_output = fully_connected(layer_3, weight_4, bias_4)# Declare loss function (L1)loss = tf.reduce_mean(tf.abs(y_target - final_output))# Declare optimizermy_opt = tf.train.AdamOptimizer(0.025)train_step = my_opt.minimize(loss) Now we initialize all the variables and start the training loop. 1234567891011121314151617181920# Initialize Variablesinit = tf.global_variables_initializer()sess.run(init)# Training looploss_vec = []test_loss = []for i in range(500): rand_index = np.random.choice(len(x_vals_train), size=batch_size) rand_x = x_vals_train[rand_index] rand_y = np.transpose([y_vals_train[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss) test_temp_loss = sess.run(loss, feed_dict=&#123;x_data: x_vals_test, y_target: np.transpose([y_vals_test])&#125;) test_loss.append(test_temp_loss) if (i+1) % 25 == 0: print('Generation: ' + str(i+1) + '. Loss = ' + str(temp_loss)) Generation: 25. Loss = 15990.672 Generation: 50. Loss = 4621.7314 Generation: 75. Loss = 2795.2063 Generation: 100. Loss = 2217.2898 Generation: 125. Loss = 2295.6526 Generation: 150. Loss = 2047.0446 Generation: 175. Loss = 1915.7665 Generation: 200. Loss = 1732.4609 Generation: 225. Loss = 1684.7881 Generation: 250. Loss = 1576.6495 Generation: 275. Loss = 1579.0376 Generation: 300. Loss = 1456.1991 Generation: 325. Loss = 1521.6523 Generation: 350. Loss = 1294.7655 Generation: 375. Loss = 1507.561 Generation: 400. Loss = 1221.8282 Generation: 425. Loss = 1636.6687 Generation: 450. Loss = 1306.686 Generation: 475. Loss = 1564.3484 Generation: 500. Loss = 1360.876 Here is code that will plot the loss by generation. 123456789%matplotlib inline# Plot loss (MSE) over timeplt.plot(loss_vec, 'k-', label='Train Loss')plt.plot(test_loss, 'r--', label='Test Loss')plt.title('Loss (MSE) per Generation')plt.legend(loc='upper right')plt.xlabel('Generation')plt.ylabel('Loss')plt.show() Here is how to calculate the model accuracy: 1234567891011121314# Model Accuracyactuals = np.array([x[0] for x in birth_data])test_actuals = actuals[test_indices]train_actuals = actuals[train_indices]test_preds = [x[0] for x in sess.run(final_output, feed_dict=&#123;x_data: x_vals_test&#125;)]train_preds = [x[0] for x in sess.run(final_output, feed_dict=&#123;x_data: x_vals_train&#125;)]test_preds = np.array([1.0 if x &lt; 2500.0 else 0.0 for x in test_preds])train_preds = np.array([1.0 if x &lt; 2500.0 else 0.0 for x in train_preds])# Print out accuraciestest_acc = np.mean([x == y for x, y in zip(test_preds, test_actuals)])train_acc = np.mean([x == y for x, y in zip(train_preds, train_actuals)])print('On predicting the category of low birthweight from regression output (&lt;2500g):')print('Test Accuracy: &#123;&#125;'.format(test_acc))print('Train Accuracy: &#123;&#125;'.format(train_acc)) On predicting the category of low birthweight from regression output (&lt;2500g): Test Accuracy: 0.5 Train Accuracy: 0.6225165562913907 Evaluate new points on the model 12345678# Need new vectors of 'AGE', 'LWT', 'RACE', 'SMOKE', 'PTL', 'HT', 'UI'new_data = np.array([[35, 185, 1., 0., 0., 0., 1.], [18, 160, 0., 1., 0., 0., 1.]])new_data_scaled = np.nan_to_num(normalize_cols(new_data, train_max, train_min))new_logits = [x[0] for x in sess.run(final_output, feed_dict=&#123;x_data: new_data_scaled&#125;)]new_preds = np.array([1.0 if x &lt; 2500.0 else 0.0 for x in new_logits])print('New Data Predictions: &#123;&#125;'.format(new_preds)) New Data Predictions: [1. 1.] Improving Linear Regression with Neural Networks (Logistic Regression)This function shows how to use TensorFlow to solve logistic regression with a multiple layer neural network \textbf{y} = sigmoid(\textbf{A}_{3} \times sigmoid(\textbf{A}_{2} \times sigmoid(\textbf{A}_{1} \times \textbf{x} + \textbf{b}_{1}) + \textbf{b}_{2}) + \textbf{b}_{3})We will use the low birth weight data, specifically:12y = 0 or 1 = low birth weightx = demographic and medical history data 12345678910import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tfimport requestsimport os.pathimport csvfrom tensorflow.python.framework import ops# reset computational graphops.reset_default_graph() Obtain and prepare data for modeling 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455# name of data filebirth_weight_file = 'birth_weight.csv'# download data and create data file if file does not exist in current directoryif not os.path.exists(birth_weight_file): birthdata_url = 'https://github.com/nfmcclure/tensorflow_cookbook/raw/master/01_Introduction/07_Working_with_Data_Sources/birthweight_data/birthweight.dat' birth_file = requests.get(birthdata_url) birth_data = birth_file.text.split('\r\n') birth_header = birth_data[0].split('\t') birth_data = [[float(x) for x in y.split('\t') if len(x)&gt;=1] for y in birth_data[1:] if len(y)&gt;=1] with open(birth_weight_file, "w") as f: writer = csv.writer(f) writer.writerows(birth_data) f.close()# read birth weight data into memorybirth_data = []with open(birth_weight_file, newline='') as csvfile: csv_reader = csv.reader(csvfile) birth_header = next(csv_reader) for row in csv_reader: birth_data.append(row)birth_data = [[float(x) for x in row] for row in birth_data]birth_data = [data for data in birth_data if len(data)==9]# Pull out target variabley_vals = np.array([x[0] for x in birth_data])# Pull out predictor variables (not id, not target, and not birthweight)x_vals = np.array([x[1:8] for x in birth_data])# set for reproducible resultsseed = 99np.random.seed(seed)tf.set_random_seed(seed)# Declare batch sizebatch_size = 90# Split data into train/test = 80%/20%train_indices = np.random.choice(len(x_vals), round(len(x_vals)*0.8), replace=False)test_indices = np.array(list(set(range(len(x_vals))) - set(train_indices)))x_vals_train = x_vals[train_indices]x_vals_test = x_vals[test_indices]y_vals_train = y_vals[train_indices]y_vals_test = y_vals[test_indices]# Normalize by column (min-max norm)def normalize_cols(m): col_max = m.max(axis=0) col_min = m.min(axis=0) return (m-col_min) / (col_max - col_min)x_vals_train = np.nan_to_num(normalize_cols(x_vals_train))x_vals_test = np.nan_to_num(normalize_cols(x_vals_test)) Define Tensorflow computational graph 123456789101112131415161718192021222324252627282930313233343536373839404142434445# Create graphsess = tf.Session()# Initialize placeholdersx_data = tf.placeholder(shape=[None, 7], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)# Create variable definitiondef init_variable(shape): return(tf.Variable(tf.random_normal(shape=shape)))# Create a logistic layer definitiondef logistic(input_layer, multiplication_weight, bias_weight, activation = True): linear_layer = tf.add(tf.matmul(input_layer, multiplication_weight), bias_weight) # We separate the activation at the end because the loss function will # implement the last sigmoid necessary if activation: return(tf.nn.sigmoid(linear_layer)) else: return(linear_layer)# First logistic layer (7 inputs to 14 hidden nodes)A1 = init_variable(shape=[7,14])b1 = init_variable(shape=[14])logistic_layer1 = logistic(x_data, A1, b1)# Second logistic layer (14 hidden inputs to 5 hidden nodes)A2 = init_variable(shape=[14,5])b2 = init_variable(shape=[5])logistic_layer2 = logistic(logistic_layer1, A2, b2)# Final output layer (5 hidden nodes to 1 output)A3 = init_variable(shape=[5,1])b3 = init_variable(shape=[1])final_output = logistic(logistic_layer2, A3, b3, activation=False)# Declare loss function (Cross Entropy loss)loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=final_output, labels=y_target))# Declare optimizermy_opt = tf.train.AdamOptimizer(learning_rate = 0.002)train_step = my_opt.minimize(loss) Train model 123456789101112131415161718192021222324252627# Initialize variablesinit = tf.global_variables_initializer()sess.run(init)# Actual Predictionprediction = tf.round(tf.nn.sigmoid(final_output))predictions_correct = tf.cast(tf.equal(prediction, y_target), tf.float32)accuracy = tf.reduce_mean(predictions_correct)# Training looploss_vec = []train_acc = []test_acc = []for i in range(1500): rand_index = np.random.choice(len(x_vals_train), size=batch_size) rand_x = x_vals_train[rand_index] rand_y = np.transpose([y_vals_train[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss) temp_acc_train = sess.run(accuracy, feed_dict=&#123;x_data: x_vals_train, y_target: np.transpose([y_vals_train])&#125;) train_acc.append(temp_acc_train) temp_acc_test = sess.run(accuracy, feed_dict=&#123;x_data: x_vals_test, y_target: np.transpose([y_vals_test])&#125;) test_acc.append(temp_acc_test) if (i+1)%150==0: print('Loss = ' + str(temp_loss)) Loss = 0.68008155 Loss = 0.54981357 Loss = 0.54257077 Loss = 0.55420905 Loss = 0.52513915 Loss = 0.5386876 Loss = 0.5331423 Loss = 0.4861947 Loss = 0.58909637 Loss = 0.5264541 Display model performance 12345678910111213141516%matplotlib inline# Plot loss over timeplt.plot(loss_vec, 'k-')plt.title('Cross Entropy Loss per Generation')plt.xlabel('Generation')plt.ylabel('Cross Entropy Loss')plt.show()# Plot train and test accuracyplt.plot(train_acc, 'k-', label='Train Set Accuracy')plt.plot(test_acc, 'r--', label='Test Set Accuracy')plt.title('Train and Test Accuracy')plt.xlabel('Generation')plt.ylabel('Accuracy')plt.legend(loc='lower right')plt.show() Learning to Play Tic-Tac-ToeTic-Tac-Toe Game Model]]></content>
      <categories>
        <category>深度学习</category>
        <category>神经网络</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[线性回归 Linear_Regression]]></title>
    <url>%2F2018%2F11%2F24%2F%E7%BA%BF%E6%80%A7%E5%9B%9E%E5%BD%92%2F</url>
    <content type="text"><![CDATA[线性回归Linear Regression (function) https://en.wikipedia.org/wiki/Linear_regression在现实世界中，存在着大量这样的情况：两个变量例如X和Y有一些依赖关系。由X可以部分地决定Y的值，但这种决定往往不很确切。常常用来说明这种依赖关系的最简单、直观的例子是体重与身高，用Y表示他的体重。众所周知，一般说来，当X大时，Y也倾向于大，但由X不能严格地决定Y。又如，城市生活用电量Y与气温X有很大的关系。在夏天气温很高或冬天气温很低时，由于室内空调、冰箱等家用电器的使用，可能用电就高，相反，在春秋季节气温不高也不低，用电量就可能少。但我们不能由气温X准确地决定用电量Y。类似的例子还很多，变量之间的这种关系称为“相关关系”，回归模型就是研究相关关系的一个有力工具。 Linear RegressionHere we show how to implement various linear regression techniques in TensorFlow. The first two sections show how to do standard matrix linear regression solving in TensorFlow. The remaining six sections depict how to implement various types of regression using computational graphs in TensorFlow. 1. Linear Regression: Inverse Matrix MethodUsing the Matrix Inverse Method Here we implement solving 2D linear regression via the matrix inverse method in TensorFlow. Model Given A * x = b, we can solve for x via: (t(A) A) x = t(A) * b x = (t(A) A)^(-1) t(A) * b Here, note that t(A) is the transpose of A. This script explores how to accomplish linear regression with TensorFlow using the matrix inverse. Given the system $ A \cdot x = y $, the matrix inverse way of linear regression (equations for overdetermined systems) is given by solving for x as follows. x = \left( A^{T} \cdot A \right)^{-1} \cdot A^{T} \cdot yAs a reminder, here, $x$ is our parameter matrix (vector of length $F+1$, where $F$ is the number of features). Here, $A$, our design matrix takes the form A= \begin{bmatrix} 1 & x_{11} & x_{12} & \dots & x_{1F} \\ 1 & x_{21} & x_{22} & \dots & x_{2F} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & x_{n1} & x_{n2} & \dots & x_{nF} \end{bmatrix}Where $F$ is the number of independent features, and $n$ is the number of points. For an overdetermined system, $n&gt;F$. Remember that one observed point in our system will have length $F+1$ and the $i^{th}$ point will look like point_{i} = \left( y_{i}, x_{i1}, x_{i2}, \dots, x_{iF} \right)For this recipe, we will consider only a 2-dimensional system ($F=1$), so that we can plot the results at the end. We start by loading the necessary libraries. 12345import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom tensorflow.python.framework import opsops.reset_default_graph() Next we start a graph session. 1sess = tf.Session() For illustration purposes, we randomly generate data to fit. The x-values will be a sequence of 100 evenly spaced values between 0 and 100. The y-values will fit to the line: $y=x$, but we will add normally distributed error according to $N(0,1)$. 123# Create the datax_vals = np.linspace(0, 10, 100)y_vals = x_vals + np.random.normal(0, 1, 100) We create the design matrix, $A$, which will be a column of ones and the x-values. 1234# Create design matrixx_vals_column = np.transpose(np.matrix(x_vals))ones_column = np.transpose(np.matrix(np.repeat(1, 100)))A = np.column_stack((x_vals_column, ones_column)) We now create the y-values as a matrix with Numpy. After we have the y-values and the design matrix, we create tensors from them. 123456# Format the y matrixy = np.transpose(np.matrix(y_vals))# Create tensorsA_tensor = tf.constant(A)y_tensor = tf.constant(y) Now we solve for the parameter matrix with TensorFlow operations. 12345# Matrix inverse solutiontA_A = tf.matmul(tf.transpose(A_tensor), A_tensor)tA_A_inv = tf.matrix_inverse(tA_A)product = tf.matmul(tA_A_inv, tf.transpose(A_tensor))solution = tf.matmul(product, y_tensor) Run the solutions and extract the slope and intercept from the parameter matrix. 12345solution_eval = sess.run(solution)# Extract coefficientsslope = solution_eval[0][0]y_intercept = solution_eval[1][0] Now we print the solution we found and create a best fit line. 1234567print('slope: ' + str(slope))print('y_intercept: ' + str(y_intercept))# Get best fit linebest_fit = []for i in x_vals: best_fit.append(slope*i+y_intercept) slope: 0.9953458430212332 y_intercept: 0.0956584431188145 We use Matplotlib to plot the results. 12345# Plot the resultsplt.plot(x_vals, y_vals, 'o', label='Data')plt.plot(x_vals, best_fit, 'r-', label='Best fit line', linewidth=3)plt.legend(loc='upper left')plt.show() 2. Linear Regression: Using a Decomposition (Cholesky Method)Using the Cholesky Decomposition Method Here we implement solving 2D linear regression via the Cholesky decomposition in TensorFlow. Model Given A x = b, and a Cholesky decomposition such that A = LL’ then we can get solve for x via Solving L y = t(A) b for y Solving L’ * x = y for x. This script will use TensorFlow’s function, tf.cholesky() to decompose our design matrix and solve for the parameter matrix from linear regression. For linear regression we are given the system $A \cdot x = y$. Here, $A$ is our design matrix, $x$ is our parameter matrix (of interest), and $y$ is our target matrix (dependent values). For a Cholesky decomposition to work we assume that $A$ can be broken up into a product of a lower triangular matrix, $L$ and the transpose of the same matrix, $L^{T}$. Note that this is when $A$ is square. Of course, with an over determined system, $A$ is not square. So we factor the product $A^{T} \cdot A$ instead. We then assume: A^{T} \cdot A = L^{T} \cdot LFor more information on the Cholesky decomposition and it’s uses, see the following wikipedia link: The Cholesky Decomposition Given that $A$ has a unique Cholesky decomposition, we can write our linear regression system as the following: L^{T} \cdot L \cdot x = A^{T} \cdot yThen we break apart the system as follows: L^{T} \cdot z = A^{T} \cdot yand L \cdot x = zThe steps we will take to solve for $x$ are the following Compute the Cholesky decomposition of $A$, where $A^{T} \cdot A = L^{T} \cdot L$. Solve ($L^{T} \cdot z = A^{T} \cdot y$) for $z$. Finally, solve ($L \cdot x = z$) for $x$. We start by loading the necessary libraries. 12345import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom tensorflow.python.framework import opsops.reset_default_graph() Next we create a graph session 1sess = tf.Session() We use the same method of generating data as in the prior recipe for consistency. 123# Create the datax_vals = np.linspace(0, 10, 100)y_vals = x_vals + np.random.normal(0, 1, 100) We generate the design matrix, $A$. 1234# Create design matrixx_vals_column = np.transpose(np.matrix(x_vals))ones_column = np.transpose(np.matrix(np.repeat(1, 100)))A = np.column_stack((x_vals_column, ones_column)) Next, we generate the 123456# Create y matrixy = np.transpose(np.matrix(y_vals))# Create tensorsA_tensor = tf.constant(A)y_tensor = tf.constant(y) Now we calculate the square of the matrix $A$ and the Cholesky decomposition. 123# Find Cholesky DecompositiontA_A = tf.matmul(tf.transpose(A_tensor), A_tensor)L = tf.cholesky(tA_A) We solve the first equation. (see step 2 in the intro paragraph above) 123# Solve L*y=t(A)*btA_y = tf.matmul(tf.transpose(A_tensor), y)sol1 = tf.matrix_solve(L, tA_y) We finally solve for the parameter matrix by solving the second equation (see step 3 in the intro paragraph). 1234# Solve L' * y = sol1sol2 = tf.matrix_solve(tf.transpose(L), sol1)solution_eval = sess.run(sol2) Extract the coefficients and create the best fit line. 1234567891011# Extract coefficientsslope = solution_eval[0][0]y_intercept = solution_eval[1][0]print('slope: ' + str(slope))print('y_intercept: ' + str(y_intercept))# Get best fit linebest_fit = []for i in x_vals: best_fit.append(slope*i+y_intercept) slope: 1.006032728766641 y_intercept: -0.0033007871888138603 Finally, we plot the fit with Matplotlib. 12345# Plot the resultsplt.plot(x_vals, y_vals, 'o', label='Data')plt.plot(x_vals, best_fit, 'r-', label='Best fit line', linewidth=3)plt.legend(loc='upper left')plt.show() 3. Linear Regression: The TensorFlow WayLearning the TensorFlow Way of Regression In this section we will implement linear regression as an iterative computational graph in TensorFlow. To make this more pertinent, instead of using generated data, we will instead use the Iris data set. Our x will be the Petal Width, our y will be the Sepal Length. Viewing the data in these two dimensions suggests a linear relationship. Model The the output of our model is a 2D linear regression: y = A * x + b The x matrix input will be a 2D matrix, where it’s dimensions will be (batch size x 1). The y target output will have the same dimensions, (batch size x 1). The loss function we will use will be the mean of the batch L2 Loss: loss = mean( (y_target - model_output)^2 ) We will then iterate through random batch size selections of the data.For this script, we introduce how to perform linear regression in the context of TensorFlow. We will solve the linear equation system: y = Ax + bWith the Sepal length (y) and Petal width (x) of the Iris data. Performing linear regression in TensorFlow is a lot easier than trying to understand Linear Algebra or Matrix decompositions for the prior two recipes. We will do the following: Create the linear regression computational graph output. This means we will accept an input, $x$, and generate the output, $Ax + b$. We create a loss function, the L2 loss, and use that output with the learning rate to compute the gradients of the model variables, $A$ and $b$ to minimize the loss. The benefit of using TensorFlow in this way is that the model can be routinely updated and tweaked with new data incrementally with any reasonable batch size of data. The more iterative we make our machine learning algorithms, the better. We start by loading the necessary libraries. 123456import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import opsops.reset_default_graph() We create a graph session. 1sess = tf.Session() Next we load the Iris data from the Scikit-Learn library. 12345# Load the data# iris.data = [(Sepal Length, Sepal Width, Petal Length, Petal Width)]iris = datasets.load_iris()x_vals = np.array([x[3] for x in iris.data])y_vals = np.array([y[0] for y in iris.data]) With most TensorFlow algorithms, we will need to declare a batch size for the placeholders and operations in the graph. Here, we set it to 25. We can set it to any integer between 1 and the size of the dataset. For the effect of batch size on the training, see Chapter 2: Batch vs Stochastic Training 12# Declare batch sizebatch_size = 25 We now initialize the placeholders and variables in the model. 1234567# Initialize placeholdersx_data = tf.placeholder(shape=[None, 1], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)# Create variables for linear regressionA = tf.Variable(tf.random_normal(shape=[1,1]))b = tf.Variable(tf.random_normal(shape=[1,1])) We add the model operations (linear model output) and the L2 loss. 12345# Declare model operationsmodel_output = tf.add(tf.matmul(x_data, A), b)# Declare loss function (L2 loss)loss = tf.reduce_mean(tf.square(y_target - model_output)) We have to tell TensorFlow how to optimize and back propagate the gradients. We do this with the standard Gradient Descent operator (tf.train.GradientDescentOptimizer), with the learning rate argument of $0.05$. Then we initialize all the model variables. 1234567# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.05)train_step = my_opt.minimize(loss)# Initialize variablesinit = tf.global_variables_initializer()sess.run(init) We start our training loop and run the optimizer for 100 iterations. 123456789101112# Training looploss_vec = []for i in range(100): rand_index = np.random.choice(len(x_vals), size=batch_size) rand_x = np.transpose([x_vals[rand_index]]) rand_y = np.transpose([y_vals[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss) if (i+1)%25==0: print('Step #' + str(i+1) + ' A = ' + str(sess.run(A)) + ' b = ' + str(sess.run(b))) print('Loss = ' + str(temp_loss)) Step #25 A = [[1.5073389]] b = [[3.7461321]] Loss = 0.53326994 Step #50 A = [[1.2745976]] b = [[4.1358175]] Loss = 0.42734933 Step #75 A = [[1.1166353]] b = [[4.4049253]] Loss = 0.29555324 Step #100 A = [[1.0541962]] b = [[4.5658007]] Loss = 0.23579143 We pull out the optimal coefficients and get the best fit line. 12345678# Get the optimal coefficients[slope] = sess.run(A)[y_intercept] = sess.run(b)# Get best fit linebest_fit = []for i in x_vals: best_fit.append(slope*i+y_intercept) Plot the results with Matplotlib. Along with the linear fit, we will also plot the L2 loss over the model training iterations. 123456789101112131415# Plot the resultplt.plot(x_vals, y_vals, 'o', label='Data Points')plt.plot(x_vals, best_fit, 'r-', label='Best fit line', linewidth=3)plt.legend(loc='upper left')plt.title('Sepal Length vs Petal Width')plt.xlabel('Petal Width')plt.ylabel('Sepal Length')plt.show()# Plot loss over timeplt.plot(loss_vec, 'k-')plt.title('L2 Loss per Generation')plt.xlabel('Generation')plt.ylabel('L2 Loss')plt.show() 4. Deming RegressionModel The model will be the same as regular linear regression: y = A * x + b Instead of measuring the vertical L2 distance, we will measure the shortest distance between the line and the predicted point in the loss function. loss = |y_target - (A * x_input + b)| / sqrt(A^2 + 1) This function shows how to use TensorFlow to solve linear Deming regression. $y = Ax + b$ We will use the iris data, specifically: y = Sepal Length and x = Petal Width. Deming regression is also called total least squares, in which we minimize the shortest distance from the predicted line and the actual (x,y) points. If least squares linear regression minimizes the vertical distance to the line, Deming regression minimizes the total distance to the line. This type of regression minimizes the error in the y values and the x values. See the below figure for a comparison. To implement this in TensorFlow, we start by loading the necessary libraries. 123456import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import opsops.reset_default_graph() Start a computational graph session: 12345sess = tf.Session()# Set a random seedtf.set_random_seed(42)np.random.seed(42) We load the iris data. 12345# Load the data# iris.data = [(Sepal Length, Sepal Width, Petal Length, Petal Width)]iris = datasets.load_iris()x_vals = np.array([x[3] for x in iris.data]) # Petal Widthy_vals = np.array([y[0] for y in iris.data]) # Sepal Length Next we declare the batch size, model placeholders, model variables, and model operations. 12345678910111213# Declare batch sizebatch_size = 125# Initialize placeholdersx_data = tf.placeholder(shape=[None, 1], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)# Create variables for linear regressionA = tf.Variable(tf.random_normal(shape=[1,1]))b = tf.Variable(tf.random_normal(shape=[1,1]))# Declare model operationsmodel_output = tf.add(tf.matmul(x_data, A), b) For the demming loss, we want to compute: \frac{\left| A \cdot x + b - y \right|}{\sqrt{A^{2} + 1}}Which will give us the shortest distance between a point (x,y) and the predicted line, $A \cdot x + b$. 1234# Declare Deming loss functiondeming_numerator = tf.abs(tf.subtract(tf.add(tf.matmul(x_data, A), b), y_target))deming_denominator = tf.sqrt(tf.add(tf.square(A),1))loss = tf.reduce_mean(tf.truediv(deming_numerator, deming_denominator)) Next we declare the optimization function and initialize all model variables. 1234567# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.25)train_step = my_opt.minimize(loss)# Initialize variablesinit = tf.global_variables_initializer()sess.run(init) Now we train our Deming regression for 250 iterations. 123456789101112# Training looploss_vec = []for i in range(1500): rand_index = np.random.choice(len(x_vals), size=batch_size) rand_x = np.transpose([x_vals[rand_index]]) rand_y = np.transpose([y_vals[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss) if (i+1)%100==0: print('Step #' + str(i+1) + ' A = ' + str(sess.run(A)) + ' b = ' + str(sess.run(b))) print('Loss = ' + str(temp_loss)) Step #100 A = [[3.0731559]] b = [[1.7809086]] Loss = 0.47353575 Step #200 A = [[2.4822469]] b = [[2.522591]] Loss = 0.41145653 Step #300 A = [[1.7613103]] b = [[3.6220071]] Loss = 0.37061805 Step #400 A = [[1.0064616]] b = [[4.5484953]] Loss = 0.26182547 Step #500 A = [[0.9593529]] b = [[4.610097]] Loss = 0.2435131 Step #600 A = [[0.9646577]] b = [[4.624607]] Loss = 0.26413646 Step #700 A = [[1.0198785]] b = [[4.6017494]] Loss = 0.2845798 Step #800 A = [[0.99521935]] b = [[4.6001368]] Loss = 0.27551532 Step #900 A = [[1.0415721]] b = [[4.6130023]] Loss = 0.2898117 Step #1000 A = [[1.0065476]] b = [[4.6437864]] Loss = 0.2525265 Step #1100 A = [[1.0090839]] b = [[4.6393313]] Loss = 0.27818772 Step #1200 A = [[0.9649767]] b = [[4.581815]] Loss = 0.25168285 Step #1300 A = [[1.006261]] b = [[4.5881867]] Loss = 0.25499973 Step #1400 A = [[1.0311592]] b = [[4.618432]] Loss = 0.2563808 Step #1500 A = [[0.9623312]] b = [[4.5966215]] Loss = 0.2465789 Retrieve the optimal coefficients (slope and intercept). 12345678# Get the optimal coefficients[slope] = sess.run(A)[y_intercept] = sess.run(b)# Get best fit linebest_fit = []for i in x_vals: best_fit.append(slope*i+y_intercept) Here is matplotlib code to plot the best fit Deming regression line and the Demming Loss. 123456789101112131415# Plot the resultplt.plot(x_vals, y_vals, 'o', label='Data Points')plt.plot(x_vals, best_fit, 'r-', label='Best fit line', linewidth=3)plt.legend(loc='upper left')plt.title('Sepal Length vs Petal Width')plt.xlabel('Petal Width')plt.ylabel('Sepal Length')plt.show()# Plot loss over timeplt.plot(loss_vec, 'k-')plt.title('Deming Loss per Generation')plt.xlabel('Iteration')plt.ylabel('Deming Loss')plt.show() 5. LASSO and Ridge RegressionThis function shows how to use TensorFlow to solve lasso or ridge regression for $\boldsymbol{y} = \boldsymbol{Ax} + \boldsymbol{b}$ We will use the iris data, specifically: $\boldsymbol{y}$ = Sepal Length, $\boldsymbol{x}$ = Petal Width 1234567# import required librariesimport matplotlib.pyplot as pltimport sysimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import ops 12# Specify 'Ridge' or 'LASSO'regression_type = 'LASSO' 12345# clear out old graphops.reset_default_graph()# Create graphsess = tf.Session() Load iris data 1234# iris.data = [(Sepal Length, Sepal Width, Petal Length, Petal Width)]iris = datasets.load_iris()x_vals = np.array([x[3] for x in iris.data])y_vals = np.array([y[0] for y in iris.data]) Model Parameters 123456789101112131415161718# Declare batch sizebatch_size = 50# Initialize placeholdersx_data = tf.placeholder(shape=[None, 1], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)# make results reproducibleseed = 13np.random.seed(seed)tf.set_random_seed(seed)# Create variables for linear regressionA = tf.Variable(tf.random_normal(shape=[1,1]))b = tf.Variable(tf.random_normal(shape=[1,1]))# Declare model operationsmodel_output = tf.add(tf.matmul(x_data, A), b) Loss Functions 1234567891011121314151617181920# Select appropriate loss function based on regression typeif regression_type == 'LASSO': # Declare Lasso loss function # Lasso Loss = L2_Loss + heavyside_step, # Where heavyside_step ~ 0 if A &lt; constant, otherwise ~ 99 lasso_param = tf.constant(0.9) heavyside_step = tf.truediv(1., tf.add(1., tf.exp(tf.multiply(-50., tf.subtract(A, lasso_param))))) regularization_param = tf.multiply(heavyside_step, 99.) loss = tf.add(tf.reduce_mean(tf.square(y_target - model_output)), regularization_param)elif regression_type == 'Ridge': # Declare the Ridge loss function # Ridge loss = L2_loss + L2 norm of slope ridge_param = tf.constant(1.) ridge_loss = tf.reduce_mean(tf.square(A)) loss = tf.expand_dims(tf.add(tf.reduce_mean(tf.square(y_target - model_output)), tf.multiply(ridge_param, ridge_loss)), 0)else: print('Invalid regression_type parameter value',file=sys.stderr) Optimizer 123# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.001)train_step = my_opt.minimize(loss) Run regression 1234567891011121314151617# Initialize variablesinit = tf.global_variables_initializer()sess.run(init)# Training looploss_vec = []for i in range(1500): rand_index = np.random.choice(len(x_vals), size=batch_size) rand_x = np.transpose([x_vals[rand_index]]) rand_y = np.transpose([y_vals[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss[0]) if (i+1)%300==0: print('Step #' + str(i+1) + ' A = ' + str(sess.run(A)) + ' b = ' + str(sess.run(b))) print('Loss = ' + str(temp_loss)) print('\n') Step #300 A = [[0.7717163]] b = [[1.8247688]] Loss = [[10.26617]] Step #600 A = [[0.75910366]] b = [[3.2217226]] Loss = [[3.059304]] Step #900 A = [[0.74844867]] b = [[3.9971633]] Loss = [[1.2329929]] Step #1200 A = [[0.73754]] b = [[4.429276]] Loss = [[0.57923675]] Step #1500 A = [[0.72945035]] b = [[4.672014]] Loss = [[0.40877518]] Extract regression results 12345678# Get the optimal coefficients[slope] = sess.run(A)[y_intercept] = sess.run(b)# Get best fit linebest_fit = []for i in x_vals: best_fit.append(slope*i+y_intercept) Plot results 12345678910111213141516%matplotlib inline# Plot the resultplt.plot(x_vals, y_vals, 'o', label='Data Points')plt.plot(x_vals, best_fit, 'r-', label='Best fit line', linewidth=3)plt.legend(loc='upper left')plt.title('Sepal Length vs Pedal Width')plt.xlabel('Pedal Width')plt.ylabel('Sepal Length')plt.show()# Plot loss over timeplt.plot(loss_vec, 'k-')plt.title(regression_type + ' Loss per Generation')plt.xlabel('Generation')plt.ylabel('Loss')plt.show() 6. Elastic Net RegressionThis function shows how to use TensorFlow to solve elastic net regression.$y = Ax + b$ Setup model12345678910111213141516171819202122232425262728293031# make results reproducibleseed = 13np.random.seed(seed)tf.set_random_seed(seed)# Declare batch sizebatch_size = 50# Initialize placeholdersx_data = tf.placeholder(shape=[None, 3], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)# Create variables for linear regressionA = tf.Variable(tf.random_normal(shape=[3,1]))b = tf.Variable(tf.random_normal(shape=[1,1]))# Declare model operationsmodel_output = tf.add(tf.matmul(x_data, A), b)# Declare the elastic net loss functionelastic_param1 = tf.constant(1.)elastic_param2 = tf.constant(1.)l1_a_loss = tf.reduce_mean(tf.abs(A))l2_a_loss = tf.reduce_mean(tf.square(A))e1_term = tf.multiply(elastic_param1, l1_a_loss)e2_term = tf.multiply(elastic_param2, l2_a_loss)loss = tf.expand_dims(tf.add(tf.add(tf.reduce_mean(tf.square(y_target - model_output)), e1_term), e2_term), 0)# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.001)train_step = my_opt.minimize(loss) 7. Logistic RegressionImplementing Logistic Regression Logistic regression is a way to predict a number between zero or one (usually we consider the output a probability). This prediction is classified into class value ‘1’ if the prediction is above a specified cut off value and class ‘0’ otherwise. The standard cutoff is 0.5. For the purpose of this example, we will specify that cut off to be 0.5, which will make the classification as simple as rounding the output. The data we will use for this example will be the UMASS low birth weight data. Model The the output of our model is the standard logistic regression: y = sigmoid(A * x + b) The x matrix input will have dimensions (batch size x # features). The y target output will have the dimension batch size x 1. The loss function we will use will be the mean of the cross-entropy loss: loss = mean( - y log(predicted) + (1-y) log(1-predicted) ) TensorFlow has this cross entropy built in, and we can use the function, ‘tf.nn.sigmoid_cross_entropy_with_logits()’ We will then iterate through random batch size selections of the data. This function shows how to use TensorFlow to solve logistic regression.$ \textbf{y} = sigmoid(\textbf{A}\times \textbf{x} + \textbf{b})$ We will use the low birth weight data, specifically:12# y = 0 or 1 = low birth weight# x = demographic and medical history data 1234567import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tfimport requestsfrom tensorflow.python.framework import opsimport os.pathimport csv 1234ops.reset_default_graph()# Create graphsess = tf.Session() Obtain and prepare data for modeling 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556# name of data filebirth_weight_file = 'birth_weight.csv'# download data and create data file if file does not exist in current directoryif not os.path.exists(birth_weight_file): birthdata_url = 'https://github.com/nfmcclure/tensorflow_cookbook/' + \ 'raw/master/01_Introduction/07_Working_with_Data_Sources/birthweight_data/birthweight.dat' birth_file = requests.get(birthdata_url) birth_data = birth_file.text.split('\r\n') birth_header = birth_data[0].split('\t') birth_data = [[float(x) for x in y.split('\t') if len(x)&gt;=1] for y in birth_data[1:] if len(y)&gt;=1] with open(birth_weight_file, 'w', newline='') as f: writer = csv.writer(f) writer.writerow(birth_header) writer.writerows(birth_data) f.close()# read birth weight data into memorybirth_data = []with open(birth_weight_file, newline='') as csvfile: csv_reader = csv.reader(csvfile) birth_header = next(csv_reader) for row in csv_reader: birth_data.append(row)birth_data = [[float(x) for x in row] for row in birth_data]# Pull out target variabley_vals = np.array([x[0] for x in birth_data])# Pull out predictor variables (not id, not target, and not birthweight)x_vals = np.array([x[1:8] for x in birth_data])# set for reproducible resultsseed = 99np.random.seed(seed)tf.set_random_seed(seed)# Split data into train/test = 80%/20%train_indices = np.random.choice(len(x_vals), round(len(x_vals)*0.8), replace=False)test_indices = np.array(list(set(range(len(x_vals))) - set(train_indices)))x_vals_train = x_vals[train_indices]x_vals_test = x_vals[test_indices]y_vals_train = y_vals[train_indices]y_vals_test = y_vals[test_indices]# Normalize by column (min-max norm)def normalize_cols(m, col_min=np.array([None]), col_max=np.array([None])): if not col_min[0]: col_min = m.min(axis=0) if not col_max[0]: col_max = m.max(axis=0) return (m-col_min) / (col_max - col_min), col_min, col_maxx_vals_train, train_min, train_max = np.nan_to_num(normalize_cols(x_vals_train))x_vals_test, _, _ = np.nan_to_num(normalize_cols(x_vals_test, train_min, train_max)) Define Tensorflow computational graph 1234567891011121314151617181920# Declare batch sizebatch_size = 25# Initialize placeholdersx_data = tf.placeholder(shape=[None, 7], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)# Create variables for linear regressionA = tf.Variable(tf.random_normal(shape=[7,1]))b = tf.Variable(tf.random_normal(shape=[1,1]))# Declare model operationsmodel_output = tf.add(tf.matmul(x_data, A), b)# Declare loss function (Cross Entropy loss)loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=model_output, labels=y_target))# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.01)train_step = my_opt.minimize(loss) Train model 123456789101112131415161718192021222324252627# Initialize variablesinit = tf.global_variables_initializer()sess.run(init)# Actual Predictionprediction = tf.round(tf.sigmoid(model_output))predictions_correct = tf.cast(tf.equal(prediction, y_target), tf.float32)accuracy = tf.reduce_mean(predictions_correct)# Training looploss_vec = []train_acc = []test_acc = []for i in range(1500): rand_index = np.random.choice(len(x_vals_train), size=batch_size) rand_x = x_vals_train[rand_index] rand_y = np.transpose([y_vals_train[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss) temp_acc_train = sess.run(accuracy, feed_dict=&#123;x_data: x_vals_train, y_target: np.transpose([y_vals_train])&#125;) train_acc.append(temp_acc_train) temp_acc_test = sess.run(accuracy, feed_dict=&#123;x_data: x_vals_test, y_target: np.transpose([y_vals_test])&#125;) test_acc.append(temp_acc_test) if (i+1)%300==0: print('Loss = ' + str(temp_loss)) Loss = 0.6944471 Loss = 0.7304496 Loss = 0.62496805 Loss = 0.69695 Loss = 0.6096429 Display model performance 12345678910111213141516%matplotlib inline# Plot loss over timeplt.plot(loss_vec, 'k-')plt.title('Cross Entropy Loss per Generation')plt.xlabel('Generation')plt.ylabel('Cross Entropy Loss')plt.show()# Plot train and test accuracyplt.plot(train_acc, 'k-', label='Train Set Accuracy')plt.plot(test_acc, 'r--', label='Test Set Accuracy')plt.title('Train and Test Accuracy')plt.xlabel('Generation')plt.ylabel('Accuracy')plt.legend(loc='lower right')plt.show()]]></content>
      <categories>
        <category>机器学习</category>
        <category>线性回归</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[最近邻方法 Nearest Neighbor Methords]]></title>
    <url>%2F2018%2F11%2F23%2F%E6%9C%80%E8%BF%91%E9%82%BB%E7%AE%97%E6%B3%95%2F</url>
    <content type="text"><![CDATA[最近邻回归 Nearest neighbor regression首先回归和分类最要得区别就是：回归的目标数据是连续的，分类的目标数据是离散的。最近邻回归的原理是从训练样本中找到与新点在距离上最近的预定数量的几个点，并从这些点中预测标签。 这些点的数量可以是用户自定义的常量（K-最近邻学习），也可以根据不同的点的局部密度（基于半径的最近邻学习）。距离通常可以通过任何方式来度量： standard Euclidean distance（标准欧式距离）是最常见的选择。Neighbors-based（基于邻居的）方法被称为 非泛化 机器学习方法， 因为它们只是简单地”记住”了其所有的训练数据（可能转换为一个快速索引结构，如 Ball Tree或 KD Tree） Nearest Neighbor MethordsNearest Neighbor methods are a very popular ML algorithm. We show how to implement k-Nearest Neighbors, weighted k-Nearest Neighbors, and k-Nearest Neighbors with mixed distance functions. In this chapter we also show how to use the Levenshtein distance (edit distance) in TensorFlow, and use it to calculate the distance between strings. We end this chapter with showing how to use k-Nearest Neighbors for categorical prediction with the MNIST handwritten digit recognition. Nearest neighbor methods are based on a distance-based conceptual idea. We consider our training set as the model and make predictions on new points based on how close they are to points in the training set. A naïve way is to make the prediction as the closest training data point class. But since most datasets contain a degree of noise, a more common method would be to take a weighted average of a set of k nearest neighbors. This method is called k-nearest neighbors (k-NN). Given a training dataset (x1, x2, …, xn), with corresponding targets (y1, y2, …, yn), we can make a prediction on a point, z, by looking at a set of nearest neighbors. The actual method of prediction depends on whether or not we are doing regression (continuous y) or classification (discrete y). For discrete classification targets, the prediction may be given by a maximum voting scheme weighted by the distance to the prediction point: prediction(z) = max ( weighted sum of distances of points in each class ) see jupyter notebook for the formula Here, our prediction is the maximum weighted value over all classes (j), where the weighted distance from the prediction point is usually given by the L1 or L2 distance functions. Continuous targets are very similar, but we usually just compute a weighted average of the target variable (y) by distance. There are many different specifications of distance metrics that we can choose. In this chapter, we will explore the L1 and L2 metrics as well as edit and textual distances. We also have to choose how to weight the distances. A straight forward way to weight the distances is by the distance itself. Points that are further away from our prediction should have less impact than nearer points. The most common way to weight is by the normalized inverse of the distance. We will implement this method in the next recipe. Note that k-NN is an aggregating method. For regression, we are performing a weighted average of neighbors. Because of this, predictions will be less extreme and less varied than the actual targets. The magnitude of this effect will be determined by k, the number of neighbors in the algorithm. 1. k-Nearest NeighborThis function illustrates how to use k-nearest neighbors in tensorflow We will use the 1970s Boston housing dataset which is available through the UCI ML data repository. Data:—————x-values—————- CRIM : per capita crime rate by town ZN : prop. of res. land zones INDUS : prop. of non-retail business acres CHAS : Charles river dummy variable NOX : nitrix oxides concentration / 10 M RM : Avg. # of rooms per building AGE : prop. of buildings built prior to 1940 DIS : Weighted distances to employment centers RAD : Index of radian highway access TAX : Full tax rate value per $10k PTRATIO: Pupil/Teacher ratio by town B : 1000*(Bk-0.63)^2, Bk=prop. of blacks LSTAT : % lower status of pop ——————y-value—————- MEDV : Median Value of homes in $1,000’s 1234567# import required librariesimport matplotlib.pyplot as pltimport numpy as npimport tensorflow as tfimport requestsfrom tensorflow.python.framework import opsops.reset_default_graph() Create graph1sess = tf.Session() Load the data123456789101112housing_url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/housing/housing.data'housing_header = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']cols_used = ['CRIM', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'TAX', 'PTRATIO', 'B', 'LSTAT']num_features = len(cols_used)housing_file = requests.get(housing_url)housing_data = [[float(x) for x in y.split(' ') if len(x)&gt;=1] for y in housing_file.text.split('\n') if len(y)&gt;=1]y_vals = np.transpose([np.array([y[13] for y in housing_data])])x_vals = np.array([[x for i,x in enumerate(y) if housing_header[i] in cols_used] for y in housing_data])## Min-Max Scalingx_vals = (x_vals - x_vals.min(0)) / x_vals.ptp(0) 1x_vals.shape (506, 10) 1y_vals.shape (506, 1) Split the data into train and test sets1234567np.random.seed(13) #make results reproducibletrain_indices = np.random.choice(len(x_vals), round(len(x_vals)*0.8), replace=False)test_indices = np.array(list(set(range(len(x_vals))) - set(train_indices)))x_vals_train = x_vals[train_indices]x_vals_test = x_vals[test_indices]y_vals_train = y_vals[train_indices]y_vals_test = y_vals[test_indices] Parameters to control run123456789# Declare k-value and batch sizek = 4batch_size=len(x_vals_test)# Placeholdersx_data_train = tf.placeholder(shape=[None, num_features], dtype=tf.float32)x_data_test = tf.placeholder(shape=[None, num_features], dtype=tf.float32)y_target_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)y_target_test = tf.placeholder(shape=[None, 1], dtype=tf.float32) Declare distance metricL1 Distance MetricUncomment following line and comment L2 1distance = tf.reduce_sum(tf.abs(tf.subtract(x_data_train, tf.expand_dims(x_data_test,1))), axis=2) L2 Distance MetricUncomment following line and comment L1 above 1#distance = tf.sqrt(tf.reduce_sum(tf.square(tf.subtract(x_data_train, tf.expand_dims(x_data_test,1))), reduction_indices=1)) Predict: Get min distance index (Nearest neighbor) 12345678910111213141516171819202122232425262728#prediction = tf.arg_min(distance, 0)top_k_xvals, top_k_indices = tf.nn.top_k(tf.negative(distance), k=k)top_k_xvals = tf.truediv(1.0, top_k_xvals)x_sums = tf.expand_dims(tf.reduce_sum(top_k_xvals, 1),1)x_sums_repeated = tf.matmul(x_sums,tf.ones([1, k], tf.float32))x_val_weights = tf.expand_dims(tf.div(top_k_xvals,x_sums_repeated), 1)top_k_yvals = tf.gather(y_target_train, top_k_indices)prediction = tf.squeeze(tf.matmul(x_val_weights,top_k_yvals), axis=[1])#prediction = tf.reduce_mean(top_k_yvals, 1)# Calculate MSEmse = tf.div(tf.reduce_sum(tf.square(tf.subtract(prediction, y_target_test))), batch_size)# Calculate how many loops over training datanum_loops = int(np.ceil(len(x_vals_test)/batch_size))for i in range(num_loops): min_index = i*batch_size max_index = min((i+1)*batch_size,len(x_vals_train)) x_batch = x_vals_test[min_index:max_index] y_batch = y_vals_test[min_index:max_index] predictions = sess.run(prediction, feed_dict=&#123;x_data_train: x_vals_train, x_data_test: x_batch, y_target_train: y_vals_train, y_target_test: y_batch&#125;) batch_mse = sess.run(mse, feed_dict=&#123;x_data_train: x_vals_train, x_data_test: x_batch, y_target_train: y_vals_train, y_target_test: y_batch&#125;) print('Batch #' + str(i+1) + ' MSE: ' + str(np.round(batch_mse,3))) Batch #1 MSE: 10.625 1234567891011%matplotlib inline# Plot prediction and actual distributionbins = np.linspace(5, 50, 45)plt.hist(predictions, bins, alpha=0.5, label='Prediction')plt.hist(y_batch, bins, alpha=0.5, label='Actual')plt.title('Histogram of Predicted and Actual Values')plt.xlabel('Med Home Value in $1,000s')plt.ylabel('Frequency')plt.legend(loc='upper right')plt.show() 2. MNIST Digit Prediction with k-Nearest NeighborsThis script will load the MNIST data, and split it into test/train and perform prediction with nearest neighbors. For each test integer, we will return the closest image/integer. Integer images are represented as 28x28 matrices of floating point numbers. 12345678import randomimport numpy as npimport tensorflow as tfimport matplotlib.pyplot as pltfrom PIL import Imagefrom tensorflow.examples.tutorials.mnist import input_datafrom tensorflow.python.framework import opsops.reset_default_graph() Create graph1sess = tf.Session() Load the data1mnist = input_data.read_data_sets("MNIST_data", one_hot=True) Generate random sample123456789np.random.seed(13) # set seed for reproducibilitytrain_size = 1000test_size = 102rand_train_indices = np.random.choice(len(mnist.train.images), train_size, replace=False)rand_test_indices = np.random.choice(len(mnist.test.images), test_size, replace=False)x_vals_train = mnist.train.images[rand_train_indices]x_vals_test = mnist.test.images[rand_test_indices]y_vals_train = mnist.train.labels[rand_train_indices]y_vals_test = mnist.test.labels[rand_test_indices] Declare k-value and batch size12345678k = 4batch_size=6# Placeholdersx_data_train = tf.placeholder(shape=[None, 784], dtype=tf.float32)x_data_test = tf.placeholder(shape=[None, 784], dtype=tf.float32)y_target_train = tf.placeholder(shape=[None, 10], dtype=tf.float32)y_target_test = tf.placeholder(shape=[None, 10], dtype=tf.float32) Declare distance metricL1 metric - uncomment following line and comment L2 metric below1distance = tf.reduce_sum(tf.abs(tf.subtract(x_data_train, tf.expand_dims(x_data_test,1))), axis=2) L2 metric - uncomment following line and comment the L1 metric above1#distance = tf.sqrt(tf.reduce_sum(tf.square(tf.subtract(x_data_train, tf.expand_dims(x_data_test,1))), reduction_indices=1)) Predict: Get min distance index (Nearest neighbor)12345678910111213141516171819202122232425# Get min distance index (Nearest neighbor)top_k_xvals, top_k_indices = tf.nn.top_k(tf.negative(distance), k=k)prediction_indices = tf.gather(y_target_train, top_k_indices)# Predict the mode categorycount_of_predictions = tf.reduce_sum(prediction_indices, axis=1)prediction = tf.argmax(count_of_predictions, axis=1)# Calculate how many loops over training datanum_loops = int(np.ceil(len(x_vals_test)/batch_size))test_output = []actual_vals = []for i in range(num_loops): min_index = i*batch_size max_index = min((i+1)*batch_size,len(x_vals_train)) x_batch = x_vals_test[min_index:max_index] y_batch = y_vals_test[min_index:max_index] predictions = sess.run(prediction, feed_dict=&#123;x_data_train: x_vals_train, x_data_test: x_batch, y_target_train: y_vals_train, y_target_test: y_batch&#125;) test_output.extend(predictions) actual_vals.extend(np.argmax(y_batch, axis=1))accuracy = sum([1./test_size for i in range(test_size) if test_output[i]==actual_vals[i]])print('Accuracy on test set: ' + str(accuracy)) Accuracy on test set: 0.8823529411764696 1234567891011121314%matplotlib inline# Plot the last batch results:actuals = np.argmax(y_batch, axis=1)Nrows = 2Ncols = 3for i in range(len(actuals)): plt.subplot(Nrows, Ncols, i+1) plt.imshow(np.reshape(x_batch[i], [28,28]), cmap='Greys_r') plt.title('Actual: ' + str(actuals[i]) + ' Pred: ' + str(predictions[i]), fontsize=10) frame = plt.gca() frame.axes.get_xaxis().set_visible(False) frame.axes.get_yaxis().set_visible(False) 3. Text DistancesThis notebook illustrates how to use the Levenstein distance (edit distance) in TensorFlow. Get required libarary and start tensorflow session. 123import tensorflow as tfsess = tf.Session() First compute the edit distance between ‘bear’ and ‘beers’1234567891011hypothesis = list('bear')truth = list('beers')h1 = tf.SparseTensor([[0,0,0], [0,0,1], [0,0,2], [0,0,3]], hypothesis, [1,1,1])t1 = tf.SparseTensor([[0,0,0], [0,0,1], [0,0,2], [0,0,3],[0,0,4]], truth, [1,1,1])print(sess.run(tf.edit_distance(h1, t1, normalize=False))) [[2.]] Compute the edit distance between (‘bear’,’beer’) and ‘beers’:1234567891011hypothesis2 = list('bearbeer')truth2 = list('beersbeers')h2 = tf.SparseTensor([[0,0,0], [0,0,1], [0,0,2], [0,0,3], [0,1,0], [0,1,1], [0,1,2], [0,1,3]], hypothesis2, [1,2,4])t2 = tf.SparseTensor([[0,0,0], [0,0,1], [0,0,2], [0,0,3], [0,0,4], [0,1,0], [0,1,1], [0,1,2], [0,1,3], [0,1,4]], truth2, [1,2,5])print(sess.run(tf.edit_distance(h2, t2, normalize=True))) [[0.4 0.2]] Now compute distance between four words and ‘beers’ more efficiently:12345678910111213141516hypothesis_words = ['bear','bar','tensor','beers']truth_word = ['beers']num_h_words = len(hypothesis_words)h_indices = [[xi, 0, yi] for xi,x in enumerate(hypothesis_words) for yi,y in enumerate(x)]h_chars = list(''.join(hypothesis_words))h3 = tf.SparseTensor(h_indices, h_chars, [num_h_words,1,1])truth_word_vec = truth_word*num_h_wordst_indices = [[xi, 0, yi] for xi,x in enumerate(truth_word_vec) for yi,y in enumerate(x)]t_chars = list(''.join(truth_word_vec))t3 = tf.SparseTensor(t_indices, t_chars, [num_h_words,1,1])print(sess.run(tf.edit_distance(h3, t3, normalize=True))) [[0.4] [0.6] [1. ] [0. ]] 4. Mixed Distance Functions for k-Nearest NeighborThis function shows how to use different distance metrics on different features for kNN. Data:—————x-values—————- CRIM : per capita crime rate by town ZN : prop. of res. land zones INDUS : prop. of non-retail business acres CHAS : Charles river dummy variable NOX : nitrix oxides concentration / 10 M RM : Avg. # of rooms per building AGE : prop. of buildings built prior to 1940 DIS : Weighted distances to employment centers RAD : Index of radian highway access TAX : Full tax rate value per $10k PTRATIO: Pupil/Teacher ratio by town B : 1000*(Bk-0.63)^2, Bk=prop. of blacks LSTAT : % lower status of pop ——————y-value—————- MEDV : Median Value of homes in $1,000’s 123456import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tfimport requestsfrom tensorflow.python.framework import opsops.reset_default_graph() Create graph1sess = tf.Session() Load the data12345678910111213141516171819202122232425housing_url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/housing/housing.data'housing_header = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']cols_used = ['CRIM', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'TAX', 'PTRATIO', 'B', 'LSTAT']num_features = len(cols_used)housing_file = requests.get(housing_url)housing_data = [[float(x) for x in y.split(' ') if len(x)&gt;=1] for y in housing_file.text.split('\n') if len(y)&gt;=1]y_vals = np.transpose([np.array([y[13] for y in housing_data])])x_vals = np.array([[x for i,x in enumerate(y) if housing_header[i] in cols_used] for y in housing_data])## Min-Max Scalingx_vals = (x_vals - x_vals.min(0)) / x_vals.ptp(0)## Create distance metric weight matrix weighted by standard deviationweight_diagonal = x_vals.std(0)weight_matrix = tf.cast(tf.diag(weight_diagonal), dtype=tf.float32)# Split the data into train and test setsnp.random.seed(13) #make results reproducibletrain_indices = np.random.choice(len(x_vals), round(len(x_vals)*0.8), replace=False)test_indices = np.array(list(set(range(len(x_vals))) - set(train_indices)))x_vals_train = x_vals[train_indices]x_vals_test = x_vals[test_indices]y_vals_train = y_vals[train_indices]y_vals_test = y_vals[test_indices] Declare k-value and batch size12345678k = 4batch_size=len(x_vals_test)# Placeholdersx_data_train = tf.placeholder(shape=[None, num_features], dtype=tf.float32)x_data_test = tf.placeholder(shape=[None, num_features], dtype=tf.float32)y_target_train = tf.placeholder(shape=[None, 1], dtype=tf.float32)y_target_test = tf.placeholder(shape=[None, 1], dtype=tf.float32) 1234567# Declare weighted distance metric# Weighted - L2 = sqrt((x-y)^T * A * (x-y))subtraction_term = tf.subtract(x_data_train, tf.expand_dims(x_data_test,1))first_product = tf.matmul(subtraction_term, tf.tile(tf.expand_dims(weight_matrix,0), [batch_size,1,1]))second_product = tf.matmul(first_product, tf.transpose(subtraction_term, perm=[0,2,1]))# matrix_diag_part(...): Returns the batched diagonal part of a batched tensor.distance = tf.sqrt(tf.matrix_diag_part(second_product)) Predict: Get min distance index (Nearest neighbor)12345678910111213141516171819202122232425top_k_xvals, top_k_indices = tf.nn.top_k(tf.negative(distance), k=k)x_sums = tf.expand_dims(tf.reduce_sum(top_k_xvals, 1),1)x_sums_repeated = tf.matmul(x_sums,tf.ones([1, k], tf.float32))x_val_weights = tf.expand_dims(tf.div(top_k_xvals,x_sums_repeated), 1)top_k_yvals = tf.gather(y_target_train, top_k_indices)prediction = tf.squeeze(tf.matmul(x_val_weights,top_k_yvals), axis=[1])# Calculate MSEmse = tf.div(tf.reduce_sum(tf.square(tf.subtract(prediction, y_target_test))), batch_size)# Calculate how many loops over training datanum_loops = int(np.ceil(len(x_vals_test)/batch_size))for i in range(num_loops): min_index = i*batch_size max_index = min((i+1)*batch_size,len(x_vals_train)) x_batch = x_vals_test[min_index:max_index] y_batch = y_vals_test[min_index:max_index] predictions = sess.run(prediction, feed_dict=&#123;x_data_train: x_vals_train, x_data_test: x_batch, y_target_train: y_vals_train, y_target_test: y_batch&#125;) batch_mse = sess.run(mse, feed_dict=&#123;x_data_train: x_vals_train, x_data_test: x_batch, y_target_train: y_vals_train, y_target_test: y_batch&#125;) print('Batch #' + str(i+1) + ' MSE: ' + str(np.round(batch_mse,3))) Batch #1 MSE: 18.847 1234567891011%matplotlib inline# Plot prediction and actual distributionbins = np.linspace(5, 50, 45)plt.hist(predictions, bins, alpha=0.5, label='Prediction')plt.hist(y_batch, bins, alpha=0.5, label='Actual')plt.title('Histogram of Predicted and Actual Values')plt.xlabel('Med Home Value in $1,000s')plt.ylabel('Frequency')plt.legend(loc='upper right')plt.show() 5. Address Matching with k-Nearest NeighborsThis function illustrates a way to perform address matching between two data sets. For each test address, we will return the closest reference address to it. We will consider two distance functions: Edit distance for street number/name and Euclidian distance (L2) for the zip codes 123456import randomimport stringimport numpy as npimport tensorflow as tffrom tensorflow.python.framework import opsops.reset_default_graph() First we generate the data sets we will need1234567891011121314151617181920212223242526272829# n = Size of created data setsn = 10street_names = ['abbey', 'baker', 'canal', 'donner', 'elm']street_types = ['rd', 'st', 'ln', 'pass', 'ave']random.seed(31) #make results reproduciblerand_zips = [random.randint(65000,65999) for i in range(5)]# Function to randomly create one typo in a string w/ a probabilitydef create_typo(s, prob=0.75): if random.uniform(0,1) &lt; prob: rand_ind = random.choice(range(len(s))) s_list = list(s) s_list[rand_ind]=random.choice(string.ascii_lowercase) s = ''.join(s_list) return(s)# Generate the reference datasetnumbers = [random.randint(1, 9999) for i in range(n)]streets = [random.choice(street_names) for i in range(n)]street_suffs = [random.choice(street_types) for i in range(n)]zips = [random.choice(rand_zips) for i in range(n)]full_streets = [str(x) + ' ' + y + ' ' + z for x,y,z in zip(numbers, streets, street_suffs)]reference_data = [list(x) for x in zip(full_streets,zips)]# Generate test dataset with some typostypo_streets = [create_typo(x) for x in streets]typo_full_streets = [str(x) + ' ' + y + ' ' + z for x,y,z in zip(numbers, typo_streets, street_suffs)]test_data = [list(x) for x in zip(typo_full_streets,zips)] Now we can perform address matching1234567891011121314151617181920212223242526272829303132333435# Create graphsess = tf.Session()# Placeholderstest_address = tf.sparse_placeholder( dtype=tf.string)test_zip = tf.placeholder(shape=[None, 1], dtype=tf.float32)ref_address = tf.sparse_placeholder(dtype=tf.string)ref_zip = tf.placeholder(shape=[None, n], dtype=tf.float32)# Declare Zip code distance for a test zip and reference setzip_dist = tf.square(tf.subtract(ref_zip, test_zip))# Declare Edit distance for addressaddress_dist = tf.edit_distance(test_address, ref_address, normalize=True)# Create similarity scoreszip_max = tf.gather(tf.squeeze(zip_dist), tf.argmax(zip_dist, 1))zip_min = tf.gather(tf.squeeze(zip_dist), tf.argmin(zip_dist, 1))zip_sim = tf.div(tf.subtract(zip_max, zip_dist), tf.subtract(zip_max, zip_min))address_sim = tf.subtract(1., address_dist)# Combine distance functionsaddress_weight = 0.5zip_weight = 1. - address_weightweighted_sim = tf.add(tf.transpose(tf.multiply(address_weight, address_sim)), tf.multiply(zip_weight, zip_sim))# Predict: Get max similarity entrytop_match_index = tf.argmax(weighted_sim, 1)# Function to Create a character-sparse tensor from stringsdef sparse_from_word_vec(word_vec): num_words = len(word_vec) indices = [[xi, 0, yi] for xi,x in enumerate(word_vec) for yi,y in enumerate(x)] chars = list(''.join(word_vec)) return(tf.SparseTensorValue(indices, chars, [num_words,1,1])) 12345678910111213141516171819202122232425# Loop through test indicesreference_addresses = [x[0] for x in reference_data]reference_zips = np.array([[x[1] for x in reference_data]])# Create sparse address reference setsparse_ref_set = sparse_from_word_vec(reference_addresses)for i in range(n): test_address_entry = test_data[i][0] test_zip_entry = [[test_data[i][1]]] # Create sparse address vectors test_address_repeated = [test_address_entry] * n sparse_test_set = sparse_from_word_vec(test_address_repeated) feeddict=&#123;test_address: sparse_test_set, test_zip: test_zip_entry, ref_address: sparse_ref_set, ref_zip: reference_zips&#125; best_match = sess.run(top_match_index, feed_dict=feeddict) best_street = reference_addresses[best_match[0]] [best_zip] = reference_zips[0][best_match] [[test_zip_]] = test_zip_entry print('Address: ' + str(test_address_entry) + ', ' + str(test_zip_)) print('Match : ' + str(best_street) + ', ' + str(best_zip)) Address: 2308 bakar rd, 65480 Match : 2308 baker rd, 65480 Address: 709 bakeo pass, 65480 Match : 709 baker pass, 65480 Address: 2273 glm ln, 65782 Match : 2273 elm ln, 65782 Address: 1843 donner st, 65402 Match : 1843 donner st, 65402 Address: 8769 klm st, 65402 Match : 8769 elm st, 65402 Address: 3798 dpnner ln, 65012 Match : 3798 donner ln, 65012 Address: 2288 bajer pass, 65012 Match : 2288 baker pass, 65012 Address: 2416 epm ln, 65480 Match : 2416 elm ln, 65480 Address: 543 abgey ave, 65115 Match : 543 abbey ave, 65115 Address: 994 abbey st, 65480 Match : 994 abbey st, 65480]]></content>
      <categories>
        <category>机器学习</category>
        <category>最近邻算法</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[支持向量机]]></title>
    <url>%2F2018%2F11%2F22%2F%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%9C%BA%2F</url>
    <content type="text"><![CDATA[经典支持向量机 Support Vector Machines在机器学习中，支持向量机是在分类与回归分析中分析数据的监督式学习模型与相关的学习算法。给定一组训练实例，每个训练实例被标记为属于两个类别中的一个或另一个，SVM训练算法创建一个将新的实例分配给两个类别之一的模型，使其成为非概率二元线性分类器。SVM模型是将实例表示为空间中的点，这样映射就使得单独类别的实例被尽可能宽的明显的间隔分开。然后，将新的实例映射到同一空间，并基于它们落在间隔的哪一侧来预测所属类别。 个人建议学习支持向量机的方法： 熟读理论 支持向量机通俗导论（理解SVM的三层境界）LaTeX最新版_2015.1.9 PDF 应用支持向量机解决实际问题 支持向量机资源 标题 说明 附加 支持向量机通俗导论（理解SVM的三层境界） 支持向量机通俗导论（理解SVM的三层境界）LaTeX最新版_2015.1.9 PDF 支持向量机(SVM)是什么意思？ 知乎 学习SVM，这篇文章就够了！（附详细代码） 贪心科技 20181017 TensorFlow Machine Learning Cookbook 04_Support_Vector_Machines 201702 Hands-on Machine Learning with Scikit-Learn and TensorFlow 05_support_vector_machines.ipynb 201705 Hands-on Machine Learning with Scikit-Learn and TensorFlow 中文版 五、支持向量机 支持向量机的序列最小最优化算法SMO实现 20170409 点到直线距离公式 Support Vector MachinesThis chapter shows how to implement various SVM methods with TensorFlow. We first create a linear SVM and also show how it can be used for regression. We then introduce kernels (RBF Gaussian kernel) and show how to use it to split up non-linear data. We finish with a multi-dimensional implementation of non-linear SVMs to work with multiple classes. 1. Linear Support Vector Machine: Soft MarginModelWe will aim to maximize the margin width, 2/||A||, or minimize ||A||. We allow for a soft margin by having an error term in the loss function which is the max(0, 1-pred*actual). This function shows how to use TensorFlow to create a soft margin SVMWe will use the iris data, specifically: $x_1 =$ Sepal Length $x_2 =$ Petal Width Class 1 : I. setosa Class -1: not I. setosa We know here that x and y are linearly seperable for I. setosa classification. Note that we implement the soft margin with an allowable margin of error for points. The margin of error term is given by ‘alpha’ below. To behave like a hard margin SVM, set alpha = 0. (in notebook code block #7) 123456import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import opsops.reset_default_graph() Set a random seed and start a computational graph. 123np.random.seed(41)tf.set_random_seed(41)sess = tf.Session() Load the data 1234# iris.data = [(Sepal Length, Sepal Width, Petal Length, Petal Width)]iris = datasets.load_iris()x_vals = np.array([[x[0], x[3]] for x in iris.data])y_vals = np.array([1 if y == 0 else -1 for y in iris.target]) Split data into train/test sets 123456train_indices = np.random.choice(len(x_vals), round(len(x_vals)*0.8), replace=False)test_indices = np.array(list(set(range(len(x_vals))) - set(train_indices)))x_vals_train = x_vals[train_indices]x_vals_test = x_vals[test_indices]y_vals_train = y_vals[train_indices]y_vals_test = y_vals[test_indices] Set model parameters, placeholders, and coefficients. 12345678910# Declare batch sizebatch_size = 110# Initialize placeholdersx_data = tf.placeholder(shape=[None, 2], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)# Create variables for SVMA = tf.Variable(tf.random_normal(shape=[2, 1]))b = tf.Variable(tf.random_normal(shape=[1, 1])) Declare our model and L2 Norm SVM linear model is given by the equation: \left[ \frac{1}{n} \sum_{i=1}^{n} \max(0, 1 - y_i(A \cdot x - b)) \right] + \alpha \cdot ||A||^{2}Our loss function will be the above quantity and we will tell TensorFlow to minimize it. Note that $n$ is the number of points (in a batch), $A$ is the hyperplane-normal vector (to solve for), $b$ is the hyperplane-offset (to solve for), and $\alpha$ is the soft-margin parameter. 12345# Declare model operationsmodel_output = tf.subtract(tf.matmul(x_data, A), b)# Declare vector L2 'norm' function squaredl2_norm = tf.reduce_sum(tf.square(A)) Here we make our special loss function based on the classification of the points (which side of the line they fall on). Also, note that alpha is the soft-margin term and an be increased to allow for more erroroneous classification points. For hard-margin behaviour, set alpha = 0. 1234567891011# Declare loss function# Loss = max(0, 1-pred*actual) + alpha * L2_norm(A)^2# L2 regularization parameter, alphaalpha = tf.constant([0.01])# Margin term in lossclassification_term = tf.reduce_mean(tf.maximum(0., tf.subtract(1., tf.multiply(model_output, y_target))))# Put terms togetherloss = tf.add(classification_term, tf.multiply(alpha, l2_norm)) Creat the prediction function, optimization algorithm, and initialize the variables. 1234567891011# Declare prediction functionprediction = tf.sign(model_output)accuracy = tf.reduce_mean(tf.cast(tf.equal(prediction, y_target), tf.float32))# Declare optimizermy_opt = tf.train.AdamOptimizer(0.005)train_step = my_opt.minimize(loss)# Initialize variablesinit = tf.global_variables_initializer()sess.run(init) Now we can start the training loop. 123456789101112131415161718192021222324252627282930# Training looploss_vec = []train_accuracy = []test_accuracy = []for i in range(1500): rand_index = np.random.choice(len(x_vals_train), size=batch_size) rand_x = x_vals_train[rand_index] rand_y = np.transpose([y_vals_train[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss) train_acc_temp = sess.run(accuracy, feed_dict=&#123; x_data: x_vals_train, y_target: np.transpose([y_vals_train])&#125;) train_accuracy.append(train_acc_temp) test_acc_temp = sess.run(accuracy, feed_dict=&#123; x_data: x_vals_test, y_target: np.transpose([y_vals_test])&#125;) test_accuracy.append(test_acc_temp) if (i + 1) % 75 == 0: print('Step #&#123;&#125; A = &#123;&#125;, b = &#123;&#125;'.format( str(i+1), str(sess.run(A)), str(sess.run(b)) )) print('Loss = ' + str(temp_loss)) Step #75 A = [[0.65587175] [0.73911524]], b = [[0.8189382]] Loss = [3.477592] Step #150 A = [[0.30820864] [0.37043768]], b = [[1.1588708]] Loss = [1.8782018] Step #225 A = [[0.05466489] [0.01620324]], b = [[1.3756151]] Loss = [0.61904156] Step #300 A = [[ 0.0723089 ] [-0.10384972]], b = [[1.2969997]] Loss = [0.50430346] Step #375 A = [[ 0.08872697] [-0.21590038]], b = [[1.214785]] Loss = [0.5581] Step #450 A = [[ 0.10302152] [-0.33577552]], b = [[1.1402861]] Loss = [0.60070616] Step #525 A = [[ 0.12028296] [-0.46366042]], b = [[1.0620526]] Loss = [0.47809908] Step #600 A = [[ 0.145114 ] [-0.5994784]], b = [[0.97037107]] Loss = [0.56837624] Step #675 A = [[ 0.16354088] [-0.7458743 ]], b = [[0.8814289]] Loss = [0.5452542] Step #750 A = [[ 0.17879468] [-0.90772235]], b = [[0.7907687]] Loss = [0.47175956] Step #825 A = [[ 0.20936723] [-1.0691159 ]], b = [[0.68023866]] Loss = [0.41458404] Step #900 A = [[ 0.236106 ] [-1.2391785]], b = [[0.5687398]] Loss = [0.29367676] Step #975 A = [[ 0.25400215] [-1.4175524 ]], b = [[0.46441486]] Loss = [0.27020118] Step #1050 A = [[ 0.28435734] [-1.5984066 ]], b = [[0.34036276]] Loss = [0.19518965] Step #1125 A = [[ 0.28947413] [-1.780023 ]], b = [[0.24134117]] Loss = [0.17559259] Step #1200 A = [[ 0.2927576] [-1.930816 ]], b = [[0.15315719]] Loss = [0.13242653] Step #1275 A = [[ 0.3031533] [-2.0399208]], b = [[0.06639722]] Loss = [0.14762701] Step #1350 A = [[ 0.29892927] [-2.1220415 ]], b = [[0.00746888]] Loss = [0.1029826] Step #1425 A = [[ 0.29492435] [-2.1905353 ]], b = [[-0.04703728]] Loss = [0.11851373] Step #1500 A = [[ 0.29012206] [-2.2488031 ]], b = [[-0.09580647]] Loss = [0.1065909] Now we extract the linear coefficients and get the SVM boundary line. 12345678910111213141516171819# Extract coefficients[[a1], [a2]] = sess.run(A)[[b]] = sess.run(b)slope = -a2/a1y_intercept = b/a1# Extract x1 and x2 valsx1_vals = [d[1] for d in x_vals]# Get best fit linebest_fit = []for i in x1_vals: best_fit.append(slope*i+y_intercept)# Separate I. setosasetosa_x = [d[1] for i, d in enumerate(x_vals) if y_vals[i] == 1]setosa_y = [d[0] for i, d in enumerate(x_vals) if y_vals[i] == 1]not_setosa_x = [d[1] for i, d in enumerate(x_vals) if y_vals[i] == -1]not_setosa_y = [d[0] for i, d in enumerate(x_vals) if y_vals[i] == -1] Matplotlib code for plotting $a_1x_1 + a_2x_2 - b = 0$ x_1 = -\frac{a_2}{a_1}x_2 + \frac{b}{a_1}$x_1 =$ Sepal Length $x_2 =$ Petal Width 123456789101112131415161718192021222324252627%matplotlib inline# Plot data and lineplt.plot(setosa_x, setosa_y, 'o', label='I. setosa')plt.plot(not_setosa_x, not_setosa_y, 'x', label='Non-setosa')plt.plot(x1_vals, best_fit, 'r-', label='Linear Separator', linewidth=3)plt.ylim([0, 10])plt.legend(loc='lower right')plt.title('Sepal Length vs Petal Width')plt.xlabel('Petal Width')plt.ylabel('Sepal Length')plt.show()# Plot train/test accuraciesplt.plot(train_accuracy, 'k-', label='Training Accuracy')plt.plot(test_accuracy, 'r--', label='Test Accuracy')plt.title('Train and Test Set Accuracies')plt.xlabel('Generation')plt.ylabel('Accuracy')plt.legend(loc='lower right')plt.show()# Plot loss over timeplt.plot(loss_vec, 'k-')plt.title('Loss per Generation')plt.xlabel('Generation')plt.ylabel('Loss')plt.show() 2. SVM RegressionThis function shows how to use TensorFlow to solve support vector regression. We are goingto find the line that has the maximum margin which INCLUDES as many points as possible. We will use the iris data, specifically: $y =$ Sepal Length $x =$ Pedal Width To start, load the necessary libraries: 123456import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import opsops.reset_default_graph() Create a TF Graph Session: 1sess = tf.Session() Load the iris data, use the Sepal Length and Petal width for SVM regression. 12345678910111213# Load the data# iris.data = [(Sepal Length, Sepal Width, Petal Length, Petal Width)]iris = datasets.load_iris()x_vals = np.array([x[3] for x in iris.data])y_vals = np.array([y[0] for y in iris.data])# Split data into train/test setstrain_indices = np.random.choice(len(x_vals), round(len(x_vals)*0.8), replace=False)test_indices = np.array(list(set(range(len(x_vals))) - set(train_indices)))x_vals_train = x_vals[train_indices]x_vals_test = x_vals[test_indices]y_vals_train = y_vals[train_indices]y_vals_test = y_vals[test_indices] Declare the batch size, initialize placeholders, and create linear regression variables 12345678910# Declare batch sizebatch_size = 50# Initialize placeholdersx_data = tf.placeholder(shape=[None, 1], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)# Create variables for linear regressionA = tf.Variable(tf.random_normal(shape=[1,1]))b = tf.Variable(tf.random_normal(shape=[1,1])) Create the model 12# Declare model operationsmodel_output = tf.add(tf.matmul(x_data, A), b) Our loss function, which maximizes the amount of points near the line. 123456# Declare loss function# = max(0, abs(target - predicted) + epsilon)# 1/2 margin width parameter = epsilonepsilon = tf.constant([0.5])# Margin term in lossloss = tf.reduce_mean(tf.maximum(0., tf.subtract(tf.abs(tf.subtract(model_output, y_target)), epsilon))) Create the optimization function and initialize all the model variables 1234567# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.075)train_step = my_opt.minimize(loss)# Initialize variablesinit = tf.global_variables_initializer()sess.run(init) Train! Loop through batches of data and optimize. 1234567891011121314151617181920# Training looptrain_loss = []test_loss = []for i in range(200): rand_index = np.random.choice(len(x_vals_train), size=batch_size) rand_x = np.transpose([x_vals_train[rand_index]]) rand_y = np.transpose([y_vals_train[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_train_loss = sess.run(loss, feed_dict=&#123;x_data: np.transpose([x_vals_train]), y_target: np.transpose([y_vals_train])&#125;) train_loss.append(temp_train_loss) temp_test_loss = sess.run(loss, feed_dict=&#123;x_data: np.transpose([x_vals_test]), y_target: np.transpose([y_vals_test])&#125;) test_loss.append(temp_test_loss) if (i+1)%50==0: print('-----------') print('Generation: ' + str(i+1)) print('A = ' + str(sess.run(A)) + ' b = ' + str(sess.run(b))) print('Train Loss = ' + str(temp_train_loss)) print('Test Loss = ' + str(temp_test_loss)) ----------- Generation: 50 A = [[2.4289258]] b = [[2.271079]] Train Loss = 0.7553672 Test Loss = 0.65542704 ----------- Generation: 100 A = [[1.9204257]] b = [[3.4155781]] Train Loss = 0.3573223 Test Loss = 0.39466858 ----------- Generation: 150 A = [[1.3823755]] b = [[4.095077]] Train Loss = 0.14115657 Test Loss = 0.14801341 ----------- Generation: 200 A = [[1.204475]] b = [[4.462577]] Train Loss = 0.09575871 Test Loss = 0.11255897 For plotting, we need to extract the coefficients and get the best fit line. (Also the upper and lower margins.) 12345678910111213# Extract Coefficients[[slope]] = sess.run(A)[[y_intercept]] = sess.run(b)[width] = sess.run(epsilon)# Get best fit linebest_fit = []best_fit_upper = []best_fit_lower = []for i in x_vals: best_fit.append(slope*i+y_intercept) best_fit_upper.append(slope*i+y_intercept+width) best_fit_lower.append(slope*i+y_intercept-width) Matplotlib code to plot the fit and loss. 1234567891011121314151617181920# Plot fit with dataplt.plot(x_vals, y_vals, 'o', label='Data Points')plt.plot(x_vals, best_fit, 'r-', label='SVM Regression Line', linewidth=3)plt.plot(x_vals, best_fit_upper, 'r--', linewidth=2)plt.plot(x_vals, best_fit_lower, 'r--', linewidth=2)plt.ylim([0, 10])plt.legend(loc='lower right')plt.title('Sepal Length vs Petal Width')plt.xlabel('Petal Width')plt.ylabel('Sepal Length')plt.show()# Plot loss over timeplt.plot(train_loss, 'k-', label='Train Set Loss')plt.plot(test_loss, 'r--', label='Test Set Loss')plt.title('L2 Loss per Generation')plt.xlabel('Generation')plt.ylabel('L2 Loss')plt.legend(loc='upper right')plt.show() 3. Illustration of Various KernelsWorking with Kernels Linear SVMs are very powerful. But sometimes the data are not very linear. To this end, we can use the ‘kernel trick’ to map our data into a higher dimensional space, where it may be linearly separable. Doing this allows us to separate out non-linear classes. See the below example. If we attempt to separate the below circular-ring shaped classes with a standard linear SVM, we fail. But if we separate it with a Gaussian-RBF kernel, we can find a linear separator in a higher dimension that works a lot better. This function wll illustrate how to implement various kernels in TensorFlow. Linear Kernel: K(x_1, x_2) = x_1^{T} \cdot x_2Gaussian Kernel (RBF): K(x_1, x_2) = e^{(-\gamma |x_1 - x_2|^2)}We start by loading the necessary libraries 123456import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import opsops.reset_default_graph() Start a computational graph session: 1sess = tf.Session() For this example, we will generate fake non-linear data. The data we will generate is concentric ring data. 1234567# Generate non-lnear data(x_vals, y_vals) = datasets.make_circles(n_samples=350, factor=.5, noise=.1)y_vals = np.array([1 if y==1 else -1 for y in y_vals])class1_x = [x[0] for i,x in enumerate(x_vals) if y_vals[i]==1]class1_y = [x[1] for i,x in enumerate(x_vals) if y_vals[i]==1]class2_x = [x[0] for i,x in enumerate(x_vals) if y_vals[i]==-1]class2_y = [x[1] for i,x in enumerate(x_vals) if y_vals[i]==-1] We declare the batch size (large for SVMs), create the placeholders, and declare the $b$ variable for the SVM model. 12345678910# Declare batch sizebatch_size = 350# Initialize placeholdersx_data = tf.placeholder(shape=[None, 2], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)prediction_grid = tf.placeholder(shape=[None, 2], dtype=tf.float32)# Create variables for svmb = tf.Variable(tf.random_normal(shape=[1,batch_size])) Here we will apply the kernel. Note that the Linear Kernel is commented out. If you choose to use the linear kernel, then uncomment the linear my_kernel variable, and comment out the five RBF kernel lines. 12345678910# Apply kernel# Linear Kernel# my_kernel = tf.matmul(x_data, tf.transpose(x_data))# Gaussian (RBF) kernelgamma = tf.constant(-50.0)dist = tf.reduce_sum(tf.square(x_data), 1)dist = tf.reshape(dist, [-1,1])sq_dists = tf.add(tf.subtract(dist, tf.multiply(2., tf.matmul(x_data, tf.transpose(x_data)))), tf.transpose(dist))my_kernel = tf.exp(tf.multiply(gamma, tf.abs(sq_dists))) Next we compute the SVM model and create a loss function. 123456# Compute SVM Modelfirst_term = tf.reduce_sum(b)b_vec_cross = tf.matmul(tf.transpose(b), b)y_target_cross = tf.matmul(y_target, tf.transpose(y_target))second_term = tf.reduce_sum(tf.multiply(my_kernel, tf.multiply(b_vec_cross, y_target_cross)))loss = tf.negative(tf.subtract(first_term, second_term)) Just like we created the kernel for the training points, we need to create the kernel for the test/prediction points. Again, comment/uncomment the appropriate lines for using the linear or RBF kernel. 123456789# Create Prediction Kernel# Linear prediction kernel# my_kernel = tf.matmul(x_data, tf.transpose(prediction_grid))# Gaussian (RBF) prediction kernelrA = tf.reshape(tf.reduce_sum(tf.square(x_data), 1),[-1,1])rB = tf.reshape(tf.reduce_sum(tf.square(prediction_grid), 1),[-1,1])pred_sq_dist = tf.add(tf.subtract(rA, tf.multiply(2., tf.matmul(x_data, tf.transpose(prediction_grid)))), tf.transpose(rB))pred_kernel = tf.exp(tf.multiply(gamma, tf.abs(pred_sq_dist))) In order to use the kernel to classify points, we create a prediction operation. This prediction operation will be the sign ( positive or negative ) of the model outputs. The accuracy can then be computed if we know the actual target labels. 123prediction_output = tf.matmul(tf.multiply(tf.transpose(y_target),b), pred_kernel)prediction = tf.sign(prediction_output-tf.reduce_mean(prediction_output))accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.squeeze(prediction), tf.squeeze(y_target)), tf.float32)) We now declare the optimizer and variable initialization operations. 1234567# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.002)train_step = my_opt.minimize(loss)# Initialize variablesinit = tf.global_variables_initializer()sess.run(init) We start the training loop for the SVM. We will randomly choose a batch of points and run the train step. Then we calculate the loss and accuracy. 1234567891011121314151617181920# Training looploss_vec = []batch_accuracy = []for i in range(1000): rand_index = np.random.choice(len(x_vals), size=batch_size) rand_x = x_vals[rand_index] rand_y = np.transpose([y_vals[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss) acc_temp = sess.run(accuracy, feed_dict=&#123;x_data: rand_x, y_target: rand_y, prediction_grid:rand_x&#125;) batch_accuracy.append(acc_temp) if (i+1)%250==0: print('Step #' + str(i+1)) print('Loss = ' + str(temp_loss)) Step #250 Loss = 46.040836 Step #500 Loss = -5.635271 Step #750 Loss = -11.075392 Step #1000 Loss = -11.158321 To plot a pretty picture of the regions we fit, we create a fine mesh to run through our model and get the predictions. (This is very similar to the SVM plotting code from sci-kit learn). 12345678910# Create a mesh to plot points inx_min, x_max = x_vals[:, 0].min() - 1, x_vals[:, 0].max() + 1y_min, y_max = x_vals[:, 1].min() - 1, x_vals[:, 1].max() + 1xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02))grid_points = np.c_[xx.ravel(), yy.ravel()][grid_predictions] = sess.run(prediction, feed_dict=&#123;x_data: x_vals, y_target: np.transpose([y_vals]), prediction_grid: grid_points&#125;)grid_predictions = grid_predictions.reshape(xx.shape) Plot the results 1234567891011121314151617181920212223242526# Plot points and gridplt.contourf(xx, yy, grid_predictions, cmap=plt.cm.Paired, alpha=0.8)plt.plot(class1_x, class1_y, 'ro', label='Class 1')plt.plot(class2_x, class2_y, 'kx', label='Class -1')plt.title('Gaussian SVM Results')plt.xlabel('x')plt.ylabel('y')plt.legend(loc='lower right')plt.ylim([-1.5, 1.5])plt.xlim([-1.5, 1.5])plt.show()# Plot batch accuracyplt.plot(batch_accuracy, 'k-', label='Accuracy')plt.title('Batch Accuracy')plt.xlabel('Generation')plt.ylabel('Accuracy')plt.legend(loc='lower right')plt.show()# Plot loss over timeplt.plot(loss_vec, 'k-')plt.title('Loss per Generation')plt.xlabel('Generation')plt.ylabel('Loss')plt.show() Prediction/Evaluation Here is code on how to predict the class on new or unseen data. 1234567# New data points:new_points = np.array([(-0.75, -0.75), (-0.5, -0.5), (-0.25, -0.25), (0.25, 0.25), (0.5, 0.5), (0.75, 0.75)]) 123[evaluations] = sess.run(prediction, feed_dict=&#123;x_data: x_vals, y_target: np.transpose([y_vals]), prediction_grid: new_points&#125;) 12for ix, p in enumerate(new_points): print('&#123;&#125; : class=&#123;&#125;'.format(p, evaluations[ix])) [-0.75 -0.75] : class=-1.0 [-0.5 -0.5] : class=1.0 [-0.25 -0.25] : class=1.0 [0.25 0.25] : class=1.0 [0.5 0.5] : class=-1.0 [0.75 0.75] : class=-1.0 4. Implementing NonLinear SVMsHere we show how to use the prior Gaussian RBF kernel to predict I.setosa from the Iris dataset. This function wll illustrate how to implement the gaussian kernel on the iris dataset. Gaussian Kernel: K(x_{1}, x_{2}) = e^{\left(-\gamma \cdot (x_{1} - x_{2})^{2}\right)}We start by loading the necessary libraries and resetting the computational graph. 123456import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import opsops.reset_default_graph() Create a graph session 1sess = tf.Session() Load the Iris Data Our x values will be $(x_1, x_2)$ where, $x_1 =$ ‘Sepal Length’ $x_2 =$ ‘Petal Width’ The Target values will be wether or not the flower species is Iris Setosa. 123456789# Load the data# iris.data = [(Sepal Length, Sepal Width, Petal Length, Petal Width)]iris = datasets.load_iris()x_vals = np.array([[x[0], x[3]] for x in iris.data])y_vals = np.array([1 if y==0 else -1 for y in iris.target])class1_x = [x[0] for i,x in enumerate(x_vals) if y_vals[i]==1]class1_y = [x[1] for i,x in enumerate(x_vals) if y_vals[i]==1]class2_x = [x[0] for i,x in enumerate(x_vals) if y_vals[i]==-1]class2_y = [x[1] for i,x in enumerate(x_vals) if y_vals[i]==-1] Model Parameters We now declare our batch size, placeholders, and the fitted b-value for the SVM kernel. Note that we will create a separate placeholder to feed in the prediction grid for plotting. 12345678910# Declare batch sizebatch_size = 150# Initialize placeholdersx_data = tf.placeholder(shape=[None, 2], dtype=tf.float32)y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)prediction_grid = tf.placeholder(shape=[None, 2], dtype=tf.float32)# Create variables for svmb = tf.Variable(tf.random_normal(shape=[1,batch_size])) Gaussian (RBF) Kernel We create the gaussian kernel that is used to transform the data points into a higher dimensional space. The Kernel of two points, $x$ and $x’$ is given as K(x, x')=exp\left(-\gamma|| x-x' ||^{2}\right)For $\gamma$ very small, the kernel is very wide, and vice-versa for large $\gamma$ values. This means that large $\gamma$ leads to high bias and low variance models. If we have a vector of points, $x$ of size (batch_size, 2), then our kernel calculation becomes K(\textbf{x})=exp\left( -\gamma \textbf{x} \cdot \textbf{x}^{T} \right)1234# Gaussian (RBF) kernelgamma = tf.constant(-50.0)sq_vec = tf.multiply(2., tf.matmul(x_data, tf.transpose(x_data)))my_kernel = tf.exp(tf.multiply(gamma, tf.abs(sq_vec))) Compute SVM Model Here, the SVM loss is given by two terms, The first term is the sum of the $b$ matrix, and the second term is \sum\left(K\cdot||\textbf{b}||^{2}||\textbf{y}||^{2}\right)We finally tell TensorFlow to maximize the loss by minimizing the negative: (The following is a horribly abbreviated version of the dual problem) -\left(\sum\textbf{b} - \sum\left(K\cdot||\textbf{b}||^{2}||\textbf{y}||^{2}\right)\right)123456# Compute SVM Modelfirst_term = tf.reduce_sum(b)b_vec_cross = tf.matmul(tf.transpose(b), b)y_target_cross = tf.matmul(y_target, tf.transpose(y_target))second_term = tf.reduce_sum(tf.multiply(my_kernel, tf.multiply(b_vec_cross, y_target_cross)))loss = tf.negative(tf.subtract(first_term, second_term)) Define the Prediction Kernel Now we do the exact same thing as above for the prediction points. 123456789# Gaussian (RBF) prediction kernelrA = tf.reshape(tf.reduce_sum(tf.square(x_data), 1),[-1,1])rB = tf.reshape(tf.reduce_sum(tf.square(prediction_grid), 1),[-1,1])pred_sq_dist = tf.add(tf.subtract(rA, tf.multiply(2., tf.matmul(x_data, tf.transpose(prediction_grid)))), tf.transpose(rB))pred_kernel = tf.exp(tf.multiply(gamma, tf.abs(pred_sq_dist)))prediction_output = tf.matmul(tf.multiply(tf.transpose(y_target),b), pred_kernel)prediction = tf.sign(prediction_output-tf.reduce_mean(prediction_output))accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.squeeze(prediction), tf.squeeze(y_target)), tf.float32)) Optimizing Method We declare our gradient descent optimizer and intialize our model variables (b) 1234567# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.01)train_step = my_opt.minimize(loss)# Initialize variablesinit = tf.global_variables_initializer()sess.run(init) Run the Classification! We iterate through the training for 300 iterations. We will output the loss every 75 iterations. 1234567891011121314151617181920# Training looploss_vec = []batch_accuracy = []for i in range(300): rand_index = np.random.choice(len(x_vals), size=batch_size) rand_x = x_vals[rand_index] rand_y = np.transpose([y_vals[rand_index]]) sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss) acc_temp = sess.run(accuracy, feed_dict=&#123;x_data: rand_x, y_target: rand_y, prediction_grid:rand_x&#125;) batch_accuracy.append(acc_temp) if (i+1)%75==0: print('Step #' + str(i+1)) print('Loss = ' + str(temp_loss)) Step #75 Loss = -135.62637 Step #150 Loss = -248.12627 Step #225 Loss = -360.6262 Step #300 Loss = -473.12637 Plotting Results We now create a fine mesh for plotting the SVM class lines 12345678910# Create a mesh to plot points inx_min, x_max = x_vals[:, 0].min() - 1, x_vals[:, 0].max() + 1y_min, y_max = x_vals[:, 1].min() - 1, x_vals[:, 1].max() + 1xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02))grid_points = np.c_[xx.ravel(), yy.ravel()][grid_predictions] = sess.run(prediction, feed_dict=&#123;x_data: x_vals, y_target: np.transpose([y_vals]), prediction_grid: grid_points&#125;)grid_predictions = grid_predictions.reshape(xx.shape) 123456789101112131415161718192021222324252627%matplotlib inline# Plot points and gridplt.contourf(xx, yy, grid_predictions, cmap=plt.cm.Paired, alpha=0.8)plt.plot(class1_x, class1_y, 'ro', label='I. setosa')plt.plot(class2_x, class2_y, 'kx', label='Non setosa')plt.title('Gaussian SVM Results on Iris Data')plt.xlabel('Petal Length')plt.ylabel('Sepal Width')plt.legend(loc='lower right')plt.ylim([-0.5, 3.0])plt.xlim([3.5, 8.5])plt.show()# Plot batch accuracyplt.plot(batch_accuracy, 'k-', label='Accuracy')plt.title('Batch Accuracy')plt.xlabel('Generation')plt.ylabel('Accuracy')plt.legend(loc='lower right')plt.show()# Plot loss over timeplt.plot(loss_vec, 'k-')plt.title('Loss per Generation')plt.xlabel('Generation')plt.ylabel('Loss')plt.show() Evaluate Test Points We create a set of test points, and evaluate the class predictions 12345x_test_seq = np.array([4., 5., 6., 7.])y_test_seq = np.array([0., 1., 2.])x_test, y_test = np.meshgrid(x_test_seq,y_test_seq)test_points = np.c_[x_test.ravel(), y_test.ravel()] 1test_points array([[4., 0.], [5., 0.], [6., 0.], [7., 0.], [4., 1.], [5., 1.], [6., 1.], [7., 1.], [4., 2.], [5., 2.], [6., 2.], [7., 2.]]) Now we can evaluate the predictions on our test points: 1test_points array([[4., 0.], [5., 0.], [6., 0.], [7., 0.], [4., 1.], [5., 1.], [6., 1.], [7., 1.], [4., 2.], [5., 2.], [6., 2.], [7., 2.]]) 123[test_predictions] = sess.run(prediction, feed_dict=&#123;x_data: x_vals, y_target: np.transpose([y_vals]), prediction_grid: test_points&#125;) 1test_predictions.ravel() array([ 1., 1., 1., 1., 1., -1., -1., 1., 1., 1., -1., -1.], dtype=float32) Format the test points together with the predictions: 123for ix, point in enumerate(test_points): point_pred = test_predictions.ravel()[ix] print('Point &#123;&#125; is predicted to be in class &#123;&#125;'.format(point, point_pred)) Point [4. 0.] is predicted to be in class 1.0 Point [5. 0.] is predicted to be in class 1.0 Point [6. 0.] is predicted to be in class 1.0 Point [7. 0.] is predicted to be in class 1.0 Point [4. 1.] is predicted to be in class 1.0 Point [5. 1.] is predicted to be in class -1.0 Point [6. 1.] is predicted to be in class -1.0 Point [7. 1.] is predicted to be in class 1.0 Point [4. 2.] is predicted to be in class 1.0 Point [5. 2.] is predicted to be in class 1.0 Point [6. 2.] is predicted to be in class -1.0 Point [7. 2.] is predicted to be in class -1.0 5. Multi-class (Nonlinear) SVM ExampleHere, we implement a 1-vs-all voting method for a multiclass SVM. We attempt to separate the three Iris flower classes with TensorFlow. This function wll illustrate how to implement the gaussian kernel with multiple classes on the iris dataset. Gaussian Kernel: K(x_1, x_2) = e^{-\gamma \cdot (x_1 - x_2)^2}X : (Sepal Length, Petal Width) Y: (I. setosa, I. virginica, I. versicolor) (3 classes) Basic idea: introduce an extra dimension to do one vs all classification. The prediction of a point will be the category with the largest margin or distance to boundary. We start by loading the necessary libraries. 123456import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import opsops.reset_default_graph() Start a computational graph session. 1sess = tf.Session() Now we load the iris data. 1234567891011121314# Load the data# iris.data = [(Sepal Length, Sepal Width, Petal Length, Petal Width)]iris = datasets.load_iris()x_vals = np.array([[x[0], x[3]] for x in iris.data])y_vals1 = np.array([1 if y==0 else -1 for y in iris.target])y_vals2 = np.array([1 if y==1 else -1 for y in iris.target])y_vals3 = np.array([1 if y==2 else -1 for y in iris.target])y_vals = np.array([y_vals1, y_vals2, y_vals3])class1_x = [x[0] for i,x in enumerate(x_vals) if iris.target[i]==0]class1_y = [x[1] for i,x in enumerate(x_vals) if iris.target[i]==0]class2_x = [x[0] for i,x in enumerate(x_vals) if iris.target[i]==1]class2_y = [x[1] for i,x in enumerate(x_vals) if iris.target[i]==1]class3_x = [x[0] for i,x in enumerate(x_vals) if iris.target[i]==2]class3_y = [x[1] for i,x in enumerate(x_vals) if iris.target[i]==2] Declare the batch size 1batch_size = 50 Initialize placeholders and create the variables for multiclass SVM 1234567# Initialize placeholdersx_data = tf.placeholder(shape=[None, 2], dtype=tf.float32)y_target = tf.placeholder(shape=[3, None], dtype=tf.float32)prediction_grid = tf.placeholder(shape=[None, 2], dtype=tf.float32)# Create variables for svmb = tf.Variable(tf.random_normal(shape=[3,batch_size])) Create the Gaussian Kernel 123456# Gaussian (RBF) kernelgamma = tf.constant(-10.0)dist = tf.reduce_sum(tf.square(x_data), 1)dist = tf.reshape(dist, [-1,1])sq_dists = tf.multiply(2., tf.matmul(x_data, tf.transpose(x_data)))my_kernel = tf.exp(tf.multiply(gamma, tf.abs(sq_dists))) Declare a function that will do reshaping and batch matrix multiplication 12345# Declare function to do reshape/batch multiplicationdef reshape_matmul(mat, _size): v1 = tf.expand_dims(mat, 1) v2 = tf.reshape(v1, [3, _size, 1]) return(tf.matmul(v2, v1)) Now we can compute the SVM model 1234567# Compute SVM Modelfirst_term = tf.reduce_sum(b)b_vec_cross = tf.matmul(tf.transpose(b), b)y_target_cross = reshape_matmul(y_target, batch_size)second_term = tf.reduce_sum(tf.multiply(my_kernel, tf.multiply(b_vec_cross, y_target_cross)),[1,2])loss = tf.reduce_sum(tf.negative(tf.subtract(first_term, second_term))) Create the same RBF kernel for a set of prediction points (used on a grid of points at the end). 123456789# Gaussian (RBF) prediction kernelrA = tf.reshape(tf.reduce_sum(tf.square(x_data), 1),[-1,1])rB = tf.reshape(tf.reduce_sum(tf.square(prediction_grid), 1),[-1,1])pred_sq_dist = tf.add(tf.subtract(rA, tf.multiply(2., tf.matmul(x_data, tf.transpose(prediction_grid)))), tf.transpose(rB))pred_kernel = tf.exp(tf.multiply(gamma, tf.abs(pred_sq_dist)))prediction_output = tf.matmul(tf.multiply(y_target,b), pred_kernel)prediction = tf.argmax(prediction_output-tf.expand_dims(tf.reduce_mean(prediction_output,1), 1), 0)accuracy = tf.reduce_mean(tf.cast(tf.equal(prediction, tf.argmax(y_target,0)), tf.float32)) Create the optimization and variable initializer operations. 1234567# Declare optimizermy_opt = tf.train.GradientDescentOptimizer(0.01)train_step = my_opt.minimize(loss)# Initialize variablesinit = tf.global_variables_initializer()sess.run(init) We now start the training loop for the multiclass SVM 1234567891011121314151617181920# Training looploss_vec = []batch_accuracy = []for i in range(100): rand_index = np.random.choice(len(x_vals), size=batch_size) rand_x = x_vals[rand_index] rand_y = y_vals[:,rand_index] sess.run(train_step, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) temp_loss = sess.run(loss, feed_dict=&#123;x_data: rand_x, y_target: rand_y&#125;) loss_vec.append(temp_loss) acc_temp = sess.run(accuracy, feed_dict=&#123;x_data: rand_x, y_target: rand_y, prediction_grid:rand_x&#125;) batch_accuracy.append(acc_temp) if (i+1)%25==0: print('Step #' + str(i+1)) print('Loss = ' + str(temp_loss)) Step #25 Loss = -295.13718 Step #50 Loss = -632.6369 Step #75 Loss = -970.1367 Step #100 Loss = -1307.6366 For a pretty picture, to see the results, we create a fine grid of points to label/color for each class. 12345678910# Create a mesh to plot points inx_min, x_max = x_vals[:, 0].min() - 1, x_vals[:, 0].max() + 1y_min, y_max = x_vals[:, 1].min() - 1, x_vals[:, 1].max() + 1xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02))grid_points = np.c_[xx.ravel(), yy.ravel()]grid_predictions = sess.run(prediction, feed_dict=&#123;x_data: rand_x, y_target: rand_y, prediction_grid: grid_points&#125;)grid_predictions = grid_predictions.reshape(xx.shape) Plot the results 123456789101112131415161718192021222324252627# Plot points and gridplt.contourf(xx, yy, grid_predictions, cmap=plt.cm.Paired, alpha=0.8)plt.plot(class1_x, class1_y, 'ro', label='I. setosa')plt.plot(class2_x, class2_y, 'kx', label='I. versicolor')plt.plot(class3_x, class3_y, 'gv', label='I. virginica')plt.title('Gaussian SVM Results on Iris Data')plt.xlabel('Petal Length')plt.ylabel('Sepal Width')plt.legend(loc='lower right')plt.ylim([-0.5, 3.0])plt.xlim([3.5, 8.5])plt.show()# Plot batch accuracyplt.plot(batch_accuracy, 'k-', label='Accuracy')plt.title('Batch Accuracy')plt.xlabel('Generation')plt.ylabel('Accuracy')plt.legend(loc='lower right')plt.show()# Plot loss over timeplt.plot(loss_vec, 'k-')plt.title('Loss per Generation')plt.xlabel('Generation')plt.ylabel('Loss')plt.show()]]></content>
      <categories>
        <category>机器学习</category>
        <category>支持向量机</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[Transfer learning for time series classification]]></title>
    <url>%2F2018%2F11%2F20%2FTransfer_learning_for_time_series_classification%2F</url>
    <content type="text"><![CDATA[本文是法国上阿尔萨斯大学发表于 IEEE Big Data 2018 上的工作。迁移学习和深度学习已经被广泛应用于计算机视觉和自然语言处理领域。但是在时间序列分类方面，至今没有完整的有代表性的工作。本文是第一篇系统探讨基于深度迁移学习进行时间序列分类的论文。在内容上与今年 CVPR 最佳论文 Taskonomy: Disentangling Task Transfer Learning 相似，都是做了大量实验来验证一些迁移学习方面的结论。 Transfer learning for time series classificationHassan Ismail Fawaz, Germain Forestier, Jonathan Weber, Lhassane Idoumghar, Pierre-Alain Muller(Submitted on 5 Nov 2018) Transfer learning for deep neural networks is the process of first training a base network on a source dataset, and then transferring the learned features (the network’s weights) to a second network to be trained on a target dataset. This idea has been shown to improve deep neural network’s generalization capabilities in many computer vision tasks such as image recognition and object localization. Apart from these applications, deep Convolutional Neural Networks (CNNs) have also recently gained popularity in the Time Series Classification (TSC) community. However, unlike for image recognition problems, transfer learning techniques have not yet been investigated thoroughly for the TSC task. This is surprising as the accuracy of deep learning models for TSC could potentially be improved if the model is fine-tuned from a pre-trained neural network instead of training it from scratch. In this paper, we fill this gap by investigating how to transfer deep CNNs for the TSC task. To evaluate the potential of transfer learning, we performed extensive experiments using the UCR archive which is the largest publicly available TSC benchmark containing 85 datasets. For each dataset in the archive, we pre-trained a model and then fine-tuned it on the other datasets resulting in 7140 different deep neural networks. These experiments revealed that transfer learning can improve or degrade the model’s predictions depending on the dataset used for transfer. Therefore, in an effort to predict the best source dataset for a given target dataset, we propose a new method relying on Dynamic Time Warping to measure inter-datasets similarities. We describe how our method can guide the transfer to choose the best source dataset leading to an improvement in accuracy on 71 out of 85 datasets. Comments: Accepted at IEEE International Conference on Big Data 2018Subjects: Machine Learning (cs.LG); Artificial Intelligence (cs.AI); Machine Learning (stat.ML)Cite as: arXiv:1811.01533 [cs.LG] (or arXiv:1811.01533v1 [cs.LG] for this version) 论文相关资源 标题 说明 附加 Transfer learning for time series classification 原始论文 20181105 hfawaz/bigdata18 官方论文代码 20181010 基于深度迁移学习进行时间序列分类 论文解读 20181119]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>迁移学习</tag>
        <tag>文本分类</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Improving Language Understanding by Generative Pre-Training]]></title>
    <url>%2F2018%2F11%2F19%2FImproving_Language_Understanding_by_Generative_Pre-Training%2F</url>
    <content type="text"><![CDATA[OpenAI 20180611日更新了一篇博客，他们利用一个任务无关的可扩展系统在多语言任务上取得了卓越进展。论文及代码已经公布。他们的方法结合了 transformers 和无监督学习两个已经存在的方法。项目结果证明了将监督学习和无监督预训练结合的方法十分有效。这是很多人设想过的方法，他们希望他们的成果可以激励更多人将该方法应用于更大更复杂的数据集上。 论文精要3 FrameworkOur training procedure consists of two stages. The first stage is learning a high-capacity language model on a large corpus of text. This is followed by a fine-tuning stage, where we adapt the model to a discriminative task with labeled data. 3.1 Unsupervised pre-training 3.2 Supervised fine-tuning 3.3 Task-sepcific input transfoemations Experiments4.1 SetupUnsupervised pre-training 4.2 Supervised fine-tuningNatural Language Inference Question answering and commonsense reasoning Semantic Similarity + Classification 总的来说，我们的方法在我们评估的12个数据集中有9个获得了最新的结果，在很多情况下超过了整体表现。我们的研究结果还表明,我们的方法是有效的在不同大小的数据集,从较小的数据集,如STS-B (≈5.7 k训练例子)——最大的一个——SNLI (≈550 k训练例子)。 analysisImpact of number of layers transferred(left) + Zero-shot Behaviors(right) Ablation studiesWe perform three different ablation studies (Table 5). First, we examine the performance of our method without the auxiliary LM objective during fine-tuning. We observe that the auxiliary objective helps on the NLI tasks and QQP. Overall, the trend suggests that larger datasets benefit from the auxiliary objective but smaller datasets do not. Second, we analyze the effect of the Transformer by comparing it with a single layer 2048 unit LSTM using the same framework. We observe a 5.6 average score drop when using the LSTM instead of the Transformer. The LSTM only outperforms the Transformer on one dataset – MRPC. Finally, we also compare with our transformer architecture directly trained on supervised target tasks, without pre-training. We observe that the lack of pre-training hurts performance across all the tasks, resulting in a 14.8% decrease compared to our full model. 6 Conclusion 论文相关资源 标题 说明 附加 Improving Language Understanding by Generative Pre-Training 论文原文 20180611 openai/finetune-transformer-lm 官方代码实现 20180831 Improving Language Understanding with Unsupervised Learning 官方论文博客 20180611]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>GPT</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[CoLA The Corpus of Linguistic Acceptability]]></title>
    <url>%2F2018%2F11%2F12%2FCoLA_data_set%2F</url>
    <content type="text"><![CDATA[CoLA 数据集官网IntroductionThe Corpus of Linguistic Acceptability (CoLA) in its full form consists of 10657 sentences from 23 linguistics publications, expertly annotated for acceptability (grammaticality) by their original authors. The public version provided here contains 9594 sentences belonging to training and development sets, and excludes 1063 sentences belonging to a held out test set. Contact alexwarstadt [at] gmail [dot] com with any questions or issues. Read the paper or checkout the source code for baselines. Data FormatEach line in the .tsv files consists of 4 tab-separated columns.Column 1: the code representing the source of the sentence.Column 2: the acceptability judgment label (0=unacceptable, 1=acceptable).Column 3: the acceptability judgment as originally notated by the author.Column 4: the sentence. Corpus Sampleclc95 0 In which way is Sandy very anxious to see if the students will be able to solve the homework problem?c-05 1 The book was written by John.c-05 0 Books were sent to each other by the students.swb04 1 She voted for herself.swb04 1 I saw that gas can explode. Neural Network Acceptability JudgmentsAlex Warstadt, Amanpreet Singh, Samuel R. Bowman(Submitted on 31 May 2018 (v1), last revised 11 Sep 2018 (this version, v2)) In this work, we explore the ability of artificial neural networks to judge the grammatical acceptability of a sentence. Machine learning research of this kind is well placed to answer important open questions about the role of prior linguistic bias in language acquisition by providing a test for the Poverty of the Stimulus Argument. In service of this goal, we introduce the Corpus of Linguistic Acceptability (CoLA), a set of 10,657 English sentences labeled as grammatical or ungrammatical by expert linguists. We train several recurrent neural networks to do binary acceptability classification. These models set a baseline for the task. Error-analysis testing the models on specific grammatical phenomena reveals that they learn some systematic grammatical generalizations like subject-verb-object word order without any grammatical supervision. We find that neural sequence models show promise on the acceptability classification task. However, human-like performance across a wide range of grammatical constructions remains far off. Comments: 12 pagesSubjects: Computation and Language (cs.CL)Cite as: arXiv:1805.12471 [cs.CL] (or arXiv:1805.12471v2 [cs.CL] for this version) CoLA-baselinesModelOur general model structure looks like figure below. Follow paper for more in-depth details. 实验论文中的基线结果 使用 BERT 模型的效果 训练过程训练参数训练输入训练损失]]></content>
      <categories>
        <category>论文</category>
        <category>论文实现</category>
      </categories>
      <tags>
        <tag>CoLA</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[智能家居自然语言理解平台的解决方案]]></title>
    <url>%2F2018%2F11%2F12%2F%E6%99%BA%E8%83%BD%E5%AE%B6%E5%B1%85%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E7%90%86%E8%A7%A3%E5%B9%B3%E5%8F%B0%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%2F</url>
    <content type="text"><![CDATA[参照百度大脑的项目经验训练我们自己的模型，研发我们的自然语言理解平台。 文档整理 标题 说明 附加 智能家居项目调研 智能家居项目 20181111 自然语言理解与交互技术平台(UNIT) 资源 标题 说明 附加 【提升篇】UNIT2.0—火车票场景实例教程 参考范例 20180708 【提升篇】酒店语音助手实例教程 参考范例 20181011 【提升篇】儿童故事机示例 参考范例 20180930 【入门体验篇】3分钟打造查天气机器 参考范例 20180720 基本概念123456在特定场景下的对话理解与交互能力。技能主要用于解决特定场景下的对话理解与交互任务。同时UNIT平台提供了一些预置的系统技能（比如问候、电视指令等，更多系统技能会陆续开放），您可根据业务需要直接选用。技能中包含了一系列『对话意图』或『问答意图』用于完成特定场景下的所有对话任务(例如，智能电视技能包含了换台、调音量、找部电影等一系列『对话意图』)。 技能训练出模型并生效到沙盒环境后，您可以在『训练/体验』对话窗口中与技能对话，体验技能的对话理解能力。您也可以在自己的产品中通API直接调用它，让您的产品具有智能对话理解与交互的能力。### ```对话意图【基本信息】 对话意图：intent，是在一个对话任务中技能要理解的用户目的（例如用户说”换到中央台”，那对应电视控制技能下的对话意图就是”换台”）。 名称：对话意图的英文定义，后续您可在程序调用中使用。 别名：对话意图的名称的中文表述，可以创建多个，对应一个对话意图的不同表达方式，可以帮助技能更容易理解一个对话意图的不同表述。 【词槽】 词槽：slot，是技能需要理解的用户对话对话意图中的一些限定条件。例如：”换到中央台”中的”中央台”就是一个”电视台词槽”，它会一定程度上影响技能对”换台”这个对话意图的执行。 词槽澄清：在口语对话中，用户的一句话 (我们称之为单轮对话) 中常常并不会包含完整的词槽(例如，换台)，而某些词槽对于对话技能的最终执行是不可或缺的（例如，电视台词槽）。因此，对话技能需要对用户发起”词槽澄清”询问（例如，换到哪个台？）来获取”不可或缺”词槽的信息(例如用户回答，要中央台)。UNIT平台可以支持定义哪些词槽是”不可或缺的”，也可以通过调整词槽顺序来定义哪个词槽应该优先被询问。 澄清话术：在这里，我们可以定义对话技能进行词槽澄清时询问用户的问题(例如，换到哪个台呢？)。如果不加以定义，系统会使用默认的问题进行询问：请澄清词槽XXX（XXX代表词槽名称）。 添加方式：开发者可以自行新建词槽，也可以复用当前技能中已创建过的词槽。此外依托百度的自然语言能力，UNIT平台内建了部分常用词槽供您使用。需要注意的是系统内建词槽是无法被进一步修改的。 词典：每个词槽都需要对应一套词典，技能的专名词识别服务会结合词槽绑定的词典来识别用户问话中的词槽。开发者可以自行导入词典，对话技能进行词槽识别时，会优先考虑自定义词典中的词汇。 复用系统词槽：复用系统词槽意味着开发者可以更灵活的”组装”自己的自定义词槽，让其直接整合系统内建词槽的识别能力。 【技能回应】 答复：定义系统直接答复用户的方式，开发者可以选择：i.返回一句对话答复。例如技能答复：今天天气还不错。ii.执行一条函数来完成这一动作。例如技能抛出函数：flick（tv_channel）;注意，unit提供的API结果中仅会告知开发者应该执行函数flick（tv_channel）,但函数需要在开发者自身的产品中实现与执行。引导：对话技能除了可以直接答复用户，还可以通过配置引导动作，指示用户进一步明确需求。引导包含对话意图引导和问答意图引导，即分别引导至对话意图和问答意图。配置对话意图引导需要配置的内容包括主话术，目标对话意图和对话意图引导话术。例如，当前对话意图是：golden_retriever；主话术是：请问您是想了解有关金毛的什么信息？目标对话意图是”golden_retriever_habits”，而对话意图引导话术是”金毛习性么？” 配置问答意图引导需要配置目标问答意图。 1234567一个问答意图代表某一类问答对的主题，它的概念范围要比对话意图大，可以是同一类问题的集合。比如售前咨询FQA，售后咨询FAQ。开发者可以根据业务定义问答意图对应主题的范围。创建完问答意图后，可前往【训练与优化--训练数据--问答集】添加或导入具体的问答对内容。名称：用于描述当前问答意图的主题的大写英文标识，在API调用中技能返回的JSON信息里会有。别名：问答意图名称的中文表述。### ```效果优化【训练数据】 【对话模板】 对话模板 在UNIT中，对话模板可以让开发者在冷启动（缺少训练语料）阶段快速让一个任务式对话技能具有很好的对话理解效果。或在表达方式有限、几乎可枚举各种表达方式的控制指令类快速获得很好的对话理解效果。同时对话模板对理解能力的作用会优先于对话样本集，因此也可以用于对错误case的紧急干预。在对话模板让技能的对话理解达到一定的效果而很难进一步提升时，可通过标注更多的对话样本以达到更好的理解效果。 系统中对话模板的数量没有上限。 优先级：系统对对话模板之间的排列顺序是敏感的，排序高的模板会被优先匹配与使用，开发者可通过移动来改变对话模板的排序。 离线编辑：离线导入文件中对话模板之间的顺序即为导入后的优先级。注意：导入时会覆盖线上对话模板集中全部对话模板，请及时做好备份工作！ 特征词 特征词是指一组具有相似特征的词，通常被用于约束某条对话模板的匹配范围(例如，天气、下雨、热等类别关键词)或提供一定限度的泛化能力(例如，我想要、我打算、我计划等辅助内容)；活用特征词机制可以事半功倍的提高对话模板的精度和覆盖度。特征词词典：开发者需自行导入词典，用于系统识别特征词。口语化词 口语化词将在语义解析时会被自动忽略掉，以此来提高解析的精准率。比如通用场景下：嗯我看一下明天的天气吧 —&gt; 明天天气，这里把”嗯、我、看一下、的、吧”等口语化词都去掉了。又比如特定场景里：预定如家酒店 —&gt; 预订如家，在定酒店的场景里省略了 “酒店”， 可以将“酒店”配置为口语化的词。系统预置了口语化词，您可以增删改，调整后也可以恢复系统默认的词典值。对话样本集：是管理对话样本的集合，类似文件夹的作用，可以把不同来源的对话样本放在不同的对话样集中，也可以把不同时间段获取的对话样本分在不同的对话样本集中。 对话样本：是由开发者提供给技能的训练语料，它给对话技能示范了应该如何将用户的对话理解为对话意图和词槽。开发者可以在对话样本集中通过新建、标注、导入等操作来完成对对话样本的管理与调整。UNIT可以通过”训练”来观察并学习开发者标注的对话样本，并以此来优化技能的对话理解能力（在训练中需要打开对话样本集的开关并选择需要参与训练的样本集）。标注状态：样本在线标注/编辑后即可生效，“已标注”的样本也可以点击重新标注/编辑进行修改；对话样本集中“已标注”的对话样本才可用于训练模型。 标注对话样本：开发者需要完成对对话样本对应的对话意图和词槽的标注。 标注对话意图：当前样本对应的对话意图，对话意图变更后槽位标记信息会被自动重置。 SYS_OTHERS为系统自动生成的对话意图，用于标记噪音样本(注：噪音样本即为技能的负例样本，它可以帮助技能模型识别哪些对话可能是不属于当应该理解的)。 CMD_UPDATE系列为系统自动生成的对话意图，用于标记多轮对话中，用户的澄清答复(例如用户回答，要中央台，则需要标注这条回答为 CMD_UPDATE_TV_CHANNEL，并且将”中央台”标记为”TV_CHANNEL”类的词槽) 【问答集】 问答集 问答集是承载问答对的容器，与技能中问答意图的定义一一对应，您可以批量将问答内容导入问答集，也可以在线编辑。离线编辑 问答对可以离线编辑后导入问答集，导入后会在当前问答集中追加问答内容；也可以将某问答集中问答对内容导出。 训练/体验【沙盒环境】 沙盒是UNIT平台提供给开发者验证技能模型效果的环境，开发者将模型训练后生效至沙盒环境，即可和技能对话，通过对话可验证沙盒中模型的效果，也可实现数据标注。沙盒环境中只能生效1个模型，新模型生效后，之前生效的模型自动失效。模型版本：沙盒环境当前生效的模型的版本。更新时间：沙盒环境最近一次更新的时间。状态：沙盒环境当前的状态，分为已停用、启用中、模型生效中、运行中、模型生效失败。已停用：表示沙盒环境处于停止状态，可通过点击“启动”按钮启动沙盒环境。启用中：表示沙盒环境正处于启动中，待启动完成后，才可进一步加载并生效模型。模型生效中：表示沙盒环境正在加载生效一个技能模型，生效成功后状态变为”运行中”，生效失败后，沙盒状态为”模型生效失败”。运行中：表示沙盒环境中有个可以正常对话（平台对话体验窗口或对接接口）的技能模型。而刚创建技能时沙盒也处在运行中，此时沙盒中的模型是一个空的模型，还不能用于对话，需要定义技能，添加训练数据，训练且生效到沙盒后才能用于对话。模型生效失败：表示沙盒环境模型加载生效失败，此时请通过百度云工单系统、QQ群（805312106）或者UNIT论坛联系客服；其中，提交百度云工单系统时，工单类型请选择“人工智能-理解与交互技术UNIT”。【模型】 模型是开发者配置技能、添加/标注对话样本、创建对话模板、导入问答集后通过UNIT平台内置的各种学习引擎训练出的技能核心文件，模型需生效至沙盒环境后才可发挥作用。 模型训练时，开发者需选择训练数据，包括技能配置、高级设置、问答集、对话样本、对话模板。 对话样本：开发者提供的对话样本数据，以对话样本集为单位存储并选择，训练时可选择使用沙盒中的模型（不会重新学习，耗时端）或重新选择样本。 - 使用沙盒中的模型：不会重新学习，耗时短。 - 重新选择样本：重新学习，约100条样本/分钟，耗时长。选择的样本集中只有已标注的对话样本才会参与训练。对话模板：开发者提供的对话模板数据在每次训练时都会默认参与训练。模型在训练过程中分为初始化、训练中、训练完成、训练失败4个状态。 初始化：模型训练过程中第1个阶段。训练中：模型训练过程中第2个阶段。训练完成：模型已训练完成，此时并不可以直接使用，需生效至沙盒环境才可以使用。训练失败：模型训练失败，需开发者手动删除。 训练自然语言理解技能的总体流程 总共分为3个阶段，需求分析并做好前期准备工作→通过UNIT创建最小可用技能模型→持续优化技能模型，具体如下： （1）第1阶段：需求分析。当前阶段需要有熟悉业务的人员参加，例如：产品经理、业务负责人等。先分析业务，明确业务中哪里需要通过和用户的对话来完成；再确认相关对话逻辑。最后基于之前的分析，从之前沉淀的数据中提取有价值信息，用于后续技能创建与训练；如果是新业务或之前没有准备，也先不用着急，我们可以先完成其他部分，但综合来看，业务中的真实数据是训练技能时最理想的“知识”。 （2）第2阶段，创建&amp;训练技能。当前阶段就是要赋予技能模型对话能力了。赋予技能模型对话能力和教小朋友说话一样，要先确认教他的知识点，而这些知识点就是技能的意图。基本定义灌输完成后，就需要通过大量的练习题来帮助技能模型理解、巩固与记忆。最后，可以通过考试，来检测技能模型的学习成果。当考试合格后，就可以用于实战了，即接入咱们的业务中（API、SDK等）。 （3）第3阶段，持续优化。因着业务程度复杂、用户画像变化等因素，技能之前掌握的只是知识可能不足以应对新市场，这时我们需要通过更多的“练习”与“考试”来帮助技能提高能力。目前技能还无法完全自主学习并提高自己，还需要训练人员辅助。]]></content>
      <categories>
        <category>项目</category>
        <category>智能家居</category>
      </categories>
      <tags>
        <tag>项目</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[自然语言理解与交互技术平台]]></title>
    <url>%2F2018%2F11%2F12%2F%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E7%90%86%E8%A7%A3%E4%B8%8E%E4%BA%A4%E4%BA%92%E6%8A%80%E6%9C%AF%E5%B9%B3%E5%8F%B0%2F</url>
    <content type="text"><![CDATA[参照百度大脑的项目经验训练我们自己的模型，研发我们的自然语言理解平台。 百度理解与交互技术平台(UNIT)【提升篇】酒店语音助手实例教程1 UNIT2.0基本概念https://ai.baidu.com/docs#/UNIT-v2-intro/top 2 训练智能对话技能的总体流程 总共分为3个阶段，需求分析并做好前期准备工作→通过UNIT创建最小可用技能模型→持续优化技能模型，具体如下： （1）第1阶段：需求分析。当前阶段需要有熟悉业务的人员参加，例如：产品经理、业务负责人等。先分析业务，明确业务中哪里需要通过和用户的对话来完成；再确认相关对话逻辑。最后基于之前的分析，从之前沉淀的数据中提取有价值信息，用于后续技能创建与训练；如果是新业务或之前没有准备，也先不用着急，我们可以先完成其他部分，但综合来看，业务中的真实数据是训练技能时最理想的“知识”。 （2）第2阶段，创建&amp;训练技能。当前阶段就是要赋予技能模型对话能力了。赋予技能模型对话能力和教小朋友说话一样，要先确认教他的知识点，而这些知识点就是技能的意图。基本定义灌输完成后，就需要通过大量的练习题来帮助技能模型理解、巩固与记忆。最后，可以通过考试，来检测技能模型的学习成果。当考试合格后，就可以用于实战了，即接入咱们的业务中（API、SDK等）。 （3）第3阶段，持续优化。因着业务程度复杂、用户画像变化等因素，技能之前掌握的只是知识可能不足以应对新市场，这时我们需要通过更多的“练习”与“考试”来帮助技能提高能力。目前技能还无法完全自主学习并提高自己，还需要训练人员辅助。 本文将基于酒店服务这一场景，通过搭建酒店智能语音助手技能（下简称酒店助手技能）来讲解整个流程。 3 需求分析 需求分析是训练智能对话技能举足轻重的一步，需要基于自身业务场景进行深入透彻的思考，从而明确整个对话技能的架构，后续的技能创建与训练工作全部在此架构的基础上展开。这一步在训练智能对话技能时很容易被忽视，但草率分析需求即着手训练的技能往往后续需要投入更多的时间和精力进行调整，甚至需要推翻重来； 3.1 业务场景分析：确定边界，明确目标 3.1.1 挖掘需求，确定边界 首先是对业务场景进行分析，在酒店服务这一场景下存在很多酒店助手“可以做”的业务，我们应当从用户需求和用户体验入手，思考在该场景下用户的刚需，以及如何通过引入对话交互来大幅提升用户体验，从而在大范围的“可以做”的业务中找到其中“必须做”和“应该做”的业务。 在酒店服务这一场景下，用户主要的活动空间是在酒店房间内，因此酒店助手的首要目标为尽可能优化用户在酒店房间内的体验，像联系前台、呼叫客房服务这些都是需要优先满足的需求；而设置日程提醒、控制房间内的家电，这些功能通过语音交互来实现可以使用户进一步感受到智能化酒店的舒适和创新；意见反馈有助于收集用户的反馈以不断优化酒店的服务，通过酒店助手的对话来完成可以获得比纸质调查表更高的反馈率。 而关于酒店的常见问题的咨询，也是酒店助手应当实现的功能之一：一方面这些问题对于新入住的顾客而言是切实需要获得解答的，另一方面直接通过对话方式获得问题的解答比传统的从宣传单中查找或是致电询问前台都更加简单便捷。 对于一些超出酒店基本服务以外的拓展服务，如新闻播报、城市导览等功能，可以对用户体验起到一定的提升，但并非强需求，同时需要对接大量的资源库；而我们的目标是首先搭建最小可用技能，因此这部分功能可以先不去开发或低优先级开发。 3.1.2 明确目标，确定任务类型 在确定了业务场景的边界之后，我们就需要明确这些功能的目标，从而确定任务的类型，不同的任务类型对应着不同的配置方式；首先我们来了解一下任务类型的分类： 可以看出，任务类型区分的关键在于任务目标的有无以及是否需要把请求参数化；了解了这一点后，我们不难将之前梳理的功能进行分类： 3.2 功能定义：确定优先级及关键信息要素 在确定边界和目标后，我们就可以动手对功能进行定义了，在这一阶段，我们需要确定各功能的优先级，并确定每个功能的实体要素。 3.2.1 优先级的确定 首先是优先级的确定，其实在确定边界的过程中，我们已经对功能的重要程度和实现难度进行了分析，在此基础上不难确定出功能的优先级： 3.2.2 关键信息要素的分析 任务型的对话需要将请求参数化，相应的我们就需要分析要完成每个对话都需要将哪些实体要素参数化，而这些实体要素所对应的正是技能的对话意图及其词槽。我们以酒店房间内场景下P0优先级的功能为例进行分析，可以梳理出如下的关键信息要素： 可以发现标红部分因为其关键信息要素的重合而产生了意图的合并，具体如何处理相似功能间意图的拆解与合并，我们在下节对话逻辑梳理中展开讲解。 3.3 对话逻辑梳理：任务型对话的常规与异常情况、问答型的知识分类 3.3.1 任务型对话的意图梳理 任务型对话因具有将请求参数化的这一特点，在配置到对话意图时需整体考虑该场景下的相似任务和相关任务，在这一阶段将对话任务与意图间的映射关系梳理清晰，可以在后续的配置中达到事半功倍的效果。 以上节中进行了关键信息要素分析的功能为例，在物品需求类型的功能间和智能家电的开关控制中出现了功能的关键信息要素重合的情况，下面我们分别针对这两类功能进行分析： 1. 物品需求类型功能 在实际的酒店场景中顾客可能产生远比本文列出的示例更多的物品需求，在物品需求与意图之间建立一一映射关系不仅会浪费大量的人力，而且存在拓展性差、不同意图间的query相似性强相互干扰影响效果的缺点。因此我们采取合并意图、通过词槽来区分具体物品的方式，这种方式前期工作量小，后期拓展性强（只需调整词槽词典即可增删物品）。但也不可不管三七二十一将所有物品需求合并为同一意图，需要从实际场景出发进行合理的意图合并与区分。 2. 家电控制类型功能 家电控制类型的功能在意图的梳理上与物品需求类型的功能基本相同，在上节的梳理中考虑方便未来的拓展，把只有开关指令的设备汇总到一个意图中。 注意：本例中假设灯具只有开关两种指令，若存在更复杂的指令如（柔和模式、工作模式……），则需单独设立意图不可合并。 3.3.2 问答型对话的意图梳理 问答型对话没有需要参数化的内容，往往具有固定的标准答案；这类型的对话逻辑梳理其实就是要对问题进行分类，或者叫知识分类。比如酒店的问题咨询可以如下分类： 3.4 场景数据收集：在真实场景下用户会怎么问？ 人工智能实现语义理解的过程，和教牙牙学语的小朋友讲话的过程是相似的：最初他只能懂你教他的一模一样的内容（训练数据量少时泛化能力差），等到教的内容多了之后就可以理解这个意思的不同表达方式（基于大量的训练数据产生泛化能力）。 因此我们在收集场景数据时，需要尽可能贴近真实场景下用户的表达方式，最好是从实际业务场景中沉淀下来的真实数据，全面覆盖用户在该场景下可能出现的表达方式。关于这些数据收集的技巧在《UNIT 使用技巧与持续优化 https://pan.baidu.com/s/1gyQXvExLka5yjdZr3tUziA 》中有详细的介绍，可参考该教程进行数据的收集。 4 搭建技能模型 -———可拷贝或选择下面红色的文字 在UNIT里一步一步配置出酒店助手技能———-注册百度账号，打开http://unit.baidu.com ，进入UNIT： 4.1 新建技能 在UNIT平台搭建对话机器人的第一步是先创建一个技能，只需要输入一个技能名称，非常简单。 技能名称：酒店助手 4.2 自定义技能：新建对话/问答意图 创建完后就进入技能定义的阶段，技能又分自定义技能和预置技能，每个技能都是由多个相关的意图组成，这个阶段的新建意图就对应我们需求分析阶段的功能定义。以需确认数量物品这一功能为例，可以如下转化为意图： 下面展开讲解具体操作步骤： 4.2.1 新建对话意图 点击【酒店助手】技能，进入技能模块，在自定义技能中【新建对话意图】： 意图名称：ITEM\_NUM\_NEEDED 意图别名：需确认数量物品 4.2.2 添加词槽 添加两个词槽： 1、词槽名：user\_item\_numneeded，别名：需确认数量物品类型，词典：自定义词典——上传自定义词典文件，必填 第一步是选择【添加方式】，选 「新建自定义词槽」，并设置词槽名（user\_item\_numneeded）和词槽别名(需确认数量物品类型)， 第二步【上传自定义词典】 UNIT平台中词槽的识别依赖词槽对应的词典。支持自定义词典，也可以选择系统预置词典，我们建议在能选择系统词典的情况下尽量选择使用系统词典(详见：http://ai.baidu.com/forum/topic/show/869949 )，当系统词典里没有你需要的类型时可以添加自定义词典。 本例中我们希望通过这一词槽来匹配酒店中顾客需要确认数量的物品需求，需要根据自身需求来添加自定义词典，词典文件格式参考demo下载，这里不做展开介绍。 词典值： 毛巾 牙刷 水 矿泉水纯净水浴巾 香皂 第三步设置词槽与意图关联属性，在该意图中的物品类型是必须的关键信息，所以我们选择必填。澄清话术就是当用户表达订票需求的语句里缺少出发时间时技能主动让用户澄清的话术。还可以设置让用户澄清多少轮后放弃要求澄清，默认是3次。 2、配置物品数量词槽的流程与上面的步骤基本相同，在选择词典时需打开【系统词槽词典】的开关，然后选择系统词典sys\_generic\_unit (更丰富的数字+单位，如：一块两毛、三桶、两摞、3千克/立方米) 词槽名：user\_item\_num，别名：物品数量，词典：系统词典——sys\_generic\_unit (更丰富的数字+单位，如：一块两毛、三桶、两摞、3千克/立方米)，必填 添加完所有词槽后如下图： 在词槽列表中可以调整词槽澄清的顺序。 4.2.3 设置对话回应 对话回应就是当对话识别出用户的意图和所有必填词槽值 时给用户的反馈。 有三种回应方式：【答复】、【引导至对话意图】、【引导至问答意图】 这里我们以【答复】为例，设置答复文本内容为：&quot;好的，马上为您送到&quot; 设置完成后最终保存意图 注意点：实际落地的时候这里其实需要你在自己的业务代码里判断当前技能解析的用户意图为需确认数量物品，且用户提供了物品重量、物品数量，这时将这两个词槽值传递到自己的业务管理系统通知到相应服务人员。 引导至对话意图：是当前对话满足一定条件时把当前意图到另一个对话意图，让用户进入另一个意图的对话中。 引导至问答意图：是当前对话满足一定条件时把当前意图到另一个问答意图，让用户直接在目标问答意图下提问并获取答案。 4.2.4 新建问答意图 针对前期分析问答型对话的退票问题 定义一个问答意图 FAQ\_PARK，意图别名：停车场相关问题 4.3 添加训练数据 完成技能的意图定义后，我们进入创建和训练技能的最重要的第二个环节，给技能添加训练数据，这个阶段用到的正是我们之前收集的真实场景下的数据，在其基础上进行总结和分类，给技能提供1到3种学习数据，让其学习我们定义的技能。 在训练数据的选择上，我们应当根据自身场景中的对话类型和数据收集情况来进行选择： 假如你的场景是任务型的又缺少对话样本，这时你就可以先去配置对话模板，快速达到一定效果后再从日志中筛选更多的对话样本； 假如你一开始就有对话样本，这时你可以对话模板、对话样本一起上，这样可以快速达到一个更好的效果； 而如果你还有问答行的对话时，只要添加问答对就可以了，简单易上手。 4.3.1 配置对话模板 对话模板是基于用户的表达方式归纳出的匹配规则，归纳得当的对话模板配置起来简单快速，可以识别多种表达方式，适合短时间内使技能达到可用的对话效果。同时对话模板的优先级高于对话样本，可用于对对话样本训练结果的优化。 在开始配置对话模板之前，我们来明确几个概念： 特征词：特征词通常是具有一类特征的词，可用于在对话模板中匹配这一类词。举例：对于“缝补衣服”意图，用户可能会说“我想缝衣服”、“我想补衣服”、“找谁缝补衣服”，那么对应的模板中，可以设置表示缝补的特征词：缝衣服、补衣服、缝补衣服……这些词不需要作为词槽被提取出来提供给业务，仅用于约束模板的匹配，因此使用特征词而非词槽。 口语化词：口语化词将在语义解析时会被自动忽略掉，以此来提高解析的精准率。比如通用场景下：嗯我看一下明天的天气吧 —&gt; 明天天气，这里把”嗯、我、看一下、的、吧”等口语化词都去掉了。又比如特定场景里：预定如家酒店 —&gt; 预订如家，在定酒店的场景里省略了 “酒店”， 可以将“酒店”配置为口语化的词。 模板片段：UNIT2.0的对话模板提供了一种非常强大的用法——模板片段。多个模板片段组成一个对话模板，每个模板片段都可以由词槽、特征词、特定文本单独或组合而成，而且多个模板片段可以是无序的，也可以是有序的。顺序设为0就表示这个模板片段可以出现在用户query中的任意位置。而非0的，必须按照数字顺序在query中出现。此外还可以设置一个模板片段是否必须在用户query中出现。 阈值：它是说当前模板配置的词槽、特征词占用户query的长度比例，当只有这个比例达到这个阈值的时候，我们才会判定用户的query就是这个模板所表示的意图。 理解了这些概念后，我们就可以从真实场景的数据中提炼相应的对话模板了。以需确认数量物品这一意图为例： 我们首先来定义代表对物品的需求的特征词： 在页面较下方找到特征词列表，点击新建特征词，填写下列内容，点击确定保存该特征词： kw_item_want，描述：物品需求 词典值： 我想要 我要 给我拿 给我送一下 给我 送 要 完成新建我们所需的特征词后，点击添加对话模板来进行配置： 在选择必须匹配这一项时，因为在用户提到的物品类型为需确认数量物品类型时，我们才会定位到需确认数量物品意图，因此将user\_item\_numneeded词槽这一模板片段设置为必须匹配，而其余两个模板片段设置为非必须匹配，来保证模板的泛化能力。 目前我们只配置了一条对话模板，当我们有多个对话模板时，它们之间是有优先级的，在对话模板列表的上面的优先级要高于下面的，可以选中一条对话模板，然后执行上移、下移的操作来调整优先级。 关于对话模板的更多技巧说明可 下载文档进一步学习了解：https://pan.baidu.com/s/1j6cx9HPuRav1tvOToW2mEA 4.3.2 标注对话样本 对话样本是技能通过对海量标注数据的深度学习，获得“理解”相应场景下的对话的能力。这部分我们要把需求分析最后一个阶段收集到的对话数据导入UNIT平台，然后给他们逐条标注意图、词槽。这部分数据可以用于后续的样本学习，让对话机器人获得更好的对话理解泛化能力。 注意机器学习一般对训练样本有数量的要求，几条几十条数据很难训练出令人满意的泛化理解能力，在实际配置时需要海量样本的标注。标注方式参考产品手册，这里不做示例。 4.3.3 添加问答对 在创建问答意图FAQ\_PARK时，系统已自动创建相应的问答集FAQ\_PARK，我们可在其中添加问答对。问答对有直接在页面上录入和导入问答对数据文件两种方式，本文示例在页面上录入问答对的方式： 点击添加问题，录入问题文本后，再点击添加答案，录入问题的对应答案；问题与答案之间支持多对多的对应关系； 问题： 停车场在哪 车往哪停 查询停车场位置 哪里有停车场 答案： 停车场的位置在酒店地下一至三层，您可通过……进入停车场 点击保存，保存该问答对。 4.5 训练模型 训练技能有两种方式，一种是只训练我们上面配置的对话模板，另外一种是 训练对话样本同时训练对话模板 系统默认必须训练对话模板，不论你有没有标注对话模板。如果这时如上图你在对话样本集里使用了默认选项『使用沙盒中的模型』，直接训练模型并生效到沙盒，会需要15~30秒的时间。（首次训练只能选择『使用沙盒中的模型』） 如果如上图在对话样本集选项中选择了『重新选择样本』且选中了有标注样本的样本集，则对应后端的训练讲采用深度机器学习的策略进行样本的训练学习，同时也会把标注的模板也融合进来一起训练。这时训练的速度会与标注的对话样本量成正比。这里需要注意的是一定要选择系统自带的「闲聊负例样本」，这样可以降低技能的误召回情况，就是告诉技能哪些query是闲聊而不是我们设置的意图。 4.6 测试体验 完成模型的训练后，就可以在测试窗口测试一下对话，看看对话效果是否符合预期了： 本入门教程到此结束]]></content>
      <categories>
        <category>项目</category>
        <category>智能家居</category>
      </categories>
      <tags>
        <tag>项目</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[智能家居项目调研]]></title>
    <url>%2F2018%2F11%2F11%2F%E6%99%BA%E8%83%BD%E5%AE%B6%E5%B1%85%E9%A1%B9%E7%9B%AE%E8%B0%83%E7%A0%94%2F</url>
    <content type="text"><![CDATA[目录 项目背景 设计原则 发展历史 国内外研究现状 可行的解决方案 一、项目背景智能家居或称智能住宅，是一个以住宅为平台，兼备建筑、网络通信、信息家电、设备自动化，集系统、结构、服务、管理为一体的高效、舒适、安全、便利、环保的居住环境。 随着“智慧地球”概念的提出，物联网技术掀起了继计算机、互联网后世界信息产业的第三次浪潮，把互联网技术应用在传感器上，将被检测设备的信息上传到服务器上，同时添加服务器对设备的控制，物联网技术为智能家居技术的发展提供了新的方法。实现家庭信息化、网络化是是未来家居发展的主要方向，智能家居将成为蕴含着巨大市场价值的自动化产业。社会在飞速发展，我们的生活发生着翻天覆地的变化。家是我们永远温馨的港湾。随着我国经济的飞速发展，人们的生活水平不断提高，特别是年轻的一代人开始追求生活的个性化、自动化，希望在快节奏的生活中感受充满乐趣的生活方式，要求居住环境更加安全舒适与人性化。随着智能家居市场的不断完善，科技的不断进步以及大规模厂商的介入，必将推动行业成本的下降，智能家居市场的行业前景一片光明。 据统计，2016年我国智能家居的渗透率只有0.1%，远远落后于美国、日本等国家。但随着云计算和人工智能等技术的快速发展，我国智能家居硬件的渗透率将快速提升，预计2020年将达到0.5%。尽管渗透率依然低于西方发达国家，但我国智能家居市场总体体量将相当可观。各国智能家居渗透率对比如图1-1所示。 2014年，我国智能家居产业市场规模达到290亿元；2015年，我国智能家居市场规模达403.40亿元，同比增长41%。未来五年（2017-2021）年均复合增长率约为48.12%，2021年市场规模将达到4，369亿元。 二、设计原则 智能家居系统设计原则一：实用便利 智能家居最基本的目标是为人们提供一个舒适、安全、方便和高效的生活环境。**对智能家居产品来说，最重要的是以实用为核心，摒弃掉那些华而不实，只能充作摆设的功能，产品以实用性、易用性和人性化为主**。 **在设计智能家居系统时，应根据用户对智能家居功能的需求，整合以下最实用最基本的家居控制功能：包括智能家电控制、智能灯光控制、电动窗帘控制、防盗报警、门禁对讲、煤气泄露等，同时还可以拓展诸如三表抄送、视频点播等服务增值功能**。对很多个性化智能家居的控制方式很丰富多样，比如：本地控制、遥控控制、集中控制、手机远程控制、感应控制、网络控制、定时控制等等，其本意是让人们摆脱繁琐的事务，提高效率，如果操作过程和程序设置过于繁琐，容易让用户产生排斥心理。所以在对智能家居的设计时一定要充分考虑到用户体验，注重操作的便利化和直观 性，最好能采用图形图像化的控制界面，让操作所见即所得。 智能家居系统设计原则二：可靠性 整个建筑的各个智能化子系统应能二十四小时运转，系统的安全性、可靠性和容错能力必须予以高度重视。对各个子系统，以电源、系统备份等方面采取相应的容错措施，保证系统正常安全使用、质量、性能良好，具备应付各种复杂环境变化的能力。 智能家居系统设计原则三：标准性 智能家居系统方案的设计应依照国家和地区的有关标准进行，确保系统的扩充性和扩展性，在系统传输上采用标准的TCP/IP协议网络技术，保证不同产商 之间系统可以兼容与互联。系统的前端设备是多功能的、开放的、可以扩展的设备。如系统主机、终端与模块采用标准化接口设计，为家居智能系统外部厂商提供集 成的平台，而且其功能可以扩展，当需要增加功能时，不必再开挖管网，简单可靠、方便节约。设计选用的系统和产品能够使本系统与未来不断发展的第三方受控设备进行互通互连。 智能家居系统设计原则四：方便性 布线安装是否简单直接关系到成本，可扩展性，可维护性的问题，一定要选择布线简单的系统，施工时可与小区宽带一起布线，简单、容易;设备方面容易学习掌握、操作和维护简便。系统在工程安装调试中的方便设计也非常重要。家庭智能化有一个显着的特点，就是安装、调试与维护的工作量非常大，需要大量的人力物力投入，成为制约行业发展的瓶颈。针对这个问题，系统在设计时， 就应考虑安装与维护的方便性，比如系统可以通过Internet远程调试与维护。通过网络，不仅使住户能够实现家庭智能化系统的控制功能，还允许工程人员 在远程检查系统的工作状况，对系统出现的故障进行诊断。这样，系统设置与版本更新可以在异地进行，从而大大方便了系统的应用与维护，提高了响应速度，降低 了维护成本。 智能家居系统设计原则五：轻巧型 “轻巧”型智能家居产品顾名思义它是一种轻量级的智能家居系统。“简单”、“实用”、“灵巧”是它的最主要特点，也是其与传统智能家居系统最大的区别。所以我们一般把无需施工部署，功能可自由搭配组合且价格相对便宜可直接面对最终消费者销售的智能家居产品称为“轻巧”型智能家居产品。 三、发展历史 事物的发展总是阶段性的，每个阶段都有一定的代表性，智能家居也是如此，其发展主要分为三个阶段： 第一阶段： 家居电子化阶段，在这个阶段，主要是面对用户家里的单个家电，家电还没有融入网络，各个家电之间也没有什么联系，都是独立工作 。 第二阶段： 住宅自动化阶段，这个阶段的主要特征是家居已经开始面向功能发展，某些家电已经连入网络，能够实现一些简单的功能，如：水电气的自动抄表等，我国大多数家庭现在就处于第二阶段。 第三阶段： 家居智能化阶段，这个阶段是面向系统的阶段，智能家居系统把家里面所有家电连入网络，人们可以通过一个控制终端达对家电的集中控制与监控的目的，并且还具有远程控制的功能。这个阶段的智能家居系统为人们提供方便安全，温馨舒适的家庭环境，丰富了人们的日常生活。同时也保持了环境和家电之间的协调，使得家电更加的节能，安全。 1915年到1920年——家用机器的开始 机器被引入家庭是为了帮助解决家庭劳动力日益短缺的问题（比如缝纫机、吸尘器、食品加工器）。广告界将这些电力机器称作是“电力春季大扫除”。 这是在家庭里使用电力技术的第一个实例，电力机器在家居行业的前景由此打开。 1939年——预测智能家居的未来 《大众机械》杂志中的“未来家电”这篇文章中所描绘的厨房装置是这样的：当你在做饭时，你还可以通过该装置接收到短波无线电频率，所以当你在做饭时，你还可以在第一时间里了解到新闻资讯。 1966年——第一台家用“电脑” ECHO IV是一台家庭自动化机器，它可以用来计算购物清单、控制房屋里的室内温度、控制家里电器的开关。但对于这个装置的真正成功性还存在着大量的质疑，并且它还有一个缺点：体型庞大。 19世纪70年代——自动化的开始 X10是一个非常简单的系统，该系统是利用家里的电线在各类家用电器之间建立起一种联系。但是，由于这个系统是依靠电线完成的，就很容易受到电波干扰，实用性不是很强。 1984年——为智能家居的发展奠定基础 世界上第一栋智能建筑于 1984 年在美国康涅迪格州建成，它的构建很简单，就是把一栋旧的大楼进行了改装，利用计算机对大楼进行监控，并控制大楼里面的电灯、电梯等，还提供了一些通信服务。 美国建筑商协会成立了一个名为“智能家居”的特殊利益集团，他们提倡将科技和家居设计相结合的设计理念；有的人也把依照这种理念设计出来的建筑称作“电脑化建筑”（cybertecture）——将计算机控制和建筑设计相结合。 19世纪90年代——智能家居理念成为一种流行文化 智能家居的想法在19世纪90年代颇受欢迎，电影《梦宅诡影》中房屋里的智能家居系统是为房屋的拥有者所控制，他是一个厚颜无耻的家伙。但在迪斯尼电影《智能房屋》中体现的则是一种家庭友好型智能家居理念。 2010年——Nest开启智能家居新时代 Tony Fadell是前苹果公司iPod的部门主管，Nest Labs（简称Nest）就是由他创办的智能家居公司。他认为现有的家庭自动化产品太过于笨重，只是简单的将技术融入进产品罢了。所以，这家公司的建立开启了智能家居发展的新时代，比如与无线网络连接的恒温器和烟雾警报器。 2012年——家庭自动化公司SmartThings成立 SmartThings承诺设计一款能够连接家里任何一款电器装置的应用，还在Kickstarter上为它筹集到了120万美元的资金（阿什顿·库奇也是投资者之一）。有了这款应用，可以让你的家用电器之间有更亲密的联系。截至2013年，SmartThings已经了发货1万多个智能家居中控器。 2013年——微软发布物联网实验室 物联网实验室是微软推出的一个全新平台，旨在让研究者更好地研究联机设备在家庭和其他物理空间中的使用。实验室提供了一个虚拟的仪表盘来监视和控制不同的连接设备，并为与建筑相关的应用制订了标准。实验室记录数据后，人们就可以通过家庭安全照相机了解到家里的门是被打开还是被关闭，当然要想通过它知道其他的事情，也不在话下。 Linux基金会组织了AllSeen Alliance，得到了23个电子制造商和软件应用开发商的支持，其中包括LG、松下、夏普和高通。为了发展连通性技术，该组织采用的是独立于供应商的办法来开发一个开源软件。作为最大的跨行业智能家居空间联盟，AllSeen Alliance的目标是让家里的所有电器产品一起工作。 至今——将所有的事物聚集到一个平台 Quirky（一个创意产品社区与电子商务网站）的创始人本·考夫曼推出了一款名为Wink的智能应用，这款应用可以将Quirky、Nest和飞利浦等的产品集中到一个网络平台，再由其集中控制。有了Wink，你没必要自己动手干任何事了。 据三星显示首席执行总裁尹富根（Boo-Keun-Yoon）指出，三星在智能家居行业的未来是光明的。三星公司以2亿美元收购了SmartThings。三星的智能家居应用能够实现用户与其家庭电器的联系，用户可以智能控制电冰箱、洗衣机、空调、微波炉等。Google以32亿美元收购了Nest Labs，Nest Labs主要是改造像恒温器和烟雾警报器一样的家用设备。谷歌的这次收购表明谷歌对其在物联网领域的发展有极大的信心，并且谷歌也因这次收购走在自动化家居行业的前沿。苹果宣布了HomeKit的到来，HomeKit允许用户智能控制家里的电灯、锁、相机、恒温器和插头等。它目前还没有投入使用，但是制造商们早已生产出能和它一起工作的相关产品。 去年7月中旬，三星、戴尔和英特尔联合成立了一个名为“开放互联联盟”（Open Interconnect Consortium）的组织，旨在为当下大热的物联网设备建立统一标准，也是为了迎合物联网数十亿设备发展的需求。大约在其成立一周后，Nest、三星和其他5家制造商也发起了一个名为“Thread”的无线网络联合组织，制订了一个基于IP化的无线网络协议，允许他们公司的智能设备之间相互联系。这种联合组织的不断出现，说明越来越多的公司和行业对家用自动化和物联网领域感兴趣，对其的投资也在不断增加。 四、国内外研究现状 国外研究现状 智能家居这个概念最早是由美国、欧洲一些发达国家提出。80 年代之后，由于计算机网络技术、通讯技术、信息处理技术的迅速发展使得这一概念成为现实。1984 年，全球首幢智能建筑坐落于美国的康涅迪格州，该建筑是通过对一栋旧式大楼改装来实现，对于智能家居后期发展起关键作用。由于当时技术水平有限，仅通过电脑对大楼的照明设备、供水系统、空调等进行控制。从第一栋智能建筑建成之后，各种智能家具设计方案如同雨后春笋，在美国、新加坡、加拿大、欧洲、日本等发达国家迅速发展开来。 此后美国颁发的《二十一世纪的技术：计算机、通信》文件，更加大了智能家居的推广，使得各种高新技术开始逐渐应用到智能建筑中。并提出了到 21世纪，美国的智能建筑将综合利用网络通讯技术、可移动办公技术、家居智能化技术、电视双向传输技术、无线组网技术以及数据卫星通信技术等，各种新技术的应用会带动此行业的发展。智能建筑在美国出现后，日本官方非常重视，出台了一系列的建设计划，包括智能家庭、智能建筑、智慧城市等等，并利用其自主研发的住宅总线技术提出了当时非常先进的家庭总线系统理念，这一理念也在 1988 年被开发制定为超级家庭总线技术-HBS 标准，至此智能家居这一概念更加完善。到 90 年代，幕张市首个示范性智能小区建成，后期又引入多媒体技术，为智能化建筑的发展道路指明了新的方向。 随着生态环境方面问题日益突出，使得欧洲的智能家居主要考虑向生态建筑方面进行发展，如何通过高科技手段来建造一栋生态建筑成为研究的主要目的。在此生态建筑不仅要利用一切可利用的先进技术来实现低能耗、低污染、可持续发展的目标，还要在深入研究人体工程学和室内热功环境的基础上，根据人体对环境做出的心理、生理方面的一些反映，来构建一个舒适、高效的办公环境。 在系统研发方面，美国和一些欧洲国家投入比较多，且发展比较快。外国的很多知名企业投身于智能家居系统的研发中，如 Microsoft 的“梦幻之家”、新加坡的“未来之家、Motorola 的“居所之门”、IBM 的“家庭主任”等。此外，日本的松下电器、韩国的三星、Intel、3COM 等知名公司也跻身于智能家居的研究中，智能家居的前景十分广阔，因此很多厂商开始加入这一市场。 下面是市场上比较出名的智能家居系统： **1. X-10 系统**，这是美国在智能家居方面最知名的技术，市场占有率也是最高的一项技术，它采用国际上通用的电力载波协议，使用此项技术的产品可以通过电力线来直接通信，无须重新布线，且价格低廉、设置方式简单、产品多样化，因此在美国得到广泛应用。此系统固然强大，在国内却并不适合。首先由于此项技术是基于美国的电力线环境来进行设计，因此在国内环境不一定适合；其次，该系统主要应用在单独别墅，与我国基本现状相差较大，故在我国并不适合。 **2. EIB 系统**，这是德国研发的一套新型系统，通过预埋总线以及中央控制的方式来完成。在德国的大型超市和办公建筑中，此系统应用较多。但是由于整个工程比较复杂，对建筑带来了较重的建设成本压力，且要求苛刻。其最大弊端是线路要事先预埋，对老式住宅区及其不便，因此还未能打开国内市场。 **3. 8X 系统**，这是新加坡通过总线预埋和集中控制的方式来构建，并引入 X-10 的产品来对系统升级扩展，整个系统发展比较成熟。但是此系统和 EIB 系统类似，都是需要总线预埋，在旧式楼房的改造方面显得有些疲软，因此只对于新建住宅较适合；其次集中控制方式使得用户控制起来不够便捷，且前期成本投入太高。综合该系统在灵活性、系统架构、以及价格方面的欠缺，使得此系统虽然发展成熟，但是在国内却有比较少的应用。 下面是市场上比较出名的智能家居公司： **1. HomeKit** HomeKit，是苹果2014年发布的智能家居平台。2015年5月15日，苹果宣布，首批支持其HomeKit平台的智能家居设备在6月上市。 2016年6月13日，苹果开发者大会WWDC在旧金山召开，会议宣布建筑商开始支持HomeKit。而在不久前举行的2018 WWDC大会上，苹果在新发布的iOS 12和tvOS 12中，赋予了HomeKit一项重要功能——支持第三方遥控器。如今经过4年多的开发和建设，HomeKit平台在家庭自动化市场中终于要站稳脚跟了。 HomeKit本质上是苹果蓝牙直连和多点设备框架的“伴侣”，允许开发人员使用一套简单的命令控制设备状态，发送命令。当然，如果设备想被iOS控制，必须要先加入到Made For iPhone（MFI）项目中，按照苹果要求，将特殊的无线芯片和软件包整合在硬件设备里面。虽然现在苹果对加入MFI设备的要求不像过去那么严格，但是这种做法还是阻碍了开发人员开发兼容HomeKit的应用，也让开发人员无法使用Arduino控制器搞定属于自己的自动化家居设备。所以，你可以把HomeKit看成是一个自动化家居行业的助推器，而不是一个“黑客工具”。 ![](https://i.imgur.com/jAMKMz9.jpg) 实际上，在获得授权允许之后，HomeKit能为支持的App和配件设备提供独立的信息访问方式。**这意味着，任何一款支持HomeKit的应用，都可以立即获取房间内部所有设备的信息**。当你在自己家里新增了智能设备之后，无需重新配置，只需插插头，把它添加到现有系统之中就可以了。 **Siri被认为是HomeKit的主要系统接口，不过设备自带的独立App也有控制功能**。**换句话说，如果你已经安装好了设备，Siri就能识别，并执行语音命令**。**你只需简单地告诉Siri“打开卧室灯”，它就会自动识别设备、配件和房间，然后执行相应的操作**。借助HomeKit，用户可以使用iOS设备控制家里所有标有“Works with Apple HomeKit”（兼容 Apple HomeKit）的配件。这些配件包括灯、锁、恒温器、智能插头及其他配件。**苹果认为，HomeKit不仅仅是一个简单的框架，用户可以在这里打开和控制各种配件**。 **在HomeKit框架里面，可以定义好一些初始设备，比如门锁、车库大门、灯光开关**。**支持开发人员也可以自定义无限数量的新设备**。苹果给HomeKit的定位是“开放的”系统，允许创建并定义任何设备，提供自动交互。内部系统非常灵活，苹果并没有做太多限制，而且允许开发人员为设备编写操作命令，做其他工作。不过，即便HomeKit具有很强的开放性，没有加入MFI就是另一番景象了。所有支持HomeKit的硬件都使用了端到端加密，有很强的安全性。HomeKit API只有在App激活，或是在前端打开时才能使用。目前，还没有应用能在后台运行时使用HomeKit。 **当然，你可以设定在特定条件下执行命令，这些条件就包括了应用关闭状态**。**但是，这需要用户给出非常明确的命令，比如“在我回到家时打开车库门”，或是“在礼拜二晚上八点开灯”，等等**。 实际上，真正处理用户命令的是iOS系统，而非是那些独立App应用，一些恶意应用如果没有用户许可，是无法执行一些多余操作的。**另外，苹果系统还提供了将房间进行分组的“区域”功能，按“楼上”或“楼下”划分区域**。用户还可能按照服务进行分类，这样就可以支持像“打开所有灯光”这样的命令了。**在MFI硬件设备上市前，开发人员可以用苹果的模拟硬件设备的程序“假装”在控制设备**。 Home Kit协议规范了智能家居产品如何和iOS终端连接和通信。苹果软件高级副总裁Craig Federighi曾经轻描淡写地说到，通过Home Ki协议的绑定功能（Secure Pairing）能确保只有你的iPhone能够开你的车库门。在宣布的芯片合作伙伴里有Broadcom，Marvel和TI，这几家都是植入式Wi－Fi芯片的主流供应商，所以可以确认HomeKit前期主要支持Wi－Fi或者直连以太网的设备。目前Wi－Fi智能硬件开发上有不少难点要克服，包括设备如何与手机配对，如何得到Wi－Fi密码并且加入家里的热点，如何保证稳定和安全的远程连接等等。 **在数据库层面，苹果推出了一个有利于行业发展的基础设施：在iOS上建立了一个可以供第三方app查询和编辑的智能家居数据库**。**这个数据库包含几个非常重要的概念是对现在的智能硬件开发商有借鉴意义的：家庭，房间，区域，设备，服务，动作，触发**。 **2. IoT** 从汽车制造商到医院的先进医疗设备，Windows在为全球各行各业的智能设备提供服务，帮助它们迈向更智能、更强大、更互联的物联网时代。Windows 10 IoT的创新路线图在2018年10月的更新中又向前迈进了一大步，通过机器学习、工业安全、边缘智能，对于对于Win 10 IoT企业，LTSC服务选项可用于Win10 IoT Core服务，如销售点系统、自动取款机和工业设备控制器。 另外，有了Win10 IoT Core服务，设备制造商可以降低支持成本，分销商可以创建业务模式，为客户提供经常性的长期价值。据微软官网介绍，Win10 IoT可以在边缘做更多的工作，包括机器学习、事件处理、图像识别和人工智能，而无需内部开发，与Azure物联网再到边缘的无缝集成为Win 10 IoT设备带来了云智能和安全分析。 以及将云工作负载转移到智能边缘。Azure IoT Edge是一个完全托管的服务，通过在Win10 IoT设备上直接部署和运行人工智能（AI）工作负载、Azure服务和定制逻辑，在本地交付云智能。Azure IoT Edge模块可以从Azure IoT Hub远程部署到运行Win 10 IoT Core或Enterprise的Edge设备上。 ![](https://i.imgur.com/MREz0yJ.png) Azure IoT Central（Azure物联网中心） ，这是一个基于Azure云服务构建的 端到端IoT SaaS（软件及服务）平台 ， 该平台可以帮助客户实现完全托管的SaaS产品，无需专业人士即可帮助客户提出并实现物联网方案。凭借着Azure IoT Central，微软成为少数几家能为物联网提供核心服务、PaaS（平台即服务）和SaaS的公司之一。 **3. Google Assistant/Home** 对于谷歌来说，昔日32亿美元收购而来的Nest，为了与智能音箱等硬件协同，对Nest进行整合，并与智能音箱部门合并。与此同时，推出了Nest Hello视频门铃和Nest X Yale智能门锁，新一波智能硬件新品上市，提高Nest在智能家居市场竞争力，并率先发起价格战，其温度传感器仅需要39美元的，可与Nest Learning Thermostat绑定使用，与亚马逊形成正面对抗。 同时，谷歌还以5600万美元投资了一家人工智能硬件公司SambaNova，为人工智能和数据分析提供计算机处理器和软件的初创公司。 得益于在AI 技术在各行各业应用，亚马逊Alexa和谷歌的Google Assistant成为全球最受欢迎的语音助手，越来越多的智能硬件产品纷纷内置其语音技术。 支持持谷歌语音助理的设备出货量超 4 亿，还有其包括谷歌Home等智能设备，截至目前，谷歌凭借安卓系统使得谷歌占据了移动互联网核心位置，且AI技术应用也走在了全球前列，引领人工智能科技发展，特别作为开放者的姿态，Google Assistant语音助手无处不在，不仅要做好家庭管家这一角色，还承担与生活息息相关的场景落地。 谷歌在智能手机和其他移动智能设备所构建的Google Assistant为核心庞大生态体系，其他厂商无法比拟，从系统道软件、再到智能硬件，嵌入AI 技术，欲让AI无处不在。 此外，谷歌Home与August、LIFX、TP－Link、Rachio、Vivint、和百思买的Insignia也进行了整合，允许其产品的所有者通过谷歌Home发布语音控制功能。 国内研究现状 智能家居主要包括以下内容： （1） 家居布线系统：家庭智能化的实现，第一步就要进行家庭布线的基础设施建设，家居布线系统把电话、有线电视、电脑网络、影音系统、家庭自动化控制系统的布线统一规划、布局、集中管理，为实现家居智能化提供网络平台，通过家居综合布线既可以实现自动化的控制，又可以做到资源共享，家庭内部只需一台影碟机、音响、卫星电视接收机就可以在家庭内部每一个房间观看电影、享受音乐，可以实现多台电脑联网，共享宽带服务，多路电话任意接听、转接。而且采用综合布线，使得家庭内部布线系统具有良好的扩展性和可升级性，满足不同用户现在和未来的需求。 （2） 家居安防系统：人们对于安防系统的要求越来越高，家居安防系统可以有效的利用技防手段来实现安全防范。家居安防系统包括防盗、防燃气泄漏、防火等功能，同时可备远程监控，便得住户可以远程通过网络或电话随时了解家庭内部情况，同时可监听或者监视听或者监视家庭内部情况。 （3） 家庭自动化系统：智能家居的主体在于家庭自动化，将来家庭自动化的主体是家电、照明等电气设备的控制。家庭自动化系统能够通过集中或者分布式控制家庭内部照明或者家电，住户可以通过网络或者电话远程控制家庭内部设备。家居自动化系统是将来智能家居的主要发展方向。 （4） 家庭体验系统：人们对生活体验的要求越来越高，对家庭内部影音系统、家庭内部环境、网络虚拟环境等的需求也越来越高，用在这方面的消费支出会越来越高，将来的家居智能化也会更多的满足人们这些消费。 目前国内的各种智能化系统和产品虽然很多，但更多的是系统相互独立、集成度比较低、各个系统相互联系不大、家庭内部没有统一的平台。 智能家居这一概念从 90 年代末引入我国，相对国外来说发展比较晚，但是随着国内房地产行业的迅猛发展，智能家居概念逐渐深入人心。在国内，智能化建筑首先在一些沿海城市出现。在 1997 年，国家首批“智能住宅示范工程”-上海中皇广场的开建成为智能家居蓬勃发展的导火线。在《2000 年小康型城乡住宅科技产业工程项目实施方案》文件中，明确提出智能化小区的建设将作为国家重点发展项目，标志着智能家居的发展进入一个全新阶段。如今国家正在重点发展物联网行业，且“十二五”规划中也提出智能化住宅建设将成为国家战略性新型产业，因此此行业前景将会非常广阔。 下面是2017年我国智能家居十大品牌： 1. 海尔 U-Home 海尔U－home是海尔集团在物联网时代推出的美好住居生活解决方案，它采用有线与无线网络相结合的方式，把所有设备通过信息传感设备与网络连接，从而实现了“家庭小网”、“社区中网”、“世界大网”的物物互联，并通过物联网实现了3C产品、智能家居系统、安防系统等的智能化识别、管理以及数字媒体信息的共享。海尔U－home用户在世界的任何角落、任何时间，均可通过打电话、发短信、上网等方式与家中的电器设备互动，畅享“安全、便利、舒适、愉悦”的高品质生活。 海尔智能家居是海尔集团在信息化时代推出的一个重要业务单元。它以U-home系统为平台，采用有线与无线网络相结合的方式，把所有设备通过信息传感设备与网络连接，从而实现了“家庭小网 ”、“社区中网 ”、“世界大网 ”的物物互联，并通过物联网实现了3C产品、智能家居系统、安防系统等的智能化识别、管理以及数字媒体信息的共享。海尔智能家居使用户在世界的任何角落、任何时间，均可通过打电话、发短信、上网等方式与家中的电器设备互动。 海尔集团在介入智能家居领域以后，把重心放在了智能家居平台的研究上，重点研究各个家庭智能化系统的整合。 2. 华为 HiLink 华为HiLink联盟的智能产品来自业界TOP厂家，目前有50余家核心合作伙伴，覆盖家庭娱乐、能耗、照明、自动化、安防等6大领域百个品类千余产品，还有更多品类正在不断增加，您可以根据自己的需要灵活选择。 其实，早在2015年12月华为就发布了HiLink战略，围绕“开放、连接、智能”三个关键词，主要包含四个部分：开放的华为HiLink协议，华为LiteOS操作系统，提供高速稳定Wi－Fi连接的华为路，由为用户提供一个统一管理的华为智能家居App。 今天我们重点剖析一下华为的“生态语言”HiLink协议和最新推出的“生态枢纽”路由器Q2。 智能硬件的“普通话” 华为HiLink如何打通全场景智能家居？ 简单来说，华为HiLink可以看作是智能硬件的“普通话”，让不同品牌厂家的智能设备互通互联。它以支持HiLink智联协议的华为路由器（带Hi按键的路由器均支持HiLink智联）为中心，构建智能家庭网络。 短短两年时间，华为HiLink智能家居联盟发展速度惊人。笔者认为，华为HiLink生态之所以快速获得行业和合作伙伴的认可，用户、技术、品牌、渠道四个方面缺一不可。 首先是用户。任何技术和标准的推广都离不开用户作为后盾，智能家居更是如此。华为HiLink依托于华为手机、平板、穿戴、家庭网络海量的用户，基础夯实。2017年，华为（含荣耀）品牌智能手机全年发货量1．53亿台，全球第三；终端设备及家庭网络2013年－2015年全球累计激活用户2．9亿，2016年－2018年全球累计激活用户预计为6亿。 其次是技术。要实现真正的智能家居生活，关键在于互联互通。众所周知，华为最擅长的就是连接技术，拥有30年来深厚的技术积淀。“无连接、不智能”是其一直坚持的理念，华为HiLink智能家居诞生伊始，就将路由器作为其核心设备，较其它智能家居“玩家”有明显的Buff加成。 从功能上来讲，华为路由不仅提供Wi－Fi连接，同时可让整个智能家居体系实现更加高效的本地控制。比如，用户在控制某一款智能设备时，无需“绕云一圈”，华为路由器作为智能家居中枢，在接收指令后可以毫秒级响应执行。而其它智能家居方案，即便在家里也要通过云来处理，速度往往会慢1－2秒，而如果外部网络不通畅，体验则大打折扣。 具体来说，华为HiLink有以下几方面的优势： 1、联网简单：自动发现各品牌家电，一键联网； 2、联接范围广：通过华为HiLink路由器，可扩展连接不同协议、其它生态的设备； 3、联接稳定：分布式WiFi路由器，WiFi无缝覆盖、信号稳定； 4、跨品牌联动：打通设备之间的连接，支持不同品牌不同品类家电联动，不再需要一个个手动操作； 5、跨时空控制：突破时间与空间的距离，无论何时身在何地，随时随地掌控家中状况。 3. 米家 MIJIA 小米智能家居是围绕小米手机、小米电视、小米路由器三大核心产品，由小米生态链企业的智能硬件产品组成一套完整的闭环体验。目前已构成智能家居网络中心小米路由器、家庭安防中心小蚁智能摄像机、影视娱乐中心小米盒子等产品矩阵，轻松实现智能设备互联，提供智能家居真实落地、简单操作、无限互联的应用体验。并且，极具竞争力的价格也将小米智能家居塑造为大众“买得起的第一个智能家居”。 小米智能家居布局与小米路由器有着密不可分的关系。从路由器第一次的公测时标榜的“顶配路由器”到第三次公测时则成为了“玩转智能家居的控制中心”，预示着小米路由器最初的产品定义：“第一是最好的路由器，第二是家庭数据中心，第三是智能家庭中心，第四是开放平台。通过小米路由器、小米路由器App、小米智能家庭App可实现多设备智能联动，设备联网、影音分享、家庭安防、空气改善等功能和应用场景十分丰富。 截止2015年1月小米路由器销量已突破百万，在国内智能路由器市场遥遥领先。截止2015年6月，小米智能家庭在线设备超1000万、APP安装用户超1500万、日活超200万，业已成为全球第一智能家居平台。 小米以“开放、不排他、不独家”为原则发展生态链，构筑智能家居产品矩阵。未来，小米智能家居将逐步实现海量用户覆盖、资金资源注入、通用技术接入、大数据存贮计算、服务方案提供、渠道扩展触达、用户互动服务等全方位多维度的解决方案，携手更多硬件设备提供商，推动智能家居产业链发展，构建相融合的核心技术，完善行业规范建立，共同打造智能硬件生态体系。 自小米路由器推出起，小米智能家居就备受业界关注。地产企业作为智能家居落地的天然土壤，在近些年来销售以及配套服务方面也在寻求差异化。而智能家居作为为业主提供的增值体验之一，成为了地产企业关注并选择的模式。结合小米智能硬件产品的良好体验，小米智能家居计划应运而生。 小米智能家居计划希望与国内地产企业的合作，真正推动智能家居在家庭用户中间的应用与落地。 天猫精灵机身尺寸：126mm X 83mm X 83mm 整机重量：400g 操作系统：AliGenie语音助手 内置cpu：MTK MT8516 网络/蓝牙：2.4G WIFI +BT 4.0 电源输入：DC 12V/1A (100V-240V) 天猫精灵（TmallGenie）是阿里巴巴人工智能实验室（Alibaba A.I.Labs）于2017年7月5日发布的AI智能产品品牌，当天同步发布了天猫精灵首款硬件产品——AI智能语音终端设备天猫精灵X1，未来还将推出更多AI智能产品。 天猫精灵X1内置AliGenie操作系统，AliGenie生活在云端，它能够听懂中文普通话语音指令，目前可实现智能家居控制、语音购物、手机充值、叫外卖、音频音乐播放等功能，带来人机交互新体验。依靠阿里云的机器学习技术和计算能力，AliGenie能够不断进化成长，了解使用者的喜好和习惯，成为人类智能助手。 天猫精灵X1采用了专门为智能语音行业开发的芯片，在解码，降噪，声音处理，多声道的协同等方面做了专门的优化处理。针对需要进行大量音频处理、声音合成的工作环境，定制芯片加入了独立的NEON处理单元，NEON技术可加速音频和语音处理、电话和声音合成等，从而带来更优秀的语音识别及音频处理效果。 在收音方案上采用了六麦克风收音阵列技术。顶部拥有一个六麦克风收音阵列，有六颗高灵敏麦克风，有助于收集到来自不同方向的声音，从而更容易在周围的噪音中识别出有用的信息，来达到更好的远场交互效果。 天猫精灵X1背后的团队在降噪技术上做了大量研究，在厨房，客厅，卧室，书房等环境里面，对玻璃，木材，混凝土，金属，石材等各种材质和环境进行了上千次实验，并专门针对家庭使用场景做了优化，即使在有噪音的环境中也能正常唤醒和使用。并且具备一定的学习功能，可以根据环境噪音进行学习和进化，适应不同家庭环境噪音，经过7天左右优化，会更加适应所在家庭环境。 此外，天猫精灵X1还使用了回声对消和远近场拾音等技术，即使在播放音乐的同时也能正常接收语音指令。 附加天猫精灵官网https://bot.tmall.com/ 关于阿里巴巴人工智能实验室 阿里巴巴人工智能实验室（Alibaba A.I Labs）致力于探索下一代人机交互技术并实现新颖的用户体验。其研发部门主要负责在阿里巴巴的商业生态系统中开发创新的人工智能应用，并为阿里巴巴的客户及合作伙伴提供人工智能解决方案。实验室拥有世界顶尖的研究团队，专注于各个领域的理论研究和产品商用发展，包括语音识别、自然语言处理、声纹识别、深度学习和计算机视觉。同时，实验室亦为消费者研发人工智能产品，包括其研发的首款智能语音助手音箱 “天猫精灵（Tmall Genie）”。 具有代表性的产品详情 小米AI音响小米AI音箱是小米公司于2017年7月26日发布的一款智能音箱，是由小米电视、小米大脑、小米探索实验室联合开发。小米把“小爱同学”作为AI音箱的唤醒词。 基本参数： 扬声器：2英寸全频 频率响应范围：80Hz-18000Hz (-6dB) 扬声器灵敏度：82dB/m/W 额定阻抗：4欧姆 麦克风：6个 CPU：64位 Cortex A53 四核 1.2GHz 双频WiFi 蓝牙 4.1 支持A2DP音乐播放 额定输出电功率：&gt;5W 电源规格：DC 12V 1.75A 硬件配置 小米AI音箱搭载64位四核芯片, 具备6个环形麦克风阵列支持360度收音；波束成形技术，可以有效屏蔽干扰，实现远距离声控。 主要功能： 内容收听 小米AI音箱可以播放音乐、电台点播，还有相声、小说、脱口秀，教育学习、儿童类多种有声读物内容 技术中心 小米AI音箱是支持语音交互，内容包括在线音乐、网络电台、有声读物、广播电台等，提供新闻、天气、闹钟、倒计时、备忘、提醒、时间、汇率、股票、限行、算数、查找手机、百科/问答、闲聊、笑话、菜谱、翻译等各类功能。APP”小米AI”内进行查询。 智能家居 小米AI（人工智能）音箱可控制小米电视、扫地机器人、空气净化器等小米及生态链设备，也可通过小米插座、插线板来控制第三方产品。 小米AI（人工智能）音箱采用波束成型技术，能够有效屏蔽干扰，实现远距离声控，使得你在房间任意方位，都可以通过语音唤醒音箱。所以在接收语音方面肯定更准确。同时在小米AI音箱灵巧的身形下面，是出色的音质。精准的声波导技术，让锥形扬声器实现360度全空间宽频覆盖；0.4L低音声腔内容积、60Hz－18KHz的宽声域，让声音还原本色，震撼动听。 小米AI音箱还推出“水滴计划”，向第三方开放人工智能语音能力和SDK，号称未来还将迎来成千上万种能力。值得一提的是，小米希望与发烧友合作培训AI设备，通过技能中心AI App训练智能音箱的智能度。 小米音响mini版，由6麦变为4麦，从理论上来说，麦克风的数量越多，越有利于远场识别。但陈孝良给出的一个看法是，AI 算法在音箱中的应用削弱了麦克风的「统治权」。 也就是说，在与唤醒以及识别等功能产生联动后，不断更迭的算法与阵型可以弥补麦克风的一部分不足之处。 小米音响的语音识别技术（ASR）的接口，用的是思必驰、Nuance 与搜狗的；自然语言理解（NLP）等关于语义方面的技术，由小米大脑亲自来做前端的麦克风阵列以及降噪方案，是由声智科技提供的；语音合成技术，是由猎户星空提供的。 小米AI音响的拆解及简要系统分析https://blog.csdn.net/leekwen/article/details/82378639 小米大脑小米公司由雷军创办，共计七名创始人，分别为创始人、董事长兼CEO雷军，联合创始人总裁林斌，联合创始及副总裁黎万强、周光平、黄江吉、刘德、洪锋。 在小米的技术开放平台上的小米AI有深度学习，计算机视觉，声学，语音，自然语言处理，知识图谱，智能问答，小爱同学。其中自然语言处理：自然预压处理基础，文本审核，情感分析，机器翻译，智能聊天。 从2016年9月小米电视推出全球首个人工智能电视系统——“PatchWall拼图墙”开始，小米电视与“小米大脑”（Mi Brain）团队已经在视频内容理解、用户喜好推荐、语音指令积累等方面有了不错的进展；小米4A的销量也尚算过关。 王川介绍说，目前小米大脑在图片识别、语音识别、语义理解、意图分析等人工智能领域取得了显著成效，比如，目前小米电视系统可以从海量的影视数据中提取特征，为不同的用户做精准匹配。 微软小冰 微软小冰是微软人工智能三条全球产品线之一。它的产品形态涉及对话式人工智能机器人、智能语音助手、人工智能创造内容提供者和一系列垂直领域解决方案。这是微软小冰的3D模型。 技术原理编辑 第五代微软小冰已全面在线上产品中使用生成模型（Generative Model）。其中，中国、日本、美国和印度小冰部分使用，印尼小冰则完全使用生成模型。第五代微软小冰是全球开放领域人工智能对话中，第一个百分之百使用生成模型的落地产品。 在使用生成模型之前的第四代小冰，虽然拥有十亿级的大数据语料库，小冰通过分析理解用户的问题，寻找语料库中最合适的话作为她的回答。使用生成模型之后，小冰不再鹦鹉学舌，而是能够自创回应。 微软将人工智能交互技术产品的演进分为三个阶段。第一阶段是基本的人工智能交互，即拥有某一种或多种交互方式，如文本、语音、图像、视频等，但不同交互方式之间是割裂的。第二阶段是初级感官，即在人工智能系统中，用一种核心引擎（如小冰的EQ核心对话引擎）将上述各种交互统一起来，使不同感官可以混合运用。微软小冰从2015年第三代发布起，进入这一阶段。微软发布第五代微软小冰，进入第三阶段（高级感官）。 微软小冰高级感官由多种初级感官有机融合形成的，因而交互能力强，对综合技术储备和数据要求大幅度提高。 第六代小冰上线全新的共感模型，同时开始公测一种融合了文本、全双工语音与实时视觉的新感官。其中：共感模型是一种基于生成模型的对话引擎。能够进一步提高小冰对于对话内容、领域和节奏的控制力，也即小冰可以通过自创回应，来牵引对话向她所希望的方向进行。 在2017年八月份举行的第五代小冰发布会上，微软宣布已完成全双工语音（Full Duplex Voice）交互感官的产品化，并在打电话和智能音箱设备两个场景中落地。微软在第六代小冰发布会上宣布开始公开测试的这个新感官，是融合了共感模型的对话引擎、全双工语音和实时视觉三个类别的全新感官。 在测试设备中，小冰可以通过视觉、语音的实时连续交互，指挥用户完成面容检测，并可在上述过程中进行开放域的对话。微软预计该感官将于一年内完成全部产品化工作。 全双工语音交互感官 全双工语音交互感官（Full Duplex Voice Sense）与既有的单轮或多轮连续语音识别不同，这项技术可实时预测人类即将说出的内容，实时生成回应并控制对话节奏，从而使长程语音交互成为可能。采用该技术的智能硬件设备，将不再需要用户在每轮交互时都说出唤醒词，仅需一次唤醒，就可以轻松实现连续对话。 自2016年8月起，微软（亚洲）互联网工程院通过人类用户主动发起的方式，已让微软小冰与人类用户累计完成了超过60万通电话。 共感模型 共感模型是一种基于生成模型的对话引擎。在生成模型的基础上，共感模型能够进一步提高小冰对于对话内容、领域和节奏的控制力。 全新交互感官 微软宣布开始公开测试一种融合了共感模型的对话引擎、全双工语音和实时视觉三个类别的全新感官。微软在第六代小冰发布会现场放置了用于体验的测试设备。在测试设备中，微软小冰可以通过视觉、语音的实时连续交互，指挥用户完成面容检测，并可在上述过程中进行开放域的对话。 第四版人工智能歌曲DNN模型 第四版人工智能歌曲DNN模型能够进一步快速合成与人类歌手质量相当的歌曲，并能够使微软小冰自由吸收多数人类歌手的演唱技巧，融会贯通，在演唱过程中达成更加成熟的演绎。此外，该技术还能够完整吸收并复制特定人类歌手的全部演唱特质（嗓音、韵律等），使小冰能完全代替原人类歌手完成新作品的创作。 六代小冰 垂直领域 在金融领域的微软小冰金融文本生成技术，与万得资讯及华尔街见闻合作，已覆盖国内约90%金融机构、75%经批准的合格境外投资机构和约40%的国内个人投资者。 在大众文化领域，微软小冰的儿童有声读物自动生成技术成果，已获得超过400万小时的收听量，微软小冰姐姐讲故事有声读物覆盖国内90%以上的儿童早教机器人以及80%在线收听平台。 在电视电台领域，微软小冰通过人工智能技术参与生产与主持的电视电台节目，已达21档电视节目和28档广播电台节目。仅每天早上6点至9点，微软小冰就需参与多达7档节目。 微软小冰还与微软Bing搜索引擎技术相结合，推出了针对媒体与出版两个垂直行业的辅助型解决方案，并已在超过15个媒体平台落地。由小冰提供人工智能技术支持的媒体及自媒体公众号已超过60000个。在第六代小冰发布会上，微软宣布了可支持人工智能以多种观点和角度，同时撰写多篇新闻文章的“白盒写作辅助工具”等新产品，并首次公布了面向出版垂直领域的有声内容、IP塑造等解决方案。 百度大脑 在百度AI的开放平台上有语音技术，图像技术等，其中的自然语言处理包括语言处理基础技术、文本审核、机器翻译。 语言处理基础技术有词法分析,词向量表示,词义相似度,依存句法分析,DNN语言模型,短文本相似度 ,文本纠错,情感倾向分析,评论观点抽取,对话情绪识别,文章分类,文章标签。 机器翻译有通用翻译API，定制化翻译API，语音翻译SDK，拍照翻译SDK。 点击相应的功能会有相关介绍和体验，有点意思。https://ai.baidu.com/ 2016年9月1日，百度世界大会在北京中国大饭店举行。会上，百度首次向外界全面展示百度人工智能成果——“百度大脑”，并宣布对广大开发者、创业者及传统企业开放其核心能力和底层技术。开放的百度大脑，将引领整个互联网行业进入下一幕。 作为最早布局人工智能的技术公司之一，百度大脑已建成超大规模的神经网络，拥有万亿级的参数、千亿样本、千亿特征训练，能模拟人脑的工作机制。相比三年前2-3岁孩子的智力水平，百度大脑如今智商已经有了超前的发展，在一些能力上甚至超越了人类。 2018年7月4日，在Baidu Creat 2018百度AI开发者大会上，百度大脑3.0发布。百度大脑1.0完成了基础能力的搭建和新技术的初步开放，对外开放20多种能力，2017年的百度大脑2.0已形成完整体系，开放60多种能力。百度大脑3.0已开放110多项能力，AI技术能力也在不断提升。百度大脑3.0最大的优势，就是多模态深度语义理解技术。百度大脑每天的调用次数已超过4000亿次。 百度的深度学习研究工作启动于2012年，2013年百度深度学习研究院IDL（Institute of Deep Learning）在李彦宏的指示下正式成立，前Facebook资深科学家徐伟、美国新泽西州立大学统计系教授张潼，异构计算专家、前AMD异构系统首席软件架构师吴韧、“千人计划”国家特聘专家余凯等一大批世界知名专家纷纷加入，除了在国内有专门实验室外，在美国硅谷，离苹果公司不远的地方，百度深度学习实验室也已经在运转。 应用功能 深度学习的研究让百度搜索更加“智能”了。如百度的语音识别，准确度已经近乎和人际交流相同；在图像识别方面，百度也已经是全世界最为领先的公司之一。 百度大脑的四大功能，分别是语音、图像，自然语言处理和用户画像这四大能力。 语音的能力：包括语音识别能力和语音合成能力。 图像的能力：图像能力指的是看到一个图片，不仅能看得见，还能看得懂。按照技术界的说法，它应该是计算机视觉。 自然语言处理能力：自然语言处理能力比语音和图像更难。语音和图像技术更多还处在认知的阶段，而自然语言理解除了要有认知能力之外，还需要逻辑推理能力、规划能力等等，同时也需要依赖于更为强大的知识图谱。 用户画像：用户画像在传统的AI中并不是主流。但是今天，我们每时每刻都可以收集很多很多和用户行为相关的数据，就可以对用户做很好的画像，而这里面使用的技术又基本上都是与人工智能相关的。 百度大脑3.0百度大脑3.0最大的优势，就是多模态深度语义理解技术。 多模态深度语义理解”是指对文字、声音、图片、视频等多模态的数据和信息进行深层次多维度的语义理解，包括数据语义、知识语义、视觉语义、语音语义一体化和自然语言语义等多方面的语义理解技术。 百度大脑3.0已经对外开放了110多项领先的AI能力。 百度大脑的深度学习训练，已经阅读了一千亿文章，相当于六万个国家图书馆的容量。同时百度深度学习平台paddlepaddle也迎来的3.0版本。 “百度大脑3.0首次将芯片纳入技术体系，它使百度大脑具备了更完备的软硬一体化能力，带动百度大脑算力爆发式增长。AI芯片还将与百度自主研发的PaddlePaddle深度学习框架深度结合，推动AI行业生态快速发展“，王海峰讲到。 百度大脑 我们的解决方案——以百度大脑为纲领 标题 说明 附加 理解与交互技术UNIT UNIT搭载业界领先的需求理解、对话控制及底层的机器学习、自然语言处理、知识挖掘等核心技术，让您的产品快速拥有对话交互能力 UNIT2.0 文档 AI开放平台文档中心 重点关注：自然语言 + 知识图谱]]></content>
      <categories>
        <category>项目</category>
        <category>智能家居</category>
      </categories>
      <tags>
        <tag>项目</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[LearningRate模型的学习率]]></title>
    <url>%2F2018%2F11%2F06%2FLearningRate%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%AD%A6%E4%B9%A0%E7%8E%87%2F</url>
    <content type="text"><![CDATA[LearningRate 在使用不同优化器（例如随机梯度下降，Adam）神经网络相关训练中，学习速率作为一个超参数控制了权重更新的幅度，以及训练的速度和精度。学习速率太大容易导致目标（代价）函数波动较大从而难以找到最优，而弱学习速率设置太小，则会导致收敛过慢耗时太长 LearningRate 详细解读]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>LearningRate</tag>
        <tag>学习率</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Attention is All You Need]]></title>
    <url>%2F2018%2F11%2F06%2FAttention_is_All_You_Need%2F</url>
    <content type="text"><![CDATA[Attention is All You Need 是谷歌发表的文章，针对nlp里的机器翻译问题，提出了一种被称为”Transformer”的网络结构，基于注意力机制。文章提出，以往nlp里大量使用RNN结构和encoder-decoder结构，RNN及其衍生网络的缺点就是慢，问题在于前后隐藏状态的依赖性，无法实现并行，而文章提出的”Transformer”完全摒弃了递归结构，依赖注意力机制，挖掘输入和输出之间的关系，这样做最大的好处是能够并行计算了。 Transformer完整实现：https://github.com/yuanxiaosc/Transformer_implementation_and_application 论文精要自注意力机制机制$Attention(Q, K, V)=softmax(\dfrac{QK^T}{\sqrt{d_k}})V$ 123Q: [batch_size, num_heads, Q_sequence_length, Q_depth]K: [batch_size, num_heads, K_sequence_length, K_depth]V: [batch_size, num_heads, V_sequence_length, V_depth] 需要满足两点： Q_depth = K_depth; K_sequence_length = V_sequence_length 第一点保证可以通过$QK^T$计算当前查询Q对应的K键，第二点保证K和V一一对应（选择一个K那么就能找到k对应的v）。 $MultiHead(Q, K, V)=Concat(head_1,…,head_h)W^o $$where head_i=Attention(QW^Q_i, KW^K_i, VW^V_i)$ The attention function used by the transformer takes three inputs: Q (query), K (key), V (value). The equation used to calculate the attention weights is: \Large{Attention(Q, K, V) = softmax_k(\frac{QK^T}{\sqrt{d_k}}) V}The dot-product attention is scaled by a factor of square root of the depth. This is done because for large values of depth, the dot product grows large in magnitude pushing the softmax function where it has small gradients resulting in a very hard softmax. For example, consider that Q and K have a mean of 0 and variance of 1. Their matrix multiplication will have a mean of 0 and variance of dk. Hence, square root of dk is used for scaling (and not any other number) because the matmul of Q and K should have a mean of 0 and variance of 1, so that we get a gentler softmax. The mask is multiplied with -1e9 (close to negative infinity). This is done because the mask is summed with the scaled matrix multiplication of Q and K and is applied immediately before a softmax. The goal is to zero out these cells, and large negative inputs to softmax are near zero in the output. 1234567891011121314151617181920212223242526272829303132333435def scaled_dot_product_attention(q, k, v, mask): &quot;&quot;&quot;Calculate the attention weights. q, k, v must have matching leading dimensions. k, v must have matching penultimate dimension, i.e.: seq_len_k = seq_len_v. The mask has different shapes depending on its type(padding or look ahead) but it must be broadcastable for addition. Args: q: query shape == (..., seq_len_q, depth) k: key shape == (..., seq_len_k, depth) v: value shape == (..., seq_len_v, depth_v) mask: Float tensor with shape broadcastable to (..., seq_len_q, seq_len_k). Defaults to None. Returns: output, attention_weights &quot;&quot;&quot; matmul_qk = tf.matmul(q, k, transpose_b=True) # (..., seq_len_q, seq_len_k) # scale matmul_qk dk = tf.cast(tf.shape(k)[-1], tf.float32) scaled_attention_logits = matmul_qk / tf.math.sqrt(dk) # add the mask to the scaled tensor. if mask is not None: scaled_attention_logits += (mask * -1e9) # softmax is normalized on the last axis (seq_len_k) so that the scores # add up to 1. attention_weights = tf.nn.softmax(scaled_attention_logits, axis=-1) # (..., seq_len_q, seq_len_k) output = tf.matmul(attention_weights, v) # (..., seq_len_v, depth_v) return output, attention_weights As the softmax normalization is done on K, its values decide the amount of importance given to Q. The output represents the multiplication of the attention weights and the V (value) vector. This ensures that the words we want to focus on are kept as is and the irrelevant words are flushed out. 多头自注意力机制 深入解析 Attention is All You Need 中自注意力机制 标题 说明 时间 The Illustrated Transformer 对论文解析的最好的一篇博文，制作精美，它的中文版本BERT大火却不懂Transformer？读这一篇就够了 20190228 标题 说明 时间 Attention Is All You Need 原始论文 20170612 The Annotated Transformer harvard NLP 解读原文 20180403 Transformer Translation Model TensorFlow 官方模型复现 长期更新 Transformer Translation Model TensorFlow NVIDIA模型复现 长期更新 attention-is-all-you-need-keras Keras 论文复现 201807 Attention Is All You Need code we used to train and evaluate our models is available at https://github.com/tensorflow/tensor2tensor 原始论文模型评估 基于注意力机制，机器之心带你理解与训练神经机器翻译系统 复现论文+ 解析 20180512 大规模集成Transformer模型，阿里达摩院如何打造WMT 2018机器翻译获胜系统 论文实际应用 201806 attention_keras.py 论文注意力机制（部分）复现 20180528 “变形金刚”为何强大：从模型到代码全面解析Google Tensor2Tensor系统 Google Tensor2Tensor系统是一套十分强大的深度学习系统，在多个任务上的表现非常抢眼。尤其在机器翻译问题上，单模型的表现就可以超过之前方法的集成模型。这一套系统的模型结构、训练和优化技巧等，可以被利用到公司的产品线上，直接转化成生产力。本文对Tensor2Tensor系统从模型到代码进行了全面的解析，期望能够给大家提供有用的信息。 20181106 碎碎念：Transformer的细枝末节 20190902 从语言模型到Seq2Seq：Transformer如戏，全靠Mask 张俊林 解读 20190918 序列到序列任务与Transformer模型序列到序列任务与Encoder-Decoder框架序列到序列（Sequence-to-Sequence）是自然语言处理中的一个常见任务，主要用来做泛文本生成的任务，像机器翻译、文本摘要、歌词/故事生成、对话机器人等。最具有代表性的一个任务就是机器翻译（Machine Translation），将一种语言的序列映射到另一个语言的序列。例如，在汉-英机器翻译任务中，模型要将一个汉语句子（词序列）转化成一个英语句子（词序列）。 目前Encoder-Decoder框架是解决序列到序列问题的一个主流模型。模型使用Encoder对source sequence进行压缩表示，使用Decoder基于源端的压缩表示生成target sequence。该结构的好处是可以实现两个sequence之间end-to-end方式的建模，模型中所有的参数变量统一到一个目标函数下进行训练，模型表现较好。图1展示了Encoder-Decoder模型的结构，从底向上是一个机器翻译的过程。Encoder和Decoder可以选用不同结构的Neural Network，比如RNN、CNN。RNN的工作方式是对序列根据时间步，依次进行压缩表示。使用RNN的时候，一般会使用双向的RNN结构。具体方式是使用一个RNN对序列中的元素进行从左往右的压缩表示，另一个RNN对序列进行从右向左的压缩表示。两种表示被联合起来使用，作为最终序列的分布式表示。使用CNN结构的时候，一般使用多层的结构，来实现序列局部表示到全局表示的过程。使用RNN建模句子可以看做是一种时间序列的观点，使用CNN建模句子可以看做一种结构化的观点。使用RNN结构的序列到序列模型主要包括RNNSearch、GNMT等，使用CNN结构的序列到序列模型主要有ConvS2S等。 神经网络模型与语言距离依赖现象Transformer是一种建模序列的新方法，序列到序列的模型依然是沿用了上述经典的Encoder-Decoder结构，不同的是不再使用RNN或是CNN作为序列建模机制了，而是使用了self-attention机制。这种机制理论上的优势就是更容易捕获“长距离依赖信息（long distance dependency）”。所谓的“长距离依赖信息”可以这么来理解：1）一个词其实是一个可以表达多样性语义信息的符号（歧义问题）。2）一个词的语义确定，要依赖其所在的上下文环境。（根据上下文消岐）3）有的词可能需要一个范围较小的上下文环境就能确定其语义（短距离依赖现象），有的词可能需要一个范围较大的上下文环境才能确定其语义（长距离依赖现象）。 举个例子，看下面两句话：“山上有很多杜鹃，春天到了的时候，会漫山遍野的开放，非常美丽。” “山上有很多杜鹃，春天到了的时候，会漫山遍野的啼鸣，非常婉转。”在这两句话中，“杜鹃”分别指花（azalea）和鸟（cuckoo）。在机器翻译问题中，如果不看距其比较远的距离的词，很难将“杜鹃”这个词翻译正确。该例子是比较明显的一个例子，可以明显的看到词之间的远距离依赖关系。当然，绝大多数的词义在一个较小范围的上下文语义环境中就可以确定，像上述的例子在语言中占的比例会相对较小。我们期望的是模型既能够很好的学习到短距离的依赖知识，也能够学习到长距离依赖的知识。 那么，为什么Transformer中的self-attention理论上能够更好的捕获这种长短距离的依赖知识呢？我们直观的来看一下，基于RNN、CNN、self-attention的三种序列建模方法，任意两个词之间的交互距离上的区别。图2是一个使用双向RNN来对序列进行建模的方法。由于是对序列中的元素按顺序处理的，两个词之间的交互距离可以认为是他们之间的相对距离。W1和Wn之间的交互距离是n-1。带有门控（Gate）机制的RNN模型理论上可以对历史信息进行有选择的存储和遗忘，具有比纯RNN结构更好的表现，但是门控参数量一定的情况下，这种能力是一定的。随着句子的增长，相对距离的增大，存在明显的理论上限。图3展示了使用多层CNN对序列进行建模的方法。第一层的CNN单元覆盖的语义环境范围较小，第二层覆盖的语义环境范围会变大，依次类推，越深层的CNN单元，覆盖的语义环境会越大。一个词首先会在底层CNN单元上与其近距离的词产生交互，然后在稍高层次的CNN单元上与其更远一些词产生交互。所以，多层的CNN结构体现的是一种从局部到全局的特征抽取过程。词之间的交互距离，与他们的相对距离成正比。距离较远的词只能在较高的CNN节点上相遇，才产生交互。这个过程可能会存在较多的信息丢失。图4展示的是基于self-attention机制的序列建模方法。注意，为了使图展示的更清晰，少画了一些连接线，图中“sentence”层中的每个词和第一层self-attention layer中的节点都是全连接的关系，第一层self-attention layer和第二层self-attention layer之间的节点也都是全连接的关系。我们可以看到在这种建模方法中，任意两个词之间的交互距离都是1，与词之间的相对距离不存在关系。这种方式下，每个词的语义的确定，都考虑了与整个句子中所有的词的关系。多层的self-attention机制，使得这种全局交互变的更加复杂，能够捕获到更多的信息。综上，self-attention机制在建模序列问题时，能够捕获长距离依赖知识，具有更好的理论基础。 Attention Is All You NeedAshish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Lukasz Kaiser, Illia Polosukhin(Submitted on 12 Jun 2017 (v1), last revised 6 Dec 2017 (this version, v5)) The dominant sequence transduction models are based on complex recurrent or convolutional neural networks in an encoder-decoder configuration. The best performing models also connect the encoder and decoder through an attention mechanism. We propose a new simple network architecture, the Transformer, based solely on attention mechanisms, dispensing with recurrence and convolutions entirely. Experiments on two machine translation tasks show these models to be superior in quality while being more parallelizable and requiring significantly less time to train. Our model achieves 28.4 BLEU on the WMT 2014 English-to-German translation task, improving over the existing best results, including ensembles by over 2 BLEU. On the WMT 2014 English-to-French translation task, our model establishes a new single-model state-of-the-art BLEU score of 41.8 after training for 3.5 days on eight GPUs, a small fraction of the training costs of the best models from the literature. We show that the Transformer generalizes well to other tasks by applying it successfully to English constituency parsing both with large and limited training data. Comments: 15 pages, 5 figuresSubjects: Computation and Language (cs.CL); Machine Learning (cs.LG)Cite as: arXiv:1706.03762 [cs.CL] (or arXiv:1706.03762v5 [cs.CL] for this version) 论文模型图片 论文结果可视化 seq2seq_example编码器 - 解码器架构 - ：编码器将源句子转换为“含义”向量，该向量通过解码器以产生翻译。 NMT-KerasAttentional recurrent neural network NMT model Transformer NMT model]]></content>
      <categories>
        <category>论文</category>
        <category>神经机器翻译</category>
      </categories>
      <tags>
        <tag>Attention</tag>
        <tag>Transformer</tag>
        <tag>Sequence-to-Sequence</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Semi-supervised sequence tagging with bidirectional language models]]></title>
    <url>%2F2018%2F10%2F30%2FSemi_Supervised_sequence_tagging_with_bidirectional_language_models%2F</url>
    <content type="text"><![CDATA[本文 是 NAACL 2018 最佳论文 Deep contextualized word representations 的前作，详细介绍了一种用预训练的双向语言模型提高其它模型（序列标注）效果的半监督方法。 Semi-supervised sequence tagging with bidirectional language modelsMatthew E. Peters, Waleed Ammar, Chandra Bhagavatula, Russell Power(Submitted on 29 Apr 2017) Pre-trained word embeddings learned from unlabeled text have become a standard component of neural network architectures for NLP tasks. However, in most cases, the recurrent network that operates on word-level representations to produce context sensitive representations is trained on relatively little labeled data. In this paper, we demonstrate a general semi-supervised approach for adding pre- trained context embeddings from bidirectional language models to NLP systems and apply it to sequence labeling tasks. We evaluate our model on two standard datasets for named entity recognition (NER) and chunking, and in both cases achieve state of the art results, surpassing previous systems that use other forms of transfer or joint learning with additional labeled data and task specific gazetteers. Comments: To appear in ACL 2017Subjects: Computation and Language (cs.CL)Cite as: arXiv:1705.00108 [cs.CL] (or arXiv:1705.00108v1 [cs.CL] for this version) 标题 说明 附加 Semi-supervised sequence tagging with bidirectional language models 原文 20170429 知乎 Semi-supervised sequence tagging with bidirectional language models 吴明昊 解读 《Semi-supervised sequence tagging with bidirectional language models》阅读笔记 Shen 20170605]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Language Modeling</tag>
        <tag>word representations</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Character-Aware Neural Language Models]]></title>
    <url>%2F2018%2F10%2F29%2FCharacter_Aware_Neural_Language_Models%2F</url>
    <content type="text"><![CDATA[本文 是 NAACL 2018 最佳论文 Deep contextualized word representations 的 ELMo 模型字符卷积的基础。 注意点： 卷积核的高度一般与单词矩阵的高度一致（字符向量维度）； 不同的卷积核宽度代表着不同的 N-gram 语法； 上图一共有 12 个卷积核，宽度一样的卷积核放在一起了（黄色、蓝色和红色）； Character-Aware Neural Language ModelsYoon Kim, Yacine Jernite, David Sontag, Alexander M. Rush(Submitted on 26 Aug 2015 (v1), last revised 1 Dec 2015 (this version, v4)) We describe a simple neural language model that relies only on character-level inputs. Predictions are still made at the word-level. Our model employs a convolutional neural network (CNN) and a highway network over characters, whose output is given to a long short-term memory (LSTM) recurrent neural network language model (RNN-LM). On the English Penn Treebank the model is on par with the existing state-of-the-art despite having 60% fewer parameters. On languages with rich morphology (Arabic, Czech, French, German, Spanish, Russian), the model outperforms word-level/morpheme-level LSTM baselines, again with fewer parameters. The results suggest that on many languages, character inputs are sufficient for language modeling. Analysis of word representations obtained from the character composition part of the model reveals that the model is able to encode, from characters only, both semantic and orthographic information. Comments: AAAI 2016Subjects: Computation and Language (cs.CL); Neural and Evolutionary Computing (cs.NE); Machine Learning (stat.ML)Cite as: arXiv:1508.06615 [cs.CL] (or arXiv:1508.06615v4 [cs.CL] for this version) 标题 说明 附加 自然语言处理中CNN模型几种常见的Max Pooling操作 张俊林 20160407]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Character Embedding</tag>
        <tag>Language Modeling</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[ELMo Deep contextualized word representations翻译]]></title>
    <url>%2F2018%2F10%2F29%2FELMo_Deep_contextualized_word_representations%E7%BF%BB%E8%AF%91%2F</url>
    <content type="text"><![CDATA[评估]]></content>
      <categories>
        <category>论文</category>
        <category>论文写作</category>
      </categories>
      <tags>
        <tag>Language Modeling</tag>
        <tag>ELMO</tag>
        <tag>word representations</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[ELMo Deep contextualized word representations]]></title>
    <url>%2F2018%2F10%2F29%2FELMo_Deep_contextualized_word_representations%2F</url>
    <content type="text"><![CDATA[NAACL 2018最佳论文 Deep contextualized word representations：艾伦人工智能研究所提出新型深度语境化词表征（研究者使用从双向 LSTM 中得到的向量，该 LSTM 是使用成对语言模型（LM）目标在大型文本语料库上训练得到的。因此，该表征叫作 ELMo（Embeddings from Language Models）表征。）。 ELMo 核心思想 最推荐 ELMo TensorFlow Hub 的使用方法OverviewComputes contextualized word representations using character-based word representations and bidirectional LSTMs, as described in the paper “Deep contextualized word representations” [1]. This modules supports inputs both in the form of raw text strings or tokenized text strings. The module outputs fixed embeddings at each LSTM layer, a learnable aggregation of the 3 layers, and a fixed mean-pooled vector representation of the input. The complex architecture achieves state of the art results on several benchmarks. Note that this is a very computationally expensive module compared to word embedding modules that only perform embedding lookups. The use of an accelerator is recommended. Trainable parametersThe module exposes 4 trainable scalar weights for layer aggregation. Example use12345elmo = hub.Module("https://tfhub.dev/google/elmo/2", trainable=True)embeddings = elmo(["the cat is on the mat", "dogs are in the fog"],signature="default",as_dict=True)["elmo"] 1234567891011elmo = hub.Module("https://tfhub.dev/google/elmo/2", trainable=True)tokens_input = [["the", "cat", "is", "on", "the", "mat"],["dogs", "are", "in", "the", "fog", ""]]tokens_length = [6, 5]embeddings = elmo(inputs=&#123;"tokens": tokens_input,"sequence_len": tokens_length&#125;,signature="tokens",as_dict=True)["elmo"] InputThe module defines two signatures: default, and tokens. With the default signature, the module takes untokenized sentences as input. The input tensor is a string tensor with shape [batch_size]. The module tokenizes each string by splitting on spaces. With the tokens signature, the module takes tokenized sentences as input. The input tensor is a string tensor with shape [batch_size, max_length] and an int32 tensor with shape [batch_size] corresponding to the sentence length. The length input is necessary to exclude padding in the case of sentences with varying length. OutputThe output dictionary contains: word_emb: the character-based word representations with shape [batch_size, max_length, 512]. lstm_outputs1: the first LSTM hidden state with shape [batch_size, max_length, 1024]. lstm_outputs2: the second LSTM hidden state with shape [batch_size, max_length, 1024]. elmo: the weighted sum of the 3 layers, where the weights are trainable. This tensor has shape [batch_size, max_length, 1024] default: a fixed mean-pooling of all contextualized word representations with shape [batch_size, 1024]. 用代码来解释 更多内容见我的 GitHub 1234567891011121314151617181920212223242526272829import tensorflow as tfimport tensorflow_hub as hub# elmo_url="https://tfhub.dev/google/elmo/2"# hub.Module(elmo_url, trainable=True)# You can either use the URL directly or download the file locally and then use it.# hub.Module(path_to_elmo_model, trainable=True)tokens_input = [["the", "cat", "is", "on", "the", "mat"], ["dogs", "are", "in", "the", "fog", ""]]tokens_length = [6, 5]max_length = max(tokens_length)def tokens_elmo(path_to_hub_elmo_model="https://tfhub.dev/google/elmo/2"): elmo_tokens_input = tf.placeholder(dtype=tf.string, shape=[None, max_length], name="tokens_input") elmo_sequence_length_input = tf.placeholder(dtype=tf.int32, shape=[None,], name="tokens_length") module = hub.Module(path_to_hub_elmo_model, trainable=True) module_features = module(inputs=&#123;"tokens":elmo_tokens_input, "sequence_len":elmo_sequence_length_input&#125;, signature='tokens', as_dict=True) elmo_embedding = module_features["elmo"] #[batch_size, max_length, 1024], the weighted sum of the 3 layers, where the weights are trainable. return elmo_tokens_input, elmo_sequence_length_input, elmo_embeddingelmo_tokens_input, elmo_sequence_length_input, elmo_embedding = tokens_elmo(path_to_hub_elmo_model="/home/b418/jupyter_workspace/B418_common/袁宵/tfhub_modules/elmo")with tf.Session() as sess: sess.run([tf.global_variables_initializer(), tf.tables_initializer()]) out_elmo_embedding = sess.run(elmo_embedding,feed_dict=&#123;elmo_tokens_input:tokens_input, elmo_sequence_length_input:tokens_length&#125;) print("out_elmo_shape:\t", out_elmo_embedding.shape) 广义 ELMo 使用方法如何使用ELMo的词向量呢？( 论文 3.3 有详细描述)在supervised learning的情况下，可以各种自如的使用: 直接将ELMo词向量 ELMo_k 与普通的词向量 x_k拼接（concat）[ x_k;ELMo_k ]。 直接将ELMo词向量ELMo_k 与隐层输出向量 h_k 拼接[ h_k;ELMo_k ]，在SNLI,SQuAD上都有提升。 代码使用实例： 官方版 知乎简版 标题 说明 附加 Deep contextualized word representations 该研究提出了一种新型深度语境化词表征，可对词使用的复杂特征（如句法和语义）和词使用在语言语境中的变化进行建模（即对多义词进行建模）。这些表征可以轻松添加至已有模型，并在 6 个 NLP 问题中显著提高当前最优性能。 20180215 TensorFlow Hub 实现 Embeddings from a language model trained on the 1 Billion Word Benchmark. allennlp.org - elmo 论文官网 elmo bilm-tf 论文官方实现 Tensorflow implementation of contextualized word representations from bi-directional language models NAACL 2018最佳论文：艾伦人工智能研究所提出新型深度语境化词表征 机器之心解读 20180607 把 ELMo 作为 keras 的一个嵌入层使用 GitHub 201804 NAACL18 Best Paper: ELMo Liyuan Liu 解读 论文笔记ELMo 赵来福 详细解读 ELMo 最好用的词向量《Deep Contextualized Word Representations》 mountain blue 详细解读 visualizing-elmo-contextual-vectors 可视化ELMo上下文向量 20190417 Deep contextualized word representationsMatthew E. Peters, Mark Neumann, Mohit Iyyer, Matt Gardner, Christopher Clark, Kenton Lee, Luke Zettlemoyer Our word vectors are learned functions of the internal states of a deep bidirectional language model (biLM), which is pre-trained on a large text corpus. We show that these representations can be easily added to existing models and significantly improve the state of the art across six challenging NLP problems, including question answering, textual entailment and sentiment analysis. We also present an analysis showing that exposing the deep internals of the pre-trained network is crucial, allowing downstream models to mix different types of semi-supervision signals. 在本论文中，我们介绍了一种新型深度语境化词表征，可对词使用的复杂特征（如句法和语义）和词使用在语言语境中的变化进行建模（即对多义词进行建模）。我们的词向量是深度双向语言模型（biLM）内部状态的函数，在一个大型文本语料库中预训练而成。本研究表明，这些表征能够被轻易地添加到现有的模型中，并在六个颇具挑战性的 NLP 问题（包括问答、文本蕴涵和情感分析）中显著提高当前最优性能。此外，我们的分析还表明，揭示预训练网络的深层内部状态至关重要，可以允许下游模型综合不同类型的半监督信号。 Comments: NAACL 2018. Originally posted to openreview 27 Oct 2017. v2 updated for NAACL camera readySubjects: Computation and Language (cs.CL)Cite as: arXiv:1802.05365 [cs.CL] (or arXiv:1802.05365v2 [cs.CL] for this version)]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Language Modeling</tag>
        <tag>ELMO</tag>
        <tag>word representations</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Keras手册]]></title>
    <url>%2F2018%2F10%2F24%2FKeras%E6%89%8B%E5%86%8C%2F</url>
    <content type="text"><![CDATA[名称 网址 Keras GitHub https://github.com/keras-team/keras Keras 英文官网 https://keras.io/ Keras 中文官网 https://keras.io/zh/ Keras 中文 https://keras-cn.readthedocs.io/en/latest/ Keras Example 实验Vision models examplesmnist_mlp.py Trains a simple deep multi-layer perceptron on the MNIST dataset. 网络结构 实验结果Gets to 98.43% test accuracy after 20 epochs mnist_cnn.py Trains a simple convnet on the MNIST dataset. 网络结构 实验结果Gets to 99.19% test accuracy after 12 epochs cifar10_cnn.py Trains a simple deep CNN on the CIFAR10 small images dataset. It gets to 75% validation accuracy in 25 epochs, and 79% after 50 epochs.(it’s still underfitting at that point, though). 网络结构 实验结果 cifar10_cnn_capsule.py Trains a simple CNN-Capsule Network on the CIFAR10 small images dataset. Capsule Implement is from https://github.com/bojone/Capsule/Capsule Paper: https://arxiv.org/abs/1710.09829 “””Train a simple CNN-Capsule Network on the CIFAR10 small images dataset. Without Data Augmentation:It gets to 75% validation accuracy in 10 epochs,and 79% after 15 epochs, and overfitting after 20 epochs With Data Augmentation:It gets to 75% validation accuracy in 10 epochs,and 79% after 15 epochs, and 83% after 30 epochs.In my test, highest validation accuracy is 83.79% after 50 epochs. This is a fast Implement, just 20s/epoch with a gtx 1070 gpu.“”” 网络结构 实验结果 cifar10_resnet.py Trains a ResNet on the CIFAR10 small images dataset. “””Trains a ResNet on the CIFAR10 dataset. ResNet v1[a] Deep Residual Learning for Image Recognitionhttps://arxiv.org/pdf/1512.03385.pdf ResNet v2[b] Identity Mappings in Deep Residual Networkshttps://arxiv.org/pdf/1603.05027.pdf“”” 1234567891011121314# Model parameter# ----------------------------------------------------------------------------# | | 200-epoch | Orig Paper| 200-epoch | Orig Paper| sec/epoch# Model | n | ResNet v1 | ResNet v1 | ResNet v2 | ResNet v2 | GTX1080Ti# |v1(v2)| %Accuracy | %Accuracy | %Accuracy | %Accuracy | v1 (v2)# ----------------------------------------------------------------------------# ResNet20 | 3 (2)| 92.16 | 91.25 | ----- | ----- | 35 (---)# ResNet32 | 5(NA)| 92.46 | 92.49 | NA | NA | 50 ( NA)# ResNet44 | 7(NA)| 92.50 | 92.83 | NA | NA | 70 ( NA)# ResNet56 | 9 (6)| 92.71 | 93.03 | 93.01 | NA | 90 (100)# ResNet110 |18(12)| 92.65 | 93.39+-.16| 93.15 | 93.63 | 165(180)# ResNet164 |27(18)| ----- | 94.07 | ----- | 94.54 | ---(---)# ResNet1001| (111)| ----- | 92.39 | ----- | 95.08+-.14| ---(---)# --------------------------------------------------------------------------- 网络结构 实验结果 conv_lstm.py Demonstrates the use of a convolutional LSTM network. 网络结构 实验结果epochs=100 - loss: 3.8720e-05 - val_loss: 1.0020e-04 image_ocr.pyTrains a convolutional stack followed by a recurrent stack and a CTC logloss function to perform optical character recognition (OCR). mnist_acgan.py Implementation of AC-GAN (Auxiliary Classifier GAN) on the MNIST dataset 123456789101112131415161718192021222324"""Train an Auxiliary Classifier Generative Adversarial Network (ACGAN) on theMNIST dataset. See https://arxiv.org/abs/1610.09585 for more details.You should start to see reasonable images after ~5 epochs, and good imagesby ~15 epochs. You should use a GPU, as the convolution-heavy operations arevery slow on the CPU. Prefer the TensorFlow backend if you plan on iterating,as the compilation time can be a blocker using Theano.Timings:Hardware | Backend | Time / Epoch------------------------------------------- CPU | TF | 3 hrs Titan X (maxwell) | TF | 4 min Titan X (maxwell) | TH | 7 minConsult https://github.com/lukedeo/keras-acgan for more information andexample output"""# Adam parameters suggested inhttps://arxiv.org/abs/1511.06434adam_lr = 0.0002adam_beta_1 = 0.5 网络结构mnist_acgan_generator mnist_acgan_discriminator mnist_acgan 实验结果1234567Testing for epoch 100:component | loss | generation_loss | auxiliary_loss-----------------------------------------------------------------generator (train) | 0.77 | 0.7664 | 0.0005generator (test) | 0.81 | 0.8105 | 0.0000discriminator (train) | 0.71 | 0.6947 | 0.0131discriminator (test) | 0.71 | 0.7032 | 0.0110 周期1 周期10 周期30 周期100 mnist_hierarchical_rnn.py Trains a Hierarchical RNN (HRNN) to classify MNIST digits. 网络结构 实验结果 mnist_siamese.pyTrains a Siamese multi-layer perceptron on pairs of digits from the MNIST dataset. mnist_swwae.py Trains a Stacked What-Where AutoEncoder built on residual blocks on the MNIST dataset. 12345678910111213141516171819202122232425262728293031323334353637383940'''Trains a stacked what-where autoencoder built on residual blocks on theMNIST dataset. It exemplifies two influential methods that have been developedin the past few years.The first is the idea of properly 'unpooling.' During any max pool, theexact location (the 'where') of the maximal value in a pooled receptive fieldis lost, however it can be very useful in the overall reconstruction of aninput image. Therefore, if the 'where' is handed from the encoderto the corresponding decoder layer, features being decoded can be 'placed' inthe right location, allowing for reconstructions of much higher fidelity.# References- Visualizing and Understanding Convolutional Networks Matthew D Zeiler, Rob Fergus https://arxiv.org/abs/1311.2901v3- Stacked What-Where Auto-encoders Junbo Zhao, Michael Mathieu, Ross Goroshin, Yann LeCun https://arxiv.org/abs/1506.02351v8The second idea exploited here is that of residual learning. Residual blocksease the training process by allowing skip connections that give the networkthe ability to be as linear (or non-linear) as the data sees fit. This allowsfor much deep networks to be easily trained. The residual element seems tobe advantageous in the context of this example as it allows a nice symmetrybetween the encoder and decoder. Normally, in the decoder, the finalprojection to the space where the image is reconstructed is linear, howeverthis does not have to be the case for a residual block as the degree to whichits output is linear or non-linear is determined by the data it is fed.However, in order to cap the reconstruction in this example, a hard softmax isapplied as a bias because we know the MNIST digits are mapped to [0, 1].# References- Deep Residual Learning for Image Recognition Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun https://arxiv.org/abs/1512.03385v1- Identity Mappings in Deep Residual Networks Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun https://arxiv.org/abs/1603.05027v3''' 网络结构 实验结果1epochs=5 loss: 0.0023 - val_loss: 0.0022 mnist_transfer_cnn.pyTransfer learning toy example on the MNIST dataset. ‘’’Transfer learning toy example.1 - Train a simple convnet on the MNIST dataset the first 5 digits [0..4].2 - Freeze convolutional layers and fine-tune dense layers for the classification of digits [5..9].Get to 99.8% test accuracy after 5 epochsfor the first five digits classifierand 99.2% for the last five digits after transfer + fine-tuning.‘’’ 网络结构 实验结果橙色的线是迁移前模型的数据，蓝色的线是迁移后模型的数据。 mnist_denoising_autoencoder.py Trains a denoising autoencoder on the MNIST dataset. 网络结构encoderdecoderautoencoder 实验结果模型去噪声结果 Text &amp; sequences examplesaddition_rnn.py Implementation of sequence to sequence learning for performing addition of two numbers (as strings). 1234567891011121314151617181920212223242526'''An implementation of sequence to sequence learning for performing additionInput: "535+61"Output: "596"Padding is handled by using a repeated sentinel character (space)Input may optionally be reversed, shown to increase performance in many tasks in:"Learning to Execute"http://arxiv.org/abs/1410.4615and"Sequence to Sequence Learning with Neural Networks"http://papers.nips.cc/paper/5346-sequence-to-sequence-learning-with-neural-networks.pdfTheoretically it introduces shorter term dependencies between source and target.Two digits reversed:+ One layer LSTM (128 HN), 5k training examples = 99% train/test accuracy in 55 epochsThree digits reversed:+ One layer LSTM (128 HN), 50k training examples = 99% train/test accuracy in 100 epochsFour digits reversed:+ One layer LSTM (128 HN), 400k training examples = 99% train/test accuracy in 20 epochsFive digits reversed:+ One layer LSTM (128 HN), 550k training examples = 99% train/test accuracy in 30 epochs''' 网络结构 实验结果12345678910111213epochs = 200 时的结果loss: 1.2168e-04 - acc: 1.0000 - val_loss: 0.0011 - val_acc: 0.9997Q 6+909 T 915 ☑ 915Q 128+263 T 391 ☑ 391Q 104+0 T 104 ☑ 104Q 63+352 T 415 ☑ 415Q 624+8 T 632 ☑ 632Q 31+251 T 282 ☑ 282Q 758+445 T 1203 ☑ 1203Q 88+534 T 622 ☑ 622Q 315+624 T 939 ☑ 939Q 81+459 T 540 ☑ 540 babi_rnn.py Trains a two-branch recurrent network on the bAbI dataset for reading comprehension. 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758'''Trains two recurrent neural networks based upon a story and a question.The resulting merged vector is then queried to answer a range of bAbI tasks.The results are comparable to those for an LSTM model provided in Weston et al.:"Towards AI-Complete Question Answering: A Set of Prerequisite Toy Tasks"http://arxiv.org/abs/1502.05698Task Number | FB LSTM Baseline | Keras QA--- | --- | ---QA1 - Single Supporting Fact | 50 | 100.0QA2 - Two Supporting Facts | 20 | 50.0QA3 - Three Supporting Facts | 20 | 20.5QA4 - Two Arg. Relations | 61 | 62.9QA5 - Three Arg. Relations | 70 | 61.9QA6 - yes/No Questions | 48 | 50.7QA7 - Counting | 49 | 78.9QA8 - Lists/Sets | 45 | 77.2QA9 - Simple Negation | 64 | 64.0QA10 - Indefinite Knowledge | 44 | 47.7QA11 - Basic Coreference | 72 | 74.9QA12 - Conjunction | 74 | 76.4QA13 - Compound Coreference | 94 | 94.4QA14 - Time Reasoning | 27 | 34.8QA15 - Basic Deduction | 21 | 32.4QA16 - Basic Induction | 23 | 50.6QA17 - Positional Reasoning | 51 | 49.1QA18 - Size Reasoning | 52 | 90.8QA19 - Path Finding | 8 | 9.0QA20 - Agent's Motivations | 91 | 90.7For the resources related to the bAbI project, refer to:https://research.facebook.com/researchers/1543934539189348# Notes- With default word, sentence, and query vector sizes, the GRU model achieves: - 100% test accuracy on QA1 in 20 epochs (2 seconds per epoch on CPU) - 50% test accuracy on QA2 in 20 epochs (16 seconds per epoch on CPU)In comparison, the Facebook paper achieves 50% and 20% for the LSTM baseline.- The task does not traditionally parse the question separately. This likelyimproves accuracy and is a good example of merging two RNNs.- The word vector embeddings are not shared between the story and question RNNs.- See how the accuracy changes given 10,000 training samples (en-10k) insteadof only 1000. 1000 was used in order to be comparable to the original paper.- Experiment with GRU, LSTM, and JZS1-3 as they give subtly different results.- The length and noise (i.e. 'useless' story components) impact the ability forLSTMs / GRUs to provide the correct answer. Given only the supporting facts,these RNNs can achieve 100% accuracy on many tasks. Memory networks and neuralnetworks that use attentional processes can efficiently search through thisnoise to find the relevant statements, improving performance substantially.This becomes especially obvious on QA2 and QA3, both far longer than QA1.''' 网络结构 实验结果 仅仅把 only_supporting=False 改为 Ture 就可以显著的提高模型准确率和训练速度。原因可能是去除了与问题无关的信息，缩小了答案搜索空间（由x(None, 552) 变成了 (None, 14) ）。这也说明目前，神经网络从大段阅读理解文章段里面找答案还是比较困难的，由几句话中找答案还是还是比较准确的。效果如下： 123with tarfile.open(path) as tar: train = get_stories(tar.extractfile(challenge.format('train')), only_supporting=True) test = get_stories(tar.extractfile(challenge.format('test')), only_supporting=True) babi_rnn_v2.py Trains a two-branch recurrent network on the bAbI dataset for reading comprehension. 1234567'''change: merged = layers.add([encoded_sentence, encoded_question])to: merged = layers.multiply([encoded_sentence, encoded_question])将 encoded_sentence 句子张量与 encoded_question 问题张量由通过加法融合变成乘积融合。模型 v2 在训练集中的表现优于 v1，在测试集同样（未过拟合前）优于 v1，但过拟合后差于 v1。''' 网络结构 实验结果橙色的表示 v1，分红表示 v2。 babi_memnn.py Trains a memory network on the bAbI dataset for reading comprehension. 123456789101112131415'''Trains a memory network on the bAbI dataset.References:- Jason Weston, Antoine Bordes, Sumit Chopra, Tomas Mikolov, Alexander M. Rush, "Towards AI-Complete Question Answering: A Set of Prerequisite Toy Tasks", http://arxiv.org/abs/1502.05698- Sainbayar Sukhbaatar, Arthur Szlam, Jason Weston, Rob Fergus, "End-To-End Memory Networks", http://arxiv.org/abs/1503.08895Reaches 98.6% accuracy on task 'single_supporting_fact_10k' after 120 epochs.Time per epoch: 3s on CPU (core i7).''' 网络结构 实验结果 babi_rnn_vs_memnn_on_10k_qa1_single-supporting-fact babi_rnn.py 和 babi_memnn.py 在 Facebook bAbi 阅读理解数据集 qa1_single-supporting-fact 上的对比实验。 网络结构见 babi_rnn.py 和 babi_memnn.py 的网络结构 实验结果 可见 babi_rnn.py 比 babi_memnn.py 不仅模型更简单，而且训练更快、效果更好。 imdb_bidirectional_lstm.py Trains a Bidirectional LSTM on the IMDB sentiment classification task. 网络结构 实验结果 imdb_cnn.py Demonstrates the use of Convolution1D for text classification. 网络结构 实验结果epochs=10loss: 0.0293 - acc: 0.9894 - val_loss: 0.5514 - val_acc: 0.8855 imdb_cnn_lstm.py Trains a convolutional stack followed by a recurrent stack network on the IMDB sentiment classification task. 网络结构 实验结果epochs=10Test score: 0.8979291968528181Test accuracy: 0.825119995546341 imdb_fasttext.py Trains a FastText model on the IMDB sentiment classification task. 1234567891011'''This example demonstrates the use of fasttext for text classificationBased on Joulin et al's paper:Bags of Tricks for Efficient Text Classificationhttps://arxiv.org/abs/1607.01759Results on IMDB datasets with uni and bi-gram embeddings: Uni-gram: 0.8813 test accuracy after 5 epochs. 8s/epoch on i7 cpu. Bi-gram : 0.9056 test accuracy after 5 epochs. 2s/epoch on GTx 980M gpu.''' 网络结构 实验结果 imdb_lstm.py Trains an LSTM model on the IMDB sentiment classification task. 1234567891011121314'''Trains an LSTM model on the IMDB sentiment classification task.The dataset is actually too small for LSTM to be of any advantagecompared to simpler, much faster methods such as TF-IDF + LogReg.# Notes- RNNs are tricky. Choice of batch size is important,choice of loss and optimizer is critical, etc.Some configurations won't converge.- LSTM loss decrease patterns during training can be quite differentfrom what you see with CNNs/MLPs/etc.''' 网络结构 实验结果epochs=15Test accuracy: 0.81312 lstm_stateful.pyDemonstrates how to use stateful RNNs to model long sequences efficiently. 网络结构 实验结果 lstm_seq2seq.py Trains a basic character-level sequence-to-sequence model.1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950'''Sequence to sequence example in Keras (character-level).This script demonstrates how to implement a basic character-levelsequence-to-sequence model. We apply it to translatingshort English sentences into short French sentences,character-by-character. Note that it is fairly unusual todo character-level machine translation, as word-levelmodels are more common in this domain.# Summary of the algorithm- We start with input sequences from a domain (e.g. English sentences) and corresponding target sequences from another domain (e.g. French sentences).- An encoder LSTM turns input sequences to 2 state vectors (we keep the last LSTM state and discard the outputs).- A decoder LSTM is trained to turn the target sequences into the same sequence but offset by one timestep in the future, a training process called "teacher forcing" in this context. Is uses as initial state the state vectors from the encoder. Effectively, the decoder learns to generate `targets[t+1...]` given `targets[...t]`, conditioned on the input sequence.- In inference mode, when we want to decode unknown input sequences, we: - Encode the input sequence into state vectors - Start with a target sequence of size 1 (just the start-of-sequence character) - Feed the state vectors and 1-char target sequence to the decoder to produce predictions for the next character - Sample the next character using these predictions (we simply use argmax). - Append the sampled character to the target sequence - Repeat until we generate the end-of-sequence character or we hit the character limit.# Data downloadEnglish to French sentence pairs.http://www.manythings.org/anki/fra-eng.zipLots of neat sentence pairs datasets can be found at:http://www.manythings.org/anki/# References- Sequence to Sequence Learning with Neural Networks https://arxiv.org/abs/1409.3215- Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation https://arxiv.org/abs/1406.1078''' 网络结构 编码器 解码器 实验结果epochs=100loss: 0.0602 - val_loss: 0.7592 123456789-Input sentence: Come in.Decoded sentence: Entrez !-Input sentence: Come on!Decoded sentence: Viens !-Input sentence: Drop it!Decoded sentence: Laisse tomber ! lstm_seq2seq_restore.py Restores a character-level sequence to sequence model from disk (saved by lstm_seq2seq.py) and uses it to generate predictions. 网络结构同 lstm_seq2seq 实验结果12345678Input sentence: Fire!Decoded sentence: Au feu !Input sentence: Help!Decoded sentence: À l'aide !Input sentence: Jump.Decoded sentence: Saute. pretrained_word_embeddings.py Loads pre-trained word embeddings (GloVe embeddings) into a frozen Keras Embedding layer, and uses it to train a text classification model on the 20 Newsgroup dataset. 网络结构 实验结果epochs=30loss: 0.1113 - acc: 0.9586 - val_loss: 1.6334 - val_acc: 0.7179 reuters_mlp.py Trains and evaluate a simple MLP on the Reuters newswire topic classification task. 网络结构 实验结果 reuters_mlp_relu_vs_selu网络结构12345Network 1 ReluHyperparameters: &#123;'n_dense': 6, 'dense_units': 16, 'activation': 'relu', 'dropout': &lt;class 'keras.layers.core.Dropout'&gt;, 'dropout_rate': 0.5, 'kernel_initializer': 'glorot_uniform', 'optimizer': 'sgd'&#125;Network 2 SeluHyperparameters: &#123;'n_dense': 6, 'dense_units': 16, 'activation': 'selu', 'dropout': &lt;class 'keras.layers.noise.AlphaDropout'&gt;, 'dropout_rate': 0.1, 'kernel_initializer': 'lecun_normal', 'optimizer': 'sgd'&#125; 实验结果123456Network 1 ReluTest score: 1.9769948146646827Test accuracy: 0.5204808548796103Network 2 SeluTest score: 1.530816549927872Test accuracy: 0.6714158504007124 Generative models exampleslstm_text_generation.py Generates text from Nietzsche’s writings. 1234567891011'''Example script to generate text from Nietzsche's writings.At least 20 epochs are required before the generated textstarts sounding coherent.It is recommended to run this script on GPU, as recurrentnetworks are quite computationally intensive.If you try this script on new data, make sure your corpushas at least ~100k characters. ~1M is better.''' 网络结构实验结果12345678910111213----- Generating text after Epoch: 99----- diversity: 0.2----- Generating with seed: " of his tolerance and humanity which pro" of his tolerance and humanity which proe ee e e e ee e ee et e ee te ee e" ! esov ehe eeted en enete ee e e ee q te e t eeqo a x een x qe n et" ! ex if i tewn x .o e v - ' e ! q jj j s t qhi xh x ! tetsa k ewetce e e of eeh e e et i e ee e x ee eetk( e e n e x xo = x ! xvekne x e ) x qnb z ehe e n x )edxd xx x xi x x tcnwet x- 'e o q e te eto e x eti '----- diversity: 0.5----- Generating with seed: " of his tolerance and humanity which pro" of his tolerance and humanity which pro ee e e ee ee ee e beeee ee e ' xx z e e ' en qengg x x evo-n x ! xn 'o xb i it k x n x xbe a wee x tix e i t q etvece e etoe o z eet i q h wete eo xe'e e egovee ! e eese e oe xe x e e zd ti q n x ni tqj x a n zxb x x " x we n n x j e et z v ! xj an ee xq " q styiete nxe! x et ! i qt ta xbn tx----- diversity: 1.0----- Generating with seed: " of his tolerance and humanity which pro" of his tolerance and humanity which proe eee ee eeeeee et eeeteeei ee (eeiiey qqe i n xxee x ue e jni " x xb z n n e in n e' ve te j e zw eeq(se t x q xve im:t x xxb tek x ehed te e't xheefe e-e xn e ebe eey zn xeg:ti xbs xvfete x !o ee- e e e o e we e ese eet -e oee e x (xb e ee necf e j e e ( ee je ie este)n ax q n . xjf z xi o t xxv x xnocese i----- diversity: 1.2----- Generating with seed: " of his tolerance and humanity which pro" of his tolerance and humanity which pro eeeee eee e e e tetee" e eteeee-e i eex o xhe ee x e on e te"( t x xg e i hek.tni etf xiecnne evet ecewe e e o ec ? e;e ,ee e e ee e;skyn xe e e x xte he et i q x jw w xn xn e x ' q= t o n nex e =tho xenwei ao? x zn x evq ety q x x et e es be d x xq ie n xetzo ke q y etx xt xsn inn eti e x ei eq t conv_filter_visualization.py Visualization of the filters of VGG16, via gradient ascent in input space. Results example: http://i.imgur.com/4nj4KjN.jpg 网络结构 实验结果 deep_dream.pyDeep Dreams in Keras. 网络结构实验结果 neural_doodle.pyNeural doodle. 网络结构实验结果 neural_style_transfer.pyNeural style transfer. 网络结构实验结果 variational_autoencoder.py Demonstrates how to build a variational autoencoder. 12345678910111213'''Example of VAE on MNIST dataset using MLPThe VAE has a modular design. The encoder, decoder and VAEare 3 models that share weights. After training the VAE model,the encoder can be used to generate latent vectors.The decoder can be used to generate MNIST digits by sampling thelatent vector from a Gaussian distribution with mean=0 and std=1.**Reference：**[1] Kingma, Diederik P., and Max Welling."Auto-encoding variational bayes."https://arxiv.org/abs/1312.6114''' 网络结构encoderdecoderautoencoder 实验结果模型生成手写数字的效果 digits_over_latent 模型 2 维隐藏变量的均值（z_mean）可视化后的效果 variational_autoencoder_deconv.py Demonstrates how to build a variational autoencoder with Keras using deconvolution layers. ‘’’Example of VAE on MNIST dataset using CNNThe VAE has a modular design. The encoder, decoder and VAEare 3 models that share weights. After training the VAE model,the encoder can be used to generate latent vectors.The decoder can be used to generate MNIST digits by sampling thelatent vector from a Gaussian distribution with mean=0 and std=1. Reference[1] Kingma, Diederik P., and Max Welling.“Auto-encoding variational bayes.”https://arxiv.org/abs/1312.6114‘’’ 网络结构encoderdecoderautoencoder 实验结果模型生成手写数字的效果 模型 2 维隐藏变量的均值（z_mean）可视化后的效果 Examples demonstrating specific Keras functionalityantirectifier.py Demonstrates how to write custom layers for Keras. 1234567891011'''The example demonstrates how to write custom layers for Keras.We build a custom activation layer called 'Antirectifier',which modifies the shape of the tensor that passes through it.We need to specify two methods: `compute_output_shape` and `call`.Note that the same result can also be achieved via a Lambda layer.Because our custom layer is written with primitives from the Kerasbackend (`K`), our code can run both on TensorFlow and Theano.''' 网络结构 实验结果12epochs = 40acc: 0.9985 - val_loss: 0.0901 - val_acc: 0.9809 灰色是 antirectifier，蓝色是 mnist_cnn，橙色是 mnist_mpl。 mnist_sklearn_wrapper.py Demonstrates how to use the sklearn wrapper. 1234&apos;&apos;&apos;Example of how to use sklearn wrapperBuilds simple CNN models on MNIST and uses sklearn&apos;s GridSearchCV to find best model&apos;&apos;&apos; 网络结构 实验结果1234The parameters of the best model are:&#123;'dense_layer_sizes': [64, 64], 'epochs': 6, 'filters': 8, 'kernel_size': 3, 'pool_size': 2&#125;loss : 0.042469549842912235acc : 0.9872 mnist_irnn.pyReproduction of the IRNN experiment with pixel-by-pixel sequential MNIST in “A Simple Way to Initialize Recurrent Networks of Rectified Linear Units” by Le et al. mnist_net2net.pyReproduction of the Net2Net experiment with MNIST in “Net2Net: Accelerating Learning via Knowledge Transfer”. reuters_mlp_relu_vs_selu.pyCompares self-normalizing MLPs with regular MLPs. mnist_tfrecord.pyMNIST dataset with TFRecords, the standard TensorFlow data format. mnist_dataset_api.pyMNIST dataset with TensorFlow’s Dataset API. cifar10_cnn_tfaugment2d.py Trains a simple deep CNN on the CIFAR10 small images dataset using Tensorflow internal augmentation APIs. 12345678910111213141516171819202122232425262728293031323334'''Train a simple deep CNN on the CIFAR10 small images dataset.Using Tensorflow internal augmentation APIs by replacing ImageGenerator withan embedded AugmentLayer using LambdaLayer, which is faster on GPU.# Benchmark of `ImageGenerator` vs `AugmentLayer` both using augmentation 2D:(backend = Tensorflow-GPU, Nvidia Tesla P100-SXM2)Settings: horizontal_flip = True----------------------------------------------------------------------------Epoch | ImageGenerator | ImageGenerator | AugmentLayer | Augment LayerNumber | %Accuracy | Performance | %Accuracy | Performance----------------------------------------------------------------------------1 | 44.84 | 15ms/step | 45.54 | 358us/step2 | 52.34 | 8ms/step | 50.55 | 285us/step8 | 65.45 | 8ms/step | 65.59 | 281us/step25 | 76.74 | 8ms/step | 76.17 | 280us/step100 | 78.81 | 8ms/step | 78.70 | 285us/step---------------------------------------------------------------------------Settings: rotation = 30.0----------------------------------------------------------------------------Epoch | ImageGenerator | ImageGenerator | AugmentLayer | Augment LayerNumber | %Accuracy | Performance | %Accuracy | Performance----------------------------------------------------------------------------1 | 43.46 | 15ms/step | 42.21 | 334us/step2 | 48.95 | 11ms/step | 48.06 | 282us/step8 | 63.59 | 11ms/step | 61.35 | 290us/step25 | 72.25 | 12ms/step | 71.08 | 287us/step100 | 76.35 | 11ms/step | 74.62 | 286us/step---------------------------------------------------------------------------(Corner process and rotation precision by `ImageGenerator` and `AugmentLayer`are slightly different.)''' 网络结构 实验结果 tensorboard_embeddings_mnist.pyTrains a simple convnet on the MNIST dataset and embeds test data which can be later visualized using TensorBoard’s Embedding Projector. Keras API 部分说明LSTM理解LSTM在keras API中参数return_sequences和return_state Understand the Difference Between Return Sequences and Return States for LSTMs in Keras Kears LSTM API 中给出的两个参数描述 return_sequences：默认 False。在输出序列中，返回单个 hidden state值还是返回全部time step 的 hidden state值。 False 返回单个， true 返回全部。 return_state：默认 False。是否返回除输出之外的最后一个状态。 return_sequences return_state 式子 效果 False False 123456789101112131415161718192021222324252627282930313233343536373839404142434445|True|False|```LSTM(1, return_sequences=True)```|输出的hidden state 包含全部时间步的结果。||False|True|```lstm1, state_h, state_c = LSTM(1, return_state=True)```|lstm1 和 state_h 结果都是 hidden state。在这种参数设定下，它们俩的值相同。都是最后一个时间步的 hidden state。 state_c 是最后一个时间步 cell state结果。||True|True|```lstm1, state_h, state_c = LSTM(1, return_sequences=True, return_state=True)```|此时，我们既要输出全部时间步的 hidden state ，又要输出 cell state。lstm1 存放的就是全部时间步的 hidden state。state_h 存放的是最后一个时间步的 hidden state。state_c 存放的是最后一个时间步的 cell state|## AlphaDropout [噪声层Noise](https://keras-cn.readthedocs.io/en/latest/layers/noise_layer/)Alpha Dropout是一种保持输入均值和方差不变的Dropout，该层的作用是即使在dropout时也保持数据的自规范性。 通过随机对负的饱和值进行激活，Alphe Drpout与selu激活函数配合较好。参数rate: 浮点数，类似Dropout的Drop比例。乘性mask的标准差将保证为sqrt(rate / (1 - rate)).seed: 随机数种子输入shape任意，当使用该层为模型首层时需指定input_shape参数输出shape与输入相同参考文献[Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515)## [文本Tokenizer与序列pad_sequences预处理](https://blog.csdn.net/zzulp/article/details/76146947)```pythonimport keras.preprocessing.text as Tfrom keras.preprocessing.text import Tokenizertext1='some thing to eat'text2='some thing to drink'texts=[text1,text2]print T.text_to_word_sequence(text1) #['some', 'thing', 'to', 'eat']print T.one_hot(text1,10) #[7, 9, 3, 4]print T.one_hot(text2,10) #[7, 9, 3, 1]tokenizer = Tokenizer(num_words=10)tokenzier.fit_on_text(texts)print tokenizer.word_count #[('some', 2), ('thing', 2), ('to', 2), ('eat', 1), ('drink', 1)]print tokenizer.word_index #&#123;'some': 1, 'thing': 2,'to': 3 ','eat': 4, drink': 5&#125;print tokenizer.word_docs #&#123;'some': 2, 'thing': 2, 'to': 2, 'drink': 1, 'eat': 1&#125;print tokenizer.index_docs #&#123;1: 2, 2: 2, 3: 2, 4: 1, 5: 1&#125;print tokenizer.text_to_sequences(texts) #[[1, 2, 3, 4], [1, 2, 3, 5]]print tokenizer.text_to_matrix(texts) #[[ 0., 1., 1., 1., 1., 0., 0., 0., 0., 0.], [ 0., 1., 1., 1., 0., 1., 0., 0., 0., 0.]] 123import keras.preprocessing.sequence as SS.pad_sequences([[1,2,3]],10,padding='post')# [[1, 2, 3, 0, 0, 0, 0, 0, 0, 0]]]]></content>
      <categories>
        <category>Artificial Intelligence Navigation</category>
        <category>Keras手册</category>
      </categories>
      <tags>
        <tag>深度学习框架</tag>
        <tag>Keras</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[循环神经网络RNN长短期记忆网络LSTM与门控循环网络GRU]]></title>
    <url>%2F2018%2F10%2F23%2F%E5%BE%AA%E7%8E%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9CRNN%E9%95%BF%E7%9F%AD%E6%9C%9F%E8%AE%B0%E5%BF%86%E7%BD%91%E7%BB%9CLSTM%E4%B8%8E%E9%97%A8%E6%8E%A7%E5%BE%AA%E7%8E%AF%E7%BD%91%E7%BB%9CGRU%2F</url>
    <content type="text"><![CDATA[RNN LSTM 最基本知识RNNCell1234567891011import tensorflow as tfimport numpy as npcell = tf.nn.rnn_cell.BasicRNNCell(num_units=128) # state_size = 128print(cell.state_size) # 128inputs = tf.placeholder(np.float32, shape=(32, 100)) # 32 是 batch_sizeh0 = cell.zero_state(32, np.float32) # 通过zero_state得到一个全0的初始状态，形状为(batch_size, state_size)output, h1 = cell(inputs, h0) #调用函数print(h1.shape) # (32, 128) BasicLSTMCell123456789import tensorflow as tfimport numpy as nplstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=128)inputs = tf.placeholder(np.float32, shape=(32, 100)) # 32 是 batch_sizeh0 = lstm_cell.zero_state(32, np.float32) # 通过zero_state得到一个全0的初始状态output, h1 = lstm_cell(inputs, h0)print(h1.h) # shape=(32, 128)print(h1.c) # shape=(32, 128) 堆叠RNNCell：MultiRNNCell12345678910111213141516171819202122232425262728293031323334import tensorflow as tfimport numpy as np# 每调用一次这个函数就返回一个BasicRNNCelldef get_a_cell(): return tf.nn.rnn_cell.BasicRNNCell(num_units=128)# 用tf.nn.rnn_cell MultiRNNCell创建3层RNNcell = tf.nn.rnn_cell.MultiRNNCell([get_a_cell() for _ in range(3)]) # 3层RNN# 得到的cell实际也是RNNCell的子类# 它的state_size是(128, 128, 128)# (128, 128, 128)并不是128x128x128的意思# 而是表示共有3个隐层状态，每个隐层状态的大小为128print(cell.state_size) # (128, 128, 128)# 使用对应的call函数inputs = tf.placeholder(np.float32, shape=(32, 100)) # 32 是 batch_sizeh0 = cell.zero_state(32, np.float32) # 通过zero_state得到一个全0的初始状态, tuple中含有3个32x128的向量output, h1 = cell.call(inputs, h0)print(h1) # tuple中含有3个32x128的向量 符号说明 RNN 单层RNN12345678910111213141516171819202122232425262728293031import tensorflow as tfimport numpy as npn_steps = 2n_inputs = 3n_neurons = 5X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)seq_length = tf.placeholder(tf.int32, [None])outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32, sequence_length=seq_length)init = tf.global_variables_initializer()X_batch = np.array([ # step 0 step 1 [[0, 1, 2], [9, 8, 7]], # instance 1 [[3, 4, 5], [0, 0, 0]], # instance 2 (padded with zero vectors) [[6, 7, 8], [6, 5, 4]], # instance 3 [[9, 0, 1], [3, 2, 1]], # instance 4 ])seq_length_batch = np.array([2, 1, 2, 2])with tf.Session() as sess: init.run() outputs_val, states_val = sess.run( [outputs, states], feed_dict=&#123;X: X_batch, seq_length: seq_length_batch&#125;) print("outputs_val.shape:", outputs_val.shape, "states_val.shape:", states_val.shape) print("outputs_val:", outputs_val, "states_val:", states_val) 123456789101112131415161718outputs_val.shape: (4, 2, 5) states_val.shape: (4, 5)outputs_val:[[[ 0.53073734 -0.61281306 -0.5437517 0.7320347 -0.6109526 ] [ 0.99996936 0.99990636 -0.9867181 0.99726075 -0.99999976]] [[ 0.9931584 0.5877845 -0.9100412 0.988892 -0.9982337 ] [ 0. 0. 0. 0. 0. ]] [[ 0.99992317 0.96815354 -0.985101 0.9995968 -0.9999936 ] [ 0.99948144 0.9998127 -0.57493806 0.91015154 -0.99998355]] [[ 0.99999255 0.9998929 0.26732785 0.36024097 -0.99991137] [ 0.98875254 0.9922327 0.6505734 0.4732064 -0.9957567 ]]]states_val: [[ 0.99996936 0.99990636 -0.9867181 0.99726075 -0.99999976] [ 0.9931584 0.5877845 -0.9100412 0.988892 -0.9982337 ] [ 0.99948144 0.9998127 -0.57493806 0.91015154 -0.99998355] [ 0.98875254 0.9922327 0.6505734 0.4732064 -0.9957567 ]] 首先输入X是一个 [batch_size，step，input_size] = [4，2，3] 的tensor，注意我们这里调用的是BasicRNNCell，只有一层循环网络，outputs是最后一层每个step的输出，它的结构是[batch_size，step，n_neurons] = [4，2，5]，states是每一层的最后那个step的输出，由于本例中，我们的循环网络只有一个隐藏层，所以它就代表这一层的最后那个step的输出，因此它和step的大小是没有关系的，我们的X有4个样本组成，输出神经元大小n_neurons是5，因此states的结构就是[batch_size，n_neurons] = [4，5]，最后我们观察数据，states的每条数据正好就是outputs的最后一个step的输出。 三层RNN1234567891011121314151617181920212223242526272829303132333435import tensorflow as tfimport numpy as npn_steps = 2n_inputs = 3n_neurons = 5n_layers = 3X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])seq_length = tf.placeholder(tf.int32, [None])layers = [tf.contrib.rnn.BasicRNNCell(num_units=n_neurons, activation=tf.nn.relu) for layer in range(n_layers)]multi_layer_cell = tf.contrib.rnn.MultiRNNCell(layers)outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32, sequence_length=seq_length)init = tf.global_variables_initializer()X_batch = np.array([ # step 0 step 1 [[0, 1, 2], [9, 8, 7]], # instance 1 [[3, 4, 5], [0, 0, 0]], # instance 2 (padded with zero vectors) [[6, 7, 8], [6, 5, 4]], # instance 3 [[9, 0, 1], [3, 2, 1]], # instance 4 ])seq_length_batch = np.array([2, 1, 2, 2])with tf.Session() as sess: init.run() outputs_val, states_val = sess.run( [outputs, states], feed_dict=&#123;X: X_batch, seq_length: seq_length_batch&#125;) print("outputs_val.shape:", outputs, "states_val.shape:", states) print("outputs_val:", outputs_val, "states_val:", states_val) 12345678910111213141516171819202122232425262728293031323334353637outputs_val.shape:Tensor("rnn/transpose_1:0", shape=(?, 2, 5), dtype=float32)states_val.shape:(&lt;tf.Tensor 'rnn/while/Exit_3:0' shape=(?, 5) dtype=float32&gt;, &lt;tf.Tensor 'rnn/while/Exit_4:0' shape=(?, 5) dtype=float32&gt;, &lt;tf.Tensor 'rnn/while/Exit_5:0' shape=(?, 5) dtype=float32&gt;)outputs_val: [[[0. 0. 0. 0. 0. ] [0. 0.18740742 0. 0.2997518 0. ]] [[0. 0.07222144 0. 0.11551574 0. ] [0. 0. 0. 0. 0. ]] [[0. 0.13463384 0. 0.21534224 0. ] [0.03702604 0.18443246 0. 0.34539366 0. ]] [[0. 0.54511094 0. 0.8718864 0. ] [0.5382122 0. 0.04396425 0.4040263 0. ]]]states_val: (array([[0. , 0.83723307, 0. , 0. , 2.8518028 ], [0. , 0.1996038 , 0. , 0. , 1.5456247 ], [0. , 1.1372368 , 0. , 0. , 0.832613 ], [0. , 0.7904129 , 2.4675028 , 0. , 0.36980057]], dtype=float32), array([[0.6524607 , 0. , 0. , 0. , 0. ], [0.25143963, 0. , 0. , 0. , 0. ], [0.5010576 , 0. , 0. , 0. , 0. ], [0. , 0.3166597 , 0.4545995 , 0. , 0. ]], dtype=float32), array([[0. , 0.18740742, 0. , 0.2997518 , 0. ], [0. , 0.07222144, 0. , 0.11551574, 0. ], [0.03702604, 0.18443246, 0. , 0.34539366, 0. ], [0.5382122 , 0. , 0.04396425, 0.4040263 , 0. ]], dtype=float32)) outputs是最后一层的输出，即 [batch_size，step，n_neurons] = [4，2，5] states是每一层的最后一个step的输出，即三个结构为 [batch_size，n_neurons] = [4，5] 的tensor。 LSTM 三层LSTM下面我们继续讲当由BasicLSTMCell构造单元工厂的时候，只讲多层的情况，我们只需要将上面的BasicRNNCell替换成BasicLSTMCell就行了，打印信息如下： 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970outputs_val.shape:Tensor("rnn/transpose_1:0", shape=(?, 2, 5), dtype=float32)states_val.shape:(LSTMStateTuple(c=&lt;tf.Tensor 'rnn/while/Exit_3:0' shape=(?, 5) dtype=float32&gt;, h=&lt;tf.Tensor 'rnn/while/Exit_4:0' shape=(?, 5) dtype=float32&gt;),LSTMStateTuple(c=&lt;tf.Tensor 'rnn/while/Exit_5:0' shape=(?, 5) dtype=float32&gt;, h=&lt;tf.Tensor 'rnn/while/Exit_6:0' shape=(?, 5) dtype=float32&gt;),LSTMStateTuple(c=&lt;tf.Tensor 'rnn/while/Exit_7:0' shape=(?, 5) dtype=float32&gt;, h=&lt;tf.Tensor 'rnn/while/Exit_8:0' shape=(?, 5) dtype=float32&gt;))outputs_val:[[[1.2949290e-04 0.0000000e+00 2.7623639e-04 0.0000000e+00 0.0000000e+00] [9.4675866e-05 0.0000000e+00 2.0214770e-04 0.0000000e+00 0.0000000e+00]] [[4.3100454e-06 4.2123037e-07 1.4312843e-06 0.0000000e+00 0.0000000e+00] [0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]] [[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00] [0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]] [[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00] [0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]]]states_val:(LSTMStateTuple(c=array([[0. , 0. , 0.04676079, 0.04284539, 0. ], [0. , 0. , 0.0115245 , 0. , 0. ], [0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0. , 0. , 0. ]], dtype=float32),h=array([[0. , 0. , 0.00035096, 0.04284406, 0. ], [0. , 0. , 0.00142574, 0. , 0. ], [0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0. , 0. , 0. ]], dtype=float32)),LSTMStateTuple(c=array([[0.0000000e+00, 1.0477135e-02, 4.9871090e-03, 8.2785974e-04, 0.0000000e+00], [0.0000000e+00, 2.3306280e-04, 0.0000000e+00, 9.9445322e-05, 5.9535629e-05], [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00], [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00]], dtype=float32),h=array([[0.00000000e+00, 5.23016974e-03, 2.47756205e-03, 4.11730434e-04, 0.00000000e+00], [0.00000000e+00, 1.16522635e-04, 0.00000000e+00, 4.97301044e-05, 2.97713632e-05], [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00], [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00]], dtype=float32)),LSTMStateTuple(c=array([[1.8937115e-04, 0.0000000e+00, 4.0442235e-04, 0.0000000e+00, 0.0000000e+00], [8.6200516e-06, 8.4243663e-07, 2.8625946e-06, 0.0000000e+00, 0.0000000e+00], [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00], [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00]], dtype=float32),h=array([[9.4675866e-05, 0.0000000e+00, 2.0214770e-04, 0.0000000e+00, 0.0000000e+00], [4.3100454e-06, 4.2123037e-07, 1.4312843e-06, 0.0000000e+00, 0.0000000e+00], [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00], [0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00]], dtype=float32))) 如果您不查看框内的内容，LSTM单元看起来与常规单元格完全相同，除了它的状态分为两个向量：h（t）和c（t）。你可以将h（t）视为短期状态，将c（t）视为长期状态。 因此我们的states包含三个LSTMStateTuple，每一个表示每一层的最后一个step的输出，这个输出有两个信息，一个是h表示短期记忆信息，一个是c表示长期记忆信息。维度都是[batch_size，n_neurons] = [4，5]，states的最后一个LSTMStateTuple中的h就是outputs的最后一个step的输出。 GRU GRU 与RNN 代码基本一致，把basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons) 改为 basic_cell = tf.nn.rnn_cell.GRUCell(num_units=n_neurons)即可，结果分析同 RNN。 123456789101112131415161718192021222324252627282930import tensorflow as tfimport numpy as npn_steps = 2n_inputs = 3n_neurons = 5X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])basic_cell = tf.nn.rnn_cell.GRUCell(num_units=n_neurons)seq_length = tf.placeholder(tf.int32, [None])outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32, sequence_length=seq_length)init = tf.global_variables_initializer()X_batch = np.array([ # step 0 step 1 [[0, 1, 2], [9, 8, 7]], # instance 1 [[3, 4, 5], [0, 0, 0]], # instance 2 (padded with zero vectors) [[6, 7, 8], [6, 5, 4]], # instance 3 [[9, 0, 1], [3, 2, 1]], # instance 4 ])seq_length_batch = np.array([2, 1, 2, 2])with tf.Session() as sess: init.run() outputs_val, states_val = sess.run( [outputs, states], feed_dict=&#123;X: X_batch, seq_length: seq_length_batch&#125;) print("outputs_val.shape:\n", outputs_val.shape, "\n", "states_val.shape:\n", states_val.shape) print("outputs_val:\n", outputs_val, "\n", "states_val:\n", states_val) 123456789101112131415161718192021outputs_val.shape: (4, 2, 5) states_val.shape: (4, 5)outputs_val: [[[ 0.22116265 -0.22573735 -0.14904192 0.37703517 -0.30065483] [-0.7885206 -0.98389083 -0.9981788 -0.69401765 -0.8436984 ]] [[-0.05911613 -0.8660758 -0.8889632 0.5718673 -0.53511584] [ 0. 0. 0. 0. 0. ]] [[-0.5683394 -0.9810551 -0.9934057 0.52230877 -0.7324221 ] [-0.78916883 -0.9947928 -0.9948283 -0.46843335 -0.8880266 ]] [[-0.23682797 -0.6044112 -0.93784267 -0.879141 -0.9476821 ] [-0.37557948 -0.73722005 -0.9297143 -0.5171338 -0.955366 ]]] states_val: [[-0.7885206 -0.98389083 -0.9981788 -0.69401765 -0.8436984 ] [-0.05911613 -0.8660758 -0.8889632 0.5718673 -0.53511584] [-0.78916883 -0.9947928 -0.9948283 -0.46843335 -0.8880266 ] [-0.37557948 -0.73722005 -0.9297143 -0.5171338 -0.955366 ]] 标题 说明 附加 看图理解长短期记忆网络与门控循环网络 翻译自 Illustrated Guide to LSTM’s and GRU’s: A step by step explanation 20181013 图解RNN、RNN变体、Seq2Seq、Attention机制 何之源 [译] 理解 LSTM 网络 译自 Christopher Olah 的博文 20180828 tf.nn.dynamic_rnn返回值详解 迗迗迗蘫 20180801]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>RNN</tag>
        <tag>LSTM</tag>
        <tag>GRU</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[SMP2018中文人机对话技术评测（ECDT）]]></title>
    <url>%2F2018%2F10%2F11%2FSMP2018%E4%B8%AD%E6%96%87%E4%BA%BA%E6%9C%BA%E5%AF%B9%E8%AF%9D%E6%8A%80%E6%9C%AF%E8%AF%84%E6%B5%8B%EF%BC%88ECDT%EF%BC%89%2F</url>
    <content type="text"><![CDATA[点击查看GitHub SMP2018 完整代码和解析 标题 说明 时间 CodaLab评测主页 数据下载 20181010 CodaLab 评测教程 20181010 评测排行榜 SMP2018-ECDT评测主页 SMP2018-ECDT评测成绩公告链接 根据SMP2018中文人机对话模型创建的应用简单的说就是给用户的问题分类，效果如下： .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } query label 0 今天东莞天气如何 weather 1 从观音桥到重庆市图书馆怎么走 map 2 鸭蛋怎么腌？ cookbook 3 怎么治疗牛皮癣 health 4 唠什么 chat 用户意图领域分类 在人机对话系统的应用过程中，用户可能会有多种意图，相应地会触发人机对话系统中的多个领域（domain） ，其中包括任务型垂直领域（如查询机票、酒店、公交车等）、知识型问答以及闲聊等。因而，人机对话系统的一个关键任务就是正确地将用户的输入分类到相应的领域（domain）中，从而才能返回正确的回复结果。 分类的类别说明 包含闲聊和垂类两大类，其中垂类又细分为30个垂直领域。 本次评测任务1中，仅考虑针对单轮对话用户意图的领域分类，多轮对话整体意图的领域分类不在此次评测范围之内。类别 = [‘website’, ‘tvchannel’, ‘lottery’, ‘chat’, ‘match’, &#39;datetime&#39;, &#39;weather&#39;, &#39;bus&#39;, &#39;novel&#39;, &#39;video&#39;, &#39;riddle&#39;, &#39;calc&#39;, &#39;telephone&#39;, &#39;health&#39;, &#39;contacts&#39;, &#39;epg&#39;, &#39;app&#39;, &#39;music&#39;, &#39;cookbook&#39;, &#39;stock&#39;, &#39;map&#39;, &#39;message&#39;, &#39;poetry&#39;, &#39;cinemas&#39;, &#39;news&#39;, &#39;flight&#39;, &#39;translation&#39;, &#39;train&#39;, &#39;schedule&#39;, &#39;radio&#39;, &#39;email&#39;] 开始使用 1from app import query_2_label Using TensorFlow backend. 1query_2_label('我喜欢你') Building prefix dict from the default dictionary ... Loading model from cache /tmp/jieba.cache Loading model cost 0.945 seconds. Prefix dict has been built succesfully. &#39;chat&#39; 运行下面代码进行查询，输入 0 结束查询 12345678while True: your_query_sentence = input() print('-'*10) label = query_2_label(your_query_sentence) print('predict label:\t', label) print('-'*10) if your_query_sentence=='0': break 今天东莞天气如何 ---------- predict label: datetime ---------- 怎么治疗感冒？ ---------- predict label: health ---------- 你好？ ---------- predict label: chat ---------- 与实验部分的分割线 SMP2018中文人机对话技术评测（ECDT） 下面是一个完整的针对 SMP2018中文人机对话技术评测（ECDT） 的实验，由该实验训练的基线模型能达到评测排行榜的前三的水平。 通过本实验，可以掌握处理自然语言文本数据的一般方法。 推荐自己修改此文件，达到更好的实验效果，比如改变以下几个超参数 123456# 词嵌入的维度embedding_word_dims = 32# 批次大小batch_size = 30# 周期epochs = 20 本实验还可以改进的地方举例 预处理阶段使用其它的分词工具 采用字符向量和词向量结合的方式 使用预先训练好的词向量 改变模型结构 改变模型超参数 导入依赖库123456789101112131415161718import numpy as npimport pandas as pdimport collectionsimport jiebafrom keras.preprocessing.text import Tokenizerfrom keras.preprocessing.sequence import pad_sequencesfrom keras.models import Sequentialfrom keras.layers import Embedding, LSTM, Densefrom keras.utils import to_categorical,plot_modelfrom keras.callbacks import TensorBoard, Callbackfrom sklearn.metrics import classification_reportimport requestsimport timeimport os Using TensorFlow backend. 辅助函数1234567891011121314151617181920212223242526272829303132from keras import backend as K# 计算 F1 值的函数def f1(y_true, y_pred): def recall(y_true, y_pred): """Recall metric. Only computes a batch-wise average of recall. Computes the recall, a metric for multi-label classification of how many relevant items are selected. """ true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) possible_positives = K.sum(K.round(K.clip(y_true, 0, 1))) recall = true_positives / (possible_positives + K.epsilon()) return recall def precision(y_true, y_pred): """Precision metric. Only computes a batch-wise average of precision. Computes the precision, a metric for multi-label classification of how many selected items are relevant. """ true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1))) precision = true_positives / (predicted_positives + K.epsilon()) return precision precision = precision(y_true, y_pred) recall = recall(y_true, y_pred) return 2*((precision*recall)/(precision+recall+K.epsilon())) 123456# 获取自定义时间格式的字符串def get_customization_time(): # return '2018_10_10_18_11_45' 年月日时分秒 time_tuple = time.localtime(time.time()) customization_time = "&#123;&#125;_&#123;&#125;_&#123;&#125;_&#123;&#125;_&#123;&#125;_&#123;&#125;".format(time_tuple[0], time_tuple[1], time_tuple[2], time_tuple[3], time_tuple[4], time_tuple[5]) return customization_time 准备数据下载SMP2018官方数据12345678910111213raw_train_data_url = "https://worksheets.codalab.org/rest/bundles/0x0161fd2fb40d4dd48541c2643d04b0b8/contents/blob/"raw_test_data_url = "https://worksheets.codalab.org/rest/bundles/0x1f96bc12222641209ad057e762910252/contents/blob/"# 如果不存在 SMP2018 数据，则下载if (not os.path.exists('./data/train.json')) or (not os.path.exists('./data/dev.json')): raw_train = requests.get(raw_train_data_url) raw_test = requests.get(raw_test_data_url) if not os.path.exists('./data'): os.makedirs('./data') with open("./data/train.json", "wb") as code: code.write(raw_train.content) with open("./data/dev.json", "wb") as code: code.write(raw_test.content) 12345678def get_json_data(path): # read data data_df = pd.read_json(path) # change row and colunm data_df = data_df.transpose() # change colunm order data_df = data_df[['query', 'label']] return data_df 123train_data_df = get_json_data(path="data/train.json")test_data_df = get_json_data(path="data/dev.json") 1train_data_df.head() .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } query label 0 今天东莞天气如何 weather 1 从观音桥到重庆市图书馆怎么走 map 2 鸭蛋怎么腌？ cookbook 3 怎么治疗牛皮癣 health 4 唠什么 chat 结巴分词示例，下面将使用结巴分词对原数据进行处理12seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式print(list(seg_list)) Building prefix dict from the default dictionary ... Loading model from cache /tmp/jieba.cache Loading model cost 1.022 seconds. Prefix dict has been built succesfully. [&#39;他&#39;, &#39;来到&#39;, &#39;了&#39;, &#39;网易&#39;, &#39;杭研&#39;, &#39;大厦&#39;] 序列化12345def use_jieba_cut(a_sentence): return list(jieba.cut(a_sentence))train_data_df['cut_query'] = train_data_df['query'].apply(use_jieba_cut)test_data_df['cut_query'] = test_data_df['query'].apply(use_jieba_cut) 1train_data_df.head(10) .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } query label cut_query 0 今天东莞天气如何 weather [今天, 东莞, 天气, 如何] 1 从观音桥到重庆市图书馆怎么走 map [从, 观音桥, 到, 重庆市, 图书馆, 怎么, 走] 2 鸭蛋怎么腌？ cookbook [鸭蛋, 怎么, 腌, ？] 3 怎么治疗牛皮癣 health [怎么, 治疗, 牛皮癣] 4 唠什么 chat [唠, 什么] 5 阳澄湖大闸蟹的做法。 cookbook [阳澄湖, 大闸蟹, 的, 做法, 。] 6 昆山大润发在哪里 map [昆山, 大润发, 在, 哪里] 7 红烧肉怎么做？嗯？ cookbook [红烧肉, 怎么, 做, ？, 嗯, ？] 8 南京到厦门的火车票 train [南京, 到, 厦门, 的, 火车票] 9 6的平方 calc [6, 的, 平方] 处理特征1tokenizer = Tokenizer() 1tokenizer.fit_on_texts(train_data_df['cut_query']) 123max_features = len(tokenizer.index_word)len(tokenizer.index_word) 2883 123x_train = tokenizer.texts_to_sequences(train_data_df['cut_query'])x_test = tokenizer.texts_to_sequences(test_data_df['cut_query']) 1max_cut_query_lenth = 26 123x_train = pad_sequences(x_train, max_cut_query_lenth)x_test = pad_sequences(x_test, max_cut_query_lenth) 1x_train.shape (2299, 26) 1x_test.shape (770, 26) 处理标签1label_tokenizer = Tokenizer() 1label_tokenizer.fit_on_texts(train_data_df['label']) 1label_numbers = len(label_tokenizer.word_counts) 1NUM_CLASSES = len(label_tokenizer.word_counts) 1label_tokenizer.word_counts OrderedDict([(&#39;weather&#39;, 66), (&#39;map&#39;, 68), (&#39;cookbook&#39;, 269), (&#39;health&#39;, 55), (&#39;chat&#39;, 455), (&#39;train&#39;, 70), (&#39;calc&#39;, 24), (&#39;translation&#39;, 61), (&#39;music&#39;, 66), (&#39;tvchannel&#39;, 71), (&#39;poetry&#39;, 102), (&#39;telephone&#39;, 63), (&#39;stock&#39;, 71), (&#39;radio&#39;, 24), (&#39;contacts&#39;, 30), (&#39;lottery&#39;, 24), (&#39;website&#39;, 54), (&#39;video&#39;, 182), (&#39;news&#39;, 58), (&#39;bus&#39;, 24), (&#39;app&#39;, 53), (&#39;flight&#39;, 62), (&#39;epg&#39;, 107), (&#39;message&#39;, 63), (&#39;match&#39;, 24), (&#39;schedule&#39;, 29), (&#39;novel&#39;, 24), (&#39;riddle&#39;, 34), (&#39;email&#39;, 24), (&#39;datetime&#39;, 18), (&#39;cinemas&#39;, 24)]) 1y_train = label_tokenizer.texts_to_sequences(train_data_df['label']) 1y_train[:10] [[10], [9], [2], [17], [1], [2], [9], [2], [8], [23]] 1y_train = [[y[0]-1] for y in y_train] 1y_train[:10] [[9], [8], [1], [16], [0], [1], [8], [1], [7], [22]] 12y_train = to_categorical(y_train, label_numbers)y_train.shape (2299, 31) 1234y_test = label_tokenizer.texts_to_sequences(test_data_df['label'])y_test = [y[0]-1 for y in y_test]y_test = to_categorical(y_test, label_numbers)y_test.shape (770, 31) 1y_test[0] array([0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32) 设计模型12345678910111213def create_SMP2018_lstm_model(max_features, max_cut_query_lenth, label_numbers): model = Sequential() model.add(Embedding(input_dim=max_features+1, output_dim=32, input_length=max_cut_query_lenth)) model.add(LSTM(units=64, dropout=0.2, recurrent_dropout=0.2)) model.add(Dense(label_numbers, activation='softmax')) # try using different optimizers and different optimizer configs model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=[f1]) plot_model(model, to_file='SMP2018_lstm_model.png', show_shapes=True) return model 训练模型123456789if 'max_features' not in dir(): max_features = 2888 print('not find max_features variable, use default max_features values:\t&#123;&#125;'.format(max_features))if 'max_cut_query_lenth' not in dir(): max_cut_query_lenth = 26 print('not find max_cut_query_lenth, use default max_features values:\t&#123;&#125;'.format(max_cut_query_lenth))if 'label_numbers' not in dir(): label_numbers = 31 print('not find label_numbers, use default max_features values:\t&#123;&#125;'.format(label_numbers)) 1model = create_SMP2018_lstm_model(max_features, max_cut_query_lenth, label_numbers) 12batch_size = 20epochs = 30 1print(x_train.shape, y_train.shape) (2299, 26) (2299, 31) 1print(x_test.shape, y_test.shape) (770, 26) (770, 31) 1234print('Train...')model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs) Train... Epoch 1/30 2299/2299 [==============================] - 16s 7ms/step - loss: 3.0916 - f1: 0.0000e+00 Epoch 2/30 2299/2299 [==============================] - 14s 6ms/step - loss: 2.6594 - f1: 0.1409 Epoch 3/30 2299/2299 [==============================] - 13s 6ms/step - loss: 2.0817 - f1: 0.4055 Epoch 4/30 2299/2299 [==============================] - 14s 6ms/step - loss: 1.6032 - f1: 0.4689 Epoch 5/30 2299/2299 [==============================] - 14s 6ms/step - loss: 1.1318 - f1: 0.6176 Epoch 6/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.8090 - f1: 0.7399 Epoch 7/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.5704 - f1: 0.8298 Epoch 8/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.4051 - f1: 0.8879 Epoch 9/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.3002 - f1: 0.9280 Epoch 10/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.2317 - f1: 0.9467 Epoch 11/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.1755 - f1: 0.9678 Epoch 12/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.1391 - f1: 0.9758 Epoch 13/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.1131 - f1: 0.9800 Epoch 14/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0883 - f1: 0.9861 Epoch 15/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0725 - f1: 0.9894 Epoch 16/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0615 - f1: 0.9929 Epoch 17/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0507 - f1: 0.9945 Epoch 18/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0455 - f1: 0.9963 Epoch 19/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0398 - f1: 0.9960 Epoch 20/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0313 - f1: 0.9978 Epoch 21/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0266 - f1: 0.9984 Epoch 22/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0279 - f1: 0.9965 Epoch 23/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0250 - f1: 0.9976 Epoch 24/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0219 - f1: 0.9982 Epoch 25/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0195 - f1: 0.9982 Epoch 26/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0179 - f1: 0.9989 Epoch 27/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0177 - f1: 0.9974 Epoch 28/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0139 - f1: 0.9987 Epoch 29/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0139 - f1: 0.9989 Epoch 30/30 2299/2299 [==============================] - 14s 6ms/step - loss: 0.0129 - f1: 0.9987 &lt;keras.callbacks.History at 0x7f84e87c5f28&gt; 评估模型12345score = model.evaluate(x_test, y_test, batch_size=batch_size, verbose=1)print('Test score:', score[0])print('Test f1:', score[1]) 770/770 [==============================] - 1s 1ms/step Test score: 0.6803552009068526 Test f1: 0.8464262740952628 1y_hat_test = model.predict(x_test) 1print(y_hat_test.shape) (770, 31) 将 one-hot 张量转换成对应的整数1y_pred = np.argmax(y_hat_test, axis=1).tolist() 1y_true = np.argmax(y_test, axis=1).tolist() 查看多分类的 准确率、召回率、F1 值1print(classification_report(y_true, y_pred)) precision recall f1-score support 0 0.78 0.93 0.85 154 1 0.92 0.97 0.95 89 2 0.67 0.62 0.64 60 3 0.83 0.83 0.83 36 4 0.79 1.00 0.88 34 5 0.83 0.65 0.73 23 6 1.00 0.83 0.91 24 7 1.00 1.00 1.00 24 8 0.68 0.65 0.67 23 9 0.90 0.86 0.88 22 10 0.85 0.50 0.63 22 11 0.88 1.00 0.93 21 12 1.00 0.90 0.95 21 13 0.91 0.95 0.93 21 14 1.00 0.95 0.98 21 15 0.79 0.95 0.86 20 16 0.90 0.47 0.62 19 17 0.79 0.61 0.69 18 18 0.63 0.67 0.65 18 19 0.90 0.82 0.86 11 20 1.00 0.70 0.82 10 21 1.00 0.67 0.80 9 22 1.00 0.88 0.93 8 23 1.00 0.62 0.77 8 24 1.00 1.00 1.00 8 25 1.00 0.88 0.93 8 26 0.88 0.88 0.88 8 27 0.86 0.75 0.80 8 28 1.00 1.00 1.00 8 29 0.75 0.75 0.75 8 30 0.75 1.00 0.86 6 micro avg 0.84 0.84 0.84 770 macro avg 0.88 0.82 0.84 770 weighted avg 0.85 0.84 0.84 770]]></content>
      <categories>
        <category>实验</category>
      </categories>
      <tags>
        <tag>文本分类</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Bag of Tricks for Efficient Text Classification]]></title>
    <url>%2F2018%2F10%2F10%2Ffasttext%2F</url>
    <content type="text"><![CDATA[N-gram features词袋模型不考虑词序的问题，若将词序信息添加进去又会造成过高的计算代价。文章取而代之使用bag of n-gram来将词序信息引入：比如 我来到颐和园参观，相应的bigram特征为：我来 来到 到颐 颐和 和园 园参 参观相应的trigram特征为：我来到 来到颐 到颐和 颐和园 和园参 园参观并使用哈希算法高效的存储n-gram信息。 标题 说明 附加 Bag of Tricks for Efficient Text Classification 原始论文 201607 脸书论文翻译《Bag of Tricks for Efficient Text Classification》 论文翻译 201707 Paper Reading Bag of Tricks for Efficient Text Classification 论文理解 20160710 论文引介 Bag of Tricks for Efficient Text Classification 论文 201607 如何评价Word2Vec作者提出的fastText算法？深度学习是否在文本分类等简单任务上没有优势？ 论文浅析和评价 fastText，智慧与美貌并重的文本分类及向量化工具 模型解析 20190901 总结一下：对简单的任务来说，用简单的网络结构进行处理基本就够了，但是对比较复杂的任务，还是依然需要更复杂的网络结构来学习sentence representation的。另外，fastText文中还提到的两个tricks分别是： hierarchical softmax类别数较多时，通过构建一个霍夫曼编码树来加速softmax layer的计算，和之前word2vec中的trick相同 N-gram features只用unigram的话会丢掉word order信息，所以通过加入N-gram features进行补充；用hashing来减少N-gram的存储。 Bag of Tricks for Efficient Text Classification Armand Joulin, Edouard Grave, Piotr Bojanowski, Tomas Mikolov(Submitted on 6 Jul 2016 (v1), last revised 9 Aug 2016 (this version, v3))This paper explores a simple and efficient baseline for text classification. Our experiments show that our fast text classifier fastText is often on par with deep learning classifiers in terms of accuracy, and many orders of magnitude faster for training and evaluation. We can train fastText on more than one billion words in less than ten minutes using a standard multicore~CPU, and classify half a million sentences among~312K classes in less than a minute. 本文探讨了一种简单有效的文本分类基线。我们的实验表明，我们的快速文本分类器 fastText在准确性方面通常与深度学习分类器相当，并且在训练和评估方面更快几个数量级。我们可以 使用标准的多核CPU在不到10分钟的时间内对超过10亿个单词进行fastText训练 ，并在不到一分钟的时间内对312K类中的50万个句子进行分类。 Subjects: Computation and Language (cs.CL)Cite as: arXiv:1607.01759 [cs.CL] (or arXiv:1607.01759v3 [cs.CL] for this version) 学习该论文的写作方法论文目录 论文内容 imdb_fasttext 与不使用 N-gram features 相比红色线是不使用 N-gram features，绿色线是使用，显然使用 N-gram features 有效果]]></content>
      <categories>
        <category>论文</category>
        <category>文本分类</category>
      </categories>
      <tags>
        <tag>fasttext</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[MarkDown问题]]></title>
    <url>%2F2018%2F10%2F08%2FMarkDown%E9%97%AE%E9%A2%98%2F</url>
    <content type="text"><![CDATA[Hexo 公式渲染z^l_j=\sum_k w^l_{jk} a^{l-1}_k+b^l_j 标题 内容 时间 如何在 hexo 中支持 Mathjax？ 20171129 Hexo博客next主题数学公式渲染问题 20180515 hexo 图片 标题 内容 时间 hexo博客图片问题 20160513]]></content>
      <tags>
        <tag>MarkDown</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[条件随机场 CRF]]></title>
    <url>%2F2018%2F10%2F04%2F%E6%9D%A1%E4%BB%B6%E9%9A%8F%E6%9C%BA%E5%9C%BA%2F</url>
    <content type="text"><![CDATA[标题 说明 附加 如何轻松愉快地理解条件随机场（CRF）？ milter 浅析 2017 如何用简单易懂的例子解释条件随机场（CRF）模型？它和HMM有什么区别？ Scofield 详解 2018 zh-NER-keras 基于keras的BiLstm与CRF实现命名实体标注this project is a sample for Chinese Named Entity Recognition(NER) by Keras 2.1.4 2018 【中文分词】条件随机场CRF 科普 CRF逐标签Softmax 条件随机场逐标签softmax是一种简单有效的方法，但有时候会出现不合理的结果。比如我们用sbme来做4标签分词时，逐标签softmax无法排除出现bbbb这样的序列的可能性，但这个序列是违反了我们的解码规则（b后面只能接m或e）。 因此，有人说逐标签softmax不需要动态规划，那是不对的，这种情况下，我们至少需要一个“非0即1”的转移矩阵，直接把不合理的转移概率设为0（如p(b|b) =0，然后通过动态规划保证得到合理的序列。 线性链CRF bilsm_crf_model.py123456789101112131415161718192021222324252627from keras.models import Sequentialfrom keras.layers import Embedding, Bidirectional, LSTMfrom keras_contrib.layers import CRFimport process_dataimport pickleEMBED_DIM = 200BiRNN_UNITS = 200def create_model(train=True): if train: (train_x, train_y), (test_x, test_y), (vocab, chunk_tags) = process_data.load_data() else: with open('model/config.pkl', 'rb') as inp: (vocab, chunk_tags) = pickle.load(inp) model = Sequential() model.add(Embedding(len(vocab), EMBED_DIM, mask_zero=True)) # Random embedding model.add(Bidirectional(LSTM(BiRNN_UNITS // 2, return_sequences=True))) crf = CRF(len(chunk_tags), sparse_target=True) model.add(crf) model.summary() model.compile('adam', loss=crf.loss_function, metrics=[crf.accuracy]) if train: return model, (train_x, train_y), (test_x, test_y) else: return model, (vocab, chunk_tags) 使用条件随机场 CRF 完成命名实体识别 NER]]></content>
      <categories>
        <category>机器学习</category>
      </categories>
      <tags>
        <tag>CRF</tag>
        <tag>条件随机场</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Auto-Encoding Variational Bayes]]></title>
    <url>%2F2018%2F09%2F30%2FAuto-Encoding%20Variational%20Bayes%2F</url>
    <content type="text"><![CDATA[标题 说明 附加 Auto-Encoding Variational Bayes 原始论文 2013 Introduction to variational autoencoders 论文精要解读 备用链接 变分自编码器（Variational Auto-Encoder，VAE） 论文详解 Auto-Encoding Variational BayesDiederik P Kingma, Max Welling(Submitted on 20 Dec 2013 (v1), last revised 1 May 2014 (this version, v10)) How can we perform efficient inference and learning in directed probabilistic models, in the presence of continuous latent variables with intractable posterior distributions, and large datasets? We introduce a stochastic variational inference and learning algorithm that scales to large datasets and, under some mild differentiability conditions, even works in the intractable case. Our contributions is two-fold. First, we show that a reparameterization of the variational lower bound yields a lower bound estimator that can be straightforwardly optimized using standard stochastic gradient methods. Second, we show that for i.i.d. datasets with continuous latent variables per datapoint, posterior inference can be made especially efficient by fitting an approximate inference model (also called a recognition model) to the intractable posterior using the proposed lower bound estimator. Theoretical advantages are reflected in experimental results. Subjects: Machine Learning (stat.ML); Machine Learning (cs.LG)Cite as: arXiv:1312.6114 [stat.ML] (or arXiv:1312.6114v10 [stat.ML] for this version)]]></content>
      <categories>
        <category>深度学习</category>
        <category>变分自编码器</category>
      </categories>
      <tags>
        <tag>VAE</tag>
        <tag>变分自编码器</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Self-Normalizing Neural Networks selu]]></title>
    <url>%2F2018%2F09%2F30%2FSELU%2F</url>
    <content type="text"><![CDATA[论文核心代码，TensorFlow 实现12345def selu(x): with ops.name_scope('elu') as scope: alpha = 1.6732632423543772848170429916717 scale = 1.0507009873554804934193349852946 return scale*tf.where(x&gt;0.0,x,alpha*tf.nn.elu(x)) 标题 说明 附加 《Self-Normalizing Neural Networks》 原始论文 2017 引爆机器学习圈：「自归一化神经网络」提出新型激活函数SELU 翻译 2017 【文献阅读】Self-Normalizing Neural Networks CSDN TensorSense 2017 如何评价 Self-Normalizing Neural Networks 这篇论文? 知乎评价 Compare SELUs (scaled exponential linear units) with other activations on MNIST, CIFAR10, etc. SELU 在不同数据集实验 2017 Self-Normalizing Neural NetworksGünter Klambauer, Thomas Unterthiner, Andreas Mayr, Sepp Hochreiter(Submitted on 8 Jun 2017 (v1), last revised 7 Sep 2017 (this version, v5)) Deep Learning has revolutionized vision via convolutional neural networks (CNNs) and natural language processing via recurrent neural networks (RNNs). However, success stories of Deep Learning with standard feed-forward neural networks (FNNs) are rare. FNNs that perform well are typically shallow and, therefore cannot exploit many levels of abstract representations. We introduce self-normalizing neural networks (SNNs) to enable high-level abstract representations. While batch normalization requires explicit normalization, neuron activations of SNNs automatically converge towards zero mean and unit variance. The activation function of SNNs are “scaled exponential linear units” (SELUs), which induce self-normalizing properties. Using the Banach fixed-point theorem, we prove that activations close to zero mean and unit variance that are propagated through many network layers will converge towards zero mean and unit variance — even under the presence of noise and perturbations. This convergence property of SNNs allows to (1) train deep networks with many layers, (2) employ strong regularization, and (3) to make learning highly robust. Furthermore, for activations not close to unit variance, we prove an upper and lower bound on the variance, thus, vanishing and exploding gradients are impossible. We compared SNNs on (a) 121 tasks from the UCI machine learning repository, on (b) drug discovery benchmarks, and on (c) astronomy tasks with standard FNNs and other machine learning methods such as random forests and support vector machines. SNNs significantly outperformed all competing FNN methods at 121 UCI tasks, outperformed all competing methods at the Tox21 dataset, and set a new record at an astronomy data set. The winning SNN architectures are often very deep. Implementations are available at: github.com/bioinf-jku/SNNs. 深度学习不仅通过卷积神经网络（CNN）变革了计算机视觉，同时还通过循环神经网络（RNN）变革了自然语言处理。然而，带有标准前馈神经网络（FNN）的深度学习很少有成功的案例。通常表现良好的 FNN 都只是浅层模型，因此不能挖掘多层的抽象表征。所以我们希望引入自归一化神经网络（self-normalizing neural networks/SNNs）以帮助挖掘高层次的抽象表征。虽然批归一化要求精确的归一化，但 SNN 的神经元激励值可以自动地收敛到零均值和单位方差。SNN 的激活函数即称之为「可缩放指数型线性单元（scaled exponential linear units/SELUs）」，该单元引入了自归一化的属性。使用 Banach 的不动点定理（fixed-point theorem），我们证明了激励值逼近于零均值和单位方差并且通过许多层的前向传播还是将收敛到零均值和单位方差，即使是存在噪声和扰动的情况下也是这样。这种 SNN 收敛属性就允许 (1) 训练许多层的深度神经网络，同时 (2) 采用强正则化、(3) 令学习更具鲁棒性。此外，对于不逼近单位方差的激励值，我们证明了其方差存在上确界和下确界，因此梯度消失和梯度爆炸是不可能出现的。同时我们采取了 (a) 来自 UCI 机器学习库的 121 个任务，并比较了其在 (b) 新药发现基准和 (c) 天文学任务上采用标准 FNN 和其他机器学习方法（如随机森林、支持向量机等）的性能。SNN 在 121 个 UCI 任务上显著地优于所有竞争的 FNN 方法，并在 Tox21 数据集上超过了所有的竞争方法，同时 SNN 还在天文数据集上达到了新纪录。该实现的 SNN 架构通常比较深，实现可以在以下链接获得：http://github.com/bioinf-jku/SNNs。 Comments: 9 pages (+ 93 pages appendix)Subjects: Machine Learning (cs.LG); Machine Learning (stat.ML)Journal reference: Advances in Neural Information Processing Systems 30 (NIPS 2017)Cite as: arXiv:1706.02515 [cs.LG] (or arXiv:1706.02515v5 [cs.LG] for this version) 实验结论我们提出了自归一化神经网络，并且已经证明了当神经元激励在网络中传播时是在朝零均值（zero mean）和单位方差（unit variance）的趋势发展的。而且，对于没有接近单位方差的激励，我们也证明了方差映射的上线和下限。于是 SNN 不会产梯度消失和梯度爆炸的问题。因此，SNN 非常适用于多层的结构，这使我们可以引入一个全新的正则化（regularization）机制，从而更稳健地进行学习。在 121UCI 基准数据集中，SNN 已经超过了其他一些包括或不包括归一化方法的 FNN，比如批归一化（batch）、层级归一化（layer）、权值归一化（weight normalization）或其它特殊结构（Highway network 或 Residual network）。SNN 也在药物研发和天文学任务中产生了完美的结果。和其他的 FNN 网络相比，高性能的 SNN 结构通常深度更深。 基于 SELUs 的模型的论文Models and architectures built on Self-Normalizing Networks 实验验证 SELU 的真实效果MNIST-MLP-SELU VS MNIST-MLP-RELU模型结构MNIST_Conv_SELU MNIST_Conv_RELU 实验结果蓝色的线代表 SELU ，橙色的线代表 RELU。 结果分析在 MNIST 数据集，多层前馈神经网络模型条件下，SELU 在训练集的效果差于 RELU，但是 SELU 在验证集效果与 RELU 几乎一致，且 SELU 训练时间更长。 MNIST-Conv-SELU VS MNIST-Conv-RELU模型结构MNIST_Conv_SELU MNIST_Conv_RELU 实验结果蓝色的线代表 SELU ，橙色的线代表 RELU 结果分析在 MNIST 数据集，多层卷积神经网络模型条件下，SELU 在训练集的效果优于 RELU，但是 SELU 在验证集效果差于 RELU ，且 SELU 训练时间更长。 CIFAR10_Conv_SELU VS CIFAR10_Conv_RELU模型结构CIFAR10_Conv_SELU CIFAR10_Conv_RELU 实验结果灰色线代表 SELU，绿色线代表 RELU。 结果分析在 CIFAR10 数据集，多层卷积神经网络模型条件下，SELU 在训练集的效果优于 RELU，但是 SELU 在验证集效果与 RELU 一致，且 RELU 更不易发生过拟合，SELU 训练时间更长。 reuters_mlp_relu_vs_selu模型结构reuters_mlp_selu reuters_mlp_relu 实验结果灰色的线代表 SELU，绿色的线代表 RELU。 结果分析在 reuters 数据集，多层前馈神经网络模型条件下，SELU 在训练集的效果差于 RELU，但是 SELU 在验证集效果稍稍优于 RELU ，但 SELU 训练时间更长。 本文结论SELU 只有在特殊限定的数据集和网络模型结构的条件下会优于 RELU，一般情况下 RELU 训练速度更快，且更不容易发生过拟合。所以根据现有证据，SELU 比 RELU 没有显著优势，一般情况下选择 RELU 更优。]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>正则化</tag>
        <tag>Self-Normalizing</tag>
        <tag>缩放指数型线性单元</tag>
        <tag>selu</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Conditional Image Synthesis with Auxiliary Classifier GANs]]></title>
    <url>%2F2018%2F09%2F27%2FACGAN%2F</url>
    <content type="text"><![CDATA[标题 说明 附加 《Conditional Image Synthesis with Auxiliary Classifier GANs》 原始论文 2016 《Conditional Image Synthesis with Auxiliary Classifier GANs》阅读笔记 summer 2017 Conditional Image Synthesis With Auxiliary Classifier GANs 马小李 论文解读 2018 Auxiliary Classifier Generative Adversarial Networks in Keras 论文实现 2016 Conditional Image Synthesis with Auxiliary Classifier GANsConditional Image Synthesis With Auxiliary Classifier GANsAugustus Odena, Christopher Olah, Jonathon Shlens(Submitted on 30 Oct 2016 (v1), last revised 20 Jul 2017 (this version, v4)) Synthesizing high resolution photorealistic images has been a long-standing challenge in machine learning. In this paper we introduce new methods for the improved training of generative adversarial networks (GANs) for image synthesis. We construct a variant of GANs employing label conditioning that results in 128x128 resolution image samples exhibiting global coherence. We expand on previous work for image quality assessment to provide two new analyses for assessing the discriminability and diversity of samples from class-conditional image synthesis models. These analyses demonstrate that high resolution samples provide class information not present in low resolution samples. Across 1000 ImageNet classes, 128x128 samples are more than twice as discriminable as artificially resized 32x32 samples. In addition, 84.7% of the classes have samples exhibiting diversity comparable to real ImageNet data. 合成高分辨率照片级真实感图像一直是机器学习中的长期挑战。 在本文中，我们介绍了用于图像合成的改进生成对抗网络（GAN）训练的新方法。 我们构建了采用标签调节的GAN变体，其产生128x128分辨率的图像样本，表现出全局一致性。 我们扩展了以前的图像质量评估工作，为评估类条件图像合成模型中样本的可辨性和多样性提供了两个新的分析。 这些分析表明，高分辨率样品提供了低分辨率样品中不存在的类信息。 在1000个ImageNet类中，128x128样本的差异是人工调整大小的32x32样本的两倍多。 此外，84.7％的类别的样本具有与真实ImageNet数据相当的多样性。 Subjects: Machine Learning (stat.ML); Computer Vision and Pattern Recognition (cs.CV)Cite as: arXiv:1610.09585 [stat.ML] (or arXiv:1610.09585v4 [stat.ML] for this version) 以下内容参考谷歌翻译 摘要在本文中，我们介绍了用于图像合成的改进生成对抗网络（GAN）训练的新方法。我们构建了采用标签调节的GAN变体，其产生了展示全局一致性的 128 × 128 分辨率图像样本。我们扩展了以前的图像质量评估工作，为评估类条件图像合成模型中样本的可辨性和多样性提供了两个新的分析。这些分析表明，高分辨率样品提供了低分辨率样品中不存在的类信息。在1000个ImageNet类中，128 × 128 个样本比人工调整大小的 32 × 32 可辨别两倍多样本。此外，84.7％的类别的样本具有与真实ImageNet数据相当的多样性。 介绍表征自然图像的结构是一项丰富的研究工作。 自然图像遵循内在的不变性，并展示历史上难以量化的多尺度统计结构（Simoncelli＆Olshausen， 2001 ）。 机器学习的最新进展提供了显着改善图像模型质量的机会。 改进的图像模型推进了图像去噪（Ballé等， 2015 ） ，压缩（Toderici等， 2016 ） ，绘画（van den Oord等， 2016a ）和超级图像去噪方面的最新技术。 - 分辨率（Ledig等， 2016 ） 。 更好的自然图像模型也提高了半监督学习任务的性能（Kingma等， 2014 ; Springenberg， 2015 ; Odena， 2016 ; Salimans等， 2016 ）和强化学习问题（Blundell等， 2016 ） 。 理解自然图像统计的一种方法是构建从头合成图像的系统。 有几种有前景的方法可用于构建图像合成模型。 变分自动编码器（VAE）最大化训练数据对数似然的变化下界（Kingma＆Welling， 2013 ; Rezende等， 2014 ） 。 VAE很容易训练，但引入了关于近似后验分布的潜在限制性假设（但参见（Rezende＆Mohamed， 2015 ; Kingma等， 2016 ） ）。 自回归模型省去了潜在变量并直接模拟了像素上的条件分布（van den Oord et al。， 2016a ， b ） 。 这些模型产生令人信服的样品，但样品成本高，并且不提供潜在的表示。 可逆密度估计器使用一系列限制为可逆的参数化函数直接转换潜在变量（Dinh等， 2016 ） 。 该技术允许精确的对数似然计算和精确推理，但是可逆性约束是限制性的。 生成性对抗网络（GAN）提供了一种独特且有前景的方法，侧重于用于训练图像合成模型的游戏理论公式（Goodfellow等， 2014 ） 。 最近的研究表明，GAN可以在具有低可变性和低分辨率的数据集上生成令人信服的图像样本（Denton等， 2015 ; Radford等， 2015 ） 。 然而，GAN努力生成全局一致的高分辨率样本 - 特别是来自具有高可变性的数据集。 此外，对GAN的理论理解是一个持续的研究课题（Uehara等， 2016 ; Mohamed和Lakshminarayanan， 2016 ） 。 图1：来自在ImageNet数据集上训练的AC-GAN的5个等级的 128×128 分辨率样本。请注意，已选择显示的类以突出显示模型的成功，并且不具有代表性。 来自所有ImageNet类的样本将在本文后面链接。 在这项工作中，我们证明了向GAN潜在空间添加更多结构以及专门的成本函数可以获得更高质量的样本。 我们展示了来自ImageNet数据集各类的 128×128 像素样本（Russakovsky等， 2015 ） ，增强了全局一致性（图1 ）。 重要的是，我们定量地证明我们的高分辨率样品不仅仅是对低分辨率样品的天真抑制。 特别是，将 128×128 样本下采样到 32×32 会导致视觉可辨性降低50％。 我们还引入了一个新的度量标准，用于评估图像样本的可变性，并使用该度量标准来证明我们的合成图像显示出与大部分（84.7％）ImageNet类的训练数据相当的多样性。 更详细地说，这项工作是第一个： 以128x128空间分辨率（或任何空间分辨率 - 参见第3节）演示所有1000个ImageNet类的图像合成模型。 测量图像合成模型实际使用其输出分辨率的程度（第4.1节）。 使用快速，易于计算的度量来衡量GAN中的感知变异性和“崩溃”行为（第4.2节）。 需要注意的是，大量的类使GAN的ImageNet合成变得困难，并提供了明确的解决方案（第4.6节）。 通过实验证明，感性表现良好的GAN不是记忆少数例子的那些（第4.3节）。 在不使用任何技术（Salimans等， 2016 ） （第4.4节）的情况下，在CIFAR-10上进行训练时，在初始得分指标上实现最先进的技术水平 。 背景生成对抗网络（GAN）由两个彼此对立训练的神经网络组成。生成器 G 将随机噪声矢量 z 作为输入，并输出图像 $X_{fake}=G(z)$ 。鉴别器 D 接收来自发生器的训练图像或合成图像作为输入，并输出概率分布 $P(S|X)=D(X)$ 可能的图像源。训练鉴别器以最大化它分配给正确来源的对数似然性： L=E[logP(S=real|X_{real})]+E[logP(S=fake|X_{fake})]训练发生器以使等式1中的第二项最小化。 可以使用辅助信息来扩充基本GAN框架。一种策略是为生成器和鉴别器提供类标签，以生成类条件样本（Mirza＆Osindero，2014）。类条件合成可以显着提高生成样本的质量（van den Oord等，2016b）。更丰富的辅助信息（如图像标题和边界框定位）可以进一步提高样本质量（Reed等，2016a，b）。 不是将类别信息馈送到鉴别器，而是可以使鉴别器重建类别信息。这是通过修改鉴别器以包含辅助解码器网络来完成的1 输出训练数据的类别标签（Odena，2016 ; Salimans等，2016） 或生成样本的潜在变量的子集（Chen等，2016）。已知迫使模型执行附加任务以改善原始任务的性能（例如（Sutskever等人，2014 ; Szegedy等人，2014 ; Ramsundar等人，2016））。此外，辅助解码器可以利用预先训练的鉴别器（例如图像分类器）来进一步改善合成图像（Nguyen等，2016）。在这些考虑因素的推动下，我们引入了一种模型，该模型结合了利用类别信息的两种策略。也就是说，下面提出的模型是类条件的，但是具有辅助解码器，其负责重建类标签。 AC-GANs我们提出了GAN架构的变体，我们将其称为辅助分类器GAN（或AC-GAN）。在AC-GAN中，除了噪声z 之外，每个生成的样本都具有相应的类标签 $c \sim p_{c}$。鉴别器给出了源上的概率分布和类标签上的概率分布 $P(S|X), P(C|X)=D(X)$。目标函数有两个部分：正确源的对数似然，$L_s$ 和正确类的对数似然，$L_c$。 L_s = E[logP(S=real|X_{real})]+E[logP(S=fake|X_{fake})]L_c = E[logP(C=c|X_{real})]+E[logP(C=c|X_{fake})]训练 D 使 $L_s + L_c$ 最大化，同时训练 G 使 $L_c - L_s$ 最大化。AC-GAN学习 z 的表示，其独立于类标签（例如（Kingma等， 2014 ） ）。 在结构上，该模型与现有模型没有太大差别。 然而，对标准GAN配方的这种修改产生了优异的结果并且似乎稳定了训练。 此外，我们认为AC-GAN模型只是这项工作的技术贡献的一部分，以及我们提出的测量模型利用其给定输出分辨率的程度的方法，测量样品的感知变异性的方法。该模型，以及图像生成模型的全面实验分析，可从所有1000个ImageNet类中创建 128×128 个样本。 早期的实验证明，在固定模型的同时增加训练课程的数量会降低模型输出的质量。 AC-GAN 模型的结构允许按类别将大数据集分成子集，并为每个子集训练生成器和鉴别器。 所有ImageNet实验都是使用100个AC-GAN的集合进行的，每个AC-GAN都采用10级分割进行训练。 结果我们在ImageNet数据集上训练了几个AC-GAN模型（Russakovsky等， 2015 ） 。 从广义上讲，发生器 G 的结构是一系列“反卷积”层，它们将噪声 z 和类 c 转换为图像（Odena等， 2016 ） 。 我们训练两种模型架构的变体，用于生成 128×128 和 64×64 空间分辨率的图像。 鉴别器 D 是具有Leaky ReLU非线性的深度卷积神经网络（Maas等人， 2013 ） 。 如前所述，我们发现减少所有1000类ImageNet引入的可变性可显着提高培训质量。 我们培训了100个AC-GAN型号 - 每个型号只有10个类别 - 用于50000个100个小批量的批量生产。 由于概率标准的多样性（Theis等， 2015 ）以及缺乏感知上有意义的图像相似性度量，评估图像合成模型的质量具有挑战性。 尽管如此，在后面的部分中，我们尝试通过构建图像样本可辨性和多样性的若干临时措施来测量AC-GAN的质量。 我们希望这项工作可以提供可用于辅助图像合成模型的培训和后续开发的量化测量。 生成高分辨率图像可提高可辨别性图2：生成高分辨率图像可提高可辨性。 上图：来自斑马类的训练数据和合成图像调整为较低的空间分辨率（如上所示），然后人工调整大小为原始分辨率（红线和黑线为 128×128 ;蓝线为 64×64 ）。 初始精度显示在相应图像下方。 左下：对于 64×64 和 128×128 模型的训练数据和图像样本，不同空间分辨率的精度总结。 误差棒测量10个图像子集的标准偏差。 虚线突出了模型输出空间分辨率的精度。 训练数据（剪裁）在分辨率分别为32,64,128和256时分别达到24％，54％，81％和81％的精度。 右下：比较 128×128 和 32×32 空间分辨率（分别为 x 和 y 轴）的精度分数。 每个点代表一个ImageNet类。 84.4％的班级低于平等线。 绿点对应斑马类。 我们还将 128×128 和 64×64 图像人工调整为 256×256 ，作为一种健全性检查，以证明简单地增加像素数量不会增加可辨别性。 构建类条件图像合成模型需要测量合成图像看起来属于预期类的程度。 特别是，我们想知道高分辨率样本不仅仅是对低分辨率样本进行天真的调整。 考虑一个简单的实验：假装存在一个合成 32x32 图像的模型。 通过执行双线性插值，可以平凡地增加合成图像的分辨率。 这将产生更高分辨率的图像，但是这些图像将仅是不可辨别的低分辨率图像的模糊版本。 因此，图像合成模型的目标不仅仅是产生高分辨率图像，而是产生比低分辨率图像更易辨别的高分辨率图像。 为了测量可辨性，我们将合成图像提供给预先训练的Inception网络（Szegedy等， 2015 ）并报告Inception网络为其分配正确标签的样本部分。 我们计算了一系列真实和合成图像的精度测量值，这些图像的空间分辨率通过双线性插值人为地降低（图2 ，上图）。 请注意，随着空间分辨率的降低，精度会降低 - 表明生成的图像包含较少的类信息（图2 ，顶部面板下方的分数）。 我们在所有1000个ImageNet类中总结了这一发现，包括ImageNet训练数据（黑色），图2中的 128×128 分辨率AC-GAN（红色）和 64x64分辨率AC-GAN（蓝色）（左下图）。 黑色曲线（剪裁）提供了真实图像可辨性的上限。 该分析的目的是表明合成更高分辨率的图像会导致可识别性增加。 128×128 模型的精度达到10.1％ ±2.0％，而7.0％±2.0％，样品尺寸调整为 64x64和5.0％ ±2.0％，样品尺寸调整为 32x32 。 换句话说，将AC-GAN的输出缩小到 32x32 和 64x64 分别将视觉辨别率降低50％和38％。 此外，84.4％的ImageNet类在 128×128 处具有比在 32x32 处更高的精度（图2 ，左下）。 我们对训练为 64x64空间分辨率的AC-GAN进行了相同的分析。 与 128×128 AC-GAN模型相比，该模型的可辨识性较差。 来自 64x64模型平台的精度在 64x64空间分辨率下与先前的结果一致。 最后， 64x64分辨率模型在64空间分辨率下比 128×128 模型具有更小的可辨识性。 据我们所知，这项工作是第一次尝试测量图像合成模型“利用其给定的输出分辨率”的程度，实际上是第一个完全考虑该问题的工作。 我们认为这是一个重要的贡献，与提出一个合成来自所有1000个ImageNet类的图像的模型相同。 我们注意到，所提出的方法可以应用于任何可以构建“样本质量”度量的图像合成模型。 事实上，这种方法（广泛定义）可以应用于任何类型的合成模型，只要有一个容易计算的样本质量概念和一些“降低分辨率”的方法。 特别是，我们希望可以对音频合成进行类似的处理。 测量生成图像的多样性如果图像合成模型仅输出一个图像，则它不是很有趣。实际上，众所周知的GAN故障模式是生成器将崩溃并输出单个原型，最大限度地愚弄鉴别器（Goodfellow等， 2014 ; Salimans等， 2016 ） 。 如果每个类只输出一个图像，则图像的类条件模型不是很有趣。 初始精度无法测量模型是否已折叠。 简单地记住每个ImageNet类中的一个示例的模型可以很好地通过该度量。 因此，我们寻求补充度量以明确地评估由AC-GAN生成的样本的类内感知多样性。 存在几种通过尝试预测人类感知相似性判断来定量评估图像相似性的方法。 其中最成功的是多尺度结构相似性（MS-SSIM） （Wang等， 2004b ; Ma等， 2016 ）。 MS-SSIM是一种充分表征的感知相似性度量的多尺度变体，其试图折扣对人类感知不重要的图像的方面（Wang等， 2004a ） 。 MS-SSIM值介于0.0和1.0之间; 较高的MS-SSIM值对应于感知上更相似的图像。 作为图像多样性的代理，我们测量给定类别中100个随机选择的图像对之间的MS-SSIM分数。 来自具有较高多样性的类别的样本导致较低的平均MS-SSIM分数（图3 ，左栏）; 来自具有较低多样性的类别的样本具有较高的平均MS-SSIM分数（图3 ，右栏）。 来自ImageNet训练数据的训练图像包含各类的各种平均MS-SSIM分数，表明ImageNet类中图像多样性的可变性（图4 ，x轴）。 注意，对于训练数据，最高平均MS-SSIM得分（表示最小可变性）是0.25。 我们计算AC-GAN模型生成的所有1000个ImageNet类的平均MS-SSIM得分。 我们在训练期间跟踪此值以确定生成器是否已折叠（图5 ，红色曲线）。 我们还使用该度量来在训练完成后将训练图像的多样性与来自GAN模型的样本进行比较。 图4绘制了按类别划分的图像样本和训练数据的平均MS-SSIM值。 蓝线是平等的线。 在1000个类中，我们发现847的平均样本MS-SSIM分数低于训练数据的最大MS-SSIM。 换句话说，84.7％的类具有超过ImageNet训练数据中的最小变量类的样本可变性。 有两个与MS-SSIM指标相关的点以及我们对它的使用值得特别注意。 第一点是我们“滥用”指标：它最初用于使用参考“原始图像”来测量图像压缩算法的质量。 我们改为在两个可能不相关的图像上使用它。 我们认为这是可以接受的，原因如下：第一：视觉检查似乎表明该指标是有意义的 - 具有较高MS-SSIM的配对似乎与具有较低MS-SSIM的配对更相似。 第二：我们将比较限制为使用相同类标签合成的图像。 这限制了MS-SSIM的使用，使其更类似于通常使用的情况（哪个图像作为参考并不重要）。 第三：对于我们的用例，度量标准不是“饱和的”。 如果大多数分数大约为0，那么我们会更关注MS-SSIM的适用性。 最后：培训数据通过该指标实现更多可变性（如预期的那样）这一事实证明该指标正在按预期工作。 第二点是MS-SSIM度量不是作为像素空间中发生器分布的熵的代理，而是作为输出的感知多样性的度量。 生成器输出分布的熵难以计算，成对的MS-SSIM分数不是一个好的代理。 即使它很容易计算，我们仍然认为对感知多样性进行单独测量仍然是有用的。 要了解原因，请考虑生成器熵对对比度的微小变化以及输出的语义内容的变化敏感。 在许多应用中，我们并不关心这种对熵的贡献，并且考虑试图忽略我们认为“在感知上毫无意义”的图像的变化的措施是有用的，因此使用MS-SSIM。 生成的图像既多样又可辨别我们已经提出了量化指标，证明AC-GAN样本可能是多样的和可辨别的，但我们尚未研究这些指标如何相互作用。 图6显示了所有类别的初始准确度和MS-SSIM分数的联合分布。 初始精度和MS-SSIM是反相关的。 相比之下，Inception-v3模型在所有1000个类别中平均达到78.8％的准确度（Szegedy等， 2015 ） 。 AC-GAN样品的一小部分达到这种精度水平。 这表明未来图像合成模型的机会。 这些结果表明，降低模式的GAN最有可能产生低质量的图像。 这与关于GAN的流行假设形成鲜明对比，GAN是以可变性为代价获得高样本质量的。 我们希望这些发现有助于进一步研究GAN与其他图像合成模型之间不同样本质量的原因。 图6：所有1000个ImageNet类的初始精度与MS-SSIM（$r^2=-0.16$）。 每个数据点代表一个类的样本的平均MS-SSIM值。 如图4所示，红线标记所有ImageNet类的最大MS-SSIM值（用于训练数据）。 来自AC-GAN模型的样本不会以可辨别性为代价实现可变性。 与先前结果的比较在对数似然性方面报告了在ImageNet上训练的图像合成模型的先前定量结果（van den Oord等， 2016a ， b ） 。 对数似然是一种粗略且可能不准确的样本质量测量（Theis等， 2015 ）。 相反，我们使用较低的空间分辨率（32x32）与CIFAR-10上先前的最新结果进行比较。 按照（Salimans等， 2016 ）中的程序 ，我们计算初始分数 3 对于分辨率为（32x32）的AC-GAN的50000个样本，随机分成10组。 我们还计算了25000个额外样本的初始分数，随机分成5组。 我们根据第一个分数选择最佳模型并报告第二个分数。 在27个超参数配置中执行网格搜索，与现有技术8.09 ± 0.07相比，我们能够获得8.25 ± 0.07的分数（Salimans等， 2016 ） 。 此外，我们在不采用该工作中引入的任何新技术（即虚拟批量标准化，小批量区分和标签平滑）的情况下实现了这一点。 这提供了额外的证据，即AC-GAN即使没有类别分裂的好处也是有效的。 参见图7 ，对AC-GAN样品和模型样品进行定性比较（Salimans等， 2016 ） 。 图7：从ImageNet数据集生成的样本。 （左）从模型中生成的样本（Salimans等， 2016 ） 。 （右）从AC-GAN生成的随机选择的样本。 AC-GAN样品在早期模型的样品中缺乏全局一致性。 搜索过度拟合的证据必须研究的一种可能性是AC-GAN在训练数据上过度拟合。 作为网络不记忆训练数据的第一次检查，我们在像素空间中通过L1距离测量的训练数据中识别图像样本的最近邻居（图8 ）。 来自训练数据的最近邻居不与相应的样本相似。 这提供了AC-GAN不仅仅是记忆训练数据的证据。 图8：最近邻分析。 （顶部）来自单个ImageNet类的样本。 （下）每个样本的训练数据中对应的最近邻居（L1距离）。 用于理解模型中过度拟合程度的更复杂方法是​​通过插值来探索该模型的潜在空间。 在过拟合模型中，可以观察到插值图像中的离散跃迁和潜在空间中与有意义的图像不对应的区域（Bengio等人， 2012 ; Radford等人， 2015 ; Dinh等人， 2016 ） 。 图9 （顶部）突出显示了几个图像样本之间潜在空间中的插值。 值得注意的是，发生器了解到某些尺寸组合对应于语义上有意义的特征（例如拱的大小，鸟喙的长度），并且在潜在空间中没有离散的过渡或“洞”。 探索AC-GAN潜在空间的第二种方法是利用模型的结构。 AC-GAN将其表示分解为类信息和类独立的潜在表示z。 采用z固定但是改变类标签对AC-GAN进行采样对应于在多个类中生成具有相同“风格”的样本（Kingma等， 2014 ） 。 图9 （底部）显示了8个鸟类的样本。 同一行的元素具有相同的z。 尽管每列的类都在变化，但全局结构的元素（例如位置，布局，背景）仍然保留，表明AC-GAN可以表示某些类型的“组合性”。 图9：（顶部）所选ImageNet类的潜在空间插值。 最左侧和右侧列显示三对图像样本 - 每对来自不同的类。 中间列突出显示这三对图像之间潜在空间中的线性插值。 （底部）与类无关的信息包含关于合成图像的全局结构。 每列是一个独特的鸟类，而每一行对应一个固定的潜在代码z。 测量类别分裂对图像样本质量的影响类条件图像合成提供了基于图像标签划分数据集的机会。 在我们的最终模型中，我们将1000个ImageNet类划分为100个AC-GAN模型。 在本节中，我们将描述实验，这些实验强调了减少用于训练AC-GAN的类别的多样性的好处。 我们采用了标签的排序，并将其分为10个连续的组。这个排序可以在下面的部分中看到，我们在这里显示来自所有1000个类的样本。 分裂绩效讨论的两个方面：每个分裂的类数和分裂内多样性。我们发现在更多类别上训练固定模型会损害模型生成引人注目的样本的能力（图10 ）。通过为模型提供更多参数，可以提高较大分割的性能。但是，使用小分割不足以实现良好的性能。我们无法训练GAN （Goodfellow et al。，2014），即使对于1的分割大小也能可靠地收敛。这就提出了一个问题，即在不同的类别上训练模型是否比在类似的集合上训练更容易课程：我们无法找到确凿的证据表明分组中的课程选择会显着影响样本质量。 图10：针对训练期间使用的ImageNet类的数量绘制的10个ImageNet类的平均成对MS-SSIM值。我们使用10到100之间的值来修复除训练课程数量之外的所有内容。我们仅报告前10个课程的MS-SSIM值以保持分数可比。随着班级计数的增加，MS-SSIM迅速超过0.25（红线）。使用每个模型的相同数量的训练步骤，使用每个类计数9个随机重启来计算这些分数。由于我们观察到生成器不能从崩溃阶段恢复，因此在这种情况下使用固定数量的训练步骤似乎是合理的。 我们没有关于是什么原因导致这种对班级计数的敏感性的假设，这种假设在实验上得到了很好的支持。我们只能注意到，由于类计数增加时发生的故障情况是“生成器崩溃”，似乎有理由解决“生成器崩溃”的一般方法也可以解决这种敏感问题。 来自所有1000个ImageNet类的样本我们还从这里托管的1000个ImageNet类中的每一个中生成10个样本。据我们所知，没有其他图像合成工作包括类似的分析。 讨论这项工作引入了AC-GAN架构，并证明了AC-GAN可以生成全局一致的ImageNet样本。我们为图像可辨性提供了一种新的定量度量，作为空间分辨率的函数。使用此度量标准，我们证明了我们的样本比生成较低分辨率图像并执行简单调整大小操作的模型更具可辨识性。我们还分析了样本在训练数据方面的多样性，并提供了一些证据，证明大多数类别的图像样本在多样性方面与ImageNet数据具有可比性。 在这项工作的基础上存在几个方向。需要做很多工作来改善 128x128 分辨率模型的视觉可辨性。虽然一些合成图像类别具有较高的初始精度，但模型的平均初始精度（10.1 ％± 2.0 ％）仍远低于实际训练数据的81％。解决这个问题的一个直接机会是用预训练模型增强鉴别器以执行额外的监督任务（例如图像分割，（Ronneberger等，2015））。 提高GAN培训的可靠性是一个持续的研究课题。只有84.7％的ImageNet类表现出与真实训练数据相当的多样性。通过在100个AC-GAN模型中划分1000个ImageNet类，极大地帮助了训练稳定性。构建可以从所有1000个类生成样本的单个模型将是向前迈出的重要一步。 图像合成模型为执行半监督学习提供了独特的机会：这些模型构建了丰富的先前自然图像统计数据，可以通过分类器来利用这些统计数据来改进对少数标签存在的数据集的预测。当标签对于给定的训练图像不可用时，AC-GAN模型可以通过忽略由类标签引起的损失的分量来执行半监督学习。有趣的是，先前的工作表明，实现良好的样本质量可能与半监督学习的成功无关（Salimans等，2016）。]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>GAN</tag>
        <tag>ACGAN</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Sequence to Sequence Learning with Neural Networks]]></title>
    <url>%2F2018%2F09%2F25%2FSequence%20to%20Sequence%20Learning%20with%20Neural%20Networks%2F</url>
    <content type="text"><![CDATA[这是由谷歌的三位大神用seq2seq模型实现的基于神经网络的机器翻译（英法互译），基本的方法还是encoder-decoder,作为seq2seq的经典必读论文，本文与其他工作相比主要有创新点有： 利用了多层的LSTM（本文中是4层）。实验表明使用LSTM对长句子的翻译来说效果很好，主要是因为LSTM本身具有长期依赖的优势。 与attention不一样，它又回归到原始模型，在编码端将输入句子编码成一个固定的维度的向量。作者说这样可以迫使模型学习捕捉句子的意思，尽管句子的表达方式不同。 最重要的一点是，实验发现将句子逆序输入可以明显改善LSTM模型的表现。 一个猜测的解释（因为作者也不知道具体的原因）是这样做可以减小“minimal time lag”（最短时间间隔），举例，输入是“ABC”，对应输出是“XYZ”，“A”与对应的“X”的间隔是3，“B”和“C”与其对应的间隔也是3，所以最短时间间隔是3。如果将输入逆序，以“CAB”作为输入，“A”与“X”的间隔是1，最短时间间隔就减小为1。于是作者猜测将输入逆序虽然没有减少源句子（输入）与目标句子（输出）的平均间隔，但是源句子与目标句子是前几个词的距离减少了，于是句子的“最短时间间隔”减少了。通过后向传播可以更快地在源句子和目标句子之间“建立通信”，整体的性能也有了显着的改善。 标题 说明 附加 《Sequence to Sequence Learning with Neural Networks》 原始论文 2014 Sequence to Sequence Learning with Neural Networks mstar1992 论文解读 2017]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>seq2seq</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Why Self-Attention? A Targeted Evaluation of Neural Machine Translation Architectures]]></title>
    <url>%2F2018%2F09%2F21%2FSelf-Attention%20A%20Targeted%20Evaluation%20of%20Neural%20Machine%20Translation%20Architectures%2F</url>
    <content type="text"><![CDATA[标题 说明 附加 《Why Self-Attention? A Targeted Evaluation of Neural Machine Translation Architectures》 原始论文 2018 为什么使用自注意力机制？ 机器之心 浅析 Why Self-Attention? A Targeted Evaluation of Neural Machine Translation ArchitecturesGongbo Tang, Mathias Müller, Annette Rios, Rico Sennrich(Submitted on 27 Aug 2018 (v1), last revised 28 Aug 2018 (this version, v2)) Recently, non-recurrent architectures (convolutional, self-attentional) have outperformed RNNs in neural machine translation. CNNs and self-attentional networks can connect distant words via shorter network paths than RNNs, and it has been speculated that this improves their ability to model long-range dependencies. However, this theoretical argument has not been tested empirically, nor have alternative explanations for their strong performance been explored in-depth. We hypothesize that the strong performance of CNNs and self-attentional networks could also be due to their ability to extract semantic features from the source text, and we evaluate RNNs, CNNs and self-attention networks on two tasks: subject-verb agreement (where capturing long-range dependencies is required) and word sense disambiguation (where semantic feature extraction is required). Our experimental results show that: 1) self-attentional networks and CNNs do not outperform RNNs in modeling subject-verb agreement over long distances; 2) self-attentional networks perform distinctly better than RNNs and CNNs on word sense disambiguation. 近期，非循环架构（卷积、自注意力）在神经机器翻译任务中的表现优于 RNN。CNN 和自注意力网络连接远距离单词的路径比 RNN 短，有研究人员推测这正是其建模长距离依赖能力得到提高的原因。但是，这一理论论断并未得到实验验证，对这两种网络的强大性能也没有其他深入的解释。我们假设 CNN 和自注意力网络的强大性能也可能来自于其从源文本提取语义特征的能力。我们在两个任务（主谓一致任务和词义消歧任务）上评估了 RNN、CNN 和自注意力网络的性能。实验结果证明：1）自注意力网络和 CNN 在建模长距离主谓一致时性能并不优于 RNN；2）自注意力网络在词义消歧方面显著优于 RNN 和 CNN。Comments: 10 pages, 5 figures, accepted by EMNLP 2018 (v2: corrected author names)Subjects: Computation and Language (cs.CL)Cite as: arXiv:1808.08946 [cs.CL] (or arXiv:1808.08946v2 [cs.CL] for this version) 本论文的主要贡献如下： 检验了这一理论断言：具备更短路径的架构更擅长捕捉长距离依赖。研究者在建模长距离主谓一致任务上的实验结果并没有表明，Transformer 或 CNN 在这方面优于 RNN。 通过实验证明 Transformer 中注意力头的数量对其捕捉长距离依赖的能力有所影响。具体来说，多头注意力对使用自注意力机制建模长距离依赖是必要的。 通过实验证明 Transformer 擅长 WSD，这表明 Transformer 是强大的语义特征提取器。]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Self-Attention</tag>
        <tag>注意力机制</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Batch Normalization——Accelerating Deep Network Training by Reducing Internal]]></title>
    <url>%2F2018%2F09%2F17%2F%E6%89%B9%E6%AD%A3%E5%88%99%E5%8C%96%2F</url>
    <content type="text"><![CDATA[标题 说明 附加 《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》 原文 2015 Batch Normalization 论文翻译 DCD_Lin 深入理解Batch Normalization批标准化 郭耀华 优化深度神经网络（三）Batch Normalization 喵喵帕斯 Batch Normalization 学习笔记 hjimce 2016 白化我们已经了解了如何使用PCA降低数据维度。在一些算法中还需要一个与之相关的预处理步骤，这个预处理过程称为白化（一些文献中也叫sphering）。举例来说，假设训练数据是图像，由于图像中相邻像素之间具有很强的相关性，所以用于训练时输入是冗余的。白化的目的就是降低输入的冗余性；更正式的说，我们希望通过白化过程使得学习算法的输入具有如下性质：(i)特征之间相关性较低；(ii)所有特征具有相同的方差。s Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate ShiftSergey Ioffe, Christian Szegedy(Submitted on 11 Feb 2015 (v1), last revised 2 Mar 2015 (this version, v3)) Training Deep Neural Networks is complicated by the fact that the distribution of each layer’s inputs changes during training, as the parameters of the previous layers change. This slows down the training by requiring lower learning rates and careful parameter initialization, and makes it notoriously hard to train models with saturating nonlinearities. We refer to this phenomenon as internal covariate shift, and address the problem by normalizing layer inputs. Our method draws its strength from making normalization a part of the model architecture and performing the normalization for each training mini-batch. Batch Normalization allows us to use much higher learning rates and be less careful about initialization. It also acts as a regularizer, in some cases eliminating the need for Dropout. Applied to a state-of-the-art image classification model, Batch Normalization achieves the same accuracy with 14 times fewer training steps, and beats the original model by a significant margin. Using an ensemble of batch-normalized networks, we improve upon the best published result on ImageNet classification: reaching 4.9% top-5 validation error (and 4.8% test error), exceeding the accuracy of human raters. 当前神经网络层之前的神经网络层的参数变化，引起神经网络每一层输入数据的分布产生了变化，这使得训练一个深度神经网络（Deep Neural Networks）变得复杂。这样就要求使用更小的学习率，参数初始化也需要更为谨慎的设置。并且由于非线性饱和（注：如sigmoid激活函数的非线性饱和问题），训练一个深度神经网络会非常困难。我们称这个现象为：internal covariate shif；同时利用归一化层输入解决这个问题。我们将归一化层输入作为神经网络的结构，并且对每一个小批量训练数据执行这一操作。Batch Normalization（BN） 能使用更高的学习率，并且不需要过多的注重参数初始化问题。BN 的过程与正则化相似，在某些情况下可以去除Dropout。将BN应用到一个state-of-the-art的图片分类模型中时，使用BN只要1/14的训练次数就能够达到同样的精度。使用含有BN神经网络模型能提升现有最好的ImageNet分类结果：在top-5 验证集中达到4.9%的错误率（测试集为4.8%），超出了人类的分类精度。 Subjects: Machine Learning (cs.LG)Cite as: arXiv:1502.03167 [cs.LG] (or arXiv:1502.03167v3 [cs.LG] for this version)]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>BN</tag>
        <tag>批正则化</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Group Normalization]]></title>
    <url>%2F2018%2F09%2F15%2FGroup%20Normalization%2F</url>
    <content type="text"><![CDATA[标题 说明 附加 《Group Normalization》 原文 2018 Group NormalizationYuxin Wu, Kaiming He(Submitted on 22 Mar 2018 (v1), last revised 11 Jun 2018 (this version, v3)) Batch Normalization (BN) is a milestone technique in the development of deep learning, enabling various networks to train. However, normalizing along the batch dimension introduces problems —- BN’s error increases rapidly when the batch size becomes smaller, caused by inaccurate batch statistics estimation. This limits BN’s usage for training larger models and transferring features to computer vision tasks including detection, segmentation, and video, which require small batches constrained by memory consumption. In this paper, we present Group Normalization (GN) as a simple alternative to BN. GN divides the channels into groups and computes within each group the mean and variance for normalization. GN’s computation is independent of batch sizes, and its accuracy is stable in a wide range of batch sizes. On ResNet-50 trained in ImageNet, GN has 10.6% lower error than its BN counterpart when using a batch size of 2; when using typical batch sizes, GN is comparably good with BN and outperforms other normalization variants. Moreover, GN can be naturally transferred from pre-training to fine-tuning. GN can outperform its BN-based counterparts for object detection and segmentation in COCO, and for video classification in Kinetics, showing that GN can effectively replace the powerful BN in a variety of tasks. GN can be easily implemented by a few lines of code in modern libraries. Comments: v3: Update trained-from-scratch results in COCO to 41.0AP. Code and models at this https URLSubjects: Computer Vision and Pattern Recognition (cs.CV); Machine Learning (cs.LG)Cite as: arXiv:1803.08494 [cs.CV] (or arXiv:1803.08494v3 [cs.CV] for this version)]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>正则化</tag>
        <tag>Group Normalization</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[残差网络]]></title>
    <url>%2F2018%2F09%2F14%2F%E6%AE%8B%E5%B7%AE%E7%BD%91%E7%BB%9C%2F</url>
    <content type="text"><![CDATA[残差网络(百度百科)残差网络是2015年提出的深度卷积网络，一经出世，便在ImageNet中斩获图像分类、检测、定位三项的冠军。 残差网络更容易优化，并且能够通过增加相当的深度来提高准确率。核心是解决了增加深度带来的副作用（退化问题），这样能够通过单纯地增加网络深度，来提高网络性能。 残差网络背景 残差网络解决退化问题 残差网络资源列表Deep Residual Learning for Image RecognitionKaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun(Submitted on 10 Dec 2015) 更深的神经网络往往更难以训练，我们在此提出一个残差学习的框架，以减轻网络的训练负担，这是个比以往的网络要深的多的网络。我们明确地将层作为输入学习残差函数，而不是学习未知的函数。我们提供了非常全面的实验数据来证明，残差网络更容易被优化，并且可以在深度增加的情况下让精度也增加。在ImageNet的数据集上我们评测了一个深度152层（是VGG的8倍）的残差网络，但依旧拥有比VGG更低的复杂度。残差网络整体达成了3.57%的错误率，这个结果获得了ILSVRC2015的分类任务第一名，我们还用CIFAR-10数据集分析了100层和1000层的网络。 在一些计算机视觉识别方向的任务当中，深度表示往往是重点。我们极深的网络让我们得到了28%的相对提升（对COCO的对象检测数据集）。我们在深度残差网络的基础上做了提交的版本参加ILSVRC和COCO2015的比赛，我们还获得了ImageNet对象检测，Imagenet对象定位，COCO对象检测和COCO图像分割的第一名。 Comments: Tech reportSubjects: Computer Vision and Pattern Recognition (cs.CV)Cite as: arXiv:1512.03385 [cs.CV] (or arXiv:1512.03385v1 [cs.CV] for this version)]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>残差网络</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Deep Residual Learning for Image Recognition]]></title>
    <url>%2F2018%2F09%2F14%2FDeep%20Residual%20Learning%20for%20Image%20Recognition%2F</url>
    <content type="text"><![CDATA[标题 说明 附加 《Deep Residual Learning for Image Recognition》 原始论文 2015 解决了神经网络 “退化问题” ResNet网络，本文获得2016 CVPR best paper，获得了ILSVRC2015的分类任务第一名。 《Deep Residual Learning for Image Recognition》HTML 原始论文网页版 《Deep Residual Learning for Image Recognition（译）》 zhwhong 译文 2017 《Deep Residual Learning for Image Recognition（译）》 XlyPb 译文 2017 《论文理论解读》 作者 junlinhe@yeah.net Deep Residual Learning for Image RecognitionKaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun(Submitted on 10 Dec 2015) 更深的神经网络往往更难以训练，我们在此提出一个残差学习的框架，以减轻网络的训练负担，这是个比以往的网络要深的多的网络。我们明确地将层作为输入学习残差函数，而不是学习未知的函数。我们提供了非常全面的实验数据来证明，残差网络更容易被优化，并且可以在深度增加的情况下让精度也增加。在ImageNet的数据集上我们评测了一个深度152层（是VGG的8倍）的残差网络，但依旧拥有比VGG更低的复杂度。残差网络整体达成了3.57%的错误率，这个结果获得了ILSVRC2015的分类任务第一名，我们还用CIFAR-10数据集分析了100层和1000层的网络。 在一些计算机视觉识别方向的任务当中，深度表示往往是重点。我们极深的网络让我们得到了28%的相对提升（对COCO的对象检测数据集）。我们在深度残差网络的基础上做了提交的版本参加ILSVRC和COCO2015的比赛，我们还获得了ImageNet对象检测，Imagenet对象定位，COCO对象检测和COCO图像分割的第一名。 Comments: Tech reportSubjects: Computer Vision and Pattern Recognition (cs.CV)Cite as: arXiv:1512.03385 [cs.CV] (or arXiv:1512.03385v1 [cs.CV] for this version)]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>ResNet</tag>
        <tag>残差网络</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Generative Adversarial Networks]]></title>
    <url>%2F2018%2F09%2F11%2FGenerative%20Adversarial%20Networks%2F</url>
    <content type="text"><![CDATA[标题 说明 附加 《Generative Adversarial Networks》 原始论文 2014 《Generative Adversarial Networks》HTML 原始论文网页版 2014 Code and hyperparameters for the paper 作者提供代码 2014 Keras-GAN 实现代码 2018 Generative Adversarial Nets（译） XIyPb 翻译 2017 《GAN完整理论推导与实现》 论文证明详细解释 2017 《Generative Adversarial Networks》Ian J. Goodfellow, Jean Pouget-Abadie, Mehdi Mirza, Bing Xu, David Warde-Farley, Sherjil Ozair, Aaron Courville, Yoshua Bengio We propose a new framework for estimating generative models via an adversarial process, in which we simultaneously train two models: a generative model G that captures the data distribution, and a discriminative model D that estimates the probability that a sample came from the training data rather than G. The training procedure for G is to maximize the probability of D making a mistake. This framework corresponds to a minimax two-player game. In the space of arbitrary functions G and D, a unique solution exists, with G recovering the training data distribution and D equal to 1/2 everywhere. In the case where G and D are defined by multilayer perceptrons, the entire system can be trained with backpropagation. There is no need for any Markov chains or unrolled approximate inference networks during either training or generation of samples. Experiments demonstrate the potential of the framework through qualitative and quantitative evaluation of the generated samples. Subjects: Machine Learning (stat.ML); Machine Learning (cs.LG)Cite as: arXiv:1406.2661 [stat.ML] (or arXiv:1406.2661v1 [stat.ML] for this version) Keras-GAN123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162from __future__ import print_function, divisionfrom keras.datasets import mnistfrom keras.layers import Input, Dense, Reshape, Flatten, Dropoutfrom keras.layers import BatchNormalization, Activation, ZeroPadding2Dfrom keras.layers.advanced_activations import LeakyReLUfrom keras.layers.convolutional import UpSampling2D, Conv2Dfrom keras.models import Sequential, Modelfrom keras.optimizers import Adamimport matplotlib.pyplot as pltimport sysimport numpy as npclass GAN(): def __init__(self): self.img_rows = 28 self.img_cols = 28 self.channels = 1 self.img_shape = (self.img_rows, self.img_cols, self.channels) self.latent_dim = 100 optimizer = Adam(0.0002, 0.5) # Build and compile the discriminator self.discriminator = self.build_discriminator() self.discriminator.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy']) # Build the generator self.generator = self.build_generator() # The generator takes noise as input and generates imgs z = Input(shape=(self.latent_dim,)) img = self.generator(z) # For the combined model we will only train the generator self.discriminator.trainable = False # The discriminator takes generated images as input and determines validity validity = self.discriminator(img) # The combined model (stacked generator and discriminator) # Trains the generator to fool the discriminator self.combined = Model(z, validity) self.combined.compile(loss='binary_crossentropy', optimizer=optimizer) def build_generator(self): model = Sequential() model.add(Dense(256, input_dim=self.latent_dim)) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) model.add(Dense(512)) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) model.add(Dense(1024)) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) model.add(Dense(np.prod(self.img_shape), activation='tanh')) model.add(Reshape(self.img_shape)) model.summary() noise = Input(shape=(self.latent_dim,)) img = model(noise) return Model(noise, img) def build_discriminator(self): model = Sequential() model.add(Flatten(input_shape=self.img_shape)) model.add(Dense(512)) model.add(LeakyReLU(alpha=0.2)) model.add(Dense(256)) model.add(LeakyReLU(alpha=0.2)) model.add(Dense(1, activation='sigmoid')) model.summary() img = Input(shape=self.img_shape) validity = model(img) return Model(img, validity) def train(self, epochs, batch_size=128, sample_interval=50): # Load the dataset (X_train, _), (_, _) = mnist.load_data() # Rescale -1 to 1 X_train = X_train / 127.5 - 1. X_train = np.expand_dims(X_train, axis=3) # Adversarial ground truths valid = np.ones((batch_size, 1)) fake = np.zeros((batch_size, 1)) for epoch in range(epochs): # --------------------- # Train Discriminator # --------------------- # Select a random batch of images idx = np.random.randint(0, X_train.shape[0], batch_size) imgs = X_train[idx] noise = np.random.normal(0, 1, (batch_size, self.latent_dim)) # Generate a batch of new images gen_imgs = self.generator.predict(noise) # Train the discriminator d_loss_real = self.discriminator.train_on_batch(imgs, valid) d_loss_fake = self.discriminator.train_on_batch(gen_imgs, fake) d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) # --------------------- # Train Generator # --------------------- noise = np.random.normal(0, 1, (batch_size, self.latent_dim)) # Train the generator (to have the discriminator label samples as valid) g_loss = self.combined.train_on_batch(noise, valid) # Plot the progress print ("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch, d_loss[0], 100*d_loss[1], g_loss)) # If at save interval =&gt; save generated image samples if epoch % sample_interval == 0: self.sample_images(epoch) def sample_images(self, epoch): r, c = 5, 5 noise = np.random.normal(0, 1, (r * c, self.latent_dim)) gen_imgs = self.generator.predict(noise) # Rescale images 0 - 1 gen_imgs = 0.5 * gen_imgs + 0.5 fig, axs = plt.subplots(r, c) cnt = 0 for i in range(r): for j in range(c): axs[i,j].imshow(gen_imgs[cnt, :,:,0], cmap='gray') axs[i,j].axis('off') cnt += 1 fig.savefig("images/%d.png" % epoch) plt.close()if __name__ == '__main__': gan = GAN() gan.train(epochs=30000, batch_size=32, sample_interval=200)]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>GAN</tag>
        <tag>生成式对抗网络</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[主成成分分析、自编码器和变分自编码器解析]]></title>
    <url>%2F2018%2F08%2F26%2F%E4%B8%BB%E6%88%90%E6%88%90%E5%88%86%E5%88%86%E6%9E%90%E3%80%81%E8%87%AA%E7%BC%96%E7%A0%81%E5%99%A8%E5%92%8C%E5%8F%98%E5%88%86%E8%87%AA%E7%BC%96%E7%A0%81%E5%99%A8%E8%A7%A3%E6%9E%90%2F</url>
    <content type="text"><![CDATA[介绍主成分分析（PCA）和自编码器（AutoEncoders, AE）是无监督学习中的两种代表性方法。 PCA 的地位不必多说，只要是讲到降维的书，一定会把 PCA 放到最前面，它与 LDA 同为机器学习中最基础的线性降维算法，SVM/Logistic Regression、PCA/LDA 也是最常被拿来作比较的两组算法。 自编码器虽然不像 PCA 那般在教科书上随处可见，但是在早期被拿来做深度网络的逐层预训练，其地位可见一斑。尽管在 ReLU、Dropout 等技术出现之后，人们不再使用 AutoEncoders 来预训练，但它延伸出的稀疏 AutoEncoders，降噪 AutoEncoders 等仍然被广泛用于表示学习。2017 年 Kaggle 比赛 Porto Seguro’s Safe Driver Prediction 的冠军就是使用了降噪 AutoEncoders 来做表示学习，最终以绝对优势击败了手工特征工程的选手们。 PCA 和 AutoEncoders 都是非概率的方法，它们分别有一种对应的概率形式叫做概率 PCA (Probabilistic PCA) 和变分自编码器（Variational AE, VAE），本文的主要目的就是整理一下 PCA、概率 PCA、AutoEncoders、变分 AutoEncoders 这四者的关系。 先放结论，后面就围绕这个表格展开： 降维方法 线性 非线性 生成式 概率PCA 变分自编码器 非生成式 PCA 自编码器 降维的线性方法和非线性方法降维分为线性降维和非线性降维，这是最普遍的分类方法。 PCA 和 LDA 是最常见的线性降维方法，它们按照某种准则为数据集找到一个最优投影方向 W 和截距 b，然后做变换得到降维后的数据集。因为是一个线性变换（严格来说叫仿射变换，因为有截距项），所以这两种方法叫做线性降维。 LDA是一种监督学习的降维技术，也就是说它的数据集的每个样本是有类别输出的。这点和PCA不同。PCA是不考虑样本类别输出的无监督降维技术。LDA的思想可以用一句话概括，就是“投影后类内方差最小，类间方差最大”。 PCA 与 LDA 相同点： 两者均可以对数据进行降维。 两者在降维时均使用了矩阵特征分解的思想。 两者都假设数据符合高斯分布。 PCA 与 LDA 不同点： LDA是有监督的降维方法，而PCA是无监督的降维方法 LDA降维最多降到类别数k-1的维数，而PCA没有这个限制。 LDA除了可以用于降维，还可以用于分类。 LDA选择分类性能最好的投影方向，而PCA选择样本点投影具有最大方差的方向。 非线性降维的两类代表方法是流形降维和 AutoEncoders，这两类方法也体现出了两种不同角度的“非线性”。流形方法的非线性体现在它认为数据分布在一个低维流形上，而流形本身就是非线性的，流形降维的代表方法是两篇 2000 年的 Science 论文提出的：多维放缩（multidimensional scaling, MDS）和局部线性嵌入（locally linear embedding, LLE）。两种流形方法发表在同一年的 Science 上。 AutoEncoders 的非线性和神经网络的非线性是一回事，都是利用堆叠非线性激活函数来近似任意连续函数。事实上，AutoEncoders 就是一种神经网络，只不过它的输入和输出相同，真正有意义的地方不在于网络的输出，而是在于网络的权重。 降维的生成式方法和非生成式方法两类方法 降维还可以分为生成式方法（概率方法）和非生成式方法（非概率方法）。 教科书对 PCA 的推导一般是基于最小化重建误差或者最大化可分性的，或者说是通过提取数据集的结构信息来建模一个约束最优化问题来推导的。事实上，PCA 还有一种概率形式的推导，那就是概率 PCA，PRML 里面有对概率 PCA 的详细讲解，感兴趣的读者可以去阅读。需要注意的是，概率 PCA 不是 PCA 的变体，它就是 PCA 本身，概率 PCA 是从另一种角度来推导和理解 PCA，它把 PCA 纳入了生成式的框架。 设 $X$ 是我们拿到的数据集，我们的目的是得到数据集中每个样本的低维表示 $Z$，其中 $dim(z) &lt; dim(x)$。 降维的非生成式方法不需要概率知识，而是直接利用数据集 $X$ 的结构信息建模一个最优化问题，然后求解这个问题得到 $X$ 对应的 $Z$。 降维的生成式方法认为数据集 $X$ 是对一个随机变量 x 的 n 次采样，而随机变量 x 依赖于随机变量 z ，对 z 进行建模： z \sim p_\theta(Z)再对这个依赖关系进行建模： x|z \sim p_\theta(x|z)有了这两个公式，我们就可以表达出随机变量 x 的分布： x \sim p_\theta(x)=\int_Zp_\theta(x|z)p_\theta(z)dz随后我们利用数据集对分布的参数 θ 进行估计，就得到这几个分布。好了，设定了这么多，可是降维降在哪里了呢，为什么没有看到？ 回想一下降维的定义：降维就是给定一个高维样本 x，给出对应的低维表示 z，这恰好就是 p(z|x) 的含义。所以我们只要应用 Bayes 定理求出这个概率即可： p_\theta(z|x)=\dfrac{p_\theta(x|z)p_\theta(z)dz}{\int_Zp_\theta(x|z)p_\theta(z)dz}这样我们就可以得到每个样本点 x 上的 z 的分布 p(z|X=x) ，可以选择这个分布的峰值点作为 z，降维就完成了。 Q：那么问题来了，生成式方法和非生成式方法哪个好呢？ A：或许是非生成式方法好，一两行就能设定完，君不见生成式方法你设定了一大段？ 应该会有很多人这样想吧？事实也的确如此，上面这个回答在一定意义上是正确的。如果你只是为了对现有的数据进行降维，而没有其他需求，那么简单粗暴的非生成式方法当然是更好的选择。 那么，在什么情况下，或者说什么需求下，生成式方法是更好的选择更好呢？答案就蕴含在“生成式”这个名称中：在需要生成新样本的情况下，生成式方法是更好的选择。 在需要生成新样本时，非生成式方法需要对 z 的概率分布进行代价巨大的数值逼近，然后才能从分布中采样；生成式方法本身就对 z 的概率分布进行了建模，因此可以直接从分布中进行采样。所以，在需要生成新样本时，生成式方法是更好的选择，甚至是必然的选择。 概率 PCA 和 VAE下面简单整理一下这四种降维方法。注意一些术语，编码=降维，解码=重建，原数据=观测变量，降维后的数据=隐变量。 PCA原数据： X=\{x|x\in R^d\}编码后的数据： z = W^T(x+b), z\in R^c解码后的数据： \hat x = Wz - b, x\in R^d重建误差： \sum||x-\hat x||^p_p最小化重建误差，就可以得到 W 和 b 的最优解和解析解，PCA 的求解就完成了。 补充说明： PCA 中的 p=2 ，即最小化二范数意义下的重建误差，如果 p=1 的话我们就得到了鲁棒 PCA (Robust PCA)。而最小化误差的二范数等价于对高斯噪声的 MLE，最小化误差的一范数等价于对拉普拉斯噪声的 MLE。 因此，PCA 其实是在假设存在高斯噪声的条件下对数据集进行重建，这个高斯误差就是我们将要在下面概率 PCA 一节中提到的 ϵ。你看，即使不是概率 PCA，其中也隐含着概率的思想。 编码和解码用到的 W 和 b 是一样的，即编码过程和解码过程是对称的，这一点与下面要讲的 AutoEncoders 是不同的。 求解上述最优化问题可以得到 b，这恰好是样本均值的相反数。也就是说，PCA 中截距项的含义是让每个样本都减去样本均值，这正是“样本中心化”的含义。 既然我们已经知道求出来的截距就是样本均值，所以干脆一开始就对样本进行中心化，这样在使用 PCA 的时候就可以忽略截距项 b 而直接使用，变量就只剩下 W 了。教科书上讲解 PCA 时一般都是上来就说“使用 PCA 之前需要进行样本中心化”，但是没有人告诉我们为什么要这样做，现在大家应该明白为什么要进行中心化了吧。 AutoEncoders原数据： X=\{x|x\in R^d\}编码后的数据： z = \sigma(Wx+b), z\in R^c解码后的数据： \hat x = \sigma(\hat Wz + \hat b), z\in R^d重建误差： \sum||x-\hat x||^p_p最小化重建误差，利用反向传播算法可以得到的局部最优解&amp;数值解，AutoEncoders 的求解完成。 补充说明： 这里可以使用任意范数，每一个范数都代表我们对数据的一种不同的假设。为了和 PCA 对应，我们也取 p=2。 σ(·) 是非线性激活函数。AutoEncoder 一般都会堆叠多层，方便起见我们只写了一层。 $W$ 和 $\hat W$ 是不同的权重矩阵，这是因为经过非线性变换之后我们已经无法将样本再用原来的基 W 进行表示了，必须要重新训练解码的基 。甚至，AutoEncoders 的编码器和解码器堆叠的层数都可以不同，例如可以用 4 层来编码，用 3 层来解码。 概率PCA隐变量边缘分布： p(z)=N(z|0,I)观测变量条件分布： p_\theta (x|z) = N(x|f(z;\theta),{\sigma}^2 I)均值函数： f(z;\theta)=Wz+\mux 的生成过程： x=f(z;\theta)+\epsilon, \epsilon \in N(0,{\sigma}^2 I))因为 $p(z)$ 和 $p_θ(x|z)$ 都是高斯分布，且 $p_θ(x|z)$ 的均值 $f(z;θ) = Wz+μ$ 是 z 的线性函数，所以这是一个线性高斯模型。 线性高斯模型有一个非常重要的性质： $p_θ(x)$ 和$p_θ(z|x)$ 也都是高斯分布。这个性质保证了我们能够使用极大似然估计或者EM算法来求解PCA。 如果没有这个性质的话，我们就只能借助变分法（变分 AE 采用的）或者对抗训练（GAN 采用的）来近似 $p_θ(x)$ 和 $p_θ(z|x)$ 了。有了这个优秀的性质之后，我们至少有三种方法可以求解概率 PCA： 是一个形式已知，仅参数未知的高斯分布，因此可以用极大似然估计来求解 θ。p_\theta(x)=\int_Zp_\theta(x|z)p_\theta(z)dz 也是一个形式已知，仅参数未知的高斯分布，因此可以用 EM 算法来求解 θ，顺便还能得到隐变量 z。 p_\theta(z|x)=\dfrac{p_\theta(x|z)p_\theta(z)dz}{\int_Zp_\theta(x|z)p_\theta(z)dz} 甚至也可以引入一个变分分布 $q_Φ(z|x)$ 来求解概率 PCA。 一旦求出了 θ，我们就得到了所有的四个概率： p(z), p_\theta(x|z), p_\theta(x), p_\theta(z|x)有了这四个概率，我们就可以做这些事情了： 降维：给定样本 x ，就得到了分布 $p_θ(z|X=x)$ ，取这个分布的峰值点 z 就是降维后的数据； 重建：给定降维后的样本 z ，就得到了分布 $p_θ(x|Z=z)$，取这个分布的峰值点 x 就是重建后的数据； 生成：从分布 p(z) 中采样一个，就得到了分布，取这个分布的峰值点就是新生成的数据； 密度估计：给定样本 x ，就得到了这一点的概率密度 pθ(X=x) 。 PCA 只能做到 1 和 2，对 3 和 4无力，这一点我们已经分析过了。 Q：为什么隐变量要取单位高斯分布（标准正态分布）？ A：这是两个问题。 subQ1：为什么要取高斯分布？ subA1：为了求解方便，如果不取高斯分布，那么 $p_θ(x)$ 有很大的可能没有解析解，这会给求解带来很大的麻烦。还有一个原因，回想生成新样本的过程，要首先从 p(z) 中采样一个，高斯分布采样简单。 subQ2：为什么是零均值单位方差的？ subA2：完全可以取任意均值和方差，但是我们要将 $p(z)$ 和 $p_θ(x|z)$ 相乘，均值和方差部分可以挪到 $f(z;θ)$ 中，所以 $p(z)$ 的均值和方差取多少都无所谓，方便起见就取单位均值方差了。 Q：$p_θ(x|z)$ 为什么选择了高斯分布呢？ A：因为简单，和上一个问题的一样。还有一个直觉的解释是 $p_θ(x|z)$ 认为 x 是由 f(z;θ) 和噪声 ϵ 加和而成的，如果 ϵ 是高斯分布的话，恰好和 PCA 的二范数重建误差相对应，这也算是一个佐证吧。 Q：$p_θ(x|z)$ 的方差为什么选择了各向同性的，而不是更一般的 ∑ 呢？ A：方差可以选择一般的 ∑ ，但是个参数一定会给求解带来困难，所导出的方法虽然也是线性降维，但它已经不是 PCA 了，而是另外的方法。方差也可以选择成一个的各向异性的对角阵 λ，这样只有 d 个参数，事实上这就是因子分析，另一种线性降维方法。只有当方差选择成各向同性的对角阵时，导出来的方法才叫主成分分析，这个地方 PRML 里有介绍。 变分AutoEncoders隐变量边缘分布： p(z)=N(z|0,I)观测变量条件分布： p_\theta (x|z) = N(x|f(z;\theta),{\sigma}^2 I)均值函数： f(z;\theta)=\sigma(Wz+\mu)x 的生成过程： x=f(z;\theta)+\epsilon, \epsilon \in N(0,{\sigma}^2 I))因为 f(z;θ) 是 z 的非线性函数，所以这不再是一个线性高斯模型。观测变量的边缘分布： p_\theta(x)=\int_Zp_\theta(x|z)p_\theta(z)dz没有解析形式。这就意味着我们无法直接使用极大似然估计来求解参数 θ。隐变量的后验分布： p_\theta(z|x)=\dfrac{p_\theta(x|z)p_\theta(z)dz}{\int_Zp_\theta(x|z)p_\theta(z)dz}也没有解析形式（这是当然，因为分母没有解析形式了）。这就意味着我们也无法通过 EM 算法来估计参数和求解隐变量。 那么，建出来的模型该怎么求解呢？这就需要上变分推断（Variational Inference），又称变分贝叶斯（Variational Bayes）了。本文不打算细讲变分推断，仅仅讲一下大致的流程。更多关于 VAE 的内容见《变分自编码器》。 变分推断会引入一个变分分布 $q_Φ(z|x)$ 来近似没有解析形式的后验概率 $p_θ(z|x)$ 。在变分 AE 的原文中，作者使用了 SGD 来同时优化参数 θ 和 Φ。一旦求出了这两个参数就可以得到这些概率： p(z), p_\theta(x|z), q_\phi(z|x)注意因为 $p_θ(x)$ 和 $p_θ(z|x)$ 没有解析形式，所以即使求出了 θ 我们也无法获得这两个概率。但是，正如上面说的， $q_Φ(z|x)$ 就是 $p_θ(z|x)$ 的近似，所以需要用 $p_θ(z|x)$ 的地方都可以用 $q_Φ(z|x)$ 代替。 有了这三个概率，我们就可以做这些事情了： 降维：给定样本 x，就得到了分布 $q_Φ(z|X=x)$ ，取这个分布的峰值点 z 就是降维后的数据； 重建：给定降维后的样本 z，就得到了分布 $p_θ(x|Z=z)$，取这个分布的峰值点 x 就是重建后的数据； 生成：从分布 $ p(z)$ 中采样一个，就得到了分布，取这个分布的峰值点就是新生成的数据。 与概率 PCA 不同的是，这里无法解析地得到 $p_θ(x)$ ，进行密度估计需要进行另外的设计，通过采样得到，计算代价还是比较大的，具体步骤变分 AE 的原文中有介绍。 AutoEncoders 只能做到 1 、2 和 3，对 4无力。 总结 从 PCA 和 AutoEncoders 这两节可以看出，PCA 实际上就是线性 Autoencoders。两者无论是编码解码形式还是重建误差形式都完全一致，只有是否线性的区别。线性与否给优化求解带来了不同性质：PCA 可以直接得到最优的解析解，而 AutoEncoders 只能通过反向传播得到局部最优的数值解。 从概率 PCA 和变分 AutoEncoders 这两节可以看出，概率 PCA 和变分 AutoEncoders 的唯一区别就是 f(z;θ) 是否是 z 的线性函数，但是这个区别给优化求解带来了巨大的影响。在概率 PCA 中，f(z;θ) 是线性的，所以我们得到了一个线性高斯模型，线性高斯模型的优秀性质是牵扯到的 4 个概率都是高斯分布，所以我们可以直接给出边缘分布和编码分布的解析形式，极大似然估计和 EM 算法都可以使用，一切处理都非常方便。在变分AutoEncoders中，f(z;θ) 是非线性的，所以边缘分布不再有解析形式，极大似然估计无法使用；编码分布也不再有解析形式，EM 算法无法使用，我们只能求助于变分推断，得到编码分布的近似 $q_Φ(z|x)$ ，再利用别的技巧得到边缘分布 $pθ(x)$ 的估计。 从 PCA 和概率 PCA 两小节可以看出，PCA 和概率 PCA 中 x 都是 z 的线性函数，只不过概率 PCA 显式地把高斯噪声 ϵ 写在了表达式中；PCA 没有显式写出噪声，而是把高斯噪声隐含在了二范数重建误差中。 从 AutoEncoders 和变分 AutoEncoders 这两节可以看出，AE 和 VAE 的最重要的区别在于 VAE 迫使隐变量 z 满足高斯分布 p(z)=N(z|0,I) ，而 AE 对 z 的分布没有做任何假设。 这个区别使得在生成新样本时，AE 需要先数值拟合 p(z) ，才能生成符合数据集分布的隐变量，而 VAE 直接从 N(z|0,I) 中采样一个 z ，它天然就符合数据集分布。事实上，这是因为在使用变分推断进行优化时，VAE 迫使 z 的分布向 N(z|0,I) 靠近，不过本文中没有讲优化细节，VAE 的原文中有详细的解释。 PCA 求解简单，但是都是线性降维，提取信息的能力有限；非线性的 AE 提取信息的能力强，但是求解复杂。要根据不同的场景选择不同的降维算法。 要生成新样本时，不能选择 PCA 或 AE，而是要选择概率 PCA 或 VAE。 对自编码器和变分自编码器的进一步理解《从自编码器到变分自编码器（其一）》《从自编码器到变分自编码器（其二）》 自编码器将数据作为输入并发现数据的一些潜在状态表示的模型（欠完备，稀疏，降噪，压缩）。也就是说，我们的输入数据被转换成一个编码向量，其中每个维度表示一些学到的关于数据的属性。在这里，最重要的细节是我们的编码器网络为每个编码维度输出单个值，而解码器网络随后接收这些值并尝试重构原始输入。 变分自编码器（VAE）以概率的方式描述潜在空间观察。因此，我们不会构建一个输出单个值来描述每个潜在状态属性的编码器，而是用编码器来描述每个潜在属性的概率分布。]]></content>
      <categories>
        <category>深度学习</category>
        <category>变分自编码器</category>
      </categories>
      <tags>
        <tag>变分自编码器</tag>
        <tag>主成成分分析</tag>
        <tag>自编码器</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[变分自编码器（Variational Auto-Encoder，VAE）]]></title>
    <url>%2F2018%2F08%2F26%2F%E5%8F%98%E5%88%86%E8%87%AA%E7%BC%96%E7%A0%81%E5%99%A8%2F</url>
    <content type="text"><![CDATA[为什么要发明变分自编码器什么是变分自编码机？要理解变分自编码机(VAE)，我们要先从一个简单的网络开始，一步一步添加部件。描述神经网络的常见方法，是把它解释成我们想要建模的功能的某种近似。然而，它们还能被理解为储存信息的某种数据结构。 假设有一个由数层解卷积层构成的神经网络，我们把输入设定为单位向量，然后训练该网络去降低其与目标图像之间的均方误差。这样，该图像的“数据”就包含在神经网络当前的参数之中了。 现在，我们用多张图像来尝试这一步骤。此时，输入不再是单位向量，而要改用独热向量。比如，输入 [1, 0, 0, 0] 可能是生成一张猫的图像，而输入 [0, 1, 0, 0] 则可能生成一张狗的图像。这是可行的，不过这样我们只能存储最多4张图像。让网络记住更多的图像则要使用更长的向量，同时也意味着越来越多的参数。 为此，我们需要使用实向量，而非独热向量。我们可以把它视为某个图像所对应的编码，比如用向量 [3.3, 4.5, 2.1, 9.8] 来表示猫的图像，而用向量 [3.4, 2.1, 6.7, 4.2] 来表示狗的图像，这就是 编码/解码 这一术语的来源。这一初始向量便是我们的潜在变量。 像我前面那样随机选择潜在变量，明显是个糟糕的做法。在自编码机中，我们加入了一个能自动把原始图像编码成向量的组件。上述解卷积层则能把这些向量“解码”回原始图像。 这样，我们的模型终于到了一个能有用武之地的阶段。根据需要，我们可以用尽可能多的图像来训练网络。如果保存了某张图像的编码向量，我们随时就能用解码组件来重建该图像，整个过程仅需一个标准的自编码机。 不过，这里我们想要的是构建一个生成式模型，而非仅仅是“记忆”图像数据的模糊结构。除了像前面那样从已有图像中编码出潜在向量，我们还不知道如何创造这些向量，也就无法凭空生成任何图像。 这里有个简单的办法。我们给编码网络增加一个约束，迫使它所生成的潜在向量大体上服从于单位高斯分布。该约束条件使得变分自编码机不同于标准自编码机。 现在，生成新的图像就变得容易了：我们只需从单位高斯分布中采样出一个潜在向量，并将其传到解码器即可。 实际操作中，我们需要仔细权衡网络的精确度与潜在变量在单位高斯分布上的契合程度。 神经网络可以自行决定这里的取舍。对于其中的误差项，我们归纳出独立的两种：生成误差，用以衡量网络重构图像精确度的均方误差；潜在误差，用以衡量潜在变量在单位高斯分布上的契合程度的KL散度。 generation_loss = mean(square(generated_image - real_image)) latent_loss = KL-Divergence(latent_variable, unit_gaussian) loss = generation_loss + latent_loss 为了优化KL散度，我们要用到重新参数化的一个简单技巧：生成一个均值向量一个标准差向量，而非直接生成实值向量。 我们的KL散度计算就变成这样： # z_mean and z_stddev are two vectors generated by encoder network latent_loss = 0.5 * tf.reduce_sum(tf.square(z_mean) + tf.square(z_stddev) - tf.log(tf.square(z_stddev)) - 1,1) 在计算解码网络的误差时，我们只需从标准差中取样，再加上均值向量，就能得到我们的潜在向量： samples = tf.random_normal([batchsize,n_z],0,1,dtype=tf.float32) sampled_z = z_mean + (z_stddev * samples) 除了能让我们生成随机的潜在变量，该约束还能提高VAE网络的泛化能力。 形象地说，我们可以把潜在变量视为数据的变换系数。 在[ 0, 10 ]的区间内，假定你有一系列的实数-名称对，一个实数代表一个物体的名字。例如，5.43表示苹果，5.44表示香蕉。当有人给你数字5.43时，你肯定知道他们是在谈论苹果。本质上，采用这一方式可以编码无限多的信息，毕竟[ 0, 10 ]之间的实数是有无数个。 然而，如果每当有人给告诉你一个新数字，它的高斯噪点也会增加一个时，情况会变成怎样？比如说，你收到数字是5.43，其原始数值则应在[4.4 ~ 6.4]之间，那其他人所说的真实数字就有可能是5.44（香蕉）。 所增噪点的标准差越大，其均值变量所能传递的信息就越少。 用此相同的逻辑，我们就能在编码器和解码器之间传递潜在变量。对原始图像的编码越有效，我们在高斯分布上所能取样的标准差就越大，直至为1（标准正态分布）。 这一约束迫使编码器变得非常高效，从而能创造出信息丰富的潜在变量。它所提升的泛化能力，让我们随机生成或从非训练图像编码而来的潜在变量，在解码时将能产生更好的结果。 VAE的效果有多好？ 我在MNIST手写数据集上做了一些测试，从中可以看出变分自编码机的效果有多好。 左：第1世代，中：第9世代，右：原始图像 看起来很不错！在我那没有显卡的笔记本上运行15分钟后，它就生成了一些很好的MNIST结果。 VAE的优点： 由于它们所遵循的是一种 编码-解码 模式，我们能直接把生成的图像同原始图像进行对比，这在使用GAN时是不可能的。 VAE的不足： 由于它是直接采用均方误差而非对抗网络，其神经网络倾向于生成更为模糊的图像。 也有一些需要结合VAE和GAN的研究工作：采用相同的 编码器-解码器 配置，但使用对抗网络来训练解码器。 研究详情参考论文 https://arxiv.org/pdf/1512.09300.pdf http://blog.otoro.net/2016/04/01/generating\-large\-images\-from\-latent\-vectors/ 变分自编码器经典论文《Auto-Encoding Variational Bayes》 | Diederik P Kingma, Max Welling | 2013 Abstract如何在有向概率模型中进行有效的推理和学习，在存在连续的潜在变量和难以处理的后验分布和大数据集的情况下？我们引入一个随机变分推理和学习算法，缩放到大数据集，并在一些温和的可微性条件下，甚至在棘手的情况下工作。我们的贡献是双重的。首先，我们表明，变分下界的重新参数化产生一个下界估计，可以直接使用标准随机梯度方法优化。第二，我们表明，对于I.I.D.数据集具有连续潜变量每个数据点，后推理可以特别有效的拟合近似推理模型（也称为识别模型）棘手的后部使用所提出的下界估计。理论优势反映在实验结果中。Subjects: Machine Learning (stat.ML); Machine Learning (cs.LG) 变分自编码器导论 Vivek Vyas 的《浅析变分自编码器VAE》 MoussaTintin 的《【Learning Notes】变分自编码器（Variational Auto-Encoder，VAE）》 变分自编码器基础首先阅读苏剑林 VAE 的第一篇文章《变分自编码器（一）：原来是这么一回事》。 下面示意 VAE 代码完整版 。 VAE 的示意图 VAE由三部分组成：编码器 $q(z|x)$，先验 $p(z)$，解码器 $p(x|z)$。 编码器将图像映射到针对该图像的代码的分布上。这种分布也被称为后验（posterior），因为它反映了我们关于代码应该用于给定图像之后的准确度。 1234567891011121314'''Example of VAE on MNIST dataset using MLPThe VAE has a modular design. The encoder, decoder and VAEare 3 models that share weights. After training the VAE model,the encoder can be used to generate latent vectors.The decoder can be used to generate MNIST digits by sampling thelatent vector from a Gaussian distribution with mean=0 and std=1.# Reference[1] Kingma, Diederik P., and Max Welling."Auto-encoding variational bayes."https://arxiv.org/abs/1312.6114''' VAE 网络结构1234567# network parametersinput_shape = (original_dim, )intermediate_dim = 512batch_size = 128latent_dim = 2 #可以是其它维度，这里选择二维只是为了方便可视化epochs = 50# VAE model = encoder + decoder 编码器123456789101112# build encoder modelinputs = Input(shape=input_shape, name='encoder_input')x = Dense(intermediate_dim, activation='relu')(inputs)z_mean = Dense(latent_dim, name='z_mean')(x)z_log_var = Dense(latent_dim, name='z_log_var')(x)# use reparameterization trick to push the sampling out as input# note that "output_shape" isn't necessary with the TensorFlow backendz = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])# instantiate encoder modelencoder = Model(inputs, [z_mean, z_log_var, z], name='encoder') 解码器1234567# build decoder modellatent_inputs = Input(shape=(latent_dim,), name='z_sampling')x = Dense(intermediate_dim, activation='relu')(latent_inputs)outputs = Dense(original_dim, activation='sigmoid')(x)# instantiate decoder modeldecoder = Model(latent_inputs, outputs, name='decoder') VAE123# instantiate VAE modeloutputs = decoder(encoder(inputs)[2]) #前两维度分别是均值和“方差”vae = Model(inputs, outputs, name='vae_mlp') 重参数技巧 1234567891011121314151617181920# reparameterization trick# instead of sampling from Q(z|X), sample eps = N(0,I)# z = z_mean + sqrt(var)*epsdef sampling(args): """Reparameterization trick by sampling fr an isotropic unit Gaussian. # Arguments: args (tensor): mean and log of variance of Q(z|X) # Returns: z (tensor): sampled latent vector """ z_mean, z_log_var = args # K is the keras backend batch = K.shape(z_mean)[0] dim = K.int_shape(z_mean)[1] # by default, random_normal has mean=0 and std=1.0 epsilon = K.random_normal(shape=(batch, dim)) return z_mean + K.exp(0.5 * z_log_var) * epsilon VAE 本质结构 网络输出结果网络输入时 MNIST 数据集123456789# MNIST dataset(x_train, y_train), (x_test, y_test) = mnist.load_data()image_size = x_train.shape[1]original_dim = image_size * image_sizex_train = np.reshape(x_train, [-1, original_dim])x_test = np.reshape(x_test, [-1, original_dim])x_train = x_train.astype('float32') / 255x_test = x_test.astype('float32') / 255 继续深入研究 VAE《变分自编码器（二）：从贝叶斯观点出发》《变分自编码器（三）：这样做为什么能成？》《what-is-variational-autoencoder-vae-tutorial》 条件变分自编码器Conditional Variational Autoencoders | Isaac Dykeman TODO：Variational AutoEncoder系列 参考文献[1] 苏剑林‏. 变分自编码器（一）：原来是这么一回事[DB/OL]. https://spaces.ac.cn/archives/5253, 2018-08-14. [2] 苏剑林‏. 变分自编码器（二）：从贝叶斯观点出发[DB/OL]. https://spaces.ac.cn/archives/5343, 2018-08-15. [3] 苏剑林‏. 变分自编码器（三）：这样做为什么能成？[DB/OL]. https://spaces.ac.cn/archives/5383, 2018-08-15. [4] Kingma D P, Welling M. Auto-Encoding Variational Bayes[J]. 2013. [5] Isaac Dykeman‏. Conditional Variational Autoencoders[DB/OL]. http://ijdykeman.github.io/ml/2016/12/21/cvae.html, 2018-08-15. [6] MoussaTintin. Learning Notes】变分自编码器（Variational Auto-Encoder，VAE）[DB/OL]. https://blog.csdn.net/JackyTintin/article/details/53641885, 2018-08-15. [7] AI科技大本营. 什么！你竟然还不懂变分自编码机？这个16岁的OpenAI天才实习生讲得可透彻了[DB/OL]. https://www.sohu.com/a/162863895_697750, 2018-08-26.]]></content>
      <categories>
        <category>深度学习</category>
        <category>变分自编码器</category>
      </categories>
      <tags>
        <tag>VAE</tag>
        <tag>变分自编码器</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[胶囊网络（Capsule Network）]]></title>
    <url>%2F2018%2F08%2F24%2F%E8%83%B6%E5%9B%8A%E7%BD%91%E7%BB%9C%2F</url>
    <content type="text"><![CDATA[胶囊网络的革命在于：它提出了一种新的“vector in vector out”的传递方案，并且这种方案在很大程度上是可解释的。Hinton大神的胶囊网络理解胶囊网络基本计算公式将 Capsule 称作向量神经元 (vector neuron, VN)，而普通的人工神经元叫做标量神经元 (scalar neuron, SN)，下表总结了 VN 和 SN 之间的差异： SN 从其他神经元接收输入标量，然后乘以标量权重再求和，然后将这个总和传递给某个非线性激活函数 (比如 sigmoid, tanh, Relu)，生出一个输出标量。该标量将作为下一层的输入变量。实质上，SN 可以用以下三个步骤来描述： 将输入标量 x 乘上权重 w 对加权的输入标量求和成标量 a 用非线性函数将标量 a 转化成标量 h VN 的步骤在 SN 的三个步骤前加一步： 将输入向量 u 用矩阵 W 加工成新的输入向量 U 将输入向量 U 乘上权重 c 对加权的输入向量求和成向量 s 用非线性函数将向量 s 转化成向量 v VN 和 SN 的过程总结如下图所示： 理解胶囊网络工作原理这一小节分析计算公式的工作原理，为了使问题具体化，假设： 上一层的 VN 代表眼睛 (u1), 鼻子 (u2) 和嘴巴 (u3)，称为低层特征。 下一层第 j 个的 VN 代表脸，称为高层特征。注意下一层可能还有很多别的高层特征，脸是最直观的一个。 第一步：矩阵转化 Uj|1 是根据眼睛位置来检测脸的位置 Uj|2 是根据鼻子位置来检测脸的位置 Uj|3 是根据嘴巴位置来检测脸的位置 现在，直觉应该是这样的：如果这三个低层特征 (眼睛，鼻子和嘴) 的预测指向相同的脸的位置和状态，那么出现在那个地方的必定是一张脸。如下图所示： 第二步：输入加权 这个步骤和标量神经元 SN 的加权形式有点类似。在 SN 的情况下，这些权重是通过反向传播 (backward propagation) 确定的，但是在 VN 的情况下，这些权重是使用动态路由 (dynamic routing) 确定的，具体算法见下面的动态路由小节 。本节只从高层面来解释动态路由，如下图： 在上图中，我们有一个较低级别 VNi需要“决定”它将发送输出给哪个更高级别 VN1和 VN2。它通过调整权重 ci1和 ci2来做出决定。 现在，高级别 VN1和 VN2已经接收到来自其他低级别 VN 的许多输入向量，所有这些输入都以红点和蓝点表示。 红点聚集在一起，意味着低级别 VN 的预测彼此接近 蓝点聚集在一起，意味着低级别 VN 的预测相差很远 那么，低别级 VNi应该输出到高级别 VN1还是 VN2？这个问题的答案就是动态路由的本质。由上图看出 VNi 的输出远离高级别 VN1 中的“正确”预测的红色簇 VNi 的输出靠近高级别 VN2 中的“正确”预测的红色簇 而动态路由会根据以上结果产生一种机制，来自动调整其权重，即调高 VN2相对的权重 ci2，而调低 VN1相对的权重 ci1。 第三步：加权求和这一步类似于普通的神经元的加权求和步骤，除了总和是向量而不是标量。加权求和的真正含义就是计算出第二步里面讲的红色簇心 (cluster centroid)。 第四步：非线性激活 这个公式的确是 VN 的一个创新，采用向量的新型非线性激活函数，又叫 squash 函数，姑且翻译成“压缩”函数。这个函数主要功能是使得 vj 的长度不超过 1，而且保持 vj和 sj同方向。 公式第一项压扁函数 如果 sj 很长，第一项约等于 1 如果 sj 很短，第一项约等于 0 公式第二项单位化向量 sj，因此第二项长度为 1 这样一来，输出向量 vj的长度是在 0 和 1 之间的一个数，因此该长度可以解释为 VN 具有给定特征的概率。 动态路由低级别 VNi 需要决定如何将其输出向量发送到高级别 VNj，它是通过改变权重 cij而实现的。首先来看看 cij的性质： 每个权重是一个非负值 对于每个低级别 VNi，所有权重 cij 的总和等于 1 对于每个低级别 VNi，权重的个数等于高级别 VN 的数量 权重由迭代动态路由 (iterative dynamic routing) 算法确定 前两个性质说明 c 符合概率概念。VN 的长度被解释为它的存在概率。VN 的方向是其特征的参数化状态。因此，对于每个低级别 VNi，其权重 cij定义了属于每个高级别 VNj 的输出的概率分布。 一言以蔽之，低级别 VN 会将其输出发送到“同意”该输出的某个高级别 VN。这是动态路由算法的本质。很绕口是吧？分析完 Hinton 论文中的动态路由算法就懂了，见截图： 算法字面解释如下： 第 1 行：这个过程用到的所有输入 - l 层的输出 Uj|i，路由迭代次数 r第 2 行：定义 bij 是 l 层 VNi 应该连接 l+1 层 VNj 的可能性，初始值为 0第 3 行：执行第 4-7 行 r 次第 4 行：对 l 层的 VNi，将 bij 用 softmax 转化成概率 cij第 5 行：对 l+1 层的 VNj，加权求和 sj第 6 行：对 l+1 层的 VNj，压缩 sj 得到 vj第 7 行：根据 Uj|i 和 vj 的关系来更新 bij算法逻辑解释如下： 第 1 行无需说明，唯一要指出的是迭代次数为 3 次，Hinton 在他论文里这样说道第 2 行初始化所有 b 为零，这是合理的。因为从第 4 行可看出，只有这样 c 才是均匀分布的，暗指“l 层 VN 到底要传送输出到 l+1 层哪个 VN 是最不确定的”第 4 行的 softmax 函数产出是非负数而且总和为 1，致使 c 是一组概率变量第 5 行的 sj 就是小节 2.3 第二步里面讲的红色簇心，可以认为是低层所有 VN 的“共识”输出第 6 行的 squash 确保向量 sj 的方向不变，但长度不超过 1，因为长度代表 VN 具有给定特征的概率第 7 行是动态路由的精华，用 Uj|i 和 vj 的点积 (dot product) 更新 bij，其中前者是 l 层 VNi对 l+1 层 VNj 的“个人”预测，而后者是所有 l 层 VN 对 l+1 层 VNj 的“共识”预测：当两者相似，点积就大，bij 就变大，低层 VNi 连接高层 VNj 的可能性就变大当两者相异，点积就小，bij 就变小，低层 VNi 连接高层 VNj 的可能性就变小下面两幅图帮助进一步理解第 7 行的含义，第一幅讲的是点积，论文中用点积来度量两个向量的相似性，当然还有很多别的度量方式。 损失函数由于 Capsule 允许多个分类同时存在，所以不能直接用传统的交叉熵 (cross-entropy) 损失，一种替代方案是用间隔损失 (margin loss) 其中， k 是分类 Tk 是分类的指示函数 (k 类存在为 1，不存在为 0) m+ 为上界，惩罚假阳性 (false positive) ，即预测 k 类存在但真实不存在，识别出来但错了 m- 为下界，惩罚假阴性 (false negative) ，即预测 k 类不存在但真实存在，没识别出来 λ 是比例系数，调整两者比重 总的损失是各个样例损失之和。论文中 m+= 0.9, m-= 0.1, λ = 0.5，用大白话说就是 如果 k 类存在，||vk|| 不会小于 0.9 如果 k 类不存在，||vk|| 不会大于 0.1 惩罚假阳性的重要性大概是惩罚假阴性的重要性的 2 倍 胶囊网络推荐阅读 标题 说明 附加 《Dynamic Routing Between Capsules》 原始论文 2017 《胶囊间的动态路由》 论文翻译 AI研习社 cifar10_cnn_capsule Keras 实现 2018 CapsNet-Tensorflow TensorFlow实现 2018 胶囊网络到底是什么东东？ 2018 如何理解和使用胶囊网络 应用 2019 Dynamic Routing Between CapsulesSara Sabour, Nicholas Frosst, Geoffrey E Hinton(Submitted on 26 Oct 2017 (v1), last revised 7 Nov 2017 (this version, v2)) A capsule is a group of neurons whose activity vector represents the instantiation parameters of a specific type of entity such as an object or an object part. We use the length of the activity vector to represent the probability that the entity exists and its orientation to represent the instantiation parameters. Active capsules at one level make predictions, via transformation matrices, for the instantiation parameters of higher-level capsules. When multiple predictions agree, a higher level capsule becomes active. We show that a discrimininatively trained, multi-layer capsule system achieves state-of-the-art performance on MNIST and is considerably better than a convolutional net at recognizing highly overlapping digits. To achieve these results we use an iterative routing-by-agreement mechanism: A lower-level capsule prefers to send its output to higher level capsules whose activity vectors have a big scalar product with the prediction coming from the lower-level capsule. Subjects: Computer Vision and Pattern Recognition (cs.CV)Cite as: arXiv:1710.09829 [cs.CV] (or arXiv:1710.09829v2 [cs.CV] for this version) 参考文献[1] 王圣元‏.看完这篇，别说你还不懂Hinton大神的胶囊网络[DB/OL]. http://www.sohu.com/a/226611009_633698, 2018-08-24.]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>胶囊网络</tag>
        <tag>Capsule Network</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[Beginning Application Development with TensorFlow and Keras（路易斯卡佩罗）]]></title>
    <url>%2F2018%2F08%2F09%2FBeginning_Application_Development_with_TensorFlow_and_Keras%2F</url>
    <content type="text"><![CDATA[阅读和下载地址PDF书籍配套代码GitHub代码整理Jupyter nbviewer购买地址《Beginning Application Development with TensorFlow and Keras》| Luis Capelo | May 2018 | Packt 读书笔记 前言这本书是你的指南将TensorFlow和Keras模型部署到实际应用程序中。 本书首先介绍了如何构建应用程序的专用蓝图产生预测。每个后续课程都会解决一个问题模型的类型，例如神经网络，配置深度学习环境，使用Keras并着重于三个重要问题：该模型如何工作，如何提高我们的预测准确性，以及如何使用它来衡量和评估其性能现实世界的应用程序。在本书中，您将学习如何创建生成的应用程序来自深度学习的预测。这个学习之旅从探索开始神经网络的共同组成部分及其必要条件性能。在课程结束时，您将探索训练有素的神经使用TensorFlow创建的网络。在剩下的课程中，你会学习构建一个包含不同组件的深度学习模型并测量他们在预测中的表现。最后，我们将能够部署一个有效的Web应用程序到本书结束时。 本书内容Lesson 1, Introduction to Neural Networks and Deep Learning, helps you set up and configure deep learning environment and start looking at individual models and case studies. It also discusses neural networks and its idea along with their origins and explores their power. Lesson 2, Model Architecture, shows how to predict Bitcoin prices using deep learning model. Lesson 3, Model Evaluation and Optimization, shows on how to evaluate a neural network model. We will modify the network’s hyperparameters to improve its performance. Lesson 4, Productization explains how to productize a deep learning model and also provides an exercise of how to deploy a model as a web application. Chapter 1. Introduction to Neural Networks and Deep LearningWhat are Neural Networks?Neural networks—also known as Artificial Neural Networks—were first proposed in the 40s by MIT professors Warren McCullough and Walter Pitts. For more information refer, Explained: Neural networks. MIT News Office, April 14, 2017. Available at: http://news.mit.edu/2017/explained-neural-networks-deep-learning-0414. Successful ApplicationsTranslating text: In 2017, Google announced that it was releasing a new algorithm for its translation service called Transformer. The algorithm consisted of a recurrent neural network (LSTM) that is trained used bilingual text. Google showed that its algorithm had gained notable accuracy when comparing to industry standards (BLEU) and was also computationally efficient. Google Research Blog. Transformer: A Novel Neural Network Architecture for Language Understanding. August 31, 2017. Available at: https://research.googleblog.com/2017/08/transformer-novel-neural-network.html. Self-driving vehicles: Uber, NVIDIA, and Waymo are believed to be using deep learning models to control different vehicle functions that control driving. Alexis C. Madrigal: Inside Waymo’s Secret World for Training Se Driving Cars. The Atlantic. August 23, 2017. Available https://www.theatlantic.com/technology/archive/2017/08/inside-waymos-secret-testing-and-simulation-facilities/537648/“&gt;lities/537648/.NVIDIA: End-to-End Deep Learning for Self-Driving Cars. Augu 17, 2016. Available https://devblogs.nvidia.com/parallelforall/deep-learning-self-driving-cars/.Dave Gershgorn: Uber’s new AI team is looking for the shorte route to self-driving cars. Quartz. December 5, 2016. Available https://qz.com/853236/ubers-new-ai-team-is-looking-for-the-shortest-route-to-self-driving-cars/. Image recognition: Facebook and Google use deep learning models to identify entities in images and automatically tag these entities as persons from a set of contacts. Why Do Neural Networks Work So Well?Neural networks are powerful because they can be used to predict any given function with reasonable approximation. If one is able to represent a problem as a mathematical function and also has data that represents that function correctly, then a deep learning model can, in principle—and given enough resources—be able to approximate that function. This is typically called the universality principle of neural networks. For more information refer, Michael Nielsen: Neural Networks and Deep Learning: A visual proof that neural nets can compute any function. Available at: http://neuralnetworksanddeeplearning.com/chap4.html. Representation Learningneural networks are computation graphs in which each step computes higher abstraction representations from input data. Each one of these steps represents a progression into a different abstraction layer. Data progresses through these layers, building continuously higher-level representations. The process finishes with the highest representation possible: the one the model is trying to predict. Function ApproximationWhen neural networks learn new representations of data, they do so by combining weights and biases with neurons from different layers. However, there are many reasons why a neural network may not be able to predict a function with perfection, chief among them being that: Many functions contain stochastic properties (that is, random properties) There may be overfitting to peculiarities from the training data There may be a lack of training data Limitations of Deep LearningDeep learning techniques are best suited to problems that can be defined with formal mathematical rules (that is, as data representations). If a problem is hard to define this way, then it is likely that deep learning will not provide a useful solution. Remember that deep learning algorithms are learning different representations of data to approximate a given function. If data does not represent a function appropriately, it is likely that a function will be incorrectly represented by a neural network. To avoid this problem, make sure that the data used to train a model represents the problem the model is trying to address as accurately as possible. Inherent Bias and Ethical Considerations Researchers have suggested that the use of the deep learning model without considering the inherent bias in the training data can lead not only to poor performing solutions, but also to ethical complications. Common Components and Operations of Neural NetworksNeural networks have two key components: layers and nodes.Nodes are responsible for specific operations, and layers are groups of nodes used to differentiate different stages of the system.节点负责特定的操作，而层是用来区分系统不同阶段的节点组。 Nodes are where data is represented in the network. There are two values associated with nodes: biases and weights. Both of these values affect how data is represented by the nodes and passed on to other nodes. Unfortunately, there isn’t a clear rule for determining how many layers or nodes a network should have. Configuring a Deep Learning EnvironmentActivity 1 – Verifying Software Components 函数名 作用 启发 __separator 打印规整的分隔符 test_python 测试 Python 版本是否符合要求 test_tensorflow 测试 TensorFlow 版本是否符合要求 测试其它第三方库时也可以用此方法 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273def __separator(c): """ Prints a pretty separator. Parameters ---------- c: str Character to use. """ print(c * 65)def test_python(): """ Tests if Python 3 is installed. """ message = None if sys.version_info[0] == 3: success = True log = """ PASS: Python 3.0 (or higher) is installed. """ else: success = False log = """ FAIL: Python 3.0 (or higher) not detected. """ message = """ https://www.python.org/downloads/ """ print(log) if message: print(message) __separator('~') return successdef test_tensorflow(): """ Tests if TensorFlow is installed. """ message = None try: import tensorflow if tensorflow.__version__ &gt;= '1.4.0': success = True log = """ PASS: TensorFlow 1.4.0 (or higher) is installed. """ else: success = False log = """ FAIL: TensorFlow 1.4.0 (or higher) not detected. """ message = """ https://www.tensorflow.org/install/ """ except ModuleNotFoundError: success = False log = """ FAIL: TensorFlow 1.4.0 (or higher) not detected. """ message = """ https://www.tensorflow.org/install/ """ print(log) if message: print(message) __separator('~') return success Activity_2_mnistmnist-demo Chapter 2. Model ArchitectureOlder architectures have been used to solve a large array of problems and are generally considered the right choice when starting a new project. Newer architectures have shown great successes in specific problems, but are harder to generalize. The latter are interesting as references of what to explore next, but are hardly a good choice when starting a project. Choosing the Right Model Architecture Table 1: Different neural network architectures have shown success indifferent fields. The networks’ architecture is typically related to the Data NormalizationBefore building a deep learning model, one more step is necessary: data normalization. Data normalization is a common practice in machine learning systems. Particularly regarding neural networks, researchers have proposed that normalization is an essential technique for training RNNs (and LSTMs), mainly because it decreases the network’s training time and increases the network’s overall performance. For more information refer, Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift by Sergey Ioffe et. al., arXiv, March 2015. Available at: https://arxiv.org/abs/1502.03167. Z-scoreWhen data is normally distributed (that is, Gaussian), one can compute the distance between each observation as a standard deviation from its mean. This normalization is useful when identifying how distant data points are from more likely occurrences in the distribution. The Z-score is defined by: Z_i=\dfrac{x_i-\mu}{\sigma}Here, $x_i$ is the $i^{th}$ observation, $\mu$ is the mean, and $\sigma$ is the stand deviation of the series. Point-Relative NormalizationThis normalization computes the difference of a given observation in relation to the first observation of the series. This kind of normalization is useful to identify trends in relation to a starting point. The point-relative normalization is defined by: n_i=(\dfrac{O_i}{O_o})-1Here, $O_i$ is the $i^{th}$ observation, $O_o$ is the first observation of the series. Maximum and Minimum NormalizationThis normalization computes the distance between a given observation and the maximum and minimum values of the series. This normalization is useful when working with series in which the maximum and minimum values are not outliers and are important for future predictions. This normalization technique can be applied with: n_i=\dfrac{O_i - min(O}{max(O)-min(O}Here, $O_i$ is the $i^{th}$ observation,ation, $O$ represents a vector with all $O$ values, and the functions $min(O)$ and $max(O)$ represent the minimum and maximum values of the series, respectively. Structuring Your ProblemCompared to researchers, practitioners spend much less time determining which architecture to choose when starting a new deep learning project. Acquiring data that represents a given problem correctly is the most important factor to consider when developing these systems, followed by the understanding of the dataset’s inherent biases and limitations. Figure 5: Decision-tree of key reflection questions to be made at the beginning of a deep learning project Activity 3 – Exploring the Bitcoin Dataset and Preparing Data for Model1bitcoin = pd.read_csv('data/bitcoin_historical_prices.csv') Our dataset contains 7 variables (i.e. columns). Here’s what each one of them represents: date: date of the observation. iso_week: week number of a given year. open: open value of a single Bitcoin coin. high: highest value achieved during a given day period. low: lowest value achieved during a given day period. close: value at the close of the transaction day. volume: what is the total volume of Bitcoin that was exchanged during that day. market_capitalization: as described in CoinMarketCap’s FAQ page, this is calculated by Market Cap = Price X Circulating Supply. All values are in USD. ExplorationWe will now explore the dataset timeseries to understand its patterns. Let’s first explore two variables: close price and volume. Volume only contains data starting in November 2013, while close prices start earlier in April of that year. However, both show similar spiking patterns starting at the beginning of 2017. 1bitcoin.set_index('date')['close'].plot(linewidth=2, figsize=(14, 4), color='#d35400') &lt;matplotlib.axes._subplots.AxesSubplot at 0x8869048&gt; Now let’s explore the yera of 2017 only. This is the year where the price of bitcoin has risen significantly. 12bitcoin[bitcoin['date'] &gt;= '2017-01-01'].set_index('date')['close'].plot( linewidth=2, figsize=(14, 4), color='#d35400') &lt;matplotlib.axes._subplots.AxesSubplot at 0x8b50048&gt; Preparing Dataset for ModelNeural networks typically work with either matrices) or tensors. Our data needs to fit that structure before it can be used by either keras (or tensorflow). Also, it is common practice to normalize data before using it to train a neural network. We will be using a normalization technique the evaluates each observation into a range between 0 and 1 in relation to the first observation in each week. 1bitcoin.head() .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } date iso_week open high low close volume market_capitalization 0 2013-04-28 2013-17 135.30 135.98 132.10 134.21 NaN 1.500520e+09 1 2013-04-29 2013-17 134.44 147.49 134.00 144.54 NaN 1.491160e+09 2 2013-04-30 2013-17 144.00 146.93 134.05 139.00 NaN 1.597780e+09 3 2013-05-01 2013-17 139.00 139.89 107.72 116.99 NaN 1.542820e+09 4 2013-05-02 2013-17 116.38 125.60 92.28 105.21 NaN 1.292190e+09 First, let’s remove data from older periods. We will keep only data from 2016 until the latest observation of 2017. Older observations may be useful to understand current prices. However, Bitcoin has gained so much popularity in recent years that including older data would require a more laborious treatment. We will leave that for a future exploration. 1bitcoin_recent = bitcoin[bitcoin['date'] &gt;= '2016-01-01'] Let’s keep only the close and volume variables. We can use the other variables in another time. 1bitcoin_recent = bitcoin_recent[['date', 'iso_week', 'close', 'volume']] Now, let’s normalize our data for both the close and volume variables. 12bitcoin_recent['close_point_relative_normalization'] = bitcoin_recent.groupby('iso_week')['close'].apply( lambda x: normalizations.point_relative_normalization(x)) 12bitcoin_recent.set_index('date')['close_point_relative_normalization'].plot( linewidth=2, figsize=(14, 4), color='#d35400') &lt;matplotlib.axes._subplots.AxesSubplot at 0xb81d160&gt; Using Keras as a TensorFlow InterfaceKeras simplifies the interface for working with different architectures by using three components - network architecture, fit, and predict: Figure 15: The Keras neural network paradigm: A. design a neural network architecture, B. Train a neural network (or Fit), and C. Make predictions Activity 4 – Creating a TensorFlow Model Using Keras1234567891011121314# build_modelmodel = Sequential()model.add(LSTM( units=period_length, batch_input_shape=(batch_size, number_of_periods, period_length), input_shape=(number_of_periods, period_length), return_sequences=False, stateful=False))model.add(Dense(units=period_length))model.add(Activation("linear"))model.compile(loss="mse", optimizer="rmsprop")## saving modelmodel.save('bitcoin_lstm_v0.h5') Activity 5 – Assembling a Deep Learning System123456789# Shaping DataX_train = data[:-1,:].reshape(1, 76, 7)Y_validation = data[-1].reshape(1, 7)# Load Modelmodel = load_model('bitcoin_lstm_v0.h5')# Make Predictions%%timehistory = model.fit(x=X_train, y=Y_validation, batch_size=32, epochs=100) Chapter 3. Model Evaluation and OptimizationParameter and HyperparameterParameters are properties that affect how a model makes predictions from data. Hyperparameters refer to how a model learns from data. Parameters can be learned from the data and modified dynamically. Hyperparameters are higher-level properties and are not typically learned from data. Table 1: Common loss functions used for classification and regression problems We learned that loss functions are key elements of neural networks, as they evaluate the performance of a network at each epoch and are the starting point for the propagation of adjustments back into layers and nodes. We also explored why some loss functions can be difficult to interpret (for instance, the MSE) and developed a strategy using two other functions—RMSE and MAPE—to interpret the predicted results from our LSTM model. Activity 6 – Creating an Active Training EnvironmentLayers and Nodes - Adding More Layersthe more layers you add, the more hyperparameters you have to tune—and the longer your network will take to train. If your model is performing fairly well and not overfitting your data, experiment with the other strategies outlined in this lesson before adding new layers to your network. Epochshe larger the date used to train your model, the more epochs it will need to achieve good performance. Activation Functions Understanding Activation Functions in Neural Networks by Avinash Sharma V, available at: https://medium.com/the-theory-of-everything/understanding-activation-functions-in-neural-networks-9491262884e0. L2 RegularizationL2 regularization (or weight decay) is a common technique for dealing with overfitting models. In some models, certain parameters vary in great magnitudes. The L2 regularization penalizes such parameters, reducing the effect of these parameters on the network. DropoutDropout is a regularization technique based on a simple question: if one randomly takes away a proportion of nodes from layers, how will the other node adapt? It turns out that the remaining neurons adapt, learning to represent patterns that were previously handled by those neurons that are missing. Activity 7: Optimizing a deep learning model12345678910111213141516171819202122232425262728293031323334# 使用 tensorboard 辅助训练的函数def train_model(model, X, Y, epochs=100, version=0, run_number=0): """ Shorthand function for training a new model. This function names each run of the model using the TensorBoard naming conventions. Parameters ---------- model: Keras model instance Compiled Keras model. X, Y: np.array Series of observations to be used in the training process. version: int Version of the model to run. run_number: int The number of the run. Used in case the same model version is run again. """ hash = random.getrandbits(128) hex_code = '%032x' % hash model_name = 'bitcoin_lstm_v&#123;version&#125;_run_&#123;run_number&#125;_&#123;hex_code&#125;'.format( version=version, run_number=run_number, hex_code=hex_code[:6]) tensorboard = TensorBoard(log_dir='./logs/&#123;&#125;'.format(model_name)) model_history = model.fit( x=X, y=Y, batch_size=1, epochs=epochs, verbose=0, callbacks=[tensorboard], shuffle=False) return model_history Chapter 4. ProductizationThis lesson focuses on how to productize a deep learning model. We use the word productize to define the creation of a software product from a deep learning model that can be used by other people and applications.We are interested in models that use new data when it becomes available, continuously learning patterns from new data and, consequently, making better predictions. We study two strategies to deal with new data: one that re-trains an existing model, and another that creates a completely new model. Then, we implement the latter strategy in our Bitcoin prices prediction model so that it can continuously predict new Bitcoin prices. Figure 1: System architecture for the web application built in this project Handling New DataModels can be trained once in a set of data and can then be used to make predictions. Such static models can be very useful, but it is often the case that we want our model to continuously learn from new data—and to continuously get better as it does so.In this section, we will discuss two strategies on how to re-train a deep learning model and how to implement them in Python. Separating Data and ModelWhen building a deep learning application, the two most important areas are data and model. From an architectural point of view, we suggest that these two areas be separate. We believe that is a good suggestion because each of these areas include functions inherently separated from each other. Data is often required to be collected, cleaned, organized, and normalized; and models need to be trained, evaluated, and able to make predictions. Both of these areas are dependent, but are better dealt with separately.As a matter of following that suggestion, we will be using two classes to help us build our web application: CoinMarketCap() and Model(): CoinMarketCap(): This is a class designed for fetching Bitcoin prices from the following website: http://www.coinmarketcap.com. This is the same place where our original Bitcoin data comes from. This class makes it easy to retrieve that data on a regular schedule, returning a Pandas DataFrame with the parsed records and all available historical data. Model(): This class implements all the code we have written so far into a single class. That class provides facilities for interacting with our previously trained models, and also allows for the making of predictions using de-normalized data—which is much easier to understand. The Model() class is our model component. These two classes are used extensively throughout our example application and define the data and model components. Activity 8: Re-training a model dynamicallyAchievements]]></content>
      <categories>
        <category>Artificial Intelligence 商业实践</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>书籍</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[hands-on-ml-with-sklearn-and-tf(Aurelien Geron) 课后习题解答]]></title>
    <url>%2F2018%2F08%2F01%2FHands-on%20Machine%20Learning%20with%20Scikit-Learn%20and%20TensorFlow%20%E4%B9%A0%E9%A2%98%E8%A7%A3%E7%AD%94%2F</url>
    <content type="text"><![CDATA[本文是 《Hands-on Machine Learning with Scikit-Learn and TensorFlow 》的课后习题解答！ 把练习和答案分开是为了督促学习和思考，提倡独立思考，主动学习，而不是背答案！文章前半段中文翻译有问题的地方欢迎评论指正，英文原文在后面。 《Hands-on Machine Learning with Scikit-Learn and TensorFlow 》资源 标题 说明 附加 《Hands-on Machine Learning with Scikit-Learn and TensorFlow 》 书籍配套GItHub代码 Sklearn 与 TensorFlow 机器学习实用指南 在线阅读 CHAPTER 1 The Machine Learning Landscape练习本章中，我们学习了一些机器学习中最为重要的概念。下一章，我们会更加深入，并写一些代码。开始下章之前，确保你能回答下面的问题： 如何定义机器学习？ 机器学习可以解决的四类问题？ 什么是带标签的训练集？ 最常见的两个监督任务是什么？ 指出四个常见的非监督任务？ 要让一个机器人能在各种未知地形行走，你会采用什么机器学习算法？ 要对你的顾客进行分组，你会采用哪类算法？ 垃圾邮件检测是监督学习问题，还是非监督学习问题？ 什么是在线学习系统？ 什么是核外学习？ 什么学习算法是用相似度做预测？ 模型参数和学习算法的超参数的区别是什么？ 基于模型学习的算法搜寻的是什么？最成功的策略是什么？基于模型学习如何做预测？ 机器学习主要的挑战是什么？ 如果模型在训练集上表现好，但推广到新实例表现差，问题是什么？给出三个可能的解决方案。 什么是测试集，为什么要使用它？ 验证集的目的是什么？ 如果用测试集调节超参数，会发生什么？ 什么是交叉验证，为什么它比验证集好？ 练习解答 机器学习是关于构建可以从数据中学习的模型。学习意味着在某些任务中，根据一些绩效衡量，模型可以更好。 机器学习非常适用于： 我们没有算法解决方案的复杂问题； 可以替换手工调整规则的长列表； 构建适应波动环境的系统； 最后帮助人类学习（例如，数据挖掘） 。提示：不要把所以问题往机器学习上套，比如做网页，比如已经有高效算法的（图联通判断）。 标记的训练集是一个训练集，其中包含每个实例的所需解决方案（例如标签）。 两个最常见的监督任务是回归和分类。 常见的无监督任务包括聚类，可视化，降维和关联规则学习。 强化学习如果我们希望机器人学会在各种未知的地形中行走，那么学习可能会表现得最好，因为这通常是强化学习所解决的问题类型。有可能将问题表达为监督或半监督学习问题，但这种解决方式不太自然。 如果您不知道如何定义组，则可以使用聚类算法（无监督学习）将客户划分为类似客户的集群。但是，如果您知道您希望拥有哪些组，那么您可以将每个组的许多示例提供给分类算法（监督学习），并将所有客户分类到这些组中。 垃圾邮件检测是一种典型的监督学习问题：算法会输入许多电子邮件及其标签（垃圾邮件或非垃圾邮件）。 在线学习系统可以逐步学习，而不是批量学习系统。这使它能够快速适应不断变化的数据和自治系统，以及对大量数据的培训。 核外算法可以处理大量无法容纳在计算机主存中的数据。核心学习算法将数据分成小批量，并使用在线学习技术从这些小批量中学习。 基于实例的学习系统用心学习训练数据;然后，当给定一个新实例时，它使用相似性度量来查找最相似的学习实例并使用它们进行预测。 模型具有一个或多个模型参数，其确定在给定新实例的情况下它将预测什么（例如，线性模型的斜率）。学习算法试图找到这些参数的最佳值，以便模型很好地推广到新实例。超参数是学习算法本身的参数，而不是模型的参数（例如，要应用的正则化的量）。 基于模型的学习算法搜索模型参数的最佳值，使得模型将很好地推广到新实例。我们通常通过最小化成本函数来训练这样的系统，该成本函数测量系统在对训练数据进行预测时的糟糕程度，以及如果模型正规化则对模型复杂性的惩罚。为了进行预测，我们使用学习算法找到的参数值将新实例的特征提供给模型的预测函数。 机器学习中的一些主要挑战是缺乏数据，数据质量差，非代表性数据，无法提供信息的特征，过于简单的模型以及过度拟合训练数据的模型，以及过度复杂的模型过度拟合数据。 如果一个模型在训练数据上表现很好，但对新实例表现不佳，那么该模型可能会过度拟合训练数据（或者我们对训练数据非常幸运）。过度拟合的可能解决方案是获得更多数据，简化模型（选择更简单的算法，减少所使用的参数或特征的数量，或使模型正规化），或减少训练数据中的噪声。 测试集用于估计模型在生产中启动之前模型将对新实例进行的泛化错误。 验证集用于比较模型。它可以选择最佳模型并调整超参数。 如果使用测试集调整超参数，则存在过度拟合测试集的风险，并且您测量的泛化错误将是乐观的（您可能会启动比预期更差的模型）。 交叉验证是一种技术，可以比较模型（模型选择和超参数调整），而无需单独的验证集。这节省了宝贵的培训数据。 ExercisesIn this chapter we have covered some of the most important concepts in Machine Learning. In the next chapters we will dive deeper and write more code, but before we do, make sure you know how to answer the following questions: How would you define Machine Learning? Can you name four types of problems where it shines? What is a labeled training set? What are the two most common supervised tasks? Can you name four common unsupervised tasks? What type of Machine Learning algorithm would you use to allow a robot to walk in various unknown terrains? What type of algorithm would you use to segment your customers into multiple groups? Would you frame the problem of spam detection as a supervised learning prob‐lem or an unsupervised learning problem? What is an online learning system? What is out-of-core learning? What type of learning algorithm relies on a similarity measure to make predic‐tions? What is the difference between a model parameter and a learning algorithm’s hyperparameter? What do model-based learning algorithms search for? What is the most common strategy they use to succeed? How do they make predictions? Can you name four of the main challenges in Machine Learning? If your model performs great on the training data but generalizes poorly to new instances, what is happening? Can you name three possible solutions? What is a test set and why would you want to use it? What is the purpose of a validation set? What can go wrong if you tune hyperparameters using the test set? What is cross-validation and why would you prefer it to a validation set? Exercise Solutions Machine Learning is about building systems that can learn from data. Learning means getting better at some task, given some performance measure. Machine Learning is great for complex problems for which we have no algorith‐mic solution, to replace long lists of hand-tuned rules, to build systems that adapt to fluctuating environments, and finally to help humans learn (e.g., data mining). A labeled training set is a training set that contains the desired solution (a.k.a. a label) for each instance. The two most common supervised tasks are regression and classification. Common unsupervised tasks include clustering, visualization, dimensionality reduction, and association rule learning. Reinforcement Learning is likely to perform best if we want a robot to learn to walk in various unknown terrains since this is typically the type of problem that Reinforcement Learning tackles. It might be possible to express the problem as a supervised or semisupervised learning problem, but it would be less natural. If you don’t know how to define the groups, then you can use a clustering algo‐rithm (unsupervised learning) to segment your customers into clusters of similar customers. However, if you know what groups you would like to have, then you can feed many examples of each group to a classification algorithm (supervised learning), and it will classify all your customers into these groups. Spam detection is a typical supervised learning problem: the algorithm is fed many emails along with their label (spam or not spam). An online learning system can learn incrementally, as opposed to a batch learn‐ing system. This makes it capable of adapting rapidly to both changing data and autonomous systems, and of training on very large quantities of data. Out-of-core algorithms can handle vast quantities of data that cannot fit in a computer’s main memory. An out-of-core learning algorithm chops the data into mini-batches and uses online learning techniques to learn from these mini-batches. An instance-based learning system learns the training data by heart; then, when given a new instance, it uses a similarity measure to find the most similar learned instances and uses them to make predictions. A model has one or more model parameters that determine what it will predict given a new instance (e.g., the slope of a linear model). A learning algorithm tries to find optimal values for these parameters such that the model generalizes well to new instances. A hyperparameter is a parameter of the learning algorithm itself, not of the model (e.g., the amount of regularization to apply). Model-based learning algorithms search for an optimal value for the model parameters such that the model will generalize well to new instances. We usually train such systems by minimizing a cost function that measures how bad the sys‐tem is at making predictions on the training data, plus a penalty for model com‐plexity if the model is regularized. To make predictions, we feed the new instance’s features into the model’s prediction function, using the parameter val‐ues found by the learning algorithm. Some of the main challenges in Machine Learning are the lack of data, poor data quality, nonrepresentative data, uninformative features, excessively simple mod‐els that underfit the training data, and excessively complex models that overfit the data. If a model performs great on the training data but generalizes poorly to new instances, the model is likely overfitting the training data (or we got extremely lucky on the training data). Possible solutions to overfitting are getting more data, simplifying the model (selecting a simpler algorithm, reducing the number of parameters or features used, or regularizing the model), or reducing the noise in the training data. A test set is used to estimate the generalization error that a model will make on new instances, before the model is launched in production. A validation set is used to compare models. It makes it possible to select the best model and tune the hyperparameters. If you tune hyperparameters using the test set, you risk overfitting the test set, and the generalization error you measure will be optimistic (you may launch a model that performs worse than you expect). Cross-validation is a technique that makes it possible to compare models (for model selection and hyperparameter tuning) without the need for a separate vali‐dation set. This saves precious training data. Chapter 13: Convolutional Neural Networks练习 CNN相对于完全连接的DNN有什么优势可用于图像分类？ 考虑由三个卷积层组成的CNN，每个卷积层具有3×3个内核，步长为2，以及SAME填充。最下层输出100个特征图，中间一个输出200，顶部输出400.输入图像是200×300像素的RGB图像。 CNN中的参数总数是多少？如果我们使用32位浮点数，那么在对单个实例进行预测时，该网络至少需要多少RAM？什么时候对50个图像的小批量培训？ 如果您的GPU在训练CNN时内存不足，您可以尝试解决问题的五件事情是什么？ 为什么要添加最大池化层而不是具有相同步幅的卷积层？ 您希望何时添加本地响应规范化层？ 与LeNet-5相比，您能说出AlexNet的主要创新吗？ GoogLeNet和ResNet的主要创新如何？ 练习解答1.这是CNN相对于完全连接的DNN进行图像分类的主要优点： 因为连续的层只是部分连接，并且因为它重复使用其权重，所以CNN的参数比完全连接的DNN少得多，这使得训练速度更快，降低了过度拟合的风险，并且需要的训练数据要少得多。 当CNN学习了可以检测特定功能的内核时，它可以在图像的任何位置检测到该功能。相反，当DNN在一个位置学习一个特征时，它只能在该特定位置检测到它。由于图像通常具有非常重复的特征，因此使用较少的训练示例，CNN能够比DNN更好地用于图像处理任务（例如分类）。 最后，DNN没有关于如何组织像素的先验知识;它不知道附近的像素是否接近。 CNN的架构嵌入了这一先验知识。较低层通常识别图像的小区域中的特征，而较高层将较低层特征组合成较大特征。这适用于大多数自然图像，使CNN与DNN相比具有决定性的先机性。 让我们计算CNN有多少参数。由于其第一个卷积层具有3×3个内核，并且输入具有三个通道（红色，绿色和蓝色），因此每个特征图具有3×3×3个权重，加上偏置项。这是每个功能图的28个参数。由于该第一卷积层具有100个特征映射，因此它具有总共2,800个参数。第二卷积层具有3×3个核，其输入是前一层的100个特征映射的集合，因此每个特征映射具有3×3×100 = 900个权重，加上偏差项。由于它有200个特征图，因此该层具有901×200 = 180,200个参数。最后，第三个和最后一个卷积层也有3×3个核，其输入是前一个层的200个特征映射的集合，因此每个特征映射具有3×3×200 = 1,800个权重，加上一个偏置项。由于它有400个特征图，因此该图层总共有1,801×400 = 720,400个参数。总而言之，CNN有2,800 + 180,200 + 720,400 = 903,400个参数。现在让我们计算这个神经网络在对单个实例进行预测时需要多少RAM（至少）。首先让我们计算每一层的特征图大小。由于我们使用2和SAME填充的步幅，因此要素图的水平和垂直尺寸在每一层被除以2（必要时向上舍入），因此输入通道为200×300像素，第一层的特征地图是100×150，第二层的特征地图是50×75，第三层的特征地图是25×38。因为32位是4个字节而第一个卷积层有100个特征地图，所以第一层需要4 x 100×150×100 = 600万字节（约5.7 MB，考虑到1 MB = 1,024 KB和1 KB = 1,024字节）。第二层占用4×50×75×200 = 300万字节（约2.9MB）。最后，第三层占用4×25×38×400 = 1,520,000字节（约1.4MB）。但是，一旦计算了一个层，就可以释放前一层占用的内存，因此如果一切都经过优化，只需要6 + 9 = 1500万字节（约14.3 MB）的RAM（第二层时）刚刚计算过，但第一层占用的内存尚未释放）。但是等等，你还需要添加CNN参数占用的内存。我们之前计算过它有903,400个参数，每个参数使用4个字节，所以这增加了3,613,600个字节（大约3.4 MB）。所需的总RAM是（至少）18,613,600字节（约17.8 MB）。最后，让我们计算在50个图像的小批量训练CNN时所需的最小RAM量。在训练期间，TensorFlow使用反向传播，这需要保留在前向传递期间计算的所有值，直到反向传递开始。因此，我们必须计算单个实例的所有层所需的总RAM，并将其乘以50。那时让我们开始以兆字节而不是字节计数。我们之前计算过，每个实例的三层分别需要5.7,2.9和1.4 MB。每个实例总共10.0 MB。因此，对于50个实例，总RAM为500 MB。再加上输入图像所需的RAM，即50×4×200×300×3 = 36百万字节（约34.3 MB），加上模型参数所需的RAM，大约3.4 MB（之前计算过）加上一些用于渐变的RAM（我们将忽略它们，因为它们可以逐渐释放，因为反向传播在反向传递过程中向下传播）。我们总共大约500.0 + 34.3 + 3.4 = 537.7 MB。这真的是一个乐观的最低限度。 如果您的GPU在训练CNN时内存不足，可以尝试解决问题的五件事情（除了购买具有更多RAM的GPU）： 减少小批量。 在一个或多个图层中使用更大的步幅减少维度。 删除一个或多个图层。 使用16位浮点数而不是32位浮点数。 在多个设备上分发CNN。 最大池层根本没有参数，而卷积层有很多参数（参见前面的问题）。 局部响应归一化层使得最强烈激活的神经元在相同位置但在相邻特征图中抑制神经元，这促使不同的特征图专门化并将它们分开，迫使它们探索更广泛的特征。 它通常在较低层中使用，以具有较大的低级特征池，上层可以构建在其上。 与LeNet-5相比，AlexNet的主要创新是：（1）它更大更深，（2）它将卷积层直接叠加在一起，而不是在每个卷积层的顶部堆叠汇集层。 GoogLeNet的主要创新是引入了初始模块，这使得有可能拥有比以前的CNN架构更深的网络，参数更少。 最后，ResNet的主要创新是跳过连接的引入，这使得它可以超越100层。 可以说，它的简洁性和一致性也相当具有创新性。 Exercises What are the advantages of a CNN over a fully connected DNN for image classi‐fication? Consider a CNN composed of three convolutional layers, each with 3 × 3 kernels, a stride of 2, and SAME padding. The lowest layer outputs 100 feature maps, the middle one outputs 200, and the top one outputs 400. The input images are RGB images of 200 × 300 pixels. What is the total number of parameters in the CNN?If we are using 32-bit floats, at least how much RAM will this network require when making a prediction for a single instance? What about when training on a mini-batch of 50 images? If your GPU runs out of memory while training a CNN, what are five things you could try to solve the problem? Why would you want to add a max pooling layer rather than a convolutional layer with the same stride? When would you want to add a local response normalization layer? Can you name the main innovations in AlexNet, compared to LeNet-5? What about the main innovations in GoogLeNet and ResNet? Exercise Solutions These are the main advantages of a CNN over a fully connected DNN for image classification: Because consecutive layers are only partially connected and because it heavily reuses its weights, a CNN has many fewer parameters than a fully connected DNN, which makes it much faster to train, reduces the risk of overfitting, and requires much less training data. When a CNN has learned a kernel that can detect a particular feature, it can detect that feature anywhere on the image. In contrast, when a DNN learns a feature in one location, it can detect it only in that particular location. Since images typically have very repetitive features, CNNs are able to generalize much better than DNNs for image processing tasks such as classification, using fewer training examples. Finally, a DNN has no prior knowledge of how pixels are organized; it does not know that nearby pixels are close. A CNN’s architecture embeds this prior knowledge. Lower layers typically identify features in small areas of the images, while higher layers combine the lower-level features into larger features. This works well with most natural images, giving CNNs a decisive head start com‐pared to DNNs. Let’s compute how many parameters the CNN has. Since its first convolutional layer has 3 × 3 kernels, and the input has three channels (red, green, and blue), then each feature map has 3 × 3 × 3 weights, plus a bias term. That’s 28 parame‐ters per feature map. Since this first convolutional layer has 100 feature maps, it has a total of 2,800 parameters. The second convolutional layer has 3 × 3 kernels, and its input is the set of 100 feature maps of the previous layer, so each feature map has 3 × 3 × 100 = 900 weights, plus a bias term. Since it has 200 feature maps, this layer has 901 × 200 = 180,200 parameters. Finally, the third and last convolutional layer also has 3 × 3 kernels, and its input is the set of 200 feature maps of the previous layers, so each feature map has 3 × 3 × 200 = 1,800 weights, plus a bias term. Since it has 400 feature maps, this layer has a total of 1,801 × 400 = 720,400 parameters. All in all, the CNN has 2,800 + 180,200 + 720,400 = 903,400 parameters.Now let’s compute how much RAM this neural network will require (at least) when making a prediction for a single instance. First let’s compute the feature map size for each layer. Since we are using a stride of 2 and SAME padding, the horizontal and vertical size of the feature maps are divided by 2 at each layer (rounding up if necessary), so as the input channels are 200 × 300 pixels, the first layer’s feature maps are 100 × 150, the second layer’s feature maps are 50 × 75, and the third layer’s feature maps are 25 × 38. Since 32 bits is 4 bytes and the first convolutional layer has 100 feature maps, this first layer takes up 4 x 100 × 150 × 100 = 6 million bytes (about 5.7 MB, considering that 1 MB = 1,024 KB and 1 KB = 1,024 bytes). The second layer takes up 4 × 50 × 75 × 200 = 3 million bytes (about 2.9 MB). Finally, the third layer takes up 4 × 25 × 38 × 400 = 1,520,000 bytes (about 1.4 MB). However, once a layer has been computed, the memory occupied by the previous layer can be released, so if everything is well optimized, only 6 + 9 = 15 million bytes (about 14.3 MB) of RAM will be required (when the second layer has just been computed, but the memory occupied by the first layer is not released yet). But wait, you also need to add the memory occupied by the CNN’s parameters. We computed earlier that it has 903,400 parameters, each using up 4 bytes, so this adds 3,613,600 bytes (about 3.4 MB). The total RAM required is (at least) 18,613,600 bytes (about 17.8 MB).Lastly, let’s compute the minimum amount of RAM required when training the CNN on a mini-batch of 50 images. During training TensorFlow uses backpropa‐gation, which requires keeping all values computed during the forward pass until the reverse pass begins. So we must compute the total RAM required by all layers for a single instance and multiply that by 50! At that point let’s start counting in megabytes rather than bytes. We computed before that the three layers require respectively 5.7, 2.9, and 1.4 MB for each instance. That’s a total of 10.0 MB per instance. So for 50 instances the total RAM is 500 MB. Add to that the RAM required by the input images, which is 50 × 4 × 200 × 300 × 3 = 36 million bytes (about 34.3 MB), plus the RAM required for the model parameters, which is about 3.4 MB (computed earlier), plus some RAM for the gradients (we will neglect them since they can be released gradually as backpropagation goes down the layers during the reverse pass). We are up to a total of roughly 500.0 + 34.3 + 3.4 = 537.7 MB. And that’s really an optimistic bare minimum. If your GPU runs out of memory while training a CNN, here are five things you could try to solve the problem (other than purchasing a GPU with more RAM): Reduce the mini-batch size. Reduce dimensionality using a larger stride in one or more layers. Remove one or more layers. Use 16-bit floats instead of 32-bit floats. Distribute the CNN across multiple devices. A max pooling layer has no parameters at all, whereas a convolutional layer has quite a few (see the previous questions). A local response normalization layer makes the neurons that most strongly acti‐vate inhibit neurons at the same location but in neighboring feature maps, which encourages different feature maps to specialize and pushes them apart, forcing them to explore a wider range of features. It is typically used in the lower layers to have a larger pool of low-level features that the upper layers can build upon. The main innovations in AlexNet compared to LeNet-5 are (1) it is much larger and deeper, and (2) it stacks convolutional layers directly on top of each other, instead of stacking a pooling layer on top of each convolutional layer. The main innovation in GoogLeNet is the introduction of inception modules, which make it possible to have a much deeper net than previous CNN architectures, with fewer parameters. Finally, ResNet’s main innovation is the introduction of skip connec‐tions, which make it possible to go well beyond 100 layers. Arguably, its simplic‐ity and consistency are also rather innovative. Chapter 14: Recurrent Neural Networks练习 你能想象 seq2seq RNN 的几个应用吗？ seq2vec 的 RNN 呢？vex2seq 的 RNN 呢？ 为什么人们使用编解码器 RNN 而不是简单的 seq2seq RNN 来自动翻译？ 如何将卷积神经网络与 RNN 结合，来对视频进行分类？ 使用 dynamic_rnn() 而不是 static_rnn() 构建 RNN 有什么好处？ 你如何处理长度可变的输入序列？ 那么长度可变输出序列呢？ 在多个 GPU 上分配深层 RNN 的训练和执行的常见方式是什么？ 练习解答 以下是一些RNN应用程序： 对于序列到序列的RNN：预测天气（或任何其他时间序列），机器翻译（使用编码器 - 解码器架构），视频字幕，语音到文本，音乐生成（或其他序列生成），识别 一首歌的和弦。 对于序列到矢量RNN：按音乐类型对音乐样本进行分类，分析书评的情绪，根据大脑植入物的读数预测失语症患者正在考虑的单词，预测概率 用户希望根据她的观看历史观看电影（这是协作过滤的许多可能实现之一）。 对于矢量到序列RNN：图像字幕，基于当前艺术家的嵌入创建音乐播放列表，基于一组参数生成旋律，在图片中定位行人。 一般来说，如果你一次翻译一个单词，结果将是非常可怕的。 例如，法语句子“Je vous en prie”的意思是“欢迎你”，但如果你一次翻译一个词，你会得到“我在祷告。”嗯？ 首先阅读整个句子然后翻译它会好得多。 普通的序列到序列RNN将在读取第一个字之后立即开始翻译句子，而编码器 - 解码器RNN将首先读取整个句子然后翻译它。 也就是说，人们可以想象一个简单的序列到序列的RNN，只要不确定接下来要说什么就会输出静音（就像人类翻译者必须翻译直播时那样）。 为了基于视觉内容对视频进行分类，一种可能的架构可以是（比方说）每秒一帧，然后通过卷积神经网络运行每一帧，将CNN的输出馈送到序列到矢量RNN ，最后通过softmax层运行其输出，为您提供所有类概率。 对于培训，您只需使用交叉熵作为成本函数。 如果您也想将音频用于分类，您可以将每秒音频转换为摄谱仪，将此摄谱仪输入CNN，并将此CNN的输出馈送到RNN（以及其他CNN的相应输出））。 使用dynamic_rnn（）而不是static_rnn（）构建RNN具有以下几个优点： 它基于while_loop（）操作，该操作能够在反向传播期间将GPU的内存交换到CPU的内存，从而避免内存不足错误。 它可以说更容易使用，因为它可以直接将单个张量作为输入和输出（涵盖所有时间步骤），而不是张量列表（每个时间步长一个）。 无需堆叠，取消堆叠或转置。 它生成一个较小的图形，更容易在TensorBoard中可视化。 5.要处理可变长度输入序列，最简单的选项是在调用static_rnn（）或dynamic_rnn（）函数时设置sequence_length参数。 另一种选择是填充较小的输入（例如，用零）以使它们与最大输入相同（如果输入序列都具有非常相似的长度，则这可能比第一选项快）。 要处理可变长度输出序列，如果事先知道每个输出序列的长度，可以使用sequence_length参数（例如，考虑序列到序列的RNN，用暴力标记视频中的每一帧 得分：输出序列与输入序列的长度完全相同）。 如果您事先不知道输出序列的长度，则可以使用填充技巧：始终输出相同大小的序列，但忽略序列结束标记之后的任何输出（通过在计算时忽略它们） 成本函数）。 要在多个GPU上分发深度RNN的训练和执行，常见的技术就是将每个层放在不同的GPU上（参见第12章）。 Exercises Can you think of a few applications for a sequence-to-sequence RNN? What about a sequence-to-vector RNN? And a vector-to-sequence RNN? Why do people use encoder–decoder RNNs rather than plain sequence-to-sequence RNNs for automatic translation? How could you combine a convolutional neural network with an RNN to classify videos? What are the advantages of building an RNN using dynamic_rnn() rather than static_rnn()? How can you deal with variable-length input sequences? What about variable-length output sequences? What is a common way to distribute training and execution of a deep RNN across multiple GPUs? Exercise Solutions Here are a few RNN applications: For a sequence-to-sequence RNN: predicting the weather (or any other time series), machine translation (using an encoder–decoder architecture), video captioning, speech to text, music generation (or other sequence generation), identifying the chords of a song. For a sequence-to-vector RNN: classifying music samples by music genre, ana‐lyzing the sentiment of a book review, predicting what word an aphasic patient is thinking of based on readings from brain implants, predicting the probabil‐ity that a user will want to watch a movie based on her watch history (this is one of many possible implementations of collaborative filtering). For a vector-to-sequence RNN: image captioning, creating a music playlist based on an embedding of the current artist, generating a melody based on a set of parameters, locating pedestrians in a picture (e.g., a video frame from a self-driving car’s camera). In general, if you translate a sentence one word at a time, the result will be terri‐ble. For example, the French sentence “Je vous en prie” means “You are welcome,” but if you translate it one word at a time, you get “I you in pray.” Huh? It is much better to read the whole sentence first and then translate it. A plain sequence-to-sequence RNN would start translating a sentence immediately after reading the first word, while an encoder–decoder RNN will first read the whole sentence and then translate it. That said, one could imagine a plain sequence-to-sequence RNN that would output silence whenever it is unsure about what to say next (just like human translators do when they must translate a live broadcast). To classify videos based on the visual content, one possible architecture could be to take (say) one frame per second, then run each frame through a convolutional neural network, feed the output of the CNN to a sequence-to-vector RNN, and finally run its output through a softmax layer, giving you all the class probabili‐ties. For training you would just use cross entropy as the cost function. If you wanted to use the audio for classification as well, you could convert every second of audio to a spectrograph, feed this spectrograph to a CNN, and feed the output of this CNN to the RNN (along with the corresponding output of the other CNN). Building an RNN using dynamic_rnn() rather than static_rnn() offers several advantages: It is based on a while_loop() operation that is able to swap the GPU’s memory to the CPU’s memory during backpropagation, avoiding out-of-memory errors. It is arguably easier to use, as it can directly take a single tensor as input and output (covering all time steps), rather than a list of tensors (one per time step). No need to stack, unstack, or transpose. It generates a smaller graph, easier to visualize in TensorBoard. To handle variable length input sequences, the simplest option is to set the sequence_length parameter when calling the static_rnn() or dynamic_rnn() functions. Another option is to pad the smaller inputs (e.g., with zeros) to make them the same size as the largest input (this may be faster than the first option if the input sequences all have very similar lengths). To handle variable-length out‐put sequences, if you know in advance the length of each output sequence, you can use the sequence_length parameter (for example, consider a sequence-to-sequence RNN that labels every frame in a video with a violence score: the output sequence will be exactly the same length as the input sequence). If you don’t know in advance the length of the output sequence, you can use the padding trick: always output the same size sequence, but ignore any outputs that come after the end-of-sequence token (by ignoring them when computing the cost function). To distribute training and execution of a deep RNN across multiple GPUs, a common technique is simply to place each layer on a different GPU (see Chap‐ter 12). Chapter 15: Autoencoders练习 自动编码器使用的主要任务是什么？ 假设你想训练一个分类器，你有很多未标记的训练数据，但是只有几千个标记的实例。自动编码器如何帮助？你将如何进行？ 如果一个自动编码器完美地重建输入，它一定是好的吗？自动编码器？如何评价自动编码器的性能？ 什么是欠完备和过完备的自动编码器？过度完备的自动编码器的主要风险是什么？超完备自动编码器的主要风险是什么？ 如何在堆叠式自动编码器中系紧砝码？这样做有什么意义呢？ 什么是一种常见的技术来可视化的特点，学习下层的堆叠自动编码器？更高层怎么办？ 什么是生成模型？你能说出一种生成式自动编码器吗？ 练习解答 以下是自动编码器用于的一些主要任务： 特征提取 无人监督的预训练 维度降低 生成模型 异常检测（自动编码器通常不利于重建异常值） 如果你想训练一个分类器，你有大量的未标记的训练数据，但是只有几千个标记的实例，那么你可以首先在完整的数据集（标记和未标记）上训练一个深度的自动编码器，然后再将其下半部分用于分类器（即，重复使用编码层）。编码层，包括使用标记数据训练分类器。如果您的标记数据很少，则可能需要在训练分类器时冻结重复使用的层。 自动编码器完美地重建其输入的事实并不一定如此意味着它是一个很好的自动编码器;也许它只是一个过度完整的自动编码器学会了将其输入复制到编码层然后再输出到输出。实际上，即使编码层包含单个神经元，也是可能的对于一个非常深的自动编码器来学习将每个训练实例映射到不同的编码（例如，第一个实例可以映射到0.001，第二个实例可以映射到0.002，即第三到0.003，等等），它可以“用心”学习重建右边每个编码的训练实例。它将完美地重建其输入没有真正学习数据中任何有用的模式。在实践中这样的映射不太可能发生，但它说明了完美的重建不是这样的事实保证自动编码器学到了什么有用的东西。但是，如果它产生非常糟糕的重建，然后它几乎保证是一个糟糕的自动编码器。为了评估自动编码器的性能，一种选择是测量重建损失（例如，计算MSE，输出的均方值）减去输入）。再次，高重建损失是一个很好的迹象自动编码器很糟糕，但重建损失很小并不能保证好。您还应该根据它将使用的内容来评估自动编码器对于。例如，如果您将其用于无人监督的分类器预训练，那么你还应该评估分类器的性能。 欠完全自动编码器是一种编码层小于编码层的编码器输入和输出层。 如果它更大，那么它是一个过完备的自动编码器。欠完全自动编码器的主要风险是它可能无法完成重建输入。 过度完整的自动编码器的主要风险是它可能只是将输入复制到输出，而不学习任何有用的功能。 要将编码器层及其相应解码器层的权重联系起来简单地使解码器权重等于编码器权重的转置。这会将模型中的参数数量减少一半，通常会进行培训通过较少的训练数据更快地收敛，并降低过度拟合的风险训练集。 为了可视化由堆叠自动编码器的下层学习的特征，通常的技术是通过将每个权重向量重新整形为输入图像的大小来简单地绘制每个神经元的权重（例如，对于MNIST，重塑一个权重向量）。 形状[784]至[28,28]）。 为了可视化更高层学习的特征，一种技术是显示最能激活每个神经元的训练实例。 生成模型是能够随机生成类似于训练实例的输出的模型。 例如，一旦在MNIST数据集上成功训练，生成模型可用于随机生成数字的真实图像。 输出分布通常类似于训练数据。 例如，由于MNIST包含每个数字的许多图像，因此生成模型将输出大致相同数量的每个数字的图像。 一些生成模型可以参数化。例如，仅生成某种输出。 生成自动编码器的一个例子是变分自动编码器。 Exercise What are the main tasks that autoencoders are used for? Suppose you want to train a classifier and you have plenty of unlabeled training data, but only a few thousand labeled instances. How can autoencoders help? How would you proceed? If an autoencoder perfectly reconstructs the inputs, is it necessarily a good autoencoder? How can you evaluate the performance of an autoencoder? What are undercomplete and overcomplete autoencoders? What is the main risk of an excessively undercomplete autoencoder? What about the main risk of an overcomplete autoencoder? How do you tie weights in a stacked autoencoder? What is the point of doing so? What is a common technique to visualize features learned by the lower layer of a stacked autoencoder? What about higher layers? What is a generative model? Can you name a type of generative autoencoder? Exercise Solutions Here are some of the main tasks that autoencoders are used for: Feature extraction Unsupervised pretraining Dimensionality reduction Generative models Anomaly detection (an autoencoder is generally bad at reconstructing outliers) If you want to train a classifier and you have plenty of unlabeled training data, but only a few thousand labeled instances, then you could first train a deep autoencoder on the full dataset (labeled + unlabeled), then reuse its lower half for the classifier (i.e., reuse the layers up to the codings layer, included) and train the classifier using the labeled data. If you have little labeled data, you probably want to freeze the reused layers when training the classifier. The fact that an autoencoder perfectly reconstructs its inputs does not necessarily mean that it is a good autoencoder; perhaps it is simply an overcomplete autoen‐coder that learned to copy its inputs to the codings layer and then to the outputs. In fact, even if the codings layer contained a single neuron, it would be possible for a very deep autoencoder to learn to map each training instance to a different coding (e.g., the first instance could be mapped to 0.001, the second to 0.002, the third to 0.003, and so on), and it could learn “by heart” to reconstruct the right training instance for each coding. It would perfectly reconstruct its inputs without really learning any useful pattern in the data. In practice such a mapping is unlikely to happen, but it illustrates the fact that perfect reconstructions are not a guarantee that the autoencoder learned anything useful. However, if it produces very bad reconstructions, then it is almost guaranteed to be a bad autoencoder. To evaluate the performance of an autoencoder, one option is to measure the reconstruction loss (e.g., compute the MSE, the mean square of the outputs minus the inputs). Again, a high reconstruction loss is a good sign that the autoencoder is bad, but a low reconstruction loss is not a guarantee that it is good. You should also evaluate the autoencoder according to what it will be used for. For example, if you are using it for unsupervised pretraining of a classifier, then you should also evaluate the classifier’s performance. An undercomplete autoencoder is one whose codings layer is smaller than the input and output layers. If it is larger, then it is an overcomplete autoencoder. The main risk of an excessively undercomplete autoencoder is that it may fail to reconstruct the inputs. The main risk of an overcomplete autoencoder is that it may just copy the inputs to the outputs, without learning any useful feature. To tie the weights of an encoder layer and its corresponding decoder layer, you simply make the decoder weights equal to the transpose of the encoder weights. This reduces the number of parameters in the model by half, often making train‐ing converge faster with less training data, and reducing the risk of overfitting the training set. To visualize the features learned by the lower layer of a stacked autoencoder, a common technique is simply to plot the weights of each neuron, by reshaping each weight vector to the size of an input image (e.g., for MNIST, reshaping a weight vector of shape [784] to [28, 28]). To visualize the features learned by higher layers, one technique is to display the training instances that most activate each neuron. A generative model is a model capable of randomly generating outputs that resemble the training instances. For example, once trained successfully on the MNIST dataset, a generative model can be used to randomly generate realistic images of digits. The output distribution is typically similar to the training data. For example, since MNIST contains many images of each digit, the generative model would output roughly the same number of images of each digit. Some generative models can be parametrized—for example, to generate only some kinds of outputs. An example of a generative autoencoder is the variational autoencoder. Chapter 16: Reinforcement Learning练习1.您如何定义强化学习？ 它与常规监督或无监督学习有什么不同？2.您能想到本章未提及的RL的三种可能应用吗？ 对于他们每个人来说，环境是什么？ 代理商是什么？可能的行动是什么？ 有什么奖励？3.折扣率是多少？ 如果修改计数率，最优政策会改变吗？4.您如何衡量强化学习代理的表现？5.什么是信用分配问题？ 什么时候发生？ 你怎么能减轻它？6.使用重放内存有什么意义？7.什么是非策略RL算法？ 练习解答 强化学习是机器学习的一个领域，旨在创建能够以最大化奖励的方式在环境中采取行动的代理。 RL与常规监督和无监督学习之间存在许多差异。以下是一些： 在有监督和无监督学习中，目标通常是在数据中找到模式。在强化学习中，目标是找到一个好的策略。 与监督学习不同，代理人没有明确给出“正确”的答案。它必须通过反复试验来学习。 与无监督学习不同，通过奖励有一种监督形式。我们不会告诉代理如何执行任务，但我们会告诉它何时进行任务或何时失败。 强化学习代理需要在探索环境，寻找获得奖励的新方法以及利用已经知道的奖励来源之间找到适当的平衡点。相比之下，有监督和无监督的学习系统通常不需要担心探索;他们只是根据他们给出的训练数据。 在有监督和无监督的学习中，训练实例通常是独立的（事实上，它们通常是洗牌的）。在强化学习中，连续观察通常不是独立的。在移动之前，代理可能会在环境的同一区域停留一段时间，因此连续的观察将非常相关。在某些情况下，使用重放存储器来确保训练算法获得相当独立的观察。 除了第16章中提到的那些之外，以下是强化学习的一些可能应用： 音乐个性化 环境是用户的个性化网络电台。代理是决定该用户接下来要播放的歌曲的软件。其可能的行动是播放目录中的任何歌曲（它必须尝试选择用户将喜欢的歌曲）或播放广告（它必须尝试选择用户将被介入的广告）。每次用户收听歌曲时获得小奖励，每次用户收听广告时获得更大奖励，当用户跳过歌曲或广告时获得负奖励，如果用户离开则获得非常负面奖励。 营销 环境是贵公司的营销部门。代理商是一个软件，根据他们的个人资料和购买历史记录定义应向哪些客户发送邮件活动（对于每个客户，它有两个可能的操作：发送或不发送）。它会对邮寄广告系列的费用产生负面回报，并对此广告系列产生的估算收入产生积极回报。 产品交付 让代理商控制一批运货卡车，决定他们应该在油库接收什么，他们应该去哪里，他们应该放下什么，等等。对于按时交付的每种产品，他们都会得到积极的回报，对于延迟交付，他们会得到负面的回报。 在估算行动的价值时，强化学习算法通常会将此行为带来的所有奖励加起来，给予即时奖励更多的权重，减少后期奖励的权重（考虑到行动对近期的影响大于在遥远的未来）。为了对此进行建模，通常在每个时间步应用折扣率。例如，在折扣率为0.9的情况下，当您估算行动的价值时，两个时间段后收到的100的奖励仅计为0.92×100 = 81。您可以将计算率视为衡量未来相对于现在的估值程度的指标：如果它非常接近1，那么未来的估值几乎与现在一样多。如果它接近0，那么只有直接奖励很重要。当然，这极大地影响了最优政策：如果你重视未来，你可能愿意为最终奖励的前景忍受很多直接的痛苦，而如果你不重视未来，你就会抓住您可以找到的任何直接奖励，永远不会投资于未来。 要衡量强化学习代理的表现，您可以简单地总结其获得的奖励。 在模拟环境中，您可以运行许多epi-sodes并查看平均得到的总奖励（并且可能会查看最小值，最大值，标准差等）。 信用分配问题是，当强化学习代理收到奖励时，它无法直接了解其先前的哪些行为对此奖励有贡献。 它通常发生在一个动作与所产生的奖励之间存在很大的延迟时（例如，在Atari的乒乓球比赛期间，在球员击球之前和赢得该球的那一刻之间可能会有几十个时间步长）。 减轻它的一种方法是在可能的情况下为代理人提供短期奖励。 这通常需要有关任务的先验知识。 例如，如果我们想要建立一个学会下棋的代理人，而不是仅在它赢得比赛时给予奖励，我们可以在每次捕获对手的棋子时给予奖励。 代理人通常可以在一段时间内保持在其环境的同一区域，因此在这段时间内，它的所有经验都非常相似。 这可以在学习算法中引入一些偏差。 它可能会调整这个环境区域的政策，但一旦离开这个区域就不会表现良好。 要解决此问题，您可以使用重放内存; 代理人不会仅使用最直接的学习经验，而是根据过去经验的缓冲来学习，最近也不是最近的经历（也许这就是为什么我们在晚上做梦：重播我们当天的经历并更好地学习 他们？）。 非策略RL算法学习最优策略的值（即，如果代理最佳地行为，则可以为每个状态预期的折扣奖励的总和），而与代理实际行为的方式无关。 Q-Learning是这种算法的一个很好的例子。 相反，on-policy算法学习代理实际执行的策略的值。 Exercises How would you define Reinforcement Learning? How is it different from regular supervised or unsupervised learning? Can you think of three possible applications of RL that were not mentioned in this chapter? For each of them, what is the environment? What is the agent?What are possible actions? What are the rewards? What is the discount rate? Can the optimal policy change if you modify the dis‐count rate? How do you measure the performance of a Reinforcement Learning agent? What is the credit assignment problem? When does it occur? How can you allevi‐ate it? What is the point of using a replay memory? What is an off-policy RL algorithm? Exercise Solutions Reinforcement Learning is an area of Machine Learning aimed at creating agents capable of taking actions in an environment in a way that maximizes rewards over time. There are many differences between RL and regular supervised and unsupervised learning. Here are a few: In supervised and unsupervised learning, the goal is generally to find patterns in the data. In Reinforcement Learning, the goal is to find a good policy. Unlike in supervised learning, the agent is not explicitly given the “right” answer. It must learn by trial and error. Unlike in unsupervised learning, there is a form of supervision, through rewards. We do not tell the agent how to perform the task, but we do tell it when it is making progress or when it is failing. A Reinforcement Learning agent needs to find the right balance between exploring the environment, looking for new ways of getting rewards, and exploiting sources of rewards that it already knows. In contrast, supervised and unsupervised learning systems generally don’t need to worry about explora‐tion; they just feed on the training data they are given. In supervised and unsupervised learning, training instances are typically inde‐pendent (in fact, they are generally shuffled). In Reinforcement Learning, con‐secutive observations are generally not independent. An agent may remain in the same region of the environment for a while before it moves on, so consecu‐tive observations will be very correlated. In some cases a replay memory is used to ensure that the training algorithm gets fairly independent observa‐tions. Here are a few possible applications of Reinforcement Learning, other than those mentioned in Chapter 16: Music personalization The environment is a user’s personalized web radio. The agent is the software deciding what song to play next for that user. Its possible actions are to play any song in the catalog (it must try to choose a song the user will enjoy) or to play an advertisement (it must try to choose an ad that the user will be inter‐ested in). It gets a small reward every time the user listens to a song, a larger reward every time the user listens to an ad, a negative reward when the user skips a song or an ad, and a very negative reward if the user leaves. Marketing The environment is your company’s marketing department. The agent is the software that defines which customers a mailing campaign should be sent to, given their profile and purchase history (for each customer it has two possi‐ble actions: send or don’t send). It gets a negative reward for the cost of the mailing campaign, and a positive reward for estimated revenue generated from this campaign. Product delivery Let the agent control a fleet of delivery trucks, deciding what they should pick up at the depots, where they should go, what they should drop off, and so on. They would get positive rewards for each product delivered on time, and negative rewards for late deliveries. When estimating the value of an action, Reinforcement Learning algorithms typ‐ically sum all the rewards that this action led to, giving more weight to immediate rewards, and less weight to later rewards (considering that an action has more influence on the near future than on the distant future). To model this, a discount rate is typically applied at each time step. For example, with a discount rate of 0.9, a reward of 100 that is received two time steps later is counted as only 0.92 × 100 = 81 when you are estimating the value of the action. You can think of the dis‐count rate as a measure of how much the future is valued relative to the present: if it is very close to 1, then the future is valued almost as much as the present. If it is close to 0, then only immediate rewards matter. Of course, this impacts the optimal policy tremendously: if you value the future, you may be willing to put up with a lot of immediate pain for the prospect of eventual rewards, while if you don’t value the future, you will just grab any immediate reward you can find, never investing in the future. To measure the performance of a Reinforcement Learning agent, you can simply sum up the rewards it gets. In a simulated environment, you can run many epi‐sodes and look at the total rewards it gets on average (and possibly look at the min, max, standard deviation, and so on). The credit assignment problem is the fact that when a Reinforcement Learning agent receives a reward, it has no direct way of knowing which of its previous actions contributed to this reward. It typically occurs when there is a large delay between an action and the resulting rewards (e.g., during a game of Atari’s Pong, there may be a few dozen time steps between the moment the agent hits the ball and the moment it wins the point). One way to alleviate it is to provide the agent with shorter-term rewards, when possible. This usually requires prior knowledge about the task. For example, if we want to build an agent that will learn to play chess, instead of giving it a reward only when it wins the game, we could give it a reward every time it captures one of the opponent’s pieces. An agent can often remain in the same region of its environment for a while, so all of its experiences will be very similar for that period of time. This can intro‐duce some bias in the learning algorithm. It may tune its policy for this region of the environment, but it will not perform well as soon as it moves out of this region. To solve this problem, you can use a replay memory; instead of using only the most immediate experiences for learning, the agent will learn based on a buffer of its past experiences, recent and not so recent (perhaps this is why we dream at night: to replay our experiences of the day and better learn from them?). An off-policy RL algorithm learns the value of the optimal policy (i.e., the sum of discounted rewards that can be expected for each state if the agent acts opti‐mally), independently of how the agent actually acts. Q-Learning is a good exam‐ple of such an algorithm. In contrast, an on-policy algorithm learns the value of the policy that the agent actually executes, including both exploration and exploi‐tation.]]></content>
      <categories>
        <category>机器学习</category>
      </categories>
  </entry>
  <entry>
    <title><![CDATA[四川大学研究生软件项目管理期末考试分析]]></title>
    <url>%2F2018%2F07%2F09%2F%E5%9B%9B%E5%B7%9D%E5%A4%A7%E5%AD%A6%E7%A0%94%E7%A9%B6%E7%94%9F%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E6%9C%9F%E6%9C%AB%E8%80%83%E8%AF%95%E5%88%86%E6%9E%90%2F</url>
    <content type="text"><![CDATA[目标 Understanding the role of software project management in software development Understanding why software project management practices are important Knowing good basic software project management practices Possessing basic skills using software management tools and practices Having applied those skills in software developing with realistic challenges 理解软件项目管理在软件开发中的作用理解为什么软件项目管理实践很重要了解良好的基本软件项目管理实践拥有使用软件管理工具和实践的基本技能将这些技能应用到软件开发中，并具有现实的挑战 Course outline (24 hours) week 1: Introduction of Software Project Management week 2: Project evaluation and programme management week 3: Overview of project planning &amp; Selection of project approach week 4: Software effort estimation week 5: Activity planning week 6: Risk management week 7: Resource allocation week 8: Monitoring and control: contracts, people, team, and quality week 9-17: Team work week 18: Finial Exam 第1周：软件项目管理的引入第2周：项目评估和方案管理第3周：项目规划和项目方法选择的概述第4周：软件工作评估星期5:活动计划第6周:风险管理第七周:资源分配第8周：监控和控制：合同、人员、团队和质量上行线周:团队合作精神18周:顶尖考试 week 2:Project evaluation and programme management项目评估和方案管理We plan to invest 5000 for a project and wish to get 12500 profit after five years. Suppose that there is 2500 profit for every year and the interest rate is 12%. Please compute the NPV and DPBP for the project.我们计划为一个项目投资5000美元，并希望在五年后获得12500美元的利润。 假设每年有2500美元的利润，利率为12％。 请计算项目的NPV和DPBP。 Year Cash-flow Discount Factor Discount cash flow 0 -5000 1.0000 -5000 1 2500 0.8929 2232.14 2 2500 0.7972 1992.98 3 2500 0.7118 1779.45 4 2500 0.6355 1588.84 5 2500 0.5674 1418.53 NP 7500 NPV 4011.94 净利润 $\text{NP(Net profit)}=sum(\text{cash-flow})=7500$ 年平均利润 $\text{average annual profit}=\dfrac{NP}{years}=\dfrac{7500}{5}=1500$ 投资回报率 $\text{ROI(Return on investment )}=\dfrac{\text{Average annual profit}}{\text{Total investment}}=\dfrac{1500}{10000}=0.15$ 折扣因子 Discount factor$\text{Discount factor}=1 / {(1+r)}^t$r is the interest rate (e.g. 10% is 0.10)t is the number of years r is the interest rate (e.g. 10% is 0.10)t is the number of years $\text{DPBP(Dynamic Pay Back Period)} = \text{year.when(sum(Discount cash flow)&gt;0)}=3 years$ 知识点 Year 0’ represents all the costs before system is operation ‘Cash-flow’ is value of income less outgoing Net profit value of all the cash-flows for the lifetime of the application Internal rate of return (IRR) is the discount rate that would produce an NPV of 0 for the project 内部收益率 Internal rate of return (IRR) 某项目期初投资200万，以后的10年每年都有30万的现金流，求该项目的内部收益率（IRR）。（注：利率插值区间宽度小于1%即可）解答：内部收益率（IRR），是指项目投资实际可望达到的收益率，实质上，它是能使项目的净现值等于零时的折现率。-200+[30/(1+IRR)+30/(1+IRR)^2+….+30/(1+IRR)^10]=0 , IRR=8.14%注意：将IRR=8.14%代入上式后结果为0.0375。另外，用Excel函数IRR求得结果为8.14%。 week 3: Overview of project planning &amp; Selection of project approach第3周：项目规划和项目方法选择的概述An invoicing system is to have the following components: amend invoice, produce invoice, produce monthly statements, record cash payment, clear paid invoices from database, create customer records, delete customer. 发票系统具有以下组成部分：修改发票，生成发票，生成月结单，记录现金支付，清除数据库中的付款发票，创建客户记录，删除客户。 (a) What physical dependencies govern the order in which these transactions are implemented?哪些物理依赖关系决定了这些交易的实施顺序？ Create customer 2. Delete customer 3. Produce invoice Amend invoice 5. Payment 6.Clear paid invoices Produce monthly statements (b) How could the system be broken down into increments which would be of some value to the users (hint – think about the problems of taking existing details onto a database when a system is first implemented).如何将系统分解为对用户有一定价值的增量（提示 - 考虑在首次实施系统时将现有细节带入数据库的问题）。 increment 1: Create customer, Delete customer increment 2: Produce invoice, Amend invoice increment 3: Payment, Clear paid invoices increment 4: Produce monthly statements 知识点 产品分解结构 Products CAN BE deliverable or intermediate产品可以是可交付的或中间的 Could be Products(among other things)physical thing (‘installed pc’),a document (‘logical data structure’)a person (‘trained user’)a new version of an old product (‘updated software’) The following are NOT normally products:activities (e.g. ‘training’)events (e.g. ‘interviews completed’)resources and actors (e.g. ‘software developer’) - may be exceptions to this 产品流程图 瀑布模型imposes structure on the projectevery stage needs to be checked and signed offBUTlimited scope for iteration“经典”模型将结构强加于项目每个阶段都需要检查和签名但有限的空间迭代 V-process model Reasons for prototyping原型设计的理由 learning by doing improved communication improved user involvement a feedback loop is established reduces the need for documentation reduces maintenance costs i.e. changes after the application goes live prototype can be used for producing expected results在实践中学习改进的通信改进的用户参与建立了一个反馈回路减少对文档的需求减少维护成本，即应用程序运行后的更改原型可以用于产生预期的结果 Prototyping: some dangers原型:一些危险 users may misunderstand the role of the prototype lack of project control and standards possible additional expense of building prototype focus on user-friendly interface could be at expense of machine efficiency用户可能误解了原型的作用缺乏项目控制和标准建筑原型的额外费用专注于用户友好的界面可能会牺牲机器的效率 渐进的过程 Incremental approach:benefits增量的方法:好处 feedback from early stages used in developing latter stages shorter development thresholds user gets some benefits earlier project may be put aside temporarily reduces ‘gold-plating’开发后阶段使用的早期阶段的反馈缩短开发阈值用户可以更早获得一些好处项目可以暂时搁置减少“画蛇添足” BUT there are some possible disadvantages loss of economy of scale ‘software breakage’ steps ideally 1% to 5% of the total project non-computer steps should be included ideal if a step takes one month or less:not more than three months each step should deliver some benefit to the user some steps will be physically dependent on others规模经济损失“软件破损each step should deliver some benefit to the usersome steps will be physically dependent on others每一步都应该给用户带来一些好处有些步骤将在物理上依赖于他人 V/C ratios: V is a score 1-10 representing value to customerC is a score 0-10 representing value to developers ‘Agile’ methods“敏捷”的方法 structured development methods have some perceived disadvantages： produce large amounts of documentation which can be largely unread documentation has to be kept up to date division into specialist groups and need to follow procedures stifles communication users can be excluded from decision process long lead times to deliver anything etc. etc结构化开发方法有一些明显的缺点产生大量的文档，这些文档大部分都是未读的文档必须保持最新划分为专家小组并需要遵循程序抑制沟通用户可以被排除在决策过程之外交付任何东西的时间很长，等等 The Manifesto for Agile Software Development敏捷软件开发的宣言“We are uncovering better ways of developing software by doing it and helping others do it. Through this work we have come to value: Individuals and interactions over processes and tools Working software over comprehensive documentation Customer collaboration over contract negotiation Responding to change over following a planThat is, while there is value in the items on the right, we value the items on the left more.” by Kent Beck et al. 个体交互优于流程和工具 软件产品优于详尽的文档 客户合作优于合同谈判 对变更作出响应优于计划 Eight core DSDM principles八个核心共享原则 Focus on business need Deliver on time Collaborate Never compromise quality Develop iteratively Build incrementally from firm foundations Communication continuously Demonstrate control1。专注于业务需求2。按时交货3。合作4。永不妥协的质量5。迭代开发6。从坚实的基础逐步构建7。不断的沟通8。显示控制 time-box fixed deadline by which something has to be delivered时间盒固定期限，必须交付一些东西 Chapter5 Software effort estimationChapter5软件工作量评估 Given the project data below: What items are size drivers?哪些项目是规模驱动的 inputs, outputs, entity accesses (system users for certain aspects) What items are productivity drivers?哪些项目是生产率驱动的 Programming language What are the productivity rates for programming languages x, y and z?编程语言 x, y, z的生产率分别是多少 x: 10 FPs/day y: 7 FPs/day z: 12 FPs/day x:[(210x0.58+420x0.26+40x1.66)/30+(469x0.58+1406x0.26+125x1.66)/85]/2d)y:[(5130.58+12830.26+761.66)/108+(6600.58+23100.26+881.66)/161+(16000.58+32000.26+237*1.66)/308]/3=[7.012+7.015+6.991]=7.006 比例系数需要记住inputs, outputs, entity accesses：0.58,0.26,1.66 What would be the estimated effort for projects X and Y using a Mark II function point count?使用Mark II功能点计数的项目X和Y的估计工作量是多少？ FP of Project X is 261.8 and FP of Project Y is 704.66. Using the productivity rate for programming language y, the estimate for Project X would be 262/7 i.e. 37 days, and for Project Y 705/7 i.e. 101 days.项目X的FP为261.8，项目Y的FP为704.66。 使用编程语言y的生产率，项目X的估计值为262/7，即37天，而项目Y 705/7，即101天。 What would be the estimated effort for X and Y using an approximate analogy approach? 使用近似类比方法对X和Y的估计工作量是多少？ Project X seems closest to Project 5 which provides an estimate of 22 days, and Project Y seems to be closest to Project 3 which gives an estimate of 108 days.项目X似乎最接近项目5，其提供22天的估计，而项目Y似乎最接近项目3，其估计为108天。 知识点estimated effort = (system size) / productivity e.g.system size = lines of codeproductivity = lines of code per dayproductivity = (system size) / effortbased on past projects估计工作量=（系统大小）/生产率如。系统大小=代码行生产力=每天的代码行数生产力=（系统大小）/努力 Some models focus on task or system size e.g. Function Points一些模型关注任务或系统大小，例如功能点FPs originally used to estimate Lines of Code, rather than effortFPs最初用于估计代码行，而不是工作 Function points Mark II功能点马克二世 For each transaction, countdata items input (Ni)data items output (No)entity types accessed (Ne) Chapter6 Activity PlanningChapter6活动计划 Create a PERT activity network using above data. Calculate the earliest and latest start and end dates and the float associated with each activity. From this identify the critical path.使用上述数据创建PERT活动网络。 计算最早和最晚的开始和结束日期以及与每项活动相关的浮动。 由此确定关键路径。 Answer: 知识点 Activity ‘write report software’Earliest start (ES)Earliest finish (EF) = ES + durationLatest finish (LF) = latest task can be completed without affecting project endLatest start (LS) = LF - duration 活动区间（最左下角的值） = 持续时间 + 最右下角的值 Chapter7 Risk Management第7章风险管理 Using the activity times above: Calcaulate the expected duration and standard deviation for each activity Identify the critical path Draw up an activity diagram applying critical chain principles for this project:Local the places where buffers will need to be located.Assess the size of the buffersStart all activities as later as possible.使用上面的活动时间：1。对每个活动的预期持续时间和标准偏差进行计算2。确定关键路径3。为这个项目绘制一个应用关键链原理的活动图：本地的缓冲区需要被定位的地方。评估缓冲区的大小尽可能晚地开始所有活动。 Activity $t_e$ $s$ $b$ A 10 0.67 2 B 15 1.67 5 C 7 0.67 2 D 10 0.67 2 E 6 1.00 3 A: $t_e=\dfrac{(a+4m+b)}{6}=\dfrac{(8+4*10+12)}{6}=10$,$s=\dfrac{(b-a)}{6}=\dfrac{(12-8)}{6}=0.67$,$b=\dfrac{(b-a)}{2}=2.$ Project buffer = sum(b:where b is key point)/2 = (2+5+2+3)/2=6 Subsidiary chain’s feeding buffer=(b:not key point)/2 = 2/2=1 知识点Using PERT to evaluate the effects of uncertainty使用PERT图来评估不确定性的影响 Three estimates are produced for each activityMost likely time (m)Optimistic time (a)Pessimistic (b)‘expected time’ t_e=\dfrac{(a+4m+b)}{6}‘activity standard deviation’ s=\dfrac{(b-a)}{6} What would be the expected duration of the chain A + B + C? Answer: 12.66 + 10.33 + 25.66 = 48.65 What would be the standard deviation for A + B+ C? Answer: square root of (12 + 12 + 32)= 3.32 Say the target for completing A+B+C was 52 days (T)Calculate the z value thus z = (T – te)/s In this example z = (52-48.33)/3.32 = 1.01 Look up in table of z values – see next overhead Risk exposure (RE)= (potential damage) x (probability of occurrence) Risk reduction leverage =(REbefore- REafter)/ (cost of risk reduction) REbeforeis risk exposure before risk reduction e.g. 1% chance of a fire causing £200k damageREafter is risk exposure after risk reduction e.g. fire alarm costing £500 reduces probability of fire damage to 0.5%RRL = (1% of £200k-0.5% of £200k)/£500 = 2RRL &gt; 1.00 therefore worth doing在降低风险之前，rebefore是风险暴露，例如，1%的可能性发生火灾，造成200 k的损失REafter是在风险降低后的风险敞口，例如，火灾报警成本为500英镑，将火灾损失的可能性降低到0.5%。RRL = (1% of £200k-0.5% of £200k)/£500 = 2RRL &gt; 1.00 因此值得做 Chapter9 Monitoring &amp; ControlChapter9监测与控制 一个项目涉及到四个软件模块的设计和构建，分别称为A、B、C和D。每个模块的估计工作量为60小时，B为30小时，C为40小时，d为45。正在进行这项工作的组织假设是为了获得价值分析（EVA），设计占了30%的工作量，编码40%，测试30%。在这个EVA进行的当天，这个项目应该已经完成了。事实上，情况如下： 实际工作时间显示任务已经完成。1。计算进度和成本差异。2。计算成本性能和进度性能指标。3。从这些数据中可以得出一般的结论这个项目吗? 详细分析已知|model|Estimated effort|Estimated design|Design(actual hours)|Estimated code|Code (actual hours)|Estimated test|Test (actual hours)||-|-|-|-|-|-|-|-||||30%||40%||30%|||A|60||25||40||Not completed||B|30||15||15||15||C|40||15||Not completed||Not completed||D|45||10||Not completed||Not completed| 首先按题目给的比例 30% of the effort, coding 40% and testing 30%,把 Estimated design、Estimated code 和 Estimated test 填写了：|model|Estimated effort|Estimated design|Design(actual hours)|Estimated code|Code (actual hours)|Estimated test|Test (actual hours)||-|-|-|-|-|-|-|-||||30%||40%||30%|||A|60|18|25|24|40|18|Not completed||B|30|9|15|12|15|9|15||C|40|12|15|16|Not completed|12|Not completed||D|45|13.5|10|18|Not completed|13.5|Not completed| Planned value (PV) 计划价值 $PV = sum(\text{Estimated effort)} =60+30+40+45=175$ Earned value (EV) 预算成本（不包括没完成的项目） $EV=sum(\text{Estimated effort)}-\text{Not completed Estimated item}$eg. EV = 175 - (18+16+12+18+13.5)=175-77.5=97.5 或者 竖着加刚才计算出的那三列，同样不包括没完成的项目eg. 18+9+12+13.5=52.5 24+12=36 1552.5+36+15=97.5 Actual cost (AC) 实际成本 $AC=sum\text{(actual hours)}=25+15+15+10+40+15+15=135$ Schedule variance (SV) 进度偏差 $SV=EV-PV=97.5-175=-77.5$ Schedule performance indicator (SPI) 进度绩效指标 $SPI=EV/PV=97.5/175=0.56$ Cost variance (CV) 成本偏差 $CV=EV-AC=97.5-135=-37.5$ Cost performance indicator (CPI) 成本绩效指数 $CPI = EV/AC=97.5/135=72.2$ 注意：都是用预算成本 EV 做分子 综上可知 中英词汇对照表 英文词汇 中文解释 Net profit(NP) 净利润 Cost benefit analysis (CBA)| 成本效益分析Return on investment (ROI) |投资回报率(ROI)Net present value (NPV) |净现值(NPV)Internal rate of return (IRR) |内部收益率（IRR）product breakdown structure(PBS)|产品分解结构Product description (PD)|产品描述(PD)PFD(Product Flow Diagram)|PFD(产品流程图)Gantt charts|甘特图Function Points（FPs）|功能点Risk exposure (RE)|风险承担Risk Reduction Leverage(RRL)|减少风险杠杆(RRL)Earned Value Analysis (EVA)|挣值分析(EVA)Planned value (PV) |计划价值Earned value (EV) |预算成本Actual cost (AC) | 实际成本Schedule variance (SV)| 进度偏差Schedule performance indicator (SPI)| 进度绩效指标Cost variance (CV)| 成本偏差Cost performance indicator (CPI)| 成本绩效指数customized off-the-shelf (COTS) |定制的现成的Invitation to tender (ITT)|招标(ITT)Memoranda of agreement (MoA)|备忘录 补充知识名词解释 名词 解释 项目 项目是一系列具有特定目标,有明确开始和终止日期，资金有限，消耗资源的活动和任务。 检查点 指在规定的时间间隔内对项目进行检查，比较实际与计划之间的差异，并根据差异进行调整。可将检查点看作是一个 固定 “ 采样 ” 时点，而时间间隔根据项目周期长短不同而不同，频度过小会失去意义，频度过大会增加管理成本。常见的间隔是每周一次，项目经理需要召开例会并上交周报。 里程碑 重要的检查点是里程碑，重要的需要客户确认的里程碑，就是基线。在我们实际的项目中，周例会是检查点的表现形式，高层的阶段汇报会是基线的表现形式。 基线 基线是经过评审和批准的配置项的集合，其作用是明确划分项目各阶段，确定各阶段的结束点。在项目的开发过程中，最基本的基线有需求基线、概要设计基线、详细设计基线、代码基线、测试基线、交付基线 CPM|即关键路径法(Critical Path Method），又称关键线路法。|PERT|Program Evaluation Review Technique计划评审技术，是一种任务工期估算的图示法。| 简答题请简述项目管理的9个知识领域和5个过程组。Please briefly describe 9 knowledge areas and 5 process groups of project management. 项目管理的九大知识领域包括项目整体管理、项目范围管理、项目时间管理、项目费用管理、项目质量管理、项目人力资源管理、项目沟通管理、项目风险管理和项目采购管理。项目管理5个过程组包括启动过程组、规划过程组、执行过程组、监督和控制过程组、收尾过程组。 项目管理有哪些不同类型的组织形式？What are the different types of organizational forms of project management? 项目管理组织分为：职能型矩阵型（包括弱矩阵型、平衡矩阵型、强矩阵型、复合矩阵型）项目新 请简述项目经理应该具备的素质。Please give a brief account of the qualities that the project manager should have. 项目经理应具备的素质包括以下几点：a) 广博的知识：包括项目管理知识、IT行业知识、客户行业知识。b) 丰富的经历c) 良好的协调能力d) 良好的职业道德e) 良好的沟通和表达能力f) 良好的领导能力 需求开发过程包括哪些过程？What processes do the requirements development process include? 需求开发包括：需求获取，需求分析，需求规格说明和需求验证等几个过程。 项目经理在需求变更管理中的职责和目标是什么？What are the responsibilities and objectives of project managers in requirements change management? 项目经理在需求彼岸管理中的职责是：a) 负责协调变更的需求并对变更的需求有拒绝的权利b) 负责对变更的需求部分设计的修改c) 保证项目的开发与需求的一致性d) 确定开发进度是否需要进行变更e) 分配新需求给相关开发人员项目经理在需求变更管理的目标：1、相关的干系人必须清楚地了解发生的变更。2、变更处于有效的管理中。3、尽量降低变更带来的风险。 什么是项目时间管理？以及项目管理包括哪些主要过程。What is project time management? And what are the main processes that project management includes. 项目时间管理是：“按时、保质地完成项目”大概是每一位项目经理最希望做到的。但工期托延的情况却时常发生。因而合理地安排项目时间是项目管理中一项关键内容，它的目的是保证按时完成项目、合理分配资源、发挥最佳工作效率。它的主要工作包括定义项目活动、任务、活动排序、每项活动的合理工期估算、制定项目完整的进度计划、资源共享分配、监控项目进度等内容。 综合题假如您是一个项目经理，负责一个基于web的图书管理系统软件的开发，问：应该如何分解此项目所应该包括的工作？请按WBS为该项目制定一份工作的分解计划。If you are a project manager, you are responsible for the development of a web based library management system software, and ask: how should you break down the work that the project should include? Please work out a breakdown plan for the project according to WBS. 答：我作为一个项目经理我按如下方式进行项目分解工作，1、首先做好用户调研计划、调研方式，通过多次迭代方式进行调研，形成最终的用户需求说明书；通过UML工具按模块进行用例图，通过用例图来确定系统范围及边界。2、同项目组开发人员进行沟通，确定项目所拥有的人力资源，根据建设的内容确定人力资源同项目建设内容搭配，根据模块的特性配备不同技术能力、沟通能力的技术人员，实现技术人员使用最优化。3、根据项目里程碑时间，以终为始划分项目开发计划里程碑，在做项目开发计划的根据实际情况酌情调整部分时间。4、做好项目开发计划，公布给项目开发组成员，并且要求严格按照进行执行；在中间发现进度出现问题，及时进行调整。]]></content>
      <tags>
        <tag>软件项目管理</tag>
        <tag>考试</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[二分类、多分类、多标签和多输出问题解析]]></title>
    <url>%2F2018%2F07%2F01%2F%E4%BA%8C%E5%88%86%E7%B1%BB%E3%80%81%E5%A4%9A%E5%88%86%E7%B1%BB%E4%B8%8E%E5%A4%9A%E6%A0%87%E7%AD%BE%E9%97%AE%E9%A2%98%E7%9A%84%E5%8C%BA%E5%88%AB%E2%80%94%E2%80%94%E5%AF%B9%E5%BA%94%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0%E7%9A%84%E9%80%89%E6%8B%A9%2F</url>
    <content type="text"><![CDATA[本文分为理论和实验两部分： 理论部分先讲解二分类、多分类与多标签分类问题的基本概念，然后分析它们为什么使用不同的激活函数和损失函数，结论见文末总结。 实验部分重点讲解了多标签和多输出问题。 二分类、多分类、多标签和多输出问题的基本概念 二分类：表示分类任务中有两个类别，比如我们想识别一幅图片是不是猫。也就是说，训练一个分类器，输入一幅图片，用特征向量x表示，输出是不是猫，用y=0或1表示。二类分类是假设每个样本都被设置了一个且仅有一个标签 0 或者 1。 多类分类(Multiclass classification): 表示分类任务中有多个类别, 比如对一堆水果图片分类, 它们可能是橘子、苹果、梨等. 多类分类是假设每个样本都被设置了一个且仅有一个标签: 一个水果可以是苹果或者梨, 但是同时不可能是两者。 多标签分类(Multilabel classification): 给每个样本一系列的目标标签. 可以想象成一个数据点的各属性不是相互排斥的(一个水果既是苹果又是梨就是相互排斥的), 比如一个文档相关的话题. 一个文本可能被同时认为是宗教、政治、金融或者教育相关话题。 多输出分类：多个多分类或多标签分类组合输出的分类。网络至少会分支两次（有时候会更多），从而在网络末端创建出多组全连接头——然后你的网络的每个头都会预测一组类别标签，使其有可能学习到不相交的标签组合。比如一个网络同时预测服饰的款式类型和颜色类型。 多分类问题与二分类问题关系 首先，两类问题是分类问题中最简单的一种。其次，很多多类问题可以被分解为多个两类问题进行求解（请看下文分解）。所以，历史上有很多算法都是针对两类问题提出的。下面我们来分析如何处理多分类问题： 直接分成多类比如使用 Softmax 回归。 一对一的策略给定数据集D这里有N个类别，这种情况下就是将这些类别两两配对，从而产生N(N−1)2个二分类任务，在测试的时候把样本交给这些分类器，然后进行投票。 一对其余策略将每一次的一个类作为正例，其余作为反例，总共训练N个分类器。测试的时候若仅有一个分类器预测为正的类别则对应的类别标记作为最终分类结果，若有多个分类器预测为正类，则选择置信度最大的类别作为最终分类结果。 多标签问题与二分类问题关系面临的问题：图片的标签数目不是固定的，有的有一个标签，有的有两个标签，但标签的种类总数是固定的，比如为5类。 解决该问题：采用了标签补齐的方法，即缺失的标签全部使用0标记，这意味着，不再使用one-hot编码。例如：标签为：-1,1,1,-1,1 ;-1表示该类标签没有，1表示该类标签存在，则这张图片的标签编码为： 0 0 0 0 00 1 0 0 00 0 1 0 00 0 0 0 00 0 0 0 1 2.如何衡量损失？ 计算出一张图片各个标签的损失，然后取平均值。 3.如何计算精度 计算出一张图片各个标签的精度，然后取平均值。 该处理方法的本质：把一个多标签问题，转化为了在每个标签上的二分类问题。 损失函数的选择问题基于逻辑回归的二分类问题对于logistic回归，有： h_{\theta}(x) = g(\theta^{T}x) = \frac{1}{1+e^{-\theta^{T}x}}逻辑回归有以下优点： 它的输入范围是 $-\infty \to+\infty$，而之于刚好为（0，1），正好满足概率分布为（0，1）的要求。我们用概率去描述分类器，自然比单纯的某个阈值要方便很多； 它是一个单调上升的函数，具有良好的连续性，不存在不连续点。 对数损失函数（logarithmic loss function) 或对数似然损失函数(log-likehood loss function) 。 L(Y,P(Y|X)) = -logP(Y|X)逻辑回归中，采用的则是对数损失函数。根据上面的内容，我们可以得到逻辑回归的对数似然损失函数cost function： cost(h_{\theta}(x),y) = \begin{cases} -log(h_{\theta}(x)) & \text {if y=1} \\ -log(1-h_{\theta}(x)) & \text{if y=0} \end{cases}将以上两个表达式合并为一个，则单个样本的损失函数可以描述为： cost(h_{\theta}(x),y) = -y_ilog(h_{\theta}(x)) - (1-y_i)log(1-h_{\theta}(x))这就是逻辑回归最终的损失函数表达式。 基于 Softmax 的多分类问题softmax层中的softmax 函数是logistic函数在多分类问题上的推广，它将一个N维的实数向量压缩成一个满足特定条件的N维实数向。压缩后的向量满足两个条件： 向量中的每个元素的大小都在[0,1] 向量所有元素的和为 1 因此，softmax适用于多分类问题中对每一个类别的概率判断，softmax的函数公式如下： a^L_j = \frac {e^{z^L_j}}{\sum_k e^{z^L_k}}基于 Softmax 的多分类问题采用的是 log似然代价函数（log-likelihood cost function）来解决。 单个样本的 log似然代价函数的公式为： C = - \sum_i y_i log a_i其中， $y_i$ 表示标签向量的第 $i$ 个分量。因为往往只有一个分量为 1 其余的分量都为 0，所以可以去掉损失函数中的求和符号，化简为， C \equiv -\ln a_j其中， $a_j$ 是向量 $y$ 中取值为 1 对应的第 $j$ 个分量的值。 交叉熵损失函数与 log 似然代价函数关系 本质一样有的文献中也称 log 似然代价函数为交叉熵损失函数，这两个都是交叉熵损失函数，但是看起来长的却有天壤之别。为什么同是交叉熵损失函数，长的却不一样呢？ cost(h_{\theta}(x),y) = -y_ilog(h_{\theta}(x)) - (1-y_i)log(1-h_{\theta}(x))C = - \sum_i y_i log a_i因为这两个交叉熵损失函数对应不同的最后一层的输出。第一个对应的最后一层是 sigmoid，用于二分类问题，第二个对应的最后一层是 softmax，用于多分类问题。但是它们的本质是一样的，请看下面的分析。 首先来看信息论中交叉熵的定义： -\int p(x)\text{log}g(x)dx交叉熵是用来描述两个分布的距离的，神经网络训练的目的就是使 g(x) 逼近 p(x)。 sigmoid + 对数损失函数先看看 sigmoid 作为神经网络最后一层的情况。sigmoid 作为最后一层输出的话，那就不能吧最后一层的输出看作成一个分布了，因为加起来不为 1。现在应该将最后一层的每个神经元看作一个分布，对应的 target 属于二项分布(target的值代表是这个类的概率)，那么第 i 个神经元交叉熵为 y_i\text{log}(h_{\theta})+(1-y_i)\text{log}(1-h_{\theta})其实这个式子可以用求和符号改写， C = - \sum_i log a_i其中， cost(h_{\theta}(x),y) = \begin{cases} -log(a_i) & a_i=h_{\theta} & \text {if } y_i=1 \\ -log(a_i) & a_i=1-h_{\theta} & \text{if } y_i=0 \end{cases}Softmax + 交叉熵现在来看 softmax 作为神经网络最后一层的情况。g(x)是什么呢？就是最后一层的输出 y 。p(x)是什么呢？就是我们的one-hot标签。我们带入交叉熵的定义中算一下，就会得到： C = - \sum_i y_i log a_i交叉熵损失函数与 log 似然损失函数的总结注意到不管是交叉熵损失函数与 log 似然损失函数，交叉熵损失函数用于二分类问题， log 似然损失函数用于多分类，但是对于某一个样本只属于一个类别，只有一个标签。如果用 one-hot 编码样本的标签那么，对于标签向量只有一个分量的值为 1 其余的值都为 0。 所以不管是交叉熵损失函数与 log 似然损失函数，都可以化简为， C \equiv -\ln a_j其中， $a_j$ 是向量 $y$ 中取值为 1 对应的第 $j$ 个分量的值。这两个长的不一样的损失函数实际上是对应的不同的输出层。本质上是一样的。 我的建议是，采用 Kears 中的命名方法，对于二分类的交叉熵损失函数称之为 “二分类交叉熵损失函数（binary_crossentropy）” ，对于多分类的交叉熵损失函数称之为 “多类别交叉熵损失函数（categorical_crossentropy）”。 在 Kears 中也有提示（注意: 当使用categorical_crossentropy损失时，你的目标值应该是分类格式 (即，如果你有10个类，每个样本的目标值应该是一个10维的向量，这个向量除了表示类别的那个索引为1，其他均为0)。 为了将 整数目标值 转换为 分类目标值，你可以使用Keras实用函数to_categorical：） 一种更直接的证明方法，数学公式， 内容来源于 Hands-on Machine Learning with Scikit-Learn and TensorFlow 141 页。 多标签分类 + 二分类交叉熵损失函数多标签问题与二分类问题关系在上文已经讨论过了，方法是计算一个样本各个标签的损失（输出层采用sigmoid函数），然后取平均值。把一个多标签问题，转化为了在每个标签上的二分类问题。 总结 分类问题名称 输出层使用激活函数 对应的损失函数 二分类 sigmoid函数 二分类交叉熵损失函数（binary_crossentropy） 多分类 Softmax函数 多类别交叉熵损失函数（categorical_crossentropy） 多标签分类 sigmoid函数 二分类交叉熵损失函数（binary_crossentropy） 为什么要引入多输出分类问题使用Keras执行多标签分类非常简单，包括两个主要步骤： 使用 sigmoid 激活替换网络末端的 softmax 激活换出明确的交叉熵的二进制交叉熵对你的损失函数从那里你可以像往常一样训练你的网络。应用上述过程的最终结果是多类分类器。可以使用Keras多类分类来预测多个标签只是一个单一的向前传递。 但是，您需要考虑以下问题： 您需要针对要预测的每个类别组合的培训数据。 就像神经网络无法预测从未接受过训练的类一样，您的神经网络无法预测从未见过的组合的多个类别标签。这种行为的原因是由于网络内神经元的激活。 如果您的网络接受过（1）黑色裤子和（2）红色衬衫的示例训练，现在您想要预测“红裤子”（数据集中没有“红裤子”图像），负责检测的神经元“红色”和“裤子”会触发，但由于网络一旦到达完全连接的层之前从未见过这种数据/激活组合，您的输出预测很可能是不正确的（即，您可能会遇到“红色”或“裤子”，但两者都不太可能）。 同样，您的网络无法正确预测从未接受过培训的数据（您也不应该期望它）。在培训您自己的Keras网络进行多标签分类时，请牢记这一点。 使用多输出分类就可以解决此问题。通过创建两个全连接头和相关的子网络（如有必要），我们可以训练一个头分类服装种类，另一个头负责识别颜色——最终得到的网络可以分类「黑色裙子」，即使它之前从未在这样的数据上训练过！ 多输出分类:针对服装类型和颜色的实验实验详细指导 创建模型的关键代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081class FashionNet: @staticmethod def build_category_branch(inputs, numCategories, finalAct="softmax", chanDim=-1): # utilize a lambda layer to convert the 3 channel input to a # grayscale representation x = Lambda(lambda c: tf.image.rgb_to_grayscale(c))(inputs) # CONV =&gt; RELU =&gt; POOL x = Conv2D(32, (3, 3), padding="same")(x) x = Activation("relu")(x) x = BatchNormalization(axis=chanDim)(x) x = MaxPooling2D(pool_size=(3, 3))(x) x = Dropout(0.25)(x) # Omit some similar code # define a branch of output layers for the number of different # clothing categories (i.e., shirts, jeans, dresses, etc.) x = Flatten()(x) x = Dense(256)(x) x = Activation("relu")(x) x = BatchNormalization()(x) x = Dropout(0.5)(x) x = Dense(numCategories)(x) x = Activation(finalAct, name="category_output")(x) # return the category prediction sub-network return x @staticmethod def build_color_branch(inputs, numColors, finalAct="softmax", chanDim=-1): # CONV =&gt; RELU =&gt; POOL x = Conv2D(16, (3, 3), padding="same")(inputs) x = Activation("relu")(x) x = BatchNormalization(axis=chanDim)(x) x = MaxPooling2D(pool_size=(3, 3))(x) x = Dropout(0.25)(x) # Omit some similar code # define a branch of output layers for the number of different # colors (i.e., red, black, blue, etc.) x = Flatten()(x) x = Dense(128)(x) x = Activation("relu")(x) x = BatchNormalization()(x) x = Dropout(0.5)(x) x = Dense(numColors)(x) x = Activation(finalAct, name="color_output")(x) # return the color prediction sub-network return x @staticmethod def build(width, height, numCategories, numColors, finalAct="softmax"): # initialize the input shape and channel dimension (this code # assumes you are using TensorFlow which utilizes channels # last ordering) inputShape = (height, width, 3) chanDim = -1 # construct both the "category" and "color" sub-networks inputs = Input(shape=inputShape) categoryBranch = FashionNet.build_category_branch(inputs, numCategories, finalAct=finalAct, chanDim=chanDim) colorBranch = FashionNet.build_color_branch(inputs, numColors, finalAct=finalAct, chanDim=chanDim) # create the model using our input (the batch of images) and # two separate outputs -- one for the clothing category # branch and another for the color branch, respectively model = Model( inputs=inputs, outputs=[categoryBranch, colorBranch], name="fashionnet") # return the constructed network architecture return model 实验输出 模型预测效果 参考文献[1] François Chollet‏. Keras Document[DB/OL]. https://keras.io/, 2018-07-01. [2] 目力过人. 多标签分类（multilabel classification ）[DB/OL]. https://blog.csdn.net/bemachine/article/details/10471383, 2018-07-01. [3] Inside_Zhang.【联系】二项分布的对数似然函数与交叉熵（cross entropy）损失函数[DB/OL]. https://blog.csdn.net/lanchunhui/article/details/75433608, 2018-07-01. [4] ke1th. 两种交叉熵损失函数的异同[DB/OL]. https://blog.csdn.net/u012436149/article/details/69660214, 2018-07-01. [5] bitcarmanlee. logistic回归详解一：为什么要使用logistic函数[DB/OL]. https://blog.csdn.net/bitcarmanlee/article/details/51154481, 2018-07-01. [6] Aurélien Géron. Hands-On Machine Learning with Scikit-Learn and TensorFlow[M]. America: O’Reilly Media, 2017-03-10, 140-141. [7] Adrian Rosebrock. 使用Keras实现多输出分类：用单个模型同时执行两个独立分类任务[DB/OL]. https://www.jiqizhixin.com/articles/2018-08-14-2, 2018-08-18.]]></content>
      <categories>
        <category>实验</category>
      </categories>
      <tags>
        <tag>二分类</tag>
        <tag>多分类</tag>
        <tag>多标签</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[神经网络可以计算任何函数的可视化证明]]></title>
    <url>%2F2018%2F06%2F29%2F%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E5%8F%AF%E4%BB%A5%E8%AE%A1%E7%AE%97%E4%BB%BB%E4%BD%95%E5%87%BD%E6%95%B0%E7%9A%84%E5%8F%AF%E8%A7%86%E5%8C%96%E8%AF%81%E6%98%8E%2F</url>
    <content type="text"><![CDATA[原文链接：CHAPTER 4 A visual proof that neural nets can compute any function 神经网络的一个最显著的事实就是它可以计算任何的函数。不管这个函数是什么样的，总会确保有一个神经网络能够对任何可能的输入 $x$，其值 $f(x)$ （或者某个足够准确的近似）是网络的输出。 表明神经网络拥有一种普遍性。不论我们想要计算什么样的函数，我们都确信存在一个神经网络可以计算它。 而且，这个普遍性定理甚至在我们限制了神经网络只在输入层和输出层之间存在一个中间层的情况下成立。所以即使是很简单的网络架构都极其强大。普遍性定理在使用神经网络的人群中是众所周知的。但是它为何正确却不被广泛地理解。现有的大多数的解释都具有很强的技术性。 如果你是数学家，这个证明应该不大难理解，但对于大多数人还是很困难的。这不得不算是一种遗憾，因为这个普遍性背后的原理其实是简单而美妙的。在这一章，我给出这个普遍性定理的简单且大部分为可视化的解释。我们会一步步深入背后的思想。你会理解为何神经网络可以计算任何的函数。你会理解到这个结论的一些局限。并且你还会理解这些结论如何和深度神经网络关联的。 神经网络拥有强大的算法来学习函数。学习算法和普遍性的结合是一种有趣的混合。直到现在，本书一直是着重谈学习算法。到了本章，我们来看看普遍性，看看它究竟意味着什么。 两个预先声明在解释为何普遍性定理成立前，我想要提下关于非正式的表述“神经网络可以计算任何函数”的两个预先声明。 第一点，这句话不是说一个网络可以被用来准确地计算任何函数。而是说，我们可以获得尽可能好的一个近似。通过增加隐藏元的数量，我们可以提升近似的精度。为了让这个表述更加准确，假设我们给定一个需要按照目标精度 $\epsilon &gt; 0$ 的函数 $f(x)$。通过使用足够多的隐藏神经元使得神经网络的输出 $g(x)$ 对所有的 $x$，满足 $|g(x) - f(x)| &lt; \epsilon$ 从而实现近似计算。换言之，近似对每个可能的输入都是限制在目标准确度范围内的。 第二点，就是可以按照上面的方式近似的函数类其实是连续函数。如果函数不是连续的，也就是会有突然、极陡的跳跃，那么一般来说无法使用一个神经网络进行近似。这并不意外，因为神经网络计算的就是输入的连续函数。然而，即使那些我们真的想要计算的函数是不连续的，一般来说连续的近似其实也足够的好了。如果这样的话，我们就可以用神经网络来近似了。实践中，这通常不是一个严重的限制。 总结一下，更加准确的关于普遍性定理的表述是包含一个隐藏层的神经网络可以被用来按照任意给定的精度来近似任何连续函数。 本章可视化证明的说明 我们会使用了两个隐藏层的网络来证明这个结果的弱化版本。然后我将简要介绍如何通过一些微调把这个解释适应于只使用一个隐藏层的网络的证明。 我们使用 S 型神经元作为神经网络的激活函数，在后面我们可以推广到其它激活函数。 证明的理论准备 S 型神经元作为神经网络的激活函数非常普遍，但是为了方便我们的证明，我们对 S 型神经元做一点点处理，把它变成阶跃函数（感知器）。实际上处理阶跃函数比一般的 S 型函数更加容易。原因是在输出层我们把所有隐藏神经元的贡献值加在一起。分析一串阶跃函数的和是容易的，相反，思考把一串 S 形状的曲线加起来是什么则要更困难些。所以假设我们的隐藏神经元输出阶跃函数会使事情更容易。更具体些，我们把权重 $w$ 固定在一个大的值，然后通过修改偏置设置阶跃函数的位置。当然，把输出作为一个阶跃函数处理只是一个近似，但是它是一个非常好的近似，现在我们把它看作是精确的。稍后我会再讨论偏离这种近似的影响。关于 S 型神经元和感知器的关系分析见 使用神经网络识别手写数字——感知器。 S 型函数变阶跃函数过程 S 型神经元的代数形式是， \sigma(z) \equiv \frac{1}{1+e^{-z}}其中，$z = w \cdot x+b$ S 型神经元的函数图形是， $x$ 取何值时阶跃会发生呢？换种方式，阶跃的位置如何取决于权重和偏置？ 因为 $z = w \cdot x+b$ 是一个直线方程， $w$ 是直线的斜率， $b$ 是直线的截距，直线与 $x$ 轴的交点是 $(-b/w, 0)$，令 $s=-b/w$。 假设 $z \equiv w \cdot x + b$ 是一个很大的正数。那么 $e^{-z} \approx 0$ 而 $\sigma(z) \approx 1$。即，当 $z = w \cdot x+b$ 很大并且为正， S 型神经元的输出近似为 $1$，正好和感知器一样。相反地，假设 $z = w \cdot x+b$ 是一个很大的负数。那么$e^{-z} \rightarrow \infty$，$\sigma(z) \approx 0$。所以当 $z = w \cdot x +b$ 是一个很大的负数。 根据上面两点可以知道，当 $|w|$ 的值很大时，$x$ 就能直接决定 S 型神经元的函数结果为零还是为一，根据第一点还可以知道 $s=-b/w$ 就是阶跃的分界点。当 $x&gt;s$ 时 S 型函数取 1，当 $x&lt;s$时 S 型函数取 0。注意，$s=-b/w$ 时我们将在后文修补阶跃函数中讨论。 S 型神经元的函数变成阶跃函数图形是： 下面的证明中，我们总是让 $|w|$ 的值很大，也就是说我们将一直使用变成阶跃函数的 S 型神经元。并且用 $s$ 表示阶跃函数阶跃的位置。这将用仅仅一个参数 $s$ 来极大简化我们描述隐藏神经元的方式，这就是阶跃位置，$s =-b/w$。 一个输入和一个输出的普遍性目前为止我们专注于仅仅从顶部隐藏神经元输出。让我们看看整个网络的行为。尤其，我们假设隐藏神经元在计算以阶跃点 $s_1$ （顶部神经元）和 $s_2$ （底部神经元）参数化的节约函数。它们各自有输出权重 $w_1$ 和 $w_2$。是这样的网络： 右边的绘图是隐藏层的加权输出 $w_1 a_1 + w_2 a_2$。这里 $a_1$ 和 $a_2$ 各自是顶部和底部神经元的输出。这些输出由 $a$ 表示，是因为它们通常被称为神经元的激活值。注意，注意整个网络的输出是 $\sigma(w_1 a_1+w_2 a_2 + b)$，其中 $b$ 是隐藏层的偏置。很明显，这不同于隐藏层加权后的输出，也就是我们这里的绘图。我们现在打算专注于隐藏层的加权输出，不一会就会考虑如何把它关联到整个网络的输出。 思考增加和减少每一个输出权重。注意，这如何调整从各自的隐藏神经元的贡献值。当一个权重是 0 时会发生什么？ 最后，试着设置 $w_1$ 为 $0.8$，$w_2$ 为 $-0.8$。你得到一个“凸起”的函数，它从点 $s_1$ 开始，到点 $s_2$ 结束，高为 $0.8$。例如，加权后的输出可能看起来像这样： 当然，我们可以调整为任意的凸起高度。让我们用一个参数，$h$，来表示高度。为了减少混乱我也会移除“$s_1 = \ldots$”和“$w_1 = \ldots$”的标记。 试着将 $h$ 值改大或改小，看看凸起的高度如何改变。试着把高度值改为负数，观察发生了什么。并且试着改变阶跃点来看看如何改变凸起的形状。我们可以用凸起制作的技巧来得到两个凸起，通过把两对隐藏神经元一起填充进同一个网络： 这里我抑制了权重，只是简单地在每对隐藏神经元上写了 $h$ 的值。试着增加和减少两个 $h$ 值，观察它如何改变图形。通过修改节点来移动凸起。更普遍地，我们可以利用这个思想来取得我们想要的任何高度的峰值。 其实到这里我们可以说已经证明了神经网络在一个输入和一个输出上的普遍性，因为从微积分的观点来看，只需要增加“凸起”的个数，众多“凸起”合在一起的图形就可更加接近需要近似的函数图形。无限多个“凸起”就能无限逼近于目标函数。一个示意的例子如下， 让我快速总结一下那是如何工作的。 第一层的权重都有一些大的，恒定的值，比如：$w = 1000$。 隐藏神经元上的偏置只是 $b = -w s$。例如，对于第二个隐藏神经元 $s = 0.2$ 变成了 $b = -1000 \times 0.2 = -200$。 最后一层的权重由 $h$ 值决定。例如，我们上面已经选择的第一个 $h$，$h = -0.5$，意味着顶部两个隐藏神经元的相应的输出权重是 $-0.5$ 和 $0.5$。如此等等，确定整个层的输出权重。 最后，输出神经元的偏置为 $0$。 这是所有要做的事情：现在我们有了一个可以很好计算我们原始目标函数的神经网络的完整的描述。而且我们理解如何通过提高隐层神经元的数目来提高近似的质量。 在本质上，我们使用我们的单层神经网络来建立一个函数的查找表。我们将能够建立这个思想，以提供普遍性的一般性证明。 多个输入变量的普遍性让我们把结果扩展到有很多个输入变量的情况下。这听上去挺复杂，但是所有我们需要的概念都可以在两个输入的情况下被理解。所以让我们处理两个输入的情况。我们从考虑当一个神经元有两个输入会发生什么开始： 这里，我们有输入 $x$ 和 $y$，分别对应于权重 $w_1$ 和 $w_2$，以及一个神经元上的偏置 $b$。让我们把权重 $w_2$ 设置为 $0$，然后反复琢磨第一个权重 $w_1$ 和偏置 $b$，看看他们如何影响神经元的输出： 正如我们前面讨论的那样，随着输入权重变大，输出接近一个阶跃函数。不同的是，现在的阶跃函数是在三个维度。也如以前一样，我们可以通过改变偏置的位置来移动阶跃点的位置。阶跃点的实际位置是 $s_x \equiv -b / w_1$。 我们可以用我们刚刚构造的阶跃函数来计算一个三维的凹凸函数。为此，我们使用两个神经元，每个计算一个$x$ 方向的阶跃函数。然后我们用相应的权重 $h$ 和 $-h$ 将这两个阶跃函数混合，这里 $h$ 是凸起的期望高度。所有这些在下面图示中说明： 试着改变高度 $h$ 的值。观察它如何和网络中的权重关联。并看看它如何改变右边凹凸函数的高度。 我们已经解决了如何制造一个 $x$ 方向的凹凸函数。当然，我们可以很容易地制造一个$y$ 方向的凹凸函数，通过使用 $y$ 方向的两个阶跃函数。回想一下，我们通过使 $y$输入的权重变大，$x$ 输入的权重为 $0$ 来这样做。这是结果： 这看上去和前面的网络一模一样！唯一的明显改变的是在我们的隐藏神经元上现在标记有一个小的 $y$。那提醒我们它们在产生 $y$ 方向的阶跃函数，不是 $x$ 方向的，并且 $y$上输入的权重变得非常大，$x$ 上的输入为 $0$，而不是相反。正如前面，我决定不去明确显示它，以避免图形杂乱。 让我们考虑当我们叠加两个凹凸函数时会发生什么，一个沿 $x$ 方向，另一个沿 $y$ 方向，两者都有高度 $h$： 为了简化图形，我丢掉了权重为 $0$ 的连接。现在，我在隐藏神经元上留下了 $x$ 和 $y$的标记，来提醒你凹凸函数在哪个方向上被计算。后面我们甚至为丢掉这些标记，因为它们已经由输入变量说明了。试着改变参数 $h$。正如你能看到，这引起输出权重的变化，以及 $x$ 和 $y$ 上凹凸函数的高度。 我们构建的有点像是一个塔型函数，如果我们能构建这样的塔型函数，那么我们能使用它们来近似任意的函数。 如果我们选择适当的阈值，比如，$3h/2$，这是高原的高度和中央塔的高度中间的值 ——我们可以把高原下降到零，并且依旧矗立着塔。 你能明白怎么做吗？试着用下面的网络做实验来解决。请注意， 我们现在正在绘制整个网络的输出，而不是只从隐藏层的加权输出。这意味着我们增加了一个偏置项到隐藏层的加权输出，并应用 S 型函数。 你能找到 $h$ 和 $b$ 的值，能产生一个塔型吗？这有点难，所以如果你想了一会儿还是困住，这是有两个提示：（1）为了让输出神经元显示正确的行为，我们需要输入的权重（所有 $h$ 或 $-h$）变得很大；（2）$b$ 的值决定了阈值的大小。 这是它看起来的样子，我们使用 $h = 10$： 甚至对于这个相对适中的 $h$ 值，我们得到了一个相当好的塔型函数。当然，我们可以通过更进一步增加 $h$ 并保持偏置$b = -3h/2$ 来使它如我们所希望的那样。 让我们尝试将两个这样的网络组合在一起，来计算两个不同的塔型函数。为了使这两个子网络更清楚，我把它们放在如下所示的分开的方形区域：每个方块计算一个塔型函数，使用上面描述的技术。图上显示了第二个隐藏层的加权输出，即，它是一个加权组合的塔型函数。 尤其你能看到通过修改最终层的权重能改变输出塔型的高度。同样的想法可以用在计算我们想要的任意多的塔型。我们也可以让它们变得任意细，任意高。通过使第二个隐藏层的加权输出为 $\sigma^{-1} \circ f$ 的近似，我们可以确保网络的输出可以是任意期望函数 $f$ 的近似。 让我们试试三个变量 $x_1, x_2, x_3$。下面的网络可以用来计算一个四维的塔型函数： 这里，$x_1, x_2, x_3$ 表示网络的输入。$s_1, t_1$ 等等是神经元的阶跃点~——~即，第一层中所有的权重是很大的，而偏置被设置为给出阶跃点 $s_1, t_1, s_2, \ldots$。第二层中的权重交替设置为 $+h, -h$，其中 $h$ 是一个非常大的数。输出偏置为 $-5h/2$。 这个网络计算这样一个函数，当三个条件满足时：$x_1$ 在 $s_1$ 和 $t_1$ 之间；$x_2$在$s_2$ 和 $t_2$ 之间；$x_3$ 在 $s_3$ 和 $t_3$ 之间，输出为 $1$。其它情况网络输出为 $0$。即，这个塔型在输入空间的一个小的区域输出为 $1$，其它情况输出 $0$。 通过组合许多个这样的网络我们能得到任意多的塔型，如此可近似一个任意的三元函数。对于 $m$ 维可用完全相同的思想。唯一需要改变的是将输出偏置设为 $(-m+1/2)h$，为了得到正确的夹在中间的行为来弄平高原。 好了，所以现在我们知道如何用神经网络来近似一个多元的实值函数。对于 $f(x_1,\ldots, x_m) \in R^n$ 的向量函数怎么样？当然，这样一个函数可以被视为 $n$ 个单独的实值函数： $f^1(x_1, \ldots, x_m)$， $f^2(x_1, \ldots, x_m)$ 等等。所以我们创建一个网络来近似 $f^1$，另一个来近似 $f^2$，如此等等。然后简单地把这些网络都组合起来。 所以这也很容易应付。 思考 我们已经看到如何使用具有两个隐藏层的网络来近似一个任意函数。你能否找到一个证明，证明只有一个隐藏层是可行的？作为一个提示，试着在只有两个输入变量的情况下工作，并证明：（a）可以得到一个不仅仅在 $x$ 和 $y$ 方向，而是在一个任意方向上的阶跃函数；（b）可以通过累加许多的源自（a）的结构，近似出一个塔型的函数，其形状是圆的，而不是方的；（c）使用这些圆形塔，可以近似一个任意函数。对于（c）可以使用本章稍后的一些思想。 S 型神经元的延伸我们已经证明了由 S 型神经元构成的网络可以计算任何函数。回想下在一个 S 型神经元中，输入$x_1, x_2, \ldots$ 导致输出 $\sigma(\sum_j w_j x_j + b)$，这里 $w_j$ 是权重，$b$ 是偏置，而 $\sigma$ 是 S 型函数： 如果我们考虑一个不同类型的神经元，它使用其它激活函数，比如如下的 $s(z)$，会怎样？ 更确切地说，我们假定如果神经元有输入 $x_1, x_2, \ldots$，权重 $w_1, w_2, \ldots$和偏置 $b$，那么输出为 $s(\sum_j w_j x_j + b)$。我们可以使用这个激活函数来得到一个阶跃函数，正如用 S 型函数做过的一样。 正如使用 S 型函数的时候，这导致激活函数收缩，并最终变成一个阶跃函数的很好的近似。试着改变偏置，然后你能看到我们可以设置我们想要的阶跃位置。所以我们能使用所有和前面相同的技巧来计算任何期望的函数。 $s(z)$ 需要什么样的性质来满足这样的结果呢？我们确实需要假定 $s(z)$ 在 $z\rightarrow -\infty$ 和 $z \rightarrow \infty$ 时是定义明确的。这两个界限是在我们的阶跃函数上取的两个值。我们也需要假定这两个界限彼此不同。如果它们不是这样，就没有阶跃，只是一个简单的平坦图形！但是如果激活函数 $s(z)$ 满足这些性质，基于这样一个激活函数的神经元可普遍用于计算。 问题 在本书前面我们遇到过其它类型的称为修正线性单元的神经元。解释为什么这样的神经元不满足刚刚给出的普遍性的条件。找到一个普遍性的证明，证明修正线性单元可普遍用于计算。 假设我们考虑线性神经元，即具有激活函数 $s(z) = z$ 的神经元。解释为什么线性神经元不满足刚刚给出的普遍性的条件。证明这样的神经元不能用于通用计算。 修补阶跃函数目前为止，我们假定神经元可以准确生成阶跃函数。这是一个非常好的近似，但也仅仅是近似。实际上，会有一个很窄的故障窗口，如下图说明，在这里函数会表现得和阶跃函数非常不同。 在这些故障窗口中我给出的普遍性的解释会失败。 现在，它不是一个很严重的故障。通过使得输入到神经元的权重为一个足够大的值，我们能把这些故障窗口变得任意小。当然，我们可以把故障窗口窄过我在上面显示的~——~窄得我们的眼睛都看不到。所以也许我们可以不用过于担心这个问题。 尽管如此，有一些方法解决问题是很好的。 实际上，这个问题很容易解决。让我们看看只有一个输入和一个输出的神经网络如何修补其计算函数。同样的想法也可以解决有更多输入和输出的问题。 特别地，假设我们想要我们的网络计算函数 $f$。和以前一样，我们试着设计我们的网络，使得隐藏神经元的加权输出是 $\sigma^{-1} \circ f(x)$： 如果我们要使用前面描述的技术做到这一点，我们会使用隐藏神经元产生一系列的凹凸函数： 再说一下，我夸大了图上的故障窗口大小，好让它们更容易看到。很明显如果我们把所有这些凹凸函数加起来，我们最终会得到一个合理的 $\sigma^{-1} \circ f(x)$ 的近似，除了那些故障窗口。 假设我们使用一系列隐藏神经元来计算我们最初的目标函数的一半，即 $\sigma^{-1} \circ f(x) / 2$，而不是使用刚刚描述的近似。当然，这看上去就像上一个图像的缩小的版本： 并且假设我们使用另一系列隐藏神经元来计算一个 $\sigma^{-1} \circ f(x) / 2$ 的近似，但是用将凹凸图形偏移一半宽度： 现在我们有两个不同的 $\sigma^{-1} \circ f(x) / 2$ 的近似。如果我们把这两个近似图形加起来，我们会得到一个 $\sigma^{-1} \circ f(x)$ 的整体近似。这个整体的近似仍然在一些小窗口的地方有故障。但是问题比以前要小很多。原因是在一个近似中的故障窗口的点，不会在另一个的故障窗口中。所以在这些窗口中，近似会有 $2$ 倍的因素更好。 我们甚至能通过加入大量的，用 $M$ 表示，重叠的近似 $\sigma^{-1} \circ f(x) / M$来做得更好。假设故障窗口已经足够窄了，其中的点只会在一个故障窗口中。并且假设我们使用一个 $M$ 足够大的重叠近似，结果会是一个非常好的整体近似。 结论我们已经讨论的对于普遍性的解释当然不是如何使用神经网络计算的切实可行的用法！其更像是 NAND 门或者其它类似的普遍性证明。因为这个原因，我主要专注于让解释更清晰和易于理解，而不是过于挖掘细节。然而，你可以发现如果你能改进这个解释是个很有趣和有教益的练习。 尽管这个结果并不能直接用于解释网络，它还是是很重要的，因为它解开了是否使用一个神经网络可以计算任意特定函数的问题。对这个问题的答案总是“是”。所以需要问的正确问题，并不是是否任意函数可计算，而是计算函数的好的方法是什么。 我们建立的对于普遍性的解释只使用了两个隐藏层来计算一个任意的函数。而且，正如我们已经讨论过的，只使用单个的隐藏层来取得相同的结果是可能的。鉴于此，你可能想知道为什么我们会对深度网络感兴趣，即具有很多隐藏层的网络。我们不能简单地把这些网络用浅层的、单个隐藏层的网络替换吗？ 尽管在原理上这是可能的，使用深度网络仍然有实际的原因。正如在第一章中表明过，深度网络有一个分级结构，使其尤其适用于学习分级的知识，这看上去可用于解决现实世界的问题。但是更具体地，当攻克诸如图像识别的问题，使用一个不仅能理解单独的像素，还能理解越来越复杂的概念的系统是有帮助的，这里说的复杂的概念，可以从图像的边缘信息到简单的几何形状，以及所有复杂的、多物体场景的方式。在后面的章节中，我们将看到在学习这样的分级知识时，深度网络要比浅层网络做得更好。总结一下： 普遍性告诉我们神经网络能计算任何函数；而实际经验依据提示深度网络最能适用于学习能够解决许多现实世界问题的函数。 参考文献[1] Michael Nielsen. CHAPTER 4 A visual proof that neural nets can compute any function[DB/OL]. http://neuralnetworksanddeeplearning.com/chap4.html, 2018-06-29. [2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL].https://github.com/zhanggyb/nndl/blob/master/chap4.tex, 2018-06-29.]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[改进神经网络的学习方法——如何选择神经网络的超参数]]></title>
    <url>%2F2018%2F06%2F28%2F%E6%94%B9%E8%BF%9B%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95%E2%80%94%E2%80%94%E5%A6%82%E4%BD%95%E9%80%89%E6%8B%A9%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E8%B6%85%E5%8F%82%E6%95%B0%2F</url>
    <content type="text"><![CDATA[原文链接：CHAPTER 3 Improving the way neural networks learn 为什么选择神经网络的超参数是个难题直到现在，我们还没有解释对诸如学习率 $\eta$，正则化参数 $\lambda$ 等等超参数选择的方法。我只是给出那些效果很好的值而已。实践中，当你使用神经网络解决问题时，寻找好的超参数其实是很困难的一件事。例如，我们要解决 MNIST 问题，开始时对于选择什么样的超参数一无所知。假设，刚开始的实验中选择前面章节的参数都是运气较好。但在使用学习率 $\eta=10.0$ 而正则化参数 $\lambda=1000.0$。下面是我们的一个尝试： 1234567891011121314151617181920212223242526&gt;&gt;&gt; import mnist_loader&gt;&gt;&gt; training_data, validation_data, test_data = \... mnist_loader.load_data_wrapper()&gt;&gt;&gt; import network2&gt;&gt;&gt; net = network2.Network([784, 30, 10])&gt;&gt;&gt; net.SGD(training_data, 30, 10, 10.0, lmbda = 1000.0,... evaluation_data=validation_data, monitor_evaluation_accuracy=True)Epoch 0 training completeAccuracy on evaluation data: 1030 / 10000Epoch 1 training completeAccuracy on evaluation data: 990 / 10000Epoch 2 training completeAccuracy on evaluation data: 1009 / 10000...Epoch 27 training completeAccuracy on evaluation data: 1009 / 10000Epoch 28 training completeAccuracy on evaluation data: 983 / 10000Epoch 29 training completeAccuracy on evaluation data: 967 / 10000 我们分类准确率并不比随机选择更好。网络就像随机噪声产生器一样。 你可能会说，“这好办，降低学习率和正则化参数就好了。”不幸的是，你并不先验地知道这些就是需要调整的超参数。可能真正的问题出在 $30$ 个隐藏元中，本身就不能很有效，不管我们如何调整其他的超参数都没有作用的？可能我们真的需要至少 $100$ 个隐藏神经元？或者是 $300$ 个隐藏神经元？或者更多层的网络？或者不同输出编码方式？可能我们的网络一直在学习，只是学习的回合还不够？可能 minibatch 设的太小了？可能我们需要切换成二次代价函数？可能我们需要尝试不同的权重初始化方法？等等。很容易就在超参数的选择中迷失了方向。如果你的网络规模很大，或者使用了很多的训练数据，这种情况就很令人失望了，因为一次训练可能就要几个小时甚至几天乃至几周，最终什么都没有获得。如果这种情况一直发生，就会打击你的自信心。可能你会怀疑神经网络是不是适合你所遇到的问题？可能就应该放弃这种尝试了？ 本节，我会给出一些用于设定超参数的启发式想法。目的是帮你发展出一套工作流来确保很好地设置超参数。当然，我不会覆盖超参数优化的每个方法。那是太繁重的问题，而且也不会是一个能够完全解决的问题，也不存在一种通用的关于正确策略的共同认知。总是会有一些新的技巧可以帮助你提高一点性能。但是本节的启发式想法能帮你开个好头。 宽泛策略（Broad strategy）在使用神经网络来解决新的问题时，一个挑战就是获得任何一种非寻常的学习，也就是说，达到比随机的情况更好的结果。这个实际上会很困难，尤其是遇到一种新类型的问题时。让我们看看有哪些策略可以在面临这类困难时候尝试。 假设，我们第一次遇到 MNIST 分类问题。刚开始，你很有激情，但是当第一个神经网络完全失效时，你会觉得有些沮丧。此时就可以将问题简化。丢开训练和验证集合中的那些除了$0$ 和 $1$ 的那些图像。然后试着训练一个网络来区分 $0$ 和 $1$。不仅仅问题比 $10$个分类的情况简化了，同样也会减少 80% 的训练数据，这样就给出了 $5$ 倍的加速。这样可以保证更快的实验，也能给予你关于如何构建好的网络更快的洞察。 你通过简化网络来加速实验进行更有意义的学习。如果你相信 $[784, 10]$ 的网络更可能比随机更加好的分类效果，那么就从这个网络开始实验。这会比训练一个 $[784, 30 ,10]$的网络更快，你可以进一步尝试后一个。 你可以通过提高监控的频率来在试验中获得另一个加速了。 我们可以继续，逐个调整每个超参数，慢慢提升性能。一旦我们找到一种提升性能的 $\eta$ 值，我们就可以尝试寻找好的值。然后按照一个更加复杂的网络架构进行实验，假设是一个有 $10$ 个隐藏元的网络。然后继续调整 $\eta$ 和 $\lambda$。接着调整成 $20$ 个隐藏元。然后将其他的超参数调整再调整。如此进行，在每一步使用我们 hold out 验证数据集来评价性能，使用这些度量来找到越来越好的超参数。当我们这么做的时候，一般都需要花费更多时间来发现由于超参数改变带来的影响，这样就可以一步步减少监控的频率。 所有这些作为一种宽泛的策略看起来很有前途。然而，我想要回到寻找超参数的原点。实际上，即使是上面的讨论也传达出过于乐观的观点。实际上，很容易会遇到神经网络学习不到任何知识的情况。你可能要花费若干天在调整参数上，仍然没有进展。 所以我想要再重申一下在前期你应该从实验中尽可能早的获得快速反馈。 直觉上看，这看起来简化问题和架构仅仅会降低你的效率。实际上，这样能够将进度加快，因为你能够更快地找到传达出有意义的信号的网络。一旦你获得这些信号，你可以尝尝通过微调超参数获得快速的性能提升。这和人生中很多情况一样，万事开头难。 好了，上面就是宽泛的策略。现在我们看看一些具体的设置超参数的推荐。我会聚焦在学习率 $\eta$，L2 regularization参数 $\lambda$，和小批量数据大小。然而，很多的观点同样可以应用在其他的超参数的选择上，包括一些关于网络架构的、其他类型的regularization和一些本书后面遇到的如 momentum co-efficient 这样的超参数。 学习速率（Learning rate）假设我们运行了三个不同学习速率（$\eta=0.025$、$\eta=0.25$、$\eta=2.5$）的 MNIST 网络。我们会像前面介绍的实验那样设置其他的超参数，进行 $30$ 回合，minibatch 大小为 $10$，然后 $\lambda = 5.0$。我们同样会使用整个 $50,000$ 幅训练图像。下面是一副展示了训练代价的变化情况的图： 使用 $\eta=0.025$，代价函数平滑下降到最后的回合。使用 $\eta=0.25$，代价刚开始下降，在大约 $20$ 回合后接近饱和状态，后面就是微小的震荡和随机抖动。最终使用 $\eta=2.5$ 代价从始至终都震荡得非常明显。为了理解震荡的原因，回想一下随机梯度下降其实是期望我们能够逐渐地抵达代价函数的谷底的， 然而，如果 $\eta$ 太大的话，步长也会变大可能会使得算法在接近最小值时候又越过了谷底。这在 $\eta=2.5$ 时非常可能发生。当我们选择 $\eta=0.25$ 时，初始几步将我们带到了谷底附近，但一旦到达了谷底，又很容易跨越过去。而在我们选择 $\eta=0.025$ 时，在前 $30$ 回合的训练中不再受到这个情况的影响。当然，选择太小的%学习速率，也会带来另一个题,\gls*{sgd}算法变慢了。一种更加好的策略其实是，在开始时使用 $\eta=0.25$，随着越来越接近谷底，就换成$\eta=0.025$。这种可变学习速率的方法我们后面会介绍。现在，我们就聚焦在找出一个单独的好的学习速率的选择，$\eta$。 所以，有了这样的想法，我们可以如下设置 $\eta$。 首先，我们选择在训练数据上的代价立即开始下降而非震荡或者增加时作为 $\eta$ 的阈值的估计。这个估计并不需要太过精确。你可以估计这个值的量级，比如说从 $\eta=0.01$ 开始。如果代价在训练的前面若干回合开始下降，你就可以逐步地尝试 $\eta=0.1, 1.0,…$，直到你找到一个 $\eta$ 的值使得在开始若干回合代价就开始震荡或者增加。 相反，如果代价在 $\eta=0.01$ 时就开始震荡或者增加，那就尝试 $\eta=0.001, 0.0001,…$ 直到你找到代价在开始回合就下降的设定。按照这样的方法，我们可以掌握学习速率的阈值的量级的估计。你可以选择性地优化估计，选择那些最大的 $\eta$，比方说 $\eta=0.5$ 或者 $\eta=0.2$（这里也不需要过于精确）。 显然，$\eta$ 实际值不应该比阈值大。实际上，如果 $\eta$ 的值重复使用很多回合的话，你更应该使用稍微小一点的值，例如，阈值的一半这样的选择。这样的选择能够允许你训练更多的回合，不会减慢学习的速度。 在 MNIST 数据中，使用这样的策略会给出一个关于学习速率 $\eta$ 的一个量级的估计，大概是 $0.1$。在一些改良后，我们得到了阈值 $\eta=0.5$。所以，我们按照刚刚的取一半的策略就确定了学习速率为 $\eta=0.25$。实际上，我发现使用 $\eta=0.5$ 在 $30$ 回合内表现是很好的，所以选择更低的学习速率，也没有什么问题。 为什么使用代价函数来选择学习速率？而不是验证集这看起来相当直接。然而，使用训练代价函数来选择 $\eta$ 看起来和我们之前提到的通过验证集来确定超参数的观点有点矛盾。实际上，我们会使用验证准确率来选择正则化超参数，minibatch 大小，和层数及隐藏元个数这些网络参数，等等。为何对学习速率要用不同的方法呢？坦白地说，这些选择其实是我个人美学偏好，个人习惯罢了。原因就是其他的超参数倾向于提升最终的测试集上的分类准确率，所以将他们通过验证准确率来选择更合理一些。然而，学习速率仅仅是偶然地影响最终的分类准确率的。学习率主要的目的是控制梯度下降的步长，监控训练代价是最好的检测步长过大的方法。 所以，这其实就是个人的偏好。在学习的前期，如果验证准确率提升，训练代价通常都在下降。所以在实践中使用那种衡量方式并不会对判断的影响太大。 学习速率调整我们一直都将学习速率设置为常量。但是，通常采用可变的学习速率更加有效。在学习的前期，权重可能非常糟糕。所以最好是使用一个较大的学习速率让权重变化得更快。越往后，我们可以降低学习速率，这样可以作出更加精良的调整。 我们要如何设置学习速率呢？其实有很多方法。一种自然的观点是使用提前终止的想法。就是保持学习速率为一个常量直到验证准确率开始变差。然后按照某个量下降学习速率，比如说按照$10$ 或者 $2$。我们重复此过程若干次，直到学习速率是初始值的 $1/1024$（或者$1/1000$）。那时就终止。 可变学习速率可以提升性能，但是也会产生大量可能的选择。这些选择会让人头疼~——~你可能需要花费很多精力才能优化学习规则。对刚开始实验，我建议使用单一的常量作为学习速率的选择。这会给你一个比较好的近似。后面，如果你想获得更好的性能，值得按照某种规则进行实验，根据我已经给出的资料。 提前停止 来确定训练的周期的数量正如我们在本章前面讨论的那样，提前停止表示在每个回合的最后，我们都要计算验证集上的分类准确率。当准确率不再提升，就终止它。这让选择回合数变得很简单。特别地，也意味着我们不再需要担心显式地掌握回合数和其他超参数的关联。而且，这个过程还是自动的。另外，提前停止也能够帮助我们避免过拟合。尽管在实验前期不采用提前停止，这样可以看到任何过匹配的信号，使用这些来选择正则化方法，但提前停止仍然是一件很棒的事。 我们需要再明确一下什么叫做分类准确率不再提升，这样方可实现提前停止。正如我们已经看到的，分类准确率在整体趋势下降的时候仍旧会抖动或者震荡。如果我们在准确度刚开始下降的时候就停止，那么肯定会错过更好的选择。一种不错的解决方案是如果分类准确率在一段时间内不再提升的时候终止。例如，我们要解决 MNIST 问题。如果分类准确度在近$10$ 个回合都没有提升的时候，我们将其终止。这样不仅可以确保我们不会终止得过快，也能够使我们不要一直干等直到出现提升。 这种 $10$ 回合不提升就终止的规则很适合 MNIST 问题的一开始的探索。然而，网络有时候会在很长时间内于一个特定的分类准确率附近形成平缓的局面，然后才会有提升。如果你尝试获得相当好的性能，这个规则可能就会太过激进了~——~停止得太草率。所以，我建议在你更加深入地理解网络训练的方式时，仅仅在初始阶段使用 $10$ 回合不提升规则，然后逐步地选择更久的回合，比如说：$20$ 回合不提升就终止，$50$ 回合不提升就终止，以此类推。当然，这就引入了一种新的需要优化的超参数！实践中，其实比较容易设置这个超参数来获得相当好的结果。类似地，对不同于 MNIST 的问题，$10$ 回合不提升就终止的规则会太过激进或者太过保守，这都取决于问题本身的特质。然而，进行一些小的实验，发现好的提前终止的策略还是非常简单的。 我们还没有在我们的 MNIST 实验中使用提前终止。原因是我们已经比较了不同的学习观点。这样的比较其实比较适合使用同样的训练回合。但是，在 network2.py 中实现提前终止还是很有价值的： 小批量数据的大小我们应该如何设置小批量数据的大小？为了回答这个问题，让我们先假设正在进行在线学习，也就是说使用大小为 $1$ 的小批量数据。 一个关于在线学习的担忧是使用只有一个样本的小批量数据会带来关于梯度的错误估计。实际上，误差并不会真的产生这个问题。原因在于单一的梯度估计不需要绝对精确。我们需要的是确保代价函数保持下降的足够精确的估计。就像你现在要去北极点，但是只有一个不大精确的（差个 $10-20$ 度）指南针。如果你不断频繁地检查指南针，指南针会在平均状况下给出正确的方向，所以最后你也能抵达北极点。 基于这个观点，这看起来好像我们需要使用在线学习。实际上，情况会变得更加复杂。在上一章的问题中我指出我们可以使用矩阵技术来对所有在小批量数据中的样本同时计算梯度更新，而不是进行循环。所以，取决于硬件和线性代数库的实现细节，这会比循环方式进行梯度更新快好多。也许是 $50$ 和 $100$ 倍的差别。 现在，看起来这对我们帮助不大。我们使用 $100$ 的小批量数据的学习规则如下; w \rightarrow w' = w-\eta \frac{1}{100} \sum_x \nabla C_x这里是对小批量数据中所有训练样本求和。而在线学习是 w \rightarrow w' = w-\eta \nabla C_x即使它仅仅是 $50$ 倍的时间，结果仍然比直接在线学习更好，因为我们在线学习更新得太过频繁了。假设，在小批量数据下，我们将学习率扩大了 $100$ 倍，更新规则就是 w \rightarrow w' = w-\eta \sum_x \nabla C_x这看起来像做了 $100$ 次独立的在线学习。但是仅仅花费了 $50$ 次在线学习的时间。当然，其实不是同样的 100 次在线学习，因为小批量数据中 $\nabla C_x$ 是都对同样的权重进行衡量的，而在线学习中是累加的学习。使用更大的小批量数据看起来还是显著地能够进行训练加速的。 所以，选择最好的小批量数据大小也是一种折衷。太小了，你不会用上很好的矩阵库的快速计算。太大，你是不能够足够频繁地更新权重的。你所需要的是选择一个折衷的值，可以最大化学习的速度。 幸运的是，小批量数据大小的选择其实是相对独立的一个超参数（网络整体架构外的参数），所以你不需要优化那些参数来寻找好的小批量数据大小。因此，可以选择的方式就是使用某些可以接受的值（不需要是最优的）作为其他参数的选择，然后进行不同小批量数据大小的尝试，像上面那样调整 $\eta$。画出验证准确率的值随时间（非回合）变化的图，选择哪个得到最快性能的提升的小批量数据大小。得到了小批量数据大小，也就可以对其他的超参数进行优化了。 当然，你也发现了，我这里并没有做到这么多。实际上，我们的实现并没有使用到小批量数据更新快速方法。就是简单使用了小批量数据大小为 $10$。所以，我们其实可以通过降低小批量数据大小来进行提速。我也没有这样做，因为我希望展示小批量数据大于$1$ 的使用，也因为我实践经验表示提升效果其实不明显。在实践中，我们大多数情况肯定是要实现更快的小批量数据更新策略，然后花费时间精力来优化小批量数据大小，来达到总体的速度提升。 自动技术：我已经给出很多在手动进行超参数优化时的启发式规则。手动选择当然是种理解网络行为的方法。不过，现实是，很多工作已经使用自动化过程进行。通常的技术就是网格搜索，可以系统化地对超参数的参数空间的网格进行搜索。网格搜索的成就和限制（易于实现的变体）在 James Bergstra 和 Yoshua Bengio $2012$年的论文作者为 James Bergstra 和 Yoshua Bengio（2012）。中已经给出了综述。很多更加精细的方法也被大家提出来了。 总结跟随上面的经验并不能帮助你的网络给出绝对最优的结果。但是很可能给你一个好的开始和一个改进的基础。特别地，我已经非常独立地讨论了超参数的选择。实践中，超参数之间存在着很多关系。你可能使用 $\eta$ 进行试验，发现效果不错，然后去优化 $\lambda$，发现这里又和 $\eta$ 混在一起了。在实践中，一般是来回往复进行的，最终逐步地选择到好的值。总之，启发式规则其实都是经验，不是金规玉律。你应该注意那些没有效果的尝试的信号，然后乐于尝试更多试验。特别地，这意味着需要更加细致地监控神经网络的行为，特别是验证集上的准确率。 选择超参数的难度在于如何选择超参数的方法太分散, 这些方法分散在许多的研究论文，软件程序甚至仅仅在一些研究人员的大脑中, 因而变得更加困难。很多很多的论文给出了（有时候矛盾的）建议。 设定超参数的挑战让一些人抱怨神经网络相比较其他的机器学习算法需要大量的工作进行参数选择。我也听到很多不同的版本：“的确，参数完美的神经网络可能会在这问题上获得最优的性能。但是，我可以尝试一下随机森林（或者 SVM 或者……这里脑补自己偏爱的技术）也能够工作的。我没有时间搞清楚那个最好的神经网络。” 当然，从一个实践者角度，肯定是应用更加容易的技术。这在你刚开始处理某个问题时尤其如此，因为那时候，你都不确定一个机器学习算法能够解决那个问题。但是，如果获得最优的性能是最重要的目标的话，你就可能需要尝试更加复杂精妙的知识的方法了。如果机器学习总是简单的话那是太好不过了，但也没有什么理由说机器学习非得这么简单。 参考文献[1] Michael Nielsen. CHAPTER 3 Improving the way neural networks learn[DB/OL]. http://neuralnetworksanddeeplearning.com/chap3.html, 2018-06-28. [2] Zhu Xiaohu. Zhang Freeman. Another Chinese Translation of Neural Networks and Deep Learning[DB/OL]. https://github.com/zhanggyb/nndl/blob/master/chap3.tex, 2018-06-28.]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>超参数</tag>
        <tag>Broad strategy</tag>
        <tag>Learning rate</tag>
        <tag>Early stopping</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[改进神经网络的学习方法——代码实现]]></title>
    <url>%2F2018%2F06%2F27%2F%E6%94%B9%E8%BF%9B%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95%E2%80%94%E2%80%94%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%2F</url>
    <content type="text"><![CDATA[原文链接：CHAPTER 3 Improving the way neural networks learn 再看手写识别问题：代码让我们实现本章讨论过的这些想法（交叉熵、正则化、初始化权重等等）。我们将写出一个新的程序，network2.py，这是一个对中开发的 network.py 的改进版本。如果你没有仔细看过 network.py，那你可能会需要重读前面关于这段代码的讨论。仅仅 $74$ 行代码，也很易懂。对 network.py 的详细讲解见第一章的 使用神经网络识别手写数字——代码实现 和 network.py 一样，主要部分就是 Network 类了，我们用这个来表示神经网络。使用一个 sizes 的列表来对每个对应层进行初始化，默认使用交叉熵作为代价 cost 参数： 1234567class Network(object): def __init__(self, sizes, cost=CrossEntropyCost): self.num_layers = len(sizes) self.sizes = sizes self.default_weight_initializer() self.cost=cost 最开始几行里的 方法的和 network.py 中一样，可以轻易弄懂。但是下面两行是新的，我们需要知道他们到底做了什么。12345678910### 权重初始化我们先看看 default_weight_initializer 方法，使用了我们新式改进后的初始权重方法。如我们已经看到的，使用了均值为 $0$ 而标准差为 $1/\sqrt&#123;n&#125;$，$n$ 为对应的输入连接个数。我们使用均值为 $0$ 而标准差为 $1$ 的高斯分布来初始化偏置。下面是代码：```Pythondef default_weight_initializer(self): self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]] self.weights = [np.random.randn(y, x)/np.sqrt(x) for x, y in zip(self.sizes[:-1], self.sizes[1:])] 为了理解这段代码，需要知道 np 就是进行线性代数运算的 Numpy 库。我们在程序的开头会 import Numpy。同样我们没有对第一层的神经元的偏置进行初始化。因为第一层其实是输入层，所以不需要引入任何的偏置。我们在 network.py 中做了完全一样的事情。 作为 default_weight_initializer 的补充，我们同样包含了一个 large_weight_initializer 方法。这个方法使用了第一章中的观点初始化了 权重和偏置。代码也就仅仅是和 default_weight_initializer 差了一点点了： 1234def large_weight_initializer(self): self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]] self.weights = [np.random.randn(y, x) for x, y in zip(self.sizes[:-1], self.sizes[1:])] 我将 larger_weight_initializer 方法包含进来的原因也就是使得跟第一章的结果更容易比较。我并没有考虑太多的推荐使用这个方法的实际情景。 交叉熵初始化方法 ``` 中的第二个新的东西就是我们初始化了 cost 属性。为了理解这个工作的原理，让我们看一下用来表示交叉熵代价的类1234567891011```Pythonclass CrossEntropyCost(object): @staticmethod def fn(a, y): return np.sum(np.nan_to_num(-y*np.log(a)-(1-y)*np.log(1-a))) @staticmethod def delta(z, a, y): return (a-y) 让我们分解一下。第一个看到的是：即使使用的是交叉熵，数学上看，就是一个函数，这里我们用 Python 的类而不是 Python 函数实现了它。为什么这样做呢？答案就是代价函数在我们的网络中扮演了两种不同的角色。明显的角色就是代价是输出激活值 $a$ 和目标输出 $y$ 差距优劣的度量。这个角色通过 CrossEntropyCost.fn 方法来扮演。（注意，np.nan_to_num 调用确保了 Numpy 正确处理接近 $0$ 的对数值）但是代价函数其实还有另一个角色。回想第二章中运行反向传播算法时，我们需要计算网络输出误差，$\delta^L$。这种形式的输出误差依赖于 代价函数的选择：不同的代价函数，输出误差的形式就不同。对于交叉熵函数，输出误差就如公式所示： \delta^L = a^L-y类似地，network2.py 还包含了一个表示二次代价函数的类。这个是用来和第一章的结果进行对比的，因为后面我们几乎都在使用交叉函数。代码如下。QuadraticCost.fn 方法是关于网络输出 $a$ 和目标输出 $y$ 的二次代价函数的直接计算结果。由 QuadraticCost.delta! 返回的值基于二次代价函数的误差表达式，我们在第二章中得到它。 123456789class QuadraticCost(object): @staticmethod def fn(a, y): return 0.5*np.linalg.norm(a-y)**2 @staticmethod def delta(z, a, y): return (a-y) * sigmoid_prime(z) Network2.py 完整代码现在，我们理解了 network2.py 和 network.py 两个实现之间的主要差别。都是很简单的东西。还有一些更小的变动，下面我们会进行介绍，包含 L2 正则化的实现。在讲述正则化之前，我们看看 network2.py 完整的实现代码。你不需要太仔细地读遍这些代码，但是对整个结构尤其是文档中的内容的理解是非常重要的，这样，你就可以理解每段程序所做的工作。当然，你也可以随自己意愿去深入研究！如果你迷失了理解，那么请读读下面的讲解，然后再回到代码中。不多说了，给代码： 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315"""network2.py~~~~~~~~~~~~~~An improved version of network.py, implementing the stochasticgradient descent learning algorithm for a feedforward neural network.Improvements include the addition of the cross-entropy cost function,regularization, and better initialization of network weights. Notethat I have focused on making the code simple, easily readable, andeasily modifiable. It is not optimized, and omits many desirablefeatures."""#### Libraries# Standard libraryimport jsonimport randomimport sys# Third-party librariesimport numpy as np#### Define the quadratic and cross-entropy cost functionsclass QuadraticCost(object): @staticmethod def fn(a, y): """Return the cost associated with an output ``a`` and desired output ``y``. """ return 0.5*np.linalg.norm(a-y)**2 @staticmethod def delta(z, a, y): """Return the error delta from the output layer.""" return (a-y) * sigmoid_prime(z)class CrossEntropyCost(object): @staticmethod def fn(a, y): """Return the cost associated with an output ``a`` and desired output ``y``. Note that np.nan_to_num is used to ensure numerical stability. In particular, if both ``a`` and ``y`` have a 1.0 in the same slot, then the expression (1-y)*np.log(1-a) returns nan. The np.nan_to_num ensures that that is converted to the correct value (0.0). """ return np.sum(np.nan_to_num(-y*np.log(a)-(1-y)*np.log(1-a))) @staticmethod def delta(z, a, y): """Return the error delta from the output layer. Note that the parameter ``z`` is not used by the method. It is included in the method's parameters in order to make the interface consistent with the delta method for other cost classes. """ return (a-y)#### Main Network classclass Network(object): def __init__(self, sizes, cost=CrossEntropyCost): """The list ``sizes`` contains the number of neurons in the respective layers of the network. For example, if the list was [2, 3, 1] then it would be a three-layer network, with the first layer containing 2 neurons, the second layer 3 neurons, and the third layer 1 neuron. The biases and weights for the network are initialized randomly, using ``self.default_weight_initializer`` (see docstring for that method). """ self.num_layers = len(sizes) self.sizes = sizes self.default_weight_initializer() self.cost=cost def default_weight_initializer(self): """Initialize each weight using a Gaussian distribution with mean 0 and standard deviation 1 over the square root of the number of weights connecting to the same neuron. Initialize the biases using a Gaussian distribution with mean 0 and standard deviation 1. Note that the first layer is assumed to be an input layer, and by convention we won't set any biases for those neurons, since biases are only ever used in computing the outputs from later layers. """ self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]] self.weights = [np.random.randn(y, x)/np.sqrt(x) for x, y in zip(self.sizes[:-1], self.sizes[1:])] def large_weight_initializer(self): """Initialize the weights using a Gaussian distribution with mean 0 and standard deviation 1. Initialize the biases using a Gaussian distribution with mean 0 and standard deviation 1. Note that the first layer is assumed to be an input layer, and by convention we won't set any biases for those neurons, since biases are only ever used in computing the outputs from later layers. This weight and bias initializer uses the same approach as in Chapter 1, and is included for purposes of comparison. It will usually be better to use the default weight initializer instead. """ self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]] self.weights = [np.random.randn(y, x) for x, y in zip(self.sizes[:-1], self.sizes[1:])] def feedforward(self, a): """Return the output of the network if ``a`` is input.""" for b, w in zip(self.biases, self.weights): a = sigmoid(np.dot(w, a)+b) return a def SGD(self, training_data, epochs, mini_batch_size, eta, lmbda = 0.0, evaluation_data=None, monitor_evaluation_cost=False, monitor_evaluation_accuracy=False, monitor_training_cost=False, monitor_training_accuracy=False): """Train the neural network using mini-batch stochastic gradient descent. The ``training_data`` is a list of tuples ``(x, y)`` representing the training inputs and the desired outputs. The other non-optional parameters are self-explanatory, as is the regularization parameter ``lmbda``. The method also accepts ``evaluation_data``, usually either the validation or test data. We can monitor the cost and accuracy on either the evaluation data or the training data, by setting the appropriate flags. The method returns a tuple containing four lists: the (per-epoch) costs on the evaluation data, the accuracies on the evaluation data, the costs on the training data, and the accuracies on the training data. All values are evaluated at the end of each training epoch. So, for example, if we train for 30 epochs, then the first element of the tuple will be a 30-element list containing the cost on the evaluation data at the end of each epoch. Note that the lists are empty if the corresponding flag is not set. """ if evaluation_data: n_data = len(evaluation_data) n = len(training_data) evaluation_cost, evaluation_accuracy = [], [] training_cost, training_accuracy = [], [] for j in xrange(epochs): random.shuffle(training_data) mini_batches = [ training_data[k:k+mini_batch_size] for k in xrange(0, n, mini_batch_size)] for mini_batch in mini_batches: self.update_mini_batch( mini_batch, eta, lmbda, len(training_data)) print "Epoch %s training complete" % j if monitor_training_cost: cost = self.total_cost(training_data, lmbda) training_cost.append(cost) print "Cost on training data: &#123;&#125;".format(cost) if monitor_training_accuracy: accuracy = self.accuracy(training_data, convert=True) training_accuracy.append(accuracy) print "Accuracy on training data: &#123;&#125; / &#123;&#125;".format( accuracy, n) if monitor_evaluation_cost: cost = self.total_cost(evaluation_data, lmbda, convert=True) evaluation_cost.append(cost) print "Cost on evaluation data: &#123;&#125;".format(cost) if monitor_evaluation_accuracy: accuracy = self.accuracy(evaluation_data) evaluation_accuracy.append(accuracy) print "Accuracy on evaluation data: &#123;&#125; / &#123;&#125;".format( self.accuracy(evaluation_data), n_data) print return evaluation_cost, evaluation_accuracy, \ training_cost, training_accuracy def update_mini_batch(self, mini_batch, eta, lmbda, n): """Update the network's weights and biases by applying gradient descent using backpropagation to a single mini batch. The ``mini_batch`` is a list of tuples ``(x, y)``, ``eta`` is the learning rate, ``lmbda`` is the regularization parameter, and ``n`` is the total size of the training data set. """ nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] for x, y in mini_batch: delta_nabla_b, delta_nabla_w = self.backprop(x, y) nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)] nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)] self.weights = [(1-eta*(lmbda/n))*w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)] self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)] def backprop(self, x, y): """Return a tuple ``(nabla_b, nabla_w)`` representing the gradient for the cost function C_x. ``nabla_b`` and ``nabla_w`` are layer-by-layer lists of numpy arrays, similar to ``self.biases`` and ``self.weights``.""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] # feedforward activation = x activations = [x] # list to store all the activations, layer by layer zs = [] # list to store all the z vectors, layer by layer for b, w in zip(self.biases, self.weights): z = np.dot(w, activation)+b zs.append(z) activation = sigmoid(z) activations.append(activation) # backward pass delta = (self.cost).delta(zs[-1], activations[-1], y) nabla_b[-1] = delta nabla_w[-1] = np.dot(delta, activations[-2].transpose()) # Note that the variable l in the loop below is used a little # differently to the notation in Chapter 2 of the book. Here, # l = 1 means the last layer of neurons, l = 2 is the # second-last layer, and so on. It's a renumbering of the # scheme in the book, used here to take advantage of the fact # that Python can use negative indices in lists. for l in xrange(2, self.num_layers): z = zs[-l] sp = sigmoid_prime(z) delta = np.dot(self.weights[-l+1].transpose(), delta) * sp nabla_b[-l] = delta nabla_w[-l] = np.dot(delta, activations[-l-1].transpose()) return (nabla_b, nabla_w) def accuracy(self, data, convert=False): """Return the number of inputs in ``data`` for which the neural network outputs the correct result. The neural network's output is assumed to be the index of whichever neuron in the final layer has the highest activation. The flag ``convert`` should be set to False if the data set is validation or test data (the usual case), and to True if the data set is the training data. The need for this flag arises due to differences in the way the results ``y`` are represented in the different data sets. In particular, it flags whether we need to convert between the different representations. It may seem strange to use different representations for the different data sets. Why not use the same representation for all three data sets? It's done for efficiency reasons -- the program usually evaluates the cost on the training data and the accuracy on other data sets. These are different types of computations, and using different representations speeds things up. More details on the representations can be found in mnist_loader.load_data_wrapper. """ if convert: results = [(np.argmax(self.feedforward(x)), np.argmax(y)) for (x, y) in data] else: results = [(np.argmax(self.feedforward(x)), y) for (x, y) in data] return sum(int(x == y) for (x, y) in results) def total_cost(self, data, lmbda, convert=False): """Return the total cost for the data set ``data``. The flag ``convert`` should be set to False if the data set is the training data (the usual case), and to True if the data set is the validation or test data. See comments on the similar (but reversed) convention for the ``accuracy`` method, above. """ cost = 0.0 for x, y in data: a = self.feedforward(x) if convert: y = vectorized_result(y) cost += self.cost.fn(a, y)/len(data) cost += 0.5*(lmbda/len(data))*sum( np.linalg.norm(w)**2 for w in self.weights) return cost def save(self, filename): """Save the neural network to the file ``filename``.""" data = &#123;"sizes": self.sizes, "weights": [w.tolist() for w in self.weights], "biases": [b.tolist() for b in self.biases], "cost": str(self.cost.__name__)&#125; f = open(filename, "w") json.dump(data, f) f.close()#### Loading a Networkdef load(filename): """Load a neural network from the file ``filename``. Returns an instance of Network. """ f = open(filename, "r") data = json.load(f) f.close() cost = getattr(sys.modules[__name__], data["cost"]) net = Network(data["sizes"], cost=cost) net.weights = [np.array(w) for w in data["weights"]] net.biases = [np.array(b) for b in data["biases"]] return net#### Miscellaneous functionsdef vectorized_result(j): """Return a 10-dimensional unit vector with a 1.0 in the j'th position and zeroes elsewhere. This is used to convert a digit (0...9) into a corresponding desired output from the neural network. """ e = np.zeros((10, 1)) e[j] = 1.0 return edef sigmoid(z): """The sigmoid function.""" return 1.0/(1.0+np.exp(-z))def sigmoid_prime(z): """Derivative of the sigmoid function.""" return sigmoid(z)*(1-sigmoid(z)) L1 、L2 正则化有个更加有趣的变动就是在代码中增加了 L2 正则化。尽管这是一个主要的概念上的变动，在实现中其实相当简单。对大部分情况，仅仅需要传递参数 lmbda 到不同的方法中，主要是 Network.SGD 方法。实际上的工作就是一行代码的事在 Network.update_mini_batch 的倒数第四行。这就是我们改动梯度下降规则来进行权重下降的地方。尽管改动很小，但其对结果影响却很大！ 12self.weights = [(1-eta*(lmbda/n))*w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)] 上面代码仅仅是下面 L2 正则化计算式子的简单代码翻译， w = \left(1-\frac{\eta \lambda}{n}\right) w -\eta \frac{\partial C_0}{\partial w}同样的道理根据 L1 正则化的计算式子可以直接翻译成代码， w =w-\frac{\eta \lambda}{n} sgn(w) - \eta \frac{\partial C_0}{\partial w}代码就是 12self.weights = [w-eta*(lmbda/n)*np.sign(w)-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)] 其实这种情况在神经网络中实现一些新技术的常见现象。我们花费了近千字的篇幅来讨论正则化。概念的理解非常微妙困难。但是添加到程序中的时候却如此简单。精妙复杂的技术可以通过微小的代码改动就可以实现了。 Network2.py 构建神经网络的其它注意事项另一个微小却重要的改动是随机梯度下降方法的几个标志位的增加。这些标志位让我们可以对在代价和准确率的监控变得可能。这些标志位默认是 False! 的，但是在我们例子中，已经被置为 True! 来监控 Network 的性能。另外，network2.py 中的 Network.SGD 方法返回了一个四元组来表示监控的结果。我们可以这样使用： 12345678&gt;&gt;&gt; evaluation_cost, evaluation_accuracy,... training_cost, training_accuracy = net.SGD(training_data, 30, 10, 0.5,... lmbda = 5.0,... evaluation_data=validation_data,... monitor_evaluation_accuracy=True,... monitor_evaluation_cost=True,... monitor_training_accuracy=True,... monitor_training_cost=True) 所以，比如 evaluation_cost 将会是一个 $30$ 个元素的列表其中包含了每个周期在验证集合上的代价函数值。这种类型的信息在理解网络行为的过程中特别有用。比如，它可以用来画出展示网络随时间学习的状态。其实，这也是我在前面的章节中展示性能的方式。然而要注意的是如果任何标志位都没有设置的话，对应的元组中的元素就是空列表。 另一个增加项就是在 Network.save 方法中的代码，用来将 Network 对象保存在磁盘上，还有一个载回内存的函数。这两个方法都是使用 JSON 进行的，而非 Python 的 pickle 或者 cPickle 块。这些通常是 Python 中常见的保存和装载对象的方法。使用 JSON 的原因是，假设在未来某天，我们想改变 Network 类来允许非 sigmoid 的神经元。对这个改变的实现，我们最可能是改变在 Network.__init__ 方法中定义的属性。如果我们简单地 pickle 对象，会导致 load 函数出错。使用 JSON 进行序列化可以显式地让老的 Network 仍然能够 load。 其他也还有一些微小的变动。但是那些只是 network.py 的微调。结果就是把程序从 $74$ 行增长到了 $152$ 行。 参考文献[1] Michael Nielsen.CHAPTER 3 Improving the way neural networks learn[DB/OL]. http://neuralnetworksanddeeplearning.com/chap3.html, 2018-06-27. [2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL].https://github.com/zhanggyb/nndl/blob/master/chap3.tex, 2018-06-27. [4] skylook. neural-networks-and-deep-learning, network2.py[DB/OL]. https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/src/network2.py, 2018-06-27.]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>手写数字识别</tag>
        <tag>代码实现</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[卷积神经网络的反向传播算法]]></title>
    <url>%2F2018%2F06%2F26%2F%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E5%8F%8D%E5%90%91%E4%BC%A0%E6%92%AD%E7%AE%97%E6%B3%95%2F</url>
    <content type="text"><![CDATA[阅读本篇前，最好先阅读多层感知机的反向传播算法。反向传播的基础知识和符号定义都在该文章中。卷积神经网络：前向传播算法CNN输入层前向传播到卷积层输入层的前向传播是CNN前向传播算法的第一步。一般输入层对应的都是卷积层。 我们这里还是以图像识别为例。先考虑最简单的，样本都是二维的黑白图片。这样输入层$X$就是一个矩阵，矩阵的值等于图片的各个像素位置的值。这时和卷积层相连的卷积核$W$就也是矩阵如果样本都是有 RGB 的彩色图片，这样输入 $X$ 就是 3 个矩阵，即分别对应 R，G 和 B 的矩阵，或者说是一个张量。这时和卷积层相连的卷积核$W$就也是张量，对应的最后一维的维度为 3 .即每个卷积核都是 3 个子矩阵组成。同样的方法，对于 3D 的彩色图片之类的样本，我们的输入 $X$ 可以是 4 维，5 维的张量，那么对应的卷积核 $W$ 也是个高维的张量。 不管维度多高，对于我们的输入，前向传播的过程可以表示为：a^2= \sigma(z^2) = \sigma(a^1*W^2 +b^2) 其中，上标代表层数，星号代表卷积，而b代表我们的偏倚, $\sigma$为激活函数，这里一般都是ReLU。和多层感知机的前向传播比较一下，其实形式非常的像，只是我们这儿是张量的卷积，而不是矩阵的乘法。同时由于$W$是张量，那么同样的位置，$W$参数的个数就比多层感知机多很多了。 为了简化我们的描述，本文后面如果没有特殊说明，我们都默认输入是3维的张量，即用RBG可以表示的彩色图片。 这里需要我们自己定义的CNN模型参数是： 一般我们的卷积核不止一个，比如有K个，那么我们输入层的输出，或者说第二层卷积层的对应的输入就K个。 卷积核中每个子矩阵的的大小，一般我们都用子矩阵为方阵的卷积核，比如FxF的子矩阵。 填充padding（以下简称P），我们卷积的时候，为了可以更好的识别边缘，一般都会在输入矩阵在周围加上若干圈的0再进行卷积，加多少圈则P为多少。 步幅stride（以下简称S），即在卷积过程中每次移动的像素距离大小。 隐藏层前向传播到卷积层现在我们再来看普通隐藏层前向传播到卷积层时的前向传播算法。 假设隐藏层的输出是M个矩阵对应的三维张量，则输出到卷积层的卷积核也是M个子矩阵对应的三维张量。这时表达式和输入层的很像，也是 a^l= \sigma(z^l) = \sigma(a^{l-1}*W^l +b^l)其中，上标代表层数，星号代表卷积，而 $b$ 代表我们的偏倚, $\sigma$ 为激活函数，这里一般都是ReLU。 也可以写成M个子矩阵子矩阵卷积后对应位置相加的形式，即： a^l= \sigma(z^l) = \sigma(\sum\limits_{k=1}^{M}z_k^l) = \sigma(\sum\limits_{k=1}^{M}a_k^{l-1}*W_k^l +b^l)和CNN输入层前向传播到卷积层的区别仅仅在于，这里的输入是隐藏层来的，而不是我们输入的原始图片样本形成的矩阵。 隐藏层前向传播到池化层池化层的处理逻辑是比较简单的，我们的目的就是对输入的矩阵进行缩小概括。比如输入的若干矩阵是NxN维的，而我们的池化大小是 $k \times k$的区域，则输出的矩阵都是 $\frac{N}{k} \times \frac{N}{k}$ 维的。 这里需要需要我们定义的CNN模型参数是： !. 池化区域的大小 k 池化的标准，一般是 MAX 或者 Average。 隐藏层前向传播到全连接层由于全连接层就是普通的 多层感知机 模型结构，因此我们可以直接使用 多层感知机 的前向传播算法逻辑，即： a^l = \sigma(z^l) = \sigma(W^la^{l-1} + b^l)这里的激活函数一般是 sigmoid 或者 tanh。 经过了若干全连接层之后，最后的一层为Softmax输出层。此时输出层和普通的全连接层唯一的区别是，激活函数是softmax函数。 这里需要需要我们定义的CNN模型参数是： 全连接层的激活函数 全连接层各层神经元的个数 CNN前向传播算法小结有了上面的基础，我们现在总结下CNN的前向传播算法。 输入：1 个图片样本，CNN 模型的层数L和所有隐藏层的类型，对于卷积层，要定义卷积核的大小 K，卷积核子矩阵的维度 F，填充大小 P，步幅 S。对于池化层，要定义池化区域大小 k 和池化标准（MAX或Average），对于全连接层，要定义全连接层的激活函数（输出层除外）和各层的神经元个数。 输出：CNN模型的输出$a^L$ 根据输入层的填充大小P，填充原始图片的边缘，得到输入张量$a^1$。 初始化所有隐藏层的参数$W,b$ for $l$=2 to $L-1$:3.1 如果第$l$层是卷积层,则输出为 a^l= ReLU(z^l) = ReLU(a^{l-1}*W^l +b^l)3.2 如果第$l$层是池化层,则输出为$ a^l= pool(a^{l-1})$, 这里的pool指按照池化区域大小k和池化标准将输入张量缩小的过程。3.3 如果第$l$层是全连接层,则输出为 a^l= \sigma(z^l) = \sigma(W^la^{l-1} +b^l) 对于输出层第L层: a^L= softmax(z^L) = softmax(W^La^{L-1} +b^L) 以上就是 CNN 前向传播算法的过程总结。有了 CNN 前向传播算法的基础，我们后面再来理解CNN的反向传播算法就简单多了。 卷积神经网络：反向传播算法计算池化层的误差 $\delta^l$ {\delta ^l} = {upsample}\left( \delta ^{l + 1} \right) \odot \sigma '\left( \right)池化层用于削减数据量，在这一层上前向传播的数据会有损失，则在反向传播时，传播来的梯度也会有所损失。一般来说，池化层没有参数，于是仅需要计算梯度反向传播的结果。 池化层的反向传播的方法是upsample，先将矩阵还原成原大小，之后： 对于最大值池化，将梯度放置于每个池化区域取得最大值的位置，其他位置为0 对于平均值池化，则把的所有子矩阵的各个池化局域的值取平均后放在还原后的子矩阵位置(在池化的正向计算过程中需记录每个小区域内最大值的位置) 下面是一个upsample的例子： 例如对于矩阵： \left( \begin{array}{} 1& 2 \\ 3& 4 \end{array} \right)假设经过2*2的池化，还原为原来大小： \left( \begin{array}{ccc} 0&0&0&0 \\ 0&1& 2&0 \\ 0&3&4&0 \\ 0&0&0&0 \end{array} \right)若是最大值池化，假设每个窗口的最大值位置都是左上，则传播结果为： \left( \begin{array}{ccc} 1&0&2&0 \\ 0&0& 0&0 \\ 3&0&4&0 \\ 0&0&0&0 \end{array} \right)若是经过平均值池化，则传播结果为： \left( \begin{array}{ccc} 0.25&0.25&0.5&0.5 \\ 0.25&0.25& 0.5&0.5 \\ 0.75&0.75&1&1 \\ 0.75&0.75&1&1 \end{array} \right)卷积层的误差 $\delta^l$\delta^{l-1} = \delta^{l}*rot180(w^{l}) \odot \sigma'(z^{l-1})其中 $rot180(w^{l})$ 为卷积核旋转 180 度的函数，* 为卷积符号。 举一个例子来说，对于以下卷积等式： \left( \begin{array}{ccc} a_{11}&a_{12}&a_{13} \\ a_{21}&a_{22}&a_{23}\\ a_{31}&a_{32}&a_{33} \end{array} \right) * \left( \begin{array}{ccc} w_{11}&w_{12}\\ w_{21}&w_{22} \end{array} \right) = \left( \begin{array}{ccc} z_{11}&z_{12}\\ z_{21}&z_{22} \end{array} \right)对于 $a_11$，有 $z_{11} = a_{11}w_{11} + a_{12}w_{12} + a_{21}w_{21} + a_{22}w_{22}$ ，仅 $z_11$ 与其有关，则有 $\nabla a_{11} = \delta_{11}w_{11}$。对于 $a_22$，所有 $z$ 项都和该数有关，有 $\nabla a_{22} = \delta_{11}w_{22} + \delta_{12}w_{21} + \delta_{21}w_{12} + \delta_{22}w_{11}$。 依次类推，可得： \left( \begin{array}{ccc} 0&0&0&0 \\ 0&\delta_{11}& \delta_{12}&0 \\ 0&\delta_{21}&\delta_{22}&0 \\ 0&0&0&0 \end{array} \right) * \left( \begin{array}{ccc} w_{22}&w_{21}\\ w_{12}&w_{11} \end{array} \right) = \left( \begin{array}{ccc} \nabla a_{11}&\nabla a_{12}&\nabla a_{13} \\ \nabla a_{21}&\nabla a_{22}&\nabla a_{23}\\ \nabla a_{31}&\nabla a_{32}&\nabla a_{33} \end{array} \right)卷积层的权重梯度 $\partial C / \partial w$对权重的梯度为： \frac{\partial C}{\partial w^{l}} = rot180(\delta^l*a^{l-1})同样对于前向传播： \left( \begin{array}{ccc} a_{11}&a_{12}&a_{13} \\ a_{21}&a_{22}&a_{23}\ a_{31}&a_{32}&a_{33} \end{array} \right) * \left( \begin{array}{ccc} w_{11}&w_{12}\\ w_{21}&w_{22} \end{array} \right) = \left( \begin{array}{ccc} z_{11}&z_{12}\\ z_{21}&z_{22} \end{array} \right)对于z，有以下： $z_{11} = a_{11}w_{11} + a_{12}w_{12} + a_{21}w_{21} + a_{22}w_{22}$ $z_{12} = a_{12}w_{11} + a_{13}w_{12} + a_{22}w_{21} + a_{23}w_{22}$ $z_{21} = a_{21}w_{11} + a_{22}w_{12} + a_{31}w_{21} + a_{32}w_{22}$ $z_{22} = a_{22}w_{11} + a_{23}w_{12} + a_{32}w_{21} + a_{33}w_{22}$ 有梯度： $\nabla w_{11} = \delta_{11}a_{11} + \delta_{12}a_{12} + \delta_{21}a_{21} + \delta_{22}a_{22}$ $\nabla w_{12} = \delta_{11}a_{12} + \delta_{12}a_{13} + \delta_{21}a_{22} + \delta_{22}a_{12}$ $\nabla w_{21} = \delta_{11}a_{21} + \delta_{12}a_{22} + \delta_{21}a_{31} + \delta_{22}a_{32}$ $\nabla w_{22} = \delta_{11}a_{22} + \delta_{12}a_{23} + \delta_{32}a_{21} + \delta_{33}a_{22}$ 反向传播为： \left( \begin{array}{ccc} 0&0&0&0 \\ 0&\delta_{11}& \delta_{12}&0 \\ 0&\delta_{21}&\delta_{22}&0 \\ 0&0&0&0 \end{array} \right) * \left( \begin{array}{ccc} a_{11}&a_{12}&a_{13}\\ a_{21}&a_{22}&a_{23}\\ a_{31}&a_{32}&a_{33} \end{array} \right) = \left( \begin{array}{ccc} \nabla w_{22}&\nabla w_{21}\\ \nabla w_{12}&\nabla w_{11} \end{array} \right)卷积层的权重梯度 $\partial C / \partial b$偏置梯度较为简单，为上一层梯度和： \frac{\partial C}{\partial b^{l}} = \sum\limits_{u,v}(\delta^l)_{u,v}卷积神经网络：反向传播算法思想卷积神经网络相比于多层感知机，增加了两种新的层次——卷积层与池化层。由现在我们想把同样的思想用到CNN中，很明显，CNN有些不同的地方，不能直接去套用多层感知机的反向传播算法的公式。 多层感知机反向传播的四个基本方程： 要套用多层感知机的反向传播算法到CNN，有几个问题需要解决： 池化层没有激活函数，这个问题倒比较好解决，我们可以令池化层的激活函数为 $\sigma(z)=z$，即激活后就是自己本身。这样池化层激活函数的导数为 1. 池化层在前向传播的时候，对输入进行了压缩，那么我们现在需要向前反向推导 $\delta^{l-1}$，这个推导方法和多层感知机完全不同。 卷积层是通过张量卷积，或者说若干个矩阵卷积求和而得的当前层的输出，这和多层感知机很不相同，多层感知机的全连接层是直接进行矩阵乘法得到当前层的输出。这样在卷积层反向传播的时候，上一层的 $\delta^{l-1}$ 递推计算方法肯定有所不同。 对于卷积层，由于 $w$ 使用的运算是卷积，那么从 $\delta$ 推导出该层的所有卷积核的 $w, b$ 的方式也不同。 从上面可以看出，问题1比较好解决，但是问题 2, 3, 4 就需要好好的动一番脑筋了，而问题 2, 3, 4也是解决 CNN 反向传播算法的关键所在。另外大家要注意到的是，多层感知机中的 $a^l, z^l$ 都只是一个向量，而我们 CNN 中的 $a^l, z^l$ 都是一个张量，这个张量是三维的，即由若干个输入的子矩阵组成。 下面我们就针对问题 2, 3, 4 来一步步研究CNN的反向传播算法。 在研究过程中，需要注意的是，由于卷积层可以有多个卷积核，各个卷积核的处理方法是完全相同且独立的，为了简化算法公式的复杂度，我们下面提到卷积核都是卷积层中若干卷积核中的一个。 卷积神经网络：反向传播计算公式的证明 {\delta ^l} = {upsample}\left( \delta ^{l + 1} \right) \odot \sigma '\left( {z^l} \right)\delta^{l-1} = \delta^{l}*rot180(w^{l}) \odot \sigma'(z^{l-1})\frac{\partial C}{\partial w^{l}} = rot180(\delta^l*a^{l-1})\frac{\partial C}{\partial b^{l}} = \sum\limits_{u,v}(\delta^l)_{u,v}证明 ${\delta ^l} = {upsample}\left( \delta ^{l + 1} \right) \odot \sigma ‘ \left( {z^l} \right)$我们首先解决上面的问题2，如果已知池化层的$\delta^l$，推导出上一隐藏层的$\delta^{l-1}$。 在前向传播算法时，池化层一般我们会用 MAX 或者 Average 对输入进行池化，池化的区域大小已知。现在我们反过来，要从缩小后的误差 $\delta^l$ ，还原前一次较大区域对应的误差。 在反向传播时，我们首先会把 $\delta^l$ 的所有子矩阵矩阵大小还原成池化之前的大小，然后如果是 MAX，则把 $\delta^l$ 的所有子矩阵的各个池化局域的值放在之前做前向传播算法得到最大值的位置。如果是 Average，则把 $\delta^l$ 的所有子矩阵的各个池化局域的值取平均后放在还原后的子矩阵位置。这个过程一般叫做 upsample。 这样我们就得到了上一层 $\frac{\partial C}{\partial a_k^{l-1}}$的值，要得到 $\delta_k^{l-1}$： \delta_k^{l-1} = \frac{\partial C}{\partial a_k^{l-1}} \frac{\partial a_k^{l-1}}{\partial z_k^{l-1}} = upsample(\delta_k^l) \odot \sigma'(z_k^{l-1})其中，upsample函数完成了池化误差矩阵放大与误差重新分配的逻辑。 我们概括下，对于张量$\delta^{l-1}$，我们有： \delta^{l-1} = upsample(\delta^l) \odot \sigma'(z^{l-1})证明 $\delta^{l-1} = \delta^{l}*rot180(w^{l}) \odot \sigma’(z^{l-1})$对于卷积网络，前向传播公式为： a^l= \sigma(z^l) = \sigma(a^{l-1}*w^l +b^l)注意到 $ \delta^{l-1}$ 和 $\delta^l$ 的递推关系为： \delta^{l} = \frac{\partial C}{\partial z^l} = \frac{\partial C}{\partial z^{l+1}}\frac{\partial z^{l+1}}{\partial z^{l}} = \delta^{l+1}\frac{\partial z^{l+1}}{\partial z^{l}}因此要推导出 $\delta^{l-1}$ 和 $\delta^{l}$ 的递推关系，必须计算 $\frac{\partial z^{l}}{\partial z^{l-1}}$的梯度表达式。 注意到 $z^{l}$和$z^{l-1}$ 的关系为：z^l = a^{l-1}*w^l +b^l =\sigma(z^{l-1})*w^l +b^l 因此我们有： \delta^{l-1} = \delta^{l}\frac{\partial z^{l}}{\partial z^{l-1}} = \delta^{l}*rot180(W^{l}) \odot \sigma'(z^{l-1})这里的式子其实和 DNN 的类似，区别在于对于含有卷积的式子求导时，卷积核被旋转了 180 度。即式子中的 $rot180()$，翻转 180 度的意思是上下翻转一次，接着左右翻转一次。在 DNN 中这里只是矩阵的转置。那么为什么呢？由于这里都是张量，直接推演参数太多了。我们以一个简单的例子说明为啥这里求导后卷积核要翻转。 假设我们 $l-1$ 层的输出 $a^{l-1}$ 是一个 3x3 矩阵，第 $l$ 层的卷积核 $W^l$ 是一个2x2矩阵，采用 1 像素的步幅，则输出 $z^{l}$ 是一个 2x2 的矩阵。我们简化 $b^l$ 都是 $0$,则有 a^{l-1} * w^l = z^{l}我们列出 $a,W,z$ 的矩阵表达式如下： \left( \begin{array}{ccc} a_{11}&a_{12}&a_{13} \\ a_{21}&a_{22}&a_{23}\\ a_{31}&a_{32}&a_{33} \end{array} \right) * \left( \begin{array}{ccc} w_{11}&w_{12}\\ w_{21}&w_{22} \end{array} \right) = \left( \begin{array}{ccc} z_{11}&z_{12}\\ z_{21}&z_{22} \end{array} \right)利用卷积的定义，很容易得出： $z_{11} = a_{11}w_{11} + a_{12}w_{12} + a_{21}w_{21} + a_{22}w_{22}$ $z_{12} = a_{12}w_{11} + a_{13}w_{12} + a_{22}w_{21} + a_{23}w_{22}$ $z_{21} = a_{21}w_{11} + a_{22}w_{12} + a_{31}w_{21} + a_{32}w_{22}$ $z_{22} = a_{22}w_{11} + a_{23}w_{12} + a_{32}w_{21} + a_{33}w_{22}$ 接着我们模拟反向求导： \nabla a^{l-1} = \frac{\partial C}{\partial a^{l-1}} = \frac{\partial C}{\partial z^{l}} \frac{\partial z^{l}}{\partial a^{l-1}} = \delta^{l} \frac{\partial z^{l}}{\partial a^{l-1}}从上式可以看出，对于 $a^{l-1}$ 的梯度误差 $\nabla a^{l-1}$，等于第 $l$ 层的梯度误差乘以 $\frac{\partial z^{l}}{\partial a^{l-1}}$，而 $\frac{\partial z^{l}}{\partial a^{l-1}}$ 对应上面的例子中相关联的 $w$ 的值。假设我们的 $z$ 矩阵对应的反向传播误差是 $\delta_{11}, \delta_{12}, \delta_{21}, \delta_{22}$ 组成的 2x2 矩阵，则利用上面梯度的式子和 4 个等式，我们可以分别写出 $\nabla a^{l-1}$ 的 9 个标量的梯度。 比如对于 $a_{11}$ 的梯度，由于在 4 个等式中 $a_{11}$ 只和 $z_{11}$ 有乘积关系，从而我们有： \nabla a_{11} = \delta_{11}w_{11}对于 $a_{12}$ 的梯度，由于在 4 个等式中 $a_{12}$ 和 $z_{12}, z_{11}$ 有乘积关系，从而我们有： \nabla a_{12} = \delta_{11}w_{12} + \delta_{12}w_{11}同样的道理我们得到： $ \nabla a_{13} = \delta_{12}w_{12} $ $\nabla a_{21} = \delta_{11}w_{21} + \delta_{21}w_{11}$ $\nabla a_{22} = \delta_{11}w_{22} + \delta_{12}w_{21} + \delta_{21}w_{12} + \delta_{22}w_{11}$ $\nabla a_{23} = \delta_{12}w_{22} + \delta_{22}w_{12}$ $\nabla a_{31} = \delta_{21}w_{21}$ $\nabla a_{32} = \delta_{21}w_{22} + \delta_{22}w_{21}$ $\nabla a_{33} = \delta_{22}w_{22}$ 这上面9个式子其实可以用一个矩阵卷积的形式表示，即： \left( \begin{array}{ccc} 0&0&0&0 \\ 0&\delta_{11}& \delta_{12}&0 \\ 0&\delta_{21}&\delta_{22}&0 \\ 0&0&0&0 \end{array} \right) * \left( \begin{array}{ccc} w_{22}&w_{21}\\ w_{12}&w_{11} \end{array} \right) = \left( \begin{array}{ccc} \nabla a_{11}&\nabla a_{12}&\nabla a_{13} \\ \nabla a_{21}&\nabla a_{22}&\nabla a_{23}\\ \nabla a_{31}&\nabla a_{32}&\nabla a_{33} \end{array} \right)为了符合梯度计算，我们在误差矩阵周围填充了一圈0，此时我们将卷积核翻转后和反向传播的梯度误差进行卷积，就得到了前一次的梯度误差。这个例子直观的介绍了为什么对含有卷积的式子求导时，卷积核要翻转180度的原因。 以上就是卷积层的误差反向传播过程。 证明 $\frac{\partial C}{\partial w^{l}} = rot180(\delta^l*a^{l-1})$ 和 $\frac{\partial C}{\partial b^{l}} = \sum\limits_{u,v}(\delta^l)_{u,v}$我们现在已经可以递推出每一层的梯度误差 $\delta^l$ 了，对于全连接层，可以按 DNN 的反向传播算法求该层 $W,b$ 的梯度，而池化层并没有 $W,b$,也不用求 $W,b$ 的梯度。只有卷积层的 $W,b$ 需要求出。 对于卷积网络，前向传播公式为： a^l= \sigma(z^l) = \sigma(a^{l-1}*w^l +b^l)又因为 \delta^l \equiv \frac{\partial C}{\partial z^l}.z^l = a^{l-1}*w^l +b^l那么 \frac{\partial C}{\partial w^l} = \frac{\partial C}{\partial z^l}\frac{\partial z^l}{\partial w^l}=\delta^l \frac{\partial z^l}{\partial w^l}= \delta^l * rot180(a^{l-1})即 \frac{\partial C}{\partial w^{l}} = \delta^l*rot180(a^{l-1})而对于b,则稍微有些特殊，因为 $\delta^l$ 是张量，而 $b$ 只是一个向量，不能像 DNN 那样直接和 $\delta^l$ 相等。通常的做法是将 $\delta^l$ 的各个子矩阵的项分别求和，得到一个误差向量，即为 $b$ 的梯度： \frac{\partial C}{\partial b^{l}} = \sum\limits_{u,v}(\delta^l)_{u,v} 参考文献[1] 月见樽. CNN的反向传播[DB/OL]. https://qiankun214.github.io/2018/02/21/CNN的反向传播/, 2018-06-26. [2] oio328Loio. 神经网络学习（三）反向（BP）传播算法（1）[DB/OL]. https://blog.csdn.net/hoho1151191150/article/details/79537246, 2018-06-26. [3] oio328Loio. 神经网络学习（十二）卷积神经网络与BP算法[DB/OL]. https://blog.csdn.net/hoho1151191150/article/details/79705332, 2018-06-26. [4] 刘建平Pinard. 卷积神经网络(CNN)反向传播算法[DB/OL]. http://www.cnblogs.com/pinard/p/6494810.html, 2018-06-26. [5] 刘建平Pinard. 卷积神经网络(CNN)前向传播算法[DB/OL]. http://www.cnblogs.com/pinard/p/6489633.html, 2018-06-26.]]></content>
      <categories>
        <category>深度学习</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>卷积神经网络</tag>
        <tag>前向传播算法</tag>
        <tag>反向传播算法</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[改进神经网络的学习方法——弃权]]></title>
    <url>%2F2018%2F06%2F24%2F%E6%94%B9%E8%BF%9B%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95%E2%80%94%E2%80%94%E5%BC%83%E6%9D%83%2F</url>
    <content type="text"><![CDATA[原文链接：CHAPTER 2 Improving the way neural networks learn 弃权（Dropout）的过程 Dropout 的比例可以自己指定，以下仅为例子说明 Dropout率为0.5 弃权是一种相当激进的技术。和规范化不同，弃权技术并不依赖于代价函数的修改。而是，在弃权中，我们改变了网络本身。在介绍它为什么能工作，以及所得到的结果前，让我描述一下弃权（Dropout）基本的工作机制。 特别地，假设我们有一个训练数据 $x$ 和 对应的目标输出 $y$。通常我们会通过在网络中前向传播 $x$ ，然后进行反向传播来确定对梯度的贡献。使用弃权（Dropout）技术，这个过程就改了。我们会从随机（临时）地删除网络中的一半的隐藏神经元开始，同时让输入层和输出层的神经元保持不变。在此之后，我们会得到最终如下线条所示的网络。注意那些被弃权（Dropout）的神经元，即那些临时被删除的神经元，用虚圈表示在图中： 我们前向传播输入 $x$，通过修改后的网络，然后反向传播结果，同样通过这个修改后的网络。在一个小批量数据的若干样本上进行这些步骤后，我们对有关的权重和偏置进行更新。然后重复这个过程，首先重置弃权（Dropout）的神经元，然后选择一个新的随机的隐藏神经元的子集进行删除，估计对一个不同的小批量数据的梯度，然后更新权重和偏置。通过不断地重复，我们的网络会学到一个权重和偏置的集合。当然，这些权重和偏置也是在一半的隐藏神经元被弃权（Dropout）的情形下学到的。当我们实际运行整个网络时，是指两倍的隐藏神经元将会被激活。为了补偿这个，我们将从隐藏神经元出去的权重减半。 为什么弃权（Dropout）有效？这个弃权（Dropout）过程可能看起来奇怪，像是临时安排的。为什么我们会指望这样的方法能够行正则化呢？为了解释所发生的事，我希望你停下来想一下标准没有弃权（Dropout））的训练方式。特别地，想象一下我们训练几个不同的神经网络，都使用同一个训练数据。当然，网络可能不是从同一初始状态开始的，最终的结果也会有一些差异。出现这种情况时，我们可以使用一些平均或者投票的方式来确定接受哪个输出。例如，如果我们训练了五个网络，其中三个把一个数字分类成 “3”，那很可能它就是“3”。另外两个可能就犯了错误。这种平均的方式通常是一种强大（尽管代价昂贵）的方式来减轻过拟合。原因在于不同的网络可能会以不同的方式过拟合，平均法可能会帮助我们消除那样的过拟合。 那么这和弃权（Dropout）有什么关系呢？启发式地看，当我们弃权（Dropout）掉不同的神经元集合时，有点像我们在训练不同的神经网络。所以，弃权（Dropout）过程就如同大量不同网络的效果的平均那样。不同的网络会以不同的方式过拟合了，所以，弃权（Dropout）过的网络的效果会减轻过拟合。 一个相关的启发式解释在早期使用这项技术的论文中曾经给出：“因为神经元不能依赖其他神经元特定的存在，这个技术其实减少了复杂的互适应的神经元。所以，强制要学习那些在神经元的不同随机子集中更加健壮的特征。” 换言之，如果我们将我们的神经网络看做一个进行预测的模型的话，我们就可以将弃权（Dropout）看做是一种确保模型对于一部分证据丢失健壮的方式。这样看来，弃权（Dropout）和 L1、L2 regularization也是有相似之处的，这也倾向于更小的权重，最后让网络对丢失个体连接的场景更加健壮。 对于弃权的理解CSDN: 神经网络之dropout层 参考文献[1] Michael Nielsen.CHAPTER 2 Improving the way neural networks learn[DB/OL]. http://neuralnetworksanddeeplearning.com/chap3.html. 2018-06-26. [2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL]. https://github.com/zhanggyb/nndl/blob/master/chap3.tex, 2018-06-26. [3] 鹿往森处走. 神经网络之dropout层[DB/OL]. https://www.cnblogs.com/zyber/p/6824980.html, 2018-06-26.]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>弃权（Dropout）</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[改进神经网络的学习方法——正则化]]></title>
    <url>%2F2018%2F06%2F24%2F%E6%94%B9%E8%BF%9B%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95%E2%80%94%E2%80%94%E6%AD%A3%E5%88%99%E5%8C%96%2F</url>
    <content type="text"><![CDATA[原文链接：CHAPTER 3 Improving the way neural networks learn 产生过度拟合和正则化的原因拥有大量的自由参数的模型能够描述特别神奇的现象。即使这样的模型能够很好的拟合已有的数据，但并不表示是一个好模型。因为这可能只是因为模型中足够的自由度使得它可以描述几乎所有给定大小的数据集，而不需要真正洞察现象的本质。所以发生这种情形时，模型对已有的数据会表现的很好，但是对新的数据很难泛化。对一个模型真正的测验就是它对没有见过的场景的预测能力。 我们用来对 MNIST 数字分类的 30 个隐藏神经元神经网络拥有将近 24,000 个参数！当然很多。我们有 100 个隐藏元的网络拥有将近 80,000 个参数，而目前最先进的深度神经网络包含百万级或者十亿级的参数。我们应当信赖这些结果么？ 让我们通过构造一个网络泛化能力很差的例子使这个问题更清晰。我们的网络有 30 个隐藏神经元，共 23,860 个参数。但是我们不会使用所有 50,000 幅 MNIST 训练图像。相反，我们只使用前 1,000 幅图像。使用这个受限的集合，会让泛化的问题突显。我们按照之前同样的方式，使用交叉熵损失函数，学习率设置为 $\eta = 0.5$ 而小批量大小设置为 $10$。不过这里我们要训练 400 个周期。我们现在使用 network2 来研究损失函数改变的情况： 12345678&gt;&gt;&gt; import mnist_loader&gt;&gt;&gt; training_data, validation_data, test_data = \... mnist_loader.load_data_wrapper()&gt;&gt;&gt; import network2&gt;&gt;&gt; net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost)&gt;&gt;&gt; net.large_weight_initializer()&gt;&gt;&gt; net.SGD(training_data[:1000], 400, 10, 0.5, evaluation_data=test_data,... monitor_evaluation_accuracy=True, monitor_training_cost=True) 使用上面的结果，我们可以画出当网络学习时代价变化的情况： 这看起来令人振奋，因为损失函数有一个光滑的下降，跟我们预期一致。注意，我只是展示了 $200$ 到 $399$ 损失函数的情况。这给出了很好的近距离理解训练后期的情况，也是出现有趣现象的地方。 让我们看看分类准确率在测试集上的表现： 这里我还是聚焦到了后面的过程。 在前 200 迭代期（图中没有显示）中准确率提升到了 82%。然后学习逐渐变缓。最终，在 280 迭代期左右分类准确率就停止了增长。后面的的迭代期，仅仅看到了在 280 迭代期准确率周围随机的小波动。将这幅图和前面的图进行对比，前面的图中和训练数据相关的代价持续平滑下降。如果我们只看那个代价，会发现我们模型的表现变得“更好”。但是测试准确率展示了提升只是一种假象。就像费米不大喜欢的那个模型一样，我们的网络在 280 迭代期后就不再能够推广到测试数据上。所以这不是有用的学习。我们说网络在 280 迭代期后就过度拟合或者过度训练了。 这里引出过度拟合的概念，过度拟合即过拟合。为了得到一致假设而使假设变得过度严格称为过拟合。过拟合的一种定义：给定一个假设空间 $H$，一个假设 $h$ 属于 $H$，如果存在其他的假设 $h’$ 属于 $H$,使得在训练样例上h的错误率比 $h’$ 小，但在整个实例分布上 $h’$ 比 $h$ 的错误率小，那么就说假设 $h$ 过度拟合训练数据。 你可能想知道这里的问题是不是由于我们看的是训练数据的代价，而对比的却是测试数据上的分类准确率导致的。 换言之，可能我们这里在进行苹果和橙子的对比。如果我们比较训练数据上的代价和测试数据上的代价，会发生什么，我们是在比较类似的度量吗？或者可能我们可以比较在两个数据集上的分类准确率啊？实际上，不管我们使用什么度量的方式，尽管细节会变化，但本质上都是一样的。让我们来看看测试数据集上的代价变化情况： 我们可以看到测试集上的代价在 15 迭代期前一直在提升，随后越来越差，尽管训练数据集上的代价表现是越来越好的。这其实是另一种模型过度拟合的迹象。尽管，这里带来了关于我们应当将 15 还是 280 迭代期当作是过度拟合开始影响学习的时间点的困扰。从一个实践角度，我们真的关心的是提升测试数据集上的分类准确率，而测试集合上的代价不过是分类准确率的一个反应。所以更加合理的选择就是将 280 迭代期看成是过度拟合开始影响学习的时间点。 另一个过度拟合的迹象在训练数据上的分类准确率上也能看出来： 准确率一直在提升接近 100%。也就是说，我们的网络能够正确地对所有 $1000$ 幅图像进行分类！而在同时，我们的测试准确率仅仅能够达到 82.27%。所以我们的网络实际上在学习训练数据集的特例，而不是能够一般地进行识别。我们的网络几乎是在单纯记忆训练集合，而没有对数字本质进行理解能够泛化到测试数据集上。 过拟合是神经网络的一个主要问题。这在现代网络中特别正常，因为网络权重 $W$ 和偏置 $b$ 数量巨大。为了高效地训练，我们需要一种检测过拟合是不是发生的技术，这样我们不会过度训练。并且我们也想要找到一些技术来降低过拟合的影响。 检测过拟合的明显方法是使用上面的方法跟踪测试数据集合上的准确率随训练变化情况。如果我们看到测试数据上的准确率不再提升，那么我们就停止训练。当然，严格地说，这其实并非是过拟合的一个必要现象，因为测试集和训练集上的准确率可能会同时停止提升。当然，采用这样的策略是可以阻止过拟合的。 实际上，我们会使用这种策略的变化形式来试验。记得之前我们载入 MNIST 数据时用了三个数据集： 123&gt;&gt;&gt; import mnist_loader&gt;&gt;&gt; training_data, validation_data, test_data = \... mnist_loader.load_data_wrapper() 到现在我们一直在使用 training_data 和 test_data，没有用过 validation_data。validation_data 中包含了 $10,000$ 幅数字图像，这些图像和 MNIST 训练数据集中的 $50,000$ 幅图像以及测试数据集中的$10,000$ 幅都不相同。我们会使用 validation_data 而不是 test_data 来防止过拟合。我们会为 test_data 使用和上面提到的相同的策略。我们在每个迭代期的最后都计算在 validation_data 上的分类准确率。一旦分类准确率已经饱和，就停止训练。这个策略被称为提前停止。当然，实际应用中，我们不会立即知道什么时候准确率会饱和。相反，我们会一直训练直到我们确信准确率已经饱和（这里需要一些判定标准来确定什么时候停止）。 为何要使用 validation_data 来替代 test_data 防止过拟合问题？实际上，这是一个更为一般的策略的一部分，这个一般的策略就是使用 validation_data 来衡量不同的超参数（如迭代期}，学习率，最好的网络架构等等）的选择的效果。我们使用这样方法来找到超参数的合适值。因此，尽管到现在我并没有提及这点，但其实本书前面已经稍微介绍了一些超参数选择的方法。 当然，这仍然没有回答为什么我们用 validation_data 而不是 test_data 来防止过拟合的问题。实际上，有一个更加一般的问题，就是 为何用 validation_data 取代 test_data 来设置更好的超参数？ 为了理解这点，想想当设置超参数时，我们想要尝试许多不同的超参数选择。如果我们设置超参数是基于 test_data 的话，可能最终我们就会得到 过拟合 于 test_data 的超参数。也就是说，我们可能会找到那些符合 test_data 特点的超参数，但是网络的性能并不能够泛化到其他数据集合上。我们借助 validation_data 来克服这个问题。然后一旦获得了想要的超参数，最终我们就使用 test_data 进行准确率测量。这给了我们在 test_data 上的结果是一个网络泛化能力真正的度量方式的信心。换言之，你可以将验证集看成是一种特殊的训练数据集能够帮助我们学习好的超参数。这种寻找好的超参数的方法有时候被称为 hold out 方法，因为 validation_data 是从 traning_data 训练集中留出或者“拿出”的一部分。 在实际应用中，甚至在衡量了 test_data 的性能后，我们可能也会改变想法并去尝试另外的方法，也许是一种不同的网络架构，这将会引入寻找新的超参数的过程。如果我们这样做，难道不会产生 过拟合 于 test_data 的困境么？我们是不是需要一种数据集的潜在无限回归，这样才能够确信模型能够泛化？去除这样的疑惑其实是一个深刻而困难的问题。但是对我们实际应用的目标，我们不会担心太多。相反，我们会继续采用基于 training_data，validation_data，和 test_data 的基本 Hold-Out 方法。 我们已经研究了只使用 $1,000$ 幅训练图像时的 过拟合 问题。那么如果我们使用所有的 50,000 幅图像的训练数据会发生什么？我们会保留所有其它的参数都一样（$30$ 个隐藏元，learning-rate $0.5$ mini-batch 规模为 $10$），但是 epoch为 30 次。下图展示了分类准确率在训练和测试集上的变化情况。注意我们使用的测试数据，而不是验证集合，为了让结果看起来和前面的图更方便比较。 如你所见，测试集和训练集上的准确率相比我们使用 $1,000$ 个训练数据时相差更小。特别地，在训练数据上的最佳的分类准确率 97.86% 只比测试集上的 95.33% 准确率高了1.53%。而之前的例子中，这个差距是 17.73%！过拟合仍然发生了，但是已经减轻了不少。我们的网络从训练数据上更好地泛化到了测试数据上。一般来说，最好的降低 过拟合 的方式之一就是增加训练样本的量。有了足够的训练数据，就算是一个规模非常大的网络也不大容易 过拟合。不幸的是，训练数据其实是很难或者很昂贵的资源，所以这不是一种太切实际的选择。 正则化增加训练样本的数量是一种减轻过拟合的方法。还有其他的方法能够减轻过拟合的程度吗？一种可行的方式就是降低网络的规模。然而，大的网络拥有一种比小网络更强的潜力，所以这里存在一种应用冗余性的选项。 幸运的是，还有其他的技术能够缓解过拟合，即使我们只有一个固定的网络和固定的训练集合。这种技术就是正则化。本节，我会给出一种最为常用的正则化手段，有时候被称为权重-decay 或者 L2正则化。L2正则化的想法是增加一个额外的项到损失函数上，这个项叫做正则化项。下面是正则化的交叉熵： C = -\frac{1}{n} \sum_{xj} \left[ y_j \ln a^L_j+(1-y_j) \ln(1-a^L_j)\right] + \frac{\lambda}{2n} \sum_w w^2其中第一个项就是常规的交叉熵的表达式。第二个现在加入的就是所有权重的平方的和。然后使用一个因子 $\lambda / 2n$ 进行量化调整，其中 $\lambda &gt; 0$ 可以称为正则化参数，而 $n$ 就是训练集合的大小。我们会在后面讨论 $\lambda$ 的选择策略。需要注意的是，正则化项里面并不包偏置。这点我们后面也会再讲述。 当然，对其他的损失函数也可以进行正则化，例如二次 损失函数。类似的正则化的形式如下： C = \frac{1}{2n} \sum_x \|y-a^L\|^2 + \frac{\lambda}{2n} \sum_w w^2两者都可以写成这样： C = C_0 + \frac{\lambda}{2n} \sum_w w^2其中 $C_0$ 是原始的 损失函数。 直觉地看，正则化的效果是让网络倾向于学习小一点的权重，其他的东西都一样的。大的权重只有能够给出损失函数第一项足够的提升时才被允许。换言之，正则化可以当做一种寻找小的权重和最小化原始的损失函数之间的折中。这两部分之间相对的重要性就由 $\lambda$ 的值来控制了：$\lambda$ 越小，就偏向于最小化原始 损失函数，反之，倾向于小的权重。 现在，对于这样的折中为何能够减轻过拟合还不是很清楚！但是，实际表现表明了这点。我们会在下一节来回答这个问题。但现在，我们来看看一个正则化的确减轻过拟合的例子。 为了构造这个例子，我们首先需要弄清楚如何将随机梯度下降算法应用在一个正则化的神经网络上。特别地，我们需要知道如何计算对网络中所有权重和偏置的偏导数 $\partial C/\partial w$ 和 $\partial C/\partial b$。对方程$C = C_0 + \frac{\lambda}{2n} \sum_w w^2$进行求偏导数得： \frac{\partial C}{\partial w} = \frac{\partial C_0}{\partial w} + \frac{\lambda}{n} w \frac{\partial C}{\partial b} = \frac{\partial C_0}{\partial b}$\partial C_0/\partial w$ 和 $\partial C_0/\partial b$ 可以通过反向传播算法进行计算，正如《反向传播算法》中描述的那样。所以我们看到其实计算正则化的损失函数的梯度是很简单的：仅仅需要反向传播，然后加上$\frac{\lambda}{n} w$ 得到所有权重的偏导数。而偏置的偏导数就不要变化，所以偏置的梯度下降学习规则不会发生变化： b \rightarrow b -\eta \frac{\partial C_0}{\partial b}权重的学习规则就变成： w \rightarrow w-\eta \frac{\partial C_0}{\partial w}-\frac{\eta \lambda}{n} w w = \left(1-\frac{\eta \lambda}{n}\right) w -\eta \frac{\partial C_0}{\partial w}这正和通常的梯度下降学习规则相同，除了通过一个因子 $1-\frac{\eta\lambda}{n}$ 重新调整了权重$w$。这种调整有时被称为权重衰减，因为它使得权重变小。粗看，这样会导致权重会不断下降到 $0$。但是实际不是这样的，因为如果在原始损失函数中造成下降的话其他的项（比如 $\eta \frac{\partial C_0}{\partial w}$）可能会让权重增加。 好的，这就是梯度下降工作的原理。那么随机梯度下降呢？正如在没有正则化的随机梯度下降中，我们可以通过平均 $m$ 个训练样本的 mini-batch 来估计 $\partial C_0/\partialw$。因此，为了随机梯度下降的正则化学习规则就变成 w \rightarrow \left(1-\frac{\eta \lambda}{n}\right) w -\frac{\eta}{m} \sum_x \frac{\partial C_x}{\partial w}其中后面一项是在训练样本的 mini-batch $x$ 上进行的，而 $C_x$ 是对每个训练样本的（无正则化的）代价。这其实和之前通常的随机梯度下降的规则是一样的，除了有一个权重下降的因子 $1-\frac{\eta \lambda}{n}$。最后，为了完整，我给出偏置的正则化的学习规则。这当然是和我们之前的非正则化的情形一致了， b \rightarrow b - \frac{\eta}{m} \sum_x \frac{\partial C_x}{\partial b}这里求和也是在训练样本的 mini-batch $x$ 上进行的。 让我们看看正则化给网络带来的性能提升吧。这里还会使用有 $30$ 个隐藏神经元、 mini-batch大小为 $10$， learning-rate为 $0.5$，使用交叉熵的神经网络。然而，这次我们会使用正则化参数为 $\lambda = 0.1$。注意在代码中，我们使用的变量名字为 lmbda!，这是因为在 Python 中 lambda是关键字，有着不相关的含义。我也会再次使用 test_data，而不是 validation_data。不过严格地讲，我们应当使用 validation_data 的，因为前面已经讲过了。这里我这样做，是因为这会让结果和非正则化的结果对比起来效果更加直接。你可以轻松地调整为 validation_data，你会发现有相似的结果。 12345678910&gt;&gt;&gt; import mnist_loader&gt;&gt;&gt; training_data, validation_data, test_data = \... mnist_loader.load_data_wrapper()&gt;&gt;&gt; import network2&gt;&gt;&gt; net = network2.Network([784, 30, 10], cost=network2.CrossEntropyCost)&gt;&gt;&gt; net.large_weight_initializer()&gt;&gt;&gt; net.SGD(training_data[:1000], 400, 10, 0.5,... evaluation_data=test_data, lmbda = 0.1,... monitor_evaluation_cost=True, monitor_evaluation_accuracy=True,... monitor_training_cost=True, monitor_training_accuracy=True) 训练集上的损失函数持续下降，和前面无正则化的情况一样的规律： 但是这次测试集上的准确率在整个 400 迭代期内持续增加： 显然，正则化的使用能够解决过拟合的问题。而且，准确率相当高了，最高处达到了87.1%，相较于之前的 82.27%。因此，我们几乎可以确信在 400 迭代期之后持续训练会有更加好的结果。看起来，经实践检验，正则化让网络具有更好的泛化能力，显著地减轻了过拟合的影响。 如果我们摆脱人为的仅用 1,000 个训练图像的环境，转而用所有 50,000 图像的训练集，会发生什么？当然，我们之前已经看到过拟合在大规模的数据上其实不是那么明显了。那正则化能不能起到相应的作用呢？保持超参数和之前一样，30 epoch, learning-rate 为 0.5, mini-batch 大小为 10。不过我们这里需要改变正则化参数。原因在于训练数据的大小已经从 $n=1,000$ 改成了 $n=50,000$，这个会改变权重衰减因子 $1-\frac{\eta\lambda}{n}$。如果我们持续使用 $\lambda = 0.1$ 就会产生很小的权重衰减，因此就将正则化的效果降低很多。我们通过修改为 $\lambda = 5.0$ 来补偿这种下降。 好了，来训练网络，重新初始化权重： 1234&gt;&gt;&gt; net.large_weight_initializer()&gt;&gt;&gt; net.SGD(training_data, 30, 10, 0.5,... evaluation_data=test_data, lmbda = 5.0,... monitor_evaluation_accuracy=True, monitor_training_accuracy=True) 我们得到： 这个结果很不错。第一，我们在测试集上的分类准确率在使用正则化后有了提升，从95.49% 到 96.49%。这是个很大的进步。第二，我们可以看到在训练数据和测试数据上的结果之间的差距也更小了。这仍然是一个大的差距，不过我们已经显著得到了本质上的降低过拟合的进步。 最后，我们看看在使用 100 个隐藏神经元和正则化参数为 $\lambda = 5.0$ 相应的测试分类准确率。我不会给出详细分析，纯粹为了好玩，来看看我们使用一些技巧（交叉熵函数和 L2正则化）能够达到多高的准确率。 12345&gt;&gt;&gt; net = network2.Network([784, 100, 10], cost=network2.CrossEntropyCost)&gt;&gt;&gt; net.large_weight_initializer()&gt;&gt;&gt; net.SGD(training_data, 30, 10, 0.5, lmbda=5.0,... evaluation_data=validation_data,... monitor_evaluation_accuracy=True) 最终在验证集上的准确率达到了 97.92%。这是比 30 个隐藏元的较大飞跃。实际上，稍微改变一点，60 epoch $\eta=0.1$ 和$\lambda = 5.0$。我们就突破了 98%，达到了98.04% 的分类准确率 98%。对于 152 行代码这个效果还真不错！ 我已经把正则化描述为一种减轻过拟合和提高分类准确率的方法。实际上，这不是仅有的好处。实践表明，在使用不同的（随机）权重初始化进行多次 MNIST 网络训练的时候，我发现无正则化的网络会偶然被限制住，明显困在了损失函数的局部最优值处。结果就是不同的运行会给出相差很大的结果。对比看来，正则化的网络能够提供更容易复制的结果。 为何会这样子？从经验上看，如果损失函数是无正则化的，那么权重向量的范数可能会增长，而其他的东西都保持一样。随着时间的推移，这会导致权重向量变得非常大。所以会使得权重向量卡在朝着更多还是更少的方向上变化，因为当范数很大的时候梯度下降带来的变化仅仅会引起在那个方向发生微小的变化。我相信这个现象让我们的学习算法更难有效地探索权重空间，最终导致很难找到损失函数的最优值。 为什么正则化可以帮助减轻过度拟合我们已经看到了正则化在实践中能够减少过拟合了。这是令人振奋的，不过，这背后的原因还不得而知！通常的说法是：小的权重在某种程度上，意味着更低的复杂性，也就对数据给出了一种更简单却更强大解释，因此应该优先选择。这虽然很简短，不过暗藏了一些可能看起来会令人困惑的因素。让我们将这个解释细化，认真地研究一下。现在给一个简单的数据集，我们为其建立模型： 这里我们其实在研究某种真实的现象，$x$ 和 $y$ 表示真实的数据。我们的目标是训练一个模型来预测 $y$ 关于 $x$ 的函数。我们可以使用神经网络来构建这个模型，但是我们先来个简单的：用一个多项式来拟合数据。这样做的原因其实是多项式相比神经网络能够让事情变得更加清楚。一旦我们理解了多项式的场景，对于神经网络可以如法炮制。现在，图中有十个点，我们就可以找到唯一的 $9$ 阶多项式 $y=a_0x^9 + a_1x^8 + … + a_9$ 来完全拟合数据。下面是多项式的图像，这里我不明确列出这些系数。 这给出了一个准确的拟合。但是我们同样也能够使用线性模型 $y=2x$ 得到一个好的拟合效果： 哪个是更好的模型？哪个更可能是真的？还有哪个模型更可能泛化到其他的拥有同样现象的样本上？ 这些都是很难回答的问题。实际上，我们如果没有更多关于真实现象背后的信息的话，并不能确定给出上面任何一个问题的答案。但是让我们考虑两种可能的情况：（1）9 阶多项式实际上是完全描述了真实情况的模型，最终它能够很好地泛化；（2）正确的模型是 $y=2x$，但是存在着由于测量误差导致的额外的噪声，使得模型不能够准确拟合。 先验假设无法说出哪个是正确的（或者，如果还有其他的情况出现）。逻辑上讲，这些都可能出现。并且这不是微不足道的差异。在给出的数据上，两个模型的表现其实是差不多的。但是假设我们想要预测对应于某个超过了图中所有的 $x$ 的 $y$ 的值，在两个模型给出的结果之间肯定有一个极大的差距，因为 9 阶多项式模型肯定会被 $x^9$ 主导，而线性模型只是线性的增长。 在科学中，一种观点是我们除非不得已应该追随更简单的解释。当我们找到一个简单模型似乎能够解释很多数据样本的时候，我们都会激动地认为发现了规律！我们怀疑模型必须表达出某些关于现象的内在的真理。如上面的例子，线性模型加噪声肯定比多项式更加可能。我们会认为线性模型加噪声表达出了一些潜在的真理。从这个角度看，多项式模型仅仅是学习到了局部噪声的影响效果。所以尽管多项式对于这些特定的数据点表现得很好。模型最终会在未知数据上的泛化上出现问题，所以噪声线性模型具有更强大的预测能力。 让我们从这个观点来看神经网络。假设神经网络大多数有很小的权重，这最可能出现在正则化的网络中。更小的权重意味着网络的行为不会因为我们随便改变了一个输入而改变太大。这会让正则化网络学习局部噪声的影响更加困难。将它看做是一种让单个的证据不会影响网络输出太多的方式。相对的， 正则化网络学习去对整个训练集中经常出现的证据进行反应。对比看，大权重的网络可能会因为输入的微小改变而产生比较大的行为改变。所以一个无正则化的网络可以使用大的权重来学习包含训练数据中的噪声的大量信息的复杂模型。简言之，正则化网络受限于根据训练数据中常见的模式来构造相对简单的模型，而能够抵抗训练数据中的噪声的特性影响。我们的想法就是这可以让我们的网络对看到的现象进行真实的学习，并能够根据已经学到的知识更好地进行泛化。 所以，倾向于更简单的解释的想法其实会让我们觉得紧张。人们有时候将这个想法称为“奥卡姆剃刀原则”，然后就会热情地将其当成某种科学原理来应用这个法则。但是，这就不是一个一般的科学原理。也没有任何先验的逻辑原因来说明简单的解释就比更为复杂的解释要好。实际上，有时候更加复杂的解释其实是正确的。 下面有三点提示：第一，确定两种解释中哪个“更加简单”其实是一件相当微妙的工作。第二，即使我们可以做出这样一个判断，简单性也是一个使用时需要相当小心的指导！第三，对模型真正的测试不是简单性，而是它在新场景中对新的活动中的预测能力。 所以，我们应当时时记住这一点，正则化的神经网络常常能够比非正则化的泛化能力更强，这只是一种实验事实（empirical fact）。 我已经在上面讲过了为何现在还没有一个人能够发展出一整套具有说服力的关于正则化可以帮助网络泛化的理论解释。实际上，研究者们不断地在写自己尝试不同的正则化方法，然后看看哪种表现更好，尝试理解为何不同的观点表现的更好。所以你可以将正则化看做某种任意整合的技术。尽管其效果不错，但我们并没有一套完整的关于所发生情况的理解，仅仅是一些不完备的启发式规则或者经验。 这里也有更深的问题，这个问题也是有关科学的关键问题：我们如何泛化。正则化能够给我们一种计算上的魔力帮助神经网络更好地泛化，但是并不会带来原理上理解的指导，甚至不会告诉我们什么样的观点才是最好的。 这实在是令人困扰，因为在日常生活中，我们人类在泛化上表现很好。给一个儿童几幅大象的图片，他就能快速地学会认识其他的大象。当然，他们偶尔也会搞错，很可能将一只犀牛误认为大象，但是一般说来，这个过程会相当准确。所以我们有个系统人的大脑拥有超大量的自由变量。在受到仅仅少量的训练图像后，系统学会了在其他图像上的推广。某种程度上，我们的大脑的正则化做得特别好！怎么做的？现在还不得而知。我期望若干年后，我们能够发展出更加强大的技术来正则化神经网络，最终这些技术会让神经网络甚至在小的训练集上也能够学到强大的泛化能力。 实际上，我们的网络已经比我们预先期望的要好一些了。拥有 100 个隐藏元的网络会有接近 80,000 个参数。我们的训练集仅仅有 50,000 幅图像。这好像是用一个 80,000 阶的多项式来拟合 50,000 个数据点。我们的网络肯定会过拟合得很严重。但是，这样的网络实际上却泛化得很好。为什么？这一点并没有很好地理解。这里有个猜想：梯度下降学习的动态有一种自正则化的效应。这真是一个意料之外的巧合，但也带来了对于这种现象本质无知的不安。不过，我们还是会在后面依照这种实践的观点来应用正则化技术的。神经网络也是由于这点表现才更好一些。 现在我们回到前面留下来的一个细节：L2 正则化没有限制偏置，以此作为本节的结论。当然了，对正则化的过程稍作调整就可以对偏置进行规范了。实践看来，做出这样的调整并不会对结果改变太多，所以，在某种程度上，对不对偏置进行正则化其实就是一种习惯了。然而，需要注意的是，有一个大的偏置并不会像大的权重那样会让神经元对输入太过敏感。所以我们不需要对大的偏置所带来的学习训练数据的噪声太过担心。同时，允许大的偏置能够让网络更加灵活。因为，大的偏置让神经元更加容易饱和，这有时候是我们所要达到的效果。所以，我们通常不会对偏置进行正则化。 L1 正则化L1正则化：这个方法是在未正则化 的损失函数上加上一个权重绝对值的和： C = C_0 + \frac{\lambda}{n} \sum_w |w|凭直觉地看，这和 L2正则化相似，惩罚大的权重，倾向于让网络优先选择小的权重。当然，L1正则化和 L2正则化并不相同，所以我们不应该期望从 L1正则化得到完全同样的行为。让我们来试着理解使用 L1正则化训练的网络和 L2正则化训练的网络所不同的行为。 首先，我们会研究一下 cost-func 的偏导数。对$C = C_0 + \frac{\lambda}{n} \sum_w |w|$求导我们有 \frac{\partial C}{\partial w} = \frac{\partial C_0}{\partial w}+ \frac{\lambda}{n} {\rm sgn}(w)其中 ${\rm sgn}(w)$ 就是 $w$ 的正负号，即 $w$ 是正数时为 $+1$，而 $w$ 为负数时为 $-1$。使用这个表达式，我们可以轻易地对反向传播算法进行修改从而使用基于 L1正则化的随机梯度下降进行学习。对 L1正则化的网络进行更新的规则就是 w \rightarrow w' =w-\frac{\eta \lambda}{n} sgn(w) - \eta \frac{\partial C_0}{\partial w}其中和往常一样，我们可以用一个小批量数据的均值来估计 $\partial C_0/\partial w$。对比 L2 正则化的更新规则， w \rightarrow w' = w\left(1 - \frac{\eta \lambda}{n} \right)- \eta \frac{\partial C_0}{\partial w}在两种情形下正则化的效果就是缩小权重。这符合我们的直觉，两种正则化都惩罚大的权重。但权重 缩小的方式不同。在 L1正则化中，权重 通过一个常量向 $0$ 进行缩小。在 L2正则化中，权重 通过一个和 $w$ 成比例的量进行缩小的。所以，当一个特定的权重 绝对值 $|w|$ 很大时，L1正则化的权重 缩小得远比 L2正则化要小得多。相反，当一个特定的权重绝对值 $|w|$ 很小时，L1正则化的权重 缩小得要比 L2正则化大得多。最终的结果就是：L1正则化倾向于聚集网络的权重 在相对少量的高重要度连接上，而其他权重 就会被驱使向 $0$ 接近。 我在上面的讨论中其实忽略了一个问题~——~在 $w=0$ 的时候，偏导数 $\partial C/\partial w$ 未定义。原因在于函数 $|w|$ 在 $w=0$ 时有个“直角”，事实上，导数是不存在的。不过也没有关系。我们下面要做的就是应用通常的（无正则化的）随机梯度下降的规则在 $w=0$ 处。这应该不会有什么问题，凭直觉地看，正则化的效果就是缩小权重，显然，不能对一个已经是 $0$ 的权重进行缩小了。更准确地说，我们将会使用上述方程并约定 $ sgn(0) = 0$。这样就给出了一种细致又紧凑的规则来进行采用 L1 正则化的随机梯度下降学习。 L1、L2 正则化与参数估计的关系 通过上面的推导我们可以发现，最大后验估计与最大似然估计最大的不同在于p(参数)项，所以可以说最大后验估计是正好可以解决机器学习缺乏先验知识的缺点，将先验知识加入后，优化损失函数。 其实p(参数)项正好起到了正则化的作用。如：如果假设p(参数)服从高斯分布，则相当于加了一个L2 正则化；如果假设p(参数)服从拉普拉斯分布，则相当于加了一个L1 正则化。]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>正则化</tag>
        <tag>奥卡姆剃刀原则</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[改进神经网络的学习方法——Softmax]]></title>
    <url>%2F2018%2F06%2F22%2F%E6%94%B9%E8%BF%9B%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95%E2%80%94%E2%80%94Softmax%2F</url>
    <content type="text"><![CDATA[原文链接：CHAPTER 3 Improving the way neural networks learn Softmax 前言我们大多数情况会使用交叉熵来解决学习缓慢的问题。但是，我希望简要介绍一下另一种解决这个问题的方法，基于 softmax 神经元层。在人工神经网络（ANN）中，softmax 通常被用作输出层的激活函数。这不仅是因为它的效果好，而且因为它使得 ANN 的输出值更易于理解。同时，softmax 配合 log 似然代价函数，其训练效果也要比采用二次代价函数的方式好。 Softmax 函数性质 softmax的函数公式如下： a^L_j = \frac{e^{z^L_j}}{\sum_k e^{z^L_k}},在公式中的指数确保了所有的输出激活值是正数。然后方程中分母的求和又保证了 softmax 的输出和为 $1$。这个特定的形式确保输出激活值形成一个概率分布的自然的方式。你可以将其想象成一种重新调节 $z^L_j$ 的方法，然后将这个结果整合起来构成一个概率分布。 softmax函数最明显的特点在于：它把每个神经元的输入占当前层所有神经元输入之和的比值，当作该神经元的输出。这使得输出更容易被解释：神经元的输出值越大，则该神经元对应的类别是真实类别的可能性更高。 softmax 的单调性 证明如果 $j=k$ 则 $\partial a^L_j / \partial z^L_k$ 为正，$j \neq k$ 时为负。结果是，增加 $z^L_j$ 会提高对应的输出激活值 $a^L_j$ 并降低其他所有输出激活值。单调性证明见后文。 softmax的非局部性 softmax 层的一个好处是输出 $a^L_j$ 是对应带权输入 $a^L_j = \sigma(z^L_j)$ 的函数。由于分母求和所有的 $e^{z^L_k}$ 所以计算式子中计算每一个 $a_j^L$ 都与其他 $a_j^L$ 紧密相关。深入理解就是对于 softmax 层来说：任何特定的输出激活值 $a^L_j$ 依赖所有的带权输入。 逆转softmax层 假设我们有一个使用 softmax 输出层的神经网络，然后激活值 $a^L_j$ 已知。容易证明对应带权输入的形式为 $z^L_j = \ln a^L_j + C$，其中常量 $C$ 是独立于 $j$ 的。 Softmax 解决学习缓慢问题我们现在已经对Softmax神经元层有了一定的认识。但是我们还没有看到一个Softmax层会怎么样解决学习缓慢问题。为了理解这点，让我们先定义一个对数似然函数。我们使用 $x$ 表示网络的训练输入，$y$ 表示对应的目标输出。然后关联这个训练输入的代价函数就是 C \equiv -\ln a^L_y所以，如果我们训练的是 MNIST 图像，输入为 $7$ 的图像，那么对应的对数似然代价就是 $-\ln a_7^L$。看看这个直觉上的含义，想想当网络表现很好的时候，也就是确认输入为 $7$ 的时候。这时，他会估计一个对应的概率 $a_7^L$ 跟$1$ 非常接近，所以代价 $-\ln a_7^L$ 就会很小。反之，如果网络的表现糟糕时，概率$a_7^L$ 就变得很小，代价 $-\ln a_7^L$ 随之增大。所以对数似然代价函数也是满足我们期待的代价函数的条件的。 那关于学习缓慢问题呢？为了分析它，回想一下学习缓慢的关键就是量 $\partial C /\partial w^L_{jk}$ 和 $\partial C / \partial b^L_j$ 的变化情况。这里我不会显式地给出详细的推导，但是通过一点代数运算你会得 \frac{\partial C}{\partial b^L_j} = a^L_j-y_j \frac{\partial C}{\partial w^L_{jk}} = a^{L-1}_k (a^L_j-y_j)证明见 矩阵形式的Softmax多分类模型 这些方程其实和我们前面对交叉熵得到的类似。而且，正如前面的分析，这些表达式确保我们不会遇到学习缓慢的问题。事实上，把一个具有对数似然代价的 softmax 输出层，看作与一个具有交叉熵代价的 S 型输出层非常相似，这是很有用的。 有了这样的相似性，你应该使用一个具有交叉熵代价的 S 型输出层，还是一个具有对数似然代价的Softmax输出层呢？实际上，在很多应用场景中，这两种方式的效果都不错。作为一种通用的视角，Softmax加上对数似然的组合更加适用于那些需要将输出激活值解释为概率的场景。那并不总是一个需要关注的问题，但是在诸如 MNIST 这种有着不重叠的分类问题上确实很有用。 数学形式证明 Softmax 有效性softmax的函数公式如下： a^L_j = \frac{e^{z^L_j}}{\sum_k e^{z^L_k}},softmax在的求导结果比较特别，分为两种情况。 上文讲到，二次代价函数在训练ANN时可能会导致训练速度变慢的问题。那就是，初始的输出值离真实值越远，训练速度就越慢。这个问题可以通过采用交叉熵代价函数来解决。其实，这个问题也可以采用另外一种方法解决，那就是采用 softmax 激活函数，并采用log似然代价函数（log-likelihood cost function）来解决。 log似然代价函数的公式为： C = - \sum_i y_i log a_i注意这种情况：其中，表示第 $a_k$ 个神经元的输出值，$y_k$ 表示第 k 个神经元对应的真实值，取值为 0 或 1 。由于 $y_k$ 取值为 0 或 1 ，对于每一个样本， $y_1,y_2,..,y_k$ 只会有一个取 1 其余的都取值为0， 所以对数似然函数求和符号可以去掉，化简为 C \equiv -\ln a^L_j 为了检验 softmax 和这个代价函数也可以解决上述所说的训练速度变慢问题，接下来的重点就是推导ANN的权重 w 和偏置 b 的梯度公式。 先求损失函数对偏置b的偏导数： 当 $i=j$ 时，带入 上面的结果$\frac{\partial a^L_j}{\partial z^L_i}=a_j^L(1-a_j^L)$ \begin{aligned} \frac{\partial C}{\partial b_{j}^L} &= \frac{\partial C}{\partial a^L_j} \frac{\partial a^L_j}{\partial z^L_i} \\ &= - \frac{1}{a^L_j} [a_j^L(1-a_j^L)] \\ &= a_j^L -1 \end{aligned} 当 $i\not= j$ 时，带入 上面的结果$\frac{\partial a^L_j}{\partial z^L_i}=-a_j^La_i^L$ \begin{aligned} \frac{\partial C}{\partial b_{j}^L} &= \frac{\partial C}{\partial a^L_j} \frac{\partial a^L_j}{\partial z^L_i} \\ &= - \frac{1}{a^L_j} (-a_j^La_i^L) \\ &= a_i^L \end{aligned}根据反向传播的四个方程，具体分析见《反向传播算法》 可以知道，$\frac{\partial C}{\partial b^l_j} =\delta^l_j$ 和 $\frac{\partial C}{\partial w^l_{jk}} = a^{l-1}_k \delta^l_j$ 所以,当 $i=j$ 时， \frac{\partial C}{\partial w^L_{jk}} = a^{L-1}_k (a^L_j-1)当 $i\not= j$ 时， \frac{\partial C}{\partial w^L_{jk}} = a^{L-1}_k a_i举个例子通过若干层的计算，最后得到的某个训练样本的向量的分数是[ 2, 3, 4 ],那么经过softmax函数作用后概率分别就是=[e^2/(e^2+e^3+e^4),e^3/(e^2+e^3+e^4),e^4/(e^2+e^3+e^4)] = [0.0903,0.2447,0.665],如果这个样本正确的分类是第二个的话，那么计算出来的偏导（实际上这个偏导就是 $\delta^L$ 或者说是 $\partial C/\partial b^L$ ）就是[0.0903,0.2447-1,0.665]=[0.0903,-0.7553,0.665]，是不是非常简单！然后再根据这个进行back propagation就可以了 注意！当 $y_j$ 取值不为 0 或 1，而是区间 [0,1] 的一个实数值时，上面的式子只需稍稍做点修改，只需把下面式子中 $\frac{\partial C}{\partial a^L_j}$ 的结果从 $\frac{1}{a^L_j}$ 改为 $\frac{y_i}{a^L_j}$ 即可， \begin{aligned} \frac{\partial C}{\partial b_{j}^L} &= \frac{\partial C}{\partial a^L_j} \frac{\partial a^L_j}{\partial z^L_i} \\ &= - \frac{1}{a^L_j} [a_j^L(1-a_j^L)] \\ &= a_j^L -1 \end{aligned}其它的求导过程也要做相应调整。所以在有的地方会看到这样的公式， \frac{\partial C}{\partial b^L_j} = a^L_j-y_j \frac{\partial C}{\partial w^L_{jk}} = a^{L-1}_k (a^L_j-y_j)两者都是正确的，只是因为前提不一样，所以结论也有差异。 交叉熵与对数似然的关系结论：交叉熵和最大似然的loss函数是一致的，在样本所属分类是唯一的情况下。 两者能够和谐统一的关键点是： 样本所属类别是唯一的，样本一定是某一类的，似然的思想是抽样样本的概率最大化，所以每一个样本只能处于一个固定的状态。这就使得每个样本的概率形式可以写成一个综合的形式，而综合的形式呢刚好可以在log下拆分成交叉熵的样子。在多类下，若样本所属类别是唯一的，最大似然的loss与交叉熵的loss仍然是一致的。 论证： 二项分布 二项分布也叫 0-1 分布，如随机变量 x 服从二项分布，关于参数 μ（0≤μ≤1），其值取 1 和取 0 的概率如下： p(x=1|\mu)=\mu p(x=0|\mu)=1-\mu则在 x 上的概率分布为： \text{Bern}(x|\mu)=\mu^x(1-\mu)^{1-x}服从二项分布的样本集的对数似然函数 给定样本集 D={x1,x2,…,xB} 是对随机变量 x 的观测值，假定样本集从二项分布 p(x|μ) 中独立（p(x1,x2,…,xN)=∏ip(xi)）采样得来，则当前样本集关于 μ 的似然函数为： p(\mathcal D|\mu)=\prod_{n=1}^Np(x_n|\mu)=\prod_{n=1}^N\mu^{x_n}\left(1-\mu\right)^{1-x_n}从频率学派的观点来说，通过最大似然函数的取值，可以估计参数 μ，最大化似然函数，等价于最大化其对数形式： 求其关于 μ 的导数，解得 μ 的最大似然解为： \mu_{ML}=\frac1N\sum_{n=1}^Nx_n这里我们仅关注： \ln P(\mathcal D|\mu)=\sum_{n=1}^Nx_n\ln \mu+(1-x_n)\ln(1-\mu)交叉熵损失函数 L_H(\mathbf x,\mathbf z)=-\sum_{n=1}^Nx_n\log z_n+(1-x_n)\log(1-z_n)x 表示原始信号，z 表示重构信号。（损失函数的目标是最小化，似然函数则是最大化，二者仅相差一个符号）。 参考文献[1] Michael Nielsen.CHAPTER 3 Improving the way neural networks learn[DB/OL]. http://neuralnetworksanddeeplearning.com/chap3.html, 2018-06-22. [2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL].https://github.com/zhanggyb/nndl/blob/master/chap3.tex, 2018-06-22. [3] __鸿. softmax的log似然代价函数（公式求导）[DB/OL]. https://blog.csdn.net/u014313009/article/details/51045303. 2018-06-22. [4] 忆臻HIT_NLP. 手打例子一步一步带你看懂softmax函数以及相关求导过程[DB/OL]. https://www.jianshu.com/p/ffa51250ba2e. 2018-06-22.]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>Softmax</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[改进神经网络的学习方法——交叉熵]]></title>
    <url>%2F2018%2F06%2F21%2F%E6%94%B9%E8%BF%9B%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E7%9A%84%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95%E2%80%94%E2%80%94%E4%BA%A4%E5%8F%89%E7%86%B5%2F</url>
    <content type="text"><![CDATA[交叉熵交叉熵 百度百科交叉熵（Cross Entropy）是Shannon信息论中一个重要概念，主要用于度量两个概率分布间的差异性信息。交叉熵的定义交叉熵的应用 交叉熵可在神经网络(机器学习)中作为损失函数，p表示真实标记的分布，q则为训练后的模型的预测标记分布，交叉熵损失函数可以衡量p与q的相似性。交叉熵作为损失函数还有一个好处是使用sigmoid函数在梯度下降时能避免均方误差损失函数学习速率降低的问题，因为学习速率可以被输出的误差所控制。 在特征工程中，可以用来衡量两个随机变量之间的相似度。 在语言模型中（NLP）中，由于真实的分布p是未知的，在语言模型中，模型是通过训练集得到的，交叉熵就是衡量这个模型在测试集上的正确率。 原文链接：CHAPTER 3 Improving the way neural networks learn 为什么需要交叉熵代价函数人类却能够根据明显的犯错快速地学习到正确的东西。相反，在我们的错误不是很好地定义的时候，学习的过程会变得更加缓慢。但神经网络却不一定如此，这种行为看起来和人类学习行为差异很大。人工神经元在其犯错较大的情况下其实学习很有难度。 为了理解这个问题的源头，想想我们的神经元是通过改变权重和偏置，并以一个代价函数的偏导数 $\partial C/\partial w$ 和 $\partial C/\partial b$ 决定的速度学习。所以，我们在说“学习缓慢”时，实际上就是说这些偏导数很小。 用上一章《反向传播算法》的符号定义，对于二次代价函数,输出层的权重的偏导数为 \frac{\partial C}{\partial w^L_{jk}} = \frac{1}{n} \sum_x a^{L-1}_k (a^L_j-y_j) \sigma'(z^L_j)项 $\sigma’(z^L_j)$ 会在一个输出神经元困在错误值时导致学习速度的下降。 我们可以从这幅图看出，当神经元的输出接近 $1$ 的时候，曲线变得相当平，所以$\sigma’(z)$ 就很小了。上面式子中的 $\frac{\partial C}{\partial w^L_{jk}}$ 也会非常小。这其实就是学习缓慢的原因所在。而且，我们后面也会提到，这种学习速度下降的原因实际上也是更加一般的神经网络学习缓慢的原因，并不仅仅是在这个特例中特有的。 注意，在输出层使用线性神经元时使用二次代价函数。假设我们有一个多层多神经元网络，最终输出层的神经元都是线性神经元，输出不再是$S$型函数作用的结果，而是 $a^L_j = z^L_j$。如果我们使用二次代价函数，那么对单个训练样本 $x$ 的输出误差就是 \delta^L = a^L-y这表明如果输出神经元是线性的那么二次代价不再会导致学习速度下降的问题。在此情形下，二次代价函数就是一种合适的选择。 但是如果输出神经元是$S$型函数作用的结果，我们就最好考虑其他的代价函数。 交叉熵代价函数的定义那么我们如何解决这个问题呢？研究表明，我们可以通过使用交叉熵函数来替换二次代价函数。为了理解什么是交叉熵，我们稍微改变一下之前的简单例子。假设，我们现在要训练一个包含若干输入变量的的神经元，$x_1, x_2, \ldots$ 对应的权重为 $w_1,w_2, \ldots$ 和偏置 $b$： 神经元的输出就是 $a = \sigma(z)$，其中 $z = \sum_j w_j x_j+b$ 是输入的带权和。我们如下定义这个神经元的交叉熵代价函数： C = -\frac{1}{n} \sum_x \left[y \ln a + (1-y ) \ln (1-a) \right]其中 $n$ 是训练数据的总数，求和是在所有的训练输入 $x$ 上进行的，$y$ 是对应的目标输出。 对于交叉熵代价函数，针对一个训练样本 $x$ 的输出误差 $\delta^L$为 \delta^L = a^L-y关于输出层的权重的偏导数为 \frac{\partial C}{\partial w^L_{jk}} = \frac{1}{n} \sum_x a^{L-1}_k (a^L_j-y_j)这里 $\sigma’(z^L_j)$ 就消失了，所以交叉熵避免了学习缓慢的问题。 那么我们应该在什么时候用交叉熵来替换二次代价函数？实际上，如果在输出神经元是$S$时，交叉熵一般都是更好的选择。为什么？考虑一下我们初始化网络的权重和偏置的时候通常使用某种随机方法。可能会发生这样的情况，这些初始选择会对某些训练输入误差相当明显，比如说，目标输出是 $1$，而实际值是$0$，或者完全反过来。如果我们使用二次代价函数，那么这就会导致学习速度的下降。它并不会完全终止学习的过程，因为这些权重会持续从其他的样本中进行学习，但是显然这不是我们想要的效果。 交叉熵在分类问题中的应用交叉熵损失函数应用在分类问题中时，不管是单分类还是多分类，类别的标签都只能是 0 或者 1。 交叉熵在单类别问题中的应用这里的单类别是指，每一张图像样本只能有一个类别，比如只能是狗或只能是猫。交叉熵在单分类问题上基本是标配的方法 loss = -\sum_{i=1}^ny_i log(\hat{y}_i)上式为一张样本的 $loss$ 计算方法。式中 $n$ 代表着 $n$ 种类别。举例如下， 交叉熵在多标签问题中的应用这里的多类别是指，每一张图像样本可以有多个类别，比如同时包含一只猫和一只狗和单分类问题的标签不同，多分类的标签是n-hot。 值得注意的是，这里的Pred采用的是sigmoid函数计算。将每一个节点的输出归一化到[0,1]之间。所有Pred值的和也不再为1。换句话说，就是每一个Label都是独立分布的，相互之间没有影响。所以交叉熵在这里是单独对每一个节点进行计算，每一个节点只有两种可能值，所以是一个二项分布。前面说过对于二项分布这种特殊的分布，熵的计算可以进行简化。 同样的，交叉熵的计算也可以简化，即 loss =-ylog(\hat{y})-(1-y)log(1-\hat{y})注意，上式只是针对一个节点的计算公式。这一点一定要和单分类loss区分开来。 交叉熵代价函数对权重求导的证明交叉熵代价函数的定义： C = -\frac{1}{n} \sum_x \left[y \ln a + (1-y ) \ln (1-a) \right]代价函数 $C$ 对 $w^L_{jk}$ 求偏导 \begin{aligned} \frac{\partial C}{\partial w_{jk}^L} &= -\frac{1}{n} \sum_x \left( \frac{y^L_j }{\sigma(z^L_j)} -\frac{(1-y^L_j)}{1-\sigma(z^L_j)} \right) \frac{\partial \sigma(z^L_j)}{\partial w_{jk}^L} \\ &= -\frac{1}{n} \sum_x \left( \frac{y^L_j }{\sigma(z^L_j)} -\frac{(1-y^L_j)}{1-\sigma(z^L_j)} \right)\sigma'(z^L_j) a_k^{L-1} \\ &=\frac{1}{n} \sum_x \frac{\sigma'(z^L_j) a_k^{L-1}}{\sigma(z^L_j) (1-\sigma(z^L_j))} (\sigma(z^L_j)-y_j) \end{aligned}其中$\frac{\partial z^l_j}{\partial w^l_{jk}} = a_k^{l-1}$ 来自，根据 $z_j^l$ 定义 z^l_j=\sum_k w^l_{jk} a^{l-1}_k+b^l_j所以 \frac{\partial z^l_j}{\partial w^l_{jk}} = a_k^{l-1}根据 $\sigma(z) = 1/(1+e^{-z})$ 的定义， \begin{aligned} \sigma'(z) &= (\frac{1}{1+e^{-z}})' \\ &= \frac{e^{-z}}{(1+e^{-z})^{2}} \\ &= \frac{1+e^{-z}-1}{(1+e^{-z})^{2}} \\ &= \frac{1}{(1+e^{-z})}(1-\frac{1}{(1+e^{-z})}) \\ &= \sigma(z)(1-\sigma(z)) \\ \end{aligned}把 $\sigma’(z)$ 带入 $\frac{\partial C}{\partial w_j}$ 可得 \frac{\partial C}{\partial w^L_{jk}} = \frac{1}{n} \sum_xa^{L-1}_k (a^L_j-y_j)其向量形式是 \frac{\partial C}{\partial w^L} = \frac{1}{n} \sum_x a^{L-1}(\sigma(z^L)-y)对偏置用同样的方法可得 \frac{\partial C}{\partial b^L_{j}} = \frac{1}{n} \sum_x (a^L_j-y_j)交叉熵的含义和来源我们对于交叉熵的讨论聚焦在代数分析和代码实现。这虽然很有用，但是也留下了一个未能回答的更加宽泛的概念上的问题，如：交叉熵究竟表示什么？存在一些直觉上的思考交叉熵的方法吗？我们如何想到这个概念？ 让我们从最后一个问题开始回答：什么能够激发我们想到交叉熵？假设我们发现学习速度下降了，并理解其原因是因为对于二次代价函数,输出层的权重的偏导数为 \frac{\partial C}{\partial w^L_{jk}} = \frac{1}{n} \sum_x a^{L-1}_k (a^L_j-y_j) \sigma'(z^L_j)项 $\sigma’(z^L_j)$ 会在一个输出神经元困在错误值时导致学习速度的下降。在研究了这些公式后，我们可能就会想到选择一个不包含 $\sigma’(z)$ 的代价函数。所以，这时候对一个训练样本 $x$，其代价 $C = C_x$ 满足： \frac{\partial C}{\partial w_j} = a_j^{L-1}(a^L_j-y) \frac{\partial C}{\partial b } = (a-y)如果我们选择的损失函数满足这些条件，那么它们就能以简单的方式呈现这样的特性：初始误差越大，神经元学习得越快。这也能够解决学习速度下降的问题。实际上，从这些公式开始，现在我们就看看凭着我们数学的直觉推导出交叉熵的形式是可行的。我们来推一下，由链式法则，我们有 \frac{\partial C}{\partial b} = \frac{\partial C}{\partial a} \sigma'(z)使用 $\sigma’(z) = \sigma(z)(1-\sigma(z)) = a(1-a)$，上个等式就变成 \frac{\partial C}{\partial b} = \frac{\partial C}{\partial a}a(1-a)对比等式，我们有 \frac{\partial C}{\partial a} = \frac{a-y}{a(1-a)}对此方程关于 $a$ 进行积分，得到 C = -[y \ln a + (1-y) \ln (1-a)]+ {\rm constant}其中 constant 是积分常量。这是一个单独的训练样本 $x$ 对损失函数的贡献。为了得到整个的损失函数，我们需要对所有的训练样本进行平均，得到了 C = -\frac{1}{n} \sum_x [y \ln a +(1-y) \ln(1-a)] + {\rm constant}而这里的常量就是所有单独的常量的平均。所以我们看到方程 \frac{\partial C}{\partial w_j} = a_j^{L-1}(a^L_j-y) \frac{\partial C}{\partial b } = (a-y)唯一确定了交叉熵的形式，并加上了一个常量的项。这个交叉熵并不是凭空产生的。而是一种我们以自然和简单的方法获得的结果。 那么交叉熵直觉含义又是什么？我们如何看待它？深入解释这一点会将我们带到一个不大愿意讨论的领域。然而，还是值得提一下，有一种源自信息论的解释交叉熵的标准方式。粗略地说，交叉熵是“不确定性”的一种度量。特别地，我们的神经元想要计算函数 $x \rightarrow y = y(x)$。但是，它用函数$x\rightarrow a = a(x)$ 进行了替换。假设我们将 $a$ 想象成我们神经元估计为 $y = 1$ 的概率，而 $1-a$ 则是 $y=0$ 的概率。那么交叉熵衡量我们学习到 $y$ 的正确值的平均起来的不确定性。 如果输出我们期望的结果，不确定性就会小一点；反之，不确定性就大一些。当然，我这里没有严格地给出“不确定性”到底意味着什么，所以看起来像在夸夸其谈。但是实际上，在信息论中有一种准确的方式来定义不确定性究竟是什么。详细内容请看交叉熵（cross-entropy）的数学历史。 交叉熵（cross-entropy）的数学历史通用的说，熵(Entropy)被用于描述一个系统中的不确定性(the uncertainty of a system)。在不同领域熵有不同的解释，比如热力学的定义和信息论也不大相同。 先给出一个”不严谨”的概念表述： 熵：可以表示一个事件A的自信息量，也就是A包含多少信息。 KL散度：可以用来表示从事件A的角度来看，事件B有多大不同。 交叉熵：可以用来表示从事件A的角度来看，如何描述事件B。 一句话总结的话：KL散度可以被用于计算代价，而在特定情况下最小化KL散度等价于最小化交叉熵。而交叉熵的运算更简单，所以用交叉熵来当做代价。 信息量 首先是信息量。假设我们听到了两件事，分别如下：事件A：巴西队进入了2018世界杯决赛圈。事件B：中国队进入了2018世界杯决赛圈。仅凭直觉来说，显而易见事件B的信息量比事件A的信息量要大。究其原因，是因为事件A发生的概率很大，事件B发生的概率很小。所以当越不可能的事件发生了，我们获取到的信息量就越大。越可能发生的事件发生了，我们获取到的信息量就越小。那么信息量应该和事件发生的概率有关。 假设 $X$ 是一个离散型随机变量，其取值集合为 $\chi$ ,概率分布函数 $p(x)=Pr(X=x),x\in\chi$ ,则定义事件 $X=x_0$ 的信息量为： I(x_0)=-log(p(x_0))由于是概率所以$p(x_0)$的取值范围是[0,1], 绘制为图形如下： 什么是熵(Entropy)？ 放在信息论的语境里面来说，就是一个事件所包含的信息量。我们现在有了信息量的定义，而熵用来表示所有信息量的期望，即： 因此熵被定义为 $S(x)=-\sum_{i}P(x_{i})log_{b}P(x_{i})$ 如何衡量两个事件/分布之间的不同：KL散度 我们上面说的是对于一个随机变量x的事件A的自信息量，如果我们有另一个独立的随机变量x相关的事件B，该怎么计算它们之间的区别？ 此处我们介绍默认的计算方法：KL散度，有时候也叫KL距离，一般被用于计算两个分布之间的不同。看名字似乎跟计算两个点之间的距离也很像，但实则不然，因为KL散度不具备有对称性。在距离上的对称性指的是A到B的距离等于B到A的距离。 KL散度的数学定义： 相对熵又称KL散度,如果我们对于同一个随机变量 x 有两个单独的概率分布 P(x) 和 Q(x)，我们可以使用 KL 散度（Kullback-Leibler (KL) divergence）来衡量这两个分布的差异 维基百科对相对熵的定义 In the context of machine learning, DKL(P‖Q) is often called the information gain achieved if P is used instead of Q. 对于离散事件我们可以定义事件A和B的差别为： D_{KL}(A||B) = \sum_{i}P_{A}(x_i) log\bigg(\frac{P_{A}(x_i)}{P_{B}(x_i)} \bigg) = \sum_{i}P_{A}(x_i)log(P_{A}(x_i ))- P_{A}(x_i)log(P_{B}(x_i))对于连续事件，那么我们只是把求和改为求积分而已。 D_{KL}(A||B) = \int a(x) log\bigg(\frac{a(x)}{b(x)} \bigg)从公式中可以看出： 如果 $P_A=P_B$，即两个事件分布完全相同，那么KL散度等于0。 观察公式，可以发现减号左边的就是事件A的熵，请记住这个发现。 如果颠倒一下顺序求 $D_{KL}(B||A)$，那么就需要使用B的熵，答案就不一样了。所以KL散度来计算两个分布A与B的时候是不是对称的，有“坐标系”的问题**，$D_{KL}(A||B)\ne D_{KL}(B||A)$ 换句话说，KL散度由A自己的熵与B在A上的期望共同决定。当使用KL散度来衡量两个事件(连续或离散)，上面的公式意义就是求 A与B之间的对数差 在 A上的期望值。 KL散度 = 交叉熵 - 熵？ 如果我们默认了用KL散度来计算两个分布间的不同，那还要交叉熵做什么？ 事实上交叉熵和KL散度的公式非常相近，其实就是KL散度的后半部分(公式2.1)：A和B的交叉熵 = A与B的KL散度 - A的熵。 $D_{KL}(A||B) = -S(A)+H(A,B) $ 对比一下这是KL散度的公式： $D_{KL}(A||B) = \sum_{i}P_{A}(x_i) log\bigg(\frac{P_{A}(x_i)}{P_{B}(x_i)} \bigg) = \sum_{i}P_{A}(x_i)log(P_{A}(x_i ))- P_{A}(x_i)log(P_{B}(x_i)) $ 这是熵的公式： $S(A) = -\sum_{i}P_A(x_{i})logP_A(x_{i})$ 这是交叉熵公式： $H(A,B)= -\sum_{i}P_{A}(x_i)log(P_{B}(x_i)) $ 此处最重要的观察是，如果 $S(A)$是一个常量，那么$D_{KL}(A||B) = H(A,B) $ ，也就是说KL散度和交叉熵在特定条件下等价。 为什么交叉熵可以用作代价？ 接着上一点说，最小化模型分布 $P(model)$ 与 训练数据上的分布 $P(training)$ 的差异 等价于 最小化这两个分布间的KL散度，也就是最小化 $KL(P(training)||P(model))$。 比照第四部分的公式： 此处的A就是数据的真实分布： $P(training)$ 此处的B就是模型从训练数据上学到的分布： $P(model)$ 巧的是，训练数据的分布A是给定的。那么根据我们在第四部分说的，因为A固定不变，那么求 $D_{KL}(A||B)$等价于求 $H(A,B)$ ，也就是A与B的交叉熵。得证，交叉熵可以用于计算“学习模型的分布”与“训练数据分布”之间的不同。当交叉熵最低时(等于训练数据分布的熵)，我们学到了“最好的模型”。 但是，完美的学到了训练数据分布往往意味着过拟合，因为训练数据不等于真实数据，我们只是假设它们是相似的，而一般还要假设存在一个高斯分布的误差，是模型的泛化误差下线。 因此在评价机器学习模型时，我们往往不能只看训练数据上的误分率和交叉熵，还是要关注测试数据上的表现。如果在测试集上的表现也不错，才能保证这不是一个过拟合或者欠拟合的模型。交叉熵比照误分率还有更多的优势，因为它可以和很多概率模型完美的结合。 所以逻辑思路是，为了让学到的模型分布更贴近真实数据分布，我们最小化 模型数据分布 与 训练数据之间的KL散度，而因为训练数据的分布是固定的，因此最小化KL散度等价于最小化交叉熵。 因为等价，而且交叉熵更简单更好计算，当然用它。 参考文献[1] Michael Nielsen.CHAPTER 3 Improving the way neural networks learn[DB/OL]. http://neuralnetworksanddeeplearning.com/chap3.html, 2018-06-21. [2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL].https://github.com/zhanggyb/nndl/blob/master/chap3.tex, 2018-06-21. [3] 微调. 为什么交叉熵（cross-entropy）可以用于计算代价？[DB/OL]. https://www.zhihu.com/question/65288314/answer/244557337. 2018-06-21. [4] 史丹利复合田. 一文搞懂交叉熵在机器学习中的使用，透彻理解交叉熵背后的直觉[DB/OL]. https://blog.csdn.net/tsyccnh/article/details/79163834. 2018-06-22.]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>交叉熵</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[反向传播算法]]></title>
    <url>%2F2018%2F06%2F21%2F%E5%8F%8D%E5%90%91%E4%BC%A0%E6%92%AD%E7%AE%97%E6%B3%95%2F</url>
    <content type="text"><![CDATA[反向传播（英语：Backpropagation，缩写为BP）是“误差反向传播”的简称，是一种与最优化方法（如梯度下降法）结合使用的，用来训练人工神经网络的常见方法。该方法计算对网络中所有权重计算损失函数的梯度。这个梯度会反馈给最优化方法，用来更新权值以最小化损失函数。 在神经网络上执行梯度下降法的主要算法。该算法会先按前向传播方式计算（并缓存）每个节点的输出值，然后再按反向传播遍历图的方式计算损失函数值相对于每个参数的偏导数。 相关资源： 喜欢研究代码的朋友可以查看我的GitHub 基于Numpy的反向传播算法代码实现 深度学习框架自动求导和梯度下降的原理 反向传播概述反向传播算法最初在 1970 年代被提及，但是人们直到 David Rumelhart、Geoffrey Hinton 和 Ronald Williams 的著名的 1986 年的论文中才认识到这个算法的重要性。 反向传播的核心是一个对代价函数 $C$ 关于任何权重 $w$ 和 偏置 $b$ 的偏导数 $\partial{C}/\partial{w}$ 的表达式。 这个表达式告诉我们在改变权重和偏置时，代价函数变化的快慢。 关于代价函数的两个假设 代价函数可以被写成在每一个训练样本 $x$ 上的代价函数 $C_x$ 的均值 $C=\frac{1}{n}\sum_{x}C_x$。 代价函数可以写成神经网络输出的函数。 需要假设1的原因是，反向传播实际上是对一个独立的训练样本计算了 $\partial{C_x}/\partial{w}$ 和 $\partial{C_x}/\partial{b}$。然后通过在所有训练样本上进行平均化获得 $\partial{C}/\partial{w}$ 和 $\partial{C}/\partial{w}$ 。 需要假设2的原因是，要把代价函数与神经网络输出联系起来，进而与神经网络的参数联系起来。 符号定义 $W_{jk}^{l}$ 是从 $l-1$ 层的第 $k$ 个神经元到 $l$ 层的第 $j$ 个神经元的权重。 $b_j^l$ 是第 $l$ 层的第 $j$ 个神经元的偏置。 $a_j^l$ 是第 $l$ 层的第 $j$ 个神经元的激活值。 $\sigma$ 是激活函数。 把上面的符号向量化 $W^{l}$ 是权重矩阵，第 $j$ 行 $k$ 列的元素是 $W_{jk}^{l}$。 例如第二层与第三层之间的权重矩阵是 w^3 = { \left[ \begin{matrix} w_{11}^3 & w_{12}^3 & w_{13}^3 & w_{14}^3\\ w_{21}^3 & w_{22}^3 & w_{23}^3 & w_{24}^3 \end{matrix} \right] } $b^l$ 是偏置向量。第 $j$ 行的元素是 $b_j^l$。 例如第二层的偏置向量是 b^2 = { \left[ \begin{matrix} b_{1}^2 \\ \\ b_{2}^2\\ \\ b_{3}^2\\ \\ b_{4}^2 \end{matrix} \right] }有了这些表示 $l$ 层的第 $j$ 个神经元的激活值 $a_j^l$ 就和 $l-1$ 层的激活值通过方程关联起来了 a^{l}_j = \sigma\left( \sum_k w^{l}_{jk} a^{l-1}_k + b^l_j \right)把上面式子向量化 a^{l} = \sigma(w^l a^{l-1}+b^l)例如第三层的激活向量是 { \left[ \begin{matrix} a_{1}^3 \\ \\ a_{2}^3 \\ \end{matrix} \right] } =\sigma\left( { \left[ \begin{matrix} w_{11}^3 & w_{12}^3 & w_{13}^3 & w_{14}^3\\ w_{21}^3 & w_{22}^3 & w_{23}^3 & w_{24}^3 \end{matrix} \right] } { \left[ \begin{matrix} a_{1}^2 \\ \\ a_{2}^2 \\ \\ a_{3}^2 \\ \\ a_{4}^2 \\ \end{matrix} \right] }+ { \left[ \begin{matrix} b_{1}^3 \\ \\ b_{2}^3 \\ \end{matrix} \right] }\right) $a^{l}$ 是激活向量。第 $j$ 行的元素是 $a_j^l$。 定义 z^l \equiv w^l a^{l-1}+b^l则 $a^l =\sigma(z^l)$ $z^l$ 表示第第 $l$ 层的带权输入。第 $j$ 个元素是 $z_j^l$。 z^l_j=\sum_k w^l_{jk} a^{l-1}_k+b^l_j $z_j^l$ 是第 $l$ 层的第 $j$ 个神经元的带权输入。 反向传播的核心是一个对代价函数 $C$ 关于任何权重 $w$ 和 偏置 $b$ 的偏导数 $\partial{C}/\partial{w}$ 的表达式。为了计算这些值，引入一个中间量 $\delta_j^l$ ,表示在 $l$ 层的第 $j$ 个神经元的误差。 定义 \delta^l_j \equiv \frac{\partial C}{\partial z^l_j}.$\delta^l$ 是误差向量，$\delta^l$ 的第 $j$ 个元素是 $\delta_j^l$。 反向传播的四个基本方程 $\nabla_a$ 是求梯度运算符，$\nabla_a C$ 结果是一个向量，其元素是偏导数 $\partial C / \partial a^L_j$。 $\odot$ 是按元素乘积的运算符，$ {(s \odot t)}_j = s_j t_j $ ，例如 \left[\begin{array}{c} 1 \\ 2 \end{array}\right] \odot \left[\begin{array}{c} 3 \\ 4\end{array} \right] = \left[ \begin{array}{c} 1 * 3 \\ 2 * 4 \end{array} \right] = \left[ \begin{array}{c} 3 \\ 8 \end{array} \right]. 计算公式 维度变化 $\delta^L =\nabla_a C\odot \dfrac{\partial f^{(L)}}{\partial z^L} $ $(d^L, 1) = (d^L, 1) * (d^L, 1)$ $\delta^{(l)} =({(w^{(l+1)})}^T\delta^{(l+1)})\odot \sigma’(z^l) $ $(d^l, 1) = {({d}^{l+1}, {d}^{l})}^T (d^{l+1}, 1) * (d^l, 1)$ $\dfrac{\partial C}{\partial b^{(l)}} =\delta^{(l)}$ $(d^l, 1) = (d^l, 1)$ $\dfrac{\partial C}{\partial w^l} = \delta^l (a^{l-1})^T $ $(d^l, d^{l-1}) = (d^l,1) {(d^{l-1}, 1)}^T$ 反向传播算法 正如我们上面所讲的，反向传播算法对一个训练样本计算代价函数的梯度，$C=C_x$。在实践中，通常将反向传播算法和诸如随机梯度下降这样的学习算法进行组合使用，我们会对许多训练样本计算对应的梯度。特别地，给定一个大小为 m 的小批量数据，下面的算法在这个小批量数据的基础上应用梯度下降学习算法： 反向传播算法与小批量随机梯度下降算法结合的一个示意代码，完整代码参看 network.py 12345678910111213141516171819202122232425262728293031323334def backprop(self, x, y): """Return a tuple ``(nabla_b, nabla_w)`` representing the gradient for the cost function C_x. ``nabla_b`` and ``nabla_w`` are layer-by-layer lists of numpy arrays, similar to ``self.biases`` and ``self.weights``.""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] # feedforward activation = x activations = [x] # list to store all the activations, layer by layer zs = [] # list to store all the z vectors, layer by layer for b, w in zip(self.biases, self.weights): z = np.dot(w, activation)+b zs.append(z) activation = sigmoid(z) activations.append(activation) # backward pass delta = self.cost_derivative(activations[-1], y) * \ sigmoid_prime(zs[-1]) nabla_b[-1] = delta nabla_w[-1] = np.dot(delta, activations[-2].transpose()) # Note that the variable l in the loop below is used a little # differently to the notation in Chapter 2 of the book. Here, # l = 1 means the last layer of neurons, l = 2 is the # second-last layer, and so on. It's a renumbering of the # scheme in the book, used here to take advantage of the fact # that Python can use negative indices in lists. for l in range(2, self.num_layers): z = zs[-l] sp = sigmoid_prime(z) delta = np.dot(self.weights[-l+1].transpose(), delta) * sp nabla_b[-l] = delta nabla_w[-l] = np.dot(delta, activations[-l-1].transpose()) return (nabla_b, nabla_w) 12345678def cost_derivative(self, output_activations, y): """Return the vector of partial derivatives \partial C_x / \partial a for the output activations.""" return (output_activations-y)def sigmoid_prime(z): """Derivative of the sigmoid function.""" return sigmoid(z)*(1-sigmoid(z)) 四个基本方程的证明 我们现在证明这四个基本的方程（BP）-（BP4）。所有的这些都是多元微积分的链式法则的推论。 证明$\delta^L = \nabla_a C \odot \sigma’(z^L)$从方程（BP1）开始，它给出了误差 $\delta^l$ 的表达式。根据定义 \delta^l_j \equiv \frac{\partial C}{\partial z^l_j}.根据关于代价函数的两个假设2 “代价函数可以写成神经网络输出的函数”，应用链式法测可知可先对神经网络输出求偏导${\partial C}/{\partial a^L_k}$再对带权输出求偏导${\partial a^L_k}/{\partial z^L_j}$。 \delta^L_j = \sum_k \frac{\partial C}{\partial a^L_k} \frac{\partial a^L_k}{\partial z^L_j},看起来上面式子很复杂，但是由于第 $k$ 个神经元的输出激活值 $a_k^l$ 只依赖于 当下标 $k=j$ 时第 $j$ 个神经元的输入权重 $z_j^l$。所有当 $k\neq {j}$ 时 $\partial a^L_k / \partial z^L_j$ 消失了。结果我们可以简化上一个式子为 \delta^L_j = \frac{\partial C}{\partial a^L_j} \frac{\partial a^L_j}{\partial z^L_j}.又因为 $a^L_j = \sigma(z^L_j)$ 所以 $\frac{\partial a^L_j}{\partial z^L_j}$ 可以写成 $\sigma’(z^L_j)$，方程变为 \delta^L_j = \frac{\partial C}{\partial a^L_j} \sigma'(z^L_j)这就是分量形式的（BP1），再根据$\nabla_a$ 是求梯度运算符，$\nabla_a C$ 结果是一个向量，其元素是偏导数 $\partial C / \partial a^L_j$。方程可以写成向量形式 \delta^L ={\nabla_a {C}} \odot {\sigma'(z^L)}（BP1） 得到证明。 证明 $ \delta^l = ((w^{l+1})^T \delta^{l+1}) \odot \sigma’(z^l)$证明（BP2），它个给出以下一层误差 $\delta^{l+1}$ 的形式表示误差 $\delta^l$。为此，要以 $\delta^l_j = \partial C / \partial z^l_j$的形式重写 $\delta^{l+1}_k = \partial C / \partial z^{l+1}_k$,$\delta^{l+1}$ 和 $\delta^l$ 通过 $z_k^{l+1}$ 和 $z_j^l$ 联系起来，应用链式法测 根据 $z_k^{l+1}$ 的定义有 z^{l+1}_k = \sum_j w^{l+1}_{kj} a^l_j +b^{l+1}_k = \sum_j w^{l+1}_{kj} \sigma(z^l_j) +b^{l+1}_k$z_k^{l+1}$ 对 $z_j^{l}$ 做偏微分，得到 \frac{\partial z^{l+1}_k}{\partial z^l_j} = w^{l+1}_{kj} \sigma'(z^l_j)注意虽然$z^{l+1}$ 和 $z^{l}$ 所在的两层神经元连接错综复杂，但两层之间任意一对神经元（同一层内不连接）只有一条连接，即 $z_k^{l+1}$ 和 $z_j^{l}$ 之间只通过 $w_{kj}^{l+1}$ 连接。所以$z_k^{l+1}$ 对 $z_j^{l}$ 做偏微分的结果很简单，只是 $ w^{l+1}_{kj} \sigma’(z^l_j)$。把这个结果带入 $\delta_j^l$ 中 \delta^l_j = \sum_k w^{l+1}_{kj} \delta^{l+1}_k \sigma'(z^l_j)这正是以分量形式写的(BP2)。 写成向量形式 \delta^l = ((w^{l+1})^T \delta^{l+1}) \odot \sigma'(z^l)举例 { \left[ \begin{matrix} \delta_{1}^l \\ \\ \delta_{2}^l \\ \\ ... \\ \delta_{j}^l \end{matrix} \right] } = { \left[ \begin{matrix} w_{11}^{l+1} & w_{21}^{l+1} & w_{31}^{l+1} & ... &w_{k1}^{l+1} \\ \\ w_{12}^{l+1} & w_{22}^{l+1} & w_{32}^{l+1} & ... & w_{k2}^{l+1} \\ \\ ... \\ w_{j1}^{l+1} & w_{j2}^{l+1} & w_{j1}^{l+1} & ... & w_{kj}^{l+1} \end{matrix} \right] } { \left[ \begin{matrix} \delta_{1}^{l+1} \\ \\ \delta_{2}^{l+1} \\ \\ \delta_{3}^{l+1} \\ \\ ... \\ \delta_{k}^{l+1} \end{matrix} \right] } \odot { \left[ \begin{matrix} \sigma'(z_1^l) \\ \\ \sigma'(z_2^l) \\ \\ \sigma'(z_3^l) \\ \\ ... \\ \sigma'(z_k^l) \end{matrix} \right] }（BP2） 得到证明。 证明 $\frac{\partial C}{\partial b^l_j} =\delta^l_j.$根据 $z_j^l$ 定义 z^l_j=\sum_k w^l_{jk} a^{l-1}_k+b^l_j和 $\delta_j^l$ 定义 \delta^l_j \equiv \frac{\partial C}{\partial z^l_j}.因此 \frac{\partial C}{\partial b^l_j} = \frac{\partial C}{\partial z^l_j}\frac{\partial z^l_j}{\partial b^l_j}又因为 \frac{\partial z^l_j}{\partial b^l_j} = 1所以 \frac{\partial C}{\partial b^l_j} = \frac{\partial C}{\partial z^l_j}\frac{\partial z^l_j}{\partial b^l_j} = \frac{\partial C}{\partial z^l_j}\cdot 1= \frac{\partial C}{\partial z^l_j}=\delta^l_j即 \frac{\partial C}{\partial b^l_j} =\delta^l_j写成向量形式 \frac{\partial C}{\partial b^l} =\delta^l（BP3） 得到证明。 证明 $\frac{\partial C}{\partial w^l_{jk}} = a^{l-1}_k \delta^l_j$根据 $z_j^l$ 定义 z^l_j=\sum_k w^l_{jk} a^{l-1}_k+b^l_j和 $\delta_j^l$ 定义 \delta^l_j \equiv \frac{\partial C}{\partial z^l_j}.又因为 \frac{\partial z^l_j}{\partial w^l_{jk}} = a_k^{l-1}所以 \frac{\partial C}{\partial w^l_{jk}} = \frac{\partial C}{\partial z^l_j}\frac{\partial z^l_j}{\partial w^l_{jk}} = \delta^l_j a_k^{l-1}把式子向量化 \frac{\partial C}{\partial w^l} = \delta^l (a^{l-1})^T举例 \frac{\partial C}{\partial w^l} = { \left[ \begin{matrix} \delta_{1}^l \\ \\ \delta_{2}^l \\ \\ ... \\ \delta_{j}^l \end{matrix} \right] }{ \left[ \begin{matrix} a_{1}^{l-1} & a_{2}^{l-1} & ... &a_{k}^{l-1} \end{matrix} \right] }（BP4） 得到证明。 一个直观的图： 到此关于反向传播的四个方程已经全部证明完毕。 其他学者反向传播四个方程的证明（他写的更简明扼要些）：CSDN: oio328Loio 矩阵形式反向传播算法正如我们上面所讲的，反向传播算法对一个训练样本计算代价函数的梯度，$C=C_x$。在实践中，通常将反向传播算法和诸如随机梯度下降这样的学习算法进行组合使用，我们会对许多训练样本计算对应的梯度。特别地，给定一个大小为 m 的小批量数据，下面的算法在这个小批量数据的基础上应用梯度下降学习算法： 根据上面的小批量数据的符号定义，为了方便用矩阵表示，下面新增了一些符号。 $z^{v,l}$ 表示神经网络第 $l$ 层的小批量样本中的第 $v$ 个样本的带权输入向量，用矩阵 $Z^l$ 来表示就是 Z^l = { \left[ \begin{matrix} {(z^{1,l})}^T \\ \\ {(z^{2,l})}^T\\ \\ ...\\ \\ {(z^{m,l})}^T \end{matrix} \right] }$a^{v,l}$ 表示神经网络第 $l$ 层的小批量样本中的第 $v$ 个样本的激活向量，用矩阵 $A^l$ 来表示就是 A^l = { \left[ \begin{matrix} {(a^{1,l})}^T \\ \\ {(a^{2,l})}^T\\ \\ ...\\ \\ {(a^{m,l})}^T \end{matrix} \right] }$\delta^{v,l}$ 表示神经网络第 $l$ 层的小批量样本中的第 $v$ 个样本的误差向量，用矩阵 $\Delta^l$ 来表示就是 \delta^l = { \left[ \begin{matrix} {(\delta^{1,l})}^T \\ \\ {(\delta^{2,l})}^T\\ \\ ...\\ \\ {(\delta^{m,l})}^T \end{matrix} \right] } \delta^L =\nabla_a C\odot \frac{\partial f^{(L)}}{\partial z^L}的矩阵形式是， \Delta^L =\nabla_{A^L} C\odot \frac{\partial f^{(L)}}{\partial Z^L} \delta^{l}=({(w^{l+1})}^T\delta^{l+1})\odot \sigma'(z^l)的矩阵形式是， \Delta^{l}=(\Delta^{l+1}w^{l+1})\odot \sigma'(Z^l) \frac{\partial C}{\partial b^{(l)}}=\delta^{(l)}的矩阵形式是， \frac{\partial C}{\partial b^{(l)}}=\frac{1}{m}{(sum(\Delta^l, axis=0))}^T \frac{\partial C}{\partial w^l} = \delta^l (a^{l-1})^T的矩阵形式是， \frac{\partial C}{\partial w^{(l)}}=\frac{1}{m}{(\Delta^l)}^TA^{l-1}归纳一下，可以得到矩阵形式的反向传播算法： 计算公式 维度变化 $\Delta^L =\nabla_{A^L} C\odot \dfrac{\partial f^{(L)}}{\partial Z^L}$ $(m, d^L) = (m, d^L) * (m, d^L)$ $\Delta^{l} =(\Delta^{l+1}W^{l+1})\odot \sigma’(Z^l)$ $(m, {d}^l) = (m, {d}^{l+1}) ({d}^{l+1}, {d}^l)$ $\dfrac{\partial C}{\partial b^{(l)}} =\dfrac{1}{m}{(sum(\Delta^l, axis=0))}^T$ $(d^l, 1) = {(1, d^l)}^T$ $\dfrac{\partial C}{\partial w^{(l)}} =\dfrac{1}{m}{(\Delta^l)}^TA^{l-1} $ $(d^{l}, d^{l-1}) = {(m, d^l)}^T(m, d^{l-1})$ 反向传播：全局观 如上图所示，假设我们对 $w_{jk}^l$ 做一点微小的扰动 $\Delta w_{jk}^l$, 这个扰动会沿着神经网络最终影响到代价函数 $C$, 代价函数的 $\Delta C$ 改变和 $\Delta w_{jk}^l$ 按照下面公式联系起来 \Delta C \approx \frac{\partial C}{\partial w^l_{jk}} \Delta w^l_{jk}可以想象影响代价函数的一条路径是 \Delta C \approx \frac{\partial C}{\partial a^L_m} \frac{\partial a^L_m}{\partial a^{L-1}_n} \frac{\partial a^{L-1}_n}{\partial a^{L-2}_p} \ldots \frac{\partial a^{l+1}_q}{\partial a^l_j} \frac{\partial a^l_j}{\partial w^l_{jk}} \Delta w^l_{jk}为了计算 $C$ 的全部改变，我们需要对所有可能的路径进行求和，即 \Delta C \approx \sum_{mnp\ldots q} \frac{\partial C}{\partial a^L_m} \frac{\partial a^L_m}{\partial a^{L-1}_n} \frac{\partial a^{L-1}_n}{\partial a^{L-2}_p} \ldots \frac{\partial a^{l+1}_q}{\partial a^l_j} \frac{\partial a^l_j}{\partial w^l_{jk}} \Delta w^l_{jk}因为 \frac{\partial C}{\partial w^l_{jk}}=\frac{\Delta C}{\Delta w^l_{jk}}根据上面的三个式子可知 \frac{\partial C}{\partial w^l_{jk}} = \sum_{mnp\ldots q} \frac{\partial C}{\partial a^L_m} \frac{\partial a^L_m}{\partial a^{L-1}_n} \frac{\partial a^{L-1}_n}{\partial a^{L-2}_p} \ldots \frac{\partial a^{l+1}_q}{\partial a^l_j} \frac{\partial a^l_j}{\partial w^l_{jk}}上面的公式看起来复杂，这里有一个相当好的直觉上的解释。我们用这个公式计算 $C$ 关于网络中一个权重的变化率。而这个公式告诉我们的是：两个神经元之间的连接其实是关联于一个变化率因子，这仅仅是一个神经元的激活值相对于其他神经元的激活值的偏导数。路径的变化率因子就是这条路径上众多因子的乘积。整个变化率 $\partial C / \partial w^l_{jk}$ 就是对于所有可能从初始权重到最终输出的代价函数的路径的变化率因子的和。针对某一路径，这个过程解释如下， 如果用矩阵运算对上面式子所有的情况求和，然后尽可能化简，最后你会发现，自己就是在做反向传播！可以将反向传播想象成一种计算所有可能路径变化率求和的方式。或者，换句话说，反向传播就是一种巧妙地追踪权重和偏置微小变化的传播，抵达输出层影响代价函数的技术。 如果你尝试用上面的思路来证明反向传播，会比本文的反向传播四个方程证明复杂许多，因为按上面的思路来证明有许多可以简化的地方。其中可以添加一个巧妙的步骤，上面方程的偏导对象是类似 $a_q^{l+1}$ 的激活值。巧妙之处是改用加权输入，例如 $z_q^{l+1}$ ，作为中间变量。如果没想到这个主意，而是继续使用激活值 $a_q^{l+1}$ ，你得到的证明最后会比前文给出的证明稍稍复杂些。 其实最早的证明的出现也不是太过神秘的事情。因为那只是对简化证明的艰辛工作的积累！ 发展分析瓶颈BP神经网络无论在网络理论还是在性能方面已比较成熟。其突出优点就是具有很强的非线性映射能力和柔性的网络结构。网络的中间层数、各层的神经元个数可根据具体情况任意设定，并且随着结构的差异其性能也有所不同。但是BP神经网络也存在以下的一些主要缺陷。 学习速度慢，即使是一个简单的问题，一般也需要几百次甚至上千次的学习才能收敛。 容易陷入局部极小值。 网络层数、神经元个数的选择没有相应的理论指导。网络推广能力有限。 可解释性瓶颈，对网络输出结果不具备可靠的数学可解释性 神经网络对推理，规划等人工智能领域的其他问题还没有特别有效的办法。另外由于其参数数量巨大，对高计算性能硬件的依赖大，难以部署在轻量级低功耗硬件上，如嵌入式设备等 反向传播算法缺乏仿生学方面的理论依据，显然生物神经网络中并不存在反向传播这样的数学算法 未来发展方向BP网络主要用于以下四个方面。 函数逼近：用输入向量和相应的输出向量训练一个网络逼近一个函数。 模式识别：用一个待定的输出向量将它与输入向量联系起来。 分类：把输入向量所定义的合适方式进行分类。 数据压缩：减少输出向量维数以便于传输或存储。 除此之外，在神经网络的可解释性研究方面，向低功耗硬件迁移，以及在认知计算，规划推理等方面和其他传统技术进行结合探索 参考文献[1] Michael Nielsen. CHAPTER 2 How the backpropagation algorithm works[DB/OL]. http://neuralnetworksanddeeplearning.com/chap2.html, 2018-06-21. [2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL]. https://github.com/zhanggyb/nndl/blob/master/chap2.tex, 2018-06-21. [3] oio328Loio. 神经网络学习（三）反向（BP）传播算法（1）[DB/OL]. https://blog.csdn.net/hoho1151191150/article/details/79537246, 2018-06-25. [4] 机器之心. 反向传播算法 [DB/OL]. https://www.jiqizhixin.com/graph/technologies/7332347c-8073-4783-bfc1-1698a6257db3, 2019-08-04.]]></content>
      <categories>
        <category>数学</category>
        <category>反向传播算法</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>反向传播算法</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[贝叶斯估计、最大似然估计、最大后验估计三者的区别]]></title>
    <url>%2F2018%2F06%2F20%2F%E8%B4%9D%E5%8F%B6%E6%96%AF%E4%BC%B0%E8%AE%A1%E3%80%81%E6%9C%80%E5%A4%A7%E4%BC%BC%E7%84%B6%E4%BC%B0%E8%AE%A1%E3%80%81%E6%9C%80%E5%A4%A7%E5%90%8E%E9%AA%8C%E4%BC%B0%E8%AE%A1%E4%B8%89%E8%80%85%E7%9A%84%E5%8C%BA%E5%88%AB%2F</url>
    <content type="text"><![CDATA[实例分析即使学过机器学习的人，对机器学习中的 MLE(极大似然估计)、MAP(最大后验估计)以及贝叶斯估计(Bayesian) 仍有可能一知半解。对于一个基础模型，通常都可以从这三个角度去建模，比如对于逻辑回归（Logistics Regression）来说： MLE: Logistics Regression MAP: Regularized Logistics RegressionBayesian: Bayesian Logistic Regression 本文结合实际例子，以通俗易懂的方式去讲解这三者之间的本质区别，希望帮助读者扫清理解中的障碍。 先导知识点： 假设空间（Hypothesis Space） 什么叫假设空间呢？我们可以这样理解。机器学习包含很多种算法，比如线性回归、支持向量机、神经网络、决策树、GDBT等等。我们在建模的时候，第一步就是要选择一个特定的算法比如“支持向量机”。一旦选择了一个算法，就相当于我们选择了一个假设空间。 在一个假设空间里，我们通常会有无数种不同的解（或者可以理解成模型），一个优化算法（比如梯度下降法）做的事情就是从中选择最好的一个解或者多个解/模型，当然优化过程要依赖于样本数据。举个例子，如果我们选择用支持向量机，那相当于我们可选的解/模型集中在上半部分（蓝色点）。 一个具体“toy”问题 “ 张三遇到了一个数学难题，想寻求别人帮助。通过一番思考之后发现自己的朋友在清华计算机系当老师。于是，他决定找清华计算机系学生帮忙。那张三用什么样的策略去寻求帮助呢？ 在这里，“清华计算机系”是一个假设空间。在这个假设空间里，每一位学生可以看做是一个模型（的实例化）。 对于张三来说，他有三种不同的策略可以选择。 第一种策略 : MLE 第一种策略就是从系里选出过往成绩最好的学生，并让他去解答这个难题。比如我们可以选择过去三次考试中成绩最优秀的学生。 一般的学习流程分为“学习过程”和“预测过程”。第一种策略的方案可以用下面的图来表示。 在这里，学习过程相当于从所有系的学生中挑选出成绩最好的学生。所以，这里的“学生过往成绩单”就是我们已知的训练数据 D， 选出成绩最好的学生（计算历史平均分数，并选出最高的），这个过程就是MLE。一旦我们找到了成绩最好的学生，就可以进入预测环节。在预测环节中，我们就可以让他回答张三手里的难题 x’, 之后就可以得到他给出的解答 y’。 第二种策略：MAP 跟第一种策略的不同点在于，第二种策略中我们听取了老师的建议，老师就是张三的朋友。这位老师给出了自己的观点：_“小明和小花的成绩中可能存在一些水分”。_当我们按照成绩的高低给学生排序，假设前两名依次为小明和小花，如果我们不考虑这位老师的评价，则我们肯定把小明作为目标对象。然而，既然老师已经对小明和小花做了一些负面的评价，那这个时候，我们很有可能最后选择的是班级里的第三名，而不是小明或者小花。 我们把第二种策略的过程也用一个图来描述。与上面的图相比，唯一的区别在于这里多出了老师的评价，我们称之为 Prior。 也就是说我们根据学生以往的成绩并结合老师评价，选择了一位我们认为最优秀的学生（可以看成是模型）。之后就可以让他去回答张老师的难题 x’，并得到他的解答 y’。整个过程类似于MAP的估计以及预测。 到这里，有些读者可能会有一些疑惑：“_老师的评价(Prior)跟学生过往的成绩（Observation）是怎么结合在一起的？”_。 为了回答这个问题，我们不得不引出一个非常著名的定理，叫做 贝叶斯定理， 如下图所示。左边的项是MAP需要优化的部分，通过贝叶斯定理这个项可以分解成 MLE（第一种策略）和 Prior，也就是老师的评价。在这里，分母是常数项（Constant），所以不用考虑。 第三种策略 - Bayesian 最后，我们来介绍第三种策略。这种策略应该很多人也可以想象得到，其实就是让所有人都去参与回答张三的难题，但最后我们通过一些加权平均的方式获得最终的答案。 比如有三个学生，而且我们对这三个学生情况没有任何了解。通过提问，第一个学生回答的答案是A，第二个学生回答的答案也是A，但第三个学生回答的是B。在这种情况下，我们基本可以把A作为标准答案。接着再考虑一个稍微复杂的情况，假设我们通过以往他们的表现得知第三个学生曾经多次获得过全国奥赛的金牌，那这个时候该怎么办？ 很显然，在这种情况下，我们给予第三个学生的话语权肯定要高于其他两位学生。 我们把上面的这种思路应用到张三的问题上，其实相当于我们让所有计算机系的学生参与回答这个问题，之后把他们的答案进行汇总并得出最终的答案。如果我们知道每一位学生的话语权（权重），这个汇总的过程是确定性（deterministic)。 但每一位学生的话语权（权重）怎么得到呢？ 这就是贝叶斯估计做的事情！ 我们用下面的一幅图来讲述贝叶斯估计和预测的整个过程。跟MAP类似，我们已知每一位学生过去三次考试考试成绩（D）以及老师的评价（Prior）。 但跟MAP不同的是， 我们这里的目标不再是- “选出最优秀的学生”，而是通过观测数据（D）去获得每一位学生的发言权（权重）， 而且这些权重全部加起来要等于1， 相当于是一个valid分布(distribution)。 总结起来，在第三种策略之下，给定过去考试成绩(D)和老师的评价（Prior）, 我们的目标是估计学生权重的分布，也称之为Posterior Distribution。 那这个分布具体怎么去估计呢？ 这部分就是贝叶斯估计做的事情，有很多种方法可以做这件事情，比如MCMC, Variational Method等等，但这并不是本文章的重点，所以不在这里进一步解释，有兴趣的读者可以关注之后关于贝叶斯的专栏文章。从直观的角度思考，因为我们知道每一位学生过往的成绩，所以我们很容易了解到他们的能力水平进而估计出每一位学生的话语权（权重）。 一旦我们获得了这个分布（也就是每一位学生的权重），接下来就可以通过类似于加权平均的方式做预测了，那些权重高的学生话语权自然就越大。 以上是对MLE, MAP以及贝叶斯估计的基本讲解。下面我们试图去回答两个常见的问题。 Q: 随着我们观测到越来越多的数据，MAP估计逐步逼近MLE，这句话怎么理解？ 我们接着使用之前MAP（第二种策略）的例子。在这里，我们对原来的问题稍作改变。在之前的例子里我们假设能够得到每一位学生过去三次考试中的成绩。但在这里，我们进一步假定可以获得每一位学生过去100次考试中的成绩。 那这样的修改会带来什么样的变化呢？ 如果仔细想一想，其实也很容易想得到。我们设想一下这样的两种场景。假设我们知道某一位学生过去三次的考试成绩比较优异，但老师却告诉我们这位学生能力其实不怎么样，那这时候我们很可能就去相信老师了，毕竟仅仅通过三次考试的成绩很难对一个学生有全面的了解。但相反，假设我们了解到这位学生在过去100次考试中全部获得了班里第一名，但同时老师又告诉我们这位学生的能力其实不怎么样，那这时候我们会有什么样的反应？ 两三次考试或许可以算做是运气，但连续100次都是第一名这件事情很难再跟运气画等号吧？ 我们甚至可能会去怀疑老师的品德，是不是故意污蔑人家？ 这就是说，当我们观测到的数据越来越多的时候，我们从数据中获取的信息的置信度是越高的，相反老师提供的反馈（Prior）的重要性就会逐渐降低。理想情况下，当我们拥有无穷多的数据样本时，MAP会逼近MLE估计，道理都是一样的。 Q: 为什么贝叶斯估计会比MLE, MAP难？ 回顾一下，MLE 和MAP都是在寻找一个最优秀的学生。贝叶斯估计则是在估计每一位学生的权重。第一种情况下，为了寻找最优秀的学生，我们只需知道学生之间的“相对”优秀程度。这个怎么理解呢？ 比如一个班里有三个学生A,B,C，我们知道学生A比B优秀，同时知道B比C优秀，那这时候就可以推断出学生A是最优秀的，我们并不需要明确知道A的成绩是多少，B的成绩是多少….. 但在贝叶斯估计模式下，我们必须要知道每一个学生的绝对权重，因为最后我们获得的答案是所有学生给出的答案的加权平均，而且所有学生的权重加起来要保证等于1(任何一个分布的积分和必须要等于1）。 假设我们知道每一位学生的能力值，a1, a2,…. an，这个能作为权重吗？ 显然不能。为了获得权重，有一种最简单的方法就是先求和，然后再求权重。比如先计算 a1+…+an = S, 再用a1/S 作为权重。这貌似看起来也不难啊，只不过多做了一个加法操作？ 我们很容易看出这个加法操作的时间复杂度是O(n)，依赖于总体学生的数量。如果我们的假设空间只有几百名学生，这个是不成问题的。 但实际中，比如我们假设我们的模型用的是支持向量机，然后把假设空间里的每一个可行解比喻成学生，那这个假设空间里有多少个学生呢？ 是无数个！！， 也就是说需要对无穷多个数做这种加法操作。 当然，这种加法操作会以积分(integeral)的方式存在，但问题是这种积分通常没有一个closed-form的解，你必须要去近似地估计才可以，这就是MCMC或者Variational方法做的事情，不在这里多做解释。 本文几点重要的Take-aways： 每一个模型定义了一个假设空间，一般假设空间都包含无穷的可行解； MLE不考虑先验（prior)，MAP和贝叶斯估计则考虑先验（prior）； MLE、MAP是选择相对最好的一个模型（point estimation）， 贝叶斯方法则是通过观测数据来估计后验分布(posterior distribution)，并通过后验分布做群体决策，所以后者的目标并不是在去选择某一个最好的模型； 当样本个数无穷多的时候，MAP理论上会逼近MLE； 贝叶斯估计复杂度大，通常用MCMC等近似算法来近似； 最后贴一张总结的图: 理论分析一、机器学习 核心思想是从past experience中学习出规则，从而对新的事物进行预测。对于监督学习来说，有用的样本数目越多，训练越准确。 用下图来表示机器学习的过程及包含的知识： 简单来说就是： 首先要定义我们的假设空间（Model assumption）：如线性分类，线性回归，逻辑回归，SVM，深度学习网络等。 如何衡量我们学出来的模型的好坏？定义损失函数（目标函数），lost function，如square loss 如何对假设的模型做优化，及optimization过程。简单说，就是选择一种算法（如：梯度下降，牛顿法等），对目标函数进行优化，最终得到最优解； 不同的模型使用不同的算法，如逻辑回归通常用梯度下降法解决，神经网络用反向传播算法解决，贝叶斯模型则用MCMC来解决。 机器学习 = 模型 + 优化（不同算法） 还有一个问题，模型的复杂度怎么衡量？因为复杂的模型容易出现过拟合（overfitting）。解决过拟合的方就是加入正则项（regularization） 以上问题都解决之后，我们怎么判断这个解就是真的好的呢？用 交叉验证（cross-validation） 来验证一下。 二、ML vs MAP vs Bayesian ML（最大似然估计）：就是给定一个模型的参数，然后试着最大化p(D|参数)。即给定参数的情况下，看到样本集的概率。目标是找到使前面概率最大的参数。 逻辑回归都是基于ML做的； 缺点：不会把我们的先验知识加入模型中。 MAP（最大后验估计）：最大化p(参数|D)。 Bayesian：我们的预测是考虑了所有可能的参数，即所有的参数空间（参数的分布）。 ML和MAP都属于同一个范畴，称为（freqentist），最后的目标都是一样的：找到一个最优解，然后用最优解做预测。 三、ML 我们需要去最大化p(D|参数)，这部分优化我们通常可以用把导数设置为0的方式去得到。然而，ML估计不会把先验知识考虑进去，而且很容易造成过拟合现象。 举个例子，比如对癌症的估计，一个医生一天可能接到了100名患者，但最终被诊断出癌症的患者为5个人，在ML估计的模式下我们得到的得到癌症的概率为0.05。 这显然是不太切合实际的，因为我们根据已有的经验，我们知道这种概率会低很多。然而ML估计并没有把这种知识融入到模型里。 四、MAP 通过上面的推导我们可以发现，MAP与ML最大的不同在于p(参数)项，所以可以说MAP是正好可以解决ML缺乏先验知识的缺点，将先验知识加入后，优化损失函数。 其实p(参数)项正好起到了正则化的作用。如：如果假设p(参数)服从高斯分布，则相当于加了一个L2 norm；如果假设p(参数)服从拉普拉斯分布，则相当于加了一个L1 norm。 五、Bayesian 再次强调一下： ML和MAP只会给出一个最优的解， 然而贝叶斯模型会给出对参数的一个分布，比如对模型的参数, 假定参数空间里有参数1,参数2, 参数3,…参数N，贝叶斯模型学出来的就是这些参数的重要性（也就是分布），然后当我们对新的样本预测的时候，就会让所有的模型一起去预测，但每个模型会有自己的权重（权重就是学出来的分布）。最终的决策由所有的估计根据其权重做出决策。 模型的ensemble的却大的优点为它可以reduce variance, 这根投资很类似，比如我们投资多种不同类型的股票，总比投资某一个股票时的风险会低。 六、上面提到了frequentist和bayesian，两者之间的区别是什么？ 用一个简答的例子来再总结一下。 比如你是班里的班长，你有个问题想知道答案，你可以问所有的班里的学生。 一种方案是，问一个学习最好的同学。 另一种方案是，问所有的同学，然后把答案综合起来，但综合的时候，会按照每个同学的成绩好坏来做个权重。 第一种方案的思想类似于ML,MAP，第二种方案类似于贝叶斯模型。 七、Bayesian的难点 所以整个贝叶斯领域的核心技术就是要近似的计算 p($\theta$|D），我们称之为 bayesian inference ,说白了，这里的核心问题就是要近似这个复杂的积分（integral), 一种解决方案就是使用蒙特卡洛算法。比如我想计算一个公司所有员工的平均身高，这个时候最简答粗暴的方法就是让行政去一个一个去测量，然后计算平均值。但想计算所有中国人的平均身高，怎么做？（显然一个个测量是不可能的） 即采样。我们随机的选取一些人测量他们的身高，然后根据他们的身高来估计全国人民的审稿。当然采样的数目越多越准确，采样的数据越有代表性越准确。这就是蒙特卡洛算法的管家思想。 再例： 假设我们不知道π，但是想计算圆的面积。也可以通过采样的方法近似得到。随机再下图所示的正方形中撒入一些点，记落入红色区域的点的个数为n1,落入白色区域的个数为n2，则四分之一圆的面积就为n1/(n1+n2).——蒙特卡洛思想 那么，如何对连续函数估计呢？采样n多个数据，逼近最后的积分值。 假设我们要计算 f(x)的期望值， 我们也有p(x)这种分布，这个时候我们就可以不断的从p(x)这个分布里做一些采样，比如 x1,x2,…xn, 然后用这些采样的值去算f(x), 所以最后得到的结果就是 (f(x1) + f(x2),, + f(xn))/ n 然鹅，上面例子中提到的采样都是独立的。也就是每个样本跟其他的样本都是独立的，不影响彼此之间的采样。然而，在现实问题上，有些时候我们想加快有效样本的采样速度。这个问题讨论的就是怎么优化采样过程了，也是机器学习里一个比较大的话题了。 重申一下，用上面提到的采样方式我们可以去近似估计复杂的积分，也可以计算圆的面积，也可以计算全国人口的平均身高。但这个采样方式是独立的，有些时候，我们希望我们用更少的样本去更准确的近似某一个目标，所以就出现了sampling这种一个领域的研究，就是在研究以什么样的方式优化整个采样过程，使得过程更加高效。 MCMC这种采样方法，全称为markov chain monte carlo采样方法，就是每个采样的样本都是互相有关联性的。 但是MCMC算法需要在整个数据集上计算。也就是说为了得到一个样本，需要用所有的数据做迭代。这样当N很大时，显然不适用。而且限制了贝叶斯方法发展的主要原因就是计算复杂度太高。因此现在贝爷第领域人们最关心的问题是：怎么去优化采样，让它能够在大数据环境下学习出贝叶斯模型？ 降低迭代复杂度的一个实例： 对于逻辑回归，使用梯度下降法更新参数时，有批量梯度下降法（即使用整个数据集去更新参数），为了降低计算复杂度，人们使用了随机梯度下降法，即随机从数据集中选取样本来更新参数。 所以，能否将此思想用于MCMC采样中呢？ Yes！langevin dynamic（MCMC算法中的一种），和stochastic optimizaiton(比如随机梯度下降法)可以结合在一起用。这样，我们就可以通过少量的样本去做采样，这个时候采样的效率就不在依赖于N了，而是依赖于m, m是远远小于N。 参考文献[1] 贪心科技. 机器学习中的MLE、MAP和贝叶斯估计[DB/OL]. https://zhuanlan.zhihu.com/p/37543542, 2018-06-20. [2] 江湖小妞. 贝叶斯思想以及与最大似然估计、最大后验估计的区别[DB/OL].http://www.cnblogs.com/little-YTMM/p/5399532.html, 2018-06-20.]]></content>
      <categories>
        <category>数学</category>
      </categories>
      <tags>
        <tag>贝叶斯估计</tag>
        <tag>最大似然估计</tag>
        <tag>最大后验估计</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[使用神经网络识别手写数字——代码实现]]></title>
    <url>%2F2018%2F06%2F19%2F%E4%BD%BF%E7%94%A8%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E8%AF%86%E5%88%AB%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97%E2%80%94%E2%80%94%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%2F</url>
    <content type="text"><![CDATA[部分代码解读在之前描述 MNIST 数据时，我说它分成了 60,000 个训练图像和 10,000 个测试图像。这是官方的 MNIST 的描述。实际上，我们将用稍微不同的方法对数据进行划分。我们将测试集保持原样，但是将 60,000 个图像的 MNIST 训练集分成两个部分：一部分 50,000 个图像，我们将用来训练我们的神经网络，和一个单独的 10,000 个图像的验证集。在本章中我们不使用验证数据，但是在本书的后面我们将会发现它对于解决如何去设置某些神经网络中的超参数是很有用的，例如学习率等，这些参数不被我们的学习算法直接选择。尽管验证数据不是原始 MNIST 规范的一部分，然而许多人以这种方式使用 MNIST，并且在神经网络中使用验证数据是很普遍的。从现在起当我提到“MNIST 训练数据”时，我指的是我们的 50,000 个图像数据集，而不是原始的 60,000图像数据集 除了 MNIST 数据，我们还需要一个叫做 Numpy 的 Python 库，用来做快速线性代数。如果你没有安装过 Numpy。在列出一个完整的代码清单之前，让我解释一下神经网络代码的核心特性。核心片段是一个 Network 类，我们用来表示一个神经网络。这是我们用来初始化一个 Network 对象的代码： 神经网络架构12345678class Network(object): def __init__(self, sizes): self.num_layers = len(sizes) self.sizes = sizes self.biases = [np.random.randn(y, 1) for y in sizes[1:]] self.weights = [np.random.randn(y, x) for x, y in zip(sizes[:-1], sizes[1:])] 在这段代码中，列表 sizes 包含各层神经元的数量。例如，如果我们想创建一个在第一层有 2 个神经元，第二层有 3 个神经元，最后层有 1 个神经元的 Network 对象，我们应这样写代码： 1net = Network([2, 3, 1]) Network 对象中的权重和偏置都是被随机初始化的，使用 Numpy 的 np.random.randn! 函数来生成均值为 0，标准差为 1 的高斯分布。这样的随机初始化给了我们的随机梯度下降算法一个起点。 激活函数我们从定义 S型函数开始： 12def sigmoid(z): return 1.0/(1.0+np.exp(-z)) 前馈神经网络然后对 Network 类添加一个 feedforward 方法，对于网络给定一个输入 $a$，返回对应的输出,这个方法所做的是对每一层应用方程。 12345def feedforward(self, a): """Return the output of the network if "a" is input.""" for b, w in zip(self.biases, self.weights): a = sigmoid(np.dot(w, a)+b) return a 随机梯度下降算法当然，我们想要 Network 对象做的主要事情是学习。为此我们给它们一个实现随机梯度下降算法的 SGD 方法。代码如下。其中一些地方看似有一点神秘，我会在代码后面逐个分析。 123456789101112131415161718192021222324def SGD(self, training_data, epochs, mini_batch_size, eta, test_data=None): """Train the neural network using mini-batch stochastic gradient descent. The "training_data" is a list of tuples "(x, y)" representing the training inputs and the desired outputs. The other non-optional parameters are self-explanatory. If "test_data" is provided then the network will be evaluated against the test data after each epoch, and partial progress printed out. This is useful for tracking progress, but slows things down substantially.""" if test_data: n_test = len(test_data) n = len(training_data) for j in xrange(epochs): random.shuffle(training_data) mini_batches = [ training_data[k:k+mini_batch_size] for k in xrange(0, n, mini_batch_size)] for mini_batch in mini_batches: self.update_mini_batch(mini_batch, eta) if test_data: print "Epoch &#123;0&#125;: &#123;1&#125; / &#123;2&#125;".format( j, self.evaluate(test_data), n_test) else: print "Epoch &#123;0&#125; complete".format(j) training_data 是一个 (x, y) 元组的列表，表示训练输入和其对应的期望输出。变量 epochs 和 mini_batch_size 正如你预料的迭代期数量，和采样时的小批量数据的大小。eta 是学习率，$\eta$。如果给出了可选参数 test_data，那么程序会在每个训练器后评估网络，并打印出部分进展。这对于追踪进度很有用，但相当拖慢执行速度。 代码如下工作。在每个周期，它首先随机地将训练数据打乱，然后将它分成多个适当大小的小批量数据。这是一个简单的从训练数据的随机采样方法。然后对于每一个小批量数据我们应用一次梯度下降。这是通过代码 self.update_mini_batch(mini_batch, eta) 完成的，它仅仅使用 mini_batch 中的训练数据，根据单次梯度下降的迭代更新网络的权重和偏置。这是 update_mini_batch 方法的代码： 123456789101112131415def update_mini_batch(self, mini_batch, eta): """Update the network's weights and biases by applying gradient descent using backpropagation to a single mini batch. The "mini_batch" is a list of tuples "(x, y)", and "eta" is the learning rate.""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] for x, y in mini_batch: delta_nabla_b, delta_nabla_w = self.backprop(x, y) nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)] nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)] self.weights = [w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)] self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)] 大部分工作由这行代码完成： 1delta_nabla_b, delta_nabla_w = self.backprop(x, y) 这行调用了一个称为反向传播的算法，一种快速计算代价函数的梯度的方法。因此 update_mini_batch 的工作仅仅是对 mini_batch 中的每一个训练样本计算梯度，然后适当地更新 self.weights 和 self.biases。 我现在不会列出 self.backprop 的代码。我们将在下章中学习反向传播是怎样工作的，包括 self.backprop 的代码。现在，就假设它按照我们要求的工作，返回与训练样本 $x$ 相关代价的适当梯度。 Network.py 完整代码让我们看一下完整的程序，包括我之前忽略的文档注释。除了 self.backprop，程序已经有了足够的文档注释，所有的繁重工作由 self.SGD 和 self.update_mini_batch 完成，对此我们已经有讨论过。self.backprop 方法利用一些额外的函数来帮助计算梯度，即 sigmoid_prime，它计算 $\sigma$ 函数的导数，以及 self.cost_derivative，这里我不会对它过多描述。你能够通过查看代码或文档注释来获得这些的要点（或者细节）。我们将在下章详细地看它们。注意，虽然程序显得很长，但是很多代码是用来使代码更容易理解的文档注释。实际上，程序只包含 74 行非空、非注释的代码。所有的代码可以在 GitHub 上找到。 注意作者的代码是 Python2 版本的，下面替换成 Python3 版本的（仅仅针对不同 Python 版本语法进行了代码修改，原理没有任何修改）。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142"""network.py~~~~~~~~~~A module to implement the stochastic gradient descent learningalgorithm for a feedforward neural network. Gradients are calculatedusing backpropagation. Note that I have focused on making the codesimple, easily readable, and easily modifiable. It is not optimized,and omits many desirable features."""#### Libraries# Standard libraryimport random# Third-party librariesimport numpy as npclass Network(object): def __init__(self, sizes): """The list ``sizes`` contains the number of neurons in the respective layers of the network. For example, if the list was [2, 3, 1] then it would be a three-layer network, with the first layer containing 2 neurons, the second layer 3 neurons, and the third layer 1 neuron. The biases and weights for the network are initialized randomly, using a Gaussian distribution with mean 0, and variance 1. Note that the first layer is assumed to be an input layer, and by convention we won't set any biases for those neurons, since biases are only ever used in computing the outputs from later layers.""" self.num_layers = len(sizes) self.sizes = sizes self.biases = [np.random.randn(y, 1) for y in sizes[1:]] self.weights = [np.random.randn(y, x) for x, y in zip(sizes[:-1], sizes[1:])] def feedforward(self, a): """Return the output of the network if ``a`` is input.""" for b, w in zip(self.biases, self.weights): a = sigmoid(np.dot(w, a)+b) return a def SGD(self, training_data, epochs, mini_batch_size, eta, test_data=None): """Train the neural network using mini-batch stochastic gradient descent. The ``training_data`` is a list of tuples ``(x, y)`` representing the training inputs and the desired outputs. The other non-optional parameters are self-explanatory. If ``test_data`` is provided then the network will be evaluated against the test data after each epoch, and partial progress printed out. This is useful for tracking progress, but slows things down substantially.""" test_data = list(test_data) training_data = list(training_data) if test_data: n_test = len(test_data) n = len(training_data) for j in range(epochs): random.shuffle(training_data) mini_batches = [ training_data[k:k+mini_batch_size] for k in range(0, n, mini_batch_size)] for mini_batch in mini_batches: self.update_mini_batch(mini_batch, eta) if test_data: print("Epoch &#123;0&#125;: &#123;1&#125; / &#123;2&#125;".format( j, self.evaluate(test_data), n_test)) else: print("Epoch &#123;0&#125; complete".format(j)) def update_mini_batch(self, mini_batch, eta): """Update the network's weights and biases by applying gradient descent using backpropagation to a single mini batch. The ``mini_batch`` is a list of tuples ``(x, y)``, and ``eta`` is the learning rate.""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] for x, y in mini_batch: delta_nabla_b, delta_nabla_w = self.backprop(x, y) nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)] nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)] self.weights = [w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)] self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)] def backprop(self, x, y): """Return a tuple ``(nabla_b, nabla_w)`` representing the gradient for the cost function C_x. ``nabla_b`` and ``nabla_w`` are layer-by-layer lists of numpy arrays, similar to ``self.biases`` and ``self.weights``.""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] # feedforwar activation = x activations = [x] # list to store all the activations, layer by layer zs = [] # list to store all the z vectors, layer by layer for b, w in zip(self.biases, self.weights): z = np.dot(w, activation)+b zs.append(z) activation = sigmoid(z) activations.append(activation) # backward pass delta = self.cost_derivative(activations[-1], y) * \ sigmoid_prime(zs[-1]) nabla_b[-1] = delta nabla_w[-1] = np.dot(delta, activations[-2].transpose()) # Note that the variable l in the loop below is used a little # differently to the notation in Chapter 2 of the book. Here, # l = 1 means the last layer of neurons, l = 2 is the # second-last layer, and so on. It's a renumbering of the # scheme in the book, used here to take advantage of the fact # that Python can use negative indices in lists. for l in range(2, self.num_layers): z = zs[-l] sp = sigmoid_prime(z) delta = np.dot(self.weights[-l+1].transpose(), delta) * sp nabla_b[-l] = delta nabla_w[-l] = np.dot(delta, activations[-l-1].transpose()) return (nabla_b, nabla_w) def evaluate(self, test_data): """Return the number of test inputs for which the neural network outputs the correct result. Note that the neural network's output is assumed to be the index of whichever neuron in the final layer has the highest activation.""" test_results = [(np.argmax(self.feedforward(x)), y) for (x, y) in test_data] return sum(int(x == y) for (x, y) in test_results) def cost_derivative(self, output_activations, y): """Return the vector of partial derivatives \partial C_x / \partial a for the output activations.""" return (output_activations-y)#### Miscellaneous functionsdef sigmoid(z): """The sigmoid function.""" return 1.0/(1.0+np.exp(-z))def sigmoid_prime(z): """Derivative of the sigmoid function.""" return sigmoid(z)*(1-sigmoid(z)) 运行结果这个程序对识别手写数字效果如何？好吧，让我们先加载 MNIST 数据。我将用下面所描述的一小段辅助程序 mnist_loader.py 来完成。我们在一个 Python shell 中执行下面的命令， 123&gt;&gt;&gt; import mnist_loader&gt;&gt;&gt; training_data, validation_data, test_data = \... mnist_loader.load_data_wrapper() 在加载完 MNIST 数据之后，我们将设置一个有 30 个隐藏层神经元的 Network。我们在导入如上所列的名为 network 的 Python 程序后做， 12&gt;&gt;&gt; import network&gt;&gt;&gt; net = network.Network([784, 30, 10]) 最后，我们将使用随机梯度下降来从 MNIST training_data 学习超过 30 次 epoch，mini-batch 大小为 10，学习率 $\eta = 3.0$， 1&gt;&gt;&gt; net.SGD(training_data, 30, 10, 3.0, test_data=test_data) 打印内容显示了在每轮训练期后神经网络能正确识别测试图像的数量。正如你所见到，在仅仅一次 epoch后，达到了 10,000 中选中的 9,129 个。而且数目还在持续增长， 1234567Epoch 0: 9129 / 10000Epoch 1: 9295 / 10000Epoch 2: 9348 / 10000...Epoch 27: 9528 / 10000Epoch 28: 9542 / 10000Epoch 29: 9534 / 10000 更确切地说，经过训练的网络给出的识别率约为 95% 在峰值时为 95.42%（“Epoch 28”）作为第一次尝试，这是非常令人鼓舞的。然而我应该提醒你，如果你运行代码然后得到的结果和我的不完全一样，那是因为我们使用了（不同的）随机权重和偏置来初始化我们的网络。 让我们重新运行上面的实验，将隐藏神经元数量改到 100。 12&gt;&gt;&gt; net = network.Network([784, 100, 10])&gt;&gt;&gt; net.SGD(training_data, 30, 10, 3.0, test_data=test_data) 果然，它将结果提升至 96.59%。至少在这种情况下，使用更多的隐藏神经元帮助我们得到了更好的结果。（注意，有的反馈表明本实验在结果上有相当多的变化，而且一些训练运行给出的结果相当糟糕。使用第三章所介绍的技术将大大减少我们网络上这些不同训练运行性能的差别。） 当然，为了获得这些准确性，我不得不对训练的迭代期数量，mini-batch 大小和学习率 $\eta$ 做特别的选择。正如我上面所提到的，这些在我们的神经网络中被称为超参数，以区别于通过我们的学习算法所学到的参数权重和偏置。如果我们选择了糟糕的超参数，我们会得到较差的结果。假如我们定 学习率 为 $\eta = 0.001$, 结果则不太令人鼓舞了， 1234567Epoch 0: 1139 / 10000Epoch 1: 1136 / 10000Epoch 2: 1135 / 10000...Epoch 27: 2101 / 10000Epoch 28: 2123 / 10000Epoch 29: 2142 / 10000 然而，你可以看到网络的性能随着时间的推移慢慢地变好了。这表明应该增大 学习率，例如 $\eta = 0.01$。如果我们那样做了，我们会得到更好的结果，这表明我们应该再次增加学习率。（如果改变能够改善一些事情，试着做更多！）如果我们这样做几次，我们最终会得到一个像 $\eta = 1.0$ 的 学习率（或者调整到$3.0$），这跟我们之前的实验很接近。因此即使我们最初选择了糟糕的超参数，我们至少获得了足够的信息来帮助我们改善对于超参数的选择。通常，调试一个神经网络是具有挑战性的。 从这得到的教训是调试一个神经网络不是琐碎的，就像常规编程那样，它是一门艺术。你需要学习调试的艺术来获得神经网络更好的结果。更普通的是，我们需要启发式方法来选择好的超参数和好的结构。我们将在整本书中讨论这些，包括上面我是怎么样选择超参数的。 补充：加载训练数据的代码前文中，我跳过了如何加载 MNIST 数据的细节。这很简单。这里列出了完整的代码。用于存储 MNIST 数据的数据结构在文档注释中有详细描述，都是简单的类型，元组和 Numpy ndarry 对象的列表（如果你不熟悉 ndarray，那就把它们看成向量）： 原来的 mnist_loader 代码 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677"""mnist_loader~~~~~~~~~~~~A library to load the MNIST image data. For details of the datastructures that are returned, see the doc strings for ``load_data``and ``load_data_wrapper``. In practice, ``load_data_wrapper`` is thefunction usually called by our neural network code."""#### Libraries# Standard libraryimport pickleimport gzip# Third-party librariesimport numpy as npdef load_data(): """Return the MNIST data as a tuple containing the training data, the validation data, and the test data. The ``training_data`` is returned as a tuple with two entries. The first entry contains the actual training images. This is a numpy ndarray with 50,000 entries. Each entry is, in turn, a numpy ndarray with 784 values, representing the 28 * 28 = 784 pixels in a single MNIST image. The second entry in the ``training_data`` tuple is a numpy ndarray containing 50,000 entries. Those entries are just the digit values (0...9) for the corresponding images contained in the first entry of the tuple. The ``validation_data`` and ``test_data`` are similar, except each contains only 10,000 images. This is a nice data format, but for use in neural networks it's helpful to modify the format of the ``training_data`` a little. That's done in the wrapper function ``load_data_wrapper()``, see below. """ f = gzip.open('../data/mnist.pkl.gz', 'rb') training_data, validation_data, test_data = pickle.load(f, encoding='bytes') f.close() return (training_data, validation_data, test_data)def load_data_wrapper(): """Return a tuple containing ``(training_data, validation_data, test_data)``. Based on ``load_data``, but the format is more convenient for use in our implementation of neural networks. In particular, ``training_data`` is a list containing 50,000 2-tuples ``(x, y)``. ``x`` is a 784-dimensional numpy.ndarray containing the input image. ``y`` is a 10-dimensional numpy.ndarray representing the unit vector corresponding to the correct digit for ``x``. ``validation_data`` and ``test_data`` are lists containing 10,000 2-tuples ``(x, y)``. In each case, ``x`` is a 784-dimensional numpy.ndarry containing the input image, and ``y`` is the corresponding classification, i.e., the digit values (integers) corresponding to ``x``. Obviously, this means we're using slightly different formats for the training data and the validation / test data. These formats turn out to be the most convenient for use in our neural network code.""" tr_d, va_d, te_d = load_data() training_inputs = [np.reshape(x, (784, 1)) for x in tr_d[0]] training_results = [vectorized_result(y) for y in tr_d[1]] training_data = list(zip(training_inputs, training_results)) validation_inputs = [np.reshape(x, (784, 1)) for x in va_d[0]] validation_data = list(zip(validation_inputs, va_d[1])) test_inputs = [np.reshape(x, (784, 1)) for x in te_d[0]] test_data = list(zip(test_inputs, te_d[1])) return (training_data, validation_data, test_data)def vectorized_result(j): """Return a 10-dimensional unit vector with a 1.0 in the jth position and zeroes elsewhere. This is used to convert a digit (0...9) into a corresponding desired output from the neural network.""" e = np.zeros((10, 1)) e[j] = 1.0 return e 怎么做到识别手写数字的？ 迈向深度学习虽然我们的神经网络给出了令人印象深刻的表现，但这样的表现带有几分神秘。网络中的权重和偏置是被自动发现的。这意味着我们不能立即解释网络怎么做的、做了什么。我们能否找到一些方法来理解我们的网络通过什么原理分类手写数字？并且，在知道了这些原理后，我们能做得更好吗？ 为了让这些问题更具体，我们假设数十年后神经网络引发了人工智能（AI）。到那个时候，我们能明白这种智能网络的工作机制吗？或许，因为有着自动学习得到的权重和偏置，这些是我们无法理解的，这样的神经网络对我们来说是不透明的。在人工智能的早期研究阶段，人们希望在构建人工智能的努力过程中，也同时能够帮助我们理解智能背后的机制，以及人类大脑的运转方式。但结果可能是我们既不能够理解大脑的机制，也不能够理解人工智能的机制。 为解决这些问题，让我们重新思考一下我在本章开始时所给的人工神经元的解释，作为一种衡量证据的方法。假设我们要确定一幅图像是否显示有人脸： 我们可以用解决手写识别问题的相同方式来攻克这个问题。网络的输入是图像中的像素，网络的输出是一个单个的神经元用于表明“是的，这是一张脸”或“不，这不是一张脸”。 假设我们就采取了这个方法，但接下来我们先不去使用一个学习算法。而是去尝试亲手设计一个网络，并为它选择合适的权重和偏置。我们要怎样做呢？暂时先忘掉神经网络，我们受到启发的一个想法是将这个问题分解成子问题：图像的左上角有一个眼睛吗？右上角有一个眼睛吗？中间有一个鼻子吗？下面中央有一个嘴吗？上面有头发吗？诸如此类。 如果一些问题的回答是“是”，或者甚至仅仅是“可能是”，那么我们可以作出结论这个图像可能是一张脸。相反地，如果大多数这些问题的答案是“不是”，那么这张图像可能不是一张脸。 当然，这仅仅是一个粗略的想法，而且它存在许多缺陷。也许有个人是秃头，没有头发。也许我们仅仅能看到脸的部分，或者这张脸是有角度的，因此一些面部特征是模糊的。不过这个想法表明了如果我们能够使用神经网络来解决这些子问题，那么我们也许可以通过将这些解决子问题的网络结合起来，构成一个人脸检测的神经网络。下图是一个可能的结构，其中的方框表示子网络。注意，这不是一个人脸检测问题的现实的解决方法，而是为了帮助我们构建起网络如何运转的直观感受。下图是这个网络的结构： 子网络也可以被继续分解，这看上去很合理。假设我们考虑这个问题：“左上角有一个眼睛吗？”。 这个问题可以被分解成这些子问题：“有一个眉毛吗？”，“有睫毛吗？”，“有虹膜吗？”，等等。当然这些问题也应该包含关于位置的信息，诸如“在左上角有眉毛，上面有虹膜吗？”，但是让我们先保持简单。回答问题“左上角有一个眼睛吗？”的网络能够被分解成： 这些子问题也同样可以继续被分解，并通过多个网络层传递得越来越远。最终，我们的子网络可以回答那些只包含若干个像素点的简单问题。举例来说，这些简单的问题可能是询问图像中的几个像素是否构成非常简单的形状。这些问题就可以被那些与图像中原始像素点相连的单个神经元所回答。 最终的结果是，我们设计出了一个网络，它将一个非常复杂的问题，这张图像是否有一张人脸，分解成在单像素层面上就可回答的非常简单的问题。它通过一系列多层结构来完成，在前面的网络层，它回答关于输入图像非常简单明确的问题，在后面的网络层，它建立了一个更加复杂和抽象的层级结构。包含这种多层结构，两层或更多隐藏层的网络被称为深度神经网络。 当然，我没有提到如何去递归地分解成子网络。手工设计网络中的权重和偏置无疑是不切实际的。取而代之的是，我们希望使用学习算法来让网络能够自动从训练数据中学习权重和偏置。这样，形成一个概念的层次结构。80年代和 90年代的研究人员尝试了使用随机梯度下降和反向传播来训练深度网络。不幸的是，除了一些特殊的结构，他们并没有取得很好的效果。虽然网络能够学习，但是学习速度非常缓慢，不适合在实际中使用。 自 2006 年以来，人们已经开发了一系列技术使深度神经网络能够学习。这些深度学习技术基于随机梯度下降和反向传播，并引进了新的想法。这些技术已经使更深（更大）的网络能够被训练~——~现在训练一个有 5 到 10 层隐藏层的网络都是很常见的。而且事实证明，在许多问题上，它们比那些浅层神经网络，例如仅有一个隐藏层的网络，表现的更加出色。当然，原因是深度网络能够构建起一个复杂的概念的层次结构。这有点像传统编程语言使用模块化的设计和抽象的思想来创建复杂的计算机程序。将深度网络与浅层网络进行对比，有点像将一个能够进行函数调用的程序语言与一个不能进行函数调用的精简语言进行对比。抽象在神经网络中的形式和传统的编程方式相比不同，但它同样重要。 参考文献[1] Michael Nielsen. CHAPTER 1 Using neural nets to recognize handwritten digits[DB/OL]. http://neuralnetworksanddeeplearning.com/chap1.html, 2018-06-19. [2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL]. https://github.com/zhanggyb/nndl/blob/master/chap1.tex, 2018-06-19. [3] skylook. neural-networks-and-deep-learning, mnist_loader.py[DB/OL]. https://github.com/skylook/neural-networks-and-deep-learning/blob/master/src/mnist_loader.py, 2018-06-19. [4] skylook. neural-networks-and-deep-learning, network.py[DB/OL]. https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/src/network.py, 2018-06-19.]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>手写数字识别</tag>
        <tag>代码实现</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[使用神经网络识别手写数字——梯度下降算法]]></title>
    <url>%2F2018%2F06%2F18%2F%E4%BD%BF%E7%94%A8%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E8%AF%86%E5%88%AB%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97%E2%80%94%E2%80%94%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E7%AE%97%E6%B3%95%2F</url>
    <content type="text"><![CDATA[原文链接：CHAPTER 1 Using neural nets to recognize handwritten digits 神经网络的架构假设我们有这样的网络：前面提过，这个网络中最左边的称为输入层，其中的神经元称为输入神经元。最右边的，即输出层包含有输出神经元，在本例中，输出层只有一个神经元。中间层，既然这层中的神经元既不是输入也不是输出，则被称为隐藏层。“隐藏”这一术语也许听上去有些神秘，我第一次听到这个词，以为它必然有一些深层的哲学或数学涵意，但它实际上仅仅意味着“既非输入也非输出”。上面的网络仅有一个隐藏层，但有些网络有多个隐藏层。例如，下面的四层网络有两个隐藏层： 有些令人困惑的是，由于历史的原因，尽管是由 S 型神经元而不是感知器构成，这种多层网络有时被称为多层感知器或者 MLP。 在这本书中我不会使用 MLP 这个术语，因为我认为这会引起混淆，但这里想提醒你它的存在。 目前为止，我们讨论的神经网络，都是以上一层的输出作为下一层的输入。这种网络被称为前馈神经网络。这意味着网络中是没有回路的，信息总是向前传播，从不反向回馈。如果确实有回路，我们最终会有这样的情况：$\sigma$ 函数的输入依赖于输出。这将难于理解，所以我们不允许这样的环路。 然而，也有一些人工神经网络的模型，其中反馈环路是可行的。它们原理上比前馈网络更接近我们大脑的实际工作。并且循环网络能解决一些重要的问题，这些问题如果仅仅用前馈网络来解决，则更加困难。然而为了篇幅，本书将专注于使用更广泛的前馈网络。 一个简单的分类手写数字的网络我们将使用一个三层神经网络来识别单个数字： 网络的输入层包含给输入像素的值进行编码的神经元。就像下一节会讨论的，我们给网络的训练数据会有很多扫描得到的 $28 \times 28$ 的手写数字的图像组成，所有输入层包含有 $784 = 28 \times 28$ 个神经元。为了简化，上图中我已经忽略了 $784$ 中大部分的输入神经元。输入像素是灰度级的，值为 $0.0$ 表示白色，值为 $1.0$ 表示黑色，中间数值表示逐渐暗淡的灰色。 网络的第二层是一个隐藏层。我们用 $n$ 来表示神经元的数量，我们将给 $n$ 实验不同的数值。示例中用一个小的隐藏层来说明，仅仅包含 $n=15$ 个神经元。 网络的输出层包含有 $10$ 个神经元。如果第一个神经元激活，即输出 $\approx 1$，那么表明网络认为数字是一个 $0$。如果第二个神经元激活，就表明网络认为数字是一个 $1$。依此类推。更确切地说，我们把输出神经元的输出赋予编号 $0$ 到 $9$，并计算出那个神经元有最高的激活值。比如，如果编号为 $6$ 的神经元激活，那么我们的网络会猜到输入的数字是 $6$。其它神经元相同。 为什么用 10 个输出神经元你可能会好奇为什么我们用 $10$ 个输出神经元。毕竟我们的任务是能让神经网络告诉我们哪个数字（ $0, 1, 2, \ldots, 9$ ）能和输入图片匹配。一个看起来更自然的方式就是使用 $4$ 个输出神经元，把每一个当做一个二进制值，结果取决于它的输出更靠近 $0$ 还是$1$。四个神经元足够编码这个问题了，因为 $2^4 = 16$ 大于 $10$ 种可能的输入。为什么我们反而要用 $10$ 个神经元呢？这样做难道效率不低吗？ 最终的判断是基于经验主义的：我们可以实验两种不同的网络设计，结果证明对于这个特定的问题而言，$10$ 个输出神经元的神经网络比4个的识别效果更好。但是令我们好奇的是为什么使用 $10$ 个输出神经元的神经网络更有效呢。 有没有什么启发性的方法能提前告诉我们用10个输出编码比使用 $4$个输出编码更有好呢？ 为了理解为什么我们这么做，我们需要从根本原理上理解神经网络究竟在做些什么。首先考虑有 $10$ 个神经元的情况。我们首先考虑第一个输出神经元，它告诉我们一个数字是不是0。它能那么做是因为可以权衡从隐藏层来的信息。隐藏层的神经元在做什么呢？假设隐藏层的第一个神经元只是用于检测如下的图像是否存在： 为了达到这个目的，它通过对此图像对应部分的像素赋予较大权重，对其它部分赋予较小的权重。同理，我们可以假设隐藏层的第二，第三，第四个神经元是为检测下列图片是否存在： 就像你能猜到的，这四幅图像组合在一起构成了前面显示的一行数字图像中的 $0$： 假设神经网络以上述方式运行，我们可以给出一个貌似合理的理由去解释为什么用 $10$ 个输出而不是 $4$ 个。如果我们有 $4$ 个输出，那么第一个输出神经元将会尽力去判断数字的最高有效位是什么。 把数字的最高有效位和数字的形状联系起来并不是一个简单的问题。很难想象出有什么恰当的历史原因，一个数字的形状要素会和一个数字的最高有效位有什么紧密联系。 上面我们说的只是一个启发性的方法。没有什么理由表明这个三层的神经网络必须按照我所描述的方式运行，即隐藏层是用来探测数字的组成形状。可能一个聪明的学习算法将会找到一些合适的权重能让我们仅仅用4个输出神经元就行。但是这个启发性的方法通常很有效，它会节省你大量时间去设计一个好的神经网络结构。 使用梯度下降算法进行学习现在我们有了神经网络的设计，它怎样可以学习识别数字呢？我们需要的第一样东西是一个用来学习的数据集称为训练数据集。我们将使用 MNIST 数据集。 我们将用符号 $x$ 来表示一个训练输入。为了方便，把每个训练输入 $x$ 看作一个 $28\times 28 = 784$ 维的向量。每个向量中的项目代表图像中单个像素的灰度值。我们用 $y= y(x)$ 表示对应的期望输出，这里 $y$ 是一个 $10$ 维的向量。例如，如果有一个特定的画成 $6$ 的训练图像，$x$ ，那么 $y(x) = (0, 0, 0, 0, 0, 0, 1, 0, 0, 0)^T$ 则是网络的期望输出。注意这里 $T$ 是转置操作，把一个行向量转换成一个列向量。 二次代价函数我们希望有一个算法，能让我们找到权重和偏置，以至于网络的输出$y(x)$ 能够拟合所有的训练输入$x$。为了量化我们如何实现这个目标，我们定义一个代价函数（有时被称为损失或目标函数。我们在这本书中可能会交换使用这几个术语）： C(w,b) \equiv \frac{1}{2n} \sum_x \| y(x) - a\|^2这里 $w$ 表示所有的网络中权重的集合，$b$ 是所有的偏置，$n$ 是训练输入数据的个数，$a$ 是表示当输入为 $x$ 时输出的向量，求和则是在总的训练输入$x$ 上进行的。当然，输出 $a$ 取决于 $x$, $w$ 和 $b$，但是为了保持符号的简洁性，我没有明确地指出这种依赖关系。符号 $|v|$ 是指向量 $v$ 的模。我们把 $C$ 称为二次代价函数；有时也被称为均方误差或者 MSE。观察二次代价函数的形式我们可以看到 $C(w,b)$ 是非负的，因为求和公式中的每一项都是非负的。此外，代价函数$C(w,b)$ 的值相当小，即 $C(w,b) \approx 0$，精确地说，是当对于所有的训练输入 $x$，$y(x)$ 接近于输出 $a$ 时。因此如果我们的学习算法能找到合适的权重和偏置，使得 $C(w,b) \approx 0$，它就能很好地工作。相反，当 $C(w,b)$ 很大时就不怎么好了，那意味着对于大量地输入， $y(x)$ 与输出 $a$ 相差很大。因此我们的训练算法的目的，是最小化权重和偏置的代价函数 $C(w,b)$。换句话说，我们想要找到一系列能让代价尽可能小的权重和偏置。我们将采用称为梯度下降的算法来达到这个目的。 为什么使用二次代价函数为什么要介绍二次代价呢？毕竟我们最初感兴趣的内容不是能正确分类的图像数量吗？为什么不试着直接最大化这个数量，而是去最小化一个类似二次代价的间接评量呢？这么做是因为在神经网络中，被正确分类的图像数量所关于权重和偏置的函数并不是一个平滑的函数。 大多数情况下，对权重和偏置做出的微小变动完全不会影响被正确分类的图像的数量。这会导致我们很难去解决如何改变权重和偏置来取得改进的性能。而用一个类似二次代价的平滑代价函数则能更好地去解决如何用权重和偏置中的微小的改变来取得更好的效果。 这就是为什么我们首先专注于最小化二次代价，只有这样，我们之后才能测试分类精度。 即使已经知道我们需要使用一个平滑的代价函数，你可能仍然想知道为什么我们选择二次函数。这是临时想出来的吗？是不是我们选择另一个不同的代价函数将会得到完全不同的最小化的权重和偏置呢？这种顾虑是合理的，我们后面会再次回到这个代价函数，并做一些修改。尽管如此，二次代价函数让我们更好地理解神经网络中学习算法的基础，所以目前我们会一直使用它。 重复一下，我们训练神经网络的目的是找到能最小化二次代价函数 $C(w,b)$ 的权重和偏置。这是一个适定问题，但是现在它有很多让我们分散精力的结构，对权重 $w$ 和偏置 $b$的解释，晦涩不清的 $\sigma$ 函数，神经网络结构的选择，MNIST 等等。事实证明我们可以忽略结构中大部分，把精力集中在最小化方面来理解它。现在我们打算忘掉所有关于代价函数的具体形式、神经网络的连接等等。现在让我们想象只要最小化一个给定的多元函数。我们打算使用一种被称为梯度下降的技术来解决这样的最小化问题。然后我们回到在神经网络中要最小化的特定函数上来。 梯度下降算法好了，假设我们要最小化某些函数，$C(v)$。它可以是任意的多元实值函数，$v = v_1,v_2, \ldots$。注意我们用 $v$ 代替了 $w$ 和 $b$ 以强调它可能是任意的函数，我们现在先不局限于神经网络的环境。为了最小化 $C(v)$，想象 $C$ 是一个只有两个变量$v1$ 和 $v2$ 的函数： 为什么要使用梯度下降算法一种解决这个问题的方式是用微积分来解析最小值。我们可以计算导数去寻找 $C$ 的极值点。运气好的话，$C$ 是一个只有一个或少数几个变量的函数。但是变量过多的话那就是噩梦。而且神经网络中我们经常需要大量的变量——最大的神经网络有依赖数亿权重和偏置的代价函数，极其复杂。用微积分来计算最小值已经不可行了。 好吧，微积分是不能用了。幸运的是，有一个漂亮的推导法暗示有一种算法能得到很好的效果。首先把我们的函数想象成一个山谷。只要瞄一眼上面的绘图就不难理解。我们想象有一个小球从山谷的斜坡滚落下来。我们的日常经验告诉我们这个球最终会滚到谷底。也许我们可以用这一想法来找到函数的最小值？我们会为一个（假想的）球体随机选择一个起始位置，然后模拟球体滚落到谷底的运动。我们可以通过计算 $C$ 的导数（或者二阶导数）来简单模拟——这些导数会告诉我们山谷中局部“形状”的一切，由此知道我们的球将怎样滚动。 注意小球不必遵常规的循物理学理论，我们在这里就是上帝，能够支配球体可以如何滚动，那么我们将会采取什么样的运动学定律来让球体能够总是滚落到谷底呢？我们让小球要往代价函数梯度的反方向滚动。 为什么小球要往梯度的反方向滚动为了更精确地描述这个问题，让我们思考一下，当我们在 $v1$ 和 $v2$ 方向分别将球体移动一个很小的量，即 $\Delta v1$ 和 $\Delta v2$ 时，球体将会发生什么情况。微积分告诉我们 $C$ 将会有如下变化： \Delta C \approx \frac{\partial C}{\partial v_1} \Delta v_1 + \frac{\partial C}{\partial v_2} \Delta v_2我们要寻找一种选择 $\Delta v_1$ 和 $\Delta v_2$ 的方法使得 $\Delta C$ 为负；即，我们选择它们是为了让球体滚落。为了弄明白如何选择，需要定义 $\Delta v$ 为 $v$ 变化的向量，$\Delta v \equiv (\Delta v_1, \Delta v_2)^T$，$T$ 是转置符号。我们也定义 $C$ 的梯度为偏导数的向量，$\left(\frac{\partial C}{\partial v_1},\frac{\partial C}{\partial v_2}\right)^T$。我们用 $\nabla C$ 来表示梯度向量，即： \nabla C \equiv \left( \frac{\partial C}{\partial v_1}, \frac{\partial C}{\partial v_2} \right)^T有了这些定义，$\Delta C$ 的表达式可以被重写为： \Delta C \approx \nabla C \cdot \Delta v这个表达式解释了为什么 $\nabla C$ 被称为梯度向量：$\nabla C$ 把 $v$ 的变化关联为 $C$ 的变化，正如我们期望的用梯度来表示。但是这个方程真正让我们兴奋的是它让我们看到了如何选取 $\Delta v$ 才能让 $\Delta C$ 为负数。假设我们选取： \Delta v = -\eta \nabla C这里的 $\eta$ 是个很小的正数（称为学习率）。方程$\Delta v = -\eta \nabla C$告诉我们 $\Delta C \approx -\eta \nabla C \cdot \nabla C = -\eta |\nabla C|^2$。由于 $| \nabla C |^2 \geq 0$，这保证了$\Delta C \leq 0$，即，如果我们按照方程$\Delta v = -\eta \nabla C$的规则去改变 $v$，那么 $C$ 会一直减小，不会增加。（当然，要在方程$\Delta C \approx \nabla C \cdot \Delta v$的近似约束下）。这正是我们想要的特性！因此我们把方程$\Delta v = -\eta \nabla C$ 用于定义球体在梯度下降算法下的“运动定律”。也就是说，我们用方程$\Delta v = -\eta \nabla C$计算 $\Delta v$，来移动球体的位置 $v$： v \rightarrow v' = v -\eta \nabla C然后我们用它再次更新规则来计算下一次移动。如果我们反复持续这样做，我们将持续减小$C$ 直到,正如我们希望的,获得一个全局的最小值。 总结一下，梯度下降算法工作的方式就是重复计算梯度 $\nabla C$，然后沿着相反的方向移动，沿着山谷“滚落”。我们可以想象它像这样： 注意具有这一规则的梯度下降并不是模仿实际的物理运动。在现实中一个球体有动量，使得它岔开斜坡滚动，甚至（短暂地）往山上滚。只有在克服摩擦力的影响，球体才能保证滚到山谷。相比之下，我们选择 $\Delta v$ 规则只是说：“往下，现在”。这仍然是一个寻找最小值的非常好的规则！ 为了使梯度下降能够正确地运行，我们需要选择足够小的学习率 $\eta$ 使得方程$\Delta C \approx \nabla C \cdot \Delta v$ 能得到很好的近似。如果不这样，我们会以 $\Delta C &gt; 0$ 结束，这显然不好。同时，我们也不想 $\eta$ 太小，因为这会使 $\Delta v$ 的变化极小，梯度下降算法就会运行得非常缓慢。在真正的实现中，$\eta$ 通常是变化的，以至方程$\Delta C \approx \nabla C \cdot \Delta v$能保持很好的近似度，但算法又不会太慢。我们后面会看这是如何工作的。 梯度下降算法的形式化证明我已经解释了具有两个变量的函数 $C$ 的梯度下降。但事实上，即使 $C$ 是一个具有更多变量的函数也能很好地工作。我们假设 $C$ 是一个有 $m$ 个变量 $v_1,\ldots,v_m$ 的多元函数。那么对 $C$ 中自变量的变化 $\Delta v = (\Delta v_1, \ldots, \Delta v_m)^T$，$\Delta C$ 将会变为： \Delta C \approx \nabla C \cdot \Delta v这里的梯度 $\nabla C$ 是向量 \nabla C \equiv \left(\frac{\partial C}{\partial v_1}, \ldots, \frac{\partial C}{\partial v_m}\right)^T正如两个变量的情况，我们可以选取 \Delta v = -\eta \nabla C而且 $\Delta C$ 的（近似）表达式 $\Delta C \approx \nabla C \cdot \Delta v$ 保证是负数。这给了我们一种方式从梯度中去取得最小值，即使 $C$ 是任意的多元函数，我们也能重复运用更新规则 v \rightarrow v' = v-\eta \nabla C你可以把这个更新规则看做定义梯度下降算法。这给我们提供了一种方式去通过重复改变 $v$ 来找到函数 $C$ 的最小值。这个规则并不总是有效的，有几件事能导致错误，让我们无法从梯度下降来求得函数 $C$ 的全局最小值，这个观点我们会在后面的章节中去探讨。但在实践中，梯度下降算法通常工作地非常好，在神经网络中这是一种非常有效的方式去求代价函数的最小值，进而促进网络自身的学习。 事实上，甚至有一种观点认为梯度下降法是求最小值的最优策略。假设我们正在努力去改变 $\Delta v$ 来让 $C$ 尽可能地减小。这相当于最小化 $\Delta C \approx \nabla C \cdot \Delta v$。我们首先限制步长为小的固定值，即 $| \Delta v | = \epsilon$，$ \epsilon &gt; 0$。当步长固定时，我们要找到使得 $C$ 减小最大的下降方向。可以证明，使得 $\nabla C \cdot \Delta v$ 取得最小值的 $\Delta v$ 为 $\Delta v = - \eta \nabla C$，这里 $\eta = \epsilon / |\nabla C|$ 是由步长限制 $|\Delta v| = \epsilon$ 所决定的。因此，梯度下降法可以被视为一种在 $C$ 下降最快的方向上做微小变化的方法。 人们已经研究出很多梯度下降的变化形式，包括一些更接近真实模拟球体物理运动的变化形式。这些模拟球体的变化形式有很多优点，但是也有一个主要的缺点：它最终必需去计算$C$ 的二阶偏导，这代价可是非常大的。 为了理解为什么这种做法代价高，假设我们想求所有的二阶偏导 $\partial^2 C/ \partial v_j \partial v_k$。如果我们有上百万的变量$v_j$，那我们必须要计算数万亿（即百万次的平方）级别的二阶偏导（实际上，更接近万亿次的一半，因为$\partial^2 C/ \partial v_j \partial v_k = \partial^2 C/ \partial v_k \partial v_j$。同样，你知道怎么做。！）这会造成很大的计算代价。不过也有一些避免这类问题的技巧，寻找梯度下降算法的替代品也是个很活跃的研究领域。但在这本书中我们将主要用梯度下降算法（包括变化形式）使神经网络学习。 随机梯度下降算法神经网络中如何使用梯度下降算法我们怎么在神经网络中用梯度下降算法去学习呢？其思想就是利用梯度下降算法去寻找能使得方程代价函数取得最小值的权重 $w_k$ 和偏置 $b_l$。为了清楚这是如何工作的，我们将用权重和偏置代替变量 $v_j$。也就是说，现在“位置”变量有两个分量组成：$w_k$ 和 $b_l$，而梯度向量 $\nabla C$ 则有相应的分量 $\partial C / \partial w_k$和$\partial C / \partial b_l$。用这些分量来写梯度下降的更新规则，我们得到： w_k \rightarrow w_k' = w_k-\eta \frac{\partial C}{\partial w_k}b_l \rightarrow b_l' = b_l-\eta \frac{\partial C}{\partial b_l}通过重复应用这一更新规则我们就能“让球体滚下山”，并且有望能找到代价函数的最小值。换句话说，这是一个能让神经网络学习的规则。 为什么使用随机梯度下降算法应用梯度下降规则有很多挑战。我们将在下一章深入讨论。但是现在只提及一个问题。为了理解问题是什么，我们先回顾 $C(w,b) \equiv \frac{1}{2n} \sum_x | y(x) - a|^2$ 中的二次代价函数。注意这个代价函数有着这样的形式 $C = \frac{1}{n} \sum_x C_x$，即，它是遍及每个训练样本代价 $C_x \equiv \frac{|y(x)-a|^2}{2}$ 的平均值。在实践中，为了计算梯度 $\nabla C$，我们需要为每个训练输入 $x$ 单独地计算梯度值 $\nabla C_x$，然后求平均值，$\nabla C = \frac{1}{n} \sum_x \nabla C_x$。不幸的是，当训练输入的数量过大时会花费很长时间，这样会使学习变得相当缓慢。 有种叫做随机梯度下降的算法能够加速学习。其思想就是通过随机选取小量训练输入样本来计算 $\nabla C_x$，进而估算梯度 $\nabla C$。通过计算少量样本的平均值我们可以快速得到一个对于实际梯度 $\nabla C$ 的很好的估算，这有助于加速梯度下降，进而加速学习过程。 怎么使用随机梯度下降算法准确地说，随机梯度下降通过随机选取小量的 $m$ 个训练输入来工作。我们将这些随机的训练输入标记为$X_1, X_2, \ldots, X_m$，并把它们称为一个小批次。假设样本数量 $m$ 足够大，我们期望 $\nabla C_{X_j}$ 的平均值大致相等于整个 $\nabla C_x$的平均值，即， \frac{\sum_{j=1}^m \nabla C_{X_{j}}}{m} \approx \frac{\sum_x \nabla C_x}{n} = \nabla C这里的第二个求和符号是在整个训练数据上进行的。交换两边我们得到 \nabla C \approx \frac{1}{m} \sum_{j=1}^m \nabla C_{X_{j}}证实了我们可以通过仅仅计算随机选取的小批量数据的梯度来估算整体的梯度。 为了将其明确地和神经网络的学习联系起来，假设 $w_k$ 和 $b_l$ 表示我们神经网络中权重和偏置。随机梯度下降通过随机地选取并训练输入的小批量数据来工作， w_k \rightarrow w_k' = w_k-\frac{\eta}{m}\sum_j \frac{\partial C_{X_j}}{\partial w_k}b_l \rightarrow b_l' = b_l-\frac{\eta}{m}\sum_j \frac{\partial C_{X_j}}{\partial b_l}其中两个求和符号是在当前小批量数据中的所有训练样本 $X_j$ 上进行的。然后我们再挑选另一随机选定的小批量数据去训练。直到我们用完了所有的训练输入，这被称为完成了一个训练周期。然后我们就会开始一个新的训练周期。 另外值得提一下，对于改变代价函数大小的参数，和用于计算权重和偏置 的小批量数据的更新规则，会有不同的约定。在方程$C(w,b) \equiv \frac{1}{2n} \sum_x | y(x) - a|^2$ 中，我们通过因子 $\frac{1}{n}$ 来改变整个代价函数的大小。人们有时候忽略 $\frac{1}{n}$，直接取单个训练样本的代价总和，而不是取平均值。这对我们不能提前知道训练数据数量的情况下特别有效。例如，这可能发生在有更多的训练数据是实时产生的情况下。同样，小批量数据的更新规则有时也会舍弃前面的 $\frac{1}{m}$。从概念上这会有一点区别，因为它等价于改变了学习率 $\eta$ 的大小。但在对不同工作进行详细对比时，需要对它警惕。 随机梯度下降算法与梯度下降算法比较我们可以把随机梯度下降想象成一次民意调查：在一个小批量数据上采样比对一个完整数据集进行梯度下降分析要容易得多，正如进行一次民意调查比举行一次全民选举要更容易。例如，如果我们有一个规模为 $n = 60,000$ 的训练集，就像 MNIST，并选取 小批量数据大小为 $m = 10$，这意味着在估算梯度过程中加速了 $6,000$ 倍！当然，这个估算并不是完美的，存在统计波动，但是没必要完美：我们实际关心的是在某个方向上移动来减少 $C$，而这意味着我们不需要梯度的精确计算。在实践中，随机梯度下降是在神经网络的学习中被广泛使用、十分有效的技术，它也是本书中展开的大多数学习技术的基础。 梯度下降算法一个极端的版本是把小批量数据的大小设为 $1$。即，假设一个训练输入 $x$，我们按照规则 $w_k \rightarrow w_k’ = w_k - \eta \partial C_x / \partial w_k$ 和 $b_l \rightarrow b_l’ = b_l - \eta \partial C_x / \partialb_l$ 更新我们的权重和偏置。然后我们选取另一个训练输入，再一次更新权重和偏置。如此重复。这个过程被称为在线、online、on-line、或者递增学习。在 online 学习中，神经网络在一个时刻只学习一个训练输入（正如人类做的）。 理解梯度和导数CSDN ： [机器学习] ML重要概念：梯度（Gradient）与梯度下降法（Gradient Descent） 知乎 ： 如何直观形象的理解方向导数与梯度以及它们之间的关系？ 知乎 ： 什么是全导数？ 拓展阅读全局最优解？为什么 SGD 能令神经网络的损失降到零 参考文献[1] Michael Nielsen. CHAPTER 1 Using neural nets to recognize handwritten digits[DB/OL]. http://neuralnetworksanddeeplearning.com/chap1.html, 2018-06-18. [2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL]. https://github.com/zhanggyb/nndl/blob/master/chap1.tex, 2018-06-18.]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>神经网络架构</tag>
        <tag>二次代价函数</tag>
        <tag>梯度下降算法</tag>
        <tag>随机梯度下降算法</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[使用神经网络识别手写数字——感知器]]></title>
    <url>%2F2018%2F06%2F17%2F%E4%BD%BF%E7%94%A8%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E8%AF%86%E5%88%AB%E6%89%8B%E5%86%99%E6%95%B0%E5%AD%97%E2%80%94%E2%80%94%E6%84%9F%E7%9F%A5%E5%99%A8%2F</url>
    <content type="text"><![CDATA[原文链接：CHAPTER 1 Using neural nets to recognize handwritten digits 本书序言在传统的编程方法中，我们告诉计算机做什么，把大问题分成许多小的、精确定义的任务，计算机可以很容易地执行。相比之下，在神经网络中，我们不告诉计算机如何解决我们的问题。相反，它从观测数据中学习，找出它自己的解决问题的方法。 一个以原理为导向的方法本书一个坚定的信念，是让读者更好地去深刻理解神经网络和深度学习，而不是像一张冗长的洗衣单一样模糊地列出一堆想法。如果你很好理解了核心理念，你就可以很快地理解其他新的推论。用编程语言对比，把这理解为掌握一种新语言的核心语法、库和数据结构。你可能仍然只是``知道’’整个编程语言的一小部分—-许多编程语言有巨大的标准库—-但新的库和数据结构可以很快且容易被理解。 这就意味着这本书的重点不是作为一个如何使用一些特定神经网络库的教程。如果你主要想围绕着某个程序库的方式去学习，那不要读这本书！找到你想学习的程序库，并通过教程和文档来完成。注意这点。虽然这也许能很快解决你的问题，但是，如果你想理解神经网络中究竟发生了什么，如果你想要了解今后几年都不会过时的原理，那么只是学习些热门的程序库是不够的。你需要领悟让神经网络工作的原理。技术来来去去，但原理是永恒的。 一个动手实践的方法我们将通过攻克一个具体的问题：教会计算机识别手写数字的问题，来学习神经网络和深度学习的核心理论。 这个问题用常规的方法来编程解决是非常困难的。然而，正如我们所看到的，它可以很好地利用一个简单的神经网络来解决，只需几十行代码，没有特别的库。更多的是，我们会通过多次迭代来改进程序，逐步融入神经网络和深度学习的核心思想。 难得有一本书能兼顾理论和动手实践。但是我相信，如果我们建立了神经网络的基本思路，你会学到最好的。我们将开发实际能用的代码，而不仅仅是抽象的理论，这些代码你可以探索和扩展。这样你就可以理解其基础，不论是理论还是实践，并且扩展和提高你的知识面。 使用神经网络识别手写数字——感知器本章我们将实现一个可以识别手写数字的神经网络。这个程序仅仅 74 行，不使用特别的神经网络库。然而，这个短小的网络不需要人类帮助便可以超过 96% 的准确率识别数字。而且，在后面的章节，我们会发展出将准确率提升到 99% 的技术。实际上，最优的商业神经网络已经足够好到被银行和邮局分别用在账单核查和识别地址上了。 手写识别常常被当成学习神经网络的原型问题，因此我们聚焦在这个问题上。作为一个原型，它具备一个关键点：挑战性，识别手写数字并不轻松，但也不会难到需要超级复杂的解决方法，或者超大规模的计算资源。另外，这其实也是一种发展出诸如深度学习更加高级的技术的方法。所以，整本书我们都会持续地讨论手写数字识别问题。本书后面部分，我们会讨论这些想法如何用在其他计算机视觉的问题或者语音、自然语言处理和其他一些领域中。 当然，如果仅仅为了编写一个计算机程序来识别手写数字，本章的内容可以简短很多！但前进的道路上，我们将扩展出很多关于神经网络的关键的思想，其中包括两个重要的人工神经元感知机和 S 型神经元），以及标准的神经网络学习算法，即随机梯度下降算法。自始至终，我专注于解释事情的原委，并构筑你对神经网络的直观感受。这需要一个漫长的讨论，而不是仅仅介绍些基本的技巧，但这对于更深入的理解是值得的。作为收益，在本章的最后，我们会准备好了解什么是深度学习，以及它为什么很重要。 感知器什么是神经网络？一开始，我将解释一种被称为“感知器”的人工神经元。今天，使用其它人工神经元模型更为普遍，在这本书中，以及更多现代的神经网络著作中，主要使用的是一种叫做 S 型的神经元模型。我们很快会讲到 S 型神经元。但是要理解为什么 S 型神经元被定义为那样的方式，值得花点时间先来理解下感知器。 感知器的定义感知器是如何工作的呢？一个感知器接受几个二进制输入，$x_1,x_2,\ldots$，并产生一个二进制输出： 示例中的感知器有三个输入，$x_1,x_2,x_3$。通常可以有更多或更少输入。Rosenblatt 提议一个简单的规则来计算输出。他引入权重，$w_1,w_2,\ldots$，表示相应输入对于输出重要性的实数。神经元的输出，$0$ 或者 $1$，则由分配权重后的总和 $\sum_j w_j x_j$ 小于或者大于一些阈值决定。和权重一样，阈值是一个实数，一个神经元的参数。用更精确的代数形式： \text{output} = \begin{cases} 0 & \quad \text{if } \sum_j w_j x_j \leq \text{ threshold} \\ 1 & \quad \text{if } \sum_j w_j x_j > \text{ threshold} \\ \end{cases}这就是一个感知器所要做的所有事情！ 目前为止我把像 $x_1$ 和 $x_2$ 这样的输入画成感知器网络左边浮动的变量。实际上，可以画一层额外的感知器输入层来方便对输入编码： 这种对有一个输出但没有输入的感知器的标记法， 是一种标准。它并不实际表示一个感知器没有输入。为了看清它，假设我们确实有一个没有输入的感知器。那么加权和 $\sum_j w_j x_j$ 会总是为零，并且感知器在 $b &gt; 0$ 时输出 $1$，当 $b \leq 0$时输出 $0$。那样，感知器会简单输出一个固定值，而不是期望值（上例中的 $x_1$）。倒不如完全不把输入感知器看作感知器，而是简单定义为输出期望值的特殊单元，$x_1, x_2,\ldots$。 感知器做决策的原理随着权重和阈值的变化，你可以得到不同的决策模型。我们来看一个由感知器构成的网络。 在这个网络中，第一列感知器我们称其为第一层感知器通过权衡输入依据做出三个非常简单的决定。那第二层的感知器呢？每一个都在权衡第一层的决策结果并做出决定。以这种方式，一个第二层中的感知器可以比第一层中的做出更复杂和抽象的决策。在第三层中的感知器甚至能进行更复杂的决策。以这种方式，一个多层的感知器网络可以从事复杂巧妙的决策。 顺便提一下，当我定义感知器时我说的是感知器只有一个输出。在上面的网络中感知器看上去像是有多个输出。实际上，他们仍然是单输出的。多个感知器输出箭头仅仅便于说明一个感知器的输出被用于其它感知器的输入。 它和把单个输出线条分叉相比，显得讨巧些。 让我们简化感知器的数学描述。条件 $\sum_j w_j x_j$ 看上去有些冗长，我们可以创建两个符号的变动来简化。第一个变动是把 $\sum_j w_j x_j$ 改写成点乘，$w\cdot x \equiv \sum_j w_j x_j$，这里 $w$ 和 $x$ 对应权重和输入的向量。第二个变动是把阈值移到不等式的另一边，并用感知器的偏置 $b \equiv -threshold$ 代替。用偏置而不是阈值，那么感知器的规则可以重写为 \text{output} = \begin{cases} 0 & \quad \text{if } w\cdot x + b \leq 0 \\ 1 & \quad \text{if } w\cdot x + b > 0 \end{cases}我们可以把偏置看作一种表示让感知器输出 $1$（或者用生物学的术语，即激活感知器）有多容易的估算。对于具有一个非常大偏置的感知器来说，输出 $1$ 是很容易的。但是如果偏置是一个非常小的负数，输出$1$ 则很困难。很明显，引入偏置只是我们描述感知器的一个很小的变动，但是我们后面会看到它引导更进一步的符号简化。因此，在这本书的后续部分，我们不再用阈值，而总是使用偏置。 感知器与逻辑运算我已经描述过感知器是一种权衡依据来做出决策的方法。感知器被采用的另一种方式，是计算基本的逻辑功能，即我们通常认为的运算基础，例如“与”，“或”和“与非”。例如，假设我们有个两个输入的感知器，每个权重为 $-2$，整体的偏置为 $3$。这是我们的感知器， 这样我们得到：输入00产生输出1，即 (-2)0 + (-2)0 + 3 = 3 是正数。这里我用符号来显式地表示乘法。但是输入11产生输出 0，即 (-2)1 + (-2)*1 + 3 = -1 是负数。如此我们的感知器实现了一个与非门！ 与非门的例子显示了我们可以用感知器来计算简单的逻辑功能。实际上，我们完全能用感知器网络来计算任何逻辑功能。原因是与非门是通用运算，那样，我们能在多个与非门之上构建出任何运算。 感知器运算的通用性既是令人鼓舞的，又是令人失望的。令人鼓舞是因为它告诉我们感知器网络能和其它计算设备一样强大。但是它也令人失望，因为它看上去只不过是一种新的与非门。这简直不算个大新闻！ 然而，实际情况比这一观点认为的更好。其结果是我们可以设计学习算法，能够自动调整人工神经元的权重和偏置。这种调整可以自动响应外部的刺激，而不需要一个程序员的直接干预。这些学习算法是我们能够以一种根本区别于传统逻辑门的方式使用人工神经元。有别于显式地设计与非门或其它门，我们的神经网络能简单地学会解决问题，这些问题有时候直接用传统的电路设计是很难解决的。 S 型神经元学习算法听上去非常棒。但是我们怎样给一个神经网络设计这样的算法呢？假设我们有一个感知器网络，想要用它来解决一些问题。 引入 S 型神经元的原因例如，网络的输入可以是一幅手写数字的扫描图像。我们想要网络能学习权重和偏置，这样网络的输出能正确分类这些数字。为了看清学习是怎样工作的，假设我们把网络中的权重（或者偏置）做些微小的改动。就像我们马上会看到的，这一属性会让学习变得可能。这里简要示意我们想要的（很明显这个网络对于手写识别还是太简单了！）： 如果对权重（或者偏置）的微小的改动真的能够仅仅引起输出的微小变化，那我们可以利用这一事实来修改权重和偏置，让我们的网络能够表现得像我们想要的那样。例如，假设网络错误地把一个“9”的图像分类为“8”。我们能够计算出怎么对权重和偏置做些小的改动，这样网络能够接近于把图像分类为“9”。然后我们要重复这个工作，反复改动权重和偏置来产生更好的输出。这时网络就在学习。 问题是当我们给实际网络加上感知器时，结果并不像我们想象的那样。实际上，网络中单个感知器上一个权重或偏置的微小改动有时候会引起那个感知器的输出完全翻转，如 $0$ 变到 $1$。那样的翻转可能接下来引起其余网络的行为以极其复杂的方式完全改变。因此，虽然你的“9”可能被正确分类，网络在其它图像上的行为很可能以一些很难控制的方式被完全改变。这使得逐步修改权重和偏置来让网络接近期望行为变得困难。也许有其它聪明的方式来解决这个问题。但是目前为止，我们还没发现有什么办法能让感知器网络进行学习。 我们可以引入一种称为 S 型神经元的新的人工神经元来克服这个问题。S 型神经元和感知器类似，但是经过修改后，权重和偏置的微小改动只引起输出的微小变化。这对于让神经元网络学习起来是很关键的。 好了, 让我来描述下 S 型神经元。我们用描绘感知器的相同方式来描绘 S 型神经元： 正如一个感知器， S 型神经元有多个输入，$x_1,x_2,\ldots$。但是这些输入可以取 $0$ 和$1$ 中的任意值，而不仅仅是 $0$ 或 $1$。例如，$0.638\ldots$ 是一个 S 型神经元的有效输入。同样， S 型神经元对每个输入有权重，$w_1,w_2,\ldots$，和一个总的偏置，$b$。但是输出不是 $0$ 或 $1$。相反，它现在是 $\sigma(w \cdot x+b)$，这里 $\sigma$ 被称为 S型函数（顺便提一下，$\sigma$ 有时被称为逻辑函数，而这种新的神经元类型被称为逻辑神经元。既然这些术语被很多从事于神经元网络的人使用，记住它是有用的。然而，我们将继续使用 S 型这个术语。）定义为： \sigma(z) \equiv \frac{1}{1+e^{-z}}把它们放在一起来更清楚地说明，一个具有输入 $x_1,x_2,\ldots$，权重$w_1,w_2,\ldots$，和偏置 $b$ 的 S 型神经元的输出是： \frac{1}{1+\exp(-\sum_j w_j x_j-b)}S 型神经元的性质初看上去， S 型神经元和感知器有很大的差别。如果你不熟悉 S型函数的代数形式，它看上去晦涩难懂又令人生畏。实际上，感知器和 S 型神经元之间有很多相似的地方，跨过理解上的障碍，S 型神经元的代数形式具有很多技术细节。 为了理解和感知器模型的相似性，假设 $z \equiv w \cdot x + b$ 是一个很大的正数。那么 $e^{-z} \approx 0$ 而 $\sigma(z) \approx 1$。即，当 $z = w \cdotx+b$ 很大并且为正， S 型神经元的输出近似为 $1$，正好和感知器一样。相反地，假设 $z = w \cdot x+b$ 是一个很大的负数。那么$e^{-z} \rightarrow \infty$，$\sigma(z) \approx 0$。所以当 $z = w \cdot x +b$ 是一个很大的负数， S 型神经元的行为也非常近似一个感知器。只有在 $w \cdot x+b$ 取中间值时，和感知器模型有比较大的偏离。 $\sigma$ 的代数形式又是什么？我们怎样去理解它呢？实际上，$\sigma$ 的精确形式不重要，重要的是这个函数绘制的形状。是这样： 这个形状是阶跃函数平滑后的版本： 如果 $\sigma$ 实际是个阶跃函数，既然输出会依赖于 $w\cdot x+b$ 是正数还是负数。（实际上，当 $w \cdot x +b = 0$ ，感知器输出 $0$，而同时阶跃函数输出$1$。所以严格地说，我们需要修改阶跃函数来符合这点。但是你知道怎么做。）那么S型神经元会成为一个感知器。利用实际的 $\sigma$ 函数，我们得到一个，就像上面说明的，平滑的感知器。确实，$\sigma$ 函数的平滑特性，正是关键因素，而不是其细部形式。$\sigma$ 的平滑意味着权重和偏置的微小变化，即 $\Delta w_j$ 和 $\Delta b$，会从神经元产生一个微小的输出变化 $\Delta output$。实际上，微积分告诉我们 $\Delta output$ 可以很好地近似表示为： \Delta output \approx \sum_j \frac{\partial \, output}{\partial w_j} \Delta w_j + \frac{\partial \, output}{\partial b} \Delta b其中求和是在所有权重 $w_j$ 上进行的，而 $\partial \, output /\partial w_j$ 和$\partial \, output /\partial b$ 符号表示 $output$ 分别对于 $w_j$ 和 $b$ 的偏导数。如果偏导数这个概念让你不安，不必惊慌。上面全部用偏导数的表达式看上去很复杂，实际上它的意思非常简单（这可是个好消息）：$\Delta output$ 是一个反映权重和偏置变化，即 $\Delta w_j$ 和$\Delta b$，的线性函数。利用这个线性特性，我们比较容易细微地修改权重和偏置的值，从而获得我们需要的细微的输出变化。所以，因为 S 型神经元具有与感知器类似的本质行为，它们可以帮助我们了解权重和偏置的变化如何影响输出值。 如果对 $\sigma$ 来说重要的是形状而不是精确的形式，那为什么要在公式$\sigma(z) \equiv \frac{1}{1+e^{-z}}$中给 $\sigma$ 使用特定的形式呢？事实上，在下文我们还将不时地考虑一些神经元，它们给其它激活函数 $f(\cdot)$ 输出是 $f(w \cdot x + b)$。当我们使用一个不同的激活函数，最大的变化是公式$\Delta output \approx \sum_j \frac{\partial \, output}{\partial w_j} \Delta w_j + \frac{\partial \, output}{\partial b} \Delta b$ 中用于偏导数的特定值的改变。事实证明当我们后面计算这些偏导数，用 $\sigma$ 会简化数学计算，这是因为指数在求导时有些可爱的属性。无论如何，$\sigma$ 在神经网络的工作中被普遍使用，并且是这本书中我们最常使用的激活函数。 S 型神经元与感知器的关系一个感性的认识是：S 型神经元是阶跃函数平滑后的版本。 但可以在数学上证明如下两点： 假设我们把一个感知器网络中的所有权重和偏置乘以一个正的常数，$c&gt;0$。可以证明网络的行为并没有改变。 假设我们有上题中相同的设置，一个感知器网络。同样假设所有输入被选中。我们不需要实际的输入值，仅仅需要固定这些输入。假设对于网络中任何特定感知器的输入 $x$， 权重和偏置遵循 $w \cdot x + b\neq 0$。现在用 S 型神经元替换所有网络中的感知器，并且把权重和偏置乘以一个正的常量 $c&gt;0$。证明在 $c \rightarrow \infty$的极限情况下， S 型神经元网络的行为和感知器网络的完全一致。当一个感知器的 $w \cdot x + b = 0$ 时又为什么会不同？ 解释 S 型神经元的输出我们应该如何解释一个 S 型神经元的输出呢？很明显，感知器和 S 型神经元之间一个很大的不同是 S 型神经元不仅仅输出 $0$ 或 $1$。它可以输出 $0$ 到 $1$ 之间的任何实数，所以诸如 $0.173\ldots$ 和 $0.689\ldots$ 的值是合理的输出。这是非常有用的，例如，当我们想要输出来表示一个神经网络的图像像素输入的平均强度。但有时候这会是个麻烦。假设我们希望网络的输出表示“输入图像是一个9”或“输入图像不是一个9”。很明显，如果输出是 $0$ 或 $1$ 是最简单的，就像用感知器。但是在实践中，我们可以设定一个约定来解决这个问题，例如，约定任何至少为 $0.5$ 的输出为表示 “这是一个9”，而其它小于 $0.5$ 的输出为表示“不是一个9”。当我们正在使用这样的约定时，我总会清楚地提出来，这样就不会引起混淆。 人工神经元的其它模型到现在，我们使用的神经元都是 S 型神经元。理论上讲，从这样类型的神经元构建起来的神经网络可以计算任何函数。实践中，使用其他模型的神经元有时候会超过 S 型网络。取决于不同的应用，基于其他类型的神经元的网络可能会学习得更快，更好地泛化到测试集上，或者可能两者都有。让我们给出一些其他的模型选择，便于了解常用的模型上的变化。 可能最简单的变种就是 tanh 神经元，使用双曲正切函数替换了 S 型函数。输入为 $x$，权重向量为 $w$，偏置为 $b$ 的 tanh 神经元的输出是 \tanh(w \cdot x+b)这其实和 S 型神经元关系相当密切。回想一下 $\tanh$ 函数的定义： \tanh(z) \equiv \frac{e^z-e^{-z}}{e^z+e^{-z}}进行简单的代数运算，我们可以得到 \sigma(z) = \frac{1+\tanh(z/2)}{2}也就是说，$\tanh$ 仅仅是 S 型函数的按比例变化版本。我们同样也能用图像看看 $\tanh$ 的形状： 这两个函数之间的一个差异就是 $\tanh$ 神经元的输出的值域是 $(-1, 1)$ 而非 $(0,1)$。这意味着如果你构建基于 $\tanh$ 神经元，你可能需要正规化最终的输出（取决于应用的细节，还有你的输入），跟 sigmoid 网络略微不同。 类似于 S 型神经元，基于 S 型神经元的网络可以在理论上，计算任何将输入映射到$(-1, 1)$ 的函数（对于 tanh 和 S 型神经元，这个说法有一些技术上的预先声明。然而，非正式地，通常可以把神经网络看做可以以任意精度近似任何函数。）而且，诸如反向传播和随机梯度这样的想法也能够轻松地用在 tanh-neuron 神经元构成的网络上的。 参考文献[1] Michael Nielsen. CHAPTER 1 Using neural nets to recognize handwritten digits[DB/OL]. http://neuralnetworksanddeeplearning.com/chap1.html, 2018-06-17. [2] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL]. https://github.com/zhanggyb/nndl/blob/master/chap1.tex, 2018-06-17. [3] Michael Nielsen. CHAPTER 3 Improving the way neural networks learn[DB/OL]. http://neuralnetworksanddeeplearning.com/chap3.html, 2018-06-28. [4] Zhu Xiaohu. Zhang Freeman.Another Chinese Translation of Neural Networks and Deep Learning[DB/OL]. https://github.com/zhanggyb/nndl/blob/master/chap3.tex, 2018-06-28.]]></content>
      <categories>
        <category>深度学习</category>
        <category>Neural Networks and Deep Learning (Michael Nielsen)</category>
      </categories>
      <tags>
        <tag>深度学习</tag>
        <tag>感知器</tag>
        <tag>Sigmoid函数</tag>
        <tag>S 型神经元</tag>
      </tags>
  </entry>
  <entry>
    <title><![CDATA[README]]></title>
    <url>%2F2018%2F05%2F20%2FREADME%2F</url>
    <content type="text"><![CDATA[yuanxiaosc.github.io个人博客；机器学习；深度学习；Python学习；]]></content>
  </entry>
  <entry>
    <title><![CDATA[Universal Language Model Fine-tuning for Text Classification翻译]]></title>
    <url>%2F2018%2F01%2F02%2FUniversal_Language_Model_Fine-tuning_for_Text_Classification%E7%BF%BB%E8%AF%91%2F</url>
    <content type="text"><![CDATA[Universal Language Model Fine-tuning for Text Classification用于文本分类的微调语言模型Abstract迁移学习为计算机视觉带来了巨大改变，但是现有的NLP技术仍需要针对具体任务改进模型，并且从零开始训练。我们提出了一种有效的迁移学习方法，可以应用到NLP领域的任何一种任务上，同时提出的技术对调整语言模型来说非常关键。我们的方法在六种文本分类任务上比现有的技术都要优秀，除此之外，这种方法仅用100个带有标签的样本进行训练，最终的性能就达到了从零开始、拥有上万个训练数据的模型性能。 Introduction迁移学习对计算机视觉（CV）产生了很大影响。应用CV模型（包括对象检测，分类和分割）很少从头开始训练，而是通过在ImageNet，MS-COCO和其他数据集上预训练的模型进行微调，Sharif Razavian等。（2014）; 龙等人。（2015a）; 他等人。（2016）; 黄等人。（2017）。 文本分类是自然语言处理（NLP）任务的一个类别，具有许多重要的实际应用程序，如垃圾邮件，欺诈和机器人检测Jindal和Liu（2007）; Ngai等。（2011）; 楚等人。（2012），紧急响应Caragea等。（2011），和商业文件分类，如法律发现Roitblat等。（2010年）。 虽然深度学习模型已经在许多NLP任务中实现了最先进的技术，但这些模型从头开始训练，需要大量数据集，并且需要数天才能收敛。NLP迁移学习的采用率落后于CV。微调预训练词嵌入Mikolov等。（2013）; Pennington等。（2014），一种仅针对模型第一层的简单迁移学习技术，在实践中产生了巨大的影响，并在大多数最先进的模型中使用。鉴于预训练Erhan等人的好处。（2010），我们应该能够比随机初始化模型的其余参数做得更好。 最近的方法将来自其他任务（例如语言建模或机器翻译）的嵌入与不同层的输入相连接.Peters等人。（2017）; 麦肯等人。（2017）; 匿名（2018）。然而，这些方法仍然从头开始训练主要任务模型，并将预训练嵌入作为固定参数处理，限制了它们的实用性。 可以说，成功的NLP迁移学习技术应该满足与CV对应类似的标准：a）该方法应该能够利用大量可用数据; b）它应该利用可以独立优化的任务，从而进一步改善下游; c）它应该依赖于可以按原样用于大多数NLP任务的单个模型; d）在实践中应该易于使用。 我们建议使用微调语言模型（FitLaM）作为满足上述标准的NLP迁移学习的有效形式。我们的方法使用语言建模，这是一项具有几乎无限量数据的任务，以及推动最新技术发展的最新进展。它通过预训练无缝集成了大量外部数据和域内数据。 FitLaM依赖于简单的递归神经网络（RNN）而无需任何额外的修改; 我们只使用一个或多个任务特定的线性层来扩充模型，相对于现有方法占少量参数。我们提出了一种新的微调技术，即区分性微调，它可以在较低层次上对较低层进行微调，以保留通过语言建模获得的知识。我们还介绍了几种技术，这些技术对于良好的微调性能和更快的培训至关重要。 我们在五种广泛研究的不同大小和类型的文本分类任务中评估我们的迁移学习方法，在这些任务上我们明显优于高度任务特定的先前工作和现有的迁移学习方法。 我们的贡献如下： 我们在CV和NLP中绘制了迁移学习的相似之处，并为NLP提供了一种有效的迁移学习方法。 我们提出了微调语言模型（FitLaM），这种方法可用于为NLP的任何任务实现类似CV的迁移学习。 我们建议使用判别性微调来保留先前的知识并避免在微调期间发生灾难性的遗忘。 我们引入了通过时间进行反向传播的文本分类（BPT3C），这是一种通过线性层将分类器丢失反向传播到任何序列大小的RNN输出的新方法。 我们介绍了对预训练语言模型进行微调的关键技术。 我们在五个代表性文本分类数据集上的表现明显优于最新技术，大多数数据集的误差降低了18-24％。 我们制作预训练模型和代码，以实现更广泛的采用。 Related workTRANSFER LEARNING IN CV 计算机视觉中的迁移学习已经观察到CV中的深度神经网络中的特征从任务特定性迁移一般性从第一层到最后一层递减Yosinski等人。（2014年）。出于这个原因，CV中的大部分工作都集中在转移模型Long等人的最后几层。（2015b）。sharif2014cnn使用ImageNet模型的特征作为简单分类器的输入来实现最先进的结果。近年来，这种方法已被最后Donahue等人的微调所取代。（2014年）或预训练模型的最后几层，并留下其余层冻结Long等。（2015a）。 Hypercolumns 超级列在NLP中，最近才提出的方法不仅仅是迁移字嵌入。流行的方法是预先嵌入通过其他任务捕获额外上下文的嵌入。然后将嵌入与单词嵌入或中间层的输入连接起来。这种方法在CV Hariharan等人中被称为超级列。（2015）并由 peters2017semi， deepcontext2017和 Mccann2017分别使用语言建模和机器翻译（MT）进行预训练。使用类似的方法Conneau2017用于学习句子表示。在CV中，超级列几乎完全被端到端的微调Long等人所取代。（2015a）。 MULTI-TASK LEARNING 多任务学习一个相关的方向是多任务学习（MTL）（Caruana,1993）。这个方法被 Rei,2017 和 Liu 2018 所采用，他们把语言模型的目标添加到主任务模型目标中联合训练。多任务学习要求每次都从头开始训练，所以它比较低效。而且多任务学习需要仔细权衡任务模型目标的权重。 Fine-tuning 微调微调已经在相似任务之间的迁移学习中获得了成功，比如 （Min 等，2017）在问答任务中，远程监督情感分析（Severyn and Moschitti, 2015），亦或是机器翻译领域（(Sennrich et al., 2015）。但是也有在不相关领域迁移失败的例子（(Mou et al.,2016）。Dai and Le (2015)也微调了一个语言模型，但是在 10K 标记样本集上过拟合了，而且需要数百万同领域文档来获得更好的表现。相反，ULMFiT 利用通用领域的文档进行预训练，同时提出新的微调技术来阻止过拟合当仅仅只有 100 个标签的样本集，并且取得了最优的效果在小数据集上。 Universal Language Model Fine-tuning我们对自然语言处理最通用场景下的迁移学习感兴趣：考虑一个静态的原任务 $T_S$ 和任何一个目标任务 $T_T$，其中 $T_S \ne T_T$，并且我们想提高在 $T_T$ 中的表现。语言模型可以被视作一个理想的原任务就像是自然语言处理界的 ImageNet：语言模型可以为下游任务捕获许多语言方面的特征，比如长短期依赖，层次关系，情感等等。不像机器翻译模型，语言模型在大多数领域和语言上有几乎无限的数据。此外，一个预训练的语言模型可以很容易地适应目标任务的特质，我们将在第五小节展示这种语言模型带来的显著提升。同时，语言模型还是现存任务的重要组成成分，比如机器翻译和对话模型。形式上，语言模型引入了一个假设空间 $H$ 可以对其它许多自然语言处理任务有用(Vapnik and Kotz, 1982; Baxter, 2000)。 我们提出的统一微调语言模型（ULMFiT），它先在大规模通用领域语料上预训练然后使用新的技术在目标任务上微调。这个新的方法在某种程度上是通用的，因为它满足以下实践标准：1)它在不同大小、数量和标签类型的任务中都有效；2）它使用单一的结构和简单的训练过程；3）它不需要特征工程和特殊的预处理；4）它不需要额外的任务领域内的文档和标签数据。 在我们的实验中，我们使用最优语言模型 AWD-LSTM (Merity et al.,2017a)，一个普通的 LSTM （它没有注意力机制、捷径连接、精致复杂的附加结构），只是含有可以改变 dropout 率。类似于计算机视觉，我们期待未来下游的表现可以显著地提高通过使用表现优异的语言模型。 ULMFiT 含有以下步骤：我们在图 1 中展示：a）通用领域语言模型预训练3.1；b）目标领域语言模型微调3.2；c）目标任务分类任务微调3.3。我们将在下面几个小节中讨论它们。 General-domain LM pretraining我们在Wikitext-103 Merity等人上预先训练了语言模型。（2017b）由28,595个预处理的维基百科文章组成。预先训练更多和更多样化的数据集可以提高性能。这个阶段是最昂贵的，但因为它只需要执行一次，所以通过改进下游模型的性能和融合，它在以下阶段中受益匪浅。我们使预训练模型的权重可用于促进实验。 Target task LM fine-tuning无论用于预训练的通用域数据多么多样，目标任务的数据可能来自不同的分布。因此，我们在目标任务的训练示例上微调语言模型。给定一个预训练的通用域LM，这个阶段收敛得更快，因为它只需要适应目标数据的特性，它允许我们训练一个强大的LM，即使对于小数据集。我们提出 discriminative fine-tuning 判别性微调 和 slanted triangular learning rates 斜三角形学习率为微调语言模型, 接下来我们逐一介绍。 Discriminative fine-tuning因为不同的层捕获不同类型的信息(Yosinski et al., 2014)，它们应该被不同程度的微调。为了这个目的，我们提出了一个新的微调方法，判别性微调。 不是对模型所有的层使用相同的学习率，我们为模型每一层使用有区别的微调学习率。通常使用随机梯度下降在时间步 $t$ 来更新模型参数 $\theta$ 就像下面这样(Ruder, 2016)： \theta_t=\theta_{t-1} - \eta \nabla_{\theta}J(\theta)其中 $\eta$ 是学习率，$\nabla_{\theta}J(\theta)$ 是模型的目标函数对参数的梯度。为了判别式微调我们把模型参数 $\theta$ 分为 $\{\theta^1,…,\theta^L\}$ 其中 $\theta^l$ 包含模型第 $l$ 层的参数。同样我们使用 $\{\eta^1,…,\eta^L\}$，其中 $\eta^l$ 是模型第 $l$ 层的学习率。 这样随机梯度下降更新使用判别式微调之后就像下面这样： \theta_t^l=\theta_{t-1}^l - \eta^l \nabla_{\theta^l}J(\theta)我们经验地发现模型工作地很好当首先为模型最后一层选择 $\eta^L$ 进行微调，然后层与层之间使用 $\eta^{l-1}=\eta^l/2.6$ 的规律计算。 Slanted triangular learning rates为了让参数适用于特定任务的特征，我们想让模型参数在训练的开始阶段迅速地汇聚到合适的参数空间然后再精调参数。使用相同的学习率或者一个退火学习率在训练模型时不是一个最佳的方式。我们提出一个斜三角形学习率，它首先线性增加然后线性递减根据安排的时间表，就如图 2所示： Slanted triangular learning rates 计算式子如下：其中 $T$ 是训练迭代次数（4In other words, the number of epochs times the number of updates per epoch）；$cut_frac$ 是我们增加学习率的部占比；$cut$ 是学习率由增到减的转折点，$p$ 是我们分别增加或减少学习率的迭代次数的分数；$ratio$ 指定最小学习率比最大学习率小的比率；$\eta_t$ 是学习率的第 $t$ 次迭代。我们通常的设定是 $cut_frac = 0.1, ratio = 32, \eta_{max} = 0.01$。 Target task classifier fine-tuning对于目标任务分类器微调，我们使用一个或多个附加线性块来扩充预训练语言模型。就像计算机视觉中的标准实践，每一个块使用批次正则化 normalization 和 dropout ，使用 ReLU 激活函数给中间连接层，并且softmax激活在最后一层的目标任务类上输出概率分布。请注意，这些特定于任务的分类器层中的参数是唯一需要从头学习的参数。第一个线性层将合并的最后隐藏层状态作为输入。 Concat pooling文本分类任务中的信号通常包含在几个单词中，这些单词可能出现在文档中的任何位置。由于输入文档可能包含数百个单词，如果我们只考虑模型的最后隐藏状态，信息可能会丢失。出于这个原因，我们将文档的最后一个步骤 $H={h_1,..,h_T}$ 的隐藏状态与隐藏状态的 max-pooled 和 mean-pooled 表示相结合，在GPU内存中适合尽可能多的时间步长。 h_c = [h_T, maxpool(H), meanpool(H)]其中 [] 表示连接操作。 微调分类模型是迁移学习中最关键的一个部分。过度激进的微调会造成灾难性的遗忘，会消除了语言模型捕捉的信息的好处；太谨慎的微调会收敛的很慢而且会导致过拟合。除了判别性微调和斜三角形学习率，我们提出逐层解冻为分类微调。 Gradual unfreezing不是一下微调所有的层，它可能导致灾难性遗忘。我们从最后一层到第一层提出逐层解冻，因为最后一层包含最少的一般性知识(Yosinski et al., 2014)：我们解冻最后一层然后微调所有解冻的层。我们然后解冻倒数第二层重复开始的过程直到我们微调了所有的层。这和“链式解冻”很相似(Felbo et al.,2017)，除了每次我们增加一个已经解冻的层，而不是每次训练一个层。 虽然模型能从 discriminative fine-tuning, slanted triangular learning rates, and gradual unfreezing 单独获益，如第五小节，这些方法会相互补充，联合起来让我们在不同的数据集上获益。 BPTT for Text Classification (BPT3C)通过时间反向传播（BPTT）训练语言模型，以实现大输入序列的梯度传播。为了使大型文档的分类器微调可行，我们提出了BPTT for Text Classification（BPT3C）：我们将文档划分为大小为b的固定长度批次。在每个批次的开头，模型初始化为前一批次的最终状态; 我们跟踪平均值和最大池的隐藏状态; 梯度被反向传播到批次，其隐藏状态有助于文档末尾的分类器预测。在实践中，我们使用可变长度反向传播序列Merity等。（2017a）。 Bidirectional language model与Peters等人的现有工作相似。（2017）; 匿名（2018），我们不仅限于微调单向语言模型。对于我们所有的实验，我们预先训练前向和后向LM。我们使用BPT3C独立微调每个LM的分类器并平均其预测。 Experiments虽然我们的方法同样适用于序列标记任务，但由于其重要的实际应用，我们专注于此工作中的文本分类任务。 Experimental setupDatasets and tasks我们在五个广泛研究的不同大小的数据集上评估我们的方法，这些数据集由最先进的文本分类和迁移学习方法使用Johnson和Zhang（2017）; 麦肯等人。（2017）作为三个常见文本分类任务的实例：情感分析，问题分类和主题分类。我们显示表1中每个数据集和任务的统计数据 Sentiment Analysis对于情绪分析，我们评估我们对二元电影评论IMDb数据集 Maas等人的方法。（2011）和由 zhang2015character 编译的二进制Yelp审查数据集。 Question Classification我们使用六类版本的小型TREC数据集 Voorhees和Tice（1999）将开放域，基于事实的问题数据集划分为广泛的语义类别。 Topic classification对于主题分类，我们评估由 zhang2015character 创建的大型AG-News和DBpedia本体数据集。 Pre-processing我们使用与早期工作相同的预处理Johnson和Zhang（2017）; 麦肯等人。（2017）。此外，为了使语言模型能够捕获可能与分类相关的方面，我们为大写单词，伸长和重复添加了特殊标记。 HyperparametersWe are interested in a model that performs robustly across a diverse set of tasks. To this end, if not mentioned otherwise, we use the same set of hyperparameters across tasks, which we tune on the IMDb validation set. We use the AWD-LSTM language model (Merity et al., 2017a) with an embedding size of 400, 3 layers, 1150 hidden activations per layer, and a BPTT batch size of 70. We apply dropout of 0.4 to layers, 0.3 to RNN layers, 0.4 to input embed-ding layers, 0.05 to embedding layers, and weight dropout of 0.5 to the RNN hidden-to-hidden ma-trix. The classifier has a hidden layer of size 50. We use Adam with β1 = 0.7 instead of the de-fault β1 = 0.9 and β2 = 0.99, similar to (Dozat and Manning, 2017). We use a batch size of 64, a base learning rate of 0.004 and 0.01 for fine-tuning the LM and the classifier respectively, and tune the number of epochs on the validation set of each task7. We otherwise use the same practices used in (Merity et al., 2017a). Baselines and comparison models对于每项任务，我们都会与当前最先进的技术进行比较。对于IMDb和TREC-6数据集，我们与CoVe McCann等人进行了比较。（2017），NLP的最先进的迁移学习方法。对于 AG, Yelp 和 DBpeadia 数据集我们与由Johnson and Zhang (2017) 提出的最先进的文本分类方法比较。 Results我们在表2中的 Mccann2017 使用的IMDb和TREC-6数据集上显示测试准确度分数。我们的方法优于CoVe，这是一种基于超级列的最先进的迁移学习方法，以及两个数据集的最新技术。在IMDb上，我们分别在CoVe和最新技术方面将误差显着降低了43.9％和22％。这是特别有希望的，因为现有的现有技术需要复杂的架构Anonymous（2018），多种形式的关注McCann等人。（2017）和复杂的嵌入方案Johnson和Zhang（2016），而我们的方法采用标准的Bi-LSTM，具有压差。 在TREC-6上，我们的改进 - 与最先进方法的改进类似 - 在统计上并不显着，因为测试的尺寸很小，仅包含500个例子。我们建议停止使用此数据集来评估文本分类算法。然而，小型TREC-6数据集的竞争性表现仍然表明，即使对于小型数据集，微调语言模型和目标任务分类器也是可行的。请注意，尽管预训练的数据比\ newcite Mccann2017 使用的700万个句子对的数据少两个数量级，但我们在两个数据集上的表现始终优于他们的方法。 我们在表3中的 johnson2017deep 使用的较大的AG-News，DBpedia和Yelp-bi数据集上显示测试错误率。我们的方法再次显着优于最先进的技术。在AG-News上，我们观察到与现有技术相比，同样显着的误差减少了23.7％。在DBpedia和Yelp-bi上，我们将误差分别减少了4.8％和18.2％。 Discussion and future directions虽然我们的方法仍然需要一些技巧和手动调整学习率和辍学权重来实现最佳性能，但我们认为它类似于AlexNet Krizhevsky等人。（2012）作为必将的第一步，将导致创新浪潮。我们相信，随着越来越多的研究专注于改善NLP的迁移学习，微调语言模型将变得更加健壮。在这条道路上迈出的重要一步将是仔细消融研究，以了解这里描述的模型和培训程序的每个组成部分的影响。 鉴于NLP的迁移学习（尤其是微调）未得到充分研究，未来的许多方向都是可能的。一个可能的方向是改进语言模型预训练任务并使其更具可扩展性：对于ImageNet，预测更少的类只会导致性能下降小Huh等。（2016） -专注于预测最频繁的单词可能会保留大部分性能，同时加快培训速度。语言建模还可以通过多任务学习方式Caruana（1993）中的其他任务来增强，或者通过额外的监督来丰富，例如语法敏感的依赖性Linzen等。（2016） 创建一个更通用或更适合某些下游任务的模型。 另一个方向是将该方法应用于新颖的任务和模型。虽然序列标记任务的扩展很简单，但其他任务（例如蕴涵和问答）使用更复杂的交互，这需要新颖的方式来预训练和微调。 最后，虽然微调是迁移学习的一个组成部分，但它很少受到关注，即使在计算机视觉中（至少在学术界 - 它是商业系统如Clarifai的关键基础）。所有常见基准测试仍然评估我们从头开始训练模型的能力，而不是微调预训练模型。创建微调基准将使我们能够开发更复杂的微调方法，这将使我们能够充分挖掘预训练模型的新潜力。 Conclusion我们已经提出了ULMFiT，一种可以应用到任何 NLP 的有效的迁移学习方法。以及一种有效的微调方法，一种有效的微调方法，可以将不同的层调整到不同的程度，以避免灾难性的遗忘和让模型在不同范围的任务中更加鲁棒性的学习。我们的方法明显优于现有的迁移学习技术和六个具有代表性文本分类任务的最新技术。我们希望我们的结果能够促进 NLP 迁移学习的新发展。]]></content>
      <categories>
        <category>论文</category>
        <category>论文阅读</category>
      </categories>
      <tags>
        <tag>Language Model</tag>
      </tags>
  </entry>
</search>
