避撞功能是 Jetbot 一開始最令人矚目的功能,因為這是所有小車都必須具備的最基本“自我保護”的能力,而 Jetbot 沒有任何距離傳感,只憑著一個 CSI 攝像頭就能完成這項任務,對很多人來說是一件蠻神奇的事情,Jetbot 是如何識別與周邊物體的距離,來決定是繼續前進還是得轉向?
這里請大家先沉淀一下來思考,人腦是如何學習判斷前方的路是可以繼續前進?或是有障礙物、坑洞必須轉向?請先忘記您的成年人身份,試著模擬剛學會爬行的小嬰兒,如何逐步學習并建立這方面的“認知系統”呢?小嬰兒對前方的信息來源,有以下三個特點:
只有視覺(眼睛)的輸入
沒有距離的概念
缺乏物件的分類
在沒有其他干預的狀況下,小嬰兒必定得經過不斷地碰撞與摔倒之后,自身防御系統會逐步學習并修正決策機制,這是動物界最原始的學習機制。小嬰兒在這個過程所接收的信息,就是沒有距離、沒有物件類別的最基本“圖像”而已。
到目前為止,Jetbot 的運作邏輯是最接近人類行進思維的一套智能無人車,因為我們并不需要去判斷與障礙物(或坑洞)之間的確實距離是多近,也不需要分辨前面障礙物是什么東西,就能下達“前進”或“轉向”的決策。
當我們安裝好 Jetbot 智能車與系統軟件之后,接下去就是為每個特定功能添加“深度學習”的智能識別技術進去。例如這個避障的應用就只使用到最基礎的“圖像識別”能力,將 CSI 鏡頭的每幀畫面識別出“無阻礙(free)”與“有阻礙(blocked)”兩種狀態,然后發出對應指令去驅動電機執行運動。
任何要添加深度學習的智能識別功能,都必須執行以下三個步驟:
數據收集與整理
模型訓練
執行識別
這個避障功能的實驗代碼在 Jetbot 的 notebooks/collision_avoidance 下,里面有 8 個 .ipynb 文件,包括 1 個 data_collecton.ipynb、3 個 train_modelxxx.ipynb 與 4 個 live_demoxxx.ipynb,分別對應上面所說的三個步驟。不過這些實驗代碼不需要全都用上,這里以 data_collecton.ipynb、train_model.ipynb 與 live_demo.ipynb 這三個最基本的代碼來做說明。
礙于篇幅問題,本文先帶著大家運行 live_demo.ipynb 代碼,去體驗一下 Jetbot 的避障功能,畢竟前面花了這么多時間與精力所組裝的系統,先跑起來能獲得一些成就感之后,在下一篇文章里再說明比較枯燥的“數據收集與整理”、“模型訓練”兩大步驟,這樣才算完成整個流程。
為了讓大家能夠先行體驗,這里提供原創團隊預訓練的 best_model.pth 模型的鏈接,模型的訓練方式會在下一篇文章里面說明,這里只管下載到 collision_avoidance 目錄下使用就行。文件鏈接如下:https://drive.google.com/file/d/1UsRax8bR3R-e-0-80KfH2zAt-IyRPtnW/view
由于我們未得到原創團隊的授權,不能擅自下載這個存放在 Google 網盤上的文件,再分享給讀者下載,請大家能夠理解,這需要讀者請自行設法下載!
接下來開啟 notebooks/collision_avoidance/live_demo.ipynb 工作腳本,逐步執行就能讓 Jetbot 小車執行避障的功能。這里面主要分為以下三大部分:
1. 加載訓練的模型:
這里關于深度學習的部分,全部使用 PyTorch 這個輕量級的框架,對于不熟悉的讀者來說,一開始的兩行代碼可能就已經會產生不小的困擾,現在就簡單地逐行說明:
model = torchvision.models.alexnet(pretrained=False) |
torchvision 是 PyTorch 里面專門用在視覺應用的深度學習庫。
由于 PyTorch 內建支持很多常用的神經網絡結構,這里要使用深度卷積網絡始祖的 AlexNet,是因為前面提供下載連接的 best_model.pth 就是以 AlexNet 進行訓練的圖像識別模型,因此這里對應地用 torchvision.models.alexnet 函數來創建 model 對象。
由于現在是要執行推理任務而不是做訓練,因此 pretrained=FALSE
model.classifier[6] = torch.nn.Linear(model.classifier[6].in_features, 2) |
這行代碼是至關重要的,首先在這行代碼上方加入“print(model.classifier)”,執行后會看到以下的數據結構:
Sequential( (0):Dropout(p=0.5, inplace=False) (1):Linear(in_features=9216, out_features=4096, bias=True) (2):ReLU(inplace=True) (3):Dropout(p=0.5, inplace=False) (4):Linear(in_features=4096, out_features=4096, bias=True) (5):ReLU(inplace=True) (6):Linear(in_features=4096, out_features=1000, bias=True) ) |
這是 torchvision 里為 AlexNet 神經網絡所預先定義的圖像分類功能的結構,其中 classifier[6].out_features 是模型最終的輸出數量,也就是分類數量。
因為 AlexNet 這個“深度神經網絡”的鼻祖,是在 2012 年 ILSVRC 競賽中以 1000 分類的 ImageNet 數據集作為測試標,一舉拔得頭籌而開創“深度學習”新時代,這個 1000 分類的 AlexNet 圖像分類模型便成為這個領域的經典之作,因此在標準的 AlexNet 模型中就保留“1000”這個數字作為基準。
在這個避障應用中只使用“free”與“blockerd”兩個分類,因此需將 classifier[6] 的輸出類別數量調整為 2。請在代碼下方加入“print(model.classifier[6])”指令,打印出修改后的內容,會看到“out_features”的值已經變成 2。
注意:每種神經網絡的處理方式是不同的,必須根據PyTorch的定義進行調整。
接下去三行代碼就是將模型文件加載進來,然后存到 CUDA 設備去,相對直觀:
model.load_state_dict(torch.load('best_model.pth')) device = torch.device('cuda') model = model.to(device) |
2. 圖像格式轉換與正規化處理:
這幾乎是所有視覺類深度學習應用中不可或缺的步驟,比較繁瑣的部分是不同神經網絡存在細節上的差異,不過總的來說都脫離不了以下部分:
(1) 顏色空間轉換:所有神經網絡都有自己定義的顏色空間格式,這里的 AlexNet 接受 RGB 數據,而 CSI 攝像頭的格式為 BGR,這樣就必須進行格式轉換。這部分的處理幾乎都使用 OpenCV、numpy、PIL 這些強大的圖像處理庫就可以,下面這行代碼就是執行這個功能。
x = cv2.cvtColor(x, cv2.COLOR_BGR2RGB) |
(2) 張量順序轉換:將 HWC 順序轉換成 CHW 順序,下面指令就是執行順序調整:
x = x.transpose((2, 0, 1)) |
(3) 正規化(normalization)處理:透過減去數據對應維度的統計平均值,消除公共部分以凸顯個體之間的差異和特征的一種平穩的分布計算。下面使用到的 [0.485, 0.456, 0.406]、[0.229, 0.224, 0.225] 兩組數據,是業界經過公認的經驗數據。
mean = 255.0 * np.array([0.485, 0.456, 0.406]) stdev = 255.0 * np.array([0.229, 0.224, 0.225]) |
以上就是針對讀入圖像與模型之間對應的一些轉換與計算的過程。
3. 創建控制元件并與攝像頭進行關聯:
這里使用的 traitlets、IPython.display、ipwidgets.wiegets 與 jetbot 的 Camera 庫,在前面的文章里都說明過,比較重要的代碼如下:
(1) blocked_slider:用于顯示所獲取圖像是“blocked”類的幾率
blocked_slider = widgets.FloatSlider(description='blocked', min=0.0, max=1.0, orientation='vertical') |
(2)speed_slider:用于調整 Jetbot 小車行進速度比
speed_slider = widgets.FloatSlider(description='speed', min=0.0, max=0.5, value=0.0, step=0.01, orientation='horizontal') |
(3)camera_link:將攝像頭獲取圖像與 image 變量進行關聯,并執行格式轉換,才能在下方“display”指令之后,將攝像頭圖像動態地在 Jupyter 里顯示。
camera_link = traitlets.dlink((camera, 'value'), (image, 'value'), transform=bgr8_to_jpeg) |
執行這個階段代碼之后,下面應該會出現如下圖左方的顯示框,試著在鏡頭前晃動手,看看畫面內容是否產生變化?顯示框右邊與下方分別出現“blocked”與“speed”兩個滑塊,就是前面代碼所建立的小工具。
由于后面會使用到這個 “speed” 滑塊對 Jetbot 進行速度調整,并且我們也希望能實時觀察到攝像頭的畫面,因此建議用鼠標在畫面上點擊右鍵,點選上圖右方 “Create New View for Output” 去創建另一個獨立輸出框,然后進行位置調整如下圖,這樣就方便后續的操作。
4. 將控制元件與網絡模型、機電控制進行結合:
這是整個應用中最核心的整合與計算過程,雖然代碼量不多,但信息量卻非常大,現在將這部分切割成幾個小塊來進行說明。
(1) 獲取圖像進行識別:
def update(change): x = change['new'] x= preprocess(x) y= model(x) 。。。 update({'new': camera.value}) |
這里首先定義 “update(change)”,在最下方用”update()”進行調用。
在“update({'new': camera.value})” 里使用{key:value}對的方式,將 camera.value 圖像內容透過 change['new'] 傳給 x 變量;
將 x 變量傳入進行前面定義的 preprocess() 格式轉換與正規化處理;
y 是 model(x) 推理計算所得出來“blocked”與“free”兩個類的個別置信度,例如為[-0.9425, 0.4077];
(2) 將置信度轉換成[0,1]范圍的值:
y= F.softmax(y, dim=1) prob_blocked= float(y.flatten()[0]) blocked_slider.value= prob_blocked |
這里調用 torch.nn.functional.softmax 函數,將所有類置信度的總和調整為1,如此一來前面的[-0.9425, 0.4077]就轉換成[0.2058, 0.7942];
作為行進的決策判斷,我們只要在兩個類別中挑選任何一個都可以,這里的代碼以“blocked”類幾率值作為判斷的依據,因此取 float(y.flatten()[0]) 的值,如果改用“free”的幾率,就取 float(y.flatten()[1]) 的值。
然后將這個值同時也傳給 blocked_slider.value,現在看看前面輸出的 blocked 滑塊的值是否跟著產生變化!
(3)用 prob_blocked 值控制 Jetbot 行進:
ifprob_blocked < 0.5: robot.forward(speed_slider.value) else: robot.left(speed_slider.value) |
這里設定以 0.5 的幾率值為上限,當 prob_blocked < 0.5 時就前進,否則就原地左轉,當然您也可以改成往右轉。
Jetbot 的行進速度由“speed_slider.value”變量所控制,這個數值得透過前面輸出畫面的 “speed” 滑塊去調整速度,最高值可以到 0.5,這是前面創建滑塊時就定義的。
執行到這里的時候,正常狀況應該如下:
攝像頭傳回的畫面是實時更新;
“blocked”滑塊固定在某個值;
現在調整“speed”滑塊的值并不會讓電機開始轉動。
現在可以將 Jetbot 小車放到您安排的執行場地上,在執行下一個步驟之前,建議透過“speed”滑塊將速度控制在 0.25 以下,避免啟動后造成 Jetbot 小車爆沖。
5. 啟動攝像頭的動態關聯:
這里其實就只有下面這一道指令:
camera.observe(update, names='value') |
這是由 jetbot 所提供的函數,將 camera.value 與前面定義的 update(change) 進行動態連接上,現在 Jetbot 小車就應該開始行動了,攝像頭里的畫面也在不停更新,右方“blocked”滑塊的值也在不斷跳動(更新),現在試著調整“speed”滑塊,是不是就能改變行進的速度了!
好了,現在就可以看看您 Jetbot 小車的避障功能執行的如何?如果想停止工作的話,就繼續往下執行暫停的指令就可以。
最后需要說明的,假如您的避障功能執行的不是太好,例如無法順利識別一些障礙物或坑洞的話,通常是因為您的測試場所或者使用的攝像頭規格(廣角),與原廠提供的模型數據有比較大的差異,甚至場地明暗度也會有影響,如果測試效果不如預期的話,就得自己重頭收集數據并重新訓練模型,這才是解決問題的根本之道。
原文標題:NVIDIA Jetson Nano 2GB 系列文章(49):智能避撞之現場演示
文章出處:【微信公眾號:NVIDIA英偉達企業解決方案】歡迎添加關注!文章轉載請注明出處。
審核編輯:湯梓紅
-
NVIDIA
+關注
關注
14文章
5021瀏覽量
103257 -
鏡頭
+關注
關注
2文章
506瀏覽量
25669 -
智能識別
+關注
關注
0文章
202瀏覽量
18134
原文標題:NVIDIA Jetson Nano 2GB 系列文章(49):智能避撞之現場演示
文章出處:【微信號:NVIDIA-Enterprise,微信公眾號:NVIDIA英偉達企業解決方案】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論