由于工作需要,目前需要融合两个模型,但是两个模型的框架完全不一样,一个是pytorch一个是keras。头疼。
目前有两个确认可行的方案。

方案一:将其中一者的模型转化为另一框架,然后进行融合。遇到的问题在于两个模型都有预训练模型,所以如果这样的转换,模型可以复现,但是训练的参数怎么办呢?难道又要重新训练吗?

方案二:将一种一者的输出结果保存为h5,因为两个模型只是作为特征提取,而本身并不参与新模型的反向传播。但是问题在于,数据多了h5也多,而且非常不方便新模型的参数调整。

但是就在做这个工作一个月后出现了tfpyth. 或许有希望吧。所以记录下tfpyth的代码学习,看看别人是如何进行转换的。

def test_pytorch_in_tensorflow_eager_mode():tf.enable_eager_execution()tfe = tf.contrib.eagerdef pytorch_expr(a, b):return 3 * a + 4 * b * bx = tfpyth.eager_tensorflow_from_torch(pytorch_expr)assert tf.math.equal(x(tf.convert_to_tensor(1.0), tf.convert_to_tensor(3.0)), 39.0)dx = tfe.gradients_function(x)assert all(tf.math.equal(dx(tf.convert_to_tensor(1.0), tf.convert_to_tensor(3.0)), [3.0, 24.0]))tf.disable_eager_execution()

x = tfpyth.eager_tensorflow_from_torch(pytorch_expr) ,输入的是是一个函数。

**def eager_tensorflow_from_torch(func):"""Wraps a PyTorch function into a TensorFlow eager-mode function (ie can be executed within Tensorflow eager-mode).:param func: Function that takes PyTorch tensors and returns a PyTorch tensor.:return: Differentiable Tensorflow eager-mode function."""@tf.custom_gradientdef compute(*inputs):th_inputs = [th.tensor(tf_input.numpy(), requires_grad=True) for tf_input in inputs]th_output = func(*th_inputs)#输入的是tensorflow下的tensor, 先转化为pytorch下的tensor#经过func也就是前面的pytorch_expr,然后输出的也是pytorch 的tensor。def compute_grad(d_output):th_d_output = th.tensor(d_output.numpy(), requires_grad=False)th_gradients = th.autograd.grad([th_output], th_inputs, grad_outputs=[th_d_output], allow_unused=True)tf_gradients = [tf.convert_to_tensor(th_gradient.numpy()) for th_gradient in th_gradients]return tf_gradientsreturn tf.convert_to_tensor(th_output.detach().numpy()), compute_gradreturn compute**

这里的输出是 把上面的th_output 进行处理,先是detach 然后是numpy转化为tf.tensor 进行输出。之前融合的时候也遇到这样的问题,将dataloader出来的tensor转化为numpy输入到模型中。但是有一个问题是:tensor和numpy的转换只能支持cpu下面的,也就是gpu下的cuda下的是不能转化的。GPU tensor不能直接转为numpy数组,必须先转到CPU tensor。

这里加了detach()所以断了上面的function出来的东西,不让他提供反向传播,然后转化为numpy接着用tf.convert_to_tensor转化为tensorflow支持的tensor。也就是不反向传播进入pytorch的模型,pytorch的模型仅仅是一个函数作用。反向传播的应该是输入与输出。

~~ torch.Tensor.detach()的使用**~~ **

detach()的官方说明如下:
Returns a new Tensor, detached from the current graph. The result will never
require gradient.
假设有模型A和模型B,我们需要将A的输出作为B的输入,但训练时我们只训练模型B. 那么可以这样做:

input_B = output_A.detach()

它可以使两个计算图的梯度传递断开,从而实现我们所需的功能。

上面的输出还有一个compute_grad
首先将输入的numpy转化为torch形式下的tensor,
然后使用了pytorch的th.autograd.grad 输入的参数有四个:前面两个是刚刚的输入与输出[th_output], th_inputs, 第三个是刚刚的numpy转化为tensor的grad_outputs=[th_d_output]。先看看th.autograd.grad的作用。https://blog.csdn.net/qq_36556893/article/details/91982925 https://zhuanlan.zhihu.com/p/29904755 作为反向传播的梯度计算问题。 这里讲了具体的。其实作用就是output对input的求导,梯度的本身就是导数,而grad_outputs=[th_d_output],只是权重的weight的作用。返回的结果是输出对输入的梯度计算。梯度计算的结果仔进一步转化为tf.tensor的格式。

def eager_tensorflow_from_torch(func): 思路逻辑图是这样的。相当于tensorflow的tensor走了一遍pytorch的函数,最后给出的还是tensorflow的tensor。


从BP的角度看思路的话是这样的。也就是前面说的一样,这一点应该是这个函数的重要思想,讲pytorch的模型作为函数的作用,但是不对模型的内部进行反向的传播。也就是当作是一个函数。而实际上从外面看就是一个输出对一个输入的BP而已。

def test_pytorch_in_tensorflow_graph_mode():session = tf.Session()def pytorch_expr(a, b):return 3 * a + 4 * b * ba = tf.placeholder(tf.float32, name="a")b = tf.placeholder(tf.float32, name="b")c = tfpyth.tensorflow_from_torch(pytorch_expr, [a, b], tf.float32)c_grad = tf.gradients([c], [a, b], unconnected_gradients="zero")assert np.allclose(session.run([c, c_grad[0], c_grad[1]], {a: 1.0, b: 3.0}), [39.0, 3.0, 24.0])

所以上述的应该是在tensorflow图中加入pytorch 模型作为函数一部分。上面是一个例子

接下里啊看另一种:pytorch图中加入

方法:torch_from_tensorflow(tf_session, tf_inputs, tf_output, tf_dtype=tf.float32)
输入包括了tensorflow的session,tensorflow的input,tensorflow的output 以及处理的过程。所以这里对应了我们的几个部分。

这次我们从例子开始看:首先是输入的数值是pytorch的tensor
a_ = th.tensor(1, dtype=th.float32, requires_grad=True)
b_ = th.tensor(3, dtype=th.float32, requires_grad=True)
思考这里是符合我们的模型的dataloader的部分,dataloader输出的也是tensor,一组组的tensor。接着输入到get_tf_function中。这里的话是tensorflow的模型,也就是相当于我们的模型,其中c是函数的output,session是tensorflow的session。

def test_tensorflow_in_pytorch():session = tf.Session()def get_tf_function():a = tf.placeholder(tf.float32, name="a")b = tf.placeholder(tf.float32, name="b")c = 3 * a + 4 * b * bf = tfpyth.torch_from_tensorflow(session, [a, b], c).applyreturn ff = get_tf_function()a_ = th.tensor(1, dtype=th.float32, requires_grad=True)b_ = th.tensor(3, dtype=th.float32, requires_grad=True)x = f(a_, b_)assert x == 39.0x.backward()

这里我们看 def torch_from_tensorflow(tf_session, tf_inputs, tf_output, tf_dtype=tf.float32):里面使用了pytorch的th.autograd.Function,所以需要先看懂这个连接 https://zhuanlan.zhihu.com/p/27783097 可以感受到了两个框架在整个前向传播和反向传播中是不同的。

def torch_from_tensorflow(tf_session, tf_inputs, tf_output, tf_dtype=tf.float32):"""Create a PyTorch TensorFlowFunction with forward and backward methods which executes evaluates the passedTensorFlow tensors.```pythonmy_tensorflow_func = MyTensorFlowFunction.applyresult = my_tensorflow_func(th_a, th_b)```:param tf_session: TensorFlow session to use:param tf_inputs: TensorFlow input tensors/placeholders:param tf_output: TensorFlow output tensor:param tf_dtype: dtype to use for gradient placeholder.:return: TensorflowFunction which can be applied to PyTorch tensors."""# create gradient placeholderstf_gradient_placeholder = tf.placeholder(dtype=tf_dtype, name=f"gradient")tf_gradient_outputs = tf.gradients(ys=tf_output, xs=tf_inputs, grad_ys=[tf_gradient_placeholder], unconnected_gradients="zero")#定义了gradient,是tf的gradientclass _TensorFlowFunction(TensorFlowFunction):inputs = tf_inputs output = tf_outputgradient_placeholder = tf_gradient_placeholdergradient_outputs = tf_gradient_outputs@staticmethoddef forward(ctx, *args):assert len(args) == len(tf_inputs)feed_dict = {tf_input: th_input.detach().numpy() for tf_input, th_input in zip(tf_inputs, args)} #外面输入的output = tf_session.run(tf_output, feed_dict)ctx.save_for_backward(*args)th_output = th.as_tensor(output)return th_output# See https://www.janfreyberg.com/blog/2019-04-01-testing-pytorch-functions/ for why "no cover"@staticmethoddef backward(ctx, grad_output): # pragma: no coverth_inputs = ctx.saved_tensorsfeed_dict = {}feed_dict.update({tf_input: th_input.detach().numpy() for tf_input, th_input in zip(tf_inputs, th_inputs)})feed_dict.update({tf_gradient_placeholder: grad_output.detach().numpy()})tf_gradients = tf_session.run(tf_gradient_outputs, feed_dict)return tuple(th.as_tensor(tf_gradient) for tf_gradient in tf_gradients)return _TensorFlowFunction()

小武与tfpyth的碰撞----torch.autograd.Function进阶版本相关推荐

  1. Pytorch的自定义拓展:torch.nn.Module和torch.autograd.Function

    参考链接:pytorch的自定义拓展之(一)--torch.nn.Module和torch.autograd.Function_LoveMIss-Y的博客-CSDN博客_pytorch自定义backw ...

  2. 使用torch.autograd.function解决dist.all_gather不能反向传播问题

    1. 问题来源 最近在用mmcv复现Partial FC模型,看到源码中,有单独写的前向反向传播,甚是疑惑- 源码: # Features all-gather total_features = to ...

  3. 自定义autograd function

    在TSN代码中, segmentconsensus是一个自定义函数, 所以要写一下它对应的梯度运算 # tj : https://blog.csdn.net/tsq292978891/article/ ...

  4. Pytorch使用autograd.Function自定义拓展神经网络

    我们知道CNN这类人工神经网络都基于BP算法进行优化,因此需要误差关于权重是连续可导的,这是可以运用BP算法的前提条件:也有一些网络不满足这个条件. 1.可导 对于可连续求导的神经网络构建时采用nn. ...

  5. RuntimeError: Legacy autograd function with non-static forward method is deprecated.

    显卡RTX3080 cuda 11.1 cudnn 8.0.5 python3.6.4 在使用pytorch1.0训练densefusion模型时报错,改用pytorch1.7,然后报上面的错误 Tr ...

  6. pytorch 笔记: 扩展torch.autograd

    1 扩展torch.autograd 向 autograd 添加操作需要为每个操作实现一个新的 Function 子类. 回想一下,函数是 autograd 用来编码操作历史和计算梯度的东西. 2 何 ...

  7. PyTorch 1.0 中文文档:torch.autograd

    译者:gfjiangly torch.autograd 提供类和函数,实现任意标量值函数的自动微分. 它要求对已有代码的最小改变-你仅需要用requires_grad=True关键字为需要计算梯度的声 ...

  8. torch.autograd.grad求二阶导数

    1 用法介绍  pytorch中torch.autograd.grad函数主要用于计算并返回输出相对于输入的梯度总和,具体的参数作用如下所示: torch.tril(input, diagonal=0 ...

  9. 小武告诉滨滨每天可以吃一块或者两块巧克力。假设滨滨每天都吃巧克力,问滨滨共有多少种不同的吃完巧克力的方案。

    [题目描述] 2013年12月8日,ACM俱乐部的小武代表学校参加了在吉林大学举办的第38届ACM国际大学生程序设计竞赛现场赛,返校时带了一盒好吃又精美的巧克力给滨滨(盒内共有 N 块巧克力,20 & ...

  10. pytorch基础-使用 TORCH.AUTOGRAD 进行自动微分(5)

    在训练神经网络时,最常用的算法是反向传播.PyTorch的反向传播(即tensor.backward())是通过autograd包来实现的,autograd包会根据tensor进行过的数学运算来自动计 ...

最新文章

  1. 公开课报名 | 那些年,我们在文本分类中遇到的坑
  2. desc mysql 连表查询_Mysql连表查询
  3. Linux系统工程师的必备素质
  4. .net你不行——是你的父亲把你封装的太死,还是你的子孙们太懒,未把你发扬光大。...
  5. 扫描过程_高考试卷扫描、阅卷过程以及答题过程注意的事项
  6. 请问如何把.net framework框架集成在安装程序里头?
  7. WebClient UI忽略所有增强的开关
  8. [机器视觉] SIFT特征-尺度不变特征理解
  9. laravel简单的laragon环境搭建不需要composer一键集成
  10. 贝叶斯定理到贝叶斯滤波器
  11. Wilcoxon Signed-Rank Test
  12. asp.net 安全
  13. AceAdmin In MVC之控件
  14. 两款Java中小医院信息管理系统源码
  15. 关于小波分解的滤波器理解
  16. 创建型模式之简单工厂模式
  17. MySQL相关知识整理
  18. 2021年高处安装、维护、拆除证考试及高处安装、维护、拆除复审模拟考试
  19. [人工智能-深度学习-4]:数据流图与正向传播、动态图与静态图
  20. 时间序列中季节性和非季节_在2019年会议季节生存的19个技巧

热门文章

  1. MacOS上符号执行模块angr和z3-solver模块的安装
  2. 九阴真经 服务器列表文件,九阴真经合服_九阴真经数据互通_九阴真经公告_快吧游戏...
  3. 阿里巴巴矢量图库,图标导入的简单使用
  4. Qt 之 Concurrent Run
  5. FSDB Dumper
  6. 四大国际反垃圾邮件组织介绍
  7. 浏览器标准模式和怪异模式之间的区别是什么?
  8. 《走出软件作坊》51:幽幽一缕香
  9. linux下upupw搭建教程,UPUPW全能空间搭建----easypanel面板
  10. 走近图灵奖大师David Patterson开挂的人生