用于分类的神经网络写法(基于iris数据集)

用于分类的神经网络写法(基于iris数据集)

  • 前言
  • 数据展示以及准备
  • 经典算法
  • 第一种神经网络写法
  • 第二种神经网络写法
  • 第三种神经网络写法
  • 结论

前言

本文本适合于学习神经网络的小白,高手或大神请绕行。
iris(鸢尾花分类)数据集是一个机器学习中的经典数据集,类别分为Setosa,Versicolour,Virginica三种;输入的特征有四个(即四维数据),分别为花萼长度,花萼宽度,花瓣长度,花瓣宽度。
从我们的通识来说,知道同一类的种类会有相近的花形状,不同一类的种类的花会有差别。
因此,可以通过上述四个特征来进行区分。
本博客程序代码iris_data_training.ipynb

数据展示以及准备

环境:python3.7+keras2.3.1+tensorflow1.15.0+sklearn0.22.1+matplotlib3.1.1
三方库:mglearn0.1.7
为什么使用mglearn呢?因为它已经封装好了matplotlib.pyplot的scatter方法,只输入X, y就好了,学习时真的没有必要重复造轮子。

  1. 首先导入通用库
from sklearn.datasets import load_iris
import numpy as np
import matplotlib.pyplot as plt
import mglearn
  1. 加载数据
# get data
iris = load_iris()
X, y = iris.data, iris.target
print('Shape', X.shape, y.shape)	# 输出结果Shape (150, 4) (150,)
RANDOM_STATE = 2	# 为了使用相同的数据好比对,选择相同的随机种子
  1. 由于数据输入有四个维度,而使用简单的展示数据分布要用二维,所以两两地组合展示出来。总共有6种搭配。
# 选择第0维第1维
mglearn.discrete_scatter(X[:, 0], X[:, 1], y)

用于分类的神经网络写法(基于iris数据集)_第1张图片

# 选择第0维第2维
mglearn.discrete_scatter(X[:, 0], X[:, 2], y)

用于分类的神经网络写法(基于iris数据集)_第2张图片

# 选择第0维第3维
mglearn.discrete_scatter(X[:, 0], X[:, 3], y)

用于分类的神经网络写法(基于iris数据集)_第3张图片

# 选择第1维第2维
mglearn.discrete_scatter(X[:, 1], X[:, 2], y)

用于分类的神经网络写法(基于iris数据集)_第4张图片

# 选择第1维第3维
mglearn.discrete_scatter(X[:, 1], X[:, 3], y)

用于分类的神经网络写法(基于iris数据集)_第5张图片

# 选择第2维第3维
mglearn.discrete_scatter(X[:, 2], X[:, 3], y)

用于分类的神经网络写法(基于iris数据集)_第6张图片
所有的组合看完,发现第2维和第3维画出来比较容易看出来分类情况,所以第2维和第3维的二维数据展示仅仅查看看预测的好坏程度。
在这里,我们写一个展示真实结果与预测结果的比对的方法。

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
def eval_on_show(X_train, y_train, y_train_pred, X_test, y_test, y_test_pred):
    f = plt.figure('train set', figsize=(10, 5))
    plt.subplot(121)
    plt.title('train set ture')
    mglearn.discrete_scatter(X_train[:, 2], X_train[:, 3], y_train)
    plt.subplot(122)
    plt.title('train set predict')
    mglearn.discrete_scatter(X_train[:, 2], X_train[:, 3], y_train_pred)

    f = plt.figure('test set', figsize=(10, 5))
    plt.subplot(121)
    plt.title('test set ture')
    mglearn.discrete_scatter(X_test[:, 2], X_test[:, 3], y_test)
    plt.subplot(122)
    plt.title('test set predict')
    mglearn.discrete_scatter(X_test[:, 2], X_test[:, 3], y_test_pred)

经典算法

学习机器学习的小伙伴一定知道,使用KNN分类iris数据集几乎是入门的标配。所以我们先看看KNN的结果。KNN(K-NearestNeighbor)的大体思路是一个数据,如果它旁边有K个和它很近距离的数据,那么它就是属于这个类别。具体公式和原理这里就不详细展开了,毕竟不是给大佬们看的。

# import common
from sklearn.neighbors import KNeighborsClassifier
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=RANDOM_STATE)
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
y_train_pred = knn.predict(X_train)
y_test_pred = knn.predict(X_test)
print('train score:', accuracy_score(y_train, y_train_pred))
print('test score:', accuracy_score(y_test, y_test_pred))

eval_on_show(X_train, y_train, y_train_pred, X_test, y_test, y_test_pred)

sklearn里使用KNN十分方便,只要用KNeighborsClassifier创建一个对象,fit一下数据,就可以做预测了。
这里的结果是
train score: 0.9583333333333334
test score: 1.0
用于分类的神经网络写法(基于iris数据集)_第7张图片
毕竟数据量小,结果感觉比较准。

第一种神经网络写法

sklearn的使用方便让人无法抗拒,只是创建一下,fit一下,就可以预测了(当然有要调超参的,以后再写GridSearchCV)。
而sklearn里有神经网络的模型,可以直接调用。

# import common
from sklearn.neural_network import MLPClassifier

MLPClassifier是多层感知机,即我们所说的神经网络,不过它只都是全连接层。
用于分类的神经网络写法(基于iris数据集)_第8张图片
实现方法,同样是创建,fit,预测即可。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=RANDOM_STATE)
mlp = MLPClassifier(hidden_layer_sizes=(10, 10), max_iter=10000)
mlp.fit(X_train, y_train)
y_train_pred = mlp.predict(X_train)
y_test_pred = mlp.predict(X_test)
print('train score:', accuracy_score(y_train, y_train_pred))
print('test score:', accuracy_score(y_test, y_test_pred))

eval_on_show(X_train, y_train, y_train_pred, X_test, y_test, y_test_pred)

这里的结果:
train score: 0.975
test score: 1.0
用于分类的神经网络写法(基于iris数据集)_第9张图片
这个效果也还是不错,使用也简单。

第二种神经网络写法

刚才第一种神经网络写法还是比较简单,这次可以自主搭建一下神经网络——使用Keras。
Keras是将下层深度神经网络封装成高级应用API,然后使用最简单的办法去调用,减少编程的难度。

# import common
import keras
from keras.layers import Dense, Activation
from keras.losses import categorical_crossentropy
from keras.models import Sequential
from keras.optimizers import Adam
from keras.utils import to_categorical

首先,我们要将输出转换成OneHot的形式。然后使用其中一种方式搭配网络:(输入层4维,网络层1有10个单元,经过一个激活函数,网络层2有10个单元,再经过一个激活函数,然后就是输出层3维,最后使用softmax激活函数)。
注:最后的softmax即把每一种类别的算成概率输出。
神经网络的训练方法:
网络模型->优化方法->损失函数->数据喂养->预测结果

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=RANDOM_STATE)
y_train_c = to_categorical(y_train)
y_test_c = to_categorical(y_test)

model = Sequential()
model.add(Dense(10, input_shape=(X_train.shape[1], )))
model.add(Activation('relu'))
model.add(Dense(10))
model.add(Activation('relu'))
model.add(Dense(y_train_c.shape[1]))
model.add(Activation('softmax'))
model.compile(Adam(), categorical_crossentropy, ['accuracy'])

model.fit(X_train, y_train_c, batch_size=200, epochs=5000, verbose=0)
y_train_pred = model.predict_classes(X_train)
y_test_pred = model.predict_classes(X_test)
print('train score:', accuracy_score(y_train, y_train_pred))
print('test score:', accuracy_score(y_test, y_test_pred))

eval_on_show(X_train, y_train, y_train_pred, X_test, y_test, y_test_pred)

最终结果:
train score: 0.9833333333333333
test score: 1.0
用于分类的神经网络写法(基于iris数据集)_第10张图片
这里的Keras搭建网络多种方式,请参考以前写的Keras添加网络层的N种方法。

第三种神经网络写法

这一种方法是目前最复杂的(当然,你可以的话可以去写深度学习的框架,再用你的框架来搭建神经网络),使用tensorflow搭建神经网络。
这里的神经网络的训练方法:
输入输出占位符->网络模型(前向传播的方法)->损失函数->优化方法优化损失值->数据喂养->预测结果

# import common
import tensorflow as tf
from keras.utils import to_categorical
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=RANDOM_STATE)
y_train_c = to_categorical(y_train)
y_test_c = to_categorical(y_test)

INPUT_NODE = 4
OUTPUT_NODE = 3
LAYER1_NODE = 10 # 20 wrose
LAYER2_NODE = 10 # 20 wrose
tf.reset_default_graph()
def front_inference(input_tensor):
    weights1 = tf.get_variable('weights1', shape=[INPUT_NODE, LAYER1_NODE], initializer=tf.truncated_normal_initializer(stddev=0.1))
    biases1 = tf.get_variable('biases1', [LAYER1_NODE], initializer=tf.constant_initializer(0.0))
    layer1 = tf.nn.relu(tf.matmul(input_tensor, weights1) + biases1)
    weights2 = tf.get_variable('weights2', shape=[LAYER1_NODE, LAYER2_NODE], initializer=tf.truncated_normal_initializer(stddev=0.1))
    biases2 = tf.get_variable('biases2', [LAYER2_NODE], initializer=tf.constant_initializer(0.0))
    layer2 = tf.nn.relu(tf.matmul(layer1, weights2) + biases2)
    weights3 = tf.get_variable('weights3', shape=[LAYER2_NODE, OUTPUT_NODE], initializer=tf.truncated_normal_initializer(stddev=0.1))
    biases3 = tf.get_variable('biases3', [OUTPUT_NODE], initializer=tf.constant_initializer(0.0))
    layeroutput = tf.nn.softmax(tf.matmul(layer2, weights3) + biases3)
    return layeroutput

TRAINING_TIMES = 5000
BATCH_SIZE = 100
LEARNING_RATE = 0.01
def train():
    global y_train_pred, y_test_pred
    X_input = tf.placeholder(tf.float32, shape=[None, INPUT_NODE], name='X_input')
    Y_output = tf.placeholder(tf.float32, shape=[None, OUTPUT_NODE], name='Y_output')
    y_output_pred = front_inference(X_input)
    print(Y_output.shape, y_output_pred.shape)
    
    entroy_cross = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.argmax(Y_output, 1), logits=y_output_pred)
    loss = tf.reduce_mean(entroy_cross)
    
    train_op = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(loss)
    
    
    with tf.Session() as sess:
        tf.global_variables_initializer().run()
        for i in range(TRAINING_TIMES):
            _, loss_train = sess.run([train_op, loss], feed_dict={X_input: X_train, Y_output: y_train_c})
            if i % 500 == 0:
                print('After {} train loss is {}'.format(i, loss_train))
                prob = sess.run(y_output_pred, feed_dict={X_input: X_test})
                pred_class = sess.run(tf.argmax(prob, 1))
                print('Accuracy', accuracy_score(pred_class, y_test))
#                 print(pred_class.reshape(-1, 1))
#                 correct_prediction = tf.equal(tf.argmax(prob, 1), tf.argmax(y_test_c))
#                 print(correct_prediction)
        # end calculate
        y_train_pred = sess.run(y_output_pred, feed_dict={X_input: X_train})
        y_train_pred = sess.run(tf.argmax(y_train_pred, 1))
        y_test_pred = sess.run(y_output_pred, feed_dict={X_input: X_test})
        y_test_pred = sess.run(tf.argmax(y_test_pred, 1))

y_train_pred = None
y_test_pred = None
train()

print('train score:', accuracy_score(y_train, y_train_pred))
print('test score:', accuracy_score(y_test, y_test_pred))

eval_on_show(X_train, y_train, y_train_pred, X_test, y_test, y_test_pred)

在这里提一下,使用tf.reset_default_graph()的原因,如果是使用文件每次直接运行,不存在问题。如果在jupyter notebook里运行,在第二次后会报错,提醒你tensor的变量不可用因为已经定义使用过了。出现这个问题需要你restart jupyter notebook,所以重置计算图就不需要restart jupyter notebook了。
结果如下:
(?, 3) (?, 3)
After 0 train loss is 1.0976234674453735
Accuracy 0.26666666666666666
After 500 train loss is 1.0871821641921997
Accuracy 0.26666666666666666
After 1000 train loss is 1.048463225364685
Accuracy 0.26666666666666666
After 1500 train loss is 0.9719091057777405
Accuracy 0.7333333333333333
After 2000 train loss is 0.867594301700592
Accuracy 0.7333333333333333
After 2500 train loss is 0.7675849199295044
Accuracy 0.9333333333333333
After 3000 train loss is 0.6780787706375122
Accuracy 1.0
After 3500 train loss is 0.630896270275116
Accuracy 1.0
After 4000 train loss is 0.6117016673088074
Accuracy 1.0
After 4500 train loss is 0.6022022366523743
Accuracy 1.0
train score: 0.975
test score: 1.0
用于分类的神经网络写法(基于iris数据集)_第11张图片
也是可以得到相同的结果。

结论

本文使用三个不同的方法使用神经网络,那么对于简单的问题,当然可以使用简单的方法,但遇到复杂的问题,还是老实地使用Keras或tensorflow吧。
最后给出各种神经网络的对比。

模型 训练集accuracy 测试集accuracy
KNeighborsClassifier 0.958 1.000
MLPClassifier 0.975 1.000
Keras 0.983 1.000
tensorflow 0.975 1.000

你可能感兴趣的:(深度学习,神经网络,机器学习,机器学习,深度学习,神经网络)