GPU Puzzles讲解(二)

news2024/11/23 22:23:21

 GPU-Puzzles项目是一个很棒的学习cuda编程的项目,可以让你学习到GPU编程和cuda核心并行编程的概念,通过一个个小问题让你理解cuda的编程和调用,创建共享显存空间,实现卷积和矩阵乘法等

https://github.com/srush/GPU-Puzzlesicon-default.png?t=O83Ahttps://github.com/srush/GPU-Puzzles

本文是接续我上一篇文章的讲解,深入分析几个比较困难的puzzles,讲解实现和优化原理

,GPU Puzzles讲解(一)-CSDN博客GPU Puzzles是一个很棒的cuda编程学习仓库,本文是对其中题目介绍和思量讲解https://blog.csdn.net/lijj0304/article/details/142737859GPU Puzzles是一个很棒的cuda编程学习仓库,本文是对其中题目介绍和思量讲解https://blog.csdn.net/lijj0304/article/details/142737859

 Puzzle 11 - 1D Convolution

Implement a kernel that computes a 1D convolution between a and b and stores it in out. You need to handle the general case. You only need 2 global reads and 1 global write per thread.

实现一维卷积的教学,这里要求控制全局读写次数。一开始很自然的会想到把待卷积的向量和卷积核内容分别存下来。同时考虑到共享内存空间一般和每块的线程数直接关联,而卷积需要乘周围的几个元素,我们需要额外存储边界的几个元素。不仅要在共享内存中存储卷积核的内容,又为了控制到2次的全局读写,这里用了一个trick:即利用不需要存卷积核时的索引去存边界的额外元素

def conv_spec(a, b):
    out = np.zeros(*a.shape)
    len = b.shape[0]
    for i in range(a.shape[0]):
        out[i] = sum([a[i + j] * b[j] for j in range(len) if i + j < a.shape[0]])
    return out


MAX_CONV = 4
TPB = 8
TPB_MAX_CONV = TPB + MAX_CONV
def conv_test(cuda):
    def call(out, a, b, a_size, b_size) -> None:
        i = cuda.blockIdx.x * cuda.blockDim.x + cuda.threadIdx.x
        local_i = cuda.threadIdx.x

        # FILL ME IN (roughly 17 lines)
        shared_a = cuda.shared.array(TPB_MAX_CONV, numba.float32)
        shared_b = cuda.shared.array(MAX_CONV, numba.float32)
        
        if i < a_size:
            shared_a[local_i] = a[i]

        if local_i < b_size:
            shared_b[local_i] = b[local_i]
        else:
            local_j = local_i - b_size
            if i-b_size+TPB < a_size and local_j < b_size:
                shared_a[local_j+TPB] = a[i-b_size+TPB]
        cuda.syncthreads()
        
        total = 0.0
        for j in range(b_size):
            if i+j < a_size:
                total += shared_a[local_i+j] * shared_b[j]
        
        if i < a_size:
            out[i] = total

    return call


# Test 1

SIZE = 6
CONV = 3
out = np.zeros(SIZE)
a = np.arange(SIZE)
b = np.arange(CONV)
problem = CudaProblem(
    "1D Conv (Simple)",
    conv_test,
    [a, b],
    out,
    [SIZE, CONV],
    Coord(1, 1),
    Coord(TPB, 1),
    spec=conv_spec,
)
problem.show()

可视化效果

# 1D Conv (Simple)
 
   Score (Max Per Thread):
   |  Global Reads | Global Writes |  Shared Reads | Shared Writes |
   |             2 |             1 |             6 |             2 | 

一维卷积Test2:向量长度超过TPB

out = np.zeros(15)
a = np.arange(15)
b = np.arange(4)
problem = CudaProblem(
    "1D Conv (Full)",
    conv_test,
    [a, b],
    out,
    [15, 4],
    Coord(2, 1),
    Coord(TPB, 1),
    spec=conv_spec,
)
problem.show()

 可视化效果

# 1D Conv (Full)
 
   Score (Max Per Thread):
   |  Global Reads | Global Writes |  Shared Reads | Shared Writes |
   |             2 |             1 |             8 |             2 | 

Puzzle 12 - Prefix Sum

Implement a kernel that computes a sum over a and stores it in out. If the size of a is greater than the block size, only store the sum of each block.

这个是利用共享内存来计算前缀和,减少访存次数。可以利用两两归并相加的原理,最终结果存储在共享内存块的第1个。利用TPB分割向量长度,输出的out是每一段TPB长度的向量和

TPB = 8
def sum_spec(a):
    out = np.zeros((a.shape[0] + TPB - 1) // TPB)
    for j, i in enumerate(range(0, a.shape[-1], TPB)):
        out[j] = a[i : i + TPB].sum()
    return out


def sum_test(cuda):
    def call(out, a, size: int) -> None:
        cache = cuda.shared.array(TPB, numba.float32)
        i = cuda.blockIdx.x * cuda.blockDim.x + cuda.threadIdx.x
        local_i = cuda.threadIdx.x
        # FILL ME IN (roughly 12 lines)
        if i < size:
            cache[local_i] = a[i]
        else:
            cache[local_i] = 0
        cuda.syncthreads()
        p = 2
        while (p <= TPB):
            if local_i % p == 0:
                cache[local_i] += cache[local_i+p/2]
            cuda.syncthreads()
            p *= 2
        if local_i == 0:
            out[cuda.blockIdx.x] = cache[local_i]

    return call


# Test 1

SIZE = 8
out = np.zeros(1)
inp = np.arange(SIZE)
problem = CudaProblem(
    "Sum (Simple)",
    sum_test,
    [inp],
    out,
    [SIZE],
    Coord(1, 1),
    Coord(TPB, 1),
    spec=sum_spec,
)
problem.show()

可视化效果

# Sum (Simple)
 
   Score (Max Per Thread):
   |  Global Reads | Global Writes |  Shared Reads | Shared Writes |
   |             1 |             1 |             7 |             4 | 

前缀和Test2:

SIZE = 15
out = np.zeros(2)
inp = np.arange(SIZE)
problem = CudaProblem(
    "Sum (Full)",
    sum_test,
    [inp],
    out,
    [SIZE],
    Coord(2, 1),
    Coord(TPB, 1),
    spec=sum_spec,
)
problem.show()

可视化效果

# Sum (Full)
 
   Score (Max Per Thread):
   |  Global Reads | Global Writes |  Shared Reads | Shared Writes |
   |             1 |             1 |             7 |             4 | 

 

 Puzzle 13 - Axis Sum

Implement a kernel that computes a sum over each column of a and stores it in out.

其实就是前缀和的运用,这里加入了batch作为列标计,每个batch计算和,out尺寸和bath大小一致

TPB = 8
def sum_spec(a):
    out = np.zeros((a.shape[0], (a.shape[1] + TPB - 1) // TPB))
    for j, i in enumerate(range(0, a.shape[-1], TPB)):
        out[..., j] = a[..., i : i + TPB].sum(-1)
    return out


def axis_sum_test(cuda):
    def call(out, a, size: int) -> None:
        cache = cuda.shared.array(TPB, numba.float32)
        i = cuda.blockIdx.x * cuda.blockDim.x + cuda.threadIdx.x
        local_i = cuda.threadIdx.x
        batch = cuda.blockIdx.y
        # FILL ME IN (roughly 12 lines)
        if i < size:
            cache[local_i] = a[batch, i]
        else:
            cache[local_i] = 0
        cuda.syncthreads() 
        p = 2
        while (p <= TPB):
            if local_i % p == 0:
                cache[local_i] += cache[local_i+p/2]
            cuda.syncthreads()
            p *= 2
        if local_i == 0:
            out[batch, 0] += cache[local_i]

    return call


BATCH = 4
SIZE = 6
out = np.zeros((BATCH, 1))
inp = np.arange(BATCH * SIZE).reshape((BATCH, SIZE))
problem = CudaProblem(
    "Axis Sum",
    axis_sum_test,
    [inp],
    out,
    [SIZE],
    Coord(1, BATCH),
    Coord(TPB, 1),
    spec=sum_spec,
)
problem.show()

可视化效果

# Axis Sum
 
   Score (Max Per Thread):
   |  Global Reads | Global Writes |  Shared Reads | Shared Writes |
   |             2 |             1 |             7 |             4 | 

Puzzle 14 - Matrix Multiply!

Implement a kernel that multiplies square matrices a and b and stores the result in out.

矩阵乘法实现教学。第一直觉肯定就是利用二维的线程矩阵,循环行列遍历乘积求和。但是会有一个致命的问题就是线程矩阵比实际的矩阵小,而且想要控制全局读取的次数。这时就要利用好二维的共享空间,可以从对应行列出发,按行横向,列竖向顺序取部分的(TPB,TPB)矩阵块然后求乘积。从Test2的可视化图可以很直观看出这个思想

def matmul_spec(a, b):
    return a @ b


TPB = 3
def mm_oneblock_test(cuda):
    def call(out, a, b, size: int) -> None:
        a_shared = cuda.shared.array((TPB, TPB), numba.float32)
        b_shared = cuda.shared.array((TPB, TPB), numba.float32)

        i = cuda.blockIdx.x * cuda.blockDim.x + cuda.threadIdx.x
        j = cuda.blockIdx.y * cuda.blockDim.y + cuda.threadIdx.y
        local_i = cuda.threadIdx.x
        local_j = cuda.threadIdx.y
        # FILL ME IN (roughly 14 lines)
        total = 0.0
        for k in range(0, size, TPB): 
            if local_j + k < size and i < size:
                a_shared[local_i, local_j] = a[i, local_j+k]
            if local_i + k < size and j < size:
                b_shared[local_i, local_j] = b[local_i+k, j]
            cuda.syncthreads()
            
            for local_k in range(min(TPB, size-k)):
                total += a_shared[local_i, local_k] * b_shared[local_k, local_j]
        if i < size and j < size:
            out[i, j] = total

    return call

# Test 1

SIZE = 2
out = np.zeros((SIZE, SIZE))
inp1 = np.arange(SIZE * SIZE).reshape((SIZE, SIZE))
inp2 = np.arange(SIZE * SIZE).reshape((SIZE, SIZE)).T

problem = CudaProblem(
    "Matmul (Simple)",
    mm_oneblock_test,
    [inp1, inp2],
    out,
    [SIZE],
    Coord(1, 1),
    Coord(TPB, TPB),
    spec=matmul_spec,
)
problem.show(sparse=True)

可视化效果

# Matmul (Simple)
 
   Score (Max Per Thread):
   |  Global Reads | Global Writes |  Shared Reads | Shared Writes |
   |             2 |             1 |             4 |             2 | 

Test2大于线程矩阵的矩阵乘法:

SIZE = 8
out = np.zeros((SIZE, SIZE))
inp1 = np.arange(SIZE * SIZE).reshape((SIZE, SIZE))
inp2 = np.arange(SIZE * SIZE).reshape((SIZE, SIZE)).T

problem = CudaProblem(
    "Matmul (Full)",
    mm_oneblock_test,
    [inp1, inp2],
    out,
    [SIZE],
    Coord(3, 3),
    Coord(TPB, TPB),
    spec=matmul_spec,
)
problem.show(sparse=True)

可视化效果

# Matmul (Full)
 
   Score (Max Per Thread):
   |  Global Reads | Global Writes |  Shared Reads | Shared Writes |
   |             6 |             1 |            16 |             6 | 

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

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

相关文章

羚羊种类检测系统源码分享

羚羊种类检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

项目——超级马里奥——Day(3)

一、游戏开发思路&#xff1a; 1.Frame--->BackGround--->Obstacle---->BufferedImage&#xff0c;人物等 2.BackGround的构造函数&#xff1a; 只要记住窗口里边的每一个场景&#xff0c;只要游戏一开始就已经出现在屏幕里边的&#xff0c;都是在构造函数里边 3.绘…

就业市场需求分析:基于前程无忧岗位数据分析

背景介绍&#xff1a;在前程无忧网站&#xff0c;以"数据分析师""武汉"作为搜索关键词&#xff0c;爬取50页岗位数据合计980条。以该数据为基础&#xff0c;从岗位搜索匹配度、HR活跃度、不同区域/行业/企业的岗位数量和薪资分布等角度进行分析。 1、原始数…

自动驾驶 车道检测实用算法

自动驾驶 | 车道检测实用算法 车道识别是自动驾驶领域的一个重要问题&#xff0c;今天介绍一个利用摄像头图像进行车道识别的实用算法。该算法利用了OpenCV库和Udacity自动驾驶汽车数据库的相关内容。 该算法包含以下步骤&#xff1a; 摄像头校准&#xff0c;以移除镜头畸变&…

百度所有网页都打不开,可能是这个原因

今天笔记本连着手机热点在使用浏览器&#xff0c;突然百度的网页就打不开了&#xff0c;不管是百度一下、百家号、百度汉语、百度经验&#xff0c;只要是百度旗下的网页全都打不开,浏览器直接显示下图这个样子。但是别的网页都能正常打开。 然后我赶紧试了一下ping命令&#xf…

cnn突破五(三层bpnet网络公式)

三层网络反向传播公式推导&#xff1a; X【196】-》HI【80】/HO【80】-》YI【10】/YO【10】&#xff0c;期望是d【10】 X&#xff0c;HI之间用w1【196&#xff0c;80】 HO&#xff0c;YI之间用w2【80,10】 k10;j80;i196 (yo[k]-d[k])*ds(yo[k])*ho[j]; (yo[k]-d[k])*ds(yo[…

推荐一款强大的书签管理工具,让你的网址不在落灰

在信息爆炸的互联网时代&#xff0c;我们每天都会浏览大量的网页&#xff0c;收藏各种各样的网址。然而&#xff0c;随着时间的推移&#xff0c;这些杂乱无章的书签往往让我们感到头疼。别担心&#xff0c;今天我要向你推荐一款强大的书签管理工具&#xff0c;它将帮助你轻松整…

训练验证器解决数学应用题

人工智能咨询培训老师叶梓 转载标明出处 数学问题解决不仅要求模型能够理解问题的语言表述&#xff0c;还要求其能够准确地执行一系列数学运算&#xff0c;每一步的准确性都至关重要。遗憾的是&#xff0c;现有的语言模型在这一领域的性能远远未能达到人类的水平&#xff0c;它…

小绿书开启副业模式(保姆级教程)

大家好&#xff0c;我是凡人。 是一个不黑、不吹、不跟风、有知识、有骨气的五好小号主。 好多小伙伴给我私信&#xff0c;问我有最近没有非常火爆的副业项目&#xff0c;现在很多赛道人满为患&#xff0c;有没有值得推荐的&#xff0c;别说还真有&#xff0c;可能大家都没注…

理解Spring中静态代理

参考https://blog.csdn.net/weixin_43005654/article/details/109317773 无论是静态代理还是动态代理&#xff0c;都有四大角色&#xff1a; 抽象角色&#xff1a;一般会使用接口或者抽象类来解决真实角色&#xff1a;被代理的角色代理角色&#xff1a;代理真实角色&#xff0…

ultralytics yolo pose 示例:加载官方pose模型进行推理

Ultralytics YOLO 是计算机视觉和 ML 领域专业人士的高效工具。 安装 ultralytics 库&#xff1a; pip install ultralytics 官方YoLo Pose 模型列表信息&#xff1a; 实现代码如下&#xff1a; from ultralytics import YOLO import cv2 # Load a model ckpt_dir "…

基于PHP的校园二手书交易管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的校园二手书交易管理系统 一 介绍 此二手书交易管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈&#xff1a;phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注…

3. BBP系列运动控制板(飞控板)简介

3.1. 概述 Bread Board Pilot(简称BBP) 是在积累了前期 Single Pilot 及 PH7 飞控板大量设计及使用经验的基础上&#xff0c;全新基于PH47代码框架开发的高灵活性&#xff0c; 高性能&#xff0c; 超低成本的最新一代飞控板设计。 目前&#xff0c;因为其使用便捷灵活&#xf…

D30【python 接口自动化学习】- python基础之输入输出与文件操作

day30 F-strings输出 学习日期&#xff1a;20241007 学习目标&#xff1a;输入输出与文件操作&#xfe63;-42 F-strings-如何通过定义好的格式进行输出&#xff1f; 学习笔记&#xff1a; F-strings 介绍 F-strings 的计算功能 F-strings 宽度和精度调整 练习 # 宽度为10个…

【计算机网络 - 基础问题】每日 3 题(二十九)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

platformio.ini工程配置文件入门

主要参考资料&#xff1a; “platformio.ini” (Project Configuration File): https://docs.platformio.org/en/latest/projectconf/index.html 目录 简介语法[platformio]: PlatformIO配置选项[env]:配置环境 简介 .ini是一个配置文件&#xff0c;它可以设置开发环境&#x…

4.循环结构在存储过程中的应用(4/10)

引言 在数据库管理中&#xff0c;存储过程是一种强大的工具&#xff0c;它允许将一组SQL语句封装为一个独立的、可重用的单元。存储过程不仅可以提高数据处理的效率&#xff0c;还可以增强代码的安全性和可维护性。在复杂的数据库操作中&#xff0c;循环结构扮演着至关重要的角…

面试系列-淘天提前批面试

00-淘天提前批面试 在牛客上看到了淘天提前批的面试题目&#xff0c;这里分析一下淘天面试的问了有哪些内容&#xff0c;面试的重点 是偏向哪些方面 项目相关 1、秒杀架构如何设计&#xff1f; 问了秒杀的架构如何设计&#xff0c;对于秒杀的设计&#xff0c;秒杀符合 写多读少…

【cpp/c++ summary 工具】Visual Studio 2022 安装与cmake项目配置

Visual Studio 2022安装 https://visualstudio.microsoft.com/zh-hans/free-developer-offers/下载后选择c桌面开发安装即可&#xff1a; Visual Studio 2022创建cmake项目 Visual Studio 2022打开cmake项目 点击打开带有cmakelists.txt的项目文件夹 配置缓存&#xff1a;点…

【操作系统考研】2进程管理(1)

在翻看操作系统知识框架的时候&#xff0c;对一些概念的理解还比较模糊&#xff0c;现在我来理清他们的关系。 操作系统、处理器、进程、线程、内存、存储器、设备、文件的关系 咱们可以把计算机系统想象成一个大工厂&#xff0c;来理解这些概念之间的关系。 操作系统&#xf…