神经网络是Tensorflow最擅长的机器学习领域。TensorFlow拥有一套符号引擎,它使得训练复杂模型变得更简单和方便。通过这套符号引擎,我们能够实现许多的模型结构和算法。
本文中,我们将会覆盖以下内容:
神经网络的基本概念;
神经网络用于回归非线性合成函数;
使用非线性回归预测汽车燃料效率;
学习葡萄酒分类——一种多类分类。
5.1.1 人工神经元
人工神经元就是使用一个数学函数来对生物的神经元建模。
简单来说,一个人工神经元就是接受一个或者多个输入(训练数据),对它们加和,并产生一个输出。一般来说,这里面的加和指的是加权求和(每个输入乘上权重,并加上一个偏差),然后将加和的输入传递给一个非线性函数(一般称作激活函数或者转移函数)。
1.最简单的人工神经元——感知器
感知器是实现人工神经元最简单的方法,它的历史可以追溯到20世纪50年代,在20世纪60年代的时候,首次被实现。
简单来说,感知器就是一个二元分类函数,它将输入映射到一个二元输出,如图5-1所示。
图5-1 单层感知器
2.感知器算法
简化版的感知器算法如下:
以一个随机分布初始化权值和偏差(通常比较小);
选择一个输入向量,并将其放入神经网络中;
将输入与权重相乘,并加上偏差,计算网络的输出y';
感知器的函数如下:
如果y′≠y,将权重wi加上Δw=yxi;
返回第步。
5.1.2 神经网络层
我们可以对单层的感知器进行泛华,将它们堆积起来,并互相连接,如图5-2所示。但这就带来一个问题,这样的线性组合出来的模型还只是一个线性分类器,对于复杂的非线性分类,这种方式并不能正确拟合,这个问题需要激活函数来解决。
1.神经网络激活函数
单独的单变量线性分类器并不能带来神经网络的强悍性能。就算那些不是很复杂的机器学习问题都会涉及多变量和非线性,所以我们常常要用其他的转移函数来替代感知器中原本的转移函数。
图5-2 连接单层感知器
有很多非线性函数可以用来做激活函数,从而表征不同的非线性模型。在输入同样的变量的时候,不同的激活函数有不同的响应。常用的激活函数如下:
Logistic:典型的激活函数,在计算分类的概率时非常有用。
Tanh:跟Sigmoid函数很像,但是范围是[−1,1],而不是[0,1]。
Relu:修正线性函数,该函数主要是为了对抗梯度消失。也就是当梯度反向传播到第一层的时候,梯度容易趋近于0或者一个极小值。
{-:-}f(x)=max(0, x)
在我们计算总的误差的时候,因为是一整个函数作用于输入数据,所以我们要调整这个方程中的所有变量,来最小化方程。
怎样最小化误差呢?正如我们在优化部分所学,我们通过损失函数的梯度来最小化误差。
如果我们的网络拥有多层权重和转移函数,我们最终需要通过链式法则来求导所有参数的梯度。
2.梯度和反向传播算法
在感知器的学习阶段,我们按照每个权重对误差的“责任”,按比例调整权重。
在更复杂的网络中,误差的责任被分散在整个结构的所有操作之中。
3.最小化损失函数:梯度下降
我们由图5-3理解一下损失函数。
4.神经网络的选择-分类vs回归
神经网络既可以被用于回归问题,也可以被用于分类问题。不同的地方在于结构的最后一层。如果需要的结果是一个数值,那么就不要连接标准函数,如 sigmoid。如果是这样的话,我们得到的就是一个连续值。
图5-3 梯度下降
5.1.3 有用的库和方法
本章中我们会用到TensorFlow中一些新的函数,下面是我们需要的最重要的函数:
1.TensorFlow激活函数
最常用的激活函数如下:
tf.sigmoid(x):标准的sigmoid函数;
tf.tanh(x):双曲正切函数;
TensorFlow中其他的函数:
tf.softsign(x):返回x/(abs(x)+1);
2.TensorFlow中损失优化方法
tf.train.GradientDescentOptimizer(learningrate, uselocking, name):原始梯度下降方法,唯一参数就是学习率。
tf.train.AdagradOptimizer:自适应调整学习率,累加历史梯度的平方,作为分母,防止有些方向的梯度值过大,提高优化效率,善于处理稀疏梯度。
tf.train.AdadeltaOptimizer:扩展AdaGrad优化方法,只累加最近的梯度值,而不对整个历史上的梯度值进行累加。
tf.train.AdamOptimizertf.train.AdamOptimizer. (learningrate, beta1, beta2, epsilon, use locking, name):梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。Adam是自适应矩估计(Adaptive Moment Estimation)的首字母缩写。
3.Sklearn预处理函数
我们看一些下面的Sklearn数据预处理函数:
preprocessing.StandardScaler():数据正规化(Normalization)是机器学习估计的一个常见要求,为了模型能更好地收敛,我们通常会将数据集预处理到一个零均值单位方差的高斯状分布。通常,我们会将数据的各个维度都减去它的均值,然后乘上一个非零的数。这个非零的数就是数据集的标准差。对于该任务,我们直接使用StandardScaler,它已经实现了我们上面提到的操作。它也保留了变换操作,让我们可以直接用在测试集上。
StandardScaler .fit_transform():将数据调整到所需要的形式。StandardScaler对象会存储数据变化的变量,这样我们可以把数据解正规化到原先的格式。
crossvalidation.traintest_split:该方法能够将数据集分割成训练集和测试集。我们只需要提供两者的比例,该方法能够自动帮我们处理。
5.2 例1——非线性模拟数据回归
人工神经网络的应用包含了很多的分类任务,但是事实上,很多这些分类任务都是用回归来实现的。
分类和回归的网络结构差的并不多,都可以使用多变量的输入,以及线性或者非线性的激活函数。
在一些例子中,唯一要变的就是在输出层,连接上Sigmoid状的函数,该函数能够表征结果为各个类别的可能性。
在第一个例子中,我们使用一个简单的带噪声的二次方程生成样本。模型我们使用带一个隐含层的神经网络,然后检测预测值跟真实值的距离远近。
5.2.1 数据集描述和加载
本例中,我们使用生成的数据集,这跟第3章线性回归类似。
我们这次选择的方程是一个二次方程,并加上随机噪声,这有助于帮助我们测试回归的泛化能力。
核心代码如下:
import numpy as np
trainsamples = 200
testsamples = 60
dsX = np.linspace(-1, 1, trainsamples + testsamples).transpose()
5.2.2 数据集预处理
本例中的数据集不需要预处理,因为它是我们人工生成的,具有更好的性能,比如能够保证数据范围是(−1,1)。
5.2.3 模型结构——损失函数描述
本例中的损失函数使用均方误差,由以下代码实现:
cost = tf.pow(py_x-Y, 2)/(2)
5.2.4 损失函数优化器
本例中,我们使用梯度下降作为损失函数优化器,可以用以下代码实现:
train_op = tf.train.AdamOptimizer(0.5).minimize(cost)
5.2.5 准确度和收敛测试
predict_op = tf.argmax(py_x, 1)
cost1 += sess.run(cost, feed_dict=) / testsamples
5.2.6 完整源代码
完整源代码如下:
import tensorflow as tf
import numpy as np
from sklearn.utils import shuffle
%matplotlib inline
import matplotlib.pyplot as plt
trainsamples = 200
testsamples = 60
#Here we will represent the model, a simple imput, a hidden layer of
sigmoid activation
def model(X, hidden_weights1, hidden_bias1, ow):
return tf.matmul(hidden_layer, ow)
dsX = np.linspace(-1, 1, trainsamples + testsamples).transpose()
plt.figure() # Create a new figure
plt.title('Original data')
plt.scatter(dsX,dsY) #Plot a scatter draw of the datapoints
X = tf.placeholder("float")
Y = tf.placeholder("float")
# Create first hidden layer
hw1 = tf.Variable(tf.random_normal([1, 10], stddev=0.1))
# Create output connection
ow = tf.Variable(tf.random_normal([10, 1], stddev=0.0))
# Create bias
b = tf.Variable(tf.random_normal([10], stddev=0.1))
model_y = model(X, hw1, b, ow)
# Cost function
cost = tf.pow(model_y-Y, 2)/(2)
# construct an optimizer
train_op = tf.train.GradientDescentOptimizer(0.05).minimize(cost)
# Launch the graph in a session
with tf.Session() as sess:
tf.initialize_all_variables().run() #Initialize all variables
for i in range(1,100):
dsX, dsY = shuffle (dsX.transpose(), dsY) #We randomize the samples
to mplement a better training
trainX, trainY =dsX[0:trainsamples], dsY[0:trainsamples]
for x1,y1 in zip (trainX, trainY):
sess.run(train_op, feed_dict=)
testX, testY = dsX[trainsamples:trainsamples + testsamples],
dsY[0:trainsamples:trainsamples+testsamples]
cost1=0.
for x1,y1 in zip (testX, testY):
cost1 += sess.run(cost, feed_dict=) /
testsamples
if (i%10 == 0):
print "Average cost for epoch " + str (i) + ":" + str(cost1)
5.2.7 结果描述
生成的人工数据的散点图如图5-4所示。
图5-4 人工数据散点图
由以下每次迭代的结果,我们知道该实现结果非常好,甚至在第一次迭代的时候就取得了不错的结果。
Average cost for epoch 9:[[ 0.0007379]]
5.3 例2——通过非线性回归,对汽车燃料效率建模
本例中,我们会进入一个新的领域:解决非线性问题。该领域是神经网络附加值最大的领域。开始该旅程之前,我们会对几个汽车型号的燃料效率建模。该问题的输入是多个变量,只有非线性模型才能取得比较好的结果。
5.3.1 数据集描述和加载
对该问题,我们会分析一个著名的、标准的、数据组织得很好的数据集。我们有一个多变量的输入(有连续的,也有离散的),预测每加仑英里数(mpg)。
这是一个玩具级例子,但是这个例子会铺开通往更复杂问题的道路。而且该例子还有个好处,就是被大量研究过。
数据集由如下的列组成。
mpg:每加仑英里数,连续。
cylinders:气缸,多值离散。
displacement:排量,连续。
horsepower:马力,连续。
weight:车重,连续。
acceleration:加速度,连续。
model year:年份,多值离散。
origin:产地,多值离散。
car name:车名,字符串(不会被使用)。
我们不会对该数据做详细的分析,我们只是想看一下每一个连续的变量都跟目标变量的增减相关,如图5-5所示。
图5-5 不同的变量和燃烧效率的关系散点图
5.3.2 数据预处理
本例中,我们会使用一个前面描述的sklearn中的StandardScaler对象:
scaler = preprocessing.StandardScaler()
Xtrain = scaler.fittransform(X_train)
5.3.3 模型架构
我们需要建立的是一个多变量输入,单变量输出的前向神经网络,如图5-6所示。
图5-6 模型架构
5.3.4 准确度测试
我们用以下代码实现准确度测试:
score =
metrics.mean_squared_error(regressor.predict(scaler.transform(X_test)),
y_test)
print(" Total Mean Squared Error: " + str(score))
5.3.5 结果描述
Step #99, avg. train loss: 182.33624
Step #199, avg. train loss: 25.09151
Step #300, epoch #1, avg. train loss: 11.92343
Step #400, epoch #1, avg. train loss: 11.20414
Step #500, epoch #1, avg. train loss: 5.14056
5.3.6 完整源代码
完整源代码如下:
%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
from sklearn import datasets, cross_validation, metrics
from sklearn import preprocessing
from tensorflow.contrib import skflow
# Read the original dataset
df = pd.read_csv("data/mpg.csv", header=0)
# Convert the displacement column as float
df['displacement']=df['displacement'].astype(float)
# We get data columns from the dataset
# First and last (mpg and car names) are ignored for X
X = df[df.columns[1:8]]
y = df['mpg']
plt.figure() # Create a new figure
for i in range (1,8):
number = 420 + i
ax1.locator_params(nbins=3)
ax1 = plt.subplot(number)
plt.title(list(df)[i])
ax1.scatter(df[df.columns[i]],y) #Plot a scatter draw of the
datapoints
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
# Split the datasets
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y,
test_size=0.25)
# Scale the data for convergency optimization
scaler = preprocessing.StandardScaler()
# Set the transform parameters
X_train = scaler.fit_transform(X_train)
# Build a 2 layer fully connected DNN with 10 and 5 units respectively
regressor = skflow.TensorFlowDNNRegressor(hidden_units=[10, 5],
steps=500, learning_rate=0.051, batch_size=1)
# Fit the regressor
regressor.fit(X_train, y_train)
# Get some metrics based on the X and Y test data
score =
metrics.mean_squared_error(regressor.predict(scaler.transform(X_test)),
y_test)
print(" Total Mean Squared Error: " + str(score))
5.4 例3——多类分类:葡萄酒分类
本部分,我们会处理一个更复杂的数据集,预测葡萄酒的原产地。
5.4.1 数据集描述和加载
这个数据集包含了3种不同起源的葡萄酒,每个数据有13个属性。这些葡萄酒都由意大利制造,但是原产地不一样。
数据变量:
Alcohol:酒精度。
Malic acid:苹果酸。
Ash:灰。
Alcalinity of ash:灰分的碱度。
Magnesium:镁含量。
Total phenols:总酚类。
Flavanoids:黄烷类。
Nonflavanoid phenols:非类黄烷酚。
Proanthocyanins:原花青素。
Color intensity:颜色强度。
Hue:色相。
OD280/OD315 of diluted wines:稀释葡萄酒的OD280 / OD315。
Proline:脯氨酸。
读取该数据集,我们只需要调用pandas库即可。
df = pd.read_csv("./wine.csv", header=0)
5.4.2 数据集预处理
因为该csv文件从1开始,为数据减去该偏差:
y = df['Wine'].values-1
对于其结果,我们使用一位有效编码:
Y = tf.one_hot(indices = y, depth=3, on_value = 1., off_value = 0., axis =
1 , name = "a").eval()
不同变量跟原产地关系散点图如图5-7所示。同样,我们会选择预先打乱数据:
图5-7 不同变量跟原产地关系散点图
X, Y = shuffle (X, Y)
scaler = preprocessing.StandardScaler()
X = scaler.fit_transform(X)
5.4.3 模型架构
该模型只需要一个单层的全链接神经网络:
x = tf.placeholder(tf.float32, [None, 12])。
W = tf.Variable(tf.zeros([12, 3]))。
b = tf.Variable(tf.zeros([3]))。
5.4.4 损失函数描述
我们选择交叉熵作为损失函数:
y_ = tf.placeholder(tf.float32, [None, 3])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y),
reduction_indices=[1]))
5.4.5 损失函数优化器
我们又一次选择梯度下降作为损失函数的优化器。
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy)
5.4.6 收敛性测试
在收敛性测试中,我们将正确预测的结果算作1,错误预测的结果算作0,计算它们的均值,作为该模型的准确度。
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(accuracy.eval())
5.4.7 结果描述
正如我们所见,准确度会随着迭代的次数而波动,但一直是一个大于90%的准确率,远高于30%的基准线(如果我们随机猜测一个0~3的结果)。
0.973684
0.921053
0.921053
0.947368
0.921053
5.4.8 完整源代码
完整源代码如下:
sess = tf.InteractiveSession()
import pandas as pd
# Import data
from sklearn.utils import shuffle
from sklearn import preprocessing
flags = tf.app.flags
FLAGS = flags.FLAGS
df = pd.read_csv("./wine.csv", header=0)
print (df.describe())
#df['displacement']=df['displacement'].astype(float)
X = df[df.columns[1:13]].values
y = df['Wine'].values-1
Y = tf.one_hot(indices = y, depth=3, on_value = 1., off_value = 0., axis =
1 , name = "a").eval()
X, Y = shuffle (X, Y)
scaler = preprocessing.StandardScaler()
X = scaler.fit_transform(X)
# Create the model
x = tf.placeholder(tf.float32, [None, 12])
W = tf.Variable(tf.zeros([12, 3]))
b = tf.Variable(tf.zeros([3]))
# Define loss and optimizer
y_ = tf.placeholder(tf.float32, [None, 3])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y),
reduction_indices=[1]))
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy)
# Train
tf.initialize_all_variables().run()
for i in range(100):
X,Y =shuffle (X, Y, random_state=1)
Xtr=X[0:140,:]
Ytr=Y[0:140,:]
Xt=X[140:178,:]
Yt=Y[140:178,:]
Xtr, Ytr = shuffle (Xtr, Ytr, random_state=0)
batch_xs, batch_ys = Xtr , Ytr
train_step.run()
cost = sess.run (cross_entropy, feed_dict=)
# Test trained model
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(accuracy.eval())
5.5 小结
在本章中,我们开始学习TensorFlow最强的功能:神经网络模型。
通过使用生成模型和实验模型,我们同时实现了神经网络的回归和分类。
在下一章中,我们将会深入新的模型结构,并且将神经网络模型用到其他的知识领域,如将卷积神经网络用于计算机视觉。
-
本文摘自《TensorFlow机器学习项目实战》
领取专属 10元无门槛券
私享最新 技术干货