pytorch 学习笔记之编写 C 扩展,又涨姿势了

pytorch利用CFFI 进行 C 语言扩展。包括两个基本的步骤(docs):

  1. 编写 C 代码;
  2. python 调用 C 代码,实现相应的 Function 或 Module。

在之前的文章中,我们已经了解了如何自定义 Module。至于 [py]torch 的 C 代码库的结构,我们留待之后讨论; 这里,重点关注,如何在 pytorch C 代码库高层接口的基础上,编写 C 代码,以及如何调用自己编写的 C 代码。

官方示例了如何定义一个加法运算(见 repo)。这里我们定义ReLU函数(见 repo)。

1. C 代码

pytorch C 的基本数据结构是 THTensor(THFloatTensor、THByteTensor等)。我们以简单的 ReLU 函数为例,示例编写 C 。

y=ReLU(x)=max(x,0)

Function 需要定义前向和后向两个方向的操作,因此,C 代码要实现相应的功能。

1.1 头文件声明

/* ext_lib.h */
int relu_forward(THFloatTensor *input, THFloatTensor *output);
int relu_backward(THFloatTensor *grad_output, THFloatTensor *input, THFloatTensor *grad_input);

1.2 函数实现

TH/TH.h 包括了 pytorch C 代码数据结构和函数的声明,这是唯一需要添加的 include 依赖。

/* ext_lib.c */

#include <TH/TH.h>

int relu_forward(THFloatTensor *input, THFloatTensor *output)
{
  THFloatTensor_resizeAs(output, input);
  THFloatTensor_clamp(output, input, 0, INFINITY);
  return 1;
}

int relu_backward(THFloatTensor *grad_output, THFloatTensor *input, THFloatTensor *grad_input)
{
  THFloatTensor_resizeAs(grad_input, grad_output);
  THFloatTensor_zero(grad_input);

  THLongStorage* size = THFloatTensor_newSizeOf(grad_output);
  THLongStorage *stride = THFloatTensor_newStrideOf(grad_output);
  THByteTensor *mask = THByteTensor_newWithSize(size, stride);

  THFloatTensor_geValue(mask, input, 0);
  THFloatTensor_maskedCopy(grad_input, mask, grad_output);
  return 1;
}

2. 编译代码

2.1 依赖

由于 pytorch 的代码是纯 C 的,因此没有过多的依赖,只需要安装:

  • pytorch - 安装方法见官网
  • cffi - pip install cffi

编译文件非常简单,主要是添加头文件和实现文件,以及相关的宏定义; 同时文件还指定了编译后的调用位置(此外为_ext.ext_lib):

# build.py
import os
import torch
from torch.utils.ffi import create_extension

sources = [‘src/ext_lib.c‘]
headers = [‘src/ext_lib.h‘]
defines = []
with_cuda = False

if torch.cuda.is_available():
    print(‘Including CUDA code.‘)
    sources += [‘src/ext_lib_cuda.c‘]
    headers += [‘src/ext_lib_cuda.h‘]
    defines += [(‘WITH_CUDA‘, None)]
    with_cuda = True

ffi = create_extension(
    ‘_ext.ext_lib‘,
    headers=headers,
    sources=sources,
    define_macros=defines,
    relative_to=__file__,
    with_cuda=with_cuda
)

if __name__ == ‘__main__‘:
    ffi.build()
python build.py

3. python 调用

3.1 编写配置文件

python 的调用非常简单——pytorch 的 tensor 对象,对应 C 代码的 THTensor 对象,以此作参数进行调用即可。配置文件如下:

import torch
from torch.autograd import Function
from _ext import ext_lib

class ReLUF(Function):
    def forward(self, input):
        self.save_for_backward(input)

        output = input.new()
        if not input.is_cuda:
            ext_lib.relu_forward(input, output)
        else:
            raise Exception, "No CUDA Implementation"
        return output

    def backward(self, grad_output):
        input, = self.saved_tensors

        grad_input = grad_output.new()
        if not grad_output.is_cuda:
            ext_lib.relu_backward(grad_output, input, grad_input)
        else:
            raise Exception, "No CUDA Implementation"
        return grad_input

3.2 测试

此处省略 Module 的定义。下面测试下新定义的基于 C 的 ReLU 函数。

import torch
import torch.nn as nn
from torch.autograd import Variable

from modules.relu import ReLUM

torch.manual_seed(1111)

class MyNetwork(nn.Module):
    def __init__(self):
        super(MyNetwork, self).__init__()
        self.relu = ReLUM()

    def forward(self, input):
        return self.relu(input)

model = MyNetwork()
x = torch.randn(1, 25).view(5, 5)
input = Variable(x, requires_grad=True)
output = model(input)
print(output)
print(input.clamp(min=0))

output.backward(torch.ones(input.size()))
print(input.grad.data)

输出结果如下:

Variable containing:
 0.8749  0.5990  0.6844  0.0000  0.0000
 0.6516  0.0000  1.5117  0.5734  0.0072
 0.1286  1.4171  0.0796  1.0355  0.0000
 0.0000  0.0000  0.0312  0.0999  0.0000
 1.0401  1.0599  0.0000  0.0000  0.0000
[torch.FloatTensor of size 5x5]

Variable containing:
 0.8749  0.5990  0.6844  0.0000  0.0000
 0.6516  0.0000  1.5117  0.5734  0.0072
 0.1286  1.4171  0.0796  1.0355  0.0000
 0.0000  0.0000  0.0312  0.0999  0.0000
 1.0401  1.0599  0.0000  0.0000  0.0000
[torch.FloatTensor of size 5x5]

 1  1  1  0  0
 1  0  1  1  1
 1  1  1  1  0
 0  0  1  1  0
 1  1  0  0  0

原文出自腾讯云技术社区

原文链接https://www.qcloud.com/community/article/314920

 
时间: 2024-10-15 23:44:01

pytorch 学习笔记之编写 C 扩展,又涨姿势了的相关文章

Hadoop学习笔记(5) ——编写HelloWorld(2)

Hadoop学习笔记(5) ——编写HelloWorld(2) 前面我们写了一个Hadoop程序,并让它跑起来了.但想想不对啊,Hadoop不是有两块功能么,DFS和MapReduce.没错,上一节我们写了一个MapReduce的HelloWorld程序,那这一节,我们就也学一学DFS程序的编写. DFS是什么,之前已经了解过,它是一个分布式文件存储系统.不管是远程或本地的文件系统,其实从接口上讲,应该是一至的,不然很难处理.同时在第2节的最后,我们列出了很多一些DFS的操作命令,仔细看一下,这

DuiLib学习笔记(二) 扩展CScrollbar属性

DuiLib学习笔记(二) 扩展CScrollbar属性 Duilib的滚动条滑块默认最小值为滚动条的高度(HScrollbar)或者宽度(VScrollbar).并且这个值默认为16.当采用系统样式的滚动条,或者 Troy的源码(https://github.com/qdtroy/DuiLib_Ultimate)自带的样式时,是没有问题的,因为这两种样式默认高(宽)度都是16,当滑块最小时,也有16*16,背景图片(九宫格式)不会出拉伸BUG.但是,当自定义背景图片时,如果图片本身大小超过16

[简明python教程]学习笔记之编写简单备份脚本

[[email protected] 0503]# cat backup_ver3.py #!/usr/bin/python #filename:backup_ver3.py import os import time #source source=['/root/a.sh','/root/b.sh','/root/c.sh'] #source='/root/c.sh' #backup dir target_dir='/tmp/' today=target_dir+time.strftime('

Linux 程序设计学习笔记----动手编写makefile文件

Befroe Beginning. 之前定了暑假的plan ,关于Linux的书籍现在在看的是ALP和Linux高级程序设计(杨宗德)第三版.在计划中的是Linux高级环境编程. 现在开始关于Linux程序设计的第一篇学习笔记. 本来打算把名字写成教程,不过觉得自己完全是新手在自学,还是写学习笔记比较负责和适合. 希望可以一起学习进步. 引入 首先我们假设这样一个场景.我们有一个程序包含了三个文件,分别是源码文件main_plus,c和function_plus.c以及头文件mydefine_p

Swift 学习笔记十五:扩展

扩展就是向一个已有的类.结构体或枚举类型添加新功能(functionality).扩展和 Objective-C 中的分类(categories)类似.(不过与Objective-C不同的是,Swift 的扩展没有名字.) Swift 中的扩展可以: 1.添加计算型属性和计算静态属性 2.定义实例方法和类型方法 3.提供新的构造器 4.定义下标 5.定义和使用新的嵌套类型 6.使一个已有类型符合某个协议 一.扩展属性,构造器,方法 class Human{ var name:String? va

PyTorch学习笔记之nn的简单实例

method 1 1 import torch 2 from torch.autograd import Variable 3 4 N, D_in, H, D_out = 64, 1000, 100, 10 5 x = Variable(torch.randn(N, D_in)) 6 y = Variable(torch.randn(N, D_out), requires_grad=False) 7 8 # define our model as a sequence of layers 9 m

ES6学习笔记二:各种扩展

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7242967.html 一:字符串扩展 二:正则的扩展 三:Number的扩展 四:函数扩展 五:数组扩展 六:对象扩展

Objective-C学习笔记_类的扩展

一Category的定义和使用 二Extension的定义和使用 三Protocol的定义和使用 delegate的使用 一.Category的定义和使用 Category,分类或类目.主要作用是为没有源代码的类添加方法.通过Category添加的方法会成为原类的一部分.从而达到扩展一个类的功能. 定义Category过程 新建?件 选择Objective-C Category模板 填写类名和分类名 .h?件添加?法声明 .m添加?法实现 Category的声明 NSString+SayHi.h

20170721 PyTorch学习笔记之计算图

1. **args, **kwargs的区别 1 def build_vocab(self, *args, **kwargs): 2 counter = Counter() 3 sources = [] 4 for arg in args: 5 if isinstance(arg, Dataset): 6 sources += [getattr(arg, name) for name, field in 7 arg.fields.items() if field is self] 8 else: