从 保龄球得分计算方法 浅析 深度学习
起因
周六被小伙伴拖去游泳,美名其曰:鍛煉身體。其實某人就是去泡澡的,哈哈。說正題吧,游完泳在體育場里閑逛,里面很大,轉著轉著看到一個保齡球館,懷著對未知事物的好奇,決定和某人去嘗試一下。我和S同學一人買了一局,按照說明,每一局分為10次,每一次有兩次機會扔球。最后的比分就不說了,反正玩的很爽,最后也在邊上一個厲害的大叔指點下,學會了基本的扔球姿勢。
看到這你以為這是一篇敘事文?那就錯了,起因是從這里開始的,我們的次數(shù)用完后,留在里面打臺球(這里也有臺球桌),看到不斷有穿著隊服一類東西的人進來,應該是來比賽的,同時又看到了賽道上面的牌子,有一個寫著:289分。那分數(shù)是怎么計算的呢,懷著好奇心搜索起保齡球的積分規(guī)則來。在了解之后,我就在想一個問題:__如果是讓我開發(fā)一個保齡球的游戲,那么計分程序要怎么寫呢?__今天我們就從這里說起。。。
規(guī)則
先簡述一下保齡球的規(guī)則,這里引用百度知道的別人的回答,每一局比賽有10格,每格有兩次擊球機會,我們這里關注它的得分情況,這里分為兩種情況:
-
1-9格擊球
每一格有3種可能: - 第一次擊球全部擊倒:這種情況得分就是擊倒的瓶數(shù)(10)+后兩次擊球擊倒的總數(shù)
- 兩次擊球全部擊倒:這樣得分為擊倒的瓶數(shù)(10)+后一次擊球擊倒的總數(shù)
- 兩次擊球沒有全部擊倒:得分為兩次擊倒總瓶數(shù)
-
第10格擊球
這一格有兩種可能: - 前兩次未能將瓶全部擊倒:得分為擊倒總瓶數(shù)+第9格的得分
- 前兩次將瓶全部擊倒,獲得一次追加機會:得分為兩次擊倒總數(shù)(10)+追加時擊倒的總瓶數(shù)+第9格分數(shù)
程序
規(guī)則也了解了,下面就到了寫代碼的時候了,為了方便,這里選擇Python,版本為3.6
考慮到直觀性,這里沒有用交互式的程序,而是直接將擊中情況抽象成矩陣(數(shù)組),算出最后總分。
輸入的數(shù)據(jù)大概是這個樣子:
[[0, 3], [2, 6], [3, 6], [0, 3], [3, 0], [9, 1], [6, 3], [6, 2], [4, 6], [4, 2]]
10x2的數(shù)組,代表前10格每格的擊倒瓶數(shù),如果一格內(nèi)不需要第二次擊球,也算作0。這里先寫一個簡單的數(shù)據(jù)生成函數(shù)。
import random def top_10():for i in range(10):for j in range(2):if j == 0 :a[i][j] = random.randint(0,10)else :a[i][j] = random.randint(0,10-a[i][j-1]) return a同時,我們注意到了,這個生成函數(shù)還少了點什么,沒錯,就是第十格的追加擊球數(shù)。所以,這里再定義一個追加球生成函數(shù)
這里為了后面計算方便,也定義為[[x,y]]這種格式
原始數(shù)據(jù)的生成我們完成了,接下來要定義計算函數(shù)了,計算總分數(shù)
def calc_total(top):sums = 0index = 0for x in top:if x[0] == 10:sums += 10if top[index+1][0] == 10:sums += 10 + top[index+2][0]else:sums += sum(top[index+1])elif sum(x) == 10:sums += 10 + top[index+1][0]else:sums += sum(x)index+=1if index == 9:breaksums += sum(top[8]+top[9]+top[10])return sums代碼寫的不是很好看,大家請諒解啊,不過整個完整的功能是做完了,我們可以寫個方法測試下
tmp1 = top_10() add1 = addto_num(tmp1) c = calc_total(tmp1+add1) print(c) 78神經(jīng)網(wǎng)絡版
想必大家也了解,當下最火的就是AI,而作為實現(xiàn)AI的其中一種手段,深度學習必不可少。最近也在學習這方面的知識(ps:給沐神瘋狂打call,強烈推薦他的深度學習課程,鏈接大家自己去搜,就不做廣告了),雖然說自己連入門都算不上,但還是想實現(xiàn)一下自己版本的。
于是就有了這個:
深度學習版本的保齡球得分計算方法這里我們用到了mxnet這個深度學習框架,最基礎的部分的兩個庫ndarray和autograd
首先,我們是基于線性回歸這個最簡單也是最基礎的神經(jīng)網(wǎng)絡實現(xiàn)的,模型看起來就像這樣
$$\boldsymbol{\hat{y}} = X \boldsymbol{w} + b$$
同時定義它的損失函數(shù),也就是計算預測值和實際值的差距,這里用兩個的平方誤差來計算,模型是這樣
$$\sum_{i=1}^n (\hat{y}_i-y_i)^2.$$
首先,我們要__創(chuàng)建數(shù)據(jù)集__
因為我們之前定義的是Python的list,所以在這里要轉換成mxnet的內(nèi)置數(shù)組ndarray
不過在此之前我們要先改進下我們的生成函數(shù),之前是由兩個函數(shù)組成,現(xiàn)在為了方便,我們合成一個。同時,計算方法改造成ndarray版本的。
from mxnet import ndarray as nd from mxnet import autograddef init_data():for i in range(0,10):for j in range(0,2):if j == 0 :a[i][j] = random.randint(0, 10)else :a[i][j] = random.randint(0,10-a[i][j-1]) return a+[[random.randint(0,10),0]] if sum(a[9]) == 10 else a+[[0,0]] def calc_total_nd(top):sums = 0index = 0for x in top:if x[0].asscalar() == 10:sums += 10if top[index+1][0].asscalar() == 10:sums += 10 + top[index+2][0].asscalar()else:sums += nd.sum(top[index+1]).asscalar()elif nd.sum(x).asscalar() == 10:sums += 10 + top[index+1][0].asscalar()else:sums += nd.sum(x).asscalar()index+=1if index == 9:breaksums += nd.sum(top[8]+top[9]+top[10]).asscalar()return sums num_inputs = 22 num_examples = 1000 X = nd.zeros(shape=(num_examples,11,2)) for i in X:i[:] = nd.array(init_data()) y = nd.array([calc_total_nd(i) for i in X])然后是定義 數(shù)據(jù)讀取方法
目的是在后面訓練時隨機遍歷我們的數(shù)據(jù)集,這里參考了沐神教程里的方法。
嘗試著讀取一個
for data, label in data_iter():print(data, label)break [[[ 2. 0.][ 7. 0.][ 1. 7.][ 2. 2.][ 6. 2.][ 0. 5.][ 0. 5.][ 7. 1.][ 6. 4.][ 3. 0.][ 0. 0.]][[ 6. 3.][ 4. 2.][ 2. 4.][ 8. 2.][ 4. 6.][ 6. 3.][ 2. 6.][ 6. 3.][ 2. 3.][ 8. 2.][ 7. 0.]][[ 10. 0.][ 8. 0.][ 2. 2.][ 8. 2.][ 0. 3.][ 10. 0.][ 10. 0.][ 6. 3.][ 10. 0.][ 1. 7.][ 0. 0.]][[ 5. 1.][ 6. 2.][ 10. 0.][ 3. 6.][ 8. 2.][ 10. 0.][ 4. 4.][ 2. 4.][ 2. 0.][ 7. 3.][ 10. 0.]][[ 6. 2.][ 8. 0.][ 0. 0.][ 9. 0.][ 6. 4.][ 5. 3.][ 5. 0.][ 1. 6.][ 0. 1.][ 4. 4.][ 0. 0.]][[ 5. 5.][ 6. 3.][ 0. 7.][ 2. 8.][ 10. 0.][ 4. 0.][ 1. 5.][ 1. 2.][ 1. 2.][ 0. 2.][ 0. 0.]][[ 10. 0.][ 0. 3.][ 3. 7.][ 3. 1.][ 8. 1.][ 4. 2.][ 8. 1.][ 6. 4.][ 10. 0.][ 5. 0.][ 0. 0.]][[ 8. 2.][ 10. 0.][ 6. 0.][ 10. 0.][ 1. 4.][ 2. 6.][ 9. 0.][ 5. 5.][ 7. 1.][ 5. 1.][ 0. 0.]][[ 9. 1.][ 7. 1.][ 6. 3.][ 0. 5.][ 7. 3.][ 7. 1.][ 6. 3.][ 3. 1.][ 3. 3.][ 10. 0.][ 6. 0.]][[ 0. 10.][ 4. 3.][ 2. 6.][ 2. 6.][ 4. 1.][ 8. 1.][ 5. 4.][ 3. 6.][ 6. 4.][ 4. 2.][ 0. 0.]]] <NDArray 10x11x2 @cpu(0)> [ 73. 104. 133. 118. 70. 87. 107. 118. 105. 99.] <NDArray 10 @cpu(0)>數(shù)據(jù)準備好了,現(xiàn)在要定義一個__初始化的模型參數(shù)__
這里隨機生成一個就好了,后面我們會通過訓練,慢慢學習完善這個參數(shù),這也是深度學習的目的
然后附上梯度,也就是讓后面autograde可以對這個函數(shù)求導
for param in params:param.attach_grad()定義模型和損失函數(shù)
這里要注意的是:我們的維度不是1,所以要把數(shù)組的維度reshape一下變成一維數(shù)組
def net(X):return nd.dot(X.reshape((-1,num_inputs)), w) + b def square_loss(yhat, y):return (yhat - y.reshape(yhat.shape)) ** 2然后是優(yōu)化方法,也就是學習方法,讓函數(shù)去學習參數(shù)
def SGD(params, lr):for param in params:param[:] = param - lr * param.grad最后就是__訓練__了
epochs = 5 learning_rate = .0001 for e in range(epochs):total_loss = 0for data, label in data_iter():with autograd.record():output = net(data)loss = square_loss(output, label)loss.backward()SGD(params, learning_rate/batch_size)total_loss += nd.sum(loss).asscalar()print("Epoch %d, average loss: %f" % (e, total_loss/num_examples)) Epoch 0, average loss: 82.049488 Epoch 1, average loss: 82.009441 Epoch 2, average loss: 81.810044 Epoch 3, average loss: 82.243776 Epoch 4, average loss: 82.023799最后來驗證下我們的預測結果
for data, label in data_iter():print("實際分數(shù)")print(label)print("預測分數(shù)")print(net(data))break 實際分數(shù)[ 108. 77. 102. 115. 85. 110. 76. 124. 78. 87.] <NDArray 10 @cpu(0)> 預測分數(shù)[ 107.43678284 86.52748871 101.92710114 116.50645447 90.5655899115.31760406 80.10424805 118.94145203 84.49520111 95.17882538] <NDArray 10 @cpu(0)>參考:
動手學深度學習
總結
以上是生活随笔為你收集整理的从 保龄球得分计算方法 浅析 深度学习的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大班教案《风儿找妈妈》反思
- 下一篇: 云南四大特产