日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

tensorflow源码编译教程_极简入门TensorFlow C++源码

發(fā)布時(shí)間:2025/3/21 c/c++ 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tensorflow源码编译教程_极简入门TensorFlow C++源码 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前一段時(shí)間,一直在忙框架方面的工作,偶爾也會(huì)幫業(yè)務(wù)同學(xué)去優(yōu)化優(yōu)化使用TensorFlow的代碼,也加上之前看了dmlc/relay,nnvm的代碼,覺(jué)得蠻有意思,也想分別看下TensorFlow的Graph IR、PaddlePaddle的Graph IR,上周五,看代碼看的正津津有味的時(shí)候,看到某個(gè)數(shù)據(jù)競(jìng)賽群里面討論東西,不記得具體內(nèi)容,大概說(shuō)的是框架的代碼實(shí)現(xiàn), 有幾位算法大佬說(shuō)看底層源碼比較麻煩,因?yàn)楸容^早從框架,這塊代碼通常都還能看,問(wèn)題都不大,和群里小伙伴吹水了半天之后,感覺(jué)是可以寫(xiě)篇如何看TensorFlow或者其他框架底層源碼的勸退文了。

利其器

首先,一定是要找個(gè)好工作來(lái)看源碼,很多人推薦vs code、sublime,我試過(guò)vs code+bazel的,好像也不錯(cuò),但是后面做c++適應(yīng)了clion之后,除了資源要求比較多,還是蠻不錯(cuò)的,使用c++一般推薦使用cmake來(lái)看編譯項(xiàng)目,但是TensorFlow是bazel的,無(wú)法直接支持,最開(kāi)始,這邊是自己寫(xiě)簡(jiǎn)單的cmake,能夠?qū)崿F(xiàn)簡(jiǎn)單的代碼跳轉(zhuǎn),但是涉及到比如protobuf之類的編譯過(guò)后產(chǎn)生的文件無(wú)法跳轉(zhuǎn),比較麻煩,不夠純粹,很早之前知道clion有bazel的組件,但是不知道為啥一直搞不通,上周找時(shí)間再試了試,發(fā)現(xiàn)竟然通了,使用之后,這才是看tf源碼的真正方式:

首先,選擇合適版本的bazel,千萬(wàn)不能太高,也不能太低,這里我拉的是TF2.0的代碼,使用bazel 0.24.0剛剛好,切記千萬(wàn)別太高也比太低, 千萬(wàn)別太高也比太低,千萬(wàn)別太高也比太低。


其次,clion上選擇bazel的插件

第三步,./configure,然后按你的意圖選擇合適的編譯配置


第四步,導(dǎo)入bazel項(xiàng)目:File=>Import Bazel Project


經(jīng)過(guò)上面幾步之后,接下來(lái)就要經(jīng)過(guò)比較長(zhǎng)時(shí)間的等待,clion會(huì)導(dǎo)入bazel項(xiàng)目,然后編譯整個(gè)項(xiàng)目,這個(gè)耗時(shí)視你機(jī)器和網(wǎng)絡(luò)而定(順便提一句,最好保證比較暢通的訪問(wèn)github的網(wǎng)絡(luò),另外由于上面targets:all,會(huì)編譯TensorFlow所有的項(xiàng)目,如果你知道是什么意思,可以自己修改,如果不知道的話我先不提了,默認(rèn)就好,期間會(huì)有很多Error出現(xiàn),放心,問(wèn)題不大,因?yàn)闀?huì)默認(rèn)編譯所有的模塊)
經(jīng)過(guò)上面之后,我們就可以愉快的看代碼啦,連protobuf生成的文件都很開(kāi)心的跳轉(zhuǎn)啦

極簡(jiǎn)版c++入門

TensorFlow大部分人都知道,底層是c++寫(xiě)的,然后外面包了一層python的api,既然底層是c++寫(xiě)的,那么用c++也是可以用來(lái)訓(xùn)練模型的,大部分人應(yīng)該都用過(guò)c++或者java去載入frozen的模型,然后做serving應(yīng)用在業(yè)務(wù)系統(tǒng)上,應(yīng)該很少人去使用c++來(lái)訓(xùn)練模型,既然我們這里要讀代碼,我們先嘗試看看用c++寫(xiě)模型,文件路徑如下圖:


主要函數(shù)就那么幾個(gè):CreateGraphDef, ConcurrentSteps, ConcurrentSessions:

CreateGraphDef 構(gòu)造計(jì)算圖

GraphDef CreateGraphDef() {// TODO(jeff,opensource): This should really be a more interesting// computation. Maybe turn this into an mnist model instead?Scope root = Scope::NewRootScope();using namespace ::tensorflow::ops; // NOLINT(build/namespaces)// A = [3 2; -1 0]. Using Const<float> means the result will be a// float tensor even though the initializer has integers.auto a = Const<float>(root, {{3, 2}, {-1, 0}});// x = [1.0; 1.0]auto x = Const(root.WithOpName("x"), {{1.f}, {1.f}});// y = A * xauto y = MatMul(root.WithOpName("y"), a, x);// y2 = y.^2auto y2 = Square(root, y);// y2_sum = sum(y2). Note that you can pass constants directly as// inputs. Sum() will automatically create a Const node to hold the// 0 value.auto y2_sum = Sum(root, y2, 0);// y_norm = sqrt(y2_sum)auto y_norm = Sqrt(root, y2_sum);// y_normalized = y ./ y_normDiv(root.WithOpName("y_normalized"), y, y_norm);GraphDef def;TF_CHECK_OK(root.ToGraphDef(&def));return def; }

定義graph 節(jié)點(diǎn) root, 然后定義常數(shù)變量a (shape為2*2), x (shape為2* 1),然后 y = A * x, y2 = y.2, y2_sum = sum(y2), y_norm = sqrt(y2_sum), y_normlized = y ./ y_norm。代碼很簡(jiǎn)潔, 看起來(lái)一目了然,
然后是ConcurrentSteps

void ConcurrentSteps(const Options* opts, int session_index) {// Creates a session.SessionOptions options;std::unique_ptr<Session> session(NewSession(options));GraphDef def = CreateGraphDef();if (options.target.empty()) {graph::SetDefaultDevice(opts->use_gpu ? "/device:GPU:0" : "/cpu:0", &def);}TF_CHECK_OK(session->Create(def));// Spawn M threads for M concurrent steps.const int M = opts->num_concurrent_steps;std::unique_ptr<thread::ThreadPool> step_threads(new thread::ThreadPool(Env::Default(), "trainer", M));for (int step = 0; step < M; ++step) {step_threads->Schedule([&session, opts, session_index, step]() {// Randomly initialize the input.Tensor x(DT_FLOAT, TensorShape({2, 1}));auto x_flat = x.flat<float>();x_flat.setRandom();std::cout << "x_flat: " << x_flat << std::endl;Eigen::Tensor<float, 0, Eigen::RowMajor> inv_norm =x_flat.square().sum().sqrt().inverse();x_flat = x_flat * inv_norm();// Iterations.std::vector<Tensor> outputs;for (int iter = 0; iter < opts->num_iterations; ++iter) {outputs.clear();TF_CHECK_OK(session->Run({{"x", x}}, {"y:0", "y_normalized:0"}, {}, &outputs));CHECK_EQ(size_t{2}, outputs.size());const Tensor& y = outputs[0];const Tensor& y_norm = outputs[1];// Print out lambda, x, and y.std::printf("%06d/%06d %sn", session_index, step,DebugString(x, y).c_str());// Copies y_normalized to x.x = y_norm;}});}// Delete the threadpool, thus waiting for all threads to complete.step_threads.reset(nullptr);TF_CHECK_OK(session->Close()); }

新建一個(gè)session,然后設(shè)置10個(gè)線程來(lái)計(jì)算,來(lái)執(zhí)行:

std::vector<Tensor> outputs;for (int iter = 0; iter < opts->num_iterations; ++iter) {outputs.clear();TF_CHECK_OK(session->Run({{"x", x}}, {"y:0", "y_normalized:0"}, {}, &outputs));CHECK_EQ(size_t{2}, outputs.size());const Tensor& y = outputs[0];const Tensor& y_norm = outputs[1];// Print out lambda, x, and y.std::printf("%06d/%06d %sn", session_index, step,DebugString(x, y).c_str());// Copies y_normalized to x.x = y_norm;}

每次計(jì)算之后,x=y_norm,這里的邏輯其實(shí)就是為了計(jì)算矩陣A的最大eigenvalue, 重復(fù)執(zhí)行x = y/y_norm; y= A*x;
編譯:

bazel build //tensorflow/cc:tutorials_example_trainer

執(zhí)行結(jié)果,前面不用太care是我打印的一些調(diào)試輸出:

簡(jiǎn)單的分析

上面簡(jiǎn)單的c++入門實(shí)例之后,可以抽象出TensorFlow的邏輯:

  • 構(gòu)造graphdef,使用TensorFlow本身的Graph API,利用算子去構(gòu)造一個(gè)邏輯計(jì)算的graph,可以試上述簡(jiǎn)單地計(jì)算eigenvalue,也可以是復(fù)雜的卷積網(wǎng)絡(luò),這里是涉及到Graph IR的東西,想要了解的話,我建議先看下nnvm和relay,才會(huì)有初步的概念;
  • 用于構(gòu)造graphdef的各種操作,比如上述將達(dá)到的Square、MatMul,這些操作可以是自己寫(xiě)的一些數(shù)學(xué)操作也可以是TensorFlow本身封裝一些數(shù)學(xué)計(jì)算操作,可以是MKL的封裝,也可以是cudnn的封裝,當(dāng)然也可以是非數(shù)學(xué)庫(kù),如TFRecord的讀取;
  • Session的構(gòu)造,新建一個(gè)session,然后用于graph外與graph內(nèi)部的數(shù)據(jù)交互:session->Run({{"x", x}}, {"y:0", "y_normalized:0"}, {}, &outputs));這里不停地把更新的x王graph里喂來(lái)計(jì)算y與y_normalized,然后將x更新為y_normalized;
  • GraphDef這一套,太過(guò)復(fù)雜,不適合演示如何看TF源碼,建議大家先有一定的基礎(chǔ)知識(shí)之后,再看,這里我們摘出一些算法同學(xué)感興趣的,比如Square這個(gè)怎么在TF當(dāng)中實(shí)現(xiàn)以及綁定到對(duì)應(yīng)操作

  • 代碼中直接跳轉(zhuǎn)到Square類,如下圖;
  • 2.很明顯看到Square類的定義,其構(gòu)造函數(shù),接收一個(gè)scope還有一個(gè)input, 然后我們找下具體實(shí)現(xiàn),如下圖:

    3.同目錄下, http://math_ops.cc,看實(shí)現(xiàn)邏輯,我們是構(gòu)造一個(gè)名為Square的op,然后往scope里更新,既然如此,肯定是預(yù)先有保存名為Square的op,接下來(lái)我們看下圖:

    4.這里講functor::square注冊(cè)到"Square"下,且為UnaryOp,這個(gè)我不知道怎么解釋,相信用過(guò)eigen的人都知道,不知道的話去google下,很容易理解,且支持各種數(shù)據(jù)類型;

    5.那么看起來(lái),square的實(shí)現(xiàn)就在functor::square,我們?cè)龠M(jìn)去看看,集成base模板類,且看起來(lái)第二個(gè)模板參數(shù)為其實(shí)現(xiàn)的op,再跳轉(zhuǎn)看看:

     6.最后,我們到達(dá)了最終的實(shí)現(xiàn)邏輯:operator()和packetOp,也看到了最終的實(shí)現(xiàn),是不是沒(méi)有想象的那么難。

    更重要一點(diǎn)

    看完了上面那些,基本上會(huì)知道怎么去看TensorFlow的一些基礎(chǔ)的代碼,如果你了解graph ir這套,可以更深入去理解下,這個(gè)過(guò)程中,如果對(duì)TensorFlow各個(gè)文件邏輯感興趣,不妨去寫(xiě)寫(xiě)測(cè)試用例,TensorFlow很多源碼文件都有對(duì)應(yīng)的test用例,我們可以通過(guò)Build文件來(lái)查看,比如我想跑下http://client_session_test.cc這里的測(cè)試用例


    我們看一下Build文件中


    這里表明了對(duì)應(yīng)的編譯規(guī)則,然后我們只需要

    bazel build //tensorflow/cc:client_client_session_test

    然后運(yùn)行相應(yīng)的測(cè)試程序即可

    更更重要的一點(diǎn)

    上面把如何看TensorFlow代碼的小經(jīng)驗(yàn)教給各位,但是其實(shí)這個(gè)只是真正的開(kāi)始,無(wú)論TensorFlow、MXNet、PaddlePaddle異或是TVM這些,單純?nèi)タ创a,很難理解深刻其中原理,需要去找相關(guān)行業(yè)的paper,以及找到行業(yè)的精英去請(qǐng)教,去學(xué)習(xí)。目前網(wǎng)上ml system的資料還是蠻多的,有點(diǎn)『亂花迷人眼』的感覺(jué),也沒(méi)有太多的課程來(lái)分享這塊的工作,十分期望這些框架的官方分享這些框架的干貨,之后我也會(huì)在學(xué)習(xí)中總結(jié)一些資料,有機(jī)會(huì)的話分享給大家。最后,這些東西確實(shí)是很復(fù)雜,作者在這塊也是還是懵懵懂懂,希望能花時(shí)間把這些內(nèi)在的東西搞清楚,真的還蠻有意思的。

    也歡迎大家關(guān)注我的同名微信公眾號(hào) 小石頭的碼瘋窩(xiaoshitou_ml_tech),或者通過(guò)公眾號(hào)加我的個(gè)人微信進(jìn)行討論

    總結(jié)

    以上是生活随笔為你收集整理的tensorflow源码编译教程_极简入门TensorFlow C++源码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 天天干天天做天天操 | 精品欧美一区二区在线观看 | 国产高潮网站 | 91热热| 影音先锋一区 | 欧洲一区二区三区在线 | av一卡二卡 | 91精品国产综合久久久久久 | 国产成年视频 | 国产精彩视频在线观看 | 91人妻一区二区三区蜜臀 | 一个色在线| 亚洲综合色婷婷 | 殴美一级视频 | 国产在线精品一区二区 | 91久久中文字幕 | 久久情趣视频 | 91伊人网 | 亚洲一区二区三区人妻 | 91精品婷婷国产综合久久 | www,日韩 | 性网爆门事件集合av | 密臀av一区二区 | 欧美v视频| 色一情一区二 | 亚洲欧美日韩国产综合 | 国产黄色网址在线观看 | 欧美永久 | 亚洲性在线 | 97人人爽 | 亚洲亚洲人成综合网络 | 欧洲亚洲成人 | 波多野结衣办公室双飞 | 久久99婷婷 | 国产日本精品 | 性欧美另类 | 精品综合久久久 | 捆绑束缚调教 | 日韩精品一区二区三区在线播放 | 欧美日韩国产网站 | 曰本三级日本三级日本三级 | 亚洲一区二区免费视频 | 亚洲国产精品一区二区久久hs | 乳色吐息免费看 | 国产精品美女久久久久图片 | 久久这里有精品 | 成人激情文学 | 高清av在线 | 天堂一区二区三区 | 秋霞福利片 | 可以免费看的av | 一级网站在线观看 | 欧美精品 日韩 | 狠操av| 欧美jizz欧美性大全 | 国产精品九九热 | 欧美成人a视频 | 中国女人黄色大片 | 一进一出视频 | 成人短视频在线 | 五月99久久婷婷国产综合亚洲 | 人妻一区二区三区四区五区 | 日本成人免费在线视频 | 色日韩| 免费av网站在线看 | 亚洲欧美自偷自拍 | 亚洲第九十七页 | 综合激情伊人 | 伊人福利| av第一区 | 欧美成人黄色网 | 亚洲欧美另类综合 | 国产女人18水真多毛片18精品 | 成人欧美视频 | 久久噜噜噜精品国产亚洲综合 | 国产精品suv一区二区三区 | 午夜视频精品 | 亚洲高清视频在线观看 | 男女污污视频在线观看 | 日韩在线视频二区 | 日日爽视频 | 欧洲熟妇的性久久久久久 | 美女上床网站 | 久久久精品综合 | 亚洲资源在线播放 | 后入内射欧美99二区视频 | 亚洲特级片 | 亚洲精品成a人 | 国产精品一区二区无码对白 | 九九色综合网 | 欧美综合自拍亚洲综合图片区 | 精品视频免费在线观看 | 亚洲精品乱码久久久久久按摩观 | 国产浮力第一页 | 亚洲成人免费在线视频 | 国产精品一区二区av | 亚洲AV成人无码网站天堂久久 | 黑鬼大战白妞高潮喷白浆 | 轻轻色在线观看 |