卷积神经网络(CNN)

关注公众号“轻松学编程”了解更多。

一、简介

​ 卷积神经网络(Convolutional Neural Network,CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。 它包括卷积层(convolutional layer)和池化层(pooling layer)。

​ 卷积神经网络包括一维卷积神经网络、二维卷积神经网络以及三维卷积神经网络。

​ 一维卷积神经网络常应用于序列类的数据处理;

​ 二维卷积神经网络常应用于图像类文本的识别;

​ 三维卷积神经网络主要应用于医学图像以及视频类数据识别。

【参考:https://blog.csdn.net/ice_actor/article/details/78648780】

【参考:https://www.cnblogs.com/skyfsm/p/6790245.html】

二、几个概念

1、反向传播

​ 几个人站成一排第一个人看一幅画(输入数据),描述给第二个人(隐层)……依此类推,到最后一个人(输出)的时候,画出来的画肯定不能看了(误差较大)。
反向传播就是,把画拿给最后一个人看(求取误差),然后最后一个人就会告诉前面的人下次描述时需要注意哪里(权值修正)。

卷积神经网络也是这样,哪个特征参数对结果影响较大就增加它的权重,影响较小就减少它的权重,通过不断的反馈,找到一系列合适的权重系数。

2、什么是卷积

​ 卷积:convolution

​ 已有运算:加减乘除,幂运算指数运算
卷积:卷积也是一种运算
【参考:https://www.zhihu.com/question/22298352?rf=21686447】

####2.1 卷积运算

​ 卷积操作是使用一个二维的卷积核在一个批处理的图片上进行不断扫描。具体操作是将一个卷积核在每张图片上按照一个合适的尺寸在每个通道上面进行扫描。
卷积的过程:如下图所示,用一个3*3的卷积核在5*5的图像上做卷积的过程

在三通道图像上的卷积过程,如下:

计算步骤如下
计算步骤解释如下,原图大小为7*7,通道数为3:,卷积核大小为3*3;

Input Volume中的蓝色方框和Filter W0中红色方框的对应位置元素相乘再求和得到res(即,下图中的步骤1.res的计算),

再把res和Bias b0进行相加(即,下图中的步骤2),

得到最终的Output Volume

两个卷积核就有两个输出。

2.2 卷积函数

如下:卷积函数tf.nn.conv2d

  • 第一个参数:input

    • input就是需要做卷积的图像(这里要求用Tensor来表示输入图像,并且Tensor(一个4维的Tensor,要求类型为float32)的shape为**[batch, in_height, in_width, in_channels]**
    • 具体含义[训练时一个batch图像的数量,图像高度,图像宽度, 图像通道数])
      第二个参数:filter
    • filter就是卷积核(这里要求用Tensor来表示卷积核,并且Tensor(一个4维的Tensor,要求类型与input相同)的shape为**[filter_height, filter_width, in_channels, out_channels]**
    • 具体含义[卷积核高度,卷积核宽度,数据(图像)通道数,卷积核个数],这里的图片通道数也就input中的图像通道数,二者相同。)
  • 第三个参数:strides
    • strides就是卷积操作时在图像每一维的步长,strides是一个长度为4的一维向量
      第四个参数:padding
    • padding是一个string类型的变量,只能是 “SAME” 或者 “VALID”,决定了两种不同的卷积方式。
      下面我们来介绍 “SAME” 和 “VALID” 的卷积方式,如下图我们使用单通道的图像,图像大小为5*5,卷积核用3*3
      • 'VALID’表示有效的,输出的图像会变小(取中间的矩阵)。红色#表示卷积核中心点在图像上的滑动过程。最后得到3*3的图像大小

  • ‘SAME’ 表示相同的,输出的图像和原来一样。首先在原图外层补一圈0,将原图的第一点作为卷积核中心,若一圈0不够,继续补一圈0

  • 第五个参数:use_cudnn_on_gpu

    • 使用GPU来运行(效率更高)
  • 第六个参数:data_format
    • data_format就是input的Tensor格式,一般默认就可以了。都采用NHWC
  • 第七个参数:name
    • 就是用以指定该操作的name,仅此而已。

3、卷积构造方法

3.1 激活函数

​ 在神经网络中,激活函数的作用是能够给神经网络加入一些非线性因素,使得神经网络可以更好地解决较为复杂的问题。
在神经网络中,有很多的非线性函数来作为激活函数,比如连续的平滑非线性函数(sigmoid,tanh和softplus),连续但不平滑的非线性函数(relurelu6relu_x)和随机正则化函数(dropout)
所有的激活函数都是单独应用在每个元素上面的,并且输出张量的维度和输入张量的维度一样(即不改变输入数组的形状)。

  • tf.nn.relu(features, name = None)

    • 这个函数的作用是计算激活函数relu,即max(features, 0)

当输入值小于或等于0时置为0,大于0时保持原状。

  • tf.nn.relu6(features, name = None)

    • 这个函数的作用是计算激活函数relu6,即min(max(features, 0), 6)

  • tf.nn.softplus(features, name = None)

    • 这个函数的作用是计算激活函数softplus,即log( exp( features ) + 1)

  • tf.sigmoid(x, name = None)

    • 这个函数的作用是计算 x 的 sigmoid 函数。具体计算公式为 y = 1 / (1 + exp(-x))

  • tf.tanh(x, name = None)

    • 这个函数的作用是计算 x 的 tanh 函数。具体计算公式为 ( exp(x) - exp(-x) ) / ( exp(x) + exp(-x) )

3.2 Dropout

​ 当训练数据量比较小时,可能会出现因为追求最小差值导致训练出来的模型极度符合训练集,但是缺乏普适性(即泛化能力低),不能表达训练数据之外的数据。

本来有普适性的模型被训练成了具有训练集特殊性,即回归曲线应该是黑色的线,由于追求最小差值导致回归曲线是红色虚线。

以至于对于真实的数据产生了错误:

解决方案:

  • tf.nn.dropout(x, keep_prob, noise_shape = None, seed = None, name = None)

    • 这个函数的作用是计算神经网络层的dropout。
    • 一个神经元将以概率keep_prob决定是否放电,如果不放电,那么该神经元的输出将是0;
    • 如果该神经元放电,那么该神经元的输出值将被放大到原来的1/keep_prob倍。
    • 这里的放大操作是为了保持神经元输出总个数不变。比如,神经元的值为[1, 2],keep_prob的值是0.5,并且是第一个神经元是放电的,第二个神经元不放电,那么神经元输出的结果是[2, 0],也就是相当于,第一个神经元被当做了1/keep_prob个输出,即2个。这样保证了总和2个神经元保持不变
    • tf.nn.dropout是TensorFlow里面为了防止或减轻过拟合而使用的函数,它一般用在全连接层
    • Dropout就是在不同的训练过程中随机扔掉一部分神经元。也就是让某个神经元的激活值以一定的概率p,让其停止工作,这次训练过程中不更新权值,也不参加神经网络的计算。但是它的权重得保留下来(只是暂时不更新而已),因为下次样本输入时它可能又得工作了。如下图所示:

3.3 卷积层

​ 卷积操作是使用一个二维的卷积核在一个批处理的图片上进行不断扫描。具体操作是将一个卷积核在每张图片上按照一个合适的尺寸在每个通道上面进行扫描。
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
这个函数的作用是对一个四维的输入数据 input 和四维的卷积核 filter 进行操作,然后对输入数据进行一个二维的卷积操作,最后得到卷积之后的结果
tf.nn.bias_add(value, bias, name = None):这个函数的作用是将偏差项 bias 加到 value 上面。

3.4 池化层

​ 池化操作是利用一个矩阵窗口在输入张量上进行扫描,并且将每个矩阵窗口中的值通过取最大值,平均值或者XXXX来减少元素个数
Maxpooling 就是在这个区域内选出最能代表边缘的值,然后丢掉那些没多大用的信息(保留最符合的特征)。
tf.nn.max_pool(value, ksize, strides, padding, name=None):
这个函数的作用是计算池化区域中元素的最大值。

  • 参数value:需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape

  • 参数ksize:池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1

  • 参数strides:和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride,stride, 1]

  • 参数padding:和卷积类似,可以取’VALID’ 或者’SAME’。

  • 返回一个Tensor,类型不变,shape仍然是[batch, height, width, channels]这种形式。

3.5 图例

##三、卷积对图像去噪处理

1、平滑均值滤波

卷积核为:

导包
import matplotlib.pyplot as plt
%matplotlib inline import numpy as np import tensorflow as tf
获取图片
moon = plt.imread('./img/moonlanding.png')
plt.figure(figsize=(8,8))
plt.imshow(moon,cmap='gray')

moon.shape

图像转为4维Tensor
# 转成一个一个4维的Tensor,数据类型为tf.float32
# [训练时一个batch图像的数量,图像高度,图像宽度, 图像通道数]
moon2 = moon.reshape(1,474,630,1)
moon2 = tf.constant(moon2,dtype=tf.float32)
设置卷积核
# 卷积核
# 使用平滑均值滤波
# 转成一个一个4维的Tensor,数据类型为tf.float32
# [卷积核高度,卷积核宽度,图像通道数,卷积核个数] filter_arg = np.array([1/9]*9).reshape(3,3,1,1) filter_arg = tf.constant(filter_arg,dtype=tf.float32)
卷积运算
#卷积处理
# input,filter,strides,padding
conv_moon = tf.nn.conv2d(
moon2, #输入的图像数组
filter_arg, #卷积核
strides=[1,1,1,1], # 步长
padding='SAME' # 输出形状
)
显示滤波后的图片
with tf.Session() as sess:
conv_moon = sess.run(conv_moon)
print(conv_moon.shape) plt.figure(figsize=(8,8))
plt.imshow(conv_moon.reshape(474,630),cmap='gray')

平滑均值滤波后,噪点与附近的像素点做了一个均值化处理,所以它们的像素值高的被拉低,低的被拉高,最后保持在同一水平线上,所以图像会变模糊,这个卷积核虽然可以对抗噪声,但是它牺牲了图像整体的边缘的清晰度。

###2、高斯平滑滤波
卷积核:

#使用高斯平滑
filter_arg_Gaus = np.array([1/16,2/16,1/16,
2/16,4/16,2/16,
1/16,2/16,1/16]).reshape(3,3,1,1) filter_arg_Gaus = tf.constant(filter_arg_Gaus,dtype=tf.float32) #卷积处理
# input,filter,strides,padding
conv_moon_Gaus = tf.nn.conv2d(
moon2, #输入的图像数组
filter_arg_Gaus, #卷积核
strides=[1,1,1,1], # 步长
padding='SAME' # 输出形状
) with tf.Session() as sess:
conv_moon_Gaus = sess.run(conv_moon_Gaus)
print(conv_moon_Gaus.shape) plt.figure(figsize=(8,8))
plt.imshow(conv_moon_Gaus.reshape(474,630),cmap='gray')

高斯平滑的水平和垂直方向呈现高斯分布,更突出了中心点在像素平滑后的权重,相比于均值滤波而言,有着更好的平滑效果。

四、卷积对图片风格化处理

1、浮雕

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
%matplotlib inline
flower = plt.imread('./img/flower.png')
plt.imshow(flower)
plt.axis('off')

flower.shape

图像的高是332,宽是444,图像通道数为3.

# 转成一个一个4维的Tensor,数据类型为tf.float32
# [训练时一个batch图像的数量,图像高度,图像宽度, 图像通道数]
flower_input = flower.reshape(1,332,444,3)
flower_input = tf.constant(flower_input,dtype=tf.float32)
# 卷积核
# 使用不同的卷积核,图片处理效果会不一样
#浮雕
# 转成一个一个4维的Tensor,数据类型为tf.float32
# [卷积核高度,卷积核宽度,图像通道数,卷积核个数]
filter_arg_relievo = tf.constant(np.array([
[-1,-1, 0],
[-1, 0, 1],
[ 0, 1, 1]
]*3).reshape(3,3,3,1),
dtype=tf.float32) #卷积运算
cnn_flower = tf.nn.conv2d(flower_input,
filter_arg_relievo,
strides=[1,1,1,1],
padding='SAME'
)
#绘图
with tf.Session() as sess:
cnn_flower = sess.run(cnn_flower)
print(cnn_flower.shape)
plt.imshow(cnn_flower.reshape(332,444),cmap='gray')
plt.axis('off')

2、强调边缘

# 卷积核
# 使用不同的卷积核,图片处理效果会不一样
# 强调边缘
# 转成一个一个4维的Tensor,数据类型为tf.float32
# [卷积核高度,卷积核宽度,图像通道数,卷积核个数]
filter_arg_strong_edge = tf.constant(np.array([
[1, 1, 1],
[1,-7, 1],
[1, 1, 1]
]*3).reshape(3,3,3,1),
dtype=tf.float32) #卷积运算
cnn_flower = tf.nn.conv2d(flower_input,
filter_arg_strong_edge,
strides=[1,1,1,1],
padding='SAME'
) with tf.Session() as sess:
cnn_flower = sess.run(cnn_flower)
print(cnn_flower.shape)
plt.imshow(cnn_flower.reshape(332,444),cmap='gray')
plt.axis('off')

3、保持原样

# 卷积核
# 使用不同的卷积核,图片处理效果会不一样
# 保持原样
# 转成一个一个4维的Tensor,数据类型为tf.float32
# [卷积核高度,卷积核宽度,图像通道数,卷积核个数]
filter_arg_original = tf.constant(np.array([
[0, 0, 0],
[0, 1, 0],
[0, 0, 0]
]*3).reshape(3,3,3,1),
dtype=tf.float32) #卷积运算
cnn_flower = tf.nn.conv2d(flower_input,
filter_arg_original,
strides=[1,1,1,1],
padding='SAME'
) with tf.Session() as sess:
cnn_flower = sess.run(cnn_flower)
print(cnn_flower.shape)
plt.imshow(cnn_flower.reshape(332,444),cmap='gray')

4、边缘检测

# 卷积核
# 使用不同的卷积核,图片处理效果会不一样
# 边缘检测
# 转成一个一个4维的Tensor,数据类型为tf.float32
# [卷积核高度,卷积核宽度,图像通道数,卷积核个数]
filter_arg_edge_check = tf.constant(np.array([
[-1,-1,-1],
[-1 ,9,-1],
[-1,-1,-1]
]*3).reshape(3,3,3,1),
dtype=tf.float32) #卷积运算
cnn_flower = tf.nn.conv2d(flower_input,
filter_arg_edge_check,
strides=[1,1,1,1],
padding='SAME'
) with tf.Session() as sess:
cnn_flower = sess.run(cnn_flower)
print(cnn_flower.shape)
plt.imshow(cnn_flower.reshape(332,444),cmap='gray')
plt.axis('off')

5、其它效果

# 卷积核
# 使用不同的卷积核,图片处理效果会不一样
# 其它效果
# 转成一个一个4维的Tensor,数据类型为tf.float32
# [卷积核高度,卷积核宽度,图像通道数,卷积核个数]
filter_arg_edge_check = tf.constant(np.array([[-1,-1,-1,-1,-1],
[-1,-1,-1,-1,-1],
[-1,-1,8,-1,-1],
[-1,-1,-1,-1,-1],
[-1,-1,-1,-1,-1]
]*3).reshape(5,5,3,1),
dtype=tf.float32) #卷积运算
cnn_flower = tf.nn.conv2d(flower_input,
filter_arg_edge_check,
strides=[1,1,1,1],
padding='SAME'
) with tf.Session() as sess:
cnn_flower = sess.run(cnn_flower)
print(cnn_flower.shape)
plt.imshow(cnn_flower.reshape(332,444),cmap='gray')
plt.axis('off')

五、CNN识别手写数字

导包

import numpy as np
import tensorflow as tf #导入手写数字数据集
from tensorflow.examples.tutorials.mnist import input_data

获取数据

mnist = input_data.read_data_sets('./data/',one_hot=True)

声明权重、卷积、池化操作

#声明方法
#系数
def gen_w(shape):
# 正态分布随机数
v = tf.random_normal(shape,stddev=0.1)
return tf.Variable(v,dtype=tf.float32) # 截距
def gen_b(shape):
v = tf.constant(0.1,shape=shape)
return tf.Variable(v,dtype=tf.float32) # 卷积操作
def gen_conv(X,filter_arg):
# 返回数据的形状和X一样
return tf.nn.conv2d(X,filter_arg,
strides=[1,1,1,1],padding='SAME') # 池化代码,进一步抽取特征
def gen_pool(conv):
#ksize = [1, height, width, 1]
return tf.nn.max_pool(value=conv,ksize=[1,2,2,1],
strides=[1,2,2,1],
padding='SAME')

声明X,y变量

x = tf.placeholder(dtype=tf.float32,shape = [None,784])
y = tf.placeholder(dtype=tf.float32,shape = [None,10])

第一层卷积

# 声明卷积核:[卷积核高度,卷积核宽度,图像通道数,卷积核个数]
#有32个卷积核就有32个输出 W_conv_1 = gen_w([5,5,1,32])
#偏置项(截距)
b_conv_1 = gen_b([32]) # 卷积的input形状[训练时一个batch图像的数量,图像高度,图像宽度, 图像通道数]
#最后一维代表图片的颜色通道数(因为是灰度图所以这里的通道数为1
#如果是rgb彩色图,则为3
# -1表示图像的数量待定
x_image = tf.reshape(X,[-1,28,28,1]) #把x_image和权值向量进行卷积,加上偏置项
#然后应用ReLU激活函数,最后进行max pooling。
conv_1 = tf.nn.relu(gen_conv(x_image,W_conv_1) + b_conv_1)
#池化
pool_1 = gen_pool(conv_1)
# pool_1 .shape = (-1,14,14,32)

第一层卷积后输出结果形状为(-1,14,14,32)。

第二层卷积

# 为了构建一个更深的网络,我们会把几个类似的层堆叠起来。
#第二层中,每个5x5的patch会得到64个特征。 W_conv_2 = gen_w([5,5,32,64])
b_conv_2 = gen_b([64])
# 激活函数 不改变数组形状
conv_2 = tf.nn.relu(gen_conv(pool_1,W_conv_2) + b_conv_2)
pool_2 = gen_pool(conv_2)
# pool_2 .shape = (-1,7,7,64)

第一层卷积后输出结果形状为(-1,7,7,64)。

全连接层

'''现在,图片尺寸减小到7x7,我们加入一个有1024个神经元的全连接层,
用于处理整个图片。
我们把池化层输出的张量reshape成一些向量,
乘上权重矩阵,加上偏置,
然后对其使用ReLU。''' W_full = gen_w([7*7*64,1024])
b_full = gen_b([1024]) pool_full = tf.reshape(pool_2,[-1,7*7*64])
full_conn = tf.nn.relu(tf.matmul(pool_full,W_full) + b_full)
# full_conn.shape = (-1,1024)

第一层卷积后输出结果形状为(-1,1024)。

为了减少过拟合,在输出层之前加入dropout

'''我们用一个placeholder来代表一个神经元的输出在dropout中保持不变的概率
这样我们可以在训练过程中启用dropout,
在测试过程中关闭dropout。''' keep_prob = tf.placeholder(tf.float32)
full_conn_drop = tf.nn.dropout(full_conn,keep_prob)

输出层

# 输出层[[10个概率],[10个概率],[概率]……].shape = (-1,10)
# (-1,1024)-------> (-1,10)
W_full_2 = gen_w([1024,10])
b_full_2 = gen_b([10]) #创建线性模型并计算概率分布
pred = tf.nn.softmax(tf.matmul(full_conn_drop,W_full_2) + b_full_2)

训练和评估模型

'''在feed_dict中加入额外的参数keep_prob来控制dropout比例。
然后每100次迭代输出一次日志。
'''
#损失函数 交叉熵
cost = -tf.reduce_sum(y*tf.log(pred))
#梯度下降优化器optimizer 获取最小交叉熵
optimizer = tf.train.AdamOptimizer(1e-4).minimize(cost) #计算准确率
correct_prediction = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32)) with tf.Session() as sess: sess.run(tf.initialize_all_variables()) # 训练20000次
for i in range(2000):
# 每次训练取100个样本
X_train,y_train = mnist.train.next_batch(50) opt,cost_ = sess.run([optimizer,cost],
feed_dict={
X:X_train,
y:y_train,
keep_prob:0.5
}
)
# 每100次输出一次日志
if i%100 == 0:
accu = sess.run(accuracy,
feed_dict={X:mnist.test.images[:1000],
y:mnist.test.labels[:1000],
keep_prob:1
}
)
print('训练次数%d,损失cost:%0.4f,准确率:%0.4f'%(i,cost_,accu))

可以看到训练500次时,准确率就达到92%了,使用卷积神经网络随着训练次数的增加,模型准确率就会增高。但是缺点就是很耗时。

后记

【后记】为了让大家能够轻松学编程,我创建了一个公众号【轻松学编程】,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。

也可加我微信【1257309054】,拉你进群,大家一起交流学习。
如果文章对您有帮助,请我喝杯咖啡吧!

公众号

关注我,我们一起成长~~

python机器学习卷积神经网络(CNN)的更多相关文章

  1. 写给程序员的机器学习入门 (八) - 卷积神经网络 (CNN) - 图片分类和验证码识别

    这一篇将会介绍卷积神经网络 (CNN),CNN 模型非常适合用来进行图片相关的学习,例如图片分类和验证码识别,也可以配合其他模型实现 OCR. 使用 Python 处理图片 在具体介绍 CNN 之前, ...

  2. 卷积神经网络CNN总结

    从神经网络到卷积神经网络(CNN)我们知道神经网络的结构是这样的: 那卷积神经网络跟它是什么关系呢?其实卷积神经网络依旧是层级网络,只是层的功能和形式做了变化,可以说是传统神经网络的一个改进.比如下图 ...

  3. 【深度学习系列】手写数字识别卷积神经--卷积神经网络CNN原理详解(一)

    上篇文章我们给出了用paddlepaddle来做手写数字识别的示例,并对网络结构进行到了调整,提高了识别的精度.有的同学表示不是很理解原理,为什么传统的机器学习算法,简单的神经网络(如多层感知机)都可 ...

  4. 【深度学习系列】卷积神经网络CNN原理详解(一)——基本原理

    上篇文章我们给出了用paddlepaddle来做手写数字识别的示例,并对网络结构进行到了调整,提高了识别的精度.有的同学表示不是很理解原理,为什么传统的机器学习算法,简单的神经网络(如多层感知机)都可 ...

  5. TensorFlow 2.0 深度学习实战 —— 浅谈卷积神经网络 CNN

    前言 上一章为大家介绍过深度学习的基础和多层感知机 MLP 的应用,本章开始将深入讲解卷积神经网络的实用场景.卷积神经网络 CNN(Convolutional Neural Networks,Conv ...

  6. 深度学习之卷积神经网络(CNN)详解与代码实现(二)

    用Tensorflow实现卷积神经网络(CNN) 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/10737065. ...

  7. 深度学习之卷积神经网络(CNN)详解与代码实现(一)

    卷积神经网络(CNN)详解与代码实现 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/10430073.html 目 ...

  8. 基于MNIST数据的卷积神经网络CNN

    基于tensorflow使用CNN识别MNIST 参数数量:第一个卷积层5x5x1x32=800个参数,第二个卷积层5x5x32x64=51200个参数,第三个全连接层7x7x64x1024=3211 ...

  9. 深度学习之卷积神经网络CNN及tensorflow代码实现示例

    深度学习之卷积神经网络CNN及tensorflow代码实现示例 2017年05月01日 13:28:21 cxmscb 阅读数 151413更多 分类专栏: 机器学习 深度学习 机器学习   版权声明 ...

随机推荐

  1. PyCharm-缩进 格式化代码

    格式化代码 Ctrl + Alt + l 缩进代码 Tab    向右缩进4格 Shift + Tab 向左缩进4格

  2. NN相关资源(持续更新)

    Iris数据介绍 http://www.cnblogs.com/Belter/p/8831216.html

  3. unity 3d 三、空间与运动

    3D游戏编程第三次作业 简答并用程序验证[建议做] 游戏对象运动的本质是什么? 游戏对象运动的本质是游戏对象Position.Rotate.Scale属性数值的变化. 请用三种方法以上方法,实现物体的 ...

  4. 025 01 Android 零基础入门 01 Java基础语法 03 Java运算符 05 if条件结构

    025 01 Android 零基础入门 01 Java基础语法 03 Java运算符 05 if条件结构 本文知识点:Java中的if条件结构语句 关系运算符回顾 生活中根据条件进行判断采取不同操作 ...

  5. TP5本地运行正常,线上运行某页面出现【模板文件不存在】问题的解决办法

    相信许多小伙伴和我一样,明明在本地运行页面一切正常,而到线上(本人是用的虚拟主机)出现了如下图的问题: 其实这个问题出现的原因很简单,就是我们开发是在windows 系统下,windows系统对大小写 ...

  6. Docker笔记1:Docker 的介绍

    目  录 1.Docker 简介 2.Docker 特性 3.Docker 应用场景 4.Docker 优点 1.Docker 简介     Docker 提供了一个可以运行你的应用程序的封套(env ...

  7. 《流畅的Python》第三部分 把函数视作对象 【一等函数】【使用一等函数实现设计模式】【函数装饰器和闭包】

    第三部分 第5章 一等函数 一等对象 在运行时创建 能赋值给变量或数据结构中的元素 能作为参数传递给函数 能作为函数的返回结果 在Python中,所有函数都是一等对象 函数是对象 函数本身是 func ...

  8. OpenSSL加密系统简介

    加密基本原理 OpenSSL移植到arm开发板参考  http://blog.chinaunix.net/uid-27717694-id-3530600.html 1.公钥和私钥: 公钥和私钥就是俗称 ...

  9. Kibana基础之直接操作ElasticSearch

    1.入门级别操作 Elasticsearch采用Rest风格API,其API就是一次http请求,你可以用任何工具发起http请求 创建索引的请求格式: 请求方式:PUT 请求路径:/索引库名 请求参 ...

  10. Jenkins集成appium自动化测试(Windows篇)

    一,引入问题 自动化测试脚本绝大部分用于回归测试,这就需要制定执行策略,如每天.代码更新后.项目上线前定时执行,才能达到最好的效果,这时就需要进行Jenkins集成. 不像web UI自动化测试可以使 ...