政安晨:【机器学习基础】(三)—— 提高泛化能力

根据我这个系列的前两篇文章,您会发现您的模型已经表现出了一定的泛化能力,并且能够过拟合,接下来应该专注于将泛化能力最大化。

政安晨的个人主页政安晨

欢迎 👍点赞✍评论⭐收藏

收录专栏政安晨的机器学习笔记

希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正!


本系列的前两篇文章为

政安晨:【机器学习基础】(一)—— 泛化:机器学习的目标icon-default.png?t=N7T8https://blog.csdn.net/snowdenkeke/article/details/136275013政安晨:【机器学习基础】(二)—— 评估机器学习模型&改进icon-default.png?t=N7T8https://blog.csdn.net/snowdenkeke/article/details/136278780

数据集管理

相信您已经知道,深度学习的泛化来源于数据的潜在结构。

如果你的数据允许在样本之间进行平滑插值,你就可以训练出一个具有泛化能力的深度学习模型。如果你的数据过于嘈杂或者本质上是离散的,比如列表排序问题,那么深度学习将无法帮助你解决这类问题。深度学习是曲线拟合,而不是魔法。

因此,你必须确保使用适当的数据集。在收集数据上花费更多的精力和金钱,几乎总是比在开发更好的模型上花费同样的精力和金钱产生更大的投资回报。

确保拥有足够的数据。请记住,你需要对输入−输出空间进行密集采样。利用更多的数据可以得到更好的模型。有时,一开始看起来无法解决的问题,在拥有更大的数据集之后就能得到解决。

尽量减少标签错误。将输入可视化,以检查异常样本并核查标签。

如果有很多特征,而你不确定哪些特征是真正有用的,那么需要进行特征选择。

提高数据泛化潜力的一个特别重要的方法就是特征工程(feature engineering)对于大多数机器学习问题,特征工程是成功的关键因素。

特征工程

特征工程是指将数据输入模型之前,利用你自己关于数据和机器学习算法(这里指神经网络)的知识对数据进行硬编码的变换(这种变换不是模型学到的),以改善算法的效果。在多数情况下,机器学习模型无法从完全随意的数据中进行学习。呈现给模型的数据应该便于模型进行学习。

咱们来看一个直观的例子:假设你想开发一个模型,输入一张时钟图像,模型就可以输出对应的时间,如下图所示

如果选择使用图像的原始像素作为输入数据,那么这个机器学习问题解决起来会非常困难。你需要用卷积神经网络来解决,而且还需要耗费大量计算资源来训练这个网络。

但如果你从更高的层次理解了这个问题(你知道人们如何读取时钟显示的时间),就可以为机器学习算法找到更好的输入特征,比如你可以编写5行Python脚本,找到时钟指针对应的黑色像素并输出每个指针顶端的(x, y)坐标,这很简单。这样一个简单的机器学习算法就可以学会这些坐标与时间的对应关系。

你还可以进一步思考:利用坐标变换,将(x, y)坐标转换为相对于图像中心的极坐标。输入变成了每个时钟指针的角度theta。这个特征让问题变得非常简单,无须使用机器学习算法,简单的舍入运算和字典查找就足以给出大致时间。

这就是特征工程的本质用更简单的方式表述问题,从而使问题更容易解决。特征工程可以让潜在流形变得更平滑、更简单、更有条理。特征工程通常需要深入理解问题。

深度学习出现之前特征工程曾经是机器学习工作流程中最重要的部分因为经典的浅层算法没有足够丰富的假设空间来自主学习有用的表示

将数据呈现给算法的方式对成功解决问题至关重要。

举例来说,在卷积神经网络成功解决MNIST数字分类问题之前这个问题的解决方法通常是基于硬编码的特征,比如数字图像中的圆圈个数、图像中的数字高度、像素值的直方图等。

幸运的是,对于现代深度学习,大多数特征工程是不需要做的,因为神经网络能够从原始数据中自动提取有用的特征这是否意味着,只要使用深度神经网络,就无须担心特征工程呢?并非如此,原因有以下两点

良好的特征仍然有助于更优雅地解决问题,同时使用更少的资源。例如,使用卷积神经网络解决读取时钟问题是非常可笑的。

良好的特征可以用更少的数据解决问题。深度学习模型自主学习特征的能力依赖于拥有大量的训练数据。如果只有很少的样本,那么特征的信息价值就变得非常重要。

提前终止

在深度学习中,我们总是使用过度参数化的模型:模型自由度远远超过拟合数据潜在流形所需的最小自由度。这种过度参数化并不是问题,因为永远不会完全拟合一个深度学习模型。这样的拟合根本没有泛化能力。你总是在达到最小训练损失之前很久就会中断训练。

在训练过程中找到最佳泛化的拟合,即欠拟合曲线和过拟合曲线之间的确切界线,是提高泛化能力的最有效的方法之一。

在我以前文章中的例子中,我们首先让模型训练时间比需要的时间更长,以确定最佳验证指标对应的轮数,然后重新训练一个新模型,正好训练这个轮数。这是很标准的做法,但需要做一些冗余工作,有时代价很高。当然,你也可以在每轮结束时保存模型,一旦找到了最佳轮数,就重新使用最近一次保存的模型。在Keras中,我们通常使用EarlyStopping回调函数来实现这一点,它会在验证指标停止改善时立即中断训练,同时记录最佳模型状态。

模型正则化

正则化方法是一组最佳实践可以主动降低模型完美拟合训练数据的能力,其目的是提高模型的验证性能。它之所以被称为模型的“正则化”,是因为它通常使模型变得更简单、更“规则”,曲线更平滑、更“通用”。因此,模型对训练集的针对性更弱,能够更好地近似数据的潜在流形,从而具有更强的泛化能力。

请记住,模型正则化过程应该始终由一个准确的评估方法来引导。只有能够衡量泛化,你才能实现泛化。我们来具体了解几种最常用的正则化方法,并将其实际应用于改进以前我以前文章中的影评分类模型。

缩减模型容量

你已经知道,一个太小的模型不会过拟合。为模型降低过拟合最简单的方法,就是缩减模型容量,即减少模型中可学习参数的个数(这由层数和每层单元个数决定

如果模型的记忆资源有限,它就不能简单地记住训练数据;

为了让损失最小化,它必须学会对目标有预测能力的压缩表示,这也正是我们感兴趣的数据表示。同时请记住,你的模型应该具有足够多的参数,以防欠拟合,即模型应避免记忆资源不足。在容量过大容量不足之间,要找到一个平衡点。

不幸的是,没有一个魔法公式能够确定最佳层数或每层的最佳大小。

你必须评估一系列不同的模型架构(当然是在验证集上评估,而不是测试集),以便为数据找到最佳的模型规模。要确定合适的模型规模,一般的工作流程是开始时选择相对较少的层和参数,然后逐渐增加层的大小或添加新层,直到这种增加对验证损失的影响变得很小

咱们在我以前文章中的影评分类模型上试一下(是以下这篇文章):

政安晨:【示例演绎机器学习】(二)—— 神经网络的二分类问题示例 (影评分类)icon-default.png?t=N7T8https://blog.csdn.net/snowdenkeke/article/details/136204994

准备

import tensorflow
from tensorflow import keras
from tensorflow.keras import layers

import numpy as np

初始模型

from tensorflow.keras.datasets import imdb

(train_data, train_labels), _ = imdb.load_data(num_words=10000)

def vectorize_sequences(sequences, dimension=10000):
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.
    return results
train_data = vectorize_sequences(train_data)

model = keras.Sequential([
    layers.Dense(16, activation="relu"),
    layers.Dense(16, activation="relu"),
    layers.Dense(1, activation="sigmoid")
])
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",
              metrics=["accuracy"])
history_original = model.fit(train_data, train_labels,
                             epochs=20, batch_size=512, validation_split=0.4)

上述这个模型的训练过程如下:

现在我们尝试用较小的模型来代替它,代码如下:

容量更小的模型

model = keras.Sequential([
    layers.Dense(4, activation="relu"),
    layers.Dense(4, activation="relu"),
    layers.Dense(1, activation="sigmoid")
])
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",
              metrics=["accuracy"])
history_smaller_model = model.fit(
    train_data, train_labels,
    epochs=20, batch_size=512, validation_split=0.4)

训练过程如下:

咱们现在对比一下初始模型较小模型的验证损失:

作者政安晨为小伙伴们把画图的代码写好:

大家可以修改下面的代码显示不同参数的值的图

import matplotlib.pyplot as plt
 
history_dict = history_original.history
history_dict2 = history_smaller_model.history
#loss_values = history_dict["loss"]
val_loss_values = history_dict["val_loss"]
val_loss_values2 = history_dict2["val_loss"]
epochs = range(1, len(val_loss_values) + 1)
 
# "b"表示“蓝色实线”
plt.plot(epochs, val_loss_values, "b", label="Original Validation loss")

# "bo"表示“蓝色圆点”
plt.plot(epochs, val_loss_values2, "bo", label="Small Validation loss")
 
plt.title("Training and validation loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
plt.show()

演绎如下:

上图为对于影评分类问题,初始模型与较小模型的对比

如上图所示,较小模型开始过拟合的时间要晚于初始模型(前者10轮后开始过拟合,而后者5轮后就开始过拟合),而且开始过拟合之后,它的性能下降速度也更慢。

如下代码所示,我们现在添加一个容量更大的模型——其容量远大于问题所需。虽然过度参数化的模型很常见,但肯定会有这样一种情况:模型的记忆容量过大。如果模型立刻开始过拟合,而且它的验证损失曲线看起来很不稳定、方差很大,你就知道模型容量过大了(不过验证指标不稳定的原因也可能是验证过程不可靠,比如验证集太小)。

(容量更大的模型)

model = keras.Sequential([
    layers.Dense(512, activation="relu"),
    layers.Dense(512, activation="relu"),
    layers.Dense(1, activation="sigmoid")
])
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",
              metrics=["accuracy"])
history_larger_model = model.fit(
    train_data, train_labels,
    epochs=20, batch_size=512, validation_split=0.4)

演绎如下:

演绎较大模型与初始模型的性能对比:

画图代码如下:

import matplotlib.pyplot as plt
 
history_dict = history_original.history
history_dict2 = history_larger_model.history
#loss_values = history_dict["loss"]
val_loss_values = history_dict["val_loss"]
val_loss_values2 = history_dict2["val_loss"]
epochs = range(1, len(val_loss_values) + 1)
 
# "b"表示“蓝色实线”
plt.plot(epochs, val_loss_values, "b", label="Original Validation loss")

# "bo"表示“蓝色圆点”
plt.plot(epochs, val_loss_values2, "bo", label="Larger Validation loss")
 
plt.title("Training and validation loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
plt.show()

对比图:

仅仅过了一轮,较大模型几乎立即开始过拟合而且过拟合程度要严重得多

它的验证损失波动更大。此外,它的训练损失很快就接近于零。模型的容量越大,它拟合训练数据的速度就越快(得到很小的训练损失),但也更容易过拟合(导致训练损失和验证损失有很大差异)。

添加权重正则化

小伙伴们可能知道奥卡姆剃刀原理如果一件事有两种解释,那么最可能正确的解释就是更简单的那种,即假设更少的那种。这个原理也适用于神经网络学到的模型给定训练数据和网络架构,多组权重值(多个模型)都可以解释这些数据。简单模型比复杂模型更不容易过拟合。 

这里的简单模型是指参数值分布的熵更小的模型(或参数更少的模型,比如上一节中的例子)。因此,降低过拟合的一种常见方法就是强制让模型权重只能取较小的值,从而限制模型的复杂度,这使得权重值的分布更加规则。这种方法叫作权重正则化(weight regularization)其实现方法是向模型损失函数中添加与较大权重值相关的成本(cost)。这种成本有两种形式。

L1正则化添加的成本与权重系数的绝对值(权重的L1范数)成正比。

L2正则化添加的成本与权重系数的平方(权重的L2范数)成正比。神经网络的L2正则化也叫作权重衰减(weight decay)。不要被不同的名称迷惑,权重衰减与L2正则化在数学上是完全相同的。

在Keras中,添加权重正则化的方法是向层中传入权重正则化项实例weight regularizer instance)作为关键字参数。下面我们向最初的影评分类模型中添加L2权重正则化,代码如下所示:

向模型中添加L2权重正则化

from tensorflow.keras import regularizers
model = keras.Sequential([
    layers.Dense(16,
                 kernel_regularizer=regularizers.l2(0.002),
                 activation="relu"),
    layers.Dense(16,
                 kernel_regularizer=regularizers.l2(0.002),
                 activation="relu"),
    layers.Dense(1, activation="sigmoid")
])
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",
              metrics=["accuracy"])
history_l2_reg = model.fit(
    train_data, train_labels,
    epochs=20, batch_size=512, validation_split=0.4)

在上述代码中,l2(0.002)的含义是该层权重矩阵的每个系数都会使模型总损失值增加0.002 * weight_coefficient_value ** 22。

训练过程:

注意,因为只在训练时添加这个惩罚项,所以该模型的训练损失会比测试损失大很多。

咱们画图对比一下

上图展示了L2正则化惩罚项的影响。如你所见,虽然两个模型的参数个数相同,但具有L2正则化的模型比初始模型更不容易过拟合。

你还可以用Keras的权重正则化项来代替L2正则化项,代码如下所示:

Keras中不同的权重正则化项

from tensorflow.keras import regularizers

# L1正则化
regularizers.l1(0.001)

# 同时做L1正则化和L2正则化
regularizers.l1_l2(l1=0.001, l2=0.001) 

请注意,权重正则化更常用于较小的深度学习模型。大型深度学习模型往往是过度参数化的,限制权重值大小对模型容量和泛化能力没有太大影响。

在这种情况下,应首选另一种正则化方法dropout。

dropout是神经网络最常用且最有效的正则化方法之一,它由多伦多大学的Geoffrey Hinton和他的学生开发。

对某一层使用dropout,就是在训练过程中随机舍弃该层的一些输出特征(将其设为0)。

比方说,某一层在训练过程中对给定输入样本的返回值应该是向量[0.2, 0.5, 1.3, 0.8, 1.1]。使用dropout之后,这个向量会有随机几个元素变为0,比如变为[0, 0.5, 1.3, 0, 1.1]。dropout比率(dropout rate)是指被设为0的特征所占的比例,它通常介于0.2~0.5。测试时没有单元被舍弃,相应地,该层的输出值需要按dropout比率缩小,因为这时比训练时有更多的单元被激活,需要加以平衡。

考虑一个包含某层输出的NumPy矩阵layer_output,其形状为(batch_size,features)。训练时,我们随机将矩阵中的一些值设为0。

# 训练时,将50%的输出单元设为0
layer_output *= np.random.randint(0, high=2, size=layer_output.shape) 

测试时,我们将输出按dropout比率缩小。这里我们乘以0.5(因为训练时舍弃了一半的单元)。

#  测试时
layer_output *= 0.5

注意,为实现这一过程,还可以在训练的同时完成两个运算,而测试时保持输出不变。这也是实践中常用的实现方法,如下图所示。

# 训练时
layer_output *= np.random.randint(0, high=2, size=layer_output.shape)

# 注意,这里是按比例放大,而不是按比例缩小
layer_output /= 0.5

(训练时对激活矩阵使用dropout,并在训练时按比例放大。测试时激活矩阵保持不变)

这一方法可能看起来有些奇怪和随意。为什么它能够降低过拟合?

Hinton说他的灵感之一来自于银行的防欺诈机制。用他自己的话来说:“我去银行,柜员不停地换人,我问其中一人这是为什么。他说他不知道,但他们经常换来换去。我想这一定是因为银行职员要想成功欺诈银行,他们之间要合作才行。这让我意识到,随机删除每个样本的一部分神经元,可以阻止‘阴谋’,从而降低过拟合。dropout的核心思想是在层的输出值中引入噪声,打破不重要的偶然模式(也就是Hinton所说的“阴谋”)。如果没有噪声,那么神经网络将记住这些偶然模式。

在Keras中,你可以通过Dropout层向模型中引入dropout。dropout将被应用于前一层的输出。下面我们向IMDB模型中添加两个Dropout层,看看它降低过拟合的效果如何,代码如下所示:

向IMDB模型中添加dropout

model = keras.Sequential([
    layers.Dense(16, activation="relu"),
    layers.Dropout(0.5),
    layers.Dense(16, activation="relu"),
    layers.Dropout(0.5),
    layers.Dense(1, activation="sigmoid")
])
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",
              metrics=["accuracy"])
history_dropout = model.fit(
    train_data, train_labels,
    epochs=20, batch_size=512, validation_split=0.4)

训练过程如下

咱们画图演绎(小伙伴们应该可以自己编辑代码完成下图了,呵呵):

总之,要想将神经网络的泛化能力最大化,并防止过拟合,最常用的方法如下所述:

1)获取更多或更好的训练数据。

2)找到更好的特征。

3)缩减模型容量。

4)添加权重正则化(用于较小的模型)。

5)添加dropout。


小伙伴们可以自己演绎哈。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS 入门手册(一)

目录 什么是 CSS? 1-CSS语法规则 2-样式表 外部样式表 内部样式表 行内样式表 3-选择器 4-背景 4.1 颜色定义方式 4.2 背景图像 5-文本 5.1 文本颜色 5.2 文本对齐方式 5.3 文本装饰 5.4 文本转换 5.5 文本首行缩进/间距 6-字体 6.1 字体系列 6.2 字体样式…

常见集合框架底层原理

常见集合框架底层原理 常见的集合有哪些 Java集合类主要由两个接口Collection和Map派生出来的,Collection有三个子接口: List、 Set、Queue List代表了有序可重复集合,可直接根据元素的索引来访问Set代表了无序集合,只能根据元素本身来访问…

“智能语音指令解析“ 基于NLP与语音识别的工单关键信息提取

“智能语音指令解析“ 基于NLP与语音识别的工单关键信息提取 1. 背景介绍1.1 场景痛点1.2 方案选型 2. 准备开发环境3. PaddleSpeech 语音识别快速使用4. PaddleNLP 信息抽取快速使用5. 语音工单信息抽取核心功能实现6. 语音工单信息抽取网页应用6.1 网页前端6.2 网页后端6.3 a…

SpringCache缓存专题

SpringCache缓存专题 学习目标 1、理解缓存存在的意义 2、掌握redis与SpringCache的集成方式 3、掌握SpringCache注解的使用 4、掌握项目集成SpringCache流程 第一章 基于SpringCache缓存方案 1.为什么需要缓存 ​ 前台请求,后台先从缓存中取数据&#xff0…

ARM 版银河麒麟桌面系统下 Qt 开发环境搭建指南

目录 前言安装Linux ARM 版 QtCreator配置 Qt Creator配置构建套件 第一个麒麟 Qt 应用程序小结 前言 在上一篇文章信创ARM架构QT应用开发环境搭建中建议大家使用 Ubuntu X86 系统作为信创 ARM 架构 QT 应用的开发环境,里面使用了交叉编译的方式。这对于自己的 Qt …

MySQL基础(二)

文章目录 MySQL基础(二)1. 数据库操作-DQL1.1 介绍1.2 语法1.3 基本查询1.4 条件查询1.5 聚合函数1.6 分组查询1.7 排序查询1.8 分页查询1.9 案例1.9.1 案例一1.9.2 案例二 2. 多表设计2.1 一对多2.1.1 表设计2.1.2 外键约束 2.2 一对一2.3 多对多2.4 案…

【Vue】组件通信组件通信

📝个人主页:五敷有你 🔥系列专栏:JVM ⛺️稳中求进,晒太阳 组件通信 组件通信,就是指组件与组件之间的数据传递 组件的数据是独立的,无法直接访问其他组件的数据想用其他组件的数据--&…

Openharmony - HDF平台驱动之I2C驱动和测试程序

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 概述I2C平台驱动I2C平台驱动HDF框架I2C平台驱动的使用I2C应用开发接口说明代码目录i2ctest.cBUILD.gnbundle.json修改config.json文件…

在Ubuntu上为ARM 8处理器安装Python 3.10.4虚拟环境指南

在Ubuntu上为ARM 8处理器安装Python 3.10.4虚拟环境指南 安装Anaconda或Miniconda: 首先,您需要从官方网站下载适用于ARM架构的Anaconda或Miniconda安装包。下载完成后,在终端中使用bash Anaconda3-2019.10-Linux-armv8.sh(文件…

ConvNeXt V2:用MAE训练CNN

论文名称:ConvNeXt V2: Co-designing and Scaling ConvNets with Masked Autoencoders 发表时间:CVPR2023 code链接:代码 作者及组织: Sanghyun Woo,Shoubhik Debnath来自KAIST和Meta AI。 前言 ConvNextV2是借助MAE的思想来训练…

pytorch -- torch.nn下的常用损失函数

1.基础 loss function损失函数:预测输出与实际输出 差距 越小越好 - 计算实际输出和目标之间的差距 - 为我们更新输出提供依据(反向传播) 1. L1 torch.nn.L1Loss(size_averageNone, reduceNone, reduction‘mean’) 2. 平方差(…

【精简版】Ubuntu/Linux Anaconda 命令行终端安装

网上重复内容很多,大都啰里啰嗦,特作此笔记。 【精简版】Ubuntu/Linux Anaconda 命令行安装 1 下载安装包1.1 寻找适配版本安装包1.2 下载 2 运行安装程序3 设置安装路径4 添加环境变量并运行4.1 环境变量4.2 运行 5 验证安装成功感谢及参考博文 1 下载…

ABAP 发送带EXCEL邮件

前言 没啥特殊需求,就是有个库龄报表用户想整邮件发送 实现 用的最简单的XLS文件作为excel附件发送出去 观察XLS文件的纯文本格式,每列之间用TAB制表符分隔,每行之间用回车符分隔 思路也比较明确,在SAP中实现这种格式&#xf…

第 1 章 微信小程序与云开发从入门到实践从零开始做小程序——开发认识微信小程序

小北的参考工具书 小程序开发的图书并不少,这本书仍然值得你拥有! 首先,这是一本全栈小程序开发教程,循序渐进,由浅入深,介绍了小程序开发你想了解的方方面面,包括近其小程序开发的各种新技术应…

golang gin单独部署vue3.0前后端分离应用

概述 因为公司最近的项目前端使用vue 3.0,后端api使用golang gin框架。测试通过后,博文记录,用于备忘。 步骤 npm run build,构建出前端项目的dist目录,dist目录的结构具体如下图 将dist目录复制到后端程序同级目录…

汽车电子笔记:BootLoader升级过程疑难问题解决方式(Bootloader响应10 02 + 刷死拯救机制)

目录 1、概述 2、如何在BootLoader响应10 02 2.1、实现流程图 2.2、实现方式(代码思路) 3、刷死拯救机制(100%能救活,适配各类控制器的方法) 3.1、强留Boot流程图 3.2、实现方式(代码思路) 1、概述 BootLoader作…

Ansible script 模块 该模块用于将本机的脚本在被管理端的机器上运行。Ansible服务执行本机脚本

目录 过程首先,我们写一个脚本,并给其加上执行权限直接运行命令来实现在被管理端执行该脚本验证错误演示 过程 该模块直接指定脚本的路径即可 首先,我们写一个脚本,并给其加上执行权限 vim /tmp/df.sh编辑脚本内容 这个脚本内容…

React_使用es5和es6语法渲染和添加class

React入门 //react的核心库 <script src"https://cdn.jsdelivr.net/npm/react17/umd/react.development.js"></script> //react操作dom的核心库&#xff0c;类似于jquery <script src"https://cdn.jsdelivr.net/npm/react-dom17/umd/react-dom.…

备考2024年高考全国甲卷文科数学:历年选择题真题练一练

距离2024年高考还有三个多月的时间&#xff0c;最后这个时间&#xff0c;同学们基本上是以刷题为主。刷题的时候最重要的是把往年的真题吃透&#xff0c;因为真题是严格按照考纲出的&#xff0c;掌握了真题后面的知识点&#xff0c;并能举一反三地运用&#xff0c;那么高考的高…

安装淘宝镜像cnpm报错

npm 安装淘宝镜像报错 npm install -g cnpm --registryhttps://registry.npm.taobao.org 安装报 The operation was rejected by your operating system. npm ERR! Its possible that the file was already in use (by a text editor or antivirus), npm ERR! or that you la…
最新文章