AI编译器:ChatGpt和Claude有何区别

编程语言及工具

105人已加入

描述

Claude在MLIR代码分析上完全超越了ChatGPT并表现十分惊艳,请阅读全文或者自己注册感受它的强大。

0x0. 前言

这里将以oneflow IR部分中的一个Codegen任务(目标是在mlir codegen中支持oneflow stream,用oneflow stream替换pass中自己生成的stream,PR链接为:https://github.com/Oneflow-Inc/oneflow/pull/10149)为例,来对比一下chatgpt和claude对mlir的理解能力。claude是Anthropic公司推出的类似于chatgpt的聊天机器人,这家公司是OpenAI的最大竞争对手之一,因为创办这家公司的人也是OpenAI的前员工。本次使用的chatgpt可以在这个 https://chatbot.theb.ai/#/chat/1002 访问。然后Claude是参考这个issue: https://www.zhihu.com/question/594115372/answer/2988759047 将其直接添加到slack里进行对话。

0x1. PR简介

PR链接为:https://github.com/Oneflow-Inc/oneflow/pull/10149

这个PR实现了3个Pass (定义在 OneFlowPasses.td),也就是:

def EliminateAllocOpsPass : Pass<"eliminate-alloc-ops", "ModuleOp"> {
  let summary = "";
  let constructor = "mlir::createEliminateAllocOpsPass()";
  let dependentDialects = ["pdl_interp::PDLInterpDialect", "pdl::PDLDialect"];
}

def AppendOneFlowStreamPass : Pass<"append-ofstream", "ModuleOp"> {
  let summary = "append oneflow stream to gpu function arguments";
  let constructor = "mlir::createAppendOneFlowStreamPass()";
}

def MgpuToOneFlowStreamPass : Pass<"mgpu-to-ofstream", "ModuleOp"> {
  let summary = "convert mlir abi about mgpu to oneflow stream, this pass should be invoked after append-ofstream pass";
  let constructor = "mlir::createMgpuToOneFlowStreamPass()";
}

EliminateAllocOpsPass用来消除IR中的无效memref.alloc指令,AppendOneFlowStreamPass给GPU相关的函数添加GPU启动kernel需要的stream参数,MgpuToOneFlowStreamPass发生在AppendOneFlowStreamPass执行之后(它生成了stream参数)并把mgpu相关的stream abi替换为oneflow stream abi。

我们分别使用newbing和claude来让它们分析一下这几行OneFlowPasses.td中定义的Pass意图:

newbing:

聊天机器人

在这里插入图片描述

newbing直接看不懂,其实我感觉claude也应该看不懂吧,抱着怀疑的态度问一下。

聊天机器人

聊天机器人

太疯狂了,claude不仅读懂了td文件的代码,甚至为我们列出了这个代码涉及到的MLIR概念。感觉是训练数据考虑了MLIR相关的预料?接下来我们再对比下C++实现的Pass代码。

0x2. 对比具体实现

PR链接为:https://github.com/Oneflow-Inc/oneflow/pull/10149

0x2.1 EliminateAllocOpsPass

EliminateAllocOpsPass使用MLIR提供的PDL语言来完成Pattern的匹配和重写,具体实现在 oneflow/ir/lib/OneFlow/PDLL/AllocEliminationPatterns.pdll :

#include "OneFlow/OneFlowOps.td"

Constraint IsFuncArguments(value: Value) [{
  return success(llvm::dyn_cast(value));
}];

Pattern {
  let alloc = op();
  let copy = op(alloc.0, arg: IsFuncArguments);

  rewrite alloc with {
    erase copy;
    replace alloc with arg;
  };
}

接下来,我们分别对比一下newbing和chatgpt对它的分析结果。

聊天机器人

在这里插入图片描述

newbing并不能解析出这段代码是MLIR的PDL语言,当然也无法理解代码内容。我们可以再使用Claude试试。

聊天机器人

在这里插入图片描述

聊天机器人

在这里插入图片描述

个人感觉这个解释是非常强大且精准的,Claude的答案非常惊艳。

0x2.2 AppendOneFlowStreamPass

接下来我们看一下AppendOneFlowStreamPass的实现,这个实现是在oneflow/ir/lib/OneFlow/Transform/OneFlowStream.cpp这个文件,具体代码如下:

struct AppendOneFlowStreamPattern final : public OpRewritePattern {
 public:
  explicit AppendOneFlowStreamPattern(mlir::MLIRContext* context)
      : OpRewritePattern(context, /*benefit=*/0) {}
  mlir::LogicalResult matchAndRewrite(func::FuncOp op,
                                      mlir::PatternRewriter& rewriter) const override {
    auto ptr_type = LLVM::get(rewriter.getContext(), 8));
    if (llvm::dyn_cast(op.getFunctionType().getInputs().back()))
      return success();

    llvm::SmallVector new_operand_type;
    for (auto type : op.getFunctionType().getInputs()) { new_operand_type.push_back(type); }
    new_operand_type.push_back(ptr_type);
    auto function_type =
        rewriter.getFunctionType(new_operand_type, op.getFunctionType().getResults());

    auto func = rewriter.create(op.getLoc(), op.getName(), function_type);
    for (auto pair : op->getDialectAttrs()) { func->setAttr(pair.getName(), pair.getValue()); }
    op.getBody().addArgument(ptr_type, func->getLoc());
    IRMapping bvm;
    op.getRegion().cloneInto(&func.getRegion(), bvm);
    rewriter.eraseOp(op);
    return success();
  }
};

c++代码newbing(chatgpt)按道理可以看懂了,我们让它分析一下:

聊天机器人

在这里插入图片描述

直接问chatgpt,它还是不懂这段代码。我手动提示了下它说,这段代码定义了一个mlir pattern,然后它先是重复我的话给出了一段回答。然后接下来就是胡说八道了,在这个例子中表现很差。接下来我们拷问一下Claude:

聊天机器人

聊天机器人

我们继续问一下c++代码中的一些细节:

聊天机器人

聊天机器人

非常强大,给出的解释大多比较精准,并且似乎Claude真的完全理解了这段代码的逻辑。我们需要注意的是,这段代码是我同事今天才写的,模型的泛化性真的很好。

MgpuToOneFlowStreamPass

我们最后再分析下MgpuToOneFlowStreamPass的实现。

struct MgpuToOneFlowStreamPattern final : public OpRewritePattern {
 public:
  explicit MgpuToOneFlowStreamPattern(mlir::MLIRContext* context)
      : OpRewritePattern(context, /*benefit=*/0) {}
  mlir::LogicalResult matchAndRewrite(LLVM::CallOp op,
                                      mlir::PatternRewriter& rewriter) const override {
    auto ptr_type = LLVM::get(rewriter.getContext(), 8));
    auto func = op->getParentOfType();
    auto callee = op.getCallee();
    if (!func || !callee) return failure();
    Value stream = func.getArguments().back();
    if (stream.getType() != ptr_type) {
      LOG(ERROR) << "failed to find stream in llvm.func block arguments";
      return failure();
    }

    DenseMap,
                       std::function>>
        oneflow_abi = {
            {"mgpuStreamCreate",
             {[](LLVM::CallOp& op, Value& stream) { return true; },
              [](mlir::PatternRewriter& rewriter, LLVM::CallOp& op, Value& stream) {
                rewriter.replaceOp(op, {stream});
              }}},
            {"mgpuLaunchKernel",
             {[](LLVM::CallOp& op, Value& stream) {
                unsigned idx = op->getNumOperands();
                return op.getOperand(idx - 3) != stream;
              },
              [](mlir::PatternRewriter& rewriter, LLVM::CallOp& op, Value& stream) {
                unsigned idx = op->getNumOperands();
                auto target = op.getOperand(idx - 3).getDefiningOp();
                rewriter.replaceOp(target, {stream});
              }}},
            {"mgpuStreamSynchronize",
             {[](LLVM::CallOp& op, Value& stream) { return true; },
              [](mlir::PatternRewriter& rewriter, LLVM::CallOp& op, Value& stream) {
                rewriter.eraseOp(op);
              }}},
            {"mgpuStreamDestroy",
             {[](LLVM::CallOp& op, Value& stream) { return true; },
              [](mlir::PatternRewriter& rewriter, LLVM::CallOp& op, Value& stream) {
                rewriter.eraseOp(op);
              }}},
        };
    auto out = oneflow_abi.find(callee.value().str());
    if (out != oneflow_abi.end() && out->getSecond().first(op, stream)) {
      out->getSecond().second(rewriter, op, stream);
    }
    return success();
  }
};

还是先让chatgpt分析下:

聊天机器人

在这里插入图片描述

回答还是比较模棱两可,并且可以确定的事情是chatgpt完全没有理解这段代码。

接下来还是使用Claude来测试下:

聊天机器人

在这里插入图片描述

这个地方让我震惊的点是,它不仅理解了这段代码,而且知道在MLIR里面这段代码只是一个Pattern规则,如果要应用这个规则需要在MLIR里面再构建一个Pass。最后我们再让Claude给我们一些Review意见:

聊天机器人

在这里插入图片描述

这里的第4点提示让我感到有些疑惑,我还请教了下同事,顺便让同事补充一下注释。

聊天机器人

在这里插入图片描述

整体来说,在阅读MLIR代码方面,Claude已经相当智能,全面领先Newbing(Chatgpt),感觉以后可以日常用Claude来辅助Review IR相关代码。

0x3. 总结

我这里以MLIR的一个任务对比了一下ChatGpt和Claude,我感受到了Calude的强大之处。虽然暂时还没有评测过别的任务,但我已经被Calude表现出来的代码分析能力所震撼。我们甚至可以将Claude作为一个入门AI编译器的入门工具

编辑:黄飞

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分