当前位置: 首页 > news >正文

高端商务网站建设广东网站开发建设

高端商务网站建设,广东网站开发建设,服务器网站别名设置,无锡网站制作哪些5 手写卷积函数 背景介绍滑动窗口的方式代码问题 矩阵乘法的方式原理代码结果 效果对比对比代码日志结果 一些思考 背景 从现在开始各种手写篇章#xff0c;先从最经典的卷积开始 介绍 对于卷积层的具体操作#xff0c;我这里就不在具体说卷积具体是什么东西了。 对于手写… 5 手写卷积函数 背景介绍滑动窗口的方式代码问题 矩阵乘法的方式原理代码结果 效果对比对比代码日志结果 一些思考 背景 从现在开始各种手写篇章先从最经典的卷积开始 介绍 对于卷积层的具体操作我这里就不在具体说卷积具体是什么东西了。 对于手写卷积操作而言有两种方式一种就是最朴素的通过滑动窗口来实现的方式另一种方式就是使用矩阵乘法来简化操作过程的方式。 滑动窗口的方式 卷积操作的动图https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md 通过上面的图片和连接就可以很直观地感受到卷积操作的方式也能很直接想到使用简单的滑动窗口来实现如果还不能理解建议去B站搜下视频学习下 代码 -*- coding: utf-8 -*- 使用滑动窗口方式的手动卷积 Author : Leezed Time : 2025/6/27 15:33 import numpy as npclass ManualSlideWindowConv():手动实现卷积操作使用滑动窗口方式没有实现反向传播功能def __init__(self, kernel_size, in_channel, out_channel, stride1, padding0, biasTrue):self.kernel_size kernel_sizeself.in_channel in_channelself.out_channel out_channelself.stride strideself.padding paddingself.bias biasself.weight np.random.randn(out_channel, in_channel, kernel_size, kernel_size)if bias:self.bias np.random.randn(out_channel)else:self.bias Nonedef print_weight(self):print(Weight shape:, self.weight.shape)print(Weight values:\n, self.weight)def get_weight(self):return self.weightdef set_weight(self, weight):if weight.shape ! self.weight.shape:raise ValueError(fWeight shape mismatch: expected {self.weight.shape}, got {weight.shape})self.weight weightdef __call__(self, x, *args, **kwargs):if self.padding 0:x np.pad(x, ((0, 0), (0, 0), (self.padding, self.padding), (self.padding, self.padding)), modeconstant) # 在四周填充0batch_size, in_channel, height, width x.shapekernel_size self.kernel_size# 计算输出的高度和宽度out_height (height - kernel_size) // self.stride 1out_width (width - kernel_size) // self.stride 1output np.zeros((batch_size, self.out_channel, out_height, out_width))for channel in range(self.out_channel):# 取出当前输出通道的权重kernel self.weight[channel, :, :, :]# 添加biasif self.bias is not None:output[:, channel, :, :] self.bias[channel]else:output[:, channel, :, :] 0for i, end_height in enumerate(range(kernel_size - 1, height, self.stride)):for j, end_width in enumerate(range(kernel_size - 1, width, self.stride)):# 取出图像的滑动窗口start_height end_height - kernel_size 1start_width end_width - kernel_size 1window x[:, :, start_height:end_height 1, start_width:end_width 1]# 计算卷积result np.sum(kernel * window, axis(1, 2, 3))output[:, channel, i, j] resultreturn outputif __name__ __main__:# 测试代码x np.random.randn(2, 3, 5, 5) # batch_size2, in_channel3, height5, width5conv_layer ManualSlideWindowConv(kernel_size3, in_channel3, out_channel2, stride1, padding1)output conv_layer(x)print(Output shape:, output.shape)conv_layer.print_weight() 问题 但是活动卷积的方式有一个问题就是这个方式太费时了因为有三层循环而对于python而言是用循环去计算是一件费力不讨好的事情具体的时间花费我会在后面画出图来直观地展现 矩阵乘法的方式 原理 https://zhuanlan.zhihu.com/p/360859627 https://gist.github.com/hsm207/7bfbe524bfd9b60d1a9e209759064180 https://blog.csdn.net/caip12999203000/article/details/126494740 具体的原理我就不赘述了上面的三个链接认真看也能看明白了他的本质思想就是讲滑动窗口中的多次乘法直接改成矩阵乘法通过这种方式来进行加速而且加速的幅度不小但是会生成一个较大的矩阵不可避免的带来内存的开销也就是说本质是拿空间换时间 具体的例子就在图中 mmConv ManualMatMulConv(kernel_size3, in_channel3, out_channel64,padding1)的卷积层面对 x np.random.randn(64, 3, 224, 224).astype(np.float32)的特征就要吃1.5G的内存了。 代码 class ManualMatMulConv():手动实现卷积操作使用卷积乘法方式没有实现反向传播功能def __init__(self, kernel_size, in_channel, out_channel, stride1, padding0, biasTrue):self.kernel_size kernel_sizeself.in_channel in_channelself.out_channel out_channelself.stride strideself.padding paddingself.bias biasself.weight np.random.randn(out_channel, in_channel, kernel_size, kernel_size)if bias:self.bias np.random.randn(out_channel)else:self.bias Nonedef print_weight(self):print(Weight shape:, self.weight.shape)print(Weight values:\n, self.weight)def get_weight(self):return self.weightdef set_weight(self, weight):if weight.shape ! self.weight.shape:raise ValueError(fWeight shape mismatch: expected {self.weight.shape}, got {weight.shape})self.weight weightdef __call__(self, x, *args, **kwargs):if self.padding 0:x np.pad(x, ((0, 0), (0, 0), (self.padding, self.padding), (self.padding, self.padding)), modeconstant) # 在四周填充0batch_size, in_channel, height, width x.shapekernel_size self.kernel_size# 计算输出的高度和宽度out_height (height - kernel_size) // self.stride 1out_width (width - kernel_size) // self.stride 1# 将权重转换为矩阵形式weight_matrix self.weight.reshape(self.out_channel, -1) # shape (out_channel, in_channel * kernel_size * kernel_size)# 将输入转为矩阵形式 手写unfold方式unfolded_x []for i in range(0, height - kernel_size 1, self.stride):for j in range(0, width - kernel_size 1, self.stride):# 取出图像的滑动窗口 转成矩阵形式window x[:, :, i:i kernel_size, j:j kernel_size].reshape(batch_size, -1)unfolded_x.append(window)unfolded_x np.array(unfolded_x) # shape: (num_windows, batch_size, in_channel * kernel_size * kernel_size)unfolded_x np.transpose(unfolded_x, (1, 0, 2)) # shape: (batch_size, num_windows, in_channel * kernel_size * kernel_size)# 使用矩阵乘法计算卷积output np.matmul(unfolded_x, weight_matrix.T) # shape (batch_size, num_windows, out_channel)output np.transpose(output, (0, 2, 1)) # shape (batch_size, out_channel, num_windows)output output.reshape(batch_size, self.out_channel, out_height, out_width)# 添加biasif self.bias is not None:output self.bias.reshape(1, -1, 1, 1)# 输出结果return output结果 检测代码 if __name__ __main__:# 测试代码conv ManualMatMulConv(kernel_size3, in_channel3, out_channel2, stride1, padding0, biasFalse)slide_window_conv ManualSlideWindowConv(kernel_size3, in_channel3, out_channel2, stride1, padding0, biasFalse)conv.set_weight(slide_window_conv.get_weight())x np.random.randn(1, 3, 5, 5) # 输入形状 (batch_size, in_channel, height, width)output conv(x)slide_window_output slide_window_conv(x)print(Output shape:, output.shape)print(slide_window_output shape:, slide_window_output.shape)assert np.allclose(conv.get_weight(), slide_window_conv.get_weight()), Weights do not match!print(output:)print(output)print(slide_window_output:)print(slide_window_output)# 校验是否相同assert np.allclose(output, slide_window_output), Outputs do not match!print(Outputs match!) 效果对比 这里采取了四种方式的卷积来进行对比 滑动窗口方式的卷积矩阵乘法的卷积torch.nn.Conv2dtorch.nn.Conv2d 使用cuda 对比代码 import numpy as np from matplotlib import pyplot as plt from manual.conv.slide_window import ManualSlideWindowConv from manual.conv.matmul import ManualMatMulConv import torch import time# 对比不同batchsize的卷积速度speeds {manual_matmul: [],manual_slide_window: [],torch: [],torch_cuda: [] }swConv ManualSlideWindowConv(kernel_size3, in_channel3, out_channel64,padding1) mmConv ManualMatMulConv(kernel_size3, in_channel3, out_channel64,padding1) torchConv torch.nn.Conv2d(in_channels3, out_channels64, kernel_size3, padding1) torchCudaConv torch.nn.Conv2d(in_channels3, out_channels64, kernel_size3, padding1).cuda()def timing_conv(conv,x):start time.time()y conv(x)end time.time()return y, end - startfor bs in [1, 2, 4, 8, 16, 32]:x np.random.randn(bs, 3, 224, 224).astype(np.float32)x_torch torch.from_numpy(x)x_torch_cuda x_torch.cuda()y, speed timing_conv(swConv, x)speeds[manual_slide_window].append(speed)print(fslide_window bs{bs}, speed{speed:.4f}s)y, speed timing_conv(mmConv, x)speeds[manual_matmul].append(speed)print(fmatmul bs{bs}, speed{speed:.4f}s)y, speed timing_conv(torchConv, x_torch)speeds[torch].append(speed)print(ftorch bs{bs}, speed{speed:.4f}s)y, speed timing_conv(torchCudaConv, x_torch_cuda)speeds[torch_cuda].append(speed)print(ftorch_cuda bs{bs}, speed{speed:.4f}s)print(- * 50) 日志 slide_window bs1, speed39.8342s matmul bs1, speed0.1436s torch bs1, speed0.0080s torch_cuda bs1, speed0.0000s -------------------------------------------------- slide_window bs2, speed39.8841s matmul bs2, speed0.2185s torch bs2, speed0.0172s torch_cuda bs2, speed0.0010s -------------------------------------------------- slide_window bs4, speed44.0416s matmul bs4, speed0.3975s torch bs4, speed0.0329s torch_cuda bs4, speed0.0000s -------------------------------------------------- slide_window bs8, speed41.7520s matmul bs8, speed0.3222s torch bs8, speed0.0588s torch_cuda bs8, speed0.0000s -------------------------------------------------- slide_window bs16, speed45.5278s matmul bs16, speed0.5858s torch bs16, speed0.1067s torch_cuda bs16, speed0.0010s -------------------------------------------------- slide_window bs32, speed58.1965s matmul bs32, speed1.2161s torch bs32, speed0.2045s torch_cuda bs32, speed0.0010s --------------------------------------------------结果 去掉最慢的滑动窗口的结果展示 可以看到矩阵乘法的方式还是挺快的至少比滑动窗口快多了 一些思考 但是随之而来的就是还有一个问题为什么矩阵乘法的方式的内存开销这么大但是torch.nn.Conv2d好像并没有这个问题 经过查阅了一些资料我简单总结一下 瓦片式Tiling或分块Blocking计算 虽然 矩阵乘法 概念上是将整个输入和卷积核展开但实际的硬件实现如GPU并不总是一次性处理所有数据。它们可能会将计算任务分解成更小的“瓦片”或“块”。 局部 矩阵乘法 不是一次性将整个图像展开而是每次只对输入的一小部分例如一个批次、或者一个输出通道的一个小区域进行 im2col 变换和矩阵乘法。这样可以限制中间矩阵的大小从而减少瞬时内存占用。计算完成后再将结果拼接到最终的输出特征图上。 重用数据 这种分块策略有助于更好地利用 CPU 缓存或 GPU 显存因为同一小块数据可以在其被完全处理完毕前反复用于计算减少数据在主存和缓存之间的移动。 智能算法选择 根据卷积参数动态选择最适合的底层算法如 Winograd, FFT, 或优化过的直接卷积而不是单一地依赖 im2col。 这也就是为啥我们写出来的方法跟官方版本的有差距的原因。
http://www.zqtcl.cn/news/567643/

相关文章:

  • 爱站seo东莞网站建设要注意什么
  • 惠州网站建设 英语6wordpress 表格提交
  • 做网站15年多少钱一度电
  • 北京网站域名快速备案外贸网站优化价格
  • 做网站 工资高吗免费建站的站点网站
  • 个人做营利性质网站会怎么样qq邮箱官方网站
  • 网站怎么做等级保护产品展示小程序
  • 奉贤网站建设专家高端自适应网站设计
  • 网站正在建设中 动态徐州网站建设方案咨询
  • 广东世纪达建设集团有限公司官方网站专业电商网站开发
  • 抚顺建设网站自适应网站建设推荐
  • 做网站的大公司手机页面
  • 网站建设的公司实习做什么系统设计
  • 兰州网站设计哪个平台好外贸网站定制公司哪家好
  • 做网站需要先买域名吗在线音乐网站开发数据库
  • 深圳优化网站搬家网站模板
  • 网站建设做的人多吗门户网站制作建设
  • 哪个网站可以做logo怀柔网页公司制作
  • 网站被抄袭怎么投诉网站建设丨金手指15
  • 中国交建平台seo搜索引擎优化是通过优化答案
  • 简述网站的建设流程图食品网站app建设方案
  • 西安建设厅网站首页听说上海又要封了
  • 兼职python做网站如何制作一个网站包含多个网页
  • 花园桥网站建设百度怎么创建网站
  • 做网站 客户一直要求改做网站学不需要做后台管理系统
  • 企业网站托管电话输入姓名查询个人征信
  • 域名注册了后怎么建设网站荆州市建设厅网站
  • 厦门网站建设合同wordpress的设置网址
  • 澎湃动力网站建设公司门户类网站建设需要多少钱
  • 祭祖网站怎么做咨询类网站开发的意义