Tian Junhttps://tianjun.me/rssAll about Tian Junen-USSun, 26 May 2019 16:18:04 GMTrfeed v1.1.1https://github.com/svpino/rfeed/blob/master/README.mdQuantum_Computinghttps://tianjun.me/essays/Quantum_Computing<body> <h1 id="量子计算入门">量子计算入门</h1> <p>本文用于记录我学习量子计算的过程。</p> <p>(Suspended due to priority change.)</p> <h2 id="some-key-concepts">Some Key Concepts</h2> <h3 id="bloch-sphere">Bloch Sphere</h3> <h2 id="resources">Resources</h2> <h3 id="web-pages">Web Pages</h3> <ul> <li><p><a href="https://quantum.country">Quantum computing for the very curious</a></p> <p>Michael Nielsen 写的简介,读下来很有收获,重新点燃了学习的兴趣!</p></li> <li><p><a href="https://medium.com/@johncoogan/the-best-resources-for-learning-about-quantum-computing-4fcc9f3cbe56">The best resources for learning about quantum computing</a></p> <p>目前找到的最好的入门资料汇总。</p></li> <li><p><a href="https://github.com/krishnakumarsekar/awesome-quantum-machine-learning">Awesome quantum machine learning</a></p> <p>量子计算与机器学习的结合。</p></li> </ul> <h3 id="books">Books</h3> <h4 id="introduction-to-the-theory-of-computation"><a href="https://book.douban.com/subject/12986396/">Introduction to the Theory of Computation</a></h4> <div class="figure"> <img alt="Introduction_to_the_Theory_of_Computation.jpg" src="/static/essay_resources/Quantum_Computing/Resources/img/Introduction_to_the_Theory_of_Computation.jpg"/> <p class="caption">Introduction_to_the_Theory_of_Computation.jpg</p> </div> <p>这本书用来补一下有关计算复杂度的知识。 很意外,这本书的Part 1 部分,填补了之前读<a href="https://book.douban.com/subject/3136252/">EOPL</a>的一些关于Parser的空白。关于自动机,正则表达式,CFG的讲解一气呵成。Part2部分对图灵机有了更多的了解,halting啥的不再停留在表面的认识。读完Part3之后对复杂性有了新的的认识,之前看到有一个书评说,如果你在别人高谈阔论P,NP,NP-complete等问题时感到一脸懵逼,请立即抱起这本书,这里有你想要的答案。</p> <h4 id="quantum-computing-since-democritusqcsd"><a href="https://book.douban.com/subject/12030716/">Quantum Computing Since Democritus</a></h4> <div class="figure"> <img alt="Quantum_Computing_Since_Democritus.jpg" src="/static/essay_resources/Quantum_Computing/Resources/img/Quantum_Computing_Since_Democritus.jpg"/> <p class="caption">Quantum_Computing_Since_Democritus.jpg</p> </div> <p>这本书没法评价。</p> <p>因为压根没读懂,水平有限,摊手......</p> <p>前几章跟Quantum Computing的关系不大,开篇的冷笑话,真的好冷......以至于我真的只记住了那句话(有兴趣的话,可以去看看作者的<a href="https://www.scottaaronson.com">博客</a>):</p> <blockquote> <p>But if quantum mechanics isn't physics in the usual sense - if it's not about matter, or energy, or waves, or particles -then what <em>is</em> it about? From my perspective, it's about information and probabilities and observables, and how they relate to each other.</p> </blockquote> <p>我能体会到作者独特的视角,无奈,自己相关的基础并不扎实,强行读到了第十章,后面的部分只是草草翻了下。后来偶然在网上看到了别人写的一篇<a href="http://slatestarcodex.com/2014/09/01/book-review-and-highlights-quantum-computing-since-democritus/">review</a>,深有同感。总的来说,如果你看到chapter1~8的标题之后,确认你对相关内容不那么陌生(不是熟悉或精通),那么可以断定这是一本非常值得一读的书,否则真的很难跟上作者的脚步(当然,你也可以像我一样,不妨先读读试试~)。Anyway,即使只读了前十章,也依然收获颇丰,许多亮点与前面提到的那篇<a href="http://slatestarcodex.com/2014/09/01/book-review-and-highlights-quantum-computing-since-democritus/">review</a>有许多共通之处。这里只说我感受最深的一点:</p> <blockquote> <p>There are two ways to teach quantum mechanics. The first way - which for most physicists today is still the only way - follows the historical order in which the ideas were discovered... The second way to teach quantum mechanics eschews a blow-by-blow account of its discovery, and instead <em>starts directly from the conceptual core</em> - namely, a certain generalization of the laws of probability to allow minus signs )and more generally, complex numbers).</p> </blockquote> <p>作者首先提到了目前学习量子原理的两种方式(作者在书中采取的是后者),然后说道:</p> <blockquote> <p><em>Quantum mechanics is what you would inevitably come up with if you started from probability theory, and then said, let's try to generalize it so that the numbers we used to call "probabilities" can be negative numbers. As such, the theory could have been invented by mathematicians in the nineteenth century without any input from experiment.</em> <strong>It wasn't, but it could have been</strong>.</p> </blockquote> <p>是的,<strong>实验先于理论</strong>。另外两个类似的例子是<strong>进化论</strong>和<strong>狭义相对论</strong>。读到这里时,我联想到的是目前深度学习的现状,何其相似。作者认为:</p> <blockquote> <p>More often than not, the <em>only</em> reason we need experiments is that we're not smart enough.</p> </blockquote> <h4 id="q-is-for-quantumqfq"><a href="https://book.douban.com/subject/27167701/">Q is for Quantum</a></h4> <div class="figure"> <img alt="Q_IS_FOR_QUANTUM" src="/static/essay_resources/Quantum_Computing/Resources/img/Q_IS_FOR_QUANTUM.jpg"/> <p class="caption">Q_IS_FOR_QUANTUM</p> </div> <p>吸取读上一本书的教训,还是先从简单点的入手。这本小册子很薄,总共150多页。作者构建了一个PETE BOX,用图形化的语言来阐述量子计算相关的一些概念。</p> <p>PART 1 部分,对比经典计算机中的与或非门,清晰地描述了<em>量子门</em>(PETE BOX)的特性。</p> <p>关键词:</p> <ol style="list-style-type: decimal"> <li>superposition / misty state</li> <li>interfere</li> <li>collision</li> </ol> <p>PART 2 部分,用一个很形象的例子(心灵感应?)讲清楚了一个很有意思的现象:</p> <p><a href="https://en.wikipedia.org/wiki/Quantum_entanglement"><strong>Entanglement</strong></a></p> <p>PART 3展开讨论了什么是<strong>REALITY</strong>,这部分相比前两部分理解得没那么透彻。照惯例,附上两篇书评:</p> <ul> <li><a href="https://tomate.wordpress.com/2017/10/03/q-is-for-quantum-reality/">Q is for Quantum &amp; “reality”</a></li> <li><a href="http://janjanjan.uk/2017/08/29/review-q-quantum-terry-rudolph/">Review: Q is for Quantum by Terry Rudolph</a></li> </ul> <h4 id="picturing-quantum-processespqp"><a href="https://book.douban.com/subject/26995979/">Picturing Quantum Processes</a></h4> <div class="figure"> <img alt="Picturing Quantum Processes" src="/static/essay_resources/Quantum_Computing/Resources/img/picturing_quantum_processes.jpg"/> <p class="caption">Picturing Quantum Processes</p> </div> <p>感觉这本书更适合在有一点点量子计算的基础之后再读,然后应该会有种耳目一新的感觉,居然还能采用这种方式来描述。目前读了大约1/5,基本能跟上作者的节奏,读这本书之前稍微回顾下线性计算会好点,有利于融会贯通。暂时需要先放下来,因为读这本书对我这种新手来说会比较累,需要同时理解两套理念(尽管二者并非独立的关系),留到后面有一定基础了再看下。</p> <h4 id="quantum_computation_and_quantum_informationqcqi"><a href="https://book.douban.com/subject/6937989/">Quantum_Computation_and_Quantum_Information</a></h4> <div class="figure"> <img alt="Quantum_Computation_and_Quantum_Information" src="/static/essay_resources/Quantum_Computing/Resources/img/Quantum_Computation_and_Quantum_Information.jpg"/> <p class="caption">Quantum_Computation_and_Quantum_Information</p> </div> <p>这本书同步进行中。</p> <h4 id="linear-algebra-done-right-3rd-edladr"><a href="https://book.douban.com/subject/26265880/">Linear Algebra Done Right (3rd ed)</a></h4> <div class="figure"> <img alt="Linear_Algebra_Done_Right" src="/static/essay_resources/Quantum_Computing/Resources/img/Linear_Algebra_Done_Right.jpeg"/> <p class="caption">Linear_Algebra_Done_Right</p> </div> <p>有些线性代数相关的部分需要回顾下。</p> <p>这本书对应的<a href="http://linearalgebras.com/">Solution</a></p> </body>Jun TianSun, 07 Apr 2019 22:10:51 GMTQuantum_ComputingThe_Senior_Software_Engineerhttps://tianjun.me/essays/The_Senior_Software_Engineer<body> <h1 id="读书笔记the-senior-software-engineer">读书笔记【The Senior Software Engineer】</h1> <p>图书馆意外翻到的一本书,读了读发现还挺有意思,随手写点读书笔记。</p> <p>关于 <strong>Senior</strong>,作者开篇就解释了,在大多数公司里,<strong>Senior</strong>区别于<strong>Junior</strong>,用来指代那些拥有更多决策权的员工。不过作者有意指出,题目中的<strong>Senior</strong>在我们这行一般是指工作了三年以上的人(从这个角度来说,我也勉强算是qualified的目标读者了......)。全书分十一章,阐述了作者18年来的一些工作心得,许多地方很有认同感,摘录下来,或许其他人读了也会有点收获?</p> <h2 id="focus-on-delivering-results">Focus on Delivering Results</h2> <p>这一章其实拆分成了3个部分:</p> <ul> <li><strong>Results</strong></li> <li><strong>Focus</strong></li> <li><strong>Delivering</strong></li> </ul> <p>首先是观念上的转变,作为SDE,一般认为产出就是代码,不过作者认为,产出一定是要体现商业价值:</p> <blockquote> <p>A <em>result</em> then, is an artivact of direct business value. Working code, documentation, and definitive statements are all results. Anything else must be understood as fundamentally different.</p> </blockquote> <p>然后是<strong>Focus</strong>,作者描述了工作中一个常见的场景:回邮件。阐述了为什么持续focus在当前的工作上要好于立即回复邮件(1. Distraction 2. We can forward to others 3. Keep promises to a minimum)。</p> <p>最后是 deliver smaller results more often,也是软件开发里常提到的一个概念,至于优点嘛:</p> <blockquote> <p>First, it turns a boring progress report into working, usable software. You won't have to merely <em>tell</em> the rest of the company how far along you are, you can <em>show</em> them. Secondly, promises of smaller value over shorter time are easier to keep. You are much more likely to accurately estimate one week's worth of work than you are one month's.</p> </blockquote> <h2 id="fix-bugs-efficiently-and-cleanly">Fix Bugs Efficiently and Cleanly</h2> <p>作者总结了自己修bug的一些best practice,我自认在工作中没这么规范的做过,但从心底还是认同书中提到的这个流程:</p> <ol style="list-style-type: decimal"> <li>Understand the problem.</li> <li>Write tests that fail (because the problem has yet to be solved).</li> <li>Solve the problem as quickly as you can, using your tests to know when you've solved it.</li> <li>Modify your solution for readability, conciseness, and safety by suing your tests to make sure you haven't broken anything.</li> <li>Commit your changes.</li> </ol> <p>简单来说,就是test driven development 。核心思想就两点:</p> <ol style="list-style-type: decimal"> <li>Thinking before coding</li> <li>Separating "getting it to work" from "doing it right". It's hard to do both at the same time.</li> </ol> <p>自我反思下,大多时候只做到了"getting it to work",尬。越是到了项目后期,"doing it right"的代价也越来越大。当然,也不能走极端了(Don't over-engineer and know when to quit),然后引用了<strong>《重构》</strong>中的一句话:</p> <blockquote> <p>[Refactoring is] restructuring an existing body of code, altering its internal structure without changing its external behavior.</p> </blockquote> <p>还有一点,记得及早commit,嗯,这一点感受还是很深的,不然,就等着哭去了......</p> <h2 id="add-new-features-with-ease">Add New Features with Ease</h2> <p>这部分内容中,自认为需要改进的应当是 <em>Plan your implementation</em> 这部分。列清楚 TODO list,找人交流讨论实现,然后预估每部分的大致时间。</p> <blockquote> <p>Whatever you produce here is for your internal use only and is designed to capture your thinking at a high level about how to solve the problem and what bases need covering. Once you dive into the code, you will focus on much smaller concerns. Your "plan" here is for those moments when you get done with something and stick your head up to see where you are.</p> </blockquote> <h2 id="deal-with-technical-debt-and-slop">Deal With Technical Debt and Slop</h2> <p>第一次了解这个单词,<strong>Sloppy</strong>,不过,其描述的场景在工作中太常见了。复制,粘贴,再修修补补,Test全绿,Coverage蹭蹭涨,Well Done!不过,作为Senior的工程师,绝对不能ship这类代码。</p> <p>关于Technical Debt,书中的一个做法直接在comment里明确写出来了,感觉这个得有工具track,不然这些Debt大概率没机会偿还了......</p> <h2 id="play-well-with-others">Play Well With Others</h2> <p>这大概是Senior进阶路上最难的一步。</p> <blockquote> <p>Translating your work to non-technical people is a skill that can be more valuable than any specific technical knowledge you have. It's what makes a senior developer in the eyes of others.</p> </blockquote> <p>作者的两个建议是:</p> <ul> <li>Empathize with your audience.</li> <li>Distill what you know in a way your audience can understand.</li> </ul> <p>关于第二点,有一些更实际的建议:</p> <ul> <li>Adapt Terms</li> <li>Avoid technical jargon of your own.</li> <li>Listen carefully to the words people use and ask questions if you aren't 100% sure what they mean.</li> <li>Don't "talk down". The other person is likely a highly intelligent person who is capable of understanding what you're explaining. Treating them like a child will only make things worse. (这点确实在太常见了)</li> <li>Don't be afraid to use longer descriptive phrases in place of acronyms or other jargon.</li> <li>Abstract Cepts to Simplify Them</li> <li>Avoid technical details</li> <li>Explain things using analogies; don't worry about precision</li> <li>Use diagrams, visual aids, or demonstrations where possible.</li> <li>Always offer to provide more details (这点已经听许多人说过了,挺受益的)</li> <li>If a question has taken you off course, spend a few seconds re-establishing the context of your discussion. (这个需要反复练习,一是得清醒地意识到off course了,二是根据问题重新澄清讨论主题)</li> <li>Be prepared to "justify" your position if challenged.</li> <li>**Remember, it's not the other person's job to understand you, it's your job to make sure they understand.</li> <li>Don't be afraid to stop and re-group if things are going poorly. Find a colleague you trust or respect who can (or already does) understand the technical information in question and ask how they would handle it.</li> </ul> <h2 id="make-technical-decisions">Make Technical Decisions</h2> <p>越往后走,就有越多(重要)的事情需要做决定,作者的建议是,从两方面出发,分别考虑:</p> <ol style="list-style-type: decimal"> <li><strong>Identify Facts</strong> 注意区分 <strong>Facts</strong> 和 <strong>Opinions</strong></li> <li><strong>Identify Priorities</strong> 综合考虑多方的<strong>Priorities</strong>,自己的,整个team的,boss的等等</li> </ol> <p>此外,注意区分<strong>fallicies</strong> (有意思的是,这里还提到了Clojure)。即使是一些非常聪明的人也会犯类似的错。</p> <blockquote> <p>If someone remains unconvinced by your arguments, rather than assume the person is "not getting it", take a moment to consider if your argument really is lacking. Give everyone the benefit of the doubt. Is there a fact you got wrong? A priority ou haven't identified? <strong>Your mission isn't to prove that you are right, it's to deliver the best results you can </strong>.</p> </blockquote> <p>还有一点非常值得学习:<strong>Document the decision-making process</strong>.</p> <blockquote> <p>A document like this is useful for two reasons. First, it can prevent someone else from going through the trouble that you've just gone through. Second, it keeps you from having to remember the details whe, sixmonths from now, a new team member asks why things are done a certain way.</p> </blockquote> <h2 id="bootstrap-a-greenfield-system">Bootstrap a Greenfield System</h2> <p>这部分涉及的内容反而在现有的项目里是做得比较好的一块(原因大概是,Dialog这块常做常新?)。</p> <h2 id="learn-to-write">Learn to Write</h2> <p>作者在这部分给出了许多关于写作的建议。</p> <p>Three steps to better writing:</p> <ol style="list-style-type: decimal"> <li>Get it down An outline, then each section.</li> <li>Revise it <ol style="list-style-type: decimal"> <li>Instead of using demonstratives "this" and "that" or pronouns like "it" or "they", use the specific names of things, enven if it seems slightly redundant.</li> <li>Name objects, concepts and procedures as specifically as you can.</li> <li>Avoid acronyms, shorthand, jargon unless you are <strong>absolutely</strong> sure the reader will understand it. (这个必须吐槽,OneNote上各种缩写满天飞)</li> <li>Organize thoughts into paragraphs. (一段表达一个意思,避免所有内容都杂糅在一段里)</li> <li>Write as if the readers are getting more and more rushed for time as they read. 尽量开门见山</li> </ol></li> <li>Polish it</li> </ol> <p>后面如何写Email和如何写技术文档可以单独找两本书来读了。</p> <h2 id="interview-potential-co-workers">Interview Potential Co-Workers</h2> <p>这部分可以跳过,帮助有限。</p> <h2 id="be-responsive-and-productive">Be Responsive and Productive</h2> <p>Visibility 除了体现在代码上之外,还体现在 <em>Responsiveness</em>。学会处理各种interruption。</p> <h2 id="lead-the-team">Lead the Team</h2> <p>这部分体会没那么深,可能,还没到这层境界?</p> </body>Jun TianMon, 01 Apr 2019 00:01:58 GMTThe_Senior_Software_EngineerA_Guide_to_Wrap_a_C++_Library_with_CXXWrap.jl_and_BinaryBuilder.jl_in_Juliahttps://tianjun.me/essays/A_Guide_to_Wrap_a_C++_Library_with_CXXWrap.jl_and_BinaryBuilder.jl_in_Julia<body> <h1 id="a-guide-to-wrap-a-c-library-with-cxxwrap.jl-and-binarybuilder.jl-in-julia">A Guide to Wrap a C++ Library with CxxWrap.jl and BinaryBuilder.jl in Julia</h1> <p>The following parts are not covered here:</p> <ol style="list-style-type: decimal"> <li>How to write the wrapper code in C++. (It is detailed <a href="https://github.com/JuliaInterop/CxxWrap.jl">here</a>. And I find the <a href="https://github.com/JuliaInterop/libcxxwrap-julia/tree/master/examples">examples</a> are also very useful!)</li> </ol> <p>And you will learn the following parts after reading this post.</p> <ol style="list-style-type: decimal"> <li>How to quickly debug your code?</li> <li>The missing parts that are not documented in <a href="https://github.com/JuliaPackaging/BinaryBuilder.jl">BinaryBuilder.jl</a> and <a href="https://github.com/JuliaInterop/CxxWrap.jl">CxxWrap.jl</a></li> </ol> <h2 id="prepare">Prepare</h2> <p>First things first. Suppose you want to write a Julia wrapper for a C++ package (I'll take the one I wrote, <a href="https://github.com/PaddlePaddle/VisualDL">VisualDL</a>, for example). You need to fork that repo into your own account and clone that repo to your local computer. Then install necessary dependencies according to the document and make sure you can compile it successfully.</p> <p>The next step is to write the wrapper code. Usually you would like to add a flag in the <code>CMakeLists.txt</code> file to signafy whether to build the Julia wrapper or not. Like <a href="https://github.com/findmyway/VisualDL/blob/julia/CMakeLists.txt#L37">this</a></p> <pre><code>option(WITH_JULIA "Compile VisualDL with Julia" OFF)</code></pre> <p>Then make a seperate folder containing all your source codes and corresponding <code>CMakeLists.txt</code>. And include that folder in the root <code>CMakeLists.txt</code> file. Like <a href="https://github.com/findmyway/VisualDL/blob/julia/CMakeLists.txt#L76-L78">this</a></p> <pre><code>if(WITH_JULIA) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/visualdl/julia) endif()</code></pre> <p>For the simplest case, only a <code>CMakeLists.txt</code> file and <code>your_wrapper_code.cc</code> are needed. Like <a href="https://github.com/findmyway/VisualDL/tree/julia/visualdl/julia">this</a></p> <p>Following the instructions from <a href="https://github.com/JuliaInterop/CxxWrap.jl">CxxWrap.jl</a>, you should find it easy to write the wrapper codes. If the project you are working on already has a python wrapper, I strongly suggest you to take look at it first. And it will save you a lot of time.</p> <p>Then you need to specify how to build your target in the <code>CMakeLists.txt</code>, for <a href="https://github.com/findmyway/VisualDL/blob/julia/visualdl/julia/CMakeLists.txt">example</a>:</p> <pre><code># 1. find JlCxx find_package(JlCxx REQUIRED) # 2. add libraries and dependencies add_library(im ${PROJECT_SOURCE_DIR}/visualdl/logic/im.cc) add_library(sdk ${PROJECT_SOURCE_DIR}/visualdl/logic/sdk.cc ${PROJECT_SOURCE_DIR}/visualdl/utils/image.h) add_dependencies(im storage_proto) add_dependencies(sdk entry binary_record storage storage_proto eigen3) add_library(vdljl SHARED vdljl.cc) add_dependencies(vdljl im entry tablet sdk storage protobuf eigen3) # 3. specify targets target_link_libraries(vdljl PRIVATE JlCxx::cxxwrap_julia entry binary_record im tablet storage sdk protobuf ${OPTIONAL_LINK_FLAGS}) # 4. install install(TARGETS vdljl RUNTIME DESTINATION lib ARCHIVE DESTINATION lib LIBRARY DESTINATION lib)</code></pre> <h2 id="local-debug">Local Debug</h2> <p>Now you have finished all the necessary changes to the original package, you may want to get the compiled library.</p> <p>Let's install <code>CxxWrap</code> in Julia first. Enter the package mode and add <code>CxxWrap</code></p> <pre class="language-julia"><code>(v1.1) pkg&gt; add CxxWrap</code></pre> <p>Now you have <code>CxxWrap</code> and the underlying <a href="https://github.com/JuliaInterop/libcxxwrap-julia"><code>libcxxwrap-julia</code></a> installed. We can print the library path and the cmake file path:</p> <pre class="language-julia"><code>julia&gt; using CxxWrap julia&gt; CxxWrap.jlcxx_path "/home/tj/.julia/packages/CxxWrap/KcmSi/deps/usr/lib/libcxxwrap_julia.so" julia&gt; julia&gt; readdir(joinpath(dirname(CxxWrap.jlcxx_path), "cmake", "JlCxx")) 5-element Array{String,1}: "FindJulia.cmake" "JlCxxConfig.cmake" "JlCxxConfigExports-release.cmake" "JlCxxConfigExports.cmake" "JlCxxConfigVersion.cmake"</code></pre> <p>What we are interested in here is the the path of <code>joinpath(dirname(CxxWrap.jlcxx_path), "cmake", "JlCxx")</code> (Here is the <code>/home/tj/.julia/packages/CxxWrap/KcmSi/deps/usr/lib/cmake/JlCxx</code>). Now we can compile the package with <code>JlCxx_DIR</code> properly set:</p> <pre><code>$ mkdir build $ cd build $ cmake -DWITH_JULIA=ON -DJlCxx_DIR=/home/tj/.julia/packages/CxxWrap/KcmSi/deps/usr/lib/cmake/JlCxx .. $ make $ make install</code></pre> <p>Then you can load the compiled library in the Julia REPL for testing:</p> <pre class="language-julia"><code>module VisualDL using CxxWrap @wrapmodule("/absolute/path/to/your/lib") function __init__() @initcxx end end using .VisualDL</code></pre> <h2 id="binarybuilder">BinaryBuilder</h2> <p>In order to leverage the BinaryBuilder, we create an independent repo (for example, <a href="https://github.com/findmyway/VisualDLBuilder">VisualDLBuilder</a>) to build the tarballs. Be careful with the following lines:</p> <ol style="list-style-type: decimal"> <li>Don't forget to specify the <code>compiler_abi</code> field in the platforms like <a href="https://github.com/findmyway/VisualDLBuilder/blob/master/build_tarballs.jl#L7">this</a> here, if your code doesn't compile with old gcc.</li> <li>For the <a href="https://github.com/findmyway/VisualDLBuilder/blob/master/build_tarballs.jl#L10"><code>sources</code></a> in the <code>build_tarballs.jl</code>, you can specify an absolute local path pointing to the modified package above for debugging. After making sure that everything works fine, you make a PR then ask the repo owner to tag a new release. And then change this variable into the <code>url =&gt; hash</code> form.</li> <li>Do not forget to run <code>make install</code> at the end of <a href="https://github.com/findmyway/VisualDLBuilder/blob/master/build_tarballs.jl#L19">script</a>. Seriously!</li> <li>In the <code>dependencies</code> <a href="https://github.com/findmyway/VisualDLBuilder/blob/master/build_tarballs.jl#L26">part</a>, remember to add both CxxWrap and Julia.</li> </ol> <p>As for the <code>.travis.yml</code> <a href="https://github.com/findmyway/VisualDLBuilder/blob/master/.travis.yml#L21">file</a>, for now you need to specify the <code>MbedTLS</code> to version <code>0.6.6</code> due to the <a href="https://github.com/JuliaWeb/MbedTLS.jl/issues/193">error</a>.</p> <p>Althought there's a helper function in BinaryBuilder.jl named <code>setup_travis</code> to help you set up the deploy step, I never succeed. So I'd suggest you to install <a href="https://github.com/travis-ci/travis.rb#installation">travis cli</a> and run <strong>travis login --pro</strong> first!!! Then <code>travis setup releases</code>.</p> <h2 id="the-julia-wrapper-package">The Julia Wrapper Package</h2> <p>This is the final step. You create a new package. Add the <code>CxxWrap</code> as your dependency. Rename the build file you get by BinaryBuilder to <code>build.jl</code> and put it into the <code>deps</code> folder. And you expect to get the <code>deps.jl</code> after running <code>julia deps/build.jl</code>. Unfortunately, you'll see an error like this:</p> <pre><code>ERROR: LoadError: LibraryProduct(nothing, ["libvdljl"], :libvdljl, "Prefix(/home/tianjun/tmp/visualdl/deps/usr)") is not satisfied, cannot generate deps.jl!</code></pre> <p>The reason is that we need the shared package of <code>jlcxx</code>. So remember to put <code>using CxxWrap</code> in the first line of <code>build.jl</code>. Then everything should work as you wish.</p> </body>Jun TianMon, 04 Mar 2019 00:35:31 GMTA_Guide_to_Wrap_a_C++_Library_with_CXXWrap.jl_and_BinaryBuilder.jl_in_JuliaLearn_You_Some_Reinforcement_Learninghttps://tianjun.me/essays/Learn_You_Some_Reinforcement_Learning<body> <h1 id="learn-you-some-reinforcement-learning">Learn You Some Reinforcement Learning</h1> <p>Here I will list everything that is helpful with a short note while implementing the reinforcement learning package <a href="https://github.com/Ju-jl/Ju.jl">Ju.jl</a> in Julia.</p> <h2 id="slides">Slides</h2> <ul> <li><p><a href="/static/essay_resources/Learn_You_Some_Reinforcement_Learning/./slides/MSRA_RL_Essentials.pdf">An Introduction to Reinforcement Learning</a></p> <p>A concise introduction to RL by <a href="http://research.microsoft.com/users/taoqin/">Tao Qin</a> from MSRA.</p></li> </ul> <h2 id="papers">Papers</h2> <ul> <li><p><a href="/static/essay_resources/Learn_You_Some_Reinforcement_Learning/./papers/An_Introduction_to_Deep_Reinforcement_Learning.pdf">An Introduction to Deep Reinforcement Learning.pdf</a></p> <p>A very comprehensive introduction. The most useful chapter to me is <strong>Benchmarking Deep RL</strong>.</p></li> <li><p><a href="/static/essay_resources/Learn_You_Some_Reinforcement_Learning/./papers/Revisiting_the_Arcade_Learning_Environment.pdf">Revisiting the Arcade Learning Environment.pdf</a></p> <p>Because we will do a lot of experiments in the Atari environment, it’s better to read this paper first to avoid some potential pitfalls.</p></li> <li><a href="/static/essay_resources/Learn_You_Some_Reinforcement_Learning/./papers/DQNNaturePaper.pdf">Human-level control through deep reinforcement learning</a></li> <li><a href="/static/essay_resources/Learn_You_Some_Reinforcement_Learning/./papers/Playing_Atari_with_Deep_Reinforcement_Learning.pdf">Playing Atari with Deep Reinforcement Learning</a></li> <li><a href="/static/essay_resources/Learn_You_Some_Reinforcement_Learning/./papers/Deep_Reinforcement_Learning_with_Double_Q-learning.pdf">Deep Reinforcement Learning with Double Q-learning</a></li> <li><a href="/static/essay_resources/Learn_You_Some_Reinforcement_Learning/./papers/Prioritized_Experience_Replay.pdf">Prioritized Experience Replay</a></li> <li><p><a href="/static/essay_resources/Learn_You_Some_Reinforcement_Learning/./papers/Distributed_Prioritized_Experience_Replay.pdf">Distributed Prioritized Experience Replay</a></p></li> </ul> <h2 id="codes">Codes</h2> <ul> <li><p><a href="https://github.com/higgsfield/RL-Adventure">RL-Adventure</a></p> <p>A good start point. Although some implementations are not that efficient, this repo provides many code snippets that are easy to understand.</p></li> </ul> <h2 id="books">Books</h2> <ul> <li><p><a href="http://incompleteideas.net/book/the-book-2nd.html">Reinforcement Learning: An Introduction</a></p> <p>It is said that everyone needs to take a look at this book before digging into reinforcement learning. And I have reproduced the figures with <a href="https://github.com/Ju-jl/Ju.jl">Ju.jl</a> at <a href="https://github.com/Ju-jl/ReinforcementLearningAnIntroduction.jl">ReinforcementLearningAnIntroduction.jl</a></p></li> <li><p><a href="http://www.athenasc.com/dpbook.html">Dynamic Programming and Optimal Control</a></p> <p>I only finished the first volume. The latest edition has covered a lot of recent research results. It’s a good supplementary of <a href="http://incompleteideas.net/book/the-book-2nd.html">Reinforcement Learning: An Introduction</a>.</p></li> </ul> </body>Jun TianSun, 27 Jan 2019 15:42:07 GMTLearn_You_Some_Reinforcement_LearningAn_Introduction_to_Flux.jlhttps://tianjun.me/essays/An_Introduction_to_Flux.jl<body> <h1 id="详解flux.jl">详解Flux.jl</h1> <p>本文将详细介绍Julia语言中的一个深度学习库——<a href="http://fluxml.ai/">Flux.jl</a>,目的是在理解其内部结构之后,能在其之上做个性化定制。</p> <h2 id="核心概念">核心概念</h2> <h3 id="trackedarray"><code>TrackedArray</code></h3> <p><code>TrackedArray</code>类型用来对最基本的数组做封装。我们知道,深度学习框架带来的最大好处之一就是不用手写梯度反传的函数,其实现是基于这样一个事实,对于一类基本的函数,其梯度的计算方式是已知的,于是通过链式法则可以实现对整个网络中的每个参数进行更新。因此,一个<code>TrackedArray</code>类型应该至少包含</p> <ol type="1"> <li>数据,即数组当前的值</li> <li>映射函数,描述当前数据是根据怎样的函数(以及对应的参数)得到的,从而方便进一步反传</li> <li>梯度,当前数据的梯度</li> </ol> <p>然后我们看看源码中的<a href="https://github.com/FluxML/Flux.jl/blob/master/src/tracker/lib/array.jl#L9-L15">定义</a></p> <pre class="language-julia"><code>struct TrackedArray{T,N,A&lt;:AbstractArray{T,N}} &lt;: AbstractArray{T,N} tracker::Tracked{A} data::A grad::A TrackedArray{T,N,A}(t::Tracked{A}, data::A) where {T,N,A} = new(t, data) TrackedArray{T,N,A}(t::Tracked{A}, data::A, grad::A) where {T,N,A} = new(t, data, grad) end</code></pre> <p>可以看到,代码的定义与我们的直觉相符,这里的<code>tracker</code>字段就是用来<strong>记录</strong><code>data</code>字段是怎么得到的。再具体看下<code>Tracked{T}</code>的<a href="https://github.com/FluxML/Flux.jl/blob/master/src/tracker/Tracker.jl#L32-L40">定义</a>:</p> <pre class="language-julia"><code>mutable struct Tracked{T} ref::UInt32 f::Call isleaf::Bool grad::T Tracked{T}(f::Call) where T = new(0, f, false) Tracked{T}(f::Call, grad::T) where T = new(0, f, false, grad) Tracked{T}(f::Call{Nothing}, grad::T) where T = new(0, f, true, grad) end</code></pre> <p><code>ref</code>先不管,<code>isleaf</code>用来标志当前是否是叶子节点(叶子节点有特殊含义,需要作区分,原因是一旦遇到叶子节点,就不需要继续反传了),<code>grad</code>用来记录梯度(初看似乎跟<code>TrackedArray</code>中有重复?其实从数据结构上来看,需要有这么个地方做缓存,后面会解释。),最关键的<code>f</code>记录了作用的函数以及其参数,下面是<code>Call</code>的<a href="https://github.com/FluxML/Flux.jl/blob/master/src/tracker/Tracker.jl#L19-L22">定义</a>:</p> <pre class="language-julia"><code>struct Call{F,As&lt;:Tuple} func::F args::As end</code></pre> <p>其实就是为了弥补Julia中函数的类型没有携带参数类型。</p> <p>总结一下:</p> <ul> <li><code>TrackedArray</code> 包含 <code>data</code>, <code>grad</code> 和 <code>tracker</code> 三个字段,分别用于记录当前节点上的数据,梯度以及当前节点是如何根据其它节点计算得到的。</li> <li><code>tracker</code> 是一个 <code>Tracked{T}</code> 类型,其中最核心的一个字段是计算函数<code>f::Call</code>。</li> </ul> <h3 id="前向计算">前向计算</h3> <p>现在我们了解了<code>TrackedArray</code>的组成,但是具体怎么做前向计算的呢?</p> <h4 id="通过param构造trackedarray">通过<code>param</code>构造<code>TrackedArray</code></h4> <p>万丈高楼平地起!</p> <p>在julia中,数组一般以<code>AbstractArray</code>的形式存在,而在Flux中,为了存储前向计算函数和梯度信息,需要将这类<code>AbstractArray</code>数据构造成<code>TrackedArray</code>,然后才能对不同的<code>TrackedArray</code>做前向计算。<code>param</code><a href="https://github.com/FluxML/Flux.jl/blob/master/src/tracker/Tracker.jl#L106-L107">函数</a>就是用来构造<code>TrackedArray</code>的。</p> <pre class="language-julia"><code># https://github.com/FluxML/Flux.jl/blob/master/src/tracker/Tracker.jl#L107 param(xs::AbstractArray) = TrackedArray(float.(xs)) # https://github.com/FluxML/Flux.jl/blob/master/src/tracker/lib/array.jl#L32 TrackedArray(x::AbstractArray) = TrackedArray(Call(), x, zeros(x)) # https://github.com/FluxML/Flux.jl/blob/master/src/tracker/Tracker.jl#L25 Call() = Call(nothing, ()) # https://github.com/FluxML/Flux.jl/blob/master/src/tracker/lib/array.jl#L29 TrackedArray(c::Call, x::A, Δ::A) where A &lt;: AbstractArray = TrackedArray{eltype(A),ndims(A),A}(Tracked{A}(c, Δ), x, Δ) # https://github.com/FluxML/Flux.jl/blob/master/src/tracker/Tracker.jl#L39 Tracked{T}(f::Call{Nothing}, grad::T) where T = new(0, f, true, grad)</code></pre> <p>可以看到,对于原始的数组类型,用<code>param</code>封装成<code>TrackedArray</code>之后,主要就是在外层套了一个<code>nothing</code>的<code>f</code>,并置为了叶子节点。</p> <figure> <img alt="the param function" src="/static/essay_resources/An_Introduction_to_Flux.jl/Resources/img/param.png"/><figcaption>the <code>param</code> function</figcaption> </figure> <p>这里用一个例子来确认下:</p> <pre class="language-julia"><code>julia&gt; w1 = [1 2; 3 4] 2×2 Array{Int64,2}: 1 2 3 4 julia&gt; w1_tracked = param(w1) Tracked 2×2 Array{Float64,2}: 1.0 2.0 3.0 4.0 julia&gt; w1_tracked.data 2×2 Array{Float64,2}: 1.0 2.0 3.0 4.0 julia&gt; w1_tracked.grad 2×2 Array{Float64,2}: 0.0 0.0 0.0 0.0 julia&gt; w1_tracked.tracker.f Flux.Tracker.Call{Void,Tuple{}}(nothing, ()) julia&gt; w1_tracked.tracker.isleaf true</code></pre> <p>理解<code>TrackedArray</code>这个基础概念之后,接下来看看如何对<code>TrackedArray</code>做运算,毕竟在Flux的世界里,深度学习的网络就是靠<code>TrackedArray</code>构造的(其实还有<code>TrackedReal</code>等等)。在Flux的<a href="https://github.com/FluxML/Flux.jl/blob/master/src/tracker/lib/array.jl">array.jl</a>文件中,做了大量对<code>TrackedArray</code>的封装工作,目的主要有:</p> <ol type="1"> <li>将<code>TrackedArray</code>看作普通的<code>AbstractArray</code>,把系统对Array的一些操作绑定到<code>data</code>字段上</li> <li>重载一些基本的数组运算,通过<code>track</code>函数将对<code>TrackedArray</code>的运算结果封装成新的<code>TrackedArray</code></li> </ol> <p>粗略看一下<a href="https://github.com/FluxML/Flux.jl/blob/master/src/tracker/lib/array.jl">array.jl</a>便可发现,几乎所有的运算都靠<code>track</code><a href="https://github.com/FluxML/Flux.jl/blob/master/src/tracker/Tracker.jl#L50-L53">函数</a>来实现转换:</p> <pre class="language-julia"><code>function track(f, xs...; kw...) # 前向计算,得到结果y和反向求导函数back y, back = _forward(f, xs...; kw...) # 生成新的Tracked结构 track(Call(back, tracker.(xs)), y) end</code></pre> <p>第一次看这个代码的时候一脸懵,因为全局搜索<code>_forward</code>你会发现,源代码中总共只出现了三处。但这不符合直觉啊,所有的<code>TrackArray</code>运算都会用到<code>_forward</code>函数,因此应该有很多重载函数才对。后来才发现,<code>_forward</code>函数是通过一个<code>@grad</code><a href="https://github.com/FluxML/Flux.jl/blob/master/src/tracker/Tracker.jl#L55">宏</a>定义的(这个宏稍稍有点复杂,核心是定义前向和反向求导的计算方式),在重载(或者定义)每个计算函数的时候,通过这个<code>@grad</code>宏同时把前向计算和梯度计算函数都定义了。</p> <pre class="language-julia"><code>macro grad(ex) @capture(shortdef(ex), (name_(args__) = body_) | (name_(args__) where {T__} = body_)) || error("Need a function definition") T == nothing &amp;&amp; (T = []) isexpr(name, :(::)) || (name = :(::typeof($name))) insert!(args, 1+isexpr(args[1], :parameters) , name) @q(Tracker._forward($(args...)) where $(T...) = $body) |&gt; esc end</code></pre> <p>这里很骚气地用了<a href="https://github.com/MikeInnes/MacroTools.jl">MacroTools</a>中的<code>@capture</code>宏,说白了,就是用来构造上面的<code>_forward</code>函数,看个例子就明白了</p> <pre class="language-julia"><code>@grad a * b = data(a)*data(b), Δ -&gt; (Δ*b, a*Δ) # 返回两个元素,第一个是前向计算的结果,第二个是反向计算梯度的函数</code></pre> <p>于是,前向计算的问题基本解决了,同时反向计算需要的偏导函数也准备好了。为了支持除了built-in计算方式之外的一些常见的函数(比如Softmax, Relu等),Flux单独开发了一个库<a href="https://github.com/FluxML/NNlib.jl">NNlib.jl</a>。</p> <h3 id="反向传播">反向传播</h3> <p>从代码逻辑上来讲,反向传播的实现很容易:</p> <ol type="1"> <li>从后往前计算偏导并更新<code>TrackedArray</code>的<code>grad</code>字段</li> <li>根据偏导更新weight</li> </ol> <p>不过有些小细节需要处理:</p> <pre class="language-julia"><code>function back!(x, Δ) istracked(x) || return scan(x) back(tracker(x), Δ) return end</code></pre> <p>这里,<code>scan</code>的目的是重置整个网络中的<code>grad</code>:</p> <pre class="language-julia"><code>function scan(x::Tracked) x.isleaf &amp;&amp; return ref = x.ref += 1 if ref == 1 scan(x.f) isdefined(x, :grad) &amp;&amp; (x.grad = zero_grad!(x.grad)) end return end</code></pre> <p>可以看到,<code>ref</code>的作用是引用计数(这里先<code>+=1</code>,后面<code>back</code>执行的时候会<code>-=1</code>),反向传播的时候,会将多次计数的<code>grad</code>进行累加,直至计算完成后再真正执行<code>back_</code>:</p> <pre class="language-julia"><code>function back(x::Tracked, Δ) x.isleaf &amp;&amp; (x.grad = accum!(x.grad, Δ); return) ref = x.ref -= 1 if ref &gt; 0 || isdefined(x, :grad) if isdefined(x, :grad) x.grad = accum!(x.grad, Δ) else x.grad = Δ end ref == 0 &amp;&amp; back_(x.f, x.grad) else ref == 0 &amp;&amp; back_(x.f, Δ) end return end</code></pre> <p>而<code>back_</code>的逻辑就很简单了:</p> <pre class="language-julia"><code>function back_(c::Call, Δ) Δs = c.func(Δ) (Δs isa Tuple &amp;&amp; length(Δs) &gt;= length(c.args)) || error("Gradient is not a tuple of length $(length(c.args))") foreach(back, c.args, data.(Δs)) end</code></pre> <p>计算偏导并迭代下去。</p> <p>接下来是<code>update!</code></p> <pre class="language-julia"><code>function update!(x, Δ) x.data .+= data(Δ) tracker(x).grad .= 0 return x end</code></pre> <p>可以看到,每次计算完会有一个置零的操作。</p> <p>对,如果手动更新的话,就这么简单了。</p> <p>不过大多时候,都有个Optimiser,如<code>SGD</code>,<code>Adam</code>等,来辅助更新梯度。Flux在这方面没有任何特殊之处,作者用一个<code>Param</code>结构来管理data和Δ。</p> <pre class="language-julia"><code>struct Param{T} x::T Δ::T en</code></pre> <p>然后,各个Optimizer管理自己的状态,<del>主要是通过闭包实现的</del>,最新版的不再使用闭包了,直接构造了<code>struct</code>。</p> <h3 id="layer">layer</h3> <p>layer对一些常见的模块做了封装,如RNN和CNN等。写起来确实简单,不过,感觉需要有benchmark测试下性能。</p> <h3 id="其它">其它</h3> <p>剩下的主要就是一些工具函数了,比如<code>treelike</code>,<code>onehot</code>等。</p> </body>Jun TianTue, 22 Jan 2019 21:18:20 GMTAn_Introduction_to_Flux.jl