numpy实现cnn

2023-05-16

经过多天的奋战,终于写出了一个完成的cnn框架,里面最主要的还是卷积反向传播这一块

网络架构

用到的包

数据集:minist

这里是随机抽取了1000份做训练集

100份做测试集

整体流程

 

'''先思考一下,前面的28*28*1的图片那么特征数为784,而对于一张比较小的图片100*100*3(其实100*100*3还是很小的一张图)来说大小特征数为30000那么第一层w就会有30000个
对于这么多参数的优化,时=是非常的浪费时间的,特别是每次迭代时一个batch如果为10即一次只处理10张图片的话,那就更加吃力,那么卷积神经网络
可以很好解决这种情况,看看卷积神经网络的原理--损失函数的定义-参数的优化'''

'''输入层 -- 卷积层 -- 池化层(下采样/压缩) -- 全连接层'''

import numpy as np
import random



def load_data():
    # 训练集
    with open('C:/Users/admin/Desktop/新建文件夹/数据挖掘/机器学习/多层感知机/MINIST_data/train-images.idx3-ubyte') as f:
        loaded = np.fromfile(file=f, dtype=np.uint8)
        train_data = loaded[16:].reshape((60000, 784))
    print(train_data.shape)  # (60000, 784)

    with open('C:/Users/admin/Desktop/新建文件夹/数据挖掘/机器学习/多层感知机/MINIST_data/train-labels.idx1-ubyte') as f:
        loaded = np.fromfile(file=f, dtype=np.uint8)
        train_labels = loaded[8:]
    print(train_labels.shape)  # (60000,)

    # 测试集
    with open('C:/Users/admin/Desktop/新建文件夹/数据挖掘/机器学习/多层感知机/MINIST_data/t10k-images.idx3-ubyte') as f:
        loaded = np.fromfile(file=f, dtype=np.uint8)
        test_data = loaded[16:].reshape((10000, 784))
    print(test_data.shape)  # (10000, 784)

    with open('C:/Users/admin/Desktop/新建文件夹/数据挖掘/机器学习/多层感知机/MINIST_data/t10k-labels.idx1-ubyte') as f:
        loaded = np.fromfile(file=f, dtype=np.uint8)
        test_labels = loaded[8:].reshape((10000))
    print(test_labels.shape)  # (10000,)
    return train_data, train_labels, test_data, test_labels


def max_pooling(array):
    n, m = array.shape
    new_image = np.zeros((int(n / 2), int(m / 2)))
    delta_pooling = np.zeros((n, m))
    for i in range(0, int(n / 2)):
        for j in range(0, int(m / 2)):
            new_image[i][j] = np.max(array[i * 2:i * 2 + 2, j * 2:j * 2 + 2])
            index = np.unravel_index(array[i * 2:i * 2 + 2, j * 2:j * 2 + 2].argmax(),
                                     array[i * 2:i * 2 + 2, j * 2:j * 2 + 2].shape)
            middle = np.zeros((2, 2))
            middle[index[0]][index[1]] = 1
            delta_pooling[i * 2:i * 2 + 2, j * 2:j * 2 + 2] = middle
    return new_image, delta_pooling

def conv_3d(array, kernel, b, stride=1):
    n, h, w = array.shape
    n_1, h_1, w_1 = kernel.shape
    new_image = np.zeros((h - h_1 + 1, w - w_1 + 1))
    delta = np.zeros(kernel.shape)
    for i in range(0, h - h_1 + 1):
        for j in range(0, w - w_1 + 1):
            new_image[i][j] = np.sum(array[:, i:i + h_1, j:j + w_1] * kernel) + b
    return new_image


class Linear(object):
    def __init__(self, input_size, output_size):
        scale = np.sqrt(input_size / 2)

        self.W = np.random.standard_normal((input_size, output_size)) / scale
        self.b = np.random.standard_normal(output_size) / scale

        self.W_grad = np.zeros((input_size, output_size))
        self.b_grad = np.zeros(output_size)

    def forward(self, x):
        self.x = x
        out = np.dot(x, self.W) + self.b
        return out

    def bp(self, delta, lr):
        '''简单的反向传播过程'''
        shape = delta.shape
        self.b_grad = np.sum(delta, axis=0) / shape[0]
        self.W_grad = np.dot(self.x.T, delta) / shape[0]
        new_delta = np.dot(delta, self.W.T)

        self.W -= lr * self.W_grad
        self.b -= lr * self.b_grad

        return new_delta


class Relu(object):
    def forward(self, x):
        self.x = x
        return np.maximum(x, 0)

    def backward(self, delta):
        delta[self.x < 0] = 0
        return delta


class Pooling(object):
    def forward(self, x):
        self.x = x
        shape = self.x.shape
        out = np.zeros((shape[0], shape[1], shape[2] // 2, shape[3] // 2))
        self.delta = np.zeros(shape)
        for i in range(shape[0]):
            for j in range(shape[1]):
                out[i][j], self.delta[i][j] = max_pooling(self.x[i][j])
        return out

    def bp(self, delta):
        shape = self.delta.shape
        for i in range(shape[0]):
            for j in range(shape[1]):
                for n in range(shape[2]):
                    for m in range(shape[3]):
                        if self.delta[i][j][n][m] == 1:
                            self.delta[i][j][n][m] = delta[i][j][n // 2][m // 2]
        return self.delta

    pass


class Softmax(object):
    def forward(self, x, y):
        self.x = x
        shape = self.x.shape
        out = np.exp(self.x - np.max(self.x))
        for i in range(shape[0]):
            sums = np.sum(out[i, :])
            for j in range(shape[1]):
                out[i][j] = out[i][j] / sums
        loss = 0
        delta = np.zeros(shape)
        for i in range(shape[0]):
            delta[i] = out[i] - y[i]
            for j in range(shape[1]):
                loss += - y[i][j] * np.log(out[i][j])
        loss /= shape[0]
        return loss, delta

    pass


class Conv(object):
    def __init__(self, kernel_shape, stride=1):
        n_out, n_in, wk, hk = kernel_shape

        self.stride = stride

        scale = np.sqrt(3 * wk * hk * n_in / n_out)
        self.k = np.random.standard_normal(kernel_shape) / scale
        self.b = np.random.standard_normal(n_out) / scale

        self.k_grad = np.zeros(kernel_shape)
        self.b_grad = np.zeros(n_out)

    def forward(self, x):
        self.x = x
        shape0 = self.x.shape
        shape1 = self.k.shape
        out = np.zeros((shape0[0], shape1[0], shape0[2] - shape1[2] + 1, shape0[3] - shape1[3] + 1))

        for i in range(out.shape[0]):
            for j in range(out.shape[1]):
                out[i][j] = conv_3d(self.x[i], self.k[j], self.b[j])

        return out

    def bp(self, delta, lr):
        shape = delta.shape
        for i in range(shape[0]):
            for j in range(shape[1]):
                for n in range(shape[2]):
                    for m in range(shape[3]):
                        self.k_grad[j] += delta[i, j, n, m] * self.x[i, :, n:n + self.k.shape[2],
                                                              m:m + self.k.shape[3]]
        self.b_grad = np.sum(delta, axis=(0, 2, 3))
        self.k_grad /= shape[0]
        self.b_grad /= shape[0]

        '''计算x的梯度'''
        k_180 = np.rot90(self.k, 2, (2, 3))
        new_delta = np.zeros(self.x.shape)
        shape1 = self.x.shape
        padding = np.zeros(
            (shape1[0], shape[1], self.x.shape[2] + self.k.shape[2] - 1, self.x.shape[3] + self.k.shape[3] - 1))
        pad = (self.x.shape[2] + self.k.shape[2] - 1 - delta.shape[2]) // 2
        for i in range(padding.shape[0]):
            for j in range(padding.shape[1]):
                padding[i][j] = np.pad(delta[i][j], ((pad, pad), (pad, pad)), 'constant')
        k_180 = k_180.swapaxes(0, 1)

        shape0 = padding.shape
        shape1 = k_180.shape
        out = np.zeros((shape0[0], shape1[0], shape0[2] - shape1[2] + 1, shape0[3] - shape1[3] + 1))

        for i in range(out.shape[0]):
            for j in range(out.shape[1]):
                out[i][j] = conv_3d(padding[i], k_180[j], 0)
        self.k -= lr * self.k_grad
        self.b -= lr * self.b_grad
        return out


def get_batchsize(batch_size, N):
    a = []
    b = list(range(N))
    random.shuffle(b)
    for i in range(N):
        l = b[i * batch_size:batch_size * (i + 1)]
        a.append(l)
        if len(l) < batch_size:
            break
    return a


def train():
    N = 1000
    random_index = random.sample(range(train_data.shape[0]), N)
    train_x = train_data[random_index]
    train_y = train_labels[random_index]
    oneHot = np.identity(10)
    train_y = oneHot[train_y]
    train_x = train_x.reshape(N, 1, 28, 28) / 255

    conv1 = Conv(kernel_shape=(6, 1, 5, 5))  # N * 6 * 24 * 24
    relu1 = Relu()
    pool1 = Pooling()  # N * 6 * 12 *12

    conv2 = Conv(kernel_shape=(16, 6, 5, 5))  # N * 16 * 8 * 8
    relu2 = Relu()
    pool2 = Pooling()  # N * 16 * 4 * 4

    linear = Linear(256, 10)

    softmax = Softmax()
    epoch = 10
    batch_size = 10
    lr = 0.01
    for i in range(epoch):
        batch_radom_index = get_batchsize(batch_size, N)
        for n, indexs in enumerate(batch_radom_index):
            if len(indexs) == 0:
                break
            batch_x = train_x[indexs]
            batch_y = train_y[indexs]
            out = conv1.forward(batch_x)
            out = relu1.forward(out)
            out = pool1.forward(out)

            out = conv2.forward(out)
            out = relu2.forward(out)
            out = pool2.forward(out)

            out = out.reshape(batch_size, -1)

            out = linear.forward(out)
            loss, delta = softmax.forward(out, batch_y)

            delta = linear.bp(delta, lr)
            delta = delta.reshape((batch_size, 16, 4, 4))

            delta = pool2.bp(delta)
            delta = relu2.backward(delta)
            delta = conv2.bp(delta, lr)

            delta = pool1.bp(delta)
            delta = relu1.backward(delta)
            conv1.bp(delta, lr)

            print("Epoch-{}-{:05d}".format(str(i), n), ":", "loss:{:.4f}".format(loss))
        lr *= 0.95 ** (i + 1)  # 学习率指数衰减
        np.savez("data.npz", k1=conv1.k, b1=conv1.b, k2=conv2.k, b2=conv2.b, w3=linear.W, b3=linear.b)


def test():
    r = np.load("data.npz")  # 载入训练好的参数
    N = 100
    random_index = random.sample(range(test_data.shape[0]), N)
    test_x = test_data[random_index]
    test_y = test_labels[random_index]
    # oneHot = np.identity(10)
    # test_y = oneHot[test_y]
    test_x = test_x.reshape(len(test_x), 1, 28, 28) / 255.  # 归一化

    conv1 = Conv(kernel_shape=(6, 1, 5, 5))  # N * 6 * 24 * 24
    relu1 = Relu()
    pool1 = Pooling()  # N * 6 * 12 *12

    conv2 = Conv(kernel_shape=(16, 6, 5, 5))  # N * 16 * 8 * 8
    relu2 = Relu()
    pool2 = Pooling()  # N * 16 * 4 * 4

    nn = Linear(256, 10)
    softmax = Softmax()

    conv1.k = r["k1"]
    conv1.b = r["b1"]
    conv2.k = r["k2"]
    conv2.b = r["b2"]
    nn.W = r["w3"]
    nn.b = r["b3"]

    out = conv1.forward(test_x)
    out = relu1.forward(out)
    out = pool1.forward(out)
    out = conv2.forward(out)
    out = relu2.forward(out)
    out = pool2.forward(out)

    out = out.reshape(N, -1)

    out = nn.forward(out)
    num = 0
    for i in range(N):
        if np.argmax(out[i, :]) == test_y[i]:
            num += 1
    print("TEST-ACC: ", num / N * 100, "%")


train_data, train_labels, test_data, test_labels = load_data()
if __name__ == '__main__':
    test()

准备下一步RNN了

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

numpy实现cnn 的相关文章

随机推荐

  • Centos8安装JDK

    官网下载页 xff1a https www oracle com java technologies downloads 选择自己需要的JDK版本进行下载即可 一 下载上传 https docs oracle com javase 8 do
  • linux操作系统关机命令

    关机命令 在linux中关机命令 有以下几个 shutdow shutdown命令安全地将系统关机 有些用户会使用直接断掉电源的方式来关闭linux xff0c 这是十分危险的 因为linux与windows不同 xff0c 其后台运行着许
  • .eslintrc.js文件内容/配置eslint/eslint参数

    首先放一个官网的链接 List of available rules ESLint中文文档 然后直接上代码 这里以vue项目为例 xff0c 主要两个文件 xff0c 1是 eslintrc js文件 xff08 配置 xff09 xff0
  • 【python】使用pyinstaller将程序打包为exe文件

    前言 xff1a 如何将python的 py文件打包为exe文件 xff0c 以打包单独文件的简单程序 和打包基于pygame库编写的多模块程序 为例 xff0c 以及如何处理素材文件使打包后的文件可以正常运行 xff0c 还有一些总结 x
  • 关于AndroidStudio添加一个新的Activity但没有配置或者模拟器无法打开app的问题

    今天原本打算测试一下是否可以用图片imageView当做一个点击事件使用 xff0c 于是我建立了一个新的Activity xff0c 结果折腾了大半天启动的时候发现模拟器怎么都无法打开那个app xff0c 检查了一下注册表已经存在这个a
  • k8s资源清单创建pod、deployment、service

    资源清单配置 pod yaml span class token comment 暴露端口可以进行访问 span span class token punctuation span root 64 master span class tok
  • windows和ubuntu双系统怎么设置默认启动windows选项

    首先获得管理员权限才能修改 sudo su 打开相应目录 cd etc default 打开编辑界面 sudo gedit grub 把下面一段代码中的 GRUB DEFAULT 61 0 中的 0 改为你的windows系统在引导界面所在
  • 解决ubuntu18.04&windows10双系统时间不同步问题(在ubuntu环境下使用)

    sudo apt get install ntpdate sudo ntpdate time windows com sudo hwclock localtime systohc
  • ROS Melodic 安装(ubuntu18.04)

    因为后面需要用到python所以我先安装一下 xff0c 不安装应该也行 sudo apt get install python 设置sources list sudo sh c 39 echo 34 deb http packages r
  • ubuntu双系统怎么完全删除ubuntu系统(主要是删除引导)

    必备基础 xff1a 会制作和简单的使用PE系统 xff0c 以下操作均需要在PE中完成 步骤 1 首先你要用U盘制作一个可以使用的PE系统 xff08 推荐使用微PE xff09 2 进入PE系统中把ubuntu对应的分区全部删除 xff
  • arch安装wps

    输入以下命令即可 yay S wps office mui zh cn wps office mime cn wps office cn wps office fonts ttf ms fonts ttf wps fonts
  • oh-my-posh 配置powershell

    写这篇文章记录的原因就是因为很多关于oh my posh的之前的配置教程已经不适用 xff0c 特此记录下来 打开powershell输入 winget span class token function install span JanD
  • 后端开发工具有哪些

    标题 后端开发工具有哪些 1 阿尔萨斯Java在线诊断工具 Arthas是一款用于Java应用程序的在线诊断工具 xff0c 由阿里巴巴于2018年9月开源 2 Cloud Toolkit IDE插件 Cloud Toolkit是一个集成开
  • 启动Zookeper时出现闪退现象

    这里写自定义目录标题 最近在回顾项目的时候遇到zookeeper闪退问题第一步 xff1a 查找问题原因第二步 xff1a 解决问题 最近在回顾项目的时候遇到zookeeper闪退问题 最近打算复习一下之前写的项目 xff0c 却在启动zo
  • 详解基数排序

    1 基数排序 基数排序是一种特殊的排序方式 xff0c 不是基于比较进行排序 xff0c 而是基于关键字的各个位置大小进行 34 分配 34 和 34 收集 34 两种操作对关键字序列进行排序的一种排序方式 基数排序可以分为 xff1a 最
  • Maven基础教程

    文章目录 一 jar包 xff08 一 xff09 打开一个jar包 xff08 二 xff09 打包一个jar包 二 Maven xff08 一 xff09 概述 xff08 二 xff09 仓库与坐标 本地仓库 第三方仓库 xff08
  • 重启策略 ,健康检查,环境变量,初始化容器

    重启策略 简介 Always 当容器终止退出后 xff0c 总是重启容器 xff0c 默认策略 OnFailure 当容器异常退出 退出状态码非0 时 xff0c 才重启容器 Never 当容器终止退出 xff0c 从不重启容器 span
  • 用两种方法求阶乘的累加和(1050: 阶乘的累加和)

    题目描述 求1 43 2 43 n 输入 输入一个整数n xff0c 你可以假定n不大于10 输出 输出一个整数 xff0c 即阶乘累加的结果 xff0c 单独占一行 样例输入 4 样例输出 33 方法一 xff1a 用for的循环两次 s
  • 小白一起学Android studio 创建项目

    本人也是在学习Android Studio xff0c 就想把自己熟悉的记录一下 我用的是Android Studio是 2021 1 1 Patch 2版本 xff1b 1 点击New Project 2 选择Empty Activity
  • numpy实现cnn

    经过多天的奋战 xff0c 终于写出了一个完成的cnn框架 xff0c 里面最主要的还是卷积反向传播这一块 网络架构 用到的包 数据集 xff1a minist 这里是随机抽取了1000份做训练集 100份做测试集 整体流程 39 39 3