【机器学习】DNN(三层多元分类模型)—— python3 实现方案

根据西瓜书《神经网络》章节反向传播的推导过程写成。

书上推导了单样本的反向传播,本例实现了批量梯度下降,设置batch_size=1,就是单样本随机梯度下降。

有别于其他分类算法的标签集,神经网络要对标签进行独热编码,在制作测试数据时要注意这点。

本例使用sklearn生成的3000个3类别的训练数据,多次调试后,能达到90%的正确率。

import numpy as np
from sklearn import datasets
from sklearn import preprocessing


class NeutalNetwork:
    def __init__(self, q=10, learning_rate=0.1, iters=10000, batch_size=10):
        self.q = q  # 隐藏层神经元个数
        self.learning_rate = learning_rate  # 学习率
        self.iters = iters  # 迭代次数
        self.batch_size = batch_size  # 小批量包含的样本数,即每次迭代的样本数
        self.para = []  # 存储参数组合
        self.cost = []  # 储存损失值

    @staticmethod
    def sigmoid(x):
        """激活函数sigmoid"""
        return 1 / (1 + np.exp(-x))

    def rand_parameter(self, features, target):
        """
        初始化参数,输入层到隐藏层的权值v,隐藏层的阀值gamma,隐藏层到输出层的权值w,输出层的阀值theta
        :param features: 已增加 x0=1 列的特征集m*n,m为样本数,n表示特征数(实际特征是n-1)np.matrix
        :param target: 已经过独热处理的标签集m*k,k表示类别数
        :return: 取值在(0,1)的随机参数值
        """
        n, k = features.shape[1], target.shape[1]
        v = np.mat(np.random.rand(n, self.q))  # n*q
        gamma = np.mat(np.random.rand(1, self.q))  # 1*q
        w = np.mat(np.random.rand(self.q, k))  # q * k
        theta = np.mat(np.random.rand(1, k))  # 1 * k
        return v, gamma, w, theta

    @staticmethod
    def cal_g(y_pre, y_true):
        """
        计算theta的一阶导数,并令其等于g,用于计算别的参数的导数
        :param y_pre: 预测结果m*k,m=self.batch_size
        :param y_true: 真实结果m*k
        :return: 参数theta的一阶导数m*k
        """
        return np.multiply(-y_pre, np.multiply(y_pre - y_true, 1 - y_pre))

    @staticmethod
    def cal_e(g, w, b):
        """
        计算gamma的一阶导数,并令其等于e,用于计算别的参数的导数
        :param g: theta的一阶导数m*k,m=self.batch_size
        :param w: 隐藏层到输出层的权值去q*k
        :param b: 隐藏层的输出m*q
        :return: 参数gamma的一阶导数m*q
        """
        return np.multiply(np.multiply(1 - b, b), np.sum(np.dot(g, w.T), axis=1))

    @staticmethod
    def cal_cost(y_pre, y_true):
        """
        计算损失函数值
        :param y_pre: 预测结果m*k
        :param y_true: 真实结果m*k
        :return: 损失值
        """
        return np.sum(np.power(y_pre - y_true, 2)) / 2

    def training(self, features, target):
        """
        使用随机梯度下降法训练神经网络,输出训练好的参数组合
        :param features: 特征集m*n,m为样本数,n为特征数
        :param target: 标签集m*k,k为类别数
        :return: 更新成员变量后,无返回值
        """
        features = np.insert(features, 0, 1, axis=1)  # 插入x0=1列,作为偏差的特征
        features, target = np.mat(features), np.mat(target)  # 矩阵运算更方便. 若用数组运算,会出现二维数组相乘之后变成一维的情况
        m, n, k = features.shape[0], features.shape[1], target.shape[1]
        v, gamma, w, theta = self.rand_parameter(features, target)  # 初始化参数

        for i in range(self.iters):
            rand_batch = np.random.randint(0, m, self.batch_size)  # 从所有样本中随机选择batch_size个样本,作为此次迭代样本
            feature_train, target_train = features[rand_batch, :], target[rand_batch, :]

            alpha = np.dot(feature_train, v)  # 计算隐藏层的输入
            b = self.sigmoid(alpha - gamma)  # 计算隐藏层的输出
            beta = np.dot(b, w)  # 计算输出层的输入
            target_pre = self.sigmoid(beta - theta)  # 计算输出层的输出,即预测为各类别的概率
            error = self.cal_cost(target_pre, target_train) / self.batch_size  # 计算均方误差
            self.cost.append(error)  # 记录误差

            g = self.cal_g(target_pre, target_train)  # 推导过程中的辅助公式
            e = self.cal_e(g, w, b)  # 推导过程中的辅助公式

            # 计算各参数的平均梯度(一阶导数)
            grad_theta = np.sum(g, axis=0) / self.batch_size
            grad_w = -np.dot(b.T, g) / self.batch_size
            grad_gamma = np.sum(e, axis=0) / self.batch_size
            grad_v = -np.dot(feature_train.T, e) / self.batch_size

            # 更新各参数
            theta -= self.learning_rate * grad_theta
            w -= self.learning_rate * grad_w
            gamma -= self.learning_rate * grad_gamma
            v -= self.learning_rate * grad_v
        self.para.extend([v, gamma, w, theta])  # 存储组合变量
        return

    def predict(self, features):
        """
        预测输入样本的类别
        :param features: 待测样本
        :return: 独热编码格式的类别
        """
        features = np.mat(np.insert(features, 0, 1, axis=1))
        v, gamma, w, theta = self.para  # 获取参数
        # 前向传播计算输出
        alpha = np.dot(features, v)
        b = self.sigmoid(alpha - gamma)
        beta = np.dot(b, w)
        target_pre = self.sigmoid(beta - theta)

        target_pre = np.array(target_pre)  # 转换成np.array
        argmax = np.argmax(target_pre, axis=1)  # 获取最大概率值的索引
        # 把最大概率值变成1,其他值变成0
        target_pre[:, :] = 0
        for i in range(features.shape[0]):
            target_pre[i, argmax[i]] = 1
        return target_pre


def test():
    features, target = datasets.make_classification(n_samples=5000, n_informative=5, n_classes=5)  # 3000个具有3个类别的训练样本
    target = target.reshape(features.shape[0], 1)
    enc = preprocessing.OneHotEncoder()
    target = enc.fit_transform(target).toarray()  # 对y进行独热编码

    nn = NeutalNetwork(q=5, learning_rate=0.1, iters=10000, batch_size=10)
    nn.training(features, target)
    prediction = nn.predict(features)
    correct = [1 if (a == b).all() else 0 for a, b in zip(prediction, target)]
    print(correct.count(1) / len(correct))
    print(nn.cost[::500])


test()

 

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的DNN分类模型的Python代码,以及混淆矩阵图的生成: ```python import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.metrics import confusion_matrix from keras.models import Sequential from keras.layers import Dense # 读取数据集 dataset = pd.read_csv('dataset.csv') # 提取特征与标签 X = dataset.iloc[:, :-1].values y = dataset.iloc[:, -1].values # 数据集划分为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0) # 特征缩放 sc = StandardScaler() X_train = sc.fit_transform(X_train) X_test = sc.transform(X_test) # 创建模型 model = Sequential() model.add(Dense(units=6, kernel_initializer='uniform', activation='relu', input_dim=X.shape[1])) model.add(Dense(units=6, kernel_initializer='uniform', activation='relu')) model.add(Dense(units=1, kernel_initializer='uniform', activation='sigmoid')) model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) # 训练模型 model.fit(X_train, y_train, batch_size=32, epochs=100) # 预测测试集结果 y_pred = model.predict(X_test) y_pred = (y_pred > 0.5) # 生成混淆矩阵图 cm = confusion_matrix(y_test, y_pred) plt.imshow(cm, cmap=plt.cm.Blues) plt.xticks([0, 1]) plt.yticks([0, 1]) plt.xlabel('Predicted Label') plt.ylabel('True Label') for i in range(2): for j in range(2): plt.text(j, i, format(cm[i, j]), horizontalalignment='center', verticalalignment='center') plt.show() ``` 在这个代码中,我们使用了Keras库来创建一个简单的DNN分类模型,使用了一个包含两个隐藏层的模型结构。通过训练模型并预测测试集结果,我们可以生成一个混淆矩阵图来展示模型的分类效果。在这个混淆矩阵图中,横轴表示预测结果,纵轴表示真实结果,图中的数字表示每个类别的样本数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值