手写数字识别中多元分类原理_广告行业中那些趣事系列:从理论到实战BERT知识蒸馏...

导读:本文将介绍在广告行业中自然语言处理和推荐系统实践。本文主要分享从理论到实战知识蒸馏,对知识蒸馏感兴趣的小伙伴可以一起沟通交流。

36166520d041eae67e8e006d9633c972.png

摘要:本篇主要分享从理论到实战知识蒸馏。首先讲了下为什么要学习知识蒸馏。一切源于业务需求,BERT这种大而重的模型虽然效果好应用范围广,但是很难满足线上推理的速度要求,所以需要进行模型加速。通常主流的模型加速方法主要包括剪枝、因式分解、权值共享、量化和知识蒸馏等;然后重点讲解了知识蒸馏,主要包括知识蒸馏的作用和原理、知识蒸馏的流程以及知识蒸馏的效果等;最后理论联系实战,讲解了实际业务中主要把BERT作为老师模型去教作为学生模型的TextCNN来学习知识,从而使TextCNN不仅达到了媲美BERT的分类效果,而且还能很好的满足线上推理速度的要求。对知识蒸馏感兴趣的小伙伴可以一起沟通交流。

下面主要按照如下思维导图进行学习分享:

cec5bd3781f90e3f5d4d7bb9231b3a1a.png

01 为什么要学习知识蒸馏

1.1 一切源于业务的需要

目前大火的BERT这一类预训练+微调的两阶段模型因为效果好和应用范围广在各种自然语言处理任务中疯狂屠榜取得state-of-art。在线下时延较低的场景下这类模型可以很好的满足业务需求,但是在线上推理场景中比如用户实时搜索返回广告就很难满足时延要求。实际业务中我们线上的文本推理时延需求是在10ms以内,因为模型太大(BERT基础版本有330M接近一亿的参数量)所以似乎很难满足线上推理的要求。

现在我们面临这样一种困境:BERT这类大模型精度高但是线上推理速度慢,传统的文本分类模型比如TextCNN等线上推理速度快(因为模型比较小)但是精度有待提升。针对上面的问题,我们的需求是获得媲美BERT等大模型的精度,还能满足线上推理速度的时延要求。

1.2 主流的模型加速方法

明确了我们的目标是获得大模型高精度的同时还能很好的满足线上推理的速度要求,这就需要用到模型加速技术。目前主流的模型加速方法主要有以下几种:

  • 剪枝。对模型的网络进行修剪,比如减掉多余的头(因为Transformer使用多头注意力机制),或者直接粗暴的使用更少的Transformer层数;

  • 因式分解。之前比较火的ALBERT模型使用的一个优化策略就是对embedding参数进行因式分解。因为BERT将词向量和encode输出的维度都设置为768维,而encode中包含丰富的语义信息,所以明显存储的信息量比词向量多,所以ALBERT的策略就是采用因式分解的方法把词向量映射到低维空间,这样就能大大降低参数量,最后再映射回高维的embedding向量;

  • 权值共享。这也是ALBERT中使用的优化策略之一。对Transformer各层参数可视化分析发现各层参数类似,都是在[CLS]token和对角线上分配更多的注意力,通过多层之间共享参数从而达到了模型加速的目的。对ALBERT中因式分解和全职共享感兴趣的小伙伴可以转过头来看看我之前写的这篇文章《广告行业中那些趣事系列6:BERT线上化ALBERT优化原理及项目实践(附github)》

  • 量化。量化操作主要是以精度换速度,业界也有尝试在BERT微调阶段进行量化感知训练,使用最小的精度损失将BERT模型参数压缩了4倍。这些量化操作方案很多也是为了将模型移植到移动端进行的优化;

  • 知识蒸馏。知识蒸馏是把大模型或者多个模型ensemble学到的知识想办法迁移到一个轻量级的小模型上去,线上部署这个小模型就可以了。

之前在知乎上看到过有好心人整理了主流模型加速的论文分享,下面是论文分类图片,有兴趣的小伙伴可以多看看论文:

6ffd0e90e0ecc20b0b50aa83ec1d656e.png

图1 主流模型加速论文分类

02 详解知识蒸馏

2.1 知识蒸馏的作用和原理

要搞明白知识蒸馏的作用,咱们还是拿前面的例子来说明。BERT这一类模型优点在于效果好,但是如果用于线上推理就比较麻烦了,因为基础版本的BERT模型接近330M包含一亿的参数,你想让一个一亿参数的模型完成线上10ms内的线上推理基本有点不现实。而传统的文本分类算法比如TextCNN可以轻松满足线上推理的需求,但是效果相比BERT还是有点不如人意。知识蒸馏通俗的理解就是BERT当老师,TextCNN当学生,让BERT这个老师把学到的知识传授给TextCNN这个学生,这样就能让TextCNN达到和BERT媲美的效果,最后我们线上去部署TextCNN,就能做到模型效果和线上推理速度兼得。这就是知识蒸馏的作用。

知识蒸馏的概念最早是2015年Geoffrey Hinton在《Distilling the Knowledge in a Neural Network》这篇论文中提出来的。知识蒸馏就是把一个大模型或者多个模型ensemble学到的知识迁移到另一个轻量级的单模型上,最主要的目的是为了方便线上部署。从上面的概念中也可以看出知识蒸馏主要有两个方面:第一个是将大而深的模型迁移到一个轻量级的小模型上。这就像我们线上把大而深的BERT模型学到的知识迁移到轻量级的TextCNN小模型上;另一个就是将多个模型ensemble学到的知识迁移到单个轻量级的模型。多个模型ensemble的操作在kaggle比赛中非常常见,为了提升那1到2个百分点,各种花里胡哨奇淫巧计无所不用其极。但是在工业场景中倒没有那么普遍,毕竟生产场景是要考虑投入产出比的。你得时刻掂量花了那么多时间精力以及机器算力提升的那一点点精度是不是真的划得来。而知识蒸馏就可以把多个模型ensemble学到的知识通通学到手,真正的做到集百家之长。

一点反思,感觉知识蒸馏和读书很像。一些人经历过各种酸甜苦辣学到了很多有用的知识,这些人就像老师模型一样。他们会通过写书等方式把这些知识传承下来,这时候我们可以通过读书(知识蒸馏)来学习他们的知识,就算不用去经历他们的酸甜苦辣我们照样能用学到的知识去指导我们以后的生活,相当于我们得到了“老师”的泛化能力。

2.2 知识蒸馏为啥有用

众所周知,一个好的模型最重要的是通过训练数据获得一定的泛化能力,不仅仅是拟合训练数据,最重要的是在新数据集上能有一定的泛化识别能力。而知识蒸馏的目的是让学生去学习老师的这种泛化能力,所以从理论上来说学生比老师单纯的去拟合训练数据能获得更多的知识。下面通过手写数据集的例子来说明知识蒸馏为啥能学到更多的知识:

02f893ba4f5b22c4b7a5f9fa2e2c74ba.png

图2 手写数据集中进行知识蒸馏

对于老师或者没有使用知识蒸馏的小模型来说,主要是通过训练数据来学习知识。我们的训练数据集是一张一张手写数字的图片,还有对应0到9十个数字的标签。在这种学习中我们可以用的只有十个类别值,比如一张手写数字1的图片样本的标签是1,告诉模型的知识就是这个样本标签是1,不是其他类别。而使用知识蒸馏的时候模型可以学到更多的知识,比如手写数字1的图片样本有0.7的可能是数字1,0.2的可能是数字7,还有0.1的可能是数字9。这非常有意思,模型不仅学到了标签本身的知识,还学习到了标签之间的关联知识,就是1和7、9可能存在某些关联,这些知识称为暗知识,这是知识蒸馏学到的知识,也是知识蒸馏有用的重要原因。

2.3 知识蒸馏的流程

知识蒸馏主要如图所示包括以下几个流程:

8e6035d3c91c506074eadb7ab981b1bd.png

图3 知识蒸馏的基本流程
  • 首先,训练一个老师模型。这里的老师模型可以是大而深的BERT类模型,也可以是多个模型ensemble集成后的模型。因为这里没有线上推理的速度要求,所以主要目标就是提升效果;

  • 然后,设计蒸馏模型的loss函数训练学生模型,这也是最重要的步骤。蒸馏模型的loss函数定义如下:

092477e67518ad978c66e164abe1482e.png

蒸馏模型的loss函数主要分成两部分:L_soft和L_hard。其中L_soft是老师教学生学习的损失函数,L_hard是学生自己跟着答案(标签)学习的损失函数,a和b(贝塔打不出来)一般相加为1。

再看看老师是怎么教学生学习的,L_soft公式具体如下图所示:

57b4d9bfacccd9a7bc86123c47c083f6.png

上述公式中p代表老师模型的输出结果,然后将老师模型的输出结果p作为学生模型的目标,使学生模型的输出结果q尽可能接近p,具体就是计算老师和学生的交叉熵。这里重点是T的作用,T是知识蒸馏里的超参数,论文中称为温度temperature。分类任务中一般采用的就是softmax+交叉熵的模型,当T=1时其实就是softmax函数。如果老师模型直接使用softmax函数输出结果p可能不太合适,主要原因是当一个模型训练好之后对于正确的答案一般会有很好的置信度。就像上面讲的手写数据集中图片样本1被预测为数字1的概率会很高,同时预测为其他数字的概率也会很低,比如10e-5等等。这样的情况下老师模型很难将学到的标签类型之间联系的知识传递给学生模型。

针对这个问题,知识蒸馏的作者提出了softmax-T函数,也就是通过temperature来控制老师模型输出的结果p的分布。p是学生模型学习的对象,v_i就是模型softmax前的输出logits。当T=1的时候这个公式就是softmax,根据logits输出各个类别的概率;当T接近0时,概率最大的类别输出值就会接近1,其他的输出值接近0,作用类似one-hot编码;当T越大时,会使各个类别输出的概率分布相对平缓,从而一定程度上保留了各个类别之间的联系知识;极端情况下,当T趋于无穷大时概率分布会变成一个均匀分布。温度T对softmax-T函数的概率分布影响如下图所示:

89d6927498caf92e9d1d6bc574b50235.png

图4 温度T对概率分布的影响

综合来说知识蒸馏通过控制超参数T使得老师模型的输出概率分布会保留类别之间的联系知识。个人觉得这也是知识蒸馏模型中最重要的知识点。

下面是L_hard损失函数公式:

bd4479c8e4566a60b3b58ff747bd1644.png

L_hard其实和常规模型是一样的,就是根据训练集的label来学习。上面公式中c就是正确答案label,也就是计算学生模型的输出结果q和标签c的交叉熵。

L_soft和L_hard分别对应的是样本soft target和hard target。下面通过手写数字集样本1来对比 soft target和hard target的区别:

eec707395dd1c466fb329faff33c75ea.png

图5 对比 soft target和hard target的区别

通过上图可以发现Hard target中样本的分布比较“极端”,是0或者1,而Soft target中样本的分布会更加平滑一些。

  • 最后是使用学生模型进行线上预测。这里需要注意线上预测的时候需要把T设置回1。

2.4 为什么用“蒸馏”一词

知识蒸馏的目的是让学生模型的softmax输出结果q尽可能的接近老师模型的softmax输出结果p。一般的softmax函数中指数e会把logits之间的差距拉大,然后作归一化,使得最终得到的分布是arg max的近似,也就是其中一个类别值很大,其他类别值非常小,类似one-hot,这样使老师模型无法把标签之间的联系知识教给学生,也就是上面说的手写数字1的图片样本它有0.7的可能是数字1,0.2的可能是数字7,还有0.1的可能是数字9这样的暗知识没有办法传递给学生模型。为了让老师模型softmax输出的结果分布更平滑一些,最简单直接的做法是直接比较logits。比如z_i是学生模型产生的logits,v_i是老师模型产生的logits,其实就是最小化v_i和z_i:

4d980e80761c039bc1afb0a86c1adf7c.png

针对这个问题知识蒸馏的作者提出了softmax-T函数。这里的T是温度temperature,是统计力学中的概念。前面也说过当T趋于0时softmax的输出结果会接近one-hot编码,也就是一个类别值接近1,其他类别接近0;当T趋向于无穷的时候,softmax的输出会趋向于均匀分布。

利用这个特性我们会在训练学生分类器的时候设置较高的T使得softmax输出的结果具有一定的平滑性,作用自然是学习类别之间的联系知识,也让学生模型的输出尽可能接近老师模型。当学生模型训练完成之后再把T设置为1来进行线上预测。

之所以叫“蒸馏”也是和化学中的蒸馏概念接近。化学中通过蒸馏的方法可以把不同沸点的物质区分开,流程就是升温把低沸点的物质汽化,然后迅速降温冷凝从而达到分离物质的目的。对比下知识蒸馏的概念也是这样,学生模型训练时增加温度参数T,然后在线上预测的时候降低温度T为1从而将老师模型中的知识提取出来,这和化学中的蒸馏流程非常类似。这可能也是作者命名为知识蒸馏的一个原因吧。

2.5 对比softmax-T函数和直接优化logits差异

上面也说过知识蒸馏中最有价值的就是通过softmax-T使得老师模型的softmax输出结果包含类别之间联系的暗知识,所以这里咱们再深入了解下softmax-T和直接优化logits也就是公式4之间的差异。学生模型训练时我们需要最小化老师分布和学生分布的交叉熵,下面是最小化交叉熵的公式:

34ccbafdc62f6f60a5e723633bdb9967.png

根据公式2和公式5,计算学生模型交叉熵对某个logits分布z_i的梯度就是:

63b9c0ec197300ef4b9d5c8ef7ebe0f7.png

回顾点高数知识,当x趋于0的时候,exp(x)-1和x是等价无穷小的。也就是说当T无穷大的时候,就变成了如下的公式:

92a1512f70126944ff6701eff4bb2121.png

当所有的logits对每个样本都是零均值化时, z_j的求和=v_j的求和=0,那么就变成了如下的公式:

fb65cc5c78c0f9db2d1e94592972b6f4.png

得到了公式8就可以看出当T足够大并且logits对所有样本都是零均值化的时候知识蒸馏和最小化logits的平方差也就是公式4是等价的。所以总体来说通过softmax-T不仅和最小化logits是等价的,而且还可以通过控制超参数T来调节老师模型的输出结果分布,具有很好的灵活性。

2.6 知识蒸馏模型效果

知识蒸馏模型的作者主要进行了以下三个实验:

  • 第一个实验是验证可以将大而深的模型知识转移到小模型上。在MNIST数据集上先使用大而深的模型进行训练,测试集中有67个错误;然后使用小模型进行训练,测试集中有146个错误;最后使用知识蒸馏的方法在目标函数中加入L_soft,学生模型在测试集中错误变成了74个。通过这个实验可以看出知识蒸馏的确可以使学生模型获得老师模型的知识从而提升小模型的效果。有趣的是作者还发现即使在训练集中不包含某一类的训练数据,通过知识蒸馏的方法在测试集中竟然能识别到没有包含这一类标签的数据。也就是说在训练集中可能学生模型从来没见过3,但是在测试集中竟然有识别3的能力。厉害不?

  • 第二个实验主要是验证将多个模型ensemble得到的知识转移到单一模型上。在语音识别任务中首先训练了10个DNN模型,然后通过ensemble的方式得到最终的模型,经过ensemble得到的模型效果是优于任意单个模型的;然后将这10个DNN模型作为老师模型去训练学生模型,得到的学生模型效果是优于任意一个老师模型的,可以看出经过知识蒸馏得到的学生模型的确学习到了老师模型的知识。下面是详细实验结果:

83a65308991f1be0e36446874b1c2d67.png

图6 验证多个模型ensemble知识转移到单一模型

03 实战知识蒸馏BERT到TextCNN

实际业务中我们线下场景因为没有时延的要求所以主要使用BERT模型来完成文本分类任务。而对于线上推理任务分别尝试了FastBERT、ALBERT等等貌似都达不到10ms的时延要求,目前主要使用知识蒸馏的方法来进行模型加速。将BERT作为老师模型,把 TextCNN作为学生模型来学习老师的知识。按照目前的实验效果来看,TextCNN学到了BERT的知识,在测试集和真实分布数据集上的效果良好,推理速度也是满足时延的。

构造TextCNN代码如下:

class TextCNN(object):    """    利用bert作为teacher,指导textcnn学习logits,损失函数为KL散度    """    def __init__(      self, sequence_length, vocab_size,      embedding_size, filter_sizes, num_filters,dropout_keep_prob=0.2):        self.dropout_keep_prob = dropout_keep_prob        # Placeholders for input, output        self.input_x = tf.placeholder(tf.int32, [None, sequence_length], name="input_x")        self.labels = tf.placeholder(tf.int32, shape=None, name="labels")        self.teacher_logits = tf.placeholder(tf.float32, shape=None, name="teacher_logits")        # Embedding layer        # with tf.device('/cpu:0'), tf.name_scope("embedding"):        with tf.name_scope("embedding"):            self.W = tf.Variable(                tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0),                name="W")            self.embedded_chars = tf.nn.embedding_lookup(self.W, self.input_x)            self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)        # Create a convolution + maxpool layer for each filter size        # textcnn模型结构        pooled_outputs = []        for i, filter_size in enumerate(filter_sizes):            with tf.name_scope("conv-maxpool-%s" % filter_size):                # Convolution Layer                filter_shape = [filter_size, embedding_size, 1, num_filters]                W = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.1), name="W")                b = tf.Variable(tf.constant(0.1, shape=[num_filters]), name="b")                conv = tf.nn.conv2d(                    self.embedded_chars_expanded,                    W,                    strides=[1, 1, 1, 1],                    padding="VALID",                    name="conv")                h = tf.nn.relu(tf.nn.bias_add(conv, b), name="relu")                # Maxpooling over the outputs                pooled = tf.nn.max_pool(                    h,                    ksize=[1, sequence_length - filter_size + 1, 1, 1],                    strides=[1, 1, 1, 1],                    padding='VALID',                    name="pool")                pooled_outputs.append(pooled)                # Combine all the pooled features        num_filters_total = num_filters * len(filter_sizes)        self.h_pool = tf.concat(pooled_outputs, 3)        self.h_pool_flat = tf.reshape(self.h_pool, [-1, num_filters_total])                 # Add dropout        with tf.name_scope("dropout"):            self.h_drop = tf.nn.dropout(self.h_pool_flat, self.dropout_keep_prob)                    l2_loss = tf.constant(0.0)        num_classes = 2        # Final (unnormalized) scores and predictions        with tf.name_scope("output"):            W = tf.get_variable(                "W",                shape=[num_filters_total, num_classes],                initializer=tf.contrib.layers.xavier_initializer())            b = tf.Variable(tf.constant(0.1, shape=[num_classes]), name="b")            l2_loss += tf.nn.l2_loss(W)            l2_loss += tf.nn.l2_loss(b)            self.scores = tf.nn.xw_plus_b(self.h_drop, W, b, name="scores")[:,1]            self.logits = tf.nn.softmax(self.scores)            tf.add_to_collection("logits", self.logits)         with tf.name_scope("loss"):            loss = 0.1*tf.nn.softmax_cross_entropy_with_logits(logits=self.logits, labels=self.labels)            loss = tf.reduce_sum(loss)            self.loss = loss + 0.9*tf.keras.losses.KLDivergence()(tf.nn.log_softmax(self.scores), self.teacher_logits)

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

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

相关文章

linux zip/unzip命令

2019独角兽企业重金招聘Python工程师标准>>> 语  法&#xff1a;zip [-AcdDfFghjJKlLmoqrSTuvVwXyz$][-b <工 作目录>][-ll][-n <字 尾字符串>][-t <日 期时间>][-<压 缩效率>][压 缩文件][文件...][-i <范本样式>][-x <范本样式…

在Windows下不使用密码远程登陆Linux

在登陆Linux进行管理的时候我们通常会使用用户名和密码进行登陆&#xff0c;这样一来是比较麻烦&#xff0c;二来是不安全&#xff0c;为了解决这个问题&#xff0c;我们可以使用公私钥 (public keys和private keys)进行认证。简单来说公钥存放在服务器上&#xff0c;私钥存放在…

Core Data

简介 Core Data是iOS5之后才出现的一个框架&#xff0c;它提供了对象-关系映射(ORM)的功能&#xff0c;即能够将OC对象转化成数据&#xff0c;保存在SQLite数据库文件中&#xff0c;也能够将保存在数据库中的数据还原成OC对象。在此数据操作期间&#xff0c;我们不需要编写任何…

2017将转行进行到底

2016 年说着转行&#xff0c;最后还是在匆匆中找了一份老本行&#xff0c;此刻的心情还是无爱&#xff0c;毕竟螺丝一直分不清啊&#xff0c;不喜欢就是不喜欢。看了django的教程&#xff0c;不得不感叹国外的书写的相对优秀一点&#xff0c;《learning django web development…

mysql非主键索引_主键索引和非主键索引的区别

1. 什么是最左前缀原则&#xff1f;以下回答全部是基于MySQL的InnoDB引擎例如对于下面这一张表如果我们按照 name 字段来建立索引的话&#xff0c;采用B树的结构&#xff0c;大概的索引结构如下如果我们要进行模糊查找&#xff0c;查找name 以“张"开头的所有人的ID&#…

优美的配色方案设计

2019独角兽企业重金招聘Python工程师标准>>> 怎么做好设计配色一直是个难题&#xff0c;虽然网站上有各种各样的色库&#xff0c;但配色仍然至关重要&#xff0c;不得已的话可以亲自动手&#xff0c;况且乐趣满满。 这个没有一套标准&#xff0c;所以看自己怎么喜欢…

mysql死锁释放时间参数_【Mysql】mysql 事务未提交导致死锁 Lock wait timeout exceeded; try restarting transaction 解决办法...

问题场景问题出现环境&#xff1a;1、在同一事务内先后对同一条数据进行插入和更新操作&#xff1b;2、多台服务器操作同一数据库&#xff1b;3、瞬时出现高并发现象&#xff1b;不断的有一下异常抛出&#xff0c;异常信息&#xff1a;org.springframework.dao.CannotAcquireLo…

springmvc视图解析器_SpringMVC视图及REST风格

什么是视图解析器&#xff1f;springMVC用于处理视图最重要的两个接口是ViewResolver和View。ViewResolver的主要作用是把一个逻辑上的视图名称解析成一个真的的视图&#xff0c;而SpringMVC中用于把View对象呈现给客户端的是View对象本身&#xff0c;而ViewResolver只是把逻辑…

mysql5.7.x 1251_MySql-8.0.x免安装版下载与配置,Navicat打开数据库链接报错1251的解决办法...

概述MySQL从5.7一下子跳到了MySQL8.0, 其中的变化必然是很大的, 这里就不说了, 本文主要讲解最新版MySQL安装的事情.实际上5.7版本后的mysql免安装版都是没有data文件和my.ini文件的&#xff0c;下面再具体说明怎么生成&#xff0c;注意不能自己手动新建.下载下载程序必然去官网…

To install 64-bit ODBC drivers

为了更充分的利用硬件资源&#xff0c;我想很多人都开使用64位操作系统了&#xff0c;同时你可以也发现了在64位操作系统上ODBC的驱动找不到了&#xff0c;所以ODBC的东西都没法用了。 因为2007以前版本的Office只有32位版本&#xff0c;所以我们不能在64位系统上使用ODBC。使用…

【Qt开发】QTableWidget设置根据内容调整列宽和行高

QTableWidget要调整表格行宽主要涉及以下一个函数 1.resizeColumnsToContents(); 根据内容调整列宽 2.resizeColumnToContents(int col); 根据内容自动调整给定列宽 3.horizontalHeader()->setResizeMode 把给定列…

深入浅出mysql数据开发_深入浅出MySQL数据库开发、优化与管理维护 PDF扫描版[513KB]...

深入浅出MySQL数据库开发、优化与管理维护 内容介绍&#xff1a;本书从数据库的基础、开发、优化、管理维护4个方面对MySQL进行了详细的介绍&#xff0c;其中每一部分都独立成篇。本书内容实用&#xff0c;覆盖广泛&#xff0c;讲解由浅入深&#xff0c;适合于各个层次的读者。…

Understand Lambda Expressions in 3 minutes(翻译)

本文翻译自CodeProject上的一篇简单解释Lambda表达式的文章&#xff0c;适合新手理解。译文后面我补充了一点对Lambda表达式的说明。 1.什么是Lambda表达式&#xff1f; Lambda表达式是一种匿名方法&#xff0c;多数情况下用来在LINQ中快速创建委托。简单地说&#xff0c;它代表…

Hibernate二级缓存配置

一、定义&#xff1a; 二级缓存是进程或集群范围内的缓存&#xff0c;可以被所有的Session共享&#xff0c;是可配置的插件 二、二级缓存原理图 解析&#xff1a;每次从二级缓存中取出的对象&#xff0c;都是一个新的对象。 三、配置步骤如下&#xff1a; 同理&#xff1a;以员…

redis配置主从没效果_跟我一起学Redis之加个哨兵让主从复制更加高可用

Redis哨兵(Sentinel)其实本质就是一个RedisServer节点&#xff0c;通过设置 运行模式 来开启哨兵的功能&#xff1b;主要功能如下&#xff1a;监控(Monitoring )&#xff1a;哨兵节点会不断地检查的主服务和从服务的运行状态&#xff1b;自动故障迁移(Automatic failover) &…

闰秒导致MySQL服务器的CPU sys过高

今天&#xff0c;有个哥们碰到一个问题&#xff0c;他有一个从库&#xff0c;只要是启动MySQL&#xff0c;CPU使用率就非常高&#xff0c;其中sys占比也比较高&#xff0c;具体可见下图。 注意&#xff1a;他的生产环境是物理机&#xff0c;单个CPU&#xff0c;4个Core。 于是&…

新安装数据库sqlserver2008r2,使用javaweb连接不上问题处理

鼠标右键【计算机】--》【管理】&#xff0c;打开界面如下&#xff1a; 选择自己数据库的实例名&#xff1a; 选择TCP/IP&#xff1a;右键【属性】&#xff0c;将所有TCP动态端口的【0】删掉&#xff0c;TCP端口设为1433&#xff1b;重启服务&#xff0c;即可连接。PS:不知道这…

vue 鼠标点击事件_VBA代码解决方案第115讲:点击鼠标实现精准控制触发事件的VBA代码第二方案...

大家好&#xff0c;我们今日继续讲解VBA代码解决方案的第115讲内容&#xff1a;工作表事件中&#xff0c;根据Target参数不同&#xff0c;实现精准控制触发事件的VBA代码第二方案。在上一讲中我们讲了利用Address的属性实现控制触发事件的方案&#xff0c;今日讲解第二方案&…

(翻译)31天Windows Phone学习-1-项目模板

今天在在外文网站Google关于Windows Phone 7的学习资料&#xff0c;无疑间Google到了Jeff Blankenburg的 31 Days of Windows Phone这个系列&#xff0c;感觉写的比较基础和浅显易懂&#xff0c;适合我这种入们级的人学习&#xff0c;所以准备拿来对Windows Phone 7的简单入门学…

MOSS点滴(2):自定义Application Page

在MOSS中后台管理的页面都是Application Page&#xff0c;比如网站设置的页面(settings.aspx)就是典型的Application Page&#xff0c;它不能被Sharepoint Desiger定制。如果我们要修改只能手动的使用其他工具来修改&#xff0c;我们也可以添加Application Page&#xff0c;必须…