现在基本的概念已经介绍得差不多了,是时候实战演示一下如何利用神经网络来处理分类问题的。按照一直的做法,自己出题自己解决。这次拿一个现实生活中的一个小问题来练练手:根据人的身高,体重,把人划分成轻,正常,偏胖,肥胖这四种情况。按照现在流行的观点认为,人正常的BMI指数范围在20-25之间,低于20就是过轻,高于25低于28是偏胖,高于28就是肥胖了。

按照前面介绍的方法,解决问题的第一步是建模和打标签。根据问题的描述,可以把训练样本定义成一个2维向量,其中第1维表示身高(以米为计算单位),第2维是体重(以千克为单位)。训练样本有了之后就是打标。有点编程经验的人一眼就可以看出来这里可以用机器打标。标签数据是一个4维布尔值向量,第1维表示过轻,第2维表示正常,第3维表示偏胖,第4维表示肥胖。

第二步是建立模型,对于分类问题而言,最好的是先根据问题的规模来确定结点的数量,从上面的问题描述中大概可以猜出至少需要3个结点,才能划分出四个分类。因此不妨就将隐层结点数定义成3或4。这里建议大家训练模型的时候,根据先简单后复杂的原则来调整网络。因为一开始就训练很复杂的网络,不仅不一定得到很好的结果,而且训练的时间太长,也不利于检验模型的质量。

第三步就是训练模型,不停改进模型,直至得到较满意的精度。

下面给出训练代码:
import tensorflow as tf
import numpy as np
 
#设置训练集大小
train_set_size=1000
#随机生成身高数据,以男性1.7m为平均身高,上下浮动0.2m
height=tf.Variable(tf.random.truncated_normal([train_set_size,1],mean=1.7,dtype=tf.double,stddev=0.1))
#随机生成体重数据,以体重60kg为平均值,上下浮动20kg
weight=tf.Variable(tf.random.truncated_normal([train_set_size,1],mean=60,dtype=tf.double,stddev=20))
#归并数据
x=tf.concat([height,weight],1)
 
# 计算BMI指数
def getBMI(x):
return x[1] / (x[0] ** 2)
 
# 根据BMI指数自动生成标签
def getLable(x):
label = np.zeros(shape=[train_set_size,4],dtype=float)
for i in range(len(x)):
bmi = getBMI(x[i])
if bmi < 20:
label[i][0] = 1
elif bmi >= 20 and bmi < 25:
label[i][1] = 1
elif bmi >= 25 and bmi < 28:
label[i][2] = 1
else:
label[i][3] = 1
 
return label
 
# 将标签数据转换成tensorflow框架能处理的张量
y_=tf.convert_to_tensor(getLable(x))
 
#  设计两层神经网络,第一层隐含层共4个结点,激活函数为RELU;第二层为输出层也包含4个结点,对应4个分类,激活函数为softmax
model = tf.keras.models.Sequential([
  tf.keras.layers.Dense(4, activation='relu',input_shape=[2]),
  tf.keras.layers.Dense(4,activation='softmax')
])
 
#  定义优化器,用于优化学习率等超参数指标
optimizer = tf.keras.optimizers.Adadelta(lr=1.0, rho=0.95, epsilon=1e-06)
 
#  编译模型,loss='categorical_crossentropy'指定损失函数为交叉熵,Metrics标注网络评价指标accuracy为准确率
model.compile(loss='categorical_crossentropy',
                optimizer=optimizer,
                metrics=['accuracy'])
 
#  打印网络参数模型,仅用于自检
model.summary()
 
#  重复训练3000次
for i in range(3000):
#  输入样本x和标签y, batch_size=1,每输入1条数据,就运行反向传播算法,更新网络参数。
model.fit(x=x,y=y_,batch_size=1)
 
#  准备测试集
test_size=3
h_t=tf.Variable(tf.random.truncated_normal([test_size,1],mean=1.7,dtype=tf.double,stddev=0.1))
w_t=tf.Variable(tf.random.truncated_normal([test_size,1],mean=60,dtype=tf.double,stddev=20))
x_t=tf.concat([h_t,w_t],1)
 
#  打印测试集内容和模型预测的结果
print(x_t)
print(model.predict(x_t))
 
下面是训练结果:
1000/1000 [==============================] - 0s 455us/step - loss: 0.1065 - accuracy: 0.9580
1000/1000 [==============================] - 0s 449us/step - loss: 0.0986 - accuracy: 0.9550
1000/1000 [==============================] - 0s 447us/step - loss: 0.1108 - accuracy: 0.9560
1000/1000 [==============================] - 0s 449us/step - loss: 0.1104 - accuracy: 0.9570
1000/1000 [==============================] - 0s 452us/step - loss: 0.0977 - accuracy: 0.9570
tf.Tensor(
[[ 1.87404843 51.79656559]
 [ 1.69247713 54.36136267]
 [ 1.80369327 53.8165295 ]], shape=(3, 2), dtype=float64)
[[1.0000000e+00 7.5280788e-35 0.0000000e+00 0.0000000e+00]
 [9.9999952e-01 5.1134185e-07 7.3078410e-31 0.0000000e+00]
 [1.0000000e+00 3.5876334e-22 0.0000000e+00 0.0000000e+00]]

连续训练3000次以上,准确率稳定在95%以上,证明算法是有效可靠的。而且从预测方面的能力看,效果还是挺不错的。从结果来看,一切都挺有趣的。但这个模型没有什么实际意义。正如前文所言,如果可以用普通的逻辑判断语句就可以实现分类,那根本就没有神经网络什么事。神经网络的分类能力主要还是用于数据挖掘上面,在海量数据中挖掘出人们还没或者不可能发现潜在的联系。