亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Python > 正文

TensorFlow實現自定義Op方式

2020-02-15 21:25:46
字體:
來源:轉載
供稿:網友

『寫在前面』

以CTC Beam search decoder為例,簡單整理一下TensorFlow實現自定義Op的操作流程。

基本的流程

1. 定義Op接口

#include "tensorflow/core/framework/op.h" REGISTER_OP("Custom")    .Input("custom_input: int32")  .Output("custom_output: int32");

2. 為Op實現Compute操作(CPU)或實現kernel(GPU)

#include "tensorflow/core/framework/op_kernel.h" using namespace tensorflow; class CustomOp : public OpKernel{  public:  explicit CustomOp(OpKernelConstruction* context) : OpKernel(context) {}  void Compute(OpKernelContext* context) override {  // 獲取輸入 tensor.  const Tensor& input_tensor = context->input(0);  auto input = input_tensor.flat<int32>();  // 創建一個輸出 tensor.  Tensor* output_tensor = NULL;  OP_REQUIRES_OK(context, context->allocate_output(0, input_tensor.shape(),                           &output_tensor));  auto output = output_tensor->template flat<int32>();  //進行具體的運算,操作input和output  //…… }};

3. 將實現的kernel注冊到TensorFlow系統中

REGISTER_KERNEL_BUILDER(Name("Custom").Device(DEVICE_CPU), CustomOp);

CTCBeamSearchDecoder自定義

該Op對應TensorFlow中的源碼部分

Op接口的定義:

tensorflow-master/tensorflow/core/ops/ctc_ops.cc

CTCBeamSearchDecoder本身的定義:

tensorflow-master/tensorflow/core/util/ctc/ctc_beam_search.cc

Op-Class的封裝與Op注冊:

tensorflow-master/tensorflow/core/kernels/ctc_decoder_ops.cc

基于源碼修改的Op

#include <algorithm>#include <vector>#include <cmath> #include "tensorflow/core/util/ctc/ctc_beam_search.h" #include "tensorflow/core/framework/op.h"#include "tensorflow/core/framework/op_kernel.h"#include "tensorflow/core/framework/shape_inference.h"#include "tensorflow/core/kernels/bounds_check.h" namespace tf = tensorflow;using tf::shape_inference::DimensionHandle;using tf::shape_inference::InferenceContext;using tf::shape_inference::ShapeHandle; using namespace tensorflow; REGISTER_OP("CTCBeamSearchDecoderWithParam")  .Input("inputs: float")  .Input("sequence_length: int32")  .Attr("beam_width: int >= 1")  .Attr("top_paths: int >= 1")  .Attr("merge_repeated: bool = true")  //新添加了兩個參數  .Attr("label_selection_size: int >= 0 = 0")   .Attr("label_selection_margin: float")   .Output("decoded_indices: top_paths * int64")  .Output("decoded_values: top_paths * int64")  .Output("decoded_shape: top_paths * int64")  .Output("log_probability: float")  .SetShapeFn([](InferenceContext* c) {   ShapeHandle inputs;   ShapeHandle sequence_length;    TF_RETURN_IF_ERROR(c->WithRank(c->input(0), 3, &inputs));   TF_RETURN_IF_ERROR(c->WithRank(c->input(1), 1, &sequence_length));    // Get batch size from inputs and sequence_length.   DimensionHandle batch_size;   TF_RETURN_IF_ERROR(     c->Merge(c->Dim(inputs, 1), c->Dim(sequence_length, 0), &batch_size));    int32 top_paths;   TF_RETURN_IF_ERROR(c->GetAttr("top_paths", &top_paths));    // Outputs.   int out_idx = 0;   for (int i = 0; i < top_paths; ++i) { // decoded_indices    c->set_output(out_idx++, c->Matrix(InferenceContext::kUnknownDim, 2));   }   for (int i = 0; i < top_paths; ++i) { // decoded_values    c->set_output(out_idx++, c->Vector(InferenceContext::kUnknownDim));   }   ShapeHandle shape_v = c->Vector(2);   for (int i = 0; i < top_paths; ++i) { // decoded_shape    c->set_output(out_idx++, shape_v);   }   c->set_output(out_idx++, c->Matrix(batch_size, top_paths));   return Status::OK();  }); typedef Eigen::ThreadPoolDevice CPUDevice; inline float RowMax(const TTypes<float>::UnalignedConstMatrix& m, int r,          int* c) { *c = 0; CHECK_LT(0, m.dimension(1)); float p = m(r, 0); for (int i = 1; i < m.dimension(1); ++i) {  if (m(r, i) > p) {   p = m(r, i);   *c = i;  } } return p;} class CTCDecodeHelper { public: CTCDecodeHelper() : top_paths_(1) {}  inline int GetTopPaths() const { return top_paths_; } void SetTopPaths(int tp) { top_paths_ = tp; }  Status ValidateInputsGenerateOutputs(   OpKernelContext* ctx, const Tensor** inputs, const Tensor** seq_len,   Tensor** log_prob, OpOutputList* decoded_indices,   OpOutputList* decoded_values, OpOutputList* decoded_shape) const {  Status status = ctx->input("inputs", inputs);  if (!status.ok()) return status;  status = ctx->input("sequence_length", seq_len);  if (!status.ok()) return status;   const TensorShape& inputs_shape = (*inputs)->shape();   if (inputs_shape.dims() != 3) {   return errors::InvalidArgument("inputs is not a 3-Tensor");  }   const int64 max_time = inputs_shape.dim_size(0);  const int64 batch_size = inputs_shape.dim_size(1);   if (max_time == 0) {   return errors::InvalidArgument("max_time is 0");  }  if (!TensorShapeUtils::IsVector((*seq_len)->shape())) {   return errors::InvalidArgument("sequence_length is not a vector");  }   if (!(batch_size == (*seq_len)->dim_size(0))) {   return errors::FailedPrecondition(     "len(sequence_length) != batch_size. ", "len(sequence_length): ",     (*seq_len)->dim_size(0), " batch_size: ", batch_size);  }   auto seq_len_t = (*seq_len)->vec<int32>();   for (int b = 0; b < batch_size; ++b) {   if (!(seq_len_t(b) <= max_time)) {    return errors::FailedPrecondition("sequence_length(", b, ") <= ",                     max_time);   }  }   Status s = ctx->allocate_output(    "log_probability", TensorShape({batch_size, top_paths_}), log_prob);  if (!s.ok()) return s;   s = ctx->output_list("decoded_indices", decoded_indices);  if (!s.ok()) return s;  s = ctx->output_list("decoded_values", decoded_values);  if (!s.ok()) return s;  s = ctx->output_list("decoded_shape", decoded_shape);  if (!s.ok()) return s;   return Status::OK(); }  // sequences[b][p][ix] stores decoded value "ix" of path "p" for batch "b". Status StoreAllDecodedSequences(   const std::vector<std::vector<std::vector<int> > >& sequences,   OpOutputList* decoded_indices, OpOutputList* decoded_values,   OpOutputList* decoded_shape) const {  // Calculate the total number of entries for each path  const int64 batch_size = sequences.size();  std::vector<int64> num_entries(top_paths_, 0);   // Calculate num_entries per path  for (const auto& batch_s : sequences) {   CHECK_EQ(batch_s.size(), top_paths_);   for (int p = 0; p < top_paths_; ++p) {    num_entries[p] += batch_s[p].size();   }  }   for (int p = 0; p < top_paths_; ++p) {   Tensor* p_indices = nullptr;   Tensor* p_values = nullptr;   Tensor* p_shape = nullptr;    const int64 p_num = num_entries[p];    Status s =     decoded_indices->allocate(p, TensorShape({p_num, 2}), &p_indices);   if (!s.ok()) return s;   s = decoded_values->allocate(p, TensorShape({p_num}), &p_values);   if (!s.ok()) return s;   s = decoded_shape->allocate(p, TensorShape({2}), &p_shape);   if (!s.ok()) return s;    auto indices_t = p_indices->matrix<int64>();   auto values_t = p_values->vec<int64>();   auto shape_t = p_shape->vec<int64>();    int64 max_decoded = 0;   int64 offset = 0;    for (int64 b = 0; b < batch_size; ++b) {    auto& p_batch = sequences[b][p];    int64 num_decoded = p_batch.size();    max_decoded = std::max(max_decoded, num_decoded);    std::copy_n(p_batch.begin(), num_decoded, &values_t(offset));    for (int64 t = 0; t < num_decoded; ++t, ++offset) {     indices_t(offset, 0) = b;     indices_t(offset, 1) = t;    }   }    shape_t(0) = batch_size;   shape_t(1) = max_decoded;  }  return Status::OK(); }  private: int top_paths_; TF_DISALLOW_COPY_AND_ASSIGN(CTCDecodeHelper);}; // CTC beam searchclass CTCBeamSearchDecoderWithParamOp : public OpKernel { public: explicit CTCBeamSearchDecoderWithParamOp(OpKernelConstruction* ctx) : OpKernel(ctx) {  OP_REQUIRES_OK(ctx, ctx->GetAttr("merge_repeated", &merge_repeated_));  OP_REQUIRES_OK(ctx, ctx->GetAttr("beam_width", &beam_width_));  //從參數列表中讀取新添的兩個參數  OP_REQUIRES_OK(ctx, ctx->GetAttr("label_selection_size", &label_selection_size));  OP_REQUIRES_OK(ctx, ctx->GetAttr("label_selection_margin", &label_selection_margin));  int top_paths;  OP_REQUIRES_OK(ctx, ctx->GetAttr("top_paths", &top_paths));  decode_helper_.SetTopPaths(top_paths); }  void Compute(OpKernelContext* ctx) override {  const Tensor* inputs;  const Tensor* seq_len;  Tensor* log_prob = nullptr;  OpOutputList decoded_indices;  OpOutputList decoded_values;  OpOutputList decoded_shape;  OP_REQUIRES_OK(ctx, decode_helper_.ValidateInputsGenerateOutputs(              ctx, &inputs, &seq_len, &log_prob, &decoded_indices,              &decoded_values, &decoded_shape));   auto inputs_t = inputs->tensor<float, 3>();  auto seq_len_t = seq_len->vec<int32>();  auto log_prob_t = log_prob->matrix<float>();   const TensorShape& inputs_shape = inputs->shape();   const int64 max_time = inputs_shape.dim_size(0);  const int64 batch_size = inputs_shape.dim_size(1);  const int64 num_classes_raw = inputs_shape.dim_size(2);  OP_REQUIRES(    ctx, FastBoundsCheck(num_classes_raw, std::numeric_limits<int>::max()),    errors::InvalidArgument("num_classes cannot exceed max int"));  const int num_classes = static_cast<const int>(num_classes_raw);   log_prob_t.setZero();   std::vector<TTypes<float>::UnalignedConstMatrix> input_list_t;   for (std::size_t t = 0; t < max_time; ++t) {   input_list_t.emplace_back(inputs_t.data() + t * batch_size * num_classes,                batch_size, num_classes);  }   ctc::CTCBeamSearchDecoder<> beam_search(num_classes, beam_width_,                      &beam_scorer_, 1 /* batch_size */,                      merge_repeated_);  //使用傳入的兩個參數進行Set  beam_search.SetLabelSelectionParameters(label_selection_size, label_selection_margin);  Tensor input_chip(DT_FLOAT, TensorShape({num_classes}));  auto input_chip_t = input_chip.flat<float>();   std::vector<std::vector<std::vector<int> > > best_paths(batch_size);  std::vector<float> log_probs;   // Assumption: the blank index is num_classes - 1  for (int b = 0; b < batch_size; ++b) {   auto& best_paths_b = best_paths[b];   best_paths_b.resize(decode_helper_.GetTopPaths());   for (int t = 0; t < seq_len_t(b); ++t) {    input_chip_t = input_list_t[t].chip(b, 0);    auto input_bi =      Eigen::Map<const Eigen::ArrayXf>(input_chip_t.data(), num_classes);    beam_search.Step(input_bi);   }   OP_REQUIRES_OK(     ctx, beam_search.TopPaths(decode_helper_.GetTopPaths(), &best_paths_b,                  &log_probs, merge_repeated_));    beam_search.Reset();    for (int bp = 0; bp < decode_helper_.GetTopPaths(); ++bp) {    log_prob_t(b, bp) = log_probs[bp];   }  }   OP_REQUIRES_OK(ctx, decode_helper_.StoreAllDecodedSequences(              best_paths, &decoded_indices, &decoded_values,              &decoded_shape)); }  private: CTCDecodeHelper decode_helper_; ctc::CTCBeamSearchDecoder<>::DefaultBeamScorer beam_scorer_; bool merge_repeated_; int beam_width_; //新添兩個數據成員,用于存儲新加的參數 int label_selection_size; float label_selection_margin; TF_DISALLOW_COPY_AND_ASSIGN(CTCBeamSearchDecoderWithParamOp);}; REGISTER_KERNEL_BUILDER(Name("CTCBeamSearchDecoderWithParam").Device(DEVICE_CPU),            CTCBeamSearchDecoderWithParamOp);            
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲一区二区三区视频| 色婷婷久久av| 欧美放荡办公室videos4k| 日韩一区二区欧美| 国产精品看片资源| 日韩av色在线| 一区二区三区天堂av| 国产亚洲欧美视频| 欧美激情免费视频| 亚洲欧美精品一区二区| 欧美亚州一区二区三区| 久久香蕉国产线看观看av| 色婷婷av一区二区三区在线观看| 亚洲三级 欧美三级| 久久精品国产一区| 日韩精品极品在线观看| 91精品综合久久久久久五月天| 国产97人人超碰caoprom| 色午夜这里只有精品| 国产精品永久免费视频| 丰满岳妇乱一区二区三区| 国产精品成av人在线视午夜片| 国产区精品在线观看| 亚洲精品一二区| 欧美日韩国产一区二区三区| 91精品啪aⅴ在线观看国产| 亚洲欧美色婷婷| 中文欧美日本在线资源| 亚洲美女喷白浆| 久久久久国产精品一区| 欧美日韩亚洲视频一区| 国外成人在线直播| 国内精品久久久久久| 高清欧美性猛交xxxx黑人猛交| 亚洲欧美国产一区二区三区| 国产日韩欧美中文| 国产成人精品久久久| 国产精品ⅴa在线观看h| 亚洲第一区第二区| 欧美高清激情视频| 久久成人人人人精品欧| 中文字幕日韩在线播放| 狠狠色狠色综合曰曰| 成人精品一区二区三区电影免费| 亚洲性日韩精品一区二区| 久久中文字幕视频| 色综合久久中文字幕综合网小说| 日韩久久午夜影院| 97高清免费视频| 亚洲欧美另类在线观看| 亚洲欧美在线免费观看| 色偷偷88888欧美精品久久久| 久久久久久国产精品久久| 热re91久久精品国99热蜜臀| 91精品在线国产| 亚洲第一av网| 久久国产精品网站| 69av视频在线播放| 国产精品av在线播放| 国产不卡一区二区在线播放| 国产日韩在线看| 久久99青青精品免费观看| 2019精品视频| 俺去亚洲欧洲欧美日韩| 精品久久久久久亚洲国产300| 乱亲女秽乱长久久久| 欧美中文字幕在线视频| 亚洲成年人影院在线| 精品成人乱色一区二区| 日韩在线观看视频免费| 欧美激情精品久久久久久久变态| 深夜福利一区二区| 夜夜嗨av一区二区三区四区| 亚洲第一天堂av| 97色在线视频观看| 国产亚洲成av人片在线观看桃| 国产精品国产自产拍高清av水多| 欧美肥老太性生活视频| 国产日韩亚洲欧美| 668精品在线视频| 欧美专区在线视频| 欧美有码在线观看视频| 精品调教chinesegay| 欧美三级免费观看| 欧美成人黄色小视频| 亚洲一区久久久| 日韩中文字幕在线视频播放| 成人精品久久久| 欧美一级淫片丝袜脚交| 欧美日韩免费区域视频在线观看| 亚洲欧美日韩国产成人| 97超级碰碰碰久久久| 久久久久久久久爱| 国产伦精品一区二区三区精品视频| 国产日韩一区在线| 国产亚洲一区二区在线| 国产精品久久一区主播| 成人午夜一级二级三级| 亚洲深夜福利网站| 91免费高清视频| 国产精品热视频| 欧美在线播放视频| 精品国产欧美一区二区三区成人| 欧美精品久久久久a| 69国产精品成人在线播放| 红桃视频成人在线观看| 国产一区二区三区在线播放免费观看| 欧美色视频日本高清在线观看| 国产精品久久久久久久久久久新郎| 91久久中文字幕| **欧美日韩vr在线| 欧美成人国产va精品日本一级| 97在线观看免费| 国产91精品视频在线观看| 欧美在线视频网站| 国产精品www色诱视频| 欧美午夜片在线免费观看| 亚洲精品动漫久久久久| 亚洲已满18点击进入在线看片| 福利精品视频在线| 国产成人+综合亚洲+天堂| 日本精品免费观看| 国产精品丝袜久久久久久高清| 日韩三级成人av网| 国产精品专区一| 久久久久久12| 久久久亚洲影院你懂的| 亚洲国产精品小视频| 亚洲福利在线播放| 欧美激情精品久久久久久| 国产精品亚发布| 91视频88av| 精品亚洲一区二区三区| 欧美性极品xxxx娇小| 国产精品999| 亚洲国产另类久久精品| 91av在线播放| 欧美最猛黑人xxxx黑人猛叫黄| 中文字幕亚洲自拍| 国外日韩电影在线观看| 国产午夜精品免费一区二区三区| 久久精品国产亚洲一区二区| 亚洲国产精品一区二区三区| 中文字幕日韩精品在线观看| 91久久精品久久国产性色也91| 亚洲天堂成人在线| 中文字幕欧美视频在线| 欧美极品第一页| 亚洲精品视频免费在线观看| 欧美尺度大的性做爰视频| 91美女片黄在线观看游戏| 国产精品欧美激情| 亚洲福利视频专区| 国产+人+亚洲| 日韩av成人在线观看| 欧美综合在线观看| 日韩天堂在线视频| 中文字幕精品网| 国产91免费观看| 亚洲国产精品嫩草影院久久| 一区二区三区高清国产| 久久躁狠狠躁夜夜爽| 97在线免费观看视频| 在线成人激情黄色|