深度学习第二周课程(下)

上一章节提到的梯度下降(Gradient Decent)过程需要多层嵌套For-Loop循环。这种循环非常耗费计算资源。为了降低计算资源消耗,提升计算效率,本章节引入向量计算(Vectorization)的概念。本章的主要内容也是围绕着向量计算和使用Python中的numpy库来实现限量计算的过程。

本章课程内容目录(与本文无关):

  • 向量计算(Vectorization)
  • 使用向量计算逻辑回归(Vectorizing Logistic Regression)
  • 使用向量计算逻辑回归中的梯度下降(Vectorizing Logistic Regression’s Gradient)
  • Python的广播(Broadcasting in Python)
  • Python/numpy向量的介绍
  • 逻辑回归里的Cost Function解释

安装一下jupyter

本章开始需要进行练习,Python是必须要装的,强烈建议Python3,课程使用Jupyter,这里也提示了一下安装,不过后来发现好像用处也不大。这个工具主要是可以把Python的程序脚本和文字进行混排,方便与演示。如果从来没有接触过Python的话,可以考虑用一下,毕竟这个是课程也在用的环境。如果有一点基础的话,Python有自己的IDE工具,PyCharm,很好用直接下载就行。

安装Python&Jupyter。因为一直写Python所以这个一直有没什么大问题,但是Jupyt这个倒是头一次见,好像是一种基于Browser的IDE,挺有意思的。具体可以访问以下几个地址:

  • 安装Python,我一直用Brew install就好了
  • 安装Pip,不过因为买了这个新电脑以后就没怎么写代码,所以竟然没有Pip。这个倒也不难,随便上网搜索“install pip”,两步简单操作就搞定了
  • 安装Jupyter,没有按照web上说的用pkg包的方式,只是担心会安装额外的Python3.所以选择了通过pip命令行形式进行安装。

OK,三个安装结束,键入下面命令,直接启动Browser的界面

1
jupyter notebook

下面是标准编辑页面(竟然Hexo的asset_img可以用,好激动,但是asset_link确实不行,估计是因为marked里面escape的问题)

首界面很简单,就是系统文件夹。右上角有新建功能,可以新建一个可运行的python文件。在课程中,Andrew主要介绍了 np.dot(i,j) 在程序中对比for-loop,超过300倍的优势。笔者后来自己查了一下原因,看来主要还是回到了Python作为解释性语言本身的问题。为了对初学者友好,Python作为解释性语言牺牲了许多性能上的东西。而np.dot之所以much faster,主要原因是一句Python语言,对应的是用C写成numpy库,这个库会将输入进来的数据进行编译,形成编译后的语言进行调用。这种方法,远好于Python一个字符一个字符的进行读取,并根据语法分析器进行描述,占据了大量的时间。当然其他原因也有许多,比如借助编译可以使用CPU或者GPU的SIMD指令集(Simple instuction multiple data)进行并行计算,大大提升效率。根据文章将,numpy的效率可以是原生python的2万倍。而据说选用cpython会达到20万倍之多。具体原理可以参看知乎上的这篇文章:

python的numpy向量化语句为什么会比for快?

建立神经网络的主要过程

先来回顾一下基础算法:

For one example $x^{(i)}$:

The cost is then computed by summing over all training examples:

建模过程

  • 定义模型结构(例如输入feature的数量)
  • 初始化模型参数
  • 升级参数(Gradient Descent)

讲上述三个部分逐个建立并整合进一个叫做model()的 $function$ 里。几个简单的 $function$ 会包含的 $sigmoid$ , initialize_with_zeros() , propagate()

特别说明,关于 propagate() 的算法回顾如下:
Forward Propagation:

  • You get X
  • You compute $A = \sigma(w^T X + b) = (a^{(1)}, a^{(2)}, …, a^{(m-1)}, a^{(m)})$
  • You calculate the cost function: $J = -\frac{1}{m}\sum_{i=1}^{m}y^{(i)}\log(a^{(i)})+(1-y^{(i)})\log(1-a^{(i)})$

Here are the two formulas you will be using:

下面的Code里面用到了一些“内积”、“外积”、“General Dot”的概念。在课程中有相关的联系材料。具体参见这个解释可能会更加实在

使用numpy进行行列式乘积的计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
m = X.shape[1]

# FORWARD PROPAGATION (FROM X TO COST)
### START CODE HERE ### (≈ 2 lines of code)
A = sigmoid(np.dot(X.T, w) + b).reshape(1, -1) # compute activation
cost = - (1/m) * np.sum(Y*np.log(A) + (1-Y) * np.log(1-A)) # compute cost
### END CODE HERE ###

# BACKWARD PROPAGATION (TO FIND GRAD)
### START CODE HERE ### (≈ 2 lines of code)
dw = 1/m * np.dot(X, (A-Y).T)
db = 1/m * np.sum(A-Y)
### END CODE HERE ###

assert(dw.shape == w.shape)
assert(db.dtype == float)
cost = np.squeeze(cost)
assert(cost.shape == ())

grads = {"dw": dw,
"db": db}

return grads, cost

总结一下,这里建立的初始模型包括
$sigmoid$, $initialize$, $propagate$

优化模型参数(Optimization)

  • 初始化参数
  • 计算cost function
  • 通过梯级下降的方式进行参数更新并计算w和b的结果()

最近基本的梯级下降依据如下:

where $\alpha$ is the learning rate

总结一下,这里建立的初始模型包括
$initialize$, $optimize$, $predict$

整合模型

合并模型建立$model$,使用plot建立拟合线

深度学习第二周课程(上)

这是一个比较数学化的一章。本章课程主要分为两部分(数学基础 + Python编程实践)。

让我们先来看看第一部分。该部分内容重点是基于神经网络的一个基础数学模型,其中包括:

  • 二元分类(Binary Classification)
  • 逻辑回归(Logistic Regression)
  • 逻辑回归中的Cost Function(Logistic Regression Cost Function)
  • 梯度下降(Gradient Decent)
  • 导数(Derivatives / Derivatives Examples)
  • 计算图(Computation Graph)
  • 计算图求导(Derivatives with a Computation Graph)
  • 梯度下架求逻辑回顾(Logistic Regression Gradient Decent)
  • 对m样本的梯度下降(Gradient Decent on m Examples)

下面我们分部分进行一些描述:

深度学习概论

在Andy Ng所讲的深度学习课程里,第一周的课相对比较简单,基本上以通识介绍为主。课程分为了一下几个部分:

  • 什么是神经网络
  • 监督学习的神经网络是什么
  • 为什么深度学习开始受到重视
  • 三巨头中的Geoffrey Hinton访谈

第一部分,什么是神经网络(Neural Network)

看一下关于房价是如何预测的,以及什么是Hidden Unit

第二部分,监督学习的神经网络是什么(Supervised Learning)

在神经网络中的监督学习是这个样子的

针对与结构化和非结构化,还是有一定区别的

第三部分,为什么深度学习开始受到重视(Why Neural Network take-off)

一张图片说明一切

第四部分,Geoffrey Hinton访谈

这部分是一个访谈,不算是学习内容。讲述了Hinton个人的成长,学习等等吧。两个有意思的Highlight

  • Hinton本人大学学生物物理,研究生学习心理学,博士开始研修AI,这也是为什么他在神经网络能做出重大贡献的主要原因吧
  • 另一个关键是对GAN的学习,生成对抗网络方面的了解。如何在unsupervised的情况下进行学习

关于如何用Hexo书写数学符号(深度学习前哨贴)

翻了几个帖子,总算是搞定了。最主要的帖子是以下两个

在hexo博客中使用Mathjax写LaTex数学公式”
如何在 hexo 中支持 Mathjax?
描述在 hexo 中使用矩阵的方法

另外,按照Hexo文档上写的,理论上Hexo-math应该已经支持MathJax了,但是似乎用起来有点问题,不知道是hexo文档的错,还是我自己那个地方配置有错,以后找时间在研究吧。地址如下:
https://github.com/hexojs/hexo-math

还有最后要提醒一点,本次修改以后,不能用Hexo原生提供的assert方式来写作了,需要使用纯markdown模式。目前感觉良好,不知道后续会不会有什么坑。目前看这个改变不会影响之前的东西。

markdown的书写格式

这是一个公式 $E=mc^2$
Simple inline $a = b + c$.

大功告成,接下来需要学习MathJax了
MathJax一些说明
原文文档

ISO27001工作记录之一声叹息

因为要和许多中国/国际企业合作,我们需要一套更加完备的信息安全认证。所以这两个礼拜搞ISO27001搞的很心烦,于是写写27001的概念,顺便聊聊认证体系。

  • 关于ISO27001:

    ISO27001认证,由英国标准协会(BSI)于1995年2月提出,中文全称《信息安全管理实施细则》(BS7799-1:1995)。它提供了一套综合性的、由信息安全最佳惯例构成的实施细则,目的是为确定各类信息系统通用控制提供唯一的参考基准。1998,提出了第二个部分,中文全称《信息安全管理体系规范》,它规定了信息安全管理体系的要求和对信息安全控制的要求。2005年被ISO国际标准化组织采纳,形成了ISO/IEC 27001:2005。完整的ISO27001包括了11个方面、39个控制目标和133项控制措施。是一个不折不扣让一个互联网人晕到吐血的管理制度。主要11个方向包括:

    1. 安全方针
    2. 信息安全组织
    3. 资产管理
    4. 人力资源安全
    5. 物理和环境安全
    6. 通信和操作管理
    7. 访问控制
    8. 信息系统获取、开发和维护
    9. 信息安全事故管理
    10. 业务连续性管理
    11. 符合性

    通过对整个ISO27001这11个方面的落地,实现一个ISMS(信息安全管理系统)。这里特别说明,这个系统不是互联网概念上的系统,指的是一个体系化的东西,包括了上面所属管理、行政、人事、信息技术等各个方面。详细的就不在这里说了,实在是好多。目前这个工作已经在做了,这里给大家看一下我们的列表,这里面大概60%是技术团队要做的。

  • ISO27001与HIPAA

    之前有不少人问HIPAA的事情,现在估计也会有不少人问ISO27991和HIPAA的区别。所以这里简单说明一下。从概念上说,ISO是一个标准,可以由相关评级机构进行评级,办法符合标准的认证证书。这个证书可以用来和企业进行合作,以表明我司在信息安全方面的准备和能力是充分的。而HIPAA是一个法案(也可以说是一个法律),就是每个医疗相关企业遵守是必须的,不遵守如果被举报就要吃官司。哦,对了,这里还要特别说明,ISO和医疗无关,HIPAA是专门为医疗信息保护准备。所以ISO主要讲的是信息保护这个系统工程要做哪些和怎么做;而HIPAA虽然原则上提供了一些强制性的标准和工作方法,但是其核心内容更加强掉哪些信息是禁止泄露的。

    所以说,本次公司的ISO27001认证,我们也是请了相关具有评估资质的公司来进行评审。

  • ISO27001我们所做的和下一步需要做的事情

    下一步主要要做的事情就是完善文档和制度了。这里我想特别说明,之所以我会很重视这件事情,不是为了完善文档和制度,反而是从一个专业技术的角度,想想怎么从里面尽可能找些方法,避免繁琐的文档和制度。在我心里,过于完善的制度和方法,对研发和快速迭代,快速试错本事是有害的。所以,尽最大程度的减少ISO27001对互联网团队的伤害,是我最近想研究的一个话题。有了结果的话,可以再写一篇博文了,呵呵。看一下一片标准的ISO27001文档的样子,像下面这种文档理论上是每次都要写的。做过企业软件的人,应该知道。

总之,ISO27001确实是一个挺麻烦的东西。但是,从企业合作的角度,又不得不去做,并且也可以成为公司系统安全方面比较好的一个PR背书,从这一点上看,质量体系的工作比HIPAA的工作实际上在中国更有公信力。所以吧,对于我来讲对于这东西属于虽然很反感,不屑,但是又知道很有用,不得不去做的东西。希望看到文章的技术兄弟,也是对此表示一种尊敬吧。我自己承认,了解还是有必要的,只是要做多少,大家根据实际情况做到心中有数就好。

无UI系统设计之再建图灵

在过去的十年时间里,从微软到ThoughtWorks,再到后来做了杏树林,历经了Symbian,Windows Mobile,然后的Blackberry和Android,直到后来的iOS,WP,设计了一个又一个从前到后的系统架构,差不多经历了大半个移动时代的发展。还算完整的工程师生涯让我对用户体验和人机交互有着格外的感情。直到有一天,一场争论让我陷入了沉思。

事情缘起于对后台运维系统的设计。在最开始季度初的时候,我雄心勃勃给DevOps团队定义了一个目标,让运维同学学会使用Axure作出产品设计原型,推演操作路径。这在我们这种搞移动产品设计起家的人眼里是顺理成章的事情。然而,技术专家的反对,却给了我一闷棍。后来想来,UI设计对于运维系统而言简直是极大的浪费。原因如下:

  • 运维系统的核心任务,是提升运维人员的工作效率,提升运维质量(降低运维差错率)
  • 运维系统的面向对象,熟练的操作人员(研发、运维)
  • 运维系统的研发目的,以最快速度,解决现有问题

第一个很重要的原因就是,正是因为如上所述,要快、要高效的面对熟练人员。如果是工作效率在运维系统中可以使用机器来尽量多的完成任务的话。那么“快”在运维系统的研发中就显得格外的重要。其实,当今世界上最简单的,也是最早出现的交互见面便是Terminal。在Terminal的情况下,大量的UI工作和交互工作都转化成了基本的命令,不再需要写表单,调整在不同窗口大小情况下的适配,也不用做繁琐的IE,Chrome等浏览器适配工作。这让DevOps研发更多的关注于“核心任务”,就是用机器方法提升工作效率本身,让出了核心功能外的代码降低到最大程度。

第二个原因,其实,随着后移动时代的到来,越来越多的人已经开始从2007年手机触屏所带来的一股极大的UI交互体验旋风中走了出来。渐渐的,一种更加方便简易的形式在兴起。Cortana, Google Now和Siri,人机对话。其实,早在Symbian时代,就有一家著名的公司Nuance公司,从事语音识别,而且效果已经很高了。不过微软、Google和苹果在识别的背后加入了更加强大的语音分析引擎,让识别结果更加语意化,可以基于场景来从事更多的工作。因此,如果说过去我们在交互这个领域,还在苦苦追求更加简单、易于理解和上手的人机交互的时候。新的机遇自然语言或者简易自然语言的交互,很可能会在不远的未来改变我们的生活,而这一切,一定会从技术本身开始。

Github去年发布了非常有意思的办公自动化软件Hubot,他通过添加adaptor的方法,想Hubot注入更多语言交互指令,让Hubot可以通过一系列在Chat过程中的指令模式完成操作。其实本质上说Hubot和Terminal的工作原理并没有多大不同,但是这一次,对话不再仅仅限制在Terminal上,更加无需了解很复杂的ip地址和命令。如今的交互在IM软件上,通过一些预先设定的语言类指令来完成。

前段时间,Google发布了他们的语言搜索系统,WWDC在新版的macOS上面加入了语义搜索功能。可以想见,ChatOps,ChatOffice,ChatXXX为代表的一系列人工语音交互模式,将会实现。那么如今,我们要做的,就是把业务内核准备好,剩下的就是不断探索更新的技术所带来的便捷。

最后,写到这里的时候,我忽然想到了一个事情--图灵实验。1950年,图灵发表了具有里程碑意义的论文《电脑能思考吗?》,在里面第一次提到了人工智能的概念。图灵对人工智能的描述就是,有一堵墙,墙上有一个小窗口,窗口的两侧,一边是人,一边是具有人工智能的机器。如果两方都认为对方是人的话,则实验成功。现在看起来,这样的日子真的不远了。:)

关于文字集与编码

写Python2的人,很多人都见过下面这行Error

1
2
3
4
5
6
Traceback (most recent call last):
File "/Users/Jack/Documents/ApricotForestDoc/2_product_rnd/redspiderlily/mailfetcher.py", line 35, in <module>
if is_reply_mail(subject):
File "/Users/Jack/Documents/ApricotForestDoc/2_product_rnd/redspiderlily/module/mailutil.py", line 46, in is_reply_mail
return ("回复" in subject_.lower()) or ("re:" in subject_.lower())
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)

上一次聊到Python3升级的一个重头就是unicode编码。所以这次想重点就聊两句字符编码。说实话就是在此之前自己也有些算不清楚。所以还是深入的跑到wiki上研究了一番,分享供参考。

ASCII,全称American Standard Code for Information Interchange,是一个字符编码标准。使用0-127(2^7)的数字代表不同的英文字符,这里包括大小写字母,空格,特殊字符等。这是一个大家都比较熟悉的字符集标准,可以看看下面图中的内容。这里不做赘述。

但是,ASCII因为标准内含有的有限,带有音标的字符‘é’就无法很好的表述,更别提汉字了。到了1980年代,计算机技术发展,那时候大家已经开始使用字节(byte)来作为计算机基本计数单位。1byte=8bit(2^8=256),所以可以表述的字符变多了。那个时候开始出现了实用128-255这些数字表示发音单词。所以直到今天,你去看word里面的字符表,Latin依然可以看到这个顺序关系,大体就是这个原因。

再之后,当世界各地的语言发展出了各自不同的字符集体系,比如中国简体(GBK,GB18030),中文繁体(Big5,以前有个特别扯的名字叫做大五码),法语(Latin1),日语等等。本来各种语言字符集各自写互不干扰,倒也相安无事。但是,世界大融合嘛,于是问题来了。有人需要在中文里写上一段日语,就像这样 ++“日本語にほんご”++ 。于是问题就来了,怎么才能在同一个文件里现实不同的字符集的字符内容呢?1980年,人来开始尝试解决这个问题,并制定了一个新的计算机工业标准用以规范的处理、表示和编码全世界主要文字。这个标准叫做Unicode(全称是The Unicode Standard)。目前,Unicode标准是8.0,已经包含了全世界已经有超过12万个字符,覆盖129种现代和历史上的语言种类。在这里面需要说明一个额外的概念叫做Universal Coded Character Set (UCS,也叫做ISO 10646)。按照Wiki对于Unicode和UCS的说法,目前两套字符集应该是完全相同的。同一个数字在两个字符集里所代表的字符应该是相同的。但是Unicode的外延要多一些。USC仅仅是一个字符集,而对应的Unicode同时还规范了校对、标准化、表示顺序的算法等。就如同本文提及对Unicode的定义一样,Unicode出来包括了字符集,还有表现和处理方法的部分。因此Unicode应该说是一个更加广泛含义上的标准。

理论上说,Unicode字符集或者UCS有110万字符点数可以被分配,目前时机分配成16个Plane,其中Plane0,被叫做BMP(Basic Multilingual Plane),一共65536个,其中绝大部分是中文(Chinese),日文(Japanese)和韩文(Korean),三者合称CJK。

这里需要特别提一下Chinese Simplified(GBK,GB18030),自从2000年以后,中国政府规定,所有在中国售卖的软件产品必须支持Chinese Simplified(GB18030)字符集。因此在我国,就出现了一个神奇的事情,就是Unicode和Chinese Simplified双字符集并行的问题。

有趣的是,笔者大概调研了几大中文网站的编码如下:

URI 字符编码
https://www.taobao.com/ Unicode(UTF-8)
http://www.jd.com/ Chinese Simplified (GBK)
http://bj.meituan.com/ Unicode(UTF-8)
https://www.baidu.com/ Unicode(UTF-8)
http://cn.bing.com/ Unicode(UTF-8)
http://www.sohu.com/ Chinese Simplified (GBK)
http://www.qq.com/ Chinese Simplified (GBK)
http://www.sina.com.cn/ Unicode(UTF-8)

感觉上各个大厂也是自说自话,不是不是很一致要遵守政府规定或者不遵守规定。这么说来,国家对这块儿在申请xxx备案的管理也不是很严格。

话有点扯远了,咱们再回来。目前Unicode字符集共设定16个Plane(数字从0x000000-0x10FFFF)对应(2^16+2^20)对应(1,114,112)。刚刚说的Plane0,基础语言集定义是从0x000000-0x00FFFF(2^16)。其他的大家可以查,Plane1和2用了一些,其他基本上用的很少。因此总共来说目前分配的字符大约是12万。

但是这样庞大的数字和计算机的比特(byte)之间并不统一,把一个Unicode字符串转换成Byte的过程,这里引入了一个叫做Encoding,编码的概念。1992年,为了兼容不同处理器和C语言,人们引入了一个编码标准,这就是大家广泛知道的UTF-8。截至2016年5月份,在WWW上的统计,UTF-8的使用率已经达到86.9%,对比GB2312(0.8%)。同时W3C也把UTF-8作为XML和HTML的推荐编码。

下面我们来阐述一下UTF-8的实现原理(同时可以结合下图来看):

如果是7位以内表述的字符表数字,就只占用一个自己,表现为(0xxxxxxx),这样刚好和ASCII码的描述相一致,这样就不会造成原有ASCII的识别错乱,特别是针对C语言的strlen()和strcopy()。从第8位,也就是十位数的256开始,采用两字节表述模式(110xxxxx 10xxxxxx),最多可以表示11个bit位,也就是2^8(256)到2^12-1(4095)。以此类推。是不是一种很有趣的编码模式 :)

下面看一个栗子。以杏树林的“杏”字为题。

所以总结一下,Unicode和ASCII是一个字符集的概念,他们是随着电信发展而产生的编码本。只不过Unicode有多包涵了表示和处理部分,范围会更广泛。为了让计算机能读懂编码,适应计算机的计算,我们有了诸如UTF-8类的编码方法。

值得参考的一系列词条出处
https://docs.python.org/3/howto/unicode.html
https://en.wikipedia.org/wiki/Character_encoding
https://en.wikipedia.org/wiki/Unicode
https://en.wikipedia.org/wiki/Universal_Coded_Character_Set
https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
https://en.wikipedia.org/wiki/UTF-8

升级Python3几个小总结

最近,主要是想集中把这次的改造写完,早日上线。这次主要干了两件事情。第一是升级Python3,这里面顺带写一点学习总结。算是个misc文章吧。下一篇主要是想聊聊没有后台的系统到底是如何搭建以及为什么要做这个实验。

OK,先说这次Python3升级吧。想了很久了,受制于各种阻力,总是担心升级会出问题。但是Python3既然已经嚷嚷了这么多年。而且还是有越来越多的系统在往Python3上迁移,所以还是用用看。至少知道坑在哪里,以后会遇到哪些问题。

总结一下本次修改较多的几个部分:

  • Print语法:Python3最有名的一个表征就是print的括号问题。在Python2里面是没有的,在3里加上了()这个语法。所以导致从2向3升级的过程中print,成了修改最多的语法之一。

  • Pip2(Python2)和Pip3(Python3),一般来讲,如果之前装的是2的,升级到3时候Python和Pip两个命令依然表示的是2,如果要是使用3.x的话,需要加入pip3或者python3,来作为命令开头。为了简单期间,或者用env来定义。还有一种就是在bash_profile里面增加python的alias

    1
    2
    alias python='python3'
    alias pip='pip3'
  • MySQL-python包的使用。这个很讨厌,因为目前这个包还不支持Python3。不过也没什么着急的,换一个呗。PyMySQL这个是Python官方对于MySQL的支持包。对于基本的增删改查操作,用法基本上是一样的。只不过要特别注意的是连接时要加入“charset=”utf8””来实现对中文的支持。这个在MySQLdb里面好像是默认,至少我当时没有设置。

    1
    db = pymysql.connect(host=host, port=int(port), user=username, passwd=password, db=database, charset="utf8")
  • 关于unicode,这里说道大头了哈。因为绝大多数人对于Python2中文支持都是一个噩梦。文字,被在--之间转换。但在Python3里面,很重要的一点是对中文做了很好的支持。消除了unicode这一层环节。所以现在就可以比较明确的说“中文.encode(‘utf-8’)”就是解码环节,无需再顾忌其他。

  • 也正是因为这个unicode的转变,其实造成了Python2里面很多原始代码都要进行一系列的和字符集相关的变化。比如一个buildin的函数open,在以前2的时代,是不需要对字符集进行指定的(话说,其实也是因为那个时代就没有什么字符集)。现在要特别说明打开字符集类型才可以进行有效的读写操作。

    1
    open(filename, 'w', newline='', encoding='utf-8')
  • 另外很赞的一点是,Unittest对Python的支持非常好。我自己实际用了unittest2和mock两个库。基本上都没有出现什么相关的修改。非常赞!所以说测试还是要加哦,很不错滴。

这次升级,确实花了些时间,处理问题。但确实得到了不少有益的实践。总结下来是两点吧

  1. 单元测试很重要。整个过程中,升级后的第一件事情就是运行单元测试,其中大量的错误,但是不可怕,一个一个的改就好了。因为我的程序设计web、邮件、数据库等多方通讯,没有单元测试,效率会大打折扣,而且还有可能遇到因为网络问题而导致的联调失败
  2. Python2到3的升级并不可怕,主要问题恰恰是来自于unicode这块儿的改变。只要记好了字符集utf-8这件事情。你会发现大量问题,都和这个有直接关系。