文章目录

  • 一、问题分析
    • 1.1 线性回归模型
    • 1.2 五步法
  • 二、数据处理
    • 2.1 数据导入
    • 2.2 数据形状变换
    • 2.3 数据集划分
    • 2.4 数据归一化处理
    • 2.5 封装成load data函数
    • 2.6 获取归一化后的训练集和测试集
  • 三、模型设计
    • 3.1 前向计算
    • 3.2 以类的方式来实现网络结构
  • 四、训练配置
    • 4.1 损失函数——均方误差
    • 4.2 同时计算多个样本的损失函数
  • 五、训练过程
    • 5.1 梯度下降法
    • 5.2 梯度计算
    • 5.3 使用NumPy进行梯度计算
    • 5.4 梯度更新
    • 5.5 封装Train函数
    • 5.6 训练过程扩展到全部参数
    • 5.7 随机梯度下降法( Stochastic Gradient Descent)
  • 六、模型保存
    • 小结

神经网络基本概念

  • 神经元、多层连接、前向计算、计算图

模型结构三要素

  • 模型假设、评价函数和优化算法

一、问题分析

对于预测问题,可以根据预测输出的类型是连续的实数值,还是离散的标签,区分为回归任务和分类任务。因为房价是一个连续值,所以房价预测显然是一个回归任务。下面我们尝试用最简单的多元线性回归模型解决这个问题,并用神经网络来实现这个模型。

1.1 线性回归模型

假设房价和各影响因素之间能够用线性关系来描述:
y=∑j=1Mxjwj+b(公式1)y = {\sum_{j=1}^Mx_j w_j} + b (公式1) y=j=1∑M​xj​wj​+b(公式1)
模型的求解即是通过数据拟合出每个wjw_jwj​和bbb。其中,wjw_jwj​和bbb分别表示该线性模型的权重和偏置。一维情况下,wjw_jwj​ 和 bbb 是直线的斜率和截距。

线性回归模型使用均方误差MSE作为损失函数(Loss),用以衡量预测房价和真实房价的差异,公式如下:

MSE=1n∑i=1n(Yi^−Yi)2(公式2)MSE = \frac{1}{n} \sum_{i=1}^n(\hat{Y_i} - {Y_i})^{2} (公式2) MSE=n1​i=1∑n​(Yi​^​−Yi​)2(公式2)
**神经网络的标准结构中每个神经元由加权和与非线性变换构成,然后将多个神经元分层的摆放并连接形成神经网络。**线性回归模型可以认为是神经网络模型的一种极简特例,是一个只有加权和、没有非线性变换的神经元(无需形成网络),如 图2 所示。


图2:线性回归模型的神经网络结构

1.2 五步法

不同场景的深度学习模型具具备一定的通用性,五个步骤即可完成模型的构建和训练。在构建不同的模型时,只有模型三要素不同,其它步骤基本一致。

  • 数据处理:从本地或URL读取数据,并完成预处理操作(如数据校验、格式转化等),保证模型可读取。
  • 模型设计: (模型要素1 )网络结构设计,相当于模型的假设空间,即模型能够表达的关系集合。
  • 训练配置:(模型要素2 )设定模型采用的寻解算法,即优化器,并指定计算资源。
  • 训练过程:(模型要素3 )循环调用训练过程,每轮都包括前向计算、损失函数(优化目标)和后向传播三个步骤。
  • 模型保存:将训练好的模型保存,模型预测时调用。


图3:构建神经网络/深度学习模型的基本步骤

二、数据处理

2.1 数据导入

通过如下代码读入数据,了解下波士顿房价的数据集结构,数据存放在本地目录下housing.data文件中。

# 导入需要用到的package
import numpy as np
import json
import math
# 读入训练数据
datafile = './work/housing.data'
data = np.fromfile(datafile, sep=' ')
data

2.2 数据形状变换

由于读入的原始数据是1维的,所有数据都连在一起。因此需要我们将数据的形状进行变换,形成一个2维的矩阵,每行为一个数据样本(14个值),每个数据样本包含13个XXX(影响房价的特征)和一个YYY(该类型房屋的均价)。

# 读入之后的数据被转化成1维array,其中array的第0-13项是第一条数据,第14-27项是第二条数据,以此类推....
# 这里对原始数据做reshape,变成N x 14的形式
feature_names = [ 'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE','DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV' ]
feature_num = len(feature_names)
data = data.reshape([data.shape[0] // feature_num, feature_num])# 查看数据
x = data[0]
print(x.shape)
print(x)

2.3 数据集划分

**将数据集划分成训练集和测试集,其中训练集用于确定模型的参数,测试集用于评判模型的效果。**一般我们将80%的数据用作训练集,20%用作测试集,实现代码如下。通过打印训练集的形状,可以发现共有404个样本,每个样本含有13个特征和1个预测值。

ratio = 0.8
offset = int(data.shape[0] * ratio)
training_data = data[:offset]
training_data.shape

2.4 数据归一化处理

**对每个特征进行归一化处理,使得每个特征的取值缩放到0~1之间。**这样做有两个好处:一是模型训练更高效,二是特征前的权重大小可以代表该变量对预测结果的贡献度(因为每个特征值本身的范围相同)。

# 计算train数据集的最大值,最小值,平均值
maximums, minimums, avgs = \training_data.max(axis=0), \training_data.min(axis=0), \training_data.sum(axis=0) / training_data.shape[0]
# 对数据进行归一化处理
for i in range(feature_num):#print(maximums[i], minimums[i], avgs[i])data[:, i] = (data[:, i] - minimums[i]) / (maximums[i] - minimums[i])

2.5 封装成load data函数

将上述几个数据处理操作封装成load data函数,以便下一步模型的调用,实现方法如下。

def load_data():# 从文件导入数据datafile = './work/housing.data'data = np.fromfile(datafile, sep=' ')# 每条数据包括14项,其中前面13项是影响因素,第14项是相应的房屋价格中位数feature_names = [ 'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', \'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV' ]feature_num = len(feature_names)# 将原始数据进行Reshape,变成[N, 14]这样的形状data = data.reshape([data.shape[0] // feature_num, feature_num])# 将原数据集拆分成训练集和测试集# 这里使用80%的数据做训练,20%的数据做测试# 测试集和训练集必须是没有交集的ratio = 0.8offset = int(data.shape[0] * ratio)training_data = data[:offset]# 计算训练集的最大值,最小值,平均值maximums, minimums, avgs = training_data.max(axis=0), training_data.min(axis=0), \training_data.sum(axis=0) / training_data.shape[0]# 对数据进行归一化处理for i in range(feature_num):#print(maximums[i], minimums[i], avgs[i])data[:, i] = (data[:, i] - minimums[i]) / (maximums[i] - minimums[i])# 训练集和测试集的划分比例training_data = data[:offset]test_data = data[offset:]return training_data, test_data

2.6 获取归一化后的训练集和测试集

# 获取数据
training_data, test_data = load_data()
x = training_data[:, :-1]
y = training_data[:, -1:]# 查看数据
print(x[0])
print(y[0])

三、模型设计

模型设计是深度学习模型关键要素之一,也称为网络结构设计,相当于模型的假设空间,即实现模型“前向计算”(从输入到输出)的过程。

3.1 前向计算

  • 如果将输入特征和输出预测值均以向量表示,输入特征xxx有13个分量,yyy有1个分量,那么参数权重的形状(shape)是13×113\times113×1。假设我们以如下任意数字赋值参数做初始化:

w=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,−0.1,−0.2,−0.3,−0.4,0.0]w=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, -0.1, -0.2, -0.3, -0.4, 0.0] w=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,−0.1,−0.2,−0.3,−0.4,0.0]

w = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, -0.1, -0.2, -0.3, -0.4, 0.0]
w = np.array(w).reshape([13, 1])
  • 取出第1条样本数据,观察样本的特征向量与参数向量相乘的结果。
x1=x[0]
t = np.dot(x1, w)
print(t)
  • 完整的线性回归公式,还需要初始化偏移量bbb,同样随意赋初值-0.2。那么,线性回归模型的完整输出是z=t+bz=t+bz=t+b,这个从特征和参数计算输出值的过程称为“前向计算”。
b = -0.2
z = t + b
print(z)

3.2 以类的方式来实现网络结构

将上述计算预测输出的过程以“类和对象”的方式来描述,类成员变量有参数www和bbb。通过写一个forward函数(代表“前向计算”)完成上述从特征和参数到输出预测值的计算过程,代码如下所示。

class Network(object):def __init__(self, num_of_weights):# 随机产生w的初始值# 为了保持程序每次运行结果的一致性,# 此处设置固定的随机数种子np.random.seed(0)self.w = np.random.randn(num_of_weights, 1)self.b = 0.def forward(self, x):z = np.dot(x, self.w) + self.breturn z
# 生成类的实例,调用其方法来完成前向计算的过程
net = Network(13)
x1 = x[0]
y1 = y[0]
z = net.forward(x1)
print(z)

从上述前向计算的过程可见,**线性回归也可以表示成一种简单的神经网络(只有一个神经元,且激活函数为恒等式)。**这也是机器学习模型普遍为深度学习模型替代的原因:由于深度学习网络强大的表示能力,很多传统机器学习模型的学习能力等同于相对简单的深度学习模型。

四、训练配置

模型设计完成后,需要通过训练配置寻找模型的最优值,即通过损失函数来衡量模型的好坏。训练配置也是深度学习模型关键要素之一。

4.1 损失函数——均方误差

通过模型计算x1x_1x1​表示的影响因素所对应的房价应该是zzz, 但实际数据告诉我们房价是yyy。这时我们需要有某种指标来衡量预测值zzz跟真实值yyy之间的差距。对于回归问题,最常采用的衡量方法是使用均方误差作为评价模型好坏的指标,具体定义如下:

Loss=(y−z)2(公式3)Loss = (y - z)^2 (公式3) Loss=(y−z)2(公式3)
**上式中的LossLossLoss(简记为: LLL)通常也被称作损失函数,它是衡量模型好坏的指标。**在回归问题中,均方误差是一种比较常见的形式,分类问题中通常会采用交叉熵作为损失函数,在后续的章节中会更详细的介绍。对一个样本计算损失函数值的实现如下。

Loss = (y1 - z)*(y1 - z)
print(Loss)

4.2 同时计算多个样本的损失函数

因为计算损失函数时需要把每个样本的损失函数值都考虑到,所以我们需要对单个样本的损失函数进行求和,并除以样本总数NNN。
L=1N∑i=1N(yi−zi)2(公式4)​L= \frac{1}{N}\sum_{i=1}^N{(y_i - z_i)^2} (公式4)​ L=N1​i=1∑N​(yi​−zi​)2(公式4)​
在Network类下面添加损失函数的计算过程如下。

class Network(object):def __init__(self, num_of_weights):# 随机产生w的初始值# 为了保持程序每次运行结果的一致性,此处设置固定的随机数种子np.random.seed(0)self.w = np.random.randn(num_of_weights, 1)self.b = 0.def forward(self, x):z = np.dot(x, self.w) + self.breturn z# 求均方误差def loss(self, z, y):cost = np.mean((z - y)**2)return cost

使用定义的Network类,可以方便的计算预测值和损失函数。需要注意的是,类中的变量xxx, www,bbb, zzz, errorerrorerror等均是向量。以变量xxx为例,共有两个维度,一个代表特征数量(值为13),一个代表样本数量,代码如下所示。

net = Network(13)
# 此处可以一次性计算多个样本的预测值和损失函数
x1 = x[0:3]
y1 = y[0:3]
z = net.forward(x1)
print('predict: ', z)
loss = net.loss(z, y1)
print('loss:', loss)

五、训练过程

上述计算过程描述了如何构建神经网络,通过神经网络完成预测值和损失函数的计算。接下来介绍如何**求解参数www和bbb的数值,这个过程也称为模型训练过程。**训练过程是深度学习模型的关键要素之一,其目标是让定义的损失函数LossLossLoss尽可能的小,也就是说找到一个参数解www和bbb,使得损失函数取得极小值。

其中LLL表示的是损失函数的值,w\boldsymbol{w}w为模型权重,bbb为偏置项。w\boldsymbol{w}w和bbb均为要学习的模型参数。
损失函数表示成矩阵的形式为
L=1N∣∣y−(Xw+b)∣∣2,(公式7)L=\frac{1}{N}||\boldsymbol{y}-(\boldsymbol{X}\boldsymbol{w}+\boldsymbol{b})||^2, (公式7) L=N1​∣∣y−(Xw+b)∣∣2,(公式7)

其中y\boldsymbol{y}y为NNN个样本的标签值构成的向量,形状为N×1N\times 1N×1;X\boldsymbol{X}X为NNN个样本特征向量构成的矩阵,形状为N×DN\times DN×D,DDD为数据特征长度;w\boldsymbol{w}w为权重向量,形状为D×1D\times 1D×1;b\boldsymbol{b}b为所有元素都为bbb的向量,形状为N×1N\times 1N×1。
计算公式7对参数bbb的偏导数
∂L∂b=1T(y−(Xw+b)),(公式8)\frac{\partial L}{\partial b} = \boldsymbol{1}^T(\boldsymbol{y}-(\boldsymbol{X}\boldsymbol{w}+\boldsymbol{b})), (公式8) ∂b∂L​=1T(y−(Xw+b)),(公式8)
请注意,上述公式忽略了系数2N\frac{2}{N}N2​,并不影响最后结果。其中1\boldsymbol{1}1为NNN维的全1向量。
令公式8等于0,得到
b∗=xˉTw−yˉ(公式9)b^* = \boldsymbol{\bar{x}}^T\boldsymbol{w}-\bar{y}(公式9) b∗=xˉTw−yˉ​(公式9)
**其中yˉ=1N1Ty\bar{y}=\frac{1}{N}\boldsymbol{1}^T\boldsymbol{y}yˉ​=N1​1Ty为所有标签的平均值,xˉ=1N(1TX)T\boldsymbol{\bar{x}}=\frac{1}{N}(\boldsymbol{1}^T\boldsymbol{X})^Txˉ=N1​(1TX)T为所有特征向量的平均值。**将b∗b^*b∗带入公式7中并对参数w\boldsymbol{w}w求偏导得到
∂L∂w=(X−xˉT)T((y−yˉ)−(X−xˉT)w)(公式10)\frac{\partial L}{\partial \boldsymbol{w}} = (\boldsymbol{X}-\boldsymbol{\bar{x}}^T)^T((\boldsymbol{y}-\bar{y})-(\boldsymbol{X}-\boldsymbol{\bar{x}}^T)\boldsymbol{w}) (公式10) ∂w∂L​=(X−xˉT)T((y−yˉ​)−(X−xˉT)w)(公式10)

令公式10等于0,得到最优参数

w∗=((X−xˉT)T(X−xˉT))−1(X−xˉT)T(y−yˉ)(公式11)b∗=xˉTw∗−yˉ(公式12)\boldsymbol{w}^*=((\boldsymbol{X}-\boldsymbol{\bar{x}}^T)^T(\boldsymbol{X}-\boldsymbol{\bar{x}}^T))^{-1}(\boldsymbol{X}-\boldsymbol{\bar{x}}^T)^T(\boldsymbol{y}-\bar{y})(公式11) \\ b^* = \boldsymbol{\bar{x}}^T\boldsymbol{w}^*-\bar{y}(公式12) w∗=((X−xˉT)T(X−xˉT))−1(X−xˉT)T(y−yˉ​)(公式11)b∗=xˉTw∗−yˉ​(公式12)

将样本数据(x,y)(x, y)(x,y)带入上面的公式11和公式12中即可求解出www和bbb的值,但是这种方法只对线性回归这样简单的任务有效。如果模型中含有非线性变换,或者损失函数不是均方差这种简单的形式,则很难通过上式求解。为了解决这个问题,下面我们将引入更加普适的数值求解方法:梯度下降法。

5.1 梯度下降法

**在现实中存在大量的函数正向求解容易,但反向求解较难,被称为单向函数,这种函数在密码学中有大量的应用。**密码锁的特点是可以迅速判断一个密钥是否是正确的(已知xxx,求yyy很容易),但是即使获取到密码锁系统,也无法破解出正确得密钥(已知yyy,求xxx很难)。

这种情况特别类似于一位想从山峰走到坡谷的盲人,他看不见坡谷在哪(无法逆向求解出LossLossLoss导数为0时的参数值),但可以伸脚探索身边的坡度(当前点的导数值,也称为梯度)。那么,求解Loss函数最小值可以这样实现:从当前的参数取值,一步步的按照下坡的方向下降,直到走到最低点。这种方法笔者称它为“盲人下坡法”。哦不,有个更正式的说法“梯度下降法”。

训练的关键是找到一组(w,b)(w, b)(w,b),使得损失函数LLL取极小值。我们先看一下损失函数LLL只随两个参数w5w_5w5​、w9w_9w9​变化时的简单情形,启发下寻解的思路。
L=L(w5,w9)(公式13)L=L(w_5, w_9) (公式13)L=L(w5​,w9​)(公式13)
这里将w0,w1,...,w12w_0, w_1, ..., w_{12}w0​,w1​,...,w12​中除w5,w9w_5, w_9w5​,w9​之外的参数和bbb都固定下来,可以用图画出L(w5,w9)L(w_5, w_9)L(w5​,w9​)的形式,并在三维空间中画出损失函数随参数变化的曲面图。

net = Network(13)
losses = []
#只画出参数w5和w9在区间[-160, 160]的曲线部分,以及包含损失函数的极值
w5 = np.arange(-160.0, 160.0, 1.0) #[-160,-159 , ... , 159],共320个数
w9 = np.arange(-160.0, 160.0, 1.0)
losses = np.zeros([len(w5), len(w9)])#计算设定区域内每个参数取值所对应的Loss
for i in range(len(w5)):for j in range(len(w9)):net.w[5] = w5[i]net.w[9] = w9[j]z = net.forward(x)loss = net.loss(z, y)losses[i, j] = loss#使用matplotlib将两个变量和对应的Loss作3D图
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = Axes3D(fig)# 生成网格点坐标矩阵
w5, w9 = np.meshgrid(w5, w9)# 绘制3D图,rstride(row)指定行的跨度,设置颜色映射
ax.plot_surface(w5, w9, losses, rstride=1, cstride=1, cmap='rainbow')
plt.show()

观察上述曲线呈现出“圆滑”的坡度,这正是我们选择以均方误差作为损失函数的原因之一。图6 呈现了只有一个参数维度时,均方误差和绝对值误差(只将每个样本的误差累加,不做平方处理)的损失函数曲线图。


图6:均方误差和绝对值误差损失函数曲线图

由此可见,均方误差表现的“圆滑”的坡度有两个好处:

  • 曲线的最低点是可导的。
  • 越接近最低点,曲线的坡度逐渐放缓,有助于通过当前的梯度来判断接近最低点的程度(是否逐渐减少步长,以免错过最低点)。

现在我们要找出一组[w5,w9][w_5, w_9][w5​,w9​]的值,使得损失函数最小,实现梯度下降法的方案如下:

  • 步骤1:随机的选一组初始值,例如:[w5,w9]=[−100.0,−100.0][w_5, w_9] = [-100.0, -100.0][w5​,w9​]=[−100.0,−100.0]
  • 步骤2:选取下一个点[w5′,w9′][w_5^{'} , w_9^{'}][w5′​,w9′​],使得L(w5′,w9′)<L(w5,w9)L(w_5^{'} , w_9^{'}) < L(w_5, w_9)L(w5′​,w9′​)<L(w5​,w9​)
  • 步骤3:重复步骤2,直到损失函数几乎不再下降。

如何选择[w5′,w9′][w_5^{'} , w_9^{'}][w5′​,w9′​]是至关重要的,第一要保证LLL是下降的,第二要使得下降的趋势尽可能的快。微积分的基础知识告诉我们:**沿着梯度的反方向,是函数值下降最快的方向。**简单理解,函数在某一个点的梯度方向是曲线斜率最大的方向,但梯度方向是向上的,所以下降最快的是梯度的反方向。

5.2 梯度计算

上文已经介绍了损失函数的计算方法,这里稍微改写。为了使梯度计算更加简洁,引入因子12\frac{1}{2}21​,定义损失函数如下:

L=12N∑i=1N(yi−zi)2(公式14)L= \frac{1}{2N}\sum_{i=1}^N{(y_i - z_i)^2} (公式14) L=2N1​i=1∑N​(yi​−zi​)2(公式14)
其中ziz_izi​是网络对第iii个样本的预测值:

zi=∑j=012xij⋅wj+b(公式15)z_i = \sum_{j=0}^{12}{x_i^{j}\cdot w_j} + b (公式15) zi​=j=0∑12​xij​⋅wj​+b(公式15)
梯度的定义:

1.1 波士顿房价预测相关推荐

  1. 机器学习(11)线性回归(2)实战 -- 正规方程优化、梯度下降优化(波士顿房价预测)

    目录 一.波士顿房价预测(正规方程优化) API 1.获取数据集 2.划分数据集 3.标准化 4. 创建预估器,得到模型 5.模型评估(均方差评估) 代码 二.波士顿房价预测(正规方程优化) API ...

  2. 竞赛大杀器xgboost,波士顿房价预测

    经常出入DC竞赛.kaggle.天池等大数据比赛的同学应该很了解xgboost这座大山. 几乎所有的比赛都绕不过它,可能只需要这一个库,在比赛中就可以得到很高的分数,究竟是为什么呢?那么就来窥探一下它 ...

  3. 线性回归之案例:波士顿房价预测

    线性回归之案例:波士顿房价预测 数据介绍   [13个特征值,1个目标值] 给定的这些特征,是专家们得出的影响房价的结果属性.此阶段不需要自己去探究特征是否有用,只需要使用这些特征.到后面量化很多特征 ...

  4. 【深度学习】实战Kaggle竞赛之线性模型解决波士顿房价预测问题(Pytorch)

    [深度学习]实战Kaggle竞赛之线性模型解决波士顿房价预测问题 文章目录 1 概述1.1 Competition Description1.2 Practice Skills 2 数据处理 3 训练 ...

  5. kaggle房价预测特征意思_Kaggle实战-波士顿房价预测

    本文数据集来自Kaggle波士顿房价预测项目https://www.kaggle.com/c/house-prices-advanced-regression-techniques/data 1.数据 ...

  6. 教你使用百度深度学习框架PaddlePaddle完成波士顿房价预测(新手向)

    首先,本文是一篇纯新手向文章,我自己也只能算是入门,有说错的地方欢迎大家批评讨论 目录 一.人工智能.机器学习.深度学习 二.PaddlePaddle(飞桨) 三.波士顿房价预测模型 数据处理 模型设 ...

  7. PaddlePaddle实现波士顿房价预测

    PaddlePaddle实现波士顿房价预测 AIStudio地址 Github地址 #加载飞桨.Numpy 和相关库 import paddle import paddle.fluid as flui ...

  8. 深度学习入门——波士顿房价预测

    基于神经网络模型的波士顿房价预测 波士顿房价预测是一个经典的机器学习任务,类似于程序员世界的"Hello World".以"波士顿房价预测"任务为例,我们学习如 ...

  9. 使用Python和Numpy进行波士顿房价预测任务(二)【深度学习入门_学习笔记】

    使用Python和Numpy进行波士顿房价预测任务–详解 目录: 一.数据处理 (1)读入数据 (2)数据形状变换 (3)数据集划分 (4)数据归一化处理 (5)封装成load data函数 二.模型 ...

  10. 使用Python和Numpy进行波士顿房价预测任务(一)【深度学习入门_学习笔记】

    波士顿房价预测是一个经典的机器学习任务,类似于程序员世界的"Hello World".和大家对房价的普遍认知相同,波士顿地区的房价是由诸多因素影响的. 下载数据集:https:// ...

最新文章

  1. python读取中文文件报错-Python3 解决读取中文文件txt编码的问题
  2. Sentinel-Dashboard 与 apollo 规则的相互同步
  3. if __name__ == __main__:什么意思_好冷的Python if __name__==__main__是啥东东
  4. flink Datastream组装
  5. TSQL--查找连续登陆用户
  6. tracepro杂散光分析例子_2020临中高考咨询群咨询成效问卷结果分析
  7. pythonpdf识别文字软件_如何使用Python进行PDF图片识别OCR
  8. 怎样利用超图客户端打点_SuperMap iClient 7C - 网络客户端GIS开发平台
  9. app上架小米应用商店流程
  10. 小刘的刷题日记——day1 【CSES】Weird Algorithm
  11. javascript飞机大战
  12. Starbound正式版的Mod制作(二)nbsp;…
  13. JavaScript完成简单的对联广告
  14. Where are Docker images stored? (杂译)
  15. 基于STM32F103的液晶显示电子钟
  16. Flutter从0到1自定义日历
  17. 妖人柴:都移动互联网时代了,为什么还要建网站?
  18. 23模式--建造者模式
  19. 自己动手写油猴脚本 - 简单优化微信读书网页版阅读体验
  20. go内存分析工具介绍--pprof

热门文章

  1. k8s之Deployment滚动更新
  2. Nginx - 正向代理与反向代理的概念
  3. python可以做微信小游戏吗_python可以写微信小游戏吗
  4. 求职面试准备——自我介绍
  5. 华为5G手机全球第一,人均年薪69万!
  6. win10系统迁移后系统重装_Win10技巧:Windows 10系统迁移方法!
  7. 一文带你吃透黑盒测试跟白盒测试的区别
  8. NXP ZigBee JN5169 DimmerLight编译过程梳理
  9. 读计算机视觉综述做的脑图(11.09更新)
  10. win10如何做服务器双系统,双系统怎么做?Win7+Win10 双系统安装图文教程