6.3神经网络算法(Neural Networks)算法应用(下)

1. 简单非线性关系数据集测试(XOR)

    X:                                 Y

   00                                 0

   01                                 1

   10                                 1

   11                                 0

NeuralNetwork.py:
# coding=utf-8
import numpy as np


def tanh(x):
    return np.tanh(x)


def tanh_deriv(x):
    return 1.0 - np.tanh(x) * np.tanh(x)  # tanh函数的导数


def logistic(x):
    return 1 / (1 + np.exp(-x))  # 逻辑函数


def logistic_derivative(x):
    return logistic(x) * (1 - logistic(x))  # 逻辑函数的导数,用来计算权重的更新


class NeuralNetwork:
    def __init__(self, layers, activation='tanh'):  # 构造函数,self相当于指针
        '''
        :param layers: 列表,包含了每一层的神经元个数
        :param activation:  激活函数的选择
        '''

        if activation == 'logistic':
            self.activation = logistic
            self.activation_deriv = logistic_derivative
        elif activation == 'tanh':
            self.activation = tanh
            self.activation_deriv = tanh_deriv

        self.weights = []
        for i in range(1, len(layers) - 1):  # 从第一层到最后的输出的前一层,都要赋予一个初始权重
            self.weights.append(
                (2 * np.random.random((layers[i - 1] + 1, layers[i] + 1)) - 1) * 0.25)  # 对i层与i-1层之间的权重进行随机的赋值
            self.weights.append(
                (2 * np.random.random((layers[i] + 1, layers[i + 1])) - 1) * 0.25)  # 对i层与i+1层之间的权重进行随机的赋值 -0.25到0.25之间

    def fit(self, X, y, learning_rate=0.2, epochs=10000):
        '''
        :param X:  二维矩阵,每一行对应一个实例,列数代表了特征数
        :param y:  标签
        :param learning_rate:
        :param epochs:   达到预设的循环次数,最多循环10000次
        :return:
        '''
        X = np.atleast_2d(X)  # 确认x的维度最少为2维数组
        temp = np.ones([X.shape[0], X.shape[1] + 1])  # 初始化矩阵全是1(行数,列数+1是为了有偏置b)
        temp[:, 0:-1] = X  # 行全选,第一列到倒数第二列
        X = temp  # 主要是偏置的赋值
        y = np.array(y)  # 转化为数组的形式,数据结构转换
        for k in range(epochs):
            i = np.random.randint(X.shape[0])  # 随机抽取一行
            a = [X[i]]

            for l in range(len(self.weights)):
                a.append(self.activation(np.dot(a[l], self.weights[l])))  # 内积实现加权求和,activation实现非线性转换
                # 向前传播,得到每个节点的输出结果
            error = y[i] - a[-1]
            deltas = [error * self.activation_deriv(a[-1])]  # 输出层的误差

            for l in range(len(a) - 2, 0, -1):
                deltas.append(deltas[-1].dot(self.weights[l].T) * self.activation_deriv(a[l]))  # 隐含层误差
            deltas.reverse()  # 对误差进行顺序颠倒
            for i in range(len(self.weights)):
                layer = np.atleast_2d(a[i])
                delta = np.atleast_2d(deltas[i])
                self.weights[i] += learning_rate * layer.T.dot(delta)  # 更新权重 w=w+(l)*E*a ,l为学习率,E为误差,o为输入

    def predict(self, x):
        x = np.array(x)
        temp = np.ones(x.shape[0] + 1)  # 偏置的加入
        temp[0:-1] = x
        a = temp
        for l in range(0, len(self.weights)):
            a = self.activation(np.dot(a, self.weights[l]))  # 预测时不需要保存a中间量的值
        return a
实现异或操作代码:
# coding=utf-8
from NeuralNetwork import NeuralNetwork
import numpy as np

nn = NeuralNetwork([2, 12, 1], 'tanh')
x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([0, 1, 1, 0])
nn.fit(x, y)
for i in [[0, 0], [0, 1], [1, 0], [1, 1]]:
    print(i, nn.predict(i))
结果:

[0, 0] [-0.01971361]
[0, 1] [0.99467795]
[1, 0] [0.99349545]
[1, 1] [-0.09293012]

2.手写数字识别:

每个图片8*8

识别数字:0,1,2,3,4,5,6,7,8,9

HandwrittenDigitsRecognition.py:

# coding=utf-8
import numpy as np
from sklearn.datasets import load_digits
from sklearn.metrics import confusion_matrix, classification_report  # 对结果的衡量
from sklearn.preprocessing import LabelBinarizer  # 转化为10位的0 1二进制数据类型
from NeuralNetwork import NeuralNetwork
from sklearn.model_selection import train_test_split  # 训练集合,测试集的划分
import pylab as pl

# 看一下手写体长啥样
digits = load_digits()  # 下载手写体数字集
print(digits.data.shape)
pl.gray()
pl.matshow(digits.images[0])
pl.show()
X = digits.data  # 特征量
y = digits.target  # 标签
X -= X.min()  # normalize the values to bring them into the range 0-1
X /= X.max()  # 转化到0-1之间

nn = NeuralNetwork([64, 100, 10], 'logistic')  # 输入为8*8的图像,64个特征,输出有10类,0-9  ,隐藏层一层,有100个单元
X_train, X_test, y_train, y_test = train_test_split(X, y)  # 划分
labels_train = LabelBinarizer().fit_transform(y_train)  # 二进制,如5,则变成[0,0,0,0,0,1,0,0,0,0]
labels_test = LabelBinarizer().fit_transform(y_test)
print('start fitting')
nn.fit(X_train, labels_train, epochs=3000)  # 3000次循环
predictions = []
for i in range(X_test.shape[0]):
    o = nn.predict(X_test[i])
    predictions.append(np.argmax(o))  # 选最大的概率
print(confusion_matrix(y_test, predictions))  # 混淆矩阵
print(classification_report(y_test, predictions))  # 查准率:true positive/预测 positive;  召回率: true positive/实际 positive

结果:

(1797, 64)
start fitting
[[43  0  0  0  1  0  0  0  0  0]
 [ 0 39  1  0  1  0  1  0  6  2]
 [ 0  0 39  0  0  0  0  0  0  0]
 [ 0  0  2 51  0  2  0  0  1  1]
 [ 0  2  0  0 34  0  0  2  0  0]
 [ 0  0  0  0  0 43  0  0  0  0]
 [ 1  2  0  0  0  0 42  0  0  0]
 [ 0  0  0  0  0  0  0 44  0  1]
 [ 0  1  2  0  0  1  0  0 42  1]
 [ 0  1  0  1  0  0  0  0  0 40]]
             precision    recall  f1-score   support

          0       0.98      0.98      0.98        44
          1       0.87      0.78      0.82        50
          2       0.89      1.00      0.94        39
          3       0.98      0.89      0.94        57
          4       0.94      0.89      0.92        38
          5       0.93      1.00      0.97        43
          6       0.98      0.93      0.95        45
          7       0.96      0.98      0.97        45
          8       0.86      0.89      0.88        47
          9       0.89      0.95      0.92        42

avg / total       0.93      0.93      0.93       450

附:VisualizeDigits.py:

from sklearn.datasets import load_digits

digits = load_digits()  # 下载手写体数字集
print (digits.data.shape)

import pylab as pl
pl.gray()
pl.matshow(digits.images[0])
pl.show()

猜你喜欢

转载自blog.csdn.net/weixin_41790863/article/details/81079233