在以上條件知足的狀況下,測試可否正確生成代碼,測試可否下載生成的代碼文件python
測試在以上異常狀況下網站的報錯狀況chrome
測試期間發現一些比較嚴重的bug,部分已經獲得修復canvas
內測版本發現的主要問題有:後端
對部分bug進行修復以後,當前版本還存在的主要問題有:瀏覽器
註冊時,用戶名含有;.<>?/:"{}[]|'~`!#$%^&*()等特殊字符或者中文字符時,會彈出「用戶名或郵箱已被註冊」網絡
用戶搭好模型以後想登陸保存,登陸以後畫布清空併發
幫助界面側邊欄與正文重疊ide
Beta階段咱們加入了註冊、登陸功能,用戶能夠保存本身搭建的模型,登陸以後能夠查看以前保存的模型,並在此基礎上進行修改再保存;此外,咱們還增長了代碼文件下載的新功能,提高用戶體驗。如下是測試過程當中針對新功能發現的問題:學習
猿巨註冊了一個帳號;測試
註冊完以後猿巨登陸成功,而後看了幫助文檔後試着本身隨便搭了個模型,進行保存;
猿巨想看是否真的保存成功,因而登出帳戶,再次登陸,查看模型;
猿巨點擊查看,畫布上顯示出他以前搭建的模型,因而猿巨又改了改模型,再次保存,查看模型,發現模型成功修改;
猿巨點擊代碼生成,發現生成了三份代碼,但是他看不懂,因而又點回畫布,拖着組件玩弄,最後退出登陸。
戰錘註冊了一個帳號;
本身拖拽組件並搭建了一個模型,進行保存以後,查看模型並生成代碼;
戰錘將生成的代碼文件下載下來,結合本身的數據進行訓練、運行;發現參數調節的不太合適;
戰錘回到網站,查看以前保存的模型,並對其中的參數進行調節,從新保存修改後的模型,並查看再次生成代碼;
戰錘通過屢次調節,不用本身手寫代碼就獲得本身想要的模型;
戰錘又搭建了幾個模型,並進行保存,查看帳戶的模型,本身搭建的模型都在,而且能夠隨時進行修改;
戰錘完成工做後,登出帳戶;
一段時間後,戰錘登陸帳戶查看模型,發現以前搭建的模型有重複的,因而將重複的幾個模型刪除,登出帳戶。
車伕註冊了一個帳號;
車伕利用網站新增長的元素級相加層和channel維度拼接層,再結合網站以前已有的組件,搭建出一個較複雜的並聯的模型;
車伕查看已保存的模型並生成代碼,將生成的代碼文件下載下來,結合本身的數據文件,進行訓練、運行;
車伕在調整修改時,忽然電腦顯示快關機了,因而車伕點擊保存,先將模型保存下來,以後找到電源再繼續,免於讓本身的努力功虧一簣;
車伕再找到電源後登陸帳戶完善模型,獲得本身想要的模型代碼,並保存最新的模型,登出帳戶。
在這一階段,咱們作了迴歸測試,首先,第一個向後端發送的數據沒有涉及到新增的兩個網絡層,以此測試新增的網絡層對以前的網絡層是否會形成影響;
def test_ops_five(self): """ Test the addition of two strings returns the two string as one concatenated string """ result = { "Main": ["'''", "", "Copyright @2019 buaa_huluwa. All rights reserved.", "", "View more, visit our team's home page: https://home.cnblogs.com/u/1606-huluwa/", "", "", "This code is the corresponding pytorch code generated from the model built by the user.", "", " \"main.py\" mainly contains the code of the training and testing part, and you can modify it according to your own needs.", "", "'''", "", "#standard library", "import os", "", "#third-party library", "import torch", "import numpy", "import torchvision", "", "", "from Model import *", "from Ops import *", "", "", "#Hyper Parameters", "epoch = 1", "optimizer = torch.optim.Adam", "learning_rate = 0.001", "batch_size = 50", "data_dir = None", "data_set = None", "train = True", "", "", "#initialize a NET object", "net = NET()", "#print net architecture", "print(net)", "", "", "#load your own dataset and normalize", "", "", "", "#you can add some functions for visualization here or you can ignore them", "", "", "", "#training and testing, you can modify these codes as you expect", "for epo in range(epoch):", "", ""], "Model": ["'''", "", "This code is the corresponding pytorch code generated from the model built by the user.", "", "\"model.py\" contains the complete model code, and you can modify it according to your own needs", "", "'''", "", "#standard library", "import os", "", "#third-party library", "import torch", "import numpy", "import torchvision", "", "", "class NET(torch.nn.Module):", " def __init__(self):", " super(NET, self).__init__()", " self.conv1d_layer = torch.nn.Sequential(", " torch.nn.Conv1d(", " in_channels = 1,", " out_channels = 16,", " kernel_size = 5,", " stride = 1,", " padding = 2,", " ),", " torch.nn.functional.relu(),", " torch.nn.functional.max_pool2d(),", " )", " self.conv2d_layer = torch.nn.Sequential(", " torch.nn.Conv2d(", " in_channels = 16,", " out_channels = 32,", " kernel_size = 5,", " stride = 1,", " padding = 2,", " ),", " torch.nn.functional.relu(),", " torch.nn.functional.max_pool2d(),", " )", " self.linear_layer = torch.nn.Linear(32, 10)", " def forward(self, x_data):", " view_layer_data = x_data.view(1)", " conv1d_layer_data = self.conv1d_layer(view_layer_data)", " conv2d_layer_data = self.conv2d_layer(conv1d_layer_data)", " linear_layer_data = self.linear_layer(conv2d_layer_data)", " return linear_layer_data"], "Ops": ["'''", "", "This code is the corresponding pytorch code generated from the model built by the user.", "", "\"ops.py\" contains functions you might use", "", "'''", "", "#standard library", "import os", "", "#third-party library", "import torch", "import numpy", "import torchvision", "", "", "def element_wise_add(inputs):", " ans = inputs[0]", " for indx in range(1, len(inputs)):", " ans.add_(inputs[indx])", " return ans"] } data = { "nets":{ "canvas_4":{ "name":"start", "attribute":{ "start":"true" }, "left":"151px", "top":"102px" }, "canvas_5":{ "name":"view_layer", "attribute":{ "shape":"1" }, "left":"386px", "top":"98px" }, "canvas_6":{ "name":"conv1d_layer", "attribute":{ "in_channels":"1", "out_channels":"16", "kernel_size":"5", "stride":"1", "padding":"2", "activity":"torch.nn.functional.relu", "pool_way":"torch.nn.functional.max_pool2d", "pool_kernel_size":"3", "pool_stride":"1", "pool_padding":"2" }, "left":"268px", "top":"282px" }, "canvas_7":{ "name":"conv2d_layer", "attribute":{ "in_channels":"16", "out_channels":"32", "kernel_size":"5", "stride":"1", "padding":"2", "activity":"torch.nn.functional.relu", "pool_way":"torch.nn.functional.max_pool2d", "pool_kernel_size":"3", "pool_stride":"1", "pool_padding":"2" }, "left":"494px", "top":"354px" }, "canvas_8":{ "name":"linear_layer", "attribute":{ "in_channels":"32", "out_channels":"10" }, "left":"75px", "top":"209px" } }, "nets_conn":[ { "source":{ "id":"canvas_4", "anchor_position":"Right" }, "target":{ "id":"canvas_5", "anchor_position":"Left" } }, { "source":{ "id":"canvas_5", "anchor_position":"Bottom" }, "target":{ "id":"canvas_6", "anchor_position":"Top" } }, { "source":{ "id":"canvas_6", "anchor_position":"Bottom" }, "target":{ "id":"canvas_7", "anchor_position":"Left" } }, { "source":{ "id":"canvas_7", "anchor_position":"Bottom" }, "target":{ "id":"canvas_8", "anchor_position":"Bottom" } } ], "static":{ "epoch":"1", "learning_rate":"0.001", "batch_size":"50" } } res = NeuralNetwork.translate.ops.main_func(data) self.assertEqual(res, result)
第二個向後端發送的數據包括以前已有的網絡層和新增的網絡層。
def test_ops_six(self): """ Test the addition of two strings returns the two string as one concatenated string """ result = { "Main": ["'''", "", "Copyright @2019 buaa_huluwa. All rights reserved.", "", "View more, visit our team's home page: https://home.cnblogs.com/u/1606-huluwa/", "", "", "This code is the corresponding pytorch code generated from the model built by the user.", "", " \"main.py\" mainly contains the code of the training and testing part, and you can modify it according to your own needs.", "", "'''", "", "#standard library", "import os", "", "#third-party library", "import torch", "import numpy", "import torchvision", "", "", "from Model import *", "from Ops import *", "", "", "#Hyper Parameters", "epoch = 1", "optimizer = torch.optim.Adam", "learning_rate = 0.5", "batch_size = 1", "data_dir = None", "data_set = None", "train = True", "", "", "#initialize a NET object", "net = NET()", "#print net architecture", "print(net)", "", "", "#load your own dataset and normalize", "", "", "", "#you can add some functions for visualization here or you can ignore them", "", "", "", "#training and testing, you can modify these codes as you expect", "for epo in range(epoch):", "", ""], "Model": ["'''", "", "This code is the corresponding pytorch code generated from the model built by the user.", "", "\"model.py\" contains the complete model code, and you can modify it according to your own needs", "", "'''", "", "#standard library", "import os", "", "#third-party library", "import torch", "import numpy", "import torchvision", "", "", "class NET(torch.nn.Module):", " def __init__(self):", " super(NET, self).__init__()", " self.conv2d_layer = torch.nn.Sequential(", " torch.nn.Conv2d(", " in_channels = 1,", " out_channels = 96,", " kernel_size = 11,", " stride = 4,", " padding = 0,", " ),", " torch.nn.functional.relu(),", " torch.nn.functional.max_pool2d(),", " )", " self.conv2d_layer_1 = torch.nn.Sequential(", " torch.nn.Conv2d(", " in_channels = 96,", " out_channels = 256,", " kernel_size = 5,", " stride = 1,", " padding = 2,", " ),", " torch.nn.functional.relu(),", " torch.nn.functional.max_pool2d(),", " )", " self.conv2d_layer_2 = torch.nn.Sequential(", " torch.nn.Conv2d(", " in_channels = 256,", " out_channels = 384,", " kernel_size = 3,", " stride = 1,", " padding = 1,", " ),", " torch.nn.functional.relu(),", " )", " self.conv2d_layer_3 = torch.nn.Sequential(", " torch.nn.Conv2d(", " in_channels = 384,", " out_channels = 384,", " kernel_size = 3,", " stride = 1,", " padding = 1,", " ),", " torch.nn.functional.relu(),", " )", " self.conv2d_layer_4 = torch.nn.Sequential(", " torch.nn.Conv2d(", " in_channels = 384,", " out_channels = 256,", " kernel_size = 3,", " stride = 1,", " padding = 1,", " ),", " )", " self.linear_layer = torch.nn.Linear(256, 4096)", " self.linear_layer_1 = torch.nn.Linear(4096, 4096)", " self.linear_layer_2 = torch.nn.Linear(4096, 1000)", " def forward(self, x_data):", " conv2d_layer_data = self.conv2d_layer(x_data)", " element_wise_add_layer_data = element_wise_add([x_data])", " conv2d_layer_1_data = self.conv2d_layer_1(conv2d_layer_data)", " conv2d_layer_2_data = self.conv2d_layer_2(conv2d_layer_1_data)", " conv2d_layer_3_data = self.conv2d_layer_3(conv2d_layer_2_data)", " conv2d_layer_4_data = self.conv2d_layer_4(conv2d_layer_3_data)", " linear_layer_data = self.linear_layer(conv2d_layer_4_data)", " linear_layer_1_data = self.linear_layer_1(linear_layer_data)", " linear_layer_2_data = self.linear_layer_2(linear_layer_1_data)", " return element_wise_add_layer_data, linear_layer_2_data"], "Ops": ["'''", "", "This code is the corresponding pytorch code generated from the model built by the user.", "", "\"ops.py\" contains functions you might use", "", "'''", "", "#standard library", "import os", "", "#third-party library", "import torch", "import numpy", "import torchvision", "", "", "def element_wise_add(inputs):", " ans = inputs[0]", " for indx in range(1, len(inputs)):", " ans.add_(inputs[indx])", " return ans"] } data = { "nets": { "canvas_1": { "name": "start", "attribute": { "start": "true" }, "left": "365px", "top": "20px" }, "canvas_2": { "name": "conv2d_layer", "attribute": { "in_channels": "1", "out_channels": "96", "kernel_size": "11", "stride": "4", "padding": "0", "activity": "torch.nn.functional.relu", "pool_way": "torch.nn.functional.max_pool2d", "pool_kernel_size": "3", "pool_stride": "2", "pool_padding": "0" }, "left": "317px", "top": "109px" }, "canvas_3": { "name": "conv2d_layer", "attribute": { "in_channels": "96", "out_channels": "256", "kernel_size": "5", "stride": "1", "padding": "2", "activity": "torch.nn.functional.relu", "pool_way": "torch.nn.functional.max_pool2d", "pool_kernel_size": "3", "pool_stride": "2", "pool_padding": "0" }, "left": "315px", "top": "203px" }, "canvas_4": { "name": "conv2d_layer", "attribute": { "in_channels": "256", "out_channels": "384", "kernel_size": "3", "stride": "1", "padding": "1", "activity": "torch.nn.functional.relu", "pool_way": "None", "pool_kernel_size": "", "pool_stride": "", "pool_padding": "0" }, "left": "313px", "top": "306px" }, "canvas_5": { "name": "conv2d_layer", "attribute": { "in_channels": "384", "out_channels": "384", "kernel_size": "3", "stride": "1", "padding": "1", "activity": "torch.nn.functional.relu", "pool_way": "None", "pool_kernel_size": "", "pool_stride": "", "pool_padding": "0" }, "left": "315px", "top": "355px" }, "canvas_6": { "name": "conv2d_layer", "attribute": { "in_channels": "384", "out_channels": "256", "kernel_size": "3", "stride": "1", "padding": "1", "activity": "None", "pool_way": "None", "pool_kernel_size": "3", "pool_stride": "2", "pool_padding": "0" }, "left": "316px", "top": "404px" }, "canvas_7": { "name": "linear_layer", "attribute": { "in_channels": "256", "out_channels": "4096" }, "left": "316px", "top": "541px" }, "canvas_8": { "name": "linear_layer", "attribute": { "in_channels": "4096", "out_channels": "4096" }, "left": "318px", "top": "672px" }, "canvas_9": { "name": "linear_layer", "attribute": { "in_channels": "4096", "out_channels": "1000" }, "left": "319px", "top": "827px" }, "canvas_10": { "name": "element_wise_add_layer", "attribute": { "element_wise_add_layer": "true" }, "left": "91px", "top": "830px" } }, "nets_conn": [ { "source": { "id": "canvas_1", "anchor_position": "Bottom" }, "target": { "id": "canvas_2", "anchor_position": "Top" } }, { "source": { "id": "canvas_2", "anchor_position": "Bottom" }, "target": { "id": "canvas_3", "anchor_position": "Top" } }, { "source": { "id": "canvas_4", "anchor_position": "Bottom" }, "target": { "id": "canvas_5", "anchor_position": "Top" } }, { "source": { "id": "canvas_5", "anchor_position": "Bottom" }, "target": { "id": "canvas_6", "anchor_position": "Top" } }, { "source": { "id": "canvas_3", "anchor_position": "Bottom" }, "target": { "id": "canvas_4", "anchor_position": "Top" } }, { "source": { "id": "canvas_1", "anchor_position": "Left" }, "target": { "id": "canvas_10", "anchor_position": "Top" } }, {"source": { "id": "canvas_6", "anchor_position": "Bottom" }, "target": { "id": "canvas_7", "anchor_position": "Top" } }, { "source": { "id": "canvas_7", "anchor_position": "Bottom" }, "target": { "id": "canvas_8", "anchor_position": "Top" } }, { "source": { "id": "canvas_8", "anchor_position": "Bottom" }, "target": { "id": "canvas_9", "anchor_position": "Top" } } ], "static": { "epoch": "1", "learning_rate": "0.5", "batch_size": "1" } } res = NeuralNetwork.translate.ops.main_func(data) self.assertEqual(res, result)
測試矩陣 | 功能測試 | 頁面測試 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
測試瀏覽器 | 測試環境(瀏覽器版本) | 組件拖拽 | 組件刪除 | 組件連線 | 參數輸入 | 點擊事件(組件、按鈕、連接)下拉框選擇 | 報錯狀況 | 註冊登陸 | 保存模型 | 查看模型 | 刪除模型 | 生成代碼 | 代碼下載 | 主頁面 | 聯繫咱們頁面 | 幫助頁面 | 代碼生成頁面 | 頁面切換 |
chrome | 74.0.3729.131 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 縮小查看時側邊欄會與正文重疊 | 正常 | 正常 |
火狐 | 67.0(64位) | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 側邊欄居中 | 正常 | 正常 |
edge | 42.17134.1.0 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 側邊欄居中 | 正常 | 正常 |
UC | 6.2.4098.3 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 側邊欄與正文重疊 | 正常 | 正常 |
Opera | 60.0.3255.95 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 縮小查看時側邊欄與正文重疊 | 正常 | 正常 |
搜狗 | 8.5.10.30358 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 縮小查看時側邊欄與正文重疊 | 正常 | 正常 |
獵豹 | 6.5.115.18552 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 正常 | 縮小查看時側邊欄與正文重疊 | 正常 | 正常 |
經過badboy + jmeter的方式,對網站進行壓力測試,設置併發數爲100,對用戶登陸查看模型,查看幫助文檔等進行測試。
在Beta階段,咱們的目標是在以前的基礎上,加入註冊登陸功能,讓用戶保存本身的工做成果,不用重複搭建模型或者在緊急時保存當前進度;而且支持了更多的網絡層,用戶能夠搭建更多樣的模型。所以,咱們將這一版本的出口條件設置爲:
實現用戶的註冊登陸,登陸以後對以前保存的模型的增刪改查;能夠利用新增的網絡層結合以前的網絡層搭建出更多的模型,而且支持對生成代碼文件的下載
目前項目的核心功能就是支持註冊登陸,而且用戶能夠經過組件的拖拽、連線、配置參數搭建模型,經過模型能生成相應的代碼而且支持下載,用戶登陸以後還能夠保存、修改及刪除本身搭建的模型。在Beta版本中,咱們針對Alpha版本對模型的單一支持與不能實時修改等作了改進,完成了一個基本完善的產品,可用性及用戶體驗方面都有了很大提高。在接下來的版本中,咱們會更多地花時間去豐富產品內容、提高用戶體驗。
秉承敏捷開發的原則,在達到出口條件的基礎上,爲了提高用戶體驗,咱們對首頁頁面作了美化,還對幫助文檔作了相應調整,優化了幫助界面,而且細化了各個方面的介紹,爲用戶提供更精確的操做步驟,此外咱們在幫助文檔中提供了幾個經典模型的搭建,裏面有咱們提供的一些模型的例子,用戶能夠查看學習。
雖然已達到了預約的目標,可是這一版本仍是存在一些問題的,好比註冊時不能使用中文名或者一些特殊字符、頁面的UI不夠美觀等,這些都是影響產品總體表現地問題所在。
在你們的共同努力下,完成了Beta版本預期的主要目標。在此基礎上,通過你們的討論,在接下來的版本中,咱們列出了幾個目標:
接下來的時間裏,咱們會繼續努力,在完成核心功能的基礎上多考慮提高用戶體驗,交付一個儘量實現的最好的產品。