近年來,由於自然語言處理領域轉換器(transformers)的興起,我們看到了一系列令人震驚的程式碼編寫深度學習模型。能夠編寫電腦程式的電腦程序,通常稱為程式合成問題,至少從20世紀60年代末和20世紀70年代初就已開始研究。
在21世紀10年代和20年代,基於注意力的模型在其他領域的成功再次激發了程式合成研究的動力,即在數百GB的文本上預先訓練具有數百萬或數十億參數的大規模基於注意力的神經模型(轉換器)的策略。
經過預先訓練的模型在元學習方面表現出了令人印象深刻的能力,這得益於它們的注意力機制,並且似乎可以實際應用於文本任務開發方面——通過在提示內容中僅提供少數幾個範例(研究文獻中稱作「零樣本或小樣本學習」)。
NLP模型可以進一步使用專門的資料集進行訓練,以微調特定任務的效能。編寫程式碼就是這方面應用的一個特別有趣的使用場景。
GitHub上的Copilot項目,被宣傳為“你的人工智慧程式設計夥伴(Your AI Pair Programmer)”,在2021推出時引起不小的爭議。在很大程度上,這是由於在訓練資料集中使用了所有公開的GitHub程式碼。根據有關說明,這些程式碼庫包括具有Copyleft許可證的項目,這些項目可能不允許將程式碼用於Copilot等項目,除非Copilot本身是開源的。
Copilot是OpenAI組織和微軟公司之間關係的產物,基於GPT-3的一個經過程式碼訓練的版本。由OpenAI示範並透過其API提供的版本稱為Codex。使用Copex的正式實驗描述在陳先生等人於2021年發表的論文中有詳細的介紹。
2022年初,DeepMind公司也不甘示弱,開發出自己的程式合成深度NLP系統:AlphaCode。
與先前的Codex和Copilot一樣,AlphaCode是一個設計和訓練用來編寫程式碼的大型NLP模型。如Copilot一樣,AlphaCode的開發也不是為了將AlphaCode作為軟體工程師的生產力工具,而是用於在競賽類程式設計任務中挑戰人類層級的程式設計效能。
用於訓練和評估AlphaCode(組成新的CodeContests資料集)的競賽編碼挑戰的難度介於先前資料集難度和現實世界軟體工程難度之間。
對於那些不熟悉競賽類程式設計挑戰網站的人來說,這項任務有點像是測試驅動開發的簡化版本。根據給定的一些文字描述和幾個例程,這種挑戰的主要內容就是,編寫一個通過一組測試的程式——其中大部分測試對程式設計師來說都是隱藏的。
理想情況下,隱藏測試應該是全面的,通過所有測試也就代表順利解決了給定的問題。但是,用單元測試覆蓋每個邊緣情況是一個困難的問題。對程式合成領域的一個重要貢獻實際上是CodeContests資料集本身,因為DeepMind團隊做出了重大努力——他們透過突變過程產生額外的測試,目的是為了降低誤報率(測試通過,但問題尚未解決)和慢陽性率(測試通過,但解決方案太慢)。
AlphaCode的表現是根據競賽網站CodeForces上的競賽程式設計挑戰內容進行評估的。總體上,AlphaCode在參與競賽的(也可能是人類)程式設計師中的平均表現為「前54.3%」。
請注意,該指標可能有點誤導,因為它實際上等同於45.7%的績效。令人難以置信的是,AlphaCode系統能夠編寫任何通過所有隱藏測試的演算法。但是,請注意:AlphaCode使用了與人類截然不同的策略來解決程式設計問題。
雖然人類競爭對手可能會編寫一種演算法來解決大多數例程——結合運行早期版本解決方案的見解不斷改進,直到通過所有測試;但是,AlphaCode採用了一種基礎更廣泛的方法,即為每個問題產生多個樣本,然後選擇10個樣本提交。
AlphaCode在CodeContests資料集上的效能的一大貢獻是,產生後過濾和聚類的結果:它在產生大約1000000個候選解決方案後,開始過濾候選方案,以刪除問題描述中未通過範例測試的候選方案,從而消除約99%的候選群體。
作者提到,大約10%的問題沒有通過此階段所有範例測試的候選解決方案。
然後透過聚類將剩餘的候選項篩選到10份或更少的提交。簡而言之,他們訓練了另一個模型,以根據問題描述產生額外的測試輸入(但請注意,他們沒有這些測試的有效輸出)。
剩餘的候選解決方案(過濾後的數量可能小於1000個),根據其在產生的測試輸入上的輸出進行聚類。按照從最大到最小的順序,從每個集群中選擇一個候選對象進行提交。如果簇少於10個,則對簇進行多次取樣。
雖然過濾/聚類步驟是獨特的,並且AlphaCode在新的CodeContests資料集上進行了微調,但它最初的訓練方式與Codex或Copilot大致相同。 AlphaCode首先在GitHub(2021年7月14日檢索)的一個大型公共可用程式碼資料集上接受了預訓練。他們訓練了5種變型,參數個數從2.84億個增加到410億個。
與AlphaGo系列或玩星海爭霸II遊戲的AlphaStar機器人的精神一樣,AlphaCode也是一個研究項目,旨在開發一個接近人類在專門任務領域的能力的系統,而且在程式合成過程中開發出的實用程式的門檻更低。
從開發解決問題的實用工具的角度來說,這方面機器人的代表是基於GPT-3的Codex和Copilot工具。 Codex是GPT-3的OpenAI變體,在一個公共可用程式碼的語料庫上進行訓練。根據與論文一起發布的HumanEval資料集,OpenAI報告稱,Codex透過在「docstring to code」格式的任務中產生100個樣本,能夠解決70%以上的問題。
接下來,我們將探索這種透過使用Codex自動產生程式碼的提示符號程式設計技術。我們將同時使用下面給定的模型來開發約翰康威的《生命遊戲》。
GitHub Copilot採用程式碼自動補全的方法,目前的包裝形式是Visual Studio,VSCode,Neovim和JetBrains等整合開發環境的擴充的方式。根據Copilot網頁相關描述,Copilot已能夠成功地根據給定描述重新編寫出一組經過良好測試的Python函數,其中57%的函數與HumanEval資料集類似。
我們將研究Copilot的一些實際用例,例如使用VSCode的專用測試版的Copilot擴充功能自動編寫測試。
在本節中,我們將介紹基於約翰康威的《生命遊戲》編寫細胞自動機模擬器的任務。稍加了一點修改,沒有對規則硬編碼,我們的程式應該能夠模擬任何一組類生命的細胞自動機規則。
我們將採用互動式方法,而不是透過產生100個範例並選擇最佳範例(可以是手動方式也可以透過執行測試的方式)。當Codex給出一個糟糕的解決方案的時候,我們將做出調整以嘗試引導更好的答案。當然,如果絕對必要的話,在Codex完全失敗的情況下,我們可以繼續修改程式碼以獲得一個能夠正常工作的範例。
寫一個逼真的CA(Cellular Automata,即「元胞自動機」。它是一種時間、空間、狀態都離散,空間交互作用和時間因果關係為局部的網格動力學模型,具有模擬複雜系統時空演化過程的能力)模擬器的第一步是提出一個計算鄰居的函數。我們編寫了以下docstring提示符,並將其提供給code-davinci-001,這是OpenAI API庫中最大的Codex模型:
# PROMPT<br>import numpy as np<br>def compute_neighborhood(grid: np.array) -> np.array:<br>"""<br>Compute the sum of cell states in the Moore neighborhood<br>for each cell in the input grid.<br>A Moore neighborhood includes 8 cells,<br>diagonally and orthogonally adjacent to, but not including, the center cell.<br>The cells denoted by '1' correspond to the Moore neighborhood for cell a:<br>1 1 1<br>1 a 1<br>1 1 1<br>If cell 'a' is on the edge of the grid,<br>the Moore neighborhood wraps around to the cells on the opposite edge,<br>i.e. grid is on a toroid.<br><br>args:<br>grid, a numpy array with binary values 0 or 1. grid contains the current cell state values<br>Returns:<br><br>neighorhood_grid, a numpy array with integer values from 0 to 8.<br>For each cell (element in grid) in grid, neighborhood_grid should<br>contain the sum of states in that cell's Moore neighborhood<br>"""
上述程式碼中,加入註解行“# PROMPT”和“ # GENERATED」是為了更清楚地說明提示符號從哪裡結束。
你仔細分析上面相當全面的docstring提示了沒有? Codex是怎麼做的?其實,Codex的第一次嘗試如下:
# GENERATED<br># TODO: implement this function<br>pass
這對我們的小實驗來說可能不是好兆頭。即使在調整P值超參數以實現更寬鬆的核採樣(並希望更好的多樣性)後,Codex似乎仍未給出上述問題的答案。
幸運的是,我們只需在docstring提示字元上添加一點類似於下面的內容,Codex就會產生一個更有希望的輸出。
# PROMPT (appended to previous prompt)<br><br>this function is completed and does not include any TODOs<br>"""<br><br># GENERATED<br><br># get the dimensions of the grid<br>n_rows, n_cols = grid.shape<br><br># initialize the output array<br>neighborhood_grid = np.zeros((n_rows, n_cols), dtype=int)<br><br># loop over the grid<br>for i in range(n_rows):<br>for j in range(n_cols):<br><br># get the current cell value<br>cell_val = grid[i, j]<br><br># get the Moore neighborhood of the current cell<br># using the get_neighborhood function<br>neighborhood = get_neighborhood(grid, i, j)<br><br># sum the cell values in the neighborhood<br>neighborhood_sum = np.sum(neighborhood)<br><br># store the sum in the neighborhood grid<br>neighborhood_grid[i, j] = neighborhood_sum<br><br>return neighborhood_grid
當然,這還不是一個很好的解決方案,因為它引入了一個未使用的變數cell_val,並將其大部分工作委託給它剛剛添加的另一個函數get_neighborhood。但總的來說,這看起來是一個可行的開始。
接下來,我們為上面提到的get_neighborhood函數寫了一個簡單的docstring:
def get_neighborhood(grid: np.array, i: int, j: int) -> np.array:<br>"""<br>get_neighborhood is used by compute_neighborhood <br>to return the 3x3 Moore neighborhood for the cell <br>located at coordinates i,j If i,j coordinates are <br>on the edge of the grid (i.e. i or j equal 0, or i == <br>grid.shape[0]-1 or j == grid.shape[1]), the Moore<br>Neighborhood should wrap around to include cells on the<br>opposite edge. In other words the grid can be considered to <br>be the surface of a toroid, like 'Pac-Man'<br><br>args:<br>grid, np.array, this is the current state of<br>the cellular automata grid<br>i, int, this coordinate corresponds to the row<br>j, int, coordinate corresponding to column<br><br>returns:<br>moore_neighborhood - np.array, should always have<br>dimensions 3x3 and<br>contain the Moore neighborhood for the cell at i,j <br>in grid.Because the center cell is not part of the<br>neighborhood, moore_neighborhood[1,1] should always <br>be 0<br>"""<br><br># GENERATED<br><br># get the dimensions of the grid<br>n_rows, n_cols = grid.shape<br><br># initialize the output array<br>moore_neighborhood = np.zeros((3, 3), dtype=int)<br><br># get the coordinates of the Moore neighborhood<br># using the get_neighborhood_coordinates function<br>neighborhood_coords = <br>get_neighborhood_coordinates(i, j, n_rows, n_cols)<br><br># loop over the coordinates<br>for coord in neighborhood_coords:<br># get the cell value at the coordinate<br>cell_val = grid[coord[0], coord[1]]<br><br># store the cell value in the output array<br>moore_neighborhood[coord[0], coord[1]] = cell_val<br><br>return moore_neighborhood
上面程式的輸出看起來也算可行;但經過檢查,它實際上包含了一個重要錯誤。
在鄰居座標的循環中,它使用與從網格中檢索值相同的座標為摩爾鄰居(Moore neighborhood)賦值。
我們沒有找到提示Codex避免錯誤的明確方法;因此,我們只好手動修改一下程式碼:
# FIXED loop over the coordinates <br>for index, coord in enumerate(neighborhood_coords): <br># get the cell value at the coordinate<br>cell_val = grid[coord[0], coord[1]] <br><br># FIXED store the cell value in the output array<br>moore_neighborhood[index // 3, index % 3] = cell_val<br><br>return moore_neighborhood
另外,前面程式碼中還引入了另一個函數get_neighborhood_coordinates來處理比較「棘手」的部分。
接下來,我們要為函數get_neighborhood_coordinates寫一個提示符。
# PROMPT <br>def get_neighborhood_coordinates(<br>i: int, j: int, n_rows: int, n_cols: int) -> list:<br>"""<br>get_neighborhood_coordinates is used by get_neighborhood <br>to return the coordinates of the 3x3 Moore neighborhood for<br>the cell located at coordinates i,j If i,j coordinates are on<br>the edge of the grid (i.e. i or j equal 0, or i ==<br>grid.shape[0]-1 or j == grid.shape[1]), the Moore<br>Neighborhood should wrap around to include cells on the<br>opposite edge. In other words the grid can be considered to <br>be the surface of a toroid, like 'Pac-Man'<br><br>args:<br>i, int, this coordinate corresponds to the row<br>j, int, coordinate corresponding to column<br>n_rows, int, number of rows in the grid<br>n_cols, int, number of columns in the grid<br><br>returns:<br>neighborhood_coords - list of tuples, <br>each tuple contains the coordinates<br>of a cell in the Moore neighborhood<br>"""<br><br># GENERATED<br><br># initialize the output list<br>neighborhood_coords = []<br><br># get the coordinates of the Moore neighborhood<br># using the get_neighborhood_coordinates function<br>for row in range(i-1, i+2):<br>for col in range(j-1, j+2):<br># skip the center cell<br>if row == i and col == j:<br>continue<br><br># check if the cell is on the edge of the grid<br># if so, wrap around to the opposite edge<br>if row row = n_rows - 1<br>elif row == n_rows:<br>row = 0<br><br>if col col = n_cols - 1<br>elif col == n_cols:<br>col = 0<br><br># store the cell coordinates<br>neighborhood_coords.append((row, col))<br><br>return neighborhood_coords
这比我们预期的函数式编程深度要深一点(compute_neighborhood调用get_neighborhood,反过来get_neighborhood又调用get_neighborhood_coordinates),但看起来我们终于有了一组函数,可以返回一个邻居和的网格。
还剩下update函数,它对应的docstring提示如下所示:
# PROMPT<br><br>def update_grid(grid: np.array, rules: list) -> np.array:<br>"""<br>update input arg grid according the the Life-like rules<br>contained in input arg rules. rules is a list of lists, <br>with the first element containing a list of 'birth'<br>conditions (cells go from 0 -> 1) and the second element<br>containing a list of 'survival' conditions (cells are<br>unchanged).<br>Cells which have a neighborhood sum that is not in the<br>'birth' (B) or 'survival' (S) rules go to 0. <br><br>This functions uses function compute_neighborhood to compute <br>the neighborhood value for each cell in grid.<br><br>args:<br>grid, np.array. grid contains the cell values (0 or 1)<br> rules, list of lists. rules contains the B/S rules <br> for Life-like cellular automatafor example, to<br> simulate Conway's Life CA, `rules = [[3], [2,3]]`,<br> i.e. B3/S23 Life Without Death has rules<br> B3/S012345678, so `rules = [[3],<br> [0,1,2,3,4,5,6,7,8]]`<br><br>update_grid should raise an Exception if rules contains <br>values greater than 8 (maximum number of live cells in a<br>Moore neighborhood) or less than 0. <br>"""<br><br># GENERATED<br><br># get the dimensions of the grid<br>n_rows, n_cols = grid.shape<br><br># get the neighborhood grid<br>neighborhood_grid = compute_neighborhood(grid)<br><br># loop over the grid<br>for i in range(n_rows):<br>for j in range(n_cols):<br># get the current cell value<br>cell_val = grid[i, j]<br><br># get the neighborhood value for the current cell<br>neighborhood_val = neighborhood_grid[i, j]<br><br># check if the cell is alive<br>if cell_val == 1:<br># check if the cell should die<br>if neighborhood_val not in rules[1]:<br>grid[i, j] = 0<br>else:<br># check if the cell should be born<br>if neighborhood_val in rules[0]:<br>grid[i, j] = 1<br><br>return grid
这看起来是解决上面问题的一种非常合理的方法;尽管我们确实明确建议,如果邻居网格包含错误的值并且在生成的输出中找不到,就会引发异常。
只需进行一些修复:在函数get_neighborhood中进行手动干预,并且尝试给出一些提示,我们就可以成功地设计出一个完全可行的类似生命的细胞自动机模拟器。
上面的代码不是一个特别快的实现方案,但它的质量与程序员在开始使用一种新语言时可能做出的那种“Hello World”尝试相似。值得注意的是,在训练数据集中包含了许多示例,供研究者参考。
在康威的《生命游戏》中,我们可以想象这段程序在微型滑翔机的发展过程中取得的成功。
虽然我们确实通过一组函数完成了CA模拟器的编写,但这种方法对于日常软件工程来说并不是非常有用或现实的开发方式。但另一方面,这并不能阻止像SourceAI这样的初创公司(本质上是OpenAI Codex API的包装商)将其服务宣传为“给每个人创造有价值的定制软件的机会”。
“我们构建了一个独立的系统,可以开发出世界上最熟练的工程师级别的软件。”不过,与Codex交互的确是学习或实践编程的一种潜在有用的方式,尤其是针对CodeSignal、CodeForces或HackerRank等网站的编程问题方面。
接下来,我们将尝试评估Codex/Copilot,以获得自动编写测试和docstring的更现实的使用情形。
对于本例来说,我们选择使用VSCode开发工具的GitHub Copilot扩展来编写测试。
# PROMPT (in VSCode)<br>import numpy as np<br>def pythagorean(a: np.float, b: np.float) -> np.float:<br>"""<br>Use the Pythagorean theorem to comput the hypotenuse for<br>a triangle with side lengths a and b<br><br>args:<br>a, np.float, side of the triangle<br>b, np.float, the other side of the triangle<br><br>returns:<br>c, np.float, the length of the hypotenuse<br>"""<br>c = np.sqrt(a**2 + b**2)<br>return c<br><br>def test_pythagorean():<br><br># GENERATED (Copilot autocomplete)<br>"""<br>Test the pythagorean function<br>"""<br>a = np.array([3, 4, 5])<br>b = np.array([4, 5, 6])<br>c = pythagorean(a, b)<br><br>assert np.allclose(c, np.sqrt(a**2 + b**2))
虽然毕达哥拉斯定理函数可能过于简单,但Copilot建议进行一次合理的测试。如果您运行它,它就会通过。你会注意到,自动完成建议能够正确地获得测试的结构和数字内容。
如果我们想使用自己喜欢的框架以更系统的方式编写测试,该怎么办?不用太担心,因为我们已经使用numpy库和自动微分技术编写了大量的低级学习模型,供给测试者使用。因此,虽然接下来的这个示例不是100%真实地来自真实世界,但效果还是比较贴近真实情况的。
在本例中,我们将使用autograd和numpy以及unittest中的TestCase类设置一个简单的多层感知器前向传递、损失函数和梯度函数进行测试。
#PROMPT<br>import unittest<br>from autograd import numpy as np<br>from autograd import grad<br><br>def forward_mlp(input_x: np.array, <br>weights: list, biases: list) -> np.array:<br>"""<br>compute the forward pass of a multilayer perceptron. <br>The number of layers is equal to the length of the list of<br>weights, which must be the same as the list of biases,<br>biases. <br><br>args:<br>input_x, np.array, input data<br>weights, list of np.arrays, a list of np.array matrices,<br> representing the weights<br>biases: list of np.arrays, a list of biases for each<br> layer<br><br>returns:<br>result, np.array, the output of the network<br>"""<br><br>assert len(weights) == len(biases)<br><br>for layer_index in range(len(weights) - 1):<br>input_x = np.tanh(np.matmul(input_x,<br>weights[layer_index]) + biases[layer_index])<br><br>output = np.matmul(input_x, weights[-1]) + biases[-1]<br>return output<br>def get_loss(input_x: np.array, weights: list, <br>biases: list, target: np.array) -> np.float:<br>"""<br>compute the mean squared error loss for an mlp with weights<br>and biases, with respect to the input data input_x and the<br>target array target.<br><br>args:<br>input_x, np.array, input data<br>weights, list of np.arrays, a list of np.array matrices,<br>representing the weights<br>biases: list of np.arrays, a list of biases for each<br>layer<br>target: np.array, the target values<br><br>returns:<br>loss, np.float, the loss<br>"""<br><br>output = forward_mlp(input_x, weights, biases)<br><br>return np.mean((output - target)**2)<br><br>get_loss_grad = grad(get_loss, argnum=(1,2))<br><br><br>class TestMLP(unittest.TestCase):<br>"""<br>tests for MLP, get_loss, and get_grad_loss<br>"""<br># GENERATED (chosen from Copilot suggestions)<br>def setUp(self):<br>pass<br><br>def test_forward_mlp(self):<br>"""<br>test forward_mlp<br>"""<br><br>input_x = np.array([[1, 2, 3], [4, 5, 6]])<br>weights = [np.array([[1, 2], [3, 4]]), <br>np.array([[5, 6], [7, 8]]), <br>np.array([[9, 10], [11, 12]])]<br>biases = [np.array([[1, 2]]), np.array([[3, 4]]),<br>np.array([[5, 6]])]<br><br>output = forward_mlp(input_x, weights, biases)<br>self.assertTrue(np.allclose(output, <br>np.array([[-0.9, -0.9], [-0.9, -0.9]])))<br><br>def test_get_loss(self):<br>"""<br>test get_loss<br>"""<br>input_x = np.array([[1, 2, 3], [4, 5, 6]])<br>weights = [np.array([[1, 2], [3, 4]]), <br>np.array([[5, 6], [7, 8]]), <br>np.array([[9, 10], [11, 12]])]<br>biases = [np.array([[1, 2]]), np.array([[3, 4]]),<br>np.array([[5, 6]])]<br>target = np.array([[1, 1], [1, 1]])<br><br>loss = get_loss(input_x, weights, biases, target)<br><br>self.assertTrue(np.allclose(loss, 0.5))<br><br>def test_get_loss_grad(self):<br>"""<br>test get_loss_grad<br>"""<br><br>input_x = np.array([[1, 2, 3], [4, 5, 6]])<br>weights = [np.array([[1, 2], [3, 4]]), <br>np.array([[5, 6], [7, 8]]), <br>np.array([[9, 10], [11, 12]])]<br>biases = [np.array([[1, 2]]), np.array([[3, 4]]), <br>np.array([[5, 6]])]<br>target = np.array([[1, 1], [1, 1]])<br><br>loss_grad = get_loss_grad(<br>input_x, weights, biases, target)<br><br>self.assertTrue(<br>np.allclose(loss_grad[0], <br>np.array([[-0.9, -0.9], [-0.9, -0.9]])))<br>self.assertTrue(<br>np.allclose(loss_grad[1], <br>np.array([[-0.9, -0.9], [-0.9, -0.9]])))<br>self.assertTrue(<br>np.allclose(loss_grad[2],<br>np.array([[-0.9, -0.9], [-0.9, -0.9]])))<br><br># END GENERATED (the final two lines are part of the prompt)<br>if __name__ == "__main__":<br>unittest.main(verbosity=1)
Copilot的建议虽然并不完美,但确实为测试类提供了合理的思路。不过,如果您尝试原封不动地运行代码的话,则不会执行任何测试,更不用说通过测试了。
输入数据和第一个权重矩阵之间存在维度不匹配,数据类型也是错误的(所有数组都是整数数据类型),而且无法使用Autograd梯度函数。
当然,上面这些问题并不是很难解决,如果用3x2矩阵替换权重矩阵列表中的第一个条目,那么前向传播应该可以运行。要使得梯度计算测试顺利进行,或者需要在np.array定义的数字上添加小数点,或者显式定义数组数据类型。
有了这些更改后,测试即可成功执行并失败,但预期值在数字表现方面还不正确。
Copilot有很大潜力的一项任务是自动编写文档,特别是为已经编写的函数填写docstring内容。这方面几乎是比较实用了。
对于毕达哥拉斯定理的示例程序,Copilot运行结果已经非常接近,但它将问题描述为查找两点a和b之间的距离,而不是查找边长c到边长a和边长b的距离。不出所料,随同Copilot一同发行的docstring中的示例也与函数的实际内容不匹配:返回的是一个标量,而不是c的值数组。
Copilot对前向MLP函数的docstrings的建议也很接近,但并不完全正确。
Copilot支持的自动Docstring建议
对于软件工程师来说,程序合成方面的每一项新进展都可能引发一次经济恐慌。
畢竟,如果電腦程式能像程式設計師一樣為電腦編程,這不意味著機器應該「取代我們的工作」嗎?不久的將來會這樣嗎?
從表面上看,答案似乎是「還沒有」;但是,這並不意味著隨著這些工具變得更加成熟,軟體工程的本質可能會保持不變。在未來,使用複雜的自動完成工具成功地進行推理可能與使用程式碼格式化工具一樣重要。
Copilot目前正處於測試版試用階段,關於如何使用它的選項數量有限。同樣,Codex也可以透過OpenAI在測試版中獲得應用程式介面。試點計畫的使用條款和隱私考慮確實限制了該技術的潛在使用情境。
根據目前的隱私權政策,輸入到這些系統的任何程式碼都可以用於微調模型,並且可以由GitHub/Microsoft或OpenAI的員工進行審查。這就排除了在敏感項目中使用Codex或Copilot的可能性。
Copilot確實為其所基於的Codex模型添加了許多實用程式。您可以為所需的程式碼編寫框架或大綱(如為unittest框架的測試編寫範例),並將遊標移至大綱的中間,以獲得合理的OK自動完成建議。
目前的Copilot,對於任何比簡單的編碼實踐更複雜的問題,都不太可能建議正確的完整程式碼;但是,它通常可以創建一個合理的大綱並節省一些手動輸入。
也應該注意的是,Copilot是在雲端運行的。這意味著它無法離線工作,自動完成建議也有點慢。此時,您可以按Alt ]組合鍵來循環瀏覽建議,但有時只有少數幾個建議可供選擇,甚至只有一個建議可供選擇。
當Copilot運作良好時——實際上已經足夠好了,有點危險。 unittest範例中建議的測試和為勾股函數建議的docstring乍看之下是正確的,可能會通過疲憊的軟體工程師的審查。但是,當它們包含神秘的錯誤時,這只會導致以後的痛苦!
綜上所述,雖然Copilot/Codex在目前的狀態下更像是玩具或學習工具,但令人難以置信的是它居然能運作。如果你遇到一隻跳著華爾滋舞的熊,我想令你印象深刻的不會是它跳得如何好。同樣,如果你遇到一個智慧程式碼完成工具,令你印象深刻的不應該是它寫的程式碼如何完美。
總之,隨著自動程式設計NLP模型技術的進一步發展,以及人類程式設計師對使用NLP自動完成工具的大量調整,很可能在不久的將來會出現程式合成模型的重大殺手級應用。
朱先忠,51CTO社群編輯,51CTO專家部落格、講師,濰坊一所大學電腦教師,自由程式設計界老兵一枚。早期專注各種微軟技術(編著成ASP.NET AJX、Cocos 2d-X相關三本技術圖書),近十多年投身於開源世界(熟悉流行全端Web開發技術),了解基於OneNet/AliOS Arduino/ ESP32/樹莓派等物聯網開發技術與Scala Hadoop Spark Flink等大數據開發技術。
原文標題:NLP Models for Writing Code: Program Synthesis#,作者:Kevin Vu
以上是自動編程NLP模型技術綜述的詳細內容。更多資訊請關注PHP中文網其他相關文章!