异星工厂中的高品质产率分析

异星工厂的品质扩展包给游戏带来了新的生产规划挑战,比起像以前只能横向扩张工厂的规模,现在可以通过使用高品质的工厂和插件,大幅增加产量。为了最大化如传奇品质的高品质物品的生产,我们需要对高品质产率的计算和规划进行一些分析。 高品质物品生产蓝图 一般来说生产高品质的物品有两种方法,生产出目标物品然后慢慢回收提升质量,或者是直接从源头生产高品质的原料,然后直接生产高品质的物品。 这里先初步的设计了两个蓝图,一个是用于电星蓝图的高品质原料生产,通过读取当前物流网络的信号,自动的将多余物品拿去回收,不断的生产高品质的原料。对于原料级别的物品(如铁板、铜板),比起直接放入回收机拿到同样的物品,将其放入到组装机里生产更高级别的物品,然后再回收回来,可以获得更高的品质。 例如下图里的: Fig. 1. 回收原料生产高品质物品的例子. 这个蓝图设计成完全全自动的模式,能自动进行负载均衡,回收多余的物品。 回收机+组装机3: 1 0eNrVV1tv2zYU/i98XKnWki+NDWy/Ym+pIcgykxCRKJei3BmBAGdrkHZIU2xNt16yBtmwre2wG9AWa9LAP2aVpTztL+xQkmXZlmunAzYM8ANN8nzn9p1zqC3UsjzS4ZQJ1NhCbeKanHYEdRhqoPPDfvTD9tvT/eD1IDg6Ot+5Ex68DH96GA2eDPe/D0++DU8Gwa3fwtvPhi+3w7MvwtPD4OcH0Ysfr7FrLDi7N7z9LPj9fvjo5vDrV0H/4V9v9hLE8/6jaLAbHjxNIb7cC08HsEhwh7/effvH8+DO/WDnM5Cd0f04Ot6Ldp8Hnz+NXhxFZ2fBN7vR8fGf/U8RRtR0mIsaq1vIpevMsKRPzLAJOMOJ2TMtwpEP11ibfIIaqo8LLhquS+yWRdm6YhvmBmVEKeeENL+JEWGCCkoSVfGfns48uwXwDRVnSKagXaJ0uNOlbcIVc4O4AqzsOC5NQryFAFFZWblcxagHouXq5aovrZrC1MaYnIoNmwhqKqZjtygzhMOLMCs5RIzaFPxPzlUAgzAJ7lh6i2wYXQoAIDVG1uG4HaO58mCNclfoM3HqGBwWAvwqyfC4REpJUVcYkk0KBMLpEG6kbPoArHQ80fEWYflFESjjmUTOOl1XU6drky5DLKggdpIu2s4pvu4ZFqhRbKftWUTR4kQnV+Em0ynrgiEO7yWi438ACX6am6hRktYWnqhzT7S5J2W/6cNvNgCVLAAtz9pUKHMJF4VRyNGpNp38SgFyNUMeJW8Btcb4V2P8Ija5iUZ3ch3HMKk9DLyywIHp3QJG4FGaYJ853AbqSKW2vCNNbKAP4w1P0i4NelKrGIleR8J1KRdeLJfiJxRUPr4geKlUguw0Cylau3CR1ksTcfzXinTRtXzZXlm2bPGEDToj4obDN2PjOIGaE9wjGK1zQgB2zbBcMm3QrEx8LROSCMXd4Sp+Z/cu4HBtqkYg8rQz6ZOKRtt6AUX+9w1lZfmGUrlYQ6nnevV1D2beu2ZfeQq7iPUm5aZHhQ5BJbqzpuf4CR1jdJoVhE6Y0bIy/sTZje3Qs5YzpynJWM36o5Yyh9rAh3iULzV7ly7rFHaqpvP/Vpct8YnW9RGSr5WkfOe8iyZHb3FnU8d92fVaQKzYmwLHtWz+FqG8xytG+68b5ML54b//KwdScwM8kolZ1bCKwadyE8OyjIFycllNdtV4qeEa1tIVZEQua/I8uVrDFVyPN2FDlRfUJijIdCbpT92BlpV5Ejx+Mjx4BY/44N627GvtedNXyQIqfVo8NWMOpApTDuDRooHkKJ024vzBraD/BuXk8oaGpzej73aGhyfwMTD86vWsreo/sbWZ9GnZDrMvIowso0UsqfuXvvwiia0ECy5ltsCdLgQ3VlStafVKvV6tatVaWVN9/29ridSk 回收机: 1 0eNrFVt1u2zYUfhdeDlRnyVYSC1ifonepIcgS0xCRJZei3BmBAGdbkXZIW3RNsP6kDTJgW3/QrgPaYksa+GFWWfLVXmGHlCz/yXFbFJh9c8TD8/GcjzwfuY2abkjajHocGdvIIYHNaJtT30MGGh720t92Ppzejv/ux0dHw+u3kv23yYsHaf/J4PavyckvyUk/vvE6ufls8HYnObubnB7GL++nb36/7F324rN7g5vP4j8Pkoc/DH5+F/ce/Pt+L0Mc9h6m/d1k/2kO8dNectoHI8Md/HHnw1/P41sH8fXvIXZu7Ufp8V66+zz+8Wn65ig9O4sf76bHx//0vkMYUdv3AmSsb6OAXvEsV9TkWS0CxTBid22XMBTBNM8h3yJDjXDJRItRvtkinNqK7bea1LO4PxmlRQ2MiMcppyRbS350TS9sNQHfUHEBZXPaIUqb+R3qEKbYmyTgkGbbD2jG8TYCREVb1S/oGHXBVPXKBT0Sic2gavj8BMtQa5OYGDkUSMhmqAAHXHHmu2aTbFodChAQN8Y2we1IvEA4NigLuDlHVttiYHCorSIoCoiIWjrNbxNm5Yfsa8jcD3k7XI4+mYPpEX7NZ1syOUYcZHAWEoyuMEIAdsNyAzKb0HyMnFYECYQoKiO/+hnka/8T+aIFuCX6WVGnqf7qY6ku5aBWcDBaYRkDlelDXV50kLESTNvQVaMmFfvuQmKzoyWJY3Q1tFxIGsY9n7WgQrFoS8wRSRroGzkQCnZk9496GiPebQu4DmU8lHE5fsaUcunTwPUK/KIG/Muo1PGcKpXxt1awN31+YCcoJ62cEGdiF/MMlZbvhC5RNClb2VRRq0m9DqTis27OZfEFkLCl9hYyKhktJR51oUdb6KkKBholFKwUFDRDd0uhXkAYX8DDWBxr9dleqpVgr07QezUEyT1Xemuz6GWn1KbMDik3gVhi+hvmRFvBURx5i641iWc13UJhADTPxCzO8oLTLviar2itqMghdnaVnN961YWELRKfHHhGeSa/1j9WiKaa4iIS92UmOwuu5mntKW+Z+mcosPrJJHzp62+pqERfUqHVyniBsAkdKFFLmFmpj5VF7M41YEbszbqGVbyGqw0MFtgVrEmzhlelVQV3XbqruJpPrMkxVVpFyBoMgqk2ALzIO9v9nJI8ZzwyDCQlc0zR4OD1cPfO8P6NuPceiWLzQNC7Yk786Mlg/x28P+N7O+L15yy6D5RiNwUHy3VcsiKEU+hT8UDGyLWaBPYEJa964oEqlx8cnoCnA/VJeH1Fq9fqdV3X9JWqpkbRf5i4IY0= 另外一种模式是通过将低级的产物不断回收,不断循环直到生产出高品质的物品,如下所示。 Fig. 1. 回收产物生产高品质物品的例子. 回收机+组装机3: 1 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 回收机+电磁工厂: 1 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 回收机+铸造厂: 1 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 原理分析 如果是生产高品质的原料,比如说铜板,那么将铜板生产成铜线,就会考虑到底是使用产能插件好还是质量插件好。虽然质量插件提升了出现高品质物品的概率,但是产能插件大幅增加了产率,特别是高品质的高级产能插件,能提升相当大比例的产率,可能能生产出更多的高品质物品。 参考Figure 2,考虑以下的生产步骤: flowchart LR Input[(蓝箱输入)] --> Ass[组装机] --> |低品质| Rec[回收机] Ass --> |高品质| Output[/红箱输出/] Rec --> Ass 如果以上图表没有正确渲染,请刷新页面。 令每次的产物$X$都用百分比表示,其中1代表原料投入的数量,如果是0.1,则表示剩下了10%的物品。 $$ X = (x_{普通}, x_{罕见}, x_{稀有}, x_{史诗}, x_{传奇}) $$ 而每次经过组装机或者回收机,则是将原料于一个转换矩阵$T$相乘,输出则是新的产物的数量。不过在生产出传奇物品之后,会将这部分收集起来,不参与矩阵乘法。 其中$T$可以表示为 $$ \begin{align*} T &= \begin{pmatrix} T_{普通到普通} & T_{普通到罕见} & T_{普通到稀有} & T_{普通到史诗} & T_{普通到传奇} \\ 0 & T_{罕见到罕见} & T_{罕见到稀有} & T_{罕见到史诗} & T_{罕见到传奇} \\ 0 & 0 & T_{稀有到稀有} & T_{稀有到史诗} & T_{稀有到传奇} \\ 0 & 0 & 0 & T_{史诗到史诗} & T_{史诗到传奇} \\ 0 & 0 & 0 & 0 & T_{传奇到传奇} \\ \end{pmatrix} \\ &= (1 + P)\begin{pmatrix} Q_{普通到普通} & Q_{普通到罕见} & Q_{普通到稀有} & Q_{普通到史诗} & Q_{普通到传奇} \\ 0 & Q_{罕见到罕见} & Q_{罕见到稀有} & Q_{罕见到史诗} & Q_{罕见到传奇} \\ 0 & 0 & Q_{稀有到稀有} & Q_{稀有到史诗} & Q_{稀有到传奇} \\ 0 & 0 & 0 & Q_{史诗到史诗} & Q_{史诗到传奇} \\ 0 & 0 & 0 & 0 & Q_{传奇到传奇} \\ \end{pmatrix} \end{align*} $$ 其中$P$是额外产率,比如说用了产能插件之后会增加,而对于回收机来说,应该取值$P=-0.75$。而矩阵中的$Q_{*}$是指在给定总共的质量加成$Q$的情况下,计算出的 每一个品级到另一个品级的转换率。这部分的计算可以参考官方wiki[1]。 定义每次产物的的起始状态为 $$X_{0} = (1, 0, 0, 0, 0)$$ 则之后的每一次的产物状态可以表示为 $$X_{t} = X_{t-1}T_{回收机}T_{组装机}$$ 但是需要注意的是,每次进入到下个循环之前,需要移除掉传奇物品,然后将其加到最终的产物中。 代码实现 当流程确定之后,就可以通过Scallop[2]来实现这个过程。Scallop是一个用Rust实现的,基于符号推理的编程语言,可以用来解决这类问题。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 type production_after_assembler(bound iter: i32, common: f32, uncommon: f32, rare: f32, epic: f32, legendary: f32) type production_after_recycler(bound iter: i32, common: f32, uncommon: f32, rare: f32, epic: f32, legendary: f32) type prod_rate(f32) type qual_rate(f32) type assembler_base_prod(f32) type MachineType = ASSEMBLER | RECYCLER // 0: ASSEMBLER, 1: RECYCLER type n_slots(f32, MachineType) type n_qual(f32, MachineType) type n_prod(f32, MachineType) type base_prod(f32, MachineType) type P(f32, MachineType) type Q(f32, MachineType) type T_self(f32, MachineType) type T_c2l(f32, MachineType) type T_c2e(f32, MachineType) type T_c2r(f32, MachineType) type T_c2u(f32, MachineType) type T_u2l(f32, MachineType) type T_u2e(f32, MachineType) type T_u2r(f32, MachineType) type T_r2l(f32, MachineType) type T_r2e(f32, MachineType) type T_e2l(f32, MachineType) rel n_slots(4, RECYCLER) rel base_prod(-0.75, RECYCLER) // only give 1/4 material back rel base_prod(b_p, ASSEMBLER) = assembler_base_prod(b_p) rel n_qual(4, RECYCLER) rel n_prod(x, m) = n_qual(y, m) and x + y == n_s and n_slots(n_s, m) // total production and quality rate for each machine rel P(p_r * n_p + b_p, m) = n_prod(n_p, m) and base_prod(b_p, m) and prod_rate(p_r) rel Q(q_r * n_q, m) = n_qual(n_q, m) and qual_rate(q_r) // transform the quality to itself rel T_self(1 - q, m) = Q(q, m) // transform common to higher rel T_c2l(q * 0.001, m) = Q(q, m) rel T_c2e(x, m) = Q(q, m) and T_c2l(t, m) and q * 0.01 == x + t rel T_c2r(x, m) = Q(q, m) and T_c2e(t1, m) and T_c2l(t2, m) and q * 0.1 == x + t1 + t2 rel T_c2u(x, m) = Q(q, m) and T_c2r(t1, m) and T_c2e(t2, m) and T_c2l(t3, m) and q == x + t1 + t2 + t3 // transform uncommon to higher rel T_u2l(q * 0.01, m) = Q(q, m) rel T_u2e(x, m) = Q(q, m) and T_u2l(t, m) and q * 0.1 == x + t rel T_u2r(x, m) = Q(q, m) and T_u2e(t1, m) and T_u2l(t2, m) and q == x + t1 + t2 // transform rare to higher rel T_r2l(q * 0.1, m) = Q(q, m) rel T_r2e(x, m) = Q(q, m) and T_r2l(t, m) and q == x + t // transform epic to higher rel T_e2l(q, m) = Q(q, m) rel production_after_recycler(0, 1.0, 0.0, 0.0, 0.0, 0.0) // initial state rel production_after_assembler( iter, (1 + p) * (c * t_self), (1 + p) * (c * t_c2u + u * t_self), (1 + p) * (c * t_c2r + u * t_u2r + r * t_self), (1 + p) * (c * t_c2e + u * t_u2e + r * t_r2e + e * t_self), (1 + p) * (c * t_c2l + u * t_u2l + r * t_r2l + e * t_e2l) + l ) = production_after_recycler(iter, c, u, r, e, l) and T_self(t_self, m) and T_c2u(t_c2u, m) and T_c2r(t_c2r, m) and T_c2e(t_c2e, m) and T_c2l(t_c2l, m) and T_u2l(t_u2l, m) and T_u2e(t_u2e, m) and T_u2r(t_u2r, m) and T_r2l(t_r2l, m) and T_r2e(t_r2e, m) and T_e2l(t_e2l, m) and P(p, m) and m == ASSEMBLER and iter >= 0 rel production_after_recycler( iter + 1, (1 + p) * (c * t_self), (1 + p) * (c * t_c2u + u * t_self), (1 + p) * (c * t_c2r + u * t_u2r + r * t_self), (1 + p) * (c * t_c2e + u * t_u2e + r * t_r2e + e * t_self), (1 + p) * (c * t_c2l + u * t_u2l + r * t_r2l + e * t_e2l) + l ) = production_after_assembler(iter, c, u, r, e, l) and T_self(t_self, m) and T_c2u(t_c2u, m) and T_c2r(t_c2r, m) and T_c2e(t_c2e, m) and T_c2l(t_c2l, m) and T_u2l(t_u2l, m) and T_u2e(t_u2e, m) and T_u2r(t_u2r, m) and T_r2l(t_r2l, m) and T_r2e(t_r2e, m) and T_e2l(t_e2l, m) and P(p, m) and m == RECYCLER and iter >= 0 rel legendary(l, n_s, n_q, p_r, q_r, b_p) = production_after_recycler(20, c, u, r, e, l) and n_slots(n_s, ASSEMBLER) and n_qual(n_q, ASSEMBLER) and prod_rate(p_r) and qual_rate(q_r) and assembler_base_prod(b_p) 注意并没有直接在scallop代码中定义输入的数据,而是通过在和Python API中进行实现,方便一次编译,多次循环调用。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 from scallopy import ScallopContext from scallopy.collection import ScallopCollection import time import pandas as pd # number of module slots of the "assembler" machine possible_n_slots = [4, 5, 6, 8] # all possible productivity module rates possible_prod_rate = sorted(list({ 0.04, 0.05, 0.06, 0.07, 0.10, # tier 1 0.06, 0.07, 0.09, 0.11, 0.15, # tier 2 0.10, 0.13, 0.16, 0.19, 0.25, # tier 3 })) # all possible quality module rates possible_qual_rate = sorted(list({ 0.01, 0.013, 0.016, 0.019, 0.025, # tier 1 0.02, 0.026, 0.032, 0.038, 0.05, # tier 2 0.025, 0.032, 0.04, 0.047, 0.062, # tier 3 })) # possible assembler base productivity 0 or 50% possible_assembler_base_prod = [0.0, 0.5] # number of quality modules will be 0..n_slots # build the inputs inputs = { "n_slots": [], "prod_rate": [], "qual_rate": [], "n_qual": [], "assembler_base_prod": [] } for n_slots in possible_n_slots: for prod_rate in possible_prod_rate: for qual_rate in possible_qual_rate: for n_qual in range(n_slots + 1): for assembler_base_prod in possible_assembler_base_prod: inputs["n_slots"].append([(n_slots, 0)]) inputs["prod_rate"].append([(prod_rate,)]) inputs["qual_rate"].append([(qual_rate,)]) inputs["n_qual"].append([(n_qual, 0)]) inputs["assembler_base_prod"].append([(assembler_base_prod,)]) print("Total number of inputs: ", len(inputs["n_slots"])) ctx = ScallopContext() ctx.import_file("model.scl") t0 = time.time() ctx.compile() print("Time: ", (t1 := time.time()) - t0) result = [ ScallopCollection(ctx.provenance, coll) for coll in ctx._internal.run_batch([["legendary"]] * len(inputs["n_slots"]), inputs, parallel=True) ] output = [list(*each) for each in result] print("Time: ", (t2 := time.time()) - t1) # save to csv output = [list(each[0]) for each in output] df = pd.DataFrame(output) df.to_csv("output.csv", index=False, header=["output", "n_slots", "n_qual", "prod_rate", "qual_rate", "assembler_base_prod"]) 在代码中,预先定义了每一种组合(不同的产能插件和品质插件的组合,还有是否有50%自带产能),然后编译Scallop模型,把每一种可能性都放进去模拟,计算出传奇物品的总产量。 结果分析 通过以上计算的结果,画了一系列热力图,来展示不同的组合下,为了最大化传奇物品的产量,应该选择用多少产能插件和品质插件。 Fig. 3. 最优的品质插件数量,4插槽组装机,无基础产能加成 (组装机3型) Fig. 4. 最优的品质插件数量,5插槽组装机,50%基础产能加成 (电磁工厂) Fig. 5. 最优的品质插件数量,8插槽组装机,无基础产能加成 (低温工厂) 结论 从上图可见,最大化传奇物品的产量,并不是直接堆质量插件即可,而是需要根据产能插件和品质插件提供的加成来灵活选择,主要是考虑产能插件的数值。具体的最优化选择可以以上面几张图作为参考。 [1] "Quality", Factorio Wiki, 2024. https://wiki.factorio.com/Quality. [2] J. Huang et al., "Scallop: From Probabilistic Deductive Databases to Scalable Differentiable Reasoning", in Advances in Neural Information Processing Systems, Curran Associates, Inc., 2021, pp. 25134–25145. [Online]. Available: https://proceedings.neurips.cc/paper_files/paper/2021/hash/d367eef13f90793bd8121e2f675f0dc2-Abstract.html #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2024/12/31
articleCard.readMore

比之前更进一步的终极看番工具栈

之前的文章中讨论了如何在Windows上配置最佳的视频播放器用于看番,然而这个方法具有很大的局限性。这篇文章将介绍如何搭建一个更加完善的系统,为了获得真正的快乐终极看番体验。 背景 之前的文章中介绍了如何在 Windows 系统中搭建一个拥有超分辨率和插帧的视频播放器,这个能保证很强的画面效果,但是这套看番的方法依然有很多局限性。 基于本地: 由于这个系统是打开本地的文件进行播放,所以当需要远程访问的时候就会有很大的问题。而且由于本地磁盘容量的限制,也只能存储有限的番剧。 缺少自动化: 由于这个系统是基于 MPC-HC 的,所以没有自动化的功能,比如自动下载番剧,自动更新番剧等等。 缺少番剧管理: 整个播放体验是基于 Windows 的文件系统,并没有使用一些软件来提升观看的体验,也没有类似于海报墙的东西。 落后的技术: 之前基于SVP的插帧已经比较落后,和现在SoTA的RIFE[1]插帧相比,画质和效果都有很大的差距。 解决方案 为了解决以上问题,我们需要一个更加完善的系统,这个系统将会搭载在一个上24小时开机的家庭服务器上,这个服务器可以是NAS,也可是软路由,或者是存算分离的Linux服务器。 考虑到不折腾,本人选择了自己DIY一个基于低功耗x86平台的NAS。考虑到折腾软路由可能会让网络没那么稳定,就没有打算在这套系统里使用软路由。家里现在是一台ASUS的硬路由,一台NAS,一台高性能的Linux服务器用于游戏服务器和爬虫脚本等等,然后是一台台式机用于日常游戏和学习。这样的设计是为了让每个设备都有自己的用途,不会因为一台设备的问题导致其他设备无法使用。这篇文章主要会讨论NAS上的部署。 硬件准备 这次是购买了一台蜗牛星际B型,带一个ITX主板+赛扬J6412。到手之后,换了一个靠谱的海韵Flex电源,又插了2根8G DDR4内存,确保之后的docker和vm不会有性能瓶颈。并且把机箱风扇换成了猫扇,确保散热效果。 硬盘方面,用了一个512G的老固态做缓存池,然后是4块8TB的机械硬盘做主存储。 Fig. 1. 硬件配置, 照片拍摄于刚刚买到基础的蜗牛星际机器时,很多硬件改装还没有开始 系统选择 NAS系统现在主要是四个,黑群晖,OMV[2],TrueNAS[3] 和 Unraid[4]。 黑群晖: 有很多自带软件,图形化界面对新手友好,但是感觉有点太花里胡哨了,系统的兼容性不是很好,也不方便升级,而且对存储系统的管理也很麻烦。 OMV: 一个基于debian的开源系统,相当于是一个debian系统+web管理界面。优势是可以很方便的进terminal进行操作,但是缺点是对文件系统用起来麻烦,而且对docker,vm的支持也不是很好。但是如果愿意折腾,OMV应该是比较强大的。还有一个是OMV的维护者感觉不是很靠谱,对这个系统的未来前景很担忧。 TrueNAS scale: 也是基于debian的开源系统,专门为NAS设计,有非常强大的存储系统管理,非常的专业,性能也很强。但是缺点是对docker的支持很糟糕,这个k3s用起来非常反人类。尽管这个系统可能在2024年下半年支持普通的docker,但是现在还没到时候。 Unraid: 一个商业系统,有很好的docker和vm支持,存储系统比较灵活,社区也很活跃。但是缺点是存储系统的性能比较差,而且还要收费。 综合考虑,自己不拿这个NAS作为热访问的存储,所以对性能需求没有那么高,只要能拖得动4K视频就行,所以最后选择了方便部署服务的Unraid。 Unraid Unraid系统安装非常简单,买了一个U盘,然后下载Unraid的安装器,把系统安装在U盘上,然后就能用U盘引导启动了,不需要把系统安装在硬盘上。 Unraid的存储系统是基于JBOD(阵列)和Unraid(池)的。阵列是允许一系列不同大小的硬盘组合成一个大存储空间,并且用1~2块最大的硬盘用于校验,如果阵列中有少于校验盘数量的硬盘挂了,那么数据还能恢复。但是由于阵列的写入就是一块盘,而且还需要实时计算校验,所以性能比较差。而池是允许组成ZFS raid的,可以保证性能,也可以不用raid就单个盘。 Unraid本身是支持多级存储的,比如说可以用一个池来作为缓存池,然后把阵列当成主存储。这样的话,写入的时候会先写入缓存池,然后再定时把缓存池的数据写入主存储。通过这样的设计,IO性能就会提升很多。并且不用保持主存储的硬盘长时间开启,也可以节省电费。 所以,我就把512G的固态硬盘作为缓存池,然后把4块8TB的机械硬盘作为主存储(1块校验盘+3块数据盘=24TB)。这样的设计可以保证不会有IO瓶颈,也可以保证数据的安全。 除此之外,通过插件,unraid也可以在webui里把SMB/NFS之类的远程磁盘挂载到本地。比如说现在在这个Unraid NAS上挂载了一个老家的威廉通NAS。 Fig. 2. Unraid的硬盘配置 这里推荐一些必装插件: Dynamix Cache Directories: 可以把文件夹的metadata缓存到内存里 Mover Tuning: 可以调整mover从缓存池移动文件到主存储阵列的行为,比如说只移动3天前的文件,更加合理 Swapfile for unRAID 6.9: swap文件,不然内存容易爆。标题说是6.9,但是最新版本也可以用 Unassigned Devices: 用于挂载远程存储,比如说SMB/NFS,还能挂载USB设备等等 unbalanced: 用于在阵列中移动文件,从阵列中的一个磁盘里移动文件到另一个磁盘等等 User Scripts: 用于设定一些定时脚本, 比如说用rsync备份文件,或者用rclone同步文件等等 基础服务 虚拟网络 尽管有公网ipv4,但是为了避免把端口暴露在公网上,现在主要用虚拟网络(ZeroTier[5]和Tailscale[6])来进行内网穿透。现在在NAS上部署了Tailscale,通过route,可以让这两个虚拟网络的设备互通。 稍微画了一个不专业的网络拓扑图。 Fig. 3. 网络拓扑图(建议使用亮色模式观看) 文件服务 首先是aria2[7]和qBittorrent[8]用于NAS上的文件下载。Aria2建议使用这个docker[9],这个docker里面包含了一些开箱即用的设置,比较方便。至于webui,可以使用AriaNg[10]。qBittorrent可以使用官方docker,然后用peerbanhelper服务[11]来ban掉吸血雷等客户端。 如果使用qb卡死,最好降低同时做种和下载的数量。 其次是文件同步,建议使用Syncthing[12],这个软件可以在不同设备之间同步文件,而且是p2p的,不需要服务器。可以用这个来同步一些文件和文件夹。 顺便提一下,用Syncthing去同步git仓库,可能会导致git仓库损坏,所以不建议这样做。 用于文件分享的话,主要用Alist[13],这个软件可以把本地的文件夹 (和网盘里的文件) 分享出去,然后可以通过webui下载文件。 用于NAS的文件管理,建议使用FileBrowser[14],这个软件可以在webui里管理文件,比如说上传文件,删除文件等等。 Fig. 4. FileBrowser的webui 服务访问 为了能访问NAS上数不清的服务,可以使用Homepage[15],这个软件可以把所有的服务整合到一个页面上,然后可以通过这个页面看到服务运行的情况,也可以访问所有的服务。 现在已经部署了一个Homepage,欢迎参观。https://portal.controlnet.space 另外也可以部署一个glances[16],用于监控系统的运行情况。 Fig. 5. Homepage的webui 追番自动化 没有人喜欢需要手动去找动画资源,然后手动下载手动整理的,所以需要部署一些工具让它尽可能的自动化。 首先是考虑了以下的一个工具链: 蜜柑计划[17]: 一个动画资源的聚合网站,可以通过RSS订阅动画资源 AutoBangumi[18]: 一个追番自动化的开源工具,通过RSS订阅动画资源,然后自动调用qb下载,并且自动按照规则整理文件 Jellyfin[19]: 一个开源的媒体服务器,可以把本地的动画资源刮削好,并且通过web或者别的客户端访问 蜜柑计划和 AutoBangumi 都是基于bangumi的元数据,其中蜜柑计划会完全采用和bangumi一样的动画标题来整理BT种子,另外蜜柑计划也会根据字幕组/压制组进行分类。这些种子都会作为RSS进行广播。在蜜柑计划中,可以注册账号,然后订阅自己感兴趣的番剧,然后这些番剧将会被聚合到一个RSS订阅中。 AutoBangumi 有两种使用方式: 订阅和收集。订阅是通过观测蜜柑计划的聚合RSS订阅,然后根据规则自动下载新出现的种子,这样可以保证一直保持新番更新,而不用手动去找。收集是通过输入RSS订阅,根据规则下载全部种子,用于下载已经完结的老番。 AutoBangumi 在下载种子之后,会自动的把文件重命名为{番剧名}/Season {季}/{番剧名} S{季}E{集}.{后缀名},这样方便Jellyfin刮削。 例如, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ├── 怪人的沙拉碗 │ ├── Season 1 │ │ ├── 怪人的沙拉碗 S01E01.mp4 │ │ ├── 怪人的沙拉碗 S01E02.mp4 │ │ ├── 怪人的沙拉碗 S01E03.mp4 │ │ ├── 怪人的沙拉碗 S01E04.mp4 │ │ ├── 怪人的沙拉碗 S01E05.mp4 │ │ ├── 怪人的沙拉碗 S01E06.mp4 │ │ ├── 怪人的沙拉碗 S01E07.mp4 │ │ ├── 怪人的沙拉碗 S01E08.mp4 │ │ ├── 怪人的沙拉碗 S01E09.mp4 │ │ ├── 怪人的沙拉碗 S01E10.mp4 │ │ ├── 怪人的沙拉碗 S01E11.mp4 │ │ ├── 怪人的沙拉碗 S01E12.mp4 媒体服务器考虑了plex[20], emby[21]和Jellyfin。plex和emby的收费内容很多,体验很差。只有Jellyfin是免费开源的,而且生态也很强大,所以选择了Jellyfin。Jellyfin可以通过webui来管理媒体库,也可以通过客户端来观看。 Jellyfin有一个bangumi插件[22],可以通过bangumi的API来刮削动画的元数据,因为下载的时候是根据bangumi的元数据下载的,所以通过这个方式可以保证绝大多数动画被刮削到Jellyfin里。但是bangumi的元数据相比于TMDB[23]和TVDB[24]来说还是有很多问题,比如说对不同季之间的合并做的很差。而且bangumi没有除了封面之外的图片,比如说背景图,logo等等。 所以最后用tinyMediaManager[25]手动进行元数据匹配来兜底。一般情况下,刮削好元数据之后,视频文件夹就会像以下这样,以后如果用别的播放器或者媒体服务器打开,也能确保一样的元数据。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 ├── 怪人的沙拉碗 │ ├── Season 1 │ │ ├── folder.jpg │ │ ├── metadata │ │ │ ├── 怪人的沙拉碗 S01E01.jpg │ │ │ ├── 怪人的沙拉碗 S01E02.jpg │ │ │ ├── 怪人的沙拉碗 S01E03.jpg │ │ │ ├── 怪人的沙拉碗 S01E04.jpg │ │ │ ├── 怪人的沙拉碗 S01E05.jpg │ │ │ ├── 怪人的沙拉碗 S01E06.jpg │ │ │ ├── 怪人的沙拉碗 S01E07.jpg │ │ │ ├── 怪人的沙拉碗 S01E08.jpg │ │ │ ├── 怪人的沙拉碗 S01E09.jpg │ │ │ └── 怪人的沙拉碗 S01E10.jpg │ │ │ └── 怪人的沙拉碗 S01E11.jpg │ │ │ └── 怪人的沙拉碗 S01E12.jpg │ │ ├── season.nfo │ │ ├── 怪人的沙拉碗 S01E01.mp4 │ │ ├── 怪人的沙拉碗 S01E01.nfo │ │ ├── 怪人的沙拉碗 S01E02.mp4 │ │ ├── 怪人的沙拉碗 S01E02.nfo │ │ ├── 怪人的沙拉碗 S01E03.mp4 │ │ ├── 怪人的沙拉碗 S01E03.nfo │ │ ├── 怪人的沙拉碗 S01E04.mp4 │ │ ├── 怪人的沙拉碗 S01E04.nfo │ │ ├── 怪人的沙拉碗 S01E05.mp4 │ │ ├── 怪人的沙拉碗 S01E05.nfo │ │ ├── 怪人的沙拉碗 S01E06.mp4 │ │ ├── 怪人的沙拉碗 S01E06.nfo │ │ ├── 怪人的沙拉碗 S01E07.mp4 │ │ ├── 怪人的沙拉碗 S01E07.nfo │ │ ├── 怪人的沙拉碗 S01E08.mp4 │ │ ├── 怪人的沙拉碗 S01E08.nfo │ │ ├── 怪人的沙拉碗 S01E09.mp4 │ │ ├── 怪人的沙拉碗 S01E09.nfo │ │ ├── 怪人的沙拉碗 S01E10.mp4 │ │ ├── 怪人的沙拉碗 S01E10.nfo │ │ ├── 怪人的沙拉碗 S01E11.mp4 │ │ ├── 怪人的沙拉碗 S01E11.nfo │ │ ├── 怪人的沙拉碗 S01E12.mp4 │ │ └── 怪人的沙拉碗 S01E12.nfo │ ├── backdrop.jpg │ ├── clearlogo.png │ ├── fanart.jpg │ ├── folder.jpg │ └── tvshow.nfo Fig. 6. Jellyfin的番剧元数据界面 除了动画之外的影视剧 有些时候除了动画番剧之外,也想看下电影和美剧。这时候用 Servarr[26] 全套来做自动化就很方便了,反而日本动画因为格式不统一且高度以来字幕组,导致用这套系统效果很差,但是对西方的电影和美剧就很好。 这套系统包括了 请求电影和美剧下载的前端 Jellyseerr[27]。 自动搜索并下载电影的自动化后端 Radarr[28], 用于美剧的 Sonarr[29]。 用于给自动化后端提供 indexer 的 Prowlarr[30]。 用于给自动化后端作为下载工具的 Aria2 和 qBittorrent。 在 Jellyseerr 中,需要设置好 Radarr 和 Sonarr 的 API key,然后就可以通过 Jellyseerr 来搜索电影和美剧,然后自动下载。 Fig. 7. 在Jelyyseerr中可以订阅几乎任何的电影或电视剧 但是想要做到自动化,需要在 Jellyseerr, Radarr, Sonarr 和 Prowlarr 中设置好 indexer 和下载工具,这样才能保证自动化的流程。 用这套系统去自动化动画下载是很困难的,因为动画的资源很杂,而且不同字幕组之间的格式也很不同,元数据很混乱。动画自动化只建议使用AutoBangumi。 Fig. 8. Jellyseerr中设置Radarr和Sonarr服务器 Fig. 9. Prowlarr中订阅indexer,并设定Radarr和Sonarr服务器 Fig. 10. Radarr中设置媒体库和下载工具 (Sonarr略) 这样,在 Jellyseerr 请求电影和美剧之后,就可以在 Radarr 和 Sonarr 中看到请求的电影和美剧,然后就可以自动下载了。然后在 Jellyfin 中就可以看到这些电影和美剧。 本地播放器 尽管可以在服务器上自动下载和整理番剧,但是依然需要通过本地的播放器软件来观看。为了使用先进的插帧和超分辨率技术,现在建议使用mpv[31]。mpv是一个开源的播放器,支持很多的插件,比如说插帧,超分辨率等等。 为了方便使用,可以使用MPV_lazy[32],这是一个mpv的整合包,里面包括了很多的插件,基本上不需要自己再另外准备什么了。这个整合包里提供了一些vs脚本,可以用于调整插帧和超分的参数,也可以自己在上面改。比如说, 1 2 3 4 5 6 7 8 9 10 # MAIN.vpy import k7sfunc as k7f clip = video_in if container_fps < 60: clip = k7f.RIFE_NV(clip, lt_d2k=True, model=46, ext_proc=False, t_tta=False, fps_in=container_fps, fps_num=2, fps_den=1, sc_mode=1, gpu=0, gpu_t=2, st_eng=False, ws_size=8) if clip.height < 1200: clip: Any = k7f.FMT_CTRL(clip, h_max=720, fmt_pix=0) clip: Any = k7f.ESRGAN_NV(clip, lt_hd=True, model=5005, gpu=0, gpu_t=2, st_eng=False, ws_size=0) 这样就可以在播放的时候同时用RIFE插帧和ESRGAN超分辨率了。 其次是需要在客户端上装一个后台服务来接管jellyfin播放,这样可以在jellyfin网页上点击播放之后,自动打开mpv。这里推荐油猴插件embyToLocalPlayer[33]。 总结 本文介绍了如何建立一个自动化的家庭服务器系统,用于自动化下载,管理,观看番剧和其他媒体内容。在这里分享了一些自己的经验,希望对大家有所帮助。 参考文献 [1] Z. Huang, T. Zhang, W. Heng, B. Shi, and S. Zhou, “Real-Time Intermediate Flow Estimation for Video Frame Interpolation,” in Proceedings of the European Conference on Computer Vision (ECCV), S. Avidan, G. Brostow, M. Cissé, G. M. Farinella, and T. Hassner, Eds., Cham: Springer Nature Switzerland, 2022, pp. 624–642. doi: 10.1007/978-3-031-19781-9_36. [2] "openmediavault - The open network attached storage solution", Openmediavault, 2024. https://www.openmediavault.org/ [3] "TrueNAS - Welcome to the Open Source Storage Era", TrueNAS, 2024. https://www.truenas.com/ [4] "Unraid | Unleash Your Hardware", Unraid, 2024. https://unraid.net/ [5] "ZeroTier | Global Networking Solution for IoT, SD-WAN, and VPN", Zerotier, 2024. https://zerotier.com/ [6] "Tailscale · Best VPN Service for Secure Networks", Tailscale, 2024. https://tailscale.com/ [7] "aria2", Aria2, 2024. https://aria2.github.io/ [8] "qBittorrent Official Website", Qbittorrent, 2024. https://www.qbittorrent.org/ [9] "P3TERX/Aria2-Pro-Docker", GitHub, 2024. https://github.com/P3TERX/Aria2-Pro-Docker [10] "mayswind/AriaNg", GitHub, 2024. https://github.com/mayswind/AriaNg [11] "PBH-BTN/PeerBanHelper", GitHub, 2024. https://github.com/PBH-BTN/PeerBanHelper [12] "Syncthing", Syncthing, 2024. https://syncthing.net/ [13] "Home | AList Docs", Alist, 2024. https://alist.nn.ci/ [14] "Welcome | File Browser", File Browser, 2024. https://filebrowser.org/ [15] "Home - homepage", Homepage, 2024. https://gethomepage.dev/latest/ [16] "nicolargo/glances", GitHub, 2024. https://github.com/nicolargo/glances [17] "蜜柑计划 - Mikan Project", Mikan Project, 2024. https://mikanani.me/ [18] "AutoBangumi | 自动追番,解放双手!", Autobangumi, 2024. https://www.autobangumi.org/ [19] "The Free Software Media System | Jellyfin", Jellyfin, 2024. https://jellyfin.org/ [20] "Stream Movies & TV Shows | Plex", Plex, 2024. https://www.plex.tv/ [21] "Emby - The open media solution", Emby, 2024. https://emby.media/ [22] "kookxiang/jellyfin-plugin-bangumi", GitHub, 2024. https://github.com/kookxiang/jellyfin-plugin-bangumi [23] "The Movie Database (TMDB)", Themoviedb, 2024. https://www.themoviedb.org/ [24] "Welcome - TheTVDB.com", Thetvdb, 2024. https://www.thetvdb.com/ [25] "tinyMediaManager", tinyMediaManager, 2024. https://www.tinymediamanager.org/ [26] "Servarr | Servarr Wiki", Servarr, 2024. https://wiki.servarr.com/ [27] "Fallenbagel/jellyseerr", GitHub, 2024. https://github.com/Fallenbagel/jellyseerr [28] "Radarr", Radarr, 2024. https://radarr.video/ [29] "Sonarr - Dive in", Sonarr, 2024. https://sonarr.tv/ [30] "Prowlarr", Prowlarr, 2024. https://prowlarr.com/ [31] "mpv.io", mpv, 2024. https://mpv.io/ [32] "hooke007/MPV_lazy", GitHub, 2024. https://github.com/hooke007/MPV_lazy [33] "embyToLocalPlayer", GreasyFork, 2024. https://greasyfork.org/zh-CN/scripts/448648-embytolocalplayer #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2024/7/6
articleCard.readMore

探索数据潜力:预训练模型与Masked Autoencoder的表征学习之旅

表征学习(Representation Learning)是一个深度学习中的概念,通过预训练一个特征提取器,把原始数据转换成有意义的低维特征,让下游任务基于这些特征进行训练,从而降低了对数据和计算能力的需求。本文将介绍表征学习的基本概念,以及以Masked Autoencoder[1]为主的最新进展。 深度学习的民主化问题 在过去的几年中,深度学习在各个领域取得了显著的成就。然而,深度学习的成功很大程度上依赖于大量的标注数据,而这些数据的获取成本往往很高。例如,对于计算机视觉领域,ImageNet数据集[2]的标注成本高达200万美元。因此,如何利用少量的标注数据来训练一个高性能的模型,是一个很有意义的研究方向。评价一个深度学习模型是否好用的时候,一般会以两个方面进行对比。一个是性能,比如说分类任务的准确度,生成任务中的PSNR,SSIM等。另一方面是运行的效率,包括训练和预测的时间,以及模型的大小。 但是,以GPT-3为例,其参数量高达1750亿,训练时间长达355个GPU年(V100),数据集包含了4990亿个token,花了差不多460万美元[3]。这样的模型对于学术界和初创企业大部分人来说,最多只能通过API访问,不可能通过自己训练和微调来使用。这个就是深度学习的民主化问题,只有少数人能够享受到深度学习带来的好处。因此,如何在保证性能的同时,降低模型的大小和训练时间,是一个很有意义的研究方向。 提取特征 直觉上,通过提取有意义的特征可以降低数据的维度,使模型训练更加容易,包括减少了对数据的需求,也降低了模型的大小。这里列举几个在不同模态下常见的特征提取方法。 视觉 在ImageNet[2]上的预训练模型,提取倒数第二层的输出作为特征 通过torchvision库加载预训练模型 model_ft = models.resnet18(pretrained=True) OpenFace[4] 一个基于深度学习的人脸分析开源工具包 使用预训练模型提取人脸特征 光流(Optical Flow) 通过计算相邻帧之间的位移,来提取视频中的运动信息 例如,可以通过传统算法,比如卢卡斯-卡纳德法[5]来计算光流 也可以通过深度学习的方法来计算光流,例如GMFlowNet[6] 如下图所示 Fig. 1. 光流. Adapted from [7] 音频 梅尔频谱图 表示了音频信号在不同频率下的能量分布 通过对音频信号进行傅里叶变换,然后对频谱进行滤波,最后再进行傅里叶逆变换,计算得到的结果 把本来是1D的音频信号,转换成了2D的梅尔频谱图 梅尔频率倒谱系数(MFCC) 从梅尔频谱图中提取的特征 Fig. 2. 梅尔频谱图和MFCC. Adapted from [8] DeepSpeech[9] 一个用于语音识别的深度学习预训练模型,可以提取音频特征 文本 TF-IDF 通过计算单词在文档中的出现频率,来计算文本特征 Word2Vec[10] 通过预训练一个神经网络,把单词转换成低维的向量 如图所示。 Fig. 3. Word2Vec. Adapted from [10] BERT[11] 同样也是通过预训练一个神经网络,把单词转换成低维的向量 例如,可以使用transformers库[12]加载预训练模型 model = BertModel.from_pretrained('bert-base-uncased') 表征学习 如果将刚才提到的全部特征类型分个类,那么大致上可以分成两类。 一类是通过预训练模型提取的特征,例如ImageNet上的预训练模型,OpenFace,DeepSpeech,BERT等等 另一类是通过传统方法提取的特征,例如光流,梅尔频谱图,TF-IDF等等 AI教父Yosha Bengio在第一次ICLR会议上提到 Learning representations of the data that make it easier to extract useful information when building classifiers or other predictors. [13] 那么表征学习的意义就是通过学习数据的表示形式,使得在构建分类器或其他预测器时更容易提取有用信息。换句话说,就是需要想办法获得一个更好的特征提取器。 Fig. 4. 智能系统的发展 如上图所示,智能系统的发展经历了四个阶段。 第一个是基于规则的系统。 开发者通过手动编写代码,来实现系统的功能,比如说分类或者预测等等。 第二个是传统的机器学习。 开发者需要通过手动提取特征,然后再基于这些特征训练传统的机器学习模型,从特征映射到标签。 而第三个和第四个都属于表征学习。 开发者通过训练模型,让模型的中间部分学习到数据的表示形式,然后再基于这些表示形式进行预测。 而最新的第四个通过加深模型层数,可以让模型学习到更高层次的表示形式,从而提升模型的性能。 Fig. 5. 表征学习的架构 因为带有标签的数据集很贵很难获得,所以当我们训练模型的时候,一般不会从零开始直接使用有标签的数据集。相反,我们会先使用未标记的数据集,从零开始训练模型参数,将其训练到合理的水平。这一部分,我们称为预训练(pretraining)。 在预训练阶段,使用未标记的数据集从零开始训练模型参数,将其训练到合理的水平。一旦参数训练到了合适的水平,我们就可以使用标记数据集来对模型进行微调,以适应特定的下游任务。在这个阶段,我们不需要大量的标记数据,因为参数已经在第一个阶段训练到了较好的水平。 第一个阶段没有涉及任何具体任务,只是用一堆未标记的数据进行预训练。我们称之为“in a task-agnostic way”。第二个阶段是使用与任务相关的标记数据对模型进行微调。我们称之为“in a task-specific way”。 Masked Autoencoder 在了解了表征学习的概念之后,这里介绍一个领域内较为热门的前沿模型,Masked Autoencoder (MAE)[1]。 介绍 Fig. 6. Masked Autoencoder的介绍. Adapted from [1] 如图所示,MAE主要概念是遮盖输入图像的随机块并进行重建。它基于两个想法。 首先,研究人员提出了一个编码器-解码器架构,其中一个编码器只对图像的可见块子集进行操作。然后,一个简单的解码器可以从可见部分的潜在表示中重构原始图像。 其次,研究人员发现,如果他们遮盖了输入图像的大部分,比如约75%,实际上可以产生重要且有意义的自监督任务。通过结合这两个设计,我们可以高效地训练大型模型,将训练速度提高3倍或更多,同时提高准确性。 一些模型结构上的细节: 使用ViT作为编码器,tokenize输入图像并且进行处理成token 编码器的结构要大于解码器 重建损失在隐藏的token之间进行计算,而不是在所有token之间进行计算 实验结果 在ImageNet上的实验结果如下图所示: Fig. 7. MAE在ImageNet上的实验结果. Adapted from [1] 其中这里”scratch, original”代表从ViT原论文[14]拿到的结果。 “scratch, our impl”指的是一样的ViT结构,但是使用了作者自己的参数。主要是有更高的weight decay。 “baseline MAE”指的是从预训练的MAE模型开始,进行微调的结果。 这里看到相比于从零开始训练,使用MAE进行预训练,可以提升大约2%的准确率。 为了能更好的选择遮盖的比例,作者进行了一些实验,如下图所示: Fig. 8. MAE在不同遮盖比例下的实验结果. Adapted from [1] 上面这张图是在finetune下,也就是同时训练编码器和分类器。而下面这张图是在linear-probing下,也就是只训练分类器。 可以看到,当遮盖比例过高和过低时,都会导致准确率下降。而在75%左右的遮盖比例下,可以达到最好的效果。 除了遮盖的比例之外,怎么选择遮盖的区域也是一个问题。作者进行了一些实验,如下图所示: Fig. 9. MAE的不同遮盖策略可视化. Adapted from [1] Fig. 10. MAE的不同遮盖策略的实验结果. Adapted from [1] 其中random就是完全随机遮盖,block是选择一个方框区域进行遮盖,grid是有规律的进行网格状覆盖。 从结果可以看出,random是最好的。 扩展到视频 既然MAE可以用在图像上,那么我们能不能将其扩展到视频上呢?答案是肯定的。我们可以将视频看作是一系列的图像,然后使用MAE进行预训练。 去年NeurIPS 2022有个spotlight工作就叫VideoMAE[15],就是将MAE扩展到视频上。 Fig. 11. VideoMAE的结构. Adapted from [15] 如上图所示,总体的结构其实没有什么大改变,依然是通过遮盖的方式进行预训练。改变的地方主要是使用了3D的cube而不是2D的patch作为token。 实验结果 作者在Something-Something-V2[16]上进行了实验,如下图所示: Fig. 12. VideoMAE在Something-Something-V2上的实验结果. Adapted from [15] 可以看到效果还是不错的。作者在文章中提到,为了训练这个模型,他们使用了64个V100。 他们也讨论了最佳的遮盖方法,认为是tube masking是最好的,即在空间维度上进行遮盖,而时间维度上保持一致。 Fig. 13. 不同遮盖策略可视化. Adapted from [17] 有趣的是,另一篇论文MAE-ST[17],也是在NeurIPS 2022上发表的,也是将MAE扩展到视频上。而且方法和结构都非常类似,但是他们认为最佳的遮盖方法是随机遮盖。 Fig. 14. 两篇论文关于不同遮盖策略的实验结果,左边来自于VideoMAE,右边是MAE-ST. Adapted from [15][17] VideoMAE的作者认为,使用tube masking可以避免信息在时间维度上的泄露。这个泄露导致编码器看到了本来被遮盖的信息,导致性能受到影响。而MAE-ST的作者认为纯粹的随机遮盖可以防止模型对信息产生bias,从而提高了性能。 个人认为VideoMAE使用的数据集要小于MAE-ST所使用的,所以可能是数据集规模的区别导致了不同的结论。 Fig. 15. 两篇论文在不同遮盖比例下的实验结果,左边来自于VideoMAE,右边是MAE-ST. Adapted from [15][17] 而关于遮盖的比例,两篇论文都认为90%是最好的。 总结 本文探讨了表征学习在深度学习中的重要性,并且介绍了MAE作为目前比较前沿的表征学习方法。MAE的核心思想是通过遮盖的方式,让模型学习到更多的信息,并且后来社区将其扩展到了视频领域。通过使用这些预训练的模型,普通的开发者也可以使用更少的数据和计算资源,将这些模型迁移到自己的任务上,从而获得更好的效果。 参考文献 [1] K. He, X. Chen, S. Xie, Y. Li, P. Dollár, and R. Girshick, “Masked Autoencoders Are Scalable Vision Learners,” in Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition, 2022, pp. 16000–16009. [2] A. Krizhevsky, I. Sutskever, and G. Hinton, “ImageNet Classification with Deep Convolutional Neural Networks,” Neural Information Processing Systems, vol. 25, pp. 1097–1105, Jan. 2012, doi: 10.1145/3065386. [3] S. Negi, “GPT-3: A new step towards general Artificial Intelligence,” Medium, Oct. 20, 2020. https://medium.com/@messisahil7/gpt-3-a-new-step-towards-general-artificial-intelligence-66879e1c4a44 [4] T. Baltrušaitis, P. Robinson, and L.-P. Morency, “OpenFace: An open source facial behavior analysis toolkit,” in 2016 IEEE Winter Conference on Applications of Computer Vision (WACV), Lake Placid, NY, USA: IEEE, Mar. 2016, pp. 1–10. doi: 10.1109/WACV.2016.7477553. [5] B. D. Lucas and T. Kanade, “An iterative image registration technique with an application to stereo vision,” in Proceedings of the 7th international joint conference on Artificial intelligence, in IJCAI’81, vol. 2. San Francisco, CA, USA: Morgan Kaufmann Publishers Inc., Aug. 1981, pp. 674–679. [6] S. Zhao, L. Zhao, Z. Zhang, E. Zhou, and D. Metaxas, “Global Matching With Overlapping Attention for Optical Flow Estimation,” in Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition, 2022, pp. 17592–17601. [7] A. Ranjan, D. T. Hoffmann, D. Tzionas, S. Tang, J. Romero, and M. J. Black, “Learning Multi-human Optical Flow,” Int J Comput Vis, vol. 128, no. 4, pp. 873–890, Apr. 2020, doi: 10.1007/s11263-019-01279-w. [8] “librosa.feature.mfcc — librosa 0.8.0 documentation,” librosa.org, 2023. https://librosa.org/doc/main/generated/librosa.feature.mfcc.html [9] A. Hannun et al., “Deep Speech: Scaling up end-to-end speech recognition.” arXiv, Dec. 19, 2014. doi: 10.48550/arXiv.1412.5567. [10] T. Mikolov, K. Chen, G. Corrado, and J. Dean, “Efficient Estimation of Word Representations in Vector Space,” in 1st International Conference on Learning Representations, ICLR 2013, Workshop Track Proceedings, Y. Bengio and Y. LeCun, Eds., Scottsdale, Arizona, USA, 2013. doi: 10.48550/arXiv.1301.3781. [11] J. Devlin, M.-W. Chang, K. Lee, and K. Toutanova, “BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding,” in Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, Volume 1 (Long and Short Papers), Minneapolis, Minnesota: Association for Computational Linguistics, Jun. 2019, pp. 4171–4186. doi: 10.18653/v1/N19-1423. [12] “🤗 Transformers,” huggingface.co, 2023. https://huggingface.co/docs/transformers/index [13] Y. Bengio, A. Courville, and P. Vincent, “Representation Learning: A Review and New Perspectives,” IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 35, no. 8, pp. 1798–1828, Aug. 2013, doi: 10.1109/TPAMI.2013.50. [14] A. Dosovitskiy et al., “An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale,” in International Conference on Learning Representations, 2021. [15] Z. Tong, Y. Song, J. Wang, and L. Wang, “VideoMAE: Masked Autoencoders are Data-Efficient Learners for Self-Supervised Video Pre-Training,” in Advances in Neural Information Processing Systems, Oct. 2022. [16] R. Goyal et al., “The ‘Something Something’ Video Database for Learning and Evaluating Visual Common Sense,” in Proceedings of the IEEE International Conference on Computer Vision, 2017, pp. 5842–5850. [17] C. Feichtenhofer, haoqi fan, Y. Li, and K. He, “Masked autoencoders as spatiotemporal learners,” in Advances in neural information processing systems, S. Koyejo, S. Mohamed, A. Agarwal, D. Belgrave, K. Cho, and A. Oh, Eds., Curran Associates, Inc., 2022, pp. 35946–35958. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2023/6/9
articleCard.readMore

异星工厂原版原创蓝图分享

前一阵子在异星工厂(Factorio)上玩了一段时间,这个游戏的玩法是建造工厂,从最初的手工采矿到自动化采矿,再到自动化生产,最后到自动化科研,最终建造火箭逃离星球。为了下次更好的游戏体验,最近特地的制作了一些用于原版的蓝图,方便下次游戏时直接使用。 这次设计的这些蓝图,大小都是以区块(32 x 23)为基础的,有的占用半个区块(32 x 16),有的占用一整个区块(32 x 32)。在使用蓝图的过程中,摆放也是自动锁定到区块上,这样方便规划建设。 蓝图簿 1 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 超市模块 超市模块用于生产多种机器和建筑材料。 模块::超市 早期超市 (红瓶科技)。 尺寸: 输入: [上] 铜板 [左] 铁板 1 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 超市扩展::绿瓶 前中期扩展 (绿瓶科技) 用于超市。 放置于超市模块的底部。 尺寸: 32 x 32 输入: [左] 铁齿轮 [左] 铁板 [左] 电路板 [左] 铜板 [左] 钢材 [右] 石块 [右] 组装机1 [右] 石头 1 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 生产模块 生产模块用于生产可以在总线上运输的中间产物。 模块::插件1工厂 用于中期游戏(蓝瓶科技)的一级插件工厂。 产能: 54/min 尺寸: 32 x 16 输入: [上] 电路板 270/min [上] 集成电路 270/min 速度插件1工厂 1 0eNqlXE1P41YU/SuW1wn1+34vuy5aqYtKlaa7AVVOYsBSYke2MxqK+O99IVOgxIhzbhczCHBOrs+7n8eXPJbr3bE5DG03lavHctuMm6E9TG3flavyy6FptsXv/fa4awpV3NabqR8eitt+KPbttrir983VdXfd/THkSzanF60KZ3/at13+8Zf272ZVGF18z/+drvqtOxyn1XVXLIuvf/aHm+KXXbOZhr5rN8WmHTbHdip0qE4vf3PRz9tvdbfJZry7pFyUY1cfllO/vBva7cn47+VK+UX5cPrytCjr9djvjlOzPF13aLu7cjUNx2ZRtpu+G8vV18dybO+6end67fRwaPIdt1Ozz8hdvrP83Xi6/+X++f7LjNh22+b0Jk83i7LppnZqmzPO8zcPf3XH/boZ8gUvCNNQd+OhH6blutlNGfnQj+2Z3Wd7w5U7G3zlMv62HZrN+bf2aXEBq2nYCoE1MGxkrLU0LGSte4Gtx7HZr3f5YJf7enPfds1SX4LbH+D2GTxDt4eZo714G09zrRHrAw1rENhIcw1Zm2hYyFpVkWeolOwQFR6I/32Hz25A07gOwn0Nxdt6nJZtNzbDlH9zAas/MlfPwVra6zAaHI2L0eBRGjxFw2vw7frscPd1TudbAN1B6HwMYiTzQQiRrCuU5PSRuX4OVpEkp4+MnkXXqNHKUFbjNVBZ5vS05YGx43N0CvIQrqdxA4QbhHU7cClfRzaFBiS6daJTHUS3qYQ5ySNWG8UmUogM8xqFx2zucDf0+esndFx6yeKl6T4NBnOHafjWFGPdCpOUR5KJcWxmDRCsJ1iP/4f1IG3PyFg1kc7mGFOJT7qQ39iKB4ayo+Ub1Qjh8o1qgnCNMJurinMR+xqp43E9TvUz5qW7n03PyF3T3t2v++NwGsyVVjdzoE7q4LT5nncY7GADD4ydbKQ9RkFzu008MKQzuIqt+JcGz1U5J1BxMIO1sOZfws/abdiiD/JhBVV/xjdeClB/nD6oQM7xkhRGvRcW/kv4ucLjAlv5L/mZxY2C0i+kPtE1GbsHL6idWGbxSoAMuYvny6eChDVveGBIWvNWWpgNqY86OusaJMt4XngFKeelV5DySOdbjIkkLRMagQ8Vn2MxiVvxwBDRQdPZ1SCZKRhpUdAQvBV3m2RMBsfnbowhQRsLOougjwW9RdDIQpJeEDSykKQXK2nu9pyfREFnC1ET+SeUIDWCZ5SYxfxTStBi+YzJnqYkODFyJMGJsSMITkihiYLghBSaxE+ZkESbBLEIMZEEsYgxYaR9CSQuJ0u3UxjRgpkSI9rzwBjRQdqXQCppinQ7BcnfSTBBQsCqkoyQHttIkMyQAYMWDJERQxZMkQlDFo+RidzQqPg5MkGP4yvBIAnSHugMBZocpZk1YvhJouAlwSMkpQTTJca+UnTaSlB2UVqabiOGbyQinox9+cjJxq8SzJzgeUj6WtCHJI0tljkV39nqCkPmW1utsG026eCpNektb7aDPn+cp9X753nW3syiaqm78zcgWBQCz1eyKoQeML8spDWGzK8LaWxHVAe2MdCQ7ql05Fd7QZOliq2GBGFlKrbxACl5syeENwYzHgI8X1JG87vKGP1GquNqSARVxrKdh9YYsBN0BlL6PV2v0bsQFFUwy5gogAadRlBVsb1dZlnoX2RsPfrNthBZrx1Z7qymkzC2LG0Nn4RB2vlld5R2R6dfkAwvrRvg+n/gUy5ItuAPT0CyE51soQ1y5SpplbAYvhI3o2x0On4bHiVJ0uaCfzMiaXMxn3GCNheTB52gzcXUQSfdi9eR9RZB3wuywy/Hg+x4vuOFHjIozy8pgGR4QX8LkmHolAg9CFBeLBfRTuidIPpB4gV6Ecp84MMfU6K8QC7ChCif6NYNU5GJxaHAkRGUtA8CLReEJmi5ePTEtONg+UoPIksCEiRFEpCYcwc+IE2F+QgekJpExquk4ZAjHpGWRMbLpCOR+fUEg4mdxK6QJ23mR0uDab8Rj8L0IfJsfEd+OwFFJmJQkdBEVaxIaELvMRx0IgQfTUIL1hPmoG8W5084Wb351JdFuaszVP7Zjw96Wa2Kdx/88uv5g1/ypd+aYTwHSFQ2JB28y/9UeHr6B3/s69s= 节能插件1工厂 1 0eNqlXMtu40YQ/BWCZ8nhvDm65bABcggQILmtjYCiKHsAiRRIyljH8L+HsnZtYUVnq3oPhmGbKs7UTHfXFNt8zte7Y3PoUzvmq+d80wx1nw5j6tp8lX/ablOdmrZ+yv7oNsddk6lsW9Vj1z9l267P9mmT3Vf75ua2vW3/7KdL6tMnV5mzv+xTO/36r/Rvs8qMzr5kyp+u+r09HMfVbZsts89/d4e77NOuqce+a1Od1amvj2nMdChOH7+46NfNY9XWzeb7S/JFPrTVYTl2y/s+bU4z+JKvlF/kT6dvL4u8Wg/d7jg2y9N1h9Te56uxPzaLPNVdO+Srz8/5kO7banf67Ph0aKZpp7HZT8jtNLPpp2a7nUaYHtP4tNy/spBPuKndNKdbvdwt8qYd05iaM9rrD0//tMf9uumnC95wxr5qh0PXj8t1sxsn/EM3pDPRr6MON+512MWNm/A3qW/q81/ty+IKVtOwCoE1MGzJjNbSsNBo3RtsNQzNfr2blne5r+qH1DZLfQ1uv4LbV/AJOh0+XOCrm3macYPMIdCwGoEtacah0UYaFhqtKsiVVOpnllLhQfntPg6ahqZxLYT7HpbbahiXqR2afpz+cgWrP4LVc7DvYbnrJr4fqimnbf4H3X9Exiy6QwftqUHzcYitHR+I2NqVJMnxo1H7OfSIkhw/GvQcrC7oOIdI1orGhUjWGqVBGYoHvB4qSxFheWCMCUenoADhehrXQ7iBTW0ByRK6FEqDIKkn+j0Kj1N09/d9N33/Qfa4pn3xpj9PGnnuRqZgcyrEllHCQuAhdF6rQlvHGIL18mdYt2ySDUhyMU5YGTyE7ulUi7EepFJNFFqmpDM7Rn7kEzCUKG3BA0PEW160RgiXF60lhGuEKVgVko1i34N0OK6HsXpFvt7rZ2Im/LZJ9w/r7tifju1Kq7s5UCfd7MJJeH7zYIsceGBslUt69yjobG8jDwx5Ea5gFcc17lyZc0ogAmaG/FaPuuP4QUFympUB4BSMUAdcL+ksvOVNK8wHcgIlIKTes1rg+j5z9cgFoRi4ZmgWnveDQOojXZ8xQrygjmJD9kqADKUWz5dSBdlu3vDAkPHmLZ0MDRLqXmrNfoVnvVkvTVwamk2g8y3GUsknRGy/RB4Y2i+hkKYpjQR9UHR2NRCu5tMf5t7zD0xAoq1YeYoiKDg+j2PUCyQtyL1A04LkC0QtZPsFgaiFbL+ykOZbL9ktJf9UEyOoFDzXxAgSBCo2YsGzTWzE8rOnbE0lgYpRJAlUjCNBoEIuTikIVMjFifzpEzJZo6IlCoarpcoKcp6j4eMdWsAoOGtiC+hoiQL5tdFLlRXkd8bApymMaMHJEiNacLKEmFaF5GgZsD4GydnSY9CCw2XEkAWnyxJD5o+XEWoCKMTnyyhqGCm8xNyLgodNqgjSjFti1JV0pQDXRHDoxLbRRXsQ4e+J2FdKmoZLKPcoTZePiAELBC7IvvwoKgs2JTiLgiRJNC6WRJVE5IILwKtcrTBkXubqAuuEkx5ItRbtmYvOoh8//tPq++d/1t7Nomrp1pdOQ9BwBK61pOUIXWy+6UgbDJlvO9JYxynfeKQhr1hdtB7hUmFm0MDDKKUjW8vBSZhCKEK0wfB5AwncMRfdRrhWENJvDFvMNWSDK2OFKkQbDN/xfdwg/Z6u3SgnggKLDroUQGNpxggqLNavzDQafUPGOpatolMj1hFutVQUOFE1tdJ+Bg32z1s6/YJEOT49gruGb59Hd420g0FDrdjKlnSyxVroreCfWjCyHd9GD5J90WzEClNZKDm+wx6k30kkL8i/RPKCCyCQvJiF6ASSF3MQXZCm31K2Z2inSQfsP4t4pwkkn+g6Chz5nm5t0JCxrzzf24CSwVtKKBliS0m4Fb0TZAKQJYGnhNIU+FSAuVVeYClhZpWPtHjEfOsgPpKC+IIjKUZJ0FJlhHnKgiYkdOSWr/rgmCUBie1tSccRygcfkKbAdh8ekIZExoul5pBLvFg6EhmPRUsi8w1GBjNBiQ4jT46Z72UwmCdc8j6Qgbq3FdFNFElkIgYLEpqoioqEJnwgzUFHwggyJLSgnWEO+m5xfqfK6uJlM4t8V01Q0+++vlpmtcrm3jfz2/l9M9P1j00/nKOkVDZEHbybvlR4efkPTCQgtw== 产能插件1工厂 1 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 模块::插件1工厂2 用于后期游戏(紫瓶科技)的一级插件工厂。 产能: 622.5/min 尺寸: 32 x 32 输入: [上] 电路板 2037.5/min [上] 集成电路 2037.5/min [上] 电路板 1075/min [上] 集成电路 1075/min 速度插件1工厂2 1 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 节能插件1工厂2 1 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 产能插件1工厂2 1 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 模块::插件2工厂 用于中期游戏(蓝瓶科技)的二级插件工厂。 产能: 27/min 尺寸: 32 x 16sd 输入: [上] 处理器 135/min [上] 集成电路 135/min [上] 一级插件 108/min 速度插件2工厂 1 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 节能插件2工厂 1 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 产能插件2工厂 1 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 模块::电路板工厂 用于中期游戏(蓝瓶科技)的电路板工厂。 产能: 1080/min 尺寸: 32 x 32 输入: [上] 铜板 1620/min [上] 铁板 1080/min 1 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 模块::集成电路工厂 用于中期游戏(蓝瓶科技)的集成电路工厂。 产能: 180/min 尺寸: 32 x 32 输入: [上] 塑料 360/min [上] 铜板 360/min [上] 电路板 360/min 1 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 模块::处理器工厂 用于中期游戏(蓝瓶科技)的处理器工厂。 产能: 72/min 尺寸: 32 x 16 输入: [上] 硫酸 360/min [上] 电路板 1440/min [上] 集成电路 144/min 1 0eNqtXE1v3DYQ/SsLnVpgN9Hwm3vroQV6KFAg7SkxgrVWdoSupYU+griB/3slb7B2vGL1ZpxTYlt6Ih9nho8zJL9m14ehPLZV3Wfbr9m+7Iq2OvZVU2fb7M+2Kcquq+rb1VBX/epmV/RNe7+6adrVXbVf3e7uytVPE8CqK6qyLsqf33yoP9Tje/uhmEC2K6/e3lXj795V/5bblVarLyty00O/18eh336oV5vV+7+a49Xq3XC4GdqqWO2KEVu7/PTi+e+/Hsqib5t6fKKo2mIYG0TGvHzql/3n3diQ/fNnpkeyddbVu+Ombza3bbWfOvsl25JbZ/fTPw/rbHfdNYehLzfTc8ex09m2b4dynVVFU3fZ9v3XrKtu691here/P5YjQ1Vf3o3I9UjE+NPxzNdm4isbQat6X07febhaZ2XdV31VnqAef7j/WA9312U7PnAG6dtd3R2btt9cl4d+BD82XXUakFOT39hTm9/YEX9ftWVx+qt6WF/AKhhWpWDNDKyGYXUK1s3AGhjWcGAtDGs5sO5p3KtjeTKsZqj3l7DuG2w+ws4Aebh9jtO+AMN6Dmw8w97sun409H3Znjq+gJ5fWNb67EZTLMhmPkY53InI8QvC/S1wyKEnh+uOh6rvx19etjRBxxwe7mnECgyE+xrlLGDc20hzYg45HFixWoz7H7HiDgV2UNcQE5GNqxBc9eRsXb8r/tlUdVe2syasUu2d40ERexZSEO6Ts+26rry7Pkwz792u+FTV5UalZw09E4nG/1fH+Un88sMaJsqlPjk7W5vvY2s6hATcWpSVBmyVDtjN0CcitnIwN5FlRJ452EQ/arQD3KNzRMOGO/JDpUKAdc6PaJAtaeIDQ6FHK3ZIsxCuZuMaCPeFpy5HSgMNnP1OU6YFqp1XktotvG8W3vcL7/uF94M01hiBONSRrcChwTX5Agvu/1kwtPB+WHhfcVkMr2DRaJjFyGLRLLAQF1hY8gWiBYAlZzgL2xSAR538HJ4NtMwN/CiKUR75wFAYtTk7jHoIl5/2cBCuYitZD2UStFBxntA5qsMaaSj1giBgLVvRemRCs07aCycRn9azZwQ37/s2SGOwiP7IFs2Qvbpc2gsR/Y7YU0mCfqekap/vaU7z9T1k/M7wwzEU3pzlA0Px2Dl2PI4QrmfjBgg3cGV4gAYuCsM85a9ca/pnKZjhejTHR5TE8j+On6rL6vbTdTO0U1WBvL2aAyWpM72+P4otoQIS2LzmewBkUV7gs5ALeMuv8EB5Uc/3WYJyz95znYugfKsPbHF22eBZoxCXJiiXTHchZ4umyw/NMRSILWMwWwkv3BEuDGHoWqo2hPwbtmrCDClYto4BGXI8/gMPnb9eJaySKMiAgpYuWLFi0SsKcqAYzVFQq4eyq5GfBCUouxqly1YybDUdDZiCfGz6HACaA00C8Avzj+MzB+XBTGCyLUEYcLFxjUJ0rMyY5/wwmCCScgKzgSkmKVfC2Al2VgvhFQZv0GRkmgA4IZqGcOKVAD8SUC4prIN0ClKoqCHwq+sEJVGJ+FlUMhgysaW6xbbJ8BOpBOXAifg1dDJYm40wKoKjaIXw4FDy6+co414Y4UBeghAe5CXyxa3FtmzlAnWLmaIS1MtBPpQSQGMjqfhFc/IYsuEjOwzZ8gOVx8zDScWzf2XyjJ7teYFjpMcMU6pLwdGQClPMjHTOj5HYYGsSBjGw4VINi9GutVjevdpWtRFEUcxYtaDcgTLmBNDgWPNrHhQxZP6+UgoYcmTryIDtNs7RrEBMLF0WN9XYRQSFLuaTCJqfWcCIN1LNCsJLNStmkIs7beIis56fagC7LpWlYNejEB5rvc3htEGKWktw2iAJwa/iEVTGIyuo46HUCSp54KBbfi1PYWccLL+Yp7CDJNazBbLCTjk82yrDE8jf8Fkyg7FTxiW7MTtF8ffK+PTYAiebHL/IpxIHyMgJ63qg7TB2yESe7TgjLRkKSedX9tKkC4t5KOniAw8Sv3KCEh/qWIIaH8iRFxT5wEjs+VU+hSWYPb/Mp7CsuNdc+a4UdkLOSEO8ee268tm+meUdUUq/3BLl86tZVHEh5Af0iF+mV9B5OPKCqghqWhInxvwh8MsiCktkBoEPY9nXoNiehhVcgubLNCz9z9gt45LI822WnzA0kn0/FPgVftRivFBIgfCBL6TA0Y1iISUbg8jfHACSFIU5WBSev5hVWCEpCjaSgy4WBYtZMJRFQXYVpVqwmsWSq5GfXFVYRjiKV7OBr7pjBNOiKnFOQuU5mBZNIxCYFk0jSFefDruVQAvhPQaPnlNM998KAxbYQOk6E6TXoynGNAEBTTGmIaJYkPP9TpFk3YjRSZIj8pghkGDhGDFkfsVfBQyZfVD+ssmzdycQv+CvAnZbiQPu8Dnf65G/aOs6u6kO0yuXlrj+pqc+Htuqacdvjs+041o1YaP84r8KGHXC4j865BG5AynBn2Pydyhv5ulT/D0CoH0oqT7F6FMCfRqxhkv0KWZSSqJPQT4k+hQLe4qvT3WO8eHZN+ShyIF9mRKKHNn35IHIjPtoDBOZ2JfcaSj/qxg30vhkm+eRNfvuOQ0dW1JacKkbCm35F9Gh0IKL3VBoz79hCYUW5FrnoK/Wp0tEt88uYl1nh90INf7uj2Y/HMrt9tlNrH9PN7H+drqJdXzyc9l2J/8IZHxU3sVRj2v18PAfeKD2Ow== 模块::石油气工厂 用于中期游戏(蓝瓶科技)的石油气工厂。 产能: 9360/min 尺寸: 32 x 32 输入: [上] 原油 9600/min [上] 水 12720/min 1 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 模块::硫酸工厂 用于中期游戏(蓝瓶科技)的硫酸工厂。 产能: 12000/min 尺寸: 32 x 16 输入: [上] 石油气 18000/min [上] 铁板 240/min [上] 水 24000/min 1 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 模块::塑料工厂 用于中期游戏(蓝瓶科技)的塑料工厂。 产能: 1800/min 尺寸: 32 x 16 输入: [上] 煤 900/min [上] 石油气 18000/min 1 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 模块::电池工厂 用于中期游戏(蓝瓶科技)的电池工厂。 产能: 270/min 尺寸: 32 x 16 输入: [上] 铁板 270/min [上] 铜板 270/min [上] 硫酸 5400/min 1 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 模块::钢材工厂 用于中期游戏(蓝瓶科技)的钢材工厂。 产能: 135/min 尺寸: 32 x 16 输入: [上] 铁板 675/min 1 0eNqlnM1u20YUhV+F4KoFJJfzP6MHKJBFgQDpLjYKWRqrBGRSIKkiruF3LyWlthGR9Tm3i8CwI30anpn7yys+l/f7Yz50dTOUq+dym/tNVx+Gum3KVfllyHlfHPbrIRcP683Qdk/FQ9sVj/W22K0fc/HT6c1Fv6lzs8k/39w2t83nrt0eNyfAqlDG/fJYj3/8Uv+dV4XRxbdC+dOrPjWH47C6bYpl8fX39nBXfOra5vsn+XB+V7ko+2Z9WA7tctfV29PqvpUr5Rfl0+nHy6Jc3/ft/jjk5el1h7rZlauhO+ZFWW/api9XX5/Lvt416/3pvcPTIY+XVA/5cSQ34+rH3/rTBS7PH1uOwLrZ5tNnvNwtytwM9VDnC+b8y9MfzfHxPnfjC94Ah309DOPfFuWh7euLbueFxss6b9zI3dZd3lz+z74srnD6FTd066Y/tN2wvM/74RoabtwZWyFYA2PVd6xBsPYV+7Duh2Xd9LmbVEDPUfUE1b1S8358XVdvlg/Hrllv8jXYvgNPoDwtJ3TdgcZqBBtROT0jZ2KpGqGqCtYgMtIqRXMhbZVGZUhzWD+FNSzWQFhL2IBS/20EyqFrVIZaJG5dylJnINDuykHcSHMtxE0Cj+WnN0tXtG+Brl0rmgtdu9a0vWLrNTQXW6/IsuY2y/EWgK1SYFqYrLxpBYjLm5aHuIlNMTwSvQxvZZAMhrcySAaj2SAeIBkMi8XUtbTtYuo6moup69kg7pH4aAKLDRA20uEcW27ifQ4kr614MHQerKKdToK4muZGiGtYZ5YQc7NWkH6k6Yhm30zsOFbA3a5rx58fuLBrURevNfapuC+nPogvzTCNA+vSMI3p2ixC2ETIHf+H3I4v1yC5nWJ9XER8kaOrtQRhjST5mzEVZ2k/jC1SkFRieyVIKiF/6fikUkHdMMdnlQrqhzlJxab0TJPpzbb6430/rM/vnesCqnF1Ta53f963x+7UUlQm3E1RleSszq5R83uP7ZE3AjK0Sd7yuw/1F7zjwVCTyXs2wCuo2eb5hiOoRBSE+wktXgNQexxmIpCn+5CYNqGiuVDbNPCNSEzzoAUxX6Z5oLuTCur8BUtzoW5q4DuVIFgQ+jCTD0FAxs6JIPhBPaCQeDDUtYoV7f4cYopRSaK1m46Ekb/FhskaDQ/GZLW0h7OQrI7mYtvlec+JKRx4MKZwpP2ZQ9xOTDTXItxUiXLDGYtIive60OUnSdIJbViSJJ3QGUuCpBNqViVB0gm115KXeMc4cxYEmSZ2+ZEHY5efeKcArVhVfM8EW7KqZLXdzJ6pSmJn4EolhgbKK7C0hJEFphYxMl/gRWyaQmB3oBgCwwPF4Cs6TAzFl3QJAwtqOkxlxd8GB1XmJ0wU1GZUii/iIgYWVHEgWVLGgTJL6jjwbPCFnFYYma/kdIVNS9Gl3PWSJ01QS2q5M3uSpgX9qwlxP76BojRf3qFa0/XdNXhaa7rAQzfRC1pYQtn5mg+VnS76rq9g0ktpuuq7XvH0rKGo7Js1HsPXfaACRpCQgrtmBAkp6E0Nn5BqbJ7R8AmpxqZajaT403buRATiTpY2P97J8tXdJDWKju3sIgVzKuA+SSZVwI0SzKpobKhVMK2isbFWfl5FQ41HZS0fS0ExJPMrE3IAN1eU9XR4BeWhZ1i0w8CRD6ag7pJBFqHurqLjK9SuVPwwi7YYWPORFiRLwiFm/c4K0NhpcYJ4iDWVmBmXf8lYJ8wF2hlCM7jKRUkID3Pf9Ui8a8Wk9fzMNCitV7S/g+aQlafHpsE98/y3E1CV+dlpVGVHe7eAfQ2IHp/WHgMHUeI4ZxqeH5xGFZCkpNiuBUlKih21IEhJsT5rEKSkWJsu4IZnyDXjhqdJMh7tHEnGo50lyYKvuGLdUGKsxZNr5u8EgmuOuBGmWfKk54iEDVYkmjBCRaKJrFOTaCLrNCRaMFiNogU3JkCPF3lLNFi/693Uy0fPLjATzbm7xeUJCqt3j41YlPv1uLbxb7+12+M+F6tVcXlyxOfz8xx+vTw5YnzdX7nrL6Ycx3o36eDd+E+Fl5d/AAWdq1E= 模块::铁板工厂 用于中期游戏(蓝瓶科技)的铁板工厂。 产能: 675/min 尺寸: 32 x 16 输入: [上] 铁矿 675/min 1 0eNqlnN1u4lYUhV/F8lUrQerzfw4PUGkuKo3U3k2iisAJtURsZJtq0ijvXgMdJip2s9buRRSF4I/jdbx/vfFr+bg/5kNXN0O5ei23ud909WGo26ZclZ+6tikO+/WQi6f1Zmi7l+Kp7Yrnelvs1s+5+OF0bNFv6txs8o93981987lrt8fN6fhV4YP76bkeX/y1/iuvCqOLr4Xyp3d9ag7HYXXfFMviy2/t4aE4f1Lb5W/HlIuyb9aH5dAud129PS3ta7lSflG+nH69Lcr1Y9/uj0Nent53qJtduRq6Y16U9aZt+nL15bXs612z3p+OHV4OeTyfesjPI7kZ1376a/zM5fnsypFXN9t8+oi3h0WZm6Ee6nyhnP94+b05Pj/mbnzD9fj+sK+HYXxtUR7avr5odl5nvCzzzo3cbd3lzeV/9m1xg9NX3NCtm/7QdsPyMe+HW2i4c2dshWANjFX/YA2CtVfs07oflnXT525SAT1H1RNUd6Xm/fi+rt4sn45ds97kW7B9B55AeVpO6LwDjdUINqJyekbOxFI1QlUVrEFkpFWK5kLaKo3KkOawfgprWKyBsJawAaX+2wiUQ9eoDLVI3LqUpa6BQLsrB3EjzbUQNwk8lp/eLF3RvgU6d61oLnTuWtP2iq3X0FxsvSLLmtssx1sAtkqBaWGy8qYVIC5vWh7iJjbF8Ej0MryVQTIY3sogGYxmg3iAZDAsFlPX0raLqetoLqauZ4O4R+KjCSw2QNhIh3NsuYn3OZC8tuLB0PVgFe10EsTVNDdCXMM6s4SYm7WC9CNNRzT73cSOYwXc7bp2/P2BC7sVdXEtsU+VfTn1QXxphmkcWJeGaUzXZhHCJkLu+D/kdny5BsntFOvjIuKLHF2tJQhrJMnfjKk4S/thbJGCpBLbK0FSCflLxyeVCuqGOT6rVFA/zEkqNqVnmkzfbas/PvbD+nzsXBdQjatrcr3747E9dqeWojLhYYqqJNfq7Bo1v/fYHnkjIEOb5C2/+1B/wTseDDWZvGcDvIKabZ5vOIJKREG4n9DiGoDa4zATgTzdh8S0CRXNhdqmgW9EYpoHLYj5Ms0D3Z1UUOcvWJoLdVMD36kEwYLQh5l8CAIydp0Igh/UAwqJB0Ndq1jR7s8hphiVJFq76UgY+VtsmKzR8GBMVkt7OAvJ6mgutl2e95yYwoEHYwpH2p85xO3ERHMtwk2VKDecsYikeK8LnX6SJJ3QhiVJ0gldY0mQdELNqiRIOqH2WvIS7xhnrgVBpomdfuTB2Okn3ilAK1YV3zPBlqwqWW03s2eqktgZuFKJoYHyCiwtYWSBqUWMzBd4EZumENgdKIbA8EAx+IoOE0PxJV3CwIKaDlNZ8bfBQZX5CRMFtRmV4ou4iIEFVRxIlpRxoMySOg68NvhCTiuMzFdyusKmpehS7nbJkyaoJbXcmT1J04L+1YS4H99AUZov71Ct6fruFjytNV3goZvoBS0soex8zYfKThd9t2cw6aU0XfXdrnh61lBU9s0aj+HrPlABI0hIwV0zgoQU9KaGT0g1Ns9o+IRUY1OtRlL8aTt3RQTiTpY2/76T5auHSWoUXbazixTMqYD7JJlUATdKMKuisaFWwbSKxsZa+XkVDTUelbV8LAXFkMyvTMgB3FxR1tPhFZSHnmHRDgNHPpiCuksGWYS6u4qOr1C7UvHDLNpiYM1HWpAsCYeY9TsrQGNXixPEQ6ypxMy4fCNjnTAXaGcIzeAqFyUhPMx91yPxrhWT1vMz06C0XtH+DppDVp4emwb3zPPfTkBV5menUZUd7d0C9jUgenxaewwcRInjnGl4fnAaVUCSkmK7FiQpKXapBUFKivVZgyAlxdp0ATc8Q64ZNzxNkvFo50gyHu0sSRZ8xRXrhhJjLZ5cM38nEFxzxI0wzZInPUckbLAi0YQRKhJNZJ2aRBNZpyHRgsFqFC24MQF6vMhbosH6Xe+mXj56doGZaM49LC4PUFi9e2TEotyvx7WNr/3Sbo/7XKxWl2c5fD4/NeLny1Mjxrf9mbv+YslxLHeTDt6NPyq8vf0NO3SpWw== 模块::铜板工厂 用于中期游戏(蓝瓶科技)的铜板工厂。 产能: 675/min 尺寸: 32 x 16 输入: [上] 铜矿 675/min 1 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 模块::石砖工厂 用于中期游戏(蓝瓶科技)的石砖工厂。 产能: 675/min 尺寸: 32 x 16 输入: [上] 石矿 1350/min 1 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 科研模块 科研瓶工厂用于生产研究用的瓶子。科研中心模块则消耗瓶子用于研究。 模块::绿瓶工厂 用于早期游戏(绿瓶科技)的绿瓶工厂 产能: 135/min 尺寸: 32 x 32 输入: [上] 铁板 607.5/min [上] 电路板 135/min 1 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 模块::蓝瓶工厂 用于中期游戏(蓝瓶科技)的蓝瓶工厂。 产能: 56/min 尺寸: 32 x 32 输入: [上] 钢材 56/min [上] 铁板 224/min [上] 集成电路 84/min [上] 水 420/min [上] 石油气 420/min 1 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 模块::紫瓶工厂 用于中期游戏(蓝瓶科技)的紫瓶工厂。 产能: 90/min 尺寸: 32 x 32 输入: [上] 铁板 225/min [上] 石矿 450/min [上] 钢材 750/min [上] 石砖 300/min [上] 集成电路 150/min [上] 产能插件1 30/min 1 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 模块::黄瓶工厂 用于中期游戏(蓝瓶科技)的黄瓶工厂。 产能: 58/min 尺寸: 32 x 32 输入: [上] 钢材 38.7/min [上] 铁板 77.4/min [上] 电路板 96.7/min [上] 润滑油 290/min [上] 电池 38.7/min [上] 轻质框架 58/min [上] 处理器 38.7/min 1 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 其他模块 模块::机器人工厂 用于中期游戏(蓝瓶科技)的两种机器人工厂,会自动部署到机器人网络里。 产能: 物流机器人 10/min 建设机器人 10/min 尺寸: 32 x 32 输入: [上] 钢材 40/min [上] 铁板 80/min [上] 电路板 120/min [上] 润滑油 300/min [上] 电池 40/min [上] 集成电路 20/min 常量输入: 物流机器人: 物流机器人的目标数量 建设机器人: 建设机器人的目标数量 1 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 物流模块 物流::总线3x4+8 用于物流总线的3x4+8的总线结构,可以用于任意长度的总线。 尺寸: 32 x 32 1 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 石墙结构 用于分割各种模块,便于管理和防御的石墙结构 结构::石墙(内侧) 用于分割32x32模块结构的石墙,建造在单元格内侧。 尺寸: 32 x 32 1 0eNqVmk1v01AQRf+K9VYguVVm/O0dS9YsWFCEkuapPMl1otiBlir/nbihEhLczNxNo7T2yZvo9uQ51y9hMxzj/pDGOfQvYRun+0Paz2k3hj58yH6uhyGb5sPxfj4eYnac4jabd9k2/UjbmBWaPS0/pvQrZo+77XGIebY5pmHO0jgtR8zf3/5wezfejZ/OB/Zvp4U8TON6fzPvbh4Oabu8/FPopc7D8/JwysN6M+2G4xxvluP2aXwI/XkpMQ/pfjdOof/yEqb0MK6H5dz5eR/Pa05zfDyTx/Xj8myad2O8WaYIZ14at3F5idPXPMRxTnOKF8rrk+dv4/FxEw/nA/53fh72uyld3pnLSm+r16WubqvTKf8Hoi7I6g9E/g8pKAhYSemC6HVI5YIU1yG1C1JehzQuSHUd0rog9XVI54I01yGyclFag+LLbGdQfKEVI3Dii60Y/0HiC64YyRVfdMXIrvjCK0Z6xRdfMfIrvgCLkWDxRViMDKsvw2KEWJ3iNVKsvhSrkWL1pVitzwGnfo0Uqy/FaqRYfSlWI8XqS7EaKVZfitVIsfpSrEaKC1+K1Uhx4UuxGikufCkujBQXvhQXRoqLksOg/UxFbWgKQKkpigJKw42EMC2HQTN11EwV2OqtKEoJKMKNhDDKYdBM3Ca4AZSSotSAUnEjIUzNYdBMDTVTBygtRWkBpeNGAphqxWHATJVwV19AVxV5EYeunUgHQw4rYTQWZ2EByqo4DQsQaEV6GHJIEcOxOBML0FbNqViARGvSxZBDyhiOxdlYgLpqTscCRFqTPoYcUshwLM7IAvRVc0oWINOadDLiNKSU0VgNZ2UF+mo4Kyv6Hom0MuSQVoZjcVZWoK+G3BwDmzbs7hhxSCvDsTgrK9BXy1lZgU1b0sqQQ1oZjsVZWYG+Ws7KCmzaklaGHNLKcCzOygr01XJWVmDTlrQy4nSkldFYHVd3FEBfHWdliOGSXKCv5kuqr4CrqajuBGJqqrOAmIbqTyCmpXoLiOmoDgVhZLWiqgvMEapIwRzl2gsMKrg2BYNKrsHAoIprVDCo5loMDGq4VgWDWq7JwKCOa1YgyFnsiRlsZ7cnZrKd9Z6ayXYWfGom21nxqZlsZ8mnZrKdNZ+ayXYWfWom21n1qZlsZ9mnZrKddZ+ayXYWfmomW8l9dAELcPKiEK+o5OqbC+hrfrmBpf/rtpw8DOtNHM6/+/R2I07ff15uzHn3cRzj4f35iB/xML1CtZWy6bSpO121hZ5OvwFJ63eO 结构::石墙(外侧1) 用于分割32x32模块结构的石墙,建造在单元格外侧1格处。 尺寸: 32 x 32 1 0eNqVms1q21AQhV9F3FULcvHMtX53fYIusuiiKcWOL6moIhlLbpMGv3ulhEChPcycTRIb6ctM+DiRfPQcDv0lnc7dMIf2ORzTdHfuTnM3DqENH7Nf+77Ppvl8uZsv55RdpnTM5jE7dj+7Y8qiZo/rl6n7nbKH8XjpU54dLl0/Z+NlTuds/v72fibZoR/vfkzZ/tf+6cPtcDvcLGe1b4yQh2nYnzbzuLk/d8d1lsfQSpmHp/XbNQ/7wzT2C3WzHnfqhvvQLnOlPHR34zCF9stzmLr7Yd+v585Pp7Qs0M3pYSEP+4f11TSPQ9qsK4WF1w3HtP6K69c8pGHu5i69Ul5ePH0bLg+HdF4O+N/5eTiNU/f6Z3qZdLP9ULzMuv5wveb/YNSFEYMSXRRrlp2LEg1K4aKoQSldlMKgVC7KzqDULkplUBoXpTQosnVhGgvj07e2ME59LX/FJ7BYBotPYbEcFp/EYlksPo3F8lh8IotlsvhUFstl8cksls3qs1ksndWns1g+q89ntXxWn89q/nfw+ayWz+oMZctn9fmsls/q81ktn9Xns1o+q89ntXyOPp/V8jn6fFbL5+jzOZrXFz6fo+VzdF5iWB7Ggrv6EoApOQyapuK2QtPUHAZN03BLRXAxuOUwCjDCLYWmUQ6DponcUgXA7DjMDmAKbik0Tclh0DQVt1QFMDWHKQGm4ZYC0xRbDgOmKci7vRpglMM0ABO5pRCGDGO0FJvF6L6RDGMBMVqwaYw4ZBzDvcg8FpBdJRnIAqK0JBMZcshIhnuRmSwgv0oylAXEaUmmMuSQsQz3InNZQIaVZDALiNSSTGbEqchoRntVZDYLyLGKDGcBsVqR6Qw5ZDzDvch8VvRZGpnPCnK1IvMZcsh8hnuR+awgx2r2ghnkak3mM+Swl8xoLzKfFeRYTeazglytyXyGHDKf4V5kPivIsZrMZwW5WpP5jDgNmc9or4bMZwU51pD5rCBXGzKfIYfMZ7gXmc8R5GFD5nNEPQWZz3AeMp/hPOznGYqaky3VkmGOUJ0d5ijVlGFOpHo7zNlRbRnmFFR3hzkl1ZhhTkX1d5hTU50Z5jRUhQc5zipQTKGdZaCYRnvrQFNpbx9oOu0tBE2pvY2gabW3EjS19naCptfeUtAU29sKmmY7a0E1zXb2gmqa7S0GTbO9zaBptrcaNM32doOm2d5y0DTb2w6aZnvrQdNsbz9omu0sCKNptrMhjKbZkbxNfAV9zV8fomr/ek4sD/3+kPrlvZu3J8Pa9vP6pNi7T+tjX/J+OeRnOk8vVK1lVzValY1u66jX6x+wQD9+ 结构::石墙(外侧2) 用于分割32x32模块结构的石墙,建造在单元格外侧2格处。 尺寸: 32 x 32 1 0eNqVms1O20AUhV/FmlUrOShzJ/7d9Qm6YNFFQVV+RtSqY0exA6Qo7147KFKrcnTv2YBAyccZdPLhcPzmNu0pHo5NN7r6ze3isD02h7HpO1e7L8nLum2TYTyetuPpGJPTEHfJ2Ce75rnZxSRI8jp/GJrfMdn3u1Mb02Rzatox6U9jPCbjz9v3E0k2bb/9NSTrl/X57qF76O6nZ9U3hkvd0K0Pi7FfPB2b3Zzl1dU+T915/nRJ3Xoz9O1EXcyPOzTdk6unXDF1zbbvBld/f3ND89St2/m54/kQpwM0Y9xP5G69n78axr6Li/lIbuI13S7OP+LymLrYjc3YxHfK9Yvzj+6038Tj9ICPnp+6Qz8077+ma9LF8i67Zl34u+xySf/DiA3jb5jlx5hAYkCalQmjUTITRfvN5CZKUCiFiSIKpTRRMoVSmSgrheKXJkyuYWwFLjSMrcClhrEVuNIwxgJr3fO2CnvtleBtJfZa/7ytxl57NXhbkb3aQVuVvfaKEFuXvVZmsZXZa20WW5u9Vmex1dlrfRZbn0X9K2Prs2h9FlufReuzGLWs9VlsfRatz2Lrs2h9DrY+i9bnYOuzaH0Otj6L1udg67NofQ62Pgetz8HW56D1ORgvMrQ+B1ufg9bnUJIcdDlYcdeD6HJwyWFAmpXnToUwwmHQochr5QAwKw4jAJNxh0KYnMOgQxXcoTKAKTnMCmAq7lAAky05DDhU5rlDFQBDvuPLASZwh0KYFYdBh8q4Q5UAk3OYCmBIG6M0pIxRGtbFQH85KWOP3leTNoZ5WB2jPKSPPVBgTgrZAwfmpJFhHlLJMA/pZA80mJNS9sCDOWlllKcgtYzyFKSXPVBhQYrZAxcWpJlhHlLNMA/pZg90WJBy9sCHBWlnmIfUM8xD+lmAD0vSz4L+10j6GeYh/QzzkH4W4MOSvWAGPizZK2aUh/QzzEP6WYAPS9LPAnxYkn5GeSrSzyhPRfpZgA8r0s8CfFiRfoZ5SD/DPKSfBfiwIv0swIcV6WeYh/QzzEP6OSzRbkIKOsABhjQ0TkQqGicK3BoZAgKRksYgstVBECinNkkcqKBWScwpqV0ScypqmYQc4xyYqRxPrZOYI9SuiDmBmjkxZ0Uti5iTUUMn5uTctIhBBbd1YlDJjYsYVHFrJwRZZ0G11NZdUG21dRhUa21dBtVeG6dBrxbbuA16tdnWcVBttnUdVJttnQfVZlv3QbXZ1oFQbbZ1IVSbbZ0I1WZbN0K12caRUNRmG1dCUZttnQnVZlt3QrXZ7FAIL68C+W4RJjJuheHfl8hj+n4zXv3X/Yapa9eb2E7fu7/dYVjX3+Y7Dj99vd4+KJ+nxzzH43DFSulXRSVFXsmyDHK5/AE2R/ib 结构::半格石墙(内侧) 用于分割32x16模块结构的半格石墙,建造在单元格内侧。 尺寸: 32 x 16 1 0eNqVmb1u2zAYRV9F4NQCciBSIvWzdWuHTh06NEFhR2xKQKYMiUqTBn73SnYDFGiuxDsZtqnjS+PzAX31Ig7dZE+D80E0L6K14/3gTsH1XjTiQ/Jr33XJGIbpPkyDTabRtknok9Y9utYmuUqeEmmS0f22ybFvp86myWFyXUicH5cV4efrGze3/tZ/mRc2r5eJVIx+f9qFfvcwuHb5+CfRSJOK5+XhnIr9Yey7Kdjdsu7k/INo5ig2Fe6+96Novr2I0T34fbdcG55Pds7sgj3OZL8/Ls/G0Hu7W3YhZp7zrV0+4nyXCuuDC85eKZcnz9/9dDzYYV7w1vWpOPWju34zl6TZjb5GvdHnc/ofREVB5F9I9jYkp5IASBEFydchOgqi1iEmCqLXIWUUpFiHVFGQch1SR0HMOkRmUZR6gxI3s9UGJXJoN6ZWxo2t3JhbGTe4cmNyZdzoyo3ZlXHDK/W6FmTJYVCauAGWGz8DWVOCyYHqMoqiAEVy3wwKozgMSsOpVwNKQVEKQNHcllAYcoJRmpLaUwkoFUUxgFJzWwJh8ozDgDQ5d3CoAUVRlApQcm5LKEzBYVAazR2pgDxzw2HQqYp0MIxTkRyUh7OwBOYrOA1LYL6C9DCMQ4oY5uFMLIH9Ck7FEtivIF0M47DHCZSHs7EEBiw4HUtgwIL0MYqjSSGjPJr8KwcsqDklS2BBTToZxiGlDPNwVlZAg5qzskL/MEkrwziklWEezsoKaNCQh2NgQUNaGcZhj8coD2dlBTRoOCsrYEFDWhnGIa0M83BWVkCDhrOyAhY0pJVRnJK0MspTclZWQIMlZ2UFLFiSVoZxSCvDPJpqDnOgwZKzMsRwk5yj0q6iSkiYpqZqSISpMqqIhBhJVZEQo6gyEmJyqo6EmILqIyFGU4UkxBiuSoSckms2IafiykTIqbluE3HqjOsBIYct3xCHPF5cfXGXXu/bNP/cjUpFtz/Ybn7t8+UGUtN8XW5Gfdx3P5J3n7y3w/t5zaMdxgtWVbIoa1WaWmVVrs7nP9AimdM= 结构::半格石墙(外侧1) 用于分割32x16模块结构的半格石墙,建造在单元格外侧1格处。 尺寸: 32 x 16 1 0eNqVmc2K2zAYRV9FaNWCM+STf2R71113Xcyii85QnESdijp28M/MpEPevXbCQKG9SHeVxNgnuuHjoFy96V07u9Pgu0nXb/rgxv3gT5PvO13rT+qlaVs1TsO8n+bBqXl0BzX16uCf/cGp1KhXJYUa/W+njv1hbl2idrNvJ9XPkxvU9PP9uhK1a/v9L9W8NOe7h+6hu18eqt8ROtFj15w2U795GvxhXcqrrqVI9Hl9uSS62Y19u0A3630n3z3pelmWS7Tf992o629vevRPXdOuz07nk1vW7yd3XMhdc1w/jVPfuc2aSC883x3c+hWXx0S7bvKTdzfK9cP5ezcfd25Ybvjf84k+9aO//UrXlW62d/l1reubyyX5B2OiMCFKGkWRACWLopgAJY+ipAFKEUXJAhQbRckDlDKKUgQoVRTFBiiyjcKUIUzc+FYhTNz4Smh+JXKAQxMscSMsoRmWuCGW0BRL3BhLaI4lbpAlNMkSN8oSmmWpOPsJkN+WwyCHCpcKYQyHQaFSLlQKMBmHMQCTc6EQpuAwKJTlQuUAU3KYDGAqLhTApFsOA0Kl5I7CAozhMAXApFwohMk4DAqVc6EqgCk4TAkwlguFMKSMUSjWxcBbGSljQbtI0saQw+oY5SJ9LMBdGSlkASrNSCNDDqlkmIt0sgB/ZaSUBeg0I62MODmpZZQrJ70swGE5KWYBSs1JM0MOqWaYi3SzAI/lpJwFaDUn7Qw5pJ5hLtLPBnisIP1s0D9r0s+QQ/oZ5iL9bIDHCnbDDLxasDtmxCH9DHORfjbAYwXpZwO8WpB+RhxL+hnlsqSfDfCYJf1sgFct6WfIIf0Mc5F+NsBjlvSzAV61pJ8hh/QzzEX6OQUeK0k/p6htJP0MOaSfYS62zwA+LDOqpIaYnGrMIaagamqIsVRnDjElVVRDTEW15ghTbamqGmKE6s0hxlBVNcSkVHEOMRnXVENOzjXnkFNwTTXkWK45h5ySa6ohp+Kac8SRLbnNuIEek9shYf3XMWii22bn2uXa/fvBZ11/XQ9CPzftD/Xhy3q0KR+X+57dMF7RppTMVsYWldmWqblc/gCWXl68 结构::半格石墙(外侧2) 用于分割32x16模块结构的半格石墙,建造在单元格外侧2格处。 尺寸: 32 x 16 1 0eNqVmUtr20AUhf/KMKsW5KA7emvXXXddZNFFE4psT9KhsmT0SOIG//dKNoZCc5g5q2AjfbnHHD6Gue962872OLhu0vW73ttxN7jj5PpO1/qLem3aVo3TMO+mebBqHu1eTb3auxe3tyox6k1Jrkb3x6pDv59bG6nt7NpJ9fNkBzX9un2vjNq2/e63al6b091D99DdLy/VN4SO9Ng1x83Ub54Ht19HedO15JE+rX/OkW62Y98u0M363NF1z7pexrKRdru+G3X9412P7rlr2vXd6XS0y/xusoeF3DWH9dM49Z3drIn0wnPd3q7/4vwYadtNbnL2Srl8OP3s5sPWDssDH70f6WM/uuuvdJl0E99ll1k3cpedz9F/GBOGkRsm/hiTkBgwTRqE8WXKgii+WfIgivFQiiBK4qGUQZTUQ6mCKJmHInEQJvdhwgpc+DBhBS59mLACVz5MWIHF12AJrLCvwxJWYvG1WMJqLL4eS1iRxddkCauy+LpswrosvjKbsDKLr83GkBygY0P6GI2Tchg0TcalQpicw6BQBRcqAZiSwxiAqbhQAJPEHAaESoQLlQEMeapIASbhQiFMymFQqIwLVQBMzmFygCm4UAhTchgUquJCVeD4F3OYEmBIGyMMKWMUinUxOhuTMhag0ZS0MeSwOka5SB8LcFdKClmASlPSyIiTkUpGuTLSyQL8lZFSFqDTjLQy5JBahrlILwtwWEaKWYBSM9LMkEOqGeYi3SzAYzkpZwFazUk7Qw6pZ5iL9LNB9wWknw3wak76GXJIP8NcpJ8N8FjOHpiBV3P2xAw4BelnlKsg/WyAxwrSzwZ4tSD9DDmkn2Eu0s8GeKwg/WyAVwvSz5BD+hnmIv1sgMdK0s8GeLUk/Qw5pJ9hLtLPCbpDJf2cAK+WpJ8hh/QzzFVwm4AEeKwk/Qw5ZJ8T4Ocqpq7x0TiVUDsFiDHURT7EJNRWAWJS6iofYjJqrwAxOXWVDzEFtViAmJK6yoeYilosIIzEMXeVj0HC7RYwyHCX+RiUcNsFDEq563wMyrj9AgaxcjYIRJ428EQlt6q4gh6j67K5/medHum22dp2+e7+tkCv6+/rQv1r0z6pT98uK3LzeXnwxQ7jhW1KSYvKFHll4jIx5/NfeAQXsQ==

2023/5/6
articleCard.readMore

学习AI绘画,从Diffusion和CLIP开始

AI绘画在这几个月火了起来,它能从提供的文字和图片中生成新的绘画,质量很高,而且非常有趣。这个封面就是用AI生成的[1]。但是在使用AI绘画的过程中,搞不懂steps,sampler之类的意思。为了想要更好的使用AI绘画,也想要理解AI绘画中那些参数的含义,所以本着学习新技术的目的,写了这篇文章来学习一下AI绘画。 AI绘画 这几个月风靡的AI绘画,主要是指在统计学和计算机视觉领域,用深度学习模型从一些条件输入中生成新的图片。这些输入主要是文字或者图片。比如说封面图它就是用Anything-V3.0模型[1]从文字直接生成的。 封面图的输入参数 masterpiece,best quality,1 girl,loli, small breasts,animal ears, cute, Age:12, Height:145, hair ribbon, cute face,shy, long hair, white hair, dress , illustration, city Negative prompt: nsfw, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry,hands Steps: 40, Sampler: Euler a, CFG scale: 13, Seed: 353263948, Size: 1216x512, Model hash: 6569e224, Clip skip: 2 对于文字生成图片而言,AI绘画系统有两个重要模块,第一个是理解文字输入,第二个是使用这个理解去生成新的图片。所幸,学术界在之前已经存在了能高质量完成这两步的技术基础。其中Denoising Diffusion Probabilistic Models (DDPM/Diffusion)[2]提供高质量的图片生成技术,而Contrastive LanguageImage Pre-training (CLIP)[3]提供了高水平的自然语言跨模态理解。 这篇文章我们将从DDPM和CLIP开始学习AI绘画。 DDPM 在DDPM出现之前,图片生成主要是通过变分自编码器(VAE)和生成对抗网络(GAN)来完成的。但是VAE生成的图片模糊,而GAN的训练很困难,最后生成的多样性比较有限。DDPM解决了这个难点,它能生成高质量的图片,而且也不需要对抗训练,训练起来也很简单。但是DDPM也有缺陷,它生成图片的速度比较慢,因为需要执行很多步的迭代。我们先从介绍DDPM开始。 Fig. 1. 生成式模型. Adapted from [4] 如上图所示,DDPM是从一个生成的噪声$z$中迭代多次生成图片的,而且相比于VAE和GAN存在一个低维的隐式表示$z$,DDPM的每次迭代生成的中间图片$x_t$都保持在相同的维度上。 DDPM之所以是Diffusion(扩散),是因为它是通过扩散过程来生成噪声,然后再训练模型去预测这个噪声来去噪,从而达到生成图片的目的。让我们先从扩散的前向过程,也就是生成噪声开始。 前向扩散 Fig. 2. 前向扩散过程. Adapted from [2] 首先需要定义用DDPM生成图片的过程。首先我们有一张真实图片$x_0\sim q(x)$从一个数据集中采样而来,我们希望能通过一系列手段去预测出$x_0$。 我们现在对$x_0$添加一点高斯噪声,一共添加$T$步,那么每步的结果可以表示为$x0$, $x1$, $x2$, …, $x_T$。那么每次从$x_{t-1}$添加噪声到$x_t$的过程可以表示为, $$ \begin{equation} x_t = \sqrt{\alpha_t}x_{t-1} + \sqrt{1 - \alpha_t}z_t \end{equation} $$ 其中,$z_t \sim N(0, I)$是采样于标准正态分布的噪声。$\alpha_t$是一个一开始被决定好的常量,在原文中被称为步长,但是更像是一个权重,决定这一步中包含噪声的多少。这里可以看出$x_t$主要是取决于$x_{t-1}$和这个高斯分布$z_t$。所以,我们可以一步步递归计算到$x_0$,这里高斯分布被合并。 $$ \begin{equation} x_t = \sqrt{\prod_{i=1}^t \alpha_i}x_0 + \sqrt{1 - \prod_{i=1}^t \alpha_i}z \end{equation} $$ 为了表示简单,我们定义 $\bar{\alpha}_{t} = \prod_{i=1}^{t} \alpha_{i}$,则这个简化版的公式如下 $$ \begin{equation} x_t = \sqrt{\bar{\alpha}_t}x_0 + \sqrt{1 - \bar{\alpha}_t}z \end{equation} $$ 我们可以认为,因为每个噪声都符合标准正态分布,所以每步加一个小噪声可以当成一口气加个大噪声,极大的简化了前向扩散过程。 代码如下。 1 2 3 4 def forward_process(x0, alpha_bar, t): z = torch.randn_like(x0) x_t = torch.sqrt(alpha_bar[t]) * x0 + torch.sqrt(1 - alpha_bar[t]) * z return x_t 反向扩散 既然我们已经知道了如何生成噪声,那么我们就可以通过预测这个噪声来去噪了。这个从$x_t$到$x_0$的过程就是反向扩散。 通过概率论的角度来看,这个前向扩散的过程可以记为条件概率分布的形式。其中从$x_0$加噪声到$x_t$的过程可以表示为$q(x_{t}|x_0)$。同理,我们也已知$q(x_{t-1}|x_0)$和$q(x_t|x_{t-1},x_0)$,根据贝叶斯公式,我们可以得到反向扩散的过程为, $$ \begin{equation} q(x_{t-1}|x_t,x_0)=\frac{q(x_t|x_{t-1},x_0)q(x_{t-1}|x_0)}{q(x_{t}|x_0)} \end{equation} $$ 为了简单表示,我们定义$\beta_t = 1 - \alpha_t$ 因为$q(x_t|x_{t-1}) \sim N(\sqrt{1-\beta_{t}}x_{t-1}, \beta_{t}I)$的方差是$\beta_{t}I$,所以我们把$q(x_{t-1}|x_t,x_0)$的方差记为$\tilde{\beta}_{t}I$,而均值则是$\tilde{\mu}_t$。我们的目标是求解$\tilde{\mu}_t$和$\tilde{\beta}_t$。 化简等式(4)得, $$ \begin{eqnarray} q(x_{t-1}|x_t,x_0)&\propto& \exp(-\frac{1}{2}((\frac{\alpha_t}{\beta_t}+\frac{1}{1-\bar{\alpha}_{t-1}})x^2_{t-1}-(\frac{2\sqrt{\alpha_t}}{\beta_t}x_t + \frac{2\sqrt{\bar{\alpha_{t-1}}}}{1-\bar{\alpha}_{t-1}}x_0)+C(x_t,x_0))) \\\ &=&\exp(-\frac{(x-\tilde{\mu}_t)^2}{2\tilde{\beta}_tI}) \end{eqnarray} $$ 省略常数项,求解以上等式,得到 $$ \begin{eqnarray} \tilde{\mu}_t &=& \frac{\sqrt{\alpha_t}(1-\bar{\alpha}_{t-1})}{1-\bar{\alpha}_{t}}x_t + \frac{\sqrt{\bar{\alpha}_{t-1}}\beta_t}{1-\bar{\alpha}_t}x_0 \\\ \tilde{\beta}_t &=& \frac{1-\bar{\alpha}_{t-1}}{1-\bar{\alpha}_t}\cdot \beta_t \end{eqnarray} $$ 这时候方差已知,而均值$\tilde{\mu}_t$只和$x_t$和$x_0$有关。而对于$x_0$来说,我们可以通过等式(3)估算得到, $$ \begin{equation} x_0 = \frac{1}{\sqrt{\bar{\alpha}_t}}(x_t - \sqrt{1-\bar{\alpha}_t}\tilde{z}_{t}) \end{equation} $$ 其中这里的$\tilde{z}_t$是一个未知的噪声,我们需要通过模型来预测。 这里的$x_0$只是一个估算的结果,不能作为最终结果输出。 通过等式(9),我们可以消去等式(7)中的$x_0$,得到 $$ \begin{equation} \tilde{\mu}_t = \frac{1}{\sqrt{\alpha_t}}(x_t - \frac{1-\alpha_t}{\sqrt{1-\bar{\alpha_t}}}\tilde{z}_{t}) \end{equation} $$ 然后我们就可以通过重参数化技巧来从$x_t$中采样$x_{t-1}$了。迭代这个过程,我们就可以得到$x_0$作为最终输出。 以下是这一步采样的代码实现。 1 2 3 4 5 6 7 8 9 10 11 12 13 def sample_x0_from_xt(xt, alpha_bar, t, pred_eps): return 1 / torch.sqrt(alpha_bar[t]) * (xt - torch.sqrt(1 - alpha_bar[t]) * pred_eps[t]) def sample_pred_mean_from_x0_xt(xt, x0, t, alpha, alpha_bar): xt_term = torch.sqrt(alpha_bar[t]) * (1 - alpha_bar[t - 1]) / (1 - alpha_bar[t]) * xt x0_term = torch.sqrt(alpha_bar[t - 1]) * (1 - alpha[t]) / (1 - alpha_bar[t]) * x0 return xt_term + x0_term def backward_process_step(xt, t, alpha_bar, alpha, beta_tilde, model): pred_eps = model(xt, t) x0 = sample_x0_from_xt(xt, alpha_bar, t, pred_eps) pred_mean = sample_pred_mean_from_x0_xt(xt, x0, t, alpha, alpha_bar) return pred_mean + torch.sqrt(beta_tilde[t]) * torch.randn_like(xt) 训练过程 在上一节我们知道,我们需要一个模型去预测噪声$\tilde{z}_t$,所以这个模型的输入是$x_t$和$t$,输出是$\tilde{z}_t$。而我们在前向扩散的过程中就已经获取了这个ground truth的噪声$z_t$,所以我们可以通过这个ground truth的噪声和预测的噪声之间的差异来训练模型。 对于DDPM来说,这个损失函数是MSE。 $$ L = ||z_t - \tilde{z}_t||_2 $$ 模型架构 尽管DDPM的主要思想是在如何进行扩散上,这个模型不是重点,但是我们还是需要大致了解一下的。 首先这个模型是基于UNet[5]的,UNet是一个经典的Encoder-Decoder图像分割模型,主要的特点是在上采样和下采样的过程中,都会通过一个跳跃连接来保留住低层次的特征信息。这个模型的架构如下图所示。 Fig. 3. U-Net. Adapted from [5] 相比于2015年的原版U-Net,DDPM中的每一步上采样或者下采样过程中,都有一个ResNet[6]的残差连接结构,然后再跟上一个Multi-Head Attention层[7]。 Fig. 4. 残差连接和 MultiHead Attention. Adapted from [6][7] 除此之外,对于时间信息$t$会被编码成一个embedding。如果是有条件输入的话,我们也可以把输入的条件信息(作为embedding)和time embedding相加。然后在模型的一些层中,再通过相加的方式添加到feature map中。 建立了这个模型之后,我们就可以通过前向扩散和后向扩散的过程来训练模型了。 简单测试结果 通过实现以上的代码,用了一个小参数的简单模型和简单的数据集(CIFAR10)[8]。用了一个RTX8000训练了十几个小时,我们可以看到,模型的效果还是不错的。 Fig. 5. DDPM的简单生成结果 CLIP 介绍完了DDPM,我们再来看一下CLIP[3]。相比于DDPM,CLIP并没有特别强的算法创新,但是它提供了一个很好的框架,用于建立自然语言和图像的关系。这个框架可以用于很多的任务,比如图像搜索,图像生成,图像分类等等。 CLIP是由OpenAI提出的多模态预训练算法,它的主要思想是通过一个超大的图像-文本数据集,来训练一个图像Encoder和一个文本Encoder。如果是相关的文本和图片,编码后的特征向量应该是相似的,如果是不相关的文本和图片,编码后的特征向量应该是不相似的。这个数据集有超过4亿个图片和文本的pair,完全是大力出奇迹。 模型架构 Fig. 6. CLIP的模型架构. Adapted from [3] 如上图所示,CLIP模型包含一个Text Encoder和一个Image Ecnoder。它们用于分别提取文本和图片的特征向量到同一个特征空间。在预训练的过程中,通过计算余弦相似度(cosine similarity)作为损失函数。原论文中也提供了伪代码来作为参考,如下所示。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # image_encoder - ResNet or Vision Transformer # text_encoder - CBOW or Text Transformer # I[n, h, w, c] - minibatch of aligned images # T[n, l] - minibatch of aligned texts # W_i[d_i, d_e] - learned proj of image to embed # W_t[d_t, d_e] - learned proj of text to embed # t - learned temperature parameter # extract feature representations of each modality I_f = image_encoder(I) #[n, d_i] T_f = text_encoder(T) #[n, d_t] # joint multimodal embedding [n, d_e] I_e = l2_normalize(np.dot(I_f, W_i), axis=1) T_e = l2_normalize(np.dot(T_f, W_t), axis=1) # scaled pairwise cosine similarities [n, n] logits = np.dot(I_e, T_e.T) * np.exp(t) # symmetric loss function labels = np.arange(n) loss_i = cross_entropy_loss(logits, labels, axis=0) loss_t = cross_entropy_loss(logits, labels, axis=1) loss = (loss_i + loss_t)/2 因为整体思路较为简单,所以不再赘述。 用于下游任务 CLIP的主要用途是将预训练好的模型用于下游任务。比如说作为zero-shot图像分类任务,如图6(2,3)所示。这个任务很好的展示了这个模型的一大优势,即通过超大的文本图像数据集建立了较为充分的知识,使得模型在没有针对性的训练的情况下,也能够很好的完成下游任务。 当然,模型也可以用于图像查询。在这个任务中,只要对需要查询的文本进行编码,然后和所有图片的编码计算余弦相似度,就可以通过找最大值得到最相关的图片。 另外就是用于文字生成图片的任务了,比如说AI绘画。我们可以将文本编码为特征向量,然后将这个特征向量作为输入,作为条件信息输入到刚才提到的DDPM中。 关于如何使用CLIP,请参考OpenAI的官方Github仓库(openai/CLIP)[9]。 总结 本文主要介绍了AI绘画的一些原理,包括了DDPM,CLIP。但是现在流行的模型Stable Diffusion (基于Latent Diffusion[10])还没有介绍。而且AI绘画中还有很多内容,比如说sampler(DPM[11], DDIM[12]),这也是以后需要继续学习的方向。 参考文献 [1] Linaqruf, “Linaqruf/anything-v3.0 · Hugging Face,” huggingface.co, 2022. [Online]. Available: https://huggingface.co/Linaqruf/anything-v3.0 [2] J. Ho, A. Jain, and P. Abbeel, "Denoising Diffusion Probabilistic Models," in Advances in Neural Information Processing Systems, 2020, vol. 33, pp. 6840–6851. [Online]. Available: https://proceedings.neurips.cc/paper/2020/hash/4c5bcfec8584af0d967f1ab10179ca4b-Abstract.html [3] A. Radford et al., “Learning Transferable Visual Models From Natural Language Supervision,” in Proceedings of the 38th International Conference on Machine Learning, Jul. 2021, pp. 8748–8763. [Online]. Available: https://proceedings.mlr.press/v139/radford21a.html [4] L. Weng, “What are Diffusion Models?,” lilianweng.github.io, Jul. 11, 2021. [Online]. Available: https://lilianweng.github.io/posts/2021-07-11-diffusion-models/ [5] O. Ronneberger, P. Fischer, and T. Brox, “U-Net: Convolutional Networks for Biomedical Image Segmentation,” in Medical Image Computing and Computer-Assisted Intervention – MICCAI 2015, Cham, 2015, pp. 234–241. doi: 10.1007/978-3-319-24574-4_28. [6] K. He, X. Zhang, S. Ren, and J. Sun, “Identity Mappings in Deep Residual Networks,” in Computer Vision – ECCV 2016, Cham, 2016, pp. 630–645. doi: 10.1007/978-3-319-46493-0_38. [7] A. Vaswani et al., “Attention is all you need,” in Proceedings of the 31st International Conference on Neural Information Processing Systems, Red Hook, NY, USA, Dec. 2017, pp. 6000–6010. [8] A. Krizhevsky, “Learning Multiple Layers of Features from Tiny Images,” Master’s thesis, University of Tront, 2009. [9] OpenAI, “CLIP,” GitHub, 2022. [Online]. Available: https://github.com/openai/CLIP [10] R. Rombach, A. Blattmann, D. Lorenz, P. Esser, and B. Ommer, “High-Resolution Image Synthesis With Latent Diffusion Models,” in Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition, 2022, pp. 10684–10695. [Online]. Available: https://openaccess.thecvf.com/content/CVPR2022/html/Rombach_High-Resolution_Image_Synthesis_With_Latent_Diffusion_Models_CVPR_2022_paper.html [11] C. Lu, Y. Zhou, F. Bao, J. Chen, C. Li, and J. Zhu, “DPM-Solver: A Fast ODE Solver for Diffusion Probabilistic Model Sampling in Around 10 Steps,” in Advances in Neural Information Processing Systems, Oct. 2022. [Online]. Available: https://openreview.net/forum?id=2uAaGwlP_V [12] J. Song, C. Meng, and S. Ermon, “Denoising Diffusion Implicit Models,” in International Conference on Learning Representations, Feb. 2022. [Online]. Available: https://openreview.net/forum?id=St1giarCHLP #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2023/1/7
articleCard.readMore

怎么通信比较快?Python跨进程通信测试

在一些场合下,我们需要同时运行多个Python程序,并且希望这些Python进程之间能互相通讯,发送一些值或者接收一些值。本文我们就来测试一下Python的跨进程通信不同方案的效率。 本文包含的内容有:HTTP, websocket, multiprocessing, gRPC, RabbitMQ等。 背景介绍 请考虑以下场景,要处理一个数据,我们需要有3步比较耗时的操作,而这个每一步的操作需要上一步的结果,如下图所示。 flowchart LR Input --> Step1 --> Step2 --> Step3 --> Output 在这里,有两种使用多进程并行的思路,使用多个进程,每个进程接受一个数据,处理完全部三步之后返回结果,每个进程之间相互独立,如下图所示。 flowchart LR subgraph Process3 direction LR Input3 --> p3s1[Step1] --> p3s2[Step2] --> p3s3[Step3] --> Output3 end subgraph Process2 direction LR Input2 --> p2s1[Step1] --> p2s2[Step2] --> p2s3[Step3] --> Output2 end subgraph Process1 direction LR Input1 --> p1s1[Step1] --> p1s2[Step2] --> p1s3[Step3] --> Output1 end 这种方法操作简单,不需要进程间通信,也容易扩展到更多的进程数,在绝大多数情况下都推荐使用。然而这种模式需要将3个Step的上下文都载入内存中,如果这些Step是占用内存很高的深度学习模型,那么内存将会成为一个严重瓶颈。 为了解决这个问题,我们可以使用另一种模式将其并行。 flowchart LRInput --> Step1 .-> Step2 .-> Step3 .-> Outputsubgraph Process1 Step1endsubgraph Process2 Step2endsubgraph Process3 Step3end 其中这里的虚线表示进程间通信(IPC)。相比于第一种并行方式,这种并行方式操作复杂,需要进程间通信,但是可以有效的减少内存占用。 然而,这种并行相比于第一种方案,需要消耗额外的时间在IPC上,因此我们需要测试一下不同IPC方案的效率。 如果以上图表没有正确渲染,请刷新页面。 运行环境 以下实验都在以下环境运行: 1 2 3 4 5 6 7 8 9 10 CPU: i7-10900X RAM: 128GB Python: 3.10.8 websockets: 10.4 fastapi: 0.88.0 grpcio: 1.56.2 pika: 1.3.2 aio-pika: 9.2.0 numpy: 1.23.4 需要通讯的内容为4种不同尺寸的numpy.ndarray[1],数据类型为float64。分别为: (1, 3, 224, 224), 模拟一张图片 (2, 1024, 16, 16), 模拟两张图像的低维特征 (2, 3, 16, 224, 224), 模拟两个16帧的视频片段 (128, 1024, 1024), 模拟128个序列特征 方案介绍 方案1: HTTP + JSON 序列化 这是最简单的方案,使用HTTP协议作为通信协议,将ndarray转换成Python的嵌套List,然后作为json发送。这种方案的优点是实现简单,不需要额外的依赖,缺点是从ndarray和List互相转换的开销大,而且json序列化的开销也很大。 这里HTTP通过fastapi[2]实现,fastapi是一个高性能的异步框架,可以很好的支持大量的并发请求。 方案2: HTTP + Base64 Bytes 这种方案和方案1类似,不过将ndarray通过numpy内置的方法转换成bytes,然后使用base64编码,这样可以避免ndarray和List之间的转换,但是HTTP传输大规模的base64编码的开销也很大。 方案3: Websocket + Bytes 这种方案和方案2类似,不过使用Websocket作为通信协议,这样可以避免HTTP的开销。因为Websocket可以发送ascii之外的字节,所以不需要base64编码。 方案4: HTTP + Shared Memory 这里采用了multiprocessing.shared_memory模块,使用SharedMemory对象将ndarray的地址共享给子进程。然后将SharedMemory对象名字作为HTTP的返回值,客户端再通过名字获取SharedMemory对象,这样可以避免ndarray和List之间的转换,也避免了base64编码的开销。 方案5: Websocket + Shared Memory 这种方案和方案4类似,不过使用Websocket作为通信协议,这样可以避免HTTP的开销。 方案6: Multiprocessing Listener / Client 这种方案使用multiprocessing模块的Listener和Client对象,使用multiprocessing的Pipe作为通信协议,这样可以避免HTTP的开销。 方案7: gRPC + Bytes 这种方案使用gRPC[3]作为通信协议,使用protobuf作为序列化协议,好处是方便客户端进行调用,但是gRPC有最大的消息长度限制(2GB)。 方案8: RabbitMQ + Bytes 这种方案使用RabbitMQ[4]作为通信协议,使用pika[5]作为Python的客户端和服务端。这种方案的好处是可以使用RabbitMQ的其他特性,比如消息队列,消息持久化等,但是有最大的消息长度限制(512MB)。 测试结果 ndarray Shape(1, 3, 224, 224)(2, 1024, 16, 16)(2, 3, 16, 224, 224)(128, 1024, 1024) HTTP + JSON290.00 ms1090 ms9230 ms259.00 s HTTP + Base64 Bytes26.40 ms51.5 ms398 ms12.30 s Websocket + Bytes4.27 ms15.0 ms171 ms5.14 s HTTP + Shared Memory10.70 ms18.1 ms127 ms3.13 s Websocket + Shared Memory4.34 ms14.9 ms127 ms3.82 s Multiprocessing Listener7.00 ms17.2 ms162 ms4.73 s gRPC + Bytes7.34 ms28.6 ms291 ms7.92 s RabbitMQ + Bytes9.35 ms25.7 ms243 ms超出消息长度 根据这个结果我们可以发现,方案4和方案5的性能是最好的,方案6的性能也很好,方案1和方案2的性能最差。 考虑网络传输协议,Websocket的性能是比HTTP好的。所以应该尽量使用Websocket作为网络传输协议。 考虑使用Base64还是Shared Memory,我们可以发现大数据的情况下,Shared Memory的性能是比较好的,但是它需要手动管理内存,可能会有一些问题。所以对于小数据,可以使用Base64,对于大数据,可以使用Shared Memory。 对于multiprocessing模块的Listener和Client,它的性能略弱于Shared Memory,但是它不需要手动管理共享内存,而且它不需要用fastapi之类的外部库,而且不需要转换成别的类型的数据,比较方便。但是正因为它没有使用fastapi,以至于它不是很方便的进行异步处理。 gRPC和RabbitMQ的性能比较差,只比HTTP好一点点,比不上Websocket,所以不推荐使用。而且它们有最大的消息大小限制,所以传输数据时不太方便。 在写以下比较重复的代码实现的时候,Github Copilot[6]起到了很大的帮助。 代码实现 方案1: HTTP + JSON 序列化 1 2 3 4 5 6 7 8 9 10 # server.py import numpy as np from fastapi import FastAPI app = FastAPI() shape = (1, 3, 224, 224) @app.get("/random_tolist") async def random_tolist(): return np.random.randn(*shape).tolist() 1 2 3 4 5 6 7 # client.py import requests import numpy as np result = requests.get("http://127.0.0.1:1234/random_tolist") result = np.array(result.json()) print(result.shape) 方案2: HTTP + Base64 Bytes 1 2 3 4 5 6 7 8 9 10 11 12 # server.py import numpy as np import base64 from fastapi import FastAPI from fastapi.responses import PlainTextResponse app = FastAPI() shape = (1, 3, 224, 224) @app.get("/random_tobytes", response_class=PlainTextResponse) async def random_tobytes(): return base64.b64encode(np.random.randn(*shape).tobytes()) 1 2 3 4 5 6 7 8 # client.py import requests import numpy as np import base64 result = requests.get("http://127.0.0.1:1234/random_tobytes") result = np.frombuffer(base64.b64decode(result.text)).reshape(*shape) print(result.shape) 方案3: Websocket + Bytes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # server.py import numpy as np from fastapi import FastAPI, WebSocket app = FastAPI() shape = (1, 3, 224, 224) @app.websocket("/ws/random_tobytes") async def websocket_random_tobytes(websocket: WebSocket): await websocket.accept() while True: await websocket.receive_text() print("Processing websocket") await websocket.send_text(np.random.randn(*shape).tobytes()) 1 2 3 4 5 6 7 8 9 # client.py import numpy as np from websocket import create_connection ws = create_connection("ws://127.0.0.1:1234/ws/random_tobytes") ws.send("") result = np.frombuffer(ws.recv()).reshape(*shape) print(result.shape) 方案4: HTTP + Shared Memory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # server.py import numpy as np from fastapi import FastAPI from fastapi.responses import PlainTextResponse from multiprocessing import shared_memory app = FastAPI() shape = (1, 3, 224, 224) @app.get("/random_sharedmemory", response_class=PlainTextResponse) async def random_sharedmemory(): arr = np.random.randn(*shape) shm = shared_memory.SharedMemory(create=True, size=arr.nbytes) out = np.ndarray(arr.shape, dtype=arr.dtype, buffer=shm.buf) out[:] = arr[:] shm.close() return shm.name 1 2 3 4 5 6 7 8 9 10 11 12 13 # client.py import numpy as np import requests from multiprocessing import shared_memory shm_name = requests.get("http://127.0.0.1:1234/random_sharedmemory") shm = shared_memory.SharedMemory(name=shm_name.text) result = np.ndarray(shape, dtype=float, buffer=shm.buf) shm.close() shm.unlink() print(result.shape) 方案5: Websocket + Shared Memory 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # server.py import numpy as np from fastapi import FastAPI, WebSocket from multiprocessing import shared_memory app = FastAPI() shape = (1, 3, 224, 224) @app.websocket("/ws/random_sharedmemory") async def websocket_random_sharedmemory(websocket: WebSocket): await websocket.accept() while True: await websocket.receive_text() print("Processing websocket") arr = np.random.randn(*shape) shm = shared_memory.SharedMemory(create=True, size=arr.nbytes) out = np.ndarray(arr.shape, dtype=arr.dtype, buffer=shm.buf) out[:] = arr[:] shm.close() print(shm.name) await websocket.send_text(shm.name) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # client.py import numpy as np from websocket import create_connection from multiprocessing import shared_memory ws = create_connection("ws://127.0.0.1:1234/ws/random_sharedmemory") ws.send("") shm_name = ws.recv() shm = shared_memory.SharedMemory(name=shm_name) result = np.ndarray(shape, dtype=float, buffer=shm.buf) shm.close() shm.unlink() print(result.shape) 方案6: Multiprocessing Listener / Client 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # server.py from multiprocessing.connection import Listener import numpy as np shape = (1, 3, 224, 224) address = ('localhost', 1234) listener = Listener(address) conn = listener.accept() while True: msg = conn.recv() print("Processing") conn.send(np.random.randn(*shape)) listener.close() 1 2 3 4 5 6 # client.py from multiprocessing.connection import Client conn = Client(("localhost", 1234)) conn.send("") result = conn.recv() print(result.shape) 方案7: gRPC + Bytes 1 2 3 4 5 6 7 8 9 10 11 // npy.proto syntax = "proto3"; import "google/protobuf/empty.proto"; service Npy { rpc Get (google.protobuf.Empty) returns (ArrayData) {} } message ArrayData { bytes body = 1; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 # server.py from concurrent import futures import time import grpc import npy_pb2 import npy_pb2_grpc import numpy as np shape = (1, 3, 224, 224) class Npy(npy_pb2_grpc.NpyServicer): def Get(self, request, context): arr = np.random.randn(*shape) return npy_pb2.ArrayData(body=np.ndarray.tobytes(arr)) def serve(): port = "50051" server = grpc.server(futures.ThreadPoolExecutor(max_workers=8), options=[ ('grpc.max_send_message_length', 2 * 1024**3 - 1), ('grpc.max_receive_message_length', 2 * 1024**3 - 1), ]) npy_pb2_grpc.add_NpyServicer_to_server(Npy(), server) server.add_insecure_port("[::]:" + port) server.start() print("Server started, listening on " + port) server.wait_for_termination() if __name__ == '__main__': serve() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # client.py from __future__ import print_function import grpc import numpy as np import npy_pb2 import npy_pb2_grpc shape = (1, 3, 224, 224) channel = grpc.insecure_channel('localhost:50051', options=[ ('grpc.max_send_message_length', 2 * 1024**3 - 1), ('grpc.max_receive_message_length', 2 * 1024**3 - 1), ] ) stub = npy_pb2_grpc.NpyStub(channel) response = stub.Get(npy_pb2.google_dot_protobuf_dot_empty__pb2.Empty()) arr = np.frombuffer(response.body, dtype=np.float64).reshape(shape) print(arr.shape) 方案8: RabbitMQ + Bytes 部署RabbitMQ的Docker容器: 1 docker run --name some-rabbit -p 5672:5672 rabbitmq:3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # server.py import pika import numpy as np connection = pika.BlockingConnection( pika.ConnectionParameters(host='localhost')) channel = connection.channel() channel.queue_declare(queue='rpc_queue') shape = (1, 3, 224, 224) def on_request(ch, method, props, body): arr = np.random.randn(*shape) data = np.ndarray.tobytes(arr) ch.basic_publish(exchange='', routing_key=props.reply_to, properties=pika.BasicProperties(correlation_id=props.correlation_id), body=data) ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_qos(prefetch_count=1) channel.basic_consume(queue='rpc_queue', on_message_callback=on_request) print(" [x] Awaiting RPC requests") channel.start_consuming() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 # client.py import pika import uuid connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel = connection.channel() result = channel.queue_declare(queue='', exclusive=True) callback_queue = result.method.queue response = None corr_id = None shape = (128, 1024, 1024) def on_response(ch, method, props, body): global response if corr_id == props.correlation_id: response = body channel.basic_consume( queue=callback_queue, on_message_callback=on_response, auto_ack=True ) def call(): global response global corr_id response = None corr_id = str(uuid.uuid4()) channel.basic_publish( exchange='', routing_key='rpc_queue', properties=pika.BasicProperties( reply_to=callback_queue, correlation_id=corr_id, ), body="" ) connection.process_data_events(time_limit=None) return response response = call() arr = np.frombuffer(response, dtype=np.float64).reshape(shape) print(arr.shape) 参考文献 [1] "NumPy", Numpy.org, 2022. https://numpy.org/. [2] "FastAPI", FastAPI, 2022. https://fastapi.tiangolo.com/ [3] "gRPC" gRPC. https://grpc.io/ [4] “Messaging that just works — RabbitMQ,” Rabbitmq.com, 2019. https://www.rabbitmq.com/ [5] pika, “Pika,” GitHub, Jul. 28, 2023. https://github.com/pika/pika (accessed Jul. 28, 2023). [6] "GitHub Copilot · Your AI pair programmer," GitHub, 2022. https://github.com/features/copilot #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2022/12/13
articleCard.readMore

Python编程基础08:单元测试和异常处理

人生苦短,我用Python![1] 这个系列是一个帮助零基础的人入门编程的教程,本文主要介绍Python中的单元测试和异常处理。 测试 在软件开发过程中,测试(Testing)是非常重要的一个步骤,用于确保程序的正确性和质量。也能在最终部署之前,识别和纠正程序的错误和缺陷。 Fig. 1. 重大的程序bug会造成严重后果。Adapted from [2][3] 一些致命的软件bug会造成严重的后果,比如737MAX飞机的故障和Uber自动驾驶系统的故障,如图1所示[2][3]。除此之外,其他一些给社会造成严重负面影响的软件bug可以看看这里 (List_of_software_bugs) 整理的。为了避免这种情况,我们需要在程序中添加测试。 测试分为4个层次,分别是: 单元测试(Unit testing) 程序中单个单元或者组件会被测试 确保每一个单元运行良好,不会有任何错误 集成测试(Integration testing) 多个单元会被组合,并且作为一个集合被测试 在集成了多个单元之间的互动中,错误可能会被暴露 系统测试(System testing) 整个系统会作为一个整体被测试 确保达到所有的功能和要求 验收测试(Acceptance testing) 完整的程序会在用户部署之前进行测试 评估这个系统符合所有的业务要求 在这里我们主要重点关注如何给Python写单元测试,其他类型的测试是软件工程部分的内容。 那么要如何写测试呢?最基本的想法是,先考虑定义一个优秀的测试策略,其中包含很多不同的测试用例,这对于确保程序的正确性很重要。 那么一个优秀的测试策略: 要保证程序所有的功能都能在有限的时间内被覆盖并且测试 由合理并且可管理可维护的测试用例组成 最大化检测错误或者缺陷的可能性 举个例子,考虑有一个程序需要通过输入的分数来计算这个学生有没有通过考试。 1 2 3 4 if mark >= 50 and mark <= 100: grade = "Passed" else: grade = "Failed" 有效(正面)用例: 基于正确的输入数据 比如: 55, 60, 65, …, 85, 90, 95, … 无效(负面)用例: 基于错误的输入数据 比如: -1, 0, 5, …, 45, 49, 101, 200, … 边缘用例: 有效用例中的一些边界值 比如: (49, 50)和(100, 101) Debug Debug是指计算机程序中查找和解决缺陷或者问题的过程。在编写程序或者测试遇到bug时,就需要debug来解决。 在Python中,有两个比较基础的手段: print语句 assert语句 关于print我们已经很熟悉了,它会输出这个变量的值,方便观测某个变量在运行时的值。 至于assert: 它能检查一个表达式是否为真,如果不为真,就会抛出一个AssertionError异常 语法: assert (condition), "<error_message>" 比如: 1 assert size <= 5, "size should not exceed 5" 但是总之,最好的debugging是实打实的理解你写的程序。 Python中的单元测试 在Python中,我们需要使用unittest标准库来进行测试。 通过继承unittest.TestCase创建一个测试类(test class) 在测试类中定义一个或多个测试方法(test method) 假设我们有一个函数product_func被定义,并且需要为它编写单元测试。 1 2 3 def product_func(first_arg, second_arg): result = first_arg * second_arg return result 那么单元测试可以这么写: 1 2 3 4 5 6 7 8 9 import unittest class TestForProduct(unittest.TestCase): def test_product(self): self.assertEqual(product_func(2, 4), 8) if __name__ == ‘__main__’: unittest.main() 运行这个测试时,将会有可能性: OK, FAIL, ERROR。 如果在Jupyter Notebook中,我们可以这样运行测试。 1 2 suite = unittest.TestLoader().loadTestsFromTestCase(TestForProduct) unittest.TextTestRunner().run(suite) 在unittest中,Python提供了以下assert的方法: MethodChecks thatNew in assertEqual(a, b)a == b assertNotEqual(a, b)a != b assertTrue(x)bool(x) is True assertFalse(x)bool(x) is False assertIs(a, b)a is b3.1 assertIsNot(a, b)a is not b3.1 assertIsNone(x)x is None3.1 assertIsNotNone(x)x is not None3.1 assertIn(a, b)a in b3.1 assertNotIn(a, b)a not in b3.1 assertIsInstance(a, b)isinstance(a, b)3.2 assertNotIsInstance(a, b)not isinstance(a, b)3.2 关于更全面的unittest介绍和解释,请参考这个页面[4]。 Python中的错误和异常 编程中,错误(Error)一般分为以下3类: 语法错误(Syntax erros) 代码在语法上有问题,编译器/解释器无法理解代码 Python中的例子: SyntaxError 运行时错误(Runtime errors) 代码在运行时发生了错误,可以进行适当处理 Python中的例子: ValueError, TypeError, NameError 逻辑错误(Logic errors) 程序逻辑的实施不正确 程序运行不出错,但是结果是错误的 以下我们举一些Python例子来说明。 SyntaxError: 程序中语法错误 1 2 if a_number > 2 print(a_number, “is greater than 2”) NameError: 在程序中使用了一个未定义的变量或者模块 1 a_number = random.random() TypeError: 尝试使用不兼容的对象类型 1 2 if a_number > 2: print(a_number + “is greater than 2”) ValueError: 尝试传入一个参数,类型正确但是值错误 1 sum_of_two = int('1') + int('b') 更多的Python错误异常,请参考这个页面[5]。 Python的异常处理 在Python中,主要使用try和except关键词来处理异常。 try和except: 在try块中的语句会被执行,如果没有发生异常,except代码块会被跳过 如果发生了异常,并且满足except中的条件,那么对应的except代码块会被执行 如果发生了异常,但是没有except满足条件,那么程序依然会报错退出 以下是一个例子,如果输入了非数字的字符串,或者除数为0,都可以进入到对应的except代码块中进行处理。 1 2 3 4 5 6 7 8 9 try: num1 = int(input(“Enter first number: ”)) num2 = int(input(“Enter second number: ”)) result = num1 // num2 print("Result of division:", result) except ValueError: print("Invalid input value") except ZeroDivisionError: print("Cannot divide by zero") else: 如果没有发生异常,else代码块会被执行 如果需要在没有发生异常的时候运行某些代码,这个就会很有用 例子: 1 2 3 4 5 6 7 8 9 10 file_name = "input_file.txt" try: file_handle = open(file_name, "r") except IOError: print("Cannot open", file_name) except RuntimeError: print("A run-time error has occurred") else: print(file_name, "has", len(file_handle.readlines()), "lines") file_handle.close() finally: 作为一个清理用的代码块 无论是否发生异常,都会执行的代码块 1 2 3 4 5 6 7 8 9 10 11 12 file_name = "input_file.txt" try: file_handle = open(file_name, "r") except IOError: print("Cannot open", file_name) except RuntimeError: print("A run-time error has occurred") else: print(file_name, "has", len(file_handle.readlines()), "lines") file_handle.close() finally: print("Exiting file reading") 实践试试 这次的练习,我们来试试用一种能处理所有异常的方式来编写代码,并且还需要为程序写单元测试。如果有必要,还需要增加注释来帮助开发。 Debugging 我们需要写一个计算学生GPA的程序。每一个学生需要计算5门课的成绩,计算规则如下: 1 2 3 4 5 A ----- 4.0 B ----- 3.0 C ----- 2.0 D ----- 1.0 F ----- 0.0 这里有一个有错误的代码,我们需要修复它。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 number_of_courses = 3 course_grades = [] total_sum = 0.0 for i in range(len(number_of_courses)): input_grades.append = input("Please enter the grade for " + (i+1) + " courses: ") for grades in input_grades: if grade == "A": total_sum += 4.0 elif grade == "B": total_sum += 3.0 elif grade == "B": total_sum += 2.0 elif grade == "D": total_sum += 1.0 elif grade == "F": total_sum += 1.0 print("The GPA of a student is: " + (total_sum * number_of_courses)) 来找找看哪里错了吧。 首先是number_of_courses应该是5而不是3。需要加一个assert来检查这个变量不会出错。 1 2 3 4 number_of_courses = 5 assert (number_of_courses == 5), "The number of courses should be equal to 5" course_grades = [] total_sum = 0.0 然后是有一个TypeError因为len(number_of_courses)中的len需要接受一个集合类型而不是一个数字。 1 for i in range(number_of_courses): 然后input_grade.append是一个方法,需要去调用这个方法,而不是赋值。 其次在字符串的组合中,(i+1)需要被转换成字符串,因为字符串不能和数字相加。 而且input_grade有一个NameError因为它并没有被定义。 所以这一行会改成 1 course_grades.append(input("Please enter the grade for " + str(i+1) + " unit: ")) 接下来input_grades也有NameError错误,需要使用正确的变量名。同样对于grade也是。 然后有一个逻辑错误,用户可能输入一个小写字母,而这个就会跳过以下代码块的处理。这里应该改为 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 for grade in course_grades: if grade.upper() == "A": total_sum += 4.0 elif grade.upper() == "B": total_sum += 3.0 elif grade.upper() == "C": total_sum += 2.0 elif grade.upper() == "D": total_sum += 1.0 elif grade.upper() == "F": total_sum += 0.0 else: print_flag = False print("Illegal grade encountered. Program aborted.") break if print_flag: print("The GPA of a student is: " + str(float(total_sum / number_of_courses))) 测试 在上一节中,我们已经编写了一个简单的程序,用来计算学生的GPA。想一想对于上面这个程序,应该如何编写测试来检查潜在错误。来试试看写一些单元测试。 首先我们把以上程序放入一个函数中。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def calculate_GPA(grade_list): total_sum = 0.0 gpa = 0.0 for grade in grade_list: if grade.upper() == "A": total_sum += 4.0 elif grade.upper() == "B": total_sum += 3.0 elif grade.upper() == "C": total_sum += 2.0 elif grade.upper() == "D": total_sum += 1.0 elif grade.upper() == "F": total_sum += 0.0 else: return -1 gpa = float(total_sum / len(grade_list)) return gpa 接下来来编写单元测试。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import unittest class TestForGPA(unittest.TestCase): # valid test case def test_calculate_GPA_1(self): self.assertEqual(calculate_GPA(['A','A','B','D']), 3.0) # invalid test case def test_calculate_GPA_2(self): self.assertEqual(calculate_GPA(['A','A','B','1']), -1) # boundary test case def test_calculate_GPA_3(self): self.assertEqual(calculate_GPA(['A','A','A','A']), 4.0) def test_calculate_GPA_4(self): self.assertEqual(calculate_GPA(['F','F','F','F']), 0.0) 在Jupyter Notebook中,我们需要运行以下代码来运行测试。 1 2 3 test = TestForGPA() suite = unittest.TestLoader().loadTestsFromModule(test) unittest.TextTestRunner().run(suite) 异常处理 让我们改善Python编程基础05的实践题代码。 以下是原来的代码。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # Open simple_file.txt for reading # Open output_file.txt for writing with open("simple_file.txt","r") as input_handle, open("output_file.txt","w") as output_handle: # Perform some data processing for line in input_handle: line = line.strip("\n") line_number = line.split(" ") if line_number[2] == "one": line_number[2] = "1" elif line_number[2] == "two": line_number[2] = "2" elif line_number[2] == "three": line_number[2] = "3" elif line_number[2] == "four": line_number[2] = "4" elif line_number[2] == "five": line_number[2] = "5" new_line = line_number[0] + " " + line_number[1] + " " + line_number[2] + "\n" output_handle.write(new_line) # Both files will be closed after finishing the with block 需要处理simple_file.txt中的文本,文件的每一行中包含三个值,前两个是数字,第三个是表示数字的英文字符串,比如说“one”。我们需要做的是将第三个值转换为数字,并且将整个文件的结果写入到output_file.txt里,我们只拿1~5作为例子。 1 2 3 4 1 2 five 5 7 one 6 9 three 9 8 four 经过了这次的学习之后,我们可以用try-catch代码块来更好的处理异常错误。以下是一种参考范例。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 try: # open simple_file.txt for reading input_handle = open('simple_file.txt','r') # open output_file.txt for writing output_handle = open('output_file.txt', 'w') except IOError: print("cannot open files") except RuntimeError: print("some run-time errors") else: # perform some data processing for line in input_handle: line = line.strip("\n") line_tokens = line.split(" ") if line_tokens[2] == "one": line_tokens[2] = '1' elif line_tokens[2] == "two": line_tokens[2] = '2' elif line_tokens[2] == "three": line_tokens[2] = '3' elif line_tokens[2] == "four": line_tokens[2] = '4' elif line_tokens[2] == "five": line_tokens[2] = '5' new_line = line_tokens[0] + " " + line_tokens[1] + " " + line_tokens[2] + "\n" output_handle.write(new_line) #close both files after processing input_handle.close() output_handle.close() finally: print("Exiting program...") 系列总结 至此,Python编程基础的内容就已经全部被覆盖完毕了。以上一共8篇blog覆盖了Python基础相关的大多数语法和编程思路。相信大家在学完以上8篇之后,就已经能够独立的编写Python程序而不会遇到很大障碍了。至于今后的内容,打算为一些Python高级语法再编写几篇后日谈,其中可能会包括类型注释,metaclass,装饰器,函数式编程和并发并行等等。 参考文献 [1] B. Eckel, “sebsauvage.net - Python”, Sebsauvage.net, 2021. [Online]. Available: http://sebsauvage.net/python/. [2] C. Nast, "Boeing Plans to Fix the 737 MAX Jet With a Software Update", Wired, 2022. [Online]. Available: https://www.wired.com/story/boeing-737-max-8-ethiopia-crash-faa-software-fix-lion-air/. [3] "So who's to blame when a driverless car has an accident?", Abc.net.au, 2022. [Online]. Available: https://www.abc.net.au/news/2018-03-20/uber-driverless-car-accident-who-is-to-blame/9567766. [4] "unittest — Unit testing framework — Python 3.10.5 documentation", Docs.python.org, 2022. [Online]. Available: https://docs.python.org/3/library/unittest.html. [5] "Built-in Exceptions — Python 3.10.5 documentation", Docs.python.org, 2022. [Online]. Available: https://docs.python.org/3/library/exceptions.html. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2022/7/29
articleCard.readMore

Python编程基础07:标准库和第三方库

人生苦短,我用Python![1] 这个系列是一个帮助零基础的人入门编程的教程,本文主要介绍Python中包和库的概念,还有一些常用的标准库和第三方库。 包和模块 Python可以通过导入(import)关键字使用来自于外部的代码。在Python中,包(package)基本上是可以视为一系列模块(module)组成的目录。而在第五章提到,模块是一个包含了定义和语句的Python源代码文件。 Fig. 1. 一个Python的包和模块的例子。Adapted from [2] 这张图展示了一个例子,这里的my_model,training,submission和metrics都是文件夹,而剩下.py结尾的都是文件。根据以上定义,我们可以认为,刚才提到的4个文件夹是4个包,而training,submission和metrics是my_model包的子包。而在各个包之下,剩下的Python文件,比如说dataset.py,training_loop.py都是模块。每一个包下都需要一个__init__.py来定义这个包的入口,可以是空白文件。 如果我们想导入training包中的dataset模块中的load_dataset函数,可以这样写: 1 2 3 import my_model.training.dataset.load_dataset dataset = my_model.training.dataset.load_dataset() 当然,这样的写法很长,看起来很不方便,所以我们需要from关键字。 1 2 3 from my_model.training.dataset import load_dataset dataset = load_dataset() 通过这样的方法可以较为简洁的导入外部代码。 另外,可以通过以下写法导入指定模组的全部成员,但是不推荐使用。 1 from my_model.training.dataset import * 相对导入 除了从绝对路径导入之外,我们也可以通过相对路径进行导入。 如果在编辑my_model/submission/submit.py,想要导入my_model/metrics/precision.py中的Precision类,可以这样写: 1 2 3 4 # absolute path from my_model.metrics.precision import Precision # relative path from ..metrics.precision import Precision 在运行环境相对复杂时,使用相对导入更加合适。 库和框架 库(library)一般而言是指可以重用的代码,经常和包(package)混用。但是一般来说,包是模块的集合,而库是包的集合。 标准库是Python官方提供的库,在安装了Python之后,即可直接导入使用。 比如说, 用于文字处理 string, re, difflib 用于数学计算 math, ramdom, statistics 用于函数式编程 itertools, functools, operator 用于文件访问 os, shutil, pathlib 用于文件压缩和解压 zlib, gzip 用于操作系统服务 os, io, time, subprocess 用于并行计算 multiprocessing, threading, concurrent 除了标准库之外,还有其他开发者提供的第三方库。这些库数量繁多,功能强大,也正是因为这些库和这个社区才让Python成为强大的编程语言。 为什么标准库需要导入 如果标准库已经是Python自带的了,为什么还需要额外导入?一个原因是,显式的声明要比隐式更好,通过指定导入哪些库,可以更好的解释这个代码的目标。 另一个原因是Python导入标准库的时候,会运行它们。如果每次运行Python代码都要导入全部的标准库,那会显著的增加Python程序的运行时间,即使它只是一行print("hello world")。 第三个原因是只有有限数量的名字可以给函数,如果同时导入每个库,可能会导致名称冲突。比如说,print是被多个标准库使用的通用名字,random和string也是一样。这种想法被成为命名空间(name space)。 标准库 在这一节,我们将会简单介绍几个常用的标准库。 math math标准库提供了一些常用的数学函数,主要是在不使用更加复杂的第三方库的情况下可以直接使用。 其中包括了一些函数, 求幂和对数 exp(x), log(x, base), pow(x, y), … 三角函数 sin(x), cos(x), tan(x), … 还有数学常量, pi, e, inf, nan 更多请看官方文档[3]。 random random标准库提供了创建假随机数(pesudo-random number)的方法。 最基础的函数: random() 返回一个随机浮点数,它在[0, 1)之间。 随机的整数: randint(a, b) 返回一个随机整数,它在[a, b]之间。 为序列准备的随机数函数: choice(seq): 返回序列中的一个随机元素。 shuffle(seq): 打乱序列中的元素。 sample(seq, k): 从序列中随机获取k个元素。 更多请看官方文档[4]。 第三方库 Python的第三方库是外部开发者提供的,所以并不会预先和Python一起安装。所以在使用第三方库之前,我们需要先安装它。 其中最简单的方式是使用pip命令。举个例子,如果需要安装NumPy这个库, 1 pip install numpy 在使用pip命令的时候,将会自动的从PyPI上下载安装包。PyPI是一个Python官方提供的第三方库的平台[5]。基本上任何一个第三方库都会介绍安装这个库的方法。 除此之外,如果使用了Anaconda[6]或者Miniconda[7]来安装Python的话,也可以使用conda命令来安装第三方库。 1 conda install numpy NumPy NumPy是一个用C编写的数学计算第三方库[8]。很多其他优秀的第三方库都是基于NumPy来实现的,比如说SciPy[9], pandas[10]。 使用NumPy的时候,我们通常会使用import numpy as np的方式来导入。 NumPy的核心是提供了一个新的数据结构: ndarray(多维数组)。 1D数组: np.array([1, 2, 3]) 2D数组: np.array([[1, 2, 3], [4, 5, 6]]) 类似于Matlab[11]和R[12]中的数组,一切都可以向量化(vectorize)。 1 2 3 4 5 import numpy as np a = np.array([1, 2, 3]) b = a + 1 print(b) # array([2, 3, 4]) 利用向量化进行编程,可以极大的提升运行的效率,弥补Python的速度短板。 关于NumPy的更多使用方法,请参考官网。 SciPy SciPy是一个NumPy的扩展包[9],提供了很多用于科学计算的算法,其中包括 线性代数 微积分 统计分布 优化 聚类 图像处理 信号处理 使用SciPy的时候,我们通常会使用import scipy as sp的方式来导入。 关于SciPy的具体用法,请参考官网。 Matplotlib Matplotlib是一个Python的2D/3D绘图库[13],主要用于数据可视化,其中包括直方图,柱状图,散点图,等等。 其中提供了一个用于快速绘图的包pyplot 一些常用的函数:plot(), hist(), scatter(), show() 使用Matplotlib的时候,我们通常会使用import matplotlib.pyplot as plt的方式来导入。 关于Matplotlib的具体用法,请参考官网。 pandas pandas是一个用于结构化数据处理和分析的Python库[10]。 常用的导入方法是import pandas as pd。 它提供了一个2维数据结构DataFrame,类似于一个表格。 从dict创建: 1 2 3 4 5 a_dataframe = pd.DataFrame({ "name":["Alice", "Bob", "Charles"], "age": [25, 23, 34], "gender": ["female", "male", "male"] }) 从NumPy的ndarray创建: 1 2 3 4 5 a_dataframe = pd.DataFrame( np.arange(16).reshape((4, 4)), index = ["x1", "x2", "x3", "x4"], columns = ["y1", "y2", "y3", "y4"] ) 一些学习pandas的好资料: pandas官方文档[14]: https://pandas.pydata.org/pandas-docs/stable/ 10分钟学习pandas[15]: https://pandas.pydata.org/pandas-docs/stable/user_guide/10min.html pandas备忘录[16]: https://github.com/pandas-dev/pandas/blob/main/doc/cheatsheet/Pandas_Cheat_Sheet.pdf Fig. 2. pandas 备忘录。Adapted from [16] 实践试试 在这次的课后实践中,我们将会尝试介绍一些第三方库。 可视化数学函数 在这一部分中,我们需要使用NumPy, SciPy和Matplotlib来可视化一些数学函数。 在这么短的一篇教程中想要覆盖这三个庞大的第三方库有些太难了,我们先从简单的地方开始,可以介绍一些这些库到底是干什么的。如果简单说的话:NumPy作为数据结构的主要来源;SciPy和pandas的存在是为了便于进行复杂的科学计算;Matplotlib用于可视化。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import numpy as np import matplotlib.pyplot as plt from scipy.misc import derivative from scipy.integrate import quad # creates a NumPy array with evenly sampled time at 200ms intervals x_values = np.arange(0., 5., 0.2) # Function 1 using sin. Drawn on the graph in red. def f1(x): return np.sin(2*x) # Function 2 is the first derivative of Function 1. Drawn on the graph in blue. def f2(x): return derivative(f1,x) # Function 3 is the first integral of Fuction 1. Drawn on the graph in green. # Note this only returns the integral between 0 and x for one value. # It returns it as a tuple, where the second element is the error of the calculation. def f3(x): return quad(f1,0,x) y_f1 = f1(x_values) y_f2 = f2(x_values) # Since f3 only returns one value at a time, it must be stored in a list. y_f3 = [] for value in x_values: y_f3.append(f3(value)[0]) # Plot all functions against the same x values plt.plot(x_values, [0]*len(x_values), 'black', x_values, y_f1, 'r*-', x_values, y_f2,'b^-', x_values, y_f3, 'g+-') plt.show() 运行结果: 数据处理 现在让我们试试看pandas。这个库提供了格式化输出的方法,但是能做到的远远不止这些,包括填充数据中的缺失值,或者处理NaN。我们可以试试看以下的部分。 首先,从上个部分中导入f1,f2和f3生成的数值,保存在pd.DataFrame中,并且通过DataFrame.describe展示统计数据。 1 2 3 4 5 6 7 8 import pandas as pd dictionary = {'f1': y_f1,'f2': y_f2, 'f3': y_f3} df = pd.DataFrame(dictionary) # statistic summary on df temp_data = df.describe() print(temp_data) 1 2 3 4 5 6 7 8 9 f1 f2 f3 count 25.000000 25.00000025.000000 mean 0.192329 -0.015361 0.508447 std 0.673530 0.673859 0.370538 min -0.996165 -0.907747 0.000000 25% -0.279415 -0.670510 0.151647 50% 0.334988 -0.026551 0.514600 75% 0.793668 0.633514 0.868697 max 0.999574 0.909297 0.999147 找出每一列中的最大值。 1 2 3 # max values of f1, f2, and f3 max_dict = {'f1_max':[temp_data['f1']['max']],'f2_max':[temp_data['f2']['max']],'f3_max':[temp_data['f3']['max']]} max_df = pd.DataFrame(max_dict) 1 2 f1 f2 f3 max 0.999574 0.909297 0.999147 根据列f2进行重排序。 1 df.sort_values(by='f2') 参考文献 [1] B. Eckel, “sebsauvage.net - Python”, Sebsauvage.net, 2021. [Online]. Available: http://sebsauvage.net/python/. [2] "Difference Between Python Modules, Packages, Libraries, and Frameworks", LearnPython.com, 2022. [Online]. Available: https://learnpython.com/blog/python-modules-packages-libraries-frameworks/. [3] "math — Mathematical functions — Python 3.10.4 documentation", Docs.python.org, 2022. [Online]. Available: https://docs.python.org/3/library/math.html. [4] "random — Generate pseudo-random numbers — Python 3.10.4 documentation", Docs.python.org, 2022. [Online]. Available: https://docs.python.org/3/library/random.html. [5] PyPI, 2022. [Online]. Available: https://pypi.org/. [6] "Anaconda | The World's Most Popular Data Science Platform", Anaconda, 2022. [Online]. Available: https://www.anaconda.com/. [7] "Miniconda — Conda documentation", Docs.conda.io, 2022. [Online]. Available: https://docs.conda.io/en/latest/miniconda.html. [8] "NumPy", Numpy.org, 2022. [Online]. Available: https://numpy.org/. [9] "SciPy", Scipy.org, 2022. [Online]. Available: https://scipy.org/. [10] "pandas - Python Data Analysis Library", Pandas.pydata.org, 2022. [Online]. Available: https://pandas.pydata.org/. [11] "MATLAB - MathWorks - MATLAB & Simulink", MathWorks, 2022. [Online]. Available: https://www.mathworks.com/products/matlab.html. [12] "R: The R Project for Statistical Computing", R-project.org, 2022. [Online]. Available: https://www.r-project.org/. [13] "Matplotlib — Visualization with Python", Matplotlib.org, 2022. [Online]. Available: https://matplotlib.org/. [14] "pandas documentation — pandas 1.4.2 documentation", Pandas.pydata.org, 2022. [Online]. Available: https://pandas.pydata.org/pandas-docs/stable/. [15] "10 minutes to pandas — pandas 1.4.2 documentation", Pandas.pydata.org, 2022. [Online]. Available: https://pandas.pydata.org/pandas-docs/stable/user_guide/10min.html. [16] "pandas/Pandas_Cheat_Sheet.pdf at main · pandas-dev/pandas", GitHub, 2022. [Online]. Available: https://github.com/pandas-dev/pandas/blob/main/doc/cheatsheet/Pandas_Cheat_Sheet.pdf. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2022/5/6
articleCard.readMore

LightIoC: Scala原生基于注解的依赖注入库

LightIoC是一个通过依赖注入的Scala轻量化控制反转工具,发布在GitHub上,项目地址。 添加依赖 Scala 这个库针对Scala 2.13.x, 2.12.x, 2.11.x进行编译,在Java8, 11, 16中通过测试。目前最新版本是0.3.0,请持续关注GitHub页面。 SBT: 1 libraryDependencies += "space.controlnet" %% "lightioc" % "0.3.0" Gradle: 1 implementation group: "space.controlnet", name: "lightioc_<scala_version>", version: "0.3.0" Java 这个库提供了一个Java友好的API,可以在Java中使用LightIoC。详情可以看Java API。 Gradle: 1 implementation group: "space.controlnet", name: "lightioc-api_2.13", version: "0.3.0" 快速开始 静态注册 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import space.controlnet.lightioc.Container @Provider class TopLevelClass @Singleton class TopLevelSingletonClass @Provider(isObject = true) object TopLevelObject @Provider(stringId = "IdForThisClass") class NamedProviderClass @Provider(isObject = true) object NestedClass { @Provider class InnerClass @Provider(isObject = true) object InnerObject } object Main extends App { Container.init("<package name>") } 动态注册 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import space.controlnet.lightioc.Container import space.controlnet.lightioc.Util._ class Foo class Bar { var x: Int = _ var y: Int = _ } object Baz class Qux(foo: Foo) object Main extends App { // register Foo to self constructor in Transient scope Container.register[Foo].toSelf.inTransientScope() // register Bar to self constructor in Singleton scope Container.register[Bar].toSelf.inSingletonScope() // register Baz as well Container.register[Baz.type].toSelf.inSingletonScope() // register a constructor with parameters Container.register[Qux].toConstructor(classOf[Foo]).inTransientScope() // register a constant value Container.register("A Number").toValue(123).inSingletonScope() // register a factory val barX = 1 val barY = 2 Container.register[Int]("Bar.x").toValue(barX).inSingletonScope() Container.register[Int]("Bar.y").toValue(barY).inSingletonScope() val factory: Factory[Bar] = Container => { // do anything you want val bar = new Bar bar.x = Container.resolve[Int]("Bar.x") bar.y = Container.resolve[Int]("Bar.y") bar } Container.register[Bar].toFactory(factory).inTransientScope() // register to another service (registry) Container.register[Foo].toSelf.inTransientScope() // target service Container.register("AnotherFoo").toService[Foo] } 当然,也可以使用Scala特色的自定义运算符。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import space.controlnet.lightioc.Container import space.controlnet.lightioc.BindingSetter.{ New, Self } object Main extends App { // register to value in Transient Container.register("AString") -> "Hello IOC" // register to constructor/class in Transient Container.register[Foo] -> classOf[Foo] // register to constructor/class in Singleton Container.register[Bar] := classOf[Bar] // register to self Container.register[Baz.type] -> Self // register to a constructor with parameters Container.register[Qux] -> New(classOf[Foo]) // register to factory Container.register[Bar] ~> factory // register to service Container.register("AnotherString") >> "AString" } 动态获取 1 2 3 4 5 6 7 8 9 10 import space.controlnet.lightioc.Container object Main extends App { // resolve by type val foo: Foo = Container.resolve[Foo] // resolve by string val str: String = Container.resolve[String]("AString") // resolve by factory val bar: Bar = Container.resolve[Bar] } 自动装配 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import space.controlnet.lightioc.annotation.{ Autowired, Provider } @Provider class Foo { @Autowired val bar: Bar = null } @Provider class Bar @Provider object Baz { @Autowired var x: Int = 0 // should be "var" } Java API 一个使用Kotlin的例子。 1 2 3 4 5 6 7 8 9 10 11 12 13 import space.controlnet.lightioc.annotation.Singleton import space.controlnet.lightioc.api.Container @Singleton class A { val x: Int = 100 } fun main() { Container.init("<package name>") val a = Container.resolve(A::class.java) println(a.x) }

2022/2/18
articleCard.readMore

Python编程基础06:Python的面对对象编程

人生苦短,我用Python![1] 这次我们来学习一下Python的面向对象编程(Object-Oriented Programming),也被简写为OOP。OOP是一种编程思想,可以让程序有更好的扩展性,可读性和可维护性。 面对对象编程 自打程序设计这一概念出现以来,人们就一直致力于研究出可靠又易于上手易于理解的编程语言以及不同的范式,人们所最熟知的C语言便是过程式编程(Procedural Programming)[2]的典范。这种编程范式曾经在很长的一段时间里解决了大部分人所面对的痛点——对着机器语言发愣。然而渐渐开始发现,C语言并非完美无缺,在各行各业软件愈发复杂的大前提下,C语言在很多时候会有许多不便之处,比如难以代码复用,功能拓展,项目维护,等等。为了解决这些问题,人们开始转而考虑另外一种编程范式:面向对象编程(Object Oriented Programming,简称OOP)[2]。 在了解何为OOP之前,我们首先需要明白,C语言所谓的“过程式编程”究竟是什么,过程式编程的重点是过程,也就是“procedure”,这一词在计算机领域有“例程”的意思,所谓例程,就是一系列指令的集合所构成的一个可供执行的单元。而在C语言中,源代码便是由这些例程所组成的,一个C语言项目会使用变量和函数(也就是例程)来描述“该怎么实现程序员的意图”,而它能做到的的唯一的代码复用,也就是将重复的代码拆出来放进新的函数里面,成为一个新的“例程”以供调用。C语言之所以选择了这种编程范式是因为他是最接近机器语言的一种编程范式,计算机的机器语言本质上就是由一条条二进制的指令所组成并交给CPU执行,就像是C语言中的一个个语句一样。 正如上一节中提到的函数封装和过程分解,可以发现,实际上之前介绍的Python语法和编程思想依然基于从C语言发展而来的过程式编程。下图明确的展示了这个编程范式的结构。 Fig. 1. 过程式编程的执行流程. 当我们提到“人”的时候,脑海中浮现出来的究竟是什么?我相信对于大部分“人”来说,这个问题的答案都是非常模糊的,我们知道人,但是仅仅是作为一个概念性的东西存在,我们需要更加详细的信息,才能对“人”这个字建立起一个更加精确地形象,比如姓名,年龄,外貌,性别等等等等,换句话说,“人”这个名词本身就像是一个模板,而这个世界上的每一个“人”,都是派生自这个模子的一个个体,这些个体补充上了前面说到的那些缺失的信息,才能让这个个体作为一个货真价实的“人”存在于这个世界上。 如果你能明白上面这段话的意思,OOP的概念对于你而言就已经熟悉了一半,上面的“人”就是一个类(class)。一个类可以拥有自己的属性和行为,但是并不能被直接拿来使用,需要以这个类为模板创造(实例化)出一个具体的东西,才能够把它拿来使用,这个东西就是对象(object)。一个类可以拥有属性(attribute),比如性别,年龄,也可以拥有行为,也被成为方法(method),比如吃饭,上学。OOP中的类通过对属性和行为的抽象,极强的提升了自身的表现力和抽象能力,一切东西都可以用类抽象出来。 OOP的三大要素 OOP有三大要素,分别是:封装(Encapsulation),继承(Inheritance),多态(Polymorphism)[3]。它们解决了过程式编程的一些不足。 封装 让我们接着拿人作为例子,我们知道人可以吃饭,但是鲜有人知道食物在人体中消化的每一个细节,我们知道人需要呼吸,却鲜有人知道肺结构的每一部分。 封装,指的就是只对外暴露自己必要的属性和行为,而隐藏具体逻辑。一个“人”类可能可以“吃饭”,但是使用这个类不需要知道食物是如何被具体消化的,这个具体逻辑是在类的内部不可见的。简单而言:对外隐藏具体实现细节,而仅仅暴露接口。 继承 生物学中有”界门纲目科属种”的分类学[4],不同的物种会因为一些相似的特征而分到同一个分类中。而分类又是带层级的,真核生物里面又有动物,动物又分脊椎动物和无脊椎动物。鸟和鱼在生存环境和呼吸方式上不同,可是共同点是他们都需要摄入食物。男人和女人在身体构造上不同,可是共同点是他们都拥有名字。 这样的场景在程序开发中实在是过于常见了,比如同一个网站不同类型的账户,有的是普通账户,有的是会员账户,如果用过程式编程,那就只能硬加条件判断,并分别去写对应的逻辑,很混乱。但是OOP的继承概念就解决了这个问题。继承,指的就是一个类可以指定另外一个或者多个作为自己的父类,这样自己就可以使用父类的字段和方法,同时也可以拥有属于自己的额外属性和方法;凡是需要父类的的地方,都可以使用该父类的子类去替换,这就是里氏替换原则(Liskov Substitution Principle)[5]。 Fig. 2. OOP的继承. Adapted from [6] 如上图所示,父类是“Person”而子类是“Programmer”, “Dancer”和“Singer”,所以它们也构成了IS-A关系,例如“Programmer”是“Person”,所以允许里氏替换。因为“Person”都有“name”、“designation”属性和“learn”、“walk”、“eat”方法,而“Dancer”是“Person”的子类,所以“Dancer”也可以直接用“Person”的共通方法,实现了代码复用。同时,“Dancer”及其他子类也可以拥有自己的独特属性和方法,比如“groupName”属性和“dancing”方法。 多态 继承的出现引入了新的问题:对于同一个行为,不同的子类可能拥有不同的逻辑。比如鸟类和鱼类的呼吸方式,虽然鸟类和鱼类都需要呼吸,但是鸟类呼吸是通过肺,而鱼类是通过鳃。针对这一问题,OOP通过多态解决,也就是父类同一行为在不同子类上可能有着不同的实现。同样的例子,让父类“动物”提供一个方法“呼吸”,在子类“鸟”中我们重写(override)这个方法,在方法的实现中让鸟类使用肺呼吸;而在子类“鱼”中我们选择让鱼用鳃呼吸。如果需要“动物”对象,由于里氏替换原则的存在,需要“动物”的地方都可以用“动物”的子类替换,所以可以提供一个“鸟”,也可以提供一个“鱼”,由于多态的存在,虽然调用的方法都是“呼吸”,但是由于不同类型的实现不同,所以效果也会不同。 Fig. 3. OOP的多态的另一个例子. Adapted from [6] Python的对象 Python支持很多类型的数据,比如说1234(int),3.1415(float),"Python"(str),[1,2,3](list),等等。这里的每一个数据都是一个对象(object)。 每一个对象都有: 一个类型(type) 一个内部数据表示(原始,复合) 一组和对象进行交互的方法 每一个对象都是一个类的实例(instance)。比如说: 1234是一个int类型的实例 "Python"是一个str类型的实例 在Python中,一切皆对象。所以在Python中, 对于某个类,可以创建新的对象 可以操作对象 可以销毁对象。比如说使用del关键字,或者直接不管它,Python会回收已销毁或者不可访问的对象,这也被称为垃圾回收(garbage collection)。 Python的类 Python中的类(class)是为了表示程序中的某一种概念而设计的,也可以被认为是定义了一种用于创建对象的模板/蓝图。在一个简单或复杂的程序中,我们需要创建很多类,每个类都有自己的职责和特性。 类的实例(instance)是从这个类中创建的对象。实例可以被赋值于一个变量,这样就可以通过这个变量来访问这个实例的内部值和相关的方法。 对于每个类,我们都会定义一些”实例变量”(instance variables) - 存储在一个实例中的内部值,和一些”方法”(methods) - 操作实例的函数。 创建一个类 创建一个类需要先指定类名,在Python中通过关键字class来定义类。比如说创建一个Point类,格式是这样的: 1 2 class Point: # define attributes here 这里在关键字class后就跟一个想要定义的类名Point,然后跟着一个冒号,接下来缩进并且定义类的内容。 注意,在Python中,类名是采用大写驼峰命名法,例如Point,CapWord,UpperCamelCase。 构造器 每一个Python中的类需要一个构造器(constructor)__init__(其中双下划线在两边)用于创建新的实例。 构造器在类中是非常重要的一部分 主要用于初始化实例的属性 通过类名进行调用 比如说在这个Point类的例子中,我们需要一个x和y分别代表一个点在平面直角坐标系的两个坐标。 1 2 3 4 class Point: def __init__(self, x, y): self.x = x self.y = y 在以上例子中,__init__右边的self是代表这个实例本身,而x和y是构造器的参数。然后下面的self.x和self.y则是实例的属性,我们需要把传入的x和y值赋值给这两个属性。这样一个Point实例就会带上两个属性x和y了。 1 2 3 p = Point(1, 2) print(p.x) # 1 print(p.y) # 2 这样我们就可以通过Point(...)和对应的x和y值来创建一个新的Point实例。然后通过p.x就可以访问x属性,就是在类定义中self.x所对应的值。 定义方法 类定义中的函数我们一般称为方法(method)。它就像一个函数一样,但是只能用在类中。 1 2 3 4 5 6 7 8 9 10 class Point: def __init__(self, x, y): self.x = x self.y = y def distance(self, other): dx = self.x - other.x dy = self.y - other.y distance = (dx**2 + dy**2) ** 0.5 return distance 上面这个例子中,我们定义了一个distance方法,它用于计算两个Point实例之间的距离。其中参数中的self代表的是这个实例本身,在使用的时候就不用再指定了。other则是另一个Point实例。 举个例子,如果要使用这个distance方法,我们可以这样写: 1 2 3 p = Point(3, 4) origin = Point(0, 0) print(p.distance(origin)) # 5 从上面的代码可以看到,distance中只需要传入一个参数other,而self则已经分配给了p了(写在这个方法名之前)。 但是我们还有另外一种调用方法的手段。对于同样的例子,可以这么写。 1 2 3 p = Point(3, 4) origin = Point(0, 0) print(Point.distance(p, origin)) # 5 在这个例子中,方法distance之前用的是Point类,而不是一个实例p,这样就可以完整的指定两个Point实例来计算了。 魔术方法 如果直接使用print来打印一个对象,会怎么样? 1 2 p = Point(3, 4) print(p) # <__main__.Point object at 0x10c8b9e58> 会发现打印的结果是包含了一个类名和所在的内存地址,对于人类来说,这个结果不是很有用。于是我们可以定义一个__str__方法,来改变打印的结果。Python会自动使用__str__方法的返回值作为打印的结果。 这样一来,Point类就是这样定义的: 1 2 3 4 5 6 7 8 9 10 11 12 13 class Point: def __init__(self, x, y): self.x = x self.y = y def distance(self, other): dx = self.x - other.x dy = self.y - other.y distance = (dx**2 + dy**2) ** 0.5 return distance def __str__(self): return "(" + str(self.x) + "," + str(self.y) + ")" 这时候再print一个Point实例,就会变成这样: 1 2 p = Point(1, 2) print(p) # (1,2) 就像这个例子中的__str__方法一样,Python中还有别的魔术方法可以用于一些特殊的目的。 比如说: __add__(self, other) -> self + other __sub__(self, other) -> self - other __eq__(self, other) -> self == other __lt__(self, other) -> self < other __len__(self) -> len(self) __str__(self) -> print(self) 还有很多,可以参考Python的文档[7]。 self 类中的self参数,在方法中表示的是当前的实例本身。所以如果用一个实例来调用方法的话,就不需要再去指定self了。假设我们在point.py这个文件里定义了Point类,如下所示: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def get_x(self): return self.x def get_y(self): return self.y def set_x(self, x): self.x = x def set_y(self, y): self.y = y def distance(self, other): dx = self.x - other.x dy = self.y - other.y distance = (dx**2 + dy**2) ** 0.5 return distance 这样我们就可以在别的文件里调用这个Point类,如下所示: 1 2 3 4 5 6 7 from point import Point point1 = Point() point2 = Point(1, 2) print(point1.get_x()) # 0 print(point1.get_y()) # 0 print(point2.get_x()) # 1 print(point2.get_y()) # 2 从这里可以看出,Point类的方法中的self参数,就是当前的实例本身。 继承和多态 正如上文中提到的OOP的三大要素,Python中也可以轻松使用继承和多态。 Python中的继承通过在类名后面加上一个括号来实现。举个例子,一个平面直角坐标系上的点实际上可以当成是一个广义上二维向量的特殊形式,这里的Point类可以当成是一个Vector类的子类。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Vector: def __init__(self, x, y): self.x = x self.y = y def get_x(self): return self.x def get_y(self): return self.y def set_x(self, x): self.x = x def set_y(self, y): self.y = y def __str__(self): return "(" + str(self.x) + " " + str(self.y) + ")" class Point(Vector): def distance(self, other): dx = self.x - other.x dy = self.y - other.y distance = (dx**2 + dy**2) ** 0.5 return distance def __str__(self): return "<" + str(self.x) + "," + str(self.y) + ">" 这样一来,Point类继承了Vector类,并且复用了x和y属性,还有一堆getter和setter方法。而且,Point类还有一个distance方法,这是子类特有的。 而且,Vector和Point类都有__str__方法,但是它们的实现不一样,这样一来,在同样打印这些对象的时候,将会有不同的结果,这就是多态的体现。 1 2 print(Vector(1, 2)) # (1 2) print(Point(1, 2)) # <1,2> 变量的作用域 作用域(scope)的相关概念在Python中是非常重要的。这里介绍其中的主要概念。 作用域(scope)是指在一个程序中变量的访问范围。 生命周期(lifecycle)是指变量在程序执行中的存在时间。 全局变量(global variable) 是指在整个程序中都可以访问的变量。 只有在程序结束之后才会被销毁。 局部变量(local variable) 是指在一个函数中可以访问的变量。 在函数执行结束之后,这个变量就会被销毁。 1 2 3 4 5 6 7 8 9 def f(x): # ----local scope---- x = x + 1 print("f(x): x =", x) return x # ----local scope---- x = 3 # global scope z = f(x) # global scope 举个例子来说的话,上面函数f中缩进的那一部分内容都是一个局部作用域,f(x)中的x是一个局部变量。而函数之外的顶层代码,比如x = 3和z = f(x)中的x和z都是全局变量。函数内的x和函数外的x是不一样的两个变量,需要分清楚。 类中的作用域 而在class中,作用域就更加复杂了。 实例变量(instance variable) 和单个实例相关,并且在那个实例中是唯一的。 在类的内部是局部的,不能被外部直接访问(必须有实例才能访问)。 类变量(class variable) 在类的顶层定义的变量,和类相关,和实例无关。 一定程度上是全局的,只要通过类即可直接访问(也可以通过实例访问)。 1 2 3 4 5 6 7 class Point: counts = 0 # class variable def __init__(self, x=0, y=0): # x, y are local variables self.x = x # self.x is an instance variable self.y = y # self.y is an instance variable 访问这些变量: 1 2 3 4 5 print(Point.count) # 0 print(Point.x) # error p = Point(1, 2) print(p.x) # 1 print(p.counts) # 0 实践试试 对于刚接触OOP的同学来说,这可能是非常困难的,就算是作者也花了起码半年的时间才慢慢理解,但是我们可以通过下面的例子先来试试。这里提供了两个部分的实践,一个是继续探索并且拓展正文中提到的Point类,另一个则是写一个井字棋游戏。 探索Point类 首先来看看正文中提到的Point类。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Point: def __init__(self, x, y): self.x = x self.y = y def get_x(self): return self.x def get_y(self): return self.y def set_x(self, x): self.x = x def set_y(self, y): self.y = y def distance(self, other): dx = self.x - other.x dy = self.y - other.y distance = (dx**2 + dy**2) ** 0.5 return distance def __eq__(self, object): return self.x == object.x and self.y == object.y def __str__(self): return str(self.x) + " , " + str(self.y) 可以先试试判断一下各个变量所处的定义域。 类变量: 没有 实例变量: self.x, self.y 局部变量: dx, dy, distance 如果我们需要计算某个点到原点的距离,可以添加以下方法distance_to_origin: 1 2 def distance_to_origin(self): return self.distance(Point(0, 0)) 这里我们使用了distance方法,这样就可以通过复用方法来让代码变得更加清晰简洁。 如果假设以原点为圆心,经过这个点画一个圆,计算这个圆的面积,就可以添加以下方法area_of_circle来实现。 1 2 3 import math def area_of_circle(self): return math.pi * self.distance_to_origin() ** 2 如果我们创建了很多个Point,想要一直追踪创建的Point的数量,可以通过添加一个类变量count来记录。 1 2 3 4 5 6 7 8 9 10 class Point: count = 0 def __init__(self, x, y): self.x = x self.y = y Point.count += 1 def get_count(self): return Point.count 以上画的点是基于平面直角坐标系的,如果我们想要一个三维立体坐标的点,也可以定义一个类似的类Point3D来实现。 当然了,2D的Point中可以画圆来计算圆的面积,现在Point3D可以通过画球来计算球的体积。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Point3D: count = 0 def __init__(self, x, y, z): self.x = x self.y = y self.z = z Point3D.count += 1 def get_count(self): return Point3D.count def distance(self, other): dx = self.x - other.x dy = self.y - other.y dz = self.z - other.z distance = (dx**2 + dy**2 + dz**2) ** 0.5 return distance def distance_to_origin(self): return self.distance(Point3D(0, 0, 0)) def volumn_of_sphere(self): return 4/3 * math.pi * self.distance_to_origin() ** 3 def __str__(self): return str(self.x) + " , " + str(self.y) + " , " + str(self.z) def __eq__(self, object): return self.x == object.x and self.y == object.y and self.z == object.z 如果更进一步,我们想要一个类PointND,它能代表任意维度的点,比如三维的点,或者五维的点,其实也可以通过非常类似的方式来实现。当然这里计算的就不是球的体积而是超球体的体积了。 其中超球体的体积公式[8]为 $$V_{n}(R)={\frac {\pi ^{n/2}}{\Gamma \left({\frac {n}{2}}+1\right)}}R^{n}$$ 其中$\Gamma(n)$代表的是Gamma函数[9],如果$n$是正整数,则$\Gamma(n)=(n-1)!$。而Gamma函数将$n$的定义域拓展至所有非负整数的复数域上,这样就可以计算任意维度的超球体的体积。当然我们不用管那么多,Python自带的math库就有一个函数gamma可以直接计算Gamma函数。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import math class PointND: count = 0 def __init__(self, *xs): self.xs = xs self.n = len(xs) # number of dimensions def get_count(self): return PointND.count def distance(self, other): assert self.n == other.n # dimensions of 2 points should be the same distance_sq = 0 # sum up squares of differences for each dimension for i in range(self.n): dx = self.xs[i] - other.xs[i] distance_sq += dx ** 2 distance = distance_sq ** 0.5 return distance def distance_to_origin(self): return self.distance(PointND(*([0] * self.n))) def volumn_of_hypersphere(self): r = self.distance_to_origin() return math.pi ** (self.n / 2) / math.gamma((self.n / 2) + 1) * r ** self.n def __str__(self): return " , ".join(str(x) for x in self.xs) def __eq__(self, object): return self.xs == object.xs 井字棋游戏 井字棋(Tic-Tac-Toe)是一个两个玩家之间对战的游戏,游戏在一个3*3的棋盘上进行,每个棋子可以是X或O。如果一个玩家在棋盘上的某一行,某一列或者某一斜线上放置三个相同的棋子,则该玩家获胜。关于井字棋的更多信息可以参考Wiki[10]。 在这个部分,我们将试试开发一个简单的井字棋游戏,游戏将在两个人类玩家之间进行。这个意思是在这个部分不需要写一个复杂的AI代码。 对于棋盘的表示,我们可以用一个二维列表来实现。然后对于将要定义的Game类,则需要以下这些方法: start_game: 开始游戏 take_input: 接受玩家输入 check_for_win: 检查是否有玩家获胜 print_game: 打印棋盘状态 来试试看实现一下这个代码吧。 以下代码提供了其中一种解决思路。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 class Game: def __init__(self): self.board = [['-','-','-'],['-','-','-'],['-','-','-']] self.player_turn = 1 self.total_turns = 0 def start_game(self): flag = True while flag: self.print_board() self.take_input() t = self.check_for_win() if t == True: self.print_board() flag = False def take_input(self): x = int(input("Enter value for x. Value can be between 0, 1, 2: ")) y = int(input("Enter value for y. Value can be between 0, 1, 2: ")) if x >= 3 or y >= 3 or x < 0 or y < 0: print("Invalid point!") elif self.board[x][y] != '-': print("Already occupied.") else: if self.player_turn == 1: self.board[x][y] = 'x' self.player_turn = 2 self.total_turns += 1 else: self.board[x][y] = 'o' self.player_turn = 1 self.total_turns += 1 def check_for_win(self): win = False if self.board[0][0] == 'x' and self.board[0][1] == 'x' and self.board[0][2] == 'x' or \ self.board[1][0] == 'x' and self.board[1][1] == 'x' and self.board[1][2] == 'x' or \ self.board[2][0] == 'x' and self.board[2][1] == 'x' and self.board[2][2] == 'x': print("player 1 wins!") win = True elif self.board[0][0] == 'x' and self.board[1][0] == 'x' and self.board[2][0] == 'x' or \ self.board[0][1] == 'x' and self.board[1][1] == 'x' and self.board[2][1] == 'x' or \ self.board[0][2] == 'x' and self.board[1][2] == 'x' and self.board[2][2] == 'x': print("player 1 wins!") win = True elif self.board[0][0] == 'x' and self.board[1][1] == 'x' and self.board[2][2] == 'x' or \ self.board[0][2] == 'x' and self.board[1][1] == 'x' and self.board[2][0] == 'x': print("player 1 wins!") win = True elif self.board[0][0] == 'o' and self.board[0][1] == 'o' and self.board[0][2] == 'o' or \ self.board[1][0] == 'o' and self.board[1][1] == 'o' and self.board[1][2] == 'o' or \ self.board[2][0] == 'o' and self.board[2][1] == 'o' and self.board[2][2] == 'o': print("player 2 wins!") win = True elif self.board[0][0] == 'o' and self.board[1][0] == 'o' and self.board[2][0] == 'o' or \ self.board[0][1] == 'o' and self.board[1][1] == 'o' and self.board[2][1] == 'o' or \ self.board[0][2] == 'o' and self.board[1][2] == 'o' and self.board[2][2] == 'o': print("player 2 wins!") win = True elif self.board[0][0] == 'o' and self.board[1][1] == 'o' and self.board[2][2] == 'o' or \ self.board[0][2] == 'o' and self.board[1][1] == 'o' and self.board[2][0] == 'o': print("player 2 wins!") win = True elif self.total_turns == 9: print("It is a draw.") win = True return win def print_board(self): print(self.board[0]) print(self.board[1]) print(self.board[2]) 参考文献 [1] B. Eckel, “sebsauvage.net - Python”, Sebsauvage.net, 2021. [Online]. Available: http://sebsauvage.net/python/. [2] "paradigms", Cs.lmu.edu, 2021. [Online]. Available: https://cs.lmu.edu/~ray/notes/paradigms/. [3] "Object-Oriented Principles", D.umn.edu, 2021. [Online]. Available: https://www.d.umn.edu/~gshute/softeng/presentations/oo-principles.xhtml. [4] "What is Taxonomy?", Cbd.int, 2021. [Online]. Available: https://www.cbd.int/gti/taxonomy.shtml. [5] B. Liskov and J. Wing, "A behavioral notion of subtyping", ACM Transactions on Programming Languages and Systems, vol. 16, no. 6, pp. 1811-1841, 1994. Available: 10.1145/197320.197383. [6] "Java Tutorials - OOP Concepts | Encapsulation | Abstraction | Inheritance | Polymorphism", Btechsmartclass.com, 2021. [Online]. Available: http://www.btechsmartclass.com/java/java-oop-concepts.html. [7] "3. Data model — Python 3.9.7 documentation", Docs.python.org, 2021. [Online]. Available: https://docs.python.org/3/reference/datamodel.html#basic-customization. [8] "DLMF: 5.19 Mathematical Applications", Dlmf.nist.gov, 2021. [Online]. Available: https://dlmf.nist.gov/5.19#E4. [9] P. Davis, "Leonhard Euler's Integral: A Historical Profile of the Gamma Function", The American Mathematical Monthly, vol. 66, no. 10, pp. 849-869, 1959. Available: 10.1080/00029890.1959.11989422. [10] "Tic-tac-toe - Wikipedia", En.wikipedia.org, 2021. [Online]. Available: https://en.wikipedia.org/wiki/Tic-tac-toe. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/9/8
articleCard.readMore

Windows最佳动画观看环境配置指南(MPC-HC, madvr, SVP, Anime4K)

在PC上最好的动画观看体验需要复杂的环境配置和硬件支持,本文介绍了这一套方案同时有极佳的上采样和去噪的画质,也有插帧带来流畅的拉镜头效果。如果你曾经只在线观看过动画的,请一定要试试。本文介绍的这一套方案使用MPC-HC播放器[1],madvr滤镜[2],SVP插件[3]和Anime4K着色器[10]。 有人可能会说,网上随便下载的高压缩流媒体源的动画根本没必要用那么复杂的设置,其实正好相反,madvr和SVP的优势是把这些高压缩的充满噪点、色带和卡顿的画面进行处理,让视频的观感大幅提升。在提升幅度上是远远超出在蓝光原盘中使用madvr渲染的。所以画质越差,分辨率越低(比如720p),它的提升幅度越大。当然,能有高画质源当然是要选更好的。在本文的最后,将会有画质对比。 软件准备 首先先下载以下软件作为准备。 madvr: 视频渲染器 http://madvr.com/ XySubFilter: 字幕渲染器 https://github.com/Cyberbeing/xy-VSFilter SVP4: 补帧插件(商业收费软件,请自行按需搜索别的来源下载)https://www.svp-team.com/ Anime4K: 超分辨率着色器(支持HLSL的最后一个版本)https://github.com/bloc97/Anime4K/releases/download/v0.9/Anime4K_HLSL.zip 软件安装 madvr 同样可以从官网安装,也可以使用包管理器。 如果是从官网上安装,会相对来说麻烦一点,把madvr文件夹解压到你想保存的地方,并且运行install.bat注册madvr渲染器。然后这个文件夹不能删,它就是这个软件的自身。 SVP SVP是一款补帧软件,可以把24帧的动画补帧到你想要的任何帧数(受限于硬件),对于动画而言,最重要的是可以把拉镜头的各种衔接变得流畅,而动作部分由于动画的制作流程问题(原画帧数极低),依然能保持原有的风味。最大的问题是果冻效应和鬼影,不过可以根据自己对比进行取舍。 SVP是一款商业软件,请大家支持正版。安装过程中会自动安装需要的ffdshow分离器解码器和MPC-HC播放器,所以基本上是非常方便了。 在第一步选择中,请只选择32位的(第一项),64位好像怎么测试都无法正常运行。 Fig. 1. SVP安装第一步 第二步的时候,记得勾选第一项安装MPC-HC(32位)播放器,如果上步没有安装madvr也可以在这里安装。 Fig. 2. SVP安装第二步 第三步,根据自己的勾选即可。MPC-HC是默认使用LAV音视频解码器[5],所以就不用再配置LAV了。如果使用potplayer这种,还需要自己配置LAV Filter。 Fig. 3. SVP安装第三步 剩下的就等安装完毕了。 XySubFilter 在使用madvr和SVP渲染之后,使用XySubFilter作为字幕渲染器可以更好的还原字幕的显示效果。 在GitHubhttps://github.com/Cyberbeing/xy-VSFilter[4]中的Release下载解压,并且管理员运行Install_XySubFilter.bat即可。 MPC-HC配置 启动MPC-HC,打开设置,进入”回放 - 输出”,按照下图红框的指示,配置渲染器为madvr,字幕渲染器为XySubFilter。 Fig. 4. MPC-HC配置madvr和XySubFilter 第二步进入到设置中的”扩展滤镜”中,选择添加滤镜,找到”ffdshow raw video filter”,如果没有找到说明其中一个并不是安装的64位版本,需要重新安装32位的MPCHC和SVP。然后根据红框位置,要设置为”首选”。只有分离器使用ffdshow,才能使用SVP。 Fig. 5. MPC-HC配置ffdshow / SVP 然后可以测试一下,随便打开一个动画,注意观察任务栏右下角的图标,看看有没有出现”ffdshow”和”madvr”的图标,如下图红框中的两个所示。 Fig. 6. 运行成功时右下角的图标 如果成功了,说明MPC-HC已经成功调用madvr和SVP了,这是一个好的开始,下一步就是配置这些工具的设置。 LAV解码器配置 在这一步参考了这篇攻略[6]。 首先需要打开MPC-HC设置中的”内部滤镜”中的这几个,先从”音频解码器”开始。 Fig. 7. LAV解码器设置的位置 音频解码器中进入”Mixing”页面,勾选”Enable Mixing”,这个设置可以将一些5.1,7.1这种多声道的音频混合输出到目前使用的声道,这样不会丢弃一些没有的声道的信息。下图是一个对于双声道的设置例子。如果是用单声道的,请不要勾选”Don’t mix Stereo sources”不然会丢失信息。需要按照自己的情况进行选择,如果是双声道的耳机/音响就选”Stereo”,如果是单声道的音响就选”Mono”,如果你用的已经是5.1甚至7.1声道的设备了,忽略本段,不使用”Mixer”设置。 Fig. 8. LAV音频解码器的设置 下一步进入视频解码器设置,基本上保持默认即可。只要确定红框位置正确即可,硬件解码器如果有的话建议选择”DXD11(copy-back)”,没有的话就”DXVA2(copy-back)”,copy-back是无损的,并且可以允许后续处理。硬件选择是”Automatic”即可。 Fig. 9. LAV视频解码器的设置 madvr配置 这一部分的设置可以参考这篇文章[7]。 打开一个视频播放,右下角应该会出现madvr的图标,双击即可打开设置。 注意:madvr设置和SVP设置极大受到硬件性能影响,请根据CPU、GPU、内存的性能酌情调整。这里参考的配置是针对RTX3080Ti + i7 8700K + 32G 3200的硬件考虑的。 设备部分配置 首先需要进入下图所示的区域,在需要播放的显示器设备中,选择”properties”把RGB level设置为”PC levels (0-255)”。 Fig. 10. madvr设置显示器配置 去压缩效果 在面对高压缩的流媒体动画视频时,这个部分起到的观感效果极佳,下图是设置。 Fig. 11. madvr设置去压缩效果 Fig. 12. 去压缩效果对比, Nekopara第三话. Adapted from [8] 上图可以看到效果开关的对比。关闭时,因为压缩造成的噪点在相对颜色单一的墙砖上清晰可见,这种在流媒体动画视频中很常见,开启就可以去噪。 锐化处理 在”image enhancements”页面,可以对线条和边缘的锐化设置进行调整,个人觉得意义不大,特别是”thin edges”它会将像素整个进行偏移填充,让画面中物体的结构比例都发生变化了,可以自行测试,个人不喜欢。而”crispen edges”会造成生硬的锐化,反而让观感变差了。所以只打开了”sharpen edges”和”enhance detail”。 Fig. 13. madvr设置锐化处理 这个页面带来的观感变化其实不大,故对比略去。 上采样处理 这一部分极为重要,它可以使用有效的实时上采样算法,将低分辨率的视频更好的展示在高分辨率的显示设备下。现在2K,4K分辨率的普及率很高,而动画主要还是1080P的,所以起到的效果很好。 首先是色度上采样,如下图所示。 Fig. 14. madvr色度上采样设置. Adapted from [7] 这里个人的选择是”NGU + Anti-Alias, very high quality”。低配电脑可以选择”super-xbr”。 然后是下采样,也就是高分辨率视频在低分辨率下播放时使用的算法。 Fig. 15. madvr下采样设置. Adapted from [7] 这里选择了和上图一样的配置,”SSIM + 1D 100% + scale in linear light”,感觉下采样一般用的不多无所谓。 然后图像上采样,这个就是所谓的把低分辨率提升到高分辨率的算法。 Fig. 16. madvr图像上采样设置. Adapted from [7] 这里个人的选择是”NGU Sharp + high + 剩下默认”,配置低一些的话可以使用”Jinc”或者”super-xbr”。 至此,基本上madvr的配置就差不多了,剩下的部分其实不是很重要,当然也可以自己去按需修改。 这里来一个简单的对比。 Fig. 17. madvr开关对比, 赛马娘第二季第五话. Adapted from [9] 可以看到线条的清晰度有一个明显的改观,这样的提升不仅仅发生在局部,而是一个整体的观感提升。 以上配置在这台3080Ti的GPU下,从1080p升采样到4K,播放时GPU的占用大约为29%。不能把GPU吃的太满,还要为后面的SVP插帧预留性能。 SVP设置 首先需要应用4GB补丁,右击SVP任务栏图标,如下图所示。然后再选择MPC-HC软件的位置即可。 Fig. 18. SVP应用4GB补丁. 双击打开SVP界面,如下图所示。手动选择你想要的帧数,一般感觉60就够了。优化选择”动画”。伪影去除和性能质量选择可以自己调整。 Fig. 19. SVP设置. 然后再是禁止SVP使用黑边填充,因为这个东西在有些视频播放时,会突然卡住,然后切换过去,然后就没字幕了等等,总而言之特别的不好用,建议直接关闭。如下图所示。 Fig. 20. SVP禁止黑边填充. Anime4k配置 根据教程[10],首先将下载的Anime4K着色器HLSL文件解压到”C:\Users\<username>\AppData\Roaming\MPC-HC\Shaders”下。再打开MPC-HC的设置,进入”回放 - 着色器”,点击”添加着色器文件”,将这些HLSL文件全部添加。如下图所示。 Fig. 21. Anime4k添加着色器. 再根据上图红框位置,将对应的着色器添加到”重绘尺寸后”。注意顺序很重要!如果显示器画面是1080p及以下,需要把”Anime4K_PushGrad”换成”Anime4K_PushGrad_Weak”。这样设置就完成了。在madvr的加持下,感觉提升幅度主要在线条锐化上,提升幅度有但是不是很大,还好Anime4K本身并不是很吃资源,所以还不错。 在以上设置下,GPU占用大约为70%,不丢帧(丢帧情况可以在MPC-HC中按Ctrl+4查看)。已经是极限了,如果再调高一点madvr的设置就会丢帧。 参考文献 [1] "MPC-BE", SourceForge, 2021. [Online]. Available: https://sourceforge.net/projects/mpcbe/. [2] "madVR", Madvr.com, 2021. [Online]. Available: http://madvr.com/. [3] "SVP – SmoothVideo Project – Real Time Video Frame Rate Conversion", Svp-team.com, 2021. [Online]. Available: https://www.svp-team.com/. [4] "GitHub - Cyberbeing/xy-VSFilter: Official xy-VSFilter Repository", GitHub, 2021. [Online]. Available: https://github.com/Cyberbeing/xy-VSFilter. [5] "GitHub - Nevcairiel/LAVFilters: LAV Filters - Open-Source DirectShow Media Splitter and Decoders", GitHub, 2021. [Online]. Available: https://github.com/Nevcairiel/LAVFilters. [6] "​小科普 | 让画质更上一层楼!配置mad VR和LAV Filters(上)_服务软件_什么值得买", Post.smzdm.com, 2021. [Online]. Available: https://post.smzdm.com/p/apz39zr2/. [7] "小科普 | 让画质更上一层楼!配置madVR和LAV Filters(下)_服务软件_什么值得买", Post.smzdm.com, 2021. [Online]. Available: https://post.smzdm.com/p/awx02qr2/. [8] Nekopara Project, "NEKOPARA TVanime Official HP", NEKOPARA TVanime Official HP, 2021. [Online]. Available: https://nekopara-anime.com/en/. [9] "TVアニメ『ウマ娘 プリティーダービー Season 2』公式サイト", TVアニメ『ウマ娘 プリティーダービー Season 2』公式サイト, 2021. [Online]. Available: https://anime-umamusume.jp/. [10] "Anime4K", Anime4K, 2021. [Online]. Available: https://bloc97.github.io/Anime4K/. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/7/31
articleCard.readMore

计算机视觉中的Transformer续

上一篇文章《计算机视觉中的Transformer》讲了计算机视觉中的Transformer结构[1],还有非常受欢迎的Vision Transformer(ViT)[2]。本篇文章将补上上一篇掠过的《Attention Augmented Convolutional Networks》[3]和《End-to-End Object Detection with Transformers》[4],同时也会介绍一下DeiT (Data-effieciency Image Transformer)[5]。 Self-Attention回顾 Transformer的核心是Self-Attention。Self-Attention是基于特征向量对序列上token成对关系的表征学习(Representation Learning)。 Fig. 1. Self Attention. 计算方式大致如下: 序列: $X\in R^{n\times d}$ Query向量: $Q$有相对应的可学习权重$W^Q\in R^{n\times dq}$ Key向量: $K$也有相对应的可学习权重$W^K\in R^{n\times dk}$ Value向量: $V$也有相对应的可学习权重$W^V\in R^{n\times dv}$ $Q=XW^Q, K=XW^K, V=XW^V$ Self-Attention层: $Z=softmax(\frac{QK^T}{\sqrt{d_q}})V$ 若是Masked Self-Attention层,则需要增加一层mask: $softmax(\frac{QK^T}{\sqrt{d_q}}\circ M)$ Fig. 2. Self Attention运算过程. Adapted from [1] 这里展示的是一个简单的Self-Attention计算方式,对于[1]同时提出的Multi-Head Self-Attention,可以将上述过程并行的执行多次来模拟不同的head。 在2021年,计算机视觉领域中的Transformer和Self-Attentio的相关技术已经发展了很多。我们可以使用以下这张图来理解今天的Self-Attention相关技术的不同类型。 Fig. 3. Self Attention不同类型. Adapted from [6] 在上图中能看到不同的Attention类型,比如Local Attention, Global Attention, Vectorized Attention。下图介绍了这些类型的大致计算流程。 Fig. 4. Self Attention的不同类型. Adapted from [6] 用Attention增强卷积 从之前我们可以了解到,Self-Attention可以很好的找到距离较远的token之间的关系,而普通的卷积层只能计算非常有限的范围。如果我们能够将这些距离较远的token之间的关系计算出来,那么就可以使用Self-Attention来弥补卷积层的这个缺陷,对图像分析是有帮助的。而且卷积层是等变的,在不同区域的卷积用的是同一个参数。所以在2019年的时候,这篇文章的作者看到Self-Attention已经被广泛运用于NLP领域,所以就想到了用Self-Attention来增强卷积,并且使用基于相对位置的Positional Encoding用于解决上述说的等变问题[3]。 Flatten和Attention层 先介绍会在这个部分中使用的一些数学符号: $H, W, F_in$是指特征图中高度、宽度、输入feature map的数量 $N_h, d_v, d_k$是指head的数量,value和key的维度。其中$N_h$是可以整除$d_v$和$d_k$的。 $d^h_v, d^h_k$是指每一个head中value和key的维度。 Fig. 5. Attention Augmented Convolution的计算过程. Adapted from [3] 第一步是需要将输入的特征图进行flatten,从$(H,W,F_in)$变成一个新矩阵$X\in \mathbb{R}^{HW\times F_{in}}$。然后把它放进标准的Multi-head Attention(MHA)层中,于是输出它的输出则是, $$O_h=Softmax(\frac{(XW_q)(XW_k)^T}{\sqrt{d^h_k}})(XW_v)$$ Positional Encoding 在这篇文章,作者使用了一个基于像素的相对位置的Positional Encoding,专门用于图像分析。其实这个相对位置的Positional Encoding之前已经提出,具体的可以参考这篇[7]。 它的计算方式是 $$l_{i,j}=\frac{q_i^T}{\sqrt{d_k^h}}(k_j+r^W_{j_x-i_x}+r^H_{j_y-i_y})$$ 其中$r$是Positional Encoding,$i$是当前token所代表的像素,$j$是计算Self-Attention时的目标像素,而$x$和$y$则是像素的位置。将这个计算向量化后, $$O_h=Softmax(\frac{QK^T+S_H^{rel}+S_W^{rel}}{\sqrt{d^h_k}})V$$ 这篇作者也提到,根据他们的实验,最好的效果是同时使用传统卷积层和Attention层的输出,所以以上的结果要通过一个简单的拼接层来获得。 $$AAConv(X)=Concat[Conv(X),MHA(X)]$$ 实验结果 首先是每篇论文都会提到的自己的方法比别人强。 Fig. 6. Attention Augmented用于分类的实验结果. Adapted from [3] 可见,用于一些传统的CNN模型,用Attention增强卷积的方法可以得到更好的结果。对于COCO数据集的对象检测也是一样的,这里就不再赘述了。 不过其中最有趣的还是Positional Encoding的对比。 Fig. 7. Positional Encoding是否使用的对比结果. Adapted from [3] 能看到这个Positional Encoding真的是很有用,所以在Transformer中的Self-Attention层中基本人人都会用它。 E2E的Transformer对象检测 在2020年的时候,一篇论文[4]提出了一个E2E的Transformer对象检测模型Detection Transformer (DETR),它非常有开创性的使用Transformer结构实现了一个完全端到端的训练方式。这有什么好处呢?首先之前的对象检测模型很多都是需要Proposal,Anchor,或者Window之类的容易出错,而且还需要一些人工处理,比如说非最大值抑制等等。这些东西在一定程度上会影响模型的性能。如果能使用E2E的模式避免人工处理的情况下训练,那就能解决这个问题。 首先来看一下它的结构。 Fig. 8. DETR结构. Adapted from [4] 这个结构是由一个骨干网络,Positional Encoding,Transformer,以及一个FFN预测头组成的。让我们一个一个看。 骨干特征提取器 首先是第一步的backbone,这一部分在原文中是一个CNN的特征提取器,需要从图像中提取出高价值的特征图。在原文中对于一个图像为$x_{img}\in \mathbb{R}^{3\times H_0 \times W_0}$,在骨干网络后将会变成一个特征图$f\in \mathbb{R}^{C\times H\times W}$。他们设定的值是$C=2048$ $H,W=\frac{H_0}{32},\frac{W_0}{32}$ 。 Transformer部分 通过骨干网络得到的特征图会通过一个1x1卷积压缩通道数,得到$z_0\in\mathbb{R}^{d\times H\times W}$。因为这个Transformer编码器希望得到一个序列作为输入,所以不能用一个三维的矩阵,需要压平成二维。这个特征图将会被flatten到$(d\times HW)$。对于每一层Transformer编码器,都有一个Self-Attention层和FFN,就像原版Transformer一样。作者还特地说明了,对于每一层,都添加了一个固定的不可训练的Positional Encoding加到输入中去。对于Self-Attention层和Transformer编码器部分相信大家都很熟悉了,但是这个网络还使用了Transformer解码器部分,这需要好好看看。 Fig. 9. DETR中的Transformer部分. Adapted from [4] 这里我们可以看到,它并没使用原版Transformer中的Masked Multi-Head Self-Attention层,可能是因为原版的是对于时间序列的预测所以需要遮盖未来时间的序列元素,但是这里是图像分析,则不需要这些。然后是对于编码器的Attention层,和解码器的第二个Attention层,都使用了Positional Encoding,而且是每一层都会使用。 这里的Object queries其实是一个可学习的参数,原文中设定的长度是$N=100$。剩下的都是一些相加融合,根据这张图应该是很容易理解的。 FFN预测头 在解码器的输出得到嵌入序列之后,对于序列中的每一个元素都通过两个FFN网络,一个用于预测类型,一个用于预测Box。 这些FFN在原文中使用的是一个3层MLP和ReLU。对于一个91个类的多分类问题,这里的类型预测FFN会输出一个92长度的向量,多出来的一个代表”没有对象($\phi$)”。这个预测Box会被编码成中心坐标(x, y)和宽度高度(w, h),也就是长度为4的向量。由于这个预测框的数量等于Object Queriesd的数量$N$且是固定且有限的,所以必须要远大于实际可能的预测框数量。 损失函数 因为预测出的是长度为$N$的一系列无序的box,而ground truth是一个长度远小于$N$的序列。所以在计算损失时,需要将预测的box和ground truth进行匹配。这里需要搜索到一个有最小损失值的box匹配,然后计算这个最小损失。这个匹配$\sigma$是: $$\hat{\sigma}=\mathop{\arg\min}_{\sigma\in\mathfrak{S}_N}\sum^N_i \mathcal{L}_{match}(y_i,\hat{y}_{\sigma(i)})$$ 对于这个问题,使用Hungarian算法可以有效的解决,找到ground truth和预测结果的最优匹配。这里的$\mathcal{L}_{match}$是一个二分图匹配的损失函数,其中$y_i$是ground truth的第i个box,$\hat{y}_{\sigma(i)}$是预测的第i个box。对于第i个预测$\sigma(i)$,定义类别$c_i$的概率是$\hat{p}_{\sigma(i)}(c_i)$,预测的box是$\hat{b}_{\sigma(i)}$。定义这个损失函数为: $$\mathcal{L}_{match}=-\mathbb{1}_{\{c_i\neq\emptyset\}}\hat{p}_{\sigma(i)}(C_i)+\mathbb{1}_{\{c_i\neq\emptyset\}}\mathcal{L}_{box}(b_i,\hat{b}_{\sigma(i)})$$ 与上面的等式结合,可以得到Hungarian损失函数, $$\mathcal{L}_{Hungarian}(y,\hat{y})=\sum^N_{i=1}[-log\hat{p}_{\hat{\sigma}(i)}(C_i)+\mathbb{1}_{\{c_i\neq\emptyset\}}\mathcal{L}_{box}(b_i,\hat{b}_{\hat{\sigma}}(i))]$$ 其中的$\hat{\sigma}$是上面找到的最佳匹配方式。 对于box损失,这里使用GIOU损失函数[8]。 再对L1损失和IOU损失进行线性组合,得到最终的损失函数, $$\mathcal{L}=\lambda_{iou}\mathcal{L}_{iou}(b_i,\hat{b}_{\sigma(i)})+\lambda_{L1}||b_i-\hat{b}_{\sigma(i)}||_1$$ 其中的$\lambda_{iou}$和$\lambda_{L1}$是超参数。 然而除此之外,他们还使用了解码器辅助损失(Auxiliary decoding loss)。添加到每一个解码器层后面,预测class和box并计算上述损失$\mathcal{L}$。 推断代码 作者们另外提供了一个基于PyTorch的用于推断的代码,放在这里有助于理解。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import torch from torch import nn from torchvision import resnet50 class DETR(nn.Module): def __init__(self, num_classes, hidden_dim, nheads, num_encoder_layers, num_decoder_layers): super().__init__() # We take only convolutional layers from ResNet-50 model self.backbone = nn.Sequential(*list(resnet50(pretrained=True).children())[:-2]) self.conv = nn.Conv2d(2048, hidden_dim, 1) self.transformer = Transformer(hidden_dim, nheads, num_encoder_layers, num_decoder_layers) self.linear_class = nn.Linear(hidden_dim, num_classes + 1) self.linear_bbox = nn.Linear(hidden_dim, 4) self.query_pos = nn.Parameter(torch.randn(100, hidden_dim)) self.row_embed = nn.Parameter(torch.randn(50, hidden_dim // 2)) self.col_embed = nn.Parameter(torch.randn(50, hidden_dim // 2)) def forward(self, inputs): x = self.backbone(inputs) h = self.conv(x) H, W = h.shape[-2:] pos = torch.cat([ self.col_embed[:W].unsqueeze(0).repeat(H, 1, 1), self.row_embed[:H].unsqueeze(1).repeat(1, W, 1) ], dim=-1).flatten(0, 1).unsqueeze(1) h = self.transformer(pos + h.flatten(2).permute(2, 0, 1), self.query_pos.unsqueeze(1)) return self.linear_class(h), self.linear_bbox(h).sigmoid() detr = DETR(num_classes=91, hidden_dim=256, nheads=8, num_encoder_layers=6, num_decoder_layers=6 ) detr.eval() inputs = torch.randn(1, 3, 800, 1200) logits, bboxes = detr(inputs) Listing 1: DETR PyTorch推断代码. Adapted from [4] 实验结果 他们使用了COCO数据集用于测试这个方法。 Fig. 10. DETR实验结果. Adapted from [4] 一言以蔽之,相比于FasterRCNN,DETR更好。 然后他们也测试了一下编码器层的数量,解码器层的数量,辅助损失,FFN,Positional Encoding的重要性,发现都很重要,都是需要的。 Fig. 11. $N$个Object Queries的预测可视化. Adapted from [4] 通过上图可以看出,这些预测插槽也已经学习到了box的预测模式,每一个插槽是专注于其中的少数几种box的样式。 Fig. 12. DETR用于图像分割. Adapted from [4] 如上图所示,DETR架构也可以用于图像分割,并且也在实验中取得了比其他方法更好的结果。 Transformer和知识蒸馏 在2020年底,ViT发布两个月后,这篇论文《Training data-efficient image transformers & distillation through attention》[5]介绍了他们的新方法Data-efficient image Transformers (DeiT),这是一个用少量数据和时间训练,就可以达到SOTA水平的方法。对于一个差不多参数量的ViT,需要一个Cloud TPU v3训练83天。而对于DeiT,只需要4个GPU训练3天,可见效率提升很大。 此外,之前的ViT需要在谷歌未公开的数据集JFT-300M用3亿张图片进行训练,而这个只需要在公开的ImageNet上训练就已经能达到SOTA的水平,所以这个模型是data-efficient的。 它主要的方法是通过知识蒸馏(knowledge distillation)的方法,并且做了不少实验,对比了不同的实验设定有怎样的效果。 它的基本结构如下图所示。 Fig. 13. DeiT架构. Adapted from [5] 知识蒸馏 知识蒸馏是一种知识训练方法,其中知识是由一个预训练的教师模型和一个需要训练的学生模型组成。知识蒸馏除了能有效的压缩模型,还能有效的提升学生模型的性能。 由Fig. 13可以看出,相比于之前的ViT,它多了一个知识蒸馏的部分。首先是输入部分,除了左下角的class token之外,还增加了一个右下角的distillation token。这个distillation token经过Transformer会输出一个值用于计算蒸馏损失。 蒸馏损失 关于蒸馏损失,这篇文章给出了两种方法,分别是硬蒸馏和软蒸馏。 $$\mathcal{L}_{dis}^{hard}=\frac{1}{2}\mathcal{L}_{CE}(\psi(Z_s),y)+\frac{1}{2}\mathcal{L}_{CE}(\psi(Z_s),y_t)$$ $$\mathcal{L}_{dis}^{soft}=(1-\lambda)\mathcal{L}_{CE}(\psi(Z_s),y)+\lambda\tau^2KL(\psi(Z_s/\tau),\psi(Z_t/\tau))$$ 其中,$Z_t$是教师模型的logits输出,$Z_s$是学生模型的logits输出,$y_t$是老师模型的label,$y$是ground truth。$\tau$是超参数蒸馏温度,$\lambda$是蒸馏损失和交叉熵损失的比例。另外,$\mathcal{L}_{CE}$指的是交叉熵损失,$\psi()$指的是sigmoid函数。 根据作者的实验结果,硬蒸馏的训练效果更好。 教师模型的选择 Fig. 14. 教师模型的实验结果对比. Adapted from [5] 作者对不同的教师模型进行了横向对比,根据上图的实验结果,可以看出使用CNN的效果要比Transformer更好。 其他超参数 作者对于训练用的很多参数都做了实验对比测试,其中包括学习率,参数初始化方法,weight decay,dropout,还有数据增强,优化器和正则化等等。对于详细的内容请参考原文,因为仅仅是实验结果而已,这里就不多做展示了。 这篇文章给Transformer使用知识蒸馏提供了很多意见和想法,如果在未来需要用一些比较高效的方法来训练Transformer,可以参考这篇文章。 参考文献 [1] A. Vaswani et al., “Attention is all you need,” in Proceedings of the 31st International Conference on Neural Information Processing Systems, Red Hook, NY, USA, Dec. 2017, pp. 6000–6010. [2] A. Dosovitskiy et al., “An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale,” arXiv:2010.11929 [cs], Oct. 2020, [Online]. Available: http://arxiv.org/abs/2010.11929. [3] I. Bello, B. Zoph, A. Vaswani, J. Shlens, and Q. V. Le, “Attention Augmented Convolutional Networks,” in Proceedings of the IEEE/CVF International Conference on Computer Vision, 2019, pp. 3286–3295, [Online]. Available: https://openaccess.thecvf.com/content_ICCV_2019/html/Bello_Attention_Augmented_Convolutional_Networks_ICCV_2019_paper.html. [4] N. Carion, F. Massa, G. Synnaeve, N. Usunier, A. Kirillov, and S. Zagoruyko, “End-to-End Object Detection with Transformers,” in Computer Vision – ECCV 2020, Cham, 2020, pp. 213–229, doi: 10.1007/978-3-030-58452-8_13. [5] H. Touvron, M. Cord, M. Douze, F. Massa, A. Sablayrolles, and H. Jegou, “Training data-efficient image transformers & distillation through attention,” in International Conference on Machine Learning, Jul. 2021, pp. 10347–10357. Accessed: Jul. 22, 2021. [Online]. Available: http://proceedings.mlr.press/v139/touvron21a.html [6] S. Khan, M. Naseer, M. Hayat, S. W. Zamir, F. S. Khan, and M. Shah, “Transformers in Vision: A Survey,” arXiv:2101.01169 [cs], Feb. 2021, Accessed: Apr. 23, 2021. [Online]. Available: http://arxiv.org/abs/2101.01169 [7] P. Shaw, J. Uszkoreit, and A. Vaswani, “Self-Attention with Relative Position Representations,” arXiv:1803.02155 [cs], Apr. 2018, Accessed: Jul. 25, 2021. [Online]. Available: http://arxiv.org/abs/1803.02155 [8] H. Rezatofighi, N. Tsoi, J. Gwak, A. Sadeghian, I. Reid, and S. Savarese, “Generalized Intersection Over Union: A Metric and a Loss for Bounding Box Regression,” in Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition, 2019, pp. 658–666. Accessed: Jul. 26, 2021. [Online]. Available: https://openaccess.thecvf.com/content_CVPR_2019/html/Rezatofighi_Generalized_Intersection_Over_Union_A_Metric_and_a_Loss_for_CVPR_2019_paper.html #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/7/27
articleCard.readMore

Python编程基础05:Python的过程分解和文件IO

人生苦短,我用Python![1] 这次的主要内容主要是介绍Python中的过程分解和文件IO。过程分解包括了函数(function),模块(module)。而文件IO主要是介绍使用Python打开文件并进行读写操作。 过程分解概念 过程分解是一种解决编程问题的策略。它将一个复杂的问题分解为一个一个的小问题,这些小问题更简单,更独立,并且更易于管理,然后通过某种方式来解决这些小问题。通过使用这种方法,编程也会变得简单,更容易理解,更方便做规划和实现。 Fig. 1. 台式机的硬件可拆分也是一种分解思维. Adapted from [2] 要合理的分解这些组件,需要清晰的认识每一个部件的输入和输出。在Python中,过程分解是主要由函数(Function),模块(Module)和类(Class)组成。其中最主要的关键,是提升整体代码的复用性(Reusability)。 函数 函数(Function)是Python中的重要组成部分。函数是一种独立的语句集合,是为完成某一个特定的任务,解决一个特定的问题而定义的。 它可以使用任意数量的参数作为输入,并且返回任意数量任意类型的值。函数需要先创建,然后再进行调用。 函数是对过程或者功能的一种抽象。用户只需要知道怎么把函数用起来去解决问题,而不需要知道函数内部是怎么工作的。 Python中的函数 在Python中,函数是使用关键字def定义的。在函数的开头,需要定义函数的名称和参数(Argument)。函数的名称,参数和返回值构成了函数签名。 函数的组成部分: 函数名 参数(0或多个) 文档注释(可选) 函数体 返回值(可选) 函数的命名规范: 与变量名相同 使用camelCase或者underscore 必须以字母或者下划线开头,并且只能包含字母、数字或者下划线 Fig. 2. 创建一个函数. 定义一个函数(有参数) 1 2 3 def addition_func(first_arg, second_arg): result = first_arg + second_arg return result 定义一个函数(默认参数) 1 2 3 def addition_func(first_arg=0, second_arg=0): result = first_arg + second_arg return result 调用函数: 位置参数(不带关键字): 得按照函数定义的顺序来调用 关键字参数: 使用关键字来调用 1 2 3 4 5 6 7 8 9 10 11 sum = addition_func(10, 8) print("The result is", sum) # The result is 18 sum = addition_func(second_arg=8) print("The result is", sum) # The result is 8 sum = addition_func(2, second_arg=8) print("The result is", sum) # The result is 10 return和print的区别 return: return只能用在函数内部,否则会有语法错误 在一个函数中只会运行一次return 在函数里return后面的代码将不会被运行 这个return的值将会赋予函数的调用者 print: print可以用在函数外部,也可以用在函数内部 可以在函数内部执行多次 在函数里print后面的代码可以继续运行 这个print的值将会输出至控制台 main函数 main函数是一个特殊的函数,它指示程序的执行流程,定义了程序的入口点。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def function1(): ... def function2(): ... def function3(): ... def main(): function2() function3() function1() if __name__ == "__main__": main() Fig. 3. 函数的执行流程. 模块 Python中的模块(module)是一个包含了定义和语句的Python源代码文件。模块可以被其他程序引用,以使用它们中的函数,类,以及变量。 为了在另一个Python程序中使用别的模块(.py文件): 使用import关键字 语法: import <module_name> import <module_name> as alias 使用已导入模块中的某一个函数: 语法: <module_name>.<function_name> <alias>.<function_name> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # Module name: arithmetic.py # Description: Defined four arithmetic functions def addition_func(first_arg, second_arg): result = first_arg + second_arg return result def subtraction_func(first_arg, second_arg): result = first_arg - second_arg return result def multiplication_func(first_arg, second_arg): result = first_arg * second_arg return result def division_func(first_arg, second_arg): result = first_arg // second_arg return result 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import arithmetic as arm def main(): num1 = int(input("Enter first number: ")) num2 = int(input("Enter second number: ")) operator = input("Enter +, -, *, or /: ") if operator == "+": output = arm.addition_func(num1, num2) print("The result is", output) elif operator == "-": output = arm.subtraction_func(num1, num2) print("The result is", output) elif operator == "*": output = arm.multiplication_func(num1, num2) print("The result is", output) elif operator == "/": output = arm.division_func(num1, num2) print("The result is", output) else: print("Invalid operator!") if __name__ == "__main__": main() 为什么要使用函数 DRY法则: 不要重复你的代码(Don’t Repeat Yourself) 将复杂任务分解为一系列简单任务 提升代码的可读性 代码复用 文件IO 打开文件: open(file, mode) 创建一个文件句柄(对文件进行各种操作的对象) 两个关键的参数: file: 文件路径(可以是绝对路径,也可以是相对路径) mode: 文件的操作模式(如下所示)[3] 在中文的Windows系统中,可能需要使用encoding="UTF-8"来指定文件的编码方式,否则可能会出现乱码。因为文件的写入格式和读取格式需要相同。 mode含义 "r"读取(默认) "w"覆盖写入 "x"新建文件并写入 "a"在文件末尾追加写入 "b"二进制 "+"打开文件用于更新(可读可写) 读取文件 读取一个文件: input_handle = open(file, "r") input_handle.readline(): 从文件中读取一行(包含\n) for line in input_handle: 遍历文件中的每一行 input_handle.readlines(): 读取整个文件,返回一个列表,每个元素为一行 input_handle.read(): 读取整个文件,返回一整个字符串 关闭一个文件: input_handle.close() 使用完之后,不要忘记关闭文件 1 2 3 4 5 6 7 8 9 10 11 # open a file for reading file_handle = open("input_file.txt", "r") # create a list to hold each line list_of_lines = [] # read one line each time, add it to list for line in file_handle: list_of_lines.append(line) # display the content read from the file print(list_of_lines) # close the file after reading file_handle.close() 也可以使用with关键字 1 2 3 4 5 6 7 8 9 # open a file for reading with open("input_file.txt", "r") as file_handle: # create a list to hold each line list_of_lines = [] # read one line at a time, add it to list for line in file_handle: list_of_lines.append(line) # display the content read from the file print(list_of_lines) 写入文件 打开一个文件用于写入: open(file, "w"): 覆盖原有文件中的内容 open(file, "a"): 在文件的末尾追加写入 写入文件: file_handle.write(the_line): 写入一行 注意: \n作为换行符,需要手动添加到每行的末尾。 1 2 3 4 5 6 7 8 9 10 11 12 # open the input file for reading input_handle = open(input_file, "r") # open the output file for writing output_handle = open(output_file, "w") for line in input_handle: # perform some data processing line = line.lower() output_handle.write(line) # close both files after processing input_handle.close() output_handle.close() 也可以使用with关键词 1 2 3 4 5 with open(input_file, "r") as input_handle, open(output_file, "w") as output_handle: for line in input_handle: # perform some data processing line = line.lower() output_handle.write(line) 实践试试 这次我们来试试看使用学到的文件IO和Python函数的知识。使用Jupyter Notebook来试试看吧。 文件基础操作 我们有一个文本文件simple_file.txt,里面包含了以下内容。 1 2 3 4 1 2 five 5 7 one 6 9 three 9 8 four 文件的每一行中包含三个值,前两个是数字,第三个是表示数字的英文字符串,比如说”one”。我们需要做的是将第三个值转换为数字,并且将整个文件的结果写入到output_file.txt里,我们只拿1~5作为例子。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # Open simple_file.txt for reading # Open output_file.txt for writing with open("simple_file.txt","r") as input_handle, open("output_file.txt","w") as output_handle: # Perform some data processing for line in input_handle: line = line.strip("\n") line_number = line.split(" ") if line_number[2] == "one": line_number[2] = "1" elif line_number[2] == "two": line_number[2] = "2" elif line_number[2] == "three": line_number[2] = "3" elif line_number[2] == "four": line_number[2] = "4" elif line_number[2] == "five": line_number[2] = "5" new_line = line_number[0] + " " + line_number[1] + " " + line_number[2] + "\n" output_handle.write(new_line) # Both files will be closed after finishing the with block 学生信息系统 这里有两个文件,一个是student_data.txt,里面包含着学生的ID,名字和课程。如下所示。 1 2 3 4 5 1,tom,clayton 2,alex,caulfield 3,sarah,clayton 4,philip,clayton 5,david,caulfield 另一个文件是enrollment.txt,包含着学生选课的记录,每一行分别是学生ID和课程名称。 1 2 3 4 5 6 7 8 9 10 1 mathematics 1 english 2 programming 3 mathematics 3 physics 4 mathematics 4 chemistry 4 literature 5 english 5 history 我们的任务是建立一个基础的查询系统,这个系统通过输入学生的名字,先判断学生在不在这个系统中,如果在,再输出学生选的课程列表。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def query(student_name): # Open both files for reading unit_list = [] with open("student_data.txt","r") as student_file, open("enrollment.txt","r") as enrollment_file: # Perform some data processing for student_line in student_file: student_line = student_line.strip("\n") student_list = student_line.split(",") if student_name in student_list: student_no = student_list[0] for enrollment_line in enrollment_file: enrollment_list = enrollment_line.split(" ") if student_no in enrollment_list: unit_list.append(enrollment_list[1].strip("\n")) if unit_list == []: print("Cannot find the student") return unit_list name = input("enter the student name. ") print(query(name)) 括号匹配检查 在求解一个数学表达式的时候,括号代表着计算的更高优先级。比如说: $$(5+3)+((6-9)/(5+7))$$ 其中$(6-9)$和$(5+7)$会在除法运算之前计算。 为了使这个能正常工作,我们需要检查括号是否匹配。匹配的括号意思是,对于每一个左括号都有一个对应的右括号,而且括号也需要正确嵌套。例如,以下是正确的括号字符串: ()()()()() (()()) ((())) 而以下的字符串是错误的: ((() ()()()(() ((()))( 区分正确的括号匹配是编程语言中的重要部分。编写一个程序,从左到右读取一串括号,并检查括号是否平衡。提示:可以使用一个叫做栈(Stack)的数据结构。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def check_for_balanced_parenthesis(string_of_parenthesis): stack = [] for char in string_of_parenthesis: if char == '(': stack.append(char) elif char == ')': if len(stack) == 0: return False else: stack.pop() if len(stack) == 0: return True else: return False check_for_balanced_parenthesis(input("Please enter a string to check parenthesis balance.")) 像这样将一段逻辑包装在代码中,可以方便以后在其他地方进行调用,提高代码的可读性和复用性。 参考文献 [1] B. Eckel, “sebsauvage.net - Python”, Sebsauvage.net, 2021. [Online]. Available: http://sebsauvage.net/python/. [2] A. Bell, "Standard 1 - Objective 1: Demonstrate understanding of computer hardware, peripherals and troubleshooting.", slideplayer, 2021. [Online]. Available: https://slideplayer.com/slide/5809212/. [3] "Python3 File 方法 | 菜鸟教程", Runoob.com, 2021. [Online]. Available: https://www.runoob.com/python3/python3-file-methods.html. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/7/19
articleCard.readMore

解锁网易云变灰曲目PC版(Windows, MacOS)

作为网易云的9级VIP用户,由于国内音乐版权的问题,用了那么久还订阅会员的网易云看到了很多音乐因版权而下架,于是折腾了一下,使用GitHub上现成的实现给网易云换源,从而解决音乐下架的问题。在这篇文章里,将会分享一下怎么在网易云PC上使用这项技术。 最早并且最出名的实现是GitHub上的nondanee/UnblockNeteaseMusic[1]。然而这名作者很少再继续维护这个项目,现在的替换效果不是很好,很多变灰的歌曲依然无法播放。于是,找到了另一个作者的Colin-XKL/UnblockNeteaseMusic[2]。这个项目在今天依然可用,所以将会介绍怎么部署服务端并且使用。现在建议使用最新的UnblockNeteaseMusic/server[3]。 整个程序的架构是基于http代理的,所以需要部署一个代理服务器(可以是本机),然后在客户端上使用代理进行访问。 服务端部署 这个项目的服务端是基于node.js的,所以服务端是不限平台(Windows, MacOS或Linux)[4]。使用一台电脑或者服务器作为服务端,只要在需要使用网易云的时候能确保这台机器能运行即可。 安装服务端环境 第一步是安装这个项目所需的node.js和git,已安装的可以跳过。Linux和MacOS可以通过包管理器如apt或者brew来安装,windows请自行去谷歌寻找相应下载。 部署服务 首先使用git下载这个项目。 1 2 # git clone https://github.com/Colin-XKL/UnblockNeteaseMusic.git git clone https://github.com/UnblockNeteaseMusic/server.git 下载完成之后进入这个文件夹,并且使用yarn安装nodejs的依赖,并且编译这个项目。 1 2 3 cd UnblockNeteaseMusic yarn yarn build 运行服务端,其中的端口可以替换为自己想要的任意端口。 1 node app.js -p 7890:7891 当命令行中提示以下文本时,说明成功启动了。(注意这两个端口跟随自己上面的设置的。) 1 2 HTTP Server running @ http://0.0.0.0:7890 HTTPS Server running @ http://0.0.0.0:7891 当然,请使用screen,docker或者加载成系统服务之类的确保后台持续运行,这方面不再赘述。 证书签名 如果需要使用MacOS的网易云,需要自签证书来使用http代理,如果仅供Windows使用可以跳过此节。这里摘录了GitHub上的其中一个issue[5]。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 生成 CA 私钥 openssl genrsa -out ca.key 2048 # 生成 CA 证书 ("YOURNAME" 处填上你自己的名字) openssl req -x509 -new -nodes -key ca.key -sha256 -days 1825 -out ca.crt -subj "/C=CN/CN=UnblockNeteaseMusic Root CA/O=YOURNAME" # 生成服务器私钥 openssl genrsa -out server.key 2048 # 生成证书签发请求 openssl req -new -sha256 -key server.key -out server.csr -subj "/C=CN/L=Hangzhou/O=NetEase (Hangzhou) Network Co., Ltd/OU=IT Dept./CN=*.music.163.com" # 使用 CA 签发服务器证书 openssl x509 -req -extfile <(printf "extendedKeyUsage=serverAuth\nsubjectAltName=DNS:music.163.com,DNS:*.music.163.com") -sha256 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt 准备好上面生成的ca.crt这个文件,等下需要用于MacOS的证书注册。 客户端配置 首先先来看一下没有解锁变灰曲目之前的样子。 Fig. 1. 解锁前的网易云 居然有那么多变灰了,这怎么能忍! Windows Windows的网易云音乐内置了代理功能,非常的方便。 Fig. 2. Windows的网易云设置 这里选择HTTP代理,并且输入服务器IP(本机则为127.0.0.1),和刚才输入的第一个端口(对于上面的例子是7890)。然后重启网易云音乐,发现全部OK。 MacOS MacOS的网易云音乐因为没有自带代理功能,所以相对来说比较麻烦。而且http代理也需要先注册证书。 先注册证书,双击之前在服务端准备好的ca.crt文件。然后在弹出的证书管理窗口中找到UnblockNeteaseMusic Root CA。 Fig. 3. 证书注册第一步 然后,双击这个证书,在”如何信任这个证书”这里选择”始终信任”即可,退出并保存。 Fig. 4. 证书注册第二步 出来之后,在证书管理界面,点击这个证书,如果没有看到任何红字警告,则说明修改成功了。 证书签名之后,接下来是设置代理。因为网易云没有自带代理功能,这里建议使用Proxifier来完成,并且参考了GitHub中的另一个issue[6]。 在本文中,我们使用Proxifier v2.29来进行演示。 Fig. 5. Proxifier第一步 根据上图的箭头提示,进入代理服务器添加界面,并且输入对应的服务器地址(本机则为127.0.0.1)和端口(这里的例子中是7890),选择HTTP代理,并确认。 Fig. 6. Proxifier第二步 根据上图提示,进入规则编辑界面,输入一个便于辨识的规则名。在应用程序处添加NeteaseMusic。在动作处选择刚才添加的代理方式,在这个例子里是Proxy HTTPS 192.168.0.146:7890。如果是本机的话,这个IP应该是127.0.0.1加一个端口。记得确认在规则界面,这条刚刚加的规则要打勾选上。 Fig. 7. Proxifier结果 回到Proxifier主界面,启动网易云,这时候如果看到日志刷出来一大片,并且上面有网易云的名字,就说明网易云正在使用这个Proxifier代理,成功了。 最终效果 当折腾完上面说的步骤之后,再打开网易云看看。 Fig. 8. 解锁后的网易云 太棒了,终于可以听了! 参考文献 [1] "nondanee/UnblockNeteaseMusic", GitHub, 2021. [Online]. Available: https://github.com/nondanee/UnblockNeteaseMusic. [2] "Colin-XKL/UnblockNeteaseMusic", GitHub, 2021. [Online]. Available: https://github.com/Colin-XKL/UnblockNeteaseMusic. [3] "UnblockNeteaseMusic/server", GitHub, 2021. [Online]. Available: https://github.com/UnblockNeteaseMusic/server. [4] "Node.js", Node.js, 2021. [Online]. Available: https://nodejs.org/en/. [5] "进阶配置 · Issue #48 · nondanee/UnblockNeteaseMusic", GitHub, 2021. [Online]. Available: https://github.com/nondanee/UnblockNeteaseMusic/issues/48. [6] "食用指南 · Issue #22 · nondanee/UnblockNeteaseMusic", GitHub, 2021. [Online]. Available: https://github.com/nondanee/UnblockNeteaseMusic/issues/22. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/6/30
articleCard.readMore

Python编程基础04:Python高级集合类型和一些杂项

人生苦短,我用Python![1] 这个系列是一个帮助零基础的人入门编程的教程,本文承接上一篇,介绍Python的另外两个重要的数据类型(字典dict和集合set)。另外,break, continue, 注释和IO也会在本文的下半部分介绍。 上一篇介绍了集合数据类型中的字符串、列表和元组,在这篇我们将补齐剩下的两个(字典和集合)。 Python的集合数据类型 集合 集合(set)是一个无序并且包含不重复元素的数据类型。 创建一个集合: 空集合: a_set = set() 带有元素的集合: a_set = {"one", 2} 列表转换为集合: a_set = set([1,2,2,3]) 结果为 {1,2,3} 由于集合是无序排列的,所以集合不能通过下标读写。 添加元素: a_set.add("c") 删除元素: a_set.remove(item) 接受一个参数,从这个集合中删除它,如果没有这个元素会抛出KeyError异常 a_set.discard(item) 和a_set.remove一样删除元素,但是不会抛出异常 a_set.pop() 随意返回一个元素并从集合中删除 a_set.clear() 删除全部元素 如上图所示,我们知道数学中也有集合这个东西,并且有一系列数学运算。Python也是支持这些运算的。 集合的数学操作: 并集(Union) a_set.union(b_set) a_set | b_set 交集(Intersection) a_set.intersection(b_set) a_set & b_set 差集(Difference) a_set.difference(b_set) a_set - b_set 对称差(Symmetric difference) a_set.symmetric_difference(b_set) a_set ^ b_set 一些集合操作的例子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 first_set = set() print(len(first_set)) # 0 first_set.add("a") first_set.add("b") first_set.add("b") print(first_set) # {"a", "b"} char_list = ["b", "c", "c", "d", "d", "e"] second_set = set(char_list) print(char_list) # {"e", "d", "c", "b"} The set is unordered. intersection = first_set * second_set print(intersection) # {"b"} union = first_set | second_set print(union) # {"e", "d", "c", "a", "b"} 集合和列表的不同 顺序 列表是有序的,集合是无序的 重复 列表允许重复元素,集合中没有重复元素 in语句中 集合会比列表的速度快得多 更多的集合方法可以参考Python官方文档[2] 字典 字典(dict)是一种数据结构将key(键)映射为value(值)。其中key必须是不可变类型,value可以是任何类型。每一个元素可以表示为key: value。 创建一个字典: 空字典: a_dict = {} 带有元素的字典: a_dict = {"one": 1, "two": 2} 从键值对元组列表中创建: a_dict = dict([("a", 1), ("b", 1)]) 添加元素: a_dict[new_key] = new_value 如果new_key已经存在于这个字典中了,则会用new_value覆盖原先的value。 删除元素: del a_dict[a_key] 检查一个key是否在字典中: a_key in a_dict 或者 a_key not in a_dict 一些字典操作的例子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 simple_dict = {} print(len(simple_dict)) # 0 simple_dict = {"a": 0, "b": 0, "c": 0} print(simple_dict["b"]) # 0 simple_dict["b"] = 1 print(simple_dict["b"]) # 1 simple_dict["d"] = 2 print(simple_dict) # {"a": 0, "b": 1, "c": 0, "d": 2} item_list = list(simple_dict.items()) print(item_list[1]) # ("b", 1) keys_list = list(simple_dict.keys()) print(key_list[3]) # "d" del simple_dict["d"] print(simple_dict) # {"a":0, "b":1, "c":0} 通过for循环遍历整个字典 1 2 3 simple_dict = {"a": 0, "b": 1, "c": 2} for key, value in simple_dict.items(): print(key, value) 更多的字典方法可以参考Python官方文档[3] 循环控制 Continue Python中的continue关键字用于跳过循环中的这一轮,并且开始下一轮循环。 从图中可以看到经过了continue语句,代码会直接进入下轮循环。 举一个使用continue的例子。有一个字符串和一个字符,想要从字符串中删除全部这个字符。 1 2 3 4 5 6 7 8 a_str = "helloWorld" char_to_remove = "e" new_str = "" for char in a_str: if char == char_to_remove: continue new_str += char print(new_str) Break Python中的break关键字将会直接跳出这个循环。 举一个使用break的例子,比如我们想要在一个列表中找到一个元素。当然这个例子可以用in表达式,但是这次用for循环和break来试试。 1 2 3 4 5 6 number_list = [3, 11, 9, 7, 6, 5, 100, 20, 9, 6, 3, 1, 0] target = 9 for number in number_list: if number == target: print("The target number is in the list") break 当使用break和continue的时候,请多注意缩进。通过缩进,我们可以清楚的找到我们想要跳出的是哪个循环。 1 2 3 4 5 6 7 a_list = [1, 2, 3] b_list = [2, 5, 6] for itemA in a_list: for itemB in b_list: if itemA == itemB: break print(itemA, itemB) 注释 无论是使用什么编程语言写什么东西,注释(comment)都是极为重要的。它既可以提升代码的可读性,也可以解释此处代码的功能和含义。如果没有注释,将会极大的打击阅读别人代码的热情,同时在自己想要回顾自己的代码的时候忘了在写什么。 Python中的注释: 以#作为开头 注释的部分将不会被解释运行 1 2 3 4 5 6 a = 1 # first number b = 2 # second number result = a + b # print the result print("The addition of a and b is", result) 行内注释: 在代码的同一行写上注释 r = 1 # radius of the circle 单行注释 一整行都是注释 # some comment 块注释 多行注释,使用三引号""" 一般多用于代码的开头介绍,或者函数和类的介绍 1 2 3 4 5 6 """ Program description: This code is for ... Author: ... First created: ... Last modified: ... """ Python官方PEP8[4]和Google代码风格[5]都有对Python注释的写法提供了风格指南。 请注意,注释是为了强调和理解,不是直接进行冗长和模糊的翻译。 开发者最讨厌的两个事情: 讨厌在自己的代码中写注释 讨厌别人的代码中没有注释 标准输入输出 输入(Input)和输出(Output)是程序中的两个重要部分。 输入是需要用于解决某个特定计算任务的数据。 输出是用于展示计算结果。 1 2 3 4 a = 1 b = 2 result = a + b print("The addition of a and b is", result) 标准输入 1 2 3 4 a = int(input("Enter the first number: ")) b = int(input("Enter the second number: ")) result = a + b print("The addition of a and b is", result) input用于从键盘接受输入的数据。 input("prompt statement:") 或者 input() input是一个Python的内置函数,它的返回值是str。如果想要转换为int可以使用int()函数。 标准输出 标准输出是用于在控制台或者终端中显示一些信息,比如说计算结果。 print函数: print("output string") 默认情况下是用"\n"换行符结尾,所以每一个print语句会显示为一行。 如果想要用print函数同时显示多个参数,有两种办法, 在print中使用两个参数 print("The addition of a and b is", result) 将两个参数重新拼接为一个字符串 print("The addition of a and b is " + str(result)) 注意,这里的+是用于拼接字符串,是Python内置的功能,加号两侧都需要是字符串类型。 实践试试 在上一章中,我们使用了字符串和列表给俳句做字符统计。这次我们学习了字典和集合之类的更加高级的数据类型,就可以对上一章节的代码做改进。 先来回顾一下上一章我们是怎么写的, 1 2 3 4 5 6 7 8 9 10 11 list_of_strings = ["This blog teaches code", "Code that will be useful soon", "Let me try this out"] haiku = list_of_strings[0] + '\n' + list_of_strings[1] + '\n' + list_of_strings[2] items = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'] count = [0] * 26 for character in haiku: if character.lower() in items: count[items.index(character.lower())] += 1 在上一章节中,熟悉了for循环的使用,我们通过它遍历每一个字符来进行统计。以后循环结构将会非常常用。 把列表升级到字典 很多人可能已经意识到了,对每个字符进行计数的这个需求非常适合字典。所以我们需要把上一章实现的列表方案升级到字典。我们可以使用zip()函数对把两个列表打包成一个二元元组的列表,就可以轻松的转换为字典了。来试试看吧。 1 2 3 4 5 6 7 8 9 10 # This will need to be overwritten with a new dictionary after "zipped_haiku" is defined dictionary = {} # This is where you zip the two lists together zipped_haiku = zip(items, count) dictionary = dict(list(zipped_haiku)) # This should give the count of 2 for the character 'a' print(dictionary['a']) 这样就可以很容易地更新每个字符的计数,而不必使用search来找到两个列表的索引。 1 2 3 4 5 6 7 8 9 10 11 12 13 items = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'] count = [0] * 26 quote = "Life is short You need Python" for character in quote: if character.lower() in items: count[items.index(character.lower())] += 1 zipped_tuple = zip(items, count) new_dictionary = dict(list(zipped_tuple)) print(new_dictionary) 分析这些文本 建立了统计字符计数的字典之后,我们现在就可以分析这些文本了。两个集合set可以从刚才的字典创建出来。我们需要使用两个循环去把字典中出现频率大于1的字符添加到集合中。 1 2 3 4 5 6 7 8 9 10 11 haiku_set = set() quote_set = set() for character in items: # From the dictionary for haiku if dictionary[character] > 0: haiku_set.add(character) # From the dictionary for your selected quote/passage if new_dictionary[character] > 0: quote_set.add(character) 使用这两个集合,运行下面的代码,它将执行一些测试,以找到两个文本之间的比较。完成之后,尝试使用其他两个文本,看看是否有任何差异,甚至添加更多的测试。如果在添加字符时设置一个阈值(比如出现超过10次的字符,或者恰好出现5次的字符,等等),那么可能会看到更加有趣的结果。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 set_1 = haiku_set set_2 = quote_set # Check if set 1 is a subset of set 2 if set_1 <= set_2: # Check if set 1 is a pure subset of set 2 if set_1 < set_2: print("All characters in Set 1 are in Set 2, but not every character in Set 2 is in Set 1.") print("The extra characters in Set 2 are:") print(set_2.difference(set_1)) # If not a pure subset, then set 1 is a normal subset else: print("All characters in Set 1 are in Set 2.") # Set 1 is not a subset of set 2 else: print("Not all characters in Set 1 are in Set 2.") print("Characters in Set 1 that are not in Set 2 are:") print(set_1.difference(set_2)) # Same as above but doing the reversed if set_1 >= set_2: if set_1 > set_2: print("All characters in Set 2 are in Set 1, but not every character in Set 1 is in Set 2.") print("The extra characters in Set 1 are:") print(set_1 - set_2) else: print("All characters in Set 2 are in Set 1.") else: print("Not all characters in Set 2 are in Set 1.") print("Characters in Set 2 that are not in Set 1 are:") print(set_2 - set_1) 这是一个让我们开始考虑这些数据类型的可能性的简单例子。这些例子中没有使用的最后一种数据类型是元组tuple。可以想想元组的一些性质,以及如何将其应用到实际的例子中。 参考文献 [1] B. Eckel, “sebsauvage.net - Python”, Sebsauvage.net, 2021. [Online]. Available: http://sebsauvage.net/python/. [2] “Built-in Types — Python 3.9.1 documentation”, Docs.python.org, 2021. [Online]. Available: https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset. [3] “Built-in Types — Python 3.9.1 documentation”, Docs.python.org, 2021. [Online]. Available: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict. [4] "PEP 8 -- Style Guide for Python Code", Python.org, 2021. [Online]. Available: https://www.python.org/dev/peps/pep-0008/#comments. [5] "styleguide", styleguide, 2021. [Online]. Available: https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/6/19
articleCard.readMore

Aria2傻瓜安装部署指南

Aria2是一个非常好用的P2P开源下载工具,不仅支持普通的HTTP链接下载,也可以使用BT种子,磁力链接。在体验过迅雷这样的国产流氓软件之后,有一款实用的下载工具还是很重要的。在这篇文章里,将介绍如何在Linux中安装并且部署运行Aria2和它的可视化界面AriaNg。在家庭局域网的路由器和NAS中,很有可能是基于Linux系统的,所以可以很方便的将Aria2服务部署起来,并且从其他网络位置进行访问。 对于Linux用户来说,这里推荐一个很棒的开源项目(P3TERX/aria2.sh),是一个Aria2自动安装和配置的脚本[1]。根据项目页面上的描述,这个脚本可以自动的在shell环境(Linux)中一键安装部署,并且自带了所谓”完美配置”。这些完美配置是来自于这位作者的另一个repo(P3TERX/aria2.conf)[2]包括, BT 下载率高、速度快 重启后不丢失任务进度、不重复下载 删除正在下载的任务自动删除未完成的文件 下载错误自动删除未完成的文件 下载完成自动删除控制文件(.aria2后缀名文件) 下载完成自动删除种子文件(.torrent后缀名文件) 下载完成自动删除空目录 BT 下载完成自动清除垃圾文件(文件类型过滤功能) BT 下载完成自动清除小文件(文件大小过滤功能) 有一定的防版权投诉、防迅雷吸血效果 更好的 PT 下载支持 看起来非常适合小白,那就赶紧开始安装吧。 安装Aria2 下载脚本可以通过以下命令直接从github中下载到home文件夹,或者进入这个开源项目(P3TERX/aria2.sh)手动下载其中的aria.sh文件。 1 2 apt install wget curl ca-certificates wget https://raw.githubusercontent.com/P3TERX/aria2.sh/master/aria2.sh 然后在当前文件夹下会有aria2.sh文件,先为这个文件添加可以运行的权限。 1 chmod u+x aria2.sh 再在sudo权限下运行这个脚本。 1 sudo ./aria2.sh 然后再根据提示输入1安装Aria2即可。 配置Aria2 因为这个安装脚本依然提供了非常方便的配置选项,我们可以启动脚本,并且输入7来修改配置。 其中主要需要修改的是”RPC密钥”,不然的话所有人都可以通过这个端口访问aria2服务,并不是很安全。这个密钥就相当于是访问这个服务的密码。 此外,”下载地址”也请自行设定。 安装AriaNg AriaNg是Aria2的一个前端图形界面,提供给用户更加方便的操作体验[3],不然的话一直用命令行来操作实在是太麻烦了。 首先进入这个GitHub的项目地址(mayswind/AriaNg)中的Release下载最新的AriaNg版本,这应该是一个zip文件。然后在电脑中解压。 对于在本地Aria2,并且需要本地访问的用户,直接打开html文件即可,并不需要做其他的事情。 而如果打算使用本地的AriaNg前端访问远程Aria2服务器,也是可以直接打开html文件,并且在下一步中配置远程Aria2服务器。 对于需要开放端口并提供远程界面的,可以通过Python建立一个基础的网页服务器。命令如下, 安装Python3,并且进入AriaNg文件夹, 1 2 sudo apt install python3 cd AriaNg-1.2.1 新建一个服务用于网页服务器。 首先需要输入以下指令,找到AriaNg文件夹的绝对路径。 1 pwd 然后复制这个路径。 再需要新建一个文本文件,命名为AriaNg.service。 1 2 3 4 5 6 7 8 9 10 11 [Unit] Description=AriaNg After=multi-user.target [Service] WorkingDirectory=刚才复制的当前绝对路径 User=root Type=idle ExecStart=/usr/bin/python3 -m http.server 6880 Restart=always [Install] WantedBy=multi-user.target 复制到系统服务目录下, 1 cp AriaNg.service /etc/systemd/system/AriaNg.service 然后启动网页服务器系统服务, 1 sudo systemctl start AriaNg 设置为开机启动, 1 sudo systemctl enable AriaNg 只要再在路由器上处理一下端口映射和内网穿透的问题,就可以正常被外网访问了。如果在局域网内则没那么麻烦,一般可以直接访问局域网IP地址:6880 配置AriaNg 在AriaNg中的侧边栏,我们可以看到现在依然没有连接上Aria2服务器,这是因为前端中还没有配置密码。 打开”AriaNg设置”,点击标签中的”RPC(…)”,我们可以在这里设置Aria2服务器的地址。我们有以下可能 如果Aria2服务器和AriaNg网页在同一台电脑上,需要在”PRC地址”中保持默认,在”PRC密钥”中输入之前设置的密码。 如果Aria2服务器和AriaNg网页不在同一台电脑上,则需要在”PRC地址”中输入远程Aria2服务器的ip地址,并且在”PRC密钥”中输入之前设置的密码。 如果一切顺利,则会显示已连接,就可以轻松使用Aria2下载了。 参考文献 [1] "P3TERX/aria2.sh", GitHub, 2021. [Online]. Available: https://github.com/P3TERX/aria2.sh. [2] "P3TERX/aria2.conf", GitHub, 2021. [Online]. Available: https://github.com/P3TERX/aria2.conf. [3] "mayswind/AriaNg", GitHub, 2021. [Online]. Available: https://github.com/mayswind/AriaNg. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/6/9
articleCard.readMore

Python编程基础03:数据结构和Python集合类型

人生苦短,我用Python![1] 这个系列是一个帮助零基础的人入门编程的教程,本文承接上一篇,介绍Python的数据结构和集合类型。 数据类型和数据结构 Python中的数据类型可以分为两种, 原子类型(Atomic) 集合类型(Collective) 原子类型是不可分的,只表示一个值,比如说int,float和bool。 集合类型是多个数据值的集合,比如说str,list,tuple,set和dict,这些类型将在本文中介绍。 数据结构 数据结构(Data Structure)定义了数据是如何在内存中物理存储和组织的,也指明了某个集合中的单个数据值是如何访问和修改的。 数据类型和数据结构的区别: 数据结构是计算机科学理论中的一般术语。 数据类型是某个特定的编程语言中的数据结构的实现。 数据结构举例: 原始(Primitive)数据结构(布尔Boolean, 浮点Floating-point, 整数Integer) 非原始(Non-primitive)数据结构(数组Array, 列表List) 线性结构(栈Stack, 队列Queue) 非线性结构(图Graph, 树Tree, 哈希表Hashmap) Python的集合数据类型 在Python中有非原始数据结构的实现, 字符串str a = "Hello" 列表list a = [1, 3, 5] 元组tuple a = (6, 2) 集合set a = {1, 5, 3} 字典dictionary a = {"a": "b", 1: 2} 内存(Memory)是连续数据存储块的集合。Python代码运行时的数据会存储在内存中。 在内存中存的信息一般是以下两者, 一个Python对象(和它的值) 指向另一个内存地址的引用 在Python中常见的str,list和tuple都是基于数组的结构。这些集合中的成员(item)是顺序的存储在一个连续的内存块上。所以在这些集合类型中,一般使用下标(index)对某个成员进行访问。 字符串 字符串(String)在Python中经常用str表示,是一个文本表示的数据类型,一个或多个字符的集合。 例: a_str = "Python" 在Python中通过index访问成员是使用中括号”a_str[index]”,其中index是从0开始。例: 第一个字符: a_str[0] 第二个字符: a_str[1] 最后一个字符: a_str[len(a_str) - 1] 或者 a_str[-1] 字符串可以使用”+”进行拼接操作。 1 2 3 4 first_name = "John" last_name = "Smith" full_name = first_name + " " + last_name print(full_name) 得到的结果是 1 John Smith 字符串也可以切片取一部分,通过a_str[start_index:end_index]获取从start_index(包含)到end_index(不包含)的子字符串。 如果start_index是0的话,可以省略;如果end_index是最后一位的话也可以省略。 1 2 3 message = "Welcome to Python" sub_message = message[0:7] # or message[:7] print(sub_message) 结果是 1 Welcome 字符串的更多方法 1 2 3 4 5 6 7 8 9 10 message = " Welcome to Python " message.strip() # "Welcome to Python" message = "Welcome to Python" message.split() # ["Welcome", "to", "Python"] message.replace("o", "0") # "Welc0me t0 Pyth0n" message.isalpha() # False message.isdigit() # False 一般来说比较常用的有 str.capitalize() 像标题一样每个单词大写第一个字符 str.count() 返回这个子字符串在这个字符串中的出现次数 str.endswith() 返回这个字符串是否是有这个后缀 str.find() 查找子字符串的位置 str.index() 返回所给的子字符串的index str.isdigit() 这个字符串是否全是数字 str.join() 将list的全部元素都合并成一个字符串 str.lower() 转换成小写 str.replace() 替换其中的某个子字符串 str.split() 通过某个分隔符分割成列表 str.strip() 去除首尾的空格 更多的字符串方法请参考Python3官方文档[2] 序列 Python中的序列(Sequence)是一个数据的集合。这些数据中的元素都可以读取,而有些序列还可以修改其中的元素。 列表(list), 元组(tuple), 集合(set), 字典(dict) 这些序列类型中的通用功能 in表达式: 检查这个元素是不是在这个序列中 拼接 合并两个序列,一般用”+”运算符 通过下标取值c 通过一个给定的下标,取其中的一个值,在python中用中括号[]来操作 切片 通过两个下标,开始的位置和结束的位置,取一个子序列 一些基础分析 min, max, seq.index, seq.count等等 接下来举几个例子来看看。 in表达式 1 2 3 4 if x in seq: print("x exists") if x not in seq: print("x doesn't exist") 拼接 1 new_seq = seq_one + seq_two 通过下标取值 1 2 a_seq[index] # read a_seq[index] = new_value # write 切片 1 2 a_seq[start_index:end_index] a_seq[start_index:end_index:step] 以下我们来专门看看这些具体的序列类型。 列表 列表(list)是Python中非常常用的一个类型。 可以保存多个任意类型的数据 可变的(Mutable),而且是有顺序的 创建列表的举例 创建空列表: a_list = [], a_list = list() 创建一个带有元素的列表: a_list = [1, "two", 3.0, '4'] 创建一个带有相同元素的列表: a_list = [1] * 6 列表中的下标是从0开始的。 1 fruits = ["Apple", "Mango", "Strawberry", "Banana", "Guava"] index[0][1][2][3][4] value“Apple”“Mango”“Strawberry”“Banana”“Guava” 给列表添加元素: 添加到末端: a_list.append(new_item) 添加到指定位置: a_list.insert(index, new_item) 移除元素: 移除末尾或者指定位置,并返回这个元素: a_list.pop()和a_list.pop(index) 移除指定值的元素: a_list.remove(item) 排列元素: 按照值的顺序进行排列,默认升序: a_list.sort() 直接将元素倒序: a_list.reverse() 一些操作列表的例子: 1 2 3 4 5 6 7 8 9 num_list = [3, 4, 2, 6] num_list.append(2) # [3, 4, 2, 6, 2] num_list.insert(2, 5) # [3, 4, 5, 2, 6, 2] num_list.pop() # return 2; num_list is [3, 4, 5, 2, 6] num_list.pop(2) # return 5; num_list is [3, 4, 2, 6] num_list.sort() # [2, 3, 4, 6] num_list.reverse() # [6, 4, 3, 2] 用for循环搭配range进行遍历 1 2 3 4 5 num_list = [1, 2, 3, 4, 5] product = 1 for i in range(len(num_list)): product *= num_list[i] print(product) 列表推导式(list comprehension)是一个用于创建新列表的具有python特色的方法,新列表的元素都是通过某种方法从已有列表中生成。 举个例子,如果我们希望把一个列表中的奇数收集起来,做一个平方添加到新列表里。 1 2 3 num_list = [1, 2, 3, 4, 5] new_list = [each ** 2 for each in num_list if each & 2 != 0] print(new_list) 等价于 1 2 3 4 5 6 num_list = [1, 2, 3, 4, 5] new_list = [] for each in num_list: if each % 2 != 0: new_list.append(each ** 2) print(new_list) 元组 元组(tuple)是python中用于表示打包一块的多类型集合的类型。 创建元组的举例: 空元组: a_tuple = () 有一些值的元组: a_tuple = (0, "a") 列表转换到元组: a_tuple = tuple([0, "a"]) 读取元组中的元素: 使用下标: a_tuple[0] 解构赋值给新变量: x, y = a_tuple 元组是不可变的,不能对其中一个元素重新赋值。 1 2 3 4 5 6 7 8 coord = (0, 1) coord[0] # 0 x, y = coord # x = 0; y = 1 coord[0] = 2 # TypeError coord_list = [(0, 0), (0, 1)] # nested list of tuples coord_tuple = tuple(coord_list) # nested tuples 列表和元组主要区别: 列表主要代表一个有顺序的序列,而元组是表示一个结构 列表是可变的,元组是不可变的 元组比列表更节省内存 实践试试 这一节中会试试如何使用字符串和列表去给一个句子做字符统计,试试看一步一步的做下来吧。这次使用的环境和第一篇教程相同,具体内容请看Python编程基础01:Python语言和编程。 从字符串开始 这开始编程之前,可以先回忆一下字符串和列表的性质。先来给一个俳句的每一个字符串都打印出来。 1 2 3 4 list_of_strings = ["This blog teaches code", "Code that will be useful soon", "Let me try this out"] for line in list_of_strings: print(line) 我们也可以把多个字符串连接到一个列表中,但是依然每一句占一行。这里我们需要用\n换行符来连接字符串。 1 2 3 4 5 6 7 # Define an empty string "haiku" haiku = "" # Concat the strings with "\n" haiku = list_of_strings[0]+ "\n" + list_of_strings[1] + "\n"+ list_of_strings[2] print(haiku) 当然我们也可以轻松把这一个长字符串重新还原成列表。 1 print(haiku.split("\n")) 开始使用列表 从这里开始,我们需要给上一部分定义的俳句的所有可能字符构造一个列表。我们可以用以下方式使用字符串。 1 2 3 4 5 6 7 8 9 10 # Define a string of all the characters in the English alphabet alphabet = "abcdefghijklmnopqrstuvwxyz" # Define a list for each character in the English alphabet items = [] # Append all characters into the list for letter in alphabet: items.append(letter) print(items) 以上只是创建这个列表的其中一个办法,有很多种办法都可以创建字母表。 接下来让我们创建26个0来作为字符计数列表的初始化。 1 2 # Define a list for the count of each character in the English alphabet count = [0 for i in range(26)] 然后就开始遍历每一个字符,把计数统计上去吧。以下的代码只是一种解决方案,编程是一种艺术,就像不同的画家有不同的画风一样,可以试试看写出自己的风格。 不过请注意,以上定义的字母表是纯小写的,所以在遍历匹配的时候需要转换成小写进行匹配。 1 2 3 4 5 6 7 8 9 10 # iterate each character of haiku for character in haiku: # filter the characters which is not " " and "\n" if character not in (" ", "\n"): # accumulate the result by adding 1 count[items.index(character.lower())] += 1 # print the result for i in range(len(items)): print(items[i] + ":" + str(count[i])) 结果是类似于这样 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 a:2 b:1 c:3 d:2 e:8 f:1 g:0 h:4 i:4 j:0 k:0 l:4 m:1 n:2 o:5 p:0 q:0 r:1 s:5 t:9 u:4 v:0 w:1 x:0 y:1 z:0 参考文献 [1] B. Eckel, “sebsauvage.net - Python”, Sebsauvage.net, 2021. [Online]. Available: http://sebsauvage.net/python/. [2] “Built-in Types — Python 3.9.1 documentation”, Docs.python.org, 2021. [Online]. Available: https://docs.python.org/3/library/stdtypes.html#string-method. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/5/19
articleCard.readMore

在UEFI Secure Boot下的Linux安装N卡驱动

最近在帮忙给一台单卡3090的工作站装Linux系统,结果踩了不少坑,折腾了一天多才成功装上。这篇文章就来分享一下,有哪些坑,然后自己是如何解决的。 当然其中最大的原因都是因为这台电脑是组织管理的,自己没有权限设置BIOS,并且强制启动Secure Boot,就算是有win10管理员账号也解决不了任何问题。 安装Linux系统 首先拿到手看看配置,是10900X和3090。有两块硬盘,一个500G左右的NVME SSD,一个2T的HDD。每个硬盘一个分区,一个受组织管理的Win10安装在SSD上。所以为了在SSD上安装Linux,先将SSD分成了两个分区,准备制作Ubuntu20.04的U盘启动盘。 Fig. 1. Ubuntu. Adapted from [13] 因为之前在家里台式机的win10上用过一个叫做Universal-USB-Installer-2.0.0.0.exe的软件挺好用,直接就复制到了自己Macbook的Win10虚拟机里,并且制作了Ubuntu启动盘。结果U盘插上启动的时候引导失败了,被Secure Boot阻止了,因为没有合格的签名,提示/casper/vmlinuz has invalid signature。后来向同学借用了win10电脑才解决问题。 所以使用虚拟机做U盘启动盘可能无法通过Secure Boot,看来虚拟机也并不是万能的。 不过最终也在Google和一些参考资料[1][2][3]的帮助下成功装上了Win10和Ubuntu双系统。 尝试安装GPU驱动 依然在很多搜索到的资料[4, 5]的帮助下,装上Ubuntu的时候第一件事就是安装N卡驱动。在N卡官网上,自动下载了.run后缀的文件。因为自己基本没怎么用过Linux,直接就双击打开了,安装速度极慢。放弃,进终端用sh运行.run文件才终于解决了。 Fig. 2. Nvidia driver download page. Adapted from [14] 然而安装的时候有很多选项并不是很能理解,虽然凭借着自己的直觉进行选择,但是不管试了几次,使用nvidia-smi依然看不到显卡,在Ubuntu的信息界面也只是显示了GPU是LLVM设备。这个时候就开始怀疑自己是不是安装的方法错误了。 这时候上网听说Linux Mint系统非常适合Linux小白[6],并且对各种第三方驱动都非常友好。Linux Mint的官网上可以选择三种GUI,Xfce, MATE, Cinnamon,根据官方的介绍[7],最终考虑到实用性和美观性选择了Cinnamon。在这个信息的驱使下,重新制作了Mint的启动盘,并且完全删除了Ubuntu安装了Mint。 Fig. 3. Linux Mint. Adapted from [15] 一进系统,就开始进入Driver Manager去检查能否直接使用推荐的N卡驱动,的确有,并且安装上了,但是依然没有看到显卡。 然后尝试按照之前同样的方法,手动安装N卡驱动。这时留意到了”UEFI Secure Boot”的字样,感觉这其中有点关系。网上一查[8][9][12],居然是Secure Boot的锅,而绝大多数人的解决方案都是关闭Secure Boot。 在Secure Boot下安装GPU驱动 还好找到了这几篇文章[10][11],上面详细的介绍了如何自己生成签名,并且添加至Linux MOK,让第三方驱动在UEFI Secure Boot启动的情况下依然可以工作。 主要的安装过程是这样的。 1.禁用图形界面,并且安装一些前置库 按Ctrl+Alt+F2进入终端。 1 2 3 sudo su service lightdm stop # stop X server apt-get install gcc kernel-devel # some dependencies 2. 安装驱动并签名 1 sudo sh "NVIDIA-xxx.run" # run the NVIDIA driver installer 在安装过程中根据自己的需要进行选择,不过需要在dkms安装的对话框中选择否。 在询问道是否需要签名时,选择生成密钥。程序将会生成一个私钥和公钥,保存在/usr/share/nvidia中,公钥是.key文件,私钥是.der。记录一下这两个文件的路径。这时候安装程序会提示是否删除私钥,选否。然后安装程序会提示运行失败,不过这个没有问题,等下一步将密钥添加到信任列表中就可以工作了。 3. 添加密钥到信任列表中 首先要将这个密钥添加到MOK,输入 1 sudo mokutil --import /usr/share/nvidia/xxx.der 然后输入一个密码两次。再直接重启电脑,这时候会进入Linux MOK Management界面,选择Enroll MOK, Continue boot再输入上一步设置的密码即可将密钥添加到信任列表中。 再启动系统输入nvidia-smi,发现显卡已经可以使用了。 Fig. 4. nvidia-smi screenshot. 安装Anaconda,一键装上PyTorch,测试能否使用CUDA。 Fig. 5. Checking pytorch cuda availability screenshot. 终于大功告成了。 参考文献 [1] R. Smith and P. Vakalopoulos, "How to install ubuntu in UEFI mode", Ask Ubuntu, 2021. [Online]. Available: https://askubuntu.com/questions/927924/how-to-install-ubuntu-in-uefi-mode. [2] ravery, "Installing Ubuntu on External Hard Drive - UEFI", Ask Ubuntu, 2021. [Online]. Available: https://askubuntu.com/questions/990790/installing-ubuntu-on-external-hard-drive-uefi. [3] "详解安装Ubuntu Linux系统时硬盘分区最合理的方法 - 云+社区 - 腾讯云", Cloud.tencent.com, 2021. [Online]. Available: https://cloud.tencent.com/developer/article/1711884. [4] "How to Install Nvidia Drivers on Ubuntu 20.04", Linuxize, 2021. [Online]. Available: https://linuxize.com/post/how-to-nvidia-drivers-on-ubuntu-20-04/. [5] L. Rendek, "How to uninstall the NVIDIA drivers on Ubuntu 20.04 Focal Fossa Linux", linuxconfig, 2021. [Online]. Available: https://linuxconfig.org/how-to-uninstall-the-nvidia-drivers-on-ubuntu-20-04-focal-fossa-linux. [6] "Ubuntu vs Mint:哪个更好?", 知乎专栏, 2021. [Online]. Available: https://zhuanlan.zhihu.com/p/52076038. [7] "选择正确的版本 — Linux Mint Installation Guide 文档", Linuxmint-installation-guide.readthedocs.io, 2021. [Online]. Available: https://linuxmint-installation-guide.readthedocs.io/zh_CN/latest/choose.html. [8] "NVIDIA driver is not loaded. Ubuntu 18.10", NVIDIA Developer Forums, 2021. [Online]. Available: https://forums.developer.nvidia.com/t/nvidia-driver-is-not-loaded-ubuntu-18-10/70495/4. [9] "Ubuntu16.04安装nvidia显卡安转与Secure Boot开启的矛盾_caobo_0512的博客-CSDN博客", Blog.csdn.net, 2021. [Online]. Available: https://blog.csdn.net/caobo_0512/article/details/106246195. [10] "Linux secure boot(安全启动)时添加Nvidia显卡驱动_天道酬勤-CSDN博客", Blog.csdn.net, 2021. [Online]. Available: https://blog.csdn.net/qq_38880380/article/details/78675202. [11] "安装Ubuntu系统的一个坑(安全启动)_荒陌的博客-CSDN博客_ubuntu关闭安全启动", Blog.csdn.net, 2021. [Online]. Available: https://blog.csdn.net/sinat_38640606/article/details/82794511?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-9.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-9.control. [12] "安装Ubuntu系统的一个坑(安全启动)_荒陌的博客-CSDN博客_ubuntu关闭安全启动", Blog.csdn.net, 2021. [Online]. Available: https://blog.csdn.net/sinat_38640606/article/details/82794511?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-9.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-9.control. [13] "🐧Installing Ubuntu - A Step by Step guide 🐧", DEV Community, 2021. [Online]. Available: https://dev.to/kaiwalyakoparkar/installing-ubuntu-a-step-by-step-guide-2b29. [14] "Download Drivers | NVIDIA", Nvidia.com, 2021. [Online]. Available: https://www.nvidia.com/Download/index.aspx. [15] "Linux Mint 20.1 “Ulyssa” Cinnamon overview | Sleek, modern, innovative.", Youtube.com, 2021. [Online]. Available: https://www.youtube.com/watch?v=Cs09YF_YlMI. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/5/13
articleCard.readMore

计算机视觉中的Transformer

深度学习中最一开始的Transformer是2017年推出的,非常强力[1]。可能当时作者觉得这个东西很强,所以才会赋予”变形金刚”的名字吧。而后来,Transformer也广泛的推广到了计算机视觉(CV)领域,从2020年开始,就有对Transformer在CV中的大量新研究发表。 本文主要会讲最初的Transformer,Vision Transformer(ViT)和Multi-scale Vision Transformer(MViT)。 最初的Transformer 解决并行问题 最初的Transformer是来源于这篇,”Attention is all you need”,用于自然语言处理(NLP)的机器翻译任务的。以前的RNN(包括LSTM[2], GRU[3])层计算并不能并行,因为一个序列中的某一个元素的计算是要基于别的元素的。如下图所示。 Fig. 1. RNN layer. Adapted from [4] 其中$a^1$到$a^4$都是一个序列中的token,RNN层可以看到一个序列中的全部信息,包括位置信息。但是这里每一个token的计算需要其他token的计算结果,所以无法做到并行化提高效率。 Fig. 2. Convolutional layer. Adapted from [4] 如上图所示, 使用卷积层[5]虽然可以并行计算,但是覆盖面积受到卷积核(kernel)的限制,无法在距离比较远的token中提取特征。 Fig. 3. Stacked convolutional layer. Adapted from [4] 如上图所示,很多人会通过将卷积层堆叠起来以达到提取更多特征的目的,但是这个覆盖范围其实依然并不是很宽,而且也需要更多的计算。 我们需要的是一个有长时记忆,并且可以并行处理的结构。所以这篇论文提出了Self-attention机制和Multi-Head Attention Layer。 Fig. 4. Calculation of $K^i$ and $Q^i$ in self-attention layer. Adapted from [4] 首先,我们有一个输入序列,从$x^1$到$x^4$。在Embedding之后,会将每一个token转换成1-D vector,$a^1$到$a^4$。使用3个线性层分别对应Q,K,V的权重,则可以把$z^i$转换成Q (Query),K (Key),V (Value)的向量。这个计算方式如下所示。 $$ \begin{split} q^i &= W^qa^i \\ k^i &= W^ka^i \\ v^i &= W^va^i \end{split} $$ 我们以第一个token作为例子,需要用$q^1$与所有token的$k$相乘,从而求得$\alpha_{1,1}$到$\alpha_{1,4}$。之后,通过一个softmax进行标准化使得它们的和为1,得到$\hat{\alpha}_{1,1}$到$\hat{\alpha}_{1,4}$。 Fig. 5. Calculation of $b^i$ in self-attention layer. Adapted from [4] 然后,再对计算出来的$\hat{\alpha}_{1,1}$到$\hat{\alpha}_{1,4}$和$v$相乘求和。以第一个token为例,它的attention层输出是, $$ b^1 = \sum_i\hat{\alpha}_{1,i}v^i $$ 重复同样的步骤,则可以得到$b_1$到$b_4$。以上的步骤看起来计算相当的复杂,但是其实可以通过几个比较简单的矩阵运算即可完成,所以它是可以很容易通过GPU进行并行计算的。 Fig. 6. Matrix multiplication form in self-attention layer. Adapted from [4] 左上角的$O$代表output,$I$代表input。而这个$I$则是将所有的输入$a_i$叠起来变成一个2D矩阵。而以上的全部需要一个一个迭代计算的过程都可以用矩阵乘法的方式实现,总的计算其实很方便。正因为这个容易进行并行计算,所以在运算速度上是快于RNN的。 Transformer结构 Fig. 7. Scaled dot product attention. Adapted from [1] $$Attention(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_K}})V$$ 如上所示[1],这个过程被称为Scaled Dot-Product Attention。你会注意到这个公式里除以一个$\sqrt{d_K}$。根据原文的说明,这个的目的是为了把值重新缩放回 Mean = 0, Variance = 1 的状态。 Fig. 8. Multi-head attention. Adapted from [4] 除此之外,他们还提出了一个Multi-Head Attention Layer,相比于普通的attention层,这个多头attention层有多个attention层互相并行。最后把多个并行的attention层拼接,再通过一个全连接层进行映射,把维度保持在和输入相同的状态。 Fig. 9. Transformer structure. Adapted from [1] 如上图所示,整个Transformer是一个encoder-decoder结构。如果这个Transformer的任务是把英文翻译成中文,那在encoder的inputs这里输入中文句子,在decoder的输入端输入英文句子,decoder的输出则是概率。从encoder开始,输入的token序列会先送入embedding层转换成向量,然后再和positional encoding相加。因为在attention层中输入token并不会知道其中的位置信息,所以需要加一个positional encoding。因为矩阵相加可以视为拼接的一种特殊情况,所以通过embedding和positional encoding相加,attention层可以同时获取两者的信息,提取的特征更有效率。这个positional encoding可以是自己手动设定的,也可以是通过学习的。在这篇文章下用的是手动设定的。相加之后,会有4条路线,1条是类似于ResNet[6]的恒等连接,而另外3条则是通过对应的全连接层得到Q,K,V,再输入进attention层。在结束了multi-head attention层的计算之后,接下来是一个Add & Norm层,这个层的过程就是将attention层的输入和输出相加,并且做一个layer normalization(LN)[7]。 Fig. 10. Layer normalization. Adapted from [4] 如上图所示[4],和常用的batch normalization(BN)[8]相比,主要是标准化的维度不同。LN是在一个输入中跨通道的标准化,BN是在一个batch中跨数据但是在同一个通道下进行标准化。在sequence数据中,一般使用LN而不是BN。 然后是decoder部分,这里的decoder的输入,也就是机器翻译的结果是需要右移一位的(shifted right),因为第一位是<BOS>标签,作为一个句子的开头。对比encoder和decoder,主要区别在于decoder的第一层是一个Masked Multi-Head Attention。因为对于一个基于时间序列的预测来说,当然是不能通过未来的信息去预测的,所以在这个Masked Multi-Head Attention层中,所有的token输入只能看到前面的信息,而后面的信息都会被隐藏。 在这个Masked Multi-Head Attention层之后,会有一个普通的Multi-Head Attention,但是其中的Q和K是来源于encoder计算的结果,只有V是来自于上一层的输出。个人理解是Q和K可以寻找不同token在这个sequence之间的相关性,所以encoder的输出要拿来给decoder使用。 Fig. 11. Transformer inference. Adapted from [4] 如上图所示[4],在预测的时候,因为不知道翻译的结果,所以只能一个一个预测,将第一个预测出的词放到这个序列的第二个输入才能依次预测出整个句子。在训练的时候因为知道了全部内容,所以可以并行,但是在预测中是不行的。 尝试把Transformer用于CV 在Transformer发布之后,有很多研究在尝试把Transformer结果用于CV。 Fig. 12. Attention augmented convolutional network. Adapted from [9] 比如这一篇[9],同时使用传统的卷积和新的Self-Attention机制用于计算机视觉相关的任务。 Fig. 13. Object detection transformer. Adapted from [10] 而这一篇[10],则仅仅用CNN替代原始Transformer中的Embedding过程,剩下的都与原版[1]很像。同样是完整的Transformer encoder和decoder,还有positional encoding,最后生成的结果也是一个个box用于对象检测(object detection)。这个过程已经和原版很像了。 关于这两篇的详解,已经在续篇中详细介绍。 Vision Transformer 之前的研究很少有讲Transformer直接用在CV上的,而且用上了速度也很慢。在2020年年底,有一篇论文,”An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale”,提出了Vision Transformer (ViT)[11],提供了另一种方法让本来用于NLP的Transformer可以直接用在CV上。在ViT中,每一个Transformer的token其实是一个图片的patch,这也是标题这么起的原因。在这篇论文中,这个ViT主要是用于最基础的图像分类任务。 Fig. 14. Vision transformer. Adapted from [11] 具体步骤 一开始我们有一个图片$x$,高度$H$,宽度$W$,通道数$C$。对于RGB图像来说$C=3$。 $$x\in H\times W\times C$$ 正如之前所说,我们先需要讲这个图片分成一块一块patch,然后将一个patch中的所有数值全部暴力的压扁到一维向量。假设patch都是正方形,边长为$P$,一个图片中的patch数量为$N$。则, $$x_p\in N \times (P^{2}C)$$ 其中, $$N=\frac{HW}{P^2}$$ 所以我们是将一个patch本来为三维矩阵$(P\times P \times C)$直接摊平为一维向量,长度为$P^{2}C$。而因为有$N$个patch,所以最后的结果是$N \times (P^{2}C)$的二维矩阵。这个形状是符合Transformer输入的。 然而$P^{2}C$的长度可能太长了,于是我们可以使用一个线性映射将维度降低到$N\times D$,其中$D$是新的patch向量的长度。把降维之后的矩阵记为$z_p$。 $$z_p\in N\times D$$ 然后,我们需要增加一个可训练的token,$z_{class}$,放到整个$Z$的第一位,并且加上一个可训练的positional encoding。 $$Z=[z_{class},z_p^1,z_p^2,z_p^3,\cdots,z_p^N]+E_{pos}$$ 由这些新的向量组成的矩阵加上positional encoding $E_{pos}$,得到的结果的矩阵记为$Z$。 这些东西就可以直接放进一个Transformer encoder,得到的结果也是一个sequence,但是只取第一个,也就是$z_{class}$对应的输出。将这个向量放入一个MLP用于分类,得到分类结果$\hat{y}$,与label $y$一起计算loss并反向传播训练整个ViT。 Class Token 根据原文,这个是从BERT[12]的结果中拿过来的,因为使用一个可训练的token,会比使用别的token的结果用于分类更加公平,因为不会受到原先包含信息的影响。 Fig. 15. BERT. Adapted from [12] Positional Encoding Fig. 16. Positional encoding in ViT. Adapted from [11] 然后是关于positional encoding的。这张图展示了positional encoding的相似度,越亮说明越相似。我们可以看到,对于每一个patch,在相似行和列的patch的相似度是较高的,而那些距离比较远的相似度则较低。这说明一个可训练的positional encoding是可以学到其中的位置关系的。 Fig. 17. Attention distance. Adapted from [11] 这张图展示了attention距离和网络深度的关系。x轴是网络深度,y轴是平均attention的patch之间的距离,不同的点代表不同的head找到的attention。很显然,在网络很浅的时候,attention层依然能找到距离较远的关系。如果这是一个CNN网络,那这个结果就应该会分布在这张图中一堆散点的下边缘。所以不用特别深的网络,ViT依然能学到这张图的全局特征。 Multiscale Vision Transformer 在之前的ViT[11]中,实际上每一个attention层的输入输出维度都是一样的,所以attention层只是在一个scale上进行检测。这篇2021年的论文提出了Multiscale Vision Transformer (MViT)[13]。大家都知道,在CNN中经过了数层卷积层之后会有一个降采样层降低特征图的长宽,这样之后的卷积层将能提取到不同scale的特征。这篇论文想通过同样的方式来把这个multi-scale的想法用在ViT上。 Fig. 18. Multiscale vision transformer. Adapted from [13] 如上图所示[13],他们提出了Multi-Head Pooling Attention (MHPA)层。很显然,最大的区别就在于对于每一条路上都加了一个pooling层。在这些pooling层之后,那些向量的长度就会降低,这样后面的attention层就能检测到不同scale的特征了。 Fig. 19. MViT structures. Adapted from [13] 在这篇文章里,他们提出两个MViT的结构,分别是MViT-B和MViT-S,用于视频分析的。他们把一整个网络分成了多个stage。在第一个stage中是读取数据,因为视频是用3D矩阵表示,切分patch也是3D,所以patch在这里被成为cube。然后在后面的stage中,cube的长度和宽度都不断降低,而通道数则不断增加。在最终的实验结果中,MViT的表现要优于之前的ViT模型,而且参数数量也更少了,运行速度也更快了。 推荐一个GitHub Repository 这里推荐一个GitHub repo,叫Awesome Visual-Transformer,里面收录了许多用于CV的Transformer论文和官方实现的code链接[14]。 https://github.com/dk-liang/Awesome-Visual-Transformer 参考文献 [1] A. Vaswani et al., “Attention is all you need,” in Proceedings of the 31st International Conference on Neural Information Processing Systems, Red Hook, NY, USA, Dec. 2017, pp. 6000–6010. [2] S. Hochreiter and J. Schmidhuber, “Long Short-Term Memory,” Neural Computation, vol. 9, no. 8, pp. 1735–1780, Nov. 1997, doi: 10.1162/neco.1997.9.8.1735. [3] K. Cho et al., “Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation,” arXiv:1406.1078 [cs, stat], 2014. [4] "Transformer & BERT", Speech.ee.ntu.edu.tw, 2021. [5] Y. Lecun, L. Bottou, Y. Bengio, and P. Haffner, ‘Gradient-based learning applied to document recognition’, Proceedings of the IEEE, vol. 86, no. 11, pp. 2278–2324, Nov. 1998, doi: 10.1109/5.726791. [6] K. He, X. Zhang, S. Ren, and J. Sun, “Deep Residual Learning for Image Recognition,” in Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, 2016, pp. 770–778. [7] J. L. Ba, J. R. Kiros, and G. E. Hinton, “Layer Normalization,” arXiv:1607.06450 [cs, stat], 2016. [8] S. Ioffe and C. Szegedy, “Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift,” in International Conference on Machine Learning, Jun. 2015, pp. 448–456. [9] I. Bello, B. Zoph, A. Vaswani, J. Shlens, and Q. V. Le, “Attention Augmented Convolutional Networks,” in Proceedings of the IEEE/CVF International Conference on Computer Vision, 2019, pp. 3286–3295. [10] N. Carion, F. Massa, G. Synnaeve, N. Usunier, A. Kirillov, and S. Zagoruyko, “End-to-End Object Detection with Transformers,” in Computer Vision – ECCV 2020, Cham, 2020, pp. 213–229, doi: 10.1007/978-3-030-58452-8_13. [11] A. Dosovitskiy et al., “An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale,” arXiv:2010.11929 [cs], Oct. 2020. [12] J. Devlin, M.-W. Chang, K. Lee, and K. Toutanova, “BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding,” in Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, Volume 1 (Long and Short Papers), Minneapolis, Minnesota, Jun. 2019, pp. 4171–4186, doi: 10.18653/v1/N19-1423. [13] H. Fan et al., “Multiscale Vision Transformers,” arXiv:2104.11227 [cs], Apr. 2021. [14] "dk-liang/Awesome-Visual-Transformer", GitHub, 2021. [Online]. Available: https://github.com/dk-liang/Awesome-Visual-Transformer. #refplus, #refplus li{ padding:0; margin:0; list-style:none; }; document.querySelectorAll(".refplus-num").forEach((ref) => { let refid = ref.firstChild.href.replace(location.origin+location.pathname,''); let refel = document.querySelector(refid); let refnum = refel.dataset.num; let ref_content = refel.innerText.replace(`[${refnum}]`,''); tippy(ref, { content: ref_content, }); });

2021/4/30
articleCard.readMore

一些邮箱客户端的使用对比

邮箱在日常中使用非常频繁,基本上一个月要发几十封邮件,所以试了试一些比较有名的客户端看看各方面表现如何。下文中分别以PC客户端和手机客户端分开考虑,分别列出了表格介绍各方面的优缺点,并且总结了自己现在的使用方式。 PC客户端 PC客户端需要考虑到写邮件,读邮件,设置日历事件并且邀请他人等活动。 客户端UI多邮箱聚合写邮件读邮件日历 Gmail网页基于Web,不方便只支持Gmail很强,有自动补全和语法检查凑合,搜索比较慢,分类比较麻烦只支持Gmail,可以查询别人的空余时间表 Win10 Mail / MacOS Mail系统预装,操作方便,看起来比较简单完全支持功能简陋,毫无辅助。Reply和Forward会出现不需要的引用系统提醒方便,其他的凑合聚合全部邮箱,但是无法查询他人时间表 Spark (不支持Windows)好看,交互方便完全支持几乎没有辅助,有少许语法检查,回复的时候会出现不可控的引用。搜索很快,有自动分组,读起来很舒服只支持Gmail邮箱的日历,不能查询他人时间表 OutlookUI有点复杂,操作繁琐完全支持有语法检查,和少量自动补全,回复的时候还会出现冗余引用因为UI复杂的关系,导致不够灵活聚合全部邮箱,但是无法查询他人的时间表 目前主要用Win10 Mail (Windows) / Spark (MacOS) 读邮件,用Gmail网页写邮件,很麻烦。有些简单的邮件可以用Win10Mail/Spark直接写,但是总感觉不放心。阅读日历,写个人活动直接用Win10/MacOS自带的日历,但是如果是需要邀请别人的活动,或者查询别人的空余时间,还是得打开Gmail网页有点麻烦,希望能有合适的工具。 手机客户端 手机客户端(iOS)主要以读为主,读邮件和日历。回复邮件和写日历活动需求比较少。 客户端UI多邮箱聚合写邮件读邮件日历 iOS自带比较简洁,功能不多完全支持毫无辅助,没有自动补全和语法检查,回复的时候也会有冗余引用,很难看。刷新比较慢,搜索比较乱,阅读体验不错支持全部邮箱聚合,不能看他人时间表,桌面小工具支持看隔天活动 Gmail手机端功能相仿只支持Gmail辅助基本上是网页端水平,很强搜索速度不太行,阅读体验不错只支持Gmail,但是有堪比网页的完整支持,小工具不支持看隔天活动 Spark漂亮,而且交互方便完全支持基本没有辅助搜索速度快,有自动智能分组,读邮件的时候没有头像现实,有的时候看起来比较乱,但是对于不同类型的邮件都有专门的UI,可读性比较强。只支持Gmail,看不了别人的空闲时间,小工具不支持看隔天活动 手机端由于是读为主,现在是用Spark当邮件收发主力,在需要长篇回复Gmail邮件时可以用Gmail APP。日历则是用手机自带。 持续更新 以后用的多了,还会继续更新。 To be continued…

2021/4/27
articleCard.readMore