【问题标题】:Gpu processing R (How to use Gpu processing to run a function on subsets of a dataset)Gpu processing R(如何使用 Gpu 处理在数据集的子集上运行函数)
【发布时间】:2019-01-20 19:29:49
【问题描述】:

我有一个大型数据集(大约 500 万个观察值)。观察记录了由“类型”表示的不同类型的子事件的特定事件的总收入。数据的小复制如下:

Event_ID = c(1,1,1,1,1,2,2,2,2,2,3,3,3,3)
Type=c("A","B","C","D","E","A","B","C","D","E","A","B","C","D")
Revenue1=c(24,9,51,7,22,15,86,66,0,57,44,93,34,37)
Revenue2=c(16,93,96,44,67,73,12,65,81,22,39,94,41,30)
z = data.frame(Event_ID,Type,Revenue1,Revenue2)

我想使用 GPU 内核来运行我编写的函数(我从未尝试过 GPU 处理,所以完全不知道如何开始)。实际功能需要很长时间才能运行。我在下面展示了一个非常简单的函数版本:

Total_Revenue=function(data){
  full_list=list()
  event_list=unique(data[,'Event_ID'])
  for (event in event_list){
    new_data=list()
    event_data = data[which(data$Event_ID==event),]
    for (i in 1:nrow(event_data)){
      event_data[i,'Total_Rev'] = event_data[i,'Revenue1']+event_data[i,'Revenue2'] 
      new_data=rbind(new_data,event_data[i,])
    }
  full_list=rbind(full_list,new_data)
  }
  return(full_list)
}

Total = Total_Revenue(data=z)
print(Total)

这个简化的版本功能如下:

a) 将数据集分解为子集,使得每个子集仅包含 1 个唯一事件。

b)对于每个观察,循环遍历所有观察并计算收入 1+收入 2。

c) 存储子集,最后返回新数据集。

由于我之前没有经验,所以我正在研究一些 R 包。我找到了 gpuR 包并安装了它。 但是,我很难理解如何实现它。另外问题是我的编码背景非常薄弱。在过去的一年里,我自学了一些东西。

任何帮助/线索将不胜感激。我也愿意使用任何替代包。如果我遗漏了什么,请告诉我。

附:我还使用以下命令对我的系统进行了快照:

str(gpuInfo())

我附上输出供您参考:

附言请注意,我的实际功能有点复杂和冗长,运行需要很长时间,这就是我想在这里实现 gpu 处理的原因。

【问题讨论】:

    标签: r gpu


    【解决方案1】:

    GPU 编程不是灵丹妙药。它仅适用于某些问题。这就是为什么gpuR 包提供了 GPU 基向量和矩阵,允许使用 GPU 完成线性代数运算。如果您的问题不是线性代数问题,这将无济于事。但是,请注意,许多问题都可以通过这种方式表述

    我们无法判断您的问题是否属于这一类,因为您(可能)过度简化了代码:

    > print(Total)
       Event_ID Type Revenue1 Revenue2 Total_Rev
    1         1    A       24       16        40
    2         1    B        9       93       102
    3         1    C       51       96       147
    4         1    D        7       44        51
    5         1    E       22       67        89
    6         2    A       15       73        88
    7         2    B       86       12        98
    8         2    C       66       65       131
    9         2    D        0       81        81
    10        2    E       57       22        79
    11        3    A       44       39        83
    12        3    B       93       94       187
    13        3    C       34       41        75
    14        3    D       37       30        67
    

    由于Total_Rev 只是Revenue1Revenue2 的总和,您可以更轻松地做到这一点:

    > z$Total_Rev <- z$Revenue1 + z$Revenue2
    > z
       Event_ID Type Revenue1 Revenue2 Total_Rev
    1         1    A       24       16        40
    2         1    B        9       93       102
    3         1    C       51       96       147
    4         1    D        7       44        51
    5         1    E       22       67        89
    6         2    A       15       73        88
    7         2    B       86       12        98
    8         2    C       66       65       131
    9         2    D        0       81        81
    10        2    E       57       22        79
    11        3    A       44       39        83
    12        3    B       93       94       187
    13        3    C       34       41        75
    14        3    D       37       30        67
    

    这是一种简单的矢量化形式,可帮助您摆脱(一些)for 循环。而且由于您的外部for 循环查看不同的Event_ID,因此研究分组和聚合技术也可能有意义。这些可以使用基础 R、data.table 包、tidyverse/dplyr 和可能的其他工具来完成。我正在使用后一种方法,因为我喜欢它的语法对新手最友好。但是,如果您有大型数据集,data.table 可能是适合您的工具。所以这里有一个非常简单的聚合,计算每个Event_ID 的平均值:

    Event_ID = c(1,1,1,1,1,2,2,2,2,2,3,3,3,3)
    Type=c("A","B","C","D","E","A","B","C","D","E","A","B","C","D")
    Revenue1=c(24,9,51,7,22,15,86,66,0,57,44,93,34,37)
    Revenue2=c(16,93,96,44,67,73,12,65,81,22,39,94,41,30)
    z = data.frame(Event_ID,Type,Revenue1,Revenue2)
    
    library(dplyr)
    z %>%
      mutate(Total_Rev = Revenue1 + Revenue2) %>%
      group_by(Event_ID) %>%
      summarise(average = mean(Total_Rev))
    #> # A tibble: 3 x 2
    #>   Event_ID average
    #>      <dbl>   <dbl>
    #> 1        1    85.8
    #> 2        2    95.4
    #> 3        3   103
    

    【讨论】:

    • 感谢您的评论。我承认我不太了解 GPU 处理(或者你完全可以说)。不幸的是,我的问题不是简单的线性代数运算。还是谢谢你。是否有 R 包或其他方式可以分解大型操作并在单个 GPU 内核上运行它?不幸的是,除了矩阵乘法(这不是我想做的)之外,我找不到任何示例。你是对的,因为我可能过度简化了我的问题。我很抱歉。我想了解如何使用 GPU 在大数据集的子集上运行操作。
    • @Prometheus 请注意,使用 GPU 的主要效率提升来自于所有内核同步运行。也就是说,它们使用不同的数据执行完全相同的指令。我不确定您的用例是否具有这种形式。从您写的内容来看,这听起来更像是一个聚合问题。这可以使用data.table 有效地解决,参见例如stackoverflow.com/a/53366310/8416610.
    • 是的,你是对的。这就是为什么我确保每个事件的“操作”一次运行一个。我相信这被称为令人尴尬的并行过程。 “操作”不是我在这里展示的简单聚合。为了说明的目的,“操作”被简化了。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 2019-11-14
    • 2018-09-08
    相关资源
    最近更新 更多