Theano3.2-练习之数据集及目标函数介绍

来自http://deeplearning.net/tutorial/gettingstarted.html#gettingstarted


一、下载

   在后续的每个学习算法上,都需要下载对应的文档,如果想要一次全部下好,那么可以复制git上面的这个教程的资料:

git clone git://github.com/lisa-lab/DeepLearningTutorials.git

二、数据集

  MNIST 数据集(mnist.pkl.gz)(现在这个数据集除了教学,好像已经没什么人关注了)

    这个MNIST 数据集包含的是手写数字图像,其中有6w张训练样本和1w张测试样本,不过在几乎许多论文和本教程中,都是将这6w张训练样本划分成5w张训练样本和1w张验证集样本,所有的图片都已经中心化而且是固定的大小28×28,其中是灰度图,白色为255,黑色为0.为了方面本教程,是需要在python下使用的,可以下载 here.也就是已经划分好了三个list:训练集、验证集和测试集。每一个list都是由图像和相应的标签组成的。其中图像是numpy的784(28*28)的一维数组(就是把2维的图像拉成一条向量),标签则是一个0-9之间的数字。下面的代码演示了如何使用这个数据集:

import cPickle, gzip, numpy# Load the dataset
f = gzip.open('mnist.pkl.gz', 'rb')
train_set, valid_set, test_set = cPickle.load(f)
f.close()
        当使用这个数据集的时候,通常是将它划分成minibatches( Stochastic Gradient Descent)(还有http://blog.csdn.net/shouhuxianjian/article/details/41040245,这是hinton的视频的第6课)。我们建议你可以将这个数据集放入到共享变量(shared variables)中,并通过基于minibatch索引、给定一个固定和已知的batch size来访问它。这样做的好处就是共享变量之后可以用在gpu上,因为当将数据复制到GPU内存上的时候会有较大的开销,如果按照代码的执行(每个minibatch都是独立的)来进行传输数据的时候,如果不是用共享变量的方法,结果反而比只使用CPU的速度还慢。如果使用Theano 共享变量,那么就是让Theano将整个数据在共享变量构造的时候通过一个单一的调用都复制到GPU上。之后,GPU可以通过在这个共享变量上进行切片slice来访问任何minibatch,而不需要从cpu的内存上复制到GPU上,所以避免了很多的数据传输的开销。因为这些数据点和他们的标签通常都是不同的(标签通常是整数,而数据点通常是实数),我们建议使用不同的变量来表示数据和标签。同样我们推荐使用对这三个不同的集合也采用不同的变量来使得代码更具有可读性(会生成6个不同的共享变量)。因为当前的数据是一个变量,而且一个minibatch可以被定为这个变量的一个切片,所以很自然的可以通过指定索引和尺寸来定义一个minibatch。在我们的步骤中,batch size在代码执行过程中 一直是一个常量,所以一个函数实际上需要的只是索引来指定哪个数据点被使用了。下面的代码来表示如何存储数据并且如何访问一个minibatch:

def shared_dataset(data_xy):""" Function that loads the dataset into shared variablesThe reason we store our dataset in shared variables is to allowTheano to copy it into the GPU memory (when code is run on GPU).Since copying data into the GPU is slow, copying a minibatch everytimeis needed (the default behaviour if the data is not in a sharedvariable) would lead to a large decrease in performance."""data_x, data_y = data_xyshared_x = theano.shared(numpy.asarray(data_x, dtype=theano.config.floatX))#因为GPU只接受float类型shared_y = theano.shared(numpy.asarray(data_y, dtype=theano.config.floatX))#因为GPU只接受float类型# When storing data on the GPU it has to be stored as floats# therefore we will store the labels as ``floatX`` as well# (``shared_y`` does exactly that). But during our computations# we need them as ints (we use labels as index, and if they are# floats it doesn't make sense) therefore instead of returning# ``shared_y`` we will have to cast it to int. This little hack# lets us get around this issuereturn shared_x, T.cast(shared_y, 'int32') #返回的时候强制标签为int类型test_set_x, test_set_y = shared_dataset(test_set)
valid_set_x, valid_set_y = shared_dataset(valid_set)
train_set_x, train_set_y = shared_dataset(train_set)batch_size = 500    # size of the minibatch# accessing the third minibatch of the training set 访问训练集的第三个minibatchdata  = train_set_x[2 * 500: 3 * 500]
label = train_set_y[2 * 500: 3 * 500]
        在GPU上存储的数据只能是floats类型的,(存储在GPu上时,右边的dtype被赋值为theano.config.floatX).为了绕过这个标签上的问题,通过将其存储为float,然后返回的时候强制为int类型。

note:如果你想要在GPU上运行代码,而你使用的数据集太大而无法放入GPU内存中,这种情况下,你可能会将数据存储到一个共享变量中。然而你可以存储一个足够小的数据块(几个minibatches)放到一个共享变量中,然后使用这个来进行训练,当这个数据块训练完成之后,更新存储的数据块换下一部分。这个方法是为了最小化CPU和GPU之间数据传输的次数的折衷方法。

三、符号

 数据集符号

    我们将数据集表示成,当需要区别对待的时候,将训练集,验证集和测试集表示成:\mathcal{D}_{train}\mathcal{D}_{valid} 和\mathcal{D}_{test}。验证集是用来执行模型选取和超参数选择的,而且测试集是用来验证最后的 泛化误差和以无偏的方式来对比不同的算法。该教程基本上处理的是分类问题,这里每个数据集是有关 (x^{(i)},y^{(i)})对的索引集合,使用上标来区分不同的训练集样本:x^{(i)} \in\mathcal{R}^D 是第 i 个维度为的训练样本。相似的,y^{(i)} \in \{0, ..., L\}是第 i 个指派给输入x^{(i)}的标签。这样就可以简单的扩展这些例子,使得y^{(i)}能够有其他类型(例如,高斯回归,或者能够预测多个符号的多项式组(也就是多分类))。

数学约定

  • W: 大写符号用来表示一个矩阵,除非有其他的特指 
  • W_{ij}: 矩阵W的第i 行第j 列的元素
  • W_{i \cdot}, W_i: 向量, 表示矩阵W第i 行
  • W_{\cdot j}: 向量, 表示矩阵W第j 列
  • b: 小写符号用来表示一个向量,除非有其他的特指
  • b_i: 向量b的第i 个元素

符号和函数的列表

  • D: 输入的维度数.
  • D_h^{(i)}: 第i 层隐藏单元的个数.
  • f_{\theta}(x)f(x): 和模型 P(Y|x,\theta)相关的分类函数, 定义成 {\rm argmax}_k P(Y=k|x,\theta). 注意到这里通常将下标 \theta丢弃掉.
  • L:标签的个数.
  • \mathcal{L}(\theta, \cal{D}): 由参数\theta定义模型 的\cal{D}的log似然 .
  • \ell(\theta, \cal{D}) 在数据集\cal{D}上由参数\theta决定的预测函数 f 的期望损失.
  • NLL: 负似然log(negative log-likelihood,NLL)
  • \theta: 对于一个给定模型的所有参数集合

python的命名空间
本教程的代码通常使用下面的命名空间:

import theano
import theano.tensor as T
import numpy

四、在DL上的有监督优化的入门

深度学习最让人兴奋的主要是利用深网络的无监督学习。不过有监督学习同样也扮演着很重要的角色。无监督预训练的使用通常是基于当使用有监督微调之后获得效果的基础上来进行评估的。本部分回顾下作为分类模型的有监督的基础部分,然后介绍下作为在许多dl教程中模型上使用的微调的minibatch随机梯度下降算法。详细的可以看看introductory course notes on gradient-based learning ,来了解更多关于使用梯度来优化训练标准的基本概念。

学习一个分类器

zero-one 损失

    本教程中呈现的模型大多是用来做分类的。训练一个分类器的目标是为了最小化在不可见样本上的误差(0-1损失)的数量。如果 f: R^D \rightarrow\{0,...,L\}是预测函数,那么损失函数可以写成:

                                                                                          \ell_{0,1} = \sum_{i=0}^{|\mathcal{D}|} I_{f(x^{(i)}) \neq y^{(i)}}

这里是\mathcal{D} 表示的是训练集合(在训练的时候)或者 \mathcal{D} \cap \mathcal{D}_{train} = \emptyset(为了避免验证集或者测试误差的有偏估计)。I 是指示函数,可以被定义成:

                                                                    I_x = \left\{\begin{array}{ccc}      1&\mbox{ if $x$ is True} \\      0&\mbox{ otherwise}\end{array}\right.

在这个教程中,f 被定义成:

                                                                   f(x) = {\rm argmax}_k P(Y=k | x, \theta)

在python中,使用Theano的话,可以写成如下形式:

# zero_one_loss is a Theano variable representing a symbolic
# expression of the zero one loss ; to get the actual value this
# symbolic expression has to be compiled into a Theano function (see
# the Theano tutorial for more details)
zero_one_loss = T.sum(T.neq(T.argmax(p_y_given_x), y))

负log似然损失

    因为0-1损失不能微分,对于大型模型(成千上百万的参数)的优化来说,代价是非常高昂的(计算量)。所以我们在训练集给定所有的标签的基础上让我们的分类器的log似然最大化:

                                                      \mathcal{L}(\theta, \mathcal{D}) =    \sum_{i=0}^{|\mathcal{D}|} \log P(Y=y^{(i)} | x^{(i)}, \theta)

    正确类别的似然和正确预测的数量是不相同的,不过从一个随机初始化的分类器的观点上看,它们相当接近。不过提醒下,0-1损失和似然是不同的目标;你需要看见它们是在验证集上是正相关的,不过有时候却是负相关的。因为我们通常说要最小化一个损失函数,所以学习其实就是为了最小化这个负log似然函数,定义为:

                                                    NLL(\theta, \mathcal{D}) = - \sum_{i=0}^{|\mathcal{D}|} \log P(Y=y^{(i)} | x^{(i)}, \theta)

我们分类器的NLL是可微分的,所以可以用来代替0-1损失,而且我们在基于训练数据上使用这个函数的梯度作为 一个分类器的dl 有监督学习信号(其实就是用梯度来训练分类器的意思,我直译的而已)。这可以通过使用下面的代码来计算得到:

# NLL is a symbolic variable ; to get the actual value of NLL, this symbolic
# expression has to be compiled into a Theano function (see the Theano
# tutorial for more details)
NLL = -T.sum(T.log(p_y_given_x)[T.arange(y.shape[0]), y])
# note on syntax: T.arange(y.shape[0]) is a vector of integers [0,1,2,...,len(y)].
# Indexing a matrix M by the two vectors [0,1,...,K], [a,b,...,k] returns the
# elements M[0,a], M[1,b], ..., M[K,k] as a vector.  Here, we use this
# syntax to retrieve the log-probability of the correct labels, y.

随机梯度下降

    普通的梯度下降是什么?它是一个简单的算法,在这个算法中首先有由一些参数定义的损失函数表示的错误表面,然后在这个表面上重复的使用很小的步长进行下降的算法。针对于普通的梯度下降法的目的来说,训练数据是需要放入到这个损失函数中的。然后这个算法的伪代码可以写成如下形式:

# GRADIENT DESCENTwhile True:loss = f(params)d_loss_wrt_params = ... # compute gradientparams -= learning_rate * d_loss_wrt_paramsif <stopping condition is met>:return params

    随机梯度下降法是和用普通梯度下降法一样的原则来work的,不过可以通过每次一点样本来计算梯度从而更快速的进行处理,所以不需要一次放入整个训练样本了。对应的伪代码如下:

# STOCHASTIC GRADIENT DESCENT
for (x_i,y_i) in training_set:# imagine an infinite generator# that may repeat examples (if there is only a finite training set)loss = f(params, x_i, y_i)d_loss_wrt_params = ... # compute gradientparams -= learning_rate * d_loss_wrt_paramsif <stopping condition is met>:return params
     在dl 上我们推荐使用在随机梯度上的进一步变体,叫做“minibatches”。minibatch sgd的工作规则是和sgd一样的,只是我们在每次的梯度估计上使用不止一个训练样本来训练。这个技术可以梯度估计中间的方差,而且通常在现代计算机中可以更好地利用层级存储的组织方式:

for (x_batch,y_batch) in train_batches:# imagine an infinite generator# that may repeat examplesloss = f(params, x_batch, y_batch)d_loss_wrt_params = ... # compute gradient using theanoparams -= learning_rate * d_loss_wrt_paramsif <stopping condition is met>:return params
    这是在minibatch size  B的选择上的权衡考虑。方差的减小和SIMD指令的使用在当B从1增加到2的时候通常是很有帮助的,不过这个很小的提升却会很快的回归虚无。使用更大的B,时间会消耗在减少梯度估计器的方差减少上,本来这些时间是应该更好的用在额外的梯度步长上的。一个最优的B是基于模型、数据集、和硬件考虑的,同时可以在任何地方从1上升到甚至好几百。在这个教程中,我们将它设置成20,不过这个选择通常是任意的。
note:如果你训练的时候使用的是固定数量的epochs,那么这个minibatch size就变得很重要了,因为它控制着你的参数的更新次数。使用batch size 为1 的10次epochs来训练相同的模型得到的结果完全不同于训练batch size 为20的而且也是10个epochs的结果。记得,在不同的batch sizes之间转换的时候,记得按照使用过的这个batch size 来调整所有的其他参数。

    上面所有的演示该算法的伪代码块,在theano中执行同样的算法的代码如下:

# Minibatch Stochastic Gradient Descent# assume loss is a symbolic description of the loss function given
# the symbolic variables params (shared variable), x_batch, y_batch;# compute gradient of loss with respect to params
d_loss_wrt_params = T.grad(loss, params)# compile the MSGD step into a theano function
updates = [(params, params - learning_rate * d_loss_wrt_params)]
MSGD = theano.function([x_batch,y_batch], loss, updates=updates)for (x_batch, y_batch) in train_batches:# here x_batch and y_batch are elements of train_batches and# therefore numpy arrays; function MSGD also updates the paramsprint('Current loss is ', MSGD(x_batch, y_batch))if stopping_condition_is_met:return params

正则化

    除了优化,在机器学习中还有更重要的部分。当我们从数据中训练我们的模型的时候,我们是将它准备用在新样本上的,而不是那些我们已经见过的样本。上面的MSGD的训练循环如果没有考虑到这一点,也许就会过拟合训练样本。一个对应过你的方法就是正则化。这里有好几种正则化的方法,这里会介绍L1/L2正则化和早期停止。

L1/L2 正则化
    L2和L2正则化涉及到在损失函数上增加额外的项,用来惩罚某一个参数组合。形式上,如果我们的损失函数是:

                                                  NLL(\theta, \mathcal{D}) = - \sum_{i=0}^{|\mathcal{D}|} \log P(Y=y^{(i)} | x^{(i)}, \theta)

那么正则化损失就该是:

                                                E(\theta, \mathcal{D}) =  NLL(\theta, \mathcal{D}) + \lambda R(\theta)\\

或者,在我们的情况中:

                                               E(\theta, \mathcal{D}) =  NLL(\theta, \mathcal{D}) + \lambda||\theta||_p^p

这里

                                              ||\theta||_p = \left(\sum_{j=0}^{|\theta|}{|\theta_j|^p}\right)^{\frac{1}{p}}

这是 \thetaL_p 范数。\lambda是一个超参数,用来控制正则化参数的相关重要性。通常 p的值是1和2,所以命名为L1/L2,如果p=2,那么这个正则化叫做“权重衰减”。原则上说,对损失函数增加一个正则化项将会使得在NN中网络更加的平滑(通过惩罚值较大的参数,这些值较大的参数会降低网络模型的非线性程度,所以需要惩罚)。更直观的说,这两项(NLL和R(\theta))对应于很好的对数据进行建模(NLL)和有着“简单”或“平滑”的解决方法R(\theta)。因此,最小化这两个项的和,从理论上来说,就是为了在拟合训练数据和解决方法的“泛化”之间找到正确的平衡点。为了遵循Occam的razor原则,这个最小化应该让我们找到最简单的解决方法(通过我们简单的标准来测量的)来拟合训练数据。注意到这样一个事实,一个所谓的“简单”的解决方法不是意味着能够很好的泛化。经验上来说,通常是在NN的背景下这样的正则化的添加有助于泛化,特别是对于小的数据集来说。下面的代码块用来表示当包含由\lambda_1来权重化的L1正则化项和由\lambda_2来权重化的L2正则化项的时候如何在python中计算损失的:

# symbolic Theano variable that represents the L1 regularization term
L1  = T.sum(abs(param))# symbolic Theano variable that represents the squared L2 term
L2_sqr = T.sum(param ** 2)# the loss
loss = NLL + lambda_1 * L1 + lambda_2 * L2

早期停止

    用早期停止来解决过拟合是通过在验证集合上监测模型的执行结果来完成的。验证集就是我们在梯度下降的时候未使用的样本集,不过这同样也不是测试集的一部分。验证集样本是被认为作为未来测试集样本的代表的。我们可以在训练的时候使用时因为它们不是测试集的一部分。如果模型的效果在验证集上已经停止了提升,或者甚至在后面的优化上还有下降,那么这里需要做的就是停止使用更多的优化。选择什么时候停止是一个主观判断而且是存在启发式的,不过这些教程将会在基于会具有几何增长的patience数量上使用一些策略:

# early-stopping parameters
patience = 5000  # look as this many examples regardless
patience_increase = 2     # wait this much longer when a new best is# found
improvement_threshold = 0.995  # a relative improvement of this much is# considered significant
validation_frequency = min(n_train_batches, patience/2)# go through this many# minibatches before checking the network# on the validation set; in this case we# check every epochbest_params = None
best_validation_loss = numpy.inf
test_score = 0.
start_time = time.clock()done_looping = False
epoch = 0
while (epoch < n_epochs) and (not done_looping):# Report "1" for first epoch, "n_epochs" for last epochepoch = epoch + 1for minibatch_index in xrange(n_train_batches):d_loss_wrt_params = ... # compute gradientparams -= learning_rate * d_loss_wrt_params # gradient descent# iteration number. We want it to start at 0.iter = (epoch - 1) * n_train_batches + minibatch_index# note that if we do `iter % validation_frequency` it will be# true for iter = 0 which we do not want. We want it true for# iter = validation_frequency - 1.if (iter + 1) % validation_frequency == 0:this_validation_loss = ... # compute zero-one loss on validation setif this_validation_loss < best_validation_loss:# improve patience if loss improvement is good enoughif this_validation_loss < best_validation_loss * improvement_threshold:patience = max(patience, iter * patience_increase)best_params = copy.deepcopy(params)best_validation_loss = this_validation_lossif patience <= iter:done_looping = Truebreak# POSTCONDITION:
# best_params refers to the best out-of-sample parameters observed during the optimization

    如果我们在跑完patience之前跑完了所有的训练数据,那么我们只需要回到训练数据的开始部分,然后再来一次。

note:validation_frequency应该总是要小于patience的。在跑完patience之前代码需要检查至少两次。这是因为我们使用的公式validation_frequency = min( value,patience/2)。

note:当决定什么时候需要增大patience的时候,算法可以通过使用统计测试的方法来明显的提升,而不是简单的使用对比。

测试

    在现有的循环之后,best_params变量表示在验证集上best-performing的模型。如果我们给另一个模型类别重复这个过程,或者甚至使用另一个随机初始化,我们应该也要对数据使用相同的train/valid/test划分,然后得到其他best-performing模型。如果我们不得不需要选择最好的模型类别或者最好的初始化,我们需要对每个模型进行对比best_validation_loss。当我们选择我们认为的最好的模型(基于验证集)的时候,我们会将这个模型用在测试集上,并报告结果。

回顾

    这是为了优化部分准备的。早期停止的技术需要我们将样本集合划分成三个不同的集合(训练集、验证集、测试集)。训练集用来作为目标函数的可微分的近似函数的minibatch sgd上。当我们执行梯度下降的时候,我们定期的使用验证集来观察我们在真正的目标函数上模型的结果(或者至少从经验上分析)。当我们在验证集上看到一个好的模型的时候,我们需要保存下来,当我们发现从看到一个好模型已经过去了很久,那么我们就放弃我们的研究,回头去找到那些最好的参数,然后在测试集上进行评估。

五、theano/python的提示

装载和保存模型

    当你做实验的时候,会花费好几个小时(或者几天)来做梯度下降然后找到最好的参数。一旦你找到了它们,你将会需要保存这些权重。随着研究的开展,你也许同样会想要保存你当前最好的结果。

从共享变量中pickle这个numpy ndarrays

    最好的保存/存档你的模型的参数的方法是使用pickle或者深度复制ndarray对象。例如,如果你的参数都放在共享变量w,v,u中,那么你可以像下面的命令来保存:

>>> import cPickle
>>> save_file = open('path', 'wb')  # this will overwrite current contents
>>> cPickle.dump(w.get_value(borrow=True), save_file, -1)  # the -1 is for HIGHEST_PROTOCOL
>>> cPickle.dump(v.get_value(borrow=True), save_file, -1)  # .. and it triggers much more efficient
>>> cPickle.dump(u.get_value(borrow=True), save_file, -1)  # .. storage than numpy's default
>>> save_file.close()
然后,你可以像这样装载你的数据:

>>> save_file = open('path')
>>> w.set_value(cPickle.load(save_file), borrow=True)
>>> v.set_value(cPickle.load(save_file), borrow=True)
>>> u.set_value(cPickle.load(save_file), borrow=True)
这些技术是有一点过于详尽了,不过试过都是正确的。你可以在matplotlib中毫无问题的装载你的数据然后对它进行加工。

不要为需要长期存储的目的而pickle你的训练或测试函数

    theano函数是兼容python的深度复制和pickle机制的,不过你没必要一定pickle一个theano函数。如果你更新你的theano文件夹或者说其内部有一些改变,那么你也许没法unpickle你的模型。theano仍然是一个动态的开发项目,内部的APIs可能会改变。所以从安全角度上来说,不要为了长期的存储而pickle你的整个训练或者测试函数(也就是如果save几天或者几个礼拜估计还ok,就是怕几个月之后更新了theano,之前的保存的就没法读取了)。pickle机智是为了短期存储而准备的,例如一个临时文件,或者在一个分布式工作中从一个机器上复制到另一个机器上。

了解更多可以看看 serialization in Theano, 或者 Python的 pickling.

显示中间的结果

    可视化对于理解你的模型或者训练算法在干什么是很有帮助的工具。你可能需要视图键入matplotlib画图命令,或者PIL 图像呈现命令到你的模型训练脚本中。然而,之后你可能想要从这些预呈现的图形中显示一些你感兴趣的或者想要看看从图形中得到的是否清晰,那么你需要保存原始的模型。

如果你有足够的磁盘空间,你的训练脚本应该保存中间模型并且一个可视化脚本应该用来处理这些保存的模型。

你已经有了一个模型保存函数了吗?可以再次使用它来保存这些中间模型

你可能会想要了解的库:python图像库 (PIL), matplotlib.


参考资料:

[1] 官网:http://deeplearning.net/tutorial/gettingstarted.html#gettingstarted

[2] theano学习指南1:http://www.cnblogs.com/xueliangliu/archive/2013/04/03/2997437.html

转载于:https://www.cnblogs.com/shouhuxianjian/p/4564627.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/291147.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#使用NPOI导出Excel文件

欢迎您成为我的读者&#xff0c;希望这篇文章能给你一些帮助。前言今天咱们一起来看看在C#中如何使用NPOI第三方控件进行数据的导出。关于NPOI插件网上资料很多&#xff0c;大家感兴趣的可以去看看。本文使用的版本是NPOI 2.5.1。大家可在包管理器NuGet或者下面网址进行下载。h…

Android之ActivityLifecycleCallbacks的得到当前的activity的状态

1、ActivityLifecycleCallbacks的介绍 Application通过此接口提供了一套回调方法,用于让开发者对Activity的生命周期事件进行集中处理,注意是在Application里面,路径如下 android.app.Application.ActivityLifecycleCallbacks要求API 14+ (Android 4.0+) ActivityLifecyc…

开放产品开发(OPD):Archi 汉化工具下载

在OPD中&#xff0c;我们使用了ArchiMate 作为架构语言&#xff0c;这是一个高层、简单的描述语言&#xff0c;之前我也写过一系列相关的文字&#xff0c;架构语言ArchiMate &#xff0d; 开篇&#xff1a;企业架构语言ArchiMate介绍架构语言ArchiMate &#xff0d; 语言结构&a…

【数据库中间件】MyCat分表分库规则实现

2019独角兽企业重金招聘Python工程师标准>>> /*** * 先根据截取字段的日期分组&#xff0c;再根据字段值数据按天入表 * author Fx_demon * */ public class PartitionBySubstringRangeDateDay extends AbstractPartitionAlgorithm implements RuleAlgo…

[C# 项目实战]: 制作一个备忘录(经典)

01—概述前几天群里有人问如何制作备忘录&#xff0c;感觉这样一个小实例挺适合新手们入门学习使用&#xff0c;所以就抽空做了出来。界面如下图&#xff1a;这个备忘录主要包括了如下功能&#xff1a;① 备忘录信息的增、删、改、查&#xff1b;② 备忘录时间到了以后进行语音…

RedHat 5.4下构建postfix全功能电子邮(七)-extmail extman平台-(下集)

2019独角兽企业重金招聘Python工程师标准>>> RedHat 5.4下构建postfix全功能电子邮&#xff08;七&#xff09;-extmail extman平台-&#xff08;下集&#xff09; 三、设置邮件系统的图形化日志信息 [rootmail ~]# ln -sf /usr/local/apache2/htdocs/extman/addon…

JNI中的内存管理(转)

源&#xff1a;JNI中的内存管理 JNI 编程简介 JNI&#xff0c;Java Native Interface&#xff0c;是 native code 的编程接口。JNI 使 Java 代码程序可以与 native code 交互——在 Java 程序中调用 native code&#xff1b;在 native code 中嵌入 Java 虚拟机调用 Java 的代码…

C# 异步方法的异常处理

在使用异步方法时&#xff0c;应该知道错误的一些特殊处理方式。所有 ErrorHandling 示例的代码都使用了如下名称空间&#xff1a;SystemSystem.Threading.Tasks从一个简单的方法开始&#xff0c;它在延迟后抛出一个异常&#xff1a;static async Task ThrowAfter(int ms, stri…

Mark Down 使用实例

为什么80%的码农都做不了架构师&#xff1f;>>> Mark Down 使用实例 MarkDown是一个非常轻量级的 【标记语言】&#xff0c;有点有很多&#xff0c;书写比较快速&#xff0c;学习成本低&#xff0c;统一的排版模式&#xff0c;可导出 PDF HTML 等文档格式&#xff…

JoySSL付费版证书的优势

JoySSL付费版证书相比免费版有很多优势。首先&#xff0c;付费版证书通常由权威的CA&#xff08;证书颁发机构&#xff09;签发&#xff0c;在浏览器和操作系统中具有99.99%的兼容性&#xff0c;被主流浏览器如Chrome、Firefox、Safari和Edge等广泛支持和认可。这确保了无论用户…

Git命令集十三——快照操作

2019独角兽企业重金招聘Python工程师标准>>> Git命令集十三——快照操作 Git工具中提供了一个stash命令&#xff0c;这个命令的作用是创建快照。快照主要的用途是将当前未更新到缓存区的修改进行入栈保存&#xff0c;创建快照后&#xff0c;Git的状态会变回上一次提…

Asp.net core IdentityServer4与传统基于角色的权限系统的集成

img写在前面因为最近在忙别的&#xff0c;好久没水文了 今天来水一篇&#xff1b;在学习或者做权限系统技术选型的过程中&#xff0c;经常有朋友有这样的疑问 &#xff1a;“IdentityServer4的能不能做到与传统基于角色的权限系统集成呢&#xff1f;”“我的公司有几百个接口&a…

算法小白——基本排序算法入门

计算的 时间复杂度&#xff08;最差、平均、和最好性能&#xff09;&#xff0c;依据列表&#xff08;list&#xff09;的大小(n)。一般而言&#xff0c;好的性能是O(n log n)&#xff0c;且坏的性能是O(n^2)。对于一个排序理想的性能是O(n)。仅使用一个抽象关键比较运算的排序…

使用Dynamic LINQ创建高级查询服务

前言在以前的文章中&#xff0c;我们介绍了使用AutoFilterer.Generators创建高级查询服务。但是&#xff0c;AutoFilterer.Generators只能提供简单的范围筛选&#xff1a;今天&#xff0c;我们介绍如何使用Dynamic LINQ轻松实现更强大的高级查询服务。Demo创建ASP.NET Core Web…

线程池的开源实现(mariadb和percona版本)

2019独角兽企业重金招聘Python工程师标准>>> 一、"Thread pool in MariaDB 5.5" 线程池解决的问题&#xff1a; 传统mysql使用一个线程处理一个客户端连接&#xff0c;如果许多的并发用户&#xff0c;将使性能下降。因为大量的线程将引起上下文交换&#…

C++之goto

1 goto code: result:

ABP vNext微服务架构详细教程——结束语

ABP vNext微服务架构详细教程——简介ABP vNext微服务架构详细教程——架构介绍ABP vNext微服务架构详细教程——身份管理服务ABP vNext微服务架构详细教程——基础服务层ABP vNext微服务架构详细教程——聚合服务ABP vNext微服务架构详细教程——身份认证服务ABP vNext微服务架…

创建 linux分区命令,Linux中创建分区

在很多情况下我们可能需要在使用Linux的时候创建新的分区来帮助我们更好的学习和工作&#xff0c;接下来我就详细的介绍一下如何利用fdisk这条命令进行硬盘分区。Linux磁盘分区和windows存在区别&#xff0c;Linux分区分为三类 主分区 扩展分区 和逻辑分区。然而它们三个关系有…

Android studio之Error:(23, 17) Failed to resolve: junit:junit:4.12

1 probleam 2 resolve method // testCompile junit:junit:4.12

20杨氏矩阵查找

问题描述&#xff1a;在一个m行n列二维数组中&#xff0c;每一行都按照从左到右递增的顺序排序&#xff0c;每一列都按照从上到下递增的顺序排序。请完成一个函数&#xff0c;输入这样的一个二维数组和一个整数&#xff0c;判断数组中是否含有该整数。 例如下面的二维数组就…