机器学习:神经网络的建立 python(异或操作与手写体识别)

依旧根据麦子学院彭亮老师的机器学习课程,并加上自己的理解进行代码巩固。

一.  NN.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 NN 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))

三 .   运行结果:

      /home/troy/anaconda2/bin/python /home/troy/2.py
([0, 0], array([ 0.01477642]))
([0, 1], array([ 0.99760303]))
([1, 0], array([ 0.99760177]))
([1, 1], array([ 0.04567761]))

Process finished with exit code 0

四. 手写体识别:

#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 NN 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
[[39  0  0  0  0  0  0  0  1  0]
 [ 0 31  0  1  0  0  0  0  9  6]
 [ 0  0 47  0  0  0  0  0  0  0]
 [ 0  0  0 39  0  1  0  1  0  0]
 [ 0  0  0  0 46  0  0  2  0  1]
 [ 0  0  0  1  0 49  0  0  0  2]
 [ 0  1  0  0  0  0 47  0  0  0]
 [ 0  0  0  0  0  2  0 42  0  1]
 [ 0  0  0  0  0  0  0  0 39  0]
 [ 0  0  0  1  0  0  0  1  0 40]]
             precision    recall  f1-score   support

          0       1.00      0.97      0.99        40
          1       0.97      0.66      0.78        47
          2       1.00      1.00      1.00        47
          3       0.93      0.95      0.94        41
          4       1.00      0.94      0.97        49
          5       0.94      0.94      0.94        52
          6       1.00      0.98      0.99        48
          7       0.91      0.93      0.92        45
          8       0.80      1.00      0.89        39
          9       0.80      0.95      0.87        42

avg / total       0.94      0.93      0.93       450


Process finished with exit code 0

(注意:1797为实例个数,即1797张8*8图片)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值