-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 655 KB
/
content.json
1
{"pages":[{"title":"About me","text":"个人介绍:斛兵塘边一枝花,才学素养人品佳 联系方式: CSDN:http://blog.csdn.net/u012052268 GitHub:https://github.com/xqtbox/","link":"/about/index.html"},{"title":"categories","text":"","link":"/categories/index.html"},{"title":"All tags","text":"","link":"/tags/index.html"}],"posts":[{"title":"2018.03.26试题理解论文两篇阅读","text":"最近读了两篇关于问题答案联合建模的论文,读书笔记如下: 1 A Constituent-Centric Neural Architecture for Reading Comprehension0 摘要:0.1应用领域:阅读理解(Reading comprehension RC)旨在理解自然语言并回答其中的问题,这是一项具有挑战性的任务。 在本文中,我们研究斯坦福问题答疑数据集(SQUAD)中的RC问题。 0.2模型从训练集观察,大多数正确的答案都集中在句子解析树(parse tree)中的组成成分(constituents)上, 我们设计了一个成分为中心(constituent-centric)的神经网络架构,其中候选答案(candidate answers)的生成和他们的表示学习(representation learning)都是基于解析树的组成部分(constituents)来生成,并由句子语法解析树指导(guided)。 好处:在这种架构下,候选答案的搜索空间可以大大减少,并且可以很好地捕获成分之间的句法(syntactic),层次(hierarchical)和组合结构(compositional structure),这有助于更好地表达候选答案。 1 引言1.1 任务阅读理解(RC)旨在通过理解文本来回答问题,这是自然语言处理中的一项很火热的研究领域。在本文中,我们是解决SQUAD QA任务(图1显示了一个例子),这个数据集的特点如下: (1)大规模:107,785个问题,23,215个段落; (2)非合成:由众包工作者提出问题; (3)候选答案的大量搜索空间(对模型能力很高要求)。例子如下: 我们研究两个主要问题:(1)如何生成候选答案?(2)如何有效地代表(represent)候选答案? 与给出少量答案选项的多选QA 和 填空式QA不同,SQUAD中的答案可以是文本中的任意跨度(any span),从而产生一个大小为O(n 2)的大搜索空间,其中n是句子中单词的数量。这会产生大量的噪音,模糊性和不确定性,使得挑选正确答案非常困难。 represent答案 首先,需要捕捉跨越多个句子的远程语义。即,回答问题需要多重推理。例如,在图1中,段落中的最后两句是解答第三个问题所必需的。 其次,局部句法结构需要纳入表征学习。 的研究表明,实验表明,句法特征是影响表现的主要因素。 1.2 解决办法 为了解决第一个问题:研究表明,人类回答问题时,给出的正确答案不是任意的跨度,而是以句法分析树中的成分为中心。我们根据成分产生候选答案,这大大减少了搜索空间。 为了解决第二个问题(句法特征的表示学习):我们首先使用链式树(chain-of-trees)LSTM 和树引导的注意机制(tree-guided attention mechanism)对各个成分进行编码,然后将这些编码生成组成序列的表示。 2模型2.1 模型的总架构:模型的输入是passage和question,输出是大部分适合于回答这个问题的段落中的答案。 我们设计了一个以成分为中心的神经网络(Constituent-Centric Neural network) (CCNN),它包含了以下四个层次: 树的chain-of-trees LSTM编码层:在编码层中,链式树LSTM和树LSTM分别对passage段落和问题中的构成要素进行编码。 树引导的注意层: 编码被馈送到树引导的注意层以学习问题意识表示(question-aware representations) 候选答案生成层:注意力输出被传递到候选答案生成层以基于组分扩展来产生和编码候选答案。 预测层:预测层使用前馈网络从候选人中挑选出最佳答案。 2.2 chain-of-trees LSTM编码层考虑到段落和问题,我们首先使用斯坦福句法解析器将它们解析为组成分析树,然后CCNN的编码层通过tree LSTM学习 组成部分 在问题和段落中的表示。 这里有两个模型:tree LSTM 和chain of tree LSTM,概念是类似的,我们先看简单的:tree LSTM 2.2.1 tree LSTM每个问题都是一个句子,有一个组成分析树(constituent parse tree)。树中的叶节点代表单个单词组成部分,内部节点表示具有多于一个单词的组成部分。 有了句法树,我们构建一个双向树LSTM,它由一个自下而上的LSTM和一个自顶向下的LSTM组成,以编码这些成分(如图4 )。 每个节点(成分)具有两个隐藏状态:LSTM在自底向上产生的h↑和LSTM从上向下产生的h↓。 h↑(i)第i个 子代 的隐藏层状态(hidden state),c↑(i)第i个 子代 的memory cell。 在自底向上的LSTM中,每个节点都有一个输入门i↑,忘记门{f(l)↑}对应于不同的孩子,一个输出门o↑和一个存储单元c↑。对于内部节点而言,输入是子节点的隐藏状态和存储单元,转换方程定义为: 在自上而下的方向上,门,存储单元和隐藏状态的定义方式与自底向上方向类似。 对于除根之外的内部节点,输入为其父节点的隐藏状态h↓和存储单元c↓。 对于叶节点,除了h↓和c↓之外,输入还包含单词嵌入。 对于根节点,自顶向下的隐藏状态h↓被设置为其自下而上的隐藏状态h↑。这样: h↑捕获所有成分的语义,然后将其复制为h↓并向下传播到每个单独的成分中。 最后,连接两个方向的隐藏状态,我们得到每个节点h = [h↑; h↓]的LSTM编码,它将成为关注层的输入。 自下而上的隐藏状态h↑构成了包含在该组成部分中的子组成部分的语义,并且自顶向下的隐藏状态h↓捕捉整个句子中表现的上下文语义。 2.2.2 Chain-of-Trees LSTM for Passage EncodingChain-of-Trees LSTM从字面上来看,就是把一系列Trees LSTM 连成一个链。 为了对包含多个句子的段落进行编码,我们设计了一个链式LSTM(图4)。为每个句子建立一个双向tree LSTM以捕捉本地句法结构,并且这些tree LSTM 通过双向链LSTM粘合在一起以捕捉跨越多个句子的远程语义。 具体位置输入为:由自底向上树LSTM生成的隐藏状态充当链LSTM的输入。类似地,链LSTM状态被馈送到自顶向下树LSTM。这使得每个成分的编码都能传播到通道中的所有其他成分。 前向LSTM:每个句子t被视为一个单位。这个单元的输入是由句子t的tree LSTM生成的,它是根部的自底向上隐藏状态h↑t。 后向LSTM:计算记忆门遗忘门之后,随后,封装所有语句的语义的→h t和←h t被输入到自顶向下树LSTM的根,并传播到句子t中的所有成分中。 2.3 Tree-Guided Attention Mechanism我们提出了一种tree-guided attention(TGA)机制来学习文章中每个组成部分的问题意义( question-aware)表示,其中包括两个步骤: (1)constituent-level attention分数计算; (2)以树为导向的归一化; 给定文章中的constituent h(p),对于问题中的每个成分h(q),计算非标准化的注意力权重a作为a = h(p)•h(q),其测量两种成分之间的相似性。 然后我们对这些分数进行树导向的规范化。在分析树中的每个内部节点处,其L个孩子的未归一化注意分数为{al} ,使用softmax操作执行局部归一化。。因为在每个内部节点处,设h为其LSTM编码,{al} 为该节点及其L个孩子的归一化注意分数,则此节点的注意力表示为: 然后将它连接到文本成分的LSTM编码h(p),并获得将成为每个成分表示向量 z = [h(p); b(r)]。 2.4 Candidate Answer Generation layer虽然训练集中的大部分正确答案都是组成部分(constituent),但是不完全是这样。 我们建议通过附加与它相邻的单词来扩展每个组成部分。 令C表示一个成分,并且S =“… wi-1 wi C wj wj+1…”是包含C的句子。我们通过追加C之前的单词(如wi-1和wi)和单词后的r个字附加到C上。 例子如下:前后扩展两个单词,共获得了9次扩展: 接下来,我们编码这些候选答案,编码将用于预测层。 鉴于每个扩展都是组成序列,我们构建了一个双向链LSTM(图5,右下),以综合其中各个组成部分的表示。在链式LSTM中,单元i的输入是Ci的组合表示。我们连接C 1处的前向隐藏状态和C 1处的后向状态作为E的最终表示。 2.5 Answer Prediction and Parameter Learning给定候选答案的表示,我们使用2个隐藏层(两者具有相同数量单位)的前馈网络f来预测正确的答案。 网络的输入是候选答案的特征向量,输出是置信度分数。 选择得分最高的那个作为正确的答案。 3实验实验在斯坦福问题答疑数据集(SQUAD)v1.1上进行,其中包含来自536维基百科文章的107,785个问题和23,215个段落。数据被随机分为训练集(80%),开发集(10%)和未发布测试集(10%)。 4思考 题目与答案 联合建模。对阅读理解任务来说,本篇论文说的是:最重要的是对“问题”与“原文(答案来源)”进行联合建模,取得了很好的效果提升。那么对于我们的“试题”表示学习来说,将题目文本(可以基于树),与答案文本(试题的讲师解析)联合建模。 总的来说,建模是一种工具,怎么如何衡量 建模的好坏。(各种测评任务) 或者建立自己的衡量数据集 与 任务。 2 Joint Modeling of Content and Discourse Relations in Dialogues对话中内容与话语关系的联合建模 1引言面向目标的对话,如会议,谈判或客户服务记录,在我们的日常生活中扮演着重要的角色。 从对话中自动提取关键点(critical points)和重要结果(important outcomes)将有助于为复杂对话生成摘要(summaries),也有助于理解会议的决策过程或分析协作的有效性。 本文主要关注 口头会议(spoken meetings),这是协作和想法分享的常用方式。 其中,话语结构(discourse structure)可以用来捕捉在会议的问题解决和决策过程中提出的主要讨论要点(主题)和论点。原因是: 不同说话人轮流的内容不是孤立地发生的,而有其内在逻辑。 同时,内容的转变也可以反映说话人的目的转变(purpose turns),从而便于话语关系的理解。 以图1中AMI语料库的会议片段为例: 这个讨论是基于Twente论证模式( Twente Argumentation Schema )(TAS)的话语结构加以注释的。 可以看出,会议参与者通过显示疑问(UNCERTAIN),提出替代解决方案(OPTION)或提供反馈(feedback)来评估不同的选项。话语信息通过揭示讨论流程帮助识别关键讨论点(key discussion point),即“使用哪种类型的电池”。 当前,对话中的自动话语分析仍然是一个具有挑战性的问题。 而且,获取关于话语关系的标注是耗时且昂贵的过程,并且不能针对大型数据集进行缩放。 所以,在本文中,我们提出了一种联合建模方法来选择(1)反映关键讨论点的重要短语,并(2)标注谈话会议中发言者轮流之间的话语关系。 据我们所知,我们的工作是第一个在会议中共同建立内容和话语关系的模型。我们用两个会议语料库 - AMI语料库和ICSI语料库测试了我们的模型。实验结果表明,我们的模型在词组选择上的准确率为63.2,明显好于基于支持向量机(SVM)的分类器。 我们的话语预测组件也比现有的基于神经网络的方法获得更好的准确性(59.2与54.2) 2模型2.1 Model Description我们提出的模型学习通过利用两种信息源之间的相互作用来共同执行内容选择和话语关系预测。 假设会议讨论记录(meeting discussion)为x,其中x由话语单元( discourse units)序列 x = {x 1 ,x 2 ,··· ,x n }组成。每个话语单元 xi 可以是某人完整的一句话或其中一部分。 如图1所示,为每次讨论构造一棵树形结构的话语图,每个话语单元作为树的一个节点。 在这项工作中,我们使用了Twente论证模式(TAS)(Rienksetal,2005)的议论性话语结构。对于每个节点x i,它在讨论中被附加到它之前的另一个节点x i’ (i’< i ),(对于每一句非开头话语,总是之前某一句话的“疑问、意见、反馈”) 并且话语关系di保持在链路(如果x i是根,则d i是空的)。令t表示x中的链路集合。根据之前的研究,我们假设话语单元之间的依附结构是在训练和测试期间给出的。 从每个话语单元x i中提取一组候选短语,从中识别包含要点信息的显着短语。我们使用斯坦福分析器(Stanford parser)获得组成和依赖分析的话语。并按照以下规则进行选取: 我们限制符合条件的候选人是最多5个单词的名词短语(NP),动词短语(VP),介词短语(PP)或形容词短语(ADJP),其首字不能是停用词。 如果候选人是组成分析树中另一位候选人的父母,我们将只保留父母。 如果后者是动词的直接宾语或主语,我们将动词和候选名词短语进一步合并为一个候选词。 对于例子x i : “let’s use a rubber case as well as rubber buttons”,我们可以确定候选词: “use a rubber case” 和 “rubber buttons”. “让我们使用橡胶外壳以及橡胶按钮”,我们可以确定候选词“使用橡胶外壳”和“橡胶按钮”。 此时,对于x i,候选短语集合表示为$ c i = (c_{i,1},c_{i,2},...,c_{i,mi}) $,其中m i是候选词数。 如果相应候选者被选为显着短语,则$c_{i,j}$取值1;否则$c_{i,j}$等于0。 整个讨论x(discussion)中的所有候选短语都表示为c ,c的特征参数为w(feature parameters),话语关系(discourse relations)为d。我们定义一个对数线性模型(对数线性模型描述的是概率与协变量之间的关系,逻辑回归就是一个对数线性模型): 这里Φ(·)和φ(·)表示特征向量。 我们利用三种类型的特征函数: (1)仅含内容的特征φc(·),它捕捉短语的重要性, (2)仅限话语特征φd(·),表征(潜在的更高阶)话语关系 (3)内容和话语φcd(·)的共同特征,它们模拟了两者之间的相互作用。 2.2 Joint Learning for Parameter Estimation参数估计的联合学习为了学习模型参数w,我们采用基于SampleRank的算法,这是一种随机结构学习方法 算法1中描述了完整的学习过程: 首先,使用从[-1,1]中随机抽取的每个值对特征权重w进行初始化。 对于每个样本,我们随机地初始化候选短语标签c和话语关系d的分配。 构造一个MCMC链,配置为σ=(c,d): 首先选择分布q(d’ | d,x)对话语结构d进行采样 然后基于新的选择分布q(c ‘ | c,d’,x)进行短语标签c的采样 计算两个提案得分。如果通过ω(σ0)提高得分,则新配置被接受。参数w会相应更新。 2.3 特征描述 内容特征Content Features 重要短语倾向于具有较高TF-IDF分数,所以我们计算每个短语中TF-IDF词的分数。 我们还要考虑这个词的主语是否在前面提到,这意味着讨论的焦点。 计数标签和短语类型的数量以表征句法结构 我们确定讨论中包含候选词组的转折的绝对位置和相对位置。最后,我们记录候选词是否由主讲者说出,主讲者在讨论中发表最多的单词。 话语特征Discourse Features 对于每个话语单元,我们收集话语树中当前单元及其父节点的对话行为类型,以及它们之间的相似性。 我们记录同一位发言者是否发出两个回合。 话语单位的长度也是相关的。因此,我们计算时间跨度和字数。 为了整合全局结构特征,我们对话语树中节点的深度和它的兄弟节点的数量进行编码。 联合特征Joint Features 为了对内容和话语之间的交互进行建模,我们将话语关系添加到每个内容特征以组成联合特征。 例如,如果候选词的内容特征φ[avg-TFIDF]的值为0.5,并且其话语关系d是POSITIVE,则联合特征采用φ[avg-TFIDF,POS]的值为 0.5。 3 收获 对试题进行建模的时候,为了提高精度。可以考虑题干文本的先后关系。 比如把一个题干分为[a、b、c]三部分,除了a 的文本之外,能否考虑a是b的条件;b是c的假设;这样的标签信息。 还有就是作者对文本的特征提取方式,比如:特征词的个数、同一个关键点之前有没出现过、转折词的个数。。。","link":"/2018/03/26/ 2018.03.26试题理解论文两篇阅读/"},{"title":"faial:refusing to merge unrelated histories","text":"本文解决在git中遇到的问题: faial: refusing to merge unrelated histories 原因: 在首次提交代码之前,必须首先pull一下。但是因为两个仓库不同,发现refusing to merge unrelated histories,无法pull。 这是因为他们是两个不同的项目,要把两个不同的项目合并,git需要添加一句代码,在git pull后面。这句代码是在git 2.9.2版本发生的,最新的版本需要添加--allow-unrelated-histories 解决:所以我们想要pull的时候 ,应该写如下git命令:假如我们的本地源是origin,github上的分支是master,那么我们 需要这样写: git pull origin master --allow-unrelated-histories(一定要注意是两个减号!!!)","link":"/2017/05/03/ faial:refusing to merge unrelated histories/"},{"title":"远程连接自动断开的问题解决办法","text":"远程连接自动断开的问题解决办法 1. 问题描述我们都知道,作为服务器,默认一般都是被动的等待客户端的连接到来。但对基于ssh协议的xshell的运用,总是出现自动断开的情况。 但是我们经常需要运行一些需要很长时间才能完成的任务,比如系统备份、ftp 传输等等。通常情况下我们都是为每一个这样的任务开一个远程终端窗口,因为它们执行的时间太长了。必须等待它们执行完毕,在此期间不能关掉窗口或者断开连接,否则这个任务就会被杀掉,一切半途而废了。 2. 解决办法可以将该会话“保存”,只要远程服务器不关闭,该会话就一直进行,下次需要的时候 重新连接即可。那么如何保存当前会话呢? 答案就是神器:screen 2.1. screen解决方案先看其简介: Screen是一款由GNU计划开发的用于命令行终端切换的自由软件。用户可以通过该软件同时连接多个本地或远程的命令行会话,并在其间自由切换。 由简介我们知道,screen可以在不同回话之间切换,那么,我们利用它的这个性能,把需要的会话“保存”,等到第二天用的使用再“切换”回 当时的会话即可。 怎么操作呢?我们先看一个简单粗暴地例子:我需要运行一个跑一夜的程序,那么在巡行程序之前先进行一步操作: screen -S myOneNight这句话的意思是,创建了一个叫 myOneNight 的screen作业会话。 现在,再执行你的 运行一夜的代码。。。。 关机,或者去玩其他事情。 第二天,再打开shell 运行命令:screen -r myOneNight 我们发现,昨天的程序还在正常运行。爽。 3. screen详解3.1 安装screen其实流行的Linux发行版(例如Red Hat Enterprise Linux)通常会自带screen实用程序,如果没有的话,可以从GNU screen的官方网站下载。 1234[root@TS-DEV ~]# yum install screen[root@TS-DEV ~]# rpm -qa|grep screenscreen-4.0.3-4.el5[root@TS-DEV ~]# 3.2 创建一个新的窗口安装完成后,直接敲命令screen就可以启动它。但是这样启动的screen会话没有名字,实践上推荐为每个screen会话取一个名字,方便分辨:screen -S david 3.3 常用的命令12345screen -S yourname -> 新建一个叫yourname的sessionscreen -ls -> 列出当前所有的sessionscreen -r yourname -> 回到yourname这个sessionscreen -d yourname -> 远程detach某个sessionscreen -d -r yourname -> 结束当前session并回到yourname这个session screen的选项: 123456789101112-A 将所有的视窗都调整为目前终端机的大小。-d <作业名称> 将指定的screen作业离线。-h <行数> 指定视窗的缓冲区行数。-m 即使目前已在作业中的screen作业,仍强制建立新的screen作业。-r <作业名称> 恢复离线的screen作业。-R 先试图恢复离线的作业。若找不到离线的作业,即建立新的screen作业。-s 指定建立新视窗时,所要执行的shell。-S <作业名称> 指定screen作业的名称。-v 显示版本信息。-x 恢复之前离线的screen作业。-ls或--list 显示目前所有的screen作业。-wipe 检查目前所有的screen作业,并删除已经无法使用的screen作业。 4 引用screen还有更加丰富的 高级用法,请参考: GNU’s Screen 官方站点:http://www.gnu.org/software/screen/ screen 常用工具命令:http://man.linuxde.net/screen","link":"/2018/04/19/ 远程连接自动断开的问题解决办法/"},{"title":"03 知识图谱 知识抽取","text":"知识抽取与挖掘> 本文是王昊奋老师《知识图谱》系列笔记第三篇。 前一课,我们通过手工的方式 构建了一个小型的知识图谱。 但是我们其实更加希望能够通过一些算法或者工具能够自动化的从互联网大数据中抽取知识扩充三元组。 知识抽取,即从不同来源、不同结构的数据中进行知识提取,形成知识(结构化数据)存入到知识图谱。大体的任务分类与对应技术如下图所示: 其中最重要的是非结构数据(纯文本)的抽取(第一章) 1. 知识抽取的概念and子任务(非结构化信息抽取)非结构化信息抽取三个最重要/最受关注的子任务: 实体抽取 也就是命名实体识别,包括实体的检测(find)和分类(classify) 检测: 北京是忙碌的城市。 [北京]: 实体 分类:北京是忙碌的城市。 [北京]: 地名 关系抽取 通常我们说的三元组(triple) 抽取,一个谓词(predicate)带 2 个形参(argument),如 Founding-location(IBM,New York) 事件抽取 相当于一种多元关系的抽取 1.1 实体识别 本节知识包含太多内容(根本写不完),专门开一篇博客详细学习,相关算法与实验操作。《03.1 知识图谱 实体识别》 实体抽取或者说命名实体识别(NER)在信息抽取中扮演着重要角色,主要抽取的是文本中的原子信息元素,如人名、组织/机构名、地理位置、事件/日期、字符值、金额值等,具体的标签定义可根据任务不同而调整。实体抽取任务有两个关键词:find & classify,找到命名实体,并进行分类。 命名实体识别主要分类,一般包括 3 大类(实体类、时间类和数字类)和 7 小类(人名、地名、组织名、机构名、时间、日期、货币和百分比)。但随着 NLP 任务的不断扩充,在特定领域中会出现特定的类别,比如医药领域中,药名、疾病等类别。 1.1.1 实体识别其他应用1.1.1.1 实体链接(共指消解 实体消歧) 首先输入的是非结构化的文本数据,经由命名实体识别或词典匹配技术进行实体的指称识别。 由于刚刚识别出来的实体可能是实体的部分表示或另类表示,因此需要结束表层名字扩展、搜索引擎、构建查询实体引用表等技术来对候选实体进行生成。 经过该步骤生成的实体可能有多个候选项,因此需要对候选实体进行消岐,此处可使用基于图的方法、基于概率生成模型、基于主题模型或基于深度学习的方法。 经过实体消岐后得到的唯一实体候选后就可以与知识库中的实体进行连接了。 举个例子: 1.1.1.2 其他应用 命名实体作为索引和超链接 情感分析的准备步骤,在情感分析的文本中需要识别公司和产品,才能进一步为- 情感词归类 关系抽取(Relation Extraction)的准备步骤 QA 系统,大多数答案都是命名实体 1.1.2 实体识别算法1.1.2.1 方法一般流程 ==Training标准流程==: 收集代表性的训练文档 为每个 token 标记命名实体(不属于任何实体就标 Others O) 设计适合该文本和类别的特征提取方法 训练一个 sequence classifier 来预测数据的 label ==Testing标准流程==: 收集测试文档 运行 sequence classifier 给每个 token 做标记 输出命名实体 1.1.2.2 编码方式看一下最常用的两种 sequence labeling 的编码方式:IO encoding和IOB encoding IO encoding 简单的为每个 实体 标注为 实体标签(PER只是众多中的一个 代表人 person),如果不是 实体 就标为 O(other),所以一共需要 C+1 个类别(label)。 而 IOB encoding 需要 2C+1 个类别(label),B 代表 begining,表示实体 开始的位置,I 代表 continue,承接上一个 NE,如果连续出现两个 B,自然就表示上一个 B 已经结束了。 在 Stanford NER 里,用的其实是 IO encoding,有两个原因: 一是 IO encoding 运行速度更快, 二是在实践中,两种编码方式的效果差不多。 IO encoding 确定 boundary 的依据是,如果有连续的 token 类别不为 O,那么类别相同,同属一个 NE;类别不相同,就分割,相同的 sequence 属同一个 NE。而实际上,两个 NE 是相同类别这样的现象出现的很少,如上面的例子,Sue,Mengqiu Huang 两个同是 PER 类别,并不多见,更重要的是,在实践中,虽然 IOB encoding 能规定 boundary,而实际上它也很少能做对,它也会把 Sue Mengqiu Huang 分为同一个 PER,这主要是因为更多的类别会带来数据的稀疏。 1.1.2.4 机器学习算法NER一直是NLP领域中的研究热点,从早期基于词典和规则的方法,到传统机器学习的方法,到近年来基于深度学习的方法,NER研究进展的大概趋势大致如下图所示。 NLP 的很多数据都是序列类型,需要使用序列模型解决。像 sequence of characters, words, phrases, lines, sentences,我们可以把这些任务当做是给每一个 item 打标签,如下图: 常见的序列模型有 有向图模型 如 HMM,假设特征之间相互独立,找到使得 P(X,Y) 最大的参数,属于生成式模型; 无向图模型 如 CRF,没有特征独立的假设,找到使得 P(Y|X) 最大的参数,判别式模型。 1.1.2.5 实验1:用CRF做实体识别实验。 本节知识包含太多内容(根本写不完),专门开一篇博客详细学习,相关算法与实验操作。《03.1 知识图谱 实体识别》 1.1.2.6 深度学习方法NER 中模型发展的历史:有一些,大致如下:MLP->LSTM->LSTM/CNN+CRF->BiLSTM+CRF- >BiLSTM+CNN+CRF。 本节知识包含太多内容(根本写不完),专门开一篇博客详细学习,相关算法与实验操作。《03.1 知识图谱 实体识别》 1.2 关系抽取关系抽取是从文本中抽取出两个或多个实体之间的语义关系。它是信息抽取研究领域的任务之一。如: 12王健林谈儿子王思聪:我期望他稳重一点。 -> 父子关系 (王健林, 王思聪) 关系抽取 主要方法有下面几类: 基于模板的方法(hand-written patterns) 基于触发词/字符串2.基于依存句法 监督学习(supervised machine learning) 机器学习 深度学习(Pipeline vs Joint Model) 半监督/无监督学习(semi-supervised and unsupervised) Bootstrapping Distant supervision Unsupervised learning from the web 1.2.1 基于模板的方法基于模板的方法在小规模数据集上容易实现且构建简单,缺点为难以维护、可移植性差、模板有可能需要专家构建。 1.2.1.1 基于触发词的Pattern首先定义一套种子模板,如: 其中的触发词为老婆、妻子、配偶等。根据这些触发词找出夫妻关系这种关系,同时通过命名实体识别给出关系的参与方。 1.2.1.2 基于依存分析的Pattern以动词为起点,构建规则,对节点上的词性和边上的依存关系进行限定。一般情况下是形容词+名字或动宾短语等情况,因此相当于以动词为中心结构做的Pattern。其执行流程为: 1.2.2 监督学习在给定实体对的情况下,根据句子上下文对实体关系进行预测,执行流程为: 预先定义好关系的类别。 人工标注一些数据。 设计特征表示。 选择一个分类方法。(SVM、NN、朴素贝叶斯) 评估方法。 其优点为准确率高,标注的数据越多越准确。缺点为标注数据的成本太高,不能扩展新的关系。 监督学习关系抽取有两种模式:管道模型Pipeline model和联合模型joint model。 管道模型Pipeline model(一环接一环) 即识别实体和关系分类是完全分离的两个过程,不会相互影响,关系的识别依赖于实体识别的效果,这样的好处的各模型相互独立,设计上较为容易,但误差会逐层传递,步骤太多有可能导致后续不可用。 联合模型joint model 将实体识别和关系分类一起做,在一个模型中完成。 如上图论文中,识别“出生地关系 born in ” 把实体识别模型(biLSTM+CRF)与关系抽取模型(树形依存关系LSTM) 一起训练,缺点是参数多训练慢,优势是精度高。 1.2.3 非监督学习前面的监督学习效果虽好,但有标注数据集的获取困难。因此可以借助半监督学习的方法,此处又分为远程监督学习和Bootstrapping方法两种。 所谓远程监督方法就是知识库与非结构化文本对齐来自动构建大量训练数据,减少模型对人工标注数据的依赖,增强模型跨领域适应能力。 Bootstrapping是通过在文本中匹配实体对和表达关系短语模式,寻找和发现新的潜在关系三元组。 1.2.3.1 远程监督远程监督流程为: 从知识库中抽取存在关系的实体对。 从非结构化文本中抽取含有实体对的句子作为训练样例。 该方法认为若两个实体如果在知识库中存在某种关系,则包含该两个实体的非结构化句子均能表示出这种关系。例子如下: 123456现在 有一条纯文本“乔布斯是苹果公司的联合创始人和CEO”我们没有任何标签; 但是在我们的知识库中存在“创始人(乔布斯,苹果公司)”这样一条规则。那么就认为出现乔布斯和苹果公司的句子就是表述创始人这项关系。因此可构建训练正例:“乔布斯是苹果公司的联合创始人和CEO”。 的分类标签为“创始人”。 远程监督可以利用丰富的知识库信息,减少一定的人工标注,但它的假设过于肯定,如乔布斯被赶出苹果公司。这句话表达的就不是创始人的例子,因此会引入大量的噪声,存在语义漂移现象。同时由于是在知识库中抽取存在的实体关系对,因此很难发现新的关系。 1.2.3.2 Bootstrapping不手写模版 而是学习模版:利用已知的“关系”所拥有的模版,去搜索新的模版。 这个方法在很多任务中都有提到,其执行流程为: 我们知道《姚明,叶莉》为“夫妻”关系。第一步从文档中抽取出所有包含种子实体(姚明叶莉)的新闻,并将实体置换为placehold: 姚明老婆 叶莉 简历身高曝光 X 老婆 Y 简历身高曝光 姚明 与妻子 叶莉 外出赴约 X 与妻子 Y 外出赴约 在剩下的文档中检索 所有满足上面第二和第四模式的句子,比如,我们找到了《小猪,伊万》也是“夫妻”关系。 小猪 与妻子 伊万 外出赴约 根据Pattern抽取出的新文档种子实体(找出所有 同时包括小猪伊万 的句子),迭代多轮直到不符合条件。 该方法的优点为构建成本低,适合大规模的构建,同时还可以发现新的(隐含的)关系。缺点为对初始给定的种子集敏感,存在语义漂移现象,结果的准确率较低等。 1.3 事件抽取从自然语言中抽取出用户感兴趣的事件信息,并以结构化的形式呈现出来,例如事件发生的时间、地点、发生原因、参与者等。如: 事件抽取任务最基础的部分包括: 识别事件触发词trigger及事件类型 type 抽取事件元素event argument 同时判断其角色role 抽出描述事件的词组或句子 此外,事件抽取任务还包括: 事件属性标注 事件共指消解 对于事件抽取,也可分为Pipeline方法和联合训练的方法。 1.3.1 管道模型Pipeline model(一环接一环)有监督的事件抽取方法的标准流程一种pipeline的方法,将事件抽取任务转化为多阶段的分类问题,需要的分类器包括: 事件触发次分类器(Trigger Classifier) 用于判断词汇是否是是事件触发词,以及事件的类别 元素分类器(Argument Classifier) 判别词组是否是事件的元素 元素角色分类器(Role Classifier) 判定元素的角色类别 属性分类器(attribute classifier) 判定事件的属性 可报告性分类器(Reportable-Event Classifier) 判定是否存在值得报告的事件实例 可以看到,这个流程还是蛮长的,因此Pipeline存在的误差传递问题在这里格外严重,因此我们需要联合训练: 1.3.2 联合模型joint model 使用一个模型同时抽取所有新的联合。 将问题建模成结构预测问题,使用搜索方法进行求解。 避免了误差传播导致的性能下降 全局特征可以从整体结构中学习得到,从而使用全局信息量提升局部预测。 2. 结构化数据的知识抽取所谓结构化数据就是指类似于关系库中表格那种形式的数据,他们往往各项之间存在明确的关系名称和对应关系。因此我们可以简单的将其转化为RDF或其他形式的知识库内容。 一种常用的W3C推荐的映射语言是R2RML(RDB2RDF)。一种映射结果如下图所示: 现有的工具免费的有D2R,Virtuoso、MOrph等。 3. 半结构化数据的知识抽取半结构化数据是指类似于百科、商品列表等那种本身存在一定结构但需要进一步提取整理的数据。 3.1 百科类知识抽取 3.2 Web网页数据抽取:包装器生成现在我们的目标网站是部分结构化的,如: 包装器是一个能够将数据从HTML网页中抽取出来,并且将它们还原为结构化的数据的软件程序(爬虫)。使用它提取信息流程为: 对于一般的有规律的页面,我们可以使用正则表达式的方式写出XPath和CSS选择器表达式来提取网页中的元素。但这样的通用性很差,因此也可以通过包装器归纳这种基于有监督学习的方法,自动的从标注好的训练样例集合中学习数据抽取规则,用于从其他相同标记或相同网页模板抽取目标数据。 对于监督学习我们知道标注数据是它的短板,因此我们想到自动抽取的方法。网站中的数据通常是用很少的一些模板来编码的,通过挖掘多个数据记录中的重复模式来寻找这些模板是可能的。","link":"/2019/04/27/03 知识图谱 知识抽取/"},{"title":"2018.06.06论文:12个NLP分类模型","text":"注1:本文翻译自GitHub上的一篇介绍,介绍了基于深度学习的文本分类问题。代码和部分模型介绍在GitHub上:https://github.com/DX2017/text_classification 注2:本文参考风起云杨译文:https://blog.csdn.net/qq_35273499/article/details/79498733 并加入自己的理解整理。 1 概述这个库 的目的是探索用深度学习进行NLP文本分类的方法。它具有文本分类的各种基准模型。 它还支持多标签分类,其中多标签与句子或文档相关联(作者的一篇论文:链接:large scale muli-label text classification with deep learning)。 虽然这12个模型都很简单,可能不会让你在这项文本分类任务中游刃有余,但是这些模型中的其中一些是非常经典的,因此它们可以说是非常适合作为基准模型的。每个模型在模型类型(github代码)下都有一个测试函数。这个几个模型也可以用于构建问答系统,或者是序列生成。 如果你想了解更多关于文本分类,或这些模型可以应用的任务的数据集详细信息,可以点击链接进行查询,我们选择了一个:https://biendata.com/competition/zhihu/ 1.1模型概览这篇文章介绍的模型有以下: 1.fastText 2.TextCNN 3.TextRNN 4.RCNN 5.分层注意网络(Hierarchical Attention Network) 6.具有注意的seq2seq模型(seq2seq with attention) 7.Transformer(“Attend Is All You Need”) 8.动态记忆网络(Dynamic Memory Network) 9.实体网络:追踪世界的状态 10.Ensemble models 11.Boosting:该模型是多模型堆叠而来的。每一层都是一个模型。结果将基于加在一起的logits,层之间的唯一链接是标签权重。每个标签的浅层预测误差率将成为下一层的权重。那些错误率很高的标签会有很大的权重。所以后面的层将更加关注那些错误预测的标签,并试图修复前一层的误差。结果是,我们可以得到一个很强大的模型。查看: a00_boosting/boosting.py 还包括一下其他模型: 1.BiLstm Text Relation 2.Two CNN Text Relation 3.BiLstm Text Relation Two RNN 1.2各模型效果对比:性能(多标签标签预测任务,要求预测能够达到前5,300万训练数据,满分:0.5) 1.4 代码用法: 模型在xxx_model.py中 运行python xxx_train.py来训练模型 运行python xxx_predict.py进行推理(测试)。 运行环境: python 2.7+tensorflow 1.1 TextCNN 模型已经可以转换成python 3.6版本 注意: 一些util函数是在data_util.py中的;典型输入如:“x1 x2 x3 x4 x5 label 323434”,其中“x1,x2”是单词,“323434”是标签;它具有一个将预训练的单词加载和分配嵌入到模型的函数,其中单词嵌入在word2vec或fastText中进行预先训练。 2 模型细节:2.1 快速文本(fastText)介绍 参考:https://www.sohu.com/a/219080991_129720 FastText是Facebook开发的一款快速文本分类器,提供简单而高效的文本分类和表征学习的方法,不过这个项目其实是有两部分组成的: 一部分是 文本分类paper:A. Joulin, E. Grave, P. Bojanowski, T. Mikolov, Bag of Tricks for Efficient TextClassification(高效文本分类技巧)。 另一部分是词嵌入学习(paper:P. Bojanowski, E. Grave, A. Joulin, T. Mikolov, Enriching Word Vectors with Subword Information(使用子字信息丰富词汇向量))。 本文主要关注FastText 用于文本分类,其词向量的用法可以参考博文:NLP︱高级词向量表达(二)——FastText(简述、学习笔记) fastText是Facebook于2016年开源的一个词向量计算和文本分类工具,在学术上并没有太大创新。但是它的优点也非常明显,在文本分类任务中,fastText(浅层网络)往往能取得和深度网络相媲美的精度,却在训练时间上比深度网络快许多数量级。在标准的多核CPU上, 能够训练10亿词级别语料库的词向量在10分钟之内。可以看出fastText有两个主要的特点: 速度很快 在速度的基础上精度较高 。 对应的解决办法就是: 层级简单 + embedding叠加 + 分层Softmax 字符级别的n-gram 解释 快的原因: 层级简单: 单词的embedding叠加获得的文档向量. 全连接参数由 n L 1024 变成 1 L 1024 在输出时,fastText采用了分层Softmax,大大降低了模型训练时间: 标准的Softmax回归中,要计算y=j时的Softmax概率:,我们需要对所有的K个概率做归一化,这在|y|很大时非常耗时。于是,分层Softmax诞生了,它的基本思想是使用树的层级结构替代扁平化的标准Softmax,使得在计算时,只需计算一条路径上的所有节点的概率值,无需在意其它的节点。 下图是一个分层Softmax示例: 树的结构是根据类标的频数构造的霍夫曼树。K个不同的类标组成所有的叶子节点,K-1个内部节点作为内部参数,从根节点到某个叶子节点经过的节点和边形成一条路径。从根节点走到叶子节点,实际上是在做了3次二分类的逻辑回归。通过分层的Softmax,计算复杂度一下从|K|降低到log|K|。 准的原因:字符级别的n-gram: word2vec把语料库中的每个单词当成原子的,它会为每个单词生成一个向量。这忽略了单词内部的形态特征,比如:“apple” 和“apples”,“达观数据”和“达观”,这两个例子中,两个单词都有较多公共字符,即它们的内部形态类似,但是在传统的word2vec中,这种单词内部形态信息因为它们被转换成不同的id丢失了。 为了克服这个问题,fastText使用了字符级别的n-grams来表示一个单词。对于单词“apple”,假设n的取值为3,则它的trigram有: 1“<ap”, “app”, “ppl”, “ple”, “le>” 其中,<表示前缀,>表示后缀。于是,我们可以用这些trigram来表示“apple”这个单词,进一步,我们可以用这5个trigram的向量叠加来表示“apple”的词向量。 这带来两点好处:(论文中怎么说》》》》》????) 对于低频词生成的词向量效果会更好。因为它们的n-gram可以和其它词共享。 对于训练词库之外的单词,仍然可以构建它们的词向量。我们可以叠加它们的字符级n-gram向量。 总结于是fastText的核心思想就是:将整篇文档的词及n-gram向量叠加平均得到文档向量,然后使用文档向量做softmax多分类。这中间涉及到两个技巧:字符级n-gram特征的引入以及分层Softmax分类。github代码:p5_fastTextB_model.py 2.2文本卷积神经网络(Text CNN)《卷积神经网络进行句子分类》ConvolutionalNeuralNetworksforSentenceClassification论文的实现 结构:降维—> conv —> 最大池化 —>完全连接层——–> softmax github代码查看:p7_Text CNN_model.py 卷积神经网络是解决计算机视觉问题的主要手段。 现在我们将展示CNN如何用于NLP,特别是文本分类。句子长度会略有不同。 所以我们将使用padding来获得固定长度,n。 对于句子中的每个标记,我们将使用单词嵌入来获得一个固定的维度向量d。 所以我们的输入是一个二维矩阵:(n,d)。这跟CNN用于图象是类似的。 首先,我们将对我们的输入进行卷积计算。他是滤波器和输入部分之间的元素乘法。我们使用k个滤波器,每个滤波器是一个二维矩阵(f,d)注意d与词向量的长度相同。现在输出的将是k个列表,每个列表的长度是n-f+1。每个元素是标量(scalar)。请注意,第二维将始终是单词嵌入的维度。我们使用不同的大小的滤波器从文本输入中获取丰富的特征,这与n-gram特征是类似的。 其次,我们将卷积运算的输出做最大池化。对于k个特征映射,我们将得到k个标量。 第三,我们将连接所有标量来获得最终的特征。他是一个固定大小的向量。它与我们使用的滤波器的大小无关。 最后,我们将使用全连接层把这些特征映射到之前定义的标签。 2.3文本循环神经网络(Text RNN) Github 代码查看:p8_Text RNN_model.py 尽管TextCNN能够在很多任务里面能有不错的表现,但CNN有个最大问题是固定 filter_size 的视野,一方面无法建模更长的序列信息,另一方面 filter _size 的超参调节也很繁琐。CNN本质是做文本的特征表达工作,而自然语言处理中更常用的是递归神经网络(RNN, Recurrent Neural Network),能够更好的表达上下文信息。 模型结构:embedding—>bi-drectional lstm —> concat output –>average—–> softmax layer 通过利用双向LSTM建模,然后输出最后一个词的结果直接接全连接层softmax输出了。 2.4 双向长短期记忆网络文本关系(BiLstm Text Relation) Github 代码查看:p9_BiLstm Text Relation_model.py 结构:结构与Text RNN相同。但输入是被特别设计,直接把两个句子进行拼接。 例如: 1# "how much is the computer? EOS price of laptop"---> label:1 “EOS”是一个特殊的标记,将问题1和问题2分开。但是 模型并没有把两个句子分割开来,而是当做一个输入进行建模: 把 (背后的逻辑应该是 BiLstm 的自动“双向”建模能力) 2.5 两个卷积神经网络文本关系(two CNN Text Relation) Github 代码查看:p9_two CNN Text Relation_model.py 结构:首先用两个不同的卷积来提取两个句子的特征,然后连接两个特征,使用线性变换层将投影输出到目标标签上,然后使用softmax二分类。 更多文档、代码参考 参见USTC大佬、iflytek之光 Randolph的github库:Text-Pairs-Relation-Classification 2.6 双长短期记忆文本关系双循环神经网络(BiLstm Text Relation Two RNN) Github 代码查看:p9_BiLstm Text Relation Two RNN_model.py 结构:一个句子的一个双向lstm(得到输出1),另一个句子的另一个双向lstm(得到输出2)。拼接之后加全连接, 最后:softmax(输出1 输出0) 2.7 循环卷积神经网络(text-RCNN) Github 代码查看:p71_TextRCNN_model.py 《用于文本分类的循环卷积神经网络》Recurrent Convolutional Neural Networks for Text Classification论文的实现。 结构:1)循环结构(卷积层)2)最大池化3)完全连接层+ softmax 重点是 循环结构(卷积层),在循环神经网络中,加入了“上一个单词”的词向量,类似于 卷积神经网络的2-gram特征。这就是为什么是循环网络 却叫卷积层,重点代码如下: 1234567891011121314151617181920212223def get_context_left(self,context_left,embedding_previous): """ :param context_left: :param embedding_previous: :return: output:[None,embed_size] """ left_c=tf.matmul(context_left,self.W_l) #context_left:[batch_size,embed_size];W_l:[embed_size,embed_size] left_e=tf.matmul(embedding_previous,self.W_sl)#embedding_previous;[batch_size,embed_size] left_h=left_c+left_e context_left=self.activation(left_h) return context_leftdef get_context_right(self,context_right,embedding_afterward): """ :param context_right: :param embedding_afterward: :return: output:[None,embed_size] """ right_c=tf.matmul(context_right,self.W_r) right_e=tf.matmul(embedding_afterward,self.W_sr) right_h=right_c+right_e context_right=self.activation(right_h) return context_right 2.8 分层注意力代码:p1_HierarchicalAttention_model.py 《用于文档分类的分层注意网络》Hierarchical Attention Networks for Document Classification 论文的实现。 结构: 词编码器:词级双向GRU,以获得丰富的词汇表征 词注意力:词级注意在句子中获取重要信息 句子编码器:句子级双向GRU,以获得丰富的句子表征 句子注意:句级注意以获得句子中的重点句子 FC + Softmax 它有两个独特的特点: 1)它具有体现文件层次结构的层次结构 2)它在单词和句子级别使用两个级别的注意力机制,它使模型能够捕捉到不同级别的重要信息。 一个重要问题: ==Uw和Us 的来源 去向?== 计算方式: 就是一个 随机初始化的“权重向量”,通过训练更新, 每次计算出前向神经网络的隐层输出之后,乘以权重得到注意力向量。 从代码来研究: 1234567891011121314151617181920212223242526272829303132333435363738394041424344def AttentionLayer(self, inputs, name): #inputs是GRU的输出,size是[batch_size, max_time, encoder_size(hidden_size * 2)] with tf.variable_scope(name): # u_context是上下文的重要性向量,用于区分不同单词/句子对于句子/文档的重要程度, # 因为使用双向GRU,所以其长度为2×hidden_szie u_context = tf.Variable(tf.truncated_normal([self.hidden_size * 2]), name='u_context') #使用一个全连接层编码GRU的输出的到期隐层表示,输出u的size是[batch_size, max_time, hidden_size * 2] h = layers.fully_connected(inputs, self.hidden_size * 2, activation_fn=tf.nn.tanh) #shape为[batch_size, max_time, 1] alpha = tf.nn.softmax(tf.reduce_sum(tf.multiply(h, u_context), axis=2, keep_dims=True), dim=1) #reduce_sum之前shape为[batch_szie, max_time, hidden_szie*2],之后shape为[batch_size, hidden_size*2] atten_output = tf.reduce_sum(tf.multiply(inputs, alpha), axis=1) return atten_output###########################################################################################1. 词向量层:省略2. 句子级注意力:def sent2vec(self, word_embedded): with tf.name_scope(\"sent2vec\"): #GRU的输入tensor是[batch_size, max_time, ...].在构造句子向量时max_time应该是每个句子的长度,所以这里将 #batch_size * sent_in_doc当做是batch_size.这样一来,每个GRU的cell处理的都是一个单词的词向量 #并最终将一句话中的所有单词的词向量融合(Attention)在一起形成句子向量 #shape为[batch_size*sent_in_doc, word_in_sent, embedding_size] word_embedded = tf.reshape(word_embedded, [-1, self.max_sentence_length, self.embedding_size]) #shape为[batch_size*sent_in_doce, word_in_sent, hidden_size*2] word_encoded = self.BidirectionalGRUEncoder(word_embedded, name='word_encoder') #shape为[batch_size*sent_in_doc, hidden_size*2] sent_vec = self.AttentionLayer(word_encoded, name='word_attention') return sent_vec3.文档级注意力def doc2vec(self, sent_vec): #原理与sent2vec一样,根据文档中所有句子的向量构成一个文档向量 with tf.name_scope(\"doc2vec\"): sent_vec = tf.reshape(sent_vec, [-1, self.max_sentence_num, self.hidden_size*2]) #shape为[batch_size, sent_in_doc, hidden_size*2] doc_encoded = self.BidirectionalGRUEncoder(sent_vec, name='sent_encoder') #shape为[batch_szie, hidden_szie*2] doc_vec = self.AttentionLayer(doc_encoded, name='sent_attention') return doc_vec4. 全连接层:省略 2.9具有注意的Seq2seq模型具有注意的Seq2seq模型的实现是通过《共同学习排列和翻译的神经机器翻译》NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE来实现的。 首先学习一下什么是seq2seq模型:https://blog.csdn.net/qq_27505047/article/details/79531049 2.9.1 encoder to decoder首先是第一篇《NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE》,这篇论文算是在自然语言处理(NLP)中第一个使用attention机制的工作,将attention机制用到了神经网络机器翻译(NMT),NMT其实就是一个典型的Seq2Seq模型,也就是一个encoder to decoder模型,传统的NMT使用两个RNN,一个RNN对源语言进行编码,将源语言编码到一个固定维度的中间向量,再使用一个RNN进行解码翻译到目标语言: 按照论文所述,encoder中的每个隐层单元的计算公式为: encoder的输出语义编码向量c为: 而decoder通过将联合概率p(y)分解成有序条件来定义翻译y的概率: 2.9.2 引入注意力机制而引入注意力机制后的模型如下: 此时,关于p(y)的定义变化如下: 此处c变成了ci,即要输出的第i个单词时对应的ci向量,因此要如何计算ci向量时注意力机制实现的关键.但在此之前si的计算也变成了: 此时引入 论文示意图: 2.9.3 attention的计算方式那么重点来了,这个系数a是怎么计算的呢? 注意机制计算过程: 计算每个编码器输入 与 解码器隐藏状态的相似度,以获得每个编码器输入的可能性分布。 计算 基于可能性分布的 编码器注意力的加权和。ci是所有具有概率αij的hj的期望。 2.10 Transformer(“Attention Is All You Need”) 参考mijiaoxiaosan的博文:《对Attention is all you need 的理解》 参考 paperweekly 《一文读懂「Attention is All You Need」| 附代码实现》 https://yq.aliyun.com/articles/342508 带注意的 seq2seq是解决序列生成问题的典型模型,如翻译、对话系统。 Transformer,它仅仅依靠注意机制执行这些任务 (编码器 解码器 都只用attention),是快速的、实现新的最先进的结果。 结构如下: 编码器: 由N = 6个相同层的堆叠组成。 每个层都有两个子层。第一是多向自注意机制;第二个是全连接前馈网络。 解码器: 1.解码器由N = 6个相同层的堆叠组成。 2.除了每个编码器层中的两个子层之外,解码器多加入了一层 多向注意。 这个模型主要创新点: ==多头注意力 和位置编码== 关键点: ==位置编码==: 由于模型没有任何循环或者卷积,为了使用序列的顺序信息,需要将tokens的相对以及绝对位置信息注入到模型中去。论文在输入embeddings的基础上加了一个“位置编码”。位置编码和embeddings由同样的维度都是d 所以两者可以直接相加。 有很多位置编码的选择,既有学习到的也有固定不变的。本文中用了正弦和余弦函数进行编码。$PosEnc_{(pos,2i)} = sin(pos/10000^{2i/{d_{model}}})$ $PE_{(pos,2i+1)} = cos(pos/10000^{2i/{d_{model}}})$其中的pos是位置,i是维度(比如50维的词向量 如果位置 和 确定了 )。 偶数维度用sin 奇数维度用cos。 最后将词向量与位置向量直接相加。 ==多头注意力 的基本组成单位==: 普通注意力 :attention函数可以看作将一个query和一系列key-value对映射为一个输出(output)的过程(多数情况下 K和V是同一向量)事实上这种 Attention 的定义并不新鲜,但由于 Google 的影响力,我们可以认为现在是更加正式地提出了这个定义,并将其视为一个层地看待。。 论文自创在普通attention的基础上加了一个Scale(缩放层):计算query和所有keys的点乘,然后每个都除以dk−−√(这个操作就是所谓的Scaled)。之后利用一个softmax函数来获取values的权重。 这样可以起到“归一化”的作用。Mask层没看懂。 总的来说 attention公式如下:$Attention(Q,K,V) = softmax({QK^T\\over {\\sqrt {d_k}}})V$ 。只要稍微思考一下就会发现,这样的 Self Attention模型并不能捕捉序列的顺序。换句话说,如果将 K,V 按行打乱顺序(相当于句子中的词序打乱),那么 Attention 的结果还是一样的。但是对于 NLP 中的任务来说,顺序是很重要的信息,它代表着局部甚至是全局的结构,学习不到顺序信息,那么效果将会大打折扣。于是 Google 再祭出了一招——Position Embedding,也就是上面的“位置向量”。 ==Multi-Head Attention 多头注意力==:本文结构中的Attention并不是简简单单将一个attention应用进去。作者发现对 原始向量 进行h 次不同的attention,再拼接起来 效果特别好。所谓“多头”(Multi-Head),就是只多做几次同样的事情(参数不共享),然后把结果拼接。 分别对每一个映射之后的得到的queries,keys以及values进行attention函数的并行操作,最后拼接成output值。具体操作细节如以下公式。 $MultiHead(Q,K,V) = Concat(head_1,...,head_h)$ $where: head_i = Attention(Q{W_i}^Q,K{W_i}^K,V{W_i}^V)$ 结构示意图: 2.11 循环实体网络(Recurrent Entity Network)这篇论文是facebook AI在2017年的ICLR会议上发表的,文章提出了Recurrent Entity Network的模型用来对world state进行建模,根据模型的输入对记忆单元进行实时的更新,从而得到对world的一个即时的认识。该模型可以用于机器阅读理解等领域。 输入: 故事:它是多句话,作为上下文。 问题:一个句子,这是一个问题。 回答:一个单一的标签。 和之前的模型一样,Entity Network模型共分为Input Encoder、Dynamic Memory和Output Model三个部分。如下图的架构图所示: 模型结构: 1.输入编码层:利用RNN或者LSTM等时序神经网络模型,使用最后一个时间步长的状态作为句子编码 来编码故事(上下文)和查询(问题)st就是固定长度的句子的向量表示。 2.动态记忆: a. 通过使用键的“相似性”,输入故事的值来计算门控。 b. 通过转换每个键,值和输入来获取候选隐藏状态。 c. 组合门和候选隐藏状态来更新当前的隐藏状态。 t时刻输入st时,每个隐含层状态hj通过st和key wj来更新,更新公式如下: $g_j \\gets \\sigma (s_t^T h_j + s_t^T w_j)$ $\\tilde{h_j} \\gets \\phi( Uh_j + Vw_j + Ws_t)$ $h_j \\gets h_j + g_j \\odot \\tilde{h_j}$ $h_j \\gets \\frac{h_j}{|h_j|}$ 例如: Mary picked up the ball. Mary went to the garden. Where is the ball? 前两句是文本,最后一句是问题。由第一句得到在时间步长t的句子表达st,由第二句得到时间步长t+1的句子表达st+1。 当st被读取,w1记录实体Mary,h1记录实体状态Mary拿了一个ball; w2记录实体ball,h2记录实体状态ball被Mary拿着; 然后st+1被读取,读取到Mary,因为w1是记录Mary的key,位置寻址项sTt+1w1变化,门函数被激活,更新h1实体状态Mary去了garden; 因为h2记录ball被mary拿着,因此内容寻址项sTt+1h2变化,门函数被激活,更新h2的实体状态球被mary拿着,球在garden。 Output Model在原文中使用了一层的记忆网络,因此得到最后一个时间步长的隐层向量hj以后,就可以直接输出。 2.12 动态记忆网络 原文:《Ask me anything: dynamic memory networks for natural language processing》 博客参考:https://blog.csdn.net/javafreely/article/details/71994247 Question answering 是自然语言处理领域的一个复杂问题. 它需要对文本的理解力和推理能力.DMN 的输入包含事实输入,问题输入,经过内部处理形成片段记忆,最终产生问题的答案. DMN 由4个模块组成: 输入模块: 将原生文本输入编码成分布式向量表示. NLP 问题中,输入可以是一个句子,一个故事,电影评论,新闻文章或者维基百科文章等. 它的输入是 Work embedding(如通过 word2vec 或 GloVe 编码). 问题模块: 同输入模块类似,也是一个 RNN 网络. 输出是最后隐藏节点. 片段记忆模块: 片段记忆模块通过注意力机制决定关注输入数据的那些部分,并根据之前的记忆和问题产生新的记忆. 回答模块:回答模块也是一个 GRU 网络.其中上次输出和问题一起作为gru节点的输入。 根据最终记忆,产生问题的回答. 输入模块 输入模块是一个 RNN 网络. 它的输入是 Work embedding(如通过 word2vec 或 GloVe 编码). 输入是 TI个单词 w1,…,wTI . 在每个时间点 t,RNN 更新其隐藏状态 ht=RNN(L[wt],ht−1) . L 是 word embedding matrix. 在输入只有一个句子的情况下,输入模块输出 RNN 的所有隐藏状态. 在输入是多个句子的情况下,我们将所有句子拼接,并在每个句子末尾插入句末 token. RNN 每个句末 token 位置的隐藏状态作为输出. 输入模块的输出序列为 Tc 个 fact representation c. 其中 $c_t$ 是输出序列的第 t 个元素. 输入多个句子的情况下,TC 是句子个数. RNN 的选择: 原生的 RNN 性能较差, GRU 和 LSTM 性能差不多,但 LSTM 的计算更加昂贵,所以一般使用 GRU. 问题模块 同输入模块类似,也是一个 RNN 网络. 输出是最后隐藏节点 qTQ. (不同于输入模块,输入模块的输出是多个隐藏节点) 片段记忆模块 每个迭代都根据之前的记忆$m^{i-1}$、问题q 和事实 c 产生新的片段 ei.新的episode (e)等$e_t^i = G(c_t, m^{m-1}, q)$ (其中初始: m 0 = q) (e每次都带着q) 在当前E之下:片段记忆在输入模块输出的事实 c 上迭代,更新内部的片段记忆.$m^i = GRU(e^i, m^{i-1})$ 注意力机制:本文使用门控功能作为我们的注意机制,门函数 G(c,m,q)=σ(W(2)tanh(W(1)z(c,m,q)+b(1))+b(2)) 来衡量当前 句子的关注力 回答模块 回答模块也是一个 GRU 网络. 初始值为 a0=mTM 输出为 yt=softmax(W(a)at) 隐藏状态 at=GRU([yt−1,q],at−1), 上次输出和问题一起作为输入","link":"/2018/06/06/2018.06.06论文:12个NLP分类模型/"},{"title":"2019-06-06三亚旅游攻略","text":"0 购买及花费购买花费记录 款项 数额 墨镜 228 防晒 80 机场大巴 50 总计 358 1 日程安排1.1 6月6日(周四)飞机到海口市 6月6日是周四,主要步骤是飞行去海南省海口市。 晚上19:00左右,从学校出发,去机场。 晚上(晚点到23点)机场T1航站楼 出发飞行。 晚上1:50到 海口 美兰机场 。 酒店有接机服务,大概2.30点 到达酒店。 睡觉 1.2 6月7日(周五)海口市游玩+高铁到三亚 6月7日是周五,主要步骤是去海口市内观光+做高铁去三亚。 下图 是路径规划: 7点左右,早餐酒店免费提供。 退房,带着行李去,让酒店送我们到机场。 坐机场大巴(或者K4)去市区。(万绿园、滨海公园) 中午到达 第一打卡: 骑楼老街 下午去第二打卡圣地:假日海滩 (如果时间不够就不去) 坐车去海口东站(骑楼老街 坐K4); 17:55 动车 D7339 去三亚。 晚上19:20 到达三亚站 ,打车去酒店入住。 睡觉前逛逛~ 大东海 1.3 6月8日(周六)三亚正式游玩第一天~ 三亚的地理: 玩好 三亚 的第一个前提,就是找到舒服的落脚点,风景要好,人还不能太多,那么位置就极其重要. 三亚 有四个海湾,从西到东是 三亚湾 , 大东海 , 亚龙湾 和 海棠湾 (请看上图)。 我们本次的游玩路线是先中间后两边: 1. 大东海(中间 市区 离火车站近)、2. 亚龙湾(东边 最干净的沙滩 主玩) 、3. 三亚湾(西边 离机场近 方便去机场) 住宿表格: 日期 地点 周四 海口 美兰机场 周五 大东海 周六 8号 亚龙湾 周日 9号 亚龙湾 周一 10号 三亚湾 所以周六的计划为 早上吃酒店早餐,泳池 中午 退房(放行李?) 中午吃饭去 第一市场买菜 去小胡子做饭(可以打车) 下午不热的话就去 鹿回头公园 热的话 就直接去 亚龙湾 公交15路 1.2H 傍晚 入住亚龙湾 晚餐可以去 百花谷商业街 打车十元;也可以酒店泳池派对100/位 晚上在沙滩边游泳。 1.4 6月9日(周日)继续亚龙 :亚龙湾 酒店 酒店早餐, 沙滩游游泳。 下午逛逛步行街 吃饭 租个车,到处游玩 再住一晚 1.5 6月10日(周一) 假期last day:由于 要去坐飞机,所以选择距离 机场比较近的三亚湾(天涯海角) 居住。 狭长的 三亚湾 分为三部分。 红色虚线区域为 三亚 市区,游客最为集中,节假日期间沙滩上就是人头攒动。 黄色虚线区域有两块,紧靠着 三亚 市区两头的椰梦长廊和南边海路,人会比 三亚 市区少一半以上,在这片区域,你会觉得呼吸都顺畅一些。 最好的是绿色区域,这是 三亚 近几年开发出来的酒店区,沿着海是一水的五星级酒店和高档小区,找到承包了整片海滩的感觉。 PS:这片区域离机场很近,特别适合到达 三亚 第一天的适应和离开前最后一天的放松。 早上 在亚龙湾 酒店吃过早饭。 享受最后一秒的 细软沙滩。 中午吃过饭坐车去三亚湾的酒店, 游玩三亚湾 酒店吃饭 ,去天涯海角过纪念日 三亚湾的酒店有温泉。 早睡,明天5点起, 6.30的飞机。 参考:https://you.ctrip.com/travels/sanya61/3718820.html 2 拍照 模版 前期参考衣服搭配;后期学习拍照姿势。 图片来自携程三亚游记前几页,侵删。 2.1 海边 2.2 泳池 2.3 公寓 2.4 街景","link":"/2019/06/06/2019-06-06三亚旅游攻略/"},{"title":"2019-06-17问答系统项目落地调研","text":"1 chatbot概述1.1 行业分类及目前的应用状况智能人机交互通过拟人化的交互体验逐步在智能客服、任务助理、智能家居、智能硬件、互动聊天等领域发挥巨大的作用和价值。因此,各大公司都将智能聊天机器人作为未来的入口级别的应用在对待。 包括Google、Facebook、Microsoft、Amazon、Apple等互联公司相继推出了自己的智能私人助理和机器人平台。 1.2 问答实现方式目前的chatbot实现方案主要有两种,检索匹配模型和生成模型。 端到端生成模型:不需要预设问题库和知识库,是通过大量的语料数据训练,以学习语言元素的组成和表达方式,再分析组合生成回答。类似于我们学习说话的方式,自然地根据对方的话,生成回答。 检索匹配模型需要有一个问题库和对应的回答知识库及回答模板。在用户发出信息后,分析用户表达的内容,通过一定的匹配规则,匹配到和问题库最相近的问题,再给出相应的回答。匹配的过程中通过自然语言处理、机器学习等技术优化匹配方式,尽量给到合理的回答。检索匹配模型有两种主要实现方式: FAQ式 文本相似度计算:比如10086的在线智能客服,用户提问“如何查询话费”,那系统可以自动给出一个对应的知识“请您向10086号码发送‘HF’短信,即可查询当前话费”,而不再需要耗费高成本的人力来做解答。一般存储 问-答文本对数据。 任务式:规则模版-词槽匹配:“我想订一张明天从杭州到北京的机票” -> 进一步填充 出发地-目的地-时间。一般存储为图结构。 1.3 两种问答模式的优劣: 生成模型的对话更灵活,更像人,但是依赖的语料数据的训练、生成的语言结构等不是特别完善,容易出现语言结构混乱语无伦次看不懂的问题; 而检索匹配式,需要更多的精力去维护问答知识库,同时也会存在意图识别不准,问东答西的情况,但由于实现逻辑相较而言容易实现,且问答是可控的,不会出现语言结构错乱的问题。 根据各自的优势,生成模型内容涉及可以很泛很广,更适用于闲聊娱乐等模式;检索匹配模型,更适用于垂直领域信息的集合和知识的汇总,在一定的领域内,建立庞大的知识体系,完成特定的业务。 2 框架分析本文将调研的chatbot系统分为三个层次:平台型;解析型;单一型。 平台型:大公司成熟的chatbot集成平台,可以处理任务式闲聊式。用户只需要简单配置即可生成自己的chatbot,这也是我们未来成果的愿景。 但并没有暴露代码,目前能直接供我们学习内容的很少。(eg:Wit.ai 、DialogFlow、UNIT) 解析型:成熟的平台,没有代码使用,但提供了论文详细解析自己的系统,便于我们学习形成自己的架构。(eg:阿里小蜜) 单一型:暴露出代码(框架),可以用来生成我们框架中的某一种模块。(rasa、chatterbot、anyq) 2.1 平台型大公司成熟的chatbot集成平台,往往再用交互式、傻瓜式配置。用户只需要简单自定义即可生成自己的chatbot,这也是我们未来成果的愿景。 但并没有暴露代码,目前能直接供我们学习内容的很少。 2.1.1 Wit.aiWit.ai 是 Facebook 推出的用于将自然语言转化为可处理指令的 API 平台,其目的是为了帮助开发者便捷的打造类 Siri 语音对话应用或设备。 Step 1 注册 Wit.ai 账号 Step 2 简单设定机器人名字描述等信息 Step 3 创建对话情景(story): 整个介面就像是一个对话视窗,左边是 User says,右边是 Bot sends, Box executes 与 Jump。 User says: 顾名思义就是定义 User 会说的话,并且你可以设定 User 的句子中,有哪些关键字是你需要的、哪些文字是代表什麽含意,在 Wit.ai 的世界中,这样的东西叫做 Entity,后面会再度说明。 Bot sends: 就是机器人要回覆的句子,这边可以带入一些参数,像是 user 所提及的一些关键字,或是机器人向外呼叫 API 所得到的结果。 Box executes: 就是让你定义机器人要执行的 function,真正的实作不会在这边,这边只是定义名称,以及要接收的 context 与 吐回的变数名称。 Jump: 则是让你能够在满足设定 Step 4 定义使用者语句 下来我们先定义 User 可能会对我们的机器人说的话,像是使用者可能会跟机器人打招呼,我们就可以在对话框的 User says 输入 Hello,并且 highlight 起来以后设定 Entity,Enity 在 Wit.ai 裡面,就是用来让系统判断使用者输入句子时,哪些关键字是要抽取出来做处理的,你可以依照该关键字的特型来设定相对应的 Entity 类别。这边我们就自定义一个 Entity 名称叫做 greeting。 用户表达同一意图的说法可能是无限的。 可以在Understanding这个地方你有三种方式可以用来训练你的机器人: 定义更多keywords: 要完全符合你预先设定的关键字才会触发。 free-text: 如果你想要撷取使用者句子中的某段文字,而该段文字并不是特定的关键字时,就要设定 free-text, trait: 如果你想设定的 意图 不是靠句子中几个关键字能够辨别,而是需要整个句子来判定的话,就要设定成 trait。 Step 5 定义机器人回覆语句 当机器人收到 greeting 的 Entity 后,可以让用相同的 entity value 回覆,并加上简单的介绍。点选下方的 Bot sends,对话框就会出现机器人的部分,你可以在裡面输入机器人的回覆语句,想要的变数可以用{ }包起来,这边我们直接使用 greeting 这个 entity,这样就能用同样的 Entity 去回覆。 多轮问答: 如果我们的机器人需要做一个包含两个问题的调查,根据第一个问题答案的不同,机器人会额外询问一个附加问题。这样的例子,就叫做基于流的对话。 我们利用 bookmark 进行处理:当第一个 intent 为 no 时,我们使用 Jump 跳转到 question-2 的 bookmark,直接开始第二个问题的询问;当第二个 intent 为 no 时,我们同样利用 Jump 跳转到 end 的 bookmark,结束询问。补全了整个对话过程。 参考:http://www.woshipm.com/pd/829819.html 参考:https://blog.techbridge.cc/2016/07/02/ChatBot-with-Wit/ 2.1.2 谷歌DialogflowDialogFlow 是Google 提供的自然语言处理服务, 能够将文字转换成电脑看得懂的结构性资料, 再传递给后端介接的Web Service处理。 建立一个的意图 将相关的对话都映射到这个意图上 DialogFlow 背后的NLP引擎, 会将我们刚刚定义的相关语句训练出一个模型, 当未来有类似的句子时, 就会分析出FindHotel的意图出来 建立action 透过这个action, 当使用者没有特别表明目的地的时候呢, action就会被执行起来反问使用者 where are you looking for 2.1.3 科大讯飞AIUI平台AIUI 是科大讯飞2015年推出的一套以语音为核心的人机交互解决方案,意在使应用和设备能够快速具备能听会说,能理解会思考的能力。 接入了 AIUI 的应用和设备 可以轻松实现查询天气、播放音视频资源、设置闹钟以及控制智能家居等能力。 成功案例:海底捞智能客服:海底捞接入科大讯飞AIUI技术,用户可以通过电话与人工智能直接交互,高效准确的完成订餐预约,甚至点餐服务,上线后平均每家门店减少1位人工客服,节省成本1000万元/年,截止18年初已上线全国150家门店,AI客服服务占比高达85%,极大的节省了人力成本。 AIUI开放平台结构在AIUI开放平台上,可以看做由“应用+技能”两部分组成,其中“技能”除了自己创建的外,还有一个“技能商店”,可以选中他人已经制作好的技能,添加到自己的应用中。 所以 ,应用可以理解为技能的一个壳,应用装上了不同的技能,就能实现不同的能力 技能是AIUI开放平台的核心,这里先简单带下,下面细讲 技能能实现不同的功能,实际是识别出了用户不同的意图,然后根据不同的意图做出不同的反应。 AIUI开放平台优点 优点1:模块化逻辑清晰 优点2:针对狭隘的封闭域对话,可快速搭建 缺点1: 模糊匹配,而非真“学习”,效果不佳 缺点2:人力成本高 参考1:https://www.jianshu.com/p/3e9f5a223cbc 参考2:https://www.jianshu.com/p/b548671e0541?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation 参考3:https://doc.iflyos.cn/studio/guide/create.html#%E5%88%9B%E5%BB%BA%E6%8A%80%E8%83%BD-2 2.1.4 百度UNIT平台要在百度的UNIT创建一个可用的chatbot,主要有6大步骤 创建场景:根据业务需要创建场景,一个场景即一个可对外输出使用的功能例如“控制电视场景”、“办理信用卡场景”等 创建技能:技能是功能的最小单位,用于识别用户意图。例如“控制电视”的场景中,技能(或意图)可以是“切换频道”,“调整音量”,“开关机” 添加词槽的过程: 准备训练数据:技能创建好之后,只是一个空壳还是“控制电视”的场景,我们只是脑中想好了一个功能是“切换频道”,但是需要准备好数据,让machine去学习,什么是“切换频道” 训练技能:当技能空壳创建好后,数据也准备好了,扔进去一锅乱炖即可,训练技能 验证技能:当machine训练好后,我们要看下machine学的好不好,需要考考他,互动下例如发出“切换CCTV5”,结果执行了“关机”,你就一脸懵逼了,这时候就要再调整,再训练…… 验证技能有“体验模式”和“学习模式”两种 体验模式就是和chatbot瞎聊,对话内容不会加入到“对话样本集”中的“默认集” 学习模式,即与chatbot对话内容会加入到“对话样本集”中的“默认集 发布场景:训练好技能,就可以发布上线了。可以通过百度云调用,也可以使用DuerOS使用。 优点: “真·Machine Learning”:使用对话样本集训练数据,真正的使用NN去train,最终表现结果不错. 支持多轮对话,操作简单:通过响应条件与或非的设定,再加上词槽的澄清,使得创建一个多轮对话变得很简单。 支持企业自研模式: 参考:https://www.jianshu.com/p/a1111e2a00c2 参考:https://www.jianshu.com/p/c5be75ef9420?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation 2.2 解析型2.2.1 阿里小蜜 https://www.alixiaomi.com/ 2015年7月,阿里推出了自己的智能私人助理-阿里小蜜,一个围绕着电子商务领域中的服务、导购以及任务助理为核心的智能人机交互产品。 在去年的双十一期间,阿里小蜜整体智能服务量达到643万,智能服务在整个服务量(总服务量=智能服务量+在线人工服务量+电话服务量)占比达到95%,成为了双十一期间服务的绝对主力。 2018年初, 阿里公开展示了自己的智能助手小蜜的设计结构。《AliMe Assist: An Intelligent Assistant for Creating an Innovative E-commerce Experience》 作为类似客服助手的大型对话问答系统, 小蜜整合了任务型模块与开放聊天模块, 并围绕自身的应用场景, 构建了的工业级智能对话系统. 意图识别:识别语言的真实意图,将意图进行分类并进行意图属性抽取。意图决定了后续的领域识别流程,在阿里小蜜的对话体系中我们按照业务场景进行了3种典型问题类型的划分,并且依据3种类型会采用不同的匹配流程和方法: 问答型:例如“密码忘记怎么办?”→ 采用基于知识图谱构建+检索模型匹配方式 任务型:例如“我想订一张明天从杭州到北京的机票”→ 意图决策+slots filling的匹配方式 语聊型:例如“我心情不好”→ 检索模型与Deep Learning相结合的方式 通过一系列判别策略串联.分配到哪个服务中. 下面分别介绍,三种模式: 2.2.1.1 任务型:意图决策+slot filling的匹配方式任务型属于 助手服务(assistance service) 该模块用于处理”用户目标明确, 属性固定“的任务。 此类任务一般只需要用户确定类型的信息, 如”订飞机票”只要用户给出<出发地, 目的地, 时间>此类属性. 对用户输入的处理也只需要识别出用户需求所含的属性, 并让用户补充属性的值填充即可. 针对应用场景, 小蜜团队设计了基于字典(dictionaries)和样式(patterns)的填槽模块(slot-filling engine), 可以识别出15种不同的属性. 技术:意图决策+slot filling 流程: 首先按照任务领域进行本体知识的构建,例如机票的领域本体知识场景如下: 在问答匹配过程中结合上下文模型和领域数据模型不断在Query中进行slot属性的提取,并循环进行本体意图树的不断填充和修改,直到必选意图树填充完整后进行输出 2.2.1.2 问答型:基于知识图谱构建+检索模型匹配方式用户服务(customer service) 如果用户需要的是寻找某种信息或某种解决办法, 比如”忘记登陆密码怎么办”. 此类需求的核心是知识图谱技术, 通过抽取实体, 关系查询等技术找到需求对应的答案. 提问预处理:分词、指代消解、纠错等基本文本处理流程; 检索召回:通过检索的方式在候选数据中召回可能的匹配候选数据; 计算:通过Query结合上下文模型与候选数据进行计算,采用文本之间的距离计算方式(余弦相似度、编辑距离)以及分类模型相结合的方式进行计算; 最终根据返回的候选集打分阈值进行最终的产品流程设计 2.2.1.3 语聊型:检索模型与Deep Learning结合以上两个模块能覆盖绝大多数的用户请求(95%), 但出现特殊情况, 比如知识图谱中不含盖的实体时, 系统就需要调用聊天服务处理了. 智能聊天的特点:非面向目标,语义意图不明确,通常期待的是语义相关性和渐进性,对准确率要求相对较低。 面向open domain的聊天机器人目前无论在学术界还是在工业界都是一大难题,通常在目前这个阶段我们有两种方式来做对话设计: 一种是学术界非常火爆的Deep Learning生成模型方式,通过Encoder-Decoder模型通过LSTM的方式进行Sequence to Sequence生成。另外一种方式就是通过传统的检索模型的方式来构建语聊的问答匹配。 生成式模型 优点:通过深层语义方式进行答案生成,答案不受语料库规模限制 缺点:模型的可解释性不强,且难以保证一致性和合理性回答 检索模型 优点:答案在预设的语料库中,可控,匹配模型相对简单,可解释性强 缺点:在一定程度上缺乏一些语义性,且有固定语料库的局限性 因此在阿里小蜜的聊天引擎中,我们结合了两者各自的优势,将两个模型进行了融合形成了阿里小蜜聊天引擎的核心。 流程: 先通过传统的检索模型检索出候选集数据 然后通过Seq2Seq Model对候选集进行Rerank,重排序后超过制定的阈值就进行输出,不到阈值就通过Seq2Seq Model进行答案生成 2.2.1.4 小蜜的整体流程 首先, 用户输入q(text/voice)被传给规则解析模块(business rule parser), 规则解析模块是由大量的样式(patterns)组成的前缀树匹配结构(trie-based), 用于判断q是否能被助手服务处理. 如果能匹配出确定的样式, 则传给填槽模块处理。输出答案。 如果规则解析模块没有检查到样式, 则进入意图分类模块(intention classifier), 该模块由FastText+单层CNN这种相对简单的深度网络模型构成。 这里判断用户是否需要直接连接人工服务(service staff), 若不需要则进入下面的用户服务判别处理流程. 这部分先由语义解析模块处理, 由语义匹配寻找知识图谱(KG)中的实体(entity), 由KG中的实体关系寻找用户问题q对应的回答(answer)并返回; 假如没找到回答, 可以检查该问题q之前的上下文信息(context), 与q合并后再传给语义解析模块循环执行; 如果匹配不到KG实体, 就将q传给聊天服务中的检索模块, 检索到匹配度高于threshold的回复就返回, 否则就接人工服务. 此外, 如果语义解析模块找不到语义标签, 就直接转到聊天服务部分. 这个图非常重要,也是区别于阿里与其他妖艳贱货的地方,公开了详细的整体问答架构流程,而不是对一个小细节繁复讲解。 可供我们学习的地方很多。 参考:https://zhuanlan.zhihu.com/p/46457853 2.3 单一型(本文重点)调研了一些暴露出代码的开源框架(基于python),可以用来生成我们框架中的某一种模块。 2.3.1 ChatterBot ❤❤❤ 8K+ star: https://github.com/gunthercox/ChatterBot ChatterBot是一个Python库,使用一系列机器学习算法来生成不同类型的回答。 (主要是 匹配式) 1pip install chatterbot 程序通过搜索与输入匹配的最接近的匹配已知语句来选择最接近的匹配响应,然后从选择对该语句的已知响应中选择响应。 每个部分都设计了不同的“适配器”(Adapter)。 机器人应答逻辑 => Logic Adapters Closest Match Adapter 字符串模糊匹配(编辑距离) Closest Meaning Adapter 借助nltk的WordNet,近义词评估 Time Logic Adapter 处理涉及时间的提问 Mathematical Evaluation Adapter 涉及数学运算 可以同时使用多个逻辑适配器来处理,机器人将返回最高计算置信度值的回应;如果多个适配器返回相同的置信度,那么选择适配器列表中第一个适配器。 同样,也可以定义自己的逻辑适配器,通过继承LogicAdapter基类,重写相关方法返回指定的值就可以实现。 经过实验,这个框架主要对问题文本 使用相似度匹配,找出库中预定好的答案。 比较适合,知识问答类的情形。 参考:https://kantai235.github.io/2017/03/16/ChatterBotTeaching/ 参考:https://cloud.tencent.com/developer/article/1337627 参考:自定义适配器:https://zhuanlan.zhihu.com/p/35066208 2.3.2 rasa ❤❤❤使用rasa_nlu 理解用户的意图(预定义好) ,纯任务型对话。 意图识别 实体识别 参考:https://www.jianshu.com/p/7f8ca4ac16e7 使用rasa_core 根据模版回答问题:(可以填槽) 1234567891011121314151617181920212223class ActionSearchConsume(Action): def name(self): return 'action_search_consume' def run(self, dispatcher, tracker, domain): item = tracker.get_slot("item") item = extract_item(item) if item is None: dispatcher.utter_message("您好,我现在只会查话费和流量") dispatcher.utter_message("你可以这样问我:“帮我查话费”") return [] time = tracker.get_slot("time") if time is None: dispatcher.utter_message("您想查询哪个月的消费?") return [] # query database here using item and time as key. but you may normalize time format first. dispatcher.utter_message("好,请稍等") if item == "流量": dispatcher.utter_message("您好,您{}共使用{}二百八十兆,剩余三十兆。".format(time, item)) else: dispatcher.utter_message("您好,您{}共消费二十八元。".format(time)) return [] 这个框架的主要优点: 便捷的意图识别。(预定好意图类别) 便捷的训练数据生成工具。(根据你给的例子,自动生成训练数据!超级好用)❤❤❤ 可以识别填槽类问题,用于任务式问答(订票之类的) 对话管理:https://www.jianshu.com/p/515385a7c7f0 rasa中文:https://jverson.com/2018/09/11/rasa-nlu/ 2.3.3 DeepQA ❤ DeepQA项目试图重现神经会话模型的结果(又名谷歌聊天机器人),它采用了RNN(seq2seq模型)判刑预测,使用Python和TensorFlow实现。 如果需要自研 闲聊对话系统,可以参考这个。 但是需要大量中文对话数据,在数据来源方面,没有调研。 2.4 DeepPavlov❤❤❤❤ 3.2K star https://github.com/deepmipt/DeepPavlov 开源的对话 AI 库,建立在 TensorFlow 和 Keras 上。DeepPavlov框架层次: Agent同用户直接交互的代理,直接接收用户输入的纯文本信息(raw text) Skill领域技能,如基于意图-词槽的任务型技能,基于Seq2Seq的闲聊技能,基于知识图谱的知识问答技能; Skill Manager确定用户query,选择使用哪些skill,并确定将哪一个skill的召回结果作为最终的回复; ComponentSkill实现的组成部分,如针对任务型技能,包括数据预处理component、意图识别component、slotfilling component等; DeepPavlov内置的skill主要包括: 任务型skill(Goal-Oriented Dialogue Bot)基于意图/词槽/对话管理等component实现的问答skill。 规则型skill(Pattern Matching)基于自定义规则实现问答skill。 Seq2Seq skill(Sequence-To-Sequence Dialogue Bot)基于Seq2Seq实现问答skill。 阅读理解skill(Open-Domain Question Answering)基于阅读理解实现问答skill。相对于阅读理解component(Context Question Answering),skill还包含在多个召回结果中进行排序的能力。 DeepPavlov内置的基本能力主要包括: 数据预处理component(Data processors)主要提供包括分词、嵌入向量化等预处理能力(主要基于俄文和英文)。 阅读理解component(Context Question Answering)相对于阅读理解skill(Open-Domain Question Answering),component不包含对多个召回结果进行排序(rank)的能力。具体的处理场景示例如下, 分类component(Classification)分类组件,可以用来做场景和意图的分类。 命名实体识别component(Named Entity Recognition)NER能力组件。 相似度计算component(Neural Ranking)通过基于孪生网络完成相似度计算,实现在标准问答库中标准答复的查找。 词槽填充component(Slot filling)在NER的基础上,增加了词表限制。 *拼写纠错component(Spelling Correction)提供了两种纠错方法: levenshtein_corrector :基于编辑距离;brillmoore:基于统计模型 TF-IDF排序component(TF-IDF Ranking)基于TF-IDF的文档召回排序。 按照介绍所说,这个框架可以覆盖任务式(填槽skill)、问答式(相似度计算skill)、闲聊式(端到端训练技术)。直接就是一个复合框架。 下一步计划是对这个项目试用调研。 参考:https://zhuanlan.zhihu.com/p/58133705 3 总结3.1 希望达到了效果我们客服的问答系统 需要达到的效果: 能简单闲聊,比如:你好,有什么可以帮你?(占比10%) 能回答知识性问题,比如:怎么修改云闪付手机号?(占比40%) 能回答规则类问题,比如:我云闪付电费交不了怎么办?需要填槽省份信息、错误代码信息等。(50%) 3.2 需要的模式因此,我们的系统需要像阿里的架构一样,包含多种问答模式,满足不同需求。 首先使用 规则模版 解决规则类问题。(使用rasa填槽) 解决不了的,使用相似度匹配的完成知识类问答。(可以使用chatterbot) 相似度信度低于 阈值,可以使用谷歌DeepQA生成式、可以使用RASA闲聊意图、可以自己配置一些问答数据在chatterbot中。 3.3 集成的方法如何将三种问答模型 结合起来? 可行的办法: 单独编写一个框架,把上述三种QA封装成三个模块。 利用chatterbot,可以自定义模块的特性。 把 rasa(结构化QA)和 闲聊(Seq2Seq生成式) 封装为两个接口。 使用DeepPavlov 直接包含三种模式。 下一步计划,调研DeepPavlov的可用性。","link":"/2019/06/17/2019-06-17问答系统项目落地调研/"},{"title":"2019-07-09 Pycharm激活码 和 远程连接服务器","text":"1 下载安装pycharm professional专业版1.1 下载安装 一般学习用直接安装社区版本即可,足够用,直接安装即可。但是,我们希望通过pycharm 连接远程服务器,这项功能只有专业版才有,所以我们选择Windows系统的专业版下载。 1、当下载好以后,点击安装,记得修改安装路径,我这里放的是E盘,修改好以后,Next 点击Install,然后就是静静的等待安装了。 1.2破解由于我们的pycharm是装在公司的电脑上,所以最好的破解方式是找到可用的激活码,而不要动机子上本身的文件。(之前有次用破解软件 导致公司杀毒报错,直接强制重装电脑,防止机密泄漏,很生气) 1.2.1 修改hosts文件:1.2.1.1 windwos系统hosts文件打开hosts文件,其中: windwos系统hosts文件路径为:C:\\Windows\\System32\\drivers\\etc 添加下面一行到hosts文件,目的是屏蔽掉Pycharm对激活码的验证 :10.0.0.0 account.jetbrains.com 如果遇到权限问题,可将hosts文件先复制出来修改后再覆盖原来的即可。 1.2.1.2 linux系统hosts文件 Linux和mac的hosts文件路径为:/etc 添加下面一行到hosts文件,目的是屏蔽掉Pycharm对激活码的验证 :10.0.0.0 account.jetbrains.com 具体操作为: 1234567cd /etcsudo vim hosts输入密码i粘贴**0.0.0.0 account.jetbrains.com**到文件最底部按esc输入 :wq 退出修改 1.2.2 输入激活码打开PyCharm,选择Activate code(用激活码激活) 复制下载激活码,填入激活码框。 156ZS5PQ1RF-eyJsaWNlbnNlSWQiOiI1NlpTNVBRMVJGIiwibGljZW5zZWVOYW1lIjoi5q2j54mI5o6I5p2DIC4iLCJhc3NpZ25lZU5hbWUiOiIiLCJhc3NpZ25lZUVtYWlsIjoiIiwibGljZW5zZVJlc3RyaWN0aW9uIjoiRm9yIGVkdWNhdGlvbmFsIHVzZSBvbmx5IiwiY2hlY2tDb25jdXJyZW50VXNlIjpmYWxzZSwicHJvZHVjdHMiOlt7ImNvZGUiOiJJSSIsInBhaWRVcFRvIjoiMjAyMC0wMy0xMCJ9LHsiY29kZSI6IkFDIiwicGFpZFVwVG8iOiIyMDIwLTAzLTEwIn0seyJjb2RlIjoiRFBOIiwicGFpZFVwVG8iOiIyMDIwLTAzLTEwIn0seyJjb2RlIjoiUFMiLCJwYWlkVXBUbyI6IjIwMjAtMDMtMTAifSx7ImNvZGUiOiJHTyIsInBhaWRVcFRvIjoiMjAyMC0wMy0xMCJ9LHsiY29kZSI6IkRNIiwicGFpZFVwVG8iOiIyMDIwLTAzLTEwIn0seyJjb2RlIjoiQ0wiLCJwYWlkVXBUbyI6IjIwMjAtMDMtMTAifSx7ImNvZGUiOiJSUzAiLCJwYWlkVXBUbyI6IjIwMjAtMDMtMTAifSx7ImNvZGUiOiJSQyIsInBhaWRVcFRvIjoiMjAyMC0wMy0xMCJ9LHsiY29kZSI6IlJEIiwicGFpZFVwVG8iOiIyMDIwLTAzLTEwIn0seyJjb2RlIjoiUEMiLCJwYWlkVXBUbyI6IjIwMjAtMDMtMTAifSx7ImNvZGUiOiJSTSIsInBhaWRVcFRvIjoiMjAyMC0wMy0xMCJ9LHsiY29kZSI6IldTIiwicGFpZFVwVG8iOiIyMDIwLTAzLTEwIn0seyJjb2RlIjoiREIiLCJwYWlkVXBUbyI6IjIwMjAtMDMtMTAifSx7ImNvZGUiOiJEQyIsInBhaWRVcFRvIjoiMjAyMC0wMy0xMCJ9LHsiY29kZSI6IlJTVSIsInBhaWRVcFRvIjoiMjAyMC0wMy0xMCJ9XSwiaGFzaCI6IjEyMjkxNDk4LzAiLCJncmFjZVBlcmlvZERheXMiOjAsImF1dG9Qcm9sb25nYXRlZCI6ZmFsc2UsImlzQXV0b1Byb2xvbmdhdGVkIjpmYWxzZX0=-SYSsDcgL1WJmHnsiGaHUWbaZLPIe2oI3QiIneDtaIbh/SZOqu63G7RGudSjf3ssPb1zxroMti/bK9II1ugHz/nTjw31Uah7D0HqeaCO7Zc0q9BeHysiWmBZ+8bABs5vr25GgIa5pO7CJhL7RitXQbWpAajrMBAeZ2En3wCgNwT6D6hNmiMlhXsWgwkw2OKnyHZ2dl8yEL+oV5SW14t7bdjYGKQrYjSd4+2zc4FnaX88yLnGNO9B3U6G+BuM37pxS5MjHrkHqMTK8W3I66mIj6IB6dYXD5nvKKO1OZREBAr6LV0BqRYSbuJKFhZ8nd6YDG20GvW6leimv0rHVBFmA0w==-MIIElTCCAn2gAwIBAgIBCTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTE4MTEwMTEyMjk0NloXDTIwMTEwMjEyMjk0NlowaDELMAkGA1UEBhMCQ1oxDjAMBgNVBAgMBU51c2xlMQ8wDQYDVQQHDAZQcmFndWUxGTAXBgNVBAoMEEpldEJyYWlucyBzLnIuby4xHTAbBgNVBAMMFHByb2QzeS1mcm9tLTIwMTgxMTAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcQkq+zdxlR2mmRYBPzGbUNdMN6OaXiXzxIWtMEkrJMO/5oUfQJbLLuMSMK0QHFmaI37WShyxZcfRCidwXjot4zmNBKnlyHodDij/78TmVqFl8nOeD5+07B8VEaIu7c3E1N+e1doC6wht4I4+IEmtsPAdoaj5WCQVQbrI8KeT8M9VcBIWX7fD0fhexfg3ZRt0xqwMcXGNp3DdJHiO0rCdU+Itv7EmtnSVq9jBG1usMSFvMowR25mju2JcPFp1+I4ZI+FqgR8gyG8oiNDyNEoAbsR3lOpI7grUYSvkB/xVy/VoklPCK2h0f0GJxFjnye8NT1PAywoyl7RmiAVRE/EKwIDAQABo4GZMIGWMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGEpG9oZGcfLMGNBkY7SgHiMGgTcMEgGA1UdIwRBMD+AFKOetkhnQhI2Qb1t4Lm0oFKLl/GzoRykGjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBggkA0myxg7KDeeEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQAF8uc+YJOHHwOFcPzmbjcxNDuGoOUIP+2h1R75Lecswb7ru2LWWSUMtXVKQzChLNPn/72W0k+oI056tgiwuG7M49LXp4zQVlQnFmWU1wwGvVhq5R63Rpjx1zjGUhcXgayu7+9zMUW596Lbomsg8qVve6euqsrFicYkIIuUu4zYPndJwfe0YkS5nY72SHnNdbPhEnN8wcB2Kz+OIG0lih3yz5EqFhld03bGp222ZQCIghCTVL6QBNadGsiN/lWLl4JdR3lJkZzlpFdiHijoVRdWeSWqM4y0t23c92HXKrgppoSV18XMxrWVdoSM3nuMHwxGhFyde05OdDtLpCv+jlWf5REAHHA201pAU6bJSZINyHDUTB+Beo28rRXSwSh3OUIvYwKNVeoBY+KwOJ7WnuTCUq1meE6GkKc4D/cXmgpOyW/1SmBz3XjVIi/zprZ0zf3qH5mkphtg6ksjKgKjmx1cXfZAAX6wcDBNaCL+Ortep1Dh8xDUbqbBVNBL4jbiL3i3xsfNiyJgaZ5sX7i8tmStEpLbPwvHcByuf59qJhV/bZOl8KqJBETCDJcY6O2aqhTUy+9x93ThKs1GKrRPePrWPluud7ttlgtRveit/pcBrnQcXOl1rHq7ByB8CFAxNotRUYL9IF5n3wJOgkPojMy6jetQA5Ogc8Sm7RG6vg1yow== 复制上面的激活码,填入激活码框,点击 OK 进行认证。注册码有效期为2019年3月10日至2020年3月11日 参考:https://blog.csdn.net/qq_33733970/article/details/79251120 2 远程连接公司服务器配置了pycharm远程连接服务器,这样不用总是到代码里修改,直接在windows下pycharm里修改再保存就可以实现同步更新到服务器里的代码里了。 主要流程为:Pycharm本身提供了一个Deployment工具,可以直接整合上述流程,将本地代码和服务器代码做一个映射,然后修改本地代码时,自动或手动上传服务器同步,然后通过Pycharm的SSH Terminal重启进程验证。 2.1 连接远程服务器1、菜单->Tools->Deployment->Configuration 2、协议选择SFTP协议;并添加需要连接的服务器,填入ip,用户名和密码。 点击Test SFTP connection会发现,如果连接成功会提示你如下: 2.2 设置第二个标签页Mappings配置代码映射: 下面选择连接windows下的那部分代码和服务器上代码相连,Mappings,本地Local path,服务器path。 2.3 自动上传修改的文件菜单->Tools->Deployment->Options,将“Upload changed files automatically to the default server”改为 “On explicit save action”,然后你每次Ctrl+s的时候,修改的代码就自动上传了 2.4 解决乱码在pycharm里tools->start ssh session可以使用ssh,使用ssh时候发现打开中文乱码,在settings里修改,如下图: 2.5 PyCharm远程调试运行SSH Terminal,Deployment配置好之后,直接运行SSH Terminal,就可以在Pycharm中,开一个SSH终端,直接重启进程、看日志啥的,很方便 (注意:新版本的pycharm按钮变为 “start SSH session”) 参考:https://blog.csdn.net/zhaihaifei/article/details/53691873","link":"/2019/07/09/2019-07-09 Pycharm激活码 和 远程连接服务器/"},{"title":"AttributeError:FeedExporter object has no attribute slot","text":"使用scrapy时候你报错: AttributeError: ‘FeedExporter’ object has no attribute ‘slot’ 因为当前需要写入的文件被占用,写不进去! 解决方法,关闭打开的 csv文件","link":"/2017/05/20/AttributeError:FeedExporter object has no attribute slot/"},{"title":"EndNote X7如何在论文中嵌入中文定格式要求的参考文献","text":"1. EndNote X7下载安装破解一条龙1.1 下载EndNote X7下载地址(内含软件以及破解文件):https://pan.baidu.com/s/1nxcdENv密码:9bwp 1.2 安装安装过程比较简单,所有设置默认选择即可,点击 “Next”或 “Accept”完成安装。 点击 “Finish”完成安装。 1.3 破解把“破解文件夹”里面的文件放入安装目录即可。 2.使用EndNote X7创建库安装好之后,第一次打开EndNote,会显示如下的界面: 选择中间的那个”Create a new library”,创建一个新的库。此时,会弹出如下的文件框: 文件名称默认是My EndNote Library.enl,存放位置最好自己选定,在某个盘下面新建一个文件夹来存放(建议一个论文,或者一个类型的论文设置一个库),以后如果换电脑了,可以把这个文件拷走,继续使用。我保存的位置是F:\\EndNote Library\\,EndNote Library是我在F盘下新建的文件夹,如下: 点击保存就好了,可以打开这个文件夹,例如,我打开EndNote Library文件夹,里面有EndNote生成的两个东东,如下: 此时,EndNote的库已经创建好了。 要怎么使用呢?继续看下面的。 刚才Create a new library之后,弄好了库的位置,EndNote的界面显示如下: 3. 使用中文格式3.1 下载中文格式因为不同的期刊对参考文献的格式不同,所以在使用EndNote自动生成并嵌入参考文献之前,你需要做一件事,就是找到这个期刊要求的参考文献格式文件,EndNote使用的期刊格式文件是以ens为后缀的文件,当然EndNote本身就自带了很多期刊的格式文件,如果没有你要投的期刊的格式文件的话,就要你自己找了。 其实不用在网上找别人的下载,endnot官网就有所有的格式: http://endnote.com/downloads/styles 搜索关键字“Chinese”: 发现有两个“国标”,大部分情况下下载第一个:带数字序号的如:[1] 找到格式文件之后,要把格式文件放到EndNote安装目录下的Styles文件夹下。 例如,我就把Chinese Standard GB/T7714 (numeric).ens放到了我的EndNote安装目录的Styles文件夹下了,注意:是安装目录,不是刚才的库目录,当然库目录下也没有Styles文件夹。放好后如下图所示: 这是关键的一步,这步完成之后,下面的就轻松了。 3.2 配置中文格式为了使用对应期刊的格式来生成参考文献,你需要在EndNote中选择该期刊的格式,如下图所示,在下拉框中会默认显示几个期刊的名称,如果有你需要的直接选定就好了,如果没有你需要的期刊,则选择Select Another Style…。操作如下图所示: 点击了Select Another Style…之后,会弹出一个框,如下所示: 在上面的滑动框中选择你要的期刊的格式,也就是你找到的期刊后缀为ens的格式文件的名称。例如,此处,我选择Chinese Standard GB/T7714 (numeric),双击一下就行了。此时期刊格式已选择好,如下图所示: 4.插入中文格式的论文4.1找参考文献格式都弄好了,下面我以一篇文章为例,来说明如何生成参考文献以及如何导入到你的Word论文中。我用这篇论文:Clustering Vessel Trajectories with Alignment Kernels under Trajectory Compression ,把参考论文的题目复制后,去google学术,如果google学术登录不了,可以去glgoo学术(和google学术一样)搜索一下,如下(也可以在知网里搜索,具体方法见:点击打开链接): 大家应该都不陌生,平常大家都直接复制参考文献格式使用,很少关注最下面的一行:BibTex EndNote RefMan RefWorks,或许并不知道这是干嘛用的。既然有EndNote,那此处就是用到了,点击EndNote,如下: 点击EndNote,会自动下载一个文件,文件名字叫scholar.enw,比如我下到C盘下面,放到哪里都行,最好放到刚才创建的库目录里,可以在库目录里再建一个文件夹来存放这类文件: 现在转到EndNote,看看如何使用这个scholar.enw文件,见下图: 首先,点击界面上的向下的绿色的箭头来导入刚才的scholar.enw文件,点击后,会弹出Import File对话框,点击Choose…按钮,会弹出文件选择对话框,选择刚才下载的scholar.enw文件,注意:在Import File对话框的”Import Option”一项中,要选择EndNote Import,而不能是默认的EndNote Library,要不然不会生成参考文献。导入后,你就会发现,在EndNote中出现了一个生成好的参考文献引用,如下图所示: 4.2插入word既然已经生成好了,要怎么用呢?继续。。。安装好了EndNote之后,Word中会自动在菜单栏上显示EndNote X7的菜单项,如下所示: 例如,我要在下面的文章的某处插入一个参考文献,就把光标放到要插入参考文献的地方,如下图: 我想在最后的“1011份”这个地方插入刚才生成的参考文献。直接点击Word菜单栏上的EndNote X7,然后点击最左侧的“Go to EndNote”,会打开EndNote,默认会打开你最近使用的库(就是你在开头创建的库,可以创建好多个),如下: 选择你要嵌入到Word中的参考文献,然后点击嵌入的按钮,就会自动在Word文章的最末尾生成参考文献引用,嵌入按钮如下图红圈标记的: 这样,所有的工作就完成了,嵌入的效果如下图所示: 参考文献都是自动生成在文章的最后面的。嵌入之后,你还可以在对参考文献进行修改,比如调整字体啥的。在文章中的这些参考文献编号都有链接功能,点击编号即可跳转到文章后面的参考文献处。参考文献的编号会根据你嵌入的位置从前往后依次排开很方便,如果你在两个参考文献中间再插入一个参考文献,后面的位置会自动更新;如果在某个位置有多个参考文献,EndNote还会帮你缩写成[3-6]这样的格式。而且,如果你以后的文章中要引用相同的文章,直接嵌入就行了。 刚开始,你可能觉得太烦了,我也是这么认为。直接在谷歌学术里搜一下不就有了,但是,谷歌生成的三个参考文献可能都不满足某个期刊的要求,那么EndNote就派上用场了。","link":"/2018/01/30/EndNote X7如何在论文中嵌入中文定格式要求的参考文献/"},{"title":"Keras1基础知识与安装.md","text":"[toc] Keras:1 基础知识与安装1.1 为什么学习keras1.1.1 keras的优点如果说 Tensorflow 或者 Theano 神经网络方面的巨人. 那 Keras 就是站在巨人肩膀上的人. Keras 是一个兼容 Theano 和 Tensorflow 的神经网络高级包, 用他来组件一个神经网络更加快速, 几条语句就搞定了. 而且广泛的兼容性能使 Keras 在 Windows 和 MacOS 或者 Linux 上运行无阻碍。如果对机器学习还不是很了解的朋友们, 可以大概粗略的看一遍莫烦的 机器学习-简介系列. 这个系列非常的简单通俗, 大多视频不过5分钟. 有了这些机器学习的基础. 使用 Keras 起来就更容易. 因为磨刀不误砍柴工. 如果你的时间很充裕, 也可以从莫烦的 Theano 教程 或者 Tensorflow 教程 看起, 这里有更加全面的知识框架. 1.1.2 我的进程学习了tensorflow一段时间以来,对tensorflow有了更全面与直观的了解,这样学习keras来也会更加得心应手。keras确实更适合快速的进行模型的建立。 实验室师兄的论文的实验就是用keras实现的,更加激发了我尽快学习keras的兴趣。与上次一样,这个系列的笔记是我学习莫烦大大的视频教程的笔记。方便我自己回过头来进行复盘,以及加上自己的感悟。 推荐大家多多关注莫烦:https://morvanzhou.github.io/about/多多给他赞助~ 1.2 安装keras 在安装 Keras 之前, 需要确认自己已经安装好了 Numpy 和 Scipy. 可参考我的 Numpy 安装教程 因为 Keras 是基于 Tensorflow 或者 Theano 的. 所以可以先自己安装 Tensorflow 或者 Theano. 可参考我的Tensorflow 安装教程 或者 Theano 安装教程 安装 Keras. 在你的 Terminal 窗口中输入. 1pip install keras 验证是否安装成功? Terminal 窗口中输入python,进入python环境 输入import keras,回车 界面显示Using tensorflow Backend 1.3后台兼容 backend我们来介绍 Keras 的两个 Backend,也就是Keras基于什么东西来做运算。 Keras 可以基于两个Backend,一个是 Theano(发音:涩啊NO),一个是 Tensorflow。如果我们选择Theano作为Keras的Backend, 那么Keras就用 Theano 在底层搭建你需要的神经网络;同样,如果选择 Tensorflow 的话呢,Keras 就使用 Tensorflow 在底层搭建神经网络。 目前 Tensorflow 支持 Mac 和 Linux 系统(现在也支持windows了),而 Theano 不但支持包括 Mac 和 Linux,还支持 Windows 系统, 所以我们就可以选择自己可以用的 Backend 就可以。我推荐tensorflow哦,大势所趋,坐等一年后打脸。 1.3.1 如何看当前使用的是什么后台Backend每次当我们import keras的时候,就会看到屏幕显示当前使用的 Backend 1Using Theano Backend 这就说明现在使用的是Theano在作Backend。 1.3.2 如何修改Backend打开文件(按ctrl + h 显示隐藏文件)1~/.keras/keras.json 文件内容: 123456{ "image_dim_ordering": "tf", "epsilon": 1e-07, "floatx": "float32", "backend": "theano"} 每次import的时候,keras 就会检查这个 keras.json 文件。一般我们以为,如果需要把 Backend 改成 Tensorflow 的话,只需要改动最后一行”backend”对应的值,修改后的文件内容: 123456{ "image_dim_ordering": "tf", "epsilon": 1e-07, "floatx": "float32", "backend": "tensorflow"} 但这样修改后,import 的时候会出现错误信息。 解决的方法有几种: 可以在其他文本编辑器内编辑好这段文本,然后整体拷贝到这个文件里。 在python代码中import keras前加入一个环境变量修改的语句: 12import osos.environ['KERAS_BACKEND']='theano' 这时import keras就会显示Using Theano backend。 第2种修改影响的范围是仅这个脚本内,所以其他文件的执行Keras还是会去找keras.json配置文件来确定用什么backend。","link":"/2017/08/24/Keras1基础知识与安装/"},{"title":"Linux安装jdk以及eclipse安装Anaconda与pyChram","text":"1.安装jdk1源码包准备首先到官网下载jdk,http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html,我下载jdk-8u25-linux-x64.tar.gz,下载到主目录 2、解压源码包通过终端在/usr/local目录下新建java文件夹,命令行: 1sudo mkdir /usr/local/java 然后将下载到压缩包拷贝到java文件夹中,命令行: 1cp jdk-8u25-linux-x64.tar.gz /usr/local/java 然后进入java目录,命令行: 1cd /usr/local/java 解压压缩包,命令行: 1sudo tar -zxvf jdk-8u25-linux-x64.tar.gz 然后可以把压缩包删除,命令行: 1sudo rm jdk-8u25-linux-x64.tar.gz 3、设置jdk环境变量要对profile进行配置:输入命令: 1sudo vim /etc/profile 按i进入插入模式,并写入: 1234export JAVA_HOME=/usr/local/java/jdk1.8.0_144export JRE_HOME=//usr/local/java/jdk1.8.0_144/jreexport CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATHexport PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH 4 重启linux5、检查在终端输入如下命令 1java -version 2.安装eclipse1下载:eclipse-SDK-3.7.2-linux-gtk.tar.gz 在地址:http://www.eclipse.org/downloads/ 2放入指定文件夹把压缩包放入/home/xqt/software 3解压安装包1tar -zxvf eclipse-SDK-4.2-linux-gtk.tar.gz 4启动eclipse 进入eclipse文件夹,点击eclipse文件。 并把他固定在启动器上 linux安装Anaconda与pyChram1linux安装Anaconda1 下载(直接到清华镜像下载)https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/,选择合适的版本。 2 安装anaconda进入下载目录,输入命令 1bash Anaconda3-4.3.1-Linux-x86.sh 在安装的过程中,会问你安装路径,直接回车默认就可以了。有个地方问你是否将anaconda安装路径加入到环境变量(.bashrc)中,输入yes,默认的是no, 如果10秒内没输入就要配置环境,根据提示,在终端输入1sudo gedit ~/bashrc 打开profile文件。添加语句1export PATH=/home/xqt/anaconda3/bin:$PATH ,保存,退出。 (想卸载的时候别忘记把这句话删除) 3 重启linux配置好PATH后,可以通过which conda或conda –version命令检查是否正确。 输入conda list 就可以查询,你现在安装了哪些库,常用的numpy, scipy名列其中。 如果你还有什么包没有安装上,可以运行conda install * 来进行安装, 如果某个包版本不是最新的,运行 conda update * 就可以了。 4 验证输入import scipy ,没有报错则安装成功 打开jupyter notebook 也只需要在终端输入: jupyter notebook 由于anaconda在linux下是安装在一个文件夹里/home/anaconda ,如果安装过程中出错问题,或者想更新另一个版本,删除anaconda也很方便,执行下面命令 1rm -rf ~/anaconda linux安装pyChram1 下载百度搜索pycharm然后打开pycharm的官网然后在官网首页点击down 2 解压打开刚才下载的目录,复制到/home/xqt/software 右击文件,点击提取到此处(这与Windows的解压是一个意思)解压完成后,可以看到文件夹 3 安装打开刚才解压好的文件夹然后再打开bin目录 在此处打开终端然后输入:1./pycharm.sh 开始安装(.sh 是一个脚本文件,相当于win下的.exe)回车","link":"/2017/08/14/Linux安装jdk以及eclipse安装Anaconda与pyChram/"},{"title":"Python - 如何拆分没有空格的文本为单词列表?将组合单词拆分开","text":"python - 如何拆分没有空格的文本为单词列表?将组合单词拆分开很多时候,我们需要把一长串单词字符拆分开来,比如: 输入:“tableapplechairtablecupboard …”很多字。我们希望有一个有效的算法来分割这样的文本到单词列表,并得到: 输出:[“table”,“apple”,“chair”,“table”,“cup”,“board”] 或者将一个很长的函数名拆分成小单词: WbxNewBrowserInstance 变为 [ wbx new browser instance ] 1算法的思想算法的思想是:通过所有可能的单词(从第一个字母开始),并找到最长的单词可能 ,插入空格。 所以我们需要一个 “常用单词列表”。 后面的方法是对输出的分布进行建模。良好的第一近似是假设所有单词是独立分布的。然后你只需要知道所有单词的相对频率。可以合理地假定它们遵循Zipf定律,即在单词列表中具有秩n的单词具有大约1 /(n log N)的概率,其中N是字典中的单词数。 一旦你修正了模型,你可以使用动态规划来推断空格的位置。最可能的句子是最大化每个单词的概率的乘积,并且很容易用动态规划来计算它。不是直接使用概率,而是使用定义为概率的倒数的对数的成本来避免溢出。 2代码12345678910111213141516171819202122232425262728293031323334353637def cutLongNameFun(self,s): ''' longWords变为 long word:log里面有很多长函数名,比如WbxMeeting_VerifyMeetingIsExist。 将其拆成小单词wbx meeting verify meeting is exist,更有意义。若有大写则分割。 ''' # Build a cost dictionary, assuming Zipf's law and cost = -math.log(probability). # 建立一个成本字典,假设Zipf定律和成本= -math.log(概率)。 words = open("words-by-frequency.txt").read().split() # 有特殊字符的话直接在其中添加 wordcost = dict((k, log((i+1)*log(len(words)))) for i,k in enumerate(words)) maxword = max(len(x) for x in words) def infer_spaces(s): '''Uses dynamic programming to infer the location of spaces in a string without spaces. .使用动态编程来推断不带空格的字符串中空格的位置。''' # Find the best match for the i first characters, assuming cost has # been built for the i-1 first characters. # Returns a pair (match_cost, match_length). def best_match(i): candidates = enumerate(reversed(cost[max(0, i-maxword):i])) return min((c + wordcost.get(s[i-k-1:i], 9e999), k+1) for k,c in candidates) # Build the cost array. cost = [0] for i in range(1,len(s)+1): c,k = best_match(i) cost.append(c) # Backtrack to recover the minimal-cost string. out = [] i = len(s) while i>0: c,k = best_match(i) assert c == cost[i] out.append(s[i-k:i]) i -= k return " ".join(reversed(out)) 使用实例: 1234s = 'thumbgreenappleactiveassignmentweeklymetaphor'print(infer_spaces(s))# 结果为 thumb green apple active assignment weekly metaphor. 123456Before: thereismassesoftextinformationofpeoplescommentswhichisparsedfromhtmlbuttherearenodelimitedcharactersinthemforexamplethumbgreenappleactiveassignmentweeklymetaphorapparentlytherearethumbgreenappleetcinthestringialsohavealargedictionarytoquerywhetherthewordisreasonablesowhatsthefastestwayofextractionthxalot.After: there is masses of text information of peoples comments which is parsed from html but there are no delimited characters in them for example thumb green apple active assignment weekly metaphor apparently there are thumb green apple etc in the string i also have a large dictionary to query whether the word is reasonable so what s the fastest way of extraction thx a lot. 正如你可以看到,这个算法基本上是完美的。最重要的部分是确保你的单词列表训练到一个类似于你实际遇到的语料库,否则结果将是非常糟糕。所以你应该手工完善自己的单词库。 3下载words-by-frequency.txt 这个文件下载:http://download.csdn.net/download/u012052268/10263440","link":"/2018/02/28/Python - 如何拆分没有空格的文本为单词列表?将组合单词拆分开/"},{"title":"Python 繁体中文与简体中文相互转换","text":"工作中需要将繁体中文转换成简体中文上网找了些资料,发现这个包最方便 1 安装不需要什么安装方法,只需要把这两个文件下载下来,保存到与代码同一目录下即可 https://raw.githubusercontent.com/skydark/nstools/master/zhtools/langconv.pyhttps://raw.githubusercontent.com/skydark/nstools/master/zhtools/zh_wiki.py 打包下载地址:http://download.csdn.net/download/u012052268/9996650 2 使用方法2.1 繁体转简体1234567891011121314151617181920from langconv import *def Traditional2Simplified(sentence): ''' 将sentence中的繁体字转为简体字 :param sentence: 待转换的句子 :return: 将句子中繁体字转换为简体字之后的句子 ''' sentence = Converter('zh-hans').convert(sentence) return sentenceif __name__==\"__main__\": traditional_sentence = '憂郁的臺灣烏龜' simplified_sentence = Traditional2Simplified(traditional_sentence) print(simplified_sentence) ''' 输出结果: 忧郁的台湾乌龟 ''' 2.2 简体转繁体12345678910111213141516171819202122from langconv import *from langconv import *def Simplified2Traditional(sentence): ''' 将sentence中的简体字转为繁体字 :param sentence: 待转换的句子 :return: 将句子中简体字转换为繁体字之后的句子 ''' sentence = Converter('zh-hant').convert(sentence) return sentenceif __name__==\"__main__\": simplified_sentence = '忧郁的台湾乌龟' traditional_sentence = Simplified2Traditional(simplified_sentence) print(traditional_sentence) ''' 输出结果: 憂郁的臺灣烏龜 ''' 3实例:第一步打开文本文件,for读取每句繁体123456789with open('question_labels.json', 'r',encoding='UTF-8') as f: question_labels = json.load(f)q_zh = [] # Data中问题的中文for line in question_labels: q_zh.append(line['q_zh'])print(q_zh)# ['請問京都議定書規定幾個工業國家的二氧化碳排放量限制?', '請問首位自費太空旅行的觀光客為誰?', 第二步转换 12345678910def Traditional2Simplified(sentence): sentence = langconv.Converter('zh-hans').convert(sentence) return sentenceq_zh_jian = []for line in q_zh: q_zh_jian.append(Traditional2Simplified(line))print(q_zh_jian)# ['请问京都议定书规定几个工业国家的二氧化碳排放量限制?', '请问首位自费太空旅行的观光客为谁?', '请问","link":"/2017/09/03/Python 繁体中文与简体中文相互转换/"},{"title":"Python3 面向对象","text":"Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。 如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。 接下来我们先来简单的了解下面向对象的一些基本特征。 1.面向对象技术简介类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。 实例变量:定义在方法中的变量,只作用于当前实例的类。 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟”是一个(is-a)”关系(例图,Dog是一个Animal)。 实例化:创建一个类的实例,类的具体对象。 方法:类中定义的函数。 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。 和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。 Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。 对象可以包含任意数量和类型的数据。 2.类定义语法格式如下: 123456class ClassName: <statement-1> . . . <statement-N> 类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。 2.类对象类对象支持两种操作:属性引用和实例化。 属性引用使用和 Python 中所有的属性引用一样的标准语法:obj.name。 类对象创建后,类命名空间中所有的命名都是有效属性名。所以如果类定义是这样: 1234567891011121314#!/usr/bin/python3class MyClass: """一个简单的类实例""" i = 12345 def f(self): return 'hello world'# 实例化类x = MyClass()# 访问类的属性和方法print("MyClass 类的属性 i 为:", x.i)print("MyClass 类的方法 f 输出为:", x.f()) 以上程序输出结果为:12MyClass 类的属性 i 为: 12345MyClass 类的方法 f 输出为: hello world 很多类都倾向于将对象创建为有初始状态的。因此类可能会定义一个名为 __init__() 的特殊方法(构造方法),像下面这样:12def __init__(self): self.data = [] 当然, __init__() 方法可以有参数,参数通过 __init__() 传递到类的实例化操作上。例如:12345678>>> class Complex:... def __init__(self, realpart, imagpart):... self.r = realpart... self.i = imagpart...>>> x = Complex(3.0, -4.5)>>> x.r, x.i(3.0, -4.5) self代表类的实例,而非类类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。 1234567class Test: def prt(self): print(self) print(self.__class__) t = Test()t.prt() 以上实例执行结果为: 12<__main__.Test instance at 0x100771878>__main__.Test 从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。 4.类的方法在类地内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数: 1234567891011121314151617181920#!/usr/bin/python3#类定义class people: #定义基本属性 name = '' age = 0 #定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0 #定义构造方法 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s 说: 我 %d 岁。" %(self.name,self.age))# 实例化类p = people('runoob',10,30)p.speak() 执行以上程序输出结果为:1runoob 说: 我 10 岁。 5.继承Python 同样支持类的继承,如果一种语言不支持继承,类就没有什么意义。派生类的定义如下所示: 需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找基类中是否包含方法。BaseClassName(示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用: 1234567891011121314151617181920212223242526272829303132#!/usr/bin/python3#类定义class people: #定义基本属性 name = '' age = 0 #定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0 #定义构造方法 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s 说: 我 %d 岁。" %(self.name,self.age))#单继承示例class student(people): grade = '' def __init__(self,n,a,w,g): #调用父类的构函 people.__init__(self,n,a,w) self.grade = g #覆写父类的方法 def speak(self): print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))s = student('ken',10,60,3)s.speak() 执行以上程序输出结果为:1ken 说: 我 10 岁了,我在读 3 年级 多继承Python同样有限的支持多继承形式。多继承的类定义形如下例: 需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#!/usr/bin/python3#类定义class people: #定义基本属性 name = '' age = 0 #定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0 #定义构造方法 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s 说: 我 %d 岁。" %(self.name,self.age))#单继承示例class student(people): grade = '' def __init__(self,n,a,w,g): #调用父类的构函 people.__init__(self,n,a,w) self.grade = g #覆写父类的方法 def speak(self): print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))#另一个类,多重继承之前的准备class speaker(): topic = '' name = '' def __init__(self,n,t): self.name = n self.topic = t def speak(self): print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))#多重继承class sample(speaker,student): a ='' def __init__(self,n,a,w,g,t): student.__init__(self,n,a,w,g) speaker.__init__(self,n,t)test = sample("Tim",25,80,4,"Python")test.speak() #方法名同,默认调用的是在括号中排前地父类的方法 执行以上程序输出结果为:1我叫 Tim,我是一个演说家,我演讲的主题是 Python 6.方法重写如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法,实例如下: 123456789101112#!/usr/bin/python3class Parent: # 定义父类 def myMethod(self): print ('调用父类方法')class Child(Parent): # 定义子类 def myMethod(self): print ('调用子类方法')c = Child() # 子类实例c.myMethod() # 子类调用重写方法 执行以上程序输出结果为:1调用子类方法 7.类属性与方法类的私有属性private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 self.private_attrs。 类的方法在类地内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数 类的私有方法private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用 self.private_methods。 实例类的私有属性实例如下: 12345678910111213141516#!/usr/bin/python3class JustCounter: __secretCount = 0 # 私有变量 publicCount = 0 # 公开变量 def count(self): self.__secretCount += 1 self.publicCount += 1 print (self.__secretCount)counter = JustCounter()counter.count()counter.count()print (counter.publicCount)print (counter.__secretCount) # 报错,实例不能访问私有变量 类的私有方法实例如下: 12345678910111213141516171819202122#!/usr/bin/python3class Site: def __init__(self, name, url): self.name = name # public self.__url = url # private def who(self): print('name : ', self.name) print('url : ', self.__url) def __foo(self): # 私有方法 print('这是私有方法') def foo(self): # 公共方法 print('这是公共方法') self.__foo()x = Site('菜鸟教程', 'www.runoob.com')x.who() # 正常输出x.foo() # 正常输出x.__foo() # 报错 类的专有方法:1234567891011121314__init__ : 构造函数,在生成对象时调用__del__ : 析构函数,释放对象时使用__repr__ : 打印,转换__setitem__ : 按照索引赋值__getitem__: 按照索引获取值__len__: 获得长度__cmp__: 比较运算__call__: 函数调用__add__: 加运算__sub__: 减运算__mul__: 乘运算__div__: 除运算__mod__: 求余运算__pow__: 称方 运算符重载Python同样支持运算符重载,我么可以对类的专有方法进行重载,实例如下: 12345678910111213141516#!/usr/bin/python3class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b)v1 = Vector(2,10)v2 = Vector(5,-2)print (v1 + v2) 以上代码执行结果如下所示: 1Vector(7,8)","link":"/2017/05/01/Python3 面向对象/"},{"title":"Python中的列表list","text":"4-1 Python创建listPython内置的一种数据类型是列表:list。list是一种有序的集合,可以随时添加和删除其中的元素。 比如,列出班里所有同学的名字,就可以用一个list表示: 12>>> ['Michael', 'Bob', 'Tracy']['Michael', 'Bob', 'Tracy'] list是数学意义上的有序集合,也就是说,list中的元素是按照顺序排列的。 构造list非常简单,按照上面的代码,直接用 [ ] 把list的所有元素都括起来,就是一个list对象。 通常,我们会把list赋值给一个变量,这样,就可以通过变量来引用list: 123>>> classmates = ['Michael', 'Bob', 'Tracy']>>> classmates # 打印classmates变量的内容['Michael', 'Bob', 'Tracy'] 由于Python是动态语言,所以list中包含的元素并不要求都必须是同一种数据类型,我们完全可以在list中包含各种数据: 1>>> L = ['Michael', 100, True] 一个元素也没有的list,就是空list: 1>>> empty_list = [] 任务 假设班里有3名同学:Adam,Lisa和Bart,他们的成绩分别是 95.5,85 和 59,请按照 名字, 分数, 名字, 分数… 的顺序按照分数从高到低用一个list表示,然后打印出来。 解答: 12L = ['adam',95.5,'lisa',85,'bart',59]print L 4-2 Python按照索引访问list由于list是一个有序集合,所以,我们可以用一个list按分数从高到低表示出班里的3个同学: 1>>> L = ['Adam', 'Lisa', 'Bart'] 那我们如何从list中获取指定第 N 名的同学呢?方法是通过索引来获取list中的指定元素。 需要特别注意的是,索引从 0 开始,也就是说,第一个元素的索引是0,第二个元素的索引是1,以此类推。 因此,要打印第一名同学的名字,用 L[0]: 12>>> print L[0]Adam 要打印第二名同学的名字,用 L[1]: 12>>> print L[1]Lisa 要打印第三名同学的名字,用 L[2]: 12>>> print L[2]Bart 要打印第四名同学的名字,用 L[3]: 1234>>> print L[3]Traceback (most recent call last): File \"<stdin>\", line 1, in <module>IndexError: list index out of range 报错了!IndexError意思就是索引超出了范围,因为上面的list只有3个元素,有效的索引是 0,1,2。 所以,使用索引时,千万注意不要越界。 任务 三名同学的成绩可以用一个list表示: L = [95.5, 85, 59] 请按照索引分别打印出第一名、第二名、第三名、第四名的分数。 答案 12345L = [95.5,85,59]print (L[0])print (L[1])print (L[2])print (L[-1]) 4-3 Python之倒序访问list我们还是用一个list按分数从高到低表示出班里的3个同学: 1>>> L = ['Adam', 'Lisa', 'Bart'] 这时,老师说,请分数最低的同学站出来。 要写代码完成这个任务,我们可以先数一数这个 list,发现它包含3个元素,因此,最后一个元素的索引是2: 12>>> print L[2]Bart 有没有更简单的方法? 有! Bart同学是最后一名,俗称倒数第一,所以,我们可以用 -1 这个索引来表示最后一个元素: 12>>> print L[-1]Bart Bart同学表示躺枪。 类似的,倒数第二用 -2 表示,倒数第三用 -3 表示,倒数第四用 -4 表示: 12345678>>> print L[-2]Lisa>>> print L[-3]Adam>>> print L[-4]Traceback (most recent call last): File \"<stdin>\", line 1, in <module>IndexError: list index out of range L[-4] 报错了,因为倒数第四不存在,一共只有3个元素。 使用倒序索引时,也要注意不要越界。 任务 三名同学的成绩可以用一个list表示: L = [95.5, 85, 59] 请按照倒序索引分别打印出倒数第一、倒数第二、倒数第三。 答案: 1234L = [95.5, 85, 59]print (L[-1])print (L[-2])print (L[-3]) 4-4 Python之添加新元素12append() 方法insert()方法 现在,班里有3名同学: 1>>> L = ['Adam', 'Lisa', 'Bart'] 今天,班里转来一名新同学 Paul,如何把新同学添加到现有的 list 中呢? 第一个办法是用 list 的 append() 方法,把新同学追加到 list 的末尾: 1234>>> L = ['Adam', 'Lisa', 'Bart']>>> L.append('Paul')>>> print L['Adam', 'Lisa', 'Bart', 'Paul'] append()总是把新的元素添加到 list 的尾部。 如果 Paul 同学表示自己总是考满分,要求添加到第一的位置,怎么办? 方法是用list的 insert()方法,它接受两个参数,第一个参数是索引号,第二个参数是待添加的新元素: 1234>>> L = ['Adam', 'Lisa', 'Bart']>>> L.insert(0, 'Paul')>>> print L['Paul', 'Adam', 'Lisa', 'Bart'] L.insert(0, ‘Paul’) 的意思是,’Paul’将被添加到索引为 0 的位置上(也就是第一个),而原来索引为 0 的Adam同学,以及后面的所有同学,都自动向后移动一位。 任务 假设新来一名学生Paul,Paul 同学的成绩比Bart好,但是比Lisa差,他应该排到第三名的位置,请用代码实现。 解 123L = ['Adam', 'Lisa', 'Bart']L.insert(2,'Paul')print L 4-5 Python从list删除元素Paul同学刚来几天又要转走了,那么我们怎么把Paul 从现有的list中删除呢? 如果Paul同学排在最后一个,我们可以用list的pop()方法删除: 12345>>> L = ['Adam', 'Lisa', 'Bart', 'Paul']>>> L.pop()'Paul'>>> print L['Adam', 'Lisa', 'Bart'] pop()方法总是删掉list的最后一个元素,并且它还返回这个元素,所以我们执行 L.pop() 后,会打印出 ‘Paul’。 如果Paul同学不是排在最后一个怎么办?比如Paul同学排在第三: 1>>> L = ['Adam', 'Lisa', 'Paul', 'Bart'] 要把Paul踢出list,我们就必须先定位Paul的位置。由于Paul的索引是2,因此,用 pop(2)把Paul删掉: 1234>>> L.pop(2)'Paul'>>> print L['Adam', 'Lisa', 'Bart'] 任务 注意右边编辑器代码中 list 如下: L = [‘Adam’, ‘Lisa’, ‘Paul’, ‘Bart’] Paul的索引是2,Bart的索引是3,如果我们要把Paul和Bart都删掉,请解释下面的代码为什么不能正确运行: L.pop(2) L.pop(3) 怎样调整代码可以把Paul和Bart都正确删除掉? 答: 1234L = ['Adam', 'Lisa', 'Paul', 'Bart']L.pop(3)L.pop(2)print L 4-6 Python中替换元素list是可变的。 假设现在班里仍然是3名同学: 1>>> L = ['Adam', 'Lisa', 'Bart'] 现在,Bart同学要转学走了,碰巧来了一个Paul同学,要更新班级成员名单,我们可以先把Bart删掉,再把Paul添加进来。 另一个办法是直接用Paul把Bart给替换掉: 123>>> L[2] = 'Paul'>>> print LL = ['Adam', 'Lisa', 'Paul'] 对list中的某一个索引赋值,就可以直接用新的元素替换掉原来的元素,list包含的元素个数保持不变。 由于Bart还可以用 -1 做索引,因此,下面的代码也可以完成同样的替换工作: 1>>> L[-1] = 'Paul' 任务 班里的同学按照分数排名是这样的: L = [‘Adam’, ‘Lisa’, ‘Bart’] 但是,在一次考试后,Bart同学意外取得第一,而Adam同学考了倒数第一。 请通过对list的索引赋值,生成新的排名。 答案 1234L = ['Adam', 'Lisa', 'Bart']L.append(L.pop(0)) L.insert(0,L.pop(1))print L","link":"/2017/03/08/Python中的列表list/"},{"title":"Python之if判断语句与while和for循环","text":"5-1 Python之if语句计算机之所以能做很多自动化的任务,因为它可以自己做条件判断。 比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,可以用if语句实现: 12345age = 20if age >= 18: print 'your age is', age print 'adult'print 'END' 注意: ==Python代码的缩进规则==。具有相同缩进的代码被视为代码块,上面的3,4行 print 语句就构成一个代码块(但不包括第5行的print)。如果 if 语句判断为 True,就会执行这个代码块。 缩进请严格按照Python的习惯写法:==4个空格==,不要使用Tab,更不要混合Tab和空格,否则很容易造成因为缩进引起的语法错误。 注意: if 语句后接表达式,然后用:表示代码块开始。 如果你在Python交互环境下敲代码,还要特别留意缩进,并且退出缩进需要多敲一行回车: 1234567>>> age = 20>>> if age >= 18:... print 'your age is', age... print 'adult'...your age is 20adult 任务 如果成绩达到60分或以上,视为passed。 假设Bart同学的分数是75,请用if语句判断是否能打印出 passed: 答案: 123score = 75if score >= 60: print 'passed' 5-2 Python之 if-else当 if 语句判断表达式的结果为 True 时,就会执行 if 包含的代码块: 12if age >= 18: print 'adult' 如果我们想判断年龄在18岁以下时,打印出 ‘teenager’,怎么办? 方法是再写一个 if: 12if age < 18: print 'teenager' 或者用 not 运算: 12if not age >= 18: print 'teenager' 细心的同学可以发现,这两种条件判断是“非此即彼”的,要么符合条件1,要么符合条件2,因此,完全可以用一个 if … else … 语句把它们统一起来: 1234if age >= 18: print 'adult'else: print 'teenager' 利用 if … else … 语句,我们可以根据条件表达式的值为 True 或者 False ,分别执行 if 代码块或者 else 代码块。 注意: else 后面有个“:”。 任务 如果成绩达到60分或以上,视为passed,否则视为failed。 假设Bart同学的分数是55,请用if语句打印出 passed 或者 failed: 答案 12345score = 55if score >= 60: print 'passed'else: print 'failed' #5-3 Python之 if-elif-else 有的时候,一个 if … else … 还不够用。比如,根据年龄的划分: 123条件1:18岁或以上:adult条件2:6岁或以上:teenager条件3:6岁以下:kid 我们可以用一个 if age >= 18 判断是否符合条件1,如果不符合,再通过一个 if 判断 age >= 6 来判断是否符合条件2,否则,执行条件3: 1234567if age >= 18: print 'adult'else: if age >= 6: print 'teenager' else: print 'kid' 这样写出来,我们就得到了一个两层嵌套的 if … else … 语句。这个逻辑没有问题,但是,如果继续增加条件,比如3岁以下是 baby: 12345678910if age >= 18: print 'adult'else: if age >= 6: print 'teenager' else: if age >= 3: print 'kid' else: print 'baby' 这种缩进只会越来越多,代码也会越来越难看。 要避免嵌套结构的 if … else …,我们可以用 if … 多个elif … else … 的结构,一次写完所有的规则: 12345678if age >= 18: print 'adult'elif age >= 6: print 'teenager'elif age >= 3: print 'kid'else: print 'baby' elif 意思就是 else if。这样一来,我们就写出了结构非常清晰的一系列条件判断。 特别注意: 这一系列条件判断会从上到下依次判断,如果某个判断为 True,执行完对应的代码块,后面的条件判断就直接忽略,不再执行了。 请思考下面的代码: 1234567age = 8if age >= 6: print 'teenager'elif age >= 18: print 'adult'else: print 'kid' 当 age = 8 时,结果正确,但 age = 20 时,为什么没有打印出 adult? 如果要修复,应该如何修复? 任务 如果按照分数划定结果: 90分或以上:excellent 80分或以上:good 60分或以上:passed 60分以下:failed 请编写程序根据分数打印结果。 答案 12345678910score = 85if score >= 90: print 'excellent'elif score >= 80: print 'good'elif score >= 60: print 'passed'else : print 'failed' #5-4 Python之 for循环 list或tuple可以表示一个有序集合。如果我们想依次访问一个list中的每一个元素呢?比如 list: 1234L = ['Adam', 'Lisa', 'Bart']print L[0]print L[1]print L[2] 如果list只包含几个元素,这样写还行,如果list包含1万个元素,我们就不可能写1万行print。 这时,循环就派上用场了。 Python的 for 循环就可以依次把list或tuple的每个元素迭代出来: 123L = ['Adam', 'Lisa', 'Bart']for name in L: print name 注意: name 这个变量是在 for 循环中定义的,意思是,依次取出list中的每一个元素,并把元素赋值给 name,然后执行for循环体(就是缩进的代码块)。 这样一来,遍历一个list或tuple就非常容易了。 任务 班里考试后,老师要统计平均成绩,已知4位同学的成绩用list表示如下: L = [75, 92, 59, 68] 请利用for循环计算出平均成绩。 答案 12345L = [75, 92, 59, 68]sum = 0.0for x in L: sum += xprint sum / 4 #5-5 Python之 while循环 Python之 while循环 和 for 循环不同的另一种循环是 while 循环,while 循环不会迭代 list 或 tuple 的元素,而是根据表达式判断循环是否结束。 比如要从 0 开始打印不大于 N 的整数: 12345N = 10x = 0while x < N: print x x = x + 1 while循环每次先判断 x < N,如果为True,则执行循环体的代码块,否则,退出循环。 在循环体内,x = x + 1 会让 x 不断增加,最终因为 x < N 不成立而退出循环。 如果没有这一个语句,while循环在判断 x < N 时总是为True,就会无限循环下去,变成死循环,所以要特别留意while循环的退出条件。 任务 利用while循环计算100以内奇数的和。 答案 123456sum = 0x = 1while x <100: sum += x x += 2print sum #5-6 Python之 break退出循环 Python之 break退出循环 用 for 循环或者 while 循环时,如果要在循环体内直接退出循环,可以使用 break 语句。 比如计算1至100的整数和,我们用while来实现: 12345678sum = 0x = 1while True: sum = sum + x x = x + 1 if x > 100: breakprint sum 咋一看, while True 就是一个死循环,但是在循环体内,我们还判断了 x > 100 条件成立时,用break语句退出循环,这样也可以实现循环的结束。 任务 利用 while True 无限循环配合 break 语句,计算 1 + 2 + 4 + 8 + 16 + … 的前20项的和。 答案: 12345678910sum = 0x = 1n = 1while True: sum += x x = x * 2 n += 1 if n > 20: breakprint sum #5-7 Python之 continue继续循环 Python之 continue继续循环 在循环过程中,可以用break退出当前循环,还可以用continue跳过后续循环代码,继续下一次循环。 假设我们已经写好了利用for循环计算平均分的代码: 1234567L = [75, 98, 59, 81, 66, 43, 69, 85]sum = 0.0n = 0for x in L: sum = sum + x n = n + 1print sum / n 现在老师只想统计及格分数的平均分,就要把 x < 60 的分数剔除掉,这时,利用 continue,可以做到当 x < 60的时候,不继续执行循环体的后续代码,直接进入下一次循环: 12345for x in L: if x < 60: continue sum = sum + x n = n + 1 任务 对已有的计算 0 - 100 的while循环进行改造,通过增加 continue 语句,使得只计算奇数的和: 12345678sum = 0x = 1while True: sum = sum + x x = x + 1 if x > 100: breakprint sum 答案 12345678910sum = 0x = 0while True: x = x + 1 if x > 100: break if x % 2 == 0: continue sum += xprint sum #5-8 Python之 多重循环 Python之 多重循环 在循环内部,还可以嵌套循环,我们来看一个例子: 123for x in ['A', 'B', 'C']: for y in ['1', '2', '3']: print x + y x 每循环一次,y 就会循环 3 次,这样,我们可以打印出一个全排列: 123456789A1A2A3B1B2B3C1C2C3 任务 对100以内的两位数,请使用一个两重循环打印出所有十位数数字比个位数数字小的数,例如,23(2 < 3)。 答案1234for x in [1,2,3,4,5,6,7,8,9]: for y in [0,1,2,3,4,5,6,7,8,9]: if x < y: print(10 * x + y)","link":"/2017/03/08/Python之if判断语句与while和for循环/"},{"title":"Python字符串的encode与decode研究心得-解决乱码问题","text":"为什么Python使用过程中会出现各式各样的乱码问题,明明是中文字符却显示成“/xe4/xb8/xad/xe6/x96/x87”的形式? 为什么会报错“UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-1: ordinal not in range(128)”? 为啥’gb2312’ codec can’t decode byte 0x95 本文就来研究一下这个问题。 基本知识:decode与encode区别字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即:先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。 decode的作用是将其他编码的字符串转换成unicode编码。如str1.decode(‘gb2312’),表示将gb2312编码的字符串str1转换成unicode编码。 encode的作用是将unicode编码转换成其他编码的字符串。如str2.encode(‘gb2312’),表示将unicode编码的字符串str2转换成gb2312编码。 因此,转码的时候一定要先搞明白,字符串str是什么编码,然后decode成unicode,然后再encode成其他编码 判断是否为unicode如果一个字符串已经是unicode了,再进行解码则将出错,因此通常要对其编码方式是否为unicode进行判断: 1isinstance(s, unicode) #用来判断是否为unicode 用非unicode编码形式的str来encode会报错 实例1原理说了半天,最后来个包治百病的吧:) 12345678910#!/usr/bin/env python #coding=utf-8 s="中文" if isinstance(s, unicode): #s=u"中文" print s.encode('gb2312') else: #s="中文" print s.decode('utf-8').encode('gb2312') 实例2有的时候,会提示错误: ‘gb2312’ codec can’t decode byte 0x95 in position 252873: illegal multibyte sequence 或者: ‘gb2312’ codec can’t decode byte 0x95 in position 252873: illegal multibyte sequence 这是因为:对string进行解码的时候,有个别字符解不出来,比如0x01就是空格。可以直接忽略,加入errors=’ignore’。具体解法如下: 1html = buff.decode("gb2312",errors='ignore')","link":"/2015/05/02/Python字符串的encode与decode研究心得-解决乱码问题/"},{"title":"Python学习路线","text":"谈到学习路线,入门是基础课。基本上,熟练掌握Python入门指南即可。 其次,要想更进一步,需要熟读官方文档,掌握各种内置函数、标准库等知识。关于两者,英文不好的鱼油们可以关Python中文官方文档板块,也欢迎有余力的鱼油加入我们的团队。关于Python的奇淫技巧,可以看《Effective Python:编写高质量Python代码的59个有效方法》这本书。 再次,在进一步发展之前,强烈建议先get几个附加技能,以避免以后可能遇到的不必要的大坑。 Linux 开发利器。有兴趣的鱼油可以安装Linux系统后,移步Linux入门教程。 Vim 编程利器。有兴趣的鱼油可以移步小甲鱼的VIM魔鬼训练营。 Git 全世界最大的开源代码托管平台。有兴趣的鱼油可以移步Git实用教程。 English 基础技能,无需多言。 方向最后,谈到发展方向,就楼主所知的有以下几个方向。 Web开发 如Flask、Django、Tornado等等,需要良好的文档阅读能力。推荐书籍: 《FlaskWeb开发:基于Python的Web应用开发实战》、《The Django Book》等。 渗透测试 陡峭的学习曲线,需要其它如汇编、计算机网络、数据结构等基础知识。推荐书籍:《Python灰帽子》、《Python黑帽子》等。 数据挖掘/大数据 据说还需要学习其它语言,如R语言等。推荐从Scrapy入手。这里有张图,我认为规划的最好: 科学计算 了解不多~_~ … 推荐书籍:《Python科学计算》。 机器学习 了解不多~_~ … 推荐书籍:《机器学习实战》。 软件开发 如Tkinter、wxpython、PyQt、PyGTK+等等。这些图形界面库各有优缺点。其中PyQt普及程度要搞一些,比如说有道词典Linux版、深度截图用的就是PyQt5。有兴趣的鱼油可以移步淘贴PyQt。 软件测试测试 如Selenium、QTP等自动化测试工具。有兴趣的鱼油可以移步自动化测试框架Selenium。推荐书籍:《Selenium 2自动化测试实战——基于Python语言》。","link":"/2016/12/20/Python学习路线/"},{"title":"Python深度学习路线","text":"[TOC] 学习对象所有==大四==以及==研一==学生,研二感兴趣的学生也可参加 深度学习准备篇==Python基础语法== 自学,资料非常多,推荐http://www.runoob.com/python3/python3-tutorial.html。 学习时间:3天-7天 框架安装:Anaconda 掌握程度,基础语法掌握,对于面向对象语法不必掌握==Python库====Python库-numpy==自学,资料非常多,建议看博客即可。 学习时间:1天 掌握程度:numpy对数组对象的封装,理解其思想与原理 学习链接:https://docs.scipy.org/doc/numpy-dev/user/quickstart.html==Python库-pandas==自学,资料非常多,建议看书或博客。 学习时间:1天 掌握程度:知道大概,会使用即可,比如DataFrame 学习链接:http://pandas.pydata.org/pandas-docs/stable/10min.html==Python库-matplotlib==自学,不建议太深入。 学习时间:半天 掌握程度:能够对官网的例子进行修改使用即可 学习链接:http://matplotlib.org/gallery.html深度学习库-TensorFlow本部分会进行一个入门讲解,其它API需要自己去看,去实践。深度学习库-Keras本部分会进行一个入门讲解,其它API需要自己去看,去实践深度学习实战篇CNN网络讲解原理,大家自己动手去实践应用场景卷积层降采样层激励函数文本分类实践RNN/LSTM网络实践讲解原理,大家自己动手去实践应用场景RNN记忆单元LSTM记忆单元文本生成/预测实践","link":"/2017/03/05/Python深度学习路线/"},{"title":"python时间序列分析","text":"本文转载自博客园大神“大熊猫淘沙”的一篇文章——python时间序列分析。文章写的生动有趣干货满满,特此收藏转载一下。原文地址:https://www.cnblogs.com/foley/p/5582358.html [toc] 1. 什么是时间序列 时间序列简单的说就是各时间点上形成的数值序列,时间序列分析就是通过观察历史数据预测未来的值。 在这里需要强调一点的是,时间序列分析并不是关于时间的回归,它主要是研究自身的变化规律的(这里不考虑含外生变量的时间序列)。 1.1 环境配置python作为科学计算的利器,当然也有相关分析的包:statsmodels中tsa模块,当然这个包和SAS、R是比不了,但是python有另一个神器:pandas!pandas在时间序列上的应用,能简化我们很多的工作。 python推荐直接装Anaconda,它集成了许多科学计算包,有一些包自己手动去装还是挺费劲的。statsmodels需要自己去安装,这里我推荐使用0.6的稳定版,0.7及其以上的版本能在github上找到,该版本在安装时会用C编译好,所以修改底层的一些代码将不会起作用。 1.2 pandas时间序列操作大熊猫真的很可爱,这里简单介绍一下它在时间序列上的可爱之处。和许多时间序列分析一样,本文同样使用航空乘客数据(AirPassengers.csv)作为样例。 数据读取: 123456789101112# -*- coding:utf-8 -*-import numpy as npimport pandas as pdfrom datetime import datetimeimport matplotlib.pylab as plt# 读取数据,pd.read_csv默认生成DataFrame对象,需将其转换成Series对象df = pd.read_csv('AirPassengers.csv', encoding='utf-8', index_col='date')df.index = pd.to_datetime(df.index) # 将字符串索引转换成时间索引ts = df['x'] # 生成pd.Series对象# 查看数据格式ts.head()ts.head().index 结果:查看某日的值既可以使用字符串作为索引,又可以直接使用时间对象作为索引12ts['1949-01-01']ts[datetime(1949,1,1)] 两者的返回值都是第一个序列值:112 如果要查看某一年的数据,pandas也能非常方便的实现 1ts['1949'] 切片操作: 1ts['1949-1' : '1949-6'] 注意时间索引的切片操作起点和尾部都是包含的,这点与数值索引有所不同 pandas还有很多方便的时间序列函数,在后面的实际应用中在进行说明。 2时间序列分析2.1基本模型自回归移动平均模型(ARMA(p,q))是时间序列中最为重要的模型之一,它主要由两部分组成: AR代表p阶自回归过程,MA代表q阶移动平均过程,其公式如下: 依据模型的形式、特性及自相关和偏自相关函数的特征,总结如下: 在时间序列中,ARIMA模型是在ARMA模型的基础上多了差分的操作。 2.2平稳性检验我们知道序列平稳性是进行时间序列分析的前提条件,很多人都会有疑问,为什么要满足平稳性的要求呢?在大数定理和中心定理中要求样本同分布(这里同分布等价于时间序列中的平稳性),而我们的建模过程中有很多都是建立在大数定理和中心极限定理的前提条件下的,如果它不满足,得到的许多结论都是不可靠的。以虚假回归为例,当响应变量和输入变量都平稳时,我们用t统计量检验标准化系数的显著性。而当响应变量和输入变量不平稳时,其标准化系数不在满足t分布,这时再用t检验来进行显著性分析,导致拒绝原假设的概率增加,即容易犯第一类错误,从而得出错误的结论。 平稳时间序列有两种定义:严平稳和宽平稳 严平稳顾名思义,是一种条件非常苛刻的平稳性,它要求序列随着时间的推移,其统计性质保持不变。对于任意的τ,其联合概率密度函数满足: 严平稳的条件只是理论上的存在,现实中用得比较多的是宽平稳的条件。 宽平稳也叫弱平稳或者二阶平稳(均值和方差平稳),它应满足: 常数均值 常数方差 常数自协方差 平稳性检验:观察法和单位根检验法 基于此,我写了一个名为test_stationarity的统计性检验模块,以便将某些统计检验结果更加直观的展现出来。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849# -*- coding:utf-8 -*-from statsmodels.tsa.stattools import adfullerimport pandas as pdimport matplotlib.pyplot as pltimport numpy as npfrom statsmodels.graphics.tsaplots import plot_acf, plot_pacf# 移动平均图def draw_trend(timeSeries, size): f = plt.figure(facecolor='white') # 对size个数据进行移动平均 rol_mean = timeSeries.rolling(window=size).mean() # 对size个数据进行加权移动平均 rol_weighted_mean = pd.ewma(timeSeries, span=size) timeSeries.plot(color='blue', label='Original') rolmean.plot(color='red', label='Rolling Mean') rol_weighted_mean.plot(color='black', label='Weighted Rolling Mean') plt.legend(loc='best') plt.title('Rolling Mean') plt.show()def draw_ts(timeSeries): f = plt.figure(facecolor='white') timeSeries.plot(color='blue') plt.show()''' Unit Root Test The null hypothesis of the Augmented Dickey-Fuller is that there is a unit root, with the alternative that there is no unit root. That is to say the bigger the p-value the more reason we assert that there is a unit root'''def testStationarity(ts): dftest = adfuller(ts) # 对上述函数求得的值进行语义描述 dfoutput = pd.Series(dftest[0:4], index=['Test Statistic','p-value','#Lags Used','Number of Observations Used']) for key,value in dftest[4].items(): dfoutput['Critical Value (%s)'%key] = value return dfoutput# 自相关和偏相关图,默认阶数为31阶def draw_acf_pacf(ts, lags=31): f = plt.figure(facecolor='white') ax1 = f.add_subplot(211) plot_acf(ts, lags=31, ax=ax1) ax2 = f.add_subplot(212) plot_pacf(ts, lags=31, ax=ax2) plt.show() 观察法,通俗的说就是通过观察序列的趋势图与相关图是否随着时间的变化呈现出某种规律。所谓的规律就是时间序列经常提到的周期性因素,现实中遇到得比较多的是线性周期成分,这类周期成分可以采用差分或者移动平均来解决,而对于非线性周期成分的处理相对比较复杂,需要采用某些分解的方法。下图为航空数据的线性图,可以明显的看出它具有年周期成分和长期趋势成分。平稳序列的自相关系数会快速衰减,下面的自相关图并不能体现出该特征,所以我们有理由相信该序列是不平稳的。 单位根检验:ADF是一种常用的单位根检验方法,他的原假设为序列具有单位根,即非平稳,对于一个平稳的时序数据,就需要在给定的置信水平上显著,拒绝原假设。ADF只是单位根检验的方法之一,如果想采用其他检验方法,可以安装第三方包arch,里面提供了更加全面的单位根检验方法,个人还是比较钟情ADF检验。以下为检验结果,其p值大于0.99,说明并不能拒绝原假设。 2.3平稳性处理由前面的分析可知,该序列是不平稳的,然而平稳性是时间序列分析的前提条件,故我们需要对不平稳的序列进行处理将其转换成平稳的序列。 a. 对数变换 对数变换主要是为了减小数据的振动幅度,使其线性规律更加明显(我是这么理解的时间序列模型大部分都是线性的,为了尽量降低非线性的因素,需要对其进行预处理,也许我理解的不对)。对数变换相当于增加了一个惩罚机制,数据越大其惩罚越大,数据越小惩罚越小。这里强调一下,变换的序列需要满足大于0,小于0的数据不存在对数变换。 12ts_log = np.log(ts)test_stationarity.draw_ts(ts_log) b. 平滑法 根据平滑技术的不同,平滑法具体分为移动平均法和指数平均法。 移动平均即利用一定时间间隔内的平均值作为某一期的估计值,而指数平均则是用变权的方法来计算均值 1test_stationarity.draw_trend(ts_log, 12) 从上图可以发现窗口为12的移动平均能较好的剔除年周期性因素,而指数平均法是对周期内的数据进行了加权,能在一定程度上减小年周期因素,但并不能完全剔除,如要完全剔除可以进一步进行差分操作。 c. 差分 时间序列最常用来剔除周期性因素的方法当属差分了,它主要是对等周期间隔的数据进行线性求减。前面我们说过,ARIMA模型相对ARMA模型,仅多了差分操作,ARIMA模型几乎是所有时间序列软件都支持的,差分的实现与还原都非常方便。而statsmodel中,对差分的支持不是很好,它不支持高阶和多阶差分,为什么不支持,这里引用作者的说法:作者大概的意思是说预测方法中并没有解决高于2阶的差分,有没有感觉很牵强,不过没关系,我们有pandas。我们可以先用pandas将序列差分好,然后在对差分好的序列进行ARIMA拟合,只不过这样后面会多了一步人工还原的工作。 12345diff_12 = ts_log.diff(12)diff_12.dropna(inplace=True)diff_12_1 = diff_12.diff(1)diff_12_1.dropna(inplace=True)test_stationarity.testStationarity(diff_12_1) 从上面的统计检验结果可以看出,经过12阶差分和1阶差分后,该序列满足平稳性的要求了。 d. 分解 所谓分解就是将时序数据分离成不同的成分。statsmodels使用的X-11分解过程,它主要将时序数据分离成长期趋势、季节趋势和随机成分。与其它统计软件一样,statsmodels也支持两类分解模型,加法模型和乘法模型,这里我只实现加法,乘法只需将model的参数设置为”multiplicative”即可。 123456from statsmodels.tsa.seasonal import seasonal_decomposedecomposition = seasonal_decompose(ts_log, model="additive")trend = decomposition.trendseasonal = decomposition.seasonalresidual = decomposition.resid 得到不同的分解成分后,就可以使用时间序列模型对各个成分进行拟合,当然也可以选择其他预测方法。我曾经用过小波对时序数据进行过分解,然后分别采用时间序列拟合,效果还不错。由于我对小波的理解不是很好,只能简单的调用接口,如果有谁对小波、傅里叶、卡尔曼理解得比较透,可以将时序数据进行更加准确的分解,由于分解后的时序数据避免了他们在建模时的交叉影响,所以我相信它将有助于预测准确性的提高。 2.4模型识别在前面的分析可知,该序列具有明显的年周期与长期成分。对于年周期成分我们使用窗口为12的移动平进行处理,对于长期趋势成分我们采用1阶差分来进行处理。 12345rol_mean = ts_log.rolling(window=12).mean()rol_mean.dropna(inplace=True)ts_diff_1 = rol_mean.diff(1)ts_diff_1.dropna(inplace=True)test_stationarity.testStationarity(ts_diff_1) 观察其统计量发现该序列在置信水平为95%的区间下并不显著,我们对其进行再次一阶差分。再次差分后的序列其自相关具有快速衰减的特点,t统计量在99%的置信水平下是显著的,这里我不再做详细说明。 12ts_diff_2 = ts_diff_1.diff(1)ts_diff_2.dropna(inplace=True) 数据平稳后,需要对模型定阶,即确定p、q的阶数。观察上图,发现自相关和偏相系数都存在拖尾的特点,并且他们都具有明显的一阶相关性,所以我们设定p=1, q=1。下面就可以使用ARMA模型进行数据拟合了。这里我不使用ARIMA(ts_diff_1, order=(1, 1, 1))进行拟合,是因为含有差分操作时,预测结果还原老出问题,至今还没弄明白。 123from statsmodels.tsa.arima_model import ARMAmodel = ARMA(ts_diff_2, order=(1, 1)) result_arma = model.fit( disp=-1, method='css') 2.5样本拟合 模型拟合完后,我们就可以对其进行预测了。由于ARMA拟合的是经过相关预处理后的数据,故其预测值需要通过相关逆变换进行还原。 12345678910111213predict_ts = result_arma.predict()# 一阶差分还原diff_shift_ts = ts_diff_1.shift(1)diff_recover_1 = predict_ts.add(diff_shift_ts)# 再次一阶差分还原rol_shift_ts = rol_mean.shift(1)diff_recover = diff_recover_1.add(rol_shift_ts)# 移动平均还原rol_sum = ts_log.rolling(window=11).sum()rol_recover = diff_recover*12 - rol_sum.shift(1)# 对数还原log_recover = np.exp(rol_recover)log_recover.dropna(inplace=True) 我们使用均方根误差(RMSE)来评估模型样本内拟合的好坏。利用该准则进行判别时,需要剔除“非预测”数据的影响。 1234567ts = ts[log_recover.index] # 过滤没有预测的记录plt.figure(facecolor='white')log_recover.plot(color='blue', label='Predict')ts.plot(color='red', label='Original')plt.legend(loc='best')plt.title('RMSE: %.4f'% np.sqrt(sum((log_recover-ts)**2)/ts.size))plt.show() 观察上图的拟合效果,均方根误差为11.8828,感觉还过得去。 2.6完善ARIMA模型前面提到statsmodels里面的ARIMA模块不支持高阶差分,我们的做法是将差分分离出来,但是这样会多了一步人工还原的操作。基于上述问题,我将差分过程进行了封装,使序列能按照指定的差分列表依次进行差分,并相应的构造了一个还原的方法,实现差分序列的自动还原。 123456789101112131415161718192021222324252627282930313233343536# 差分操作def diff_ts(ts, d): global shift_ts_list # 动态预测第二日的值时所需要的差分序列 global last_data_shift_list shift_ts_list = [] last_data_shift_list = [] tmp_ts = ts for i in d: last_data_shift_list.append(tmp_ts[-i]) print last_data_shift_list shift_ts = tmp_ts.shift(i) shift_ts_list.append(shift_ts) tmp_ts = tmp_ts - shift_ts tmp_ts.dropna(inplace=True) return tmp_ts# 还原操作def predict_diff_recover(predict_value, d): if isinstance(predict_value, float): tmp_data = predict_value for i in range(len(d)): tmp_data = tmp_data + last_data_shift_list[-i-1] elif isinstance(predict_value, np.ndarray): tmp_data = predict_value[0] for i in range(len(d)): tmp_data = tmp_data + last_data_shift_list[-i-1] else: tmp_data = predict_value for i in range(len(d)): try: tmp_data = tmp_data.add(shift_ts_list[-i-1]) except: raise ValueError('What you input is not pd.Series type!') tmp_data.dropna(inplace=True) return tmp_data 现在我们直接使用差分的方法进行数据处理,并以同样的过程进行数据预测与还原。 123456diffed_ts = diff_ts(ts_log, d=[12, 1])model = arima_model(diffed_ts)model.certain_model(1, 1)predict_ts = model.properModel.predict()diff_recover_ts = predict_diff_recover(predict_ts, d=[12, 1])log_recover = np.exp(diff_recover_ts) 是不是发现这里的预测结果和上一篇的使用12阶移动平均的预测结果一模一样。这是因为12阶移动平均加上一阶差分与直接12阶差分是等价的关系,后者是前者数值的12倍,这个应该不难推导。 对于个数不多的时序数据,我们可以通过观察自相关图和偏相关图来进行模型识别,倘若我们要分析的时序数据量较多,例如要预测每只股票的走势,我们就不可能逐个去调参了。这时我们可以依据BIC准则识别模型的p, q值,通常认为BIC值越小的模型相对更优。这里我简单介绍一下BIC准则,它综合考虑了残差大小和自变量的个数,残差越小BIC值越小,自变量个数越多BIC值越大。个人觉得BIC准则就是对模型过拟合设定了一个标准(过拟合这东西应该以辩证的眼光看待)。 12345678910111213141516171819def proper_model(data_ts, maxLag): init_bic = sys.maxint init_p = 0 init_q = 0 init_properModel = None for p in np.arange(maxLag): for q in np.arange(maxLag): model = ARMA(data_ts, order=(p, q)) try: results_ARMA = model.fit(disp=-1, method='css') except: continue bic = results_ARMA.bic if bic < init_bic: init_p = p init_q = q init_properModel = results_ARMA init_bic = bic return init_bic, init_p, init_q, init_properModel 相对最优参数识别结果:BIC: -1090.44209358 p: 0 q: 1 , RMSE:11.8817198331。我们发现模型自动识别的参数要比我手动选取的参数更优。 2.7.滚动预测所谓滚动预测是指通过添加最新的数据预测第二天的值。对于一个稳定的预测模型,不需要每天都去拟合,我们可以给他设定一个阀值,例如每周拟合一次,该期间只需通过添加最新的数据实现滚动预测即可。基于此我编写了一个名为arima_model的类,主要包含模型自动识别方法,滚动预测的功能,详细代码可以查看附录。数据的动态添加: 12345678910111213141516171819from dateutil.relativedelta import relativedeltadef _add_new_data(ts, dat, type='day'):if type == 'day': new_index = ts.index[-1] + relativedelta(days=1) elif type == 'month': new_index = ts.index[-1] + relativedelta(months=1) ts[new_index] = datdef add_today_data(model, ts, data, d, type='day'): _add_new_data(ts, data, type) # 为原始序列添加数据 # 为滞后序列添加新值 d_ts = diff_ts(ts, d) model.add_today_data(d_ts[-1], type)def forecast_next_day_data(model, type='day'): if model == None: raise ValueError('No model fit before') fc = model.forecast_next_day_value(type) return predict_diff_recover(fc, [12, 1]) 现在我们就可以使用滚动预测的方法向外预测了,取1957年之前的数据作为训练数据,其后的数据作为测试,并设定模型每第七天就会重新拟合一次。这里的diffed_ts对象会随着add_today_data方法自动添加数据,这是由于它与add_today_data方法中的d_ts指向的同一对象,该对象会动态的添加数据。 1234567891011121314151617ts_train = ts_log[:'1956-12']ts_test = ts_log['1957-1':]diffed_ts = diff_ts(ts_train, [12, 1])forecast_list = []for i, dta in enumerate(ts_test): if i%7 == 0: model = arima_model(diffed_ts) model.certain_model(1, 1) forecast_data = forecast_next_day_data(model, type='month') forecast_list.append(forecast_data) add_today_data(model, ts_train, dta, [12, 1], type='month')predict_ts = pd.Series(data=forecast_list, index=ts['1957-1':].index)log_recover = np.exp(predict_ts)original_ts = ts['1957-1':] 动态预测的均方根误差为:14.6479,与前面样本内拟合的均方根误差相差不大,说明模型并没有过拟合,并且整体预测效果都较好。 2.8模型序列化在进行动态预测时,我们不希望将整个模型一直在内存中运行,而是希望有新的数据到来时才启动该模型。这时我们就应该把整个模型从内存导出到硬盘中,而序列化正好能满足该要求。序列化最常用的就是使用json模块了,但是它是时间对象支持得不是很好,有人对json模块进行了拓展以使得支持时间对象,这里我们不采用该方法,我们使用pickle模块,它和json的接口基本相同,有兴趣的可以去查看一下。我在实际应用中是采用的面向对象的编程,它的序列化主要是将类的属性序列化即可,而在面向过程的编程中,模型序列化需要将需要序列化的对象公有化,这样会使得对前面函数的参数改动较大,我不在详细阐述该过程。 3总结与其它统计语言相比,python在统计分析这块还显得不那么“专业”。随着numpy、pandas、scipy、sklearn、gensim、statsmodels等包的推动,我相信也祝愿python在数据分析这块越来越好。与SAS和R相比,python的时间序列模块还不是很成熟,我这里仅起到抛砖引玉的作用,希望各位能人志士能贡献自己的力量,使其更加完善。实际应用中我全是面向过程来编写的,为了阐述方便,我用面向过程重新罗列了一遍,实在感觉很不方便。原本打算分三篇来写的,还有一部分实际应用的部分,不打算再写了,还请大家原谅。实际应用主要是具体问题具体分析,这当中第一步就是要查询问题,这步花的时间往往会比较多,然后再是解决问题。以我前面项目遇到的问题为例,当时遇到了以下几个典型的问题:1.周期长度不恒定的周期成分,例如每月的1号具有周期性,但每月1号与1号之间的时间间隔是不相等的;2.含有缺失值以及含有记录为0的情况无法进行对数变换;3.节假日的影响等等。","link":"/2018/03/05/Python时间序列分析/"},{"title":"TDB Can't open database at location /path/to/db as it is already locked by the process with PID","text":"1现象当运行apache-jena-fuseki-3.7.0的时候,命令窗报错:Can’t open database at location /path/to/db as it is already locked by the process with PID 1234 when trying to open a TDB database。 说我们的TDB数据库被 一个进程给占用了。我赶紧搜索怎么解决。 2解决办法: 2.1官网描述搜到了 两个网址:https://issues.apache.org/jira/browse/JENA-1136 和官网:https://jena.apache.org/documentation/tdb/faqs.html#lock-exception 很好,正好官网有类似的解决问题,我们来看一下官网解释: 此异常是TDB自动多JVM使用防范的结果,如前所述我可以在多个应用程序之间共享TDB数据集吗?问题TDB数据库只能由单个JVM安全使用,否则可能会发生数据损坏。从1.1.0开始,TDB会尽可能自动执行此限制,如果您尝试访问从另一个JVM访问的数据库,您将收到此异常。 推荐解决办法: 在极少数情况下,您可能会发现该过程完全不相关(这可能由于过时的锁定文件而发生,因为它们并不总是自动清除),在这种情况下,您可以尝试从数据库目录中手动删除tdb.lock文件。如果您确定其他进程未访问TDB数据库,请执行此操作,否则可能会发生数据损坏。 我按照这个办法 ,去jena的tdb数据文件夹中把tdb.lock文件 删除了, 但是再次运行 还是没用。 还是报错! 2.2 去找pid既然直接删除没用, 那么就去找这个PID。 2.2.1 windows中找 进程id(PID)的方法为:1234567891、右键点击任务栏,打开任管管理器;2、我们点击“进程”标签切换到进程选项卡下;3、点击任务管理器菜单上的“查看按钮”,并选点击“选择列”;4、在选择进程页列中,我们勾选“PID(进程标识符)”选项,并点击确定即可;5、这时候我们看到PID已经显示在进程页列表里了。 2.2.2 我们发现我们发现原来是 pid6844 原来是 notepad++ 把apache-jena-fuseki-3.7.0的 配置文件打开了,这样就锁定了。 所以我们把 NOTPAD++软件关闭; 或者把这个进程给杀死即可。","link":"/2019/03/27/TDB Can t open database at location path to db as it is already locked by the process with PID/"},{"title":"Tensorboard 可视化好帮手","text":"4.1 Tensorboard简介学会用 Tensorflow 自带的 tensorboard 去可视化我们所建造出来的神经网络是一个很好的学习理解方式. 用最直观的流程图告诉你你的神经网络是长怎样,有助于你发现编程中间的问题和疑问. 通过tensorboard的工具大致可以看到,上节课要显示的神经网络差不多是这样子的: 同时我们也可以展开看每个layer中的一些具体的结构: 4.2 绘制图层与其中的参数主要用到两个语法: 定义图层:with tf.name_scope() ( 里面写名字,下面用缩进) 定义参数:增加参数变量的属性name 4.2.1 对隐藏层例如对添加的隐藏层进行画图,最终,layer形式如下: 1234567891011121314def add_layer(inputs, in_size, out_size, activation_function=None): # add one more layer and return the output of this layer with tf.name_scope('layer'): with tf.name_scope('weights'): Weights = tf.Variable(tf.random_normal([in_size, out_size]),name='W') with tf.name_scope('biases'): biases = tf.Variable(tf.zeros([1,out_size]) + 0.1,name='b') with tf.name_scope('Wx_plus_b'): Wx_plus_b = tf.add(tf.matmul(inputs, Weights),biases) if activation_function is None: outputs = Wx_plus_b else: outputs = activation_function(Wx_plus_b, ) return outputs 效果如下:(有没有看见刚才定义layer里面的“内部构件”呢?) 4.2.2 loss函数再例如对loss部分: 1234567# the error between prediciton and real datawith tf.name_scope('loss'): loss = tf.reduce_mean( tf.reduce_sum( tf.square(ys - prediction), eduction_indices=[1] )) 这句话就是“绘制” loss了, 如下: 4.2.3 train_step部分12with tf.name_scope('train'): train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss) 形式都相同。 4.3 保存并执行绘图 保存绘画:tf.summary.FileWriter()运行程序,生成绘画文件 运行绘画1:在CMD中tensorboard –logdir logs设定文件目录 打开Google Chrome:http://localhost:6006 4.3.1 保存绘画我们需要使用 tf.summary.FileWriter() 将上面‘绘画’出的图保存到一个目录中,以方便后期在浏览器中可以浏览。 这个方法中的第二个参数需要使用sess.graph , 因此我们需要把这句话放在获取session的后面。 这里的graph是将前面定义的框架信息收集起来,然后放在logs/目录下面。 123sess = tf.Session() # get sessionwriter = tf.summary.FileWriter("logs/", sess.graph) 这句话就把当前的绘图保存到,当前py文件下的logs中去了。 4.3.2 运行绘画11.在你的terminal(终端)中 ,cd进入你的logs所在目录。(或者shift进入) 2.使用以下命令 12tensorboard --logdir logs# 设置告诉tensorboard绘画在/logs 目录中 4.3.3 运行绘画2浏览器是 “Google Chrome”. 使用 http://localhost:6006 tensorboard 还有很多其他的参数,希望大家可以多多了解, 可以使用 tensorboard –help 查看tensorboard的详细参数 4.3最终的全部代码在这里 4.4 可视化训练过程tensorboard还可以可视化训练过程( biase等参数的变化过程) , 这节重点讲一下可视化训练过程的图标是如何做的 。请看下图, 这是如何做到的呢? 4.4.1 distributions制作对Weights和biases的变化图表distributions。 我们层中的Weights设置变化图, tensorflow中提供了tf.histogram_summary()方法,用来绘制图片, 第一个参数是图表的名称, 第二个参数是图表要记录的变量 1234with tf.name_scope('layer'): with tf.name_scope('weights'): Weights= tf.Variable(tf.random_normal([in_size,out_size]),name='W') tf.summary.histogram(layer_name + '/weights', Weights) 同样的方法我们对biases进行绘制图标:123with tf.name_scope('biases'): biases = tf.Variable(tf.zeros([1,out_size])+0.1, name='b') tf.summary.histogram(layer_name + '/biases', biases) 至于activation_function 可以不绘制. 我们对output 使用同样的方法: 1tf.summary.histogram(layer_name + '/outputs', outputs) 最终经过我们的修改 , addlayer()方法成为如下的样子: 1234567891011121314151617181920212223242526272829def add_layer(inputs , in_size, out_size,n_layer, activation_function=None): ## add one more layer and return the output of this layer layer_name='layer%s'%n_layer with tf.name_scope('layer'): with tf.name_scope('weights'): Weights= tf.Variable(tf.random_normal([in_size, out_size]),name='W') # tf.histogram_summary(layer_name+'/weights',Weights) tf.summary.histogram(layer_name + '/weights', Weights) # tensorflow >= 0.12 with tf.name_scope('biases'): biases = tf.Variable(tf.zeros([1,out_size])+0.1, name='b') # tf.histogram_summary(layer_name+'/biase',biases) tf.summary.histogram(layer_name + '/biases', biases) # Tensorflow >= 0.12 with tf.name_scope('Wx_plus_b'): Wx_plus_b = tf.add(tf.matmul(inputs,Weights), biases) if activation_function is None: outputs=Wx_plus_b else: outputs= activation_function(Wx_plus_b) # tf.histogram_summary(layer_name+'/outputs',outputs) tf.summary.histogram(layer_name + '/outputs', outputs) # Tensorflow >= 0.12 return outputs 修改之后的名称会显示在每个tensorboard中每个图表的上方显示, 如下图所示: 4.4.2 eventsLoss 的变化图和之前设置的方法略有不同. loss是在tesnorBorad 的event下面的, 这是由于我们使用的是tf.scalar_summary() 方法. 观看loss的变化比较重要. 当你的loss呈下降的趋势,说明你的神经网络训练是有效果的. 修改后的代码片段如下:123with tf.name_scope('loss'): loss= tf.reduce_mean(tf.reduce_sum(tf.square(ys- prediction), reduction_indices=[1])) tf.summary.scalar('loss', loss) # tensorflow >= 0.12 4.4.3 给所有训练图‘合并‘接下来, 开始合并打包。 tf.summary.merge_all() 方法会对我们所有的 summaries 合并到一起. 因此在原有代码片段中添加: 1234567sess= tf.Session()merged = tf.summary.merge_all() writer = tf.summary.FileWriter("logs/", sess.graph) sess.run(tf.global_variables_initializer()) 4.4.4 训练数据假定给出了x_data,y_data并且训练1000次. 以上这些仅仅可以记录很绘制出训练的图表, 但是不会记录训练的数据。 为了较为直观显示训练过程中每个参数的变化,我们每隔上50次就记录一次结果 , 同时我们也应注意, merged 也是需要run 才能发挥作用的,所以在for循环中写下:123if i%50 == 0: rs = sess.run(merged,feed_dict={xs:x_data,ys:y_data}) writer.add_summary(rs, i) 最后修改后的片段如下:12345for i in range(1000): sess.run(train_step, feed_dict={xs:x_data, ys:y_data}) if i%50 == 0: rs = sess.run(merged,feed_dict={xs:x_data,ys:y_data}) writer.add_summary(rs, i) 程序运行完毕之后, 会产生logs目录 , 使用命令 tensorboard –logdir logs 将输出中显示的URL地址粘贴到浏览器中便可以查看. 最终的效果如下: 4.3最终的全部代码在这里 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970"""Please note, this code is only for python 3+. If you are using python 2+, please modify the code accordingly."""from __future__ import print_functionimport tensorflow as tfimport numpy as npdef add_layer(inputs, in_size, out_size, n_layer, activation_function=None): # add one more layer and return the output of this layer layer_name = 'layer%s' % n_layer with tf.name_scope(layer_name): with tf.name_scope('weights'): Weights = tf.Variable(tf.random_normal([in_size, out_size]), name='W') tf.summary.histogram(layer_name + '/weights', Weights) with tf.name_scope('biases'): biases = tf.Variable(tf.zeros([1, out_size]) + 0.1, name='b') tf.summary.histogram(layer_name + '/biases', biases) with tf.name_scope('Wx_plus_b'): Wx_plus_b = tf.add(tf.matmul(inputs, Weights), biases) if activation_function is None: outputs = Wx_plus_b else: outputs = activation_function(Wx_plus_b, ) tf.summary.histogram(layer_name + '/outputs', outputs) return outputs# Make up some real datax_data = np.linspace(-1, 1, 300)[:, np.newaxis]noise = np.random.normal(0, 0.05, x_data.shape)y_data = np.square(x_data) - 0.5 + noise# define placeholder for inputs to networkwith tf.name_scope('inputs'): xs = tf.placeholder(tf.float32, [None, 1], name='x_input') ys = tf.placeholder(tf.float32, [None, 1], name='y_input')# add hidden layerl1 = add_layer(xs, 1, 10, n_layer=1, activation_function=tf.nn.relu)# add output layerprediction = add_layer(l1, 10, 1, n_layer=2, activation_function=None)# the error between prediciton and real datawith tf.name_scope('loss'): loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction), reduction_indices=[1])) tf.summary.scalar('loss', loss)with tf.name_scope('train'): train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)sess = tf.Session()merged = tf.summary.merge_all()writer = tf.summary.FileWriter("logs/", sess.graph)init = tf.global_variables_initializer()sess.run(init)for i in range(1000): sess.run(train_step, feed_dict={xs: x_data, ys: y_data}) if i % 50 == 0: result = sess.run(merged, feed_dict={xs: x_data, ys: y_data}) writer.add_summary(result, i)# direct to the local dir and run this in terminal:# $ tensorboard --logdir logs# Google Chrome”访问 http://localhost:6006","link":"/2017/07/19/Tensorboard可视化好帮手/"},{"title":"The Myeclipse executable launcher was unable to locate its companion shared library","text":"The Myeclipse executable launcher was unable to locate its companion shared library 打开myeclipse的时候弹出:The Myeclipse executable launcher was unable to locate its companion shared library 解决办法: 在安装目录下打开 myeclipse.ini发现 /MyEclipse/Common/的路径找不到了,因为修改了文件夹的名字。 因为上次装MyEclipse装在E盘 这次装在D盘 所以会有两个地方。 所以:1.根据ini文件的路径找到MyEclipse/Common/2.或者更改ini文件到新的路径。 1234567891011121314151617#utf8 (do not remove) #utf8 (do not remove) -startup E:/本机常用软件/MyEclipse/Common/plugins/org.eclipse.equinox.launcher_1.2.0.v20110502.jar --launcher.library E:/本机常用软件/MyEclipse/Common/plugins/org.eclipse.equinox.launcher.i18n.win32.win32.x86_4.2.0.v201201111650 -install D:\\Program Files\\MyEclipse -vm E:\\本机常用软件\\MyEclipse\\Common\\binary\\com.sun.java.jdk.win32.x86_1.6.0.013\\jre\\bin\\javaw.exe -configuration D:\\Program Files\\MyEclipse\\configuration -vmargs -Xmx512m -XX:MaxPermSize=256m -XX:ReservedCodeCacheSize=64m -Dosgi.nls.warnings=ignore","link":"/2015/03/28/The Myeclipse executable launcher was unable to locate its companion shared library/"},{"title":"VC6.0+ddk+DriverStudio3.2安装与配置","text":"再学习VS2013+wdk之前。首先学习VC6.0+ddk+DriverStudio3.2环境下的驱动开发,来理解驱动的世界。完全新手,从零开始,亚历山大,且行且珍惜。。。。。 首先是:环境的搭建 安装和配置一.软件的安装顺序:Windows XP(虚拟机中) –> VC6.0 –> WinXP_DDK -> DriverStudio3.2,如果顺序装错了,那么把DriverStudio3.2删除再重装就OK了。 下载地址:1.vc6.0英文原版(最好不要用中文版): http://down.liangchan.net/microsoftvisualc-en6.0.zip 2.WinXP_DDK:安装DDK,安装时注意需要将所有的组件、工具、例子等都安装(避免出现hidport.h找不到的问题)。 http://download.microsoft.com/download/9/0/f/90f019ac-8243-48d3-91cf-81fc4093ecfd/1830_usa_ddk.iso 3.DriverStudio3.2: http://ttl4.pc6.com/tx/driverstudio.zip (安装时会检测系统有无D盘,如果虚机中XP无D盘,安装不上。用“分区助手”分下区即可) 二.配置DriverStudio1.从网上找到库文件 ntstrsafe.lib+csq.lib.rar,把解压出来的两个库文件拷贝到WinXP_DDK的安装目录下的库目录中.(我的是 C:\\WINDDK\\2600\\lib\\wxp\\i386)。启动vc6,然后进行简单的配置:菜单DriverStudio菜单下的DDK Build Settings,在弹出的对话框中选择已经安装的DDK目录(比如我的是C:\\WINDDK\\2600), (ntstrsafe.lib+csq.lib.rar下载地址: http://download.csdn.net/detail/victoryckl/4444640 ) 2.在Windows DDK compiler Options中选择”Enable only for Driver Studio”。VC6.0–>Tools–>Options,点击”Directories”选项卡:1)·“Show directories for:”下选择Include files,然后检查有没有包含ddk的头文件目录(我的是C:\\WINDDK\\2600\\inc\\wxp),如果没有则加上; 以及123C:\\WINDDK\\2600\\INC\\W2K C:\\WINDDK\\2600\\INC\\DDK\\W2K C:\\WINDDK\\2600\\INC\\DDK\\WDM\\W2K 2)·“Show directories for:”下选择Library files,然后检查有没有包含ddk的库文件目录(我的是C:\\WINDDK\\2600\\lib\\wxp\\i386),如果没有则加上;以及 C:\\WINDDK\\2600\\LIB\\W2K\\I386 三。编译库文件(一定注意32位)·编译适合本机使用的库文件(以下内容,如果用DDK编程者可以不看) (1).启动VC6.0。开始–>所有程序 –>Compuware DriveStudio–>Develop–>DDK Building Settings,确保“DDK Root Directory”下方的内容是ddk的安装目录(比如我的是C:\\WINDDK\\2600),然后点击下方的”Luanch Program”正式启动vc6的开发环境。 (2).进入菜单File–>Open Workspace(打开位于DriverStudio3.2安装目录的\\DriverWorks\\Source\\vdwlibs.dsw)–> 进入菜单Build–>batch Build,点击“Select x86”按钮只选中全部的32位库(我的电脑是32位的。注意:对于32位的电脑一定不要选中64位的库,否则后面编译会出错)–>点击按 钮”Rebuild AlL”开始编译。(注意:这种方法我曾经成功过一次,但后来再也没成功过,于是百度GOOGLE很久,发现下面这样也行:设置VdwLibs为活动项,选中Win32 WDM Checked,然后用DriverStudio里面的 Build with Build.exe即可以。然后再选Win32 WDM Free再Build一下,这样就出现了想要的vdw_wdm.lib) 注:如果出现无法打开文件这类的错误,一般都是DDK Build Settings指向不对,或安装顺序有误,或者你在32位机器上选中了64位库。 四·编译一个DriverStudio自带的实例(1)·启动vc6,点击菜单 File–>Open Workspace,打开项目文件C:\\Program Files\\Compuware\\DriverStudio\\DriverWorks\\Examples\\wdm\\hellowdm \\HelloWdm.dsw,然后编译,如果没有报错,那说明安装和配置成功。但请你别高兴的太早,开发环境安装配置成功只是万里长城的第一步,剩下的你 就是要理解驱动模块的架构和具体的代码编写了。 五·使用Driver wizard生成驱动程序框架(1).在VC6.0的界面下,点击菜单DriverStudio–>Driver wizard,此后系统会一步一步引导你完成设置,最后自动生产的驱动程序框架。 (2).设置好后将生成驱动文件,然后用VC6.0进行编译:进行Build菜单,Rebuild AlL将生成.sys文件,说明驱动模块编译成功! 注:如果出现无法打开ntstrsafe.lib的错误,说明系统缺少这个库文件,参照上面的方法补上这个库文件,或者进入菜单 Project–>Settings,鼠标点击左边方框里的最上面一行,然后右边”Project Option”下的ntstrsafe.lib并删除它。","link":"/2016/11/18/VC6.0+ddk+DriverStudio3.2安装与配置/"},{"title":"Windows下neo4j安装使用","text":"0. 简介前面我们学习了如何使用jena完成一个全流程的知识图谱查询。jena的优势是可以快速的方便的集成各种插件,方便基于知识图谱的问答系统构建。 但是jena也有劣势:不能很好的可视化三元组。 今天我们学习大家最常用的知识图谱可视化——图数据库neo4j Neo4j支持三种网络协议(Protocol),分别是Bolt,HTTP和HTTPS,默认的连接器配置有三种,为了使用这三个端口,需要在Windows防火墙中创建Inbound Rules,允许通过端口7687,7474和7473访问本机。 1. 下载nea4j1.进入Neo4j官网地址:https://link.zhihu.com/?target=http%3A//neo4j.com 2.点击Download,进入下载界面: 3.点击DOWNLOAD NEO4J SERVER ,选择社区版community edition Windows版本 2. 安装neo4j2.1 直接解压至此下载的版本为压缩包版本,无需安装,只需解压至合适目录即可。找到刚刚下载的zip文件,右键单击,全部解压缩。 将提取的文件放在服务器上的合适地址中,例如1D:\\Programming\\neo4j-community-3.5.3 注意看下图: neo4j主要的运行命令都在 第一个/bin 文件夹内。 各个文件夹的作用:1234bin目录:用于存储Neo4j的可执行程序;conf目录:用于控制Neo4j启动的配置文件;data目录:用于存储核心数据库文件;plugins目录:用于存储Neo4j的插件; 进入这个bin文件夹 ,++按住shift + 右键鼠标 –> 在此处打开命令行++ 可以有如下命令:12345678910111213console:打开Neo4j的控制台start:启动stop:关闭restart:重启status:查看运行状态install-service:安装Neo4j在Windows系统上的服务。uninstall-service:卸载服务 2.2 配置系统环境变量 我的电脑→属性→高级系统设置→高级→环境变量 新建变量:NEO4J_HOME,变量值:D:\\Programming\\neo4j-community-3.5.3 修改变量:path,增加值:%NEO4J_HOME%\\bin; 2.3 打开neo4j控制台在命令行输入: 1neo4j console 开启数据库,并在浏览器 http://localhost:7474 中查看NEO4J数据库 2.3.1 安装报错输入neo4j console命令之后可能会报错: 12Import-Module : 未能加载指定的模块“\\Neo4j-Management.psd1”,因为在任何模块目录中都没有找到有效模块文件。 ==解决办法==: 将路径转至bin所在目录下依然报同样错误,最后用了最直接的方法将PSScriptRoot改为%your path%\\neo4j\\bin,如图: 参考:https://blog.csdn.net/moxiaobeimm/article/details/87275756 2.4 安装neo4jwindows服务 Neo4j也可以作为Windows服务运行。使用neo4j install-service安装服务,并使用neo4j start启动它。 由于我们是首次在windows上安装neo4j,所以要先安装服务。 进入这个bin文件夹 ,++按住shift + 右键鼠标 –> 在此处打开命令行++, 输入以下命令:;1neo4j install-service 3. neo4j的使用3.1 修改密码Neo4j服务器具有一个集成的浏览器,在一个运行的服务器实例上访问 “ http://localhost:7474/ ”,打开浏览器,显示启动页面 默认的host是bolt://localhost:7687,默认的用户是neo4j,其默认的密码是:neo4j,第一次成功登陆到Neo4j服务器之后,需要重置密码。 我设置为:root 访问Graph Database需要输入身份验证,Host是Bolt协议标识的主机。 3.2 示例编写Cypher命令,用四条语句创建两个节点和两个关系: 1234CREATE (n:Person { name: 'Andres', title: 'Developer' }) return n;CREATE (n:Person { name: 'Vic', title: 'Developer' }) return n;match(n:Person{name:"Vic"}),(m:Person{name:"Andres"}) create (n)-[r:Friend]->(m) return r;match(n:Person{name:"Vic"}),(m:Person{name:"Andres"}) create (n)<-[r:Friend]-(m) return r; 在$ 命令行中,编写Cypher脚本代码,点击Play按钮,点击创建第一个节点,1CREATE (n:Person { name: 'Andres', title: 'Developer' }) return n; 在第一个节点创建之后,在Graph模式下,能够看到创建的图形,继续编写Cypher脚本,创建其他节点和关系 在创建完两个节点和关系之后,查看数据库中的图形: 参考:https://www.cnblogs.com/ljhdo/p/5521577.html 3.3 如何导入mysql数据https://segmentfault.com/a/1190000014521657","link":"/2019/05/02/Windows下neo4j安装使用/"},{"title":"Windows下用Anaconda安装TensorFlow并在pycharm中使用","text":"笔者之前在学习TensorFlow,也在自己的笔记本上完成了安装,在PyCharm中进行学习。但是最近为了使用Python的科学计算环境,我把之前的环境卸载了,并用Anaconda重新安装了TensorFlow,由于自己的笔记本已经很旧了,显卡不行,所以这里介绍一下cpu版本的安装方法和自己遇到的一些坑,截图甚多。 这里直接上干货: 1.安装Anaconda 选择相应的Anaconda进行安装,下载地址点击这里,下载对应系统版本的Anaconda,官网现在的版本是Anaconda 4.3.1 for python3.6。笔者安装的是4.3.0版本的。 就和安装普通的软件一样,全部选择默认即可,注意勾选将python3.6添加进环境变量。 这样Anaconda就安装好了,我们可以通过下面的命令来查看Anaconda已经安装了哪些包。运行 开始菜单->Anaconda3—>Anaconda Prompt :1conda list 可以看到已经安装了numpy、sympy等常用的包。 2.安装TensorflowTensorFlow目前在Windows下只支持python 3.5版本。 (1)打开Anaconda Prompt,输入清华仓库镜像,这样更新会快一些: 12conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/conda config --set show_channel_urls yes (2)同样在Anaconda Prompt中利用Anaconda创建一个python3.5的环境,环境名称为tensorflow ,输入下面命令:1conda create -n tensorflow python=3.5 运行 开始菜单->Anaconda3—>Anaconda Navigator,点击左侧的Environments,可以看到tensorflow的环境已经创建好了。 (3)在Anaconda Prompt中启动tensorflow环境:1activate tensorflow 注:当不使用tensorflow时,关闭tensorflow环境,命令为:deactivate(4)安装cpu版本的TensorFlow1pip install --upgrade --ignore-installed tensorflow 注:这里没有介绍GPU版本的安装方法,GPU版本需要安装cuda8+cudnn5,如需要的请搜索其他博文。 注意:一定要在 刚刚创建的tensorflow的环境下安装!!!!这样tensorflow cpu版本就安装好了。 (5)测试tensorflow在Anaconda Prompt中启动tensorflow环境,并进入python环境。测试代码如下:1234import tensorflow as tfhello = tf.constant('Hello, TensorFlow!')sess = tf.Session()print(sess.run(hello)) 运行结果: 3.其他问题或许到这里我们并没有满足,我们在Anaconda自带的ipython 和Spyder中import tensorflow的时候一直失败,提示 No module named ‘tensorflow’,如下图,那是因为我们没有在tensorflow的环境下打开它们。 为了能在ipython 和Spyder中使用tensorflow,我们需要在tensorflow的环境中安装这两个的插件。 打开Anaconda Navigator,选择Not installed,找到 ipython和Spyder并安装,笔者这里已经安装好,所以在这个页面没有显示。 切换到installed,可以看到两个都已经安装好,其实可以按照自己的需要安装。下图显示已经安装好的Spyder: 安装好插件后,我们需要测试一下。 在Anaconda Prompt中启动tensorflow环境,并运行ipython,import tensorflow发现成功: 同样,在Anaconda Prompt中启动tensorflow环境,并运行Spyder,等一会儿后会启动Spyder IDE,import tensorflow 同样成功: 注意:一定要启动tensorflow 环境下的Spyder才可以import tensorflow,不要去开始菜单运行Spyder,在那里是无法运行的,如: 4.在pycharm中使用tensorflow习惯了使用PyCharm来开发,配置如下:新建工程后在 File-Setting–Project Interpreter选择tensorflow下的Python解释器, 例如我的解释器位置: 等部署完后便可跑个HelloWorld了12345import tensorflow as tfhello = tf.constant("Hello!TensorFlow")sess = tf.Session()print(sess.run(hello)) 运行一下 起飞! 这种方式的好处:不用每次都 开启、关闭环境了。(activate tensorflow 、deactivate tensorflow)","link":"/2017/07/03/Windows下用Anaconda安装TensorFlow并在pycharm中使用/"},{"title":"bat2018自然语言处理校园招聘的要求","text":"寻找了多家国内主要IT公司有关NLP的2018校园招聘,于大家分享。另外查漏补缺,看看自己缺乏那些方面的经验和技术。下面直接放结论,没时间的可以只看总结: 总结: 主要在以下几个方面有要求,打勾的次数反应了热度: 自然语言处理相关的具体操作:分词、语义、句意、对话、机器翻译、自动问答等√√√√√ 经典的机器学习算法、竞赛经历√√√ 多线程、网络编程、分布式编程√ hadoop、spark√√√√ SQL、NoSQL√ linux√√前面3个更面向纯NLP,而后面的知识偏向数据分析,其实这两个岗位相辅相成,很多技能都是共通的。 2018 阿里算法工程师-自然语言处理 Software engineer -Natural Language Processing岗位描述Job Description阿里巴巴广阔的商业生态需要丰富且深入的的自然语言处理技术,涵盖底层文本知识库建设、词法分析、句法分析、语义分析、文档分析、深度文本表示、文本生成、机器翻译、智能对话等。阿里巴巴的自然语言处理技术正在推进平台化、服务化策略,不断追求技术的深度以及技术与业务的适当解耦。本岗位需要招聘自然语言处理专业的优秀本科、硕士、博士毕业生一起来夯实基础、赋能商业,实现技术与商业的完美结合。期待追求卓越、自我驱动、聪明、乐观、自省、皮实的优秀人士加入阿里巴巴,共同开创人工智能的商业新格局。 具体职责包括但不限于:1、紧跟业界最新自然语言处理技术动态,深入研发自然语言处理相关的知识库、词法、句法、语义、文档、深度学习、机器翻译、智能对话等技术,包括模块的实际开发以及对接自然语言处理平台的接入;2、理解自然语言处理技术应用的相关的业务场景及需求,在自然语言处理技术内核的基础上考虑业务场景的特殊性进而适当适配业务需求;3、在核心技术研发之外,也会适当参与到具体的NLP相关业务中,例如搜索Query分析、智能对话的语义解析及意图理解、商品评价的语义理解、内容搜索推荐的结构化分析、商品搜索推荐的标签体系、社会化问答的文本分析、智能客服的场景定制等; 岗位要求Qualifications1、本科及以上学历,硕士博士优先,计算机、数学、信息管理等相关专业;2、具备极佳的工程实现能力,精通C/C++、Java、Python、Perl等至少一门语言;3、精通自然语言处理领域的1到2项底层技术,有实际成果并发表在自然语言处理国际顶级会议、期刊者优先,有在相关的自然语言处理竞赛中获得优异成绩者优先;4、熟悉深度学习以及常见机器学习算法的原理与算法,能熟练运用聚类、分类、回归、排序等模型解决有挑战性的问题,有大数据处理的实战经验;5、有强烈求知欲,对人工智能领域相关技术有热情;6、具有良好的数学基础,良好的英语阅读能力;7、有团队意识,与他人合作良好,最好具有团队协作的经验。 工作地点Location成都市(Chengdu),上海市(Shanghai),杭州市(Hangzhou),北京市(Beijing),广州市(Guangzhou)参加面试的城市或地区Interview City or Region远程(Remote Interviews) 2018 腾讯岗位描述腾讯拥有上亿量级的产品数据、极其丰富的产品场景、超大规模的计算资源、全谱领域的深厚技术积累、追求极致的创新氛围、适宜年轻人的企业文化,可为您提供充分的专业发挥空间,让您有可能做出影响整个互联网行业发展的优秀成果。 该岗位主要职责包括但不限于:1、 负责词法分析、自动对话、语义挖掘和语言逻辑等相关研究工作;2、 负责自然语言处理的算法研发,包括但不限于语义分析、意图识别、人机对话、机器翻译、知识图谱、命名实体识别等;3、 负责NLP前沿问题的研究,结合未来实际应用场景,提供技术解决方案。 岗位要求1、 计算机、应用数学、模式识别、人工智能、自控、统计学、运筹学、生物信息、物理学/量子计算、神经科学、社会学/心理学等专业,本科及以上,博士优先;2、 熟悉至少一种编程语言,包括但不限于java、C/C++、C#、python等;3、 在学术会议ACL、EMNLP、NAACL、COLING、IJCAI、AAAI等发表过文章,有深度学习学术或工程项目经验优先;4、 熟悉自然语言处理领域的1到2项底层技术,有实际成果并发表在自然语言处理国际顶级会议、期刊者优先,有在相关的自然语言处理竞赛中获得优异成绩者优先。 工作地点深圳 北京 上海 广州 成都招聘城市哈尔滨 杭州 北京 南京 远程面试 2018 百度北京-机器学习/数据挖掘/自然语言处理工程师所属部门: 百度工作地点: 北京市招聘人数: 210公 司: 百度职位类别: 技术发布时间: 2017-07-28 工作职责: 研究数据挖掘或统计学习领域的前沿技术,并用于实际问题的解决和优化 大规模机器学习算法研究及并行化实现,为各种大规模机器学习应用研发核心技术 通过对数据的敏锐洞察,深入挖掘产品潜在价值和需求,进而提供更有价值的产品和服务,通过技术创新推动产品成长职责要求: 热爱互联网,对技术研究和应用抱有浓厚的兴趣,有强烈的上进心和求知欲,善于学习和运用新知识 具有以下一个或多个领域的理论背景和实践经验:机器学习/数据挖掘/深度学习/信息检索/自然语言处理/机制设计/博弈论 至少精通一门编程语言,熟悉网络编程、多线程、分布式编程技术,对数据结构和算法设计有较为深刻的理解 良好的逻辑思维能力,对数据敏感,能够发现关键数据、抓住核心问题 较强的沟通能力和逻辑表达能力,具备良好的团队合作精神和主动沟通意识具有以下条件者优先: 熟悉文本分类、聚类、机器翻译,有相关项目经验 熟悉海量数据处理、最优化算法、分布式计算或高性能并行计算,有相关项目经验 2018 网易NLP算法研发工程师(网易杭州) 岗位描述1、负责NLP技术在自动问答、人机对话、语义理解等方向上的应用研究;2、负责NLP相关核心技术研发及前沿算法跟踪,根据产品需求完成技术转化,推动业务发展。 岗位要求我们希望你是:1、正直诚信、有责任感、有激情;2、模式识别/人工智能/数学/计算机相关专业,硕士以上学历;3、熟悉基于统计和句法/语法分析的自然处理方法,包括分词、词性标注、命名实体识别、依存句法分析、文本分类、文本检索、Deep Learning在NLP领域中的应用等等;4、具有较强编程能力(熟悉C++/Java),熟练使用至少一种脚本语言(python/shell等),熟悉hadoop、spark框架者尤佳;5、在自动问答、人机对话、口语理解、知识库管理等领域有实际的开发经验者优先;6、学习能力强,能独立分析并解决问题。 2018 科大讯飞研究员(自然语言处理方向)工作地点: 合肥市,北京市…工作经验:学 历:工作类型: 全职招聘人数:若干发布时间:2017-08-04 职位描述您可以:1、负责语言理解、人机对话、意图识别、知识图谱、命名体识别等相关算法的研究和开发2、负责机器翻译相关算法的研究和开发 任职要求我们需要您具备以下条件:1、重点院校硕士及以上学历,计算机、信号处理、自动化、应用数学等相关专业,具备一定的数理统计、模式识别、自然语言处理等理论知识2、英语六级以上,具备中英文学术论文的调研能力,有从事研究型项目的经历3、具备较好的C、C++或python等热门脚本语言编程能力,有一定的代码开发经历 如果将优先考虑:1、熟悉RNN、CNN等深度学习算法及其常用工具如Caffe、Theano、TensorFlow等2、熟悉深度学习算法在自然语言理解中的应用3、有自然语言理解相关方向较丰富的实际系统研究和开发经验者4、在ACL、COLING、IJCAI、AAAI、ICLR、NIPS等会议上发表过文章,有深度学习学术或工程项目经验者 2018 科大讯飞大数据分析工程师工作地点: 合肥市工作经验:学 历:本科及以上工作类型: 全职招聘人数:若干发布时间:2017-08-04 职位描述1、通过对数据的敏锐洞察,深入挖掘产品和服务的潜在价值和需求,进而提供更有价值的产品和服务,通过技术创新推动产品成长2、通过统计分析和数据挖掘算法解决实际问题,主要聚焦于城市动态产生的海量数据,进行城市交通分析、规划分析、商业地产分析等 任职要求1、热爱技术,对技术研究和应用抱有浓厚的兴趣,善于学习和运用新知识2、具备商业分析报告撰写能力和良好的逻辑思维能力,对数据敏感,能够发现关键数据、抓住核心问题3、较强的沟通能力和逻辑表达能力,具备良好的团队合作精神和主动沟通意识4、具有以下一个或多个领域的理论背景和实践经验:统计、数学、信息技术、计算机等5、至少精通一门编程语言(C/C++,Java,Python,Scala等),了解Hadoop/Spark分布式编程技术6、至少掌握一种数据分析工具(R,SAS,SPSS,Matlab等),熟练运用SQL7、具有数据挖掘、海量数据处理等相关项目经验者优先 2018 美团点评【2018届】机器学习/数据挖掘算法工程师-北京工作地点:北京职位类型:技术研发招聘类别:应届毕业生发布时间:2017-08-10 15:12:00 岗位职责:在这里,你将通过机器学习、数据挖掘、深度/增强学习前沿技术对海量O2O数据进行洞察和预测,提高线下服务效率,优化线上用户体验,人和服务的高效连接潜力无限,帮助亿万用户吃得更好过得更好;在这里,你将从海量浏览和交易数据中不断抽象模式建立模型,一手保障商户在线营销可靠安全,另一手为消费者呈现有效评价提供优质服务,用技术提升消费质量;在这里,你可以发挥你的算法天赋,在海量数据的平台上实践各种机器学习和挖掘算法,搜索、推荐、广告、调度、无人配送、风控、金融、ERP和智能化交互,为你提供最广阔的施展天地。 工作要求: 良好的数据结构和算法基础,具有较强的程序开发和分布式系统实现能力;2. 熟练掌握数据库设计原理,对NoSQL和分布式计算有理解和实践;3. 对概率论、机器学习和自然语言处理有一定的理论基础,在深度学习/增强学习/最优化等方向有理解或实践;4. 对数据敏感,思维逻辑清晰,对业务问题充满好奇,相信大数据背后的力量。 2018 美团点评【2018届】自然语言处理开发工程师-上海工作地点:上海职位类型:技术研发招聘类别:应届毕业生发布时间:2017-08-10 15:06:40 岗位职责:在这里,你将有机会深入研究自然语言处理领域的特定技术;在这里,你将用深度语义理解,让我们更懂用户;在这里,你将用深度语义计算,让我们精准匹配用户需求;在这里,你将用智能问答技术,让我们为客户实时解决各种问题。 工作要求: 熟练掌握自然语言处理领域的基础理论和方法,并有丰富的相关方向的研究经验;2. 在一个或多个领域有深入研究:分词、文本分类、语义分析、语义表示、语义匹配、组块分析、主题模型、篇章分析等;3. 熟练掌握C/C++Python/Perl/Shell等编程语言及数据结构基础算法;4. 优秀的分析问题和解决问题的能力,对解决具有挑战性问题充满激情。 2017携程你敢吗?携程作为中国在线旅游的领军企业,是一家崇尚数据驱动文化的公司。BI团队做为Ctrip的数据和数据应用中心,不断实践数据驱动的文化,不断利用数据和数据模型来解决Ctrip十三个业务线中的各种业务问题。您将有机会和旅游领域的业务、流程、研发、基数数据、资深机器学习专家等领域的专家合作。我们的数据科学家团队的理念是,理解问题、解决问题、驱动问题。您将会分析产品、操作、流量、用户甚至财务绩效相关的数据,从而能够更好的驱动业务发展的机会。您将有足够的支持把你的发现变成业务成果,一起分享Ctrip成功的业务结果。 岗位介绍1、与产品沟通并准确理解需求;2、评估需求的可行性、设计算法并成功植入系统。携程旅行2018届春季实习生招聘已经启动!欢迎关注官方微信公众号:ctriptech_campus官方校招QQ群:314810731、545235287、529598646、278735052、541803697(添加任意一个即可) 我们寻找这样的你1、2018届毕业生,全日制硕博。计算机或相关专业;2、熟悉算法相关理论,算法原理和机器学习基本理论,具备扎实良好的数学基础;3、熟悉中文分词、文本分类/聚类、语言模型、语义分析、情感分析、信息检索、问答系统设计等至少其中两项NLP相关算法;4、精通Java/C++/Python/Perl任意一种语言,熟练掌握SQL/Hive;5、良好的数据分析能力,能够从数据中发现规律;6、熟悉Linux环境/Shell命令;7、熟悉分布式计算Hadoop/hive/Spark/Map-Reduce等相关技术;8、具备深度学习相关项目经验者优先;9、至少能保证暑期7、8月份在公司实习。(通过实习考核即签三方) 2018 小米职位名称: 数据挖掘工程师 工作地点: 北京职位类别: 研发工程师 招聘渠道: 校园招聘招聘地点: 北京 工作职责:方向一:负责公司级数据产品与平台的设计与管理,对公司各部分业务数据进行数据采集、抽取、整合、提取和数据可视化等工作;方向二:负责小米数据管理平台的设计与研发,基于亿级用户的大数据,建立小米用户画像和用户标签体系,建设数据管理平台提供商业智能分析;*方向三:负责大数据的分析与挖掘,针对海量信息建模,挖掘潜在商业价值,预测用户行为,为产品决策及优化提供数据支持与建议;方向四:负责个性化推荐服务系统的运营与设计,将海量内容精准送达至海量的用户。 工作要求:1、熟悉数据挖掘、机器学习, 自然语言处理等相关技术者优先考虑;2、拥有Hadoop、Spark等分布式环境开发经验者优先考虑;3、熟悉Linux,java、 Python (或Shell脚本 );4、优秀的分析和解决问题的能力,对大数据挖掘充满激情; 2018今日头条算法工程师 岗位描述:1、利用机器学习技术,改进头条的推荐、广告系统,优化数亿用户的阅读体验;2、分析基础数据,挖掘用户兴趣、文章价值,增强推荐、广告系统的预测能力;3、分析用户商业意图,挖掘流量潜在商业价值,提升流量变现;4、研究计算机视觉算法,给用户提供更多更酷炫的功能。 岗位要求:1、2018年应届毕业生,本科及以上学历,计算机、机器学习和模式识别相关专业;2、热爱计算机科学和互联网技术,对人工智能类产品有浓厚兴趣;3、具备强悍的编码能力,熟悉 linux 开发环境,熟悉 C++ 和 Python 语言优先;4、有扎实的数据结构和算法功底,熟悉机器学习、自然语言处理、数据挖掘、分布式计算、计算机视觉中一项或多项;5、对推荐系统、计算广告、搜索引擎、图像和视频处理相关技术有经验者优先;6、优秀的分析问题和解决问题的能力,对解决具有挑战性问题充满激情。、、 无码科技自然语言处理工程师于 无码科技 in 杭州无码科技致力构建值得用户信赖的搜索引擎。我们要找自然语言处理工程师。期待找到长期的合作伙伴,创始团队成员。 职位描述:利用自然语言处理和机器学习算法对海量文本数据进行挖掘分析,包括但不限于文本聚类、语义理解、信息抽取、知识图谱、对话生成等。尝试新的机器学习算法、计算框架,提升机器学习系统效率。 职位要求:两年以上自然语言处理相关的研发经验。具备较强的编码能力,扎实的数据结构和算法功底。熟悉机器学习的基本算法与概念,如:逻辑回归、神经网络、决策树等。熟悉自然语言处理常见算法与模型(如 LDA、Word2Vec、CNN/RNN 等)。较好的英文技术文献阅读能力。 加分项:发表过高水平学术会议论文。熟悉 Apache Hadoop/Spark/Storm 等至少一种分布式系统。有过在医疗数据上应用机器学习 / 自然语言处理 (NLP) 的经历。工作地点:杭州市滨江区。 总结:主要在以下几个方面有要求,打勾的次数反应了热度: 自然语言处理相关的具体操作:分词、语义、句意、对话、机器翻译、自动问答等√√√√√ 经典的机器学习算法、竞赛经历√√√ 多线程、网络编程、分布式编程√ hadoop、spark√√√√ SQL、NoSQL√ linux√√","link":"/2017/08/11/bat2018自然语言处理校园招聘的要求/"},{"title":"coursera-斯坦福-机器学习-吴恩达-机器学习课程总结","text":"1结论1.1总结和致谢 在这门课中 我们花了大量的时间 介绍了诸如线性回归 逻辑回归 神经网络 支持向量机 等等一些监督学习算法, 这类算法需要带标签的数据和样本 ,比如 x(i) y(i)。 然后我们也花了很多时间介绍无监督学习 ,例如 K-均值聚类 用于降维的主成分分析。 以及当你只有一系列无标签数据 x(i) 时的 异常检测算法, 当然 有时带标签的数据 也可以用于异常检测算法的评估 。此外 我们也花时间讨论了一些特别的应用 ,或者特别的话题 比如说推荐系统 以及大规模机器学习系统 ,包括并行系统和映射化简方法。 还有其他一些特别的应用比如 用于计算机视觉技术的滑动窗口分类算法 。 最后 我们还提到了很多关于构建 机器学习系统的实用建议 ,这包括了怎样理解 某个机器学习算法, 是否正常工作的原因。 所以我们谈到了偏差和方差的问题, 也谈到了解决方差问题的正则化 ,同时我们也讨论了 怎样决定接下来做什么的问题, 也就是说当你在开发一个机器学习系统时 什么工作才是接下来应该优先考虑的问题。 因此我们讨论了学习算法的评价方法 ,介绍了评价矩阵 比如 查准率 召回率以及F1分数, 还有评价学习算法比较实用的 训练集 交叉验证集和测试集。 我们也介绍了学习算法的调试 以及如何确保 学习算法的正常运行, 于是我们介绍了一些诊断方法 ,比如学习曲线, 同时也讨论了 误差分析 上限分析的内容 。 所有这些工具都能在你开发机器学习系统时 帮助你决定接下来应该做什么, 怎样把宝贵的时间用在刀刃上 。现在你已经掌握了很多机器学习的工具, 包括监督学习算法和无监督学习算法等。 但除了这些以外, 我更希望你现在不仅仅只是认识这些工具 ,更重要的是掌握怎样有效地利用这些工具 来建立强大的机器学习系统 。 就是这样 以上就是这门课的全部内容 ,如果你跟着我们的课程一路走来 ,到现在 你应该已经感觉到 自己已经成为机器学习方面的专家了吧 。 所以 我衷心地希望你们能从这门课中有所收获 最后我想说 再次感谢你们选修这门课程! 1.2成果到这里,这门《机器学习》公开课算是上完了,吴老师也说上万这门课就是“专家”,但是机器学习的路才刚刚开始。这门课程只能是机器学习的入门课程。吴老师用最简单的方式带领我们走进这个领域,给了我们实现未来的可能。下一步,应该做的: 对于课程中的模糊的点,老师一带而过的点,重点回顾并总结。 通过书本,通过比较不同学者的理解来,系统的复习一下《机器学习》的框架(推荐《西瓜书》)。 做一个小项目,在实践中练习:1.编程技术 2.模型的实现 3.优化的能力 最后,衷心的感谢吴恩达老师,经过这个课程我懂得了什么是思考、分享和坚持。 上面是coursera上完成课程给的证书,一般要300¥左右才能购买;而在校学生可以通过申请网站助学金免除这一费用(再次感谢吴老师)。 下附我的助学金申请书模板(必须是英文),给有需要的童鞋下载:http://download.csdn.net/download/u012052268/10199129 在学习的过程中,积累的编程作业的答案:http://download.csdn.net/download/u012052268/10199117","link":"/2018/01/10/coursera-斯坦福-机器学习-吴恩达-机器学习课程总结/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第10周笔记-使用大数据训练","text":"1 大数据下的梯度下降在接下来的几个视频里 ,我们会讲大规模的机器学习, 就是用来处理大数据的算法。 如果我们看近5到10年的机器学习的历史 ,现在的学习算法比5年前的好很多, 其中的原因之一就是我们现在拥有很多可以训练算法的数据 。 1.1 大数据为什么我们喜欢用大的数据集呢? 我们已经知道 得到一个高效的机器学习系统的最好的方式之一是 用一个低偏差的学习算法 ,然后用很多数据来训练它. 当然 ,在我们训练一个上亿条数据的模型之前 ,我们还应该问自己: 为什么不用几千条数据呢 ?也许我们可以随机从上亿条的数据集里选个一千条的子集,然后用我们的算法计算。 通常的方法是画学习曲线 : 如果你要绘制学习曲线,并且如果你的训练目标看起来像是左边的,而你的交叉验证集目标,theta的Jcv,那么这看起来像是一个高方差学习算法,所以加入额外的训练样例提高性能。 右边看起来像传统的高偏见学习算法,那么看起来不大可能增加1亿到1亿将会更好,然后你会坚持n等于1000,而不是花费很多的精力弄清楚算法的规模如何。 正确的做法之一是增加额外的特性,或者为神经网络增加额外的隐藏单位等等,这样你就可以得到更接近于左边的情况,在这种情况下可能达到n 等于1000,这样就给了你更多的信心,试图添加基础设施(下部构造)来改变算法,使用更多的例子,可能实际上是一个很好的利用你的时间。 1.2 随机梯度下降对于很多机器学习算法, 包括线性回归、逻辑回归、神经网络等等, 算法的实现都是通过得出某个代价函数 或者某个最优化的目标来实现的, 然后使用梯度下降这样的方法来求得代价函数的最小值。 当我们的训练集较大时 ,梯度下降算法则显得计算量非常大 ,在这段视频中 我想介绍一种跟普通梯度下降不同的方法 随机梯度下降(stochastic gradient descent) 。 他的主要思想是: {在每次迭代中不需要看所有的训练样例,但是在一次迭代中只需要看一个训练样例} 第一步是打乱数据 第二步是算法的关键 是关于某个单一的训练样本(x(i),y(i))来对参数进行更新 对于随即梯度下降来说,有以下说法: 当训练集的个数m很大的时候,随即梯度下降比梯度下降要快很多。 对与损失函数$J\\text{train}(\\theta) = \\frac{1}{2m}\\sum{i=1}^m (h_\\theta(x^{(i)}) - y^{(i)})^2$来说,梯度下降每次迭代都会减小,而随即梯度下降不一定减小,甚至可能增大。 随即梯度下降可以用在多种模拟的优化中。 在随机梯度下降之前,最好(必须)打乱训练集的顺序。 与随机梯度下降相比,每次迭代都要快得多,因为我们不需要总结所有的训练样例。但是每次迭代只是试图更好地适应单个训练样例。 随即梯度下降的劣势:当你运行随机梯度下降时,你会发现它通常会将参数向全局最小值的方向移动,但并不总是如此。事实上,当运行随机梯度下降时,它实际上并没有收敛到相同的固定值,最终做的是在一些接近全局最小值的区域连续四处流浪,但是它不会达到全局最小值并停留在那里。对于任何最实际的目的来说,这都是一个很好的假设。 所以:选择随机梯度下降还是批梯度下降? 答案:数据量大的时候使用随机梯度下降,而数据量不那么大的话还是用批梯度下降吧。 1.3 mini-batch梯度下降在之前的视频中 我们讨论了随机梯度下降 ,以及它是怎样比批量梯度下降更快。 在这次视频中, 让我们讨论基于这些方法的另一种变形, 叫做小批量梯度下降。 这种算法有时候甚至比随机梯度下降还要快一点 。 由上图可以看出 批量梯度下降、随即梯度下降、小批量梯度下降的区别。小批量介于二者的规模的中间。具体计算方法如下图,选b个样本计算。(当b等于m的时候,minibatch就成了batch GD。) 尤其是,小批量梯度下降可能要超过随机梯度下降,只有当你有一个良好的实现时,通过使用适当的向量化来计算余下的项。 1.4 随机梯度下降的收敛性现在你已经知道了随机梯度下降算法 ,但是当你运行这个算法时 你如何确保调试过程已经完成 并且能正常收敛呢? 还有 同样重要的是 你怎样调整随机梯度下降中学习速率α的值? 在这段视频中 我们会谈到一些方法来处理这些问题 ,确保它能收敛 以及选择合适的学习速率α 。 在过去的1000个示例中绘制平均成本的平均值,这些图可能看起来像几个例子,看图修正模型: 因为这些数字平均只有一千个例子,所以它们会有点吵,所以每一次迭代都不会减少。 图2红线:通过平均5000个例子,而不是1,000个,你可能会得到更加平滑的曲线。 图3平均数量较多的例子,我们在这里取平均值超过5000个例子,可能得到两种较平缓的曲线。如果得到的是洋红色水平线,你需要改变学习率或改变特征 改变算法的其他内容。 图4如果你看到一条曲线正在增加,那么这是一个信号,表明算法是发散的。你真正应该做的就是把学习速率α的值作为一个微不足道的值。降低学习速率α意味着每一次随机梯度下降的迭代将会 采取一个较小的步骤,因此它可能会聚,而不是分歧。 总结:因此,如果曲线看起来过于嘈杂,或者如果它太多摆动,那么尝试增加你平均的例子的数量,这样你可以更好地看到情节的整体趋势。如果你看到错误是实际上增加,成本实际上是增加,尝试使用较小的alpha值。 最后还需要再说一下关于学习速率的问题 如果你想要随机梯度下降实际收敛到全局最小值,那么你可以做的一件事是你可以慢慢地降低α的学习速率。迭代次数是你运行的随机梯度下降的迭代次数 ,所以这真的是你见过的培训例子的数量。 2 大数据的高级技巧2.1在线学习什么情况下使用在线学习?如果你运行一个主要的网站有一个连续的用户流,在线学习算法是非常合理的。因为数据本质上是免费的,如果你有这么多的数据,那么数据本质上是无限的当然,如果我们只有少量的用户,而不是使用在线学习算法,那么最好将所有的数据保存在一个固定的训练集中,然后运行一些算法。但是如果你真的有一个连续的数据流,那么在线学习算法可以是非常有效的。 这种在线学习算法的一个有趣效果就是,它能够适应不断变化的用户偏好。尤其是,如果随着时间的推移,由于经济的变化,用户的价格敏感度会降低,他们愿意支付更高的价格。如果你开始有新类型的用户来到你的网站。这种在线学习算法也可以适应不断变化的用户喜好,并跟踪你不断变化的用户愿意支付的种类。而且,因为如果你的用户池发生了变化,那么这些更新到你的参数theta将只是适应你的参数, 在线学习的优势: 可以适应用户的品味变化。 允许我们对流数据进行学习。 2.2 mapreduce在上面几个视频中 我们讨论了 随机梯度下降 以及梯度下降算法的 其他一些变种, 包括如何将其 运用于在线学习 ,然而所有这些算法 都只能在一台计算机上运行 。 但是 有些机器学习问题 太大以至于不可能 只在一台计算机上运行 ,有时候 它涉及的数据量如此巨大 以至于不论你使用何种算法 ,你都不希望只使用 一台计算机来处理这些数据 。 因此 在这个视频中 我希望介绍 进行大规模机器学习的另一种方法 称为映射约减 (map reduce) 方法。 注意: 如果没有网络延迟,并且没有网络通信的费用来回发送数据,则可以达到4倍的速度。 如果您只有一台具有多个处理内核的计算机,则MapReduce也可以适用。因此,与在数据传感器内的不同计算机上使用这种方法相比,网络延迟的问题要少得多。 一些好的MapReduce开源实现,叫做Hadoop,使用你自己的实现或者使用别人的开源实现,你可以使用这些想法来并行化学习算法,并让它们在更大的数据集上运行。 3quiz Suppose you are training a logistic regression classifier using stochastic gradient descent. You find that the cost (say, cost(θ,(x(i),y(i))), averaged over the last 500 examples), plotted as a function of the number of iterations, is slowly increasing over time. Which of the following changes are likely to help?答案:D This is not an issue, as we expect this to occur with stochastic gradient descent.、 Try averaging the cost over a larger number of examples (say 1000 examples instead of 500) in the plot. Try using a larger learning rate α. Try using a smaller learning rate α. Which of the following statements about stochastic gradientdescent are true? Check all that apply.答案:CD In order to make sure stochastic gradient descent is converging, we typically compute Jtrain(θ) after each iteration (and plot it) in order to make sure that the cost function is generally decreasing. Suppose you are using stochastic gradient descent to train a linear regression classifier. The cost function J(θ)=12m∑mi=1(hθ(x(i))−y(i))2 is guaranteed to decrease after every iteration of the stochastic gradient descent algorithm. You can use the method of numerical gradient checking to verify that your stochastic gradient descent implementation is bug-free. (One step of stochastic gradient descent computes the partial derivative ∂∂θjcost(θ,(x(i),y(i))).) Before running stochastic gradient descent, you should randomly shuffle (reorder) the training set. Which of the following statements about online learning are true? Check all that apply.答案:AB In the approach to online learning discussed in the lecture video, we repeatedly get a single training example, take one step of stochastic gradient descent using that example, and then move on to the next example. When using online learning, in each step we get a new example (x,y), perform one step of (essentially stochastic gradient descent) learning on that example, and then discard that example and move on to the next. One of the disadvantages of online learning is that it requires a large amount of computer memory/disk space to store all the training examples we have seen. One of the advantages of online learning is that there is no need to pick a learning rate α. Assuming that you have a very large training set, which of the following algorithms do you think can be parallelized using map-reduce and splitting the training set across different machines? Check all that apply.答案:BD Logistic regression trained using stochastic gradient descent. Linear regression trained using batch gradient descent. An online learning setting, where you repeatedly get a single example (x,y), and want to learn from that single example before moving on. A neural network trained using batch gradient descent. Which of the following statements about map-reduce are true? Check all that apply.答案:BCD Running map-reduce over N computers requires that we split the training set into N2 pieces. In order to parallelize a learning algorithm using map-reduce, the first step is to figure out how to express the main work done by the algorithm as computing sums of functions of training examples. When using map-reduce with gradient descent, we usually use a single machine that accumulates the gradients from each of the map-reduce machines, in order to compute the parameter update for that iteration. If you have just 1 computer, but your computer has multiple CPUs or multiple cores, then map-reduce might be a viable way to parallelize your learning algorithm. 第五题的第二个版本:第 5 个问题Which of the following statements about map-reduce are true? Check all that apply.答案:ABD If you have only 1 computer with 1 computing core, then map-reduce is unlikely to help. Because of network latency and other overhead associated with map-reduce, if we run map-reduce using N computers, we might get less than an N-fold speedup compared to using 1 computer. If we run map-reduce using N computers, then we will always get at least an N-fold speedup compared to using 1 computer. When using map-reduce with gradient descent, we usually use a single machine that accumulates the gradients from each of the map-reduce machines, in order to compute the parameter update for that iteration.","link":"/2018/01/07/coursera-斯坦福-机器学习-吴恩达-第10周笔记-使用大数据训练/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第11周笔记-ORC系统","text":"1图像ORC1.1问题描述在这一段介绍一种 机器学习的应用实例 照片OCR技术。 我想介绍这部分内容的原因 主要有以下三个 , 第一 我想向你展示 一个复杂的机器学习系统 是如何被组合起来的 第二 我想介绍一下 机器学习流水线(machine learning pipeline)的有关概念, 以及在决定下一步做什么时, 如何分配资源。 最后,通过介绍照片OCR问题 的机会来告诉你, 机器学习的诸多 有意思的想法和理念 。其中之一是如何将机器学习 应用到计算机视觉问题中, 第二是有关 人工数据合成(artificial data synthesis)的概念。 OCR技术 主要解决的问题是让计算机 读出照片中拍到的文字信息。 OCR pipeline的意思主要是把一个ML系统分割为几个连续的部分,如下图: 如果你有一个工程师的团队 在完成同样类似的任务, 那么通常你可以让 不同的人来完成 不同的模块 ,所以我可以假设 文字检测这个模块 需要大概1到5个人 ,字符分割部分 需要另外1到5个人 ,字母识别部分 还需要另外1到5个人。 在复杂的机器学习系统中 流水线的概念 已经渗透到各种应用中 1.2 滑动窗(sliding windows)为了更好地介绍 图像的检测 ,我们从一个简单一点的例子开始, 我们先看这个探测行人的例子: 在行人检测中 你希望照一张相片 然后找出图像中 出现的行人。 这个问题似乎 比文字检测的问题更简单, 原因是 大部分的 行人都比较相似, 因此可以使用一个固定宽高比的 矩形来分离出你希望找到的行人。 我们要做的是 首先对这个图像取一小块长方形, 比如这是一个 82×36的图像块, 我们将这个图像块 ,通过我们训练得到的分类器 来确定 这个图像块中是不是有行人。 如果没问题的话, 我们的分类器 应该报告这个图像块 y=0 因为没有行人 。 做完这以后 , 我们再向右滑动一点窗口 然后同样地 把图像块传入分类器, 你每次滑动窗口的 大小是一个参数 ,通常被称为 步长(step size) 。这样一个滑动的过程就叫做:滑动窗(sliding windows)。 接下来我们转向 文字识别的例子 ,让我们来看看 对于照片 OCR 流水线中 要检测出文字 需要怎样的步骤 。 第一步通过滑动窗在图像中找出有字母的部分,然后把他变白方便下一步提取。 分割字母,使用滑动窗在上一部提取的像素中提取分割的部分。 —–> 第三步,字母分类。 分类哪个字母或哪个26个字符A到Z。 1.3获取大量的图片Getting Lots of Data and Artificial Data获取大量数据和人工合成数据。 要想获得一个比较高效的 机器学习系统, 其中一种最可靠的办法是 选择一个低偏差的学习算法 ,然后用一个巨大的训练集来训练它 。但你从哪儿得到那么多的训练数据呢? 其实在机器学习中 有一个很棒的想法 叫做“人工数据合成”(artificial data synthesis) 。 就是说用一个小的训练集 将它扩充为一个 大的训练集 ,这节课中 我们将对这两种方法进行介绍 。 为了介绍人工数据合成的概念 让我们还是用之前用过的 照片OCR流水线中 的字母识别问题, 我们输入一个图像数据 然后想识别出是什么字母 。 如果你想要获得 更多的训练样本 ,其中一种方法是你可以 采集同一个字符的不同种字体 ,然后将这些字符 加上不同的随机背景。 比如你可以取这个字母C, 然后把它粘贴到一个随机背景前面 。 因此通过使用合成的数据 ,你实际上已经获得了 无限的训练样本, 这就是人工数据合成 。 idea2: take an existing example and and introducing distortions通过引入扭曲合成数据 注意:网格线覆盖图像只是为了说明的目的。 如果您面临机器学习问题,通常值得做两件事情:其中一个就是头脑清楚,通过学习曲线,可以得到更多的数据。其次,假设情况如此,请问:要获得十倍的创造数据将需要多少时间,但有时候,您可能会感到惊讶,原因可能是几天,几周甚至几天 ,这可以是一个很好的方式来给你的学习算法在性能上有巨大的提升。 1.4分析Ceiling Analysis:What Part of the Pipeline to Work on Next 上限分析-接下来工作重心应放在pipeline哪个部分。 上限分析的想法:通过经历这样的分析,你试图找出什么是上升的潜力,改善这些组件的每一个,或者如果这些组件中的一个变得绝对完美,那么你可能获得多少对该系统的性能提出了一个上限。 首先写出总的项目精度为72%;然后手工把某一个模块设置为“全对”,看模型提升了多少,提升的多说明这个工作有用;提升的少,说明在这里做工作没什么太大意义。 另外一个例子:Another more complex ceiling analysis example人脸识别。 看每一个小块的提升对总的精度提升的大小。 2复习 quiz 第 1 个问题Suppose you are running a sliding window detector to find text in images. Your input images are 1000x1000 pixels. You will run your sliding windows detector at two scales, 10x10 and 20x20 (i.e., you will run your classifier on lots of 10x10 patches to decide if they contain text or not; and also on lots of 20x20 patches), and you will “step” your detector by 2 pixels each time. About how many times will you end up running your classifier on a single 1000x1000 test set image?答案:B 1,000,000 500,000 100,000 250,000 第 2 个问题 Suppose that you just joined a product team that has been developing a machine learning application, using m=1,000 training examples. You discover that you have the option of hiring additional personnel to help collect and label data. You estimate that you would have to pay each of the labellers $10 per hour, and that each labeller can label 4 examples per minute. About how much will it cost to hire labellers to label 10,000 new training examples?答案:D $600 $250 $10,000 $400 第 3 个问题What are the benefits of performing a ceiling analysis? Check all that apply. 答案:AB It can help indicate that certain components of a system might not be worth a significant amount of work improving, because even if it had perfect performance its impact on the overall system may be small. It helps us decide on allocation of resources in terms of which component in a machine learning pipeline to spend more effort on. It is a way of providing additional training data to the algorithm. If we have a low-performing component, the ceiling analysis can tell us if that component has a high bias problem or a high variance problem. Suppose you are building an object classifier, that takes as input an image, and recognizes that image as either containing a car (y=1) or not (y=0). For example, here are a positive example and a negative example: After carefully analyzing the performance of your algorithm, you conclude that you need more positive (y=1) training examples. Which of the following might be a good way to get additional positive examples?答案:A Apply translations, distortions, and rotations to the images already in your training set. Select two car images and average them to make a third example. Take a few images from your training set, and add random, gaussian noise to every pixel. Make two copies of each image in the training set; this immediately doubles your training set size. Suppose you have a PhotoOCR system, where you have the following pipeline:You have decided to perform a ceiling analysis on this system, and find the following:Which of the following statements are true?答案: If the text detection system was trained using gradient descent, running gradient descent for more iterations is unlikely to help much. If we conclude that the character recognition’s errors are mostly due to the character recognition system having high variance, then it may be worth significant effort obtaining additional training data for character recognition. We should dedicate significant effort to collecting additional training data for the text detection system. The least promising component to work on is the character recognition system, since it is already obtaining 100% accuracy.","link":"/2018/01/09/coursera-斯坦福-机器学习-吴恩达-第11周笔记-ORC系统/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第1周笔记","text":"0 前言第一,这门课是最好的机器学习、深度学习入门教程之一,老师很有名气,是深度学习三驾马车之一的吴恩达,而且课程讲的很通俗易懂。 每堂课后面还有编程作业,一定要做。课程推荐使用Octave编程语言,只需要填写核心代码,很适合自学。这门语言很多人没有学过,有些排斥。但是学计算机的同志就是要保持对新事物新工具的热爱,更何况这门语言并不难。 第二,我发现网络上关于这门课的笔记有很多,但是质量参差不齐。有的虎头蛇尾甚至半途而废;有的几乎就是复制英文讲义,没有自己的理解。这也是我写笔记的目的,顺便强化自己的理解。 第三,这门课有官方笔记,自己下载下来,有条件的打印出来。用笔实际写写画画理解会更深刻,比如我的。 1 Introduction介绍-对应笔记lectur1 Introduction介绍-对应笔记lecture11.1 机器学习应用这一章首先简单介绍了,机器学习在现实生活中用的应用例子。吹了一波机器学习未来应用宏伟蓝图,好像又回到大学教室听老师吹牛的感觉~ 1.2 机器学习概念介绍了机器学习的概念:A computer program is said to learn from experience E with respect to some task T and some performance measure P, if its performance on T, as measured by P, improves with experience E. 主要包括了几个名词:你要做的任务T;以往可以学习经验的数据记录E;和判别记录做对否的判别器P 1.3 机器学习分类 监督学习 Supervised learning (已知经验数据E的对错标签“p”) 1.1 回归 regression(连续值) 1.2 分类 classification(离散值) 非监督学习 Unsupervised learning(有以往数据,但不知道他们的分类) 2.1 聚类 clustering 2.2 非聚类 non-clustering 2 一个变量的线性回归 -对应lecture2这一节对应官方笔记lecture2。 2.1 线性回归的表示起始给出了预测房价的例子。 像这样用一条线来模拟房价走势,就叫做线性回归。 这个问题属于监督问题,每个样本都给出了准确的答案。同时因为房价是连续值,所以这是一个回归问题,对给定值预测实际输出。 公式: $h_\\theta(x) = \\theta_0 + \\theta_1*x$ 其中两个θ是位置参数,我们的目的是求出他俩的值。 2.2 Cost function 代价函数我们取怎样的θ值可以使预测值更加准确呢? 想想看,我们应使得每一个预测值hθ和真实值y差别不大,可以定义代价函数如下 $J(\\theta_0, \\theta1) = \\dfrac {1}{2m} \\displaystyle \\sum {i=1}^m \\left ( \\hat{y}{i}- y{i} \\right)^2 = \\dfrac {1}{2m} \\displaystyle \\sum {i=1}^m \\left (h\\theta (x{i}) - y{i} \\right)^2$这样,只需要通过使J值取最小,即可满足需求 那么怎么使J最小化呢?看图:误差与两个参数的关系。 我们看到通过改变斜线的斜率 误差变得很小。也就是选择了右图的中心圈子里。 2.3 参数求解(❤梯度下降法❤)从上图,我们直观的看到,圈子中心误差最小。那么怎样从数学的角度计算得到那个“中心点”呢?老师给的方法是“梯度下降”如图,当我们的成本函数处于图的坑底时,即当它的值是最小值时,我们将知道我们已经成功了。 红色箭头显示图中的最小点。我们这样做的方式是通过我们的成本函数的导数(函数的切线)。切线的斜率是那个点的导数,它会给我们一个走向的方向。我们降低成本功能的方向与最陡的下降。每一步的大小由参数α决定,称为学习率。 公式如下: $\\theta_j = \\theta_j - \\alpha\\frac{\\partial}{\\partial\\theta_j}J(\\theta_0, \\theta_1) $重复计算这个公式,直到函数收敛。 注意更新theta值应同时更新 其中的α称之为步长,在最优化课中我们有好几种方法来确定这个α的值。 这个α如果过小,则收敛很慢;如果过大,则可能导致不收敛。 对于J(θ)的偏导数学推导过程如下:在这里你就看到,我们在构造J(θ)时1/2的出现就是为了与指数的在求导时抵消。 经过简单的替换之后我们就可以得到θ新的迭代公式: 2.4 总结到这里,我们就学习了一个最最简单的机器学习模型求解的全部内容。我们梳理一下,一共有三个层次 的 三个公式。 第一层 模型函数$h_\\theta(x) = \\theta_0 + \\theta_1*x$ 第二层 代价函数$J(\\theta_0, \\theta1) = \\dfrac {1}{2m} \\displaystyle \\sum {i=1}^m \\left (h\\theta (x{i}) - y_{i} \\right)^2$ 第三层 GD法求解参数$\\theta_j = \\theta_j - \\alpha\\frac{\\partial}{\\partial\\theta_j}J(\\theta_0, \\theta_1) $ 就这么简单 ,就可以求出一个预测房价的线性回归模型。 3 线性代数知识复习 -对应lecture33.1 概念线性代数知识,主要理解“向量”和“矩阵”两个概念即可。 a是一个3×2的矩阵,b是一个2×3的矩阵,c是一个3×1的矩阵,d是一个1×2的矩阵。 其中,c只有一列,我们也可以称c为列向量,d只有一行,我们也可以称d为行向量。本课程中,对于向量,默认都是指列向量。 3.2 矩阵运算 矩阵的数乘运算 一个标量(你可以直接理解为一个数字)乘以矩阵,得到的结果为矩阵中的每个元素和该标量相乘,如下 矩阵的转置运算 转置运算通过在矩阵右上角添加一“撇”表示。 矩阵之间的加减法 矩阵之间的加减法要求参与运算的两个矩阵尺寸相同,运算的结果等于两个矩阵对应元素相加 矩阵魔力的来源–矩阵之间的乘法 用第一个矩阵的行元素,乘第二个矩阵的列元素。所以矩阵乘法首先要求参与乘法运算的两个矩阵的尺寸能够“兼容”,具体的要求就是,第一个矩阵的列数与第二个矩阵的行数必须相同。","link":"/2017/11/16/coursera-斯坦福-机器学习-吴恩达-第1周笔记/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第2周笔记","text":"1 多元线性回归1.1 方程多元线性回归指的就是有多个X的情况。比如与房价y有关的变量有:房屋面积x1;位置x2。 此时,我们就要把我们的方程$h_\\theta(x) = \\theta_0 + \\theta_1*x$修改为: $h_\\theta(x) = \\theta_0 + \\theta_1x_1 + \\theta_2x_2 + \\cdots + \\theta_nx_n$其实本质并没有变,就是变量x多了,所以参数θ也跟着多了。但是思想还是没有变:通过误差函数,经过梯度下降求参数。 为了结构统一,我们设 x0=1 ;此时方程应为: $h_\\theta(x) = \\theta_0 + \\theta_1x_1 + \\theta_2x_2 + \\cdots + \\theta_nx_n = \\theta^Tx$如此一来,便将变量向量化了。也变得和第一章的一样了。 1.2 损失函数 与 梯度下降同理,我们写出损失函数。$J(\\theta_0, \\theta_1,…, \\thetan) = \\dfrac {1}{2m} \\displaystyle \\sum {i=1}^m \\left (h\\theta (x{i}) - y_{i} \\right)^2$ 梯度下降的方法也没有变,重复往相减即可。 repeat until convergence:{ $\\theta_j = \\theta_j - \\alpha\\frac{\\partial}{\\partial\\theta_j}J(\\theta) = \\thetaj - \\alpha\\frac{1}{m}\\sum{i=1}^{m}(h_\\theta(x^{(i)}) - y^{(i)})*x_j^{(i)}$} 其中α的选择有讲究:12如果α太小,则收敛速度慢。如果α太大:每次迭代都不会减少,因此可能不会收敛。 1.3 特征约简当两种变量数值维度相差过大的时候,梯度下降法会迭代得很慢,比如房屋面积X1都是100多平米,楼层都是1、2、3这样的数字,两种特征就相差很大。 在这种情况下,我们可以通过使每个输入值在大致相同的范围内来加速梯度下降。(−1 ≤ x(i) ≤ 1) 课程介绍了两种方式:1.特征缩放2.均值归一化 特征缩放就是将数字除以最大的数,比如100<x<300两边都除以100,变成1<x<3 均值归一化 平均归一化包括从该输入变量的值中减去输入变量的平均值,导致输入变量的新平均值为零。 公式: $x_i := \\dfrac{x_i - \\mu_i}{s_i}$其中μi是特征(i)的所有值的平均值,si是值的范围(max - min),或者si是标准偏差。 例如,如果xi代表100到2000的平均值和1000的房价,那么,每个价格都转化为: $x_i := \\dfrac{price-1000}{1900}$ 1.4 小点:多项式回归有些时候,直线并不能很好的拟合数据。有些时候各种曲线反而更好。比如: 在这种时候,除了线性回归外(图像是直线),我们也能采用多项式回归 (图像是曲线)。我们的解决办法是设变量:举例如下假设函数: $h_\\theta(x) = \\theta_0 + \\theta_1x + \\theta_2x^2 + \\theta_3x^3$我们的技巧是 设: x2 and x3 并且使 $x_2 = x_1^2 $$x_3 = x_1^3$ 这样原式子就变成: $h_\\theta(x) = \\theta_0 + \\theta_1x_1 + \\theta_2x_1^2 + \\theta_3x_1^3= \\theta_0 + \\theta_1x_1 + \\theta_2x_2 + \\theta_3x_3 $这样就把多项式回归,转化成了多参数线性回归。可方便计算。 2 正规方程除了梯度下降法,另一种求最小值的方式则是让代价函数导数为0,求θ值 。即: 写出代价函数:$J(\\theta) = \\frac{1}{2m}\\sum{i=1}^{m}(h\\theta(x^{(i)}) - y^{(i)})^2$ 求导,并令其等于零: $\\frac{\\partial}{\\partial\\theta_j}J(\\theta) = 0$ 解得: $\\theta = (X^TX)^{-1}X^Ty$ 2.1 正规方程 与 梯度下降 的优缺点课堂给出两者区别:简单整理一下: 梯度下降要设置α并不保证一次能获得最优的α,正规方程不用考虑α。 梯度下降要迭代多次,正规方程不用。(所以,遇到比较简单的情况,可用正规方程) 梯度下降最后总能得到一个最优结果,正规方程不一定。因为正规方程要求X的转置乘X的结果可逆。 当特征数量很多的时候,正规方程计算不方便,不如梯度下降。 总体来说: 正规方程计算巧妙,但不一定有效。 梯度下降法速度慢,但是稳定可靠。 3 octave基础教程3.1 下载安装octave打开 octave官方网站 ,下载windows 64W版本。新手不要使用ZIP下载,比较难配置。j建议直接下载EXE 下一步下一步安装即可。 打开程序界面如下:界面交互非常友好,左面是文件夹,可以直接修改工作文件件,右面是控制台可以输入指令。 3.2 基本操作Octave最简单的使用方式就是像使用一个计算器一样在命令提示符下输入相应的计算式。Octave能识别通常的计算表达式。例如,在终端输入 12+2 并按回车键,你将得到以下的结果1ans=4 各种计算符号的优先级与常规的一致,比如括号有最大优先级,其次为乘方,其次为乘、除运算,最后为加、减运算。 Octave还提供了一系列的常用数学函数,其中的一部分函数如表1所示: 3.3 向量操作构造向量:1231. a=[1 4 5];2. d=[a 6]; 向量构造函数: 12345671. zeros(M,N) 创建一个M×N的零矩阵2. ones(M,N) 创建一个M×N的全1矩阵3. linspace(x1,x2,N) 创建一个N个元素的向量,均匀分布于x1和x2之间4.rand() 生成随机数矩阵 向量计算12345671. 遵循向量+、-、*、/2. 两个向量的相乘遵循矩阵的乘法法则,向量乘法并不是对应元素的相乘。如果要两个向量的进行对应元素的乘除法, 你可以使用.*或者./算符3. ^ 为乘方计算4.转置 X‘ 载入数据的方法 3.4 画图最基本的画图命令是plot(x,y),其中x,y分别为横轴和纵轴数据, 举例如下: angles=linspace(0,2*pi,100),y=sin(angles), 则plot(angles,y)图像如下: 图形形状可以修改,这一点与python的matplotlib很像,比如plot(angles,y,’ro’)图像如下: 具体画图的形状参数如下: title(‘Graph of y=sin(x)’),xlabel(‘Angle’),ylabel(‘Value’)进行标题,横轴,纵轴的表示。 replot命令来更新图片,grid命令为图片添加网格线。 legend命令为该图片在右上角添加相应的图例legend(‘Sine’,’Cosine’),图像如下: 另外: 1231. 多幅图片可以通过figure命令来控制。figure命令下一个plot命令将会在新创建的窗口中绘制,figure(1)返回上一张图片2. 保存当前图像到一个eps文件 print('graph1.eps','-deps') 4 编程作业-octave实现线性回归4.1 作业环境 下载 作业包 在此下载第一次编程任务。此ZIP文件包含PDF的说明。注意PDF是最好的说明说,里面详细的说明了每一步操作,和下一步操作,对照着谷歌翻译,一步步走即可。 要做作业,用cd命令,进入作业文件夹。 介绍一下里面的文件: 主文件ex1.m,他是整个任务的流程文件 他自动调用其他文件,运行他可以一步步走完每个小人任务。 computeCost.m 计算代价函数的 文件。我们要在里面填空。填空完成,再次运行ex1.m 即可。 gradientDescent.m :计算梯度下降的文件,我们要在里面填空。填空完成,再次运行ex1.m 即可使用我们自己的梯度下降算法。 最后提交文件:使用octave在当前作业文件件内输入submit() 然后输入自己的邮箱密码。 4.2 答案与分析这个作业的主文件是ex1.m,它控制着整个流程,让作业程序 一步一步往下走,但是我们并不需要修改这个文件,只需要把它调用的代码文件 挨个修改即可。 Part 1 首先我们来看 第一个小作业,ex1.m中的作业要求如下: 12345678%% ==================== Part 1: Basic Function ====================% Complete warmUpExercise.mfprintf('Running warmUpExercise ... \\n');fprintf('5x5 Identity Matrix: \\n');warmUpExercise()fprintf('Program paused. Press enter to continue.\\n');pause; 意思就是,通过修改warmUpExercise.m这个文件,让主程序调用它时能产生一个5*5的矩阵。那么我们就去修改这个文件,在文件包里找到这个文件,然后在原来代码的基础上添加一句话即可: 1A = eye(5); # 生成一个5*5的矩阵 总样子为: 123456789101112131415161718function A = warmUpExercise()%WARMUPEXERCISE Example function in octave% A = WARMUPEXERCISE() is an example function that returns the 5x5 identity matrixA = [];% ============= YOUR CODE HERE ==============% Instructions: Return the 5x5 identity matrix % In octave, we return values by defining which variables% represent the return values (at the top of the file)% and then set them accordingly. A = eye(5);% ===========================================end part 2 作业要求:123456789101112%% ======================= Part 2: Plotting =======================fprintf('Plotting Data ...\\n')data = load('ex1data1.txt');X = data(:, 1); y = data(:, 2);m = length(y); % number of training examples% Plot Data% Note: You have to complete the code in plotData.mplotData(X, y);fprintf('Program paused. Press enter to continue.\\n');pause; 这一步,已经帮你装载好了数据ex1data1.txt,并分配为了x,y。你要完成画图函数plotData.m,把这个数据画出来。 同理修改plotData.m为: 123456789101112131415161718192021222324function plotData(x, y)%PLOTDATA Plots the data points x and y into a new figure % PLOTDATA(x,y) plots the data points and gives the figure axes labels of% population and profit.figure; % open a new figure window% ====================== YOUR CODE HERE ======================% Instructions: Plot the training data into a figure using the % "figure" and "plot" commands. Set the axes labels using% the "xlabel" and "ylabel" commands. Assume the % population and revenue data have been passed in% as the x and y arguments of this function.%% Hint: You can use the 'rx' option with plot to have the markers% appear as red crosses. Furthermore, you can make the% markers larger by using plot(..., 'rx', 'MarkerSize', 10);plot(x, y, 'rx', 'MarkerSize', 10); % Plot the dataylabel('Profit in $10,000s'); % Set the y?axis labelxlabel('Population of City in 10,000s'); % Set the x?axis label% ============================================================end part 3 要求就是完成梯度下降函数computeCost.m: 1234567891011121314151617181920function J = computeCost(X, y, theta)%COMPUTECOST Compute cost for linear regression% J = COMPUTECOST(X, y, theta) computes the cost of using theta as the% parameter for linear regression to fit the data points in X and y% Initialize some useful valuesm = length(y); % number of training examples% You need to return the following variables correctly J = 0;% ====================== YOUR CODE HERE ======================% Instructions: Compute the cost of a particular choice of theta% You should set J to the cost.h = X*theta - y;J = 1/(2*m) * sum(h.^2);% =========================================================================end 其实重点就两句话: 12h = X * theta;J = 1/(2*m) * sum((h-y).^2); 这是根据前面一章的基础知识来写的,一定要注意复习,知道为什么公式这么写。 part4 修改梯度下降函数gradientDescent.m,添加代码1theta = theta - alpha/m*X'*(X*theta - y); 最后的结果1234567891011121314151617181920212223242526272829function [theta, J_history] = gradientDescent(X, y, theta, alpha, num_iters)%GRADIENTDESCENT Performs gradient descent to learn theta% theta = GRADIENTDESCENT(X, y, theta, alpha, num_iters) updates theta by % taking num_iters gradient steps with learning rate alpha% Initialize some useful valuesm = length(y); % number of training examplesJ_history = zeros(num_iters, 1);for iter = 1:num_iters % ====================== YOUR CODE HERE ====================== % Instructions: Perform a single gradient step on the parameter vector % theta. % % Hint: While debugging, it can be useful to print out the values % of the cost function (computeCost) and gradient here. % theta = theta - alpha/m*X'*(X*theta - y); % ============================================================ % Save the cost J in every iteration J_history(iter) = computeCost(X, y, theta);endend 画出图片:","link":"/2017/11/21/coursera-斯坦福-机器学习-吴恩达-第2周笔记/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第4周笔记-神经网络","text":"1 提出神经网络的动机前面我们学习了,线性回归、逻辑回归,他们可以很好的解决一些预测问题。但是面对一些多特征的问题,比如以下的情况,他们并不能很好的画出分类边界线。 这种时候需要用到多项式回归(非线性的),这种函数画出的曲线可以有任意角度。但是这种函数会因为特征量的增多导致二次项数的剧增。 比如在图像识别中,一个50×50像素的图片,拥有的特征量为2500,那么它的二次项数为2500×2500/2,大约为3百万个。 在这种情况下,神经网络在1970左右被提出。 2 神经网络算法2.1 神经元神经网络是有一个个的神经元组成的网络。那么什么是“神经元”?如图,这是一个最简单的神经元,模型的输入是x1,x2,x3通过参数(权重)θ1,θ2…,并使用逻辑函数激活(压缩),得到输出结果。 2.2 神经网络下图为一个三层神经网络模型。第一层为输入层,第二层为隐藏层,第三层为输出层。 每条边上有一个权值θ。 $a^{(j)}_i$:第j层单元i的“激励” $\\theta^{(j)}$:第j层到第j+1层单元的权值矩阵。 若第j层单元数为$sj$,第j+1层单元数为$s{j+1}$,则$\\theta^{(j)}\\epsilon s_{j+1}*(s_j+1)$。 +1来自于“偏置节点”的$\\Theta^{(j)}$中的加法$x_0$和$\\Theta_0^{(j)}$。 比如: If layer 1 has 2 input nodes and layer 2 has 4 activation nodes. Dimension of Θ(1) is going to be 4×3 where sj=2 and sj+1=4, so sj+1×(sj+1)=4×3. 在bp神经网络中,我们使用sigmoid函数作为激励函数。即$g(z) = \\frac{1}{1+e^{-z}}$,也就是我们逻辑回归中使用的函数。 记住:$z^{(j)} = \\Theta^{(j-1)}a^{(j-1)}$然后:$a^{(j)} = g(z^{(j)})$ 3 应用3.1 例子1 and与or运算我们前面一直说,神经网络可以计算复杂的分线性函数,那么到底是怎么计算的呢下面通过小例子一步步说明。 看图:X取0或1,并给定权重。此时这个神经元就表示“and”运算。 而图片X取0或1,并给定权重。此时这个神经元就表示“OR”运算。 同样的还可以表示not a and not b: 3.2 例子2我们把上面三个式子总结一下: 这三个式子可以合起来,组成一个复杂的表达式。 其中不同的颜色表示,从不同的神经元取得的参数。 这样,窥一斑而知全豹。我们举一反三,可以理解: 通过组合不同计算功能的神经元,我们可以使神经网络表示复杂的表达式。—— GREAT TANG 3.3 多分类为了将数据分类到多个类中,我们让我们的假设函数返回值的向量。假设我们想将我们的数据分为四类中的一类。 我们将使用下面的例子来看看这个分类是如何完成的。该算法将图像作为输入并相应地进行分类: 我们可以定义我们的结果类为y:每个y(i)代表对应于汽车,行人,卡车或摩托车的不同图像。内层为我们提供了一些新的信息,这些信息导致了我们最终的假设功能。设置看起来像: 后面我们会学习如何计算。 这里有个小作业 60= 10×(5+1) 4 复习作业4.1测验 Which of the following statements are true? Check all that apply.答案:BD Suppose you have a multi-class classification problem with three classes, trained with a 3 layer network. Let a(3)1=(hΘ(x))1 be the activation of the first output unit, and similarly a(3)2=(hΘ(x))2 and a(3)3=(hΘ(x))3. Then for any input x, it must be the case that a(3)1+a(3)2+a(3)3=1.(不对,因为每个a都是由前面的节点计算而来,同层之间的节点互不影响,只有加上softmax才有影响) The activation values of the hidden units in a neural network, with the sigmoid activation function applied at every layer, are always in the range (0, 1). A two layer (one input layer, one output layer; no hidden layer) neural network can represent the XOR function.(得不同的网络叠加) Any logical function over binary-valued (0 or 1) inputs x1 and x2 can be (approximately) represented using some neural network. Consider the following neural network which takes two binary-valued inputs x1,x2∈{0,1} and outputs hΘ(x). Which of the following logical functions does it (approximately) compute? -20 ,30,30答案:A OR and NAND (meaning “NOT AND”) XOR (exclusive OR) Consider the neural network given below. Which of the following equations correctly computes the activation a(3)1? Note: g(z) is the sigmoid activation function. 答案:A You have the following neural network: You’d like to compute the activations of the hidden layer a(2)∈R3. One way to do so is the following Octave code: You want to have a vectorized implementation of this (i.e., one that does not use for loops). Which of the following implementations correctly compute a(2)? Check all that apply.答案:A a2 = sigmoid (Theta1 * x);(Theta1是个3×的矩阵,x是个列向量) a2 = sigmoid (x * Theta1); a2 = sigmoid (Theta2 * x); z = sigmoid(x); a2 = Theta1 * z; You are using the neural network pictured below and have learned the parameters Θ(1)=[110.51.21.92.7] (used to compute a(2)) and Θ(2)=[1−0.2−1.7] (used to compute a(3)} as a function of a(2)). Suppose you swap the parameters for the first hidden layer between its two units so Θ(1)=[111.20.52.71.9] and also swap the output layer so Θ(2)=[1−1.7−0.2]. How will this change the value of the output hΘ(x)?答案:A It will stay the same. It will increase. It will decrease Insufficient information to tell: it may increase or decrease. 4.2编程作业-多分类在这个练习中,你将实现一对多 逻辑回归和神经网络来识别手写数字。 在开始编程练习之前,我们强烈建议您观看视频讲座并完成相关主题的复习问题。 要开始练习,您需要下载初学者代码并将其内容解压到您希望完成练习的目录。 如果需要,在开始本练习之前,使用Octave / MATLAB中的cd命令切换到此目录。 下面是各个文件的作用123456789101112ex3.m - Octave / MATLAB脚本,指导您完成第1部分ex3 nn.m - Octave / MATLAB脚本,指导您完成第2部分ex3data1.mat - 手写数字的训练集ex3weights.mat - 神经网络练习的初始权重submit.m - 提交您的解决方案到我们的服务器的提交脚本displayData.m - 帮助可视化数据集的功能fmincg.m - 函数最小化例程(类似于fminunc)sigmoid.m - 乙状结肠功能-lrCostFunction.m - Logistic回归成本函数-oneVsAll.m - 训练一对多多分类器-predictOneVsAll.m - 使用一个对所有多类分类器进行预测-predict.m神经网络预测函数 4.2.1多分类对于这个练习,你将使用逻辑回归和神经网络来识别手写数字(从0到9)。 自动手写数字识别在今天被广泛使用,从识别邮件信封上的邮政编码(邮政编码)到识别银行支票上的金额。 本练习将向您展示如何将您学习的方法用于此分类任务。 在练习的第一部分,您将扩展先前的逻辑回归实现,并将其应用于“one-vs-all”分类。 程序已经写好载入数据,我们修改lrCostFunction.m来计算代价函数 和梯度。 12345sigm = sigmoid(X*theta); J = -1/m * (y'*log(sigm) + (1-y')*log(1-sigm)) + lambda/2/m*sigm;grad(1,:) = 1/m * (X(:,1)' * (sigm -y)); grad(1:end,:) = 1/m * (X(:,2:end)'*(sigm - y)) +lambda/m*theta(2:end, :); 下面修改oneVsAll.m 实现一对多分类。在里面加入12345initial_theta = zeros(n+1, 1);options = optimset('GradObj', 'on', 'MaxIter', 50);for c=1:num_labels all_theta(c, :) = fmincg(@(t)(lrCostFunction(t, X, (y==c), lambda)), initial_theta, options);end 下面进行预测,修改 predictOneVsAll.m添加123temp = all_theta * X';[maxx, pp] = max(temp);p = pp'; 最后精度Training Set Accuracy: 94.880000 4.2.2 Neural Networks在本练习的前一部分中,您实现了多类逻辑回归来识别手写数字。 然而,逻辑回归不能形成更复杂的假设,因为它只是一个线性分类器。 在练习的这一部分,您将实现一个神经网络,使用与之前相同的训练集来识别手写数字。 神经网络将能够表示形成非线性假设的复杂模型。 本周,您将使用我们已经训练过的神经网络的参数。 您的目标是实现前馈传播算法以使用我们的权重进行预测。 在下周的练习中,您将编写用于学习神经网络参数的反向传播算法。 提供的脚本ex3 nn.m将帮助您逐步完成此练习。 首先修改predict.m来写1234X = [ones(m, 1) X];XX = sigmoid(X*Theta1');pp = sigmoid([ones(size(XX, 1), 1) XX] * Theta2');[a, p] = max(pp, [], 2); 最终预测准确性:Training Set Accuracy: 97.520000","link":"/2017/11/30/coursera-斯坦福-机器学习-吴恩达-第4周笔记-神经网络/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第5周笔记-反向传播","text":"1代价函数and反向传播1.1代价函数首先定义一些我们需要使用的变量: L =网络中的总层数 $s_l$ =第l层中的单位数量(不包括偏差单位) K =输出单元/类的数量 首先,回想一下“逻辑回归”正则化的成本函数是: $J(\\theta) = - \\frac{1}{m} \\sum{i=1}^m [ y^{(i)}\\ \\log (h\\theta (x^{(i)})) + (1 - y^{(i)})\\ \\log (1 - h\\theta(x^{(i)}))] + \\frac{\\lambda}{2m}\\sum{j=1}^n \\theta_j^2$ 再回想一下,在神经网络中,我们可能有许多输出节点。我们把 $h_\\Theta(x)_k$表示为导致第k个输出的假设。我们的神经网络的成本函数将会是我们用于逻辑回归的一个综合泛化。神经网络的代价函数为: $ J(\\Theta) = - \\frac{1}{m} \\sum{i=1}^m \\sum{k=1}^K \\left[y^{(i)}k \\log ((h\\Theta (x^{(i)}))_k) + (1 - y^{(i)}k)\\log (1 - (h\\Theta(x^{(i)}))k)\\right] + \\frac{\\lambda}{2m}\\sum{l=1}^{L-1} \\sum_{i=1}^{sl} \\sum{j=1}^{s{l+1}} ( \\Theta{j,i}^{(l)})^2$ 这个式子看着复杂,但其实并不难理解:我们只是添加了几个嵌套的求和,来解释我们的多个输出节点。 在方程的第一部分,在方括号之前,我们有一个额外的嵌套总和,表示输出节点的数量。 在正则化部分,在方括号后面,我们必须考虑多个theta矩阵。当前theta矩阵中的列数等于当前图层中的节点数(包括偏置单元)。在我们当前theta矩阵中的行数等于下一层中的节点数(不包括偏置单元)。与之前的逻辑回归一样,我们对每一项进行平方。 1.2误差反向传播就像我们在逻辑回归和线性回归中使用梯度下降所做的一样。我们的目标是:$\\min_\\Theta J(\\Theta)$ 所以我们希望使用theta中的一组最优参数来最小化我们的成本函数J。寻找最小的参数,需要使用梯度下降法;而梯度下降法最重要的是计算梯度$\\dfrac{\\partial}{\\partial \\Theta_{i,j}^{(l)}}J(\\Theta)$ 为了计算这个偏导数,我们使用反向传播算法: 我们现在来讲一下反向传播算法,它是计算偏导数的一种有效方法。 设$a^{(1)} := x^{(t)}$ 执行前向传播以计算$a^{(l)}$ for l=2,3,…,L 使用$y^{(t)}$计算最后一层的误差:$\\delta^{(L)} = a^{(L)} - y^{(t)}$ 其中L是我们的总层数,a(L)是最后一层激活单元的输出向量。所以我们最后一层的“误差值”就是我们最后一层的实际结果和y中的正确输出的差别。为了得到最后一层之前的图层的增量值,我们可以使用一个从右到左的方程式: 计算之前层次的误差:$\\delta^{(L-1)}$ , $\\delta^{(L-2)}$ ,… ,$\\delta^{(2)}$ 使用公式:$\\delta^{(l)} = ((\\Theta^{(l)})^T \\delta^{(l+1)})\\ .\\ a^{(l)}\\ .\\ (1 - a^{(l)})$ 其中,我们用一个称为g’的函数或者g-prime来元素乘法,g是用z(l)给出的输入值评估的激活函数g的导数:$g’(z^{(l)}) = a^{(l)}\\ .*\\ (1 - a^{(l)})$ 进一步,把每个样本的误差合计$\\Delta^{(l)}{i,j} := \\Delta^{(l)}{i,j} + a_j^{(l)} \\delta_i^{(l+1)}$ 然后计算正则化: $D^{(l)}{i,j} := \\dfrac{1}{m}\\left(\\Delta^{(l)}{i,j} + \\lambda\\Theta^{(l)}_{i,j}\\right)$ $D^{(l)}{i,j} := \\dfrac{1}{m}\\Delta^{(l)}{i,j}$ 误差-增量 矩阵D被用作“累加器”来累加我们的误差,并最终计算得到我们所需要的偏导数:$\\frac \\partial {\\partial \\Theta{ij}^{(l)}} J(\\Theta)=D{ij}^{(l)}$ 1.3直观感受反向传播吴老师生怕我们不能“理解感受”反向传播,所以在这一节,他讲了一种反向传播的直观理解方式。 首先回忆神经网络的代价函数是: $J(\\Theta) = - \\frac{1}{m} \\sum{t=1}^m\\sum{k=1}^K \\left[ y^{(t)}k \\ \\log (h\\Theta (x^{(t)}))_k + (1 - y^{(t)}k)\\ \\log (1 - h\\Theta(x^{(t)})k)\\right] + \\frac{\\lambda}{2m}\\sum{l=1}^{L-1} \\sum_{i=1}^{sl} \\sum{j=1}^{sl+1} ( \\Theta{j,i}^{(l)})^2$ 如果我们考虑简单的非多类分类(k = 1)并且忽视正则化,则成本计算如下: $cost(t) =y^{(t)} \\ \\log (h\\Theta (x^{(t)})) + (1 - y^{(t)})\\ \\log (1 - h\\Theta(x^{(t)}))$ 那么直观上,$\\delta_j^{(l)}$是$a^{(l)}_j$(第1层中的单元j)的“误差”。更正式地说,δ值实际上是成本函数的导数,即:$\\delta_j^{(l)} = \\dfrac{\\partial}{\\partial z_j^{(l)}} cost(t)$ 每一个神经元的误差都与后面连接的神经元有关。比如:$\\delta2^{(2)}=\\Theta{12}^{(2)}\\delta1^{(3)}+\\Theta{22}^{(2)}\\delta_2^{(3)}$ 再比如:$\\delta2^{(3)}=\\Theta{12}^{(3)}*\\delta_1^{(4)}$ tips:这是一种表达方法,并不意味着使用这么简单的方法就能求出δ。这只是一种解释,直观的展示不同层次误差之间的关系。 我对反向传播的一种形象的理解: 由于参数选的不好,导致网络最后输出的结果与真实值相差甚远。我们很自然的求出了最后一层的误差(真实-输出)。 但是,最后一层的神经元不服气:明明数值都是前面的神经元传递过来的,出了误差凭什么都赖我啊?我要兴师问罪! 于是,最后一层的神经元就去找前面一层的神经元问罪,问罪的证据就是参数Θ。谁的Θ大,就说明谁传过来的误差大,责任也就越多。靠这个方法,最后一层的神经元,把误差的责任按照比例“推卸”给了前一层。 前一层也按照这个方式,一层层往前“推诿责任”。这样,误差就反向传播给了每一层。 2神经网络的技巧2.1参数的展开使用神经网络时,我们处理的一组矩阵:$\\Theta^{(1)},\\Theta^{(2)}\\Theta^{(3)}…$ 为了使用诸如“fminunc()”这样的优化函数,我们将要“展开”所有元素,并将它们放入一个长向量中,我们可以使用命令[]:1thetaVector = [ Theta1(:); Theta2(:); Theta3(:); ] 如果Theta1的尺寸是10x11,Theta2是10x11,Theta3是1x11,那么我们可以从“展开”版本中取回我们的原始矩阵,如下所示:123Theta1 = reshape(thetaVector(1:110),10,11)Theta2 = reshape(thetaVector(111:220),10,11)Theta3 = reshape(thetaVector(221:231),1,11) 像这样的函数需要一个参数向量。 2.2梯度检验 Gradient Checking渐变检查将确保我们的反向传播按预期工作。我们可以用下式近似我们的成本函数的导数: $\\dfrac{\\partial}{\\partial\\Theta}J(\\Theta) \\approx \\dfrac{J(\\Theta + \\epsilon) - J(\\Theta - \\epsilon)}{2\\epsilon}$ 使用多个theta矩阵,我们可以如下近似于关于Θj的导数:$\\dfrac{\\partial}{\\partial\\Theta_j}J(\\Theta) \\approx \\dfrac{J(\\Theta_1,\\Theta_j + \\epsilon, \\Theta_n) - J(\\Theta_1 , \\Theta_j - \\epsilon, \\Theta_n)}{2\\epsilon}$ 为保证数学运算正确ε(ε)的一个很小的值,比如ε=${\\epsilon = 10^{-4}}$。但如果ε的值太小,我们最终会出现数值问题。 因此,我们只是在Θj矩阵中加上或减去ε。在octave我们可以做到这一点,如下所示:12345678epsilon = 1e-4;for i = 1:n, thetaPlus = theta; thetaPlus(i) += epsilon; thetaMinus = theta; thetaMinus(i) -= epsilon; gradApprox(i) = (J(thetaPlus) - J(thetaMinus))/(2*epsilon)end; 记住一旦验证了反向传播算法是正确的,就不需要再次计算gradApprox。因为计算gradApprox的代码可能非常慢。 2.3随机初始化参数将所有的权重初始化为0不适用于神经网络。那样反向传播时,所有节点将重复更新为相同的值。 相反,我们可以使用以下方法随机初始化我们的Θ矩阵的权重:因此,我们将每个$\\Theta^{(l)}_{ij}$初始化为[-ε,ε]之间的随机值。使用上面的公式保证我们得到所需的界限。相同的程序适用于所有的Θ。以下是您可以用来进行实验的一些工作代码。 123Theta1 = rand(10,11) * (2 * INIT_EPSILON) - INIT_EPSILON;Theta2 = rand(10,11) * (2 * INIT_EPSILON) - INIT_EPSILON;Theta3 = rand(1,11) * (2 * INIT_EPSILON) - INIT_EPSILON; rand(x,y)只是一个八度函数,它将初始化一个0到1之间的随机实数矩阵。 2.4总结神经网络 网络体系结构 首先,选择一个网络体系结构;选择你的神经网络的布局,包括每层中有多少个隐藏单元,以及你想要的总共有多少层。一些经验: 输入单元的数量=特征的维度x(i) 输出单元的数量=类的数量y 每层隐藏单元的数量=通常越多越好(必须与计算成本平衡,因为随着更多隐藏单元的增加而增加) 默认值:1个隐藏层。如果您有多个隐藏层,则建议您在每个隐藏层中具有相同数量的单元。 模型的训练 模型的训练遵照以下步骤: 随机初始化权重 实现向前传播以获得任何x(i)的hΘ(x(i)), 实施成本函数 实施反向传播以计算偏导数 循环每个训练的例子for i = 1:m 使用梯度检查来确认您的反向传播的作品。然后禁用梯度检查。 使用梯度下降或内置的优化功能,以theta中的权重最小化成本函数。 下面的图像让我们直观地了解当我们实施我们的神经网络时发生了什么: 理想情况下,你需要$h_\\Theta(x^{(i)})$≈$y^{(i)}$。这将使我们的成本函数最小化。但是,请记住,J(Θ)不是凸的,因此我们可以最终找到局部最小值。 3神经网络的应用吴老师举了一个自动驾驶的例子: 训练一个人驾驶汽车 然后让ALVINN观看 。ALVINN每两秒 将前方的路况图生成一张数字化图片 并且记录驾驶者的驾驶方向 。得到的训练集图片 被压缩为30x32像素 并且作为输入 提供给ALVINN的三层神经网络。 通过使用反向传播学习算法, ALVINN会训练得到一个 与人类驾驶员操纵方向 基本相近的结果。 一开始 我们的网络选择出的方向是随机的 ,大约经过两分钟的训练后 ,我们的神经网络 便能够准确地模拟 人类驾驶者的驾驶方向 对其他道路类型 4测验quiz You are training a three layer neural network and would like to use backpropagation to compute the gradient of the cost function. In the backpropagation algorithm, one of the steps is to update。答案A Suppose Theta1 is a 5x3 matrix, and Theta2 is a 4x6 matrix. You set thetaVec=[Theta1(:);Theta2(:)]. Which of the following correctly recovers Theta2?答案A Let J(θ)=3θ3+2. Let θ=1, and ϵ=0.01. Use the formula J(θ+ϵ)−J(θ−ϵ)2ϵ to numerically compute an approximation to the derivative at θ=1. What value do you get? (When θ=1, the true/exact derivative is dJ(θ)dθ=9.)答案:A Which of the following statements are true? Check all that apply.答案AD Which of the following statements are true? Check all that apply.答案AD If we are training a neural network using gradient descent, one reasonable “debugging” step to make sure it is working is to plot J(Θ) as a function of the number of iterations, and make sure it is decreasing (or at least non-increasing) after each iteration. 5编程题在前面的练习中,你实现了神经网络的前馈传播,并用它来预测我们提供的权重的手写数字。 在这个练习中,您将实施反向传播算法来学习神经网络的参数。 所提供的脚本ex4.m将帮助您逐步完成这个练习。 Part 1: Loading and Visualizing Data 自动画图,不用修改。 Part 2: Loading Parameters 自动加载 Part 3: Compute Cost (Feedforward) Part 4: Implement Regularization 这两个都是修改nnCostFunction.m 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253%计算每层的结果,记得要把bias unit加上,第一次写把a1 写成了 [ones(m,1); X]; a1 = [ones(m,1) X]; z2 = Theta1 * a1'; a2 = sigmoid(z2); a2 = [ones(1,m); a2]; %这里 a2 和 a1 的格式已经不一样了,a1是行排列,a2是列排列 z3 = Theta2 * a2; a3 = sigmoid(z3); % 首先把原先label表示的y变成向量模式的output,下面用了循环 y_vect = zeros(num_labels, m); for i = 1:m, y_vect(y(i),i) = 1; end; %每一training example的cost function是使用的向量计算,然后for loop累加所有m个training example %的cost function for i=1:m, J =J+ sum(-1*y_vect(:,i).*log(a3(:,i))-(1-y_vect(:,i)).*log(1-a3(:,i))); end; J = J/m; %增加regularization,一开始只写了一个sum,但其实theta1 2 分别都是矩阵,一个sum只能按列累加,bias unit的theta不参与regularization J = J + lambda*(sum(sum(Theta1(:,2:end).^2))+sum(sum(Theta2(:,2:end).^2)))/2/m; %backward propagation %Δ的元素个数应该和对应的theta中的元素的个数相同 Delta1 = zeros(size(Theta1)); Delta2 = zeros(size(Theta2)); for i=1:m, delta3 = a3(:,i) - y_vect(:,i); T=(Theta2'*delta3); %注意这里的δ是不包含bias unit的delta的,毕竟bias unit永远是1, %不需要计算delta, 下面的2:end,: 过滤掉了bias unit相关值 delta2 = T(2:end,:).*sigmoidGradient(z2(:,i)); %移除bias unit上的delta2,但是由于上面sigmoidGradient式子中 %的z,本身不包含bias unit,所以下面的过滤不必要,注释掉。 %delta2 = delta2(2:end); Delta2 =Delta2+ delta3 *a2(:,i)'; %第一层的input是一行一行的,和后面的结构不一样,后面是一列作为一个example Delta1 =Delta1+ delta2 * a1(i,:); end; %总结一下,δ不包含bias unit的偏差值,Δ对跟θ对应的,用来计算每个θ %后面的偏导数的,所以Δ包含bias unit的θ Theta2_grad = Delta2/m; Theta1_grad = Delta1/m; %regularization gradient Theta2_grad(:,2:end) = Theta2_grad(:,2:end) + lambda * Theta2(:,2:end) / m; Theta1_grad(:,2:end) = Theta1_grad(:,2:end) + lambda * Theta1(:,2:end) / m; Part 5: Sigmoid Gradient 在开始实施神经网络之前,您将首先实现sigmoid函数的渐变。 您应该完成sigmoidGradient.m文件中的代码。 1g = 1.0 ./ (1.0 + exp(-z)); Part 6: Initializing Pameters 在这部分的练习中,你将开始实现分类数字的双层神经网络。 您将开始执行一个函数来初始化神经网络的权重(randInitializeWeights.m) 12epsilon = 0.12;W = rand(L_out, 1+L_in)*2*epsilon - epsilon;","link":"/2017/12/03/coursera-斯坦福-机器学习-吴恩达-第5周笔记-反向传播/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第3周笔记-逻辑回归","text":"1.分类 和 模型表示这一周对应PPT lecture6 逻辑回归 1.1分类的概念 Classification先来谈谈二分类问题。课程中先给出了几个例子。 邮件是垃圾邮件还是非垃圾邮件; 网上交易是的欺骗性(Y or N); 肿瘤是恶性的还是良性的。 对于这些问题,我们可以通过输出值y ϵ {0, 1} 来表示。 注意:分类结果是离散值,这是分类的根本特点。 1.2 分类模型表示通过上次的课程,我们可以想到利用假设函数y=hθ(x)来预测分类。 如果y的取值只有0和1,训练集画出来这这个样子(先没有绿框中的点),我们用线性回归得到1号直线,如果认为模拟直线的取值小于0.5时则预测值就为0,如果模拟直线的取值大于0.5时预测值就为1,感觉还不错。但是将绿框中的点加入后,线性回归得到的直线2,就显得不是很完美了。经过大量的实验证明,线性回归不适合这种训练集。那么怎么解决这个问题呢? 而且普通的hθ(x)函数存在函数值大于1和小于0的情况(没有意义),于是我们要构造特殊函数使0≤hθ(x)≤1。 我们提出来了一种新的回归模型: $y=h_\\theta(x) = g(\\theta^Tx)$ 其中:$$g(z) = \\frac{1}{1 + e^{-z}}$$ 则$$h_\\theta(x) = \\frac{1}{1 + e^{-\\theta^Tx}}$$g(z)这个函数称之为:logistic function 或者 sigmoid function,其图像为: 1.3 分类边界有了模型,怎么分类呢? 当y>0.5的时候,为正。此时由图像可知: $$h_\\theta(x) \\geq 0.5$$ $$\\theta^Tx\\geq 0$$ 下面的图可以用来体会一下边界的含义 2.逻辑回归模型 logistic regression2.1 代价函数 cost func让我们先来看看线性回归中的代价函数 , $$J(\\theta) = \\frac{1}{2m}\\sum{i=1}^{m}(h\\theta(x^{(i)}) - y^{(i)})^2$$ 如果将其应用在逻辑回归中,由于假设函数hθ(x) 的非线性,代价函数会呈现以下形状。 图像呈现出非凸性,也就是说,如果我们运用梯度下降法,不能保证算法收敛到全局最小值。 所以,对于逻辑回归问题,我们定义新的代价函数如下所示 : 对上面的式子进行简化,总结如下 $$J(\\theta) = \\frac{1}{2m}\\sum{i=1}^{m}Cost(h\\theta(x^{(i)}), y^{(i)})$$$$Cost(h\\theta(x^{(i)}), y^{(i)}) = -y^{(i)}log(h\\theta(x)) - (1 - y^{(i)})log(1 - h_\\theta(x^{(i)}))$$ 即: $$J(\\theta) = - \\frac{1}{m} \\displaystyle \\sum{i=1}^m [y^{(i)}\\log (h\\theta (x^{(i)})) + (1 - y^{(i)})\\log (1 - h_\\theta(x^{(i)}))]$$ 他$的图像如下: 如果我们的正确答案“y”是0,那么如果我们的假设函数也输出0,则成本函数将是0。如果我们的假设接近1,则成本函数将接近无穷大。 如果我们的正确答案“y”是1,那么如果我们的假设函数输出1,则成本函数将为0.如果我们的假设接近0,则成本函数将接近无穷大. 这种方式编写成本函数可以保证J(θ)对于逻辑回归是凸的。 2.2 梯度下降请记住,梯度下降的一般形式是 Repeat{$$\\theta_j := \\theta_j - \\alpha \\dfrac{\\partial}{\\partial \\theta_j}J(\\theta)$$} 我们可以使用微积分来计算微分部分以得到: Repeat{ $$\\theta_j := \\thetaj - \\frac{\\alpha}{m} \\sum{i=1}^m (h_\\theta(x^{(i)}) - y^{(i)}) x_j^{(i)}$$} 算法看上去和线性回归保持一致 2.3 高级优化方法(相对于梯度下降)“共轭梯度Conjugate gradient”,“BFGS”和“L-BFGS”是可以用来代替梯度下降来优化θ的更复杂,更快捷的方法。 对于梯度下降法我们可以在octive中使用如下高级函数 其中要定义代价函数costFunction: $$function [jVal, gradient] = costFunction(theta)$$ 2.4 复习逻辑回归按照惯例,我们复习一下逻辑回归,写出三个维度的函数: 模型层面:逻辑回归模型$$h_\\theta(x) = \\frac{1}{1 + e^{-\\theta^Tx}}$$ 代价函数:cost func $$J(\\theta) = - \\frac{1}{m} \\displaystyle \\sum{i=1}^m [y^{(i)}\\log (h\\theta (x^{(i)})) + (1 - y^{(i)})\\log (1 - h_\\theta(x^{(i)}))]$$ 梯度下降 $$\\theta_j := \\thetaj - \\frac{\\alpha}{m} \\sum{i=1}^m (h_\\theta(x^{(i)}) - y^{(i)}) x_j^{(i)}$$ 3.多分类任务文中给出的多分类解决办法是,把K分类转换为K个2分类。例如: 训练每个类别的逻辑回归分类器hθ(x)来预测y的概率。最后,选择最大化 max hθ(x)的类, 4.过拟合overfitting这一章对应PPT lecture7 过拟合 4.1 什么是过拟合考虑从x∈R预测y的问题。图片显示了将y 拟合到数据集的结果。左边是underfitting 也叫高偏差bias,中间是just right,右边是overfitting overfitting通常是由一个复杂的函数造成的,这个函数会产生大量与数据无关的不必要的曲线和角度。 有两个主要的选择来解决过度拟合的问题: 1)减少特征的数量: 手动选择要保留的功能。 使用模型选择算法(在课程后面研究)。 2)正则化 保留所有的特征,但是减小参数θj的大小。 4.2 修改代价函数实现正则化我们要消除θ3x3和θ4x4的影响。如果没有真正摆脱这些特征或改变我们假设的形式,我们可以修改我们的成本函数:$$min\\theta\\ \\dfrac{1}{2m}\\sum{i=1}^m (h_\\theta(x^{(i)}) - y^{(i)})^2 + 1000\\cdot\\theta_3^2 + 1000\\cdot\\theta_4^2$$最后我们增加了两个额外的术语来夸大θ3和θ4的成本。现在,为了使成本函数接近零,我们将不得不将θ3和θ4的值减小到接近零。 这又会大大减少我们的假设函数中的θ3x3和θ4x4的值。 因此,我们看到新的假设(由粉红色曲线表示)看起来像一个二次函数,但是由于额外的小项θ3x3和θ4x4,所以更好地拟合数据。 所以, 在代价函数后面加上一些乘法系数,可以“捋平”图像的弯曲,完成泛化。 但是,在实际情况中,我们不知道具体惩罚哪个θ,所以就整体惩罚,把每个弯平一平。也就是修改代价函数为: $$min\\theta\\ \\dfrac{1}{2m}\\ \\sum{i=1}^m (h\\theta(x^{(i)}) - y^{(i)})^2 + \\lambda\\ \\sum{j=1}^n \\theta_j^2$$其中λ是正则化参数 regularization parameter。它决定了我们θ参数的成本膨胀了多少。 如果选择的lambda太大,可能会使功能过于平滑,under fitting。因此,如果λ= 0或太小会发生泛化失败,overfitting 4.3 在线性回归中使用正则化我们可以将正则化应用于线性回归和逻辑回归。(因为就学了这俩)我们将首先处理线性回归。 一共有两种方法,梯度下降和正规方程 梯度下降我们将修改我们的梯度下降函数,从其他参数中分离出θ0,因为我们不想惩罚θ0。Repeat {}$$\\theta_j := \\thetaj - \\alpha\\ \\left[ \\left( \\frac{1}{m}\\ \\sum{i=1}^m (h_\\theta(x^{(i)}) - y^{(i)})x_j^{(i)} \\right) + \\frac{\\lambda}{m}\\theta_j \\right]$$通过一些操作,我们的更新规则也可以表示为:$$\\theta_j := \\thetaj(1 - \\alpha\\frac{\\lambda}{m}) - \\alpha\\frac{1}{m}\\sum{i=1}^m(h_\\theta(x^{(i)}) - y^{(i)})x_j^{(i)}$$上面的等式中的第一项1-α λ/m将总是小于1.直觉上你可以看到它在每次更新时减少θj的值一定量 正规方程 现在让我们使用非迭代法线方程的替代方法来进行正则化。$$\\theta = \\left( X^TX + \\lambda \\cdot L \\right)^{-1} X^Ty$$L是一个矩阵,左上角为0,下角为1,其他地方为0。它应该有维度(n 1)×(n 1)。直观地说,这是单位矩阵(尽管我们不包括x0),乘以单个实数λ。 12回想一下,如果m <n,则XTX是不可逆的。然而,当我们加上术语λ⋅L时,则XTXλ⋅L变成可逆的。 4.4 在逻辑回归中使用正则化我们可以用类似的方式调整逻辑回归,就像我们调整线性回归一样。因此,我们可以避免过度配合。下图显示了粉红线所显示的正则化函数如何比蓝线所表示的非正则化函数更不可能过配: 回想一下,逻辑回归的成本函数是: $$J(\\theta) = - \\frac{1}{m} \\sum{i=1}^m \\large[ y^{(i)}\\ \\log (h\\theta (x^{(i)})) + (1 - y^{(i)})\\ \\log (1 - h\\theta(x^{(i)})) \\large]$$我们可以通过在最后添加一个术语来规范这个等式:$$J(\\theta) = - \\frac{1}{m} \\sum{i=1}^m \\large[ y^{(i)}\\ \\log (h\\theta (x^{(i)})) + (1 - y^{(i)})\\ \\log (1 - h\\theta(x^{(i)}))\\large] + \\frac{\\lambda}{2m}\\sum_{j=1}^n \\theta_j^2$$第二个和Σnj=1θ2j意味着明确排除偏差项θ0。即θ矢量从0到n(保持n 1个值,θ0到θn)被索引,并且该和明确跳过θ0,从1跳到n,跳过0.因此,当计算等式时,我们应该连续更新两个以下等式: 5.编程作业2首先下载作业:Download the programming assignment here. 此ZIP文件包含PDF和启动器代码中的说明。 首先是PDF简介: 在本练习中,您将执行逻辑回归并将其应用于两个不同的数据集。 在开始编程练习之前,我们强烈建议您观看视频讲座并完成相关主题的复习问题。 要开始练习,您需要下载初学者代码并将其内容解压到您希望完成练习的目录。 如果需要,在开始本练习之前,使用Octave / MATLAB中的cd命令切换到此目录。 各个文件的作用: 1234567ex2.m - Octave / MATLAB脚本,指导您完成练习ex2 reg.m - 练习后面部分的Octave / MATLAB脚本ex2data1.txt - 练习的前半部分的训练集ex2data2.txt - 练习后半部分的训练集submit.m - 提交您的解决方案到我们的服务器的提交脚本mapFeature.m - 生成多项式特征的函数plotDecisionBoundary.m - 绘制分类器决策边界的函数 在整个练习中,您将使用脚本ex2.m和ex2 reg.m. 这些脚本为问题设置数据集,并调用您将要编写的函数。 你不需要修改其中的任何一个。 您只需按照本作业中的说明修改其他文件中的功能。 5.1 逻辑回归练习在这部分的练习中,你将建立一个逻辑回归模型来预测一个学生是否被录取进大学。 假设你是大学部门的管理者,你想根据两次考试的结果来确定每个申请者的录取机会。 您可以从以前的申请人获得历史数据,您可以将其用作逻辑回归的训练集。 对于每个培训的例子,你有两个考试的申请者的分数和录取决定。 你的任务是建立一个分类模型,根据这两个考试的分数来估计申请者的录取概率。 这个大纲和ex2.m中的框架代码将指导你完成这个练习。 5.1.1 可视化数据 Visualizing the data在开始实施任何学习算法之前,如果可能的话,最好将数据可视化。 在ex2.m的第一部分,代码将加载数据并通过调用函数plotData将其显示在二维图上。 您现在将在plotData中完成代码,使其显示如图1所示的图形,其中轴是两个考试分数,正面和负面的示例显示为不同的标记。 我们打开文件plotData.m编辑,在其中加入:1234567% Find Indices of Positive and Negative Examplespos = find(y==1); neg = find(y == 0);% Plot Examplesplot(X(pos, 1), X(pos, 2), 'k+','LineWidth', 2, ...'MarkerSize', 7);plot(X(neg, 1), X(neg, 2), 'ko', 'MarkerFaceColor', 'y', ...'MarkerSize', 7); 5.1.2 实现 实现 sigmoid 打开 sigmoid.m编辑加入一行即可: 1g = 1./(1+exp(-z)); 实现Cost function and gradient 打开 costFunction.m编辑加入: 12J = 1/m*(-y'*log(sigmoid(X*theta)) - (1-y)'*(log(1-sigmoid(X*theta))));grad = 1/m * X'*(sigmoid(X*theta) - y); 5.1.3 Learning parameters using fminunc在前面的作业中,通过执行渐变下降,找到了线性回归模型的最佳参数。 您编写了一个成本函数并计算了它的梯度,然后相应地进行了梯度下降步骤。这一次,你将使用一个名为fminunc的Octave / MATLAB内置函数。 Octave / MATLAB的fminunc是一个优化求解器,可以找到一个无约束2函数的最小值。 对于逻辑回归,您想用参数θ来优化成本函数J(θ)。 请注意,通过使用fminunc,您不必自己编写任何循环,也可以像设置渐变下降一样设置学习速度。 这一切都是由fminunc完成的:你只需要提供一个计算成本和梯度的函数.(前面已经提供) 5.1.4 评估逻辑回归学习完参数后,您可以使用该模型来预测某个特定的学生是否被录取。 对于考试1分为45分和考试2分为85分的学生,您应该期望看到0.776的录取概率。 评估我们发现的参数质量的另一种方法是看看学习模型在我们的训练集上的预测程度。 在这一部分中,您的任务是完成predict.m中的代码。 给定数据集和学习参数矢量θ,预测函数将产生“1”或“0”预测。 完成predict.m中的代码之后,ex2.m脚本将通过计算正确示例的百分比来报告分类器的训练准确性。 打开 predict.m编辑加入:1p = sigmoid(X * theta)>=0.5; 5.2 正则化逻辑回归 Regularized logistic regression在这部分的练习中,您将执行正则化的逻辑回归来预测制造工厂的微芯片是否通过了质量保证(QA)。 在QA期间,每个微芯片都经过各种测试以确保其正常工作。 假设你是工厂的产品经理,你在两个不同的测试中有一些微芯片的测试结果。 从这两个测试,你想确定是否应该接受或拒绝芯片。 为了帮助您做出决定,您可以在过去的微芯片上获得测试结果的数据集,从中可以建立逻辑回归模型。 您将使用另一个脚本ex2 reg.m来完成这部分练习。 5.1.1 可视化数据图显示我们的数据集不能通过绘图的直线分成正面和负面的例子。 因此,logistic回归的直接应用在这个数据集上表现不好,因为逻辑回归只能找到一个线性的决策边界。 5.1.2 特征映射Feature mapping更好地拟合数据的一种方法是从每个数据点创建更多的特征。 在提供的函数mapFeature.m中,我们将把特征映射到x 1和x 2的所有多项式到6次幂。 作为这种映射的结果,我们的两个特征(两个QA测试中的分数)的矢量已被变换成28维矢量。 在这个高维特征向量上训练的逻辑回归分类器将具有更复杂的决策边界,并且在我们的二维图中绘制时将呈现非线性。 虽然特征映射允许我们构建更具表现力的分类器,但它也更易于过度拟合。 在接下来的练习中,您将实施规则化的逻辑回归以适应数据,同时也要了解正规化如何帮助解决过度拟合问题。 5.1.3 Cost function and gradient现在您将执行代码来计算正则化逻辑回归的成本函数和梯度。 完成costFunctionReg.m中的代码以返回成本和渐变 就是在原来的代价函数的基础上加入正则项: 在costFunctionReg.m中加: 12345J = 1/m * (-y' * log(sigmoid(X*theta)) - (1 - y') * log(1 - sigmoid(X * theta))) + lambda/2/m*sum(theta(2:end).^2);grad(1,:) = 1/m * (X(:, 1)' * (sigmoid(X*theta) - y));grad(2:size(theta), :) = 1/m * (X(:, 2:size(theta))' * (sigmoid(X*theta) - y))... + lambda/m*theta(2:size(theta), :); 5.1.4 画出决策边界Plotting the decision boundary为了帮助您可视化由此分类器学习的模型,我们提供了plotDecisionBoundary.m函数,绘制分隔正例和负例的(非线性)决策边界。 在plotDecisionBoundary.m中,我们通过在均匀间隔的网格上计算分类器的预测来绘制非线性决策边界,然后画出预测从y = 0变化到y = 1的等高线图。 在学习参数θ之后,ex reg.m中的下一步将绘制类似于图4的决策边界。 最后结果如下: 精确度89%左右","link":"/2017/11/28/coursera-斯坦福-机器学习-吴恩达-第3周笔记-逻辑回归/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第7周笔记-支持向量机SVM","text":"1大间距分类器 large margin classifier1.1通过逻辑回归引入SVM先回顾一下逻辑回归的相关概念$h_\\theta(x) = \\frac{1}{1+e^{-\\theta^T x}}$ IF y=1, we want hθ(x)≈1, θTx≫0 IF y=0, we want hθ(x)≈0, θTx≪0 其CostFunction为: $J(\\theta) = \\frac{1}{m}[\\sum{i=1}^m y^{(i)} (-logh{\\theta}(x^{(i)})) + (1-y^{(i)})(-(log(1-h\\theta(x^{(i)}))))] + \\frac{\\lambda}{2m}\\sum{j=1}^{m}\\theta_j^2$ 在SVM中对costfunction进行改变 : 将其中log函数部分换成了蓝色折线所代表的cost函数。(更简洁) costFunction也相应的改变为:$J(\\theta) = \\frac{1}{m}[\\sum_{i=1}^m y^{(i)} Cost_1(\\theta^Tx^{(i)}) + (1-y^{(i)})Cost0(\\theta^Tx^{(i)})] + \\frac{\\lambda}{2m}\\sum{j=1}^{m}\\theta_j^2$ 然后在SVM中,我们用C代替λ$J(\\theta) = C\\sum_{i=1}^m [y^{(i)} Cost_1(\\theta^Tx^{(i)}) + (1-y^{(i)})Cost0(\\theta^Tx^{(i)})] + \\frac{1}{2}\\sum{j=1}^{m}\\theta_j^2$ 也就是通过逻辑回归,引出了SVM的代价函数:$J(\\theta) = C\\sum_{i=1}^m [y^{(i)} Cost_1(\\theta^Tx^{(i)}) + (1-y^{(i)})Cost0(\\theta^Tx^{(i)})] + \\frac{1}{2}\\sum{j=1}^{m}\\theta_j^2$ 1.1宽边界分类器SVMSVM是一种“宽边界”分类器(Large Margin Intuition)。如图,SVM希望找到“最中间”的那条分界线(最宽边界)来分割两类。 我们一步步来看: 首先观察SVM代价函数的图像: 和逻辑回归相比较: IF y=1, we want θTx≥1 (not just ≥0) IF y=0, we want θTx≤−1 (not just ≤0) 同时,当C非常大时,我们希望蓝色的这部分为0 即min$\\frac{1}{2}\\sum_{i=1}^{n}\\theta_j^2$ 总结一下:此时,我们把SVM的代价函数(目标函数)化简为了: min$\\frac{1}{2}\\sum_{i=1}^{n}\\theta_j^2$ 同时,这个函数的约束条件(S.T)为: $\\theta^Tx^{(i)} \\ge +1 (if) y^{(i)}=1$ $\\theta^Tx^{(i)} \\le +1 (if) y^{(i)}=0$ 这是一个条件极值问题 。 1.3SVM数学原理通过上一节简化问题,我们知道SVM要求的最小值为||θ||的最小值,即θ的范数最小值。模型如下: 下面看一下限制条件代表的含义,通过高中数学,我们知道两个向量相乘(内积)的几何含义如下 :(向量A在另一条向量B上的映射×向量B的模) 通过上面可知,我们要求||θ||的最小值,因此我们希望$p^{(i)}$(x在θ上的映射)尽量大。只有这样才能使上面说的约束条件S.T满足。也就是SVM转变为了找到那个x在θ上的最大映射。 例子如下(θ为分界的法线(垂直)): 假如选择了下面图中的绿色线作为边界,我们会发现p(i)比较小,这样不能得出||θ||的最小值 如果选择下面的绿色线作为边界,我们可以得较长的映射p、和较小的||θ||值。 最后再来一张图来直观感受一下: 总结: SVM 要找到最中间的边界。 所以要找到最长的映射p。 进而可以找到所求参数θ的最小值。2核函数2.1核函数1:简单例子讲解概念 引入:之前的课程中我们讲解了使用多项式解决非线性拟合问题 , 在这里我们通过引入核函数来解决这个问题。 假设函数$h_\\theta(x) = \\theta_0 + \\theta_1f_1 + \\theta_2f_2 + \\theta_3f_3 + \\cdots$(用f代替x的参数)这个函数为新的假设函数。 引入:如果我们给出几个向量$l^{(i)}$作为landmarks 我们设置f函数,衡量标记点和原先样本点的相似性。 为$f_i = similarity(x^{(i)}, l^{(i)}) = exp(-\\frac{||x^{(i)} - l^{(i)}||^2}{2\\delta^2})$exp中的函数为高斯核函数 在这种情况下,f的取值为: if $x^{(i)}\\approx l^{(i)}$时:$f_i \\approx exp(-\\frac{0^2}{2\\delta^2}) \\approx 1$ if $x^{(i)}$ is far from $l^{(i)}$时:$f_i \\approx exp(-\\frac{(large number)^2}{2\\delta^2}) \\approx 0$ 这样就表示了样本x的一种高维映射,里标记点越近值越高。 最后,我们需要研究δ对核函数的影响,通过图片看出,δ越大收敛慢,δ越小收敛快。 2.2核函数2:SVM计算步骤上一节中的标记点,我们是随机选取的,但是这样不科学。 那么,关于landmarks我们应该怎么选取呢? 一种比较好的方法,是将训练集中的正样本选取为标记点,如图: 这样定义好l后,再定义每一个映射F。 此时,对于每一个训练集中的数据,我们都有一个m+1维向量与之对应。 每给定一个样本x,计算他与所有l的映射f: 预测样本点的归属类: 在预测时,使用以下计算公式: 这个函数等价于:$h_\\theta(x) = \\theta_0 + \\theta_1f_1 + \\theta_2f_2 + \\theta_3f_3 + \\cdots$ 以上就是已知参数θ时 ,怎么做出预测的过程。那么 怎样得到参数θ呢? 方法具体来说就是要求解这个最小化问题, 你需要求出能使这个式子取最小值的参数θ。 $J(\\theta) = C\\sum_{i=1}^m [y^{(i)} Cost_1(\\theta^Tf^{(i)}) + (1-y^{(i)})Cost0(\\theta^Tf^{(i)})] + \\frac{1}{2}\\sum{j=1}^{m}\\theta_j^2$ 下面总结一些SVM中的参数对模型的影响,主要是两个方面:C和δ。 1.C 大C:低偏差,高方差(对应低λ,overfitting)因为C约等于λ的倒数。 小C:高偏差,低方差(对应高λ) δ 大δ2:fi分布更平滑,高偏差,低方差 小δ2:fi分布更集中,低偏差,高方差 (overfitting) 3实践SVM在实际工作中,我们往往使用已有的工具包中所包含的SVM。在使用时,我们需要注意其中的参数选定 : 选择一个合适的C: 大C:低偏差,高方差(对应低λ,overfitting)因为C约等于λ的倒数。 小C:高偏差,低方差(对应高λ) 选择一个合适的核函数: linear kernel(No kernel) 高斯核表达式如下: 另外一个问题什么时候选择SVM或逻辑回归?如图: 特征维度n很大:使用逻辑回归和线性SVM. 特征维度n小,样本数量m中等:使用高斯核SVM。 特征维度n小,且样本数量m巨大: 可以创建新的特征 然后使用逻辑回归和无核SVM 4复习一种形象的解释: 你用一根棍分开它们?要求:尽量在放更多球之后,仍然适用。” SVM就是试图把棍放在最佳位置,好让在棍的两边有尽可能大的间隙。 魔鬼看到大侠已经学会了一个trick,于是魔鬼给了大侠一个新的挑战。 现在,SVM大侠没有一根直棍可以很好帮他分开两种球了,现在怎么办呢?当然像所有武侠片中一样大侠桌子一拍,球飞到空中。然后,凭借大侠的轻功,大侠抓起一张纸,插到了两种球的中间。 现在,从上面的角度看这些球,这些球看起来像是被一条曲线分开了。 再之后,无聊的大人们,把这些球叫做 「data」,把棍子 叫做 「classifier」, 最大间隙trick 叫做「optimization」, 拍桌子叫做「kernelling」, 那张纸叫做「hyperplane」。 4.1quiz Suppose you have trained an SVM classifier with a Gaussian kernel, and it learned the following decision boundary on the training set: You suspect that the SVM is underfitting your dataset. Should you try increasing or decreasing C? Increasing or decreasing σ2? 答案:A It would be reasonable to try increasing C. It would also be reasonable to try decreasing σ2. It would be reasonable to try decreasing C. It would also be reasonable to try increasing σ2. It would be reasonable to try increasing C. It would also be reasonable to try increasing σ2. It would be reasonable to try decreasing C. It would also be reasonable to try decreasing σ2. The formula for the Gaussian kernel is given by similarity(x,l(1))=exp(−||x−l(1)||22σ2). The figure below shows a plot of f1=similarity(x,l(1)) when σ2=1. Which of the following is a plot of f1 when σ2=0.25? 答案D,σ减小,变瘦,低误差,容易overfitting The SVM solves minθ C∑mi=1y(i)cost1(θTx(i))+(1−y(i))cost0(θTx(i))+∑nj=1θ2j where the functions cost0(z) and cost1(z) look like this: The first term in the objective is: C∑mi=1y(i)cost1(θTx(i))+(1−y(i))cost0(θTx(i)). This first term will be zero if two of the following four conditions hold true. Which are the two conditions that would guarantee that this term equals zero? 答案CD For every example with y(i)=0, we have that θTx(i)≤0. For every example with y(i)=1, we have that θTx(i)≥0. For every example with y(i)=0, we have that θTx(i)≤−1. For every example with y(i)=1, we have that θTx(i)≥1. Suppose you have a dataset with n = 10 features and m = 5000 examples. After training your logistic regression classifier with gradient descent, you find that it has underfit the training set and does not achieve the desired performance on the training or cross validation sets. Which of the following might be promising steps to take? Check all that apply.答案AC Try using a neural network with a large number of hidden units. Use a different optimization method since using gradient descent to train logistic regression might result in a local minimum. Create / add new polynomial features. Reduce the number of examples in the training set. Which of the following statements are true? Check all that apply.答案CD Suppose you are using SVMs to do multi-class classification and would like to use the one-vs-all approach. If you have K different classes, you will train K - 1 different SVMs. If the data are linearly separable, an SVM using a linear kernel will return the same parameters θ regardless of the chosen value of C (i.e., the resulting value of θ does not depend on C). It is important to perform feature normalization before using the Gaussian kernel. The maximum value of the Gaussian kernel (i.e., sim(x,l(1))) is 1 4.2编程在本练习的前半部分,您将使用具有各种示例2D数据集的支持向量机(SVM)。 对这些数据集进行实验将有助于您直观地了解SVM如何工作以及如何在SVM中使用高斯核函数。作业所提供的脚本ex6.m将帮助您逐步完成练习的前半部分。 打开gaussianKernel.m填入: 1sim = exp(-sum((x1 - x2).^2)/2/sigma^2); 打开 dataset3Params.m 填入: 12345678910111213141516cc = [0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30];ss = cc;maxx = 0;for i=1:length(cc) for j=1:length(cc) model = svmTrain(X, y, cc(i), @(x1, x2) gaussianKernel(x1, x2, ss(j))); predict = svmPredict(model, Xval); cur = mean(double(predict == yval)); if maxx < cur maxx = cur; C = cc(i); sigma = ss(j); end endend 在下半年的练习中,您将使用支持向量机来构建垃圾邮件分类器。 今天的许多电子邮件服务都提供了垃圾邮件过滤器,可以将电子邮件以高精度分类为垃圾邮件和非垃圾邮件。 在这部分练习中,您将使用SVM构建您自己的垃圾邮件过滤器。 您将会训练一个分类器来分类给定的电子邮件x是垃圾邮件(y = 1)还是非垃圾邮件(y = 0)。 特别是,您需要将每个电子邮件转换为一个特征向量x∈R n。 练习的以下部分将引导您如何通过电子邮件构建这样的特征向量。 在本练习的其余部分中,您将使用脚本ex6 spam.m. 本练习包含的数据集基于SpamAssassin公共语料库的一个子集。 3为了本练习的目的,您只能使用电子邮件正文(不包括电子邮件标题)。 打开 processEmail.m填入:123456for i=1:length(vocabList) if strcmp(vocabList{i}, str) word_indices = [word_indices; i]; break; endend 打开emailFeatures.m填入:123for i=1:length(word_indices) x(word_indices(i)) = 1;end","link":"/2017/12/15/coursera-斯坦福-机器学习-吴恩达-第7周笔记-支持向量机SVM/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第6周笔记-算法改进and机器学习系统设计","text":"1算法改进1.1评价算法1.1.1模型诊断对于正则化线性回归,其代价函数为:$min\\theta\\ \\dfrac{1}{2m}\\ \\sum{i=1}^m (h\\theta(x^{(i)}) - y^{(i)})^2 + \\lambda\\ \\sum{j=1}^n \\theta_j^2$ 当面对测试集,你的算法效果不佳时,你一般会怎么做? 获得更多的训练样本? 尝试更少的特征? 尝试获取附加的特征? 尝试增加多项式的特征? 尝试增加λ? 尝试减小λ? 具体的情况要具体分析,方法不能乱用机器学习(算法)诊断(Diagnostic)是一种测试方法,使你能对一种学习算法进行深入的认识,知道什么能运行,什么不能运行,并且能指导你如何最大限度的提高学习算法的性能。 诊断测试虽然需要一些时间来实现,但是这样做可以更有效的利用你的时间。 通常的解决办法是: 将数据集分成训练集和测试集,将训练集训练出的参数用测试集数据测试性能。通常情况下,训练集包含70%的数据,测试集是剩下的30%。 那么使用这两套新步骤是: 学习Θ并使用训练集最小化Jtrain(Θ) 计算测试集错误Jtest(Θ) The test set error计算为: linear regression$J{test}(\\Theta) = \\dfrac{1}{2m{test}} \\sum{i=1}^{m{test}}(h\\Theta(x^{(i)}{test}) - y^{(i)}_{test})^2$ classification$J{test}(\\theta) = -\\frac{1}{2m{test}}\\sum{i=1}^{m{test}}y^{(i)}{test}log(h{\\theta}(x^{(i)}{test})) + (1-y^{(i)}{test})log(1-h{\\theta}(x^{(i)}{test}))$ 1.1.2模型选择,validation只是因为学习算法很好地适合训练集,这并不意味着这是一个很好的假设。它可能会过于合适,因此您对测试集的预测会很差。假设您在训练参数的数据集上测量的假设的误差将低于任何其他数据集上的误差。 给定许多具有不同多项式度的模型,我们可以用系统的方法来确定“最佳”函数。为了选择你的假设的模型,你可以测试每个多项式的程度,看看错误的结果。比如在多项式回归时,我们该怎么选择次数作为我们的假设模型呢? 我们可以把数据集分为三类,训练集,交叉验证集和测试集, 训练集:60% 交叉验证集:20% 测试集:20% 用交叉验证集来作为评判选择的标准,选择合适的模型,而测试集则是作为算法性能的评判。 现在我们可以使用以下方法为三个不同的集合计算三个单独的错误值: 使用每个多项式的训练集来优化Θ中的参数。 使用交叉验证集找出具有最小误差的多项式度d(确定合适的模型)。 使用带有Jtest的测试集(Θ(d))估计泛化误差,(d =具有较低误差的多项式的theta);(评价模型) 为啥要设置 “交叉验证集”呢?答案: 一般的数据集都是分为trainning set, cross validation set, test set.当然, 也有只分为training set和test set的分法对第二种分法来说,取得min(Err(test_set))的model作为最佳model,但是我们并不能评价选出来的这个model的性能,如果就将Err(test_set)的值当作这个model的评价的话,这是不公正的,因为这个model本来就是最满足test_set的model 相反,第一种方法取得min(Err(cv_set))的model作为最佳model,对其进行评价的时候,使用剩下的test_set对其进行评价 而不是使用Err(cv_set))的值 1.2偏置与方差1.2.1诊断偏差与方差上面的图分别表示了高偏差,刚好,高方差 在本节中,我们考察多项式d的程度与假设的不合适或过拟合之间的关系。 我们需要区分是否偏差bias 或方差variance 是造成不良预测的问题。 高偏差是不足的,高方差是过度拟合。理想的情况下,我们需要找到这两者之间的中庸之道。 随着我们增加多项式的阶数d,训练误差将趋于减小。 与此同时,交叉验证误差会随着我们将d增加到一个点而降低,然后随d的增加而增加,形成一个凸曲线。 高偏差(underfitting):Jtrain(Θ)和JCV(Θ)都很高。而且,JCV(Θ)≈Jtrain(Θ)。 高方差(overfitting):Jtrain(Θ)将是低的,JCV(Θ)将比Jtrain(Θ)大得多。总结如图,记住图的左边与右边。 1.2.2正则化方差与偏差算法正则化可以有效地防止过拟合, 但正则化跟算法的偏差和方差 又有什么关系呢? 在这段视频中 探讨偏差和方差的问题, 讨论一下两者之间 是如何相互影响的。 以及和算法的正则化之间的相互关系根据λ大小画出的拟合曲线如下 在上图中,我们看到随着λ的增加,我们的拟合变得更加低下。(右边欠拟合) 另一方面,当λ接近0时,我们倾向于过度拟合数据。(左边过拟合) 那么我们如何选择我们的参数λ来使其“恰到好处”呢?为了选择模型和正则化项λ,我们需要: 创建一个lambda表(即λ∈{0,0.01,0.02,0.04,0.08,0.16,0.32,0.64,1.28,2.56,5.12,10.24}); 创建一个不同程度的模型或任何其他变体。 通过λs迭代,并为每个λ遍历所有的模型学习一些Θ。 使用JCV(Θ)上学习的Θ(用λ计算)来计算交叉验证误差,无需正则化或λ= 0。 选择交叉验证集合中产生最低错误的最佳组合。 使用最佳组合Θ和λ,将其应用于Jtest(Θ),以查看它是否具有良好的问题概括性。 1.2.3学习曲线Learning Curves绘制学习曲线非常有用 。也许你想检查你的学习算法 运行是否一切正常 ,或者你希望改进算法的表现或效果。 那么学习曲线 就是一种很好的工具, 使用学习曲线 来判断某一个学习算法 是否处于偏差 方差问题 或是二者皆有 。下面绘制: 在少数几个数据点(如1,2或3)上训练一个算法将很容易产生0个错误,因为我们总是可以找到一个接近这些点数的二次曲线。因此: 随着训练集变大,二次函数的误差增加。 经过一定的m或训练集大小后,误差值将平稳。 根据样本的大小与误差的关系我们可以画出一般的学习曲线模样 下面在两种情况分析:高偏差和高方差 高偏差 从图片上看增大样本的方法对高偏差的模型并不能起到一定作用 高方差 而模型处于高方差的情况下,增大样本可能会起到效果。 1.2.4决定保留谁对开头提出的各种措施,我们看看他们适合于什么样的模型 获取更多培训示例:高度差异 尝试更小的功能集:高差异 增加特征:高偏见 添加多项式特征:高偏差 降低λ:高偏差 增加λ:高方差。 诊断神经网络: 一个参数较少的神经网络容易出现underfitting。这也是计算待价更低。 具有更多参数的大型神经网络容易过度拟合overfitting。这在计算上也是昂贵的。在这种情况下,您可以使用正则化(增加λ)来解决过度拟合问题。 使用单个隐藏层是一个很好的默认开始。您可以使用交叉验证集在许多隐藏层上训练您的神经网络。然后您可以选择性能最好的一个。 模型复杂性的影响: 低阶多项式(低模型复杂度)具有高偏差和低方差。在这种情况下,模型不太一致。 高阶多项式(高模型复杂度)非常适合训练数据,测试数据极其糟糕。这些对训练数据的偏倚低,但差异很大。 实际上,我们希望选择一个介于两者之间的模型,这个模型可以很好地推广,但是也能很好地适合数据。 1.3复习1.3.1quiz You train a learning algorithm, and find that it has unacceptably high error on the test set. You plot the learning curve, and obtain the figure below. Is the algorithm suffering from high bias, high variance, or neither?答案:A 你训练一个学习算法,发现它在测试集上有很高的误差。您绘制学习曲线,并获得下图。该算法是否受到高偏差,高方差或两者都没有? Suppose you have implemented regularized logistic regression to classify what object is in an image (i.e., to do object recognition). However, when you test your hypothesis on a new set of images, you find that it makes unacceptably large errors with its predictions on the new images. However, your hypothesis performs well (has low error) on the training set. Which of the following are promising steps to take? Check all that apply.(过拟合,高方差)答案CD!!!! 假设你已经实现了规则化逻辑回归来分类图像中的对象(即做对象识别)。 然而,当你在一组新的图像上测试你的假设时,你会发现它对新图像的预测会产生无法接受的大错误。 但是,您的假设在训练集上表现良好(误差较低)。 以下哪一项是有希望的步骤? 检查所有适用。 3.假设您已经实施正规化的逻辑回归来预测客户将在网上购物网站上购买什么项目。 然而,当你在一组新的客户上测试你的假设时,你会发现它在预测中产生了无法接受的大错误。 此外,假设在训练集上表现不佳。 以下哪一个可能是有希望的步骤? 检查所有适用。 Suppose you have implemented regularized logistic regression to predict what items customers will purchase on a web shopping site. However, when you test your hypothesis on a new set of customers, you find that it makes unacceptably large errors in its predictions. Furthermore, the hypothesis performs poorly on the training set. Which of the following might be promising steps to take? Check all that apply.(欠拟合,高偏差) Which of the following statements are true? Check all that apply. It is okay to use data from the test set to choose the regularization parameter λ, but not the model parameters (θ).答案BC Which of the following statements are true? Check all that apply.答案BCD (A) If a neural network has much lower training error than test error, then adding more layers will help bring the test error down because we can fit the test set better. (B) If a learning algorithm is suffering from high bias, only adding more training examples may not improve the test error significantly. (C)When debugging learning algorithms, it is useful to plot a learning curve to understand if there is a high bias or high variance problem. (D)A model with more parameters is more prone to overfitting and typically has higher variance. 1.3.1编程在上半场练习中,您将实施正则化的线性回归,利用水库水位的变化来预测大坝出水量。 下半场,您将通过调试学习算法的一些诊断,并检查偏差和方差的影响。 完成文件linearRegCostFunction.m中的代码。 你的任务是写一个函数来计算正则化的线性回归成本函数。 如果可能的话,尝试向量化你的代码,避免写循环。 1234J = 1/2/m* sum((X*theta - y) .^ 2) + lambda/2/m * sum(theta(2:end) .^ 2);grad = 1/m* (X'*(X*theta - y));grad(2:end) = grad(2:end) + lambda/m*theta(2:end); 填写learningCurve.m,以便返回训练集和交叉验证集的错误向量。 12345for i=1:m theta = trainLinearReg(X(1:i, :), y(1:i), lambda); error_train(i) = linearRegCostFunction(X(1:i, :), y(1:i), theta, 0); error_val(i) = linearRegCostFunction(Xval, yval, theta, 0);end 完成polyFeatures.m中的代码,以便函数将大小为m×1的原始训练集X映射到其更高的权力。 123for i = 1:p X_poly(:,i) = X.^i;end 完成validationCurve.m中的代码。具体来说,应该使用trainLinearReg函数来训练使用不同λ值的模型,并计算训练误差和交叉验证误差。 12345for i=1:size(lambda_vec, 1) theta = trainLinearReg(X, y, lambda_vec(i)); error_train(i) = linearRegCostFunction(X, y, theta, 0); error_val(i) = linearRegCostFunction(Xval, yval, theta, 0);end 2机器学习系统设计这一章对应PPT lecture11 给定一个电子邮件数据集,我们可以为每个电子邮件构建一个向量。这个向量中的每个条目代表一个单词(词袋模型)。该矢量通常包含10,000到50,000个条目,通过查找我们数据集中最常用的单词来收集。如果在电子邮件中找到一个单词,我们将分配它的相应条目1,否则如果没有找到,条目将是0.一旦我们已经准备好了所有的x向量,我们将训练我们的算法,最后,我们可以用它来分类电子邮件是否是垃圾邮件。 那么你怎么能花时间来提高这个分类器的准确度呢? Step1.使用快速但不完美的算法实现; Step2.画出学习曲线,分析偏差、方差,判断是否需要更多的数据、增加特征量….; Step3.误差分析:人工检测错误、发现系统短处,来增加特征量以改进系统。 那么你怎么能花时间来提高这个分类器的准确度呢? 收集大量的数据(例如“蜜罐”项目,但并不总是有效) 开发复杂的功能(例如:在垃圾电子邮件中使用电子邮件标题数据) 开发算法以不同的方式处理您的输入(识别垃圾邮件中的拼写错误)。 2.1 误差分析一般我们提升模型的步骤为: Step1.使用快速但不完美的算法实现; Step2.画出学习曲线,分析偏差、方差,判断是否需要更多的数据、增加特征量….; Step3.误差分析:人工检测错误、发现系统短处,来增加特征量以改进系统。 因此,我们应该尝试新的东西,为我们的错误率得到一个数值,并根据我们的结果决定是否要保留新的特征。(使用误差度量值 来判断是否添加新的特征) 2.2 处理“倾斜”数据有些时候,一些数据很不平衡,比如正向的占99%、负向的占1%(倾斜数据shewed data)。这样只用准确度这个指标就不能很好的衡量算法的好坏,所以我们引入了信度precision和召回率recall。举个例子: 判断癌症的分类器,建立逻辑回归模型hθ(x),y=1表示有癌症,y=0则没有。假设你的算法在测试集上只有1%的错误,可实际上,测试集中只有0.5%的病人患有癌症,因此我们可以通过下面的方法来提高正确率。这个“算法”很搞笑:不管是谁来看病,统统判断为没有癌症。这样准确度就提高了,但是病人一时开心,以后会耽误治疗哈哈哈哈哈哈。 从上面的例子我们可以知道正确率不足以表现一个算法的优劣(在某些正例或反例及其少的数据集中),因此我们引入了Precision/Recall。 构造方法: Precision(准确率、信度) 在我们预测y=1的数据中,真正得癌症的比重,也就是你预测的可信度。 $\\frac{True pos}{predicted pos} = \\frac{True pos}{True pos+ false pos}$ Recal(召回率)在真正得癌症的数据中,我们预测癌症所占的比重。 $\\frac{True pos}{actual pos} = \\frac{True pos}{True pos+ false neg}$ 在大多数的时候我们想找到两个评价指标的平衡。比如: 假设考虑到一个正常人如果误判为癌症,将会承受不必要的心理和生理压力,所以我们要有很大把握才预测一个病人患癌症(y=1)。那么一种方式就是提高阙值(threshold),不妨设我们将阙值提高到0.7,即: 12Predict 1 if: hθ(x)≥0.7 Predict 0 if: hθ(x)<0.7 在这种情况下,我们将会有较高的precision,但是recall将会变低。 假设考虑到一个已经患癌症的病人如果误判为没有患癌症,那么病人可能将因不能及时治疗而失去宝贵生命,所以我们想要避免错过癌症患者的一种方式就是降低阙值,假设降低到0.3, 即 12Predict 1 if: hθ(x)≥0.3 Predict 0 if: hθ(x)<0.3 在这种情况下,将得到较高的recall,但是precision将会下降。 为了将precision和Recal转变为一个单一数值,我们引入了F1值:$F = 2\\frac{PR}{P+R}$ 总结:衡量一个算法应该用一下值综合考虑: Accuracy = (true positives + true negatives) / (total examples) Precision = (true positives) / (true positives + false positives) Recall = (true positives) / (true positives + false negatives) F 1 score = (2 precision recall) / (precision + recall) 2.3 使用大的数据集但事实证明 在一定条件下 , 得到大量的数据并在 某种类型的学习算法中进行训练。 可以是一种 获得 一个具有良好性能的学习算法 有效的方法。 像这样的结果 引起了一种 在机器学习中 的普遍共识: “取得成功的人不是拥有最好算法的人 而是拥有最多数据的人” 那么这种说法 在什么时候是真 什么时候是假呢? 特征x包含足够的信息来准确地预测y。 (例如,验证这种情况的一种方式是,如果只有在给定x的情况下,领域上的专家才能自信地预测y)。 我们训练一个具有大量参数(能够学习/表示相当复杂的函数)的学习算法。 2.4 quiz机器学习系统的测试题: You are working on a spam classification system using regularized logistic regression. “Spam” is a positive class (y = 1) and “not spam” is the negative class (y = 0). You have trained your classifier and there are m = 1000 examples in the cross-validation set. The chart of predicted class vs. actual class is:您正在使用正则化逻辑回归来处理垃圾邮件分类系统。 “垃圾邮件”是一个积极的类(y = 1),“不垃圾邮件”是否定类(y = 0)。 您已经对分类器进行了训练,并且在交叉验证集中有m = 1000个示例。 预测班级与实际班级的关系图如下: · Actual Class: 1 Actual Class: 0 Predicted Class: 1 85 890 Predicted Class: 0 15 10 计算公式如下: Accuracy = (true positives + true negatives) / (total examples) Precision = (true positives) / (true positives + false positives) Recall = (true positives) / (true positives + false negatives) F1 score = (2 precision recall) / (precision + recall) What is the classifier’s accuracy (as a value from 0 to 1)?答案:0.095 第 2 个问题Suppose a massive dataset is available for training a learning algorithm. Training on a lot of data is likely to give good performance when two of the following conditions hold true. Which are the two? The features x contain sufficient information to predict y accurately. (For example, one way to verify this is if a human expert on the domain can confidently predict y when given only x). We train a learning algorithm with a large number of parameters (that is able to learn/represent fairly complex functions). Suppose you have trained a logistic regression classifier which is outputing hθ(x). Currently, you predict 1 if hθ(x)≥threshold, and predict 0 if hθ(x)《threshold, where currently the threshold is set to 0.5. Suppose you increase the threshold to 0.9. Which of the following are true? Check all that apply. 假设你已经训练了输出hθ(x)的逻辑回归分类器。目前,如果hθ(x)≥threshold,则预测1;如果hθ(x)《threshold,则预测为0,其中当前阈值设置为0.5。假设将阈值增加到0.9。 以下哪一项是正确的? 检查所有适用。 答案:高信度,低召回。 Suppose you are working on a spam classifier, where spam emails are positive examples (y=1) and non-spam emails are negative examples (y=0). You have a training set of emails in which 99% of the emails are non-spam and the other 1% is spam. Which of the following statements are true? Check all that apply. 假设您正在使用垃圾邮件分类器,其中垃圾邮件是正面示例(y = 1),非垃圾邮件是负面示例(y = 0)。 您有一组电子邮件,其中99%的电子邮件是非垃圾邮件,另外1%是垃圾邮件。 以下哪一项是正确的? 检查所有适用。 If you always predict non-spam (output y=0), your classifier will have an accuracy of 99%. If you always predict non-spam (output y=0), your classifier will have a recall of 0%. If you always predict spam (output y=1), your classifier will have a recall of 100% and precision of 1%. 如果你总是预测非垃圾邮件(输出y = 0),你的分类器将有99%的准确性。 如果你总是预测非垃圾邮件(输出y = 0),你的分类器将有一个0%的召回。 如果您总是预测垃圾邮件(输出y = 1),您的分类器将具有100%的回忆率和1%的精度。 Which of the following statements are true? Check all that apply. Using a very large training set makes it unlikely for model to overfit the training data. On skewed datasets (e.g., when there are more positive examples than negative examples), accuracy is not a good measure of performance and you should instead use F1 score based on the precision and recall. 使用非常大的训练集使模型不太可能过度训练数据。 在偏斜的数据集上(例如,当比正面的例子更多的时候,正确的例子),准确性不是一个好的衡量指标,你应该使用基于精度和回忆的F1分数。","link":"/2017/12/14/coursera-斯坦福-机器学习-吴恩达-第6周笔记-算法改进and机器学习系统设计/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第9周笔记(上)-异常检测","text":"1异常检测异常检测(Anomaly detection)问题 是机器学习算法 的一个常见应用, 这种算法的一个有趣之处在于 :它虽然主要用于 非监督学习问题 ,但从某些角度看 它又类似于一些监督学习问题 。 1.1引入那么 什么是异常检测呢? 为了解释这个概念 ,让我举一个例子吧: 假想你是一个 飞机引擎制造商, 当你生产的飞机引擎 从生产线上流出时 你需要进行 QA (质量控制测试), 而作为这个测试的一部分 你测量了飞机引擎的一些特征变量 ,比如 你可能测量了 引擎运转时产生的热量, 或者引擎的振动等等 。采集这些特征变量 这样一来 你就有了一个数据集 ,从x(1)到x(m), 如果你生产了m个引擎的话 也许你会将这些数据绘制成图表。 后来有一天 ,你有一个新的飞机引擎 从生产线上流出,而你的新飞机引擎 有特征变量x-test 。所谓的异常检测问题就是 我们希望知道, 这个新的飞机引擎是否有某种异常。 感性来理解一下,如图: 这些样本点 有很大的概率值 落在 在中心区域。而稍微远离中心区域的点概率会小一些 ,更远的地方的点 它们的概率将更小, 这外面的点 和这外面的点 将成为异常点 。 而这些圈是可以用一个概率模型P(x)来衡量的,我们的异常检测算法就是找到这样一个概率模型画出这个圈。 异常检测算法有很多用途,比如: 欺诈检测:把用户的使用习惯设为特征,若很反常有可能为欺诈。 制造业:产品的质量控制(QA)。 数据中心的计算监控:监控cpu、内存等的使用情况是否又反常。 1.2高斯(正态)分布异常检测的数学基础:高斯(正态)分布。是数理统计中的知识,话说线性代数与数理统计这两门课真的是有用啊。 所谓样本x服从高斯分布(x~N),就是x出现的概率(或者说发生x事件的概率)满足这样一个公式:$p(x) = \\frac{1}{\\sqrt{2\\pi}\\sigma}\\exp\\left(-\\frac{(x-\\mu)^2}{2\\sigma^2}\\right)$ 所以这是一个概率公式。他的图像如下:以均值为中心,方差为宽度。 其中均值与方差的计算方法如下: 有了均值与方差的计算方法,就有了参数估计这一名词。就是:给你了一些样本值,你可以求出他们的均值与方差,然后用这两个参数估计总体样本的分布。 第二个比较重要的数学知识就是独立分布的概率,等于概率的乘积。 1.3异常检测算法❤❤❤这一节给出了异常检测的步骤,对于给出的样本${x^{(1)},…, x^{(m)}}$: 选出一些重要的特征,比如:$x_j^{(i)}$表示第i个样本的第j个特征,比如发动机温度。 计算各个特征的均值与方差:$\\displaystyle \\muj = \\frac{1}{m}\\sum{i=1}^m x_j^{(i)},\\ \\sigmaj^2 = \\frac{1}{m}\\sum{i=1}^m(x_j^{(i)} - \\mu_j)^2$ 。 这样也就算出了每种特征的分布,也就算出了每种特征出现某值的概率。 给出一个新的样本,计算他出现的概率P(x)。P(x)等于各项特征出现概率的乘积。 下面通过图像直观感受: 左上角为样本点,有X1和X2两个特征。 计算分别计算X1和X2的均值和方差。图像如右上角,综合两者的图像为三维左下角,高度为概率。 给定2个样本Xtest,计算出现的概率,大于阈值为正常,小于这么小的阈值为异常。 总结:异常检验的数学内涵是数理统的一条法则: 小概率事件一般不会发生。 翻译成通俗解释就是:不可能发生的事情却发生了,必有阴谋!所以判断其为异常值,事后专门对其进行检查。 2建立一个异常检测系统在上一段视频中 我们推导了异常检测算法, 在这段视频中, 我想介绍一下 如何开发一个 关于异常检测的应用 ,来解决一个实际问题 。 2.1评价一个异常检测系统评价异常检测系统最常用的方法就是使用 cross validation(与监督学习一样):将训练数据分为三部分:Training set is unlabled, cross validation & test set is labled.如图: 对于异常检测问题,要检测出的是anomalous的,所以anomalous对应y = 1,我们举个例子,对与飞机发动机故障检测,将10000个好数据分为三部分,20个故障数据分成2部分,如图: 其中第二种方式,把CV与test数据弄的一样,吴恩达老师不鼓励这样。 下面总结一下步骤:即: 对训练数据进行寻找估计模型。P(X) 使用交叉验证和test数据集预测0和1. 使用召回率和置信度计算F1值评价算法。(为啥不用精度?因为:这是个不均衡数据skewed,前面讲过不能使用classification accuracy。) 设置epsilon,在交叉验证集上评估算法,然后当我们选择了特征集时,找到epsilon的值,对测试集上的算法进行最终评估。 2.2异常检测vs.监督学习在上一段视频中 ,我们谈到 如何评价一个 异常检测算法 ,我们先是用了一些 带标签的数据 ,以及一些我们知道是异常 或者正常的样本 用 y=1 或 y=0 来表示 。 这就引出了这样一个问题: 我们有了这些带标签的数据 我们有了一些样本 其中一些我们知道是异常的 另外一些是正常的 那我们为什么我们不 直接用监督学习的方法呢? ppt已经写得很清楚了,在总结一下:关键的区别就是 :在异常检测算法中 我们只有一小撮 正样本 因此学习算法不可能 从这些正样本中学出太多东西 。 异常检测 监督学习 负向数据很多,可以精确的计算出参数估计P(x) 需要两种数据都多,才能很好的计算出模型。 好的数据很集中,但故障可能有很多种,只要将其找出即可 需要大量正样本,才能学习出相关特征,表示出故障的特征进行分类。 下一页ppt给出了两种算法的一般使用场景: 下面一个练习题,可以看一下。 2.3选择使用哪些features在此之前 我们讨论了如何 评估一个异常检测算法 。事实上 当你应用异常检测时 对它的效率 影响最大的 因素之一是 你使用什么特征变量 。两种方法: 参数修改 在我们的异常检测算法中我们做的事情之一就是使用这种正态(高斯)分布来对特征向量建模,但是有些数据并不太符合高斯分布,虽然算法也常常可以正常运行,但效果不好,可以用这种数学方法: 进行数据的不同转换,以使其看起来更加高斯。比如:用 x1 的对数 log(x1) 来替换掉 x1,或者平方根来取代 x3。 误差分析 像之前讲监督学习的误差分析一样, 我们先完整地训练出 一个学习算法, 然后在一组交叉验证集上运行算法 ;然后找出那些预测出错的样本, 然后再看看 我们能否找到一些其他的特征变量 来帮助学习算法, 让它在那些交叉验证时 判断出错的样本中表现更好 。 比如下图:绿色x代表anomaly example, 只有一个feature x1时会区分错误,加一个feature x2时就可以正确区分。 3多元高斯分布异常检测算法的 一种可能的延伸 —— 多元高斯分布 (multivariate Gaussian distribution) 。它有一些劣势(计算量大),也有一些优势( 它能捕捉到一些之前的算法检测不出来的异常)。 3.1多元高斯分布数学 我们先来看看一个例子: 假设我们的没有标签的数据看起来像这张图一样。 ,我要使用数据中心的监控机的例子 ,我的两个特征变量 x1 是 CPU 的负载和 x2 可能是内存使用量 。 那么普通的高斯分布建模就是粉红色的圆圈,多元高斯分布建模就是蓝色的“斜”椭圆。(其知识为多元正态分布的相关性,其实普通正态分布就是多元正态分布的特例——特征独立不相关。) 其概率表达式为: 推导过程如下: 设(X1,X2)是二元正态变量,其密度函数为: 即 (X1,X2)~$N(\\mu_1, \\mu_2, \\sigma_1^2,\\sigma_2^2,\\rho)$其中:ρ是相关系数 令: $x = (x_1, x_2)^T$ $\\mu = (\\mu_1, \\mu_2)^T$ C=$\\begin{pmatrix}c_{11} & c_{12} \\\\ c_{21} & c_{22} \\\\ \\end{pmatrix}$=$\\begin{pmatrix} \\sigma_1^2 & \\rho\\sigma_1\\sigma_2 \\\\ \\rho\\sigma_1\\sigma_2&\\sigma_2^2 \\\\ \\end{pmatrix}$ 于是推出: $f(x_1, x_2) = \\frac1{(2\\pi)^\\frac n2(|C|)^{\\frac12}} e^{-\\frac12(x-\\mu)^TC^(-1)(x-\\mu)}$即: 其中: μ 相当于每个正态分布的对称轴,是一个一维向量 Σ是协方差矩阵 下面通过图像来看一下多元正态分布的特点: 协方差相同,说明特征独立,与普通高斯分布相同: 协方差改变,特征相关,变成椭圆: 正相关(右上-左下) 负相关(左上-右下) 3.2应用多元高斯分布进行异常检测之前看到了一些例子, 通过改变参数 µ 和 Σ 来给不同的概率分布建模。 在这节视频中 ,我们来使用那些想法 ,用它们来开发另一种异常检测算法 。 步骤如下: 传统高斯分布与多元高斯分布的关系:当多元高斯分布的协方差为对角矩阵的时候就是不同高斯分布。 具体区别对比: 多元高斯模型有很多参数,所以这个协方差矩阵σ是一个n乘n的矩阵,大约有n个平方参数,因为它是一个对称矩阵,它实际上更接近于2个参数的n平方,但是这是很多参数,所以你需要确保你有一个相当大的m值,确保你有足够的数据来适应所有这些参数。 m大于或等于10 n将是一个合理的经验法则,以确保您可以相当好地估计这个协方差矩阵西格玛。 在你有非常大的训练集或m非常大而n不是太大的问题中,那么多元高斯模型是值得考虑的,并且可以更好地工作,并且可以节省你不必花费时间手动创建额外的功能,以防异常结果被特征值的异常组合所捕捉。 协方差矩阵西格玛不可逆,他们通常是这种情况2,一个如果它不能满足这个米大于n条件; secondcase是如果你有多余features.if你有2个功能是相同的。如果你的x1只是等于x2。或者如果你有多余的功能,比如你的功能X3等同于功能X4,再加上功能X5,那么X3不包含任何额外的信息。 4 复习 For which of the following problems would anomaly detection be a suitable algorithm?答案AC [ ] Given a dataset of credit card transactions, identify unusual transactions to flag them as possibly fraudulent. [ ] Given data from credit card transactions, classify each transaction according to type of purchase (for example: food, transportation, clothing). [ ] From a large set of primary care patient records, identify individuals who might have unusual health conditions. [ ] Given an image of a face, determine whether or not it is the face of a particular famous individual. Suppose you have trained an anomaly detection system that flags anomalies when p(x)is less than ε, and you find on the cross-validation set that it has too many false positives (flagging too many things as anomalies). What should you do?答案B [ ] Increase ε [ ] Decrease ε Suppose you are developing an anomaly detection system to catch manufacturing defects in airplane engines.You model uses $p(x) = \\prod_{j=1}^n p(x_j ; \\mu_j, \\sigma^2_j)$ You have two features x1 = vibration intensity, and x2 = heat generated. Both x1 and x2take on values between 0 and 1 (and are strictly greater than 0), and for most “normal” engines you expect that x1≈x2. One of the suspected anomalies is that a flawed engine may vibrate very intensely even without generating much heat (large x1, small x2), even though the particular values of x1 and x2 may not fall outside their typical ranges of values. What additional feature x3 should you create to capture these types of anomalies:答案B x3=x21×x22 x3=x1x2 x3=(x1+x2)2 x3=x1×x22 Which of the following are true? Check all that apply.答案AD [ ] If you do not have any labeled data (or if all your data has label y=0), then is is still possible to learn p(x), but it may be harder to evaluate the system or choose a good value of ϵ. [ ] If you are developing an anomaly detection system, there is no way to make use of labeled data to improve your system. [ ] If you have a large labeled training set with many positive examples and many negative examples, the anomaly detection algorithm will likely perform just as well as a supervised learning algorithm such as an SVM. [ ] When choosing features for an anomaly detection system, it is a good idea to look for features that take on unusually large or small values for (mainly the) anomalous examples. You have a 1-D dataset {x(1),…,x(m)} and you want to detect outliers in the dataset. You first plot the dataset and it looks like this:Suppose you fit the gaussian distribution parameters μ1 and σ21 to this dataset. Which of the following values for μ1 and σ21 might you get?答案A [ ] μ1=−3,σ21=4 [ ] μ1=−6,σ21=4 [ ] μ1=−3,σ21=2 [ ] μ1=−6,σ21=2","link":"/2017/12/20/coursera-斯坦福-机器学习-吴恩达-第9周笔记(上)-异常检测/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第9周笔记(下)-推荐系统","text":"1预测电影等级推荐系统(recommender systems),比如对像 Netflix 这样的公司 ,他们向用户推荐的电影 占了用户观看的电影的 相当大一部分 。 对于机器学习来说 特征量是重要的, 你选择的特征 对你学习算法的表现有很大影响。 在机器学习领域 有这么一个宏大的想法, 就是对于一些问题 存在一些算法, 能试图自动地替你学习到一组优良的特征量。 而推荐系统 就是这种情形的一个例子。还有其他很多例子 但通过学习推荐系统 ,我们将能够 对这种学习特征量的想法 有一点理解。 1.1任务设想 我这里有5部电影 《爱到最后》 《浪漫永远》 《小爱犬》 《无尽狂飙》 还有 《剑与空手道》。 我们有4位用户 名叫 Alice Bob Carol 和 Dave 。首字母为A B C和D 我们称他们用户1 2 3和4 。比方说 ,Alice 她非常喜欢 《爱到最后》 把它评为5颗星。 她还喜欢 《浪漫永远》 也把它评为5颗星。 她没看过 《小爱犬》 也就没评分, 这样我们没有这个评分数据。 我们查看数据并查看所有缺失的电影评级,并试图预测这些问号的值应该是多少。 1.2基于内容的推荐每个items都有一些features,如果我们知道它们的值是多少,同时每个用户通过θj告诉我们他们有多喜欢romantic或者action movies。这种按照内容的特征来推荐的算法就是——基于内容推荐。 使用梯度下降优化: 如果你觉得这个 梯度下降的更新 看起来跟之前 线性回归差不多的话, 那是因为这其实就是线性回归, 唯一的一点区别 是在线性回归中 我们有1/m项 。 通过这节课 你应该知道了 怎样应用一种 事实上是线性回归的一个变体, 来预测不同用户对不同电影的评分值 ,这种具体的算法叫 ”基于内容的推荐“ 或者”基于内容的方法“。 因为我们假设 我们有不同电影的特征 ,我们有了电影 内容的特征 比如电影的爱情成分有多少?动作成分有多少? 我们就是用电影的这些特征 来进行预测 。 但事实上 对很多电影 我们并没有这些特征 或者说 很难得到 所有电影的特征 很难知道 我们要卖的产品 有什么样的特征 。所以在下一段视频中 我们将谈到一种不基于内容的推荐系统:协同过滤。 2协同过滤2.1协同过滤在这段视频中 我们要讲 一种构建推荐系统的方法 叫做协同过滤(collaborative filtering) 。 算法 有一个值得一提的 特点 ,那就是它能实现 对特征的学习。 我的意思是 这种算法能够 自行学习所要使用的特征 。 我们建一个数据集 ,假定是为每一部电影准备的 ,对每一部电影 我们找一些人来 告诉我们这部电影 浪漫指数是多少 动作指数是多少。但想一下就知道 这样做难度很大, 也很花费时间 。你想想 要让每个人 看完每一部电影 告诉你你每一部电影有多浪漫 多动作 这是一件不容易的事情。 现在我们稍稍改变一下这个假设 ,假设我们采访了每一位用户 而且每一位用户都告诉我们 他们是否喜欢 爱情电影。 总结一下, 这一阶段要做的 就是为所有 为电影评分的 用户 j 选择特征 x(i)。 这一算法同样也预测出一个值 ,表示该用户将会如何评价某部电影。 而这个预测值 在平方误差的形式中 与用户对该电影评分的实际值尽量接近 。 优化目标:$\\displaystyle \\min_{x^{(1)},…,x^{(nm)}} \\frac{1}{2}\\sum{i=1}^{nm}\\sum{j:r(i,j)=1}\\left((\\theta^{(j)})^T x^{(i)}-y^{(i,j)}\\right)^2 + \\frac{\\lambda}{2}\\sum_{i=1}^{nm}\\sum{k=1}^n(x_k^{(i)})^2$ 梯度下降(注意是对x求偏导):$x_k^{(i)} := xk^{(i)} - \\alpha\\left(\\sum{j:r(i,j)=1}\\left((\\theta^{(j)})^T(x^{(i)}) - y^{(i,j)}\\right)\\theta_k^{(j)}+ \\lambda x_k^{(i)}\\right)$ 我们之前 这个视频中讲的是 ,如果用户愿意 为你提供参数 ,那么你就可以为不同的电影估计特征 。 这有点像鸡和蛋的问题 到底先有鸡还是先有蛋?就是说 如果我们能知道 θ 就能学习到 x ,如果我们知道 x 也会学出 θ 来 。 我们可以一开始随机 猜测出的 θ 的值, 你可以继续下去 运用我们刚刚讲到的 步骤 我们可以学习出 不同电影的特征 。 同样的给出已有的一些电影的 原始特征, 你可以运用 我们在上一个视频中讨论过的 第一种方法 ,可以得到 对参数 θ 的更好估计 ,这样就会为用户提供更好的参数 θ 集。 我们可以继续 迭代 不停重复 优化θ x θ x θ 这非常有效 2.2协同过滤算法在前面几个视频里 我们谈到几个概念 ,首先 ,如果给你几个特征表示电影, 我们可以使用这些资料去获得用户的参数数据。 第二 ,如果给你用户的参数数据, 你可以使用这些资料去获得电影的特征。 本节视频中 我们将会使用这些概念 并且将它们合并成 协同过滤算法 (Collaborative Filtering Algorithm) 。 总结一下我们之前做过的事情 :其中之一是, 假如你有了电影的特征 ,你就可以解出 这个最小化问题 ,为你的用户找到参数 θ 。然后我们也 知道了, 如果你拥有参数 θ, 你也可以用该参数 通过解一个最小化问题 去计算出特征 x 。 所以你可以做的事 是不停地重复这些计算 ,首先随机地初始化这些参数 ,然后解出 θ 解出 x 解出 θ 解出 x ….但我将它们给合在一起 然后同时计算两个的梯度: 3低秩矩阵分解Low Rank Matrix Factorization在上几节视频中 我们谈到了协同过滤算法 ,本节视频中我将会 讲到有关 该算法的向量化实现。 3.1向量化:低秩矩阵分解Low Rank Matrix Factorization 如果你有 预测评分矩阵 ,你就会有 以下的这个 有着(i, j)位置数据的矩阵 。 也就是令:$X = \\begin{bmatrix} - & (x^{(1)})^T & - \\ & \\vdots & \\ - & (x^{(n_m)} & - \\end{bmatrix},\\ \\Theta = \\begin{bmatrix} - & (\\theta^{(1)})^T & - \\ & \\vdots & \\ - & (\\theta^{(n_u)} & - \\end{bmatrix}$ 则:$X\\Theta^T = \\displaystyle \\begin{bmatrix} (x^{(1)})^T(\\theta^{(1)}) & \\ldots & (x^{(1)})^T(\\theta^{(n_u)})\\ \\vdots & \\ddots & \\vdots \\ (x^{(n_m)})^T(\\theta^{(1)}) & \\ldots & (x^{(n_m)})^T(\\theta^{(n_u)})\\end{bmatrix}$这就是低秩矩阵分解 。 现在既然你已经 对特征参数向量进行了学习 ,那么我们就会有一个很方便的方法 来度量两部电影之间的相似性。 例如说 ,电影i有一个特征向量x(i), 你是否能找到一部 不同的电影 j,保证两部电影的特征向量之间的距离x(i)和x(j)很小 ,那就能 很有力地表明 电影 i 和电影 j在某种程度上有相似。 就是计算 small ||$x^{(i)}-x^{(j)}$||。 3.2实现细节到目前为止 你已经了解到了 推荐系统算法或者 协同过滤算法的所有要点 。在这节视频中 我想分享最后一点实现过程中的细节 ,这一点就是均值归一化 有时它可以让算法 运行得更好 。 所有item减去其(所有用户给它的)打分均值(没有评分的user_item不计入均值的计算),参数推断完成后再加回来。 如果电影没有评分,就将列和均值设置为0;如果用户没有评分,就将行均值设置为0。 否则新用户评分为0,则为负样例。 4复习4.1quiz Suppose you run a bookstore, and have ratings (1 to 5 stars) of books. Your collaborative filtering algorithm has learned a parameter vector θ(j) for user j, and a feature vector x(i) for each book. You would like to compute the “training error”, meaning the average squared error of your system’s predictions on all the ratings that you have gotten from your users. Which of these are correct ways of doing so (check all that apply)? For this problem, let m be the total number of ratings you have gotten from your users. (Another way of saying this is that m=∑nmi=1∑nuj=1r(i,j)). [Hint: Two of the four options below are correct.]答案AC [ ] 1m∑nmi=1∑j:r(i,j)=1(∑nk=1(θ(j))kx(i)k−y(i,j))2 [ ] 1m∑nuj=1∑i:r(i,j)=1(∑nk=1(θ(k))jx(k)i−y(i,j))2 [ ] 1m∑(i,j):r(i,j)=1((θ(j))Tx(i)−y(i,j))2 [ ] 1m∑(i,j):r(i,j)=1((θ(j))Tx(i)−r(i,j))2 In which of the following situations will a collaborative filtering system be the most appropriate learning algorithm (compared to linear or logistic regression)?答案BCD(这个题醉了 怎么选都错) [ ] You manage an online bookstore and you have the book ratings from many users. You want to learn to predict the expected sales volume (number of books sold) as a function of the average rating of a book. [ ] You manage an online bookstore and you have the book ratings from many users. For each user, you want to recommend other books she will enjoy, based on her own ratings and the ratings of other users. [ ] You run an online news aggregator, and for every user, you know some subset of articles that the user likes and some different subset that the user dislikes. You’d want to use this to find other articles that the user likes. [ ] You’ve written a piece of software that has downloaded news articles from many news websites. In your system, you also keep track of which articles you personally like vs. dislike, and the system also stores away features of these articles (e.g., word counts, name of author). Using this information, you want to build a system to try to find additional new articles that you personally will like. You run a movie empire, and want to build a movie recommendation system based on collaborative filtering. There were three popular review websites (which we’ll call A, B and C) which users to go to rate movies, and you have just acquired all three companies that run these websites. You’d like to merge the three companies’ datasets together to build a single/unified system. On website A, users rank a movie as having 1 through 5 stars. On website B, users rank on a scale of 1 - 10, and decimal values (e.g., 7.5) are allowed. On website C, the ratings are from 1 to 100. You also have enough information to identify users/movies on one website with users/movies on a different website. Which of the following statements is true?答案D [ ] You can combine all three training sets into one without any modification and expect high performance from a recommendation system. [ ] Assuming that there is at least one movie/user in one database that doesn’t also appear in a second database, there is no sound way to merge the datasets, because of the missing data. [ ] It is not possible to combine these websites’ data. You must build three separate recommendation systems. [ ] You can merge the three datasets into one, but you should first normalize each dataset’s ratings (say rescale each dataset’s ratings to a 1-100 range). Which of the following are true of collaborative filtering systems? Check all that apply.答案AC [ ] If you have a dataset of users ratings’ on some products, you can use these to predict one user’s preferences on products he has not rated. [ ] When using gradient descent to train a collaborative filtering system, it is okay to initialize all the parameters (x(i) and θ(j)) to zero. [ ] Recall that the cost function for the content-based recommendation system is J(θ)=12∑nuj=1∑i:r(i,j)=1((θ(j))Tx(i)−y(i,j))2+λ2∑nuj=1∑nk=1(θ(j)k)2. Suppose there is only one user and he has rated every movie in the training set. This implies that nu=1 and r(i,j)=1 for every i,j. In this case, the cost function J(θ) is equivalent to the one used for regularized linear regression. [ ] To use collaborative filtering, you need to manually design a feature vector for every item (e.g., movie) in your dataset, that describes that item’s most important properties. Suppose you have two matrices A and B, where A is 5x3 and B is 3x5. Their product is C=AB, a 5x5 matrix. Furthermore, you have a 5x5 matrix R where every entry is 0 or 1. You want to find the sum of all elements C(i,j) for which the corresponding R(i,j) is 1, and ignore all elements C(i,j) where R(i,j)=0. One way to do so is the following code: Which of the following pieces of Octave code will also correctly compute this total? Check all that apply. Assume all options are in code.答案AB [ ] total = sum(sum((A B) . R)) [ ] C = (A B) . R; total = sum(C(:)); [ ] total = sum(sum((A B) R)); [ ] C = (A B) R; total = sum(C(:)); 1m∑(i,j):r(i,j)=1((θ(j))Tx(i)−y(i,j))2 1m∑nuj=1∑i:r(i,j)=1((θ(j))ix(i)j−y(i,j))2 1m∑(i,j):r(i,j)=1(∑nk=1(θ(j))kx(i)k−y(i,j))2 1m∑nuj=1∑i:r(i,j)=1(∑nk=1(θ(j))kx(i)k−y(i,j))2 1m∑(i,j):r(i,j)=1∑nk=1((θ(j))kx(i)k−y(i,j))2 4.2编程在本练习中,您将实施异常检测算法并将其应用于检测网络上发生故障的服务器。 在第二部分中,您将使用协作过滤来构建电影的推荐系统 1异常检测在这个练习中,您将实现一个异常检测算法来检测服务器计算机中的异常行为。 这些功能衡量每个服务器响应的吞吐量(mb / s)和延迟(ms)。 当你的服务器正在运行时,你收集了他们如何行为的例子,因此有一个未标记的数据集{x(1),…,x(m)}。 您怀疑这些示例中绝大多数是服务器正常运行的“正常”(非异常)示例,但也可能有一些服务器在此数据集中异常运行的示例。 打开estimateGaussian.m12mu = 1/m * sum(X);sigma2 = 1/m * sum((X - repmat(mu, m, 1)).^2); 打开selectThreshold.m填入: 123456789predictions = (pval < epsilon);fp = sum((predictions == 1) & (yval == 0));fn = sum((predictions == 0) & (yval == 1));tp = sum((predictions == 1) & (yval == 1));prec = tp / (tp + fp);rec = tp / (tp + fn);F1 = 2 * prec * rec / (prec + rec); 打开cofiCostFunc.m填入: 12X_grad = (((X*Theta').*R*Theta-Y.*R*Theta)+lambda.*X);Theta_grad = ((X'*((X*Theta').*R)-X'*(Y.*R)))'+lambda.*Theta;","link":"/2017/12/21/coursera-斯坦福-机器学习-吴恩达-第9周笔记(下)-推荐系统/"},{"title":"eclipse使用maven教程","text":"0.什么是maven参考 https://www.cnblogs.com/whgk/p/7112560.html 我们开发一个项目,或者做一个小demo,比如用SSH框架,那么我们就必须将SSH框架所用的几十个依赖的jar包依次找出来并手动导入,超级繁琐。 上面问题的描述,其实都属于项目与项目之间依赖的问题[A项目使用SSH的所有jar,就说A项目依赖SSH],人为手动的去解决,很繁琐,也不方便,所以使用maven来帮我们管理Maven是基于项目对象模型(POM project object model),可以通过一小段描述信息(配置)来管理项目的构建,报告和文档的软件项目管理工具[百度百科] 这种又是大白话,如果没明白maven是什么,那么上面这句话跟没说一样,我自己觉得,Maven的核心功能便是合理叙述项目间的依赖关系,通俗点讲,就是通过pom.xml文件的配置获取jar包,而不用手动去添加jar包,而这里pom.xml文件对于学了一点maven的人来说,就有些熟悉了,怎么通过pom.xml的配置就可以获取到jar包呢?pom.xml配置文件从何而来?等等类似问题我们需要搞清楚,如果需要使用pom.xml来获取jar包,那么首先该项目就必须为maven项目,maven项目可以这样去想,就是在java项目和web项目的上面包裹了一层maven,本质上java项目还是java项目,web项目还是web项目,但是包裹了maven之后,就可以使用maven提供的一些功能了(通过pom.xml添加jar包)。 所以,根据上一段的描述,我们最终的目的就是学会如何在pom.xml中配置获取到我们想要的jar包,在此之前我们就必须了解如何创建maven项目,maven项目的结构是怎样,与普通java,web项目的区别在哪里,还有如何配置pom.xml获取到对应的jar包等等,这里提前了解一下我们如何通过pom.xml文件获取到想要的jar的,具体后面会详细讲解该配置文件。 为什么通过groupId、artifactId、version三个属性就能定位一个jar包? 加入上面的pom.xml文件属于A项目,那么A项目肯定是一个maven项目,通过上面这三个属性能够找到junit对应版本的jar包,那么junit项目肯定也是一个maven项目,junit的maven项目中的pom.xml文件就会有三个标识符,比如像下图这样,然后别的maven项目就能通过这三个属性来找到junit项目的jar包了。所以,在每个创建的maven项目时都会要求写上这三个属性值的。 1.maven下载与安装与配置在最新的Eclipse中自带了maven,我们打开,Windows->Preferences,如果会出现下面的画面: 值得注意的是Embedded内置的默认maven版本是我们即将要修改的,应为这个版本有点老了,这直接导致的后果就是在添加dependences的时候,maven的库不是最新的。 1.1下载去maven的官网下载最新版的maven,此时的最新版本为3.5.2,下载地址如下:http://www-eu.apache.org/dist/maven/maven-3/3.5.2/binaries/apache-maven-3.5.2-bin.zip。 解压到本地,安装Maven前,先确保已安装JDK,CMD下输入java -version验证是否已安装JDK,如下为我本机的JDK版本: 1.2安装解压到本地目录,比如我的环境中,在本地目录C:\\Program Files\\Java\\apache-maven-3.5.2中. 1.3配置环境变量在下面配置一下C:\\Program Files\\Java\\apache-maven-3.5.2\\conf目录中的settings.xml文件,更改一下如下配置: 12345<!-- localRepository | The path to the local repository maven will use to store artifacts. | | Default: ${user.home}/.m2/repository --> <localRepository>C:\\Program Files\\Java\\apache-maven-3.5.2\\m2\\repository</localRepository> 如果不改的话就在用户目录。 还有个问题,可能有人说需不需要设置maven的环境变量,可以设置,但是如果只是使用Eclipse的maven的插件而不需要使用命令行,就不用了。反正我有设置。 设置环境变量: MAVEN_HOME变量设置为C:\\Program Files\\Java\\apache-maven-3.5.2,即下载下来的maven包解压路径; 另外在PATH变量前面增加%MAVEN_HOME%\\bin; 最后检验配置是否成功:用win键+R,来打开命令行提示符窗口,即Dos界面,输入mvn –version 若出现以下情况说明配置成功 2.在eclipse中配置2.1 m2eclipse安装我本机使用的Eclipse版本已经集成m2eclipse,如果没有集成的话,安装也很简单,有两种方式, 从Eclipse Marketplace上获取m2eclipse并安装: 首先要在Eclipse中安装插件:在Help–>install new software,输入下面地址http://download.eclipse.org/technology/m2e/releases,出现如下页面:![image](http://images.cnitblog.com/i/255323/201404/041546144066670.jpg)然后就像安装其他插件那样一路下一步就OK了。 这个就是eclipse管理maven的插件。 2.2配置eclipse安装好m2eclipse后,一般不使用eclipse自带的maven,而是使用外部我们自己安装的maven版本, 因为Embedded内置的默认maven版本是我们即将要修改的,这个版本有点老了,这直接导致的后果就是在添加dependences的时候,maven的库不是最新的。 操作:在eclipse上只需作如下配置即可,如下图 然后设置用户settings,这是maven下载库的地址。如下图: 3创建一个maven项目在实际操作中学习maven及其命令操作。 1在创建向导中多了maven的相关选项: 2 选择默认的工程位置 3 创建工程,红色是创建普通的maven工程的。粉色是创建web工程的。 4 填写相关的groupId artifactId version等信息 点击完成就创建好了一个简单的maven工程。 3.1项目的结构maven的工程一般都是如下的结构: pom.xml:用于定义或者添加jar包的依赖 src-main:用于存放java源文件 src-test:用于存放测试用例。 也许工程下还会出现target文件夹,这个是用来生成对应的class文件或发布的jar包。 3.2Eclipse中maven常用的命Eclipse中maven常用的命令, 点击Run As就可以发现几个Maven的命令: Maven Build: 这个命令用于编译Maven工程,执行命令后会在target文件夹中的classes中生成对应的class文件。 使用Build的时候,会让你选此次build的目标goal,下附主要的goal选项:(左边这列是步骤名,同时也是phase的名字,右边是对应的goal): 步骤名 对应的goal process-resources resources:resources compile compiler:compile process-test-resources resources:testResources test-compile compiler:testCompile test surefire:test package jar:jar Maven Clean: 删除target文件夹,即删除生成的package包以及class等文件。 Maven Test: 先自动进行编译,在运行所有的测试用例。 Maven install: 发布生成对应的package包。 注意: 留意上面的命令的作用,build和test都会生成相应的class文件。也就是说,当你新建一个maven工程,或者clean一个maven工程后,如果没有使用这两个命令,直接针对类进行测试,会跑出java.class.notfound的错误。因为此时还没有编译生成class文件,如果有朋友发现这个问题注意一下就好了。(该部分只针对旧版本,新版本如maven3.3是可以自动编译的) 只有使用了上面的两个命令后,才能针对某个类进行单元测试。 3.3使用maven命令现在eclipse可以使用自带的run as来进行maven但是对于linux来说还是命令好用,下面通过一个例子演示maven命令的使用。1234567891011 编译:mvn compile --src/main/java目录java源码编译生成class (target目录下)测试:mvn test --src/test/java 目录编译清理:mvn clean --删除target目录,也就是将class文件等删除打包:mvn package --生成压缩文件:java项目#jar包;web项目#war包,也是放在target目录下安装:mvn install --将压缩文件(jar或者war)上传到本地仓库部署|发布:mvn deploy --将压缩文件上传私服 下面我们看项目代码: 一个简单的类com.liuyan.maven.helloword.HelloWorld123456789101112131415package com.liuyan.maven.helloword;public class HelloWorld { public String sayHello() { return "hello maven"; } /** * @param args */ public static void main(String[] args) { System.out.println(new HelloWorld().sayHello()); }} 在此项目的根目录下有一个pom.xml文件,内容是默认的,暂时不用管。 进入控制台,将当前目录cd到与pom.xml同级的文件夹下面(或者使用shift进入)。执行编译命令:1mvn clean compile 执行后造成的结果。就是项目的根路径下出现了一个taget文件夹 里面就是编译后的class类。经理过来说,你需要进行单元测试才能发布出来给大家用。Ok,我们在源码包——src/test/java下面开始编写junit单元测试类。 单元测试代码如下1234567891011121314package com.liuyan.maven.helloword;import org.junit.Test;import org.junit.Assert;public class TestHelloWorld { @Test public void testSayHello() { HelloWorld helloWorld = new HelloWorld(); Assert.assertEquals(helloWorld.sayHello(), "hello maven"); }} 之后我们因为使用了junit单元测试,那么就是说我们这个项目依赖了它。修改一下pom.xml文件内容,如下123456789101112131415<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.liuyan.maven</groupId> <artifactId>MavenDemo</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> </dependencies></project> 进入命令行,执行命令1mvn clean test 执行后观察一下taget文件夹如下图,多出了test-classes文件夹和另外2个咱们暂时不用去管的文件夹。 之后在观察一下本地的临时仓库C:\\Users\\liuyan.m2\\repository,会多出文件夹junit,下载的版本是4.7。 如果我们想把项目打成jar的形式输出出去呢?在项目根目录下执行1mvn clean package 执行后效果如下 生成了一个jar包,至于SNAPSHOT是快照的意思,快照就是项目暂时还不稳定的意思。 打包测试后没问题了,想把此项目当做Maven的本地资源仓库,为其他的项目也能提供服务,可以这么做。 执行命令1mvn clean install 执行后本地的临时库文件多了你自己的这个项目。这样别的项目需要你这个项目提供服务的时候就可以从本地Mavne库中提取相应的jar了。","link":"/2017/12/27/eclipse使用maven教程/"},{"title":"coursera-斯坦福-机器学习-吴恩达-第8周笔记-无监督学习","text":"对于无监督学习我们主要学习两种算法:聚类(K-means)和维度约简(PCA法)。 1聚类算法clutering1.1聚类算法简介无监督学习:我们面对的是一组无标记的训练数据, 数据之间, 不具任何相关联的标记。如图: 我们得到的数据 看起来像这样:一个数据集, 一堆数据点,但没有任何标记以供参考。所以从训练数据中, 我们只能看到 x 1、 x 2… 等等… 到 x(m) 没有任何标记 y 供参考。 就此数据而言, 其中一种可能的结构 是 所有的数据 可以大致地划分成 两个类或组。 因此,像我介绍的 这种划分组的算法, 称为聚类算法。 这是我们第一种 无监督学习算法。 记住,聚类算法clutering只是无监督学习的一种,不是所有的无监督学习都是聚类算法 1.2K-meansK-means也是聚类算法中最简单的一种。但是里面包含的思想却是不一般。 K-means算法是将样本聚类成k个簇(cluster),具体算法描述如下: 随机选取k个聚类质心点(cluster centroids)为。 重复下面过程直到收敛 { 对于每一个样例i,计算其应该属于的类 对于每一个类j,重新计算该类的质心 } 下图展示了对n个样本点进行K-means聚类的效果,这里k取2。 一个练习题: 1.2.1kmeans的目标函数在大多数我们已经学到的 监督学习算法中。 算法都有一个优化目标函数 或者某个代价函数(又叫:畸变函数)需要通过算法进行最小化 。 事实上 K均值也有 一个优化目标函数或者 需要最小化的代价函数。 注意,这个值只会随着迭代下降,不会上升。 1.2.2随机初始化这一节我们讨论: 如何避开局部最优来构建K均值聚类方法 。 有几种不同的方法 可以用来随机 初始化聚类中心 ,但是 事实证明, 有一种方法比其他 大多数方法 更加被推荐。 可以避免 可能局部,获得全局最优的结果 。 1.2.3选择类别数讨论一下 K-均值聚类的最后一个细节 :我想选择聚类数目的更好方法。 或者说是如何去选择 参数大写K的值 。 说实话 这个问题上没有一个 非常标准的解答 、或者能自动解决它的方法。 目前用来决定聚类数目的 最常用的方法 ,仍然是通过看可视化的图, 或者看聚类算法的输出结果 ,或者其他一些东西来手动地决定聚类的数目。 两种常见方法: 肘部法则 例如下面的例子,分别考虑3和5,画出loss图像。 从后续需求(生意)角度考虑 下面有个练习题: 1.3考试quiz For which of the following tasks might K-means clustering be a suitable algorithm? Select all that apply.答案ad From the user usage patterns on a website, figure out what different groups of users exist. Given historical weather records, predict if tomorrow’s weather will be sunny or rainy. Given many emails, you want to determine if they are Spam or Non-Spam emails. Given a set of news articles from many different news websites, find out what are the main topics covered. 第二题: K-means is an iterative algorithm, and two of the following steps are repeatedly carried out in its inner-loop. Which two? K-means是一种迭代算法,以下两个步骤在其内部循环中重复执行。哪两个? The cluster assignment step, where the parameters c(i) are updated. Move the cluster centroids, where the centroids μk are updated. Suppose you have an unlabeled dataset {x(1),…,x(m)}. You run K-means with 50 different random initializations, and obtain 50 different clusterings of the data. What is the recommended way for choosing which one of these 50 clusterings to use?答案C Plot the data and the cluster centroids, and pick the clustering that gives the most “coherent” cluster centroids. Manually examine the clusterings, and pick the best one. Compute the distortion function J(c(1),…,c(m),μ1,…,μk), and pick the one that minimizes this. Use the elbow method. 第 5 个问题 Which of the following statements are true? Select all that apply.答案BC Since K-Means is an unsupervised learning algorithm, it cannot overfit the data, and thus it is always better to have as large a number of clusters as is computationally feasible. If we are worried about K-means getting stuck in bad local optima, one way to ameliorate (reduce) this problem is if we try using multiple random initializations.- For some datasets, the “right” or “correct” value of K (the number of clusters) can be ambiguous, and hard even for a human expert looking carefully at the data to decide. The standard way of initializing K-means is setting μ1=⋯=μk to be equal to a vector of zeros. 2 维数约减 (dimensionality reduction)这节开始介绍 第二种无监督学习问题 它叫维数约减 (dimensionality reduction) 。 我们希望使用维数约简 的原因有以下几个 : 一个原因是数据压缩。数据压缩不仅通过 压缩数据使得数据 占用更少的计算机 内存和硬盘空间, 它还能给算法提速 它还能给算法提速 。 另一个原因就是可视化。通过降维进行可视化,进而更好地理解数据。 2.1数据压缩在实际工作中,数据的维度通常是很大的(100+)。那么数据维度约简(data dimensionality reduction)是很有必要的。 举一个例子:3维降成2维: 2.2数据可视化比如这个国家GDP的数据,数据有50维。不能画出来,但是个以用两个维度大体上表示出来。比如这样:横轴可以表示国家面积,国家总GDP等,纵轴可以表示人均GDP,幸福度等等。 那么怎么找出这种可以很好表示其他特征的特征呢?下面一节介绍这个算法PCA(主成分分析法)。 3维度约简-主成分分析法PCA对于降维问题来说 目前 最流行 最常用的算法是 主成分分析法 (Principal Componet Analysis, PCA) 3.1 PCA是做什么的PCA是寻找到一个低维的平面 对数据进行投影 ,以便 最小化投影误差的平方( 最小化每个点 与投影后的对应点之间的距离的平方值 )。 定义:想把数据从n维降到k维(k < n),就在这个空间里面找k个单位向量来表示数据,使得数据点投影到这个面上的误差最小。如下例子:2到1 和 3到2 下面介绍 线性回归与2维PCA的区别:虽然都是找一条直线去拟合但是, 计算loss的方式不同(垂直)。 PCA没有标签Y(非监督)。 3.2PCA的计算过程❤❤❤设有m条n维数据。将原始数据按列组成n行m列矩阵X 将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值 求出协方差矩阵 求出协方差矩阵的特征值及对应的特征向量(使用svd函数)。(特征向量最能代表原数据) 将特征向量按对应特征值大小从上到下按行排列成矩阵,取前k行组成矩阵$U_r$。(找k个最能代表原数据的向量) $Y=U^T \\times X$即为降维到k维后的数据 例子如下: 假设我们得到的2维数据如下: 行代表了样例,列代表特征,这里有10个样例,每个样例两个特征。可以这样认为,有10篇文档,x是10篇文档中“learn”出现的TF-IDF,y是10篇文档中“study”出现的TF-IDF。也可以认为有10辆汽车,x是千米/小时的速度,y是英里/小时的速度,等等。 第一步均值归一化 分别求x和y的平均值,然后对于所有的样例,都减去对应的均值。这里x的均值是1.81,y的均值是1.91,那么一个样例减去均值后即为(0.69,0.49),得到 计算协方差矩阵 求特征协方差矩阵,如果数据是3维,那么协方差矩阵是 这里只有x和y(两维),求解得 对角线上分别是x和y的方差,非对角线上是协方差。协方差大于0表示x和y若有一个增,另一个也增;小于0表示一个增,一个减;协方差为0时,两者独立。协方差绝对值越大,两者对彼此的影响越大,反之越小。 求协方差的特征值和特征向量,得到 上面是两个特征值,下面是对应的特征向量,特征值0.0490833989对应特征向量为。。。,这里的特征向量都归一化为单位向量。 取前k个最有代表意义的特征向量: 将特征值按照从大到小的顺序排序,选择其中最大的k个,然后将其对应的k个特征向量分别作为列向量组成特征向量矩阵。 这里特征值只有两个,我们选择其中最大的那个,这里是1.28402771,对应的特征向量是 ( 0.677873399,0.735178656) 得到最后的数据 将样本点投影到选取的特征向量上。假设样例数为m,特征数为n,减去均值后的样本矩阵为DataAdjust(m n),协方差矩阵是n n,选取的k个特征向量组成的矩阵为EigenVectors(n * k)。那么投影后的数据FinalData为 (0.677873399,0.735178656)T 这样,就将原始样例的 n 维特征变成了 k 维,这 k 维就是原始特征在 k 维上的投影。 4应用PCA4.1PCA反向压缩既然PCA可以将高维数据压缩到低维,那么反着使用PCA则可以将低维数据恢复到高维。 因为$Y=U^T \\times X$,所以换算一下$ U\\times Y= X$这里的X只是近似值。 那么当n和k相同的时候会发生什么呢?看下题: U的维度为方阵 反着求x,为原值 保存率为100% 4.2怎么选择维度k在 PCA 算法中 我们把n维特征变量 降维到k维特征变量 。这个数字k也被称作 主成分的数量 或者说是我们保留的主成分的数量 。在这个视频中 我会给你们一些参考 告诉你们 人们是怎样思考如何选择 PCA 的参数k的 。 我们先来思考两个值: 第一个是:PCA 所做的是 尽量最小化 平均平方映射误差 (Average Squared Projection Error) 。 第二个是:我还要定义一下 数据的总变差 (Total Variation) 。 它的意思是 “平均来看 我的训练样本 距离零向量多远? 我们把两个数的比值作为衡量PCA算法的有效性,比如 所以一个比较好的办法是:定义一个阈值,然后实验k,看看那个最小的k合适。计算步骤如下: 这里有个技巧:svd函数会返回一个对角矩阵S,他的元素可以很快的计算这个阈值。 4.3使用PCA的场景主成份分析法主要有以下用途: 数据压缩 减少内存的占用、存储硬盘 加速算法的运转 数据可视化:3维2维 有些人觉的PCA也可以用来防止过拟合,但是这是不对的。应该用正则化。正则化使用y标签最小化损失函数,使用了y标签信息。而PCA只单纯的看x的分部就删除了一些特征,损失率很多信息。 总结一下PCA的用法: 5总复习quiz与编程5.1quiz主成份分析: 第 1 个问题Consider the following 2D dataset:Which of the following figures correspond to possible values that PCA may return for u(1) (the first eigenvector / first principal component)? Check all that apply (you may have to check more than one figure).答案AB Which of the following is a reasonable way to select the number of principal components k? (Recall that n is the dimensionality of the input data and m is the number of input examples.)答案:C C. Choose k to be the smallest value so that at least 99% of the variance is retained. Suppose someone tells you that they ran PCA in such a way that “95% of the variance was retained.” What is an equivalent statement to this?答案:C $\\frac{ \\frac{1}{m} \\sum{i=1}^m ||x^{(i)}- x^{(i)}{approx}||^2}{\\frac{1}{m} \\sum_{i=1}^m ||x^{(i)}||^2} \\leq 0.05$ 第 4 个问题Which of the following statements are true? Check all that apply. [ ] Even if all the input features are on very similar scales, we should still perform mean normalization (so that each feature has zero mean) before running PCA. [ ] Given input data x∈Rn, it makes sense to run PCA only with values of k that satisfy k≤n. (In particular, running it with k=n is possible but not helpful, and k>n does not make sense.) 第 5 个问题Which of the following are recommended applications of PCA? Select all that apply.答案AC Data compression: Reduce the dimension of your data, so that it takes up less memory / disk space. Data compression: Reduce the dimension of your input data x(i), which will be used in a supervised learning algorithm (i.e., use PCA so that your supervised learning algorithm runs faster). 5.2编程题在本练习中,您将实现K均值聚类算法并将其应用于压缩图像。 在第二部分中,您将使用主成分分析来查找面部图像的低维表示。 1 K-means clustering先从二维的点开始,使用K-means进行分类。 1.1 Implement K-means K-means步骤如上,在每次循环中,先对所有点更新分类,再更新每一类的中心坐标。 1.1.1 Finding closest centroids 对每个example,根据公式: 找到距离它最近的centroid,并标记。若有数个距离相同且均为最近,任取一个即可。 打开findClosestCentroids.m代码如下:1234567891011for i=1:size(X,1) adj=sqrt((X(i,:)-centroids(1,:))*(X(i,:)-centroids(1,:))'); idx(i)=1; for j=2:K temp=sqrt((X(i,:)-centroids(j,:))*(X(i,:)-centroids(j,:))'); if(temp<adj) idx(i)=j; adj=temp; end end end 1.1.2 Compute centroid means 对每个centroid,根据公式:求出该类所有点的平均值(即中心点)进行更新。 打开computeCentroids.m写入:1234567for i=1:K if(size(find(idx==i),2)~=0) centroids(i,:)=mean(X(find(idx==i),:)); else centroids(i,:)=zeros(1,n); end end 1.2 K-means on example dataset ex7.m中提供了一个例子,其中中 K 已经被手动初始化过了。 我们要把点分成三类,迭代次数为10次。三类的中心点初始化为(3,3),(6,2),(8,5).得到如下图像。(中间的图像略去,只展示开始和完成时的图像)这是初始图像: 进行10次迭代后的图像:可以看到三堆点被很好地分成了三类。图片上同时也展示了中心点的移动轨迹。 1.3 Random initialization ex7.m中为了方便检验结果正确性,给定了K的初始化。而实际应用中,我们需要随机初始化。kMeansInitCentroids.m 完成如下代码:123randidx = randperm(size(X, 1));% Take the first K examples as centroidscentroids = X(randidx(1:K), :); 1.4 Image compression with K-means 用K-means进行图片压缩。用一张128\\times 128的图片为例,采用RGB,总共需要128\\times 128 \\times 24 = 393216个bit。这里我们对他进行压缩,把所有颜色分成16类,以其centroid对应的颜色代替整个一类中的颜色,可以将空间压缩至16\\times 24 + 128\\times 128 \\times 4 = 65920 个bit。用题目中提供的例子,效果大概如下: 2主成分分析在这个练习中,您将使用主成分分析(PCA)来执行降维。 您将首先尝试使用示例2D数据集来直观了解PCA如何工作,然后将其用于5000张面部图像数据集的较大数据集。 所提供的脚本ex7 pca.m将帮助您逐步完成练习的前半部分。 先对例子中的二维向量实现降低到一维。绘制散点图如下: 2.2 Implementing PCA 首先需要计算数据的协方差矩阵(covariance matrix)。然后使用 Octave/MATLAB中的SVD函数计算特征向量(eigenvector)。 可以先对数据进行normalization和feature scaling的处理。协方差矩阵如下计算: 然后用SVD函数求特征向量。故完成pca.m如下:1[U,S,V] = svd(1/m * X' * X); 把求出的特征向量绘制在图上: 2.3 Dimensionality reduction with PCA 将高维的examples投影到低维上。 2.3.1 Projecting the data onto the principal components 完成projectData.m如下:12Ureduce = U(:,1:K);Z = X * Ureduce; 2.3.2 Reconstructing an approximation of the data 从投影过的低维恢复高维recoverData.m:12Ureduce = U(:, 1:K);X_rec = Z * Ureduce'; 2.3.3 Visualizing the projections 根据上图可以看出,恢复后的图只保留了其中一个特征向量上的信息,而垂直方向的信息丢失了。 2.4 Face image dataset 对人脸图片进行dimension reduction。ex7faces.mat中存有大量人脸的灰度图(32 \\times 32) , 因此每一个向量的维数是 32 \\times 32 = 1024。如下是前一百张人脸图: 2.4.1 PCA on faces 用PCA得到其主成分,将其重新转化为 32\\times 32 的矩阵后,对其可视化,如下:(只展示前36个) 2.4.2 Dimensionality reduction 取前100个特征向量进行投影, 可以看出,降低维度后,人脸部的大致框架还保留着,但是失去了一些细节。这给我们的启发是,当我们在用神经网络训练人脸识别时,有时候可以用这种方式来提高速度。","link":"/2017/12/19/coursera-斯坦福-机器学习-吴恩达-第8周笔记-无监督学习/"},{"title":"eclipse的git插件安装、配置与使用","text":"1. eclipse的git插件安装与配置1.1 git插件安装新版本的eclipse已经自带了GIt了,就不用安装了。 老版本的eclipse安装Git,和安装一般插件过程一样: 点击help——Install new software 在弹出的框里面,输入git下载地址:http://download.eclipse.org/egit/updates/ 点击ok,如果没反应,请点击Add前面小三角,找到刚创建的以git为名字的项,稍等一会儿,出现这个框 name下面2项勾选起来,点击next,进入安装了。安装好后,会重启eclipse,安装完成 1.2 git插件卸载如果不想要git插件了,或者想重新安装,可以先卸载GIT: 在Eclipse中依次点击菜单”Help”->”About Eclipse”。弹出图1所示对话框,点击”Installation Details”按钮,弹出图2所示对话框。选中要卸载的插件(按住Ctrl可多选),点击”Uninstall…”按钮。 Adt——about adt,如图 点击Installation Details 弹出下面框,在里面找到相应的插件进行卸载 选择好需要卸载的插件后,点击Uninstall,进行卸载。ctrl+鼠标左键可以多选哈 1.3 配置git插件安装好后,进行,一个简单配置,填入我们的用户名和邮箱 点击Preferences》Team》Git>Configuration 点击Add Entry,在弹出框里面输入key和value的值 名字的key :user.name ; value:是你的github用户名。 邮箱的key:user.email ; value:你的登陆GitHub邮箱账号. 以后你使用git提交代码时候,eclipse会自动提取这些信息,和代码一起发送到git远程仓库。 2. 从git云端下载项目到本地 创建github账户,并new一个新的库repository,点击clone ,记住克隆的地址(.git结尾的网址),如下图。(或者找到你想复制的别人的库,点击clone并记住库的克隆地址。) 从Eclipse中选择File-》import-》Git-》Projects from Git 选择next-》选择URI 选择next,粘贴如下信息(注意填上您在github上申请的账号密码): 选择next,进入分支选择,这里选择的是master 如果是大型项目,可能会有多个分支,选择master即可。 选择next,配置本地项目存放路径,一般是c:/你的userName/git 单击Finish,然后选择Import existing projects,然后再单击Finish即可在Eclipse中看到导入的项目了。(项目复制到了eclipse的工作空间中) 这里选择Import existing projects可能会出现一个问题:就==是系统提示.project文件已存在==。 解决办法:先后退一步;然后进入c:/你的userName/git下载的项目文件夹中,把原项目的.project文件删除(没关系,这个文件不重要),然后再点击Finish 3. 修改并提交自己的代码到云端上面把项目下载并导入到到了本地,自己肯定要修改一下,或者加上一些自己的代码。那么修改好之后怎么发布回GitHub云呢? 3.1 把修改好的文件上传到本地仓库即:把你在eclipse-workspace的项目,提交到C:/../Git/项目 中去。 点击项目右键>team>commit 在注释中输入提交信息:记录一下修改了哪些文件/为啥修改;方便以后查阅。 勾选你需要提交的文件(确定修改的文件),或者右边小勾,点击全选。 执行commit ,提交到本地仓库。这样你的修改就在本地仓库确认了。接下来我们把本地项目提交至远程远程仓库github上。 3.2 pull一下把本地项目提交至远程远程仓库github上之前,我们首先要pull一下,表示从云端拉取最新的版本。 防止在你修改的过程中,云端代码有变化(别人修改)。 1右键点击项目 -> team -> pull 3.3 提交代码到云端在本地修改好文件,并在本地仓库确认后,就可以把代码上传到云端。有两种办法: 3.3.1 简易方法:直接上传到master分支右键点击项目 -> team -> push Branch master next 最后点击finish即可。 3.3.2 或者上传分支 右键点击项目 -> team -> Remot->Push 进行如下设置: 最后点击finish 4. 小技巧4.1 如何恢复未提交的修改文件:有的时候,我修改了代码,但是觉得改的不好,想恢复原装,只需要Replace With–HEAD Revision (命令行为 git checkout head .): 4.2 查看提交记录Team–Show in History (命令行为:git log) 4.3 更新项目远程仓库:Team– Pull (命令行:git pull https://github.com/someone/xxx.git)","link":"/2018/01/25/eclipse的git插件安装、配置与使用/"},{"title":"Hello World","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new \"My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment","link":"/2015/01/11/hello-world/"},{"title":"linux ubuntu安装MAC主题","text":"离线进行linux安装MAC主题效果图: 1安装主题 yu 图标1.1安装 unity tweak tool在系统自带应用中心安装 unity tweak tool(主题管理工具) 1.2安装mac主题下载离线软件包http://pan.baidu.com/s/1eQnHx8u 包里的内容如下: 使用系统自带的软件中心安装,使用鼠标双击安装包即可。 12345先装mbuntu-y-ithemes-v4_3.12~utopic~NoobsLab.com_all.deb (这个是主题文件)再装mbuntu-y-icons-v4_3.12-b~utopic~NoobsLab.com_all.deb(这个是图标文件) 1.3 更换主题打开一开始下载的unity软件,首先更改主题: 再更改图标: 低配版搞定了~ 2更换桌面在一开始下载的离线包里 有一个MBuntu-Wallpaper 解压之后右键点击桌面->修改背景图片->选择下载的背景 3安装dockydocky是最装逼的,没有docky,根本不像mac双击 安装1docky_2.2.1~bzr1855-0ubuntu1~14.10~dockycore1_all.deb 设置开机自动启动,重启电脑。开始装","link":"/2017/08/23/linux ubuntu安装MAC主题/"},{"title":"linux常用指令-整理(不断完善)","text":"常用指令1操作文件的指令123456789101112131415touch 创建空文件echo 创建带有内容的文件。cat 查看文件内容cp 拷贝mv 移动或重命名rm 删除文件 -r 递归删除,可删除子目录及文件 -f 强制删除find 在文件系统中搜索某文件wc 统计文本中行数、字数、字符数grep 在文本文件中查找某个字符串ln 创建链接文件more、less 分页显示文本文件内容head、tail 显示文件头、尾内容ctrl+alt+F1 命令行全屏模式 2文件夹指令12345678910cd 切换目录 ls 显示文件或目录 -l 列出文件详细信息l(list) -a 列出当前目录下所有文件及目录,包括隐藏的a(all)mkdir 创建目录 -p 创建目录,若无父目录,则创建p(parent) rmdir 删除空目录 rm -r 删除该目录(包括里面的东西)tree 树形结构显示目录,需要安装tree包pwd 显示当前目录 3打包压缩相关命令1234567tar: 打包压缩 -c 归档文件 -x 解压缩文件 -z gzip压缩文件 -j bzip2压缩文件 -v 显示压缩或解压缩过程 v(view) -f 使用档名 例:123456789101112tar -cvf /home/abc.tar /home/abc 只打包,不压缩tar -zcvf /home/abc.tar.gz /home/abc 打包,并用gzip压缩!tar -jcvf /home/abc.tar.bz2 /home/abc 打包,并用bzip2压缩这三个命令:/home/abc.tar指的是你压缩好之后的文件放在哪里;abc.tar就默认当前路径。/home/abc 指的是 你要压缩的文件夹是哪个,注意我上次写home,结果把整个home给压缩了,所以一定要写好文件名,可以不写绝对路径,但是最后你想压缩的文件夹名abc一定要写上。 当然,如果想解压缩,就直接替换上面的命令tar -cvf / tar -zcvf / tar -jcvf 中的“c” 换成“x” 就可以了。常见解压:tar -zxvf /home/abc.tar.gz /home/abc 4关机/重启机器123456shutdown -r 关机重启 -h 关机不重启 now 立刻关机halt 关机reboot 重启 5Linux软件包管理5.1离线dpkg (Debian Package)管理工具,软件包名以.deb后缀。这种方法适合系统不能联网的情况下。 比如安装tree命令的安装包,先将tree.deb传到Linux系统中。再使用如下命令安装。 12sudo dpkg -i tree_1.5.3-1_i386.deb 安装软件sudo dpkg -r tree 卸载软件 5.2在线APT(Advanced Packaging Tool)高级软件工具。这种方法适合系统能够连接互联网的情况。1234sudo apt-get install tree 安装treesudo apt-get remove tree 卸载tree (sudo apt-get remove --purge tree 干净的卸载tree)sudo apt-get update 更新软件sudo apt-get upgrade 5.3 .sh有些时候,下载的包是.sh结尾的,直接bash安装。 这是因为.sh是shell的文件格式,他把一些复杂的shell安装命令过程封装,我们只需要运行即可。这类软件一半卸载的时候,直接把安装包删除,然后再把path删除即可。 6vim使用vim三种模式:命令模式、插入模式、编辑模式。分别使用ESC或 i 或:来切换模式。命令模式下: 12345678:q 退出:q! 强制退出:wq 保存并退出:set number 显示行号:set nonumber 隐藏行号/apache 在文档中查找apache 按n跳到下一个,shift+n上一个yyp 复制光标所在行,并粘贴h(左移一个字符←)、j(下一行↓)、k(上一行↑)、l(右移一个字符→) 7用户及用户组管理1234567891011121314151617/etc/passwd 存储用户账号/etc/group 存储组账号/etc/shadow 存储用户账号的密码/etc/gshadow 存储用户组账号的密码useradd 添加用户名userdel 删除用户名adduser 添加用户名groupadd 添加组名groupdel 删除组名passwd root 给root设置密码su rootsu – root/etc/profile 系统环境变量bash_profile 用户环境变量.bashrc 用户环境变量su user 切换用户,加载配置文件.bashrcsu – user 切换用户,加载配置文件/etc/profile ,加载bash_profile 8更改文件的用户及用户组1sudo chown [-R] owner[:group] {File|Directory} 例如:还以jdk-7u21-linux-i586.tar.gz为例。属于用户hadoop,组hadoop要想切换此文件所属的用户及组。可以使用命令。1sudo chown root:root jdk-7u21-linux-i586.tar.gz 更改anaconda目录的用户为xqt(原来是root)否则会导致安装不上,权限不够。1sudo chown -R xqt:xqt anaconda3/ 9文件权限管理三种基本权限 1234R 读 数值表示为4W 写 数值表示为2X 可执行 数值表示为1所以权利全开是数字7 例如:jdk-7u21-linux-i586.tar.gz文件的权限为-rw-rw-r– 12345第一个字符“-”表示普通文件;这个位置还可能会出现“l”链接;“d”表示目录第二三四个字符“rw-”表示当前所属用户的权限。 所以用数值表示为4+2=6第五六七个字符“rw-”表示当前所属组的权限。 所以用数值表示为4+2=6第八九十个字符“r–”表示其他用户权限。 所以用数值表示为2所以操作此文件的权限用数值表示为662? 例如:有一个文件filename,权限为“-rw-r—-x” ,将权限值改为”-rwxrw-r-x”,用数值表示为765 123sudo chmod u+x g+w o+r filename或者sudo chmod 765 filename 10Linux管道将一个命令的标准输出作为另一个命令的标准输入。也就是把几个命令组合起来使用,后一个命令除以前一个命令的结果。 例:grep -r “close” /home/* | more 在home目录下所有文件中查找,包括close的文件,并分页输出。 11系统管理命令12345678910111213141516stat 显示指定文件的详细信息,比ls更详细who 显示在线登陆用户whoami 显示当前操作用户hostname 显示主机名uname 显示系统信息top 动态显示当前耗费资源最多进程信息ps 显示瞬间进程状态 ps -auxdu 查看目录大小 du -h /home带有单位显示目录信息df 查看磁盘大小 df -h 带有单位显示磁盘信息ifconfig 查看网络情况ping 测试网络连通netstat 显示网络状态信息man 命令不会用了,找男人? 如:man lsclear 清屏alias 对命令重命名 如:alias showmeit=”ps -aux” ,另外解除使用unaliax showmeitkill 杀死进程,可以先用ps 或 top命令查看进程的id,然后再用kill命令杀死进程。 学习中遇到什么再补充~","link":"/2017/08/23/linux常用指令-整理(不断完善)/"},{"title":"linux环境变量的设置+关于bashrc与profile的区别","text":"0. 简介1. linux关于bashrc与profile的区别bashrc与profile都用于保存用户的环境信息,bashrc用于交互式non-loginshell,而profile用于交互式login shell。系统中存在许多bashrc和profile文件,下面逐一介绍: /etc/profile 此文件为系统的每个用户设置环境信息,当第一个用户登录时,该文件被执行. /etc/ bashrc 每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取。有些linux版本中的/etc目录下已经没有了bashrc文件。 ~/.profile每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,它设置一些环境变量,然后执行用户的.bashrc文件. ~/.bashrc:该文件包含专用于某个用户的bash shell的bash信息,当该用户登录时以及每次打开新的shell时,该文件被读取. 另外,/etc/profile中设定的变量(全局)的可以作用于任何用户,而~/.bashrc等中设定的变量(局部)只能继承/etc/profile中的变量,他们是”父子”关系,平常设置的时候,也是用这两个。 总结 /etc/profile,/etc/bashrc 是系统全局环境变量设定~/.profile,~/.bashrc用户家目录下的私有环境变量设定 当登入系统时候获得一个shell进程时,其读取环境设定档有三步: 首先读入的是全局环境变量设定档/etc/profile,然后根据其内容读取额外的设定的文档,如/etc/profile.d和/etc/inputrc 然后根据不同使用者帐号,去其家目录读取~/.bash_profile,如果这读取不了就读取~/.bash_login,这个也读取不了才会读取~/.profile,这三个文档设定基本上是一样的, 读取有优先关系. 然后在根据用户帐号读取~/.bashrc 2. linux环境变量的设置linux环境变量平常设置的时候,通常用这两个:/etc/profile和~/.bashrc,以安装anaconda为例: 2.1 为当前用户 设置环境变量: 用vim命令修改 ~/.bashrc 文件 添加export PATH=/home/lishanliao/anaconda3/bin:$PATH 重新执行刚修改的初始化文档: source ~/.bashrc 注意这里有两点需要注意的 1.在步骤2中,$PATH之前的是冒号 ,而不是分号,这个是初学者挺容易犯的错误。如果换成分号的话就会出现我这样的错误。。。。。点击打开链接 2.在步骤2中不能写成export PATH=$PATH:/home/lishanliao/anaconda3/bin,因为这样的话虽然是把Anaconda的路径加了进去,在系统搜索命令时,是先搜索$PATH的路径,再搜索/home/lishanliao/anaconda3/bin这部分路径,如果在$PATH路径中有其他版本的python,那么就不会执行Anaconda了。 参考:https://blog.csdn.net/m0_37041325/article/details/77169972 2.2 为root用户修改环境变量1、在终端输入$sudo vim /etc/profile,打开profile文件。 2、在文件末尾添加一行:export PATH=/home/grant/anaconda2/bin:$PATH,其中,将“/home/grant/anaconda2/bin”替换为你实际的安装路径。保存。 注入环境变量,让其立即生效(重启也行,太麻烦): source /etc/profile","link":"/2019/05/03/linux环境变量的设置+关于bashrc与profile的区别/"},{"title":"linux的Anaconda环境下安装TensorFlow","text":"现在tensorflow全面支持python3.6了,哈哈,全面拥抱python3.6~ 下附官网安装方式参考:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/docs_src/install/install_linux.md#InstallingAnaconda 1. 建立专门的运行环境再安装可以专门建立一个tensorflow的运行环境,好处是:1.官网建议 2.不与其他文件混乱 (1)创建专门运行环境为Anaconda创建一个python3.5(或者3.6都行,随便)的环境,环境名称为tensorflow ,输入下面命令: 1conda create -n tensorflow (2)启动tensorflow的环境:1source activate tensorflow 注:当不使用tensorflow时,关闭tensorflow环境,命令为:1source deactivate tensorflow (3)安装cpu版本的TensorFlow1pip install --upgrade --ignore-installed tensorflow tfBinaryURL where tfBinaryURL is the URL of the TensorFlow Python package. For example, the following command installs the CPU-only version of TensorFlow for Python 3.6:1(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.3.0-cp36-cp36m-linux_x86_64.whl 我觉的,也可以不写后面的地址。 (4)测试是否安装完成1234import tensorflow as tfhello = tf.constant('Hello, TensorFlow!')sess = tf.Session()print(sess.run(hello)) 2. 直接在python3.6中安装(1)安装cpu版本的TensorFlow1sudo pip install --upgrade --ignore-installed tensorflow (2)测试是否安装完成1234import tensorflow as tfhello = tf.constant('Hello, TensorFlow!')sess = tf.Session()print(sess.run(hello)) 3 报错,权限不够因为anaconda安装的时候用户默认为root,所以装其他的撞不上。 更改anaconda目录的用户为xqt(原来是root)否则会导致安装不上,权限不够。1sudo chown -R xqt:xqt anaconda3/","link":"/2017/08/22/linux的Anaconda环境下安装TensorFlow/"},{"title":"list tuple dict set的对比","text":"[toc] 基本用法定义:list:链表,有序的项目, 通过索引进行查找,使用方括号”[]”;tuple:元组,元组将多样的对象集合到一起,不能修改,通过索引进行查找, 使用括号”()”;dict:字典,字典是一组键(key)和值(value)的组合,通过键(key)进行查找,没有顺序, 使用大括号”{}”;set:集合,无序,元素只出现一次, 自动去重,使用”set([])”应用场景:list, 简单的数据集合,可以使用索引;tuple, 把一些数据当做一个整体去使用,不能修改;dict,使用键值和值进行关联的数据;set,数据只出现一次,只关心数据是否出现, 不关心其位置; List 列表创建List:L = [‘Adam’, ‘Lisa’, ‘Bart’, ‘Gechong’, ‘Kongming’] 显示List:L[0] 遍历List:print (L)和for循环 更新List:append()和insert()和直接赋值 删除List:pop()和pop(n) List特点: 可以添加删除 123456Li = ['Adam', 'Lisa', 'Bart', 'Gechong', 'Kongming'] print (Li) for name in Li: print(name) Tuple 元组创建Tuple:Tu = (‘Adam’, ‘Lisa’, ‘Bart’, ‘Gechong’, ‘Kongming’) 显示Tuple:Tu[0] 遍历Tuple:print (Tu)和for循环 更新Tuple:不可以更新 删除Tuple:不可以删除 Tuple特点:不可以改变,如果创建之后一个元素的Tuple时,要加”,” 123456Tu = ('Adam', 'Lisa', 'Bart', 'Gechong', 'Kongming') print (Tu) for name in Tu: print(name) Dict字典创建Dict:Di = {‘Adam’:100, ‘Lisa’:90, ‘Bart’:93, ‘Gechong’:100, ‘Kongming’:100} 显示Dict:Di[‘Adam’]和Di.get(‘Adam’) 遍历Dict:print(Di)和for循环 1234Di = {'Adam':100, 'Lisa':90, 'Bart':93, 'Gechong':100, 'Kongming':100} for key in Di: print (key) 1234Di = {'Adam':100, 'Lisa':90, 'Bart':93, 'Gechong':100, 'Kongming':100} for key in Di: print (Di[key]) 更新Dict:对应位置赋值即可 删除Dict: Dict特点: 1:查找速度快 2:浪费空间 3:key不可以重复,且不可变 4:数据无序排放 set 集合创建set:s = set([‘Adam’, ‘Lisa’, ‘Bart’, ‘Gechong’, ‘Kongming’]) 显示set: 123456s = set(['Adam', 'Lisa', 'Bart', 'Gechong', 'Kongming']) if 'Test' in s: print ('Test')else: print ('No') 遍历set:print (s) 1234s = set(['Adam', 'Lisa', 'Bart', 'Gechong', 'Kongming']) for name in s: print (name) 更新set:s.add() 删除set:s.remove() 考虑性能Python中Set和List的性能差距能有数百倍如果有需要求(集合,列表等)的并集和交集的时候,最好使用Set。 set和lsit可以自由转换,在删除list中多个/海量重复元素时,可以先转换成set,然后再转回list并排序(set没有排序)。此种方法不仅方便且效率较高。","link":"/2017/03/08/list tuple dict set的对比/"},{"title":"myeclipes配置tomecat时,一点击就报错89","text":"myeclipes配置tomecat时,一点击就报错89 因为你没有注册 myeclipes! 真心的。","link":"/2015/03/27/myeclipes配置tomecat时,一点击就报错89/"},{"title":"pip离线下载&安装python包","text":"0 离线原因对于有些企业服务器是无法连接外网的,而安装一些python包所需依赖太多,如果无法在线安装会被依赖搞到死…,所以记录下离线安装python包的方法。 1.在可以上网的服务器下载所有的安装依赖包 我有一个虚拟机 可以使用以下命令安装: 1pip install jieba==0.38 --download ~/tmp/offline_packages 其中jieba==0.38指定 包和版本;~/tmp/offline_packages指定下载的路径(需要提前创建文件夹) 2.将下载好的Packages拷贝至内网服务器使用scp、sftp等方式将下载好的Packages拷贝至需要离线安装这些包的内网服务器。 3.安装Packages假设内网服务器的目录 /tmp/transferred_packages 包含你上一步远程拷贝过来packages,在内网服务器上执行如下命令 1pip install --no-index --find-links=file:~/download/my_pip_pakage SPARQLWrapper-1.8.4-py3-none-any.whl 其中--find-links=file:指定文件夹地址; SPARQLWrapper-1.8.4-py3-none-any.whl指定主安装包 这样就可以 安装所有下载好的包","link":"/2019/04/23/pip离线下载&安装python包/"},{"title":"pip错误:TypeError parse() got an unexpected keyword argument transport_encoding.md","text":"1环境Win10,ANACONDA3(64-bit),Python3.6.2。ANACONDA Prompt中不能用pip命令安装包,并且是在安装了TensorFlow后才发生的。TypeError: parse() got an unexpected keyword argument ‘transport_encoding’ 2错误信息报错如下: [html] view plain copyException:Traceback (most recent call last): File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\basecommand.py”, line 215, in main status = self.run(options, args) File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\commands\\install.py”, line 335, in run wb.build(autobuilding=True) File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\wheel.py”, line 749, in build self.requirement_set.prepare_files(self.finder) File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\req\\req_set.py”, line 380, in prepare_files ignore_dependencies=self.ignore_dependencies)) File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\req\\req_set.py”, line 554, in _prepare_file require_hashes File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\req\\req_install.py”, line 278, in populate_link self.link = finder.find_requirement(self, upgrade) File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\index.py”, line 465, in find_requirement all_candidates = self.find_all_candidates(req.name) File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\index.py”, line 423, in find_all_candidates for page in self._get_pages(url_locations, project_name): File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\index.py”, line 568, in _get_pages page = self._get_page(location) File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\index.py”, line 683, in _get_page return HTMLPage.get_page(link, session=self.session) File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\index.py”, line 811, in get_page inst = cls(resp.content, resp.url, resp.headers) File “C:\\ProgramData\\Anaconda3\\lib\\site-packages\\pip\\index.py”, line 731, in init namespaceHTMLElements=False,TypeError: parse() got an unexpected keyword argument ‘transport_encoding’ 3解决办法在cmd中输入: 1conda install pip 4报错原因pip命令在安装TensorFlow前是可以正常使用的,在安装后才出现的问题,大概原因就是Python的新版本与TensorFlow可能有点不太兼容,这样更新pip与conda命令,就可以fix了。","link":"/2018/01/03/pip错误:TypeError parse() got an unexpected keyword argument transport_encoding/"},{"title":"pycharm下打开执行并调试scrapy爬虫程序","text":"首先得有一个Scrapy项目,我在Desktop上新建一个Scrapy的项目叫test,在Desktop目录打开命令行,键入命令:scrapy startproject test1 目录结构如下: 打开Pycharm,选择open 选择项目,ok 打开如下界面之后,按alt + 1, 打开project 面板 在test1/spiders/,文件夹下,新建一个爬虫spider.py, 注意代码中的name=”dmoz”。这个名字后面会用到。 在test1目录和scrapy.cfg同级目录下面,新建一个begin.py文件(便于理解可以写成main.py),注意箭头2所指的名字和第5步中的name=’dmoz’ 名字是一样的。123from scrapy import cmdlinecmdline.execute("scrapy crawl dmoz".split()) 上面把文件搞定了,下面要配置一下pycharm了。点击Run->Edit Configurations 新建一个运行的python模块 Name:改成spider; script:选择刚才新建的那个begin.py文件;Working Direciton:改成自己的工作目录 至此,大功告成了,点击下图,右上角的按钮就能运行了。 调试可以在其他代码中设置断点,就可以debug运行 转载1:http://www.jianshu.com/p/f85120fcbca0 转载2:http://blog.csdn.net/wangsidadehao/article/details/52911746","link":"/2017/05/14/pycharm下打开执行并调试scrapy爬虫程序/"},{"title":"python-慕课网-Python开发简单爬虫-蚂蚁-读书笔记","text":"本文阅读并记录自己的学习笔记。感谢蚂蚁大神的分享。 主要目录: 爬虫基础 1.1 爬虫课程介绍 1.2 爬虫简介 1.3 爬虫架构 1.4 URL管理模块 1.5 网页下载器:urllib2 1.6 网页解析器:正则或BeautifulSoup 1.7 爬取实践 Scrapy框架的学习 2.1啊 爬虫的难点 有的网站需要登录 有些内容是JS的Ajax异步加载的。很难搞到数据。但是我们这门课是入门,所以只解决不需要登录的静态加载网页,上面2个问题以后专门去解决。 1 课程内容 爬虫简介 爬虫架构 URL管理器 网页下载器(urllib2) 网页解析器(BeautifulSoup) 实战 :爬去百度百科关于Python的页面。保存进一个html页面中。 爬虫简介爬虫比人工快多了。 爬虫价值过程:爬虫:抓取数据-存储数据-分析数据-产品(大数据) 应用:","link":"/2017/04/27/python-慕课网-Python开发简单爬虫-蚂蚁-读书笔记/"},{"title":"python替换同义词 jieba替换同义词","text":"python替换同义词 jieba替换同义词@[toc] 0 描述:在构建基于知识图谱的问答系统过程中,我们发现 知识图谱对于实体的识别是非常敏感的, 如果用户输入的关键词 不对(哪怕只差一个词) 知识图谱就找不到对应的三元组。 所以我们打算现将用户的输入做一个预处理 , 将一些同义词 手动 转化为 知识图谱的中标准输入。 1构建同义词文件txt 构建同义词文件tongyici_tihuan.txt,每一个同义词列为一行,每行第一个为希望分隔后呈现的词语,后几个为第一个词的同义词,用tab键分隔,比如: 12年休假 年假 年休北京 北平 首都 在这个例子里“北平 首都”都会被替换为 “北京” 2代码1234567891011121314151617181920212223242526272829303132333435# encoding=utf-8import jiebadef tihuan_tongyici(string1): # tongyici_tihuan.txt是同义词表,每行是一系列同义词,用tab分割 # 1读取同义词表:并生成一个字典。 combine_dict = {} for line in open(\"tongyici_tihuan.txt\", \"r\"): seperate_word = line.strip().split(\"\\t\") num = len(seperate_word) for i in range(1, num): combine_dict[seperate_word[i]] = seperate_word[0] # 2提升某些词的词频,使其能够被jieba识别出来 jieba.suggest_freq(\"年假\", tune = True) # 3将语句切分 seg_list = jieba.cut(string1, cut_all = False) f = \"/\".join(seg_list).encode(\"utf-8\") # 不用utf-8编码的话,就不能和tongyici文件里的词对应上 # print f # 4 final_sentence = \"\" for word in f.split(\"/\"): if word in combine_dict: word = combine_dict[word] final_sentence += word else: final_sentence += word # print final_sentence return final_sentencestring1 = '年假到底放几天?'print tihuan_tongyici(string1)","link":"/2019/03/26/python替换同义词 jieba替换同义词/"},{"title":"python结巴分词、jieba加载停用词表","text":"python结巴分词1 jieba中文分词简介中文分词是中文NLP的第一步,一个优秀的分词系统取决于足够的语料和完善的模型,很多机构和公司也都会开发和维护自己的分词系统。 这里推荐的是一款完全开源、简单易用的分词工具,jieba中文分词。官网在这里,https://github.com/fxsjy/jieba 里面提供了详细的说明文档。虽然jieba分词的性能并不是最优秀的,但它开源免费、使用简单、功能丰富,并且支持多种编程语言实现。 2 中文分词的原理中文分词的模型实现主要分类两大类:基于规则和基于统计。 2.1 基于规则基于规则是指根据一个已有的词典,采用前向最大匹配、后向最大匹配、双向最大匹配等人工设定的规则来进行分词。 例如对于“上海自来水来自海上”这句话,使用前向最大匹配,即从前向后扫描,使分出来的词存在于词典中并且尽可能长,则可以得到“上海/自来水/来自/海上”。这类方法思想简单且易于实现,对数据量的要求也不高。 当然,分词所使用的规则可以设计得更复杂,从而使分词效果更理想。但是由于中文博大精深、语法千变万化,很难设计足够全面而通用的规则,并且具体的上下文语境、词语之间的搭配组合也都会影响到最终的分词结果,这些挑战都使得基于规则的分词模型愈发力不从心。 2.2 基于统计基于统计是从大量人工标注语料中总结词的概率分布以及词之间的常用搭配,使用有监督学习训练分词模型。 对于“上海自来水来自海上”这句话,一个最简单的统计分词想法是,尝试所有可能的分词方案,因为任何两个字之间,要么需要切分,要么无需切分。 对于全部可能的分词方案,根据语料统计每种方案出现的概率,然后保留概率最大的一种。很显然,“上海/自来水/来自/海上”的出现概率比“上海自/来水/来自/海上”更高,因为“上海”和“自来水”在标注语料中出现的次数比“上海自”和“来水”更多。 2.3 jieba的原理jieba分词结合了基于规则和基于统计两类方法。 首先基于前缀词典进行词图扫描,前缀词典是指词典中的词按照前缀包含的顺序排列,例如词典中出现了“上”,之后以“上”开头的词都会出现在这一块,例如“上海”,进而会出现“上海市”,从而形成一种层级包含结构。 如果将词看作节点,词和词之间的分词符看作边,那么一种分词方案则对应着从第一个字到最后一个字的一条分词路径。因此,基于前缀词典可以快速构建包含全部可能分词结果的有向无环图,这个图中包含多条分词路径,有向是指全部的路径都始于第一个字、止于最后一个字,无环是指节点之间不构成闭环。 基于标注语料,使用动态规划的方法可以找出最大概率路径,并将其作为最终的分词结果。 3 安装结巴jieba以下我们使用Python中的jieba分词完成一些基础NLP任务,如果对jieba分词感兴趣,希望了解更多内容,可以参考官方使用文档。首先没有jieba分词的话需要安装,使用pip即可。 1pip install jieba 4 jieba三种分词模式以及其应用jieba提供了三种分词模式: 精确模式:试图将句子最精确地切开,适合文本分析;cut_all=True 全模式:把句子中所有可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;cut_all=False 搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。jieba.cut_for_search() 以下代码使用jieba实现中文分词,使用jieba.cut()函数并传入待分词的文本字符串即可,使用cut_all参数控制选择使用全模式还是精确模式,默认为精确模式。如果需要使用搜索引擎模式,使用jieba.cut_for_search()函数即可。运行以下代码之后,jieba首先会加载自带的前缀词典,然后完成相应的分词任务。 123456789101112131415import jiebaseg_list = jieba.cut(\"我来到北京清华大学\", cut_all=True)# join是split的逆操作# 即使用一个拼接符将一个列表拼成字符串print(\"/ \".join(seg_list)) # 全模式seg_list = jieba.cut(\"我来到北京清华大学\", cut_all=False)print(\"/ \".join(seg_list)) # 精确模式seg_list = jieba.cut(\"他来到了网易杭研大厦\") # 默认是精确模式print(\"/ \".join(seg_list))seg_list = jieba.cut_for_search(\"小明硕士毕业于中国科学院计算所,后在日本京都大学深造\") # 搜索引擎模式print(\"/ \".join(seg_list)) 结果: 1234我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学我/ 来到/ 北京/ 清华大学他/ 来到/ 了/ 网易/ 杭研/ 大厦小明/ 硕士/ 毕业/ 于/ 中国/ 科学/ 学院/ 科学院/ 中国科学院/ 计算/ 计算所/ ,/ 后/ 在/ 日本/ 京都/ 大学/ 日本京都大学/ 深造 5 jieba增强功能-加载自定义词典5.1 载入新自定义词典开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率 用法: jieba.load_userdict(file_name) # file_name 为文件类对象或自定义词典的路径 词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。 词频省略时使用自动计算的能保证分出该词的词频。 例如: 1234创新办 3 i云计算 5凱特琳 nz台中 用法示例:https://github.com/fxsjy/jieba/blob/master/test/test_userdict.py 123之前: 李小福 / 是 / 创新 / 办 / 主任 / 也 / 是 / 云 / 计算 / 方面 / 的 / 专家 /加载自定义词库后: 李小福 / 是 / 创新办 / 主任 / 也 / 是 / 云计算 / 方面 / 的 / 专家 / 5.2 载入停用词表主要思想是分词过后,遍历一下停用词表,去掉停用词。123456789101112131415161718192021222324252627282930import jieba # jieba.load_userdict('userdict.txt') # 创建停用词list def stopwordslist(filepath): stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()] return stopwords # 对句子进行分词 def seg_sentence(sentence): sentence_seged = jieba.cut(sentence.strip()) stopwords = stopwordslist('./test/stopwords.txt') # 这里加载停用词的路径 outstr = '' for word in sentence_seged: if word not in stopwords: if word != '\\t': outstr += word outstr += \" \" return outstr inputs = open('./test/input.txt', 'r', encoding='utf-8') outputs = open('./test/output.txt', 'w') for line in inputs: line_seg = seg_sentence(line) # 这里的返回值是字符串 outputs.write(line_seg + '\\n') outputs.close() inputs.close() 6 jieba分词的其他应用6.1 关键词提取jieba还实现了TF-IDF和TextRank这两种关键词提取算法,直接调用即可。 当然,提取关键词的前提是中文分词,所以这里也会使用到jieba自带的前缀词典和IDF权重词典。 12345678910111213141516171819202122import jieba.analyse# 字符串前面加u表示使用unicode编码content = u'中国特色社会主义是我们党领导的伟大事业,全面推进党的建设新的伟大工程,是这一伟大事业取得胜利的关键所在。党坚强有力,事业才能兴旺发达,国家才能繁荣稳定,人民才能幸福安康。党的十八大以来,我们党坚持党要管党、从严治党,凝心聚力、直击积弊、扶正祛邪,党的建设开创新局面,党风政风呈现新气象。习近平总书记围绕从严管党治党提出一系列新的重要思想,为全面推进党的建设新的伟大工程进一步指明了方向。'# 第一个参数:待提取关键词的文本# 第二个参数:返回关键词的数量,重要性从高到低排序# 第三个参数:是否同时返回每个关键词的权重# 第四个参数:词性过滤,为空表示不过滤,若提供则仅返回符合词性要求的关键词keywords = jieba.analyse.extract_tags(content, topK=20, withWeight=True, allowPOS=())# 访问提取结果for item in keywords: # 分别为关键词和相应的权重 print item[0], item[1]# 同样是四个参数,但allowPOS默认为('ns', 'n', 'vn', 'v')# 即仅提取地名、名词、动名词、动词keywords = jieba.analyse.textrank(content, topK=20, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v'))# 访问提取结果for item in keywords: # 分别为关键词和相应的权重 print item[0], item[1] 结果展示: 1234567891011121314151617181920才能 1.0管党 0.7999933934163805全面 0.7325692441985737社会主义 0.6327916888315029围绕 0.60594603358887总书记 0.5945625023471114凝心 0.5840883789052874政风 0.5792034335473362新气象 0.5772168490112909党风 0.5728262292165519呈现 0.5700456186486299推进 0.5548361394986431方向 0.5150324602730256指明 0.5113586590717408治党 0.5062232626208965局面 0.4744549207999055聚力 0.46596165707522896积弊 0.4646149902996275直击 0.46314922535402286国家 0.46179235227324805 6.2 词性标注jieba在进行中文分词的同时,还可以完成词性标注任务。根据分词结果中每个词的词性,可以初步实现命名实体识别,即将标注为nr的词视为人名,将标注为ns的词视为地名等。所有标点符号都会被标注为x,所以可以根据这个去除分词结果中的标点符号。 123456# 加载jieba.posseg并取个别名,方便调用import jieba.posseg as psegwords = pseg.cut("我爱北京天安门")for word, flag in words: # 格式化模版并传入参数 print('%s, %s' % (word, flag)) 结果展示: 1234我, r爱, v北京, ns天安门, ns 参考视频:全栈数据工程师养成攻略-18-结巴分词 7 用jieba分词实战(含文件的读取与存储)12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667# -*- coding: utf-8 -*-#本程序主要用于jieba分词,以及去除停用词import osimport jieba# 保存文件的函数def savefile(savepath,content): fp = open(savepath,'w',encoding='utf8',errors='ignore') fp.write(content) fp.close()# 读取文件的函数def readfile(path): fp = open(path, \"r\", encoding='utf8', errors='ignore') content = fp.read() fp.close() return content## 去除停用词的2个函数# 创建停用词listdef stopwordslist(filepath): stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()] return stopwords# 对句子去除停用词def movestopwords(sentence): stopwords = stopwordslist('语料/hlt_stop_words.txt') # 这里加载停用词的路径 outstr = '' for word in sentence: if word not in stopwords: if word != '\\t'and'\\n': outstr += word # outstr += \" \" return outstrcorpus_path = \"语料/train/\" # 未分词分类预料库路径seg_path = \"语料/train_seg/\" # 分词后分类语料库路径catelist = os.listdir(corpus_path) # 获取未分词目录下所有子目录for mydir in catelist: class_path = corpus_path + mydir + \"/\" # 拼出分类子目录的路径 seg_dir = seg_path + mydir + \"/\" # 拼出分词后预料分类目录 if not os.path.exists(seg_dir): # 是否存在,不存在则创建 os.makedirs(seg_dir) file_list = os.listdir(class_path) # 列举当前目录所有文件 for file_path in file_list: fullname = class_path + file_path # 路径+文件名 print(\"当前处理的文件是: \",fullname) # 语料/train/pos/pos1.txt # 语料/train/neg/neg1.txt content = readfile(fullname).strip() # 读取文件内容 content = content.replace(\"\\n\", \"\").strip() # 删除换行和多余的空格 content_seg = jieba.cut(content) # jieba分词 print(\"jieba分词后:\",content_seg) listcontent = '' for i in content_seg: listcontent += i listcontent += \" \" print(listcontent[0:10]) listcontent = movestopwords(listcontent) # 去除停用词 print(\"去除停用词后:\", listcontent[0:10]) listcontent = listcontent.replace(\" \", \" \").replace(\" \", \" \") savefile(seg_dir + file_path, \"\".join(listcontent)) # 保存 结果展示:12345分词前:和秦一对比就是弱爆了的技术分词后: 和 秦一 对比 就是 弱 爆 了 的 技术 , 都 有点去除停用词后:秦 弱 爆 技术 都 点 不好意思 出 口碑","link":"/2017/09/03/python结巴分词、jieba加载停用词表/"},{"title":"scrapy的内置服务介绍","text":"1 logging日志服务logging的等级: logging.CRITICAL - for critical errors (highest severity) logging.ERROR - for regular errors logging.WARNING - for warning messages logging.INFO - for informational messages logging.DEBUG - for debugging messages (lowest severity)基本使用方法 三种基本使用方法: 1234567891011121314# 1.简单使用import logginglogging.warning("this is a warning")# 2.通用的记录日志的方法,可加入日志的级别import logginglogging.log(logging.WARNING,"this is a warning")# 3.通过logger记录日志import logginglogger = logging.getLogger(__name__)logger.warning("this is a warning") 在scrapy中使用 在spider中直接使用 123456789import scrapyclass MySpider(scrapy.Spider): # 因为MySpider继承了scrapy.Spider,所以自带了logger name = 'myspider' start_urls = ['http://scrapinghub.com'] def parse(self, response): self.logger.info('Parse function called on %s', response.url) 可以自己改名字 123456789101112import loggingimport scrapylogger = logging.getLogger('mycustomlogger') # 给自己的logger取名字为mycustomloggerclass MySpider(scrapy.Spider): name = 'myspider' start_urls = ['http://scrapinghub.com'] def parse(self, response): logger.info('Parse function called on %s', response.url) 在settings.py中配置These settings can be used to configure the logging: LOG_FILE LOG_ENABLED LOG_ENCODING LOG_LEVEL LOG_FORMAT LOG_DATEFORMAT LOG_STDOUT stats collectionsScrapy提供了方便的收集数据的机制。数据以key/value方式存储,值大多是计数值。该机制叫做数据收集器(Stats Collector)。 通过 stats 属性来使用数据收集器。 下面是在扩展中使用状态的例子: 基本操作12345678class ExtensionThatAccessStats(object): def __init__(self, stats): self.stats = stats @classmethod def from_crawler(cls, crawler): return cls(crawler.stats) 设置数据: 1stats.set_value('hostname', socket.gethostname()) 增加数据值: 1stats.inc_value('pages_crawled') 当新的值比原来的值大时设置数据: 1stats.max_value('max_items_scraped', value) 当新的值比原来的值小时设置数据: 1stats.min_value('min_free_memory_percent', value) 获取数据: 12>>> stats.get_value('pages_crawled')8 获取所有数据: 12>>> stats.get_stats(){'pages_crawled': 1238, 'start_time': datetime.datetime(2009, 7, 14, 21, 47, 28, 977139)} 内置可用收集器12345# 记录内存的只能在linux中使用class scrapy.statscollectors.MemoryStatsCollector # 信息清道收集器class scrapy.statscollectors.DummyStatsCollector sending-email虽然Python通过 smtplib 库使得发送email变得很简单,Scrapy仍然提供了自己的实现。 该功能十分易用,同时由于采用了 Twisted非阻塞式(non-blocking)IO ,其避免了对爬虫的非阻塞式IO的影响。 另外,其也提供了简单的API来发送附件。 通过一些 settings 设置,您可以很简单的进行配置。 基本使用方法有两种方法可以创建邮件发送器(mail sender)。 您可以通过标准构造器(constructor)创建: 12from scrapy.mail import MailSendermailer = MailSender() 或者您可以传递一个Scrapy设置对象,其会参考 settings:1mailer = MailSender.from_settings(settings) 这是如何来发送邮件了(不包括附件): 1mailer.send(to=["[email protected]"], subject="Some subject", body="Some body", cc=["[email protected]"]) mailsender类初始化参数: 1class scrapy.mail.MailSender(smtphost=None, mailfrom=None, smtpuser=None, smtppass=None, smtpport=None) 参数: 1234567smtphost (str) – 发送email的SMTP主机(host)。如果忽略,则使用 MAIL_HOST 。mailfrom (str) – 用于发送email的地址(address)(填入 From:) 。 如果忽略,则使用 MAIL_FROM 。smtpuser – SMTP用户。如果忽略,则使用 MAIL_USER 。 如果未给定,则将不会进行SMTP认证(authentication)。smtppass (str) – SMTP认证的密码smtpport (int) – SMTP连接的短裤smtptls – 强制使用STARTTLSsmtpssl (boolean) – 强制使用SSL连接 123456classmethod from_settings(settings)使用Scrapy设置对象来初始化对象。其会参考 这些Scrapy设置.send(to, subject, body, cc=None, attachs=(), mimetype='text/plain')发送email到给定的接收者。 mail settings这些设置定义了 MailSender 构造器的默认值。其使得在您不编写任何一行代码的情况下,为您的项目配置实现email通知的功能。 123456789101112131415161718192021222324252627MAIL_FROM默认值: 'scrapy@localhost'用于发送email的地址(address)(填入 From:) 。MAIL_HOST默认值: 'localhost'发送email的SMTP主机(host)。MAIL_PORT默认值: 25发用邮件的SMTP端口。MAIL_USER默认值: NoneSMTP用户。如果未给定,则将不会进行SMTP认证(authentication)。MAIL_PASS默认值: None用于SMTP认证,与 MAIL_USER 配套的密码。MAIL_TLS默认值: False强制使用STARTTLS。STARTTLS能使得在已经存在的不安全连接上,通过使用SSL/TLS来实现安全连接。MAIL_SSL默认值: False强制使用SSL加密连接。","link":"/2017/05/19/scrapy的内置服务介绍/"},{"title":"scrapy的重要对象request和response","text":"scrapy的重要对象 web服务器收到客户端的HTTP请求,会针对每一次请求分别创建一个用于代表请求的request对象和代表响应的response对象。 要得到客户机提交过来的数据,只需要找request对象就行了。 要向客户机输出数据,只需要找response对象就行了。 1.requests1.1初始化的参数12345678910class scrapy.http.Request(url [ , callback, method='GET',headers, body,cookies, meta,encoding='utf-8', priority=0, don't_filter=False, errback ] ) 1.2属性12345678910111213141516url method headers body meta copy() 复制一个相同的request replace()### 1.3实例1,生成Request的方法 def parse_page1(self, response): return scrapy.Request(“http://www.example.com/some_page.html“, callback=self.parse_page2) def parse_page2(self, response): # this would log http://www.example.com/some_page.html self.logger.info("Visited %s", response.url) 12342,通过Request传递数据的方法在两个不同的解析函数之间传递数据的方法。 def parse_page1(self, response): item = MyItem() item[‘main_url’] = response.url request = scrapy.Request(“http://www.example.com/some_page.html“, callback=self.parse_page2) request.meta[‘item’] = item return request def parse_page2(self, response): item = response.meta[‘item’] item[‘other_url’] = response.url return item1234567891011 3 Request.meta中的特殊关键字 ### 1.4子类主要的子类是FormRequest。主要用来“登录”作用。所以非常重要。 1,新参数: formdata #用于存储用户名,密码等数据 2,新的类方法: from_reponse # 从一个reponse中生成一个request 1234#### 实例:使用FormRequest.from_response()方法模拟用户登录通常网站通过 <input type="hidden"> 实现对某些表单字段(如数据或是登录界面中的认证令牌等)的预填充。 使用Scrapy抓取网页时,如果想要预填充或重写像用户名、用户密码这些表单字段, 可以使用 FormRequest.from_response() 方法实现。下面是使用这种方法的爬虫例子: import scrapy class LoginSpider(scrapy.Spider): name = ‘example.com’ start_urls = [‘http://www.example.com/users/login.php‘] def parse(self, response): return scrapy.FormRequest.from_response( # 从respongse返回一个request(FormRequest) response, formdata={'username': 'john', 'password': 'secret'}, callback=self.after_login ) def after_login(self, response): # check login succeed before going on if "authentication failed" in response.body: self.logger.error("Login failed") return # continue scraping with authenticated session... 12345678## 2.responsesresponse是scrapy对request的相应,所以是自动产生。一般不用自己生成。### 2.1初始化的参数 class scrapy.http.Response( url [ , status=200, headers, body, flags ] ) 123### 2.2成员属性与方法 url status headers body request # 是产生该response的request meta # 是request.meta的简要形式 flags copy() replace() urljoin() # 经常用到!用相对连接生成绝对连接。 12### 2.3子类 class scrapy.http.TextResponse(url [ , encoding [ , … ]] ) class scrapy.http.HtmlResponse(url [ , … ] ) class scrapy.http.XmlResponse(url [ , … ] )``` 要搞懂的问题1,掌握Request初始化参数的意义,并学会使用;了解Request中的剩余属性和方法 2,掌握通过Request传递数据的方法; 3,掌握FormRequest的用法; 4,掌握Response中属性方法的意义 5,了解Response的子类都有那些,是干什么用的","link":"/2017/05/13/scrapy的重要对象request和response/"},{"title":"utf-8项目生成javadoc时:报错:编码GB:的不可映射字符","text":"utf-8项目生成javadoc时,报错: 编码GBK 的不可映射字符这是因为:由于JDK是国际版的,在编译的时候,如果我们没有用-encoding参数指定我们的Java源程序的编码格式,则javac.exe首先获得我们操作系统默认采用的编码格式, 也即在编译java程序时,若我们不指定源程序文件的编码格式,JDK首先获得操作系统的file.encoding参数(它保存的就是操作系统默认的编码格式,如WIN2k,它的值为GBK), 然后JDK就把我们的java源程序从file.encoding编码格式转化为JAVA内部默认的UNICODE格式放入内存中。然后,javac把转换后的unicode格式的文件进行编译成.class类文件, 此时.class文件是UNICODE编码的,它暂放在内存中,紧接着,JDK将此以UNICODE编码的编译后的class文件保存到我们的操作系统中形成我们见到的.class文件。 对我们来说,我们最终获得的.class文件是内容以UNICODE编码格式保存的类文件,它内部包含我们源程序中的中文字符串,只不过此时它己经由file.encoding格式转化为UNICODE格式了。 当我们不加设置就编译时,相当于使用了参数:javac -encoding gbk XX.java,当然就会出现不兼容的情况。 解决办法:打开eclipse,右键点击project -> Generate javadoc 一项一项的选你要输出javadoc的项目,最后一步中VM设置行中加入以下代码:1-encoding utf-8 -charset utf-8","link":"/2017/02/19/utf-8项目生成javadoc时:报错:编码GB:的不可映射字符/"},{"title":"人工智能工程师学习路线 自然语言处理算法工程师学习路径","text":"1入门级别1.1 数据结构1.2 算法(重点)面试必考。参考学习地址:麻省理工学院公开课:算法导论 http://open.163.com/special/opencourse/algorithms.html 1.3python包括python基础、面向对象要懂。 2进阶阶段2.1 机器学习算法 特征工程、特征分析 监督学习算法 非监督学习算法 参考学习地址: Coursera 斯坦福吴恩达课程❤❤❤ 能使用sklearn解决一些小的机器学习任务。 参考书本:《西瓜书》 2.2深度学习算法视频: Andrew Ng (吴恩达) 深度学习专项课程 by Coursera and deeplearning.ai❤❤❤ 或者Hinton 大神的coursera 面向机器学习的神经网络 Udacity 深度学习(中/英)by Google。你将通过项目和任务接触完整的机器学习系统 TensorFlow。 书:《AI圣经 深度学习》 2.3深度学习框架 keras tensorflow 掌握好编程的利器,参考视频资料: 斯坦福大学深度学习课程: CS 20SI: Tensorflow for Deep Learning Research。准确的说,这门课程主要是针对深度学习工具Tensorflow的❤❤❤ 2.4 大数据计算框架 hadoop spark因为深度学习工程师一般面对的是大数据,所以公司的分布式计算平台要熟悉会用。 3高阶3.1 强化学习理论与实践 3.2 迁移学习理论与实践 3.3自然语言处理 斯坦福课程深度学习应用课程。这门课程融合了两位授课者之前在斯坦福大学的授课课程,分别是自然语言处理课程 cs224n (Natural Language Processing)和面向自然语言处理的深度学习课程 cs224d( Deep Learning for Natural Language Processing). 牛津大学Deep Learning for Natural Language Processing: 2016-2017<深度NLP>http://study.163.com/course/introduction/1004336028.htm ❤❤❤","link":"/2018/01/08/人工智能工程师学习路线 自然语言处理算法工程师学习路径/"},{"title":"在Editplus中配置java的(带包)编译(javac)和运行(java)的方法","text":"首先打开Editplus,打开工具-配置自定义工具(或者使用快捷键Alt+G): 然后点击“组名”,将Group 1改为“Java编译与运行”: 然后点击“添加工具”-“程序”: 1添加编译功能 “菜单文字”里的内容修改为“JAVAC”; “命令”选择安装JDK后的BIN目录中的编译程序JAVAC.EXE,如果JDK 安装路径为“c:/jdk”,那么此路径为“c:/jdk/bin/javac.exe” (如果系统参数path已经设置,此处可以直接填写javac); “参数”选择“文件名称”,即显示为“(FileName)”;“初始目录”选择“文件目录”,显示为“(FileName)”; “初始目录”选择“文件目录”,显示为“(FileDir)”; 选择“捕获输出”复选框。(如果不选“捕获输出”复选框的话那么编译或者运行的时候都会自动弹出一个命令提示符),然后设置成如下: 2添加执行功能 “菜单文字”里的内容修改为“JAVA”; “命令”选择安装JDK后的BIN目录中的编译程序JAVA.EXE,路径为 “c:/jdk/bin/java.exe”(path已经设置的情况下,可以直接填写为java); “参数”选择“文件名(不含扩展名)”,即显示为 “(FileNameNoExt)”;“初始目录”选择“文件目录”,显示为“(FileNameNoExt)”; “初始目录”选择“文件目录”,显示为“(FileDir)”;选择“捕获输出”复选框。然后设置成如下: 这样就完成了基本的配置工作,下面您就可以试着编写一个JAVA程序来测试一下,编译的所有信息都会显示在输出窗口中,双击某一行错误信息,EditPlus会自动定位到出错行。 但是,完成了上面的设置之后,如果程序中包含package(包),则程序编译可以通过,但是运行时却出现错误,如果需要使用Editplus来编译执行包含package的程序,则还需要进行如下的设置:3添加编译带包Java程序功能“菜单文字”里的内容修改为“JAVAC package”; “命令”填写为:javac –d .; “参数”选择“文件名称”,即显示为“(FileName)”;“初始目录”选择“文件目录”,显示为“(FileName)”; “初始目录”选择“文件目录”,显示为“(FileDir)”; 选择“捕获输出”复选框。需要注意的是,在-d后面要空一格再添加.。然后设置成如下: 4 添加执行带包Java程序功能“菜单文字”里的内容修改为“JAVA”; “命令”填写为:java; “参数”选择“当前选中内容”,加一个.后再选择“主文件名(不含扩展名)”,即显示为“(CurSel).(CurSel).(FileNameNoExt)”; “初始目录”选择“文件目录”,显示为“$(FileDir)”; 选择“捕获输出”复选框。完成上面的设置,Editplus就可以编译执行带package的Java程序了,但是需要注意的一点是,在编译完程序后,如果程序是带包的,需要先将包名选中,然后在执行“java package”命令。然后设置成如下: 这个时候配置就全部完成了,打开工具可以看见有四个快捷方式已经出现在最下面了,并且快捷键依次为ctrl+1,ctrl+2,ctrl+3,ctrl+4: 下面测试一下,编写一个带包的java程序并且保存在任意一个位置,然后编译(这里两个编译不管java源文件有没有包名都可以用,但是注意编译分别有两个:ctrl+1和ctrl+3,ctrl+1编译之后就会在当前目录生成一个类文件,而ctrl+3编译之后会根据包名自动生成对应的文件夹,并在文件夹的最里层生成一个类文件),可以看见在下面控制台中显示成功了:(注意如果不带包编译(ctrl+1)源文件和类文件就是在同一个目录下的,如果带包编译(ctrl+3)源文件和类文件就都是分开的) 然后运行(注意运行也有两个,ctrl+2只有在没有包名的情况下才可以使用,而ctrl+4只有在带包名的情况下才可以使用,并且注意使用之前必须先选中包名,不能选多了,也不能选少了),如图,运行成功: 面说说还有一种特殊情况,我们现在的配置的运行的动作是也就是说我们编译之后运行后的结果不会自动弹出命令提示符显示,而是在下面的控制台中显示,那么就会有一种特殊情况了,就是如果当java程序需要用户输入的时候我们该怎么输入,我们直接输入是不行的,方法就是在控制台上右击 然后点击键盘输入 当然如果觉得这样麻烦的话也可以不设置成而设置成无,那么运行的时候就会自动弹出我们熟悉的命令提示符了:","link":"/2016/09/06/在Editplus中配置java的(带包)编译(javac)和运行(java)的方法/"},{"title":"在Keras的Embedding层中使用预训练的word2vec词向量","text":"本文的部分工作、代码、数据共享到gethub网站《使用多层级注意力机制和keras实现问题分类》:https://github.com/xqtbox/question-classification-with-multi-level-attention-mechanism-and-keras 1 准备工作1.1 什么是词向量?”词向量”(词嵌入)是将一类将词的语义映射到向量空间中去的自然语言处理技术。即将一个词用特定的向量来表示,向量之间的距离(例如,任意两个向量之间的L2范式距离或更常用的余弦距离)一定程度上表征了的词之间的语义关系。由这些向量形成的几何空间被称为一个嵌入空间。 传统的独热表示( one-hot representation)仅仅将词符号化,不包含任何语义信息。必须考虑将语义融入到词表示中。 解决办法将原来稀疏的巨大维度压缩嵌入到一个更小维度的空间进行分布式表示。 这也是词向量又名词嵌入的缘由了。 例如,“椰子”和“北极熊”是语义上完全不同的词,所以它们的词向量在一个合理的嵌入空间的距离将会非常遥远。但“厨房”和“晚餐”是相关的话,所以它们的词向量之间的距离会相对小。 理想的情况下,在一个良好的嵌入空间里,从“厨房”向量到“晚餐”向量的“路径”向量会精确地捕捉这两个概念之间的语义关系。在这种情况下,“路径”向量表示的是“发生的地点”,所以你会期望“厨房”向量 - “晚餐”向量(两个词向量的差异)捕捉到“发生的地点”这样的语义关系。基本上,我们应该有向量等式:晚餐 + 发生的地点 = 厨房(至少接近)。如果真的是这样的话,那么我们可以使用这样的关系向量来回答某些问题。例如,应用这种语义关系到一个新的向量,比如“工作”,我们应该得到一个有意义的等式,工作+ 发生的地点 = 办公室,来回答“工作发生在哪里?”。 词向量通过降维技术表征文本数据集中的词的共现信息。方法包括神经网络(“Word2vec”技术),或矩阵分解。 1.2 获取词向量词向量 对与中文自然语言处理任务 是基石,一般情况下 有两种获取方式: 别人训练好的百科数据。优势:包含词语多,符合日常用语的语义;劣势:专有名词不足,占用空间大; 自己训练。优势:专有名词,针对具体任务语义更准确; 劣势:泛化性差。 步骤: 1234graph LR文本-->分词分词-->训练词向量训练词向量-->保存词向量 具体代码:1234567891011121314151617181920212223import gensim## 训练自己的词向量,并保存。def trainWord2Vec(filePath): sentences = gensim.models.word2vec.LineSentence(filePath) # 读取分词后的 文本 model = gensim.models.Word2Vec(sentences, size=100, window=5, min_count=1, workers=4) # 训练模型 model.save('./CarComment_vord2vec_100')def testMyWord2Vec(): # 读取自己的词向量,并简单测试一下 效果。 inp = './CarComment_vord2vec_100' # 读取词向量 model = gensim.models.Word2Vec.load(inp) print('空间的词向量(100维):',model['空间']) print('打印与空间最相近的5个词语:',model.most_similar('空间', topn=5))if __name__ == '__main__': #trainWord2Vec('./CarCommentAll_cut.csv') testMyWord2Vec() pass 这样我们就 拥有了 预训练的 词向量文件CarComment_vord2vec_100 。 下一单元 继续讲解如何在keras中使用它。 2 转化词向量为keras所需格式上一步拿到了所有词语的词向量,但还需转化词向量为keras所需格式。众所周知,keras中使用预训练的词向量的层是Embedding层,而Embedding层中所需要的格式为 一个巨大的“矩阵”:第i列表示词索引为i的词的词向量 所以,本单元的总体思路就是给 Embedding 层提供一个 [ word : word_vector] 的词典来初始化Embedding层中所需要的大矩阵 ,并且标记为不可训练。 2.1 获取所有词语word和词向量首先要导入 预训练的词向量。12345## 1 导入 预训练的词向量myPath = './CarComment_vord2vec_100' # 本地词向量的地址Word2VecModel = gensim.models.Word2Vec.load(myPath) # 读取词向量vector = Word2VecModel.wv['空间'] # 词语的向量,是numpy格式 gensim的word2vec模型 把所有的单词和 词向量 都存储在了Word2VecModel.wv里面,讲道理直接使用这个.wv即可。 但是我们打印这个东西的 类型 123456print(type(Word2VecModel.wv)) # 结果为:Word2VecKeyedVectorsfor i,j in Word2VecModel.wv.vocab.items(): print(i) # 此时 i 代表每个单词 print(j) # j 代表封装了 词频 等信息的 gensim“Vocab”对象,例子:Vocab(count:1481, index:38, sample_int:3701260191) break 发现它是 gensim自己封装的一种数据类型:Word2VecKeyedVectors,1<class 'gensim.models.keyedvectors.Word2VecKeyedVectors'> 不能使用for循环迭代取单词。 2.2 构造“词语-词向量”字典第二步 构造数据: 构造 一个list存储所有单词:vocab_list 存储所有词语。 构造一个字典word_index :{word : index} ,key是每个词语,value是单词在字典中的序号。 在后期 tokenize(序号化) 训练集的时候就是用该词典。构造包含 构造一个 大向量矩阵embeddings_matrix (按照embedding层的要求):行数 为 所有单词数,比如 10000;列数为 词向量维度,比如100。 代码: 123456789## 2 构造包含所有词语的 list,以及初始化 “词语-序号”字典 和 “词向量”矩阵vocab_list = [word for word, Vocab in Word2VecModel.wv.vocab.items()]# 存储 所有的 词语word_index = {\" \": 0}# 初始化 `[word : token]` ,后期 tokenize 语料库就是用该词典。word_vector = {} # 初始化`[word : vector]`字典# 初始化存储所有向量的大矩阵,留意其中多一位(首行),词向量全为 0,用于 padding补零。# 行数 为 所有单词数+1 比如 10000+1 ; 列数为 词向量“维度”比如100。embeddings_matrix = np.zeros((len(vocab_list) + 1, Word2VecModel.vector_size)) 2.3 填充字典和矩阵第三步:填充 上述步骤中 的字典 和 大矩阵 1234567## 3 填充 上述 的字典 和 大矩阵for i in range(len(vocab_list)): # print(i) word = vocab_list[i] # 每个词语 word_index[word] = i + 1 # 词语:序号 word_vector[word] = Word2VecModel.wv[word] # 词语:词向量 embeddings_matrix[i + 1] = Word2VecModel.wv[word] # 词向量矩阵 2.4 在 keras的Embedding层中使用 预训练词向量1234567891011from keras.layers import EmbeddingEMBEDDING_DIM = 100 #词向量维度embedding_layer = Embedding(input_dim = len(embeddings_matrix), # 字典长度 EMBEDDING_DIM, # 词向量 长度(100) weights=[embeddings_matrix], # 重点:预训练的词向量系数 input_length=MAX_SEQUENCE_LENGTH, # 每句话的 最大长度(必须padding) trainable=False # 是否在 训练的过程中 更新词向量 ) Embedding层的输入shape 此时 输入Embedding层的数据的维度是形如(samples,sequence_length)的2D张量,注意,此时句子中的词语word已经被转化为 index(依靠word_index,所以在 embedding层之前 往往结合 input层, 用于将 文本 分词 转化为数字形式) Embedding层的输出shape Embedding层把 所有输入的序列中的整数,替换为对应的词向量矩阵中对应的向量(也就是它的词向量),比如一句话[1,2,8]将被序列[词向量第[1]行,词向量第[2]行,词向量第[8]行]代替。 这样,输入一个2D张量后,我们可以得到一个3D张量:(samples, sequence_length, embeddings_matrix) *2.5 不使用“预训练”而直接生成词向量我们也可以直接使用Keras自带的Embedding层训练词向量,而不用预训练的word2vec词向量。代码如下所示: 123embedding_layer = Embedding(len(word_index) + 1, # 由于 没有预训练,设置+1 EMBEDDING_DIM, # 设置词向量的维度 input_length=MAX_SEQUENCE_LENGTH) #设置句子的最大长度 可以看出在使用 Keras的中Embedding层时候,不指定参数weights=[embeddings_matrix] 即可自动生成词向量。 先是随机初始化,然后,在训练数据的过程中训练。 在参考文献1中 做的对比实验,对于新闻文本分类任务:直接使用Keras自带的Embedding层训练词向量而不用预训练的word2vec词向量,得到0.9的准确率。 使用预训练的word2vec词向量,同样的模型最后可以达到0.95的分类准确率。 所以使用预训练的词向量作为特征是非常有效的。一般来说,在自然语言处理任务中,当样本数量非常少时,使用预训练的词向量是可行的(实际上,预训练的词向量引入了外部语义信息,往往对模型很有帮助)。 3 整体代码:在Keras模型中使用预训练的词向量文本数据预处理,将每个文本样本转换为一个数字矩阵,矩阵的每一行表示一个词向量。下图梳理了处理文本数据的一般步骤。 3.1 读取数据1234567891011121314def load_file(): dataFrame_2016 = pd.read_csv('data\\\\nlpcc2016_kbqa_traindata_zong_right.csv',encoding='utf-8') print(dataFrame_2016.columns) # 打印列的名称 texts = [] # 存储读取的 x labels = [] # 存储读取的y # 遍历 获取数据 for i in range(len(dataFrame_2016)): texts.append(dataFrame_2016.iloc[i].q_text) # 每个元素为一句话“《机械设计基础》这本书的作者是谁?” labels.append(dataFrame_2016.iloc[i].q_type) # 每个元素为一个int 代表类别 # [2, 6, ... 3] 的形式 ## 把类别从int 3 转换为(0,0,0,1,0,0)的形式 labels = to_categorical(np.asarray(labels)) # keras的处理方法,一定要学会# 此时为[[0. 0. 1. 0. 0. 0. 0.]....] 的形式 return texts, labels # 总文本,总标签 3.2 句子分词1234## 2. cut_sentence2word 句子分词def cut_sentence2word(texts): texts = [jieba.lcut(Sentence.replace('\\n', '')) for Sentence in texts] # 句子分词 return texts 3.3 *构造词向量字典1234567891011121314151617181920212223242526272829303132## 3.获取word2vec模型, 并构造,词语index字典,词向量字典def get_word2vec_dictionaries(texts): def get_word2vec_model(texts=None): # 获取 预训练的词向量 模型,如果没有就重新训练一个。 if os.path.exists('data_word2vec/Word2vec_model_embedding_25'): # 如果训练好了 就加载一下不用反复训练 model = Word2Vec.load('data_word2vec/Word2vec_model_embedding_25') # print(model['作者']) return model else: model = Word2Vec(texts, size = EMBEDDING_LEN, window=7, min_count=10, workers=4) model.save('data_word2vec/Word2vec_model_embedding_25') # 保存模型 return model Word2VecModel = get_word2vec_model(texts) # 获取 预训练的词向量 模型,如果没有就重新训练一个。 vocab_list = [word for word, Vocab in Word2VecModel.wv.vocab.items()] # 存储 所有的 词语 word_index = {\" \": 0}# 初始化 `[word : token]` ,后期 tokenize 语料库就是用该词典。 word_vector = {} # 初始化`[word : vector]`字典 # 初始化存储所有向量的大矩阵,留意其中多一位(首行),词向量全为 0,用于 padding补零。 # 行数 为 所有单词数+1 比如 10000+1 ; 列数为 词向量“维度”比如100。 embeddings_matrix = np.zeros((len(vocab_list) + 1, Word2VecModel.vector_size)) ## 填充 上述 的字典 和 大矩阵 for i in range(len(vocab_list)): word = vocab_list[i] # 每个词语 word_index[word] = i + 1 # 词语:序号 word_vector[word] = Word2VecModel.wv[word] # 词语:词向量 embeddings_matrix[i + 1] = Word2VecModel.wv[word] # 词向量矩阵 return word_index, word_vector, embeddings_matrix 3.4 文本序号化Tokenizer在上文中已经得到了每条文本的文字了,但是text-CNN等深度学习模型的输入应该是数字矩阵。可以使用Keras的Tokenizer模块实现转换。 简单讲解Tokenizer如何实现转换。当我们创建了一个Tokenizer对象后,使用该对象的fit_on_texts()函数,可以将输入的文本中的每个词编号,编号是根据词频的,词频越大,编号越小。可能这时会有疑问:Tokenizer是如何判断文本的一个词呢?其实它是以空格去识别每个词。因为英文的词与词之间是以空格分隔,所以我们可以直接将文本作为函数的参数,但是当我们处理中文文本时,我们需要使用分词工具将词与词分开,并且词间使用空格分开。具体实现如下: 当然 ,也可以使用之前构建的word_index字典,手动 构建文本tokenizer句子:(推荐这种方法,这样序号下标与预训练词向量一致。) 12345678910111213141516# 序号化 文本,tokenizer句子,并返回每个句子所对应的词语索引def tokenizer(texts, word_index): data = [] for sentence in texts: new_txt = [] for word in sentence: try: new_txt.append(word_index[word]) # 把句子中的 词语转化为index except: new_txt.append(0) data.append(new_txt) texts = sequence.pad_sequences(data, maxlen = MAX_SEQUENCE_LENGTH) # 使用kears的内置函数padding对齐句子,好处是输出numpy数组,不用自己转化了 return texts 3.5 切分数据1234## 5.切分数据def split_data(texts, labels): x_train, x_test, y_train, y_test = train_test_split(texts, labels, test_size=0.2) return x_train, x_test, y_train, y_test 3.6 使用Embedding层将每个词编码转换为词向量通过以上操作,已经将每个句子变成一个向量,但上文已经提及text-CNN的输入是一个数字矩阵,即每个影评样本应该是以一个矩阵,每一行代表一个词,因此,需要将词编码转换成词向量。使用Keras的Embedding层可以实现转换。 需要声明一点的是Embedding层是作为模型的第一层,在训练模型的同时,得到该语料库的词向量。当然,也可以使用已经预训练好的词向量表示现有语料库中的词。 1234567embedding_layer = Embedding(input_dim=len(embeddings_matrix), # 字典长度 output_dim = EMBEDDING_LEN, # 词向量 长度(25) weights=[embeddings_matrix], # 重点:预训练的词向量系数 input_length=MAX_SEQUENCE_LENGTH, # 每句话的 最大长度(必须padding) 10 trainable=False, # 是否在 训练的过程中 更新词向量 name= 'embedding_layer' ) 然后利用 keras的建模能力,把Embedding层嵌入到 模型中去即可。后面可以接CNN或者LSTM 参考文献 参考《Keras的中Embedding层 官方文档》: https://keras-cn.readthedocs.io/en/latest/layers/embedding_layer/ 参考1 官方文档《在Keras模型中使用预训练的词向量》:https://keras-cn-docs.readthedocs.io/zh_CN/latest/blog/word_embedding/ 参考2 :《Keras 模型中使用预训练的 gensim 词向量(word2vec) 和可视化》 https://eliyar.biz/using-pre-trained-gensim-word2vector-in-a-keras-model-and-visualizing/ 参考3《Embedding原理和Tensorflow-tf.nn.embedding_lookup()》:https://blog.csdn.net/laolu1573/article/details/77170407","link":"/2019/05/15/在Keras的Embedding层中使用预训练的word2vec词向量/"},{"title":"在win7环境下oracle10g安装问题","text":"虽然oracle10g这个版本已经比较老,但是他比较经典。并且许多高校都用这个版本。所以把安装过程中所有问题贴出来。 1. ORACLE 10g下载地址现在直接点击不能下载了要经过oracle许可才可以下载如果嫌麻烦可以用迅雷直接下载32位:(经检验64位电脑也可以用) Oracle Database 10g Release 2 (10.2.0.1.0) Enterprise/Standard Edition forMicrosoft Windows (32-bit) http://download.oracle.com/otn/nt/oracle10g/10201/10201_database_win32.zip 2、 然后解压3、 退出360等,最好关闭防火墙。4、 让陈旧的oracle10g支持高大上的win7,呵呵:更改解压好的文件夹里面:.. \\database\\stage\\prereq\\db下的refhost.xml文件,在 任意一个之后增加1234<!--MicrosoftWindows 7--> <OPERATING_SYSTEM> <VERSION VALUE="6.1"/></OPERATING_SYSTEM> 5、 更改.. \\database\\install下的oraparam.ini文件,增加如下项:1234567Windows=5.0,5.1,5.2,6.0,6.1[Windows-6.1-required]#Minimum display colours for OUI to runMIN_DISPLAY_COLORS=256#Minimum CPU speed required for OUI#CPU=300[Windows-6.1-optional] 6、 右击“stuep.exe”文件–》选择“属性”–》兼容性–》选中兼容系统然后就可以开始安装了,(以管理员身份运行此程序)首先会弹出一个框说是找不到先决条件(这个很正常,因为上面被你更改了配置),不要紧张,耐心等待一会就会开始安装了,千万不要关闭这个窗口。 7、 ERROR 2正在检查网络配置要求…检查完成。此次检查的总体结果为: 失败 <<<< 问题: 安装检测到系统的主 IP 地址是 DHCP 分配的地址。 建议案: Oracle 支持在具有 DHCP 分配的 IP 地址的系统上进行安装。但在安装之前, 必须将Microsoft LoopBack Adapter 配置为系统的主网络适配器。有关在配置有 DHCP 的系统上安装软件的详细信息, 请参阅 Installation Guide。 解决方案:1.单击开始图标,在智能搜索中输入“hdwwiz”,在搜索结果中鼠标右键单击该程序,使用“以管理员身份运行”方式来启动。 根据操作系统向导,选择“安装我手动从列表选择的硬件(高级)”。3.在硬件列表中,选择“网络适配器”。4.选择“Microsoft”厂商,并在右边网络适配器列表中选中“MicrosoftLoopback Adapter”,下一步按照向导完成安装。5 然后进入 控制面板\\网络和 Internet\\网络连接 把当前的本地连接禁止,然后给新增的Microsoft LoopBack Adapter本地连接指定个IP:192.168..0.1,然后启动。OK,然后点Oracle中的重试,this’s Problem Resolve! 8、ERROR 2正在检查网络配置出现错误:”无法确定主机的IP地址时产生异常错误” 问题原因:找不到本机系统的IP地址,无法解析机器名。 解决办法:在hosts文件下手动修改。 (1)打开c:\\windows\\system32\\drivers\\etc\\hosts文件 手动加入:12127.0.0.1 localhost192.168.0.1 lenovothink 第二行,每台机器不一样!那么 怎么找到自己机器的IP地址和机器名? (1) IP地址网络连接->本地连接(2) 本机的机器名:右键 我的电脑 即可看到。 情况3:如果企业管理控制器打不开怎么办呢? 检查自己的IP地址与host文件中的是否一致。 如果不一致,更改host 如果一致重启电脑即可。 情况四:出现错误时登录企业管理器时出现的界面 出现这种错误一般是因为没有设置时区,一般默认的是agentTZRegion=GMT,也就是GMT。所以大家只要设置了这个东西,然后重新启动dbconsole就可以了。下面是设置以及重新启动dbconsole的全过程: 第一步,在Oracle安装目录中找打这个文件emd.properties(以往大家都是找不到这个文件在哪里),D:\\oracle\\product\\10.2.0\\db_1\\lenovothink_orcl\\sysman\\config,我的这个文件就是在这个路径下。估计大家都能找到这里D:\\oracle\\product\\10.2.0\\db_1,再往下就是lenovothinkorcl文件夹,这个是我的计算机名数据库全局变量,大家只要找到以自己计算机命名的这个文件即可,然后依次找到sysman\\config这个路劲下,然后就找到了emd.properties这个文件。然后用记事本打开这个文件,在此文件的最后一行你就可以看到agentTZRegion=GMT。 第二步,将agentTZRegion=GMT中的GMT改成Asia/Shanghai,也就是agentTZRegion=Asia/Shanghai,这里有个问题就是Asia一定首字母大写,Shanghai的首字母也要大些,你也可以用其他的地区,比如Asia/Beijing,不过我试过这个在我的机器上行不通,而改成Shanghai之后便可以正确显示,这个我也不清楚为什么,关于时区的列表参考:10.2.0\\db_1\\sysman\\admin\\supportedtzs.lst这个路径的文件去查找下中查找。改完后保存就行。 第三步,在cmd下输入输入此命令,>setoracle_sid=orcl(orcl也就是数据库全局变量名,也就是数据库名),当然回车之后没任何反应。如下图: 第四步,继续输入命令>emctlstop dbconsole(大家一定要注意emctl,最后一个字母是L,不是1,笔者因为把l弄成1,费了好大劲,希望大家不要犯我的错误)。这一步就是关闭dbconsole,回车之后如下图: 第五步,最后一步,启动原来关闭的dbconsole服务。键入命令>emctl start dbconsole,回车之后如下图: 好了,经过这些操作之后大家重新启动浏览器,然后重新登录企业管理器就会发现java.lang.Exception:Exception in sending Request :: null这个错误没有了。我重新启动浏览器,重新登录后的界面如下图: Fujia附加的,卸载过程: 停止所有与ORACLE相关的服务。Ctrl+alt+delete….. 使用OUI(OracleUniversal Installer)卸载Oracle软件。 “开始”->“程序”->“Oracle-OraDb110g_home1/Oracle installation product/Universalinstaller.或者安装的那个程序:setup.exe也可以卸载。 3.删除注册表内容。 运行regedit命令,删除下面内容:HKEY_LOCAL_MACHINE/SOFTWARE/ORACLE注册表键,删除此键。 HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services,删除Services键下所有以oracle为首的键。 HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Eventlog/Application, 删除此键下所有以oracle为首的键。 HKEY_CLASSES_ROOT,删除此键下所有以Ora,Oracle,Orcl,EnumOra 为前缀的键。 HKEY_CURRENT_USER/Software/Microsoft/Windows/CurrentVersion/Explorer/MenuOrder/StartMenu/Programs,删除此键下所有以oracle为首的键。 HKEY_LOCAL_MACHINE/SOFTWARE/ODBC/ODBCINST.INI注册表键,删除了MicrosoftODBC FOR ORACLE注册表键以外的所有有Oracle字样的键值。 4.最后在文件系统内删除ORACLE相关的文件及目录:如果无法删除,就用360粉碎删除。 5.重新启动。","link":"/2015/05/21/在win7环境下oracle10g安装问题/"},{"title":"实战天猫数据爬取","text":"主要用到的知识点 实用技巧1—多级页面的抓取-callback函数 实用技巧2—图片的抓取- 抓取过程中的常见问题—cookie的处理,cookie模拟登录 分页 1. 实用技巧1—多级页面的抓取-callback函数1yield scrapy.Request(url=item["GOODS_URL"], meta={'item': item}, callback=self.parse_detail,dont_filter=True) 返回的是一个请求,参数为: 123url为进一步处理的地址。meta为了进一步把对象传进去callback是指处理的函数 2. 实用技巧2—图片的抓取-1.首先把图片地址获取 12345678# 图片链接 try: file_urls = div.xpath('div[@class="productImg-wrap"]/a[1]/img/@src|' 'div[@class="productImg-wrap"]/a[1]/img/@data-ks-lazyload').extract()[0] item['file_urls'] = ["http:" + file_urls] except Exception as e: print("Error:",e) import pdb;pdb.set_trace() 2.在settings中引入引擎 123456# 以下三行引入默认的图片下载器,想改可以重写它ITEM_PIPELINES = {'scrapy.pipelines.images.ImagesPipeline': 1}# 引入items的连接属性IMAGES_URLS_FIELD = 'file_urls'# 设置存入本地的地址,当前目录。IMAGES_STORE = r'./images' 3. 抓取过程中的常见问题—cookie的处理,cookie模拟登录自己登录后,查看cookie,把cookie里面的所有参数都输入。 12345678910111213141516171819202122232425def start_requests(self): # 循环页码,就在这个函数中实现。 reqs = [] # 每个页面的request cookies = { 'miid':'1279809970704864021', 'thw':'cn', 't':'7349beda1fac2771e1b07173a388c1a7', 'cookie2':'169e58df275871365bf763a04f83945d', '_tb_token_':'f5836335bbbed', 'l':'As7Ol7pcpNOglmJtnYezXP/Fnq6RuZJB', 'isg':'AuTkU7_eYUo5n5WHgkykUP1IteI6RAjnXtEpK_4Ehq96qYZzJ431dp1BH7ZL', 'cna':'xxqjEU4BaTMCAXLV6R/2cfxq', 'sca':'49d5174e', 'atpsida':'b8147f8d3acd3709988ab26d_1495089785_1', 'aimx':'xxqjEYvEdQcCAXLV6R9iOoQn_1495089785', 'cad':'k95WugY3Sgew+2KIuDSUxTOnySH07xok1SSfrDICn3k=0001', 'cap':'41cf', '_med':'dw:1366&dh:768&pw:1366&ph:768&ist:0', 'res':'scroll%3A1349*6611-client%3A1349*637-offset%3A1349*6611-screen%3A1366*768', 'pnm_cku822':'043UW5TcyMNYQwiAiwQRHhBfEF8QXtHcklnMWc%3D%7CUm5Ockt%2FR3pPe0F5QndJdCI%3D%7CU2xMHDJ7G2AHYg8hAS8XIgwsAl4%2FWTVSLFZ4Lng%3D%7CVGhXd1llXGhQbVhsVm5VYF5jVGlLcEx2SHxBf0F0QH5AekF%2FQG44%7CVWldfS0RMQ01DDQUKBMzHWxSPAIrFioSKhI4Az0YLlV7LXs%3D%7CVmhIGCUFOBgkGiMXNww3CzcXKxUuFTUPNAEhHSMYIwM5BjNlMw%3D%3D%7CV25Tbk5zU2xMcEl1VWtTaUlwJg%3D%3D', 'cq':'ccp%3D1' } for i in range(0, 2): # 代表从0到1页 req = scrapy.Request("https://list.tmall.com/search_product.htm?spm=a220m.1000858.0.0.wH40GN&s="+str(i*60)+"&q=%C4%D0%D7%B0&sort=d&style=g&from=nanzhuang..pc_1_suggest&suggest=0_1&type=pc#J_Filter",cookies=cookies ) reqs.append(req) return reqs 4. 分页123456789def start_requests(self): # 循环页码,就在这个函数中实现。 reqs = [] # 每个页面的request cookies = { 'miid':'1279809970704864021', } for i in range(0, 2): # 代表从0到1页 req = scrapy.Request("https://list.tmall.com/search_product.htm?spm=a220m.1000858.0.0.wH40GN&s="+str(i*60)+"&q=%C4%D0%D7%B0&sort=d&style=g&from=nanzhuang..pc_1_suggest&suggest=0_1&type=pc#J_Filter",cookies=cookies ) reqs.append(req) return reqs 完整代码参见 :githubxqtbox实战天猫数据爬取","link":"/2017/05/19/实战天猫数据爬取/"},{"title":"实践篇(1)准备数据和本体建模","text":"本文参考知乎大神SimmerChan文章:《实践篇(一):数据准备和本体建模》https://zhuanlan.zhihu.com/p/32389370 通过前面几篇文章的介绍,读者应该对知识图谱,其相关概念,以及语义网技术 栈中的RDF,RDFS/OWL有了一定的了解。然而,之前我们都是在介绍一些概念性的东西。实践才出真知,理论掌握得再好,不能解决实际问题也只是纸上谈兵。因此,笔者准备开一个实践篇,结合理论篇,让读者能够从无到有构建一个领域知识图谱,并在其上搭建一个基于知识图谱的问答小程序。demo比较简单,问答实现是基于模板匹配和正则表达式,整个流程是为了让读者对知识图谱及其相关应用有个直观的认识。 本文作为实践篇第一篇文章,首先介绍我们使用的数据、数据来源和数据获取方法;其次,基于数据内部关系,介绍如何以自顶向下的方式构建本体结构。 1. 数据准备实践篇使用的数据是与电影相关的。基本统计数据如下: 演员数量:505人 电影数量:4518部 电影类型:19类 人物与电影的关系:14451 电影与类型的关系:7898 演员的基本信息包括:姓名、英文名、出生日期、死亡日期、出生地、个人简介。 电影的基本信息包括:电影名称、电影简介、电影评分、电影发行日期、电影类型。 经过去重处理,我们得到了505个演员的基本信息和4518部电影的基本信息。数据保存在mysql中,其ER图如下: 2. 本体建模本体的构建大体有两种方式:自顶向下和自底向上。 开放域知识图谱的本体构建通常用自底向上的方法,自动地从知识图谱中抽取概念、概念层次和概念之间的关系。这也很好理解,开放的世界太过复杂,用自顶向下的方法无法考虑周全,且随着世界变化,对应的概念还在增长。 领域知识图谱多采用自顶向下的方法来构建本体。一方面,相对于开放域知识图谱,领域知识图谱涉及的概念和范围都是固定或者可控的;另一方面,对于领域知识图谱,我们要求其满足较高的精度。现在大家接触到的一些语音助手背后对接的知识图谱大多都是领域知识图谱,比如音乐知识图谱、体育知识图谱、烹饪知识图谱等等。正因为是这些领域知识图谱来满足用户的大多数需求,更需要保证其精度。 2.1 Protege的下载安装Protégé,又常常简单地拼写为“Protege”,是一个斯坦福大学开发的本体编辑和知识获取软件。开发语言采用Java,属于开放源码软件。由于其优秀的设计和众多的插件,Protégé已成为目前使用最广泛的本体论编辑器之一(来自维基百科)。 知识图谱本体构建工具 Protege的下载安装与使用:https://blog.csdn.net/u012052268/article/details/88052390 2.2 构建本体2.2.1 本体资源的IRI打开protege,看到和下图类似的界面。在Ontology IRI中填写我们新建本体资源的IRI。读者一定要先填写自己的符合标准的IRI。 这个后面建实体关系都会用到。 和下面: 比如我们设置的hr知识图谱:1@prefix: <http://www.hr_kg_qa.com#> . 2.2.2 定义“类”点击“Entities”tab标签,选择“Classes”标签。在这个界面,我们创建电影知识图谱的类/概念。 注意,所有的类都是“Thing”的子类。最左边红色小方框中的按钮用于创建当前选中类的子类,中间的按钮用于创建兄弟类(平行类),最右边的按钮删除当前选中的类 。我们创建了三个类,“人物”、“电影”、“类别”。 右下方的界面是用于描述该类的一些特性,例如:”disjoint of”是用于表示该类与哪些类是互斥的。 本例中,三个类都是互斥的。也就是说,一个实例只能是三个类中的一个。我们没有在protege中显式地定义互斥关系,读者可以自己定义。 2.2.3 定义实体间的关系接下来我们切换到”Object Properties”页面,我们在此界面创建类之间的关系,即,对象属性。 这里我们创建了三个对象属性,”hasActedIn”表示某人参演了某电影,因此我们在右下方的3号矩形框中定义该属性的”domain”是人,4号框定义”range”是电影。这个很好理解,”domain”表示该属性是属于哪个类的,”range”表示该属性的取值范围。 2号框表示该属性的逆属性是”hasActor”,即,有了推理机,尽管我们的RDF数据只保存了A出演了B,我们在查询的时候也能得到B的演员有A。 1号方框中是一些描述该属性的词汇,我们在上一篇文章中已经介绍过,这里不再赘述。同理,我们定义另外两个属性,这里不再展示。 2.2.4 定义实体属性最后,我们切换到”Data properties”,我们在该界面创建类的属性,即,数据属性。其定义方法和对象属性类似,除了没有这么丰富的描述属性特性的词汇。其实不难理解,这些描述特性的词汇是传递、对称、反对称、自反等,表明其必定有指向其他资源或自身的边,而我们之前提到过,数据属性相当于树的叶子节点,只有入度,而没有出度。 其实区分数据属性和对象属性还有一个很直观的方法,我们观察其”range”,取值范围即可。对象属性的取值范围是类,而数据属性的取值范围则是字面量,如下图。 2.2.5 可视化本体protege也支持以可视化的方式来展示本体结构。我们点击”Window”选项,在”Tabs”中选择”OntoGraf”,然后”Entities”旁边就多了一个标签页。在右侧窗口中移动元素,可以很直观地观察本体之间的关系。 其他操作也可以参考:https://blog.csdn.net/u012052268/article/details/88052390 2.2.6 本体保存本体文件是从顶向下定义的,采用protege软件编辑生成,保存时格式选择为Turtle,放在自己定义的文件夹里 后缀是.owl的。 3 总结这篇文章介绍了接下来实践中使用的数据,以及如何利用protege,根据我们的数据来进行本体建模。 下一篇实践文章将介绍关系数据库中的数据转换为RDF的几种方法,让读者学会如何把存在Mysql中的电影数据转为RDF格式的数据。","link":"/2019/04/27/实践篇(1)准备数据和本体建模/"},{"title":"在TensorFlow中实现文本分类的CNN","text":"注意: 本文翻译自WILDML的博客Implementing a CNN for Text Classification in TensorFlow 博客地址: http://www.wildml.com/2015/12/implementing-a-cnn-for-text-classification-in-tensorflow/ github地址:https://github.com/dennybritz/cnn-text-classification-tf 在这篇文章中,我们将实现一个类似于Kim Yoon的卷积神经网络语句分类模型。 本文提出的模型在一系列文本分类任务(如情绪分析)中实现了良好的分类性能,并已成为新的文本分类架构的标准基准。 我假设你已经熟悉了应用于NLP的卷积神经网络的基础知识。 如果没有,我建议先阅读NLP的理解卷积神经网络,以获得必要的背景。 1 数据和预处理我们在这篇文章中使用的数据集是Rotten Tomatoes的Movie Review数据,也是原始文件中使用的数据集之一。 数据集包含10,662个实例审查句子,半正负半数。 数据集的大小约为20k。 请注意,由于这个数据集很小,我们很可能会使用强大的模型。 此外,数据集不附带官方列车/测试拆分,因此我们只需将10%的数据用作开发套件。 原始文件报告了对数据进行10倍交叉验证的结果。 我不会在这篇文章中介绍数据预处理代码,但是它可以在Github上使用,并执行以下操作: 从原始数据文件中加载正负句子。 使用与原始论文相同的代码清理文本数据。 将每个句子加到最大句子长度,结果是59.我们将特殊的标记附加到所有其他句子,使其成为59个字。 填充句子相同的长度是有用的,因为它允许我们有效地批量我们的数据,因为批处理中的每个示例必须具有相同的长度。 构建词汇索引,并将每个单词映射到0到18,765之间的整数(词汇大小)。 每个句子都成为整数向量。 2 模型我们将在这篇文章中建立的网络大致如下:第一层将单词嵌入到低维向量中。 下一层使用多个过滤器大小对嵌入的字矢量进行卷积。 例如,一次滑过3个,4个或5个字。 接下来,我们将卷积层的结果最大化为一个长的特征向量,添加退出正则化,并使用softmax层对结果进行分类。 因为这是一个教育文章,我决定从原始文件中简化模型: 我们不会将预先训练的word2vec矢量用于我们的词嵌入。 相反,我们从头开始学习嵌入。 我们不会对权重向量执行L2规范约束。 (和从业者指南)对句子分类的卷积神经网络的敏感性分析发现,约束对最终结果几乎没有影响。 原始实验用两个输入数据通道 - 静态和非静态字矢量。 我们只使用一个通道。 将这些扩展代码添加到这里是比较简单的(几十行代码)。 看看帖子结尾的练习。 让我们开始吧! 3 实现为了允许各种超参数配置,我们将代码放入一个TextCNN类中,在init函数中生成模型图。123456789101112import tensorflow as tfimport numpy as np class TextCNN(object): """ A CNN for text classification. Uses an embedding layer, followed by a convolutional, max-pooling and softmax layer. """ def __init__( self, sequence_length, num_classes, vocab_size, embedding_size, filter_sizes, num_filters): # Implementation... 要实例化类,我们传递以下参数: sequence_length - 我们的句子的长度。 请记住,我们填充所有句子的长度相同(59为我们的数据集)。 num_classes - 输出层中的类数,在我们的例子中为正(负)。 vocab_size - 我们的词汇量。 这需要定义我们的嵌入层的大小,它将具有[vocabulary_size,embedding_size]的形状。 embedding_size - 我们嵌入的维度。 filter_sizes - 我们想要卷积过滤器覆盖的字数。 我们将为此处指定的每个大小设置num_filters。 例如,[3,4,5]意味着我们将有一个过滤器,分别滑过3个,4个和5个字,总共有3 * num_filters过滤器。 num_filters - 每个过滤器大小的过滤器数量(见上文)。 3.1 输入占位符我们首先定义我们传递给我们网络的输入数据:1234# Placeholders for input, output and dropoutself.input_x = tf.placeholder(tf.int32, [None, sequence_length], name="input_x")self.input_y = tf.placeholder(tf.float32, [None, num_classes], name="input_y")self.dropout_keep_prob = tf.placeholder(tf.float32, name="dropout_keep_prob") tf.placeholder创建一个占位符变量,当我们在火车或测试时间执行它时,我们馈送到网络。 第二个参数是输入张量的形状。 无意味着该维度的长度可以是任何东西。 在我们的情况下,第一个维度是批量大小,并且使用“无”允许网络处理任意大小的批次。 将神经元保留在丢失层中的概率也是网络的输入,因为我们仅在训练期间启用退出。 我们在评估模型时禁用它(稍后再说)。 3.2 向量层我们定义的第一层是嵌入层,它将词汇词索引映射到低维向量表示中。 它本质上是一个从数据中学习的查找表。123456with tf.device('/cpu:0'), tf.name_scope("embedding"): W = tf.Variable( tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0), name="W") self.embedded_chars = tf.nn.embedding_lookup(W, self.input_x) self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1) 我们在这里使用了几个新功能,让我们来看看: tf.device(“/ cpu:0”)强制在CPU上执行操作。 默认情况下,TensorFlow将尝试将操作放在GPU上(如果有的话)可用,但是嵌入式实现当前没有GPU支持,并且如果放置在GPU上则会抛出错误。 tf.name_scope创建一个名称范围,名称为“embedding”。 范围将所有操作添加到名为“嵌入”的顶级节点中,以便在TensorBoard中可视化您的网络时获得良好的层次结构。 W是我们在训练中学习的嵌入矩阵。 我们使用随机均匀分布来初始化它。 tf.nn.embedding_lookup创建实际的嵌入操作。 嵌入操作的结果是形状为[None,sequence_length,embedding_size]的三维张量。 TensorFlow的卷积conv2d操作期望具有对应于批次,宽度,高度和通道的尺寸的四维张量。 我们嵌入的结果不包含通道尺寸,所以我们手动添加它们,留下一层形状[None,sequence_length,embedding_size,1]。 3.3 卷积层和池化层现在我们已经准备好构建卷积层,然后再进行最大化。 请记住,我们使用不同大小的过滤器。 因为每个卷积产生不同形状的张量,我们需要迭代它们,为它们中的每一个创建一个层,然后将结果合并成一个大的特征向量。12345678910111213141516171819202122232425262728pooled_outputs = []for i, filter_size in enumerate(filter_sizes): with tf.name_scope("conv-maxpool-%s" % filter_size): # Convolution Layer filter_shape = [filter_size, embedding_size, 1, num_filters] W = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.1), name="W") b = tf.Variable(tf.constant(0.1, shape=[num_filters]), name="b") conv = tf.nn.conv2d( self.embedded_chars_expanded, W, strides=[1, 1, 1, 1], padding="VALID", name="conv") # Apply nonlinearity h = tf.nn.relu(tf.nn.bias_add(conv, b), name="relu") # Max-pooling over the outputs pooled = tf.nn.max_pool( h, ksize=[1, sequence_length - filter_size + 1, 1, 1], strides=[1, 1, 1, 1], padding='VALID', name="pool") pooled_outputs.append(pooled) # Combine all the pooled featuresnum_filters_total = num_filters * len(filter_sizes)self.h_pool = tf.concat(3, pooled_outputs)self.h_pool_flat = tf.reshape(self.h_pool, [-1, num_filters_total]) 这里,W是我们的滤波器矩阵,h是将非线性应用于卷积输出的结果。 每个过滤器在整个嵌入中滑过,但是它涵盖的字数有所不同。 “VALID”填充意味着我们将过滤器滑过我们的句子而不填充边缘,执行一个窄的卷积,给出一个形状[1,sequence_length - filter_size + 1,1,1]的输出。 在特定过滤器大小的输出上执行最大化池将留下一张张量[batch_size,1,num_filters]。 这本质上是一个特征向量,其中最后一个维度对应于我们的特征。 一旦我们从每个过滤器大小得到所有的汇集输出张量,我们将它们组合成一个长形特征向量[batch_size,num_filters_total]。 在tf.reshape中使用-1可以告诉TensorFlow在可能的情况下平坦化维度。 花一些时间,尝试了解每个操作的输出形状。 您还可以参考NLP的理解卷积神经网络来获得一些直觉。 可视化TensorBoard中的操作也可以帮助(对于特定的过滤器大小3,4和5) 3.4 Dropout 层花一些时间,尝试了解每个操作的输出形状。 您还可以参考NLP的理解卷积神经网络来获得一些直觉。 可视化TensorBoard中的操作也可以帮助(对于特定的过滤器大小3,4和5)…… 123# Add dropoutwith tf.name_scope("dropout"): self.h_drop = tf.nn.dropout(self.h_pool_flat, self.dropout_keep_prob) 3.5 得分和预测使用max-pooling中的特征向量(使用退出),我们可以通过执行矩阵乘法并选择具有最高分数的类来生成预测。 我们还可以应用softmax函数将原始分数转换为归一化概率,但这不会改变我们的最终预测。 12345with tf.name_scope("output"): W = tf.Variable(tf.truncated_normal([num_filters_total, num_classes], stddev=0.1), name="W") b = tf.Variable(tf.constant(0.1, shape=[num_classes]), name="b") self.scores = tf.nn.xw_plus_b(self.h_drop, W, b, name="scores") self.predictions = tf.argmax(self.scores, 1, name="predictions") 这里,tf.nn.xw_plus_b是执行Wx + b矩阵乘法的便利包装器。 3.6 loss 和 Accuracy使用我们的分数我们可以定义损失函数。 损失是我们网络造成的错误的衡量标准,我们的目标是尽量减少网络的误差。 分类问题的标准损失函数是交叉熵损失。 1234# Calculate mean cross-entropy losswith tf.name_scope("loss"): losses = tf.nn.softmax_cross_entropy_with_logits(self.scores, self.input_y) self.loss = tf.reduce_mean(losses) 这里,tf.nn.softmax_cross_entropy_with_logits是一个方便的函数,计算每个类的交叉熵损失,给定我们的分数和正确的输入标签。 然后我们把损失的平均值。 我们也可以使用这个总和,但这比较难以比较不同批量大小和列车/开发数据的损失。 1234# Calculate Accuracywith tf.name_scope("accuracy"): correct_predictions = tf.equal(self.predictions, tf.argmax(self.input_y, 1)) self.accuracy = tf.reduce_mean(tf.cast(correct_predictions, "float"), name="accuracy") 3.7 可视化网络就这样,我们完成了我们的网络定义。 完整的代码网络定义代码在这里可用。 为了获得大图,我们还可以在TensorBoard中可视化网络: 4 训练过程在我们为网络定义培训程序之前,我们需要了解一些关于TensorFlow如何使用会话和图形的基础知识。 如果您已经熟悉这些概念,请随时跳过本节。 在TensorFlow中,会话是您正在执行图形操作的环境,它包含有关变量和队列的状态。 每个会话都在单个图形上运行。 如果在创建变量和操作时未明确使用会话,则使用TensorFlow创建的当前默认会话。 您可以通过执行session.as_default()块中的命令来更改默认会话(见下文)。 图形包含操作和张量。 您可以在程序中使用多个图形,但大多数程序只需要一个图形。 您可以在多个会话中使用相同的图表,但在一个会话中不能使用多个图表。 TensorFlow始终创建一个默认图形,但您也可以手动创建一个图形,并将其设置为新的默认图像,如下所示。 显式创建会话和图表可确保在不再需要资源时正确释放资源。1234567with tf.Graph().as_default(): session_conf = tf.ConfigProto( allow_soft_placement=FLAGS.allow_soft_placement, log_device_placement=FLAGS.log_device_placement) sess = tf.Session(config=session_conf) with sess.as_default(): # Code that operates on the default graph and session comes here... allow_soft_placement设置允许TensorFlow在首选设备不存在的情况下实现特定操作的设备上回退。 例如,如果我们的代码在GPU上执行操作,并且我们在没有GPU的机器上运行代码,则不使用allow_soft_placement将导致错误。 如果设置了log_device_placement,TensorFlow会登录哪些设备(CPU或GPU)进行操作。 这对调试非常有用。 标记是我们程序的命令行参数。 4.1 实例化CNN并尽可能减少损失当我们实例化我们的TextCNN模型时,所有定义的变量和操作将被放置在上面创建的默认图形和会话中。1234567cnn = TextCNN( sequence_length=x_train.shape[1], num_classes=2, vocab_size=len(vocabulary), embedding_size=FLAGS.embedding_dim, filter_sizes=map(int, FLAGS.filter_sizes.split(",")), num_filters=FLAGS.num_filters) 接下来,我们定义如何优化网络损耗功能。 TensorFlow有几个内置优化器。 我们正在使用Adam优化器。1234global_step = tf.Variable(0, name="global_step", trainable=False)optimizer = tf.train.AdamOptimizer(1e-4)grads_and_vars = optimizer.compute_gradients(cnn.loss)train_op = optimizer.apply_gradients(grads_and_vars, global_step=global_step) 在这里,train_op这里是一个新创建的操作,我们可以运行它来对我们的参数执行渐变更新。 train_op的每次执行都是一个训练步骤。 TensorFlow自动计算哪些变量是“可训练的”并计算它们的梯度。 通过定义一个global_step变量并将其传递给优化器,我们允许TensorFlow处理对我们的培训步骤的计数。 每次执行train_op时,全局步骤将自动递增1。 4.2 Summaries 摘要TensorFlow有一个Summaries,可以让您在培训和评估过程中跟踪和查看各种数量。 例如,您可能想要跟踪您的损失和准确性随时间的变化。 您还可以跟踪更复杂的数量,例如图层激活的直方图。 汇总是序列化的对象,它们使用SummaryWriter写入磁盘。 123456789101112131415161718# Output directory for models and summariestimestamp = str(int(time.time()))out_dir = os.path.abspath(os.path.join(os.path.curdir, "runs", timestamp))print("Writing to {}\\n".format(out_dir)) # Summaries for loss and accuracyloss_summary = tf.scalar_summary("loss", cnn.loss)acc_summary = tf.scalar_summary("accuracy", cnn.accuracy) # Train Summariestrain_summary_op = tf.merge_summary([loss_summary, acc_summary])train_summary_dir = os.path.join(out_dir, "summaries", "train")train_summary_writer = tf.train.SummaryWriter(train_summary_dir, sess.graph_def) # Dev summariesdev_summary_op = tf.merge_summary([loss_summary, acc_summary])dev_summary_dir = os.path.join(out_dir, "summaries", "dev")dev_summary_writer = tf.train.SummaryWriter(dev_summary_dir, sess.graph_def) 在这里,我们分别跟踪培训和评估的总结。 在我们的情况下,这些数量是相同的,但您可能只有在培训期间跟踪的数量(如参数更新值)。 tf.merge_summary是将多个摘要操作合并到可以执行的单个操作中的便利函数。 4.3 Checkpointing 检查点您通常想要使用的另一个TensorFlow功能是检查点 - 保存模型的参数以便稍后恢复。 检查点可用于稍后继续训练,或使用提前停止选择最佳参数设置。 使用Saver对象创建检查点。 1234567# Checkpointingcheckpoint_dir = os.path.abspath(os.path.join(out_dir, "checkpoints"))checkpoint_prefix = os.path.join(checkpoint_dir, "model")# Tensorflow assumes this directory already exists so we need to create itif not os.path.exists(checkpoint_dir): os.makedirs(checkpoint_dir)saver = tf.train.Saver(tf.all_variables()) 4.4 Initializing the variables初始化变量在我们可以训练我们的模型之前,我们还需要在图中初始化变量。1sess.run(tf.initialize_all_variables()) initialize_all_variables函数是一个方便的函数,运行我们为变量定义的所有初始化器。 您也可以手动调用变量的初始值。 如果您希望使用预先训练的值初始化嵌入,这很有用。 4.5Defining a single training step定义单一培训步骤现在我们来定义一个单一的训练步骤的功能,评估一批数据上的模型和更新模型参数。123456789101112131415def train_step(x_batch, y_batch): """ A single training step """ feed_dict = { cnn.input_x: x_batch, cnn.input_y: y_batch, cnn.dropout_keep_prob: FLAGS.dropout_keep_prob } _, step, summaries, loss, accuracy = sess.run( [train_op, global_step, train_summary_op, cnn.loss, cnn.accuracy], feed_dict) time_str = datetime.datetime.now().isoformat() print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy)) train_summary_writer.add_summary(summaries, step) feed_dict包含我们传递到我们网络的占位符节点的数据。您必须为所有占位符节点提供值,否则TensorFlow将抛出错误。使用输入数据的另一种方法是使用队列,但这超出了这篇文章的范围。 接下来,我们使用session.run执行我们的train_op,它返回我们要求它进行评估的所有操作的值。请注意,train_op什么都不返回,它只是更新我们网络的参数。最后,我们打印当前培训批次的损失和准确性,并将总结保存到磁盘。请注意,如果批量大小,培训批次的损失和准确性可能会有很大差异。而且因为我们使用辍学,您的培训指标可能开始比您的评估指标更差。 我们编写一个类似的函数来评估任意数据集的丢失和准确性,例如验证集或整个训练集。本质上这个功能与上述相同,但没有训练操作。它也禁用退学。12345678910111213141516def dev_step(x_batch, y_batch, writer=None): """ Evaluates model on a dev set """ feed_dict = { cnn.input_x: x_batch, cnn.input_y: y_batch, cnn.dropout_keep_prob: 1.0 } step, summaries, loss, accuracy = sess.run( [global_step, dev_summary_op, cnn.loss, cnn.accuracy], feed_dict) time_str = datetime.datetime.now().isoformat() print("{}: step {}, loss {:g}, acc {:g}".format(time_str, step, loss, accuracy)) if writer: writer.add_summary(summaries, step) 4.6 Training loop训练循环最后,我们准备好编写我们的训练循环。 我们迭代我们的数据批次,为每个批次调用train_step函数,并偶尔评估和检查我们的模型:123456789101112131415# Generate batchesbatches = data_helpers.batch_iter( zip(x_train, y_train), FLAGS.batch_size, FLAGS.num_epochs)# Training loop. For each batch...for batch in batches: x_batch, y_batch = zip(*batch) train_step(x_batch, y_batch) current_step = tf.train.global_step(sess, global_step) if current_step % FLAGS.evaluate_every == 0: print("\\nEvaluation:") dev_step(x_dev, y_dev, writer=dev_summary_writer) print("") if current_step % FLAGS.checkpoint_every == 0: path = saver.save(sess, checkpoint_prefix, global_step=current_step) print("Saved model checkpoint to {}\\n".format(path)) 这里,batch_iter是一个我写的批处理数据的帮助函数,而tf.train.global_step是返回global_step值的便利函数。 培训的完整代码也在这里提供。 5 Visualizing Results in TensorBoard 在TensorBoard中可视化结果我们的训练脚本将摘要写入输出目录,并通过将TensorBoard指向该目录,我们可以将图形和我们创建的摘要可视化。1tensorboard --logdir /PATH_TO_CODE/runs/1449760558/summaries/ 使用默认参数(128维嵌入,过滤器尺寸为3,4和5,每个过滤器尺寸为0.5和128个过滤器)的运行训练过程导致以下损失和精度图(蓝色是训练数据,红色为10% 开发数据)。 有几件事情脱颖而出: 我们的培训指标不顺利,因为我们使用小批量大小。 如果我们使用较大的批次(或在整个训练集上评估),我们将获得更平滑的蓝线。 因为开发者的准确性显着低于训练准确度,我们的网络似乎超过了训练数据,这表明我们需要更多的数据(MR数据集非常小),更强的正则化或更少的模型参数。 例如,我尝试在最后一层添加额外的L2惩罚权重,并能够将准确度提高到76%,接近于原始报告。 培训损失和准确性开始大大低于开发商指标,因为应用了退出。 您可以玩代码,并尝试运行具有各种参数配置的模型。 Github提供了代码和说明。 6 Extensions and Exercises扩展和练习以下是一些有用的练习,可以提高模型的性能: 使用预先训练的word2vec向量初始化嵌入。 为了使这项工作,您需要使用300维嵌入,并用预先训练的值初始化它们。 限制最后一层权重向量的L2范数,就像原始的纸张一样。 您可以通过定义一个新的操作,在每个培训步骤之后更新权重值。 将L2正规化添加到网络以防止过度配对,同时也提高辍学率。 (Github上的代码已经包括L2正则化,但默认情况下禁用) 添加重量更新和图层操作的直方图摘要,并在TensorBoard中进行可视化。","link":"/2017/09/06/在TensorFlow中实现文本分类的CNN/"},{"title":"实践篇(2):关系数据库到RDF","text":"简介在上一文章中我们定义了本体结构、并且把数据保存在mysql中,其ER图如下: 为了把RDB(关系型数据库)转换成RDF(三元组形式),同时把RDB中数据映射到我们定义的本体上面一一对应。 我们使用D2RQ工具将RDB数据转换到RDF形式。 D2RQ有一个比较方便的地方,可以根据已定义的数据库自动生成预定义的mapping文件,用户可以在mapping文件上修改,把数据映射到自己的本体上。 D2RQ 的框架如下图所示: 1. D2RQ下载安装d2rq的下载,查看如下官方网站:http://d2rq.org/ 2. D2RQ安装下载到喜欢的地方,解压即可算是安装,我的是解压到了D:\\Programming\\d2rq-0.8.1 3. D2RQ的使用3.1 D2RQ使用第一步:生成mapping D2RQ使用第一步:生成mapping文件: 下载D2RQ,进入其目录,运行下面的命令根据我们的mysql数据库生成的默认mapping文件(当前文件夹下): 1generate-mapping -u root -p root -o Hr_HG_QA_mapping.ttl jdbc:mysql:///hr_kg_qa_db 参数解读:root是mysql的用户名,没有密码则不输入,-o指定输出文件路径及名称,jdbc:mysql:///kg_demo_movie 指定我们要映射的数据库。 3.2 D2RQ使用第二步:修改mapping文件 D2RQ使用第二步:修改mapping文件 将mapping文件中的数据列名 对应到 我们设计的本体文件中。修改规则如下 首先,为了表达简练,我们给本体的IRI设置一个前缀。 1@prefix: <http://www.hr_kg_qa.com#> . 将数据库自动生成的id和label属性删除,因为我们不需要这两个属性。 vocab 这个我们不用,因此删除开头和正文中带有 vocab 的部分。 把默认的映射词汇改为我们本体.owl中的词汇即可:修改类型值,将vocab:xxxx修改为我们owl文件中定义的类 和属性。例如将d2rq:class vocab: Leave;修改为d2rq:class :Leave;(千万别忘记删除属性第三行的vocab) 将连接表(连接两个实体关系的表)属性从类d2rq:ClassMap改为属性d2rq:PropertyBridge 。在处理外键的时候要注意当前编辑的属性的domain和range,belongsToClassMap是domain,refersToClassMap是range。 123456789#这个例子是 外键 是自己表的主键, 该表必须与自身相连。需要用到d2rq:alias 声明自己map:leave_LeaveTogetherWith a d2rq:PropertyBridge; d2rq:belongsToClassMap map:leave; d2rq:property :LeaveTogetherWith; d2rq:refersToClassMap map:leave; d2rq:join "leave.LeaveTogetherWith => LeaveTogetherWith.id"; d2rq:alias "leave AS LeaveTogetherWith"; . 更多规则可参考:http://link.zhihu.com/?target=http%3A//d2rq.org/d2rq-language 3.3 D2RQ使用第三步:生成RDF文件 D2RQ使用第三步 根据修改后的mapping文件生成RDF 使用下面的命令将我们的数据转为RDF: 在D2RQ目录右键 shift -> 在此处打开命令窗口。运行以下命令,则在当前文件夹内生成 三原则文件:“Hr_HG_QA.nt ” 1dump-rdf.bat -o Hr_HG_QA.nt Hr_HG_QA_mapping.ttl 参数解读:.nt 这是rdf的一种保存格式 命令将数据转换为Ntriples。这一步比较慢,如果sql中的数据很多,则生成的文件也比较大,因此要做好预留空间。","link":"/2019/04/28/实践篇(2):关系数据库到RDF/"},{"title":"实践篇(3)RDF查询语言SPARQL","text":"本文转载自SimmerChan大神知乎文章:https://zhuanlan.zhihu.com/p/32703794 简介前面我们已经介绍过了语义网技术栈中的RDF,RDFS/OWL。这次我们介绍最 后一个核心技术标准——SPARQL(RDF,OWL和SPARQL称为语义网的三大核心技术)。RDF本质上是一种数据模型,那么我们如何在RDF上进行查询呢?类似使用SQL查询关系数据库,我们使用SPARQL查询RDF格式的数据。本文先简单介绍一下SPARQL的历史,然后结合我们实践篇的数据举几个具体的例子。 1. SPARQLSPARQL即SPARQL Protocol and RDF Query Language的递归缩写,专门用于访问和操作RDF数据,是语义网的核心技术之一。W3C的RDF数据存取小组(RDF Data Access Working Group, RDAWG)对其进行了标准化。在2008年,SPARQL 1.0成为W3C官方所推荐的标准。2013年发布了SPARQL 1.1。相对第一个版本,其支持RDF图的更新,提供更强大的查询,比如:子查询、聚合操作(像我们常用的count)等等。 从SPARQL的全称我们可以知道,其由两个部分组成:协议和查询语言。 查询语言很好理解,就像SQL用于查询关系数据库中的数据,XQuery用于查询XML数据,SPARQL用于查询RDF数据。 协议是指我们可以通过HTTP协议在客户端和SPARQL服务器(SPARQL endpoint)之间传输查询和结果,这也是和其他查询语言最大的区别。 一个SPARQL查询本质上是一个带有变量的RDF图,以我们之前提到的罗纳尔多RDF数据为例: 1<http://www.kg.com/person/1> <http://www.kg.com/ontology/chineseName> "罗纳尔多·路易斯·纳萨里奥·德·利马"^^string. 我们把属性值用变量代替(SPARQL中,用问号加变量名的方式来表示一个变量。),即: 1<http://www.kg.com/person/1> <http://www.kg.com/ontology/chineseName> ?x. SPARQL查询是基于图匹配的思想。我们把上述的查询与RDF图进行匹配,找到符合该匹配模式的所有子图,最后得到变量的值。就上面这个例子而言,在RDF图中找到匹配的子图后,将”罗纳尔多·路易斯·纳萨里奥·德·利马”和“?x”绑定,我们就得到最后的结果。简而言之,SPARQL查询分为三个步骤: 构建查询图模式,表现形式就是带有变量的RDF。 匹配,匹配到符合指定图模式的子图。 绑定,将结果绑定到查询图模式对应的变量上。 2、例子以实践篇的RDF电影数据为例,我们介绍如何利用SPARQL查询: 所有的RDF三元组。 周星驰出演了哪些电影? 英雄这部电影有哪些演员参演? 巩俐参演的评分大于7的电影有哪些? 如何查询所有数据?参照我们在第一个部分介绍的查询过程,查询所有数据即我们没有任何已知值,SPO三元组每个都是未知变量。对应的SPARQL查询语言为: 123456789101112PREFIX : <http://www.kgdemo.com#>PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>PREFIX owl: <http://www.w3.org/2002/07/owl#>PREFIX xsd: <XML Schema>PREFIX vocab: <http://localhost:2020/resource/vocab/>PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>PREFIX map: <http://localhost:2020/resource/#>PREFIX db: <http://localhost:2020/resource/>SELECT * WHERE { ?s ?p ?o} SPARQL的部分关键词: SELECT, 指定我们要查询的变量。在这里我们查询所有的变量,用*代替。 WHERE,指定我们要查询的图模式。含义上和SQL的WHERE没有区别。 FROM,指定查询的RDF数据集。我们这里只有一个图,因此省去了FROM关键词。 PREFIX,用于IRI的缩写。 例子:“周星驰出演了哪些电影”: 123456789101112131415PREFIX : <http://www.kgdemo.com#>PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>PREFIX owl: <http://www.w3.org/2002/07/owl#>PREFIX xsd: <XML Schema>PREFIX vocab: <http://localhost:2020/resource/vocab/>PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>PREFIX map: <http://localhost:2020/resource/#>PREFIX db: <http://localhost:2020/resource/>SELECT ?n WHERE { ?s rdf:type :Person. ?s :personName '周星驰'. ?s :hasActedIn ?o. ?o :movieTitle ?n} 部分结果: 12345678910111213n"功夫""琉璃樽""英雄本色""少林足球""西游记第壹佰零壹回之月光宝盒""长江七号""西游记大结局之仙履奇缘""建国大业""审死官""龙在天涯""大内密探零零发" 就我们这个例子而言,可以不要“?s rdf:type :Person”,这里只是让查询图更具体(在拥有复杂关系的RDF图中,可能会存在不同的类拥有相同的属性名。比如,猫和狗名字的属性名都是”name”,我们想查询一只叫汤姆的猫;如果不指定类型,返回结果可能也包含一只叫汤姆的狗)。图模式中,每个RDF用英文句号进行分割。 例子2:“巩俐参演的评分大于7的电影有哪些”: 1234567891011121314151617PREFIX : <http://www.kgdemo.com#>PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>PREFIX owl: <http://www.w3.org/2002/07/owl#>PREFIX xsd: <XML Schema>PREFIX vocab: <http://localhost:2020/resource/vocab/>PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>PREFIX map: <http://localhost:2020/resource/#>PREFIX db: <http://localhost:2020/resource/>SELECT ?n WHERE { ?s rdf:type :Person. ?s :personName '巩俐'. ?s :hasActedIn ?o. ?o :movieTitle ?n. ?o :movieRating ?r.FILTER (?r >= 7)} 结果: 12345678910111213141516n"2046""Memoirs of a Geisha""荆轲刺秦王""大红灯笼高高挂""霸王别姬""活着""唐伯虎点秋香""秋菊打官司""菊豆""Hong gao liang""画魂""风月""Piao Liang Ma Ma""The Hand" 这里我们用到了FILTER关键词,可以对变量取值进行约束。 SPARQL更详细的语法和功能这里就不再多做介绍。读者可以参考W3C的文档或者SPARQL查询的例子。 3开放域假设另外多提一点,关于知识图谱,有一个非常重要的概念,即开放世界假定(Open-world assumption,OWA)。这个假定的意思是当前没有陈述的事情是未知的,或者说知识图谱没有包含的信息是未知的。怎么理解?首先我们要承认知识图谱无法包含所有完整的信息。以我们这个电影数据的例子而言,很明显,它的数据十分残缺。即使我们拥有一个十分完整的电影知识图谱,包含了当下所有的电影、演员等信息,在现实世界中,信息也是动态变化和增长的。即,我们要承认知识图谱的信息本身就是残缺的。有了这个前提,我们来思考例子中的第二个SPARQL语句: 周星驰出演了上述查询结果中的电影。基于我们构建的电影知识图谱,提问:周星驰出演了《卧虎藏龙》吗?根据OWA,我们得到的答案是“不知道”,相反,如果是封闭世界假定(Closed-world assumption),我们得到的答案是“没有出演”。 我们在设计本体和开发相关应用的时候需要考虑开放世界假定。举个简单的例子,基于知识图谱的问答系统,用户提问“周星驰出演了《卧虎藏龙》吗?”,合适的回答是“不知道”而不是“没有出演”。直觉上这和一个人向另一个人提这个问题一样,如果我们知道问题答案,我们会给出肯定的回答,不知道的话,我们往往倾向于回复“我不知道”,“我不太清楚”,“我查查看”,而不是信誓旦旦地回答“没有出演”。毕竟,大多数人都有“自知之明”,知道自己总有不了解的东西。从这个角度上说,人和知识图谱类似,我们都存在于OWA的世界中。 4、总结本文主要介绍了RDF查询语言SPARQL及其基本用法,希望能让读者对SPARQL有个初步的认识。下一篇文章是实践篇,介绍如何利用D2RQ创建SPARQL endpoint并在我们的数据上进行相关查询。","link":"/2019/04/29/实践篇(3)RDF查询语言SPARQL/"},{"title":"实践篇(4):Apache jena SPARQL endpoint及推理","text":"本文主要参考SimmerChan大神文章:https://zhuanlan.zhihu.com/p/33224431 做了一些版本更新 0 前言在上一步,我们得到了.nt格式的三元组文件。并且学会了如果使用sparsql语句进行三元组查询。 在这篇文章我们将利用框架实现对三元组知识的查询。 我们知道SPARQL是我们最常用的查询三元组的工具,那么我们需要一个平台,这个平台既可以在下层存储三元组,又可以在上层提供SPARQL endpoint接口 让我们写SPARQL语句来查询。 这样一个平台就是JENA。 1 JENA简介APACHE JENA,一款免费的JAVA开源框架,用来做语义网(Semantic Web)和数据连接(Linked Data)的应用。Jena支持的RDF格式数据,是一套NoSQL(非关系数据库)、一套可推理的图数据库。Jena框架将这类数据的存储、添加、删除、推理,查询(Sparql)等所有的操作封装进一个框架,大大的方便了做相关应用的开发和使用。 参考: http://www.flykun.com/jena%E6%89%8B%E5%86%8C-%E5%85%A5%E9%97%A8/ 1.1 Jena框架的架构Jena是一个框架,则必然有其架构,让我们从下面这个官网提供的架构图来了解Jena结构,了解其在我们应用开发中的位置,是一个非常好的开始。 从这个架构图来看,应用程序的入口可以分为4个主要部分: The RDF API – 核心管理模块,对RDF进行添加、删除和修改; SPARQL – 查询模块,提供SPARQL语句,查询,管理RDF,类似SQL语句。 Inference – 推理模块,介绍如何使用推理机对RDF进行推理。 TDB – 存储模块,一个高效的硬盘存储方案,有别于内存存储,这个更加便于对大数据进行操作。 2 JENA下载安装2.1 官网下载在官网下载( https://jena.apache.org/download/index.cgi )。注意要同时下载apache-jena和apache-jena-fuseki两个包,下载方式如下:(建议下载3.7版本的) 2.2 安装(解压即可)下载好之后分别解压到D盘,(地址无所谓,可以解压到java所在的目录,方便记忆): 注意java版本必须高于1.8 3 使用jena进行查询三元组 实战3.1 导入jena需要的三元组信息(也可以不用这一步)TDB 是Jena用于存储RDF的组件,是属于存储层面的技术。在单机情况下,它能够提供非常高的RDF存储性能。 我们必须将之前得到的.nt格式的三元组转化为TDB格式的。步骤如下 首先,拿到我们之前得到的.nt格式的三元组文件,比如: 1D:\\Programming\\d2rq-0.8.1\\Hr_HG_QA.nt 在“apache-jena-3.7.0”文件夹下创建一个子文件夹(我这里命名为“test-tdb”)用于存放tdb数据。 进入“apache-jena-3.7.0”文件夹的bat目录,可以看到很多批处理文件,我们使用“tdbloader.bat”将之前我们的RDF数据以TDB的方式存储。 在这个文件夹按住键盘shift并点击鼠标右键 -> 在此处打开命令行,输入命令如下: 1tdbloader.bat --loc="D:\\Programming\\apache-jena-3.7.0\\test-tdb" "D:\\Programming\\d2rq-0.8.1\\Hr_HG_QA.nt" 其中,“–loc”指定tdb文件存储的位置,即刚才我们创建的文件夹;第二个参数是我们之前由Mysql数据转换得到的RDF数据。 这样在整个3.1这一节,我们就得到了 jena 所需的TBD格式的三元组文件。 3.2 添加本体数据 使用jena这样一个框架,而不是直接将rdf数据导入图数据库,其中一个主要原因是:jena支持OWL语言的推理,可以按照你自己定义的本体类型和推理规则 方便的进行简单推理。 这一步我们 添加之前使用protege创建的本体文件。 进入D盘“apache-jena-fuseki”文件夹, 双击运行“fuseki-server.bat”,程序会为我们在当前目录自动创建“run”文件夹。 然后关闭命令窗。 我们之前通过protege设计得到的本体文件,按照turtle syntax 格式保存,得到hr-kg-ontology-en-turtle.owl 使用记事本打开,一定要把 1@prefix hr_kg_ontology: <http://www.hr_kg_qa.com#> . 改为自己的前缀,与上一步的三元组的@prefix对应 将“hr-kg-ontology-en-turtle.owl”移动到“fuseki/run”文件夹下的“databases”文件夹中。 并直接将“owl”后缀名改为“ttl”。即hr-kg-ontology-en-turtle.owl.ttl 3.3 fuseki服务器配置在“run”文件夹下的“configuration”中,我们创建名为“fuseki_conf.ttl”的文本文件(取名没有要求),加入如下内容: ==注意,千万别忘记修改 本体文件地址 为你本机的地址!== 12345678910111213141516171819202122232425262728293031323334353637383940@prefix : <http://base/#> .@prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .@prefix tdb2: <http://jena.apache.org/2016/tdb#> .@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .@prefix fuseki: <http://jena.apache.org/fuseki#> .<#service1> rdf:type fuseki:Service ; fuseki:name "Hr_HG_QA" ; fuseki:serviceQuery "sparql", "query" ; fuseki:serviceReadGraphStore "get" ; fuseki:serviceReadWriteGraphStore "data" ; fuseki:serviceUpdate "update" ; fuseki:serviceUpload "upload" ; fuseki:dataset <#dataset> ; .<#dataset> rdf:type ja:RDFDataset ; ja:defaultGraph # 这样做可以不抱错。 [ a ja:MemoryModel ; # 加载本体文件 ja:content [ja:externalContent <file:///D:/Programming/apache-jena-fuseki-3.7.0/run/databases/hr-kg-ontology-en-turtle.ttl> ] ; # 不用jena转换,直接加载三元组 ja:content [ja:externalContent <file:///D:/Programming/d2rq-0.8.1/Hr_HG_QA.nt> ] ; ] ; .<#model_inf> a ja:InfModel ; #打开OWL推理机 ja:reasoner [ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner>] ; #关闭规则推理机,并指定规则文件路径 #ja:reasoner [ ja:reasonerURL <http://jena.hpl.hp.com/2003/GenericRuleReasoner> ; # ja:rulesFrom <file:///D:/Programming/apache-jena-fuseki-3.7.0/run/databases/rules.ttl> ] ; . ==注意,千万别忘记修改 本体文件地址、三元组TDB 为你本机的地址! 这一步可以先把推理机 那两行注销掉== 3.4 运行服务器检验再次运行“fuseki-server.bat”,如果在命令窗中没有error则算成功。 Fuseki默认的端口是3030,打开浏览器输入: http://localhost:3030/ ,我们可以进行SPARQL查询等操作。在Python中用SPARQLWrapper向Fuseki server发送查询请求: 12345678PREFIX : <http://www.kgdemo.com#>PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>SELECT * WHERE {?x :movieTitle '功夫'.?x ?p ?o.} 即查询电影《功夫》的所有属性。返回的结果: 123456789101112131415161718192021222324252627282930 x p o file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasGenre file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#genre/14 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasGenre file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#genre/28 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasGenre file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#genre/35 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasGenre file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#genre/80 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://www.kgdemo.com#Movie file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#movieRating 7.2E0 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#movieIntroduction 1940年代的上海,自小受尽欺辱的街头混混阿星(周星驰)为了能出人头地,可谓窥见机会的缝隙就往里钻,今次他盯上行动日益猖獗的黑道势力“斧头帮”,想借之大名成就大业。 阿星假冒“斧头帮”成员试图在一个叫“猪笼城寨”的地方对居民敲诈,不想引来真的“斧头帮”与“猪笼城寨”居民的恩怨。“猪笼城寨”原是藏龙卧虎之处,居民中有许多身怀绝技者(元华、梁小龙等),他们隐藏于此本是为远离江湖恩怨,不想麻烦自动上身,躲都躲不及。而在观战正邪两派的斗争中,阿星逐渐领悟功夫的真谛。 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#movieTitle 功夫 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#movieReleaseDate 2004-02-10 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://www.w3.org/2002/07/owl#Thing file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/25251 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/57609 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/118745 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/57607 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/65975 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/78878 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/83635 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/119426 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/545277 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/576408 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1136808 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1173200 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1173216 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1173223 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1173224 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1287732 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.kgdemo.com#hasActor file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1676386 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://www.w3.org/2000/01/rdf-schema#Resource file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 http://www.w3.org/2002/07/owl#sameAs file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#movie/9470 3.5 可能会报错:运行fuseki-server.bat” 命令窗中很可能会报错: 123Server ERROR Exception in initialization: the loading of content intofile:///D:/AppsPath/apache-jena-fuseki-3.8.0/run/configuration/fuseki_conf.ttl#model_inf was aborted because of Read-only object file 3.5.1 原因:这是由于fuseki版本升级所导致的问题:jena版本高于3.7的时候 InfModel里baseModel和content属性两者不兼容。 3.5.2 解决办法:两种办法,第一种重新下载jena低版本的(比如3.7)。 但这也不是长远的办法。 第二种办法:将content注释掉(前面加#),也就是暂时不上传本体文件,等服务器成功启动后,再手动上传本体文件,即: 第一步:将content注释掉12#本体文件的路径#ja:content [ja:externalContent <file:///D:/Programming/apache-jena-fuseki-3.7.0/run/databases/ontology.ttl>] ; 第二步:手动上传本体步骤 注意 如果注释了content本体文件,并且不手动上传,则无法推理。比如:电影的“hasActor”属性是通过OWL推理机得到的,即我们原本的RDF数据里面是没有的。 3.5.3 解决办法2使用新版本的配置方式ja:MemoryModel ; 避免了加载冲突。 并且同步加载 本体和 三元组。 12345678<#dataset> rdf:type ja:RDFDataset ; ja:defaultGraph [ a ja:MemoryModel ; ja:content [ja:externalContent <file:///D:/Programming/apache-jena-fuseki-3.7.0/run/databases/hr-kg-ontology-en-turtle.ttl> ] ; ja:content [ja:externalContent <file:///D:/Programming/d2rq-0.8.1/Hr_HG_QA.nt> ] ; ] ; . 这样 优点:不要每次都 重新加载。 缺点:经过实践,发现丧失了 推理能力。 删除tdb路径下所有prefixXXX文件,就可以启动fuseki服务。(再次启动会重新生成这些文件,不用担心) 优点: 可以推理 但是每次都得自己删除prefixXXX 参考:https://blog.csdn.net/u012052268/article/details/88919129 3.5.4 解决办法34 jena规则推理实战 参考 :https://www.zhihu.com/question/47323119 除了使用protege进行简单推理,我们还可以使用jena的推理机进行复杂规则的推理,比如要实现以下推理: 1如果有一个演员,出演了一部喜剧电影,那么他就是一位喜剧演员 4.1 编写推理文件在“databases”文件夹下新建一个文本文件“rules.ttl”,填入如下内容: 12345678@prefix : <http://www.kgdemo.com#> .@prefix owl: <http://www.w3.org/2002/07/owl#> .@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .@prefix xsd: <XML Schema> .@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .[ruleComedian: (?p :hasActedIn ?m) (?m :hasGenre ?g) (?g :genreName '喜剧') -> (?p rdf:type :Comedian)][ruleInverse: (?p :hasActedIn ?m) -> (?m :hasActor ?p)] 在上面这个文件里我们定义了一个名为“ruleComedian”的规则, 它的意思是:如果有一个演员,出演了一部喜剧电影,那么他就是一位喜剧演员。 接下来,如果想让这个规则文件生效,则需要修改配置文件“fuseki_conf.ttl”: 4.2 配置推理机修改配置文件“fuseki_conf.ttl中关于推理机的代码: 关闭OWL推理机,开启规则推理机。 123456#关闭OWL推理机 #ja:reasoner [ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner>] #开启规则推理机,并指定规则文件路径 ja:reasoner [ ja:reasonerURL <http://jena.hpl.hp.com/2003/GenericRuleReasoner> ; ja:rulesFrom <file:///D:/Java/apache-jena-fuseki-3.7.0/run/databases/rules.ttl> ] ; 我们只能启用一种推理机。前面也提到,OWL的推理功能也可以在规则推理机里面实现,因此我们定义了“ruleInverse”来表示“hasActedIn”和“hasActor”的相反关系。更多细节读者可以参考文档。 也就是说,如果你习惯于用protege的规则,就不要开启这种推理机。还是用之前的owl推理机比较好。 此时,我们执行如下SPARQL查询,喜剧演员有哪些: 123456789PREFIX : <http://www.kgdemo.com#>PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>SELECT * WHERE {?x rdf:type :Comedian.?x :personName ?n.}limit 10 查询结果: 1234567891011x n file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/111298 郑丹瑞 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/70591 陈欣健 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/116351 沈殿霞 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/116052 鲍汉琳 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1002925 张同祖 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/62423 林正英 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1614091 林琪欣 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/224929 陈法蓉 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/1135398 叶世荣 file:///D:/d2rq/d2rq-0.8.1/kg_demo_movie.nt#person/119426 元秋 4.3 如果推理机无法使用: 参考文献:https://blog.csdn.net/qingdujun/article/details/82501166 参考文献:https://stackoverflow.com/questions/52204735/no-data-available-in-table-when-i-customize-the-rules-of-jena-fuseki 在阅读《实践篇(四):Apache jena SPARQL endpoint及推理》 一文后, 发现最新版本 JENA FUSEKI (v3.8.0)自定义推导功能无法正常使用。 造成该问题,主要两大缘由: 其一,推导规则(rules.ttl)需要用逗号隔开。123456@prefix : <http://www.kgdemo.com#> .@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .[ruleComedian: (?p :hasActedIn ?m), (?m :hasGenre ?g), (?g :genreName '喜剧') -> (?p rdf:type :Comedian)][ruleInverse: (?p :hasActedIn ?m) -> (?m :hasActor ?p)] 其二,配置问题。以下为查阅官网后,重写的配置文件(fuseki_conf.ttl)。配置的主要解析过程为, 1service>dataset>defaultGraph>infModel> 也就是 根据fuseki_conf.ttl文件中的<# > 符号来确定的, 每两个一组,守卫照应,且每段结束的时候有一个小数点结尾。 5 总结本次实践介绍了如何使用Jena来开启endpoint服务,提供高效的查询;并介绍了如何加入推理引擎。我们是用Jena提供的命令行工具来完成上述操作。实际上,jena提供了所有工具的API接口,读者可以用Java编写程序,进行开发。相关文件已上传至github。大家都可以按照这个学习。 最后,衷心真心感谢SimmerChan的文章和代码,我和我的小伙伴都是看你的文章代码入门,多谢! 5.1 附件附件一:可以推理,但是每次tdb都要重新删除prefixXXX文件。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546@prefix : <http://base/#> .@prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .@prefix tdb2: <http://jena.apache.org/2016/tdb#> .@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .@prefix fuseki: <http://jena.apache.org/fuseki#> .<#service1> rdf:type fuseki:Service ; fuseki:name "Hr_HG_QA" ; fuseki:serviceQuery "sparql", "query" ; fuseki:serviceReadGraphStore "get" ; fuseki:serviceReadWriteGraphStore "data" ; fuseki:serviceUpdate "update" ; fuseki:serviceUpload "upload" ; fuseki:dataset <#dataset> ; .<#dataset> rdf:type ja:RDFDataset ; ja:defaultGraph <#model_inf> ; .<#model_inf> a ja:InfModel ; #本体文件的路径 ja:content [ja:externalContent <file:///D:/Programming/apache-jena-fuseki-3.7.0/run/databases/hr-kg-ontology-en-turtle.ttl>] ; #打开OWL推理机 ja:reasoner [ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner>] ; #开启规则推理机,并指定规则文件路径 #ja:reasoner [ ja:reasonerURL <http://jena.hpl.hp.com/2003/GenericRuleReasoner> ; # ja:rulesFrom <file:///D:/Programming/apache-jena-fuseki-3.7.0/run/databases/rules.ttl> ] ; # 基本的模型 ja:baseModel <#tdbGraph> ; . <#tdbGraph> rdf:type tdb:GraphTDB ; tdb:dataset <#tdbDataset> ; . <#tdbDataset> rdf:type tdb:DatasetTDB ; tdb:location "D:/Programming/apache-jena-3.7.0/test-tdb" ; . 附件二:每次不用重新载入,但是无法推理。 12345678910111213141516171819202122232425262728293031323334353637383940@prefix : <http://base/#> .@prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .@prefix tdb2: <http://jena.apache.org/2016/tdb#> .@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .@prefix fuseki: <http://jena.apache.org/fuseki#> .<#service1> rdf:type fuseki:Service ; fuseki:name "Hr_HG_QA" ; fuseki:serviceQuery "sparql", "query" ; fuseki:serviceReadGraphStore "get" ; fuseki:serviceReadWriteGraphStore "data" ; fuseki:serviceUpdate "update" ; fuseki:serviceUpload "upload" ; fuseki:dataset <#dataset> ; .<#dataset> rdf:type ja:RDFDataset ; ja:defaultGraph # 这样做可以不抱错。 [ a ja:MemoryModel ; # 加载本体文件 ja:content [ja:externalContent <file:///D:/Programming/apache-jena-fuseki-3.7.0/run/databases/hr-kg-ontology-en-turtle.ttl> ] ; # 不用jena转换,直接加载三元组 ja:content [ja:externalContent <file:///D:/Programming/d2rq-0.8.1/Hr_HG_QA.nt> ] ; ] ; .<#model_inf> a ja:InfModel ; #打开OWL推理机 ja:reasoner [ja:reasonerURL <http://jena.hpl.hp.com/2003/OWLFBRuleReasoner>] ; #关闭规则推理机,并指定规则文件路径 #ja:reasoner [ ja:reasonerURL <http://jena.hpl.hp.com/2003/GenericRuleReasoner> ; # ja:rulesFrom <file:///D:/Programming/apache-jena-fuseki-3.7.0/run/databases/rules.ttl> ] ; .","link":"/2019/04/30/实践篇(4):Apache jena SPARQL endpoint及推理/"},{"title":"实践篇(5):基于REfO的简单知识问答","text":"本文主要参考SimmerChan大神文章:https://zhuanlan.zhihu.com/p/33224431Pelhans 大神的博客:http://pelhans.com/2018/09/03/kg_from_0_note3/ 1 简介基于浙江大学在openKG上提供的 基于REfO的KBQA实现及示例。代码部分浙大方面已经完成绝大部分,这里主要将其应用到自己的知识图谱上。在运行KBQA代码前,应按照前面的教程将电影类知识图谱导入到Jena的TDB数据库中,并运行fuseki服务器,这样我们才能进行访问查询。 1.1代码结构123456789101112jena_sparql_endpoint.py query_main.py question2sparql.py question_temp.py word_tagging.py external_dict/ csv2txt.py movie_title.csv movie_title.txt person_name.csv person_name.txt __init__.py “KB_query”文件夹包含的是完成整个问答demo流程所需要的脚本。 “external_dict”包含的是人名和电影名两个外部词典。csv文件是从mysql-workbench导出的,按照jieba外部词典的格式,我们将csv转为对应的txt。 “word_tagging”,定义Word类的结构(即我们在REfO中使用的对象);定义”Tagger”类来初始化词典,并实现自然语言到Word对象的方法。 “jena_sparql_endpoint”,用于完成与Fuseki的交互。 “question2sparql”,将自然语言转为对应的SPARQL查询。 “question_temp”,定义SPARQL模板和匹配规则。 “query_main”,main函数。 在运行”query_main”之前,读者需要启动Fuseki服务,具体方法请参考上一篇文章。 1.2 展示: 2具体实现基于REfO的简单知识问答的原理很简单,就是通过REfo提供的匹配能力,在输入的自然语言问题中进行匹配查找。如果找到我们预先设定的词或词性组合,那么就认为该问题与这个词或词性组合匹配。而一个词或词性的组合又对应着一个SPARQL查询模板,这样我们就借助REfO完成了自然语言到查询模板的转换。得到查询模板后,我们就利用Jena fuseki 服务器提供的端口进行查询得到返回的结果。 2.1 模块一 word_tagging部分该部分利用jieba分词对中文句子进行分词和词性标注。将词的文本和词性进行打包,视为词对象,对应 :class:Word(token, pos)。 123456789101112131415class Word(object): def __init__(self, token, pos): self.token = token self.pos = pos class Tagger: def __init__(self, dict_paths): # TODO 加载外部词典 for p in dict_paths: jieba.load_userdict(p) def get_word_objects(self, sentence): """ Get :class:WOrd(token, pos) """ return [Word(word.encode('utf-8'), tag) for word, tag in pseg.cut(sentence)] 2.2 模块二 rules 部分该部分为程序核心,负责将自然语言转换为SPARQL模板。 下面为rules的程序入口,customize_rules 函数: 12345678910111213141516171819202122def customize_rules(): # some rules for matching # TODO: customize your own rules here person = (W(pos="nr") | W(pos="x") | W(pos="nrt")) movie = (W(pos="nz")) place = (W("出生地") | W("出生")) intro = (W("简介") | W(pos="介绍")) rules = [ Rule(condition=W(pos="r") + W("是") + person | \\ person + W("是") + W(pos="r"), action=who_is_question), Rule(condition=person + Star(Any(), greedy=False) + place + Star(Any(), greedy=False), action=where_is_from_question), Rule(condition=movie + Star(Any(), greedy=False) + intro + Star(Any(), greedy=False) , action=movie_intro_question) ] return rules 该函数中我们设置了一些简单的匹配规则,例如我们设置 ‘’’movie = (W(pos=”nz”))’’‘,即movie 的词性应该是nz。其中的W()是我们在继承REfO的Predicate方法的基础上扩展更新了match方法。您可以简单的把它理解为re中compile后的match,只不过多个W()间出现的顺序可以变化。这样通过多个定制的W()和Star(Any(), greedy=False)(相当于.*?)这种通配符的组合,我们就定义了一组匹配规则,当遇到符合该规则的句子时,就选取该规则后action对应的查询模板。 例如当输入为“周星驰是谁”这样的问题时,会匹配到rules 中的 第一条规则。而后执行该规则后对应的action, who_is_question。而who_is_question对应的查询模板为: 12345678910111213def who_is_question(x): select = u"?x0" sparql = None for w in x: if w.pos == "nr" or w.pos == "x": e = u" ?a :actor_chName '{person}'. \\n \\ ?a :actor_bio ?x0".format(person=w.token.decode("utf-8")) sparql = SPARQL_TEM.format(preamble=SPARQL_PREAMBLE, select=select, expression=INDENT + e) break return sparql 有了查询模板后,我们通过SPARQLWrapper 模块的SPARQLWrapper 执行该查询,并对返回的结果进行转换得到回答。对应的代码如下: 12345678910111213141516171819202122232425262728293031323334from SPARQLWrapper import SPARQLWrapper, JSON from utils.word_tagging import Taggerfrom utils.rules import customize_rules if __name__ == "__main__": print("init...........") sparql_base = SPARQLWrapper("http://localhost:3030/kg_demo_movie/query") #加载外部词典,提升分词准确性和词性标注准确性 tagger = Tagger(['data/actorName.txt', 'data/movieName.txt']) #初始化并获取规则列表 rules = customize_rules() print("done \\n") while True: print("Please input your question: ") default_question = raw_input() # 获取wordclass seg_list = tagger.get_word_objects(default_question) for rule in rules: # 将规则列表应用到问题上得到查询模板 query = rule.apply(seg_list) if query: # 设置查询相关 sparql_base.setQuery(query) sparql_base.setReturnFormat(JSON) # 得到返回结果并做转换 results = sparql_base.query().convert() if not results["results"]["bindings"]: print("No answer found :(") continue for result in results["results"]["bindings"]: print "Result: ", result["x0"]["value"]","link":"/2019/05/01/实践篇(5):基于REfO的简单知识问答/"},{"title":"破解myeclipse10时找不到myeclipse-Common-plusgin","text":"1.注册账户以及创建仓库要想使用github第一步当然是注册github账号了。之后就可以创建仓库了。步骤如下: 打开https://github.com 直接在首页上注册 点按钮注册成功之后,在页面上方用户菜单上选择 “+”->New repository 创建一个新的仓库。 为仓库取一个名字,点击创建仓库按钮 你将成功创建一个仓库。 2.安装git客户端github是服务端,要想在自己电脑上使用git我们还需要一个git客户端, windows用户请下载 http://msysgit.github.com/ mac用户请下载 http://code.google.com/p/tortoisegit/ 一路next,安装成功后, 回到C盘,或任何文件夹下,点鼠标右键会多出一些菜单如 Git Bash、Git Init Hear(新版本消失)、Git Gui , 说明安装成功。 3.配置Git我们先在电脑硬盘里找一块地方存放本地仓库,比如我们把本地仓库建立在C:\\MyRepository\\1ke_test文件夹下(自己选择文件夹,可以在D盘,推荐在github安装目录下) 进入1ke_test文件夹 鼠标右键操作如下步骤: 1)设定主目录在本地仓库里右键选择Git Bash进入git命令行,截图效果如下: 为了设定此目录为主目录!!我们先执行git init命令(github将以此文件夹为据点) 1$ git init (输入时 去掉$号) 为了把本地的仓库传到github,还需要配置ssh key!!!!用于建立本地到github的连接. 2)在本地创建ssh key1$ ssh-keygen -t rsa -C "[email protected]" 后面的[email protected]改为你的邮箱。我的邮箱是[email protected],也是在github上注册的那个邮箱: 直接点回车,说明会在默认文件id_rsa上生成ssh key。 然后系统要求输入密码,直接按回车表示不设密码 重复密码时也是直接回车,之后提示你shh key已经生成成功。 然后我们进入提示的地址下查看ssh key文件。 我的电脑的地址是C:\\Users\\lilu\\.ssh ,其中lilu是我的电脑的名称 打开id_rsa.pub,复制里面的key。里面的key是一对看不懂的字符数字组合,不用管它,直接复制。 回到github网站,进入Account Settings,左边选择SSH Keys,Add SSH Key, title随便填,粘贴key。 3)验证是否成功在git bash下输入 1$ ssh -T [email protected] 回车就会看到:You’ve successfully authenticated, but GitHub does not provide shell access 。这就表示已成功连上github。 4)设置username和email接下来我们要做的就是把本地仓库传到github上去,在此之前还需要设置username和email,因为github每次commit都会记录他们。 12$ git config --global user.name "your name"$ git config --global user.email "[email protected]" 分别输入上述命令行 回车, 我的界面显示如下 5)连接本地与github进入要上传的仓库,右键git bash,添加远程地址 1$ git remote add origin [email protected]:yourName/yourRepo.git 后面的yourName和yourRepo表示你再github的用户名和刚才新建的仓库,加完之后进入.git,打开config,这里会多出一个remote “origin”内容,这就是刚才添加的远程地址,也可以直接修改config来配置远程地址。 与github上的对应 4.提交上传1)在本地仓库添加一些文件接下来在本地仓库里添加一些文件,比如README 在本地新建一个README文件(或者复制你的代码项目) 2)上传到本地缓存服务器在命令行输入一下命令 123$ git add README$ git commit -m "first commit" 执行界面如下 3)上传到github如果这是第一次上传(push)到github的这个项目里。 上传之前,需要先将github上已有数据的拉取到本地,这样才能比较你上传过后的与之前的数据的区别。 1)拉取(pull)服务器数据指令:1git pull origin master --allow-unrelated-histories 此时,我们发现,将服务器上的readme给下载下来了。正和我们意。 2) 上传到github指令: 1$ git push origin master git push命令会将本地仓库推送到远程服务器。 git pull命令则相反。 5.常用Git命令查看、添加、提交、删除、找回,重置修改文件 1234567891011121314151617181920212223242526272829git help <command> # 显示command的helpgit show # 显示某次提交的内容 git show $idgit co -- <file> # 抛弃工作区修改git co . # 抛弃工作区修改git add <file> # 将工作文件修改提交到本地暂存区git add . # 将所有修改过的工作文件提交暂存区git rm <file> # 从版本库中删除文件git rm <file> --cached # 从版本库中删除文件,但不删除文件git reset <file> # 从暂存区恢复到工作文件git reset -- . # 从暂存区恢复到工作文件git reset --hard # 恢复最近一次提交过的状态,即放弃上次提交后的所有本次修改git ci <file> git ci . git ci -a # 将git add, git rm和git ci等操作都合并在一起做 git ci -am "some comments"git ci --amend # 修改最后一次提交记录git revert <$id> # 恢复某次提交的状态,恢复动作本身也创建次提交对象git revert HEAD # 恢复最后一次提交的状态 查看文件diff 1234567891011git diff <file> # 比较当前文件和暂存区文件差异 git diffgit diff <id1><id2> # 比较两次提交之间的差异git diff <branch1>..<branch2> # 在两个分支之间比较git diff --staged # 比较暂存区和版本库差异git diff --cached # 比较暂存区和版本库差异git diff --stat # 仅仅比较统计信息 查看提交记录 1234567git log git log <file> # 查看该文件每次提交记录git log -p <file> # 查看每次详细修改内容的diffgit log -p -2 # 查看最近两次详细修改内容的diffgit log --stat #查看提交统计信息 tig Mac上可以使用tig代替diff和log,brew install tig Git 本地分支管理查看、切换、创建和删除分支 1234567891011121314151617181920212223git br -r # 查看远程分支git br <new_branch> # 创建新的分支git br -v # 查看各个分支最后提交信息git br --merged # 查看已经被合并到当前分支的分支git br --no-merged # 查看尚未被合并到当前分支的分支git co <branch> # 切换到某个分支git co -b <new_branch> # 创建新的分支,并且切换过去git co -b <new_branch> <branch> # 基于branch创建新的new_branchgit co $id # 把某次历史提交记录checkout出来,但无分支信息,切换到其他分支会自动删除git co $id -b <new_branch> # 把某次历史提交记录checkout出来,创建成一个分支git br -d <branch> # 删除某个分支git br -D <branch> # 强制删除某个分支 (未被合并的分支被删除的时候需要强制) 分支合并和rebase 12345git merge <branch> # 将branch分支合并到当前分支git merge origin/master --no-ff # 不要Fast-Foward合并,这样可以生成merge提交git rebase master <branch> # 将master rebase到branch,相当于: git co <branch> && git rebase master && git co master && git merge <branch> Git补丁管理(方便在多台机器上开发同步时用) 12345git diff > ../sync.patch # 生成补丁git apply ../sync.patch # 打补丁git apply --check ../sync.patch #测试补丁能否成功 Git暂存管理123456789101112131415161718192021git stash # 暂存git stash list # 列所有stashgit stash apply # 恢复暂存的内容git stash drop # 删除暂存区Git远程分支管理git pull # 抓取远程仓库所有分支更新并合并到本地git pull --no-ff # 抓取远程仓库所有分支更新并合并到本地,不要快进合并git fetch origin # 抓取远程仓库更新git merge origin/master # 将远程主分支合并到本地当前分支git co --track origin/branch # 跟踪某个远程分支创建相应的本地分支git co -b <local_branch> origin/<remote_branch> # 基于远程分支创建本地分支,功能同上 git push # push所有分支 123456789git push origin master # 将本地主分支推到远程主分支git push -u origin master # 将本地主分支推到远程(如无远程主分支则创建,用于初始化远程仓库)git push origin <local_branch> # 创建远程分支, origin是远程仓库名git push origin <local_branch>:<remote_branch> # 创建远程分支git push origin :<remote_branch> #先删除本地分支(git br -d <branch>),然后再push删除远程分支 Git远程仓库管理 1234567git remote -v # 查看远程服务器地址和仓库名称git remote show origin # 查看远程服务器仓库状态git remote add origin git@ github:robbin/robbin_site.git # 添加远程仓库地址git remote set-url origin git@ github.com:robbin/robbin_site.git # 设置远程仓库地址(用于修改远程仓库地址) git remote rm <repository> # 删除远程仓库 创建远程仓库 12345678910111213git clone --bare robbin_site robbin_site.git # 用带版本的项目创建纯版本仓库scp -r my_project.git git@ git.csdn.net:~ # 将纯仓库上传到服务器上mkdir robbin_site.git && cd robbin_site.git && git --bare init # 在服务器创建纯仓库git remote add origin git@ github.com:robbin/robbin_site.git # 设置远程仓库地址git push -u origin master # 客户端首次提交git push -u origin develop # 首次将本地develop分支提交到远程develop分支,并且trackgit remote set-head origin master # 设置远程仓库的HEAD指向master分支 也可以命令设置跟踪远程库和本地库123456789101112git branch --set-upstream master origin/mastergit branch --set-upstream develop origin/develop此文章属转载,原文地址:http://1ke.co/course/194另附: 解决 在使用git 对源代码进行push到gitHub时可能会出错,error: failed to push some refs to git。出现错误的主要原因是github中的README.md文件不在本地代码目录中可以通过如下命令进行github与本地代码合并: git pull --rebase origin master重新执行之前的git push 命令,成功!","link":"/2017/05/03/将本地的项目上传到github上面的方法教程/"},{"title":"怎么保存Protege 5.x中HermiT推理机reasoner的推理结果?","text":"How save the result of reasoner HermiT in Protege 怎么保存Protege 5.x中HermiT推理机reasoner的推理结果?我们在使用Protégé5.5,我想将推理器的结果保存到本体文件中。当我停止推理时,所有结果都消失了。如何保存结果? 单个效果预览: 所有动画效果:https://huaji8.top/post/live2d-plugin-2.0/ 2 安装过程2.1 安装总插件在hexo的根目录下执行1npm install --save hexo-helper-live2d 2.2 安装喜欢的具体模型安装完总插件后,可以安装喜欢的模型 所有动画效果可以在这个网站观看:https://huaji8.top/post/live2d-plugin-2.0/ 选择一个自己喜欢的,比如tororo(白猫),下载具体的模型: 在根目录下执行:1npm install live2d-widget-model-tororo (喜欢别的形象就把tororo换成别的名字) 2.3 移动模型地址 从hexo的根目录的node_modules中找到刚刚安装的模型文件夹,比如我这里安装的是:live2d-widget-model-tororo ;复制这个文件夹。 在hexo的根目录创建名为live2d_models的文件夹 把之前找到的的模型文件夹从node_modules文件夹复制到live2d_models中 2.4 配置使用在hexo根目录下的_config.yml中的最后面添加以下内容 12345678910111213141516live2d: enable: true scriptFrom: local pluginRootPath: live2dw/ pluginJsPath: lib/ pluginModelPath: assets/ tagMode: false debug: false model: use: live2d-widget-model-haruto display: position: right width: 150 height: 300 mobile: show: true 3 成功大功告成,部署博客即可。 hexo -d -g 效果如下: ## 1现象当我们使用推理机推理后,protege推理出来的结果会用黄色标出。 但是当我们想要保存推理后的结果时候,点击file中的save project或者save as project,再打开该项目发现,还是原来的结构,并不是推理机推理后的结构数据。 并且点击stop reasoner之后,推理的结果也消失了。 2 解决办法点击 File → Export inferred axioms as ontology… 选择所有选项: 然后选一个 你想保存的本体文件地址。 保存的文件没有后缀。所以我们把保存的文件的后缀 改为.owl 即可。 参考大神:https://stackoverflow.com/questions/23079459/how-save-the-result-of-reasoner-fact-or-hermit-in-protege","link":"/2019/03/22/怎么保存Protege 5.x中HermiT推理机reasoner的推理结果?/"},{"title":"怎么加载训练好的词向量bin","text":"word2vec 有的时候需要加载之际之前训练好的词向量,或者加载下载的别人的词向量,加载如下: 1默认方法如果你是用默认方法训练的,则可以直接load: 123model.save('/model/word2vec_model')new_model=gensim.models.Word2Vec.load('/model/word2vec_model') 也可以获取每个词的词向量 1model['computer'] 2下载的二进制bin类型如果及自己保存的二进制类型,则需要这样: 1234567891011121314151617'''Created on 2018年1月5日@author: qingtxu'''import gensim# 导入模型 model = gensim.models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin',binary=True) # 返回一个词 的向量:print(model['word'])# 返回和一个词语最相关的多个词语以及对应的相关度items = model.most_similar('happy')for item in items: # 词的内容,词的相关度 print(item[0], item[1]) 3 词向量的下载地址:3.1 英文 谷歌新闻词向量,1.2G,地址:https://code.google.com/archive/p/word2vec/ 下载文件:GoogleNews-vectors-negative300.bin.gz. 3.2中文向量中文还没找到好,下次把我自己训练的维基百科上传","link":"/2018/01/05/怎么加载训练好的词向量bin/"},{"title":"文件操作与数据存储json","text":"文件读取键盘读取Python2中有两个内置的函数可从标准输入读取数据,它默认来自键盘。这些函数分别是:input() 和 raw_input()。 但在Python3中,raw_input()函数已被弃用。此外, input() 函数是从键盘作为字符串读取数据,不论是否使用引号(‘’或“”)与否。 12345678910#!/usr/bin/python3>>> x=input("something:")something:10>>> x'10'>>> x=input("something:")something:'10' #entered data treated as string with or without ''>>> x"'10'" 从本地读取打开和关闭文件open()函数注意: 文件被打开后一定得记得关闭close()。否则可能会损害文件。所以尽量使用 with 。让python自己判断什么时候该关闭,并自己去关闭。 open()后是一个对象,这个对象有read()方法与write()方法。 常用打开模式: 123456r 只能读 r+ 可读可写,不会创建不存在的文件,从顶部开始写,会覆盖之前此位置的内容w 只能写,覆盖整个原有文件(不要乱用),不存在则创建 w+ 可读可写,如果文件存在,则覆盖整个文件,不存在则创建a 只能写,从文件底部添加内容 不存在则创建 a+ 可读可写 从文件顶部读取内容 从文件底部添加内容 不存在则创建 如果我们在open文件后,没有进行任何读写,则默认r模式 123with open ('pi.txt') as file_object : contents = file_object.read() print( contents ) 逐行读取: 1234filename = 'pi.txt'with open (filename) as file_object : for line in file_object: print (line) 文件写入w模式:覆盖原有数据 1234filename = 'pi.txt'with open (filename,'w') as file_object : file_object.write("i love you \\n") file_object.write("i love you \\n") # 加上\\n可以一行一行的加入 a模式:添加新的内容,不会覆盖原有内容 1234filename = 'pi.txt'with open (filename,'a') as file_object : file_object.write("i love you \\n") file_object.write("i love you \\n") # 加上\\n可以一行一行的加入 数据存储jsonJSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于ECMAScript的一个子集。 Python3 中可以使用 json 模块来对 JSON 数据进行编解码,它包含了两个函数: 12json.dumps(): 对数据进行编码。json.loads(): 对数据进行解码。 在json的编解码过程中,python 的原始类型与json类型会相互转换,具体的转化对照如下: Python JSON dict object list, tuple array str string int, float, int- & float-derived Enums number True true False false None null json.dumps 与 json.loads 实例以下实例演示了 Python 数据结构转换为JSON: 1234567891011121314#!/usr/bin/python3import json# Python 字典类型转换为 JSON 对象data = { 'no' : 1, 'name' : 'Runoob', 'url' : 'http://www.runoob.com'}json_str = json.dumps(data)print ("Python 原始数据:", repr(data))print ("JSON 对象:", json_str) 执行以上代码输出结果为: 12Python 原始数据: {'url': 'http://www.runoob.com', 'no': 1, 'name': 'Runoob'}JSON 对象: {"url": "http://www.runoob.com", "no": 1, "name": "Runoob"} 通过输出的结果可以看出,简单类型通过编码后跟其原始的repr()输出结果非常相似。接着以上实例,我们可以将一个JSON编码的字符串转换回一个Python数据结构: 12345678910111213141516171819#!/usr/bin/python3import json# Python 字典类型转换为 JSON 对象data1 = { 'no' : 1, 'name' : 'Runoob', 'url' : 'http://www.runoob.com'}json_str = json.dumps(data1)print ("Python 原始数据:", repr(data1))print ("JSON 对象:", json_str)# 将 JSON 对象转换为 Python 字典data2 = json.loads(json_str)print ("data2['name']: ", data2['name'])print ("data2['url']: ", data2['url']) 执行以上代码输出结果为:1234Python 原始数据: {'name': 'Runoob', 'no': 1, 'url': 'http://www.runoob.com'}JSON 对象: {"name": "Runoob", "no": 1, "url": "http://www.runoob.com"}data2['name']: Runoobdata2['url']: http://www.runoob.com 如果你要处理的是文件而不是字符串,你可以使用 json.dump() 和 json.load() 来编码和解码JSON数据。例如: 1234567# 写入 JSON 数据with open('data.json', 'w') as f: json.dump(data, f)# 读取数据with open('data.json', 'r') as f: data = json.load(f)","link":"/2017/05/01/文件操作与数据存储json/"},{"title":"汽车之家口碑爬虫","text":"1.需求分析因项目需求,要爬取汽车之家的口碑数据进行下一步分析。 但是普通的爬虫软件(如八爪鱼、火车头、神箭手)无法爬取评论(该公司采取了反爬虫措施)。 经分析,发现该公司的的反爬虫措施主要是用前端js去替换显示的字体,为一些标签。并且封住鼠标右键导致不好观察源代码。 本文以解决各个问题为顺序。 2.前端js反爬虫措施分析2.1问题描述以任意车型(奥迪A4L)为例:http://k.autohome.com.cn/692/ 我们可以看到,表面上各个评论都由文字组成,但是打开F12开发者模式。我们就发现:一些形容词被替换成了span标签,如图: 他们的具体做法是: 发布的口碑正文中随机抽取某几个字使用span标签代替,标签内容位空,但css样式显示为所代替的文。 这样不会影响正常用户的阅读,只是在用鼠标选择的时候是选不到被替换的文字的,对爬虫则会造成采集内容不全的影响。 这些是用JS实现的,这是一段js代码: 12345678910111213141516171819202122232425(function(hZ_) { functionEW_() { = DV_()[decodeURIComponent]('%E3%80%81%E3%80%82%E4%B8%80%E4%B8%8A%E4%B8%8B%E4%B8%8D%E4%BA%86%E4%BA%94%E5%92%8C%E5%9C%B0%E5%A4%9A%E5%A4%A7%E5%A5%BD%E5%B0%8F%E5%BE%88%E5%BE%97%E6%98%AF%E7%9A%84%E7%9D%80%E8%BF%9C%E9%95%BF%E9%AB%98%EF%BC%81%EF%BC%8C%EF%BC%9F' yc_()); = la_((yc_() 23; 3; 19; 17; 9; 1; 8; 12; 18; 13; 2; 4; 16; 5; 6; 21; 15; 11; 22; 14; 24; 0; 10; 7; 20), lf_(;)); = la_((10 _7, 6 _0; 2 _33, 14 _18; 8 _45, 8 _36; 0 _71, 16 _54; 13 _76, 3 _72; 0 _107, 16 _90; 15 _110, 1 _108; 4 _139, 12 _126; 9 _152, 7 _144; 10 _169, 6 _162; 4 _193, 12 _180; 11 _204, 5 _198; 3 _230, 13 _216; 1 _250, 15 _234; 13 _256, 3 _252; 6 _281, 10 _270; 9 _296, 7 _288; 13 _310, 3 _306; 6 _335, 10 _324; 7 _352, 9 _342; 6 _371, 10 _360; 5 _390, 11 _378; 5 _408, 11 _396; 7 _424, 9 _414; 6 _443, 10 _432lf_(;)), yc_(;)); Uj_(); return;; } function mS_() { for (Gx_ = 0; Gx_ < nf_.length; Gx_++) { var su_ = Pn_(nf_[Gx_], ','); var KN_ = ''; for (Bk_ = 0; Bk_ < su_.length; Bk_++) { KN_ += ui_(su_[Bk_]) + ''; } Kx_(Gx_, KN_); } } function NH_(Gx_) { return '.hs_kw' + Gx_ + '_maindC'; } function Ln_() { return '::before { content:' }})(document); 他的逻辑是,预先定义好哪几个字要被替换,上面代码中的那个很多%的字符串就是被替换的文字串,然后定义好每个文字的序号,最后按照文字的序号对文字串进行重新排序并生成css样式,注意,最一开始的span标签的class属性中是有个序号的,这个序号就是用来定位应该对应哪个文字。 接下来要做的就是无非就是从js代码中找到这个文字串,找到文字串的顺序,然后进行重排,然后根据span标签序号对原文进行反向替换,从而得到完整的内容。 2.2解决方法: 从js代码中找到被替换的文字串和顺序 重排文字串 对原文中span标签根据class序号进行替换 其实2、3都比较简单,重点是第一步,找到被替换的文字串和顺序,由于源代码中js代码是被混淆过的,无法直接看出哪个 是文字串,所以首先应该对js代码进行反混淆,这个反混淆也不是说非得完整的还原所有的js代码,其实只要能反混淆到能 让我们看出文字串和顺序是什么就行了。 说一下反混淆的思路,其实很简单。就是执行起来比较麻烦而已,混淆是利用将一个简单的变量定义成复杂的js代码的方法 实现的,但这种\b混淆方式其实是有限的(这个有限指的是混淆用的工具在生成混淆代码时肯定是人为预先定义好了几种模式 ,人为定义的肯定是有限的,只要你把所有的模式找出来,就可以还原了)。举个例子 1234function iq_() { 'return iq_'; return '3'; } 这段代码其实你可以简单的认为就是变量iq()等于’3’,使用正则匹配这样的代码模式,然后提取关键字:函数名和最后一个return的值,然后将提取到的信息保存起来用于对js代码进行全文替换。 12345678910function cz_() { function _c() { return 'cz_'; }; if (_c() == 'cz__') { return _c(); } else { return '84'; } } 这段代码复杂了一些,增加了判断,不过也简单,利用正则匹配这样的模式,然后提取关键字:函数名、第一个return的值,判断中==后面的值,最后一个return的值,然后自己进行判断来确定cz_()的值应该是多少,保存起来进行全文替换。 以此类推,每种模式都可以使用正则来提取关键字并进行全文替换来反混淆,最后我们会得到一个大概被还原的js代码,其中的文字串和顺序都清晰可见,再使用正则匹配出来就可以了。 需要注意的一点是有时候被替换的不是单个文字,而是一些词语,这是找到的顺序是”3,1;23,5”这样的,不过这些小伎俩应该不算什么,很好解决。 下面给出完整的代码: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403# coding:utf8import reimport urllibimport urllib.parseimport requestsdef get_char(js): all_var = {} # 判断混淆 无参数 返回常量 函数 if_else_no_args_return_constant_function_functions = [] \"\"\" function zX_() { function _z() { return '09'; }; if (_z() == '09,') { return 'zX_'; } else { return _z(); } } \"\"\" constant_function_regex4 = re.compile(\"\"\" function\\s+\\w+\\(\\)\\s*\\{\\s* function\\s+\\w+\\(\\)\\s*\\{\\s* return\\s+[\\'\\\"][^\\'\\\"]+[\\'\\\"];\\s* \\};\\s* if\\s*\\(\\w+\\(\\)\\s*==\\s*[\\'\\\"][^\\'\\\"]+[\\'\\\"]\\)\\s*\\{\\s* return\\s*[\\'\\\"][^\\'\\\"]+[\\'\\\"];\\s* \\}\\s*else\\s*\\{\\s* return\\s*\\w+\\(\\);\\s* \\}\\s* \\} \"\"\", re.X) l = constant_function_regex4.findall(js) # print(\"l 38\",l) for i in l: function_name = re.search(\"\"\" function\\s+(\\w+)\\(\\)\\s*\\{\\s* function\\s+\\w+\\(\\)\\s*\\{\\s* return\\s+[\\'\\\"]([^\\'\\\"]+)[\\'\\\"];\\s* \\};\\s* if\\s*\\(\\w+\\(\\)\\s*==\\s*[\\'\\\"]([^\\'\\\"]+)[\\'\\\"]\\)\\s*\\{\\s* return\\s*[\\'\\\"]([^\\'\\\"]+)[\\'\\\"];\\s* \\}\\s*else\\s*\\{\\s* return\\s*\\w+\\(\\);\\s* \\}\\s* \\} \"\"\", i, re.X) if_else_no_args_return_constant_function_functions.append(function_name.groups()) js = js.replace(i, \"\") # 替换全文 a, b, c, d = function_name.groups() all_var[\"%s()\" % a] = d if b == c else b # 判断混淆 无参数 返回函数 常量 if_else_no_args_return_function_constant_functions = [] \"\"\" function wu_() { function _w() { return 'wu_'; }; if (_w() == 'wu__') { return _w(); } else { return '5%'; } } \"\"\" constant_function_regex5 = re.compile(\"\"\" function\\s+\\w+\\(\\)\\s*\\{\\s* function\\s+\\w+\\(\\)\\s*\\{\\s* return\\s+[\\'\\\"][^\\'\\\"]+[\\'\\\"];\\s* \\};\\s* if\\s*\\(\\w+\\(\\)\\s*==\\s*[\\'\\\"][^\\'\\\"]+[\\'\\\"]\\)\\s*\\{\\s* return\\s*\\w+\\(\\);\\s* \\}\\s*else\\s*\\{\\s* return\\s*[\\'\\\"][^\\'\\\"]+[\\'\\\"];\\s* \\}\\s* \\} \"\"\", re.X) l = constant_function_regex5.findall(js) # print(\"l 87\",l) for i in l: function_name = re.search(\"\"\" function\\s+(\\w+)\\(\\)\\s*\\{\\s* function\\s+\\w+\\(\\)\\s*\\{\\s* return\\s+[\\'\\\"]([^\\'\\\"]+)[\\'\\\"];\\s* \\};\\s* if\\s*\\(\\w+\\(\\)\\s*==\\s*[\\'\\\"]([^\\'\\\"]+)[\\'\\\"]\\)\\s*\\{\\s* return\\s*\\w+\\(\\);\\s* \\}\\s*else\\s*\\{\\s* return\\s*[\\'\\\"]([^\\'\\\"]+)[\\'\\\"];\\s* \\}\\s* \\} \"\"\", i, re.X) if_else_no_args_return_function_constant_functions.append(function_name.groups()) js = js.replace(i, \"\") # 替换全文 a, b, c, d = function_name.groups() all_var[\"%s()\" % a] = b if b == c else d # var 参数等于返回值函数 var_args_equal_value_functions = [] \"\"\" var ZA_ = function(ZA__) { 'return ZA_'; return ZA__; }; \"\"\" constant_function_regex1 = re.compile( \"var\\s+[^=]+=\\s*function\\(\\w+\\)\\{\\s*[\\'\\\"]return\\s*\\w+\\s*[\\'\\\"];\\s*return\\s+\\w+;\\s*\\};\") l = constant_function_regex1.findall(js) # print(\"l 119\",l) for i in l: function_name = re.search(\"var\\s+([^=]+)\", i).group(1) var_args_equal_value_functions.append(function_name) js = js.replace(i, \"\") # 替换全文 a = function_name js = re.sub(\"%s\\(([^\\)]+)\\)\" % a, r\"\\1\", js) # var 无参数 返回常量 函数 var_no_args_return_constant_functions = [] \"\"\" var Qh_ = function() { 'return Qh_'; return ';'; }; \"\"\" constant_function_regex2 = re.compile(\"\"\" var\\s+[^=]+=\\s*function\\(\\)\\{\\s* [\\'\\\"]return\\s*\\w+\\s*[\\'\\\"];\\s* return\\s+[\\'\\\"][^\\'\\\"]+[\\'\\\"];\\s* \\}; \"\"\", re.X) l = constant_function_regex2.findall(js) # print(\"l 144\",l) for i in l: function_name = re.search(\"\"\" var\\s+([^=]+)=\\s*function\\(\\)\\{\\s* [\\'\\\"]return\\s*\\w+\\s*[\\'\\\"];\\s* return\\s+[\\'\\\"]([^\\'\\\"]+)[\\'\\\"];\\s* \\}; \"\"\", i, re.X) var_no_args_return_constant_functions.append(function_name.groups()) js = js.replace(i, \"\") # 替换全文 a, b = function_name.groups() all_var[\"%s()\" % a] = b # 无参数 返回常量 函数 no_args_return_constant_functions = [] \"\"\" function ZP_() { 'return ZP_'; return 'E'; } \"\"\" constant_function_regex3 = re.compile(\"\"\" function\\s*\\w+\\(\\)\\s*\\{\\s* [\\'\\\"]return\\s*[^\\'\\\"]+[\\'\\\"];\\s* return\\s*[\\'\\\"][^\\'\\\"]+[\\'\\\"];\\s* \\}\\s* \"\"\", re.X) l = constant_function_regex3.findall(js) # print(\"l 176\",l) for i in l: function_name = re.search(\"\"\" function\\s*(\\w+)\\(\\)\\s*\\{\\s* [\\'\\\"]return\\s*[^\\'\\\"]+[\\'\\\"];\\s* return\\s*[\\'\\\"]([^\\'\\\"]+)[\\'\\\"];\\s* \\}\\s* \"\"\", i, re.X) no_args_return_constant_functions.append(function_name.groups()) js = js.replace(i, \"\") # 替换全文 a, b = function_name.groups() all_var[\"%s()\" % a] = b # 无参数 返回常量 函数 中间无混淆代码 no_args_return_constant_sample_functions = [] \"\"\" function do_() { return ''; } \"\"\" constant_function_regex3 = re.compile(\"\"\" function\\s*\\w+\\(\\)\\s*\\{\\s* return\\s*[\\'\\\"][^\\'\\\"]*[\\'\\\"];\\s* \\}\\s* \"\"\", re.X) l = constant_function_regex3.findall(js) # print(\"l 206\",l) for i in l: function_name = re.search(\"\"\" function\\s*(\\w+)\\(\\)\\s*\\{\\s* return\\s*[\\'\\\"]([^\\'\\\"]*)[\\'\\\"];\\s* \\}\\s* \"\"\", i, re.X) no_args_return_constant_sample_functions.append(function_name.groups()) js = js.replace(i, \"\") # 替换全文 a, b = function_name.groups() all_var[\"%s()\" % a] = b # 字符串拼接时使无参常量函数 \"\"\" (function() { 'return sZ_'; return '1' })() \"\"\" constant_function_regex6 = re.compile(\"\"\" \\(function\\(\\)\\s*\\{\\s* [\\'\\\"]return[^\\'\\\"]+[\\'\\\"];\\s* return\\s*[\\'\\\"][^\\'\\\"]*[\\'\\\"];? \\}\\)\\(\\) \"\"\", re.X) l = constant_function_regex6.findall(js) # print(\"l 236\",l) for i in l: function_name = re.search(\"\"\" \\(function\\(\\)\\s*\\{\\s* [\\'\\\"]return[^\\'\\\"]+[\\'\\\"];\\s* return\\s*([\\'\\\"][^\\'\\\"]*[\\'\\\"]);? \\}\\)\\(\\) \"\"\", i, re.X) js = js.replace(i, function_name.group(1)) # 字符串拼接时使用返回参数的函数 \"\"\" (function(iU__) { 'return iU_'; return iU__; })('9F') \"\"\" constant_function_regex6 = re.compile(\"\"\" \\(function\\(\\w+\\)\\s*\\{\\s* [\\'\\\"]return[^\\'\\\"]+[\\'\\\"];\\s* return\\s*\\w+; \\}\\)\\([\\'\\\"][^\\'\\\"]*[\\'\\\"]\\) \"\"\", re.X) l = constant_function_regex6.findall(js) # print(\"l 264\",l) for i in l: function_name = re.search(\"\"\" \\(function\\(\\w+\\)\\s*\\{\\s* [\\'\\\"]return[^\\'\\\"]+[\\'\\\"];\\s* return\\s*\\w+; \\}\\)\\(([\\'\\\"][^\\'\\\"]*[\\'\\\"])\\) \"\"\", i, re.X) js = js.replace(i, function_name.group(1)) print(\"275\",js) # 获取所有变量 var_regex = \"var\\s+(\\w+)=(.*?);\\s\" var_find = re.findall(var_regex, js) print(\"var_find\",var_find) for var_name, var_value in var_find: var_value = var_value.strip(\"\\'\\\"\").strip() # print(var_name,\"---\",var_value) if \"(\" in var_value: var_value = \";\" all_var[var_name] = var_value print(\"all var\",all_var) # 注释掉 此正则可能会把关键js语句删除掉 # js = re.sub(var_regex, \"\", js) for var_name, var_value in all_var.items(): js = js.replace(var_name, var_value) print(\"----282\",js) js = re.sub(\"[\\s+']\", \"\", js) print(\"----284\",js) string_m = re.search(\"(%\\w\\w(?:%\\w\\w)+)\", js) # string = urllib.parse.unquote(string_m.group(1)).encode(\"utf-8\").decode(\"utf8\") print(\"string_m\",string_m.groups()) string = urllib.parse.unquote(string_m.group(1)).encode(\"utf-8\").decode(\"utf8\") print(string) index_m = re.search(\"([\\d,]+(;[\\d,]+)+)\", js[string_m.end():]) print(index_m.group()) string_list = list(string) print(\"str\",len(string_list)) # print(\"string_list\",string_list) index_list = index_m.group(1).split(\";\") # print(\"index_list\",index_list) _word_list = [] # print(type(_word_list)) # print(_word_list) i = 1 exflag = 0; # deal exception # print(\"--max \",type(int(max(index_list)))) max_index=0; for word_index_list in index_list: _word = \"\" if \",\" in word_index_list: word_index_list = word_index_list.split(\",\") word_index_list = [int(x) for x in word_index_list] else: word_index_list = [int(word_index_list)] for word_index in word_index_list: # print(word_index) if(word_index>max_index): max_index=word_index try: string_list[word_index] except Exception as e: exflag=1; print(max_index) print(\"exflag\",exflag) less = max_index - len(string_list) print(less) for word_index_list in index_list: _word = \"\" if \",\" in word_index_list: word_index_list = word_index_list.split(\",\") # print(\"word_index_list\",word_index_list) word_index_list = [int(x) for x in word_index_list] # print(\"word_index_list\", word_index_list) else: word_index_list = [int(word_index_list)] j = 1; for word_index in word_index_list: # print(\"for\",j) j += 1 # print(\"word_index\",word_index) # print(\"string_list[word_index]\",string_list[word_index]) try: _word += string_list[word_index-1-less] except Exception as e: print(e) # print(_word) _word_list.append(_word) # print(\"----------\") # print(i) # print(_word_list) i += 1 return _word_listdef get_complete_text_autohome(text): #print(\"text0\",text) text = text.replace(r\"\\u0027\",\"'\").replace(r\"\\u003e\",\">\").replace(r\"\\u003c\",\"<\") #print(\"text1\",text) js = re.search(\"<!--@HS_ZY@--><script>([\\s\\S]+)\\(document\\);</script>\", text) #print(\"find : %s\" % js.group()) if not js: print(\" if not js:\") return text try: #print(\"try0\") char_list = get_char(js.group(1)) print(\"try111\") except Exception as e: print(e) print(\"except222\") return text def char_replace(m): index = int(m.group(1)) char = char_list[index] return char text = re.sub(\"<span\\s*class=[\\'\\\"]hs_kw(\\d+)_[^\\'\\\"]+[\\'\\\"]></span>\", char_replace, text) # print(text) return text# resp = requests.get(\"http://k.autohome.com.cn/FrontAPI/GetFeelingByEvalId?evalId=1538569\")resp = requests.get(\"http://k.autohome.com.cn/FrontAPI/GetFeelingByEvalId?evalId=1585634\")resp.encoding = \"gbk\"text = get_complete_text_autohome(resp.text)print(re.search(\"<!--@HS_BASE64@-->.*<!--@HS_ZY@-->\", text).group())print(\"2\")# print(re.search(\"<div\\s*class=[\\'\\\"]text-con[^\\'\\\"]*?[\\'\\\"]>([\\s\\S]+?)</div>\", text).group(1)) 前一个函数是核心,用于解析js 3.爬虫框架3.1 获取所有车型的id首先利用爬虫软件爬取了 汽车列表 里面的所有汽车id,用两层循环爬取所有页面的评论: 123456# 两层遍历,分别遍历车型和页数 for i in car_id_list: # i代表从车型的遍历 for j in range(1,101): # j代表评论页数,range(1,3)表示1到2页 req = scrapy.Request(\"http://k.autohome.com.cn/\"+str(i)+\"/index_\"+str(j)+\".html#dataList\") reqs.append(req) return reqs 3.2本爬虫采用scrapy框架,分析所需要的评论信息为:123456789101112131415161718192021222324252627282930313233343536373839404142434445# 车ID CAR_ID = scrapy.Field() # 车名 CAR_NAME = scrapy.Field() # 用户ID USER_ID = scrapy.Field() # 用户名 USER_NAME = scrapy.Field() # 购买地点 PURCHASE_PLACE = scrapy.Field() # 购买时间 PURCHASE_TIME = scrapy.Field() # 裸车购买价 CAR_PRICE = scrapy.Field() # 购车目的 PURCHASE_PURPOSE = scrapy.Field() # 评分- 空间 SCORE_SPACE = scrapy.Field() # 评分- 动力 SCORE_POWER = scrapy.Field() # 评分- 操控 SCORE_CONTROL = scrapy.Field() # 评分- 油耗 SCORE_FUEL_CONSUMPTION = scrapy.Field() # 评分- 舒适性 SCORE_COMFORT = scrapy.Field() # 评分- 外观 SCORE_EXTERIOR = scrapy.Field() # 评分- 内饰 SCORE_INTERIOR = scrapy.Field() # 评分- 性价比 SCORE_COST_EFFECTIVE = scrapy.Field() # 评论的url COMMENT_URL = scrapy.Field() # 评论的内容 COMMENT_CONTENT = scrapy.Field() # 有多少人支持这条口碑 COMMENT_SUPPORT_QUANTITY = scrapy.Field() # 有多少人看过这条口碑 COMMENT_SEEN_QUANTITY = scrapy.Field() 将其写进item中。 3.3将常用设置写入sttings中1234567891011# 绕过robots.txtROBOTSTXT_OBEY = False#记录日志LOG_FILE = \"scrapy_autohome_log.log\"# 保存文件编码类型FEED_EXPORT_ENCODING = 'GBK'# 伪装chromeUSER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' 这样利用我们前面学习的scrapy框架的知识,再加上破解的js。我们成功爬取了汽车之家的数据。经过试验爬取了 将近22万条评论。 4.结果展示1.数据条数: 2.数据格式 3.完整代码参见我饿github:https://github.com/xqtbox/AutoHomeSpider_Scrapy","link":"/2017/05/30/汽车之家口碑爬虫/"},{"title":"深度学习 自然语言处理 怎么获得数据集 中文语料集?","text":"现如今构件人工智能、机器学习甚至深度学习系统,变得越来越容易。 但是让这些模型或者系统真正有价值的却是“数据”。那么如果刚刚上手机器学习或者深度学习,怎么寻找合适的数据集呢? 下面就介绍一些获取数据的方法: 1 爬虫最好的方法就是自己写爬虫,优点是可以自由的定制想要的数据,缺点是周期较长。 但现在随着python的兴起,越来越多的架包的开发,爬虫越来越简单实现。 跟着下面这个教程可以很快的实现一个强大的爬虫: CSDN 爬虫教程http://blog.csdn.net/u012052268/article/category/6889435 2 数据平台国内一些机构贡献了一些数据集出来,大家可以在上面下载。 2.1 数据堂数据堂 是国内比较大的大数据交易平台,上面有许多数据覆盖面很广,但是要收费,推荐有财力的实验室采购。网址: http://www.datatang.com/ 2.2 搜狗实验室搜狗实验室是比较权威的数据提供方提供的数据质量很高而且数据是免费的。网址:http://www.sogou.com/labs/ 2.3 自然语言处理与信息检索共享平台是中科大的信息平台,上面有一些自然语言相关的数据集。网址:http://www.nlpir.org/?action-category-catid-28 2.4 聚数力http://dataju.cn/Dataju/web/home 3 人工收集的这是几个博主自己总结的,质量很高。 https://zhuanlan.zhihu.com/p/25138563 https://www.zhihu.com/question/53655758/answer/146351918 https://www.douban.com/note/269081724/","link":"/2017/09/19/深度学习 自然语言处理 怎么获得数据集 中文语料集?/"},{"title":"深度学习中的highway network、ResNet、Inception","text":"不是特别清楚这三个流行且有用的模型(或者说层)的具体作用和使用方法。 概念CNN演化先引入一张CNN结构演化图: 2012年AlexNet做出历史突破以来,直到GoogLeNet出来之前,主流的网络结构突破大致是网络更深(层数),网络更宽(神经元数)。所以大家调侃深度学习为“深度调参”,但是纯粹的增大网络的缺点: 参数太多,容易过拟合,若训练数据集有限; 网络越大计算复杂度越大,难以应用; 网络越深,梯度越往后穿越容易消失(梯度弥散),难以优化模型梯度消失我们都知道神经网络中会使用非线性变换。 一般会使用sigmoid函数,得到,这个函数会把数据压缩到开区间(0,1),函数的图像如下: 可以看到,函数的两侧非常平滑,而且无限的接近0和1,仅仅是中间部分函数接近一条直线。 要知道,神经网络训练的方法是BP算法(反向传播)。BP算法的基础其实就是导数的链式法则,就是有很多乘法会连接在一起。 看sigmoid函数的图像知道了,导数最大是1,而且大多数值都被推向两侧饱和的区域,这些区域的导数很小。 可以预见到,随着网络的加深,梯度后向传播到输入层时,就所剩无几,基本不能引起参数W数值的扰动,这样输入层一侧的网络就学习不到新的特征了参数得不到更新)。 那么怎么办?我暂时看到了四种解决问题的办法。 第一种很明显,可以通过使用别的激活函数; 第二种可以使用层归一化; 第三种是在权重的初始化上下功夫, 第四种是调整网络的结构。 我们主要关注第4个。 highway networkHighway Network的灵感来自“解决RNN的问题,提出的LSTM结构” 也就是加入“门”结构。 Highway Network主要解决的问题是,网络深度加深,梯度信息回流受阻,造成网络训练困难的问题。 公式:对于highway network来说,不需要看图片,看公式就可以理解其意义。 1.一般一个 feedforward neural network 有L层网络组成,每层网络对输入进行一个非线性映射变换,可以表达如下 对于高速CNN网络,我们定义一层网络如下 ,其中T和C分别表示 对输入的门控(0到1) 和 直接传送。 为了理解,我们观察到,对于特殊的门值T 也就是:当门为1的时候,全部输出原x,不用激活。 意义、好处 物理意义:假设所有的门t的均值为0.5的话,就是把所有的原始信息一半激活,一半不变直接输入下一层,保留了很多信息。 反向传播的时候,可以让更多的(梯度)信息直接回流到输入,而不需要经过一个非线性转化。 参考:https://www.cnblogs.com/jie-dcai/p/5803220.html ResNet网上有传言 微软的深度残差学习是抄袭 Highway Networks,只是Highway Networks的一个特例。Highway Networks 的确是先发表的。 但不管怎么说,ResNet的名气确实更大,很多面试会问到。 动机、目的ResNet最根本的动机就是所谓的“退化”问题。 但是模型的深度加深,学习能力增强,因此更深的模型不应当产生比它更浅的模型更高的错误率。 而退化就是当模型的层次加深时,错误率却提高了,如下图: 而这个“退化”问题产生的原因归结于优化难题,当模型变复杂时,SGD的优化变得更加困难,导致了模型达不到好的学习效果。 针对这个问题,作者提出了一个Residual的结构: 模型模型增加一个identity mapping(恒等映射),将原始所需要学的函数H(x)转换成F(x)+x, 而作者认为这两种表达的效果相同,但是优化的难度却并不相同,作者假设F(x)的优化 会比H(x)简单的多。 这一想法也是源于图像处理中的残差向量编码,通过一个reformulation,将一个问题分解成多个尺度直接的残差问题,能够很好的起到优化训练的效果。 这个Residual block通过shortcut connection实现,通过shortcut将这个block的输入和输出进行一个element-wise的加叠。 作用: 这个简单的加法并不会给网络增加额外的参数和计算量,同时却可以大大增加模型的训练速度、提高训练效果 并且当模型的层数加深时,这个简单的结构能够很好的解决退化问题。因为identity map是的梯度可以直接回流到了输入层 参考:https://blog.csdn.net/wspba/article/details/56019373 Inception那么解决深度学习 参数过多、和梯度消失问题,方法当然就是增加网络深度和宽度的同时减少参数,Inception就是在这样的情况下应运而生。 Inception v1模型目前很多工作证明,要想增强网络能力,可以:增加网络深度,增加网络宽度;但是为了减少过拟合,也要减少自由参数。 因此,就自然而然有了这个第一版的Inception网络结构——同一层里面,有卷积1 1, 3 3,5* 5 不同的卷积模板,他们可以在不同size的感受野做特征提取,也算的上是一种混合模型了。 因为Max Pooling本身也有特征提取的作用,而且和卷积不同,没有参数不会过拟合,也作为一个分支。 但是直接这样做,整个网络计算量会较大,且层次并没有变深,因此,在33和55卷积前面先做1*1的卷积,降低input的channel数量,这样既使得网络变深,同时计算量反而小了;(在每一个卷积之后都有ReLU) 第一张图是论文中提出的最原始的版本,所有的卷积核都在上一层的所有输出上来做,那5×5的卷积核所需的计算量就太大了,造成了特征图厚度很大。为了避免这一现象提出的inception具有如下结构,在3x3前,5x5前,max pooling后分别加上了1x1的卷积核起到了降低特征图厚度的作用,也就是Inception v1的网络结构: Inception V2-V3:V2和V3版本比较接近,就不绝对区分了,具体可以看[3]。讲一讲其中的创新点: 首先,用两层堆叠的33代替了一层55,我们可以看到,这样做参数量少了,计算量少了,但是层数变深了,效果也变好了: Inception v4模型v4研究了Inception模块结合Residual Connection能不能有改进?发现ResNet的结构可以极大地加速训练,同时性能也有提升,得到一个Inception-ResNet v2网络,同时还设计了一个更深更优化的Inception v4模型,能达到与Inception-ResNet v2相媲美的性能。","link":"/2018/05/17/深度学习中的highway network、ResNet、Inception/"},{"title":"爬取汽车之家实战","text":"1. 任务简介 及 爬虫架构极前面学习了,爬虫的基本架构。现在要动手实践了,因为师兄说“学一门语言就必须上手去练习!”。 爬取哪个网站呢?正好,最近需要汽车之家上面的数据, 我就爬这个。本文代码全部共享于GitHub上,地址:爬取汽车之家实战:github 目标:爬取100种汽车的名字,以及网友对它的评分。 下面开始编程: 在pychram中创建一个工程 在工程中新建一个python包 新建一个main类 创建各个功能类:url管理器、网页下载器、网页解析器、保存获取的信息 下面贴上main类的代码(有详细注释): 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152# 加载url管理器、下载器、解析器、输出器from autohome_spider import url_manager, html_downloader, html_parser, html_outputerclass SpiderMain(object): # 初始化各个对象 def __init__(self): self.urls = url_manager.UrlManager() self.downloader = html_downloader.HtmlDownloader() self.parser = html_parser.HtmlParser() self.outputer = html_outputer.HtmlOutputer() def craw(self, root_url): # 记录当前爬取的是第几个url count = 1 # 将入口url添加进url管理器,这样url管理器就有了待爬取的url,我们就可以启动爬虫的循环 self.urls.add_new_url(root_url) # 当url管理器有新的url时,启动循环 while self.urls.has_new_url(): try: # 获取待爬取的url new_url = self.urls.get_new_url() # 实时打印爬取数和爬取url print('craw %s : %s' % (count, new_url)) # 下载器下载页面 html_cont = self.downloader.download(new_url) # print(html_cont) # 解析器解析url和页面,得到新的url和数据(返回两个值) new_urls, new_data = self.parser.parse(new_url, html_cont) # 获得的新的url添加进url管理器 self.urls.add_new_urls(new_urls) # 收集数据 self.outputer.collect_data(new_data) # 设置爬取数 if count == 100: break count = count + 1 except Exception as e: print(str(e)) # 输出收集好的数据 self.outputer.output_html()if __name__ == '__main__': # 爬虫入口url root_url = 'http://www.autohome.com.cn/78/#pvareaid=103177' obj_spider = SpiderMain() obj_spider.craw(root_url) 2. url管理器url管理器存放已经抓取的url和还没抓取的url 123456789101112131415161718192021222324252627282930313233343536class UrlManager(object): # 初始化存放新的url列表和爬取过的url列表 def __init__(self): self.new_urls = set() self.old_urls = set() # 向url管理器添加一个新的url def add_new_url(self, url): # url是否是空 if url is None: return # url是否存在在新的url列表和爬取过的url列表中 if url not in self.new_urls and url not in self.old_urls: self.new_urls.add(url) # 向url管理器添加新的url(urls是 解析器 返回的新的url列表) def add_new_urls(self, urls): # urls是否是空 if urls is None or len(urls) == 0: return # 逐一添加url for url in urls: self.add_new_url(url) # url管理器是否有新的待爬取url def has_new_url(self): return len(self.new_urls) != 0 # 从url管理器中获取新的待爬取url def get_new_url(self): # 获取url并从new_urls中移除 new_url = self.new_urls.pop() # 添加进已爬取old_urls中 self.old_urls.add(new_url) # 返回新的url return new_url 3. 网页下载器网页下载器 将下载所给的url的网页html代码。在这里要特别注意“乱码问题”,解决办法见我另一篇文章–>:Python字符串的encode与decode研究心得——解决乱码问题 代码如下: 12345678910111213141516171819202122232425262728293031323334353637383940from urllib import requestfrom urllib import parse### 使用urllib库进行下载HTML页面class HtmlDownloader(object): def download(self, url): if url is None: return None values = {'name': 'voidking', 'language': 'Python'} data = parse.urlencode(values).encode(encoding='utf-8', errors='ignore') headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0','Content-Length': '0'} request1 = request.Request(url=url, data=data, headers=headers, method='GET') response = request.urlopen(request1) if response.getcode() != 200: return None buff = response.read() html = buff.decode(\"gb2312\",errors='ignore') return htmlfrom urllib import requestfrom urllib import parse### 使用urllib库进行下载HTML页面class HtmlDownloader(object): def download(self, url): if url is None: return None values = {'name': 'voidking', 'language': 'Python'} data = parse.urlencode(values).encode(encoding='utf-8', errors='ignore') headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0','Content-Length': '0'} request1 = request.Request(url=url, data=data, headers=headers, method='GET') response = request.urlopen(request1) if response.getcode() != 200: return None buff = response.read() html = buff.decode(\"gb2312\",errors='ignore') return html 4. 网页解析器网页解析器的主要作用是: 匹配html代码中的所需信息(车名,评分) 找出当前页面中指向另外的车页面的url 代码如下: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253from bs4 import BeautifulSoupimport refrom urllib import parseclass HtmlParser(object): # 获取html中的新的连接 def _get_new_urls(self, page_url, soup): # 结果存入列表 new_urls = set() # 正则匹配:<a href=\"/3589/#pvareaid=101201\" title=\"博瑞\">博瑞</a> links = soup.find_all('a', href=re.compile(r'/\\d+/#pvareaid=\\d+'),title=re.compile(r'\\S')) for link in links: # 获取相对url new_url = link['href'] # 拼接为完整url new_full_url = parse.urljoin(page_url, new_url) # print(new_full_url) new_urls.add(new_full_url) # print(new_urls) return new_urls # 获取当前页面 汽车的名字以及评分 def _get_new_data(self, page_url, soup): # 存放数据 res_data = {} # url res_data['url'] = page_url # 获取html中的车名 # <div class=\"subnav-title-name\"> <a href=\"/78/\">广汽本田-<h1>雅阁</h1></a> </div> title_node = soup.find( 'div', class_='subnav-title-name').find('a') # 转换成字符串 并去除<h1>标签 res_data['title'] = title_node.get_text().strip('<h1>').strip('</h1>') # 获取html中的汽车评分 # <a class=\"font-score\" href=\"http://k.autohome.com.cn/78/8369/#pvareaid=101486\">4.38</a> summary_node = soup.find('a', class_='font-score') res_data['summary'] = summary_node.get_text() print(res_data) return res_data def parse(self, page_url, html_cont): if page_url is None or html_cont is None: return soup = BeautifulSoup(html_cont, 'html.parser', from_encoding='utf-8') soup2 = BeautifulSoup(html_cont, 'html.parser', from_encoding='utf-8') new_urls = self._get_new_urls(page_url, soup) new_data = self._get_new_data(page_url, soup2) return new_urls, new_data 5. 保存获取的信息这个类用于保存获取的信息,将所需要的信息保存为一个页面,便于查看。如下图: 代码如下: 1234567891011121314151617181920212223242526272829303132333435class HtmlOutputer(object): def __init__(self): self.datas = [] def collect_data(self, data): if data is None: return self.datas.append(data) def output_html(self): # 在windows下新文件的默认编码是gbk,需手动改为utf-8 fout = open('output.html', 'w', encoding='utf-8') fout.write('<html>') fout.write('<body>') fout.write('<table>') # 表头 fout.write('<tr>') fout.write('<td>公司-车名</td>') fout.write('<td>网友评分</td>') fout.write('</tr>') for data in self.datas: fout.write('<tr>') # fout.write('<td>%s</td>' % data['url']) fout.write('<td>%s</td>' % data['title']) fout.write('<td> %s</td>' % data['summary']) fout.write('</tr>') fout.write('</table>') fout.write('</body>') fout.write('</html>') fout.close()","link":"/2017/05/02/爬取汽车之家实战/"},{"title":"破解myeclipse10时找不到myeclipse-Common-plusgin","text":"破解myeclipse10时找不到myeclipse/Common/plusgin 说明你原来安装过myeclipse,这个文件夹有默认跑到原来的路径了。 解决方法,查看你最新安装的路径下的 .ini文件(myeclipse.ini)。 里面有myeclipse/Common/plusgin的路径","link":"/2015/03/27/破解myeclipse10时找不到myeclipse-Common-plusgin/"},{"title":"词嵌入来龙去脉 word embedding和word2vec","text":"0词嵌入来龙去脉之前一段时间,在结合深度学习做NLP的时候一直有思考一些问题, 不少的terms like: 词向量、word embedding、分布式表示、word2vec、glove等等, 这一锅粥的名词术语分别代表什么,他们具体的关系是什么,他们是否处于平级关系? 整篇文章的构架是按照属于概念在逻辑上的先后大小顺序,一层一层一级一级地往下剖析、比较、说明。 另外说明下,here整篇文字内容相对是比较入门,甚至有的点可能描述的不太客观正确,限于当前的认知水平……还请您海涵,希望您在评论中指正! 1 NLP的核心关键:语言表示(Representation)Deep Learning如何能在NLP中发挥出应有的real power呢?很明显,先不提如何设计出很强势的网络结构,不提如何在NLP中引入基于NN的解决例如情感分析、实体识别、机器翻译、文本生成这些高级任务,咱们首先得把语言表示这一关过了——如何让语言表示成为NN能够处理的数据类型。 我们看看图像和语音是怎么表示数据的: 在语音中,用音频频谱序列向量所构成的matrix作为前端输入喂给NN进行处理,good;在图像中,用图片的像素构成的matrix展平成vector后组成的vector序列喂给NN进行处理,good;那在自然语言处理中呢?噢你可能知道或者不知道,将每一个词用一个向量表示出来!想法是挺简单的,对,事实上就是这么简单,然而真有这么简单吗?可能没这么简单。 有人提到,图像、语音属于比较自然地低级数据表示形式,在图像和语音领域,最基本的数据是信号数据,我们可以通过一些距离度量,判断信号是否相似,在判断两幅图片是否相似时,只需通过观察图片本身就能给出回答。而语言作为人类在进化了几百万年所产生的一种高层的抽象的思维信息表达的工具,其具有高度抽象的特征,文本是符号数据,两个词只要字面不同,就难以刻画它们之间的联系,即使是“麦克风”和“话筒”这样的同义词,从字面上也难以看出这两者意思相同(语义鸿沟现象),可能并不是简单地一加一那么简单就能表示出来,而判断两个词是否相似时,还需要更多的背景知识才能做出回答。 那么据上是不是可以自信地下一个结论呢:如何有效地表示出语言句子是决定NN能发挥出强大拟合计算能力的关键前提! 2 NLP词的表示方法类型接下来将按照上面的思路,引出各种词的表示方法。按照现今目前的发展,词的表示分为独热表示one-hot、分布式表示distributed。 2.1词的独热表示one-hot representationNLP 中最直观,也是到目前为止最常用的词表示方法是 One-hot Representation,这种方法把每个词表示为一个很长的向量。这个向量的维度是词表大小,其中绝大多数元素为 0,只有一个维度的值为 1,这个维度就代表了当前的词。关于one-hot编码的资料很多,街货,这里简单举个栗子说明:12“话筒”表示为 [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 ...]“麦克”表示为 [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...] 每个词都是茫茫 0 海中的一个 1。这种 One-hot Representation 如果采用稀疏方式存储,会是非常的简洁:也就是给每个词分配一个数字 ID。比如刚才的例子中,话筒记为 3,麦克记为 8(假设从 0 开始记)。如果要编程实现的话,用 Hash 表给每个词分配一个编号就可以了。这么简洁的表示方法配合上最大熵、SVM、CRF 等等算法已经很好地完成了 NLP 领域的各种主流任务。 现在我们分析他的不当处。1、向量的维度会随着句子的词的数量类型增大而增大;2、任意两个词之间都是孤立的,根本无法表示出在语义层面上词语词之间的相关信息,而这一点是致命的。 2.2词的分布式表示distributed representation统的独热表示( one-hot representation)仅仅将词符号化,不包含任何语义信息。如何将语义融入到词表示中?Harris 在 1954 年提出的分布假说( distributional hypothesis)为这一设想提供了理论基础:上下文相似的词,其语义也相似。Firth 在 1957 年对分布假说进行了进一步阐述和明确:词的语义由其上下文决定( a word is characterized by thecompany it keeps)。 到目前为止,基于分布假说的词表示方法,根据建模的不同,主要可以分为三类:基于矩阵的分布表示、基于聚类的分布表示和基于神经网络的分布表示。尽管这些不同的分布表示方法使用了不同的技术手段获取词表示,但由于这些方法均基于分布假说,它们的核心思想也都由两部分组成:一、选择一种方式描述上下文;二、选择一种模型刻画某个词(下文称“目标词”)与其上下文之间的关系。 3 NLP语言模型 在详细介绍词的分布式表示之前,需要将NLP中的一个关键概念描述清楚:语言模型。语言模型包括文法语言模型和统计语言模型。一般我们指的是统计语言模型。之所以要将语言模型摆在词表示方法之前,是因为后面的表示方法马上要用到这一概念。 统计语言模型: 统计语言模型把语言(词的序列)看作一个随机事件,并赋予相应的概率来描述其属于某种语言集合的可能性。给定一个词汇集合 V,对于一个由 V 中的词构成的序列S = ⟨w1, · · · , wT ⟩ ∈ Vn,统计语言模型赋予这个序列一个概率P(S),来衡量S 符合自然语言的语法和语义规则的置信度。 用一句简单的话说,就语言模型就是计算一个句子的概率大小的这种模型。有什么意义呢?一个句子的打分概率越高,越说明他是更合乎人说出来的自然句子。 就是这么简单。常见的统计语言模型有N元文法模型(N-gram Model),最常见的是unigram model、bigram model、trigram model等等。形式化讲,统计语言模型的作用是为一个长度为 m 的字符串确定一个概率分布 P(w1; w2; :::; wm),表示其存在的可能性,其中 w1 到 wm 依次表示这段文本中的各个词。一般在实际求解过程中,通常采用下式计算其概率值: 同时通过这些方法均也可以保留住一定的词序信息,这样就能把一个词的上下文信息capture住。 具体的语言模型详情属于街货,详细请自行搜索。 4 词的分布式表示4.1基于矩阵的分布表示基于矩阵的分布表示通常又称为分布语义模型,在这种表示下,矩阵中的一行,就成为了对应词的表示,这种表示描述了该词的上下文的分布。由于分布假说认为上下文相似的词,其语义也相似,因此在这种表示下,两个词的语义相似度可以直接转化为两个向量的空间距离。 常见到的Global Vector 模型( GloVe模型)是一种对“词-词”矩阵进行分解从而得到词表示的方法,属于基于矩阵的分布表示。 4.2基于聚类的分布表示基于聚类的分布表示我也还不是太清楚,所以就不做具体描述。 4.3基于神经网络的分布表示,词嵌入( word embedding) ==基于神经网络的分布表示一般称为词向量、词嵌入(word embedding)或分布式表示(distributed representation)==。 这正是我们的主角today。 神经网络词向量表示技术通过神经网络技术对上下文,以及上下文与目标词之间的关系进行建模。由于神经网络较为灵活,这类方法的最大优势在于可以表示复杂的上下文。在前面基于矩阵的分布表示方法中,最常用的上下文是词。如果使用包含词序信息的 n-gram 作为上下文,当 n 增加时, n-gram 的总数会呈指数级增长,此时会遇到维数灾难问题。而神经网络在表示 n-gram 时,可以通过一些组合方式对 n 个词进行组合,参数个数仅以线性速度增长。有了这一优势,神经网络模型可以对更复杂的上下文进行建模,在词向量中包含更丰富的语义信息。 5 词嵌入( word embedding)5.1概念基于神经网络的分布表示又称为词向量、词嵌入,神经网络词向量模型与其它分布表示方法一样,均基于分布假说,核心依然是上下文的表示以及上下文与目标词之间的关系的建模。 前面提到过,为了选择一种模型刻画某个词(下文称“目标词”)与其上下文之间的关系,我们需要在词向量中capture到一个词的上下文信息。同时,上面我们恰巧提到了统计语言模型正好具有捕捉上下文信息的能力。那么构建上下文与目标词之间的关系,最自然的一种思路就是使用语言模型。从历史上看,早期的词向量只是神经网络语言模型的副产品。 2001年, Bengio 等人正式提出神经网络语言模型( Neural Network Language Model ,NNLM),该模型在学习语言模型的同时,也得到了词向量。所以请注意一点:==词向量可以认为是神经网络训练语言模型的副产品==。 5.2理解前面提过,one-hot表示法具有维度过大的缺点,那么现在将vector做一些改进:1、将vector每一个元素由整形改为浮点型,变为整个实数范围的表示;2、将原来稀疏的巨大维度压缩嵌入到一个更小维度的空间。如图示: 这也是词向量又名词嵌入的缘由了。 6 神经网络语言模型与word2vec 好了,到目前为止我们已经对的分布式表示以及词嵌入的概念的层级关系有了个理性的认识了,那这跟word2vec有什么联系? 6.1神经网络语言模型 上面说,通过神经网络训练语言模型可以得到词向量,那么,究竟有哪些类型的神经网络语言模型呢?个人所知,大致有这么些个: 12345a) Neural Network Language Model ,NNLMb) Log-Bilinear Language Model, LBLc) Recurrent Neural Network based Language Model,RNNLMd) Collobert 和 Weston 在2008 年提出的 C&W 模型e) Mikolov 等人提出了 CBOW( Continuous Bagof-Words)和 Skip-gram 模型 到这,估计有人看到了两个熟悉的term:CBOW、skip-gram,有看过word2vec的同学应该对此有所了解。我们继续。 6.2word2vec与CBOW、Skip-gram现在我们正式引出最火热的另一个term:word2vec。 上面提到的5个神经网络语言模型,只是个在逻辑概念上的东西,那么具体我们得通过设计将其实现出来,而实现CBOW( Continuous Bagof-Words)和 Skip-gram 语言模型的工具正是well-known word2vec!另外,C&W 模型的实现工具是SENNA。 所以说,分布式词向量并不是word2vec的作者发明的,他只是提出了一种更快更好的方式来训练语言模型罢了。分别是:连续词袋模型Continous Bag of Words Model(CBOW)和Skip-Gram Model,这两种都是可以训练出词向量的方法,再具体代码操作中可以只选择其一,不过据论文说CBOW要更快一些。 顺便说说这两个语言模型。统计语言模型statistical language model就是给你几个词,在这几个词出现的前提下来计算某个词出现的(事后)概率。CBOW也是统计语言模型的一种,顾名思义就是根据某个词前面的C个词或者前后C个连续的词,来计算某个词出现的概率。Skip-Gram Model相反,是根据某个词,然后分别计算它前后出现某几个词的各个概率。 以“我爱北京天安门”这句话为例。假设我们现在关注的词是“爱”,C=2时它的上下文分别是“我”,“北京天安门”。CBOW模型就是把“我” “北京天安门” 的one hot表示方式作为输入,也就是C个1xV的向量,分别跟同一个VxN的大小的系数矩阵W1相乘得到C个1xN的隐藏层hidden layer,然后C个取平均所以只算一个隐藏层。这个过程也被称为线性激活函数(这也算激活函数?分明就是没有激活函数了)。然后再跟另一个NxV大小的系数矩阵W2相乘得到1xV的输出层,这个输出层每个元素代表的就是词库里每个词的事后概率。输出层需要跟ground truth也就是“爱”的one hot形式做比较计算loss。这里需要注意的就是V通常是一个很大的数比如几百万,计算起来相当费时间,除了“爱”那个位置的元素肯定要算在loss里面,word2vec就用基于huffman编码的Hierarchical softmax筛选掉了一部分不可能的词,然后又用nagetive samping再去掉了一些负样本的词所以时间复杂度就从O(V)变成了O(logV)。Skip gram训练过程类似,只不过输入输出刚好相反。 补充下,Word embedding的训练方法大致可以分为两类:一类是无监督或弱监督的预训练;一类是端对端(end to end)的有监督训练。无监督或弱监督的预训练以word2vec和auto-encoder为代表。这一类模型的特点是,不需要大量的人工标记样本就可以得到质量还不错的embedding向量。不过因为缺少了任务导向,可能和我们要解决的问题还有一定的距离。因此,我们往往会在得到预训练的embedding向量后,用少量人工标注的样本去fine-tune整个模型。 相比之下,端对端的有监督模型在最近几年里越来越受到人们的关注。与无监督模型相比,端对端的模型在结构上往往更加复杂。同时,也因为有着明确的任务导向,端对端模型学习到的embedding向量也往往更加准确。例如,通过一个embedding层和若干个卷积层连接而成的深度神经网络以实现对句子的情感分类,可以学习到语义更丰富的词向量表达。 6.3个人对word embedding的理解现在,词向量既能够降低维度,又能够capture到当前词在本句子中上下文的信息(表现为前后距离关系),那么我们对其用来表示语言句子词语作为NN的输入是非常自信与满意的。 另外一点很实用的建议,在你做某一项具体的NLP任务时如你要用到词向量,那么我建议你:要么1、选择使用别人训练好的词向量,注意,得使用相同语料内容领域的词向量;要么2、自己训练自己的词向量。我建议是前者,因为……坑太多了。 说到这里,其实我并没有想继续说下去的打算了,即并没有打算将word2vec的数学原理、详解啥的统统来一顿讲了,因为我发现网上关于讲解word2vec的文章实在是太多了,多到几乎所有的文章都是一样的。所以我也没有必要再copy一份过来咯。 所以,要详细了解word2vec、cbow、skip-gram细节的请您仔细搜索。我相信,在了解了这一系列的前提上下文知识的背景下,你再去读word2vec相关的细节文章时,一定不会感到有多吃力。","link":"/2017/08/14/词嵌入来龙去脉 word embedding和word2vec/"},{"title":"运维团队(OPS)与技术团队有效沟通配合探讨","text":"一、技术团队细分及配合问题在IT企业里产品从创意到交付给用户,从整体上看是由技术部门负责,但如果深入到技术部门,会发现由不同的技术团队负责不同的部分或者阶段。一般会分产品团队、开发团队、测试团队以及运维团队,在互联网公司里,运维团队一般还分基础运维和产品运维两个团队,基础运维负责基础设施(包括机架、网络、硬件)和操作系统的安装,为整体公司的所有产品提供基础设施的运维服务。而产品运维负责线上产品的问题处理、代码的布署和跟开发的接口等。 不同的技术团队一般隶属不同的部门,分散在公司不同的办公区域,团队内部的沟通相对多一些,但团队之间的沟通较少。不同团队都会形成自己的办事习惯、节奏,都有自己的关注点,一般只是知道与之接口的团队的总体职责,但是不知道对方可能面临的困难与工作中的挑战点。另外,如果公司够大,每个团队内部又会分为许更细的小团队,如基础运维一般有系统团队、网络团队和IDC团队等,这样更加重了团队之间沟通难度。 从产品策划到上线,一般是以下边的顺序经过各个团队: 开发团队收集产品的需求,定下时间表并进行开发 开发完后,交由测试或质量团队进行测试 然后交给运维团队布署新产品或新版本 运维团队将运维过程中发现的代码缺陷反馈给开发团队进行修复 在上面的每个阶段,对应的团队都是各做各的,一般是在最后才会把球踢给下一个团队,如果下一个团队发现问题又会把球踢回原来的团队。如果你深入到不同的团队中去,或听到不同的抱怨声音。 基础运维团队经常抱怨: 产品开发一点计划都没有,突然要上线机器,让我们措手不及。每个产品都急着上线,谁催得急就上谁的,谁能说一下,到底那个重要?动不动就要重装系统,坏了一块盘就着急去修,刚从机房回来,又要过去。上线太突然了,没有交换机,没有机架,还需要搬别的机器腾地方。那个地方有机架和交换机端口,但没有四层设备,他们又要放在四层后边,真的没有办法了。刚跟他们上线到一个机房,他们又说要换到另一个机房,尽折腾。他们怎么能那么用设备,把上连端口带宽都跑满了。 产品运维团队会说: 真没办法,上个线不是说没机架,就是没有交换机,还有就是说没有四层设备。从来不告诉我们什么时候能设备能上线交付给我们,不派专人催着这事,一点谱都没有。本来没有想好怎么用这些设备,先提前一个月申请上线,得我们想清楚了,他们却说又得换机房。网络怎么老是出问题,他们怎么规划的。开发的代码太不靠谱,一上线就引发用户投诉,只能回滚到老版本。开发人员的技术能力不行,写不出能用的版本。开发要求有一个跟生产环境一样的测试环境,这不可能有的。 而开发团队却说: 他们又不让我们碰线上的系统,生产环境是什么样,我们都不知道,没法开发代码。我们辛苦开发几个月,上线出问题又直接回滚了,心情很不好受。代码在测试环境或我的机器跑的好好的呀,怎么一上线就出问题呢。测试怎么测的,那么多问题发现不了。我们希望产品运维同事帮忙搭一个跟线上一模一样的测试环境。 另外,测试团队的人也许会说: 开发人员不写规定写单元测试代码。想着能用一个自动的集成测试环境,因为开发的原因,老是实现不了。测试环境跟生产环境不一样,好多问题才发现还有那么多的bug没有解决,产品就催着上线。 二、技术团队之间配合不好的影响上面看到的团队之间的冲突和抱怨问题虽然都不一样,产生的影响确是类似的:产品上线的进度延误,整个团队很难正常交付新版本。产品上线后问题很多,影响用户的访问。团队的士气很差。 最近又发生了运维团队与开发团队之间的配合不好的问题,影响及原因如下:新产品上线延误了两个星期,正常情况下一天就可以上线。原因是开发考虑不周,测试环境中没有发现,到上线前才发现部署到多台机器上后,按开发原先计划的方式多台机器无法协作完成任务。还有就是在设计阶段没有考虑生产环境的状况,在上线的过程中需要做出对应的代码调整。上线后质量不稳定,出现多次紧急修复。原因同上。 临时增加硬件投入。新产品中有个组件采用全新的技术方案,跟原来的LAMP体系不兼容,所以需要新增机器,单独部署。 除低了服务可用性标准,并产生了遗留问题。因为临时需要增加硬件,而恰好又只有一台,这样就形成了单点,如果该机器出现故障,服务将全部中断。另外,由于开发前设计上考虑不周,跟别的组件集成时产生别的单点。所以这些降低了服务的可用性,以后还得想办法解决。除此之外,组件采有新的软件,安装、服务起停以及软件配置的管理都是纯手工打造,以后还得找时间纳入到自动配置管理中。 影响了团队士气。在上线过程中开发、测试和运维都觉得不舒服,相互之间产生了抱怨。如果不处理好,会影响以后的配合。 虽然,有些问题确实需要靠某些团队提高自身的人员技能才能解决好,但这些团队能够形成一股合力的话,同样的人员组合肯定会产生更好的效果。 三、过去解决团队配合问题的方法第一次碰到团队之间的配合问题时,我们还没来得及解决的时候,公司战略调整,整个开发和系统运营团队转给了另一个大部门。但我们在别的地方重新梳理技术团队时,后来又没有出现这种问题,回想起来,我们的做法是: 部分开发人员有生产环境中服务器的帐号,可以观察代码的运转情况,少数核心开发人员还有sudo权限,当然他们也不会随便修改服务器的设置 开发时一开始就会跟系统运维团队沟通,在代码中增加数据收集的接口和监控接口,这样上线后,很容易收集产品的性能数据,并能方便地对运行状态进行监控与报警生产环境中也有沙箱与beta环境,这样大的版本从测试中过渡到生产环境前,先在沙箱环境中适应一段时间,这样能相对平稳过渡到生产环境 部分开发人员临时转到系统运维团队工作一到二个季度,跟系统运维同事一起上线产品,解决产品在运行中发生的问题,这样更好地了解代码如何在生产环境中运行,回去之后能更好地运维同事沟通,开发出来的代码更容易在生产环境中运行 这样,不同团队之间虽然有职责上的明确分工,但在中间的配合的部分做了不少柔性处理。另外,开发、运维与测试等团队中的核心人员之间本身就有认同感,大家一开始的目标就是奔着公司能成功来的,这是没有出配合问题的根本原因。这一点其实跟DevOps的核心点类似,既然如此,何不重新审视一下DevOps,并参考着解决团队之间的配合问题呢。 四、DevOpsDevOps是2010年从欧洲传过来的概念,最先是由一群有着跨学科技能的工程师提出来的,为了解决下面的问题: 推出新功能和解决老问题的周期过长 新产品或新版本上线充满风险,代码能否在生产环境中稳定运行,没有人有信心,只能艰难地推上去,再看是不是有问题 不同团队相互隔离,配合差。如开发人员收到问题后,第一反应是“在我的机器上工作得好好的呀” 我认为DevOps的核心是不管你是开发者、测试人员、管理者、DBA、网络工程师还是系统管理员,大家都是一起的,只有一起努力给客户提供稳定而高质量的软件服务,实现公司的商业利益才会有别的,包括自己的工作机会。 所以,DevOps实际是给各个团队之间搭桥,让他们不仅仅是依靠上线申请单这样的鸿雁传书工具进行沟通,而且经常离开自己的孤岛,走到别人的岛上去,了解别人,并提供自己的想法,帮助对方。 DevOps更象是一种运动,每家公司都需要根椐自身的特点进行借鉴,推动团队之间的协作与合作。需要在三个方面努力: 人员 一方面对现有人员进行培训,鼓励他们了解别的团队的工作、面临的挑战等,让他们用自己的特长去审视和帮助别的团队,另一方面也想办法招一些全面的技术人才,在不同团队之间搭出一些适用的桥来。 流程 在研发的前期,让系统运维同事参与起来,一起搭建测试环境,验证想法,或者也可以在一些项目团队中直接配有系统、开发和测试以及产品人员,一起为产品的上线努力。出现问题的时候,一起想方法找到问题的真正根源,避免相互推托,将解决方案落实在以后的研发过程中。从绩效考核流程上也需要考虑协作因素。 工具 说实在的,大家针对DevOps在工具方面其实讨论得更多,这里面跟敏捷有些类似之处。快速的系统部署和自动化产品代码发布方面的工具显得尤为重要了。 为了避免校弯过正,走向另一个极端,也需要避免下面的对DevOps的常见误解: DevOps意味着要给开发者root权限 可以给开发者加sudo权限,运行指定的命令,比如重启web服务。让开发者更多地了解生产环境和产品的运行状况,但并不意味着让开发者象管理员一样的去管理机器。所有系统管理员需要写代码,所有开发者需要上架机器在系统管理和开发者各个领域仍然需要各自的专家,如存储、网络、安装、javascript等专门的人才,DevOps并不意味着让大家不做自己专长的事情。 你一定要用某个工具,不然就不是DevOps一些技术和自动化的工具对推动各个团队之间协作很有帮助,但是还是需要聚焦于要解决的问题,根椐问题和组织的特点选择合适的工具。 我们需要招聘DevOpsDevOps不是一个新的岗位 五、结合DevOps,解决团队配合问题管理人员关注团队之间的沟通机制及氛围: 以新版能在生产环境中可靠稳定运行为目标,形成协作的氛围。在项目的早期,立项之间,运维、开发与测试就进行沟通,可能的话坐在一起,面对面沟通。 在项目上线前,除了测试功能,还要关注部署、备份、监控、安全以及配置管理,在早期发现的问题越多,越能尽少后期的问题并避免影响用户体验。建立各个团队的核心成员定期沟通机制。 团队之间的协作纳入绩效考核过程中去。让开发人员了解运维工作、关注点及挑战,并从开发视角帮助运维:开发人员参与运维团队的内部培训,了解线上的系统。 了解运维如何定位并解决故障、如何监控系统的运转情况等。 少数开发人员可以跟运维一样发版本到生产环境中,让开发人员关注并了解自己代码的运行情况。 从运维的视角修改代码,方便运维人员进行日常的变更与调整,监控与报警。帮助运维人员修改puppet配置模板。 帮助运维人员编写与修改产品的发布脚本,提高自动化水平。 让运维人员了解开发过程的关注点及挑战,并从运维角度改善开发过程: 运维为开发在公司搭建基于虚拟机的测试环境,虚拟机的安装、配置管理以及代码的发布采用跟生产环境一样的方式。 开发人员与测试人员象运维一样发布版本到测试环境中。鼓励开发与测试人员修改puppet配置与模板,管理自己的虚拟机。在生产环境中建立了beta环境,开发人员可以直接发版本上去,让代码在最终上线前多一层缓冲。 运维去了解代码的模块结构,从运维的角度修改代码,让产品上线后更方便运维与适应生产环境的特点。 运维参与到持续的集成测试中,用自己的自动化知识帮助实现自动的集成测试等。","link":"/2016/09/20/运维团队(OPS)与技术团队有效沟通配合探讨/"},{"title":"零基础学习GitHub桌面版-1 GitHub桌面版的下载安装与使用","text":"GitHub桌面版的操作GitHub桌面版对于个人用户非常方便,不用去记忆那么多的命令,只需要懂得一些概念,然后点击界面即可。 1 下载GitHub桌面版下载客户端,这里推荐大家去官网下载:https://desktop.github.com/ 点击download即可: (官网只提供了windows和mac版本,暂时没有linux版,让我们一起期待吧~) 2 安装下载好后双击运行,这个安装程序比较奇葩,是强制安装路径的(与谷歌chrome很像),运行后什么界面都没有,后台安装中间会重启一次,大概等到你觉得它已经安装好后,双击桌面的github就可以了。 3 github客户端的使用3.1创建库先来创建一个仓库,仓库里的文件变动都会被github记录下来 点击又上角的File,然后有一个New repository 给仓库取个名字,给它在本地找一个地址, 然后把第三行的单选框勾上,相当于一个初始化,会创建一个readme文件,这个文件一半是用来介绍自己项目是做什么的,怎么用。 3.2修改文件现在来进行仓库的修改 进入仓库的目录,新建一个txt文件,此时,github上就有显示了 (或者直接用文本编辑器修改TXT,GitHub也能检测到) (或者将你原来写好的程序组复制进去,GitHub也能检测到) 3.3提交版本conmmitcommit的意思是“版本”,你修改了依稀代码,那么此时此刻这个项目就进入了新的“版本”,所以如果你确定刚刚做的修改,就应该点击conmmit,提交当前版本。 对修改进行适当地解释,并点击左下角 commit to master 在History历史界面里,你可以看到自己过去的修改,什么时间修改的,修改了几行代码等等。那么等你修改好了几次之后,觉的差不多世纪成熟可以上传了,就可以进入下一步 “同步到云端publish” 3.4同步到云端publish以上修改和提交版本,都是在本地进行的,云端的github网站上并没有变化。所以如果你确定你在本地的修改,就应该推送publish到云端。 如果是云端仓库已经存在当前项目,点击publish就会同步你本地的修改到云端,并刷新云端数据 如果是你第一次publish,点击之后就会弹出以下界面,问你是否在云端创建与本地相同的仓库,当然选择是喽~ 单选框不要选,只有付费用户才可以创建私有仓库,然后点击publish respository仓库就同步到云端了。 3.5 Github主页上查看Test现在到自己的Github主页上查看Test仓库,可以看到我们新建的”test.txt”已经出现在个人主页上了。 4总结注意:你随时可以修改自己的本地代码,然后按照上面的流程走一遍,云端的代码就会更新,来让我们一起读一遍上述流程:modify -> conmmit -> publish -> view 中文就是:修改 -> 提交版本 -> 发布到云端 -> 在网站上查看 怎么样,用客户端玩转GitHub是不是超简单?继续跟着我一起探索GitHub桌面版吧~","link":"/2017/08/30/零基础学习GitHub桌面版-1 GitHub桌面版的下载安装与使用/"},{"title":"零基础学习GitHub桌面版-10给博客添加萌萌的live2d插件","text":"1 效果预览我们希望在网站上显示一个好看的动漫形象,live2d这个库完美的解决了我们的需求。 单个效果预览: 所有动画效果:https://huaji8.top/post/live2d-plugin-2.0/ 2 安装过程2.1 安装总插件在hexo的根目录下执行1npm install --save hexo-helper-live2d 2.2 安装喜欢的具体模型安装完总插件后,可以安装喜欢的模型 所有动画效果可以在这个网站观看:https://huaji8.top/post/live2d-plugin-2.0/ 选择一个自己喜欢的,比如tororo(白猫),下载具体的模型: 在根目录下执行:1npm install live2d-widget-model-tororo (喜欢别的形象就把tororo换成别的名字) 2.3 移动模型地址 从hexo的根目录的node_modules中找到刚刚安装的模型文件夹,比如我这里安装的是:live2d-widget-model-tororo ;复制这个文件夹。 在hexo的根目录创建名为live2d_models的文件夹 把之前找到的的模型文件夹从node_modules文件夹复制到live2d_models中 2.4 配置使用在hexo根目录下的_config.yml中的最后面添加以下内容 12345678910111213141516live2d: enable: true scriptFrom: local pluginRootPath: live2dw/ pluginJsPath: lib/ pluginModelPath: assets/ tagMode: false debug: false model: use: live2d-widget-model-haruto display: position: right width: 150 height: 300 mobile: show: true 3 成功大功告成,部署博客即可。 hexo -d -g 效果如下:","link":"/2019/03/07/零基础学习GitHub桌面版-10给博客添加萌萌的live2d插件/"},{"title":"零基础学习GitHub桌面版-2 分支的使用","text":"分支的使用创建分支的目的在于删除分支!当你对某些修改不确定,不想在主分支上修改,就可以新建一个分支,改的好,就可以合并到主分支。 下面是详细步骤: 1 创建分支我们创建第一个分支取名为“new masterh”,点击Create new branch创建第一个分支。 我们发现此时的分支已经切换到了我们刚刚创建的分支new masterch 我们来修改new masterch分支上的内容。我们仍旧打开FirstDemo.txt进行编辑。输入以下内容 创建的第一个分支。 打开github进行,填写Summary和Description 之后我们点击Commit to new-master 在History目录下,我们可以看到会有两条主线,分别是master和new-master并且在new-master的分支下又一个蓝色的实线空心圈和一个虚线空心圈。实线圈表示当前的节点,空心圈表示下一次修改时的节点。 2 切换分支点击图片左上角部分就会出现分支的列表我们点击master就会切换到master主分支。(当你转换分支的时候,本地文件也会跟着变化) 3 上传/同步分支这个操作和同步仓库是一个操作,点击Publish/Sync上传或同步分支。 4 删除分支首先要把分支切换到你要删除的分支下,如我们要删除new master,将分支切换到new master点击branch菜单栏就会出现Delete 点击Delete new master就会弹出一个对话框,询问删除的内容。 第一个yes ,Delete both是将本地与网页全部删除; 第二个Delete local only仅仅是删除本地。 第三个是取消。 5 合并两个分支Merged当你觉的这个分支不错,可以将其合并到Merged主分支中,然后删除这个分支。 将一个分支与master分支进行合并。我们首先把分支切换到master下,点击branch菜单–>点击 Update from new-branch进行分支的合并。此时我们查看history目录下就会显示多了一个合并版本。","link":"/2017/09/01/零基础学习GitHub桌面版-2 分支的使用/"},{"title":"零基础学习GitHub桌面版-3 团队协作流程","text":"团队协作流程GitHub Flow是一个轻量级的,基于分支的工作流程,支持团队和部署在那里的定期做项目。 这个应用适用于这样的情境中:同公司的几个同事共同开发一款应用,大家拥有相同的权限,相同的目标,相同的责任。这种情况下,可以开启团队合作模式。 团队成员可以各自修改改进代码,然后发起讨论,讨论通过后,合并成一个总分支,流程如下图: 团队合作共有一赋予权限 创建分支并修改版本 打开一个拉取请求Pull Request。 讨论和审核你的代码 部署Deploy 合并Merge 1为团队成员写入权限在我们的队友添加一个写的权限,这样我们的队友才能很好的修改代码。 我们打开网页上的GitHub,点击settings, 之后我们找到collaborators,这里会让我们验证密码,之后就有添加合作者的选项。这样我们就能添加我们的小伙伴了! 这样我们就添加了新的小伙伴,新的小伙伴有着同样的权限去修改和管理代码。此时我们就会看到我的小伙伴的github主页上就会出现关于我创建的First的各种通知。 2创建分支并修改版本 在我们创建一个叫add new function的分支。 Create a branch 修改新的版本填写好新的Summary和Description,提交新的版本并同步。 这样其他小伙伴登陆到GitHub上就看到了就可以清楚的看到一切的修改。 3打开一个拉取请求Pull Request 这个是整个流程中最关键的一步,发布Pull Request。意思是告诉小伙伴我做了一些修改,大家看看怎么样?可以的话就作为主分支了哦~ 点击客户端或者网页上的Pull Request发布。我们这里点击Pull Request 我们填写好必要的说明性文字,界面如下: 点击Send Pull Request 这样分其他小伙伴就看到了你的请求,他们会审核你写的代码,也许会提出修改意见,也许会直接同意,并同意发布。 4讨论和审核你的代码 你的小伙伴开始对你的代码讨论,您还可以继续推送到你的分支在你提交的讨论和反馈光。如果有人评论说,你忘了做某件事,或者如果在代码中的错误,你可以在你的分支修复它,进行版本的更新。直到达成一个大家都满意的状态。 5合并Merge 一旦你拉的请求进行了审查,并且大家通过你的测试,您可以部署您的更改。如果你的分支造成的问题,您可以通过部署现有的主投产回滚。 现在,您的更改在生产中得到了验证,现在是时候你的代码合并到主分支。将其合并到Merged主分支中,然后删除这个分支。 merge的具体流程参照上篇日志:零基础学习GitHub桌面版-2分支的使用","link":"/2017/09/03/零基础学习GitHub桌面版-3 团队协作流程/"},{"title":"零基础学习GitHub桌面版-4 怎么给开源项目贡献代码?","text":"[toc] 怎么给开源项目贡献代码?给别人贡献代码,特别是一些开源组织,是件光荣的事。 有两种方式: 成为项目合作者,直接改别人的。 fork别人的项目到自己本地,更改后请求原作者接纳自己的修改。 可能都给权限。 所以本章我们着重介绍第二种方法,下面是方法的具体步骤: 1点击fork喜欢的项目在github上找到自己想要贡献代码的地址,如图1点击fork。 然后回到自己github主页查看仓库,可以看到我们仓库里也躺着一个一样的项目。 而且还写着原作者是谁,图中红箭头标记了fork的地址 2修改代码既然已经fork了别人的项目到了自己的主页,那么就可以实现早前的想法了。先用客户端把代码下载clone到本地,把自己想改的都改了。 2.1 克隆clone的方法进入自己的github网站,找到想要复制的项目,进入浏览器的地址栏,复制这个项目的链接。 打开github客户端,点击file菜单 –> 选第三个 clone repsitory,出现以下图片: 在一个栏目填入你刚刚复制的链接,第二个栏目填入想要存放的本地目录,点击clone即可。 这样项目就下载到本地了。 2.2 更新到github仓库在本地拿到代码之后,修改你想要修改的地方。然后做成版本commit。然后更新到云端。 不会修改和上传的请看我之前的文章: 零基础学习GitHub桌面版-1 GitHub桌面版的下载安装与使用 3修改完成后Pull request等你觉得想要把你改的发给原项目同步,就在你的项目上点Pull request按钮. 原有项目就会收到推送消息,原作者查看你的修改之后,如果觉得不好会给你提出意见,觉得好,就你的扯进主分支了。 这样,你也就完成了对开源项目的贡献。 我们来复习一下整个逻辑: fork别人的项目到自己帐户 从自己账户下载到本地 在本地修改 把修改上传到自己的github账户 从自己的账户向原主人发起pull request 4小问题:原项目已修改?如果你更改代码比较慢,那么有个问题出来了,在你fork他的项目之后,你还没来得及修改完成。而原主人又更新了代码,如果你直接修改老版本,会造成与原作者新版冲突。那么你自己fork的项目怎么做到和原项目同步呢? 有一个小技巧来解决: 就是,在本地弄俩仓库分支,一个是对应原作者的远程库,一个对应自己folk出来的远程库。第一个库专管拉原作改动(pull),第二个库管开发和提交到自己的远程库。 等你改好了第二个分支,就先合并到第一个分支中去(因为第一个与原作者同步),然后再把合并后的整个项目Pull request。","link":"/2017/09/03/零基础学习GitHub桌面版-4 怎么给开源项目贡献代码?/"},{"title":"零基础学习GitHub桌面版-5 github的使用技巧","text":"github的使用技巧在上述的几篇教程里讲解了一些Github的基础使用,看完之后一定要自己动手操纵一遍才能有深刻印象。等把这些个功能都试过一遍之后,你会发现这些东西都是相通的,可以举一反三。 千面学会了基础的用法,今天开始分享一些github使用小技巧。 1 查找内容 在github页面上是没有搜索的按钮,如何搜索呢。在网页上按 T就会出现。 这样我们就能很方便的查找到我们需要的代码了。 2 评论小表情常常在版本描述或者pull request时我们需要对伙伴的代码进行一下评论与说明,光是文字有点很死板,其实github给我有emoji,如何使用呢? 其实很简单,只需要冒号就可以 : 这样我们就可以看到emoji表情,当然默认会显示五个常用的,你也可以继续敲下emoji的名字,出现更多。 这里有所有的表情表示方式https://www.webpagefx.com/tools/emoji-cheat-sheet/ 3 忽略不想上传的文件有些在github中的文件我们是不想上传的,我们如何过滤掉它们呢?在github中对不想上传的文件点击右键。就会出现下面选项。 Ignore file忽略这个文件Ignore all.txt files 忽略所有的以.txt结尾的文件这样就可以过滤掉你不想上传的文件 4 搜索项目当学习一个新的领域的时候,在github看别人的源码是个不错的方式。 那么如何高效的搜索一个你想要的库呢?我们常常评判一个项目的标准有star数目,fork数目和跟新时间。通过搜索命令123starsstars:>1000 表示star数目大于1000。123forkfork:>1000 表示fork数目大于1000。 123语言搜索java,html等等 综合一下就是,比如你要查找一个stars大于1000的,fork大于200的java代码。 1stars:>1000 fork:>200 java 5 查看项目中的语言类型这个比较好玩: 一个项目中,可能使用了多种语言,我们如何一下子就能看到一个项目使用了什么语言?其实很简单,Github已经为我们统计好了。也行你注意过,但是没有发现它有什么用。 点击下面的彩条 github已经为我们统计好这个项目所有的语言及其比例。 一些常见的代码表示颜色","link":"/2017/09/04/零基础学习GitHub桌面版-5 github的使用技巧/"},{"title":"零基础学习GitHub桌面版-6使用pages创建网站","text":"0 使用pages创建网站折腾了几天,尝试用github来搭建自己的个人博客,一直没有找到好的方法。今天看到了一种最简单的搭建教程有所进展,现在试试将自己的经历写下来。 网上有很多帖子讲了要怎么使用github的page服务来搭建个人网站。但是涉及到很多东西。这里介绍最简单的办法——直接fork一个现成的blog。 是的,你没看错!你喜欢谁的博客就把谁的copy下来即可!github本就是一个开放分享的平台~!! 1 Git和GitHub的相关内容(略)这里略去了如何创建github账号,以及git、github的基本用法。参考本系列前面的文章:零基础学习GitHub桌面版 1.1开启gh-pages功能点击界面右侧的Settings,你将会打开这个库的setting页面,向下拖动,直到看见GitHub Pages,如图: 点击Automatic page generator,Github将会自动替你创建出一个gh-pages的页面。 如果你的配置没有问题,那么大约15分钟之后,yourname.github.io这个网址就可以正常访问了~ 如果yourname.github.io已经可以正常访问了,那么Github一侧的配置已经全部结束了。 2 fork现成的blog下面进行最重要也是最爽的一步,fork其他博主现成的blog。 2.1选择你喜欢的风格其实page博客只有几种基础款:Jekyll 、Hexo等,目前是Node.js编写的Hexo比较流行也更为方便。有很多人基于Hexo修改成了自己的风格,我们下面选择几款优秀的改编介绍一下: 下面介绍几个推荐的模板。 效果:http://huangxuan.me/ 复制地址:https://github.com/Huxpro/huxpro.github.io 效果:http://litten.me/ 复制地址:https://github.com/litten/hexo-theme-yilia 效果:http://notes.iissnan.com/ 复制地址:https://github.com/iissnan/hexo-theme-next 效果:https://luuman.github.io/ 复制地址:https://github.com/luuman/hexo-theme-spfk 效果:https://blog.viosey.com 复制地址:https://github.com/viosey/hexo-theme-material 效果:https://www.ezlippi.com/ 复制地址:https://github.com/EZLippi/EZLippi.github.io 我这里选择的是第6个(最后一个),https://github.com/EZLippi/EZLippi.github.io 2.2 fork项目我们首先在GitHub中找到自己想要fork的博客仓库。比如这个 https://github.com/EZLippi/EZLippi.github.io,然后我们将它fork到我们自己的GitHub上。 这时你的GitHub仓库中就多了一个叫EZLippi.github.io的仓库。假设你的GitHub用户名是tom,因为GitHub Pages服务的原因,我们需要将刚刚fork的EZLippi.github.io的名字修改为:tom.github.io。修改方式为在当前库中点击setting修改名字。这样修改好之后,就可以通过 https://tom.github.io/ 来访问你的博客啦。这里要注意的是,一定要用你的用户名来给仓库命名。 3 发布新博文在_posts文件夹中新建文件,文件命名是有要求的,必须是日期+英文文件名+md。比如:2017-07-07-how-to-build-blog.md。 建立新的文件后就可以开始写作了。但要注意的是每篇博文的最开头一定要插入一段代码,指明博文的相关属性,这样github才能够正确解析它,用户也才能看到正确显示的格式。通常需要设置的信息有如下几个: 1234567---layout: post title: 搭建博客 categories: [blog ] tags: [blog, ] description: 「这个博客是怎么搭建起来的」 --- layout: 表示你要用的模版,一般就用默认的就行 title:就是你的这篇博文的名字 categories:表示这篇博文所属的类别 tags:表示这篇博文要打的标签,如果有多个标签,需要用英文半角逗号分隔开 description:就是概括下整篇博文的主要内容","link":"/2018/01/18/零基础学习GitHub桌面版-6使用pages创建网站/"},{"title":"零基础学习GitHub桌面版-7使用Hexo建站并更换主题","text":"0什么是 Hexo?Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。 配合Hexo与github可以免费、快速配置出强大、绚丽的个人网站!哈哈,动心了把?一起来做把。 1 安装Hexo安装 Hexo 只需几分钟时间,若您在安装过程中遇到问题或无法找到解决方式,请提交问题,我会尽力解决您的问题。 1.1安装前提安装 Hexo 相当简单。然而在安装前,您必须检查电脑中是否已安装下列应用程序: Node.js Git 如果您的电脑中尚未安装所需要的程序,请根据以下安装指示完成安装。 1.2安装 Git: Windows:下载并安装 git. Mac:使用 Homebrew, MacPorts :brew install git;或下载 安装程序 安装。 Linux (Ubuntu, Debian):sudo apt-get install git-core Linux (Fedora, Red Hat, CentOS):sudo yum install git-core 1.3安装 Node.js安装过程参考:http://www.runoob.com/nodejs/nodejs-install-setup.html linux下安装:安装 Node.js 的最佳方式是使用 nvm。 cURL: 1$ curl https://raw.github.com/creationix/nvm/master/install.sh | sh Wget: 1$ wget -qO- https://raw.github.com/creationix/nvm/master/install.sh | sh 安装完成后,重启终端并执行下列命令即可安装 Node.js。 1$ nvm install stable Windows直接下一步下一步安装:可以下载 安装程序 来安装。 1.4安装 Hexo所有必备的应用程序安装完成后,即可使用 npm 安装 Hexo。 $ npm install -g hexo-cli 1.5 遇到的问题 报错: /usr/bin/env: node: No such file or directory 解决办法: 12sudo rm /usr/bin/nodesudo ln -s /usr/bin/nodejs /usr/bin/node 此时若出现如下报错: 12ERROR Local hexo not found in ~/blogERROR Try runing: 'npm install hexo --save' 则执行命令: 1sudo npm install hexo --save 发布文章中出现的错误:12$ hexo deployERROR Deployer not found: git 解决办法:安装 hexo-deployer-git:1sudo npm install hexo-deployer-git --save 然后设置你的github地址和名字:12git config --global user.email "[email protected]"git config --global user.name "Your Name" 2建站Hexo安装好了之后,就开始进行建站。打开终端cd到桌面并使用如下命令即可建好: 123hexo init yournamecd yournamenpm install 其中yourname是你的文件夹名字可随意取(本文章假设yourname的文件夹名称是Hexo)。 建站好了之后需要了解更多的信息和其他步骤请参考官网的这篇文档。https://hexo.io/zh-cn/docs/setup.html 这里需要特别提一下,官方的文档里并没讲解如何配置与Github pages进行关联,在此特意说一下配置信息。进入到你的站点(使用hexo init yourname命令时,这里的yourname文件夹目录,刚假设yourname是Hexo,所以我们进入Hexo目录),然后以文本编辑器打开_config.yml文件,并滚动到最下面添加如下配置信息(注意最下边有deploy和type字段,覆盖这两个字段或者删除这两个字段然后复制下面的四个字段也行。): 1234deploy:type: gitrepo: https://github.com/xqtbox/xqtbox.github.io.gitbranch: master 把其中repo字段的值替换成你的github pages提交代码的git地址。 你的github pages的git提交地址。。。如图: 好吧,到此你使用终端,然后进入到你的站点文件夹使用hexo s命令,如果成功会打印类似Hexo is running at http://localhost:4000/. Press Ctrl+C to stop的一句话,再打开你的浏览器输入localhost:4000地址见证神奇的一刻吧。 2.1简单的配置您可以在 _config.yml 中修改大部份的配置。 网站 1234567参数 描述title 网站标题subtitle 网站副标题description 网站描述author 您的名字language 网站使用的语言timezone 网站时区。Hexo 默认使用您电脑的时区。时区列表。比如说:America/New_York, Japan, 和 UTC 。 其中,description主要用于SEO,告诉搜索引擎一个关于您站点的简单描述,通常建议在其中包含您网站的关键词。author参数用于主题显示文章的作者。 网址 12345参数 描述 url 网址 root 网站根目录 permalink 文章的 永久链接 格式 :year/:month/:day/:title/permalink_defaults 永久链接中各部分的默认值 网站存放在子目录 如果您的网站存放在子目录中,例如 http://yoursite.com/blog,则请将您的 url 设为 http://yoursite.com/blog 并把 root 设为 /blog/。 其他集体配置参考官网:https://hexo.io/zh-cn/docs/configuration.html 3发布此时。我们的博客只是本地跑起来了,而你的github pages服务器上并没有,所以你就需要在你的站点里使用终端命令进行发布: 123hexo cleanhexo g hexo d 命令详解,第一条是清楚缓存,第二条命令是生成本地发布文件夹,第三条命令才是最后的发布到github pages上。更多的hexo命令操作请参考官方文档即可。不过一般用来用去无非就是创建页面、发布这么几条命令而已。Hexo官方命令参考文档 其实学习一个新东西有事没事多去官方看文档,比在网上查资料要来的更靠谱的多。 其中出现的错误:12$ hexo deployERROR Deployer not found: git 解决办法:安装 hexo-deployer-git:1sudo npm install hexo-deployer-git --save 然后设置你的github地址和名字:12git config --global user.email "[email protected]"git config --global user.name "Your Name" 这样在你的网站中,就出现了第一篇文章helloworld。 下一篇我再写如果写文章。 4 HEXO主题如果你到了这里没有任何问题,那么恭喜你已经成功了,不过这才刚刚开始。 当你成功的看到自己博客搭建好的那一刻又是激动又是失望,激动的是博客总算折腾出来了,失望的是,为何如此的丑。。。说实话Hexo默认的主题自我感觉还过得去,如果你想换风格,Hexo的主题网上随便一搜也有很多。 在此笔者使用的博客主题是icarus。这个网站 https://github.com/iissnan/hexo-theme-next 给了详细的主题安装过程。 4.1 安装主题 进入你的网页文件夹,里面必须有这些文件:node_modules, source, themes and other directories: 123$ cd myblog$ ls_config.yml node_modules package.json public scaffolds source themes 从github获取主题: 在主题文件夹里面建立一个主题文件夹,然后下载最新:12$ mkdir themes/icarus$ curl -s https://api.github.com/repos/ppoffice/hexo-theme-icarus/releases/latest | grep tarball_url | cut -d '"' -f 4 | wget -i - -O- | tar -zx -C themes/icarus --strip-components=1 4.2更新12cd themes/icarusgit pull 在站点配置文件_config.yml中更改: 1theme: icarus 到这里你的博客就初出茅庐啦~哈哈 欣赏一下:","link":"/2018/02/01/零基础学习GitHub桌面版-7使用Hexo建站并更换主题/"},{"title":"零基础学习GitHub桌面版-8配置你的Hexo","text":"1. 完善你的页面新站初见,还有一些网站页面是空的,比如tags还有分类页面、自我介绍页面,打开的时候显示404,下面挨个配置。 1.1 标签页 Tags page添加一个标签页面,里面包含您网站中的所有标签。 使用hexo命令创建一个名为 tags 页面 1hexo new page "tags" 此时生成了文件夹:INFO Created: ~/Desktop/MyBlog/source/tags/index.md 编辑标签页 index.md, 设置页面类型为tags. 1234title: All tagsdate: 2018-01-18 13:39:45type: "tags"layout: "tags" 添加 tags 到主题配置文件 _config.yml 里(注意是主题的配置文件): 1234menu: home: archives: archives tags: tags 然后执行:123hexo cleanhexo g -d然后输入github账号密码 然后去访问自己的网站 https://xqtbox.github.io 吧,哈哈,漂亮 1.2 分类页 Categories page添加一个分类页面,里面包含您网站中的所有分类 使用hexo命创建一个名为 categories 页面 1hexo new page "categories" 这样就创建了:INFO Created: ~/Desktop/MyBlog/source/categories/index.md 编辑分类页categories/index.md, 设置页面类型为 categories. 1234title: All categoriesdate: 2014-12-22 12:39:04type: "categories"layout: "categories" 添加 categories 到主题配置文件 _config.yml 里: 1234menu: home: archives: archives categories: categories 然后执行:123hexo cleanhexo g -d然后输入github账号密码 然后去访问自己的网站 https://xqtbox.github.io 吧,哈哈,漂亮 1.3 社交媒体连接 Social Media Contact配置一下主题 可以自动添加链接到您的社交媒体帐户里: 123456social: GitHub: your-github-url Twitter: your-twitter-url Weibo: your-weibo-url DouBan: your-douban-url ZhiHu: your-zhihu-url 填写真实地址即可。 1.3.1如何在contacts中增加新的选项?但是我们不一定有facebook和twitter,那么如何在contacts中增加中文的新的选项?如新浪微博、微信等,并且添加对应的图标? 答案是:访问 http://fontawesome.io/icons/ ,找到自己需要的图标,然后将对应的icon名称直接填入主题的配置文件的cantacts中。例如:12345contacts: github: http://github.com/xqtbox/ twitter: 'https://twitter.com/hanangellove' weibo: "http://weibo.com/1619592223/" rss: atom.xml 这个网站提供了一些国内常见的contact比如 新浪微博、微信、百度等公司,但是这个网站不提供的就不行了。 1.4 Feed 链接 Feed link显示 feed 链接。也就是RSS订阅: 在主题配置文件_config.yml里设置rss , 如下所示: rss: false 会禁用 feed 链接。 rss: 使用站点 feed 链接。这是默认的选项。按照插件hexo-generator-feed的README中的安装说明进行操作。在完成这个插件的配置后,Feed链接也生成好了 rss: http://your-feed-url 设置你的 feed 链接. 2. 评论支持 Comment support博客是用来交流与分享的地方,如果不能评论,那就会少很多乐趣。下面我们配置Disqus 评论系统。 好消息是NexT 已经原生支持 Disqus 评论系统,我们只需要简单配置,过程思路如下: 去disqus官网申请个帐号,免费的。 注册的时候填写一个用户名(shortname) 复制这个用户名在博客配置文件里,就ok了 首先账号的注册过程见: https://www.jianshu.com/p/c4f65ebe23ad 注册好后,进入theme文件夹,再进入你的主题,打开你的主题配置文件 _config.yml 添加以下代码: 1disqus_shortname: your-disqus-shortname 然后执行:123hexo cleanhexo generatehexo deploy 然后去访问自己的网站 https://xqtbox.github.io 吧,哈哈,漂亮 注意,这个评论系统部署在国外,不翻墙是看不到评论的…不过程序员肯定都翻墙,也没关系。 3.开通网站内搜索 Insight Search是一个插件,用于搜索你的网站内的文字。下面是配置方法: install hexo-generator-json-content 1sudo npm install -S hexo-generator-json-content 更改配置文件: 1insight: true 同时可以开启Baidu搜索,但是不推荐。 (Not Recommended) 1baidu: true 4.开通站内统计使用LeanCloud平台为Hexo博客添加文章浏览量统计组件:http://crescentmoon.info/2014/12/11/popular-widget/ 注册LeanCloud(Xu4…) 首先到『控制台』创建一个应用,名字随便取。 点击新建应用的『数据』选项,选择『创建Class』,取名为”Counter“。 点击新建应用右上角的齿轮,在『应用Key』选项里得到APP ID 和 APP Key,在后面会用到。 修改hexo页面生成文件 新建popular_posts.ejs 首先在theme/你的主题/layout/_widget目录下新建popular_posts.ejs文件,其内容为 123456789<% if (site.posts.length){ %> <div class="widget-wrap"> <h3 class="widget-title">浏览数目</h3> <div class="widget"> <ul class="popularlist"> </ul> </div> </div><% } %> 修改head.ejs 修改theme/你的主题/layout/_partial/head.ejs文件,在head标签的最后插入: 12<script src="https://cdn1.lncld.net/static/js/av-min-1.2.1.js"></script> <script>AV.initialize("你的APP ID", "你的APP Key");</script> 修改after-footer.ejs 修改theme/你的主题/layout/_partial/after-footer.ejs文件,在最后插入: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869<!--page counter part--><script>function addCount (Counter) { url=$('.article-date').attr('href').trim(); title = $('.article-title').text().trim(); var query=new AV.Query(Counter); //use url as unique idnetfication query.equalTo("url",url); query.find({ success: function(results){ if(results.length>0) { var counter=results[0]; counter.fetchWhenSave(true); //get recent result counter.increment("time"); counter.save(); } else { var newcounter=new Counter(); newcounter.set("title",title); newcounter.set("url",url); newcounter.set("time",1); newcounter.save(null,{ success: function(newcounter){ //alert('New object created'); }, error: function(newcounter,error){ alert('Failed to create'); } }); } }, error: function(error){ //find null is not a error alert('Error:'+error.code+" "+error.message); } });}$(function(){ var Counter=AV.Object.extend("Counter"); //only increse visit counting when intering a page if ($('.article-title').length == 1) addCount(Counter); var query=new AV.Query(Counter); query.descending("time"); // the sum of popular posts query.limit(10); query.find({ success: function(results){ for(var i=0;i<results.length;i++) { var counter=results[i]; title=counter.get("title"); url=counter.get("url"); time=counter.get("time"); // add to the popularlist widget showcontent=title+" ("+time+")"; //notice the "" in href $('.popularlist').append('<li><a href="'+url+'">'+showcontent+'</a></li>'); } }, error: function(error){ alert("Error:"+error.code+" "+error.message); } } ) });</script> 这段代码的核心逻辑就是对Counter对象的增加和查询,每一篇文章都会有一个time字段来记录访问次数。这里查询的时候我用的是文章通过Hexo生成的URL作为主键的,所以post文件夹目录下的文件名一旦取好就不要轻易修改了,要不然访问次数会重新计算的:)。 修改config.yml 最后,修改theme/你的主题/config.yml文件,在widgets:选项找个位置下添加- popular_posts即可。 还可以参考:https://notes.wanghao.work/2015-10-21-%E4%B8%BANexT%E4%B8%BB%E9%A2%98%E6%B7%BB%E5%8A%A0%E6%96%87%E7%AB%A0%E9%98%85%E8%AF%BB%E9%87%8F%E7%BB%9F%E8%AE%A1%E5%8A%9F%E8%83%BD.html#%E9%85%8D%E7%BD%AELeanCloud 5.小技巧:5.1 设置favicon:favicon的全称Favorites Icon,即地址栏左侧的图标: 有个在线工具可以上传自己的图片去生成指定规格的favicon.ico文件: http://www.atool.org/ico.php 。打开主题配置文件_config.yml可以看到favicon的配置信息: 12# Put your favicon.ico into `hexo-site/source/` directory.favicon: css/images/favicon.png 根据说明,我们将图标取名为favicon.ico然后放到当前工程的hexo\\source目录下,重启博客即可生效。 5.2 主页显示摘要要实现摘要,只需要在文章开头写好摘要后,另起一行键入<!−− more −−>即可,就像这样: 1234---这是摘要<!-- more -->这是正文 也就是想显示多少就显示多少。 如果不想显示“Read More”而显示别的文字比如“阅读更多”,打开主题的配置文件,定位到如下位置: _config.yml 1excerpt_link: Read More 改为: 1excerpt_link: 阅读更多 5.3 文章预览图片如何设置preview 中的文章标题都是在图片下面。 在头文件的里面添加: 1banner: http://blog.zhangruipeng.me/hexo-theme-icarus/gallery/salt-lake.jpg 这样文章又漂亮,在主页上还能显示小图片。 5.4支持数学公式为了支持MathJax数学公式,只需要在主题的_config.yml文件中加上:plugins.mathjax = true1234# Pluginsplugins: ... mathjax: true # options: true, false 同时还要设置/layout/plugin/scripts.ejs:: 1234567<% if (theme.plugins.mathjax) { %> <!-- Edit here --> <script type="text/x-mathjax-config"> MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ['\\\\(','\\\\)']] } }); </script> <%- js('https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML') %><% } %> 发现第二步已经做好了,不用我们写,更新发布一下看效果。","link":"/2018/02/02/零基础学习GitHub桌面版-8配置你的Hexo/"},{"title":"零基础学习GitHub桌面版-9购买属于自己的域名并关联","text":"0 摘要因为Hexo个人博客是托管在github之上,每次访问都要使用githubname.github.io这么一个长串的域名来访问,会显得非常繁琐。这个时候我们可以购买一个域名,设置DNS跳转,以达到通过域名即可访问我们的个人博客。通过查阅文档发现,github pages是支持域名绑定的 1 购买域名国内国外有很多的域名供应商,选择一个好的机构购买域名,会为自己的站点配置节约很多时间,也不会因为域名的出错,导致影响百度对我们个人博客的收录。 近几年来,国内做的比较好的域名供应商有阿里的万网。我就是在阿里的万网购买的域名。通过查找,找到自己喜欢的域名,后来为了解决成本,我选了.top结尾的域名,一年只需要10块钱,很便宜,建议如果只是作为自己的博客使用建议不要购买.com的域名(主要还是穷啊T.T)。 注意:购买.top域名之后,大概6个小时之内就会生效,5之内必须对域名进行认证,超过5天没有认证域名将会被锁定。 2 域名解析 登录进入万网的域名控制台,点击”域名和网站”中的”云DNS” 点击对应域名的”解析” 点击添加解析,添加三个记录: 前两个的记录类型选A,A记录的记录值就是ip地址,github(官方文档)提供了两个IP地址,192.30.252.153和192.30.252.154,这两个IP地址为github的服务器地址,两个都要填上,解析记录设置两个@,线路就默认就行了。 CNAME记录值填你的github博客网址,解析记录设置两个www和。如我的是 xqtbox.github.io 3 在本地配置博客这些全部设置完成后,此时你并不能要申请的域名访问你的博客。 接着你需要做的是在hexo根目录的source文件夹里创建CNAME文件,不带任何后缀,里面添加你的域名信息,如:penglei.com。 实践证明如果此时你填写的是www.penglei.top那么以后你只能用www.penglei.top访问,而如果你填写的是penglei.top。那么用www.penglei.top和penglei.top访问都是可以的。重新清理hexo,并发布即可用新的域名访问。 12hexo cleanhexo g -d 4 搭建完成访问出现404 可能的原因是: 绑定了个人域名,但是域名解析错误。域名解析正确但你的域名是通过国内注册商注册的,你的域名因没有实名制而无法访问。 你认为配置没有问题,那么可能只是你的浏览器在捣鬼,可尝试清除浏览器缓存再访问或者换个浏览器访问。 也有可能是你的路由器缓存导致的错觉,所以也可以尝试换个局域网访问你的网站。 最有可能的原因是你下载的hexo有问题,导致所有的东西都上传到了github,而导致index页面在主域名的下一级目录。你可以尝试查看上传的内容,找到index页面,在域名后面添加下一级目录。若能访问index页面(此时样式可能是乱的),则证明是hexo安装有问题,笔者当时遇到的就是这个问题。可卸载重新安装。 注:1,2默认你的CNAME文件配置没有问题,如果没有绑定个人域名,则不需要CNAME文件。","link":"/2018/02/05/零基础学习GitHub桌面版-9购买属于自己的域名并关联/"}],"tags":[{"name":"问答系统","slug":"问答系统","link":"/tags/问答系统/"},{"name":"阅读理解","slug":"阅读理解","link":"/tags/阅读理解/"},{"name":"CNN","slug":"CNN","link":"/tags/CNN/"},{"name":"LSTM","slug":"LSTM","link":"/tags/LSTM/"},{"name":"Git","slug":"Git","link":"/tags/Git/"},{"name":"GitHub","slug":"GitHub","link":"/tags/GitHub/"},{"name":"报错","slug":"报错","link":"/tags/报错/"},{"name":"Linux","slug":"Linux","link":"/tags/Linux/"},{"name":"xshell","slug":"xshell","link":"/tags/xshell/"},{"name":"screen","slug":"screen","link":"/tags/screen/"},{"name":"session","slug":"session","link":"/tags/session/"},{"name":"知识图谱","slug":"知识图谱","link":"/tags/知识图谱/"},{"name":"深度学习","slug":"深度学习","link":"/tags/深度学习/"},{"name":"自然语言处理","slug":"自然语言处理","link":"/tags/自然语言处理/"},{"name":"旅行","slug":"旅行","link":"/tags/旅行/"},{"name":"Python","slug":"Python","link":"/tags/Python/"},{"name":"爬虫","slug":"爬虫","link":"/tags/爬虫/"},{"name":"scrapy","slug":"scrapy","link":"/tags/scrapy/"},{"name":"EndNote","slug":"EndNote","link":"/tags/EndNote/"},{"name":"Keras","slug":"Keras","link":"/tags/Keras/"},{"name":"eclipse","slug":"eclipse","link":"/tags/eclipse/"},{"name":"Anaconda","slug":"Anaconda","link":"/tags/Anaconda/"},{"name":"Pycharm","slug":"Pycharm","link":"/tags/Pycharm/"},{"name":"Java","slug":"Java","link":"/tags/Java/"},{"name":"面向对象","slug":"面向对象","link":"/tags/面向对象/"},{"name":"GBK","slug":"GBK","link":"/tags/GBK/"},{"name":"UTF-8","slug":"UTF-8","link":"/tags/UTF-8/"},{"name":"学习路线","slug":"学习路线","link":"/tags/学习路线/"},{"name":"RNN","slug":"RNN","link":"/tags/RNN/"},{"name":"NLP","slug":"NLP","link":"/tags/NLP/"},{"name":"Jena","slug":"Jena","link":"/tags/Jena/"},{"name":"Tensorflow","slug":"Tensorflow","link":"/tags/Tensorflow/"},{"name":"Tensorboard","slug":"Tensorboard","link":"/tags/Tensorboard/"},{"name":"myeclipse","slug":"myeclipse","link":"/tags/myeclipse/"},{"name":"USB","slug":"USB","link":"/tags/USB/"},{"name":"驱动程序","slug":"驱动程序","link":"/tags/驱动程序/"},{"name":"DriverSttudio3.2","slug":"DriverSttudio3-2","link":"/tags/DriverSttudio3-2/"},{"name":"ddk","slug":"ddk","link":"/tags/ddk/"},{"name":"Neo4j","slug":"Neo4j","link":"/tags/Neo4j/"},{"name":"机器学习","slug":"机器学习","link":"/tags/机器学习/"},{"name":"coursera","slug":"coursera","link":"/tags/coursera/"},{"name":"maven","slug":"maven","link":"/tags/maven/"},{"name":"Jieba","slug":"Jieba","link":"/tags/Jieba/"},{"name":"分词","slug":"分词","link":"/tags/分词/"},{"name":"jieba","slug":"jieba","link":"/tags/jieba/"},{"name":"编码","slug":"编码","link":"/tags/编码/"},{"name":"Editplus","slug":"Editplus","link":"/tags/Editplus/"},{"name":"Word2vec","slug":"Word2vec","link":"/tags/Word2vec/"},{"name":"Embedding","slug":"Embedding","link":"/tags/Embedding/"},{"name":"win7","slug":"win7","link":"/tags/win7/"},{"name":"Oracle","slug":"Oracle","link":"/tags/Oracle/"},{"name":"Protege","slug":"Protege","link":"/tags/Protege/"},{"name":"文件操作","slug":"文件操作","link":"/tags/文件操作/"},{"name":"汽车之家","slug":"汽车之家","link":"/tags/汽车之家/"},{"name":"word2vec","slug":"word2vec","link":"/tags/word2vec/"},{"name":"运维","slug":"运维","link":"/tags/运维/"},{"name":"DevOps","slug":"DevOps","link":"/tags/DevOps/"}],"categories":[{"name":"NLP","slug":"NLP","link":"/categories/NLP/"},{"name":"Git","slug":"Git","link":"/categories/Git/"},{"name":"Linux","slug":"Linux","link":"/categories/Linux/"},{"name":"自然语言处理","slug":"自然语言处理","link":"/categories/自然语言处理/"},{"name":"随笔","slug":"随笔","link":"/categories/随笔/"},{"name":"Python","slug":"Python","link":"/categories/Python/"},{"name":"爬虫","slug":"爬虫","link":"/categories/爬虫/"},{"name":"深度学习","slug":"深度学习","link":"/categories/深度学习/"},{"name":"Java","slug":"Java","link":"/categories/Java/"},{"name":"驱动开发","slug":"驱动开发","link":"/categories/驱动开发/"},{"name":"机器学习","slug":"机器学习","link":"/categories/机器学习/"},{"name":"数据库","slug":"数据库","link":"/categories/数据库/"},{"name":"运维","slug":"运维","link":"/categories/运维/"}]}