“任何足够先进的技术都与魔法无异。” 亚瑟·克拉克
在 SBC 神经网络 发布后,我们看到了一个 1k 权重网络,用 10k 个样本训练来逼近正弦函数。 在这篇文章中,我们将使用 175G 样本训练的 450G 权重,这些样本可以比普通程序员更好地编程。 这些模型的大小令人印象深刻,但实际上没有人真正知道它们是如何工作的,或者它们的局限性是什么。
GitHub Copilot 是一种加速软件开发的人工智能工具,允许程序员做很多以前不可能的事情。 起初,它似乎类似于使用 StackOverflow,这是一个程序员在不知道如何做某事时发送问题的网站,但 Copilot 走得更远,它能够为我们的问题合成一个新的答案。
Copilot 包含在 Microsoft Visual Studio 代码中,并不断建议您可以通过按选项卡按钮接受的灰色代码。 这个建议的代码可以粗略地定义为您的查询(您的代码)和训练数据集(GitHub 代码)之间的“最常见”匹配。
例子1
在此示例中,我们定义了我们的函数及其文档字符串,并要求 Copilot 完成。 如我们所见,完成对应于文档字符串。 第一个直觉是 Copilot 充当搜索引擎,只是将您的查询与其训练数据集(150GB 的开源项目)相匹配,但这不是它的工作方式。
例子2
在这里,我们创建了一些不能在训练集中的随机/疯狂字符串。 结果看起来仍然是可以提供的最连贯的解决方案,在这种情况下:输入参数的总和。
例子3
在这个例子中,我们要求(用西班牙语)在给定圆心和半径的情况下求两个圆的相交面积之和。 Copilot 可以毫无问题地理解西班牙语文本,并建议函数名称、参数和所有函数体。 经过简短的审查后,看起来代码应该可以工作。
例子4
现在我们创建一个假设的问题/答案文本。 这使得 Copilot 将查询与可能在此训练数据集中的一些考试相匹配。 我们只需询问西班牙的首都,Copilot 就会生成正确答案。
例子5
但是,如果我们询问一个不存在的国家,Copilot 也会给出看起来“正确”的最佳答案。
例子6
在这个例子中我们反转这个过程,我们给出答案来尝试生成问题。 Copilot 产生了一个我们没有预料到的问题。 我们期待“法国的首都是什么?” 副驾驶问“以下代码的结果是什么?” 但我们仍然可以理解正确的建议。
例子7
在这里,我们迫使 Copilot 询问我们想要更改为更通用的语言并添加第一个字母。然而,它产生了另一个问题,这一次是完全错误的,并且与答案无关。
总之,副驾驶:
- 根据最常见的解决方案构建建议。
- 如果您的查询有意义,通常是正确的。
- 当您的查询看起来像一个常见问题但实际上不是,并且它实际上有一个非常不同的目标时,通常是错误的。
Copilot 使用开源库
Copilot 接受过开源项目的培训。 它包含任何开源库(如 numpy、opencv、qt)的数百万个用例……这使得 Copilot 非常有用,因为它可以帮助程序员提供最常见的建议,而这些建议通常是最好的。
例子8
在此示例中,我们使用 单元测试 python 模块,并且 Copilot 知道 单元测试.TestCase 有一个名为的方法 断言相等 并且也知道 富(1, 2) 应该是3。
例子9
上面我们创建了一个更复杂的 FOO 函数(我们假设它不能在训练数据中),看看 Copilot 是否真的理解代码。 用 17 个测试用例运行代码后,只有 6 个失败,成功率为 65%。
它可能看起来不多,但请记住,Copilot 不是 Python 解释器,它没有执行函数来获取其输出...... Copilot 使用在训练期间学到的知识将我们的查询转换为具有完美 Python 语法的输出和也有 65% 的时间运行良好。
例子10
人们可能期望输入较长的文本会导致 Copilot 失败,但事实并非如此,我们提供的信息越多,copilot 可以生成的答案就越好。
在上面的示例中,我们要求一个复杂的任务,一个需要不同理解才能解决的完整程序,例如:python 编程技巧、micropython 特定库以及如何在人类文本描述理解中正确使用它们。
完整的提示显示在下一个单元格中。 请注意,它与程序描述非常匹配。 应用程序类是有意义的,甚至正确使用了 micropython 库(PIN、UART、ADC、PIN.irq…)。 它不是 100% 完美的,例如在这种情况下 温度传感器 是一个 ADC 对象,它没有 温度传感器.init() 方法,和其他小错误可以产生,但整个程序的结构是绝对正确的,小错误可以很容易地修复。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 进口 次 进口 程 应用领域: DEF __init__(自): 自.按键 = .别针(0,机器.置顶.在) 自.温度传感器 = .ADC(机.别针(1)) 自.乌尔特 = .串口(1, 115200) 自.乌尔特.在里面(115200, 位=8, 平价=不包含, 停止=1) 自.最后一个事件 = 0 自.最后一个温度 = 0 自.上次 = 0 自.按键.中断(触发= .置顶.IRQ_FALLING,处理程序=自.按钮按下) 自.按键.中断(触发= .置顶.IRQ_RISING,处理程序=自.按钮_释放) 自.温度传感器.在里面() DEF 按下按钮(自, 别针): 自.最后一个事件 = 1 自.上次 = 次.ticks_ms() 自.乌尔特.写(b'{},{},{}\n'.格式(自.上次, 自.最后一个事件, 自.最后的温度)) DEF 按钮已释放(自, 别针): 自.最后一个事件 = 0 自.上次 = 次.ticks_ms() 自.乌尔特.写(b'{},{},{}\n'.格式(自.上次, 自.最后一个事件, 自.最后的温度)) DEF 读取温度(自): 自.最后一个温度 = 自.温度传感器.读() 自.乌尔特.写(b'{},{},{}\n'.格式(自.上次, 自.最后一个事件, 自.最后的温度)) DEF 运行(自): 而 真: 自.read_temp() 时间.睡觉(0.1) |
例子11
最后,在下面的示例中,我们使用 Copilot 将注释添加到前面的代码中。 我们复制该类两次,并向 Copilot 添加一些指南,例如“上述类的 Docstring 版本”。 Copilot 为每一行生成类和注释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | # 上述类的文档字符串版本 程 应用领域: “““ 简短的: 这是一个简单的应用程序,它读取温度传感器并将数据发送到 UART。 数据以以下格式发送: 时间、事件、温度 时间是自应用程序启动以来的时间(以毫秒为单位)。 如果按钮被按下,则事件为 1,如果按钮被释放,则事件为 0。 temp 是以摄氏度为单位的温度。 “”“ DEF __init__(自): # 创建一个按钮对象 自.按键 = .别针(0,机器.置顶.在) # 创建温度传感器对象 自.温度传感器 = .ADC(机.别针(1)) # 创建一个UART对象 自.乌尔特 = .串口(1, 115200) # 初始化UART对象 自.乌尔特.在里面(115200, 位=8, 平价=不包含, 停止=1) # 创建一个变量来存储最后一个事件 自.最后一个事件 = 0 # 创建一个变量来存储最后的温度 自.最后一个温度 = 0 # 创建一个变量来存储上次的时间 自.上次 = 0 # 注册按钮按下事件处理程序 自.按键.中断(触发= .置顶.IRQ_FALLING,处理程序=自.按钮按下) # 注册按钮释放事件处理程序 自.按键.中断(触发= .置顶.IRQ_RISING,处理程序=自.按钮_释放) # 初始化温度传感器 自.温度传感器.在里面() DEF 按下按钮(自, 别针): # 设置最后一个事件为1 自.最后一个事件 = 1 # 将上次时间设置为当前时间 自.上次 = 次.ticks_ms() # 将上次时间、上次事件和上次温度发送到 UART 自.乌尔特.写(b'{},{},{}\n'.格式(自.上次, 自.最后一个事件, 自.最后的温度)) DEF 按钮已释放(自, 别针): # 设置最后一个事件为0 自.最后一个事件 = 0 # 将上次时间设置为当前时间 自.上次 = 次.ticks_ms() # 将上次时间、上次事件和上次温度发送到 UART 自.乌尔特.写(b'{},{},{}\n'.格式(自.上次, 自.最后一个事件, 自.最后的温度)) DEF 读取温度(自): # 将上次温度设置为当前温度 自.最后一个温度 = 自.温度传感器.读() # 将上次时间、上次事件和上次温度发送到 UART 自.乌尔特.写(b'{},{},{}\n'.格式(自.上次, 自.最后一个事件, 自.最后的温度)) DEF 运行(自): 而 真: # 读取温度 自.读临时() # 等待 0.1 秒 次.睡觉(0.1) |