-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 240 KB
/
content.json
1
{"meta":{"title":"Cape of Good Hope","subtitle":"I miss you","description":"I'm not only Christmas,I'm also a captain.","author":"Christmas","url":"https://imbowei.com"},"pages":[{"title":"categories","date":"2016-09-05T15:41:55.000Z","updated":"2018-08-10T03:37:36.000Z","comments":false,"path":"categories/index.html","permalink":"https://imbowei.com/categories/index.html","excerpt":"","text":""},{"title":"","date":"2018-07-11T03:19:47.000Z","updated":"2019-07-19T13:55:12.364Z","comments":false,"path":"about/index.html","permalink":"https://imbowei.com/about/index.html","excerpt":"","text":"It was the best of times, it was the worst of times. About meI am now a Master student.My major research focuses on Machine Learning and Natural Language Processing.More specifically, I am now conducting research into semantic parsing and paraphrase. Contact me Blog: Imbowei.com Email: m_christmas@qq.com"},{"title":"tags","date":"2016-09-05T15:41:32.000Z","updated":"2018-08-10T03:37:36.000Z","comments":false,"path":"tags/index.html","permalink":"https://imbowei.com/tags/index.html","excerpt":"","text":""},{"title":"Top","date":"2018-07-16T07:55:01.000Z","updated":"2018-12-03T03:01:06.000Z","comments":false,"path":"top/index.html","permalink":"https://imbowei.com/top/index.html","excerpt":"","text":"AV.initialize(\"CYiT0KdkmU0LEo3kFuLb4TPP-gzGzoHsz\", \"6RIqigijTviGwWrSUQgaVMP7\"); var time=0 var title=\"\" var url=\"\" var query = new AV.Query('Counter'); query.notEqualTo('id',0); query.descending('time'); query.limit(1000); query.find().then(function (todo) { for (var i=0;i"}],"posts":[{"title":"【阅读笔记】项亮前辈的《推荐系统实战》","slug":"Recommended-system","date":"2019-05-11T02:15:41.000Z","updated":"2019-09-10T06:57:03.465Z","comments":true,"path":"2019/05/11/Recommended-system/","link":"","permalink":"https://imbowei.com/2019/05/11/Recommended-system/","excerpt":"推荐系统是个有意思的方向。项亮前辈的《推荐系统实战》来当作入门的第一本书还是很合适的,这段时间断断续续的抽空阅读了一遍。本书写的浅显易懂,很好的勾勒出了推荐引擎十年前的主流算法,以及工业推荐系统是如何打磨的。从这个角度讲,项亮前辈很好地完成了”让学生了解如何将自己了解的算法实现到一个工业系统中去“这一写作目标。 看书的过程中简单记录了一些内容,夹杂着自己突然产生的一些想法。用以过段时间后的来重新复习消化本书。","text":"推荐系统是个有意思的方向。项亮前辈的《推荐系统实战》来当作入门的第一本书还是很合适的,这段时间断断续续的抽空阅读了一遍。本书写的浅显易懂,很好的勾勒出了推荐引擎十年前的主流算法,以及工业推荐系统是如何打磨的。从这个角度讲,项亮前辈很好地完成了”让学生了解如何将自己了解的算法实现到一个工业系统中去“这一写作目标。 看书的过程中简单记录了一些内容,夹杂着自己突然产生的一些想法。用以过段时间后的来重新复习消化本书。 序&前言随着互联网信息技术的快速发展,我们逐渐从信息匮乏的时代进入了信息过载(information overload)的时代。在这种情况下,不论是对于想要快速找到目标信息的消费者,还是想要让自己的信息脱颖而出的生产者,都是严峻的考验。推荐系统正是在这种环境下有了生长的土壤,它一方面可以提高用户获取有效信息的能力,另一方面可以提升高质量信息的曝光度,实现双赢。但不可避免地,也会产生信息蚕房这样的桎梏。我们该何如构建一个高效的信息推荐系统呢?我们该入何如避免信息蚕房的桎梏呢? 在写一本书前,应该思考这样几个问题。其实不论做什么事情都是一样的道理。 为什么要写这本书? 写给谁看? 有几种角度去写这本书? 推荐系统的应用前景早在2010年的时候就已经被挖掘出来,并且开始被总结成书……虽然最早提出是在上世纪90年代。那么下一个重要领域是什么?强化学习吗? 评价推荐系统什么是推荐系统在互联网经济初兴之时,信息还没有那么的爆炸。一些公司可以人为地收集一些热门网站,对于信息分类组织,方便人们找到自己想要的信息。这个商机造就了第一代互联网巨头,美国有雅虎,中国有腾讯新浪搜狐网易四大门户。当技术发展,人们在明确知道自己的需求的时候,可以通过搜索功能寻找信息,这样的商机成就了Google、百度这样的第二代互联网巨头。而很多时候,人们并没有明确的需求,仅仅是想要从海量信息中找到一些自己感兴趣的信息来进行消遣。这个时候,能够通过历史数据准确捕捉用户兴趣的千人千面推荐系统就派上了用途,第三代巨头字节跳动崛起。 搜索系统什么时候比较有用呢?当信息过载,且用户有明确需求的的时候。但如果用户只是想消遣一下,并没有明确的需求该怎么办?你需要一个人或者一个工具来帮你对于过载的信息进行筛选,给出一些建议供你选择。然而人力总是昂贵且不是是实时可得的,这个时候个性化推荐系统就派上了用场。它就是一个能够自动联系物品和用户的工具。 推荐系统的应用推荐系统严重依赖于用户的历史行为数据,因此并不能向搜索引擎那样独立存在,往往内嵌于各个领域之中,成为一个提高网站/APP用户存留,活跃度的利器。 推荐系统的应用包括不限于 电子商务商品推荐(例如淘宝有好货) 基于购物记录的推荐;基于好友信息的推荐;当前购买物品的相关推荐(打包销售策略) 视频 / 电影推荐 基于以往看过 / 喜欢的电影记录进行推荐 音乐推荐 标注歌曲计算歌曲之间的相似度推给用户;根据用户行为计算歌曲相似度的推荐 社交网络好友推荐 利用社交网络推荐物品;根据社交关系给用户推荐好友;信息流会话的排序推荐 个性化阅读推荐 手动关注特定人 / 领域的推荐(Google reader); 基于文章特征的推荐(Zite / 头条);基于协同过滤的推荐 LBS 基于位置的服务(各种网上预订服务) 个性化邮件 根据用户的使用历史,对每天处理的大量邮件进行整理分类推荐 个性化广告推荐系统————计算广告学(互联网公司命根子) 广告推荐系统是帮助广告找到对它感兴趣的用户,而普通的推荐是帮助用户找到感兴趣的信息,这是它们之间的根本差别。 搜索广告:根据用户的搜索历史,判断用户的搜索目的,投放相关目的的广告。 上下文广告:根据用户当前浏览的网页内容推荐相关内容的广告。 尽管推荐系统用于不同的领域,但是他们的内在构造逻辑却基本一致。都是由前台的展示页面(要设计用户的反馈机制,以不断迭代调整后台的算法),后台算法,以及日志系统这三部分组成。 为什么淘宝不建造会员之间添加好友的功能,这样小白用户就可以跟着购物达人去消费。可能是考虑隐私问题?因为淘宝的评论也都是默认匿名。 为什么音乐电台的个性化推荐这个商机早就存在,网易云音乐(2013)能用推荐系统将它做火?我觉得是因为它构造了一个音乐社区,让大家抒发出获得新奇的音乐推荐的感受,引起用户之间的共鸣,增强产品的使用粘性(听歌之前先看评论已经变成了病……)。推荐引擎也可以通过用户的这些评论反馈用NLU技术作为提取强特征去优化推荐算法,不知道猪场有没有做……应该做了吧…… 未来社交网络的广告的发展空间大概率会超过搜索广告,微信QQ他们沉淀了太多有用的用户数据了!鹅厂的部门墙导致数据的利用率太低了!不知道架构调整之后有没有点起色……微信朋友圈现在全面开放第三条广告商业化不知道是不是为时已晚?现在用户的朋友圈使用时间是不是都快被抖音快手吸干了…… 据说淘宝系现在的推荐、搜索流量比是六比四? 推荐系统评测推荐系统本质上是想要消除搜素引擎带来的信息马太效应。但其实基于协同过滤算法的也会在一定程度上造成马太效应。 评测方法一个完整的推荐系统有三个参与方:用户,信息生产者,推荐平台。 推荐系统是帮助用户挖掘那些他们可能感兴趣却又不那么容易发现的内容(那些埋没在长尾中的信息内容),而不是去一昧的追求高的预测准确率,去预测很多没有新意的东西。(比如:明天太阳一定从东方升起)因为高预测准确率并不等于高的用户满意度。 通常来说,一个新的推荐系统上线需要走过以下的三个流程: 离线测试,通过日志系统存留的用户数据对新模型进行离线指标的评测,与现有算法的离线指标比较。 用户调查,选取一部分用户(注意要与真实用户的分布一致)进行双盲测评(实验人员和用户都不知道测试目标),尽量保证用户和实验人员在评测中不参杂主观性。 在线AB test,用控制变量的方法,将新系统和原有系统分别给用户成分相似的两个用户组使用,观察两个用户组不同的表现情况,需要长时间的实验才能得到关于新旧系统对比的可靠实验结果。 评测指标用户满意度这是推荐系统最重要的指标。但是这个指标只能在用户调查和在线实验中获得。最常用的离线实验中无法使用。 预测准确度推荐系统离线测评中最重要的指标。 评分预测作为一个回归问题,常用以下两种评测指标,均方根误差 $RMSE = \\sqrt{ \\sum{(r_i - \\hat{r} )^2}/|T|} $,以及平均绝对值误差 $MAE= \\sum{| r_i - \\hat{r}|}/|T|$。相比较之下,RMSE对于预测不准确的评分惩罚更大,是一个更加苛刻的评测指标。 Top N推荐推荐的真实应用场景是给用户一个推荐列表,我们对这个列表中的结果进行准确率和召回率的计算。有些时候会选取不同的推荐列表长度N,计算一组评测结果,画出准确率 / 召回率曲线。因为我们更加关心的是用户会不会选取我们推荐列表中的内容,而没有那么关心用户对于选取内容的评价。因此TopN推荐是我们更加关注的一个指标。 覆盖率描述推荐系统对于物品长尾的挖掘能力,这是一个内容生产者极为关心的目标。简单的想,每个内容至少被推荐给用户一下,证明了推荐系统挖掘长尾的能力。但实际情况下,不同物品的流行度极为不同,因为通过研究所有物品的流行度分布可以证明推荐系统长尾信息挖掘能力的差异。物品流行度分布越是平整,这种能力越强,覆盖率也就越高。 信息论中的信息熵的概念可以评价覆盖率,$H = - \\sum p(i)logp(i)$,分布越均匀的时候,信息熵越大,覆盖率越大。 经济学中的基尼系数也可以评价覆盖率,$i_j$ 是按照物品流行度从小到大排列。 $ G = 1/(n-1) \\sum_{j = 1}^{n} (2j - n -1) P(i_j)$, 分布越平均,基尼系数越小(趋近于零),覆盖率越大。 多样性用户的兴趣不是单一的,而是多样的。尽管用户的兴趣在较长的跨度中是不一样的,但是具体到用户访问系统的某一个时刻,这个时刻的兴趣点是确定的。理想化的推荐列表中的内容应该是和用户的兴趣同分布的。 相似性和多样性是一个相对应的概念。假设$s(i , j)$定义了物品i,j之间的相似性,那么 用户u 的推荐列表R(u)的多样性定义如下: $Diversity(R(u)) = 1 - 2*\\sum s(i,j) / |R(u)|(|R(u) - 1|)$ 新颖性推荐系统提高推荐内容新颖性方法很简单,直接过滤掉用户已经关注过的内容就好。但是这种方法不能排除掉用户通过其他途径获得过的信息。另一个想法是,如果推荐物品中的平均流行度更低,那么其对于用户的新颖性是更大的。这很容易做到,其难点在于如何在不牺牲推荐精度的情况下提升推荐内容的多样性和新颖度。 惊喜度惊喜度这个指标乍一看和新颖性关联性很强。但这只是英文翻译成中文后词语之间的相似性对于我们带来的困扰。 当推荐的一个内容与用户以往的使用记录相关性很低,却又使用户很满意的时候,用户是惊喜的。这就是惊喜度的定性定义。换个角度思考,为了提高用户的惊喜度,需要首先降低推荐内容与用户以往使用记录的相关性,另一方面需要提升用户的满意度。由于第一方面因素的限制,是的惊喜度成为了一个推荐系统比较难以提高的指标。并且,提高这个指标还会冒着相对较大的风险,因为一个与用户以往使用记录不类似的内容不可控因素也会更大。但是这个点倒是可以和强化学习的“探索”结合起来,进一步优化系统。 信任度在电商的推荐场景下,这是一个很重要的指标。当用户信任推荐系统的推荐和不信任时做出的选择是完全不同的。一般来说有以下两种方式: 提供推荐内容的解释信息; 根据用户的好友信息进行推荐,博得用户的信任感。 实时性在某些场景下,信息的时效性是非常重要的。比如:新闻的推荐。推荐系统的实效性一般来说分为两个方面。 实时的更新推荐列表需用户有新的变化行为。这可以通过推荐列表的变化速率来进行测评。如果推荐列表在用户有行为后变化不大或者没有变化,说明其实时性不够高。 实时的将新加入系统的内容推荐给感兴趣的用户,这主要考验了系统的冷启动能力。可以通过记录用户的推荐列表中有多大比例的物品是当天新加入的来判断这个方面的实时性。 健壮性任何一个能带来利益的算法都会被人攻击,反作弊能力这个时候就至关重要了,也就是系统的鲁棒性。算法健壮性的检测主要依靠模拟攻击。用常用的攻击方法是向推荐系统中注入噪声,比较攻击前后两次系统生成的推荐列表的内容差异,如果没有太大变化,证明系统比较鲁棒。 另外,在算法设计的时候,尽量主要考虑使用代价比较高的用户行为特征。这样的数据由于攻击代价较高,因此更不容易受到攻击;另一方面,由于攻击代价较高,这样的数据中本身的混有的噪声也更少。 商业目标对于公司而言,推荐系统是为了提高公司的营收额,本质上是想要提高每个用户为公司带来的营收额。而这种计算指标计算一次的代价过于高昂,不同的公司根据其具体情况设计了不同的商业目标。有的是商品消费额,有的是广告点击总数,有的是广告展示总数等等。 评测维度推荐系统不存在银弹,我们需要根据我们的数据状况,以及实际的应用背景选择合适的推荐系统。这就需要我们从多个维度全面的考虑算法的优劣。一般来说,分为如下三个方面: 用户维度:新旧用户,活跃度,用户的人口统计学信息。 物品维度:物品属性、流行度、新旧程度 时间维度:季节,白天 / 晚上,工作日 / 周末 利用用户行为数据用户的行为数据分为两大类,一类是通过设计的用户反馈模块返回的显性反馈,通常这类数据数量较小,产生代价更高,对于用户画像的描述贡献更大;另一类是用户在网站上的一般性操作(例如浏览)返回的隐性反馈。这类数据并不会十分明确地表达出用户的喜好,但数据量比较大,对于推荐系统的构造也起到了不可忽视的作用。 隐形数据中的大量噪音如何消除?(例如用户被虚假标题诱导的错误点击,或者交互不合理导致的错误点击) 基于邻域的算法基于用户的协同过滤算法基于邻域的用户协同过滤算法是最古老的推荐算法之一。这个算法有两个关键任务。 如何找到与目标用户兴趣相似的用户集合? 两个用户有过正反馈的物品集合越大说明两个用户的相似性越大,但很明显,所有物品在这个方法下的权重不应该是相同的,需要对热门的物品的权重进行一个惩罚。 何如找到这个集合中用户喜欢的,且目标用户没有听说过的物品推荐给用户(新奇)。 是否推荐一个物品有两方面因素决定,一方面这个集合中的用户有多少个对这个物品有过正反馈操作?另一方面,这些有正反馈操作的用户与目标用户的兴趣相似度有多大? 基于物品的协同过滤算法这是2010年左右业界最常用的算法。用以解决基于用户的协同过滤算法的两个弊端。第一,基于用户的协同过滤算法要探究所有用用户之间的相似性,那么随着用户的增加,用户相似度矩阵将越来越大。时间复杂度和空间复杂度也以平方的级别增加,矩阵难以维护。其次,基于用户的协同过滤算法做出推荐的时候没有办法做出推荐解释,用户的信任度比较低。 基于物品的协同过滤算法有两个关键任务。 何如获取物品之间的相似度? 物品的相似性用后验概率来表示,喜欢物品A的用户中有多少人同时喜欢B,人数越多,说明两个物品的相似度越高。(这里需要对特别活跃的用户降权重) 何如根据物品相似度和用户的历史行为给用户生成推荐列表。 某物品与目标用户历史上正反馈的的物品的相似度越高越容易被推荐。相似度归一化可以提高性能。 UserCF 与 ItemCF之间的比较UserCF的推荐结果更加着重于反应和用户兴趣相似的小群体的热点,也就是说大家都关心的东西就推荐给新用户,新用户也大概率会关心;ItemCF 的推荐结果更着重于维系用户的历史兴趣,不同用户也有自己所关心的领域。 UserCF ItemCF 性能 适用于用户较少的场合,如果用户很多,计算用户相似度矩阵代价很大 适用于物品数明显小于用户数的场合,如果物品很多(网页),计算物品相似度矩阵代价很大 领域 时效性较强,用户个性化兴趣不太明显的领域 长尾物品丰富,用户个性化需求强烈的领域 实时性 用户有新行为,不一定造成推荐结果的立即变化 用户有新行为,一定会导致推荐结果的实时变化 冷启动 在新用户对很少的物品产生行为后,不能立即对他进行个性化推荐,因为用户相似度表是每隔一段时间离线计算的 新用户只要对一个物品产生行为,就可以给他推荐和该物品相关的其他物品 新物品上线后一段时间,一旦有用户对物品产生为,就可以将新物品推荐给和对它产生行为的用 但没有办法在不离线更新物品相似度表的情况下将新物品推荐给用户 推荐理由 很难提供令用户信服的推荐解释 利用用户的历史行为给用户做推荐解释,可以令用户比较信服 没有“银弹”,在不同的业务场景下,在不同的数据背景下。算法的表现不尽相同,真实的推荐结果往往是扬长避短,多种推荐算法的集成。 一个推荐系统可不可以用户连续的使用时长为标准切换不同的算法。例如抖音,用户刚登陆可以用UserCF推荐一波热点视频,随着用户连续使用的时常增加,可以逐步平滑的切换到ItemCF实时变化,推荐更多兴趣化的内容。 隐语义算法就是文本挖掘领域中的主题模型(LSI、pLSA、LDA等)。一方面提取待推荐物品的主题向量,另一方面提取目标用户的兴趣主题向量。当两个向量相似度越高说明越合适被推荐。 这里有个构造负样本的点需要注意。应该选取那些比较热门但是用户却没有行为的样本作为负样本。 这类方法有个弊端就是很难做到较高的实时性。因为计算用户隐向量的时候需要扫描用户之前的所有的操作记录,很耗时。在实时性要求比较高的新闻推荐领域不适合使用这种方法。 基于图的模型基于图的推荐算法算法是构造基于用户和物品的二分图,用基于大数据量统计的随机游走算法(PersonalRank)来衡量顶点之间的相似性,进而选择推荐的物品。顶点之间的相似性需要从以下三个方面衡量 两个顶点之间的路径数(相关性高的两个节点之间的路径数多) 两个顶点之间的路径长度(相关性高的两个节点之间的路径长度短) 两个顶点之间的路径经过的顶点(相关性高的两个节点之间的路径不会经过出度比较大的节点) 随机游走算法就是每次从目标点出发,按照特定的概率$ \\alpha $决定是继续走下去还是返回起始点。如果继续走下去,就按照均匀分布的方式随机选择下一个节点作为下次需要经过的结点。循环往复这个过程。但是随机游走算法需要多次迭代才能收敛,只能用早停或者构造转移概率矩阵的方式求解。 推荐系统冷启动推荐系统冷启动就是如何淘来第一桶金的问题。根据对象的不同分为三个方面。 用户的冷启动 物品的冷启动 系统的冷启动 用户的冷启动用户的冷启动指的是一个新用户刚加入网站后没有对应的历史行为数据,如何为他推荐物品。 首先可以考虑从用户的注册信息破局。其实从引入额外信息的角度考虑,用户的冷启动越来越是个伪问题。随着每个用户再互联网上留下的蛛丝马迹越来越多,冷启动问题也就越来越不是个问题了。 用户的注册信息分为以下三种: 人口统计学特征:年龄,性别、职业、民族、学历、居住地等等一系列。 用户兴趣描述:新用户注册界面可以给之以少许的标签(或者典型物品)选择来让用户表述自己的兴趣。 建立账号体系:从其它网站导流(社交网站为最佳,可以借助社交推荐的力量)。 可以根据已有的信息,选择用树状结构对用户进行分组,对新用户进行粗粒度的个性化推荐。或者辅以最热门物品的加权推荐。 物品冷启动UserCF算法对于物品的冷启动是不敏感的。要知道,目标用户获取新推荐物品的方式是根据相似人群喜欢的物品,知道将新物品加入到系统中,只要被一个用户有正反馈就必然会逐步扩散开来。 对于ItemCF算法来说,新物品的冷启动显然更加的困难。我们想要将一个物品推荐给用户需要先找到与其相似的物品,但是在没有物品使用记录的时候就无法更新物品的相关性表。这时候可以根据物品不同类型的特征构造特征向量,运用向量的相似性度量方法去寻找相似物品(内容过滤算法)。但是这样的方法却没有考虑到用户行为,也忽略了物品流行度,精确性就相对差一些。 系统冷启动在一个新系统一穷二白的时候可以先用热门排行榜(这也是一种推荐方法)的方式积累原始数据。或者用大的代价请专家迅速建立起现有物品的相关性表,就可以初始时候就采用ItemCF的推荐方式。 利用用户标签数据推荐系统中的用户标签数据是重要的用户反馈。相比于用户的行为数据,这样的显性反馈对于捕捉用户的兴趣准确性会更高。但是再或者标签数据的时候,也要关注如何获得更高质量的数据,显然给用户推荐他可能选择的标签可以显著降低用户反馈的成本,同时也能提高反馈标签的质量(用户自己写新标签可能写错,或者新构造出了与现有某标签的同义标签)。因此,关于这个点主要有以下两个问题需要解决。 如何利用标签数据为用户更好的推荐物品? 如何为用户推荐标签,以提高标签数据的质量? 以用户反馈标签构造推荐算法,最简单的想法。首先可以找到用户最喜欢用的若干标签,然后找到拥有这些标签最多的对应物品,将这些物品推荐给用户。这个算法会非常倾向于热门标签对应的热门物品,为了提高推荐系统的新颖性,可以通过TF-IDF的方法去降低热门标签的权重,甚至同时惩罚热门物品。 复杂一点的算法,可以将用户,标签,物品三部分分别分开,构造成图结构的三部分顶点,然后同样用随机游走算法去推荐物品。基于标签的系统还有一个优点就是可以很好的根据标签生成推荐理由,增加用户的信任度,从而提高点击通过率。 为用户推荐标签的算法可以简单到只有一行代码,因为仅是一个排序算法。第一种,可以推荐系统中最常出现的标签;第二种方法,可以推荐给用户其本身最喜欢用的标签;第三种,推荐给用户的标签是待打标签物品最经常被打的标签。然后,还可以进一步地将它们线性加权起来使用。当然还可以用图结构下的随机游走算法确定所推荐的标签。 利用上下文信息一个好的推荐系统往往要考虑多方面的信息。前面所述的所有推荐算法都可以增加关于用户时间信息,地理信息,用户心情信息等等上下文信息来辅助进行推荐。 以时间效应为例,我们在周中搜索的内容往往是工作相关的内容,周末搜索的往往是个人兴趣,呈现出强周期性;我们在冬天想要买的鞋子显然和夏天想要买的鞋子不是一样的种类;一个体育新闻只有刚发生时才是用户想要的,时间越久用户对于他的兴趣是越低的。如果能够基于此能够特定调整推荐系统的推荐内容,相信会提高用户的满意度。加上时间信息之后,推荐系统就相当于多了一个时间的维度,成为一个时变系统。 推荐系统的时效性分为近期和远期两种。这需要算法平衡用户近期行为和远期行为。既要让推荐列表反映出用户近期行为所体现出的兴趣变化,又不能让推荐列表完全受用户近期行为的影响,保证推荐列表对用户兴趣的预测延续性。 另一方面,推荐系统应该在时间维度上体现出多样性这一特点。这要求加入用户有一段时间没有操作,推荐列表也能表现出一些变化。要做到这一点比较容易,大体有以下三种方法: 推荐算法生成的时候本身就加入一些随机性。比如最后展示的是个结果是从排名前二十的结果中随机采样获取的。 对之前看到过的内容进行降权。减小再次生成的概率。 推荐系统集成若干种算法,可以根据时间信息,采取不同的算法推荐。 如果从地理信息的位置信息考虑个性化推荐系统,有一种金字塔模型的集成算法思路。根据用户的地理位置信息进行树结构的划分,可以划分若干层。基于每一层的位置信息进行推荐内容的生成,最后展示的推荐信息是每一层信息的加权结合。心情信息也可以参照此思路采取类似的算法。 利用社交网络信息根据社交网络的推荐给推荐系统带来最大的好处就是可以增加用户的信任度,其实是可以辅助解决新用户的冷启动问题。推荐系统的根本目的是提高用户点击率(满意度),而提升推荐物品的被信任程度和提升被推荐物品的准确度(惊喜度)是同时存在的两种实现方式。这种社会化推荐对于提升用户的广告接受度有着非常强烈的作用。 基于社交网络的推荐最主要的社交网络信息从用户的注册邮件 / 手机通信录来获得,当然了,如果用户愿意绑定 自己的社交帐号到新网站。新网站有可能会获取用户的在社交网络中的关系以及兴趣点,以实现根据社交网络关系的推荐。 社交网络的数据一般分为三种,基于社区(小组)的弱关联社交关系;基于单向关注的社交关系(例如微博);基于双向确认的强社交关系(例如微信)。 社交推荐同样可以采用基于邻域的推荐方法,以及基于图的推荐方法。值得注意的是,同热门物品权重过大的问题一样。社交网络关系中也存在”大V“这样的热门人物,需要有特殊的权重处理。另外,在实际应用中,UserCF的实用价值不高,因为在给一个用户作推荐的时候,需要他所有好友的历史行为数据,计算起来会比较缓慢。现有的社交网络推荐主要以信息流的方式存在,当某用户产生一条内容后,这条内容会出现在所有关注他的人的消息队列当中。如果这个消息是一条广告推荐,非常有利于提升其他用户对于广告品牌的好感以及对广告内容的接受程度。 给用户推荐好友好友推荐系统的目的是根据用户的现有好友、以及用户的行为记录,给用户推荐信的朋友,从而提升整个社区的社交网络稠密性,提升用户粘性以及活跃度。 具体的推荐思路有以下几种。 基于用户基本信息:例如用户的地点,年龄,性别,学校,职业等等信息推荐潜在的好友。 基于共同兴趣:UGC社区中一定会设计若干机制让用户对内容反馈。可以利用这些反馈数据构造用户的兴趣向量,通过计算向量相似度的方式找到潜在的好友。 基于社交网络图:根据用户的社交关系链进行推荐,就是著名的六度人脉网络理论。 推荐系统的架构推荐系统一般有UI设计,日志系统,后台存储系统,推荐算法等几个部分。 推荐系统往往有多个推荐引擎组成,每个推荐引擎负责一类特征和一种任务,而推荐系统的任务只是将推荐引擎的结果按照一定权重或者优先级合并、排序然后返回。所以Ranking组是一个比较核心的组? 这样组合一方面方便增加或者删除不同推荐引擎;另一方面在使用不同的推荐引擎的时候,可以获得到推荐引擎级别的用户反馈。 A模块:负责从用户的基本统计信息,或者隐性、显性的用户行为数据中提取特征向量。 B模块:维护着若干项物品相关性表(从不同的角度分析)。 过滤功能:去掉用户已经见过的物品;去掉质量很差的物品;去掉不符合推荐候选(商业因素)的物品 排名模块:将推荐引擎得到的结果进一步排序(内容展现顺序很影响用户点击率),以期提高用户的满意度。 新颖性:将匹配度较高,且流行度较低的长尾物品推荐给过滤模块。 多样性:精心选择内容属性(影响很大),尽量防止同一个推荐原因出现多次。已经被用过的推荐理由下次采样得到的权重减半就是一个常见的处理方式。 时间多样性:也就是所谓的实时性。可以记录用户上次的推荐内容,即使上次用户没有操作,用户下次登陆也不会再次推荐重复的内容(对已经看过的内容进行降权)。 用户反馈:排名模块最重要的部分就是用户反馈模块。用户反馈模块主要通过分析用户之前和推荐结果的交互日志,预测用户会对什么样的推荐结果比较感兴趣。如果推荐系统的目标是提高用户对推荐结果的点击率,那么可以利用点击模型(click model)预测用户是否会点击推荐结果。点击模型需要离线计算好,在线将模型加载到内存中。 设计推荐系统的十个建议 确定你真的需要推荐系统:只有信息过载时候才需要,不要为了推荐而推荐。无论算法是否复杂,能过达到目的的系统就是好的系统。 确定商业目标和用户满意度之间的关系:用户满意度和商业目标并不一定是完全吻合的。商业目标更多关注短期,用户满意度则是长期收益。 选择合适的开发人员。 忘记冷启动:互联网大潮席卷每一个人,每个用户都不断的在互联网都吓自己的蛛丝马迹。我们有越来越多的初始数据来了解一个人,冷启动问题将慢慢消逝。 数据与算法:深刻理解数据是设计一个好的算法的必要前提。数据分析决定了如何设计模型,算法只是去优化这个模型。 呈现方式:找到相关值得推荐的物品不难,难的是以何种方式展现给用户,以提高用户的点击率。 社交网络的力量:社交推荐势必会慢慢替代陈旧的基于邻域的协同过滤算法,这是推荐系统的高地。 不断提高系统的、模型的可拓展性。 选择恰当的用户反馈方式。 设计合理的测评系统,关注推荐系统各个方面的性能。 十年Recsys 总结 2018 推荐系统总结","categories":[{"name":"Recommend-system","slug":"Recommend-system","permalink":"https://imbowei.com/categories/Recommend-system/"}],"tags":[{"name":"UserCF","slug":"UserCF","permalink":"https://imbowei.com/tags/UserCF/"},{"name":"ItemCF","slug":"ItemCF","permalink":"https://imbowei.com/tags/ItemCF/"},{"name":"Collaborative-filtering","slug":"Collaborative-filtering","permalink":"https://imbowei.com/tags/Collaborative-filtering/"},{"name":"Social-recommendation","slug":"Social-recommendation","permalink":"https://imbowei.com/tags/Social-recommendation/"}]},{"title":"Python3复习总结","slug":"python3-tips","date":"2019-01-19T11:59:45.000Z","updated":"2019-09-02T14:55:41.587Z","comments":true,"path":"2019/01/19/python3-tips/","link":"","permalink":"https://imbowei.com/2019/01/19/python3-tips/","excerpt":"抽空复习了一下python的语言特性,其中容易忘记、混淆的点特地记录如下。","text":"抽空复习了一下python的语言特性,其中容易忘记、混淆的点特地记录如下。 python 特性 运行速度 python > java > c c 适合充分发挥硬件性能的任务,贴近硬件的任务 python 优点 完善的基础代码库,高级语言,易理解,代码短而优雅 有良好的平台兼容性,在任何环境中都可以运行,前提是安装了解释器(虚拟机)。灵活,修改代码的时候直接修改就可以,可以快速部署,不用停机维护。 python 缺点 因为不能编译后,发布编译后的机器语言文件。因此代码不能加密,如果发布python程序必须发布源代码 作为解释型语言,需要相应语言的解释器,“翻译”成目标代码后执行,不可脱离解释器运行。所以效率低……(不过这不是事儿,部署线上应用时网络更慢……) cpython 是使用最广的 python 解释器 python 基础 输入输出 a = input(‘写输入提示’) 输入数据的默认类型是字符串 print() 基本数据类型 因为是动态语言,不必事先设定好变量类型 ==地板除 // 相当于取除法结果的整数部分==,常搭配取余运算。 编码问题 为了能统一表示各种语言,内存中用的是unicode编码,但是为了提升网络传输效率,我们保存的磁盘文件往往应该写成utf-8编码 格式化输出 可以用占位符(%s) %d %f %s %x .format() 函数 list 和 tuple 能用tuple 就多用,它一经建立就不可进行添加、删除等操作,相当于一个只读的list。这样代码更安全,鲁棒; 它们内部都可以放多种类型的数据; 尽量避免过多地使用 continue 和 break 提前结束循环,因为这样会造成逻辑混乱。 dic & list 随着数据量的变大,dic 的查询性能优势就会越好的体现出来 但是会比较占用内存 dic 是一种用空间换时间的方法,查询靠hash表完成 set 相当于dic 的 key ,同样不可放入重复的元素。这里的集合不可改变针对的是不可变元素,如果集合内有可变元素列表是可以改变的。 1234t1=(1,2,3,[1,2,3])t1[-1][-1]=4t1>>> (1, 2, 3, [1, 2, 4]) 不可变元素 str、int 、float 、tuple 是不可变元素,对于改变它的操作,本质上是生成了一个新的字符串,应该定义一个新的变量指向这个新的字符串 函数 占位符 pass没有实际意义,用于没想好怎么写的函数体。先把程序框架搭起来 返回值 函数可以返回多个值。但其实相当于返回一个tuple组,多个变量接受对应位置的返回值。 默认的自动返回值是None 检查参数 在函数体内部首先检查参数的类型是否输入正确是一个好的习惯 函数参数类型 默认参数放在必选参数后面,默认参数一般是变化小的数。 使用默认参数可以有效降低调用函数的难度。 ==默认参数一定要是不可变对象==,否则每次调用默认参数其实都会改变默认参数的值,程序可能会出错 程序设计能设计成不变对象(例如:str,None等扽那个)是最好的。因为不易导致修改数据带来的错误。而且在多任务的环境下不用加锁,因为数据是不会改变的。 当参数数量不确定的时候用可变参数,普通参数nums可以变成可变参数nums。想将一个列表中数据都传入的时候也可以用 list , 可变参数传入函数后一一个元组的形式存在。 关键字参数**other 可以接受一个dic,即任意个数的带名字的参数。调用的时候和可变参数一样,可以直接传入一个dic 命名关键字参数。放在函数参数的最后,用一个 将他们与前面的位置参数分隔开。如果有可变参数将命名关键字参数与位置参数分隔开了,就不必再单独用一个 隔开他们 函数参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数 但是最好不要同时使用多种参数类型,导致程序可解释性太差 递归函数 理论上,所有的递归函数都可以写成循环的形式。但是写成循环逻辑不清晰 递归函数要小心过深的调用会导致堆栈溢出(缺点) 采取尾递归的方式,递归函数值只会占用一个栈帧,就不会堆栈溢出了。即,return 的就是递归函数本身,而不是包含递归函数的一个表达式 可惜的是,与大多数编程语言一样,python 并没有实现尾递归的优化。任何递归函数都存在栈溢出的风险。 一个递归函数例子:汉诺塔! 对字符串进行递归删除的时候小心索引错误。 高级特性 切片 切片操作为什么在对于空字符串只能用S[0:1]不报错,而用s[0]就会报错? ==切片操作允许超出索引,或者部分缺失;但是对于数组取值是不可以的!== 切片操作能有效代替循环,简化程序 迭代 判断某变量是否可以迭代 isinstance(s, Iterable) 想获得迭代对象的角标可以用 enumerate()函数 列表生成式 把代码写在一行非常的简洁 12>>> [x * x for x in range(1, 11) if x % 2 == 0][4, 16, 36, 64, 100] 12>>> [m + n for m in 'ABC' for n in 'XYZ']['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] 123>>> import os # 导入os模块,模块的概念后面讲到>>> [d for d in os.listdir('.')] # os.listdir可以列出文件和目录['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode'] 生成器 可以有效节省程序的内存,一个大的列表,其中的元素随着程序的运行而一个一个的生成。 直接将列表生成式的[] 改成()就可以得到一个生成器 generator 保存的是生成数据的算法,可以通过for循环或者next()函数不断的迭代新生成的数据。 可以把生成器做成一个函数的形式调用,他和一般的函数执行顺序不一样。执行一小段,然后返回 yield,下次调用的时候接着上次执行的地方继续往下执行。 注意为生成器设置一个程序停止条件。 123456>>> L = [x * x for x in range(10)]>>> L[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]>>> g = (x * x for x in range(10))>>> g<generator object <genexpr> at 0x1022ef630> 12345678# 杨辉三角的迭代生成# 停止条件和输出格式在调用的时候定义,最大限度地提高函数的重用率# 列表元素还可以直接加?def triangles(): l = [1] while 1: yield l l = [1] + [l[n] + l[n + 1] for n in range(len(l) - 1)] + [1] 123456789# 斐波那契数列的迭代生成# 不需要中间变量的变量赋值方法,节省一点内存def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return 'done' 迭代器 可迭代对象list、tuple、dict、set、str、generator,带有yield 的generator function 判断是否可迭代 isinstance({}, Iterable) True 相比于可迭代对象list ,迭代器iter([])的好处就是可以放入一个任意大的迭代对象,不会占用大量内存。 模块 作用域 类似_xxx和xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,abc等。一般的变量就是公开的 对于那些不需要外部引用的函数,都可以定义成_private()的private形式,代码更规范 system sys.argv 可以存储命令行调用函数的所有变量(至少会有一个,就是.py的文件名本身) 内置函数属性操作 Func 语法 作用 retype hasattr hasattr(object, name) 判断 对象中是否含有 该属性。 True / False setattr setattr(object, name, values) 给对象的属性 赋值,若属性不存在,先创建再赋值。 None getattr getattr(object, name[,default]) 获取 属性数值。 属性存在时,返回 属性数值;否则根据 默认输出值 返回 或 报 AttributeError。 delattr delattr(object, name) 删除属性。 属性存在则无返回,否则报 AttributeError。 函数式编程 map & reduce map(f(),iterable) 相当于把函数f作用在一个可迭代对象中的每一个元素,返回指是对应的处理后的 iterable 。 再看reduce的用法。reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是: 1reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) 有用的 nonlocal 声明 用于函数套嵌的内部函数。如果内部函数的变量与外部函数的变量重名,相当于在内部函数新建了一个同名变量,内部函数并不能访问修改外部函数的变量。 但是只要在内部函数声明 nonlocal ‘变量名’ 就可以让内部函数对外部变量进行==赋值==操作。 字典不需要nonlocal 声明就可以在内部函数改变外部字典。 可以起到像静态变量的作用,‘只初始化一次,然后不断改变它 ’ filter 过滤函数 与map()函数的用法一致,都是输入量两个参数,第一个是一个函数,第二个是iterable 所需要的返回是True or False 返回的是一个iter(惰性计算) ,所以需要套一个list 才能继续工作 字符串倒序技巧 str(s)[::-1] sorted 排序高阶函数 可以接受三个参数(‘排序对象’,key = ‘函数’,reverse = True) 12>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)['Zoo', 'Credit', 'bob', 'about'] 返回函数 当某些功能不必立即执行的时候,定义一个内部函数,返回该内部函数。 同样的语句调用两次,返回的两个函数也不会是一样的,他们的运行结果也相互独立 相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。++编写起来都是坑++ ==返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。== lambda 函数 冒号前面是函数参数,后面是函数体,运算结果就是函数返回值 匿名函数也是一个函数对象,也可以将其复制给一个变量,然后再通过变量调用它 12>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))[1, 4, 9, 16, 25, 36, 49, 64, 81] decorator 装饰器高级函数 输入一个函数,返回一个函数。在代码运行的期间动态的为一些函数增加功能 def wrapper(args, *kw) 这样的函数能接受任意参数形式的函数作为参数,用在装饰器内部,接收旧函数,返回新函数是最好的选择。 一个普通的不需要参数的装饰器都要decorator 双层嵌套,而需要的参数的decorator 需要三层嵌套。 decorator 会使func.name发生变化,导致某些调用出错。可以在wrapper前面加上@functools.wraps(func)默认的装饰器。起到保持原函数名不变的功能。 partail 偏函数 为了简化我们对于常用函数的调用,可以用fu’nctools.partail() 固定函数的常用参数,返回一个新的函数,调用更方便 123456>>> import functools>>> int2 = functools.partial(int, base=2)>>> int2('1000000')64>>> int2('1010101')85 防坑指南可变对象与不可变对象 不可变对象: int 、string 、float 、tuple 可变对象: list 、dict、set 12345678910# 例子一>>> a=b=['hello','world'];a.append('hello')>>> print(b)['hello','world','hello']# 例子二>>> a=b='hello';a='world'>>> print(b) hello 对于可变类型来说,两个变量名指向相同的内存地址的时候相当于给同一个内存地址起了两个名字。如果改变一个变量名的内容,并不会开辟新的内存,而是直接改变原来内存地址中的内容。也就是说对于不可变类型,不同的变量名指向的内存地址永远是相同的。 对于不可变类型来说,两个变量指向相同的内容时拥有共同的内存地址(id(arg) 命令可以查看),但是改变一个变量之后相当于另外开辟一块新内存,其内存 id 会随之改变。 但是起名可变和不可变的原因呢?是相对于函数传参来说的。 12345678910111213141516171819202122def test(a_int, b_list): a_int = a_int + 1 b_list.append('13') print('inner a_int:' + str(a_int)) print('inner b_list:' + str(b_list))if __name__ == '__main__': a_int = 5 b_list = [10, 11] c_list = b_list test(a_int, c_list) print('outer a_int:' + str(a_int)) print('outer b_list:' + str(b_list)) print('outer c_list:' + str(c_list)) >>> inner a_int:6>>> inner b_list:[10, 11, '13']>>> outer a_int:5>>> outer b_list:[10, 11, '13'] 所谓的可变类型,就是传入函数中,函数中的变化会同步到函数外的变量。类似引用传递(可以把引用理解为一个箭头,这个箭头指向某块内存地址,而引用传递,传递过来的就是这个箭头,当你修改内容的时候,就是修改这个箭头所指向的内存地址中的内容,因为外部也是指向这个内存中的内容的,所以,在函数内部修改就会影响函数外部的内容。) 而不可变类型,传入函数中的操作会事先新创造一个内存地址,所以并不会影响函数外的变量值。类似值传递(表示传递直接传递变量的值,把传递过来的变量的值复制到形参中,这样在函数内部的操作不会影响到外部的变量)。 初始化二维矩阵1234567891011121314# 如下这种方法初始化以为矩阵没有问题,但是初始化二维矩阵的时候,只是相当于将它的一维列表复制了三次,如果更改某个元素,相当于更改了一列元素alist = [0] * 5multi = [[0] * 5] * 3multi[0][1] = 1print(multi)>>> [[0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0]]# 初始化二维矩阵最好如下操作。multilist = [[0 for col in range(5)] for row in range(3)]multilist[0][1] = 1print(multilist)>>> [[0, 1, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] 深拷贝与浅拷贝 直接赋值:其实就是对象的引用(别名)。 12345a = [1,2,3,[1,2]]b = ab[-1] = [1,2,3]print(a,b)>>> [[1,2,3,[1,2,3]],[1,2,3,[1,2,3]]] 浅拷贝(copy):拷贝父对象,对象的内部的子对象仍是相同的。 123456l1=[1,2,3,[1,2,3]]l2=l1.copy()l2[-1].append(4) # 子对象仍相同,同步变化l2.append(5) # 父对象不同,不会同步变化print(l1,l2)>>> [[1,2,3,[1,2,3,4]], [1,2,3,[1,2,3,4],5]] 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。 1234567import copyl1=[1,2,3,[1,2,3]]l2=copy.deepcopy(l1)l2[-1].append(4)print(l1)>>> [1,2,3,[1,2,3]] # 深度拷贝是将原对象中所有的值完全复制一份存放在内存中(包括可变数据类型对象)。这样遇到原对象即使是更改,也不会影响其值。 1234567891011121314151617# 复制引用与copy.copy, copy.deepcopyimport copya = [1, 2, 3, 4, ['a', 'b']] #原始对象b = a #赋值,传对象的引用c = copy.copy(a) #对象拷贝,浅拷贝d = copy.deepcopy(a) #对象拷贝,深拷贝a.append(5) #修改对象aa[4].append('c') #修改对象a中的['a', 'b']数组对象print( 'a = ', a )print( 'b = ', b )print( 'c = ', c )print( 'd = ', d )>>> ('a = ', [1, 2, 3, 4, ['a', 'b', 'c'], 5])>>> ('b = ', [1, 2, 3, 4, ['a', 'b', 'c'], 5])>>> ('c = ', [1, 2, 3, 4, ['a', 'b', 'c']])>>> ('d = ', [1, 2, 3, 4, ['a', 'b']]) python 运算符优先级 运算符 描述 ** 指数 (最高优先级) ~ + - 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@) * / % // 乘,除,取模和取整除 + - 加法减法 >> << 右移,左移运算符 & 位 ‘AND’ ^ \\ 位运算符 <= < > >= 比较运算符 <> == != 等于运算符 = %= /= //= -= += = *= 赋值运算符 is is not 身份运算符 in not in 成员运算符 not or and 逻辑运算符 123print(100 - 25 * 3 % 4)>>> 97 IO operationsfiles operations read([size]) 文件当前位置起读取size个字节,若无参数size,则表示读取至文件结束为止,整个文件返回为一个字符串对象,文件很大时候 readline() 每次读出一行内容,所以,读取时占用内存小,比较适合大文件,但是速度慢啊!(内存不够时采用)每次读取返回一个字符串对象。 reandlines() 读取整个文件所有行,保存在一个列表(list)变量中,每行作为一个元素,但读取大文件会比较占内存。 linecache 输出某个文件的第n行, 使用示例如下: 12text = lincache.getline('a.txt' , 2)print(text) keyboard operations raw_input([prompt]) 可以读取一行任意字符串 str,将返回 str.strip()12s = raw_input('请输入:')print('你刚才输入了:'+s) 请输入:hhhh你刚才输入了:hhhh input([prompt]) 在 raw_input([prompt]) 的基础上多了一个接受表达式的功能,可以返回运算结果 。 dict123a = {'s':1 , 'w':1}b = {'w':1 , 'e':1}z = {**a , **b} dict.update(dictnew) 命令可以用dictnew更新覆盖原有的字典 在数字作为字典的key值时候,整数和浮点数是相等的,即 {1:5,1.0:6} == {1:6} str str.ljust(50,'@') 用 @ 将字符串填充为长度 50 ,@填补在字符串的后面。 字符串可以通过切片访问,但是不可以通过这种方式赋值。 123>>> a = '456123'>>> a[-3,-1] = 'aaa'TypeError: 'str' object does not support item assignment 创建新字典的方法 12>>> print({}.fromkeys((1,2,8),(3,4))){1: (3, 4), 2: (3, 4), 8: (3, 4)} list从本质上讲,自带pop() 、append() 函数的列表结构是以 stack 为基础的。 删除列表中的元素 del 删除某位置的元素。 12345a = ['a','b','c']del a[0] #指定删除0位的元素print(a)---> ['b', 'c'] list.remove() 删除某指定值元素。 12345a = ['a','b','c']a.remove('b') #删除第一个匹配的指定元素,直接改变原数组,无返回值。print(a)---> ['a', 'c'] list.pop() 删除指定位置元素,并且返回它的数值。如果没有参数,默认参数为”-1”。 12345678a = ['a','b','c']b = ['d','e','f']# pop的命令,其有返回值,可赋值带出c = a.pop() #默认删除-1位置元素'c',并将删除元素返回值赋值d = b.pop(0) #删除0位元素'd',并将删除元素返回值赋值print(a,b,c,d)---> ['a', 'b'] ['e', 'f'] c d list的引用才有append()函数,不可直接调用 123456# 错误用法[5,6].append(9)list().append(9)# 正确用法a = [5,6]a.append(9) 正则表达式 ^ 符号不出现在中括号中,表示匹配开始字符;而出现在中括号中,表示匹配除了中括号中的其他所有字符。 \\w 表示匹配字母、下划线或者数字 \\? 表示正则表达式中的非贪婪模式 @staticmethod与@classmethodpython 面向对象中,不带装饰器的叫做实例方法, @classmethod 装饰的是类方法,@staticmethod 装饰是的静态方法。 静态方法,跟普通函数没什么区别,与类和实例都没有所谓的绑定关系,它只不过是碰巧存在类中的一个函数而已。不论是通过类还是实例都可以引用该方法。 Others 任何一个内置的shuffle()函数,返回值类型都为None,它们直接作用在原本的列表上,不会创建新对象。 1234import randomL = [2,3,4,56,78,9,0]random.shuffle(L)print(L) 当 python 中表示复数的时候,复数之间不能比较大小。 python 中表示复数,实部可以是整数、也可以是浮点数; 而虚部是关于X轴的反转程度。 python 静态类变量可以被实例或者类本身访问并且修改。 heapq 是python自带的完全二叉树结构的类型,常用于堆排序(最小堆,不受初始数据顺序影响) deque 是python中的双端队列结构 检查函数类型时候只写函数名,不加括号;调用函数时侯加括号,返回函数的运行结果值。 python 是弱语言类型, 不用对变量类型进行直接赋值。但如果调用一个未赋值对象会报 NameError 错误。 Python变量访问时有个LEGB原则,也就是说,变量访问时搜索顺序为Local ==> Enclosing ==> Global ==> Builtin,其实很多语言都遵循这个规则。简单地说,访问变量时,先在当前作用域找,如果找到了就使用,如果没找到就继续到外层作用域看看有没有,找到了就使用,如果还是没找到就继续到更外层作用域找,如果已经到了最外层作用域了还是实在找不到就看看是不是内置对象,如果也不是,抛出异常。 自定义类中,如果我们想要返回特定信息。需要改变函数中的 str 方法 Stackless并非以库的形式和Python整合,Stackless提供的并发建模工具,比目前其它大多数传统编程语言所提供的工具都更加易用: 不仅用于Python自身,也包括Java、C++,以及其它语言。 Scrapy是Python进行网络抓取的第三方库,包含Scrapy引擎,下载器,爬虫,调度器,Item Pipeline以及中间件,并没有沟通隧道(connect)。 常用模块os 模块os.listdir(dirname):列出dirname下的目录和文件 os.getcwd():获得当前工作目录 os.curdir:返回当前目录(’.’) os.chdir(dirname):改变工作目录到dirname os.path.isdir(name):判断name是不是一个目录,name不是目录就返回false os.path.isfile(name):判断name是不是一个文件,不存在name也返回false os.path.exists(name):判断是否存在文件或目录name os.path.getsize(name):获得文件大小,如果name是目录返回0 os.path.abspath(name):获得绝对路径 os.path.normpath(path):规范path字符串形式 os.path.split(name):分割文件名与目录(事实上,如果你完全使用目录,它也会将最后一个目录作为文件名而分离,同时它不会判断文件或目录是否存在) os.path.splitext():分离文件名与扩展名 os.path.join(path,name):连接目录与文件名或目录 os.path.basename(path):返回文件名 os.path.dirname(path):返回文件路径 参考 廖雪峰的官方网站 RUNOOB.COM","categories":[{"name":"Programming_language","slug":"Programming-language","permalink":"https://imbowei.com/categories/Programming-language/"},{"name":"Python3","slug":"Programming-language/Python3","permalink":"https://imbowei.com/categories/Programming-language/Python3/"}],"tags":[{"name":"File_operations","slug":"File-operations","permalink":"https://imbowei.com/tags/File-operations/"},{"name":"Python3","slug":"Python3","permalink":"https://imbowei.com/tags/Python3/"},{"name":"Deepcopy","slug":"Deepcopy","permalink":"https://imbowei.com/tags/Deepcopy/"},{"name":"Copy","slug":"Copy","permalink":"https://imbowei.com/tags/Copy/"},{"name":"Generator","slug":"Generator","permalink":"https://imbowei.com/tags/Generator/"},{"name":"Iterator","slug":"Iterator","permalink":"https://imbowei.com/tags/Iterator/"}]},{"title":"无名之辈不无名(A Cool Fish)","slug":"an-unknown-person-is-not-unknown","date":"2018-11-16T12:41:16.000Z","updated":"2018-11-17T12:26:16.000Z","comments":true,"path":"2018/11/16/an-unknown-person-is-not-unknown/","link":"","permalink":"https://imbowei.com/2018/11/16/an-unknown-person-is-not-unknown/","excerpt":"感谢影片Cast阵容中的一个个“无名之辈”, 让我们置身于一个西南小城中,陪着一个个无名之辈度过了生命中的荒诞一天。","text":"感谢影片Cast阵容中的一个个“无名之辈”, 让我们置身于一个西南小城中,陪着一个个无名之辈度过了生命中的荒诞一天。 在一座山间小城中,一对低配劫匪、一个落魄的泼皮保安、一个身体残疾却性格彪悍的残毒舌女。以及一系列生活在社会不同轨迹上的小人物,在一个貌似平常的日子里,因为一把丢失的老枪和一桩当天发生在城中的乌龙劫案,从而被阴差阳错地拧到一起,发生的一幕幕令人啼笑皆非的荒诞喜剧。 以下剧透 无名之保安2018.11.16,贵州一个小城中,泼皮保安的一天从一场群架开始。 为了一个欠债逃跑的老板,被吊在空中戏耍,被殴打。最终靠着武林绝学九阴白骨爪才得以侥幸逃脱,临了还不忘为自己捞点外快。捂着肿起来的眼角还死皮赖脸的勾搭警队队长,为了自己邀功请赏获得协警职位。下一幕,他又勾搭调侃卖菜大娘,顺手牵羊,欠账耍赖。 貌似,一个生活在社会底层的泼皮已经跃然纸上了。 然而,事实真是如此吗? 去赊账枣子送给学校老师,借口钱买了房,学校走廊上当众教育女儿,嗦他人吃剩下的粉。因为喝醉酒葬送自己的前程,妻子的生命。嗯,泼皮无误。 但其实,泼皮也有泼皮的认真,泼皮也有泼皮的执着,泼皮也有泼皮的爱。 泼皮认真了,他是真的想要找到那把枪。利用小市民心理,套取银行保安第一现场情况;厚脸皮的借口”要饭”吃,实则偷听警方线索;机智的守株待兔,”捕获”波波;“残忍”逼供,逐步揭开谜底;娱乐场所私自办案被误会,却依旧忍辱负重;巧设陷阱,乔装打扮,终获丢失的枪! 泼皮仅仅是为了协警的职位吗?不,他也有他的倔强,即使已经巧妙躲过一枪。警车上拿着水枪与悍匪对峙仍寸步不让。他是真的热爱警察这个行业。 同样的,泼皮是真的爱她的女儿。低声下气地向老师求情,然而尊严被老师和女儿踩碎一地。他也悉心照料自己的妹妹,妹妹受到侮辱时,会激动以泼皮暴力的方式解决问题;妹妹情绪不佳时,作为哥哥也会及时体察。 这,就是有血有肉的泼皮保安,一个无名之辈。 无名之憨匪2018.11.16,贵州一个小城中,两个悍匪的一天从一场抢劫开始。 君见,他霸道嚣张。 抢劫“银行”,开枪示威。侵入民宅,一言不合就“一枪爆头”。得意洋洋的等待电视台报道他们哥俩的光辉事迹,雄心勃勃的计划哥俩的光明前程。 不见,他自卑敏感,细腻温柔。 他看到电视台对他们的嘲讽时,痛苦癫狂。其实所谓的霸道张扬只是他坚硬的盔甲,真实的小我敏感又自卑,绝对不允许发生的事情是别人对他的玩弄的和嘲笑。而是什么将他从受辱的癫狂中解救出来呢?直到敏感的他意识到了眼前的毒舍女为什么一心求死,那种连大小便都无法自理的尴尬和痛苦他太有代入感了。他心软了,拍照,聊天,劫匪和毒蛇女度过了一个还算是“愉快”的下午,他细腻的吹干头发和衣服,准备了音乐,温柔的满足了她的每一个愿望。 貌似,他在楼门口吸完一支烟后,绝情地离开了。其实呢?离开是为了更好的回来。但是,自卑敏感的他不敢说出自己心中真实所想。他只会委婉地暗示,“路走得没了有桥的,桥也是路的一种”。而“后半辈子的桥,我陪你一起走”这么煽情丢脸的话,他一定是不会说出口的……他是真的想照顾她一辈子了,却阴差阳错地被夜晚的礼炮(一开始无名猥琐男听收音机时候有铺垫)吓得失手放枪…… 相比于前一位“悍匪”,后面这位无名大侠只能称之为“憨匪”了吧。 他的憨是那种真的憨,不是假的憨,是由内到外往外冒泡泡的憨。。。憨憨的他也自然而然地承包了本片的很多笑点,天然憨的他也和霸道冲动的他也组成了一对“黄金搭档”。你负责放枪耍威风,我就负责卖萌装手机;你负责下令逃跑。我就负责搞笑耍宝;你负责暴怒冲动,我负责冷静劝架;不敢想象没有他,他们两个还会不会在毒舌女的攻击下全身而退。 连编剧设计的台词都那么恰到好处的为他量身定做,咕嘟咕嘟的往外冒着憨气…… “如果抢劫分到十万块,七万块装修,两万块结婚,剩下的一万全部给你买棒棒糖。谁让你最喜欢吃棒棒糖呢。” 这,就是“年度最憨”劫匪,两个来自十八线小寨子的无名之辈。 无名之残女2018.11.16,贵州一个小城中,一个残女的一天从新的绝望开始。 当飞来横祸,姐姐去世,自己高位截瘫,生活不能自理,你会怎么办?一睁眼,又是新的绝望的一天。 可是这一天,还是有点不一样的。自己拼了老命的毒舌,终于把碍手碍脚的保姆骂走了。然而,从窗户里却飞进两个不速之客。刚开始,也还是害怕的啊,直到被激怒的一个悍匪冲动的将猎枪对准自己的脑门。红了眼眶的她想到了一个能让自己快速摆脱惨淡余生的方法。所以啊,她拉着两个劫匪不放,肆意地调笑、怒骂,只求一死。直到……直到……她无法控制的小便失禁,尴尬的现场触动了两个男人内心深处的善良,帮她完成最后的愿望。 多么欢乐的一个下午,浑身都不能动的她要被吊着摆出各种动作拍照。却意外发现,躺在地上是更为有趣的方法。欢乐是短暂的,该来的黄昏总会来的。貌似,一切都没有变,路的尽头没有了路;貌似,有什么悄悄变化了,路的尽头还有桥。即使和哥哥的最后一次对话恋恋不舍,也还是会破口大骂。我们终于明白最终,毒舌不是她的本色,而只是保护色。即使恋恋不舍地要抱抱,也不肯改变自己的决定 。倔强的她还是要求打开煤气,告别这她爱的世界。 这,就是一个残废毒舌女,来自西南小城的无名之辈。 无名之辈不无名其实啊,无名之辈不无名。这不,我们不都知道他们是谁吗? 你是泼皮保安马先勇,你是陈建斌; 你是截瘫毒舌马嘉旗,你是任素汐; 你是憨萌劫匪李海根,你是潘斌龙; 你是霸道劫匪胡广生,你是章宇; 你是潜逃老赖高明,你是王砚辉; 你是…… 谢谢这一个个“无名之辈”为我们上演了一出最热血、最荒诞、最搞笑、最悬疑、最奇葩的“无名之辈”。","categories":[{"name":"Movie","slug":"Movie","permalink":"https://imbowei.com/categories/Movie/"},{"name":"Absurd-comedy","slug":"Movie/Absurd-comedy","permalink":"https://imbowei.com/categories/Movie/Absurd-comedy/"}],"tags":[{"name":"Movie","slug":"Movie","permalink":"https://imbowei.com/tags/Movie/"},{"name":"Absurd","slug":"Absurd","permalink":"https://imbowei.com/tags/Absurd/"},{"name":"Comedy","slug":"Comedy","permalink":"https://imbowei.com/tags/Comedy/"},{"name":"Multithreading","slug":"Multithreading","permalink":"https://imbowei.com/tags/Multithreading/"},{"name":"A-Cool-Fish","slug":"A-Cool-Fish","permalink":"https://imbowei.com/tags/A-Cool-Fish/"}]},{"title":"BERT:From Transformer Architecture to Transfer Learning","slug":"From-transformer-architecture-to-transfer-learning","date":"2018-10-27T12:07:40.000Z","updated":"2019-04-15T01:22:50.538Z","comments":true,"path":"2018/10/27/From-transformer-architecture-to-transfer-learning/","link":"","permalink":"https://imbowei.com/2018/10/27/From-transformer-architecture-to-transfer-learning/","excerpt":"半个月前BERT横空出世,在数十个数据集上屠榜,一时风头无两。外加国内一些科技自媒体的“UC式”标题推波助澜,也给这篇文章博得了更多的关注。为了更好的理解BERT,我们需要先理解Attention和Transformer结构。然后可以集中精力从Transfer Learning的角度来比较ELMo,GPT,BERT这三篇文章的优劣异同。","text":"半个月前BERT横空出世,在数十个数据集上屠榜,一时风头无两。外加国内一些科技自媒体的“UC式”标题推波助澜,也给这篇文章博得了更多的关注。为了更好的理解BERT,我们需要先理解Attention和Transformer结构。然后可以集中精力从Transfer Learning的角度来比较ELMo,GPT,BERT这三篇文章的优劣异同。 Attention 什么是注意力机制?可以想象这样一个画面,当电视机上有非常吸引我们的画面时,我们的视野之中除了电视画面,眼中所看到的屋子中的其他部分仿佛都变得模糊了。甚至妈妈在你的面前从一侧穿行到另外一侧,你都毫无察觉。 有所关注,有所忽略——这便是注意力机制。 从生物进化的角度上来讲,这是十分合理的“节能减排”,我们的大脑将资源集中分到了我们最关心的事物上面,让我们免受其他事务的干扰。 Attention机制最早应用于视觉领域的分类问题,而为了更好的取得词向量表达, Bengio 在2014年引入了Attention机制,这极大的提升了NMT方法的性能。尽管仍存在训练时间长,OOV,可解释性差等问题,但某些性能指标上已经媲美SMT系统,并大大减少了形态学和句法错误,提升了翻译的流畅性。这篇论文也直接影响Google在2016年用GNMT系统替换掉了上线十年之久的PBMT系统,不仅将Attention机制推到闪耀的聚光灯之下,也彻底将SMT方法推下了机器翻译的神坛,开启了NMT方法狂飙的时代。 以2013年Nal Kalchbrenner 和 Phil Blunsom的 Recurrent Continuous Translation Models 论文为标志,神经网络机器翻译诞生。该文整体采用编码器——解码器框架,用CNN将源文本编码成特定的向量,再用一个RNN作为解码器将该向量转化为目标语言。但由于梯度消失/爆炸问题的存在, 长距离依存问题制约模型的表现。 为了缓解这一问题,Sutskever et al. 和 Cho et al. 引入了LSTM。 Attention Mechanism以上就是Attention机制在NLP领域的应用背景和重要意义,下面我们来详细理解它的作用机制。 Seq2seq普通的LSTM是采取的是序列编码的方式来获取信息,这样的一大好处就是在编码的时候可以得到词语的远距离依赖信息。如下图所示:我们在编码“力量”的时候,可以知道“知识”是它的来源。 下面我们来看一个形象化的基于sequence-to-sequence框架的NMT模型。先看编码器,除了最初状态之外,后续每个状态都接收前一个状态的编码信息以及当前位置的源句子词语信息,整个源句子顺次编码。在编码完源句子最后一个词的信息之后,才执行解码操作。同样的,解码结构也是顺序执行的。视频中给出的过程应该是测试过程,前一个位置没有传递给下一个位置真实的解码词语参考,而在训练过程中是要给出的。 Seq2seq构架的劣势也不难发现: 如果单向RNN编码,前面的词语在先行编码的时候没有办法得到后面词语的信息; 一个形象的例子, “I arrived at the bank after crossing the …. ” 我们在不知道后面省略的单词是 river or road 的前提下,该如果编码单词 bank 的真实含义呢? 信息损失:如果句子很长,两次词语之间相隔比较远,信息传递过程中的损失比较大; 信息糅杂:最后一个状态中理论上包含前面所有的信息,所有信息都杂糅在一起不好区分; 顺序编码本质上是一个马尔可夫决策过程,无法很好的得到全局信息; 无法并行计算,只有当所有词语都编码结束的时候才可以开始解码,系统的训练速度很慢; Seq2seq+Attention加上Attention Mechainism的seq2seq结构解决了上述 Long Range Dependence弊端。与seq2seq过程对比,我们观察下面一个视频。 首先避免信息缺失问题,将Encoder每个时刻的状态都传递给Decoder,而不是只传递Encoder最后一个时刻的状态。最大程度上保留源句子的信息。 其次,为了避免信息冗余,我们如何只在每个时刻关注我们最关心的部分呢?用一个动态的权重向量(注意力分布),根据其与所有Encoder的隐藏状态信息的相似性大小进行加权求和。加权计算的过程,如下视频所示。 最后,解码时,每一时刻的注意力分布都由这一时刻的解码hidden states来决定。这一时刻的hidden states的输出和注意力机制加权过的向量拼接后归一化,概率最大的一维所对应的词语就是我们这一时刻的翻译结果。过程如下动画所示。 经过上述Attention结构上的剖析,我们再次来总结什么是 Attention 机制? 在我看来,Attention 其实就是一种用在Seq2seq构架上的加权词对其模型。起名为注意力机制,一方面是为了可以从大众容易理解的方式更好的解释模型设计的合理性;另一方面,我认为也是为了更容易完成学术投稿吧。Just a writing trick! Transformer 在GNMT掀起神经网络机器翻译的热潮之后,Amazon、Microsoft、Facebook、百度、网易有道、腾讯 、搜狗、讯飞、阿里巴巴等公司都迅速跟进。其中Facebook以CNN为基础的NMT模型不但效果超过了Google的GNMT,而且在训练速度上也比前者大幅提升九倍。 Google可不能容忍这个风头被抢,作为回应,2017.06谷歌发布了一个完全以注意力机制为基础的NMT模型,也就是我们常说的Transformer。整体构架如下所示,观察模型结构,正如作者所说,Attention is all you need。 Self-Attention对于Transformer构架而言,最核心的部分莫过于Self-attention。如下图所示,每个词语的初始向量乘以三个权重矩阵得到q、k、v三个向量。重新编码每个词语的时候,所有词语的k向量分别与该词语的q向量相乘,然后除以模型维数的开方,最终权重归一化成values向量的权重值。这样的操作,是根据词语向量之间的相似度来完成的。也就是说,每个词语的新向量必然还是会以自身的原本的信息为主要组成部分,只是在此基础上无距离差别的补充了与其他词语的相关性信息。相当于,我们通过整个句子中所有词语之间的相互关系获取了每个词语在句子中的重要性程度,有了更加丰富的语义信息。另外,所有词语获得新向量的过程是可以并行计算的(矩阵运算),即使模型的参数量巨大,在GPU的加持下也获得了远远高于LSTM的训练速度。 Attention(Q,K,V)=softmax(\\frac{QK^T}{\\sqrt{d_k}})VPosition Embedding上述Self-Attention虽然构思巧妙,但是只能说是一个精妙的词袋模型,并没有捕捉到任何次序信息。很不幸,这对翻译任务是致命的。为了能让这个简单的结构很好的工作,这个时候作者提供了一个额外的词向量去补充词语之间的位置关系,缓解这一缺陷。公式如下,采用的是三角函数的形式,好处是在测试的时候如果遇到超出我们训练长度限制的句子,模型也可以进行位置编码。 PE_(pos,2i)=sin(\\frac{pos}{10000^{\\frac{2i}{d_{model}}}}) \\\\ PE_(pos,2i+1)=cos(\\frac{pos}{10000^{\\frac{2i}{d_{model}}}}) 然而,Position Embedding对于本身模型不能捕捉位置信息,只是起到了一个弥补的作用,并不能从根本上解决模型设计上的缺陷。在实验结果上也可以察觉出一些端倪,为什么同一语系的双语翻译的BLUE数值表现会比不同语系之间的双语翻译效果要好呢?我猜测是同一语系不同语言之间的语序差别较小,而不同语系语言之间的语序差别较大。甚至说,以BLUE作为翻译效果的自动评价指标对于Transformer模型也是占便宜的,因为语言模型本身对于语序正确的要求并没有很高。 Multi-Head AttentionMulti-Head Attention这个概念是在这篇论文中第一次被提及,然而其实际操作并不罕见。其实就是将Self-Attention这一个过程随机初始化8次,相当于映射到不同的子空间,然后拼接起来并乘以权重向量产生输出层。 相当于我们从多种角度来理解同一个句子,以求更加完备的语义表达。 MultiHead(Q,K,V)=Concat(head_1,...,headf_h)W^o \\\\ where\\ head_i = Attention(QW_i^Q,KW_i^K,VW_i^V)最后我们来观察一下Multi-Head Attention的效果,已经其背后的含义。下面的第一张图片只展示了两次的Multi-Head Attention,我们还可以尝试来解释。黄色的注意力机制敏锐了步骤到了it这个代词所指代的对象,是animal;而绿色的注意力机制貌似是错误的,因为直接指向了一个动词tire。但细细琢磨,这似乎也有一定的道理,因为动词tire是服务于主语animal,而it在这里恰好指代的就是主语animal。 由上面的观察分析可以发现,多重的注意力机制确实可以捕捉到许多句子中隐含的语义细节,得到更好的句子标示。当这种语义表示维度过高时,我们往往难以解释其真实含义。但是,确实效果还不错。 Conclusion总的来说,Transformer构架的核心思想是计算一句话中每个词对于这句话中其它所有词的相互关系,然后认为这些词与词之间的相互关系在一定程度上反应了这句话中不同词之间的关联性以及它们的重要程度。再利用这些相互关系来调整每个词的重要性(权重)就可以获得每个词新的表达。这个新的表征不但蕴含了该词本身,还蕴含了其他词与这个词的关系,因此和单纯的词向量相比是一个更加全局的表达。Transformer通过对输入的文本不断进行这样的注意力机制层和普通的非线性层交叠来得到最终的文本表达。拥有一个文本信息更加充分全面的表达,得到更好的BLUE数值表现也就顺理成章了。 根据上述介绍的模型结构,并且结合Transformer结构提出的背景,不难看出其浓重的CNN气息。具体的有以下几个方面: Attention是不是像一个没有感受野限制的CNN?所有单词之间的距离为一,一步到位的获得全局信息,免去的CNN的堆叠操作。 Multi-Head Attention多次运算进行拼接操作,对比CNN中的多个卷积核,是否感觉似曾相识? 同CNN一样,需要一个Position Embedding 来辅助获得位置信息。只不过这个更为“泛化的CNN”对Position Embedding的依赖更加严重。 尽管作者的writing trick让人有些许反感,但这并不失为一篇好论文。 首先,模型构架大道至简。感概Google工程师扎实的炼丹功底,如此简单的方法都可调出STOA。 Attention 并不简简单单可以完成“词对齐”工作,而且可以完成序列到序列的转换。 其次,写作清晰,整篇论文读起来很清爽,没有故弄玄虚的堆砌公式。(可惜没有Ablation Test,不能确定Transformer构架各个部分的作用效果) 最后,运用些许的写作技巧来提升自己工作的影响力这本无可厚非(这个名字确实太吸引人去阅读他们的论文了)。也是我需要尽快提高的地方。。 Transfer 源于Google扎实的工作(夸张的论文名字),Transformer 坐上了NMT模型的王座,更是在NLP领域一时风头无两,在众多任务上都取得了很好的表现。当其应用到迁移学习领域的时候,就创造出了现在Google另一个红透半边天的工作——BERT。 ELMo2018初的NAACL上,AllenNLP祭出了大杀器ELMo。而Google将自身的 Transformer 构架用在迁移学习领域,相信少不了受到了这篇 Deep contextualized word representations 文章的启发。 在EMLo出现之前,不论时研究者习惯性地用word2vec去初始化,还是尝试性的用CNN、RNN等网络结构探索字符级别的文本向量。然而,无论再怎么折腾,怎么细化挖掘信息的级别。都有共同的一点,Embedding没有考虑到语境中的上下文信息 ,总是一成不变的,没有表征一词多义的能力。而EMLo拿出了极具说服力的表现告诉大家,是时候该放弃古老的word2vec了。。。 这篇论文有以下几个关键点: CNN提取字符(中文可以考虑拼音或者笔画)级别信息; 两个单向LSTM,loss相互独立; 浅层语法,深层语义; 层级输出线性加权,可以根据任务需要自训练不同的权重; GPT趁热打铁,AllenNLP 又从迁移学习 Fine-tuning的角度发布了另一个重要工作——Improving Language Understanding by Generative Pre-training(GPT)。这个工作也直接引导出了Google的重磅论文BERT。如果说ELMo的野心只是想要取代Word2vec,成为NLP领域文本输入的标准操作。那GPT显然野心更大,其试图提出一个通用的框架网络,想要成为类似于图像领域的ResNet那样的神经网络骨架,以扭转现在研究task-specific方法愈演愈烈的风气。拯救近期国内外一些公司在某些固定的数据集上穷尽奇淫巧技去调试出一个个过拟合模型,抢占所谓的SOTA。 GPT提出了一个两阶段的模型。第一阶段,在大规模的无监督文本上训练一个单向的Transformer模型;第二阶段,只需要根据不同的任务要求,仅需要少量的特定标注数据进行调优训练,即可获得若干任务数据集上SOTA级别的表现。这样的迁移学习方法,极大的节省了为不同的特定任务进行人工标注数据的高昂成本需求。 GPT已经取得了很令人实验结果,有以下几个点值得我们多加关注: 继续增加生语料,模型效果是否会继续提升? 泛化能力不够强,如果精细化调优技巧(类似:ULMFiT每一层设置不同的学习率?),会不会在适应各个任务的数据集上有更好的表现? 5GB语料,需要8块GPU训练一个月,如何合理的拓展出降低计算需求的方法? 现用的训练生语料,可能由于其自身局限性,导致模型认知世界产生偏差。 BERT顺着GPT的思路,今年10月BERT的横空出世,无疑将2018年NLP领域无监督学习的热潮推向了一个新的高度! 先来看看它在GLUE leaderboard屠榜的盛况。 为什么BERT的性能如此只有优越呢?由于它在以下的几个方面在GPT的基础上有了进一步的突破: Deep modeljacob 以极强的工程能力成功驾驭了一个深达24层、每层1024个神经元、并且Multi-dead数为16、总参数340M的巨大Transformer模型,再一次向我们证明了对于深度学习来说,深度>宽度这一重要规律。当然,也体现了Transformer模型具有良好的稳定性这一重要优点,因为其本身就含有各种Normalization。 Masked LM 观察上图,相比于GPT,BERT在训练上解决了无法使用双向Transformer的窘境。相比于ELMo,两个方向上的loss结合在一起,而不是相互独立,更大程度上释放了Transformer构架的信息采集能力。不难理解为什么双向的Transformer效果要更好,就像我们学习英语做完形填空。我们是只看半句填的准呢?还是前后半句都阅读完填的准呢?相信这不难回答。 双向训练具体是怎么做到的呢?观察下图,当模型层数加深的时候,在每个位置上已经有了原本这个位置上的词的信息,这对于词的预测任务来说无异于作弊,显然是不可行的一种方案。 那么怎么办呢?直接删除需要预测的词语吗?这会是原本的句子失去顺序信息,并且丢掉了这一个词的原本信息,显然不可取。替换为一个随机的词吗?但这会使模型难以收敛,也不可以。最后作者选择只将10%的词语进行随机处理(相当于噪声),而将80%的词用“mask”标记来遮盖,让模型通过这个编辑来学习该位置的填词。然而下游任务中显然不会存在这个“mask”标记,所以最后另外10%的词语我们保持原有这个原有正确的词语。虽然通过这样一个训练技巧,使得双向的Transformer可以正常的工作了。但是由于加入了大量的噪声,模型的收敛仍有待提升。 Jointly Pre-Train由于很多的NLP下游任务涉及到句子之间关系的理解,例如:Question Answering (QA) 、Natural Language Inference (NLI)等等。作者在原有的loss函数后面新添加了一项关于句子间关系理解的loss,来进行联合训练。如下所示,这仅仅是一个简单的二分类问题。jacob将此处的训练模式与下游任务相统一,都是将两个句子一起作为输入(中间有间隔符[SEP])。用无监督语料训练的时候,将一半的句子下一句进行随机句子采样,作为负例“NotNext”;而其余一半则直接给出真正的后句,作为正例“IsNext”。 Input = [CLS] the man went to [MASK] store [SEP] he bought a gallon [MASK] milk [SEP] Label = IsNext Input = [CLS] the man [MASK] to the store [SEP] penguin [MASK] are flight ##less birds [SEP] Label = NotNext Others昨天,中文定制版model也可以在github上获取了。 Position EmbeddingBERT并没有采取GNMT那篇论文中用三角函数来表达句子中词语位置的方法,而是直接设置句子的固定长度去训练Position Embedding,在每个词的位置随机初始化词向量,经过训练,将Position Embedding与Token Embedding、以及模型训练得到的Segment Embeddings 直接相加即可食用。如下图所示。 feature-based?在倒数第二页的一栏,作者实验表明,BERT不仅仅是一个Fine-tuning迁移学习方法,还可以是一个Feature-based迁移学习方法,就像ELMo和Wordsvec。jacob用CoNLL-2003 NER数据集做了实验,feature-based(合并最后四层的输出)版本的BERT仅仅比fine-tuning版本的BERT低0.3的准确率,再次心疼一下帅不过三秒的ElMo和GPT。 More Data相比于GPT模型5GB、800M words 的训练数据,BERT更是用了惊人的3,200M words的训练数据。联想到GPT论文中提到,如果有更多的训练语料,该模型的效果还会进一步提升。我觉得在BERT论文中应该有一个关于Data size的Ablation study,然而令我失望的是我并没有找到。 在BERT巨大的提升背后,我想知道模型上的创新和训练数据数量上的增加,谁贡献更大一点呢?jacob似乎避而不谈。 Conclusion 总的来说,jacob凭借着高超的工程技能,海量的训练数据,以及强大的算力,完成了一篇里程碑级别论文。它的出现在NLP社区产生了重要的影响,并在以下的几方面给我们带来了许多的惊喜和思考: 深度、双向的transformer构架具有强大的数据表示能力以及良好的稳定性; Jointly Pre-Train 对于训练的帮助; Pre-Training 的这把火会以何种形式烧到 NLG ? One for All:手握大量资源的公司越来越倾向于发布一个简单粗暴的通用模型去解决一众问题,科研院校该何去何从? Few-shot Learning:大数据的学习模式真的是机器学习的归宿吗?科研院校是否该从其他角度发力,来探索ML的未来? Reference The Mathematics of Statistical Machine Translation: Parameter Estimation Recurrent Continuous Translation Models Sequence to sequence learning with neural networks Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation Harvard NLP Tensor2tensor GLUE Leaderboard Recurrent Models of Visual Attention Neural Machine Translation by Jointly Learning to Align and Translate Effective Approaches to Attention-based Neural Machine Translation Attention is All you Need Universal Language Model Fine-tuning for Text Classification Deep Contextualized Word Representations Improving Language Understanding by Generative Pre-training BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding One Model to Learn Them All Depthwise Separable Convolutions for Neural Machine Translation Training Tips for the Transformer Model Self-Attention with Relative Position Representations Adafactor: Adaptive Learning Rates with Sublinear Memory Cost Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shif Layer Normalization Semi-supervised Sequence Learning","categories":[{"name":"Deep-learning","slug":"Deep-learning","permalink":"https://imbowei.com/categories/Deep-learning/"},{"name":"Pre-training","slug":"Deep-learning/Pre-training","permalink":"https://imbowei.com/categories/Deep-learning/Pre-training/"}],"tags":[{"name":"Deep-learning","slug":"Deep-learning","permalink":"https://imbowei.com/tags/Deep-learning/"},{"name":"Transformer","slug":"Transformer","permalink":"https://imbowei.com/tags/Transformer/"},{"name":"Attention","slug":"Attention","permalink":"https://imbowei.com/tags/Attention/"},{"name":"Transfer-learning","slug":"Transfer-learning","permalink":"https://imbowei.com/tags/Transfer-learning/"},{"name":"BERT","slug":"BERT","permalink":"https://imbowei.com/tags/BERT/"},{"name":"GNMT","slug":"GNMT","permalink":"https://imbowei.com/tags/GNMT/"},{"name":"Self-attention","slug":"Self-attention","permalink":"https://imbowei.com/tags/Self-attention/"},{"name":"Multi-head-attention","slug":"Multi-head-attention","permalink":"https://imbowei.com/tags/Multi-head-attention/"},{"name":"Positional-encoding","slug":"Positional-encoding","permalink":"https://imbowei.com/tags/Positional-encoding/"},{"name":"ELMo","slug":"ELMo","permalink":"https://imbowei.com/tags/ELMo/"},{"name":"Semi-supervised-learning","slug":"Semi-supervised-learning","permalink":"https://imbowei.com/tags/Semi-supervised-learning/"},{"name":"Pre-training","slug":"Pre-training","permalink":"https://imbowei.com/tags/Pre-training/"}]},{"title":"如何写好学术论文?","slug":"How-to-write-a-great-paper","date":"2018-09-29T12:09:59.000Z","updated":"2018-10-14T07:12:16.000Z","comments":true,"path":"2018/09/29/How-to-write-a-great-paper/","link":"","permalink":"https://imbowei.com/2018/09/29/How-to-write-a-great-paper/","excerpt":"Since the last submission was rejected, I studied how to write English papers. The details are summarized as follows.","text":"Since the last submission was rejected, I studied how to write English papers. The details are summarized as follows. Several Suggestions for writing academic papers Don’t wait: Just write Your idea -> Write paper -> Do research(Forces us to be clear, focused) Do not be intimidated When you research the related work before doing research, you can start to write a survey (3 pages), you can urge yourself to carefully investigate the related papers. In case you are doing experiments, you find that this idea has been done by others. In the process of doing the experiment, you can continually modify the previous three pages. In this process, the paper has gradually formed (5—6 pages). Then add a chart of the experimental results. Identify your key idea Ask yourself why, not how. A re-usable insight, useful to the reader(one clear, sharp idea) You want to infect the mind of your reader with your idea, like a virus. Papers are far more durable than programs. Tell one story(Your narrative flow) Do not assume that the reader wants to read your paper. You have to convince the reader to keep reading at every paragraph. Before switching sections, always have the last paragraph of the previous one introduce it. More importantly, explain why the next section is needed. Do not say “Here are some guarantees from our algorithm”. Introduce and justify its existence first. Here is a problem It’s an interesting problem It’s an unsolved problem Here is my idea My idea works(details , data) Here’s how my idea compares to other people’s approaches Nail your contributions to the mast Write the list of contributions(The major contributions of this paper are summarized as follows:) Do not leave the reader to guess what your contributions are! The list of contributions drives the entire paper: the paper substantiates the claims you have made Reader thinks “gosh, if they can really deliver this, that’s be exciting; I’d better read on” A brief description of each point in one or two sentences. Related work: later The most important thing in the whole paper is my own point of view, put in front. Fallacy: To make my work look good, I have to make other people’s work look bad. Put your readers first Remember: Explain it as if you were speaking to someone using a whiteboard Conveying the intuition is primary, not secondary Introduce the problem Your idea Using EXAMPLES and only then present the general case Do not recapitulate your personal journey of discovery. This route may be soaked with your blood, but that is not interesting to the reader. Instead, choose the most direct route to the idea. Once your reader has the intuition, she can follow the details (but not vice versa) Even if she skips the details, she still takes away something valuable Listen to your readers Getting help Each reader can only read your paper for the first time once! So use them carefully Explain carefully what you want (“I got lost here” is much more important than “Jarva is mis-spelt”.) Treat every review like gold dust Be (truly) grateful for criticism as well as praise Read every criticism as a positive suggestion for something you could explain more clearly DO NOT respond “you stupid person, I meant X” INSTEAD: fix the paper so that X is apparent even to the stupidest reader. Thank them warmly. They have given up their time for you. Language and Style Submit by the deadline Keep to the length restrictions Always use a spell checker Give strong visual structure to your paper using Figures and their captions are the first thing the reader will see! Make them self-contained, with extremely concise and clear captions, saying what they mean and their conclusion. Find out how to draw pictures, and use them Use the active voice(Use “we” as the subject) Use simple, direct language Finish the paper 2 weeks before actual deadline Add colourized TODO notes (different colour for each author) in the document using \\newcommand. This way you can easily remove them to generate a draft for submission. When there’s a paper you like, take literally notes, and try to understand why you liked reading it! Paper Structure Framing research problems (conference paper) Title (1000 readers) Abstract (4 sentences, 100 readers) Do you have a clear problem statement in the abstract? Can you write a research statement for your paper in a single sentence? The “one thing” is stated in the first two lines of the abstract..…(two sentences) Introduction (1 page, 100 readers) Describe the problem Use an example to introduce the problem Transform the sentence pattern and have a simple description of the problem, not a straightforward description. “To the best of our knowledge, balabala……” State your contributions My idea(model) (2 pages, 10 readers) The details(experiments) (4 pages, 3 readers) Related work (1-2 pages, 10 readers) Conclusions and further work (0.5 pages) Good papers leave the reader with one solution to solving a specific problem; great papers leave the reader with new ideas for their own problems. Don’t leave it up to your reader, always ask yourself “what have I learned” and make that explicit. Ideal process Write a rough 2-4 sentence abstract first (what, why, how) Write the Model description next. This is easy, it’s the idea you’re trying out. Then write the Experimental section (ie get the results). Add your results tables, create your graphs. Then write the Discussion & Conclusion sections (what did we learn from this?) Finally write the Introduction (expand #1 by framing the research question, and introducing relevant background work) Write the Abstract last. ReferencesSimon Peyton Jones’s 7 simple suggestions","categories":[{"name":"Academic","slug":"Academic","permalink":"https://imbowei.com/categories/Academic/"},{"name":"Writing","slug":"Academic/Writing","permalink":"https://imbowei.com/categories/Academic/Writing/"}],"tags":[{"name":"Write-a-paper","slug":"Write-a-paper","permalink":"https://imbowei.com/tags/Write-a-paper/"},{"name":"Conference-papers","slug":"Conference-papers","permalink":"https://imbowei.com/tags/Conference-papers/"}]},{"title":"配置便捷的开发环境(PyCharm & Jupyter)","slug":"Configuring-the-best-development-environment-with-pycharm-and-jupyter-notebook","date":"2018-09-17T11:39:43.000Z","updated":"2018-09-20T14:51:20.000Z","comments":true,"path":"2018/09/17/Configuring-the-best-development-environment-with-pycharm-and-jupyter-notebook/","link":"","permalink":"https://imbowei.com/2018/09/17/Configuring-the-best-development-environment-with-pycharm-and-jupyter-notebook/","excerpt":"由于在PyCharm中进行统计整理数据、画图等操作有诸多的不便。在本地的jupyter notebook进行处理又显得步骤繁琐(传输文件),故萌生在服务器搭建jupyter notebook的想法。两种工具优势互补,从而最大程度上集中注意力在项目本身,提升开发效率。","text":"由于在PyCharm中进行统计整理数据、画图等操作有诸多的不便。在本地的jupyter notebook进行处理又显得步骤繁琐(传输文件),故萌生在服务器搭建jupyter notebook的想法。两种工具优势互补,从而最大程度上集中注意力在项目本身,提升开发效率。 “工欲善其事,必先利其器”,接下来看看如何用PyCharm和Jupyter配置最便捷的python开发环境。 PyCharm 一打开软件界面,满满的科幻感迎面扑来。用色块构建的魔幻画面好似一张变形金刚的面庞。最新的版本加入了默认的Vim编辑模式,让强大的PyCharm更如猛虎添翼一般。 基础配置打开设置界面的快捷键是Ctrl+Alt+S。 背景色:软件默认的背景是白色的,这显然不符合我们广大程序员的审美。File -> Appearance &Behaior -> Appearance 中可以修改, Darcula 是常用的黑色主题。 字体:不出意外的话,你会认为它的字体有些小。File -> Editor -> Font 中可以放大,console中的代码和编辑区的代码设置方式类似。 主题:如果对默认主题的配色不满意,可以在 File -> Editor -> Color Scheme 中修改。 代码风格:在 File -> Editor -> Code Style 中,可以对不同类型的代码文件可以分别进行个性化设置。 代码模板懒人改变世界,而程序员往往都很懒。。。能让计算机手工完成的内容绝对不会自己动手重复添加。 不难发现,在程序开发过程中,有一些代码基本没有变化,而且我们会经常性的重复使用。那么,这种傻傻很麻烦的事情最适合计算机来自动完成了。显然,开发PyCharm的程序员小哥想到了这一用户痛点。 在 File -> Editor -> File and Code Templates 中,我们可以将常用的文件类型中的一些常用代码写入该类型文件的默认模板中,例如。 1# -*- coding: utf-8 -*- 除此之外,还可以在文件开头添加一些注释信息。如下所示: 版本控制一个好的开发环境不可能没有版本控制系统。 PyCharm内置了CVS、Git、Mercurial、Subversion等多种版本控制工具,我们只需要简单的配置即可使用。 从github上Clone 代码,上传保存,进行版本控制,多人协同开发,统统可以在软件内轻松地完成。 远程调试这是一个超级良心的免费功能,我相信即使这个功能收费,也会有很多程序员小哥继续使用PyCharm。在其他的地方写代码,我们都需要在本地调试好,再上传服务器。出问题后,再次修改,再次上传,非常浪费时间。那么如何简化本地代码和服务器代码之间的沟通工作呢?PyCharm也帮我们内置好了。 在Tools -> Deployment -> Configurtion中可以配置好多台服务器,如果服务器中的python环境配置良好,我们就不需要再单独在本地配置一遍。配置如下所示: 在对应的位置填写好服务器的位置,自己的用户名和密码,以及想要打开的根目录(节省重复打开文件夹的时间)。 第二个选项卡Mappings中配置本地项目和服务器项目对应的映射关系。这里有个需要注意的地方,建议只将代码和训练语料分开存储,不要使训练语料成为映射项目的一部分,加快加载速度。在第一次配置好开发环境的时候,需要将服务器的一些文件下载到本地,需要稍等几分钟,以后就很幸福了! 在Tools -> Deployment -> Configurtion中选择本地文件的上传方式,我这里将Ctrl+S设置为本地保存并上传服务器。 Jupyter-notebook对于jupyter notebook来说,它的缺点还是十分明显的。没有一个很好的框架,不能清晰的构建大型项目。也不曾拥有IDECtrl+点击函数名就可以跳转的方便功能,导致阅读代码吃力。 但同样的,它的对于PyCharm的优点也是无可替代的。 PyCharm简直是一个科学计算的神奇,在做数据挖掘的时候,代码和报告(支持latex公式)高度融合,无需二次撰写。 在处理数据的时候,所有中间结果不会被擦除,都显示在对应的cell下面。方便调试,减轻记忆的工作量。 方便的图表展示,不像PyCharm那样,会新弹出一个窗口展示图片,图文融合在一起。 丰富的插件支持,高度自定义。 等等…… 虽然优点众多,但如果只能在本地运行也只能算是鸡肋。经常将工程中的部分文件从服务器传输到本地再分析,这是一件很累人的事情。 服务器jupyter搭建 首先保证我们的linux服务器的python(Anaconda)环境已经配置好了。 打开Ipython,输入如下两行代码后,会生成一个字符串,例如”sha1:9305015210b4:32cad364c85e7f7a13b9efa137cfadf633cc62d“。请复制出来暂时保存,稍后会使用。 12from notebook.auth import passwdpasswd() 如果~/.jupyter路径下没有 jupyter_notebook_config.py ,则输入如下命令新建它。 1jupyter notebook --generate-config 新产生的文件中的所有内容都以注释的形式存在,直接在文件末尾加入如下几行代码,并根据自己的环境调整路径。 12345c.NotebookApp.ip = '*' # 允许访问此服务器的 IP,星号表示任意 IPc.NotebookApp.password = u'sha1:xxx:xxx' # 之前生成的密码 hash 字串c.NotebookApp.open_browser = False # 运行时不打开本机浏览器c.NotebookApp.port = 12035 # 使用的端口c.NotebookApp.enable_mathjax = True # 启用 MathJax 由于大家公用的服务器,我并没有管理员权限,不能将jupyter notebook添加为系统级别的服务。我们只需执行如下命令就可以方便的在本地调用jupyter notebook了(服务器不会经常重启)。 1nohup jupyter notebook > notebook.file 2>&1 & 调用方式:在本地浏览器中输入`服务器地址:设置的端口号`即可。例如:165.32.65.109:7060 Jupyter 优化 感谢造轮子的大佬 jupyter-themes ,为优化jupyter 做了一个很好的包。 更换主题 对于程序员来说,Jupyter默认的白色背景不是很友好,为了和黑色的Pycharm更加搭配,可以先执行如下命令安装其他主题 pip install jupyterthemes --user 安装好之后的操作很简单,如下例所示。 1234567891011121314151617# list available themes# onedork | grade3 | oceans16 | chesterish | monokai | solarizedl | solarizedd# 列出所有可用的主题jt -l# select theme...# jt -t 主题名jt -t chesterish# restore default theme# NOTE: Need to delete browser cache after running jt -r# If this doesn't work, try starting a new notebook session.# 恢复默认主题jt -r# 更改主题,改变代码字体,改变代码大小,改变cell占屏幕宽度,jt -t oceans16 -f fira -fs 12 -cellw 90% 自动代码补全 虽然Jupyter也可以代码补全,但是总是需要多此一举的按一个Tab键,与PyCharm风格不搭配。 方法一:执行ipython profile create 命令, vim ~/.ipython/profile_default/ipython_config.py,修改成如下样子。重启jupyter后生效 1234567891011121314## Activate greedy completion PENDING DEPRECTION. this is now mostly taken care# of with Jedi.## This will enable completion on elements of lists, results of function calls,# etc., but can be unsafe because the code is actually evaluated on TAB.c.Completer.greedy = True## Experimental: restrict time (in milliseconds) during which Jedi can compute# types. Set to 0 to stop computing types. Non-zero value lower than 100ms may# hurt performance by preventing jedi to build its cache.c.Completer.jedi_compute_type_timeout = 400## Experimental: Use Jedi to generate autocompletions. Off by default.c.Completer.use_jedi = True 方法二:安装如下插件,如果报错,还需要更新配置一些包环境: 12pip install jupyter_contrib_nbextensions --userpip install jupyter_nbextensions_configurator --user 1234pip install --upgrade ipykernel --userchmod 777 ~/.local/share/jupyter/pip install --upgrade --user nbconvertpip install --upgrade jupyter_core jupyter_client --user 总结至此,PyCharm 和 Jupyter 都已经配置完毕。今后PyCharm仍然是主力的代码编辑工具。但在工程构建过程中,免不了许多中间结果需要分析和查看,这个时候Jupyter就可以派上用场。进行轻量的模块化分析任务。另外,Jupyter也可以打开文本文件进行编辑(可以自由选择Vim/Sublime等编辑模式),这样就不用使用WinSCP来单独查看文件;Jupyter也可以打开Terminal,这样我们就不用再单独使用Xshell,Xming等软件。释放本地内存。 我们只需要开启浏览器和PyCharm就可以方便交互服务器,进行代码的版本控制,以及进行数据分析。接下来可以更加愉快的干活了!","categories":[{"name":"Tool","slug":"Tool","permalink":"https://imbowei.com/categories/Tool/"},{"name":"Server","slug":"Tool/Server","permalink":"https://imbowei.com/categories/Tool/Server/"}],"tags":[{"name":"PyCharm","slug":"PyCharm","permalink":"https://imbowei.com/tags/PyCharm/"},{"name":"Jupyter","slug":"Jupyter","permalink":"https://imbowei.com/tags/Jupyter/"}]},{"title":"Win10平台下的常用软件","slug":"win10-software","date":"2018-09-09T07:56:09.000Z","updated":"2018-10-14T03:14:16.000Z","comments":true,"path":"2018/09/09/win10-software/","link":"","permalink":"https://imbowei.com/2018/09/09/win10-software/","excerpt":"由于电脑系统最近崩溃两次,让我有了备份常用软件清单的想法。工欲善其事必先利其器,不断追求效率的提升是一件很幸福的事情。清单不定期更新。","text":"由于电脑系统最近崩溃两次,让我有了备份常用软件清单的想法。工欲善其事必先利其器,不断追求效率的提升是一件很幸福的事情。清单不定期更新。 楔子 由于组里面配备的电脑是金胜维硬盘,前一个月系统崩溃了两次,硬盘报废了。导致我花费了大量的时间重装系统,配置环境。 在此特地致谢良心的金胜维公司锻炼我重装系统的耐心。 🙃╮(╯▽╰)╭🙃 现在新换了三星的SSD,但还是决定记录一下常用的软件环境配置,为以后可能的迁移系统做准备(虽然也有可能直接入坑Linux了)。 操作系统 对于很多组织(学校/公司)来说,都会统一购买正版的win10系统,从相应的资源站点下载正版系统,并获取激活码即可。 在这里或者这里可以下载Ultraiso,将我们的正版系统制作成U盘安装。 台式机启动的时候按Fn+F12选择U盘启动(这里是Dell台式机),然后先格式化掉原有系统,重装正版系统。 安装系统后,登陆微软账号就可以将之前的主题配置找回。(前提在快捷键win+i后的更新与安全选项卡中同意配置同步) 双屏配置很简单(免去Alt+Tab之苦,还能多看几行代码),但找一个漂亮的壁纸就不简单了。可以在 沙沙野 找到很多漂亮的高清原图,然后按照显示器分辨率PS两张图出来就好了。 软件 工欲善其事必先利其器,记录一下常用的一下软件。 日常必备Shadowsocks(SS)如果学校/公司没有搭梯子,那只能自力更生了,梯子在这里,你只需要一台国外的服务器就好了~ Chrome可高度自定义的浏览器,搭配Google使用口味更佳哦(可以直接同步其他电脑的设置)。介绍一些有用的的插件(啧啧啧~)插件商店 Grammarly: 搭配 overleaf , 用于学术写作。 Google schoolar: 常用的学术搜索。 Google translate: 页面划词翻译。 Markdown here: 写漂亮得电子邮件。 qiniu upload files:七牛云插件(如果你用markdown写作的话) 低价保护/惠惠购物助手/购物党:淘宝京东等购物网站的比价插件~ Firefox有时候一些网站会有个人/公司,两个账号,浏览器记住密码的时候不方便,chrome搭配火狐使用。 Git这是一个没有办法不用的东西。 下载地址 Bandzip口碑较好的一个压缩软件。 Offices这个没什么好说的,必须安装。就算你每天写markdown或者latex,但是别人会给你发word啊,┏┛墓┗┓…(((m -__-)m Teamviwer非常棒的远程连接软件,QQ什么的远程连接就别提了。。。有了它,在家加班再也不是梦想了!(这追求……) 注册账号登陆就可以免去忘了记密码,请别人帮忙的尴尬。 切记,设置电脑永不休眠。要不然还是要麻烦别人了。 Anaconda虽然可以远程服务器调试代码,但本地常备一个python环境调试代码也是必须的。 不想用,但必须用的聊天软件微信还不是因为生活所迫……有本事别装啊 😀<(_ _)>😀 TIM还有少量的QQ交流的需要,但是又不想要哪些花里胡哨的没用功能,那就选择TIM吧,它的共享文档还是一个能用的功能。当然,如果没有交流需要,还是不要安装了,共享文档找Google。 效率软件Flux虽然现在win10已经内置了护眼功能,但是我还是一直使用这款简洁的软件(直接开机自启就好了)。 百度网盘毕竟2T的存储空间,还是有很多人在使用的。如果嫌弃它上传/下载速度慢又不想充网费,那就DIY吧。BaiduPCS-Go(估计百度的程序员小哥哥假装自己没看见吧)。 Photoshop虽然不是专业人士,但是工作中遇到稍微处理一下图片的情景还不少,手边预备一个PS是不错的选择。 关于英语 Aboboo:如果你练习英语口语,这是一个不错的选择。 有道词典:如果你经常查看英文论文/文档,但是英语又不太好。网易有道的划词翻译还是有很大帮助的。 灵格斯:专业强大的英文词典。 文本编辑器任选一种或多种皆可。 Sublime:常用的文本编辑器,满足轻量级的代码查看需求,也有人将其自定义成轻量IDE,不能连接远程服务器是硬伤。 Atom:基于github社区的开源编辑器,可谓是含着金钥匙出生。可高度自定义(程序员的最爱),完全可以变成一个IDE…… Vs code:相比于它兄弟vs studio,这款代码查看软件还是可以考虑的。(不过我没考虑) Notepad++:相比于前面三位选手,Notepad++最主要的优势是容量小,启动快,速度快,不占内存,其他功能也不差的。麻雀虽小,balabala~ Everything电脑文件多而杂怎么办,windows 自带的搜索功能太慢怎么办?这款软件值得拥有。 PDF阅读器 Adobe reader:广大科研工作者的第一选择(我看很多老师们都用它……) SumatraPDF:一个广受好评的PDF阅读器。 Gaaiho Reader:一个功能齐全的阅读器。 Pdf element:好用的编辑功能,当初为了它的OCR功能而下载。 Foxit pdf reader:用过一段时间的轻量、快速的PDF阅读器,但是标注不是很方便。 Drawbroad:windows 下一个很不错的产品,漂亮也方便标注,但是……还挺贵的,全价67¥,不过有打折甚至免费的时候,看看你能不能遇到了。 Xodo:漂亮简洁的界面,运行快速,批注方便,而且免费。但是!它暂时不支持撤销操作,不支持中文…… Textstudio其实网页版的overleaf写论文已经很方便了。但是,遇到ddl,免费帐户还是有点吃力,可以在电脑上安装一个text studio,以备不时之需。 Markdown Typora: 专业的markdown编辑器,优点很多。昧着良心不列举了,虽然我此刻正在使用它记笔记。 Mark Text: 相比于Typora, 暗黑风格默认界面没有最上面的白色菜单栏,外观很不错。有一个斗图功能,如果是搞笑图片的爱好者,可能会对这个功能爱不释手。但是我没有发现打开历史文件的快捷方式,这一点稍有不便。 PicGo一款方便简洁的图传管理软件,支持多种图床,拖拽上传,自定义的图片链接直接放入粘贴板,直接粘贴即可。 TranslucentTB一块小巧的系统插件,几乎不占用系统资源,方便的实现任务栏的半透明或者透明化,露出漂亮的桌面背景。 Xmind画思维导图的软件,不想安装,也有网页版的百度脑图可以替代使用,百度为数不多的良心产品啊。 Mendeleywindow 平台常见的文献管理软件,虽然做的丑的一点,虽然会把你的文档在电脑里另外复制一份……但还是有一些用户的…… PE制作大白菜/老毛桃这两个软件任选其一即可(这名字谁起的啊……)。 开发环境 Pycharm: 配置导入,方便的代码跳转,自定义快捷键设定,还提供免费的远程服务器连接功能,还等什么啊?!真不明白用jupyter的人们是怎么写工程代码的…… Download jupyter:存在即合理,虽然jupyter notebook 在工程构建方面略差pycharm一筹,但由于其便捷性的特点,处理数据的时候非常方便,广受数据科学家的喜爱。它与pycharm一起可以构建出最便捷的开发环境。 Xshell:连接服务器利器,可以改变常用服务器配置文件的存储位置,防止重装系统后再配置一遍……都是泪啊 Xming:提供远程服务器的图形界面。 winSCP:可以获取服务器的目录,通过本地的文本编辑器打开服务器上的文件。 下载软件 迅雷极速版:下载速度尚可,重点是没有广告! IDM:下载速度很快,但是是收费软件。 uTorren:同样好用,但只有十五天试用期的下载软件。 电脑管理如果对于电脑很熟悉,可以忽略以下软件。 玩具大师(鲁大师):有硬件检测,驱动更新,电脑温度异常等等不太常用的功能,但保不准需要偶尔用一下…… 腾讯管家:可以方便地搜索一些国内的常见软件,管理开机时间等等。当然如果习惯自己配置电脑,也就不需要它了。 仅剩的娱乐 网易云音乐:不多说,要不是因为版权问题,它会是一家独大的音乐软件吧~ 当然不安装也有网页版可以使用。 Potpalyter:一款小巧强大的视频播放器。 尾声 上面列举了很多的软件,并且以后还会不定期的更新名单。 但其实,工具只是工具,它们能发挥出多大的生产力,最直接的影响因素还是用户本身。加油吧,皮卡丘~","categories":[{"name":"Operating-system","slug":"Operating-system","permalink":"https://imbowei.com/categories/Operating-system/"},{"name":"Win10","slug":"Operating-system/Win10","permalink":"https://imbowei.com/categories/Operating-system/Win10/"}],"tags":[{"name":"Flux","slug":"Flux","permalink":"https://imbowei.com/tags/Flux/"},{"name":"Shadowsocks","slug":"Shadowsocks","permalink":"https://imbowei.com/tags/Shadowsocks/"},{"name":"Pycharm","slug":"Pycharm","permalink":"https://imbowei.com/tags/Pycharm/"},{"name":"Teamviwer","slug":"Teamviwer","permalink":"https://imbowei.com/tags/Teamviwer/"},{"name":"Tpyora","slug":"Tpyora","permalink":"https://imbowei.com/tags/Tpyora/"}]},{"title":"双网卡配置:同时使用公司(学校/实验室)内网和外网","slug":"Dual-NIC-configuration","date":"2018-09-07T13:37:09.000Z","updated":"2019-09-25T06:19:57.349Z","comments":true,"path":"2018/09/07/Dual-NIC-configuration/","link":"","permalink":"https://imbowei.com/2018/09/07/Dual-NIC-configuration/","excerpt":"没有一个好用的网络根本是没有办法好好工作的呀。最近通过改变路由表、调整网卡优先级,实现了内外网络的同时使用,终于可以愉快的上网了。","text":"没有一个好用的网络根本是没有办法好好工作的呀。最近通过改变路由表、调整网卡优先级,实现了内外网络的同时使用,终于可以愉快的上网了。 why实验室的内网实在是太慢了……即使是查资料也会有令人不悦的卡顿,更别说下载大规模数据。然而,学校的无线网还是不错的。但是,用学校的无线网怎么用实验室的服务器呢? 开始折腾。 How首先,自购一块无线网卡。并确认其可以正常工作。 这个时候,我们其实已经可以通过临时禁用有线网络,来使用无线网络下载数据等等…… 但是,有线网络每次禁用启用都需要若干秒钟的时间,等待的滋味不好受呐。 改变路由表 快捷键win+R ,然后键入cmd回车。在cmd中键入命令route print 可以查看自己的当前路由表。 route delete #ip 命令可以删除当前的路由表。在执行route delete 0.0.0.0后可以彻底禁用有线网络。 接着要添加内网的ip地址,以及无线外网的ip地址。用 route add #ip命令。 总的来说,我们只需将上述三行代码写入一个.bat脚本中,以管理员权限运行就好了。比频繁的手动操作,等待网卡切换,节省很多时间。代码如下: 12345route delete 0.0.0.0route -p add 172.0.0.0 mask 255.0.0.0 172.31.202.1route add 0.0.0.0 mask 0.0.0.0 10.1.88.1 调整优先级完成上述部分,貌似大功告成了,内网和外网都可以使用了。但是,此时很多国内的网站速度会非常之慢,慢到没有朋友…… 这个时候就需要设置一下两块网卡的工作优先级。流程非常简单,如下图所示: 从控制面板打开网络连接设置; 右键无线网络图标,选’属性‘; 双击“IPV4”,选取”高级”; 将自动跃点数改为固定的 10,一路确定保存。 同理,可以将有线网卡的自动跃点数设置为 20。 两张网卡的自动跃点数越小表示优先级越高。 此时,我们就可以在实验室愉快的上网啦!","categories":[{"name":"Tool","slug":"Tool","permalink":"https://imbowei.com/categories/Tool/"},{"name":"Computer-network","slug":"Tool/Computer-network","permalink":"https://imbowei.com/categories/Tool/Computer-network/"}],"tags":[{"name":"Hop-number","slug":"Hop-number","permalink":"https://imbowei.com/tags/Hop-number/"},{"name":"Routing-table","slug":"Routing-table","permalink":"https://imbowei.com/tags/Routing-table/"}]},{"title":"算法的时间复杂度和空间复杂度","slug":"Summary-of-time-complexity-and-space-complexity","date":"2018-08-17T10:37:34.000Z","updated":"2019-04-22T08:30:39.163Z","comments":true,"path":"2018/08/17/Summary-of-time-complexity-and-space-complexity/","link":"","permalink":"https://imbowei.com/2018/08/17/Summary-of-time-complexity-and-space-complexity/","excerpt":"趁假期复习了算法基础的时间复杂度和空间复杂度,整理一遍。","text":"趁假期复习了算法基础的时间复杂度和空间复杂度,整理一遍。 算法的有效性要想理解时间复杂度和空间复杂度这两个概念,首先要明白算法的含义。所谓算法,是解决一类问题的通法,即一系列清晰无歧义的计算指令。 具体的,一个算法应该有以下五个方面的特性: 输入(Input):算法必须有输入量,用以刻画算法的初始条件(特殊情况也可以没有输入量,这时算法本身定义了初始状态); 输出(Output):算法应有一个或以上输出量,输出量是算法计算的结果。没有输出的算法毫无意义。 明确性(Definiteness):算法的描述必须无歧义,以保证算法的实际执行结果是精确地匹配要求或期望,通常要求实际运行结果是确定的。 有限性(Finiteness):算法必须在有限个步骤内完成任务。 有效性(Effectiveness):算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现(又称可行性)。 根据以上的定义,不难发现。每个算法只能解决具有特定特征的一类问题。然而,每个有固定输入输出的问题可以采取多种算法来决解。那么,要怎么来比较解决同一个问题的不同算法之间的优劣呢?这个时候,时间复杂度和空间复杂度就有了用武之地。 时间复杂度所谓时间复杂度就是从初始状态到达最终状态中间需要多少步! 算法的时间复杂度反映了程序执行时间随输入规模增长而增长的量级,在很大程度上能很好反映出算法的优劣与否。验证算法的时间复杂度,我们有以下两个方法。 事后统计一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。所以就有了事后统计的方法。计算算法的时间复杂度,往往是为了评测算法的性能,设计更好的算法。这就给事后统计的方法带来了两个弊端。 需要先实现算法设计,并至少运行一次。 统计算法时间容易受到计算机硬件、编程语言效率等环境因素影响。 事前分析由于事后统计的方法有上述的弊端,我们通常采取事先估计的方法来评价算法的时间复杂度。为了更好的比较不同算法在处理统一问题上的效率,通常从算法中选取一种对于所研究的问题(或算法类型)来说是基本操作的原操作,以该基本操作的重复执行的次数作为算法的时间量度,记为T(n)。在这里,n为输入问题的规模。对于同一个问题来说,他的输入规模越大,往往时间复杂度也就越大。关于输入问题规模n,有辅助函数f(n),来统计算法基本操作的频度。因此,算法的时间复杂度往往记为$T(n)=O(f(n))$。 为了简便,我们一般在计算时间复杂度往往选取最简单的f(n)表示。例如:$O(2n^2+n+1) = O (3n^2+n+3) = O(7n^2+n) = O(n_2)$ ,一般都只用$O(n_2)$表示就可以了。也就是说,两个算法的时间频度不一样,但很有可能拥有相同的时间复杂度。例如:$T(n)=n^2+3n+4$ 与 $T(n)=4n^2+2n+1$它们的频度不同,但时间复杂度相同,都为$O(n^2)$。 常见的算法时间复杂度由小到大依次为: $O(1)<O(log_2(n))<O(n)<O(nlog_2(n))<O(n^2)<O(n^3)<…<O(n!)$ 下面的图片直观的表示他们之间复杂度关系。 事前估计主要影响因素 依据算法选用何种策略 问题的规模 书写语言的程序(语言的级别越高,执行效率就越低) 编写程序所产生的机器代码的质量 机器执行指令的速度 时间复杂度的分类 最坏时间复杂度:输入数据状态最不理想情况下的时间复杂度,也就是算法时间复杂度的上界。若没有特别声明,时间复杂度就是指最坏时间复杂度。 平均时间复杂度:在所有可能的输入实例均以等概率出现的情况下,算法的期望时间复杂度。 最好时间复杂度:输入数据状态最理想情况下的时间复杂度。 时间复杂度预估步骤 找出基本语句:算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体,被称作原操作。 计算基本语句的执行次数的数量级:只需计算基本语句执行次数的数量级,这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略所有低次幂和最高次幂的系数。这样能够简化算法分析,并且使注意力集中在最重要的一点上:增长率。 用O()表示算法的时间性能:将基本语句执行次数的数量级放入O()中。 时间复杂度分析技巧 简单语句:程序的输入输出、赋值等语句都近似认为需要$O(1)$时间。 顺序结构:需要依次执行一系列语句所用的时间可采用O()的”求和法则”, 选择结构:如if语句,它的主要时间耗费是在执行then字句或else字句所用的时间,需注意的是检验条件也需要$O(1)$时间。 循环结构:循环语句的运行时间主要体现在多次迭代中执行循环体以及检验循环条件的时间耗费,一般可用O()的”乘法法则”。 复杂算法:将其分成几个容易估算的部分,然后利用求和法则和乘法法则计算整个算法的时间复杂度。 其他准则 若$g(n)=O(f(n))$,则$O(f(n))+ O(g(n))= O(f(n))$ $O(Cf(n)) = O(f(n))$ , 其中C是一个正常数。 乘法法则: 是指若算法的2个部分时间复杂度分别为 $T_1(n)=O(f(n))$和 $T_2(n)=O(g(n))$,则 $T_1 T_2=O(f(n) g(n))$ 求和法则:是指若算法的2个部分时间复杂度分别为 $T_1(n)=O(f(n))$ 和 $T_2(n)=O(g(n))$,则 $T_1(n)+T_2(n)=O(max(f(n), g(n)))$特别地,若$T_1(m)=O(f(m))$, $T_2(n)=O(g(n))$,则 $T_1(m)+T_2(n)=O(f(m)+g(n))$ 实际演练 三个简单语句,$T(n)=O(1)$。123Temp=i;i=j;j=temp; 如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是$O(1)$。 因为 $O(n^2+1)=n^2$ ,忽略低阶项, 所以$T(n)=O(n^2)$;1234sum=0; (一次)for(i=1;i<=n;i++) for(j=1;j<=n;j++) sum++; (n^2次) 一般情况下,循环语句只需考虑循环体中语句的执行次数,忽略该语句中步长加1、终值判别、控制转移等成分,当有若干个循环语句嵌套时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。 语句①的频度是$n-1$,语句②的频度是$(n-1)*(2n+1)=2n^2-n-1$(乘法法则), 所以$f(n)=2n^2-n-1+(n-1)=2n^2-2$(加法法则), 最终 $O(2n^2-2)=n^2 $ , 即该程序的时间复杂度$T(n)=O(n^2)$。 123456for (i=1;i<n;i++) { y=y+1; ① for (j=0;j<=(2*n);j++) x++; ② } 语句①的频度:2;语句②的频度一般不考虑;语句③的频度:n-1;语句④的频度:n-1;语句⑤的频度:n-1;$T(n)=2+3(n-1)=3n-1=O(n)$。 12345678a=0; ①b=1; ①for (i=1;i<=n;i++) ②{ s=a+b; ③ b=a; ④ a=s; ⑤} 语句①的频度是1;设语句②的频度是f(n), 则:$f(n)<=log_2(n)$。取最大值$f(n)=log_2(n)$,$T(n)=O(log_(n))$ 123i=1; ①while (i<=n) i=i*2; $T(n)=O((n)(n+1)(n-1)/6)=O(n^3)$ 12345678for(i=0;i<n;i++) { for(j=0;j<i;j++) { for(k=0;k<j;k++) x=x+2; ① } } 空间复杂度设计算法的时候,我们还会关注空间复杂度,空间复杂度是算法在运行过程中临时占用的存储空间大小的度量, 同样是关于问题规模n的函数。表示为了支持你的计算所必需存储的状态最多有多少。但根本上,算法的时间运行效率才是最重要的。只要算法占用的存储空间不要达到计算机无法接受的程度即可。所以,常常通过牺牲空间复杂度来换取算法更加高效的运行时间效率。 算法在计算机存储器上占用的空间包括三个部分。 输入输出算法的输入输出数据所占用的存储空间是由要解决的问题决定的,是通过参数表由调用函数传递而来的,它不会随算法的不同而改变。这不是我们需要考虑的部分。 算法本身存储算法本身所占用的存储空间与算法书写的长短成正比,要压缩这部分存储空间,就必须编写出较短的算法。然而,算法想要实际应用需要根据需求采取不同的编程语言来实现,不同编程语言实现的代码长短差别很大,然而存储空间都在可接受范围之内(通常不同编程语言的效率更受关注)。 运行临时占用根据算法在运行过程中临时占用存储空间的不同,可以将算法分为两类。 原地算法(in-place algorithm):只需要占用少量的临时工作单元,而且 不随问题规模的大小而改变 ,我们称这种算法是“就地”进行的,是节省存储的算法, 空间复杂度为O(1) 。 非原地算法(not-in-place):需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元。算法临时占用空间是考虑算法空间复杂度时主要考虑的部分。相比于随着问题输入规模扩大而扩大的非原地算法,原地算法是更加简洁高效的算法(仅考虑空间复杂度时)。 实际例子假设我们想要将拥有n个项目的数组反过来。一个最简单作这件事的方式是这样:12345function reverse(a[0..n]) allocate b[0..n] for i from 0 to n b[n - i] = a[i] return b 不幸地,这样需要$O(n)$的空间来创建b数组,且配置存储器通常是一件缓慢的运算。如果我们不再需要a,我们可使用这个原地算法,用它自己反转的内容来覆盖掉:123function reverse-in-place(a[0..n]) for i from 0 to floor(n/2) swap(a[i], a[n-i]) 排序算法分析了解算法的时间复杂度和空间复杂度之后,再看一些常用算法总结的时候就不会再向原来一样有雾里探花之感了。 参考文献算法的时间复杂度和空间复杂度-总结原地算法","categories":[{"name":"Algorithm","slug":"Algorithm","permalink":"https://imbowei.com/categories/Algorithm/"}],"tags":[{"name":"Time-complexity","slug":"Time-complexity","permalink":"https://imbowei.com/tags/Time-complexity/"},{"name":"Space-complexity","slug":"Space-complexity","permalink":"https://imbowei.com/tags/Space-complexity/"}]},{"title":"AI发电厂——数据标注公司(国内数据标注公司服务调研)","slug":"Investigate-domestic-data-labeling-companies","date":"2018-08-07T11:07:28.000Z","updated":"2018-09-04T10:19:20.000Z","comments":true,"path":"2018/08/07/Investigate-domestic-data-labeling-companies/","link":"","permalink":"https://imbowei.com/2018/08/07/Investigate-domestic-data-labeling-companies/","excerpt":"众所周知,深度学习需要大量的标记数据和高效的运算来做支撑。计算资源只要从黄老板的公司订购就可以了,但大规模的高质量有标记数据却不是那么容易获得,让科研人员头疼不已。应用时代而生的就是一大批数据众包公司和平台。正好借着一个数据众包任务,对于国内的数据标注公司服务有了更深一步的了解。","text":"众所周知,深度学习需要大量的标记数据和高效的运算来做支撑。计算资源只要从黄老板的公司订购就可以了,但大规模的高质量有标记数据却不是那么容易获得,让科研人员头疼不已。应用时代而生的就是一大批数据众包公司和平台。正好借着一个数据众包任务,对于国内的数据标注公司服务有了更深一步的了解。 AI的老师:画框的这些人 伴随着AI兴起的最关键的技术莫过于深度学习,作为深度学习的基础,神经网络是一种以输入为导向的算法,其结果的准确性取决于接近“无穷”量级的数据。所以摒除那些复杂的中间环节,深度学习最关键的就是需要大量的数据训练,这也是为什么在互联网大数据的时代,AI可以崛起。而在数据训练之前,又必须先对大量的数据进行标注,作为机器学习的先导经验。 因此,催生了大量数据标注公司的诞生。 什么是数据标注要理解数据标注,得先理解AI其实是部分替代人的认知功能。回想一下我们是如何学习的,例如我们学习认识苹果,那么就需要有人拿着一个苹果到你面前告诉你,这是一个苹果。然后以后你遇到了苹果,你才知道这玩意儿叫做“苹果”。类比机器学习,我们要教他认识一个苹果,你直接给它一张苹果的图片,它是完全不知道这是个啥玩意的。我们得先有苹果的图片,上面标注着“苹果”两个字,然后机器通过学习了大量的图片中的特征,这时候再给机器任意一张苹果的图片,它就能认出来了。 根据应用场景的不同,数据标注有许多类型。大体上分为图像、语音、自然语言三大类。其中由于图像研究领域的水文热潮,图像标注的任务也尤为众多。。。无人驾驶、人脸识别、物体检测……语音和语言相对来说,数据标注难度更大一点。价格也相对高昂一些。 在进行数据标注之前,我们首先要对数据进行清洗,得到符合我们要求的数据。数据的清洗包括去除无效的数据、整理成规整的格式等等。具体的数据要求可以和算法人员确认。 众包标注的困难众包标注由于是非专业标注,自然会遇到很多问题。这困难主要由以下三个方面组成: 标注者的水平由于标注者是众包标注,因此其标注者的水平也参差不齐,其背景知识和行为习惯可能有较大的差异。这就相当于是给若干个已训练好的模型来做预测一样,其不同的模型有不同的输出结果。那么这种情况下,基本上使用多数投票的方法来解决。 评价困难标注的内容可以分为两类,一类是有明确标签的,就好比是试卷里的客观题一样,尽管各个标注都不同,但是还是在有限集合内的。另一类是开放式回答,这种标注如同试卷里的主观题一样,可能会有无限种可能的结果。甚至是截然相反的结果,比如什么是美,什么是丑,每个人的评价标准是不同的。我们本次想要的数据众包也是这个类型的。 标注稀疏性如果一个需要标注的训练集中的数据本身就比较稀疏,而我们又需要把它们分割成一个个小块,这就有可能造成数据稀疏。比如,我们要进行鸟类图片标注,如果本身鸟类种类很多,而分给每个人的鸟的种类也很多的话,由于每个人认识的鸟的种类是不多的,因此可能存在每个人的标注都会有很高的错误率。这时候我们可能就需要让标注者之间有重叠的部分,然后使用多数表决来解决。 数据众包公司调研由于我们需要众包的数据是中文数据,所以只关心国内的一些数据众包公司。国外的Amazon Mechanical Turk、CrowdFlower、Mighty AI等公司不在考察范围之内。 据悉,在国内的数据标注行业实行这样一套分工流程:上游的科技巨头把任务交给中游的数据标注公司,再由中游众包给下游的小公司、小作坊,有的小作坊还会进一步众包给“散兵游勇”,比如学生或家庭主妇。这条产业链上,分包现象越严重,最终落到最底层的数据服务公司的价格就越低,一层层的“数据黄牛”压缩了利润空间,所以一些任务经过数手转包,酬劳已低得惊人。目前的数据标注工作主要是集中在河北、河南、山东、山西等劳动力密集的地区,这样的选址也因为能够以更加低廉的劳动力成本去完成大量的数据标注工作。 下面是我对国内的数据众包公司做的一些调研(按照我搜索得知该公司的顺序排序)。不知道是否是我们的标注任务太难的缘故,绝大多数公司没有任何反馈。 1.百度数据众包、百度云众包百度不愧是靠PC端的网页搜索起家的,其前端技术还是不错,网站做的还是比较精致的。但是我提出了数据标注任务之后,贵司的这个相应效率可就有点搞笑了。完全没有反应…… 2.泛函科技第二天下午有反馈, 0.35元/条, 后来涨价到1.5元/条……而且拿走我的数据,试标结果都没有反馈。但是客户经理态度还比较好,最后给出这样一个方案“您确定一个期望的价格,我们也可以把他发到我们的平台上,我们抽取一定佣金后,按您意愿的价格发布任务。看是否有用户愿意标注,这样的工期我们不敢保证。”,我是不敢采取的,23333。 3.京东众智数据标注的需求申请是真难用!京东公司就没有一个会前端的人嘛?但是,京东的效率很高,反应很快(第二天就有回复),对接服务还比较周到细致,测评试标注有标注结果反馈,且效果尚可。最后谈妥的价格是0.55元/条,含6个点的税,增值税普通发票。关键是,京东平台只接受5W元以上的订单。这一点为什么不在官网说明?浪费我那么多的联系时间。 4.数据堂联系之后没有反馈 5.龙猫数据联系之后没有反馈 6.阿里众包联系之后没有反馈 7.星辰数据网页做的很好看,但是联系之后没有反馈 8.爱数智慧第二天下午有反应,但进展比较慢。问我要走了样例数据试标注却没有结果反馈。难道不需要顾客审查标注质量么?最后报出的定价是0.45元/条,但是谁知道他们标注的质量呢? 9.倍赛公司联系之后没有反馈 10.tagger联系之后没有反馈 总的来说,我眼中国内最靠谱的数据标注公司是京东众智。不论是客户经理的对接工作,还是数据的试标注反馈,完成的都比较高效和到位。但也有一个致命的缺陷,它们只接受5W元以上的标注任务订单,,,这就基本把高校的科研组统统拒之门外了。另外,泛函科技和爱数智慧的服务以及价格尚可,只是没有京东众志应答迅速,没有试标注的结果反馈。至于其他一些公司,统统没有反馈,令人失望。 PS:上文中,BA已经出镜,不给T家一个机会貌似不太公平。那就给他们一个亮相机会吧。 参考文献众包数据标注中的隐类别分析谈谈人工智能数据标注那些事儿数据标注员,最后一批被AI取代的人","categories":[{"name":"Machine-learning","slug":"Machine-learning","permalink":"https://imbowei.com/categories/Machine-learning/"},{"name":"Data-labeling","slug":"Machine-learning/Data-labeling","permalink":"https://imbowei.com/categories/Machine-learning/Data-labeling/"}],"tags":[{"name":"Machine-learning","slug":"Machine-learning","permalink":"https://imbowei.com/tags/Machine-learning/"},{"name":"Data-labeling","slug":"Data-labeling","permalink":"https://imbowei.com/tags/Data-labeling/"},{"name":"Crowdsourcing","slug":"Crowdsourcing","permalink":"https://imbowei.com/tags/Crowdsourcing/"}]},{"title":"用Github和Coding双线绑定自定义域名","slug":"Github-and-Coding-bulid-blog","date":"2018-07-29T09:26:57.000Z","updated":"2018-10-29T02:21:36.000Z","comments":true,"path":"2018/07/29/Github-and-Coding-bulid-blog/","link":"","permalink":"https://imbowei.com/2018/07/29/Github-and-Coding-bulid-blog/","excerpt":"本来博客已经搭建好了,可是总觉得用Github一个二级域名怪怪的,非要折腾自己来绑定自己的域名,并申请SSL(就是喜欢看那个小绿锁!)前前后后花了不少时间,走了不少弯路,将踩过的坑记录下来。","text":"本来博客已经搭建好了,可是总觉得用Github一个二级域名怪怪的,非要折腾自己来绑定自己的域名,并申请SSL(就是喜欢看那个小绿锁!)前前后后花了不少时间,走了不少弯路,将踩过的坑记录下来。 域名设计原则域名的设置应该根据什么原则呢?参考域名价值评估,我们可以根据如下因素来 域名的长短:1位:10万,2位:5万,3位:1万,4位:5000,5位以上1000,6位以上500域名的组成结构:纯字母的*2,数字与字母杂的*1,中划线/3域名的组合方式:单词*3,纯数及单词组合*2,拼音及其它*1域名的形式分类:行业词*3,通用词*2,创单词*1域名的商业价值:搜索数量:1000以下/3,1000到1万/2,1万到10万*1,10万到100万*2,100万*3,100万以后搜索数量多一个0就*3的倍数,百度以100万,google以300万为参数。域名的后缀:com结尾的大于net,net结尾的大约cn的,cn结尾的大于http://com.cn(org、gov排除例外一般不属于商业险域名),http://com.cn大于其他尾缀域名域名的历史记录:自己衡量。域名记忆性标准:跟实际生活中某些词汇重叠,跟语言、语音发声重叠适用性较强域名的合法性标准:域名是否符合法律,是否涉及到知识产品争议方面。域名的潜在商业价值:域名所涉及的行业规模及互联网的相关性。 域名服务商选择心中构思好了自己的域名后,就可以着手选择一个靠谱的域名购买商。如果懒得备案,那就将我们的目光锁定在国外。参考分析域名购买商,2018最佳国外域名注册商,不需要备案这两篇文章,我将目光初步锁定在namesilo和namecheap两家口碑较好、服务稳定、价格尚可的服务商身上。 这里有两个网站来查询你所想好的域名目前的状况,以及价格对比。查域名是否被注册(中文站),domcomp——国外多家域名购买网站的价格对比如果准备购买,从domcomp内点击对应的域名服务商还有额外的优惠。 我最终选择的是Namesilo,因为更便宜……口碑也还不错。namesilo传送门 Namesilo还免费提供隐私服务(即不公开域名持有者的信息)。对了, Namesilo 支持支付宝付款。从传送门进去,注册新用户,选好合适的域名后填入下面两个优惠码其中任意一个都可以优惠一美元。(截止日期:2020年12月31日) NameSilo 新用户购物优惠码一 imbowei NameSilo 新用户购物优惠码二 miaomiao 域名购买及配置namesilo购买域名之前记得填写优惠码,并且提交(提交按钮一直都是灰色的!),提交后可以便宜一美元。经过以上步骤,就可以最终购买域名了。 购买得到域名,要紧接着配置。新域名默认有四条停靠的广告记录,不要犹豫,直接全部删除!然后我选用了DNSpod的域名解析服务。中文网站,简单易懂。它有两个默认的解析记录,我们直接添加到namesilo购买的域名中,如下图所示。(注意:不需要第三条记录。)这样就可以放心关闭Namesilo的网站了。 Coding配置如果Coding和GitHub的用户名和注册邮箱完全一样,就不用再次配置Git,只要找到.ssh文件夹下对应的id_ras.pub文件,再去coding以相同的方式设置一次公钥即可。 如果用户名或者注册邮箱并不是完全一致,那么按照如下步骤在进行一遍配置。注意,需要先将配置GitHub时候生成的公钥密钥文件备份,或者生成Coding配置的时候改掉生成的文件名。 git config --global user.name "OnlyChristmas" 设置Coding用户名 git config --global user.email "OnlyChristmas@hh.com"设置注册Coding邮箱 ssh-keygen -t rsa "OnlyChristmas@hh.com" 在bash中执行命令,连着三个回车(不需要密码)。 生成两个文件 id_rsa 和 id_rsa.pub ,而 id_rsa 是密钥,id_rsa.pub 就是公钥。生成文件目录`C:/用户/你的用户名/ 输入 ssh -T git@coding.net 如果出现如下字样不要慌张,因为可能是本地网络禁止了22端口,我们换个端口就好。 ssh: connect to host coding.net port 22: Connection refused 再次输入 ssh -T -p 443 git@git-ssh.coding.net 出现如下字样,说明配置coding成功。 The authenticity of host …………………Coding 提示: Hello OnlyChristmas, You’ve connected to Coding.net via SSH. This is a personal key.OnlyChristmas,你好,你已经通过 SSH 协议认证 Coding.net 服务,这是一个个人公钥 将博客托管到Coding和GitHub首先,在本地博客根目录/source/下建立一个名为 CNAME的文件,里面写填入你购买的域名。例如imbowei.com, 不需要任何的其他字符,例如“www”,”https”之类。 在本地博客文件夹下的srouce文件夹下新建Staticfile文件,接下来就可以同时向coding和GitHub上传博客了。 向coding提交代码遇到了如下问题怎么办? remote: Coding 提示: Authentication failed! 认证失败,请确认您输入了正确的账号密码 我是因为配置出现了问题,改成如下样式,即可同时上传github和coding123456deploy: type: git repo: github: https://github.com/OnlyChristmas/OnlyChristmas.github.io.git coding: git@git.coding.net:OnlyChristmas/OnlyChristmas.git branch: master 代码上传之后,在coding项目的代码/pages 服务中选取master分支,开启静态pages服务,即可访问coding的主页了。 Github and Coding 双线部署并申请SSL现在Coding pages和Github pages 已经都可以使用了。那么我们现在要做的就是设置他们同时解析到我们刚才购买的域名imbowei.com,实现双线访问。这里的坑比较多。首先要在DNSpod先设置解析Coding,并且在Coding项目的pages界面申请SSL证书。申请配置如下图所示。否则Let’s Encrypt主机根据域名解析记录验证域名所有权时,会定位到GitHub Page的主机上,导致Let’s EncryptSSL证书申请失败。 然后在DNSpod再配置Github pages的解析,并在Github博客项目的设置中绑定主页。 然而,Github pages 出现了如下的错误信息, Domain’s DNS record could not be retrieved.不要着急,这是因为github pages的自定义HTTPS请求没有配置成功(2018年5月1日新推出的良心服务),在刚才的DNSpod中添加一条A记录即可,其中IP指向在下面的地址中任选其一即可(一项不行,就换另外一个)1234185.199.108.153185.199.109.153185.199.110.153185.199.111.153 Gituhb pages的配置成功界面如下所示。 最终的DNSpod解析配置如下图所示。 去除Coding的广告……配置好之后很开心,然而发现,Coding会自动给你的博客加一个滞留好几秒钟的跳转页面,感觉非常非常的不好。还好除了升级为它的黄金会员之外还有其他解决方法。 只要在博客主页为它打一点点广告就好了(要两个工作日才会通过!)……毕竟托管在上面还是很方便的。12<div>Hosted by <a href="https://pages.coding.me" style="font-weight: bold">Coding Pages</a></div> 对于Next主题来说,在themes/next/layout/_partials/footer.swig的文件末尾加入上述代码就可以把Coding要求的小广告加入到主页的页脚位置。 但是Coding这种强制要求真的很烦人,一点互联网精神都没有!货比货,感觉Coding距离Github还差几个光年吧。既然打广告,也顺便带上良心的Github吧! 资源配置现在部署好了HTTPS,那为什么还是没有出现小绿锁?刷新页面出现的小绿锁一闪而过,让我们空欢喜一场!因为网站没有全站HTTPS,也就是说,我们引用了http的资源,要将对应资源全部换成HTTPS才能出现小绿锁。 怎么知道自己什么还没有换成HTTPS资源?很简单,F12打开调式界面就可以发现警告信息。例如我的站点就是因为加载了一个自定义的鼠标图片,如鼠标图片引用了HTTP的资源,将该段代码注释掉,或者换一个HTTPS的资源连接即可。 然后,就有心心念的小绿锁了! 另外由于主页地址的改变,我还更新了如下资源配置: gitment评论系统的Authorization callback URL主页设置为自定义域名。 SEO相关设置 在 站点配置文件 中更改默认站点,使得文档末尾的copyright链接生成正确。 还在阿里云申请了一个为期一年的SSL免费证书,用于一些资源网站的验证使用。","categories":[{"name":"blog","slug":"blog","permalink":"https://imbowei.com/categories/blog/"}],"tags":[{"name":"Github-pages","slug":"Github-pages","permalink":"https://imbowei.com/tags/Github-pages/"},{"name":"Coding-pages","slug":"Coding-pages","permalink":"https://imbowei.com/tags/Coding-pages/"},{"name":"DNSpod","slug":"DNSpod","permalink":"https://imbowei.com/tags/DNSpod/"},{"name":"SSL","slug":"SSL","permalink":"https://imbowei.com/tags/SSL/"},{"name":"Domain","slug":"Domain","permalink":"https://imbowei.com/tags/Domain/"}]},{"title":"Linux服务器命令行上传数据到百度云盘","slug":"linux-uploading-baiduyunpan","date":"2018-07-25T23:25:35.000Z","updated":"2018-09-04T10:19:50.000Z","comments":true,"path":"2018/07/26/linux-uploading-baiduyunpan/","link":"","permalink":"https://imbowei.com/2018/07/26/linux-uploading-baiduyunpan/","excerpt":"每次想把服务器上的数据上传到百度云盘都要先下载到本地,然后再上传百度云。这一点都不优雅,既浪费时间,还占用电脑本来的带宽。如果Linux命令行能够直接上传百度云盘岂不美哉?说干就干,磨刀不误砍柴工!","text":"每次想把服务器上的数据上传到百度云盘都要先下载到本地,然后再上传百度云。这一点都不优雅,既浪费时间,还占用电脑本来的带宽。如果Linux命令行能够直接上传百度云盘岂不美哉?说干就干,磨刀不误砍柴工! 准备 CentOS Linux, python3 配置环境 pip install bypy --user 配置 输入bypy info,得到如下显示。 12345Please visit:https://openapi.baidu.com/oauth/2.0/authorize?client_id=q8WE4EpCsau1oS0MplgMKNBn&response_type=code&redirect_uri=oob&scope=basic+netdiskAnd authorize this appPaste the Authorization Code here within 10 minutes.Press [Enter] when you are done 访问该链接,获得授权码,复制回来。确认。得到类似信息即配置成功。 12Quota: 2.008TBUsed: 1.272TB 使用再也不用把一些实验结果保存到本地,从实验室服务器折腾到本地再进行上传。写两条命令就可以继续干活了,感觉真好!下面是一些常用命令 12345bypy list # 显示文档bypy upload filename -v # 上传某文件,显示进度bypy -c # 取消令牌文件。一段时间后要重新授权bypy downdir filename # 下载bypy compare # 比较本地目录和网盘目录 执行上传命令之后有如下的显示,说明正在上传 ‘Wiki50.tar.gz’ >>==> ‘/apps/bypy/Wiki50.tar.gz’ OK.[=___] 9% (20.0MB/214.1MB) ETA: 6m52s (481kB/s, 42s gone) ‘Wiki50.tar.gz’ >>==> ‘/apps/bypy/Wiki50.tar.gz’ OK.[===_] 18% (40.0MB/214.1MB) ETA: 6m10s (481kB/s, 1m25s gone) ‘Wiki50.tar.gz’ >>==> ‘/apps/bypy/Wiki50.tar.gz’ OK. 参考文献Linux命令行上传文件到百度网盘","categories":[{"name":"Linux","slug":"Linux","permalink":"https://imbowei.com/categories/Linux/"}],"tags":[{"name":"Shell","slug":"Shell","permalink":"https://imbowei.com/tags/Shell/"},{"name":"Bypy","slug":"Bypy","permalink":"https://imbowei.com/tags/Bypy/"}]},{"title":"wikipedia 训练繁(简)体中文 embedding(word2vec)模型","slug":"wikipedia-train-traditional-chinese-embedding(word2vec)model","date":"2018-07-22T14:52:39.000Z","updated":"2018-09-25T08:53:00.000Z","comments":true,"path":"2018/07/22/wikipedia-train-traditional-chinese-embedding(word2vec)model/","link":"","permalink":"https://imbowei.com/2018/07/22/wikipedia-train-traditional-chinese-embedding(word2vec)model/","excerpt":"由于课题任务需要一个繁体中文的word3vec, 折腾经过记录在此。希望以后少掉几个坑。训练好的embedding放在网盘中, 密码:2um0后来又按照这个方法训练了简体中文维度分别为50、100、200、300的embedding,一并放出来网盘链接 密码:751d","text":"由于课题任务需要一个繁体中文的word3vec, 折腾经过记录在此。希望以后少掉几个坑。训练好的embedding放在网盘中, 密码:2um0后来又按照这个方法训练了简体中文维度分别为50、100、200、300的embedding,一并放出来网盘链接 密码:751d get wiki最新的wiki data下载地址,目前有1.6G大小。 里面的内容以XML格式保存。节点信息如下:12345678<page> <title></title> <id></id> <timestamp></timestamp> <username></username> <comment></comment> <text xml:space="preserve"></text></page> 初步处理我顺手直接解压真的too young。为了节省时间,免去自己写代码处理Wiki的烦恼,Wikipedia Extractor先初步处理。(服务器非root用户,安装命令加上--user) 1234git clone https://github.com/attardi/wikiextractor.git wikiextractorcd wikiextractorpython setup.py install --userpython WikiExtractor.py -b 1024M -o extracted zhwiki-latest-pages-articles.xml.bz2 执行过程如下,可以看到一共处理了1012693篇文章,输出如下所示: INFO: 6205533 手語新聞INFO: 6205536 班傑明·古根海姆INFO: 6205549 同意INFO: 6205556 2018年荷蘭網路監控法公民投票INFO: 6205594 李儒新INFO: 6205610 深圳信息职业技术学院INFO: 6205626 停下來等著你 (2018年電視劇)INFO: 6205642 簡單矩陣的快速演算法設計INFO: 6205644 斯義桂INFO: 6205646 焦耳效应INFO: 6205648 1925年世界大賽INFO: 6205653 True (方力申專輯)INFO: 6205657 华睿2号INFO: 6205664 河內郡 (大阪府)INFO: 6205691 京都寺町三条商店街的福爾摩斯INFO: 6205675 莫莉·比什死亡事件INFO: 6205703 都筑郡INFO: 6205701 皇座法庭所屬分庭庭長INFO: 6205709 冬瓜餅INFO: 6205710 吸血鬼莫比亞斯INFO: 6205712 淘綾郡INFO: 6205714 明石香織INFO: Finished 71-process extraction of 1012693 articles in 1114.1s (909.0 art/s) 通过以上抽取后得到两个文件wiki_00和wiki_01。里面的格式类似下面123<doc id="5323477" url="https://zh.wikipedia.org/wiki?curid=5323477" title="結構與能動性">文章内容</doc> 在上面的基础上,我们在去掉一些不需要的特殊符号。12345678910111213141516import reimport sysimport codecsdef filte(input_file): p5 = re.compile('<doc (.*)>') p6 = re.compile('</doc>') outfile = codecs.open('std_' + input_file, 'w', 'utf-8') with codecs.open(input_file, 'r', 'utf-8') as myfile: for line in myfile: line = p5.sub('', line) line = p6.sub('', line) outfile.write(line) outfile.close()if __name__ == '__main__':filte(input_file) input_file = sys.argv[1] 简体转繁体首先安装opencc-python网上一大堆教程,全是深坑!其实直接按照代码仓库作者的方法安装就好了。123git clone https://github.com/yichen0831/opencc-python.gitcd opencc-pythonpython setup.py install --user 但是,如果追求效率,可以安装opencc C++ 版本,python代码的效率堪忧。 看文档不难发现,繁体字也分为香港区和台湾省,要用怎么样的转换看具体需求就好12345678910from opencc import OpenCCopencc = OpenCC('s2hk')for filename in ['wiki_01','wiki_00']:truewith open('std_'+filename,'r',encoding='utf-8') as fin, open('hk_'+filename,'w',encoding='utf-8') as fou:truetruefor index , line in enumerate(fin.readlines()):truetruetruehk = opencc.convert(line) if index % 10000 == 0:truetruetruetrueprint(index,hk)truetruetruefou.write(hk) 得到了两个文件分别大小为 1024M 和154M jieba Segment先把两个wiki文件合并cat hk_wiki_00 hk_wiki_01 > hk_wiki 1python -m jieba -d \" \" ./hk_wiki > ./SegHk_wiki train word2vec运行下面写好的脚本,1234567891011121314151617# -*- coding: utf-8 -*-from gensim.models import word2vecfrom gensim.models import KeyedVectorsimport loggingimport osif not os.path.exists('./word2vec_tradiCN/'):trueos.makedirs('./word2vec_tradiCN/')logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)sentences = word2vec.LineSentence('./SegHk_wiki')for number in [50,100,200,300]:truemodel = word2vec.Word2Vec(sentences,size=number,window=5,min_count=5,workers=20)true# min-count 表示设置最低频率,默认为5,如果一个词语在文档中出现的次数小于该阈值,那么该词就会被舍弃; size代表词词向量的维度true# 为了后续建模读取vector方便,我们的保存格式应该和glove vector 保持一致truemodel.wv.save_word2vec_format('./word2vec_tradiCN/Wiki'+str(number)+'.txt', binary=False) 然而出现了Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so.这个错误运行conda install nomkl安装nomkl,这是anaconda的问题。 test word2vec如果用python2,运行下面的测试脚本可能会出现如下错误KeyError: "word '\\xe7\\xb8\\xbd\\xe7\\xb5\\xb1' not in vocabulary"这个是python2对于中文的支持不太友好造成的,用python3即可表现正常。123456# -*- coding: utf-8 -*-from gensim.models.keyedvectors import KeyedVectorsfor number in [50,100,200,300]: wv = KeyedVectors.load_word2vec_format('./word2vec_tradiCN/Wiki'+ str(number)+'.txt', binary=False) print(number, wv.similarity('總統','民國')) #两个词的相关性 print(number, wv.most_similar(['倫敦','中國'],['北京']),'\\n\\n') # 北京is to中国 as 伦敦is to? 注意,繁体中文,测试的时候也要用繁体的 这里直接测试了四组不同大小的embedding,可以对比效果。以这个简单的测试来说,200d embedding效果比较好。 当然,在实际中,效果怎么样,还是要实际测试。 50 0.0890698850 [(‘美國’, 0.8497380614280701), (‘英國’, 0.8156374096870422), (‘荷蘭’, 0.7635571956634521), (‘加拿大’, 0.7618951201438904), (‘蘇格蘭’, 0.7564111948013306), (‘法國’, 0.7498287558555603), (‘冰島’, 0.7447660565376282), (‘愛爾蘭’, 0.7290477752685547), (‘德國’, 0.7261558175086975), (‘哥倫比亞’, 0.715803861618042)] 100 0.0021609096100 [(‘英國’, 0.7518529891967773), (‘美國’, 0.716768741607666), (‘蘇格蘭’, 0.706271767616272), (‘德國’, 0.6398693323135376), (‘法國’, 0.6289862394332886), (‘愛爾蘭’, 0.6286278963088989), (‘荷蘭’, 0.6277433633804321), (‘英格蘭’, 0.625410795211792), (‘加拿大’, 0.6076068878173828), (‘威爾斯’, 0.6075741052627563)] 200 0.044366393200 [(‘英國’, 0.6959728598594666), (‘蘇格蘭’, 0.6404226422309875), (‘美國’, 0.6401909589767456), (‘英格蘭’, 0.6158463358879089), (‘愛爾蘭’, 0.5740842223167419), (‘德國’, 0.5558757781982422), (‘威爾斯’, 0.5539498925209045), (‘法國’, 0.5375431776046753), (‘荷蘭’, 0.5276069641113281), (‘威爾士’, 0.5051602721214294)] 300 0.034565542300 [(‘英國’, 0.6512337923049927), (‘蘇格蘭’, 0.5884094834327698), (‘英格蘭’, 0.5666802525520325), (‘美國’, 0.5420516729354858), (‘愛爾蘭’, 0.5202239751815796), (‘威爾斯’, 0.48060378432273865), (‘荷蘭’, 0.4763559103012085), (‘德國’, 0.4744102358818054), (‘法國’, 0.4675533175468445), (‘北愛爾蘭’, 0.46320733428001404)] 网盘链接训练好的四个embedding包含892594个词,都放到了网盘中,可以按需下载。 密码:2um0 参考文献word2vec实战:获取和预处理中文维基百科(Wikipedia)语料库,并训练成word2vec模型","categories":[{"name":"NLP","slug":"NLP","permalink":"https://imbowei.com/categories/NLP/"},{"name":"Word2vex","slug":"NLP/Word2vex","permalink":"https://imbowei.com/categories/NLP/Word2vex/"}],"tags":[{"name":"Wikipedia","slug":"Wikipedia","permalink":"https://imbowei.com/tags/Wikipedia/"},{"name":"Gensim","slug":"Gensim","permalink":"https://imbowei.com/tags/Gensim/"},{"name":"Embedding","slug":"Embedding","permalink":"https://imbowei.com/tags/Embedding/"},{"name":"Opencc","slug":"Opencc","permalink":"https://imbowei.com/tags/Opencc/"}]},{"title":"linux 常用命令备忘","slug":"Use-linux-well","date":"2018-07-20T11:56:19.000Z","updated":"2019-05-07T11:26:42.502Z","comments":true,"path":"2018/07/20/Use-linux-well/","link":"","permalink":"https://imbowei.com/2018/07/20/Use-linux-well/","excerpt":"经常会有一些的Linux命令记不牢,持续整理更新,以便查找。","text":"经常会有一些的Linux命令记不牢,持续整理更新,以便查找。 系统信息 Command Annotation date 显示当前日期和时间 cal 显示当前的日历 uptime 查看系统运行时间、用户数、负载 w 显示登陆的用户 whoami 查看自己当前的用户名 uname -a 显示内核信息 man command 显示命令的说明手册 df 显示磁盘占用情况 du 显示当前目录的空间占用情况 free 显示内存和交换区占用情况 du -h --max-depth=1 显示当前目录所占空间的大小 lspci -v 查看PCI信息,lspci 是读取 hwdata 数据库 cat /proc/cpuinfo 查看CPU信息 env 查看环境变量 ifconfig 查看所有网络接口的属性 route -n 查看路由表 netstat -antp 查看所有监听端口 netstat -s 查看网络统计信息 last 查看用户登录日志 crontab -l 查看当前用户的定时任务 rpm -qa 查看所有安装的软件包 文件命令 Command Annotation ls -a / ls -al 查看隐藏文件 / 格式化列出隐藏文件 ls -s 当前目录下的每个文件夹中有多少文件 pwd 显示当前所处路径 make dir 创建新的dir rm file / rm -r file 删除 / 强制删除file rm -r dir / rm -rf dir 删除 / 强制删除某dir cp file1 file2 将file1 复制到 file2 cp -r dir1 dir2 将dir1复制到dir2,如不存在则创建 mv file1 file2 将file1移动到file2 ln -s file link 创建 file 的符号链接 link touch file 创建新文件 cat file1 >> file2 将file1拼接到file2的末尾 cat file1 file2 > file3 将file2拼接到file1的末尾创建new file3 head file 查看某文件的前10行 tail file 查看某文件的后10行 cat file | head -n N 查看某文件的前N行 wc -l file 查看文件有多少行 wc -w file 查看文件有多少单词 wc -c file 查看文件有多少字符 wc file 默认返回三个值,依次是行数,单词数,字符数 wc file1 file2 可以统计多个文件,默认返回三行,分别是file1 file2 和 total 进程管理 Command Annotation ps -ef 显示当前所有进程 ps -ef | gerp python 显示python相关的进程 lsof -i: 2223 查看占用某端口程序的进程号 top 显示所有进程的实时运行状态 kill pid 终止某pid进程 文件权限只有一条命令chmod(change mode), 其执行形式为 chmod 777 file / chmod -r 777 dir 其权限设置分为三级,分别用三位数字代表 第一位为文件拥有者的权限 第二位其他同组用户对这个文件的权限 第三位代表其他不同组用户对其的权限 具体的每位上的数字对应什么权限? 4 —- read(r) 2 —- write(w) 1 —- execute(x) SSH Command Annotation ssh user@host 以某user的身份连接host ssh -p user@host 在端口p以user的身份连接到host logout / exit ssh 登陆后的退出命令 scp $ scp [arg] source target 123456-v : 显示进度,可以用来查看连接、认证或是配置错误。-r : 复制目录-C : 使能压缩选项-P : 选择端口-4 : 强行使用 IPV4 地址-6 : 强行使用 IPV6 地址 scp local_file remote_username@remove_ip:remote_folder 将本地文件复制到远端服务器。 搜索 Command Annotation grep pattern files 搜索files中匹配pattern的内容 grep -r pattern dir 递归搜索dir中匹配pattern的内容 command | grep pattern 搜索 command 输出中匹配 pattern 的内容 网络 Command Annotation ping host 测试某host的网络连接 wget Link 通过网络连接下载 wget -c Link 断点续传下载 安装&卸载 Command Annotation make install dpkg -i software.deb 安装包(Debian) rpm —qpl software.rpm 安装包 Red Hat Package Manager(RPM) rpm-e file 卸载软件 apt-get upgrade 更新所有已安装的软件包 压缩 tar 只是归档,不是压缩 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (tar.gz和tgz只是两种不同的书写方式,后者是一种简化书写,等同处理) .gz 解压1:gunzip FileName.gz 解压2:gzip -d FileName.gz 压缩:gzip FileName .tar.gz 和 .tgz 解压:tar zxvf FileName.tar.gz 压缩:tar zcvf FileName.tar.gz DirName Linux下压缩比率较tgz大,即压缩后占用更小的空间,使得压缩包看起来更小。 但同时在压缩,解压的过程却是非常耗费CPU时间。 .bz2 解压1:bzip2 -d FileName.bz2 解压2:bunzip2 FileName.bz2 压缩: bzip2 -z FileName .tar.bz2 解压:tar jxvf FileName.tar.bz2 压缩:tar jcvf FileName.tar.bz2 DirName zip 格式是开放且免费的,所以广泛使用在 Windows、Linux、MacOS 平台,要说 zip 有什么缺点的话,就是它的压缩率并不是很高,不如 rar及 tar.gz 等格式。 压缩:zip -r examples.zip examples (examples为目录) 解压:zip examples.zip Linux下对于占用空间与耗费时间的折衷 多选用tgz格式,不仅压缩率较高,而且打包、解压的时间都较为快速,是较为理想的选择。 快捷键 Command Annotation Ctrl + C 终止当前命令 Ctrl + Z 暂停当前命令,fg 可恢复运行 Ctrl + D 注销当前对话(类似exit) Ctrl + U 删除整行 Ctrl + W 删除当前行中的字 !! 重复上次的命令 其他操作python path Linux 非root用户pip install package -–user 默认的安装路径。查看后发现默认安装路径在/home/username/.local/bin/ whereis python 查看python的安装路径 ls /usr/bin/python* 查看可用的python脚本 for non root user modify python 将alias python='/usr/bin/python3.4' 写入vim ~/.bashrc . ~/.bashrc 重载bashrc 脚本或者重新登陆即可生效 python --version bypy12345bypy list # 显示文档bypy upload filename -v # 上传某文件,显示进度bypy -c # 取消令牌文件。一段时间后要重新授权bypy downdir filename # 下载bypy compare # 比较本地目录和网盘目录","categories":[{"name":"Linux","slug":"Linux","permalink":"https://imbowei.com/categories/Linux/"}],"tags":[{"name":"Linux","slug":"Linux","permalink":"https://imbowei.com/tags/Linux/"}]},{"title":"Hexo_Next_博客搭建记","slug":"Hexo_Next_博客搭建记","date":"2018-07-14T04:43:07.000Z","updated":"2019-05-01T09:15:13.411Z","comments":true,"path":"2018/07/14/Hexo_Next_博客搭建记/","link":"","permalink":"https://imbowei.com/2018/07/14/Hexo_Next_博客搭建记/","excerpt":"与我而言,建立个人博客存在的意义有两个。一方面,当作自己的备忘录,记录零散的知识点,避免重复的搜索工作;另一方面,可以更好的分享一些自己的心得,方便与大家交流。选择GitHub Hexo Next的组合的主要原因就是方便、便宜、简单,为从来没有接触过前端的自己降低难度。为了能让博客漂亮一点,这几天来的折腾过程记录整理在此,以备遗忘。","text":"与我而言,建立个人博客存在的意义有两个。一方面,当作自己的备忘录,记录零散的知识点,避免重复的搜索工作;另一方面,可以更好的分享一些自己的心得,方便与大家交流。选择GitHub Hexo Next的组合的主要原因就是方便、便宜、简单,为从来没有接触过前端的自己降低难度。为了能让博客漂亮一点,这几天来的折腾过程记录整理在此,以备遗忘。 博客搭建 本地构建博客我的环境是win10系统,经过一下步骤可以构建好一个运行在本地的静态博客(电脑不能占用localhost:4000端口) 安装Node.js, 这是建立Hexo的基础。在powershell中验证是否安装成功用后面两条命令 node -v、 npm -v。 建立一个存放博客文件的新文件夹。按住shift单击右键点击‘在此处打开Powershell’ 安装Hexo,并初始化博客(需要几分钟) 12npm install -g hexo-clihexo init blog 开启本地服务器 123hexo new "我就是试试博客搭建好没"hexo ghexo s 关联GitHub要想将本地博客部署到gitpages上,按照下面步骤操作即可。 安装分布式版本控制系统Git, 这是下载地址 、这是git教程 没有github账户的先注册一个 要将本地的git和github账户绑定,打开git bash ,配置如下信息。 12git config --global user.name "OnlyChristmas"git config --global user.email "OnlyChristmas@hh.com" 生成ssh密钥文件的命令:ssh-keygen -t rsa -C "OnlyChristmas@hh.com",中间不需要设置什么,直接三个回车。 在这里 点击 New SSH key 新建一个链接,并将C://users/用户名/.ssh/id_rsa.pub文件中的密钥复制进去(标题随便填)。 bash中输入ssh git@github.com验证是否配置成功。如果出现 Hi 你的用户名!You've successfully authenticated ,,,bala,,,Connection to github.com closed证明连接成功,以后推送的时候只需第一次输入密码,以后直接推送即可。 在github中新建一个仓库,名字是默认写法用户名.github.io 例如:OnlyChristmas.github.io 在 站点配置文件 配置如下信息: 1234deploy:type: gitrepo: https://github.com/OnlyChristmas/OnlyChristmas.github.io.git # 你的代码仓库地址,记得后面加上`.git`branch: master 然后保存你的配置文件 1npm install hexo-deployer-git --save 让你的博客上线! 123hexo cleanhexo ghexo d 博客上线后,chrome浏览器页面通常会直接载入缓存,无法正常显示我们上传的新内容。 这时按`F12`进入后台,然后右键单击浏览器的刷新按钮,选择清空缓存并硬性重新加载即可正常浏览页面 绑定域名不来不准备弄的,但是不折腾不舒服啊,最终还是配置完成了,链接如下。用Github和Coding双线绑定自定义域名,并申请全站SSL 初探Hexo 下面是常用的及条命令以及简写,更多命令参考官方文档 123456789101112131415161718npm install hexo -g #安装Hexonpm update hexo -g #升级hexo init #初始化博客# 主要命令的含义以及简写hexo n "我的博客" == hexo new "我的博客" #新建文章hexo g == hexo generate #生成hexo s == hexo server #启动服务预览hexo d == hexo deploy #部署# 可能用到的设置命令hexo server #Hexo会监视文件变动并自动更新,无须重启服务器hexo server -s #静态模式hexo server -p 5000 #更改端口hexo server -i 192.168.1.1 #自定义 IPhexo clean #清除缓存,若是网页正常情况下可以忽略这条命令 图片是博客必不可少的一部分,但它们会造成加载缓慢。所以对于我们严肃的技术博客来说,就要少贴图,多敲代码,哈哈~。 但是偶尔也是要贴几张图,才能说得更明白,这个时候推荐使用七牛云的外链,来提高速度。为什么选用七牛云 虽然我们是个严肃的技术博客,要有学术风格(就是丑!),但也不能太丑吧!?所以我这里换用Next主题,配置方式如下。当然也有更多的漂亮主题可供挑选,只是在配置的时候如是出现问题,更难解决,新手慎用。 在blog文件夹下的shell中输入,下载主题文件。 1git clone https://github.com/iissnan/hexo-theme-next themes/next 然后在 站点配置文件 配置如下信息: 123456789# Extensions## Plugins: https://hexo.io/plugins/## Themes: https://hexo.io/themes/# theme: landscapetheme: next Next内置优化 优化虽好,可不要贪多哦。全打开的话网页加载会很慢。。。 选择Next主题中的风格样式 在 主题配置文件 中搜索到如下这部分,并在四种风格中选择一个即可。 123456789# Schemes# scheme: Muse# scheme: Mist# scheme: Piscesscheme: Gemini algolia搜索 首先在 algolia 注册账号。此处优化需注意,官方文档不够完善。 创建APIKey HEXO_ALGOLIA_INDEXING_KEY 进入Algolia的API Keys页面ALL API KEYS选项卡 创建APIKey Description:HEXO_ALGOLIA_INDEXING_KEY Indices:<此处选择之前创建的Index> ACL:Add records,Delete records,List indices,Delete index 也就是说,我们有两个APIKey,其中一个是Search-only API Key(我们后面需要进行用它配置),另一个是HEXO_ALGOLIA_INDEXING_KEY(新建好即可)。具体的配置步骤如下: 在 站点配置文件 中需要添加 12345algolia: applicationID: # Application ID apiKey: # Search-only API Key indexName: # 此处选择之前创建的Index chunkSize: 5000 在 主题配置文件 中搜索到如下这部分,只需将enable改为true,最后两个搜索提示信息有需要的话也可以修改。 12345678algolia_search: enable: true hits: per_page: 10 labels: input_placeholder: Search for Posts hits_empty: "不好意思,木有'${query}'的搜索结果😂" hits_stats: "${hits} results found in ${time} ms" 接下来,我采取的配置方法和官方文档有点出入,但是亲测有效(我是win10系统)。 1. 在博客文件夹根目录右键打开git bash here 2. `export HEXO_ALGOLIA_INDEXING_KEY='Search-only API Key'` 3. `hexo algolia` bash中出现类似提示说明配置成功 123INFO [Algolia] Identified 6 pages and posts to index.INFO [Algolia] Indexing chunk 1 of 1 (50 items each)INFO [Algolia] Indexing done. 选择动画背景 在 主题配置文件 中搜索并配置如下信息,最好四选一。 1234567891011121314151617181920# Canvas-nestcanvas_nest: true # 背景有降落伞# three_wavesthree_waves: false # 背景有像海浪一样的小球球# canvas_linescanvas_lines: false # 背景有立体蜘蛛网# canvas_spherecanvas_sphere: false # 屏幕中央有一个爆炸状的球球#### 代码块语法高亮设置- 在<span id="inline-blue"> 站点配置文件 </span> 设置highlight: enable: true line_number: true auto_detect: true tab_replace: true 注意,网上的自定义样式优化代码中,有对代码块的优化,那部分代码需要注释掉。 添加RSS 打开博客根目录,shell安装插件,用如下代码: 1npm install --save hexo-generator-feed 在 站点配置文件 配置如下信息: 1234567891011121314151617# Extensions## Plugins: http://hexo.io/plugins/#RSS订阅plugin:- hexo-generator-feed #Feed Atom feed: type: atom path: atom.xml limit: 20 hub: content: content_limit: 140 content_limit_delim: ‘ ’ 在 主题配置文件 中搜索并配置如下信息。 1234# Set rss to false to disable feed link.# Leave rss as empty to use site's feed link.# Set rss to specific value if you have burned your feed already.rss: "/atom.xml" 最后重新生成,只要在./public中看到atom.xml说明生成成功。 修改文章底部的tag图标 修改模板/themes/next/layout/_macro/post.swig,搜索 rel="tag">#,将 # 换成<i class="fa fa-tag"></i>,当然也可以切换成任何你喜欢的小图标。 busuanzi统计访客人数在 主题配置文件 中搜索并配置如下信息,也可以根据自己的喜欢修改其他配置。 1234567891011121314151617# Show PV/UV of the website/page with busuanzi.# Get more information on http://ibruce.info/2015/04/04/busuanzi/busuanzi_count: # count values only if the other configs are false enable: true # custom uv span for the whole site site_uv: true site_uv_header: <i class="fa fa-user"></i> 你是第 site_uv_footer: 个小伙伴 # custom pv span for the whole site site_pv: true site_pv_header: <i class="fa fa-eye"></i> 总访问 site_pv_footer: 人次 # custom pv span for one page only page_pv: false page_pv_header: <i class="fa fa-file-o"></i> page_pv_footer: 20181009更新:由于卜算子的域名到期,需要更换/next/layout/_third-party/analytics/busuanzi-counter.swig 下的网址为新网址,https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js 文章“热度” 首先要注册leancloud 左上角创建一个新的应用,获取AppID and AppKey。并且在网站的设置->安全中心中设置Web安全域名。 在 主题配置文件 中搜索并配置如下信息: 123456# Show number of visitors to each article.# You can visit https://leancloud.cn get AppID and AppKey.leancloud_visitors:enable: trueapp_id: #<app_id>app_key: #<app_key> 打开/themes/next/layout/_macro/post.swig,我的代码修改成如下样子,也可以自由发挥。 1234567891011121314151617{# LeanCould PageView #}{% if theme.leancloud_visitors.enable %} <span id="{{ url_for(post.path) }}" class="leancloud_visitors" data-flag-title="{{ post.title }}"> <span class="post-meta-divider">|</span> <!-- 注释掉了图片 --><!-- <span class="post-meta-item-icon"> <i class="fa fa-eye"></i> </span> --> {% if theme.post_meta.item_text %} <span class="post-meta-item-text">{{__('post.visitors')}}&#58;</span> {% endif %} <span class="leancloud-visitors-count"></span> <span>℃</span> </span>{% endif %} 最后,在/themes/next/languages/zh-Hans.yml,可以任意修改文字信息,我的代码如下所示: 12345678910post:created: 创建于modified: 更新于sticky: 置顶posted: '发表于:'in: '类别:'read_more: 阅读全文untitled: 未命名toc_empty: 此文章未包含目录visitors: 热度 字数统计功能配置 切换到根目录下,然后运行如下代码 $ npm install hexo-wordcount --save 然后在 主题配置文件 中自定义如下配置: 123456789Post wordcount display settings# Dependencies: https://github.com/willin/hexo-wordcountpost_wordcount: item_text: true wordcount: true min2read: false totalcount: true separated_meta: true 这里我遇到一个大坑,在正文中写``标签一定要用代码块包括,否则可能会造成wordcount无法正常统计字数!一直显示为0 解决readme问题在github手动添加readme文件总是会被擦掉,会很麻烦,现在有两种解决方法。 第一种,在/blog/source中添加一个README.MDOWN文件,每次推送到github都可以正常解析。 第二种,在 站点配置文件 配置如下信息: 1skip_render: README.md 自定义网站图标 在 主题配置文件 中搜索到如下这部分, 123456789101112131415161718favicon:# small: /images/favicon-16x16-next.png# medium: /images/favicon-32x32-next.png# apple_touch_icon: /images/apple-touch-icon-next.png# safari_pinned_tab: /images/logo.svg small: # 你的图像 medium: # 你的图像 apple_touch_icon: # 你的图像 safari_pinned_tab: # 你的图像 #android_manifest: /images/manifest.json #ms_browserconfig: /images/browserconfig.xml 网站顶部加载条 已经被Next主题做成了默认的设置,在 主题配置文件 中配置: 12345678910111213141516171819202122232425262728293031323334353637# Progress bar in the top during page loading.pace: true# Themes list:#pace-theme-big-counter#pace-theme-bounce#pace-theme-barber-shop#pace-theme-center-atom#pace-theme-center-circle#pace-theme-center-radar#pace-theme-center-simple#pace-theme-corner-indicator#pace-theme-fill-left#pace-theme-flash#pace-theme-loading-bar#pace-theme-mac-osx#pace-theme-minimal# For example# pace_theme: pace-theme-center-simple# pace_theme: pace-theme-minimal 版权信息 已经被Next主题做成了默认的设置,在 主题配置文件 中配置: 12345678910111213141516171819202122232425262728footer:# Specify the date when the site was setup.# If not defined, current year will be used. since: 2018# Icon between year and copyright info. icon: heart# If not defined, will be used `author` from Hexo main config. copyright:# -–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–-–--—# Hexo link (Powered by Hexo). powered: false theme: # Theme & scheme info link (Theme - NexT.scheme).enable: false# Version info of NexT after scheme info (vX.X.X).version: true 可以在每天博文生成的时候,将它作为一个文章模板。这样可以灵活地对于每篇文章设定是否需要版权信息。 我在/blog/scaffolds/中新建了一个next博文模板,代码如下: 123456789title: {{ title }}date: {{ date }}comments: truecategories: NLPtags: [tag1, tag2]post_copyright: true This is a summary<!-- more --> 在 站点配置文件 配置如下信息,每次新生成的文章都会使用此模板。 1234#### Writingnew_post_name: :title.md # File name of new postsdefault_layout: next SEO配置 想要让我们的站点被搜索引擎收录,要提交给他们站点文件。 首先安装两个插件,并生成两个站点文件,sitemap.xml与baidusitemap.xml文件 1234npm install hexo-generator-sitemap --save-devhexo d -gnpm install hexo-generator-baidu-sitemap --save-devhexo d -g 在 站点配置文件 配置如下信息: 12345# SEO 优化sitemap: path: sitemap.xmlbaidusitemap: path: baidusitemap.xml 新建robots.txt文件,添加以下文件内容,把robots.txt放在hexo站点的source文件下 12345678910User-agent: * Allow: /Allow: /archives/Disallow: /vendors/Disallow: /js/Disallow: /css/Disallow: /fonts/Disallow: /vendors/Disallow: /fancybox/Sitemap: http://imbowei.com/sitemap.xmlSitemap: http://imbowei.com/baidusitemap.xml 在 主题配置文件 中配置如下。 123# Enable baidu push so that the blog will push the url to baidu automatically which is very helpful for SEObaidu_push: true 当然还要去百度站长和谷歌站长验证,bing验证 google_analytics 在 主题配置文件 中有若干种分析工具可以配置,我这里只配置了谷歌分析 123# Google Analyticsgoogle_analytics: UA-balbalbal 20180809更新 为了提升新浏览器的性能,将Next主题原有的blog/themes/next/layout/_third_party/analytics/google_analytics.js脚本改为异步加载。如果 IE 9 以及不识别 async 脚本属性的旧版移动浏览器中会自动降级为同步加载和执行。 12345678<script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', '{{ theme.google_analytics }}', 'auto'); ga('send', 'pageview');</script> 123456<script>window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;ga('create', '{{ theme.google_analytics }}', 'auto');ga('send', 'pageview');</script><script async src='https://www.google-analytics.com/analytics.js'></script> gitment评论系统先注册gitment,这是作者博客,按照官方文档搭建即可 12345678910111213141516# Gitment# Introduction: https://imsun.net/posts/gitment-introduction/# You can get your Github ID from https://api.github.com/users/<Github username>gitment: enable: true mint: true # RECOMMEND, A mint on Gitment, to support count, language and proxy_gateway count: false # Show comments count in post meta area lazy: false # Comments lazy loading with a button cleanly: false # Hide 'Powered by ...' on footer, and more language: # Force language, or auto switch by theme github_user: OnlyChristmas # MUST HAVE, Your Github ID github_repo: OnlyChristmas.github.io # MUST HAVE, The repo you use to store Gitment comments client_id: 8fc5c43242323koljoa # MUST HAVE, Github client id for the Gitment client_secret: 4ff9a214325312515151b04c400d46 # EITHER this or proxy_gateway, Github access secret token for the Gitment proxy_gateway: # Address of api proxy, See: https://github.com/aimingoo/intersect redirect_protocol: # Protocol of redirect_uri with force_redirect_protocol when mint enabled Mathjax数学公式支持 08.22更新 首先,在 主题配置文件 中修改如下配置:enable 为 true 12345# MathJax Supportmathjax:enable: falseper_page: truecdn: //cdn.bootcss.com/mathjax/2.7.1/latest.js?config=TeX-AMS-MML_HTMLorMML 在/scaffolds/draft.md文件中添加mathjax: false默认不启用mathjax(想要启用的文章再改为true),加快页面加载速度。 Hexo默认使用hexo-renderer-marked引擎进行网页渲染,其中对许多字符诸如划线、下划线、中括号等定义了转义。因此,在进行网页渲染时,数学公式中的这些字符先通过hexo-renderer-marked进行转义,就发生了歧义,而再通过MathJax渲染出来的数学公式,自然就显示不正常了。根据这种情况,我们更换渲染器。 12npm uninstall hexo-renderer-marked --savenpm install hexo-renderer-kramed --save 在做完工作上面的工作后,行间公式就可以被正确渲染了,但行内公式却还存在着部分问题,这是因为对行间定义的转义字符和对行内定义的转义字符并不相同,还有部分已定义的行间转义字符会与数学公式中可能用到的字符发生冲突,用到这些字符的数学公式在渲染前仍被进行了转义。 打开node_modules\\kramed\\lib\\rules\\inline.js文件,做出如下两处修改。 1234567line 11,// escape: /^\\\\([\\\\`*{}\\[\\]()#$+\\-.!_>])/,-> escape: /^\\\\([`*\\[\\]()#$+\\-.!_>])/,line 20,// em: /^\\b_((?:__|[\\s\\S])+?)_\\b|^\\*((?:\\*\\*|[\\s\\S])+?)\\*(?!\\*)/,-> em: /^\\*((?:\\*\\*|[\\s\\S])+?)\\*(?!\\*)/, 不要安装 `hexo-math` 和 `hexo-renderer-markdown-it-plus` 这两个包,否则出错。 自定义优化 优化虽好,可不要贪多哦。全打开的话网页加载会很慢。。。 百度分享next内置的代码在服务器升级https之后,百度分享的js请求不了。但是在 github上的轮子 可以修改后再其启用这一功能。 下载后得到static文件夹,放入到/themes/next/source/目录下。 将themes/next/layout/_partials/share/baidushare.swig中末尾处的代码进行替换。 原代码 123<script> with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script> 替换代码 123<script> with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script> 最后一定记得先hexo g再hexo s,否则可能会出现问题。 自定义网页title 在next\\source\\js\\src下新建脚本custom_title.js,将下面代码复制进去。 js脚本来源 1234567891011121314151617<!--崩溃欺骗--> var OriginTitle = document.title; var titleTime; document.addEventListener('visibilitychange', function () { if (document.hidden) { $('[rel="icon"]').attr('href', "/img/TEP.ico"); document.title = '╭(°A°`)╮ 爱我别走 ~'; clearTimeout(titleTime); } else { $('[rel="icon"]').attr('href', "/favicon.ico"); document.title = '(ฅ>ω<*ฅ) 这才对嘛~' + OriginTitle; titleTime = setTimeout(function () { document.title = OriginTitle; }, 2000); } }); 在next\\layout\\_layout.swig的<body> </body>标签体内添加 12<!--崩溃欺骗--><script type="text/javascript" src="/js/src/custom_title.js"></script> 鼠标点击桃心样式 在/themes/next/source/js/src/中新建love.js,其中写入的代码如下。 1!function(e,t,a){function r(){for(var e=0;e<n.length;e++)n[e].alpha<=0?(t.body.removeChild(n[e].el),n.splice(e,1)):(n[e].y--,n[e].scale+=.004,n[e].alpha-=.013,n[e].el.style.cssText="left:"+n[e].x+"px;top:"+n[e].y+"px;opacity:"+n[e].alpha+";transform:scale("+n[e].scale+","+n[e].scale+") rotate(45deg);background:"+n[e].color+";z-index:99999");requestAnimationFrame(r)}var n=[];e.requestAnimationFrame=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)},function(e){var a=t.createElement("style");a.type="text/css";try{a.appendChild(t.createTextNode(e))}catch(t){a.styleSheet.cssText=e}t.getElementsByTagName("head")[0].appendChild(a)}(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),function(){var a="function"==typeof e.onclick&&e.onclick;e.onclick=function(e){a&&a(),function(e){var a=t.createElement("div");a.className="heart",n.push({el:a,x:e.clientX-5,y:e.clientY-5,scale:1,alpha:1,color:"rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"}),t.body.appendChild(a)}(e)}}(),r()}(window,document); 在/themes/next/layout/_layout.swig中的<body></body>标签体内添加下面代码。 12<!-- 页面点击小红心 --><script type="text/javascript" src="/js/src/love.js"></script> 鼠标点击烟花爆炸样式 在/themes/next/source/js/src/中新建fireworks.js,其中写入的代码如下。 1"use strict";function updateCoords(e){pointerX=(e.clientX||e.touches[0].clientX)-canvasEl.getBoundingClientRect().left,pointerY=e.clientY||e.touches[0].clientY-canvasEl.getBoundingClientRect().top}function setParticuleDirection(e){var t=anime.random(0,360)*Math.PI/180,a=anime.random(50,180),n=[-1,1][anime.random(0,1)]*a;return{x:e.x+n*Math.cos(t),y:e.y+n*Math.sin(t)}}function createParticule(e,t){var a={};return a.x=e,a.y=t,a.color=colors[anime.random(0,colors.length-1)],a.radius=anime.random(16,32),a.endPos=setParticuleDirection(a),a.draw=function(){ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.fillStyle=a.color,ctx.fill()},a}function createCircle(e,t){var a={};return a.x=e,a.y=t,a.color="#F00",a.radius=0.1,a.alpha=0.5,a.lineWidth=6,a.draw=function(){ctx.globalAlpha=a.alpha,ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.lineWidth=a.lineWidth,ctx.strokeStyle=a.color,ctx.stroke(),ctx.globalAlpha=1},a}function renderParticule(e){for(var t=0;t<e.animatables.length;t++){e.animatables[t].target.draw()}}function animateParticules(e,t){for(var a=createCircle(e,t),n=[],i=0;i<numberOfParticules;i++){n.push(createParticule(e,t))}anime.timeline().add({targets:n,x:function(e){return e.endPos.x},y:function(e){return e.endPos.y},radius:0.1,duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule}).add({targets:a,radius:anime.random(80,160),lineWidth:0,alpha:{value:0,easing:"linear",duration:anime.random(600,800)},duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule,offset:0})}function debounce(e,t){var a;return function(){var n=this,i=arguments;clearTimeout(a),a=setTimeout(function(){e.apply(n,i)},t)}}var canvasEl=document.querySelector(".fireworks");if(canvasEl){var ctx=canvasEl.getContext("2d"),numberOfParticules=30,pointerX=0,pointerY=0,tap="mousedown",colors=["#FF1461","#18FF92","#5A87FF","#FBF38C"],setCanvasSize=debounce(function(){canvasEl.width=2*window.innerWidth,canvasEl.height=2*window.innerHeight,canvasEl.style.width=window.innerWidth+"px",canvasEl.style.height=window.innerHeight+"px",canvasEl.getContext("2d").scale(2,2)},500),render=anime({duration:1/0,update:function(){ctx.clearRect(0,0,canvasEl.width,canvasEl.height)}});document.addEventListener(tap,function(e){"sidebar"!==e.target.id&&"toggle-sidebar"!==e.target.id&&"A"!==e.target.nodeName&&"IMG"!==e.target.nodeName&&(render.play(),updateCoords(e),animateParticules(pointerX,pointerY))},!1),setCanvasSize(),window.addEventListener("resize",setCanvasSize,!1)}"use strict";function updateCoords(e){pointerX=(e.clientX||e.touches[0].clientX)-canvasEl.getBoundingClientRect().left,pointerY=e.clientY||e.touches[0].clientY-canvasEl.getBoundingClientRect().top}function setParticuleDirection(e){var t=anime.random(0,360)*Math.PI/180,a=anime.random(50,180),n=[-1,1][anime.random(0,1)]*a;return{x:e.x+n*Math.cos(t),y:e.y+n*Math.sin(t)}}function createParticule(e,t){var a={};return a.x=e,a.y=t,a.color=colors[anime.random(0,colors.length-1)],a.radius=anime.random(16,32),a.endPos=setParticuleDirection(a),a.draw=function(){ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.fillStyle=a.color,ctx.fill()},a}function createCircle(e,t){var a={};return a.x=e,a.y=t,a.color="#F00",a.radius=0.1,a.alpha=0.5,a.lineWidth=6,a.draw=function(){ctx.globalAlpha=a.alpha,ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.lineWidth=a.lineWidth,ctx.strokeStyle=a.color,ctx.stroke(),ctx.globalAlpha=1},a}function renderParticule(e){for(var t=0;t<e.animatables.length;t++){e.animatables[t].target.draw()}}function animateParticules(e,t){for(var a=createCircle(e,t),n=[],i=0;i<numberOfParticules;i++){n.push(createParticule(e,t))}anime.timeline().add({targets:n,x:function(e){return e.endPos.x},y:function(e){return e.endPos.y},radius:0.1,duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule}).add({targets:a,radius:anime.random(80,160),lineWidth:0,alpha:{value:0,easing:"linear",duration:anime.random(600,800)},duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule,offset:0})}function debounce(e,t){var a;return function(){var n=this,i=arguments;clearTimeout(a),a=setTimeout(function(){e.apply(n,i)},t)}}var canvasEl=document.querySelector(".fireworks");if(canvasEl){var ctx=canvasEl.getContext("2d"),numberOfParticules=30,pointerX=0,pointerY=0,tap="mousedown",colors=["#FF1461","#18FF92","#5A87FF","#FBF38C"],setCanvasSize=debounce(function(){canvasEl.width=2*window.innerWidth,canvasEl.height=2*window.innerHeight,canvasEl.style.width=window.innerWidth+"px",canvasEl.style.height=window.innerHeight+"px",canvasEl.getContext("2d").scale(2,2)},500),render=anime({duration:1/0,update:function(){ctx.clearRect(0,0,canvasEl.width,canvasEl.height)}});document.addEventListener(tap,function(e){"sidebar"!==e.target.id&&"toggle-sidebar"!==e.target.id&&"A"!==e.target.nodeName&&"IMG"!==e.target.nodeName&&(render.play(),updateCoords(e),animateParticules(pointerX,pointerY))},!1),setCanvasSize(),window.addEventListener("resize",setCanvasSize,!1)}; 在/themes/next/layout/_layout.swig中的<body></body>标签体内添加下面代码。 123456<!-- 页面点击烟花爆炸 --> {% if theme.fireworks %} <canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 1; pointer-events: none;" ></canvas> <script type="text/javascript" src="//cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script> <script type="text/javascript" src="/js/src/fireworks.js"></script> {% endif %} 在 主题配置文件 中添加如下配置: 12# Fireworks 鼠标点击烟花爆炸fireworks: true 自定义鼠标图片 在themes/next/source/css/_custom/custom.styl中,添加如下代码 1234567// 鼠标样式{cursor: url("http://om8u46rmb.bkt.clouddn.com/sword2.ico"),auto!important}:active { cursor: url("http://om8u46rmb.bkt.clouddn.com/sword1.ico"),auto!important} 上面的url必须是ico 图片,想要自定义图片可以自行上传七牛云获取外链(加速),也可以本地加载。我就偷懒直接用其他博主的链接了。 网易云音乐添加歌单进正文页面怎么生成歌单的外链看这里然后将生成的代码加入到想要放入的位置就好了(适当调整大小)。 12<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=260 height=240 src="//music.163.com/outchain/player?type=0&id=2315300596&auto=1&height=430"></iframe> 设置fork me on github 在这里挑选样式并复制代码 或者这里也可以。 刚才复制的代码放到themes/next/layout/_layout.swig文件中,<div class="headband"></div>的下面,并且记得herf改为自己的github地址。 配置文章结束模板 在\\themes\\next\\layout\\_macro文件夹中,新建passage-end-tag.swig,并且写入如下代码(当然也可以自由发挥): 1234567<div> {% if not is_index %} <blockquote class="blockquote-center"> <div style="text-align:center;color: #FF5733;font-size:24px;">-------------本文结束 <i class="fa fa-heart"></i> 感谢您的时间-------------</div> </blockquote> {% endif %}</div> 接着打开\\themes\\next\\layout\\_macro\\post.swig文件,在post-body 之后, post-footer 之前添加如下代码。(在我文件大约360的位置) 12345<div> {% if not is_index %} {% include 'passage-end-tag.swig' %} {% endif %}</div> 最后在 主题配置文件 中添加如下配置: 123# 文章末尾添加“本文结束”标记passage_end_tag:enabled: true 实现效果如本文结尾所示 头像制作按照NEXT主题,上传的网站图片需要满足一定的规格要求。 网站图标:我这里在一个在线艺术字网站,设计了一个汉字,下载图片(转换SVG),并且尽量在保证图片清晰度的情况下减小图片大小,以保证网站的加载速度。很棒的免费在线图片压缩网站 个人头像:这里涉及到方照片裁剪呈圆形图片的问题。 首先,你需要安装一个PS; 然后,左上角选取圆形套索。按住SHIFT键的同时选取图片满意的部分; 在图片中,右键”通过拷贝的图层“。然后勾选掉下面图层的眼睛标识,得到下图所示的样子。 接下来用裁剪工具可以去掉多余的透明背景。 在顶部选项卡,”图像-–>图像大小“可以根据需要调整图像的大小。 最后,照例为了保证网站的加载速度,尽可能的在保证图片质量的前提下压缩图片。很棒的免费在线图片压缩网站 头像旋转 首先打开头像选项,在 主题配置文件 中。 123in theme directory(source/images): # 你的头像# in site directory(source/uploads): /uploads/avatar.gifavatar: # 你的头像 打开\\themes\\next\\source\\css\\_common\\components\\sidebar\\sidebar-author.styl,在里面添加如下代码: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354.site-author-image {display: block;margin: 0 auto;padding: $site-author-image-padding;max-width: $site-author-image-width;height: $site-author-image-height;border: $site-author-image-border-width solid $site-author-image-border-color;/* 头像圆形 */border-radius: 80px;-webkit-border-radius: 80px;-moz-border-radius: 80px;box-shadow: inset 0 -1px 0 #333sf;/* 设置循环动画 [animation: (play)动画名称 (2s)动画播放时长单位秒或微秒 (ase-out)动画播放的速度曲线为以低速结束 (1s)等待1秒然后开始动画 (1)动画播放次数(infinite为循环播放) ]*//* 鼠标经过头像旋转360度 */-webkit-transition: -webkit-transform 1.0s ease-out;-moz-transition: -moz-transform 1.0s ease-out;transition: transform 1.0s ease-out;}img:hover {/* 鼠标经过停止头像旋转-webkit-animation-play-state:paused;animation-play-state:paused;*//* 鼠标经过头像旋转360度 */-webkit-transform: rotateZ(360deg);-moz-transform: rotateZ(360deg);transform: rotateZ(360deg);}/* Z 轴旋转动画 */@-webkit-keyframes play {0% { -webkit-transform: rotateZ(0deg);}100% { -webkit-transform: rotateZ(-360deg);}}@-moz-keyframes play {0% { -moz-transform: rotateZ(0deg);}100% { -moz-transform: rotateZ(-360deg);}}@keyframes play {0% { transform: rotateZ(0deg);}100% { transform: rotateZ(-360deg);}} 站点上线时间 在/themes/next/layout/_partials/footer.swig文件尾部加上,并且修改你的上线时间。 1234567891011121314151617<span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span><script> var now = new Date(); function createtime() { var grt= new Date("07/06/2018 11:11:00");//此处修改你的建站时间或者网站上线时间 now.setTime(now.getTime()+250); days = (now - grt ) / 1000 / 60 / 60 / 24; dnum = Math.floor(days); hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum); hnum = Math.floor(hours); if(String(hnum).length ==1 ){hnum = "0" + hnum;} minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum); mnum = Math.floor(minutes); if(String(mnum).length ==1 ){mnum = "0" + mnum;} seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum); snum = Math.round(seconds); if(String(snum).length ==1 ){snum = "0" + snum;} document.getElementById("timeDate").innerHTML = "本站已安全运行 "+dnum+" 天 "; document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒"; }setInterval("createtime()",250);</script> daovoice 在daovoice注册账号可以得到 app_id 在 主题配置文件 中添加如下配置 123# Online contactdaovoice: truedaovoice_app_id: # 这里填你刚才获得的 app_id 在/themes/next/layout/_partials/head.swig,添加如下代码: 12345678910<!-- 添加DaoVioce -->{% if theme.daovoice %}<script>(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/0f81ff2f.js","daovoice")daovoice('init', { app_id: "{{theme.daovoice_app_id}}" });daovoice('update');</script>{% endif %} 阅读排行榜 hexo n page top新建页面,编辑自动生成的index.md文件,代码如下,替换好你的 leancloud账号 和页面链接(一共三处) 12345678910111213141516171819202122232425<div id="top"></div><script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script><script>AV.initialize("leancloud_appid", "leancloud_appkey");</script><script type="text/javascript">var time=0var title=""var url=""var query = new AV.Query('Counter');query.notEqualTo('id',0);query.descending('time');query.limit(1000);query.find().then(function (todo) { for (var i=0;i<1000;i++){ var result=todo[i].attributes; time=result.time; title=result.title; url=result.url; // var content="<a href='"+"https://onlychristmas.github.io"+url+"'>"+title+"</a>"+"<br>"+"<font color='#fff'>"+"阅读次数:"+time+"</font>"+"<br><br>"; var content="<p>"+"<font color='#1C1C1C'>"+"【文章热度:"+time+"℃】"+"</font>"+"<a href='"+"https://onlychristmas.github.io"+url+"'>"+title+"</a>"+"</p>"; document.getElementById("top").innerHTML+=content }}, function (error) { console.log("error");});</script> 本地调试不显示,重新生成上传,才能看到排序效果 背景透明 考虑到我们这么好看的动态背景,只在文章两边很小的区域展示,有点别扭,想要让它在文章后面也能显示。 在themes\\next\\source\\css_schemes\\你设置的主题\\index.styl文件中搜索background,会出现五个结果,我这里只将前两个设置为none(透明),也可以根据需求设置更多的透明。 1234567891011121314151617// =================================================// Desktop layout styles.// =================================================// Post blocks..content-wrap {padding: initial;background: none;box-shadow: initial;border-radius: initial;}// Post & Comments blocks..post-block { padding: $content-desktop-padding; background: none; box-shadow: $box-shadow-inner; border-radius: $border-radius-inner;} 如果手机端背景透明,整个页面会比较凌乱,影响阅读效果。切记保持white 12345678910// =================================================// < 767px// =================================================+mobile() { // Posts in blocks. .content-wrap { padding: $content-mobile-padding; background: white; } 同理,在平台电脑上最好也保持背景不透明 12345678910// =================================================// > 768px & < 991px// =================================================+tablet() { // Posts in blocks. .content-wrap { padding: $content-tablet-padding; background: white; } 添加代码块复制按钮 下载clipboard.min.js并将其放到.\\themes\\next\\source\\js\\src\\目录下。 在.\\themes\\next\\source\\js\\src\\目录下,创建clipboard-use.js,文件内容如下: 123456789101112131415161718192021222324252627282930313233343536//代码块复制按钮.highlight{ //方便copy代码按钮(btn-copy)的定位 position: relative;}.btn-copy { display: inline-block; cursor: pointer; background-color: #eee; background-image: linear-gradient(#fcfcfc,#eee); border: 1px solid #d5d5d5; border-radius: 3px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-appearance: none; font-size: 13px; font-weight: 700; line-height: 20px; color: #333; -webkit-transition: opacity .3s ease-in-out; -o-transition: opacity .3s ease-in-out; transition: opacity .3s ease-in-out; padding: 2px 6px; position: absolute; right: 5px; top: 5px; opacity: 0;}.btn-copy span { margin-left: 5px;}.highlight:hover .btn-copy{ opacity: 1;} 在.\\themes\\next\\source\\css\\_custom\\custom.styl样式文件中添加下面代码: 在.\\themes\\next\\layout\\_layout.swig文件中,添加引用要在<body></body>标签内: high一下 打开 blog\\themes\\next\\layout\\_partials\\header.swig ,在<ul> ... /ul> 标签之间加入以下代码: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190<li class="menu-item"> <a title=“把这个链接拖到你的工具栏中,任何网页都可以High” href=’javascript:(function go() {var songs = [ “http://www.170mv.com/kw/other.web.ri01.sycdn.kuwo.cn/resource/n3/43/85/4088203395.mp3”, “http://www.170mv.com/kw/other.web.rm01.sycdn.kuwo.cn/resource/n3/10/77/3147640053.mp3”, “http://7xoiki.com1.z0.glb.clouddn.com/Music-sunburst.mp3”, “”];function c() {var e = document.createElement(“link”);e.setAttribute(“type”, “text/css”);e.setAttribute(“rel”, “stylesheet”);e.setAttribute(“href”, f);e.setAttribute(“class”, l);document.body.appendChild(e)}function h() {var e = document.getElementsByClassName(l);for (var t = 0; t < e.length; t++) { document.body.removeChild(e[t])}}function p() {var e = document.createElement(“div”);e.setAttribute(“class”, a);document.body.appendChild(e);setTimeout(function() { document.body.removeChild(e)}, 100)}function d(e) {return { height : e.offsetHeight, width : e.offsetWidth}}function v(i) {var s = d(i);return s.height > e && s.height < n && s.width > t && s.width < r}function m(e) {var t = e;var n = 0;while (!!t) { n += t.offsetTop; t = t.offsetParent}return n}function g() {var e = document.documentElement;if (!!window.innerWidth) { return window.innerHeight} else if (e && !isNaN(e.clientHeight)) { return e.clientHeight}return 0}function y() {if (window.pageYOffset) { return window.pageYOffset}return Math.max(document.documentElement.scrollTop, document.body.scrollTop)}function E(e) {var t = m(e);return t >= w && t <= b + w}function S() {var e = document.getElementById(“audio_element_id”);if(e != null){ var index = parseInt(e.getAttribute(“curSongIndex”)); if(index > songs.length - 2) { index = 0; } else { index++; } e.setAttribute(“curSongIndex”, index); N();}e.src = i;e.play()}function x(e) {e.className += “ “ + s + “ “ + o}function T(e) {e.className += “ “ + s + “ “ + u[Math.floor(Math.random() * u.length)]}function N() {var e = document.getElementsByClassName(s);var t = new RegExp(“\\\\b” + s + “\\\\b”);for (var n = 0; n < e.length; ) { e[n].className = e[n].className.replace(t, “”)}}function initAudioEle() {var e = document.getElementById(“audio_element_id”);if(e === null){ e = document.createElement(“audio”); e.setAttribute(“class”, l); e.setAttribute(“curSongIndex”, 0); e.id = “audio_element_id”; e.loop = false; e.bgcolor = 0; e.addEventListener(“canplay”, function() { setTimeout(function() { x(k) }, 500); setTimeout(function() { N(); p(); for (var e = 0; e < O.length; e++) { T(O[e]) } }, 15500)}, true);e.addEventListener(“ended”, function() { N(); h(); go();}, true);e.innerHTML = “ <p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p> <p>”;document.body.appendChild(e);}}initAudioEle();var e = 30;var t = 30;var n = 350;var r = 350;var curSongIndex = parseInt(document.getElementById(“audio_element_id”).getAttribute(“curSongIndex”));var i = songs[curSongIndex];var s = “mw-harlem_shake_me”;var o = “im_first”;var u = [“im_drunk”, “im_baked”, “im_trippin”, “im_blown”];var a = “mw-strobe_light”;/* harlem-shake-style.css,替换成你的位置,也可以直接使用://s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css */var f = “//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css”;var l = “mw_added_css”;var b = g();var w = y();var C = document.getElementsByTagName(“*”);var k = null;for (var L = 0; L < C.length; L++) {var A = C[L];if (v(A)) { if (E(A)) { k = A; break }}}if (A === null) {console.warn(“Could not find a node of the right size. Please try a different page.”);return}c();S();var O = [];for (var L = 0; L < C.length; L++) {var A = C[L];if (v(A)) { O.push(A)}}})()’><i class="menu-item-icon fa fa-music fa-fw"></i>High一下</a> </li><!-- end High一下 --> 这段代码貌似有个bug,在播放曲目为空的时候,博客就会尬舞,退出high一下,刷新界面就好 跳动的心 在 站点配置文件 配置如下信息: 12footer: icon: heart 打开 /blog/themes/next/layout/_partials/footer.swig文件, 将 <span class="with-love">换成下面代码: 1<span class="with-love" id="heart"> 打开/blog/themes/next/source/css/_custom/custom.styl文件,下面代码(颜色可以自定义): 1234567891011121314// 自定义页脚跳动的心样式@keyframes heartAnimate { 0%,100%{transform:scale(1);} 10%,30%{transform:scale(0.9);} 20%,40%,60%,80%{transform:scale(1.1);} 50%,70%{transform:scale(1.1);}}#heart { animation: heartAnimate 1.33s ease-in-out infinite;}.with-love { color: rgb(255, 113, 168);} 添加404页面 在blog/source/文件夹下新建404.html并加入如下代码: 123456789101112131415161718192021<html><head> <meta http-equiv="content-type" content="text/html;charset=utf-8;"/> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="robots" content="all" /> <meta name="robots" content="index,follow"/> <link rel="stylesheet" type="text/css" href="https://qzone.qq.com/gy/404/style/404style.css"></head><body> <script type="text/plain" src="http://www.qq.com/404/search_children.js" charset="utf-8" homePageUrl="https://onlychristmas.github.io/" homePageName="回到我的主页"> </script> <script src="https://qzone.qq.com/gy/404/data.js" charset="utf-8"></script> <script src="https://qzone.qq.com/gy/404/page.js" charset="utf-8"></script></body></html> <!DOCTYPE HTML> 调试优化 在blog/package.json中并列"dependencies": {}添加如下代码: 123"scripts": { "dev": "hexo clean && hexo generate && hexo server --debug"} 现在我们只需 npm run dev 一条命令就可以启动本地的调试环境 博客内容压缩 在blog/package.json中 "dependencies": {}后面平行的添加如下内容: 123456789101112131415161718192021222324“devDependencies”: { “gulp-asset-rev”: “^0.0.15”, “gulp-clean-css”: “^3.9.0”, “gulp-concat”: “^2.6.1”, “gulp-debug”: “^3.1.0”, “gulp-htmlclean”: “^2.7.15”, “gulp-htmlmin”: “^3.0.0”, “gulp-if”: “^2.0.2”, “gulp-changed”: “^3.1.0”, “gulp-make-css-url-version”: “^0.0.13”, “gulp-modify-css-urls”: “^0.2.2”, “gulp-plumber”: “^1.1.0”, “gulp-uglify”: “^3.0.0”, “gulp-useref”: “^3.1.2”, “gulp-util”: “^3.0.8”, “hexo-deployer-git”: “^0.3.1”, “hexo-encrypt”: “^0.5.1”, “hexo-generator-json-content”: “^3.0.1”, “hexo-generator-search”: “^2.1.1”, “hexo-generator-searchdb”: “^1.0.8”, “hexo-server”: “^0.2.2”, “run-sequence”: “^2.2.0”} 然后输入以下命令安装依赖包 12npm config set registry https://registry.npm.taobao.orgnpm install 在blog/gulpfile.js中添加如下代码(没有的话则新建): 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273/* npm install 超时请使用:(两条命令在当前文件目录下执行) npm config set registry https://registry.npm.taobao.org npm install 或者: npm install -g cnpm --registry=https://registry.npm.taobao.org cnpm install*/var gulp = require('gulp');var debug = require('gulp-debug');var cleancss = require('gulp-clean-css'); //css压缩组件var cssversion = require('gulp-make-css-url-version'); //css资源添加版本号var uglify = require('gulp-uglify'); //js压缩组件var htmlmin = require('gulp-htmlmin'); //html压缩组件var htmlclean = require('gulp-htmlclean'); //html清理组件var assetRev = require('gulp-asset-rev'); //版本控制插件var runSequence = require('run-sequence'); //异步执行组件var changed = require('gulp-changed'); //文件更改校验组件var gulpif = require('gulp-if') //任务 帮助调用组件var plumber = require('gulp-plumber'); //容错组件(发生错误不跳出任务,并报出错误内容)var isScriptAll = true; //是否处理所有文件,(true|处理所有文件)(false|只处理有更改的文件)var isDebug = true; //是否调试显示 编译通过的文件// 压缩js文件gulp.task('compressJs', function () { var option = { // preserveComments: 'all',//保留所有注释 mangle: true, //类型:Boolean 默认:true 是否修改变量名 compress: true //类型:Boolean 默认:true 是否完全压缩 } return gulp.src(['./public/**/*.js','!./public/**/*.min.js']) //排除的js .pipe(gulpif(!isScriptAll, changed('./public'))) .pipe(gulpif(isDebug,debug({title: 'Compress JS:'}))) .pipe(plumber()) .pipe(uglify(option)) //调用压缩组件方法uglify(),对合并的文件进行压缩 .pipe(gulp.dest('./public')); //输出到目标目录});// 压缩css文件gulp.task('compressCss', function () { return gulp.src('./public/**/*.css') .pipe(gulpif(!isScriptAll, changed('./public'))) .pipe(gulpif(isDebug,debug({title: 'Compress CSS:'}))) .pipe(plumber()) .pipe(cleancss({rebase: false})) .pipe(gulp.dest('./public'));});// 压缩html文件gulp.task('compressHtml', function () { var cleanOptions = { protect: /<\\!--%fooTemplate\\b.*?%-->/g, //忽略处理 unprotect: /<script [^>]*\\btype="text\\/x-handlebars-template"[\\s\\S]+?<\\/script>/ig //特殊处理 } var minOption = { collapseWhitespace: true, //压缩HTML collapseBooleanAttributes: true, //省略布尔属性的值 <input checked="true"/> ==> <input /> removeEmptyAttributes: true, //删除所有空格作属性值 <input id="" /> ==> <input /> removeScriptTypeAttributes: true, //删除<script>的type="text/javascript" removeStyleLinkTypeAttributes: true,//删除<style>和<link>的type="text/css" removeComments: true, //清除HTML注释 minifyJS: true, //压缩页面JS minifyCSS: true, //压缩页面CSS minifyURLs: true //替换页面URL }; return gulp.src('./public/**/*.html') .pipe(gulpif(isDebug,debug({title: 'Compress HTML:'}))) .pipe(plumber()) .pipe(htmlclean(cleanOptions)) .pipe(htmlmin(minOption)) .pipe(gulp.dest('./public'));});// 默认任务gulp.task('default', function () { runSequence.options.ignoreUndefinedTasks = true; runSequence('compressHtml','compressCss','compressJs');}); 然后我们的上传命令就变成了 123hexo ggulphexo d 其实还可以继续偷懒,没办法,就是懒人才能改变世界……在刚才添加的`\"devDependencies\": {}`后面平行的添加如下代码 123"scripts": { "submit": "hexo clean && hexo generate && gulp && hexo d"} 这样之后,上传就变为了一条命令`npm run sumbit` 自动打开脚本 为了每次新建博文我们可以直接编辑,而不是在一堆文件中找到它再打开。我们需要在博客根目录新建script文件夹(已有就不用新建) 在新建的文件夹新建一个.js文件,其中填写的代码如下所示。代码来自这里 win用户 1234567891011var spawn = require(‘child_process’).exec;// Hexo 2.x 用户复制这段hexo.on(‘new’, function(path){ spawn(‘start “markdown编辑器绝对路径.exe” ’ + path);});// Hexo 3 用户复制这段hexo.on(‘new’, function(data){ spawn(‘start “markdown编辑器绝对路径.exe” ’ + data.path);}); Mac用户 12345678910var exec = require(‘child_process’).exec;// Hexo 2.x 用户复制这段hexo.on(‘new’, function(path){ exec(‘open -a “markdown编辑器绝对路径.app” ’ + path);});// Hexo 3 用户复制这段hexo.on(‘new’, function(data){ exec(‘open -a “markdown编辑器绝对路径.app” ’ + data.path);}); 仓库备份博客 依次执行下列命令 123git init # 初始化仓库git remote add origin git@github.com # 从仓库复制你的地址 .gitgit pull origin master 在/blog/目录下新建.gitignore文件(如果没有的话),里面内容如下。主要是为了忽略./public等无需备份的文件,加快备份速度。 1234567.DS_StoreThumbs.dbdb.json*.lognode_modules/public/.deploy*/ 本地写完博客上传后,只要依次运行下列命令就可以备份文件。 123git add .git commit -m "更新hexo源文件"git push origin master 当远程仓库有更新时,执行以下命令,即可同步hexo源文件到本地。 1git pull origin master 在你的其他电脑,只要git clone git@github.com #你的仓库地址就可以同步博客文件了。 自动备份博客脚本 程序员在变懒这件事情上绝对有着永无止境的追求!我们不仅会担心博客本地源文件的丢失,还会烦恼多台电脑文件同步困难。那么我们怎么解决这样的困境呢? npm install --save shelljs安装这个模块 在/blog/scripts/文件夹下新建一个js脚本(任意名字),如果没有/blog/scripts/目录,请新建一个。脚本内容如下:更改第十七行的内容 12345678910111213141516171819202122232425262728293031323334require(‘shelljs/global’);try { hexo.on(‘deployAfter’, function() {//当deploy完成后执行备份 run(); });} catch (e) { console.log(“产生了一个错误<( ̄3 ̄)> !,错误详情为:” + e.toString());}function run() { if (!which(‘git’)) { echo(‘Sorry, this script requires git’); exit(1); } else { echo(“======================Auto Backup Begin===========================”); cd(‘####你的地址’); //此处修改为博客根目录路径 if (exec(‘git add -–all’).code !== 0) { echo(‘Error: Git add failed’); exit(1); } if (exec('git commit -am "Form auto backup script\\'s commit"').code !== 0) { echo('Error: Git commit failed'); exit(1); } if (exec('git push origin master').code !== 0) { echo('Error: Git push failed'); exit(1); } echo("==================Auto Backup Complete============================")}} 这样在每次`hexo d`命令之后就能自动备份博客到设置好的代码仓库。成功后会显示如下类似内容 1234567INFO Deploy done: git======================Auto Backup Begin===========================[master cea81b4] Form auto backup script's commit 1 file changed, 1 insertion(+), 1 deletion(-)To #你的仓库地址 8f2653b..cea81b4 master -> master==================Auto Backup Complete============================ 此脚本在blog文件夹没有任何改动的情况下会报错,但不会影响上传。 博客自定义写作样式 这里从neveryu的建站日志引用部分代码,放入到themes/next/source/css/_custom/custom.styl中,即可生效。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337// 下载样式a#download { display: inline-block; padding: 0 10px; color: #000; background: transparent; border: 2px solid #000; border-radius: 2px; transition: all .5s ease; font-weight: bold; &:hover { background: #000; color: #fff; }}//阅读全文样式.post-more-link .btn { position:relative; border: 2px solid #000; border-radius: 2px; padding: 0 10px; font-weight: bold; background: transparent; transition: all .5s ease; &:hover { background: #000; color: #eee; }}//// 颜色块-黄span#inline-yellow { display:inline; padding:.2em .6em .3em; font-size:80%; font-weight:bold; line-height:1; color:#fff; text-align:center; white-space:nowrap; vertical-align:baseline; border-radius:0; background-color: #f0ad4e;}// 颜色块-黑span#inline-black { display:inline; padding:.2em .6em .3em; font-size:80%; font-weight:bold; line-height:1; color:#fff; text-align:center; white-space:nowrap; vertical-align:baseline; border-radius:0; background-color: black;}// 颜色块-绿span#inline-green { display:inline; padding:.2em .6em .3em; font-size:80%; font-weight:bold; line-height:1; color:#fff; text-align:center; white-space:nowrap; vertical-align:baseline; border-radius:0; background-color: #5cb85c;}// 颜色块-蓝span#inline-blue { display:inline; padding:.2em .6em .3em; font-size:80%; font-weight:bold; line-height:1; color:#fff; text-align:center; white-space:nowrap; vertical-align:baseline; border-radius:0; background-color: #2780e3;}// 颜色块-紫span#inline-purple { display:inline; padding:.2em .6em .3em; font-size:80%; font-weight:bold; line-height:1; color:#fff; text-align:center; white-space:nowrap; vertical-align:baseline; border-radius:0; background-color: #9954bb;}// 颜色块-红span#inline-red { display:inline; padding:.2em .6em .3em; font-size:80%; font-weight:bold; line-height:1; color:#fff; text-align:center; white-space:nowrap; vertical-align:baseline; border-radius:0; background-color: #df3e3e;}// 左侧边框红色块级p#div-border-left-red { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-left-width: 5px; border-radius: 3px; border-left-color: #df3e3e;}// 左侧边框黄色块级p#div-border-left-yellow { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-left-width: 5px; border-radius: 3px; border-left-color: #f0ad4e;}// 左侧边框绿色块级p#div-border-left-green { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-left-width: 5px; border-radius: 3px; border-left-color: #5cb85c;}// 左侧边框蓝色块级p#div-border-left-blue { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-left-width: 5px; border-radius: 3px; border-left-color: #2780e3;}// 左侧边框紫色块级p#div-border-left-purple { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-left-width: 5px; border-radius: 3px; border-left-color: #9954bb;}// 右侧边框红色块级p#div-border-right-red { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-right-width: 5px; border-radius: 3px; border-right-color: #df3e3e;}// 右侧边框黄色块级p#div-border-right-yellow { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-right-width: 5px; border-radius: 3px; border-right-color: #f0ad4e;}// 右侧边框绿色块级p#div-border-right-green { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-right-width: 5px; border-radius: 3px; border-right-color: #5cb85c;}// 右侧边框蓝色块级p#div-border-right-blue { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-right-width: 5px; border-radius: 3px; border-right-color: #2780e3;}// 右侧边框紫色块级p#div-border-right-purple { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-right-width: 5px; border-radius: 3px; border-right-color: #9954bb;}// 上侧边框红色p#div-border-top-red { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-top-width: 5px; border-radius: 3px; border-top-color: #df3e3e;}// 上侧边框黄色p#div-border-top-yellow { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-top-width: 5px; border-radius: 3px; border-top-color: #f0ad4e;}// 上侧边框绿色p#div-border-top-green { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-top-width: 5px; border-radius: 3px; border-top-color: #5cb85c;}// 上侧边框蓝色p#div-border-top-blue { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-top-width: 5px; border-radius: 3px; border-top-color: #2780e3;}// 上侧边框紫色p#div-border-top-purple { display: block; padding: 10px; margin: 10px 0; border: 1px solid #ccc; border-top-width: 5px; border-radius: 3px; border-top-color: #9954bb;}//动画模块//第一篇博客中-精于心,简于形-的动画(https://neveryu.github.io/page/2/)span#top-down-samll { display:inline; position:relative; border-top:1px solid #222; border-bottom:1px solid #222; font-size:110%; cursor:pointer; &:hover { background-color: #000; color: #fff; animation: animate-yu-1 3s ease-in; }}@keyframes animate-yu-1 { 0% { left:-10px; top:0px; } 10% { left:10px; top:0px; } 20% { left:-8px; top:0px; } 30% { left:8px; top:0px; } 40% { left:-5px; top:0px; } 50% { left:5px; top:0px; } 60% { left:-3px; top:0px; } 70% { left:3px; top:0px; } 80% { left:-1px; top:0px; } 90% { left:1px; top:0px; } 100% { left:0px; top:0px; }}//留言页面-[最近访客]-的样式span#top-down { display:inline; position:relative; border-top:1px solid #222; border-bottom:1px solid #222; font-size:130%;} 写作辅助 新建文件类型 hexo new post "title" 用来创建新文章 hexo new page "title" 用来创建新菜单页面 hexo new draft "title" 用来创建新草稿 hexo new "title" 用来创建新文章(默认) 关于目录 目录的层级靠###和####来维护,相差几个#就是相差几级的目录。 目录的最高层级为## 主题自带样式 note 标签首先要在 站点配置文件 配置如下信息: 1234567891011121314151617181920212223# Note tag (bs-callout).note:# Note tag style values:# - simple bs-callout old alert style. Default.# - modern bs-callout new (v2-v3) alert style.# - flat flat callout style with background, like on Mozilla or StackOverflow.# - disabled disable all CSS styles import of note tag. style: flat icons: true border_radius: 3# Offset lighter of background in % for modern and flat styles (modern: -12 | 12; flat: -18 | 6).# Offset also applied to label tag variables. This option can work with disabled note tag. light_bg_offset: 0 default灰色样式调用方式 <div class="note default"><p>default</p></div>primary紫色样式调用方式 <div class="note primary"><p>primary</p></div>success绿色样式调用方式 <div class="note success"><p>success</p></div>info蓝色样式调用方式 <div class="note info"><p>info</p></div>warning橙色样式调用方式 <div class="note warning"><p>warning</p></div>danger红色样式调用方式 <div class="note danger"><p>danger</p></div>danger no-icon红色无图标样式调用方式 <div class="note danger no-icon"><p>danger no-icon</p></div> just try just try just try just try just try just try just try 自定义数字块 ~/themes/next/source/css/_custom/custom.styl中添加下列代码: 12345678910// 自定义的数字块 span#inline-toc { display: inline-block; border-radius: 80% 100% 90% 20%; background-color: rgb(227, 242, 253); color: #555; padding: 0.05em 0.4em; margin: 2px 5px 2px 0px; line-height: 1.5;} 这是调用方式<span id="inline-toc">1.</span>和样式展示 1. 自定义颜色块自定义的颜色块标签,这么用: yellowblackgreenblueredpurple 颜色块标签内容 123<p id='div-border-right-red'> 块级框该这么用(自定义的比Next主题内置的优化要更加清晰好用):</p><p id='div-border-top-red'> 上侧块级框总共5个类型 </p><p id='div-border-left-red'> 类似的,侧边块级框比颜色块少一个黑色,分左右两种,总共十个类型 </p> 1<span id="top-down">文字的上下加横线</span> 文字的上下加横线 1<span id="top-down-samll">鼠标放这里有惊喜</span> 小一号文字,上下加横线 1234567#### 文本居中{% cq %}人生乃是一面镜子,从镜子里认识自己,我要称之为头等大事,也只是我们追求的目的!{% endcq %} 人生乃是一面镜子,从镜子里认识自己,我要称之为头等大事,也只是我们追求的目的! 添加视频采用如下代码,即可在博文中添加视频。更多的iframe标签参数设定在此处查询 1<iframe width="100%" height="540" align="middle" src="https://jalammar.github.io/images/seq2seq_6.mp4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> 参考文献 打造个性超赞博客Hexo+NexT+GithubPages的超深度优化 Hexo的Hnext主题个性化教程(33个小优化) neveryu的建站日志 thief的建站日志 很好的写作辅助","categories":[{"name":"blog","slug":"blog","permalink":"https://imbowei.com/categories/blog/"}],"tags":[{"name":"Github-pages","slug":"Github-pages","permalink":"https://imbowei.com/tags/Github-pages/"},{"name":"Hexo","slug":"Hexo","permalink":"https://imbowei.com/tags/Hexo/"},{"name":"Next","slug":"Next","permalink":"https://imbowei.com/tags/Next/"},{"name":"Web-design","slug":"Web-design","permalink":"https://imbowei.com/tags/Web-design/"}]},{"title":"【NLP competition】中文信息学会 文本溯源技术评测(SMP ETST)Ranking First","slug":"【NLP比赛】中国中文信息学会文本溯源技术评测(SMP-ETST)Ranking-First","date":"2018-07-09T00:10:43.000Z","updated":"2018-09-30T01:36:16.000Z","comments":true,"path":"2018/07/09/【NLP比赛】中国中文信息学会文本溯源技术评测(SMP-ETST)Ranking-First/","link":"","permalink":"https://imbowei.com/2018/07/09/【NLP比赛】中国中文信息学会文本溯源技术评测(SMP-ETST)Ranking-First/","excerpt":"此次的文本溯源项目我们以n-gram为核心思想,构建候选句子对的评测标准。用TF-IDF和词袋模型的的思想来预筛选候选句子对,大大提升算法效率。最后用了两种切词方式的模型融合和规则后处理(提升很小)。Final-Leaderboard Ranking First","text":"此次的文本溯源项目我们以n-gram为核心思想,构建候选句子对的评测标准。用TF-IDF和词袋模型的的思想来预筛选候选句子对,大大提升算法效率。最后用了两种切词方式的模型融合和规则后处理(提升很小)。Final-Leaderboard Ranking First 2018.07.24更新经过组委会测试算法的高效性和原创性,我们最终获得了SMP-ETSE测评的第一名。最终获奖名单评测任务介绍测评代码开源 序以前没有参加过NLP类型的比赛和测评,每天看论文想idea的日子有些许的枯燥和单调。就和一个同学趁着期末考试复习期间(实力作死)的空闲时间,抽出时间玩了玩这个比赛。SMP 2018 测评地址 题目分析本次的文本溯源题目和同期的另外两个比赛其实很相似。蚂蚁金服计算句子相似度拍拍贷识别相似的问题句子但文本溯源又和另外两个题有着本质的不同,因为主办方放出的数据并没有任何标签。很明显,我们需要一个无监督的算法来找到句子之间的潜在语义关系,红的发紫的深度学习在此没有用武之地。恐怕这也是为什么这个测评的参加人数如此之少的主要原因吧。 验证集 待溯源句子1000 候选句子约10W 测试集 待溯源句子4000 候选句子约500W 思路一根据我们之前的一些经验,探讨两个句子之前的相似性的时候,n-gram就是一个简单,并且行之有效的方法。这也是我们最早的想法。 思路二另一个想法,传统的NLP parsing技术在理论上会比简单的n-gram 方法更好的分析句子结构,从而帮助计算机理解句子语义,找到对应的句子。但是,整个代码构建工程量大,实现难度较高。 我们的当然要从简单的第一种思路入手尝试。(也是我们最后采用的方案) 预处理按照思路一构建一个简单的baseline,在没有调参和仔细预处理之前,在验证集上取得了0.8737 的成绩,这也给了我们继续这一方法的信心。 随后我们反过头来仔细进行预处理。 处理影响分词效果的杂乱字符 直接删除 将他们替换为空格 对于数据进行全半角格式转换(计算机并不认为相同字符的全半角格式是一样的字符) 符号预处理之后,在验证集获得了0.9008的表现 ,然后又轻微调参(根据不等式,我们知道,P、R相等的时候,F值表现会是最好的),验证集表现上涨到了0.9087。 切词在预处理方面,切词是最令人头疼的第一个地方。我们有了很多开源的切词工具,最终选了用了thulac和jieba两种。 我们发现这两种切词方法的本身都有一定的局限性,但是又有一定的互补性。虽然用两种切词工具在时间上会对花费很多,但是为了更好的算法效果,我们采用两种切词方式(后来想想好像有点亏,这样的处理大约只能带来一个点的提升,但花费了大量的时间)。 python 代码运行效率的低效众所周知,对于测试集500W句子的数据量来说,可谓是十分头疼。 解决方式也很简单,直接调用两种切词方法的c++接口就好了。就可以体验飞一般的速度。 值得注意的是,thulac 的切词包在大数据量的情况下,会有崩溃的情况,原因未知。我们的处理方式是将500W数据切分成了四份,调用四次thulac的c++接口(多了三次的model载入时间),切词后再将所有数据合并起来。 TF-IDFn-gram 方法固然简单高效,但也很容易想到一个缺陷。我们不应该对于所有的gram“一视同仁”! 所以我们建立了TF-IDF,根据每个词语在文档中的几个句子中出现,设立TF。并且设立反向的IDF,为了不同频次的词语反向加权。 这使我们的验证集F值表现达到了0.9356。 优化目标对于深度学习,大家都知道。当我们的loss和最后的评价指标越相近的时候,模型的训练效果也往往是更好的。 一个简单的n-gram 通常是仅仅考虑精确率,我们为什么不进一步的考虑召回率呢?甚至直接对于F值进行优化?这里有一篇ACL2014的文章作为参考 这样的优化操作之后,我们的验证集表现达到了0.9430 倒排索引(词袋模型)以上主要是在算法精度上的优化,并且没有可以的优化算法效率。导致我们在每一次对齐的时候都要对10W数据做遍历比较…… 为了使算法快点出结果,我们用了多进程的方法,但这显然不是长久之计。 经过观察发现。10W句子中的绝大多数句子,算法评价两个句子的相关性,都极低,对于我们的溯源任务造不成任何干扰,那么如何去掉他们呢? 不难想到,我们的算法基于n-gram,而对齐表现差的句子显然和目标句子重合的n-gram非常少。那么,我们为什么不讲这样的句子直接过滤掉呢?可以减少句子对的评价次数几百倍,大大提升算法运行效率! 具体的,我们首先用one gram对句子进行过滤(候选句子中连一个词语都没有出现在目标句子中,全部去掉不考虑);进一步的,还可以对 two gram 设定一定的阈值。让我们在算法精度和运行速度上进行权衡。 最终,我们算法经过此处理后。在10W验证集上的表现,从单进程500min缩短为了40s 以下,还没有损失精度! 模型融合 & 后处理以上提到了两种切词方式,以及两种预处理方式。为了取得更好的算法效果。我们从它们排列组合后的四种方法中挑取了两个互补性较强的model进行模型融合。验证集达到了0.9549的数值水准。 然后我们肉眼观察一些阈值附近的“疑似”对齐错误的句子。建立几个规则性的后处理操作。验证集达到了0.96036的数值水准。 最终测试集结果 硬件环境 Intel(R) Xeon(R) CPU E5-2697 v4 @ 2.30GHz 内存 188 GB Linux version 3.10.0-514.el7.x86_64 , gcc version 4.8.5 20150623 (Red Hat 4.8.5-11) Python 3.4.5 ,numpy 运行时间参考 预处理时间共 1267秒 (21.1分钟) 符号处理 & 编码格式转换:218秒 THULAC分词(c++版本):272秒 jieba分词(c++版本):112秒 计算TF-IDF 164秒 建立倒排索引表 501秒 核心算法:115秒 (1.9分钟) 最后数值表现 F1-Measure : 0.801258108905052 Precision: 0.7133356667833392 Recall : 0.9139013452914798 Ranking: First 尾声虽然时间紧迫,经验不足。在比赛中和队友都有一些失误,但最终侥幸排名第一。 做的不够好的地方: 预处理不够精细 切词处理没有去增加一个字典 懒得去寻找同义词源,或者训练一个词语级别的翻译模型。理论上可以进一步提高算法表现。 由于留给测试集出结果的时间只有24h,事先准备的代码不够充分。 在测试集阈值设定的时候陷入了思维误区,算法最终的F值结果损失精度百分之三以上。 做得比较好的地方: 基本的n-gram 思路简单而高效。 TF-IDF使算法的评价方式更加合理。 倒排索引是使算法高效,简洁。 艰苦卓绝的后处理和肉眼调参…… 最后:感谢队友这些天的付出,也感谢努力的自己。","categories":[{"name":"NLP","slug":"NLP","permalink":"https://imbowei.com/categories/NLP/"},{"name":"Competition","slug":"NLP/Competition","permalink":"https://imbowei.com/categories/NLP/Competition/"}],"tags":[{"name":"Paraphrase","slug":"Paraphrase","permalink":"https://imbowei.com/tags/Paraphrase/"},{"name":"N-gram","slug":"N-gram","permalink":"https://imbowei.com/tags/N-gram/"},{"name":"Segment","slug":"Segment","permalink":"https://imbowei.com/tags/Segment/"},{"name":"Information-retrieval","slug":"Information-retrieval","permalink":"https://imbowei.com/tags/Information-retrieval/"},{"name":"BoW","slug":"BoW","permalink":"https://imbowei.com/tags/BoW/"},{"name":"Inverted-index","slug":"Inverted-index","permalink":"https://imbowei.com/tags/Inverted-index/"}]}]}