从 CallBack 到 Promise,React 框架异步开发学习心得

引入 说起 React,我印象最深刻的是,在 React 中,数据是向下流动的(react 为什么是单向数据流)——越高层级的组件,获得着越多的数据,而低层级组件数据的获取和更新,大多都通过组件属性传递以及回调函数方式得到。这就意味着,高层组件刷新会同时刷新低层组件,而低层组件刷新往往不会带动高层组件刷新,于是更多的状态和逻辑会出现在比较高层级的组件里,在 React 中叫做状态提升 。例如对话框的打开与关闭更应该是对话框组件的属性,而不是对话框组件的状态——对话框的操作往往与高层数据相关,如果把状态放在低层级,则很难把当前的状态和数据与高层级组件交互。 在这种数据流的模式下,为了使得基本组件“动起来”,高层级组件里总会有大大小小的许多状态,以便控制基本组件的开/关、显示/隐藏等等。此外,除了控制基本组件的状态以外,高层级组件本身可能还承担着数据通信的功能,例如我们本次提到的异步请求和发送数据。在 React 中,状态state的更新会使得组件重新进行渲染(见State & 生命周期),有的时候我们只希望重新渲染这个组件的一部分组件(例如刚才所说的对话框),而有的时候我们希望重新请求数据(数据同步、表格翻页)全部刷新,于是我们通常会使用 useEffect 钩子对一些刷新操作添加限定,仅仅在某些变量修改的时候,才会重新执行该部分代码逻辑(在 React 官方文档中叫做关注点分离)。 问题 所以对于一个又需要刷新数据,又需要控制对话框,而且获取数据要请求两次 api 的组件,就会变成这个样子(CallBack 版本): export default function Component(props) { let [dialogState, setDialogState] = useState(false); // some states for dialogs let [renderData, setRenderData] = useState(null); // some states for rendering let [page, setPage] = useState(1); // some states which force data refresh useEffect(() => { fetchSomeData("url", {params: "Some Params"}, {config: "Some Configurations"}, (data) => { // callback for success let someProps = getSomeProps(data); fetchSomeData("url2", {params: someProps}, {config: "Some Configurations"}, (data) => { // funciton for process setRenderData(processing(data)); }, () => {}); }, (error) => { // callback for failure }); }, [page]); // fetch data only when page changes if (renderData === null) return null; return ( <> {/* equals to <React.Fragment> */} <Dialog someStates={dialogState}/> <Others data={RenderData}/> </> {/* equals to </React.Fragment> */} ); } 于是这个组件的执行流程是这样子的: 组件第一次渲染:执行useEffect,开启异步数据请求,此时并没有任何有效数据用于渲染,于是返回null不加载模型; 组件收取到信息:执行回调函数,对数据进行处理,并更新组件状态,此时仍未执行组件刷新,数据不变; 组件状态得到更新:组件状态变化,组件刷新,但不再执行useEffect; (中间可能的)对话框状态变化:组件状态变化,组件刷新,但不再执行useEffect。 这样存在的问题在于, 回调函数过于复杂——函数体量太大在合作时难以理解,包装起来可能涉及数据传递的问题 回调函数嵌套——有可能在收到某些信息,还要基于这些信息继续发请求,那么回调函数可能嵌套多层 Promise 的意义 我感觉理解 JavaScript Promise这篇文章写的还是不错的,使用 Promise 构造一个函数,这个 Promise 就可以管理这个函数的状态,以便后续任务在这个函数执行完毕后使用。所以现代的 fetch 函数都尽可能返回一个 Promise,以便我们使用 Promise.then() 这个方法以便对数据进行处理。 所以上面的代码或许可以改成这个样子: export default function Component(props) { ... useEffect(() => { fetchSomeData("url", {params: "Some Params"}, {config: "Some Configurations"}).then((data) => { // funciton for process let someProps = getSomeProps(data); return fetchSomeData("url2", {params: someProps}, {config: "Some Configurations"}); }).then((data) => { // funciton for process setRenderData(processing(data)); }).catch((error) => { // function for failure }); }, [page]); // fetch data only when page changes ... } 那么这样有没有实质性的减少代码层数?减少了,原先存在的嵌套调用现在变成了连续使用 .then()函数,使得硕大的处理层变得轻松的多。 Async 和 await 与上一节一样,先挂出一个链接用于学习:【学习笔记】深入理解 async/await。 await 的出现带来了什么呢?await 使得获取的结果直接提取了出来,不再需要额外套一层函数用于执行。这样函数嵌套会更加少,而且也可以像同步的函数一样处理数据了。于是我们的代码会变得更加清楚,不会再像原来一样晦涩难懂。 于是我们的代码可能变成这样子,如果想分开处理异常可以套两个 try-catch块: export default function Component(props) { ... useEffect(async () => { try { let data = await fetchSomeData("url", {params: "Some Params"}, {config: "Some Configurations"}); // funciton for process let someProps = getSomeProps(data); let anoData = await fetchSomeData("url2", {params: someProps}, {config: "Some Configurations"}); // funciton for process setRenderData(processing(anoData)); } catch (error) { // function for failure } // try-catch block is unnecessary if no error exist }, [page]); // fetch data only when page changes ... } 但是这样 Eslint 组件是会报警告的—— ESLint: Effect callbacks are synchronous to prevent race conditions. Put the async function inside: 如果版本早于 React 16,可能会直接报错误—— An effect function must not return anything besides a function, which is used for clean-up. It looks like you wrote useEffect(async () => …) or returned a Promise. Instead, write the async function inside your effect and call it immediately 这是因为 useEffect是需要返回值来解决组件销毁/重建时的副作用清除的,而我们加上 async 关键字则会让这个函数返回一个 Promise,所以应该建一个普通的函数,然后在函数里面创建带有async关键字的函数,并立即调用。详见 hooks 学习之 useEffect。 export default function Component(props) { ... useEffect(() => {(async () => { ... })()}, [page]); // fetch data only when page changes ... } 并行的数据请求 我们的请求可能没有前置要求,那么异步的数据获取我们怎么进行处理呢?一般来说,我们对于数据请求,难免存在请求失败的情况,所以常见的策略是哪部分到了先加载哪部分,报错的部分再进行重试或请求备用数据源,以免用户等待太着急。于是我们就可以建造多个useEffect函数,分别进行数据请求和处理,加上 React 的关注点分离策略,我们就可以实现部分数据的渲染。 export default function Component(props) { let [dataA, setDataA] = useState(null); // data for Component A let [dataB, setDataB] = useState(null); // data for Component B useEffect(() => { fetchSomeData("urlA", {params: "Some Params"}, {config: "Some Configurations"}).then((data) => setDataA(data)); }, [page]); useEffect(() => { fetchSomeData("urlB", {params: "Some Params"}, {config: "Some Configurations"}).then((data) => setDataB(data)); }, [page]); return ( <> {/* equals to <React.Fragment> */} { dataA && <A data={dataA}/> } { dataB && <B data={dataB}/> } </> {/* equals to </React.Fragment> */} ); } 如果我们对数据正确性有非常高的要求,要求必须所有数据到齐才能渲染的话,可以使用Promise.all()函数。 export default function Component(props) { let [dataA, setDataA] = useState(null); // data for Component A let [dataB, setDataB] = useState(null); // data for Component B useEffect(() => { let remoteA = fetchSomeData("urlA", {params: "Some Params"}, {config: "Some Configurations"}); let remoteB = fetchSomeData("urlB", {params: "Some Params"}, {config: "Some Configurations"}); Promise.all([remoteA, remoteB]).then((dataArray) => { let [first, second] = dataArray; setDataA(first); setDataB(second); }).catch((error) => someFunction(error)); }, [page]); return ( <> {/* equals to <React.Fragment> */} { dataA && <A data={dataA}/> } { dataB && <B data={dataB}/> } </> {/* equals to </React.Fragment> */} ); }

2023/2/4
articleCard.readMore

2022年保研经历--快乐与痛苦并存的夏

保研推免经历 目标学校:浙江大学计算机学院专硕 实际上岸:南京大学计算机系专硕 成绩信息:六级 458、绩点 89.72、排名 6/17(五学期,拔尖班) 科研信息:一篇 SCI 一区三作在投、一个软件著作权、两个课题组项目、所在学校科研训练对应学科第一名 竞赛信息:CCSP 全国银奖,CSP 前 1%,无建模、无 ACM 作为基础学科拔尖计划的同学来讲,大多数同学本来应该出国留学的。结果因为疫情原因,交流项目取消,大多数同学留被迫留在国内内卷,真的是伤透了心。 现在大家都海投,报名的学校有: 学校和院系报名类型阶段结果 复旦大学计算机学院专硕夏令营&预推免都没过初审(复旦没有珠峰计划独立学院,所以好像不怎么 care 拔尖班,在排名上吃了亏) 浙江大学计算机学院专硕预推免Waiting 中游,928 下午三点接到 offer,但已经确认南大 南京大学计算机系学硕夏令营Waiting 中游,928 上午十点接到专硕 offer,最后确认 中国科学技术大学计算机学院学硕夏令营前五个人过了初审,我第六没要我 中科院软件所学硕夏令营老师给了学硕 offer,但是导师据说人品一般,放弃 中科院上海高等研究院学硕夏令营因为后来大家发现没听说过这学校,于是放弃 哈工大深圳计算机学院专硕预推免报着玩的,专硕 offer,最后没去 华中科技大学计算机学院学硕预推免过了初审,鸽了复试 山东大学计算机学院学硕夏令营本校,最后还是放弃了 offer 中国人民大学信息学院学硕夏令营Waiting 上游,9 月中旬获得学硕 offer,928 放弃 中科院网络中心学硕夏令营&预推免报着玩,需要机考所以两次都鸽了 浙江大学软件学院专硕夏令营CAD 夏令营,去跟老师混脸熟的,也不发 offer,认识了几个同学 各个学校怎么准备的文章肯定有许多,那本文只介绍几个 icy 的小故事: 浙大计院,我的浙大计院 当时托本科导师 Linda 的关系,联系到了浙江大学黄劲老师,还提前面试通过了(硕士)。黄老师主要的方向是偏数值方法的结构、力学分析,当时自己的数值计算知识还都还给数值计算老师了,发现一问三不知 2333。 不知是因为我“虽然我现在基础薄弱,但是我大四没大有课,可以提前进入课题组学习,这样可以在研究生一年级有一定的储备量”打动了他,还是他碍于我本科导师的面子,最后愿意为我预留硕士名额。而浙江大学对于硕士来说本校保护很强,绝大多数名额都分给了本校同学,直接录取的外校学生里,学硕 50 人仅有 4-5 人是外校,学硕+专硕的 120 人里,也只有 30-40 人是外校,这作为外校同学来说压力山大。 9 月中旬开始的预推免,就开始乱七八糟的看各种专业课知识,也准备了自己的项目,按照 21 年的推免要求——20 分钟的面试(其中五分钟自我介绍,五分钟里有不少于一分钟的英文展示)一点一点准备。 当时拿了山大的 PPT Poster(山大计算机要求只能用一页 PPT)作为第一页,然后每个项目各用一页介绍的项目,时间分配是一分钟英语自我介绍+四分钟的项目(科研训练两分钟+两个软件项目各一分钟)。结果老师们没关心我的各个项目,直接来问数据结构、编译原理之类的专业课,有点措手不及。 后来和黄老师的讨论中了解到,能进入浙大复试的同学里,大家都有深度学习的项目,但绝大多数同学对项目的原理问几句就答不上来,于是老师们可能不再对同学们的深度学习项目感兴趣(尤其是时间靠后,比较困还可能比较饿的时间段)。 所以如果自己排的靠前,推荐学弟学妹们多准备项目,反之多准备文化课。面试的老师都是临时通知来的,所以各个方向都有,自己教什么课可能就问什么课,所以计算机专业课,以及线性代数还是多准备准备为好。 当时帮着自己准备的还有浙大本校的松鼠同学和小明同学,他们还给我了很多帮助和建议,最后还是面试寄了,感觉有愧于他们的帮助啊。我寄了之后他们还给我打气,这样的好朋友再来一打也不为过呀 qwq。 一共候补 80 人左右,自己排 50 多,感觉基本没希望了,到了 928 当天下午三点,浙大招办来电话说候补到了。此时南大已经录取且不允许再解锁系统,便作罢。 CAD 五人组——浙软夏令营的好朋友们 浙江大学软件学院其实是在宁波的独立学院,原本是借用计算机学院导师,一同培养的,不过最近听说不让前往杭州找老师了,于是含金量就低了许多。当初因为黄老师没有多余的博士名额了,加上自己六级分数不够(要求 460 分),于是夏令营不能报浙大计算机的博士夏令营(只有博士开营),报了软件学院玩一玩。 软件学院的优营没有用,其实就是体验营,CAD 里让大家五人一组翻译一篇论文,然后复现论文。我们组里的朋友们,也有和我一样,为报计算机学院硕士来玩的同学小 X,他联系好了导师就 quit 了小组项目,于是出现了只有四人的“CAD 五人组”。我们翻译的是一篇经典的论文 MeshCNN,我借着我对图形学比较多的了解,主要负责审校论文学术词汇有没有翻译错误,最后得到了翻译终稿,也在博客里挂出了。 到了预推免,我和小 X 同学一起,报了计算机学院,但是可能小 X 因为排名原因没有进入复试,于是除了我的四人还是报名了浙软。最后他们浙软都过了,就我寄了,异常悲伤。928 当天,五个人里一个南大、一个北航、一个武大、一个浙软,险些成为浙软鸽子团 2333。朋友们都很好,希望后面有机会还能再见。 薛定谔的电话——南大的鸡贼老师们 南京大学计算机系研究生招生办是有电话的 025-83594674,但是这个电话在绝大多数情况都是打不通的。面试完之后,南大发 waiting 的时候,有幸接到招生组长曹迎春老师的电话(划重点,待会儿要考),说我分数不够专硕,但是可以转直博。 于是联系了相关方向的老师们,比如 MCG、软件所、图形学组、路通老师组,纷纷表示博士名额有限,只能选择继续等待。 本来觉得没啥希望了,928 突然接到了招办电话说补到专硕了,于是系统填报了南京大学,等待学校录取。南大的确认时间是下午一点,12 点 58 的时候紧卡慢卡赶紧确认了。后面浙大打电话的时候,还在想能不能找南大解锁一下,结果大招办电话,果然一如既往的打不通。奇了怪了,上午给我打我还能打回去,一过十二点就打不通了笑死。 于是直接给曹老师手机打电话,老师先问了“你怎么知道我手机号的”,拿几句假话骗了过去之后,不管怎么求老师,老师就“你可以投诉我们,反正我们就不给解锁”的无赖态度,死死卡着系统,于是转去浙大的梦想破灭了。 薛定谔的电话——需要给你打电话的时候能打通,不希望你打电话的时候就拔线,这个操作也是神之一笔呀。 Social 巅峰——GDC2022 山大计算机学院的图形学组 IRC,每年都会承办学术会议,2021 年承办的 ICCVM,2022 年承办的 GDC2022。去年自己的学长 L 哥,在 CVM 的晚宴上各处推销自己,加上他一作的 A 会,成功上岸鲍虎军老师直博。今年为了能压中面试老师,尽可能晚宴找到了各浙大的老师们敬酒(当然最后也没能押中,唉浙大计算机学院体量太大老师太多了),甚至饭都没能吃上几口。 当时作为志愿者,我负责接待老师们,其中接待的嘉宾里有一位老先生——南京大学张福炎老师,他与汪嘉业老师等老师一起,为图形学学科奠定了重要的基础。当时自己与老师短信聊得很好,按照老师“一天问候一次”的指标编辑短信,于是聊聊青岛风景,聊聊老师当年的事情啥的,逐渐熟络起来。老师离开会场,还特地跟我们的老师表扬我——“XX(我们老师)你好!返程列车已缓缓启动,短短几天青岛给我们留下了美好的印象,感谢山大的热情接待,特别是谢谢小黄同学,他细致而负责。欢迎你们来南京,到南大计算机系看看。” 没成想到,邀请我去南大计算机系,最后真的去成了南大计算机系。我 928 录取后,给张老师发了短信“张老师好,我是暑假 GDC 会议的小黄同学,今天我成功推免到南京大学计算机系,导师是郭延文老师。郭老师说他是您的学生,真的非常巧,期待与老师南京大学相见!”,老师回复“祝贺您来南大深造,郭老师学问很好,相信您会成功”。张老师的祝福真的打动了我,也希望之后自己在南京大学,能有番成长、有番收获。 给学弟学妹们 现在保研太卷了,如果有出国打算,不如提前考虑一下。申请国外的 Master 可能资金上可能比较昂贵,但申请国外的 PhD 的话,可能需要导师的强推或者 publication。如果自己比较早能中论文,真的可以出国看看。如果是 PhD 的话,奖学金用于学习生活真的是非常充足的。 如果国内的话,其实对于科研还是多看老师,尤其是老师的人品,毕竟是自己未来三四年(含大四)合作的伙伴,如果老师风格不能接受那可能还是挺痛苦的。绿群里经常对学校分档,什么清北两所、华五人啥的,其实不同方向真的不一样,每个学校都会有好老师,也会有能力上不太突出的老师,在自己已有的 offer 里择优选择就好。 另外就是,今年浙大计算机被鸽穿、浙大软件被鸽穿、复旦密歇根学院被鸽穿(听说),其实有的时候,搏一搏,单车变摩托,真的等一等就有可能递补到自己。不过机会对应着风险,如果自己没能递补到,可能就更加难受了,还是结合往年候补位次和自己的 waiting 排名,自己心里做好选择吧。 基督山伯爵最后一句是“人们都是在等待和希望中生活着”,可能保研夏令营,乃至预推免还没能找到很好的导师,也不要过于焦虑,相信后面是会更好的消息的。祝大家保研顺利上岸,升学成功! icy 9 月 30 日于青岛

2022/9/30
articleCard.readMore

DNS CCA记录与SSL证书申请

引入 之前在聊聊证书中提到,在申请时遇到了Type: caa Detail: CAA record for domain.cn prevents issuance问题。到底CAA是什么,为什么当时不能申请证书?真的是挖了好久的一个坑,发现最近一直都在填坑诶,这次我们来解释一下这个问题。 CAA(Certification Authority Authorization,即证书颁发机构授权)是一项防止HTTPS证书错误签发的安全措施,于2013年1月通过互联网工程任务组(IETF)的批准列为RFC6844,2017年3月,CA浏览器论坛投票通过187号提案,要求CA机构从2017年9月8日起执行CAA强制性检查。 CAA标准是指域名所有者在其域名DNS记录的CAA字段中,授权指定CA机构为其域名签发证书,CA机构签发证书时强制性检查CAA记录,如果检查发现未获得授权,将拒绝为该域名签发证书,从而防止未授权HTTPS证书错误签发。如果域名所有者没有为其域名设置CAA记录,那么任何CA都可以为其域名颁发证书。 要顺利执行CAA标准,需要三方共同完成: DNS服务商:升级DNS系统使其支持CAA记录设置; 域名所有者:在DNS记录的CAA字段中,授权指定的几家CA机构为域名签发证书; CA机构: CA机构签发证书之前,强制性检查DNS CAA记录。 这是沃通在2017年的一篇资讯,介绍了CAA的作用,简单来讲就是域名证书的申请,要进一步的进行约束。证书的发放,会使得获得私钥的人有代表证书持有人的身份,如果让第三方在持有人不知道的情况下申请,则会带来不必要的麻烦。因此IETF组织认为有必要让域名持有者认定,自己的域名到底可以让哪些证书颁发机构CA(Certification Authority)签发,则白名单之外的CA则不能签发,以起到对域名持有者的保护作用。 CAA记录的构成 先简单介绍一下CAA记录长什么样子。根据规范,一条CAA记录可以用CAA <flag> <tag> <value>表示,是由一个标志字节的<flag>和一个被称为属性的 <tag>-<value>(标签-值)对组成。每个标签的意义和范围如下: 标签描述 flag可填写0或128,用于标志认证机构。 默认情况下填写0,表示如果颁发证书机构无法识别本条信息,进行忽略。 tag支持 issue、issuewild 和 iodef。 valueCA 的域名或用于违规通知的电子邮箱。 而定义的tag标签的意义如下: 字段说明 issueCA 授权单个证书颁发机构发布的任何类型域名证书。 issuewildCA 授权单个证书颁发机构发布主机名的通配符证书。 iodefCA 可以将违规的颁发记录 URL 发送给某个电子邮箱。 CAA记录的检索规则 根据cab论坛的文章,设被查询的域名为X,X域名直接关联CAA记录为CAA(X),X域名CNAME指向的域名为A(X),X域名父级域名(如a.b.com的父级域名为b.com,而b.com没有父级域名)为P(X),则检索规则如下: 如CAA(X)直接存在,则返回CAA(X) 若A(X)存在,在规定的步数(最少8步)内不能找到X在CNAME链条的最终域名A^n^(X),则返回报错 CNAME reaches the maximum number of 8 若A(X)存在,在规定的步数(最少8步)内能找到X在CNAME链条的最终域名A^n^(X),而且CAA(A^n^(X))存在,则返回CAA(A^n^(X)) 若X不为主域名xxx.com,且CAA(P(X))存在,则返回CAA(P(X)),否则依次找CAA(P(P(X)))等,直到检索主域名的CAA记录 如第四步找不到CAA记录,返回空 用Python代码写起来就是 # step 1 & 3 step = 8 target = X while step >= 0: if A(target) is null: break target = A(target) step -= 1 # step 2 if step < 0: return error("CNAME reaches the maximum number of 8.") if CAA(target) is not null: return CAA(target) # step 4 while P(X) is not null: if CAA(P(X)) is not null: return CAA(P(X)) X = P(X) # step 5 return null 可能有的人想问了,如果在第3步中,CNAME链条的某个域名配置了CAA记录呢?根据测试,CNAME和CAA记录不共存,在DNSPods添加记录时会报错。 失误的复现 当时申请的是*.oops-sdu.cn及oops-sdu.cn域名的SSL证书,而oops-sdu.cn设置的是oops-sdu.github.io的CNAME解析。根据上面的规则,CA会查询oops-sdu.github.io的CAA记录,查询结果如下: ;; ANSWER SECTION: oops-sdu.github.io. 3600 IN CAA 0 issue "digicert.com" oops-sdu.github.io. 3600 IN CAA 0 issuewild "digicert.com" oops-sdu.github.io. 3600 IN CAA 0 issue "letsencrypt.org" 而根据上面的介绍,网站只允许digicert.com申请单域名及泛域名的证书,而letsencrypt.org只能申请单域名证书、不能申请泛域名证书。因此使用letsencrypt.org同时申请*.oops-sdu.cn及oops-sdu.cn是会失败的,不过只申请oops-sdu.cn会成功。当然,根据上述第四步,在子域名没有额外设置 CNAME 和 CAA 相关记录的时候,那么我们的子域名也会继承 apex 域名的 CAA 记录,使得子域名下还是只能单网站申请证书,不能申请子域名下的泛域名证书,影响还是蛮大的。同样,这也是意味着,在子域名没有额外设置 CNAME 和 CAA 相关记录的时候,在 apex 域名下的 CAA 限制会影响整个域名,尤其是对于不在 CAA 记录里许可的证书发行商。 其实,GitHub Pages在配置域名的时候,提起过对apex域名的解析配置方法。方法提出填写A记录和AAAA记录(IPv6),就是防止CAA记录被同步转移。其实同步转移的不只是CAA记录,TXT记录和MX记录(用于域名绑定企业邮箱)等记录也会被同步重定向(甚至有时候重定向的优先级更高,忽略域名本身的记录),因此提醒大家在配置@域名时慎重选择CNAME记录。 更新:阿里云和腾讯云的域名解析上,充分考虑到了域名CNAME影响MX和TXT记录的问题,于是他们分别对@主机的解析规则进行了一定的修改,并列出冲突的情况(见腾讯云冲突规则,腾讯云CNAME加速,阿里云冲突规则)。 设置CAA记录 虽然上面说2013年这个CAA就已经出现了,但是到2017年11月沃通资讯发布的时候,国内的DNS厂商还不支持CAA记录的添加。不过目前来看,国内阿里云、腾讯云都已经支持相关记录的添加了。 按照CAA <flag> <tag> <value>的规则,我们一般填写的时候,第一个直接写0,第二个从三个里选一个,例如issue,第三个要写一个英文引号引起来的域名"letsencrypt.org",如果是邮箱则是mailto:email@icys.top,连起来则是0 issue "letsencrypt.org",填写在属性值里即可。至于其他的项目,基本按默认填写即可。关于DNSPods配置CAA记录的文档,见CAA记录。 一条记录可以设置一条信息(一个CA或一个网址),我们可以通过创建多条记录来允许更多的CA(创建多条iodef的记录是被允许的,但不知道CA会怎么处理)。 致谢 感谢Ephen的文章SSL 证书颁发机构将对域名强制 CAA 检查,到底什么是 CAA ? CAA 记录详解,Deepzz的文章DNS 一站到家之 CAA 记录的启发,也欢迎大家了解一下这两位的文章。 感谢DNSPods小泽和龙及纯两位朋友的帮助,帮忙排查出证书申请的问题,才有了这一篇文章。

2022/8/2
articleCard.readMore

境内外分离并分离图片源的 Hexo 博客配置

每年寒暑假,我都会去倒腾倒腾博客的搭建问题,上一次的全站加速存在着可能的几个问题: 对于更新的同步来说太慢了,导致修改后还得手动到后台“刷新预热”处清除各部署单元的缓存 全站加速的境内境外分别计费,资源包不互通 在博客访问少的时候,CDN 节点也得回源到 GitHub,还是挺慢的 所以有没有一种方法,对内对外都可以用起来很方便呢?在研究域名解析的负载均衡后,我选择了国内国外分开解析的方法——国内直接解析到自己的服务器,国外解析到 GitHub Pages,就可以了。 一开始觉得,这有什么难的呀,改改解析就完事了,后来发现博客的图包太大了,部署起来费事(因为从 GitHub 克隆仓库,带宽时高时低),再加上服务器是 1M 小水管儿,所以这次我用上了云服务中吹来吹去的对象存储来托管图片的存储(对哦,没有对象存就 new 一个诶)。 顺便在这里提一句,腾讯云的对象存储对于新用户赠送 180 天 50GB 的存储(但是流量费、请求费少不了),但是我看了一下我的免费额度,好像对于我当时那批用户,腾讯云给的额度好像不局限于存储诶,还是永久免费的。庆幸高一的时候,我就已经整起腾讯云这东西了 23333。 对象存储首先需要在云服务商控制台创建桶,设置好权限(记得设置防盗链,以及关闭空 referer 支持),设置好自定义域名(其实是换 cdn 方便,因为到时候只要改解析就好了,不过坏处是要设置 SSL 证书,各有利弊吧)。 由于本站的图片都在/images/目录下,于是一个非常简单的想法就是把这个目录 302 出去。 location /images/ { rewrite ^/(.*) https://imgcdn.icys.top$request_uri redirect; } 因为我也不喜欢存储桶里图片堆在根目录下(不好清理),所以我在存储桶里还是建立了一个images目录,这样在跳转的时候就省事了。 但是国内外如果我都使用国内节点可能带来国外图片速度下降问题,再加上 Pages 也没有 302 支持,于是还得考虑一下国外的图片处理问题。然后我发现,好像我可以选择建一个叫做images的仓库,开启 Pages 后就自然而然的就是icy-blue.github.io/images/(配置 CNAME 之后就是icys.top/images/),自然而然地就可以不用 302 了,真的是方便。 于是,对于图片的处理,可以在本地images目录新建一个仓库与 GitHub 同步,这样本地编辑 markdown 的时候写../images/xxx也能找得到,计划再在images仓库设置Action对新图片自动同步到腾讯云,这样就实现了一个比较优秀的图片加载问题。 对了,刚打算收工,就发现 GitHub 对于 Pages 的更新GitHub Pages: Custom GitHub Actions Workflows (beta)。大概说的是,Pages 的输入可以不是一个分支了,可以直接用 Action 打好的 tar 包去部署,省的像我,先建立一个icy-blog仓库,再通过 Action 生成到icy-blue.github.io仓库,就可以一步到位啦。看看暑假有没有空做,不行等寒假再搞搞~ 另外,之前好像挖了几个坑来着,填填坑—— 使用 GitHub Actions 实现仓库从 GitHub 到 Gitee 的同步:这个 Gitee 好像自己就可以实现,也省的自己写了 使用 Gitee Pages:现在 Gitee 的开源环境还是算了吧,另外 Gitee Pages 是要身份证核验的 做一个合适的负载均衡:境内外的负载均衡可能也算负载均衡吧 使用 Lint-md 让博客内容排版更加规范:这个好像可以简单提一下,用的是llint-md的仓库,用起来也非常轻松,在 Action 部署的时候 npm 安装好,然后把 markdown 文件送到参数里(我用了 shell 里xargs的一个方法使得一行就弄完了,不过注意一下当时我设置的时候项目路径有大小写 bug 所以我用的 Windows 下的 Bash Shell,也许现在 bug 修了罢),最后别忘了创建提交改回去(要在设置里给 Action 写权限) - name: Import lint-md run: | npm update npm npm i -g @lint-md/cli - name: Fix format of markdown sources shell: bash run: | find ./source/ -name "*.md" | xargs lint-md --fix

2022/7/30
articleCard.readMore

【论文阅读】Computational Design of High-level Interlocking Puzzles

这是新加坡科技大学宋鹏老师组的项目,获得了 SIGGRAPH 2022 提名奖,在创新上还是非常不错的,也非常的有趣。 宋鹏老师在一月前还参加了 Games 的Webminar 报告,也是讲述的类似的工作,也欢迎大家去了解一下。 谜题与解组装 这是 B 站 Up 主“GM 的秘密基地”关于“圣剑”谜题的解题动画还原,论文中提到的谜题 Puzzle,其实就是指的这些可以在一步步移动后拆解为一块块的个体的过程。 为了方便读者了解相关背景,在这里先科普一些背景知识(来自于宋老师组在Eurographics 2022上的tutorial)。 关于这种谜题,学术界通常将其与组装 Assembly 归为一类问题,并把解开谜题的问题列为解组装问题 disassembly。组装的话每个物块之间有不同的连接方式,按永久性来讲,分为永久和临时的连接;按接触形式来讲,分为用摩擦力固定的连接和支持力固定的连接;按连接方式来讲,临时的连接还分为内在 internal(结构形状决定)和外在 external(使用非连接部件的第三方部件进行连接)…… 组装问题中,学术界还会去研究两个物块之间接触面的几何特征,来约束物块之间的相对位移(该工作出自 ZIQI WANG 于 2021 年 SIGGRAPH 的MOCCA 论文,通讯也是宋鹏老师)。 当然上面那篇论文更重要的贡献是在结构稳定与平衡方面。论文对输入的物体给出了设计每个块的方式,使得在组装的时候组装比较容易,这个工作非常有意思。 解组装 Disassembly 问题的常见分类 前四个分类是描述组装问题难度的重要指标,后面的论文中我们还会遇到。而自锁 interlocking 是描述一个组装的重要特征,也是一个重要的分类。 顺序性 Sequentiality Maximum number of moving sub-assemblies w.r.t one another in any (dis)assembly operation 个人理解的顺序性指的是每个物块(组)可以从整体中按一个方向取下,不存在需要一次性需要两个物块按照不同方向同时用力才能取出的情况。从图片中我们可以看出来,上方的组合可以用两只手解决,而下方的需要三只手(两只手移动下面两块,一只手用来固定)。 单调性 Monotonicity Need for intermediate placement operations for at least one part of the assembly 个人理解的单调性指的是某块物体的取出需要其他物块的移动,从而在操作顺序上存在了一个偏序关系。从图片中我们可以看到,上面的图片移动蓝色还是绿色都是无阻挡的,而下方的组合需要先把绿色块移走才能把蓝色的块取出来。 线性性 Linearity All assembly operations involve moving a single part with respect to the rest of the assembly 个人理解的线性性指的是组合可以一块块取出。从图片中我们可以看到,上面的图片中蓝色块和绿色块可以独立取出,而下面的需要把蓝绿两块作为整体取出。 相干性 Coherence Whether or not each part that is moved will touch the rest of the assembly 个人理解的相干性指的是每个物块的移除对当前状态是有影响的。从图片中我们可以看到,上面的图片由于是一个整体,某块的移除对当前状态自然是影响的,而下面的图中,移除了绿色块后,自然地形成了左右两部分,左边块的移除自然不影响右边的状态,所以这一块是不相干的。 自锁 Interlocking An assembly is interlocking if only one movable part (key), while all other parts, as well as any subset of the parts, are immobilized 个人理解这里说的自锁描述的是组合可解,而且活动块只有一块,这一块取出后其他块才可以移动取出。从图中我们可以看到,左图中绿色和蓝色都可以直接取出,中间的只有绿色的可以取出,绿色取出钱其他块无法取出,右图中每块都不能正常取出。这也意味着这种结构存在一种稳定性,只要锁住活动块 key,就能保证整个结构是稳定的。 High Level Puzzle 贡献与创新 论文主要有以下几个贡献 给出了难度等级的准确定义,并给出了一个求解每个谜题难度计算的算法(虽然是 NP 完全的 BFS 算法) 给出了用于构造每一个块的迭代计算算法,并让难度维持在输入的难度上,此外还给出了基于已有迭代结果构造更大难度的 puzzle 算法 给出了将非立方体体素的物体进行形状优化,转化为规则体素结构的方法 理论上,pipeline 应该是先把 Mesh 网格进行优化,优化为可以打印的体素表示,再对体素进行分块处理。不过为了与论文同步,我们接下来我们将依次介绍每个贡献。 难度等级与难度计算 那既然叫做 High Level,那怎么去定义一个谜题的 level 呢?论文给出了业界常用的两个计算方法——按第一块取出的最少移动步骤数以及所有块相互分离所需的最小移动步骤数,并选取了前者作为论文所关心的难度指标(毕竟拿掉第一块之后可能后面的块拿出就会简单一些,当然这也确定了论文讨论是满足单调性 Monotonicity 的 puzzle,否则难度就是 1 了)。论文对此进行了详细的描述: 无论一次移动几个块,只要是按照一个方向同时移动,记一次移动 移除某个块记一次移动 一块无论移动多长的距离,记一次移动 而难度计算其实就是一个平凡的 BFS 方法,每一次设置一个状态,以状态和移动的关系构成一张无向图。在图中节点分为根节点(初始状态)、普通节点和目标节点(成功移除一块),而初始状态到目标节点的最短路径的边数正是难度等级数。这里我把论文中的伪代码贴在下方,就不再展开介绍了。 值得注意的是,对于 K 个物块来说,运动超过一半的物块相当于剩下的物块进行移动(运动的相对性),所以在枚举物块数量的时候不需要让单步移动的物块数超过一半$\lceil K / 2 \rceil$。 除了盲目的搜索以外,我们还要考虑到无解的情况,因此论文也给出了一个伪代码来解决问题无解(主要指的是上方 deadlock 的情况)。 谜题构造 如图所示,本节介绍的是迭代生成每个物块的方法。论文对生成的物块有以下的约束: 几何连通性:需要保证每一个物块的体素都是六连通的 大小均匀:需要保证每一块既不是太大又不是太小,设允许误差为$\delta$,总体素数为$M$,物块数为$K$,则约束每个块大小在$[(1-\delta)\lfloor M/K\rfloor],\ (1+\delta)\lfloor M/K\rfloor]$范围内。 块的可移动性:正在设计的这一块是可以移动的 子问题不可解:选择的前一状态是不可解的,否则就变成了并行的问题,难度并没有增加 最终结果可解:不然就设计了个寂寞 其实设计每一块,总的来说就分为设计第一块和从一个状态设计下一块的问题,我们将分别进行展开。 设计第一块 第一块来说是相对麻烦的,我们要设计一块可以移动但是不能直接移除的一块,设计方法如下: 确定一个移动方向,来确定有那些块可以被移动。如图 a 和图 b 所示,当选择向左还是向右时,既要满足块可以移动而且不能直接移除的体素被标记为 S,而阻挡他们按此方向移除的体素被标记为 T。 从适合的体素中随机选一个(通过设置随机种子进行随机),作为块的一个体素。 通过设置阻碍对,保证选出来的块只能沿着选择的移动方向移动(草怎么引用的这篇论文还是宋老师团队的,还是 2012 的 SIG ASIA) 如图,图 a 的红色体素有向上和向左两个移动方向,而我们希望限制其向左移动 我们会选择限制方向的一对体素(图 b 中的任意蓝色圈都可以作为这一对体素)作为阻碍对 让阻碍对目标方向侧的体素作为阻碍体素,让红色体素与另一个体素最短路相连(但不能包含阻碍体素),就像图 c 一样,使得红色块无法向左移动 但是图 c 现在也不能向目标方向移动了,我们则扩展块使其可以向目标方向移动,得到图 e 在对满足上面条件的块进行增补,使得块的大小满足上节的约束条件 设计其他块 我们设计其他块,其实是有意让难度增加(也是子问题不可解),所以我们尽可能地在已有 puzzle 状态中离根节点最远的节点进行扩展,以免难度不变或降低。 其他的与设计第一块是类似的,在设计完所有块后判断一下是否满足输入要求的难度等级,不满足则继续递归求解(所以是一个复杂度特别大的算法)。 提高谜题难度 论文发现直接通过迭代去构造满足比较大难度的谜题,需要的时间成本太高,所以他们分了两步走——先构造低难度再通过调整提高难度。具体操作如下: 选择邻居块相对少的体素 把它加到随机选择的邻居里 计算新难度 如果难度增大则保留修改,否则还原修改 形状优化和体素化 对于一个 Mesh 表达的物体,不是总能无瑕疵地分为体素,如果是对于没有完全填充结构的体素,则可能会导致一些断裂之类的的打印问题。因此如何更好地对形状进行优化,以适合的方法进行体素化,是一个比较重要的问题。所以论文提出希望牺牲一部分的形状精度,通过一些小变形来解决打印问题。 对于一个 Mesh $M$,其中的点集为$V$,面集为$F$。如果用户给定的体素边长为$\mu$,则可以把体素分为三类——填充满的体素、部分填充体素和空体素(如图 a)。而论文定义有问题的体素是部分填充率小于 10%的体素。因此,论文提出优化目标$$\mathop{\min}{\boldsymbol{t}, w, V} E{\mathrm{voxel}(\boldsymbol{t}, w, V) + \lambda E_{\mathrm{shape}(V)}}$$,其中$\boldsymbol{t}$是物体相对于中心点的位移,$w$是等比缩放率,$E_{\mathrm{voxel}}$是问题体素数量,$E_{\mathrm{shape}}$是维持形状的能量,$\lambda$是权重系数,而$E_{\mathrm{shape}}(V)$的计算使用的是尽可能刚性的形状维持能量计算公式。 这个优化问题存在两个问题:$E_{\mathrm{voxel}}$梯度不好求,以及$E_{\mathrm{voxel}}$的参数$t, w, V$范围太大,不可能完全采样。为了解决梯度的问题,论文提出了一个外壳 S,是从原填充满的体素(不含部分填充体素)向外拓展$a \cdot \mu$和$\mu$中间所夹的区域(见图 b 中黄色和绿色线所夹区域),而$E_{\mathrm{voxel}}$则定义为面片到夹层距离$E_{\mathrm{voxel}}(\boldsymbol{t}, w, V)=\sum_{F_i\in F}(\mathrm{dist}(F_i)(\boldsymbol{t}, w, V))$,通过这样的方式来细化梯度的求解,使得梯度方向为目标优化方向。而范围问题,论文选择了两阶段法进行考虑——先固定$V$,对于$\boldsymbol{t}, w$的四个自由度进行随机采样,然后固定$\boldsymbol{t}, w$,使用 L-BFGS 方法优化 V。 工作的效果 这是论文工作的效果,上方是体素表示,下方是实物展示。此外论文给出一个表格来表现工作的情况(见下表),第三列表示是否为光滑表面(需要使用形状优化算法),第四列为体素化的分辨率,后边的列分别为孔洞体素(为了游戏块可以移动设计的,后面还会提)数$E$,谜题块数$K$,难度等级$L$,在第一个贡献中的无向图里计算出来的状态数$G_N$、边数$G_E$、目标状态数$G_T$(目标状态数越多表示解开谜题的方法越多),是否二次修改难度$\mathrm{Modify}$,以及程序计算(不含形状优化)的时间$\mathrm{Time}$。 此外,论文与 2020 年的工作相比,同样都是对于立方体进行谜题设计,他们就可以生成更高难度的谜题。 下面的是他们的一些结果,其中左图表示在$K$块、难度为$L$的谜题中,程序计算的时间,右图是实际结果的展示。 此外,论文还展示了其中一个边长为 6 的立方体,解开第一块需要 27 步,其中每一步的移动如图所示。 尾记 年初看到学长在讨论班里讲宋老师去年 SIGGRAPH 那篇平衡性的论文,于是这次就用了些时间来跟了一下宋老师的工作。当我运行代码,发现 run 不起来的时候,还给作者陈学长发了一封邮件。其实也是第一次发邮件来请教论文的问题,英文的邮件打磨了好久,最后收到了“加个微信吧,这样交流起来方便”的中文回答,还是感觉学长蛮实在的,非常的意外 2333。 其实这个工作还是很不错的,美中不足的地方是,论文其实并没有提到如何选择谜题中孔洞体素的选择方法,也没有对孔洞数量对设计难度的影响进行定量的分析。此外论文给出的设计问题的复杂度是$O(K^N\cdot N^{2K})$,也能看出来是个 NP 问题,其中$K$是块数,$N$是实心体素数。这意味着论文给的方法基本上只能解决$K \le 8$且$N \le 1000$的输入,这个输入规模还是非常有限的。 没想到,从 2012 的那篇 SIG ASIA 看出,宋老师的课题组已经在这个项目耕耘十余年了,对于喜欢新问题的 SIGGRAPH 来说,每篇论文对他们来说都是一个挑战。祝宋老师的课题组做得越来越好,也期待之后能与他们有合作 qwq!

2022/7/18
articleCard.readMore

论文翻译——MeshCNN

论文翻译——MeshCNN: A Network with an Edge 这是 CAD 五人组(好吧实际上四个人)完成的论文翻译,原论文 MeshCNN: A Network with an Edge,感谢 juraws, Gwyn, tk 三位朋友的一同协作。 摘要 多边形网格为三维形状提供了一种有效的表示方法。它们显式地捕获形状的表面和拓扑情况,并利用网格的非均匀性来表示大形平坦区域以及尖锐、复杂的特征共存的情况。然而,这种不均匀性和不规则性会阻碍使用结合卷积和池化运算的神经网络进行网格分析。在本文中,我们使用 MeshCNN,一个专门为三角形网格设计的卷积神经网络,直接通过网格的独特性质来分析 3D 形状。类似于经典的卷积神经网络,MeshCNN 使用了专门处理网格边的卷积层和池化层,具体将通过利用网格固有的测地线连接来完成。MeshCNN 对边及其 4 条邻边应用卷积,并通过保留表面拓扑的边折叠操作应用池化,从而为后续卷积生成新的网格连接 MeshCNN 学习要折叠哪些边,从而形成一个任务驱动的过程,在这个过程中,网络逐渐暴露并扩展重要的特征,同时丢弃冗余的特征。我们展示了我们的任务驱动池化操作在各种 3D 网格学习任务上应用的有效性。 介绍 三维形状是计算机图形学领域的前沿和中心,也是计算机视觉和计算几何等相关领域的主要研究点。我们周围的形状,尤其是描述自然实体的形状,通常由连续曲面组成。 出于计算的原因,同时为了便于数据处理,已经提出了各种三维形状的离散近似方法,并用于在一系列应用中表示形状。多边形网格表示(简称网格)是许多人的最爱,它通过三维空间中的一组二维多边形来近似曲面。网格提供了高效、非均匀的形状表示。一方面,只需要少量的多边形就可以描述形状大而简单的表面,另一方面,网格灵活的表示支持可能需要的高分辨率,以便支持真实感重建及表现在几何上复杂的显著形状特征。网格的另一个显著特征是它可以自然地提供面片之间的接信息。这形成了下垫面的综合表示。 与另一个流行选项(点云表示)相比,这些优势显而易见。尽管点云表示法简单且与常用的数据采集技术(扫描)直接相关,但当需要更高的质量和保留锐利的形状特征时,点云表示法仍存在不足。 近年来,在图像上使用卷积神经网络(CNN)在分类和语义分割等多种任务上表现出了优异的性能。他们成功的秘诀在于卷积层、非线性激活函数和池化层的结合,从而形成一个对输入的无关变化保持不变(或鲁棒性)的框架。然而,由于图像是在离散值的规则晶格上表示的,将 CNN 扩展到不规则结构上是不容易的。 最初的方法通过使用规则的表示,来绕过适配对于不规则数据的 CNN:将 3D 形状映射到多个 2D 投影或 3D 体素晶格。虽然这些方法受益于直接使用理解良好的图像 CNN 操作符,但它们的间接表示需要大量的内存和浪费或冗余的 CNN 计算。 更有效的方法是直接将 CNN 应用于不规则和稀疏的点云表示。虽然这些方法得益于紧凑的输入表示,但它们本质上对局部曲面不敏感。此外,邻域和连通性的概念定义不明确,使得应用卷积和池化运算变得困难。这种模糊性带来了一系列的工作来克服这一挑战。 为了激发原生的网格表示的自然潜力,我们提出了 MeshCNN:一种类似于著名 CNN,但专门为网格设计的神经网络。MeshCNN 直接对三角形网格进行操作,执行卷积和池化运算,这些操作与独特的网格属性相协调。在 MeshCNN 中,网格的边类似于图像中的像素,因为它们是应用所有操作的基本对象。我们选择使用边,因为每条边正好与两个面(三角形)关联,这定义了四条边的自然的固定大小的卷积邻域(见图 2)。我们利用一致的表面法线顺序应用非对称卷积运算,学习与位置、旋转、缩放无关的边的特征。 MeshCNN 的一个关键特征是独特的池化操作,即网格池化操作,该操作在不规则结构上运行,并在空间上适应 CNN 中的任务,池化减少了网络中特征的数量,从而学会消除信息量较小的特征。由于特征位于边,下采样的直观方法是使用著名的网格简化技术边折叠。但是,与传统的边折叠不同,传统的边折叠会删除引入最小几何变形的边,网格池化将选择要折叠的边以特定于任务的方式交给网络。删除的边是特征对所用目标贡献最小的边(参见图 1 和图 8 中的示例)。 为了增加灵活性并支持各种可用数据,每个池化层将网格简化为预定的恒定边数。此外,尽管 MeshCNN 生成某个特定数量边的输出,但它对输入网格大小没有限制,也能处理不同的三角剖分。如图 1 所示,中间计算池化步骤以及最终输出在语义上是可解释的。为了说明我们的方法的能力,我们在形状分类和分割任务上进行了各种实验,并在常见数据集和高度非均匀网格上证明了优于最新方法的结果。 相关工作 我们在工作中提出或使用的许多算子都基于经典网格处理技术,或者更具体地说,基于网格简化技术。特别是,我们使用用于任务驱动池化算子的边折叠技术。不同于经典的网格简化技术旨在以最小的几何失真减少网格元素的数量,在这项工作中,我们使用网格简化技术来降低神经网络背景下特征图的分辨率。 在下文中,我们将回顾使用神经网络进行 3D 数据分析的相关工作,这些神经网络按照输入表示类型进行组织。 我们在工作中展示或使用的许多操作都是基于经典的网格处理技术[Hoppe 于 1999 年提出;Rusinkiewicz 和 Levoy 等人于 2000 年提出;Botsch 等人于 2010 提出;Kalogerakis 等人于 2010 提出],更具体地说,网格简化技术[Hoppe 等人于 1993 提出;land 和 Heckbert 等人于 1997 年提出;Hoppe 于 1997 年提出]。特别地,我们在我们的任务驱动池化操作符中使用了边折叠技术[Hoppe 于 1997 年提出]。而经典的网格简化技术旨在以最小的几何变形减少网格元素的数量[Tarini 等人于 2010 年提出;Gao 等人于 2017 年提出],在这项工作中,我们使用网格简化技术来降低神经网络背景下特征映射的分辨率。在接下来的文章中,我们将回顾使用根据输入表示类型组织的神经网络进行 3D 数据分析的相关工作。 多视角 2D 投影。通过不同视角的 2D 投影来表示 3D 形状,使得利用 2D 领域的现有技术和架构成为可能。这些渲染后的图像作为标准 CNN 模型后续处理的输入。Su 等人[2015]是第一个应用多视图卷积神经网络进行形状分类的,但是这种方法不能很好地进行分割任务。后来,Kalogerakis 等人在 2017 年提出了一种更全面的多视图框架用于形状分割:生成每个视图的图像级分割地图,然后使用 CRF(端到端训练)方式解决标签一致性问题。Qi 等人[2016]探索了基于视图的方法和基于体积的方法,并观察到与当时可用的方法相比,第一种方法存在优越性。 体素。将 3D 形状转换为二进制体素形式提供了类似于图像的 2D 晶格的基于晶格的表示。因此,应用于 2D 晶格的操作可以以一种直接的方式扩展到 3D 晶格,从而允许常见的基于图像的方法自然转移到 3D。Wu 等人[2015]率先提出了这一概念,并提出了一种处理体素化形状进行分类和补全的卷积神经网络。随后,Brock 等人[2016]使用基于体素的变分自编码器进行形状重建,[Tchapmi 等人于 2017 提出]将三线性插值和条件随机场(CRF)与体积网络相结合,以促进语义形状分割。Hanocka 等人[2018]使用体积形状表示训练网络回归基于晶格的翘曲场以进行形状对齐,并将估计的变形应用于原始晶格。 尽管它们的表示非常简单,但体积表示需要高要求的计算,以及大量内存使用。为了缓解这一问题,人们提出了几种加速策略,其中包含利用实心体素的稀疏性来减少特征的策略。 图。允许基于晶格的不规则表示的一个常见表达即为图结构。为了支持基于图的数据分析,神经网络在涉及以图表示的数据的热门任务中的应用受到了相当大的关注,尤其是在社交网络、通信中的传感器网络或遗传数据。一种方法提倡处理拉普拉斯图表示 [Bruna 等人于 2014 年提出; Henaff 等人于 2015 年提出; Defferrard 等人于 2016 年提出; Kostrikov 等人于 2018 年提出],因此在频域中起作用。另一种方法选择直接处理图,通过提取局部连接区域,并将其转换为标准形式,Niepert 等人在 2016 提出由神经网络处理。Atwood 等人[2016]提出扩散-卷积,在每个节点上应用扩散来确定其局部邻域。Monti 等人[2017]利用图空间域将曲面参数化为局部斑块。Xu 等人[2017]使用曲面斑块的方向卷积进行语义分割。Yi 等人[2017]在三维分割任务中使用频域的图卷积。Kostrikov 等人[2018]使用拉普拉斯曲面网络开发三维形状的生成模型。Such 等人[2017]引入了图上顶点过滤的概念,但没有纳入用于特征聚合的池化操作,这些方法通常是对图的顶点进行操作。 流形簇。Masci 等人[2015]的开创性工作引入了网格上局部特征的深度学习(与[Kokkinos 等人 2012]中的内固有网格描述符类似),并展示了如何进行深度学习,使用这些学习到的特征进行通信和检索。具体来说,它们演示了如何使卷积操作成为网格固有的操作。 通常,流形簇上的局部块近似满足欧几里得性质。通过将三维流形参数化至二维,这一特性可以用于使用标准神经网络卷积进行流形分析 [Henaff 等人于 2015 年提出; Boscaini 等人于 2016 年提出; Sinha 等人于 2016 年提出;Maron 等人于 2017 年提出; Ezuz 等人于 2017 年提出]。如 Boscaini 等人在[2015]提出的那样使用顶点频率分析来学习局部固有三维形状描述符。另一种方法使用环面拓扑来定义形状图上的卷积 [Haim 等人于 2018 年提出; Maron 等人于 2017 年提出]。Poulenard 等人在 2018 年定义了一种新的卷积层,允许在网络的各个层传播测地线信息。 Verma 等人在 2018 年提出了一种图神经网络,其中卷积操作的每个顶点的邻域不是预定义,而是基于其特征动态计算的。Tatarchenko 等人[2018]引入了切线卷积,在每个点周围使用一个小的邻域来重建应用卷积的局部函数。与之前的作品不同,他们通过在 3D 晶格上进行子采样来合并池化操作。一些生成模型也被提出。Litany 等人[2018]介绍了一种执行形状补全的自动编码器。Ranjan 等人在 2018 演示了如何通过网格自动编码器生成 3D 人脸。 查阅[Bronstein 等人于 2017 年提出]关于几何深度学习的综述。与之前的方法相比,我们方法的独特性在于,我们的网络操作经过了特殊的设计,能适应网格结构。特别地,我们学习了一个唯一的池化操作符,它根据目标任务选择要简化的区域。 据我们所知,这是第一个同时满足(i)在网格的边上进行卷积和(ii)一个经过学习以适应手头的任务的网格池化操作。在[Ranjan 等人 2018]中,为网格自动编码器提出了一种固定的池化操作。学习池化操作已经在图神经网络的背景下被提出[Ying 等人 2018;Cangea 等人 2018]。然而,这些操作没有考虑到三角形网格的独特性质。 有人提出了一种利用对偶图卷积模型来提取边特征的卷积[Monti 等人在 2018 年提出],该模型扩展了图关注网络[Velickovic 等人在 2018 年提出]。然而,他们在工作中所使用的注意力和优化机制与我们截然不同;在这项工作中,我们定义了运算符的网格,利用其独特的结构和性质。这使得我们可以定义一个对称卷积,从而得到不变的网络特征。 点云:点云表示法可以说是所有 3D 数据表示法中最简单的一种,它为底层的 3D 形状提供了一个简单的近似值。它能与数据获取密切关系并能与其他表示法进行轻松转换,这使得点云表示法成为数据分析的经典候选。因此,近期研究方向集中于开发使用神经网络分析点云形状的技术。如 PointNet[Qi 等人在 2017 年提出]建议使用 1x1 卷积,然后通过全局最大池化以实现顺序不变。在其基础上又研究了 PointNet++ [Qi 等人在 2017 年提出],以划分点集的方式更好地捕获局部结构特征。[Wang 等人在 2018 年提出]考虑局部点邻域信息,基于特征空间中点的距离进行相似性计算驱动的动态更新。虽然大多数基于点的方法关注全局或中间属性,[Guerrero 等人于 2018 年]提出了一个估计局部形状属性的网络,其关注点在于原始点云的法线和曲率;Williams 等人[2018]从点学习从表面重建的几何先验;而 Atzmon 等人[2018]通过将点云函数映射为体积函数,定义了一种有效的点云卷积算子。这使得该方法对于点的顺序来说具有不变性,对数据中的一些变形具有鲁棒性。最近,Li 等人[2018]提出了 PointCNN,它将卷积的概念从局部晶格扩展到欧几里得领域中驻留点的χ-卷积。 与以往的研究不同,在这项工作中,我们依靠多边形网格边来提供非均匀的测地线邻域信息和拥有统一数量的卷积邻域。在多边形网格边上执行特征不变计算,并应用网格精简技术,如符合形状几何及拓扑结构进行抽取的边折叠技术。 概述:将卷积操作应用到网格上 计算机图形学中最基本、最常用的 3D 数据表达方式为非均匀多边形网格,这种表达方式在大的较为平坦的区域采用少量大型多边形,而在需要体现细节的区域采用大量多边形。一个非均匀多边形网格能很好地体现物体曲面的拓扑结构,如图 3 所示,它在完美体现结构细节的同时又能够消除邻域曲面的歧义。 为了实现将卷积操作应用到三角形网格的目标,需要设计一种类似于传统卷积定义与实现的标准化构建模块:卷积层和池化层。对比于在晶格上用离散值表示的图像,非均匀多边形网格分析上的关键挑战为其固有的不规则性和不均匀性。在这项工作中,我们的目标是运用这些具有挑战性的独特性质,而不是绕过它们。出于上述原因,我们在设计网络时有意直接在非均匀多边形网格上应用卷积和池化操作,从而避免将非均匀多边形网络转化为规则统一的表示。 卷积不变性: 我们假设,所有的图形都被表示为了可能有边界的非均匀多边形网格。这样的假设保证了每条边与 1 到 2 个三角形面相连,因此每条边会与 2 或 4 条边相邻,每个三角形面的顶点以逆时针的顺序排列,则对于每条边的 4 条邻边存在 2 种可能的排序,例如在图 4 中,边 e 的 4 条邻边就可以被排成(a, b, c, d) 或者 (c, d, a, b) , 这种存在歧义性的表示方法对卷积不变性造成了阻碍。 为了保证网格内相似性变换(平移、旋转、缩放)对于网络的卷积不变性,我们采取了两种行动来解决这个问题。首先,我们仔细设计了基于边的输入描述,使得它只包含对相似变换具有不变性的相对的几何特征。其次,我们将 4 条邻边分成 2 对具有模糊性特征的边对(如图 5 中的 a 与 c、b 与 d),并且在新的边对基础上应用简单的具有对称性的变换函数(如求和操作)生成新的特征。卷积操作将应用在新生成的特征上以消除输入顺序带来的歧义。 输入特征:每条边的输入特征在形式上是一个 5 维向量:二面角、2 个内角和 2 个三角形面各自的边比值。其中每个三角形面的边比值为中间边边长与每个三角形面垂线(图中虚线)的比值。我们将这些特征按一定顺序(每个面的内角值紧接着边比值)排列来消除歧义从而保证卷积不变性。由于这些特征都是相对的,对网格作相似变换如旋转、等比缩放等操作并不会影响到它们的不变性。 全局顺序:边的全局顺序是特定形状的边的数据进入网络的顺序。由于卷积操作是在局部邻域内完成的,上述顺序对卷积不会造成影响。更一般地,需要完整卷积的任务例如分割任务也不会受此影响。对于需要全局特征聚合的任务,例如分类任务,我们按照 Qi 等人在 PointNet 中建议的那样,在网络中的卷积层和全连接层中间添加一层全局平均池化层,这一层使得初始输入顺序与特征聚合无关从而保证了变换的不变性。 池化:网格的池化由边折叠完成,如图 2 中的(b)和(c)的说明,在(b)中虚线的边被折叠成了一个点,随后,4 条蓝色的边被折叠成了(c)中 2 条蓝色的边,注意在边折叠操作中,原来的 5 条边变换成了 2 条边。操作按边的特征优先级(最小范数)进行排序,从而允许网络选择哪部分网格简化、哪部分保留,这创建了一个任务感知过程,在此过程中,网络可以通过学习确定每部分物体对于任务的重要性(如图 1)。 这种简化的一个天然而显著的优点在于它能够在到达最终的全连接层之前,为池化层提供输出维度上的灵活性。池化操作也有助于对初始三角形网格的稳定性作贡献。虽然它并不提供三角形的不变性,但是在不同初始条件下,通过不断地对边进行折叠和简化,我们最终总能观察到网络收敛到相似的表达。 具体方法 基于晶格的表达(如传统图片)可以通过一个单一矩阵提供邻域的信息以及本身特征的信息。然而,网格不符合这样的格式,我们必须将其本身的特征和它的连通性分开定义。我们将通过使用标准的网格结构来完成上述工作。 一个网格由一组($V$, $F$)定义,其中$V= { \mathbf{v}_1, \mathbf{v}_2 \cdots }$为三维立体空间中的点集,$F$通过给出三角形网格面的三元组定义了连通性。在给出($V$, $F$)后,网格的连通性同时采用一组两两连接的点对形成的边集合$F$来定义。 所有的网格元素$V$, $F$, $E$可以被关联到多种多样的特征(例如法线或颜色)。在上述工作中,$E$同样包含了大量的特征信息。边的特征刚开始为一组相似但独立的几何特征(与图片的 RGB 值类似),它们通过网络层后将变得更加抽象。 在我们的设定中,不规则多边形网格为网络提供了两个特征:相邻卷积元素的连通性以及初始的几何输入特征。当这些输入特征被提取后,网格顶点的具体位置就失去了意义。随着边折叠操作而产生的新顶点的位置对分类和分割任务没有任何影响,计算它们只是为了满足可视化的需求。 在接下来的内容中,我们将进一步提供关于网格卷积、网格池化和网格反池化操作的细节。 网格卷积 我们为边定义卷积操作,其中每条边的空间信息是通过它的 4 条邻边定义的(如图 3 所示)。回想一下,传统卷积是卷积核 k 与一个邻域的点积,类似地,网格卷积基于一条边 e 以及它的 4 条邻边的操作为: $$\begin{equation} e \cdot k_0 + \sum\limits_{j=1}^{4} k_j \cdot e^j, \end{equation}$$ 其中$e^j$即为$e$的第$j$条卷积邻边。注意如图 4 中展示的那样,$e$的 4 条邻边的顺序,即!,$(e^1,e^2,e^3,e^4)$不是就$(a,b,c,d)$是$(c,d,a,b)$, 这样会使得每个滤值的操作对象可能对应到最多 2 条不同的边上(如$k_1$的操作对象可能为$a$或$c$)。为了保证卷积对于输入数据不同顺序的不变性,我们将在存在歧义的边对上应用简单对称函数。上述操作产生了一组能够保证卷积不变性的新的卷积邻域,在我们的设定中,边$e$的邻域为: $$\begin{equation} (e^1,e^2,e^3,e^4) = (|a-c|, a+c, |b-d|, b+d). \end{equation}$$ 显然,不论初始的网格元素的输入顺序是什么,卷积操作都会给出相同的输出。回想一下,在传统卷积中多通道张量与一个卷积核的操作可以通过将图片数据展成列矩阵然后执行一般的矩阵乘法来实现。类似地,我们可以为网格卷积构造一个展开矩阵来提高卷积操作的效率。 在实际应用中,我们可以通过将所有边特征聚合成$n_c \times n_e \times 5$格式的特征张量以使用高度优化的批处理操作(如二维卷积),其中是$n_e$边的数量,$n_c$是特征通道的数量,$5$是包含边$e$本身以及它的卷积邻域特征值信息(见式 2)的数量。这个矩阵以标准一般矩阵乘法的方式乘以权重矩阵。 在卷积操作之后,一个新的批处理特征张量将被生成,其中新的特征数量等于卷积核的数量(类似在传统图像上的卷积)。注意在每个池化阶段之后,下一次卷积操作的卷积邻域是在新的连接基础上定义的。 网格池化 为了将池化操作扩展到不规则的数据上,我们需要明确池化操作的三个基本步骤: 定义池化邻域; 合并每个池化邻域的特征信息; 重新定义合并特征后的池化邻域。 对于传统图片的池化来说,邻域是暗含的,因此每个池化邻域在确定了卷积核的大小后就被直接确定了。因为不同区域内的特征被合并(如通过平均或取最大值的方式合并)会产生另一个新的晶格,这种方式同时暗含确定了新的邻域。结合上文定义的池化操作的三个基本步骤,传统图片池化操作显然是广义池化操作的一种特殊情况。 网格池化是广义池化的另一种特殊情况,其连通性由拓扑序决定。不像图片池化具有天然的简化换算方式,例如需要简化系数为 4 自然对应$2 \times 2$池化,我们将网格的池化定义为一系列的边折叠操作,在每个边折叠操作中我们将 5 条边转换为 2 条边。因此,我们可以添加一个超参数,表示池化后网格边的数量,从而在每个网格池化操作之后控制所需的网格分辨率。在实际运行时,提取网格邻接信息需要不断查询连续更新的特殊数据结构。 我们将根据边特征信息的重要性为边折叠顺序定义优先级以帮助网络确定哪部分网格与解决任务的关联性更强(采用优先队列)。这使得网络可以不均匀地折叠对损失影响最小的特定区域。回想一下前面定义的折叠两个相邻面中间的边的操作,由于该操作将每个面都变成了一条边,从结果上来看是删除 3 条边(见图 2)。每一个三角形网格面含有 3 条边:两个面相交的中间边以及 2 条中间边的邻边(如图 2,中间边被标成了红色,它的邻边被标成了蓝色)。三条边中的所有特征都以均值的方式被合并到了新边的特征通道中。 根据边特征的强度对边折叠顺序进行优先级排序,并将其作为边折叠的 L2 范式。特征的聚合过程在图 5 中有详细解释,这里有两个合并操作,对于每个输入的三角形网格表面的边特征,操作的结果为两个新的特征向量(用 p 和 q 表示)。更形式化地,第 i 个通道中两个三角形网格面的边特征可以表示为: $$\begin{equation} p_i = avg (a_i, b_i, e_i), \textrm{ and, } q_i = avg (c_i, d_i, e_i), \end{equation}$$ 在一系列边折叠操作的同时,数据结构也随之更新。 最后需要注意的是,不是每条边都可以被折叠。在我们的设定中,一条处于非流形网格面的边是不允许被折叠的,因为这会违反每条边有 4 条邻边的前提假设。因此,一条边如果含有 3 条邻边或者它的 2 个顶点都是边界顶点,则不允许被折叠。 网格上池化 上池化是池化的(部分)逆操作。池化层降低了特征激活的分辨率(对信息进行编码或压缩),而上池化层增加了特征激活的分辨率(对信息进行解码或解压)。池化操作记录了每次历史合并操作(例如最大位置),并使用它们来扩展特征激活。因此,单独的上池化操作不具有可学习参数,它通常与卷积操作结合起来以解析恢复在池化操作中丢失的原始特征信息。与卷积操作的有效结合使上池化成为一种可学习的操作。 每个网格上池化层都匹配有一个网格池化层以上采样网格拓扑和边的特征。上池化层通过存储池化操作之前的连接来恢复上采样拓扑(在网格池化之前)。注意,对连接进行上采样是一个可逆的操作(就像在传统图像上那样)。对于上池化中的边特征计算,我们保留一个存储了从原始边(池化前)到新边(池化后)的邻接表。每个上池化边的特征都是池化边特征的加权组合。图 5 即为一个平均上池化操作的例子。 实验 MeshCNN 是一种在三角网格上直接应用卷积的方法,它具有许多应用。结合在第 4 节中提到的 MeshCNN 标准化构建模块,我们可以构建不同的网络以解决不同的任务。与传统的卷积神经网络一样,这些构建模块提供了即插即用的框架。为了提高计算效率,在池化操作中,每个池化操作只对特征进行一次聚合。而边的排序和折叠是按顺序进行的,这种松弛使得可以在 GPU 上进行特征聚合操作,从而提高计算效率。 接下来,我们将展示 MeshCNN 在分类和分割任务上的表现。所使用的网络架构细节将在附录 A 中给出。 数据处理 在所有集合中,我们将每个网格简化为数量大致相同的边。注意,如前所述,MeshCNN 并不要求输入的边数相同。然而,与卷积神经网络中调整图像初始大小的原因类似,几何网格抽取有助于降低输入分辨率,从而降低训练网络所需的内存容量。由于分类任务是对全局形状描述进行学习,相比于分割任务(2250 条边左右),分类任务通常使用较低的分辨率(750 条边左右)。 数据扩充。为了为网络生成更多的数据样本,存在几种数据扩充方式。注意,由于我们的输入特征具有相似不变性,应用旋转、平移和各向同性缩放($x$, $y$,$z$轴相同)不会产生新的输入特征。然而,我们可以通过对$x$, $y$和$z$中的顶点位置$<S_x,S_y,S_z>$应用各向异性缩放(使得每一个值都来自于服从$\mu=1$和 $\sigma=0.1$正态分布的随机抽样)来生成新的特征;我们可以将顶点转移到同一个网格曲面的不同位置;我们还可以通过执行随机的边翻转来增加每个对象的细分。另外,由于输入分辨率非常灵活,我们可以在训练前随机折叠数量不多的一组边。 网格的分类 SHREC:我们对 SHREC 数据集中的$30$个类进行了分类[Lian 等人在 2011 年提出],每个类有$20$个数据。我们参照[Ezuz 等人在 2017 年提出]中的设置方式,其中分为两组,训练测试数据比为$1:1$(Split $10$)和$4:1$(Split $16$)。我们在$200$个 epoch 后停止训练。因为我们没有像[2017]中使用精确分割,我们在$3$个随机生成的$4:1$和 1:1 组取平均结果,结果见表 1。为了进行比较,我们直接从[2017]获得其他结构的评估结果,与 SG [Bronstein 等人在 2011 年提出] (bof 表示)、SN [Wu 等人在 2015 年提出] (体积 CNN)、GI [Sinha 等人在 2016 提出] (固定几何图像上的 CNN)和 GWCNN [2017](学习几何图像的 CNN)进行比较。我们的方法的优点是显而易见的。我们在图 6 中可视化了这个数据集的网格池化简化示例。我们观察到网格池化的表现具有一致的语义方式(参见图 11)。 Cube 数据集。为了说明 MeshCNN 的独特功能,我们建了一组图标浅雕刻的立方体模型(见图 7)。我们使用 MPEG-7 二进制形状[Latecki 和 Lakamper 2000]数据集中的 23 个类,每个类大约有$20$个图标。我们每类为测试集各留出三个图标,其余的用于训练。对于每个图标,我们随机抽取$10$个不同的位置(坐标,旋转及立方体的某个面)来雕刻图标。每个立方体大约有$500$个面片,这意味着精细模型在平面区域中有更少的三角形,而不精细的模型在平面区域中有更多的三角形。这个集合包含了总共$4600$个模型,其中训练集$3910$个,测试集$690$个。我们计划在论文发表之后公开这个数据集以及数据生成代码。 我们训练 MeshCNN 对立方体进行分类。我们在表 2 中展示了定量结果。为了可视化网格池化对分类任务的影响,我们提取了每次网格池化操作后的中间结果(如图 8 所示)。观察 MeshCNN 如何学会减少与分类任务无关的边(平面立方体表面),同时保留图标雕刻内部和周围的边。 我们还在这个数据集上训练了基于点的方法,结果如表 2 所示。虽然该例会被认为是不自然的,这是为了强调 MeshCNN 擅长在几何分辨率方差较大的 3D 模型集合。 网格分割 MeshCNN 的另一个应用是一致的形状分割,这是形状分析和合成中许多应用的一个重要构件。我们使用监督学习来训练 MeshCNN,以预测每条边属于 COSEG 和人体分割数据集上的特定段的概率。由于这两个数据集都提供了每个表面的真实分割,我们根据原始分辨率的标签在简化的网格上生成边级的语义标签。 最直接的 MeshCNN 语义分割配置是使用一连串的网格卷积层(以及归一化和非线性激活函数)。然而,加入网格池化使 MeshCNN 能够学习分割驱动的边折叠。考虑到网格池降低了输入网格的分辨率,这不再符合边级别的真实标签。为此,我们使用网格上池化层上采样将分辨率提高到原来的输入尺寸。 COSEG。我们评估了 MeshCNN 在 COSEG 数据集的分割任务上的表现。该数据集包含三个大型集合: 外星人,花瓶和椅子,各包含$200$、$300$和$400$个模型。我们将每个形状类别分成$85 % / 15 %$的训练集/测试集。我们与 PointNet、PointNet++和 PointCNN 进行了比较。在表 3 中报告了所有方法的最佳准确性。我们的技术 在这个数据集上取得了比所有其他方法更好的结果。 我们认为,这是因为我们的网络是根据网格结构定制的,这使它比其他策略更有优势。为了进一步证明这一点,我们还报告了随机集合(随机抽取塌陷边)并且表明这一变化降低了网络的性能。此外,在一个测试集中使用池化和上池化层的 MeshCNN 语义分割网络最终的分割预测如图 9 所示。这也体现了所进行的池化是如何适应目标问题的。 人体分割。我们在[Maron 等人]提出的人体分割数据集上评估了我们的方法。该数据集包括来自 SCAPE[Anguelov 等人]、FAUST[Bogo 等人]、MIT[Vlasic 等人]和 Adobe Fuse[Adobe ]的$370$个训练模型,测试集是来自 SHREC07[Giorgi 等人](人类)数据集的$18$个模型。根据[Kalogerakis 等人,2010]中的标签,这些模型被手动分割成八个标签。最近,[Poulenard 和 Ovsjanikov ]报告了他们的方法在这个数据集上的结果,并与之进行了比较 (GCNN [Masci 等人于 2015 年提出]、PointNet++ [Qi 等人,2017b]、Dynamic 图 CNN[Wang 等人,2018b]和 Toric Cover[Meron 等人,2017]。 我们直接从[Poulenard 和 Ovsjanikov 2018]获得结果,并将其列于表 4。我们在表中加入了最近由 Haim 等人[2018]报告的最先进的结果。在这种情况下,MeshCNN 也比其他的方法(部分是基于图/多方面的,部分是基于点的)有优势,我们认为这是由于 MeshCNN 对网格结构及任务的适应性。图 10 展示了 一些 MeshCNN 的定性结果。 附加评估 计算时间:当使用 GTX $1080$ Ti 显卡对$2250 / 750$个边进行分割/分类训练时,我们的非优化 PyTorch[Paszke 等人,2017]实现每个示例平均需要$0.21 / 0.13$秒。 曲面细分的鲁棒性:我们使用 COSEG 分割数据集,通过几个定性和定量实验,检验了我们的方法对三角剖分差异的鲁棒性。为此,我们生成了数据集的两个修改版本。第一种是通过应用重新网格化程序(使用 Blender 和 MeshLab)获得的,第二种是通过随机扰动$30%$的顶点位置获得的,使得这些点及所有与这些点直接相邻的顶点随机增加向量。 性能上的微小差异(见表 5)意味着对细分变化的弹性。定性结果见图 12。 不变特征:使用相对特征的一个值得注意的优点是,MeshCNN 保证对旋转、平移和均匀缩放保持不变。从本质上讲,常用的笛卡尔坐标对刚性变换很敏感。为了说明这一点,我们对 MeshCNN 进行了语义分割训练:(i)使用不变几何特征,(ii)使用边的中点$(x,y,z)$作为输入特征。为了评估学习泛化,我们沿纵轴应用非等比缩放(无需对这些类型的增强进行训练)。我们的相对几何特征达到$98.44%$,而标准测试集为$99.63%$,而绝对坐标下降到$78.27%$,而标准测试集为$99.11%$。请注意,虽然我们的几何特征对非均匀缩放不是不变性的,但由于它们对定位不敏感,因此可以更好地概括。 讨论和未来的工作 我们提出了 MeshCNN,这是一种在不规则三角形网格上直接使用神经网络的通用方法。我们工作的主要贡献是针对不规则和非均匀结构定义和应用卷积和池化操作。这些操作有助于直接分析那些原始表现形式为网格的形状,也因此受益于具有非均匀结构的曲面流形表示的独特属性。 不变卷积:选择网格边作为网络运行的基本构建块是非常重要的,因为边集有一种简单的方法,来定义局部固定大小的邻域,以便在不规则结构上进行卷积。通过利用三角形网格特有的唯一对称性,我们消除了邻域排序对偶性的歧义,以实现对变换的不变性。我们通过选择输入边特征来完成这一点。这些特征经过精心设计,仅包含相对几何特性,而不是绝对位置。因此,与常见表示(例如基于点的表示)不同,顶点的笛卡尔坐标被忽略,局部和非局部特征不受位置影响,从而更好地概括形状特征,并促进对相似性变换的不变性。我们强调,我们仅使用顶点位置来显示演化网格,但它们的位置对任务没有影响。 空间适应池化:我们开发了一种通过边折叠执行的池化操作,该操作基于学习过的边特征,导致任务驱动池化由网络损失函数引导。在未来,我们希望添加一组专用的单独功能,用于优先处理边折叠,类似于注意力模型。将网络确定的一系列特征可视化是很重要的,这导向了对网络实际学习内容的深刻见解。我们观察到,与使用绝对笛卡尔坐标相比,我们的微分特征不仅提供了对相似变换的不变性,而且还抑制了过度拟合。通过在不同对象之间执行语义相似的池化的能力,网络的泛化功能被进一步证明,这自然会产生更好的结果。研究这种强大的机制可以更好地理解神经网络的行为。 我们认为这种空间自适应的不规则任务驱动池化是一种重要的贡献,可能还会影响许多基于图像的 CNN 任务。例如,高分辨率图像分割通常会生成低分辨率的分割图并对其进行上采样,这一过程可能会跳过连接。MeshCNN 中的池化在语义上简化了具有统一特征的区域,同时保留了复杂的区域;因此,在未来,我们有兴趣将类似的不规则池化应用于图像分割任务,以获得高分辨率的分割图,其中图像中的大的均匀区域将由少量三角形表示。 目前,我们的实现执行顺序边折叠。通过对边特征使用并行排序技术(每个池化操作仅计算一次),并确保仅同时折叠非相邻边,可以在 GPU 上并行化此操作。显然,以这种非顺序方式进行池化的特征可能与顺序方式不同。 尽管我们的方法对不同的三角剖分具有鲁棒性(如我们的实验所示),但与任何其他网络一样,MeshCNN 依靠良好的训练数据进行成功的泛化。从这个意义上讲,与图像中的对抗性噪声非常相似,MeshCNN 容易受到可能影响性能的对抗性的网格重划分攻击。因此,对此类对抗性攻击的鲁棒性是未来工作的一个有趣方向。 未来研究的另一个途径是生成建模、网格上采样和属性合成,以修改现有网格。我们的想法是通过记录边折叠列表,以与边折叠操作相反的顺序应用顶点分割。这类似于用于反池化层的记录。因此,在合成新网格时,网络决定分割哪个顶点,例如,分割与具有高特征值的边相邻的顶点。 最后,我们发现了一个很有希望的尝试,即将我们针对三角形网格设计的策略扩展到一般图。基于边折叠的池化和上池化可以以与我们提出的网格连接神经网络类似的方式应用于一般图。至于卷积,我们必须考虑一种适用于一般图的不规则性的适当替代方法。一种有趣的方法可能是使用注意力机制来处理边。 训练配置 对于分类,我们对 SHREC 和 Cube engraving 数据集使用相同的网络架构。我们在表 6 中详细介绍了网络配置和学习参数。对于分割任务,对于 COSEG 和人体数据集,我们使用 U-Net 类型的网络。表 7 提供了该网络的详细信息。

2022/7/3
articleCard.readMore

英文学术论文写作指南

英文学术论文写作指南 本文章出自 CCF 学生领航计划 (CCF SPP),讲义和回放都挂在 CCF 的电子图书馆,这里放一个传送门,方便大家前去了解(第一周限免,第二周起需要 CCF 学生会员)。 第一期:学术研究与论文写作 讲义地址 视频地址 第二期:英文学术论文写作规范与日常积累 讲义地址 视频地址 讲者于静老师,b 站帐号于老师的日常 学术研究过程与论文写作过程是一致的,从确定研究领域,找到研究动机,提出问题,设计方法,实验验证最后总结展望,也是我们论文 introduction related work 到 methodology 和 experiments 最后 conclusion 的一个流程。 目前新手上路完成论文存在以下几个问题 学生什么都不懂,希望老师一步一步教;老师希望学生自己完成论文,自己只做点拨(甚至带带老师) 选择了很好的主题,得到了或许很好的结果,但是由于论文写作水平的原因,自己所写并不能写出整个论文的水平 论文无法准确表达研究的内容,把文章逻辑和自己的贡献讲清楚 论文在 abstract 把贡献写的很大,但根据后面实验的结果来看难以自圆其说,应该在写论文之前把所有的内容有个把握 持续拖延:写论文与科研应该是协同的,可能重要性占 30-40%,不应该拖来拖去 不知道论文如何逐步完善 科研论文写作四步走 价值观: 为何做科研?为何选这个问题?(第一期 Why?) 思路: 写哪些?什么逻辑?什么内容?(第一期 What? ) 写法: 怎么写?怎么改?怎么高效?(第二期 How?) 规范: 英文怎么写规范、简洁、清晰?(第二期 How?) 研究动机——是否探究本质 CCF-ACCF-C 问题-方法-实验,相互呼应问题-方法-实验,各为其说 问题:有理有据,足够具体问题:大家都在研究,所以我研究 方法:针对问题设计,每一步设计目标明确方法:step1->step2->step3 实验:针对方法逐一证明,针对动机逐一分析实验:达到了 SOTA,缺乏分析 SOTA model: state-of-the-art model,并不是特指某个具体的模型,而是指在该项研究任务中,目前最好/最先进的模型。 SOTA result: state-of-the-art result,指的是在该项研究任务中,目前最好的模型的结果/性能/表现。 各模块方法技巧 标题:核心问题与创新点的高度凝练 标题的基本要求:不超过 15 个单词、英文形式规范、语言精炼简洁、范围大小适当 一个好的标题:反应核心问题、突出技术创新、保护知识产权、易于记忆传播 一个不太好的标题:无法从标题中看不出工作或者贡献(创新点)、为了拼凑大写字母把单词中间的某个字母大写、或者直接凑了几个大写字母使得自己的论文难以记忆 MuKEA: Multimodal Knowledge Extraction and Accumulation for Knowledge-based Visual Question Answering(CVPR 2022) 其中 Multimodal Knowledge Extraction and Accumulation 是贡献,Knowledge-based Visual Question Answering 是领域,一目了然;为了方便记忆,把字母最好拼成方便读的单词,效果会更好 摘要——题目的扩展 现在这个问题存在的挑战->现有方法存在的问题->本文方法思路(1 句)->本文的亮点->本文方法优势 引言 引言的内容与 abstract 格式大致相同,但是需要展开阐述。 引言要有理有据,足够具体: 背景阐述聚焦重点 问题提出明确具体 背景时提的问题是这个 task 最核心的问题,要解决的任务的本质问题 而 Related work 是具体某个方法提出来的问题,是某个方法的具体缺陷 聚焦研究动机,总结现状问题 认真阅读,客观评价 基于研究动机,概述研究方法 为什么方法可以解决问题,每一步具体是解决了问题的哪个部分,不需要详细介绍每个步骤 面向领域需求,拔高论文贡献 准确评估自己的贡献,每个贡献要分开分点表述 介绍大背景->对现有方法问题进行归纳,进行客观的评价->从具体方法归纳技术问题->介绍自己方法,如何解决这些问题,每一步解决了问题的哪个环节->评估自己的贡献(提出新问题、解决的新视角、实现的新框架、新方法、达到了新 SOTA、具备了新的能力) 相关工作 基本要求: 包括理解本文的所有主题,不要罗列看过的所有论文 包括问题相关的所有工作,Task 或者我的方法的相关工作 自己研究领域的相关工作+自己的方法在领域内外的应用+与自己方法起到相同的功能的方法的介绍 从不同维度划分主题 同一主题方法归类 总结问题 引出本研究的区别和贡献 方法 方法是最容易写的部分,可以先写。不过真正的科研论文,方法内是含有问题的研究思路的,而不是简简单单的第一步第二步第三步。 总原则:换位思考,从读者角度出发 最费力的部分不一定是最重要的部分 问题建模:数学语言描述、确定研究目标 模型介绍: 模型框架图,清晰定义模块,突出创新之处 小标题确定,突出方法特色、用于、创新性,图文一致 模型总体介绍,突出模块间关联 分模块介绍,突出模块设计动机 精简表达,善用公式,理论分析 根据重点,重新组织方法介绍思路 标题和图突出创新性和重点,相互呼应 每一步方法设计都有理可依,介绍这一步是解决了什么样的问题 绘制 Framework 图 把输入输出、模块(大块里的小块)表现好,一个例子贯穿始终 图上的模块名字与论文子标题要一致 每个过程首先介绍背后的动机以及目标,具体的过程可以分小标题或加粗来表现逻辑。 在讲方法之前,整体介绍模型设计思路,描写动机以及为什么不选择其他的方式的原因,以便给审稿人进行解释。 实验 一致:支撑理论/方法、动机(实验要印证工作的特性) 核心:提供重要实验结果 诚实:不只展示最佳个例(开源之后得到反差可能会影响自己学术生涯) 分析:给出结果的合理解释(为什么会这样,结果与设计的关联) 局限:给出方法的能力边界(写出自己方法的边界,不要凭空地去解释,可以学习 ML 的论文的设计) 提出一个具体的问题->针对问题设计方法,每一步目标明确->针对方法逐一证明,针对动机逐一分析,以不同的维度进行分析。 结论 尽量简洁、避免过度夸大地总结论文的主要发现以及经过验证后的结论,介绍未来工作等。 总结工作体现效果+说明局限指明方向 致谢 帮助这篇论文的人员、机构、项目资助 审稿人 提供建议的其他科研人员 非 co-author 参考文献 不遗漏,查全 按照会议/期刊既定格式 常见错误:大小写、全称/缩写、漏写、名字错拼 做图规范 研究动机图绘制 记录方法需要的输入输出,解决了什么问题 使用专业语言和符号表达,使用对比表示和之前工作的不同 使用例子来帮助理解问题,避免歧义和偏见 减少大面积的文字,使得图片直观 合理表现本文的研究内容和挑战 模型图绘制 目标:确定思路是否清晰,逻辑能否形成闭环 有哪些步骤,分别解决什么问题,每个模块概念和边界在哪里 训练过程和测试过程是什么样的(对边界进行确认),输入是什么,输出是什么 排版问题、字体字号、图片大小等 精准语言描述每个过程、变量、符号 相同的概念颜色保持一致(不然不知道是一个概念) 前后无歧义(否则审稿人会觉得是不是有什么操作没展示出来) 展示自己的创新点,而不是展示自己费劲的部分,例如数据处理 英语写作规范 精简的表达方式 用最简单的话表达最明白的意思,不需要非得凑成一句 一句话最好只表达一个意思 减少从中文翻译的英文 避免重复的表达 严谨的叙述逻辑 在术语使用之前进行定义,缩写为什么这么缩写 所有的符号在定义前后定义清楚,在全文表示相同的信息要用相同的符号 有清晰的段落结构,段落和章节之间有过度 图表文字清晰表达内容,与图注、表注、正文一致 专业的学术用语 表述自己的贡献的时候,不要过于绝对(the best) 不要过于口语化(As we know) 对于自己和他人的评价,不要太主观(good enough to) 学习《导师防秃指南》The Most Common Habits from more than 200 English Papers written by Graduate Chinese Engineering Students 学术论文需要精准把握学术术语边界(共识),可以参考计算机 CCF 计算机术语工委的CCFpedia 规范的符号运用 阅读英文论文符号公式定义规范 Comprehensive List of Mathematical Symbols 学习本领域的经典论文 客观的图表绘制 展示探究本质的全面结果:不要只展示自己方法的 best case,客观展示自己的结果以便其他人复现参照 多视角量化分析结果提升原因 模型细节明确,提供代码 正确的文献引用 使用会议期刊标准模板 使用 DBLP 寻找文献信息 一键完善参考文献工具 Rebiber: A tool for normalizing bibtex with official info 坚守的学术道德 严守学术道德,切忌抄袭 日常积累 日常 5L 积累: Paper List, Idea List, Math List, English List, Code List Paper List 找论文 从自己的方向找相关方向,收集相关的讲座、报告、workshop 和综述 会议里经常出现相关的综述 找一个经典的工作(引用量高的论文) 从一个工作向前向后找到整个发展脉络 可以 Follow 研究团队,文章 related work 等 读论文 读之前进行积极的提问,带着问题读论文—— 文章是关于什么领域的? 解决什么问题?为什么要解决此问题? 创新点在哪里?为何巧妙? 如何验证并得出结论的? 对“我”的研究有何启发? 用批判性思维读论文—— 论文是否正确、真正地解决了问题? 论文所用的方法是否具有局限性? 论文的实验能否证明观点 or 方法的有效性? 所读论文没有解决的问题,“我”能解决吗? 能采用比论文中更简单的方法解决问题吗? 循序渐进阅读—— 第一遍:阅读标题、摘要和文中图表 第二遍:阅读引言、结论、关键信息,结合图表快速扫视其他内容 第三遍:整体阅读论文,可跳过陌生复杂的技术、数学公式 第四遍:增强对数学、技术和未知术语了解 为对领域深入研究,还可再多读几遍 系统记录—— 记录文章的主体内容 记录有启发的地方 记录有问题的地方 对接下来工作的帮助—— “我”错过了哪些相关论文? 这篇论文值得关注吗?对我的工作有何帮助? 这个领域的领头人有哪些?哪些团队值得关注? 如果我遇到作者,“我”会问什么问题? 下一步可以做什么? 文献整理—— 按内容整理:将论文按照不同的主题进行分类 按时间整理:年份+ 来源+ 题目+ 内容简介 可以将领域内的经典模型方法记录在 Excel 表格中,便于查找。 Idea List 论文读好了,自然而然就有 idea 的 list 根据所需目标、时间要求、资源实际情况统筹考虑 idea 顺序 及时复盘自己的计划 Math List 积累基础的数学知识 对模型中重要的数学公式进行推导 积累领域常用的符号、公式,形成自己与专家的共同语言 English List 积累专业知识相关的英语词汇 积累论文中的好句、好词(但是注意不要抄袭) Code List 注意代码的命名,注释规范 统一函数接口,形成自己的代码库,便于复用代码 整理深度学习框架的常用函数 QA 及小问题整理 论文写作及修改过程: 从论文到期刊:改进方法(更加通用、更加优化、可迁移性高、泛化性强)、扩展实验(增加数据集、对比方法、对比任务,更全面、更深入进行分析)、完善描述(背景、问题、模型、实验部分描述更加详细,related work 随着方法设计内容更多增多)、增多 contribution 本科生做科研的发展路径:找科研导师,给定点指导,复现论文,从调研小问题相关的工作,找到关联启发和改进。 在引言中挑战和问题哪个更重要:都是非常重要的 Contribution 在摘要和引言的区别:引言里详细写对领域的推进作用 写综述论文与这个有什么区别:刚入门时,更像调研报告,分类组织,找到相关问题,完成偏总结性文章;到博士中后期,对领域有非常多的理解,在小领域的范围内写现在有哪些方法以及他们的缺陷,存在哪些挑战,方法在哪些情况下是适用的。 在进入工业界如何提升学术敏感度:从技术与本质问题做关联,从细节中理解问题,把实际需求与本质问题关联在一起 找导师:为什么要来实验室,未来有什么计划?看看老师的方向,与老师沟通。 导师指导比较少,怎么发出第一篇:调研问题(选论文读论文讲论文)、把论文写好、给别人介绍工作以获得其他人的 feedback Step by step 不好的地方在哪里:让外行人无法看出自己的贡献 在开始研究问题前,如何积累对一个研究领域的认识:在网上找其他老师的 tutorial,从他们所讲比较泛泛的内容进行了解,从打动自己的方向进行研究 如果研究内容比较工程,比较 open,无法抽出研究问题:把实际问题用 research 的方法去解决 老师对于科研热爱的点在哪里:如果是充满好奇心去做新的东西,做好了可以有成就感 写论文先写中文框架还是全英文:先抛开语言,把逻辑表示清楚,再先按中文组织,但是写完之后一定要保证逻辑正确,再看看英文怎么组织

2022/7/3
articleCard.readMore

【数据库实验】实验8解析

在不开启自动提交的时候,用户对数据库的修改仅对自己可见,直到 commit 提交结果,或 rollback 撤回结果。commit 的结果无法 rollback,反之同理。 有一个例外,一些对表结构的操作(创建修改表结构,以及对索引的操作),会使得在操作之前自动 commit 提交事务,执行完再次 commit,使得这些操作是不可被撤销的。 网上对于这个实验只有答案,没有解释,来解释一下答案的来源。 序号窗口题号执行语句结果/解释 1备用窗口update test8_00 set age=88当前用户可见 88,其他人不可见 2备用窗口结果 1select * from test8_0088 3备用窗口commit提交成功,其他成员可见 88 4备用窗口rollback该语句紧跟在 commit 后面无效 5备用窗口update test8_00 set age=age+1当前用户可见 89,其他人为 88 6备用窗口rollback回滚成功,所有成员可见 88 7备用窗口commit该语句紧跟在 rollback 后面无效 8备用窗口update test8_00 set age=age+2当前用户可见 90,其他人为 88 9备用窗口commit提交成功,其他成员可见 90 10备用窗口结果 2select * from test8_0090 11备用窗口rollback回滚查询语句对数据存储没有影响 12主窗口结果 3select * from userb.test8_0090 13备用窗口update test8_00 set age=age-2当前用户可见 88,其他人为 90 14备用窗口update test8_00 set age=age-2当前用户可见 86,其他人为 90 15备用窗口结果 4select * from test8_0086 16主窗口结果 5select * from userb.test8_0090 17主窗口commit提交查询语句对数据存储没有影响 18主窗口结果 6select * from userb.test8_0090 19主窗口rollback回滚查询语句对数据存储没有影响 20主窗口update userb.test8_00 set age=age-10卡死,等待备用窗口提交或回滚后执行 21备用窗口结果 7select * from test8_0086 22备用窗口create table test8_01 as select * from test8_00建表前提交之前事务,解冻主窗口,主 76 其他 86 23备用窗口rollback创建表无法回滚 24备用窗口结果 8select * from userb.test8_0086 25主窗口结果 9select * from userb.test8_0076 26主窗口rollback所有用户回归 86 27主窗口结果 10select * from userb.test8_0086

2022/6/20
articleCard.readMore

Neural Marching Cubes——基于 ResNet 的 Marching Cubes 算法

这是SIGGRAPH Asia 2021 的论文,也是ACM Transaction of Graphics的论文。其实基础的MC算法也是图形学常用底层算法之一,研究研究也挺好的~ PPT:https://icys.top/reveal-0406/ 起源——Marching Cubes 说到Marching Cubes,朋友给我发了张图,表示这就是Marching Cubes(图片来自于YouTube Code Adventure频道)。 Marching Cubes (通常缩写为MC)算法是1987年发明的等值面提取算法,也是迄今为止使用最多的提取方法。当时原论文利用原始的三维数据推导内切片的连通性、表面位置和表面梯度,通过分而治之,得到相对高质量的结果。 MC算法把按均匀晶格(Grid)采样的隐式场作为输入,并提取表示场的零等值面的三角形网格(Mesh)。 在图形学中,曲线曲面等的表示,分为显式表达和隐式表达。显式表达就是能写出一个类似于$z=x^2+y$的表达式,其中一个维度作为因变量,其他维度作为自变量,可以写出一个等价的关系,而隐式表达则是类似于$F(x, y, z)=0$的形式。从显式表达到隐式表达是非常简单的(移项就有了)。一些例如球、椭球等曲面就又可以显式表达也可以隐式表达,但是更多的复杂的曲面是很难有其显式表达的,我们就常用一个隐式距离场来进行表达,即对自变量组成的线性空间进行均匀间隔采样,通过三线性插值(在X、Y、Z坐标依次按顺序进行插值)来确定这个隐式表达的面。 在图形学中,三维物体常用Mesh结构表示,结构将连续的表面离散化,用多个三角面片(有的会用多边形)来表示曲面,这样会造成一定的精度误差。因此各种方法就是在尽可能地向准确值逼近,以更好地还原物体。 1987年发明的MC算法是最经典的做法,它通过检测一个立方体对应的八个顶点的符号,结合已有的预定义查找表格(在去除对称、旋转等变式后,论文总结出15种情况),确定这个立方体中的Mesh表示。当等值面与立方体边相交,将该边线性插值的点加入最后的顶点集合中。立方体一步一步依次移动(或者说前进March,这也是为什么叫做Marching Cubes),最后得到整个物体的面片结构。 改进——MC33 基础的MC算法在计算的时候,由于过度的分而治之,导致相邻两个立方体的面片结构不连续,使得生成出的结构带有孔洞(见下左图)。此外,基础的MC算法无法形成管道结构,对于真实物体的还原性有限(下右)。基于此,1995年,Chernyaev发表了MC33论文,对已有的MC算法进行优化,以保证拓扑的正确性。 MC33的论文假设每个立方体的顶点不仅限于正负,可以使用三线性插值(按三个方向依次插值)以精确最后得到的结果。这篇论文发现,原来的15种结构中,平面内对角相同的2正2反正方形有两种(一个原象有两个象无法形成映射关系),称其为Ambiguous face,并且在相同立方体排布下仍可能存在多种情况,称其为Internal Ambiguity。 为了解决上述问题,确保在三线性插值基础上的拓扑正确性,论文细化了分类,将当前状态与相邻立方体结构情况相结合一并考虑,得到了33种立方体,具体结构如下: 主菜——NMC 在若干年的发展中,MC方法修修补补,但仍没有完全解决一个比较棘手的问题——MC算法对于尖锐边缘的还原性不佳。近期有一些算法可以解决尖锐边缘问题,但是需要额外的输入。 于是自称加拿大最强的图形学高校SFU(况且称呼它为顺丰大学)的张皓团队,提出了深度学习的MC算法NMC,设计了兼容于传统MC算法的立方体结构表示方法,修改了一部分镶嵌方案(加入了一些隧道的情况),设计数据集并使用有监督的深度学习(基于ResNet网络模型)代替MC33的三线性插值方案,以获得更好的(尤其是可以更好表现边缘锐度的)物体重建效果。 效果预览 除了论文宣称的边缘锐利明显以外,可能有些(审稿)人会问,这个方法为了解决表现锐度边缘问题,那对于比较平滑的表面,效果怎么样呢?论文在补充材料里给出了效果对比(每一列的标签在图片最下方)。 表示输出的Mesh结构 我们很希望深度学习网络输入一个隐式距离场(其实论文还可以输入体素结构),输出一个Mesh,但生成Mesh不太现实,那如何用深度学习网络的输出表示Mesh呢? 有一个Naive的表达方式,使用One-hot Vector表示每个立方体单元是每种镶嵌情况的概率,这样会使得训练效率非常低,而且不太好表示旋转对称等(否则会让向量的编码更长),不是一个明智的表达方式。 论文提出了一个新的表达方式,它从二维进行举例,并顺其自然地扩展到三维。对于MC算法的二维情况,论文在正方形中间加入四个自由的点,根据四角点的正负情况,这四个自由点会有1至2个点有效,参与形成的Mesh的顶点连接。此外,论文摒弃了传统的线性插值方法,将四条边上各加上一个有自由度的点(现在一共有$4+4=8$个点)。此时,对于一个正方形的嵌入方案,需要5个布尔值表示分别表示四角的正负情况和对角情况的正负面情况(刚才说一对二无法形成映射,则对于这种情况额外加一个布尔变量进行区分),还需要12个浮点数表示八个点的自由度(四条边上的点各有一个自由度,而正方形内的点各有两个自由度,共有$4\times1+4\times2=12$个自由度)。 由于正方形不是独自存在,相邻正方形共用一边,一个顶点至多被四个正方形共用,故我们在表达时只表达每个正方形左上角顶点,以及上、左两边(最后一行一列加空padding就行了),这样一个正方形需要两个布尔值和10个浮点数进行表达(正方形内的点没有被共用)。 扩展到三维的时候,与二维同样的,每条边有一个自由度为1的点,每个面有4个自由度为2的点,此外还有体内8个自由度为3的点。此时表示一个立方体需要15个布尔值,分别表示8个顶点正负、6个面朝向(同正方形面朝向、仅在对角相同的情况使用)和一个Tunnel flag(与MC33相同,表示这个格子内是否存在隧道。因为论文仅考虑出现一个隧道的情况,所以只需要一个布尔值),需要84个浮点数,分别表示84个自由度($12\times1+6\times4\times2+8\times3=84$)。同样地,删节后,需要存储5个布尔值(1个顶点、三个面和隧道标志)和51个浮点数($3\times1+3\times4\times2+8\times3=51$)。 一个立方体八个顶点的数据已经编码成功,而论文对这样的数据与镶嵌模式进行对应时,也扩充了原有的情况数,在2003年的论文(对MC33进行了一定的修正)基础上,添加了6种管道类的镶嵌方案,被他们称作NMC-lite,而他们基于NMC-lite重新设计的结构叫做NMC。可能有人会好奇,$33+6=39\neq37$,那少的两种情况去哪了呢?这两种在论文中与其他的结构表达合并,故少了两种结构。 数据集的设计 由于网络需要输入距离场或体素,输出布尔值和浮点数向量,他们将物体按分辨率切分,对于每一个小立方体,按照以下次序去得到布尔值和浮点数的真实值(Ground Truth): 确定拓扑类型(布尔比特) 使用$9\times9\times9$的采样,判断各点正负,得到隐式距离场 通过采样的隐式距离场,判断每个面的顶点的连通性(相邻的采样点符号相同为相连) 通过检测立方体内部的连通块数量,判断是否有隧道,以及判断是否能表示 立方体与物体求交,获得所有立方体每条边与物体的交点(如果有) 对物体与立方体表面的交采样,确定所有立方体面片内点的位置 对物体与立方体的交进行采样,确定所有立方体内8个点(如果需要)的位置 深度学习网络相关 其实这篇论文并没有对深度学习网络进行优化,更多的贡献在于架构了几何表达到网络输入输出的结构关系。 网络:3D ResNet Loss函数 对于布尔值结果使用BCE(Binary Cross Entropy) 对于浮点数部分使用MSE(Mean Square Loss) 如果输入是voxel,为了让结果光滑,在浮点数部分Loss中额外加了光滑性loss(对于Ground Truth中的长度较短的Mesh中的边,计算其在预测模型中的长度。由于镶嵌模式是另一个网络计算,可以保证预测和真实模式相同,使得边是能对应的上的) 由于BCE和MSE的Loss权重不好设置,故用两个网络分别计算布尔值和浮点数 效果比对 论文其实给了许多的客观的评价指标,但是由于过于专业,本文仅从主观判断的角度展示结果。 MNC的效果在所有分辨率的情况都优于MC33,但是随着分辨率的增长,NMC与MC33的差距会逐渐减小,因为每个立方体的拓扑情况会简化。从图片上来看,NMC的结果与MC33下一个精度的结果接近。 NMC比MNC-lite效果好一些,但是三角形的数量要翻一番。 对于噪声的处理:如果把噪声的数据以正常数据的比例放入训练集和测试集,训练得到的模型效果会有明显的改善。 缺陷和未来工作 网络对于旋转是敏感的,因为他们训练的数据集的物体大多与坐标轴对齐,于是他们写的平滑项loss会驱使着向坐标轴对齐。 对于某些拓扑结构,匹配不到对应的镶嵌模板(主要是分辨率不够,使得拓扑结构复杂或极端) 某些匹配不成功的立方体,所计算的结果可能有自交叉。

2022/4/2
articleCard.readMore

【添翼工程】雅思课

写作 中国大陆均分 5.37:语法词汇、评分标准、逻辑 题目设置:图表信息描述 20min+议论文 250 词 40min 大作文 分类 讨论类:Discuss both views and give your opinion? 两个段落一样长 观点类:To what extent 程度 do you agree or disagree? Do you agree or disagree? 不一样长 两种不同的问法回答不一样 问题解决类:What caused the problem and what solutions can solve this problem? 常见误区 以类分区:避免跑题 用万能模板套题 享受舒适圈(使用简单词句,目标凑字数) 评分标准 任务回应 完成各部分任务 清晰的观点,不能最后更换观点 逻辑与连接 语义上的逻辑连贯 每个段落都有一个清晰的中心主题 词汇丰富度 试图使用不常用词汇,但有时不准确 语法丰富度和正确性 用复杂句式 结构 介绍段 核心段——面向逻辑连贯 问题:没有细节(举不出例子)、不连贯、想说的太多(每个段有一个中心主题) 第一局应当是一个主旨句 总结段 核心段 核心段的顺序和个人观点有关,观点有偏向一方(任何题目)和缺一不可(如果观点对立 就不能缺一不可),先写反对的,再写偏向的 如果是 Discuss,无论是否偏向,字数差不多,不要带感情。 Discuss:3 种 偏向一方(√)、缺一不可 extent:3 种 完全赞同 部分赞同 完全不赞同 do you agree: 2 种 outweigh:2 种 先写缺点 跟 2 优点 主旨句的书写 审题,找准限定词(对 xxx 来说、在 xxx 方面) 主旨句内容要合理(举办奥运会可以提升国际影响力 因为逻辑不通顺) 简洁明了(不需要写从句),预告写作内容(含有观点) 近二十年科学技术有了发展:描述了客观事实没有观点 主题句的展开 原因+举例/对比(明确的结果) 举例+举例(说不出原因的时候 明确的结果) 年轻人应该受到重视——一线人员以年轻人为多、创业公司多是年轻人 反向假设/让步+结果/举例(意见与建议) 细化+举例(抽象的概念) 开头段 People have different views about / People have different opinions about while/although I belive that / in my opinion / I would argue that 结尾段——个人观点+倡议/建议(凑字数) 做题方法 审题三遍,画出双方关键词 确定个人观点(只影响顺序 不影响内容) 快速写提纲,可以不用英语,确定段落顺序(偏向 A 则先 B 后 A, 总结)和大致的例子,5min 内 写作(首段有模板,核心段首句,尾段总结) 问程度:100%同意、100%不赞同、部分赞同 部分赞同确定哪一部分,完全的观点不需要写让步段 分类:把人/物进行分类 阅读 判断题 判断题有 T/F/NG(not given)或者 Y/N/NG,分别都有其判断依据 True 题目是对原文的同义改写(题目和原文的信息出现了同义词替换、主动换被动等情况) 原文:Food production has kept pace with soaring populations mainly because of the expansion of artificial irrigation(灌溉) system. 题目:Feeding increasing populations is possible due primarily to improved irrigation systems. 题目是对原文的合理总结或推断 原文:The metal had to melt at a temperature less than the hardening point of glass(about 600℃), but could not boil at a temperature below to the temperature of the molten glass(about 1500℃). 题目:The metal used in the floated process had to have specific properties. False 反义改写(题目和原文的信息出现了反义词驳斥) Before—after Almost—totally Always—never 肯定—否定 原文:It is by no means the most obvious way to resolve the problem. 题目:It is the most apparent way to resolve the problem. 关系驳斥(对比关系、因果关系、目的关系等相矛盾) More/less/as……as/……. Because /result from/ as a result of/so/result in/……. In order to/ lead to/aim/purpose/……. 原文:The systems supplied the Roman Empire with as much as water per person as is provided in many parts of the Industrial world 题目:Water use per person is higher in the industrial world than it was in Ancient Rome 原文:The FAA was created as a result of the introduction of the jet engine. 题目:The Grand Canyon crash in 1956 resulted in the establishment of FAA. 隐含否定或者通过时态的不同进行表述(Used to do sth/ as was once the case) 原文:She used to ask advice from me. 过去常常,现在不再 题目:She often get some suggestions from me. 原文:He undertook a task to record the almost-completed railway 题目:the railway had been finished when he undertook the task. Not Given 题干的信息在原文找不到定位词,或者没有提及无中生出一个国家名、时间、细节信息等 无中生出比较关系,因果关系等 原文:Schools are usually modern in design, set well back from the road and spacious inside. 题目:Private schools in Japan are more modern and spacious than state-run lower secondary schools. 题目可以定位到原文,但是从原文无法得知题目中的事实 原文是某人的目标(aim)、目的(purpose)、愿望(wish)、保证(promise)、发誓(vow)等,题目是事实 原文是并列关系,题目是占比关系 原文是大范围,题目是范围中具体的一个 原文:The new police chief vows to crack down on crimes with tough control and iron hands. 题目:The crime rate will be down in the future. 原文:China is the world’s biggest exporter of raw silk and silk yarn(纱,纱线) 题目:Silk yarn makes up the majority of silk exported from China. 判断题考点词 绝对词(Only, all, most, first, always, none, must, 最高级等) 比较关系,因果关系,目的关系等 数字(日期, 数量, 百分比等) Increase= soar =burst = ascend =grow= climb Reduce =diminish =decline = decrease= mitigate=dampen=decend 细节信息(宾语的替换,主宾位置,范围大小,并列和占比等) 易混淆练习题 原文:Beijing is one of the largest cities in the world. 题目:Beijing is the largest city in the world. NG 原文:Beijing is the largest city in the world. 题目: Beijing is one of the largest cities in the world. Y 原文:I used to play piano very often. 题目:I often play piano. N 原文:Visitors can travel the park not only by bus but also by bike. 题目:It was found that most visitors travel the park by bike. NG 原文:The trees are native to Yantai. 题目: The trees grow only in Yantai. NG 填空题 句子填空、笔记题 做题方法 精读答题指引,看清题目要求(字数限制) 通读题目,判断最容易定位的一道题 划出空格所在句中的定位词,迅速找到题目的出处 找出文中出题句,根据题干其他信息确定空格答案 定位 绝对特殊词 数字(百分数、钱数),年份,时间,专有名词/全大写缩合词,斜体,带引号的词 相对特殊词 名词>形容词>动词 备注:注意误区 标题词汇 在通读题目, 划出定位词的过程中,除了题干的定位词,同时要 重视逻辑关系词,如 and / both / but / neither 等。这些关系词所表达的逻辑在文章也一般不会发生变化,较为稳定 注意空格前后的语法现象,如词性、单复数等。利用空格前后的词去推测空格中词的词性,甚至词义 n.(80%) v.(10%) adj./adv./num. (10%) 表格、图表标记、流程题 题目特点:难度低,出镜率低,送分题 顺序原则:展示文章思路和叙述逻辑 做题方法 精读答题指引,看清题目要求(字数限制) 定位:有标题首先用标题定位大致位置 对于单道题目,使用空格前后的定位词(如名词,数字等)定位。 找出文中出题句,根据题干其他信息确定空格答案 注意表格,流程,图表标记是否有标题 注意事项 表格题需要注意表格的表头,识别单元格信息特征 流程图是顺序题,注意箭头走向 图表标记题需要理解图表含义和特点以及各种方位关系(前后上下左右) 注意空格字数要求,以及是否需要填写数字 摘要题 做题方法 精读答题指引,看清题目要求(字数限制) 如果是有选项摘要,看一下是否有提及 NB you may use any letter more than once; 忽略空格,通读 Summary 划出空格所在句中的定位词,并判断空格词性 找出文中出题句,根据题干其他信息确定空格答案 如果是有选项摘要题,注意正确选项是原文词或词组近义词。 注意事项 摘要题分为无选项摘要和有选项摘要 无选项摘要选用原文中的原词,注意选词的字数限定 有选项摘要需要选择和文中词或者词组意思相近的选项 有选项摘要不一定是顺序题,正确选项是原文的同义替换 标题题 匹配题 填空和判断一般按顺序出题,但是匹配完全乱序 特殊词匹配 题目是人名,匹配是观点->去原文找人名,匹配对应观点 地名/国家与解决措施匹配 段落信息匹配 信息匹配段落(类似于四六级) NB(特别注意) You may use any letter more than once 可能重复选择 一般是 1 个字母选 2 次,很少 1 字母 3 次和 2 字母 2 次 审题 NB 划定位词 略读 不要精读 读完一段之后看题 比对题目 做法 审题 注意乱序 特殊词等对应 分析题目观点,划出关键词 实义名词 用特殊词定位,分析出题句 比对(注意同义替换) 注意事项 句子结尾配对题 有顺序 分类题 类型配特征 听力 月份的说法 April the twenty-ninth the twenty-ninth of April 29 the fourth 拼写 答案修改 双写 double l double r 辨音 uu&w 重音位置, j&g, m&n T for Tango 路的说法:Avenue, lane, path, drive, boulevard 时间说法:a quarter past/to am/pm 时间单位不缩写 钱 $ £ € cash check credit card 钱的数额和题号区分 566222 five double six triple two 0 o zero naught 三种 0 的说法 z /zed/ /zi-/ 字母+数字 postcode passport drivers’ licence 50A vs 58 P4 生物 商业 限定词、定位词

2022/3/27
articleCard.readMore

【雅思哥】雅思口语会员课程笔记

这是雅思哥的会员系统课,报了正课之后送了 7 天会员,一些笔记分享一下~ Part1 如何获得考官好感 自如、准确 不要踩中考官的雷区 背答案万能模板->说不到点上或用词汇不正确(比如 claim 一般来说对其观点表示反对) 没有拓展答案的意识(比如问 Where are you from 不要回答一个特别简单的答案) 不要弄得太长,因为考官要在 4 分半问完 12 个问题 答案有真实感 敢于否定(如果真没有相关的经历,就可以否定,说想象或者未来会不会怎么样) To be honest, not really. I only read the books that our teachers requires us to read. In my spare time, I prefer playing computer games to reading. To be honest, I never planted a tree because my schools never organized tree-planting activities. But in the future, I hope I can have a chance to participate in such meaningful activities. 结合个人经历与感受 Do you often visit a museum? Actually, whenever I move to a new city, I only visit the museum there for once. I feel like the exhibits in museums are always the same. There’s no reason to visit twice. Do you enjoy your current stage of life? I can’t say I totally enjoy my current stage of life. Even though my current life is quite comfortable, I don’t feel like there’s much personal growth. That’s why I’m thinking to study overseas and experience something new. 敢于承认无知 What kind of trees do people usually plant in your country? Well, it’s really difficult for me to generate what kind of trees Chinese people usually plant. But I guess … farmers like to plant fruit trees so they can make profits form selling fruits. Do you know any famous people in your area? I personally don’t know anyone who I’d consider a famous person. And I guess there’s little possibility that those rich celebrities could live in my area. Part1 除了 Because 还有什么拓展方法 Response + examples Response + fact

2022/3/13
articleCard.readMore

【雅思哥】雅思 7 分备考

这是雅思哥的 6.6r 的公开课,报了正课之后送了这个课,一些笔记分享一下~ 口语 Part1 【高频话题】手机如何改变生活 需要细节 口语不需要 conclusion 养成考试习惯,Part1 通用结构——时间双观点结构 先给主旨(可选) 过去 xxxxx 样,现在 xxxxx 样 常见词汇 daily errands 日常事务 俚语表达 加分项 game changer 造成了巨大的变化 game 其实没有用其原因 case in point 例如 Part2 Describe an interesting song As a typical millennial down to a t fit this bill millennial 80-90s gen-z 00s push comes to shove 成名曲 breakout song ( and shot them to fame) binge watching 疯狂地做 super duper catchy 非常吸引人 注意重音 听力 听力填空: 不需要背特别广(四级、六级)的词汇 选择配对: 新题的多,强调口音(英、美、奥新西兰)+语速(平均比剑桥稍快一点,参考剑 8 剑 12) 考试经验: 考前回顾考点(陷阱)、根据语境区分近音词 地图(5%)流程问答: 总体题量不大,占比不大 机考地图注意巧妙处理(左边是地图右边是表格,两个距离太远,可以抄一下题目) 注意多义词(pass 通道、路过 past the bridge 不过桥) 5 分及以下短期备考策略 趋势内考试高频词优先背记 填空题+选择题优先学习 考前剑雅模考(月份/星期/数字必练) 5.5-7 分备考策略 趋势内考试答案词尽全力背记 填空题、选择题、地图、配对技巧梳理 要高分必须从有效沟通的方向去理解题目 听的答案要符合逻辑,写一些让交流有信息量的词汇 8+备考策略 预测+熟悉难题套路 抽象到具体的替换 写作 写作预测题精讲 雅思大作文的类型 利弊类 Is is positive or negative…… 观点类 Do you agree / disagree 讨论类 Discuss both views and give your own opinion 报告类 What are reasons, effects and solutions 开放式 What? How? 学习建议 最好学习作文结构,学习范文中的好词好句,不要闭门造车 不要抄范文,不能化用成自己的,没有用 多练习,从范文里举一反三 考的是熟练度和准确度不是难度 solution 类 把目的和措施分开 不要只看范文,可以看着范文思路结构,仿写然后对答案更好 句子扩展 使用介词,把句子进行延伸 both within …… and …… such as …… etc. 写作素材的一题多用 提建议、解决措施 To do…, we need to …… …… would be an effective strategy for …… … should …… If …, …… would …… …… should …… so that …… 加上一点衔接词 Considering In this process 代词 阅读 中国平均分阅读最高,口语最低,阅读对于中国人是一个提分的科目,对于一个 7 分,一般来说就是 8766。 同学提分误区:天天做题;对照解析书总结错题;总结文章中不认识的单词;精读 其实这样只是在做题,忽略了单词的学习,忽略了方法的学习 不要自己总结单词,因为高频词单词书比自己总结的好 自己这个总结的单词,大概率是假努力,为了满足感而已 学习方法 单词,一定要提升词汇,不要放在句子背 循环、时间、专注 做题方法技巧(短时间提分用) 刷题(有了 12 再去做题不然没用) 总结 看考前预测 题目有许多种,每个题型都有对应的方法,要分细 You may use any letter more than once 有 90%概率会有选项重复选 None of the above 有且仅会被选一次 即便有 NB(Nota Bene) 大定位:对于名字配对题,先数每个名字在文章出现的次数,从出现次数最少的开始选,最后没时间了都选出现次数最多的 小定位:分析题干,把所有重复出现的词拿掉(对做题没有意义),再找定位词 定位词不一定是一个词 有数字划数字,有比较划比较,剩下的划剩下的,在剩下的重点划有实际意义的词 人名是不会发生同义替换的,所以好找

2022/3/8
articleCard.readMore

【雅思哥】雅思 FAQ

这是雅思哥的 6.6r 的公开课,报了正课之后送了这个课,一些笔记分享一下~ 口语 两周内准备口语 六分:把 Part1 和 Part2 先练好 七分:在六分没问题的基础上稍微练一下 Part3 一紧张语法混乱 先保证流畅性,允许一定的语法错误,以免考官打断 思维打不开 积累 P2P3 怎么备考 Part2 准备故事 Part3 准备通用的观点去答题 不能背题 考官问的东西听不懂 P1 会有归类 P2 基本都是原题 P3 可以问一下 P3 考官越聊越深入很慌张 不需要每个都头头是道 不知道这个话题可以去拓展,学方法 语料不丰富 如何在短期内快速提升 会提供范文 学习俚语表达 一个月报考,如何合理安排备考 四个评分标准 fluency 词汇 语法 发音 内容大众化好还是个性化好 个性化好 P2 准备多少故事比较合适 一共 50 个话题 准备 30 个话题比较合适 口语题库换题对备考有什么影响 Part1 换 1/3(出现新题 1/3) Part2(40%-50%) 不建议 159 月初考试,会换题 从来没学过怎么学 口语不推荐自己学 很多内容中文拓展丰富,但是缺乏俚语表达,或者俚语表达不合适,发音不太好练习 有些人过于关注语法、词汇,应该使用更好的方法 说的时候简单的单词想不起来 把一些句型要养成习惯,从课上吸收表达 Part3 需要高级词汇吗 需要 口语每天练习多长时间 3-4 小时,纯说,不包括写题时间 实在没时间了,再去挑重点 10 天复习口语复习什么 看小范围预测 口语考试时间有什么讲究吗 我们没办法选择考官,不要追寻虚无缥缈的东西(早上考、下午考、穿着之类的) 突然卡顿怎么办 课上会讲怎么圆一下 想说定语从句但总是卡顿,脑子在想语序、动词就会卡顿 我们学习方法太书面化了 先保证流畅性,再去想语法和俚语表达 给老师交作业,发现问题解决问题 听力 听力几倍速练习比较合适 本身不高(6 以下)的就不要倍速了 其他的适度加速,一点一点加速,最多不要超过两倍 听力经常走神怎么办 练习注意时长,精听不要超过半小时,不要无用功 不要一个 section 一练,一次做一套 是不是基础不行 听不懂 学习 答案词错过了怎么办 模考的时候反复背关键词 听 TED 有用吗 意义不算太大 因为语速、内容与考试不一定匹配 填空题日期时间等的写法 North-West可以写northwest 年份写在最后,日在前月在前都可以 月份不可以缩写,不可以用数字,但是大小写无所谓 时间写17:30和17.30都可以 Section 2、3 的选择题比 1、4 填词题更容易出错,应该怎么提升呢 因为 2、3 的干扰项太多 特别注意思维严谨 要在草稿纸上记笔记吗 如果已经读完题目了,就不要记笔记了,而是观察题目的替换,提前预判 看不完题目,还是记一下比较好 双选题选不对 音频中碰(匹配)词的概率挺多,而不是匹配一个句子,从而选错 题干和选项过长的选择题,眼耳兼顾不到,反应不过来 读题优先看长选项 配对题不知道匹配到哪了 题干如果是大写的定位 如果是小写的大概率是替换 听力一天练多少合适 马上就考试了一天三套 如果刷题都刷完了,有瓶颈了,好好找出一套找问题 每个单词都能听懂,但是连起来听不懂 在练习的时候听他们讲了什么,而不只是听单词 注意关联和逻辑 容易被陷阱题影响 没有注意细节,练习不要泛泛听 What When How Where 之后能复述出来 地图题怎么判断 示意图、填图、配对 方向的说法(总结)、尽头拐角之类的标识怎么说之类的要总结 抓不到答案 加强看题,是不是听完之前看完题 漏听:磨耳朵 Matching 题跟不上 注重替换 阅读 阅读达到 7 需要多少词汇量 如果不用方法的话,需要 7000~8000 词汇量 如果有方法的话,可以减半,4000 词汇量就可以 阅读机考 机考优势:左边题目右边题,省的翻来翻去,已经很好了 定位词不明显的怎么快速定位 40 个题有 35 个题有定位词,不过可能不是一个词而已,需要掌握技巧 怎么更好的做题 如果单词掌握不好,没找到技巧,直接做题没用,因为很多题干没听懂 对照老师讲的方法进行总结,但不需要总结词汇,买词汇书更好 NG 和 F 怎么区分 如果是阅读整体不行,有了方法同义替换看不懂,也没用 如果只是判断题有问题,其实是没找到套路,在有方法之后很快能掌握 文章很长,细节题定位不明显 定位词技巧 有 30%的题会有同意替换 阅读能力如何提升 上课可以短期之内提高雅思阅读分数,但短期之内不能提高阅读能力 每篇时间分配上有侧重吗 有三篇文章,不一定第一篇最简单最后一篇最难 先判断哪个是最难的,剩下俩 18min,难的 24min 判断题 TF 写成了 YN 有分吗 看考官,很有可能没分了 问答题首字母大写扣分吗 阅读大小写无所谓不扣分 听力只考察拼写,不考差大小写 需要把每段意思都弄懂再做题吗 不需要,因为三篇文章都读完,题目一定做不完 95%的人做不到 官方考察的是效率阅读 如何保证速度的基础上提高做题的准确度 方法、技巧、练习 技巧 Example 原文:香蕉是世界上最古老的水果,而题目:香蕉是世界上最古老的水果之一->T 原文:香蕉是世界上最古老的水果之一,而题目:香蕉是世界上最古老的水果->NG 能力和技巧哪个重要 能力更重要,但是培养需要两年 但是对于备考雅思,技巧重要 阅读对 34~36 道,但是需要一个半小时,如何提高阅读速度 这个其实是能力技巧都有问题 而且不要这么做题,这样只会给自己盲目的自信 阅读词汇量怎么快速提升 背单词:高度注意力、循环、专注 不建议用手机背单词,因为手机诱惑比较多 最好一天一个小时单词 阅读没耐心 多做做题,做得少了 填空题或问答题找到定位段但是找不到答案 单词的问题,同义替换问题 长难句怎么处理 考试时候没时间分析长难句 答案的查找与长难句分析没关系 备考阅读的时候不考语法,只有口语写作考语法 作文 大作文是不是任何话题都可以用五段式书写 四段式:好处坏处各占一半 五段式:有侧重,好处两段坏处一段 大作文如果跑题扣分很严重吗 看跑题程度 看错单词 planet->plant,很有可能寄了 题目之间看着很像,但是侧重点不一样,直接背答案可能会有点偏,成绩稍微有影响 文章思路要连贯 作为格式标准应该是像中文那样首行缩进还是顶格写,段落于段落之间是否需要空行 顶格写、空行 备考书籍 长期备考:杂志、新闻、小说 短期备考:看看真题 机考是随时存盘吗?拼写错了会识别吗 拼写错了不会识别 7 分的作文是什么样的 有一些比较好的词汇和句型 其实考的不是难度,是熟练度和准确度,七分不需要用特别难的词汇 短期准备雅思作文最简易从哪方面入手呢 造句 3 天 段落 4-5 天 全篇剩下时间 Task Response 单方面 8 分的标准是什么 词汇不好,通过扣题提分不现实,提高的话从语言提高 大作文看语言能力还是思维能力 雅思是语言考试,把 70%的时间放在语言上 思维也是很重要的,作文是看整体等级 小作文万能模板和大作文万能理由 写开头和段之间关联的时候,有固定的套句,考试的时候可以使用 不能用四六级模板,那个容易不扣题 固定的句型可以背一些,可以快速搭建框架 写作 5.5 一个月提到 6 6 分是一个门槛,造句是一个难点,少犯语法错误,基本就可以 6 分 7 分需要扩充词汇,注意连贯性,句法多用一些 字数不够怎么办 讲完道理后,来个例子,再不够,反着再来一次 流程图字数不够 根据常识补充一些内容,加上一两句话 大作文写多少字 250-300 字,不够 250 扣分,太多了可能不太想看 备考计划 第一阶段:基础练习(写作词汇+造句练习+语法练习) 第二阶段:写作练习(仿写)段落练习 第三阶段:写作练习(不限时写作) 第四阶段:5-8 次模考+复习 过犹不及,建议隔一天写一次,这样在休息的时候好好复习一下

2022/3/8
articleCard.readMore

C++ 中字符串与数字的拼接

在 Java 中,字符串和其他类型的对象用 + 相连时,默认将非字符串对象转为字符串(调用.toString() 函数)。今天被问到才发现,在 C++ 中,string 与 string 的连接与 Java 一样,而字符串与数字的拼接,可能就与 Java 不一样了。 通过查询 cpp reference,发现其实对于这种加法的重载只定义了以下这些: string operator+ (const string& lhs, const string& rhs); string operator+ (string&& lhs, string&& rhs); string operator+ (string&& lhs, const string& rhs); string operator+ (const string& lhs, string&& rhs); string operator+ (const string& lhs, const char* rhs); string operator+ (string&& lhs, const char* rhs); string operator+ (const char* lhs, const string& rhs); string operator+ (const char* lhs, string&& rhs); string operator+ (const string& lhs, char rhs); string operator+ (string&& lhs, char rhs); string operator+ (char lhs, const string& rhs); string operator+ (char lhs, string&& rhs); 那字符串直接与数字用 + 相连时,会怎么样呢? string str = "abc"; string b = str + 1; // compile failure string str = "abc"; string b = str + (char) 1; // compile successfully 由于自动的类型转换只能向上转(char -> int)而不能反向,所以编译是失败的,如果是引号的字符串呢? string str = "str" + 1; cout << str << endl; // output: tr string str = 1 + "str"; cout << str << endl; // output: tr 可见,这个加数字其实意味着字符数组的偏移,与string str = &"str" [1];等价。在这种情况下,部分编译器会提 Warning,提醒用户这个加号并不是表示字符串的连接,防止用户受到 Java 影响误用。 那如何实现字符串和数字的拼接呢? 对于 C 语言有经典的做法sprintf,与printf类似,这个函数的作用是格式化输出存到字符数组中。以下是该函数的一个例子,关于该函数的其他信息可以查阅cplusplus reference。 #include <stdio.h> int main () { char buffer [50]; int n, a=5, b=3; n=sprintf (buffer, "%d plus %d is %d", a, b, a+b); printf ("[%s] is a string %d chars long\n",buffer,n); return 0; } 一般对于 C++ 来说,如果使用的是 C99,一般来说是使用字符串流(有人好像叫它字符串操作模板类,在这里也一并列上这个名字)stringstream。 在 C++ 里这样的流有很多,就像 C++ 中进行文件输入输出的ifstream ofstream,如果不熟悉的话,我们可以把它类似于 C++ 的cin和cout。 这个字符串流使用的方式比较简单,样例如下: #include<bits/stdc++.h> using namespace std; int main() { stringstream s; s << "str" << 1; cout << s.str() << endl; } // output: str1 这样就可以用这种流的方法处理字符串拼接问题了~ Emmm,如果能把支持的 C++ 特性提升到 C11,可能就不需要那么麻烦了,我们有了to_string()函数,把一些数据转成字符串,样例如下: #include<bits/stdc++.h> using namespace std; int main() { string str = "str" + to_string(1); cout << str << endl; } // output: str1 C++11 给的新特性真的很方便,比如可能大家常用的auto,比如大家可能用得到的智能指针shared_ptr,以及更好用的 random uniform_int_distribution uniform_real_distribution,所以很多在线的考试、平台对 C++11 支持的很好。 不过正是因为 C++11 满足了很多人的需求,这些平台对以后的 C++14、C++17 甚至 C++20 支持有限,因此很多人就没法享受到例如字符串分割、函数模板的推导、optional之类新特性带来的好处。新特性,是真的香啊~

2022/2/26
articleCard.readMore

退群杯——从闲聊到现实

各位 OI 退役或还没退役的选手、各位对 XCPC 感兴趣或已经参与过的选手、各位仍在关注退群杯的同学以及各位乐子人: 首先祝大家新年快乐!我们非常荣幸地在此宣布,经过两个多月的前期筹备,第三届「退群杯」竞赛(XCPC 分场)即将与大家见面! 本届「退群杯」与前两届不同,其内容为算法竞赛,赛制则采取大家所熟悉如果不熟悉就现在熟悉的 XCPC 赛制,但改为单人参赛。正赛共⑨题,时长 5 小时,计划于 2 月 12 日下午进行。为方便各位选手熟悉赛制和办赛平台,正赛前一天即 2 月 11 日将有一场时长 2 小时的热身赛。赛后,我们将公开题解(PDF 格式)。如条件允许,我们也将准备一场直播讲解。 与第二届「退群杯」一样,本届「退群杯」也将有伴随题目的剧情。我们力图为大家带来更多参赛乐趣,得益于算法竞赛题目相对较高的自由度,解谜剧情将与题目充分结合。不过请各位选手放心,即使完全不看剧情也不会影响 AK 解题。 本次比赛我们为各位参赛选手准备了丰富的奖励,包括但不限于马克杯退群杯、桌垫、亚克力挂件,解谜成功更有机会领取神秘奖品! 退役 OIer 文化课交流群 第三届「退群杯」全体 STAFF 2022 年 2 月 1 日 「退群杯」中的「退群」二字,可能与大家所熟悉的退群含义不同,指的是退役 OIer 文化课交流群(群号 1107305016,其实由于 OIer 的不断迭代,其实也已经成为了一个社交文化圈,并衍生出了若干子群,退群杯群就是其中一个)。 由于自招取消,强基计划开始,高中生们也开始用脚投票,高中生 OIer 也越来越少。第三届「退群杯」即将开始,作为第一届第二届「退群杯」英语科出题人(前两届是文化课模拟考试,第三届开始为 XCPC 类考试),很高兴学弟们接过了「退群杯」的接力棒,让这种 Oier 学长学姐带学弟学妹的风气继续保持下去。 从无到有——第一届退群杯 由于主群退群「退役 OIer 文化课交流群」迭代了数次,导致一些历史不可考,此处仅能通过一部分聊天记录和个人回忆来还原历史。 其他组的成员看到都有在知乎上发表自己角度的经历,我也分享一下我的经历。 当时看到了主群的群公告,征集一些群友一起给 20 级高中毕业生出套模拟题。当时正值疫情最严重的时候,各地也没法如期开学,大学生们也省去了各种各样非必要的活动,剩下的时间正好可以用来出题,于是我报名了英语组,也成为了第一届退群杯的英语组负责人。 当时一起去完成的有六七人,每人从选素材到高考题型的适配化,最后拼在一起,就形成了一套英语科试题。对于听力,当时没有条件去录音(我们的口音也不合适),然后我们最后的决定是找一些听力题拼在一起,我使用 Au 把各段听力进行了拼接,把 ksyx 用谷歌娘读的考试名称组装在一起,导出了听力音频。 当初一个组的 SDUer 还有 Kamigen 和 Raffica,在后期高考结束志愿选择的时候,我们三位与其他群友劝退自己学校的行为相反,非常欢迎大家来 SDU,于是我们三位的行为就非常亮眼,成为了退群杯群里的 SDU 三人组。 在这次英语出题里,我记得我们还借此成立了一个英语口语交流组,以讨论班的形式举行。每位同学准备一次讨论的材料,然后其他人就会一起用英语讨论这些话题。当时因为有泰山学堂周小兰老师的英语口语课,我就拉了学堂的 Arno 同学,一起参与这个口语交流。当然在英语口语课结束之后那个群就长期咕咕咕了😎。 记得在公告之前,大家讨论宣传文案,记得当时借鉴的文案来自 UOJ—— 10 月 26 号,星期日晚上 7:00~10:00 开始公测! UOJ 就要迈出第一步了!欢迎大家来捧场! 由于是公测,目的主要在于测 BUG,所以是人民群众喜闻乐见的原题大战。 不过不用担心!我觉得我选的题还是蛮好玩的! 为了应景,题目难度、部分分设置都和联赛差不多,对于想要为 NOIP 准备的同学而言是个不可错过的机会! 赛后我们会有详细的题解。 出题人有 ydc, vfleaking。 题目三小时三道题的 OI 赛制, 难度高仿 noip, 大家也不用担心掉 rating, 因为这一场是 unrated 哟,还怕什么! 这是神犇强者展现实力,虐爆全场的时候! 这是大众选手增强信心,迈向未来的时候! 还等什么?来战吧! 有什么问题请在下面留言。 最后一版文案如下(还好当时截了个图,不然真就没记录了 2333) 以及当时做的宣传图,宣传图好像是 Kamigen 同学使用 SCP 同人图 P 出来的 Kamigen 小姐姐真的很认真负责,最后英语科试题的讲评是她讲的,虽然由于设备原因,笔记本噪音比较大,但是小姐姐甜美的嗓音还是非常动人的( 我记得当时答题卡,一直不知道该怎么还原一个好看的答题卡,于是我盯上了当时高中用的“好分数”平台。果然高中班主任老师的密码还是 6 位数生日,然后我就用他的权限做了各科的答题卡,导出后删除(抹除痕迹)。 从小试牛刀到一次突破——第二届退群杯 第二年,出题组们又开始“搞事情”了。今年大家想做一个“剧情向”的比赛,大家按照不同的顺序完成题目,可以解锁不同的剧情。 在这一年,出题组里又来了许多新血液——例如第一届退群杯受众 MikuNotFound 同学,搭建了第二届退群杯的前端。 这一次,退群杯甚至有了官网,用的是 KS 同学的域名和后端。大家可以通过在界面上注册登录进行做题,解锁剧情。 在staff 列表的同学们越来越多啦,大家不光可以展示自己的 id 和头像,还可以放上一句话简介。数学组比较会玩,而英语组就没能提前商量好😰。 附第二届退群杯相关知乎文档 2021 年退役 OIer 文化课交流群联合竞赛暨第二届“退群杯”预告 第二届退群杯的一些近况 第二届“退群杯”正式上线公告 第二届“退群杯”剧情与数值系统前瞻

2022/2/2
articleCard.readMore

Ubuntu 常见安装使用问题速查

放在前面 由于不同文章所遵循的开源协议不同,本文无法仔细梳理各个文章的协议,本文将以 MIT 格式开放,提前向各位作者表示歉意,如有问题请邮件至i#icys.top。 本文作者 icy 声明对文章作者可能存在的部分偏激或错误言论表示反对,不具有个人倾向。 链接仅为收藏时的推荐情况,作者 icy 会尽力筛选高质量且正确的文章,但不对文章质量及正确性作保证,对用户使用本文操作得到意料之外的结果不负责任。 本文不含有关于政治、宗教、肤色、性别歧视等内容,若本文推荐的链接在文章更新日之后出现不良及不正确的内容,与作者无关。 【下列文章正在施工中,如果您对以下文章列表有意见和建议,请邮件至i#icys.top。 安装前的选择 作为一个 Linux 新人,该如何选择发行版 请直接跳到最后—— 选用建议 如果是完全 0 基础的新手,只是想入门Linux的生态,体验Linux界面,那Ubuntu就非常合适 如果喜欢折腾和 DIY,好奇心满满,可以试试Arch、Manjaro、Gentoo这些 如果想用来部署服务,考虑稳定性,那CentOS、Debian都是不错的选择 当然这仅仅只是参考,最终的选择还是看个人需求和兴趣吧。 Linux 黑话解释:什么是长期支持(LTS)版本?什么是 Ubuntu LTS? 哪一种 Ubuntu 官方版本最适合你? x86,x64,x86-64,amd64,arm 指令集架构之间的关系 Ubuntu 服务器版与桌面版有什么区别? Ubuntu 中文官网 当然一般来说,对于运行在国内云服务商的服务器来说,使用云服务商的镜像肯定是没问题的。 虚拟机的配置 VMware Workstation Pro 下载 VMware Workstation Pro 由于版权问题,本文并不展示激活码,请大家自行购买或者使用其他方式获取。 VMware Workstation Pro 16 安装 Ubuntu 20.04 简易安装:虚拟机(VMware Workstation)安装 Ubuntu 简易安装 简易安装的缺点:无法在安装时换源、安装完没有中文语言,不过操作简单 普通安装:2021 安装 Vmware 和 Ubuntu 教程 如何在 VMWare 的 Ubuntu 虚拟机中设置共享文件夹 【Ubuntu 疑难杂症】虚拟机复制粘贴、文件夹共享及全屏效果 至于共享显卡来说,可能比较难,还是老老实实双系统罢。 VMware 中桥接模式,NAT,仅主机的区别 推荐使用默认设置 NAT,至于什么区别可以去看看,一般来说无需操作,可以去博客看看这三个模式有什么区别。 Virtual Box 2021 年全网最细 VirtualBox 虚拟机安装 Ubuntu 20.04.2.0 LTS 及 Ubuntu 的相关配置 其他 鼠标如何从常见虚拟机中切出 Virtual Box:右 Ctrl VMware:Ctrl+Alt KVM:右 Ctrl+右 Alt 环境配置说明 Ubuntu 设置中文界面 Ubuntu 语言设置里简体中文是灰色的问题 Ubuntu 安装中文输入法 如何在 Ubuntu 服务器上安装桌面环境(GUI) 常见命令、工具 包管理工具 apt Ubuntu 的 apt 命令详解 Ubuntu /etc/apt/sources.list 软件源格式说明 apt 和 apt-get 的区别 Ubuntu 镜像源使用说明 现可下载微软 Edge 的 Linux 稳定版了 常见编辑器 Vim / Vi vi 和 vim 的区别 Vim:如何退出 Vim 编辑器? 如何在 Vim/Vi 中保存文件并退出编辑器 VI/VIM 提示没有权限保存时的解决方法 Mousepad 有图形界面的文本编辑器,就像 Windows 下的 notepad Nano Linux nano 命令用法详解 Nano 保存等怎么操作在界面上都写着,很方便 宝塔 Linux 面板安装教程 怎样在 Ubuntu Linux 上安装 MySQL 如何在 Ubuntu 20.04 上安装 Nginx Ubuntu 下安装 Anaconda 的步骤 Ubuntu 搭建 Ftp 服务器 Linux cd 命令 cd、 cd ~、cd /、cd../、cd /home 讲解 Linux 黑话解释:什么是 sudo rm -rf?为什么如此危险? Linux 中的 Diff 和 Patch 【推荐】Ubuntu 安装多版本 python 共存 Understanding the /etc/passwd File Conda 类 清华源更换 创建 python 环境 更换 GCC 版本 使用 yaml 创建虚拟环境 常见问题 Linux Shell 管道详解 Linux 如何查看端口被哪个进程占用? Linux 用户及权限管理 修改文件所有、设置权限、二进制权限、掩码 Linux 软连接和硬链接 linux 如何修改文件名? Linux 学习 28-Linux 一行命令杀掉指定名称进程(killall 、kill 、pkill) Linux Shell 编程 Ubuntu 修改系统时间 Ubuntu 分辨率设置 Linux 磁盘挂载 Linux /dev 目录详解和 Linux 系统各个目录的作用 Linux 命令中的大于号、小于号的作用 Linux 常见错误 “cp: omitting directory”解决办法 Linux passwd 命令:修改用户密码 其实也可以使用图形界面改密码,不过密码太简单会不允许更改 Linux 给用户添加 sudo 权限 Linux 添加环境变量的五种方法 执行 sudo 命令时 command not found 的解决办法 Ubuntu 开机自动登录(命令行模式) 如果是有图形界面,在Setting->User accounts里面enable就行了 从 Windows 下解压压缩包或复制可执行文件后,在 Linux 无法正常运行或运行报错 一般来说是缺少可执行权限 x 权限,可以尝试sudo chmod +x -R xxxx/(如果希望递归添加),sudo chmod +x xxxx(仅文件或仅文件夹),成功后会让文件(夹)变绿,具体见下条帮助 Linux 的 ls 命令中文件颜色含义 在 Linux 后台运行脚本的方法和命令 Linux 中&&、&、|、||等特殊符号 如何更改 Ubuntu 的终端的字体和大小

2022/1/26
articleCard.readMore

基于 GitHub Actions + 宝塔 + DCDN 的 Hexo 博客配置

不知不觉博客已经开启接近两年了,一直以来本站使用的技术是阿里云全站加速+GitHub Pages 的部署方式。不过由于国内 CDN 回源 Pages 服务器还是存在着连接质量差的问题,在两周年之际,本站使用了基于 GitHub Actions + 宝塔 + 阿里云全站加速的搭建模式。 好用的 GitHub Actions Actions 是个好东西,一个月有 3000 分钟的私有仓库时长配额(GitHub Pro 或 GitHub Student Pack),普通用户也有 2000 分钟每月的私有仓库时长配额。值得一提的是,对于公开的仓库,GitHub Actions 是全免费、随便用的(单帐户同类镜像仅允许同时开启一个,否则会排队等待上一个 Job 执行完毕,单 Job 运行最长时间 6 小时)。 相比于Travis CI之类的持续集成工具来说,GitHub Actions 对同平台的仓库相比更加具有便利性(至少 clone 个代码是真心快😂)。 Actions 不只是可以做 Release 导出、项目构建之类的操作,由于其定时运行的特性,常被大家用来渲染账户成就(如 star 超过 3k 的Metrics,作者 icy 也部署了其自动生成个人 Profile),自动体温填报等操作。 Hexo 类博客与 GitHub Pages Hexo 是目前来说非常普遍使用的博客了,在 GitHub 上有许多主题,如本站使用的是闪烁之狐的matery主题,在此也再次向作者表示感谢。用户可以轻易通过几行代码就可以生成一个简单的博客,编写 markdown 的博客内容,并通过一句简单的hexo deploy或者hexo d就可以将自己博客部署到仓库中。 虽然 Hexo 最近一直在更新,不过 Hexo 很多功能插件的依赖项,爆出了安全漏洞,如hexo-renderer-marked使用的marked@^2.1.3,爆出了GHSA-5v2h-r2cx-5xgj和GHSA-rrrm-qjm4-v8hf安全漏洞,而截至目前(2022 年 1 月 21 日)插件维护方尚未对该插件的依赖版本升级至4.0.10以上。 为了更加的傻瓜式,GitHub 还提供了 Pages 服务,帮助直接将一个静态网站部署到https://<username>.github.io/<repository>/上。经过一段时间的自动部署,我们就可以访问自己刚刚部署好的博客界面了。 GitHub Pages 可以满足绝大多数海外用户的使用需求,因为 Pages 对于一个简单的非商业项目来说配额已经十分充足—— GitHub Pages sites are subject to the following usage limits: GitHub Pages source repositories have a recommended limit of 1GB. Published GitHub Pages sites may be no larger than 1 GB. GitHub Pages sites have a soft bandwidth limit of 100GB per month. GitHub Pages sites have a soft limit of 10 builds per hour. 配额说明来自于 2022 年 1 月 21 日的GitHub Docs,不过对于国内用户来说更大的问题是,由于海外带宽的限制以及一些原因,国内用户访问 GitHub 及 GitHub Pages 经常出现连接问题。自己好不容易搭建的博客,发现国内的朋友们,尤其是不太会科学使用网络的朋友们,打不开自己的博客,可能也会非常沮丧吧😢😱。 使用 CDN 分发与加速 既然 GitHub Pages 打不开,我们可能就想,有没有其他更合适的办法,让大陆用户正常地访问自己的网页呢?当然有——icy 和他的朋友KS就不约而同地使用了 CDN 分发和加速。内容分发网络 CDN(Content Delivery Network)可以将用户的请求负载均衡到不同的缓存节点,当用户的请求到达时,CDN 将判断访问者 IP,将请求按优先级分发给源站或最近缓存节点,以加快用户的请求速度。 以当前的场景来说,在网站设置了 CDN(设置解析、源站、设置缓存目录及后缀、设置缓存过期时限、配置 HTTPS 等)后,用户请求到 CDN 时,CDN 会先判断是否存在缓存,有缓存将请求转给缓存,没有缓存会由 CDN 请求源站,按照配置进行缓存,并将结果返回给用户。由于 CDN 和 Pages 的连接是畅通的,用户和 CDN 的连接是畅通的,于是通过 CDN 作为跳板,实现了 GitHub Pages 的高速访问。自然,也付出了 CDN 的使用费用(见CDN 是是什么可以吃吗)。 值得注意的是,如果使用国内 CDN,且对国内用户提供服务时,要求域名进行 ICP 备案。 使用服务器部署博客 既然使用国内 CDN 了,何不直接使用国内的服务器呢~ 在 2021 年双十一期间(活动已结束,价格供参考),腾讯云打出了 2 核 4GB 8Mbps 月流量 1200GB 的轻量应用服务器一年 70 元、三年 198 元的活动,吸引了许多建站开发者。按购买 3 年计算,月均消费 5.5 元,是非常适合学生党“折腾”的。 一般来说,我们的代码编辑仍然还是在自己的电脑上,而服务器仅仅是对于 Hexo 生成的静态文件的展示(一般来说不会在服务器上使用 Node.js 展示 Hexo 服务,因为对于静态网站,在线解析生成其实是一种浪费)。此时我们其实就可以使用上面所说的hexo d命令,把静态网站部署到Gitee上(因为服务器去访问 GitHub 还是非常困难的),然后在服务器上同步拉取即可。 同步拉取的方式,最简单的办法就是在服务器上设置循环脚本,每隔一段时间拉取仓库`。 git fetch --all git reset --hard origin/<branch> git pull 由于 Hexo 的部署是强制推送,不存储过往的界面,以减少整个仓库的大小,我们在拉取仓库的时候使用强制覆盖本地仓库的方式进行更新。考虑到 SSH 会话运行的程序在 SSH 连接断开后不太稳定,我们可以使用终端复用器 Tmux(terminal multiplexer),使得脚本在后台使用。 关于 Tmux,在阮一峰博客那里有一个很好的介绍,我们可以通过tmux new -s <session-name>创建一个新的会话,然后在会话里运行 Python 脚本,一个简单的 Python 脚本可能像这样: import os import time import threading while True: time.sleep(60) # 60 seconds os.system("git fetch --all") os.system("git reset --hard origin/master") os.system("git pull") 当然读者也可以通过写 bash 脚本解决问题。我们在刚刚建立的 session 中运行脚本后关闭 SSH 会话或按下Ctrl + B d将会话切回到后台,即可实现脚本的后台运行。 WebHook 循环拉取仓库好像挺傻的,不美观,那能不能让仓库主动去推送更新消息呢?WebHook 可以帮助我们了解这样的信息。 WebHook 是一种 API 概念,当仓库有变动时(新 Push、新 PR、新 Issue 等等),代码托管平台会给仓库预留的链接发送 POST 请求。我们一般在服务器的某个端口,监听这类的 POST 请求(用 Node.js、Python 等程序可以很快地编写一个监听 POST 请求的 Server,Python + Flask 的实现可以参考python+flask:实现 POST 接口功能,Go 语言可以参考GO 接收 GET/POST 参数以及发送 GET/POST 请求,Node.js 可以参考【node.js】处理前端提交的 POST 请求,其他语言不再列举)。根据GitHub和Gitee的文档,我们可以在服务器上解析平台上发生的事件,并进行一定的处理。 以监测平台有新提交自动拉取代码这个需求来说,我们可以设置相关的触发器,设置相关的钩子地址,并设置鉴权(以免其他用户滥发),当代码托管平台的仓库有了新提交,我们的服务器则会收到 POST 消息,以便实现。 作为 POST 的回应,建议在服务器上回复 JSON,并设置HTTP status 200,以免部分平台认定推送失败。 宝塔的 WebHook 不愿意自己写代码监听?宝塔软件商店里的宝塔WebHook可以帮你实现 WebHook 的接收。 在宝塔的软件商店中,搜索WebHook,找到宝塔WebHook,便可以在里面添加钩子。 添加完后,我们可以看到自己添加钩子的情况,包括钩子名称、添加时间、近期调用、调用次数等信息。我们还可以查看密钥查看钩子的密钥,以便鉴权。在查看密钥的界面,宝塔提供了一个示例的链接,其中参数包括密钥和脚本参数,我们可以按需进行调整,并把最后的链接放在代码仓库-设置-WebHook 的相应位置(由于我们的鉴权密钥在 URL 的参数上,所以对于 GitHub 和 Gitee 来说,密码处可以随便写)。 下面是 GitHub 和 Gitee 的 WebHook 设置示例: 做到这里,我们就可以让服务器自动跟进代码仓库的更新了。 使用 GitHub Actions 实现静态界面的生成 每次我们发现,自己的静态界面确实已经保存在代码仓库中了,而原始文件却没能保存。有的朋友会选择再建一个仓库专门提交原始文件,先提交静态界面,再提交原始文件,提交两次可能总是会遗漏,那有没有只提交一次的办法呢? 答案自然是肯定的,我们可以通过使用 GitHub Actions 实现静态界面的生成。 下面是一个简单的配置文件,修改用户名邮箱等信息后,将其放在原始博客仓库的.github/workflows/内,以 yml 格式为文件名后缀,配置就已经部署好了——吗? name: Hexo Deploy on: # 如果你的默认 branch 是 master,将下面的 main 改为 master push: branches: [ main ] pull_request: branches: [ main ] workflow_dispatch: jobs: deploy-github: runs-on: ubuntu-latest steps: # 设置服务器时区为东八区 - name: Set time zone run: sudo timedatectl set-timezone 'Asia/Shanghai' - name: Checkout source uses: actions/checkout@v2.4.0 - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: '12' - name: Setup Hexo run: | npm install hexo-cli -g npm install hexo-deployer-git --save npm install - name: Setup Git env: ACTION_DEPLOY_KEY: ${{ secrets.HEXO_DEPLOY_KEY }} run: | mkdir -p ~/.ssh/ echo "$ACTION_DEPLOY_KEY" > ~/.ssh/id_rsa chmod 700 ~/.ssh chmod 600 ~/.ssh/id_rsa ssh-keyscan github.com >> ~/.ssh/known_hosts git pull git config --global user.email "<email>" git config --global user.name "<username>" # 如果在自己的_config.yml已配置,则直接运行最后两条命令即可 - name: Deploy run: | cat >> _config.yml <<EOF # 自动部署配置 deploy: type: git repo: git@github.com:<username>/<username>.github.io.git branch: hexo EOF hexo clean hexo deploy 去部署一个仓库,我们当然是要提供一些权限让它有权更改目的仓库,我们到目的仓库<username>.github.io的设置界面,找到Deploy keys后在右上角添加一对公钥(为了避免后期权限混乱的麻烦,建议新建一对新的公钥私钥对,公钥私钥的生成方式可以参考Gitee 的帮助文档),将公钥放在Key区域,标题任取即可,注意勾选Allow write access,否则仅有只读权限,仍然无法部署。 现在目的仓库就认可了这个公钥,接下来我们要把私钥交给源仓库。直接放在仓库内是不保险的,因为我们 clone 了这个仓库就可以看到私钥明文,即便是私有仓库但是如果存储该仓库的主机被攻破,仍然可以得到私钥的明文。因此我们应该放在一个更加合适的位置,就比如仓库设置中的Secret区域。 我们在右上角添加新密钥,命名为HEXO_DEPLOY_KEY(如修改需要同步修改上面 yml 文件的名称)。密钥粘贴时,需将-----BEGIN OPENSSH PRIVATE KEY-----之类的标识行一同复制,在-----END OPENSSH PRIVATE KEY-----后最好换一行(即光标在密钥下一行)。 请注意,密钥写入后无法查看,只能覆盖,如丢失需要重新生成公钥私钥对。 此时,用于部署的仓库就有了部署权限,在每次用户的 Push 操作和 PR 操作后,可以把生成的静态目录推送的目标仓库了。 放在最后 篇幅有点长了,剩下的当作下期预告吧—— 使用 GitHub Actions 实现仓库从 GitHub 到 Gitee 的同步 使用 Gitee Pages 做一个合适的负载均衡 使用 Lint-md 让博客内容排版更加规范

2022/1/21
articleCard.readMore

孤独

孤独 好久没有更新博客了,在四六级与频繁的实验 ddl 之间,聊点别的吧 QAQ 最近看了一个 b 站比较火的日漫《国王排名》,点开后前两集都没撑下来就已经落泪了。可怜的王子波吉天生聋哑,又体弱无力,在武力崇高的背景下,只能沦落他人的嘲笑。身为王子,他不能一味的闪躲,必须正面抗下攻击,以更好地保护臣民。身为王子,他必须总摆出坚强的标签,在独自无人处孤自哭泣。 身为国王,他要做的不只是这些。在《国王 武士 祭司 诗人》中说到,“国王拥有主权去界定他国度的边界。在国界之内是祝福与繁荣,在国界之外是无秩序与混乱;他坐在大地的中心,将他的能量释放到国界内的各个角落,保护臣民免受外来侵袭,并且,如果有必要的话,支配武士来到边疆,进入战斗状态;国王放眼望去,用一种慈祥而充满力量的眼神看着他的臣民-而不像神圣男孩那样寻找被宠。他期望去知晓每一个臣民的价值,并给于赞赏,保护,奖赏他们对国度的贡献”。对于我来说,我恐怕很难做到,谁又不希望自己可以得到他人的宠爱,在为难当头有他人保护呢。 作为一名 985 的学生,作为一名拔尖计划学生,感觉自己也背负上了许多的压力,尤其是前往上海交通大学的致远夏令营之后。总会感觉有无数双眼睛盯着自己,认为自己理应做的比普通班的同学做得更好,在相关的决定上越发艰难,给自己带来很大的焦虑和压力。有的时候一些同学前来咨询问题,称呼大佬来大佬去,而自己无法提供帮助的时候,一种尴尬感油然而生。记得在七夕节的时候,自己有转发邓紫棋解解的《孤独》歌词。“原来孤独,是灯光下所有人对我佩服,但月光下却一直害怕自己退步”。这种“形象”,或者说“人设”,可能就不是那么好维护吧。 这可能就是所谓的“标签化”的结果,与其相反自己也碰上了另一个极端。高中时期,由于语文英语学科偏科弱项,导致最后总成绩在高中的拔尖班里到不了前列,在“请教和讨论问题只找比自己强的同学”的氛围下,其实我也是很渴望别人能问我一些文化课相关的问题的。而其实,在他们眼中,我或许就已经被打上“信息竞赛”标签了罢,来问我的好像只有有关如何自招综招的内容,有时确实会感到失落,这或许也是一种孤独吧。 或许是自己太害怕孤独了,总会找许多事情活的“现充”一点,来避免自己有时间考虑那些所谓的“孤独”。现在自己主要带队的团队和组织也有好几个了,确实在学生工作方面练出来了,尤其是不怕写大篇幅的策划之类的文案了(笑)。真的能作为一剂良方解决问题吗,我不知道。 知乎上说,人到大学,要学会孤独。学会自己一个人去图书馆学习,自己一个人吃饭,而不是与可能的狐朋狗友一起,为了聚餐浪费了更多的时间。说的很有道理,但我害怕做不到——可能是话痨本痨了 2333。自己经常混迹于各种群当中,个别群还刷一下存在感,可能是为了让大家对自己有影响,活在与他人的圈子中吧。 自己一个人看书,一个人跑步,一个人吃饭,一个人写代码的生活,又会是什么样子呢?突然想起来大学入学时候年级里一位非常特殊的同学,他由于疾病原因只能乘坐轮椅,在残疾人专用宿舍,进行着独自吃饭、独自前往上课、独自进行活动的生活。可能是当时一开始自己竞选班委,或许是什么其他的原因,摒弃其他人的不解,首先去了解他的困难,陪着他一起经历了军训期间许多时光。现在看来,可能是一个自己感到孤独的人向一个同样孤独的人的一种同情吧。在这也希望他能更好地生活,如以往一样继续坚强地走好人生路。 人们常说现在的城市是钢筋水泥浇灌的钢铁森林,行走在自己的城市当中,也些或产生一种距离感和陌生感。只身一人前往广场,看着一个个家庭在茶余饭后那些许闲暇其乐融融,却找不到自己在广场的落脚点——自己或许就是那无根的浮萍,随波逐流,走过小溪,走过乡村,走过城市,走过广场,那扎根于哪里呢?路途的前方在哪,接下来去哪呢? 人们总说,离开故乡,前往远方,我的故乡便或许是别人向往的远方,我的远方又或许是他们不愿久居的地方。当激情的潮水褪去,平平淡淡的生活里自己是否对自己之前选择的远方满意呢?又或是在人均焦虑的社会丢失了自己,或许不再为了曾经的梦想而单纯努力,在日常他人与社会的推动下,快马加鞭,忽略了的许多细节中,有哪些是当时自己的初心呢? 暑期和同学一起从电影到十笏园观光,一同坐在景区门口的摇椅上,互相吐露着心里话,在景区里互相调侃。其实双方都是互相羡慕的,那不妨把优势留好,一起为了各自的目标一起前行。这么看来,还有什么孤独的呢?但愿和一起学习、科研、娱乐的朋友们,一起水群的群友们,一起走向各自目标的终点站时,都不会后悔。 在万退群(退役 OIer 文化课交流群)的深夜电台里,我应该不止一次去吐露心声,可能也是第一次真正写篇文章挂在博客上。就像某学校横幅“祝每个有灵魂的 1 在计算机世界中找到属于自己的 0”那句玩笑话,希望留到最后的看官们在日常生活中,能有着自己精神不孤独的生活。

2021/12/19
articleCard.readMore

聊聊证书

聊聊证书 证书好像在网络中使用的越来越多了,我们用的绝大多数网站应该都已经上 HTTPS 协议了,这些协议需要服务器提供证书来证明他们的身份。我们通常的证明方式有两种,一个是分布式的,就类似于区块链,另一个就是证书这种层级式信任的了。 SSL 的连接方式 我们的 SSL 连接方式,使得客户端浏览器与服务器之间的连接进行了双向加密,保障了浏览的安全。下面的是 SSL 连接的简要步骤,具体可以参考 客户端的浏览器向服务器传送客户端 SSL 协议的版本号,加密算法的种类,产生的随机数,以及其他服务器和客户端之间通讯所需要的各种信息。 服务器向客户端传送 SSL 协议的版本号,加密算法的种类,随机数以及其他相关信息,同时服务器还将向客户端传送自己的证书。 客户利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过期,发行服务器证书的 CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。如果合法性验证没有通过, 通讯将断开;如果合法性验证通过,将继续进行第四步。 用户端随机产生一个用于后面通讯的“对称密码”,然后用服务器的公钥(服务器的公钥从步骤②中的服务器的证书中获得)对其加密,然后将加密后的“预主密码”传给服务器。 如果服务器要求客户的身份认证(在握手过程中为可选),用户可以建立一个随机数然后对其进行数据签名,将这个含有签名的随机数和客户自己的证书以及加密过的“预主密码”一起传给服务器。 如果服务器要求客户的身份认证,服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的 CA 是否可靠,发行 CA 的公钥能否正确解开客户证书的发行 CA 的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验如果没有通过,通讯立刻中断;如果验证通过,服务器将用自己的私钥解开加密的“预主密 码”,然后执行一系列步骤来产生主通讯密码(客户端也将通过同样的方法产生相同的主通讯密码)。 服务器和客户端用相同的主密码即“通话密码”,一个对称密钥用于 SSL 协议的安全数据通讯的加解密通讯。同时在 SSL 通讯过程中还要完成数据通讯的完整性,防止数据通讯中的任何变化。 客户端向服务器端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知服务器客户端的握手过程结束。 服务器向客户端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知客户端服务器端的握手过程结束。 SSL 的握手部分结束,SSL 安全通道的数据通讯开始,客户和服务器开始使用相同的对称密钥进行数据通讯,同时进行通讯完整性的检验。 证书的结构 每个证书均有公钥和私钥,其中私钥自己保存,公钥会放在证书内。除了私钥公钥外,证书还会包括证书内容信息$F$,加密算法$A$(通常是 SHA 和 RSA 加密),F 被两次加密后得到的密文$F’$。 ROOT CA 既然是层级式的,上层信任下层,那上层为什么可信呢,就类似于数学的公理,我们在信任链中就有了根证书,表示我们完全相信这个证书,只要是它相信的我们就都相信。 ROOT CA,如我们所见,有着特别大的权力,所以拥有这么大权力的证书的机构也为数不多,这些证书的公钥被放到了 Windows、Chrome 等的可信任列表里,作为我们信任的基础。那 ROOT CA 恶意捣乱的话,因为它没有上一层来管辖它(吊销证书),这样的危害力是蛮大的,只能每个把其放到信任列表的软件和系统,通过手动打补丁的方式来取消其信任(见CNNIC CA 事件),如果没及时打补丁,这个事件当时许多人只能手动拉黑该 CA。 层级式信任 ROOT CA 数量那么少,如果光让他们颁发证书,他们工作量便特别巨大。于是他们会去找一些他们信任的分支机构,让他们颁发证书。而二级 CA 也是不是太多,于是他们找了三级 CA 进行代理。我们一般的 SSL 证书(其实证书不光是 SSL 证书,还有的是为了给文件/程序添加数字签名的证书)大多都是由三级 CA 颁发的。 那二三级 CA 如果捣乱,给不该发证书的人(非域名所有者等)颁发了证书,或者二三级 CA 由于意外泄漏了私钥,一样会导致混乱啊。对于这种情况,上级 CA 便可以吊销下级 CA(或者用户)的证书。上级 CA 把这个证书放在吊销名单(CRL)中后,用户如果在浏览过程中,服务器返回这个证书,浏览器在请求 CRL 后发现在名单上,便会终止访问,提示浏览不安全。由于下一级 CA 出现问题,可以由上一级 CA 进行吊销,由此看来,根证书无人可以吊销,故上文所述根证书危害力较大。 那如何授权下级 CA(CA 颁发证书)呢?如果证书 A 目前已经被信任,而且具有颁发策略时,那这个证书所有者可以用私钥去加密想生成的下一级证书的内容部分$F$的 SHA 摘要,并把加密的信息$F’$也放在证书里,这样等浏览器去验证的时候,它可以用父证书的公钥去解密$F’$,与自行求出的$F$的 SHA 摘要进行比对,比对正确则可以确定该证书确实由其父级证书颁发而来,从而杜绝了父级证书作假的情况。 申请证书 对于单域名(没有通配符星号,如www.icys.top或者icys.top),可以直接去云服务厂商处申请一年的 DV 免费证书,但是如果想要含有通配符星号的证书,或者一个证书同时可以证明多个域名(使用者可选名称)的话,我们往往会选择使用 Let’s Encrypt 的三个月免费证书。 域名验证方式 常见的域名验证方式有两种,一个是 DNS 验证,另一个是文件验证方式。 DNS 验证 DNS 验证一般用于有 DNS 解析管理权限的用户,以及需要申请多域名证书的用户。 DNS 验证的方式是通过设置 TXT 解析,把 CA 要求的域名解析到对应的文本,一般一个域名仅验证一个文本。 其中 TXT 解析中,一个域名可以对应多段文本,大家在同时申请*.example.com和example.com的证书的时候,可能会提示你对同一个 domain 设定两段文本,大家一定注意不要覆盖掉了,否则会提示验证失败。 在设置好 TXT 解析的内容后,大家可以用命令行自行尝试一下解析是否正确 nslookup set type=txt acme_challenge.example.com 设置好就可以提交给证书服务商进行检查和证书颁发了。 文件验证 文件验证比较适合于,可以管理网站主页内容的用户,以及使用宝塔之类运维的用户。 注意,Let’s Encrypt 泛域名验证不能使用文件验证的方式。 证书服务商为了确定你的身份,会让你在网站根目录wwwroot设立一个 txt 文件,要求在外网可以访问到这个 txt 文件。当你设置好后,自我检测在www.example.com/xxxx.txt可以请求到相应的文本,检测所有权便成功。 云服务商 DV 证书申请 在阿里云-控制台-找到SSL证书(应用安全),选择左边的证书资源包,购买免费的证书资源包(免费证书扩容包)20 个。 购买完毕后,证书资源包处会显示当前证书总数 20,我们开始右侧的证书申请: 并选择消耗一次: 提交后,我们便发现控制台有一个未完成的证书申请请求,我们点击“证书申请”,会看到以下界面: 其中 CSR 可以填写可以不填写,若填写可以参考阿里云的相关文档。 按照要求完成验证后,证书提供商会在几分钟到几天内准备好证书,其中有 Apache、nginx 等不同环境所需的证书,按照要求部署即可。另外,如果使用阿里云的高防 DDOS、全站加速 HTTPS 等服务时,可以一键部署,减少麻烦。 宝塔的 Let’s Encrypt 证书申请 我们安装好宝塔面板,登录后,点击网站,点击自己要申请证书的网站(记得提前 DNS 解析到对应服务器,如果还没在宝塔建立网站,可以先建立再点击) 我们选择 SSL-Let’s Encrypt,按照对应验证方式选择,文件验证可以直接由宝塔完成,而 DNS 验证需要使用域名提供商的 DNS 管理接口(不过好处是支持通配符)。证书申请完成后证书会在有效期还剩一个月的时候由宝塔面板自动续期。 CertBot 的 Let’s Encrypt 证书申请 CertBot 的安装可以参考官网的说明,不过值得一提的是,国内安装 snap 出了名的慢,而且 snap 国内没有镜像站,只能通过代理+ProxyChains 的方式进行加速,推荐知乎抵拢倒拐的文章CentOS7 使用 Certbot 申请 Wildcard 证书。 省流:sudo certbot -d icys.top -d "*.icys.top" --manual --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory certonly 放在最后 2021 年 3 月 28 日,可怜的 icy 为他的社团用 CertBot 申请证书时,出现了Type: caa Detail: CAA record for oops-sdu.cn prevents issuance问题,经过v2ex 论坛中 17 层—— 我是给根域名签发,把根域名的解析 exampe.com CNAME another.domain.com改成 A 记录,就成功了 真实有效,解决了我的问题,特此膜拜一下 2333。 2022 年 8 月更新:关于这个问题到底是怎么回事,请见CAA 记录篇。

2021/2/17
articleCard.readMore

CDN 是什么可以吃吗

CDN 是什么可以吃吗 许多人的个人主页可能会部署在 GitHub Pages 上,不过由于众所周知的原因,GitHub Pages 的加载速度实在是堪忧,所以为了更好地面向国内的用户,我们可以考虑使用 CDN 进行加速。 什么事 CDN 呀 就像我们访问一些“不存在”的奇怪网站的时候,直接连接是不通的,需要一个代理来进行转发来科学上网一样,CDN 是用来解决资源加载太慢的问题。与科学上网不同,CDN 会在不同国家的节点上缓存自己网站的内容,对于已有的静态资源直接命中,未缓存的资源才会转发回源。而如今我们使用的,大多是全站加速 DCDN,它可以使得动态资源也可以成功加速,这部分资源的加速类似于代理的请求模式。 CDN 的资源包们 CDN 常用的计费方式一般是按量计费(因为按带宽计费太贵了 23333),对于最基本的用户来说,买个 100GB/年的下行流量包就足够了,毕竟我们也不用于分发大型文件嘛。 我们在购买资源包的时候,发现还有其他几种资源包,比如静态 HTTPS 请求数和动态请求数资源包。 HTTPS 请求数是云服务中比较恶心的东西(我感觉在请求过程中,对比不开 HTTPS,就多了证书验证的部分啊,为啥还需要额外收费)。如果我们 cdn 不使用 HTTPS 的话,我们加载出来的网页就会告诉我们部分不安全(部分浏览器会有个黄色的锁),而网页所有资源全都是 HTTPS 协议请求的话,一般是绿色的锁。动态请求常见于链接里那些带着问号,后面跟着参数的 URL,这个在 DCDN 里如果不设置忽略的话,这个就需要 CDN 去访问源网站求请求相关资源,消耗动态请求数。 不过好消息是,由于阿里的按量计费是每个小时进行结算的,他们规定“计费明细存在多小数位;汇总进位为 2 位小数时,产生的 3 位及以上小数的金额抹除”,这样其实就告诉我们,只要每个小时自己的消耗不超过 1 分钱,这个小时的请求费用就是免费的。本文编辑时(2021 年 2 月 16 日),静态 HTTPS 请求数的按量计费是 0.05 元/10000 次,也就是说只要每小时 HTTPS 使用不超过 2000 次就是免费的;动态请求数的按量计费是 0.15 元/10000 次,也就是大约每小时 666 次以内是免费的。 值得注意的是,云服务商的 CDN 通常会要求在国内加速的域名要进行 ICP 备案。 配置一个全站加速 配置全站加速 DCDN 第一步,确保自己的加速域名已经通过了 ICP 备案,否则申请加速是通过不了的。 添加域名 我们在阿里云控制台的全站加速模块中,添加域名,我们需要配置源站的相关信息,源站就是 cdn 没有命中回源(即去哪里找)的网站,不应与加速域名相同(如果源站域名与加速域名相同,则 cdn 在找不到内容后会请求自己资源,而显然 cdn 自己没有这个资源,就会继续请求自己……这样 cdn 一直找不到源资源文件)。 假设我们的加速域名为example.com,想加速example.github.io的 GitHub Pages,而且想即便访问example.github.io也可以重定向到example.com,我们应在 GitHub Pages 中配置 CNAME 为example.com,然后源站类型选择源站域名,填写example.github.io,端口 443(HTTPS)。 在提交之后,我们需要设置回源 HOST、静态文件(目录)、HTTPS 等。 设置回源 HOST 这一步是非常关键的一步,我就栽在这里一次。 回源 HOST 指全站加速节点在回源过程中,在源站访问的站点域名。 还是上面 GitHub Pages 的例子,我们需要设置 HOST 为加速域名,**而不是example.github.io**。如果选择example.github.io,GitHub 会由于我们配置了 CNAME,不给予资源文件,而是让 cdn 跳转到加速域名,导致无限循环。(参考blog) 配置静态文件类型/文件路径 这一步决定哪些文件会让 cdn 进行缓存(没缓存的会回源嘛)。一般我们会配置常见资源类型为图片文档等,我们也可以设置 html,css 等文件的缓存,而文件路径如果为/则表示网站的全部资源文件均需要进行缓存。 文件过期时间有几个默认的时间,我们可以按照自己实际情况酌情修改缓存时长。为了避免反复刷新缓存,变化可能比较快的资源建议缓存时长不要太大。 设置 HTTPS HTTPS 如果开启必然会造成一笔不小的 HTTPS 请求资源消耗费用,这部分费用甚至会比流量费还要贵一些,但是开启后会比较安全,建议购买资源包后开启。 获取 SSL 证书 对于 HTTPS,我们首先需要有一个加速域名的 SSL 证书。证书获取方式可以通过云服务商(推荐域名管理商或者 CDN 提供商,可以方便添加 TXT 解析或者方便证书的部署)获得的证书(通常为一年),或者 Let’s encrypt 的三个月证书。 可能有人问,为什么 Let’s encrypt 给的证书只有三个月有效期,根据官方的解释,90 天可以减少证书错误分发及密钥泄漏导致的损失,也可以鼓励大家进行自动部署。 获取证书的步骤我应该还会再写一篇博客的吧见“聊聊证书”。 HTTP2、TLS、强制跳转与 HSTS HTTP2 和新的 TLS 握手协议可以使得用户访问网站更加安全,比较建议打开。 强制跳转可以让以 http 协议访问的用户被自动跳转到 HTTPS 协议上,以防被中间人攻击。 而 HSTS 是告诉用户,未来 x 天内我这个域名只支持 HTTPS 协议。浏览器得知后,再以后的访问中无需跳转,浏览器会自动修改协议为 HTTPS 协议,减少被中间人攻击的可能。此外开启 HSTS 后,浏览器则不允许忽略证书错误,如果证书过期或者被攻击后,用户无法选择“忽略安全问题(不推荐)”来跳过这个错误,以免造成不必要的风险。 当然后两个开启会让 HTTPS 请求数进一步增加(原本是 http 的也 HTTPS 了),但是还是建议大家开启。 其他 在缓存配置-HTTP 头中,我们可以自定义 HTTP 头。这个的使用就比如自定义Access-Control-Allow-Origin。(这是一个跨域允许的 HTTP 头,我们在网站中通过引用或者 ajax 请求资源的时候,如果资源与访问域名不同,则属于跨域行为。如果请求的资源没有这个请求头则默认不允许跨域请求,强行请求会被浏览器拒绝;这个 HTTP 头的值为允许请求的域名,如为*则表示允许任意域名请求。)对于原网站不允许跨域的文件,我们可以自定义允许跨域的 HTTP 头,使得自己的域名允许被跨域访问。 访问控制中有一个 URL 鉴权和 Referer 防盗链,前者是需要适当的密钥进行请求资源,才能被 cdn 响应;后者是请求来源必须符合一定规则,但是 referer 只对浏览器请求有效,python 访问甚至可以自定义 referer。这两个综合起来的用途一般是只想在线播放,不希望用户下载的知识产权资源,可以通过后端返回合适的 URL(写在前端就没用了),然后供在线浏览使用。

2021/2/16
articleCard.readMore