资讯专栏INFORMATION COLUMN

从 保龄球得分计算方法 浅析 深度学习

wangxinarhat / 3298人阅读

摘要:最近也在学习这方面的知识给沐神疯狂打,强烈推荐他的深度学习课程,链接大家自己去搜,就不做广告了,虽然说自己连入门都算不上,但还是想实现一下自己版本的。同时,计算方法改造成版本的。

起因

周六被小伙伴拖去游泳,美名其曰:锻炼身体。其实某人就是去泡澡的,哈哈。说正题吧,游完泳在体育场里闲逛,里面很大,转着转着看到一个保龄球馆,怀着对未知事物的好奇,决定和某人去尝试一下。我和S同学一人买了一局,按照说明,每一局分为10次,每一次有两次机会扔球。最后的比分就不说了,反正玩的很爽,最后也在边上一个厉害的大叔指点下,学会了基本的扔球姿势。

看到这你以为这是一篇叙事文?那就错了,起因是从这里开始的,我们的次数用完后,留在里面打台球(这里也有台球桌),看到不断有穿着队服一类东西的人进来,应该是来比赛的,同时又看到了赛道上面的牌子,有一个写着:289分。那分数是怎么计算的呢,怀着好奇心搜索起保龄球的积分规则来。在了解之后,我就在想一个问题:__如果是让我开发一个保龄球的游戏,那么计分程序要怎么写呢?__今天我们就从这里说起。。。

规则

先简述一下保龄球的规则,这里引用百度知道的别人的回答,每一局比赛有10格,每格有两次击球机会,我们这里关注它的得分情况,这里分为两种情况:

1-9格击球
每一格有3种可能:

第一次击球全部击倒:这种情况得分就是击倒的瓶数(10)+后两次击球击倒的总数

两次击球全部击倒:这样得分为击倒的瓶数(10)+后一次击球击倒的总数

两次击球没有全部击倒:得分为两次击倒总瓶数

第10格击球
这一格有两种可能:

前两次未能将瓶全部击倒:得分为击倒总瓶数+第9格的得分

前两次将瓶全部击倒,获得一次追加机会:得分为两次击倒总数(10)+追加时击倒的总瓶数+第9格分数

程序

规则也了解了,下面就到了写代码的时候了,为了方便,这里选择Python,版本为3.6
考虑到直观性,这里没有用交互式的程序,而是直接将击中情况抽象成矩阵(数组),算出最后总分。
输入的数据大概是这个样子:

[[0, 3], [2, 6], [3, 6], [0, 3], [3, 0], [9, 1], [6, 3], [6, 2], [4, 6], [4, 2]]

10x2的数组,代表前10格每格的击倒瓶数,如果一格内不需要第二次击球,也算作0。这里先写一个简单的数据生成函数。

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

同时,我们注意到了,这个生成函数还少了点什么,没错,就是第十格的追加击球数。所以,这里再定义一个追加球生成函数
这里为了后面计算方便,也定义为[[x,y]]这种格式

def addto_num(a):
    return [[random.randint(0,10),0]] if sum(a[9]) == 10 else [[0,0]]

原始数据的生成我们完成了,接下来要定义计算函数了,计算总分数

def calc_total(top):
    sums = 0
    index = 0
    for x in top:
        if x[0] == 10:
            sums += 10
            if 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+=1
        if index == 9:
            break
    sums += sum(top[8]+top[9]+top[10])
    return sums   

代码写的不是很好看,大家请谅解啊,不过整个完整的功能是做完了,我们可以写个方法测试下

tmp1 = top_10()
add1 = addto_num(tmp1)
c = calc_total(tmp1+add1)
print(c)
78
神经网络版

想必大家也了解,当下最火的就是AI,而作为实现AI的其中一种手段,深度学习必不可少。最近也在学习这方面的知识(ps:给沐神疯狂打call,强烈推荐他的深度学习课程,链接大家自己去搜,就不做广告了),虽然说自己连入门都算不上,但还是想实现一下自己版本的。

于是就有了这个:

深度学习版本的保龄球得分计算方法

这里我们用到了mxnet这个深度学习框架,最基础的部分的两个库ndarray和autograd

首先,我们是基于线性回归这个最简单也是最基础的神经网络实现的,模型看起来就像这样
$$oldsymbol{hat{y}} = X oldsymbol{w} + b$$
同时定义它的损失函数,也就是计算预测值和实际值的差距,这里用两个的平方误差来计算,模型是这样
$$sum_{i=1}^n (hat{y}_i-y_i)^2.$$

首先,我们要__创建数据集__
因为我们之前定义的是Python的list,所以在这里要转换成mxnet的内置数组ndarray

不过在此之前我们要先改进下我们的生成函数,之前是由两个函数组成,现在为了方便,我们合成一个。同时,计算方法改造成ndarray版本的。

from mxnet import ndarray as nd
from mxnet import autograd

def 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 = 0
    index = 0
    for x in top:
        if x[0].asscalar() == 10:
            sums += 10
            if 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+=1
        if index == 9:
            break
    sums += 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])

然后是定义 数据读取方法
目的是在后面训练时随机遍历我们的数据集,这里参考了沐神教程里的方法。

import random
batch_size = 10
def data_iter():
    # 产生一个随机索引
    idx = list(range(num_examples))
    random.shuffle(idx)
    for i in range(0, num_examples, batch_size):
        j = nd.array(idx[i:min(i+batch_size,num_examples)])
        yield nd.take(X, j), nd.take(y, 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.]]]
 
[  73.  104.  133.  118.   70.   87.  107.  118.  105.   99.]

数据准备好了,现在要定义一个__初始化的模型参数__
这里随机生成一个就好了,后面我们会通过训练,慢慢学习完善这个参数,这也是深度学习的目的

w = nd.random_normal(shape=(num_inputs, ))
b = nd.random_normal(shape=(1,))
params = [w, b]
print(params)
[
[ 0.50869578 -0.16038011  0.91511744  0.84187603 -0.49177799 -1.00553632
 -1.55609238  3.13221502 -0.15748753 -0.4358989  -0.52664566 -0.49295077
 -0.17884982  1.43718672  0.43164727 -0.31814137  0.46760127 -0.16282491
  0.17287086  0.6836102   0.76158988  1.61066961]
, 
[  9.91063134e-05]
]

然后附上梯度,也就是让后面autograde可以对这个函数求导

for param in params:
    param.attach_grad()

定义模型和损失函数

这里要注意的是:我们的维度不是1,所以要把数组的维度reshape一下变成一维数组

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

然后是优化方法,也就是学习方法,让函数去学习参数

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 = 0
    for 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("实际分数")
        print(label)
        print("预测分数")
        print(net(data))
        break
实际分数

[ 108.   77.  102.  115.   85.  110.   76.  124.   78.   87.]

预测分数

[ 107.43678284   86.52748871  101.92710114  116.50645447   90.5655899
  115.31760406   80.10424805  118.94145203   84.49520111   95.17882538]

参考:
动手学深度学习

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/40842.html

相关文章

  • 浅析 Hinton 最近提出的 Capsule 计划

    摘要:近几年以卷积神经网络有什么问题为主题做了多场报道,提出了他的计划。最初提出就成为了人工智能火热的研究方向。展现了和玻尔兹曼分布间惊人的联系其在论文中多次称,其背后的内涵引人遐想。 Hinton 以深度学习之父 和 神经网络先驱 闻名于世,其对深度学习及神经网络的诸多核心算法和结构(包括深度学习这个名称本身,反向传播算法,受限玻尔兹曼机,深度置信网络,对比散度算法,ReLU激活单元,Dropo...

    Donald 评论0 收藏0
  • CNN浅析和历年ImageNet冠军模型解析

    摘要:卷积神经网络原理浅析卷积神经网络,最初是为解决图像识别等问题设计的,当然其现在的应用不仅限于图像和视频,也可用于时间序列信号,比如音频信号文本数据等。卷积神经网络的概念最早出自世纪年代科学家提出的感受野。 卷积神经网络原理浅析  卷积神经网络(Convolutional Neural Network,CNN)最初是为解决图像识别等问题设计的,当然其现在的应用不仅限于图像和视频,也可用于时间序...

    edagarli 评论0 收藏0
  • 谷歌用3亿张图做了个深度学习实验,结论:数据还是越大越好

    摘要:然而,可用数据集的规模却没有成比例地扩大。这还说明无监督表征学习,以及半监督表征学习方法有良好的前景。例如,对于对象探测得分,单个模型目前可以实现,高于此前的。此外,构建包含图片的数据集并不是最终目标。 都说深度学习的兴起和大数据息息相关,那么是不是数据集越大,训练出的图像识别算法准确率就越高呢?Google的研究人员用3亿张图的内部数据集做了实验,然后写了篇论文。他们指出,在深度模型中,视...

    twohappy 评论0 收藏0
  • 极验验证:浅析深度学习模型与应用

    摘要:一时之间,深度学习备受追捧。百度等等公司纷纷开始大量的投入深度学习的应用研究。极验验证就是将深度学习应用于网络安全防御,通过深度学习建模学习人类与机器的行为特征,来区别人与机器,防止恶意程序对网站进行垃圾注册,撞库登录等。 2006年Geoffery  Hinton提出了深度学习(多层神经网络),并在2012年的ImageNet竞赛中有非凡的表现,以15.3%的Top-5错误率夺魁,比利用传...

    王岩威 评论0 收藏0
  • Kubernetes 调度器浅析

    摘要:与已运行相关的过滤规则负责检查待调度与上已有之间的亲和性关系。并且每个打分函数都可以配置对应的权重值,下面介绍调度器策略配置时,也会涉及权重值的配置。默认权重值是,如果觉得某个打分函数特别重要,便可以加大该权重值。 一、概述 Kubernetes 是 Google 开源的容器集群管理系统(谷歌内部:Borg),而今天要介绍的 kube-scheduler 是 k8s 系统的核心组件之一...

    ranwu 评论0 收藏0

发表评论

0条评论

wangxinarhat

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<