机器学习入门之流浪地球

2023-11-17

1、引言

我国里程碑式科幻电影巨制《流浪地球》一经播出,在国内外引起了广泛的关注,吸引了一大批科幻爱好者前去踊跃观赏。

在这里插入图片描述

在电影中,时间已辗转至2075年,受到某些因素的影响,我们赖以生存的太阳即将面临毁灭。面对绝境,人类试图开启"流浪地球"计划,试图带着地球一起逃离太阳系,在浩瀚的宇宙中寻找人类宜居的新家园…

在现实中,时间回溯至2021年。当下的人类去年刚经历了人类历史上又一场天际浩劫,席卷全球的COVID-19病毒夺取了数以万计遇难者的宝贵生命,且该灾难目前仍留有余温…

接憧而至的灾难让人们捉襟见肘,我们无法预知下一次的灾难究竟会何时降临,该灾难是打击性的,还是毁灭性的。但我们能够把握的一点是,当灾难降临时,除了团结互助、众志成城外,我们人类亮出的“圣剑”无疑将是科学与技术…

而当下的科学与技术中,人工智能已悄然站在了一个时代的风口。人工智能技术正以有目共睹的速度影响着当今的各行各业。熟悉与掌握人工智能技术,不仅是时代使然,更像是一种使命,以帮助我们更好地应对变幻莫测的未来。利用科技改变生活,利用科技驱动革命…

而掌握人工智能技术的关键之一,便是学习与了解机器学习的相关概念。

为了比较直观地初步了解有关机器学习的相关概念,让我们用一个比较浅显的例子来为大家做一个简单的引入。

2、问题描述

电影《流浪地球》于2019年上映,观影人数第一年有2千万人,第二年有4千万人,第三年有6千万人,请问在2072年有多少千万人将会观看过该电影?

3、问题分析

这个问题,在我们人类看来,是十分简单的。我们假设x表示年份,y表示该年观影人数(单位:千万人)。根据问题中所给的几组数据,我们可以很容易地猜测x和y具有线性相关性。因此我们假设 y = k ∗ x y=k * x y=kx,将这几组数据中的任意一组代入即可得 y = 2 ∗ x y=2*x y=2x,故2072年有 y = 2 ∗ ( 2072 − 2019 + 1 ) = 2 ∗ 54 = 108 y=2*(2072-2019+1)=2*54=108 y=2(20722019+1)=254=108千万人观看过电影《流浪地球》。

以上我们仅用了简单的数学思想,便轻易地得到了该问题的答案。可对于机器而言,机器只会算术,机器可不懂数学啊!那我们如何让机器学会去思考并求解这个问题呢?

4、问题求解

4.1 数据集

对于任何一个学习任务而言,用以学习的数据必不可少。在本例中,仅有简单的三组数据作为训练数据集。

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]

4.2 模型构造

我们知道,对于一台机器而言,机器有输入input,也有输出output,且output在大多情况下依赖于input。

在本问题中,我们将年份x看作input,观影人数y看作output,问题就转换为了让机器去求解x与y之间的依赖关系。

对于机器而言,机器一开始并不知道x和y之间的具体关系,故我们姑且可以帮助机器假设x与y之间具有最简单的线性相关关系,即 y = w ∗ x y=w*x y=wx

def model(w, x):
    return w*x

从而该问题的核心即是利用已知的数据去求解系数 w w w

可问题是,机器可不知道数学里的代数学知识,它可不会求解方程…所以它只好使用最笨的方法,给 w w w先取一个简单的随机值 w 0 w_0 w0。在这里,机器选择给 w w w取一个介于0到1之间(或介于3-4之间)的随机值…

w_0 = random.uniform(0, 1)
# w_0 = random.uniform(3, 4)

4.3 损失函数

在我们期待机器自我学习求解 w w w之前,让我们先思考一个问题:如何衡量机器训练时预测的数据 y h a t y_{hat} yhat与真实值 y y y之间的差异

我们先容易想到的是,通过计算 y h a t y_{hat} yhat y y y之间的差值,即 ∣ y h a t − y ∣ |y_{hat}-y| yhaty。可问题是,该计算方式并不方便,该式中绝对值的存在会给我们的计算处理时带来麻烦。

由于开平方可以去绝对值,于是,我们不妨给该式加个平方,再除个2(方便后续求梯度),从而得到了该式的改进版本 1 2 ∗ ( y h a t − y ) 2 \frac{1}{2}*(y_{hat}-y)^2 21(yhaty)2

我们记训练预测值 y h a t y_{hat} yhat和真实值 y y y之间的差异为损失 l o s s loss loss,故有

l o s s = 1 2 ∗ ( y h a t − y ) 2 loss=\frac{1}{2}*(y_{hat}-y)^2 loss=21(yhaty)2

def loss(w, x, y):
    y_hat = model(w, x)
    return (y_hat- y)**2 / 2

4.4 梯度下降

有了损失函数 l o s s loss loss之后,我们还是不能够让机器直接开始训练学习,因为我们还需要弄明白一个问题: w w w如何才能变化至我们的理想值?

要解决这个问题,我们需要引入梯度的概念。

梯度原先是为研究多元函数而提出的概念。其本意是一个向量,表示某一点在该点处的方向导数沿着该方向取得最大值,即函数上在该点处沿着该方向变化率最大。

上述的说法可能有些抽象,其实可以这么理解:你在山顶,打算下山。下山总共有3个方向,每个方向有1个坡,其中最陡的那个坡,就是你沿着梯度方向的坡,也是你下山最快的坡。故梯度下降,实际上也就是"沿着梯度下降"

当然,如果这么解释还没有搞明白,也没事。因为在本例中,未知量仅有 w w w,故我们所面临的方向只有1个,故所求的梯度实际上并不是偏导数,而是导数。

那么梯度下降在本例中的具体含义是什么呢?

我们知道,在损失函数 l o s s = 1 2 ∗ ( y h a t − y ) 2 = 1 2 ∗ ( w ∗ x − y ) 2 loss=\frac{1}{2}*(y_{hat}-y)^2=\frac{1}{2}*(w*x-y)^2 loss=21(yhaty)2=21(wxy)2中,当给定x和y后, w w w为自变量,loss为因变量。loss关于w变化的函数图像大致如下所示:
在这里插入图片描述
很显然,该函数是一个简单的二次函数,它关于某一条直线 w = w ∗ w=w^* w=w对称。且 l o s s loss loss w = w ∗ w=w^* w=w时取得最小值 l o s s m i n = 0 loss_{min}=0 lossmin=0,此时表示机器经学习训练后所得的预测值与真实值之间没有差异,也就是我们期望达到的结果。

在本例中, w ∗ = 2 w^*=2 w=2,故我们让机器学习的目标就是让一开始所设的 w w w值不断地朝目标 w = w ∗ = 2 w=w^*=2 w=w=2靠近。而这个“靠近”的过程,也就是梯度下降的过程,其具体可以用以下数学表达式表示:

w t = w t − 1 − α ∗ g r a d w_{t}=w_{t-1}-α*grad wt=wt1αgrad

其中, α α α为学习率, g r a d grad grad表示 t − 1 t-1 t1时刻变量 w w w l o s s loss loss曲线上的梯度。

以下让我们来解析该式为何如此构成,以及式中各参数的具体含义…

首先我们看梯度 g r a d grad grad。按照上面的说法,grad既然表示某个变化率最大的方向,故在本例中, w w w l o s s loss loss曲线上的梯度方向应为切线方向。该切线的具体表达式为:

g r a d = ∂ l o s s ∂ w = ∂ ∂ w [ 1 2 ( w x − y ) 2 ] = ( w x − y ) ∗ x grad=\frac{\partial loss}{\partial w}=\frac{\partial}{\partial w}[\frac{1}{2}(wx-y)^2]=(wx-y)*x grad=wloss=w[21(wxy)2]=(wxy)x

def gradient(w, x, y):
    return x*(w*x - y)

接下来,我们看学习率 α α α,它是一个大于0的正值,它用于控制梯度下降速度的快慢

在了解了这两个参数的含义后,我们再来看下图。

在这里插入图片描述
该图即反映了公式 w t = w t − 1 − α ∗ g r a d w_{t}=w_{t-1}-α*grad wt=wt1αgrad的运行机理…

首先我们看loss曲线的左半部分。橙色点start 可以看作 w t − 1 w_{t-1} wt1,青色next 可以看作 w t w_{t} wt,而蓝色的直线表示 w t − 1 w_{t-1} wt1在曲线上的切线。由于该切线的斜率显然小于0,即 g r a d < 0 grad<0 grad<0,而 α α α又是一个大于0的值,即 α > 0 α>0 α>0,从而 α ∗ g r a d α*grad αgrad是一个小于0的值, w t = w t − 1 − α ∗ g r a d w_t=w_{t-1}-α*grad wt=wt1αgrad就相当于 w t − 1 w_{t-1} wt1加上了一个大于0的值,再将该结果赋值给 w t w_t wt而在loss曲线的左半部分,随着 w w w的不断增大,loss将会随之不断减小,从而 w w w随着梯度下降的过程也就是 w w w不断增大趋近于 w = w ∗ w=w^* w=w的过程。

同理,接下来我们再看loss曲线的右半部分。金色点start 可以看作 w t − 1 w_{t-1} wt1,品红色next 可以看作 w t w_{t} wt,而蓝色的直线表示 w t − 1 w_{t-1} wt1在曲线上的切线。在这边,切线的斜率 g r a d > 0 grad>0 grad>0,同时 α > 0 α>0 α>0,从而 w t = w t − 1 − α ∗ g r a d w_t=w_{t-1}-α*grad wt=wt1αgrad就相当于 w t − 1 w_{t-1} wt1加上了一个小于0的值,再将该结果赋值给 w t w_t wt。而在loss曲线的右半部分,随着 w w w的不断减小,loss将会随之不断减小,从而 w w w随着梯度下降的过程也就是 w w w不断减少且趋近于 w = w ∗ w=w^* w=w的过程。

此时,我们将会惊讶的发现:我们仅仅只使用了一个公式,就模拟了机器学习训练的过程!理论上,无论 w w w的初始值为多少,只要公式 w t = w t − 1 − α ∗ g r a d w_t=w_{t-1}-α*grad wt=wt1αgrad的迭代次数够多, w t w_t wt最终必将趋近于我们的理想值 w ∗ w^* w

def gradient_decent(x, y, lr, w):
    grad = gradient(x, y)
    w = w - lr*grad
    return w

4.5 模型训练

掌握了梯度下降的大致原理后,便可以开始进行模型的训练了。这也是机器学习中体现机器“学习”的过程。

但在我们进行正式的训练之前,我们还需要思考以下两个问题:

  • x和y在本例中总共有3组数据。我们在计算梯度grad时,应取其中任意一组数据计算的值,还是取三组数据计算的平均值?
  • 学习率α在训练过程中对于梯度grad的控制作用具体如何体现?

首先对于第一个问题,其实答案很简单,即在本例中采用两种方案其中任意一种都可以。实际上,这是因为在本例中训练数据量较小的原因。但我们可以考虑当训练数据量n很庞大的时候,比如有 n = 1 0 6 n=10^6 n=106组数据时,计算所有组数据计算的平均值可想是一个非常耗时的工作。因此此时我们可以取其中的任意一组数据来代表整体的数据,以减少计算量,提高工作效率。然而在一些情景下仅用一组数据的计算值来代表整体的数据计算的平均值,难免会带来较大的偏差,故我们可以考虑使用m组( 1 < = m < = n 1<=m<=n 1<=m<=n)数据的平均值来代替整体数据计算的平均值。

实际上,在计算梯度grad时,取n组数据计算的平均值、取其中任意一组数据计算的值、取n组数据中任意m组数据的平均值三种不同的做法代表了梯度下降算法中计算梯度的三个不同版本:

梯度下降GD(gradient decent)
g r a d = 1 n ∑ i = 1 n ( w x i − y i ) ∗ x i grad=\frac{1}{n}\sum_{i=1}^n(wx_i-y_i)*x_i grad=n1i=1n(wxiyi)xi

随机梯度下降SGD(stochastic gradient decent)
g r a d = ( w x i − y i ) ∗ x i , i = r a n d i n t ( 1 , n ) grad=(wx_i-y_i)*x_i,i=randint(1,n) grad=(wxiyi)xi,i=randint(1,n)

批量梯度下降batch-SGD(batch gradient decent)
g r a d = 1 m ∑ i = 1 m ( w x i − y ) ∗ x i grad=\frac{1}{m}\sum_{i=1}^m(wx_i-y)*x_i grad=m1i=1m(wxiy)xi

在这里,为了简便,我们采用最为简单的SGD算法。故上述的GD算法将替换为:

def SGD(x, y, lr, w):
    # stochastic index
    sc_index = random.randint(0, len(x) - 1)
    x_i, y_i = x[sc_index], y[sc_index]
    grad = gradient(x_i, y_i)
    w = w - lr*grad
    return sc_index, w

接下来,让我们讨论一下学习率 α α α的具体作用形式。

首先我们考虑初始状态 α = 1 , w = 0.56 α=1,w=0.56 α=1,w=0.56的情况,假设我们采用SGD算法进行训练。经第一轮SGD后,设随机选出的为第一组数据 x 1 = 1.0 , y 1 = 2.0 x_1=1.0,y_1=2.0 x1=1.0,y1=2.0,计算得出 g r a d = ( w x 1 − y 1 ) ∗ x 1 = ( 0.56 ∗ 1.0 − 2.0 ) ∗ 1.0 = − 1.44 grad=(wx_1-y_1)*x_1=(0.56*1.0-2.0)*1.0=-1.44 grad=(wx1y1)x1=(0.561.02.0)1.0=1.44。从而第一轮对w的更新为 w = w − α ∗ g r a d = 0.56 − ( − 1.44 ) ∗ 1.0 = 2.0 w=w-α*grad=0.56-(-1.44)*1.0=2.0 w=wαgrad=0.56(1.44)1.0=2.0,直接一步便学到位了…

这里能够一步学到位,实际上是因为本例中给的数据都是不包含噪音(不含偏差数据组)的。假如我将原先的3组数据中第一组数据改为含偏差的新数据,即 x 1 = 1.0 , y 1 = 2.5 x_1=1.0,y_1=2.5 x1=1.0,y1=2.5,其中 y 1 = 2.5 y_1=2.5 y1=2.5与实际的真实数据 y 1 = 2 y_1=2 y1=2相差了 0.5 0.5 0.5

此时的训练数据集为:

x_data = [1.0, 2.0, 3.0]
y_data = [2.5, 4.0, 6.0]

假设我们此时继续采用SGD算法进行训练, w w w α α α的初始值与上述相同。经第一轮SGD后,设随机选出的第一组数据为 x 1 = 1.0 , y 1 = 2.5 x_1=1.0, y_1=2.5 x1=1.0,y1=2.5,计算得出 g r a d = ( w ∗ x 1 − y 1 ) ∗ x 1 = ( 0.56 ∗ 1.0 − 2.5 ) ∗ 1.0 = − 1.94 grad=(w*x_1-y_1)*x_1=(0.56*1.0-2.5)*1.0=-1.94 grad=(wx1y1)x1=(0.561.02.5)1.0=1.94。从而第一轮对w的更新为 w = w − α ∗ g r a d = 0.56 − ( − 1.94 ) ∗ 1.0 = 2.56 w=w-α*grad=0.56-(-1.94)*1.0=2.56 w=wαgrad=0.56(1.94)1.0=2.56。接着第二轮选出了第二组数据 x 2 = 2.0 , y 2 = 4.0 x2=2.0,y2=4.0 x2=2.0,y2=4.0,计算得出 g r a d = 2.24 , w = w − α ∗ g r a d = 2.56 − 2.24 ∗ 1.0 = 0.32 grad=2.24,w=w-α*grad=2.56-2.24*1.0=0.32 grad=2.24w=wαgrad=2.562.241.0=0.32

从这个过程中,我们发现一件奇怪的事:随着机器的不断学习训练,训练得出的 w w w不但没有逐渐接近我们的期望值 w ∗ = 2.0 w^*=2.0 w=2.0,反而却不断偏离?具体的直观表示即如下图中 w w w在loss曲线上以对称轴 w = w ∗ w=w^* w=w"反复横跳",偏离目标值…

在这里插入图片描述
为了减小噪声数据所带来的影响,我们可以采用的一种做法即为降低学习率 α α α。比如我可以将 α α α降到0.1,那么纵使由于噪声数据的影响使得 w w w在曲线两端"反复横跳",也可以保证在整体趋势下 w w w的值是不断地趋近于我们的目标值的,较为直观的理解如下图所示。

在这里插入图片描述
在实际任务中,我们无法保证拿到的训练数据是无偏的,所以设置一个学习率 α α α,对于机器学习的训练过程是十分有必要的, α α α常取的值有 0.1 , 0.01 , 0.003 0.1,0.01,0.003 0.1,0.01,0.003等。

在理解了以上两个重要概念后,训练过程对于我们来说便十分简单了。实际上,对于本例而言,仅有以下三步:

  1. 设置训练参数w初始值 w 0 w_0 w0,训练数据x_data、y_data、学习率lr以及训练次数num_epochs。
  2. 拿到训练数据x_data、y_data,学习率lr,训练参数w,使用SGD算法进行梯度下降,返回训练时所取的数据索引sc_index和训练后参数w。
  3. 拿到SGD返回的数据索引sc_index和训练参数w,利用loss函数衡量x_data[sc_index]*w和真实值y_data[sc_index]之间的差异。

除此之外,为了有一个直观的理解,我们将整个训练过程的结果保存下来,并做一个简单的可视化。

def train(num_epochs, x, y, w, lr):
    epoch_list = [epoch + 1 for epoch in range(num_epochs)]
    loss_list = []
    for epoch in range(num_epochs):
        sc_index, w = SGD(x_data, y_data, lr, w)
        l = loss(w, x[sc_index], y[sc_index])
        loss_list.append(l)
        print(f'epoch:{epoch+1} loss={l:.6f} w={w:.3f}')
    plt.plot(epoch_list, loss_list)
    plt.xlabel("epoch")
    plt.ylabel("loss")
    plt.show()
    return w

假设我们的训练数据与参数为:

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w_0 = random.uniform(0, 1)
num_epochs, lr = 10, 0.1
train(num_epochs, x_data, y_data, w_0, lr)

最终的训练结果为:

在这里插入图片描述
假设我们的训练数据与参数为:

x_data = [1.0, 2.0, 3.0]
y_data = [2.5, 4.0, 6.0]
w_0 = random.uniform(0, 1)
num_epochs, lr = 20, 0.1
w_final = train(num_epochs, x_data, y_data, w_0, lr)

最终的训练结果为:

在这里插入图片描述

4.6 预测

在机器完成了训练之后,便得到了一个接近于理想参数 w ∗ w^* w的值 w f i n a l w_{final} wfinal。从而我们的预测代码为:

def prediction(w, year):
    return w*(year - 2019 + 1)

print(f'2072年时观看过《流浪地球》的人数将达到{prediction(w_final, 2072):.1f}千万人')

4.7 完整实现代码

import random
import matplotlib.pyplot as plt
def model(w, x):
    return w*x

def loss(w, x, y):
    y_hat = model(w, x)
    return (y_hat - y)**2 / 2

def gradient(w, x, y):
    return x*(w*x - y)

def SGD(x, y, lr, w):
    # stochastic index
    sc_index = random.randint(0, len(x) - 1)
    print("sc_index:", sc_index)
    x_i, y_i = x[sc_index], y[sc_index]
    grad = gradient(w, x_i, y_i)
    w = w - lr*grad
    return sc_index, w

def train(num_epochs, x, y, w, lr):
    epoch_list = [epoch + 1 for epoch in range(num_epochs)]
    loss_list = []
    for epoch in range(num_epochs):
        sc_index, w = SGD(x_data, y_data, lr, w)
        l = loss(w, x[sc_index], y[sc_index])
        loss_list.append(l)
        print(f'epoch:{epoch+1} loss={l:.6f} w={w:.3f}')
    plt.plot(epoch_list, loss_list)
    plt.xlabel("epoch")
    plt.ylabel("loss")
    plt.show()
    return w

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w_0 = random.uniform(0, 1)
num_epochs, lr = 50, 0.1
w_final = train(num_epochs, x_data, y_data, w_0, lr)

def prediction(w, year):
    return w*(year - 2019 + 1)

print(f'2072年时观看过《流浪地球》的人数将达到{prediction(w_final, 2072):.1f}千万人')

5、总结与思考

通过以上这么一个线性模型的简单例子,我们或许可以总结出机器学习的全过程中几个重要的组成部分:数据、模型、策略、算法。

首先就是数据,数据质量的好坏直接会影响我们的训练过程与训练结果。故在整个训练开始前,进行数据的筛选和噪音数据的剔除(即所谓的人工特征提取)对于整个机器学习过程尤为重要。

接下来是模型、策略和算法,这三个部分共同组成了机器学习的三要素。

  • 模型即为我们期盼机器学习到的映射函数 y = f ( x ) y=f(x) y=f(x),使得对于一个我们任意给定机器的一个输入 x x x,能得到一个接近于真实值(等于那最好) y y y
  • 策略即为帮助机器从众多可能存在的假设模型学习到理想模型所使用的方法。如本例中为得到我们理想的模型 y = 2 ∗ x y=2*x y=2x,我们使用损失函数loss来度量机器经每轮训练后的所得预测值 y h a t y_{hat} yhat与真实值 y y y之间的差异。
  • 算法表示机器学习模型的具体方法,也就是使得模型中可训练参数接近于理想值的具体实施步骤,如本例中所采用的学习算法为SGD。

-------------------------------------------结尾分割线-------------------------------------------

正如上文所讲,以上的例子仅为了对想要学习人工智能或机器学习的朋友做一个简单的引入,可能存在诸多不严谨之处,还望各位见谅。但我个人看来,无论学习再怎么高大上的知识,先做一个深入浅出的理解还是十分有必要的…

对于本文所举的例子而言,其关键便在于对SGD算法中梯度下降的过程与学习率α的理解。如果看完后一时半会儿并没有理解,或者觉得难以理解,没关系,只要能从本例中有一些收获,日后在根据自己的理解对整个机器学习过程进行一个简单的推导,在纸上勾勾画画一下,或许你将在某个时刻茅塞顿开。

实际上,对于学习率 α α α的理解,除了从噪音数据的角度外,还可以再从另外的一些角度理解。如讨论在数据正常时学习率 α > 1 α>1 α>1或学习率 α < 1 α<1 α<1对训练过程所起到的作用。限于篇幅,具体的过程在这里我便不再赘述了…

最后,希望看到了这里的你,能收获探究人工智能与机器学习的乐趣…

2072年,受到了某种因素的影响,太阳的能源即将燃烧殆尽,《流浪地球》的电影情景猛然照进了现实…但这一次,人类不再恐慌。伴随着强人工智能AGI的发展,人类的科技高歌猛进,人类对量子力学、黑洞、虫洞、弦理论的研究有了新的突破…在灾难即将降临的那一刻,AGI按下按钮,整个地球瞬间坍缩至普朗克尺度的一个粒子,进入了高维空间,进入了虫洞,最后顺着虫洞空间跳跃至了人类早已在宇宙中物色好的新家园…

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

机器学习入门之流浪地球 的相关文章

随机推荐

  • python3 练习题100例 (十二)

    题目十二 打印出所有的 水仙花数 所谓 水仙花数 是指一个三位数 其各位数字立方和等于该数本身 例如 153是一个 水仙花数 因为153 1的三次方 5的三次方 3的三次方 usr bin env python3 coding utf 8
  • “ModuleNotFoundError: No module named sklearn”解决办法

    最近在跑实验的时候 需要导入sklearn 但是运行代码一直提示 ModuleNotFoundError No module named sklearn 实验中导入sklearn的代码 from sklearn import metrics
  • Linux CentOS7 中 完美解决VMTools失效,windows 与 Liunx间完美复制文件,无报错的解决方案

    问题 我也是才刚使用CentOS7没多久 搭建好环境后出现比较头疼的问题就是 Windows 和 Linux 之间无法复制粘贴文本和文件 这个问题只要在虚拟机中安装 VMTools 就能解决 但是不知道什么原因导致 我在CentOS 6 8
  • Linux 狂神说学习笔记

    狂神说linux Linux 基本目录 目录相关命令 文件属性 查看文件 硬链接和软链接 vim 账号管理 用户组管理 磁盘管理 进程管理 环境安装 基本目录 目录相关命令 ls al 列出目录 a所有文件包括隐藏文件 l列出所有文件包括文
  • MyBatis ognl.NoSuchPropertyException 或者 Invalid bound statement (not found)

    描述 SpringBoot Mybatis plus 项目 运行时出现如下错误 ognl NoSuchPropertyException 没有对应属性异常 Invalid bound statement not found 绑定语句无效 未
  • 问题小结(3)-dialog标题居中

    dialog标题居中问题 用系统的AlertDialog Builder创建dialog时 如果需要将dialog的title居中显示 需要调用 setCustomTitle View view 方法 对需要设置的view设置居中的相关属性
  • zookeeper 分布式共享锁的流程图

    1分布式共享锁的流程图 原理 package cn itcast bigdata zklock import java util Collections import java util List import java util Rand
  • 水球图 及各种参数设置

    水球图 Liquid Fill Chart 是Echarts的一个插件 在官方文档中没有 可以用来优雅的展示百分比数据 水球图 gif 安装 HTML中引入水球图
  • docker基础1——架构组成、安装配置

    文章目录 一 发展起源 1 1 传统虚拟化与容器虚拟化 1 2 docker底层核心技术 1 2 1 命名空间 1 2 2 控制组 1 3 docker工作方式 1 4 docker容器编排 1 5 docker优劣势 1 6 docker
  • iframe的替代品

    面试题 使用过iframe框架 那你对于iframe框架的优缺点知道多少 并且由于iframe的一些缺点 国内外针对这个框架的替代品你知道有哪些呢 知识点1 iframe框架的优缺点 优点 1 可以跨域请求其他网站 并将网站完整展示出来 2
  • [课程复习] 数据结构之线性表、树、图、查找、排序经典算法复习

    作者最近在复习考博 乘此机会分享一些计算机科学与技术 软件工程等相关专业课程考题 一方面分享给考研 考博 找工作的博友 另一方面也是自己今后完成这些课程的复习资料 同时也是在线笔记 基础知识 希望对您有所帮助 不喜勿喷 无知 乐观 低调 谦
  • 【Qt Modbus通信】QModbus实现modbus的主机功能 源码分享

    前言 modbus在上下位机数据交互时被广泛使用 因此写了这篇笔记和大家一起学习 Qt Modbus通信 libmodbus实现modbus的主机功能 从机功能 源码分享 之前使用libmodbus实现了modbus的主从功能 但发现主机查
  • docker frp 搭建内网穿透

    docker frp 搭建内网穿透 可运行的云服务器 docker pull snowdreamtech frps mkdir p root docker frp cd root docker frp touch frps ini comm
  • 企业微信如何简单实现定时发送文件到群:企业微信群机器人操作(Java代码实现)

    前言 不知道小伙伴们的公司组织架构通勤用的啥软件 我公司用的企业微信 然后业务销售部那边需要每天统计销售数据报表然后发在群里 我是开发 我不配在群里 知道这个背景以后 产品给我们的需求是 直接统计数据按照业务那边的报表模板直接生成销售报表
  • ARM-A架构入门基础(三)MMU

    14天学习训练营导师课程 周贺贺 ARMv8 ARMv9架构 快速入门 1 MMU Memory Management Unit 内存管理单元 MMU的意义在于将软件程序的虚拟地址转换为真实的物理地址 2 MMU种类 Secure EL1
  • 数据结构——图解循环队列长度计算问题

    队列定义是这样的 define MAXSIZE 10 typedef struct ElemType data MAXSIZE int front rear SeqQueue 一个队列 一个存放元素的数组 一个队头指针 一个队尾指针 fro
  • np.array与list的内存大小比较

    1 np array与list 比较 a 1 2 3 4 需要4个指针和四个数据 增加了存储和消耗cpu a np array 1 2 3 4 只需要存放四个数据 读取和计算更加方便 2 np array与list所占内存 def test
  • sqlserver语言转mysql_SQLSERVER 脚本转MYSQL 脚本的方法总结

    标签 1 MYSQL中SQL脚步都要以分号 结尾 这点比SQLSERVER要严谨 2 所有关键字都要加上 比如 Status 替换成 Status 按是有个 的键 3 SQLSERVER的dbo 在mysql中不支持 都要去掉 4 isnu
  • java field static_Java基础之关键字static

    static是Java中的一个关键字 用来修饰成员变量与成员方法 还可以用于编写静态代码块 对于被static修饰的东西 JVM在加载类的时候 就给这些变量在内存中分配了一定的空间 即在编译阶段时就为这些成员变量的实例分配了空间 一 静态变
  • 机器学习入门之流浪地球

    机器学习入门之流浪地球 1 引言 2 问题描述 3 问题分析 4 问题求解 4 1 数据集 4 2 模型构造 4 3 损失函数 4 4 梯度下降 4 5 模型训练 4 6 预测 4 7 完整实现代码 5 总结与思考 1 引言 我国里程碑式科