精通 TensorFlow 1.x:1~5(2)https://developer.aliyun.com/article/1426815
我们得到以下原始数据与受训模型数据的关系图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HL0lY202-1681566326307)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/987b1418-d3bc-40d6-9412-0826b81fded5.png)]
让我们绘制每次迭代中训练和测试数据的均方误差:
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 附近的相同水平:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hwTFmUAz-1681566326307)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/02e135a4-4a8a-47ad-a85e-48bec81ce693.png)]
让我们绘制 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 平方超过周期的值时,我们得到以下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VJWxV3C3-1681566326307)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/b8c11857-8723-4d5c-9e56-a064607aabe8.png)]
这基本上表明该模型以 R 的平均值开始,但随着模型的训练并减少误差,R 平方的值开始变高,最终在某一点变得稳定略高于 0.6。
绘制 MSE 和 R 平方可以让我们看到我们的模型得到多快的训练以及它开始变得稳定的地方,以便进一步的训练在减少误差方面产生微不足道的好处或几乎没有好处。
使用训练的模型进行预测
现在您已经拥有训练有素的模型,它可用于预测新数据。线性模型的预测是通过理解我们在前一个图中看到的一些最小均方误差得出的,因为直线可能不完全适合数据。
为了获得更好的拟合模型,我们必须使用不同的方法扩展我们的模型,例如添加变量的线性组合。
多元回归
现在您已经学习了如何使用 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
中的特征缩放为平均值为零,标准差为 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 的绘图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KScRpOxr-1681566326308)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/b90f3cfb-8b86-47d7-9d0d-64d94acd59f2.png)]
下图显示了 R 平方值的绘图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AfNyl46Z-1681566326308)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/60be36ac-1116-4f4e-a5dc-15fffcea81f1.png)]
正如我们在单变量数据集中看到的那样,我们看到了 MSE 和 R 平方的类似模式。
正则化回归
在线性回归中,我们训练的模型返回训练数据的最佳拟合参数。但是,在训练数据上找到最合适的参数可能会导致过拟合。
过拟合意味着模型最适合训练数据,但会给测试数据带来更大的误差。因此,我们通常在模型中添加惩罚项以获得更简单的模型。
该惩罚项称为正则化项,由此获得的回归模型称为正则化回归模型。正则化模型有三种主要类型:
- LASSO 回归:在 LASSO 正则化中,也称为 L1 正则化,正则化项是 LASSO 参数
α
乘以权重w
绝对值之和。因此,损失函数如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wLOkeZVN-1681566326308)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/662a9855-a00c-41ad-8b0e-2b65dbfbdd69.png)]
- 岭回归:在岭正则化中,也称为 L2 正则化,正则化项是岭参数
α
乘以i-th
权重w
的平方和。因此,损失函数如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CWgQA3Lf-1681566326309)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/b6aba15b-577d-4a22-a559-bd6f1f2e0d1b.png)]
- ElasticNet 回归:当我们添加 LASSO 和岭正则化项时,得到的正则化称为 ElasticNet 正则化。因此,损失函数如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pSaFpuE0-1681566326309)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/f6144fe6-9175-4d26-9e6b-f07fb0cd3212.png)]
有关正则化的更多详细信息,请参阅互联网上的这些资源。
一个简单的经验法则是当我们想要删除某些特征时使用 L1 或 LASSO,从而减少计算时间,但代价是降低了准确率。
现在让我们看看在 TensorFlow 中实现的这些正则化损失函数。我们将继续使用前面示例中使用的波士顿数据集。
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()
我们得到以下损失绘图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dWpZpUa2-1681566326309)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/e0e1db8b-6a49-4e35-89a8-0acde4ad83cc.png)]
迭代中 R 平方的图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DEVcakta-1681566326310)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/f75f8e2b-1395-4a1c-b50e-1f44ba2dd7da.png)]
让我们用岭回归重复相同的例子。
岭正则化
以下是岭正则化回归的完整代码,用于训练模型以预测波士顿房屋定价:
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 的值,我们得到以下损失图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qnX5QdGI-1681566326310)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/0f74f654-50a2-4203-b9e8-0a2f29d7cd38.png)]
我们得到以下 R 平方图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UXnOv1Vu-1681566326310)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/56fd975b-a22b-44b4-83aa-dc0d38ad77ce.png)]
让我们来看看 LASSO 和岭正则化方法的组合。
ElasticNet 正则化
笔记本ch-04a_Regression
提供了 ElasticNet 正规回归的完整代码,用于训练模型以预测波士顿房屋定价。在运行模型时,我们得到以下结果:
For test data : MSE = 30.64861488, R2 = 0.63979971
绘制损失和 MSE 的值,我们得到以下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0sZ64J2O-1681566326311)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/71369789-39e3-4c2c-affb-d46290e841ab.png)]
我们得到以下 R 平方图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Ekt5Ih3-1681566326311)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/c8314797-8170-4325-b9ac-d563348c0609.png)]
逻辑回归和分类
最常用的分类方法是使用逻辑回归。逻辑回归是概率和线性分类器。输入是特征向量,特定类的成员的概率可以正式写成如下等式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZGPZvRTo-1681566326311)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/b54ac424-2f70-4aee-afca-253935b4a455.png)]In the above equation:
y
代表输出,i
代表其中一个类x
代表输入w
代表权重b
代表偏置z
代表回归方程z = w × x + b
φ
代表我们案例中的平滑函数或模型
前面的等式表示当w
和b
被给出时x
属于i
类的概率由函数表示φ((z)
。因此,必须训练模型以最大化概率值。
二分类的逻辑回归
对于二分类,我们将模型函数φ(z)
定义为 sigmoid 函数,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wc9HKyGp-1681566326312)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/62e26ec4-6cff-4601-b544-cb79aa11a704.png)]
sigmoid 函数在范围[0, 1]
之间产生 y 的值。因此,我们可以使用y = φ(z)
的值来预测类:如果y > 0.5
则类别等于 1,否则类别等于 0。
正如我们在本章的前几节中所见,对于线性回归,可以通过查找最小化损失函数的参数来训练模型,并且损失函数可以是平方误差或均方误差的总和。对于逻辑回归,我们希望最大化可能性:L(w) = P(y|x, w, b)
。
但是,由于更容易使对数似然最大化,因此我们使用对数似然l(w)
作为成本函数。因此,损失函数(J(w)
)被写为-1(w)
,其可以使用诸如梯度下降的优化算法来最小化。
二元逻辑回归的损失函数在数学上写成如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dfObkdLX-1681566326312)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/43249834-ffa5-490f-842b-3be538ea34e8.png)]
其中φ(z)
是 Sigmoid 函数。
我们将在下一节中实现这个损失函数。
多类分类的逻辑回归
当涉及两个以上的类时,逻辑回归是已知的多项逻辑回归。在多项逻辑回归中,我们使用 softmax 函数代替 sigmoid,它是最受欢迎的函数之一。 Softmax 可以用数学表示如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zBfU7tLh-1681566326312)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/31227522-ba57-4b0d-a624-566ce56452aa.png)]
Softmax 函数产生每个类的概率,概率向量和为 1。在预测时,具有最高 softmax 值的类成为输出或预测类。正如我们前面讨论的那样,损失函数是负对数似然函数-l(w)
,它可以被优化器最小化,例如梯度下降。
多项逻辑回归的损失函数正式写成如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QWvFTLE3-1681566326313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/8a2c95b7-307d-4e20-8374-6db23980125e.png)]
其中φ(z)
是 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()
我们得到以下绘图;您可能会得到一个不同的图,因为每次运行数据生成函数时都会随机生成数据:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1EjcDt2E-1681566326313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/707586af-1084-493a-86a8-f827a115cfa5.png)]
然后我们使用 NumPy eye
函数将y
转换为单热编码目标:
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 函数来量化模型的值,使得输出值位于范围[0,1]之间。以下等式表示由φ(z)
表示的 Sigmoid 函数,其中z
是等式w × x + b
。损失函数现在变为由J(θ)
表示的值,其中θ
表示参数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9z9iVA6M-1681566326313)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/af47d49d-2bb6-4e48-b6d3-4d7cd65ff6d5.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nBDfxRbg-1681566326314)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/e5b82a11-b867-4a43-9f3d-09d6cb44099b.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GKrvVhY8-1681566326315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/717945b1-b35a-43d9-a469-44f33de91e8a.png)]
我们使用以下代码实现新模型和损失函数:
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% 的相当好的准确率,原始和预测的数据图如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SG9WJoX7-1681566326315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/abc7eea6-1cdf-486e-9f34-0b571ef90b67.png)]
很简约!!现在让我们让我们的问题变得复杂,并尝试预测两个以上的类。
多类分类
多类分类的一个流行示例是标记手写数字的图像。此示例中的类或标签为{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_rate
:此参数表示梯度下降优化器算法的学习率。我们将学习率任意设定为 0.001。num_epochs
:我们将仅针对一次迭代运行我们的第一个示例,因此我们将周期数设置为 1。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 函数是 sigmoid 函数的推广,它将任意实数值的 n 维向量 z 转换为实数值的 n 维向量σ(z)
,范围(0, 1]
和为 1。
现在让我们运行模型并打印精度:
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
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cxu4vASV-1681566326315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/19db0579-c2c6-4d7a-a4ef-a2417fc5fd2f.png)]
从图中我们可以看出,初始迭代中的准确率会急剧提高,然后准确率的提高速度会降低。稍后,我们将看到如何在 TensorFlow 中使用神经网络的全部功能,并将此分类精度提高到更大的值。
总结
在本章中,我们学习了如何在 TensorFlow 中应用经典机器学习算法,而不使用神经网络。在本章的第一部分,我们了解了回归模型。我们解释了如何训练具有一个或多个特征的线性回归模型。我们使用 TensorFlow 编写线性回归代码。我们还讨论了正则化基本上是增加一个惩罚项,以便模型在训练阶段学习参数时不会过拟合训练数据。我们使用 TensorFlow 实现了 Lasso,Ridge 和 ElasticNet 正则化。 TensorFlow 有一些内置的正则化方法,我们将在下一章中学习。
在本章的后续章节中,我们了解了有监督机器学习中的分类问题。我们讨论了两类和多类分类的模型函数,平滑函数和损失函数。我们在本章中使用了逻辑回归,因为这是实现分类的最简单方法。对于二分类,我们使用 sigmoid 函数,对于多类分类,我们使用 softmax 函数来平滑线性模型的值,以产生输出在特定类中的概率。
我们在 TensorFlow 中实现了模型和损失函数的逻辑,并训练模型进行二分类和多类分类。虽然我们在本章中使用了经典的机器学习方法,并使用 TensorFlow 实现了它们,但是当我们实现神经网络和深度神经网络来解决机器学习问题时,TensorFlow 的全部功能得以释放。我们将在本书的神经网络相关章节中研究这些高级方法。
建议您阅读以下书籍以了解有关回归和分类的更多详细信息:
Sebastian Raschka,Python 机器学习,第 2 版,Packt Publishing,2017
Trevor Hastie,Robert Tibshirani,Jerome Friedman,统计学习的要素,第二版,施普林格,2013
五、TensorFlow 和 Keras 中的神经网络和 MLP
神经网络是一种受大脑结构和功能启发的建模技术。正如大脑包含数百万个被称为神经元的微小互连单元一样,今天的神经网络由数百万个分层排列的微小互连计算单元组成。由于神经网络的计算单元仅存在于数字世界中,与大脑的物理神经元相反,它们也被称为人工神经元。类似地,神经网络(NN)也称为人工神经网络(ANN)。
在本章中,我们将进一步扩展以下主题:
- 感知机(人工神经元)
- 前馈神经网络
- 用于图像分类的多层感知机(MLP)
- 基于 TensorFlow 的用于 MNIST 图像分类的 MLP
- 基于 Keras 的用于 MNIST 分类的 MLP
- 基于 TFLearn 的用于 MNIST 分类的 MLP
- 用于时间序列回归的 MLP
感知机
让我们了解神经网络的最基本构建块,感知机,也称为人工神经元。感知机的概念起源于 Frank Rosenblatt 于 1962 年的作品。
您可能希望阅读以下工作来探索神经网络的起源:
Frank Rosenblatt,神经动力学原理:感知器和脑机制理论,斯巴达书籍,1962 年
在最简化的视图中,感知机被建模在生物神经元之后,使得它接收一个或多个输入并将它们组合以产生输出。
如下图所示,感知机采用三个输入并将它们相加以生成输出y
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xefYKr7w-1681566326315)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/a19eccda-749c-4dab-9020-41120070fd53.png)]
这种感知机太简单了,不具备任何实际用途。因此,通过添加权重,偏差和激活函数的概念来增强它。将权重添加到每个输入以获得加权和。如果加权和Σw[i]x[i]
小于阈值,则输出为 0,否则输出为 1:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tDa46bxZ-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/ad008099-c40e-4e5f-bc65-721e82255fa8.png)]
阈值称为偏差。让我们将偏差移到等式的左边,用b
表示它,Σw·x
代表w
和x
的向量点积。感知机的等式现在变为如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NEzmPXAJ-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/144a0cb4-f3e8-440c-9778-28e0f4c8b603.png)]
感知机现在看起来像下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YvbzKvAB-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/6c2085db-a65d-495c-96b9-4524ba54eacf.png)] Simple perceptron with weights and bias
到目前为止,神经元是一个线性函数。为了使这个神经元产生非线性决策边界,通过称为激活或传递函数的非线性函数运行求和输出。有许多流行的激活函数可用:
ReLU
:整流线性单元,将值平滑到范围(0, x)
,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ICvcbHeW-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/7538f31f-444e-4922-9d11-7ae37e375e4f.png)]sigmoid
:Sigmoid 将值平滑到(0, 1)
,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IOdw2Kfj-1681566326316)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/5433180b-4099-4c59-ad7d-9ca67d6deff1.png)]tanh
:双曲正切将值平滑到(-1, 1)
,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NEXNPiPG-1681566326317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/bf847fab-b08c-41e5-af41-19d2bb877240.png)]
使用激活函数,感知机的等式变为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNDvguh4-1681566326317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/d16676a1-31ee-43ba-9f94-25cc90573568.png)]
其中φ(·)
是激活函数。
神经元看起来像下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IoPijA2s-1681566326317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/4ec4a553-192d-42a2-bf66-e6790103a7c6.png)]
多层感知机
当我们将人工神经元连接在一起时,基于明确定义的结构,我们将其称为神经网络。这是一个神经元最简单的神经网络:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DoeDU9ZZ-1681566326317)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/ba2849d1-c6bf-42c2-a9d3-d50f9d49de08.png)]Neural network with one neuron
我们连接神经元,使得一层的输出成为下一层的输入,直到最后一层的输出成为最终输出。这种神经网络被称为前馈神经网络(FFNN)。由于这些 FFNN 由连接在一起的神经元层组成,因此它们被称为多层感知机(MLP)或深度神经网络(DNN)。
作为示例,下图中描绘的 MLP 具有三个特征作为输入:两个隐藏层,每个神经元包含五个神经元,一个输出 y。神经元完全连接到下一层的神经元。这些层也称为致密层或仿射层,并且这种模型也称为顺序模型。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GGzRhi1L-1681566326318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/2f715ec1-4960-4c19-b0c0-150dadcdadd0.png)]
让我们重温一下我们之前探索过的一些示例数据集,并在 TensorFlow 中构建简单的神经网络(MLP 或 DNN)。
您可以按照 Jupyter 笔记本ch-05_MLP
中的代码进行操作。
用于图像分类的 MLP
让我们使用不同的库(例如 TensorFlow,Keras 和 TFLearn)构建用于图像分类的 MLP 网络。 我们将在本节中使用示例的 MNIST 数据集。
MNIST 数据集包含从 0 到 9 的手写数字的28x28
像素图像,以及它们的标签,训练集为 60K,测试集为 10K。 MNIST 数据集是使用最广泛的数据集,包括 TensorFlow 示例和教程。
让我们从纯 TensorFlow 方法开始。
TensorFlow 中的用于 MNIST 分类的 MLP
首先,加载 MNIST 数据集,并使用以下代码定义训练和测试特征以及目标:
from tensorflow.examples.tutorials.mnist import input_data mnist_home = os.path.join(datasetslib.datasets_root, 'mnist') mnist = input_data.read_data_sets(mnist_home, one_hot=True) X_train = mnist.train.images X_test = mnist.test.images Y_train = mnist.train.labels Y_test = mnist.test.labels num_outputs = 10 # 0-9 digits num_inputs = 784 # total pixels
我们创建了三个辅助函数,它们将帮助我们创建一个只有一个隐藏层的简单 MLP,然后是一个更大的 MLP,每层有多个层和多个神经元。
mlp()
函数使用以下逻辑构建网络层:
mlp()
函数需要五个输入:
x
是输入特征张量num_inputs
是输入特征的数量num_outputs
是输出目标的数量num_layers
是所需隐藏层数num_neurons
是包含每层神经元数量的列表
- 将权重和偏差列表设置为空:
w=[] b=[]
- 为隐藏层的数量运行循环以创建权重和偏移张量并将它们附加到各自的列表:
- 张量分别名为
w_
和b_
。命名张量有助于调试和查找代码问题。 - 使用
tf.random_normal()
以正态分布初始化张量。 - 权重张量的第一个维度是来自前一层的输入数量。对于第一个隐藏层,第一个维度是
num_inputs
。权重张量的第二维是当前层中的神经元的数量。 - 偏差都是一维张量,其中维度等于当前层中的神经元数量。
for i in range(num_layers): # weights w.append(tf.Variable(tf.random_normal( [num_inputs if i == 0 else num_neurons[i - 1], num_neurons[i]]), name="w_{0:04d}".format(i) )) # biases b.append(tf.Variable(tf.random_normal( [num_neurons[i]]), name="b_{0:04d}".format(i) ))
- 为最后一个隐藏层创建权重和偏差。在这种情况下,权重张量的维度等于最后隐藏层中的神经元数量和输出目标的数量。偏差是一个张量,具有输出特征数量大小的单一维度:
w.append(tf.Variable(tf.random_normal( [num_neurons[num_layers - 1] if num_layers > 0 else num_inputs, num_outputs]), name="w_out")) b.append(tf.Variable(tf.random_normal([num_outputs]), name="b_out"))
- 现在开始定义层。首先,将
x
视为第一个最明显的输入层:
# x is input layer layer = x
- 在循环中添加隐藏的层。每个隐藏层表示,通过激活函数
tf.nn.relu()
使线性函数tf.matmul(layer, w[i]) + b[i]
非线性化:
# add hidden layers for i in range(num_layers): layer = tf.nn.relu(tf.matmul(layer, w[i]) + b[i])
- 添加输出层。输出层和隐藏层之间的一个区别是输出层中没有激活函数:
layer = tf.matmul(layer, w[num_layers]) + b[num_layers]
- 返回包含 MLP 网络的
layer
对象:
return layer
整个 MLP 函数的完整代码如下:
def mlp(x, num_inputs, num_outputs, num_layers, num_neurons): w = [] b = [] for i in range(num_layers): # weights w.append(tf.Variable(tf.random_normal( [num_inputs if i == 0 else num_neurons[i - 1], num_neurons[i]]), name="w_{0:04d}".format(i) )) # biases b.append(tf.Variable(tf.random_normal( [num_neurons[i]]), name="b_{0:04d}".format(i) )) w.append(tf.Variable(tf.random_normal( [num_neurons[num_layers - 1] if num_layers > 0 else num_inputs, num_outputs]), name="w_out")) b.append(tf.Variable(tf.random_normal([num_outputs]), name="b_out")) # x is input layer layer = x # add hidden layers for i in range(num_layers): layer = tf.nn.relu(tf.matmul(layer, w[i]) + b[i]) # add output layer layer = tf.matmul(layer, w[num_layers]) + b[num_layers] return layer
辅助函数mnist_batch_func()
为 MNIST 数据集包装 TensorFlow 的批量函数,以提供下一批图像:
def mnist_batch_func(batch_size=100): X_batch, Y_batch = mnist.train.next_batch(batch_size) return [X_batch, Y_batch]
此函数不言自明。 TensorFlow 为 MNIST 数据集提供此函数;但是,对于其他数据集,我们可能必须编写自己的批量函数。
辅助函数tensorflow_classification()
训练并评估模型。
tensorflow_classification()
函数有几个输入:
n_epochs
是要运行的训练循环的数量n_batches
是应该运行每个循环中的训练的随机抽样批次的数量batch_size
是每批中的样本数batch_func
是batch_size
并返回X
和Y
样本批次的函数model
是具有神经元的实际神经网络或层optimizer
是使用 TensorFlow 定义的优化函数loss
是优化器优化参数的成本函数损失accuracy_function
是计算准确率分数的函数X_test
和Y_test
是测试的数据集
- 启动 TensorFlow 会话以运行训练循环:
with tf.Session() as tfs: tf.global_variables_initializer().run()
- 运行
n_epoch
循环来训练:
for epoch in range(n_epochs):
- 在每个循环中,取样本集的
n_batches
数量并训练模型,计算每批的损失,计算每个周期的平均损失:
epoch_loss = 0.0 for batch in range(n_batches): X_batch, Y_batch = batch_func(batch_size) feed_dict = {x: X_batch, y: Y_batch} _, batch_loss = tfs.run([optimizer, loss], feed_dict) epoch_loss += batch_loss average_loss = epoch_loss / n_batches print("epoch: {0:04d} loss = {1:0.6f}".format( epoch, average_loss))
- 完成所有周期循环后,计算并打印用
accuracy_function
计算的精度分数:
feed_dict = {x: X_test, y: Y_test} accuracy_score = tfs.run(accuracy_function, feed_dict=feed_dict) print("accuracy={0:.8f}".format(accuracy_score))
tensorflow_classification()
函数的完整代码如下:
def tensorflow_classification(n_epochs, n_batches, batch_size, batch_func, model, optimizer, loss, accuracy_function, X_test, Y_test): with tf.Session() as tfs: tfs.run(tf.global_variables_initializer()) for epoch in range(n_epochs): epoch_loss = 0.0 for batch in range(n_batches): X_batch, Y_batch = batch_func(batch_size) feed_dict = {x: X_batch, y: Y_batch} _, batch_loss = tfs.run([optimizer, loss], feed_dict) epoch_loss += batch_loss average_loss = epoch_loss / n_batches print("epoch: {0:04d} loss = {1:0.6f}".format( epoch, average_loss)) feed_dict = {x: X_test, y: Y_test} accuracy_score = tfs.run(accuracy_function, feed_dict=feed_dict) print("accuracy={0:.8f}".format(accuracy_score))
现在让我们定义输入和输出占位符,x
和y
以及其他超参数:
# input images x = tf.placeholder(dtype=tf.float32, name="x", shape=[None, num_inputs]) # target output y = tf.placeholder(dtype=tf.float32, name="y", shape=[None, num_outputs]) num_layers = 0 num_neurons = [] learning_rate = 0.01 n_epochs = 50 batch_size = 100 n_batches = int(mnist.train.num_examples/batch_size)
参数如下所述:
num_layers
是隐藏层数。我们首先练习没有隐藏层,只有输入和输出层。num_neurons
是空列表,因为没有隐藏层。learning_rate
是 0.01,随机选择的小数。num_epochs
代表 50 次迭代,以学习将输入连接到输出的唯一神经元的参数。batch_size
保持在 100,这也是一个选择问题。较大的批量大小不一定提供更高的好处。您可能需要探索不同的批量大小,以找到神经网络的最佳批量大小。n_batches
:批次数大致计算为示例数除以批次中的样本数。
现在让我们将所有内容放在一起,使用到目前为止定义的变量定义网络,loss
函数,optimizer
函数和accuracy
函数。
model = mlp(x=x, num_inputs=num_inputs, num_outputs=num_outputs, num_layers=num_layers, num_neurons=num_neurons) loss = tf.reduce_mean( tf.nn.softmax_cross_entropy_with_logits(logits=model, labels=y)) optimizer = tf.train.GradientDescentOptimizer( learning_rate=learning_rate).minimize(loss) predictions_check = tf.equal(tf.argmax(model, 1), tf.argmax(y, 1)) accuracy_function = tf.reduce_mean(tf.cast(predictions_check, tf.float32))
在这段代码中,我们使用一个新的 tensorflow 函数来定义损失函数:
tf.nn.softmax_cross_entropy_with_logits(logits=model, labels=y)
当使用softmax_cross_entropy_with_logits()
函数时,请确保输出未缩放且尚未通过softmax
激活函数。 此函数在内部使用softmax
来缩放输出。
该函数计算模型之间的 softmax 熵(估计值y
)和y
的实际值。当输出属于一个类而不是一个类时,使用熵函数。在我们的示例中,图像只能属于其中一个数字。
有关此熵函数的更多信息,请参阅此链接。
一旦定义了所有内容,运行tensorflow_classification
函数来训练和评估模型:
tensorflow_classification(n_epochs=n_epochs, n_batches=n_batches, batch_size=batch_size, batch_func=mnist_batch_func, model = model, optimizer = optimizer, loss = loss, accuracy_function = accuracy_function, X_test = mnist.test.images, Y_test = mnist.test.labels )
我们从运行分类得到以下输出:
epoch: 0000 loss = 8.364567 epoch: 0001 loss = 4.347608 epoch: 0002 loss = 3.085622 epoch: 0003 loss = 2.468341 epoch: 0004 loss = 2.099220 epoch: 0005 loss = 1.853206 --- Epoch 06 to 45 output removed for brevity --- epoch: 0046 loss = 0.684285 epoch: 0047 loss = 0.678972 epoch: 0048 loss = 0.673685 epoch: 0049 loss = 0.668717 accuracy=0.85720009
我们看到单个神经元网络在 50 次迭代中缓慢地将损失从 8.3 降低到 0.66,最终得到几乎 85% 的准确率。对于这个具体的例子,这是非常糟糕的准确率,因为这只是使用 TensorFlow 进行分类使用 MLP 的演示。
我们使用更多层和神经元运行相同的代码,并获得以下准确率:
层数 | 每个隐藏层中的神经元数量 | 准确率 |
0 | 0 | 0.857 |
1 | 8 | 0.616 |
2 | 256 | 0.936 |
因此,通过在每层添加两行和 256 个神经元,我们将精度提高到 0.936。我们鼓励您尝试使用不同变量值的代码来观察它如何影响损失和准确率。
Keras 中的用于 MNIST 分类的 MLP
现在让我们与 Keras 建立相同的 MLP 网络,Keras 是 TensorFlow 的高级库。我们保留所有参数与本章中用于 TensorFlow 示例的参数相同,例如,隐藏层的激活函数保留为 ReLU 函数。
- 从 Keras 导入所需的模块:
import keras from keras.models import Sequential from keras.layers import Dense from keras.optimizers import SGD
- 定义超参数(我们假设数据集已经加载到
X_train
,Y_train
,X_test
和Y_test
变量):
num_layers = 2 num_neurons = [] for i in range(num_layers): num_neurons.append(256) learning_rate = 0.01 n_epochs = 50 batch_size = 100
- 创建顺序模型:
model = Sequential()
- 添加第一个隐藏层。只有在第一个隐藏层中,我们必须指定输入张量的形状:
model.add(Dense(units=num_neurons[0], activation='relu', input_shape=(num_inputs,)))
- 添加第二层:
model.add(Dense(units=num_neurons[1], activation='relu'))
- 使用 softmax 激活函数添加输出层:
model.add(Dense(units=num_outputs, activation='softmax'))
- 打印模型详细信息:
model.summary()
我们得到以下输出:
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_1 (Dense) (None, 256) 200960 _________________________________________________________________ dense_2 (Dense) (None, 256) 65792 _________________________________________________________________ dense_3 (Dense) (None, 10) 2570 ================================================================= Total params: 269,322 Trainable params: 269,322 Non-trainable params: 0 _________________________________________________________________
- 使用 SGD 优化器编译模型:
model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=learning_rate), metrics=['accuracy'])
- 训练模型:
model.fit(X_train, Y_train, batch_size=batch_size, epochs=n_epochs)
在训练模型时,我们可以观察每次训练迭代的损失和准确率:
Epoch 1/50 55000/55000 [========================] - 4s - loss: 1.1055 - acc: 0.7413 Epoch 2/50 55000/55000 [========================] - 3s - loss: 0.4396 - acc: 0.8833 Epoch 3/50 55000/55000 [========================] - 3s - loss: 0.3523 - acc: 0.9010 Epoch 4/50 55000/55000 [========================] - 3s - loss: 0.3129 - acc: 0.9112 Epoch 5/50 55000/55000 [========================] - 3s - loss: 0.2871 - acc: 0.9181 --- Epoch 6 to 45 output removed for brevity --- Epoch 46/50 55000/55000 [========================] - 4s - loss: 0.0689 - acc: 0.9814 Epoch 47/50 55000/55000 [========================] - 4s - loss: 0.0672 - acc: 0.9819 Epoch 48/50 55000/55000 [========================] - 4s - loss: 0.0658 - acc: 0.9822 Epoch 49/50 55000/55000 [========================] - 4s - loss: 0.0643 - acc: 0.9829 Epoch 50/50 55000/55000 [========================] - 4s - loss: 0.0627 - acc: 0.9829
- 评估模型并打印损失和准确率:
score = model.evaluate(X_test, Y_test) print('\n Test loss:', score[0]) print('Test accuracy:', score[1])
我们得到以下输出:
Test loss: 0.089410082236 Test accuracy: 0.9727
笔记本ch-05_MLP
中提供了使用 Keras 进行 MNIST 分类的 MLP 的完整代码。
TFLearn 中的用于 MNIST 分类的 MLP
现在让我们看看如何使用 TFLearn 实现相同的 MLP,TFLearn 是 TensorFlow 的另一个高级库:
- 导入 TFLearn 库:
import tflearn
- 定义超参数(我们假设数据集已经加载到
X_train
,Y_train
,X_test
和Y_test
变量):
num_layers = 2 num_neurons = [] for i in range(num_layers): num_neurons.append(256) learning_rate = 0.01 n_epochs = 50 batch_size = 100
- 构建输入层,两个隐藏层和输出层(与 TensorFlow 和 Keras 部分中的示例相同)
# Build deep neural network input_layer = tflearn.input_data(shape=[None, num_inputs]) dense1 = tflearn.fully_connected(input_layer, num_neurons[0], activation='relu') dense2 = tflearn.fully_connected(dense1, num_neurons[1], activation='relu') softmax = tflearn.fully_connected(dense2, num_outputs, activation='softmax')
- 使用最后一步中构建的 DNN(在变量
softmax
中)定义优化器函数,神经网络和 MLP 模型(在 TFLearn 中称为 DNN):
optimizer = tflearn.SGD(learning_rate=learning_rate) net = tflearn.regression(softmax, optimizer=optimizer, metric=tflearn.metrics.Accuracy(), loss='categorical_crossentropy') model = tflearn.DNN(net)
- 训练模型:
model.fit(X_train, Y_train, n_epoch=n_epochs, batch_size=batch_size, show_metric=True, run_id="dense_model")
训练结束后,我们得到以下输出:
Training Step: 27499 | total loss: 0.11236 | time: 5.853s | SGD | epoch: 050 | loss: 0.11236 - acc: 0.9687 -- iter: 54900/55000 Training Step: 27500 | total loss: 0.11836 | time: 5.863s | SGD | epoch: 050 | loss: 0.11836 - acc: 0.9658 -- iter: 55000/55000 --
- 评估模型并打印准确率分数:
score = model.evaluate(X_test, Y_test) print('Test accuracy:', score[0])
我们得到以下输出:
Test accuracy: 0.9637
与使用 TFLearn 相比,我们获得了相当的精确度。
在笔记本ch-05_MLP
中提供了使用 TFLearn 进行 MNIST 分类的 MLP 的完整代码。
TensorFlow,Keras 和 TFLearn 中的 MLP 总结
在前面的部分中,我们学习了如何使用 TensorFLow 及其高级库构建简单的 MLP 架构。纯 TensorFlow 的准确率约为 0.93-0.94,Keras 的准确率为 0.96-0.98,TFLearn 的准确率为 0.96-0.97。尽管我们的代码的所有示例都使用下面的 TensorFlow,但相同架构和参数的准确率差异可归因于这样的事实:尽管我们初始化了一些重要的超参数,但高级库和 TensorFlow 却抽象了许多其他超级 - 我们没有从默认值修改的参数。
我们观察到,与 Keras 和 TFLearn 相比,TensorFlow 中的代码非常详细和冗长。高级库使我们更容易构建和训练神经网络模型。
用于时间序列回归的 MLP
我们已经看到了图像数据分类的例子;现在让我们看一下时间序列数据的回归。我们将建立并使用 MLP 作为一个较小的单变量时间序列数据集,称为国际航空公司乘客数据集。该数据集包含多年来的乘客总数。该数据集可从此链接获得:
- https://www.kaggle.com/andreazzini/international-airline-passengers/data
- https://datamarket.com/data/set/22u3/international-airline-passengers-monthly-totals-in-thousands-jan-49-dec-60
让我们从准备数据集开始。
- 首先,使用以下代码加载数据集:
filename = os.path.join(datasetslib.datasets_root, 'ts-data', 'international-airline-passengers-cleaned.csv') dataframe = pd.read_csv(filename,usecols=[1],header=0) dataset = dataframe.values dataset = dataset.astype('float32')
- 利用
datasetslib
的效用函数,我们将数据集分成测试和训练集。对于时间序列数据集,我们有一个单独的函数,不会改变观察结果,因为对于时间序列回归,我们需要维持观察的顺序。我们使用 67% 的数据进行训练,33% 的数据用于测试。您可能希望尝试使用不同比例的示例。
train,test=dsu.train_test_split(dataset,train_size=0.67)
- 对于时间序列回归,我们转换数据集以构建监督数据集。在此示例中,我们使用两个时间步长的滞后。我们将
n_x
设置为 2,mvts_to_xy()
函数返回输入和输出(X
和Y
)训练和测试集,使得X
是两列具有时间{t-1, t}
的值,Y
是一列中具有时间{t + 1}
的值。我们的学习算法假设通过找到时间{t-1, t, t + 1}
的值之间的关系,可以学习时间t + 1
的值。
# reshape into X=t-1,t and Y=t+1 n_x=2 n_y=1 X_train, Y_train, X_test, Y_test = tsd.mvts_to_xy(train, test,n_x=n_x,n_y=n_y)
有关将时间序列数据集转换为监督学习问题的更多信息,请访问此链接。
现在我们在我们的训练数据集上构建和训练模型:
- 导入所需的 Keras 模块:
from keras.models import Sequential from keras.layers import Dense from keras.optimizers import SGD
- 设置构建模型所需的超参数:
num_layers = 2 num_neurons = [8,8] n_epochs = 50 batch_size = 2
请注意,我们使用批量大小为 2,因为数据集非常小。我们使用两层 MLP,每层只有八个神经元,因为我们的示例问题的规模很小。
- 构建,编译和训练模型:
model = Sequential() model.add(Dense(num_neurons[0], activation='relu', input_shape=(n_x,))) model.add(Dense(num_neurons[1], activation='relu')) model.add(Dense(units=1)) model.summary() model.compile(loss='mse', optimizer='adam') model.fit(X_train, Y_train, batch_size=batch_size, epochs=n_epochs)
请注意,我们使用 Adam 优化器而不是 SGD。 您可能想要尝试 TensorFlow 和 Keras 中可用的不同优化器。
- 评估模型并打印均方误差(MSE)和均方根误差(RMSE):
score = model.evaluate(X_test, Y_test) print('\nTest mse:', score) print('Test rmse:', math.sqrt(score))
我们得到以下输出:
Test mse: 5619.24934188 Test rmse: 74.96165247566114
- 使用我们的模型预测值并绘制它们,用于测试和训练数据集:
# make predictions Y_train_pred = model.predict(X_train) Y_test_pred = model.predict(X_test) # shift train predictions for plotting Y_train_pred_plot = np.empty_like(dataset) Y_train_pred_plot[:, :] = np.nan Y_train_pred_plot[n_x-1:len(Y_train_pred)+n_x-1, :] = Y_train_pred # shift test predictions for plotting Y_test_pred_plot = np.empty_like(dataset) Y_test_pred_plot[:, :] = np.nan Y_test_pred_plot[len(Y_train_pred)+(n_x*2)-1:len(dataset)-1, :] = \ Y_test_pred # plot baseline and predictions plt.plot(dataset,label='Original Data') plt.plot(Y_train_pred_plot,label='Y_train_pred') plt.plot(Y_test_pred_plot,label='Y_test_pred') plt.legend() plt.show()
我们得到以下关于原始和预测时间序列值的图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O16oIKvo-1681566326318)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/mastering-tf-1x-zh/img/3d26fd19-43da-4196-8f1f-4c19ed3040fe.png)]
如你所见,这是一个非常好的估计。然而,在现实生活中,数据本质上是多变量和复杂的。因此,我们将在后面的章节中看到时间序列数据的循环神经网络架构。
总结
在本章中,我们了解了多层感知机。我们解释了如何为分类和回归问题构建和训练 MLP 模型。我们使用纯 TensorFlow,Keras 和 TFLearn 构建了 MLP 模型。对于分类,我们使用图像数据,对于回归,我们使用时间序列数据。
构建和训练 MLP 网络模型的技术对于任何其他类型的数据(例如数字或文本)是相同的。然而,对于图像数据集,CNN 架构已被证明是最佳架构,对于序列数据集,例如时间序列和文本,RNN 模型已被证明是最佳架构。
虽然我们在本章中仅使用简单的数据集示例来演示 MLP 架构,但在后面的章节中,我们将介绍具有一些大型和高级数据集的 CNN 和 RNN 架构。