4.神经网络可以计算任何函数的可视化证明

神经网络拥有一定的普遍性,即包含一个隐藏层的神经网络可以被用来按照任意给定的精度来近似任何连续函数。

这一章使用一个实例来阐述神经网络是如何来近似一个一元函数,和一个二元函数,并扩展到一个多元的实值函数。

5.深度神经网络为何很难训练

这一章讲述了在深度网络中,不同的层学习的速度差异很大,尤其是,在网络中后面的层学习的情况很好的情况下,先前的层常常会在训练的时候停滞不变,基本学习不到东西。这根本的原因是因为我们学习的速度下降了,实际上,我们会发现在深度学习中使用基于梯度下降的学习方法本身存在着内在的不稳定性。这种不稳定使得先前或者后面的层学习过于阻滞。

我们研究一下神经网络学习阻滞的原因,借用书中的内容:

消失的梯度问题:当激活函数采用sigmoid函数时,反向传播计算会出现消失的梯度问题,主要是由于|σ('z)|<1/4,而且我们初始化权重ω采用μ(0,1)高斯分布,权重|ω|通常会小于1,导致前面的隐藏层中的神经元学习速度要慢于后面的隐藏层。

梯度激增的问题:如果我们权重初始化选择比较大话,并且σ('z)项不会太小,就会导致前面的隐藏层中的神经元学习速度要快于后面的隐藏层,即出现梯度激增的问题。

不稳定的梯度问题:根本的问题其实并⾮是消失的梯度问题或者激增的梯度问题,⽽是在前⾯的层上的梯度是来⾃后⾯的层上项的乘积。当存在过多的层次时,就出现了内在本质上的不稳定场景。 唯⼀让所有层都接近相同的学习速度的⽅式是所有这些项的乘积都能得到⼀种平衡。如果没有某种机制或者更加本质的保证来达成平衡,那⽹络就很容易不稳定了。简⽽⾔之,真实的问题就是神经⽹络受限于不稳定梯度的问题。所以,如果我们使⽤标准的基于梯度的学习算法,在⽹络中的不同层会出现按照不同学习速度学习的情况。
为了避免出现不稳定的梯度问题,我们可以采用修正线性神经元。因为其σ('z)=1.

6.深度学习

本章主要介绍了卷及神经网络。在前面已经详细介绍了这一块内容

第三节,如何直观理解卷积神经网络的工作原理

Network3.py的程序与之前的程序有所不同,这里使用到了theano的学习库。Theano的一个非常好的特性是它能够运行于CPU或者GPU上,运行于GPU上可以显著的获得加速。

# -*- coding: utf-8 -*-
"""
Created on Sun Mar 18 18:25:33 2018 @author: Administrator
""" '''
书籍:神经网络与深度学习
第6章:卷积神经网络
''' import pickle
import gzip
import numpy as np
import theano
import theano.tensor as T
from theano.tensor.nnet import conv
from theano.tensor.nnet import softmax
from theano.tensor import shared_randomstreams
#from theano.tensor.signal import downsample
from theano.tensor.signal.pool import pool_2d '''
本程序中神经网络中运算的数据:每层输入inpt,权重w,偏置b,以及网络层输出al全部采用thean.config.floatX类型
(该类型在.theanorc文件之指定),b为TensorType(theano.config.floatX,vector),其它为TensorType(theano.config.floatX,matrix)
由于函数方程式在运算时要求theano,变量类型一致,所以不一致时需要用T.cast(变量,dtype)进行转换
而期望输出y,以及网络输出类别y_out采用int32类型 TensorType(int32,vctor)
并且 w,b,实例数据集(x,y),权重w,b均为shared 变量
''' #限制
GPU = False
if GPU:
print('尝试使用GPU加速,如果不想,修改标志位GPU=False')
try:
theano.config.device = 'gpu'
except:
pass
theano.config.floatX = 'float32' else:
print('尝试在CPU下运行,如果想使用GPU加速,修改标志位GPU=True')
print(theano.config.floatX) #float32 在.theanorc文件中配置 #定义神经元的激活函数
def linear(z):
'''
线性函数
'''
return z def ReLU(z):
'''
修正后的线性函数
'''
return T.maximum(0.0,z) from theano.tensor.nnet import sigmoid
from theano.tensor import tanh #### Load the MNIST data
def load_data_shared(filename="data/mnist.pkl.gz"):
with gzip.open(filename, 'rb') as f:
training_data, validation_data, test_data = pickle.load(f,encoding='bytes')
def shared(data):
"""Place the data into shared variables. This allows Theano to copy
the data to the GPU, if one is available. """
shared_x = theano.shared(
np.asarray(data[0], dtype=theano.config.floatX), borrow=True)
shared_y = theano.shared(
np.asarray(data[1], dtype=theano.config.floatX), borrow=True)
return shared_x,T.cast(shared_y, "int32") #shared_y由theano.config.floatX转换为int32是因为后面输出准确率的时候输出类别y_out是int32类型,类型需要一致
return [shared(training_data), shared(validation_data), shared(test_data)] class ConvPoolLayer(object):
'''
定义卷积-池化层的类
Used to create a combination of a convolutional and a max-pooling
layer. A more sophisticated implementation would separate the
two, but for our purposes we'll always use them together, and it
simplifies the code, so it makes sense to combine them.
'''
def __init__(self,filter_shape,image_shape,poolsize=(2,2),activation_fn=sigmoid):
'''
初始化参数
filter_shape:卷积础参数 (滤波器个数,深度,宽度,高度) 例如filter_shape = (20,3,5,5)
image_shape:图片像素维数(mini_batch_size,深度,宽度,高度)
poolsize:池化层维数
activation_fn:卷积层激活输出函数 filter_shape` is a tuple of length 4, whose entries are the number
of filters, the number of input feature maps, the filter height, and the
filter width. `image_shape` is a tuple of length 4, whose entries are the
mini-batch size, the number of input feature maps, the image
height, and the image width. `poolsize` is a tuple of length 2, whose entries are the y and
x pooling sizes. '''
self.filter_shape = filter_shape
self.image_shape = image_shape
self.poolsize = poolsize
self.activation_fn = activation_fn #初始化权重和偏置
n_out = (filter_shape[0]*np.prod(filter_shape[2:])/np.prod(poolsize))
self.w = theano.shared(
np.asarray( #转换为数组,并指定数据类型
np.random.normal(
loc=0.0,scale=np.sqrt(1.0/n_out),size= filter_shape),
dtype=theano.config.floatX),
name='w',borrow=True) self.b = theano.shared(
np.asarray(
np.random.normal(
loc=0.0,scale=1.0,size=(filter_shape[0],)),
dtype=theano.config.floatX),
name='b',borrow=True)
self.params = [self.w,self.b] def set_inpt(self,inpt,inpt_dropout,mini_batch_size):
'''
设置该层的输入,并计算该层的输出
inpt:输入数据样本特征值集合 每一行数据对应一个实例 输入数据集的大小为mini_batch_size
inpt_dropout:采用弃权后 输入数据样本特征值集合
mini_batch_size:小批量数据个数 '''
self.inpt = inpt.reshape(self.image_shape)
#计算卷积层输出(相当于计算w*a) 这里没有经过激活函数
conv_out = conv.conv2d(
input = self.inpt,filters = self.w,filter_shape = self.filter_shape,
image_shape = self.image_shape) #计算池化层输出 (利用最大池化方法)
pooled_out = pool_2d(
input = conv_out,ds = self.poolsize,ignore_border = True) #卷积层没有弃权 计算每个样本经过该层激活函数的最终输出 [实例1输出,实例2输出,...实例mini_batch_size输出]
self.output = self.activation_fn(
pooled_out + self.b.dimshuffle('x',0,'x','x'))
self.output_dropout = self.output class FullyConnectedLayer(object):
'''
定义全连接层的类
'''
def __init__(self,n_in,n_out,activation_fn=sigmoid,p_dropout=0.0):
'''
初始化参数
n_in:输入维数 例如 n_in = 40*4**4
n_out:输出维数 例如 n_out = 100
activation_fn:该层激活函数 可选值有 sigmod,tanh,ReLU
p_dropout:丢弃的概率(减少过拟合) 0.0~1.0
'''
self.n_in = n_in
self.n_out = n_out
self.activation_fn = activation_fn
self.p_dropout = p_dropout #共享变量
'''
共享变量时多线程编程中的一个名词,故名此意就是各线程,公用拥有的变量,这个是为了多线程高效计算
、访问而使用的变量。因为深度学习中,我们整个计算过程基本上都是多线程计算,于是就要用到共享变量
在程序中,我们一般把神经网络的参数W、b等定义为共享变量,因为网络的参数,基本上每个线程都需要访问的
#初始化该层权重和偏置
'''
#loc指定均值为0 scale:标准差为1/sqrt(n_out),size:维数为n_in*n_out
self.w = theano.shared(
np.asarray( #转换为数组,并制定数据类型
np.random.normal(
loc=0.0,scale=np.sqrt(1.0/n_out),size=(n_in,n_out)),
dtype=theano.config.floatX),
name='w',borrow=True) self.b = theano.shared(
np.asarray(
np.random.normal(
loc=0.0,scale=1.0,size=(n_out,)),
dtype=theano.config.floatX),
name='b',borrow=True)
self.params = [self.w,self.b] def set_inpt(self,inpt,inpt_dropout,mini_batch_size):
'''
设置该层的输入,并计算该层的输出
inpt:输入数据样本特征值集合 每一行数据对应一个实例 输入数据集的大小为mini_batch_size
inpt_dropout:采用弃权后 输入数据样本特征值集合
mini_batch_size:小批量数据个数 '''
#没有使用弃权 计算该层输出向量 因为输入inpt可能是mini_batch_size个1*28*28维的数据 这里需要重新定义维数
self.inpt = inpt.reshape((mini_batch_size,self.n_in))
self.output = self.activation_fn(
T.dot(self.inpt,self.w) + self.b)
#按行统计最大值索引 最终得到所有实例的输出类别 [实例1类别,实例2类别,...]
#self.y_out = T.argmax(self.output,axis=1) #使用弃权 把该层输入中部分值按照p_dropout概率置为0
self.inpt_dropout = dropout_layer(
inpt_dropout.reshape((mini_batch_size,self.n_in)),self.p_dropout)
    self.inpt_dropout /= 1 - self.p_dropout
self.output_dropout = self.activation_fn(T.dot(self.inpt_dropout,self.w) + self.b)
#按行统计最大值索引 最终得到所有实例的输出类别 [实例1类别,实例2类别,...]
self.y_out = T.argmax(self.output_dropout,axis=1) def accuracy(self,y):
'''
返回准确率
y:输入对应的目标类别集合
'''
return T.mean(T.eq(y,self.y_out)) class SoftmaxLayer(object):
'''
定义一个柔性最大层的类
'''
def __init__(self,n_in,n_out,p_dropout=0.0):
'''
初始化参数
n_in:输入维数 例如 n_in = 100
n_out:输出维数 例如 n_out = 10
p_dropout:丢弃的概率(减少过拟合) 0.0~1.0
'''
self.n_in = n_in
self.n_out = n_out
self.p_dropout = p_dropout #初始化权重和偏置
self.w = theano.shared(
np.zeros((n_in,n_out),dtype=theano.config.floatX),
name='w',borrow=True) self.b = theano.shared(
np.zeros((n_out,),dtype=theano.config.floatX),
name='b',borrow=True)
self.params = [self.w,self.b] def set_inpt(self,inpt,inpt_dropout,mini_batch_size):
'''
设置该层的输入,并计算该层的输出
inpt:输入数据样本特征值集合
inpt_dropout:采用弃权后 输入数据样本特征值集合
mini_batch_size:小批量数据个数 output:不使用弃权该层的输出
output_dropout:使用弃权该层的输出
y_out:该层的输出类别 '''
self.inpt = inpt.reshape((mini_batch_size,self.n_in))
#计算该层输出
self.output = softmax(T.dot(self.inpt,self.w) + self.b)
#获取输出类别
#self.y_out = T.argmax(self.output,axis=1) #使用弃权
self.inpt_dropout = dropout_layer(
inpt_dropout.reshape((mini_batch_size,self.n_in)),self.p_dropout)
self.inpt_dropout /= 1 - self.p_dropout
self.output_dropout = softmax(T.dot(self.inpt_dropout,self.w) + self.b)
self.y_out = T.argmax(self.output_dropout,axis=1) def cost(self,net):
'''
返回代价值
net:传入Network对象
'''
#print(net.y.type) #TensorType(int32, vector)
#print(self.output_dropout.type) #TensorType(float32, matrix)
return -T.mean(T.log(self.output_dropout)[T.arange(net.y.shape[0]),net.y]) def accuracy(self,y):
'''
返回准确率
'''
return T.mean(T.eq(self.y_out,y)) #T.eq:逐元素判断是否相等 相等为True,否则为False def size(data):
'''
返回数据集的数据大小
'''
return data[0].get_value(borrow=True).shape[0] def dropout_layer(layer,p_dropout):
'''
计算使用弃权该层的输出
layer:神经网络下一层输入值,也是该层输出值
p_dropout:弃权概率
'''
#print(layer.type)
#分配一个RandomStreams随机流对象
srng = shared_randomstreams.RandomStreams(
np.random.RandomState(0).randint(999999)) # np.random.RandomState(0).randint(999999)产生一个小于999999的任意整数
#二项分布 n=1,返回值为1的概率为p,随机生成size 0和1值 要随机地从n个数中以概率p对其进行选择,可以先生成一个掩膜(mask = np.random.binomial(1, p, n))
mask = srng.binomial(n=1,p=1-p_dropout,size=layer.shape)
#对layer层中神经元按照p_dropout概率进行屏蔽,即把该神经元输出设置为0
# cast(x, dtype):象征性地投X到张量型D
return layer*T.cast(mask,theano.config.floatX) class Network(object):
'''
定义神经网络的类
'''
def __init__(self,layers,mini_batch_size):
'''
layers:list类型 神经网络的结构 如[ConvPoolLayer(image_shape = (mini_batch_size,1,28,28),
filter_shape=(20,1,5,5),
poolsize=(2,2)),
FullyConnectedLayer(n_in=20*12*12,n_out=100),
SoftmaxLayer=(n_in=100,n_out=10)]
mini_batch_size:小批量数据的大小 Takes a list of `layers`, describing the network architecture, and
a value for the `mini_batch_size` to be used during training
by stochastic gradient descent.
'''
self.layers = layers
self.mini_batch_size = mini_batch_size
#遍历权重和偏置参数
self.params = [param for layer in self.layers for param in layer.params]
#声明变量x,x是一个矩阵
self.x = T.matrix('x')
#声明变量y,y是一个int类型的向量
self.y = T.ivector('y') #初始化所有层 编写每一层的输出函数方程式 也就是把上一层输出和下一层输入连接起来
init_layer = self.layers[0]
init_layer.set_inpt(self.x,self.x,self.mini_batch_size) for j in range(1,len(self.layers)):
prev_layer,layer = self.layers[j-1],self.layers[j]
layer.set_inpt(
prev_layer.output,prev_layer.output_dropout,self.mini_batch_size)
self.output = self.layers[-1].output
self.output_dropout = self.layers[-1].output_dropout def SGD(self,training_data,epochs,mini_batch_size,eta,validation_data,test_data,lamda=0.0):
'''
随机梯度下降算法:使用小批量训练样本来计算梯度(计算随机选取的小批量数据的梯度来估计整体的梯度)
training_data:元素为(x,y)元组的列表 (x,y):表示训练输入以及对应的输出类别 这里的输出类别是二值化后的10*1维向量
epochs:迭代期数量 即迭代次数
mini_batch:小批量数据的大小
eta:学习率
lamda:规范化lamda参数
evaluation_data:评估数据集 validation_data
test_data:测试数据集 test_data
''' #把数据集分成 实例样本集合和对应的类别集合
training_x,training_y = training_data
validation_x,validation_y = validation_data
test_x,test_y = test_data #计算按mini_batch_size大小划分,数据集可以划分为几组
num_training_batches = int(size(training_data)/mini_batch_size)
num_validation_batches = int(size(validation_data)/mini_batch_size)
num_test_batches = int(size(test_data)/mini_batch_size) #定义(规范化)代价函数,并对代价函数求梯度,然后计算新的更新后的函数表达式
l2_norm_squared = sum([(layer.w**2).sum() for layer in self.layers]) #计算所有权重元素的平方和
#定义规范化代价函数方程式
cost = self.layers[-1].cost(self) + 0.5*lamda*l2_norm_squared/mini_batch_size
grads = T.grad(cost,self.params)
updates = [(param,param - eta*grad) for param,grad in zip(self.params,grads)] #定义函数方程式用来训练小批量数据,计算在validation_data,和test_data数据集上的准确率
i = T.lscalar() #定义int64类型变量 小批量数据索引
#一次传入mini_batch_size大小的实例,并计算小批量样本的带价值和梯度值,并更新权重和偏置
train_mb = theano.function(
[i],cost,updates=updates,
givens={
self.x: #training_x[i*self.mini_batch_size:(i+1)*self.mini_batch_size]替代self.x
training_x[i*self.mini_batch_size:(i+1)*self.mini_batch_size],
self.y:
training_y[i*self.mini_batch_size:(i+1)*self.mini_batch_size]
})
#一次传入mini_batch_size大小的实例 计算validation_data数据的准确率
validate_mb_accuracy = theano.function(
[i],self.layers[-1].accuracy(self.y),
givens={
self.x:
validation_x[i*self.mini_batch_size:(i+1)*self.mini_batch_size],
self.y:
validation_y[i*self.mini_batch_size:(i+1)*self.mini_batch_size]
})
#一次传入mini_batch_size大小的实例 计算test_data数据的准确率
test_mb_accuracy = theano.function(
[i],self.layers[-1].accuracy(self.y),
givens={
self.x:
test_x[i*self.mini_batch_size:(i+1)*self.mini_batch_size],
self.y:
test_y[i*self.mini_batch_size:(i+1)*self.mini_batch_size]
}) ##一次传入mini_batch_size大小的实例 计算test_data数据的预测类别
self.test_mb_predictions = theano.function(
[i],self.layers[-1].y_out,
givens={
self.x:
test_x[i*self.mini_batch_size:(i+1)*self.mini_batch_size]
}) #开始训练 传入参数
best_validation_accuracy = 0.0
#循环迭代周期,每个周期迭代完一轮training_data数据
for epoch in range(epochs):
#把训练集数据按照mini_batch-size划分为num_training_batches组,迭代每一组数据
for minibatch_index in range(num_training_batches):
#当前组数
iteration = num_training_batches*epoch + minibatch_index
#迭代组数为1000的倍数
if iteration % 1000 == 0:
print('Training mini_batch number {0}'.format(iteration))
#计算每一组mini_batch数据的代价值
cost_ij = train_mb(minibatch_index)
#一个周期数据迭代完成(即一轮迭代),并对校验数据进行测试,记录准确率最高时的迭代次数,并计算在该参数下(w,b),测试数据的准确率为多少
if (iteration+1) % num_training_batches == 0:
#计算validation_data数据的平均准确率(计算每一组的准确率求平均)
validation_accuracy = np.mean(
[validate_mb_accuracy(j) for j in range(num_validation_batches)])
print('Epoch {0}:validation accuracy {1:.2%}'.format(epoch,validation_accuracy))
#更新最大的校验准确率,并记录准确率最高的迭代次数,并计算在该参数下(w,b),测试数据的准确率为多少
if validation_accuracy >= best_validation_accuracy:
print('This is the best validation accuracy to date.')
best_validation_accuracy = validation_accuracy
best_iteration = iteration
#计算test_data数据的平均准确率(计算每一组的准确率求平均)
if test_data:
test_accuracy = np.mean(
[test_mb_accuracy(j) for j in range(num_test_batches)])
print('The corresponding test accuracy is {0:.2%}'.format(test_accuracy)) print('Finished training network.')
print('Best validation accuracy of {0:.2%} obtained at iteraion {1}'.format(
best_validation_accuracy,best_iteration))
print('Corresponding test accuracy of {0:.2%}'.format(test_accuracy)) #开始测试
training_data,validation_data,test_data = load_data_shared()
mini_batch_size = 10
net = Network([
ConvPoolLayer(image_shape=(mini_batch_size,1,28,28), #image_shape:小批量数据大小为mini_batch_size,图像1*28*28
filter_shape=(20,1,5,5), #filter_shape:滤波器个数为20,共享权重为1*5*5
poolsize=(2,2), #poolsize:池化层参数为2*2
activation_fn=ReLU), #经过卷积-池化层输出的是 20*12*12的图像
ConvPoolLayer(image_shape=(mini_batch_size,20,12,12), #image_shape:小批量数据大小为mini_batch_size,图像20*12*12
filter_shape=(40,20,5,5), #filter_shape:滤波器个数为40,共享权重为20*5*5
poolsize=(2,2), #poolsize:池化层参数为2*2
activation_fn=ReLU), #经过卷积-池化层输出的是40*4*4的图像
FullyConnectedLayer(n_in=40*4*4,n_out=1000,activation_fn=ReLU,p_dropout=0.5),
FullyConnectedLayer(n_in=1000,n_out=100,activation_fn=ReLU,p_dropout=0.5),
SoftmaxLayer(n_in=100,n_out=10)
],mini_batch_size)
net.SGD(training_data,40,mini_batch_size,0.015,validation_data,test_data)

第六节,Neural Networks and Deep Learning 一书小节(下)的更多相关文章

  1. 第四节,Neural Networks and Deep Learning 一书小节(上)

    最近花了半个多月把Mchiael Nielsen所写的Neural Networks and Deep Learning这本书看了一遍,受益匪浅. 该书英文原版地址地址:http://neuralne ...

  2. 第五节,Neural Networks and Deep Learning 一书小节(中)

    在这一节,我们对上一个程序(Network1.py)进行了优化 3.改进神经网络的学习方法 (1)交叉熵代价函数的引入 Network1程序采用了S型神经元,S型神经元存在一个问题,当输出层神经元的输 ...

  3. 【DeepLearning学习笔记】Coursera课程《Neural Networks and Deep Learning》——Week1 Introduction to deep learning课堂笔记

    Coursera课程<Neural Networks and Deep Learning> deeplearning.ai Week1 Introduction to deep learn ...

  4. 【DeepLearning学习笔记】Coursera课程《Neural Networks and Deep Learning》——Week2 Neural Networks Basics课堂笔记

    Coursera课程<Neural Networks and Deep Learning> deeplearning.ai Week2 Neural Networks Basics 2.1 ...

  5. Neural Networks and Deep Learning学习笔记ch1 - 神经网络

    近期開始看一些深度学习的资料.想学习一下深度学习的基础知识.找到了一个比較好的tutorial,Neural Networks and Deep Learning,认真看完了之后觉得收获还是非常多的. ...

  6. Neural Networks and Deep Learning

    Neural Networks and Deep Learning This is the first course of the deep learning specialization at Co ...

  7. [C3] Andrew Ng - Neural Networks and Deep Learning

    About this Course If you want to break into cutting-edge AI, this course will help you do so. Deep l ...

  8. 《Neural Networks and Deep Learning》课程笔记

    Lesson 1 Neural Network and Deep Learning 这篇文章其实是 Coursera 上吴恩达老师的深度学习专业课程的第一门课程的课程笔记. 参考了其他人的笔记继续归纳 ...

  9. [C1W1] Neural Networks and Deep Learning - Introduction to Deep Learning

    第一周:深度学习引言(Introduction to Deep Learning) 欢迎(Welcome) 深度学习改变了传统互联网业务,例如如网络搜索和广告.但是深度学习同时也使得许多新产品和企业以 ...

随机推荐

  1. 在linux系统中实现各项监控的关键技术(1)--cpu使用率的计算

    转载自 Linux中通过/proc/stat等文件计算Cpu使用率 http://www.blogjava.net/fjzag/articles/317773.html proc文件系统 /proc文 ...

  2. 如何在mac下安装php

    步骤如下: 1.下载php源码并解压 2.进入php源码并configure 3.安装openssl 4.sudo make及make test 5.sudo make install 具体命令如下: ...

  3. bootstrap簡介

    bootstarp是最受歡迎的前端開發框架,可以開發數適用pc.平板電腦和手機的web應用,是基於html.css和javascript.只要學會bootstarp,就代表具有web的開發的中級水準.

  4. Linux成为云计算平台的主流操作系统

    导读 这是一个人人谈"云"."大数据"的时代,作为一个IT民工,如果与同行间聊天时,不谈及这方面的内容,有人可能会觉得你落伍了,跟不上这个时代了. 这是一个人人 ...

  5. notepad++上直接运行python文件

    一.打开notepad++,点击语言,选择python,这样就写的是python文件了 二.点击运行>运行:输入cmd /k python "$(FULL_CURRENT_PATH)& ...

  6. GLSL 变量属性

    1. attribute变量为这个attribute变量指定一个位置(用无符号值表示):glBindAttribLocation利用这个“位置”来指定需要传给shader里的attribue变量的数据 ...

  7. Go语言类型(布尔、整型、数组、切片、map等)

    1.基本类型 布尔类型:bool 注意:布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换. 整型:int8.byte(uint8).int16.int.uint.uintptr int.ui ...

  8. 4、new一个对象的时候,初始化顺序:

    父类静态块>子类静态块> 父类属性(先系统默认值,后直接你赋予的值) >父类构造器>子类属性>子类构造器

  9. kubernetes 创建系统用户来支持访问 dashboard

    Dashboard: 1.部署: 下载yaml文件  可以直接运行也可以下载下来kubectl apply -f https://raw.githubusercontent.com/kubernete ...

  10. C# Timer 的区别

    首先,我们看一下 3种Timer 1.System.Threading.Timer 2.System.Timers.Timer 3.System.Windows.Forms.Timer 主要区别,其实 ...