PaddleX還能給遊戲「開掛」?『跳一跳』安排上

2021-02-20 飛槳PaddlePaddle
【飛槳開發者說】作者:工地專業搬磚工。希望有生之年不要被機器搬磚狗取代。PaddleX是百度飛槳推出的深度學習全流程開發工具,本文以微信小遊戲跳一跳為例,體驗了PaddleX從數據準備到模型部署的全流程。
本次用到的模型是PaddleX提供的目標檢測模型YOLOv3。通過此模型檢測跳一跳遊戲界面中的小人和跳臺,然後估算出小人成功落入跳臺所需要的時間,把模型部署到手機模擬器上,即可模擬玩家按屏完成跳一跳,最終實現了自動成功跳躍。本項目所涉及的代碼和文件均放在百度一站式在線開發平臺AI Studio上,連結如下:https://aistudio.baidu.com/aistudio/projectdetail/526100
在跳一跳遊戲中,玩家通過按下手機屏幕來控制小人跳起,若準確落入下一個跳臺則積分,否則遊戲失敗。主要有這幾個界面:
玩家需要根據小人與下一個跳臺之間的距離,估算出按下屏幕的時長,按下時間越長,小人彈跳地越遠。個人直覺估計小人彈跳的距離與按下時長是一種拋物線的關係。所以首先要解決的是如何得到小人與下一個跳臺之間的距離,這就要用到PaddleX中的明星產品YOLOv3了。在使用PaddleX之前,需要製作符合格式的數據集,可以使用LableImg標註工具來製作目標檢測數據集。為了讓模型收斂的更好,標註的圖片儘可能多一些,本項目中的圖片總數不低於150張。根據遊戲流程,按照需要標註三個遊戲界面的按鈕(例如小人、跳臺、積分數)。

!pip install paddlex -i https://mirror.baidu.com/pypi/simple

設置使用0號GPU卡(如無GPU,執行以下代碼後會使用CPU訓練模型)

import matplotlib
matplotlib.use('Agg') 
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
import paddlex as pdx

#把製作好的數據集解壓到相應子目錄
!rm data/game -r
# !cat game.zip.* > game.zip
!unzip game.zip
!mv game data/
# !rm game.zip

import os
import zipfile
import xml.etree.ElementTree as ET
import re
import numpy as np

lables = os.listdir("data/game/lable")
print("lables:",len(lables))
trains = os.listdir("data/game/train1")
print("trains:",len(trains))
_lable = []
ratio = 0.8
offset = int(len(lables)*ratio)
np.random.shuffle(lables)
path = "data/game/"
with open(path + "train_list.txt","w") as f:
    for lable in lables[:offset]:
        if lable.split(".")[0] + ".jpg" in trains:
            f.writelines("train1/" + lable.split(".")[0] + ".jpg" + " " + "lable/" + lable +"\n")
            tree = ET.parse(path + "lable/" + lable)
            root = tree.getroot()
            objs = root.findall("object")
            for obj in objs:
                if obj.find("name").text not in _lable:
                    _lable.append(obj.find("name").text)
            tree.find("path").text = path + "lable/" + lable
            tree.write(path + "lable/" + lable)

with open(path + "test_list.txt","w") as f:
    for lable in lables[offset:]:
        if lable.split(".")[0] + ".jpg" in trains:
            f.writelines("train1/" + lable.split(".")[0] + ".jpg" + " " + "lable/" + lable +"\n")
            tree = ET.parse(path + "lable/" + lable)
            root = tree.getroot()
            objs = root.findall("object")
            for obj in objs:
                tree.find("path").text = path + "lable/" + lable
                tree.write(path + "lable/" + lable)
                if obj.find("name").text not in _lable:
                    _lable.append(obj.find("name").text)

with open(path + "val_list.txt","w") as f:
    for lable in lables[offset:]:
        if lable.split(".")[0] + ".jpg" in trains:
            f.writelines("train1/" + lable.split(".")[0] + ".jpg" + " " + "lable/" + lable +"\n")

print(_lable)
with open(path + "lable.txt","w") as f:
    for lable in _lable:
        f.writelines(lable+"\n")

from paddlex.det import transforms
train_transforms = transforms.Compose([
    transforms.MixupImage(mixup_epoch=250),
    transforms.RandomDistort(),
    transforms.RandomExpand(),
    transforms.RandomCrop(),
    transforms.Resize(target_size=608, interp='RANDOM'),
    transforms.RandomHorizontalFlip(),
    transforms.Normalize(),
])

eval_transforms = transforms.Compose([
    transforms.Resize(target_size=608, interp='CUBIC'),
    transforms.Normalize(),
])

train_dataset = pdx.datasets.VOCDetection(
    data_dir='data/game',
    file_list='data/game/train_list.txt',
    label_list='data/game/lable.txt',
    transforms=train_transforms,
    shuffle=True)
eval_dataset = pdx.datasets.VOCDetection(
    data_dir='data/game',
    file_list='data/game/val_list.txt',
    label_list='data/game/lable.txt',
    transforms=eval_transforms)

初始化模型,並進行訓練。由於backbone選擇的是DarkNet53,且batch_size設置值較大,CPU下跑不動,所以一定要用GPU

num_classes = len(train_dataset.labels)
model = pdx.det.YOLOv3(num_classes=num_classes, backbone='DarkNet53')
model.train(
    num_epochs=300,
    train_dataset=train_dataset,
    train_batch_size=12,
    eval_dataset=eval_dataset,
    learning_rate=0.000125,
    lr_decay_epochs=[210, 240],
    save_interval_epochs=20,
    save_dir='output/yolov3_darknet53',
    use_vdl=True)

# 訓練完了,就可以用來檢測小人與下一個跳臺分別在什麼地方了。

# 設置使用0號GPU卡(如無GPU,執行此代碼後會使用CPU訓練模型)

import matplotlib
matplotlib.use('Agg') 
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
import paddlex as pdx

# 加載模型文件夾路徑,這裡修改為訓練時模型保存的路徑:

base_path = "output/best_model"
model = pdx.load_model(base_path)

獲取屏幕畫面,可以是攝像頭,也可以是安桌模擬器。這裡講一下如何獲取手機屏幕:首先,安裝安卓模擬器,或者adb,推薦大家安裝360手機助手,這樣就可以在電腦上獲取手機屏幕了。

import win32gui
import win32api
from PIL import ImageGrab
import cv2
import time
import numpy as np
classname = None
titlename = "360手機演示"
#獲取句柄
hwnd = win32gui.FindWindow(classname, titlename)
print("獲取窗口:",hwnd)
#獲取窗口左上角和右下角坐標
left, top, right, bottom = win32gui.GetWindowRect(hwnd)
print(left, top, right, bottom)

def getScreen():
    n = time.time()
    left, top, right, bottom = win32gui.GetWindowRect(hwnd)
    img = ImageGrab.grab(bbox=(left, top, right, bottom))
    img = np.array(img.getdata(), np.uint8).reshape(img.size[1], img.size[0], 3)
    #img = img[...,::-1]
    cv2.imwrite("response.jpg", img)
getScreen()

想辦法把獲取的屏幕畫面傳遞給模型,在畫面中檢測出小人和跳臺的位置。

filename = "response.jpg"
result = model.predict("temp/" +filename)
pdx.det.visualize("temp/" +filename, result, threshold=0.5, save_dir='./output/yolov3_mobilenetv1')
#result的格式是
# [{'category_id': 1, 
# 'bbox': [164.57411193847656, 248.15550231933594, 34.76348876953125, 16.626205444335938], 
# 'score': 0.972798228263855, 
# 'category': 'next'}]

獲取屏幕時,360演示窗口要在桌面上保持為可見狀態,ImageGrab.grab獲取的就是桌面截屏。在保存截取的屏幕後,用訓練好的模型對截屏進行目標檢測。此處需注意,訓練集是由攝像頭獲取的,攝像頭獲取時設置的是橫屏,而模擬器截屏設置的是豎屏,所以需要把模擬器截屏轉換成橫屏。驚喜點:發現模型意外的可靠,本來還以為橫屏和豎屏兩種模式下的數據格式差別大,會導致識別能力下降,結果完全沒有影響,轉換後直接預測就可以了,這說明模型泛化能力很強。

#獲取小人腳底坐標與下一個跳臺中心的坐標,計算距離d
#計算距離d和時間t的之間函數關係,
#假定小人的路徑是拋物線,與發射角和時間都相關
#當按下時間為0時,發射方向為垂直向上的,此時發射角為0度
#按下時間越長,發射角越接近0度,所以構造以下函數
#發射角aa = Pi/2 - Pi/2*(a/(c*t + 1.0) + (1-a))
#發射起始速度V與按下時間成正比,V = z*t
#Vx = V*cos(aa),Vy= V*sin(aa)
#空中飛行時間為T = 2*Vy/g
#跳躍距離為Vx*T = V*cos(aa)* 2*V*sin(aa)/g= z^2 * t^2 *sin(aa)*cos(aa) /g =b *t^2 * sin(2*aa)
#
#這部分其實應該用深度學習來找這個函數,這個以後再弄
import math
def d2t(a,b,c,d):
    #返回按下的時間長度,感覺是單調函數,所以二分法試一下
    t0,t1 = 0.0,500.0
    for _ in range(100):
        t = t1/2.0 + t0/2.0
        aa = (3.1415926*(a/(c*t+1.0)+1-a) - 3.1415926/2)
        d0 = b * t**2 *math.sin(aa)
        if (d - d0)**2 < 0.000001:
            return t
        if d > d0:
            t0 = t1/2.0 + t0/2.0
        else:
            t1 = t1/2.0 + t0/2.0
    return t
#手工調試這組參數
a,b,c = 0.25, 420, 3.0
#最後就是在屏幕上對遊戲進行操作:
#需要用到autopy庫
!pip install autopy
import autopy
def toggle(x,y,t):
#在x,y位置按下t時長,模擬在手機上的按下操作
autopy.mouse.move(x ,y)
autopy.mouse.toggle(None,True)
time.sleep(t)
autopy.mouse.toggle(None,False)


因為跳一跳遊戲本身實在太慢了,優化整個遊戲流程比較耗時,目前最高積分僅100多分。後續還會持續優化,感興趣的同學可以持續關注本項目。參考連結本項目代碼和文件均放在百度一站式在線開發平臺AI Studio上,連結如下:https://aistudio.baidu.com/aistudio/projectdetail/526100如果您想詳細了解更多PaddleX的相關內容,請參閱以下文檔。https://github.com/PaddlePaddle/PaddleXhttps://gitee.com/paddlepaddle/PaddleX如在使用過程中有問題,可加入飛槳PaddleX官方QQ群交流:1045148026如果您想詳細了解更多飛槳的相關內容,請參見以下文檔。https://www.paddlepaddle.org.cnhttps://github.com/PaddlePaddle/Paddlehttps://gitee.com/paddlepaddle/Paddle

相關焦點

  • Paddle.js & PaddleClas 實戰 ——『尋物大作戰』AI 小遊戲
    『尋物大作戰』正是一款基於 AI 能力打造的趣味性小遊戲,目的就是讓玩家通過遊戲的方式感受 AI 的魅力。雖然受限於數據,它目前還是一款初級階段的遊戲,不過麻雀雖小,五臟俱全,整體開發過程囊括了 數據處理、模型設計、模型訓練、上線部署 ,四位一體的全部流程!
  • 100 行代碼實現『跳一跳』輔助
    分享一下今天下午用python寫的"跳一跳"小遊戲的輔助程序。之前是準備用樹莓派操控一個"機械手指"來代替人的觸摸操作,但該方案還在醞釀中,實現了再分享。接下來要分享的是用"純軟體"的方法來玩"跳一跳"。
  • 「跳一跳」還能這麼玩?
    近日,微信版本升級,小程序增加新類目「小遊戲」,已上線的「跳一跳」,在朋友圈還是引起不小的圍觀的。
  • 「IT」人應如何面對微信『跳一跳』高分挑戰
    社交酬賞和自我酬賞才是上癮的根本在社交網絡上,為什麼我們總是渴望被點讚、被評論?實際上,這些點讚、評論都屬於社交酬賞,是每個人渴望被接納、被認同的物化表現。在微信「跳一跳」這個遊戲中,除了遊戲常見的好友排行榜,它還新增了超越提示——當你越過一個跳躍臺時,你會看到你正在超過某個好友。
  • 網紅遊戲【跳一跳】隱藏得分攻略!
    沒想到2018年第一篇文章居然是跳一跳!
  • 跳一跳遊戲
    跳一跳是近期騰訊推出的一款微信小遊戲程序,比較簡單便捷有誘惑力,越來越受到網友們追捧,本著學習了解的態度我試了一下,談一下感受。
  • 盤古團隊證實:微信小遊戲「跳一跳」改分漏洞仍在,這是最新攻略
    1 月 2 日下午,著名安全團隊「盤古」的安全專家向宅客頻道證實,微信小遊戲「跳一跳」改分漏洞仍在,此前流傳的「微信已補漏洞」是指已經修補了微信小遊戲「跳一跳」的原始碼下載漏洞。這意味著,改分依然可行。到底怎麼回事?宅客頻道從盤古旗下的 Janus 威脅情報平臺了解到了詳情。
  • 跳一跳怎麼自動刷分 跳一跳安卓/ios刷分作弊器下載安裝教程
    微信跳一跳怎麼自動刷分微信跳一跳怎麼自動跳躍?首先小編要說的就是現在微信正在大力地打擊外掛,一旦被官方發現了開掛之後,不僅會被清空分數,要是情節嚴重的,甚至在以後騰訊小遊戲中,都無法取得成績。
  • 微信跳一跳小遊戲有毒
    微信派還爆出了些技巧:跳在盒子中間,會得 2 分;連續調在盒子中間,會在上次的基礎上累加 2 分。跳在一些特殊樣式的盒子上停留一段時間,比如徐記士多、魔方、黑膠唱片機、井蓋等,會獲得 5 - 30 不等的額外加分。得分的時候還有配樂
  • Python教程——製作「微信跳一跳」輔助工具
    跳一跳是一個最近出的一個比較熱然後估計馬上就要涼了的微信小遊戲,一出來就有各路大神直接實現了各種掛。今天逛了逛b站,沒想到發現了一個超簡單的版本,雖然還是要手動操作,但勝在代碼簡單,本人花上10多分鐘也能輕鬆理解並寫出來,一般只要你有毅力,就能一直刷下去。
  • 新版本的絕地求生還能「超級跳」?巧用跳窗技巧,在細節上戰勝敵人
    甚至很多人不知道還能跳窗那麼跳窗有什麼實用技巧呢?來看看WJ的視頻介紹翻譯源:虎撲電競首先要說明的是,超級跳這個動作確實不好實現,不僅需要掌握一定的技巧而且還需要大量的練習除此之外,現在的超級跳僅僅只適用於翻越窗戶,並不能像以前那樣能夠讓你攀爬到更高的地方
  • 小程序遊戲 跳一跳
    If you haven't heard about Tiao yi tiao, you are so out:如果你還沒有聽說過跳一跳,那你就過時啦。Mini program: 小程序Mini games:小遊戲Tiao yi tiao has just exploded on Wechat:跳一跳刷爆朋友圈What are WeChat mini-games
  • 微信推出「跳一跳」新模式:多人參與接龍
    自從微信小遊戲「跳一跳」問世以來,就獲得了很高的遊戲熱度。社交也是這款小遊戲的重要屬性之一,你的微信裡有多少好友每周仍在孜孜不倦地刷新著榜單?
  • 新手Python實現微信跳一跳自動運行,再忍不住了
    最近我相信很多人都在玩微信的跳一跳小遊戲,前面幾天,很多人在朋友圈曬「跳一跳」人工智慧開掛教程:如何讓電腦自己玩微信跳一跳。
  • 有了它,我「跳一跳」已經8666了,你呢?
    最近,官舍君受朋友圈「洗禮」迷上了一款小遊戲—— 跳一跳。這款遊戲是繼 18 歲、支付寶帳單和網易雲音樂年度回顧之後,又一刷屏黑馬。要問近一年最火的遊戲是啥,有 2 億朋友會說王者農藥,2.7 千萬人篤定「吃雞」,但僅僅上線 3 天玩家就破四億的跳一跳笑而不語。曾經多少人沉浸在王者農藥中無法自拔,如今又陷入跳一跳的怪圈裡無法逃脫。
  • 微信跳一跳遊戲裡,隱藏著哪些小秘密
    跳一跳為什麼能刷爆朋友圈呢
  • 微信跳一跳輔助程序
    天寫一個微信跳一跳輔助程序這個項目我是跟著一個視頻課程做的雖然我測試的時候,最後得到的分數被判定為作弊
  • 微信跳一跳分數怎麼作弊?黑松鼠跳一跳輔助外掛使用方法說明
    微信最近出現了一款叫跳一跳的小遊戲,非常好玩的哦,只不過想要拿到高分還是很有難度的,黑松鼠跳一跳可以讓你輕鬆拿到高分,那麼要怎麼使用這個黑松鼠跳一跳呢,和小編一起來看看吧~  黑松鼠跳一跳怎麼用 使用方法介紹  1、首先用戶需要打開黑松鼠跳一跳輔助,設置好遊戲參數,微調為-35,如果跳不準的話,可在-100到100之間調節;  2、
  • 我用Python玩小遊戲「跳一跳」,瞬間稱霸了朋友圈!
    以上是針對普通用戶,但對咱們程序猿來說用這套太 Low 了,接下來要說的是如何從技術層面去實現高分:在 Github 上面已經有人用 Python 來玩跳一跳這個遊戲了,想多少分就有多少分。界面轉至微信跳一跳遊戲,點擊開始遊戲。運行 python wechat_junp_auto.py,如果手機界面顯示 USB 授權,請點擊確認。很有趣!簡單點說就是:用電腦幫你玩微信跳一跳,全自動,不用手動。效果:
  • Chrome暗藏的恐龍跳一跳,已經被AI輕鬆掌握了
    開!淡定。作為一個Google Chrome瀏覽器的用戶,當你看到上面那個頁面時,不要沮喪。換個角度一想,牆內還能有更多的Play時間哦~你有沒有注意到畫面裡那個小恐龍?當你遇到打不開網頁的時候,只需要再點擊一下這個頁面(手機),或者按下空格(電腦),隨著小恐龍輕輕一跳——一個新世界開啟了。