【兔年创意投稿】兔兔的奇妙之旅(五)神秘的黑盒子

1,162 阅读5分钟

我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛

注:本系列文章以虚构的兔子世界为素材,穿插悬疑侦探。博君一笑,请勿当真。如有雷同,实属巧合~

书接上回。

突突和达达还是决定赴约,但出于安全考虑,这次它们没有带上小小。

两兔再次来到密林中,上次的兔子热情地欢迎了它们。

兔子问它们是否已经算出了结果,达达拿出了预先画好的三角图。(图片有点大,这里就不放出来了),只见最后一行的内容是:

[1,19,171,969,3876,11628,27132,50388,75582,92378,92378,75582,50388,27132,11628,3876,969,171,19,1]

对面的兔子点点头,它说道:“之前我提到的快捷办法————”

神秘黑箱登场

只见它边说边将桌上的一个矩形大黑盖掀开成两半,上半部分的屏幕突然发出了亮光。在突突和达达惊异的目光中,它的手指在下半部分的一排排列整齐的按钮中噼噼啪啪一顿狂敲,或者说像在飞舞和生花,而它说这是在写代码

最后,屏幕中输出了完整的杨辉三角前20行序列。

对面的兔子表示,这个黑箱很神奇,它能帮助解决很多问题,做很多决策。

因为兔子的本名中有“湘”字,又有一个大黑箱,突突和达达就把它记作“黑箱兔”了。

这时达达发问,“那这个箱子能告诉我,如果现在要在这个村子里设一个医馆,要建在哪里才能尽可能照顾到所有家庭呢?”

说着,它指了指黑箱兔屋子里墙上的地图。

医馆的最佳位置

黑箱兔眉毛一挑,“这个问题有点意思。”

只见它以地图的左下角为原点(0,0),标记了各个村民家的位置并记在纸上,随后,它编写了一段代码,并将这些数据输入黑箱。屏幕上显示了一个坐标。

三兔按照坐标找到了图上的地点,发现果然是兼顾各处。达达不由感叹:“妙啊!”

“不过,” 黑箱兔补充道:“虽然它确实很有用,但目前而言它于我们而言却还是一个黑箱。我们知道给它输入,它会有输出。但我们却不清楚它为什么会这样输出,背后的机制又是什么。对这个生成结果的程序是这样,对这个黑箱本身也是这样。”

(作者注:在现实世界中,我们大多数人对计算机以及大火的机器ML、DL的真正了解又有多少呢?直到现在,后者的领域中的大多数东西也还是黑箱)

黑箱兔扭过头,看向达达和突突,“我最近在研究这个机器的底层———操作系统,你们想一起来吗?”

达达和突突面面相觑。

本期总结及下期看点

突突和达达终于明白了密林中的兔子被避讳的原因。原来,是因为它们拥有一股神秘力量————黑箱。而其他兔子不懂,觉得它们很高深很可怕罢了。兔子们对自己不懂的事物总是又畏惧又抗拒。

那么,突突和达达是否会加入黑箱兔呢?它们又能否搞清其中的玄机?黑箱兔所说的操作系统又该怎么理解呢?

欲知后事如何,请听下回分解!

附录

杨辉三角

详情参见百度百科 杨辉三角

image.png

杨辉三角是中国古代数学的杰出研究成果之一,它把二项式系数图形化,把组合数内在的一些代数性质直观地从图形中体现出来,是一种离散型的数与形的结合.

代码实现

以下代码借助杨辉三角的数学性质:

第 n 行的第 i 个数等于第 n−1 行的第 i−1 个数和第 i个数之和

class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> list=new ArrayList<List<Integer>>();
        for(int i=0;i<numRows;i++){
            List<Integer> row=new ArrayList<>();
            for(int j=0;j<=i;j++){
                if(j==0||j==i) row.add(1);
                else row.add(list.get(i-1).get(j-1)+list.get(i-1).get(j));
            }
            list.add(row);
        }
        return list;
    }
}

梯度下降法

上文情形中用到了 梯度下降法

这是一种最优化算法,常用于机器学习和人工智能当中用来递归逼近最小偏差模型。 所谓的“梯度”,就是函数的某个点在某时刻的斜率;求梯度,就是对函数求导。 image.png

梯度下降法服务于具体的应用场景。 以下是上文提到的场景的代码的具体实现。

代码实现

该题的梯度下降的手写版代码如下:(我用Java写算法题比较多,以下代码参考官解)

class Solution {
    public double getMinDistSum(int[][] positions) {
        double eps = 1e-7;
        double alpha = 1;
        double decay = 1e-3;
        int n=positions.length;
        int batchsize=n;
        double x=0,y=0;
        for(int [] pos:positions){
            x+=pos[0];
            y+=pos[1];
        }
        x/=n;
        y/=n;

        while(true){
            shuffle(positions);
            double xPre=x;
            double yPre=y;
            for(int i=0;i<n;i+=batchsize){
                int j=Math.min(n,i+batchsize);
                //求导
                double dx=0,dy=0;
                for(int k=i;k<j;k++){
                    int [] pos=positions[k];
                    dx+=(x-pos[0])/(Math.sqrt((x-pos[0])*(x-pos[0])+(y-pos[1])*(y-pos[1]))+eps);
                dy+=(y-pos[1])/(Math.sqrt((x -pos[0])*(x-pos[0])+(y-pos[1])*(y-pos[1]))+eps);
                }
                x-=alpha*dx;
                y-=alpha*dy;
                alpha*=(1.0-decay);
            }
            if (Math.sqrt((x-xPre)*(x-xPre)+(y-yPre)*(y-yPre))<eps) {
                break;
            }
        }
        return getDistance(x,y,positions);
    }

    public double getDistance(double xc,double yc,int [][] positions){
        double res=0;
        for(int [] pos:positions){
            int x=pos[0];
            int y=pos[1];
            res+=Math.sqrt((xc-x)*(xc-x)+(yc-y)*(yc-y));
        }
        return res;
    }

    public void shuffle(int[][] positions){
        int n=positions.length;
        Random r=new Random();
        for(int i=0;i<n;i++){
            int ran=r.nextInt(n);
            int x=positions[i][0];
            int y=positions[i][1];
            positions[i][0]=positions[ran][0];
            positions[i][1]=positions[ran][1];
            positions[ran][0]=x;
            positions[ran][1]=y;
        }
    }
}
  • 梯度下降法是机器学习和深度学习领域中一个基本思想。一般实际应用中不需要自己实现这个过程。所以上述的代码一般不会出现在工程应用中,而更多出现在相关岗位的笔试面试考察中。
  • 截至目前,用于搞机器学习和深度学习的代码语言主要是Python。