1.3 从代码开始
“Talk is cheap, show me the code”这句话无论是对于程序开发还是对于机器学习都是适用的。对于一个软件工程师来说,原理、分析和推导都比不上一段真实的代码更容易让人理解,下面就让我们直接尝试用代码来解决问题吧。
1.3.1 搭建环境
本节希望让读者尽快接触真实开发环境下的代码,因此将使用TensorFlow中的Keras作为开发框架(现在Keras已是TensorFlow的一部分)。此外,我们需要一些额外的Python包作为支持。我们选用了Python 3.7以上版本,并假设读者已经安装好Python 3.7。下面执行安装本章代码运行所需依赖库的命令:
1.3.2 一段简单的代码
考虑一个简单的问题:对正负数分类,对正数返回1,对负数返回0。
这用传统的代码实现起来非常简单,如下所示:
但用机器学习该如何实现呢?
下面用TensorFlow自带的Keras实现对正负数分类:
我们看看这18行代码都做了什么。
第1~3行:引入依赖库TensorFlow和其自带的Keras相关库。
第5~8行:这4行建立了一个简单的两层神经网络模型。在第5行定义了一个Sequential类型的网络,顾名思义是按顺序层叠的网络。在第6行加入第1层网络,输入input_dim为1,意味着只有1个输入(因为我们只判断一个数字是否为正数);但是定义了8个输出(units=8),这个数字其实是随意定的,可以视为其中神经元的个数(我们将在第2章解释什么是神经元),一般神经元的个数越多,效果越好(训练时间也越长)。算法科研人员会耗费大量的时间来确定这些数字,以找到最佳的个数。第7行再叠加一层,接收前面的输出(8个),但作为最后一层,这次只定义一个输出(units=1),这个输出决定了最后的分类结果。第8行对整个模型进行最后的配置,选择mean_squared_error(平均方差)作为损失函数计算,选择随机梯度下降(Stochastic Gradient Descent,SGD)作为梯度优化方式。这里将不从理论角度解释随机梯度下降的原理,但在第2章中将通过代码来手工实现随机梯度下降。
第10~12行:设定了两组数据x和y作为训练集,其中,x包括10个正数,y包括对应的10个分类结果。可以看到,对于x中的每个正数,y中对应的值都是1.0,负数x[i]所对应的y[i]则是0。然后我们调用model.fit函数进行训练,设置epochs为10(训练10次),batch_size为4(每次都随机挑选4组数据)。
第14~18行:这里构建了4个输入数据进行测试并打印结果。我们构建了数组test_x,该数组包含4个整数,然后调用model.predict方法对test_x进行预测。在第17~18行将打印每个输入所对应的预测结果。
以上18行代码的运行结果如下:
可以看到,在最后的预测结果中,所有正数的预测值都非常接近1,所有负数的预测值都小于0.01。前面解释过,机器学习是一种概率预测,不可能完全精确,以上结果对正负数做了较为明确的划分,是可以接受的。
经过上面的代码实现,读者可能仍然对其中涉及的一些内容有些茫然,比如什么是梯度下降,神经元又是什么,什么叫加一层、减一层,具体的参数又是怎样训练的,等等,在第2~4章会详细解释这些内容。
上述代码是基于Keras实现的,Keras是机器学习研究主流的开发框架,封装了很多常见的算法和模型。第2章将抛开这些框架,用最基本的Python代码从最简单的神经网络开始,尝试实现上面的功能。