阅读视图

发现新文章,点击刷新页面。

图解CodeWhisperer的安装使用

今天我们主要来了解一下codewhisperer的安装和使用,大家使用过程中的疑问可以一起交流。另外,参与亚马逊云科技云创计划即可免费体验各种云服务。

CodeWhisperer简介

CodeWhisperer是亚⻢逊出品的一款基于机器学习的通用代码生成器,可实时提供代码建议。

在编写代码时,它会自动根据现有的代码和注释生成建议。从单行代码建议到完整的函数,它可以提供各种大小和范围的个性化建议。CodeWhisperer 还可以扫描代码以突出显示和定义安全问题。

第一步:在pycharm插件搜索AWS并下载

第二步:打开AWS Toolkit视图(菜单View/Tool Windows/AWS Toolkit),点击"Developer Tools"tab⻚⾯,选择“CodeWhisperer/Start"

第三步:选择个人应用绑定自己的账号,选择allow之后就可以配置我们的IDEA使用了

在IDEA中使用

  1. 还是进行最简单的测试,在UI自动化,只写注释,然后CodeWhisperer会根据注释自动生成几段代码,可以根据自己的需要选择table键表示我们想要选择的,next、previous可以向前向后选择非常方便。

2.经过实际测试,在代码补全,根据注释生成代码方面,效果还不错,在注释生成代码方面,可以不断细化注释的描述,描述的越清楚,代码生成的精度更高,不得不说这款编程助手做的还是不错的,能大大提升办公效率。

3.提供的安全扫描功能,互联网的发展迅速代码安全检查是不能忽视的一个大头,我们使用CodeWhisperer中的Security Scan可以轻松的扫描代码,并更具扫描代码的结果更改我们代码中检测到的问题,上线的项目可以更加安全。

4.使用总结:在平时使用idea开发编码中,使用此插件,确实能如虎添翼,对于自动生成代码,代码提示。代码编写规范自动提醒。根据注释生成代码结构,能大大提高开发工作效率。之后会继续使用此插件,来减少开发量。同时也会向身边同事推荐此款插件,来提升团队开发能力。参与亚马逊云科技云创计划即可免费体验各种云服务。

借助 ControlNet 生成艺术二维码 – 基于 Stable Diffusion 的 AI 绘画方案

背景介绍

在过去的数月中,亚马逊云科技已经推出了多篇 Blog,来介绍如何在亚马逊云科技上部署 Stable Diffusion,或是如何结合 Amazon SageMaker 与 Stable Diffusion 进行模型训练和推理任务。

最近,亚马逊云科技核心级服务合作伙伴 eCloudrover(伊克罗德) 推出了基于 Stable Diffusion 的 AI 绘画解决方案——imAgine,既拥有经过广泛验证且易于部署的先进 AI 算法模型,又提供丰富且高性价比的云端资源以优化成本,旨在帮助游戏、电商、媒体、影视、广告、传媒等行业快速构建 AIGC 应用通路,打造 AI 时代的领先生产力。参与亚马逊云科技云创计划即可免费体验各种云服务

本文主要分享使用 Stable Diffusion 时的实战经验,以及使用基于 Stable Diffusion 研发的 imAgine 产品生成艺术二维码的最佳实践。

我们将以 QRCode 作为 ControlNet 的输入,使 QRCode 数据点融入到艺术图像中,同时仍然可以被 QRCode 阅读器扫描。借助这项技术,您可以将任何二维码转化为独特的艺术作品,以一种全新的方式来表达和传递信息。以下为几张图片案例:

Stable Diffusion 实战技巧

古语有云:“万事开头难”,“致广大而尽精微”。这对应了在 Stable Diffusion 实战中,最常遇到的两方面问题,一是如何选择合适的提示词起手式,来生成满足期望的图片;二是如何对图片进行细节优化,使最终产出的结果能够满足生产应用需求。

我们整理了以下内容作为推荐的最佳实践,希望对读者使用 Stable Diffusion 进行创作时提供参考。

提示词工程

随着 Stable Diffusion 版本不断迭代,AI 对语义的理解越来越接近“常识”之后,对提示词(Prompts)的要求也会越来越高。很多提示词上的误区有时会对绘图产生反作用。

Prompt的基本概念
  • 提示词分为正向提示词(positive prompt)和反向提示词(negative prompt),用来告诉 AI 哪些需要,哪些不需要。
Prompt的误区
  • Prompt 在于精确,不在于数量;用最简短的单词阐述画面,比自然语言要更有效。
  • 提升质量的描绘词绝不是无脑堆砌、越多越好。
  • 经常出现的起手式:“masterpiece”, “best quality” 等,很多时候会成为提示词中的累赘。这些词语在 NovelAI 时代是有意义的,因为当时 NovelAI 训练模型时大量使用了这些词汇来对图像进行评价;但在如今,经过 Civitai 上模型作者们不断重新炼制模型,这些提示词已经很难在生图结果中展现应有的作用。
调整提示词的权重
  • 词缀的权重默认值都是 1,从左到右依次减弱
  • 提示词权重会显著影响画面生成结果
  • 通过小括号+冒号+数字来指定提示词权重,写法如 (one girl:1.5)
注意提示词的顺序
  • 比如景色 Tag 在前,人物就会小,相反的人物会变大或半身
  • 选择正确的顺序、语法来使用提示词,将更好、更快、更有效率地展现所想所愿的画面
Prompt中的Emoji
  • Prompt 支持使用 emoji,且表现力较好,对于特定的人脸表情或动作,可通过添加 emoji 图来达到效果
  • 为了防止语义偏移,优先考虑 emoji,然后少用不必要的 with 一类的复杂语法
视角Prompt推荐
参数解释
extreme closeup脸部特写
close up头部
medium close up证件照
medium shot半身
cowboy shot无腿
medium full shot无脚
full shot全身

图片优化

很多时候我们生成了一张差强人意的图片,希望对这个结果进行进一步的优化,但往往不知道从何下手。这时您或许可以参考以下图片参数调优的最佳实践:

哪些参数需要调整
  • CFG Scale:图像与提示词的相关度。该值越高,提示词对最终生成结果的影响越大,契合度越高。

    • CFG 2-6:有创意,但可能太扭曲,没有遵循提示。对于简短的提示来说,可以很有趣和有用。
    • CFG 7-10:推荐用于大多数提示。创造力和引导力度之间的良好平衡。
    • CFG 10-15:当您确定提示是详细且非常清晰的,对图片内容有极明确的要求时使用。
    • CFG 16-20:除非提示非常详细,否则通常不推荐。可能影响一致性和质量。
    • CFG > 20:几乎无法使用。
  • Sampling Steps 迭代步数:步骤越多,每一步图像的调整也就越小、越精确。同时也会成比例地增加生成图像所需要的时间。

    • 对于大部分采样器,迭代越多次效果越好,但超过 50 步后就收效甚微。
  • Sampling method 采样方法:不同的采样方法,对应的最佳迭代步数是不同的,在进行对比时需要综合考虑。

    • Euler a:富有创造力,不同步数可以生产出不同的图片。并且这是一个效率较高的采样方法,可以用来快速检查 prompt 效果的好坏。
    • DPM2 a Karras:适合跑真实模型,30 步以后不好把控。
    • DPM++ 2M Karras:在高步数下表现优异,步数越高细节越多。
    • DDIM:收敛快,但效率相对较低,因为需要很多 step 才能获得好的结果,适合在重绘时候使用。
    • 不同模型与采样方法搭配出的结果也不同,以上仅供参考,在进行采样方法的选择时,最好使用 X/Y/Z 图表进行对比。
  • Seed 随机种子:随机种子值很多时候对构图的影响是巨大的,这也是 SD 生图随机性的最主要来源。

    • 保持种子不变,同样的提示词和模型,保持所有参数一致的情况下,相同的种子可以多次生成(几乎)相同的图像。
    • 在确定好一个合适的画面构图时,固定种子,对细节进行进一步打磨,是最合适的做法。
如何对比寻找最佳参数
  • 利用X/Y/Z图找最佳参数:通过使用 X/Y/Z 图,我们可以很清晰地对比不同参数下的结果,快速定位合适的参数范围,进行进一步的生成控制。

图片尺寸优化
  • 图片质量并不直接与图像尺寸挂钩。
  • 但尺寸在一定程度上影响了主题/图片内容,因为它潜在代表选择的类别(比如竖屏人物,横屏风景,小分辨率表情包等)。
  • 当出图尺寸太宽时,图中可能会出现多个主体。
  • 1024 之上的尺寸可能会出现不理想的结果,并且对服务器显存压力是巨大的。推荐使用小尺寸分辨率 + 高清修复。
优化多人物 / 宽幅单人物的生成
  • 单纯使用 txt2img 无法有效指定多人物情况下,单个人物的特征。
  • 较为推荐的方案是制作草稿 + img2img 或 ControlNet 的方式。
  • 宽幅画作+单人物生成最好打草图,进行色彩涂抹,确定画面主体;或使用 ControlNet 的 OpenPose 做好人物骨架。
  • 多人物确定人物数量,最好使用 ControlNet 的 OpenPose 来指定;该方案也适合画同一人物的三视图。
进行手部修复
  • 将图片送入 img2img inpaint,使用大致相同的提示词,将关于“手”的提示放在前面,根据希望手部特征变动多少来设置重绘幅度(如果只是希望手更完整,调至 0.25 以下),然后保留步骤和 CFG 与 txt2img 相同。
  • 找到一个满足期望的手部图片,借助 ControlNet 的 Canny 或 OpenPose_hands 等预处理器+模型,结合 inpaint 操作,能实现更精确的手部控制。
进行面部修复
  • 在绘制人物主体较小的图片时,经常会出现面部崩坏的情况。尤其是本文之后会介绍的生成艺术二维码流程,人物的面部经常会因为二维码码点的存在而崩坏。
  • 对面部的重绘,更推荐使用 !After Detailer 插件实现,通称 ADetailer。
  • 该插件会使用 yolo 算法对图片中的物体进行识别,我们设定其识别人物面部,并提供面部重绘的提示词和模型;该插件会在识别到的面部位置进行局部重绘,完成面部修复。
  • ADetailer 插件可以满足面部和手部的识别与修复。
  • 在 ADetailer 中也能引用 Lora 模型进行局部重绘生成。

借助ControlNet生成艺术二维码

Step1:优化二维码

二维码是一种借助特定几何图形分配,在二维空间上分布的、黑白相间的、记录数据符号信息的图形。二维码有多种不同的编码方式,我们此处采用通用度最高也是最基础的编码方式:QR Code。

输入的二维码是借助 SD 生成艺术二维码过程中最重要的部分之一。我们主要关心输入的二维码的以下两个特点:

1.二维码中包含的信息量

无论二维码采用何种编码方式,承载的字符信息越多,二维码在视觉上呈现的黑白结构就越复杂。复杂的结构很容易导致我们在生成艺术创意时,极大地收到二维码本身信息的掣肘。因此我们首先要想办法精简二维码中包含的字符长度

对于最广泛的应用场景,二维码通常会包含一个网页链接;为了提升二维码生成的美观性,我们首先需要对网页链接进行缩短。市面上的链接缩短工具有很多,您可以自由选择。但需要注意,在中国大陆境内请选择有域名备案的缩链平台,否则会被微信、浏览器等阻挡。

例如我们有一个希望制作成二维码的网址:https://www.ecloudrover.com/aigc/,通过缩链处理后为:http://c.suo.nz/7KZrF

通过下图可以比较直观地看出链接长短对于二维码视觉的影响,缩短的链接将更有利于我们接下来的创作。

2.二维码的呈现形式

随着技术发展,二维码不仅只支持黑白方块状的图案样式,定位点和码元都支持多样化的呈现,例如以下几种样式

在实际操作中,我们可以尝试多种不同的码点形式,以使得生图效果符合我们的预期。

下图展示了不同的二维码形式对最终效果图的影响:

生成参数:

Prompt: mountain, green grassland, sky, cloud, bird, blue sky, no human, day, wide shot, flying, border, outdoors, white bird, scenery
Negative prompt: easynegative
Steps: 40, Sampler: DPM++ 2M Karras, CFG scale: 6, Seed: 3943213078, Size: 872x872, Model hash: 876b4c7ba5, Model: cetusMix_Whalefall2, Clip skip: 2, ControlNet: "preprocessor: none, model: control_v1p_sd15_qrcode_monster [a6e58995], weight: 1.35-1.5, starting/ending: (0.05, 1), resize mode: Resize and Fill, pixel perfect: True, control mode: Balanced, preprocessor params: (512, 64, 64)", Version: v1.3.
Step2:制作基础二维码

了解了上述要点后,我们将要开始使用二维码制作工具,生成一个输入给 SD 的基础二维码。互联网上有多种网页二维码生成工具,您可以自由选择。同时为了方便您使用,我们在 Blog 专用的 AMI 中已经预装了 QRCode 生成插件,只要您从正确的版本中启用 AMI,都可以直接在 Webui 上看到下述的 QRCode Toolkit:

  • Anthony’s QR Toolkit:整合在 Webui 的 QRCode 生成与优化工具

https://github.com/antfu/sd-webui-qrcode-toolkit

接下来我们演示如何使用 Anthony’s QR Toolkit 来生成二维码,您可以参考下图完成二维码参数的配置。

完成二维码制作后,可以点击右侧的 “Download” 以下载到本地。或点击 “Send to ControlNet”,直接将二维码发送至 ControlNet 以进行下一步操作。

Step3:确定艺术风格

使用 Stable Diffusion 进行艺术创作的核心是选择合适的模型+提示词。我们在创作艺术二维码之前,建议先不使用 ControlNet,先进行一次普通的图片生成,以测试生图效果。

此处我希望二维码中有山川、蓝天、白云等自然景观,因此先使用以下参数,测试提示词和模型的生成效果。

生成参数:

Prompt: mountain, green grassland, sky, cloud, bird, blue sky, no human, day, wide shot, flying, border, outdoors, white bird, scenery
Negative prompt: easynegative
Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 4078355702, Face restoration: CodeFormer, Size: 512x512, Model hash: 876b4c7ba5, Model: cetusMix_Whalefall2, Clip skip: 2, Version: v1.3.2
Step4:在 ControlNet 中导入二维码

确认好图片风格后,我们将未经处理的二维码上传 ControlNet。请注意以下几个选项的配置:

  • “启用” 按钮:勾选以确保 ControlNet 在图片生成过程中生效;
  • 模型选框:请选择 “control_v1p_sd15_qrcode_monster” 来加强二维码的控制力度;
  • 控制权重:对于 qrcode_monster 模型,我们建议设置在 1.1-1.6 之间;
  • 引导介入/终止时机:介入时机建议在 0-0.1 之间,终止时机建议为 1

在文生图配置中建议调整两组数值:

  • 迭代步数:建议在 30-50 之间,默认值 20 不足以引导生成一个高质量的二维码图片
  • 宽度/高度:建议直接从 ControlNet 发送二维码原图的宽高比至上方

参数全部配置完成后,点击生成即可,可以看到此处我们生成了一个效果不错的图片,使用手机扫码测试也完全通过。

如果生成的二维码不能够达到期望,可以选择微调以下几个参数,并增加生成的总批次数,不断尝试抽卡以逼近最终期望的效果:

  • 提示词
  • 采样方法
  • ControlNet 控制权重
  • ControlNet 引导介入/终止时机

必要时可以选择使用 “脚本” 中的 X/Y/Z Plot,来对比不同参数下生成二维码的效果。我们此处对比了 ControlNet 的控制权重和引导介入时机:

参与亚马逊云科技云创计划即可免费体验各种云服务。云服务器 12 个月免费、虚拟服务器 VPS 3 个月免费、无服务器计算服务永久免费,更多详情请进入官网查看。

附录

附录1:ControlNet QRCode模型的选择

为方便您使用,我们在 Blog 专用的 AMI 中已经完成了 ControlNet QRCode 模型的植入,只要您从正确的版本中启用 AMI,都可以直接在 ControlNet 中选择模型。

截至目前,QRCode Monster 是我们测试后认为控制二维码成功率最高,也是二维码融入图像效果最好的模型,该模型可以在 HuggingFace 下载到:

https://huggingface.co/monster-labs/control_v1p_sd15_qrcode_monster

市面上也有另一个二维码模型:QR Pattern v2.0。该模型我们建议结合使用IoC Lab的 Brightness 模型作为辅助模型来提高局部对比度,也会产出不错的效果。但根据我们的测试,该模型自带的干扰内容较多,可能会导致图像风格发生很大的变化。这两个模型可以在下方链接下载:

https://civitai.com/models/90940/controlnet-qr-pattern-qr-codes

https://huggingface.co/ioclab/ioc-controlnet

附录2:如何使用 Stable Diffusion AI 绘图解决方案

imAgine 是一款由亚马逊云科技核心级服务合作伙伴伊克罗德,基于 Automatic1111 Stable Diffusion Webui,结合亚马逊云科技多种托管服务定制开发的AI绘图解决方案。imAgine 目前已经上线亚马逊云科技MarketPlace,用户能够在 Marketplace 中一键订阅,快速启动,无需进行复杂的环境配置,敏捷地在云上部署 AI 绘画环境。

同时还结合亚马逊云科技无服务器服务 Amazon API Gateway、AWS DynamoDB 等,将 WebUI 前端的训练、推理请求,无缝转发到 Amazon SageMaker 后端的专用推理、训练服务器上,实现算力的无缝扩展,并基于此架构基础实现前后端分离、精确的成本管控。

对于任何希望快速上手 AIGC 技术,并且希望得到全生命周期维护与技术支持的读者订阅并测试解决方案,限于篇幅,订阅 imAgine 解决方案的详细操作流程请参考 WorkShop 页面:https://catalog.us-east-1.prod.workshops.aws/workshops/facdf921-2eea-4638-bc01-522e1eef3dc5

参考链接

  • 使用原生JS实现Echarts数据导出Excel的功能

    Echarts toolbox 增加数据导出Excel的功能

    Echarts的toolbox提供了很多工具,例如saveAsImage(导出图片)、magicType(切换类型)等,具体的可以参考toolbox官方文档。toolbox原生提供的功能算是比较全面的了,但唯独缺少了一键将数据导出为Excel的功能。虽然可以通过toolbox中的dataView(数据视图)查看数据,然后复制粘贴到Excel中,但这种做法着实不够优雅。好在toolbox支持用户自定义工具。

    在自定义功能之前,需要注意的是,自定义的工具名字,只能以my开头,例如myTool1、myTool2......,具体示例可以参考toolbox.feature文档,示例代码如下:

    toolbox: {
        feature: {
            myTool1: {
                show: true,
                title: '自定义扩展方法1',
                icon: 'path://M432.45,595.444c0,2.177-4.661,6.82-11.305,6.82c-6.475,0-11.306-4.567-11.306-6.82s4.852-6.812,11.306-6.812C427.841,588.632,432.452,593.191,432.45,595.444L432.45,595.444z M421.155,589.876c-3.009,0-5.448,2.495-5.448,5.572s2.439,5.572,5.448,5.572c3.01,0,5.449-2.495,5.449-5.572C426.604,592.371,424.165,589.876,421.155,589.876L421.155,589.876z M421.146,591.891c-1.916,0-3.47,1.589-3.47,3.549c0,1.959,1.554,3.548,3.47,3.548s3.469-1.589,3.469-3.548C424.614,593.479,423.062,591.891,421.146,591.891L421.146,591.891zM421.146,591.891',
                onclick: function () {
                    alert('myToolHandler1')
                }
            }
        }
    }

    其中的重点就是onclick函数,我希望实现点击按钮自动下载Excel的功能,下面我先给出最终实现的代码:

    myTool: {
        show: true,
        title: '导出EXCEL',
        icon: 'path://M925.248 356.928l-258.176-258.176a64 64 0 0 0-45.248-18.752H144a64 64 0 0 0-64 64v736a64 64 0 0 0 64 64h736a64 64 0 0 0 64-64V402.176a64 64 0 0 0-18.752-45.248zM288 144h192V256H288V144z m448 736H288V736h448v144z m144 0H800V704a32 32 0 0 0-32-32H256a32 32 0 0 0-32 32v176H144v-736H224V288a32 32 0 0 0 32 32h256a32 32 0 0 0 32-32V144h77.824l258.176 258.176V880z',
        onclick: function(opt) {
            opt = opt.option;
            var cell, csv, csvContent, encodedUri, head, i, j, k, len, line, lines, link, ref, s, tr, tr_list, value, x, y;
            x = opt.xAxis[0].data
            y = [
                (function() {
                    var k, len, ref, results;
                    ref = opt.series;
                    results = [];
                    for (k = 0, len=ref.length; k < len; k++) {
                        i = ref[k];
                        results.push(i.name)
                    }
                    return results;
                })()
            ];
            y[0].splice(0, 0, "日期");
            value = [
                (function() {
                    var k, len, ref, results;
                    ref = opt.series;
                    results = [];
                    for (k=0, len = ref.length; k < len; k++) {
                        i = ref[k];
                        results.push(i.data);
                    }
                    return results;
                })()
            ][0];
            tr = "";
            csvContent = "data:text/csv;charset=utf-8,%EF%BB%BF";
            csv = y[0].join(",") + ",\n";
            head = "<tr>";
            ref = y[0];
            for (k = 0, len = ref.length; k < len; k++) {
                i = ref[k];
                head += '<th>' + i + '</th>';
            }
            head += "</tr>";
            tr_list = [];
            i = 0;
            lines = [];
            while (i < value[0].length) {
                j = 0;
                tr = "";
                tr += "<tr>";
                tr += "<td>" + x[i].replace(/,/g, " ") + "</td>";
                line = x[i].replace(/,/g, ' ');
                while (j < value.length) {
                    cell = value[j][i];
                    tr += "<td>" + cell + "</td>";
                    line += ", " + cell;
                    j += 1;
                }
                line += "\n";
                tr += "</tr>";
                i += 1;
                lines.push(line);
                tr_list.push(tr);
            }
            csv += lines.join("");
            encodedUri = csvContent + encodeURI(csv);
            var downloadLink = document.createElement('a');
            // 设置<a>元素的属性
            downloadLink.href = encodedUri;
            downloadLink.target = '_blank'; // 在新窗口中打开下载
            downloadLink.download = '气井分类.csv'; // 设置下载文件的名称
            // 将<a>元素添加到文档中
            document.body.appendChild(downloadLink);
            // 触发<a>元素的点击事件,开始下载
            downloadLink.click();
            // 下载完成后,从文档中移除<a>元素
            document.body.removeChild(downloadLink);
        }
    }

    从上往下看比较重要的几个参数,icon顾名思义就是按钮的图标,我从阿里巴巴矢量图标库中选择了一个类似于"保存"的图标。onclick函数可以传参数,这个参数具体代表什么我也不太清楚,在函数里log打印看看就清楚了,我个人觉得大概是类似于this之类的东西,里面保存了这个echarts对象的很多信息,其中就有完整的数据信息。csvContent设置的是保存文件的类型,我保存的csv格式的文件,类型名和文件后缀名必须对应上,否则就会出问题。常见的文件类型可以看MIME类型列表。其实大体设计思路就是将数据编码为HTML的表格(前端不会展示该表格),最终下载这个表格,<th>包裹的是最终导出Excel文件中每一列的列名。一个<tr>中是一种类别的数据,<tr>中一般来说会有很多<td>,每个<td>包裹的就是具体属于该类的每一个样本。我的数据如下图所示:

    导出的csv如下所示:

    后记

    其实在网上搜Echarts导出Excel字样,有很多大佬给出了解决方案,有些是用了第三方库,有些是基于Vue的,但是由于笔者并不会Vue,并且某些第三方库可能会和我本身的项目冲突,因此我才想着能否使用原生JS解决,不过由于我的JS水平也就属于半吊子,所以我自己写不出来,翻遍了搜索引擎也没找到用原生JS实现的代码。后来我是在Echarts的Github Issues中翻到了一位大佬的提问,从他的提问代码中窥探到了答案,在这里贴出这个Issue,并且感谢下这位大佬

    亚马逊实时 AI 编程助手 CodeWhisperer使用体验

    1. 什么是CodeWhisperer ?

    最近ChatGPT展现出强大AI能力给我们带来了深刻的影响,AI现在不是一个概念,基于AI的产品一定在各行各业帮助工作人员更快更好的完成繁琐的复杂的任务,提升工作效率,而在AI技术的发源地也就是码农圈,也早已经出现了一些好用的AI驱动的编程助手,这些助手可以在IDE中为我们补全代码甚至按照注释自动编写代码,基于AI技术,这些编程助手吸收了Github公开代码库和一些可公开代码库的数据样本,提供自动补全,语法检查、错误修复、导航跳转、类型与范围提示、参数补全、自动注释、代码生成、代码质量分析,漏洞检测等等功能。参与亚马逊云科技云创计划即可免费体验各种云服务

    AWS 2023/4月已正式推出Amazon CodeWhisperer,是亚马逊的用几十亿行开源代码训练出来的 AI 工具,它可以根据你的代码注释和现有代码实时生成代码建议。其中CodeWhisperer个人套餐,所有开发人员均可免费使用。

    Amazon CodeWhisperer目前支持多种语言(Python, Java, JavaScript, TypeScript, C#, Go, Rust, PHP, Ruby, Kotlin, C, C++, Shell scripting, SQL, and Scala);并同时支持多种IDE(JetBrains IDEs, Visual Studio (VS) Code, AWS Cloud9, AWS Lambda console)

    2. 试用

    我们以VS Code为例来做一个简单的体验

    首先是安装VS Code插件,AWS Toolkit是亚马逊云科技官方产品,现在集成了CodeWhisperer

    安装好了后,我们直接点击AWS Toolkit,并找到下面的CodeWhisperer,这是我们接着点击run,启动CodeWhisperer

    然后我们注册或者登录AWS Builder ID

    当出现如图的绿色的提示就代表完成

    3. 上手体验

    当我们写完后,我们简单的测试下,发现结果是正确的,此外我们还可以进行代码安全扫描和代码来源检查

    当然无论你多么信任CodeWhisperer或者其他的AI辅助工具,你都需要人工检查代码正确性并做好单元测试,AI辅助工具主要是减少你在互联网上搜索或者查看文档的时间,至于代码的正确性和效率,需要你来核对

    2023总结

    2023对我来说是改变非常巨大的一年,首先从身份的转变上,这一年我终于结束了我的求学生涯,正式从学生变成了一名打工人。“读了20几年书,以后终于不用再读书了”,快要毕业的时候我总是这么想着,以为即将脱离苦海,但其实无非是从一个苦海跳到另一个苦海罢了。接着从财富上来说,工作意味着有了稳定的收入来源,终于可以自己想买什么就买什么,由于我是果粉,并且极度讨厌华为(如果看到这里你产生了某些心理上的不适,请退出这篇文章),因此10月一发工资我就果断入手了iphone 15 pro,同时给自己买了一份保险,每年9000块钱,年底在小县城看上了一套二手房,付了1.5w的购房订金,除此之外还海淘了不少中古游戏,以及各类奇奇怪怪的电子产品,前前后后加起来又花了1w左右。本来到这儿几乎快把我上4个月班的工资花光了,但是年底发了一笔年终奖,又给我回了口血

    今年是我代码能力提升最快的一年,实际上直到上班之前我都好久没写过稍微复杂的代码了。我入职的单位并不是互联网公司,同事也几乎没有计算机专业的,不过领导非常赏识我,希望我能发挥所长,利用编程来解决问题,我非常感谢部门领导,可以说他对我有知遇之恩。入职之后我写过爬虫、Excel数据处理、Flask+Layui+JS网站搭建、Windows桌面应用程序自动化等,详情可以查看我的这期视频。可以说除了爬虫和Excel数据处理是我以前接触过的,剩下的全是从零开始学,但是为了快速解决问题,实际上也没有那么多时间真的让你从头学起,无非就是点开API文档快速看一下示例,然后一点一点Debug把功能实现。说实话,我非常享受这种极限编程的感觉,快速学会一个库的核心功能,快速上手,快速Debug,中间不会的快速查资料解决,以达到短时间完成工作的效果,这非常有挑战性也很有成就感,尤其是同事在使用时对你表示由衷的赞叹,每每这时我都会觉得:“计算机真是学对了,计算机就是世界第一专业!”

    今年是我特别注重健康的一年,可能让大家很讶异的是,我略微有点酒瘾,尤其喜欢喝啤酒,我非常享受那种微醺的感觉。但是今年无论是家庭聚餐,还是在外和同学、同事吃饭,一年总共也就喝了不超过500ml的啤酒,除了谢师宴喝了一点白酒,剩下的时间几乎是滴酒不沾。往大了说酒精是一类致癌物,往小了说,在代谢酒精的过程中,会消耗体内大量的维生素,时间长了还会导致酒精肝、痛风等等,因此在23年年初我就定下了目标:要戒酒。回顾这一年,这一目标也算是达成了。除了戒酒以外,几乎每天我都有吃各种各样的补剂,例如复合维生素、益生菌、鱼油等等,因为我比较挑食,具体来说我只喜欢吃肉,不爱吃素,这就导致我的营养摄入不均衡,因此我才选择额外摄入一些营养补剂

    今年是充满遗憾的一年,每当学术界有什么爆炸性的新闻时,我总会想:“要是我当初选择读博就好了”,我对计算机领域内的所有事情仍然保持着最大的好奇,我也曾不止一次的想紧跟学术前沿,可是最后却发现实在没那个精力,就拿今年比较火的文生图为例,我甚至从来没有亲自生成过一张图片,一方面是我实在懒得去研究如何部署模型,另一方面是我不知道该生成什么图片,于是也就懒得去找在线Demo,就好像大部分人第一次使用ChatGPT时不知道该说些什么,也就只能试探性的发送:“你好”便作罢了。今年同样有很多事情出乎我的意料,不过涉及到隐私,解释起来比较复杂,也就不在此赘述了

    总的来说,今年对我来说有很特别的意义,我毕业了、将自己剩下半辈子的人生埋葬在了一家公司、即将拥有属于自己的房子。我对自己24年的期望是,B站达到1w粉、去日本旅游、尽量别再刚愎自用

    免费AI代码生成器Amazon CodeWhisperer初体验

    简介

    随着ChatGPT的到来,不由让很多程序员感到恐慌。虽然我们阻止不了AI时代到来,但是我们可以跟随AI的脚步,近期我发现了一个神仙AI代码生产工具CodeWhisperer ,它是一项基于机器学习的服务,其根据自然语言注释和集成开发环境(IDE)中的代码,生成代码建议,帮助提高开发者生产力。参与亚马逊云科技云创计划即可免费体验各种云服务。云服务器 12 个月免费、虚拟服务器 VPS 3 个月免费、无服务器计算服务永久免费,更多详情请进入官网查看。

    接下來就跟随我的脚步来看看这款VSCode插件的使用方式吧。

    安装使用

    • 开发工具:Visual Studio Code(VSCode)
    • 打开工具拓展安装(快捷键:Ctrl + Shift + X),然后搜索AWS或AWS Toolkit,如下图所示

    • 安装完成之后,按照下图步骤进行登录,偷偷告诉你,目前可以免费使用呦。

    • 根据弹窗出来的操作,复制 => 打开aws网站,黏贴验证码 => 进行aws账号注册(特别提醒,密码需要3中字符以上)=> 然后会出现允许aws在你的VSCode上使用
    • 完成上诉步骤之后,点击下图位置,开启AI代码生成之路

    • 无线的代码联想,让你为所欲为,大大提升了你的划水时间,话不多说,上代码,图1:插件代码联想,图2:按下Tab键之后生产的代码。

    • 简单的业务描述,入参定义,它就能够帮你完整实现逻辑,联想过程中,最下面的状态栏CodeWhisperer会转动。

    • 上下文联想,让你欲罢不能。

    总结

    相对其他GPT代码工具,使用方便,上下文联想强,同时CodeWhisperer还可以再代码中检测潜在的错误或问题,并向开发者发送警告,以便他们可以尽早解决这些问题,重点是免费免费免费,重要的事情说3遍。参与亚马逊云科技云创计划即可免费体验。

    Amazon Aurora MySQL 和 Amazon RDS for MySQL 集群故障转移和只读实例扩容时间测试

    1 测试背景

    Amazon Aurora MySQL 是与 MySQL 兼容的关系数据库,专为云而打造,性能和可用性与商用数据库相当,成本只有其 1/10。

    Amazon RDS for MySQL 让您能够在云中更轻松设置、操作和扩展 MySQL 部署。借助 Amazon RDS,您可以在几分钟内部署可扩展的 MySQL 服务器。参与亚马逊云科技云创计划即可免费体验各种云服务。云服务器12个月免费、虚拟服务器VPS 3个月免费、无服务器计算服务永久免费,更多详情请进入官网查看。

    客户在使用亚马逊云科技托管 MySQL 数据库服务时,通常需要选择 Amazon Aurora MySQL 或 Amazon RDS for MySQL。本次测试是对比 Amazon Aurora MySQL 和 Amazon RDS for MySQL 在不同模式、不同机型、有无工作负载情况下的集群故障转移时间和只读实例扩容时间,为客户在亚马逊云科技上选择托管 MySQL 数据库服务提供参考。

    2 测试环境

    被测服务Amazon Auron MySQL和Amazon RDS for MySQL
    测试区域孟买区域(ap-south-1)
    测试版本Amazon Aurora 2.11.2 (MySQL 5.7)
    Amazon RDS for MySQL 5.7.41
    测试机型AmazonAuroraMySQLdb.r5.2xlarge和db.r5.xlarge
    Amazon RDS for MySQL db.m5.4xlarge # db.m5.2xlarge
    部署模式AmazonAuroraMysQL采用跨AZ部署,一写一读和一写二读两种模式
    AmazonRDSforMysQL采用Multi-AZ实例部署,一写一读和一写二读两种模式
    压测实例c5.12xlarge*1
    压测软件sysbench (https://github.com/akopytov/sysbench)

    3 测试前提

    本次测试基于以下 3 个前提:

    • 压测实例、Amazon Aurora MySQL 和 Amazon RDS for MySQL 均在一个 VPC
    • Amazon Aurora MySQL 和 Amazon RDS for MySQL 均使用生产模板的默认配置
    • 开启 Amazon CloudTrail 分别统计集群故障转移和只读实例扩容的开始、结束时间

    4 测试架构图

    4.1 Amazon Aurora MySQL 测试架构图

    4.2 Amazon RDS for MySQL 测试架构图

    5 测试用例

    5.1 集群故障转移时间测试用例,测试基于以下8种配置模式,分别测试无法工作负载和有工作负载两种情况下的集群故障转移时间

    *工作负载场景:数据库存储100GB数据,主节点80%CPU工作负载

    5.2 只读实例扩容时间测试用例,测试基于以下 8 种配置模式,分别测试无工作负载和有工作负载两种情况下的只读实例扩容时间

    *工作负载场景:数据库存储 100GB 数据,主节点 80%CPU 工作负载

    6 测试方法

    6.1 集群故障转移时间测试方法

    1.对于Amazon Aurora MySQL,在控制台上,选择目标集群的写入实例并点击下图中的“故障转移”按钮:

    2.点击“日志和时间”,在下方的近期时间里查看故障转移开始和结束时间,计算出故障转移花费的时间:

    3.对于 Amazon RDS for MySQL,在控制台上,选择目标集群的主实例并点击下图中的“重启”按钮,在下一个页面勾选“是否进行重启和故障转移”,点击确认:

    4.点击“日志和事件”,在下方的近期事件里查看故障转移开始和结束时间,计算得出故障转移花费的时间:

    5.在模拟工作负载的场景下重新统计时间,模拟工作负载的步骤如下:

    sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --threads=64 --mysql-host=bench-test.cluster-cum78jhrtci1.ap-south-1.rds.amazonaws.com --mysql-user=admin --mysql-password=xxxx --mysql-port=3306 --mysql-db= bench _test --oltp-tables-count=100 --oltp-table-size=5000000 --db-driver=mysql prepare
    • 按照如下命令,对主节点进行压力测试
    sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --mysql-host=bench-test.cluster-cum78jhrtci1.ap-south-1.rds.amazonaws.com --mysql-user=admin --mysql-password=xxxx --mysql-port=3306  --mysql-db= bench_test --max-requests=0 --oltp-simple-ranges=0 --oltp-distxinct-ranges=0 --oltp-sum-ranges=0 --oltp-order-ranges=0 --time=3600 --oltp-read-only=on --threads=120 run #可以通过调整 threads 来控制工作负载,不同数据库实例类型线程数不一样

    6.2 只读实例扩容时间测试方法

    1.对于 Amazon Aurora MySQL,在控制台上,选择目标集群并点击下图中的“添加读取器”按钮:

    2.使用 CloudTrail 里 CreateDBInstance 事件的时间作为添加只读实例的开始时间:

    3.回到控制台,在目标集群 “日志和事件”里使用最后一步的时间作为添加只读实例的结束时间:

    4.对于 Amazon RDS for MySQL,在控制台上,选择目标集群并点击下图中的“创建只读副本”按钮:

    5.使用 CloudTrail 里 CreateDBInstanceReadReplica 事件的时间作为添加只读实例的开始时间:

    6.回到控制台,在目标集群“日志和事件”里使用最后一步的时间作为添加只读实例的结束时间:

    7.在模拟工作负载场景下重新统计时间,模拟工作负载步骤如下:

    sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --threads=64 --mysql-host=bench-test.cluster-cum78jhrtci1.ap-south-1.rds.amazonaws.com --mysql-user=admin --mysql-password=xxxx --mysql-port=3306 --mysql-db= bench _test --oltp-tables-count=100 --oltp-table-size=5000000 --db-driver=mysql prepare
    • 按照如下命令,对主节点进行压力测试
    sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --mysql-host=bench-test.cluster-cum78jhrtci1.ap-south-1.rds.amazonaws.com --mysql-user=admin --mysql-password=xxxx --mysql-port=3306  --mysql-db= bench_test --max-requests=0 --oltp-simple-ranges=0 --oltp-distxinct-ranges=0 --oltp-sum-ranges=0 --oltp-order-ranges=0 --time=3600 --oltp-read-only=on --threads=120 run #可以通过调整threads来控制工作负载,不同数据库实例类型线程数不一样

    7 测试数据

    7.1 集群故障转移时间测试数据

    表格记录时间均为 3 次测试的平均时间

    7.2 只读实例扩容时间测试数据

    表格记录时间均为 3 次测试的平均时间

    8 测试结论

    1. Amazon Aurora MySQL 的集群故障转移时间与读写模式、实例机型、工作负载相关性较小,整体时间分布在 29 秒-41 秒之间。Amazon RDS for MySQL 的集群故障转移时间与读写模式、实例机型相关性较小,与工作负载相关性较大,在无工作负载时为 50 秒-65 秒,有工作负载时增加至 85 秒-93 秒,有工作负载的情况下故障转移时间变长。
    2. Amazon Aurora MySQL 的只读实例扩容时间与读写模式,实例机型、工作负载相关性较小,整体时间分布在 6 分 08 秒-6 分 57 秒之间。Amazon RDS for MySQL 的只读实例扩容时间与读写模式,实例机型相关性较小,与工作负载相关性较大,在无工作负载时为 6 分 12 秒-7 分 1 秒,有工作负载时增加至 15 分 19 秒-15 分 31 秒,有工作负载的情况下只读实例扩容时间变长。
    3. 对比 Amazon Aurora MySQL 和 Amazon RDS for MySQL

      1. 在无工作负载的情况下,Amazon Aurora MySQL 集群故障转移时间为 Amazon RDS for MySQL 的 64%,Amazon Aurora MySQL 集群故障转移时间更短。
      2. 在无工作负载的情况下,Amazon Aurora MySQL 的只读实例扩容时间为 Amazon RDS for MySQL 的 96%,两者相差较小。
      3. 在有工作负载的情况下,Amazon Aurora MySQL 集群故障转移时间为 Amazon RDS for MySQL 的 33%,Amazon Aurora MySQL 集群故障转移时间更短。
      4. 在有工作负载的情况下,Amazon Aurora MySQL 的只读实例扩容时间为 Amazon RDS for MySQL 的 42% ,Amazon Aurora MySQL 只读实例扩容时间更短。

    综上所述,Amazon Aurora MySQL 无论是在集群故障转移时间还是只读实例扩容时间都优于 Amazon RDS for MySQL。

    转自亚马逊云科技

    关于毕业和未来展望

    各位同学大家好!这篇文章我想简单对自己研究生三年做个总结,至于为什么是“简单的总结”,因为实际上我读研期间一直有在写各种总结的blog,所以这篇文章中也不需要重复赘述。另外也想和大家分享一些这半年的所思所想,主要是两点:关于毕业和未来展望(工作与生活)

    关于毕业

    对我来说,2023年上半年几乎没有别的事比毕业更重要了,或者说,没有别的事比写出一篇合格的毕业论文更重要。自从2月底到了学校以后,我每天的大部分时间都是在实验室度过的,写论文固然重要,可是身体以及心理状态也很重要,这里简单说说我每天的饮食以及生活作息,供大家参考。早餐是一定要吃的,如果在家(湖北),我一般会选择吃一碗汤面,但其实早餐吃碳水并不算多健康,毕竟摄入过多碳水会让人犯困,另外碳水也仅仅只能提供能量,至于维生素和微量元素只能说几乎没有。在学校的时候,我每天早上只买两个鸡蛋,偶尔配一杯不加糖的豆浆。午餐倒没有什么特别要注意的,无非就是多吃点,吃的种类多一点。晚餐也没有什么特别的讲究,不需要吃太多,以瘦肉、蔬菜为主即可。当然了,我们大部分人并不是健身爱好者,也不需要特别控制体重、体脂率,因此每一顿吃什么也不必太过纠结

    长时间的学习工作不一定会得到很好的效果,因此需要控制时间,适当放松。例如我每天下午6点左右就会离开实验室,围着操场跑20分钟。说到跑步,其实我从没有这个习惯,或者说我根本就不喜欢任何体育运动。主要是由于写毕业论文那段时间压力太大,正好我室友有跑步的习惯,他问我要不要考虑跑跑步释放一下压力,跑了几天以后发现确实人的精神要好很多,于是便坚持了下来,实际上也没有坚持多久,也就跑了大概一个月左右便放弃了(因为真的很累)。晚上我从不去实验室,因为我认为睡前的几个小时是属于自己的娱乐时间,可以看看直播或者打打游戏缓解一天学习的压力。我几乎不熬夜,一般11点整就上床睡觉。我室友是个夜猫子,不过这次来学校以后他的发际线明显有点问题,于是他立了个flag,说是只要我上床,他就必定在20分钟内也上床。不过上床不等于睡觉,就我所知,他虽然上了床,可仍然在刷手机,所以发际线问题也没能得到缓解(现在正在考虑抹药)

    前面是生活部分,下面讲讲毕业相关的事。我们学校大概是4月初需要将毕业论文进行查重,意味着我们需要在此之前将毕业论文写完。查重通过后一个星期左右申请预答辩,预答辩通过的同学可以参加论文盲审,一部分同学被抽中教育部盲审,也就是送到其他学校,给其他老师审。剩下大部分同学提交到学院内进行双盲审。也不知道运气好还是不好,我就被抽中了教育部盲审。从盲审到出结果,中间大约有一个月的时间,这段时间其实并不忙,或者说完全闲下来了,毕竟此时自己再如何努力也没用,自己的命运已经不掌握在自己手里了。这段时间也是大家“最后疯狂”的一段时间,有的同学选择出去旅游,有的同学在进行春招,还有的同学(例如我)选择在宿舍摆烂。但无论每个人在做什么,其实都在等待着悬在头上的达摩克利斯之剑落下的那天。

    达摩克利斯之剑(The Sword of Damocles)的说法源自古希腊传说:迪奥尼修斯国王(Dionysius)邀请他贪婪的大臣达摩克利斯(Damocles)坐在自己的宝座之上掌管王位,达摩克里斯却发现自己坐在用一根马鬃悬挂的一把寒光闪闪的利剑下,仓皇而逃。

    迪奥尼修斯王用这个故事说明,国王的幸福和安乐都是假象,极大的财富和权力也意味着巨大的责任和危险。

    5月中旬的某一天盲审结果公布了,有人欢喜就有人忧,通过的同学自然欢喜,没通过的同学想必心里并不好受。盲审通过的同学就可以参加毕业前的最后一步——答辩。我依然忘不了我的答辩日期:5月24日,倒不是那天有多特别。诚然,答辩前和答辩结束的几天内,这个日子确实让人紧张以及具有纪念意义,可是之后这种感觉就慢慢淡化了。所以令人难以忘记,只是因为我的生日是11月24日,两个24正好重复罢了

    总的来说,我们学院的延毕率不算低。应该说自从“翟天临”事件以来,全国大部分高校的研究生延毕率相较以前有所上升,这里我只叙述整体的客观事实,并不想对此多加评论

    通过答辩之后我就又进入了一段摆烂的阶段,好像答辩通过,我人生的一道大坎儿也通过了一样,每天继续看看书,打打游戏

    未来展望(工作与生活)

    在之前的文章里我提到过,去年秋招我应聘的岗位是中石化江汉油田的信息技术岗,正好最近单位也发了通知,我们需要在7月12日之前去潜江报到,报到之后会进行一段时间的培训,培训结束了再分配到工作岗位。距离报到还有一段时间,因此我打算在7月2日去一趟苏州,实际上苏州以前我就去旅游过,而且我也不觉得夏天适合去江南地区游玩,主要是因为我想线下观看一次LPL比赛,正好7月2日是LNG在苏州主场对战OMG,我是LNG粉丝,我妹是OMG粉丝,我俩一拍即合决定一块儿去。看完比赛之后我想一路向东,去看看海,顺便吃几顿海鲜大餐

    再说说这段时间的计划,首先我要完成可能是最后一个与学习有关的视频——prompt的代码实现。这个视频我之前就说过要做,只不过因为毕业的事儿一直搁置到现在。另外,我深感以后写博客的频率不会很高,每年花一笔钱在服务器和域名上有些浪费,所以我要考虑将博客迁移到github上,这样以后就不用花钱续费服务器和域名了

    最后这一段算不上未来展望,但是我不知道写在什么地方比较好,所以就干脆放这里了。不知道从什么时候开始,随着时间的推移,我离学术界越来越远,业界最新的技术、方法我一点也没有去仔细了解原理,也没有仔细看过论文。每天都会有这样的情况发生,我关注的公众号按时发布了一条关于NLP最新技术或者方法的剖析,我看着标题以及配图,感到很好奇,非常想要了解其中具体的内容,但不知道为什么,我就是没有点进去阅读的欲望。仔细想想,这其实是我的好奇心和懒惰所产生的矛盾。不仅是学术,我对这个世界很多未知的东西仍然保有着最大的好奇,但同时我又是一个懒惰的人,我的懒惰致使我不想跨出舒适圈。现在是如此,等工作以后,我更没有精力去了解其他东西了。刚学计算机的时候,我真的觉得编程很有意思,凭借我对计算机的热爱,到了30岁甚至40岁肯定还能写得出代码。现在我越来越觉得当年的想法是一个很难完成的flag,我也能理解为什么有些程序员出身的大佬到最后也只能纸上谈兵。不过人的一生,代码并不是全部,就算到了40岁写不出来代码也无所谓,毕竟古语有云:吾生也有涯,而知也无涯,以有涯随无涯,殆已

    致谢

    “终于要毕业了”,我常常会这样想。伴随着对未来的一丝期待和恐惧,我想对自己的研究生生涯,甚至是学生生涯做一个不算正式的告别。

    “研究生只有刚考上和毕业时才是快乐的”。诚然,考上研究生的那一刻,我确实感到了无限的喜悦,当下有多少考生为了薄薄一张入学通知书正在奋笔疾书,可是每年成功上岸的却又寥寥无几,与他们相比,我是幸运的。而此刻即将毕业的我,同样也因为两张薄薄的证书正在努力奋斗。扪心自问,回首这三年研究生生涯,快乐的瞬间其实并不少:每个月助学金到账的时候、每学期导师发科研津贴的时候、论文被期刊接收的时候、拿到奖学金的时候......如此看来,三年的时光似乎并没有让我摆脱低级趣味,我仍然是一个功利、庸俗的普通人,可是做这样一个普通人又有什么不好呢?从始至终都是如此,我们登上并非我们所选择的舞台,演出并非我们所选择的剧本。悲剧的是:剧本是好剧本,而我不一定是位好演员。

    “关键是要问题驱动”,这是我的导师---教授常挂在嘴边的一句话。或许在研究生期间我读的论文没有其他人多、发表论文没有其他人多、交的女朋友也没有其他人多,但是导师对我的指导却不比其他人少。在老师的支持下我才有科研经费进行研究、在老师的帮助下我才能完成论文撰写以及修改。可实际上,老师对我最大的帮助是传授于我“问题驱动”的思想,这个思想会在以后很长一段时间的工作和生活中影响我。我很庆幸自己选择了---老师作为导师,这是我读研期间做的最正确的事。

    感谢计算机科学这个专业,它让我多了一种观察事物的角度;感谢《斗破苍穹》有声小说,它陪我熬过了无数个难眠的夜晚,帮我建立了为数不多的自信;感谢任天堂、Square Enix等游戏公司,它们让我的意识超越了时间、地点和金钱的限制,带我领略了一个个精彩、紧张而又深邃的冒险故事。最重要的是感谢我自己,感谢自己有着破釜沉舟,坚韧不拔的品性、感谢自己在许多人生交叉路口做出了正确的选择、感谢自己所经历的一切,正是这一切构成了独一无二的我。

    这篇致谢很轻,它仅仅是我毕业论文的一角,甚至打印出来也不过薄薄一张纸。可是这篇致谢又很重,它承载着我三年的总结和感悟,需要很多人的帮助才能撑起这篇文章。“长风破浪会有时,直挂云帆济沧海”,感谢各位同学、老师、家人以及朋友。

    《满江红》的平庸之恶

    事先声明,本文不涉及剧透

    大年初五,我抱着批判的眼光观看了《满江红》,这也是我今年看的第一部电影。有的同学可能好奇为什么我没有选择《流浪地球2》,原因很简单,因为我没有看过《流浪地球1》,不清楚他们之间是否有剧情的关联,因此我想抽空看完《流浪地球1》之后再看《流浪地球2》。为何是“批判的眼光”,这个不难理解,近些天讨论热度最高的莫过于中国电影,其中的零零种种,似乎也不需要我再赘言

    在看《满江红》之前,我根本不知道这部电影讲述的大体背景。说来惭愧,要不是看了电影,我甚至都已忘了这曾是八年级学过的课文。看来导演高估了我的文化水平,作为一个初中毕业十多年的人来说,很难仅凭标题联想到故事背景。不过我猜,和我相似的人亦不在少数。坦白地说,这部电影对我的最大作用是给我上了一堂历史课,以前我只有“秦桧”、“岳飞”这些模糊的概念,看完电影我方才知道,原来他们是同一朝代的人,而“精忠报国”中的“国”指的便是宋

    电影剧情大概讲述的是宋朝宰相秦桧与金私通的信件偶然丢失,秦桧命人寻找所发生的一系列反转再反转的故事。单论剧情,如果10分满分,我会打7~7.5分。原因有很多,首先剧情可以分成两个阶段,第一阶段是找信,这部分由于带着悬疑内容一直吊着观众胃口,所以观感倒还不错。第二阶段是信找到以后,众人的处理方式及其结果。不同于第一阶段,第二阶段时各角色的目的悉数展现,因此此时观众更像是上帝视角看着每个人的命运走向。仅将两阶段的故事讲好,我觉得就可以打6分,至于多出来的分,我要给到反转部分。不过成也反转,败也反转,这也是为什么我不给8分甚至更高的原因。首先第一个反转为我们点破了关键人物的身份,给我一种“凶手原来是他”的震撼。但是,这个反转给的太早了,电影接下来大半的时间我都是在一种”已知凶手是谁,看看他还能翻出什么浪花“的感觉中度过的,这种感觉说实在少了些许趣味,但好在接下来剧情的一系列反转尚能为观众填补一些乐趣。第二个扣分点是电影临近结尾时的反转,也许是大部分电影都要表达”邪不压正“的主题,所以我实际上很早就猜到了最后的结局,因此在我看来构不成反转,倒是让我有些审美疲劳

    接着是演技,或者说演员&演技,这也是网上争议颇大的部分。在我看来,这部电影中有两个人格格不入,第一是沈腾,第二是易烊千玺

    先说沈腾的部分,这部电影中大部分喜剧情节都源于沈腾,而喜剧的内容需要表演和台词共同传达。沈腾的表演给我一种舞台剧或是小品的感觉,这是他最擅长的部分,或者说是他的舒适区,但是放在这样一部气氛有些紧张甚至肃杀的电影中似乎不太合适,上一个给我这种感觉的演员是陈赫。沈腾的台词相比演技就更让我别扭了,电影的背景设置在宋朝,按理来说演员台词应尽量避免太过于白话,不是说不能用白话,而是应该少用。与之相对的是张译饰演的角色,张译的台词介于文邹邹和白话之间,这才是我认为古装电影应有的台词水平

    如果说《满江红》惹人争议的部分是演员,那么演员中最惹人争议的便是易烊千玺。很难找到一个词描述易烊千玺的演技,如果他的演技从头烂到尾,我可以直接说烂。正因为他的演技并不是从头到尾一无是处,也有高光的部分,所以很难形容。但是,再如何高光,在张译、雷佳音等一众老戏骨面前也显得平庸了许多。我首先要吐槽的便是其形体,易烊千玺饰演的是军队统领,按理说一军之将其身形即便不说高大,但至少应该站如松、行如风。可他却正好相反,永远驮着背,脖子也有些前倾,这种形象很难让观众相信他能统领军队。并且他的形象,从发型到面容再到着装似乎与“日本大佐”有些异曲同工之处,实在容易让人出戏

    最后是关于服化道的问题,注意,场景布置也属于服化道的部分。《满江红》的场景非常朴素,经常是一群人在一个院落中商谈,亦或是在石巷中行走,室内场景不多,即便有,布置也非常简单。实际上这种场景布置我并不觉得有什么问题,因为《满江红》并不涉及战争等大场面,它本质上和《扬名立万》差不多,讲好故事是首位。真正的问题在于,《满江红》宣传时称电影成本达到了5亿人民币,以我外行人的眼光,怎么也看不出用了5亿。不过,如果把宣发等电影制作以外的工作也算在成本里的话,倒是勉强能理解了

    实际上在我看来《满江红》不是一部出彩的电影,也不是一部糟糕透顶的电影,它仅仅是一部平庸的电影。可是平庸的影视作品有很多,甚至在我看来有些捧的比较高的作品其中也不乏平庸者,但似乎也不是每个都像《满江红》这样引来大量的口诛笔伐。为什么《满江红》会从一开始集体意淫式的狂欢,到现在集体癫狂式的谩骂,这个令我很感兴趣。究其原因有很多,抛开最近“幽灵场”、“偷票房”、“买票房”等指责不谈,我不是电影从业人员,对这方面着实不了解。实际上我看这部电影是冲着张艺谋的名头去的,就好像姜文导演了一部电影我也必看一样。但最终《满江红》带给我的落差很大,它没有达到我心中的预期,算不得神作,也谈不上糟糕,介于可看可不看之间的一部作品。如果这是一个新人导演的作品,我会觉得还不错。可问题就在于它是一部花费5亿人民币,并且由张艺谋导演的作品,最终呈现的效果着实难以让人买账

    2022总结

    这篇文章简单总结下我的2022年。这一年对我而言是丰富的,上半年我的小论文发表了,下半年我去了云南旅游,年底还找到了工作。总的来说,今年比去年好

    首先,我要进行一番自我批斗。自从3月我的论文发表后,就再没看过论文,甚至也没写几篇博客。与此同时,几乎每天都有同学在b站或者博客中提出各种各样的问题,有的问题太过基础,有的问题我也不知道作何解答,因此几乎所有问题我都看到了,但是大多没有回答

    暑假我去云南玩了大概一个星期,从昆明到大理,再到丽江。不得不说云南确实是个好地方,气候宜人,即便当时是最热的那段时间,在云南都能感受到一丝凉爽。旅行结束后休整了一段时间,随即便开始准备秋招

    每年都听闻秋招神仙打架、诸神黄昏、地狱难度,疫情这几年尤是如此。但实际上我刚开始进行秋招的时候并没有感受到行业的"寒气",放眼望去不少企业都在招聘,有大家熟知的大厂,还有不少小厂,算上各种国企、央企,一时间我产生了一种错觉——好像找工作并不难。随着时间的推移,我也投了十几家公司,大大小小的笔试也参加了不少,但都没什么回应。笔试的时候,我甚至在想,这些题目真的能起到区分水平刷人的效果吗?例如小米的某些岗位,笔试内容是行测,难度不算很高,甚至有的人如果找同学帮忙一起做,那不是随便考满分。后来我明白了,对于某些大厂来说,他们今年实际上压根就没有什么招聘指标,换句话说,不缺人。因此大家做了也是白做,无论你是985,还是普通211,最后的结局都是被添加进人才库。除了虚假的招聘岗位外,今年很多企业的报录比也创下了新高,以中石化为例,去年秋招招聘人数共11694人,今年仅有11421人,少了273个名额。去年共136850人报名,今年有超过177606人报名。我报的计算机岗位招10人,报名参加笔试的有601人,最终进入面试的有将近100人。这100人中,有本硕都是985的大佬,有国外留学的大佬,有拿了两次国家奖学金的大佬等等,这个比例以及难度相较于考研,只能说有过之而无不及。每个人找工作想必都有自己的目标,或者说优先级,对我来说,国企>工作地点在海外的企业>私企。我一直比较追求work life balance,所以国企自然是首选。而工作地点在海外的企业,是因为我想借助海外工作的机会和平台,在合适的时机润出去。私企实际上我并不考虑,即便是华为给我开30k我也不去,倒不是说我不喜欢钱,而是因为我不想出卖自己的时间,我还有很多事情想做,我的生活不能只有工作。而且私企的不稳定因素太多,不知道什么时候就被裁了,与其每天提心吊胆,倒不如去更稳定的国企。当然,国企和国企之间,亦有差距,接下来的内容算是我的一点心得。对于我们计算机专业来说,提到国企,大家首先想到的肯定是银行以及各大运营商,并且到目前为止你可能仍然觉得这些企业待遇很好,但实际上银行和运营商,能不去就别去。首先对于银行来说,除了总行或是省会城市的开发岗以外,其他地方分行并没有很多需要开发的内容,因此小县城的银行开发岗千万别去。再者,无论是哪儿的开发岗,校招入职银行都需要在一线工作一段时间,美其名曰熟悉业务,而所谓的"一线"实际上就是柜员。每天坐在里面替别人办理业务,运气不好甚至还有某些奇奇怪怪的绩效考核,例如售卖理财产品,拉存款等等。运营商亦是如此,除却某些设计院或是研究院,其他地方的运营商,不管你是不是技术岗,或多或少也都有绩效考核。另外,如果你很优秀,甚至根本拿不到它们的offer,借用牛客网某位大佬的评论

    因为你太优秀了,也有很多公司保底。你要明白他们需要什么样的人,招个一般的一本的进去,好管理,而且也知道自己的劣势,不会不知天高地厚,毕竟岗位本质是销售,你太优秀了,万一受不了客户的气,走了,或者发现别人双休,你单休,再或者发现本科、硕士福利都差不多。考,肯定能考进去,前提是你得准备好,是他们需要的本地人,毕竟要招存款,要卖各种产品。一个外地孩子,需要更努力才会认可你

    总之各位学弟学妹找工作应该多收集信息,多在知乎、牛客网上看看经验总结。我个人觉得随着疫情的结束,私企应该要重新恢复活力了,而不再像现在这样,大家为了国企那低到可怜的工资挤破头

    提到工作,我不得不反思下自己的阿喀琉斯之踵。说来惭愧,虽然我是计算机专业,但是长久以来,我对于开发这件事一直都很恐惧

    Achilles' Heel(阿喀琉斯之踵)阿喀琉斯是古希腊神话故事中的英雄人物,刀枪不入,唯一的弱点是脚后跟(踵)。后用于来比喻某东西的致命缺陷

    最早接触开发是在本科学习Java Web的时候,那时候上机课跟着老师敲代码经常走神,等回过头来便不知道老师在讲什么了。亦或是照着老师的操作,将这个库添加进环境,将那个包导入等等,但实际上我并不懂这样做到底是什么意思,回到寝室在自己的电脑上操作一番又是各种报错。久而久之我便对开发失去了兴趣,后来很长一段时间我都没有碰过开发。不过好在东边不亮西边亮,虽然我的开发水平很菜,但是我的数学以及算法水平还算不错,这也为我研究生期间的算法工作打下了扎实的基础。提这个事儿,是因为我签的工作是信息技术工程岗,打听之后才了解,工作内容就是要做开发,因此也只能想办法克服了

    最后,我想谈谈今年对我影响最深的一部作品——《斗破苍穹》。我大概是从8月底开始看《斗破苍穹》,与其说是"看",不如说是听,因为我是直接听的有声书(桑梓播讲的版本)。实际上这并不是我第一次看《斗破苍穹》,读高中的时候,每天上学路上我都戴着蓝牙耳机,耳机里放的就是《斗破苍穹》,只不过没听多久就转而听英语听力了。今年9月正值秋招,那时候我每天都在投简历、刷题,整个人处于一种非常低迷的情绪中,而《斗破苍穹》的剧情正好属于那种充满幻想且富有希望的感觉。实话说,在听《斗破苍穹》的过程中,我有意识地将自己代入成主人公萧炎,这确实给我带来了极大地自信,帮我度过了秋招那段压抑的时间。话又说回来,我和萧炎在某些方面很像,例如,我们都有一个坚定的目标,我们为这个目标都付出了很多,我们的性格都很坚韧等等。可能很多人认为《斗破苍穹》只不过是一部爽文罢了,诚然,它确实存在很多问题,剧情的节奏有些不到位、经常出现越级挑战的桥段、后期内容有些重复等等。但是对我而言,《斗破苍穹》就是一部好作品

    我的秋招经历

    首先介绍一下我的背景,我本科就读于一所双非软件工程专业,后考研到了末流211的计算机科学与技术专业

    准备阶段

    我的秋招大概是从8月底开始的,具体应该是英语六级出分的那天,当我得知自己的六级过了以后便从淘宝下单了三本书。从8月底便开始了无止尽的刷题。刷题的内容主要是行测,行测全称为行政职业能力测试,是几乎所有国企和公务员考试都会考的内容。行测里分很多内容,例如小学数学题、小学语文题、资料分析、常识题等等。由于行测的题量比较多,计算量相对也比较大,为了考一个好成绩,必须要刷题练习

    除了上图的三本书以外,我还在网上做了不少题,这里安利一个比较好的刷题网站——华图题库。这并不是给华图打广告(麻烦华图给我点广告费),我觉得华图的这个网站做的确实不错,题目全都按照类别归类好了,需要补强什么知识点可以专门进行针对性的训练,而且做题的时候还有自带的计时功能,每次做完之后可以看看自己的做题速度有没有变快

    我不喜欢用手机刷题,其中一个原因是字体太小,对于我这种"精神老年人"很不友好,而且对很多人来说,手机刷题可以充分利用碎片化时间,这对我来说也没什么意义,因为我基本上每天都有大块儿时间,不存在碎片时间。具体刷题数量可以参考上面的图,数量关系部分我就做了有至少613题。我是按照各个专题进行刷题的,并且每次做完都会将正确率和时间记录下来,观察自己的变化,看看哪里还有薄弱的部分,哪里需要进行加强

    刷题确实很辛苦,下面是我打草稿用掉的A4纸

    有时候会忘掉一些知识点,因此我也画了不少思维导图方便复习

    为了应付一些私企的考试,我也有刷算法题。相较于行测来说,算法对我来说是相对简单的,因为我本科就有参加算法竞赛的经历,所以对于一些algorithm不需要专门再去学,只要做题就行了。不过我也并没有去Leetcode刷题,因为我个人觉得私企笔试的时候是给定时间限制的,并且别人不会告诉你这个题考的是什么算法。而刷题首先你知道他考的是什么算法,并且没有时间限制,所以这对于上机笔试并没有太大帮助,因此我只参加算法比赛来锻炼自己。算法比赛非常类似于私企上机的过程,都是在规定时间内给你几道题让你解决,并且不会告诉你这些题考的算法是什么,需要自己阅读以后思考,然后编程解决。这里列几个我参加过的算法竞赛网站:

    首先是Leetcode,它的优点在于有中文,并且题目风格也类似私企笔试题。缺点是一周只有两次比赛,并且其中一次的时间还是晚上非常晚的时候,因此对于我来说相当于一周只有一次,次数太少

    其次是牛客网,它的缺点是比赛题目都是由acm选手出的,因此质量参差不齐,并且题目描述也不是很规范,和私企笔试题的风格也不太像

    codeforces是我以前本科经常参加竞赛的网站,但是比赛时间也比较阴间,大概都是晚上11点开始,不适合现在的我

    atcoder是日本的算法竞赛网站,所以比赛时间对于中国人来说比较友好,大概是晚上7、8点左右开始


    笔试&面试

    从9月初到12月我投了非常多的公司,有小厂,有大厂,有国企。这里说几个我印象特别深的企业

    亿纬动力:笔试是以手机问卷的形式给出的,考的是行测的内容,大概不到40题。考完之后大概过了1个星期左右面试,分两面,一面大概简单问问是哪里人,问了一个和同事起冲突怎么办的问题。二面算是半技术面,因为你说他问了技术也算问了,说没问也算是没问,问的问题是当时比较火的"羊了个羊"游戏,如果你要写程序自动玩这个游戏,应该怎么办?我理解的是要设计一个比较好的算法去分析当前局面,因为羊了个羊第二关四周有一些堆叠起来的卡片,如果让我设计程序,我应该会采用类似贪心算法的方法,优先消掉四周的卡片,多暴露出更多的卡片,暴露的信息越多,可选择的余地也越多。最终拿到offer,具体数字就不说了,一年大概15w左右,工作地点在荆门,就在我家出门10几公里的地方。不过我毫不犹豫的就拒了,主要是因为我想进国企,国企中我最想去的是中石化

    专利局审查中心(湖北):笔试内容有4篇英语长文翻译(英译中)和一篇作文,浏览器考试,双摄像头全程监控。面试内容是提前15分钟让你阅读一份专利文件,之后面试官会考你这个专利的相关内容。可能是面试没发挥好,没拿到offer

    三桶油:中石油、中石化、中海油考的都差不多,都是行测+时政+企业文化的内容,但是对于其他企业来说,时政和企业文化的占比会比较高,大概有个30分左右,剩下70分都是行测。中石油我考了72.5分,分两面,一面上来让你阐述一下你报考这个岗位的优势,然后是一段英语听力,让你简单说说这段内容讲述了什么内容,接着是根据你简历上的内容用英语对你提问,我在简历里写了我是一个拥有7000粉丝的b站up主,然后面试官就用英语问我,你平时会上传一些vlog是吗?你有多少粉丝?英语环节结束后,最后是一个开放性问题,你怎么看待"没有规矩不成方圆"和"要创新必须要打破规则"这两句话。还没等来二面通知,我就已经签约别的单位了

    中石化是我最想去的单位,也是我最后签约的单位。笔试我考了73.4分,报的岗位是信息工程技术岗,大概有80人进面,招10个人。12月2号面试,12月6号下午接到录用通知,当天我就完成了签约,具体细节就不说了,感兴趣的可以私聊问。实际上我的整个秋招过程所有环节都在为中石化做准备,前期刷题我买的是中石化的书,参加其他企业的笔试也是为了测试自己的做题速度,为中石化笔试做准备,参加其他企业的面试也是为了锻炼自己的脸皮,顺便锻炼自己谈吐,为中石化面试做准备。说说我为什么最想去中石化,勉强来说,我可以算是"油三代",我的奶奶以前是石化的员工,我叔叔(我爸的亲弟弟)和姑姑(我爸的亲妹妹)也都是中石化的员工,我住的小区叫石化小区,我上的小学、初中、高中全部都带有"石化"字样。以前上学的时候,吃早餐可以看到穿着石化工服的员工,中午放学可以看到石化的班车......毫不夸张地说,"石化"这两个字肯定刻在我灵魂的什么地方了。所以当我在考虑找工作的时候,我毫不犹豫的就决定一定要进中石化,中石油都不行,必须是中石化。最后也算是如愿以偿

    初中同学聚会有感

    10月3日这天,荆门温度最高有38度,过了3号气温将会急转直下,例如我写这篇文章的时候已经在家穿了四天的毛衣了。本着明知不可为而为之的精神,我和几个初中同学相约在3号最热的这天举行同学聚会


    我们上初中周末经常约着一块儿网吧通宵,所以群名叫“通宵专业户”

    这次是我们第二次同学聚会,第一次是2019年2月,大家在饭桌上约定以后每年都聚一次,没想到第二次聚会一晃就过了三年,中间因为疫情或是其它原因没能聚成。第一次聚会有8个人,那时候大家都还没有大学毕业,第二次聚会只有5个人,却只剩我还在读书。第一次同学聚会的时候我们在饭桌上滔滔不绝地聊着以前的事儿,就好像重新上了一遍初中,讨论我们8个人谁被班主任揍的最多(首先排除我),谁抄作业被逮到的最多(首先排除我),谁和哪个女生是冤家......

    在参加这次聚会前我预想了很多,例如大家的样貌变化、身份变化、第一句话该说什么,甚至为了饭后的网吧开黑环节,我提前好几天训练了一下自己的英雄联盟(以下简称LOL)水平


    夸下海口,表示我要carry他们

    见了面以后我才发现大家和三年前比其实没有什么太大的变化。我们都很好奇对方的近况,于是在饭桌上轮流进行“拷打”,问问最近过的怎么样,在做什么,有没有女朋友之类的


    胖子

    首先是胖子,我对他算是最了解的,今年7月我去襄阳找胖子玩,当时他正一边上班一边考研。这次见到他,他说不考研了,问他为什么,他说因为今年研究生缩招,不好考了。我没继续说什么,或者说我早有预感,以我对胖子的了解,他不是一个做事坚持的人,在学校有老师管着的时候如此,更别说没有老师监督的时候了。关于更多胖子的故事,可以看我之前写的文章我与胖子的二三事&暑假杂记-1


    梁总

    然后是梁总,群里昵称叫“瓜瓜乐”的就是他,群名也是他起的。以前他是我们几个中打LOL最好的,好到上大学的时候可以靠接单代练养活自己。还记得初中我和梁总的一件趣事,晚上我在他家楼下等他去网吧,他从上面丢下来一个纸团,上面写着:“等会,我爷爷睡着了我再出来”。梁总在现在安徽某公司上班,他们公司有入党的机会,最近刚成为预备党员,也算从良了吧


    虎哥

    虎哥是我们这些人中最腼腆的,平时话也少。别看他戴个眼镜斯斯文文的,初中班上男生跟他比扳手腕没几个能超过4秒,平时也没见他健身,我们总说他名字里带个“虎”,所以天生神力。初中的时候有个学姐,个子高高的,人也很漂亮,天天下课就来我们班后门口找虎哥,给虎哥送各种礼物,但是虎哥对人家没任何好感,礼物也从不收,后来这事儿被我们班主任知道了,找那个女生谈话,此后她就再没来过了。虎哥目前在荆门某4s店当销售,我们这伙儿人两个有车,其中一个就是虎哥,另一个是胖子


    邱总

    邱总最初和胖子在一个高中,后来学艺术所以转学了,最后以艺术生的身份和我考上了同一所大学,大一的时候我们还约在学校附近的网吧通宵过一次,后来觉得通宵身体有点顶不住就再没去过了。关于邱总的工作,这里不方便说,便略过了

    在聊天的过程中,我问了一句:“谁现在有女朋友?”,大家相视一笑,没人开口。可能因为谈到了女性,话题被转向了我们初中的那些女同学上。首先想起的是我们初中三年的班长,她是我们所有人心中的女神,用“出淤泥而不染,濯清莲而不妖”来形容似乎有过之而无不及,最后一次关于班长的消息源自她的QQ空间,大致内容是她直博首都医科大学了。不论好坏,极端往往更容易被人记住,班长如此,我们班上另一位女生亦是如此。我们班主任几乎不对女生动手,除了这位女生,她因为收低年级学生保护费这件事被我们班主任扇了几巴掌,另外还有一些违法的事儿,就不在这儿细说了。后来我们又谈及了很多女生的名字,但是大家很久都没有联系,也不知道她们最近在做什么就略过了。邱总最后开始揭我老底儿,提到了我们班的一个转校生,迫于他们的拷打,我只好和盘托出。这个女生姓刘,她的名字起的很不错,有“瑞雪兆丰年之意”。大概是初二上学期的时候她从别的学校转来我们班。有一次无意间我在老师办公室看到了各个同学的出生年月日,清一色1998中的一个1996格外显眼,望向姓名俨然便是她。某个星期六我坐公交回家,公交停在某一站的时候我看到了站台边的她,现在很难回想我当时的感觉,或许和《赛博朋克 边缘行者》中大卫第一次见到露西时候的感觉一样。之后在班上我会偷偷注意这个女生,发现她不属于好好学习类型的时候我松了口气,因为这样我每天就可以把作业给她抄了。作业一直抄到了毕业,初三毕业的暑假相当漫长,我也记不清是几月份了,某天她给我发了个消息,说是生病了,希望我能去看她,我问她想吃什么早餐,她说:“肯德基的皮蛋瘦肉粥”。那天我去的很早,不到7点我就进了病房,病房里有两张床,其中一张床上躺着一个女生,另一张床上也躺着一个女生。可能我开门的声音惊动了其中一个女生,她抬起头来看我,我也望向她,确认她不是刘xx后,我径直走向另一个病床。将皮蛋瘦肉粥放在床边的柜子上,瞅了眼她还没醒,于是搬个了个板凳坐在她旁边开始玩手机。由于好奇她得了什么病,我起身走向床尾,拿起病历簿看了看,具体内容我记得不是很清了,只记得四个字——“中期妊娠”。说来惭愧,当时我并不认识“妊娠”两个字,只好利用偏旁部首查了一下百度,我已记不清当初得知其含义时的想法,只记得后来默默坐回到了椅子上,没过多久她醒了,我们随便聊了聊,我没有问,她也没有说。离开医院的时候将近9点半,走之前她让我不要告诉别人,我点了点头

    饭后是经典的网吧开黑环节,每次聚会吃完饭去网吧上网已经成了我们的惯例。第一次聚会的时候由于人太多,我们只好分两队进行4v4,这次正好5个人,便干脆一起匹配对战了


    战绩

    打了两局之后我才发现,原来梁总那句“很久没玩了”不是他在谦虚,看得出来他真的很久没玩了,以前只要他在,我们随便玩都能赢,那天我们被连续暴捶了几局,直到最后才赢了两把

    到了下午5点多,我们一块儿结账下机,梁总有点事就先打车走了,剩下我们几个决定走回去。走路回家也算是经典环节了,初中的时候我们通宵完无论多累,出了网吧都会先找个地方吃碗面,吃完之后走回家,没有别的原因,就是想硬撑着表示自己通完宵一点事儿没有,实际上到家之后完全顶不住,倒头就睡了。第一次聚会结束我们也是一块儿走回家的,但那次走回家不是谁为了硬撑,或许是为了珍惜哥儿几个好不容易聚在一块儿的机会,想再多聊聊,至少我是这么想的。这次回家的路上,大家的话并没有我想象的多,甚至很多时候一两分钟没人说话,谈论的话题也从原来的天马行空变成了就业形势、工作情况等。我家住的最近,因此每次都是我最先离开。到了小区门口,我记不清说了几次“拜拜”便与他们分开了

    我与胖子的二三事&暑假杂记-1

    我与胖子的二三事

    还记得以前看过一部关于高中生的电影,里面说到,无论你在哪读高中,基本上班里都会有一个被称为胖子的家伙,与之相对应的也会有一个被称为子的男生。在我们班上,我就是那个瘦子,而胖子是我的好哥们儿


    最近一次测体重只有50.2

    我与胖子的关系最早可以追溯到初中,我们从初中开始就在一个班,甚至很长一段时间他都是我的同桌,可能是老师分配座位的时候故意为之,想平衡一下我俩的体重。胖子的妈是我们学校旁边一家网吧的网管,而且是夜班的网管,所以初中周末我们经常会叫上胖子一块儿去通宵。他上网不需要掏网费,我们几个也想走走“后门儿”,但没人好意思开口。有一次家长会,胖子的妈坐我旁边儿,我没敢抬头,生怕她认出我,后来我再去上网的时候,她在柜台直接跟我们说:“上次家长会你们太好玩儿了,一个个都不敢抬头看我,怕我告诉你们家长是吧?”。自此以后的家长会我们就再没低过头


    一点通网吧

    初中在我早恋以前,我的成绩基本上是班里前几。这并没有吹牛,即便我经常去网吧通宵,但学业从没有落下过。胖子的成绩倒是一般般,以前并不觉得,现在想来算是我害了他。因为我和胖子是同桌,所以每次家庭作业的答案他也总是能从我这儿弄到第一手资料,别的同学要么等他抄完再抄我的,要么就再抄他的。有的作业是上午布置的,那我就赶在下午上学前在家写完(或许我没有午睡的习惯就是因为习惯了中午做作业)。还有些作业是下午上完课才布置的,那我就会和胖子在放学后找个僻静的地儿,我边做他边抄。有时候我会和胖子提出一些等价交换,例如他骑自行车载我回家,如果没骑自行车就背我回家,那时候胖子就有1米7了,再加上我很轻,所以对他来说没什么太大问题。当然也会存在作业实在太多或太难,来不及抄。这种情况我一般会回家写完,第二天凌晨5点多就起床去学校,每次我进教室胖子一般都在,就是为了等我的作业(还有一些其他同学也在等我的作业)

    后来因为一些原因我学坏了,所以中考自然也考的不咋地,胖子就更不用说了。不过我们那个年代是可以买分上高中的,这也并不违法。但是我家拿不出那么多钱,所以我在初中老师的推荐下去了一所非常差的公办高中。胖子买分上的另一所高中,他上的高中实际上就是我们的初中学校,我们这个学校既有高中也有初中

    我在高中上了一年之后,学校里陆陆续续有传言,说是我所在的高中即将拆了,变成一个小学。一开始只是一两个人在传,后面传的人越来越多,直到那一天真的来临了。周一早上照例升国旗,校长在国旗下讲话通知了这件事情,并且明确告诉我们所有的学生都将进入另一所高中学习,要不怎么说缘,妙不可言呢,这个高中就是胖子所在的高中

    大概高二开学没几个月,我们就到了新的高中。我学的是理科,胖子学的也是理科,但是胖子所在的高中有两个理科班(这两个理科班是同一等级的,不存在什么火箭班之类的),我们基本上是按照一半一半的比例平均分配到两个班,说来就是这么巧,我正好被分配到了胖子所在的班。如果硬要说,我原来的高中实力是不如新高中的,所以我们这些“外来者”无不例外都被安排在了最后一排。胖子上了高中后听说有些开窍,所以他没有坐在后几排,因此自然也没可能成为我的同桌。后来经过了几次考试,我的实力有所展现,老师也就把我调到了前面几排,这中间有一次我和胖子坐了一段时间的同桌,不过考试很频繁,每次考完试基本上就会换座位,所以我们同桌的时间也没有那么长。再到后面我的记忆就很模糊了,因为学习压力越来越重,下课铃好像被附了魔法一样,铃声一响所有人都趴桌子上睡着了

    中间我和胖子有两件大事儿,我觉得不得不提。高三的时候我喜欢上了我们班一个女生,这个女生和胖子的关系还不错。晚自习之前我把她拉到墙角表白,结果当然以失败告终,当天晚上回到家后她给我发了个qq消息,是她和胖子的聊天记录截图,内容大概就是她和胖子说了一声我对她表白了,胖子的回复是让她认真考虑,并且附上了我的一些缺点。当时我就想,这家伙不地道,兄弟表白,你不帮我就算了,还在背后说我坏话。我当时很气愤,把这张截图反手转发给了胖子,然后把他删了,后面直到高中毕业我们都没说过一句话。第二件事儿发生在高考结束,还没出分数的那段时间,那时候我想着要及时行乐,找个城市进行一趟毕业旅行,于是我叫上了初中的另一个铁哥们儿,他和我一拍即合决定去杭州,但是他想要叫上胖子,因为初中的时候我们仨经常在一块儿鬼混。我对他说了我和胖子的事儿,表示会有点尴尬,他觉得没啥,并且劝我把胖子加回来。其实当时我早就不生气了,只不过拉不下面子。经历了一段时间的思想斗争,某一天我照例在外面吃完早餐后,坐在面馆门口把胖子加了回来,很快他就通过了好友申请,不过现在我已经想不起来谁发的第一句话,以及第一句话说了什么。唯一记得的是,我和胖子没说几句就都释怀了,并且表示这都不是事儿。后来我们仨把江苏基本上玩儿了个遍,并且赶在出成绩之前去了趟灵隐寺,拜了拜各路神仙,祈求考个好成绩。不过胖子本身学的就不咋的,神仙也救不了,最终上了襄阳的一所专科,而我去了武汉的一所本科


    暑假杂记-1

    前两天,也就是7月14日我到襄阳找胖子玩儿,这也是我时隔4年再见胖子。18年暑假的时候我就去找过胖子,那时候他快要毕业了,正准备秋招,在襄阳租了个房子,房子虽然小,晚上我俩挤在一张床上,不过有地方住也不错,省下了酒店的费用。这次去找胖子,他换了个离公司更近的地儿,房子也更大了,还多了个室友,就是我们一块儿去苏州的初中同学。14号早上到襄阳,胖子没能来接我,因为他要上班,另一个同学来接的我。胖子住在一个机关大院儿里,据他说是捡漏租到了这里。胖子家里还养了条狗,很听话,刚去的时候对我一直叫,没过多久就跟我熟络了,经常跑到我面前把肚皮对着我让我摸


    胖子养的中华田园犬

    胖子混的不错,找的一个955的公司做后端开发,几年前被提到技术总监的位置。他跟我说前两年公司老总犯事儿被判了三年,所以这几年公司一直群龙无首,每个员工自己就是老板。谈及胖子的感情史,他说这些年从上大学开始陆陆续续谈了四个,最长的谈了两年,最短的十几天。针对胖子的四段感情我做了一个大约半小时采访,本来准备剪剪做个字幕发到b站,不过我太懒,也就作罢了。在来襄阳之前,胖子就有咨询过我考研的相关事宜,这次我去襄阳,看到他的桌子上有一堆考研的书籍,我不解,问他现在日子不是挺好的吗,工资照发,工作又轻松,为什么要考研,他的回答很干脆,想进国企


    胖子背考研单词的草稿

    胖子在用墨墨背单词

    与胖子交流的这两天,我才发现我是一个活在过去的人,我主动和胖子交流的话题总是些初高中时候的那些事儿,聊聊以前谁干了些什么蠢事儿,那些同学最近都在干什么。胖子是活在未来的人,他对过去没有像我这般留恋,他觉得当下是最好的,对未来也不迷茫

    我才知道胖子买了辆车,我坐在后座儿看着他开车的背影,也不知自己在想什么,只觉得他变得有些陌生,我在想以后是不是不应该用“胖子”来称呼他,毕竟这多少对他有些不尊重,不过我也只是稍微想了一下而已,实际上我还是叫他“胖子”,这么多年的贯口不是那么容易改的


    开车的是胖子,副驾驶是我们初中同学

    那天晚上我们仨吃烧烤聊天,胖子说他羡慕我学历这么高,我羡慕他实现了财富自由。我们干了最后一杯,我说我来付钱,他说:“你都还没赚钱,不用你来付”


    部分烤串儿

    这篇回忆录越写到后面越写不下去,倒不是别的原因,只是因为我太懒,想着快点儿收尾。最后我在想要不要把这篇文章发给胖子看一下,思索了一下觉得还是不了,我不想让他知道我这么矫情,也不想听他对我的调侃

    Flooding-X: 超参数无关的Flooding方法

    ICML2020的论文《Do We Need Zero Training Loss After Achieving Zero Training Error?》提出了一种Flooding方法,用于缓解模型过拟合,详情可以看我的文章《我们真的需要把训练集的损失降到零吗?》。这里简单过一下,论文提出了一个超参数$b$,并将损失函数改写为

    $$ \tilde{\mathcal{L}}(\boldsymbol{\theta}) = |\mathcal{L}(\boldsymbol{\theta}) -b| + b\tag{1} $$

    其中,$b$是预先设定的阈值,当$\mathcal{L}(\boldsymbol{\theta})>b$时$\tilde{\mathcal{L}}(\boldsymbol{\theta})=\mathcal{L}(\boldsymbol{\theta})$,这时就是执行普通的梯度下降;而$\mathcal{L}(\boldsymbol{\theta})<b$时$\tilde{\mathcal{L}}(\boldsymbol{\theta})=2b-\mathcal{L}(\boldsymbol{\theta})$,注意到损失函数变号了,所以这时候是梯度上升。因此,总的来说就是以$b$为阈值,低于阈值时反而希望损失函数变大。论文把这个改动称为"Flooding"

    这样做有什么效果呢?论文显示,在某些任务中,训练集的损失函数经过这样处理后,验证集的损失能出现 "二次下降(Double Descent)",如下图


    左图:不加Flooding的训练示意图;右图:加了Flooding的训练示意图

    我们可以假设梯度先下降一步后上升一步,学习率为$\varepsilon$,通过泰勒展开可以得到

    $$ \boldsymbol{\theta}_{n+1} \approx \boldsymbol{\theta}_{n-1}-\frac{\varepsilon^2}{2}\nabla_{\boldsymbol{\theta}} ||g(\boldsymbol{\theta}_{n-1})||^2\tag{2} $$

    其中,$\boldsymbol{\theta}_{n}$表示第$n$次迭代的参数,$g(\boldsymbol{\theta}_{n-1})=\nabla_{\boldsymbol{\theta}}\mathcal{L}(\boldsymbol{\theta}_{n-1})$表示损失对参数$\boldsymbol{\theta}_{n-1}$的梯度。式(2)的结果相当于以$\frac{\varepsilon^2}{2}$为学习率、损失函数为梯度惩罚$|g(\boldsymbol{\theta})||^2=||\nabla_{\boldsymbol{\theta}}\mathcal{L}(\boldsymbol{\theta})||^2$的梯度下降

    详细的推导过程见《我们真的需要把训练集的损失降到零吗?》

    Achilles' Heel of Flooding

    Flooding的阿喀琉斯之踵在于超参数$b$,我们需要花非常多的时间寻找最佳的阈值$b$,这并不是一件容易的事

    Achilles' Heel(阿喀琉斯之踵)阿喀琉斯是古希腊神话故事中的英雄人物,刀枪不入,唯一的弱点是脚后跟(踵)。后用于来比喻某东西的致命缺陷

    下图展示了使用BERT在SST-2数据集上不同的阈值$b$对结果的影响(黄色区域是最佳结果)。可以看出,$b$的设置对结果的影响非常大

    Gradient Accordance

    ACL2022的投稿有一篇名为《Flooding-X: Improving BERT’s Resistance to Adversarial Attacks via Loss-Restricted Fine-Tuning》的文章,以"梯度一致性"作为开启Flooding的"阀门",而不再采用超参数$b$。具体来说,我们首先定义包含参数$\boldsymbol{\theta}$的模型$f$,考虑一个样本$x$以及真实标签$y$,它们的损失为$\mathcal{L}(f(\boldsymbol{\theta}, x), y)$,损失关于参数的梯度为

    $$ \boldsymbol{g} = \nabla_{\boldsymbol{\theta}}\mathcal{L}(f(\boldsymbol{\theta}, x),y)\tag{3} $$

    其中,式(3)的负值就是参数$\boldsymbol{\theta}$更新的方向。现在我们考虑两个样本$(x_1,y_1), (x_2,y_2)$的情况,根据上述定义,样本1的梯度为

    $$ \boldsymbol{g_1} = \nabla_{\boldsymbol{\theta}}\mathcal{L}(f(\boldsymbol{\theta}, x_1), y_1)\tag{4} $$

    对于样本1来说,参数更新所导致的损失变化为

    $$ \begin{aligned} \Delta \mathcal{L}_1 = &\mathcal{L}(f(\boldsymbol{\theta} - \varepsilon \boldsymbol{g_1}, x_1), y_1)\\ &- \mathcal{L}(f(\boldsymbol{\theta}, x_1), y_1) \end{aligned}\tag{5} $$

    将$f(\boldsymbol{\theta}, x_1)$通过泰勒展开变形得

    $$ f(\boldsymbol{\theta}, x_1)\approx f(\boldsymbol{\theta} - \varepsilon\boldsymbol{g_1}, x_1) + \varepsilon \boldsymbol{g_1}\frac{\partial f}{\partial \boldsymbol{\theta}}\tag{6} $$

    $$ \frac{f(\boldsymbol{\theta} - \varepsilon\boldsymbol{g_1}, x_1) -f(\boldsymbol{\theta}, x_1)}{\varepsilon \boldsymbol{g_1}}= \frac{\partial f}{\partial \boldsymbol{\theta}} $$

    我们将$\varepsilon \boldsymbol{g_1}\frac{\partial f}{\partial \boldsymbol{\theta}}$记作$T(x_1)$,并对$\mathcal{L}(f(\boldsymbol{\theta}, x_1), y_1)$做类似的泰勒展开得

    $$ \begin{aligned} \mathcal{L}(&f(\boldsymbol{\theta}, x_1), y_1)\\ &= \mathcal{L}(f(\boldsymbol{\theta} - \varepsilon \boldsymbol{g_1}, x_1) + T(x_1), y_1)\\ &\approx \mathcal{L}(f(\boldsymbol{\theta} - \varepsilon \boldsymbol{g_1}, x_1), y_1)\\ &+\frac{\partial \mathcal{L}}{\partial f}T(x_1) \end{aligned}\tag{7} $$

    根据式(6)可以推出第一个等号,约等于是从泰勒展开推导的,具体来说

    $$ \frac{\mathcal{L}(A + T(x_1), y_1) -\mathcal{L}(A, y_1)}{T(x_1)} = \mathcal{L}' $$

    将式(7)带入式(5)得

    $$ \begin{aligned} \Delta \mathcal{L}_1 &\approx -\frac{\partial \mathcal{L}}{\partial f}T(x_1)\\ &=-\varepsilon \boldsymbol{g_1}\frac{\partial \mathcal{L}}{\partial f} \frac{\partial f}{\partial \boldsymbol{\theta}}\\ &=-\varepsilon \boldsymbol{g_1} \cdot \boldsymbol{g_1} \end{aligned}\tag{8} $$

    类似的,参数根据样本$(x_1,y_1)$更新后,在样本$(x_2, y_2)$上的损失差为$\Delta \mathcal{L}_2 = -\varepsilon \boldsymbol{g_1}\cdot \boldsymbol{g_2}$

    值得注意的是,根据定义,$\Delta \mathcal{L}_1$是负的,因为模型是对于$(x_1,y_1)$更新的,自然就会导致其损失的降低。如果$\Delta \mathcal{L_2}$也是负的,那么在$(x_1, y_1)$上更新的模型被认为对$(x_2, y_2)$有积极的影响。上面的等式表明,这种共同关系相当于两个样本的梯度$\boldsymbol{g_1},\boldsymbol{g_2}$之间的乘积,我们称其为梯度一致性(Gradient Accordance)

    Coarse-Grained Gradient Accordance

    上面提到的可以看作是样本级别的梯度一致性,由于其粒度太细,计算起来非常复杂,因此我们将其应用到batch级别的粗粒度上进行计算

    考虑训练过程中包含$n$个样本的mini-batch $B_0$,其中样本$\boldsymbol{X} = \{x_1, x_2,...,x_n\}$,标签$\boldsymbol{y}=\{y_1, y_2,...,y_n\}$,其中$y_i\in \{c_1, c_2,...,c_k\}$,即有$k$个类别。这些样本可以根据它们的标签拆分成$k$组(每组内的样本标签是一样的)

    $$ \boldsymbol{X} = \boldsymbol{X_1}\cup \boldsymbol{X_2} \cup \cdots \cup \boldsymbol{X_k} $$

    由此可以将$B_0$拆分成多个子batch的并集,$B_0 = B_0^1\cup B_0^2\cup \cdots B_0^k$。我们定义两个子batch $B_0^1$和$B_0^2$的类一致性分数为

    $$ C(B_0^1, B_0^2) = \mathbb{E}[\cos (\boldsymbol{g_1}, \boldsymbol{g_2})]\tag{9} $$

    其中,$\boldsymbol{g}_1$是模型在样本集$B_0^1$上的损失对参数的梯度,$\cos(\boldsymbol{g_1}, \boldsymbol{g_2})=(\boldsymbol{g_1}/|\boldsymbol{g_1}|)\cdot (\boldsymbol{g_2}/|\boldsymbol{g_2}|)$

    类一致性可以用于判断:对类别$c_1$的样本集$B_0^1$进行梯度下降是否也会减少类别$c_2$所对应的样本集$B_0^2$的损失

    假设一个Epoch中有$N$个batch,那么$B_s$与$B_t$的批一致性分数定义如下:

    $$ \begin{aligned} S_{\text{batch accd}}&(B_s, B_t)\\ &=\frac{1}{k(k-1)}\sum_{j=1}^k\sum_{i=1 \atop i \neq j}^k C(B_s^i, B_t^j) \end{aligned}\tag{10} $$

    批一致性可以通过评估一个批次的参数更新对另一个批次的影响,量化两个批次的学习一致性。更具体地说,$S_{\text{batch accd}}$如果是正的,表示这两个批次处于相同的学习节奏下,每个批次更新的模型对它们都有好处

    任意一个Epoch的梯度一致性最终定义为

    $$ \begin{aligned} &S_{\text{epoch accd}} \\ &= \frac{1}{N(N-1)}\sum_{j=i+1}^N \sum_{i=1}^{N-1} S_{\text{batch accd}}(B_s, B_t) \end{aligned}\tag{11} $$

    Analysis and Discussion

    实验结果这里就不放了,简单说一下就是作者使用了TextFooler、BERT-Attack、TextBugger三种攻击手段,以PGD、FreeLB、TAVAT等方法为Baseline进行对比,结果表明使用Flooding-X效果很好

    从下图可以看出,当梯度一致性指标从负数变为正数时,测试集损失也开始上升,说明梯度一致性这个指标可以很好的当作是过拟合的信号

    个人总结

    2020年提出的Flooding本身就是一个非常有意思的Trick,可惜原论文作者也苦于超参数$b$的选择,因此其应用不算广泛。ACL2022这篇论文提出了梯度一致性的概念,让模型自己感知什么时候该进行Flooding,避免了超参数的选择问题

    References

    ❌