机器学习---CNN(创建和训练一个卷积神经网络并评估其性能)上

news2024/11/23 11:43:30

1. cnn_operations模块

cnn_operations类

    @staticmethod
    def calc_loss(Y, tilde_Y):
        
        # 训练样本个数
        n_samples = Y.shape[0]
        # 网络代价
        loss = 0
        for i in range(n_samples):
            loss += np.sum((Y[i, :] - tilde_Y[i, :])**2)
        loss /= (2 * n_samples)
        
        return loss
    

计算网络代价:
      
 
        Y: N * M array,各训练样本对应的类别标签,N为训练样本个数,M为类别数
        
        tilde_Y: N * M array,预测出的各训练样本的类别标签

        这个函数被定义为静态方法(使用了@staticmethod装饰器),所以它可以通过类名直接调

用,而不需要创建类的实例。  

    @staticmethod
    def convolute_2d(feature_map, kernel, size_kernel, stride, padding):
        
        # 输入特征图尺寸
        size_feature_map = np.asarray(feature_map.shape)
        # 输出特征图尺寸
        size_output = [int( \
            (size_feature_map[0] + 2 * padding - size_kernel[0]) / stride + 1),
            int( \
            (size_feature_map[1] + 2 * padding - size_kernel[1]) / stride + 1)]
        
        if padding == 0:
            feature_map_padded = feature_map
        elif padding > 0:
            # 补零后的特征图
            feature_map_padded = np.zeros(size_feature_map + 2 * padding)
            feature_map_padded[padding: -padding, padding: -padding] += \
                    feature_map
                    
        output = np.empty(size_output)
        
        for i in range(0, feature_map_padded.shape[0], stride):
            for j in range(0, feature_map_padded.shape[1], stride):
                sub_mat = feature_map_padded[i: np.min([i + size_kernel[0], 
                        feature_map_padded.shape[0]]), 
                        j: np.min([j + size_kernel[1], 
                        feature_map_padded.shape[1]])]
                shape_sub_mat = sub_mat.shape
                if (shape_sub_mat[0] < size_kernel[0]) or \
                        (shape_sub_mat[1] < size_kernel[1]):
                    break
                
                output[int(i/stride), int(j/stride)] = \
                        np.sum(sub_mat * kernel)
        
        return output

二维卷积(卷积核不翻转):

        feature_map: 2-d array,输入特征图(也可以被看作是输入的图像或前一层输出的特征图)
        
        kernel: 2-d array,卷积核;
        
        size_kernel: array,卷积核尺寸;
        
        stride: 整数,卷积核步长;
        
        padding: 整数,边缘补零的宽度,常用于保持特征图的尺寸。

         output: 二维数组,表示进行卷积操作后输出的特征图。

操作流程:

①计算输入特征图的尺寸size_feature_map。

②计算输出特征图的尺寸size_output。这个尺寸取决于输入特征图的尺寸,卷积核的尺寸,步长和

补零的宽度。

③如果补零的宽度为0,则不进行任何操作;如果补零的宽度大于0,则在输入特征图的边缘添加相

应宽度的零,得到feature_map_padded。

④初始化输出特征图output。

⑤对feature_map_padded进行卷积操作:在每个步长位置,取出与卷积核相同尺寸的子区域

sub_mat,然后将sub_mat与卷积核逐元素相乘并求和,得到的结果存储在output的相应位置。

    @staticmethod
    def pool(feature_map, type_pooling, size_kernel, stride, padding):
      
        # 输入特征图尺寸
        size_feature_map = np.asarray(feature_map.shape)
        # 输出特征图尺寸
        size_output = [int( \
            (size_feature_map[0] + 2 * padding - size_kernel[0]) / stride + 1),
            int( \
            (size_feature_map[1] + 2 * padding - size_kernel[1]) / stride + 1)]
        
        if padding == 0:
            feature_map_padded = feature_map
        elif padding > 0:
            # 补零后的特征图
            feature_map_padded = np.zeros(size_feature_map + 2 * padding)
            feature_map_padded[padding: -padding, padding: -padding] += \
                    feature_map
                    
        output = np.empty(size_output)
        
        if type_pooling is "max":
            func = np.max
        elif type_pooling is "average":
            #池化层每个神经元有一个权值,此处只需求和,不需求均值
            func = np.sum
        
        for i in range(0, feature_map_padded.shape[0], stride):
            for j in range(0, feature_map_padded.shape[1], stride):
                sub_mat = feature_map_padded[i: np.min([i + size_kernel[0], 
                        feature_map_padded.shape[0]]), 
                        j: np.min([j + size_kernel[1], 
                        feature_map_padded.shape[1]])]
                shape_sub_mat = sub_mat.shape
                if (shape_sub_mat[0] < size_kernel[0]) or \
                        (shape_sub_mat[1] < size_kernel[1]):
                    break
                
                output[int(i/stride), int(j/stride)] = func(sub_mat)
                
        return output

池化(用于降低特征图的维度,同时保持重要的特征):
        
        feature_map: 2-d array,输入特征图
        
        type_pooling: 池化核类型,{"max", "average"}
        
        size_kernel: array,池化核尺寸
        
        stride: 池化核步长,整数
        
        padding: 边缘补零的宽度,整数

        output: 二维数组,表示进行池化操作后输出的特征图。

操作流程:

①计算输入特征图的尺寸size_feature_map。

②计算输出特征图尺寸size_output。取决于输入特征图尺寸,池化核尺寸,步长和补零的宽度。

③如果补零的宽度为0,则不进行任何操作;如果补零的宽度大于0,则在输入特征图的边缘添加相

应宽度的零,得到feature_map_padded。

④初始化输出特征图output。

⑤根据池化类型选择相应的函数func。

⑥对feature_map_padded进行池化操作:在每个步长位置,取出与池化核相同尺寸的子区域

sub_mat,然后将func应用于sub_mat,得到的结果存储在output的相应位置。

    @staticmethod
    def upsample_conv_2d(delta_next_layer, kernel, size_kernel, stride):
       
        # 下一层(卷积层)中一个神经元的灵敏度map的尺寸
        size_delta_next_layer = np.asarray(delta_next_layer.shape)
        # 边缘补零后当前层一中一个神经元灵敏度map的尺寸
        size_delta_padded = \
                [size_delta_next_layer[0] * stride + size_kernel[0] - stride, 
                 size_delta_next_layer[1] * stride + size_kernel[1] - stride]
        delta_padded = np.zeros(size_delta_padded)
        for i in range(delta_next_layer.shape[0]):
            for j in range(delta_next_layer.shape[1]):
                # 卷积核不翻转
                delta_padded[i * stride: i * stride + size_kernel[0], 
                             j * stride: j * stride + size_kernel[1]] += \
                                     delta_next_layer[i, j] * kernel
        
        return delta_padded

当前层为池化层,下一层为卷积层时的上采样:
        
        delta_next_layer: 2-d array,下一层(卷积层)中一个神经元的灵敏度map
        
        kernel: 2-d array,(下一层中一个神经元的一个)卷积核
        
        size_kernel: array,(下一层中一个神经元的一个)卷积核的尺寸
        
        stride: (下一层中一个神经元的一个)卷积核的步长
    
        delta_padded: 2-d array,当前(池化)层中一个神经元的灵敏度map(边缘补零后)
     
操作流程:

①计算下一层(卷积层)中一个神经元的灵敏度map的尺寸size_delta_next_layer。

②计算边缘补零后当前层中一个神经元的灵敏度map的尺寸size_delta_padded。这个尺寸取决于

下一层灵敏度map的尺寸,卷积核的尺寸和步长。

③初始化当前层的灵敏度map:delta_padded。

④对下一层的灵敏度map进行遍历,在每个位置,将该位置的灵敏度值乘以卷积核,然后加到当前

层的相应位置。

    @classmethod
    def upsample_pool(cls, delta_next_layer, type_pooling, 
                      size_kernel, stride):
       
        if type_pooling is "max":
            # TODO: 
            pass
        
        elif type_pooling is "average":
            # 池化时实际进行了求和运算,故权值均为1
            kernel = np.ones(size_kernel)
            delta_padded = cls.upsample_conv_2d(delta_next_layer, kernel, 
                                                size_kernel, stride)
            
        return delta_padded

当前层为卷积层,下一层为池化层时的上采样:
        
        delta_next_layer: 2-d array,下一层(池化层)中一个神经元的灵敏度map
        
        type_pooling: (下一层中一个神经元的)池化核类型,{"max", "average"}
        
        size_kernel: array,(下一层中一个神经元的)池化核尺寸
        
        stride: (下一层中一个神经元的)池化核步长

        delta_padded: 2-d array,当前(卷积)层中一个神经元的灵敏度map(边缘补零后)
     
操作流程:

①首先判断池化类型。如果是max,那么暂未实现(标记为TODO)。如果是average,则进行

下一步操作。

②对于average池化,由于池化过程实际上是求和运算,每个元素的贡献相同,所以权值均为1,

构造一个全为1的kernel。

③调用upsample_conv_2d方法,将下一层的灵敏度map扩展到当前层的尺寸。

    @staticmethod
    def inv_conv_2d(feature_map, size_kernel, stride, padding, delta):
       
        # 输入特征图尺寸
        size_feature_map = np.asarray(feature_map.shape)
        
        if padding == 0:
            feature_map_padded = feature_map
        elif padding > 0:
            # 补零后的特征图
            feature_map_padded = np.zeros(size_feature_map + 2 * padding)
            feature_map_padded[padding: -padding, padding: -padding] += \
                    feature_map
                    
        output = 0
        for i in range(0, feature_map_padded.shape[0], stride):
            for j in range(0, feature_map_padded.shape[1], stride):
                sub_mat = feature_map_padded[i: np.min([i + size_kernel[0], 
                        feature_map_padded.shape[0]]), 
                        j: np.min([j + size_kernel[1], 
                        feature_map_padded.shape[1]])]
                shape_sub_mat = sub_mat.shape
                
                if (shape_sub_mat[0] < size_kernel[0]) or \
                        (shape_sub_mat[1] < size_kernel[1]):
                    break
                
                output += delta[int(i/stride), int(j/stride)] * sub_mat
                
        return output

计算网络代价对卷积层中一个神经元的一个卷积核的偏导数:
        
        feature_map: 2-d array,输入特征图
        
        size_kernel: array,卷积核尺寸
        
        stride: 卷积核的步长
        
        padding: 边缘补零的宽度
        
        delta: 2-d array,卷积层中一个神经元的灵敏度map
 
        output: 2-d array,尺寸与卷积核尺寸相同

操作流程:

①首先获取输入特征图的尺寸,然后根据边缘补零的宽度padding,对输入特征图进行补零操作。

②初始化输出output为0。

③进行两层循环,以步长`stride`遍历补零后的特征图。

④在每次循环中,取出特征图中与卷积核尺寸相同的一个子区域sub_mat。

⑤检查子区域的尺寸,如果子区域的尺寸小于卷积核尺寸,那么跳过当前循环。

⑥计算子区域与对应的灵敏度值的乘积,并累加到输出值output中。

    @staticmethod
    def _relu(x):
        
        return np.max([0, x])
    
    
    @staticmethod
    def _sigmoid(x):
        return 1 / (1 + np.exp(-x))
    
    
    @classmethod
    def _tanh(cls, x):
        return 2 * cls._sigmoid(2 * x) - 1
    
    @classmethod
    def activate(cls, feature_map, type_activation):
      
        if type_activation is None:
            return feature_map
        
        elif type_activation is "relu":
            func = cls._relu
        elif type_activation is "sigmoid":
            func = cls._sigmoid
        elif type_activation is "tanh":
            func = cls._tanh
            
        size_feature_map = np.asarray(feature_map.shape)
        
        output = np.empty(size_feature_map)
        for i in range(size_feature_map[0]):
            for j in range(size_feature_map[1]):
                output[i, j] = func(feature_map[i, j])
                
        return output
    

激活:

       feature_map: 2-d array,输入特征图
        
        type_activation: 激活函数类型,{"relu", "sigmoid", "tanh", None}
      
        output: 2-d array,激活后特征图,与输入特征图尺寸相同

        根据输入的类型_activation选择对应的激活函数,比如"relu"选择ReLU函数。通过双循环遍历

输入特征图每个元素,将其输入到选择的激活函数中,得到输出特征图每个元素的值。实现了将输入

特征图经过不同激活函数处理,输出经激活后的特征图。

2. test模块

配置和构建一个简单的卷积神经网络模型:

def config_net():
   
    # 输入层
    size_input = np.array([8, 8])
    args_input = ("input", (size_input,))
    
    # C1卷积层
    connecting_matrix_C1 = np.ones([1, 2])
    size_conv_kernel_C1 = np.array([5, 5])
    stride_conv_kernel_C1 = 1
    padding_conv_C1 = 0
    type_activation_C1 = "sigmoid"
    args_C1 = ("convoluting", (connecting_matrix_C1, size_conv_kernel_C1, 
                               stride_conv_kernel_C1, padding_conv_C1, 
                               type_activation_C1))
    
    # S2池化层
    type_pooling_S2 = "average"
    size_pool_kernel_S2 = np.array([2, 2])
    stride_pool_kernel_S2 = 2
    padding_pool_S2 = 0
    type_activation_S2 = "sigmoid"
    args_S2 = ("pooling", (type_pooling_S2, size_pool_kernel_S2, 
                           stride_pool_kernel_S2, padding_pool_S2, 
                           type_activation_S2))
    
    # C3卷积层
    connecting_matrix_C3 = np.ones([2, 2])
    size_conv_kernel_C3 = np.array([2, 2])
    stride_conv_kernel_C3 = 1
    padding_conv_C3 = 0
    type_activation_C3 = "sigmoid"
    args_C3 = ("convoluting", (connecting_matrix_C3, size_conv_kernel_C3, 
                               stride_conv_kernel_C3, padding_conv_C3, 
                               type_activation_C3))
    
    # 输出层
    n_nodes_output = 2
    type_output = "softmax"
    args_output = ("output", (n_nodes_output, type_output))
    
    args = (args_input,
            args_C1,
            args_S2,
            args_C3,
            args_output)
    cnn_net = cnn()
    cnn_net.config(args)
    
    return cnn_net

定义了网络各层的参数:

        输入层大小;

        每个卷积层的连接矩阵、卷积核大小、步长、边缘填充、激活函数;

        池化层类型、池化核大小、步长、边缘填充、激活函数;

         输出层节点数和激活函数。

将这些参数打包成元组,形成每个层的参数元组,如args_C1定义C1层的参数元组。

将所有层的参数元组组成一个总的参数元组args,初始化一个cnn网络对象cnn_net,调用cnn_net

的config方法,传入参数元组args,完成网络结构的配置,返回配置好结构的cnn_net对象。
 

n_train = 10000
X_train = 0.2 * np.random.randn(8, 8, n_train)
Y_train = np.random.randint(2, size=n_train)
for i in range(Y_train.shape[0]):
    if Y_train[i] == 0:
        X_train[1, :, i] += np.ones(8)
    elif Y_train[i] == 1:
        X_train[:, 1, i] += np.ones(8)

size_batch = 50
n_epochs = 500
cnn_net = config_net()
cnn_net.fit(X_train, Y_train, size_batch=size_batch, n_epochs=n_epochs)

n_test = 1000
X_test = 0.2 * np.random.randn(8, 8, n_test)
Y_test = np.random.randint(2, size=n_test)
for i in range(Y_test.shape[0]):
    if Y_test[i] == 0:
        X_test[1, :, i] += np.ones(8)
    elif Y_test[i] == 1:
        X_test[:, 1, i] += np.ones(8)
        
correct_rate = cnn_net.test(X_test, Y_test)

plt.figure()
for i in range(cnn_net.layers[1].n_nodes):
    plt.subplot(1, 2, i + 1)
    plt.imshow(cnn_net.layers[1].nodes[i].conv_kernels[0], cmap="gray")
plt.show()

生成训练数据和测试数据:

         X_train, X_test shape为(8,8,n);Y_train, Y_test为0或1;

         根据Y标记,在X的不同位置增加一个单位向量 signal

        配置网络结构cnn_net,使用训练数据训练网络cnn_net.fit(),使用测试数据评估网络准确率

cnn_net.test(),可视化第一个卷积层学习得到的卷积核参数。

主要步骤包括:数据生成、网络配置、训练、测试、参数可视化

完整的分类任务流程:生成带有标记的训练和测试数据、搭建并训练卷积神经网络、测试网络效

果、查看卷积层学习到的特征
 

 


  


        

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1126247.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

编程自学路线:开源免费的教育资源 | 开源专题 No.40

trekhleb/javascript-algorithms Stars: 174.1k License: MIT 这个项目是一个包含许多流行算法和数据结构的 JavaScript 示例。该项目提供了各种不同类型的数据结构&#xff0c;如链表、队列、栈等&#xff0c;并且还提供了各种常见的算法实现&#xff0c;如排序算法、搜索算…

Kubernetes技术与架构-网络 3

Kubernetes集群支持为Pod或者Service申请IPV4或者IPV6的地址空间。 kube-apiserver --service-cluster-ip-range<IPv4 CIDR>,<IPv6 CIDR> kube-controller-manager --cluster-cidr<IPv4 CIDR>,<IPv6 CIDR> --service-cluster-ip-range<IPv4 CI…

Java switch封神之路

Java switch升级之路 一&#xff0c;介绍 switch 是一种用于多分支条件判断的控制流语句。它通过检查一个表达式的值&#xff0c;然后根据不同的情况执行相应的代码块。 在大多数编程语言中&#xff0c;switch 语句由多个 case 分支组成&#xff0c;每个 case 后面跟着一个常…

unity游戏画质设置功能实现

在游戏中往往会出现游戏画质设置的功能。 如图&#xff1a; 这个功能是怎么实现完成的呢&#xff1f; 一、目标&#xff1a;实现切换画质功能 二、了解unity支持的画质 首先要了解unity中共支持多少种画质。 在代码中也可以进行打印。 方法如下&#xff1a; void Start …

NC61 两数之和

牛客网 NC61 两数之和 https://www.nowcoder.com/share/jump/7890810391698077140732 记录&#xff1a;维护哈希表&#xff0c;题目满足&#xff0c;numbers内必有两数相加为target&#xff0c;则可理解为&#xff0c;每次只需要判断target减去当前数&#xff0c;是否能在维护的…

zookeeper源码(02)源码编译启动及idea导入

本文介绍一下zookeeper-3.9.0源码下载、编译及本地启动。 下载源码 git clone https://gitee.com/apache/zookeeper.gitcd zookeeper git checkout release-3.9.0 git checkout -b release-3.9.0源码编译 README_packaging.md文件 该文件介绍了编译zookeeper需要的环境和命…

【JavaEE】UDP数据报套接字编程

一、UDP数据报套接字编程 1.1 DatagramSocket API DatagramSocket 是UDP Socket&#xff0c;用于发送和接收UDP数据报。 DatagramSocket 构造方法&#xff1a; DatagramSocket 方法&#xff1a; 1.2 DatagramPacket API DatagramPacket是UDP Socket发送和接收的数据报。…

NAS搭建指南三——私人云盘

一、私人云盘选择 我选择的是可道云进行私人云盘的搭建可道云官网地址可道云下载地址&#xff0c;下载服务器端和 Windows 客户端可道云官方文档 二、环境配置 PHP 与 MySQL 环境安装&#xff1a;XAMPP 官网地址 下载最新的 windows 版本 安装时只勾选 MySQL 与 PHP相关即可…

sklearn-6算法链与管道

思想类似于pipeline&#xff0c;将多个处理步骤连接起来。 看个例子&#xff0c;如果用MinMaxScaler和训练模型&#xff0c;需要反复执行fit和tranform方法&#xff0c;很繁琐&#xff0c;然后还要网格搜索&#xff0c;交叉验证 1 预处理进行参数选择 对于放缩的数据&#x…

工程化测试:Apollo的单元测试与集成测试指南

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

vue后台第二部步(布局和封装图标组件)

目录结构&#xff1b;根据需求修改、创建对应目录&#xff1b; src 应用部署目录├─api 接口├─assets 公共文件│ ├─theme.scss 主题样式…

一文了解AIGC与ChatGPT

一、AIGC简介 1.AIGC基础 (1)AIGC是什么 AIGC是人工智能图形计算的缩写&#xff0c;是一种基于图形处理器&#xff08;GPU&#xff09;的计算技术&#xff0c;可以加速各种计算任务&#xff0c;包括机器学习、深度学习、计算机视觉等。 AIGC是一种基于GPU的计算技术&#x…

MSQL系列(七) Mysql实战-SQL语句Join,exists,in的区别

Mysql实战-SQL语句Join&#xff0c;exists&#xff0c;in的区别 前面我们讲解了索引的存储结构&#xff0c;BTree的索引结构&#xff0c;以及索引最左侧匹配原则及讲解一下常用的SQL语句的优化建议&#xff0c;今天我们来详细讲解一下 我们经常使用的 join&#xff0c; exist&…

【机器学习】模型平移不变性/等变性归纳偏置Attention机制

Alphafold2具有旋转不变性吗——从图像识别到蛋白结构预测的旋转对称性实现 通过Alphafold2如何预测蛋白质结构&#xff0c;看有哪些机制或tricks可以利用&#xff1f; 一、等变Transformer 等变Transformer是Transformer众多变体的其中一种&#xff0c;其强调等变性。不变性…

基于Java的疫苗接种管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

面试题—JAVA基础①

文章目录 1.Java面向对象有哪些特征&#xff1f;2.ArrayList和LinkedList有什么区别&#xff1f;3.Java接口和抽象类有哪些区别&#xff1f;4.hashcode和equals如何使用&#xff1f;5.try-catch6.局部变量和实例变量7.String、StringBuffer、StringBuilder 的区别&#xff1f;8…

pycharm转移缓存目录

原来的缓存目录为C:\Users\86176\AppData\Local\JetBrains&#xff0c;各种配置文件、缓存文件随着pycharm的使用堆积在这里&#xff0c;导致C盘逐渐爆满。 因此需要将缓存目录转移至D盘。首先需要了解缓存目录的知识。 PyCharm 和其他 JetBrains 的 IDE 通常会有两个关键的目…

云原生之深入解析Kubernetes Pod如何获取IP地址

一、背景 Kubernetes 网络模型的核心要求之一是每个 Pod 都拥有自己的 IP 地址并可以使用该 IP 地址进行通信。很多人刚开始使用 Kubernetes 时&#xff0c;还不清楚如何为每个 Pod 分配 IP 地址。它们了解各种组件如何独立工作&#xff0c;但不清楚这些组件如何组合在一起使用…

牛客网刷题-(2)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…