一、深度学习 vs 深层神经网络

深度学习:一类通过多层非线性变换对高复杂性数据建模算法的集合。

1、激活函数

线性模型的最大特点:任意线性模型的组合仍是线性模型,能够解决的问题也是有限的,这就是线性模型最大的局限。

==》解决方法:激活函数实现去线性化
如果将前面提到的加权和节点后(注意:添加偏置项)通过一个非线性函数,那么神经网络模型就是非线性的了。这个非线性函数就是激活函数(activation)

常用激活函数:

  • ReLU函数—— tf.nn.relu
  • sigmoid函数——tf.nn.sigmoid
  • tanh函数——tf.nn.tanh

    使用激活函数和偏置项的前向传播。
# 前向传播
a = tf.nn.relu(tf.matmul(x, w1) + biases1)
y = tf.nn.relu(tf.matmul(a, w2) + biases2)

2、多层网络解决异或运算

二、损失函数

1、经典损失函数

(1)分类问题

交叉熵:两个概率分布之间的距离,广泛用于分类问题中。交叉熵是信息论中概念,原本用于估算平均编码的长度。

公式:
对于给定两个概率分布 ppp 和 qqq,通过 qqq 来表示 ppp 的交叉熵为:
H(p,q)=−∑xp(x)logq(x)H(p,q)=-\sum_{x}p(x)log\ q(x)H(p,q)=−x∑​p(x)log q(x)
注意:交叉熵不是对称的,H(p,q)≠H(q,p)H(p,q)\neq H(q,p)H(p,q)̸​=H(q,p),交叉熵刻画通过通过概率分布 qqq 来表示 ppp 的困难程度。所以, qqq 表示预测结果, ppp 表示ground-truth。
交叉熵刻画的是两个概率分布的距离,然而神经网络的输出不一定是一个概率分布(任意事件发生的概率都在0和1之间,且概率总和为1)。Softmax回归是一个常用的将前向传播结果变成概率分布的方法。

Softmax回归本身可以作为一个学习算法来优化分类结果,但在tf中,Softmax回归的参数被去掉了,只作为一个额外的处理层,将输出变成一个概率分布。
softmax(y)i=yi′=eyi∑j=1neyisoftmax(y)_i=y_i^\prime=\frac{e^{yi}}{\sum_{j=1}^{n}e^{yi}}softmax(y)i​=yi′​=∑j=1n​eyieyi​

交叉熵代码实现

cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))

因为交叉熵一般与Softmax回归一起使用,tf提供了 tf.nn.softmax_cross_entropy_with_logits 函数:

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)

(2)回归问题

回归问题目标:具体数值的预测问题。

均方误差(MSE, mean squared error)

公式:
MSE(y,y′)=∑i=1n(yi−yi′)2nMSE(y, y')=\frac{\sum_{i=1}^{n}(y_i-y_i')^2}{n}MSE(y,y′)=n∑i=1n​(yi​−yi′​)2​
其中,yiy_iyi​ 为一个 batch 中第 i 个数据的正确答案,yi′y_i'yi′​ 为预测值

tf 实现:

mse = tf.reduce_mean(tf.square(y_ - y))

2、自定义损失函数

为了让神经网络优化的结果更加接近实际问题,我们需要自定义损失函数。

比如商品销量问题,如果预测值较大(大于真实销量),商家损失生产商品的成本。如果预测值较小,损失商品的利润。因为一般成本和利润不相同,使用均方误差不能够很好地最大化利润。比如成本是1元,利润是10元,那么模型应该偏向预测值较大。下面的公式给出了预测值多于或少于真实值时有不同系数的损失函数,通过这个损失函数,模型可能最大化收益。
Loss(y,y′)=∑i=1nf(yi,yi′),f(x,y)={a(x−y),if x>yb(y−x),if x≤yLoss(y,y')=\sum_{i=1}^{n}f(y_i,y_i'),f(x,y)=\begin{cases} a(x-y), & \text{if $x>y$} \\ b(y-x), & \text{if $x\leq y$ } \end{cases} Loss(y,y′)=i=1∑n​f(yi​,yi′​),f(x,y)={a(x−y),b(y−x),​if x>yif x≤y ​
注意:损失函数定义的是损失,所以要将利润最大化,定义的损失函数应该刻画成本或代价。

tf 实现

loss = tf.reduce_sum(tf.where(tf.greater(v1, v2), (v1 - v2) * a, (v2 - v1) * b))

整体代码

import tensorflow as tf
from numpy.random import RandomStatebatch_size = 8# 两个输入节点,一个输出节点
x = tf.placeholder(tf.float32, shape=(None, 2), name='x-input')
y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y-input')w1 = tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
y = tf.matmul(x, w1)# 定义预测多了的成本和预测少了的成本
loss_less = 10
loss_more = 1
loss = tf.reduce_mean(tf.where(tf.greater(y, y_), (y - y_) * loss_more, (y_ - y) * loss_less))train_step = tf.train.AdamOptimizer(0.001).minimize(loss)# 随机数生成一个模拟数据集
rdm = RandomState(1)
dataset_size = 128X = rdm.rand(dataset_size, 2)
Y = [[x1 + x2 + rdm.rand()/10.0 - 0.05] for (x1, x2) in X]with tf.Session() as sess:init_op = tf.global_variables_initializer()sess.run(init_op)STEPS = 5000for i in range(STEPS):start = (i * batch_size) % dataset_sizeend = min(start + batch_size, dataset_size)sess.run(train_step, feed_dict={x: X[start: end], y_: Y[start: end]})print(sess.run(w1))

输出

2019-03-09 15:21:02.100189: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-03-09 15:21:02.193850: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:897] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2019-03-09 15:21:02.194763: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1405] Found device 0 with properties:
name: GeForce GTX 1060 major: 6 minor: 1 memoryClockRate(GHz): 1.6705
pciBusID: 0000:01:00.0
totalMemory: 5.94GiB freeMemory: 5.37GiB
2019-03-09 15:21:02.194798: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1484] Adding visible gpu devices: 0
2019-03-09 15:21:02.422253: I tensorflow/core/common_runtime/gpu/gpu_device.cc:965] Device interconnect StreamExecutor with strength 1 edge matrix:
2019-03-09 15:21:02.422279: I tensorflow/core/common_runtime/gpu/gpu_device.cc:971]      0
2019-03-09 15:21:02.422285: I tensorflow/core/common_runtime/gpu/gpu_device.cc:984] 0:   N
2019-03-09 15:21:02.422603: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1097] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 5139 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1060, pci bus id: 0000:01:00.0, compute capability: 6.1)
[[1.0193471][1.0428091]]

三、神经网络优化算法

关键:通过反向传播算法(backpropagation)和梯度下降算法(Gradient Decent)调整神经网络中的参数。梯度下降算法主要用于优化单个参数的取值,而反向传播算法给出了一个高效的方式在所有参数上使用梯度下降算法。

1、优化过程

  • 前向传播阶段:通过前向传播算法计算得到预测值,并计算损失函数。
  • 反向传播阶段:计算损失函数对每一个参数的梯度,再根据梯度和学习率使用梯度下降算法更新每一个参数。更新公式如下:
    θn+1=θn−η∂∂θnJ(θn)\theta_{n+1}=\theta_n-\eta\frac{\partial}{\partial\theta_n}J(\theta_n)θn+1​=θn​−η∂θn​∂​J(θn​)
    其中,θ\thetaθ 表示需要更新的参数,∂\partial∂ 表示学习率,J(θn)J(\theta_n)J(θn​) 表示损失函数值

2、几个概念

  • 学习率
  • 局部最优
  • 随机梯度下降
  • mini-batch梯度下降:不会比单个数据慢太多,同时可以大大减小收敛所需的迭代次数,使得收敛到的结果更加接近梯度下降的效果。

3、神经网络训练模式

import tensorflow as tfbatch_size = nx = tf.placeholder(tf.float32, shape=(None, 2), name='x-input')
y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y-input')# 定义损失函数和优化算法
loss = ...
train_step = tf.train.AdamOptimizer(0.001).minimize(loss)# 训练神经网络
with tf.Session() as sess:# 初始化参数...# 迭代参数更新for i in range(STEPS):current_X, current_Y = ...sess.run(train_step, feed_dict={x: current_X, y_: current_Y})

四、进一步优化

1、学习率设置

通过指数缩减的方法设置梯度下降算法中的学习率,在 tf 中使用 tf.train.exponential_decay 函数实现。先使用较大的学习率快速得到一个比较优的解,随着迭代的继续逐步减少学习率,使得模型在训练后期更加稳定。它实现了以下代码的功能:

decayed_learning_rate = learning_rate * decay_rate * decay_rate ^ (global_step / decay_steps)

其中,decayed_learning_rate 为每一轮优化时使用的学习率,learning_rate 为设定的初始学习率,decay_rate 为衰减系数,decay_steps 为衰减速度。

tf.train.exponential_decay 可以通过设置参数staircase 选择不同的衰减方式,默认为 False,此时学习率衰减趋势如下图灰色曲线。当设置为 True 时,global_step/decay_steps 会被转化成整数,使得学习率成为一个阶梯函数,如黑色曲线。在这样的设置下,decay_steps 通常代表完整使用一遍训练数据所需要的迭代轮数,也就是总训练数据/一个batch的样本数。这样可以使得总训练数据中的每一个batch都使用相同的学习率,对模型产生相等的作用。当完整过完一遍训练数据时,学习率就减少一次。

tf 实现

import tensorflow as tfglobal_step = tf.Variable(0)# 通过exponential_decay函数生成学习率
learning_rate = tf.train.exponential_decay(0.1, grobal_step, 100, 0.96, staircase=True)# 使用指数衰减的学习率。在minimize中传入global_step参数,从而更新学习率
learning_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)

2、过拟合问题

(1)正则化

正则化的思想是在损失函数中加入刻画模型复杂程度的指标。所以一般优化的损失函数为 J(θ)+λR(w)J(\theta)+\lambda R(w)J(θ)+λR(w)。一般来说模型复杂度只由权重w决定,和偏置b无关。

常用正则化

  • L1正则化
    R(w)=∣∣w∣∣1=∑i∣wi∣R(w)=||w||_1=\sum_{i}|w_i|R(w)=∣∣w∣∣1​=i∑​∣wi​∣
  • L2正则化
    R(w)=∣∣w∣∣2=∑i∣wi2∣R(w)=||w||_2=\sum_{i}|w_i^2|R(w)=∣∣w∣∣2​=i∑​∣wi2​∣
  • 同时使用L1正则化和L2正则化
    R(w)=∣∣w∣∣2=∑iα∣wi∣+(2−α)wi2R(w)=||w||_2=\sum_{i}\alpha|w_i|+(2-\alpha)w_i^2R(w)=∣∣w∣∣2​=i∑​α∣wi​∣+(2−α)wi2​

L1正则化 会让参数变得更稀疏,可达到类似特征选择功能;而 L2正则 不会。其次,L1正则 的计算公式不可导,L2正则 可导。因为优化时需要计算损失函数的偏导数,所以对 L2正则 损失函数的优化要更加简洁。优化 L1正则 更加复杂,而且优化方法也有很多种。

TF 实现
带 L2 正则项的损失函数

w = tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1)
y = tf.matmul(x, w)# 损失函数包括:均方误差损失函数 + 正则化项
## lambda参数表示正则化的权重,w为需要计算正则化损失的参数
loss = tf.reduce_mean(tf.square(y_ - y)) + tf.contrib.layers.l2_regularizer(lambda)(w)
  • tf.contrib.layers.l2_regularizer:计算给定参数的L2正则化项的值;
  • tf.contrib.layers.l1_regularizer:计算L1正则化项的值。
weights = tf.constant([[1.0, -2.0], [-3.0, 4.0]])
with tf.Session() as sess:# 输出为(|1|+|-2|+|3|+|-4|)*0.5=5. 其中0.5为正则项的权重print(sess.run(tf.contrib.layers.l1_regularizer(0.5)(weights))# 输出为(1^2+(-2)^2+3^2+(-4)^2)/2*0.5=7.5。 其中0.5为正则项的权重print(sess.run(tf.contrib.layers.l2_regularizer(0.5)(weights))

当网络结构复杂后,利用集合(collection)计算损失函数。eg:计算一个 5 层神经网络带 L2 正则化的损失函数计算方法。

import tensorflow as tf# 获取一层神经网络边上的权重,并将这个权重的L2正则化损失加入“losses”的集合中
def get_weight(shape, lambda1):# 生成一个变量var = tf.Variable(tf.random_normal(shape), dtype=tf.float32)# add_to_collection函数将这个新生成变量的L2正则化损失项加入集合# 第一个参数:losses是集合的名字,第二个参数:要加入集合的内容tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambda1)(var))return varx = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))
batch_size = 8# 定义每一层网络中节点的个数
layer_dimension = [2, 10, 10, 10, 1]
# 定义网络的层数
n_layers = len(layer_dimension)# 这个变量维护前向传播时最深层的节点,开始的时候就是输入层
cur_layer = x
# 当前层的节点个数
in_dimension = layer_dimension[0]# 通过一个循环来生成5层的FC层
for i in range(1, n_layers):# layer_dimension[i] 为下一层的节点个数out_dimension = layer_dimension[i]# 生成当前层中权重的变量,并将这个变量的L2正则化损失加入计算图上的集合weight = get_weight([in_dimension, out_dimension], 0.001)bias = tf.Variable(tf.constant(0.1, shape=[out_dimension]))# ReLU activation functioncur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)# 进入下一层之前将下一层的节点个数更新为当前层节点的个数in_dimension = layer_dimension[i]# 定义前向传播的同时已经将所有的L2正则化损失加入图上的集合
# 这里只需要计算刻画模型在训练数据上表现的损失函数
mse_loss = tf.reduce_mean(tf.square(y_ - cur_layer))# 将均方误差损失加入到损失集合
tf.add_to_collection('losses', mse_loss)# get_collection 返回一个列表,该列表是所有这个集合中的元素。
# 在样例中,这些元素就是损失函数的不同部分,将它们加起来就可以得到最终的损失函数
loss = tf.add_n(tf.get_collection('losses'))

3、滑动平均模型

作用:在使用随机梯度下降算法训练网络时,可以使模型在测试数据上更健壮(robust)。

tf 的实现:tf.train.ExponentialMovingAverage

参数:

  • 衰减率(decay):该参数用于控制模型更新的速度。ExponentialMovingAverage 对每一个变量会维护一个影子变量(shadow_variable),这个影子变量的初始值就是相应变量的初始值,而每次运行变量更新时,影子变量的值会更新为:
    shadow_variable=decay×shadow_variable+(1−decay)×variableshadow\_variable=decay\times shadow\_variable + (1-decay)\times variableshadow_variable=decay×shadow_variable+(1−decay)×variable
    其中,shadow_variable为影子变量,variable为待更新的变量,decay为衰减率,衰减率越大模型越稳定。实际中,decay一般会设置非常接近1(eg: 0.999或0.9999)。

  • num_updates参数:为了在训练的前期更新得更快,通过设置num_updates参数来动态设置decay的大小。若初始化时提供num_updates参数,则衰减率为:
    min{decay,1+num_updates10+1+num_updates}min\{decay,\frac{1+num\_updates}{10+1+num\_updates}\}min{decay,10+1+num_updates1+num_updates​}

TF实现

import tensorflow as tf# 定义一个变量用于计算滑动平均,初始值为实数型的0
v1 = tf.Variable(0, dtype=tf.float32)
# step 变量模拟神经网络中迭代的轮数,可以用于控制衰减率
step = tf.Variable(0, trainable = False)# 定义一个滑动平均的类。初始化:衰减率(0.99)和控制衰减率的变量 step
ema = tf.train.ExponentialMovingAverage(0.99, step)
# 定义一个更新变量滑动平均的操作。
# 这里需要给定一个列表,每次执行这个操作时,这个列表中的变量都会被更新
maintain_averages_op = ema.apply([v1])
with tf.Session() as sess:# 初始化所有变量init_op = tf.global_variables_initializer()sess.run(init_op)# 通过ema.average(v1)获取滑动平均之后变量的取值。# 在初始化之后变量v1的值和v1的滑动平均都是0print(sess.run([v1, ema.average(v1)]))# output: [0.0, 0.0]# 更新变量v1的值到5sess.run(tf.assign(v1, 5))# 更新变量v1的值到5# 更新v1的滑动平均值。衰减率为min{0.99, (1+step)/(10+step)=0.1}=0.1,# 所以v1的滑动平均被更新为0.1*0+0.9*5=4.5sess.run(maintain_averages_op)print(sess.run([v1, ema.average(v1)]))# output: [5.0, 4.5]# 更新变量step的值到10000sess.run(tf.assign(step, 10000))# 更新变量v1的值到10sess.run(tf.assign(v1, 10))# 更新v1的滑动平均值。衰减率为min{0.99, (1+step)/(10+step)}=0.99,# 所以v1的滑动平均被更新为0.99*4.5+0.01*10=4.555sess.run(maintain_averages_op)print(sess.run([v1, ema.average(v1)]))# output: [10.0, 4.5549998]# 再次更新滑动平均值,得到的新滑动平均值为0.99*4.555+0.01*10 = 4.60945sess.run(maintain_averages_op)print(sess.run([v1, ema.average(v1)]))# Output: [10.0, 4.6094499]

输出结果

2019-03-13 22:50:23.313337: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-03-13 22:50:23.444235: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:897] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2019-03-13 22:50:23.445227: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1405] Found device 0 with properties:
name: GeForce GTX 1060 major: 6 minor: 1 memoryClockRate(GHz): 1.6705
pciBusID: 0000:01:00.0
totalMemory: 5.94GiB freeMemory: 5.38GiB
2019-03-13 22:50:23.445260: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1484] Adding visible gpu devices: 0
2019-03-13 22:50:24.216058: I tensorflow/core/common_runtime/gpu/gpu_device.cc:965] Device interconnect StreamExecutor with strength 1 edge matrix:
2019-03-13 22:50:24.216088: I tensorflow/core/common_runtime/gpu/gpu_device.cc:971]      0
2019-03-13 22:50:24.216096: I tensorflow/core/common_runtime/gpu/gpu_device.cc:984] 0:   N
2019-03-13 22:50:24.216673: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1097] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 5150 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1060, pci bus id: 0000:01:00.0, compute capability: 6.1)
[0.0, 0.0]
[5.0, 4.5]
[10.0, 4.555]
[10.0, 4.60945]
[Finished in 4.9s]

【TensorFlow】笔记2:深层神经网络相关推荐

  1. [DeeplearningAI笔记]改善深层神经网络_深度学习的实用层面1.10_1.12/梯度消失/梯度爆炸/权重初始化...

    觉得有用的话,欢迎一起讨论相互学习~Follow Me 1.10 梯度消失和梯度爆炸 当训练神经网络,尤其是深度神经网络时,经常会出现的问题是梯度消失或者梯度爆炸,也就是说当你训练深度网络时,导数或坡 ...

  2. 北京大学曹健——Tensorflow笔记 03 搭建神经网络

    透过vim ~/.vimrc 写入 set ts=4, set nu,保存退出来设定vim编辑器.自动换行,4个空格 计算图:只搭建神经网络,不运行运算,不计算结果. 上图中:x 为 1行,2列的张量 ...

  3. 北京大学曹健——Tensorflow笔记 07 卷积神经网络

                         

  4. [DeeplearningAI笔记]改善深层神经网络_优化算法2.1_2.2_mini-batch梯度下降法

    觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.1 mini-batch gradient descent mini-batch梯度下降法 我们将训练数据组合到一个大的矩阵中 \(X=\b ...

  5. 01.神经网络和深度学习 W4.深层神经网络

    文章目录 1. 深层神经网络 2. 前向传播和反向传播 3. 核对矩阵维数 4. 参数.超参数 参考: 吴恩达视频课 深度学习笔记 1. 深层神经网络 有的时候只有非常深的神经网络才能发挥作用. 但是 ...

  6. TensorFlow学习笔记——深层神经网络

    引言 TensorFlow 版本1.15pip3 install tensorflow==1.15.0. 这是<TensorFlow实战Google深度学习框架(第2版)>的学习笔记,所有 ...

  7. 02.改善深层神经网络:超参数调试、正则化以及优化 W3. 超参数调试、Batch Norm和程序框架(作业:TensorFlow教程+数字手势预测)

    文章目录 1. 探索TensorFlow库 1.1 线性函数 1.2 计算 sigmoid 1.3 计算损失函数 1.4 One_Hot 编码 1.5 用0,1初始化 2. 用TensorFlow建立 ...

  8. (tensorflow笔记)神经网络中的一些关键概念(学习率、激活函数、损失函数、欠拟合和过拟合、正则化和优化器)

    目录 1.神经网络复杂度 空间复杂度 时间复杂度 2.学习率策略 指数衰减学习率 分段常数衰减 3.激活函数 sigmoid tanh ReLU Leaky ReLU 建议 4.损失函数 均方误差损失 ...

  9. 人工智能实践:TensorFlow笔记学习(八)—— 卷积神经网络实践

    大纲 7.1  复现已有的卷积神经网络 7.2  用vgg16实现图片识别 目标 掌握复现已有网络,用vgg16实现图片识别 7.1  复现已有的卷积神经网络 VGGNet是Karen simonya ...

最新文章

  1. Emacs 使用YASnippet
  2. 01.ShardingSphere笔记
  3. 享学金三银四一线大厂面试专题学习笔记
  4. vb获取textbox数字_Spectrum仪器PCIe数字化仪可额外扩展8个数字输入
  5. Spark读写Hbase的二种方式对比
  6. OJ1000: A+B Problem
  7. SqlServer性能检测之Sql语句排查
  8. 建筑施工技术【14】
  9. 微信api中转站(用python搭建flask服务器)
  10. python实现小写金额转换成大写
  11. 人脸识别活体检测之眨眨眼和张张嘴
  12. 正圆锥体空间方程_计算机基础算法(一)——时间与空间复杂度
  13. xlsx表格怎么筛选重复数据_excel表格怎么筛选重复数据
  14. 历届试题 填字母游戏
  15. c语言中特殊符号怎么定义,C语言特殊符号意义
  16. 计算机键盘汉字,统一码计算机汉字键盘输入法
  17. 笔记本实现有线路由器功能
  18. SU-03T语音模块的使用(小智语音控制LED灯)
  19. thinkadmin V6 Experiences
  20. I.MX6Q(TQIMX6Q/TQE9)学习笔记——新版BSP之kernel移植

热门文章

  1. 「后端小伙伴来学前端了」Vue中全局事件总线(GlobalEventBus)原理及探究过程
  2. java jdk安装失败 mac_Mac javaJDK安装遇到的坑和环境变量配置2019-07-09.
  3. serverless 框架_Serverless计算这么强大
  4. 13-Qt6 QMap
  5. centos 安装ftp FileZilla
  6. lpop 原子_【concurrent】面试重灾区之原子操作你有必要了解下
  7. extmail mysql数据库 重启_centos 5.8 x86_64下安装mysql+postfix+extmail+extman+courier-authlib+courier-imap...
  8. iis php cgi.exe 漏洞,IIS4\IIS5 CGI环境块伪造0day漏洞
  9. java poi导入50万数据_java从oracle读取50万条数据写入Excel中抛GC overhead limit exc
  10. html简单的图片切换js,一分钟让你学会如何使用js切换图片