机器学习是涉及算法的研究、开发和应用的计算机科学领域, 该领域使计算机能从数据中学习。 计算机学习的模型用于进行预测和预测。 机器学习研究人员和工程师通过构建模型然后使用这些模型进行预测来实现这一目标。 现在众所周知,机器学习已成功地应用于各种领域,如自然语言理解,视频处理,图像识别,语音和视觉。
我们来谈谈模型。 所有机器学习问题都以一种或另一种形式抽象为以下等式:
其中,是输出或目标,且
是输入或特征。若
是一个特征及合,我们也将它称作特征向量,并记作
。当我们提到“模型”,指的是找到一个能将特征映射到目标的函数
。因此一旦我们找到了
,我们就能使用新的
值来预测
。
机器学习集中于寻找能用来从预测
的函数
。正如您可能从高中数学时代回忆的那样,该线性等式如下:
我们可以重写前面的简单等式,如下所示:
其中,被称为权重,
被称为偏置。不要担心现在提到的权重和偏置,稍后会有解释。现在,您可以将
视为
和
的等价物,等同于线的等式中的
。 因此,现在机器学习问题可以被陈述为从X的当前值找到
和
的问题,使得该等式可以用于预测
的值。
回归分析或回归建模是指用于估计变量之间关系的方法和技术。 输入到回归模型的变量称为独立变量或预测变量或特征,而回归模型的输出变量称为因变量或目标。 回归模型定义如下:
其中是目标变量,
是一个特征向量,
是一个参数向量。
通常,我们使用一种非常简单的回归形式,称为简单线性回归来估计参数
。
在机器学习问题中,我们必须从给定数据中学习模型参数 和
,以便我们有一个估计模型来预测
的未来
值。我们使用术语权重
和偏差
和 分别用代码中的
和
表示它们。
因此模型如下:
分类是机器学习中的经典问题之一。 正在考虑的数据可以属于一个或其他类别,例如,如果提供的图像是数据,则它们可以是猫或狗的图片。 因此,在这种情况下,类别是猫和狗。 分类是指识别或识别所考虑的数据或对象的标签或类别。 分类属于监督机器学习的范畴。 在分类问题中,提供具有特征或输入及其相应输出或标签的训练数据集。 使用该训练数据集,训练模型;换句话说,计算模型的参数。 然后将训练的模型用于新数据以找到其正确的标签。
分类问题可以有两种类型:二分类或多分类。 二分类意味着数据被分类为两个不同且不连续的标签,例如,患者患有癌症或患者没有癌症,图像是猫或狗。 多分类意味着数据将被分类到多个类别中,例如,电子邮件分类问题会将电子邮件划分为社交媒体电子邮件,与工作相关的电子邮件,个人电子邮件,与家人相关的电子邮件,垃圾邮件,购物优惠电子邮件等等。另一个例子是数字图片的例子;每张图片可以标记在0到9之间,具体取决于图片所代表的数字。在本篇文章中,我们将看到两种分类的示例。
在本章中,我们将进一步扩展以下主题:
- 回归
- 简单线性回归
- 多回归
- 正则化回归(Regularized regression)
- L1范数正则化(Lasso regularization)
- 岭正则化(Ridge regularization)
- ElasticNet 正则化
- 分类
- 使用逻辑回归分类
- 二分类
- 多分类
简单线性回归
您可能使用过其他机器学习库;现在让我们练习使用 TensorFlow 学习简单的线性回归模型。在继续讨论特定领域的示例之前,我们将首先使用生成的数据集解释这些概念。
我们将使用随机生成的数据集,以便来自所有不同领域的读者可以学习而不会被示例的特定领域的细节所淹没。
您可以按照 Jupyter 笔记本 ch-04a_Regression 中的代码进行操作。
数据准备
要生成数据集,我们使用 sklearn 库的数据集模块中的 make_regression 函数:
from sklearn import datasets as skds X, y = skds.make_regression(n_samples=200, n_features=1, n_informative=1, n_targets=1, noise = 20.0)
这将生成一个回归数据集,其中包含一个要素的200个样本值和每个要素的一个目标,并添加了一些噪声。 由于我们只生成一个目标,该函数使用一维NumPy数组生成;因此,我们重塑了两个维度:
if (y.ndim == 1): y = y.reshape(len(y), 1)
我们使用以下代码绘制生成的数据集以查看数据:
import matplotlib.pyplot as plt plt.figure(figsize=(14,8)) plt.plot(X,y,'b.') plt.title('Original Dataset') plt.show()

现在让我们将数据分为训练集和测试集:
X_train, X_test, y_train, y_test = skms.train_test_split(X, y, test_size=.4, random_state=123)
构建一个简单回归模型
要在 TensorFlow 中构建和训练回归模型,通常采取以下步骤:
- 定义输入、参数和其他变量。
- 定义模型。
- 定义损失函数。
- 定义优化函数。
- 以一定迭代次数训练模型,称为“世代”。
定义输入、参数和其他变量
在我们使用 TensorFlow 构建和训练回归模型之前,让我们定义一些重要的变量和操作。 我们从 X_train 和 y_train 中找出输出和输入变量的数量,然后使用这些数字来定义x(x_tensor),y(y_tensor),权重(w)和偏差(b):
num_outputs = y_train.shape[1] num_inputs = X_train.shape[1] x_tensor = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name="x") y_tensor = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name="y") w = tf.Variable(tf.zeros([num_inputs,num_outputs]), dtype=tf.float32, name="w") b = tf.Variable(tf.zeros([num_outputs]), dtype=tf.float32, name="b")
- x_tensor被定义为具有变量行和num_inputs列的形状,并且在我们的示例中列数仅为1
- y_tensor被定义为具有变量行和num_outputs列的形状,并且列数在我们的示例中只有一个维度
- w定义为维度num_inputs x num_outputs的变量,在我们的示例中为1 x 1
- b被定义为维度num_outputs的变量,在我们的示例中是一个维度
定义模型
接下来,我们将模型定义为:
model = tf.matmul(x_tensor, w) + b
定义损失函数
接下来,我们使用均方误差(MSE)定义损失函数。 MSE定义如下:
有关MSE的更多详细信息,请访问以下链接:
https://en.wikipedia.org/wiki/Mean_squared_error
http://www.statisticshowto.com/mean-squared-error/
的实际值和估计值的差异称为残差(residual)。 损失函数计算残差平方的平均值。 我们通过以下方式在 TensorFlow 中定义它:
loss = tf.reduce_mean(tf.square(model - y_tensor))
- model – y_tensor 计算残差
- tf.square(model – y_tensor) 计算每个残差的平方
- tf.reduce_mean(…) 最后计算在前一步骤中得出的平方的均值
我们还定义了均方误差(mse)和r平方(rs)函数来评估训练模型。 我们使用单独的 MSE 函数,因为在接下来的文章中,损失函数将改变但 MSE 函数将保持不变。
#mse and R2 functions mse = tf.reduce_mean(tf.square(model - y_tensor)) y_mean = tf.reduce_mean(y_tensor) total_error = tf.reduce_sum(tf.square(y_tensor - y_mean)) unexplained_error = tf.reduce_sum(tf.square(y_tensor - model)) rs = 1 - tf.div(unexplained_error, total_error)
定义优化函数
接下来,我们实例化了学习率为0.001的 GradientDescentOptimizer 函数,并将其设置为最小化损失函数:
learning_rate = 0.001 optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
有关梯度下降的更多详细信息,请访问以下链接:https://en.wikipedia.org/wiki/Gradient_descent
https://www.analyticsvidhya.com/blog/2017/03/introduction-togradient-descent-algorithm-along-its-variants/
TensorFlow提供了许多其他优化器功能,如Adadelta,Adagrad和Adam。 我们将在接下来的文章中介绍其中一些内容。
训练模型
现在我们已经定义了模型,损失函数和优化器函数,训练模型以学习参数w和b。 要训练模型,请定义以下全局变量:
- num_epochs:运行培训的迭代次数。 每次迭代,模型都会学习更好的参数,我们将在后面的图中看到。
- w_hat 和 b_hat:收集估计的w和b参数。
- loss_epochs, mse_epochs, rs_epochs:收集训练数据集上的总误差值,以及每次迭代中测试数据集上模型的MSE和r平方值。
- mse_score 和 rs_score:收集最终训练模型的 MSE 和r平方值。
num_epochs = 1500 w_hat = 0 b_hat = 0 loss_epochs = np.empty(shape=[num_epochs],dtype=float) mse_epochs = np.empty(shape=[num_epochs],dtype=float) rs_epochs = np.empty(shape=[num_epochs],dtype=float) mse_score = 0 rs_score = 0
初始化会话和全局变量后,运行num_epoch次训练循环:
with tf.Session() as tfs: tf.global_variables_initializer().run() for epoch in range(num_epochs):
在循环的每次迭代中,在训练数据上运行优化器:
tfs.run(optimizer, feed_dict={x_tensor: X_train, y_tensor: y_train})
使用学习的w和b值,计算误差并将其保存在loss_val中以便稍后绘制:
loss_val = tfs.run(loss,feed_dict={x_tensor: X_train, y_tensor: y_train}) loss_epochs[epoch] = loss_val
计算测试数据预测值的均方误差和r平方值:
mse_score = tfs.run(mse,feed_dict={x_tensor: X_test, y_tensor: y_test}) mse_epochs[epoch] = mse_score rs_score = tfs.run(rs,feed_dict={x_tensor: X_test, y_tensor: y_test}) rs_epochs[epoch] = rs_score
最后,一旦完成循环,保存w和b的值以便稍后绘制它们:
w_hat,b_hat = tfs.run([w,b]) w_hat = w_hat.reshape(1)
让我们在2,000次迭代后打印模型和测试数据的最终均方误差:
print('model : Y = {0:.8f} X + {1:.8f}'.format(w_hat[0],b_hat[0])) print('For test data : MSE = {0:.8f}, R2 = {1:.8f} '.format(mse_score,rs_score))
输出如下:
model : Y = 20.37448120 X + -2.75295663 For test data : MSE = 297.57995605, R2 = 0.66098368
因此,我们训练的模型不是一个非常好的模型,但我们将在后面的章节中看到如何使用神经网络来改进它。
本篇文章的目标是介绍如何使用TensorFlow构建和训练回归模型,而无需使用神经网络。
让我们绘制估计模型和原始数据:
我们得到以下原始数据与受训模型数据的关系图:

让我们绘制每次迭代中训练和测试数据的均方误差:
plt.figure(figsize=(14,8)) plt.axis([0,num_epochs,0,np.max(loss_epochs)]) plt.plot(loss_epochs, label='Loss on X_train') plt.title('Loss in Iterations') plt.xlabel('# Epoch') plt.ylabel('MSE') plt.axis([0,num_epochs,0,np.max(mse_epochs)]) plt.plot(mse_epochs, label='MSE on X_test') plt.xlabel('# Epoch') plt.ylabel('MSE') plt.legend() plt.show()
我们得到以下图表,显示每次迭代时,均方误差减小,然后保持在500附近的相同水平:

让我们绘制r平方的值:
plt.figure(figsize=(14,8)) plt.axis([0,num_epochs,0,np.max(rs_epochs)]) plt.plot(rs_epochs, label='R2 on X_test') plt.xlabel('# Epoch') plt.ylabel('R2') plt.legend() plt.show()
当我们绘制r平方超过时期的值时,我们得到以下图:

这基本上表明模型以非常低的r平方值开始,但随着模型的训练并减少误差,r平方的值开始变高,最终在略高于0.6的点处变得稳定。
绘制 MSE 和 r-squared 可以让我们看到我们的模型训练得有多快以及它在何处(即在减少误差方面产生好处太少或几乎没有好处的地方)开始变得更稳定。
使用训练好的模型预测
现在您已经拥有训练有素的模型,它可用于预测新数据。 线性模型的预测是通过理解我们在前一个图中看到的一些最小均方误差得出的,因为直线可能不完全适合数据。
为了获得更好的拟合模型,我们必须使用不同的方法扩展我们的模型,例如添加变量的线性组合。
多回归
现在您已经学习了如何使用TensorFlow创建基本回归模型,让我们尝试在不同域的示例数据集上运行它。 我们作为示例数据集生成的数据集是单变量的,即目标仅依赖于一个特征。
实际上,大多数数据集都是多变量的。 为了强调一点,目标取决于多个变量或特征,因此回归模型称为多元回归或多维回归。
我们首先从最受欢迎的波士顿数据集开始。 该数据集包含波士顿506所房屋的13个属性,例如每个住所的平均房间数,一氧化氮浓度,到波士顿五个就业中心的加权距离等等。 目标是自住房屋的中位数值。 让我们深入探索这个数据集的回归模型。
从sklearn库加载数据集并查看其描述:
boston=skds.load_boston() print(boston.DESCR) X=boston.data.astype(np.float32) y=boston.target.astype(np.float32) if (y.ndim == 1): y = y.reshape(len(y),1) X = skpp.StandardScaler().fit_transform(X)
我们还要提取X,也就是一个特征矩阵,以及y,前面代码中提到的目标向量。我们重塑y使其成为二维的并且将x中的特征缩放为平均值为0以及标准差为1。 现在让我们使用这个 X 和 y 来训练回归模型,就像我们在前面的例子中所做的那样:
您可能会发现此示例的代码类似于上一节中关于简单回归的代码; 但是,我们使用多个功能来训练模型,因此称为多元回归。
X_train, X_test, y_train, y_test = skms.train_test_split(X, y, test_size=.4, random_state=123) num_outputs = y_train.shape[1] num_inputs = X_train.shape[1] x_tensor = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name="x") y_tensor = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name="y") w = tf.Variable(tf.zeros([num_inputs,num_outputs]), dtype=tf.float32, name="w") b = tf.Variable(tf.zeros([num_outputs]), dtype=tf.float32, name="b") model = tf.matmul(x_tensor, w) + b loss = tf.reduce_mean(tf.square(model - y_tensor)) # mse and R2 functions mse = tf.reduce_mean(tf.square(model - y_tensor)) y_mean = tf.reduce_mean(y_tensor) total_error = tf.reduce_sum(tf.square(y_tensor - y_mean)) unexplained_error = tf.reduce_sum(tf.square(y_tensor - model)) rs = 1 - tf.div(unexplained_error, total_error) learning_rate = 0.001 optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) num_epochs = 1500 loss_epochs = np.empty(shape=[num_epochs],dtype=np.float32) mse_epochs = np.empty(shape=[num_epochs],dtype=np.float32) rs_epochs = np.empty(shape=[num_epochs],dtype=np.float32) mse_score = 0 rs_score = 0 with tf.Session() as tfs: tfs.run(tf.global_variables_initializer()) for epoch in range(num_epochs): feed_dict = {x_tensor: X_train, y_tensor: y_train} loss_val, _ = tfs.run([loss, optimizer], feed_dict) loss_epochs[epoch] = loss_val feed_dict = {x_tensor: X_test, y_tensor: y_test} mse_score, rs_score = tfs.run([mse, rs], feed_dict) mse_epochs[epoch] = mse_score rs_epochs[epoch] = rs_score print('For test data : MSE = {0:.8f}, R2 = {1:.8f} '.format(mse_score, rs_score))
我们从模型中获得以下输出:
For test data : MSE = 30.48501778, R2 = 0.64172244
让我们绘制 MSE 和R平方值。
下图显示了MSE图:

下图显示了R平方值的绘图:

正如我们在单变量数据集中看到的那样,我们看到了MSE和r平方的类似模式。
正则化回归
在线性回归中,我们训练的模型返回训练数据的最佳拟合参数。 但是,在训练数据上找到最合适的参数可能会导致过度拟合。
过度拟合意味着模型最适合训练数据,但会给测试数据带来更大的误差。 因此,我们通常在模型中添加惩罚项以获得更简单的模型。
该惩罚项称为正则化项,由此获得的回归模型称为正则化回归模型。 正则化模型有三种主要类型:
- L1范数正则化:在 Lasso 正则化中,也称为L1正则化,正则化项是套索参数α乘以权重w的绝对值之和。 因此,损失函数如下:
- 岭正则化:在岭正则化(也称为L2正则化)中,正则化项是岭参数α乘以权重w的平方和。 因此,损失函数如下:
- ElasticNet 回归:当我们添加套索和脊正则化项时,所得到的正则化称为ElasticNet正则化。 因此,损失函数如下:
有关正则化的更多详细信息,请参阅互联网上的以下资源:
http://www.statisticshowto.com/regularization/
一个简单的经验法则是当我们想要删除某些特征时使用L1或Lasso正则化,从而减少计算时间,但代价是降低了准确性。
现在让我们看看在TensorFlow中实现的这些正则化损失函数。 我们将继续使用前面示例中使用的Boston数据集。
Lasso 正则化
我们将lasso参数定义为值0.8:
lasso_param = tf.Variable(0.8, dtype=tf.float32) lasso_loss = tf.reduce_mean(tf.abs(w)) * lasso_param
将 Lasso 参数设置为零意味着没有正则化,因为该项变为零。 正则化项的值越高,惩罚越高。以下是 Lasso 正则化回归的完整代码,用于训练模型以预测波士顿房屋定价:
下面的代码假定列车和测试数据集已按照前面的示例进行拆分。
num_outputs = y_train.shape[1] num_inputs = X_train.shape[1] x_tensor = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name='x') y_tensor = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name='y') w = tf.Variable(tf.zeros([num_inputs, num_outputs]), dtype=tf.float32, name='w') b = tf.Variable(tf.zeros([num_outputs]), dtype=tf.float32, name='b') model = tf.matmul(x_tensor, w) + b lasso_param = tf.Variable(0.8, dtype=tf.float32) lasso_loss = tf.reduce_mean(tf.abs(w)) * lasso_param loss = tf.reduce_mean(tf.square(model - y_tensor)) + lasso_loss learning_rate = 0.001 optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) mse = tf.reduce_mean(tf.square(model - y_tensor)) y_mean = tf.reduce_mean(y_tensor) total_error = tf.reduce_sum(tf.square(y_tensor - y_mean)) unexplained_error = tf.reduce_sum(tf.square(y_tensor - model)) rs = 1 - tf.div(unexplained_error, total_error) num_epochs = 1500 loss_epochs = np.empty(shape=[num_epochs],dtype=np.float32) mse_epochs = np.empty(shape=[num_epochs],dtype=np.float32) rs_epochs = np.empty(shape=[num_epochs],dtype=np.float32) mse_score = 0.0 rs_score = 0.0 num_epochs = 1500 loss_epochs = np.empty(shape=[num_epochs], dtype=np.float32) mse_epochs = np.empty(shape=[num_epochs], dtype=np.float32) rs_epochs = np.empty(shape=[num_epochs], dtype=np.float32) mse_score = 0.0 rs_score = 0.0 with tf.Session() as tfs: tfs.run(tf.global_variables_initializer()) for epoch in range(num_epochs): feed_dict = {x_tensor: X_train, y_tensor: y_train} loss_val,_ = tfs.run([loss,optimizer], feed_dict) loss_epochs[epoch] = loss_val feed_dict = {x_tensor: X_test, y_tensor: y_test} mse_score,rs_score = tfs.run([mse,rs], feed_dict) mse_epochs[epoch] = mse_score rs_epochs[epoch] = rs_score print('For test data : MSE = {0:.8f}, R2 = {1:.8f} '.format(mse_score, rs_score))
我们得到以下输出:
For test data : MSE = 30.48978233, R2 = 0.64166653
让我们使用以下代码绘制MSE和r平方的值:
plt.figure(figsize=(14,8)) plt.axis([0,num_epochs,0,np.max([loss_epochs,mse_epochs])]) plt.plot(loss_epochs, label='Loss on X_train') plt.plot(mse_epochs, label='MSE on X_test') plt.title('Loss in Iterations') plt.xlabel('# Epoch') plt.ylabel('Loss or MSE') plt.legend() plt.show() plt.figure(figsize=(14,8)) plt.axis([0,num_epochs,np.min(rs_epochs),np.max(rs_epochs)]) plt.title('R-squared in Iterations') plt.plot(rs_epochs, label='R2 on X_test') plt.xlabel('# Epoch') plt.ylabel('R2') plt.legend() plt.show()
我们得到以下损失图:

迭代R平方的图如下:

让我们用岭回归重复相同的例子。
岭正则化
以下是岭正则化回归的完整代码,用于训练模型以预测波士顿房屋定价:
num_outputs = y_train.shape[1] num_inputs = X_train.shape[1] x_tensor = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name='x') y_tensor = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name='y') w = tf.Variable(tf.zeros([num_inputs, num_outputs]), dtype=tf.float32, name='w') b = tf.Variable(tf.zeros([num_outputs]), dtype=tf.float32, name='b') model = tf.matmul(x_tensor, w) + b ridge_param = tf.Variable(0.8, dtype=tf.float32) ridge_loss = tf.reduce_mean(tf.square(w)) * ridge_param loss = tf.reduce_mean(tf.square(model - y_tensor)) + ridge_loss learning_rate = 0.001 optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) mse = tf.reduce_mean(tf.square(model - y_tensor)) y_mean = tf.reduce_mean(y_tensor) total_error = tf.reduce_sum(tf.square(y_tensor - y_mean)) unexplained_error = tf.reduce_sum(tf.square(y_tensor - model)) rs = 1 - tf.div(unexplained_error, total_error) num_epochs = 1500 loss_epochs = np.empty(shape=[num_epochs],dtype=np.float32) mse_epochs = np.empty(shape=[num_epochs],dtype=np.float32) rs_epochs = np.empty(shape=[num_epochs],dtype=np.float32) mse_score = 0.0 rs_score = 0.0 with tf.Session() as tfs: tfs.run(tf.global_variables_initializer()) for epoch in range(num_epochs): feed_dict = {x_tensor: X_train, y_tensor: y_train} loss_val, _ = tfs.run([loss, optimizer], feed_dict=feed_dict) loss_epochs[epoch] = loss_val feed_dict = {x_tensor: X_test, y_tensor: y_test} mse_score, rs_score = tfs.run([mse, rs], feed_dict=feed_dict) mse_epochs[epoch] = mse_score rs_epochs[epoch] = rs_score print('For test data : MSE = {0:.8f}, R2 = {1:.8f} '.format(mse_score, rs_score))
我们得到以下结果:
For test data : MSE = 30.64177132, R2 = 0.63988018
绘制损失和MSE的值,我们得到以下损失图:

我们得到以下R平方图:

让我们来看看 Lasso 和岭线正则化方法的组合。
ElasticNet 正则化
在笔记本ch-04a_Regression中提供了ElasticNet正则化回归的完整代码,用于训练模型以预测波士顿房屋定价。在运行模型时,我们得到以下结果:
For test data : MSE = 30.64861488, R2 = 0.63979971
绘制损失和MSE的值,我们得到以下图:

我们得到以下R平方图:

使用逻辑回归进行分类
最常用的分类方法是使用逻辑回归。逻辑回归是概率和线性分类器。输入特征的向量是特定类的成员的概率可以正式写成如下等式:
在上述等式中:
代表输出
代表分类中的某一个
代表输入
代表权重
代表偏置
代表回归等式
代表我们的例子中的平滑函数或模型
前面的等式表示当给出 和
时
属于类
的概率,由函数
表示。因此,必须训练模型以最大化概率值。
二元分类的逻辑回归
对于二元分类,我们将模型函数 定义为 sigmoid 函数,如下所示:
sigmoid 函数使 的值位于范围 [0,1] 之间。因此,我们可以使用
的值来预测类:如果
则 class 等于 1,否则 class 等于 0。
正如我们在本章的前几节中所看到的,对于线性回归,可以通过查找最小化损失函数的参数来训练模型,并且损失函数可以是平方误差或均方误差的总和。对于逻辑回归,我们希望最大化概率:
但是,由于更容易使对数似然最大化,因此我们使用对数似然 作为成本函数。 因此,损失函数
被写为
,其可以使用诸如梯度下降的优化算法来最小化。
二元逻辑回归的损失函数在数学上写成如下:
其中 是 sigmoid 函数。
我们将在下一节中实现这个损失函数。
多类分类的逻辑回归
当涉及两个以上的类时,逻辑回归被称作多项逻辑回归。在多项逻辑回归中,我们使用softmax函数代替sigmoid,这是最受欢迎的函数之一。 Softmax可以用数学表示如下:
Softmax函数产生每个类的概率,所有概率向量之和为1。在预测时,具有最高softmax值的类成为输出或预测类。正如我们前面讨论的那样,损失函数是负对数似然函数,其可以由诸如梯度下降的优化器最小化。
多项Logistic回归的损失函数正式写成如下:
其中, 是 softmax 函数。
我们将在本篇文章稍后提到实现损失函数。
让我们在下一节中深入研究一些例子。
您可以按照Jupyter中的代码进行操作
笔记本文件名为ch-04b_Classification。
二分类
二分类是指仅有两个不同类的问题。正如我们在前一篇文章中所做的那样,我们将使用SciKit Learn库中的便捷函数 make_classification() 生成数据集:
X, y = skds.make_classification(n_samples=200, n_features=2, n_informative=2, n_redundant=0, n_repeated=0, n_classes=2, n_clusters_per_class=1) if (y.ndim == 1): y = y.reshape(-1,1)
make_classification() 的参数是不言自明的;n_samples是要生成的数据点的数量,n_features是要生成的要素的数量,n_classes是类的数量,即2:
- n_samples:是要生成的数据点的数量。 我们将其保持在200以保持数据集较小。
- n_features:是要生成的特征数量;我们只使用两个特征,因此我们可以将它作为一个简单的问题来理解TensorFlow命令。
- n_classes:类的数量是2,因为它是二进制分类问题。
让我们使用以下代码绘制数据:
plt.scatter(X[:,0],X[:,1],marker='o',c=y) plt.show()
我们得到以下情节;您可能会得到一个不同的图,因为每次运行数据生成函数时都会随机生成数据:

然后我们使用NumPy单位阵函数将 转换为单热编码目标:
print(y[0:5]) y=np.eye(num_outputs)[y] print(y[0:5])
单热编码目标如下所示:
[1 0 0 1 0] [[ 0. 1.] [ 1. 0.] [ 1. 0.] [ 0. 1.] [ 1. 0.]]
将数据划分为训练和测试类别:
X_train, X_test, y_train, y_test = skms.train_test_split(X, y, test_size=.4, random_state=42)
在分类中,我们使用sigmoid函数来量化模型的值,使得输出值位于范围 之间。以下等式表示由
表示的 sigmoid 函数,其中
是等式
。 损失函数现在变为由
表示的值,其中
表示参数。
我们使用以下代码实现新模型和损失函数:
num_outputs = y_train.shape[1] num_inputs = X_train.shape[1] learning_rate = 0.001 # input images x = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name="x") # output labels y = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name="y") # model paramteres w = tf.Variable(tf.zeros([num_inputs,num_outputs]), name="w") b = tf.Variable(tf.zeros([num_outputs]), name="b") model = tf.nn.sigmoid(tf.matmul(x, w) + b) loss = tf.reduce_mean(-tf.reduce_sum((y * tf.log(model)) + ((1 - y) * tf.log(1 - model)), axis=1)) optimizer = tf.train.GradientDescentOptimizer( learning_rate=learning_rate).minimize(loss)
最后,我们运行一下我们的分类模型:
num_epochs = 1 with tf.Session() as tfs: tf.global_variables_initializer().run() for epoch in range(num_epochs): tfs.run(optimizer, feed_dict={x: X_train, y: y_train}) y_pred = tfs.run(tf.argmax(model, 1), feed_dict={x: X_test}) y_orig = tfs.run(tf.argmax(y, 1), feed_dict={y: y_test}) preds_check = tf.equal(y_pred, y_orig) accuracy_op = tf.reduce_mean(tf.cast(preds_check, tf.float32)) accuracy_score = tfs.run(accuracy_op) print("epoch {0:04d} accuracy={1:.8f}".format(epoch, accuracy_score)) plt.figure(figsize=(14, 4)) plt.subplot(1, 2, 1) plt.scatter(X_test[:, 0], X_test[:, 1], marker='o', c=y_orig) plt.title('Original') plt.subplot(1, 2, 2) plt.scatter(X_test[:, 0], X_test[:, 1], marker='o', c=y_pred) plt.title('Predicted') plt.show()
我们获得了大约96%的相当好的准确度,原始和预测的数据图如下所示:

很简约!! 现在让我们让我们的问题变得复杂,并尝试预测两个以上的类。
多类分类
多类分类的一个流行示例是标记手写数字的图像。此示例中的类或标签为{0,1,2,3,4,5,6,7,8,9}。在以下示例中,我们将使用MNIST。 让我们像前面章节中所做的那样加载MNIST图像,代码如下:
from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets(os.path.join(datasetslib.datasets_root, 'mnist'), one_hot=True)
如果已按照前一章的说明下载了MNIST数据集,那么我们将获得以下输出:
Extracting /Users/armando/datasets/mnist/train-images-idx3-ubyte.gz Extracting /Users/armando/datasets/mnist/train-labels-idx1-ubyte.gz Extracting /Users/armando/datasets/mnist/t10k-images-idx3-ubyte.gz Extracting /Users/armando/datasets/mnist/t10k-labels-idx1-ubyte.gz
现在让我们设置一些参数,如下面的代码所示:
num_outputs = 10 # 0-9 digits num_inputs = 784 # total pixels learning_rate = 0.001 num_epochs = 1 batch_size = 100 num_batches = int(mnist.train.num_examples/batch_size)
上面代码中的参数如下:
- num_outputs:由于我们必须预测图像表示十位数中的哪一位,因此我们将输出数设置为10。数字由输出本身所代表的数字决定,或设置为1。
- num_inputs:我们知道,我们的输入数字是 28 x 28 像素,因此每个像素都是模型的输入。因此我们一共有784个输入。
- learning_rates:此参数表示梯度下降优化器算法的学习速率。我们将学习率任意设定为0.001。
- num_epochs:我们将仅为第一个实例运行一次迭代,因此我们将时期数量任意设置为1.e至0.001。
- batch_size:在现实世界中,我们可能拥有庞大的数据集,并且加载整个数据集以便训练模型基本是不可能的。因此,我们将输入数据分成随机选择的批次。我们将batch_size设置为100个图像,可以使用TensorFlow的内置算法一次性选择出来。
- num_batches:此参数的设置应根据总数据集中选择批次的次数;我们将其设置为等于数据集中的项目数除以批处理中的项目数。
我们鼓励您尝试使用这些参数的不同值。
现在让我们使用以下代码定义输入,输出,参数,模型和损失函数:
# input images x = tf.placeholder(dtype=tf.float32, shape=[None, num_inputs], name="x") # output labels y = tf.placeholder(dtype=tf.float32, shape=[None, num_outputs], name="y") # model paramteres w = tf.Variable(tf.zeros([784, 10]), name="w") b = tf.Variable(tf.zeros([10]), name="b") model = tf.nn.softmax(tf.matmul(x, w) + b) loss = tf.reduce_mean(-tf.reduce_sum(y * tf.log(model), axis=1)) optimizer = tf.train.GradientDescentOptimizer( learning_rate=learning_rate).minimize(loss)
代码类似于二元分类示例,但有一个显着差异:我们使用softmax而不是sigmoid函数。 Softmax用于多类分类,而sigmoid用于二元类分类。 Softmax函数是S形函数的推广,其将任意实数值的n维向量z转换为加起来为1的范围 中的实数值的n维向量
。
现在让我们运行模型并打印精度:
with tf.Session() as tfs: tf.global_variables_initializer().run() for epoch in range(num_epochs): for batch in range(num_batches): batch_x, batch_y = mnist.train.next_batch(batch_size) tfs.run(optimizer, feed_dict={x: batch_x, y: batch_y}) predictions_check = tf.equal(tf.argmax(model, 1), tf.argmax(y, 1)) accuracy_function = tf.reduce_mean(tf.cast(predictions_check, tf.float32)) feed_dict = {x: mnist.test.images, y: mnist.test.labels} accuracy_score = tfs.run(accuracy_function, feed_dict) print("epoch {0:04d} accuracy={1:.8f}".format(epoch, accuracy_score))
我们得到了以下精确度:
epoch 0000 accuracy=0.76109999
让我们尝试在多次迭代中训练我们的模型,以便在每次迭代中学习不同的批次。我们建立了两个支持函数来帮助我们:
def mnist_batch_func(batch_size=100): batch_x, batch_y = mnist.train.next_batch(batch_size) return [batch_x, batch_y]
上述函数将批处理中的示例数作为输入,并使用 mnist.train.next_batch() 函数返回一批要素 (batch_x) 和目标 (batch_y) :
def tensorflow_classification(num_epochs, num_batches, batch_size, batch_func, optimizer, test_x, test_y): accuracy_epochs = np.empty(shape=[num_epochs], dtype=np.float32) with tf.Session() as tfs: tf.global_variables_initializer().run() for epoch in range(num_epochs): for batch in range(num_batches): batch_x, batch_y = batch_func(batch_size) feed_dict = {x: batch_x, y: batch_y} tfs.run(optimizer, feed_dict) predictions_check = tf.equal(tf.argmax(model, 1), tf.argmax(y, 1)) accuracy_function = tf.reduce_mean( tf.cast(predictions_check, tf.float32)) feed_dict = {x: test_x, y: test_y} accuracy_score = tfs.run(accuracy_function, feed_dict) accuracy_epochs[epoch] = accuracy_score print("epoch {0:04d} accuracy={1:.8f}".format(epoch, accuracy_score)) plt.figure(figsize=(14, 8)) plt.axis([0, num_epochs, np.min(accuracy_epochs), np.max(accuracy_epochs)]) plt.plot(accuracy_epochs, label='Accuracy Score') plt.title('Accuracy over Iterations') plt.xlabel('# Epoch') plt.ylabel('Accuracy Score') plt.legend() plt.show()
上述函数获取参数并执行训练迭代,打印每次迭代的准确度分数并打印准确度分数。 它还保存了accuracy_epochs数组中每个时代的准确度分数。之后,它绘制了每个时代的准确性。让我们使用我们之前设置的参数运行此函数30个时代,使用以下代码:
num_epochs=30 tensorflow_classification(num_epochs=num_epochs, num_batches=num_batches, batch_size=batch_size, batch_func=mnist_batch_func, optimizer=optimizer, test_x=mnist.test.images,test_y=mnist.test.labels)
我们得到以下准确度和图表:
epoch 0000 accuracy=0.76020002 epoch 0001 accuracy=0.79420000 epoch 0002 accuracy=0.81230003 epoch 0003 accuracy=0.82309997 epoch 0004 accuracy=0.83230001 epoch 0005 accuracy=0.83770001 --- epoch 6 to 24 removed for brevity --- epoch 0025 accuracy=0.87930000 epoch 0026 accuracy=0.87970001 epoch 0027 accuracy=0.88059998 epoch 0028 accuracy=0.88120002 epoch 0029 accuracy=0.88180000

从图中我们可以看出,初始迭代中的准确度会急剧提高,然后准确度的提高速度会降低。稍后,我们将看到如何在TensorFlow中使用神经网络的全部功能,并将此分类精度提高到更大的值。
总结
在本文中,我们学习了如何在TensorFlow中应用经典机器学习算法,而不使用神经网络。 在本章的第一部分,我们了解了回归模型。我们解释了如何训练具有一个或多个特征的线性回归模型。我们使用TensorFlow编写线性回归代码。我们还讨论了正则化基本上是增加一个惩罚项,以便模型在训练阶段学习参数时不会过度拟合训练数据。我们使用TensorFlow实现了 Lasso、Ridge 和 ElasticNet 正则化。 TensorFlow有一些内置的正则化方法,我们将在下一篇文章中学习。
在本文的后续章节中,我们了解了有监督机器学习中的分类问题。我们讨论了二分类和多类分类的模型函数,平滑函数和损失函数。我们在本章中使用了逻辑回归,因为这是实现分类的最简单方法。对于二进制分类,我们使用sigmoid函数,对于多类分类,我们使用softmax函数来平滑线性模型的值,以产生输出在特定类中的概率。
我们在TensorFlow中实现了模型和损失函数的逻辑,并训练模型进行二分类和多类分类。虽然我们在本文中使用了经典的机器学习方法并使用TensorFlow实现了它们,但是当我们实现神经网络和深度神经网络来解决机器学习问题时,TensorFlow的全部功能才得以释放。我们将在本系列有关神经网络的文章的相关章节中研究这些高级方法。
关于 “使用 TensorFlow 的经典机器学习案例” 的 1 个意见
您必须登录才能发表评论。