Javascript操作CSS
TL;DR : js的一个重要功能,就是实现网页的各种交互效果。主要是通过添加事件处理函数,然后修改DOM元素的style,或者添加预制的css class来实现各种前端展现。
TL;DR : js的一个重要功能,就是实现网页的各种交互效果。主要是通过添加事件处理函数,然后修改DOM元素的style,或者添加预制的css class来实现各种前端展现。
安利一下udemy上的这门课Object-oriented Programming in JavaScript,让我明白了很多困扰我很久的概念。
我没正规做过前端开发,连现在所谓的web后台开发都没做过,这是我始终进展很慢的原因之一。因为别人提到的技术实现,我根本看不懂,即使是花钱,也没法判断投入的是否合理。
我个人的经历与前端开发、javascript简直就是平行空间,就想和现在的邻居,虽然都生活距离很近,但貌似谁也不了解对方的状态。
javascript的标准叫ECMAScript,99年出版的ES3,我可能看过一点,但是那个时候觉得MFC牛逼,甚至操作系统、汇编才牛逼,就压根不喜欢看和界面有关的一切技术。没想到差不多到现在界面技术反而前后通吃了,而且更容易做一个产品出来,后台技术只能做幕后英雄了。ES5是2009年发布的标准,2015年大佬们又发布了ES6,也就是ECMAScript 2015,估计未来还会有ES7,ES8,ESX。。。
随着对用户体验要求越来越高,前端代码肯定越来越复杂,大佬们希望通过更多的语言特性,使前端开发更加工程化。工程化有啥内涵,我也不是很了解,但至少现在能看到的就是模块化,然后提供更便利的工具。
1 | //JS里面创建一个对象最简单的方式是通过{}来直接建立 |
想在自己的Hexo博客上加个评论功能。Hexo是个基于node.js静态博客系统,可以利用github page发布个人博客。这类博客系统添加评论系统,都是通过增加一个js代码,将评论信息提交到后台存储起来。(怎么调动回来的??)
网上搜了一下,发现有很多的备选方案,选择了最简单的Valine。还有gitcomment是基于github issue系统保存评论数据,但需要github账号登录。(github issue怎么用??Oauth是什么?)
Valine需要在LeanCloud上注册一个账号,所有的数据会保存在LeanCloud上。
在什么地方添加Valine的js代码呢?网上很多文章是说新版的NeXT已经添加了Valine的功能,只要修改配置就可以了,但是想多了解一些Hexo和Next主题的内部机制,所以想自己动手修改。代码看的很费劲,Hexo基于node.js用到了很多Node提供的全局对象,而且又做了很多的概念抽象,代码看起来一点都不容易。主题的代码也是懵逼,里面全是.swig结尾的文件,后来才知道是一个模板引擎的文件后缀。
最后终于找到一篇文章说,主题渲染的入口是_layout.swig文件,Hexo会根据source目录下的所有md文件,使用特定的模板进行渲染,默认使用post.swig文件进行渲染。所谓渲染,我的理解就是进行各种生成和替换,最终生成一个静态HTML。
1 | new Valine({ |
就是把这样一短代码加入到post.swig中,就可以展示评论输入框了。调试的时候差了一点,还需要去LeanCloud上建一个Comment类,这时Valine就可以提交代码了。
最近在看NLP,其中的基础就是word embedding,我也看了cs224n的课,也看了那个关于word2vec的论文,但我看到的就是优化这么一个目标函数
logσ(vwO′TvwI)+i=1∑nEwi∼Pn(w)[logσ(−vwi′TvwI)]
这是什么?原论文基本没有写细节。我特别想知道,这样的函数怎么做back propagation。于是总算找到这个:《word2vec Parameter Learning Explained》。人家确认牛,不仅深入浅出的给出数学推导,还能给出一个直观的,说人话的解释,让人更加能够明白word2vec到底在干什么。我想尝试整理一下,看看都学到了哪些,所以总结如下:
训练word embedding的网络结构是这样的,他的隐藏层后面并没有任何非线性函数。
为了说明计算过程,模型简化为1对1 的预测,类似bigram。
模型的输入到hidden的计算是
h=WTX=W(k,.)T
X是one-hot向量,是V*1的列向量,W是V*N的矩阵,就是word embed,每行代表词表中的一个词。h是N*1的列向量。
h向量就是W的第k行,也就是词表中第k个词的向量。$$W^{'}$$ 是N*V的矩阵,可理解为另外一组word embed。 从h预测output时,相当于是输入词的embed和输出词embed做内积,得出一个score u
u=W′Th
u是V*1的向量,通过softmax,得出预测的每个词的概率y $$ y_{i} = \frac{exp(u_{i})}{\sum_{k=1}^{V} exp(u_{k})} $$
有了预测概率,有了true target,就可以通过交叉熵来计算损失函数了,经过基本变形就得到了
\begin{align*} E &= - log \space y_{j^{*}} \\ &= -u_{j^{*}} + \log \sum_{j'=1}^{V} exp(u_{j'}) \end{align*}
我真正的困惑是从下面开始,不知道怎么去做导数反向传递,好在《word2vec Parameter Learning Explained》给出的推导过程特别详细,我才能勉强看懂。
h=WTX=W(k,.)T
u=W′Th
yi=∑k=1Vexp(uk)exp(ui)
E=−uj∗+logj′=1∑Vexp(uj′)
就是这几个公式依次求导。可是反向求导为啥难理解呢,我觉得主要是因为,前向过程都是用矩阵或向量计算的,求导时需要很多变换,还需要考虑转置的问题,行列的问题,转换步骤一多,思维就乱掉了。
首先求关于$$u_{j}$$ 的导数
∂uj∂E=yj−tj:=ejj∈[1,V]
然后求关于$$W_{i,j}^{'}$$ 的导数
\begin{align*} \frac{\partial E}{\partial W_{ij}^{'}} &= \frac{\partial E}{\partial u_{j}} . \frac{\partial u_{j}}{\partial W_{ij}^{'}} \\ \\&=e _{j}.h_{i} \qquad\qquad j\in [1,V]\quad i \in [1,N] \end{align*}
这个要理解我觉得最好还是把矩阵画出来,然后一步步去推导比较容易理解。其实最后$$\frac{\partial E}{\partial W^{'}} $$ 会最终变为一个矩阵,参数更新也都是通过矩阵运算的方式。这个公式在原论文中给出了一个直观理解,就是对于输出参数矩阵的每个词,根据预测的概率误差,相应的远离输入词。相当于这次word vector在他们的高维空间,不停的移动,已获得最佳的位置。当训练样本足够多了,每个word vector也就基本稳定不会移动了,这时候就可以把参数矩阵拿出来直接当做word embedding使用了。这些word embedding中包含了很多语义特征。
其他的推导懒得写了,如果以后忘记了,就回看论文好了。
以前总听别人说做广告CTR需要用到LR,经常会在log中提取各种特种,一般是从Hadoop中跑出特征,然后再放到LR的并行系统上,进行计算,然后通过划分实验流量,做A/B Test。如果效果好,则新特征上线。
而我之前由于没有ML的基础,所以直接学NN,感觉全世界就只有NN,回头想想好像LR还是能够在其他很多场景下应用。
LR和NN的区别主要在于,LR是把一个线性函数
σ(z)=1+e−(Wx+b)1
对于线性函数,他的能力有限,比较直来直去,无非就是直线或者平面,来区分所有样本。这样对于一些比较复杂的样本分布,就会产生很多误差。
第一个图是逻辑回归对复杂数据分布的分类情况,第二个图是神经网络hidden layer有4个节点的分类情况(参考:Planar data classification with one hidden layer)。明显具有hidden layer的NN表现更好。科学家们好像能够证明NN可以表示任何复杂的函数,我没必要深究其中的数学证明了。
我目前的理解就是,神经网络把多个神经单元(线性函数+激活函数)整合在一起,然后在隐含层通过一种无法描述的魔力自行提取特征,然后在最后一层,仍然用线性分类函数对结果进行分类。后面的Loss function、SGD就都是一样的了。神经网络多了一点就是BP算法,主要的原理就是复合函数求导。前一篇(http://wliang.me/2018/02/05/20180205_DL学习笔记_逻辑回归/)的时候我也总结过。
我想总结时没比较加入太多数学公示,还是把直观的理解通过文字图表表达清楚最好,毕竟我又不去做research,我只是想做application。对自己放松点要求。
Python这个语言在语法上,数据结构上提供了很多遍历,使得开发代码量上了很多。
每次看别人的Python代码总能学到一些新的用法,以下几个小收获记录下来,算是一点总结:
1,tuple
1 | x = 'wangliang' |
2,zip函数可以把两个序列,按位置先后,两两组成一个tuple pair,很方便形成dict
1 | x = 'wangliang' |
3,sorted函数可以对序列类型进行排序
4,dict按值排序
1 | #https://stackoverflow.com/questions/613183/how-do-i-sort-a-dictionary-by-value |
这些方便的数据处理方式,可以应用到机器学习的数据预处理上。机器学习模型部分实现代码量不大,而且有很多框架可以直接调用。但是数据预处理部分就要自己来了。
提到ML,很郁闷。最近一直在看NLP,但是发现看论文好难找到通透的感觉,而且数学基础不够,也导致问题多多。这个会不会又是一个大坑呢。反正,在不为钱发愁的情况,尽量做自己能做且喜欢的事情吧。
y^=σ(wTX+b),where σ(z)=1+e−z1
Loss=−(ylogy^+(1−y)log(1−y^))
Cost Function:
J(w,b)=m1i=0∑mL(y^,y)
梯度下降:根据LostFunc,给出dw,dx,db 的计算式,得到值。每个变量,沿梯度方向变化一点,整个loss就会变化,不停的反复迭代,就会找到最佳的参数。
我一直有个错误的认识,就是dw, db和Loss值有关,dw,db需要使用Loss值进行计算,其实不是,dw只和LostFunc的表达式有关,只和其他参数当前值有关,有没有Loss值都不重要,只是每次迭代之后,需要看看Loss是不是在减少了,而不需要通过Loss计算梯度。
简单的路由绑定就像这样
1 | @app.route('/') |
在Flask内部可以这样做
1 | def index(): |
在add_url_rule函数中核心代码主要是这几行
1 | rule = self.url_rule_class(rule, methods=methods, **options) |
其中url_rule_class和url_map都是利用的werkzeug.routing的代码,核心的类就是Rule, Map, MapAdapter,代码看的我头疼,一方面现在智力下滑严重,很多看不懂,另外一方面,感觉怎么这么麻烦不就是简单的从url到具体函数的匹配么?可是深入看的话,发现人家的功能确实强大,比如可以进行变量转换,还能生成url。