算法初探:Tensorflow及PAI平台的使用

前言

Tensorflow这个词由来已久,但是对它的理解一直就停留在“听过”的层面。之前做过一个无线图片适配问题智能识别的项目,基于Tensorflow实现了GoogLeNet - Inception V3网络(一种包含22层的深层卷积神经网络),但是基本上也属于“盲人摸象”、“照葫芦画瓢”的程度。作为当今机器学习乃至深度学习界出现频率最高的一个词,有必要去了解一下它到底是个什么东西。

而PAI,作为一站式地机器学习和算法服务平台,它大大简化了模型构建、模型训练、调参、模型性能评估、服务化等一系列算法的工作,可以帮助我们更快捷地实现算法实验和应用。

一、Tensorflow初探

1. 安装和启动

因为我自己的mac-pro安装了docker,所以安装Tensorflow的环境非常简单,只要拉取Tensorflow的官方镜像就可以完成Tensorflow的环境搭建。

#拉取tensorflow镜像
docker pull tensorflow/tensorflow

#创建一个tensorflow的工作目录,挂载到容器内
mkdir -p /Users/znifeng/docker-data/tensorflow/notebooks #启动容器 docker run -it --rm --name myts -v /Users/znifeng/docker-data/tensorflow/notebooks:/notebooks -p 8888:8888 tensorflow/tensorflow 

启动成功后,将看到如下信息:
算法初探:Tensorflow及PAI平台的使用_第1张图片

 

复制链接http://127.0.0.1:8888/?token=487c52e0aa0cd2a7b231bf909c1d6666482f8ed03353e510到浏览器,就可以看到jupyter(支持在线编写和调试python的交互式笔记本)页面:

算法初探:Tensorflow及PAI平台的使用_第2张图片

 

接下来,你可以在jupyter上或者在docker容器内部编写和调试tensorflow的代码,容器内部已经包含了tensorflow的所有库。

2. 基本使用

2.1 核心概念

  • 使用图(graph)来表示计算任务
  • 使用张量(tensor)来表示数据。张量与矢量的区别:矢量相当于一阶的张量,张量可以从0阶到多阶(多维)
  • 图中的每一个节点称之为op(operation),每一个op有0或多个Tensor作为输入,执行计算后产出0或多个Tensor作为输出
  • 在被称之为会话Session的上下文(context)中执行图
  • 通过变量(variable)来维护状态
  • 使用feed和fetch可以为任意的操作赋值或者从其中获取数据
  • 使用placeholder来定义占位符,在运行时传入对应的参数值

TensorFlow程序通常被组织成一个构建阶段和一个执行阶段。在构建阶段,op的执行步骤被描述成一个图,在执行阶段,使用会话执行图中的op。在Python中,返回的tensor是numpy.ndarray对象。;在C/C++中,返回的是tensorflow:Tensor实例。

2.2 使用示例

2.2.1 第一个helloworld程序:
import tensorflow as tf

#第一阶段: 构建图
#定义一个1x2的矩阵,矩阵元素为[3 3]
matrix1 = tf.constant([[3., 3.]])

#定义一个2x1的矩阵,矩阵元素为[2 2] matrix2 = tf.constant([[2.],[2.]]) # 创建一个矩阵乘法 matmul op , 把 'matrix1' 和 'matrix2' 作为输入. product = tf.matmul(matrix1, matrix2) #第二阶段: 执行图 with tf.Session() as sess: print "matrix1: %s" % sess.run(matrix1) print "matrix2: %s" % sess.run(matrix2) print "result type: %s" % type(sess.run(product)) print "result: %s" % sess.run(product) 

输出结果:

matrix1: [[3. 3.]]
matrix2: [[2.]
 [2.]]
result type: <type 'numpy.ndarray'> result: [[12.]] 

如上图所示,在第一阶段(构建图)中,我们的每一行操作其实都是一个operation,包含两个constant操作和一个矩阵相乘的操作,每个operation的输出都是tensor,它的类型是num.ndarray。实际上,构建阶段我们只是定义op,并不会真正去执行;而在第二阶段中,通过定义了一个会话session,我们才会在会话中真正开始执行前面定义的各个operation,然后获得执行的结果。

2.2.2 使用tensorflow实现识别手写数字(1~9)模型 —— Softmax Regression
import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

import tensorflow as tf

##Define input data format #input images, each image is represented by a tensor of 784 dimensions x = tf.placeholder("float", [None,784]) #input labels, each label values one digit of [0,9], which is represented by a tensor of 10 dimensions y_ = tf.placeholder("float", [None, 10]) ##Define Model and algorithm #weight array of each feature VS predicted result W = tf.Variable(tf.zeros([784, 10])) #bias of each digit b = tf.Variable(tf.zeros([10])) #predicted probability array of an image, which is of 10 dimensions. #tf.matmul:矩阵相乘 y = tf.nn.softmax(tf.matmul(x,W) + b) #cross-entropy or called loss function #tf.reduce_sum:压缩求和: tf.reduce_sum(x, 0)将x按行求和,tf.reduce_sum(x, 1)将x按列求和,tf.reduce_sum(x, [0, 1])按行列求和 cross_entropy = -tf.reduce_sum(y_*tf.log(y)) #gredient descent algorithm train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy) ##Training model #initialize all variables init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) for i in range(1000): batch_xs, batch_ys = mnist.train.next_batch(100) sess.run(train_step, feed_dict={x: batch_xs, y_:batch_ys}) ##Evaluation #tf.argmax(vector, 1):返回的是vector中的最大值的索引号。tf.argmax(vector, 0) correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) print sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}) 

输出结果:

0.904

模型中使用的数据来自tensorflow/g3doc/tutorials/mnist/,总共包含7万张784(28x28)像素的1~9的数字图片,其中55000张用于模型训练作为训练集,5000张作为验证集,剩余10000张用作测试集。

因此,每一张图片都可以用一个784维的向量来表示,向量里的每一个元素表示某个像素的强度值,介于0和1之间。使用x = tf.placeholder("float", [None,784])表示输入集x,其中placeholder为占位符,在实际使用时,我们再通过feed传入具体的行数来替换其中的None。y_则为对应的实际结果,因为结果集合为0~9,因此我们可以用[y0,y1,...,y9]的十维向量来表示结果,比如数字“1”可以表示为[0,1,0,0,0,0,0,0,0,0]。本例中,定义的模型为线性模型,先用wx+b得到初步结果z,再通过softmax函数将z折射得到0~9各个数字的概率值。

算法初探:Tensorflow及PAI平台的使用_第3张图片

 

在模型求解时,我们需要定义一个指标来评估模型是好的。而在机器学习中,通常是定义指标来表示模型是坏的,然后尽量最小化该指标得到最优解,该指标也称为成本(cost)或损失(loss)函数。本例中,我们用“交叉熵”来作为损失函数cross_entropy = -tf.reduce_sum(y_*tf.log(y)),然后用梯度下降的方式求解train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)。其中0.01为下降的速率。

可以看到,经过1000次迭代,我们的模型的预测结果的准确率达到了90.4%。

2.2.3 使用tensorflow实现识别手写数字(1~9)模型 —— DeepCNN

上节中用softmax模型预测的准确率大概在90%,接下来尝试下用tensorflow实现一个卷积神经网络模型来识别手写数字。

import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

import tensorflow as tf def weight_variable(shape): initial = tf.truncated_normal(shape, stddev=0.1) return tf.Variable(initial) def bias_variable(shape): initial = tf.constant(0.1, shape=shape) return tf.Variable(initial) def conv2d(x, W): return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding="SAME") def max_pool_2x2(x): return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') x = tf.placeholder("float", shape=[None, 784]) y_ = tf.placeholder("float", shape=(None, 10)) #第一层卷积 W_conv1 = weight_variable([5, 5, 1, 32]) b_conv1 = bias_variable([32]) x_image = tf.reshape(x, [-1,28,28,1]) h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) h_pool1 = max_pool_2x2(h_conv1) #第二层卷积 W_conv2 = weight_variable([5, 5, 32, 64]) b_conv2 = bias_variable([64]) h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) h_pool2 = max_pool_2x2(h_conv2) #密集连接层 W_fc1 = weight_variable([7 * 7 * 64, 1024]) b_fc1 = bias_variable([1024]) h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64]) h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1) #Dropout防止过拟合 keep_prob = tf.placeholder("float") h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) #输出层: softmax W_fc2 = weight_variable([1024, 10]) b_fc2 = bias_variable([10]) y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2) #训练和评估模型 cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv)) train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy) correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) for i in range(2000): batch = mnist.train.next_batch(50) if i%200 == 0: train_accuracy = sess.run(accuracy, feed_dict={x:batch[0], y_: batch[1], keep_prob: 1.0}) print "step %d, training accuracy %g"%(i, train_accuracy) train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5}) print "final training accuracy %g" % sess.run(accuracy, feed_dict={x:batch[0], y_: batch[1], keep_prob: 1.0}) 

输出结果:

step 0, training accuracy 0.14
step 200, training accuracy 0.92
step 400, training accuracy 0.96 step 600, training accuracy 1 step 800, training accuracy 0.9 step 1000, training accuracy 0.96 step 1200, training accuracy 0.94 step 1400, training accuracy 0.94 step 1600, training accuracy 0.98 step 1800, training accuracy 1 final training accuracy 0.99 

可以看到,2000次迭代后,deepccn的预测准确率达到了:99%。

二、PAI平台的使用

前面介绍了Tensorflow的基本概念和使用,下面简单介绍下使用PAI完成LR模型训练的基本过程。整个流程大概包含以下步骤:离线数据开发 -> PAI平台实验搭建 -> 模型服务化

2.1 离线数据开发

首先,算法的基础是数据,我们首先要通过对业务的分析,找出影响目标结果的特征,并对特征数据进行采集,得到各项特征的原始数据。这一部分,可以在odps完成。如“需求风险智能识别”中,涉及到多个表的join和指标的提取、计算等,对于一些缺省的值可以按照不同的策略来填充(如用0填充,或者该项的平均值)。最终得到如下的训练数据:

算法初探:Tensorflow及PAI平台的使用_第4张图片

 

 

2.2 PAI平台实验搭建

进入PAI平台中,新建实验:smarttest,搭建如下的实验流程:

算法初探:Tensorflow及PAI平台的使用_第5张图片

 

流程中的每个组件可以从左侧“组件”导航栏中获取。具体流程如下:

  • 读数据表:输入odps表名
  • 类型转换:将特定的字段统一转化为double/int类型
  • 归一化:选取用于训练的特征,并进行归一化。归一化的逻辑为:y= (x-MinValue)/(MaxValue-MinValue)
  • 拆分:将数据集按照比例拆分为训练集和测试集
  • 逻辑回归二分类:使用LR模型对训练集的数据进行训练
  • 预测:将训练得到的模型对测试集的输入数据进行预测
  • 混淆矩阵:产出模型预测结果的混淆矩阵
  • 二分类评估:得到模型评估的AUC、KS、F1 Score等结果

2.3 模型服务化

训练好模型后,就可以将模型在线服务化。

 

你可能感兴趣的:(算法初探:Tensorflow及PAI平台的使用)