解语科技
首发于解语科技

斯坦福CS231N课程学习笔记(一).课程简介与准备

前言

开这个系列是因为工作中需要用到计算机视觉相关知识。几经淘洗,发现了斯坦福大学的CS231N课程。为了强制自己学习,强化学习效果,将学习中的笔记整理出来,与大家一起分享,也希望借此与同在学习这门课程、以及其他计算机视觉的学习者、研究者一起探讨和进步。

本人此前没有接触过这一领域,IT从业以来多以工程为主,少有接触学术和算法研究,所以学习笔记也会因为本人理解能力原因,存在谬误,恳请阅读者指正。

请注意:本系列是以CS231N为蓝本进行学习的学习笔记,并不是对CS231N的翻译。在学习过程中不可避免地会针对个人知识体系特点补充学习相关内容。关于CS231N的课程翻译,可以参见知乎网友@杜客翻译

CS231N课程简介

CS231N课程的全称是卷积神经网络在视觉辨识中的应用(Convolutional Neural Networks for Visual Recognition),是一个学习时长跨度为两个月的课程。这门课程从2015年起第一次开设,授课者是李飞飞Andrej Karpathy,Justin Johnson。李飞飞,斯坦福大学计算机科学系副教授,入选2015年“全球百大思想者”,现为斯坦福人工智能实验室(SAIL)主任。斯坦福大学在机器学习和计算机视觉上都非常牛。著名的人工智能专家, Google Brain之父吴恩达也是斯坦福大学副教授。

计 算机视觉在搜索,图像理解,地图,医疗,无人机和无人驾驶汽车等方面的应用越来越重要和广泛。这些任务的核心就是视觉辨识,即图像分类,本地化 (localization)和检测。而神经网络(即深度学习)在这一领域的应用又大大提高的视觉辨识系统的最新水平。这门课程将以上述任务,特别是图像 分类为研究对象,以端到端的模式解析深度学习架构在视觉辨识领域的实现。

这门课程将教会学生如何实现、训练和调试他们自己的神经网络,并获 得对计算机视觉这一前沿科学深入了解。在课程最后,你将训练一个有几百万参数的神经网络并将其应用于全球最大的图像分类数据库--ImageNet. 具体而言,课程重点将会是图像识别问题的设定,学习算法(即后向传播),神经网络训练和调优中的工程技术难题和技巧,以及如何上手完成布置的作业及最终的 课业项目(final course project)。

学习这门课程需要对python很熟练,以及对C/C++有High-level 的熟悉程度。作业主要使用python(以及python的库如numpy等),但一些关于深度学习的库,也可能使用C/C++。需要有一些大学微积分知 识及线性代数知识,需要能看懂求导及矩阵运算。也需要一些基础的概率知识,如高斯分布,均值,标准差等等。这门课程还将讲述代价函数,求导和使用梯度下降 法进行优化等,如果学习过CS229(机器学习),这些知识将直接可用。

课程资源

课程的主页在这里。在主页上使用一段JS向来访者显示一个正在进行的图像分类任务。这段javascript,被称之为ConvNetJS,由课程讲授者Andrej Karpathy贡献,在后面的学习中会专门提到。

课程的大纲和课程表见这里。这个课程表可以供自己学习时作为进度参考,同时,这个而面也列举了课程中使用的资源的链接地址。这些资源包括授课用的课件,工具使用指南及一些课程笔记。这些课程笔记非常详细,对于不能现场听课的人来讲,非常重要。这里是课程笔记的一个例子。

这些课件也可以在google的云盘中获取。如果你要给其它人讲课,这些课件倒是很好的资源,如果仅用于自己学习,建议多从它的课程笔记开始,或者从本笔记开始。

这里有一份讲课的视频播放清单,是 youtube 的。如果无法访问youtube,也可以访问百度云盘

Andrej Karpathy的博客及课程教职员的twitter也值得关注,提供了最新的一些资讯。另外,你也可以访问Reddit.

课程准备

编程和课程实践工具

CS231N课程作业主要使用python。使用python 2.7版本就可以完成这些作业。安装完python之后,检查一下是否安装了numpy、scipy、Pillow和matplotlib:


bogon:~ aaron$ pip list |grep numpy
numpy (1.8.0rc1)
bogon:~ aaron$ pip list |grep scipy
scipy (0.17.1)
bogon:~ aaron$ pip list |grep matplot
matplotlib (1.3.1)
bogon:~aaron$ pip list |grep Pillow
Pillow (3.2.0)

这里有一个trick,如果你要使用 scipy.misc.imread等图像文件操作函数(正如本文例子中所示),那么实际上需要导入Pillow。但是 scipy安装文件并没有把这个依赖写进来,所以如果你的系统中没有安装Pillow,在执行下面的语句时会出错:


from scipy.misc import imread, imsave, imresize

错误是:


>>> from scipy.misc import imread
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name imread

如果没有安装,使用下面的命令安装:


pip install numpy
pip install scipy
pip install matplotlib
pip install Pillow

如何使用scipy全家桶

SciPy提供用于科学计算的核心库。在我们的研究中,比较常用的有图像操作:


from scipy.misc import imread, imsave, imresize

# Read an JPEG image into a numpy array
img = imread('assets/cat.jpg')
print img.dtype, img.shape  # Prints "uint8 (400, 248, 3)"

# We can tint the image by scaling each of the color channels
# by a different scalar constant. The image has shape (400, 248, 3);
# we multiply it by the array [1, 0.95, 0.9] of shape (3,);
# numpy broadcasting means that this leaves the red channel unchanged,
# and multiplies the green and blue channels by 0.95 and 0.9
# respectively.
img_tinted = img * [1, 0.95, 0.9]

# Resize the tinted image to be 300 by 300 pixels.
img_tinted = imresize(img_tinted, (300, 300))

# Write the tinted image back to disk
imsave('assets/cat_tinted.jpg', img_tinted)

可以先花一点时间过一下它的quick start tutorial,对numpy的基本用法有个大致了解。当你需要完成某个任务,不知道numpy是否支持时,可以查看它的参考文档。如果你明确知道某个方法,需要详尽了解其具体用法,可以查看按字母顺序索引的索引表

当然也可以使用python的终极帮助大法,通过全局函数dir()来查看一个对象(或者类)提供的属性和方法,然后通过 全局函数help() 来查看其用法。

在 numpy中,最重要的数据类型是同构多维数组ndarray。它支持建立矩阵、reshape,copy等操作。linalg是numpy中处理线性代 数运算的包,比如对矩阵进行转置,求逆, 点乘,求迹,求特征值和特征向量等。numpy还有用于傅立叶变换的库numpy.fft,与随机数、概率相关的库numpy.random。

matplotlib的主要工作是提供绘图操作:


import numpy as np
import matplotlib.pyplot as plt

# Compute the x and y coordinates for points on sine and cosine curves
x = np.arange(0, 3 * np.pi, 0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)

# Plot the points using matplotlib
plt.plot(x, y_sin)
plt.plot(x, y_cos)
plt.xlabel('x axis label')
plt.ylabel('y axis label')
plt.title('Sine and Cosine')
plt.legend(['Sine', 'Cosine'])
plt.show()

安装IPython notebook

课程简介里提到了安装IPython notebook。CS231N的课程作业使用这个工具来布置。他们的作业布置方法是下发一些后缀为ipnb的文件,通过在IPython notebook中加载这些文件,你就能得到完成这些作业所必须的skeleton代码和作业指导,如下例所示:

可以看到上方有详细的指示,告诉你需要完成的代码是实现一个K=5的KNN分类器,并且代码实现的位置已经指定,你需要做的就是在指定的位置填写上代码。这里面要求的一些skeleton的代码,已经事先写好了,比如第二课要用到的load_CIFAR10等。

从这些地方可以看出,这门课程的设计是多么精心,不由得让人感叹一下国内的大学跟世界一流大学的差距,其实不仅仅是在科研上,就连教学上也有很大的差距。

具体安装方法是:


pip install "ipython[notebook]"
python -m IPython notebook

最后一个命令会运行一个本地服务器,注意启动时提示的端口。打开浏览器,输入localhost:8888/tree即可以查看提供的服务。

安装ConvNetJS

从Github上下载convnetjs的代码。在本地生成这个html文件(命名为index.html):


<html>
<head>
<title>minimal demo</title>
 
<!-- CSS goes here -->
<style>
body {
  background-color: #FFF; /* example... */
}
</style>
 
<!-- import convnetjs library -->
<script src="convnet.js"></script>
 
<!-- javascript goes here -->
<script type="text/javascript">
 
function periodic() {
  var d = document.getElementById('egdiv');
  d.innerHTML = 'Random number: ' + Math.random()
}
 
var net; // declared outside -> global variable in window scope
function start() {
  // this gets executed on startup
  //... 
  net = new convnetjs.Net();
  // ...
 
  // example of running something every 1 second
  setInterval(periodic, 1000);
}
 
</script>
</head>
 
<body onload="start()">
<div id="egdiv"></div>
</body>
</html>

注意这里引用的JS文件是convnet.js,所以你需要在与本HTML相同的位置处保存一份从Github上下载的convnet.js.

现在运行命令:


python -m SimpleHTTPServer 8000

在浏览器中打开localhost:8000,如果看到一串随机数在不停跳动,说明部署成功了。这个简单的demo基本上不包含任何有用的内容,但我们后面需要用到它。现在你可以通过它来观察convnetjs的对象封装,并对Vol, Net等模块的代码进行阅读和调试。

基础数学知识

高斯分布,又称正态分布。可以使用Box-Muller方法来生成一个符合高斯分布的随机数。这个方法的核心是,如果在值域(0, 1]内有两个独立同分布的变量U,V, 那么可用以下两个等式之一生成服从高斯分布的随机变量Z:

或者,这里满足:

参考实现代码如下(引用至Karpathy的ConvNetJs):


var gaussRandom = function() {
    if(return_v) { 
      return_v = false;
      return v_val; 
    }
    var u = 2*Math.random()-1;
    var v = 2*Math.random()-1;
    var r = u*u + v*v;
    if(r == 0 || r > 1) return gaussRandom();
    var c = Math.sqrt(-2*Math.log(r)/r);
    v_val = v*c; // cache this
    return_v = true;
    return u*c;
  }

这个随机数可以通过numpy生成,代码是:


import numpy as np
np.random.normal()

现在我们来检验一下它生成的随机数是否真的是正态分布:


import matplotlib.pyplot as plt
import numpy as np
a = []
for i in range(50000):
    a.append(np.random.normal())
plt.hist(a, 10000)
plt.show()

矩阵相关知识

矩阵乘法。如果A是矩阵和B是矩阵,则A可以乘以B,即。在numpy里,矩阵的乘法是:


b = a * a
#or
c = np.dot(a, a)

转置。在python中使用下面的代码:


A = np.array([[1,2,3],[4,5,6],[7,8,9]])
print A.T

行列式

在numpy里,计算行列式的方法是:


import numpy as np
A = np.array([[1, 2, 3], [4, 5,6], [7,8,9]])
np.linalg.det(A)

代数余子式

伴随矩阵

在python中求伴随矩阵()


A = np.array([[1,2,3], [4,5,6], [7,8,9]])
print np.linalg.inv(A)*np.linalg.det(A)
[[ -3.   6.  -3.]
 [  6. -12.   6.]
 [ -3.   6.  -3.]]

逆矩阵()

在python中求矩阵的逆:


import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6], [7,8,9]])
print np.linalg.inv(A)

import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6], [7,8,9]])
print np.linalg.trace(A)

特征值和特征向量

在python中求特征值和特征向量


import numpy as np
x = numpy.array([[1, 0, 0], [0, 2,0], [0, 0,3]])
a,b = numpy.linalg.eig(x)
print a, b

计算机视觉简介

请见课程讲义。这部分CS231N主页未提供任何课堂笔记和讲课视频。所以本笔记以下内容完全是基于个人理解,并跳过了很多计算机视觉这门学科的发展史上的内容。

计算机视觉发展到现阶段,就是机器学习在可视化数据上的应用。它与数字图像处理、计算图形学等是相邻学科。见下图:

计算机视觉,就是让计算机能理解它所处理的图像内容,1966年,图灵奖得主Minksy给出以下描述:

然 而半个世纪过去了, 我们依然很难说完全解决了这一问题。在本课程授课者之一的Karpathy的博客中有一篇文章: The state of Computer Vision and AI: we are really, really far away. 这篇文章里有一张美国总统奥巴马的照片:

这篇文章列举了近十个计算机视觉理解这张图片的难点。

其它


百纳(武汉)信息技术有限公司在武汉组织CS231N线下学习课堂,并通过QQ群(142961883)和腾讯课堂向不能到现场的同学进行直播。每周组织一次授课,具体学习时间地点请见微信公众号黑斑马团队(zero_zebra)及QQ群发布。课程学习中的相关知识点和笔记通过公众号、知乎专栏发布。

本课程也可以参考CS231N的在线资料及视频来自学。我们组织的课程学习将额外提供:

  1. 很多人需要良好的学习环境才能更有效率地学习。本课程通过组织大家集体学习,相互鼓励和监督,提供各种形式地交流互助,使得学习更有效率。
  2. 原课程录像是英文的,且部分课时不全。我们讲课全程使用中文,并且会根据学习者的程度不同,补充必要的预备知识。
  3. 提供对作业题的答疑和讨论,一些工具软件在使用中的困难帮助等等。
  4. 对课程体系的宏观把握,以方便大家入门,和根据自己的实际情况补充预备知识。

关于百纳(武汉)

百纳(武汉)信息技术有限公司(以下简称武汉百纳)成立于2010年。武汉百纳是武汉移动互联网行业的领先企业,公司专注于自主创新,以出色的市场前瞻力和卓越的技术创新力为依托,研发了著名的海豚浏览器(2015年全球用户超过2亿),先后得到红杉资本、经纬创投、高通及畅游的战略投资。

公司现面向全球招聘计算机视觉及虚拟现实项目相关人才,有意者请向recruiting@bainainfo.com投递简历。

JD请看这里

编辑于 2019-07-03

文章被以下专栏收录